From e9a3c4b489ed830b73b530dfc6a3b9a8a048b452 Mon Sep 17 00:00:00 2001 From: Andre Richter Date: Tue, 19 Apr 2022 09:09:09 +0200 Subject: [PATCH 01/75] Rename main LD script to kernel.ld --- 01_wait_forever/Makefile | 2 +- .../bsp/raspberrypi/{link.ld => kernel.ld} | 0 02_runtime_init/Makefile | 2 +- 02_runtime_init/README.md | 6 +++--- .../bsp/raspberrypi/{link.ld => kernel.ld} | 0 03_hacky_hello_world/Makefile | 2 +- .../bsp/raspberrypi/{link.ld => kernel.ld} | 0 04_safe_globals/Makefile | 2 +- .../bsp/raspberrypi/{link.ld => kernel.ld} | 0 05_drivers_gpio_uart/Makefile | 2 +- .../bsp/raspberrypi/{link.ld => kernel.ld} | 0 06_uart_chainloader/Makefile | 2 +- 06_uart_chainloader/README.md | 6 +++--- .../bsp/raspberrypi/{link.ld => kernel.ld} | 0 07_timestamps/Makefile | 2 +- 07_timestamps/README.md | 6 +++--- .../bsp/raspberrypi/{link.ld => kernel.ld} | 0 08_hw_debug_JTAG/Makefile | 2 +- .../bsp/raspberrypi/{link.ld => kernel.ld} | 0 09_privilege_level/Makefile | 2 +- .../bsp/raspberrypi/{link.ld => kernel.ld} | 0 .../Makefile | 2 +- .../README.md | 6 +++--- .../bsp/raspberrypi/{link.ld => kernel.ld} | 0 11_exceptions_part1_groundwork/Makefile | 2 +- .../bsp/raspberrypi/{link.ld => kernel.ld} | 0 12_integrated_testing/Makefile | 2 +- .../bsp/raspberrypi/{link.ld => kernel.ld} | 0 13_exceptions_part2_peripheral_IRQs/Makefile | 2 +- .../bsp/raspberrypi/{link.ld => kernel.ld} | 0 14_virtual_mem_part2_mmio_remap/Makefile | 2 +- 14_virtual_mem_part2_mmio_remap/README.md | 6 +++--- .../bsp/raspberrypi/{link.ld => kernel.ld} | 0 .../Makefile | 2 +- .../README.md | 20 +++++++++---------- .../bsp/raspberrypi/{link.ld => kernel.ld} | 0 .../Makefile | 2 +- .../README.md | 6 +++--- .../bsp/raspberrypi/{link.ld => kernel.ld} | 0 X1_JTAG_boot/Makefile | 2 +- .../bsp/raspberrypi/{link.ld => kernel.ld} | 0 41 files changed, 45 insertions(+), 45 deletions(-) rename 01_wait_forever/src/bsp/raspberrypi/{link.ld => kernel.ld} (100%) rename 02_runtime_init/src/bsp/raspberrypi/{link.ld => kernel.ld} (100%) rename 03_hacky_hello_world/src/bsp/raspberrypi/{link.ld => kernel.ld} (100%) rename 04_safe_globals/src/bsp/raspberrypi/{link.ld => kernel.ld} (100%) rename 05_drivers_gpio_uart/src/bsp/raspberrypi/{link.ld => kernel.ld} (100%) rename 06_uart_chainloader/src/bsp/raspberrypi/{link.ld => kernel.ld} (100%) rename 07_timestamps/src/bsp/raspberrypi/{link.ld => kernel.ld} (100%) rename 08_hw_debug_JTAG/src/bsp/raspberrypi/{link.ld => kernel.ld} (100%) rename 09_privilege_level/src/bsp/raspberrypi/{link.ld => kernel.ld} (100%) rename 10_virtual_mem_part1_identity_mapping/src/bsp/raspberrypi/{link.ld => kernel.ld} (100%) rename 11_exceptions_part1_groundwork/src/bsp/raspberrypi/{link.ld => kernel.ld} (100%) rename 12_integrated_testing/src/bsp/raspberrypi/{link.ld => kernel.ld} (100%) rename 13_exceptions_part2_peripheral_IRQs/src/bsp/raspberrypi/{link.ld => kernel.ld} (100%) rename 14_virtual_mem_part2_mmio_remap/src/bsp/raspberrypi/{link.ld => kernel.ld} (100%) rename 15_virtual_mem_part3_precomputed_tables/src/bsp/raspberrypi/{link.ld => kernel.ld} (100%) rename 16_virtual_mem_part4_higher_half_kernel/src/bsp/raspberrypi/{link.ld => kernel.ld} (100%) rename X1_JTAG_boot/src/bsp/raspberrypi/{link.ld => kernel.ld} (100%) diff --git a/01_wait_forever/Makefile b/01_wait_forever/Makefile index cd987db5..15082c03 100644 --- a/01_wait_forever/Makefile +++ b/01_wait_forever/Makefile @@ -51,7 +51,7 @@ export LD_SCRIPT_PATH ##-------------------------------------------------------------------------------------------------- ## Targets and Prerequisites ##-------------------------------------------------------------------------------------------------- -KERNEL_LINKER_SCRIPT = link.ld +KERNEL_LINKER_SCRIPT = kernel.ld LAST_BUILD_CONFIG = target/$(BSP).build_config diff --git a/01_wait_forever/src/bsp/raspberrypi/link.ld b/01_wait_forever/src/bsp/raspberrypi/kernel.ld similarity index 100% rename from 01_wait_forever/src/bsp/raspberrypi/link.ld rename to 01_wait_forever/src/bsp/raspberrypi/kernel.ld diff --git a/02_runtime_init/Makefile b/02_runtime_init/Makefile index d1d71ec9..d44f07aa 100644 --- a/02_runtime_init/Makefile +++ b/02_runtime_init/Makefile @@ -51,7 +51,7 @@ export LD_SCRIPT_PATH ##-------------------------------------------------------------------------------------------------- ## Targets and Prerequisites ##-------------------------------------------------------------------------------------------------- -KERNEL_LINKER_SCRIPT = link.ld +KERNEL_LINKER_SCRIPT = kernel.ld LAST_BUILD_CONFIG = target/$(BSP).build_config diff --git a/02_runtime_init/README.md b/02_runtime_init/README.md index 88c29239..f2f0f047 100644 --- a/02_runtime_init/README.md +++ b/02_runtime_init/README.md @@ -196,9 +196,9 @@ diff -uNr 01_wait_forever/src/bsp/raspberrypi/cpu.rs 02_runtime_init/src/bsp/ras +#[link_section = ".text._start_arguments"] +pub static BOOT_CORE_ID: u64 = 0; -diff -uNr 01_wait_forever/src/bsp/raspberrypi/link.ld 02_runtime_init/src/bsp/raspberrypi/link.ld ---- 01_wait_forever/src/bsp/raspberrypi/link.ld -+++ 02_runtime_init/src/bsp/raspberrypi/link.ld +diff -uNr 01_wait_forever/src/bsp/raspberrypi/kernel.ld 02_runtime_init/src/bsp/raspberrypi/kernel.ld +--- 01_wait_forever/src/bsp/raspberrypi/kernel.ld ++++ 02_runtime_init/src/bsp/raspberrypi/kernel.ld @@ -3,6 +3,8 @@ * Copyright (c) 2018-2022 Andre Richter */ diff --git a/02_runtime_init/src/bsp/raspberrypi/link.ld b/02_runtime_init/src/bsp/raspberrypi/kernel.ld similarity index 100% rename from 02_runtime_init/src/bsp/raspberrypi/link.ld rename to 02_runtime_init/src/bsp/raspberrypi/kernel.ld diff --git a/03_hacky_hello_world/Makefile b/03_hacky_hello_world/Makefile index 49dcc1ed..ac52002f 100644 --- a/03_hacky_hello_world/Makefile +++ b/03_hacky_hello_world/Makefile @@ -51,7 +51,7 @@ export LD_SCRIPT_PATH ##-------------------------------------------------------------------------------------------------- ## Targets and Prerequisites ##-------------------------------------------------------------------------------------------------- -KERNEL_LINKER_SCRIPT = link.ld +KERNEL_LINKER_SCRIPT = kernel.ld LAST_BUILD_CONFIG = target/$(BSP).build_config diff --git a/03_hacky_hello_world/src/bsp/raspberrypi/link.ld b/03_hacky_hello_world/src/bsp/raspberrypi/kernel.ld similarity index 100% rename from 03_hacky_hello_world/src/bsp/raspberrypi/link.ld rename to 03_hacky_hello_world/src/bsp/raspberrypi/kernel.ld diff --git a/04_safe_globals/Makefile b/04_safe_globals/Makefile index 49dcc1ed..ac52002f 100644 --- a/04_safe_globals/Makefile +++ b/04_safe_globals/Makefile @@ -51,7 +51,7 @@ export LD_SCRIPT_PATH ##-------------------------------------------------------------------------------------------------- ## Targets and Prerequisites ##-------------------------------------------------------------------------------------------------- -KERNEL_LINKER_SCRIPT = link.ld +KERNEL_LINKER_SCRIPT = kernel.ld LAST_BUILD_CONFIG = target/$(BSP).build_config diff --git a/04_safe_globals/src/bsp/raspberrypi/link.ld b/04_safe_globals/src/bsp/raspberrypi/kernel.ld similarity index 100% rename from 04_safe_globals/src/bsp/raspberrypi/link.ld rename to 04_safe_globals/src/bsp/raspberrypi/kernel.ld diff --git a/05_drivers_gpio_uart/Makefile b/05_drivers_gpio_uart/Makefile index 28702bc8..193581e9 100644 --- a/05_drivers_gpio_uart/Makefile +++ b/05_drivers_gpio_uart/Makefile @@ -54,7 +54,7 @@ export LD_SCRIPT_PATH ##-------------------------------------------------------------------------------------------------- ## Targets and Prerequisites ##-------------------------------------------------------------------------------------------------- -KERNEL_LINKER_SCRIPT = link.ld +KERNEL_LINKER_SCRIPT = kernel.ld LAST_BUILD_CONFIG = target/$(BSP).build_config diff --git a/05_drivers_gpio_uart/src/bsp/raspberrypi/link.ld b/05_drivers_gpio_uart/src/bsp/raspberrypi/kernel.ld similarity index 100% rename from 05_drivers_gpio_uart/src/bsp/raspberrypi/link.ld rename to 05_drivers_gpio_uart/src/bsp/raspberrypi/kernel.ld diff --git a/06_uart_chainloader/Makefile b/06_uart_chainloader/Makefile index b3af24c5..5ae54175 100644 --- a/06_uart_chainloader/Makefile +++ b/06_uart_chainloader/Makefile @@ -56,7 +56,7 @@ export LD_SCRIPT_PATH ##-------------------------------------------------------------------------------------------------- ## Targets and Prerequisites ##-------------------------------------------------------------------------------------------------- -KERNEL_LINKER_SCRIPT = link.ld +KERNEL_LINKER_SCRIPT = kernel.ld LAST_BUILD_CONFIG = target/$(BSP).build_config diff --git a/06_uart_chainloader/README.md b/06_uart_chainloader/README.md index f07131ec..b3db670f 100644 --- a/06_uart_chainloader/README.md +++ b/06_uart_chainloader/README.md @@ -380,9 +380,9 @@ diff -uNr 05_drivers_gpio_uart/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs 0 {} } -diff -uNr 05_drivers_gpio_uart/src/bsp/raspberrypi/link.ld 06_uart_chainloader/src/bsp/raspberrypi/link.ld ---- 05_drivers_gpio_uart/src/bsp/raspberrypi/link.ld -+++ 06_uart_chainloader/src/bsp/raspberrypi/link.ld +diff -uNr 05_drivers_gpio_uart/src/bsp/raspberrypi/kernel.ld 06_uart_chainloader/src/bsp/raspberrypi/kernel.ld +--- 05_drivers_gpio_uart/src/bsp/raspberrypi/kernel.ld ++++ 06_uart_chainloader/src/bsp/raspberrypi/kernel.ld @@ -3,8 +3,6 @@ * Copyright (c) 2018-2022 Andre Richter */ diff --git a/06_uart_chainloader/src/bsp/raspberrypi/link.ld b/06_uart_chainloader/src/bsp/raspberrypi/kernel.ld similarity index 100% rename from 06_uart_chainloader/src/bsp/raspberrypi/link.ld rename to 06_uart_chainloader/src/bsp/raspberrypi/kernel.ld diff --git a/07_timestamps/Makefile b/07_timestamps/Makefile index 3f6b230a..d127c422 100644 --- a/07_timestamps/Makefile +++ b/07_timestamps/Makefile @@ -54,7 +54,7 @@ export LD_SCRIPT_PATH ##-------------------------------------------------------------------------------------------------- ## Targets and Prerequisites ##-------------------------------------------------------------------------------------------------- -KERNEL_LINKER_SCRIPT = link.ld +KERNEL_LINKER_SCRIPT = kernel.ld LAST_BUILD_CONFIG = target/$(BSP).build_config diff --git a/07_timestamps/README.md b/07_timestamps/README.md index 14bdc6bd..6904f4f9 100644 --- a/07_timestamps/README.md +++ b/07_timestamps/README.md @@ -451,9 +451,9 @@ diff -uNr 06_uart_chainloader/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs 07 {} } -diff -uNr 06_uart_chainloader/src/bsp/raspberrypi/link.ld 07_timestamps/src/bsp/raspberrypi/link.ld ---- 06_uart_chainloader/src/bsp/raspberrypi/link.ld -+++ 07_timestamps/src/bsp/raspberrypi/link.ld +diff -uNr 06_uart_chainloader/src/bsp/raspberrypi/kernel.ld 07_timestamps/src/bsp/raspberrypi/kernel.ld +--- 06_uart_chainloader/src/bsp/raspberrypi/kernel.ld ++++ 07_timestamps/src/bsp/raspberrypi/kernel.ld @@ -3,6 +3,8 @@ * Copyright (c) 2018-2022 Andre Richter */ diff --git a/07_timestamps/src/bsp/raspberrypi/link.ld b/07_timestamps/src/bsp/raspberrypi/kernel.ld similarity index 100% rename from 07_timestamps/src/bsp/raspberrypi/link.ld rename to 07_timestamps/src/bsp/raspberrypi/kernel.ld diff --git a/08_hw_debug_JTAG/Makefile b/08_hw_debug_JTAG/Makefile index e3db66a9..1cf4d1aa 100644 --- a/08_hw_debug_JTAG/Makefile +++ b/08_hw_debug_JTAG/Makefile @@ -58,7 +58,7 @@ export LD_SCRIPT_PATH ##-------------------------------------------------------------------------------------------------- ## Targets and Prerequisites ##-------------------------------------------------------------------------------------------------- -KERNEL_LINKER_SCRIPT = link.ld +KERNEL_LINKER_SCRIPT = kernel.ld LAST_BUILD_CONFIG = target/$(BSP).build_config diff --git a/08_hw_debug_JTAG/src/bsp/raspberrypi/link.ld b/08_hw_debug_JTAG/src/bsp/raspberrypi/kernel.ld similarity index 100% rename from 08_hw_debug_JTAG/src/bsp/raspberrypi/link.ld rename to 08_hw_debug_JTAG/src/bsp/raspberrypi/kernel.ld diff --git a/09_privilege_level/Makefile b/09_privilege_level/Makefile index e3db66a9..1cf4d1aa 100644 --- a/09_privilege_level/Makefile +++ b/09_privilege_level/Makefile @@ -58,7 +58,7 @@ export LD_SCRIPT_PATH ##-------------------------------------------------------------------------------------------------- ## Targets and Prerequisites ##-------------------------------------------------------------------------------------------------- -KERNEL_LINKER_SCRIPT = link.ld +KERNEL_LINKER_SCRIPT = kernel.ld LAST_BUILD_CONFIG = target/$(BSP).build_config diff --git a/09_privilege_level/src/bsp/raspberrypi/link.ld b/09_privilege_level/src/bsp/raspberrypi/kernel.ld similarity index 100% rename from 09_privilege_level/src/bsp/raspberrypi/link.ld rename to 09_privilege_level/src/bsp/raspberrypi/kernel.ld diff --git a/10_virtual_mem_part1_identity_mapping/Makefile b/10_virtual_mem_part1_identity_mapping/Makefile index e3db66a9..1cf4d1aa 100644 --- a/10_virtual_mem_part1_identity_mapping/Makefile +++ b/10_virtual_mem_part1_identity_mapping/Makefile @@ -58,7 +58,7 @@ export LD_SCRIPT_PATH ##-------------------------------------------------------------------------------------------------- ## Targets and Prerequisites ##-------------------------------------------------------------------------------------------------- -KERNEL_LINKER_SCRIPT = link.ld +KERNEL_LINKER_SCRIPT = kernel.ld LAST_BUILD_CONFIG = target/$(BSP).build_config diff --git a/10_virtual_mem_part1_identity_mapping/README.md b/10_virtual_mem_part1_identity_mapping/README.md index 1bf427c0..1a02666b 100644 --- a/10_virtual_mem_part1_identity_mapping/README.md +++ b/10_virtual_mem_part1_identity_mapping/README.md @@ -828,9 +828,9 @@ diff -uNr 09_privilege_level/src/_arch/aarch64/memory/mmu.rs 10_virtual_mem_part + } +} -diff -uNr 09_privilege_level/src/bsp/raspberrypi/link.ld 10_virtual_mem_part1_identity_mapping/src/bsp/raspberrypi/link.ld ---- 09_privilege_level/src/bsp/raspberrypi/link.ld -+++ 10_virtual_mem_part1_identity_mapping/src/bsp/raspberrypi/link.ld +diff -uNr 09_privilege_level/src/bsp/raspberrypi/kernel.ld 10_virtual_mem_part1_identity_mapping/src/bsp/raspberrypi/kernel.ld +--- 09_privilege_level/src/bsp/raspberrypi/kernel.ld ++++ 10_virtual_mem_part1_identity_mapping/src/bsp/raspberrypi/kernel.ld @@ -3,6 +3,9 @@ * Copyright (c) 2018-2022 Andre Richter */ diff --git a/10_virtual_mem_part1_identity_mapping/src/bsp/raspberrypi/link.ld b/10_virtual_mem_part1_identity_mapping/src/bsp/raspberrypi/kernel.ld similarity index 100% rename from 10_virtual_mem_part1_identity_mapping/src/bsp/raspberrypi/link.ld rename to 10_virtual_mem_part1_identity_mapping/src/bsp/raspberrypi/kernel.ld diff --git a/11_exceptions_part1_groundwork/Makefile b/11_exceptions_part1_groundwork/Makefile index e3db66a9..1cf4d1aa 100644 --- a/11_exceptions_part1_groundwork/Makefile +++ b/11_exceptions_part1_groundwork/Makefile @@ -58,7 +58,7 @@ export LD_SCRIPT_PATH ##-------------------------------------------------------------------------------------------------- ## Targets and Prerequisites ##-------------------------------------------------------------------------------------------------- -KERNEL_LINKER_SCRIPT = link.ld +KERNEL_LINKER_SCRIPT = kernel.ld LAST_BUILD_CONFIG = target/$(BSP).build_config diff --git a/11_exceptions_part1_groundwork/src/bsp/raspberrypi/link.ld b/11_exceptions_part1_groundwork/src/bsp/raspberrypi/kernel.ld similarity index 100% rename from 11_exceptions_part1_groundwork/src/bsp/raspberrypi/link.ld rename to 11_exceptions_part1_groundwork/src/bsp/raspberrypi/kernel.ld diff --git a/12_integrated_testing/Makefile b/12_integrated_testing/Makefile index afa22480..925ac45f 100644 --- a/12_integrated_testing/Makefile +++ b/12_integrated_testing/Makefile @@ -67,7 +67,7 @@ export LD_SCRIPT_PATH ##-------------------------------------------------------------------------------------------------- ## Targets and Prerequisites ##-------------------------------------------------------------------------------------------------- -KERNEL_LINKER_SCRIPT = link.ld +KERNEL_LINKER_SCRIPT = kernel.ld LAST_BUILD_CONFIG = target/$(BSP).build_config diff --git a/12_integrated_testing/src/bsp/raspberrypi/link.ld b/12_integrated_testing/src/bsp/raspberrypi/kernel.ld similarity index 100% rename from 12_integrated_testing/src/bsp/raspberrypi/link.ld rename to 12_integrated_testing/src/bsp/raspberrypi/kernel.ld diff --git a/13_exceptions_part2_peripheral_IRQs/Makefile b/13_exceptions_part2_peripheral_IRQs/Makefile index afa22480..925ac45f 100644 --- a/13_exceptions_part2_peripheral_IRQs/Makefile +++ b/13_exceptions_part2_peripheral_IRQs/Makefile @@ -67,7 +67,7 @@ export LD_SCRIPT_PATH ##-------------------------------------------------------------------------------------------------- ## Targets and Prerequisites ##-------------------------------------------------------------------------------------------------- -KERNEL_LINKER_SCRIPT = link.ld +KERNEL_LINKER_SCRIPT = kernel.ld LAST_BUILD_CONFIG = target/$(BSP).build_config diff --git a/13_exceptions_part2_peripheral_IRQs/src/bsp/raspberrypi/link.ld b/13_exceptions_part2_peripheral_IRQs/src/bsp/raspberrypi/kernel.ld similarity index 100% rename from 13_exceptions_part2_peripheral_IRQs/src/bsp/raspberrypi/link.ld rename to 13_exceptions_part2_peripheral_IRQs/src/bsp/raspberrypi/kernel.ld diff --git a/14_virtual_mem_part2_mmio_remap/Makefile b/14_virtual_mem_part2_mmio_remap/Makefile index afa22480..925ac45f 100644 --- a/14_virtual_mem_part2_mmio_remap/Makefile +++ b/14_virtual_mem_part2_mmio_remap/Makefile @@ -67,7 +67,7 @@ export LD_SCRIPT_PATH ##-------------------------------------------------------------------------------------------------- ## Targets and Prerequisites ##-------------------------------------------------------------------------------------------------- -KERNEL_LINKER_SCRIPT = link.ld +KERNEL_LINKER_SCRIPT = kernel.ld LAST_BUILD_CONFIG = target/$(BSP).build_config diff --git a/14_virtual_mem_part2_mmio_remap/README.md b/14_virtual_mem_part2_mmio_remap/README.md index 07a82cda..9e9adb70 100644 --- a/14_virtual_mem_part2_mmio_remap/README.md +++ b/14_virtual_mem_part2_mmio_remap/README.md @@ -1431,9 +1431,9 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/src/bsp/raspberrypi/driver.rs 14_v super::GPIO.map_pl011_uart(); } -diff -uNr 13_exceptions_part2_peripheral_IRQs/src/bsp/raspberrypi/link.ld 14_virtual_mem_part2_mmio_remap/src/bsp/raspberrypi/link.ld ---- 13_exceptions_part2_peripheral_IRQs/src/bsp/raspberrypi/link.ld -+++ 14_virtual_mem_part2_mmio_remap/src/bsp/raspberrypi/link.ld +diff -uNr 13_exceptions_part2_peripheral_IRQs/src/bsp/raspberrypi/kernel.ld 14_virtual_mem_part2_mmio_remap/src/bsp/raspberrypi/kernel.ld +--- 13_exceptions_part2_peripheral_IRQs/src/bsp/raspberrypi/kernel.ld ++++ 14_virtual_mem_part2_mmio_remap/src/bsp/raspberrypi/kernel.ld @@ -38,7 +38,7 @@ ***********************************************************************************************/ .boot_core_stack (NOLOAD) : diff --git a/14_virtual_mem_part2_mmio_remap/src/bsp/raspberrypi/link.ld b/14_virtual_mem_part2_mmio_remap/src/bsp/raspberrypi/kernel.ld similarity index 100% rename from 14_virtual_mem_part2_mmio_remap/src/bsp/raspberrypi/link.ld rename to 14_virtual_mem_part2_mmio_remap/src/bsp/raspberrypi/kernel.ld diff --git a/15_virtual_mem_part3_precomputed_tables/Makefile b/15_virtual_mem_part3_precomputed_tables/Makefile index fec9097c..56a77692 100644 --- a/15_virtual_mem_part3_precomputed_tables/Makefile +++ b/15_virtual_mem_part3_precomputed_tables/Makefile @@ -67,7 +67,7 @@ export LD_SCRIPT_PATH ##-------------------------------------------------------------------------------------------------- ## Targets and Prerequisites ##-------------------------------------------------------------------------------------------------- -KERNEL_LINKER_SCRIPT = link.ld +KERNEL_LINKER_SCRIPT = kernel.ld TT_TOOL_PATH = translation_table_tool diff --git a/15_virtual_mem_part3_precomputed_tables/README.md b/15_virtual_mem_part3_precomputed_tables/README.md index 37d157cc..39881214 100644 --- a/15_virtual_mem_part3_precomputed_tables/README.md +++ b/15_virtual_mem_part3_precomputed_tables/README.md @@ -813,7 +813,7 @@ diff -uNr 14_virtual_mem_part2_mmio_remap/Makefile 15_virtual_mem_part3_precompu +++ 15_virtual_mem_part3_precomputed_tables/Makefile @@ -69,12 +69,19 @@ ##-------------------------------------------------------------------------------------------------- - KERNEL_LINKER_SCRIPT = link.ld + KERNEL_LINKER_SCRIPT = kernel.ld +TT_TOOL_PATH = translation_table_tool + @@ -1190,15 +1190,9 @@ diff -uNr 14_virtual_mem_part2_mmio_remap/src/bsp/raspberrypi/console.rs 15_virt + } +} -diff -uNr 14_virtual_mem_part2_mmio_remap/src/bsp/raspberrypi/kernel_virt_addr_space_size.ld 15_virtual_mem_part3_precomputed_tables/src/bsp/raspberrypi/kernel_virt_addr_space_size.ld ---- 14_virtual_mem_part2_mmio_remap/src/bsp/raspberrypi/kernel_virt_addr_space_size.ld -+++ 15_virtual_mem_part3_precomputed_tables/src/bsp/raspberrypi/kernel_virt_addr_space_size.ld -@@ -0,0 +1 @@ -+__kernel_virt_addr_space_size = 1024 * 1024 * 1024 - -diff -uNr 14_virtual_mem_part2_mmio_remap/src/bsp/raspberrypi/link.ld 15_virtual_mem_part3_precomputed_tables/src/bsp/raspberrypi/link.ld ---- 14_virtual_mem_part2_mmio_remap/src/bsp/raspberrypi/link.ld -+++ 15_virtual_mem_part3_precomputed_tables/src/bsp/raspberrypi/link.ld +diff -uNr 14_virtual_mem_part2_mmio_remap/src/bsp/raspberrypi/kernel.ld 15_virtual_mem_part3_precomputed_tables/src/bsp/raspberrypi/kernel.ld +--- 14_virtual_mem_part2_mmio_remap/src/bsp/raspberrypi/kernel.ld ++++ 15_virtual_mem_part3_precomputed_tables/src/bsp/raspberrypi/kernel.ld @@ -3,6 +3,8 @@ * Copyright (c) 2018-2022 Andre Richter */ @@ -1209,6 +1203,12 @@ diff -uNr 14_virtual_mem_part2_mmio_remap/src/bsp/raspberrypi/link.ld 15_virtual PAGE_MASK = PAGE_SIZE - 1; +diff -uNr 14_virtual_mem_part2_mmio_remap/src/bsp/raspberrypi/kernel_virt_addr_space_size.ld 15_virtual_mem_part3_precomputed_tables/src/bsp/raspberrypi/kernel_virt_addr_space_size.ld +--- 14_virtual_mem_part2_mmio_remap/src/bsp/raspberrypi/kernel_virt_addr_space_size.ld ++++ 15_virtual_mem_part3_precomputed_tables/src/bsp/raspberrypi/kernel_virt_addr_space_size.ld +@@ -0,0 +1 @@ ++__kernel_virt_addr_space_size = 1024 * 1024 * 1024 + diff -uNr 14_virtual_mem_part2_mmio_remap/src/bsp/raspberrypi/memory/mmu.rs 15_virtual_mem_part3_precomputed_tables/src/bsp/raspberrypi/memory/mmu.rs --- 14_virtual_mem_part2_mmio_remap/src/bsp/raspberrypi/memory/mmu.rs +++ 15_virtual_mem_part3_precomputed_tables/src/bsp/raspberrypi/memory/mmu.rs diff --git a/15_virtual_mem_part3_precomputed_tables/src/bsp/raspberrypi/link.ld b/15_virtual_mem_part3_precomputed_tables/src/bsp/raspberrypi/kernel.ld similarity index 100% rename from 15_virtual_mem_part3_precomputed_tables/src/bsp/raspberrypi/link.ld rename to 15_virtual_mem_part3_precomputed_tables/src/bsp/raspberrypi/kernel.ld diff --git a/16_virtual_mem_part4_higher_half_kernel/Makefile b/16_virtual_mem_part4_higher_half_kernel/Makefile index fec9097c..56a77692 100644 --- a/16_virtual_mem_part4_higher_half_kernel/Makefile +++ b/16_virtual_mem_part4_higher_half_kernel/Makefile @@ -67,7 +67,7 @@ export LD_SCRIPT_PATH ##-------------------------------------------------------------------------------------------------- ## Targets and Prerequisites ##-------------------------------------------------------------------------------------------------- -KERNEL_LINKER_SCRIPT = link.ld +KERNEL_LINKER_SCRIPT = kernel.ld TT_TOOL_PATH = translation_table_tool diff --git a/16_virtual_mem_part4_higher_half_kernel/README.md b/16_virtual_mem_part4_higher_half_kernel/README.md index 52ca9bfe..f7c72aca 100644 --- a/16_virtual_mem_part4_higher_half_kernel/README.md +++ b/16_virtual_mem_part4_higher_half_kernel/README.md @@ -638,9 +638,9 @@ diff -uNr 15_virtual_mem_part3_precomputed_tables/src/bsp/raspberrypi/console.rs panic_uart -diff -uNr 15_virtual_mem_part3_precomputed_tables/src/bsp/raspberrypi/link.ld 16_virtual_mem_part4_higher_half_kernel/src/bsp/raspberrypi/link.ld ---- 15_virtual_mem_part3_precomputed_tables/src/bsp/raspberrypi/link.ld -+++ 16_virtual_mem_part4_higher_half_kernel/src/bsp/raspberrypi/link.ld +diff -uNr 15_virtual_mem_part3_precomputed_tables/src/bsp/raspberrypi/kernel.ld 16_virtual_mem_part4_higher_half_kernel/src/bsp/raspberrypi/kernel.ld +--- 15_virtual_mem_part3_precomputed_tables/src/bsp/raspberrypi/kernel.ld ++++ 16_virtual_mem_part4_higher_half_kernel/src/bsp/raspberrypi/kernel.ld @@ -8,6 +8,13 @@ PAGE_SIZE = 64K; PAGE_MASK = PAGE_SIZE - 1; diff --git a/16_virtual_mem_part4_higher_half_kernel/src/bsp/raspberrypi/link.ld b/16_virtual_mem_part4_higher_half_kernel/src/bsp/raspberrypi/kernel.ld similarity index 100% rename from 16_virtual_mem_part4_higher_half_kernel/src/bsp/raspberrypi/link.ld rename to 16_virtual_mem_part4_higher_half_kernel/src/bsp/raspberrypi/kernel.ld diff --git a/X1_JTAG_boot/Makefile b/X1_JTAG_boot/Makefile index 3f6b230a..d127c422 100644 --- a/X1_JTAG_boot/Makefile +++ b/X1_JTAG_boot/Makefile @@ -54,7 +54,7 @@ export LD_SCRIPT_PATH ##-------------------------------------------------------------------------------------------------- ## Targets and Prerequisites ##-------------------------------------------------------------------------------------------------- -KERNEL_LINKER_SCRIPT = link.ld +KERNEL_LINKER_SCRIPT = kernel.ld LAST_BUILD_CONFIG = target/$(BSP).build_config diff --git a/X1_JTAG_boot/src/bsp/raspberrypi/link.ld b/X1_JTAG_boot/src/bsp/raspberrypi/kernel.ld similarity index 100% rename from X1_JTAG_boot/src/bsp/raspberrypi/link.ld rename to X1_JTAG_boot/src/bsp/raspberrypi/kernel.ld From 353d92b1dfb6b3cb154c70e98b403d155ff0261b Mon Sep 17 00:00:00 2001 From: Andre Richter Date: Tue, 19 Apr 2022 09:10:06 +0200 Subject: [PATCH 02/75] Revert "Move test-features activation to Cargo.toml" This reverts commit 0b449706f3a0c3bbd115f1a3e6844e5fc0459ee0. Also moves the feature addition before the if/else --- 12_integrated_testing/Cargo.lock | 1 - 12_integrated_testing/Cargo.toml | 7 ------- 12_integrated_testing/Makefile | 2 ++ 12_integrated_testing/README.md | 19 +++++++------------ .../Cargo.lock | 1 - .../Cargo.toml | 7 ------- 13_exceptions_part2_peripheral_IRQs/Makefile | 2 ++ 14_virtual_mem_part2_mmio_remap/Cargo.lock | 1 - 14_virtual_mem_part2_mmio_remap/Cargo.toml | 7 ------- 14_virtual_mem_part2_mmio_remap/Makefile | 2 ++ .../Cargo.lock | 1 - .../Cargo.toml | 7 ------- .../Makefile | 2 ++ .../README.md | 2 +- .../Cargo.lock | 1 - .../Cargo.toml | 7 ------- .../Makefile | 2 ++ 17 files changed, 18 insertions(+), 53 deletions(-) diff --git a/12_integrated_testing/Cargo.lock b/12_integrated_testing/Cargo.lock index d34ce134..5834e9f3 100644 --- a/12_integrated_testing/Cargo.lock +++ b/12_integrated_testing/Cargo.lock @@ -16,7 +16,6 @@ name = "mingo" version = "0.12.0" dependencies = [ "cortex-a", - "mingo", "qemu-exit", "test-macros", "test-types", diff --git a/12_integrated_testing/Cargo.toml b/12_integrated_testing/Cargo.toml index 3e4b2a8a..e768e678 100644 --- a/12_integrated_testing/Cargo.toml +++ b/12_integrated_testing/Cargo.toml @@ -35,13 +35,6 @@ cortex-a = { version = "7.x.x" } [dev-dependencies] test-macros = { path = "test-macros" } -# The following line is a workaround, as suggested in [1], to enable a feature in test-builds only. -# This allows building the library part of the kernel with specialized code for testing. -# -# -# [1] https://github.com/rust-lang/cargo/issues/2911#issuecomment-749580481 -mingo = { path = ".", features = ["test_build"] } - # Unit tests are done in the library part of the kernel. [lib] name = "libkernel" diff --git a/12_integrated_testing/Makefile b/12_integrated_testing/Makefile index 925ac45f..6adb1aca 100644 --- a/12_integrated_testing/Makefile +++ b/12_integrated_testing/Makefile @@ -277,6 +277,8 @@ gdb gdb-opt0: $(KERNEL_ELF) ##-------------------------------------------------------------------------------------------------- .PHONY: test test_boot test_unit test_integration +test_unit test_integration: FEATURES += --features test_build + ifeq ($(QEMU_MACHINE_TYPE),) # QEMU is not supported for the board. test_boot test_unit test_integration test: diff --git a/12_integrated_testing/README.md b/12_integrated_testing/README.md index 05029ca1..3bd88c96 100644 --- a/12_integrated_testing/README.md +++ b/12_integrated_testing/README.md @@ -324,7 +324,7 @@ pub fn qemu_exit_success() -> ! { [Click here] in case you are interested in the implementation. Note that for the functions to work, the `-semihosting` flag must be added to the `QEMU` invocation. -You might have also noted the `#[cfg(feature = "test_build")]`. In `Cargo.toml`, we ensure that +You might have also noted the `#[cfg(feature = "test_build")]`. In the `Makefile`, we ensure that this feature is only enabled when `cargo test` runs. This way, it is ensured that testing-specific code is conditionally compiled only for testing. @@ -417,7 +417,7 @@ endef test_unit: $(call color_header, "Compiling unit test(s) - $(BSP)") $(call test_prepare) - @RUSTFLAGS="$(RUSTFLAGS_PEDANTIC)" $(TEST_CMD) --lib + RUSTFLAGS="$(RUSTFLAGS_PEDANTIC)" $(TEST_CMD) --lib ``` It first does the standard `objcopy` step to strip the `ELF` down to a raw binary. Just like in all @@ -910,7 +910,7 @@ diff -uNr 11_exceptions_part1_groundwork/Cargo.toml 12_integrated_testing/Cargo. authors = ["Andre Richter "] edition = "2021" -@@ -11,20 +11,57 @@ +@@ -11,20 +11,50 @@ default = [] bsp_rpi3 = ["tock-registers"] bsp_rpi4 = ["tock-registers"] @@ -942,13 +942,6 @@ diff -uNr 11_exceptions_part1_groundwork/Cargo.toml 12_integrated_testing/Cargo. +[dev-dependencies] +test-macros = { path = "test-macros" } + -+# The following line is a workaround, as suggested in [1], to enable a feature in test-builds only. -+# This allows building the library part of the kernel with specialized code for testing. -+# -+# -+# [1] https://github.com/rust-lang/cargo/issues/2911#issuecomment-749580481 -+mingo = { path = ".", features = ["test_build"] } -+ +# Unit tests are done in the library part of the kernel. +[lib] +name = "libkernel" @@ -1014,12 +1007,14 @@ diff -uNr 11_exceptions_part1_groundwork/Makefile 12_integrated_testing/Makefile OBJCOPY_CMD = rust-objcopy \ --strip-all \ -O binary -@@ -265,11 +275,11 @@ +@@ -265,11 +275,13 @@ ##-------------------------------------------------------------------------------------------------- ## Testing targets ##-------------------------------------------------------------------------------------------------- -.PHONY: test test_boot +.PHONY: test test_boot test_unit test_integration ++ ++test_unit test_integration: FEATURES += --features test_build ifeq ($(QEMU_MACHINE_TYPE),) # QEMU is not supported for the board. @@ -1028,7 +1023,7 @@ diff -uNr 11_exceptions_part1_groundwork/Makefile 12_integrated_testing/Makefile $(call color_header, "$(QEMU_MISSING_STRING)") else # QEMU is supported. -@@ -281,6 +291,43 @@ +@@ -281,6 +293,43 @@ $(call color_header, "Boot test - $(BSP)") @$(DOCKER_TEST) $(EXEC_TEST_DISPATCH) $(EXEC_QEMU) $(QEMU_RELEASE_ARGS) -kernel $(KERNEL_BIN) diff --git a/13_exceptions_part2_peripheral_IRQs/Cargo.lock b/13_exceptions_part2_peripheral_IRQs/Cargo.lock index ba1b9013..8fde49ef 100644 --- a/13_exceptions_part2_peripheral_IRQs/Cargo.lock +++ b/13_exceptions_part2_peripheral_IRQs/Cargo.lock @@ -16,7 +16,6 @@ name = "mingo" version = "0.13.0" dependencies = [ "cortex-a", - "mingo", "qemu-exit", "test-macros", "test-types", diff --git a/13_exceptions_part2_peripheral_IRQs/Cargo.toml b/13_exceptions_part2_peripheral_IRQs/Cargo.toml index a1a3bfbf..7ef55831 100644 --- a/13_exceptions_part2_peripheral_IRQs/Cargo.toml +++ b/13_exceptions_part2_peripheral_IRQs/Cargo.toml @@ -35,13 +35,6 @@ cortex-a = { version = "7.x.x" } [dev-dependencies] test-macros = { path = "test-macros" } -# The following line is a workaround, as suggested in [1], to enable a feature in test-builds only. -# This allows building the library part of the kernel with specialized code for testing. -# -# -# [1] https://github.com/rust-lang/cargo/issues/2911#issuecomment-749580481 -mingo = { path = ".", features = ["test_build"] } - # Unit tests are done in the library part of the kernel. [lib] name = "libkernel" diff --git a/13_exceptions_part2_peripheral_IRQs/Makefile b/13_exceptions_part2_peripheral_IRQs/Makefile index 925ac45f..6adb1aca 100644 --- a/13_exceptions_part2_peripheral_IRQs/Makefile +++ b/13_exceptions_part2_peripheral_IRQs/Makefile @@ -277,6 +277,8 @@ gdb gdb-opt0: $(KERNEL_ELF) ##-------------------------------------------------------------------------------------------------- .PHONY: test test_boot test_unit test_integration +test_unit test_integration: FEATURES += --features test_build + ifeq ($(QEMU_MACHINE_TYPE),) # QEMU is not supported for the board. test_boot test_unit test_integration test: diff --git a/14_virtual_mem_part2_mmio_remap/Cargo.lock b/14_virtual_mem_part2_mmio_remap/Cargo.lock index ab4eda71..6526767a 100644 --- a/14_virtual_mem_part2_mmio_remap/Cargo.lock +++ b/14_virtual_mem_part2_mmio_remap/Cargo.lock @@ -16,7 +16,6 @@ name = "mingo" version = "0.14.0" dependencies = [ "cortex-a", - "mingo", "qemu-exit", "test-macros", "test-types", diff --git a/14_virtual_mem_part2_mmio_remap/Cargo.toml b/14_virtual_mem_part2_mmio_remap/Cargo.toml index 130d80f7..3146ad05 100644 --- a/14_virtual_mem_part2_mmio_remap/Cargo.toml +++ b/14_virtual_mem_part2_mmio_remap/Cargo.toml @@ -35,13 +35,6 @@ cortex-a = { version = "7.x.x" } [dev-dependencies] test-macros = { path = "test-macros" } -# The following line is a workaround, as suggested in [1], to enable a feature in test-builds only. -# This allows building the library part of the kernel with specialized code for testing. -# -# -# [1] https://github.com/rust-lang/cargo/issues/2911#issuecomment-749580481 -mingo = { path = ".", features = ["test_build"] } - # Unit tests are done in the library part of the kernel. [lib] name = "libkernel" diff --git a/14_virtual_mem_part2_mmio_remap/Makefile b/14_virtual_mem_part2_mmio_remap/Makefile index 925ac45f..6adb1aca 100644 --- a/14_virtual_mem_part2_mmio_remap/Makefile +++ b/14_virtual_mem_part2_mmio_remap/Makefile @@ -277,6 +277,8 @@ gdb gdb-opt0: $(KERNEL_ELF) ##-------------------------------------------------------------------------------------------------- .PHONY: test test_boot test_unit test_integration +test_unit test_integration: FEATURES += --features test_build + ifeq ($(QEMU_MACHINE_TYPE),) # QEMU is not supported for the board. test_boot test_unit test_integration test: diff --git a/15_virtual_mem_part3_precomputed_tables/Cargo.lock b/15_virtual_mem_part3_precomputed_tables/Cargo.lock index 29683180..9ce8fc76 100644 --- a/15_virtual_mem_part3_precomputed_tables/Cargo.lock +++ b/15_virtual_mem_part3_precomputed_tables/Cargo.lock @@ -16,7 +16,6 @@ name = "mingo" version = "0.15.0" dependencies = [ "cortex-a", - "mingo", "qemu-exit", "test-macros", "test-types", diff --git a/15_virtual_mem_part3_precomputed_tables/Cargo.toml b/15_virtual_mem_part3_precomputed_tables/Cargo.toml index 1c39f36f..6a41bd03 100644 --- a/15_virtual_mem_part3_precomputed_tables/Cargo.toml +++ b/15_virtual_mem_part3_precomputed_tables/Cargo.toml @@ -35,13 +35,6 @@ cortex-a = { version = "7.x.x" } [dev-dependencies] test-macros = { path = "test-macros" } -# The following line is a workaround, as suggested in [1], to enable a feature in test-builds only. -# This allows building the library part of the kernel with specialized code for testing. -# -# -# [1] https://github.com/rust-lang/cargo/issues/2911#issuecomment-749580481 -mingo = { path = ".", features = ["test_build"] } - # Unit tests are done in the library part of the kernel. [lib] name = "libkernel" diff --git a/15_virtual_mem_part3_precomputed_tables/Makefile b/15_virtual_mem_part3_precomputed_tables/Makefile index 56a77692..a695185d 100644 --- a/15_virtual_mem_part3_precomputed_tables/Makefile +++ b/15_virtual_mem_part3_precomputed_tables/Makefile @@ -293,6 +293,8 @@ gdb gdb-opt0: $(KERNEL_ELF) ##-------------------------------------------------------------------------------------------------- .PHONY: test test_boot test_unit test_integration +test_unit test_integration: FEATURES += --features test_build + ifeq ($(QEMU_MACHINE_TYPE),) # QEMU is not supported for the board. test_boot test_unit test_integration test: diff --git a/15_virtual_mem_part3_precomputed_tables/README.md b/15_virtual_mem_part3_precomputed_tables/README.md index 39881214..bc666db8 100644 --- a/15_virtual_mem_part3_precomputed_tables/README.md +++ b/15_virtual_mem_part3_precomputed_tables/README.md @@ -869,7 +869,7 @@ diff -uNr 14_virtual_mem_part2_mmio_remap/Makefile 15_virtual_mem_part3_precompu $(call color_progress_prefix, "Name") @echo $(KERNEL_BIN) $(call color_progress_prefix, "Size") -@@ -300,6 +316,7 @@ +@@ -302,6 +318,7 @@ TEST_ELF=$$(echo $$1 | sed -e 's/.*target/target/g') TEST_BINARY=$$(echo $$1.img | sed -e 's/.*target/target/g') diff --git a/16_virtual_mem_part4_higher_half_kernel/Cargo.lock b/16_virtual_mem_part4_higher_half_kernel/Cargo.lock index a1766828..af4081af 100644 --- a/16_virtual_mem_part4_higher_half_kernel/Cargo.lock +++ b/16_virtual_mem_part4_higher_half_kernel/Cargo.lock @@ -16,7 +16,6 @@ name = "mingo" version = "0.16.0" dependencies = [ "cortex-a", - "mingo", "qemu-exit", "test-macros", "test-types", diff --git a/16_virtual_mem_part4_higher_half_kernel/Cargo.toml b/16_virtual_mem_part4_higher_half_kernel/Cargo.toml index 34f5090d..4964df47 100644 --- a/16_virtual_mem_part4_higher_half_kernel/Cargo.toml +++ b/16_virtual_mem_part4_higher_half_kernel/Cargo.toml @@ -35,13 +35,6 @@ cortex-a = { version = "7.x.x" } [dev-dependencies] test-macros = { path = "test-macros" } -# The following line is a workaround, as suggested in [1], to enable a feature in test-builds only. -# This allows building the library part of the kernel with specialized code for testing. -# -# -# [1] https://github.com/rust-lang/cargo/issues/2911#issuecomment-749580481 -mingo = { path = ".", features = ["test_build"] } - # Unit tests are done in the library part of the kernel. [lib] name = "libkernel" diff --git a/16_virtual_mem_part4_higher_half_kernel/Makefile b/16_virtual_mem_part4_higher_half_kernel/Makefile index 56a77692..a695185d 100644 --- a/16_virtual_mem_part4_higher_half_kernel/Makefile +++ b/16_virtual_mem_part4_higher_half_kernel/Makefile @@ -293,6 +293,8 @@ gdb gdb-opt0: $(KERNEL_ELF) ##-------------------------------------------------------------------------------------------------- .PHONY: test test_boot test_unit test_integration +test_unit test_integration: FEATURES += --features test_build + ifeq ($(QEMU_MACHINE_TYPE),) # QEMU is not supported for the board. test_boot test_unit test_integration test: From 5d746828ad1311d88d0a6013aeb1b009d4d1f74a Mon Sep 17 00:00:00 2001 From: Andre Richter Date: Tue, 19 Apr 2022 09:10:36 +0200 Subject: [PATCH 03/75] Remove relative path import from test scripts --- 12_integrated_testing/README.md | 4 ++-- 12_integrated_testing/tests/00_console_sanity.rb | 2 +- .../tests/03_exception_restore_sanity.rb | 2 +- .../tests/00_console_sanity.rb | 2 +- .../tests/03_exception_restore_sanity.rb | 2 +- .../tests/00_console_sanity.rb | 2 +- .../tests/03_exception_restore_sanity.rb | 2 +- .../tests/00_console_sanity.rb | 2 +- .../tests/03_exception_restore_sanity.rb | 2 +- .../tests/00_console_sanity.rb | 2 +- .../tests/03_exception_restore_sanity.rb | 2 +- common/tests/dispatch.rb | 9 ++++++--- 12 files changed, 18 insertions(+), 15 deletions(-) diff --git a/12_integrated_testing/README.md b/12_integrated_testing/README.md index 3bd88c96..bfcff97a 100644 --- a/12_integrated_testing/README.md +++ b/12_integrated_testing/README.md @@ -1824,7 +1824,7 @@ diff -uNr 11_exceptions_part1_groundwork/tests/00_console_sanity.rb 12_integrate +# +# Copyright (c) 2019-2022 Andre Richter + -+require_relative '../../common/tests/console_io_test' ++require 'console_io_test' + +# Verify sending and receiving works as expected. +class TxRxHandshakeTest < SubtestBase @@ -2022,7 +2022,7 @@ diff -uNr 11_exceptions_part1_groundwork/tests/03_exception_restore_sanity.rb 12 +# +# Copyright (c) 2022 Andre Richter + -+require_relative '../../common/tests/console_io_test' ++require 'console_io_test' + +# Verify that exception restore works. +class ExceptionRestoreTest < SubtestBase diff --git a/12_integrated_testing/tests/00_console_sanity.rb b/12_integrated_testing/tests/00_console_sanity.rb index 48c9703d..4dde5576 100644 --- a/12_integrated_testing/tests/00_console_sanity.rb +++ b/12_integrated_testing/tests/00_console_sanity.rb @@ -4,7 +4,7 @@ # # Copyright (c) 2019-2022 Andre Richter -require_relative '../../common/tests/console_io_test' +require 'console_io_test' # Verify sending and receiving works as expected. class TxRxHandshakeTest < SubtestBase diff --git a/12_integrated_testing/tests/03_exception_restore_sanity.rb b/12_integrated_testing/tests/03_exception_restore_sanity.rb index c3c725ed..5f52e0c7 100644 --- a/12_integrated_testing/tests/03_exception_restore_sanity.rb +++ b/12_integrated_testing/tests/03_exception_restore_sanity.rb @@ -4,7 +4,7 @@ # # Copyright (c) 2022 Andre Richter -require_relative '../../common/tests/console_io_test' +require 'console_io_test' # Verify that exception restore works. class ExceptionRestoreTest < SubtestBase diff --git a/13_exceptions_part2_peripheral_IRQs/tests/00_console_sanity.rb b/13_exceptions_part2_peripheral_IRQs/tests/00_console_sanity.rb index 48c9703d..4dde5576 100644 --- a/13_exceptions_part2_peripheral_IRQs/tests/00_console_sanity.rb +++ b/13_exceptions_part2_peripheral_IRQs/tests/00_console_sanity.rb @@ -4,7 +4,7 @@ # # Copyright (c) 2019-2022 Andre Richter -require_relative '../../common/tests/console_io_test' +require 'console_io_test' # Verify sending and receiving works as expected. class TxRxHandshakeTest < SubtestBase diff --git a/13_exceptions_part2_peripheral_IRQs/tests/03_exception_restore_sanity.rb b/13_exceptions_part2_peripheral_IRQs/tests/03_exception_restore_sanity.rb index c3c725ed..5f52e0c7 100644 --- a/13_exceptions_part2_peripheral_IRQs/tests/03_exception_restore_sanity.rb +++ b/13_exceptions_part2_peripheral_IRQs/tests/03_exception_restore_sanity.rb @@ -4,7 +4,7 @@ # # Copyright (c) 2022 Andre Richter -require_relative '../../common/tests/console_io_test' +require 'console_io_test' # Verify that exception restore works. class ExceptionRestoreTest < SubtestBase diff --git a/14_virtual_mem_part2_mmio_remap/tests/00_console_sanity.rb b/14_virtual_mem_part2_mmio_remap/tests/00_console_sanity.rb index 48c9703d..4dde5576 100644 --- a/14_virtual_mem_part2_mmio_remap/tests/00_console_sanity.rb +++ b/14_virtual_mem_part2_mmio_remap/tests/00_console_sanity.rb @@ -4,7 +4,7 @@ # # Copyright (c) 2019-2022 Andre Richter -require_relative '../../common/tests/console_io_test' +require 'console_io_test' # Verify sending and receiving works as expected. class TxRxHandshakeTest < SubtestBase diff --git a/14_virtual_mem_part2_mmio_remap/tests/03_exception_restore_sanity.rb b/14_virtual_mem_part2_mmio_remap/tests/03_exception_restore_sanity.rb index c3c725ed..5f52e0c7 100644 --- a/14_virtual_mem_part2_mmio_remap/tests/03_exception_restore_sanity.rb +++ b/14_virtual_mem_part2_mmio_remap/tests/03_exception_restore_sanity.rb @@ -4,7 +4,7 @@ # # Copyright (c) 2022 Andre Richter -require_relative '../../common/tests/console_io_test' +require 'console_io_test' # Verify that exception restore works. class ExceptionRestoreTest < SubtestBase diff --git a/15_virtual_mem_part3_precomputed_tables/tests/00_console_sanity.rb b/15_virtual_mem_part3_precomputed_tables/tests/00_console_sanity.rb index 48c9703d..4dde5576 100644 --- a/15_virtual_mem_part3_precomputed_tables/tests/00_console_sanity.rb +++ b/15_virtual_mem_part3_precomputed_tables/tests/00_console_sanity.rb @@ -4,7 +4,7 @@ # # Copyright (c) 2019-2022 Andre Richter -require_relative '../../common/tests/console_io_test' +require 'console_io_test' # Verify sending and receiving works as expected. class TxRxHandshakeTest < SubtestBase diff --git a/15_virtual_mem_part3_precomputed_tables/tests/03_exception_restore_sanity.rb b/15_virtual_mem_part3_precomputed_tables/tests/03_exception_restore_sanity.rb index c3c725ed..5f52e0c7 100644 --- a/15_virtual_mem_part3_precomputed_tables/tests/03_exception_restore_sanity.rb +++ b/15_virtual_mem_part3_precomputed_tables/tests/03_exception_restore_sanity.rb @@ -4,7 +4,7 @@ # # Copyright (c) 2022 Andre Richter -require_relative '../../common/tests/console_io_test' +require 'console_io_test' # Verify that exception restore works. class ExceptionRestoreTest < SubtestBase diff --git a/16_virtual_mem_part4_higher_half_kernel/tests/00_console_sanity.rb b/16_virtual_mem_part4_higher_half_kernel/tests/00_console_sanity.rb index 48c9703d..4dde5576 100644 --- a/16_virtual_mem_part4_higher_half_kernel/tests/00_console_sanity.rb +++ b/16_virtual_mem_part4_higher_half_kernel/tests/00_console_sanity.rb @@ -4,7 +4,7 @@ # # Copyright (c) 2019-2022 Andre Richter -require_relative '../../common/tests/console_io_test' +require 'console_io_test' # Verify sending and receiving works as expected. class TxRxHandshakeTest < SubtestBase diff --git a/16_virtual_mem_part4_higher_half_kernel/tests/03_exception_restore_sanity.rb b/16_virtual_mem_part4_higher_half_kernel/tests/03_exception_restore_sanity.rb index c3c725ed..5f52e0c7 100644 --- a/16_virtual_mem_part4_higher_half_kernel/tests/03_exception_restore_sanity.rb +++ b/16_virtual_mem_part4_higher_half_kernel/tests/03_exception_restore_sanity.rb @@ -4,7 +4,7 @@ # # Copyright (c) 2022 Andre Richter -require_relative '../../common/tests/console_io_test' +require 'console_io_test' # Verify that exception restore works. class ExceptionRestoreTest < SubtestBase diff --git a/common/tests/dispatch.rb b/common/tests/dispatch.rb index 13ae3af8..86aaea86 100755 --- a/common/tests/dispatch.rb +++ b/common/tests/dispatch.rb @@ -5,9 +5,12 @@ # # Copyright (c) 2019-2022 Andre Richter -require_relative 'boot_test' -require_relative 'console_io_test' -require_relative 'exit_code_test' +file_dir = File.dirname(__FILE__) +$LOAD_PATH.unshift(file_dir) unless $LOAD_PATH.include?(file_dir) + +require 'boot_test' +require 'console_io_test' +require 'exit_code_test' qemu_cmd = ARGV.join(' ') binary = ARGV.last From 70f1ced57b20d2acd431347c94ace1d7c3e9bd0c Mon Sep 17 00:00:00 2001 From: Andre Richter Date: Tue, 19 Apr 2022 09:11:12 +0200 Subject: [PATCH 04/75] Fix various clippy warnings --- 12_integrated_testing/README.md | 2 +- 12_integrated_testing/test-macros/src/lib.rs | 2 +- .../test-macros/src/lib.rs | 2 +- 14_virtual_mem_part2_mmio_remap/README.md | 12 +++++------- 14_virtual_mem_part2_mmio_remap/src/memory.rs | 2 +- .../src/memory/mmu/types.rs | 8 +++----- .../test-macros/src/lib.rs | 2 +- 15_virtual_mem_part3_precomputed_tables/README.md | 8 ++++++-- .../src/bsp/raspberrypi/console.rs | 4 ++++ .../src/memory.rs | 2 +- .../src/memory/mmu/types.rs | 8 +++----- .../test-macros/src/lib.rs | 2 +- 16_virtual_mem_part4_higher_half_kernel/README.md | 4 ++-- .../src/bsp/raspberrypi/console.rs | 4 ++++ .../src/memory.rs | 2 +- .../src/memory/mmu/types.rs | 8 +++----- .../test-macros/src/lib.rs | 2 +- .../tests/02_exception_sync_page_fault.rs | 2 +- 18 files changed, 40 insertions(+), 36 deletions(-) diff --git a/12_integrated_testing/README.md b/12_integrated_testing/README.md index bfcff97a..9c325e76 100644 --- a/12_integrated_testing/README.md +++ b/12_integrated_testing/README.md @@ -1797,7 +1797,7 @@ diff -uNr 11_exceptions_part1_groundwork/test-macros/src/lib.rs 12_integrated_te +pub fn kernel_test(_attr: TokenStream, input: TokenStream) -> TokenStream { + let f = parse_macro_input!(input as ItemFn); + -+ let test_name = &format!("{}", f.sig.ident.to_string()); ++ let test_name = &format!("{}", f.sig.ident); + let test_ident = Ident::new( + &format!("{}_TEST_CONTAINER", f.sig.ident.to_string().to_uppercase()), + Span::call_site(), diff --git a/12_integrated_testing/test-macros/src/lib.rs b/12_integrated_testing/test-macros/src/lib.rs index 83025a09..9879677c 100644 --- a/12_integrated_testing/test-macros/src/lib.rs +++ b/12_integrated_testing/test-macros/src/lib.rs @@ -11,7 +11,7 @@ use syn::{parse_macro_input, Ident, ItemFn}; pub fn kernel_test(_attr: TokenStream, input: TokenStream) -> TokenStream { let f = parse_macro_input!(input as ItemFn); - let test_name = &format!("{}", f.sig.ident.to_string()); + let test_name = &format!("{}", f.sig.ident); let test_ident = Ident::new( &format!("{}_TEST_CONTAINER", f.sig.ident.to_string().to_uppercase()), Span::call_site(), diff --git a/13_exceptions_part2_peripheral_IRQs/test-macros/src/lib.rs b/13_exceptions_part2_peripheral_IRQs/test-macros/src/lib.rs index 83025a09..9879677c 100644 --- a/13_exceptions_part2_peripheral_IRQs/test-macros/src/lib.rs +++ b/13_exceptions_part2_peripheral_IRQs/test-macros/src/lib.rs @@ -11,7 +11,7 @@ use syn::{parse_macro_input, Ident, ItemFn}; pub fn kernel_test(_attr: TokenStream, input: TokenStream) -> TokenStream { let f = parse_macro_input!(input as ItemFn); - let test_name = &format!("{}", f.sig.ident.to_string()); + let test_name = &format!("{}", f.sig.ident); let test_ident = Ident::new( &format!("{}_TEST_CONTAINER", f.sig.ident.to_string().to_uppercase()), Span::call_site(), diff --git a/14_virtual_mem_part2_mmio_remap/README.md b/14_virtual_mem_part2_mmio_remap/README.md index 9e9adb70..0056174b 100644 --- a/14_virtual_mem_part2_mmio_remap/README.md +++ b/14_virtual_mem_part2_mmio_remap/README.md @@ -2639,7 +2639,7 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/src/memory/mmu/translation_table.r diff -uNr 13_exceptions_part2_peripheral_IRQs/src/memory/mmu/types.rs 14_virtual_mem_part2_mmio_remap/src/memory/mmu/types.rs --- 13_exceptions_part2_peripheral_IRQs/src/memory/mmu/types.rs +++ 14_virtual_mem_part2_mmio_remap/src/memory/mmu/types.rs -@@ -0,0 +1,375 @@ +@@ -0,0 +1,373 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2020-2022 Andre Richter @@ -3005,13 +3005,11 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/src/memory/mmu/types.rs 14_virtual + assert_eq!(allocation.num_pages(), 2); + assert_eq!(three_region.num_pages(), 1); + -+ let mut count = 0; -+ for i in allocation.into_iter() { ++ for (i, alloc) in allocation.into_iter().enumerate() { + assert_eq!( -+ i.into_inner().as_usize(), -+ count * bsp::memory::mmu::KernelGranule::SIZE ++ alloc.into_inner().as_usize(), ++ i * bsp::memory::mmu::KernelGranule::SIZE + ); -+ count = count + 1; + } + } +} @@ -3588,7 +3586,7 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/src/memory.rs 14_virtual_mem_part2 + bsp::memory::mmu::KernelGranule::SIZE * 2 + ); + -+ assert_eq!(addr.is_page_aligned(), false); ++ assert!(!addr.is_page_aligned()); + + assert_eq!(addr.offset_into_page(), 100); + } diff --git a/14_virtual_mem_part2_mmio_remap/src/memory.rs b/14_virtual_mem_part2_mmio_remap/src/memory.rs index b5aa666d..f20719bb 100644 --- a/14_virtual_mem_part2_mmio_remap/src/memory.rs +++ b/14_virtual_mem_part2_mmio_remap/src/memory.rs @@ -160,7 +160,7 @@ mod tests { bsp::memory::mmu::KernelGranule::SIZE * 2 ); - assert_eq!(addr.is_page_aligned(), false); + assert!(!addr.is_page_aligned()); assert_eq!(addr.offset_into_page(), 100); } diff --git a/14_virtual_mem_part2_mmio_remap/src/memory/mmu/types.rs b/14_virtual_mem_part2_mmio_remap/src/memory/mmu/types.rs index 82d5009c..7a4fb071 100644 --- a/14_virtual_mem_part2_mmio_remap/src/memory/mmu/types.rs +++ b/14_virtual_mem_part2_mmio_remap/src/memory/mmu/types.rs @@ -363,13 +363,11 @@ mod tests { assert_eq!(allocation.num_pages(), 2); assert_eq!(three_region.num_pages(), 1); - let mut count = 0; - for i in allocation.into_iter() { + for (i, alloc) in allocation.into_iter().enumerate() { assert_eq!( - i.into_inner().as_usize(), - count * bsp::memory::mmu::KernelGranule::SIZE + alloc.into_inner().as_usize(), + i * bsp::memory::mmu::KernelGranule::SIZE ); - count = count + 1; } } } diff --git a/14_virtual_mem_part2_mmio_remap/test-macros/src/lib.rs b/14_virtual_mem_part2_mmio_remap/test-macros/src/lib.rs index 83025a09..9879677c 100644 --- a/14_virtual_mem_part2_mmio_remap/test-macros/src/lib.rs +++ b/14_virtual_mem_part2_mmio_remap/test-macros/src/lib.rs @@ -11,7 +11,7 @@ use syn::{parse_macro_input, Ident, ItemFn}; pub fn kernel_test(_attr: TokenStream, input: TokenStream) -> TokenStream { let f = parse_macro_input!(input as ItemFn); - let test_name = &format!("{}", f.sig.ident.to_string()); + let test_name = &format!("{}", f.sig.ident); let test_ident = Ident::new( &format!("{}_TEST_CONTAINER", f.sig.ident.to_string().to_uppercase()), Span::call_site(), diff --git a/15_virtual_mem_part3_precomputed_tables/README.md b/15_virtual_mem_part3_precomputed_tables/README.md index bc666db8..b27571e3 100644 --- a/15_virtual_mem_part3_precomputed_tables/README.md +++ b/15_virtual_mem_part3_precomputed_tables/README.md @@ -1146,11 +1146,15 @@ diff -uNr 14_virtual_mem_part2_mmio_remap/src/bsp/raspberrypi/console.rs 15_virt pub unsafe fn panic_console_out() -> impl fmt::Write { use driver::interface::DeviceDriver; -@@ -45,6 +46,23 @@ +@@ -45,6 +46,27 @@ panic_uart } +/// Reduced version for test builds. ++/// ++/// # Safety ++/// ++/// - Use only for printing during a panic. +#[cfg(feature = "test_build")] +pub unsafe fn panic_console_out() -> impl fmt::Write { + use driver::interface::DeviceDriver; @@ -1170,7 +1174,7 @@ diff -uNr 14_virtual_mem_part2_mmio_remap/src/bsp/raspberrypi/console.rs 15_virt /// Return a reference to the console. pub fn console() -> &'static impl console::interface::All { &super::PL011_UART -@@ -56,7 +74,15 @@ +@@ -56,7 +78,15 @@ /// Minimal code needed to bring up the console in QEMU (for testing only). This is often less steps /// than on real hardware due to QEMU's abstractions. diff --git a/15_virtual_mem_part3_precomputed_tables/src/bsp/raspberrypi/console.rs b/15_virtual_mem_part3_precomputed_tables/src/bsp/raspberrypi/console.rs index edb1a831..f4105ed7 100644 --- a/15_virtual_mem_part3_precomputed_tables/src/bsp/raspberrypi/console.rs +++ b/15_virtual_mem_part3_precomputed_tables/src/bsp/raspberrypi/console.rs @@ -47,6 +47,10 @@ pub unsafe fn panic_console_out() -> impl fmt::Write { } /// Reduced version for test builds. +/// +/// # Safety +/// +/// - Use only for printing during a panic. #[cfg(feature = "test_build")] pub unsafe fn panic_console_out() -> impl fmt::Write { use driver::interface::DeviceDriver; diff --git a/15_virtual_mem_part3_precomputed_tables/src/memory.rs b/15_virtual_mem_part3_precomputed_tables/src/memory.rs index b5aa666d..f20719bb 100644 --- a/15_virtual_mem_part3_precomputed_tables/src/memory.rs +++ b/15_virtual_mem_part3_precomputed_tables/src/memory.rs @@ -160,7 +160,7 @@ mod tests { bsp::memory::mmu::KernelGranule::SIZE * 2 ); - assert_eq!(addr.is_page_aligned(), false); + assert!(!addr.is_page_aligned()); assert_eq!(addr.offset_into_page(), 100); } diff --git a/15_virtual_mem_part3_precomputed_tables/src/memory/mmu/types.rs b/15_virtual_mem_part3_precomputed_tables/src/memory/mmu/types.rs index 82d5009c..7a4fb071 100644 --- a/15_virtual_mem_part3_precomputed_tables/src/memory/mmu/types.rs +++ b/15_virtual_mem_part3_precomputed_tables/src/memory/mmu/types.rs @@ -363,13 +363,11 @@ mod tests { assert_eq!(allocation.num_pages(), 2); assert_eq!(three_region.num_pages(), 1); - let mut count = 0; - for i in allocation.into_iter() { + for (i, alloc) in allocation.into_iter().enumerate() { assert_eq!( - i.into_inner().as_usize(), - count * bsp::memory::mmu::KernelGranule::SIZE + alloc.into_inner().as_usize(), + i * bsp::memory::mmu::KernelGranule::SIZE ); - count = count + 1; } } } diff --git a/15_virtual_mem_part3_precomputed_tables/test-macros/src/lib.rs b/15_virtual_mem_part3_precomputed_tables/test-macros/src/lib.rs index 83025a09..9879677c 100644 --- a/15_virtual_mem_part3_precomputed_tables/test-macros/src/lib.rs +++ b/15_virtual_mem_part3_precomputed_tables/test-macros/src/lib.rs @@ -11,7 +11,7 @@ use syn::{parse_macro_input, Ident, ItemFn}; pub fn kernel_test(_attr: TokenStream, input: TokenStream) -> TokenStream { let f = parse_macro_input!(input as ItemFn); - let test_name = &format!("{}", f.sig.ident.to_string()); + let test_name = &format!("{}", f.sig.ident); let test_ident = Ident::new( &format!("{}_TEST_CONTAINER", f.sig.ident.to_string().to_uppercase()), Span::call_site(), diff --git a/16_virtual_mem_part4_higher_half_kernel/README.md b/16_virtual_mem_part4_higher_half_kernel/README.md index f7c72aca..0c45e3ec 100644 --- a/16_virtual_mem_part4_higher_half_kernel/README.md +++ b/16_virtual_mem_part4_higher_half_kernel/README.md @@ -617,7 +617,7 @@ diff -uNr 15_virtual_mem_part3_precomputed_tables/src/bsp/raspberrypi/console.rs .unwrap_or_else(|_| cpu::wait_forever()); panic_uart -@@ -51,13 +56,14 @@ +@@ -55,13 +60,14 @@ pub unsafe fn panic_console_out() -> impl fmt::Write { use driver::interface::DeviceDriver; @@ -880,7 +880,7 @@ diff -uNr 15_virtual_mem_part3_precomputed_tables/tests/02_exception_sync_page_f - info!("Writing beyond mapped area to address 9 GiB..."); - let big_addr: u64 = 9 * 1024 * 1024 * 1024; + info!("Writing to bottom of address space to address 1 GiB..."); -+ let big_addr: u64 = 1 * 1024 * 1024 * 1024; ++ let big_addr: u64 = 1024 * 1024 * 1024; core::ptr::read_volatile(big_addr as *mut u64); // If execution reaches here, the memory access above did not cause a page fault exception. diff --git a/16_virtual_mem_part4_higher_half_kernel/src/bsp/raspberrypi/console.rs b/16_virtual_mem_part4_higher_half_kernel/src/bsp/raspberrypi/console.rs index e75f5fda..a0d2e687 100644 --- a/16_virtual_mem_part4_higher_half_kernel/src/bsp/raspberrypi/console.rs +++ b/16_virtual_mem_part4_higher_half_kernel/src/bsp/raspberrypi/console.rs @@ -52,6 +52,10 @@ pub unsafe fn panic_console_out() -> impl fmt::Write { } /// Reduced version for test builds. +/// +/// # Safety +/// +/// - Use only for printing during a panic. #[cfg(feature = "test_build")] pub unsafe fn panic_console_out() -> impl fmt::Write { use driver::interface::DeviceDriver; diff --git a/16_virtual_mem_part4_higher_half_kernel/src/memory.rs b/16_virtual_mem_part4_higher_half_kernel/src/memory.rs index b5aa666d..f20719bb 100644 --- a/16_virtual_mem_part4_higher_half_kernel/src/memory.rs +++ b/16_virtual_mem_part4_higher_half_kernel/src/memory.rs @@ -160,7 +160,7 @@ mod tests { bsp::memory::mmu::KernelGranule::SIZE * 2 ); - assert_eq!(addr.is_page_aligned(), false); + assert!(!addr.is_page_aligned()); assert_eq!(addr.offset_into_page(), 100); } diff --git a/16_virtual_mem_part4_higher_half_kernel/src/memory/mmu/types.rs b/16_virtual_mem_part4_higher_half_kernel/src/memory/mmu/types.rs index b72ece28..85c852b3 100644 --- a/16_virtual_mem_part4_higher_half_kernel/src/memory/mmu/types.rs +++ b/16_virtual_mem_part4_higher_half_kernel/src/memory/mmu/types.rs @@ -368,13 +368,11 @@ mod tests { assert_eq!(allocation.num_pages(), 2); assert_eq!(three_region.num_pages(), 1); - let mut count = 0; - for i in allocation.into_iter() { + for (i, alloc) in allocation.into_iter().enumerate() { assert_eq!( - i.into_inner().as_usize(), - count * bsp::memory::mmu::KernelGranule::SIZE + alloc.into_inner().as_usize(), + i * bsp::memory::mmu::KernelGranule::SIZE ); - count = count + 1; } } } diff --git a/16_virtual_mem_part4_higher_half_kernel/test-macros/src/lib.rs b/16_virtual_mem_part4_higher_half_kernel/test-macros/src/lib.rs index 83025a09..9879677c 100644 --- a/16_virtual_mem_part4_higher_half_kernel/test-macros/src/lib.rs +++ b/16_virtual_mem_part4_higher_half_kernel/test-macros/src/lib.rs @@ -11,7 +11,7 @@ use syn::{parse_macro_input, Ident, ItemFn}; pub fn kernel_test(_attr: TokenStream, input: TokenStream) -> TokenStream { let f = parse_macro_input!(input as ItemFn); - let test_name = &format!("{}", f.sig.ident.to_string()); + let test_name = &format!("{}", f.sig.ident); let test_ident = Ident::new( &format!("{}_TEST_CONTAINER", f.sig.ident.to_string().to_uppercase()), Span::call_site(), diff --git a/16_virtual_mem_part4_higher_half_kernel/tests/02_exception_sync_page_fault.rs b/16_virtual_mem_part4_higher_half_kernel/tests/02_exception_sync_page_fault.rs index 71b63e21..0d2a1e63 100644 --- a/16_virtual_mem_part4_higher_half_kernel/tests/02_exception_sync_page_fault.rs +++ b/16_virtual_mem_part4_higher_half_kernel/tests/02_exception_sync_page_fault.rs @@ -29,7 +29,7 @@ unsafe fn kernel_init() -> ! { println!("Testing synchronous exception handling by causing a page fault"); info!("Writing to bottom of address space to address 1 GiB..."); - let big_addr: u64 = 1 * 1024 * 1024 * 1024; + let big_addr: u64 = 1024 * 1024 * 1024; core::ptr::read_volatile(big_addr as *mut u64); // If execution reaches here, the memory access above did not cause a page fault exception. From e13edf999226007fc497646d6c6152a59aa296dc Mon Sep 17 00:00:00 2001 From: Andre Richter Date: Tue, 19 Apr 2022 22:43:26 +0200 Subject: [PATCH 05/75] No diffs in translations --- 02_runtime_init/README.CN.md | 299 +-------------------------- 02_runtime_init/README.ES.md | 329 +----------------------------- 03_hacky_hello_world/README.ES.md | 285 +------------------------- 3 files changed, 14 insertions(+), 899 deletions(-) diff --git a/02_runtime_init/README.CN.md b/02_runtime_init/README.CN.md index 51c63793..46c52467 100644 --- a/02_runtime_init/README.CN.md +++ b/02_runtime_init/README.CN.md @@ -19,302 +19,5 @@ [bss]: https://en.wikipedia.org/wiki/.bss ## 相比之前的变化(diff) -```diff -diff -uNr 01_wait_forever/Cargo.toml 02_runtime_init/Cargo.toml ---- 01_wait_forever/Cargo.toml -+++ 02_runtime_init/Cargo.toml -@@ -4,6 +4,9 @@ - authors = ["Andre Richter "] - edition = "2018" - -+[profile.release] -+lto = true -+ - # The features section is used to select the target board. - [features] - default = [] - -diff -uNr 01_wait_forever/src/_arch/aarch64/cpu/boot.S 02_runtime_init/src/_arch/aarch64/cpu/boot.S ---- 01_wait_forever/src/_arch/aarch64/cpu/boot.S -+++ 02_runtime_init/src/_arch/aarch64/cpu/boot.S -@@ -7,5 +7,15 @@ - .global _start - - _start: --1: wfe // Wait for event -- b 1b // In case an event happened, jump back to 1 -+ mrs x1, mpidr_el1 // Read Multiprocessor Affinity Register -+ and x1, x1, #3 // Clear all bits except [1:0], which hold core id -+ cbz x1, 2f // Jump to label 2 if we are core 0 -+1: wfe // Wait for event -+ b 1b // In case an event happened, jump back to 1 -+2: // If we are here, we are core0 -+ ldr x1, =_start // Load address of function "_start()" -+ mov sp, x1 // Set start of stack to before our code, aka first -+ // address before "_start()" -+ bl runtime_init // Jump to the "runtime_init()" kernel function -+ b 1b // We should never reach here. But just in case, -+ // park this core aswell - -diff -uNr 01_wait_forever/src/_arch/aarch64/cpu.rs 02_runtime_init/src/_arch/aarch64/cpu.rs ---- 01_wait_forever/src/_arch/aarch64/cpu.rs -+++ 02_runtime_init/src/_arch/aarch64/cpu.rs -@@ -0,0 +1,30 @@ -+// SPDX-License-Identifier: MIT OR Apache-2.0 -+// -+// Copyright (c) 2018-2022 Andre Richter -+ -+//! Architectural processor code. -+//! -+//! # Orientation -+//! -+//! Since arch modules are imported into generic modules using the path attribute, the path of this -+//! file is: -+//! -+//! crate::cpu::arch_cpu -+ -+//-------------------------------------------------------------------------------------------------- -+// Public Code -+//-------------------------------------------------------------------------------------------------- -+ -+/// Pause execution on the core. -+#[inline(always)] -+pub fn wait_forever() -> ! { -+ unsafe { -+ loop { -+ #[rustfmt::skip] -+ asm!( -+ "wfe", -+ options(nomem, nostack, preserves_flags) -+ ); -+ } -+ } -+} - -diff -uNr 01_wait_forever/src/bsp/raspberrypi/link.ld 02_runtime_init/src/bsp/raspberrypi/link.ld ---- 01_wait_forever/src/bsp/raspberrypi/link.ld -+++ 02_runtime_init/src/bsp/raspberrypi/link.ld -@@ -13,5 +13,27 @@ - *(.text._start) *(.text*) - } - -+ .rodata : -+ { -+ *(.rodata*) -+ } -+ -+ .data : -+ { -+ *(.data*) -+ } -+ -+ /* Section is zeroed in u64 chunks, align start and end to 8 bytes */ -+ .bss ALIGN(8): -+ { -+ __bss_start = .; -+ *(.bss*); -+ . = ALIGN(8); -+ -+ /* Fill for the bss == 0 case, so that __bss_start <= __bss_end_inclusive holds */ -+ . += 8; -+ __bss_end_inclusive = . - 8; -+ } -+ - /DISCARD/ : { *(.comment*) } - } - -diff -uNr 01_wait_forever/src/bsp/raspberrypi/memory.rs 02_runtime_init/src/bsp/raspberrypi/memory.rs ---- 01_wait_forever/src/bsp/raspberrypi/memory.rs -+++ 02_runtime_init/src/bsp/raspberrypi/memory.rs -@@ -0,0 +1,37 @@ -+// SPDX-License-Identifier: MIT OR Apache-2.0 -+// -+// Copyright (c) 2018-2022 Andre Richter -+ -+//! BSP Memory Management. -+ -+use core::{cell::UnsafeCell, ops::RangeInclusive}; -+ -+//-------------------------------------------------------------------------------------------------- -+// Private Definitions -+//-------------------------------------------------------------------------------------------------- -+ -+// Symbols from the linker script. -+extern "Rust" { -+ static __bss_start: UnsafeCell; -+ static __bss_end_inclusive: UnsafeCell; -+} -+ -+//-------------------------------------------------------------------------------------------------- -+// Public Code -+//-------------------------------------------------------------------------------------------------- -+ -+/// Return the inclusive range spanning the .bss section. -+/// -+/// # Safety -+/// -+/// - Values are provided by the linker script and must be trusted as-is. -+/// - The linker-provided addresses must be u64 aligned. -+pub fn bss_range_inclusive() -> RangeInclusive<*mut u64> { -+ let range; -+ unsafe { -+ range = RangeInclusive::new(__bss_start.get(), __bss_end_inclusive.get()); -+ } -+ assert!(!range.is_empty()); -+ -+ range -+} - -diff -uNr 01_wait_forever/src/bsp/raspberrypi.rs 02_runtime_init/src/bsp/raspberrypi.rs ---- 01_wait_forever/src/bsp/raspberrypi.rs -+++ 02_runtime_init/src/bsp/raspberrypi.rs -@@ -4,4 +4,4 @@ - - //! Top-level BSP file for the Raspberry Pi 3 and 4. - --// Coming soon. -+pub mod memory; - -diff -uNr 01_wait_forever/src/cpu.rs 02_runtime_init/src/cpu.rs ---- 01_wait_forever/src/cpu.rs -+++ 02_runtime_init/src/cpu.rs -@@ -4,4 +4,13 @@ - - //! Processor code. - -+#[cfg(target_arch = "aarch64")] -+#[path = "_arch/aarch64/cpu.rs"] -+mod arch_cpu; -+ - mod boot; -+ -+//-------------------------------------------------------------------------------------------------- -+// Architectural Public Reexports -+//-------------------------------------------------------------------------------------------------- -+pub use arch_cpu::wait_forever; - -diff -uNr 01_wait_forever/src/main.rs 02_runtime_init/src/main.rs ---- 01_wait_forever/src/main.rs -+++ 02_runtime_init/src/main.rs -@@ -102,6 +102,7 @@ - //! - //! 1. The kernel's entry point is the function [`cpu::boot::arch_boot::_start()`]. - //! - It is implemented in `src/_arch/__arch_name__/cpu/boot.rs`. -+//! 2. Once finished with architectural setup, the arch code calls [`runtime_init::runtime_init()`]. - //! - //! [`cpu::boot::arch_boot::_start()`]: cpu/boot/arch_boot/fn._start.html - -@@ -112,6 +113,15 @@ - - mod bsp; - mod cpu; -+mod memory; - mod panic_wait; -+mod runtime_init; - --// Kernel code coming next tutorial. -+/// Early init code. -+/// -+/// # Safety -+/// -+/// - Only a single core must be active and running this function. -+unsafe fn kernel_init() -> ! { -+ panic!() -+} - -diff -uNr 01_wait_forever/src/memory.rs 02_runtime_init/src/memory.rs ---- 01_wait_forever/src/memory.rs -+++ 02_runtime_init/src/memory.rs -@@ -0,0 +1,30 @@ -+// SPDX-License-Identifier: MIT OR Apache-2.0 -+// -+// Copyright (c) 2018-2022 Andre Richter -+ -+//! Memory Management. -+ -+use core::ops::RangeInclusive; -+ -+//-------------------------------------------------------------------------------------------------- -+// Public Code -+//-------------------------------------------------------------------------------------------------- -+ -+/// Zero out an inclusive memory range. -+/// -+/// # Safety -+/// -+/// - `range.start` and `range.end` must be valid. -+/// - `range.start` and `range.end` must be `T` aligned. -+pub unsafe fn zero_volatile(range: RangeInclusive<*mut T>) -+where -+ T: From, -+{ -+ let mut ptr = *range.start(); -+ let end_inclusive = *range.end(); -+ -+ while ptr <= end_inclusive { -+ core::ptr::write_volatile(ptr, T::from(0)); -+ ptr = ptr.offset(1); -+ } -+} - -diff -uNr 01_wait_forever/src/panic_wait.rs 02_runtime_init/src/panic_wait.rs ---- 01_wait_forever/src/panic_wait.rs -+++ 02_runtime_init/src/panic_wait.rs -@@ -4,9 +4,10 @@ - - //! A panic handler that infinitely waits. - -+use crate::cpu; - use core::panic::PanicInfo; - - #[panic_handler] - fn panic(_info: &PanicInfo) -> ! { -- unimplemented!() -+ cpu::wait_forever() - } - -diff -uNr 01_wait_forever/src/runtime_init.rs 02_runtime_init/src/runtime_init.rs ---- 01_wait_forever/src/runtime_init.rs -+++ 02_runtime_init/src/runtime_init.rs -@@ -0,0 +1,38 @@ -+// SPDX-License-Identifier: MIT OR Apache-2.0 -+// -+// Copyright (c) 2018-2022 Andre Richter -+ -+//! Rust runtime initialization code. -+ -+use crate::{bsp, memory}; -+ -+//-------------------------------------------------------------------------------------------------- -+// Private Code -+//-------------------------------------------------------------------------------------------------- -+ -+/// Zero out the .bss section. -+/// -+/// # Safety -+/// -+/// - Must only be called pre `kernel_init()`. -+#[inline(always)] -+unsafe fn zero_bss() { -+ memory::zero_volatile(bsp::memory::bss_range_inclusive()); -+} -+ -+//-------------------------------------------------------------------------------------------------- -+// Public Code -+//-------------------------------------------------------------------------------------------------- -+ -+/// Equivalent to `crt0` or `c0` code in C/C++ world. Clears the `bss` section, then jumps to kernel -+/// init code. -+/// -+/// # Safety -+/// -+/// - Only a single core must be active and running this function. -+#[no_mangle] -+pub unsafe fn runtime_init() -> ! { -+ zero_bss(); -+ -+ crate::kernel_init() -+} - -``` +Please check [the english version](README.md#diff-to-previous), which is kept up-to-date. diff --git a/02_runtime_init/README.ES.md b/02_runtime_init/README.ES.md index 6a5b3974..79c4c2b4 100644 --- a/02_runtime_init/README.ES.md +++ b/02_runtime_init/README.ES.md @@ -9,340 +9,29 @@ ## Adiciones importantes * Adiciones importantes al script `link.ld`: - + * Nuevas secciones: `.rodata`, `.got`, `.data`, `.bss`. - + * Un lugar totalmente dedicado a enlazar argumentos de tiempo de arranque (boot-time) que necesitan estar listos cuando se llame a `_start()`. * `_start()` en `_arch/__arch_name__/cpu/boot.s`: - + 1. Para todos los núcleos expecto el núcleo 0. - + 2. Inicializa la [`DRAM`](https://es.wikipedia.org/wiki/DRAM) poniendo a cero la sección [`.bss`](https://en.wikipedia.org/wiki/.bss). - + 3. Configura el `stack pointer` (puntero a la memoria [pila](https://es.wikipedia.org/wiki/Pila_(inform%C3%A1tica))). - + 4. Salta hacia la función `_start_rust()`, definida en `arch/__arch_name__/cpu/boot.rs`. * `_start_rust()`: - + * Llama a `kernel_init()`, que llama a `panic!()`, que al final también pone al núcleo 0 en pausa. * La librería ahora usa el crate [cortex-a](https://github.com/rust-embedded/cortex-a), que nos da abstracciones sin coste y envuelve las partes que hacen uso de un `unsafe` (partes con código que no es seguro y podría causar errores) cuando se trabaja directamente con los recursos del procesador. - + * Lo puedes ver en acción en `_arch/__arch_name__/cpu.rs`. ## Diferencia con el archivo anterior -```diff -diff -uNr 01_wait_forever/Cargo.toml 02_runtime_init/Cargo.toml ---- 01_wait_forever/Cargo.toml -+++ 02_runtime_init/Cargo.toml -@@ -1,6 +1,6 @@ - [package] - name = "mingo" --version = "0.1.0" -+version = "0.2.0" - authors = ["Andre Richter "] - edition = "2021" - -@@ -21,3 +21,7 @@ - ##-------------------------------------------------------------------------------------------------- - - [dependencies] -+ -+# Platform specific dependencies -+[target.'cfg(target_arch = "aarch64")'.dependencies] -+cortex-a = { version = "7.x.x" } - -diff -uNr 01_wait_forever/Makefile 02_runtime_init/Makefile ---- 01_wait_forever/Makefile -+++ 02_runtime_init/Makefile -@@ -153,6 +153,8 @@ - $(call colorecho, "\nLaunching objdump") - @$(DOCKER_TOOLS) $(OBJDUMP_BINARY) --disassemble --demangle \ - --section .text \ -+ --section .rodata \ -+ --section .got \ - $(KERNEL_ELF) | rustfilt - - ##------------------------------------------------------------------------------ - -diff -uNr 01_wait_forever/src/_arch/aarch64/cpu/boot.rs 02_runtime_init/src/_arch/aarch64/cpu/boot.rs ---- 01_wait_forever/src/_arch/aarch64/cpu/boot.rs -+++ 02_runtime_init/src/_arch/aarch64/cpu/boot.rs -@@ -13,3 +13,15 @@ - - // Assembly counterpart to this file. - core::arch::global_asm!(include_str!("boot.s")); -+ -+//-------------------------------------------------------------------------------------------------- -+// Public Code -+//-------------------------------------------------------------------------------------------------- -+ -+/// The Rust entry of the `kernel` binary. -+/// -+/// The function is called from the assembly `_start` function. -+#[no_mangle] -+pub unsafe fn _start_rust() -> ! { -+ crate::kernel_init() -+} - -diff -uNr 01_wait_forever/src/_arch/aarch64/cpu/boot.s 02_runtime_init/src/_arch/aarch64/cpu/boot.s ---- 01_wait_forever/src/_arch/aarch64/cpu/boot.s -+++ 02_runtime_init/src/_arch/aarch64/cpu/boot.s -@@ -3,6 +3,24 @@ - // Copyright (c) 2021-2022 Andre Richter - - //-------------------------------------------------------------------------------------------------- -+// Definitions -+//-------------------------------------------------------------------------------------------------- -+ -+// Load the address of a symbol into a register, PC-relative. -+// -+// The symbol must lie within +/- 4 GiB of the Program Counter. -+// -+// # Resources -+// -+// - https://sourceware.org/binutils/docs-2.36/as/AArch64_002dRelocations.html -+.macro ADR_REL register, symbol -+ adrp \register, \symbol -+ add \register, \register, #:lo12:\symbol -+.endm -+ -+.equ _core_id_mask, 0b11 -+ -+//-------------------------------------------------------------------------------------------------- - // Public Code - //-------------------------------------------------------------------------------------------------- - .section .text._start -@@ -11,6 +29,34 @@ - // fn _start() - //------------------------------------------------------------------------------ - _start: -+ // Only proceed on the boot core. Park it otherwise. -+ mrs x1, MPIDR_EL1 -+ and x1, x1, _core_id_mask -+ ldr x2, BOOT_CORE_ID // provided by bsp/__board_name__/cpu.rs -+ cmp x1, x2 -+ b.ne .L_parking_loop -+ -+ // If execution reaches here, it is the boot core. -+ -+ // Initialize DRAM. -+ ADR_REL x0, __bss_start -+ ADR_REL x1, __bss_end_exclusive -+ -+.L_bss_init_loop: -+ cmp x0, x1 -+ b.eq .L_prepare_rust -+ stp xzr, xzr, [x0], #16 -+ b .L_bss_init_loop -+ -+ // Prepare the jump to Rust code. -+.L_prepare_rust: -+ // Set the stack pointer. -+ ADR_REL x0, __boot_core_stack_end_exclusive -+ mov sp, x0 -+ -+ // Jump to Rust code. -+ b _start_rust -+ - // Infinitely wait for events (aka "park the core"). - .L_parking_loop: - wfe - -diff -uNr 01_wait_forever/src/_arch/aarch64/cpu.rs 02_runtime_init/src/_arch/aarch64/cpu.rs ---- 01_wait_forever/src/_arch/aarch64/cpu.rs -+++ 02_runtime_init/src/_arch/aarch64/cpu.rs -@@ -0,0 +1,26 @@ -+// SPDX-License-Identifier: MIT OR Apache-2.0 -+// -+// Copyright (c) 2018-2022 Andre Richter -+ -+//! Architectural processor code. -+//! -+//! # Orientation -+//! -+//! Since arch modules are imported into generic modules using the path attribute, the path of this -+//! file is: -+//! -+//! crate::cpu::arch_cpu -+ -+use cortex_a::asm; -+ -+//-------------------------------------------------------------------------------------------------- -+// Public Code -+//-------------------------------------------------------------------------------------------------- -+ -+/// Pause execution on the core. -+#[inline(always)] -+pub fn wait_forever() -> ! { -+ loop { -+ asm::wfe() -+ } -+} - -diff -uNr 01_wait_forever/src/bsp/raspberrypi/cpu.rs 02_runtime_init/src/bsp/raspberrypi/cpu.rs ---- 01_wait_forever/src/bsp/raspberrypi/cpu.rs -+++ 02_runtime_init/src/bsp/raspberrypi/cpu.rs -@@ -0,0 +1,14 @@ -+// SPDX-License-Identifier: MIT OR Apache-2.0 -+// -+// Copyright (c) 2018-2022 Andre Richter -+ -+//! BSP Processor code. -+ -+//-------------------------------------------------------------------------------------------------- -+// Public Definitions -+//-------------------------------------------------------------------------------------------------- -+ -+/// Used by `arch` code to find the early boot core. -+#[no_mangle] -+#[link_section = ".text._start_arguments"] -+pub static BOOT_CORE_ID: u64 = 0; - -diff -uNr 01_wait_forever/src/bsp/raspberrypi/link.ld 02_runtime_init/src/bsp/raspberrypi/link.ld ---- 01_wait_forever/src/bsp/raspberrypi/link.ld -+++ 02_runtime_init/src/bsp/raspberrypi/link.ld -@@ -3,6 +3,8 @@ - * Copyright (c) 2018-2022 Andre Richter - */ - -+__rpi_phys_dram_start_addr = 0; -+ - /* The physical address at which the the kernel binary will be loaded by the Raspberry's firmware */ - __rpi_phys_binary_load_addr = 0x80000; - -@@ -13,21 +15,58 @@ - * 4 == R - * 5 == RX - * 6 == RW -+ * -+ * Segments are marked PT_LOAD below so that the ELF file provides virtual and physical addresses. -+ * It doesn't mean all of them need actually be loaded. - */ - PHDRS - { -- segment_code PT_LOAD FLAGS(5); -+ segment_boot_core_stack PT_LOAD FLAGS(6); -+ segment_code PT_LOAD FLAGS(5); -+ segment_data PT_LOAD FLAGS(6); - } - - SECTIONS - { -- . = __rpi_phys_binary_load_addr; -+ . = __rpi_phys_dram_start_addr; -+ -+ /*********************************************************************************************** -+ * Boot Core Stack -+ ***********************************************************************************************/ -+ .boot_core_stack (NOLOAD) : -+ { -+ /* ^ */ -+ /* | stack */ -+ . += __rpi_phys_binary_load_addr; /* | growth */ -+ /* | direction */ -+ __boot_core_stack_end_exclusive = .; /* | */ -+ } :segment_boot_core_stack - - /*********************************************************************************************** -- * Code -+ * Code + RO Data + Global Offset Table - ***********************************************************************************************/ - .text : - { - KEEP(*(.text._start)) -+ *(.text._start_arguments) /* Constants (or statics in Rust speak) read by _start(). */ -+ *(.text._start_rust) /* The Rust entry point */ -+ *(.text*) /* Everything else */ - } :segment_code -+ -+ .rodata : ALIGN(8) { *(.rodata*) } :segment_code -+ .got : ALIGN(8) { *(.got) } :segment_code -+ -+ /*********************************************************************************************** -+ * Data + BSS -+ ***********************************************************************************************/ -+ .data : { *(.data*) } :segment_data -+ -+ /* Section is zeroed in pairs of u64. Align start and end to 16 bytes */ -+ .bss (NOLOAD) : ALIGN(16) -+ { -+ __bss_start = .; -+ *(.bss*); -+ . = ALIGN(16); -+ __bss_end_exclusive = .; -+ } :segment_data - } - -diff -uNr 01_wait_forever/src/bsp/raspberrypi.rs 02_runtime_init/src/bsp/raspberrypi.rs ---- 01_wait_forever/src/bsp/raspberrypi.rs -+++ 02_runtime_init/src/bsp/raspberrypi.rs -@@ -4,4 +4,4 @@ - - //! Top-level BSP file for the Raspberry Pi 3 and 4. - --// Coming soon. -+pub mod cpu; - -diff -uNr 01_wait_forever/src/cpu.rs 02_runtime_init/src/cpu.rs ---- 01_wait_forever/src/cpu.rs -+++ 02_runtime_init/src/cpu.rs -@@ -4,4 +4,13 @@ - - //! Processor code. - -+#[cfg(target_arch = "aarch64")] -+#[path = "_arch/aarch64/cpu.rs"] -+mod arch_cpu; -+ - mod boot; -+ -+//-------------------------------------------------------------------------------------------------- -+// Architectural Public Reexports -+//-------------------------------------------------------------------------------------------------- -+pub use arch_cpu::wait_forever; - -diff -uNr 01_wait_forever/src/main.rs 02_runtime_init/src/main.rs ---- 01_wait_forever/src/main.rs -+++ 02_runtime_init/src/main.rs -@@ -102,6 +102,7 @@ - //! - //! 1. The kernel's entry point is the function `cpu::boot::arch_boot::_start()`. - //! - It is implemented in `src/_arch/__arch_name__/cpu/boot.s`. -+//! 2. Once finished with architectural setup, the arch code calls `kernel_init()`. - - #![no_main] - #![no_std] -@@ -110,4 +111,11 @@ - mod cpu; - mod panic_wait; - --// Kernel code coming next tutorial. -+/// Early init code. -+/// -+/// # Safety -+/// -+/// - Only a single core must be active and running this function. -+unsafe fn kernel_init() -> ! { -+ panic!() -+} - -diff -uNr 01_wait_forever/src/panic_wait.rs 02_runtime_init/src/panic_wait.rs ---- 01_wait_forever/src/panic_wait.rs -+++ 02_runtime_init/src/panic_wait.rs -@@ -4,9 +4,10 @@ - - //! A panic handler that infinitely waits. - -+use crate::cpu; - use core::panic::PanicInfo; - - #[panic_handler] - fn panic(_info: &PanicInfo) -> ! { -- unimplemented!() -+ cpu::wait_forever() - } -``` +Please check [the english version](README.md#diff-to-previous), which is kept up-to-date. diff --git a/03_hacky_hello_world/README.ES.md b/03_hacky_hello_world/README.ES.md index f52b226e..eafa3c21 100644 --- a/03_hacky_hello_world/README.ES.md +++ b/03_hacky_hello_world/README.ES.md @@ -31,292 +31,15 @@ Kernel panic: Stopping here. * *Hacky:* Solución torpe o poco elegante para un problema. * *Debugging:* Proceso para identificar y corregir errores de programación. - + * *printf debugging:* Usado para describir el trabajo de depuración (*debugging*) poniendo comandos que dan una salida en consola, como el de "printf", en diferentes lugares del programa; observando la información y tratando de deducir qué está mal en el programa basándose en la información que nos dan nuestros comandos. * *Traits:* Un *trait* le hace saber al compilador de Rust acerca de una funcionalidad que tiene un tipo de dato particular y que puede compartir con otros tipos de datos. - + > NOTA: Los *traits* son similares a una característica que se le conoce comúnmente como *interfaces* en otros lenguajes, aunque con algunas diferencias. - + Si deseas aprender más acerca de esto, por favor lee este capítulo del libro de Rust: [Traits: Defining Shared Behavior - The Rust Programming Language](https://doc.rust-lang.org/book/ch10-02-traits.html) ## Diferencias con el archivo anterior -```diff -diff -uNr 02_runtime_init/Cargo.toml 03_hacky_hello_world/Cargo.toml ---- 02_runtime_init/Cargo.toml -+++ 03_hacky_hello_world/Cargo.toml -@@ -1,6 +1,6 @@ - [package] - name = "mingo" --version = "0.2.0" -+version = "0.3.0" - authors = ["Andre Richter "] - edition = "2021" - - -diff -uNr 02_runtime_init/Makefile 03_hacky_hello_world/Makefile ---- 02_runtime_init/Makefile -+++ 03_hacky_hello_world/Makefile -@@ -24,7 +24,7 @@ - KERNEL_BIN = kernel8.img - QEMU_BINARY = qemu-system-aarch64 - QEMU_MACHINE_TYPE = raspi3 -- QEMU_RELEASE_ARGS = -d in_asm -display none -+ QEMU_RELEASE_ARGS = -serial stdio -display none - OBJDUMP_BINARY = aarch64-none-elf-objdump - NM_BINARY = aarch64-none-elf-nm - READELF_BINARY = aarch64-none-elf-readelf -@@ -35,7 +35,7 @@ - KERNEL_BIN = kernel8.img - QEMU_BINARY = qemu-system-aarch64 - QEMU_MACHINE_TYPE = -- QEMU_RELEASE_ARGS = -d in_asm -display none -+ QEMU_RELEASE_ARGS = -serial stdio -display none - OBJDUMP_BINARY = aarch64-none-elf-objdump - NM_BINARY = aarch64-none-elf-nm - READELF_BINARY = aarch64-none-elf-readelf -@@ -71,17 +71,20 @@ - --strip-all \ - -O binary - --EXEC_QEMU = $(QEMU_BINARY) -M $(QEMU_MACHINE_TYPE) -+EXEC_QEMU = $(QEMU_BINARY) -M $(QEMU_MACHINE_TYPE) -+EXEC_TEST_DISPATCH = ruby ../common/tests/dispatch.rb - - ##------------------------------------------------------------------------------ - ## Dockerization - ##------------------------------------------------------------------------------ --DOCKER_CMD = docker run -t --rm -v $(shell pwd):/work/tutorial -w /work/tutorial --DOCKER_CMD_INTERACT = $(DOCKER_CMD) -i -+DOCKER_CMD = docker run -t --rm -v $(shell pwd):/work/tutorial -w /work/tutorial -+DOCKER_CMD_INTERACT = $(DOCKER_CMD) -i -+DOCKER_ARG_DIR_COMMON = -v $(shell pwd)/../common:/work/common - - # DOCKER_IMAGE defined in include file (see top of this file). - DOCKER_QEMU = $(DOCKER_CMD_INTERACT) $(DOCKER_IMAGE) - DOCKER_TOOLS = $(DOCKER_CMD) $(DOCKER_IMAGE) -+DOCKER_TEST = $(DOCKER_CMD) $(DOCKER_ARG_DIR_COMMON) $(DOCKER_IMAGE) - - - -@@ -169,3 +172,28 @@ - ##------------------------------------------------------------------------------ - check: - @RUSTFLAGS="$(RUSTFLAGS)" $(CHECK_CMD) --message-format=json -+ -+ -+ -+##-------------------------------------------------------------------------------------------------- -+## Testing targets -+##-------------------------------------------------------------------------------------------------- -+.PHONY: test test_boot -+ -+ifeq ($(QEMU_MACHINE_TYPE),) # QEMU is not supported for the board. -+ -+test_boot test : -+ $(call colorecho, "\n$(QEMU_MISSING_STRING)") -+ -+else # QEMU is supported. -+ -+##------------------------------------------------------------------------------ -+## Run boot test -+##------------------------------------------------------------------------------ -+test_boot: $(KERNEL_BIN) -+ $(call colorecho, "\nBoot test - $(BSP)") -+ @$(DOCKER_TEST) $(EXEC_TEST_DISPATCH) $(EXEC_QEMU) $(QEMU_RELEASE_ARGS) -kernel $(KERNEL_BIN) -+ -+test: test_boot -+ -+endif - -diff -uNr 02_runtime_init/src/bsp/raspberrypi/console.rs 03_hacky_hello_world/src/bsp/raspberrypi/console.rs ---- 02_runtime_init/src/bsp/raspberrypi/console.rs -+++ 03_hacky_hello_world/src/bsp/raspberrypi/console.rs -@@ -0,0 +1,47 @@ -+// SPDX-License-Identifier: MIT OR Apache-2.0 -+// -+// Copyright (c) 2018-2022 Andre Richter -+ -+//! BSP console facilities. -+ -+use crate::console; -+use core::fmt; -+ -+//-------------------------------------------------------------------------------------------------- -+// Private Definitions -+//-------------------------------------------------------------------------------------------------- -+ -+/// A mystical, magical device for generating QEMU output out of the void. -+struct QEMUOutput; -+ -+//-------------------------------------------------------------------------------------------------- -+// Private Code -+//-------------------------------------------------------------------------------------------------- -+ -+/// Implementing `core::fmt::Write` enables usage of the `format_args!` macros, which in turn are -+/// used to implement the `kernel`'s `print!` and `println!` macros. By implementing `write_str()`, -+/// we get `write_fmt()` automatically. -+/// -+/// See [`src/print.rs`]. -+/// -+/// [`src/print.rs`]: ../../print/index.html -+impl fmt::Write for QEMUOutput { -+ fn write_str(&mut self, s: &str) -> fmt::Result { -+ for c in s.chars() { -+ unsafe { -+ core::ptr::write_volatile(0x3F20_1000 as *mut u8, c as u8); -+ } -+ } -+ -+ Ok(()) -+ } -+} -+ -+//-------------------------------------------------------------------------------------------------- -+// Public Code -+//-------------------------------------------------------------------------------------------------- -+ -+/// Return a reference to the console. -+pub fn console() -> impl console::interface::Write { -+ QEMUOutput {} -+} - -diff -uNr 02_runtime_init/src/bsp/raspberrypi.rs 03_hacky_hello_world/src/bsp/raspberrypi.rs ---- 02_runtime_init/src/bsp/raspberrypi.rs -+++ 03_hacky_hello_world/src/bsp/raspberrypi.rs -@@ -4,4 +4,5 @@ - - //! Top-level BSP file for the Raspberry Pi 3 and 4. - -+pub mod console; - pub mod cpu; - -diff -uNr 02_runtime_init/src/console.rs 03_hacky_hello_world/src/console.rs ---- 02_runtime_init/src/console.rs -+++ 03_hacky_hello_world/src/console.rs -@@ -0,0 +1,19 @@ -+// SPDX-License-Identifier: MIT OR Apache-2.0 -+// -+// Copyright (c) 2018-2022 Andre Richter -+ -+//! System console. -+ -+//-------------------------------------------------------------------------------------------------- -+// Public Definitions -+//-------------------------------------------------------------------------------------------------- -+ -+/// Console interfaces. -+pub mod interface { -+ /// Console write functions. -+ /// -+ /// `core::fmt::Write` is exactly what we need for now. Re-export it here because -+ /// implementing `console::Write` gives a better hint to the reader about the -+ /// intention. -+ pub use core::fmt::Write; -+} - -diff -uNr 02_runtime_init/src/main.rs 03_hacky_hello_world/src/main.rs ---- 02_runtime_init/src/main.rs -+++ 03_hacky_hello_world/src/main.rs -@@ -104,12 +104,16 @@ - //! - It is implemented in `src/_arch/__arch_name__/cpu/boot.s`. - //! 2. Once finished with architectural setup, the arch code calls `kernel_init()`. - -+#![feature(format_args_nl)] -+#![feature(panic_info_message)] - #![no_main] - #![no_std] - - mod bsp; -+mod console; - mod cpu; - mod panic_wait; -+mod print; - - /// Early init code. - /// -@@ -117,5 +121,7 @@ - /// - /// - Only a single core must be active and running this function. - unsafe fn kernel_init() -> ! { -- panic!() -+ println!("[0] Hello from Rust!"); -+ -+ panic!("Stopping here.") - } - -diff -uNr 02_runtime_init/src/panic_wait.rs 03_hacky_hello_world/src/panic_wait.rs ---- 02_runtime_init/src/panic_wait.rs -+++ 03_hacky_hello_world/src/panic_wait.rs -@@ -4,10 +4,16 @@ - - //! A panic handler that infinitely waits. - --use crate::cpu; -+use crate::{cpu, println}; - use core::panic::PanicInfo; - - #[panic_handler] --fn panic(_info: &PanicInfo) -> ! { -+fn panic(info: &PanicInfo) -> ! { -+ if let Some(args) = info.message() { -+ println!("\nKernel panic: {}", args); -+ } else { -+ println!("\nKernel panic!"); -+ } -+ - cpu::wait_forever() - } - -diff -uNr 02_runtime_init/src/print.rs 03_hacky_hello_world/src/print.rs ---- 02_runtime_init/src/print.rs -+++ 03_hacky_hello_world/src/print.rs -@@ -0,0 +1,38 @@ -+// SPDX-License-Identifier: MIT OR Apache-2.0 -+// -+// Copyright (c) 2018-2022 Andre Richter -+ -+//! Printing. -+ -+use crate::{bsp, console}; -+use core::fmt; -+ -+//-------------------------------------------------------------------------------------------------- -+// Public Code -+//-------------------------------------------------------------------------------------------------- -+ -+#[doc(hidden)] -+pub fn _print(args: fmt::Arguments) { -+ use console::interface::Write; -+ -+ bsp::console::console().write_fmt(args).unwrap(); -+} -+ -+/// Prints without a newline. -+/// -+/// Carbon copy from -+#[macro_export] -+macro_rules! print { -+ ($($arg:tt)*) => ($crate::print::_print(format_args!($($arg)*))); -+} -+ -+/// Prints with a newline. -+/// -+/// Carbon copy from -+#[macro_export] -+macro_rules! println { -+ () => ($crate::print!("\n")); -+ ($($arg:tt)*) => ({ -+ $crate::print::_print(format_args_nl!($($arg)*)); -+ }) -+} - -diff -uNr 02_runtime_init/tests/boot_test_string.rb 03_hacky_hello_world/tests/boot_test_string.rb ---- 02_runtime_init/tests/boot_test_string.rb -+++ 03_hacky_hello_world/tests/boot_test_string.rb -@@ -0,0 +1,3 @@ -+# frozen_string_literal: true -+ -+EXPECTED_PRINT = 'Stopping here' -``` +Please check [the english version](README.md#diff-to-previous), which is kept up-to-date. From 8c661977b8541f403cd1405a5fa4ae6d73d43675 Mon Sep 17 00:00:00 2001 From: Andre Richter Date: Tue, 19 Apr 2022 22:44:01 +0200 Subject: [PATCH 06/75] Use a virtual manifest starting tutorial 12 This is finally possible since the new feature resolver. For reference: https://github.com/rust-lang/rust-analyzer/issues/6197#issuecomment-827564835 --- 12_integrated_testing/Cargo.lock | 4 +- 12_integrated_testing/Cargo.toml | 63 +- 12_integrated_testing/Makefile | 18 +- 12_integrated_testing/README.md | 1352 +---------------- 12_integrated_testing/kernel/Cargo.toml | 58 + 12_integrated_testing/{ => kernel}/build.rs | 0 .../{ => kernel}/src/_arch/aarch64/cpu.rs | 0 .../src/_arch/aarch64/cpu/boot.rs | 0 .../{ => kernel}/src/_arch/aarch64/cpu/boot.s | 0 .../src/_arch/aarch64/exception.rs | 0 .../src/_arch/aarch64/exception.s | 0 .../_arch/aarch64/exception/asynchronous.rs | 0 .../src/_arch/aarch64/memory/mmu.rs | 0 .../aarch64/memory/mmu/translation_table.rs | 0 .../{ => kernel}/src/_arch/aarch64/time.rs | 0 12_integrated_testing/{ => kernel}/src/bsp.rs | 0 .../{ => kernel}/src/bsp/device_driver.rs | 0 .../{ => kernel}/src/bsp/device_driver/bcm.rs | 0 .../src/bsp/device_driver/bcm/bcm2xxx_gpio.rs | 0 .../device_driver/bcm/bcm2xxx_pl011_uart.rs | 0 .../src/bsp/device_driver/common.rs | 0 .../{ => kernel}/src/bsp/raspberrypi.rs | 0 .../src/bsp/raspberrypi/console.rs | 0 .../{ => kernel}/src/bsp/raspberrypi/cpu.rs | 0 .../src/bsp/raspberrypi/driver.rs | 0 .../src/bsp/raspberrypi/kernel.ld | 0 .../src/bsp/raspberrypi/memory.rs | 0 .../src/bsp/raspberrypi/memory/mmu.rs | 0 .../{ => kernel}/src/console.rs | 0 12_integrated_testing/{ => kernel}/src/cpu.rs | 0 .../{ => kernel}/src/cpu/boot.rs | 0 .../{ => kernel}/src/driver.rs | 0 .../{ => kernel}/src/exception.rs | 0 .../src/exception/asynchronous.rs | 0 12_integrated_testing/{ => kernel}/src/lib.rs | 0 .../{ => kernel}/src/main.rs | 0 .../{ => kernel}/src/memory.rs | 0 .../{ => kernel}/src/memory/mmu.rs | 0 .../src/memory/mmu/translation_table.rs | 0 .../{ => kernel}/src/panic_wait.rs | 0 .../{ => kernel}/src/print.rs | 0 .../{ => kernel}/src/synchronization.rs | 0 .../{ => kernel}/src/time.rs | 0 .../{ => kernel}/tests/00_console_sanity.rb | 0 .../{ => kernel}/tests/00_console_sanity.rs | 0 .../{ => kernel}/tests/01_timer_sanity.rs | 0 .../tests/02_exception_sync_page_fault.rs | 0 .../tests/03_exception_restore_sanity.rb | 0 .../tests/03_exception_restore_sanity.rs | 0 .../{ => kernel}/tests/boot_test_string.rb | 0 .../tests/panic_exit_success/mod.rs | 0 .../tests/panic_wait_forever/mod.rs | 0 .../{ => libraries}/test-macros/Cargo.toml | 0 .../{ => libraries}/test-macros/src/lib.rs | 0 .../{ => libraries}/test-types/Cargo.toml | 0 .../{ => libraries}/test-types/src/lib.rs | 0 .../Cargo.lock | 4 +- .../Cargo.toml | 63 +- 13_exceptions_part2_peripheral_IRQs/Makefile | 18 +- 13_exceptions_part2_peripheral_IRQs/README.md | 178 +-- .../kernel/Cargo.toml | 58 + .../{ => kernel}/build.rs | 0 .../{ => kernel}/src/_arch/aarch64/cpu.rs | 0 .../src/_arch/aarch64/cpu/boot.rs | 0 .../{ => kernel}/src/_arch/aarch64/cpu/boot.s | 0 .../{ => kernel}/src/_arch/aarch64/cpu/smp.rs | 0 .../src/_arch/aarch64/exception.rs | 0 .../src/_arch/aarch64/exception.s | 0 .../_arch/aarch64/exception/asynchronous.rs | 0 .../src/_arch/aarch64/memory/mmu.rs | 0 .../aarch64/memory/mmu/translation_table.rs | 0 .../{ => kernel}/src/_arch/aarch64/time.rs | 0 .../{ => kernel}/src/bsp.rs | 0 .../{ => kernel}/src/bsp/device_driver.rs | 0 .../{ => kernel}/src/bsp/device_driver/arm.rs | 0 .../src/bsp/device_driver/arm/gicv2.rs | 0 .../src/bsp/device_driver/arm/gicv2/gicc.rs | 0 .../src/bsp/device_driver/arm/gicv2/gicd.rs | 0 .../{ => kernel}/src/bsp/device_driver/bcm.rs | 0 .../src/bsp/device_driver/bcm/bcm2xxx_gpio.rs | 0 .../bcm/bcm2xxx_interrupt_controller.rs | 0 .../peripheral_ic.rs | 0 .../device_driver/bcm/bcm2xxx_pl011_uart.rs | 0 .../src/bsp/device_driver/common.rs | 0 .../{ => kernel}/src/bsp/raspberrypi.rs | 0 .../src/bsp/raspberrypi/console.rs | 0 .../{ => kernel}/src/bsp/raspberrypi/cpu.rs | 0 .../src/bsp/raspberrypi/driver.rs | 0 .../src/bsp/raspberrypi/exception.rs | 0 .../bsp/raspberrypi/exception/asynchronous.rs | 0 .../src/bsp/raspberrypi/kernel.ld | 0 .../src/bsp/raspberrypi/memory.rs | 0 .../src/bsp/raspberrypi/memory/mmu.rs | 0 .../{ => kernel}/src/console.rs | 0 .../{ => kernel}/src/cpu.rs | 0 .../{ => kernel}/src/cpu/boot.rs | 0 .../{ => kernel}/src/cpu/smp.rs | 0 .../{ => kernel}/src/driver.rs | 0 .../{ => kernel}/src/exception.rs | 0 .../src/exception/asynchronous.rs | 0 .../{ => kernel}/src/lib.rs | 0 .../{ => kernel}/src/main.rs | 0 .../{ => kernel}/src/memory.rs | 0 .../{ => kernel}/src/memory/mmu.rs | 0 .../src/memory/mmu/translation_table.rs | 0 .../{ => kernel}/src/panic_wait.rs | 0 .../{ => kernel}/src/print.rs | 0 .../{ => kernel}/src/state.rs | 0 .../{ => kernel}/src/synchronization.rs | 0 .../{ => kernel}/src/time.rs | 0 .../{ => kernel}/tests/00_console_sanity.rb | 0 .../{ => kernel}/tests/00_console_sanity.rs | 0 .../{ => kernel}/tests/01_timer_sanity.rs | 0 .../tests/02_exception_sync_page_fault.rs | 0 .../tests/03_exception_restore_sanity.rb | 0 .../tests/03_exception_restore_sanity.rs | 0 .../tests/04_exception_irq_sanity.rs | 0 .../{ => kernel}/tests/boot_test_string.rb | 0 .../tests/panic_exit_success/mod.rs | 0 .../tests/panic_wait_forever/mod.rs | 0 .../{ => libraries}/test-macros/Cargo.toml | 0 .../{ => libraries}/test-macros/src/lib.rs | 0 .../{ => libraries}/test-types/Cargo.toml | 0 .../{ => libraries}/test-types/src/lib.rs | 0 14_virtual_mem_part2_mmio_remap/Cargo.lock | 4 +- 14_virtual_mem_part2_mmio_remap/Cargo.toml | 63 +- 14_virtual_mem_part2_mmio_remap/Makefile | 18 +- 14_virtual_mem_part2_mmio_remap/README.md | 187 +-- .../kernel/Cargo.toml | 58 + .../{ => kernel}/build.rs | 0 .../{ => kernel}/src/_arch/aarch64/cpu.rs | 0 .../src/_arch/aarch64/cpu/boot.rs | 0 .../{ => kernel}/src/_arch/aarch64/cpu/boot.s | 0 .../{ => kernel}/src/_arch/aarch64/cpu/smp.rs | 0 .../src/_arch/aarch64/exception.rs | 0 .../src/_arch/aarch64/exception.s | 0 .../_arch/aarch64/exception/asynchronous.rs | 0 .../src/_arch/aarch64/memory/mmu.rs | 0 .../aarch64/memory/mmu/translation_table.rs | 0 .../{ => kernel}/src/_arch/aarch64/time.rs | 0 .../{ => kernel}/src/bsp.rs | 0 .../{ => kernel}/src/bsp/device_driver.rs | 0 .../{ => kernel}/src/bsp/device_driver/arm.rs | 0 .../src/bsp/device_driver/arm/gicv2.rs | 0 .../src/bsp/device_driver/arm/gicv2/gicc.rs | 0 .../src/bsp/device_driver/arm/gicv2/gicd.rs | 0 .../{ => kernel}/src/bsp/device_driver/bcm.rs | 0 .../src/bsp/device_driver/bcm/bcm2xxx_gpio.rs | 0 .../bcm/bcm2xxx_interrupt_controller.rs | 0 .../peripheral_ic.rs | 0 .../device_driver/bcm/bcm2xxx_pl011_uart.rs | 0 .../src/bsp/device_driver/common.rs | 0 .../{ => kernel}/src/bsp/raspberrypi.rs | 0 .../src/bsp/raspberrypi/console.rs | 0 .../{ => kernel}/src/bsp/raspberrypi/cpu.rs | 0 .../src/bsp/raspberrypi/driver.rs | 0 .../src/bsp/raspberrypi/exception.rs | 0 .../bsp/raspberrypi/exception/asynchronous.rs | 0 .../src/bsp/raspberrypi/kernel.ld | 0 .../src/bsp/raspberrypi/memory.rs | 0 .../src/bsp/raspberrypi/memory/mmu.rs | 0 .../{ => kernel}/src/common.rs | 0 .../{ => kernel}/src/console.rs | 0 .../{ => kernel}/src/cpu.rs | 0 .../{ => kernel}/src/cpu/boot.rs | 0 .../{ => kernel}/src/cpu/smp.rs | 0 .../{ => kernel}/src/driver.rs | 0 .../{ => kernel}/src/exception.rs | 0 .../src/exception/asynchronous.rs | 0 .../{ => kernel}/src/lib.rs | 0 .../{ => kernel}/src/main.rs | 0 .../{ => kernel}/src/memory.rs | 0 .../{ => kernel}/src/memory/mmu.rs | 0 .../{ => kernel}/src/memory/mmu/alloc.rs | 0 .../src/memory/mmu/mapping_record.rs | 0 .../src/memory/mmu/translation_table.rs | 0 .../{ => kernel}/src/memory/mmu/types.rs | 0 .../{ => kernel}/src/panic_wait.rs | 0 .../{ => kernel}/src/print.rs | 0 .../{ => kernel}/src/state.rs | 0 .../{ => kernel}/src/synchronization.rs | 0 .../{ => kernel}/src/time.rs | 0 .../{ => kernel}/tests/00_console_sanity.rb | 0 .../{ => kernel}/tests/00_console_sanity.rs | 0 .../{ => kernel}/tests/01_timer_sanity.rs | 0 .../tests/02_exception_sync_page_fault.rs | 0 .../tests/03_exception_restore_sanity.rb | 0 .../tests/03_exception_restore_sanity.rs | 0 .../tests/04_exception_irq_sanity.rs | 0 .../{ => kernel}/tests/boot_test_string.rb | 0 .../tests/panic_exit_success/mod.rs | 0 .../tests/panic_wait_forever/mod.rs | 0 .../{ => libraries}/test-macros/Cargo.toml | 0 .../{ => libraries}/test-macros/src/lib.rs | 0 .../{ => libraries}/test-types/Cargo.toml | 0 .../{ => libraries}/test-types/src/lib.rs | 0 .../Cargo.lock | 4 +- .../Cargo.toml | 63 +- .../Makefile | 20 +- .../README.md | 280 ++-- .../kernel/Cargo.toml | 58 + .../{ => kernel}/build.rs | 0 .../{ => kernel}/src/_arch/aarch64/cpu.rs | 0 .../src/_arch/aarch64/cpu/boot.rs | 0 .../{ => kernel}/src/_arch/aarch64/cpu/boot.s | 0 .../{ => kernel}/src/_arch/aarch64/cpu/smp.rs | 0 .../src/_arch/aarch64/exception.rs | 0 .../src/_arch/aarch64/exception.s | 0 .../_arch/aarch64/exception/asynchronous.rs | 0 .../src/_arch/aarch64/memory/mmu.rs | 0 .../aarch64/memory/mmu/translation_table.rs | 0 .../{ => kernel}/src/_arch/aarch64/time.rs | 0 .../{ => kernel}/src/bsp.rs | 0 .../{ => kernel}/src/bsp/device_driver.rs | 0 .../{ => kernel}/src/bsp/device_driver/arm.rs | 0 .../src/bsp/device_driver/arm/gicv2.rs | 0 .../src/bsp/device_driver/arm/gicv2/gicc.rs | 0 .../src/bsp/device_driver/arm/gicv2/gicd.rs | 0 .../{ => kernel}/src/bsp/device_driver/bcm.rs | 0 .../src/bsp/device_driver/bcm/bcm2xxx_gpio.rs | 0 .../bcm/bcm2xxx_interrupt_controller.rs | 0 .../peripheral_ic.rs | 0 .../device_driver/bcm/bcm2xxx_pl011_uart.rs | 0 .../src/bsp/device_driver/common.rs | 0 .../{ => kernel}/src/bsp/raspberrypi.rs | 0 .../src/bsp/raspberrypi/console.rs | 0 .../{ => kernel}/src/bsp/raspberrypi/cpu.rs | 0 .../src/bsp/raspberrypi/driver.rs | 0 .../src/bsp/raspberrypi/exception.rs | 0 .../bsp/raspberrypi/exception/asynchronous.rs | 0 .../src/bsp/raspberrypi/kernel.ld | 0 .../kernel_virt_addr_space_size.ld | 0 .../src/bsp/raspberrypi/memory.rs | 0 .../src/bsp/raspberrypi/memory/mmu.rs | 0 .../{ => kernel}/src/common.rs | 0 .../{ => kernel}/src/console.rs | 0 .../{ => kernel}/src/cpu.rs | 0 .../{ => kernel}/src/cpu/boot.rs | 0 .../{ => kernel}/src/cpu/smp.rs | 0 .../{ => kernel}/src/driver.rs | 0 .../{ => kernel}/src/exception.rs | 0 .../src/exception/asynchronous.rs | 0 .../{ => kernel}/src/lib.rs | 0 .../{ => kernel}/src/main.rs | 0 .../{ => kernel}/src/memory.rs | 0 .../{ => kernel}/src/memory/mmu.rs | 0 .../{ => kernel}/src/memory/mmu/alloc.rs | 0 .../src/memory/mmu/mapping_record.rs | 0 .../src/memory/mmu/translation_table.rs | 0 .../{ => kernel}/src/memory/mmu/types.rs | 0 .../{ => kernel}/src/panic_wait.rs | 0 .../{ => kernel}/src/print.rs | 0 .../{ => kernel}/src/state.rs | 0 .../{ => kernel}/src/synchronization.rs | 0 .../{ => kernel}/src/time.rs | 0 .../{ => kernel}/tests/00_console_sanity.rb | 0 .../{ => kernel}/tests/00_console_sanity.rs | 0 .../{ => kernel}/tests/01_timer_sanity.rs | 0 .../tests/02_exception_sync_page_fault.rs | 0 .../tests/03_exception_restore_sanity.rb | 0 .../tests/03_exception_restore_sanity.rs | 0 .../tests/04_exception_irq_sanity.rs | 0 .../{ => kernel}/tests/boot_test_string.rb | 0 .../tests/panic_exit_success/mod.rs | 0 .../tests/panic_wait_forever/mod.rs | 0 .../{ => libraries}/test-macros/Cargo.toml | 0 .../{ => libraries}/test-macros/src/lib.rs | 0 .../{ => libraries}/test-types/Cargo.toml | 0 .../{ => libraries}/test-types/src/lib.rs | 0 .../translation_table_tool/arch.rb | 0 .../{ => tools}/translation_table_tool/bsp.rb | 2 +- .../translation_table_tool/generic.rb | 0 .../translation_table_tool/kernel_elf.rb | 0 .../translation_table_tool/main.rb | 0 .../Cargo.lock | 4 +- .../Cargo.toml | 63 +- .../Makefile | 20 +- .../README.md | 102 +- .../kernel/Cargo.toml | 58 + .../{ => kernel}/build.rs | 0 .../{ => kernel}/src/_arch/aarch64/cpu.rs | 0 .../src/_arch/aarch64/cpu/boot.rs | 0 .../{ => kernel}/src/_arch/aarch64/cpu/boot.s | 0 .../{ => kernel}/src/_arch/aarch64/cpu/smp.rs | 0 .../src/_arch/aarch64/exception.rs | 0 .../src/_arch/aarch64/exception.s | 0 .../_arch/aarch64/exception/asynchronous.rs | 0 .../src/_arch/aarch64/memory/mmu.rs | 0 .../aarch64/memory/mmu/translation_table.rs | 0 .../{ => kernel}/src/_arch/aarch64/time.rs | 0 .../{ => kernel}/src/bsp.rs | 0 .../{ => kernel}/src/bsp/device_driver.rs | 0 .../{ => kernel}/src/bsp/device_driver/arm.rs | 0 .../src/bsp/device_driver/arm/gicv2.rs | 0 .../src/bsp/device_driver/arm/gicv2/gicc.rs | 0 .../src/bsp/device_driver/arm/gicv2/gicd.rs | 0 .../{ => kernel}/src/bsp/device_driver/bcm.rs | 0 .../src/bsp/device_driver/bcm/bcm2xxx_gpio.rs | 0 .../bcm/bcm2xxx_interrupt_controller.rs | 0 .../peripheral_ic.rs | 0 .../device_driver/bcm/bcm2xxx_pl011_uart.rs | 0 .../src/bsp/device_driver/common.rs | 0 .../{ => kernel}/src/bsp/raspberrypi.rs | 0 .../src/bsp/raspberrypi/console.rs | 0 .../{ => kernel}/src/bsp/raspberrypi/cpu.rs | 0 .../src/bsp/raspberrypi/driver.rs | 0 .../src/bsp/raspberrypi/exception.rs | 0 .../bsp/raspberrypi/exception/asynchronous.rs | 0 .../src/bsp/raspberrypi/kernel.ld | 0 .../kernel_virt_addr_space_size.ld | 0 .../src/bsp/raspberrypi/memory.rs | 0 .../src/bsp/raspberrypi/memory/mmu.rs | 0 .../{ => kernel}/src/common.rs | 0 .../{ => kernel}/src/console.rs | 0 .../{ => kernel}/src/cpu.rs | 0 .../{ => kernel}/src/cpu/boot.rs | 0 .../{ => kernel}/src/cpu/smp.rs | 0 .../{ => kernel}/src/driver.rs | 0 .../{ => kernel}/src/exception.rs | 0 .../src/exception/asynchronous.rs | 0 .../{ => kernel}/src/lib.rs | 0 .../{ => kernel}/src/main.rs | 0 .../{ => kernel}/src/memory.rs | 0 .../{ => kernel}/src/memory/mmu.rs | 0 .../{ => kernel}/src/memory/mmu/alloc.rs | 0 .../src/memory/mmu/mapping_record.rs | 0 .../src/memory/mmu/translation_table.rs | 0 .../{ => kernel}/src/memory/mmu/types.rs | 0 .../{ => kernel}/src/panic_wait.rs | 0 .../{ => kernel}/src/print.rs | 0 .../{ => kernel}/src/state.rs | 0 .../{ => kernel}/src/synchronization.rs | 0 .../{ => kernel}/src/time.rs | 0 .../{ => kernel}/tests/00_console_sanity.rb | 0 .../{ => kernel}/tests/00_console_sanity.rs | 0 .../{ => kernel}/tests/01_timer_sanity.rs | 0 .../tests/02_exception_sync_page_fault.rs | 0 .../tests/03_exception_restore_sanity.rb | 0 .../tests/03_exception_restore_sanity.rs | 0 .../tests/04_exception_irq_sanity.rs | 0 .../{ => kernel}/tests/boot_test_string.rb | 0 .../tests/panic_exit_success/mod.rs | 0 .../tests/panic_wait_forever/mod.rs | 0 .../{ => libraries}/test-macros/Cargo.toml | 0 .../{ => libraries}/test-macros/src/lib.rs | 0 .../{ => libraries}/test-types/Cargo.toml | 0 .../{ => libraries}/test-types/src/lib.rs | 0 .../translation_table_tool/arch.rb | 0 .../{ => tools}/translation_table_tool/bsp.rb | 2 +- .../translation_table_tool/generic.rb | 0 .../translation_table_tool/kernel_elf.rb | 0 .../translation_table_tool/main.rb | 0 common/tests/dispatch.rb | 7 +- utils/devtool.rb | 10 +- utils/diff_tut_folders.bash | 3 +- 355 files changed, 833 insertions(+), 2009 deletions(-) create mode 100644 12_integrated_testing/kernel/Cargo.toml rename 12_integrated_testing/{ => kernel}/build.rs (100%) rename 12_integrated_testing/{ => kernel}/src/_arch/aarch64/cpu.rs (100%) rename 12_integrated_testing/{ => kernel}/src/_arch/aarch64/cpu/boot.rs (100%) rename 12_integrated_testing/{ => kernel}/src/_arch/aarch64/cpu/boot.s (100%) rename 12_integrated_testing/{ => kernel}/src/_arch/aarch64/exception.rs (100%) rename 12_integrated_testing/{ => kernel}/src/_arch/aarch64/exception.s (100%) rename 12_integrated_testing/{ => kernel}/src/_arch/aarch64/exception/asynchronous.rs (100%) rename 12_integrated_testing/{ => kernel}/src/_arch/aarch64/memory/mmu.rs (100%) rename 12_integrated_testing/{ => kernel}/src/_arch/aarch64/memory/mmu/translation_table.rs (100%) rename 12_integrated_testing/{ => kernel}/src/_arch/aarch64/time.rs (100%) rename 12_integrated_testing/{ => kernel}/src/bsp.rs (100%) rename 12_integrated_testing/{ => kernel}/src/bsp/device_driver.rs (100%) rename 12_integrated_testing/{ => kernel}/src/bsp/device_driver/bcm.rs (100%) rename 12_integrated_testing/{ => kernel}/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs (100%) rename 12_integrated_testing/{ => kernel}/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs (100%) rename 12_integrated_testing/{ => kernel}/src/bsp/device_driver/common.rs (100%) rename 12_integrated_testing/{ => kernel}/src/bsp/raspberrypi.rs (100%) rename 12_integrated_testing/{ => kernel}/src/bsp/raspberrypi/console.rs (100%) rename 12_integrated_testing/{ => kernel}/src/bsp/raspberrypi/cpu.rs (100%) rename 12_integrated_testing/{ => kernel}/src/bsp/raspberrypi/driver.rs (100%) rename 12_integrated_testing/{ => kernel}/src/bsp/raspberrypi/kernel.ld (100%) rename 12_integrated_testing/{ => kernel}/src/bsp/raspberrypi/memory.rs (100%) rename 12_integrated_testing/{ => kernel}/src/bsp/raspberrypi/memory/mmu.rs (100%) rename 12_integrated_testing/{ => kernel}/src/console.rs (100%) rename 12_integrated_testing/{ => kernel}/src/cpu.rs (100%) rename 12_integrated_testing/{ => kernel}/src/cpu/boot.rs (100%) rename 12_integrated_testing/{ => kernel}/src/driver.rs (100%) rename 12_integrated_testing/{ => kernel}/src/exception.rs (100%) rename 12_integrated_testing/{ => kernel}/src/exception/asynchronous.rs (100%) rename 12_integrated_testing/{ => kernel}/src/lib.rs (100%) rename 12_integrated_testing/{ => kernel}/src/main.rs (100%) rename 12_integrated_testing/{ => kernel}/src/memory.rs (100%) rename 12_integrated_testing/{ => kernel}/src/memory/mmu.rs (100%) rename 12_integrated_testing/{ => kernel}/src/memory/mmu/translation_table.rs (100%) rename 12_integrated_testing/{ => kernel}/src/panic_wait.rs (100%) rename 12_integrated_testing/{ => kernel}/src/print.rs (100%) rename 12_integrated_testing/{ => kernel}/src/synchronization.rs (100%) rename 12_integrated_testing/{ => kernel}/src/time.rs (100%) rename 12_integrated_testing/{ => kernel}/tests/00_console_sanity.rb (100%) rename 12_integrated_testing/{ => kernel}/tests/00_console_sanity.rs (100%) rename 12_integrated_testing/{ => kernel}/tests/01_timer_sanity.rs (100%) rename 12_integrated_testing/{ => kernel}/tests/02_exception_sync_page_fault.rs (100%) rename 12_integrated_testing/{ => kernel}/tests/03_exception_restore_sanity.rb (100%) rename 12_integrated_testing/{ => kernel}/tests/03_exception_restore_sanity.rs (100%) rename 12_integrated_testing/{ => kernel}/tests/boot_test_string.rb (100%) rename 12_integrated_testing/{ => kernel}/tests/panic_exit_success/mod.rs (100%) rename 12_integrated_testing/{ => kernel}/tests/panic_wait_forever/mod.rs (100%) rename 12_integrated_testing/{ => libraries}/test-macros/Cargo.toml (100%) rename 12_integrated_testing/{ => libraries}/test-macros/src/lib.rs (100%) rename 12_integrated_testing/{ => libraries}/test-types/Cargo.toml (100%) rename 12_integrated_testing/{ => libraries}/test-types/src/lib.rs (100%) create mode 100644 13_exceptions_part2_peripheral_IRQs/kernel/Cargo.toml rename 13_exceptions_part2_peripheral_IRQs/{ => kernel}/build.rs (100%) rename 13_exceptions_part2_peripheral_IRQs/{ => kernel}/src/_arch/aarch64/cpu.rs (100%) rename 13_exceptions_part2_peripheral_IRQs/{ => kernel}/src/_arch/aarch64/cpu/boot.rs (100%) rename 13_exceptions_part2_peripheral_IRQs/{ => kernel}/src/_arch/aarch64/cpu/boot.s (100%) rename 13_exceptions_part2_peripheral_IRQs/{ => kernel}/src/_arch/aarch64/cpu/smp.rs (100%) rename 13_exceptions_part2_peripheral_IRQs/{ => kernel}/src/_arch/aarch64/exception.rs (100%) rename 13_exceptions_part2_peripheral_IRQs/{ => kernel}/src/_arch/aarch64/exception.s (100%) rename 13_exceptions_part2_peripheral_IRQs/{ => kernel}/src/_arch/aarch64/exception/asynchronous.rs (100%) rename 13_exceptions_part2_peripheral_IRQs/{ => kernel}/src/_arch/aarch64/memory/mmu.rs (100%) rename 13_exceptions_part2_peripheral_IRQs/{ => kernel}/src/_arch/aarch64/memory/mmu/translation_table.rs (100%) rename 13_exceptions_part2_peripheral_IRQs/{ => kernel}/src/_arch/aarch64/time.rs (100%) rename 13_exceptions_part2_peripheral_IRQs/{ => kernel}/src/bsp.rs (100%) rename 13_exceptions_part2_peripheral_IRQs/{ => kernel}/src/bsp/device_driver.rs (100%) rename 13_exceptions_part2_peripheral_IRQs/{ => kernel}/src/bsp/device_driver/arm.rs (100%) rename 13_exceptions_part2_peripheral_IRQs/{ => kernel}/src/bsp/device_driver/arm/gicv2.rs (100%) rename 13_exceptions_part2_peripheral_IRQs/{ => kernel}/src/bsp/device_driver/arm/gicv2/gicc.rs (100%) rename 13_exceptions_part2_peripheral_IRQs/{ => kernel}/src/bsp/device_driver/arm/gicv2/gicd.rs (100%) rename 13_exceptions_part2_peripheral_IRQs/{ => kernel}/src/bsp/device_driver/bcm.rs (100%) rename 13_exceptions_part2_peripheral_IRQs/{ => kernel}/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs (100%) rename 13_exceptions_part2_peripheral_IRQs/{ => kernel}/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs (100%) rename 13_exceptions_part2_peripheral_IRQs/{ => kernel}/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs (100%) rename 13_exceptions_part2_peripheral_IRQs/{ => kernel}/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs (100%) rename 13_exceptions_part2_peripheral_IRQs/{ => kernel}/src/bsp/device_driver/common.rs (100%) rename 13_exceptions_part2_peripheral_IRQs/{ => kernel}/src/bsp/raspberrypi.rs (100%) rename 13_exceptions_part2_peripheral_IRQs/{ => kernel}/src/bsp/raspberrypi/console.rs (100%) rename 13_exceptions_part2_peripheral_IRQs/{ => kernel}/src/bsp/raspberrypi/cpu.rs (100%) rename 13_exceptions_part2_peripheral_IRQs/{ => kernel}/src/bsp/raspberrypi/driver.rs (100%) rename 13_exceptions_part2_peripheral_IRQs/{ => kernel}/src/bsp/raspberrypi/exception.rs (100%) rename 13_exceptions_part2_peripheral_IRQs/{ => kernel}/src/bsp/raspberrypi/exception/asynchronous.rs (100%) rename 13_exceptions_part2_peripheral_IRQs/{ => kernel}/src/bsp/raspberrypi/kernel.ld (100%) rename 13_exceptions_part2_peripheral_IRQs/{ => kernel}/src/bsp/raspberrypi/memory.rs (100%) rename 13_exceptions_part2_peripheral_IRQs/{ => kernel}/src/bsp/raspberrypi/memory/mmu.rs (100%) rename 13_exceptions_part2_peripheral_IRQs/{ => kernel}/src/console.rs (100%) rename 13_exceptions_part2_peripheral_IRQs/{ => kernel}/src/cpu.rs (100%) rename 13_exceptions_part2_peripheral_IRQs/{ => kernel}/src/cpu/boot.rs (100%) rename 13_exceptions_part2_peripheral_IRQs/{ => kernel}/src/cpu/smp.rs (100%) rename 13_exceptions_part2_peripheral_IRQs/{ => kernel}/src/driver.rs (100%) rename 13_exceptions_part2_peripheral_IRQs/{ => kernel}/src/exception.rs (100%) rename 13_exceptions_part2_peripheral_IRQs/{ => kernel}/src/exception/asynchronous.rs (100%) rename 13_exceptions_part2_peripheral_IRQs/{ => kernel}/src/lib.rs (100%) rename 13_exceptions_part2_peripheral_IRQs/{ => kernel}/src/main.rs (100%) rename 13_exceptions_part2_peripheral_IRQs/{ => kernel}/src/memory.rs (100%) rename 13_exceptions_part2_peripheral_IRQs/{ => kernel}/src/memory/mmu.rs (100%) rename 13_exceptions_part2_peripheral_IRQs/{ => kernel}/src/memory/mmu/translation_table.rs (100%) rename 13_exceptions_part2_peripheral_IRQs/{ => kernel}/src/panic_wait.rs (100%) rename 13_exceptions_part2_peripheral_IRQs/{ => kernel}/src/print.rs (100%) rename 13_exceptions_part2_peripheral_IRQs/{ => kernel}/src/state.rs (100%) rename 13_exceptions_part2_peripheral_IRQs/{ => kernel}/src/synchronization.rs (100%) rename 13_exceptions_part2_peripheral_IRQs/{ => kernel}/src/time.rs (100%) rename 13_exceptions_part2_peripheral_IRQs/{ => kernel}/tests/00_console_sanity.rb (100%) rename 13_exceptions_part2_peripheral_IRQs/{ => kernel}/tests/00_console_sanity.rs (100%) rename 13_exceptions_part2_peripheral_IRQs/{ => kernel}/tests/01_timer_sanity.rs (100%) rename 13_exceptions_part2_peripheral_IRQs/{ => kernel}/tests/02_exception_sync_page_fault.rs (100%) rename 13_exceptions_part2_peripheral_IRQs/{ => kernel}/tests/03_exception_restore_sanity.rb (100%) rename 13_exceptions_part2_peripheral_IRQs/{ => kernel}/tests/03_exception_restore_sanity.rs (100%) rename 13_exceptions_part2_peripheral_IRQs/{ => kernel}/tests/04_exception_irq_sanity.rs (100%) rename 13_exceptions_part2_peripheral_IRQs/{ => kernel}/tests/boot_test_string.rb (100%) rename 13_exceptions_part2_peripheral_IRQs/{ => kernel}/tests/panic_exit_success/mod.rs (100%) rename 13_exceptions_part2_peripheral_IRQs/{ => kernel}/tests/panic_wait_forever/mod.rs (100%) rename 13_exceptions_part2_peripheral_IRQs/{ => libraries}/test-macros/Cargo.toml (100%) rename 13_exceptions_part2_peripheral_IRQs/{ => libraries}/test-macros/src/lib.rs (100%) rename 13_exceptions_part2_peripheral_IRQs/{ => libraries}/test-types/Cargo.toml (100%) rename 13_exceptions_part2_peripheral_IRQs/{ => libraries}/test-types/src/lib.rs (100%) create mode 100644 14_virtual_mem_part2_mmio_remap/kernel/Cargo.toml rename 14_virtual_mem_part2_mmio_remap/{ => kernel}/build.rs (100%) rename 14_virtual_mem_part2_mmio_remap/{ => kernel}/src/_arch/aarch64/cpu.rs (100%) rename 14_virtual_mem_part2_mmio_remap/{ => kernel}/src/_arch/aarch64/cpu/boot.rs (100%) rename 14_virtual_mem_part2_mmio_remap/{ => kernel}/src/_arch/aarch64/cpu/boot.s (100%) rename 14_virtual_mem_part2_mmio_remap/{ => kernel}/src/_arch/aarch64/cpu/smp.rs (100%) rename 14_virtual_mem_part2_mmio_remap/{ => kernel}/src/_arch/aarch64/exception.rs (100%) rename 14_virtual_mem_part2_mmio_remap/{ => kernel}/src/_arch/aarch64/exception.s (100%) rename 14_virtual_mem_part2_mmio_remap/{ => kernel}/src/_arch/aarch64/exception/asynchronous.rs (100%) rename 14_virtual_mem_part2_mmio_remap/{ => kernel}/src/_arch/aarch64/memory/mmu.rs (100%) rename 14_virtual_mem_part2_mmio_remap/{ => kernel}/src/_arch/aarch64/memory/mmu/translation_table.rs (100%) rename 14_virtual_mem_part2_mmio_remap/{ => kernel}/src/_arch/aarch64/time.rs (100%) rename 14_virtual_mem_part2_mmio_remap/{ => kernel}/src/bsp.rs (100%) rename 14_virtual_mem_part2_mmio_remap/{ => kernel}/src/bsp/device_driver.rs (100%) rename 14_virtual_mem_part2_mmio_remap/{ => kernel}/src/bsp/device_driver/arm.rs (100%) rename 14_virtual_mem_part2_mmio_remap/{ => kernel}/src/bsp/device_driver/arm/gicv2.rs (100%) rename 14_virtual_mem_part2_mmio_remap/{ => kernel}/src/bsp/device_driver/arm/gicv2/gicc.rs (100%) rename 14_virtual_mem_part2_mmio_remap/{ => kernel}/src/bsp/device_driver/arm/gicv2/gicd.rs (100%) rename 14_virtual_mem_part2_mmio_remap/{ => kernel}/src/bsp/device_driver/bcm.rs (100%) rename 14_virtual_mem_part2_mmio_remap/{ => kernel}/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs (100%) rename 14_virtual_mem_part2_mmio_remap/{ => kernel}/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs (100%) rename 14_virtual_mem_part2_mmio_remap/{ => kernel}/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs (100%) rename 14_virtual_mem_part2_mmio_remap/{ => kernel}/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs (100%) rename 14_virtual_mem_part2_mmio_remap/{ => kernel}/src/bsp/device_driver/common.rs (100%) rename 14_virtual_mem_part2_mmio_remap/{ => kernel}/src/bsp/raspberrypi.rs (100%) rename 14_virtual_mem_part2_mmio_remap/{ => kernel}/src/bsp/raspberrypi/console.rs (100%) rename 14_virtual_mem_part2_mmio_remap/{ => kernel}/src/bsp/raspberrypi/cpu.rs (100%) rename 14_virtual_mem_part2_mmio_remap/{ => kernel}/src/bsp/raspberrypi/driver.rs (100%) rename 14_virtual_mem_part2_mmio_remap/{ => kernel}/src/bsp/raspberrypi/exception.rs (100%) rename 14_virtual_mem_part2_mmio_remap/{ => kernel}/src/bsp/raspberrypi/exception/asynchronous.rs (100%) rename 14_virtual_mem_part2_mmio_remap/{ => kernel}/src/bsp/raspberrypi/kernel.ld (100%) rename 14_virtual_mem_part2_mmio_remap/{ => kernel}/src/bsp/raspberrypi/memory.rs (100%) rename 14_virtual_mem_part2_mmio_remap/{ => kernel}/src/bsp/raspberrypi/memory/mmu.rs (100%) rename 14_virtual_mem_part2_mmio_remap/{ => kernel}/src/common.rs (100%) rename 14_virtual_mem_part2_mmio_remap/{ => kernel}/src/console.rs (100%) rename 14_virtual_mem_part2_mmio_remap/{ => kernel}/src/cpu.rs (100%) rename 14_virtual_mem_part2_mmio_remap/{ => kernel}/src/cpu/boot.rs (100%) rename 14_virtual_mem_part2_mmio_remap/{ => kernel}/src/cpu/smp.rs (100%) rename 14_virtual_mem_part2_mmio_remap/{ => kernel}/src/driver.rs (100%) rename 14_virtual_mem_part2_mmio_remap/{ => kernel}/src/exception.rs (100%) rename 14_virtual_mem_part2_mmio_remap/{ => kernel}/src/exception/asynchronous.rs (100%) rename 14_virtual_mem_part2_mmio_remap/{ => kernel}/src/lib.rs (100%) rename 14_virtual_mem_part2_mmio_remap/{ => kernel}/src/main.rs (100%) rename 14_virtual_mem_part2_mmio_remap/{ => kernel}/src/memory.rs (100%) rename 14_virtual_mem_part2_mmio_remap/{ => kernel}/src/memory/mmu.rs (100%) rename 14_virtual_mem_part2_mmio_remap/{ => kernel}/src/memory/mmu/alloc.rs (100%) rename 14_virtual_mem_part2_mmio_remap/{ => kernel}/src/memory/mmu/mapping_record.rs (100%) rename 14_virtual_mem_part2_mmio_remap/{ => kernel}/src/memory/mmu/translation_table.rs (100%) rename 14_virtual_mem_part2_mmio_remap/{ => kernel}/src/memory/mmu/types.rs (100%) rename 14_virtual_mem_part2_mmio_remap/{ => kernel}/src/panic_wait.rs (100%) rename 14_virtual_mem_part2_mmio_remap/{ => kernel}/src/print.rs (100%) rename 14_virtual_mem_part2_mmio_remap/{ => kernel}/src/state.rs (100%) rename 14_virtual_mem_part2_mmio_remap/{ => kernel}/src/synchronization.rs (100%) rename 14_virtual_mem_part2_mmio_remap/{ => kernel}/src/time.rs (100%) rename 14_virtual_mem_part2_mmio_remap/{ => kernel}/tests/00_console_sanity.rb (100%) rename 14_virtual_mem_part2_mmio_remap/{ => kernel}/tests/00_console_sanity.rs (100%) rename 14_virtual_mem_part2_mmio_remap/{ => kernel}/tests/01_timer_sanity.rs (100%) rename 14_virtual_mem_part2_mmio_remap/{ => kernel}/tests/02_exception_sync_page_fault.rs (100%) rename 14_virtual_mem_part2_mmio_remap/{ => kernel}/tests/03_exception_restore_sanity.rb (100%) rename 14_virtual_mem_part2_mmio_remap/{ => kernel}/tests/03_exception_restore_sanity.rs (100%) rename 14_virtual_mem_part2_mmio_remap/{ => kernel}/tests/04_exception_irq_sanity.rs (100%) rename 14_virtual_mem_part2_mmio_remap/{ => kernel}/tests/boot_test_string.rb (100%) rename 14_virtual_mem_part2_mmio_remap/{ => kernel}/tests/panic_exit_success/mod.rs (100%) rename 14_virtual_mem_part2_mmio_remap/{ => kernel}/tests/panic_wait_forever/mod.rs (100%) rename 14_virtual_mem_part2_mmio_remap/{ => libraries}/test-macros/Cargo.toml (100%) rename 14_virtual_mem_part2_mmio_remap/{ => libraries}/test-macros/src/lib.rs (100%) rename 14_virtual_mem_part2_mmio_remap/{ => libraries}/test-types/Cargo.toml (100%) rename 14_virtual_mem_part2_mmio_remap/{ => libraries}/test-types/src/lib.rs (100%) create mode 100644 15_virtual_mem_part3_precomputed_tables/kernel/Cargo.toml rename 15_virtual_mem_part3_precomputed_tables/{ => kernel}/build.rs (100%) rename 15_virtual_mem_part3_precomputed_tables/{ => kernel}/src/_arch/aarch64/cpu.rs (100%) rename 15_virtual_mem_part3_precomputed_tables/{ => kernel}/src/_arch/aarch64/cpu/boot.rs (100%) rename 15_virtual_mem_part3_precomputed_tables/{ => kernel}/src/_arch/aarch64/cpu/boot.s (100%) rename 15_virtual_mem_part3_precomputed_tables/{ => kernel}/src/_arch/aarch64/cpu/smp.rs (100%) rename 15_virtual_mem_part3_precomputed_tables/{ => kernel}/src/_arch/aarch64/exception.rs (100%) rename 15_virtual_mem_part3_precomputed_tables/{ => kernel}/src/_arch/aarch64/exception.s (100%) rename 15_virtual_mem_part3_precomputed_tables/{ => kernel}/src/_arch/aarch64/exception/asynchronous.rs (100%) rename 15_virtual_mem_part3_precomputed_tables/{ => kernel}/src/_arch/aarch64/memory/mmu.rs (100%) rename 15_virtual_mem_part3_precomputed_tables/{ => kernel}/src/_arch/aarch64/memory/mmu/translation_table.rs (100%) rename 15_virtual_mem_part3_precomputed_tables/{ => kernel}/src/_arch/aarch64/time.rs (100%) rename 15_virtual_mem_part3_precomputed_tables/{ => kernel}/src/bsp.rs (100%) rename 15_virtual_mem_part3_precomputed_tables/{ => kernel}/src/bsp/device_driver.rs (100%) rename 15_virtual_mem_part3_precomputed_tables/{ => kernel}/src/bsp/device_driver/arm.rs (100%) rename 15_virtual_mem_part3_precomputed_tables/{ => kernel}/src/bsp/device_driver/arm/gicv2.rs (100%) rename 15_virtual_mem_part3_precomputed_tables/{ => kernel}/src/bsp/device_driver/arm/gicv2/gicc.rs (100%) rename 15_virtual_mem_part3_precomputed_tables/{ => kernel}/src/bsp/device_driver/arm/gicv2/gicd.rs (100%) rename 15_virtual_mem_part3_precomputed_tables/{ => kernel}/src/bsp/device_driver/bcm.rs (100%) rename 15_virtual_mem_part3_precomputed_tables/{ => kernel}/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs (100%) rename 15_virtual_mem_part3_precomputed_tables/{ => kernel}/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs (100%) rename 15_virtual_mem_part3_precomputed_tables/{ => kernel}/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs (100%) rename 15_virtual_mem_part3_precomputed_tables/{ => kernel}/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs (100%) rename 15_virtual_mem_part3_precomputed_tables/{ => kernel}/src/bsp/device_driver/common.rs (100%) rename 15_virtual_mem_part3_precomputed_tables/{ => kernel}/src/bsp/raspberrypi.rs (100%) rename 15_virtual_mem_part3_precomputed_tables/{ => kernel}/src/bsp/raspberrypi/console.rs (100%) rename 15_virtual_mem_part3_precomputed_tables/{ => kernel}/src/bsp/raspberrypi/cpu.rs (100%) rename 15_virtual_mem_part3_precomputed_tables/{ => kernel}/src/bsp/raspberrypi/driver.rs (100%) rename 15_virtual_mem_part3_precomputed_tables/{ => kernel}/src/bsp/raspberrypi/exception.rs (100%) rename 15_virtual_mem_part3_precomputed_tables/{ => kernel}/src/bsp/raspberrypi/exception/asynchronous.rs (100%) rename 15_virtual_mem_part3_precomputed_tables/{ => kernel}/src/bsp/raspberrypi/kernel.ld (100%) rename 15_virtual_mem_part3_precomputed_tables/{ => kernel}/src/bsp/raspberrypi/kernel_virt_addr_space_size.ld (100%) rename 15_virtual_mem_part3_precomputed_tables/{ => kernel}/src/bsp/raspberrypi/memory.rs (100%) rename 15_virtual_mem_part3_precomputed_tables/{ => kernel}/src/bsp/raspberrypi/memory/mmu.rs (100%) rename 15_virtual_mem_part3_precomputed_tables/{ => kernel}/src/common.rs (100%) rename 15_virtual_mem_part3_precomputed_tables/{ => kernel}/src/console.rs (100%) rename 15_virtual_mem_part3_precomputed_tables/{ => kernel}/src/cpu.rs (100%) rename 15_virtual_mem_part3_precomputed_tables/{ => kernel}/src/cpu/boot.rs (100%) rename 15_virtual_mem_part3_precomputed_tables/{ => kernel}/src/cpu/smp.rs (100%) rename 15_virtual_mem_part3_precomputed_tables/{ => kernel}/src/driver.rs (100%) rename 15_virtual_mem_part3_precomputed_tables/{ => kernel}/src/exception.rs (100%) rename 15_virtual_mem_part3_precomputed_tables/{ => kernel}/src/exception/asynchronous.rs (100%) rename 15_virtual_mem_part3_precomputed_tables/{ => kernel}/src/lib.rs (100%) rename 15_virtual_mem_part3_precomputed_tables/{ => kernel}/src/main.rs (100%) rename 15_virtual_mem_part3_precomputed_tables/{ => kernel}/src/memory.rs (100%) rename 15_virtual_mem_part3_precomputed_tables/{ => kernel}/src/memory/mmu.rs (100%) rename 15_virtual_mem_part3_precomputed_tables/{ => kernel}/src/memory/mmu/alloc.rs (100%) rename 15_virtual_mem_part3_precomputed_tables/{ => kernel}/src/memory/mmu/mapping_record.rs (100%) rename 15_virtual_mem_part3_precomputed_tables/{ => kernel}/src/memory/mmu/translation_table.rs (100%) rename 15_virtual_mem_part3_precomputed_tables/{ => kernel}/src/memory/mmu/types.rs (100%) rename 15_virtual_mem_part3_precomputed_tables/{ => kernel}/src/panic_wait.rs (100%) rename 15_virtual_mem_part3_precomputed_tables/{ => kernel}/src/print.rs (100%) rename 15_virtual_mem_part3_precomputed_tables/{ => kernel}/src/state.rs (100%) rename 15_virtual_mem_part3_precomputed_tables/{ => kernel}/src/synchronization.rs (100%) rename 15_virtual_mem_part3_precomputed_tables/{ => kernel}/src/time.rs (100%) rename 15_virtual_mem_part3_precomputed_tables/{ => kernel}/tests/00_console_sanity.rb (100%) rename 15_virtual_mem_part3_precomputed_tables/{ => kernel}/tests/00_console_sanity.rs (100%) rename 15_virtual_mem_part3_precomputed_tables/{ => kernel}/tests/01_timer_sanity.rs (100%) rename 15_virtual_mem_part3_precomputed_tables/{ => kernel}/tests/02_exception_sync_page_fault.rs (100%) rename 15_virtual_mem_part3_precomputed_tables/{ => kernel}/tests/03_exception_restore_sanity.rb (100%) rename 15_virtual_mem_part3_precomputed_tables/{ => kernel}/tests/03_exception_restore_sanity.rs (100%) rename 15_virtual_mem_part3_precomputed_tables/{ => kernel}/tests/04_exception_irq_sanity.rs (100%) rename 15_virtual_mem_part3_precomputed_tables/{ => kernel}/tests/boot_test_string.rb (100%) rename 15_virtual_mem_part3_precomputed_tables/{ => kernel}/tests/panic_exit_success/mod.rs (100%) rename 15_virtual_mem_part3_precomputed_tables/{ => kernel}/tests/panic_wait_forever/mod.rs (100%) rename 15_virtual_mem_part3_precomputed_tables/{ => libraries}/test-macros/Cargo.toml (100%) rename 15_virtual_mem_part3_precomputed_tables/{ => libraries}/test-macros/src/lib.rs (100%) rename 15_virtual_mem_part3_precomputed_tables/{ => libraries}/test-types/Cargo.toml (100%) rename 15_virtual_mem_part3_precomputed_tables/{ => libraries}/test-types/src/lib.rs (100%) rename 15_virtual_mem_part3_precomputed_tables/{ => tools}/translation_table_tool/arch.rb (100%) rename 15_virtual_mem_part3_precomputed_tables/{ => tools}/translation_table_tool/bsp.rb (94%) rename 15_virtual_mem_part3_precomputed_tables/{ => tools}/translation_table_tool/generic.rb (100%) rename 15_virtual_mem_part3_precomputed_tables/{ => tools}/translation_table_tool/kernel_elf.rb (100%) rename 15_virtual_mem_part3_precomputed_tables/{ => tools}/translation_table_tool/main.rb (100%) create mode 100644 16_virtual_mem_part4_higher_half_kernel/kernel/Cargo.toml rename 16_virtual_mem_part4_higher_half_kernel/{ => kernel}/build.rs (100%) rename 16_virtual_mem_part4_higher_half_kernel/{ => kernel}/src/_arch/aarch64/cpu.rs (100%) rename 16_virtual_mem_part4_higher_half_kernel/{ => kernel}/src/_arch/aarch64/cpu/boot.rs (100%) rename 16_virtual_mem_part4_higher_half_kernel/{ => kernel}/src/_arch/aarch64/cpu/boot.s (100%) rename 16_virtual_mem_part4_higher_half_kernel/{ => kernel}/src/_arch/aarch64/cpu/smp.rs (100%) rename 16_virtual_mem_part4_higher_half_kernel/{ => kernel}/src/_arch/aarch64/exception.rs (100%) rename 16_virtual_mem_part4_higher_half_kernel/{ => kernel}/src/_arch/aarch64/exception.s (100%) rename 16_virtual_mem_part4_higher_half_kernel/{ => kernel}/src/_arch/aarch64/exception/asynchronous.rs (100%) rename 16_virtual_mem_part4_higher_half_kernel/{ => kernel}/src/_arch/aarch64/memory/mmu.rs (100%) rename 16_virtual_mem_part4_higher_half_kernel/{ => kernel}/src/_arch/aarch64/memory/mmu/translation_table.rs (100%) rename 16_virtual_mem_part4_higher_half_kernel/{ => kernel}/src/_arch/aarch64/time.rs (100%) rename 16_virtual_mem_part4_higher_half_kernel/{ => kernel}/src/bsp.rs (100%) rename 16_virtual_mem_part4_higher_half_kernel/{ => kernel}/src/bsp/device_driver.rs (100%) rename 16_virtual_mem_part4_higher_half_kernel/{ => kernel}/src/bsp/device_driver/arm.rs (100%) rename 16_virtual_mem_part4_higher_half_kernel/{ => kernel}/src/bsp/device_driver/arm/gicv2.rs (100%) rename 16_virtual_mem_part4_higher_half_kernel/{ => kernel}/src/bsp/device_driver/arm/gicv2/gicc.rs (100%) rename 16_virtual_mem_part4_higher_half_kernel/{ => kernel}/src/bsp/device_driver/arm/gicv2/gicd.rs (100%) rename 16_virtual_mem_part4_higher_half_kernel/{ => kernel}/src/bsp/device_driver/bcm.rs (100%) rename 16_virtual_mem_part4_higher_half_kernel/{ => kernel}/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs (100%) rename 16_virtual_mem_part4_higher_half_kernel/{ => kernel}/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs (100%) rename 16_virtual_mem_part4_higher_half_kernel/{ => kernel}/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs (100%) rename 16_virtual_mem_part4_higher_half_kernel/{ => kernel}/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs (100%) rename 16_virtual_mem_part4_higher_half_kernel/{ => kernel}/src/bsp/device_driver/common.rs (100%) rename 16_virtual_mem_part4_higher_half_kernel/{ => kernel}/src/bsp/raspberrypi.rs (100%) rename 16_virtual_mem_part4_higher_half_kernel/{ => kernel}/src/bsp/raspberrypi/console.rs (100%) rename 16_virtual_mem_part4_higher_half_kernel/{ => kernel}/src/bsp/raspberrypi/cpu.rs (100%) rename 16_virtual_mem_part4_higher_half_kernel/{ => kernel}/src/bsp/raspberrypi/driver.rs (100%) rename 16_virtual_mem_part4_higher_half_kernel/{ => kernel}/src/bsp/raspberrypi/exception.rs (100%) rename 16_virtual_mem_part4_higher_half_kernel/{ => kernel}/src/bsp/raspberrypi/exception/asynchronous.rs (100%) rename 16_virtual_mem_part4_higher_half_kernel/{ => kernel}/src/bsp/raspberrypi/kernel.ld (100%) rename 16_virtual_mem_part4_higher_half_kernel/{ => kernel}/src/bsp/raspberrypi/kernel_virt_addr_space_size.ld (100%) rename 16_virtual_mem_part4_higher_half_kernel/{ => kernel}/src/bsp/raspberrypi/memory.rs (100%) rename 16_virtual_mem_part4_higher_half_kernel/{ => kernel}/src/bsp/raspberrypi/memory/mmu.rs (100%) rename 16_virtual_mem_part4_higher_half_kernel/{ => kernel}/src/common.rs (100%) rename 16_virtual_mem_part4_higher_half_kernel/{ => kernel}/src/console.rs (100%) rename 16_virtual_mem_part4_higher_half_kernel/{ => kernel}/src/cpu.rs (100%) rename 16_virtual_mem_part4_higher_half_kernel/{ => kernel}/src/cpu/boot.rs (100%) rename 16_virtual_mem_part4_higher_half_kernel/{ => kernel}/src/cpu/smp.rs (100%) rename 16_virtual_mem_part4_higher_half_kernel/{ => kernel}/src/driver.rs (100%) rename 16_virtual_mem_part4_higher_half_kernel/{ => kernel}/src/exception.rs (100%) rename 16_virtual_mem_part4_higher_half_kernel/{ => kernel}/src/exception/asynchronous.rs (100%) rename 16_virtual_mem_part4_higher_half_kernel/{ => kernel}/src/lib.rs (100%) rename 16_virtual_mem_part4_higher_half_kernel/{ => kernel}/src/main.rs (100%) rename 16_virtual_mem_part4_higher_half_kernel/{ => kernel}/src/memory.rs (100%) rename 16_virtual_mem_part4_higher_half_kernel/{ => kernel}/src/memory/mmu.rs (100%) rename 16_virtual_mem_part4_higher_half_kernel/{ => kernel}/src/memory/mmu/alloc.rs (100%) rename 16_virtual_mem_part4_higher_half_kernel/{ => kernel}/src/memory/mmu/mapping_record.rs (100%) rename 16_virtual_mem_part4_higher_half_kernel/{ => kernel}/src/memory/mmu/translation_table.rs (100%) rename 16_virtual_mem_part4_higher_half_kernel/{ => kernel}/src/memory/mmu/types.rs (100%) rename 16_virtual_mem_part4_higher_half_kernel/{ => kernel}/src/panic_wait.rs (100%) rename 16_virtual_mem_part4_higher_half_kernel/{ => kernel}/src/print.rs (100%) rename 16_virtual_mem_part4_higher_half_kernel/{ => kernel}/src/state.rs (100%) rename 16_virtual_mem_part4_higher_half_kernel/{ => kernel}/src/synchronization.rs (100%) rename 16_virtual_mem_part4_higher_half_kernel/{ => kernel}/src/time.rs (100%) rename 16_virtual_mem_part4_higher_half_kernel/{ => kernel}/tests/00_console_sanity.rb (100%) rename 16_virtual_mem_part4_higher_half_kernel/{ => kernel}/tests/00_console_sanity.rs (100%) rename 16_virtual_mem_part4_higher_half_kernel/{ => kernel}/tests/01_timer_sanity.rs (100%) rename 16_virtual_mem_part4_higher_half_kernel/{ => kernel}/tests/02_exception_sync_page_fault.rs (100%) rename 16_virtual_mem_part4_higher_half_kernel/{ => kernel}/tests/03_exception_restore_sanity.rb (100%) rename 16_virtual_mem_part4_higher_half_kernel/{ => kernel}/tests/03_exception_restore_sanity.rs (100%) rename 16_virtual_mem_part4_higher_half_kernel/{ => kernel}/tests/04_exception_irq_sanity.rs (100%) rename 16_virtual_mem_part4_higher_half_kernel/{ => kernel}/tests/boot_test_string.rb (100%) rename 16_virtual_mem_part4_higher_half_kernel/{ => kernel}/tests/panic_exit_success/mod.rs (100%) rename 16_virtual_mem_part4_higher_half_kernel/{ => kernel}/tests/panic_wait_forever/mod.rs (100%) rename 16_virtual_mem_part4_higher_half_kernel/{ => libraries}/test-macros/Cargo.toml (100%) rename 16_virtual_mem_part4_higher_half_kernel/{ => libraries}/test-macros/src/lib.rs (100%) rename 16_virtual_mem_part4_higher_half_kernel/{ => libraries}/test-types/Cargo.toml (100%) rename 16_virtual_mem_part4_higher_half_kernel/{ => libraries}/test-types/src/lib.rs (100%) rename 16_virtual_mem_part4_higher_half_kernel/{ => tools}/translation_table_tool/arch.rb (100%) rename 16_virtual_mem_part4_higher_half_kernel/{ => tools}/translation_table_tool/bsp.rb (94%) rename 16_virtual_mem_part4_higher_half_kernel/{ => tools}/translation_table_tool/generic.rb (100%) rename 16_virtual_mem_part4_higher_half_kernel/{ => tools}/translation_table_tool/kernel_elf.rb (100%) rename 16_virtual_mem_part4_higher_half_kernel/{ => tools}/translation_table_tool/main.rb (100%) diff --git a/12_integrated_testing/Cargo.lock b/12_integrated_testing/Cargo.lock index 5834e9f3..46e09629 100644 --- a/12_integrated_testing/Cargo.lock +++ b/12_integrated_testing/Cargo.lock @@ -39,9 +39,9 @@ checksum = "9ff023245bfcc73fb890e1f8d5383825b3131cc920020a5c487d6f113dfc428a" [[package]] name = "quote" -version = "1.0.17" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "632d02bff7f874a36f33ea8bb416cd484b90cc66c1194b1a1110d067a7013f58" +checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1" dependencies = [ "proc-macro2", ] diff --git a/12_integrated_testing/Cargo.toml b/12_integrated_testing/Cargo.toml index e768e678..6480a727 100644 --- a/12_integrated_testing/Cargo.toml +++ b/12_integrated_testing/Cargo.toml @@ -1,60 +1,9 @@ -[package] -name = "mingo" -version = "0.12.0" -authors = ["Andre Richter "] -edition = "2021" +[workspace] + +members = [ + "libraries/*", + "kernel" +] [profile.release] lto = true - -[features] -default = [] -bsp_rpi3 = ["tock-registers"] -bsp_rpi4 = ["tock-registers"] -test_build = ["qemu-exit"] - -##-------------------------------------------------------------------------------------------------- -## Dependencies -##-------------------------------------------------------------------------------------------------- - -[dependencies] -test-types = { path = "test-types" } - -# Optional dependencies -tock-registers = { version = "0.7.x", default-features = false, features = ["register_types"], optional = true } -qemu-exit = { version = "3.x.x", optional = true } - -# Platform specific dependencies -[target.'cfg(target_arch = "aarch64")'.dependencies] -cortex-a = { version = "7.x.x" } - -##-------------------------------------------------------------------------------------------------- -## Testing -##-------------------------------------------------------------------------------------------------- - -[dev-dependencies] -test-macros = { path = "test-macros" } - -# Unit tests are done in the library part of the kernel. -[lib] -name = "libkernel" -test = true - -# Disable unit tests for the kernel binary. -[[bin]] -name = "kernel" -path = "src/main.rs" -test = false - -# List of tests without harness. -[[test]] -name = "00_console_sanity" -harness = false - -[[test]] -name = "02_exception_sync_page_fault" -harness = false - -[[test]] -name = "03_exception_restore_sanity" -harness = false diff --git a/12_integrated_testing/Makefile b/12_integrated_testing/Makefile index 6adb1aca..427c9303 100644 --- a/12_integrated_testing/Makefile +++ b/12_integrated_testing/Makefile @@ -41,7 +41,7 @@ ifeq ($(BSP),rpi3) READELF_BINARY = aarch64-none-elf-readelf OPENOCD_ARG = -f /openocd/tcl/interface/ftdi/olimex-arm-usb-tiny-h.cfg -f /openocd/rpi3.cfg JTAG_BOOT_IMAGE = ../X1_JTAG_boot/jtag_boot_rpi3.img - LD_SCRIPT_PATH = $(shell pwd)/src/bsp/raspberrypi + LD_SCRIPT_PATH = $(shell pwd)/kernel/src/bsp/raspberrypi RUSTC_MISC_ARGS = -C target-cpu=cortex-a53 else ifeq ($(BSP),rpi4) TARGET = aarch64-unknown-none-softfloat @@ -55,7 +55,7 @@ else ifeq ($(BSP),rpi4) READELF_BINARY = aarch64-none-elf-readelf OPENOCD_ARG = -f /openocd/tcl/interface/ftdi/olimex-arm-usb-tiny-h.cfg -f /openocd/rpi4.cfg JTAG_BOOT_IMAGE = ../X1_JTAG_boot/jtag_boot_rpi4.img - LD_SCRIPT_PATH = $(shell pwd)/src/bsp/raspberrypi + LD_SCRIPT_PATH = $(shell pwd)/kernel/src/bsp/raspberrypi RUSTC_MISC_ARGS = -C target-cpu=cortex-a72 endif @@ -67,9 +67,9 @@ export LD_SCRIPT_PATH ##-------------------------------------------------------------------------------------------------- ## Targets and Prerequisites ##-------------------------------------------------------------------------------------------------- +KERNEL_MANIFEST = kernel/Cargo.toml KERNEL_LINKER_SCRIPT = kernel.ld - -LAST_BUILD_CONFIG = target/$(BSP).build_config +LAST_BUILD_CONFIG = target/$(BSP).build_config KERNEL_ELF = target/$(TARGET)/release/kernel # This parses cargo's dep-info file. @@ -94,11 +94,11 @@ COMPILER_ARGS = --target=$(TARGET) \ $(FEATURES) \ --release -RUSTC_CMD = cargo rustc $(COMPILER_ARGS) +RUSTC_CMD = cargo rustc $(COMPILER_ARGS) --manifest-path $(KERNEL_MANIFEST) DOC_CMD = cargo doc $(COMPILER_ARGS) CLIPPY_CMD = cargo clippy $(COMPILER_ARGS) CHECK_CMD = cargo check $(COMPILER_ARGS) -TEST_CMD = cargo test $(COMPILER_ARGS) +TEST_CMD = cargo test $(COMPILER_ARGS) --manifest-path $(KERNEL_MANIFEST) OBJCOPY_CMD = rust-objcopy \ --strip-all \ -O binary @@ -203,6 +203,8 @@ chainboot: $(KERNEL_BIN) ##------------------------------------------------------------------------------ clippy: @RUSTFLAGS="$(RUSTFLAGS_PEDANTIC)" $(CLIPPY_CMD) + @RUSTFLAGS="$(RUSTFLAGS_PEDANTIC)" $(CLIPPY_CMD) --features test_build --tests \ + --manifest-path $(KERNEL_MANIFEST) ##------------------------------------------------------------------------------ ## Clean @@ -299,6 +301,10 @@ test_boot: $(KERNEL_BIN) define KERNEL_TEST_RUNNER #!/usr/bin/env bash + # The cargo test runner seems to change into the crate under test's directory. Therefore, ensure + # this script executes from the root. + cd $(shell pwd) + TEST_ELF=$$(echo $$1 | sed -e 's/.*target/target/g') TEST_BINARY=$$(echo $$1.img | sed -e 's/.*target/target/g') diff --git a/12_integrated_testing/README.md b/12_integrated_testing/README.md index 9c325e76..14dc3878 100644 --- a/12_integrated_testing/README.md +++ b/12_integrated_testing/README.md @@ -16,6 +16,7 @@ - [Introduction](#introduction) - [Challenges](#challenges) * [Acknowledgements](#acknowledgements) +- [Folder Restructuring](#folder-restructuring) - [Implementation](#implementation) * [Test Organization](#test-organization) * [Enabling `custom_test_frameworks` for Unit Tests](#enabling-custom_test_frameworks-for-unit-tests) @@ -82,6 +83,24 @@ additional insights. [testing]: https://os.phil-opp.com/testing +## Folder Restructuring + +For reasons explained later, in this tutorial, we need to add two support crates next to our main +kernel crate. To keep everything organized in separate directories, we are switching to what `cargo` +calls a [virtual manifest]. The kernel crate moves to `$ROOT/kernel`, and the support crates will go +into `$ROOT/libraries/`. The `Cargo.toml` in the `$ROOT` folder desribes this layout: + +```toml +[workspace] + +members = [ + "libraries/*", + "kernel" +] +``` + +[virtual manifest]: https://doc.rust-lang.org/cargo/reference/workspaces.html#virtual-manifest + ## Implementation We introduce two new `Makefile` targets: @@ -104,8 +123,8 @@ test: test_boot test_unit test_integration ### Test Organization -Until now, our kernel was a so-called `binary crate`. As [explained in the official Rust book], this -crate type disallows having `integration tests`. Quoting the book: +Until now, our kernel crate was a so-called `binary crate`. As [explained in the official Rust +book], this crate type disallows having `integration tests`. Quoting the book: [explained in the official Rust book]: https://doc.rust-lang.org/book/ch11-03-test-organization.html#integration-tests-for-binary-crates @@ -126,10 +145,10 @@ of the kernel code. The `main.rs` file is stripped down to the minimum. It only `use` statements. Since it is not possible to use `kernel` as the name for both the library and the binary part of the -crate, new entries in `Cargo.toml` are needed to differentiate the names. What's more, `cargo test` -would try to compile and run `unit tests` for both. In our case, it will be sufficient to have all -the unit test code in `lib.rs`, so test generation for `main.rs` can be disabled in `Cargo.toml` as -well through the `test` flag: +crate, new entries in `$ROOT/kernel/Cargo.toml` are needed to differentiate the names. What's more, +`cargo test` would try to compile and run `unit tests` for both. In our case, it will be sufficient +to have all the unit test code in `lib.rs`, so test generation for `main.rs` can be disabled in +`Cargo.toml` as well through the `test` flag: ```toml [lib] @@ -193,10 +212,10 @@ pub fn test_runner(tests: &[&test_types::UnitTest]) { The function signature shows that `test_runner` takes one argument: A slice of `test_types::UnitTest` references. This type definition lives in an external crate stored at -`$ROOT/test_types`. It is external because the type is also needed for a self-made [procedural -macro] that we'll use to write unit tests, and procedural macros _have_ to live in their own crate. -So to avoid a circular dependency between kernel and proc-macro, this split was needed. Anyways, -here is the type definition: +`$ROOT/libraries/test_types`. It is external because the type is also needed for a self-made +[procedural macro] that we'll use to write unit tests, and procedural macros _have_ to live in their +own crate. So to avoid a circular dependency between kernel and proc-macro, this split was needed. +Anyways, here is the type definition: [procedural macro]: https://doc.rust-lang.org/reference/procedural-macros.html @@ -396,6 +415,10 @@ The file `kernel_test_runner.sh` does not exist by default. We generate it on de define KERNEL_TEST_RUNNER #!/usr/bin/env bash + # The cargo test runner seems to change into the crate under test's directory. Therefore, ensure + # this script executes from the root. + cd $(shell pwd) + TEST_ELF=$$(echo $$1 | sed -e 's/.*target/target/g') TEST_BINARY=$$(echo $$1.img | sed -e 's/.*target/target/g') @@ -417,7 +440,7 @@ endef test_unit: $(call color_header, "Compiling unit test(s) - $(BSP)") $(call test_prepare) - RUSTFLAGS="$(RUSTFLAGS_PEDANTIC)" $(TEST_CMD) --lib + @RUSTFLAGS="$(RUSTFLAGS_PEDANTIC)" $(TEST_CMD) --lib ``` It first does the standard `objcopy` step to strip the `ELF` down to a raw binary. Just like in all @@ -426,7 +449,7 @@ provided to it by `cargo`, and finally compiles a `docker` command to execute th reference, here it is fully resolved for an `RPi3 BSP`: ```bash -docker run --rm -v /opt/rust-raspberrypi-OS-tutorials/12_integrated_testing:/work/tutorial -w /work/tutorial -v /opt/rust-raspberrypi-OS-tutorials/12_integrated_testing/../common:/work/common rustembedded/osdev-utils ruby ../common/tests/dispatch.rb qemu-system-aarch64 -M raspi3 -serial stdio -display none -semihosting -kernel $TEST_BINARY +docker run -t --rm -v /opt/rust-raspberrypi-OS-tutorials/12_integrated_testing:/work/tutorial -w /work/tutorial -v /opt/rust-raspberrypi-OS-tutorials/12_integrated_testing/../common:/work/common rustembedded/osdev-utils:2021.12 ruby ../common/tests/dispatch.rb qemu-system-aarch64 -M raspi3 -serial stdio -display none -semihosting -kernel $TEST_BINARY ``` This command is quite similar to the one used in the `make test_boot` target that we have since @@ -441,17 +464,16 @@ executed successfully, which can be checked by inspecting `QEMU`'s exit code. So the provided qemu command it got from `ARGV`, and creates and runs an instance of `ExitCodeTest`: ```ruby -require_relative 'boot_test' -require_relative 'console_io_test' -require_relative 'exit_code_test' - qemu_cmd = ARGV.join(' ') binary = ARGV.last test_name = binary.gsub(%r{.*deps/}, '').split('-')[0] +# Check if virtual manifest (tutorial 12 or later) or not +path_prefix = File.exist?('kernel/Cargo.toml') ? 'kernel/' : '' + case test_name when 'kernel8.img' - load 'tests/boot_test_string.rb' # provides 'EXPECTED_PRINT' + load "#{path_prefix}tests/boot_test_string.rb" # provides 'EXPECTED_PRINT' BootTest.new(qemu_cmd, EXPECTED_PRINT).run # Doesn't return when 'libkernel' @@ -566,7 +588,7 @@ mod tests { ``` Note that since proc macros need to live in their own crates, we need to create a new one at -`$ROOT/test-macros` and save it there. +`$ROOT/libraries/test-macros` and save it there. Aaaaaand that's how you write unit tests. We're finished with that part for good now :raised_hands:. @@ -633,9 +655,9 @@ Note how the `test_runner` from `libkernel` is pulled in through For some tests, however, it is not needed to have the harness, because there is no need or possibility to partition the test into individual pieces. In this case, all the test code can live -in `kernel_init()`, and harness generation can be turned off through `Cargo.toml`. This tutorial -introduces two tests that don't need a harness. Here is how harness generation is turned off for -them: +in `kernel_init()`, and harness generation can be turned off through `$ROOT/kernel/Cargo.toml`. This +tutorial introduces two tests that don't need a harness. Here is how harness generation is turned +off for them: ```toml # List of tests without harness. @@ -740,7 +762,7 @@ Here is an excerpt from `00_console_sanity.rb` showing a subtest that does a han kernel over the console: ```ruby -require_relative '../../common/tests/console_io_test' +require 'console_io_test' # Verify sending and receiving works as expected. class TxRxHandshakeTest < SubtestBase @@ -890,1284 +912,12 @@ Compiling integration test(s) - rpi3 ``` ## Diff to previous -```diff - -diff -uNr 11_exceptions_part1_groundwork/.cargo/config.toml 12_integrated_testing/.cargo/config.toml ---- 11_exceptions_part1_groundwork/.cargo/config.toml -+++ 12_integrated_testing/.cargo/config.toml -@@ -0,0 +1,2 @@ -+[target.'cfg(target_os = "none")'] -+runner = "target/kernel_test_runner.sh" - -diff -uNr 11_exceptions_part1_groundwork/Cargo.toml 12_integrated_testing/Cargo.toml ---- 11_exceptions_part1_groundwork/Cargo.toml -+++ 12_integrated_testing/Cargo.toml -@@ -1,6 +1,6 @@ - [package] - name = "mingo" --version = "0.11.0" -+version = "0.12.0" - authors = ["Andre Richter "] - edition = "2021" - -@@ -11,20 +11,50 @@ - default = [] - bsp_rpi3 = ["tock-registers"] - bsp_rpi4 = ["tock-registers"] -- --[[bin]] --name = "kernel" --path = "src/main.rs" -+test_build = ["qemu-exit"] - - ##-------------------------------------------------------------------------------------------------- - ## Dependencies - ##-------------------------------------------------------------------------------------------------- - - [dependencies] -+test-types = { path = "test-types" } - - # Optional dependencies - tock-registers = { version = "0.7.x", default-features = false, features = ["register_types"], optional = true } -+qemu-exit = { version = "3.x.x", optional = true } - - # Platform specific dependencies - [target.'cfg(target_arch = "aarch64")'.dependencies] - cortex-a = { version = "7.x.x" } -+ -+##-------------------------------------------------------------------------------------------------- -+## Testing -+##-------------------------------------------------------------------------------------------------- -+ -+[dev-dependencies] -+test-macros = { path = "test-macros" } -+ -+# Unit tests are done in the library part of the kernel. -+[lib] -+name = "libkernel" -+test = true -+ -+# Disable unit tests for the kernel binary. -+[[bin]] -+name = "kernel" -+path = "src/main.rs" -+test = false -+ -+# List of tests without harness. -+[[test]] -+name = "00_console_sanity" -+harness = false -+ -+[[test]] -+name = "02_exception_sync_page_fault" -+harness = false -+ -+[[test]] -+name = "03_exception_restore_sanity" -+harness = false - -diff -uNr 11_exceptions_part1_groundwork/Makefile 12_integrated_testing/Makefile ---- 11_exceptions_part1_groundwork/Makefile -+++ 12_integrated_testing/Makefile -@@ -15,6 +15,13 @@ - # Default to a serial device name that is common in Linux. - DEV_SERIAL ?= /dev/ttyUSB0 - -+# Optional integration test name. -+ifdef TEST -+ TEST_ARG = --test $(TEST) -+else -+ TEST_ARG = --test '*' -+endif -+ - - - ##-------------------------------------------------------------------------------------------------- -@@ -28,6 +35,7 @@ - QEMU_BINARY = qemu-system-aarch64 - QEMU_MACHINE_TYPE = raspi3 - QEMU_RELEASE_ARGS = -serial stdio -display none -+ QEMU_TEST_ARGS = $(QEMU_RELEASE_ARGS) -semihosting - OBJDUMP_BINARY = aarch64-none-elf-objdump - NM_BINARY = aarch64-none-elf-nm - READELF_BINARY = aarch64-none-elf-readelf -@@ -41,6 +49,7 @@ - QEMU_BINARY = qemu-system-aarch64 - QEMU_MACHINE_TYPE = - QEMU_RELEASE_ARGS = -serial stdio -display none -+ QEMU_TEST_ARGS = $(QEMU_RELEASE_ARGS) -semihosting - OBJDUMP_BINARY = aarch64-none-elf-objdump - NM_BINARY = aarch64-none-elf-nm - READELF_BINARY = aarch64-none-elf-readelf -@@ -89,6 +98,7 @@ - DOC_CMD = cargo doc $(COMPILER_ARGS) - CLIPPY_CMD = cargo clippy $(COMPILER_ARGS) - CHECK_CMD = cargo check $(COMPILER_ARGS) -+TEST_CMD = cargo test $(COMPILER_ARGS) - OBJCOPY_CMD = rust-objcopy \ - --strip-all \ - -O binary -@@ -265,11 +275,13 @@ - ##-------------------------------------------------------------------------------------------------- - ## Testing targets - ##-------------------------------------------------------------------------------------------------- --.PHONY: test test_boot -+.PHONY: test test_boot test_unit test_integration -+ -+test_unit test_integration: FEATURES += --features test_build - - ifeq ($(QEMU_MACHINE_TYPE),) # QEMU is not supported for the board. - --test_boot test: -+test_boot test_unit test_integration test: - $(call color_header, "$(QEMU_MISSING_STRING)") - - else # QEMU is supported. -@@ -281,6 +293,43 @@ - $(call color_header, "Boot test - $(BSP)") - @$(DOCKER_TEST) $(EXEC_TEST_DISPATCH) $(EXEC_QEMU) $(QEMU_RELEASE_ARGS) -kernel $(KERNEL_BIN) - --test: test_boot -+##------------------------------------------------------------------------------ -+## Helpers for unit and integration test targets -+##------------------------------------------------------------------------------ -+define KERNEL_TEST_RUNNER -+ #!/usr/bin/env bash -+ -+ TEST_ELF=$$(echo $$1 | sed -e 's/.*target/target/g') -+ TEST_BINARY=$$(echo $$1.img | sed -e 's/.*target/target/g') -+ -+ $(OBJCOPY_CMD) $$TEST_ELF $$TEST_BINARY -+ $(DOCKER_TEST) $(EXEC_TEST_DISPATCH) $(EXEC_QEMU) $(QEMU_TEST_ARGS) -kernel $$TEST_BINARY -+endef -+ -+export KERNEL_TEST_RUNNER -+ -+define test_prepare -+ @mkdir -p target -+ @echo "$$KERNEL_TEST_RUNNER" > target/kernel_test_runner.sh -+ @chmod +x target/kernel_test_runner.sh -+endef -+ -+##------------------------------------------------------------------------------ -+## Run unit test(s) -+##------------------------------------------------------------------------------ -+test_unit: -+ $(call color_header, "Compiling unit test(s) - $(BSP)") -+ $(call test_prepare) -+ @RUSTFLAGS="$(RUSTFLAGS_PEDANTIC)" $(TEST_CMD) --lib -+ -+##------------------------------------------------------------------------------ -+## Run integration test(s) -+##------------------------------------------------------------------------------ -+test_integration: -+ $(call color_header, "Compiling integration test(s) - $(BSP)") -+ $(call test_prepare) -+ @RUSTFLAGS="$(RUSTFLAGS_PEDANTIC)" $(TEST_CMD) $(TEST_ARG) -+ -+test: test_boot test_unit test_integration - - endif - -diff -uNr 11_exceptions_part1_groundwork/src/_arch/aarch64/cpu.rs 12_integrated_testing/src/_arch/aarch64/cpu.rs ---- 11_exceptions_part1_groundwork/src/_arch/aarch64/cpu.rs -+++ 12_integrated_testing/src/_arch/aarch64/cpu.rs -@@ -26,3 +26,24 @@ - asm::wfe() - } - } -+ -+//-------------------------------------------------------------------------------------------------- -+// Testing -+//-------------------------------------------------------------------------------------------------- -+#[cfg(feature = "test_build")] -+use qemu_exit::QEMUExit; -+ -+#[cfg(feature = "test_build")] -+const QEMU_EXIT_HANDLE: qemu_exit::AArch64 = qemu_exit::AArch64::new(); -+ -+/// Make the host QEMU binary execute `exit(1)`. -+#[cfg(feature = "test_build")] -+pub fn qemu_exit_failure() -> ! { -+ QEMU_EXIT_HANDLE.exit_failure() -+} -+ -+/// Make the host QEMU binary execute `exit(0)`. -+#[cfg(feature = "test_build")] -+pub fn qemu_exit_success() -> ! { -+ QEMU_EXIT_HANDLE.exit_success() -+} - -diff -uNr 11_exceptions_part1_groundwork/src/_arch/aarch64/exception.rs 12_integrated_testing/src/_arch/aarch64/exception.rs ---- 11_exceptions_part1_groundwork/src/_arch/aarch64/exception.rs -+++ 12_integrated_testing/src/_arch/aarch64/exception.rs -@@ -87,15 +87,14 @@ - - #[no_mangle] - unsafe extern "C" fn current_elx_synchronous(e: &mut ExceptionContext) { -- if e.fault_address_valid() { -- let far_el1 = FAR_EL1.get(); -- -- // This catches the demo case for this tutorial. If the fault address happens to be 8 GiB, -- // advance the exception link register for one instruction, so that execution can continue. -- if far_el1 == 8 * 1024 * 1024 * 1024 { -- e.elr_el1 += 4; -- -- return; -+ #[cfg(feature = "test_build")] -+ { -+ const TEST_SVC_ID: u64 = 0x1337; -+ -+ if let Some(ESR_EL1::EC::Value::SVC64) = e.esr_el1.exception_class() { -+ if e.esr_el1.iss() == TEST_SVC_ID { -+ return; -+ } - } - } - -@@ -192,6 +191,12 @@ - fn exception_class(&self) -> Option { - self.0.read_as_enum(ESR_EL1::EC) - } -+ -+ #[cfg(feature = "test_build")] -+ #[inline(always)] -+ fn iss(&self) -> u64 { -+ self.0.read(ESR_EL1::ISS) -+ } - } - - /// Human readable ESR_EL1. - -diff -uNr 11_exceptions_part1_groundwork/src/_arch/aarch64/memory/mmu/translation_table.rs 12_integrated_testing/src/_arch/aarch64/memory/mmu/translation_table.rs ---- 11_exceptions_part1_groundwork/src/_arch/aarch64/memory/mmu/translation_table.rs -+++ 12_integrated_testing/src/_arch/aarch64/memory/mmu/translation_table.rs -@@ -290,3 +290,31 @@ - self.lvl2.phys_start_addr_u64() - } - } -+ -+//-------------------------------------------------------------------------------------------------- -+// Testing -+//-------------------------------------------------------------------------------------------------- -+ -+#[cfg(test)] -+mod tests { -+ use super::*; -+ use test_macros::kernel_test; -+ -+ /// Check if the size of `struct TableDescriptor` is as expected. -+ #[kernel_test] -+ fn size_of_tabledescriptor_equals_64_bit() { -+ assert_eq!( -+ core::mem::size_of::(), -+ core::mem::size_of::() -+ ); -+ } -+ -+ /// Check if the size of `struct PageDescriptor` is as expected. -+ #[kernel_test] -+ fn size_of_pagedescriptor_equals_64_bit() { -+ assert_eq!( -+ core::mem::size_of::(), -+ core::mem::size_of::() -+ ); -+ } -+} - -diff -uNr 11_exceptions_part1_groundwork/src/_arch/aarch64/memory/mmu.rs 12_integrated_testing/src/_arch/aarch64/memory/mmu.rs ---- 11_exceptions_part1_groundwork/src/_arch/aarch64/memory/mmu.rs -+++ 12_integrated_testing/src/_arch/aarch64/memory/mmu.rs -@@ -163,3 +163,33 @@ - SCTLR_EL1.matches_all(SCTLR_EL1::M::Enable) - } - } -+ -+//-------------------------------------------------------------------------------------------------- -+// Testing -+//-------------------------------------------------------------------------------------------------- -+ -+#[cfg(test)] -+mod tests { -+ use super::*; -+ use core::{cell::UnsafeCell, ops::Range}; -+ use test_macros::kernel_test; -+ -+ /// Check if KERNEL_TABLES is in .bss. -+ #[kernel_test] -+ fn kernel_tables_in_bss() { -+ extern "Rust" { -+ static __bss_start: UnsafeCell; -+ static __bss_end_exclusive: UnsafeCell; -+ } -+ -+ let bss_range = unsafe { -+ Range { -+ start: __bss_start.get(), -+ end: __bss_end_exclusive.get(), -+ } -+ }; -+ let kernel_tables_addr = unsafe { &KERNEL_TABLES as *const _ as usize as *mut u64 }; -+ -+ assert!(bss_range.contains(&kernel_tables_addr)); -+ } -+} - -diff -uNr 11_exceptions_part1_groundwork/src/bsp/raspberrypi/console.rs 12_integrated_testing/src/bsp/raspberrypi/console.rs ---- 11_exceptions_part1_groundwork/src/bsp/raspberrypi/console.rs -+++ 12_integrated_testing/src/bsp/raspberrypi/console.rs -@@ -35,3 +35,14 @@ - pub fn console() -> &'static impl console::interface::All { - &super::PL011_UART - } -+ -+//-------------------------------------------------------------------------------------------------- -+// Testing -+//-------------------------------------------------------------------------------------------------- -+ -+/// Minimal code needed to bring up the console in QEMU (for testing only). This is often less steps -+/// than on real hardware due to QEMU's abstractions. -+/// -+/// For the RPi, nothing needs to be done. -+#[cfg(feature = "test_build")] -+pub fn qemu_bring_up_console() {} - -diff -uNr 11_exceptions_part1_groundwork/src/bsp/raspberrypi/memory/mmu.rs 12_integrated_testing/src/bsp/raspberrypi/memory/mmu.rs ---- 11_exceptions_part1_groundwork/src/bsp/raspberrypi/memory/mmu.rs -+++ 12_integrated_testing/src/bsp/raspberrypi/memory/mmu.rs -@@ -69,3 +69,46 @@ - pub fn virt_mem_layout() -> &'static KernelVirtualLayout { - &LAYOUT - } -+ -+//-------------------------------------------------------------------------------------------------- -+// Testing -+//-------------------------------------------------------------------------------------------------- -+ -+#[cfg(test)] -+mod tests { -+ use super::*; -+ use test_macros::kernel_test; -+ -+ /// Check alignment of the kernel's virtual memory layout sections. -+ #[kernel_test] -+ fn virt_mem_layout_sections_are_64KiB_aligned() { -+ const SIXTYFOUR_KIB: usize = 65536; -+ -+ for i in LAYOUT.inner().iter() { -+ let start: usize = *(i.virtual_range)().start(); -+ let end: usize = *(i.virtual_range)().end() + 1; -+ -+ assert_eq!(start modulo SIXTYFOUR_KIB, 0); -+ assert_eq!(end modulo SIXTYFOUR_KIB, 0); -+ assert!(end >= start); -+ } -+ } -+ -+ /// Ensure the kernel's virtual memory layout is free of overlaps. -+ #[kernel_test] -+ fn virt_mem_layout_has_no_overlaps() { -+ let layout = virt_mem_layout().inner(); -+ -+ for (i, first) in layout.iter().enumerate() { -+ for second in layout.iter().skip(i + 1) { -+ let first_range = first.virtual_range; -+ let second_range = second.virtual_range; -+ -+ assert!(!first_range().contains(second_range().start())); -+ assert!(!first_range().contains(second_range().end())); -+ assert!(!second_range().contains(first_range().start())); -+ assert!(!second_range().contains(first_range().end())); -+ } -+ } -+ } -+} - -diff -uNr 11_exceptions_part1_groundwork/src/cpu.rs 12_integrated_testing/src/cpu.rs ---- 11_exceptions_part1_groundwork/src/cpu.rs -+++ 12_integrated_testing/src/cpu.rs -@@ -14,3 +14,6 @@ - // Architectural Public Reexports - //-------------------------------------------------------------------------------------------------- - pub use arch_cpu::{nop, wait_forever}; -+ -+#[cfg(feature = "test_build")] -+pub use arch_cpu::{qemu_exit_failure, qemu_exit_success}; - -diff -uNr 11_exceptions_part1_groundwork/src/exception.rs 12_integrated_testing/src/exception.rs ---- 11_exceptions_part1_groundwork/src/exception.rs -+++ 12_integrated_testing/src/exception.rs -@@ -28,3 +28,21 @@ - Hypervisor, - Unknown, - } -+ -+//-------------------------------------------------------------------------------------------------- -+// Testing -+//-------------------------------------------------------------------------------------------------- -+ -+#[cfg(test)] -+mod tests { -+ use super::*; -+ use test_macros::kernel_test; -+ -+ /// Libkernel unit tests must execute in kernel mode. -+ #[kernel_test] -+ fn test_runner_executes_in_kernel_mode() { -+ let (level, _) = current_privilege_level(); -+ -+ assert!(level == PrivilegeLevel::Kernel) -+ } -+} - -diff -uNr 11_exceptions_part1_groundwork/src/lib.rs 12_integrated_testing/src/lib.rs ---- 11_exceptions_part1_groundwork/src/lib.rs -+++ 12_integrated_testing/src/lib.rs -@@ -0,0 +1,183 @@ -+// SPDX-License-Identifier: MIT OR Apache-2.0 -+// -+// Copyright (c) 2018-2022 Andre Richter -+ -+// Rust embedded logo for `make doc`. -+#![doc(html_logo_url = "https://git.io/JeGIp")] -+ -+//! The `kernel` library. -+//! -+//! Used to compose the final kernel binary. -+//! -+//! # Code organization and architecture -+//! -+//! The code is divided into different *modules*, each representing a typical **subsystem** of the -+//! `kernel`. Top-level module files of subsystems reside directly in the `src` folder. For example, -+//! `src/memory.rs` contains code that is concerned with all things memory management. -+//! -+//! ## Visibility of processor architecture code -+//! -+//! Some of the `kernel`'s subsystems depend on low-level code that is specific to the target -+//! processor architecture. For each supported processor architecture, there exists a subfolder in -+//! `src/_arch`, for example, `src/_arch/aarch64`. -+//! -+//! The architecture folders mirror the subsystem modules laid out in `src`. For example, -+//! architectural code that belongs to the `kernel`'s MMU subsystem (`src/memory/mmu.rs`) would go -+//! into `src/_arch/aarch64/memory/mmu.rs`. The latter file is loaded as a module in -+//! `src/memory/mmu.rs` using the `path attribute`. Usually, the chosen module name is the generic -+//! module's name prefixed with `arch_`. -+//! -+//! For example, this is the top of `src/memory/mmu.rs`: -+//! -+//! ``` -+//! #[cfg(target_arch = "aarch64")] -+//! #[path = "../_arch/aarch64/memory/mmu.rs"] -+//! mod arch_mmu; -+//! ``` -+//! -+//! Often times, items from the `arch_ module` will be publicly reexported by the parent module. -+//! This way, each architecture specific module can provide its implementation of an item, while the -+//! caller must not be concerned which architecture has been conditionally compiled. -+//! -+//! ## BSP code -+//! -+//! `BSP` stands for Board Support Package. `BSP` code is organized under `src/bsp.rs` and contains -+//! target board specific definitions and functions. These are things such as the board's memory map -+//! or instances of drivers for devices that are featured on the respective board. -+//! -+//! Just like processor architecture code, the `BSP` code's module structure tries to mirror the -+//! `kernel`'s subsystem modules, but there is no reexporting this time. That means whatever is -+//! provided must be called starting from the `bsp` namespace, e.g. `bsp::driver::driver_manager()`. -+//! -+//! ## Kernel interfaces -+//! -+//! Both `arch` and `bsp` contain code that is conditionally compiled depending on the actual target -+//! and board for which the kernel is compiled. For example, the `interrupt controller` hardware of -+//! the `Raspberry Pi 3` and the `Raspberry Pi 4` is different, but we want the rest of the `kernel` -+//! code to play nicely with any of the two without much hassle. -+//! -+//! In order to provide a clean abstraction between `arch`, `bsp` and `generic kernel code`, -+//! `interface` traits are provided *whenever possible* and *where it makes sense*. They are defined -+//! in the respective subsystem module and help to enforce the idiom of *program to an interface, -+//! not an implementation*. For example, there will be a common IRQ handling interface which the two -+//! different interrupt controller `drivers` of both Raspberrys will implement, and only export the -+//! interface to the rest of the `kernel`. -+//! -+//! ``` -+//! +-------------------+ -+//! | Interface (Trait) | -+//! | | -+//! +--+-------------+--+ -+//! ^ ^ -+//! | | -+//! | | -+//! +----------+--+ +--+----------+ -+//! | kernel code | | bsp code | -+//! | | | arch code | -+//! +-------------+ +-------------+ -+//! ``` -+//! -+//! # Summary -+//! -+//! For a logical `kernel` subsystem, corresponding code can be distributed over several physical -+//! locations. Here is an example for the **memory** subsystem: -+//! -+//! - `src/memory.rs` and `src/memory/**/*` -+//! - Common code that is agnostic of target processor architecture and `BSP` characteristics. -+//! - Example: A function to zero a chunk of memory. -+//! - Interfaces for the memory subsystem that are implemented by `arch` or `BSP` code. -+//! - Example: An `MMU` interface that defines `MMU` function prototypes. -+//! - `src/bsp/__board_name__/memory.rs` and `src/bsp/__board_name__/memory/**/*` -+//! - `BSP` specific code. -+//! - Example: The board's memory map (physical addresses of DRAM and MMIO devices). -+//! - `src/_arch/__arch_name__/memory.rs` and `src/_arch/__arch_name__/memory/**/*` -+//! - Processor architecture specific code. -+//! - Example: Implementation of the `MMU` interface for the `__arch_name__` processor -+//! architecture. -+//! -+//! From a namespace perspective, **memory** subsystem code lives in: -+//! -+//! - `crate::memory::*` -+//! - `crate::bsp::memory::*` -+//! -+//! # Boot flow -+//! -+//! 1. The kernel's entry point is the function `cpu::boot::arch_boot::_start()`. -+//! - It is implemented in `src/_arch/__arch_name__/cpu/boot.s`. -+//! 2. Once finished with architectural setup, the arch code calls `kernel_init()`. -+ -+#![allow(clippy::upper_case_acronyms)] -+#![allow(incomplete_features)] -+#![feature(core_intrinsics)] -+#![feature(format_args_nl)] -+#![feature(linkage)] -+#![feature(panic_info_message)] -+#![feature(trait_alias)] -+#![no_std] -+// Testing -+#![cfg_attr(test, no_main)] -+#![feature(custom_test_frameworks)] -+#![reexport_test_harness_main = "test_main"] -+#![test_runner(crate::test_runner)] -+ -+mod panic_wait; -+mod synchronization; -+ -+pub mod bsp; -+pub mod console; -+pub mod cpu; -+pub mod driver; -+pub mod exception; -+pub mod memory; -+pub mod print; -+pub mod time; -+ -+//-------------------------------------------------------------------------------------------------- -+// Public Code -+//-------------------------------------------------------------------------------------------------- -+ -+/// Version string. -+pub fn version() -> &'static str { -+ concat!( -+ env!("CARGO_PKG_NAME"), -+ " version ", -+ env!("CARGO_PKG_VERSION") -+ ) -+} -+ -+#[cfg(not(test))] -+extern "Rust" { -+ fn kernel_init() -> !; -+} -+ -+//-------------------------------------------------------------------------------------------------- -+// Testing -+//-------------------------------------------------------------------------------------------------- -+ -+/// The default runner for unit tests. -+pub fn test_runner(tests: &[&test_types::UnitTest]) { -+ // This line will be printed as the test header. -+ println!("Running {} tests", tests.len()); -+ -+ for (i, test) in tests.iter().enumerate() { -+ print!("{:>3}. {:.<58}", i + 1, test.name); -+ -+ // Run the actual test. -+ (test.test_func)(); -+ -+ // Failed tests call panic!(). Execution reaches here only if the test has passed. -+ println!("[ok]") -+ } -+} -+ -+/// The `kernel_init()` for unit tests. -+#[cfg(test)] -+#[no_mangle] -+unsafe fn kernel_init() -> ! { -+ exception::handling_init(); -+ bsp::console::qemu_bring_up_console(); -+ -+ test_main(); -+ -+ cpu::qemu_exit_success() -+} - -diff -uNr 11_exceptions_part1_groundwork/src/main.rs 12_integrated_testing/src/main.rs ---- 11_exceptions_part1_groundwork/src/main.rs -+++ 12_integrated_testing/src/main.rs -@@ -6,123 +6,12 @@ - #![doc(html_logo_url = "https://git.io/JeGIp")] - - //! The `kernel` binary. --//! --//! # Code organization and architecture --//! --//! The code is divided into different *modules*, each representing a typical **subsystem** of the --//! `kernel`. Top-level module files of subsystems reside directly in the `src` folder. For example, --//! `src/memory.rs` contains code that is concerned with all things memory management. --//! --//! ## Visibility of processor architecture code --//! --//! Some of the `kernel`'s subsystems depend on low-level code that is specific to the target --//! processor architecture. For each supported processor architecture, there exists a subfolder in --//! `src/_arch`, for example, `src/_arch/aarch64`. --//! --//! The architecture folders mirror the subsystem modules laid out in `src`. For example, --//! architectural code that belongs to the `kernel`'s MMU subsystem (`src/memory/mmu.rs`) would go --//! into `src/_arch/aarch64/memory/mmu.rs`. The latter file is loaded as a module in --//! `src/memory/mmu.rs` using the `path attribute`. Usually, the chosen module name is the generic --//! module's name prefixed with `arch_`. --//! --//! For example, this is the top of `src/memory/mmu.rs`: --//! --//! ``` --//! #[cfg(target_arch = "aarch64")] --//! #[path = "../_arch/aarch64/memory/mmu.rs"] --//! mod arch_mmu; --//! ``` --//! --//! Often times, items from the `arch_ module` will be publicly reexported by the parent module. --//! This way, each architecture specific module can provide its implementation of an item, while the --//! caller must not be concerned which architecture has been conditionally compiled. --//! --//! ## BSP code --//! --//! `BSP` stands for Board Support Package. `BSP` code is organized under `src/bsp.rs` and contains --//! target board specific definitions and functions. These are things such as the board's memory map --//! or instances of drivers for devices that are featured on the respective board. --//! --//! Just like processor architecture code, the `BSP` code's module structure tries to mirror the --//! `kernel`'s subsystem modules, but there is no reexporting this time. That means whatever is --//! provided must be called starting from the `bsp` namespace, e.g. `bsp::driver::driver_manager()`. --//! --//! ## Kernel interfaces --//! --//! Both `arch` and `bsp` contain code that is conditionally compiled depending on the actual target --//! and board for which the kernel is compiled. For example, the `interrupt controller` hardware of --//! the `Raspberry Pi 3` and the `Raspberry Pi 4` is different, but we want the rest of the `kernel` --//! code to play nicely with any of the two without much hassle. --//! --//! In order to provide a clean abstraction between `arch`, `bsp` and `generic kernel code`, --//! `interface` traits are provided *whenever possible* and *where it makes sense*. They are defined --//! in the respective subsystem module and help to enforce the idiom of *program to an interface, --//! not an implementation*. For example, there will be a common IRQ handling interface which the two --//! different interrupt controller `drivers` of both Raspberrys will implement, and only export the --//! interface to the rest of the `kernel`. --//! --//! ``` --//! +-------------------+ --//! | Interface (Trait) | --//! | | --//! +--+-------------+--+ --//! ^ ^ --//! | | --//! | | --//! +----------+--+ +--+----------+ --//! | kernel code | | bsp code | --//! | | | arch code | --//! +-------------+ +-------------+ --//! ``` --//! --//! # Summary --//! --//! For a logical `kernel` subsystem, corresponding code can be distributed over several physical --//! locations. Here is an example for the **memory** subsystem: --//! --//! - `src/memory.rs` and `src/memory/**/*` --//! - Common code that is agnostic of target processor architecture and `BSP` characteristics. --//! - Example: A function to zero a chunk of memory. --//! - Interfaces for the memory subsystem that are implemented by `arch` or `BSP` code. --//! - Example: An `MMU` interface that defines `MMU` function prototypes. --//! - `src/bsp/__board_name__/memory.rs` and `src/bsp/__board_name__/memory/**/*` --//! - `BSP` specific code. --//! - Example: The board's memory map (physical addresses of DRAM and MMIO devices). --//! - `src/_arch/__arch_name__/memory.rs` and `src/_arch/__arch_name__/memory/**/*` --//! - Processor architecture specific code. --//! - Example: Implementation of the `MMU` interface for the `__arch_name__` processor --//! architecture. --//! --//! From a namespace perspective, **memory** subsystem code lives in: --//! --//! - `crate::memory::*` --//! - `crate::bsp::memory::*` --//! --//! # Boot flow --//! --//! 1. The kernel's entry point is the function `cpu::boot::arch_boot::_start()`. --//! - It is implemented in `src/_arch/__arch_name__/cpu/boot.s`. --//! 2. Once finished with architectural setup, the arch code calls `kernel_init()`. -- --#![allow(clippy::upper_case_acronyms)] --#![allow(incomplete_features)] --#![feature(core_intrinsics)] -+ - #![feature(format_args_nl)] --#![feature(panic_info_message)] --#![feature(trait_alias)] - #![no_main] - #![no_std] - --mod bsp; --mod console; --mod cpu; --mod driver; --mod exception; --mod memory; --mod panic_wait; --mod print; --mod synchronization; --mod time; -+use libkernel::{bsp, console, driver, exception, info, memory, time}; - - /// Early init code. - /// -@@ -133,6 +22,7 @@ - /// - MMU + Data caching must be activated at the earliest. Without it, any atomic operations, - /// e.g. the yet-to-be-introduced spinlocks in the device drivers (which currently employ - /// NullLocks instead of spinlocks), will fail to work (properly) on the RPi SoCs. -+#[no_mangle] - unsafe fn kernel_init() -> ! { - use driver::interface::DriverManager; - use memory::mmu::interface::MMU; -@@ -159,15 +49,9 @@ - fn kernel_main() -> ! { - use bsp::console::console; - use console::interface::All; -- use core::time::Duration; - use driver::interface::DriverManager; -- use time::interface::TimeManager; - -- info!( -- "{} version {}", -- env!("CARGO_PKG_NAME"), -- env!("CARGO_PKG_VERSION") -- ); -+ info!("{}", libkernel::version()); - info!("Booting on: {}", bsp::board_name()); - - info!("MMU online. Special regions:"); -@@ -193,31 +77,6 @@ - info!(" {}. {}", i + 1, driver.compatible()); - } - -- info!("Timer test, spinning for 1 second"); -- time::time_manager().spin_for(Duration::from_secs(1)); -- -- // Cause an exception by accessing a virtual address for which no translation was set up. This -- // code accesses the address 8 GiB, which is outside the mapped address space. -- // -- // For demo purposes, the exception handler will catch the faulting 8 GiB address and allow -- // execution to continue. -- info!(""); -- info!("Trying to read from address 8 GiB..."); -- let mut big_addr: u64 = 8 * 1024 * 1024 * 1024; -- unsafe { core::ptr::read_volatile(big_addr as *mut u64) }; -- -- info!("************************************************"); -- info!("Whoa! We recovered from a synchronous exception!"); -- info!("************************************************"); -- info!(""); -- info!("Let's try again"); -- -- // Now use address 9 GiB. The exception handler won't forgive us this time. -- info!("Trying to read from address 9 GiB..."); -- big_addr = 9 * 1024 * 1024 * 1024; -- unsafe { core::ptr::read_volatile(big_addr as *mut u64) }; -- -- // Will never reach here in this tutorial. - info!("Echoing input now"); - - // Discard any spurious received characters before going into echo mode. - -diff -uNr 11_exceptions_part1_groundwork/src/memory/mmu.rs 12_integrated_testing/src/memory/mmu.rs ---- 11_exceptions_part1_groundwork/src/memory/mmu.rs -+++ 12_integrated_testing/src/memory/mmu.rs -@@ -66,7 +66,6 @@ - - /// Architecture agnostic translation types. - #[allow(missing_docs)] --#[allow(dead_code)] - #[derive(Copy, Clone)] - pub enum Translation { - Identity, -@@ -261,4 +260,9 @@ - info!("{}", i); - } - } -+ -+ #[cfg(test)] -+ pub fn inner(&self) -> &[TranslationDescriptor; NUM_SPECIAL_RANGES] { -+ &self.inner -+ } - } - -diff -uNr 11_exceptions_part1_groundwork/src/panic_wait.rs 12_integrated_testing/src/panic_wait.rs ---- 11_exceptions_part1_groundwork/src/panic_wait.rs -+++ 12_integrated_testing/src/panic_wait.rs -@@ -17,6 +17,23 @@ - unsafe { bsp::console::panic_console_out().write_fmt(args).unwrap() }; - } - -+/// The point of exit for `libkernel`. -+/// -+/// It is linked weakly, so that the integration tests can overload its standard behavior. -+#[linkage = "weak"] -+#[no_mangle] -+fn _panic_exit() -> ! { -+ #[cfg(not(feature = "test_build"))] -+ { -+ cpu::wait_forever() -+ } -+ -+ #[cfg(feature = "test_build")] -+ { -+ cpu::qemu_exit_failure() -+ } -+} -+ - /// Prints with a newline - only use from the panic handler. - /// - /// Carbon copy from -@@ -53,7 +70,7 @@ - return; - } - -- cpu::wait_forever() -+ _panic_exit() - } - - #[panic_handler] -@@ -81,5 +98,5 @@ - info.message().unwrap_or(&format_args!("")), - ); - -- cpu::wait_forever() -+ _panic_exit() - } - -diff -uNr 11_exceptions_part1_groundwork/test-macros/Cargo.toml 12_integrated_testing/test-macros/Cargo.toml ---- 11_exceptions_part1_groundwork/test-macros/Cargo.toml -+++ 12_integrated_testing/test-macros/Cargo.toml -@@ -0,0 +1,14 @@ -+[package] -+name = "test-macros" -+version = "0.1.0" -+authors = ["Andre Richter "] -+edition = "2021" -+ -+[lib] -+proc-macro = true -+ -+[dependencies] -+proc-macro2 = "1.x" -+quote = "1.x" -+syn = { version = "1.x", features = ["full"] } -+test-types = { path = "../test-types" } - -diff -uNr 11_exceptions_part1_groundwork/test-macros/src/lib.rs 12_integrated_testing/test-macros/src/lib.rs ---- 11_exceptions_part1_groundwork/test-macros/src/lib.rs -+++ 12_integrated_testing/test-macros/src/lib.rs -@@ -0,0 +1,29 @@ -+// SPDX-License-Identifier: MIT OR Apache-2.0 -+// -+// Copyright (c) 2019-2022 Andre Richter -+ -+use proc_macro::TokenStream; -+use proc_macro2::Span; -+use quote::quote; -+use syn::{parse_macro_input, Ident, ItemFn}; -+ -+#[proc_macro_attribute] -+pub fn kernel_test(_attr: TokenStream, input: TokenStream) -> TokenStream { -+ let f = parse_macro_input!(input as ItemFn); -+ -+ let test_name = &format!("{}", f.sig.ident); -+ let test_ident = Ident::new( -+ &format!("{}_TEST_CONTAINER", f.sig.ident.to_string().to_uppercase()), -+ Span::call_site(), -+ ); -+ let test_code_block = f.block; -+ -+ quote!( -+ #[test_case] -+ const #test_ident: test_types::UnitTest = test_types::UnitTest { -+ name: #test_name, -+ test_func: || #test_code_block, -+ }; -+ ) -+ .into() -+} - -diff -uNr 11_exceptions_part1_groundwork/tests/00_console_sanity.rb 12_integrated_testing/tests/00_console_sanity.rb ---- 11_exceptions_part1_groundwork/tests/00_console_sanity.rb -+++ 12_integrated_testing/tests/00_console_sanity.rb -@@ -0,0 +1,48 @@ -+# frozen_string_literal: true -+ -+# SPDX-License-Identifier: MIT OR Apache-2.0 -+# -+# Copyright (c) 2019-2022 Andre Richter -+ -+require 'console_io_test' -+ -+# Verify sending and receiving works as expected. -+class TxRxHandshakeTest < SubtestBase -+ def name -+ 'Transmit and Receive handshake' -+ end -+ -+ def run(qemu_out, qemu_in) -+ qemu_in.write_nonblock('ABC') -+ expect_or_raise(qemu_out, 'OK1234') -+ end -+end -+ -+# Check for correct TX statistics implementation. Depends on test 1 being run first. -+class TxStatisticsTest < SubtestBase -+ def name -+ 'Transmit statistics' -+ end -+ -+ def run(qemu_out, _qemu_in) -+ expect_or_raise(qemu_out, '6') -+ end -+end -+ -+# Check for correct RX statistics implementation. Depends on test 1 being run first. -+class RxStatisticsTest < SubtestBase -+ def name -+ 'Receive statistics' -+ end -+ -+ def run(qemu_out, _qemu_in) -+ expect_or_raise(qemu_out, '3') -+ end -+end -+ -+##-------------------------------------------------------------------------------------------------- -+## Test registration -+##-------------------------------------------------------------------------------------------------- -+def subtest_collection -+ [TxRxHandshakeTest.new, TxStatisticsTest.new, RxStatisticsTest.new] -+end - -diff -uNr 11_exceptions_part1_groundwork/tests/00_console_sanity.rs 12_integrated_testing/tests/00_console_sanity.rs ---- 11_exceptions_part1_groundwork/tests/00_console_sanity.rs -+++ 12_integrated_testing/tests/00_console_sanity.rs -@@ -0,0 +1,38 @@ -+// SPDX-License-Identifier: MIT OR Apache-2.0 -+// -+// Copyright (c) 2019-2022 Andre Richter -+ -+//! Console sanity tests - RX, TX and statistics. -+ -+#![feature(format_args_nl)] -+#![no_main] -+#![no_std] -+ -+/// Console tests should time out on the I/O harness in case of panic. -+mod panic_wait_forever; -+ -+use libkernel::{bsp, console, cpu, exception, print}; -+ -+#[no_mangle] -+unsafe fn kernel_init() -> ! { -+ use bsp::console::console; -+ use console::interface::*; -+ -+ exception::handling_init(); -+ bsp::console::qemu_bring_up_console(); -+ -+ // Handshake -+ assert_eq!(console().read_char(), 'A'); -+ assert_eq!(console().read_char(), 'B'); -+ assert_eq!(console().read_char(), 'C'); -+ print!("OK1234"); -+ -+ // 6 -+ print!("{}", console().chars_written()); -+ -+ // 3 -+ print!("{}", console().chars_read()); -+ -+ // The QEMU process running this test will be closed by the I/O test harness. -+ cpu::wait_forever(); -+} - -diff -uNr 11_exceptions_part1_groundwork/tests/01_timer_sanity.rs 12_integrated_testing/tests/01_timer_sanity.rs ---- 11_exceptions_part1_groundwork/tests/01_timer_sanity.rs -+++ 12_integrated_testing/tests/01_timer_sanity.rs -@@ -0,0 +1,49 @@ -+// SPDX-License-Identifier: MIT OR Apache-2.0 -+// -+// Copyright (c) 2019-2022 Andre Richter -+ -+//! Timer sanity tests. -+ -+#![feature(custom_test_frameworks)] -+#![no_main] -+#![no_std] -+#![reexport_test_harness_main = "test_main"] -+#![test_runner(libkernel::test_runner)] -+ -+use core::time::Duration; -+use libkernel::{bsp, cpu, exception, time, time::interface::TimeManager}; -+use test_macros::kernel_test; -+ -+#[no_mangle] -+unsafe fn kernel_init() -> ! { -+ exception::handling_init(); -+ bsp::console::qemu_bring_up_console(); -+ -+ // Depending on CPU arch, some timer bring-up code could go here. Not needed for the RPi. -+ -+ test_main(); -+ -+ cpu::qemu_exit_success() -+} -+ -+/// Simple check that the timer is running. -+#[kernel_test] -+fn timer_is_counting() { -+ assert!(time::time_manager().uptime().as_nanos() > 0) -+} -+ -+/// Timer resolution must be sufficient. -+#[kernel_test] -+fn timer_resolution_is_sufficient() { -+ assert!(time::time_manager().resolution().as_nanos() < 100) -+} -+ -+/// Sanity check spin_for() implementation. -+#[kernel_test] -+fn spin_accuracy_check_1_second() { -+ let t1 = time::time_manager().uptime(); -+ time::time_manager().spin_for(Duration::from_secs(1)); -+ let t2 = time::time_manager().uptime(); -+ -+ assert_eq!((t2 - t1).as_secs(), 1) -+} - -diff -uNr 11_exceptions_part1_groundwork/tests/02_exception_sync_page_fault.rs 12_integrated_testing/tests/02_exception_sync_page_fault.rs ---- 11_exceptions_part1_groundwork/tests/02_exception_sync_page_fault.rs -+++ 12_integrated_testing/tests/02_exception_sync_page_fault.rs -@@ -0,0 +1,43 @@ -+// SPDX-License-Identifier: MIT OR Apache-2.0 -+// -+// Copyright (c) 2019-2022 Andre Richter -+ -+//! Page faults must result in synchronous exceptions. -+ -+#![feature(format_args_nl)] -+#![no_main] -+#![no_std] -+ -+/// Overwrites libkernel's `panic_wait::_panic_exit()` so that it returns a "success" code. -+/// -+/// In this test, reaching the panic is a success, because it is called from the synchronous -+/// exception handler, which is what this test wants to achieve. -+/// -+/// It also means that this integration test can not use any other code that calls panic!() directly -+/// or indirectly. -+mod panic_exit_success; -+ -+use libkernel::{bsp, cpu, exception, info, memory, println}; -+ -+#[no_mangle] -+unsafe fn kernel_init() -> ! { -+ use memory::mmu::interface::MMU; -+ -+ exception::handling_init(); -+ bsp::console::qemu_bring_up_console(); -+ -+ // This line will be printed as the test header. -+ println!("Testing synchronous exception handling by causing a page fault"); -+ -+ if let Err(string) = memory::mmu::mmu().enable_mmu_and_caching() { -+ info!("MMU: {}", string); -+ cpu::qemu_exit_failure() -+ } -+ -+ info!("Writing beyond mapped area to address 9 GiB..."); -+ let big_addr: u64 = 9 * 1024 * 1024 * 1024; -+ core::ptr::read_volatile(big_addr as *mut u64); -+ -+ // If execution reaches here, the memory access above did not cause a page fault exception. -+ cpu::qemu_exit_failure() -+} - -diff -uNr 11_exceptions_part1_groundwork/tests/03_exception_restore_sanity.rb 12_integrated_testing/tests/03_exception_restore_sanity.rb ---- 11_exceptions_part1_groundwork/tests/03_exception_restore_sanity.rb -+++ 12_integrated_testing/tests/03_exception_restore_sanity.rb -@@ -0,0 +1,25 @@ -+# frozen_string_literal: true -+ -+# SPDX-License-Identifier: MIT OR Apache-2.0 -+# -+# Copyright (c) 2022 Andre Richter -+ -+require 'console_io_test' -+ -+# Verify that exception restore works. -+class ExceptionRestoreTest < SubtestBase -+ def name -+ 'Exception restore' -+ end -+ -+ def run(qemu_out, _qemu_in) -+ expect_or_raise(qemu_out, 'Back from system call!') -+ end -+end -+ -+##-------------------------------------------------------------------------------------------------- -+## Test registration -+##-------------------------------------------------------------------------------------------------- -+def subtest_collection -+ [ExceptionRestoreTest.new] -+end - -diff -uNr 11_exceptions_part1_groundwork/tests/03_exception_restore_sanity.rs 12_integrated_testing/tests/03_exception_restore_sanity.rs ---- 11_exceptions_part1_groundwork/tests/03_exception_restore_sanity.rs -+++ 12_integrated_testing/tests/03_exception_restore_sanity.rs -@@ -0,0 +1,55 @@ -+// SPDX-License-Identifier: MIT OR Apache-2.0 -+// -+// Copyright (c) 2022 Andre Richter -+ -+//! A simple sanity test to see if exception restore code works. -+ -+#![feature(format_args_nl)] -+#![no_main] -+#![no_std] -+ -+/// Console tests should time out on the I/O harness in case of panic. -+mod panic_wait_forever; -+ -+use core::arch::asm; -+use libkernel::{bsp, cpu, exception, info, memory, println}; -+ -+#[inline(never)] -+fn nested_system_call() { -+ #[cfg(target_arch = "aarch64")] -+ unsafe { -+ asm!("svc #0x1337", options(nomem, nostack, preserves_flags)); -+ } -+ -+ #[cfg(not(target_arch = "aarch64"))] -+ { -+ info!("Not supported yet"); -+ cpu::wait_forever(); -+ } -+} -+ -+#[no_mangle] -+unsafe fn kernel_init() -> ! { -+ use memory::mmu::interface::MMU; -+ -+ exception::handling_init(); -+ bsp::console::qemu_bring_up_console(); -+ -+ // This line will be printed as the test header. -+ println!("Testing exception restore"); -+ -+ if let Err(string) = memory::mmu::mmu().enable_mmu_and_caching() { -+ info!("MMU: {}", string); -+ cpu::qemu_exit_failure() -+ } -+ -+ info!("Making a dummy system call"); -+ -+ // Calling this inside a function indirectly tests if the link register is restored properly. -+ nested_system_call(); -+ -+ info!("Back from system call!"); -+ -+ // The QEMU process running this test will be closed by the I/O test harness. -+ cpu::wait_forever(); -+} - -diff -uNr 11_exceptions_part1_groundwork/tests/boot_test_string.rb 12_integrated_testing/tests/boot_test_string.rb ---- 11_exceptions_part1_groundwork/tests/boot_test_string.rb -+++ 12_integrated_testing/tests/boot_test_string.rb -@@ -1,3 +1,3 @@ - # frozen_string_literal: true - --EXPECTED_PRINT = 'lr : 0x' -+EXPECTED_PRINT = 'Echoing input now' - -diff -uNr 11_exceptions_part1_groundwork/tests/panic_exit_success/mod.rs 12_integrated_testing/tests/panic_exit_success/mod.rs ---- 11_exceptions_part1_groundwork/tests/panic_exit_success/mod.rs -+++ 12_integrated_testing/tests/panic_exit_success/mod.rs -@@ -0,0 +1,9 @@ -+// SPDX-License-Identifier: MIT OR Apache-2.0 -+// -+// Copyright (c) 2019-2022 Andre Richter -+ -+/// Overwrites libkernel's `panic_wait::_panic_exit()` with the QEMU-exit version. -+#[no_mangle] -+fn _panic_exit() -> ! { -+ libkernel::cpu::qemu_exit_success() -+} - -diff -uNr 11_exceptions_part1_groundwork/tests/panic_wait_forever/mod.rs 12_integrated_testing/tests/panic_wait_forever/mod.rs ---- 11_exceptions_part1_groundwork/tests/panic_wait_forever/mod.rs -+++ 12_integrated_testing/tests/panic_wait_forever/mod.rs -@@ -0,0 +1,9 @@ -+// SPDX-License-Identifier: MIT OR Apache-2.0 -+// -+// Copyright (c) 2022 Andre Richter -+ -+/// Overwrites libkernel's `panic_wait::_panic_exit()` with wait_forever. -+#[no_mangle] -+fn _panic_exit() -> ! { -+ libkernel::cpu::wait_forever() -+} - -diff -uNr 11_exceptions_part1_groundwork/test-types/Cargo.toml 12_integrated_testing/test-types/Cargo.toml ---- 11_exceptions_part1_groundwork/test-types/Cargo.toml -+++ 12_integrated_testing/test-types/Cargo.toml -@@ -0,0 +1,5 @@ -+[package] -+name = "test-types" -+version = "0.1.0" -+authors = ["Andre Richter "] -+edition = "2021" - -diff -uNr 11_exceptions_part1_groundwork/test-types/src/lib.rs 12_integrated_testing/test-types/src/lib.rs ---- 11_exceptions_part1_groundwork/test-types/src/lib.rs -+++ 12_integrated_testing/test-types/src/lib.rs -@@ -0,0 +1,16 @@ -+// SPDX-License-Identifier: MIT OR Apache-2.0 -+// -+// Copyright (c) 2019-2022 Andre Richter -+ -+//! Types for the `custom_test_frameworks` implementation. -+ -+#![no_std] -+ -+/// Unit test container. -+pub struct UnitTest { -+ /// Name of the test. -+ pub name: &'static str, -+ -+ /// Function pointer to the test. -+ pub test_func: fn(), -+} +The diff in this tutorial is skipped, because due to the changes in top-level folder structure, it +becomes unreadable. This might be fixed in the future. For now, consider using a diff tool like +`meld` to diff between the previous and the `kernel` folder of this tutorial to see the lion's share +of changes: + +```console +meld 11_exceptions_part1_groundwork 12_integrated_testing/kernel ``` diff --git a/12_integrated_testing/kernel/Cargo.toml b/12_integrated_testing/kernel/Cargo.toml new file mode 100644 index 00000000..be478e85 --- /dev/null +++ b/12_integrated_testing/kernel/Cargo.toml @@ -0,0 +1,58 @@ +[package] +name = "mingo" +version = "0.12.0" +authors = ["Andre Richter "] +edition = "2021" + + +[features] +default = [] +bsp_rpi3 = ["tock-registers"] +bsp_rpi4 = ["tock-registers"] +test_build = ["qemu-exit"] + +##-------------------------------------------------------------------------------------------------- +## Dependencies +##-------------------------------------------------------------------------------------------------- + +[dependencies] +test-types = { path = "../libraries/test-types" } + +# Optional dependencies +tock-registers = { version = "0.7.x", default-features = false, features = ["register_types"], optional = true } +qemu-exit = { version = "3.x.x", optional = true } + +# Platform specific dependencies +[target.'cfg(target_arch = "aarch64")'.dependencies] +cortex-a = { version = "7.x.x" } + +##-------------------------------------------------------------------------------------------------- +## Testing +##-------------------------------------------------------------------------------------------------- + +[dev-dependencies] +test-macros = { path = "../libraries/test-macros" } + +# Unit tests are done in the library part of the kernel. +[lib] +name = "libkernel" +test = true + +# Disable unit tests for the kernel binary. +[[bin]] +name = "kernel" +path = "src/main.rs" +test = false + +# List of tests without harness. +[[test]] +name = "00_console_sanity" +harness = false + +[[test]] +name = "02_exception_sync_page_fault" +harness = false + +[[test]] +name = "03_exception_restore_sanity" +harness = false diff --git a/12_integrated_testing/build.rs b/12_integrated_testing/kernel/build.rs similarity index 100% rename from 12_integrated_testing/build.rs rename to 12_integrated_testing/kernel/build.rs diff --git a/12_integrated_testing/src/_arch/aarch64/cpu.rs b/12_integrated_testing/kernel/src/_arch/aarch64/cpu.rs similarity index 100% rename from 12_integrated_testing/src/_arch/aarch64/cpu.rs rename to 12_integrated_testing/kernel/src/_arch/aarch64/cpu.rs diff --git a/12_integrated_testing/src/_arch/aarch64/cpu/boot.rs b/12_integrated_testing/kernel/src/_arch/aarch64/cpu/boot.rs similarity index 100% rename from 12_integrated_testing/src/_arch/aarch64/cpu/boot.rs rename to 12_integrated_testing/kernel/src/_arch/aarch64/cpu/boot.rs diff --git a/12_integrated_testing/src/_arch/aarch64/cpu/boot.s b/12_integrated_testing/kernel/src/_arch/aarch64/cpu/boot.s similarity index 100% rename from 12_integrated_testing/src/_arch/aarch64/cpu/boot.s rename to 12_integrated_testing/kernel/src/_arch/aarch64/cpu/boot.s diff --git a/12_integrated_testing/src/_arch/aarch64/exception.rs b/12_integrated_testing/kernel/src/_arch/aarch64/exception.rs similarity index 100% rename from 12_integrated_testing/src/_arch/aarch64/exception.rs rename to 12_integrated_testing/kernel/src/_arch/aarch64/exception.rs diff --git a/12_integrated_testing/src/_arch/aarch64/exception.s b/12_integrated_testing/kernel/src/_arch/aarch64/exception.s similarity index 100% rename from 12_integrated_testing/src/_arch/aarch64/exception.s rename to 12_integrated_testing/kernel/src/_arch/aarch64/exception.s diff --git a/12_integrated_testing/src/_arch/aarch64/exception/asynchronous.rs b/12_integrated_testing/kernel/src/_arch/aarch64/exception/asynchronous.rs similarity index 100% rename from 12_integrated_testing/src/_arch/aarch64/exception/asynchronous.rs rename to 12_integrated_testing/kernel/src/_arch/aarch64/exception/asynchronous.rs diff --git a/12_integrated_testing/src/_arch/aarch64/memory/mmu.rs b/12_integrated_testing/kernel/src/_arch/aarch64/memory/mmu.rs similarity index 100% rename from 12_integrated_testing/src/_arch/aarch64/memory/mmu.rs rename to 12_integrated_testing/kernel/src/_arch/aarch64/memory/mmu.rs diff --git a/12_integrated_testing/src/_arch/aarch64/memory/mmu/translation_table.rs b/12_integrated_testing/kernel/src/_arch/aarch64/memory/mmu/translation_table.rs similarity index 100% rename from 12_integrated_testing/src/_arch/aarch64/memory/mmu/translation_table.rs rename to 12_integrated_testing/kernel/src/_arch/aarch64/memory/mmu/translation_table.rs diff --git a/12_integrated_testing/src/_arch/aarch64/time.rs b/12_integrated_testing/kernel/src/_arch/aarch64/time.rs similarity index 100% rename from 12_integrated_testing/src/_arch/aarch64/time.rs rename to 12_integrated_testing/kernel/src/_arch/aarch64/time.rs diff --git a/12_integrated_testing/src/bsp.rs b/12_integrated_testing/kernel/src/bsp.rs similarity index 100% rename from 12_integrated_testing/src/bsp.rs rename to 12_integrated_testing/kernel/src/bsp.rs diff --git a/12_integrated_testing/src/bsp/device_driver.rs b/12_integrated_testing/kernel/src/bsp/device_driver.rs similarity index 100% rename from 12_integrated_testing/src/bsp/device_driver.rs rename to 12_integrated_testing/kernel/src/bsp/device_driver.rs diff --git a/12_integrated_testing/src/bsp/device_driver/bcm.rs b/12_integrated_testing/kernel/src/bsp/device_driver/bcm.rs similarity index 100% rename from 12_integrated_testing/src/bsp/device_driver/bcm.rs rename to 12_integrated_testing/kernel/src/bsp/device_driver/bcm.rs diff --git a/12_integrated_testing/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs b/12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs similarity index 100% rename from 12_integrated_testing/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs rename to 12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs diff --git a/12_integrated_testing/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs b/12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs similarity index 100% rename from 12_integrated_testing/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs rename to 12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs diff --git a/12_integrated_testing/src/bsp/device_driver/common.rs b/12_integrated_testing/kernel/src/bsp/device_driver/common.rs similarity index 100% rename from 12_integrated_testing/src/bsp/device_driver/common.rs rename to 12_integrated_testing/kernel/src/bsp/device_driver/common.rs diff --git a/12_integrated_testing/src/bsp/raspberrypi.rs b/12_integrated_testing/kernel/src/bsp/raspberrypi.rs similarity index 100% rename from 12_integrated_testing/src/bsp/raspberrypi.rs rename to 12_integrated_testing/kernel/src/bsp/raspberrypi.rs diff --git a/12_integrated_testing/src/bsp/raspberrypi/console.rs b/12_integrated_testing/kernel/src/bsp/raspberrypi/console.rs similarity index 100% rename from 12_integrated_testing/src/bsp/raspberrypi/console.rs rename to 12_integrated_testing/kernel/src/bsp/raspberrypi/console.rs diff --git a/12_integrated_testing/src/bsp/raspberrypi/cpu.rs b/12_integrated_testing/kernel/src/bsp/raspberrypi/cpu.rs similarity index 100% rename from 12_integrated_testing/src/bsp/raspberrypi/cpu.rs rename to 12_integrated_testing/kernel/src/bsp/raspberrypi/cpu.rs diff --git a/12_integrated_testing/src/bsp/raspberrypi/driver.rs b/12_integrated_testing/kernel/src/bsp/raspberrypi/driver.rs similarity index 100% rename from 12_integrated_testing/src/bsp/raspberrypi/driver.rs rename to 12_integrated_testing/kernel/src/bsp/raspberrypi/driver.rs diff --git a/12_integrated_testing/src/bsp/raspberrypi/kernel.ld b/12_integrated_testing/kernel/src/bsp/raspberrypi/kernel.ld similarity index 100% rename from 12_integrated_testing/src/bsp/raspberrypi/kernel.ld rename to 12_integrated_testing/kernel/src/bsp/raspberrypi/kernel.ld diff --git a/12_integrated_testing/src/bsp/raspberrypi/memory.rs b/12_integrated_testing/kernel/src/bsp/raspberrypi/memory.rs similarity index 100% rename from 12_integrated_testing/src/bsp/raspberrypi/memory.rs rename to 12_integrated_testing/kernel/src/bsp/raspberrypi/memory.rs diff --git a/12_integrated_testing/src/bsp/raspberrypi/memory/mmu.rs b/12_integrated_testing/kernel/src/bsp/raspberrypi/memory/mmu.rs similarity index 100% rename from 12_integrated_testing/src/bsp/raspberrypi/memory/mmu.rs rename to 12_integrated_testing/kernel/src/bsp/raspberrypi/memory/mmu.rs diff --git a/12_integrated_testing/src/console.rs b/12_integrated_testing/kernel/src/console.rs similarity index 100% rename from 12_integrated_testing/src/console.rs rename to 12_integrated_testing/kernel/src/console.rs diff --git a/12_integrated_testing/src/cpu.rs b/12_integrated_testing/kernel/src/cpu.rs similarity index 100% rename from 12_integrated_testing/src/cpu.rs rename to 12_integrated_testing/kernel/src/cpu.rs diff --git a/12_integrated_testing/src/cpu/boot.rs b/12_integrated_testing/kernel/src/cpu/boot.rs similarity index 100% rename from 12_integrated_testing/src/cpu/boot.rs rename to 12_integrated_testing/kernel/src/cpu/boot.rs diff --git a/12_integrated_testing/src/driver.rs b/12_integrated_testing/kernel/src/driver.rs similarity index 100% rename from 12_integrated_testing/src/driver.rs rename to 12_integrated_testing/kernel/src/driver.rs diff --git a/12_integrated_testing/src/exception.rs b/12_integrated_testing/kernel/src/exception.rs similarity index 100% rename from 12_integrated_testing/src/exception.rs rename to 12_integrated_testing/kernel/src/exception.rs diff --git a/12_integrated_testing/src/exception/asynchronous.rs b/12_integrated_testing/kernel/src/exception/asynchronous.rs similarity index 100% rename from 12_integrated_testing/src/exception/asynchronous.rs rename to 12_integrated_testing/kernel/src/exception/asynchronous.rs diff --git a/12_integrated_testing/src/lib.rs b/12_integrated_testing/kernel/src/lib.rs similarity index 100% rename from 12_integrated_testing/src/lib.rs rename to 12_integrated_testing/kernel/src/lib.rs diff --git a/12_integrated_testing/src/main.rs b/12_integrated_testing/kernel/src/main.rs similarity index 100% rename from 12_integrated_testing/src/main.rs rename to 12_integrated_testing/kernel/src/main.rs diff --git a/12_integrated_testing/src/memory.rs b/12_integrated_testing/kernel/src/memory.rs similarity index 100% rename from 12_integrated_testing/src/memory.rs rename to 12_integrated_testing/kernel/src/memory.rs diff --git a/12_integrated_testing/src/memory/mmu.rs b/12_integrated_testing/kernel/src/memory/mmu.rs similarity index 100% rename from 12_integrated_testing/src/memory/mmu.rs rename to 12_integrated_testing/kernel/src/memory/mmu.rs diff --git a/12_integrated_testing/src/memory/mmu/translation_table.rs b/12_integrated_testing/kernel/src/memory/mmu/translation_table.rs similarity index 100% rename from 12_integrated_testing/src/memory/mmu/translation_table.rs rename to 12_integrated_testing/kernel/src/memory/mmu/translation_table.rs diff --git a/12_integrated_testing/src/panic_wait.rs b/12_integrated_testing/kernel/src/panic_wait.rs similarity index 100% rename from 12_integrated_testing/src/panic_wait.rs rename to 12_integrated_testing/kernel/src/panic_wait.rs diff --git a/12_integrated_testing/src/print.rs b/12_integrated_testing/kernel/src/print.rs similarity index 100% rename from 12_integrated_testing/src/print.rs rename to 12_integrated_testing/kernel/src/print.rs diff --git a/12_integrated_testing/src/synchronization.rs b/12_integrated_testing/kernel/src/synchronization.rs similarity index 100% rename from 12_integrated_testing/src/synchronization.rs rename to 12_integrated_testing/kernel/src/synchronization.rs diff --git a/12_integrated_testing/src/time.rs b/12_integrated_testing/kernel/src/time.rs similarity index 100% rename from 12_integrated_testing/src/time.rs rename to 12_integrated_testing/kernel/src/time.rs diff --git a/12_integrated_testing/tests/00_console_sanity.rb b/12_integrated_testing/kernel/tests/00_console_sanity.rb similarity index 100% rename from 12_integrated_testing/tests/00_console_sanity.rb rename to 12_integrated_testing/kernel/tests/00_console_sanity.rb diff --git a/12_integrated_testing/tests/00_console_sanity.rs b/12_integrated_testing/kernel/tests/00_console_sanity.rs similarity index 100% rename from 12_integrated_testing/tests/00_console_sanity.rs rename to 12_integrated_testing/kernel/tests/00_console_sanity.rs diff --git a/12_integrated_testing/tests/01_timer_sanity.rs b/12_integrated_testing/kernel/tests/01_timer_sanity.rs similarity index 100% rename from 12_integrated_testing/tests/01_timer_sanity.rs rename to 12_integrated_testing/kernel/tests/01_timer_sanity.rs diff --git a/12_integrated_testing/tests/02_exception_sync_page_fault.rs b/12_integrated_testing/kernel/tests/02_exception_sync_page_fault.rs similarity index 100% rename from 12_integrated_testing/tests/02_exception_sync_page_fault.rs rename to 12_integrated_testing/kernel/tests/02_exception_sync_page_fault.rs diff --git a/12_integrated_testing/tests/03_exception_restore_sanity.rb b/12_integrated_testing/kernel/tests/03_exception_restore_sanity.rb similarity index 100% rename from 12_integrated_testing/tests/03_exception_restore_sanity.rb rename to 12_integrated_testing/kernel/tests/03_exception_restore_sanity.rb diff --git a/12_integrated_testing/tests/03_exception_restore_sanity.rs b/12_integrated_testing/kernel/tests/03_exception_restore_sanity.rs similarity index 100% rename from 12_integrated_testing/tests/03_exception_restore_sanity.rs rename to 12_integrated_testing/kernel/tests/03_exception_restore_sanity.rs diff --git a/12_integrated_testing/tests/boot_test_string.rb b/12_integrated_testing/kernel/tests/boot_test_string.rb similarity index 100% rename from 12_integrated_testing/tests/boot_test_string.rb rename to 12_integrated_testing/kernel/tests/boot_test_string.rb diff --git a/12_integrated_testing/tests/panic_exit_success/mod.rs b/12_integrated_testing/kernel/tests/panic_exit_success/mod.rs similarity index 100% rename from 12_integrated_testing/tests/panic_exit_success/mod.rs rename to 12_integrated_testing/kernel/tests/panic_exit_success/mod.rs diff --git a/12_integrated_testing/tests/panic_wait_forever/mod.rs b/12_integrated_testing/kernel/tests/panic_wait_forever/mod.rs similarity index 100% rename from 12_integrated_testing/tests/panic_wait_forever/mod.rs rename to 12_integrated_testing/kernel/tests/panic_wait_forever/mod.rs diff --git a/12_integrated_testing/test-macros/Cargo.toml b/12_integrated_testing/libraries/test-macros/Cargo.toml similarity index 100% rename from 12_integrated_testing/test-macros/Cargo.toml rename to 12_integrated_testing/libraries/test-macros/Cargo.toml diff --git a/12_integrated_testing/test-macros/src/lib.rs b/12_integrated_testing/libraries/test-macros/src/lib.rs similarity index 100% rename from 12_integrated_testing/test-macros/src/lib.rs rename to 12_integrated_testing/libraries/test-macros/src/lib.rs diff --git a/12_integrated_testing/test-types/Cargo.toml b/12_integrated_testing/libraries/test-types/Cargo.toml similarity index 100% rename from 12_integrated_testing/test-types/Cargo.toml rename to 12_integrated_testing/libraries/test-types/Cargo.toml diff --git a/12_integrated_testing/test-types/src/lib.rs b/12_integrated_testing/libraries/test-types/src/lib.rs similarity index 100% rename from 12_integrated_testing/test-types/src/lib.rs rename to 12_integrated_testing/libraries/test-types/src/lib.rs diff --git a/13_exceptions_part2_peripheral_IRQs/Cargo.lock b/13_exceptions_part2_peripheral_IRQs/Cargo.lock index 8fde49ef..51d3ab82 100644 --- a/13_exceptions_part2_peripheral_IRQs/Cargo.lock +++ b/13_exceptions_part2_peripheral_IRQs/Cargo.lock @@ -39,9 +39,9 @@ checksum = "9ff023245bfcc73fb890e1f8d5383825b3131cc920020a5c487d6f113dfc428a" [[package]] name = "quote" -version = "1.0.17" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "632d02bff7f874a36f33ea8bb416cd484b90cc66c1194b1a1110d067a7013f58" +checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1" dependencies = [ "proc-macro2", ] diff --git a/13_exceptions_part2_peripheral_IRQs/Cargo.toml b/13_exceptions_part2_peripheral_IRQs/Cargo.toml index 7ef55831..6480a727 100644 --- a/13_exceptions_part2_peripheral_IRQs/Cargo.toml +++ b/13_exceptions_part2_peripheral_IRQs/Cargo.toml @@ -1,60 +1,9 @@ -[package] -name = "mingo" -version = "0.13.0" -authors = ["Andre Richter "] -edition = "2021" +[workspace] + +members = [ + "libraries/*", + "kernel" +] [profile.release] lto = true - -[features] -default = [] -bsp_rpi3 = ["tock-registers"] -bsp_rpi4 = ["tock-registers"] -test_build = ["qemu-exit"] - -##-------------------------------------------------------------------------------------------------- -## Dependencies -##-------------------------------------------------------------------------------------------------- - -[dependencies] -test-types = { path = "test-types" } - -# Optional dependencies -tock-registers = { version = "0.7.x", default-features = false, features = ["register_types"], optional = true } -qemu-exit = { version = "3.x.x", optional = true } - -# Platform specific dependencies -[target.'cfg(target_arch = "aarch64")'.dependencies] -cortex-a = { version = "7.x.x" } - -##-------------------------------------------------------------------------------------------------- -## Testing -##-------------------------------------------------------------------------------------------------- - -[dev-dependencies] -test-macros = { path = "test-macros" } - -# Unit tests are done in the library part of the kernel. -[lib] -name = "libkernel" -test = true - -# Disable unit tests for the kernel binary. -[[bin]] -name = "kernel" -path = "src/main.rs" -test = false - -# List of tests without harness. -[[test]] -name = "00_console_sanity" -harness = false - -[[test]] -name = "02_exception_sync_page_fault" -harness = false - -[[test]] -name = "03_exception_restore_sanity" -harness = false diff --git a/13_exceptions_part2_peripheral_IRQs/Makefile b/13_exceptions_part2_peripheral_IRQs/Makefile index 6adb1aca..427c9303 100644 --- a/13_exceptions_part2_peripheral_IRQs/Makefile +++ b/13_exceptions_part2_peripheral_IRQs/Makefile @@ -41,7 +41,7 @@ ifeq ($(BSP),rpi3) READELF_BINARY = aarch64-none-elf-readelf OPENOCD_ARG = -f /openocd/tcl/interface/ftdi/olimex-arm-usb-tiny-h.cfg -f /openocd/rpi3.cfg JTAG_BOOT_IMAGE = ../X1_JTAG_boot/jtag_boot_rpi3.img - LD_SCRIPT_PATH = $(shell pwd)/src/bsp/raspberrypi + LD_SCRIPT_PATH = $(shell pwd)/kernel/src/bsp/raspberrypi RUSTC_MISC_ARGS = -C target-cpu=cortex-a53 else ifeq ($(BSP),rpi4) TARGET = aarch64-unknown-none-softfloat @@ -55,7 +55,7 @@ else ifeq ($(BSP),rpi4) READELF_BINARY = aarch64-none-elf-readelf OPENOCD_ARG = -f /openocd/tcl/interface/ftdi/olimex-arm-usb-tiny-h.cfg -f /openocd/rpi4.cfg JTAG_BOOT_IMAGE = ../X1_JTAG_boot/jtag_boot_rpi4.img - LD_SCRIPT_PATH = $(shell pwd)/src/bsp/raspberrypi + LD_SCRIPT_PATH = $(shell pwd)/kernel/src/bsp/raspberrypi RUSTC_MISC_ARGS = -C target-cpu=cortex-a72 endif @@ -67,9 +67,9 @@ export LD_SCRIPT_PATH ##-------------------------------------------------------------------------------------------------- ## Targets and Prerequisites ##-------------------------------------------------------------------------------------------------- +KERNEL_MANIFEST = kernel/Cargo.toml KERNEL_LINKER_SCRIPT = kernel.ld - -LAST_BUILD_CONFIG = target/$(BSP).build_config +LAST_BUILD_CONFIG = target/$(BSP).build_config KERNEL_ELF = target/$(TARGET)/release/kernel # This parses cargo's dep-info file. @@ -94,11 +94,11 @@ COMPILER_ARGS = --target=$(TARGET) \ $(FEATURES) \ --release -RUSTC_CMD = cargo rustc $(COMPILER_ARGS) +RUSTC_CMD = cargo rustc $(COMPILER_ARGS) --manifest-path $(KERNEL_MANIFEST) DOC_CMD = cargo doc $(COMPILER_ARGS) CLIPPY_CMD = cargo clippy $(COMPILER_ARGS) CHECK_CMD = cargo check $(COMPILER_ARGS) -TEST_CMD = cargo test $(COMPILER_ARGS) +TEST_CMD = cargo test $(COMPILER_ARGS) --manifest-path $(KERNEL_MANIFEST) OBJCOPY_CMD = rust-objcopy \ --strip-all \ -O binary @@ -203,6 +203,8 @@ chainboot: $(KERNEL_BIN) ##------------------------------------------------------------------------------ clippy: @RUSTFLAGS="$(RUSTFLAGS_PEDANTIC)" $(CLIPPY_CMD) + @RUSTFLAGS="$(RUSTFLAGS_PEDANTIC)" $(CLIPPY_CMD) --features test_build --tests \ + --manifest-path $(KERNEL_MANIFEST) ##------------------------------------------------------------------------------ ## Clean @@ -299,6 +301,10 @@ test_boot: $(KERNEL_BIN) define KERNEL_TEST_RUNNER #!/usr/bin/env bash + # The cargo test runner seems to change into the crate under test's directory. Therefore, ensure + # this script executes from the root. + cd $(shell pwd) + TEST_ELF=$$(echo $$1 | sed -e 's/.*target/target/g') TEST_BINARY=$$(echo $$1.img | sed -e 's/.*target/target/g') diff --git a/13_exceptions_part2_peripheral_IRQs/README.md b/13_exceptions_part2_peripheral_IRQs/README.md index eefe4b7e..35e0307f 100644 --- a/13_exceptions_part2_peripheral_IRQs/README.md +++ b/13_exceptions_part2_peripheral_IRQs/README.md @@ -489,7 +489,7 @@ sequences might be needed. Since nothing complex is happening in the implementation, it is not covered in detail here. Please refer to [the source of the **peripheral** controller] to check it out. -[the source of the **peripheral** controller]: src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs +[the source of the **peripheral** controller]: kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs ##### The IRQ Handler Table @@ -639,7 +639,7 @@ As with the implementation of the BCM interrupt controller driver, we won't cove parts in exhaustive detail. For that, please refer to [this folder] folder which contains all the sources. -[this folder]: src/bsp/device_driver/arm +[this folder]: kernel/src/bsp/device_driver/arm ## Test it @@ -746,9 +746,9 @@ Minipush 1.0 ## Diff to previous ```diff -diff -uNr 12_integrated_testing/Cargo.toml 13_exceptions_part2_peripheral_IRQs/Cargo.toml ---- 12_integrated_testing/Cargo.toml -+++ 13_exceptions_part2_peripheral_IRQs/Cargo.toml +diff -uNr 12_integrated_testing/kernel/Cargo.toml 13_exceptions_part2_peripheral_IRQs/kernel/Cargo.toml +--- 12_integrated_testing/kernel/Cargo.toml ++++ 13_exceptions_part2_peripheral_IRQs/kernel/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mingo" @@ -758,9 +758,9 @@ diff -uNr 12_integrated_testing/Cargo.toml 13_exceptions_part2_peripheral_IRQs/C edition = "2021" -diff -uNr 12_integrated_testing/src/_arch/aarch64/cpu/smp.rs 13_exceptions_part2_peripheral_IRQs/src/_arch/aarch64/cpu/smp.rs ---- 12_integrated_testing/src/_arch/aarch64/cpu/smp.rs -+++ 13_exceptions_part2_peripheral_IRQs/src/_arch/aarch64/cpu/smp.rs +diff -uNr 12_integrated_testing/kernel/src/_arch/aarch64/cpu/smp.rs 13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/cpu/smp.rs +--- 12_integrated_testing/kernel/src/_arch/aarch64/cpu/smp.rs ++++ 13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/cpu/smp.rs @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// @@ -793,9 +793,9 @@ diff -uNr 12_integrated_testing/src/_arch/aarch64/cpu/smp.rs 13_exceptions_part2 + T::from((MPIDR_EL1.get() & CORE_MASK) as u8) +} -diff -uNr 12_integrated_testing/src/_arch/aarch64/exception/asynchronous.rs 13_exceptions_part2_peripheral_IRQs/src/_arch/aarch64/exception/asynchronous.rs ---- 12_integrated_testing/src/_arch/aarch64/exception/asynchronous.rs -+++ 13_exceptions_part2_peripheral_IRQs/src/_arch/aarch64/exception/asynchronous.rs +diff -uNr 12_integrated_testing/kernel/src/_arch/aarch64/exception/asynchronous.rs 13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/exception/asynchronous.rs +--- 12_integrated_testing/kernel/src/_arch/aarch64/exception/asynchronous.rs ++++ 13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/exception/asynchronous.rs @@ -11,13 +11,18 @@ //! //! crate::exception::asynchronous::arch_asynchronous @@ -889,9 +889,9 @@ diff -uNr 12_integrated_testing/src/_arch/aarch64/exception/asynchronous.rs 13_e #[rustfmt::skip] pub fn print_state() { -diff -uNr 12_integrated_testing/src/_arch/aarch64/exception.rs 13_exceptions_part2_peripheral_IRQs/src/_arch/aarch64/exception.rs ---- 12_integrated_testing/src/_arch/aarch64/exception.rs -+++ 13_exceptions_part2_peripheral_IRQs/src/_arch/aarch64/exception.rs +diff -uNr 12_integrated_testing/kernel/src/_arch/aarch64/exception.rs 13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/exception.rs +--- 12_integrated_testing/kernel/src/_arch/aarch64/exception.rs ++++ 13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/exception.rs @@ -11,6 +11,7 @@ //! //! crate::exception::arch_exception @@ -915,9 +915,9 @@ diff -uNr 12_integrated_testing/src/_arch/aarch64/exception.rs 13_exceptions_par #[no_mangle] -diff -uNr 12_integrated_testing/src/bsp/device_driver/arm/gicv2/gicc.rs 13_exceptions_part2_peripheral_IRQs/src/bsp/device_driver/arm/gicv2/gicc.rs ---- 12_integrated_testing/src/bsp/device_driver/arm/gicv2/gicc.rs -+++ 13_exceptions_part2_peripheral_IRQs/src/bsp/device_driver/arm/gicv2/gicc.rs +diff -uNr 12_integrated_testing/kernel/src/bsp/device_driver/arm/gicv2/gicc.rs 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/arm/gicv2/gicc.rs +--- 12_integrated_testing/kernel/src/bsp/device_driver/arm/gicv2/gicc.rs ++++ 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/arm/gicv2/gicc.rs @@ -0,0 +1,141 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// @@ -1061,9 +1061,9 @@ diff -uNr 12_integrated_testing/src/bsp/device_driver/arm/gicv2/gicc.rs 13_excep + } +} -diff -uNr 12_integrated_testing/src/bsp/device_driver/arm/gicv2/gicd.rs 13_exceptions_part2_peripheral_IRQs/src/bsp/device_driver/arm/gicv2/gicd.rs ---- 12_integrated_testing/src/bsp/device_driver/arm/gicv2/gicd.rs -+++ 13_exceptions_part2_peripheral_IRQs/src/bsp/device_driver/arm/gicv2/gicd.rs +diff -uNr 12_integrated_testing/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs +--- 12_integrated_testing/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs ++++ 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs @@ -0,0 +1,199 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// @@ -1265,9 +1265,9 @@ diff -uNr 12_integrated_testing/src/bsp/device_driver/arm/gicv2/gicd.rs 13_excep + } +} -diff -uNr 12_integrated_testing/src/bsp/device_driver/arm/gicv2.rs 13_exceptions_part2_peripheral_IRQs/src/bsp/device_driver/arm/gicv2.rs ---- 12_integrated_testing/src/bsp/device_driver/arm/gicv2.rs -+++ 13_exceptions_part2_peripheral_IRQs/src/bsp/device_driver/arm/gicv2.rs +diff -uNr 12_integrated_testing/kernel/src/bsp/device_driver/arm/gicv2.rs 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/arm/gicv2.rs +--- 12_integrated_testing/kernel/src/bsp/device_driver/arm/gicv2.rs ++++ 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/arm/gicv2.rs @@ -0,0 +1,219 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// @@ -1489,9 +1489,9 @@ diff -uNr 12_integrated_testing/src/bsp/device_driver/arm/gicv2.rs 13_exceptions + } +} -diff -uNr 12_integrated_testing/src/bsp/device_driver/arm.rs 13_exceptions_part2_peripheral_IRQs/src/bsp/device_driver/arm.rs ---- 12_integrated_testing/src/bsp/device_driver/arm.rs -+++ 13_exceptions_part2_peripheral_IRQs/src/bsp/device_driver/arm.rs +diff -uNr 12_integrated_testing/kernel/src/bsp/device_driver/arm.rs 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/arm.rs +--- 12_integrated_testing/kernel/src/bsp/device_driver/arm.rs ++++ 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/arm.rs @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// @@ -1503,9 +1503,9 @@ diff -uNr 12_integrated_testing/src/bsp/device_driver/arm.rs 13_exceptions_part2 + +pub use gicv2::*; -diff -uNr 12_integrated_testing/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs 13_exceptions_part2_peripheral_IRQs/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs ---- 12_integrated_testing/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs -+++ 13_exceptions_part2_peripheral_IRQs/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs +diff -uNr 12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs +--- 12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs ++++ 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs @@ -6,7 +6,7 @@ use crate::{ @@ -1534,9 +1534,9 @@ diff -uNr 12_integrated_testing/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs 13_exc } -diff -uNr 12_integrated_testing/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs 13_exceptions_part2_peripheral_IRQs/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs ---- 12_integrated_testing/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs -+++ 13_exceptions_part2_peripheral_IRQs/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs +diff -uNr 12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs +--- 12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs ++++ 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs @@ -0,0 +1,167 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// @@ -1706,9 +1706,9 @@ diff -uNr 12_integrated_testing/src/bsp/device_driver/bcm/bcm2xxx_interrupt_cont + } +} -diff -uNr 12_integrated_testing/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs 13_exceptions_part2_peripheral_IRQs/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs ---- 12_integrated_testing/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs -+++ 13_exceptions_part2_peripheral_IRQs/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs +diff -uNr 12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs +--- 12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs ++++ 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs @@ -0,0 +1,131 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// @@ -1842,9 +1842,9 @@ diff -uNr 12_integrated_testing/src/bsp/device_driver/bcm/bcm2xxx_interrupt_cont + } +} -diff -uNr 12_integrated_testing/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs 13_exceptions_part2_peripheral_IRQs/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs ---- 12_integrated_testing/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs -+++ 13_exceptions_part2_peripheral_IRQs/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs +diff -uNr 12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs +--- 12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs ++++ 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs @@ -10,8 +10,8 @@ //! - @@ -2010,9 +2010,9 @@ diff -uNr 12_integrated_testing/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs + } +} -diff -uNr 12_integrated_testing/src/bsp/device_driver/bcm.rs 13_exceptions_part2_peripheral_IRQs/src/bsp/device_driver/bcm.rs ---- 12_integrated_testing/src/bsp/device_driver/bcm.rs -+++ 13_exceptions_part2_peripheral_IRQs/src/bsp/device_driver/bcm.rs +diff -uNr 12_integrated_testing/kernel/src/bsp/device_driver/bcm.rs 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm.rs +--- 12_integrated_testing/kernel/src/bsp/device_driver/bcm.rs ++++ 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm.rs @@ -5,7 +5,11 @@ //! BCM driver top level. @@ -2026,9 +2026,9 @@ diff -uNr 12_integrated_testing/src/bsp/device_driver/bcm.rs 13_exceptions_part2 +pub use bcm2xxx_interrupt_controller::*; pub use bcm2xxx_pl011_uart::*; -diff -uNr 12_integrated_testing/src/bsp/device_driver.rs 13_exceptions_part2_peripheral_IRQs/src/bsp/device_driver.rs ---- 12_integrated_testing/src/bsp/device_driver.rs -+++ 13_exceptions_part2_peripheral_IRQs/src/bsp/device_driver.rs +diff -uNr 12_integrated_testing/kernel/src/bsp/device_driver.rs 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver.rs +--- 12_integrated_testing/kernel/src/bsp/device_driver.rs ++++ 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver.rs @@ -4,9 +4,13 @@ //! Device driver. @@ -2044,9 +2044,9 @@ diff -uNr 12_integrated_testing/src/bsp/device_driver.rs 13_exceptions_part2_per #[cfg(any(feature = "bsp_rpi3", feature = "bsp_rpi4"))] pub use bcm::*; -diff -uNr 12_integrated_testing/src/bsp/raspberrypi/driver.rs 13_exceptions_part2_peripheral_IRQs/src/bsp/raspberrypi/driver.rs ---- 12_integrated_testing/src/bsp/raspberrypi/driver.rs -+++ 13_exceptions_part2_peripheral_IRQs/src/bsp/raspberrypi/driver.rs +diff -uNr 12_integrated_testing/kernel/src/bsp/raspberrypi/driver.rs 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/driver.rs +--- 12_integrated_testing/kernel/src/bsp/raspberrypi/driver.rs ++++ 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/driver.rs @@ -12,7 +12,7 @@ /// Device Driver Manager type. @@ -2070,9 +2070,9 @@ diff -uNr 12_integrated_testing/src/bsp/raspberrypi/driver.rs 13_exceptions_part //-------------------------------------------------------------------------------------------------- -diff -uNr 12_integrated_testing/src/bsp/raspberrypi/exception/asynchronous.rs 13_exceptions_part2_peripheral_IRQs/src/bsp/raspberrypi/exception/asynchronous.rs ---- 12_integrated_testing/src/bsp/raspberrypi/exception/asynchronous.rs -+++ 13_exceptions_part2_peripheral_IRQs/src/bsp/raspberrypi/exception/asynchronous.rs +diff -uNr 12_integrated_testing/kernel/src/bsp/raspberrypi/exception/asynchronous.rs 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/exception/asynchronous.rs +--- 12_integrated_testing/kernel/src/bsp/raspberrypi/exception/asynchronous.rs ++++ 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/exception/asynchronous.rs @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// @@ -2111,9 +2111,9 @@ diff -uNr 12_integrated_testing/src/bsp/raspberrypi/exception/asynchronous.rs 13 + &super::super::INTERRUPT_CONTROLLER +} -diff -uNr 12_integrated_testing/src/bsp/raspberrypi/exception.rs 13_exceptions_part2_peripheral_IRQs/src/bsp/raspberrypi/exception.rs ---- 12_integrated_testing/src/bsp/raspberrypi/exception.rs -+++ 13_exceptions_part2_peripheral_IRQs/src/bsp/raspberrypi/exception.rs +diff -uNr 12_integrated_testing/kernel/src/bsp/raspberrypi/exception.rs 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/exception.rs +--- 12_integrated_testing/kernel/src/bsp/raspberrypi/exception.rs ++++ 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/exception.rs @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// @@ -2123,9 +2123,9 @@ diff -uNr 12_integrated_testing/src/bsp/raspberrypi/exception.rs 13_exceptions_p + +pub mod asynchronous; -diff -uNr 12_integrated_testing/src/bsp/raspberrypi/memory.rs 13_exceptions_part2_peripheral_IRQs/src/bsp/raspberrypi/memory.rs ---- 12_integrated_testing/src/bsp/raspberrypi/memory.rs -+++ 13_exceptions_part2_peripheral_IRQs/src/bsp/raspberrypi/memory.rs +diff -uNr 12_integrated_testing/kernel/src/bsp/raspberrypi/memory.rs 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/memory.rs +--- 12_integrated_testing/kernel/src/bsp/raspberrypi/memory.rs ++++ 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/memory.rs @@ -73,10 +73,12 @@ pub mod mmio { use super::*; @@ -2153,9 +2153,9 @@ diff -uNr 12_integrated_testing/src/bsp/raspberrypi/memory.rs 13_exceptions_part } } -diff -uNr 12_integrated_testing/src/bsp/raspberrypi.rs 13_exceptions_part2_peripheral_IRQs/src/bsp/raspberrypi.rs ---- 12_integrated_testing/src/bsp/raspberrypi.rs -+++ 13_exceptions_part2_peripheral_IRQs/src/bsp/raspberrypi.rs +diff -uNr 12_integrated_testing/kernel/src/bsp/raspberrypi.rs 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi.rs +--- 12_integrated_testing/kernel/src/bsp/raspberrypi.rs ++++ 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi.rs @@ -7,6 +7,7 @@ pub mod console; pub mod cpu; @@ -2193,9 +2193,9 @@ diff -uNr 12_integrated_testing/src/bsp/raspberrypi.rs 13_exceptions_part2_perip //-------------------------------------------------------------------------------------------------- // Public Code -diff -uNr 12_integrated_testing/src/cpu/smp.rs 13_exceptions_part2_peripheral_IRQs/src/cpu/smp.rs ---- 12_integrated_testing/src/cpu/smp.rs -+++ 13_exceptions_part2_peripheral_IRQs/src/cpu/smp.rs +diff -uNr 12_integrated_testing/kernel/src/cpu/smp.rs 13_exceptions_part2_peripheral_IRQs/kernel/src/cpu/smp.rs +--- 12_integrated_testing/kernel/src/cpu/smp.rs ++++ 13_exceptions_part2_peripheral_IRQs/kernel/src/cpu/smp.rs @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// @@ -2212,9 +2212,9 @@ diff -uNr 12_integrated_testing/src/cpu/smp.rs 13_exceptions_part2_peripheral_IR +//-------------------------------------------------------------------------------------------------- +pub use arch_smp::core_id; -diff -uNr 12_integrated_testing/src/cpu.rs 13_exceptions_part2_peripheral_IRQs/src/cpu.rs ---- 12_integrated_testing/src/cpu.rs -+++ 13_exceptions_part2_peripheral_IRQs/src/cpu.rs +diff -uNr 12_integrated_testing/kernel/src/cpu.rs 13_exceptions_part2_peripheral_IRQs/kernel/src/cpu.rs +--- 12_integrated_testing/kernel/src/cpu.rs ++++ 13_exceptions_part2_peripheral_IRQs/kernel/src/cpu.rs @@ -10,6 +10,8 @@ mod boot; @@ -2225,9 +2225,9 @@ diff -uNr 12_integrated_testing/src/cpu.rs 13_exceptions_part2_peripheral_IRQs/s // Architectural Public Reexports //-------------------------------------------------------------------------------------------------- -diff -uNr 12_integrated_testing/src/driver.rs 13_exceptions_part2_peripheral_IRQs/src/driver.rs ---- 12_integrated_testing/src/driver.rs -+++ 13_exceptions_part2_peripheral_IRQs/src/driver.rs +diff -uNr 12_integrated_testing/kernel/src/driver.rs 13_exceptions_part2_peripheral_IRQs/kernel/src/driver.rs +--- 12_integrated_testing/kernel/src/driver.rs ++++ 13_exceptions_part2_peripheral_IRQs/kernel/src/driver.rs @@ -23,6 +23,14 @@ unsafe fn init(&self) -> Result<(), &'static str> { Ok(()) @@ -2244,9 +2244,9 @@ diff -uNr 12_integrated_testing/src/driver.rs 13_exceptions_part2_peripheral_IRQ /// Device driver management functions. -diff -uNr 12_integrated_testing/src/exception/asynchronous.rs 13_exceptions_part2_peripheral_IRQs/src/exception/asynchronous.rs ---- 12_integrated_testing/src/exception/asynchronous.rs -+++ 13_exceptions_part2_peripheral_IRQs/src/exception/asynchronous.rs +diff -uNr 12_integrated_testing/kernel/src/exception/asynchronous.rs 13_exceptions_part2_peripheral_IRQs/kernel/src/exception/asynchronous.rs +--- 12_integrated_testing/kernel/src/exception/asynchronous.rs ++++ 13_exceptions_part2_peripheral_IRQs/kernel/src/exception/asynchronous.rs @@ -8,7 +8,145 @@ #[path = "../_arch/aarch64/exception/asynchronous.rs"] mod arch_asynchronous; @@ -2395,9 +2395,9 @@ diff -uNr 12_integrated_testing/src/exception/asynchronous.rs 13_exceptions_part + ret +} -diff -uNr 12_integrated_testing/src/lib.rs 13_exceptions_part2_peripheral_IRQs/src/lib.rs ---- 12_integrated_testing/src/lib.rs -+++ 13_exceptions_part2_peripheral_IRQs/src/lib.rs +diff -uNr 12_integrated_testing/kernel/src/lib.rs 13_exceptions_part2_peripheral_IRQs/kernel/src/lib.rs +--- 12_integrated_testing/kernel/src/lib.rs ++++ 13_exceptions_part2_peripheral_IRQs/kernel/src/lib.rs @@ -108,6 +108,7 @@ #![allow(clippy::upper_case_acronyms)] @@ -2415,9 +2415,9 @@ diff -uNr 12_integrated_testing/src/lib.rs 13_exceptions_part2_peripheral_IRQs/s //-------------------------------------------------------------------------------------------------- -diff -uNr 12_integrated_testing/src/main.rs 13_exceptions_part2_peripheral_IRQs/src/main.rs ---- 12_integrated_testing/src/main.rs -+++ 13_exceptions_part2_peripheral_IRQs/src/main.rs +diff -uNr 12_integrated_testing/kernel/src/main.rs 13_exceptions_part2_peripheral_IRQs/kernel/src/main.rs +--- 12_integrated_testing/kernel/src/main.rs ++++ 13_exceptions_part2_peripheral_IRQs/kernel/src/main.rs @@ -11,7 +11,7 @@ #![no_main] #![no_std] @@ -2484,9 +2484,9 @@ diff -uNr 12_integrated_testing/src/main.rs 13_exceptions_part2_peripheral_IRQs/ + cpu::wait_forever(); } -diff -uNr 12_integrated_testing/src/panic_wait.rs 13_exceptions_part2_peripheral_IRQs/src/panic_wait.rs ---- 12_integrated_testing/src/panic_wait.rs -+++ 13_exceptions_part2_peripheral_IRQs/src/panic_wait.rs +diff -uNr 12_integrated_testing/kernel/src/panic_wait.rs 13_exceptions_part2_peripheral_IRQs/kernel/src/panic_wait.rs +--- 12_integrated_testing/kernel/src/panic_wait.rs ++++ 13_exceptions_part2_peripheral_IRQs/kernel/src/panic_wait.rs @@ -4,7 +4,7 @@ //! A panic handler that infinitely waits. @@ -2506,9 +2506,9 @@ diff -uNr 12_integrated_testing/src/panic_wait.rs 13_exceptions_part2_peripheral panic_prevent_reenter(); -diff -uNr 12_integrated_testing/src/state.rs 13_exceptions_part2_peripheral_IRQs/src/state.rs ---- 12_integrated_testing/src/state.rs -+++ 13_exceptions_part2_peripheral_IRQs/src/state.rs +diff -uNr 12_integrated_testing/kernel/src/state.rs 13_exceptions_part2_peripheral_IRQs/kernel/src/state.rs +--- 12_integrated_testing/kernel/src/state.rs ++++ 13_exceptions_part2_peripheral_IRQs/kernel/src/state.rs @@ -0,0 +1,92 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// @@ -2603,9 +2603,9 @@ diff -uNr 12_integrated_testing/src/state.rs 13_exceptions_part2_peripheral_IRQs + } +} -diff -uNr 12_integrated_testing/src/synchronization.rs 13_exceptions_part2_peripheral_IRQs/src/synchronization.rs ---- 12_integrated_testing/src/synchronization.rs -+++ 13_exceptions_part2_peripheral_IRQs/src/synchronization.rs +diff -uNr 12_integrated_testing/kernel/src/synchronization.rs 13_exceptions_part2_peripheral_IRQs/kernel/src/synchronization.rs +--- 12_integrated_testing/kernel/src/synchronization.rs ++++ 13_exceptions_part2_peripheral_IRQs/kernel/src/synchronization.rs @@ -28,6 +28,21 @@ /// Locks the mutex and grants the closure temporary mutable access to the wrapped data. fn lock(&self, f: impl FnOnce(&mut Self::Data) -> R) -> R; @@ -2738,9 +2738,9 @@ diff -uNr 12_integrated_testing/src/synchronization.rs 13_exceptions_part2_perip + } } -diff -uNr 12_integrated_testing/tests/04_exception_irq_sanity.rs 13_exceptions_part2_peripheral_IRQs/tests/04_exception_irq_sanity.rs ---- 12_integrated_testing/tests/04_exception_irq_sanity.rs -+++ 13_exceptions_part2_peripheral_IRQs/tests/04_exception_irq_sanity.rs +diff -uNr 12_integrated_testing/kernel/tests/04_exception_irq_sanity.rs 13_exceptions_part2_peripheral_IRQs/kernel/tests/04_exception_irq_sanity.rs +--- 12_integrated_testing/kernel/tests/04_exception_irq_sanity.rs ++++ 13_exceptions_part2_peripheral_IRQs/kernel/tests/04_exception_irq_sanity.rs @@ -0,0 +1,66 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/Cargo.toml b/13_exceptions_part2_peripheral_IRQs/kernel/Cargo.toml new file mode 100644 index 00000000..1d99ad38 --- /dev/null +++ b/13_exceptions_part2_peripheral_IRQs/kernel/Cargo.toml @@ -0,0 +1,58 @@ +[package] +name = "mingo" +version = "0.13.0" +authors = ["Andre Richter "] +edition = "2021" + + +[features] +default = [] +bsp_rpi3 = ["tock-registers"] +bsp_rpi4 = ["tock-registers"] +test_build = ["qemu-exit"] + +##-------------------------------------------------------------------------------------------------- +## Dependencies +##-------------------------------------------------------------------------------------------------- + +[dependencies] +test-types = { path = "../libraries/test-types" } + +# Optional dependencies +tock-registers = { version = "0.7.x", default-features = false, features = ["register_types"], optional = true } +qemu-exit = { version = "3.x.x", optional = true } + +# Platform specific dependencies +[target.'cfg(target_arch = "aarch64")'.dependencies] +cortex-a = { version = "7.x.x" } + +##-------------------------------------------------------------------------------------------------- +## Testing +##-------------------------------------------------------------------------------------------------- + +[dev-dependencies] +test-macros = { path = "../libraries/test-macros" } + +# Unit tests are done in the library part of the kernel. +[lib] +name = "libkernel" +test = true + +# Disable unit tests for the kernel binary. +[[bin]] +name = "kernel" +path = "src/main.rs" +test = false + +# List of tests without harness. +[[test]] +name = "00_console_sanity" +harness = false + +[[test]] +name = "02_exception_sync_page_fault" +harness = false + +[[test]] +name = "03_exception_restore_sanity" +harness = false diff --git a/13_exceptions_part2_peripheral_IRQs/build.rs b/13_exceptions_part2_peripheral_IRQs/kernel/build.rs similarity index 100% rename from 13_exceptions_part2_peripheral_IRQs/build.rs rename to 13_exceptions_part2_peripheral_IRQs/kernel/build.rs diff --git a/13_exceptions_part2_peripheral_IRQs/src/_arch/aarch64/cpu.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/cpu.rs similarity index 100% rename from 13_exceptions_part2_peripheral_IRQs/src/_arch/aarch64/cpu.rs rename to 13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/cpu.rs diff --git a/13_exceptions_part2_peripheral_IRQs/src/_arch/aarch64/cpu/boot.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/cpu/boot.rs similarity index 100% rename from 13_exceptions_part2_peripheral_IRQs/src/_arch/aarch64/cpu/boot.rs rename to 13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/cpu/boot.rs diff --git a/13_exceptions_part2_peripheral_IRQs/src/_arch/aarch64/cpu/boot.s b/13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/cpu/boot.s similarity index 100% rename from 13_exceptions_part2_peripheral_IRQs/src/_arch/aarch64/cpu/boot.s rename to 13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/cpu/boot.s diff --git a/13_exceptions_part2_peripheral_IRQs/src/_arch/aarch64/cpu/smp.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/cpu/smp.rs similarity index 100% rename from 13_exceptions_part2_peripheral_IRQs/src/_arch/aarch64/cpu/smp.rs rename to 13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/cpu/smp.rs diff --git a/13_exceptions_part2_peripheral_IRQs/src/_arch/aarch64/exception.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/exception.rs similarity index 100% rename from 13_exceptions_part2_peripheral_IRQs/src/_arch/aarch64/exception.rs rename to 13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/exception.rs diff --git a/13_exceptions_part2_peripheral_IRQs/src/_arch/aarch64/exception.s b/13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/exception.s similarity index 100% rename from 13_exceptions_part2_peripheral_IRQs/src/_arch/aarch64/exception.s rename to 13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/exception.s diff --git a/13_exceptions_part2_peripheral_IRQs/src/_arch/aarch64/exception/asynchronous.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/exception/asynchronous.rs similarity index 100% rename from 13_exceptions_part2_peripheral_IRQs/src/_arch/aarch64/exception/asynchronous.rs rename to 13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/exception/asynchronous.rs diff --git a/13_exceptions_part2_peripheral_IRQs/src/_arch/aarch64/memory/mmu.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/memory/mmu.rs similarity index 100% rename from 13_exceptions_part2_peripheral_IRQs/src/_arch/aarch64/memory/mmu.rs rename to 13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/memory/mmu.rs diff --git a/13_exceptions_part2_peripheral_IRQs/src/_arch/aarch64/memory/mmu/translation_table.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/memory/mmu/translation_table.rs similarity index 100% rename from 13_exceptions_part2_peripheral_IRQs/src/_arch/aarch64/memory/mmu/translation_table.rs rename to 13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/memory/mmu/translation_table.rs diff --git a/13_exceptions_part2_peripheral_IRQs/src/_arch/aarch64/time.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/time.rs similarity index 100% rename from 13_exceptions_part2_peripheral_IRQs/src/_arch/aarch64/time.rs rename to 13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/time.rs diff --git a/13_exceptions_part2_peripheral_IRQs/src/bsp.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp.rs similarity index 100% rename from 13_exceptions_part2_peripheral_IRQs/src/bsp.rs rename to 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp.rs diff --git a/13_exceptions_part2_peripheral_IRQs/src/bsp/device_driver.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver.rs similarity index 100% rename from 13_exceptions_part2_peripheral_IRQs/src/bsp/device_driver.rs rename to 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver.rs diff --git a/13_exceptions_part2_peripheral_IRQs/src/bsp/device_driver/arm.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/arm.rs similarity index 100% rename from 13_exceptions_part2_peripheral_IRQs/src/bsp/device_driver/arm.rs rename to 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/arm.rs diff --git a/13_exceptions_part2_peripheral_IRQs/src/bsp/device_driver/arm/gicv2.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/arm/gicv2.rs similarity index 100% rename from 13_exceptions_part2_peripheral_IRQs/src/bsp/device_driver/arm/gicv2.rs rename to 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/arm/gicv2.rs diff --git a/13_exceptions_part2_peripheral_IRQs/src/bsp/device_driver/arm/gicv2/gicc.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/arm/gicv2/gicc.rs similarity index 100% rename from 13_exceptions_part2_peripheral_IRQs/src/bsp/device_driver/arm/gicv2/gicc.rs rename to 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/arm/gicv2/gicc.rs diff --git a/13_exceptions_part2_peripheral_IRQs/src/bsp/device_driver/arm/gicv2/gicd.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs similarity index 100% rename from 13_exceptions_part2_peripheral_IRQs/src/bsp/device_driver/arm/gicv2/gicd.rs rename to 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs diff --git a/13_exceptions_part2_peripheral_IRQs/src/bsp/device_driver/bcm.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm.rs similarity index 100% rename from 13_exceptions_part2_peripheral_IRQs/src/bsp/device_driver/bcm.rs rename to 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm.rs diff --git a/13_exceptions_part2_peripheral_IRQs/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs similarity index 100% rename from 13_exceptions_part2_peripheral_IRQs/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs rename to 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs diff --git a/13_exceptions_part2_peripheral_IRQs/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs similarity index 100% rename from 13_exceptions_part2_peripheral_IRQs/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs rename to 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs diff --git a/13_exceptions_part2_peripheral_IRQs/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs similarity index 100% rename from 13_exceptions_part2_peripheral_IRQs/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs rename to 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs diff --git a/13_exceptions_part2_peripheral_IRQs/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs similarity index 100% rename from 13_exceptions_part2_peripheral_IRQs/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs rename to 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs diff --git a/13_exceptions_part2_peripheral_IRQs/src/bsp/device_driver/common.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/common.rs similarity index 100% rename from 13_exceptions_part2_peripheral_IRQs/src/bsp/device_driver/common.rs rename to 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/common.rs diff --git a/13_exceptions_part2_peripheral_IRQs/src/bsp/raspberrypi.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi.rs similarity index 100% rename from 13_exceptions_part2_peripheral_IRQs/src/bsp/raspberrypi.rs rename to 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi.rs diff --git a/13_exceptions_part2_peripheral_IRQs/src/bsp/raspberrypi/console.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/console.rs similarity index 100% rename from 13_exceptions_part2_peripheral_IRQs/src/bsp/raspberrypi/console.rs rename to 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/console.rs diff --git a/13_exceptions_part2_peripheral_IRQs/src/bsp/raspberrypi/cpu.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/cpu.rs similarity index 100% rename from 13_exceptions_part2_peripheral_IRQs/src/bsp/raspberrypi/cpu.rs rename to 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/cpu.rs diff --git a/13_exceptions_part2_peripheral_IRQs/src/bsp/raspberrypi/driver.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/driver.rs similarity index 100% rename from 13_exceptions_part2_peripheral_IRQs/src/bsp/raspberrypi/driver.rs rename to 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/driver.rs diff --git a/13_exceptions_part2_peripheral_IRQs/src/bsp/raspberrypi/exception.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/exception.rs similarity index 100% rename from 13_exceptions_part2_peripheral_IRQs/src/bsp/raspberrypi/exception.rs rename to 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/exception.rs diff --git a/13_exceptions_part2_peripheral_IRQs/src/bsp/raspberrypi/exception/asynchronous.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/exception/asynchronous.rs similarity index 100% rename from 13_exceptions_part2_peripheral_IRQs/src/bsp/raspberrypi/exception/asynchronous.rs rename to 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/exception/asynchronous.rs diff --git a/13_exceptions_part2_peripheral_IRQs/src/bsp/raspberrypi/kernel.ld b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/kernel.ld similarity index 100% rename from 13_exceptions_part2_peripheral_IRQs/src/bsp/raspberrypi/kernel.ld rename to 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/kernel.ld diff --git a/13_exceptions_part2_peripheral_IRQs/src/bsp/raspberrypi/memory.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/memory.rs similarity index 100% rename from 13_exceptions_part2_peripheral_IRQs/src/bsp/raspberrypi/memory.rs rename to 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/memory.rs diff --git a/13_exceptions_part2_peripheral_IRQs/src/bsp/raspberrypi/memory/mmu.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/memory/mmu.rs similarity index 100% rename from 13_exceptions_part2_peripheral_IRQs/src/bsp/raspberrypi/memory/mmu.rs rename to 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/memory/mmu.rs diff --git a/13_exceptions_part2_peripheral_IRQs/src/console.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/console.rs similarity index 100% rename from 13_exceptions_part2_peripheral_IRQs/src/console.rs rename to 13_exceptions_part2_peripheral_IRQs/kernel/src/console.rs diff --git a/13_exceptions_part2_peripheral_IRQs/src/cpu.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/cpu.rs similarity index 100% rename from 13_exceptions_part2_peripheral_IRQs/src/cpu.rs rename to 13_exceptions_part2_peripheral_IRQs/kernel/src/cpu.rs diff --git a/13_exceptions_part2_peripheral_IRQs/src/cpu/boot.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/cpu/boot.rs similarity index 100% rename from 13_exceptions_part2_peripheral_IRQs/src/cpu/boot.rs rename to 13_exceptions_part2_peripheral_IRQs/kernel/src/cpu/boot.rs diff --git a/13_exceptions_part2_peripheral_IRQs/src/cpu/smp.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/cpu/smp.rs similarity index 100% rename from 13_exceptions_part2_peripheral_IRQs/src/cpu/smp.rs rename to 13_exceptions_part2_peripheral_IRQs/kernel/src/cpu/smp.rs diff --git a/13_exceptions_part2_peripheral_IRQs/src/driver.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/driver.rs similarity index 100% rename from 13_exceptions_part2_peripheral_IRQs/src/driver.rs rename to 13_exceptions_part2_peripheral_IRQs/kernel/src/driver.rs diff --git a/13_exceptions_part2_peripheral_IRQs/src/exception.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/exception.rs similarity index 100% rename from 13_exceptions_part2_peripheral_IRQs/src/exception.rs rename to 13_exceptions_part2_peripheral_IRQs/kernel/src/exception.rs diff --git a/13_exceptions_part2_peripheral_IRQs/src/exception/asynchronous.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/exception/asynchronous.rs similarity index 100% rename from 13_exceptions_part2_peripheral_IRQs/src/exception/asynchronous.rs rename to 13_exceptions_part2_peripheral_IRQs/kernel/src/exception/asynchronous.rs diff --git a/13_exceptions_part2_peripheral_IRQs/src/lib.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/lib.rs similarity index 100% rename from 13_exceptions_part2_peripheral_IRQs/src/lib.rs rename to 13_exceptions_part2_peripheral_IRQs/kernel/src/lib.rs diff --git a/13_exceptions_part2_peripheral_IRQs/src/main.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/main.rs similarity index 100% rename from 13_exceptions_part2_peripheral_IRQs/src/main.rs rename to 13_exceptions_part2_peripheral_IRQs/kernel/src/main.rs diff --git a/13_exceptions_part2_peripheral_IRQs/src/memory.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/memory.rs similarity index 100% rename from 13_exceptions_part2_peripheral_IRQs/src/memory.rs rename to 13_exceptions_part2_peripheral_IRQs/kernel/src/memory.rs diff --git a/13_exceptions_part2_peripheral_IRQs/src/memory/mmu.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/memory/mmu.rs similarity index 100% rename from 13_exceptions_part2_peripheral_IRQs/src/memory/mmu.rs rename to 13_exceptions_part2_peripheral_IRQs/kernel/src/memory/mmu.rs diff --git a/13_exceptions_part2_peripheral_IRQs/src/memory/mmu/translation_table.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/memory/mmu/translation_table.rs similarity index 100% rename from 13_exceptions_part2_peripheral_IRQs/src/memory/mmu/translation_table.rs rename to 13_exceptions_part2_peripheral_IRQs/kernel/src/memory/mmu/translation_table.rs diff --git a/13_exceptions_part2_peripheral_IRQs/src/panic_wait.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/panic_wait.rs similarity index 100% rename from 13_exceptions_part2_peripheral_IRQs/src/panic_wait.rs rename to 13_exceptions_part2_peripheral_IRQs/kernel/src/panic_wait.rs diff --git a/13_exceptions_part2_peripheral_IRQs/src/print.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/print.rs similarity index 100% rename from 13_exceptions_part2_peripheral_IRQs/src/print.rs rename to 13_exceptions_part2_peripheral_IRQs/kernel/src/print.rs diff --git a/13_exceptions_part2_peripheral_IRQs/src/state.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/state.rs similarity index 100% rename from 13_exceptions_part2_peripheral_IRQs/src/state.rs rename to 13_exceptions_part2_peripheral_IRQs/kernel/src/state.rs diff --git a/13_exceptions_part2_peripheral_IRQs/src/synchronization.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/synchronization.rs similarity index 100% rename from 13_exceptions_part2_peripheral_IRQs/src/synchronization.rs rename to 13_exceptions_part2_peripheral_IRQs/kernel/src/synchronization.rs diff --git a/13_exceptions_part2_peripheral_IRQs/src/time.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/time.rs similarity index 100% rename from 13_exceptions_part2_peripheral_IRQs/src/time.rs rename to 13_exceptions_part2_peripheral_IRQs/kernel/src/time.rs diff --git a/13_exceptions_part2_peripheral_IRQs/tests/00_console_sanity.rb b/13_exceptions_part2_peripheral_IRQs/kernel/tests/00_console_sanity.rb similarity index 100% rename from 13_exceptions_part2_peripheral_IRQs/tests/00_console_sanity.rb rename to 13_exceptions_part2_peripheral_IRQs/kernel/tests/00_console_sanity.rb diff --git a/13_exceptions_part2_peripheral_IRQs/tests/00_console_sanity.rs b/13_exceptions_part2_peripheral_IRQs/kernel/tests/00_console_sanity.rs similarity index 100% rename from 13_exceptions_part2_peripheral_IRQs/tests/00_console_sanity.rs rename to 13_exceptions_part2_peripheral_IRQs/kernel/tests/00_console_sanity.rs diff --git a/13_exceptions_part2_peripheral_IRQs/tests/01_timer_sanity.rs b/13_exceptions_part2_peripheral_IRQs/kernel/tests/01_timer_sanity.rs similarity index 100% rename from 13_exceptions_part2_peripheral_IRQs/tests/01_timer_sanity.rs rename to 13_exceptions_part2_peripheral_IRQs/kernel/tests/01_timer_sanity.rs diff --git a/13_exceptions_part2_peripheral_IRQs/tests/02_exception_sync_page_fault.rs b/13_exceptions_part2_peripheral_IRQs/kernel/tests/02_exception_sync_page_fault.rs similarity index 100% rename from 13_exceptions_part2_peripheral_IRQs/tests/02_exception_sync_page_fault.rs rename to 13_exceptions_part2_peripheral_IRQs/kernel/tests/02_exception_sync_page_fault.rs diff --git a/13_exceptions_part2_peripheral_IRQs/tests/03_exception_restore_sanity.rb b/13_exceptions_part2_peripheral_IRQs/kernel/tests/03_exception_restore_sanity.rb similarity index 100% rename from 13_exceptions_part2_peripheral_IRQs/tests/03_exception_restore_sanity.rb rename to 13_exceptions_part2_peripheral_IRQs/kernel/tests/03_exception_restore_sanity.rb diff --git a/13_exceptions_part2_peripheral_IRQs/tests/03_exception_restore_sanity.rs b/13_exceptions_part2_peripheral_IRQs/kernel/tests/03_exception_restore_sanity.rs similarity index 100% rename from 13_exceptions_part2_peripheral_IRQs/tests/03_exception_restore_sanity.rs rename to 13_exceptions_part2_peripheral_IRQs/kernel/tests/03_exception_restore_sanity.rs diff --git a/13_exceptions_part2_peripheral_IRQs/tests/04_exception_irq_sanity.rs b/13_exceptions_part2_peripheral_IRQs/kernel/tests/04_exception_irq_sanity.rs similarity index 100% rename from 13_exceptions_part2_peripheral_IRQs/tests/04_exception_irq_sanity.rs rename to 13_exceptions_part2_peripheral_IRQs/kernel/tests/04_exception_irq_sanity.rs diff --git a/13_exceptions_part2_peripheral_IRQs/tests/boot_test_string.rb b/13_exceptions_part2_peripheral_IRQs/kernel/tests/boot_test_string.rb similarity index 100% rename from 13_exceptions_part2_peripheral_IRQs/tests/boot_test_string.rb rename to 13_exceptions_part2_peripheral_IRQs/kernel/tests/boot_test_string.rb diff --git a/13_exceptions_part2_peripheral_IRQs/tests/panic_exit_success/mod.rs b/13_exceptions_part2_peripheral_IRQs/kernel/tests/panic_exit_success/mod.rs similarity index 100% rename from 13_exceptions_part2_peripheral_IRQs/tests/panic_exit_success/mod.rs rename to 13_exceptions_part2_peripheral_IRQs/kernel/tests/panic_exit_success/mod.rs diff --git a/13_exceptions_part2_peripheral_IRQs/tests/panic_wait_forever/mod.rs b/13_exceptions_part2_peripheral_IRQs/kernel/tests/panic_wait_forever/mod.rs similarity index 100% rename from 13_exceptions_part2_peripheral_IRQs/tests/panic_wait_forever/mod.rs rename to 13_exceptions_part2_peripheral_IRQs/kernel/tests/panic_wait_forever/mod.rs diff --git a/13_exceptions_part2_peripheral_IRQs/test-macros/Cargo.toml b/13_exceptions_part2_peripheral_IRQs/libraries/test-macros/Cargo.toml similarity index 100% rename from 13_exceptions_part2_peripheral_IRQs/test-macros/Cargo.toml rename to 13_exceptions_part2_peripheral_IRQs/libraries/test-macros/Cargo.toml diff --git a/13_exceptions_part2_peripheral_IRQs/test-macros/src/lib.rs b/13_exceptions_part2_peripheral_IRQs/libraries/test-macros/src/lib.rs similarity index 100% rename from 13_exceptions_part2_peripheral_IRQs/test-macros/src/lib.rs rename to 13_exceptions_part2_peripheral_IRQs/libraries/test-macros/src/lib.rs diff --git a/13_exceptions_part2_peripheral_IRQs/test-types/Cargo.toml b/13_exceptions_part2_peripheral_IRQs/libraries/test-types/Cargo.toml similarity index 100% rename from 13_exceptions_part2_peripheral_IRQs/test-types/Cargo.toml rename to 13_exceptions_part2_peripheral_IRQs/libraries/test-types/Cargo.toml diff --git a/13_exceptions_part2_peripheral_IRQs/test-types/src/lib.rs b/13_exceptions_part2_peripheral_IRQs/libraries/test-types/src/lib.rs similarity index 100% rename from 13_exceptions_part2_peripheral_IRQs/test-types/src/lib.rs rename to 13_exceptions_part2_peripheral_IRQs/libraries/test-types/src/lib.rs diff --git a/14_virtual_mem_part2_mmio_remap/Cargo.lock b/14_virtual_mem_part2_mmio_remap/Cargo.lock index 6526767a..337a9ed8 100644 --- a/14_virtual_mem_part2_mmio_remap/Cargo.lock +++ b/14_virtual_mem_part2_mmio_remap/Cargo.lock @@ -39,9 +39,9 @@ checksum = "9ff023245bfcc73fb890e1f8d5383825b3131cc920020a5c487d6f113dfc428a" [[package]] name = "quote" -version = "1.0.17" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "632d02bff7f874a36f33ea8bb416cd484b90cc66c1194b1a1110d067a7013f58" +checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1" dependencies = [ "proc-macro2", ] diff --git a/14_virtual_mem_part2_mmio_remap/Cargo.toml b/14_virtual_mem_part2_mmio_remap/Cargo.toml index 3146ad05..6480a727 100644 --- a/14_virtual_mem_part2_mmio_remap/Cargo.toml +++ b/14_virtual_mem_part2_mmio_remap/Cargo.toml @@ -1,60 +1,9 @@ -[package] -name = "mingo" -version = "0.14.0" -authors = ["Andre Richter "] -edition = "2021" +[workspace] + +members = [ + "libraries/*", + "kernel" +] [profile.release] lto = true - -[features] -default = [] -bsp_rpi3 = ["tock-registers"] -bsp_rpi4 = ["tock-registers"] -test_build = ["qemu-exit"] - -##-------------------------------------------------------------------------------------------------- -## Dependencies -##-------------------------------------------------------------------------------------------------- - -[dependencies] -test-types = { path = "test-types" } - -# Optional dependencies -tock-registers = { version = "0.7.x", default-features = false, features = ["register_types"], optional = true } -qemu-exit = { version = "3.x.x", optional = true } - -# Platform specific dependencies -[target.'cfg(target_arch = "aarch64")'.dependencies] -cortex-a = { version = "7.x.x" } - -##-------------------------------------------------------------------------------------------------- -## Testing -##-------------------------------------------------------------------------------------------------- - -[dev-dependencies] -test-macros = { path = "test-macros" } - -# Unit tests are done in the library part of the kernel. -[lib] -name = "libkernel" -test = true - -# Disable unit tests for the kernel binary. -[[bin]] -name = "kernel" -path = "src/main.rs" -test = false - -# List of tests without harness. -[[test]] -name = "00_console_sanity" -harness = false - -[[test]] -name = "02_exception_sync_page_fault" -harness = false - -[[test]] -name = "03_exception_restore_sanity" -harness = false diff --git a/14_virtual_mem_part2_mmio_remap/Makefile b/14_virtual_mem_part2_mmio_remap/Makefile index 6adb1aca..427c9303 100644 --- a/14_virtual_mem_part2_mmio_remap/Makefile +++ b/14_virtual_mem_part2_mmio_remap/Makefile @@ -41,7 +41,7 @@ ifeq ($(BSP),rpi3) READELF_BINARY = aarch64-none-elf-readelf OPENOCD_ARG = -f /openocd/tcl/interface/ftdi/olimex-arm-usb-tiny-h.cfg -f /openocd/rpi3.cfg JTAG_BOOT_IMAGE = ../X1_JTAG_boot/jtag_boot_rpi3.img - LD_SCRIPT_PATH = $(shell pwd)/src/bsp/raspberrypi + LD_SCRIPT_PATH = $(shell pwd)/kernel/src/bsp/raspberrypi RUSTC_MISC_ARGS = -C target-cpu=cortex-a53 else ifeq ($(BSP),rpi4) TARGET = aarch64-unknown-none-softfloat @@ -55,7 +55,7 @@ else ifeq ($(BSP),rpi4) READELF_BINARY = aarch64-none-elf-readelf OPENOCD_ARG = -f /openocd/tcl/interface/ftdi/olimex-arm-usb-tiny-h.cfg -f /openocd/rpi4.cfg JTAG_BOOT_IMAGE = ../X1_JTAG_boot/jtag_boot_rpi4.img - LD_SCRIPT_PATH = $(shell pwd)/src/bsp/raspberrypi + LD_SCRIPT_PATH = $(shell pwd)/kernel/src/bsp/raspberrypi RUSTC_MISC_ARGS = -C target-cpu=cortex-a72 endif @@ -67,9 +67,9 @@ export LD_SCRIPT_PATH ##-------------------------------------------------------------------------------------------------- ## Targets and Prerequisites ##-------------------------------------------------------------------------------------------------- +KERNEL_MANIFEST = kernel/Cargo.toml KERNEL_LINKER_SCRIPT = kernel.ld - -LAST_BUILD_CONFIG = target/$(BSP).build_config +LAST_BUILD_CONFIG = target/$(BSP).build_config KERNEL_ELF = target/$(TARGET)/release/kernel # This parses cargo's dep-info file. @@ -94,11 +94,11 @@ COMPILER_ARGS = --target=$(TARGET) \ $(FEATURES) \ --release -RUSTC_CMD = cargo rustc $(COMPILER_ARGS) +RUSTC_CMD = cargo rustc $(COMPILER_ARGS) --manifest-path $(KERNEL_MANIFEST) DOC_CMD = cargo doc $(COMPILER_ARGS) CLIPPY_CMD = cargo clippy $(COMPILER_ARGS) CHECK_CMD = cargo check $(COMPILER_ARGS) -TEST_CMD = cargo test $(COMPILER_ARGS) +TEST_CMD = cargo test $(COMPILER_ARGS) --manifest-path $(KERNEL_MANIFEST) OBJCOPY_CMD = rust-objcopy \ --strip-all \ -O binary @@ -203,6 +203,8 @@ chainboot: $(KERNEL_BIN) ##------------------------------------------------------------------------------ clippy: @RUSTFLAGS="$(RUSTFLAGS_PEDANTIC)" $(CLIPPY_CMD) + @RUSTFLAGS="$(RUSTFLAGS_PEDANTIC)" $(CLIPPY_CMD) --features test_build --tests \ + --manifest-path $(KERNEL_MANIFEST) ##------------------------------------------------------------------------------ ## Clean @@ -299,6 +301,10 @@ test_boot: $(KERNEL_BIN) define KERNEL_TEST_RUNNER #!/usr/bin/env bash + # The cargo test runner seems to change into the crate under test's directory. Therefore, ensure + # this script executes from the root. + cd $(shell pwd) + TEST_ELF=$$(echo $$1 | sed -e 's/.*target/target/g') TEST_BINARY=$$(echo $$1.img | sed -e 's/.*target/target/g') diff --git a/14_virtual_mem_part2_mmio_remap/README.md b/14_virtual_mem_part2_mmio_remap/README.md index 0056174b..e19cedb7 100644 --- a/14_virtual_mem_part2_mmio_remap/README.md +++ b/14_virtual_mem_part2_mmio_remap/README.md @@ -298,8 +298,8 @@ pub unsafe fn kernel_map_mmio( This allocator is defined and implemented in the added file `src/memory/mmu/alloc.rs`. Like other parts of the mapping code, its implementation makes use of the newly introduced `PageAddress` -and `MemoryRegion` types (in [`src/memory/mmu/types.rs`](src/memory/mmu/types.rs)), but apart -from that is rather straight forward. Therefore, it won't be covered in details here. +and `MemoryRegion` types (in [`src/memory/mmu/types.rs`](kernel/src/memory/mmu/types.rs)), +but apart from that is rather straight forward. Therefore, it won't be covered in details here. The more interesting question is: How does the allocator get to learn which VAs it can use? @@ -341,13 +341,14 @@ the VA range. There's a couple of changes not covered in this tutorial text, but the reader should ideally skim through them: -- [`src/memory.rs`](src/memory.rs) and [`src/memory/mmu/types.rs`](src/memory/mmu/types.rs) - introduce a couple of supporting types, like`Address`, `PageAddress` and - `MemoryRegion`. It is worth reading their implementations. -- [`src/memory/mmu/mapping_record.rs`](src/memory/mmu/mapping_record.rs) provides the generic kernel - code's way of tracking previous memory mappings for use cases such as reusing existing mappings - (in case of drivers that have their MMIO ranges in the same `64 KiB` page) or printing mappings - statistics. +- [`src/memory.rs`](kernel/src/memory.rs) and + [`src/memory/mmu/types.rs`](kernel/src/memory/mmu/types.rs) introduce a couple of supporting + types, like`Address`, `PageAddress` and `MemoryRegion`. It is worth reading + their implementations. +- [`src/memory/mmu/mapping_record.rs`](kernel/src/memory/mmu/mapping_record.rs) provides the generic + kernel code's way of tracking previous memory mappings for use cases such as reusing existing + mappings (in case of drivers that have their MMIO ranges in the same `64 KiB` page) or printing + mappings statistics. ## Test it @@ -433,9 +434,9 @@ Minipush 1.0 ## Diff to previous ```diff -diff -uNr 13_exceptions_part2_peripheral_IRQs/Cargo.toml 14_virtual_mem_part2_mmio_remap/Cargo.toml ---- 13_exceptions_part2_peripheral_IRQs/Cargo.toml -+++ 14_virtual_mem_part2_mmio_remap/Cargo.toml +diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/Cargo.toml 14_virtual_mem_part2_mmio_remap/kernel/Cargo.toml +--- 13_exceptions_part2_peripheral_IRQs/kernel/Cargo.toml ++++ 14_virtual_mem_part2_mmio_remap/kernel/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mingo" @@ -445,9 +446,9 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/Cargo.toml 14_virtual_mem_part2_mm edition = "2021" -diff -uNr 13_exceptions_part2_peripheral_IRQs/src/_arch/aarch64/memory/mmu/translation_table.rs 14_virtual_mem_part2_mmio_remap/src/_arch/aarch64/memory/mmu/translation_table.rs ---- 13_exceptions_part2_peripheral_IRQs/src/_arch/aarch64/memory/mmu/translation_table.rs -+++ 14_virtual_mem_part2_mmio_remap/src/_arch/aarch64/memory/mmu/translation_table.rs +diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/memory/mmu/translation_table.rs 14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/memory/mmu/translation_table.rs +--- 13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/memory/mmu/translation_table.rs ++++ 14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/memory/mmu/translation_table.rs @@ -14,10 +14,14 @@ //! crate::memory::mmu::translation_table::arch_translation_table @@ -705,9 +706,9 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/src/_arch/aarch64/memory/mmu/trans use super::*; use test_macros::kernel_test; -diff -uNr 13_exceptions_part2_peripheral_IRQs/src/_arch/aarch64/memory/mmu.rs 14_virtual_mem_part2_mmio_remap/src/_arch/aarch64/memory/mmu.rs ---- 13_exceptions_part2_peripheral_IRQs/src/_arch/aarch64/memory/mmu.rs -+++ 14_virtual_mem_part2_mmio_remap/src/_arch/aarch64/memory/mmu.rs +diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/memory/mmu.rs 14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/memory/mmu.rs +--- 13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/memory/mmu.rs ++++ 14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/memory/mmu.rs @@ -15,7 +15,7 @@ use crate::{ @@ -802,9 +803,9 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/src/_arch/aarch64/memory/mmu.rs 14 - } -} -diff -uNr 13_exceptions_part2_peripheral_IRQs/src/bsp/device_driver/arm/gicv2/gicc.rs 14_virtual_mem_part2_mmio_remap/src/bsp/device_driver/arm/gicv2/gicc.rs ---- 13_exceptions_part2_peripheral_IRQs/src/bsp/device_driver/arm/gicv2/gicc.rs -+++ 14_virtual_mem_part2_mmio_remap/src/bsp/device_driver/arm/gicv2/gicc.rs +diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/arm/gicv2/gicc.rs 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/arm/gicv2/gicc.rs +--- 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/arm/gicv2/gicc.rs ++++ 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/arm/gicv2/gicc.rs @@ -4,7 +4,9 @@ //! GICC Driver - GIC CPU interface. @@ -891,9 +892,9 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/src/bsp/device_driver/arm/gicv2/gi } } -diff -uNr 13_exceptions_part2_peripheral_IRQs/src/bsp/device_driver/arm/gicv2/gicd.rs 14_virtual_mem_part2_mmio_remap/src/bsp/device_driver/arm/gicv2/gicd.rs ---- 13_exceptions_part2_peripheral_IRQs/src/bsp/device_driver/arm/gicv2/gicd.rs -+++ 14_virtual_mem_part2_mmio_remap/src/bsp/device_driver/arm/gicv2/gicd.rs +diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs +--- 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs ++++ 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs @@ -8,8 +8,9 @@ //! - SPI - Shared Peripheral Interrupt. @@ -967,9 +968,9 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/src/bsp/device_driver/arm/gicv2/gi _ => { let enable_reg_index_shared = enable_reg_index - 1; -diff -uNr 13_exceptions_part2_peripheral_IRQs/src/bsp/device_driver/arm/gicv2.rs 14_virtual_mem_part2_mmio_remap/src/bsp/device_driver/arm/gicv2.rs ---- 13_exceptions_part2_peripheral_IRQs/src/bsp/device_driver/arm/gicv2.rs -+++ 14_virtual_mem_part2_mmio_remap/src/bsp/device_driver/arm/gicv2.rs +diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/arm/gicv2.rs 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/arm/gicv2.rs +--- 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/arm/gicv2.rs ++++ 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/arm/gicv2.rs @@ -79,7 +79,8 @@ mod gicc; mod gicd; @@ -1043,9 +1044,9 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/src/bsp/device_driver/arm/gicv2.rs self.gicd.boot_core_init(); } -diff -uNr 13_exceptions_part2_peripheral_IRQs/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs 14_virtual_mem_part2_mmio_remap/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs ---- 13_exceptions_part2_peripheral_IRQs/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs -+++ 14_virtual_mem_part2_mmio_remap/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs +diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs +--- 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs ++++ 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs @@ -5,9 +5,10 @@ //! GPIO Driver. @@ -1131,9 +1132,9 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/src/bsp/device_driver/bcm/bcm2xxx_ + } } -diff -uNr 13_exceptions_part2_peripheral_IRQs/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs 14_virtual_mem_part2_mmio_remap/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs ---- 13_exceptions_part2_peripheral_IRQs/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs -+++ 14_virtual_mem_part2_mmio_remap/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs +diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs +--- 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs ++++ 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs @@ -7,7 +7,7 @@ use super::{InterruptController, PendingIRQs, PeripheralIRQ}; use crate::{ @@ -1218,9 +1219,9 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/src/bsp/device_driver/bcm/bcm2xxx_ type IRQNumberType = PeripheralIRQ; -diff -uNr 13_exceptions_part2_peripheral_IRQs/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs 14_virtual_mem_part2_mmio_remap/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs ---- 13_exceptions_part2_peripheral_IRQs/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs -+++ 14_virtual_mem_part2_mmio_remap/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs +diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs +--- 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs ++++ 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs @@ -6,7 +6,7 @@ mod peripheral_ic; @@ -1259,9 +1260,9 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/src/bsp/device_driver/bcm/bcm2xxx_ impl exception::asynchronous::interface::IRQManager for InterruptController { -diff -uNr 13_exceptions_part2_peripheral_IRQs/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs 14_virtual_mem_part2_mmio_remap/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs ---- 13_exceptions_part2_peripheral_IRQs/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs -+++ 14_virtual_mem_part2_mmio_remap/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs +diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs +--- 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs ++++ 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs @@ -10,10 +10,13 @@ //! - @@ -1368,9 +1369,9 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/src/bsp/device_driver/bcm/bcm2xxx_ impl console::interface::Write for PL011Uart { -diff -uNr 13_exceptions_part2_peripheral_IRQs/src/bsp/raspberrypi/console.rs 14_virtual_mem_part2_mmio_remap/src/bsp/raspberrypi/console.rs ---- 13_exceptions_part2_peripheral_IRQs/src/bsp/raspberrypi/console.rs -+++ 14_virtual_mem_part2_mmio_remap/src/bsp/raspberrypi/console.rs +diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/console.rs 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/console.rs +--- 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/console.rs ++++ 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/console.rs @@ -5,7 +5,7 @@ //! BSP console facilities. @@ -1410,9 +1411,9 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/src/bsp/raspberrypi/console.rs 14_ } -diff -uNr 13_exceptions_part2_peripheral_IRQs/src/bsp/raspberrypi/driver.rs 14_virtual_mem_part2_mmio_remap/src/bsp/raspberrypi/driver.rs ---- 13_exceptions_part2_peripheral_IRQs/src/bsp/raspberrypi/driver.rs -+++ 14_virtual_mem_part2_mmio_remap/src/bsp/raspberrypi/driver.rs +diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/driver.rs 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/driver.rs +--- 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/driver.rs ++++ 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/driver.rs @@ -46,7 +46,15 @@ &self.device_drivers[..] } @@ -1431,9 +1432,9 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/src/bsp/raspberrypi/driver.rs 14_v super::GPIO.map_pl011_uart(); } -diff -uNr 13_exceptions_part2_peripheral_IRQs/src/bsp/raspberrypi/kernel.ld 14_virtual_mem_part2_mmio_remap/src/bsp/raspberrypi/kernel.ld ---- 13_exceptions_part2_peripheral_IRQs/src/bsp/raspberrypi/kernel.ld -+++ 14_virtual_mem_part2_mmio_remap/src/bsp/raspberrypi/kernel.ld +diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/kernel.ld 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/kernel.ld +--- 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/kernel.ld ++++ 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/kernel.ld @@ -38,7 +38,7 @@ ***********************************************************************************************/ .boot_core_stack (NOLOAD) : @@ -1469,9 +1470,9 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/src/bsp/raspberrypi/kernel.ld 14_v + ASSERT((. & PAGE_MASK) == 0, "MMIO remap reservation is not page aligned") } -diff -uNr 13_exceptions_part2_peripheral_IRQs/src/bsp/raspberrypi/memory/mmu.rs 14_virtual_mem_part2_mmio_remap/src/bsp/raspberrypi/memory/mmu.rs ---- 13_exceptions_part2_peripheral_IRQs/src/bsp/raspberrypi/memory/mmu.rs -+++ 14_virtual_mem_part2_mmio_remap/src/bsp/raspberrypi/memory/mmu.rs +diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/memory/mmu.rs 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/memory/mmu.rs +--- 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/memory/mmu.rs ++++ 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/memory/mmu.rs @@ -4,70 +4,163 @@ //! BSP Memory Management Unit. @@ -1761,9 +1762,9 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/src/bsp/raspberrypi/memory/mmu.rs + } } -diff -uNr 13_exceptions_part2_peripheral_IRQs/src/bsp/raspberrypi/memory.rs 14_virtual_mem_part2_mmio_remap/src/bsp/raspberrypi/memory.rs ---- 13_exceptions_part2_peripheral_IRQs/src/bsp/raspberrypi/memory.rs -+++ 14_virtual_mem_part2_mmio_remap/src/bsp/raspberrypi/memory.rs +diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/memory.rs 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/memory.rs +--- 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/memory.rs ++++ 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/memory.rs @@ -10,27 +10,59 @@ //! as the boot core's stack. //! @@ -2005,9 +2006,9 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/src/bsp/raspberrypi/memory.rs 14_v + PageAddress::from(map::END) } -diff -uNr 13_exceptions_part2_peripheral_IRQs/src/bsp/raspberrypi.rs 14_virtual_mem_part2_mmio_remap/src/bsp/raspberrypi.rs ---- 13_exceptions_part2_peripheral_IRQs/src/bsp/raspberrypi.rs -+++ 14_virtual_mem_part2_mmio_remap/src/bsp/raspberrypi.rs +diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi.rs 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi.rs +--- 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi.rs ++++ 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi.rs @@ -10,17 +10,20 @@ pub mod exception; pub mod memory; @@ -2054,9 +2055,9 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/src/bsp/raspberrypi.rs 14_virtual_ //-------------------------------------------------------------------------------------------------- -diff -uNr 13_exceptions_part2_peripheral_IRQs/src/common.rs 14_virtual_mem_part2_mmio_remap/src/common.rs ---- 13_exceptions_part2_peripheral_IRQs/src/common.rs -+++ 14_virtual_mem_part2_mmio_remap/src/common.rs +diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/common.rs 14_virtual_mem_part2_mmio_remap/kernel/src/common.rs +--- 13_exceptions_part2_peripheral_IRQs/kernel/src/common.rs ++++ 14_virtual_mem_part2_mmio_remap/kernel/src/common.rs @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// @@ -2088,9 +2089,9 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/src/common.rs 14_virtual_mem_part2 + (value + alignment - 1) & !(alignment - 1) +} -diff -uNr 13_exceptions_part2_peripheral_IRQs/src/driver.rs 14_virtual_mem_part2_mmio_remap/src/driver.rs ---- 13_exceptions_part2_peripheral_IRQs/src/driver.rs -+++ 14_virtual_mem_part2_mmio_remap/src/driver.rs +diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/driver.rs 14_virtual_mem_part2_mmio_remap/kernel/src/driver.rs +--- 13_exceptions_part2_peripheral_IRQs/kernel/src/driver.rs ++++ 14_virtual_mem_part2_mmio_remap/kernel/src/driver.rs @@ -31,6 +31,14 @@ fn register_and_enable_irq_handler(&'static self) -> Result<(), &'static str> { Ok(()) @@ -2132,9 +2133,9 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/src/driver.rs 14_virtual_mem_part2 } } -diff -uNr 13_exceptions_part2_peripheral_IRQs/src/lib.rs 14_virtual_mem_part2_mmio_remap/src/lib.rs ---- 13_exceptions_part2_peripheral_IRQs/src/lib.rs -+++ 14_virtual_mem_part2_mmio_remap/src/lib.rs +diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/lib.rs 14_virtual_mem_part2_mmio_remap/kernel/src/lib.rs +--- 13_exceptions_part2_peripheral_IRQs/kernel/src/lib.rs ++++ 14_virtual_mem_part2_mmio_remap/kernel/src/lib.rs @@ -111,8 +111,10 @@ #![feature(asm_const)] #![feature(core_intrinsics)] @@ -2163,9 +2164,9 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/src/lib.rs 14_virtual_mem_part2_mm test_main(); -diff -uNr 13_exceptions_part2_peripheral_IRQs/src/main.rs 14_virtual_mem_part2_mmio_remap/src/main.rs ---- 13_exceptions_part2_peripheral_IRQs/src/main.rs -+++ 14_virtual_mem_part2_mmio_remap/src/main.rs +diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/main.rs 14_virtual_mem_part2_mmio_remap/kernel/src/main.rs +--- 13_exceptions_part2_peripheral_IRQs/kernel/src/main.rs ++++ 14_virtual_mem_part2_mmio_remap/kernel/src/main.rs @@ -25,21 +25,41 @@ #[no_mangle] unsafe fn kernel_init() -> ! { @@ -2226,9 +2227,9 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/src/main.rs 14_virtual_mem_part2_m let (_, privilege_level) = exception::current_privilege_level(); info!("Current privilege level: {}", privilege_level); -diff -uNr 13_exceptions_part2_peripheral_IRQs/src/memory/mmu/alloc.rs 14_virtual_mem_part2_mmio_remap/src/memory/mmu/alloc.rs ---- 13_exceptions_part2_peripheral_IRQs/src/memory/mmu/alloc.rs -+++ 14_virtual_mem_part2_mmio_remap/src/memory/mmu/alloc.rs +diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/memory/mmu/alloc.rs 14_virtual_mem_part2_mmio_remap/kernel/src/memory/mmu/alloc.rs +--- 13_exceptions_part2_peripheral_IRQs/kernel/src/memory/mmu/alloc.rs ++++ 14_virtual_mem_part2_mmio_remap/kernel/src/memory/mmu/alloc.rs @@ -0,0 +1,70 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// @@ -2301,9 +2302,9 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/src/memory/mmu/alloc.rs 14_virtual + } +} -diff -uNr 13_exceptions_part2_peripheral_IRQs/src/memory/mmu/mapping_record.rs 14_virtual_mem_part2_mmio_remap/src/memory/mmu/mapping_record.rs ---- 13_exceptions_part2_peripheral_IRQs/src/memory/mmu/mapping_record.rs -+++ 14_virtual_mem_part2_mmio_remap/src/memory/mmu/mapping_record.rs +diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/memory/mmu/mapping_record.rs 14_virtual_mem_part2_mmio_remap/kernel/src/memory/mmu/mapping_record.rs +--- 13_exceptions_part2_peripheral_IRQs/kernel/src/memory/mmu/mapping_record.rs ++++ 14_virtual_mem_part2_mmio_remap/kernel/src/memory/mmu/mapping_record.rs @@ -0,0 +1,233 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// @@ -2539,9 +2540,9 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/src/memory/mmu/mapping_record.rs 1 + KERNEL_MAPPING_RECORD.read(|mr| mr.print()); +} -diff -uNr 13_exceptions_part2_peripheral_IRQs/src/memory/mmu/translation_table.rs 14_virtual_mem_part2_mmio_remap/src/memory/mmu/translation_table.rs ---- 13_exceptions_part2_peripheral_IRQs/src/memory/mmu/translation_table.rs -+++ 14_virtual_mem_part2_mmio_remap/src/memory/mmu/translation_table.rs +diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/memory/mmu/translation_table.rs 14_virtual_mem_part2_mmio_remap/kernel/src/memory/mmu/translation_table.rs +--- 13_exceptions_part2_peripheral_IRQs/kernel/src/memory/mmu/translation_table.rs ++++ 14_virtual_mem_part2_mmio_remap/kernel/src/memory/mmu/translation_table.rs @@ -8,7 +8,91 @@ #[path = "../../_arch/aarch64/memory/mmu/translation_table.rs"] mod arch_translation_table; @@ -2636,9 +2637,9 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/src/memory/mmu/translation_table.r + } +} -diff -uNr 13_exceptions_part2_peripheral_IRQs/src/memory/mmu/types.rs 14_virtual_mem_part2_mmio_remap/src/memory/mmu/types.rs ---- 13_exceptions_part2_peripheral_IRQs/src/memory/mmu/types.rs -+++ 14_virtual_mem_part2_mmio_remap/src/memory/mmu/types.rs +diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/memory/mmu/types.rs 14_virtual_mem_part2_mmio_remap/kernel/src/memory/mmu/types.rs +--- 13_exceptions_part2_peripheral_IRQs/kernel/src/memory/mmu/types.rs ++++ 14_virtual_mem_part2_mmio_remap/kernel/src/memory/mmu/types.rs @@ -0,0 +1,373 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// @@ -3014,9 +3015,9 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/src/memory/mmu/types.rs 14_virtual + } +} -diff -uNr 13_exceptions_part2_peripheral_IRQs/src/memory/mmu.rs 14_virtual_mem_part2_mmio_remap/src/memory/mmu.rs ---- 13_exceptions_part2_peripheral_IRQs/src/memory/mmu.rs -+++ 14_virtual_mem_part2_mmio_remap/src/memory/mmu.rs +diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/memory/mmu.rs 14_virtual_mem_part2_mmio_remap/kernel/src/memory/mmu.rs +--- 13_exceptions_part2_peripheral_IRQs/kernel/src/memory/mmu.rs ++++ 14_virtual_mem_part2_mmio_remap/kernel/src/memory/mmu.rs @@ -3,29 +3,24 @@ // Copyright (c) 2020-2022 Andre Richter @@ -3424,9 +3425,9 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/src/memory/mmu.rs 14_virtual_mem_p } } -diff -uNr 13_exceptions_part2_peripheral_IRQs/src/memory.rs 14_virtual_mem_part2_mmio_remap/src/memory.rs ---- 13_exceptions_part2_peripheral_IRQs/src/memory.rs -+++ 14_virtual_mem_part2_mmio_remap/src/memory.rs +diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/memory.rs 14_virtual_mem_part2_mmio_remap/kernel/src/memory.rs +--- 13_exceptions_part2_peripheral_IRQs/kernel/src/memory.rs ++++ 14_virtual_mem_part2_mmio_remap/kernel/src/memory.rs @@ -5,3 +5,163 @@ //! Memory Management. @@ -3592,9 +3593,9 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/src/memory.rs 14_virtual_mem_part2 + } +} -diff -uNr 13_exceptions_part2_peripheral_IRQs/tests/02_exception_sync_page_fault.rs 14_virtual_mem_part2_mmio_remap/tests/02_exception_sync_page_fault.rs ---- 13_exceptions_part2_peripheral_IRQs/tests/02_exception_sync_page_fault.rs -+++ 14_virtual_mem_part2_mmio_remap/tests/02_exception_sync_page_fault.rs +diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/tests/02_exception_sync_page_fault.rs 14_virtual_mem_part2_mmio_remap/kernel/tests/02_exception_sync_page_fault.rs +--- 13_exceptions_part2_peripheral_IRQs/kernel/tests/02_exception_sync_page_fault.rs ++++ 14_virtual_mem_part2_mmio_remap/kernel/tests/02_exception_sync_page_fault.rs @@ -21,18 +21,40 @@ #[no_mangle] @@ -3641,9 +3642,9 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/tests/02_exception_sync_page_fault info!("Writing beyond mapped area to address 9 GiB..."); let big_addr: u64 = 9 * 1024 * 1024 * 1024; -diff -uNr 13_exceptions_part2_peripheral_IRQs/tests/03_exception_restore_sanity.rs 14_virtual_mem_part2_mmio_remap/tests/03_exception_restore_sanity.rs ---- 13_exceptions_part2_peripheral_IRQs/tests/03_exception_restore_sanity.rs -+++ 14_virtual_mem_part2_mmio_remap/tests/03_exception_restore_sanity.rs +diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/tests/03_exception_restore_sanity.rs 14_virtual_mem_part2_mmio_remap/kernel/tests/03_exception_restore_sanity.rs +--- 13_exceptions_part2_peripheral_IRQs/kernel/tests/03_exception_restore_sanity.rs ++++ 14_virtual_mem_part2_mmio_remap/kernel/tests/03_exception_restore_sanity.rs @@ -30,18 +30,40 @@ #[no_mangle] diff --git a/14_virtual_mem_part2_mmio_remap/kernel/Cargo.toml b/14_virtual_mem_part2_mmio_remap/kernel/Cargo.toml new file mode 100644 index 00000000..deb0c8bc --- /dev/null +++ b/14_virtual_mem_part2_mmio_remap/kernel/Cargo.toml @@ -0,0 +1,58 @@ +[package] +name = "mingo" +version = "0.14.0" +authors = ["Andre Richter "] +edition = "2021" + + +[features] +default = [] +bsp_rpi3 = ["tock-registers"] +bsp_rpi4 = ["tock-registers"] +test_build = ["qemu-exit"] + +##-------------------------------------------------------------------------------------------------- +## Dependencies +##-------------------------------------------------------------------------------------------------- + +[dependencies] +test-types = { path = "../libraries/test-types" } + +# Optional dependencies +tock-registers = { version = "0.7.x", default-features = false, features = ["register_types"], optional = true } +qemu-exit = { version = "3.x.x", optional = true } + +# Platform specific dependencies +[target.'cfg(target_arch = "aarch64")'.dependencies] +cortex-a = { version = "7.x.x" } + +##-------------------------------------------------------------------------------------------------- +## Testing +##-------------------------------------------------------------------------------------------------- + +[dev-dependencies] +test-macros = { path = "../libraries/test-macros" } + +# Unit tests are done in the library part of the kernel. +[lib] +name = "libkernel" +test = true + +# Disable unit tests for the kernel binary. +[[bin]] +name = "kernel" +path = "src/main.rs" +test = false + +# List of tests without harness. +[[test]] +name = "00_console_sanity" +harness = false + +[[test]] +name = "02_exception_sync_page_fault" +harness = false + +[[test]] +name = "03_exception_restore_sanity" +harness = false diff --git a/14_virtual_mem_part2_mmio_remap/build.rs b/14_virtual_mem_part2_mmio_remap/kernel/build.rs similarity index 100% rename from 14_virtual_mem_part2_mmio_remap/build.rs rename to 14_virtual_mem_part2_mmio_remap/kernel/build.rs diff --git a/14_virtual_mem_part2_mmio_remap/src/_arch/aarch64/cpu.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/cpu.rs similarity index 100% rename from 14_virtual_mem_part2_mmio_remap/src/_arch/aarch64/cpu.rs rename to 14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/cpu.rs diff --git a/14_virtual_mem_part2_mmio_remap/src/_arch/aarch64/cpu/boot.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/cpu/boot.rs similarity index 100% rename from 14_virtual_mem_part2_mmio_remap/src/_arch/aarch64/cpu/boot.rs rename to 14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/cpu/boot.rs diff --git a/14_virtual_mem_part2_mmio_remap/src/_arch/aarch64/cpu/boot.s b/14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/cpu/boot.s similarity index 100% rename from 14_virtual_mem_part2_mmio_remap/src/_arch/aarch64/cpu/boot.s rename to 14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/cpu/boot.s diff --git a/14_virtual_mem_part2_mmio_remap/src/_arch/aarch64/cpu/smp.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/cpu/smp.rs similarity index 100% rename from 14_virtual_mem_part2_mmio_remap/src/_arch/aarch64/cpu/smp.rs rename to 14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/cpu/smp.rs diff --git a/14_virtual_mem_part2_mmio_remap/src/_arch/aarch64/exception.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/exception.rs similarity index 100% rename from 14_virtual_mem_part2_mmio_remap/src/_arch/aarch64/exception.rs rename to 14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/exception.rs diff --git a/14_virtual_mem_part2_mmio_remap/src/_arch/aarch64/exception.s b/14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/exception.s similarity index 100% rename from 14_virtual_mem_part2_mmio_remap/src/_arch/aarch64/exception.s rename to 14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/exception.s diff --git a/14_virtual_mem_part2_mmio_remap/src/_arch/aarch64/exception/asynchronous.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/exception/asynchronous.rs similarity index 100% rename from 14_virtual_mem_part2_mmio_remap/src/_arch/aarch64/exception/asynchronous.rs rename to 14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/exception/asynchronous.rs diff --git a/14_virtual_mem_part2_mmio_remap/src/_arch/aarch64/memory/mmu.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/memory/mmu.rs similarity index 100% rename from 14_virtual_mem_part2_mmio_remap/src/_arch/aarch64/memory/mmu.rs rename to 14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/memory/mmu.rs diff --git a/14_virtual_mem_part2_mmio_remap/src/_arch/aarch64/memory/mmu/translation_table.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/memory/mmu/translation_table.rs similarity index 100% rename from 14_virtual_mem_part2_mmio_remap/src/_arch/aarch64/memory/mmu/translation_table.rs rename to 14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/memory/mmu/translation_table.rs diff --git a/14_virtual_mem_part2_mmio_remap/src/_arch/aarch64/time.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/time.rs similarity index 100% rename from 14_virtual_mem_part2_mmio_remap/src/_arch/aarch64/time.rs rename to 14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/time.rs diff --git a/14_virtual_mem_part2_mmio_remap/src/bsp.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp.rs similarity index 100% rename from 14_virtual_mem_part2_mmio_remap/src/bsp.rs rename to 14_virtual_mem_part2_mmio_remap/kernel/src/bsp.rs diff --git a/14_virtual_mem_part2_mmio_remap/src/bsp/device_driver.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver.rs similarity index 100% rename from 14_virtual_mem_part2_mmio_remap/src/bsp/device_driver.rs rename to 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver.rs diff --git a/14_virtual_mem_part2_mmio_remap/src/bsp/device_driver/arm.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/arm.rs similarity index 100% rename from 14_virtual_mem_part2_mmio_remap/src/bsp/device_driver/arm.rs rename to 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/arm.rs diff --git a/14_virtual_mem_part2_mmio_remap/src/bsp/device_driver/arm/gicv2.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/arm/gicv2.rs similarity index 100% rename from 14_virtual_mem_part2_mmio_remap/src/bsp/device_driver/arm/gicv2.rs rename to 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/arm/gicv2.rs diff --git a/14_virtual_mem_part2_mmio_remap/src/bsp/device_driver/arm/gicv2/gicc.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/arm/gicv2/gicc.rs similarity index 100% rename from 14_virtual_mem_part2_mmio_remap/src/bsp/device_driver/arm/gicv2/gicc.rs rename to 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/arm/gicv2/gicc.rs diff --git a/14_virtual_mem_part2_mmio_remap/src/bsp/device_driver/arm/gicv2/gicd.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs similarity index 100% rename from 14_virtual_mem_part2_mmio_remap/src/bsp/device_driver/arm/gicv2/gicd.rs rename to 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs diff --git a/14_virtual_mem_part2_mmio_remap/src/bsp/device_driver/bcm.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm.rs similarity index 100% rename from 14_virtual_mem_part2_mmio_remap/src/bsp/device_driver/bcm.rs rename to 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm.rs diff --git a/14_virtual_mem_part2_mmio_remap/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs similarity index 100% rename from 14_virtual_mem_part2_mmio_remap/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs rename to 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs diff --git a/14_virtual_mem_part2_mmio_remap/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs similarity index 100% rename from 14_virtual_mem_part2_mmio_remap/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs rename to 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs diff --git a/14_virtual_mem_part2_mmio_remap/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs similarity index 100% rename from 14_virtual_mem_part2_mmio_remap/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs rename to 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs diff --git a/14_virtual_mem_part2_mmio_remap/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs similarity index 100% rename from 14_virtual_mem_part2_mmio_remap/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs rename to 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs diff --git a/14_virtual_mem_part2_mmio_remap/src/bsp/device_driver/common.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/common.rs similarity index 100% rename from 14_virtual_mem_part2_mmio_remap/src/bsp/device_driver/common.rs rename to 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/common.rs diff --git a/14_virtual_mem_part2_mmio_remap/src/bsp/raspberrypi.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi.rs similarity index 100% rename from 14_virtual_mem_part2_mmio_remap/src/bsp/raspberrypi.rs rename to 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi.rs diff --git a/14_virtual_mem_part2_mmio_remap/src/bsp/raspberrypi/console.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/console.rs similarity index 100% rename from 14_virtual_mem_part2_mmio_remap/src/bsp/raspberrypi/console.rs rename to 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/console.rs diff --git a/14_virtual_mem_part2_mmio_remap/src/bsp/raspberrypi/cpu.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/cpu.rs similarity index 100% rename from 14_virtual_mem_part2_mmio_remap/src/bsp/raspberrypi/cpu.rs rename to 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/cpu.rs diff --git a/14_virtual_mem_part2_mmio_remap/src/bsp/raspberrypi/driver.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/driver.rs similarity index 100% rename from 14_virtual_mem_part2_mmio_remap/src/bsp/raspberrypi/driver.rs rename to 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/driver.rs diff --git a/14_virtual_mem_part2_mmio_remap/src/bsp/raspberrypi/exception.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/exception.rs similarity index 100% rename from 14_virtual_mem_part2_mmio_remap/src/bsp/raspberrypi/exception.rs rename to 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/exception.rs diff --git a/14_virtual_mem_part2_mmio_remap/src/bsp/raspberrypi/exception/asynchronous.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/exception/asynchronous.rs similarity index 100% rename from 14_virtual_mem_part2_mmio_remap/src/bsp/raspberrypi/exception/asynchronous.rs rename to 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/exception/asynchronous.rs diff --git a/14_virtual_mem_part2_mmio_remap/src/bsp/raspberrypi/kernel.ld b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/kernel.ld similarity index 100% rename from 14_virtual_mem_part2_mmio_remap/src/bsp/raspberrypi/kernel.ld rename to 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/kernel.ld diff --git a/14_virtual_mem_part2_mmio_remap/src/bsp/raspberrypi/memory.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/memory.rs similarity index 100% rename from 14_virtual_mem_part2_mmio_remap/src/bsp/raspberrypi/memory.rs rename to 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/memory.rs diff --git a/14_virtual_mem_part2_mmio_remap/src/bsp/raspberrypi/memory/mmu.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/memory/mmu.rs similarity index 100% rename from 14_virtual_mem_part2_mmio_remap/src/bsp/raspberrypi/memory/mmu.rs rename to 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/memory/mmu.rs diff --git a/14_virtual_mem_part2_mmio_remap/src/common.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/common.rs similarity index 100% rename from 14_virtual_mem_part2_mmio_remap/src/common.rs rename to 14_virtual_mem_part2_mmio_remap/kernel/src/common.rs diff --git a/14_virtual_mem_part2_mmio_remap/src/console.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/console.rs similarity index 100% rename from 14_virtual_mem_part2_mmio_remap/src/console.rs rename to 14_virtual_mem_part2_mmio_remap/kernel/src/console.rs diff --git a/14_virtual_mem_part2_mmio_remap/src/cpu.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/cpu.rs similarity index 100% rename from 14_virtual_mem_part2_mmio_remap/src/cpu.rs rename to 14_virtual_mem_part2_mmio_remap/kernel/src/cpu.rs diff --git a/14_virtual_mem_part2_mmio_remap/src/cpu/boot.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/cpu/boot.rs similarity index 100% rename from 14_virtual_mem_part2_mmio_remap/src/cpu/boot.rs rename to 14_virtual_mem_part2_mmio_remap/kernel/src/cpu/boot.rs diff --git a/14_virtual_mem_part2_mmio_remap/src/cpu/smp.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/cpu/smp.rs similarity index 100% rename from 14_virtual_mem_part2_mmio_remap/src/cpu/smp.rs rename to 14_virtual_mem_part2_mmio_remap/kernel/src/cpu/smp.rs diff --git a/14_virtual_mem_part2_mmio_remap/src/driver.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/driver.rs similarity index 100% rename from 14_virtual_mem_part2_mmio_remap/src/driver.rs rename to 14_virtual_mem_part2_mmio_remap/kernel/src/driver.rs diff --git a/14_virtual_mem_part2_mmio_remap/src/exception.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/exception.rs similarity index 100% rename from 14_virtual_mem_part2_mmio_remap/src/exception.rs rename to 14_virtual_mem_part2_mmio_remap/kernel/src/exception.rs diff --git a/14_virtual_mem_part2_mmio_remap/src/exception/asynchronous.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/exception/asynchronous.rs similarity index 100% rename from 14_virtual_mem_part2_mmio_remap/src/exception/asynchronous.rs rename to 14_virtual_mem_part2_mmio_remap/kernel/src/exception/asynchronous.rs diff --git a/14_virtual_mem_part2_mmio_remap/src/lib.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/lib.rs similarity index 100% rename from 14_virtual_mem_part2_mmio_remap/src/lib.rs rename to 14_virtual_mem_part2_mmio_remap/kernel/src/lib.rs diff --git a/14_virtual_mem_part2_mmio_remap/src/main.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/main.rs similarity index 100% rename from 14_virtual_mem_part2_mmio_remap/src/main.rs rename to 14_virtual_mem_part2_mmio_remap/kernel/src/main.rs diff --git a/14_virtual_mem_part2_mmio_remap/src/memory.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/memory.rs similarity index 100% rename from 14_virtual_mem_part2_mmio_remap/src/memory.rs rename to 14_virtual_mem_part2_mmio_remap/kernel/src/memory.rs diff --git a/14_virtual_mem_part2_mmio_remap/src/memory/mmu.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/memory/mmu.rs similarity index 100% rename from 14_virtual_mem_part2_mmio_remap/src/memory/mmu.rs rename to 14_virtual_mem_part2_mmio_remap/kernel/src/memory/mmu.rs diff --git a/14_virtual_mem_part2_mmio_remap/src/memory/mmu/alloc.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/memory/mmu/alloc.rs similarity index 100% rename from 14_virtual_mem_part2_mmio_remap/src/memory/mmu/alloc.rs rename to 14_virtual_mem_part2_mmio_remap/kernel/src/memory/mmu/alloc.rs diff --git a/14_virtual_mem_part2_mmio_remap/src/memory/mmu/mapping_record.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/memory/mmu/mapping_record.rs similarity index 100% rename from 14_virtual_mem_part2_mmio_remap/src/memory/mmu/mapping_record.rs rename to 14_virtual_mem_part2_mmio_remap/kernel/src/memory/mmu/mapping_record.rs diff --git a/14_virtual_mem_part2_mmio_remap/src/memory/mmu/translation_table.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/memory/mmu/translation_table.rs similarity index 100% rename from 14_virtual_mem_part2_mmio_remap/src/memory/mmu/translation_table.rs rename to 14_virtual_mem_part2_mmio_remap/kernel/src/memory/mmu/translation_table.rs diff --git a/14_virtual_mem_part2_mmio_remap/src/memory/mmu/types.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/memory/mmu/types.rs similarity index 100% rename from 14_virtual_mem_part2_mmio_remap/src/memory/mmu/types.rs rename to 14_virtual_mem_part2_mmio_remap/kernel/src/memory/mmu/types.rs diff --git a/14_virtual_mem_part2_mmio_remap/src/panic_wait.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/panic_wait.rs similarity index 100% rename from 14_virtual_mem_part2_mmio_remap/src/panic_wait.rs rename to 14_virtual_mem_part2_mmio_remap/kernel/src/panic_wait.rs diff --git a/14_virtual_mem_part2_mmio_remap/src/print.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/print.rs similarity index 100% rename from 14_virtual_mem_part2_mmio_remap/src/print.rs rename to 14_virtual_mem_part2_mmio_remap/kernel/src/print.rs diff --git a/14_virtual_mem_part2_mmio_remap/src/state.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/state.rs similarity index 100% rename from 14_virtual_mem_part2_mmio_remap/src/state.rs rename to 14_virtual_mem_part2_mmio_remap/kernel/src/state.rs diff --git a/14_virtual_mem_part2_mmio_remap/src/synchronization.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/synchronization.rs similarity index 100% rename from 14_virtual_mem_part2_mmio_remap/src/synchronization.rs rename to 14_virtual_mem_part2_mmio_remap/kernel/src/synchronization.rs diff --git a/14_virtual_mem_part2_mmio_remap/src/time.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/time.rs similarity index 100% rename from 14_virtual_mem_part2_mmio_remap/src/time.rs rename to 14_virtual_mem_part2_mmio_remap/kernel/src/time.rs diff --git a/14_virtual_mem_part2_mmio_remap/tests/00_console_sanity.rb b/14_virtual_mem_part2_mmio_remap/kernel/tests/00_console_sanity.rb similarity index 100% rename from 14_virtual_mem_part2_mmio_remap/tests/00_console_sanity.rb rename to 14_virtual_mem_part2_mmio_remap/kernel/tests/00_console_sanity.rb diff --git a/14_virtual_mem_part2_mmio_remap/tests/00_console_sanity.rs b/14_virtual_mem_part2_mmio_remap/kernel/tests/00_console_sanity.rs similarity index 100% rename from 14_virtual_mem_part2_mmio_remap/tests/00_console_sanity.rs rename to 14_virtual_mem_part2_mmio_remap/kernel/tests/00_console_sanity.rs diff --git a/14_virtual_mem_part2_mmio_remap/tests/01_timer_sanity.rs b/14_virtual_mem_part2_mmio_remap/kernel/tests/01_timer_sanity.rs similarity index 100% rename from 14_virtual_mem_part2_mmio_remap/tests/01_timer_sanity.rs rename to 14_virtual_mem_part2_mmio_remap/kernel/tests/01_timer_sanity.rs diff --git a/14_virtual_mem_part2_mmio_remap/tests/02_exception_sync_page_fault.rs b/14_virtual_mem_part2_mmio_remap/kernel/tests/02_exception_sync_page_fault.rs similarity index 100% rename from 14_virtual_mem_part2_mmio_remap/tests/02_exception_sync_page_fault.rs rename to 14_virtual_mem_part2_mmio_remap/kernel/tests/02_exception_sync_page_fault.rs diff --git a/14_virtual_mem_part2_mmio_remap/tests/03_exception_restore_sanity.rb b/14_virtual_mem_part2_mmio_remap/kernel/tests/03_exception_restore_sanity.rb similarity index 100% rename from 14_virtual_mem_part2_mmio_remap/tests/03_exception_restore_sanity.rb rename to 14_virtual_mem_part2_mmio_remap/kernel/tests/03_exception_restore_sanity.rb diff --git a/14_virtual_mem_part2_mmio_remap/tests/03_exception_restore_sanity.rs b/14_virtual_mem_part2_mmio_remap/kernel/tests/03_exception_restore_sanity.rs similarity index 100% rename from 14_virtual_mem_part2_mmio_remap/tests/03_exception_restore_sanity.rs rename to 14_virtual_mem_part2_mmio_remap/kernel/tests/03_exception_restore_sanity.rs diff --git a/14_virtual_mem_part2_mmio_remap/tests/04_exception_irq_sanity.rs b/14_virtual_mem_part2_mmio_remap/kernel/tests/04_exception_irq_sanity.rs similarity index 100% rename from 14_virtual_mem_part2_mmio_remap/tests/04_exception_irq_sanity.rs rename to 14_virtual_mem_part2_mmio_remap/kernel/tests/04_exception_irq_sanity.rs diff --git a/14_virtual_mem_part2_mmio_remap/tests/boot_test_string.rb b/14_virtual_mem_part2_mmio_remap/kernel/tests/boot_test_string.rb similarity index 100% rename from 14_virtual_mem_part2_mmio_remap/tests/boot_test_string.rb rename to 14_virtual_mem_part2_mmio_remap/kernel/tests/boot_test_string.rb diff --git a/14_virtual_mem_part2_mmio_remap/tests/panic_exit_success/mod.rs b/14_virtual_mem_part2_mmio_remap/kernel/tests/panic_exit_success/mod.rs similarity index 100% rename from 14_virtual_mem_part2_mmio_remap/tests/panic_exit_success/mod.rs rename to 14_virtual_mem_part2_mmio_remap/kernel/tests/panic_exit_success/mod.rs diff --git a/14_virtual_mem_part2_mmio_remap/tests/panic_wait_forever/mod.rs b/14_virtual_mem_part2_mmio_remap/kernel/tests/panic_wait_forever/mod.rs similarity index 100% rename from 14_virtual_mem_part2_mmio_remap/tests/panic_wait_forever/mod.rs rename to 14_virtual_mem_part2_mmio_remap/kernel/tests/panic_wait_forever/mod.rs diff --git a/14_virtual_mem_part2_mmio_remap/test-macros/Cargo.toml b/14_virtual_mem_part2_mmio_remap/libraries/test-macros/Cargo.toml similarity index 100% rename from 14_virtual_mem_part2_mmio_remap/test-macros/Cargo.toml rename to 14_virtual_mem_part2_mmio_remap/libraries/test-macros/Cargo.toml diff --git a/14_virtual_mem_part2_mmio_remap/test-macros/src/lib.rs b/14_virtual_mem_part2_mmio_remap/libraries/test-macros/src/lib.rs similarity index 100% rename from 14_virtual_mem_part2_mmio_remap/test-macros/src/lib.rs rename to 14_virtual_mem_part2_mmio_remap/libraries/test-macros/src/lib.rs diff --git a/14_virtual_mem_part2_mmio_remap/test-types/Cargo.toml b/14_virtual_mem_part2_mmio_remap/libraries/test-types/Cargo.toml similarity index 100% rename from 14_virtual_mem_part2_mmio_remap/test-types/Cargo.toml rename to 14_virtual_mem_part2_mmio_remap/libraries/test-types/Cargo.toml diff --git a/14_virtual_mem_part2_mmio_remap/test-types/src/lib.rs b/14_virtual_mem_part2_mmio_remap/libraries/test-types/src/lib.rs similarity index 100% rename from 14_virtual_mem_part2_mmio_remap/test-types/src/lib.rs rename to 14_virtual_mem_part2_mmio_remap/libraries/test-types/src/lib.rs diff --git a/15_virtual_mem_part3_precomputed_tables/Cargo.lock b/15_virtual_mem_part3_precomputed_tables/Cargo.lock index 9ce8fc76..1bac7e89 100644 --- a/15_virtual_mem_part3_precomputed_tables/Cargo.lock +++ b/15_virtual_mem_part3_precomputed_tables/Cargo.lock @@ -39,9 +39,9 @@ checksum = "9ff023245bfcc73fb890e1f8d5383825b3131cc920020a5c487d6f113dfc428a" [[package]] name = "quote" -version = "1.0.17" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "632d02bff7f874a36f33ea8bb416cd484b90cc66c1194b1a1110d067a7013f58" +checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1" dependencies = [ "proc-macro2", ] diff --git a/15_virtual_mem_part3_precomputed_tables/Cargo.toml b/15_virtual_mem_part3_precomputed_tables/Cargo.toml index 6a41bd03..6480a727 100644 --- a/15_virtual_mem_part3_precomputed_tables/Cargo.toml +++ b/15_virtual_mem_part3_precomputed_tables/Cargo.toml @@ -1,60 +1,9 @@ -[package] -name = "mingo" -version = "0.15.0" -authors = ["Andre Richter "] -edition = "2021" +[workspace] + +members = [ + "libraries/*", + "kernel" +] [profile.release] lto = true - -[features] -default = [] -bsp_rpi3 = ["tock-registers"] -bsp_rpi4 = ["tock-registers"] -test_build = ["qemu-exit"] - -##-------------------------------------------------------------------------------------------------- -## Dependencies -##-------------------------------------------------------------------------------------------------- - -[dependencies] -test-types = { path = "test-types" } - -# Optional dependencies -tock-registers = { version = "0.7.x", default-features = false, features = ["register_types"], optional = true } -qemu-exit = { version = "3.x.x", optional = true } - -# Platform specific dependencies -[target.'cfg(target_arch = "aarch64")'.dependencies] -cortex-a = { version = "7.x.x" } - -##-------------------------------------------------------------------------------------------------- -## Testing -##-------------------------------------------------------------------------------------------------- - -[dev-dependencies] -test-macros = { path = "test-macros" } - -# Unit tests are done in the library part of the kernel. -[lib] -name = "libkernel" -test = true - -# Disable unit tests for the kernel binary. -[[bin]] -name = "kernel" -path = "src/main.rs" -test = false - -# List of tests without harness. -[[test]] -name = "00_console_sanity" -harness = false - -[[test]] -name = "02_exception_sync_page_fault" -harness = false - -[[test]] -name = "03_exception_restore_sanity" -harness = false diff --git a/15_virtual_mem_part3_precomputed_tables/Makefile b/15_virtual_mem_part3_precomputed_tables/Makefile index a695185d..81de6005 100644 --- a/15_virtual_mem_part3_precomputed_tables/Makefile +++ b/15_virtual_mem_part3_precomputed_tables/Makefile @@ -41,7 +41,7 @@ ifeq ($(BSP),rpi3) READELF_BINARY = aarch64-none-elf-readelf OPENOCD_ARG = -f /openocd/tcl/interface/ftdi/olimex-arm-usb-tiny-h.cfg -f /openocd/rpi3.cfg JTAG_BOOT_IMAGE = ../X1_JTAG_boot/jtag_boot_rpi3.img - LD_SCRIPT_PATH = $(shell pwd)/src/bsp/raspberrypi + LD_SCRIPT_PATH = $(shell pwd)/kernel/src/bsp/raspberrypi RUSTC_MISC_ARGS = -C target-cpu=cortex-a53 else ifeq ($(BSP),rpi4) TARGET = aarch64-unknown-none-softfloat @@ -55,7 +55,7 @@ else ifeq ($(BSP),rpi4) READELF_BINARY = aarch64-none-elf-readelf OPENOCD_ARG = -f /openocd/tcl/interface/ftdi/olimex-arm-usb-tiny-h.cfg -f /openocd/rpi4.cfg JTAG_BOOT_IMAGE = ../X1_JTAG_boot/jtag_boot_rpi4.img - LD_SCRIPT_PATH = $(shell pwd)/src/bsp/raspberrypi + LD_SCRIPT_PATH = $(shell pwd)/kernel/src/bsp/raspberrypi RUSTC_MISC_ARGS = -C target-cpu=cortex-a72 endif @@ -67,11 +67,11 @@ export LD_SCRIPT_PATH ##-------------------------------------------------------------------------------------------------- ## Targets and Prerequisites ##-------------------------------------------------------------------------------------------------- +KERNEL_MANIFEST = kernel/Cargo.toml KERNEL_LINKER_SCRIPT = kernel.ld +LAST_BUILD_CONFIG = target/$(BSP).build_config -TT_TOOL_PATH = translation_table_tool - -LAST_BUILD_CONFIG = target/$(BSP).build_config +TT_TOOL_PATH = tools/translation_table_tool KERNEL_ELF_RAW = target/$(TARGET)/release/kernel # This parses cargo's dep-info file. @@ -101,11 +101,11 @@ COMPILER_ARGS = --target=$(TARGET) \ $(FEATURES) \ --release -RUSTC_CMD = cargo rustc $(COMPILER_ARGS) +RUSTC_CMD = cargo rustc $(COMPILER_ARGS) --manifest-path $(KERNEL_MANIFEST) DOC_CMD = cargo doc $(COMPILER_ARGS) CLIPPY_CMD = cargo clippy $(COMPILER_ARGS) CHECK_CMD = cargo check $(COMPILER_ARGS) -TEST_CMD = cargo test $(COMPILER_ARGS) +TEST_CMD = cargo test $(COMPILER_ARGS) --manifest-path $(KERNEL_MANIFEST) OBJCOPY_CMD = rust-objcopy \ --strip-all \ -O binary @@ -219,6 +219,8 @@ chainboot: $(KERNEL_BIN) ##------------------------------------------------------------------------------ clippy: @RUSTFLAGS="$(RUSTFLAGS_PEDANTIC)" $(CLIPPY_CMD) + @RUSTFLAGS="$(RUSTFLAGS_PEDANTIC)" $(CLIPPY_CMD) --features test_build --tests \ + --manifest-path $(KERNEL_MANIFEST) ##------------------------------------------------------------------------------ ## Clean @@ -315,6 +317,10 @@ test_boot: $(KERNEL_BIN) define KERNEL_TEST_RUNNER #!/usr/bin/env bash + # The cargo test runner seems to change into the crate under test's directory. Therefore, ensure + # this script executes from the root. + cd $(shell pwd) + TEST_ELF=$$(echo $$1 | sed -e 's/.*target/target/g') TEST_BINARY=$$(echo $$1.img | sed -e 's/.*target/target/g') diff --git a/15_virtual_mem_part3_precomputed_tables/README.md b/15_virtual_mem_part3_precomputed_tables/README.md index b27571e3..c3554f19 100644 --- a/15_virtual_mem_part3_precomputed_tables/README.md +++ b/15_virtual_mem_part3_precomputed_tables/README.md @@ -540,15 +540,15 @@ already, the only missing piece that's left is the offline computation of the tr ### The Translation Table Tool -The tool for translation table computation is located in the folder `translation_table_tool` in the -root directory. For ease of use, it is written in `Ruby` 💎. The code is organized into `BSP` and -`arch` parts just like the kernel's `Rust` code, and also has a class for processing the kernel -`ELF` file: +The tool for translation table computation is located in the folder +`$ROOT/tools/translation_table_tool`. For ease of use, it is written in `Ruby` 💎. The code is +organized into `BSP` and `arch` parts just like the kernel's `Rust` code, and also has a class for +processing the kernel `ELF` file: ```console -$ tree translation_table_tool +$ tree tools/translation_table_tool -translation_table_tool +tools/translation_table_tool ├── arch.rb ├── bsp.rb ├── generic.rb @@ -568,7 +568,7 @@ In the `Makefile`, the tool is invoked after compiling and linking the kernel, a to the kernel's `ELF` file: ```Makefile -TT_TOOL_PATH = translation_table_tool +TT_TOOL_PATH = tools/translation_table_tool KERNEL_ELF_RAW = target/$(TARGET)/release/kernel # [...] @@ -796,9 +796,9 @@ Minipush 1.0 ## Diff to previous ```diff -diff -uNr 14_virtual_mem_part2_mmio_remap/Cargo.toml 15_virtual_mem_part3_precomputed_tables/Cargo.toml ---- 14_virtual_mem_part2_mmio_remap/Cargo.toml -+++ 15_virtual_mem_part3_precomputed_tables/Cargo.toml +diff -uNr 14_virtual_mem_part2_mmio_remap/kernel/Cargo.toml 15_virtual_mem_part3_precomputed_tables/kernel/Cargo.toml +--- 14_virtual_mem_part2_mmio_remap/kernel/Cargo.toml ++++ 15_virtual_mem_part3_precomputed_tables/kernel/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mingo" @@ -808,79 +808,9 @@ diff -uNr 14_virtual_mem_part2_mmio_remap/Cargo.toml 15_virtual_mem_part3_precom edition = "2021" -diff -uNr 14_virtual_mem_part2_mmio_remap/Makefile 15_virtual_mem_part3_precomputed_tables/Makefile ---- 14_virtual_mem_part2_mmio_remap/Makefile -+++ 15_virtual_mem_part3_precomputed_tables/Makefile -@@ -69,12 +69,19 @@ - ##-------------------------------------------------------------------------------------------------- - KERNEL_LINKER_SCRIPT = kernel.ld - -+TT_TOOL_PATH = translation_table_tool -+ - LAST_BUILD_CONFIG = target/$(BSP).build_config - --KERNEL_ELF = target/$(TARGET)/release/kernel -+KERNEL_ELF_RAW = target/$(TARGET)/release/kernel - # This parses cargo's dep-info file. - # https://doc.rust-lang.org/cargo/guide/build-cache.html#dep-info-files --KERNEL_ELF_DEPS = $(filter-out modulo: ,$(file < $(KERNEL_ELF_RAW).d)) $(LAST_BUILD_CONFIG) -+KERNEL_ELF_RAW_DEPS = $(filter-out modulo: ,$(file < $(KERNEL_ELF_RAW).d)) $(LAST_BUILD_CONFIG) -+ -+KERNEL_ELF_TTABLES = target/$(TARGET)/release/kernel+ttables -+KERNEL_ELF_TTABLES_DEPS = $(KERNEL_ELF_RAW) $(wildcard $(TT_TOOL_PATH)/*) -+ -+KERNEL_ELF = $(KERNEL_ELF_TTABLES) - - - -@@ -104,6 +111,7 @@ - -O binary - - EXEC_QEMU = $(QEMU_BINARY) -M $(QEMU_MACHINE_TYPE) -+EXEC_TT_TOOL = ruby $(TT_TOOL_PATH)/main.rb - EXEC_TEST_DISPATCH = ruby ../common/tests/dispatch.rb - EXEC_MINIPUSH = ruby ../common/serial/minipush.rb - -@@ -154,16 +162,24 @@ - ##------------------------------------------------------------------------------ - ## Compile the kernel ELF - ##------------------------------------------------------------------------------ --$(KERNEL_ELF): $(KERNEL_ELF_DEPS) -+$(KERNEL_ELF_RAW): $(KERNEL_ELF_RAW_DEPS) - $(call color_header, "Compiling kernel ELF - $(BSP)") - @RUSTFLAGS="$(RUSTFLAGS_PEDANTIC)" $(RUSTC_CMD) - - ##------------------------------------------------------------------------------ -+## Precompute the kernel translation tables and patch them into the kernel ELF -+##------------------------------------------------------------------------------ -+$(KERNEL_ELF_TTABLES): $(KERNEL_ELF_TTABLES_DEPS) -+ $(call color_header, "Precomputing kernel translation tables and patching kernel ELF") -+ @cp $(KERNEL_ELF_RAW) $(KERNEL_ELF_TTABLES) -+ @$(DOCKER_TOOLS) $(EXEC_TT_TOOL) $(BSP) $(KERNEL_ELF_TTABLES) -+ -+##------------------------------------------------------------------------------ - ## Generate the stripped kernel binary - ##------------------------------------------------------------------------------ --$(KERNEL_BIN): $(KERNEL_ELF) -+$(KERNEL_BIN): $(KERNEL_ELF_TTABLES) - $(call color_header, "Generating stripped binary") -- @$(OBJCOPY_CMD) $(KERNEL_ELF) $(KERNEL_BIN) -+ @$(OBJCOPY_CMD) $(KERNEL_ELF_TTABLES) $(KERNEL_BIN) - $(call color_progress_prefix, "Name") - @echo $(KERNEL_BIN) - $(call color_progress_prefix, "Size") -@@ -302,6 +318,7 @@ - TEST_ELF=$$(echo $$1 | sed -e 's/.*target/target/g') - TEST_BINARY=$$(echo $$1.img | sed -e 's/.*target/target/g') - -+ $(DOCKER_TOOLS) $(EXEC_TT_TOOL) $(BSP) $$TEST_ELF > /dev/null - $(OBJCOPY_CMD) $$TEST_ELF $$TEST_BINARY - $(DOCKER_TEST) $(EXEC_TEST_DISPATCH) $(EXEC_QEMU) $(QEMU_TEST_ARGS) -kernel $$TEST_BINARY - endef - -diff -uNr 14_virtual_mem_part2_mmio_remap/src/_arch/aarch64/cpu/boot.rs 15_virtual_mem_part3_precomputed_tables/src/_arch/aarch64/cpu/boot.rs ---- 14_virtual_mem_part2_mmio_remap/src/_arch/aarch64/cpu/boot.rs -+++ 15_virtual_mem_part3_precomputed_tables/src/_arch/aarch64/cpu/boot.rs +diff -uNr 14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/cpu/boot.rs 15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/cpu/boot.rs +--- 14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/cpu/boot.rs ++++ 15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/cpu/boot.rs @@ -11,6 +11,7 @@ //! //! crate::cpu::boot::arch_boot @@ -908,9 +838,9 @@ diff -uNr 14_virtual_mem_part2_mmio_remap/src/_arch/aarch64/cpu/boot.rs 15_virtu asm::eret() } -diff -uNr 14_virtual_mem_part2_mmio_remap/src/_arch/aarch64/cpu/boot.s 15_virtual_mem_part3_precomputed_tables/src/_arch/aarch64/cpu/boot.s ---- 14_virtual_mem_part2_mmio_remap/src/_arch/aarch64/cpu/boot.s -+++ 15_virtual_mem_part3_precomputed_tables/src/_arch/aarch64/cpu/boot.s +diff -uNr 14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/cpu/boot.s 15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/cpu/boot.s +--- 14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/cpu/boot.s ++++ 15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/cpu/boot.s @@ -56,11 +56,14 @@ // Prepare the jump to Rust code. @@ -930,9 +860,9 @@ diff -uNr 14_virtual_mem_part2_mmio_remap/src/_arch/aarch64/cpu/boot.s 15_virtua // Infinitely wait for events (aka "park the core"). -diff -uNr 14_virtual_mem_part2_mmio_remap/src/_arch/aarch64/memory/mmu/translation_table.rs 15_virtual_mem_part3_precomputed_tables/src/_arch/aarch64/memory/mmu/translation_table.rs ---- 14_virtual_mem_part2_mmio_remap/src/_arch/aarch64/memory/mmu/translation_table.rs -+++ 15_virtual_mem_part3_precomputed_tables/src/_arch/aarch64/memory/mmu/translation_table.rs +diff -uNr 14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/memory/mmu/translation_table.rs 15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/memory/mmu/translation_table.rs +--- 14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/memory/mmu/translation_table.rs ++++ 15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/memory/mmu/translation_table.rs @@ -125,7 +125,7 @@ } @@ -1135,9 +1065,9 @@ diff -uNr 14_virtual_mem_part2_mmio_remap/src/_arch/aarch64/memory/mmu/translati //-------------------------------------------------------------------------------------------------- -diff -uNr 14_virtual_mem_part2_mmio_remap/src/bsp/raspberrypi/console.rs 15_virtual_mem_part3_precomputed_tables/src/bsp/raspberrypi/console.rs ---- 14_virtual_mem_part2_mmio_remap/src/bsp/raspberrypi/console.rs -+++ 15_virtual_mem_part3_precomputed_tables/src/bsp/raspberrypi/console.rs +diff -uNr 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/console.rs 15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/console.rs +--- 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/console.rs ++++ 15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/console.rs @@ -22,6 +22,7 @@ /// # Safety /// @@ -1194,9 +1124,9 @@ diff -uNr 14_virtual_mem_part2_mmio_remap/src/bsp/raspberrypi/console.rs 15_virt + } +} -diff -uNr 14_virtual_mem_part2_mmio_remap/src/bsp/raspberrypi/kernel.ld 15_virtual_mem_part3_precomputed_tables/src/bsp/raspberrypi/kernel.ld ---- 14_virtual_mem_part2_mmio_remap/src/bsp/raspberrypi/kernel.ld -+++ 15_virtual_mem_part3_precomputed_tables/src/bsp/raspberrypi/kernel.ld +diff -uNr 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/kernel.ld 15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/kernel.ld +--- 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/kernel.ld ++++ 15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/kernel.ld @@ -3,6 +3,8 @@ * Copyright (c) 2018-2022 Andre Richter */ @@ -1207,15 +1137,15 @@ diff -uNr 14_virtual_mem_part2_mmio_remap/src/bsp/raspberrypi/kernel.ld 15_virtu PAGE_MASK = PAGE_SIZE - 1; -diff -uNr 14_virtual_mem_part2_mmio_remap/src/bsp/raspberrypi/kernel_virt_addr_space_size.ld 15_virtual_mem_part3_precomputed_tables/src/bsp/raspberrypi/kernel_virt_addr_space_size.ld ---- 14_virtual_mem_part2_mmio_remap/src/bsp/raspberrypi/kernel_virt_addr_space_size.ld -+++ 15_virtual_mem_part3_precomputed_tables/src/bsp/raspberrypi/kernel_virt_addr_space_size.ld +diff -uNr 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/kernel_virt_addr_space_size.ld 15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/kernel_virt_addr_space_size.ld +--- 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/kernel_virt_addr_space_size.ld ++++ 15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/kernel_virt_addr_space_size.ld @@ -0,0 +1 @@ +__kernel_virt_addr_space_size = 1024 * 1024 * 1024 -diff -uNr 14_virtual_mem_part2_mmio_remap/src/bsp/raspberrypi/memory/mmu.rs 15_virtual_mem_part3_precomputed_tables/src/bsp/raspberrypi/memory/mmu.rs ---- 14_virtual_mem_part2_mmio_remap/src/bsp/raspberrypi/memory/mmu.rs -+++ 15_virtual_mem_part3_precomputed_tables/src/bsp/raspberrypi/memory/mmu.rs +diff -uNr 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/memory/mmu.rs 15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/memory/mmu.rs +--- 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/memory/mmu.rs ++++ 15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/memory/mmu.rs @@ -7,8 +7,8 @@ use crate::{ memory::{ @@ -1441,9 +1371,9 @@ diff -uNr 14_virtual_mem_part2_mmio_remap/src/bsp/raspberrypi/memory/mmu.rs 15_v + ); } -diff -uNr 14_virtual_mem_part2_mmio_remap/src/main.rs 15_virtual_mem_part3_precomputed_tables/src/main.rs ---- 14_virtual_mem_part2_mmio_remap/src/main.rs -+++ 15_virtual_mem_part3_precomputed_tables/src/main.rs +diff -uNr 14_virtual_mem_part2_mmio_remap/kernel/src/main.rs 15_virtual_mem_part3_precomputed_tables/kernel/src/main.rs +--- 14_virtual_mem_part2_mmio_remap/kernel/src/main.rs ++++ 15_virtual_mem_part3_precomputed_tables/kernel/src/main.rs @@ -15,31 +15,23 @@ /// Early init code. @@ -1493,9 +1423,9 @@ diff -uNr 14_virtual_mem_part2_mmio_remap/src/main.rs 15_virtual_mem_part3_preco // Now bring up the remaining drivers. for i in bsp::driver::driver_manager() -diff -uNr 14_virtual_mem_part2_mmio_remap/src/memory/mmu/translation_table.rs 15_virtual_mem_part3_precomputed_tables/src/memory/mmu/translation_table.rs ---- 14_virtual_mem_part2_mmio_remap/src/memory/mmu/translation_table.rs -+++ 15_virtual_mem_part3_precomputed_tables/src/memory/mmu/translation_table.rs +diff -uNr 14_virtual_mem_part2_mmio_remap/kernel/src/memory/mmu/translation_table.rs 15_virtual_mem_part3_precomputed_tables/kernel/src/memory/mmu/translation_table.rs +--- 14_virtual_mem_part2_mmio_remap/kernel/src/memory/mmu/translation_table.rs ++++ 15_virtual_mem_part3_precomputed_tables/kernel/src/memory/mmu/translation_table.rs @@ -23,6 +23,8 @@ /// Translation table interfaces. @@ -1583,9 +1513,9 @@ diff -uNr 14_virtual_mem_part2_mmio_remap/src/memory/mmu/translation_table.rs 15 } } -diff -uNr 14_virtual_mem_part2_mmio_remap/src/memory/mmu.rs 15_virtual_mem_part3_precomputed_tables/src/memory/mmu.rs ---- 14_virtual_mem_part2_mmio_remap/src/memory/mmu.rs -+++ 15_virtual_mem_part3_precomputed_tables/src/memory/mmu.rs +diff -uNr 14_virtual_mem_part2_mmio_remap/kernel/src/memory/mmu.rs 15_virtual_mem_part3_precomputed_tables/kernel/src/memory/mmu.rs +--- 14_virtual_mem_part2_mmio_remap/kernel/src/memory/mmu.rs ++++ 15_virtual_mem_part3_precomputed_tables/kernel/src/memory/mmu.rs @@ -16,7 +16,8 @@ use crate::{ bsp, @@ -1752,9 +1682,9 @@ diff -uNr 14_virtual_mem_part2_mmio_remap/src/memory/mmu.rs 15_virtual_mem_part3 - } -} -diff -uNr 14_virtual_mem_part2_mmio_remap/tests/00_console_sanity.rs 15_virtual_mem_part3_precomputed_tables/tests/00_console_sanity.rs ---- 14_virtual_mem_part2_mmio_remap/tests/00_console_sanity.rs -+++ 15_virtual_mem_part3_precomputed_tables/tests/00_console_sanity.rs +diff -uNr 14_virtual_mem_part2_mmio_remap/kernel/tests/00_console_sanity.rs 15_virtual_mem_part3_precomputed_tables/kernel/tests/00_console_sanity.rs +--- 14_virtual_mem_part2_mmio_remap/kernel/tests/00_console_sanity.rs ++++ 15_virtual_mem_part3_precomputed_tables/kernel/tests/00_console_sanity.rs @@ -11,7 +11,7 @@ /// Console tests should time out on the I/O harness in case of panic. mod panic_wait_forever; @@ -1773,9 +1703,9 @@ diff -uNr 14_virtual_mem_part2_mmio_remap/tests/00_console_sanity.rs 15_virtual_ // Handshake -diff -uNr 14_virtual_mem_part2_mmio_remap/tests/01_timer_sanity.rs 15_virtual_mem_part3_precomputed_tables/tests/01_timer_sanity.rs ---- 14_virtual_mem_part2_mmio_remap/tests/01_timer_sanity.rs -+++ 15_virtual_mem_part3_precomputed_tables/tests/01_timer_sanity.rs +diff -uNr 14_virtual_mem_part2_mmio_remap/kernel/tests/01_timer_sanity.rs 15_virtual_mem_part3_precomputed_tables/kernel/tests/01_timer_sanity.rs +--- 14_virtual_mem_part2_mmio_remap/kernel/tests/01_timer_sanity.rs ++++ 15_virtual_mem_part3_precomputed_tables/kernel/tests/01_timer_sanity.rs @@ -11,12 +11,13 @@ #![test_runner(libkernel::test_runner)] @@ -1792,9 +1722,9 @@ diff -uNr 14_virtual_mem_part2_mmio_remap/tests/01_timer_sanity.rs 15_virtual_me // Depending on CPU arch, some timer bring-up code could go here. Not needed for the RPi. -diff -uNr 14_virtual_mem_part2_mmio_remap/tests/02_exception_sync_page_fault.rs 15_virtual_mem_part3_precomputed_tables/tests/02_exception_sync_page_fault.rs ---- 14_virtual_mem_part2_mmio_remap/tests/02_exception_sync_page_fault.rs -+++ 15_virtual_mem_part3_precomputed_tables/tests/02_exception_sync_page_fault.rs +diff -uNr 14_virtual_mem_part2_mmio_remap/kernel/tests/02_exception_sync_page_fault.rs 15_virtual_mem_part3_precomputed_tables/kernel/tests/02_exception_sync_page_fault.rs +--- 14_virtual_mem_part2_mmio_remap/kernel/tests/02_exception_sync_page_fault.rs ++++ 15_virtual_mem_part3_precomputed_tables/kernel/tests/02_exception_sync_page_fault.rs @@ -21,40 +21,12 @@ #[no_mangle] @@ -1839,9 +1769,9 @@ diff -uNr 14_virtual_mem_part2_mmio_remap/tests/02_exception_sync_page_fault.rs info!("Writing beyond mapped area to address 9 GiB..."); let big_addr: u64 = 9 * 1024 * 1024 * 1024; -diff -uNr 14_virtual_mem_part2_mmio_remap/tests/03_exception_restore_sanity.rs 15_virtual_mem_part3_precomputed_tables/tests/03_exception_restore_sanity.rs ---- 14_virtual_mem_part2_mmio_remap/tests/03_exception_restore_sanity.rs -+++ 15_virtual_mem_part3_precomputed_tables/tests/03_exception_restore_sanity.rs +diff -uNr 14_virtual_mem_part2_mmio_remap/kernel/tests/03_exception_restore_sanity.rs 15_virtual_mem_part3_precomputed_tables/kernel/tests/03_exception_restore_sanity.rs +--- 14_virtual_mem_part2_mmio_remap/kernel/tests/03_exception_restore_sanity.rs ++++ 15_virtual_mem_part3_precomputed_tables/kernel/tests/03_exception_restore_sanity.rs @@ -30,40 +30,12 @@ #[no_mangle] @@ -1886,9 +1816,9 @@ diff -uNr 14_virtual_mem_part2_mmio_remap/tests/03_exception_restore_sanity.rs 1 info!("Making a dummy system call"); -diff -uNr 14_virtual_mem_part2_mmio_remap/tests/04_exception_irq_sanity.rs 15_virtual_mem_part3_precomputed_tables/tests/04_exception_irq_sanity.rs ---- 14_virtual_mem_part2_mmio_remap/tests/04_exception_irq_sanity.rs -+++ 15_virtual_mem_part3_precomputed_tables/tests/04_exception_irq_sanity.rs +diff -uNr 14_virtual_mem_part2_mmio_remap/kernel/tests/04_exception_irq_sanity.rs 15_virtual_mem_part3_precomputed_tables/kernel/tests/04_exception_irq_sanity.rs +--- 14_virtual_mem_part2_mmio_remap/kernel/tests/04_exception_irq_sanity.rs ++++ 15_virtual_mem_part3_precomputed_tables/kernel/tests/04_exception_irq_sanity.rs @@ -10,11 +10,12 @@ #![reexport_test_harness_main = "test_main"] #![test_runner(libkernel::test_runner)] @@ -1904,9 +1834,77 @@ diff -uNr 14_virtual_mem_part2_mmio_remap/tests/04_exception_irq_sanity.rs 15_vi exception::handling_init(); -diff -uNr 14_virtual_mem_part2_mmio_remap/translation_table_tool/arch.rb 15_virtual_mem_part3_precomputed_tables/translation_table_tool/arch.rb ---- 14_virtual_mem_part2_mmio_remap/translation_table_tool/arch.rb -+++ 15_virtual_mem_part3_precomputed_tables/translation_table_tool/arch.rb +diff -uNr 14_virtual_mem_part2_mmio_remap/Makefile 15_virtual_mem_part3_precomputed_tables/Makefile +--- 14_virtual_mem_part2_mmio_remap/Makefile ++++ 15_virtual_mem_part3_precomputed_tables/Makefile +@@ -71,10 +71,17 @@ + KERNEL_LINKER_SCRIPT = kernel.ld + LAST_BUILD_CONFIG = target/$(BSP).build_config + +-KERNEL_ELF = target/$(TARGET)/release/kernel ++TT_TOOL_PATH = tools/translation_table_tool ++ ++KERNEL_ELF_RAW = target/$(TARGET)/release/kernel + # This parses cargo's dep-info file. + # https://doc.rust-lang.org/cargo/guide/build-cache.html#dep-info-files +-KERNEL_ELF_DEPS = $(filter-out modulo: ,$(file < $(KERNEL_ELF_RAW).d)) $(LAST_BUILD_CONFIG) ++KERNEL_ELF_RAW_DEPS = $(filter-out modulo: ,$(file < $(KERNEL_ELF_RAW).d)) $(LAST_BUILD_CONFIG) ++ ++KERNEL_ELF_TTABLES = target/$(TARGET)/release/kernel+ttables ++KERNEL_ELF_TTABLES_DEPS = $(KERNEL_ELF_RAW) $(wildcard $(TT_TOOL_PATH)/*) ++ ++KERNEL_ELF = $(KERNEL_ELF_TTABLES) + + + +@@ -104,6 +111,7 @@ + -O binary + + EXEC_QEMU = $(QEMU_BINARY) -M $(QEMU_MACHINE_TYPE) ++EXEC_TT_TOOL = ruby $(TT_TOOL_PATH)/main.rb + EXEC_TEST_DISPATCH = ruby ../common/tests/dispatch.rb + EXEC_MINIPUSH = ruby ../common/serial/minipush.rb + +@@ -154,16 +162,24 @@ + ##------------------------------------------------------------------------------ + ## Compile the kernel ELF + ##------------------------------------------------------------------------------ +-$(KERNEL_ELF): $(KERNEL_ELF_DEPS) ++$(KERNEL_ELF_RAW): $(KERNEL_ELF_RAW_DEPS) + $(call color_header, "Compiling kernel ELF - $(BSP)") + @RUSTFLAGS="$(RUSTFLAGS_PEDANTIC)" $(RUSTC_CMD) + + ##------------------------------------------------------------------------------ ++## Precompute the kernel translation tables and patch them into the kernel ELF ++##------------------------------------------------------------------------------ ++$(KERNEL_ELF_TTABLES): $(KERNEL_ELF_TTABLES_DEPS) ++ $(call color_header, "Precomputing kernel translation tables and patching kernel ELF") ++ @cp $(KERNEL_ELF_RAW) $(KERNEL_ELF_TTABLES) ++ @$(DOCKER_TOOLS) $(EXEC_TT_TOOL) $(BSP) $(KERNEL_ELF_TTABLES) ++ ++##------------------------------------------------------------------------------ + ## Generate the stripped kernel binary + ##------------------------------------------------------------------------------ +-$(KERNEL_BIN): $(KERNEL_ELF) ++$(KERNEL_BIN): $(KERNEL_ELF_TTABLES) + $(call color_header, "Generating stripped binary") +- @$(OBJCOPY_CMD) $(KERNEL_ELF) $(KERNEL_BIN) ++ @$(OBJCOPY_CMD) $(KERNEL_ELF_TTABLES) $(KERNEL_BIN) + $(call color_progress_prefix, "Name") + @echo $(KERNEL_BIN) + $(call color_progress_prefix, "Size") +@@ -308,6 +324,7 @@ + TEST_ELF=$$(echo $$1 | sed -e 's/.*target/target/g') + TEST_BINARY=$$(echo $$1.img | sed -e 's/.*target/target/g') + ++ $(DOCKER_TOOLS) $(EXEC_TT_TOOL) $(BSP) $$TEST_ELF > /dev/null + $(OBJCOPY_CMD) $$TEST_ELF $$TEST_BINARY + $(DOCKER_TEST) $(EXEC_TEST_DISPATCH) $(EXEC_QEMU) $(QEMU_TEST_ARGS) -kernel $$TEST_BINARY + endef + +diff -uNr 14_virtual_mem_part2_mmio_remap/tools/translation_table_tool/arch.rb 15_virtual_mem_part3_precomputed_tables/tools/translation_table_tool/arch.rb +--- 14_virtual_mem_part2_mmio_remap/tools/translation_table_tool/arch.rb ++++ 15_virtual_mem_part3_precomputed_tables/tools/translation_table_tool/arch.rb @@ -0,0 +1,312 @@ +# frozen_string_literal: true + @@ -2221,9 +2219,9 @@ diff -uNr 14_virtual_mem_part2_mmio_remap/translation_table_tool/arch.rb 15_virt +end +end -diff -uNr 14_virtual_mem_part2_mmio_remap/translation_table_tool/bsp.rb 15_virtual_mem_part3_precomputed_tables/translation_table_tool/bsp.rb ---- 14_virtual_mem_part2_mmio_remap/translation_table_tool/bsp.rb -+++ 15_virtual_mem_part3_precomputed_tables/translation_table_tool/bsp.rb +diff -uNr 14_virtual_mem_part2_mmio_remap/tools/translation_table_tool/bsp.rb 15_virtual_mem_part3_precomputed_tables/tools/translation_table_tool/bsp.rb +--- 14_virtual_mem_part2_mmio_remap/tools/translation_table_tool/bsp.rb ++++ 15_virtual_mem_part3_precomputed_tables/tools/translation_table_tool/bsp.rb @@ -0,0 +1,49 @@ +# frozen_string_literal: true + @@ -2235,7 +2233,7 @@ diff -uNr 14_virtual_mem_part2_mmio_remap/translation_table_tool/bsp.rb 15_virtu +class RaspberryPi + attr_reader :kernel_granule, :kernel_virt_addr_space_size + -+ MEMORY_SRC = File.read('src/bsp/raspberrypi/memory.rs').split("\n") ++ MEMORY_SRC = File.read('kernel/src/bsp/raspberrypi/memory.rs').split("\n") + + def initialize + @kernel_granule = Granule64KiB @@ -2275,9 +2273,9 @@ diff -uNr 14_virtual_mem_part2_mmio_remap/translation_table_tool/bsp.rb 15_virtu + end +end -diff -uNr 14_virtual_mem_part2_mmio_remap/translation_table_tool/generic.rb 15_virtual_mem_part3_precomputed_tables/translation_table_tool/generic.rb ---- 14_virtual_mem_part2_mmio_remap/translation_table_tool/generic.rb -+++ 15_virtual_mem_part3_precomputed_tables/translation_table_tool/generic.rb +diff -uNr 14_virtual_mem_part2_mmio_remap/tools/translation_table_tool/generic.rb 15_virtual_mem_part3_precomputed_tables/tools/translation_table_tool/generic.rb +--- 14_virtual_mem_part2_mmio_remap/tools/translation_table_tool/generic.rb ++++ 15_virtual_mem_part3_precomputed_tables/tools/translation_table_tool/generic.rb @@ -0,0 +1,179 @@ +# frozen_string_literal: true + @@ -2459,9 +2457,9 @@ diff -uNr 14_virtual_mem_part2_mmio_remap/translation_table_tool/generic.rb 15_v + BSP.phys_kernel_tables_base_addr_offset_in_file) +end -diff -uNr 14_virtual_mem_part2_mmio_remap/translation_table_tool/kernel_elf.rb 15_virtual_mem_part3_precomputed_tables/translation_table_tool/kernel_elf.rb ---- 14_virtual_mem_part2_mmio_remap/translation_table_tool/kernel_elf.rb -+++ 15_virtual_mem_part3_precomputed_tables/translation_table_tool/kernel_elf.rb +diff -uNr 14_virtual_mem_part2_mmio_remap/tools/translation_table_tool/kernel_elf.rb 15_virtual_mem_part3_precomputed_tables/tools/translation_table_tool/kernel_elf.rb +--- 14_virtual_mem_part2_mmio_remap/tools/translation_table_tool/kernel_elf.rb ++++ 15_virtual_mem_part3_precomputed_tables/tools/translation_table_tool/kernel_elf.rb @@ -0,0 +1,96 @@ +# frozen_string_literal: true + @@ -2560,9 +2558,9 @@ diff -uNr 14_virtual_mem_part2_mmio_remap/translation_table_tool/kernel_elf.rb 1 + end +end -diff -uNr 14_virtual_mem_part2_mmio_remap/translation_table_tool/main.rb 15_virtual_mem_part3_precomputed_tables/translation_table_tool/main.rb ---- 14_virtual_mem_part2_mmio_remap/translation_table_tool/main.rb -+++ 15_virtual_mem_part3_precomputed_tables/translation_table_tool/main.rb +diff -uNr 14_virtual_mem_part2_mmio_remap/tools/translation_table_tool/main.rb 15_virtual_mem_part3_precomputed_tables/tools/translation_table_tool/main.rb +--- 14_virtual_mem_part2_mmio_remap/tools/translation_table_tool/main.rb ++++ 15_virtual_mem_part3_precomputed_tables/tools/translation_table_tool/main.rb @@ -0,0 +1,46 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/Cargo.toml b/15_virtual_mem_part3_precomputed_tables/kernel/Cargo.toml new file mode 100644 index 00000000..0d675c93 --- /dev/null +++ b/15_virtual_mem_part3_precomputed_tables/kernel/Cargo.toml @@ -0,0 +1,58 @@ +[package] +name = "mingo" +version = "0.15.0" +authors = ["Andre Richter "] +edition = "2021" + + +[features] +default = [] +bsp_rpi3 = ["tock-registers"] +bsp_rpi4 = ["tock-registers"] +test_build = ["qemu-exit"] + +##-------------------------------------------------------------------------------------------------- +## Dependencies +##-------------------------------------------------------------------------------------------------- + +[dependencies] +test-types = { path = "../libraries/test-types" } + +# Optional dependencies +tock-registers = { version = "0.7.x", default-features = false, features = ["register_types"], optional = true } +qemu-exit = { version = "3.x.x", optional = true } + +# Platform specific dependencies +[target.'cfg(target_arch = "aarch64")'.dependencies] +cortex-a = { version = "7.x.x" } + +##-------------------------------------------------------------------------------------------------- +## Testing +##-------------------------------------------------------------------------------------------------- + +[dev-dependencies] +test-macros = { path = "../libraries/test-macros" } + +# Unit tests are done in the library part of the kernel. +[lib] +name = "libkernel" +test = true + +# Disable unit tests for the kernel binary. +[[bin]] +name = "kernel" +path = "src/main.rs" +test = false + +# List of tests without harness. +[[test]] +name = "00_console_sanity" +harness = false + +[[test]] +name = "02_exception_sync_page_fault" +harness = false + +[[test]] +name = "03_exception_restore_sanity" +harness = false diff --git a/15_virtual_mem_part3_precomputed_tables/build.rs b/15_virtual_mem_part3_precomputed_tables/kernel/build.rs similarity index 100% rename from 15_virtual_mem_part3_precomputed_tables/build.rs rename to 15_virtual_mem_part3_precomputed_tables/kernel/build.rs diff --git a/15_virtual_mem_part3_precomputed_tables/src/_arch/aarch64/cpu.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/cpu.rs similarity index 100% rename from 15_virtual_mem_part3_precomputed_tables/src/_arch/aarch64/cpu.rs rename to 15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/cpu.rs diff --git a/15_virtual_mem_part3_precomputed_tables/src/_arch/aarch64/cpu/boot.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/cpu/boot.rs similarity index 100% rename from 15_virtual_mem_part3_precomputed_tables/src/_arch/aarch64/cpu/boot.rs rename to 15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/cpu/boot.rs diff --git a/15_virtual_mem_part3_precomputed_tables/src/_arch/aarch64/cpu/boot.s b/15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/cpu/boot.s similarity index 100% rename from 15_virtual_mem_part3_precomputed_tables/src/_arch/aarch64/cpu/boot.s rename to 15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/cpu/boot.s diff --git a/15_virtual_mem_part3_precomputed_tables/src/_arch/aarch64/cpu/smp.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/cpu/smp.rs similarity index 100% rename from 15_virtual_mem_part3_precomputed_tables/src/_arch/aarch64/cpu/smp.rs rename to 15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/cpu/smp.rs diff --git a/15_virtual_mem_part3_precomputed_tables/src/_arch/aarch64/exception.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/exception.rs similarity index 100% rename from 15_virtual_mem_part3_precomputed_tables/src/_arch/aarch64/exception.rs rename to 15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/exception.rs diff --git a/15_virtual_mem_part3_precomputed_tables/src/_arch/aarch64/exception.s b/15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/exception.s similarity index 100% rename from 15_virtual_mem_part3_precomputed_tables/src/_arch/aarch64/exception.s rename to 15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/exception.s diff --git a/15_virtual_mem_part3_precomputed_tables/src/_arch/aarch64/exception/asynchronous.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/exception/asynchronous.rs similarity index 100% rename from 15_virtual_mem_part3_precomputed_tables/src/_arch/aarch64/exception/asynchronous.rs rename to 15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/exception/asynchronous.rs diff --git a/15_virtual_mem_part3_precomputed_tables/src/_arch/aarch64/memory/mmu.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/memory/mmu.rs similarity index 100% rename from 15_virtual_mem_part3_precomputed_tables/src/_arch/aarch64/memory/mmu.rs rename to 15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/memory/mmu.rs diff --git a/15_virtual_mem_part3_precomputed_tables/src/_arch/aarch64/memory/mmu/translation_table.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/memory/mmu/translation_table.rs similarity index 100% rename from 15_virtual_mem_part3_precomputed_tables/src/_arch/aarch64/memory/mmu/translation_table.rs rename to 15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/memory/mmu/translation_table.rs diff --git a/15_virtual_mem_part3_precomputed_tables/src/_arch/aarch64/time.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/time.rs similarity index 100% rename from 15_virtual_mem_part3_precomputed_tables/src/_arch/aarch64/time.rs rename to 15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/time.rs diff --git a/15_virtual_mem_part3_precomputed_tables/src/bsp.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp.rs similarity index 100% rename from 15_virtual_mem_part3_precomputed_tables/src/bsp.rs rename to 15_virtual_mem_part3_precomputed_tables/kernel/src/bsp.rs diff --git a/15_virtual_mem_part3_precomputed_tables/src/bsp/device_driver.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver.rs similarity index 100% rename from 15_virtual_mem_part3_precomputed_tables/src/bsp/device_driver.rs rename to 15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver.rs diff --git a/15_virtual_mem_part3_precomputed_tables/src/bsp/device_driver/arm.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/arm.rs similarity index 100% rename from 15_virtual_mem_part3_precomputed_tables/src/bsp/device_driver/arm.rs rename to 15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/arm.rs diff --git a/15_virtual_mem_part3_precomputed_tables/src/bsp/device_driver/arm/gicv2.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/arm/gicv2.rs similarity index 100% rename from 15_virtual_mem_part3_precomputed_tables/src/bsp/device_driver/arm/gicv2.rs rename to 15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/arm/gicv2.rs diff --git a/15_virtual_mem_part3_precomputed_tables/src/bsp/device_driver/arm/gicv2/gicc.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/arm/gicv2/gicc.rs similarity index 100% rename from 15_virtual_mem_part3_precomputed_tables/src/bsp/device_driver/arm/gicv2/gicc.rs rename to 15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/arm/gicv2/gicc.rs diff --git a/15_virtual_mem_part3_precomputed_tables/src/bsp/device_driver/arm/gicv2/gicd.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs similarity index 100% rename from 15_virtual_mem_part3_precomputed_tables/src/bsp/device_driver/arm/gicv2/gicd.rs rename to 15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs diff --git a/15_virtual_mem_part3_precomputed_tables/src/bsp/device_driver/bcm.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/bcm.rs similarity index 100% rename from 15_virtual_mem_part3_precomputed_tables/src/bsp/device_driver/bcm.rs rename to 15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/bcm.rs diff --git a/15_virtual_mem_part3_precomputed_tables/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs similarity index 100% rename from 15_virtual_mem_part3_precomputed_tables/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs rename to 15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs diff --git a/15_virtual_mem_part3_precomputed_tables/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs similarity index 100% rename from 15_virtual_mem_part3_precomputed_tables/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs rename to 15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs diff --git a/15_virtual_mem_part3_precomputed_tables/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs similarity index 100% rename from 15_virtual_mem_part3_precomputed_tables/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs rename to 15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs diff --git a/15_virtual_mem_part3_precomputed_tables/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs similarity index 100% rename from 15_virtual_mem_part3_precomputed_tables/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs rename to 15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs diff --git a/15_virtual_mem_part3_precomputed_tables/src/bsp/device_driver/common.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/common.rs similarity index 100% rename from 15_virtual_mem_part3_precomputed_tables/src/bsp/device_driver/common.rs rename to 15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/common.rs diff --git a/15_virtual_mem_part3_precomputed_tables/src/bsp/raspberrypi.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi.rs similarity index 100% rename from 15_virtual_mem_part3_precomputed_tables/src/bsp/raspberrypi.rs rename to 15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi.rs diff --git a/15_virtual_mem_part3_precomputed_tables/src/bsp/raspberrypi/console.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/console.rs similarity index 100% rename from 15_virtual_mem_part3_precomputed_tables/src/bsp/raspberrypi/console.rs rename to 15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/console.rs diff --git a/15_virtual_mem_part3_precomputed_tables/src/bsp/raspberrypi/cpu.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/cpu.rs similarity index 100% rename from 15_virtual_mem_part3_precomputed_tables/src/bsp/raspberrypi/cpu.rs rename to 15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/cpu.rs diff --git a/15_virtual_mem_part3_precomputed_tables/src/bsp/raspberrypi/driver.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/driver.rs similarity index 100% rename from 15_virtual_mem_part3_precomputed_tables/src/bsp/raspberrypi/driver.rs rename to 15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/driver.rs diff --git a/15_virtual_mem_part3_precomputed_tables/src/bsp/raspberrypi/exception.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/exception.rs similarity index 100% rename from 15_virtual_mem_part3_precomputed_tables/src/bsp/raspberrypi/exception.rs rename to 15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/exception.rs diff --git a/15_virtual_mem_part3_precomputed_tables/src/bsp/raspberrypi/exception/asynchronous.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/exception/asynchronous.rs similarity index 100% rename from 15_virtual_mem_part3_precomputed_tables/src/bsp/raspberrypi/exception/asynchronous.rs rename to 15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/exception/asynchronous.rs diff --git a/15_virtual_mem_part3_precomputed_tables/src/bsp/raspberrypi/kernel.ld b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/kernel.ld similarity index 100% rename from 15_virtual_mem_part3_precomputed_tables/src/bsp/raspberrypi/kernel.ld rename to 15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/kernel.ld diff --git a/15_virtual_mem_part3_precomputed_tables/src/bsp/raspberrypi/kernel_virt_addr_space_size.ld b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/kernel_virt_addr_space_size.ld similarity index 100% rename from 15_virtual_mem_part3_precomputed_tables/src/bsp/raspberrypi/kernel_virt_addr_space_size.ld rename to 15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/kernel_virt_addr_space_size.ld diff --git a/15_virtual_mem_part3_precomputed_tables/src/bsp/raspberrypi/memory.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/memory.rs similarity index 100% rename from 15_virtual_mem_part3_precomputed_tables/src/bsp/raspberrypi/memory.rs rename to 15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/memory.rs diff --git a/15_virtual_mem_part3_precomputed_tables/src/bsp/raspberrypi/memory/mmu.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/memory/mmu.rs similarity index 100% rename from 15_virtual_mem_part3_precomputed_tables/src/bsp/raspberrypi/memory/mmu.rs rename to 15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/memory/mmu.rs diff --git a/15_virtual_mem_part3_precomputed_tables/src/common.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/common.rs similarity index 100% rename from 15_virtual_mem_part3_precomputed_tables/src/common.rs rename to 15_virtual_mem_part3_precomputed_tables/kernel/src/common.rs diff --git a/15_virtual_mem_part3_precomputed_tables/src/console.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/console.rs similarity index 100% rename from 15_virtual_mem_part3_precomputed_tables/src/console.rs rename to 15_virtual_mem_part3_precomputed_tables/kernel/src/console.rs diff --git a/15_virtual_mem_part3_precomputed_tables/src/cpu.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/cpu.rs similarity index 100% rename from 15_virtual_mem_part3_precomputed_tables/src/cpu.rs rename to 15_virtual_mem_part3_precomputed_tables/kernel/src/cpu.rs diff --git a/15_virtual_mem_part3_precomputed_tables/src/cpu/boot.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/cpu/boot.rs similarity index 100% rename from 15_virtual_mem_part3_precomputed_tables/src/cpu/boot.rs rename to 15_virtual_mem_part3_precomputed_tables/kernel/src/cpu/boot.rs diff --git a/15_virtual_mem_part3_precomputed_tables/src/cpu/smp.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/cpu/smp.rs similarity index 100% rename from 15_virtual_mem_part3_precomputed_tables/src/cpu/smp.rs rename to 15_virtual_mem_part3_precomputed_tables/kernel/src/cpu/smp.rs diff --git a/15_virtual_mem_part3_precomputed_tables/src/driver.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/driver.rs similarity index 100% rename from 15_virtual_mem_part3_precomputed_tables/src/driver.rs rename to 15_virtual_mem_part3_precomputed_tables/kernel/src/driver.rs diff --git a/15_virtual_mem_part3_precomputed_tables/src/exception.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/exception.rs similarity index 100% rename from 15_virtual_mem_part3_precomputed_tables/src/exception.rs rename to 15_virtual_mem_part3_precomputed_tables/kernel/src/exception.rs diff --git a/15_virtual_mem_part3_precomputed_tables/src/exception/asynchronous.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/exception/asynchronous.rs similarity index 100% rename from 15_virtual_mem_part3_precomputed_tables/src/exception/asynchronous.rs rename to 15_virtual_mem_part3_precomputed_tables/kernel/src/exception/asynchronous.rs diff --git a/15_virtual_mem_part3_precomputed_tables/src/lib.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/lib.rs similarity index 100% rename from 15_virtual_mem_part3_precomputed_tables/src/lib.rs rename to 15_virtual_mem_part3_precomputed_tables/kernel/src/lib.rs diff --git a/15_virtual_mem_part3_precomputed_tables/src/main.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/main.rs similarity index 100% rename from 15_virtual_mem_part3_precomputed_tables/src/main.rs rename to 15_virtual_mem_part3_precomputed_tables/kernel/src/main.rs diff --git a/15_virtual_mem_part3_precomputed_tables/src/memory.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/memory.rs similarity index 100% rename from 15_virtual_mem_part3_precomputed_tables/src/memory.rs rename to 15_virtual_mem_part3_precomputed_tables/kernel/src/memory.rs diff --git a/15_virtual_mem_part3_precomputed_tables/src/memory/mmu.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/memory/mmu.rs similarity index 100% rename from 15_virtual_mem_part3_precomputed_tables/src/memory/mmu.rs rename to 15_virtual_mem_part3_precomputed_tables/kernel/src/memory/mmu.rs diff --git a/15_virtual_mem_part3_precomputed_tables/src/memory/mmu/alloc.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/memory/mmu/alloc.rs similarity index 100% rename from 15_virtual_mem_part3_precomputed_tables/src/memory/mmu/alloc.rs rename to 15_virtual_mem_part3_precomputed_tables/kernel/src/memory/mmu/alloc.rs diff --git a/15_virtual_mem_part3_precomputed_tables/src/memory/mmu/mapping_record.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/memory/mmu/mapping_record.rs similarity index 100% rename from 15_virtual_mem_part3_precomputed_tables/src/memory/mmu/mapping_record.rs rename to 15_virtual_mem_part3_precomputed_tables/kernel/src/memory/mmu/mapping_record.rs diff --git a/15_virtual_mem_part3_precomputed_tables/src/memory/mmu/translation_table.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/memory/mmu/translation_table.rs similarity index 100% rename from 15_virtual_mem_part3_precomputed_tables/src/memory/mmu/translation_table.rs rename to 15_virtual_mem_part3_precomputed_tables/kernel/src/memory/mmu/translation_table.rs diff --git a/15_virtual_mem_part3_precomputed_tables/src/memory/mmu/types.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/memory/mmu/types.rs similarity index 100% rename from 15_virtual_mem_part3_precomputed_tables/src/memory/mmu/types.rs rename to 15_virtual_mem_part3_precomputed_tables/kernel/src/memory/mmu/types.rs diff --git a/15_virtual_mem_part3_precomputed_tables/src/panic_wait.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/panic_wait.rs similarity index 100% rename from 15_virtual_mem_part3_precomputed_tables/src/panic_wait.rs rename to 15_virtual_mem_part3_precomputed_tables/kernel/src/panic_wait.rs diff --git a/15_virtual_mem_part3_precomputed_tables/src/print.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/print.rs similarity index 100% rename from 15_virtual_mem_part3_precomputed_tables/src/print.rs rename to 15_virtual_mem_part3_precomputed_tables/kernel/src/print.rs diff --git a/15_virtual_mem_part3_precomputed_tables/src/state.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/state.rs similarity index 100% rename from 15_virtual_mem_part3_precomputed_tables/src/state.rs rename to 15_virtual_mem_part3_precomputed_tables/kernel/src/state.rs diff --git a/15_virtual_mem_part3_precomputed_tables/src/synchronization.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/synchronization.rs similarity index 100% rename from 15_virtual_mem_part3_precomputed_tables/src/synchronization.rs rename to 15_virtual_mem_part3_precomputed_tables/kernel/src/synchronization.rs diff --git a/15_virtual_mem_part3_precomputed_tables/src/time.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/time.rs similarity index 100% rename from 15_virtual_mem_part3_precomputed_tables/src/time.rs rename to 15_virtual_mem_part3_precomputed_tables/kernel/src/time.rs diff --git a/15_virtual_mem_part3_precomputed_tables/tests/00_console_sanity.rb b/15_virtual_mem_part3_precomputed_tables/kernel/tests/00_console_sanity.rb similarity index 100% rename from 15_virtual_mem_part3_precomputed_tables/tests/00_console_sanity.rb rename to 15_virtual_mem_part3_precomputed_tables/kernel/tests/00_console_sanity.rb diff --git a/15_virtual_mem_part3_precomputed_tables/tests/00_console_sanity.rs b/15_virtual_mem_part3_precomputed_tables/kernel/tests/00_console_sanity.rs similarity index 100% rename from 15_virtual_mem_part3_precomputed_tables/tests/00_console_sanity.rs rename to 15_virtual_mem_part3_precomputed_tables/kernel/tests/00_console_sanity.rs diff --git a/15_virtual_mem_part3_precomputed_tables/tests/01_timer_sanity.rs b/15_virtual_mem_part3_precomputed_tables/kernel/tests/01_timer_sanity.rs similarity index 100% rename from 15_virtual_mem_part3_precomputed_tables/tests/01_timer_sanity.rs rename to 15_virtual_mem_part3_precomputed_tables/kernel/tests/01_timer_sanity.rs diff --git a/15_virtual_mem_part3_precomputed_tables/tests/02_exception_sync_page_fault.rs b/15_virtual_mem_part3_precomputed_tables/kernel/tests/02_exception_sync_page_fault.rs similarity index 100% rename from 15_virtual_mem_part3_precomputed_tables/tests/02_exception_sync_page_fault.rs rename to 15_virtual_mem_part3_precomputed_tables/kernel/tests/02_exception_sync_page_fault.rs diff --git a/15_virtual_mem_part3_precomputed_tables/tests/03_exception_restore_sanity.rb b/15_virtual_mem_part3_precomputed_tables/kernel/tests/03_exception_restore_sanity.rb similarity index 100% rename from 15_virtual_mem_part3_precomputed_tables/tests/03_exception_restore_sanity.rb rename to 15_virtual_mem_part3_precomputed_tables/kernel/tests/03_exception_restore_sanity.rb diff --git a/15_virtual_mem_part3_precomputed_tables/tests/03_exception_restore_sanity.rs b/15_virtual_mem_part3_precomputed_tables/kernel/tests/03_exception_restore_sanity.rs similarity index 100% rename from 15_virtual_mem_part3_precomputed_tables/tests/03_exception_restore_sanity.rs rename to 15_virtual_mem_part3_precomputed_tables/kernel/tests/03_exception_restore_sanity.rs diff --git a/15_virtual_mem_part3_precomputed_tables/tests/04_exception_irq_sanity.rs b/15_virtual_mem_part3_precomputed_tables/kernel/tests/04_exception_irq_sanity.rs similarity index 100% rename from 15_virtual_mem_part3_precomputed_tables/tests/04_exception_irq_sanity.rs rename to 15_virtual_mem_part3_precomputed_tables/kernel/tests/04_exception_irq_sanity.rs diff --git a/15_virtual_mem_part3_precomputed_tables/tests/boot_test_string.rb b/15_virtual_mem_part3_precomputed_tables/kernel/tests/boot_test_string.rb similarity index 100% rename from 15_virtual_mem_part3_precomputed_tables/tests/boot_test_string.rb rename to 15_virtual_mem_part3_precomputed_tables/kernel/tests/boot_test_string.rb diff --git a/15_virtual_mem_part3_precomputed_tables/tests/panic_exit_success/mod.rs b/15_virtual_mem_part3_precomputed_tables/kernel/tests/panic_exit_success/mod.rs similarity index 100% rename from 15_virtual_mem_part3_precomputed_tables/tests/panic_exit_success/mod.rs rename to 15_virtual_mem_part3_precomputed_tables/kernel/tests/panic_exit_success/mod.rs diff --git a/15_virtual_mem_part3_precomputed_tables/tests/panic_wait_forever/mod.rs b/15_virtual_mem_part3_precomputed_tables/kernel/tests/panic_wait_forever/mod.rs similarity index 100% rename from 15_virtual_mem_part3_precomputed_tables/tests/panic_wait_forever/mod.rs rename to 15_virtual_mem_part3_precomputed_tables/kernel/tests/panic_wait_forever/mod.rs diff --git a/15_virtual_mem_part3_precomputed_tables/test-macros/Cargo.toml b/15_virtual_mem_part3_precomputed_tables/libraries/test-macros/Cargo.toml similarity index 100% rename from 15_virtual_mem_part3_precomputed_tables/test-macros/Cargo.toml rename to 15_virtual_mem_part3_precomputed_tables/libraries/test-macros/Cargo.toml diff --git a/15_virtual_mem_part3_precomputed_tables/test-macros/src/lib.rs b/15_virtual_mem_part3_precomputed_tables/libraries/test-macros/src/lib.rs similarity index 100% rename from 15_virtual_mem_part3_precomputed_tables/test-macros/src/lib.rs rename to 15_virtual_mem_part3_precomputed_tables/libraries/test-macros/src/lib.rs diff --git a/15_virtual_mem_part3_precomputed_tables/test-types/Cargo.toml b/15_virtual_mem_part3_precomputed_tables/libraries/test-types/Cargo.toml similarity index 100% rename from 15_virtual_mem_part3_precomputed_tables/test-types/Cargo.toml rename to 15_virtual_mem_part3_precomputed_tables/libraries/test-types/Cargo.toml diff --git a/15_virtual_mem_part3_precomputed_tables/test-types/src/lib.rs b/15_virtual_mem_part3_precomputed_tables/libraries/test-types/src/lib.rs similarity index 100% rename from 15_virtual_mem_part3_precomputed_tables/test-types/src/lib.rs rename to 15_virtual_mem_part3_precomputed_tables/libraries/test-types/src/lib.rs diff --git a/15_virtual_mem_part3_precomputed_tables/translation_table_tool/arch.rb b/15_virtual_mem_part3_precomputed_tables/tools/translation_table_tool/arch.rb similarity index 100% rename from 15_virtual_mem_part3_precomputed_tables/translation_table_tool/arch.rb rename to 15_virtual_mem_part3_precomputed_tables/tools/translation_table_tool/arch.rb diff --git a/15_virtual_mem_part3_precomputed_tables/translation_table_tool/bsp.rb b/15_virtual_mem_part3_precomputed_tables/tools/translation_table_tool/bsp.rb similarity index 94% rename from 15_virtual_mem_part3_precomputed_tables/translation_table_tool/bsp.rb rename to 15_virtual_mem_part3_precomputed_tables/tools/translation_table_tool/bsp.rb index 4aaedaf7..0b76b403 100644 --- a/15_virtual_mem_part3_precomputed_tables/translation_table_tool/bsp.rb +++ b/15_virtual_mem_part3_precomputed_tables/tools/translation_table_tool/bsp.rb @@ -8,7 +8,7 @@ class RaspberryPi attr_reader :kernel_granule, :kernel_virt_addr_space_size - MEMORY_SRC = File.read('src/bsp/raspberrypi/memory.rs').split("\n") + MEMORY_SRC = File.read('kernel/src/bsp/raspberrypi/memory.rs').split("\n") def initialize @kernel_granule = Granule64KiB diff --git a/15_virtual_mem_part3_precomputed_tables/translation_table_tool/generic.rb b/15_virtual_mem_part3_precomputed_tables/tools/translation_table_tool/generic.rb similarity index 100% rename from 15_virtual_mem_part3_precomputed_tables/translation_table_tool/generic.rb rename to 15_virtual_mem_part3_precomputed_tables/tools/translation_table_tool/generic.rb diff --git a/15_virtual_mem_part3_precomputed_tables/translation_table_tool/kernel_elf.rb b/15_virtual_mem_part3_precomputed_tables/tools/translation_table_tool/kernel_elf.rb similarity index 100% rename from 15_virtual_mem_part3_precomputed_tables/translation_table_tool/kernel_elf.rb rename to 15_virtual_mem_part3_precomputed_tables/tools/translation_table_tool/kernel_elf.rb diff --git a/15_virtual_mem_part3_precomputed_tables/translation_table_tool/main.rb b/15_virtual_mem_part3_precomputed_tables/tools/translation_table_tool/main.rb similarity index 100% rename from 15_virtual_mem_part3_precomputed_tables/translation_table_tool/main.rb rename to 15_virtual_mem_part3_precomputed_tables/tools/translation_table_tool/main.rb diff --git a/16_virtual_mem_part4_higher_half_kernel/Cargo.lock b/16_virtual_mem_part4_higher_half_kernel/Cargo.lock index af4081af..7a24ae09 100644 --- a/16_virtual_mem_part4_higher_half_kernel/Cargo.lock +++ b/16_virtual_mem_part4_higher_half_kernel/Cargo.lock @@ -39,9 +39,9 @@ checksum = "9ff023245bfcc73fb890e1f8d5383825b3131cc920020a5c487d6f113dfc428a" [[package]] name = "quote" -version = "1.0.17" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "632d02bff7f874a36f33ea8bb416cd484b90cc66c1194b1a1110d067a7013f58" +checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1" dependencies = [ "proc-macro2", ] diff --git a/16_virtual_mem_part4_higher_half_kernel/Cargo.toml b/16_virtual_mem_part4_higher_half_kernel/Cargo.toml index 4964df47..6480a727 100644 --- a/16_virtual_mem_part4_higher_half_kernel/Cargo.toml +++ b/16_virtual_mem_part4_higher_half_kernel/Cargo.toml @@ -1,60 +1,9 @@ -[package] -name = "mingo" -version = "0.16.0" -authors = ["Andre Richter "] -edition = "2021" +[workspace] + +members = [ + "libraries/*", + "kernel" +] [profile.release] lto = true - -[features] -default = [] -bsp_rpi3 = ["tock-registers"] -bsp_rpi4 = ["tock-registers"] -test_build = ["qemu-exit"] - -##-------------------------------------------------------------------------------------------------- -## Dependencies -##-------------------------------------------------------------------------------------------------- - -[dependencies] -test-types = { path = "test-types" } - -# Optional dependencies -tock-registers = { version = "0.7.x", default-features = false, features = ["register_types"], optional = true } -qemu-exit = { version = "3.x.x", optional = true } - -# Platform specific dependencies -[target.'cfg(target_arch = "aarch64")'.dependencies] -cortex-a = { version = "7.x.x" } - -##-------------------------------------------------------------------------------------------------- -## Testing -##-------------------------------------------------------------------------------------------------- - -[dev-dependencies] -test-macros = { path = "test-macros" } - -# Unit tests are done in the library part of the kernel. -[lib] -name = "libkernel" -test = true - -# Disable unit tests for the kernel binary. -[[bin]] -name = "kernel" -path = "src/main.rs" -test = false - -# List of tests without harness. -[[test]] -name = "00_console_sanity" -harness = false - -[[test]] -name = "02_exception_sync_page_fault" -harness = false - -[[test]] -name = "03_exception_restore_sanity" -harness = false diff --git a/16_virtual_mem_part4_higher_half_kernel/Makefile b/16_virtual_mem_part4_higher_half_kernel/Makefile index a695185d..81de6005 100644 --- a/16_virtual_mem_part4_higher_half_kernel/Makefile +++ b/16_virtual_mem_part4_higher_half_kernel/Makefile @@ -41,7 +41,7 @@ ifeq ($(BSP),rpi3) READELF_BINARY = aarch64-none-elf-readelf OPENOCD_ARG = -f /openocd/tcl/interface/ftdi/olimex-arm-usb-tiny-h.cfg -f /openocd/rpi3.cfg JTAG_BOOT_IMAGE = ../X1_JTAG_boot/jtag_boot_rpi3.img - LD_SCRIPT_PATH = $(shell pwd)/src/bsp/raspberrypi + LD_SCRIPT_PATH = $(shell pwd)/kernel/src/bsp/raspberrypi RUSTC_MISC_ARGS = -C target-cpu=cortex-a53 else ifeq ($(BSP),rpi4) TARGET = aarch64-unknown-none-softfloat @@ -55,7 +55,7 @@ else ifeq ($(BSP),rpi4) READELF_BINARY = aarch64-none-elf-readelf OPENOCD_ARG = -f /openocd/tcl/interface/ftdi/olimex-arm-usb-tiny-h.cfg -f /openocd/rpi4.cfg JTAG_BOOT_IMAGE = ../X1_JTAG_boot/jtag_boot_rpi4.img - LD_SCRIPT_PATH = $(shell pwd)/src/bsp/raspberrypi + LD_SCRIPT_PATH = $(shell pwd)/kernel/src/bsp/raspberrypi RUSTC_MISC_ARGS = -C target-cpu=cortex-a72 endif @@ -67,11 +67,11 @@ export LD_SCRIPT_PATH ##-------------------------------------------------------------------------------------------------- ## Targets and Prerequisites ##-------------------------------------------------------------------------------------------------- +KERNEL_MANIFEST = kernel/Cargo.toml KERNEL_LINKER_SCRIPT = kernel.ld +LAST_BUILD_CONFIG = target/$(BSP).build_config -TT_TOOL_PATH = translation_table_tool - -LAST_BUILD_CONFIG = target/$(BSP).build_config +TT_TOOL_PATH = tools/translation_table_tool KERNEL_ELF_RAW = target/$(TARGET)/release/kernel # This parses cargo's dep-info file. @@ -101,11 +101,11 @@ COMPILER_ARGS = --target=$(TARGET) \ $(FEATURES) \ --release -RUSTC_CMD = cargo rustc $(COMPILER_ARGS) +RUSTC_CMD = cargo rustc $(COMPILER_ARGS) --manifest-path $(KERNEL_MANIFEST) DOC_CMD = cargo doc $(COMPILER_ARGS) CLIPPY_CMD = cargo clippy $(COMPILER_ARGS) CHECK_CMD = cargo check $(COMPILER_ARGS) -TEST_CMD = cargo test $(COMPILER_ARGS) +TEST_CMD = cargo test $(COMPILER_ARGS) --manifest-path $(KERNEL_MANIFEST) OBJCOPY_CMD = rust-objcopy \ --strip-all \ -O binary @@ -219,6 +219,8 @@ chainboot: $(KERNEL_BIN) ##------------------------------------------------------------------------------ clippy: @RUSTFLAGS="$(RUSTFLAGS_PEDANTIC)" $(CLIPPY_CMD) + @RUSTFLAGS="$(RUSTFLAGS_PEDANTIC)" $(CLIPPY_CMD) --features test_build --tests \ + --manifest-path $(KERNEL_MANIFEST) ##------------------------------------------------------------------------------ ## Clean @@ -315,6 +317,10 @@ test_boot: $(KERNEL_BIN) define KERNEL_TEST_RUNNER #!/usr/bin/env bash + # The cargo test runner seems to change into the crate under test's directory. Therefore, ensure + # this script executes from the root. + cd $(shell pwd) + TEST_ELF=$$(echo $$1 | sed -e 's/.*target/target/g') TEST_BINARY=$$(echo $$1.img | sed -e 's/.*target/target/g') diff --git a/16_virtual_mem_part4_higher_half_kernel/README.md b/16_virtual_mem_part4_higher_half_kernel/README.md index 0c45e3ec..89f650a3 100644 --- a/16_virtual_mem_part4_higher_half_kernel/README.md +++ b/16_virtual_mem_part4_higher_half_kernel/README.md @@ -78,8 +78,8 @@ type KernelTranslationTable = ### Linking Changes -In the `link.ld` linker script, we define a new symbol `__kernel_virt_start_addr` now, which is the -start address of the kernel's virtual address space, calculated as `(u64::MAX - +In the `kernel.ld` linker script, we define a new symbol `__kernel_virt_start_addr` now, which is +the start address of the kernel's virtual address space, calculated as `(u64::MAX - __kernel_virt_addr_space_size) + 1`. Before the first section definition, we set the linker script's location counter to this address: @@ -325,9 +325,9 @@ Minipush 1.0 ## Diff to previous ```diff -diff -uNr 15_virtual_mem_part3_precomputed_tables/Cargo.toml 16_virtual_mem_part4_higher_half_kernel/Cargo.toml ---- 15_virtual_mem_part3_precomputed_tables/Cargo.toml -+++ 16_virtual_mem_part4_higher_half_kernel/Cargo.toml +diff -uNr 15_virtual_mem_part3_precomputed_tables/kernel/Cargo.toml 16_virtual_mem_part4_higher_half_kernel/kernel/Cargo.toml +--- 15_virtual_mem_part3_precomputed_tables/kernel/Cargo.toml ++++ 16_virtual_mem_part4_higher_half_kernel/kernel/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mingo" @@ -337,9 +337,9 @@ diff -uNr 15_virtual_mem_part3_precomputed_tables/Cargo.toml 16_virtual_mem_part edition = "2021" -diff -uNr 15_virtual_mem_part3_precomputed_tables/src/_arch/aarch64/cpu/boot.rs 16_virtual_mem_part4_higher_half_kernel/src/_arch/aarch64/cpu/boot.rs ---- 15_virtual_mem_part3_precomputed_tables/src/_arch/aarch64/cpu/boot.rs -+++ 16_virtual_mem_part4_higher_half_kernel/src/_arch/aarch64/cpu/boot.rs +diff -uNr 15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/cpu/boot.rs 16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/cpu/boot.rs +--- 15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/cpu/boot.rs ++++ 16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/cpu/boot.rs @@ -30,7 +30,10 @@ /// - The `bss` section is not initialized yet. The code must not use or reference it in any way. /// - The HW state of EL1 must be prepared in a sound way. @@ -390,9 +390,9 @@ diff -uNr 15_virtual_mem_part3_precomputed_tables/src/_arch/aarch64/cpu/boot.rs asm::eret() } -diff -uNr 15_virtual_mem_part3_precomputed_tables/src/_arch/aarch64/cpu/boot.s 16_virtual_mem_part4_higher_half_kernel/src/_arch/aarch64/cpu/boot.s ---- 15_virtual_mem_part3_precomputed_tables/src/_arch/aarch64/cpu/boot.s -+++ 16_virtual_mem_part4_higher_half_kernel/src/_arch/aarch64/cpu/boot.s +diff -uNr 15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/cpu/boot.s 16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/cpu/boot.s +--- 15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/cpu/boot.s ++++ 16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/cpu/boot.s @@ -18,6 +18,18 @@ add \register, \register, #:lo12:\symbol .endm @@ -441,9 +441,9 @@ diff -uNr 15_virtual_mem_part3_precomputed_tables/src/_arch/aarch64/cpu/boot.s 1 // Infinitely wait for events (aka "park the core"). -diff -uNr 15_virtual_mem_part3_precomputed_tables/src/_arch/aarch64/memory/mmu/translation_table.rs 16_virtual_mem_part4_higher_half_kernel/src/_arch/aarch64/memory/mmu/translation_table.rs ---- 15_virtual_mem_part3_precomputed_tables/src/_arch/aarch64/memory/mmu/translation_table.rs -+++ 16_virtual_mem_part4_higher_half_kernel/src/_arch/aarch64/memory/mmu/translation_table.rs +diff -uNr 15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/memory/mmu/translation_table.rs 16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/memory/mmu/translation_table.rs +--- 15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/memory/mmu/translation_table.rs ++++ 16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/memory/mmu/translation_table.rs @@ -136,7 +136,7 @@ /// aligned, so the lvl3 is put first. #[repr(C)] @@ -515,9 +515,9 @@ diff -uNr 15_virtual_mem_part3_precomputed_tables/src/_arch/aarch64/memory/mmu/t #[cfg(test)] mod tests { -diff -uNr 15_virtual_mem_part3_precomputed_tables/src/_arch/aarch64/memory/mmu.rs 16_virtual_mem_part4_higher_half_kernel/src/_arch/aarch64/memory/mmu.rs ---- 15_virtual_mem_part3_precomputed_tables/src/_arch/aarch64/memory/mmu.rs -+++ 16_virtual_mem_part4_higher_half_kernel/src/_arch/aarch64/memory/mmu.rs +diff -uNr 15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/memory/mmu.rs 16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/memory/mmu.rs +--- 15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/memory/mmu.rs ++++ 16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/memory/mmu.rs @@ -66,6 +66,7 @@ impl MemoryManagementUnit { @@ -568,9 +568,9 @@ diff -uNr 15_virtual_mem_part3_precomputed_tables/src/_arch/aarch64/memory/mmu.r self.configure_translation_control(); -diff -uNr 15_virtual_mem_part3_precomputed_tables/src/bsp/raspberrypi/console.rs 16_virtual_mem_part4_higher_half_kernel/src/bsp/raspberrypi/console.rs ---- 15_virtual_mem_part3_precomputed_tables/src/bsp/raspberrypi/console.rs -+++ 16_virtual_mem_part4_higher_half_kernel/src/bsp/raspberrypi/console.rs +diff -uNr 15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/console.rs 16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi/console.rs +--- 15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/console.rs ++++ 16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi/console.rs @@ -4,7 +4,6 @@ //! BSP console facilities. @@ -638,9 +638,9 @@ diff -uNr 15_virtual_mem_part3_precomputed_tables/src/bsp/raspberrypi/console.rs panic_uart -diff -uNr 15_virtual_mem_part3_precomputed_tables/src/bsp/raspberrypi/kernel.ld 16_virtual_mem_part4_higher_half_kernel/src/bsp/raspberrypi/kernel.ld ---- 15_virtual_mem_part3_precomputed_tables/src/bsp/raspberrypi/kernel.ld -+++ 16_virtual_mem_part4_higher_half_kernel/src/bsp/raspberrypi/kernel.ld +diff -uNr 15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/kernel.ld 16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi/kernel.ld +--- 15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/kernel.ld ++++ 16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi/kernel.ld @@ -8,6 +8,13 @@ PAGE_SIZE = 64K; PAGE_MASK = PAGE_SIZE - 1; @@ -719,9 +719,9 @@ diff -uNr 15_virtual_mem_part3_precomputed_tables/src/bsp/raspberrypi/kernel.ld + ASSERT((. & PAGE_MASK) == 0, "End of boot core stack is not page aligned") } -diff -uNr 15_virtual_mem_part3_precomputed_tables/src/bsp/raspberrypi/memory/mmu.rs 16_virtual_mem_part4_higher_half_kernel/src/bsp/raspberrypi/memory/mmu.rs ---- 15_virtual_mem_part3_precomputed_tables/src/bsp/raspberrypi/memory/mmu.rs -+++ 16_virtual_mem_part4_higher_half_kernel/src/bsp/raspberrypi/memory/mmu.rs +diff -uNr 15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/memory/mmu.rs 16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi/memory/mmu.rs +--- 15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/memory/mmu.rs ++++ 16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi/memory/mmu.rs @@ -20,7 +20,7 @@ //-------------------------------------------------------------------------------------------------- @@ -760,9 +760,9 @@ diff -uNr 15_virtual_mem_part3_precomputed_tables/src/bsp/raspberrypi/memory/mmu + ); } -diff -uNr 15_virtual_mem_part3_precomputed_tables/src/bsp/raspberrypi/memory.rs 16_virtual_mem_part4_higher_half_kernel/src/bsp/raspberrypi/memory.rs ---- 15_virtual_mem_part3_precomputed_tables/src/bsp/raspberrypi/memory.rs -+++ 16_virtual_mem_part4_higher_half_kernel/src/bsp/raspberrypi/memory.rs +diff -uNr 15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/memory.rs 16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi/memory.rs +--- 15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/memory.rs ++++ 16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi/memory.rs @@ -37,13 +37,7 @@ //! The virtual memory layout is as follows: //! @@ -796,9 +796,9 @@ diff -uNr 15_virtual_mem_part3_precomputed_tables/src/bsp/raspberrypi/memory.rs pub mod mmu; -diff -uNr 15_virtual_mem_part3_precomputed_tables/src/lib.rs 16_virtual_mem_part4_higher_half_kernel/src/lib.rs ---- 15_virtual_mem_part3_precomputed_tables/src/lib.rs -+++ 16_virtual_mem_part4_higher_half_kernel/src/lib.rs +diff -uNr 15_virtual_mem_part3_precomputed_tables/kernel/src/lib.rs 16_virtual_mem_part4_higher_half_kernel/kernel/src/lib.rs +--- 15_virtual_mem_part3_precomputed_tables/kernel/src/lib.rs ++++ 16_virtual_mem_part4_higher_half_kernel/kernel/src/lib.rs @@ -150,11 +150,6 @@ ) } @@ -812,9 +812,9 @@ diff -uNr 15_virtual_mem_part3_precomputed_tables/src/lib.rs 16_virtual_mem_part // Testing //-------------------------------------------------------------------------------------------------- -diff -uNr 15_virtual_mem_part3_precomputed_tables/src/memory/mmu/translation_table.rs 16_virtual_mem_part4_higher_half_kernel/src/memory/mmu/translation_table.rs ---- 15_virtual_mem_part3_precomputed_tables/src/memory/mmu/translation_table.rs -+++ 16_virtual_mem_part4_higher_half_kernel/src/memory/mmu/translation_table.rs +diff -uNr 15_virtual_mem_part3_precomputed_tables/kernel/src/memory/mmu/translation_table.rs 16_virtual_mem_part4_higher_half_kernel/kernel/src/memory/mmu/translation_table.rs +--- 15_virtual_mem_part3_precomputed_tables/kernel/src/memory/mmu/translation_table.rs ++++ 16_virtual_mem_part4_higher_half_kernel/kernel/src/memory/mmu/translation_table.rs @@ -99,9 +99,9 @@ assert!(tables.init().is_ok()); @@ -838,9 +838,9 @@ diff -uNr 15_virtual_mem_part3_precomputed_tables/src/memory/mmu/translation_tab ); -diff -uNr 15_virtual_mem_part3_precomputed_tables/src/memory/mmu/types.rs 16_virtual_mem_part4_higher_half_kernel/src/memory/mmu/types.rs ---- 15_virtual_mem_part3_precomputed_tables/src/memory/mmu/types.rs -+++ 16_virtual_mem_part4_higher_half_kernel/src/memory/mmu/types.rs +diff -uNr 15_virtual_mem_part3_precomputed_tables/kernel/src/memory/mmu/types.rs 16_virtual_mem_part4_higher_half_kernel/kernel/src/memory/mmu/types.rs +--- 15_virtual_mem_part3_precomputed_tables/kernel/src/memory/mmu/types.rs ++++ 16_virtual_mem_part4_higher_half_kernel/kernel/src/memory/mmu/types.rs @@ -67,6 +67,11 @@ // PageAddress //------------------------------------------------------------------------------ @@ -854,9 +854,9 @@ diff -uNr 15_virtual_mem_part3_precomputed_tables/src/memory/mmu/types.rs 16_vir pub fn into_inner(self) -> Address { self.inner -diff -uNr 15_virtual_mem_part3_precomputed_tables/src/memory/mmu.rs 16_virtual_mem_part4_higher_half_kernel/src/memory/mmu.rs ---- 15_virtual_mem_part3_precomputed_tables/src/memory/mmu.rs -+++ 16_virtual_mem_part4_higher_half_kernel/src/memory/mmu.rs +diff -uNr 15_virtual_mem_part3_precomputed_tables/kernel/src/memory/mmu.rs 16_virtual_mem_part4_higher_half_kernel/kernel/src/memory/mmu.rs +--- 15_virtual_mem_part3_precomputed_tables/kernel/src/memory/mmu.rs ++++ 16_virtual_mem_part4_higher_half_kernel/kernel/src/memory/mmu.rs @@ -66,6 +66,11 @@ pub trait AssociatedTranslationTable { /// A translation table whose address range is: @@ -870,9 +870,9 @@ diff -uNr 15_virtual_mem_part3_precomputed_tables/src/memory/mmu.rs 16_virtual_m type TableStartFromBottom; } -diff -uNr 15_virtual_mem_part3_precomputed_tables/tests/02_exception_sync_page_fault.rs 16_virtual_mem_part4_higher_half_kernel/tests/02_exception_sync_page_fault.rs ---- 15_virtual_mem_part3_precomputed_tables/tests/02_exception_sync_page_fault.rs -+++ 16_virtual_mem_part4_higher_half_kernel/tests/02_exception_sync_page_fault.rs +diff -uNr 15_virtual_mem_part3_precomputed_tables/kernel/tests/02_exception_sync_page_fault.rs 16_virtual_mem_part4_higher_half_kernel/kernel/tests/02_exception_sync_page_fault.rs +--- 15_virtual_mem_part3_precomputed_tables/kernel/tests/02_exception_sync_page_fault.rs ++++ 16_virtual_mem_part4_higher_half_kernel/kernel/tests/02_exception_sync_page_fault.rs @@ -28,8 +28,8 @@ // This line will be printed as the test header. println!("Testing synchronous exception handling by causing a page fault"); @@ -885,9 +885,9 @@ diff -uNr 15_virtual_mem_part3_precomputed_tables/tests/02_exception_sync_page_f // If execution reaches here, the memory access above did not cause a page fault exception. -diff -uNr 15_virtual_mem_part3_precomputed_tables/translation_table_tool/arch.rb 16_virtual_mem_part4_higher_half_kernel/translation_table_tool/arch.rb ---- 15_virtual_mem_part3_precomputed_tables/translation_table_tool/arch.rb -+++ 16_virtual_mem_part4_higher_half_kernel/translation_table_tool/arch.rb +diff -uNr 15_virtual_mem_part3_precomputed_tables/tools/translation_table_tool/arch.rb 16_virtual_mem_part4_higher_half_kernel/tools/translation_table_tool/arch.rb +--- 15_virtual_mem_part3_precomputed_tables/tools/translation_table_tool/arch.rb ++++ 16_virtual_mem_part4_higher_half_kernel/tools/translation_table_tool/arch.rb @@ -255,6 +255,8 @@ end @@ -898,9 +898,9 @@ diff -uNr 15_virtual_mem_part3_precomputed_tables/translation_table_tool/arch.rb lvl3_index = (addr & Granule512MiB::MASK) >> Granule64KiB::SHIFT -diff -uNr 15_virtual_mem_part3_precomputed_tables/translation_table_tool/bsp.rb 16_virtual_mem_part4_higher_half_kernel/translation_table_tool/bsp.rb ---- 15_virtual_mem_part3_precomputed_tables/translation_table_tool/bsp.rb -+++ 16_virtual_mem_part4_higher_half_kernel/translation_table_tool/bsp.rb +diff -uNr 15_virtual_mem_part3_precomputed_tables/tools/translation_table_tool/bsp.rb 16_virtual_mem_part4_higher_half_kernel/tools/translation_table_tool/bsp.rb +--- 15_virtual_mem_part3_precomputed_tables/tools/translation_table_tool/bsp.rb ++++ 16_virtual_mem_part4_higher_half_kernel/tools/translation_table_tool/bsp.rb @@ -6,7 +6,7 @@ # Raspberry Pi 3 + 4 @@ -908,7 +908,7 @@ diff -uNr 15_virtual_mem_part3_precomputed_tables/translation_table_tool/bsp.rb - attr_reader :kernel_granule, :kernel_virt_addr_space_size + attr_reader :kernel_granule, :kernel_virt_addr_space_size, :kernel_virt_start_addr - MEMORY_SRC = File.read('src/bsp/raspberrypi/memory.rs').split("\n") + MEMORY_SRC = File.read('kernel/src/bsp/raspberrypi/memory.rs').split("\n") @@ -14,6 +14,7 @@ @kernel_granule = Granule64KiB diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/Cargo.toml b/16_virtual_mem_part4_higher_half_kernel/kernel/Cargo.toml new file mode 100644 index 00000000..d58c2f09 --- /dev/null +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/Cargo.toml @@ -0,0 +1,58 @@ +[package] +name = "mingo" +version = "0.16.0" +authors = ["Andre Richter "] +edition = "2021" + + +[features] +default = [] +bsp_rpi3 = ["tock-registers"] +bsp_rpi4 = ["tock-registers"] +test_build = ["qemu-exit"] + +##-------------------------------------------------------------------------------------------------- +## Dependencies +##-------------------------------------------------------------------------------------------------- + +[dependencies] +test-types = { path = "../libraries/test-types" } + +# Optional dependencies +tock-registers = { version = "0.7.x", default-features = false, features = ["register_types"], optional = true } +qemu-exit = { version = "3.x.x", optional = true } + +# Platform specific dependencies +[target.'cfg(target_arch = "aarch64")'.dependencies] +cortex-a = { version = "7.x.x" } + +##-------------------------------------------------------------------------------------------------- +## Testing +##-------------------------------------------------------------------------------------------------- + +[dev-dependencies] +test-macros = { path = "../libraries/test-macros" } + +# Unit tests are done in the library part of the kernel. +[lib] +name = "libkernel" +test = true + +# Disable unit tests for the kernel binary. +[[bin]] +name = "kernel" +path = "src/main.rs" +test = false + +# List of tests without harness. +[[test]] +name = "00_console_sanity" +harness = false + +[[test]] +name = "02_exception_sync_page_fault" +harness = false + +[[test]] +name = "03_exception_restore_sanity" +harness = false diff --git a/16_virtual_mem_part4_higher_half_kernel/build.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/build.rs similarity index 100% rename from 16_virtual_mem_part4_higher_half_kernel/build.rs rename to 16_virtual_mem_part4_higher_half_kernel/kernel/build.rs diff --git a/16_virtual_mem_part4_higher_half_kernel/src/_arch/aarch64/cpu.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/cpu.rs similarity index 100% rename from 16_virtual_mem_part4_higher_half_kernel/src/_arch/aarch64/cpu.rs rename to 16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/cpu.rs diff --git a/16_virtual_mem_part4_higher_half_kernel/src/_arch/aarch64/cpu/boot.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/cpu/boot.rs similarity index 100% rename from 16_virtual_mem_part4_higher_half_kernel/src/_arch/aarch64/cpu/boot.rs rename to 16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/cpu/boot.rs diff --git a/16_virtual_mem_part4_higher_half_kernel/src/_arch/aarch64/cpu/boot.s b/16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/cpu/boot.s similarity index 100% rename from 16_virtual_mem_part4_higher_half_kernel/src/_arch/aarch64/cpu/boot.s rename to 16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/cpu/boot.s diff --git a/16_virtual_mem_part4_higher_half_kernel/src/_arch/aarch64/cpu/smp.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/cpu/smp.rs similarity index 100% rename from 16_virtual_mem_part4_higher_half_kernel/src/_arch/aarch64/cpu/smp.rs rename to 16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/cpu/smp.rs diff --git a/16_virtual_mem_part4_higher_half_kernel/src/_arch/aarch64/exception.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/exception.rs similarity index 100% rename from 16_virtual_mem_part4_higher_half_kernel/src/_arch/aarch64/exception.rs rename to 16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/exception.rs diff --git a/16_virtual_mem_part4_higher_half_kernel/src/_arch/aarch64/exception.s b/16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/exception.s similarity index 100% rename from 16_virtual_mem_part4_higher_half_kernel/src/_arch/aarch64/exception.s rename to 16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/exception.s diff --git a/16_virtual_mem_part4_higher_half_kernel/src/_arch/aarch64/exception/asynchronous.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/exception/asynchronous.rs similarity index 100% rename from 16_virtual_mem_part4_higher_half_kernel/src/_arch/aarch64/exception/asynchronous.rs rename to 16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/exception/asynchronous.rs diff --git a/16_virtual_mem_part4_higher_half_kernel/src/_arch/aarch64/memory/mmu.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/memory/mmu.rs similarity index 100% rename from 16_virtual_mem_part4_higher_half_kernel/src/_arch/aarch64/memory/mmu.rs rename to 16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/memory/mmu.rs diff --git a/16_virtual_mem_part4_higher_half_kernel/src/_arch/aarch64/memory/mmu/translation_table.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/memory/mmu/translation_table.rs similarity index 100% rename from 16_virtual_mem_part4_higher_half_kernel/src/_arch/aarch64/memory/mmu/translation_table.rs rename to 16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/memory/mmu/translation_table.rs diff --git a/16_virtual_mem_part4_higher_half_kernel/src/_arch/aarch64/time.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/time.rs similarity index 100% rename from 16_virtual_mem_part4_higher_half_kernel/src/_arch/aarch64/time.rs rename to 16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/time.rs diff --git a/16_virtual_mem_part4_higher_half_kernel/src/bsp.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp.rs similarity index 100% rename from 16_virtual_mem_part4_higher_half_kernel/src/bsp.rs rename to 16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp.rs diff --git a/16_virtual_mem_part4_higher_half_kernel/src/bsp/device_driver.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver.rs similarity index 100% rename from 16_virtual_mem_part4_higher_half_kernel/src/bsp/device_driver.rs rename to 16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver.rs diff --git a/16_virtual_mem_part4_higher_half_kernel/src/bsp/device_driver/arm.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/arm.rs similarity index 100% rename from 16_virtual_mem_part4_higher_half_kernel/src/bsp/device_driver/arm.rs rename to 16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/arm.rs diff --git a/16_virtual_mem_part4_higher_half_kernel/src/bsp/device_driver/arm/gicv2.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/arm/gicv2.rs similarity index 100% rename from 16_virtual_mem_part4_higher_half_kernel/src/bsp/device_driver/arm/gicv2.rs rename to 16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/arm/gicv2.rs diff --git a/16_virtual_mem_part4_higher_half_kernel/src/bsp/device_driver/arm/gicv2/gicc.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/arm/gicv2/gicc.rs similarity index 100% rename from 16_virtual_mem_part4_higher_half_kernel/src/bsp/device_driver/arm/gicv2/gicc.rs rename to 16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/arm/gicv2/gicc.rs diff --git a/16_virtual_mem_part4_higher_half_kernel/src/bsp/device_driver/arm/gicv2/gicd.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs similarity index 100% rename from 16_virtual_mem_part4_higher_half_kernel/src/bsp/device_driver/arm/gicv2/gicd.rs rename to 16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs diff --git a/16_virtual_mem_part4_higher_half_kernel/src/bsp/device_driver/bcm.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/bcm.rs similarity index 100% rename from 16_virtual_mem_part4_higher_half_kernel/src/bsp/device_driver/bcm.rs rename to 16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/bcm.rs diff --git a/16_virtual_mem_part4_higher_half_kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs similarity index 100% rename from 16_virtual_mem_part4_higher_half_kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs rename to 16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs diff --git a/16_virtual_mem_part4_higher_half_kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs similarity index 100% rename from 16_virtual_mem_part4_higher_half_kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs rename to 16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs diff --git a/16_virtual_mem_part4_higher_half_kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs similarity index 100% rename from 16_virtual_mem_part4_higher_half_kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs rename to 16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs diff --git a/16_virtual_mem_part4_higher_half_kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs similarity index 100% rename from 16_virtual_mem_part4_higher_half_kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs rename to 16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs diff --git a/16_virtual_mem_part4_higher_half_kernel/src/bsp/device_driver/common.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/common.rs similarity index 100% rename from 16_virtual_mem_part4_higher_half_kernel/src/bsp/device_driver/common.rs rename to 16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/common.rs diff --git a/16_virtual_mem_part4_higher_half_kernel/src/bsp/raspberrypi.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi.rs similarity index 100% rename from 16_virtual_mem_part4_higher_half_kernel/src/bsp/raspberrypi.rs rename to 16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi.rs diff --git a/16_virtual_mem_part4_higher_half_kernel/src/bsp/raspberrypi/console.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi/console.rs similarity index 100% rename from 16_virtual_mem_part4_higher_half_kernel/src/bsp/raspberrypi/console.rs rename to 16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi/console.rs diff --git a/16_virtual_mem_part4_higher_half_kernel/src/bsp/raspberrypi/cpu.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi/cpu.rs similarity index 100% rename from 16_virtual_mem_part4_higher_half_kernel/src/bsp/raspberrypi/cpu.rs rename to 16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi/cpu.rs diff --git a/16_virtual_mem_part4_higher_half_kernel/src/bsp/raspberrypi/driver.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi/driver.rs similarity index 100% rename from 16_virtual_mem_part4_higher_half_kernel/src/bsp/raspberrypi/driver.rs rename to 16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi/driver.rs diff --git a/16_virtual_mem_part4_higher_half_kernel/src/bsp/raspberrypi/exception.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi/exception.rs similarity index 100% rename from 16_virtual_mem_part4_higher_half_kernel/src/bsp/raspberrypi/exception.rs rename to 16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi/exception.rs diff --git a/16_virtual_mem_part4_higher_half_kernel/src/bsp/raspberrypi/exception/asynchronous.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi/exception/asynchronous.rs similarity index 100% rename from 16_virtual_mem_part4_higher_half_kernel/src/bsp/raspberrypi/exception/asynchronous.rs rename to 16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi/exception/asynchronous.rs diff --git a/16_virtual_mem_part4_higher_half_kernel/src/bsp/raspberrypi/kernel.ld b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi/kernel.ld similarity index 100% rename from 16_virtual_mem_part4_higher_half_kernel/src/bsp/raspberrypi/kernel.ld rename to 16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi/kernel.ld diff --git a/16_virtual_mem_part4_higher_half_kernel/src/bsp/raspberrypi/kernel_virt_addr_space_size.ld b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi/kernel_virt_addr_space_size.ld similarity index 100% rename from 16_virtual_mem_part4_higher_half_kernel/src/bsp/raspberrypi/kernel_virt_addr_space_size.ld rename to 16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi/kernel_virt_addr_space_size.ld diff --git a/16_virtual_mem_part4_higher_half_kernel/src/bsp/raspberrypi/memory.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi/memory.rs similarity index 100% rename from 16_virtual_mem_part4_higher_half_kernel/src/bsp/raspberrypi/memory.rs rename to 16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi/memory.rs diff --git a/16_virtual_mem_part4_higher_half_kernel/src/bsp/raspberrypi/memory/mmu.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi/memory/mmu.rs similarity index 100% rename from 16_virtual_mem_part4_higher_half_kernel/src/bsp/raspberrypi/memory/mmu.rs rename to 16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi/memory/mmu.rs diff --git a/16_virtual_mem_part4_higher_half_kernel/src/common.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/common.rs similarity index 100% rename from 16_virtual_mem_part4_higher_half_kernel/src/common.rs rename to 16_virtual_mem_part4_higher_half_kernel/kernel/src/common.rs diff --git a/16_virtual_mem_part4_higher_half_kernel/src/console.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/console.rs similarity index 100% rename from 16_virtual_mem_part4_higher_half_kernel/src/console.rs rename to 16_virtual_mem_part4_higher_half_kernel/kernel/src/console.rs diff --git a/16_virtual_mem_part4_higher_half_kernel/src/cpu.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/cpu.rs similarity index 100% rename from 16_virtual_mem_part4_higher_half_kernel/src/cpu.rs rename to 16_virtual_mem_part4_higher_half_kernel/kernel/src/cpu.rs diff --git a/16_virtual_mem_part4_higher_half_kernel/src/cpu/boot.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/cpu/boot.rs similarity index 100% rename from 16_virtual_mem_part4_higher_half_kernel/src/cpu/boot.rs rename to 16_virtual_mem_part4_higher_half_kernel/kernel/src/cpu/boot.rs diff --git a/16_virtual_mem_part4_higher_half_kernel/src/cpu/smp.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/cpu/smp.rs similarity index 100% rename from 16_virtual_mem_part4_higher_half_kernel/src/cpu/smp.rs rename to 16_virtual_mem_part4_higher_half_kernel/kernel/src/cpu/smp.rs diff --git a/16_virtual_mem_part4_higher_half_kernel/src/driver.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/driver.rs similarity index 100% rename from 16_virtual_mem_part4_higher_half_kernel/src/driver.rs rename to 16_virtual_mem_part4_higher_half_kernel/kernel/src/driver.rs diff --git a/16_virtual_mem_part4_higher_half_kernel/src/exception.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/exception.rs similarity index 100% rename from 16_virtual_mem_part4_higher_half_kernel/src/exception.rs rename to 16_virtual_mem_part4_higher_half_kernel/kernel/src/exception.rs diff --git a/16_virtual_mem_part4_higher_half_kernel/src/exception/asynchronous.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/exception/asynchronous.rs similarity index 100% rename from 16_virtual_mem_part4_higher_half_kernel/src/exception/asynchronous.rs rename to 16_virtual_mem_part4_higher_half_kernel/kernel/src/exception/asynchronous.rs diff --git a/16_virtual_mem_part4_higher_half_kernel/src/lib.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/lib.rs similarity index 100% rename from 16_virtual_mem_part4_higher_half_kernel/src/lib.rs rename to 16_virtual_mem_part4_higher_half_kernel/kernel/src/lib.rs diff --git a/16_virtual_mem_part4_higher_half_kernel/src/main.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/main.rs similarity index 100% rename from 16_virtual_mem_part4_higher_half_kernel/src/main.rs rename to 16_virtual_mem_part4_higher_half_kernel/kernel/src/main.rs diff --git a/16_virtual_mem_part4_higher_half_kernel/src/memory.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/memory.rs similarity index 100% rename from 16_virtual_mem_part4_higher_half_kernel/src/memory.rs rename to 16_virtual_mem_part4_higher_half_kernel/kernel/src/memory.rs diff --git a/16_virtual_mem_part4_higher_half_kernel/src/memory/mmu.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/memory/mmu.rs similarity index 100% rename from 16_virtual_mem_part4_higher_half_kernel/src/memory/mmu.rs rename to 16_virtual_mem_part4_higher_half_kernel/kernel/src/memory/mmu.rs diff --git a/16_virtual_mem_part4_higher_half_kernel/src/memory/mmu/alloc.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/memory/mmu/alloc.rs similarity index 100% rename from 16_virtual_mem_part4_higher_half_kernel/src/memory/mmu/alloc.rs rename to 16_virtual_mem_part4_higher_half_kernel/kernel/src/memory/mmu/alloc.rs diff --git a/16_virtual_mem_part4_higher_half_kernel/src/memory/mmu/mapping_record.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/memory/mmu/mapping_record.rs similarity index 100% rename from 16_virtual_mem_part4_higher_half_kernel/src/memory/mmu/mapping_record.rs rename to 16_virtual_mem_part4_higher_half_kernel/kernel/src/memory/mmu/mapping_record.rs diff --git a/16_virtual_mem_part4_higher_half_kernel/src/memory/mmu/translation_table.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/memory/mmu/translation_table.rs similarity index 100% rename from 16_virtual_mem_part4_higher_half_kernel/src/memory/mmu/translation_table.rs rename to 16_virtual_mem_part4_higher_half_kernel/kernel/src/memory/mmu/translation_table.rs diff --git a/16_virtual_mem_part4_higher_half_kernel/src/memory/mmu/types.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/memory/mmu/types.rs similarity index 100% rename from 16_virtual_mem_part4_higher_half_kernel/src/memory/mmu/types.rs rename to 16_virtual_mem_part4_higher_half_kernel/kernel/src/memory/mmu/types.rs diff --git a/16_virtual_mem_part4_higher_half_kernel/src/panic_wait.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/panic_wait.rs similarity index 100% rename from 16_virtual_mem_part4_higher_half_kernel/src/panic_wait.rs rename to 16_virtual_mem_part4_higher_half_kernel/kernel/src/panic_wait.rs diff --git a/16_virtual_mem_part4_higher_half_kernel/src/print.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/print.rs similarity index 100% rename from 16_virtual_mem_part4_higher_half_kernel/src/print.rs rename to 16_virtual_mem_part4_higher_half_kernel/kernel/src/print.rs diff --git a/16_virtual_mem_part4_higher_half_kernel/src/state.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/state.rs similarity index 100% rename from 16_virtual_mem_part4_higher_half_kernel/src/state.rs rename to 16_virtual_mem_part4_higher_half_kernel/kernel/src/state.rs diff --git a/16_virtual_mem_part4_higher_half_kernel/src/synchronization.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/synchronization.rs similarity index 100% rename from 16_virtual_mem_part4_higher_half_kernel/src/synchronization.rs rename to 16_virtual_mem_part4_higher_half_kernel/kernel/src/synchronization.rs diff --git a/16_virtual_mem_part4_higher_half_kernel/src/time.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/time.rs similarity index 100% rename from 16_virtual_mem_part4_higher_half_kernel/src/time.rs rename to 16_virtual_mem_part4_higher_half_kernel/kernel/src/time.rs diff --git a/16_virtual_mem_part4_higher_half_kernel/tests/00_console_sanity.rb b/16_virtual_mem_part4_higher_half_kernel/kernel/tests/00_console_sanity.rb similarity index 100% rename from 16_virtual_mem_part4_higher_half_kernel/tests/00_console_sanity.rb rename to 16_virtual_mem_part4_higher_half_kernel/kernel/tests/00_console_sanity.rb diff --git a/16_virtual_mem_part4_higher_half_kernel/tests/00_console_sanity.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/tests/00_console_sanity.rs similarity index 100% rename from 16_virtual_mem_part4_higher_half_kernel/tests/00_console_sanity.rs rename to 16_virtual_mem_part4_higher_half_kernel/kernel/tests/00_console_sanity.rs diff --git a/16_virtual_mem_part4_higher_half_kernel/tests/01_timer_sanity.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/tests/01_timer_sanity.rs similarity index 100% rename from 16_virtual_mem_part4_higher_half_kernel/tests/01_timer_sanity.rs rename to 16_virtual_mem_part4_higher_half_kernel/kernel/tests/01_timer_sanity.rs diff --git a/16_virtual_mem_part4_higher_half_kernel/tests/02_exception_sync_page_fault.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/tests/02_exception_sync_page_fault.rs similarity index 100% rename from 16_virtual_mem_part4_higher_half_kernel/tests/02_exception_sync_page_fault.rs rename to 16_virtual_mem_part4_higher_half_kernel/kernel/tests/02_exception_sync_page_fault.rs diff --git a/16_virtual_mem_part4_higher_half_kernel/tests/03_exception_restore_sanity.rb b/16_virtual_mem_part4_higher_half_kernel/kernel/tests/03_exception_restore_sanity.rb similarity index 100% rename from 16_virtual_mem_part4_higher_half_kernel/tests/03_exception_restore_sanity.rb rename to 16_virtual_mem_part4_higher_half_kernel/kernel/tests/03_exception_restore_sanity.rb diff --git a/16_virtual_mem_part4_higher_half_kernel/tests/03_exception_restore_sanity.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/tests/03_exception_restore_sanity.rs similarity index 100% rename from 16_virtual_mem_part4_higher_half_kernel/tests/03_exception_restore_sanity.rs rename to 16_virtual_mem_part4_higher_half_kernel/kernel/tests/03_exception_restore_sanity.rs diff --git a/16_virtual_mem_part4_higher_half_kernel/tests/04_exception_irq_sanity.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/tests/04_exception_irq_sanity.rs similarity index 100% rename from 16_virtual_mem_part4_higher_half_kernel/tests/04_exception_irq_sanity.rs rename to 16_virtual_mem_part4_higher_half_kernel/kernel/tests/04_exception_irq_sanity.rs diff --git a/16_virtual_mem_part4_higher_half_kernel/tests/boot_test_string.rb b/16_virtual_mem_part4_higher_half_kernel/kernel/tests/boot_test_string.rb similarity index 100% rename from 16_virtual_mem_part4_higher_half_kernel/tests/boot_test_string.rb rename to 16_virtual_mem_part4_higher_half_kernel/kernel/tests/boot_test_string.rb diff --git a/16_virtual_mem_part4_higher_half_kernel/tests/panic_exit_success/mod.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/tests/panic_exit_success/mod.rs similarity index 100% rename from 16_virtual_mem_part4_higher_half_kernel/tests/panic_exit_success/mod.rs rename to 16_virtual_mem_part4_higher_half_kernel/kernel/tests/panic_exit_success/mod.rs diff --git a/16_virtual_mem_part4_higher_half_kernel/tests/panic_wait_forever/mod.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/tests/panic_wait_forever/mod.rs similarity index 100% rename from 16_virtual_mem_part4_higher_half_kernel/tests/panic_wait_forever/mod.rs rename to 16_virtual_mem_part4_higher_half_kernel/kernel/tests/panic_wait_forever/mod.rs diff --git a/16_virtual_mem_part4_higher_half_kernel/test-macros/Cargo.toml b/16_virtual_mem_part4_higher_half_kernel/libraries/test-macros/Cargo.toml similarity index 100% rename from 16_virtual_mem_part4_higher_half_kernel/test-macros/Cargo.toml rename to 16_virtual_mem_part4_higher_half_kernel/libraries/test-macros/Cargo.toml diff --git a/16_virtual_mem_part4_higher_half_kernel/test-macros/src/lib.rs b/16_virtual_mem_part4_higher_half_kernel/libraries/test-macros/src/lib.rs similarity index 100% rename from 16_virtual_mem_part4_higher_half_kernel/test-macros/src/lib.rs rename to 16_virtual_mem_part4_higher_half_kernel/libraries/test-macros/src/lib.rs diff --git a/16_virtual_mem_part4_higher_half_kernel/test-types/Cargo.toml b/16_virtual_mem_part4_higher_half_kernel/libraries/test-types/Cargo.toml similarity index 100% rename from 16_virtual_mem_part4_higher_half_kernel/test-types/Cargo.toml rename to 16_virtual_mem_part4_higher_half_kernel/libraries/test-types/Cargo.toml diff --git a/16_virtual_mem_part4_higher_half_kernel/test-types/src/lib.rs b/16_virtual_mem_part4_higher_half_kernel/libraries/test-types/src/lib.rs similarity index 100% rename from 16_virtual_mem_part4_higher_half_kernel/test-types/src/lib.rs rename to 16_virtual_mem_part4_higher_half_kernel/libraries/test-types/src/lib.rs diff --git a/16_virtual_mem_part4_higher_half_kernel/translation_table_tool/arch.rb b/16_virtual_mem_part4_higher_half_kernel/tools/translation_table_tool/arch.rb similarity index 100% rename from 16_virtual_mem_part4_higher_half_kernel/translation_table_tool/arch.rb rename to 16_virtual_mem_part4_higher_half_kernel/tools/translation_table_tool/arch.rb diff --git a/16_virtual_mem_part4_higher_half_kernel/translation_table_tool/bsp.rb b/16_virtual_mem_part4_higher_half_kernel/tools/translation_table_tool/bsp.rb similarity index 94% rename from 16_virtual_mem_part4_higher_half_kernel/translation_table_tool/bsp.rb rename to 16_virtual_mem_part4_higher_half_kernel/tools/translation_table_tool/bsp.rb index ddf69a17..536a2f21 100644 --- a/16_virtual_mem_part4_higher_half_kernel/translation_table_tool/bsp.rb +++ b/16_virtual_mem_part4_higher_half_kernel/tools/translation_table_tool/bsp.rb @@ -8,7 +8,7 @@ class RaspberryPi attr_reader :kernel_granule, :kernel_virt_addr_space_size, :kernel_virt_start_addr - MEMORY_SRC = File.read('src/bsp/raspberrypi/memory.rs').split("\n") + MEMORY_SRC = File.read('kernel/src/bsp/raspberrypi/memory.rs').split("\n") def initialize @kernel_granule = Granule64KiB diff --git a/16_virtual_mem_part4_higher_half_kernel/translation_table_tool/generic.rb b/16_virtual_mem_part4_higher_half_kernel/tools/translation_table_tool/generic.rb similarity index 100% rename from 16_virtual_mem_part4_higher_half_kernel/translation_table_tool/generic.rb rename to 16_virtual_mem_part4_higher_half_kernel/tools/translation_table_tool/generic.rb diff --git a/16_virtual_mem_part4_higher_half_kernel/translation_table_tool/kernel_elf.rb b/16_virtual_mem_part4_higher_half_kernel/tools/translation_table_tool/kernel_elf.rb similarity index 100% rename from 16_virtual_mem_part4_higher_half_kernel/translation_table_tool/kernel_elf.rb rename to 16_virtual_mem_part4_higher_half_kernel/tools/translation_table_tool/kernel_elf.rb diff --git a/16_virtual_mem_part4_higher_half_kernel/translation_table_tool/main.rb b/16_virtual_mem_part4_higher_half_kernel/tools/translation_table_tool/main.rb similarity index 100% rename from 16_virtual_mem_part4_higher_half_kernel/translation_table_tool/main.rb rename to 16_virtual_mem_part4_higher_half_kernel/tools/translation_table_tool/main.rb diff --git a/common/tests/dispatch.rb b/common/tests/dispatch.rb index 86aaea86..b6223418 100755 --- a/common/tests/dispatch.rb +++ b/common/tests/dispatch.rb @@ -16,16 +16,19 @@ qemu_cmd = ARGV.join(' ') binary = ARGV.last test_name = binary.gsub(%r{.*deps/}, '').split('-')[0] +# Check if virtual manifest (tutorial 12 or later) or not +path_prefix = File.exist?('kernel/Cargo.toml') ? 'kernel/' : '' + case test_name when 'kernel8.img' - load 'tests/boot_test_string.rb' # provides 'EXPECTED_PRINT' + load "#{path_prefix}tests/boot_test_string.rb" # provides 'EXPECTED_PRINT' BootTest.new(qemu_cmd, EXPECTED_PRINT).run # Doesn't return when 'libkernel' ExitCodeTest.new(qemu_cmd, 'Kernel library unit tests').run # Doesn't return else - console_test_file = "tests/#{test_name}.rb" + console_test_file = "#{path_prefix}tests/#{test_name}.rb" test_name.concat('.rs') test = if File.exist?(console_test_file) load console_test_file # provides 'subtest_collection' diff --git a/utils/devtool.rb b/utils/devtool.rb index a926cd2c..9473ff8d 100755 --- a/utils/devtool.rb +++ b/utils/devtool.rb @@ -301,7 +301,15 @@ class DevTool # Only diff adjacent tutorials. This checks the numbers of the tutorial folders. return unless original[0..1].to_i + 1 == update[0..1].to_i - puts 'Diffing '.light_blue + original.ljust(padding) + " -> #{update}" + # Skip for tutorial 11. Due to the change to virtual manifest, the diff is rather + # unreadable. + if original[0..1].to_i == 11 + puts 'Skipping '.light_yellow + + "#{original}: Too noisy due to change to virtual manifest" + return + end + + puts 'Diffing '.light_blue + original.ljust(padding) + " -> #{update}" system("bash utils/diff_tut_folders.bash #{original} #{update}") end diff --git a/utils/diff_tut_folders.bash b/utils/diff_tut_folders.bash index f4e6d107..d93ca57d 100755 --- a/utils/diff_tut_folders.bash +++ b/utils/diff_tut_folders.bash @@ -9,7 +9,6 @@ DIFF=$( -x README.md \ -x README.CN.md \ -x README.ES.md \ - -x kernel \ -x kernel8.img \ -x Cargo.lock \ -x target \ @@ -17,7 +16,7 @@ DIFF=$( | sed -r "s/[12][90][127][0-9]-[0-9][0-9]-[0-9][0-9] .*//g" \ | sed -r "s/[[:space:]]*$//g" \ | sed -r "s/%/modulo/g" \ - | sed -r "s/diff -uNr -x README.md -x README.CN.md -x README.ES.md -x kernel -x kernel8.img -x Cargo.lock -x target/\ndiff -uNr/g" + | sed -r "s/diff -uNr -x README.md -x README.CN.md -x README.ES.md -x kernel8.img -x Cargo.lock -x target/\ndiff -uNr/g" ) HEADER="## Diff to previous" From 6e3051e6fd045151b85fc23e2d6a0c5d43296aca Mon Sep 17 00:00:00 2001 From: Andrew Cherry Date: Tue, 19 Apr 2022 10:26:00 +0100 Subject: [PATCH 07/75] Updated to reflect rename of link.ld to kernel.ld --- 01_wait_forever/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/01_wait_forever/README.md b/01_wait_forever/README.md index 9c6eaf76..73b15af5 100644 --- a/01_wait_forever/README.md +++ b/01_wait_forever/README.md @@ -18,7 +18,7 @@ ## Code to look at -- `BSP`-specific `link.ld` linker script. +- `BSP`-specific `kernel.ld` linker script. - Load address at `0x8_0000` - Only `.text` section. - `main.rs`: Important [inner attributes]: From b836655d668959b8fdd39ca91ea04e3ee0803c0f Mon Sep 17 00:00:00 2001 From: Andre Richter Date: Tue, 19 Apr 2022 22:54:42 +0200 Subject: [PATCH 08/75] More link.ld -> kernel.ld renaming --- 01_wait_forever/README.CN.md | 2 +- 01_wait_forever/README.ES.md | 28 +++++++++---------- 02_runtime_init/README.ES.md | 2 +- 06_uart_chainloader/README.md | 9 +++--- .../README.md | 4 +-- .../README.md | 6 ++-- 6 files changed, 26 insertions(+), 25 deletions(-) diff --git a/01_wait_forever/README.CN.md b/01_wait_forever/README.CN.md index 281a9290..06b2178d 100644 --- a/01_wait_forever/README.CN.md +++ b/01_wait_forever/README.CN.md @@ -14,7 +14,7 @@ - `nm`: 检查符号。 - 代码按照 `kernel`, `arch` 和 `BSP` (板级支持包)的形式组织。 - 条件编译会根据用户提供的参数编译各自的 `arch` 和 `BSP` 的内容。 -- 自定义 `link.ld` 链接脚本. +- 自定义 `kernel.ld` 链接脚本. - 载入地址为 `0x80_000` - 目前仅有 `.text` 小节(section)。 - `main.rs`: 重要的 [inner attributes]: diff --git a/01_wait_forever/README.ES.md b/01_wait_forever/README.ES.md index 5244372a..0d86a4ea 100644 --- a/01_wait_forever/README.ES.md +++ b/01_wait_forever/README.ES.md @@ -9,37 +9,37 @@ ## Compilar * El archivo `Makefile` permite ejecutar: - + * `doc`: Genera la documentación. - + * `qemu`: Ejecutar el kernel en QEMU. - + * `clippy`: Analiza el código y sugiere mejoras. - + * `clean`: Elimina todos los archivos generados durante la compilación, etc. - + * `readelf`: Inspecciona el archivo `ELF` de salida. - - * `objdump`: Inspecciona el ensamblador. - + + * `objdump`: Inspecciona el ensamblador. + * `nm`: Inspecciona los símbolos. ## Código a revisar -* El script para enlazado específico para la `BSP` llamado `link.ld`. - +* El script para enlazado específico para la `BSP` llamado `kernel.ld`. + * Carga la dirección en `0x8_0000`. - + * Solo la sección `.text`. * `main.rs`: [Atributos internos](https://doc.rust-lang.org/reference/attributes.html) importantes: - + * `#![no_std]`, `#![no_main]`. -* `boot.s`: La función de ensamblador `_start()` que inicia `wfe` (Wait For Event / Esperar Hasta Un Evento), detiene todos los núcleos del procesador que están ejecutando `_start()`. +* `boot.s`: La función de ensamblador `_start()` que inicia `wfe` (Wait For Event / Esperar Hasta Un Evento), detiene todos los núcleos del procesador que están ejecutando `_start()`. * Tenemos que definir una función que funcione como `#[panic_handler]` (manejador de pánico) para que el compilador no nos cause problemas. - + * Hazla `unimplemented!()` porque se eliminará ya que no está siendo usada. ## Pruébalo diff --git a/02_runtime_init/README.ES.md b/02_runtime_init/README.ES.md index 79c4c2b4..e1210e9b 100644 --- a/02_runtime_init/README.ES.md +++ b/02_runtime_init/README.ES.md @@ -8,7 +8,7 @@ ## Adiciones importantes -* Adiciones importantes al script `link.ld`: +* Adiciones importantes al script `kernel.ld`: * Nuevas secciones: `.rodata`, `.got`, `.data`, `.bss`. diff --git a/06_uart_chainloader/README.md b/06_uart_chainloader/README.md index b3db670f..8c860316 100644 --- a/06_uart_chainloader/README.md +++ b/06_uart_chainloader/README.md @@ -17,8 +17,8 @@ at the source code changes. The gist of it is that in `boot.s`, we are writing a piece of [position independent code] which automatically determines where the firmware has loaded the binary (`0x8_0000`), and where it was -linked to (`0x200_0000`, see `link.ld`). The binary then copies itself from loaded to linked address -(aka "relocating" itself), and then jumps to the relocated version of `_start_rust()`. +linked to (`0x200_0000`, see `kernel.ld`). The binary then copies itself from loaded to linked +address (aka "relocating" itself), and then jumps to the relocated version of `_start_rust()`. Since the chainloader has put itself "out of the way" now, it can now receive another kernel binary from the `UART` and copy it to the standard load address of the RPi firmware at `0x8_0000`. Finally, @@ -27,8 +27,9 @@ from SD card all along. Please bear with me until I find the time to write it all down here elaborately. For the time being, please see this tutorial as an enabler for a convenience feature that allows booting the following -tutorials in a quick manner. _For those keen to get a deeper understanding, it could make sense to skip forward to [Chapter 15](../15_virtual_mem_part3_precomputed_tables) and read the first half of the README, -where `Load Address != Link Address` is discussed_. +tutorials in a quick manner. _For those keen to get a deeper understanding, it could make sense to +skip forward to [Chapter 15](../15_virtual_mem_part3_precomputed_tables) and read the first half of +the README, where `Load Address != Link Address` is discussed_. [position independent code]: https://en.wikipedia.org/wiki/Position-independent_code diff --git a/10_virtual_mem_part1_identity_mapping/README.md b/10_virtual_mem_part1_identity_mapping/README.md index 1a02666b..8c2de206 100644 --- a/10_virtual_mem_part1_identity_mapping/README.md +++ b/10_virtual_mem_part1_identity_mapping/README.md @@ -14,7 +14,7 @@ * [Generic Kernel code: `memory/mmu.rs`](#generic-kernel-code-memorymmurs) * [BSP: `bsp/raspberrypi/memory/mmu.rs`](#bsp-bspraspberrypimemorymmurs) * [AArch64: `_arch/aarch64/memory/*`](#aarch64-_archaarch64memory) - * [`link.ld`](#linkld) + * [`kernel.ld`](#kernelld) - [Address translation examples](#address-translation-examples) * [Address translation using a 64 KiB page descriptor](#address-translation-using-a-64-kib-page-descriptor) - [Zero-cost abstraction](#zero-cost-abstraction) @@ -222,7 +222,7 @@ enables caching for data and instructions. [Translation Control Register - EL1]: https://docs.rs/crate/cortex-a/5.1.2/source/src/regs/tcr_el1.rs [System Control Register - EL1]: https://docs.rs/crate/cortex-a/5.1.2/source/src/regs/sctlr_el1.rs -### `link.ld` +### `kernel.ld` We need to align the `code` segment to `64 KiB` so that it doesn't overlap with the next section that needs read/write attributes instead of read/execute attributes: diff --git a/15_virtual_mem_part3_precomputed_tables/README.md b/15_virtual_mem_part3_precomputed_tables/README.md index c3554f19..8cd644f4 100644 --- a/15_virtual_mem_part3_precomputed_tables/README.md +++ b/15_virtual_mem_part3_precomputed_tables/README.md @@ -118,7 +118,7 @@ Here are the compilation steps and the corresponding `objdump` for `AArch64`: ```console $ clang --target=aarch64-none-elf -Iinclude -Wall -c start.c -o start.o -$ ld.lld start.o -T link.ld -o example.elf +$ ld.lld start.o -T kernel.ld -o example.elf ``` ```c-objdump @@ -326,7 +326,7 @@ space: ```console $ clang --target=aarch64-none-elf -Iinclude -Wall -fpic -c start.c -o start.o -$ ld.lld start.o -T link.ld -o example.elf +$ ld.lld start.o -T kernel.ld -o example.elf ``` ```c-objdump @@ -473,7 +473,7 @@ the precompute use-case. The additional `#[no_mangle]` is added because we will symbol from the `translation table tool`, and this is easier with unmangled names. In the `BSP` code, there is also a new file called `kernel_virt_addr_space_size.ld`, which contains -the kernel's virtual address space size. This file gets included in both, the `link.ld` linker +the kernel's virtual address space size. This file gets included in both, the `kernel.ld` linker script and `mmu.rs`. We need this value both as a symbol in the kernel's ELF (for the `translation table tool` to parse it later) and as a constant in the `Rust` code. This inclusion approach is just a convenience hack that turned out working well. From 1323c8245b83b340d63952e23e8ffce2c8606164 Mon Sep 17 00:00:00 2001 From: Andre Richter Date: Fri, 22 Apr 2022 22:30:16 +0200 Subject: [PATCH 09/75] Remove RA helper target from Makefile --- 01_wait_forever/.vscode/settings.json | 3 ++- 01_wait_forever/Makefile | 5 ----- 02_runtime_init/.vscode/settings.json | 3 ++- 02_runtime_init/Makefile | 5 ----- 03_hacky_hello_world/.vscode/settings.json | 3 ++- 03_hacky_hello_world/Makefile | 6 ------ 03_hacky_hello_world/README.md | 9 ++++----- 04_safe_globals/.vscode/settings.json | 3 ++- 04_safe_globals/Makefile | 6 ------ 05_drivers_gpio_uart/.vscode/settings.json | 3 ++- 05_drivers_gpio_uart/Makefile | 6 ------ 06_uart_chainloader/.vscode/settings.json | 3 ++- 06_uart_chainloader/Makefile | 6 ------ 06_uart_chainloader/README.md | 2 +- 07_timestamps/.vscode/settings.json | 3 ++- 07_timestamps/Makefile | 6 ------ 07_timestamps/README.md | 2 +- 08_hw_debug_JTAG/.vscode/settings.json | 3 ++- 08_hw_debug_JTAG/Makefile | 6 ------ 08_hw_debug_JTAG/README.md | 2 +- 09_privilege_level/.vscode/settings.json | 3 ++- 09_privilege_level/Makefile | 6 ------ .../.vscode/settings.json | 3 ++- 10_virtual_mem_part1_identity_mapping/Makefile | 6 ------ 11_exceptions_part1_groundwork/.vscode/settings.json | 3 ++- 11_exceptions_part1_groundwork/Makefile | 6 ------ 12_integrated_testing/.vscode/settings.json | 3 ++- 12_integrated_testing/Makefile | 6 ------ .../.vscode/settings.json | 3 ++- 13_exceptions_part2_peripheral_IRQs/Makefile | 6 ------ 14_virtual_mem_part2_mmio_remap/.vscode/settings.json | 3 ++- 14_virtual_mem_part2_mmio_remap/Makefile | 6 ------ .../.vscode/settings.json | 3 ++- 15_virtual_mem_part3_precomputed_tables/Makefile | 6 ------ 15_virtual_mem_part3_precomputed_tables/README.md | 2 +- .../.vscode/settings.json | 3 ++- 16_virtual_mem_part4_higher_half_kernel/Makefile | 6 ------ X1_JTAG_boot/.vscode/settings.json | 3 ++- X1_JTAG_boot/Makefile | 6 ------ 39 files changed, 42 insertions(+), 126 deletions(-) diff --git a/01_wait_forever/.vscode/settings.json b/01_wait_forever/.vscode/settings.json index 0a8d7c09..292bf2a9 100644 --- a/01_wait_forever/.vscode/settings.json +++ b/01_wait_forever/.vscode/settings.json @@ -3,7 +3,8 @@ "editor.rulers": [100], "rust-analyzer.cargo.target": "aarch64-unknown-none-softfloat", "rust-analyzer.cargo.features": ["bsp_rpi3"], - "rust-analyzer.checkOnSave.overrideCommand": ["make", "check"], + "rust-analyzer.checkOnSave.allTargets": false, + "rust-analyzer.checkOnSave.extraArgs": ["--lib", "--bins"], "rust-analyzer.lens.debug": false, "rust-analyzer.lens.run": false } diff --git a/01_wait_forever/Makefile b/01_wait_forever/Makefile index 15082c03..7699e5f4 100644 --- a/01_wait_forever/Makefile +++ b/01_wait_forever/Makefile @@ -190,8 +190,3 @@ nm: $(KERNEL_ELF) $(call color_header, "Launching nm") @$(DOCKER_TOOLS) $(NM_BINARY) --demangle --print-size $(KERNEL_ELF) | sort | rustfilt -##------------------------------------------------------------------------------ -## Helper target for rust-analyzer -##------------------------------------------------------------------------------ -check: - @RUSTFLAGS="$(RUSTFLAGS)" $(CHECK_CMD) --message-format=json diff --git a/02_runtime_init/.vscode/settings.json b/02_runtime_init/.vscode/settings.json index 0a8d7c09..292bf2a9 100644 --- a/02_runtime_init/.vscode/settings.json +++ b/02_runtime_init/.vscode/settings.json @@ -3,7 +3,8 @@ "editor.rulers": [100], "rust-analyzer.cargo.target": "aarch64-unknown-none-softfloat", "rust-analyzer.cargo.features": ["bsp_rpi3"], - "rust-analyzer.checkOnSave.overrideCommand": ["make", "check"], + "rust-analyzer.checkOnSave.allTargets": false, + "rust-analyzer.checkOnSave.extraArgs": ["--lib", "--bins"], "rust-analyzer.lens.debug": false, "rust-analyzer.lens.run": false } diff --git a/02_runtime_init/Makefile b/02_runtime_init/Makefile index d44f07aa..0d877c15 100644 --- a/02_runtime_init/Makefile +++ b/02_runtime_init/Makefile @@ -192,8 +192,3 @@ nm: $(KERNEL_ELF) $(call color_header, "Launching nm") @$(DOCKER_TOOLS) $(NM_BINARY) --demangle --print-size $(KERNEL_ELF) | sort | rustfilt -##------------------------------------------------------------------------------ -## Helper target for rust-analyzer -##------------------------------------------------------------------------------ -check: - @RUSTFLAGS="$(RUSTFLAGS)" $(CHECK_CMD) --message-format=json diff --git a/03_hacky_hello_world/.vscode/settings.json b/03_hacky_hello_world/.vscode/settings.json index 0a8d7c09..292bf2a9 100644 --- a/03_hacky_hello_world/.vscode/settings.json +++ b/03_hacky_hello_world/.vscode/settings.json @@ -3,7 +3,8 @@ "editor.rulers": [100], "rust-analyzer.cargo.target": "aarch64-unknown-none-softfloat", "rust-analyzer.cargo.features": ["bsp_rpi3"], - "rust-analyzer.checkOnSave.overrideCommand": ["make", "check"], + "rust-analyzer.checkOnSave.allTargets": false, + "rust-analyzer.checkOnSave.extraArgs": ["--lib", "--bins"], "rust-analyzer.lens.debug": false, "rust-analyzer.lens.run": false } diff --git a/03_hacky_hello_world/Makefile b/03_hacky_hello_world/Makefile index ac52002f..c3e75cce 100644 --- a/03_hacky_hello_world/Makefile +++ b/03_hacky_hello_world/Makefile @@ -195,12 +195,6 @@ nm: $(KERNEL_ELF) $(call color_header, "Launching nm") @$(DOCKER_TOOLS) $(NM_BINARY) --demangle --print-size $(KERNEL_ELF) | sort | rustfilt -##------------------------------------------------------------------------------ -## Helper target for rust-analyzer -##------------------------------------------------------------------------------ -check: - @RUSTFLAGS="$(RUSTFLAGS)" $(CHECK_CMD) --message-format=json - ##-------------------------------------------------------------------------------------------------- diff --git a/03_hacky_hello_world/README.md b/03_hacky_hello_world/README.md index a1f3e150..7263532c 100644 --- a/03_hacky_hello_world/README.md +++ b/03_hacky_hello_world/README.md @@ -94,11 +94,10 @@ diff -uNr 02_runtime_init/Makefile 03_hacky_hello_world/Makefile -@@ -197,3 +200,28 @@ - ##------------------------------------------------------------------------------ - check: - @RUSTFLAGS="$(RUSTFLAGS)" $(CHECK_CMD) --message-format=json -+ +@@ -192,3 +195,27 @@ + $(call color_header, "Launching nm") + @$(DOCKER_TOOLS) $(NM_BINARY) --demangle --print-size $(KERNEL_ELF) | sort | rustfilt + + + +##-------------------------------------------------------------------------------------------------- diff --git a/04_safe_globals/.vscode/settings.json b/04_safe_globals/.vscode/settings.json index 0a8d7c09..292bf2a9 100644 --- a/04_safe_globals/.vscode/settings.json +++ b/04_safe_globals/.vscode/settings.json @@ -3,7 +3,8 @@ "editor.rulers": [100], "rust-analyzer.cargo.target": "aarch64-unknown-none-softfloat", "rust-analyzer.cargo.features": ["bsp_rpi3"], - "rust-analyzer.checkOnSave.overrideCommand": ["make", "check"], + "rust-analyzer.checkOnSave.allTargets": false, + "rust-analyzer.checkOnSave.extraArgs": ["--lib", "--bins"], "rust-analyzer.lens.debug": false, "rust-analyzer.lens.run": false } diff --git a/04_safe_globals/Makefile b/04_safe_globals/Makefile index ac52002f..c3e75cce 100644 --- a/04_safe_globals/Makefile +++ b/04_safe_globals/Makefile @@ -195,12 +195,6 @@ nm: $(KERNEL_ELF) $(call color_header, "Launching nm") @$(DOCKER_TOOLS) $(NM_BINARY) --demangle --print-size $(KERNEL_ELF) | sort | rustfilt -##------------------------------------------------------------------------------ -## Helper target for rust-analyzer -##------------------------------------------------------------------------------ -check: - @RUSTFLAGS="$(RUSTFLAGS)" $(CHECK_CMD) --message-format=json - ##-------------------------------------------------------------------------------------------------- diff --git a/05_drivers_gpio_uart/.vscode/settings.json b/05_drivers_gpio_uart/.vscode/settings.json index 0a8d7c09..292bf2a9 100644 --- a/05_drivers_gpio_uart/.vscode/settings.json +++ b/05_drivers_gpio_uart/.vscode/settings.json @@ -3,7 +3,8 @@ "editor.rulers": [100], "rust-analyzer.cargo.target": "aarch64-unknown-none-softfloat", "rust-analyzer.cargo.features": ["bsp_rpi3"], - "rust-analyzer.checkOnSave.overrideCommand": ["make", "check"], + "rust-analyzer.checkOnSave.allTargets": false, + "rust-analyzer.checkOnSave.extraArgs": ["--lib", "--bins"], "rust-analyzer.lens.debug": false, "rust-analyzer.lens.run": false } diff --git a/05_drivers_gpio_uart/Makefile b/05_drivers_gpio_uart/Makefile index 193581e9..38afeef9 100644 --- a/05_drivers_gpio_uart/Makefile +++ b/05_drivers_gpio_uart/Makefile @@ -214,12 +214,6 @@ nm: $(KERNEL_ELF) $(call color_header, "Launching nm") @$(DOCKER_TOOLS) $(NM_BINARY) --demangle --print-size $(KERNEL_ELF) | sort | rustfilt -##------------------------------------------------------------------------------ -## Helper target for rust-analyzer -##------------------------------------------------------------------------------ -check: - @RUSTFLAGS="$(RUSTFLAGS)" $(CHECK_CMD) --message-format=json - ##-------------------------------------------------------------------------------------------------- diff --git a/06_uart_chainloader/.vscode/settings.json b/06_uart_chainloader/.vscode/settings.json index 0a8d7c09..292bf2a9 100644 --- a/06_uart_chainloader/.vscode/settings.json +++ b/06_uart_chainloader/.vscode/settings.json @@ -3,7 +3,8 @@ "editor.rulers": [100], "rust-analyzer.cargo.target": "aarch64-unknown-none-softfloat", "rust-analyzer.cargo.features": ["bsp_rpi3"], - "rust-analyzer.checkOnSave.overrideCommand": ["make", "check"], + "rust-analyzer.checkOnSave.allTargets": false, + "rust-analyzer.checkOnSave.extraArgs": ["--lib", "--bins"], "rust-analyzer.lens.debug": false, "rust-analyzer.lens.run": false } diff --git a/06_uart_chainloader/Makefile b/06_uart_chainloader/Makefile index 5ae54175..3cde6041 100644 --- a/06_uart_chainloader/Makefile +++ b/06_uart_chainloader/Makefile @@ -220,12 +220,6 @@ nm: $(KERNEL_ELF) $(call color_header, "Launching nm") @$(DOCKER_TOOLS) $(NM_BINARY) --demangle --print-size $(KERNEL_ELF) | sort | rustfilt -##------------------------------------------------------------------------------ -## Helper target for rust-analyzer -##------------------------------------------------------------------------------ -check: - @RUSTFLAGS="$(RUSTFLAGS)" $(CHECK_CMD) --message-format=json - ##-------------------------------------------------------------------------------------------------- diff --git a/06_uart_chainloader/README.md b/06_uart_chainloader/README.md index 8c860316..04a21dff 100644 --- a/06_uart_chainloader/README.md +++ b/06_uart_chainloader/README.md @@ -248,7 +248,7 @@ diff -uNr 05_drivers_gpio_uart/Makefile 06_uart_chainloader/Makefile ##------------------------------------------------------------------------------ ## Run clippy -@@ -239,7 +245,8 @@ +@@ -233,7 +239,8 @@ ##------------------------------------------------------------------------------ test_boot: $(KERNEL_BIN) $(call color_header, "Boot test - $(BSP)") diff --git a/07_timestamps/.vscode/settings.json b/07_timestamps/.vscode/settings.json index 0a8d7c09..292bf2a9 100644 --- a/07_timestamps/.vscode/settings.json +++ b/07_timestamps/.vscode/settings.json @@ -3,7 +3,8 @@ "editor.rulers": [100], "rust-analyzer.cargo.target": "aarch64-unknown-none-softfloat", "rust-analyzer.cargo.features": ["bsp_rpi3"], - "rust-analyzer.checkOnSave.overrideCommand": ["make", "check"], + "rust-analyzer.checkOnSave.allTargets": false, + "rust-analyzer.checkOnSave.extraArgs": ["--lib", "--bins"], "rust-analyzer.lens.debug": false, "rust-analyzer.lens.run": false } diff --git a/07_timestamps/Makefile b/07_timestamps/Makefile index d127c422..d5395011 100644 --- a/07_timestamps/Makefile +++ b/07_timestamps/Makefile @@ -214,12 +214,6 @@ nm: $(KERNEL_ELF) $(call color_header, "Launching nm") @$(DOCKER_TOOLS) $(NM_BINARY) --demangle --print-size $(KERNEL_ELF) | sort | rustfilt -##------------------------------------------------------------------------------ -## Helper target for rust-analyzer -##------------------------------------------------------------------------------ -check: - @RUSTFLAGS="$(RUSTFLAGS)" $(CHECK_CMD) --message-format=json - ##-------------------------------------------------------------------------------------------------- diff --git a/07_timestamps/README.md b/07_timestamps/README.md index 6904f4f9..abdca348 100644 --- a/07_timestamps/README.md +++ b/07_timestamps/README.md @@ -149,7 +149,7 @@ diff -uNr 06_uart_chainloader/Makefile 07_timestamps/Makefile ##------------------------------------------------------------------------------ ## Run clippy -@@ -245,8 +239,7 @@ +@@ -239,8 +233,7 @@ ##------------------------------------------------------------------------------ test_boot: $(KERNEL_BIN) $(call color_header, "Boot test - $(BSP)") diff --git a/08_hw_debug_JTAG/.vscode/settings.json b/08_hw_debug_JTAG/.vscode/settings.json index 0a8d7c09..292bf2a9 100644 --- a/08_hw_debug_JTAG/.vscode/settings.json +++ b/08_hw_debug_JTAG/.vscode/settings.json @@ -3,7 +3,8 @@ "editor.rulers": [100], "rust-analyzer.cargo.target": "aarch64-unknown-none-softfloat", "rust-analyzer.cargo.features": ["bsp_rpi3"], - "rust-analyzer.checkOnSave.overrideCommand": ["make", "check"], + "rust-analyzer.checkOnSave.allTargets": false, + "rust-analyzer.checkOnSave.extraArgs": ["--lib", "--bins"], "rust-analyzer.lens.debug": false, "rust-analyzer.lens.run": false } diff --git a/08_hw_debug_JTAG/Makefile b/08_hw_debug_JTAG/Makefile index 1cf4d1aa..4f6b01f9 100644 --- a/08_hw_debug_JTAG/Makefile +++ b/08_hw_debug_JTAG/Makefile @@ -225,12 +225,6 @@ nm: $(KERNEL_ELF) $(call color_header, "Launching nm") @$(DOCKER_TOOLS) $(NM_BINARY) --demangle --print-size $(KERNEL_ELF) | sort | rustfilt -##------------------------------------------------------------------------------ -## Helper target for rust-analyzer -##------------------------------------------------------------------------------ -check: - @RUSTFLAGS="$(RUSTFLAGS)" $(CHECK_CMD) --message-format=json - ##-------------------------------------------------------------------------------------------------- diff --git a/08_hw_debug_JTAG/README.md b/08_hw_debug_JTAG/README.md index 902ca6e4..b1f5d679 100644 --- a/08_hw_debug_JTAG/README.md +++ b/08_hw_debug_JTAG/README.md @@ -364,7 +364,7 @@ diff -uNr 07_timestamps/Makefile 08_hw_debug_JTAG/Makefile endif -@@ -222,6 +233,35 @@ +@@ -216,6 +227,35 @@ diff --git a/09_privilege_level/.vscode/settings.json b/09_privilege_level/.vscode/settings.json index 0a8d7c09..292bf2a9 100644 --- a/09_privilege_level/.vscode/settings.json +++ b/09_privilege_level/.vscode/settings.json @@ -3,7 +3,8 @@ "editor.rulers": [100], "rust-analyzer.cargo.target": "aarch64-unknown-none-softfloat", "rust-analyzer.cargo.features": ["bsp_rpi3"], - "rust-analyzer.checkOnSave.overrideCommand": ["make", "check"], + "rust-analyzer.checkOnSave.allTargets": false, + "rust-analyzer.checkOnSave.extraArgs": ["--lib", "--bins"], "rust-analyzer.lens.debug": false, "rust-analyzer.lens.run": false } diff --git a/09_privilege_level/Makefile b/09_privilege_level/Makefile index 1cf4d1aa..4f6b01f9 100644 --- a/09_privilege_level/Makefile +++ b/09_privilege_level/Makefile @@ -225,12 +225,6 @@ nm: $(KERNEL_ELF) $(call color_header, "Launching nm") @$(DOCKER_TOOLS) $(NM_BINARY) --demangle --print-size $(KERNEL_ELF) | sort | rustfilt -##------------------------------------------------------------------------------ -## Helper target for rust-analyzer -##------------------------------------------------------------------------------ -check: - @RUSTFLAGS="$(RUSTFLAGS)" $(CHECK_CMD) --message-format=json - ##-------------------------------------------------------------------------------------------------- diff --git a/10_virtual_mem_part1_identity_mapping/.vscode/settings.json b/10_virtual_mem_part1_identity_mapping/.vscode/settings.json index 0a8d7c09..292bf2a9 100644 --- a/10_virtual_mem_part1_identity_mapping/.vscode/settings.json +++ b/10_virtual_mem_part1_identity_mapping/.vscode/settings.json @@ -3,7 +3,8 @@ "editor.rulers": [100], "rust-analyzer.cargo.target": "aarch64-unknown-none-softfloat", "rust-analyzer.cargo.features": ["bsp_rpi3"], - "rust-analyzer.checkOnSave.overrideCommand": ["make", "check"], + "rust-analyzer.checkOnSave.allTargets": false, + "rust-analyzer.checkOnSave.extraArgs": ["--lib", "--bins"], "rust-analyzer.lens.debug": false, "rust-analyzer.lens.run": false } diff --git a/10_virtual_mem_part1_identity_mapping/Makefile b/10_virtual_mem_part1_identity_mapping/Makefile index 1cf4d1aa..4f6b01f9 100644 --- a/10_virtual_mem_part1_identity_mapping/Makefile +++ b/10_virtual_mem_part1_identity_mapping/Makefile @@ -225,12 +225,6 @@ nm: $(KERNEL_ELF) $(call color_header, "Launching nm") @$(DOCKER_TOOLS) $(NM_BINARY) --demangle --print-size $(KERNEL_ELF) | sort | rustfilt -##------------------------------------------------------------------------------ -## Helper target for rust-analyzer -##------------------------------------------------------------------------------ -check: - @RUSTFLAGS="$(RUSTFLAGS)" $(CHECK_CMD) --message-format=json - ##-------------------------------------------------------------------------------------------------- diff --git a/11_exceptions_part1_groundwork/.vscode/settings.json b/11_exceptions_part1_groundwork/.vscode/settings.json index 0a8d7c09..292bf2a9 100644 --- a/11_exceptions_part1_groundwork/.vscode/settings.json +++ b/11_exceptions_part1_groundwork/.vscode/settings.json @@ -3,7 +3,8 @@ "editor.rulers": [100], "rust-analyzer.cargo.target": "aarch64-unknown-none-softfloat", "rust-analyzer.cargo.features": ["bsp_rpi3"], - "rust-analyzer.checkOnSave.overrideCommand": ["make", "check"], + "rust-analyzer.checkOnSave.allTargets": false, + "rust-analyzer.checkOnSave.extraArgs": ["--lib", "--bins"], "rust-analyzer.lens.debug": false, "rust-analyzer.lens.run": false } diff --git a/11_exceptions_part1_groundwork/Makefile b/11_exceptions_part1_groundwork/Makefile index 1cf4d1aa..4f6b01f9 100644 --- a/11_exceptions_part1_groundwork/Makefile +++ b/11_exceptions_part1_groundwork/Makefile @@ -225,12 +225,6 @@ nm: $(KERNEL_ELF) $(call color_header, "Launching nm") @$(DOCKER_TOOLS) $(NM_BINARY) --demangle --print-size $(KERNEL_ELF) | sort | rustfilt -##------------------------------------------------------------------------------ -## Helper target for rust-analyzer -##------------------------------------------------------------------------------ -check: - @RUSTFLAGS="$(RUSTFLAGS)" $(CHECK_CMD) --message-format=json - ##-------------------------------------------------------------------------------------------------- diff --git a/12_integrated_testing/.vscode/settings.json b/12_integrated_testing/.vscode/settings.json index 0a8d7c09..292bf2a9 100644 --- a/12_integrated_testing/.vscode/settings.json +++ b/12_integrated_testing/.vscode/settings.json @@ -3,7 +3,8 @@ "editor.rulers": [100], "rust-analyzer.cargo.target": "aarch64-unknown-none-softfloat", "rust-analyzer.cargo.features": ["bsp_rpi3"], - "rust-analyzer.checkOnSave.overrideCommand": ["make", "check"], + "rust-analyzer.checkOnSave.allTargets": false, + "rust-analyzer.checkOnSave.extraArgs": ["--lib", "--bins"], "rust-analyzer.lens.debug": false, "rust-analyzer.lens.run": false } diff --git a/12_integrated_testing/Makefile b/12_integrated_testing/Makefile index 427c9303..50986ce2 100644 --- a/12_integrated_testing/Makefile +++ b/12_integrated_testing/Makefile @@ -237,12 +237,6 @@ nm: $(KERNEL_ELF) $(call color_header, "Launching nm") @$(DOCKER_TOOLS) $(NM_BINARY) --demangle --print-size $(KERNEL_ELF) | sort | rustfilt -##------------------------------------------------------------------------------ -## Helper target for rust-analyzer -##------------------------------------------------------------------------------ -check: - @RUSTFLAGS="$(RUSTFLAGS)" $(CHECK_CMD) --message-format=json - ##-------------------------------------------------------------------------------------------------- diff --git a/13_exceptions_part2_peripheral_IRQs/.vscode/settings.json b/13_exceptions_part2_peripheral_IRQs/.vscode/settings.json index 0a8d7c09..292bf2a9 100644 --- a/13_exceptions_part2_peripheral_IRQs/.vscode/settings.json +++ b/13_exceptions_part2_peripheral_IRQs/.vscode/settings.json @@ -3,7 +3,8 @@ "editor.rulers": [100], "rust-analyzer.cargo.target": "aarch64-unknown-none-softfloat", "rust-analyzer.cargo.features": ["bsp_rpi3"], - "rust-analyzer.checkOnSave.overrideCommand": ["make", "check"], + "rust-analyzer.checkOnSave.allTargets": false, + "rust-analyzer.checkOnSave.extraArgs": ["--lib", "--bins"], "rust-analyzer.lens.debug": false, "rust-analyzer.lens.run": false } diff --git a/13_exceptions_part2_peripheral_IRQs/Makefile b/13_exceptions_part2_peripheral_IRQs/Makefile index 427c9303..50986ce2 100644 --- a/13_exceptions_part2_peripheral_IRQs/Makefile +++ b/13_exceptions_part2_peripheral_IRQs/Makefile @@ -237,12 +237,6 @@ nm: $(KERNEL_ELF) $(call color_header, "Launching nm") @$(DOCKER_TOOLS) $(NM_BINARY) --demangle --print-size $(KERNEL_ELF) | sort | rustfilt -##------------------------------------------------------------------------------ -## Helper target for rust-analyzer -##------------------------------------------------------------------------------ -check: - @RUSTFLAGS="$(RUSTFLAGS)" $(CHECK_CMD) --message-format=json - ##-------------------------------------------------------------------------------------------------- diff --git a/14_virtual_mem_part2_mmio_remap/.vscode/settings.json b/14_virtual_mem_part2_mmio_remap/.vscode/settings.json index 0a8d7c09..292bf2a9 100644 --- a/14_virtual_mem_part2_mmio_remap/.vscode/settings.json +++ b/14_virtual_mem_part2_mmio_remap/.vscode/settings.json @@ -3,7 +3,8 @@ "editor.rulers": [100], "rust-analyzer.cargo.target": "aarch64-unknown-none-softfloat", "rust-analyzer.cargo.features": ["bsp_rpi3"], - "rust-analyzer.checkOnSave.overrideCommand": ["make", "check"], + "rust-analyzer.checkOnSave.allTargets": false, + "rust-analyzer.checkOnSave.extraArgs": ["--lib", "--bins"], "rust-analyzer.lens.debug": false, "rust-analyzer.lens.run": false } diff --git a/14_virtual_mem_part2_mmio_remap/Makefile b/14_virtual_mem_part2_mmio_remap/Makefile index 427c9303..50986ce2 100644 --- a/14_virtual_mem_part2_mmio_remap/Makefile +++ b/14_virtual_mem_part2_mmio_remap/Makefile @@ -237,12 +237,6 @@ nm: $(KERNEL_ELF) $(call color_header, "Launching nm") @$(DOCKER_TOOLS) $(NM_BINARY) --demangle --print-size $(KERNEL_ELF) | sort | rustfilt -##------------------------------------------------------------------------------ -## Helper target for rust-analyzer -##------------------------------------------------------------------------------ -check: - @RUSTFLAGS="$(RUSTFLAGS)" $(CHECK_CMD) --message-format=json - ##-------------------------------------------------------------------------------------------------- diff --git a/15_virtual_mem_part3_precomputed_tables/.vscode/settings.json b/15_virtual_mem_part3_precomputed_tables/.vscode/settings.json index 0a8d7c09..292bf2a9 100644 --- a/15_virtual_mem_part3_precomputed_tables/.vscode/settings.json +++ b/15_virtual_mem_part3_precomputed_tables/.vscode/settings.json @@ -3,7 +3,8 @@ "editor.rulers": [100], "rust-analyzer.cargo.target": "aarch64-unknown-none-softfloat", "rust-analyzer.cargo.features": ["bsp_rpi3"], - "rust-analyzer.checkOnSave.overrideCommand": ["make", "check"], + "rust-analyzer.checkOnSave.allTargets": false, + "rust-analyzer.checkOnSave.extraArgs": ["--lib", "--bins"], "rust-analyzer.lens.debug": false, "rust-analyzer.lens.run": false } diff --git a/15_virtual_mem_part3_precomputed_tables/Makefile b/15_virtual_mem_part3_precomputed_tables/Makefile index 81de6005..5c11f99e 100644 --- a/15_virtual_mem_part3_precomputed_tables/Makefile +++ b/15_virtual_mem_part3_precomputed_tables/Makefile @@ -253,12 +253,6 @@ nm: $(KERNEL_ELF) $(call color_header, "Launching nm") @$(DOCKER_TOOLS) $(NM_BINARY) --demangle --print-size $(KERNEL_ELF) | sort | rustfilt -##------------------------------------------------------------------------------ -## Helper target for rust-analyzer -##------------------------------------------------------------------------------ -check: - @RUSTFLAGS="$(RUSTFLAGS)" $(CHECK_CMD) --message-format=json - ##-------------------------------------------------------------------------------------------------- diff --git a/15_virtual_mem_part3_precomputed_tables/README.md b/15_virtual_mem_part3_precomputed_tables/README.md index 8cd644f4..9072bac4 100644 --- a/15_virtual_mem_part3_precomputed_tables/README.md +++ b/15_virtual_mem_part3_precomputed_tables/README.md @@ -1893,7 +1893,7 @@ diff -uNr 14_virtual_mem_part2_mmio_remap/Makefile 15_virtual_mem_part3_precompu $(call color_progress_prefix, "Name") @echo $(KERNEL_BIN) $(call color_progress_prefix, "Size") -@@ -308,6 +324,7 @@ +@@ -302,6 +318,7 @@ TEST_ELF=$$(echo $$1 | sed -e 's/.*target/target/g') TEST_BINARY=$$(echo $$1.img | sed -e 's/.*target/target/g') diff --git a/16_virtual_mem_part4_higher_half_kernel/.vscode/settings.json b/16_virtual_mem_part4_higher_half_kernel/.vscode/settings.json index 0a8d7c09..292bf2a9 100644 --- a/16_virtual_mem_part4_higher_half_kernel/.vscode/settings.json +++ b/16_virtual_mem_part4_higher_half_kernel/.vscode/settings.json @@ -3,7 +3,8 @@ "editor.rulers": [100], "rust-analyzer.cargo.target": "aarch64-unknown-none-softfloat", "rust-analyzer.cargo.features": ["bsp_rpi3"], - "rust-analyzer.checkOnSave.overrideCommand": ["make", "check"], + "rust-analyzer.checkOnSave.allTargets": false, + "rust-analyzer.checkOnSave.extraArgs": ["--lib", "--bins"], "rust-analyzer.lens.debug": false, "rust-analyzer.lens.run": false } diff --git a/16_virtual_mem_part4_higher_half_kernel/Makefile b/16_virtual_mem_part4_higher_half_kernel/Makefile index 81de6005..5c11f99e 100644 --- a/16_virtual_mem_part4_higher_half_kernel/Makefile +++ b/16_virtual_mem_part4_higher_half_kernel/Makefile @@ -253,12 +253,6 @@ nm: $(KERNEL_ELF) $(call color_header, "Launching nm") @$(DOCKER_TOOLS) $(NM_BINARY) --demangle --print-size $(KERNEL_ELF) | sort | rustfilt -##------------------------------------------------------------------------------ -## Helper target for rust-analyzer -##------------------------------------------------------------------------------ -check: - @RUSTFLAGS="$(RUSTFLAGS)" $(CHECK_CMD) --message-format=json - ##-------------------------------------------------------------------------------------------------- diff --git a/X1_JTAG_boot/.vscode/settings.json b/X1_JTAG_boot/.vscode/settings.json index 0a8d7c09..292bf2a9 100644 --- a/X1_JTAG_boot/.vscode/settings.json +++ b/X1_JTAG_boot/.vscode/settings.json @@ -3,7 +3,8 @@ "editor.rulers": [100], "rust-analyzer.cargo.target": "aarch64-unknown-none-softfloat", "rust-analyzer.cargo.features": ["bsp_rpi3"], - "rust-analyzer.checkOnSave.overrideCommand": ["make", "check"], + "rust-analyzer.checkOnSave.allTargets": false, + "rust-analyzer.checkOnSave.extraArgs": ["--lib", "--bins"], "rust-analyzer.lens.debug": false, "rust-analyzer.lens.run": false } diff --git a/X1_JTAG_boot/Makefile b/X1_JTAG_boot/Makefile index d127c422..d5395011 100644 --- a/X1_JTAG_boot/Makefile +++ b/X1_JTAG_boot/Makefile @@ -214,12 +214,6 @@ nm: $(KERNEL_ELF) $(call color_header, "Launching nm") @$(DOCKER_TOOLS) $(NM_BINARY) --demangle --print-size $(KERNEL_ELF) | sort | rustfilt -##------------------------------------------------------------------------------ -## Helper target for rust-analyzer -##------------------------------------------------------------------------------ -check: - @RUSTFLAGS="$(RUSTFLAGS)" $(CHECK_CMD) --message-format=json - ##-------------------------------------------------------------------------------------------------- From 9785300ab44b5d8098fc75a7ba8da7a6d61d0826 Mon Sep 17 00:00:00 2001 From: Andre Richter Date: Fri, 22 Apr 2022 23:10:03 +0200 Subject: [PATCH 10/75] Fix newest rubocop complaints --- .rubocop.yml | 2 +- common/tests/test.rb | 2 -- utils/devtool.rb | 6 +++--- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/.rubocop.yml b/.rubocop.yml index b0f756ac..1de61528 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -11,7 +11,7 @@ Layout/IndentationWidth: Width: 4 - IgnoredPatterns: ['^\s*module'] + AllowedPatterns: ['^\s*module'] Layout/LineLength: Max: 100 diff --git a/common/tests/test.rb b/common/tests/test.rb index 7ba5b7c4..d102ecd9 100644 --- a/common/tests/test.rb +++ b/common/tests/test.rb @@ -8,7 +8,6 @@ class Test INDENT = ' ' - # rubocop:disable Style/RedundantInitialize def initialize # Template instance variables. # @test_name @@ -16,7 +15,6 @@ class Test # @test_output # @test_error end - # rubocop:enable Style/RedundantInitialize private diff --git a/utils/devtool.rb b/utils/devtool.rb index 9473ff8d..7c02e9ba 100755 --- a/utils/devtool.rb +++ b/utils/devtool.rb @@ -94,11 +94,11 @@ class TutorialCrate private def boot_test? - Dir.exist?("#{@folder}/tests") + Dir.exist?("#{@folder}/kernel/tests") end def unit_integration_tests? - !Dir.glob("#{@folder}/tests/00_*.rs").empty? + !Dir.glob("#{@folder}/kernel/tests/00_*.rs").empty? end end @@ -233,7 +233,7 @@ class DevTool SUPPORTED_BSPS = %w[rpi3 rpi4].freeze def bsp_from_env - bsp = ENV['BSP'] + bsp = ENV.fetch('BSP', nil) return bsp if SUPPORTED_BSPS.include?(bsp) From 8d87d2c847a8768bec8282edec5a52cc633cc2c2 Mon Sep 17 00:00:00 2001 From: Andre Richter Date: Mon, 25 Apr 2022 23:22:50 +0200 Subject: [PATCH 11/75] minor cosmetics --- 12_integrated_testing/kernel/Cargo.toml | 1 - .../kernel/Cargo.toml | 1 - 14_virtual_mem_part2_mmio_remap/kernel/Cargo.toml | 1 - 15_virtual_mem_part3_precomputed_tables/Makefile | 7 +++++-- 15_virtual_mem_part3_precomputed_tables/README.md | 15 +++++++++------ .../kernel/Cargo.toml | 1 - 16_virtual_mem_part4_higher_half_kernel/Makefile | 7 +++++-- .../kernel/Cargo.toml | 1 - 8 files changed, 19 insertions(+), 15 deletions(-) diff --git a/12_integrated_testing/kernel/Cargo.toml b/12_integrated_testing/kernel/Cargo.toml index be478e85..864cfb61 100644 --- a/12_integrated_testing/kernel/Cargo.toml +++ b/12_integrated_testing/kernel/Cargo.toml @@ -4,7 +4,6 @@ version = "0.12.0" authors = ["Andre Richter "] edition = "2021" - [features] default = [] bsp_rpi3 = ["tock-registers"] diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/Cargo.toml b/13_exceptions_part2_peripheral_IRQs/kernel/Cargo.toml index 1d99ad38..f45458f9 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/Cargo.toml +++ b/13_exceptions_part2_peripheral_IRQs/kernel/Cargo.toml @@ -4,7 +4,6 @@ version = "0.13.0" authors = ["Andre Richter "] edition = "2021" - [features] default = [] bsp_rpi3 = ["tock-registers"] diff --git a/14_virtual_mem_part2_mmio_remap/kernel/Cargo.toml b/14_virtual_mem_part2_mmio_remap/kernel/Cargo.toml index deb0c8bc..f187a467 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/Cargo.toml +++ b/14_virtual_mem_part2_mmio_remap/kernel/Cargo.toml @@ -4,7 +4,6 @@ version = "0.14.0" authors = ["Andre Richter "] edition = "2021" - [features] default = [] bsp_rpi3 = ["tock-registers"] diff --git a/15_virtual_mem_part3_precomputed_tables/Makefile b/15_virtual_mem_part3_precomputed_tables/Makefile index 5c11f99e..85b8ca38 100644 --- a/15_virtual_mem_part3_precomputed_tables/Makefile +++ b/15_virtual_mem_part3_precomputed_tables/Makefile @@ -71,13 +71,16 @@ KERNEL_MANIFEST = kernel/Cargo.toml KERNEL_LINKER_SCRIPT = kernel.ld LAST_BUILD_CONFIG = target/$(BSP).build_config -TT_TOOL_PATH = tools/translation_table_tool - KERNEL_ELF_RAW = target/$(TARGET)/release/kernel # This parses cargo's dep-info file. # https://doc.rust-lang.org/cargo/guide/build-cache.html#dep-info-files KERNEL_ELF_RAW_DEPS = $(filter-out %: ,$(file < $(KERNEL_ELF_RAW).d)) $(LAST_BUILD_CONFIG) +##------------------------------------------------------------------------------ +## Translation tables +##------------------------------------------------------------------------------ +TT_TOOL_PATH = tools/translation_table_tool + KERNEL_ELF_TTABLES = target/$(TARGET)/release/kernel+ttables KERNEL_ELF_TTABLES_DEPS = $(KERNEL_ELF_RAW) $(wildcard $(TT_TOOL_PATH)/*) diff --git a/15_virtual_mem_part3_precomputed_tables/README.md b/15_virtual_mem_part3_precomputed_tables/README.md index 9072bac4..b09b265b 100644 --- a/15_virtual_mem_part3_precomputed_tables/README.md +++ b/15_virtual_mem_part3_precomputed_tables/README.md @@ -1837,19 +1837,22 @@ diff -uNr 14_virtual_mem_part2_mmio_remap/kernel/tests/04_exception_irq_sanity.r diff -uNr 14_virtual_mem_part2_mmio_remap/Makefile 15_virtual_mem_part3_precomputed_tables/Makefile --- 14_virtual_mem_part2_mmio_remap/Makefile +++ 15_virtual_mem_part3_precomputed_tables/Makefile -@@ -71,10 +71,17 @@ +@@ -71,10 +71,20 @@ KERNEL_LINKER_SCRIPT = kernel.ld LAST_BUILD_CONFIG = target/$(BSP).build_config -KERNEL_ELF = target/$(TARGET)/release/kernel -+TT_TOOL_PATH = tools/translation_table_tool -+ +KERNEL_ELF_RAW = target/$(TARGET)/release/kernel # This parses cargo's dep-info file. # https://doc.rust-lang.org/cargo/guide/build-cache.html#dep-info-files -KERNEL_ELF_DEPS = $(filter-out modulo: ,$(file < $(KERNEL_ELF_RAW).d)) $(LAST_BUILD_CONFIG) +KERNEL_ELF_RAW_DEPS = $(filter-out modulo: ,$(file < $(KERNEL_ELF_RAW).d)) $(LAST_BUILD_CONFIG) + ++##------------------------------------------------------------------------------ ++## Translation tables ++##------------------------------------------------------------------------------ ++TT_TOOL_PATH = tools/translation_table_tool ++ +KERNEL_ELF_TTABLES = target/$(TARGET)/release/kernel+ttables +KERNEL_ELF_TTABLES_DEPS = $(KERNEL_ELF_RAW) $(wildcard $(TT_TOOL_PATH)/*) + @@ -1857,7 +1860,7 @@ diff -uNr 14_virtual_mem_part2_mmio_remap/Makefile 15_virtual_mem_part3_precompu -@@ -104,6 +111,7 @@ +@@ -104,6 +114,7 @@ -O binary EXEC_QEMU = $(QEMU_BINARY) -M $(QEMU_MACHINE_TYPE) @@ -1865,7 +1868,7 @@ diff -uNr 14_virtual_mem_part2_mmio_remap/Makefile 15_virtual_mem_part3_precompu EXEC_TEST_DISPATCH = ruby ../common/tests/dispatch.rb EXEC_MINIPUSH = ruby ../common/serial/minipush.rb -@@ -154,16 +162,24 @@ +@@ -154,16 +165,24 @@ ##------------------------------------------------------------------------------ ## Compile the kernel ELF ##------------------------------------------------------------------------------ @@ -1893,7 +1896,7 @@ diff -uNr 14_virtual_mem_part2_mmio_remap/Makefile 15_virtual_mem_part3_precompu $(call color_progress_prefix, "Name") @echo $(KERNEL_BIN) $(call color_progress_prefix, "Size") -@@ -302,6 +318,7 @@ +@@ -302,6 +321,7 @@ TEST_ELF=$$(echo $$1 | sed -e 's/.*target/target/g') TEST_BINARY=$$(echo $$1.img | sed -e 's/.*target/target/g') diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/Cargo.toml b/15_virtual_mem_part3_precomputed_tables/kernel/Cargo.toml index 0d675c93..4641b0e8 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/Cargo.toml +++ b/15_virtual_mem_part3_precomputed_tables/kernel/Cargo.toml @@ -4,7 +4,6 @@ version = "0.15.0" authors = ["Andre Richter "] edition = "2021" - [features] default = [] bsp_rpi3 = ["tock-registers"] diff --git a/16_virtual_mem_part4_higher_half_kernel/Makefile b/16_virtual_mem_part4_higher_half_kernel/Makefile index 5c11f99e..85b8ca38 100644 --- a/16_virtual_mem_part4_higher_half_kernel/Makefile +++ b/16_virtual_mem_part4_higher_half_kernel/Makefile @@ -71,13 +71,16 @@ KERNEL_MANIFEST = kernel/Cargo.toml KERNEL_LINKER_SCRIPT = kernel.ld LAST_BUILD_CONFIG = target/$(BSP).build_config -TT_TOOL_PATH = tools/translation_table_tool - KERNEL_ELF_RAW = target/$(TARGET)/release/kernel # This parses cargo's dep-info file. # https://doc.rust-lang.org/cargo/guide/build-cache.html#dep-info-files KERNEL_ELF_RAW_DEPS = $(filter-out %: ,$(file < $(KERNEL_ELF_RAW).d)) $(LAST_BUILD_CONFIG) +##------------------------------------------------------------------------------ +## Translation tables +##------------------------------------------------------------------------------ +TT_TOOL_PATH = tools/translation_table_tool + KERNEL_ELF_TTABLES = target/$(TARGET)/release/kernel+ttables KERNEL_ELF_TTABLES_DEPS = $(KERNEL_ELF_RAW) $(wildcard $(TT_TOOL_PATH)/*) diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/Cargo.toml b/16_virtual_mem_part4_higher_half_kernel/kernel/Cargo.toml index d58c2f09..28f87a50 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/Cargo.toml +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/Cargo.toml @@ -4,7 +4,6 @@ version = "0.16.0" authors = ["Andre Richter "] edition = "2021" - [features] default = [] bsp_rpi3 = ["tock-registers"] From 067589b0cf240b2e2152d560089b43f1d3a9bf88 Mon Sep 17 00:00:00 2001 From: Andre Richter Date: Mon, 25 Apr 2022 23:23:26 +0200 Subject: [PATCH 12/75] Add tutorial 17 --- .editorconfig | 2 +- 17_kernel_symbols/.cargo/config.toml | 2 + 17_kernel_symbols/.vscode/settings.json | 10 + 17_kernel_symbols/Cargo.lock | 96 ++ 17_kernel_symbols/Cargo.toml | 10 + 17_kernel_symbols/Makefile | 389 ++++++++ 17_kernel_symbols/README.md | 927 ++++++++++++++++++ 17_kernel_symbols/kernel/Cargo.toml | 58 ++ 17_kernel_symbols/kernel/build.rs | 20 + .../kernel/src/_arch/aarch64/cpu.rs | 49 + .../kernel/src/_arch/aarch64/cpu/boot.rs | 95 ++ .../kernel/src/_arch/aarch64/cpu/boot.s | 100 ++ .../kernel/src/_arch/aarch64/cpu/smp.rs | 30 + .../kernel/src/_arch/aarch64/exception.rs | 321 ++++++ .../kernel/src/_arch/aarch64/exception.s | 150 +++ .../_arch/aarch64/exception/asynchronous.rs | 152 +++ .../kernel/src/_arch/aarch64/memory/mmu.rs | 158 +++ .../aarch64/memory/mmu/translation_table.rs | 521 ++++++++++ .../kernel/src/_arch/aarch64/time.rs | 121 +++ 17_kernel_symbols/kernel/src/bsp.rs | 13 + .../kernel/src/bsp/device_driver.rs | 16 + .../kernel/src/bsp/device_driver/arm.rs | 9 + .../kernel/src/bsp/device_driver/arm/gicv2.rs | 246 +++++ .../src/bsp/device_driver/arm/gicv2/gicc.rs | 156 +++ .../src/bsp/device_driver/arm/gicv2/gicd.rs | 209 ++++ .../kernel/src/bsp/device_driver/bcm.rs | 15 + .../src/bsp/device_driver/bcm/bcm2xxx_gpio.rs | 259 +++++ .../bcm/bcm2xxx_interrupt_controller.rs | 138 +++ .../peripheral_ic.rs | 192 ++++ .../device_driver/bcm/bcm2xxx_pl011_uart.rs | 536 ++++++++++ .../kernel/src/bsp/device_driver/common.rs | 38 + .../kernel/src/bsp/raspberrypi.rs | 62 ++ .../kernel/src/bsp/raspberrypi/console.rs | 98 ++ .../kernel/src/bsp/raspberrypi/cpu.rs | 14 + .../kernel/src/bsp/raspberrypi/driver.rs | 61 ++ .../kernel/src/bsp/raspberrypi/exception.rs | 7 + .../bsp/raspberrypi/exception/asynchronous.rs | 36 + .../kernel/src/bsp/raspberrypi/kernel.ld | 114 +++ .../kernel_virt_addr_space_size.ld | 1 + .../kernel/src/bsp/raspberrypi/memory.rs | 227 +++++ .../kernel/src/bsp/raspberrypi/memory/mmu.rs | 179 ++++ 17_kernel_symbols/kernel/src/common.rs | 29 + 17_kernel_symbols/kernel/src/console.rs | 53 + 17_kernel_symbols/kernel/src/cpu.rs | 21 + 17_kernel_symbols/kernel/src/cpu/boot.rs | 9 + 17_kernel_symbols/kernel/src/cpu/smp.rs | 14 + 17_kernel_symbols/kernel/src/driver.rs | 62 ++ 17_kernel_symbols/kernel/src/exception.rs | 48 + .../kernel/src/exception/asynchronous.rs | 152 +++ 17_kernel_symbols/kernel/src/lib.rs | 185 ++++ 17_kernel_symbols/kernel/src/main.rs | 109 ++ 17_kernel_symbols/kernel/src/memory.rs | 167 ++++ 17_kernel_symbols/kernel/src/memory/mmu.rs | 270 +++++ .../kernel/src/memory/mmu/alloc.rs | 70 ++ .../kernel/src/memory/mmu/mapping_record.rs | 233 +++++ .../src/memory/mmu/translation_table.rs | 137 +++ .../kernel/src/memory/mmu/types.rs | 378 +++++++ 17_kernel_symbols/kernel/src/panic_wait.rs | 104 ++ 17_kernel_symbols/kernel/src/print.rs | 94 ++ 17_kernel_symbols/kernel/src/state.rs | 92 ++ 17_kernel_symbols/kernel/src/symbols.rs | 85 ++ .../kernel/src/synchronization.rs | 159 +++ 17_kernel_symbols/kernel/src/time.rs | 37 + .../kernel/tests/00_console_sanity.rb | 48 + .../kernel/tests/00_console_sanity.rs | 39 + .../kernel/tests/01_timer_sanity.rs | 50 + .../tests/02_exception_sync_page_fault.rs | 37 + .../tests/03_exception_restore_sanity.rb | 25 + .../tests/03_exception_restore_sanity.rs | 49 + .../kernel/tests/04_exception_irq_sanity.rs | 67 ++ .../kernel/tests/boot_test_string.rb | 3 + .../kernel/tests/panic_exit_success/mod.rs | 9 + .../kernel/tests/panic_wait_forever/mod.rs | 9 + 17_kernel_symbols/kernel_symbols.mk | 103 ++ 17_kernel_symbols/kernel_symbols/Cargo.toml | 15 + 17_kernel_symbols/kernel_symbols/build.rs | 14 + .../kernel_symbols/kernel_symbols.ld | 15 + 17_kernel_symbols/kernel_symbols/src/main.rs | 16 + .../libraries/debug-symbol-types/Cargo.toml | 4 + .../libraries/debug-symbol-types/src/lib.rs | 39 + .../libraries/test-macros/Cargo.toml | 14 + .../libraries/test-macros/src/lib.rs | 29 + .../libraries/test-types/Cargo.toml | 5 + .../libraries/test-types/src/lib.rs | 16 + .../tools/kernel_symbols_tool/cmds.rb | 45 + .../tools/kernel_symbols_tool/kernel_elf.rb | 74 ++ .../tools/kernel_symbols_tool/main.rb | 47 + .../tools/translation_table_tool/arch.rb | 314 ++++++ .../tools/translation_table_tool/bsp.rb | 50 + .../tools/translation_table_tool/generic.rb | 179 ++++ .../translation_table_tool/kernel_elf.rb | 96 ++ .../tools/translation_table_tool/main.rb | 46 + 92 files changed, 9801 insertions(+), 1 deletion(-) create mode 100644 17_kernel_symbols/.cargo/config.toml create mode 100644 17_kernel_symbols/.vscode/settings.json create mode 100644 17_kernel_symbols/Cargo.lock create mode 100644 17_kernel_symbols/Cargo.toml create mode 100644 17_kernel_symbols/Makefile create mode 100644 17_kernel_symbols/README.md create mode 100644 17_kernel_symbols/kernel/Cargo.toml create mode 100644 17_kernel_symbols/kernel/build.rs create mode 100644 17_kernel_symbols/kernel/src/_arch/aarch64/cpu.rs create mode 100644 17_kernel_symbols/kernel/src/_arch/aarch64/cpu/boot.rs create mode 100644 17_kernel_symbols/kernel/src/_arch/aarch64/cpu/boot.s create mode 100644 17_kernel_symbols/kernel/src/_arch/aarch64/cpu/smp.rs create mode 100644 17_kernel_symbols/kernel/src/_arch/aarch64/exception.rs create mode 100644 17_kernel_symbols/kernel/src/_arch/aarch64/exception.s create mode 100644 17_kernel_symbols/kernel/src/_arch/aarch64/exception/asynchronous.rs create mode 100644 17_kernel_symbols/kernel/src/_arch/aarch64/memory/mmu.rs create mode 100644 17_kernel_symbols/kernel/src/_arch/aarch64/memory/mmu/translation_table.rs create mode 100644 17_kernel_symbols/kernel/src/_arch/aarch64/time.rs create mode 100644 17_kernel_symbols/kernel/src/bsp.rs create mode 100644 17_kernel_symbols/kernel/src/bsp/device_driver.rs create mode 100644 17_kernel_symbols/kernel/src/bsp/device_driver/arm.rs create mode 100644 17_kernel_symbols/kernel/src/bsp/device_driver/arm/gicv2.rs create mode 100644 17_kernel_symbols/kernel/src/bsp/device_driver/arm/gicv2/gicc.rs create mode 100644 17_kernel_symbols/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs create mode 100644 17_kernel_symbols/kernel/src/bsp/device_driver/bcm.rs create mode 100644 17_kernel_symbols/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs create mode 100644 17_kernel_symbols/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs create mode 100644 17_kernel_symbols/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs create mode 100644 17_kernel_symbols/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs create mode 100644 17_kernel_symbols/kernel/src/bsp/device_driver/common.rs create mode 100644 17_kernel_symbols/kernel/src/bsp/raspberrypi.rs create mode 100644 17_kernel_symbols/kernel/src/bsp/raspberrypi/console.rs create mode 100644 17_kernel_symbols/kernel/src/bsp/raspberrypi/cpu.rs create mode 100644 17_kernel_symbols/kernel/src/bsp/raspberrypi/driver.rs create mode 100644 17_kernel_symbols/kernel/src/bsp/raspberrypi/exception.rs create mode 100644 17_kernel_symbols/kernel/src/bsp/raspberrypi/exception/asynchronous.rs create mode 100644 17_kernel_symbols/kernel/src/bsp/raspberrypi/kernel.ld create mode 100644 17_kernel_symbols/kernel/src/bsp/raspberrypi/kernel_virt_addr_space_size.ld create mode 100644 17_kernel_symbols/kernel/src/bsp/raspberrypi/memory.rs create mode 100644 17_kernel_symbols/kernel/src/bsp/raspberrypi/memory/mmu.rs create mode 100644 17_kernel_symbols/kernel/src/common.rs create mode 100644 17_kernel_symbols/kernel/src/console.rs create mode 100644 17_kernel_symbols/kernel/src/cpu.rs create mode 100644 17_kernel_symbols/kernel/src/cpu/boot.rs create mode 100644 17_kernel_symbols/kernel/src/cpu/smp.rs create mode 100644 17_kernel_symbols/kernel/src/driver.rs create mode 100644 17_kernel_symbols/kernel/src/exception.rs create mode 100644 17_kernel_symbols/kernel/src/exception/asynchronous.rs create mode 100644 17_kernel_symbols/kernel/src/lib.rs create mode 100644 17_kernel_symbols/kernel/src/main.rs create mode 100644 17_kernel_symbols/kernel/src/memory.rs create mode 100644 17_kernel_symbols/kernel/src/memory/mmu.rs create mode 100644 17_kernel_symbols/kernel/src/memory/mmu/alloc.rs create mode 100644 17_kernel_symbols/kernel/src/memory/mmu/mapping_record.rs create mode 100644 17_kernel_symbols/kernel/src/memory/mmu/translation_table.rs create mode 100644 17_kernel_symbols/kernel/src/memory/mmu/types.rs create mode 100644 17_kernel_symbols/kernel/src/panic_wait.rs create mode 100644 17_kernel_symbols/kernel/src/print.rs create mode 100644 17_kernel_symbols/kernel/src/state.rs create mode 100644 17_kernel_symbols/kernel/src/symbols.rs create mode 100644 17_kernel_symbols/kernel/src/synchronization.rs create mode 100644 17_kernel_symbols/kernel/src/time.rs create mode 100644 17_kernel_symbols/kernel/tests/00_console_sanity.rb create mode 100644 17_kernel_symbols/kernel/tests/00_console_sanity.rs create mode 100644 17_kernel_symbols/kernel/tests/01_timer_sanity.rs create mode 100644 17_kernel_symbols/kernel/tests/02_exception_sync_page_fault.rs create mode 100644 17_kernel_symbols/kernel/tests/03_exception_restore_sanity.rb create mode 100644 17_kernel_symbols/kernel/tests/03_exception_restore_sanity.rs create mode 100644 17_kernel_symbols/kernel/tests/04_exception_irq_sanity.rs create mode 100644 17_kernel_symbols/kernel/tests/boot_test_string.rb create mode 100644 17_kernel_symbols/kernel/tests/panic_exit_success/mod.rs create mode 100644 17_kernel_symbols/kernel/tests/panic_wait_forever/mod.rs create mode 100644 17_kernel_symbols/kernel_symbols.mk create mode 100644 17_kernel_symbols/kernel_symbols/Cargo.toml create mode 100644 17_kernel_symbols/kernel_symbols/build.rs create mode 100644 17_kernel_symbols/kernel_symbols/kernel_symbols.ld create mode 100644 17_kernel_symbols/kernel_symbols/src/main.rs create mode 100644 17_kernel_symbols/libraries/debug-symbol-types/Cargo.toml create mode 100644 17_kernel_symbols/libraries/debug-symbol-types/src/lib.rs create mode 100644 17_kernel_symbols/libraries/test-macros/Cargo.toml create mode 100644 17_kernel_symbols/libraries/test-macros/src/lib.rs create mode 100644 17_kernel_symbols/libraries/test-types/Cargo.toml create mode 100644 17_kernel_symbols/libraries/test-types/src/lib.rs create mode 100644 17_kernel_symbols/tools/kernel_symbols_tool/cmds.rb create mode 100644 17_kernel_symbols/tools/kernel_symbols_tool/kernel_elf.rb create mode 100755 17_kernel_symbols/tools/kernel_symbols_tool/main.rb create mode 100644 17_kernel_symbols/tools/translation_table_tool/arch.rb create mode 100644 17_kernel_symbols/tools/translation_table_tool/bsp.rb create mode 100644 17_kernel_symbols/tools/translation_table_tool/generic.rb create mode 100644 17_kernel_symbols/tools/translation_table_tool/kernel_elf.rb create mode 100755 17_kernel_symbols/tools/translation_table_tool/main.rb diff --git a/.editorconfig b/.editorconfig index dd8892ca..4d2b34c1 100644 --- a/.editorconfig +++ b/.editorconfig @@ -13,7 +13,7 @@ max_line_length = 100 [Dockerfile] indent_size = 4 -[Makefile] +[{Makefile,*.mk}] indent_style = tab indent_size = 8 diff --git a/17_kernel_symbols/.cargo/config.toml b/17_kernel_symbols/.cargo/config.toml new file mode 100644 index 00000000..e3476485 --- /dev/null +++ b/17_kernel_symbols/.cargo/config.toml @@ -0,0 +1,2 @@ +[target.'cfg(target_os = "none")'] +runner = "target/kernel_test_runner.sh" diff --git a/17_kernel_symbols/.vscode/settings.json b/17_kernel_symbols/.vscode/settings.json new file mode 100644 index 00000000..292bf2a9 --- /dev/null +++ b/17_kernel_symbols/.vscode/settings.json @@ -0,0 +1,10 @@ +{ + "editor.formatOnSave": true, + "editor.rulers": [100], + "rust-analyzer.cargo.target": "aarch64-unknown-none-softfloat", + "rust-analyzer.cargo.features": ["bsp_rpi3"], + "rust-analyzer.checkOnSave.allTargets": false, + "rust-analyzer.checkOnSave.extraArgs": ["--lib", "--bins"], + "rust-analyzer.lens.debug": false, + "rust-analyzer.lens.run": false +} diff --git a/17_kernel_symbols/Cargo.lock b/17_kernel_symbols/Cargo.lock new file mode 100644 index 00000000..7648b5c1 --- /dev/null +++ b/17_kernel_symbols/Cargo.lock @@ -0,0 +1,96 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "cortex-a" +version = "7.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27bd91f65ccd348bb2d043d98c5b34af141ecef7f102147f59bf5898f6e734ad" +dependencies = [ + "tock-registers", +] + +[[package]] +name = "debug-symbol-types" +version = "0.1.0" + +[[package]] +name = "kernel_symbols" +version = "0.1.0" +dependencies = [ + "debug-symbol-types", +] + +[[package]] +name = "mingo" +version = "0.17.0" +dependencies = [ + "cortex-a", + "debug-symbol-types", + "qemu-exit", + "test-macros", + "test-types", + "tock-registers", +] + +[[package]] +name = "proc-macro2" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec757218438d5fda206afc041538b2f6d889286160d649a86a24d37e1235afd1" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "qemu-exit" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ff023245bfcc73fb890e1f8d5383825b3131cc920020a5c487d6f113dfc428a" + +[[package]] +name = "quote" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "syn" +version = "1.0.91" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b683b2b825c8eef438b77c36a06dc262294da3d5a5813fac20da149241dcd44d" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "test-macros" +version = "0.1.0" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "test-types", +] + +[[package]] +name = "test-types" +version = "0.1.0" + +[[package]] +name = "tock-registers" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ee8fba06c1f4d0b396ef61a54530bb6b28f0dc61c38bc8bc5a5a48161e6282e" + +[[package]] +name = "unicode-xid" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" diff --git a/17_kernel_symbols/Cargo.toml b/17_kernel_symbols/Cargo.toml new file mode 100644 index 00000000..1ea72c9f --- /dev/null +++ b/17_kernel_symbols/Cargo.toml @@ -0,0 +1,10 @@ +[workspace] + +members = [ + "libraries/*", + "kernel", + "kernel_symbols" +] + +[profile.release] +lto = true diff --git a/17_kernel_symbols/Makefile b/17_kernel_symbols/Makefile new file mode 100644 index 00000000..1e9282a2 --- /dev/null +++ b/17_kernel_symbols/Makefile @@ -0,0 +1,389 @@ +## SPDX-License-Identifier: MIT OR Apache-2.0 +## +## Copyright (c) 2018-2022 Andre Richter + +include ../common/format.mk +include ../common/docker.mk + +##-------------------------------------------------------------------------------------------------- +## Optional, user-provided configuration values +##-------------------------------------------------------------------------------------------------- + +# Default to the RPi3. +BSP ?= rpi3 + +# Default to a serial device name that is common in Linux. +DEV_SERIAL ?= /dev/ttyUSB0 + +# Optional integration test name. +ifdef TEST + TEST_ARG = --test $(TEST) +else + TEST_ARG = --test '*' +endif + + + +##-------------------------------------------------------------------------------------------------- +## BSP-specific configuration values +##-------------------------------------------------------------------------------------------------- +QEMU_MISSING_STRING = "This board is not yet supported for QEMU." + +ifeq ($(BSP),rpi3) + TARGET = aarch64-unknown-none-softfloat + KERNEL_BIN = kernel8.img + QEMU_BINARY = qemu-system-aarch64 + QEMU_MACHINE_TYPE = raspi3 + QEMU_RELEASE_ARGS = -serial stdio -display none + QEMU_TEST_ARGS = $(QEMU_RELEASE_ARGS) -semihosting + OBJDUMP_BINARY = aarch64-none-elf-objdump + NM_BINARY = aarch64-none-elf-nm + READELF_BINARY = aarch64-none-elf-readelf + OPENOCD_ARG = -f /openocd/tcl/interface/ftdi/olimex-arm-usb-tiny-h.cfg -f /openocd/rpi3.cfg + JTAG_BOOT_IMAGE = ../X1_JTAG_boot/jtag_boot_rpi3.img + LD_SCRIPT_PATH = $(shell pwd)/kernel/src/bsp/raspberrypi + RUSTC_MISC_ARGS = -C target-cpu=cortex-a53 +else ifeq ($(BSP),rpi4) + TARGET = aarch64-unknown-none-softfloat + KERNEL_BIN = kernel8.img + QEMU_BINARY = qemu-system-aarch64 + QEMU_MACHINE_TYPE = + QEMU_RELEASE_ARGS = -serial stdio -display none + QEMU_TEST_ARGS = $(QEMU_RELEASE_ARGS) -semihosting + OBJDUMP_BINARY = aarch64-none-elf-objdump + NM_BINARY = aarch64-none-elf-nm + READELF_BINARY = aarch64-none-elf-readelf + OPENOCD_ARG = -f /openocd/tcl/interface/ftdi/olimex-arm-usb-tiny-h.cfg -f /openocd/rpi4.cfg + JTAG_BOOT_IMAGE = ../X1_JTAG_boot/jtag_boot_rpi4.img + LD_SCRIPT_PATH = $(shell pwd)/kernel/src/bsp/raspberrypi + RUSTC_MISC_ARGS = -C target-cpu=cortex-a72 +endif + +# Export for build.rs. +export LD_SCRIPT_PATH + + + +##-------------------------------------------------------------------------------------------------- +## Targets and Prerequisites +##-------------------------------------------------------------------------------------------------- +KERNEL_MANIFEST = kernel/Cargo.toml +KERNEL_LINKER_SCRIPT = kernel.ld +LAST_BUILD_CONFIG = target/$(BSP).build_config + +KERNEL_ELF_RAW = target/$(TARGET)/release/kernel +# This parses cargo's dep-info file. +# https://doc.rust-lang.org/cargo/guide/build-cache.html#dep-info-files +KERNEL_ELF_RAW_DEPS = $(filter-out %: ,$(file < $(KERNEL_ELF_RAW).d)) $(LAST_BUILD_CONFIG) + +##------------------------------------------------------------------------------ +## Translation tables +##------------------------------------------------------------------------------ +TT_TOOL_PATH = tools/translation_table_tool + +KERNEL_ELF_TTABLES = target/$(TARGET)/release/kernel+ttables +KERNEL_ELF_TTABLES_DEPS = $(KERNEL_ELF_RAW) $(wildcard $(TT_TOOL_PATH)/*) + +##------------------------------------------------------------------------------ +## Kernel symbols +##------------------------------------------------------------------------------ +export KERNEL_SYMBOLS_TOOL_PATH = tools/kernel_symbols_tool + +KERNEL_ELF_TTABLES_SYMS = target/$(TARGET)/release/kernel+ttables+symbols + +# Unlike with KERNEL_ELF_RAW, we are not relying on dep-info here. One of the reasons being that the +# name of the generated symbols file varies between runs, which can cause confusion. +KERNEL_ELF_TTABLES_SYMS_DEPS = $(KERNEL_ELF_TTABLES) \ + $(wildcard kernel_symbols/*) \ + $(wildcard $(KERNEL_SYMBOLS_TOOL_PATH)/*) + +export TARGET +export KERNEL_SYMBOLS_INPUT_ELF = $(KERNEL_ELF_TTABLES) +export KERNEL_SYMBOLS_OUTPUT_ELF = $(KERNEL_ELF_TTABLES_SYMS) + +KERNEL_ELF = $(KERNEL_ELF_TTABLES_SYMS) + + + +##-------------------------------------------------------------------------------------------------- +## Command building blocks +##-------------------------------------------------------------------------------------------------- +RUSTFLAGS = $(RUSTC_MISC_ARGS) \ + -C link-arg=--library-path=$(LD_SCRIPT_PATH) \ + -C link-arg=--script=$(KERNEL_LINKER_SCRIPT) + +RUSTFLAGS_PEDANTIC = $(RUSTFLAGS) \ + -D warnings \ + -D missing_docs + +FEATURES = --features bsp_$(BSP) +COMPILER_ARGS = --target=$(TARGET) \ + $(FEATURES) \ + --release + +RUSTC_CMD = cargo rustc $(COMPILER_ARGS) --manifest-path $(KERNEL_MANIFEST) +DOC_CMD = cargo doc $(COMPILER_ARGS) +CLIPPY_CMD = cargo clippy $(COMPILER_ARGS) +CHECK_CMD = cargo check $(COMPILER_ARGS) +TEST_CMD = cargo test $(COMPILER_ARGS) --manifest-path $(KERNEL_MANIFEST) +OBJCOPY_CMD = rust-objcopy \ + --strip-all \ + -O binary + +EXEC_QEMU = $(QEMU_BINARY) -M $(QEMU_MACHINE_TYPE) +EXEC_TT_TOOL = ruby $(TT_TOOL_PATH)/main.rb +EXEC_TEST_DISPATCH = ruby ../common/tests/dispatch.rb +EXEC_MINIPUSH = ruby ../common/serial/minipush.rb + +##------------------------------------------------------------------------------ +## Dockerization +##------------------------------------------------------------------------------ +DOCKER_CMD = docker run -t --rm -v $(shell pwd):/work/tutorial -w /work/tutorial +DOCKER_CMD_INTERACT = $(DOCKER_CMD) -i +DOCKER_ARG_DIR_COMMON = -v $(shell pwd)/../common:/work/common +DOCKER_ARG_DIR_JTAG = -v $(shell pwd)/../X1_JTAG_boot:/work/X1_JTAG_boot +DOCKER_ARG_DEV = --privileged -v /dev:/dev +DOCKER_ARG_NET = --network host + +# DOCKER_IMAGE defined in include file (see top of this file). +DOCKER_QEMU = $(DOCKER_CMD_INTERACT) $(DOCKER_IMAGE) +DOCKER_TOOLS = $(DOCKER_CMD) $(DOCKER_IMAGE) +DOCKER_TEST = $(DOCKER_CMD) $(DOCKER_ARG_DIR_COMMON) $(DOCKER_IMAGE) +DOCKER_GDB = $(DOCKER_CMD_INTERACT) $(DOCKER_ARG_NET) $(DOCKER_IMAGE) + +# Dockerize commands, which require USB device passthrough, only on Linux. +ifeq ($(shell uname -s),Linux) + DOCKER_CMD_DEV = $(DOCKER_CMD_INTERACT) $(DOCKER_ARG_DEV) + + DOCKER_CHAINBOOT = $(DOCKER_CMD_DEV) $(DOCKER_ARG_DIR_COMMON) $(DOCKER_IMAGE) + DOCKER_JTAGBOOT = $(DOCKER_CMD_DEV) $(DOCKER_ARG_DIR_COMMON) $(DOCKER_ARG_DIR_JTAG) $(DOCKER_IMAGE) + DOCKER_OPENOCD = $(DOCKER_CMD_DEV) $(DOCKER_ARG_NET) $(DOCKER_IMAGE) +else + DOCKER_OPENOCD = echo "Not yet supported on non-Linux systems."; \# +endif + + + +##-------------------------------------------------------------------------------------------------- +## Targets +##-------------------------------------------------------------------------------------------------- +.PHONY: all doc qemu chainboot clippy clean readelf objdump nm check + +all: $(KERNEL_BIN) + +##------------------------------------------------------------------------------ +## Save the configuration as a file, so make understands if it changed. +##------------------------------------------------------------------------------ +$(LAST_BUILD_CONFIG): + @rm -f target/*.build_config + @mkdir -p target + @touch $(LAST_BUILD_CONFIG) + +##------------------------------------------------------------------------------ +## Compile the kernel ELF +##------------------------------------------------------------------------------ +$(KERNEL_ELF_RAW): $(KERNEL_ELF_RAW_DEPS) + $(call color_header, "Compiling kernel ELF - $(BSP)") + @RUSTFLAGS="$(RUSTFLAGS_PEDANTIC)" $(RUSTC_CMD) + +##------------------------------------------------------------------------------ +## Precompute the kernel translation tables and patch them into the kernel ELF +##------------------------------------------------------------------------------ +$(KERNEL_ELF_TTABLES): $(KERNEL_ELF_TTABLES_DEPS) + $(call color_header, "Precomputing kernel translation tables and patching kernel ELF") + @cp $(KERNEL_ELF_RAW) $(KERNEL_ELF_TTABLES) + @$(DOCKER_TOOLS) $(EXEC_TT_TOOL) $(BSP) $(KERNEL_ELF_TTABLES) + +##------------------------------------------------------------------------------ +## Generate kernel symbols and patch them into the kernel ELF +##------------------------------------------------------------------------------ +$(KERNEL_ELF_TTABLES_SYMS): $(KERNEL_ELF_TTABLES_SYMS_DEPS) + $(call color_header, "Generating kernel symbols and patching kernel ELF") + @time -f "in %es" \ + $(MAKE) --no-print-directory -f kernel_symbols.mk + +##------------------------------------------------------------------------------ +## Generate the stripped kernel binary +##------------------------------------------------------------------------------ +$(KERNEL_BIN): $(KERNEL_ELF_TTABLES_SYMS) + $(call color_header, "Generating stripped binary") + @$(OBJCOPY_CMD) $(KERNEL_ELF_TTABLES_SYMS) $(KERNEL_BIN) + $(call color_progress_prefix, "Name") + @echo $(KERNEL_BIN) + $(call color_progress_prefix, "Size") + @printf '%s KiB\n' `du -k $(KERNEL_BIN) | cut -f1` + +##------------------------------------------------------------------------------ +## Generate the documentation +##------------------------------------------------------------------------------ +doc: + $(call color_header, "Generating docs") + @$(DOC_CMD) --document-private-items --open + +##------------------------------------------------------------------------------ +## Run the kernel in QEMU +##------------------------------------------------------------------------------ +ifeq ($(QEMU_MACHINE_TYPE),) # QEMU is not supported for the board. + +qemu: + $(call color_header, "$(QEMU_MISSING_STRING)") + +else # QEMU is supported. + +qemu: $(KERNEL_BIN) + $(call color_header, "Launching QEMU") + @$(DOCKER_QEMU) $(EXEC_QEMU) $(QEMU_RELEASE_ARGS) -kernel $(KERNEL_BIN) + +endif + +##------------------------------------------------------------------------------ +## Push the kernel to the real HW target +##------------------------------------------------------------------------------ +chainboot: $(KERNEL_BIN) + @$(DOCKER_CHAINBOOT) $(EXEC_MINIPUSH) $(DEV_SERIAL) $(KERNEL_BIN) + +##------------------------------------------------------------------------------ +## Run clippy +##------------------------------------------------------------------------------ +clippy: + @RUSTFLAGS="$(RUSTFLAGS_PEDANTIC)" $(CLIPPY_CMD) + @RUSTFLAGS="$(RUSTFLAGS_PEDANTIC)" $(CLIPPY_CMD) --features test_build --tests \ + --manifest-path $(KERNEL_MANIFEST) + +##------------------------------------------------------------------------------ +## Clean +##------------------------------------------------------------------------------ +clean: + rm -rf target $(KERNEL_BIN) + +##------------------------------------------------------------------------------ +## Run readelf +##------------------------------------------------------------------------------ +readelf: $(KERNEL_ELF) + $(call color_header, "Launching readelf") + @$(DOCKER_TOOLS) $(READELF_BINARY) --headers $(KERNEL_ELF) + +##------------------------------------------------------------------------------ +## Run objdump +##------------------------------------------------------------------------------ +objdump: $(KERNEL_ELF) + $(call color_header, "Launching objdump") + @$(DOCKER_TOOLS) $(OBJDUMP_BINARY) --disassemble --demangle \ + --section .text \ + --section .rodata \ + --section .got \ + $(KERNEL_ELF) | rustfilt + +##------------------------------------------------------------------------------ +## Run nm +##------------------------------------------------------------------------------ +nm: $(KERNEL_ELF) + $(call color_header, "Launching nm") + @$(DOCKER_TOOLS) $(NM_BINARY) --demangle --print-size $(KERNEL_ELF) | sort | rustfilt + + + +##-------------------------------------------------------------------------------------------------- +## Debugging targets +##-------------------------------------------------------------------------------------------------- +.PHONY: jtagboot openocd gdb gdb-opt0 + +##------------------------------------------------------------------------------ +## Push the JTAG boot image to the real HW target +##------------------------------------------------------------------------------ +jtagboot: + @$(DOCKER_JTAGBOOT) $(EXEC_MINIPUSH) $(DEV_SERIAL) $(JTAG_BOOT_IMAGE) + +##------------------------------------------------------------------------------ +## Start OpenOCD session +##------------------------------------------------------------------------------ +openocd: + $(call color_header, "Launching OpenOCD") + @$(DOCKER_OPENOCD) openocd $(OPENOCD_ARG) + +##------------------------------------------------------------------------------ +## Start GDB session +##------------------------------------------------------------------------------ +gdb: RUSTC_MISC_ARGS += -C debuginfo=2 +gdb-opt0: RUSTC_MISC_ARGS += -C debuginfo=2 -C opt-level=0 +gdb gdb-opt0: $(KERNEL_ELF) + $(call color_header, "Launching GDB") + @$(DOCKER_GDB) gdb-multiarch -q $(KERNEL_ELF) + + + +##-------------------------------------------------------------------------------------------------- +## Testing targets +##-------------------------------------------------------------------------------------------------- +.PHONY: test test_boot test_unit test_integration + +test_unit test_integration: FEATURES += --features test_build + +ifeq ($(QEMU_MACHINE_TYPE),) # QEMU is not supported for the board. + +test_boot test_unit test_integration test: + $(call color_header, "$(QEMU_MISSING_STRING)") + +else # QEMU is supported. + +##------------------------------------------------------------------------------ +## Run boot test +##------------------------------------------------------------------------------ +test_boot: $(KERNEL_BIN) + $(call color_header, "Boot test - $(BSP)") + @$(DOCKER_TEST) $(EXEC_TEST_DISPATCH) $(EXEC_QEMU) $(QEMU_RELEASE_ARGS) -kernel $(KERNEL_BIN) + +##------------------------------------------------------------------------------ +## Helpers for unit and integration test targets +##------------------------------------------------------------------------------ +define KERNEL_TEST_RUNNER + #!/usr/bin/env bash + + # The cargo test runner seems to change into the crate under test's directory. Therefore, ensure + # this script executes from the root. + cd $(shell pwd) + + TEST_ELF=$$(echo $$1 | sed -e 's/.*target/target/g') + TEST_ELF_SYMS="$${TEST_ELF}_syms" + TEST_BINARY=$$(echo $$1.img | sed -e 's/.*target/target/g') + + $(DOCKER_TOOLS) $(EXEC_TT_TOOL) $(BSP) $$TEST_ELF > /dev/null + + # This overrides the two ENV variables. The other ENV variables that are required as input for + # the .mk file are set already because they are exported by this Makefile and this script is + # started by the same. + KERNEL_SYMBOLS_INPUT_ELF=$$TEST_ELF \ + KERNEL_SYMBOLS_OUTPUT_ELF=$$TEST_ELF_SYMS \ + $(MAKE) --no-print-directory -f kernel_symbols.mk > /dev/null 2>&1 + + $(OBJCOPY_CMD) $$TEST_ELF_SYMS $$TEST_BINARY + $(DOCKER_TEST) $(EXEC_TEST_DISPATCH) $(EXEC_QEMU) $(QEMU_TEST_ARGS) -kernel $$TEST_BINARY +endef + +export KERNEL_TEST_RUNNER + +define test_prepare + @mkdir -p target + @echo "$$KERNEL_TEST_RUNNER" > target/kernel_test_runner.sh + @chmod +x target/kernel_test_runner.sh +endef + +##------------------------------------------------------------------------------ +## Run unit test(s) +##------------------------------------------------------------------------------ +test_unit: + $(call color_header, "Compiling unit test(s) - $(BSP)") + $(call test_prepare) + @RUSTFLAGS="$(RUSTFLAGS_PEDANTIC)" $(TEST_CMD) --lib + +##------------------------------------------------------------------------------ +## Run integration test(s) +##------------------------------------------------------------------------------ +test_integration: + $(call color_header, "Compiling integration test(s) - $(BSP)") + $(call test_prepare) + @RUSTFLAGS="$(RUSTFLAGS_PEDANTIC)" $(TEST_CMD) $(TEST_ARG) + +test: test_boot test_unit test_integration + +endif diff --git a/17_kernel_symbols/README.md b/17_kernel_symbols/README.md new file mode 100644 index 00000000..72428c23 --- /dev/null +++ b/17_kernel_symbols/README.md @@ -0,0 +1,927 @@ +# Tutorial 17 - Kernel Symbols + +## tl;dr + +- To enrich and augment existing and future debugging code, we add support for `kernel symbol` + lookup. + +## Table of Contents + +- [Introduction](#introduction) +- [Implementation](#implementation) + - [Linking Changes](#linking-changes) + - [Kernel Symbols Tool](#kernel-symbols-tool) + - [Lookup Code](#lookup-code) +- [Test it](#test-it) +- [Diff to previous](#diff-to-previous) + +## Introduction + +Ever since the first tutorial, it was possible to execute the `make nm` target in order to view all +`kernel symbols`. The kernel itself, however, does not have any means yet to correlate a virtual +address to a symbol during runtime. Gaining this capability would be useful for augmenting +debug-related prints. For example, when the kernel is handling an `exception`, it prints the content +of the `exception link register`, which is the program address where the CPU was executing from when +the exception happened. + +Until now, in order to understand to which function or code such an address belongs to, a manual +lookup by the person debugging the issue was necessary. In this tutorial, we are adding a `data +structure` to the kernel which contains _all the symbol names and corresponding address ranges_. +This enables the kernel to print symbol names in existing and future debug-related code, which +improves triaging of issues by humans, because it does away with the manual lookup. + +This tutorial is mostly is an enabler for the upcoming tutorial that will add [`backtracing`] +support. + +[`backtracing`]: https://en.wikipedia.org/wiki/Stack_trace + +## Implementation + +First of all, a new support crate is added under `$ROOT/libraries/debug-symbol-types`. It contains +the definition for `struct Symbol`: + +```rust +/// A symbol containing a size. +#[repr(C)] +pub struct Symbol { + addr_range: Range, + name: &'static str, +} +``` + +The implementation of the struct furthermore defines the two public functions `name()` and +`contains()`, which will be used to query information. + +To enable the kernel to lookup symbol names, we will add an `array` to the kernel binary that +contains all the kernel symbols. Because we can query the final symbol names and addresses only +_after_ the kernel has been `linked`, the same approach as for the `translation tables` will be +used: The symbols array will be patched into a `placeholder section` of the final kernel `ELF`. + +### Linking Changes + +In the `kernel.ld` linker script, we define a new section named `kernel_symbols` and give it a size +of `32 KiB`: + +```ld.s + .rodata : ALIGN(8) { *(.rodata*) } :segment_code + .got : ALIGN(8) { *(.got) } :segment_code + .kernel_symbols : ALIGN(8) { + __kernel_symbols_start = .; + . += 32 * 1024; + } :segment_code +``` + +Also, we are providing the start address of the section through the symbol `__kernel_symbols_start`, +which will be used by our `Rust` code later on. + +### Kernel Symbols Tool + +Under `$ROOT/tools/kernel_symbols_tool`, we are adding a helper tool that is able to dynamically +generate an `array` of all the kernel symbols and patch it into the final kernel `ELF`. In our main +`Makefile`, we are invoking the tool after the translation table generation. In the first step, the +tool generates a temporary `Rust` file that instantiates the symbols array. Here is an example of +how this can look like: + +```console +$ head ./target/aarch64-unknown-none-softfloat/release/kernel+ttables_symbols_demangled.rs +``` +```rust +use debug_symbol_types::Symbol; + +# [no_mangle] +# [link_section = ".rodata.symbol_desc"] +static KERNEL_SYMBOLS: [Symbol; 139] = [ + Symbol::new(18446744072635809792, 124, "_start"), + Symbol::new(18446744072635809920, 8, "BOOT_CORE_ID"), + Symbol::new(18446744072635809928, 8, "PHYS_KERNEL_TABLES_BASE_ADDR"), + Symbol::new(18446744072635809936, 80, "_start_rust"), + Symbol::new(18446744072635813888, 84, "__exception_restore_context"), + // Many more +``` + +Next, the _helper crate_ `$ROOT/kernel_symbols` is compiled. This crate contains a single `main.rs` +that just includes the temporary symbols file shown above. + +```rust +//! Generation of kernel symbols. + +#![no_std] +#![no_main] + +#[cfg(feature = "generated_symbols_available")] +include!(env!("KERNEL_SYMBOLS_DEMANGLED_RS")); +``` + +`KERNEL_SYMBOLS_DEMANGLED_RS` is set by the corresponding `build.rs` file. The helper crate has its +own `linker file`, which ensures that that just the array and the corresponding strings that it +references are kept: + +```ld.s +SECTIONS +{ + .rodata : { + ASSERT(. > 0xffffffff00000000, "Expected higher half address") + + KEEP(*(.rodata.symbol_desc*)) + . = ALIGN(8); + *(.rodata*) + } +} +``` + +Afterwards, `objcopy` is used to strip the produced helper crate ELF. What remains is a small +`binary blob` that just contains the symbols array and the `names` that are referenced. To ensure +that these references are valid kernel addresses (remember that those are defined as `name: &'static +str`, so basically a pointer to a kernel address), the sub-makefile compiling this helper crate +(`$ROOT/kernel_symbols.mk`) did the following: + +It used the `kernel_symbols_tool` to query the virtual address of the `kernel_symbols` **section** +(of the final kernel ELF). This address was then supplied to the linker when the helper crate was +linked (emphasis on the `--section-start=.rodata=` part): + +```Makefile +GET_SYMBOLS_SECTION_VIRT_ADDR = $(DOCKER_TOOLS) $(EXEC_SYMBOLS_TOOL) \ + --get_symbols_section_virt_addr $(KERNEL_SYMBOLS_OUTPUT_ELF) + +RUSTFLAGS = -C link-arg=--script=$(KERNEL_SYMBOLS_LINKER_SCRIPT) \ + -C link-arg=--section-start=.rodata=$$($(GET_SYMBOLS_SECTION_VIRT_ADDR)) +``` + +This might be a bit convoluted, but the main take away is: This ensures that the start address of +the `.rodata` section of the `kernel_symbols` helper crate is exactly the same address as the +`placeholder section` of the final kernel ELF where the symbols `binary blob` will be patched into. +The latter is the last step done by the tool. + +### Lookup Code + +In the kernel, we add the file `src/symbols.rs`. It makes the linker-provided symbol +`__kernel_symbols_start` that we saw earlier accesible, and also defines `NUM_KERNEL_SYMBOLS`: + +```rust +#[no_mangle] +static NUM_KERNEL_SYMBOLS: u64 = 0; +``` + +When the `kernel_symbols_tool` patches the symbols blob into the kernel ELF, it also updates this +value to reflect the number of symbols that are available. This is needed for the code that +internally crafts the slice of symbols that the kernel uses for lookup: + +```rust +fn kernel_symbol_section_virt_start_addr() -> Address { + Address::new(unsafe { __kernel_symbols_start.get() as usize }) +} + +fn kernel_symbols_slice() -> &'static [Symbol] { + let ptr = kernel_symbol_section_virt_start_addr().as_usize() as *const Symbol; + + unsafe { + let num = core::ptr::read_volatile(&NUM_KERNEL_SYMBOLS as *const u64) as usize; + slice::from_raw_parts(ptr, num) + } +} +``` + +Lookup is done by just iterating over the slice: + +```rust +/// Retrieve the symbol name corresponding to a virtual address, if any. +pub fn lookup_symbol(addr: Address) -> Option<&'static str> { + for i in kernel_symbols_slice() { + if i.contains(addr.as_usize()) { + return Some(i.name()); + } + } + + None +} +``` + +And that's it for this tutorial. The upcoming tutorial on `backtracing` will put this code to more +prominent use. + +## Test it + +For now, symbol lookup can be observed in the integration test for synchronous exception handling. +Here, the kernel now also prints the symbol name that corresponds to the value of `ELR_EL1`. In the +following case, this is `kernel_init()`, which is where the the exception is generated in the test: + +```console +$ TEST=02_exception_sync_page_fault make test_integration +[...] + ------------------------------------------------------------------- + 🦀 Testing synchronous exception handling by causing a page fault + ------------------------------------------------------------------- + + [ 0.002640] Writing to bottom of address space to address 1 GiB... + [ 0.004549] Kernel panic! + + Panic location: + File 'kernel/src/_arch/aarch64/exception.rs', line 59, column 5 + + CPU Exception! + + ESR_EL1: 0x96000004 + + ... + + ELR_EL1: 0xffffffffc0001118 + Symbol: kernel_init +``` + +## Diff to previous +```diff + +diff -uNr 16_virtual_mem_part4_higher_half_kernel/Cargo.toml 17_kernel_symbols/Cargo.toml +--- 16_virtual_mem_part4_higher_half_kernel/Cargo.toml ++++ 17_kernel_symbols/Cargo.toml +@@ -2,7 +2,8 @@ + + members = [ + "libraries/*", +- "kernel" ++ "kernel", ++ "kernel_symbols" + ] + + [profile.release] + +diff -uNr 16_virtual_mem_part4_higher_half_kernel/kernel/Cargo.toml 17_kernel_symbols/kernel/Cargo.toml +--- 16_virtual_mem_part4_higher_half_kernel/kernel/Cargo.toml ++++ 17_kernel_symbols/kernel/Cargo.toml +@@ -1,6 +1,6 @@ + [package] + name = "mingo" +-version = "0.16.0" ++version = "0.17.0" + authors = ["Andre Richter "] + edition = "2021" + +@@ -16,6 +16,7 @@ + + [dependencies] + test-types = { path = "../libraries/test-types" } ++debug-symbol-types = { path = "../libraries/debug-symbol-types" } + + # Optional dependencies + tock-registers = { version = "0.7.x", default-features = false, features = ["register_types"], optional = true } + +diff -uNr 16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/exception.rs 17_kernel_symbols/kernel/src/_arch/aarch64/exception.rs +--- 16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/exception.rs ++++ 17_kernel_symbols/kernel/src/_arch/aarch64/exception.rs +@@ -11,7 +11,7 @@ + //! + //! crate::exception::arch_exception + +-use crate::{bsp, exception}; ++use crate::{bsp, exception, memory, symbols}; + use core::{arch::global_asm, cell::UnsafeCell, fmt}; + use cortex_a::{asm::barrier, registers::*}; + use tock_registers::{ +@@ -262,6 +262,12 @@ + + writeln!(f, "{}", self.spsr_el1)?; + writeln!(f, "ELR_EL1: {:#018x}", self.elr_el1)?; ++ writeln!( ++ f, ++ " Symbol: {}", ++ symbols::lookup_symbol(memory::Address::new(self.elr_el1 as usize)) ++ .unwrap_or("Symbol not found") ++ )?; + writeln!(f)?; + writeln!(f, "General purpose register:")?; + + +diff -uNr 16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi/kernel.ld 17_kernel_symbols/kernel/src/bsp/raspberrypi/kernel.ld +--- 16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi/kernel.ld ++++ 17_kernel_symbols/kernel/src/bsp/raspberrypi/kernel.ld +@@ -56,8 +56,12 @@ + *(.text*) /* Everything else */ + } :segment_code + +- .rodata : ALIGN(8) { *(.rodata*) } :segment_code +- .got : ALIGN(8) { *(.got) } :segment_code ++ .rodata : ALIGN(8) { *(.rodata*) } :segment_code ++ .got : ALIGN(8) { *(.got) } :segment_code ++ .kernel_symbols : ALIGN(8) { ++ __kernel_symbols_start = .; ++ . += 32 * 1024; ++ } :segment_code + + . = ALIGN(PAGE_SIZE); + __code_end_exclusive = .; + +diff -uNr 16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi/memory.rs 17_kernel_symbols/kernel/src/bsp/raspberrypi/memory.rs +--- 16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi/memory.rs ++++ 17_kernel_symbols/kernel/src/bsp/raspberrypi/memory.rs +@@ -20,6 +20,7 @@ + //! | .text | + //! | .rodata | + //! | .got | ++//! | .kernel_symbols | + //! | | + //! +---------------------------------------+ + //! | | data_start == code_end_exclusive +@@ -41,6 +42,7 @@ + //! | .text | + //! | .rodata | + //! | .got | ++//! | .kernel_symbols | + //! | | + //! +---------------------------------------+ + //! | | data_start == code_end_exclusive + +diff -uNr 16_virtual_mem_part4_higher_half_kernel/kernel/src/lib.rs 17_kernel_symbols/kernel/src/lib.rs +--- 16_virtual_mem_part4_higher_half_kernel/kernel/src/lib.rs ++++ 17_kernel_symbols/kernel/src/lib.rs +@@ -135,6 +135,7 @@ + pub mod memory; + pub mod print; + pub mod state; ++pub mod symbols; + pub mod time; + + //-------------------------------------------------------------------------------------------------- + +diff -uNr 16_virtual_mem_part4_higher_half_kernel/kernel/src/symbols.rs 17_kernel_symbols/kernel/src/symbols.rs +--- 16_virtual_mem_part4_higher_half_kernel/kernel/src/symbols.rs ++++ 17_kernel_symbols/kernel/src/symbols.rs +@@ -0,0 +1,85 @@ ++// SPDX-License-Identifier: MIT OR Apache-2.0 ++// ++// Copyright (c) 2022 Andre Richter ++ ++//! Debug symbol support. ++ ++use crate::memory::{Address, Virtual}; ++use core::{cell::UnsafeCell, slice}; ++use debug_symbol_types::Symbol; ++ ++//-------------------------------------------------------------------------------------------------- ++// Private Definitions ++//-------------------------------------------------------------------------------------------------- ++ ++// Symbol from the linker script. ++extern "Rust" { ++ static __kernel_symbols_start: UnsafeCell<()>; ++} ++ ++//-------------------------------------------------------------------------------------------------- ++// Global instances ++//-------------------------------------------------------------------------------------------------- ++ ++/// This will be patched to the correct value by the "kernel symbols tool" after linking. This given ++/// value here is just a (safe) dummy. ++#[no_mangle] ++static NUM_KERNEL_SYMBOLS: u64 = 0; ++ ++//-------------------------------------------------------------------------------------------------- ++// Private Code ++//-------------------------------------------------------------------------------------------------- ++ ++fn kernel_symbol_section_virt_start_addr() -> Address { ++ Address::new(unsafe { __kernel_symbols_start.get() as usize }) ++} ++ ++fn kernel_symbols_slice() -> &'static [Symbol] { ++ let ptr = kernel_symbol_section_virt_start_addr().as_usize() as *const Symbol; ++ ++ unsafe { ++ let num = core::ptr::read_volatile(&NUM_KERNEL_SYMBOLS as *const u64) as usize; ++ slice::from_raw_parts(ptr, num) ++ } ++} ++ ++//-------------------------------------------------------------------------------------------------- ++// Public Code ++//-------------------------------------------------------------------------------------------------- ++ ++/// Retrieve the symbol name corresponding to a virtual address, if any. ++pub fn lookup_symbol(addr: Address) -> Option<&'static str> { ++ for i in kernel_symbols_slice() { ++ if i.contains(addr.as_usize()) { ++ return Some(i.name()); ++ } ++ } ++ ++ None ++} ++ ++//-------------------------------------------------------------------------------------------------- ++// Testing ++//-------------------------------------------------------------------------------------------------- ++ ++#[cfg(test)] ++mod tests { ++ use super::*; ++ use test_macros::kernel_test; ++ ++ /// Sanity of symbols module. ++ #[kernel_test] ++ fn symbols_sanity() { ++ let first_sym = lookup_symbol(Address::new( ++ crate::common::is_aligned as *const usize as usize, ++ )) ++ .unwrap(); ++ ++ assert_eq!(first_sym, "libkernel::common::is_aligned"); ++ ++ let second_sym = ++ lookup_symbol(Address::new(crate::version as *const usize as usize)).unwrap(); ++ ++ assert_eq!(second_sym, "libkernel::version"); ++ } ++} + +diff -uNr 16_virtual_mem_part4_higher_half_kernel/kernel_symbols/build.rs 17_kernel_symbols/kernel_symbols/build.rs +--- 16_virtual_mem_part4_higher_half_kernel/kernel_symbols/build.rs ++++ 17_kernel_symbols/kernel_symbols/build.rs +@@ -0,0 +1,14 @@ ++use std::{env, path::Path}; ++ ++fn main() { ++ if let Ok(path) = env::var("KERNEL_SYMBOLS_DEMANGLED_RS") { ++ if Path::new(&path).exists() { ++ println!("cargo:rustc-cfg=feature=\"generated_symbols_available\"") ++ } ++ } ++ ++ println!( ++ "cargo:rerun-if-changed={}", ++ Path::new("kernel_symbols.ld").display() ++ ); ++} + +diff -uNr 16_virtual_mem_part4_higher_half_kernel/kernel_symbols/Cargo.toml 17_kernel_symbols/kernel_symbols/Cargo.toml +--- 16_virtual_mem_part4_higher_half_kernel/kernel_symbols/Cargo.toml ++++ 17_kernel_symbols/kernel_symbols/Cargo.toml +@@ -0,0 +1,15 @@ ++[package] ++name = "kernel_symbols" ++version = "0.1.0" ++edition = "2021" ++ ++[features] ++default = [] ++generated_symbols_available = [] ++ ++##-------------------------------------------------------------------------------------------------- ++## Dependencies ++##-------------------------------------------------------------------------------------------------- ++ ++[dependencies] ++debug-symbol-types = { path = "../libraries/debug-symbol-types" } + +diff -uNr 16_virtual_mem_part4_higher_half_kernel/kernel_symbols/kernel_symbols.ld 17_kernel_symbols/kernel_symbols/kernel_symbols.ld +--- 16_virtual_mem_part4_higher_half_kernel/kernel_symbols/kernel_symbols.ld ++++ 17_kernel_symbols/kernel_symbols/kernel_symbols.ld +@@ -0,0 +1,15 @@ ++/* SPDX-License-Identifier: MIT OR Apache-2.0 ++ * ++ * Copyright (c) 2022 Andre Richter ++ */ ++ ++SECTIONS ++{ ++ .rodata : { ++ ASSERT(. > 0xffffffff00000000, "Expected higher half address") ++ ++ KEEP(*(.rodata.symbol_desc*)) ++ . = ALIGN(8); ++ *(.rodata*) ++ } ++} + +diff -uNr 16_virtual_mem_part4_higher_half_kernel/kernel_symbols/src/main.rs 17_kernel_symbols/kernel_symbols/src/main.rs +--- 16_virtual_mem_part4_higher_half_kernel/kernel_symbols/src/main.rs ++++ 17_kernel_symbols/kernel_symbols/src/main.rs +@@ -0,0 +1,16 @@ ++// SPDX-License-Identifier: MIT OR Apache-2.0 ++// ++// Copyright (c) 2022 Andre Richter ++ ++//! Generation of kernel symbols. ++ ++#![no_std] ++#![no_main] ++ ++#[cfg(feature = "generated_symbols_available")] ++include!(env!("KERNEL_SYMBOLS_DEMANGLED_RS")); ++ ++#[panic_handler] ++fn panic(_info: &core::panic::PanicInfo) -> ! { ++ unimplemented!() ++} + +diff -uNr 16_virtual_mem_part4_higher_half_kernel/kernel_symbols.mk 17_kernel_symbols/kernel_symbols.mk +--- 16_virtual_mem_part4_higher_half_kernel/kernel_symbols.mk ++++ 17_kernel_symbols/kernel_symbols.mk +@@ -0,0 +1,101 @@ ++## SPDX-License-Identifier: MIT OR Apache-2.0 ++## ++## Copyright (c) 2018-2022 Andre Richter ++ ++include ../common/format.mk ++include ../common/docker.mk ++ ++##-------------------------------------------------------------------------------------------------- ++## Check for input variables that need be exported by the calling Makefile ++##-------------------------------------------------------------------------------------------------- ++ifndef KERNEL_SYMBOLS_TOOL_PATH ++$(error KERNEL_SYMBOLS_TOOL_PATH is not set) ++endif ++ ++ifndef TARGET ++$(error TARGET is not set) ++endif ++ ++ifndef KERNEL_SYMBOLS_INPUT_ELF ++$(error KERNEL_SYMBOLS_INPUT_ELF is not set) ++endif ++ ++ifndef KERNEL_SYMBOLS_OUTPUT_ELF ++$(error KERNEL_SYMBOLS_OUTPUT_ELF is not set) ++endif ++ ++ ++ ++##-------------------------------------------------------------------------------------------------- ++## Targets and Prerequisites ++##-------------------------------------------------------------------------------------------------- ++KERNEL_SYMBOLS_MANIFEST = kernel_symbols/Cargo.toml ++KERNEL_SYMBOLS_LINKER_SCRIPT = kernel_symbols/kernel_symbols.ld ++ ++KERNEL_SYMBOLS_RS = $(KERNEL_SYMBOLS_INPUT_ELF)_symbols.rs ++KERNEL_SYMBOLS_DEMANGLED_RS = $(shell pwd)/$(KERNEL_SYMBOLS_INPUT_ELF)_symbols_demangled.rs ++ ++KERNEL_SYMBOLS_ELF = target/$(TARGET)/release/kernel_symbols ++KERNEL_SYMBOLS_STRIPPED = target/$(TARGET)/release/kernel_symbols_stripped ++ ++# Export for build.rs of kernel_symbols crate. ++export KERNEL_SYMBOLS_DEMANGLED_RS ++ ++ ++ ++##-------------------------------------------------------------------------------------------------- ++## Command building blocks ++##-------------------------------------------------------------------------------------------------- ++GET_SYMBOLS_SECTION_VIRT_ADDR = $(DOCKER_TOOLS) $(EXEC_SYMBOLS_TOOL) \ ++ --get_symbols_section_virt_addr $(KERNEL_SYMBOLS_OUTPUT_ELF) ++ ++RUSTFLAGS = -C link-arg=--script=$(KERNEL_SYMBOLS_LINKER_SCRIPT) \ ++ -C link-arg=--section-start=.rodata=$$($(GET_SYMBOLS_SECTION_VIRT_ADDR)) ++ ++RUSTFLAGS_PEDANTIC = $(RUSTFLAGS) \ ++ -D warnings \ ++ -D missing_docs ++ ++COMPILER_ARGS = --target=$(TARGET) \ ++ --release ++ ++RUSTC_CMD = cargo rustc $(COMPILER_ARGS) --manifest-path $(KERNEL_SYMBOLS_MANIFEST) ++OBJCOPY_CMD = rust-objcopy \ ++ --strip-all \ ++ -O binary ++ ++EXEC_SYMBOLS_TOOL = ruby $(KERNEL_SYMBOLS_TOOL_PATH)/main.rb ++ ++##------------------------------------------------------------------------------ ++## Dockerization ++##------------------------------------------------------------------------------ ++DOCKER_CMD = docker run -t --rm -v $(shell pwd):/work/tutorial -w /work/tutorial ++ ++# DOCKER_IMAGE defined in include file (see top of this file). ++DOCKER_TOOLS = $(DOCKER_CMD) $(DOCKER_IMAGE) ++ ++ ++ ++##-------------------------------------------------------------------------------------------------- ++## Targets ++##-------------------------------------------------------------------------------------------------- ++.PHONY: all ++ ++all: ++ @cp $(KERNEL_SYMBOLS_INPUT_ELF) $(KERNEL_SYMBOLS_OUTPUT_ELF) ++ ++ @$(DOCKER_TOOLS) $(EXEC_SYMBOLS_TOOL) --gen_symbols $(KERNEL_SYMBOLS_OUTPUT_ELF) \ ++ $(KERNEL_SYMBOLS_RS) ++ ++ $(call color_progress_prefix, "Demangling") ++ @echo Symbol names ++ @cat $(KERNEL_SYMBOLS_RS) | rustfilt > $(KERNEL_SYMBOLS_DEMANGLED_RS) ++ ++ @RUSTFLAGS="$(RUSTFLAGS_PEDANTIC)" $(RUSTC_CMD) ++ ++ $(call color_progress_prefix, "Stripping") ++ @echo Symbols ELF file ++ @$(OBJCOPY_CMD) $(KERNEL_SYMBOLS_ELF) $(KERNEL_SYMBOLS_STRIPPED) ++ ++ @$(DOCKER_TOOLS) $(EXEC_SYMBOLS_TOOL) --patch_data $(KERNEL_SYMBOLS_OUTPUT_ELF) \ ++ $(KERNEL_SYMBOLS_STRIPPED) + +diff -uNr 16_virtual_mem_part4_higher_half_kernel/libraries/debug-symbol-types/Cargo.toml 17_kernel_symbols/libraries/debug-symbol-types/Cargo.toml +--- 16_virtual_mem_part4_higher_half_kernel/libraries/debug-symbol-types/Cargo.toml ++++ 17_kernel_symbols/libraries/debug-symbol-types/Cargo.toml +@@ -0,0 +1,4 @@ ++[package] ++name = "debug-symbol-types" ++version = "0.1.0" ++edition = "2021" + +diff -uNr 16_virtual_mem_part4_higher_half_kernel/libraries/debug-symbol-types/src/lib.rs 17_kernel_symbols/libraries/debug-symbol-types/src/lib.rs +--- 16_virtual_mem_part4_higher_half_kernel/libraries/debug-symbol-types/src/lib.rs ++++ 17_kernel_symbols/libraries/debug-symbol-types/src/lib.rs +@@ -0,0 +1,39 @@ ++// SPDX-License-Identifier: MIT OR Apache-2.0 ++// ++// Copyright (c) 2022 Andre Richter ++ ++//! Types for implementing debug symbol support. ++ ++#![no_std] ++ ++use core::ops::Range; ++ ++/// A symbol containing a size. ++#[repr(C)] ++pub struct Symbol { ++ addr_range: Range, ++ name: &'static str, ++} ++ ++impl Symbol { ++ /// Create an instance. ++ pub const fn new(start: usize, size: usize, name: &'static str) -> Symbol { ++ Symbol { ++ addr_range: Range { ++ start, ++ end: start + size, ++ }, ++ name, ++ } ++ } ++ ++ /// Returns true if addr is contained in the range. ++ pub fn contains(&self, addr: usize) -> bool { ++ self.addr_range.contains(&addr) ++ } ++ ++ /// Returns the symbol's name. ++ pub fn name(&self) -> &'static str { ++ self.name ++ } ++} + +diff -uNr 16_virtual_mem_part4_higher_half_kernel/Makefile 17_kernel_symbols/Makefile +--- 16_virtual_mem_part4_higher_half_kernel/Makefile ++++ 17_kernel_symbols/Makefile +@@ -84,7 +84,24 @@ + KERNEL_ELF_TTABLES = target/$(TARGET)/release/kernel+ttables + KERNEL_ELF_TTABLES_DEPS = $(KERNEL_ELF_RAW) $(wildcard $(TT_TOOL_PATH)/*) + +-KERNEL_ELF = $(KERNEL_ELF_TTABLES) ++##------------------------------------------------------------------------------ ++## Kernel symbols ++##------------------------------------------------------------------------------ ++export KERNEL_SYMBOLS_TOOL_PATH = tools/kernel_symbols_tool ++ ++KERNEL_ELF_TTABLES_SYMS = target/$(TARGET)/release/kernel+ttables+symbols ++ ++# Unlike with KERNEL_ELF_RAW, we are not relying on dep-info here. One of the reasons being that the ++# name of the generated symbols file varies between runs, which can cause confusion. ++KERNEL_ELF_TTABLES_SYMS_DEPS = $(KERNEL_ELF_TTABLES) \ ++ $(wildcard kernel_symbols/*) \ ++ $(wildcard $(KERNEL_SYMBOLS_TOOL_PATH)/*) ++ ++export TARGET ++export KERNEL_SYMBOLS_INPUT_ELF = $(KERNEL_ELF_TTABLES) ++export KERNEL_SYMBOLS_OUTPUT_ELF = $(KERNEL_ELF_TTABLES_SYMS) ++ ++KERNEL_ELF = $(KERNEL_ELF_TTABLES_SYMS) + + + +@@ -178,11 +195,18 @@ + @$(DOCKER_TOOLS) $(EXEC_TT_TOOL) $(BSP) $(KERNEL_ELF_TTABLES) + + ##------------------------------------------------------------------------------ ++## Generate kernel symbols and patch them into the kernel ELF ++##------------------------------------------------------------------------------ ++$(KERNEL_ELF_TTABLES_SYMS): $(KERNEL_ELF_TTABLES_SYMS_DEPS) ++ $(call color_header, "Generating kernel symbols and patching kernel ELF") ++ @$(MAKE) --no-print-directory -f kernel_symbols.mk ++ ++##------------------------------------------------------------------------------ + ## Generate the stripped kernel binary + ##------------------------------------------------------------------------------ +-$(KERNEL_BIN): $(KERNEL_ELF_TTABLES) ++$(KERNEL_BIN): $(KERNEL_ELF_TTABLES_SYMS) + $(call color_header, "Generating stripped binary") +- @$(OBJCOPY_CMD) $(KERNEL_ELF_TTABLES) $(KERNEL_BIN) ++ @$(OBJCOPY_CMD) $(KERNEL_ELF_TTABLES_SYMS) $(KERNEL_BIN) + $(call color_progress_prefix, "Name") + @echo $(KERNEL_BIN) + $(call color_progress_prefix, "Size") +@@ -319,10 +343,19 @@ + cd $(shell pwd) + + TEST_ELF=$$(echo $$1 | sed -e 's/.*target/target/g') ++ TEST_ELF_SYMS="$${TEST_ELF}_syms" + TEST_BINARY=$$(echo $$1.img | sed -e 's/.*target/target/g') + + $(DOCKER_TOOLS) $(EXEC_TT_TOOL) $(BSP) $$TEST_ELF > /dev/null +- $(OBJCOPY_CMD) $$TEST_ELF $$TEST_BINARY ++ ++ # This overrides the two ENV variables. The other ENV variables that are required as input for ++ # the .mk file are set already because they are exported by this Makefile and this script is ++ # started by the same. ++ KERNEL_SYMBOLS_INPUT_ELF=$$TEST_ELF \ ++ KERNEL_SYMBOLS_OUTPUT_ELF=$$TEST_ELF_SYMS \ ++ $(MAKE) --no-print-directory -f kernel_symbols.mk ++ ++ $(OBJCOPY_CMD) $$TEST_ELF_SYMS $$TEST_BINARY + $(DOCKER_TEST) $(EXEC_TEST_DISPATCH) $(EXEC_QEMU) $(QEMU_TEST_ARGS) -kernel $$TEST_BINARY + endef + + +diff -uNr 16_virtual_mem_part4_higher_half_kernel/tools/kernel_symbols_tool/cmds.rb 17_kernel_symbols/tools/kernel_symbols_tool/cmds.rb +--- 16_virtual_mem_part4_higher_half_kernel/tools/kernel_symbols_tool/cmds.rb ++++ 17_kernel_symbols/tools/kernel_symbols_tool/cmds.rb +@@ -0,0 +1,45 @@ ++# frozen_string_literal: true ++ ++# SPDX-License-Identifier: MIT OR Apache-2.0 ++# ++# Copyright (c) 2022 Andre Richter ++ ++def generate_symbols(kernel_elf, output_file) ++ File.open(output_file, 'w') do |file| ++ header = <<~HEREDOC ++ use debug_symbol_types::Symbol; ++ ++ # [no_mangle] ++ # [link_section = ".rodata.symbol_desc"] ++ static KERNEL_SYMBOLS: [Symbol; #{kernel_elf.num_symbols}] = [ ++ HEREDOC ++ ++ file.write(header) ++ kernel_elf.symbols.each do |sym| ++ value = sym.header.st_value ++ size = sym.header.st_size ++ name = sym.name ++ ++ file.write(" Symbol::new(#{value}, #{size}, \"#{name}\"),\n") ++ end ++ file.write("];\n") ++ end ++end ++ ++def get_symbols_section_virt_addr(kernel_elf) ++ kernel_elf.kernel_symbols_section_virt_addr ++end ++ ++def patch_symbol_data(kernel_elf, symbols_blob_path) ++ symbols_blob = File.binread(symbols_blob_path) ++ ++ raise if symbols_blob.size > kernel_elf.kernel_symbols_section_size ++ ++ File.binwrite(kernel_elf.path, File.binread(symbols_blob_path), ++ kernel_elf.kernel_symbols_section_offset_in_file) ++end ++ ++def patch_num_symbols(kernel_elf) ++ num_packed = [kernel_elf.num_symbols].pack('Q<*') # "Q" == uint64_t, "<" == little endian ++ File.binwrite(kernel_elf.path, num_packed, kernel_elf.num_kernel_symbols_offset_in_file) ++end + +diff -uNr 16_virtual_mem_part4_higher_half_kernel/tools/kernel_symbols_tool/kernel_elf.rb 17_kernel_symbols/tools/kernel_symbols_tool/kernel_elf.rb +--- 16_virtual_mem_part4_higher_half_kernel/tools/kernel_symbols_tool/kernel_elf.rb ++++ 17_kernel_symbols/tools/kernel_symbols_tool/kernel_elf.rb +@@ -0,0 +1,74 @@ ++# frozen_string_literal: true ++ ++# SPDX-License-Identifier: MIT OR Apache-2.0 ++# ++# Copyright (c) 2021-2022 Andre Richter ++ ++# KernelELF ++class KernelELF ++ attr_reader :path ++ ++ def initialize(kernel_elf_path, kernel_symbols_section, num_kernel_symbols) ++ @elf = ELFTools::ELFFile.new(File.open(kernel_elf_path)) ++ @symtab_section = @elf.section_by_name('.symtab') ++ ++ @path = kernel_elf_path ++ fetch_values(kernel_symbols_section, num_kernel_symbols) ++ end ++ ++ private ++ ++ def fetch_values(kernel_symbols_section, num_kernel_symbols) ++ sym = @symtab_section.symbol_by_name(num_kernel_symbols) ++ raise "Symbol \"#{num_kernel_symbols}\" not found" if sym.nil? ++ ++ @num_kernel_symbols = sym ++ ++ section = @elf.section_by_name(kernel_symbols_section) ++ raise "Section \"#{kernel_symbols_section}\" not found" if section.nil? ++ ++ @kernel_symbols_section = section ++ end ++ ++ def num_kernel_symbols_virt_addr ++ @num_kernel_symbols.header.st_value ++ end ++ ++ def segment_containing_virt_addr(virt_addr) ++ @elf.each_segments do |segment| ++ return segment if segment.vma_in?(virt_addr) ++ end ++ end ++ ++ def virt_addr_to_file_offset(virt_addr) ++ segment = segment_containing_virt_addr(virt_addr) ++ segment.vma_to_offset(virt_addr) ++ end ++ ++ public ++ ++ def symbols ++ non_zero_symbols = @symtab_section.symbols.reject { |sym| sym.header.st_size.zero? } ++ non_zero_symbols.sort_by { |sym| sym.header.st_value } ++ end ++ ++ def num_symbols ++ symbols.size ++ end ++ ++ def kernel_symbols_section_virt_addr ++ @kernel_symbols_section.header.sh_addr.to_i ++ end ++ ++ def kernel_symbols_section_size ++ @kernel_symbols_section.header.sh_size.to_i ++ end ++ ++ def kernel_symbols_section_offset_in_file ++ virt_addr_to_file_offset(kernel_symbols_section_virt_addr) ++ end ++ ++ def num_kernel_symbols_offset_in_file ++ virt_addr_to_file_offset(num_kernel_symbols_virt_addr) ++ end ++end + +diff -uNr 16_virtual_mem_part4_higher_half_kernel/tools/kernel_symbols_tool/main.rb 17_kernel_symbols/tools/kernel_symbols_tool/main.rb +--- 16_virtual_mem_part4_higher_half_kernel/tools/kernel_symbols_tool/main.rb ++++ 17_kernel_symbols/tools/kernel_symbols_tool/main.rb +@@ -0,0 +1,47 @@ ++#!/usr/bin/env ruby ++# frozen_string_literal: true ++ ++# SPDX-License-Identifier: MIT OR Apache-2.0 ++# ++# Copyright (c) 2022 Andre Richter ++ ++require 'rubygems' ++require 'bundler/setup' ++require 'colorize' ++require 'elftools' ++ ++require_relative 'kernel_elf' ++require_relative 'cmds' ++ ++KERNEL_SYMBOLS_SECTION = '.kernel_symbols' ++NUM_KERNEL_SYMBOLS = 'NUM_KERNEL_SYMBOLS' ++ ++cmd = ARGV[0] ++ ++kernel_elf_path = ARGV[1] ++kernel_elf = KernelELF.new(kernel_elf_path, KERNEL_SYMBOLS_SECTION, NUM_KERNEL_SYMBOLS) ++ ++case cmd ++when '--gen_symbols' ++ output_file = ARGV[2] ++ ++ print 'Generating'.rjust(12).green.bold ++ puts ' Symbols source file' ++ ++ generate_symbols(kernel_elf, output_file) ++when '--get_symbols_section_virt_addr' ++ addr = get_symbols_section_virt_addr(kernel_elf) ++ ++ puts "0x#{addr.to_s(16)}" ++when '--patch_data' ++ symbols_blob_path = ARGV[2] ++ num_symbols = kernel_elf.num_symbols ++ ++ print 'Patching'.rjust(12).green.bold ++ puts " Symbols blob and number of symbols (#{num_symbols}) into ELF" ++ ++ patch_symbol_data(kernel_elf, symbols_blob_path) ++ patch_num_symbols(kernel_elf) ++else ++ raise ++end + +``` diff --git a/17_kernel_symbols/kernel/Cargo.toml b/17_kernel_symbols/kernel/Cargo.toml new file mode 100644 index 00000000..c040d60c --- /dev/null +++ b/17_kernel_symbols/kernel/Cargo.toml @@ -0,0 +1,58 @@ +[package] +name = "mingo" +version = "0.17.0" +authors = ["Andre Richter "] +edition = "2021" + +[features] +default = [] +bsp_rpi3 = ["tock-registers"] +bsp_rpi4 = ["tock-registers"] +test_build = ["qemu-exit"] + +##-------------------------------------------------------------------------------------------------- +## Dependencies +##-------------------------------------------------------------------------------------------------- + +[dependencies] +test-types = { path = "../libraries/test-types" } +debug-symbol-types = { path = "../libraries/debug-symbol-types" } + +# Optional dependencies +tock-registers = { version = "0.7.x", default-features = false, features = ["register_types"], optional = true } +qemu-exit = { version = "3.x.x", optional = true } + +# Platform specific dependencies +[target.'cfg(target_arch = "aarch64")'.dependencies] +cortex-a = { version = "7.x.x" } + +##-------------------------------------------------------------------------------------------------- +## Testing +##-------------------------------------------------------------------------------------------------- + +[dev-dependencies] +test-macros = { path = "../libraries/test-macros" } + +# Unit tests are done in the library part of the kernel. +[lib] +name = "libkernel" +test = true + +# Disable unit tests for the kernel binary. +[[bin]] +name = "kernel" +path = "src/main.rs" +test = false + +# List of tests without harness. +[[test]] +name = "00_console_sanity" +harness = false + +[[test]] +name = "02_exception_sync_page_fault" +harness = false + +[[test]] +name = "03_exception_restore_sanity" +harness = false diff --git a/17_kernel_symbols/kernel/build.rs b/17_kernel_symbols/kernel/build.rs new file mode 100644 index 00000000..cab00bb3 --- /dev/null +++ b/17_kernel_symbols/kernel/build.rs @@ -0,0 +1,20 @@ +use std::{env, fs, process}; + +fn main() { + let ld_script_path = match env::var("LD_SCRIPT_PATH") { + Ok(var) => var, + _ => process::exit(0), + }; + + let files = fs::read_dir(ld_script_path).unwrap(); + files + .filter_map(Result::ok) + .filter(|d| { + if let Some(e) = d.path().extension() { + e == "ld" + } else { + false + } + }) + .for_each(|f| println!("cargo:rerun-if-changed={}", f.path().display())); +} diff --git a/17_kernel_symbols/kernel/src/_arch/aarch64/cpu.rs b/17_kernel_symbols/kernel/src/_arch/aarch64/cpu.rs new file mode 100644 index 00000000..66da661c --- /dev/null +++ b/17_kernel_symbols/kernel/src/_arch/aarch64/cpu.rs @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2018-2022 Andre Richter + +//! Architectural processor code. +//! +//! # Orientation +//! +//! Since arch modules are imported into generic modules using the path attribute, the path of this +//! file is: +//! +//! crate::cpu::arch_cpu + +use cortex_a::asm; + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +pub use asm::nop; + +/// Pause execution on the core. +#[inline(always)] +pub fn wait_forever() -> ! { + loop { + asm::wfe() + } +} + +//-------------------------------------------------------------------------------------------------- +// Testing +//-------------------------------------------------------------------------------------------------- +#[cfg(feature = "test_build")] +use qemu_exit::QEMUExit; + +#[cfg(feature = "test_build")] +const QEMU_EXIT_HANDLE: qemu_exit::AArch64 = qemu_exit::AArch64::new(); + +/// Make the host QEMU binary execute `exit(1)`. +#[cfg(feature = "test_build")] +pub fn qemu_exit_failure() -> ! { + QEMU_EXIT_HANDLE.exit_failure() +} + +/// Make the host QEMU binary execute `exit(0)`. +#[cfg(feature = "test_build")] +pub fn qemu_exit_success() -> ! { + QEMU_EXIT_HANDLE.exit_success() +} diff --git a/17_kernel_symbols/kernel/src/_arch/aarch64/cpu/boot.rs b/17_kernel_symbols/kernel/src/_arch/aarch64/cpu/boot.rs new file mode 100644 index 00000000..3d01b0dc --- /dev/null +++ b/17_kernel_symbols/kernel/src/_arch/aarch64/cpu/boot.rs @@ -0,0 +1,95 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2021-2022 Andre Richter + +//! Architectural boot code. +//! +//! # Orientation +//! +//! Since arch modules are imported into generic modules using the path attribute, the path of this +//! file is: +//! +//! crate::cpu::boot::arch_boot + +use crate::{memory, memory::Address}; +use core::arch::global_asm; +use cortex_a::{asm, registers::*}; +use tock_registers::interfaces::Writeable; + +// Assembly counterpart to this file. +global_asm!(include_str!("boot.s")); + +//-------------------------------------------------------------------------------------------------- +// Private Code +//-------------------------------------------------------------------------------------------------- + +/// Prepares the transition from EL2 to EL1. +/// +/// # Safety +/// +/// - The `bss` section is not initialized yet. The code must not use or reference it in any way. +/// - The HW state of EL1 must be prepared in a sound way. +#[inline(always)] +unsafe fn prepare_el2_to_el1_transition( + virt_boot_core_stack_end_exclusive_addr: u64, + virt_kernel_init_addr: u64, +) { + // Enable timer counter registers for EL1. + CNTHCTL_EL2.write(CNTHCTL_EL2::EL1PCEN::SET + CNTHCTL_EL2::EL1PCTEN::SET); + + // No offset for reading the counters. + CNTVOFF_EL2.set(0); + + // Set EL1 execution state to AArch64. + HCR_EL2.write(HCR_EL2::RW::EL1IsAarch64); + + // Set up a simulated exception return. + // + // First, fake a saved program status where all interrupts were masked and SP_EL1 was used as a + // stack pointer. + SPSR_EL2.write( + SPSR_EL2::D::Masked + + SPSR_EL2::A::Masked + + SPSR_EL2::I::Masked + + SPSR_EL2::F::Masked + + SPSR_EL2::M::EL1h, + ); + + // Second, let the link register point to kernel_init(). + ELR_EL2.set(virt_kernel_init_addr); + + // Set up SP_EL1 (stack pointer), which will be used by EL1 once we "return" to it. Since there + // are no plans to ever return to EL2, just re-use the same stack. + SP_EL1.set(virt_boot_core_stack_end_exclusive_addr); +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +/// The Rust entry of the `kernel` binary. +/// +/// The function is called from the assembly `_start` function. +/// +/// # Safety +/// +/// - Exception return from EL2 must must continue execution in EL1 with `kernel_init()`. +#[no_mangle] +pub unsafe extern "C" fn _start_rust( + phys_kernel_tables_base_addr: u64, + virt_boot_core_stack_end_exclusive_addr: u64, + virt_kernel_init_addr: u64, +) -> ! { + prepare_el2_to_el1_transition( + virt_boot_core_stack_end_exclusive_addr, + virt_kernel_init_addr, + ); + + // Turn on the MMU for EL1. + let addr = Address::new(phys_kernel_tables_base_addr as usize); + memory::mmu::enable_mmu_and_caching(addr).unwrap(); + + // Use `eret` to "return" to EL1. Since virtual memory will already be enabled, this results in + // execution of kernel_init() in EL1 from its _virtual address_. + asm::eret() +} diff --git a/17_kernel_symbols/kernel/src/_arch/aarch64/cpu/boot.s b/17_kernel_symbols/kernel/src/_arch/aarch64/cpu/boot.s new file mode 100644 index 00000000..d2c9270d --- /dev/null +++ b/17_kernel_symbols/kernel/src/_arch/aarch64/cpu/boot.s @@ -0,0 +1,100 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2021-2022 Andre Richter + +//-------------------------------------------------------------------------------------------------- +// Definitions +//-------------------------------------------------------------------------------------------------- + +// Load the address of a symbol into a register, PC-relative. +// +// The symbol must lie within +/- 4 GiB of the Program Counter. +// +// # Resources +// +// - https://sourceware.org/binutils/docs-2.36/as/AArch64_002dRelocations.html +.macro ADR_REL register, symbol + adrp \register, \symbol + add \register, \register, #:lo12:\symbol +.endm + +// Load the address of a symbol into a register, absolute. +// +// # Resources +// +// - https://sourceware.org/binutils/docs-2.36/as/AArch64_002dRelocations.html +.macro ADR_ABS register, symbol + movz \register, #:abs_g3:\symbol + movk \register, #:abs_g2_nc:\symbol + movk \register, #:abs_g1_nc:\symbol + movk \register, #:abs_g0_nc:\symbol +.endm + +.equ _EL2, 0x8 +.equ _core_id_mask, 0b11 + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- +.section .text._start + +//------------------------------------------------------------------------------ +// fn _start() +//------------------------------------------------------------------------------ +_start: + // Only proceed if the core executes in EL2. Park it otherwise. + mrs x0, CurrentEL + cmp x0, _EL2 + b.ne .L_parking_loop + + // Only proceed on the boot core. Park it otherwise. + mrs x1, MPIDR_EL1 + and x1, x1, _core_id_mask + ldr x2, BOOT_CORE_ID // provided by bsp/__board_name__/cpu.rs + cmp x1, x2 + b.ne .L_parking_loop + + // If execution reaches here, it is the boot core. + + // Initialize DRAM. + ADR_REL x0, __bss_start + ADR_REL x1, __bss_end_exclusive + +.L_bss_init_loop: + cmp x0, x1 + b.eq .L_prepare_rust + stp xzr, xzr, [x0], #16 + b .L_bss_init_loop + + // Prepare the jump to Rust code. +.L_prepare_rust: + // Load the base address of the kernel's translation tables. + ldr x0, PHYS_KERNEL_TABLES_BASE_ADDR // provided by bsp/__board_name__/memory/mmu.rs + + // Load the _absolute_ addresses of the following symbols. Since the kernel is linked at + // the top of the 64 bit address space, these are effectively virtual addresses. + ADR_ABS x1, __boot_core_stack_end_exclusive + ADR_ABS x2, kernel_init + + // Load the PC-relative address of the stack and set the stack pointer. + // + // Since _start() is the first function that runs after the firmware has loaded the kernel + // into memory, retrieving this symbol PC-relative returns the "physical" address. + // + // Setting the stack pointer to this value ensures that anything that still runs in EL2, + // until the kernel returns to EL1 with the MMU enabled, works as well. After the return to + // EL1, the virtual address of the stack retrieved above will be used. + ADR_REL x4, __boot_core_stack_end_exclusive + mov sp, x4 + + // Jump to Rust code. x0, x1 and x2 hold the function arguments provided to _start_rust(). + b _start_rust + + // Infinitely wait for events (aka "park the core"). +.L_parking_loop: + wfe + b .L_parking_loop + +.size _start, . - _start +.type _start, function +.global _start diff --git a/17_kernel_symbols/kernel/src/_arch/aarch64/cpu/smp.rs b/17_kernel_symbols/kernel/src/_arch/aarch64/cpu/smp.rs new file mode 100644 index 00000000..351fde62 --- /dev/null +++ b/17_kernel_symbols/kernel/src/_arch/aarch64/cpu/smp.rs @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2018-2022 Andre Richter + +//! Architectural symmetric multiprocessing. +//! +//! # Orientation +//! +//! Since arch modules are imported into generic modules using the path attribute, the path of this +//! file is: +//! +//! crate::cpu::smp::arch_smp + +use cortex_a::registers::*; +use tock_registers::interfaces::Readable; + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +/// Return the executing core's id. +#[inline(always)] +pub fn core_id() -> T +where + T: From, +{ + const CORE_MASK: u64 = 0b11; + + T::from((MPIDR_EL1.get() & CORE_MASK) as u8) +} diff --git a/17_kernel_symbols/kernel/src/_arch/aarch64/exception.rs b/17_kernel_symbols/kernel/src/_arch/aarch64/exception.rs new file mode 100644 index 00000000..3515d956 --- /dev/null +++ b/17_kernel_symbols/kernel/src/_arch/aarch64/exception.rs @@ -0,0 +1,321 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2018-2022 Andre Richter + +//! Architectural synchronous and asynchronous exception handling. +//! +//! # Orientation +//! +//! Since arch modules are imported into generic modules using the path attribute, the path of this +//! file is: +//! +//! crate::exception::arch_exception + +use crate::{bsp, exception, memory, symbols}; +use core::{arch::global_asm, cell::UnsafeCell, fmt}; +use cortex_a::{asm::barrier, registers::*}; +use tock_registers::{ + interfaces::{Readable, Writeable}, + registers::InMemoryRegister, +}; + +// Assembly counterpart to this file. +global_asm!(include_str!("exception.s")); + +//-------------------------------------------------------------------------------------------------- +// Private Definitions +//-------------------------------------------------------------------------------------------------- + +/// Wrapper structs for memory copies of registers. +#[repr(transparent)] +struct SpsrEL1(InMemoryRegister); +struct EsrEL1(InMemoryRegister); + +/// The exception context as it is stored on the stack on exception entry. +#[repr(C)] +struct ExceptionContext { + /// General Purpose Registers. + gpr: [u64; 30], + + /// The link register, aka x30. + lr: u64, + + /// Exception link register. The program counter at the time the exception happened. + elr_el1: u64, + + /// Saved program status. + spsr_el1: SpsrEL1, + + // Exception syndrome register. + esr_el1: EsrEL1, +} + +//-------------------------------------------------------------------------------------------------- +// Private Code +//-------------------------------------------------------------------------------------------------- + +/// Prints verbose information about the exception and then panics. +fn default_exception_handler(exc: &ExceptionContext) { + panic!( + "CPU Exception!\n\n\ + {}", + exc + ); +} + +//------------------------------------------------------------------------------ +// Current, EL0 +//------------------------------------------------------------------------------ + +#[no_mangle] +unsafe extern "C" fn current_el0_synchronous(_e: &mut ExceptionContext) { + panic!("Should not be here. Use of SP_EL0 in EL1 is not supported.") +} + +#[no_mangle] +unsafe extern "C" fn current_el0_irq(_e: &mut ExceptionContext) { + panic!("Should not be here. Use of SP_EL0 in EL1 is not supported.") +} + +#[no_mangle] +unsafe extern "C" fn current_el0_serror(_e: &mut ExceptionContext) { + panic!("Should not be here. Use of SP_EL0 in EL1 is not supported.") +} + +//------------------------------------------------------------------------------ +// Current, ELx +//------------------------------------------------------------------------------ + +#[no_mangle] +unsafe extern "C" fn current_elx_synchronous(e: &mut ExceptionContext) { + #[cfg(feature = "test_build")] + { + const TEST_SVC_ID: u64 = 0x1337; + + if let Some(ESR_EL1::EC::Value::SVC64) = e.esr_el1.exception_class() { + if e.esr_el1.iss() == TEST_SVC_ID { + return; + } + } + } + + default_exception_handler(e); +} + +#[no_mangle] +unsafe extern "C" fn current_elx_irq(_e: &mut ExceptionContext) { + use exception::asynchronous::interface::IRQManager; + + let token = &exception::asynchronous::IRQContext::new(); + bsp::exception::asynchronous::irq_manager().handle_pending_irqs(token); +} + +#[no_mangle] +unsafe extern "C" fn current_elx_serror(e: &mut ExceptionContext) { + default_exception_handler(e); +} + +//------------------------------------------------------------------------------ +// Lower, AArch64 +//------------------------------------------------------------------------------ + +#[no_mangle] +unsafe extern "C" fn lower_aarch64_synchronous(e: &mut ExceptionContext) { + default_exception_handler(e); +} + +#[no_mangle] +unsafe extern "C" fn lower_aarch64_irq(e: &mut ExceptionContext) { + default_exception_handler(e); +} + +#[no_mangle] +unsafe extern "C" fn lower_aarch64_serror(e: &mut ExceptionContext) { + default_exception_handler(e); +} + +//------------------------------------------------------------------------------ +// Lower, AArch32 +//------------------------------------------------------------------------------ + +#[no_mangle] +unsafe extern "C" fn lower_aarch32_synchronous(e: &mut ExceptionContext) { + default_exception_handler(e); +} + +#[no_mangle] +unsafe extern "C" fn lower_aarch32_irq(e: &mut ExceptionContext) { + default_exception_handler(e); +} + +#[no_mangle] +unsafe extern "C" fn lower_aarch32_serror(e: &mut ExceptionContext) { + default_exception_handler(e); +} + +//------------------------------------------------------------------------------ +// Misc +//------------------------------------------------------------------------------ + +/// Human readable SPSR_EL1. +#[rustfmt::skip] +impl fmt::Display for SpsrEL1 { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + // Raw value. + writeln!(f, "SPSR_EL1: {:#010x}", self.0.get())?; + + let to_flag_str = |x| -> _ { + if x { "Set" } else { "Not set" } + }; + + writeln!(f, " Flags:")?; + writeln!(f, " Negative (N): {}", to_flag_str(self.0.is_set(SPSR_EL1::N)))?; + writeln!(f, " Zero (Z): {}", to_flag_str(self.0.is_set(SPSR_EL1::Z)))?; + writeln!(f, " Carry (C): {}", to_flag_str(self.0.is_set(SPSR_EL1::C)))?; + writeln!(f, " Overflow (V): {}", to_flag_str(self.0.is_set(SPSR_EL1::V)))?; + + let to_mask_str = |x| -> _ { + if x { "Masked" } else { "Unmasked" } + }; + + writeln!(f, " Exception handling state:")?; + writeln!(f, " Debug (D): {}", to_mask_str(self.0.is_set(SPSR_EL1::D)))?; + writeln!(f, " SError (A): {}", to_mask_str(self.0.is_set(SPSR_EL1::A)))?; + writeln!(f, " IRQ (I): {}", to_mask_str(self.0.is_set(SPSR_EL1::I)))?; + writeln!(f, " FIQ (F): {}", to_mask_str(self.0.is_set(SPSR_EL1::F)))?; + + write!(f, " Illegal Execution State (IL): {}", + to_flag_str(self.0.is_set(SPSR_EL1::IL)) + ) + } +} + +impl EsrEL1 { + #[inline(always)] + fn exception_class(&self) -> Option { + self.0.read_as_enum(ESR_EL1::EC) + } + + #[cfg(feature = "test_build")] + #[inline(always)] + fn iss(&self) -> u64 { + self.0.read(ESR_EL1::ISS) + } +} + +/// Human readable ESR_EL1. +#[rustfmt::skip] +impl fmt::Display for EsrEL1 { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + // Raw print of whole register. + writeln!(f, "ESR_EL1: {:#010x}", self.0.get())?; + + // Raw print of exception class. + write!(f, " Exception Class (EC) : {:#x}", self.0.read(ESR_EL1::EC))?; + + // Exception class. + let ec_translation = match self.exception_class() { + Some(ESR_EL1::EC::Value::DataAbortCurrentEL) => "Data Abort, current EL", + _ => "N/A", + }; + writeln!(f, " - {}", ec_translation)?; + + // Raw print of instruction specific syndrome. + write!(f, " Instr Specific Syndrome (ISS): {:#x}", self.0.read(ESR_EL1::ISS)) + } +} + +impl ExceptionContext { + #[inline(always)] + fn exception_class(&self) -> Option { + self.esr_el1.exception_class() + } + + #[inline(always)] + fn fault_address_valid(&self) -> bool { + use ESR_EL1::EC::Value::*; + + match self.exception_class() { + None => false, + Some(ec) => matches!( + ec, + InstrAbortLowerEL + | InstrAbortCurrentEL + | PCAlignmentFault + | DataAbortLowerEL + | DataAbortCurrentEL + | WatchpointLowerEL + | WatchpointCurrentEL + ), + } + } +} + +/// Human readable print of the exception context. +impl fmt::Display for ExceptionContext { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + writeln!(f, "{}", self.esr_el1)?; + + if self.fault_address_valid() { + writeln!(f, "FAR_EL1: {:#018x}", FAR_EL1.get() as usize)?; + } + + writeln!(f, "{}", self.spsr_el1)?; + writeln!(f, "ELR_EL1: {:#018x}", self.elr_el1)?; + writeln!( + f, + " Symbol: {}", + symbols::lookup_symbol(memory::Address::new(self.elr_el1 as usize)) + .unwrap_or("Symbol not found") + )?; + writeln!(f)?; + writeln!(f, "General purpose register:")?; + + #[rustfmt::skip] + let alternating = |x| -> _ { + if x % 2 == 0 { " " } else { "\n" } + }; + + // Print two registers per line. + for (i, reg) in self.gpr.iter().enumerate() { + write!(f, " x{: <2}: {: >#018x}{}", i, reg, alternating(i))?; + } + write!(f, " lr : {:#018x}", self.lr) + } +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- +use crate::exception::PrivilegeLevel; + +/// The processing element's current privilege level. +pub fn current_privilege_level() -> (PrivilegeLevel, &'static str) { + let el = CurrentEL.read_as_enum(CurrentEL::EL); + match el { + Some(CurrentEL::EL::Value::EL2) => (PrivilegeLevel::Hypervisor, "EL2"), + Some(CurrentEL::EL::Value::EL1) => (PrivilegeLevel::Kernel, "EL1"), + Some(CurrentEL::EL::Value::EL0) => (PrivilegeLevel::User, "EL0"), + _ => (PrivilegeLevel::Unknown, "Unknown"), + } +} + +/// Init exception handling by setting the exception vector base address register. +/// +/// # Safety +/// +/// - Changes the HW state of the executing core. +/// - The vector table and the symbol `__exception_vector_table_start` from the linker script must +/// adhere to the alignment and size constraints demanded by the ARMv8-A Architecture Reference +/// Manual. +pub unsafe fn handling_init() { + // Provided by exception.S. + extern "Rust" { + static __exception_vector_start: UnsafeCell<()>; + } + + VBAR_EL1.set(__exception_vector_start.get() as u64); + + // Force VBAR update to complete before next instruction. + barrier::isb(barrier::SY); +} diff --git a/17_kernel_symbols/kernel/src/_arch/aarch64/exception.s b/17_kernel_symbols/kernel/src/_arch/aarch64/exception.s new file mode 100644 index 00000000..5aae30b9 --- /dev/null +++ b/17_kernel_symbols/kernel/src/_arch/aarch64/exception.s @@ -0,0 +1,150 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2018-2022 Andre Richter + +//-------------------------------------------------------------------------------------------------- +// Definitions +//-------------------------------------------------------------------------------------------------- + +/// Call the function provided by parameter `\handler` after saving the exception context. Provide +/// the context as the first parameter to '\handler'. +.macro CALL_WITH_CONTEXT handler + // Make room on the stack for the exception context. + sub sp, sp, #16 * 17 + + // Store all general purpose registers on the stack. + stp x0, x1, [sp, #16 * 0] + stp x2, x3, [sp, #16 * 1] + stp x4, x5, [sp, #16 * 2] + stp x6, x7, [sp, #16 * 3] + stp x8, x9, [sp, #16 * 4] + stp x10, x11, [sp, #16 * 5] + stp x12, x13, [sp, #16 * 6] + stp x14, x15, [sp, #16 * 7] + stp x16, x17, [sp, #16 * 8] + stp x18, x19, [sp, #16 * 9] + stp x20, x21, [sp, #16 * 10] + stp x22, x23, [sp, #16 * 11] + stp x24, x25, [sp, #16 * 12] + stp x26, x27, [sp, #16 * 13] + stp x28, x29, [sp, #16 * 14] + + // Add the exception link register (ELR_EL1), saved program status (SPSR_EL1) and exception + // syndrome register (ESR_EL1). + mrs x1, ELR_EL1 + mrs x2, SPSR_EL1 + mrs x3, ESR_EL1 + + stp lr, x1, [sp, #16 * 15] + stp x2, x3, [sp, #16 * 16] + + // x0 is the first argument for the function called through `\handler`. + mov x0, sp + + // Call `\handler`. + bl \handler + + // After returning from exception handling code, replay the saved context and return via + // `eret`. + b __exception_restore_context +.endm + +.macro FIQ_SUSPEND +1: wfe + b 1b +.endm + +//-------------------------------------------------------------------------------------------------- +// Private Code +//-------------------------------------------------------------------------------------------------- +.section .text + +//------------------------------------------------------------------------------ +// The exception vector table. +//------------------------------------------------------------------------------ + +// Align by 2^11 bytes, as demanded by ARMv8-A. Same as ALIGN(2048) in an ld script. +.align 11 + +// Export a symbol for the Rust code to use. +__exception_vector_start: + +// Current exception level with SP_EL0. +// +// .org sets the offset relative to section start. +// +// # Safety +// +// - It must be ensured that `CALL_WITH_CONTEXT` <= 0x80 bytes. +.org 0x000 + CALL_WITH_CONTEXT current_el0_synchronous +.org 0x080 + CALL_WITH_CONTEXT current_el0_irq +.org 0x100 + FIQ_SUSPEND +.org 0x180 + CALL_WITH_CONTEXT current_el0_serror + +// Current exception level with SP_ELx, x > 0. +.org 0x200 + CALL_WITH_CONTEXT current_elx_synchronous +.org 0x280 + CALL_WITH_CONTEXT current_elx_irq +.org 0x300 + FIQ_SUSPEND +.org 0x380 + CALL_WITH_CONTEXT current_elx_serror + +// Lower exception level, AArch64 +.org 0x400 + CALL_WITH_CONTEXT lower_aarch64_synchronous +.org 0x480 + CALL_WITH_CONTEXT lower_aarch64_irq +.org 0x500 + FIQ_SUSPEND +.org 0x580 + CALL_WITH_CONTEXT lower_aarch64_serror + +// Lower exception level, AArch32 +.org 0x600 + CALL_WITH_CONTEXT lower_aarch32_synchronous +.org 0x680 + CALL_WITH_CONTEXT lower_aarch32_irq +.org 0x700 + FIQ_SUSPEND +.org 0x780 + CALL_WITH_CONTEXT lower_aarch32_serror +.org 0x800 + +//------------------------------------------------------------------------------ +// fn __exception_restore_context() +//------------------------------------------------------------------------------ +__exception_restore_context: + ldr w19, [sp, #16 * 16] + ldp lr, x20, [sp, #16 * 15] + + msr SPSR_EL1, x19 + msr ELR_EL1, x20 + + ldp x0, x1, [sp, #16 * 0] + ldp x2, x3, [sp, #16 * 1] + ldp x4, x5, [sp, #16 * 2] + ldp x6, x7, [sp, #16 * 3] + ldp x8, x9, [sp, #16 * 4] + ldp x10, x11, [sp, #16 * 5] + ldp x12, x13, [sp, #16 * 6] + ldp x14, x15, [sp, #16 * 7] + ldp x16, x17, [sp, #16 * 8] + ldp x18, x19, [sp, #16 * 9] + ldp x20, x21, [sp, #16 * 10] + ldp x22, x23, [sp, #16 * 11] + ldp x24, x25, [sp, #16 * 12] + ldp x26, x27, [sp, #16 * 13] + ldp x28, x29, [sp, #16 * 14] + + add sp, sp, #16 * 17 + + eret + +.size __exception_restore_context, . - __exception_restore_context +.type __exception_restore_context, function diff --git a/17_kernel_symbols/kernel/src/_arch/aarch64/exception/asynchronous.rs b/17_kernel_symbols/kernel/src/_arch/aarch64/exception/asynchronous.rs new file mode 100644 index 00000000..73b82e65 --- /dev/null +++ b/17_kernel_symbols/kernel/src/_arch/aarch64/exception/asynchronous.rs @@ -0,0 +1,152 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2018-2022 Andre Richter + +//! Architectural asynchronous exception handling. +//! +//! # Orientation +//! +//! Since arch modules are imported into generic modules using the path attribute, the path of this +//! file is: +//! +//! crate::exception::asynchronous::arch_asynchronous + +use core::arch::asm; +use cortex_a::registers::*; +use tock_registers::interfaces::{Readable, Writeable}; + +//-------------------------------------------------------------------------------------------------- +// Private Definitions +//-------------------------------------------------------------------------------------------------- + +mod daif_bits { + pub const IRQ: u8 = 0b0010; +} + +trait DaifField { + fn daif_field() -> tock_registers::fields::Field; +} + +struct Debug; +struct SError; +struct IRQ; +struct FIQ; + +//-------------------------------------------------------------------------------------------------- +// Private Code +//-------------------------------------------------------------------------------------------------- + +impl DaifField for Debug { + fn daif_field() -> tock_registers::fields::Field { + DAIF::D + } +} + +impl DaifField for SError { + fn daif_field() -> tock_registers::fields::Field { + DAIF::A + } +} + +impl DaifField for IRQ { + fn daif_field() -> tock_registers::fields::Field { + DAIF::I + } +} + +impl DaifField for FIQ { + fn daif_field() -> tock_registers::fields::Field { + DAIF::F + } +} + +fn is_masked() -> bool +where + T: DaifField, +{ + DAIF.is_set(T::daif_field()) +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +/// Returns whether IRQs are masked on the executing core. +pub fn is_local_irq_masked() -> bool { + !is_masked::() +} + +/// Unmask IRQs on the executing core. +/// +/// It is not needed to place an explicit instruction synchronization barrier after the `msr`. +/// Quoting the Architecture Reference Manual for ARMv8-A, section C5.1.3: +/// +/// "Writes to PSTATE.{PAN, D, A, I, F} occur in program order without the need for additional +/// synchronization." +/// +/// # Safety +/// +/// - Changes the HW state of the executing core. +#[inline(always)] +pub unsafe fn local_irq_unmask() { + #[rustfmt::skip] + asm!( + "msr DAIFClr, {arg}", + arg = const daif_bits::IRQ, + options(nomem, nostack, preserves_flags) + ); +} + +/// Mask IRQs on the executing core. +/// +/// # Safety +/// +/// - Changes the HW state of the executing core. +#[inline(always)] +pub unsafe fn local_irq_mask() { + #[rustfmt::skip] + asm!( + "msr DAIFSet, {arg}", + arg = const daif_bits::IRQ, + options(nomem, nostack, preserves_flags) + ); +} + +/// Mask IRQs on the executing core and return the previously saved interrupt mask bits (DAIF). +/// +/// # Safety +/// +/// - Changes the HW state of the executing core. +#[inline(always)] +pub unsafe fn local_irq_mask_save() -> u64 { + let saved = DAIF.get(); + local_irq_mask(); + + saved +} + +/// Restore the interrupt mask bits (DAIF) using the callee's argument. +/// +/// # Safety +/// +/// - Changes the HW state of the executing core. +/// - No sanity checks on the input. +#[inline(always)] +pub unsafe fn local_irq_restore(saved: u64) { + DAIF.set(saved); +} + +/// Print the AArch64 exceptions status. +#[rustfmt::skip] +pub fn print_state() { + use crate::info; + + let to_mask_str = |x| -> _ { + if x { "Masked" } else { "Unmasked" } + }; + + info!(" Debug: {}", to_mask_str(is_masked::())); + info!(" SError: {}", to_mask_str(is_masked::())); + info!(" IRQ: {}", to_mask_str(is_masked::())); + info!(" FIQ: {}", to_mask_str(is_masked::())); +} diff --git a/17_kernel_symbols/kernel/src/_arch/aarch64/memory/mmu.rs b/17_kernel_symbols/kernel/src/_arch/aarch64/memory/mmu.rs new file mode 100644 index 00000000..3d6c18b7 --- /dev/null +++ b/17_kernel_symbols/kernel/src/_arch/aarch64/memory/mmu.rs @@ -0,0 +1,158 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2018-2022 Andre Richter + +//! Memory Management Unit Driver. +//! +//! Only 64 KiB granule is supported. +//! +//! # Orientation +//! +//! Since arch modules are imported into generic modules using the path attribute, the path of this +//! file is: +//! +//! crate::memory::mmu::arch_mmu + +use crate::{ + bsp, memory, + memory::{mmu::TranslationGranule, Address, Physical}, +}; +use core::intrinsics::unlikely; +use cortex_a::{asm::barrier, registers::*}; +use tock_registers::interfaces::{ReadWriteable, Readable, Writeable}; + +//-------------------------------------------------------------------------------------------------- +// Private Definitions +//-------------------------------------------------------------------------------------------------- + +/// Memory Management Unit type. +struct MemoryManagementUnit; + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +pub type Granule512MiB = TranslationGranule<{ 512 * 1024 * 1024 }>; +pub type Granule64KiB = TranslationGranule<{ 64 * 1024 }>; + +/// Constants for indexing the MAIR_EL1. +#[allow(dead_code)] +pub mod mair { + pub const DEVICE: u64 = 0; + pub const NORMAL: u64 = 1; +} + +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +static MMU: MemoryManagementUnit = MemoryManagementUnit; + +//-------------------------------------------------------------------------------------------------- +// Private Code +//-------------------------------------------------------------------------------------------------- + +impl memory::mmu::AddressSpace { + /// Checks for architectural restrictions. + pub const fn arch_address_space_size_sanity_checks() { + // Size must be at least one full 512 MiB table. + assert!((AS_SIZE % Granule512MiB::SIZE) == 0); + + // Check for 48 bit virtual address size as maximum, which is supported by any ARMv8 + // version. + assert!(AS_SIZE <= (1 << 48)); + } +} + +impl MemoryManagementUnit { + /// Setup function for the MAIR_EL1 register. + #[inline(always)] + fn set_up_mair(&self) { + // Define the memory types being mapped. + MAIR_EL1.write( + // Attribute 1 - Cacheable normal DRAM. + MAIR_EL1::Attr1_Normal_Outer::WriteBack_NonTransient_ReadWriteAlloc + + MAIR_EL1::Attr1_Normal_Inner::WriteBack_NonTransient_ReadWriteAlloc + + + // Attribute 0 - Device. + MAIR_EL1::Attr0_Device::nonGathering_nonReordering_EarlyWriteAck, + ); + } + + /// Configure various settings of stage 1 of the EL1 translation regime. + #[inline(always)] + fn configure_translation_control(&self) { + let t1sz = (64 - bsp::memory::mmu::KernelVirtAddrSpace::SIZE_SHIFT) as u64; + + TCR_EL1.write( + TCR_EL1::TBI1::Used + + TCR_EL1::IPS::Bits_40 + + TCR_EL1::TG1::KiB_64 + + TCR_EL1::SH1::Inner + + TCR_EL1::ORGN1::WriteBack_ReadAlloc_WriteAlloc_Cacheable + + TCR_EL1::IRGN1::WriteBack_ReadAlloc_WriteAlloc_Cacheable + + TCR_EL1::EPD1::EnableTTBR1Walks + + TCR_EL1::A1::TTBR1 + + TCR_EL1::T1SZ.val(t1sz) + + TCR_EL1::EPD0::DisableTTBR0Walks, + ); + } +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +/// Return a reference to the MMU instance. +pub fn mmu() -> &'static impl memory::mmu::interface::MMU { + &MMU +} + +//------------------------------------------------------------------------------ +// OS Interface Code +//------------------------------------------------------------------------------ +use memory::mmu::MMUEnableError; + +impl memory::mmu::interface::MMU for MemoryManagementUnit { + unsafe fn enable_mmu_and_caching( + &self, + phys_tables_base_addr: Address, + ) -> Result<(), MMUEnableError> { + if unlikely(self.is_enabled()) { + return Err(MMUEnableError::AlreadyEnabled); + } + + // Fail early if translation granule is not supported. + if unlikely(!ID_AA64MMFR0_EL1.matches_all(ID_AA64MMFR0_EL1::TGran64::Supported)) { + return Err(MMUEnableError::Other( + "Translation granule not supported in HW", + )); + } + + // Prepare the memory attribute indirection register. + self.set_up_mair(); + + // Set the "Translation Table Base Register". + TTBR1_EL1.set_baddr(phys_tables_base_addr.as_usize() as u64); + + self.configure_translation_control(); + + // Switch the MMU on. + // + // First, force all previous changes to be seen before the MMU is enabled. + barrier::isb(barrier::SY); + + // Enable the MMU and turn on data and instruction caching. + SCTLR_EL1.modify(SCTLR_EL1::M::Enable + SCTLR_EL1::C::Cacheable + SCTLR_EL1::I::Cacheable); + + // Force MMU init to complete before next instruction. + barrier::isb(barrier::SY); + + Ok(()) + } + + #[inline(always)] + fn is_enabled(&self) -> bool { + SCTLR_EL1.matches_all(SCTLR_EL1::M::Enable) + } +} diff --git a/17_kernel_symbols/kernel/src/_arch/aarch64/memory/mmu/translation_table.rs b/17_kernel_symbols/kernel/src/_arch/aarch64/memory/mmu/translation_table.rs new file mode 100644 index 00000000..f0b4ac85 --- /dev/null +++ b/17_kernel_symbols/kernel/src/_arch/aarch64/memory/mmu/translation_table.rs @@ -0,0 +1,521 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2021-2022 Andre Richter + +//! Architectural translation table. +//! +//! Only 64 KiB granule is supported. +//! +//! # Orientation +//! +//! Since arch modules are imported into generic modules using the path attribute, the path of this +//! file is: +//! +//! crate::memory::mmu::translation_table::arch_translation_table + +use crate::{ + bsp, + memory::{ + self, + mmu::{ + arch_mmu::{Granule512MiB, Granule64KiB}, + AccessPermissions, AttributeFields, MemAttributes, MemoryRegion, PageAddress, + }, + Address, Physical, Virtual, + }, +}; +use core::convert; +use tock_registers::{ + interfaces::{Readable, Writeable}, + register_bitfields, + registers::InMemoryRegister, +}; + +//-------------------------------------------------------------------------------------------------- +// Private Definitions +//-------------------------------------------------------------------------------------------------- + +// A table descriptor, as per ARMv8-A Architecture Reference Manual Figure D5-15. +register_bitfields! {u64, + STAGE1_TABLE_DESCRIPTOR [ + /// Physical address of the next descriptor. + NEXT_LEVEL_TABLE_ADDR_64KiB OFFSET(16) NUMBITS(32) [], // [47:16] + + TYPE OFFSET(1) NUMBITS(1) [ + Block = 0, + Table = 1 + ], + + VALID OFFSET(0) NUMBITS(1) [ + False = 0, + True = 1 + ] + ] +} + +// A level 3 page descriptor, as per ARMv8-A Architecture Reference Manual Figure D5-17. +register_bitfields! {u64, + STAGE1_PAGE_DESCRIPTOR [ + /// Unprivileged execute-never. + UXN OFFSET(54) NUMBITS(1) [ + False = 0, + True = 1 + ], + + /// Privileged execute-never. + PXN OFFSET(53) NUMBITS(1) [ + False = 0, + True = 1 + ], + + /// Physical address of the next table descriptor (lvl2) or the page descriptor (lvl3). + OUTPUT_ADDR_64KiB OFFSET(16) NUMBITS(32) [], // [47:16] + + /// Access flag. + AF OFFSET(10) NUMBITS(1) [ + False = 0, + True = 1 + ], + + /// Shareability field. + SH OFFSET(8) NUMBITS(2) [ + OuterShareable = 0b10, + InnerShareable = 0b11 + ], + + /// Access Permissions. + AP OFFSET(6) NUMBITS(2) [ + RW_EL1 = 0b00, + RW_EL1_EL0 = 0b01, + RO_EL1 = 0b10, + RO_EL1_EL0 = 0b11 + ], + + /// Memory attributes index into the MAIR_EL1 register. + AttrIndx OFFSET(2) NUMBITS(3) [], + + TYPE OFFSET(1) NUMBITS(1) [ + Reserved_Invalid = 0, + Page = 1 + ], + + VALID OFFSET(0) NUMBITS(1) [ + False = 0, + True = 1 + ] + ] +} + +/// A table descriptor for 64 KiB aperture. +/// +/// The output points to the next table. +#[derive(Copy, Clone)] +#[repr(C)] +struct TableDescriptor { + value: u64, +} + +/// A page descriptor with 64 KiB aperture. +/// +/// The output points to physical memory. +#[derive(Copy, Clone)] +#[repr(C)] +struct PageDescriptor { + value: u64, +} + +trait StartAddr { + fn virt_start_addr(&self) -> Address; +} + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +/// Big monolithic struct for storing the translation tables. Individual levels must be 64 KiB +/// aligned, so the lvl3 is put first. +#[repr(C)] +#[repr(align(65536))] +pub struct FixedSizeTranslationTable { + /// Page descriptors, covering 64 KiB windows per entry. + lvl3: [[PageDescriptor; 8192]; NUM_TABLES], + + /// Table descriptors, covering 512 MiB windows. + lvl2: [TableDescriptor; NUM_TABLES], + + /// Have the tables been initialized? + initialized: bool, +} + +//-------------------------------------------------------------------------------------------------- +// Private Code +//-------------------------------------------------------------------------------------------------- + +impl StartAddr for [T; N] { + fn virt_start_addr(&self) -> Address { + Address::new(self as *const _ as usize) + } +} + +impl TableDescriptor { + /// Create an instance. + /// + /// Descriptor is invalid by default. + pub const fn new_zeroed() -> Self { + Self { value: 0 } + } + + /// Create an instance pointing to the supplied address. + pub fn from_next_lvl_table_addr(phys_next_lvl_table_addr: Address) -> Self { + let val = InMemoryRegister::::new(0); + + let shifted = phys_next_lvl_table_addr.as_usize() >> Granule64KiB::SHIFT; + val.write( + STAGE1_TABLE_DESCRIPTOR::NEXT_LEVEL_TABLE_ADDR_64KiB.val(shifted as u64) + + STAGE1_TABLE_DESCRIPTOR::TYPE::Table + + STAGE1_TABLE_DESCRIPTOR::VALID::True, + ); + + TableDescriptor { value: val.get() } + } +} + +/// Convert the kernel's generic memory attributes to HW-specific attributes of the MMU. +impl convert::From + for tock_registers::fields::FieldValue +{ + fn from(attribute_fields: AttributeFields) -> Self { + // Memory attributes. + let mut desc = match attribute_fields.mem_attributes { + MemAttributes::CacheableDRAM => { + STAGE1_PAGE_DESCRIPTOR::SH::InnerShareable + + STAGE1_PAGE_DESCRIPTOR::AttrIndx.val(memory::mmu::arch_mmu::mair::NORMAL) + } + MemAttributes::Device => { + STAGE1_PAGE_DESCRIPTOR::SH::OuterShareable + + STAGE1_PAGE_DESCRIPTOR::AttrIndx.val(memory::mmu::arch_mmu::mair::DEVICE) + } + }; + + // Access Permissions. + desc += match attribute_fields.acc_perms { + AccessPermissions::ReadOnly => STAGE1_PAGE_DESCRIPTOR::AP::RO_EL1, + AccessPermissions::ReadWrite => STAGE1_PAGE_DESCRIPTOR::AP::RW_EL1, + }; + + // The execute-never attribute is mapped to PXN in AArch64. + desc += if attribute_fields.execute_never { + STAGE1_PAGE_DESCRIPTOR::PXN::True + } else { + STAGE1_PAGE_DESCRIPTOR::PXN::False + }; + + // Always set unprivileged exectue-never as long as userspace is not implemented yet. + desc += STAGE1_PAGE_DESCRIPTOR::UXN::True; + + desc + } +} + +/// Convert the HW-specific attributes of the MMU to kernel's generic memory attributes. +impl convert::TryFrom> for AttributeFields { + type Error = &'static str; + + fn try_from( + desc: InMemoryRegister, + ) -> Result { + let mem_attributes = match desc.read(STAGE1_PAGE_DESCRIPTOR::AttrIndx) { + memory::mmu::arch_mmu::mair::NORMAL => MemAttributes::CacheableDRAM, + memory::mmu::arch_mmu::mair::DEVICE => MemAttributes::Device, + _ => return Err("Unexpected memory attribute"), + }; + + let acc_perms = match desc.read_as_enum(STAGE1_PAGE_DESCRIPTOR::AP) { + Some(STAGE1_PAGE_DESCRIPTOR::AP::Value::RO_EL1) => AccessPermissions::ReadOnly, + Some(STAGE1_PAGE_DESCRIPTOR::AP::Value::RW_EL1) => AccessPermissions::ReadWrite, + _ => return Err("Unexpected access permission"), + }; + + let execute_never = desc.read(STAGE1_PAGE_DESCRIPTOR::PXN) > 0; + + Ok(AttributeFields { + mem_attributes, + acc_perms, + execute_never, + }) + } +} + +impl PageDescriptor { + /// Create an instance. + /// + /// Descriptor is invalid by default. + pub const fn new_zeroed() -> Self { + Self { value: 0 } + } + + /// Create an instance. + pub fn from_output_page_addr( + phys_output_page_addr: PageAddress, + attribute_fields: &AttributeFields, + ) -> Self { + let val = InMemoryRegister::::new(0); + + let shifted = phys_output_page_addr.into_inner().as_usize() >> Granule64KiB::SHIFT; + val.write( + STAGE1_PAGE_DESCRIPTOR::OUTPUT_ADDR_64KiB.val(shifted as u64) + + STAGE1_PAGE_DESCRIPTOR::AF::True + + STAGE1_PAGE_DESCRIPTOR::TYPE::Page + + STAGE1_PAGE_DESCRIPTOR::VALID::True + + (*attribute_fields).into(), + ); + + Self { value: val.get() } + } + + /// Returns the valid bit. + fn is_valid(&self) -> bool { + InMemoryRegister::::new(self.value) + .is_set(STAGE1_PAGE_DESCRIPTOR::VALID) + } + + /// Returns the output page. + fn output_page_addr(&self) -> PageAddress { + let shifted = InMemoryRegister::::new(self.value) + .read(STAGE1_PAGE_DESCRIPTOR::OUTPUT_ADDR_64KiB) as usize; + + PageAddress::from(shifted << Granule64KiB::SHIFT) + } + + /// Returns the attributes. + fn try_attributes(&self) -> Result { + InMemoryRegister::::new(self.value).try_into() + } +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +impl memory::mmu::AssociatedTranslationTable + for memory::mmu::AddressSpace +where + [u8; Self::SIZE >> Granule512MiB::SHIFT]: Sized, +{ + type TableStartFromTop = + FixedSizeTranslationTable<{ Self::SIZE >> Granule512MiB::SHIFT }, true>; + + type TableStartFromBottom = + FixedSizeTranslationTable<{ Self::SIZE >> Granule512MiB::SHIFT }, false>; +} + +impl + FixedSizeTranslationTable +{ + const START_FROM_TOP_OFFSET: Address = + Address::new((usize::MAX - (Granule512MiB::SIZE * NUM_TABLES)) + 1); + + /// Create an instance. + #[allow(clippy::assertions_on_constants)] + const fn _new(for_precompute: bool) -> Self { + assert!(bsp::memory::mmu::KernelGranule::SIZE == Granule64KiB::SIZE); + + // Can't have a zero-sized address space. + assert!(NUM_TABLES > 0); + + Self { + lvl3: [[PageDescriptor::new_zeroed(); 8192]; NUM_TABLES], + lvl2: [TableDescriptor::new_zeroed(); NUM_TABLES], + initialized: for_precompute, + } + } + + pub const fn new_for_precompute() -> Self { + Self::_new(true) + } + + #[cfg(test)] + pub fn new_for_runtime() -> Self { + Self::_new(false) + } + + /// Helper to calculate the lvl2 and lvl3 indices from an address. + #[inline(always)] + fn lvl2_lvl3_index_from_page_addr( + &self, + virt_page_addr: PageAddress, + ) -> Result<(usize, usize), &'static str> { + let mut addr = virt_page_addr.into_inner(); + + if START_FROM_TOP { + addr = addr - Self::START_FROM_TOP_OFFSET; + } + + let lvl2_index = addr.as_usize() >> Granule512MiB::SHIFT; + let lvl3_index = (addr.as_usize() & Granule512MiB::MASK) >> Granule64KiB::SHIFT; + + if lvl2_index > (NUM_TABLES - 1) { + return Err("Virtual page is out of bounds of translation table"); + } + + Ok((lvl2_index, lvl3_index)) + } + + /// Returns the PageDescriptor corresponding to the supplied page address. + #[inline(always)] + fn page_descriptor_from_page_addr( + &self, + virt_page_addr: PageAddress, + ) -> Result<&PageDescriptor, &'static str> { + let (lvl2_index, lvl3_index) = self.lvl2_lvl3_index_from_page_addr(virt_page_addr)?; + let desc = &self.lvl3[lvl2_index][lvl3_index]; + + Ok(desc) + } + + /// Sets the PageDescriptor corresponding to the supplied page address. + /// + /// Doesn't allow overriding an already valid page. + #[inline(always)] + fn set_page_descriptor_from_page_addr( + &mut self, + virt_page_addr: PageAddress, + new_desc: &PageDescriptor, + ) -> Result<(), &'static str> { + let (lvl2_index, lvl3_index) = self.lvl2_lvl3_index_from_page_addr(virt_page_addr)?; + let desc = &mut self.lvl3[lvl2_index][lvl3_index]; + + if desc.is_valid() { + return Err("Virtual page is already mapped"); + } + + *desc = *new_desc; + Ok(()) + } +} + +//------------------------------------------------------------------------------ +// OS Interface Code +//------------------------------------------------------------------------------ + +impl + memory::mmu::translation_table::interface::TranslationTable + for FixedSizeTranslationTable +{ + fn init(&mut self) -> Result<(), &'static str> { + if self.initialized { + return Ok(()); + } + + // Populate the l2 entries. + for (lvl2_nr, lvl2_entry) in self.lvl2.iter_mut().enumerate() { + let virt_table_addr = self.lvl3[lvl2_nr].virt_start_addr(); + let phys_table_addr = memory::mmu::try_kernel_virt_addr_to_phys_addr(virt_table_addr)?; + + let new_desc = TableDescriptor::from_next_lvl_table_addr(phys_table_addr); + *lvl2_entry = new_desc; + } + + self.initialized = true; + + Ok(()) + } + + unsafe fn map_at( + &mut self, + virt_region: &MemoryRegion, + phys_region: &MemoryRegion, + attr: &AttributeFields, + ) -> Result<(), &'static str> { + assert!(self.initialized, "Translation tables not initialized"); + + if virt_region.size() != phys_region.size() { + return Err("Tried to map memory regions with unequal sizes"); + } + + if phys_region.end_exclusive_page_addr() > bsp::memory::phys_addr_space_end_exclusive_addr() + { + return Err("Tried to map outside of physical address space"); + } + + let iter = phys_region.into_iter().zip(virt_region.into_iter()); + for (phys_page_addr, virt_page_addr) in iter { + let new_desc = PageDescriptor::from_output_page_addr(phys_page_addr, attr); + let virt_page = virt_page_addr; + + self.set_page_descriptor_from_page_addr(virt_page, &new_desc)?; + } + + Ok(()) + } + + fn try_virt_page_addr_to_phys_page_addr( + &self, + virt_page_addr: PageAddress, + ) -> Result, &'static str> { + let page_desc = self.page_descriptor_from_page_addr(virt_page_addr)?; + + if !page_desc.is_valid() { + return Err("Page marked invalid"); + } + + Ok(page_desc.output_page_addr()) + } + + fn try_page_attributes( + &self, + virt_page_addr: PageAddress, + ) -> Result { + let page_desc = self.page_descriptor_from_page_addr(virt_page_addr)?; + + if !page_desc.is_valid() { + return Err("Page marked invalid"); + } + + page_desc.try_attributes() + } + + /// Try to translate a virtual address to a physical address. + /// + /// Will only succeed if there exists a valid mapping for the input address. + fn try_virt_addr_to_phys_addr( + &self, + virt_addr: Address, + ) -> Result, &'static str> { + let virt_page = PageAddress::from(virt_addr.align_down_page()); + let phys_page = self.try_virt_page_addr_to_phys_page_addr(virt_page)?; + + Ok(phys_page.into_inner() + virt_addr.offset_into_page()) + } +} + +//-------------------------------------------------------------------------------------------------- +// Testing +//-------------------------------------------------------------------------------------------------- + +#[cfg(test)] +pub type MinSizeTranslationTable = FixedSizeTranslationTable<1, true>; + +#[cfg(test)] +mod tests { + use super::*; + use test_macros::kernel_test; + + /// Check if the size of `struct TableDescriptor` is as expected. + #[kernel_test] + fn size_of_tabledescriptor_equals_64_bit() { + assert_eq!( + core::mem::size_of::(), + core::mem::size_of::() + ); + } + + /// Check if the size of `struct PageDescriptor` is as expected. + #[kernel_test] + fn size_of_pagedescriptor_equals_64_bit() { + assert_eq!( + core::mem::size_of::(), + core::mem::size_of::() + ); + } +} diff --git a/17_kernel_symbols/kernel/src/_arch/aarch64/time.rs b/17_kernel_symbols/kernel/src/_arch/aarch64/time.rs new file mode 100644 index 00000000..c814219c --- /dev/null +++ b/17_kernel_symbols/kernel/src/_arch/aarch64/time.rs @@ -0,0 +1,121 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2018-2022 Andre Richter + +//! Architectural timer primitives. +//! +//! # Orientation +//! +//! Since arch modules are imported into generic modules using the path attribute, the path of this +//! file is: +//! +//! crate::time::arch_time + +use crate::{time, warn}; +use core::time::Duration; +use cortex_a::{asm::barrier, registers::*}; +use tock_registers::interfaces::{ReadWriteable, Readable, Writeable}; + +//-------------------------------------------------------------------------------------------------- +// Private Definitions +//-------------------------------------------------------------------------------------------------- + +const NS_PER_S: u64 = 1_000_000_000; + +/// ARMv8 Generic Timer. +struct GenericTimer; + +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +static TIME_MANAGER: GenericTimer = GenericTimer; + +//-------------------------------------------------------------------------------------------------- +// Private Code +//-------------------------------------------------------------------------------------------------- + +impl GenericTimer { + #[inline(always)] + fn read_cntpct(&self) -> u64 { + // Prevent that the counter is read ahead of time due to out-of-order execution. + unsafe { barrier::isb(barrier::SY) }; + CNTPCT_EL0.get() + } +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +/// Return a reference to the time manager. +pub fn time_manager() -> &'static impl time::interface::TimeManager { + &TIME_MANAGER +} + +//------------------------------------------------------------------------------ +// OS Interface Code +//------------------------------------------------------------------------------ + +impl time::interface::TimeManager for GenericTimer { + fn resolution(&self) -> Duration { + Duration::from_nanos(NS_PER_S / (CNTFRQ_EL0.get() as u64)) + } + + fn uptime(&self) -> Duration { + let current_count: u64 = self.read_cntpct() * NS_PER_S; + let frq: u64 = CNTFRQ_EL0.get() as u64; + + Duration::from_nanos(current_count / frq) + } + + fn spin_for(&self, duration: Duration) { + // Instantly return on zero. + if duration.as_nanos() == 0 { + return; + } + + // Calculate the register compare value. + let frq = CNTFRQ_EL0.get(); + let x = match frq.checked_mul(duration.as_nanos() as u64) { + #[allow(unused_imports)] + None => { + warn!("Spin duration too long, skipping"); + return; + } + Some(val) => val, + }; + let tval = x / NS_PER_S; + + // Check if it is within supported bounds. + let warn: Option<&str> = if tval == 0 { + Some("smaller") + // The upper 32 bits of CNTP_TVAL_EL0 are reserved. + } else if tval > u32::max_value().into() { + Some("bigger") + } else { + None + }; + + #[allow(unused_imports)] + if let Some(w) = warn { + warn!( + "Spin duration {} than architecturally supported, skipping", + w + ); + return; + } + + // Set the compare value register. + CNTP_TVAL_EL0.set(tval); + + // Kick off the counting. // Disable timer interrupt. + CNTP_CTL_EL0.modify(CNTP_CTL_EL0::ENABLE::SET + CNTP_CTL_EL0::IMASK::SET); + + // ISTATUS will be '1' when cval ticks have passed. Busy-check it. + while !CNTP_CTL_EL0.matches_all(CNTP_CTL_EL0::ISTATUS::SET) {} + + // Disable counting again. + CNTP_CTL_EL0.modify(CNTP_CTL_EL0::ENABLE::CLEAR); + } +} diff --git a/17_kernel_symbols/kernel/src/bsp.rs b/17_kernel_symbols/kernel/src/bsp.rs new file mode 100644 index 00000000..824787f6 --- /dev/null +++ b/17_kernel_symbols/kernel/src/bsp.rs @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2018-2022 Andre Richter + +//! Conditional reexporting of Board Support Packages. + +mod device_driver; + +#[cfg(any(feature = "bsp_rpi3", feature = "bsp_rpi4"))] +mod raspberrypi; + +#[cfg(any(feature = "bsp_rpi3", feature = "bsp_rpi4"))] +pub use raspberrypi::*; diff --git a/17_kernel_symbols/kernel/src/bsp/device_driver.rs b/17_kernel_symbols/kernel/src/bsp/device_driver.rs new file mode 100644 index 00000000..eafaf775 --- /dev/null +++ b/17_kernel_symbols/kernel/src/bsp/device_driver.rs @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2018-2022 Andre Richter + +//! Device driver. + +#[cfg(feature = "bsp_rpi4")] +mod arm; +#[cfg(any(feature = "bsp_rpi3", feature = "bsp_rpi4"))] +mod bcm; +mod common; + +#[cfg(feature = "bsp_rpi4")] +pub use arm::*; +#[cfg(any(feature = "bsp_rpi3", feature = "bsp_rpi4"))] +pub use bcm::*; diff --git a/17_kernel_symbols/kernel/src/bsp/device_driver/arm.rs b/17_kernel_symbols/kernel/src/bsp/device_driver/arm.rs new file mode 100644 index 00000000..e83e24c9 --- /dev/null +++ b/17_kernel_symbols/kernel/src/bsp/device_driver/arm.rs @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2020-2022 Andre Richter + +//! ARM driver top level. + +pub mod gicv2; + +pub use gicv2::*; diff --git a/17_kernel_symbols/kernel/src/bsp/device_driver/arm/gicv2.rs b/17_kernel_symbols/kernel/src/bsp/device_driver/arm/gicv2.rs new file mode 100644 index 00000000..4c68a692 --- /dev/null +++ b/17_kernel_symbols/kernel/src/bsp/device_driver/arm/gicv2.rs @@ -0,0 +1,246 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2020-2022 Andre Richter + +//! GICv2 Driver - ARM Generic Interrupt Controller v2. +//! +//! The following is a collection of excerpts with useful information from +//! - `Programmer's Guide for ARMv8-A` +//! - `ARM Generic Interrupt Controller Architecture Specification` +//! +//! # Programmer's Guide - 10.6.1 Configuration +//! +//! The GIC is accessed as a memory-mapped peripheral. +//! +//! All cores can access the common Distributor, but the CPU interface is banked, that is, each core +//! uses the same address to access its own private CPU interface. +//! +//! It is not possible for a core to access the CPU interface of another core. +//! +//! # Architecture Specification - 10.6.2 Initialization +//! +//! Both the Distributor and the CPU interfaces are disabled at reset. The GIC must be initialized +//! after reset before it can deliver interrupts to the core. +//! +//! In the Distributor, software must configure the priority, target, security and enable individual +//! interrupts. The Distributor must subsequently be enabled through its control register +//! (GICD_CTLR). For each CPU interface, software must program the priority mask and preemption +//! settings. +//! +//! Each CPU interface block itself must be enabled through its control register (GICD_CTLR). This +//! prepares the GIC to deliver interrupts to the core. +//! +//! Before interrupts are expected in the core, software prepares the core to take interrupts by +//! setting a valid interrupt vector in the vector table, and clearing interrupt mask bits in +//! PSTATE, and setting the routing controls. +//! +//! The entire interrupt mechanism in the system can be disabled by disabling the Distributor. +//! Interrupt delivery to an individual core can be disabled by disabling its CPU interface. +//! Individual interrupts can also be disabled (or enabled) in the distributor. +//! +//! For an interrupt to reach the core, the individual interrupt, Distributor and CPU interface must +//! all be enabled. The interrupt also needs to be of sufficient priority, that is, higher than the +//! core's priority mask. +//! +//! # Architecture Specification - 1.4.2 Interrupt types +//! +//! - Peripheral interrupt +//! - Private Peripheral Interrupt (PPI) +//! - This is a peripheral interrupt that is specific to a single processor. +//! - Shared Peripheral Interrupt (SPI) +//! - This is a peripheral interrupt that the Distributor can route to any of a specified +//! combination of processors. +//! +//! - Software-generated interrupt (SGI) +//! - This is an interrupt generated by software writing to a GICD_SGIR register in the GIC. The +//! system uses SGIs for interprocessor communication. +//! - An SGI has edge-triggered properties. The software triggering of the interrupt is +//! equivalent to the edge transition of the interrupt request signal. +//! - When an SGI occurs in a multiprocessor implementation, the CPUID field in the Interrupt +//! Acknowledge Register, GICC_IAR, or the Aliased Interrupt Acknowledge Register, GICC_AIAR, +//! identifies the processor that requested the interrupt. +//! +//! # Architecture Specification - 2.2.1 Interrupt IDs +//! +//! Interrupts from sources are identified using ID numbers. Each CPU interface can see up to 1020 +//! interrupts. The banking of SPIs and PPIs increases the total number of interrupts supported by +//! the Distributor. +//! +//! The GIC assigns interrupt ID numbers ID0-ID1019 as follows: +//! - Interrupt numbers 32..1019 are used for SPIs. +//! - Interrupt numbers 0..31 are used for interrupts that are private to a CPU interface. These +//! interrupts are banked in the Distributor. +//! - A banked interrupt is one where the Distributor can have multiple interrupts with the +//! same ID. A banked interrupt is identified uniquely by its ID number and its associated +//! CPU interface number. Of the banked interrupt IDs: +//! - 00..15 SGIs +//! - 16..31 PPIs + +mod gicc; +mod gicd; + +use crate::{bsp, cpu, driver, exception, memory, synchronization, synchronization::InitStateLock}; +use core::sync::atomic::{AtomicBool, Ordering}; + +//-------------------------------------------------------------------------------------------------- +// Private Definitions +//-------------------------------------------------------------------------------------------------- + +type HandlerTable = [Option; GICv2::NUM_IRQS]; + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +/// Used for the associated type of trait [`exception::asynchronous::interface::IRQManager`]. +pub type IRQNumber = exception::asynchronous::IRQNumber<{ GICv2::MAX_IRQ_NUMBER }>; + +/// Representation of the GIC. +pub struct GICv2 { + gicd_mmio_descriptor: memory::mmu::MMIODescriptor, + gicc_mmio_descriptor: memory::mmu::MMIODescriptor, + + /// The Distributor. + gicd: gicd::GICD, + + /// The CPU Interface. + gicc: gicc::GICC, + + /// Have the MMIO regions been remapped yet? + is_mmio_remapped: AtomicBool, + + /// Stores registered IRQ handlers. Writable only during kernel init. RO afterwards. + handler_table: InitStateLock, +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +impl GICv2 { + const MAX_IRQ_NUMBER: usize = 300; // Normally 1019, but keep it lower to save some space. + const NUM_IRQS: usize = Self::MAX_IRQ_NUMBER + 1; + + /// Create an instance. + /// + /// # Safety + /// + /// - The user must ensure to provide correct MMIO descriptors. + pub const unsafe fn new( + gicd_mmio_descriptor: memory::mmu::MMIODescriptor, + gicc_mmio_descriptor: memory::mmu::MMIODescriptor, + ) -> Self { + Self { + gicd_mmio_descriptor, + gicc_mmio_descriptor, + gicd: gicd::GICD::new(gicd_mmio_descriptor.start_addr().as_usize()), + gicc: gicc::GICC::new(gicc_mmio_descriptor.start_addr().as_usize()), + is_mmio_remapped: AtomicBool::new(false), + handler_table: InitStateLock::new([None; Self::NUM_IRQS]), + } + } +} + +//------------------------------------------------------------------------------ +// OS Interface Code +//------------------------------------------------------------------------------ +use synchronization::interface::ReadWriteEx; + +impl driver::interface::DeviceDriver for GICv2 { + fn compatible(&self) -> &'static str { + "GICv2 (ARM Generic Interrupt Controller v2)" + } + + unsafe fn init(&self) -> Result<(), &'static str> { + let remapped = self.is_mmio_remapped.load(Ordering::Relaxed); + if !remapped { + // GICD + let mut virt_addr = memory::mmu::kernel_map_mmio("GICD", &self.gicd_mmio_descriptor)?; + self.gicd.set_mmio(virt_addr.as_usize()); + + // GICC + virt_addr = memory::mmu::kernel_map_mmio("GICC", &self.gicc_mmio_descriptor)?; + self.gicc.set_mmio(virt_addr.as_usize()); + + // Conclude remapping. + self.is_mmio_remapped.store(true, Ordering::Relaxed); + } + + if bsp::cpu::BOOT_CORE_ID == cpu::smp::core_id() { + self.gicd.boot_core_init(); + } + + self.gicc.priority_accept_all(); + self.gicc.enable(); + + Ok(()) + } +} + +impl exception::asynchronous::interface::IRQManager for GICv2 { + type IRQNumberType = IRQNumber; + + fn register_handler( + &self, + irq_number: Self::IRQNumberType, + descriptor: exception::asynchronous::IRQDescriptor, + ) -> Result<(), &'static str> { + self.handler_table.write(|table| { + let irq_number = irq_number.get(); + + if table[irq_number].is_some() { + return Err("IRQ handler already registered"); + } + + table[irq_number] = Some(descriptor); + + Ok(()) + }) + } + + fn enable(&self, irq_number: Self::IRQNumberType) { + self.gicd.enable(irq_number); + } + + fn handle_pending_irqs<'irq_context>( + &'irq_context self, + ic: &exception::asynchronous::IRQContext<'irq_context>, + ) { + // Extract the highest priority pending IRQ number from the Interrupt Acknowledge Register + // (IAR). + let irq_number = self.gicc.pending_irq_number(ic); + + // Guard against spurious interrupts. + if irq_number > GICv2::MAX_IRQ_NUMBER { + return; + } + + // Call the IRQ handler. Panic if there is none. + self.handler_table.read(|table| { + match table[irq_number] { + None => panic!("No handler registered for IRQ {}", irq_number), + Some(descriptor) => { + // Call the IRQ handler. Panics on failure. + descriptor.handler.handle().expect("Error handling IRQ"); + } + } + }); + + // Signal completion of handling. + self.gicc.mark_comleted(irq_number as u32, ic); + } + + fn print_handler(&self) { + use crate::info; + + info!(" Peripheral handler:"); + + self.handler_table.read(|table| { + for (i, opt) in table.iter().skip(32).enumerate() { + if let Some(handler) = opt { + info!(" {: >3}. {}", i + 32, handler.name); + } + } + }); + } +} diff --git a/17_kernel_symbols/kernel/src/bsp/device_driver/arm/gicv2/gicc.rs b/17_kernel_symbols/kernel/src/bsp/device_driver/arm/gicv2/gicc.rs new file mode 100644 index 00000000..1a151d24 --- /dev/null +++ b/17_kernel_symbols/kernel/src/bsp/device_driver/arm/gicv2/gicc.rs @@ -0,0 +1,156 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2020-2022 Andre Richter + +//! GICC Driver - GIC CPU interface. + +use crate::{ + bsp::device_driver::common::MMIODerefWrapper, exception, synchronization::InitStateLock, +}; +use tock_registers::{ + interfaces::{Readable, Writeable}, + register_bitfields, register_structs, + registers::ReadWrite, +}; + +//-------------------------------------------------------------------------------------------------- +// Private Definitions +//-------------------------------------------------------------------------------------------------- + +register_bitfields! { + u32, + + /// CPU Interface Control Register + CTLR [ + Enable OFFSET(0) NUMBITS(1) [] + ], + + /// Interrupt Priority Mask Register + PMR [ + Priority OFFSET(0) NUMBITS(8) [] + ], + + /// Interrupt Acknowledge Register + IAR [ + InterruptID OFFSET(0) NUMBITS(10) [] + ], + + /// End of Interrupt Register + EOIR [ + EOIINTID OFFSET(0) NUMBITS(10) [] + ] +} + +register_structs! { + #[allow(non_snake_case)] + pub RegisterBlock { + (0x000 => CTLR: ReadWrite), + (0x004 => PMR: ReadWrite), + (0x008 => _reserved1), + (0x00C => IAR: ReadWrite), + (0x010 => EOIR: ReadWrite), + (0x014 => @END), + } +} + +/// Abstraction for the associated MMIO registers. +type Registers = MMIODerefWrapper; + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +/// Representation of the GIC CPU interface. +pub struct GICC { + registers: InitStateLock, +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- +use crate::synchronization::interface::ReadWriteEx; + +impl GICC { + /// Create an instance. + /// + /// # Safety + /// + /// - The user must ensure to provide a correct MMIO start address. + pub const unsafe fn new(mmio_start_addr: usize) -> Self { + Self { + registers: InitStateLock::new(Registers::new(mmio_start_addr)), + } + } + + pub unsafe fn set_mmio(&self, new_mmio_start_addr: usize) { + self.registers + .write(|regs| *regs = Registers::new(new_mmio_start_addr)); + } + + /// Accept interrupts of any priority. + /// + /// Quoting the GICv2 Architecture Specification: + /// + /// "Writing 255 to the GICC_PMR always sets it to the largest supported priority field + /// value." + /// + /// # Safety + /// + /// - GICC MMIO registers are banked per CPU core. It is therefore safe to have `&self` instead + /// of `&mut self`. + pub fn priority_accept_all(&self) { + self.registers.read(|regs| { + regs.PMR.write(PMR::Priority.val(255)); // Comment in arch spec. + }); + } + + /// Enable the interface - start accepting IRQs. + /// + /// # Safety + /// + /// - GICC MMIO registers are banked per CPU core. It is therefore safe to have `&self` instead + /// of `&mut self`. + pub fn enable(&self) { + self.registers.read(|regs| { + regs.CTLR.write(CTLR::Enable::SET); + }); + } + + /// Extract the number of the highest-priority pending IRQ. + /// + /// Can only be called from IRQ context, which is ensured by taking an `IRQContext` token. + /// + /// # Safety + /// + /// - GICC MMIO registers are banked per CPU core. It is therefore safe to have `&self` instead + /// of `&mut self`. + #[allow(clippy::trivially_copy_pass_by_ref)] + pub fn pending_irq_number<'irq_context>( + &self, + _ic: &exception::asynchronous::IRQContext<'irq_context>, + ) -> usize { + self.registers + .read(|regs| regs.IAR.read(IAR::InterruptID) as usize) + } + + /// Complete handling of the currently active IRQ. + /// + /// Can only be called from IRQ context, which is ensured by taking an `IRQContext` token. + /// + /// To be called after `pending_irq_number()`. + /// + /// # Safety + /// + /// - GICC MMIO registers are banked per CPU core. It is therefore safe to have `&self` instead + /// of `&mut self`. + #[allow(clippy::trivially_copy_pass_by_ref)] + pub fn mark_comleted<'irq_context>( + &self, + irq_number: u32, + _ic: &exception::asynchronous::IRQContext<'irq_context>, + ) { + self.registers.read(|regs| { + regs.EOIR.write(EOIR::EOIINTID.val(irq_number)); + }); + } +} diff --git a/17_kernel_symbols/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs b/17_kernel_symbols/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs new file mode 100644 index 00000000..60bbc468 --- /dev/null +++ b/17_kernel_symbols/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs @@ -0,0 +1,209 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2020-2022 Andre Richter + +//! GICD Driver - GIC Distributor. +//! +//! # Glossary +//! - SPI - Shared Peripheral Interrupt. + +use crate::{ + bsp::device_driver::common::MMIODerefWrapper, + state, synchronization, + synchronization::{IRQSafeNullLock, InitStateLock}, +}; +use tock_registers::{ + interfaces::{Readable, Writeable}, + register_bitfields, register_structs, + registers::{ReadOnly, ReadWrite}, +}; + +//-------------------------------------------------------------------------------------------------- +// Private Definitions +//-------------------------------------------------------------------------------------------------- + +register_bitfields! { + u32, + + /// Distributor Control Register + CTLR [ + Enable OFFSET(0) NUMBITS(1) [] + ], + + /// Interrupt Controller Type Register + TYPER [ + ITLinesNumber OFFSET(0) NUMBITS(5) [] + ], + + /// Interrupt Processor Targets Registers + ITARGETSR [ + Offset3 OFFSET(24) NUMBITS(8) [], + Offset2 OFFSET(16) NUMBITS(8) [], + Offset1 OFFSET(8) NUMBITS(8) [], + Offset0 OFFSET(0) NUMBITS(8) [] + ] +} + +register_structs! { + #[allow(non_snake_case)] + SharedRegisterBlock { + (0x000 => CTLR: ReadWrite), + (0x004 => TYPER: ReadOnly), + (0x008 => _reserved1), + (0x104 => ISENABLER: [ReadWrite; 31]), + (0x108 => _reserved2), + (0x820 => ITARGETSR: [ReadWrite; 248]), + (0x824 => @END), + } +} + +register_structs! { + #[allow(non_snake_case)] + BankedRegisterBlock { + (0x000 => _reserved1), + (0x100 => ISENABLER: ReadWrite), + (0x104 => _reserved2), + (0x800 => ITARGETSR: [ReadOnly; 8]), + (0x804 => @END), + } +} + +/// Abstraction for the non-banked parts of the associated MMIO registers. +type SharedRegisters = MMIODerefWrapper; + +/// Abstraction for the banked parts of the associated MMIO registers. +type BankedRegisters = MMIODerefWrapper; + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +/// Representation of the GIC Distributor. +pub struct GICD { + /// Access to shared registers is guarded with a lock. + shared_registers: IRQSafeNullLock, + + /// Access to banked registers is unguarded. + banked_registers: InitStateLock, +} + +//-------------------------------------------------------------------------------------------------- +// Private Code +//-------------------------------------------------------------------------------------------------- + +impl SharedRegisters { + /// Return the number of IRQs that this HW implements. + #[inline(always)] + fn num_irqs(&mut self) -> usize { + // Query number of implemented IRQs. + // + // Refer to GICv2 Architecture Specification, Section 4.3.2. + ((self.TYPER.read(TYPER::ITLinesNumber) as usize) + 1) * 32 + } + + /// Return a slice of the implemented ITARGETSR. + #[inline(always)] + fn implemented_itargets_slice(&mut self) -> &[ReadWrite] { + assert!(self.num_irqs() >= 36); + + // Calculate the max index of the shared ITARGETSR array. + // + // The first 32 IRQs are private, so not included in `shared_registers`. Each ITARGETS + // register has four entries, so shift right by two. Subtract one because we start + // counting at zero. + let spi_itargetsr_max_index = ((self.num_irqs() - 32) >> 2) - 1; + + // Rust automatically inserts slice range sanity check, i.e. max >= min. + &self.ITARGETSR[0..spi_itargetsr_max_index] + } +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- +use crate::synchronization::interface::ReadWriteEx; +use synchronization::interface::Mutex; + +impl GICD { + /// Create an instance. + /// + /// # Safety + /// + /// - The user must ensure to provide a correct MMIO start address. + pub const unsafe fn new(mmio_start_addr: usize) -> Self { + Self { + shared_registers: IRQSafeNullLock::new(SharedRegisters::new(mmio_start_addr)), + banked_registers: InitStateLock::new(BankedRegisters::new(mmio_start_addr)), + } + } + + pub unsafe fn set_mmio(&self, new_mmio_start_addr: usize) { + self.shared_registers + .lock(|regs| *regs = SharedRegisters::new(new_mmio_start_addr)); + self.banked_registers + .write(|regs| *regs = BankedRegisters::new(new_mmio_start_addr)); + } + + /// Use a banked ITARGETSR to retrieve the executing core's GIC target mask. + /// + /// Quoting the GICv2 Architecture Specification: + /// + /// "GICD_ITARGETSR0 to GICD_ITARGETSR7 are read-only, and each field returns a value that + /// corresponds only to the processor reading the register." + fn local_gic_target_mask(&self) -> u32 { + self.banked_registers + .read(|regs| regs.ITARGETSR[0].read(ITARGETSR::Offset0)) + } + + /// Route all SPIs to the boot core and enable the distributor. + pub fn boot_core_init(&self) { + assert!( + state::state_manager().is_init(), + "Only allowed during kernel init phase" + ); + + // Target all SPIs to the boot core only. + let mask = self.local_gic_target_mask(); + + self.shared_registers.lock(|regs| { + for i in regs.implemented_itargets_slice().iter() { + i.write( + ITARGETSR::Offset3.val(mask) + + ITARGETSR::Offset2.val(mask) + + ITARGETSR::Offset1.val(mask) + + ITARGETSR::Offset0.val(mask), + ); + } + + regs.CTLR.write(CTLR::Enable::SET); + }); + } + + /// Enable an interrupt. + pub fn enable(&self, irq_num: super::IRQNumber) { + let irq_num = irq_num.get(); + + // Each bit in the u32 enable register corresponds to one IRQ number. Shift right by 5 + // (division by 32) and arrive at the index for the respective ISENABLER[i]. + let enable_reg_index = irq_num >> 5; + let enable_bit: u32 = 1u32 << (irq_num % 32); + + // Check if we are handling a private or shared IRQ. + match irq_num { + // Private. + 0..=31 => self.banked_registers.read(|regs| { + let enable_reg = ®s.ISENABLER; + enable_reg.set(enable_reg.get() | enable_bit); + }), + // Shared. + _ => { + let enable_reg_index_shared = enable_reg_index - 1; + + self.shared_registers.lock(|regs| { + let enable_reg = ®s.ISENABLER[enable_reg_index_shared]; + enable_reg.set(enable_reg.get() | enable_bit); + }); + } + } + } +} diff --git a/17_kernel_symbols/kernel/src/bsp/device_driver/bcm.rs b/17_kernel_symbols/kernel/src/bsp/device_driver/bcm.rs new file mode 100644 index 00000000..5a7cc23b --- /dev/null +++ b/17_kernel_symbols/kernel/src/bsp/device_driver/bcm.rs @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2018-2022 Andre Richter + +//! BCM driver top level. + +mod bcm2xxx_gpio; +#[cfg(feature = "bsp_rpi3")] +mod bcm2xxx_interrupt_controller; +mod bcm2xxx_pl011_uart; + +pub use bcm2xxx_gpio::*; +#[cfg(feature = "bsp_rpi3")] +pub use bcm2xxx_interrupt_controller::*; +pub use bcm2xxx_pl011_uart::*; diff --git a/17_kernel_symbols/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs b/17_kernel_symbols/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs new file mode 100644 index 00000000..eea07b75 --- /dev/null +++ b/17_kernel_symbols/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs @@ -0,0 +1,259 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2018-2022 Andre Richter + +//! GPIO Driver. + +use crate::{ + bsp::device_driver::common::MMIODerefWrapper, driver, memory, synchronization, + synchronization::IRQSafeNullLock, +}; +use core::sync::atomic::{AtomicUsize, Ordering}; +use tock_registers::{ + interfaces::{ReadWriteable, Writeable}, + register_bitfields, register_structs, + registers::ReadWrite, +}; + +//-------------------------------------------------------------------------------------------------- +// Private Definitions +//-------------------------------------------------------------------------------------------------- + +// GPIO registers. +// +// Descriptions taken from +// - https://github.com/raspberrypi/documentation/files/1888662/BCM2837-ARM-Peripherals.-.Revised.-.V2-1.pdf +// - https://datasheets.raspberrypi.org/bcm2711/bcm2711-peripherals.pdf +register_bitfields! { + u32, + + /// GPIO Function Select 1 + GPFSEL1 [ + /// Pin 15 + FSEL15 OFFSET(15) NUMBITS(3) [ + Input = 0b000, + Output = 0b001, + AltFunc0 = 0b100 // PL011 UART RX + + ], + + /// Pin 14 + FSEL14 OFFSET(12) NUMBITS(3) [ + Input = 0b000, + Output = 0b001, + AltFunc0 = 0b100 // PL011 UART TX + ] + ], + + /// GPIO Pull-up/down Register + /// + /// BCM2837 only. + GPPUD [ + /// Controls the actuation of the internal pull-up/down control line to ALL the GPIO pins. + PUD OFFSET(0) NUMBITS(2) [ + Off = 0b00, + PullDown = 0b01, + PullUp = 0b10 + ] + ], + + /// GPIO Pull-up/down Clock Register 0 + /// + /// BCM2837 only. + GPPUDCLK0 [ + /// Pin 15 + PUDCLK15 OFFSET(15) NUMBITS(1) [ + NoEffect = 0, + AssertClock = 1 + ], + + /// Pin 14 + PUDCLK14 OFFSET(14) NUMBITS(1) [ + NoEffect = 0, + AssertClock = 1 + ] + ], + + /// GPIO Pull-up / Pull-down Register 0 + /// + /// BCM2711 only. + GPIO_PUP_PDN_CNTRL_REG0 [ + /// Pin 15 + GPIO_PUP_PDN_CNTRL15 OFFSET(30) NUMBITS(2) [ + NoResistor = 0b00, + PullUp = 0b01 + ], + + /// Pin 14 + GPIO_PUP_PDN_CNTRL14 OFFSET(28) NUMBITS(2) [ + NoResistor = 0b00, + PullUp = 0b01 + ] + ] +} + +register_structs! { + #[allow(non_snake_case)] + RegisterBlock { + (0x00 => _reserved1), + (0x04 => GPFSEL1: ReadWrite), + (0x08 => _reserved2), + (0x94 => GPPUD: ReadWrite), + (0x98 => GPPUDCLK0: ReadWrite), + (0x9C => _reserved3), + (0xE4 => GPIO_PUP_PDN_CNTRL_REG0: ReadWrite), + (0xE8 => @END), + } +} + +/// Abstraction for the associated MMIO registers. +type Registers = MMIODerefWrapper; + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +pub struct GPIOInner { + registers: Registers, +} + +// Export the inner struct so that BSPs can use it for the panic handler. +pub use GPIOInner as PanicGPIO; + +/// Representation of the GPIO HW. +pub struct GPIO { + mmio_descriptor: memory::mmu::MMIODescriptor, + virt_mmio_start_addr: AtomicUsize, + inner: IRQSafeNullLock, +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +impl GPIOInner { + /// Create an instance. + /// + /// # Safety + /// + /// - The user must ensure to provide a correct MMIO start address. + pub const unsafe fn new(mmio_start_addr: usize) -> Self { + Self { + registers: Registers::new(mmio_start_addr), + } + } + + /// Init code. + /// + /// # Safety + /// + /// - The user must ensure to provide a correct MMIO start address. + pub unsafe fn init(&mut self, new_mmio_start_addr: Option) -> Result<(), &'static str> { + if let Some(addr) = new_mmio_start_addr { + self.registers = Registers::new(addr); + } + + Ok(()) + } + + /// Disable pull-up/down on pins 14 and 15. + #[cfg(feature = "bsp_rpi3")] + fn disable_pud_14_15_bcm2837(&mut self) { + use crate::{time, time::interface::TimeManager}; + use core::time::Duration; + + // The Linux 2837 GPIO driver waits 1 µs between the steps. + const DELAY: Duration = Duration::from_micros(1); + + self.registers.GPPUD.write(GPPUD::PUD::Off); + time::time_manager().spin_for(DELAY); + + self.registers + .GPPUDCLK0 + .write(GPPUDCLK0::PUDCLK15::AssertClock + GPPUDCLK0::PUDCLK14::AssertClock); + time::time_manager().spin_for(DELAY); + + self.registers.GPPUD.write(GPPUD::PUD::Off); + self.registers.GPPUDCLK0.set(0); + } + + /// Disable pull-up/down on pins 14 and 15. + #[cfg(feature = "bsp_rpi4")] + fn disable_pud_14_15_bcm2711(&mut self) { + self.registers.GPIO_PUP_PDN_CNTRL_REG0.write( + GPIO_PUP_PDN_CNTRL_REG0::GPIO_PUP_PDN_CNTRL15::PullUp + + GPIO_PUP_PDN_CNTRL_REG0::GPIO_PUP_PDN_CNTRL14::PullUp, + ); + } + + /// Map PL011 UART as standard output. + /// + /// TX to pin 14 + /// RX to pin 15 + pub fn map_pl011_uart(&mut self) { + // Select the UART on pins 14 and 15. + self.registers + .GPFSEL1 + .modify(GPFSEL1::FSEL15::AltFunc0 + GPFSEL1::FSEL14::AltFunc0); + + // Disable pull-up/down on pins 14 and 15. + #[cfg(feature = "bsp_rpi3")] + self.disable_pud_14_15_bcm2837(); + + #[cfg(feature = "bsp_rpi4")] + self.disable_pud_14_15_bcm2711(); + } +} + +impl GPIO { + /// Create an instance. + /// + /// # Safety + /// + /// - The user must ensure to provide correct MMIO descriptors. + pub const unsafe fn new(mmio_descriptor: memory::mmu::MMIODescriptor) -> Self { + Self { + mmio_descriptor, + virt_mmio_start_addr: AtomicUsize::new(0), + inner: IRQSafeNullLock::new(GPIOInner::new(mmio_descriptor.start_addr().as_usize())), + } + } + + /// Concurrency safe version of `GPIOInner.map_pl011_uart()` + pub fn map_pl011_uart(&self) { + self.inner.lock(|inner| inner.map_pl011_uart()) + } +} + +//------------------------------------------------------------------------------ +// OS Interface Code +//------------------------------------------------------------------------------ +use synchronization::interface::Mutex; + +impl driver::interface::DeviceDriver for GPIO { + fn compatible(&self) -> &'static str { + "BCM GPIO" + } + + unsafe fn init(&self) -> Result<(), &'static str> { + let virt_addr = memory::mmu::kernel_map_mmio(self.compatible(), &self.mmio_descriptor)?; + + self.inner + .lock(|inner| inner.init(Some(virt_addr.as_usize())))?; + + self.virt_mmio_start_addr + .store(virt_addr.as_usize(), Ordering::Relaxed); + + Ok(()) + } + + fn virt_mmio_start_addr(&self) -> Option { + let addr = self.virt_mmio_start_addr.load(Ordering::Relaxed); + + if addr == 0 { + return None; + } + + Some(addr) + } +} diff --git a/17_kernel_symbols/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs b/17_kernel_symbols/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs new file mode 100644 index 00000000..99961fac --- /dev/null +++ b/17_kernel_symbols/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs @@ -0,0 +1,138 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2020-2022 Andre Richter + +//! Interrupt Controller Driver. + +mod peripheral_ic; + +use crate::{driver, exception, memory}; + +//-------------------------------------------------------------------------------------------------- +// Private Definitions +//-------------------------------------------------------------------------------------------------- + +/// Wrapper struct for a bitmask indicating pending IRQ numbers. +struct PendingIRQs { + bitmask: u64, +} + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +pub type LocalIRQ = + exception::asynchronous::IRQNumber<{ InterruptController::MAX_LOCAL_IRQ_NUMBER }>; +pub type PeripheralIRQ = + exception::asynchronous::IRQNumber<{ InterruptController::MAX_PERIPHERAL_IRQ_NUMBER }>; + +/// Used for the associated type of trait [`exception::asynchronous::interface::IRQManager`]. +#[derive(Copy, Clone)] +pub enum IRQNumber { + Local(LocalIRQ), + Peripheral(PeripheralIRQ), +} + +/// Representation of the Interrupt Controller. +pub struct InterruptController { + periph: peripheral_ic::PeripheralIC, +} + +//-------------------------------------------------------------------------------------------------- +// Private Code +//-------------------------------------------------------------------------------------------------- + +impl PendingIRQs { + pub fn new(bitmask: u64) -> Self { + Self { bitmask } + } +} + +impl Iterator for PendingIRQs { + type Item = usize; + + fn next(&mut self) -> Option { + use core::intrinsics::cttz; + + let next = cttz(self.bitmask); + if next == 64 { + return None; + } + + self.bitmask &= !(1 << next); + + Some(next as usize) + } +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +impl InterruptController { + const MAX_LOCAL_IRQ_NUMBER: usize = 11; + const MAX_PERIPHERAL_IRQ_NUMBER: usize = 63; + const NUM_PERIPHERAL_IRQS: usize = Self::MAX_PERIPHERAL_IRQ_NUMBER + 1; + + /// Create an instance. + /// + /// # Safety + /// + /// - The user must ensure to provide correct MMIO descriptors. + pub const unsafe fn new( + _local_mmio_descriptor: memory::mmu::MMIODescriptor, + periph_mmio_descriptor: memory::mmu::MMIODescriptor, + ) -> Self { + Self { + periph: peripheral_ic::PeripheralIC::new(periph_mmio_descriptor), + } + } +} + +//------------------------------------------------------------------------------ +// OS Interface Code +//------------------------------------------------------------------------------ + +impl driver::interface::DeviceDriver for InterruptController { + fn compatible(&self) -> &'static str { + "BCM Interrupt Controller" + } + + unsafe fn init(&self) -> Result<(), &'static str> { + self.periph.init() + } +} + +impl exception::asynchronous::interface::IRQManager for InterruptController { + type IRQNumberType = IRQNumber; + + fn register_handler( + &self, + irq: Self::IRQNumberType, + descriptor: exception::asynchronous::IRQDescriptor, + ) -> Result<(), &'static str> { + match irq { + IRQNumber::Local(_) => unimplemented!("Local IRQ controller not implemented."), + IRQNumber::Peripheral(pirq) => self.periph.register_handler(pirq, descriptor), + } + } + + fn enable(&self, irq: Self::IRQNumberType) { + match irq { + IRQNumber::Local(_) => unimplemented!("Local IRQ controller not implemented."), + IRQNumber::Peripheral(pirq) => self.periph.enable(pirq), + } + } + + fn handle_pending_irqs<'irq_context>( + &'irq_context self, + ic: &exception::asynchronous::IRQContext<'irq_context>, + ) { + // It can only be a peripheral IRQ pending because enable() does not support local IRQs yet. + self.periph.handle_pending_irqs(ic) + } + + fn print_handler(&self) { + self.periph.print_handler(); + } +} diff --git a/17_kernel_symbols/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs b/17_kernel_symbols/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs new file mode 100644 index 00000000..f09da862 --- /dev/null +++ b/17_kernel_symbols/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs @@ -0,0 +1,192 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2020-2022 Andre Richter + +//! Peripheral Interrupt Controller Driver. + +use super::{InterruptController, PendingIRQs, PeripheralIRQ}; +use crate::{ + bsp::device_driver::common::MMIODerefWrapper, + driver, exception, memory, synchronization, + synchronization::{IRQSafeNullLock, InitStateLock}, +}; +use tock_registers::{ + interfaces::{Readable, Writeable}, + register_structs, + registers::{ReadOnly, WriteOnly}, +}; + +//-------------------------------------------------------------------------------------------------- +// Private Definitions +//-------------------------------------------------------------------------------------------------- + +register_structs! { + #[allow(non_snake_case)] + WORegisterBlock { + (0x00 => _reserved1), + (0x10 => ENABLE_1: WriteOnly), + (0x14 => ENABLE_2: WriteOnly), + (0x24 => @END), + } +} + +register_structs! { + #[allow(non_snake_case)] + RORegisterBlock { + (0x00 => _reserved1), + (0x04 => PENDING_1: ReadOnly), + (0x08 => PENDING_2: ReadOnly), + (0x0c => @END), + } +} + +/// Abstraction for the WriteOnly parts of the associated MMIO registers. +type WriteOnlyRegisters = MMIODerefWrapper; + +/// Abstraction for the ReadOnly parts of the associated MMIO registers. +type ReadOnlyRegisters = MMIODerefWrapper; + +type HandlerTable = + [Option; InterruptController::NUM_PERIPHERAL_IRQS]; + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +/// Representation of the peripheral interrupt controller. +pub struct PeripheralIC { + mmio_descriptor: memory::mmu::MMIODescriptor, + + /// Access to write registers is guarded with a lock. + wo_registers: IRQSafeNullLock, + + /// Register read access is unguarded. + ro_registers: InitStateLock, + + /// Stores registered IRQ handlers. Writable only during kernel init. RO afterwards. + handler_table: InitStateLock, +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +impl PeripheralIC { + /// Create an instance. + /// + /// # Safety + /// + /// - The user must ensure to provide correct MMIO descriptors. + pub const unsafe fn new(mmio_descriptor: memory::mmu::MMIODescriptor) -> Self { + let addr = mmio_descriptor.start_addr().as_usize(); + + Self { + mmio_descriptor, + wo_registers: IRQSafeNullLock::new(WriteOnlyRegisters::new(addr)), + ro_registers: InitStateLock::new(ReadOnlyRegisters::new(addr)), + handler_table: InitStateLock::new([None; InterruptController::NUM_PERIPHERAL_IRQS]), + } + } + + /// Query the list of pending IRQs. + fn pending_irqs(&self) -> PendingIRQs { + self.ro_registers.read(|regs| { + let pending_mask: u64 = + (u64::from(regs.PENDING_2.get()) << 32) | u64::from(regs.PENDING_1.get()); + + PendingIRQs::new(pending_mask) + }) + } +} + +//------------------------------------------------------------------------------ +// OS Interface Code +//------------------------------------------------------------------------------ +use synchronization::interface::{Mutex, ReadWriteEx}; + +impl driver::interface::DeviceDriver for PeripheralIC { + fn compatible(&self) -> &'static str { + "BCM Peripheral Interrupt Controller" + } + + unsafe fn init(&self) -> Result<(), &'static str> { + let virt_addr = + memory::mmu::kernel_map_mmio(self.compatible(), &self.mmio_descriptor)?.as_usize(); + + self.wo_registers + .lock(|regs| *regs = WriteOnlyRegisters::new(virt_addr)); + self.ro_registers + .write(|regs| *regs = ReadOnlyRegisters::new(virt_addr)); + + Ok(()) + } +} + +impl exception::asynchronous::interface::IRQManager for PeripheralIC { + type IRQNumberType = PeripheralIRQ; + + fn register_handler( + &self, + irq: Self::IRQNumberType, + descriptor: exception::asynchronous::IRQDescriptor, + ) -> Result<(), &'static str> { + self.handler_table.write(|table| { + let irq_number = irq.get(); + + if table[irq_number].is_some() { + return Err("IRQ handler already registered"); + } + + table[irq_number] = Some(descriptor); + + Ok(()) + }) + } + + fn enable(&self, irq: Self::IRQNumberType) { + self.wo_registers.lock(|regs| { + let enable_reg = if irq.get() <= 31 { + ®s.ENABLE_1 + } else { + ®s.ENABLE_2 + }; + + let enable_bit: u32 = 1 << (irq.get() % 32); + + // Writing a 1 to a bit will set the corresponding IRQ enable bit. All other IRQ enable + // bits are unaffected. So we don't need read and OR'ing here. + enable_reg.set(enable_bit); + }); + } + + fn handle_pending_irqs<'irq_context>( + &'irq_context self, + _ic: &exception::asynchronous::IRQContext<'irq_context>, + ) { + self.handler_table.read(|table| { + for irq_number in self.pending_irqs() { + match table[irq_number] { + None => panic!("No handler registered for IRQ {}", irq_number), + Some(descriptor) => { + // Call the IRQ handler. Panics on failure. + descriptor.handler.handle().expect("Error handling IRQ"); + } + } + } + }) + } + + fn print_handler(&self) { + use crate::info; + + info!(" Peripheral handler:"); + + self.handler_table.read(|table| { + for (i, opt) in table.iter().enumerate() { + if let Some(handler) = opt { + info!(" {: >3}. {}", i, handler.name); + } + } + }); + } +} diff --git a/17_kernel_symbols/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs b/17_kernel_symbols/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs new file mode 100644 index 00000000..23c09a7f --- /dev/null +++ b/17_kernel_symbols/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs @@ -0,0 +1,536 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2018-2022 Andre Richter + +//! PL011 UART driver. +//! +//! # Resources +//! +//! - +//! - + +use crate::{ + bsp, bsp::device_driver::common::MMIODerefWrapper, console, cpu, driver, exception, memory, + synchronization, synchronization::IRQSafeNullLock, +}; +use core::{ + fmt, + sync::atomic::{AtomicUsize, Ordering}, +}; +use tock_registers::{ + interfaces::{Readable, Writeable}, + register_bitfields, register_structs, + registers::{ReadOnly, ReadWrite, WriteOnly}, +}; + +//-------------------------------------------------------------------------------------------------- +// Private Definitions +//-------------------------------------------------------------------------------------------------- + +// PL011 UART registers. +// +// Descriptions taken from "PrimeCell UART (PL011) Technical Reference Manual" r1p5. +register_bitfields! { + u32, + + /// Flag Register. + FR [ + /// Transmit FIFO empty. The meaning of this bit depends on the state of the FEN bit in the + /// Line Control Register, LCR_H. + /// + /// - If the FIFO is disabled, this bit is set when the transmit holding register is empty. + /// - If the FIFO is enabled, the TXFE bit is set when the transmit FIFO is empty. + /// - This bit does not indicate if there is data in the transmit shift register. + TXFE OFFSET(7) NUMBITS(1) [], + + /// Transmit FIFO full. The meaning of this bit depends on the state of the FEN bit in the + /// LCR_H Register. + /// + /// - If the FIFO is disabled, this bit is set when the transmit holding register is full. + /// - If the FIFO is enabled, the TXFF bit is set when the transmit FIFO is full. + TXFF OFFSET(5) NUMBITS(1) [], + + /// Receive FIFO empty. The meaning of this bit depends on the state of the FEN bit in the + /// LCR_H Register. + /// + /// - If the FIFO is disabled, this bit is set when the receive holding register is empty. + /// - If the FIFO is enabled, the RXFE bit is set when the receive FIFO is empty. + RXFE OFFSET(4) NUMBITS(1) [], + + /// UART busy. If this bit is set to 1, the UART is busy transmitting data. This bit remains + /// set until the complete byte, including all the stop bits, has been sent from the shift + /// register. + /// + /// This bit is set as soon as the transmit FIFO becomes non-empty, regardless of whether + /// the UART is enabled or not. + BUSY OFFSET(3) NUMBITS(1) [] + ], + + /// Integer Baud Rate Divisor. + IBRD [ + /// The integer baud rate divisor. + BAUD_DIVINT OFFSET(0) NUMBITS(16) [] + ], + + /// Fractional Baud Rate Divisor. + FBRD [ + /// The fractional baud rate divisor. + BAUD_DIVFRAC OFFSET(0) NUMBITS(6) [] + ], + + /// Line Control Register. + LCR_H [ + /// Word length. These bits indicate the number of data bits transmitted or received in a + /// frame. + #[allow(clippy::enum_variant_names)] + WLEN OFFSET(5) NUMBITS(2) [ + FiveBit = 0b00, + SixBit = 0b01, + SevenBit = 0b10, + EightBit = 0b11 + ], + + /// Enable FIFOs: + /// + /// 0 = FIFOs are disabled (character mode) that is, the FIFOs become 1-byte-deep holding + /// registers. + /// + /// 1 = Transmit and receive FIFO buffers are enabled (FIFO mode). + FEN OFFSET(4) NUMBITS(1) [ + FifosDisabled = 0, + FifosEnabled = 1 + ] + ], + + /// Control Register. + CR [ + /// Receive enable. If this bit is set to 1, the receive section of the UART is enabled. + /// Data reception occurs for either UART signals or SIR signals depending on the setting of + /// the SIREN bit. When the UART is disabled in the middle of reception, it completes the + /// current character before stopping. + RXE OFFSET(9) NUMBITS(1) [ + Disabled = 0, + Enabled = 1 + ], + + /// Transmit enable. If this bit is set to 1, the transmit section of the UART is enabled. + /// Data transmission occurs for either UART signals, or SIR signals depending on the + /// setting of the SIREN bit. When the UART is disabled in the middle of transmission, it + /// completes the current character before stopping. + TXE OFFSET(8) NUMBITS(1) [ + Disabled = 0, + Enabled = 1 + ], + + /// UART enable: + /// + /// 0 = UART is disabled. If the UART is disabled in the middle of transmission or + /// reception, it completes the current character before stopping. + /// + /// 1 = The UART is enabled. Data transmission and reception occurs for either UART signals + /// or SIR signals depending on the setting of the SIREN bit + UARTEN OFFSET(0) NUMBITS(1) [ + /// If the UART is disabled in the middle of transmission or reception, it completes the + /// current character before stopping. + Disabled = 0, + Enabled = 1 + ] + ], + + /// Interrupt FIFO Level Select Register. + IFLS [ + /// Receive interrupt FIFO level select. The trigger points for the receive interrupt are as + /// follows. + RXIFLSEL OFFSET(3) NUMBITS(5) [ + OneEigth = 0b000, + OneQuarter = 0b001, + OneHalf = 0b010, + ThreeQuarters = 0b011, + SevenEights = 0b100 + ] + ], + + /// Interrupt Mask Set/Clear Register. + IMSC [ + /// Receive timeout interrupt mask. A read returns the current mask for the UARTRTINTR + /// interrupt. + /// + /// - On a write of 1, the mask of the UARTRTINTR interrupt is set. + /// - A write of 0 clears the mask. + RTIM OFFSET(6) NUMBITS(1) [ + Disabled = 0, + Enabled = 1 + ], + + /// Receive interrupt mask. A read returns the current mask for the UARTRXINTR interrupt. + /// + /// - On a write of 1, the mask of the UARTRXINTR interrupt is set. + /// - A write of 0 clears the mask. + RXIM OFFSET(4) NUMBITS(1) [ + Disabled = 0, + Enabled = 1 + ] + ], + + /// Masked Interrupt Status Register. + MIS [ + /// Receive timeout masked interrupt status. Returns the masked interrupt state of the + /// UARTRTINTR interrupt. + RTMIS OFFSET(6) NUMBITS(1) [], + + /// Receive masked interrupt status. Returns the masked interrupt state of the UARTRXINTR + /// interrupt. + RXMIS OFFSET(4) NUMBITS(1) [] + ], + + /// Interrupt Clear Register. + ICR [ + /// Meta field for all pending interrupts. + ALL OFFSET(0) NUMBITS(11) [] + ] +} + +register_structs! { + #[allow(non_snake_case)] + pub RegisterBlock { + (0x00 => DR: ReadWrite), + (0x04 => _reserved1), + (0x18 => FR: ReadOnly), + (0x1c => _reserved2), + (0x24 => IBRD: WriteOnly), + (0x28 => FBRD: WriteOnly), + (0x2c => LCR_H: WriteOnly), + (0x30 => CR: WriteOnly), + (0x34 => IFLS: ReadWrite), + (0x38 => IMSC: ReadWrite), + (0x3C => _reserved3), + (0x40 => MIS: ReadOnly), + (0x44 => ICR: WriteOnly), + (0x48 => @END), + } +} + +/// Abstraction for the associated MMIO registers. +type Registers = MMIODerefWrapper; + +#[derive(PartialEq)] +enum BlockingMode { + Blocking, + NonBlocking, +} + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +pub struct PL011UartInner { + registers: Registers, + chars_written: usize, + chars_read: usize, +} + +// Export the inner struct so that BSPs can use it for the panic handler. +pub use PL011UartInner as PanicUart; + +/// Representation of the UART. +pub struct PL011Uart { + mmio_descriptor: memory::mmu::MMIODescriptor, + virt_mmio_start_addr: AtomicUsize, + inner: IRQSafeNullLock, + irq_number: bsp::device_driver::IRQNumber, +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +impl PL011UartInner { + /// Create an instance. + /// + /// # Safety + /// + /// - The user must ensure to provide a correct MMIO start address. + pub const unsafe fn new(mmio_start_addr: usize) -> Self { + Self { + registers: Registers::new(mmio_start_addr), + chars_written: 0, + chars_read: 0, + } + } + + /// Set up baud rate and characteristics. + /// + /// This results in 8N1 and 921_600 baud. + /// + /// The calculation for the BRD is (we set the clock to 48 MHz in config.txt): + /// `(48_000_000 / 16) / 921_600 = 3.2552083`. + /// + /// This means the integer part is `3` and goes into the `IBRD`. + /// The fractional part is `0.2552083`. + /// + /// `FBRD` calculation according to the PL011 Technical Reference Manual: + /// `INTEGER((0.2552083 * 64) + 0.5) = 16`. + /// + /// Therefore, the generated baud rate divider is: `3 + 16/64 = 3.25`. Which results in a + /// genrated baud rate of `48_000_000 / (16 * 3.25) = 923_077`. + /// + /// Error = `((923_077 - 921_600) / 921_600) * 100 = 0.16%`. + /// + /// # Safety + /// + /// - The user must ensure to provide a correct MMIO start address. + pub unsafe fn init(&mut self, new_mmio_start_addr: Option) -> Result<(), &'static str> { + if let Some(addr) = new_mmio_start_addr { + self.registers = Registers::new(addr); + } + + // Execution can arrive here while there are still characters queued in the TX FIFO and + // actively being sent out by the UART hardware. If the UART is turned off in this case, + // those queued characters would be lost. + // + // For example, this can happen during runtime on a call to panic!(), because panic!() + // initializes its own UART instance and calls init(). + // + // Hence, flush first to ensure all pending characters are transmitted. + self.flush(); + + // Turn the UART off temporarily. + self.registers.CR.set(0); + + // Clear all pending interrupts. + self.registers.ICR.write(ICR::ALL::CLEAR); + + // From the PL011 Technical Reference Manual: + // + // The LCR_H, IBRD, and FBRD registers form the single 30-bit wide LCR Register that is + // updated on a single write strobe generated by a LCR_H write. So, to internally update the + // contents of IBRD or FBRD, a LCR_H write must always be performed at the end. + // + // Set the baud rate, 8N1 and FIFO enabled. + self.registers.IBRD.write(IBRD::BAUD_DIVINT.val(3)); + self.registers.FBRD.write(FBRD::BAUD_DIVFRAC.val(16)); + self.registers + .LCR_H + .write(LCR_H::WLEN::EightBit + LCR_H::FEN::FifosEnabled); + + // Set RX FIFO fill level at 1/8. + self.registers.IFLS.write(IFLS::RXIFLSEL::OneEigth); + + // Enable RX IRQ + RX timeout IRQ. + self.registers + .IMSC + .write(IMSC::RXIM::Enabled + IMSC::RTIM::Enabled); + + // Turn the UART on. + self.registers + .CR + .write(CR::UARTEN::Enabled + CR::TXE::Enabled + CR::RXE::Enabled); + + Ok(()) + } + + /// Send a character. + fn write_char(&mut self, c: char) { + // Spin while TX FIFO full is set, waiting for an empty slot. + while self.registers.FR.matches_all(FR::TXFF::SET) { + cpu::nop(); + } + + // Write the character to the buffer. + self.registers.DR.set(c as u32); + + self.chars_written += 1; + } + + /// Block execution until the last buffered character has been physically put on the TX wire. + fn flush(&self) { + // Spin until the busy bit is cleared. + while self.registers.FR.matches_all(FR::BUSY::SET) { + cpu::nop(); + } + } + + /// Retrieve a character. + fn read_char_converting(&mut self, blocking_mode: BlockingMode) -> Option { + // If RX FIFO is empty, + if self.registers.FR.matches_all(FR::RXFE::SET) { + // immediately return in non-blocking mode. + if blocking_mode == BlockingMode::NonBlocking { + return None; + } + + // Otherwise, wait until a char was received. + while self.registers.FR.matches_all(FR::RXFE::SET) { + cpu::nop(); + } + } + + // Read one character. + let mut ret = self.registers.DR.get() as u8 as char; + + // Convert carrige return to newline. + if ret == '\r' { + ret = '\n' + } + + // Update statistics. + self.chars_read += 1; + + Some(ret) + } +} + +/// Implementing `core::fmt::Write` enables usage of the `format_args!` macros, which in turn are +/// used to implement the `kernel`'s `print!` and `println!` macros. By implementing `write_str()`, +/// we get `write_fmt()` automatically. +/// +/// The function takes an `&mut self`, so it must be implemented for the inner struct. +/// +/// See [`src/print.rs`]. +/// +/// [`src/print.rs`]: ../../print/index.html +impl fmt::Write for PL011UartInner { + fn write_str(&mut self, s: &str) -> fmt::Result { + for c in s.chars() { + self.write_char(c); + } + + Ok(()) + } +} + +impl PL011Uart { + /// Create an instance. + /// + /// # Safety + /// + /// - The user must ensure to provide correct MMIO descriptors. + /// - The user must ensure to provide correct IRQ numbers. + pub const unsafe fn new( + mmio_descriptor: memory::mmu::MMIODescriptor, + irq_number: bsp::device_driver::IRQNumber, + ) -> Self { + Self { + mmio_descriptor, + virt_mmio_start_addr: AtomicUsize::new(0), + inner: IRQSafeNullLock::new(PL011UartInner::new( + mmio_descriptor.start_addr().as_usize(), + )), + irq_number, + } + } +} + +//------------------------------------------------------------------------------ +// OS Interface Code +//------------------------------------------------------------------------------ +use synchronization::interface::Mutex; + +impl driver::interface::DeviceDriver for PL011Uart { + fn compatible(&self) -> &'static str { + "BCM PL011 UART" + } + + unsafe fn init(&self) -> Result<(), &'static str> { + let virt_addr = memory::mmu::kernel_map_mmio(self.compatible(), &self.mmio_descriptor)?; + + self.inner + .lock(|inner| inner.init(Some(virt_addr.as_usize())))?; + + self.virt_mmio_start_addr + .store(virt_addr.as_usize(), Ordering::Relaxed); + + Ok(()) + } + + fn register_and_enable_irq_handler(&'static self) -> Result<(), &'static str> { + use bsp::exception::asynchronous::irq_manager; + use exception::asynchronous::{interface::IRQManager, IRQDescriptor}; + + let descriptor = IRQDescriptor { + name: "BCM PL011 UART", + handler: self, + }; + + irq_manager().register_handler(self.irq_number, descriptor)?; + irq_manager().enable(self.irq_number); + + Ok(()) + } + + fn virt_mmio_start_addr(&self) -> Option { + let addr = self.virt_mmio_start_addr.load(Ordering::Relaxed); + + if addr == 0 { + return None; + } + + Some(addr) + } +} + +impl console::interface::Write for PL011Uart { + /// Passthrough of `args` to the `core::fmt::Write` implementation, but guarded by a Mutex to + /// serialize access. + fn write_char(&self, c: char) { + self.inner.lock(|inner| inner.write_char(c)); + } + + fn write_fmt(&self, args: core::fmt::Arguments) -> fmt::Result { + // Fully qualified syntax for the call to `core::fmt::Write::write:fmt()` to increase + // readability. + self.inner.lock(|inner| fmt::Write::write_fmt(inner, args)) + } + + fn flush(&self) { + // Spin until TX FIFO empty is set. + self.inner.lock(|inner| inner.flush()); + } +} + +impl console::interface::Read for PL011Uart { + fn read_char(&self) -> char { + self.inner + .lock(|inner| inner.read_char_converting(BlockingMode::Blocking).unwrap()) + } + + fn clear_rx(&self) { + // Read from the RX FIFO until it is indicating empty. + while self + .inner + .lock(|inner| inner.read_char_converting(BlockingMode::NonBlocking)) + .is_some() + {} + } +} + +impl console::interface::Statistics for PL011Uart { + fn chars_written(&self) -> usize { + self.inner.lock(|inner| inner.chars_written) + } + + fn chars_read(&self) -> usize { + self.inner.lock(|inner| inner.chars_read) + } +} + +impl exception::asynchronous::interface::IRQHandler for PL011Uart { + fn handle(&self) -> Result<(), &'static str> { + self.inner.lock(|inner| { + let pending = inner.registers.MIS.extract(); + + // Clear all pending IRQs. + inner.registers.ICR.write(ICR::ALL::CLEAR); + + // Check for any kind of RX interrupt. + if pending.matches_any(MIS::RXMIS::SET + MIS::RTMIS::SET) { + // Echo any received characters. + while let Some(c) = inner.read_char_converting(BlockingMode::NonBlocking) { + inner.write_char(c) + } + } + }); + + Ok(()) + } +} diff --git a/17_kernel_symbols/kernel/src/bsp/device_driver/common.rs b/17_kernel_symbols/kernel/src/bsp/device_driver/common.rs new file mode 100644 index 00000000..fd9e988e --- /dev/null +++ b/17_kernel_symbols/kernel/src/bsp/device_driver/common.rs @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2020-2022 Andre Richter + +//! Common device driver code. + +use core::{marker::PhantomData, ops}; + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +pub struct MMIODerefWrapper { + start_addr: usize, + phantom: PhantomData T>, +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +impl MMIODerefWrapper { + /// Create an instance. + pub const unsafe fn new(start_addr: usize) -> Self { + Self { + start_addr, + phantom: PhantomData, + } + } +} + +impl ops::Deref for MMIODerefWrapper { + type Target = T; + + fn deref(&self) -> &Self::Target { + unsafe { &*(self.start_addr as *const _) } + } +} diff --git a/17_kernel_symbols/kernel/src/bsp/raspberrypi.rs b/17_kernel_symbols/kernel/src/bsp/raspberrypi.rs new file mode 100644 index 00000000..fb9edf88 --- /dev/null +++ b/17_kernel_symbols/kernel/src/bsp/raspberrypi.rs @@ -0,0 +1,62 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2018-2022 Andre Richter + +//! Top-level BSP file for the Raspberry Pi 3 and 4. + +pub mod console; +pub mod cpu; +pub mod driver; +pub mod exception; +pub mod memory; + +use super::device_driver; +use crate::memory::mmu::MMIODescriptor; +use memory::map::mmio; + +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +static GPIO: device_driver::GPIO = + unsafe { device_driver::GPIO::new(MMIODescriptor::new(mmio::GPIO_START, mmio::GPIO_SIZE)) }; + +static PL011_UART: device_driver::PL011Uart = unsafe { + device_driver::PL011Uart::new( + MMIODescriptor::new(mmio::PL011_UART_START, mmio::PL011_UART_SIZE), + exception::asynchronous::irq_map::PL011_UART, + ) +}; + +#[cfg(feature = "bsp_rpi3")] +static INTERRUPT_CONTROLLER: device_driver::InterruptController = unsafe { + device_driver::InterruptController::new( + MMIODescriptor::new(mmio::LOCAL_IC_START, mmio::LOCAL_IC_SIZE), + MMIODescriptor::new(mmio::PERIPHERAL_IC_START, mmio::PERIPHERAL_IC_SIZE), + ) +}; + +#[cfg(feature = "bsp_rpi4")] +static INTERRUPT_CONTROLLER: device_driver::GICv2 = unsafe { + device_driver::GICv2::new( + MMIODescriptor::new(mmio::GICD_START, mmio::GICD_SIZE), + MMIODescriptor::new(mmio::GICC_START, mmio::GICC_SIZE), + ) +}; + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +/// Board identification. +pub fn board_name() -> &'static str { + #[cfg(feature = "bsp_rpi3")] + { + "Raspberry Pi 3" + } + + #[cfg(feature = "bsp_rpi4")] + { + "Raspberry Pi 4" + } +} diff --git a/17_kernel_symbols/kernel/src/bsp/raspberrypi/console.rs b/17_kernel_symbols/kernel/src/bsp/raspberrypi/console.rs new file mode 100644 index 00000000..a0d2e687 --- /dev/null +++ b/17_kernel_symbols/kernel/src/bsp/raspberrypi/console.rs @@ -0,0 +1,98 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2018-2022 Andre Richter + +//! BSP console facilities. + +use crate::{bsp::device_driver, console, cpu, driver}; +use core::fmt; + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +/// In case of a panic, the panic handler uses this function to take a last shot at printing +/// something before the system is halted. +/// +/// We try to init panic-versions of the GPIO and the UART. The panic versions are not protected +/// with synchronization primitives, which increases chances that we get to print something, even +/// when the kernel's default GPIO or UART instances happen to be locked at the time of the panic. +/// +/// # Safety +/// +/// - Use only for printing during a panic. +#[cfg(not(feature = "test_build"))] +pub unsafe fn panic_console_out() -> impl fmt::Write { + use driver::interface::DeviceDriver; + + // If remapping of the driver's MMIO hasn't already happened, we won't be able to print. Just + // park the CPU core in this case. + let gpio_mmio_start_addr = match super::GPIO.virt_mmio_start_addr() { + None => cpu::wait_forever(), + Some(x) => x, + }; + + let uart_mmio_start_addr = match super::PL011_UART.virt_mmio_start_addr() { + None => cpu::wait_forever(), + Some(x) => x, + }; + + let mut panic_gpio = device_driver::PanicGPIO::new(gpio_mmio_start_addr); + let mut panic_uart = device_driver::PanicUart::new(uart_mmio_start_addr); + + panic_gpio + .init(None) + .unwrap_or_else(|_| cpu::wait_forever()); + panic_gpio.map_pl011_uart(); + panic_uart + .init(None) + .unwrap_or_else(|_| cpu::wait_forever()); + + panic_uart +} + +/// Reduced version for test builds. +/// +/// # Safety +/// +/// - Use only for printing during a panic. +#[cfg(feature = "test_build")] +pub unsafe fn panic_console_out() -> impl fmt::Write { + use driver::interface::DeviceDriver; + + let uart_mmio_start_addr = match super::PL011_UART.virt_mmio_start_addr() { + None => cpu::wait_forever(), + Some(x) => x, + }; + let mut panic_uart = device_driver::PanicUart::new(uart_mmio_start_addr); + + panic_uart + .init(None) + .unwrap_or_else(|_| cpu::qemu_exit_failure()); + + panic_uart +} + +/// Return a reference to the console. +pub fn console() -> &'static impl console::interface::All { + &super::PL011_UART +} + +//-------------------------------------------------------------------------------------------------- +// Testing +//-------------------------------------------------------------------------------------------------- + +/// Minimal code needed to bring up the console in QEMU (for testing only). This is often less steps +/// than on real hardware due to QEMU's abstractions. +#[cfg(feature = "test_build")] +pub fn qemu_bring_up_console() { + use driver::interface::DeviceDriver; + + // Calling the UART's init ensures that the BSP's instance of the UART does remap the MMIO + // addresses. + unsafe { + super::PL011_UART + .init() + .unwrap_or_else(|_| cpu::qemu_exit_failure()); + } +} diff --git a/17_kernel_symbols/kernel/src/bsp/raspberrypi/cpu.rs b/17_kernel_symbols/kernel/src/bsp/raspberrypi/cpu.rs new file mode 100644 index 00000000..85fb89e4 --- /dev/null +++ b/17_kernel_symbols/kernel/src/bsp/raspberrypi/cpu.rs @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2018-2022 Andre Richter + +//! BSP Processor code. + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +/// Used by `arch` code to find the early boot core. +#[no_mangle] +#[link_section = ".text._start_arguments"] +pub static BOOT_CORE_ID: u64 = 0; diff --git a/17_kernel_symbols/kernel/src/bsp/raspberrypi/driver.rs b/17_kernel_symbols/kernel/src/bsp/raspberrypi/driver.rs new file mode 100644 index 00000000..53168752 --- /dev/null +++ b/17_kernel_symbols/kernel/src/bsp/raspberrypi/driver.rs @@ -0,0 +1,61 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2018-2022 Andre Richter + +//! BSP driver support. + +use crate::driver; + +//-------------------------------------------------------------------------------------------------- +// Private Definitions +//-------------------------------------------------------------------------------------------------- + +/// Device Driver Manager type. +struct BSPDriverManager { + device_drivers: [&'static (dyn DeviceDriver + Sync); 3], +} + +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +static BSP_DRIVER_MANAGER: BSPDriverManager = BSPDriverManager { + device_drivers: [ + &super::GPIO, + &super::PL011_UART, + &super::INTERRUPT_CONTROLLER, + ], +}; + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +/// Return a reference to the driver manager. +pub fn driver_manager() -> &'static impl driver::interface::DriverManager { + &BSP_DRIVER_MANAGER +} + +//------------------------------------------------------------------------------ +// OS Interface Code +//------------------------------------------------------------------------------ +use driver::interface::DeviceDriver; + +impl driver::interface::DriverManager for BSPDriverManager { + fn all_device_drivers(&self) -> &[&'static (dyn DeviceDriver + Sync)] { + &self.device_drivers[..] + } + + fn early_print_device_drivers(&self) -> &[&'static (dyn DeviceDriver + Sync)] { + &self.device_drivers[0..=1] + } + + fn non_early_print_device_drivers(&self) -> &[&'static (dyn DeviceDriver + Sync)] { + &self.device_drivers[2..] + } + + fn post_early_print_device_driver_init(&self) { + // Configure PL011Uart's output pins. + super::GPIO.map_pl011_uart(); + } +} diff --git a/17_kernel_symbols/kernel/src/bsp/raspberrypi/exception.rs b/17_kernel_symbols/kernel/src/bsp/raspberrypi/exception.rs new file mode 100644 index 00000000..aa6c5a63 --- /dev/null +++ b/17_kernel_symbols/kernel/src/bsp/raspberrypi/exception.rs @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2020-2022 Andre Richter + +//! BSP synchronous and asynchronous exception handling. + +pub mod asynchronous; diff --git a/17_kernel_symbols/kernel/src/bsp/raspberrypi/exception/asynchronous.rs b/17_kernel_symbols/kernel/src/bsp/raspberrypi/exception/asynchronous.rs new file mode 100644 index 00000000..dc5ab421 --- /dev/null +++ b/17_kernel_symbols/kernel/src/bsp/raspberrypi/exception/asynchronous.rs @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2020-2022 Andre Richter + +//! BSP asynchronous exception handling. + +use crate::{bsp, exception}; + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +#[cfg(feature = "bsp_rpi3")] +pub(in crate::bsp) mod irq_map { + use super::bsp::device_driver::{IRQNumber, PeripheralIRQ}; + + pub const PL011_UART: IRQNumber = IRQNumber::Peripheral(PeripheralIRQ::new(57)); +} + +#[cfg(feature = "bsp_rpi4")] +pub(in crate::bsp) mod irq_map { + use super::bsp::device_driver::IRQNumber; + + pub const PL011_UART: IRQNumber = IRQNumber::new(153); +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +/// Return a reference to the IRQ manager. +pub fn irq_manager() -> &'static impl exception::asynchronous::interface::IRQManager< + IRQNumberType = bsp::device_driver::IRQNumber, +> { + &super::super::INTERRUPT_CONTROLLER +} diff --git a/17_kernel_symbols/kernel/src/bsp/raspberrypi/kernel.ld b/17_kernel_symbols/kernel/src/bsp/raspberrypi/kernel.ld new file mode 100644 index 00000000..6fcbf31c --- /dev/null +++ b/17_kernel_symbols/kernel/src/bsp/raspberrypi/kernel.ld @@ -0,0 +1,114 @@ +/* SPDX-License-Identifier: MIT OR Apache-2.0 + * + * Copyright (c) 2018-2022 Andre Richter + */ + +INCLUDE kernel_virt_addr_space_size.ld; + +PAGE_SIZE = 64K; +PAGE_MASK = PAGE_SIZE - 1; + +/* The kernel's virtual address range will be: + * + * [END_ADDRESS_INCLUSIVE, START_ADDRESS] + * [u64::MAX , (u64::MAX - __kernel_virt_addr_space_size) + 1] + */ +__kernel_virt_start_addr = ((0xffffffffffffffff - __kernel_virt_addr_space_size) + 1); + +__rpi_phys_dram_start_addr = 0; + +/* The physical address at which the the kernel binary will be loaded by the Raspberry's firmware */ +__rpi_phys_binary_load_addr = 0x80000; + + +ENTRY(__rpi_phys_binary_load_addr) + +/* Flags: + * 4 == R + * 5 == RX + * 6 == RW + * + * Segments are marked PT_LOAD below so that the ELF file provides virtual and physical addresses. + * It doesn't mean all of them need actually be loaded. + */ +PHDRS +{ + segment_code PT_LOAD FLAGS(5); + segment_data PT_LOAD FLAGS(6); + segment_boot_core_stack PT_LOAD FLAGS(6); +} + +SECTIONS +{ + . = __kernel_virt_start_addr; + + ASSERT((. & PAGE_MASK) == 0, "Start of address space is not page aligned") + + /*********************************************************************************************** + * Code + RO Data + Global Offset Table + ***********************************************************************************************/ + __code_start = .; + .text : AT(__rpi_phys_binary_load_addr) + { + KEEP(*(.text._start)) + *(.text._start_arguments) /* Constants (or statics in Rust speak) read by _start(). */ + *(.text._start_rust) /* The Rust entry point */ + *(.text*) /* Everything else */ + } :segment_code + + .rodata : ALIGN(8) { *(.rodata*) } :segment_code + .got : ALIGN(8) { *(.got) } :segment_code + .kernel_symbols : ALIGN(8) { + __kernel_symbols_start = .; + . += 32 * 1024; + } :segment_code + + . = ALIGN(PAGE_SIZE); + __code_end_exclusive = .; + + /*********************************************************************************************** + * Data + BSS + ***********************************************************************************************/ + __data_start = .; + .data : { *(.data*) } :segment_data + + /* Section is zeroed in pairs of u64. Align start and end to 16 bytes */ + .bss (NOLOAD) : ALIGN(16) + { + __bss_start = .; + *(.bss*); + . = ALIGN(16); + __bss_end_exclusive = .; + } :segment_data + + . = ALIGN(PAGE_SIZE); + __data_end_exclusive = .; + + /*********************************************************************************************** + * MMIO Remap Reserved + ***********************************************************************************************/ + __mmio_remap_start = .; + . += 8 * 1024 * 1024; + __mmio_remap_end_exclusive = .; + + ASSERT((. & PAGE_MASK) == 0, "MMIO remap reservation is not page aligned") + + /*********************************************************************************************** + * Guard Page + ***********************************************************************************************/ + . += PAGE_SIZE; + + /*********************************************************************************************** + * Boot Core Stack + ***********************************************************************************************/ + .boot_core_stack (NOLOAD) : AT(__rpi_phys_dram_start_addr) + { + __boot_core_stack_start = .; /* ^ */ + /* | stack */ + . += __rpi_phys_binary_load_addr; /* | growth */ + /* | direction */ + __boot_core_stack_end_exclusive = .; /* | */ + } :segment_boot_core_stack + + ASSERT((. & PAGE_MASK) == 0, "End of boot core stack is not page aligned") +} diff --git a/17_kernel_symbols/kernel/src/bsp/raspberrypi/kernel_virt_addr_space_size.ld b/17_kernel_symbols/kernel/src/bsp/raspberrypi/kernel_virt_addr_space_size.ld new file mode 100644 index 00000000..c5d58c30 --- /dev/null +++ b/17_kernel_symbols/kernel/src/bsp/raspberrypi/kernel_virt_addr_space_size.ld @@ -0,0 +1 @@ +__kernel_virt_addr_space_size = 1024 * 1024 * 1024 diff --git a/17_kernel_symbols/kernel/src/bsp/raspberrypi/memory.rs b/17_kernel_symbols/kernel/src/bsp/raspberrypi/memory.rs new file mode 100644 index 00000000..01aa9441 --- /dev/null +++ b/17_kernel_symbols/kernel/src/bsp/raspberrypi/memory.rs @@ -0,0 +1,227 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2018-2022 Andre Richter + +//! BSP Memory Management. +//! +//! The physical memory layout. +//! +//! The Raspberry's firmware copies the kernel binary to 0x8_0000. The preceding region will be used +//! as the boot core's stack. +//! +//! +---------------------------------------+ +//! | | boot_core_stack_start @ 0x0 +//! | | ^ +//! | Boot-core Stack | | stack +//! | | | growth +//! | | | direction +//! +---------------------------------------+ +//! | | code_start @ 0x8_0000 == boot_core_stack_end_exclusive +//! | .text | +//! | .rodata | +//! | .got | +//! | .kernel_symbols | +//! | | +//! +---------------------------------------+ +//! | | data_start == code_end_exclusive +//! | .data | +//! | .bss | +//! | | +//! +---------------------------------------+ +//! | | data_end_exclusive +//! | | +//! +//! +//! +//! +//! +//! The virtual memory layout is as follows: +//! +//! +---------------------------------------+ +//! | | code_start @ __kernel_virt_start_addr +//! | .text | +//! | .rodata | +//! | .got | +//! | .kernel_symbols | +//! | | +//! +---------------------------------------+ +//! | | data_start == code_end_exclusive +//! | .data | +//! | .bss | +//! | | +//! +---------------------------------------+ +//! | | mmio_remap_start == data_end_exclusive +//! | VA region for MMIO remapping | +//! | | +//! +---------------------------------------+ +//! | | mmio_remap_end_exclusive +//! | Unmapped guard page | +//! | | +//! +---------------------------------------+ +//! | | boot_core_stack_start +//! | | ^ +//! | Boot-core Stack | | stack +//! | | | growth +//! | | | direction +//! +---------------------------------------+ +//! | | boot_core_stack_end_exclusive +//! | | +pub mod mmu; + +use crate::memory::{mmu::PageAddress, Address, Physical, Virtual}; +use core::cell::UnsafeCell; + +//-------------------------------------------------------------------------------------------------- +// Private Definitions +//-------------------------------------------------------------------------------------------------- + +// Symbols from the linker script. +extern "Rust" { + static __code_start: UnsafeCell<()>; + static __code_end_exclusive: UnsafeCell<()>; + + static __data_start: UnsafeCell<()>; + static __data_end_exclusive: UnsafeCell<()>; + + static __mmio_remap_start: UnsafeCell<()>; + static __mmio_remap_end_exclusive: UnsafeCell<()>; + + static __boot_core_stack_start: UnsafeCell<()>; + static __boot_core_stack_end_exclusive: UnsafeCell<()>; +} + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +/// The board's physical memory map. +#[rustfmt::skip] +pub(super) mod map { + use super::*; + + /// Physical devices. + #[cfg(feature = "bsp_rpi3")] + pub mod mmio { + use super::*; + + pub const PERIPHERAL_IC_START: Address = Address::new(0x3F00_B200); + pub const PERIPHERAL_IC_SIZE: usize = 0x24; + + pub const GPIO_START: Address = Address::new(0x3F20_0000); + pub const GPIO_SIZE: usize = 0xA0; + + pub const PL011_UART_START: Address = Address::new(0x3F20_1000); + pub const PL011_UART_SIZE: usize = 0x48; + + pub const LOCAL_IC_START: Address = Address::new(0x4000_0000); + pub const LOCAL_IC_SIZE: usize = 0x100; + + pub const END: Address = Address::new(0x4001_0000); + } + + /// Physical devices. + #[cfg(feature = "bsp_rpi4")] + pub mod mmio { + use super::*; + + pub const GPIO_START: Address = Address::new(0xFE20_0000); + pub const GPIO_SIZE: usize = 0xA0; + + pub const PL011_UART_START: Address = Address::new(0xFE20_1000); + pub const PL011_UART_SIZE: usize = 0x48; + + pub const GICD_START: Address = Address::new(0xFF84_1000); + pub const GICD_SIZE: usize = 0x824; + + pub const GICC_START: Address = Address::new(0xFF84_2000); + pub const GICC_SIZE: usize = 0x14; + + pub const END: Address = Address::new(0xFF85_0000); + } + + pub const END: Address = mmio::END; +} + +//-------------------------------------------------------------------------------------------------- +// Private Code +//-------------------------------------------------------------------------------------------------- + +/// Start page address of the code segment. +/// +/// # Safety +/// +/// - Value is provided by the linker script and must be trusted as-is. +#[inline(always)] +fn virt_code_start() -> PageAddress { + PageAddress::from(unsafe { __code_start.get() as usize }) +} + +/// Size of the code segment. +/// +/// # Safety +/// +/// - Value is provided by the linker script and must be trusted as-is. +#[inline(always)] +fn code_size() -> usize { + unsafe { (__code_end_exclusive.get() as usize) - (__code_start.get() as usize) } +} + +/// Start page address of the data segment. +#[inline(always)] +fn virt_data_start() -> PageAddress { + PageAddress::from(unsafe { __data_start.get() as usize }) +} + +/// Size of the data segment. +/// +/// # Safety +/// +/// - Value is provided by the linker script and must be trusted as-is. +#[inline(always)] +fn data_size() -> usize { + unsafe { (__data_end_exclusive.get() as usize) - (__data_start.get() as usize) } +} + +/// Start page address of the MMIO remap reservation. +/// +/// # Safety +/// +/// - Value is provided by the linker script and must be trusted as-is. +#[inline(always)] +fn virt_mmio_remap_start() -> PageAddress { + PageAddress::from(unsafe { __mmio_remap_start.get() as usize }) +} + +/// Size of the MMIO remap reservation. +/// +/// # Safety +/// +/// - Value is provided by the linker script and must be trusted as-is. +#[inline(always)] +fn mmio_remap_size() -> usize { + unsafe { (__mmio_remap_end_exclusive.get() as usize) - (__mmio_remap_start.get() as usize) } +} + +/// Start page address of the boot core's stack. +#[inline(always)] +fn virt_boot_core_stack_start() -> PageAddress { + PageAddress::from(unsafe { __boot_core_stack_start.get() as usize }) +} + +/// Size of the boot core's stack. +#[inline(always)] +fn boot_core_stack_size() -> usize { + unsafe { + (__boot_core_stack_end_exclusive.get() as usize) - (__boot_core_stack_start.get() as usize) + } +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +/// Exclusive end address of the physical address space. +#[inline(always)] +pub fn phys_addr_space_end_exclusive_addr() -> PageAddress { + PageAddress::from(map::END) +} diff --git a/17_kernel_symbols/kernel/src/bsp/raspberrypi/memory/mmu.rs b/17_kernel_symbols/kernel/src/bsp/raspberrypi/memory/mmu.rs new file mode 100644 index 00000000..bfebd8b2 --- /dev/null +++ b/17_kernel_symbols/kernel/src/bsp/raspberrypi/memory/mmu.rs @@ -0,0 +1,179 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2018-2022 Andre Richter + +//! BSP Memory Management Unit. + +use crate::{ + memory::{ + mmu::{ + self as generic_mmu, AddressSpace, AssociatedTranslationTable, AttributeFields, + MemoryRegion, PageAddress, TranslationGranule, + }, + Physical, Virtual, + }, + synchronization::InitStateLock, +}; + +//-------------------------------------------------------------------------------------------------- +// Private Definitions +//-------------------------------------------------------------------------------------------------- + +type KernelTranslationTable = + ::TableStartFromTop; + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +/// The translation granule chosen by this BSP. This will be used everywhere else in the kernel to +/// derive respective data structures and their sizes. For example, the `crate::memory::mmu::Page`. +pub type KernelGranule = TranslationGranule<{ 64 * 1024 }>; + +/// The kernel's virtual address space defined by this BSP. +pub type KernelVirtAddrSpace = AddressSpace<{ kernel_virt_addr_space_size() }>; + +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +/// The kernel translation tables. +/// +/// It is mandatory that InitStateLock is transparent. +/// +/// That is, `size_of(InitStateLock) == size_of(KernelTranslationTable)`. +/// There is a unit tests that checks this porperty. +#[link_section = ".data"] +#[no_mangle] +static KERNEL_TABLES: InitStateLock = + InitStateLock::new(KernelTranslationTable::new_for_precompute()); + +/// This value is needed during early boot for MMU setup. +/// +/// This will be patched to the correct value by the "translation table tool" after linking. This +/// given value here is just a dummy. +#[link_section = ".text._start_arguments"] +#[no_mangle] +static PHYS_KERNEL_TABLES_BASE_ADDR: u64 = 0xCCCCAAAAFFFFEEEE; + +//-------------------------------------------------------------------------------------------------- +// Private Code +//-------------------------------------------------------------------------------------------------- + +/// This is a hack for retrieving the value for the kernel's virtual address space size as a +/// constant from a common place, since it is needed as a compile-time/link-time constant in both, +/// the linker script and the Rust sources. +#[allow(clippy::needless_late_init)] +const fn kernel_virt_addr_space_size() -> usize { + let __kernel_virt_addr_space_size; + + include!("../kernel_virt_addr_space_size.ld"); + + __kernel_virt_addr_space_size +} + +/// Helper function for calculating the number of pages the given parameter spans. +const fn size_to_num_pages(size: usize) -> usize { + assert!(size > 0); + assert!(size % KernelGranule::SIZE == 0); + + size >> KernelGranule::SHIFT +} + +/// The code pages of the kernel binary. +fn virt_code_region() -> MemoryRegion { + let num_pages = size_to_num_pages(super::code_size()); + + let start_page_addr = super::virt_code_start(); + let end_exclusive_page_addr = start_page_addr.checked_offset(num_pages as isize).unwrap(); + + MemoryRegion::new(start_page_addr, end_exclusive_page_addr) +} + +/// The data pages of the kernel binary. +fn virt_data_region() -> MemoryRegion { + let num_pages = size_to_num_pages(super::data_size()); + + let start_page_addr = super::virt_data_start(); + let end_exclusive_page_addr = start_page_addr.checked_offset(num_pages as isize).unwrap(); + + MemoryRegion::new(start_page_addr, end_exclusive_page_addr) +} + +/// The boot core stack pages. +fn virt_boot_core_stack_region() -> MemoryRegion { + let num_pages = size_to_num_pages(super::boot_core_stack_size()); + + let start_page_addr = super::virt_boot_core_stack_start(); + let end_exclusive_page_addr = start_page_addr.checked_offset(num_pages as isize).unwrap(); + + MemoryRegion::new(start_page_addr, end_exclusive_page_addr) +} + +// There is no reason to expect the following conversions to fail, since they were generated offline +// by the `translation table tool`. If it doesn't work, a panic due to the unwraps is justified. +fn kernel_virt_to_phys_region(virt_region: MemoryRegion) -> MemoryRegion { + let phys_start_page_addr = + generic_mmu::try_kernel_virt_page_addr_to_phys_page_addr(virt_region.start_page_addr()) + .unwrap(); + + let phys_end_exclusive_page_addr = phys_start_page_addr + .checked_offset(virt_region.num_pages() as isize) + .unwrap(); + + MemoryRegion::new(phys_start_page_addr, phys_end_exclusive_page_addr) +} + +fn kernel_page_attributes(virt_page_addr: PageAddress) -> AttributeFields { + generic_mmu::try_kernel_page_attributes(virt_page_addr).unwrap() +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +/// Return a reference to the kernel's translation tables. +pub fn kernel_translation_tables() -> &'static InitStateLock { + &KERNEL_TABLES +} + +/// The MMIO remap pages. +pub fn virt_mmio_remap_region() -> MemoryRegion { + let num_pages = size_to_num_pages(super::mmio_remap_size()); + + let start_page_addr = super::virt_mmio_remap_start(); + let end_exclusive_page_addr = start_page_addr.checked_offset(num_pages as isize).unwrap(); + + MemoryRegion::new(start_page_addr, end_exclusive_page_addr) +} + +/// Add mapping records for the kernel binary. +/// +/// The actual translation table entries for the kernel binary are generated using the offline +/// `translation table tool` and patched into the kernel binary. This function just adds the mapping +/// record entries. +pub fn kernel_add_mapping_records_for_precomputed() { + let virt_code_region = virt_code_region(); + generic_mmu::kernel_add_mapping_record( + "Kernel code and RO data", + &virt_code_region, + &kernel_virt_to_phys_region(virt_code_region), + &kernel_page_attributes(virt_code_region.start_page_addr()), + ); + + let virt_data_region = virt_data_region(); + generic_mmu::kernel_add_mapping_record( + "Kernel data and bss", + &virt_data_region, + &kernel_virt_to_phys_region(virt_data_region), + &kernel_page_attributes(virt_data_region.start_page_addr()), + ); + + let virt_boot_core_stack_region = virt_boot_core_stack_region(); + generic_mmu::kernel_add_mapping_record( + "Kernel boot-core stack", + &virt_boot_core_stack_region, + &kernel_virt_to_phys_region(virt_boot_core_stack_region), + &kernel_page_attributes(virt_boot_core_stack_region.start_page_addr()), + ); +} diff --git a/17_kernel_symbols/kernel/src/common.rs b/17_kernel_symbols/kernel/src/common.rs new file mode 100644 index 00000000..678f4a6c --- /dev/null +++ b/17_kernel_symbols/kernel/src/common.rs @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2020-2022 Andre Richter + +//! General purpose code. + +/// Check if a value is aligned to a given size. +#[inline(always)] +pub const fn is_aligned(value: usize, alignment: usize) -> bool { + assert!(alignment.is_power_of_two()); + + (value & (alignment - 1)) == 0 +} + +/// Align down. +#[inline(always)] +pub const fn align_down(value: usize, alignment: usize) -> usize { + assert!(alignment.is_power_of_two()); + + value & !(alignment - 1) +} + +/// Align up. +#[inline(always)] +pub const fn align_up(value: usize, alignment: usize) -> usize { + assert!(alignment.is_power_of_two()); + + (value + alignment - 1) & !(alignment - 1) +} diff --git a/17_kernel_symbols/kernel/src/console.rs b/17_kernel_symbols/kernel/src/console.rs new file mode 100644 index 00000000..e49e241f --- /dev/null +++ b/17_kernel_symbols/kernel/src/console.rs @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2018-2022 Andre Richter + +//! System console. + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +/// Console interfaces. +pub mod interface { + use core::fmt; + + /// Console write functions. + pub trait Write { + /// Write a single character. + fn write_char(&self, c: char); + + /// Write a Rust format string. + fn write_fmt(&self, args: fmt::Arguments) -> fmt::Result; + + /// Block until the last buffered character has been physically put on the TX wire. + fn flush(&self); + } + + /// Console read functions. + pub trait Read { + /// Read a single character. + fn read_char(&self) -> char { + ' ' + } + + /// Clear RX buffers, if any. + fn clear_rx(&self); + } + + /// Console statistics. + pub trait Statistics { + /// Return the number of characters written. + fn chars_written(&self) -> usize { + 0 + } + + /// Return the number of characters read. + fn chars_read(&self) -> usize { + 0 + } + } + + /// Trait alias for a full-fledged console. + pub trait All = Write + Read + Statistics; +} diff --git a/17_kernel_symbols/kernel/src/cpu.rs b/17_kernel_symbols/kernel/src/cpu.rs new file mode 100644 index 00000000..e1493d1d --- /dev/null +++ b/17_kernel_symbols/kernel/src/cpu.rs @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2020-2022 Andre Richter + +//! Processor code. + +#[cfg(target_arch = "aarch64")] +#[path = "_arch/aarch64/cpu.rs"] +mod arch_cpu; + +mod boot; + +pub mod smp; + +//-------------------------------------------------------------------------------------------------- +// Architectural Public Reexports +//-------------------------------------------------------------------------------------------------- +pub use arch_cpu::{nop, wait_forever}; + +#[cfg(feature = "test_build")] +pub use arch_cpu::{qemu_exit_failure, qemu_exit_success}; diff --git a/17_kernel_symbols/kernel/src/cpu/boot.rs b/17_kernel_symbols/kernel/src/cpu/boot.rs new file mode 100644 index 00000000..8091dac3 --- /dev/null +++ b/17_kernel_symbols/kernel/src/cpu/boot.rs @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2021-2022 Andre Richter + +//! Boot code. + +#[cfg(target_arch = "aarch64")] +#[path = "../_arch/aarch64/cpu/boot.rs"] +mod arch_boot; diff --git a/17_kernel_symbols/kernel/src/cpu/smp.rs b/17_kernel_symbols/kernel/src/cpu/smp.rs new file mode 100644 index 00000000..57386f79 --- /dev/null +++ b/17_kernel_symbols/kernel/src/cpu/smp.rs @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2018-2022 Andre Richter + +//! Symmetric multiprocessing. + +#[cfg(target_arch = "aarch64")] +#[path = "../_arch/aarch64/cpu/smp.rs"] +mod arch_smp; + +//-------------------------------------------------------------------------------------------------- +// Architectural Public Reexports +//-------------------------------------------------------------------------------------------------- +pub use arch_smp::core_id; diff --git a/17_kernel_symbols/kernel/src/driver.rs b/17_kernel_symbols/kernel/src/driver.rs new file mode 100644 index 00000000..7b800dbc --- /dev/null +++ b/17_kernel_symbols/kernel/src/driver.rs @@ -0,0 +1,62 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2018-2022 Andre Richter + +//! Driver support. + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +/// Driver interfaces. +pub mod interface { + /// Device Driver functions. + pub trait DeviceDriver { + /// Return a compatibility string for identifying the driver. + fn compatible(&self) -> &'static str; + + /// Called by the kernel to bring up the device. + /// + /// # Safety + /// + /// - During init, drivers might do stuff with system-wide impact. + unsafe fn init(&self) -> Result<(), &'static str> { + Ok(()) + } + + /// Called by the kernel to register and enable the device's IRQ handlers, if any. + /// + /// Rust's type system will prevent a call to this function unless the calling instance + /// itself has static lifetime. + fn register_and_enable_irq_handler(&'static self) -> Result<(), &'static str> { + Ok(()) + } + + /// After MMIO remapping, returns the new virtual start address. + /// + /// This API assumes a driver has only a single, contiguous MMIO aperture, which will not be + /// the case for more complex devices. This API will likely change in future tutorials. + fn virt_mmio_start_addr(&self) -> Option { + None + } + } + + /// Device driver management functions. + /// + /// The `BSP` is supposed to supply one global instance. + pub trait DriverManager { + /// Return a slice of references to all `BSP`-instantiated drivers. + fn all_device_drivers(&self) -> &[&'static (dyn DeviceDriver + Sync)]; + + /// Return only those drivers needed for the BSP's early printing functionality. + /// + /// For example, the default UART. + fn early_print_device_drivers(&self) -> &[&'static (dyn DeviceDriver + Sync)]; + + /// Return all drivers minus early-print drivers. + fn non_early_print_device_drivers(&self) -> &[&'static (dyn DeviceDriver + Sync)]; + + /// Initialization code that runs after the early print driver init. + fn post_early_print_device_driver_init(&self); + } +} diff --git a/17_kernel_symbols/kernel/src/exception.rs b/17_kernel_symbols/kernel/src/exception.rs new file mode 100644 index 00000000..f4af8144 --- /dev/null +++ b/17_kernel_symbols/kernel/src/exception.rs @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2020-2022 Andre Richter + +//! Synchronous and asynchronous exception handling. + +#[cfg(target_arch = "aarch64")] +#[path = "_arch/aarch64/exception.rs"] +mod arch_exception; + +pub mod asynchronous; + +//-------------------------------------------------------------------------------------------------- +// Architectural Public Reexports +//-------------------------------------------------------------------------------------------------- +pub use arch_exception::{current_privilege_level, handling_init}; + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +/// Kernel privilege levels. +#[allow(missing_docs)] +#[derive(PartialEq)] +pub enum PrivilegeLevel { + User, + Kernel, + Hypervisor, + Unknown, +} + +//-------------------------------------------------------------------------------------------------- +// Testing +//-------------------------------------------------------------------------------------------------- + +#[cfg(test)] +mod tests { + use super::*; + use test_macros::kernel_test; + + /// Libkernel unit tests must execute in kernel mode. + #[kernel_test] + fn test_runner_executes_in_kernel_mode() { + let (level, _) = current_privilege_level(); + + assert!(level == PrivilegeLevel::Kernel) + } +} diff --git a/17_kernel_symbols/kernel/src/exception/asynchronous.rs b/17_kernel_symbols/kernel/src/exception/asynchronous.rs new file mode 100644 index 00000000..fb1785c2 --- /dev/null +++ b/17_kernel_symbols/kernel/src/exception/asynchronous.rs @@ -0,0 +1,152 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2020-2022 Andre Richter + +//! Asynchronous exception handling. + +#[cfg(target_arch = "aarch64")] +#[path = "../_arch/aarch64/exception/asynchronous.rs"] +mod arch_asynchronous; + +use core::{fmt, marker::PhantomData}; + +//-------------------------------------------------------------------------------------------------- +// Architectural Public Reexports +//-------------------------------------------------------------------------------------------------- +pub use arch_asynchronous::{ + is_local_irq_masked, local_irq_mask, local_irq_mask_save, local_irq_restore, local_irq_unmask, + print_state, +}; + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +/// Interrupt descriptor. +#[derive(Copy, Clone)] +pub struct IRQDescriptor { + /// Descriptive name. + pub name: &'static str, + + /// Reference to handler trait object. + pub handler: &'static (dyn interface::IRQHandler + Sync), +} + +/// IRQContext token. +/// +/// An instance of this type indicates that the local core is currently executing in IRQ +/// context, aka executing an interrupt vector or subcalls of it. +/// +/// Concept and implementation derived from the `CriticalSection` introduced in +/// +#[derive(Clone, Copy)] +pub struct IRQContext<'irq_context> { + _0: PhantomData<&'irq_context ()>, +} + +/// Asynchronous exception handling interfaces. +pub mod interface { + + /// Implemented by types that handle IRQs. + pub trait IRQHandler { + /// Called when the corresponding interrupt is asserted. + fn handle(&self) -> Result<(), &'static str>; + } + + /// IRQ management functions. + /// + /// The `BSP` is supposed to supply one global instance. Typically implemented by the + /// platform's interrupt controller. + pub trait IRQManager { + /// The IRQ number type depends on the implementation. + type IRQNumberType; + + /// Register a handler. + fn register_handler( + &self, + irq_number: Self::IRQNumberType, + descriptor: super::IRQDescriptor, + ) -> Result<(), &'static str>; + + /// Enable an interrupt in the controller. + fn enable(&self, irq_number: Self::IRQNumberType); + + /// Handle pending interrupts. + /// + /// This function is called directly from the CPU's IRQ exception vector. On AArch64, + /// this means that the respective CPU core has disabled exception handling. + /// This function can therefore not be preempted and runs start to finish. + /// + /// Takes an IRQContext token to ensure it can only be called from IRQ context. + #[allow(clippy::trivially_copy_pass_by_ref)] + fn handle_pending_irqs<'irq_context>( + &'irq_context self, + ic: &super::IRQContext<'irq_context>, + ); + + /// Print list of registered handlers. + fn print_handler(&self); + } +} + +/// A wrapper type for IRQ numbers with integrated range sanity check. +#[derive(Copy, Clone)] +pub struct IRQNumber(usize); + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +impl<'irq_context> IRQContext<'irq_context> { + /// Creates an IRQContext token. + /// + /// # Safety + /// + /// - This must only be called when the current core is in an interrupt context and will not + /// live beyond the end of it. That is, creation is allowed in interrupt vector functions. For + /// example, in the ARMv8-A case, in `extern "C" fn current_elx_irq()`. + /// - Note that the lifetime `'irq_context` of the returned instance is unconstrained. User code + /// must not be able to influence the lifetime picked for this type, since that might cause it + /// to be inferred to `'static`. + #[inline(always)] + pub unsafe fn new() -> Self { + IRQContext { _0: PhantomData } + } +} + +impl IRQNumber<{ MAX_INCLUSIVE }> { + /// Creates a new instance if number <= MAX_INCLUSIVE. + pub const fn new(number: usize) -> Self { + assert!(number <= MAX_INCLUSIVE); + + Self(number) + } + + /// Return the wrapped number. + pub const fn get(self) -> usize { + self.0 + } +} + +impl fmt::Display for IRQNumber<{ MAX_INCLUSIVE }> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.0) + } +} + +/// Executes the provided closure while IRQs are masked on the executing core. +/// +/// While the function temporarily changes the HW state of the executing core, it restores it to the +/// previous state before returning, so this is deemed safe. +#[inline(always)] +pub fn exec_with_irq_masked(f: impl FnOnce() -> T) -> T { + let ret: T; + + unsafe { + let saved = local_irq_mask_save(); + ret = f(); + local_irq_restore(saved); + } + + ret +} diff --git a/17_kernel_symbols/kernel/src/lib.rs b/17_kernel_symbols/kernel/src/lib.rs new file mode 100644 index 00000000..0178b272 --- /dev/null +++ b/17_kernel_symbols/kernel/src/lib.rs @@ -0,0 +1,185 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2018-2022 Andre Richter + +// Rust embedded logo for `make doc`. +#![doc(html_logo_url = "https://git.io/JeGIp")] + +//! The `kernel` library. +//! +//! Used to compose the final kernel binary. +//! +//! # Code organization and architecture +//! +//! The code is divided into different *modules*, each representing a typical **subsystem** of the +//! `kernel`. Top-level module files of subsystems reside directly in the `src` folder. For example, +//! `src/memory.rs` contains code that is concerned with all things memory management. +//! +//! ## Visibility of processor architecture code +//! +//! Some of the `kernel`'s subsystems depend on low-level code that is specific to the target +//! processor architecture. For each supported processor architecture, there exists a subfolder in +//! `src/_arch`, for example, `src/_arch/aarch64`. +//! +//! The architecture folders mirror the subsystem modules laid out in `src`. For example, +//! architectural code that belongs to the `kernel`'s MMU subsystem (`src/memory/mmu.rs`) would go +//! into `src/_arch/aarch64/memory/mmu.rs`. The latter file is loaded as a module in +//! `src/memory/mmu.rs` using the `path attribute`. Usually, the chosen module name is the generic +//! module's name prefixed with `arch_`. +//! +//! For example, this is the top of `src/memory/mmu.rs`: +//! +//! ``` +//! #[cfg(target_arch = "aarch64")] +//! #[path = "../_arch/aarch64/memory/mmu.rs"] +//! mod arch_mmu; +//! ``` +//! +//! Often times, items from the `arch_ module` will be publicly reexported by the parent module. +//! This way, each architecture specific module can provide its implementation of an item, while the +//! caller must not be concerned which architecture has been conditionally compiled. +//! +//! ## BSP code +//! +//! `BSP` stands for Board Support Package. `BSP` code is organized under `src/bsp.rs` and contains +//! target board specific definitions and functions. These are things such as the board's memory map +//! or instances of drivers for devices that are featured on the respective board. +//! +//! Just like processor architecture code, the `BSP` code's module structure tries to mirror the +//! `kernel`'s subsystem modules, but there is no reexporting this time. That means whatever is +//! provided must be called starting from the `bsp` namespace, e.g. `bsp::driver::driver_manager()`. +//! +//! ## Kernel interfaces +//! +//! Both `arch` and `bsp` contain code that is conditionally compiled depending on the actual target +//! and board for which the kernel is compiled. For example, the `interrupt controller` hardware of +//! the `Raspberry Pi 3` and the `Raspberry Pi 4` is different, but we want the rest of the `kernel` +//! code to play nicely with any of the two without much hassle. +//! +//! In order to provide a clean abstraction between `arch`, `bsp` and `generic kernel code`, +//! `interface` traits are provided *whenever possible* and *where it makes sense*. They are defined +//! in the respective subsystem module and help to enforce the idiom of *program to an interface, +//! not an implementation*. For example, there will be a common IRQ handling interface which the two +//! different interrupt controller `drivers` of both Raspberrys will implement, and only export the +//! interface to the rest of the `kernel`. +//! +//! ``` +//! +-------------------+ +//! | Interface (Trait) | +//! | | +//! +--+-------------+--+ +//! ^ ^ +//! | | +//! | | +//! +----------+--+ +--+----------+ +//! | kernel code | | bsp code | +//! | | | arch code | +//! +-------------+ +-------------+ +//! ``` +//! +//! # Summary +//! +//! For a logical `kernel` subsystem, corresponding code can be distributed over several physical +//! locations. Here is an example for the **memory** subsystem: +//! +//! - `src/memory.rs` and `src/memory/**/*` +//! - Common code that is agnostic of target processor architecture and `BSP` characteristics. +//! - Example: A function to zero a chunk of memory. +//! - Interfaces for the memory subsystem that are implemented by `arch` or `BSP` code. +//! - Example: An `MMU` interface that defines `MMU` function prototypes. +//! - `src/bsp/__board_name__/memory.rs` and `src/bsp/__board_name__/memory/**/*` +//! - `BSP` specific code. +//! - Example: The board's memory map (physical addresses of DRAM and MMIO devices). +//! - `src/_arch/__arch_name__/memory.rs` and `src/_arch/__arch_name__/memory/**/*` +//! - Processor architecture specific code. +//! - Example: Implementation of the `MMU` interface for the `__arch_name__` processor +//! architecture. +//! +//! From a namespace perspective, **memory** subsystem code lives in: +//! +//! - `crate::memory::*` +//! - `crate::bsp::memory::*` +//! +//! # Boot flow +//! +//! 1. The kernel's entry point is the function `cpu::boot::arch_boot::_start()`. +//! - It is implemented in `src/_arch/__arch_name__/cpu/boot.s`. +//! 2. Once finished with architectural setup, the arch code calls `kernel_init()`. + +#![allow(clippy::upper_case_acronyms)] +#![allow(incomplete_features)] +#![feature(asm_const)] +#![feature(core_intrinsics)] +#![feature(format_args_nl)] +#![feature(generic_const_exprs)] +#![feature(linkage)] +#![feature(panic_info_message)] +#![feature(step_trait)] +#![feature(trait_alias)] +#![no_std] +// Testing +#![cfg_attr(test, no_main)] +#![feature(custom_test_frameworks)] +#![reexport_test_harness_main = "test_main"] +#![test_runner(crate::test_runner)] + +mod panic_wait; +mod synchronization; + +pub mod bsp; +pub mod common; +pub mod console; +pub mod cpu; +pub mod driver; +pub mod exception; +pub mod memory; +pub mod print; +pub mod state; +pub mod symbols; +pub mod time; + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +/// Version string. +pub fn version() -> &'static str { + concat!( + env!("CARGO_PKG_NAME"), + " version ", + env!("CARGO_PKG_VERSION") + ) +} + +//-------------------------------------------------------------------------------------------------- +// Testing +//-------------------------------------------------------------------------------------------------- + +/// The default runner for unit tests. +pub fn test_runner(tests: &[&test_types::UnitTest]) { + // This line will be printed as the test header. + println!("Running {} tests", tests.len()); + + for (i, test) in tests.iter().enumerate() { + print!("{:>3}. {:.<58}", i + 1, test.name); + + // Run the actual test. + (test.test_func)(); + + // Failed tests call panic!(). Execution reaches here only if the test has passed. + println!("[ok]") + } +} + +/// The `kernel_init()` for unit tests. +#[cfg(test)] +#[no_mangle] +unsafe fn kernel_init() -> ! { + exception::handling_init(); + memory::mmu::post_enable_init(); + bsp::console::qemu_bring_up_console(); + + test_main(); + + cpu::qemu_exit_success() +} diff --git a/17_kernel_symbols/kernel/src/main.rs b/17_kernel_symbols/kernel/src/main.rs new file mode 100644 index 00000000..8bc80885 --- /dev/null +++ b/17_kernel_symbols/kernel/src/main.rs @@ -0,0 +1,109 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2018-2022 Andre Richter + +// Rust embedded logo for `make doc`. +#![doc(html_logo_url = "https://git.io/JeGIp")] + +//! The `kernel` binary. + +#![feature(format_args_nl)] +#![no_main] +#![no_std] + +use libkernel::{bsp, cpu, driver, exception, info, memory, state, time, warn}; + +/// Early init code. +/// +/// When this code runs, virtual memory is already enabled. +/// +/// # Safety +/// +/// - Only a single core must be active and running this function. +/// - Printing will not work until the respective driver's MMIO is remapped. +#[no_mangle] +unsafe fn kernel_init() -> ! { + use driver::interface::DriverManager; + + exception::handling_init(); + memory::mmu::post_enable_init(); + + // Add the mapping records for the precomputed entries first, so that they appear on the top of + // the list. + bsp::memory::mmu::kernel_add_mapping_records_for_precomputed(); + + // Bring up the drivers needed for printing first. + for i in bsp::driver::driver_manager() + .early_print_device_drivers() + .iter() + { + // Any encountered errors cannot be printed yet, obviously, so just safely park the CPU. + i.init().unwrap_or_else(|_| cpu::wait_forever()); + } + bsp::driver::driver_manager().post_early_print_device_driver_init(); + // Printing available from here on. + + // Now bring up the remaining drivers. + for i in bsp::driver::driver_manager() + .non_early_print_device_drivers() + .iter() + { + if let Err(x) = i.init() { + panic!("Error loading driver: {}: {}", i.compatible(), x); + } + } + + // Let device drivers register and enable their handlers with the interrupt controller. + for i in bsp::driver::driver_manager().all_device_drivers() { + if let Err(msg) = i.register_and_enable_irq_handler() { + warn!("Error registering IRQ handler: {}", msg); + } + } + + // Unmask interrupts on the boot CPU core. + exception::asynchronous::local_irq_unmask(); + + // Announce conclusion of the kernel_init() phase. + state::state_manager().transition_to_single_core_main(); + + // Transition from unsafe to safe. + kernel_main() +} + +/// The main function running after the early init. +fn kernel_main() -> ! { + use driver::interface::DriverManager; + use exception::asynchronous::interface::IRQManager; + + info!("{}", libkernel::version()); + info!("Booting on: {}", bsp::board_name()); + + info!("MMU online:"); + memory::mmu::kernel_print_mappings(); + + let (_, privilege_level) = exception::current_privilege_level(); + info!("Current privilege level: {}", privilege_level); + + info!("Exception handling state:"); + exception::asynchronous::print_state(); + + info!( + "Architectural timer resolution: {} ns", + time::time_manager().resolution().as_nanos() + ); + + info!("Drivers loaded:"); + for (i, driver) in bsp::driver::driver_manager() + .all_device_drivers() + .iter() + .enumerate() + { + info!(" {}. {}", i + 1, driver.compatible()); + } + + info!("Registered IRQ handlers:"); + bsp::exception::asynchronous::irq_manager().print_handler(); + + info!("Echoing input now"); + cpu::wait_forever(); +} diff --git a/17_kernel_symbols/kernel/src/memory.rs b/17_kernel_symbols/kernel/src/memory.rs new file mode 100644 index 00000000..f20719bb --- /dev/null +++ b/17_kernel_symbols/kernel/src/memory.rs @@ -0,0 +1,167 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2018-2022 Andre Richter + +//! Memory Management. + +pub mod mmu; + +use crate::{bsp, common}; +use core::{ + fmt, + marker::PhantomData, + ops::{Add, Sub}, +}; + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +/// Metadata trait for marking the type of an address. +pub trait AddressType: Copy + Clone + PartialOrd + PartialEq {} + +/// Zero-sized type to mark a physical address. +#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)] +pub enum Physical {} + +/// Zero-sized type to mark a virtual address. +#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)] +pub enum Virtual {} + +/// Generic address type. +#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)] +pub struct Address { + value: usize, + _address_type: PhantomData ATYPE>, +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +impl AddressType for Physical {} +impl AddressType for Virtual {} + +impl Address { + /// Create an instance. + pub const fn new(value: usize) -> Self { + Self { + value, + _address_type: PhantomData, + } + } + + /// Convert to usize. + pub const fn as_usize(self) -> usize { + self.value + } + + /// Align down to page size. + #[must_use] + pub const fn align_down_page(self) -> Self { + let aligned = common::align_down(self.value, bsp::memory::mmu::KernelGranule::SIZE); + + Self::new(aligned) + } + + /// Align up to page size. + #[must_use] + pub const fn align_up_page(self) -> Self { + let aligned = common::align_up(self.value, bsp::memory::mmu::KernelGranule::SIZE); + + Self::new(aligned) + } + + /// Checks if the address is page aligned. + pub const fn is_page_aligned(&self) -> bool { + common::is_aligned(self.value, bsp::memory::mmu::KernelGranule::SIZE) + } + + /// Return the address' offset into the corresponding page. + pub const fn offset_into_page(&self) -> usize { + self.value & bsp::memory::mmu::KernelGranule::MASK + } +} + +impl Add for Address { + type Output = Self; + + #[inline(always)] + fn add(self, rhs: usize) -> Self::Output { + match self.value.checked_add(rhs) { + None => panic!("Overflow on Address::add"), + Some(x) => Self::new(x), + } + } +} + +impl Sub> for Address { + type Output = Self; + + #[inline(always)] + fn sub(self, rhs: Address) -> Self::Output { + match self.value.checked_sub(rhs.value) { + None => panic!("Overflow on Address::sub"), + Some(x) => Self::new(x), + } + } +} + +impl fmt::Display for Address { + // Don't expect to see physical addresses greater than 40 bit. + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let q3: u8 = ((self.value >> 32) & 0xff) as u8; + let q2: u16 = ((self.value >> 16) & 0xffff) as u16; + let q1: u16 = (self.value & 0xffff) as u16; + + write!(f, "0x")?; + write!(f, "{:02x}_", q3)?; + write!(f, "{:04x}_", q2)?; + write!(f, "{:04x}", q1) + } +} + +impl fmt::Display for Address { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let q4: u16 = ((self.value >> 48) & 0xffff) as u16; + let q3: u16 = ((self.value >> 32) & 0xffff) as u16; + let q2: u16 = ((self.value >> 16) & 0xffff) as u16; + let q1: u16 = (self.value & 0xffff) as u16; + + write!(f, "0x")?; + write!(f, "{:04x}_", q4)?; + write!(f, "{:04x}_", q3)?; + write!(f, "{:04x}_", q2)?; + write!(f, "{:04x}", q1) + } +} + +//-------------------------------------------------------------------------------------------------- +// Testing +//-------------------------------------------------------------------------------------------------- + +#[cfg(test)] +mod tests { + use super::*; + use test_macros::kernel_test; + + /// Sanity of [Address] methods. + #[kernel_test] + fn address_type_method_sanity() { + let addr = Address::::new(bsp::memory::mmu::KernelGranule::SIZE + 100); + + assert_eq!( + addr.align_down_page().as_usize(), + bsp::memory::mmu::KernelGranule::SIZE + ); + + assert_eq!( + addr.align_up_page().as_usize(), + bsp::memory::mmu::KernelGranule::SIZE * 2 + ); + + assert!(!addr.is_page_aligned()); + + assert_eq!(addr.offset_into_page(), 100); + } +} diff --git a/17_kernel_symbols/kernel/src/memory/mmu.rs b/17_kernel_symbols/kernel/src/memory/mmu.rs new file mode 100644 index 00000000..dfc29993 --- /dev/null +++ b/17_kernel_symbols/kernel/src/memory/mmu.rs @@ -0,0 +1,270 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2020-2022 Andre Richter + +//! Memory Management Unit. + +#[cfg(target_arch = "aarch64")] +#[path = "../_arch/aarch64/memory/mmu.rs"] +mod arch_mmu; + +mod alloc; +mod mapping_record; +mod translation_table; +mod types; + +use crate::{ + bsp, + memory::{Address, Physical, Virtual}, + synchronization::{self, interface::Mutex}, + warn, +}; +use core::{fmt, num::NonZeroUsize}; + +pub use types::*; + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +/// MMU enable errors variants. +#[allow(missing_docs)] +#[derive(Debug)] +pub enum MMUEnableError { + AlreadyEnabled, + Other(&'static str), +} + +/// Memory Management interfaces. +pub mod interface { + use super::*; + + /// MMU functions. + pub trait MMU { + /// Turns on the MMU for the first time and enables data and instruction caching. + /// + /// # Safety + /// + /// - Changes the HW's global state. + unsafe fn enable_mmu_and_caching( + &self, + phys_tables_base_addr: Address, + ) -> Result<(), MMUEnableError>; + + /// Returns true if the MMU is enabled, false otherwise. + fn is_enabled(&self) -> bool; + } +} + +/// Describes the characteristics of a translation granule. +pub struct TranslationGranule; + +/// Describes properties of an address space. +pub struct AddressSpace; + +/// Intended to be implemented for [`AddressSpace`]. +pub trait AssociatedTranslationTable { + /// A translation table whose address range is: + /// + /// [u64::MAX, (u64::MAX - AS_SIZE) + 1] + type TableStartFromTop; + + /// A translation table whose address range is: + /// + /// [AS_SIZE - 1, 0] + type TableStartFromBottom; +} + +//-------------------------------------------------------------------------------------------------- +// Private Code +//-------------------------------------------------------------------------------------------------- +use interface::MMU; +use synchronization::interface::ReadWriteEx; +use translation_table::interface::TranslationTable; + +/// Query the BSP for the reserved virtual addresses for MMIO remapping and initialize the kernel's +/// MMIO VA allocator with it. +fn kernel_init_mmio_va_allocator() { + let region = bsp::memory::mmu::virt_mmio_remap_region(); + + alloc::kernel_mmio_va_allocator().lock(|allocator| allocator.initialize(region)); +} + +/// Map a region in the kernel's translation tables. +/// +/// No input checks done, input is passed through to the architectural implementation. +/// +/// # Safety +/// +/// - See `map_at()`. +/// - Does not prevent aliasing. +unsafe fn kernel_map_at_unchecked( + name: &'static str, + virt_region: &MemoryRegion, + phys_region: &MemoryRegion, + attr: &AttributeFields, +) -> Result<(), &'static str> { + bsp::memory::mmu::kernel_translation_tables() + .write(|tables| tables.map_at(virt_region, phys_region, attr))?; + + kernel_add_mapping_record(name, virt_region, phys_region, attr); + + Ok(()) +} + +/// Try to translate a kernel virtual address to a physical address. +/// +/// Will only succeed if there exists a valid mapping for the input address. +fn try_kernel_virt_addr_to_phys_addr( + virt_addr: Address, +) -> Result, &'static str> { + bsp::memory::mmu::kernel_translation_tables() + .read(|tables| tables.try_virt_addr_to_phys_addr(virt_addr)) +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +impl fmt::Display for MMUEnableError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + MMUEnableError::AlreadyEnabled => write!(f, "MMU is already enabled"), + MMUEnableError::Other(x) => write!(f, "{}", x), + } + } +} + +impl TranslationGranule { + /// The granule's size. + pub const SIZE: usize = Self::size_checked(); + + /// The granule's mask. + pub const MASK: usize = Self::SIZE - 1; + + /// The granule's shift, aka log2(size). + pub const SHIFT: usize = Self::SIZE.trailing_zeros() as usize; + + const fn size_checked() -> usize { + assert!(GRANULE_SIZE.is_power_of_two()); + + GRANULE_SIZE + } +} + +impl AddressSpace { + /// The address space size. + pub const SIZE: usize = Self::size_checked(); + + /// The address space shift, aka log2(size). + pub const SIZE_SHIFT: usize = Self::SIZE.trailing_zeros() as usize; + + const fn size_checked() -> usize { + assert!(AS_SIZE.is_power_of_two()); + + // Check for architectural restrictions as well. + Self::arch_address_space_size_sanity_checks(); + + AS_SIZE + } +} + +/// Add an entry to the mapping info record. +pub fn kernel_add_mapping_record( + name: &'static str, + virt_region: &MemoryRegion, + phys_region: &MemoryRegion, + attr: &AttributeFields, +) { + if let Err(x) = mapping_record::kernel_add(name, virt_region, phys_region, attr) { + warn!("{}", x); + } +} + +/// MMIO remapping in the kernel translation tables. +/// +/// Typically used by device drivers. +/// +/// # Safety +/// +/// - Same as `kernel_map_at_unchecked()`, minus the aliasing part. +pub unsafe fn kernel_map_mmio( + name: &'static str, + mmio_descriptor: &MMIODescriptor, +) -> Result, &'static str> { + let phys_region = MemoryRegion::from(*mmio_descriptor); + let offset_into_start_page = mmio_descriptor.start_addr().offset_into_page(); + + // Check if an identical region has been mapped for another driver. If so, reuse it. + let virt_addr = if let Some(addr) = + mapping_record::kernel_find_and_insert_mmio_duplicate(mmio_descriptor, name) + { + addr + // Otherwise, allocate a new region and map it. + } else { + let num_pages = match NonZeroUsize::new(phys_region.num_pages()) { + None => return Err("Requested 0 pages"), + Some(x) => x, + }; + + let virt_region = + alloc::kernel_mmio_va_allocator().lock(|allocator| allocator.alloc(num_pages))?; + + kernel_map_at_unchecked( + name, + &virt_region, + &phys_region, + &AttributeFields { + mem_attributes: MemAttributes::Device, + acc_perms: AccessPermissions::ReadWrite, + execute_never: true, + }, + )?; + + virt_region.start_addr() + }; + + Ok(virt_addr + offset_into_start_page) +} + +/// Try to translate a kernel virtual page address to a physical page address. +/// +/// Will only succeed if there exists a valid mapping for the input page. +pub fn try_kernel_virt_page_addr_to_phys_page_addr( + virt_page_addr: PageAddress, +) -> Result, &'static str> { + bsp::memory::mmu::kernel_translation_tables() + .read(|tables| tables.try_virt_page_addr_to_phys_page_addr(virt_page_addr)) +} + +/// Try to get the attributes of a kernel page. +/// +/// Will only succeed if there exists a valid mapping for the input page. +pub fn try_kernel_page_attributes( + virt_page_addr: PageAddress, +) -> Result { + bsp::memory::mmu::kernel_translation_tables() + .read(|tables| tables.try_page_attributes(virt_page_addr)) +} + +/// Enable the MMU and data + instruction caching. +/// +/// # Safety +/// +/// - Crucial function during kernel init. Changes the the complete memory view of the processor. +#[inline(always)] +pub unsafe fn enable_mmu_and_caching( + phys_tables_base_addr: Address, +) -> Result<(), MMUEnableError> { + arch_mmu::mmu().enable_mmu_and_caching(phys_tables_base_addr) +} + +/// Finish initialization of the MMU subsystem. +pub fn post_enable_init() { + kernel_init_mmio_va_allocator(); +} + +/// Human-readable print of all recorded kernel mappings. +pub fn kernel_print_mappings() { + mapping_record::kernel_print() +} diff --git a/17_kernel_symbols/kernel/src/memory/mmu/alloc.rs b/17_kernel_symbols/kernel/src/memory/mmu/alloc.rs new file mode 100644 index 00000000..aadb72ef --- /dev/null +++ b/17_kernel_symbols/kernel/src/memory/mmu/alloc.rs @@ -0,0 +1,70 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2021-2022 Andre Richter + +//! Allocation. + +use super::MemoryRegion; +use crate::{ + memory::{AddressType, Virtual}, + synchronization::IRQSafeNullLock, + warn, +}; +use core::num::NonZeroUsize; + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +/// A page allocator that can be lazyily initialized. +pub struct PageAllocator { + pool: Option>, +} + +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +static KERNEL_MMIO_VA_ALLOCATOR: IRQSafeNullLock> = + IRQSafeNullLock::new(PageAllocator::new()); + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +/// Return a reference to the kernel's MMIO virtual address allocator. +pub fn kernel_mmio_va_allocator() -> &'static IRQSafeNullLock> { + &KERNEL_MMIO_VA_ALLOCATOR +} + +impl PageAllocator { + /// Create an instance. + pub const fn new() -> Self { + Self { pool: None } + } + + /// Initialize the allocator. + pub fn initialize(&mut self, pool: MemoryRegion) { + if self.pool.is_some() { + warn!("Already initialized"); + return; + } + + self.pool = Some(pool); + } + + /// Allocate a number of pages. + pub fn alloc( + &mut self, + num_requested_pages: NonZeroUsize, + ) -> Result, &'static str> { + if self.pool.is_none() { + return Err("Allocator not initialized"); + } + + self.pool + .as_mut() + .unwrap() + .take_first_n_pages(num_requested_pages) + } +} diff --git a/17_kernel_symbols/kernel/src/memory/mmu/mapping_record.rs b/17_kernel_symbols/kernel/src/memory/mmu/mapping_record.rs new file mode 100644 index 00000000..d171c6e6 --- /dev/null +++ b/17_kernel_symbols/kernel/src/memory/mmu/mapping_record.rs @@ -0,0 +1,233 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2020-2022 Andre Richter + +//! A record of mapped pages. + +use super::{ + AccessPermissions, Address, AttributeFields, MMIODescriptor, MemAttributes, MemoryRegion, + Physical, Virtual, +}; +use crate::{bsp, info, synchronization, synchronization::InitStateLock, warn}; + +//-------------------------------------------------------------------------------------------------- +// Private Definitions +//-------------------------------------------------------------------------------------------------- + +/// Type describing a virtual memory mapping. +#[allow(missing_docs)] +#[derive(Copy, Clone)] +struct MappingRecordEntry { + pub users: [Option<&'static str>; 5], + pub phys_start_addr: Address, + pub virt_start_addr: Address, + pub num_pages: usize, + pub attribute_fields: AttributeFields, +} + +struct MappingRecord { + inner: [Option; 12], +} + +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +static KERNEL_MAPPING_RECORD: InitStateLock = + InitStateLock::new(MappingRecord::new()); + +//-------------------------------------------------------------------------------------------------- +// Private Code +//-------------------------------------------------------------------------------------------------- + +impl MappingRecordEntry { + pub fn new( + name: &'static str, + virt_region: &MemoryRegion, + phys_region: &MemoryRegion, + attr: &AttributeFields, + ) -> Self { + Self { + users: [Some(name), None, None, None, None], + phys_start_addr: phys_region.start_addr(), + virt_start_addr: virt_region.start_addr(), + num_pages: phys_region.num_pages(), + attribute_fields: *attr, + } + } + + fn find_next_free_user(&mut self) -> Result<&mut Option<&'static str>, &'static str> { + if let Some(x) = self.users.iter_mut().find(|x| x.is_none()) { + return Ok(x); + }; + + Err("Storage for user info exhausted") + } + + pub fn add_user(&mut self, user: &'static str) -> Result<(), &'static str> { + let x = self.find_next_free_user()?; + *x = Some(user); + Ok(()) + } +} + +impl MappingRecord { + pub const fn new() -> Self { + Self { inner: [None; 12] } + } + + fn find_next_free(&mut self) -> Result<&mut Option, &'static str> { + if let Some(x) = self.inner.iter_mut().find(|x| x.is_none()) { + return Ok(x); + } + + Err("Storage for mapping info exhausted") + } + + fn find_duplicate( + &mut self, + phys_region: &MemoryRegion, + ) -> Option<&mut MappingRecordEntry> { + self.inner + .iter_mut() + .filter(|x| x.is_some()) + .map(|x| x.as_mut().unwrap()) + .filter(|x| x.attribute_fields.mem_attributes == MemAttributes::Device) + .find(|x| { + if x.phys_start_addr != phys_region.start_addr() { + return false; + } + + if x.num_pages != phys_region.num_pages() { + return false; + } + + true + }) + } + + pub fn add( + &mut self, + name: &'static str, + virt_region: &MemoryRegion, + phys_region: &MemoryRegion, + attr: &AttributeFields, + ) -> Result<(), &'static str> { + let x = self.find_next_free()?; + + *x = Some(MappingRecordEntry::new( + name, + virt_region, + phys_region, + attr, + )); + Ok(()) + } + + pub fn print(&self) { + const KIB_RSHIFT: u32 = 10; // log2(1024). + const MIB_RSHIFT: u32 = 20; // log2(1024 * 1024). + + info!(" -------------------------------------------------------------------------------------------------------------------------------------------"); + info!( + " {:^44} {:^30} {:^7} {:^9} {:^35}", + "Virtual", "Physical", "Size", "Attr", "Entity" + ); + info!(" -------------------------------------------------------------------------------------------------------------------------------------------"); + + for i in self.inner.iter().flatten() { + let size = i.num_pages * bsp::memory::mmu::KernelGranule::SIZE; + let virt_start = i.virt_start_addr; + let virt_end_inclusive = virt_start + (size - 1); + let phys_start = i.phys_start_addr; + let phys_end_inclusive = phys_start + (size - 1); + + let (size, unit) = if (size >> MIB_RSHIFT) > 0 { + (size >> MIB_RSHIFT, "MiB") + } else if (size >> KIB_RSHIFT) > 0 { + (size >> KIB_RSHIFT, "KiB") + } else { + (size, "Byte") + }; + + let attr = match i.attribute_fields.mem_attributes { + MemAttributes::CacheableDRAM => "C", + MemAttributes::Device => "Dev", + }; + + let acc_p = match i.attribute_fields.acc_perms { + AccessPermissions::ReadOnly => "RO", + AccessPermissions::ReadWrite => "RW", + }; + + let xn = if i.attribute_fields.execute_never { + "XN" + } else { + "X" + }; + + info!( + " {}..{} --> {}..{} | \ + {: >3} {} | {: <3} {} {: <2} | {}", + virt_start, + virt_end_inclusive, + phys_start, + phys_end_inclusive, + size, + unit, + attr, + acc_p, + xn, + i.users[0].unwrap() + ); + + for k in i.users[1..].iter() { + if let Some(additional_user) = *k { + info!( + " | {}", + additional_user + ); + } + } + } + + info!(" -------------------------------------------------------------------------------------------------------------------------------------------"); + } +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- +use synchronization::interface::ReadWriteEx; + +/// Add an entry to the mapping info record. +pub fn kernel_add( + name: &'static str, + virt_region: &MemoryRegion, + phys_region: &MemoryRegion, + attr: &AttributeFields, +) -> Result<(), &'static str> { + KERNEL_MAPPING_RECORD.write(|mr| mr.add(name, virt_region, phys_region, attr)) +} + +pub fn kernel_find_and_insert_mmio_duplicate( + mmio_descriptor: &MMIODescriptor, + new_user: &'static str, +) -> Option> { + let phys_region: MemoryRegion = (*mmio_descriptor).into(); + + KERNEL_MAPPING_RECORD.write(|mr| { + let dup = mr.find_duplicate(&phys_region)?; + + if let Err(x) = dup.add_user(new_user) { + warn!("{}", x); + } + + Some(dup.virt_start_addr) + }) +} + +/// Human-readable print of all recorded kernel mappings. +pub fn kernel_print() { + KERNEL_MAPPING_RECORD.read(|mr| mr.print()); +} diff --git a/17_kernel_symbols/kernel/src/memory/mmu/translation_table.rs b/17_kernel_symbols/kernel/src/memory/mmu/translation_table.rs new file mode 100644 index 00000000..9d627f97 --- /dev/null +++ b/17_kernel_symbols/kernel/src/memory/mmu/translation_table.rs @@ -0,0 +1,137 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2021-2022 Andre Richter + +//! Translation table. + +#[cfg(target_arch = "aarch64")] +#[path = "../../_arch/aarch64/memory/mmu/translation_table.rs"] +mod arch_translation_table; + +use super::{AttributeFields, MemoryRegion}; +use crate::memory::{Address, Physical, Virtual}; + +//-------------------------------------------------------------------------------------------------- +// Architectural Public Reexports +//-------------------------------------------------------------------------------------------------- +#[cfg(target_arch = "aarch64")] +pub use arch_translation_table::FixedSizeTranslationTable; + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +/// Translation table interfaces. +pub mod interface { + use crate::memory::mmu::PageAddress; + + use super::*; + + /// Translation table operations. + pub trait TranslationTable { + /// Anything that needs to run before any of the other provided functions can be used. + /// + /// # Safety + /// + /// - Implementor must ensure that this function can run only once or is harmless if invoked + /// multiple times. + fn init(&mut self) -> Result<(), &'static str>; + + /// Map the given virtual memory region to the given physical memory region. + /// + /// # Safety + /// + /// - Using wrong attributes can cause multiple issues of different nature in the system. + /// - It is not required that the architectural implementation prevents aliasing. That is, + /// mapping to the same physical memory using multiple virtual addresses, which would + /// break Rust's ownership assumptions. This should be protected against in the kernel's + /// generic MMU code. + unsafe fn map_at( + &mut self, + virt_region: &MemoryRegion, + phys_region: &MemoryRegion, + attr: &AttributeFields, + ) -> Result<(), &'static str>; + + /// Try to translate a virtual page address to a physical page address. + /// + /// Will only succeed if there exists a valid mapping for the input page. + fn try_virt_page_addr_to_phys_page_addr( + &self, + virt_page_addr: PageAddress, + ) -> Result, &'static str>; + + /// Try to get the attributes of a page. + /// + /// Will only succeed if there exists a valid mapping for the input page. + fn try_page_attributes( + &self, + virt_page_addr: PageAddress, + ) -> Result; + + /// Try to translate a virtual address to a physical address. + /// + /// Will only succeed if there exists a valid mapping for the input address. + fn try_virt_addr_to_phys_addr( + &self, + virt_addr: Address, + ) -> Result, &'static str>; + } +} + +//-------------------------------------------------------------------------------------------------- +// Testing +//-------------------------------------------------------------------------------------------------- + +#[cfg(test)] +mod tests { + use super::*; + use crate::memory::mmu::{AccessPermissions, MemAttributes, PageAddress}; + use arch_translation_table::MinSizeTranslationTable; + use interface::TranslationTable; + use test_macros::kernel_test; + + /// Sanity checks for the TranslationTable implementation. + #[kernel_test] + fn translationtable_implementation_sanity() { + // This will occupy a lot of space on the stack. + let mut tables = MinSizeTranslationTable::new_for_runtime(); + + assert!(tables.init().is_ok()); + + let virt_end_exclusive_page_addr: PageAddress = PageAddress::MAX; + let virt_start_page_addr: PageAddress = + virt_end_exclusive_page_addr.checked_offset(-5).unwrap(); + + let phys_start_page_addr: PageAddress = PageAddress::from(0); + let phys_end_exclusive_page_addr: PageAddress = + phys_start_page_addr.checked_offset(5).unwrap(); + + let virt_region = MemoryRegion::new(virt_start_page_addr, virt_end_exclusive_page_addr); + let phys_region = MemoryRegion::new(phys_start_page_addr, phys_end_exclusive_page_addr); + + let attr = AttributeFields { + mem_attributes: MemAttributes::CacheableDRAM, + acc_perms: AccessPermissions::ReadWrite, + execute_never: true, + }; + + unsafe { assert_eq!(tables.map_at(&virt_region, &phys_region, &attr), Ok(())) }; + + assert_eq!( + tables.try_virt_page_addr_to_phys_page_addr(virt_start_page_addr), + Ok(phys_start_page_addr) + ); + + assert_eq!( + tables.try_page_attributes(virt_start_page_addr.checked_offset(-1).unwrap()), + Err("Page marked invalid") + ); + + assert_eq!(tables.try_page_attributes(virt_start_page_addr), Ok(attr)); + + let virt_addr = virt_start_page_addr.into_inner() + 0x100; + let phys_addr = phys_start_page_addr.into_inner() + 0x100; + assert_eq!(tables.try_virt_addr_to_phys_addr(virt_addr), Ok(phys_addr)); + } +} diff --git a/17_kernel_symbols/kernel/src/memory/mmu/types.rs b/17_kernel_symbols/kernel/src/memory/mmu/types.rs new file mode 100644 index 00000000..85c852b3 --- /dev/null +++ b/17_kernel_symbols/kernel/src/memory/mmu/types.rs @@ -0,0 +1,378 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2020-2022 Andre Richter + +//! Memory Management Unit types. + +use crate::{ + bsp, common, + memory::{Address, AddressType, Physical}, +}; +use core::{convert::From, iter::Step, num::NonZeroUsize, ops::Range}; + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +/// A wrapper type around [Address] that ensures page alignment. +#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)] +pub struct PageAddress { + inner: Address, +} + +/// A type that describes a region of memory in quantities of pages. +#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)] +pub struct MemoryRegion { + start: PageAddress, + end_exclusive: PageAddress, +} + +/// Architecture agnostic memory attributes. +#[allow(missing_docs)] +#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)] +pub enum MemAttributes { + CacheableDRAM, + Device, +} + +/// Architecture agnostic access permissions. +#[allow(missing_docs)] +#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)] +pub enum AccessPermissions { + ReadOnly, + ReadWrite, +} + +/// Collection of memory attributes. +#[allow(missing_docs)] +#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)] +pub struct AttributeFields { + pub mem_attributes: MemAttributes, + pub acc_perms: AccessPermissions, + pub execute_never: bool, +} + +/// An MMIO descriptor for use in device drivers. +#[derive(Copy, Clone)] +pub struct MMIODescriptor { + start_addr: Address, + end_addr_exclusive: Address, +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +//------------------------------------------------------------------------------ +// PageAddress +//------------------------------------------------------------------------------ +impl PageAddress { + /// The largest value that can be represented by this type. + pub const MAX: Self = PageAddress { + inner: Address::new(usize::MAX).align_down_page(), + }; + + /// Unwraps the value. + pub fn into_inner(self) -> Address { + self.inner + } + + /// Calculates the offset from the page address. + /// + /// `count` is in units of [PageAddress]. For example, a count of 2 means `result = self + 2 * + /// page_size`. + pub fn checked_offset(self, count: isize) -> Option { + if count == 0 { + return Some(self); + } + + let delta = count + .unsigned_abs() + .checked_mul(bsp::memory::mmu::KernelGranule::SIZE)?; + let result = if count.is_positive() { + self.inner.as_usize().checked_add(delta)? + } else { + self.inner.as_usize().checked_sub(delta)? + }; + + Some(Self { + inner: Address::new(result), + }) + } +} + +impl From for PageAddress { + fn from(addr: usize) -> Self { + assert!( + common::is_aligned(addr, bsp::memory::mmu::KernelGranule::SIZE), + "Input usize not page aligned" + ); + + Self { + inner: Address::new(addr), + } + } +} + +impl From> for PageAddress { + fn from(addr: Address) -> Self { + assert!(addr.is_page_aligned(), "Input Address not page aligned"); + + Self { inner: addr } + } +} + +impl Step for PageAddress { + fn steps_between(start: &Self, end: &Self) -> Option { + if start > end { + return None; + } + + // Since start <= end, do unchecked arithmetic. + Some( + (end.inner.as_usize() - start.inner.as_usize()) + >> bsp::memory::mmu::KernelGranule::SHIFT, + ) + } + + fn forward_checked(start: Self, count: usize) -> Option { + start.checked_offset(count as isize) + } + + fn backward_checked(start: Self, count: usize) -> Option { + start.checked_offset(-(count as isize)) + } +} + +//------------------------------------------------------------------------------ +// MemoryRegion +//------------------------------------------------------------------------------ +impl MemoryRegion { + /// Create an instance. + pub fn new(start: PageAddress, end_exclusive: PageAddress) -> Self { + assert!(start <= end_exclusive); + + Self { + start, + end_exclusive, + } + } + + fn as_range(&self) -> Range> { + self.into_iter() + } + + /// Returns the start page address. + pub fn start_page_addr(&self) -> PageAddress { + self.start + } + + /// Returns the start address. + pub fn start_addr(&self) -> Address { + self.start.into_inner() + } + + /// Returns the exclusive end page address. + pub fn end_exclusive_page_addr(&self) -> PageAddress { + self.end_exclusive + } + + /// Returns the exclusive end page address. + pub fn end_inclusive_page_addr(&self) -> PageAddress { + self.end_exclusive.checked_offset(-1).unwrap() + } + + /// Checks if self contains an address. + pub fn contains(&self, addr: Address) -> bool { + let page_addr = PageAddress::from(addr.align_down_page()); + self.as_range().contains(&page_addr) + } + + /// Checks if there is an overlap with another memory region. + pub fn overlaps(&self, other_region: &Self) -> bool { + let self_range = self.as_range(); + + self_range.contains(&other_region.start_page_addr()) + || self_range.contains(&other_region.end_inclusive_page_addr()) + } + + /// Returns the number of pages contained in this region. + pub fn num_pages(&self) -> usize { + PageAddress::steps_between(&self.start, &self.end_exclusive).unwrap() + } + + /// Returns the size in bytes of this region. + pub fn size(&self) -> usize { + // Invariant: start <= end_exclusive, so do unchecked arithmetic. + let end_exclusive = self.end_exclusive.into_inner().as_usize(); + let start = self.start.into_inner().as_usize(); + + end_exclusive - start + } + + /// Splits the MemoryRegion like: + /// + /// -------------------------------------------------------------------------------- + /// | | | | | | | | | | | | | | | | | | | + /// -------------------------------------------------------------------------------- + /// ^ ^ ^ + /// | | | + /// left_start left_end_exclusive | + /// | + /// ^ | + /// | | + /// right_start right_end_exclusive + /// + /// Left region is returned to the caller. Right region is the new region for this struct. + pub fn take_first_n_pages(&mut self, num_pages: NonZeroUsize) -> Result { + let count: usize = num_pages.into(); + + let left_end_exclusive = self.start.checked_offset(count as isize); + let left_end_exclusive = match left_end_exclusive { + None => return Err("Overflow while calculating left_end_exclusive"), + Some(x) => x, + }; + + if left_end_exclusive > self.end_exclusive { + return Err("Not enough free pages"); + } + + let allocation = Self { + start: self.start, + end_exclusive: left_end_exclusive, + }; + self.start = left_end_exclusive; + + Ok(allocation) + } +} + +impl IntoIterator for MemoryRegion { + type Item = PageAddress; + type IntoIter = Range; + + fn into_iter(self) -> Self::IntoIter { + Range { + start: self.start, + end: self.end_exclusive, + } + } +} + +impl From for MemoryRegion { + fn from(desc: MMIODescriptor) -> Self { + let start = PageAddress::from(desc.start_addr.align_down_page()); + let end_exclusive = PageAddress::from(desc.end_addr_exclusive().align_up_page()); + + Self { + start, + end_exclusive, + } + } +} + +//------------------------------------------------------------------------------ +// MMIODescriptor +//------------------------------------------------------------------------------ + +impl MMIODescriptor { + /// Create an instance. + pub const fn new(start_addr: Address, size: usize) -> Self { + assert!(size > 0); + let end_addr_exclusive = Address::new(start_addr.as_usize() + size); + + Self { + start_addr, + end_addr_exclusive, + } + } + + /// Return the start address. + pub const fn start_addr(&self) -> Address { + self.start_addr + } + + /// Return the exclusive end address. + pub fn end_addr_exclusive(&self) -> Address { + self.end_addr_exclusive + } +} + +//-------------------------------------------------------------------------------------------------- +// Testing +//-------------------------------------------------------------------------------------------------- + +#[cfg(test)] +mod tests { + use super::*; + use crate::memory::Virtual; + use test_macros::kernel_test; + + /// Sanity of [PageAddress] methods. + #[kernel_test] + fn pageaddress_type_method_sanity() { + let page_addr: PageAddress = + PageAddress::from(bsp::memory::mmu::KernelGranule::SIZE * 2); + + assert_eq!( + page_addr.checked_offset(-2), + Some(PageAddress::::from(0)) + ); + + assert_eq!( + page_addr.checked_offset(2), + Some(PageAddress::::from( + bsp::memory::mmu::KernelGranule::SIZE * 4 + )) + ); + + assert_eq!( + PageAddress::::from(0).checked_offset(0), + Some(PageAddress::::from(0)) + ); + assert_eq!(PageAddress::::from(0).checked_offset(-1), None); + + let max_page_addr = Address::::new(usize::MAX).align_down_page(); + assert_eq!( + PageAddress::::from(max_page_addr).checked_offset(1), + None + ); + + let zero = PageAddress::::from(0); + let three = PageAddress::::from(bsp::memory::mmu::KernelGranule::SIZE * 3); + assert_eq!(PageAddress::steps_between(&zero, &three), Some(3)); + } + + /// Sanity of [MemoryRegion] methods. + #[kernel_test] + fn memoryregion_type_method_sanity() { + let zero = PageAddress::::from(0); + let zero_region = MemoryRegion::new(zero, zero); + assert_eq!(zero_region.num_pages(), 0); + assert_eq!(zero_region.size(), 0); + + let one = PageAddress::::from(bsp::memory::mmu::KernelGranule::SIZE); + let one_region = MemoryRegion::new(zero, one); + assert_eq!(one_region.num_pages(), 1); + assert_eq!(one_region.size(), bsp::memory::mmu::KernelGranule::SIZE); + + let three = PageAddress::::from(bsp::memory::mmu::KernelGranule::SIZE * 3); + let mut three_region = MemoryRegion::new(zero, three); + assert!(three_region.contains(zero.into_inner())); + assert!(!three_region.contains(three.into_inner())); + assert!(three_region.overlaps(&one_region)); + + let allocation = three_region + .take_first_n_pages(NonZeroUsize::new(2).unwrap()) + .unwrap(); + assert_eq!(allocation.num_pages(), 2); + assert_eq!(three_region.num_pages(), 1); + + for (i, alloc) in allocation.into_iter().enumerate() { + assert_eq!( + alloc.into_inner().as_usize(), + i * bsp::memory::mmu::KernelGranule::SIZE + ); + } + } +} diff --git a/17_kernel_symbols/kernel/src/panic_wait.rs b/17_kernel_symbols/kernel/src/panic_wait.rs new file mode 100644 index 00000000..08d7d453 --- /dev/null +++ b/17_kernel_symbols/kernel/src/panic_wait.rs @@ -0,0 +1,104 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2018-2022 Andre Richter + +//! A panic handler that infinitely waits. + +use crate::{bsp, cpu, exception}; +use core::{fmt, panic::PanicInfo}; + +//-------------------------------------------------------------------------------------------------- +// Private Code +//-------------------------------------------------------------------------------------------------- + +fn _panic_print(args: fmt::Arguments) { + use fmt::Write; + + unsafe { bsp::console::panic_console_out().write_fmt(args).unwrap() }; +} + +/// The point of exit for `libkernel`. +/// +/// It is linked weakly, so that the integration tests can overload its standard behavior. +#[linkage = "weak"] +#[no_mangle] +fn _panic_exit() -> ! { + #[cfg(not(feature = "test_build"))] + { + cpu::wait_forever() + } + + #[cfg(feature = "test_build")] + { + cpu::qemu_exit_failure() + } +} + +/// Prints with a newline - only use from the panic handler. +/// +/// Carbon copy from +#[macro_export] +macro_rules! panic_println { + ($($arg:tt)*) => ({ + _panic_print(format_args_nl!($($arg)*)); + }) +} + +/// Stop immediately if called a second time. +/// +/// # Note +/// +/// Using atomics here relieves us from needing to use `unsafe` for the static variable. +/// +/// On `AArch64`, which is the only implemented architecture at the time of writing this, +/// [`AtomicBool::load`] and [`AtomicBool::store`] are lowered to ordinary load and store +/// instructions. They are therefore safe to use even with MMU + caching deactivated. +/// +/// [`AtomicBool::load`]: core::sync::atomic::AtomicBool::load +/// [`AtomicBool::store`]: core::sync::atomic::AtomicBool::store +fn panic_prevent_reenter() { + use core::sync::atomic::{AtomicBool, Ordering}; + + #[cfg(not(target_arch = "aarch64"))] + compile_error!("Add the target_arch to above's check if the following code is safe to use"); + + static PANIC_IN_PROGRESS: AtomicBool = AtomicBool::new(false); + + if !PANIC_IN_PROGRESS.load(Ordering::Relaxed) { + PANIC_IN_PROGRESS.store(true, Ordering::Relaxed); + + return; + } + + _panic_exit() +} + +#[panic_handler] +fn panic(info: &PanicInfo) -> ! { + use crate::time::interface::TimeManager; + + unsafe { exception::asynchronous::local_irq_mask() }; + + // Protect against panic infinite loops if any of the following code panics itself. + panic_prevent_reenter(); + + let timestamp = crate::time::time_manager().uptime(); + let (location, line, column) = match info.location() { + Some(loc) => (loc.file(), loc.line(), loc.column()), + _ => ("???", 0, 0), + }; + + panic_println!( + "[ {:>3}.{:06}] Kernel panic!\n\n\ + Panic location:\n File '{}', line {}, column {}\n\n\ + {}", + timestamp.as_secs(), + timestamp.subsec_micros(), + location, + line, + column, + info.message().unwrap_or(&format_args!("")), + ); + + _panic_exit() +} diff --git a/17_kernel_symbols/kernel/src/print.rs b/17_kernel_symbols/kernel/src/print.rs new file mode 100644 index 00000000..9ec13a28 --- /dev/null +++ b/17_kernel_symbols/kernel/src/print.rs @@ -0,0 +1,94 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2018-2022 Andre Richter + +//! Printing. + +use crate::{bsp, console}; +use core::fmt; + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +#[doc(hidden)] +pub fn _print(args: fmt::Arguments) { + use console::interface::Write; + + bsp::console::console().write_fmt(args).unwrap(); +} + +/// Prints without a newline. +/// +/// Carbon copy from +#[macro_export] +macro_rules! print { + ($($arg:tt)*) => ($crate::print::_print(format_args!($($arg)*))); +} + +/// Prints with a newline. +/// +/// Carbon copy from +#[macro_export] +macro_rules! println { + () => ($crate::print!("\n")); + ($($arg:tt)*) => ({ + $crate::print::_print(format_args_nl!($($arg)*)); + }) +} + +/// Prints an info, with a newline. +#[macro_export] +macro_rules! info { + ($string:expr) => ({ + use $crate::time::interface::TimeManager; + + let timestamp = $crate::time::time_manager().uptime(); + + $crate::print::_print(format_args_nl!( + concat!("[ {:>3}.{:06}] ", $string), + timestamp.as_secs(), + timestamp.subsec_micros(), + )); + }); + ($format_string:expr, $($arg:tt)*) => ({ + use $crate::time::interface::TimeManager; + + let timestamp = $crate::time::time_manager().uptime(); + + $crate::print::_print(format_args_nl!( + concat!("[ {:>3}.{:06}] ", $format_string), + timestamp.as_secs(), + timestamp.subsec_micros(), + $($arg)* + )); + }) +} + +/// Prints a warning, with a newline. +#[macro_export] +macro_rules! warn { + ($string:expr) => ({ + use $crate::time::interface::TimeManager; + + let timestamp = $crate::time::time_manager().uptime(); + + $crate::print::_print(format_args_nl!( + concat!("[W {:>3}.{:06}] ", $string), + timestamp.as_secs(), + timestamp.subsec_micros(), + )); + }); + ($format_string:expr, $($arg:tt)*) => ({ + use $crate::time::interface::TimeManager; + + let timestamp = $crate::time::time_manager().uptime(); + + $crate::print::_print(format_args_nl!( + concat!("[W {:>3}.{:06}] ", $format_string), + timestamp.as_secs(), + timestamp.subsec_micros(), + $($arg)* + )); + }) +} diff --git a/17_kernel_symbols/kernel/src/state.rs b/17_kernel_symbols/kernel/src/state.rs new file mode 100644 index 00000000..0af3688c --- /dev/null +++ b/17_kernel_symbols/kernel/src/state.rs @@ -0,0 +1,92 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2020-2022 Andre Richter + +//! State information about the kernel itself. + +use core::sync::atomic::{AtomicU8, Ordering}; + +//-------------------------------------------------------------------------------------------------- +// Private Definitions +//-------------------------------------------------------------------------------------------------- + +/// Different stages in the kernel execution. +#[derive(Copy, Clone, Eq, PartialEq)] +enum State { + /// The kernel starts booting in this state. + Init, + + /// The kernel transitions to this state when jumping to `kernel_main()` (at the end of + /// `kernel_init()`, after all init calls are done). + SingleCoreMain, + + /// The kernel transitions to this state when it boots the secondary cores, aka switches + /// exectution mode to symmetric multiprocessing (SMP). + MultiCoreMain, +} + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +/// Maintains the kernel state and state transitions. +pub struct StateManager(AtomicU8); + +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +static STATE_MANAGER: StateManager = StateManager::new(); + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +/// Return a reference to the global StateManager. +pub fn state_manager() -> &'static StateManager { + &STATE_MANAGER +} + +impl StateManager { + const INIT: u8 = 0; + const SINGLE_CORE_MAIN: u8 = 1; + const MULTI_CORE_MAIN: u8 = 2; + + /// Create a new instance. + pub const fn new() -> Self { + Self(AtomicU8::new(Self::INIT)) + } + + /// Return the current state. + fn state(&self) -> State { + let state = self.0.load(Ordering::Acquire); + + match state { + Self::INIT => State::Init, + Self::SINGLE_CORE_MAIN => State::SingleCoreMain, + Self::MULTI_CORE_MAIN => State::MultiCoreMain, + _ => panic!("Invalid KERNEL_STATE"), + } + } + + /// Return if the kernel is init state. + pub fn is_init(&self) -> bool { + self.state() == State::Init + } + + /// Transition from Init to SingleCoreMain. + pub fn transition_to_single_core_main(&self) { + if self + .0 + .compare_exchange( + Self::INIT, + Self::SINGLE_CORE_MAIN, + Ordering::Acquire, + Ordering::Relaxed, + ) + .is_err() + { + panic!("transition_to_single_core_main() called while state != Init"); + } + } +} diff --git a/17_kernel_symbols/kernel/src/symbols.rs b/17_kernel_symbols/kernel/src/symbols.rs new file mode 100644 index 00000000..bde40a60 --- /dev/null +++ b/17_kernel_symbols/kernel/src/symbols.rs @@ -0,0 +1,85 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2022 Andre Richter + +//! Debug symbol support. + +use crate::memory::{Address, Virtual}; +use core::{cell::UnsafeCell, slice}; +use debug_symbol_types::Symbol; + +//-------------------------------------------------------------------------------------------------- +// Private Definitions +//-------------------------------------------------------------------------------------------------- + +// Symbol from the linker script. +extern "Rust" { + static __kernel_symbols_start: UnsafeCell<()>; +} + +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +/// This will be patched to the correct value by the "kernel symbols tool" after linking. This given +/// value here is just a (safe) dummy. +#[no_mangle] +static NUM_KERNEL_SYMBOLS: u64 = 0; + +//-------------------------------------------------------------------------------------------------- +// Private Code +//-------------------------------------------------------------------------------------------------- + +fn kernel_symbol_section_virt_start_addr() -> Address { + Address::new(unsafe { __kernel_symbols_start.get() as usize }) +} + +fn kernel_symbols_slice() -> &'static [Symbol] { + let ptr = kernel_symbol_section_virt_start_addr().as_usize() as *const Symbol; + + unsafe { + let num = core::ptr::read_volatile(&NUM_KERNEL_SYMBOLS as *const u64) as usize; + slice::from_raw_parts(ptr, num) + } +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +/// Retrieve the symbol name corresponding to a virtual address, if any. +pub fn lookup_symbol(addr: Address) -> Option<&'static str> { + for i in kernel_symbols_slice() { + if i.contains(addr.as_usize()) { + return Some(i.name()); + } + } + + None +} + +//-------------------------------------------------------------------------------------------------- +// Testing +//-------------------------------------------------------------------------------------------------- + +#[cfg(test)] +mod tests { + use super::*; + use test_macros::kernel_test; + + /// Sanity of symbols module. + #[kernel_test] + fn symbols_sanity() { + let first_sym = lookup_symbol(Address::new( + crate::common::is_aligned as *const usize as usize, + )) + .unwrap(); + + assert_eq!(first_sym, "libkernel::common::is_aligned"); + + let second_sym = + lookup_symbol(Address::new(crate::version as *const usize as usize)).unwrap(); + + assert_eq!(second_sym, "libkernel::version"); + } +} diff --git a/17_kernel_symbols/kernel/src/synchronization.rs b/17_kernel_symbols/kernel/src/synchronization.rs new file mode 100644 index 00000000..4b4c4c3f --- /dev/null +++ b/17_kernel_symbols/kernel/src/synchronization.rs @@ -0,0 +1,159 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2020-2022 Andre Richter + +//! Synchronization primitives. +//! +//! # Resources +//! +//! - +//! - +//! - + +use core::cell::UnsafeCell; + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +/// Synchronization interfaces. +pub mod interface { + + /// Any object implementing this trait guarantees exclusive access to the data wrapped within + /// the Mutex for the duration of the provided closure. + pub trait Mutex { + /// The type of the data that is wrapped by this mutex. + type Data; + + /// Locks the mutex and grants the closure temporary mutable access to the wrapped data. + fn lock(&self, f: impl FnOnce(&mut Self::Data) -> R) -> R; + } + + /// A reader-writer exclusion type. + /// + /// The implementing object allows either a number of readers or at most one writer at any point + /// in time. + pub trait ReadWriteEx { + /// The type of encapsulated data. + type Data; + + /// Grants temporary mutable access to the encapsulated data. + fn write(&self, f: impl FnOnce(&mut Self::Data) -> R) -> R; + + /// Grants temporary immutable access to the encapsulated data. + fn read(&self, f: impl FnOnce(&Self::Data) -> R) -> R; + } +} + +/// A pseudo-lock for teaching purposes. +/// +/// In contrast to a real Mutex implementation, does not protect against concurrent access from +/// other cores to the contained data. This part is preserved for later lessons. +/// +/// The lock will only be used as long as it is safe to do so, i.e. as long as the kernel is +/// executing on a single core. +pub struct IRQSafeNullLock +where + T: ?Sized, +{ + data: UnsafeCell, +} + +/// A pseudo-lock that is RW during the single-core kernel init phase and RO afterwards. +/// +/// Intended to encapsulate data that is populated during kernel init when no concurrency exists. +pub struct InitStateLock +where + T: ?Sized, +{ + data: UnsafeCell, +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +unsafe impl Send for IRQSafeNullLock where T: ?Sized + Send {} +unsafe impl Sync for IRQSafeNullLock where T: ?Sized + Send {} + +impl IRQSafeNullLock { + /// Create an instance. + pub const fn new(data: T) -> Self { + Self { + data: UnsafeCell::new(data), + } + } +} + +unsafe impl Send for InitStateLock where T: ?Sized + Send {} +unsafe impl Sync for InitStateLock where T: ?Sized + Send {} + +impl InitStateLock { + /// Create an instance. + pub const fn new(data: T) -> Self { + Self { + data: UnsafeCell::new(data), + } + } +} + +//------------------------------------------------------------------------------ +// OS Interface Code +//------------------------------------------------------------------------------ +use crate::{exception, state}; + +impl interface::Mutex for IRQSafeNullLock { + type Data = T; + + fn lock(&self, f: impl FnOnce(&mut Self::Data) -> R) -> R { + // In a real lock, there would be code encapsulating this line that ensures that this + // mutable reference will ever only be given out once at a time. + let data = unsafe { &mut *self.data.get() }; + + // Execute the closure while IRQs are masked. + exception::asynchronous::exec_with_irq_masked(|| f(data)) + } +} + +impl interface::ReadWriteEx for InitStateLock { + type Data = T; + + fn write(&self, f: impl FnOnce(&mut Self::Data) -> R) -> R { + assert!( + state::state_manager().is_init(), + "InitStateLock::write called after kernel init phase" + ); + assert!( + !exception::asynchronous::is_local_irq_masked(), + "InitStateLock::write called with IRQs unmasked" + ); + + let data = unsafe { &mut *self.data.get() }; + + f(data) + } + + fn read(&self, f: impl FnOnce(&Self::Data) -> R) -> R { + let data = unsafe { &*self.data.get() }; + + f(data) + } +} + +//-------------------------------------------------------------------------------------------------- +// Testing +//-------------------------------------------------------------------------------------------------- + +#[cfg(test)] +mod tests { + use super::*; + use test_macros::kernel_test; + + /// InitStateLock must be transparent. + #[kernel_test] + fn init_state_lock_is_transparent() { + use core::mem::size_of; + + assert_eq!(size_of::>(), size_of::()); + } +} diff --git a/17_kernel_symbols/kernel/src/time.rs b/17_kernel_symbols/kernel/src/time.rs new file mode 100644 index 00000000..6d92b196 --- /dev/null +++ b/17_kernel_symbols/kernel/src/time.rs @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2020-2022 Andre Richter + +//! Timer primitives. + +#[cfg(target_arch = "aarch64")] +#[path = "_arch/aarch64/time.rs"] +mod arch_time; + +//-------------------------------------------------------------------------------------------------- +// Architectural Public Reexports +//-------------------------------------------------------------------------------------------------- +pub use arch_time::time_manager; + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +/// Timekeeping interfaces. +pub mod interface { + use core::time::Duration; + + /// Time management functions. + pub trait TimeManager { + /// The timer's resolution. + fn resolution(&self) -> Duration; + + /// The uptime since power-on of the device. + /// + /// This includes time consumed by firmware and bootloaders. + fn uptime(&self) -> Duration; + + /// Spin for a given duration. + fn spin_for(&self, duration: Duration); + } +} diff --git a/17_kernel_symbols/kernel/tests/00_console_sanity.rb b/17_kernel_symbols/kernel/tests/00_console_sanity.rb new file mode 100644 index 00000000..4dde5576 --- /dev/null +++ b/17_kernel_symbols/kernel/tests/00_console_sanity.rb @@ -0,0 +1,48 @@ +# frozen_string_literal: true + +# SPDX-License-Identifier: MIT OR Apache-2.0 +# +# Copyright (c) 2019-2022 Andre Richter + +require 'console_io_test' + +# Verify sending and receiving works as expected. +class TxRxHandshakeTest < SubtestBase + def name + 'Transmit and Receive handshake' + end + + def run(qemu_out, qemu_in) + qemu_in.write_nonblock('ABC') + expect_or_raise(qemu_out, 'OK1234') + end +end + +# Check for correct TX statistics implementation. Depends on test 1 being run first. +class TxStatisticsTest < SubtestBase + def name + 'Transmit statistics' + end + + def run(qemu_out, _qemu_in) + expect_or_raise(qemu_out, '6') + end +end + +# Check for correct RX statistics implementation. Depends on test 1 being run first. +class RxStatisticsTest < SubtestBase + def name + 'Receive statistics' + end + + def run(qemu_out, _qemu_in) + expect_or_raise(qemu_out, '3') + end +end + +##-------------------------------------------------------------------------------------------------- +## Test registration +##-------------------------------------------------------------------------------------------------- +def subtest_collection + [TxRxHandshakeTest.new, TxStatisticsTest.new, RxStatisticsTest.new] +end diff --git a/17_kernel_symbols/kernel/tests/00_console_sanity.rs b/17_kernel_symbols/kernel/tests/00_console_sanity.rs new file mode 100644 index 00000000..6595aac1 --- /dev/null +++ b/17_kernel_symbols/kernel/tests/00_console_sanity.rs @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2019-2022 Andre Richter + +//! Console sanity tests - RX, TX and statistics. + +#![feature(format_args_nl)] +#![no_main] +#![no_std] + +/// Console tests should time out on the I/O harness in case of panic. +mod panic_wait_forever; + +use libkernel::{bsp, console, cpu, exception, memory, print}; + +#[no_mangle] +unsafe fn kernel_init() -> ! { + use bsp::console::console; + use console::interface::*; + + exception::handling_init(); + memory::mmu::post_enable_init(); + bsp::console::qemu_bring_up_console(); + + // Handshake + assert_eq!(console().read_char(), 'A'); + assert_eq!(console().read_char(), 'B'); + assert_eq!(console().read_char(), 'C'); + print!("OK1234"); + + // 6 + print!("{}", console().chars_written()); + + // 3 + print!("{}", console().chars_read()); + + // The QEMU process running this test will be closed by the I/O test harness. + cpu::wait_forever(); +} diff --git a/17_kernel_symbols/kernel/tests/01_timer_sanity.rs b/17_kernel_symbols/kernel/tests/01_timer_sanity.rs new file mode 100644 index 00000000..9b2b228d --- /dev/null +++ b/17_kernel_symbols/kernel/tests/01_timer_sanity.rs @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2019-2022 Andre Richter + +//! Timer sanity tests. + +#![feature(custom_test_frameworks)] +#![no_main] +#![no_std] +#![reexport_test_harness_main = "test_main"] +#![test_runner(libkernel::test_runner)] + +use core::time::Duration; +use libkernel::{bsp, cpu, exception, memory, time, time::interface::TimeManager}; +use test_macros::kernel_test; + +#[no_mangle] +unsafe fn kernel_init() -> ! { + exception::handling_init(); + memory::mmu::post_enable_init(); + bsp::console::qemu_bring_up_console(); + + // Depending on CPU arch, some timer bring-up code could go here. Not needed for the RPi. + + test_main(); + + cpu::qemu_exit_success() +} + +/// Simple check that the timer is running. +#[kernel_test] +fn timer_is_counting() { + assert!(time::time_manager().uptime().as_nanos() > 0) +} + +/// Timer resolution must be sufficient. +#[kernel_test] +fn timer_resolution_is_sufficient() { + assert!(time::time_manager().resolution().as_nanos() < 100) +} + +/// Sanity check spin_for() implementation. +#[kernel_test] +fn spin_accuracy_check_1_second() { + let t1 = time::time_manager().uptime(); + time::time_manager().spin_for(Duration::from_secs(1)); + let t2 = time::time_manager().uptime(); + + assert_eq!((t2 - t1).as_secs(), 1) +} diff --git a/17_kernel_symbols/kernel/tests/02_exception_sync_page_fault.rs b/17_kernel_symbols/kernel/tests/02_exception_sync_page_fault.rs new file mode 100644 index 00000000..0d2a1e63 --- /dev/null +++ b/17_kernel_symbols/kernel/tests/02_exception_sync_page_fault.rs @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2019-2022 Andre Richter + +//! Page faults must result in synchronous exceptions. + +#![feature(format_args_nl)] +#![no_main] +#![no_std] + +/// Overwrites libkernel's `panic_wait::_panic_exit()` so that it returns a "success" code. +/// +/// In this test, reaching the panic is a success, because it is called from the synchronous +/// exception handler, which is what this test wants to achieve. +/// +/// It also means that this integration test can not use any other code that calls panic!() directly +/// or indirectly. +mod panic_exit_success; + +use libkernel::{bsp, cpu, exception, info, memory, println}; + +#[no_mangle] +unsafe fn kernel_init() -> ! { + exception::handling_init(); + memory::mmu::post_enable_init(); + bsp::console::qemu_bring_up_console(); + + // This line will be printed as the test header. + println!("Testing synchronous exception handling by causing a page fault"); + + info!("Writing to bottom of address space to address 1 GiB..."); + let big_addr: u64 = 1024 * 1024 * 1024; + core::ptr::read_volatile(big_addr as *mut u64); + + // If execution reaches here, the memory access above did not cause a page fault exception. + cpu::qemu_exit_failure() +} diff --git a/17_kernel_symbols/kernel/tests/03_exception_restore_sanity.rb b/17_kernel_symbols/kernel/tests/03_exception_restore_sanity.rb new file mode 100644 index 00000000..5f52e0c7 --- /dev/null +++ b/17_kernel_symbols/kernel/tests/03_exception_restore_sanity.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +# SPDX-License-Identifier: MIT OR Apache-2.0 +# +# Copyright (c) 2022 Andre Richter + +require 'console_io_test' + +# Verify that exception restore works. +class ExceptionRestoreTest < SubtestBase + def name + 'Exception restore' + end + + def run(qemu_out, _qemu_in) + expect_or_raise(qemu_out, 'Back from system call!') + end +end + +##-------------------------------------------------------------------------------------------------- +## Test registration +##-------------------------------------------------------------------------------------------------- +def subtest_collection + [ExceptionRestoreTest.new] +end diff --git a/17_kernel_symbols/kernel/tests/03_exception_restore_sanity.rs b/17_kernel_symbols/kernel/tests/03_exception_restore_sanity.rs new file mode 100644 index 00000000..983d488f --- /dev/null +++ b/17_kernel_symbols/kernel/tests/03_exception_restore_sanity.rs @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2022 Andre Richter + +//! A simple sanity test to see if exception restore code works. + +#![feature(format_args_nl)] +#![no_main] +#![no_std] + +/// Console tests should time out on the I/O harness in case of panic. +mod panic_wait_forever; + +use core::arch::asm; +use libkernel::{bsp, cpu, exception, info, memory, println}; + +#[inline(never)] +fn nested_system_call() { + #[cfg(target_arch = "aarch64")] + unsafe { + asm!("svc #0x1337", options(nomem, nostack, preserves_flags)); + } + + #[cfg(not(target_arch = "aarch64"))] + { + info!("Not supported yet"); + cpu::wait_forever(); + } +} + +#[no_mangle] +unsafe fn kernel_init() -> ! { + exception::handling_init(); + memory::mmu::post_enable_init(); + bsp::console::qemu_bring_up_console(); + + // This line will be printed as the test header. + println!("Testing exception restore"); + + info!("Making a dummy system call"); + + // Calling this inside a function indirectly tests if the link register is restored properly. + nested_system_call(); + + info!("Back from system call!"); + + // The QEMU process running this test will be closed by the I/O test harness. + cpu::wait_forever(); +} diff --git a/17_kernel_symbols/kernel/tests/04_exception_irq_sanity.rs b/17_kernel_symbols/kernel/tests/04_exception_irq_sanity.rs new file mode 100644 index 00000000..9030424d --- /dev/null +++ b/17_kernel_symbols/kernel/tests/04_exception_irq_sanity.rs @@ -0,0 +1,67 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2020-2022 Andre Richter + +//! IRQ handling sanity tests. + +#![feature(custom_test_frameworks)] +#![no_main] +#![no_std] +#![reexport_test_harness_main = "test_main"] +#![test_runner(libkernel::test_runner)] + +use libkernel::{bsp, cpu, exception, memory}; +use test_macros::kernel_test; + +#[no_mangle] +unsafe fn kernel_init() -> ! { + memory::mmu::post_enable_init(); + bsp::console::qemu_bring_up_console(); + + exception::handling_init(); + exception::asynchronous::local_irq_unmask(); + + test_main(); + + cpu::qemu_exit_success() +} + +/// Check that IRQ masking works. +#[kernel_test] +fn local_irq_mask_works() { + // Precondition: IRQs are unmasked. + assert!(exception::asynchronous::is_local_irq_masked()); + + unsafe { exception::asynchronous::local_irq_mask() }; + assert!(!exception::asynchronous::is_local_irq_masked()); + + // Restore earlier state. + unsafe { exception::asynchronous::local_irq_unmask() }; +} + +/// Check that IRQ unmasking works. +#[kernel_test] +fn local_irq_unmask_works() { + // Precondition: IRQs are masked. + unsafe { exception::asynchronous::local_irq_mask() }; + assert!(!exception::asynchronous::is_local_irq_masked()); + + unsafe { exception::asynchronous::local_irq_unmask() }; + assert!(exception::asynchronous::is_local_irq_masked()); +} + +/// Check that IRQ mask save is saving "something". +#[kernel_test] +fn local_irq_mask_save_works() { + // Precondition: IRQs are unmasked. + assert!(exception::asynchronous::is_local_irq_masked()); + + let first = unsafe { exception::asynchronous::local_irq_mask_save() }; + assert!(!exception::asynchronous::is_local_irq_masked()); + + let second = unsafe { exception::asynchronous::local_irq_mask_save() }; + assert_ne!(first, second); + + unsafe { exception::asynchronous::local_irq_restore(first) }; + assert!(exception::asynchronous::is_local_irq_masked()); +} diff --git a/17_kernel_symbols/kernel/tests/boot_test_string.rb b/17_kernel_symbols/kernel/tests/boot_test_string.rb new file mode 100644 index 00000000..f778b3d8 --- /dev/null +++ b/17_kernel_symbols/kernel/tests/boot_test_string.rb @@ -0,0 +1,3 @@ +# frozen_string_literal: true + +EXPECTED_PRINT = 'Echoing input now' diff --git a/17_kernel_symbols/kernel/tests/panic_exit_success/mod.rs b/17_kernel_symbols/kernel/tests/panic_exit_success/mod.rs new file mode 100644 index 00000000..908fac51 --- /dev/null +++ b/17_kernel_symbols/kernel/tests/panic_exit_success/mod.rs @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2019-2022 Andre Richter + +/// Overwrites libkernel's `panic_wait::_panic_exit()` with the QEMU-exit version. +#[no_mangle] +fn _panic_exit() -> ! { + libkernel::cpu::qemu_exit_success() +} diff --git a/17_kernel_symbols/kernel/tests/panic_wait_forever/mod.rs b/17_kernel_symbols/kernel/tests/panic_wait_forever/mod.rs new file mode 100644 index 00000000..7a4effa5 --- /dev/null +++ b/17_kernel_symbols/kernel/tests/panic_wait_forever/mod.rs @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2022 Andre Richter + +/// Overwrites libkernel's `panic_wait::_panic_exit()` with wait_forever. +#[no_mangle] +fn _panic_exit() -> ! { + libkernel::cpu::wait_forever() +} diff --git a/17_kernel_symbols/kernel_symbols.mk b/17_kernel_symbols/kernel_symbols.mk new file mode 100644 index 00000000..5b51ccfe --- /dev/null +++ b/17_kernel_symbols/kernel_symbols.mk @@ -0,0 +1,103 @@ +## SPDX-License-Identifier: MIT OR Apache-2.0 +## +## Copyright (c) 2018-2022 Andre Richter + +include ../common/format.mk +include ../common/docker.mk + +##-------------------------------------------------------------------------------------------------- +## Check for input variables that need be exported by the calling Makefile +##-------------------------------------------------------------------------------------------------- +ifndef KERNEL_SYMBOLS_TOOL_PATH +$(error KERNEL_SYMBOLS_TOOL_PATH is not set) +endif + +ifndef TARGET +$(error TARGET is not set) +endif + +ifndef KERNEL_SYMBOLS_INPUT_ELF +$(error KERNEL_SYMBOLS_INPUT_ELF is not set) +endif + +ifndef KERNEL_SYMBOLS_OUTPUT_ELF +$(error KERNEL_SYMBOLS_OUTPUT_ELF is not set) +endif + + + +##-------------------------------------------------------------------------------------------------- +## Targets and Prerequisites +##-------------------------------------------------------------------------------------------------- +KERNEL_SYMBOLS_MANIFEST = kernel_symbols/Cargo.toml +KERNEL_SYMBOLS_LINKER_SCRIPT = kernel_symbols/kernel_symbols.ld + +KERNEL_SYMBOLS_RS = $(KERNEL_SYMBOLS_INPUT_ELF)_symbols.rs +KERNEL_SYMBOLS_DEMANGLED_RS = $(shell pwd)/$(KERNEL_SYMBOLS_INPUT_ELF)_symbols_demangled.rs + +KERNEL_SYMBOLS_ELF = target/$(TARGET)/release/kernel_symbols +KERNEL_SYMBOLS_STRIPPED = target/$(TARGET)/release/kernel_symbols_stripped + +# Export for build.rs of kernel_symbols crate. +export KERNEL_SYMBOLS_DEMANGLED_RS + + + +##-------------------------------------------------------------------------------------------------- +## Command building blocks +##-------------------------------------------------------------------------------------------------- +GET_SYMBOLS_SECTION_VIRT_ADDR = $(DOCKER_TOOLS) $(EXEC_SYMBOLS_TOOL) \ + --get_symbols_section_virt_addr $(KERNEL_SYMBOLS_OUTPUT_ELF) + +RUSTFLAGS = -C link-arg=--script=$(KERNEL_SYMBOLS_LINKER_SCRIPT) \ + -C link-arg=--section-start=.rodata=$$($(GET_SYMBOLS_SECTION_VIRT_ADDR)) + +RUSTFLAGS_PEDANTIC = $(RUSTFLAGS) \ + -D warnings \ + -D missing_docs + +COMPILER_ARGS = --target=$(TARGET) \ + --release + +RUSTC_CMD = cargo rustc $(COMPILER_ARGS) --manifest-path $(KERNEL_SYMBOLS_MANIFEST) +OBJCOPY_CMD = rust-objcopy \ + --strip-all \ + -O binary + +EXEC_SYMBOLS_TOOL = ruby $(KERNEL_SYMBOLS_TOOL_PATH)/main.rb + +##------------------------------------------------------------------------------ +## Dockerization +##------------------------------------------------------------------------------ +DOCKER_CMD = docker run -t --rm -v $(shell pwd):/work/tutorial -w /work/tutorial + +# DOCKER_IMAGE defined in include file (see top of this file). +DOCKER_TOOLS = $(DOCKER_CMD) $(DOCKER_IMAGE) + + + +##-------------------------------------------------------------------------------------------------- +## Targets +##-------------------------------------------------------------------------------------------------- +.PHONY: all + +all: + @cp $(KERNEL_SYMBOLS_INPUT_ELF) $(KERNEL_SYMBOLS_OUTPUT_ELF) + + @$(DOCKER_TOOLS) $(EXEC_SYMBOLS_TOOL) --gen_symbols $(KERNEL_SYMBOLS_OUTPUT_ELF) \ + $(KERNEL_SYMBOLS_RS) + + $(call color_progress_prefix, "Demangling") + @echo Symbol names + @cat $(KERNEL_SYMBOLS_RS) | rustfilt > $(KERNEL_SYMBOLS_DEMANGLED_RS) + + @RUSTFLAGS="$(RUSTFLAGS_PEDANTIC)" $(RUSTC_CMD) + + $(call color_progress_prefix, "Stripping") + @echo Symbols ELF file + @$(OBJCOPY_CMD) $(KERNEL_SYMBOLS_ELF) $(KERNEL_SYMBOLS_STRIPPED) + + @$(DOCKER_TOOLS) $(EXEC_SYMBOLS_TOOL) --patch_data $(KERNEL_SYMBOLS_OUTPUT_ELF) \ + $(KERNEL_SYMBOLS_STRIPPED) + + $(call color_progress_prefix, "Finished") diff --git a/17_kernel_symbols/kernel_symbols/Cargo.toml b/17_kernel_symbols/kernel_symbols/Cargo.toml new file mode 100644 index 00000000..3407aa7e --- /dev/null +++ b/17_kernel_symbols/kernel_symbols/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "kernel_symbols" +version = "0.1.0" +edition = "2021" + +[features] +default = [] +generated_symbols_available = [] + +##-------------------------------------------------------------------------------------------------- +## Dependencies +##-------------------------------------------------------------------------------------------------- + +[dependencies] +debug-symbol-types = { path = "../libraries/debug-symbol-types" } diff --git a/17_kernel_symbols/kernel_symbols/build.rs b/17_kernel_symbols/kernel_symbols/build.rs new file mode 100644 index 00000000..5062df44 --- /dev/null +++ b/17_kernel_symbols/kernel_symbols/build.rs @@ -0,0 +1,14 @@ +use std::{env, path::Path}; + +fn main() { + if let Ok(path) = env::var("KERNEL_SYMBOLS_DEMANGLED_RS") { + if Path::new(&path).exists() { + println!("cargo:rustc-cfg=feature=\"generated_symbols_available\"") + } + } + + println!( + "cargo:rerun-if-changed={}", + Path::new("kernel_symbols.ld").display() + ); +} diff --git a/17_kernel_symbols/kernel_symbols/kernel_symbols.ld b/17_kernel_symbols/kernel_symbols/kernel_symbols.ld new file mode 100644 index 00000000..0625f008 --- /dev/null +++ b/17_kernel_symbols/kernel_symbols/kernel_symbols.ld @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: MIT OR Apache-2.0 + * + * Copyright (c) 2022 Andre Richter + */ + +SECTIONS +{ + .rodata : { + ASSERT(. > 0xffffffff00000000, "Expected higher half address") + + KEEP(*(.rodata.symbol_desc*)) + . = ALIGN(8); + *(.rodata*) + } +} diff --git a/17_kernel_symbols/kernel_symbols/src/main.rs b/17_kernel_symbols/kernel_symbols/src/main.rs new file mode 100644 index 00000000..bd90b535 --- /dev/null +++ b/17_kernel_symbols/kernel_symbols/src/main.rs @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2022 Andre Richter + +//! Generation of kernel symbols. + +#![no_std] +#![no_main] + +#[cfg(feature = "generated_symbols_available")] +include!(env!("KERNEL_SYMBOLS_DEMANGLED_RS")); + +#[panic_handler] +fn panic(_info: &core::panic::PanicInfo) -> ! { + unimplemented!() +} diff --git a/17_kernel_symbols/libraries/debug-symbol-types/Cargo.toml b/17_kernel_symbols/libraries/debug-symbol-types/Cargo.toml new file mode 100644 index 00000000..e5b1fd1f --- /dev/null +++ b/17_kernel_symbols/libraries/debug-symbol-types/Cargo.toml @@ -0,0 +1,4 @@ +[package] +name = "debug-symbol-types" +version = "0.1.0" +edition = "2021" diff --git a/17_kernel_symbols/libraries/debug-symbol-types/src/lib.rs b/17_kernel_symbols/libraries/debug-symbol-types/src/lib.rs new file mode 100644 index 00000000..4c12e86f --- /dev/null +++ b/17_kernel_symbols/libraries/debug-symbol-types/src/lib.rs @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2022 Andre Richter + +//! Types for implementing debug symbol support. + +#![no_std] + +use core::ops::Range; + +/// A symbol containing a size. +#[repr(C)] +pub struct Symbol { + addr_range: Range, + name: &'static str, +} + +impl Symbol { + /// Create an instance. + pub const fn new(start: usize, size: usize, name: &'static str) -> Symbol { + Symbol { + addr_range: Range { + start, + end: start + size, + }, + name, + } + } + + /// Returns true if addr is contained in the range. + pub fn contains(&self, addr: usize) -> bool { + self.addr_range.contains(&addr) + } + + /// Returns the symbol's name. + pub fn name(&self) -> &'static str { + self.name + } +} diff --git a/17_kernel_symbols/libraries/test-macros/Cargo.toml b/17_kernel_symbols/libraries/test-macros/Cargo.toml new file mode 100644 index 00000000..fff98a1f --- /dev/null +++ b/17_kernel_symbols/libraries/test-macros/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "test-macros" +version = "0.1.0" +authors = ["Andre Richter "] +edition = "2021" + +[lib] +proc-macro = true + +[dependencies] +proc-macro2 = "1.x" +quote = "1.x" +syn = { version = "1.x", features = ["full"] } +test-types = { path = "../test-types" } diff --git a/17_kernel_symbols/libraries/test-macros/src/lib.rs b/17_kernel_symbols/libraries/test-macros/src/lib.rs new file mode 100644 index 00000000..9879677c --- /dev/null +++ b/17_kernel_symbols/libraries/test-macros/src/lib.rs @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2019-2022 Andre Richter + +use proc_macro::TokenStream; +use proc_macro2::Span; +use quote::quote; +use syn::{parse_macro_input, Ident, ItemFn}; + +#[proc_macro_attribute] +pub fn kernel_test(_attr: TokenStream, input: TokenStream) -> TokenStream { + let f = parse_macro_input!(input as ItemFn); + + let test_name = &format!("{}", f.sig.ident); + let test_ident = Ident::new( + &format!("{}_TEST_CONTAINER", f.sig.ident.to_string().to_uppercase()), + Span::call_site(), + ); + let test_code_block = f.block; + + quote!( + #[test_case] + const #test_ident: test_types::UnitTest = test_types::UnitTest { + name: #test_name, + test_func: || #test_code_block, + }; + ) + .into() +} diff --git a/17_kernel_symbols/libraries/test-types/Cargo.toml b/17_kernel_symbols/libraries/test-types/Cargo.toml new file mode 100644 index 00000000..2f20f060 --- /dev/null +++ b/17_kernel_symbols/libraries/test-types/Cargo.toml @@ -0,0 +1,5 @@ +[package] +name = "test-types" +version = "0.1.0" +authors = ["Andre Richter "] +edition = "2021" diff --git a/17_kernel_symbols/libraries/test-types/src/lib.rs b/17_kernel_symbols/libraries/test-types/src/lib.rs new file mode 100644 index 00000000..922c2a1c --- /dev/null +++ b/17_kernel_symbols/libraries/test-types/src/lib.rs @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2019-2022 Andre Richter + +//! Types for the `custom_test_frameworks` implementation. + +#![no_std] + +/// Unit test container. +pub struct UnitTest { + /// Name of the test. + pub name: &'static str, + + /// Function pointer to the test. + pub test_func: fn(), +} diff --git a/17_kernel_symbols/tools/kernel_symbols_tool/cmds.rb b/17_kernel_symbols/tools/kernel_symbols_tool/cmds.rb new file mode 100644 index 00000000..fe66ea71 --- /dev/null +++ b/17_kernel_symbols/tools/kernel_symbols_tool/cmds.rb @@ -0,0 +1,45 @@ +# frozen_string_literal: true + +# SPDX-License-Identifier: MIT OR Apache-2.0 +# +# Copyright (c) 2022 Andre Richter + +def generate_symbols(kernel_elf, output_file) + File.open(output_file, 'w') do |file| + header = <<~HEREDOC + use debug_symbol_types::Symbol; + + # [no_mangle] + # [link_section = ".rodata.symbol_desc"] + static KERNEL_SYMBOLS: [Symbol; #{kernel_elf.num_symbols}] = [ + HEREDOC + + file.write(header) + kernel_elf.symbols.each do |sym| + value = sym.header.st_value + size = sym.header.st_size + name = sym.name + + file.write(" Symbol::new(#{value}, #{size}, \"#{name}\"),\n") + end + file.write("];\n") + end +end + +def get_symbols_section_virt_addr(kernel_elf) + kernel_elf.kernel_symbols_section_virt_addr +end + +def patch_symbol_data(kernel_elf, symbols_blob_path) + symbols_blob = File.binread(symbols_blob_path) + + raise if symbols_blob.size > kernel_elf.kernel_symbols_section_size + + File.binwrite(kernel_elf.path, File.binread(symbols_blob_path), + kernel_elf.kernel_symbols_section_offset_in_file) +end + +def patch_num_symbols(kernel_elf) + num_packed = [kernel_elf.num_symbols].pack('Q<*') # "Q" == uint64_t, "<" == little endian + File.binwrite(kernel_elf.path, num_packed, kernel_elf.num_kernel_symbols_offset_in_file) +end diff --git a/17_kernel_symbols/tools/kernel_symbols_tool/kernel_elf.rb b/17_kernel_symbols/tools/kernel_symbols_tool/kernel_elf.rb new file mode 100644 index 00000000..b1649767 --- /dev/null +++ b/17_kernel_symbols/tools/kernel_symbols_tool/kernel_elf.rb @@ -0,0 +1,74 @@ +# frozen_string_literal: true + +# SPDX-License-Identifier: MIT OR Apache-2.0 +# +# Copyright (c) 2021-2022 Andre Richter + +# KernelELF +class KernelELF + attr_reader :path + + def initialize(kernel_elf_path, kernel_symbols_section, num_kernel_symbols) + @elf = ELFTools::ELFFile.new(File.open(kernel_elf_path)) + @symtab_section = @elf.section_by_name('.symtab') + + @path = kernel_elf_path + fetch_values(kernel_symbols_section, num_kernel_symbols) + end + + private + + def fetch_values(kernel_symbols_section, num_kernel_symbols) + sym = @symtab_section.symbol_by_name(num_kernel_symbols) + raise "Symbol \"#{num_kernel_symbols}\" not found" if sym.nil? + + @num_kernel_symbols = sym + + section = @elf.section_by_name(kernel_symbols_section) + raise "Section \"#{kernel_symbols_section}\" not found" if section.nil? + + @kernel_symbols_section = section + end + + def num_kernel_symbols_virt_addr + @num_kernel_symbols.header.st_value + end + + def segment_containing_virt_addr(virt_addr) + @elf.each_segments do |segment| + return segment if segment.vma_in?(virt_addr) + end + end + + def virt_addr_to_file_offset(virt_addr) + segment = segment_containing_virt_addr(virt_addr) + segment.vma_to_offset(virt_addr) + end + + public + + def symbols + non_zero_symbols = @symtab_section.symbols.reject { |sym| sym.header.st_size.zero? } + non_zero_symbols.sort_by { |sym| sym.header.st_value } + end + + def num_symbols + symbols.size + end + + def kernel_symbols_section_virt_addr + @kernel_symbols_section.header.sh_addr.to_i + end + + def kernel_symbols_section_size + @kernel_symbols_section.header.sh_size.to_i + end + + def kernel_symbols_section_offset_in_file + virt_addr_to_file_offset(kernel_symbols_section_virt_addr) + end + + def num_kernel_symbols_offset_in_file + virt_addr_to_file_offset(num_kernel_symbols_virt_addr) + end +end diff --git a/17_kernel_symbols/tools/kernel_symbols_tool/main.rb b/17_kernel_symbols/tools/kernel_symbols_tool/main.rb new file mode 100755 index 00000000..30a8be6f --- /dev/null +++ b/17_kernel_symbols/tools/kernel_symbols_tool/main.rb @@ -0,0 +1,47 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +# SPDX-License-Identifier: MIT OR Apache-2.0 +# +# Copyright (c) 2022 Andre Richter + +require 'rubygems' +require 'bundler/setup' +require 'colorize' +require 'elftools' + +require_relative 'kernel_elf' +require_relative 'cmds' + +KERNEL_SYMBOLS_SECTION = '.kernel_symbols' +NUM_KERNEL_SYMBOLS = 'NUM_KERNEL_SYMBOLS' + +cmd = ARGV[0] + +kernel_elf_path = ARGV[1] +kernel_elf = KernelELF.new(kernel_elf_path, KERNEL_SYMBOLS_SECTION, NUM_KERNEL_SYMBOLS) + +case cmd +when '--gen_symbols' + output_file = ARGV[2] + + print 'Generating'.rjust(12).green.bold + puts ' Symbols source file' + + generate_symbols(kernel_elf, output_file) +when '--get_symbols_section_virt_addr' + addr = get_symbols_section_virt_addr(kernel_elf) + + puts "0x#{addr.to_s(16)}" +when '--patch_data' + symbols_blob_path = ARGV[2] + num_symbols = kernel_elf.num_symbols + + print 'Patching'.rjust(12).green.bold + puts " Symbols blob and number of symbols (#{num_symbols}) into ELF" + + patch_symbol_data(kernel_elf, symbols_blob_path) + patch_num_symbols(kernel_elf) +else + raise +end diff --git a/17_kernel_symbols/tools/translation_table_tool/arch.rb b/17_kernel_symbols/tools/translation_table_tool/arch.rb new file mode 100644 index 00000000..deceb6d0 --- /dev/null +++ b/17_kernel_symbols/tools/translation_table_tool/arch.rb @@ -0,0 +1,314 @@ +# frozen_string_literal: true + +# SPDX-License-Identifier: MIT OR Apache-2.0 +# +# Copyright (c) 2021-2022 Andre Richter + +# Bitfield manipulation. +class BitField + def initialize + @value = 0 + end + + def self.attr_bitfield(name, offset, num_bits) + define_method("#{name}=") do |bits| + mask = (2**num_bits) - 1 + + raise "Input out of range: #{name} = 0x#{bits.to_s(16)}" if (bits & ~mask).positive? + + # Clear bitfield + @value &= ~(mask << offset) + + # Set it + @value |= (bits << offset) + end + end + + def to_i + @value + end + + def size_in_byte + 8 + end +end + +# An array class that knows its memory location. +class CArray < Array + attr_reader :phys_start_addr + + def initialize(phys_start_addr, size, &block) + @phys_start_addr = phys_start_addr + + super(size, &block) + end + + def size_in_byte + inject(0) { |sum, n| sum + n.size_in_byte } + end +end + +#--------------------------------------------------------------------------------------------------- +# Arch:: +#--------------------------------------------------------------------------------------------------- +module Arch +#--------------------------------------------------------------------------------------------------- +# Arch::ARMv8 +#--------------------------------------------------------------------------------------------------- +module ARMv8 +# ARMv8 Table Descriptor. +class Stage1TableDescriptor < BitField + module NextLevelTableAddr + OFFSET = 16 + NUMBITS = 32 + end + + module Type + OFFSET = 1 + NUMBITS = 1 + + BLOCK = 0 + TABLE = 1 + end + + module Valid + OFFSET = 0 + NUMBITS = 1 + + FALSE = 0 + TRUE = 1 + end + + attr_bitfield(:__next_level_table_addr, NextLevelTableAddr::OFFSET, NextLevelTableAddr::NUMBITS) + attr_bitfield(:type, Type::OFFSET, Type::NUMBITS) + attr_bitfield(:valid, Valid::OFFSET, Valid::NUMBITS) + + def next_level_table_addr=(addr) + addr = addr >> Granule64KiB::SHIFT + + self.__next_level_table_addr = addr + end + + private :__next_level_table_addr= +end + +# ARMv8 level 3 page descriptor. +class Stage1PageDescriptor < BitField + module UXN + OFFSET = 54 + NUMBITS = 1 + + FALSE = 0 + TRUE = 1 + end + + module PXN + OFFSET = 53 + NUMBITS = 1 + + FALSE = 0 + TRUE = 1 + end + + module OutputAddr + OFFSET = 16 + NUMBITS = 32 + end + + module AF + OFFSET = 10 + NUMBITS = 1 + + FALSE = 0 + TRUE = 1 + end + + module SH + OFFSET = 8 + NUMBITS = 2 + + INNER_SHAREABLE = 0b11 + end + + module AP + OFFSET = 6 + NUMBITS = 2 + + RW_EL1 = 0b00 + RO_EL1 = 0b10 + end + + module AttrIndx + OFFSET = 2 + NUMBITS = 3 + end + + module Type + OFFSET = 1 + NUMBITS = 1 + + RESERVED_INVALID = 0 + PAGE = 1 + end + + module Valid + OFFSET = 0 + NUMBITS = 1 + + FALSE = 0 + TRUE = 1 + end + + attr_bitfield(:uxn, UXN::OFFSET, UXN::NUMBITS) + attr_bitfield(:pxn, PXN::OFFSET, PXN::NUMBITS) + attr_bitfield(:__output_addr, OutputAddr::OFFSET, OutputAddr::NUMBITS) + attr_bitfield(:af, AF::OFFSET, AF::NUMBITS) + attr_bitfield(:sh, SH::OFFSET, SH::NUMBITS) + attr_bitfield(:ap, AP::OFFSET, AP::NUMBITS) + attr_bitfield(:attr_indx, AttrIndx::OFFSET, AttrIndx::NUMBITS) + attr_bitfield(:type, Type::OFFSET, Type::NUMBITS) + attr_bitfield(:valid, Valid::OFFSET, Valid::NUMBITS) + + def output_addr=(addr) + addr = addr >> Granule64KiB::SHIFT + + self.__output_addr = addr + end + + private :__output_addr= +end + +# Translation table representing the structure defined in translation_table.rs. +class TranslationTable + module MAIR + NORMAL = 1 + end + + def initialize + do_sanity_checks + + num_lvl2_tables = BSP.kernel_virt_addr_space_size >> Granule512MiB::SHIFT + + @lvl3 = new_lvl3(num_lvl2_tables, BSP.phys_addr_of_kernel_tables) + + @lvl2_phys_start_addr = @lvl3.phys_start_addr + @lvl3.size_in_byte + @lvl2 = new_lvl2(num_lvl2_tables, @lvl2_phys_start_addr) + + populate_lvl2_entries + end + + def map_at(virt_region, phys_region, attributes) + return if virt_region.empty? + + raise if virt_region.size != phys_region.size + raise if phys_region.last > BSP.phys_addr_space_end_page + + virt_region.zip(phys_region).each do |virt_page, phys_page| + desc = page_descriptor_from(virt_page) + set_lvl3_entry(desc, phys_page, attributes) + end + end + + def to_binary + data = @lvl3.flatten.map(&:to_i) + @lvl2.map(&:to_i) + data.pack('Q<*') # "Q" == uint64_t, "<" == little endian + end + + def phys_tables_base_addr_binary + [@lvl2_phys_start_addr].pack('Q<*') # "Q" == uint64_t, "<" == little endian + end + + def phys_tables_base_addr + @lvl2_phys_start_addr + end + + private + + def do_sanity_checks + raise unless BSP.kernel_granule::SIZE == Granule64KiB::SIZE + raise unless (BSP.kernel_virt_addr_space_size % Granule512MiB::SIZE).zero? + end + + def new_lvl3(num_lvl2_tables, start_addr) + CArray.new(start_addr, num_lvl2_tables) do + temp = CArray.new(start_addr, 8192) do + Stage1PageDescriptor.new + end + start_addr += temp.size_in_byte + + temp + end + end + + def new_lvl2(num_lvl2_tables, start_addr) + CArray.new(start_addr, num_lvl2_tables) do + Stage1TableDescriptor.new + end + end + + def populate_lvl2_entries + @lvl2.each_with_index do |descriptor, i| + descriptor.next_level_table_addr = @lvl3[i].phys_start_addr + descriptor.type = Stage1TableDescriptor::Type::TABLE + descriptor.valid = Stage1TableDescriptor::Valid::TRUE + end + end + + def lvl2_lvl3_index_from(addr) + addr -= BSP.kernel_virt_start_addr + + lvl2_index = addr >> Granule512MiB::SHIFT + lvl3_index = (addr & Granule512MiB::MASK) >> Granule64KiB::SHIFT + + raise unless lvl2_index < @lvl2.size + + [lvl2_index, lvl3_index] + end + + def page_descriptor_from(virt_addr) + lvl2_index, lvl3_index = lvl2_lvl3_index_from(virt_addr) + + @lvl3[lvl2_index][lvl3_index] + end + + # rubocop:disable Metrics/MethodLength + def set_attributes(desc, attributes) + case attributes.mem_attributes + when :CacheableDRAM + desc.sh = Stage1PageDescriptor::SH::INNER_SHAREABLE + desc.attr_indx = MAIR::NORMAL + else + raise 'Invalid input' + end + + desc.ap = case attributes.acc_perms + when :ReadOnly + Stage1PageDescriptor::AP::RO_EL1 + when :ReadWrite + Stage1PageDescriptor::AP::RW_EL1 + else + raise 'Invalid input' + + end + + desc.pxn = if attributes.execute_never + Stage1PageDescriptor::PXN::TRUE + else + Stage1PageDescriptor::PXN::FALSE + end + + desc.uxn = Stage1PageDescriptor::UXN::TRUE + end + # rubocop:enable Metrics/MethodLength + + def set_lvl3_entry(desc, output_addr, attributes) + desc.output_addr = output_addr + desc.af = Stage1PageDescriptor::AF::TRUE + desc.type = Stage1PageDescriptor::Type::PAGE + desc.valid = Stage1PageDescriptor::Valid::TRUE + + set_attributes(desc, attributes) + end +end +end +end diff --git a/17_kernel_symbols/tools/translation_table_tool/bsp.rb b/17_kernel_symbols/tools/translation_table_tool/bsp.rb new file mode 100644 index 00000000..536a2f21 --- /dev/null +++ b/17_kernel_symbols/tools/translation_table_tool/bsp.rb @@ -0,0 +1,50 @@ +# frozen_string_literal: true + +# SPDX-License-Identifier: MIT OR Apache-2.0 +# +# Copyright (c) 2021-2022 Andre Richter + +# Raspberry Pi 3 + 4 +class RaspberryPi + attr_reader :kernel_granule, :kernel_virt_addr_space_size, :kernel_virt_start_addr + + MEMORY_SRC = File.read('kernel/src/bsp/raspberrypi/memory.rs').split("\n") + + def initialize + @kernel_granule = Granule64KiB + + @kernel_virt_addr_space_size = KERNEL_ELF.symbol_value('__kernel_virt_addr_space_size') + @kernel_virt_start_addr = KERNEL_ELF.symbol_value('__kernel_virt_start_addr') + + @virt_addr_of_kernel_tables = KERNEL_ELF.symbol_value('KERNEL_TABLES') + @virt_addr_of_phys_kernel_tables_base_addr = KERNEL_ELF.symbol_value( + 'PHYS_KERNEL_TABLES_BASE_ADDR' + ) + end + + def phys_addr_of_kernel_tables + KERNEL_ELF.virt_to_phys(@virt_addr_of_kernel_tables) + end + + def kernel_tables_offset_in_file + KERNEL_ELF.virt_addr_to_file_offset(@virt_addr_of_kernel_tables) + end + + def phys_kernel_tables_base_addr_offset_in_file + KERNEL_ELF.virt_addr_to_file_offset(@virt_addr_of_phys_kernel_tables_base_addr) + end + + def phys_addr_space_end_page + x = MEMORY_SRC.grep(/pub const END/) + x = case BSP_TYPE + when :rpi3 + x[0] + when :rpi4 + x[1] + else + raise + end + + x.scan(/\d+/).join.to_i(16) + end +end diff --git a/17_kernel_symbols/tools/translation_table_tool/generic.rb b/17_kernel_symbols/tools/translation_table_tool/generic.rb new file mode 100644 index 00000000..13df0658 --- /dev/null +++ b/17_kernel_symbols/tools/translation_table_tool/generic.rb @@ -0,0 +1,179 @@ +# frozen_string_literal: true + +# SPDX-License-Identifier: MIT OR Apache-2.0 +# +# Copyright (c) 2021-2022 Andre Richter + +module Granule64KiB + SIZE = 64 * 1024 + SHIFT = Math.log2(SIZE).to_i +end + +module Granule512MiB + SIZE = 512 * 1024 * 1024 + SHIFT = Math.log2(SIZE).to_i + MASK = SIZE - 1 +end + +# Monkey-patch Integer with some helper functions. +class Integer + def power_of_two? + self[0].zero? + end + + def aligned?(alignment) + raise unless alignment.power_of_two? + + (self & (alignment - 1)).zero? + end + + def align_up(alignment) + raise unless alignment.power_of_two? + + (self + alignment - 1) & ~(alignment - 1) + end + + def to_hex_underscore(with_leading_zeros: false) + fmt = with_leading_zeros ? '%016x' : '%x' + value = format(fmt, self).to_s.reverse.scan(/.{4}|.+/).join('_').reverse + + format('0x%s', value) + end +end + +# An array where each value is the start address of a Page. +class MemoryRegion < Array + def initialize(start_addr, size, granule_size) + raise unless start_addr.aligned?(granule_size) + raise unless size.positive? + raise unless (size % granule_size).zero? + + num_pages = size / granule_size + super(num_pages) do |i| + (i * granule_size) + start_addr + end + end +end + +# Collection of memory attributes. +class AttributeFields + attr_reader :mem_attributes, :acc_perms, :execute_never + + def initialize(mem_attributes, acc_perms, execute_never) + @mem_attributes = mem_attributes + @acc_perms = acc_perms + @execute_never = execute_never + end + + def to_s + x = case @mem_attributes + when :CacheableDRAM + 'C' + else + '?' + end + + y = case @acc_perms + when :ReadWrite + 'RW' + when :ReadOnly + 'RO' + else + '??' + end + + z = @execute_never ? 'XN' : 'X ' + + "#{x} #{y} #{z}" + end +end + +# A container that describes a virt-to-phys region mapping. +class MappingDescriptor + @max_section_name_length = 'Sections'.length + + class << self + attr_accessor :max_section_name_length + + def update_max_section_name_length(length) + @max_section_name_length = [@max_section_name_length, length].max + end + end + + attr_reader :name, :virt_region, :phys_region, :attributes + + def initialize(name, virt_region, phys_region, attributes) + @name = name + @virt_region = virt_region + @phys_region = phys_region + @attributes = attributes + end + + def to_s + name = @name.ljust(self.class.max_section_name_length) + virt_start = @virt_region.first.to_hex_underscore(with_leading_zeros: true) + phys_start = @phys_region.first.to_hex_underscore(with_leading_zeros: true) + size = ((@virt_region.size * 65_536) / 1024).to_s.rjust(3) + + "#{name} | #{virt_start} | #{phys_start} | #{size} KiB | #{@attributes}" + end + + def self.print_divider + print ' ' + print '-' * max_section_name_length + puts '--------------------------------------------------------------------' + end + + def self.print_header + print_divider + print ' ' + print 'Sections'.center(max_section_name_length) + print ' ' + print 'Virt Start Addr'.center(21) + print ' ' + print 'Phys Start Addr'.center(21) + print ' ' + print 'Size'.center(7) + print ' ' + print 'Attr'.center(7) + puts + print_divider + end +end + +def kernel_map_binary + mapping_descriptors = KERNEL_ELF.generate_mapping_descriptors + + # Generate_mapping_descriptors updates the header being printed with this call. So it must come + # afterwards. + MappingDescriptor.print_header + + mapping_descriptors.each do |i| + print 'Generating'.rjust(12).green.bold + print ' ' + puts i.to_s + + TRANSLATION_TABLES.map_at(i.virt_region, i.phys_region, i.attributes) + end + + MappingDescriptor.print_divider +end + +def kernel_patch_tables(kernel_elf_path) + print 'Patching'.rjust(12).green.bold + print ' Kernel table struct at ELF file offset ' + puts BSP.kernel_tables_offset_in_file.to_hex_underscore + + File.binwrite(kernel_elf_path, TRANSLATION_TABLES.to_binary, BSP.kernel_tables_offset_in_file) +end + +def kernel_patch_base_addr(kernel_elf_path) + print 'Patching'.rjust(12).green.bold + print ' Kernel tables physical base address start argument to value ' + print TRANSLATION_TABLES.phys_tables_base_addr.to_hex_underscore + print ' at ELF file offset ' + puts BSP.phys_kernel_tables_base_addr_offset_in_file.to_hex_underscore + + File.binwrite(kernel_elf_path, TRANSLATION_TABLES.phys_tables_base_addr_binary, + BSP.phys_kernel_tables_base_addr_offset_in_file) +end diff --git a/17_kernel_symbols/tools/translation_table_tool/kernel_elf.rb b/17_kernel_symbols/tools/translation_table_tool/kernel_elf.rb new file mode 100644 index 00000000..f2d5b0b7 --- /dev/null +++ b/17_kernel_symbols/tools/translation_table_tool/kernel_elf.rb @@ -0,0 +1,96 @@ +# frozen_string_literal: true + +# SPDX-License-Identifier: MIT OR Apache-2.0 +# +# Copyright (c) 2021-2022 Andre Richter + +# KernelELF +class KernelELF + SECTION_FLAG_ALLOC = 2 + + def initialize(kernel_elf_path) + @elf = ELFTools::ELFFile.new(File.open(kernel_elf_path)) + @symtab_section = @elf.section_by_name('.symtab') + end + + def machine + @elf.machine.to_sym + end + + def symbol_value(symbol_name) + @symtab_section.symbol_by_name(symbol_name).header.st_value + end + + def segment_containing_virt_addr(virt_addr) + @elf.each_segments do |segment| + return segment if segment.vma_in?(virt_addr) + end + end + + def virt_to_phys(virt_addr) + segment = segment_containing_virt_addr(virt_addr) + translation_offset = segment.header.p_vaddr - segment.header.p_paddr + + virt_addr - translation_offset + end + + def virt_addr_to_file_offset(virt_addr) + segment = segment_containing_virt_addr(virt_addr) + segment.vma_to_offset(virt_addr) + end + + def sections_in_segment(segment) + head = segment.mem_head + tail = segment.mem_tail + + sections = @elf.each_sections.select do |section| + file_offset = section.header.sh_addr + flags = section.header.sh_flags + + file_offset >= head && file_offset < tail && (flags & SECTION_FLAG_ALLOC != 0) + end + + sections.map(&:name).join(' ') + end + + def select_load_segments + @elf.each_segments.select do |segment| + segment.instance_of?(ELFTools::Segments::LoadSegment) + end + end + + def segment_get_acc_perms(segment) + if segment.readable? && segment.writable? + :ReadWrite + elsif segment.readable? + :ReadOnly + else + :Invalid + end + end + + def update_max_section_name_length(descriptors) + MappingDescriptor.update_max_section_name_length(descriptors.map { |i| i.name.size }.max) + end + + def generate_mapping_descriptors + descriptors = select_load_segments.map do |segment| + # Assume each segment is page aligned. + size = segment.mem_size.align_up(BSP.kernel_granule::SIZE) + virt_start_addr = segment.header.p_vaddr + phys_start_addr = segment.header.p_paddr + acc_perms = segment_get_acc_perms(segment) + execute_never = !segment.executable? + section_names = sections_in_segment(segment) + + virt_region = MemoryRegion.new(virt_start_addr, size, BSP.kernel_granule::SIZE) + phys_region = MemoryRegion.new(phys_start_addr, size, BSP.kernel_granule::SIZE) + attributes = AttributeFields.new(:CacheableDRAM, acc_perms, execute_never) + + MappingDescriptor.new(section_names, virt_region, phys_region, attributes) + end + + update_max_section_name_length(descriptors) + descriptors + end +end diff --git a/17_kernel_symbols/tools/translation_table_tool/main.rb b/17_kernel_symbols/tools/translation_table_tool/main.rb new file mode 100755 index 00000000..6419e364 --- /dev/null +++ b/17_kernel_symbols/tools/translation_table_tool/main.rb @@ -0,0 +1,46 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +# SPDX-License-Identifier: MIT OR Apache-2.0 +# +# Copyright (c) 2021-2022 Andre Richter + +require 'rubygems' +require 'bundler/setup' +require 'colorize' +require 'elftools' + +require_relative 'generic' +require_relative 'kernel_elf' +require_relative 'bsp' +require_relative 'arch' + +BSP_TYPE = ARGV[0].to_sym +kernel_elf_path = ARGV[1] + +start = Time.now + +KERNEL_ELF = KernelELF.new(kernel_elf_path) + +BSP = case BSP_TYPE + when :rpi3, :rpi4 + RaspberryPi.new + else + raise + end + +TRANSLATION_TABLES = case KERNEL_ELF.machine + when :AArch64 + Arch::ARMv8::TranslationTable.new + else + raise + end + +kernel_map_binary +kernel_patch_tables(kernel_elf_path) +kernel_patch_base_addr(kernel_elf_path) + +elapsed = Time.now - start + +print 'Finished'.rjust(12).green.bold +puts " in #{elapsed.round(2)}s" From 73003ce8e6ec0a20e72eb9d8b51c6b947d67d9a1 Mon Sep 17 00:00:00 2001 From: Andre Richter Date: Mon, 25 Apr 2022 23:37:21 +0200 Subject: [PATCH 13/75] Actions: Add rustfilt and other fixes --- .github/workflows/build_rpi3.yml | 2 +- .github/workflows/build_rpi4.yml | 2 +- .github/workflows/test_integration.yml | 2 +- .github/workflows/test_unit.yml | 2 +- .github/workflows/test_xtra.yml | 2 +- utils/devtool.rb | 1 + 6 files changed, 6 insertions(+), 5 deletions(-) diff --git a/.github/workflows/build_rpi3.yml b/.github/workflows/build_rpi3.yml index d6dcfa3f..d974eebf 100644 --- a/.github/workflows/build_rpi3.yml +++ b/.github/workflows/build_rpi3.yml @@ -29,7 +29,7 @@ jobs: uses: ruby/setup-ruby@v1 - name: Set up Rust nightly run: | - cargo install cargo-binutils + cargo install cargo-binutils rustfilt - name: Set up Ruby run: | gem install bundler diff --git a/.github/workflows/build_rpi4.yml b/.github/workflows/build_rpi4.yml index de47cc83..68de1dc1 100644 --- a/.github/workflows/build_rpi4.yml +++ b/.github/workflows/build_rpi4.yml @@ -29,7 +29,7 @@ jobs: uses: ruby/setup-ruby@v1 - name: Set up Rust nightly run: | - cargo install cargo-binutils + cargo install cargo-binutils rustfilt - name: Set up Ruby run: | gem install bundler diff --git a/.github/workflows/test_integration.yml b/.github/workflows/test_integration.yml index 8c18c0a0..954d6432 100644 --- a/.github/workflows/test_integration.yml +++ b/.github/workflows/test_integration.yml @@ -29,7 +29,7 @@ jobs: uses: ruby/setup-ruby@v1 - name: Set up Rust nightly run: | - cargo install cargo-binutils + cargo install cargo-binutils rustfilt - name: Set up Ruby run: | gem install bundler diff --git a/.github/workflows/test_unit.yml b/.github/workflows/test_unit.yml index 624cf16d..c9a88892 100644 --- a/.github/workflows/test_unit.yml +++ b/.github/workflows/test_unit.yml @@ -29,7 +29,7 @@ jobs: uses: ruby/setup-ruby@v1 - name: Set up Rust nightly run: | - cargo install cargo-binutils + cargo install cargo-binutils rustfilt - name: Set up Ruby run: | gem install bundler diff --git a/.github/workflows/test_xtra.yml b/.github/workflows/test_xtra.yml index 97fa2081..a330ef74 100644 --- a/.github/workflows/test_xtra.yml +++ b/.github/workflows/test_xtra.yml @@ -37,4 +37,4 @@ jobs: bundle install --retry 3 - name: Make all run: | - bundle exec ruby utils/devtool.rb test_xtra + bundle exec ruby utils/devtool.rb make_xtra diff --git a/utils/devtool.rb b/utils/devtool.rb index 7c02e9ba..00417125 100755 --- a/utils/devtool.rb +++ b/utils/devtool.rb @@ -343,4 +343,5 @@ else puts puts 'Commands:' commands.each { |m| puts " #{m}" } + exit(1) end From 55499d0c61945d430dd2efebd11f847dcf08e9ae Mon Sep 17 00:00:00 2001 From: Andre Richter Date: Mon, 25 Apr 2022 23:52:13 +0200 Subject: [PATCH 14/75] Actions: Add boot tests --- .github/workflows/test_unit.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test_unit.yml b/.github/workflows/test_unit.yml index c9a88892..02de1b84 100644 --- a/.github/workflows/test_unit.yml +++ b/.github/workflows/test_unit.yml @@ -1,4 +1,4 @@ -name: Unit-Tests +name: Boot-and-Unit-Tests on: push: @@ -20,7 +20,7 @@ on: jobs: build: - name: Run unit tests + name: Run boot and unit tests runs-on: ubuntu-20.04 steps: @@ -37,4 +37,5 @@ jobs: bundle install --retry 3 - name: Make all run: | + bundle exec ruby utils/devtool.rb test_boot bundle exec ruby utils/devtool.rb test_unit From 66c68e3eb9480ac94f1eb714ba91df8d8db31e6c Mon Sep 17 00:00:00 2001 From: paulnice Date: Mon, 25 Apr 2022 23:18:22 -0700 Subject: [PATCH 15/75] Fix a typo --- 04_safe_globals/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/04_safe_globals/README.md b/04_safe_globals/README.md index b42be642..bfb2b4fa 100644 --- a/04_safe_globals/README.md +++ b/04_safe_globals/README.md @@ -177,7 +177,7 @@ diff -uNr 03_hacky_hello_world/src/bsp/raspberrypi/console.rs 04_safe_globals/sr +/// serialize access. +impl console::interface::Write for QEMUOutput { + fn write_fmt(&self, args: core::fmt::Arguments) -> fmt::Result { -+ // Fully qualified syntax for the call to `core::fmt::Write::write:fmt()` to increase ++ // Fully qualified syntax for the call to `core::fmt::Write::write_fmt()` to increase + // readability. + self.inner.lock(|inner| fmt::Write::write_fmt(inner, args)) + } From 9250099090c6028bb9f8bf43343330095e84ca3a Mon Sep 17 00:00:00 2001 From: Pavel Shirshov Date: Mon, 25 Apr 2022 23:54:32 -0700 Subject: [PATCH 16/75] Fix even more typos s/write:fmt/write_fmt/ --- 04_safe_globals/src/bsp/raspberrypi/console.rs | 2 +- 05_drivers_gpio_uart/README.md | 4 ++-- .../src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs | 2 +- .../src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs | 2 +- 07_timestamps/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs | 2 +- .../src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs | 2 +- .../src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs | 2 +- .../src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs | 2 +- .../src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs | 2 +- .../kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs | 2 +- .../kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs | 2 +- .../kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs | 2 +- .../kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs | 2 +- .../kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs | 2 +- .../kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs | 2 +- X1_JTAG_boot/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs | 2 +- 16 files changed, 17 insertions(+), 17 deletions(-) diff --git a/04_safe_globals/src/bsp/raspberrypi/console.rs b/04_safe_globals/src/bsp/raspberrypi/console.rs index f471cebb..774dbadb 100644 --- a/04_safe_globals/src/bsp/raspberrypi/console.rs +++ b/04_safe_globals/src/bsp/raspberrypi/console.rs @@ -103,7 +103,7 @@ use synchronization::interface::Mutex; /// serialize access. impl console::interface::Write for QEMUOutput { fn write_fmt(&self, args: core::fmt::Arguments) -> fmt::Result { - // Fully qualified syntax for the call to `core::fmt::Write::write:fmt()` to increase + // Fully qualified syntax for the call to `core::fmt::Write::write_fmt()` to increase // readability. self.inner.lock(|inner| fmt::Write::write_fmt(inner, args)) } diff --git a/05_drivers_gpio_uart/README.md b/05_drivers_gpio_uart/README.md index ccd4575e..3b6f38f3 100644 --- a/05_drivers_gpio_uart/README.md +++ b/05_drivers_gpio_uart/README.md @@ -831,7 +831,7 @@ diff -uNr 04_safe_globals/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs 05_dri + } + + fn write_fmt(&self, args: core::fmt::Arguments) -> fmt::Result { -+ // Fully qualified syntax for the call to `core::fmt::Write::write:fmt()` to increase ++ // Fully qualified syntax for the call to `core::fmt::Write::write_fmt()` to increase + // readability. + self.inner.lock(|inner| fmt::Write::write_fmt(inner, args)) + } @@ -1067,7 +1067,7 @@ diff -uNr 04_safe_globals/src/bsp/raspberrypi/console.rs 05_drivers_gpio_uart/sr -/// serialize access. -impl console::interface::Write for QEMUOutput { - fn write_fmt(&self, args: core::fmt::Arguments) -> fmt::Result { -- // Fully qualified syntax for the call to `core::fmt::Write::write:fmt()` to increase +- // Fully qualified syntax for the call to `core::fmt::Write::write_fmt()` to increase - // readability. - self.inner.lock(|inner| fmt::Write::write_fmt(inner, args)) - } diff --git a/05_drivers_gpio_uart/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs b/05_drivers_gpio_uart/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs index 878ea567..85cd3154 100644 --- a/05_drivers_gpio_uart/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs +++ b/05_drivers_gpio_uart/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs @@ -364,7 +364,7 @@ impl console::interface::Write for PL011Uart { } fn write_fmt(&self, args: core::fmt::Arguments) -> fmt::Result { - // Fully qualified syntax for the call to `core::fmt::Write::write:fmt()` to increase + // Fully qualified syntax for the call to `core::fmt::Write::write_fmt()` to increase // readability. self.inner.lock(|inner| fmt::Write::write_fmt(inner, args)) } diff --git a/06_uart_chainloader/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs b/06_uart_chainloader/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs index e6b4a952..7d66484b 100644 --- a/06_uart_chainloader/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs +++ b/06_uart_chainloader/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs @@ -359,7 +359,7 @@ impl console::interface::Write for PL011Uart { } fn write_fmt(&self, args: core::fmt::Arguments) -> fmt::Result { - // Fully qualified syntax for the call to `core::fmt::Write::write:fmt()` to increase + // Fully qualified syntax for the call to `core::fmt::Write::write_fmt()` to increase // readability. self.inner.lock(|inner| fmt::Write::write_fmt(inner, args)) } diff --git a/07_timestamps/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs b/07_timestamps/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs index 878ea567..85cd3154 100644 --- a/07_timestamps/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs +++ b/07_timestamps/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs @@ -364,7 +364,7 @@ impl console::interface::Write for PL011Uart { } fn write_fmt(&self, args: core::fmt::Arguments) -> fmt::Result { - // Fully qualified syntax for the call to `core::fmt::Write::write:fmt()` to increase + // Fully qualified syntax for the call to `core::fmt::Write::write_fmt()` to increase // readability. self.inner.lock(|inner| fmt::Write::write_fmt(inner, args)) } diff --git a/08_hw_debug_JTAG/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs b/08_hw_debug_JTAG/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs index 878ea567..85cd3154 100644 --- a/08_hw_debug_JTAG/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs +++ b/08_hw_debug_JTAG/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs @@ -364,7 +364,7 @@ impl console::interface::Write for PL011Uart { } fn write_fmt(&self, args: core::fmt::Arguments) -> fmt::Result { - // Fully qualified syntax for the call to `core::fmt::Write::write:fmt()` to increase + // Fully qualified syntax for the call to `core::fmt::Write::write_fmt()` to increase // readability. self.inner.lock(|inner| fmt::Write::write_fmt(inner, args)) } diff --git a/09_privilege_level/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs b/09_privilege_level/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs index 878ea567..85cd3154 100644 --- a/09_privilege_level/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs +++ b/09_privilege_level/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs @@ -364,7 +364,7 @@ impl console::interface::Write for PL011Uart { } fn write_fmt(&self, args: core::fmt::Arguments) -> fmt::Result { - // Fully qualified syntax for the call to `core::fmt::Write::write:fmt()` to increase + // Fully qualified syntax for the call to `core::fmt::Write::write_fmt()` to increase // readability. self.inner.lock(|inner| fmt::Write::write_fmt(inner, args)) } diff --git a/10_virtual_mem_part1_identity_mapping/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs b/10_virtual_mem_part1_identity_mapping/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs index 878ea567..85cd3154 100644 --- a/10_virtual_mem_part1_identity_mapping/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs +++ b/10_virtual_mem_part1_identity_mapping/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs @@ -364,7 +364,7 @@ impl console::interface::Write for PL011Uart { } fn write_fmt(&self, args: core::fmt::Arguments) -> fmt::Result { - // Fully qualified syntax for the call to `core::fmt::Write::write:fmt()` to increase + // Fully qualified syntax for the call to `core::fmt::Write::write_fmt()` to increase // readability. self.inner.lock(|inner| fmt::Write::write_fmt(inner, args)) } diff --git a/11_exceptions_part1_groundwork/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs b/11_exceptions_part1_groundwork/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs index 878ea567..85cd3154 100644 --- a/11_exceptions_part1_groundwork/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs +++ b/11_exceptions_part1_groundwork/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs @@ -364,7 +364,7 @@ impl console::interface::Write for PL011Uart { } fn write_fmt(&self, args: core::fmt::Arguments) -> fmt::Result { - // Fully qualified syntax for the call to `core::fmt::Write::write:fmt()` to increase + // Fully qualified syntax for the call to `core::fmt::Write::write_fmt()` to increase // readability. self.inner.lock(|inner| fmt::Write::write_fmt(inner, args)) } diff --git a/12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs b/12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs index 878ea567..85cd3154 100644 --- a/12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs +++ b/12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs @@ -364,7 +364,7 @@ impl console::interface::Write for PL011Uart { } fn write_fmt(&self, args: core::fmt::Arguments) -> fmt::Result { - // Fully qualified syntax for the call to `core::fmt::Write::write:fmt()` to increase + // Fully qualified syntax for the call to `core::fmt::Write::write_fmt()` to increase // readability. self.inner.lock(|inner| fmt::Write::write_fmt(inner, args)) } diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs index af573fd0..4d000ad5 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs @@ -441,7 +441,7 @@ impl console::interface::Write for PL011Uart { } fn write_fmt(&self, args: core::fmt::Arguments) -> fmt::Result { - // Fully qualified syntax for the call to `core::fmt::Write::write:fmt()` to increase + // Fully qualified syntax for the call to `core::fmt::Write::write_fmt()` to increase // readability. self.inner.lock(|inner| fmt::Write::write_fmt(inner, args)) } diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs index 23c09a7f..3133047b 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs @@ -477,7 +477,7 @@ impl console::interface::Write for PL011Uart { } fn write_fmt(&self, args: core::fmt::Arguments) -> fmt::Result { - // Fully qualified syntax for the call to `core::fmt::Write::write:fmt()` to increase + // Fully qualified syntax for the call to `core::fmt::Write::write_fmt()` to increase // readability. self.inner.lock(|inner| fmt::Write::write_fmt(inner, args)) } diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs index 23c09a7f..3133047b 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs @@ -477,7 +477,7 @@ impl console::interface::Write for PL011Uart { } fn write_fmt(&self, args: core::fmt::Arguments) -> fmt::Result { - // Fully qualified syntax for the call to `core::fmt::Write::write:fmt()` to increase + // Fully qualified syntax for the call to `core::fmt::Write::write_fmt()` to increase // readability. self.inner.lock(|inner| fmt::Write::write_fmt(inner, args)) } diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs index 23c09a7f..3133047b 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs @@ -477,7 +477,7 @@ impl console::interface::Write for PL011Uart { } fn write_fmt(&self, args: core::fmt::Arguments) -> fmt::Result { - // Fully qualified syntax for the call to `core::fmt::Write::write:fmt()` to increase + // Fully qualified syntax for the call to `core::fmt::Write::write_fmt()` to increase // readability. self.inner.lock(|inner| fmt::Write::write_fmt(inner, args)) } diff --git a/17_kernel_symbols/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs b/17_kernel_symbols/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs index 23c09a7f..3133047b 100644 --- a/17_kernel_symbols/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs +++ b/17_kernel_symbols/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs @@ -477,7 +477,7 @@ impl console::interface::Write for PL011Uart { } fn write_fmt(&self, args: core::fmt::Arguments) -> fmt::Result { - // Fully qualified syntax for the call to `core::fmt::Write::write:fmt()` to increase + // Fully qualified syntax for the call to `core::fmt::Write::write_fmt()` to increase // readability. self.inner.lock(|inner| fmt::Write::write_fmt(inner, args)) } diff --git a/X1_JTAG_boot/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs b/X1_JTAG_boot/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs index 878ea567..85cd3154 100644 --- a/X1_JTAG_boot/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs +++ b/X1_JTAG_boot/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs @@ -364,7 +364,7 @@ impl console::interface::Write for PL011Uart { } fn write_fmt(&self, args: core::fmt::Arguments) -> fmt::Result { - // Fully qualified syntax for the call to `core::fmt::Write::write:fmt()` to increase + // Fully qualified syntax for the call to `core::fmt::Write::write_fmt()` to increase // readability. self.inner.lock(|inner| fmt::Write::write_fmt(inner, args)) } From f4f02da28ed34fa679cfb2efa2bb3ea0c89b2507 Mon Sep 17 00:00:00 2001 From: Bryan Lee Date: Wed, 27 Apr 2022 01:13:00 +0800 Subject: [PATCH 17/75] chore: replace `git.io` link with the original URL --- .github/workflows/sanity.yml | 2 +- 01_wait_forever/src/main.rs | 2 +- 02_runtime_init/src/main.rs | 2 +- 03_hacky_hello_world/src/main.rs | 2 +- 04_safe_globals/src/main.rs | 2 +- 05_drivers_gpio_uart/src/main.rs | 2 +- 06_uart_chainloader/src/main.rs | 2 +- 07_timestamps/src/main.rs | 2 +- 08_hw_debug_JTAG/src/main.rs | 2 +- 09_privilege_level/src/main.rs | 2 +- 10_virtual_mem_part1_identity_mapping/src/main.rs | 2 +- 11_exceptions_part1_groundwork/src/main.rs | 2 +- 12_integrated_testing/kernel/src/lib.rs | 2 +- 12_integrated_testing/kernel/src/main.rs | 2 +- 13_exceptions_part2_peripheral_IRQs/kernel/src/lib.rs | 2 +- 13_exceptions_part2_peripheral_IRQs/kernel/src/main.rs | 2 +- 14_virtual_mem_part2_mmio_remap/kernel/src/lib.rs | 2 +- 14_virtual_mem_part2_mmio_remap/kernel/src/main.rs | 2 +- 15_virtual_mem_part3_precomputed_tables/kernel/src/lib.rs | 2 +- 15_virtual_mem_part3_precomputed_tables/kernel/src/main.rs | 2 +- 16_virtual_mem_part4_higher_half_kernel/kernel/src/lib.rs | 2 +- 16_virtual_mem_part4_higher_half_kernel/kernel/src/main.rs | 2 +- 17_kernel_symbols/kernel/src/lib.rs | 2 +- 17_kernel_symbols/kernel/src/main.rs | 2 +- X1_JTAG_boot/src/main.rs | 2 +- contributor_setup.sh | 2 +- 26 files changed, 26 insertions(+), 26 deletions(-) diff --git a/.github/workflows/sanity.yml b/.github/workflows/sanity.yml index 4f058992..a42198d7 100644 --- a/.github/workflows/sanity.yml +++ b/.github/workflows/sanity.yml @@ -34,7 +34,7 @@ jobs: npm install prettier - name: Setup misspell run: | - curl -L -o ./install-misspell.sh https://git.io/misspell + curl -L -o ./install-misspell.sh https://raw.githubusercontent.com/client9/misspell/master/install-misspell.sh sh ./install-misspell.sh -b .vendor - name: Run checks run: | diff --git a/01_wait_forever/src/main.rs b/01_wait_forever/src/main.rs index 4f405bec..30dd45e7 100644 --- a/01_wait_forever/src/main.rs +++ b/01_wait_forever/src/main.rs @@ -3,7 +3,7 @@ // Copyright (c) 2018-2022 Andre Richter // Rust embedded logo for `make doc`. -#![doc(html_logo_url = "https://git.io/JeGIp")] +#![doc(html_logo_url = "https://raw.githubusercontent.com/rust-embedded/wg/master/assets/logo/ewg-logo-blue-white-on-transparent.png")] //! The `kernel` binary. //! diff --git a/02_runtime_init/src/main.rs b/02_runtime_init/src/main.rs index 398c4a04..6b3b1efd 100644 --- a/02_runtime_init/src/main.rs +++ b/02_runtime_init/src/main.rs @@ -3,7 +3,7 @@ // Copyright (c) 2018-2022 Andre Richter // Rust embedded logo for `make doc`. -#![doc(html_logo_url = "https://git.io/JeGIp")] +#![doc(html_logo_url = "https://raw.githubusercontent.com/rust-embedded/wg/master/assets/logo/ewg-logo-blue-white-on-transparent.png")] //! The `kernel` binary. //! diff --git a/03_hacky_hello_world/src/main.rs b/03_hacky_hello_world/src/main.rs index da450139..ee9afd2a 100644 --- a/03_hacky_hello_world/src/main.rs +++ b/03_hacky_hello_world/src/main.rs @@ -3,7 +3,7 @@ // Copyright (c) 2018-2022 Andre Richter // Rust embedded logo for `make doc`. -#![doc(html_logo_url = "https://git.io/JeGIp")] +#![doc(html_logo_url = "https://raw.githubusercontent.com/rust-embedded/wg/master/assets/logo/ewg-logo-blue-white-on-transparent.png")] //! The `kernel` binary. //! diff --git a/04_safe_globals/src/main.rs b/04_safe_globals/src/main.rs index 450ae1ff..422dcf91 100644 --- a/04_safe_globals/src/main.rs +++ b/04_safe_globals/src/main.rs @@ -3,7 +3,7 @@ // Copyright (c) 2018-2022 Andre Richter // Rust embedded logo for `make doc`. -#![doc(html_logo_url = "https://git.io/JeGIp")] +#![doc(html_logo_url = "https://raw.githubusercontent.com/rust-embedded/wg/master/assets/logo/ewg-logo-blue-white-on-transparent.png")] //! The `kernel` binary. //! diff --git a/05_drivers_gpio_uart/src/main.rs b/05_drivers_gpio_uart/src/main.rs index 70e6b116..241d9498 100644 --- a/05_drivers_gpio_uart/src/main.rs +++ b/05_drivers_gpio_uart/src/main.rs @@ -3,7 +3,7 @@ // Copyright (c) 2018-2022 Andre Richter // Rust embedded logo for `make doc`. -#![doc(html_logo_url = "https://git.io/JeGIp")] +#![doc(html_logo_url = "https://raw.githubusercontent.com/rust-embedded/wg/master/assets/logo/ewg-logo-blue-white-on-transparent.png")] //! The `kernel` binary. //! diff --git a/06_uart_chainloader/src/main.rs b/06_uart_chainloader/src/main.rs index 32a56bda..79f8b0b3 100644 --- a/06_uart_chainloader/src/main.rs +++ b/06_uart_chainloader/src/main.rs @@ -3,7 +3,7 @@ // Copyright (c) 2018-2022 Andre Richter // Rust embedded logo for `make doc`. -#![doc(html_logo_url = "https://git.io/JeGIp")] +#![doc(html_logo_url = "https://raw.githubusercontent.com/rust-embedded/wg/master/assets/logo/ewg-logo-blue-white-on-transparent.png")] //! The `kernel` binary. //! diff --git a/07_timestamps/src/main.rs b/07_timestamps/src/main.rs index 3d4ace4f..c067d90c 100644 --- a/07_timestamps/src/main.rs +++ b/07_timestamps/src/main.rs @@ -3,7 +3,7 @@ // Copyright (c) 2018-2022 Andre Richter // Rust embedded logo for `make doc`. -#![doc(html_logo_url = "https://git.io/JeGIp")] +#![doc(html_logo_url = "https://raw.githubusercontent.com/rust-embedded/wg/master/assets/logo/ewg-logo-blue-white-on-transparent.png")] //! The `kernel` binary. //! diff --git a/08_hw_debug_JTAG/src/main.rs b/08_hw_debug_JTAG/src/main.rs index 3d4ace4f..c067d90c 100644 --- a/08_hw_debug_JTAG/src/main.rs +++ b/08_hw_debug_JTAG/src/main.rs @@ -3,7 +3,7 @@ // Copyright (c) 2018-2022 Andre Richter // Rust embedded logo for `make doc`. -#![doc(html_logo_url = "https://git.io/JeGIp")] +#![doc(html_logo_url = "https://raw.githubusercontent.com/rust-embedded/wg/master/assets/logo/ewg-logo-blue-white-on-transparent.png")] //! The `kernel` binary. //! diff --git a/09_privilege_level/src/main.rs b/09_privilege_level/src/main.rs index b4449734..45dba34c 100644 --- a/09_privilege_level/src/main.rs +++ b/09_privilege_level/src/main.rs @@ -3,7 +3,7 @@ // Copyright (c) 2018-2022 Andre Richter // Rust embedded logo for `make doc`. -#![doc(html_logo_url = "https://git.io/JeGIp")] +#![doc(html_logo_url = "https://raw.githubusercontent.com/rust-embedded/wg/master/assets/logo/ewg-logo-blue-white-on-transparent.png")] //! The `kernel` binary. //! diff --git a/10_virtual_mem_part1_identity_mapping/src/main.rs b/10_virtual_mem_part1_identity_mapping/src/main.rs index faa81ee8..148cdfff 100644 --- a/10_virtual_mem_part1_identity_mapping/src/main.rs +++ b/10_virtual_mem_part1_identity_mapping/src/main.rs @@ -3,7 +3,7 @@ // Copyright (c) 2018-2022 Andre Richter // Rust embedded logo for `make doc`. -#![doc(html_logo_url = "https://git.io/JeGIp")] +#![doc(html_logo_url = "https://raw.githubusercontent.com/rust-embedded/wg/master/assets/logo/ewg-logo-blue-white-on-transparent.png")] //! The `kernel` binary. //! diff --git a/11_exceptions_part1_groundwork/src/main.rs b/11_exceptions_part1_groundwork/src/main.rs index 77ffd9cd..5534750a 100644 --- a/11_exceptions_part1_groundwork/src/main.rs +++ b/11_exceptions_part1_groundwork/src/main.rs @@ -3,7 +3,7 @@ // Copyright (c) 2018-2022 Andre Richter // Rust embedded logo for `make doc`. -#![doc(html_logo_url = "https://git.io/JeGIp")] +#![doc(html_logo_url = "https://raw.githubusercontent.com/rust-embedded/wg/master/assets/logo/ewg-logo-blue-white-on-transparent.png")] //! The `kernel` binary. //! diff --git a/12_integrated_testing/kernel/src/lib.rs b/12_integrated_testing/kernel/src/lib.rs index 51f10d7c..1218e30e 100644 --- a/12_integrated_testing/kernel/src/lib.rs +++ b/12_integrated_testing/kernel/src/lib.rs @@ -3,7 +3,7 @@ // Copyright (c) 2018-2022 Andre Richter // Rust embedded logo for `make doc`. -#![doc(html_logo_url = "https://git.io/JeGIp")] +#![doc(html_logo_url = "https://raw.githubusercontent.com/rust-embedded/wg/master/assets/logo/ewg-logo-blue-white-on-transparent.png")] //! The `kernel` library. //! diff --git a/12_integrated_testing/kernel/src/main.rs b/12_integrated_testing/kernel/src/main.rs index 2c1bf9ac..dfbc1166 100644 --- a/12_integrated_testing/kernel/src/main.rs +++ b/12_integrated_testing/kernel/src/main.rs @@ -3,7 +3,7 @@ // Copyright (c) 2018-2022 Andre Richter // Rust embedded logo for `make doc`. -#![doc(html_logo_url = "https://git.io/JeGIp")] +#![doc(html_logo_url = "https://raw.githubusercontent.com/rust-embedded/wg/master/assets/logo/ewg-logo-blue-white-on-transparent.png")] //! The `kernel` binary. diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/lib.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/lib.rs index 6133f01a..9bd360c0 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/lib.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/lib.rs @@ -3,7 +3,7 @@ // Copyright (c) 2018-2022 Andre Richter // Rust embedded logo for `make doc`. -#![doc(html_logo_url = "https://git.io/JeGIp")] +#![doc(html_logo_url = "https://raw.githubusercontent.com/rust-embedded/wg/master/assets/logo/ewg-logo-blue-white-on-transparent.png")] //! The `kernel` library. //! diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/main.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/main.rs index 6729d45c..228b984b 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/main.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/main.rs @@ -3,7 +3,7 @@ // Copyright (c) 2018-2022 Andre Richter // Rust embedded logo for `make doc`. -#![doc(html_logo_url = "https://git.io/JeGIp")] +#![doc(html_logo_url = "https://raw.githubusercontent.com/rust-embedded/wg/master/assets/logo/ewg-logo-blue-white-on-transparent.png")] //! The `kernel` binary. diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/lib.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/lib.rs index 9ed0941c..2c874f18 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/lib.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/lib.rs @@ -3,7 +3,7 @@ // Copyright (c) 2018-2022 Andre Richter // Rust embedded logo for `make doc`. -#![doc(html_logo_url = "https://git.io/JeGIp")] +#![doc(html_logo_url = "https://raw.githubusercontent.com/rust-embedded/wg/master/assets/logo/ewg-logo-blue-white-on-transparent.png")] //! The `kernel` library. //! diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/main.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/main.rs index b891492a..68d34e35 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/main.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/main.rs @@ -3,7 +3,7 @@ // Copyright (c) 2018-2022 Andre Richter // Rust embedded logo for `make doc`. -#![doc(html_logo_url = "https://git.io/JeGIp")] +#![doc(html_logo_url = "https://raw.githubusercontent.com/rust-embedded/wg/master/assets/logo/ewg-logo-blue-white-on-transparent.png")] //! The `kernel` binary. diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/lib.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/lib.rs index 9ed0941c..2c874f18 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/lib.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/lib.rs @@ -3,7 +3,7 @@ // Copyright (c) 2018-2022 Andre Richter // Rust embedded logo for `make doc`. -#![doc(html_logo_url = "https://git.io/JeGIp")] +#![doc(html_logo_url = "https://raw.githubusercontent.com/rust-embedded/wg/master/assets/logo/ewg-logo-blue-white-on-transparent.png")] //! The `kernel` library. //! diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/main.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/main.rs index 8bc80885..c0c18818 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/main.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/main.rs @@ -3,7 +3,7 @@ // Copyright (c) 2018-2022 Andre Richter // Rust embedded logo for `make doc`. -#![doc(html_logo_url = "https://git.io/JeGIp")] +#![doc(html_logo_url = "https://raw.githubusercontent.com/rust-embedded/wg/master/assets/logo/ewg-logo-blue-white-on-transparent.png")] //! The `kernel` binary. diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/lib.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/lib.rs index 76cd3792..5ecc3a71 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/lib.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/lib.rs @@ -3,7 +3,7 @@ // Copyright (c) 2018-2022 Andre Richter // Rust embedded logo for `make doc`. -#![doc(html_logo_url = "https://git.io/JeGIp")] +#![doc(html_logo_url = "https://raw.githubusercontent.com/rust-embedded/wg/master/assets/logo/ewg-logo-blue-white-on-transparent.png")] //! The `kernel` library. //! diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/main.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/main.rs index 8bc80885..c0c18818 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/main.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/main.rs @@ -3,7 +3,7 @@ // Copyright (c) 2018-2022 Andre Richter // Rust embedded logo for `make doc`. -#![doc(html_logo_url = "https://git.io/JeGIp")] +#![doc(html_logo_url = "https://raw.githubusercontent.com/rust-embedded/wg/master/assets/logo/ewg-logo-blue-white-on-transparent.png")] //! The `kernel` binary. diff --git a/17_kernel_symbols/kernel/src/lib.rs b/17_kernel_symbols/kernel/src/lib.rs index 0178b272..68f7e874 100644 --- a/17_kernel_symbols/kernel/src/lib.rs +++ b/17_kernel_symbols/kernel/src/lib.rs @@ -3,7 +3,7 @@ // Copyright (c) 2018-2022 Andre Richter // Rust embedded logo for `make doc`. -#![doc(html_logo_url = "https://git.io/JeGIp")] +#![doc(html_logo_url = "https://raw.githubusercontent.com/rust-embedded/wg/master/assets/logo/ewg-logo-blue-white-on-transparent.png")] //! The `kernel` library. //! diff --git a/17_kernel_symbols/kernel/src/main.rs b/17_kernel_symbols/kernel/src/main.rs index 8bc80885..c0c18818 100644 --- a/17_kernel_symbols/kernel/src/main.rs +++ b/17_kernel_symbols/kernel/src/main.rs @@ -3,7 +3,7 @@ // Copyright (c) 2018-2022 Andre Richter // Rust embedded logo for `make doc`. -#![doc(html_logo_url = "https://git.io/JeGIp")] +#![doc(html_logo_url = "https://raw.githubusercontent.com/rust-embedded/wg/master/assets/logo/ewg-logo-blue-white-on-transparent.png")] //! The `kernel` binary. diff --git a/X1_JTAG_boot/src/main.rs b/X1_JTAG_boot/src/main.rs index 6e6cf909..d2f9dbde 100644 --- a/X1_JTAG_boot/src/main.rs +++ b/X1_JTAG_boot/src/main.rs @@ -3,7 +3,7 @@ // Copyright (c) 2018-2022 Andre Richter // Rust embedded logo for `make doc`. -#![doc(html_logo_url = "https://git.io/JeGIp")] +#![doc(html_logo_url = "https://raw.githubusercontent.com/rust-embedded/wg/master/assets/logo/ewg-logo-blue-white-on-transparent.png")] //! The `kernel` binary. //! diff --git a/contributor_setup.sh b/contributor_setup.sh index 8bad881f..8348b4d7 100755 --- a/contributor_setup.sh +++ b/contributor_setup.sh @@ -31,6 +31,6 @@ then echo "'curl' could not be found. Please install it." exit fi -curl -L -o ./install-misspell.sh https://git.io/misspell +curl -L -o ./install-misspell.sh https://raw.githubusercontent.com/client9/misspell/master/install-misspell.sh sh ./install-misspell.sh -b .vendor rm install-misspell.sh From 358bb729d90d33726b507d9900abf87793100f1b Mon Sep 17 00:00:00 2001 From: Andre Richter Date: Tue, 26 Apr 2022 20:12:22 +0200 Subject: [PATCH 18/75] Update pull_request_template.md --- .github/pull_request_template.md | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 98339970..c0c34d89 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -10,4 +10,5 @@ Related Issue: - Not needed if it is just a README change or similar. - [ ] Ran `./contributor_setup.sh` followed by `./devtool ready_for_publish` - You'll need `Ruby` with `Bundler` and `NPM` installed locally. + - If no Rust files were changed, `./devtool ready_for_publish_no_rust` can be used instead (faster). - This step is optional, but much appreciated if done. From a0cfe170a54508dfdc1a21e5234cda9721ae557e Mon Sep 17 00:00:00 2001 From: Andre Richter Date: Tue, 26 Apr 2022 20:13:00 +0200 Subject: [PATCH 19/75] Update pull_request_template.md --- .github/pull_request_template.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index c0c34d89..f6167fff 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -10,5 +10,5 @@ Related Issue: - Not needed if it is just a README change or similar. - [ ] Ran `./contributor_setup.sh` followed by `./devtool ready_for_publish` - You'll need `Ruby` with `Bundler` and `NPM` installed locally. - - If no Rust files were changed, `./devtool ready_for_publish_no_rust` can be used instead (faster). + - If no Rust-related files were changed, `./devtool ready_for_publish_no_rust` can be used instead (faster). - This step is optional, but much appreciated if done. From 8513ccfd8dc83e76997c4f83252452e495fbc17b Mon Sep 17 00:00:00 2001 From: Andre Richter Date: Wed, 27 Apr 2022 22:08:55 +0200 Subject: [PATCH 20/75] Various minor fixes --- 01_wait_forever/Makefile | 1 - 01_wait_forever/src/main.rs | 4 +- 02_runtime_init/Makefile | 1 - 02_runtime_init/README.md | 6 +- 02_runtime_init/src/main.rs | 4 +- 03_hacky_hello_world/Makefile | 1 - 03_hacky_hello_world/README.md | 8 +-- 03_hacky_hello_world/src/main.rs | 4 +- 04_safe_globals/Makefile | 1 - 04_safe_globals/README.md | 6 +- 04_safe_globals/src/main.rs | 4 +- 05_drivers_gpio_uart/Makefile | 1 - 05_drivers_gpio_uart/README.md | 12 ++-- 05_drivers_gpio_uart/src/main.rs | 4 +- 06_uart_chainloader/Makefile | 1 - 06_uart_chainloader/README.md | 14 ++--- 06_uart_chainloader/src/main.rs | 4 +- 07_timestamps/Makefile | 1 - 07_timestamps/README.md | 12 ++-- 07_timestamps/src/main.rs | 4 +- 08_hw_debug_JTAG/Makefile | 1 - 08_hw_debug_JTAG/README.md | 4 +- 08_hw_debug_JTAG/src/main.rs | 4 +- 09_privilege_level/Makefile | 1 - 09_privilege_level/README.md | 8 +-- 09_privilege_level/src/main.rs | 4 +- .../Makefile | 1 - .../README.md | 10 ++-- .../src/main.rs | 4 +- 11_exceptions_part1_groundwork/Makefile | 1 - 11_exceptions_part1_groundwork/README.md | 16 ++++-- .../src/_arch/aarch64/exception.rs | 2 +- .../src/_arch/aarch64/exception.s | 4 ++ 11_exceptions_part1_groundwork/src/main.rs | 4 +- 12_integrated_testing/Makefile | 1 - .../kernel/src/_arch/aarch64/exception.rs | 2 +- .../kernel/src/_arch/aarch64/exception.s | 4 ++ 12_integrated_testing/kernel/src/lib.rs | 4 +- 12_integrated_testing/kernel/src/main.rs | 4 +- 13_exceptions_part2_peripheral_IRQs/Makefile | 1 - 13_exceptions_part2_peripheral_IRQs/README.md | 12 ++-- .../kernel/src/_arch/aarch64/exception.rs | 2 +- .../kernel/src/_arch/aarch64/exception.s | 4 ++ .../kernel/src/lib.rs | 4 +- .../kernel/src/main.rs | 4 +- 14_virtual_mem_part2_mmio_remap/Makefile | 1 - 14_virtual_mem_part2_mmio_remap/README.md | 10 ++-- .../kernel/src/_arch/aarch64/exception.rs | 2 +- .../kernel/src/_arch/aarch64/exception.s | 4 ++ .../kernel/src/lib.rs | 4 +- .../kernel/src/main.rs | 4 +- .../Makefile | 1 - .../README.md | 10 ++-- .../kernel/src/_arch/aarch64/exception.rs | 2 +- .../kernel/src/_arch/aarch64/exception.s | 4 ++ .../kernel/src/lib.rs | 4 +- .../kernel/src/main.rs | 4 +- .../Makefile | 1 - .../README.md | 2 +- .../kernel/src/_arch/aarch64/exception.rs | 2 +- .../kernel/src/_arch/aarch64/exception.s | 4 ++ .../kernel/src/lib.rs | 4 +- .../kernel/src/main.rs | 4 +- 17_kernel_symbols/Makefile | 3 +- 17_kernel_symbols/README.md | 56 +++++++++++-------- .../kernel/src/_arch/aarch64/exception.rs | 8 ++- .../kernel/src/_arch/aarch64/exception.s | 4 ++ 17_kernel_symbols/kernel/src/lib.rs | 4 +- 17_kernel_symbols/kernel/src/main.rs | 4 +- 17_kernel_symbols/kernel/src/symbols.rs | 14 +++-- .../libraries/debug-symbol-types/src/lib.rs | 6 ++ X1_JTAG_boot/Makefile | 1 - X1_JTAG_boot/src/main.rs | 4 +- 73 files changed, 228 insertions(+), 142 deletions(-) diff --git a/01_wait_forever/Makefile b/01_wait_forever/Makefile index 7699e5f4..59884220 100644 --- a/01_wait_forever/Makefile +++ b/01_wait_forever/Makefile @@ -81,7 +81,6 @@ COMPILER_ARGS = --target=$(TARGET) \ RUSTC_CMD = cargo rustc $(COMPILER_ARGS) DOC_CMD = cargo doc $(COMPILER_ARGS) CLIPPY_CMD = cargo clippy $(COMPILER_ARGS) -CHECK_CMD = cargo check $(COMPILER_ARGS) OBJCOPY_CMD = rust-objcopy \ --strip-all \ -O binary diff --git a/01_wait_forever/src/main.rs b/01_wait_forever/src/main.rs index 30dd45e7..f7e08a59 100644 --- a/01_wait_forever/src/main.rs +++ b/01_wait_forever/src/main.rs @@ -3,7 +3,9 @@ // Copyright (c) 2018-2022 Andre Richter // Rust embedded logo for `make doc`. -#![doc(html_logo_url = "https://raw.githubusercontent.com/rust-embedded/wg/master/assets/logo/ewg-logo-blue-white-on-transparent.png")] +#![doc( + html_logo_url = "https://raw.githubusercontent.com/rust-embedded/wg/master/assets/logo/ewg-logo-blue-white-on-transparent.png" +)] //! The `kernel` binary. //! diff --git a/02_runtime_init/Makefile b/02_runtime_init/Makefile index 0d877c15..ba5f0c79 100644 --- a/02_runtime_init/Makefile +++ b/02_runtime_init/Makefile @@ -81,7 +81,6 @@ COMPILER_ARGS = --target=$(TARGET) \ RUSTC_CMD = cargo rustc $(COMPILER_ARGS) DOC_CMD = cargo doc $(COMPILER_ARGS) CLIPPY_CMD = cargo clippy $(COMPILER_ARGS) -CHECK_CMD = cargo check $(COMPILER_ARGS) OBJCOPY_CMD = rust-objcopy \ --strip-all \ -O binary diff --git a/02_runtime_init/README.md b/02_runtime_init/README.md index f2f0f047..02ed0488 100644 --- a/02_runtime_init/README.md +++ b/02_runtime_init/README.md @@ -52,7 +52,7 @@ diff -uNr 01_wait_forever/Cargo.toml 02_runtime_init/Cargo.toml diff -uNr 01_wait_forever/Makefile 02_runtime_init/Makefile --- 01_wait_forever/Makefile +++ 02_runtime_init/Makefile -@@ -181,6 +181,8 @@ +@@ -180,6 +180,8 @@ $(call color_header, "Launching objdump") @$(DOCKER_TOOLS) $(OBJDUMP_BINARY) --disassemble --demangle \ --section .text \ @@ -302,7 +302,7 @@ diff -uNr 01_wait_forever/src/cpu.rs 02_runtime_init/src/cpu.rs diff -uNr 01_wait_forever/src/main.rs 02_runtime_init/src/main.rs --- 01_wait_forever/src/main.rs +++ 02_runtime_init/src/main.rs -@@ -102,6 +102,7 @@ +@@ -104,6 +104,7 @@ //! //! 1. The kernel's entry point is the function `cpu::boot::arch_boot::_start()`. //! - It is implemented in `src/_arch/__arch_name__/cpu/boot.s`. @@ -310,7 +310,7 @@ diff -uNr 01_wait_forever/src/main.rs 02_runtime_init/src/main.rs #![no_main] #![no_std] -@@ -110,4 +111,11 @@ +@@ -112,4 +113,11 @@ mod cpu; mod panic_wait; diff --git a/02_runtime_init/src/main.rs b/02_runtime_init/src/main.rs index 6b3b1efd..42653ac4 100644 --- a/02_runtime_init/src/main.rs +++ b/02_runtime_init/src/main.rs @@ -3,7 +3,9 @@ // Copyright (c) 2018-2022 Andre Richter // Rust embedded logo for `make doc`. -#![doc(html_logo_url = "https://raw.githubusercontent.com/rust-embedded/wg/master/assets/logo/ewg-logo-blue-white-on-transparent.png")] +#![doc( + html_logo_url = "https://raw.githubusercontent.com/rust-embedded/wg/master/assets/logo/ewg-logo-blue-white-on-transparent.png" +)] //! The `kernel` binary. //! diff --git a/03_hacky_hello_world/Makefile b/03_hacky_hello_world/Makefile index c3e75cce..a90b2fd6 100644 --- a/03_hacky_hello_world/Makefile +++ b/03_hacky_hello_world/Makefile @@ -81,7 +81,6 @@ COMPILER_ARGS = --target=$(TARGET) \ RUSTC_CMD = cargo rustc $(COMPILER_ARGS) DOC_CMD = cargo doc $(COMPILER_ARGS) CLIPPY_CMD = cargo clippy $(COMPILER_ARGS) -CHECK_CMD = cargo check $(COMPILER_ARGS) OBJCOPY_CMD = rust-objcopy \ --strip-all \ -O binary diff --git a/03_hacky_hello_world/README.md b/03_hacky_hello_world/README.md index 7263532c..30a717e8 100644 --- a/03_hacky_hello_world/README.md +++ b/03_hacky_hello_world/README.md @@ -70,7 +70,7 @@ diff -uNr 02_runtime_init/Makefile 03_hacky_hello_world/Makefile OBJDUMP_BINARY = aarch64-none-elf-objdump NM_BINARY = aarch64-none-elf-nm READELF_BINARY = aarch64-none-elf-readelf -@@ -86,17 +86,20 @@ +@@ -85,17 +85,20 @@ --strip-all \ -O binary @@ -94,7 +94,7 @@ diff -uNr 02_runtime_init/Makefile 03_hacky_hello_world/Makefile -@@ -192,3 +195,27 @@ +@@ -191,3 +194,27 @@ $(call color_header, "Launching nm") @$(DOCKER_TOOLS) $(NM_BINARY) --demangle --print-size $(KERNEL_ELF) | sort | rustfilt @@ -212,7 +212,7 @@ diff -uNr 02_runtime_init/src/console.rs 03_hacky_hello_world/src/console.rs diff -uNr 02_runtime_init/src/main.rs 03_hacky_hello_world/src/main.rs --- 02_runtime_init/src/main.rs +++ 03_hacky_hello_world/src/main.rs -@@ -104,12 +104,16 @@ +@@ -106,12 +106,16 @@ //! - It is implemented in `src/_arch/__arch_name__/cpu/boot.s`. //! 2. Once finished with architectural setup, the arch code calls `kernel_init()`. @@ -229,7 +229,7 @@ diff -uNr 02_runtime_init/src/main.rs 03_hacky_hello_world/src/main.rs /// Early init code. /// -@@ -117,5 +121,7 @@ +@@ -119,5 +123,7 @@ /// /// - Only a single core must be active and running this function. unsafe fn kernel_init() -> ! { diff --git a/03_hacky_hello_world/src/main.rs b/03_hacky_hello_world/src/main.rs index ee9afd2a..67b0551b 100644 --- a/03_hacky_hello_world/src/main.rs +++ b/03_hacky_hello_world/src/main.rs @@ -3,7 +3,9 @@ // Copyright (c) 2018-2022 Andre Richter // Rust embedded logo for `make doc`. -#![doc(html_logo_url = "https://raw.githubusercontent.com/rust-embedded/wg/master/assets/logo/ewg-logo-blue-white-on-transparent.png")] +#![doc( + html_logo_url = "https://raw.githubusercontent.com/rust-embedded/wg/master/assets/logo/ewg-logo-blue-white-on-transparent.png" +)] //! The `kernel` binary. //! diff --git a/04_safe_globals/Makefile b/04_safe_globals/Makefile index c3e75cce..a90b2fd6 100644 --- a/04_safe_globals/Makefile +++ b/04_safe_globals/Makefile @@ -81,7 +81,6 @@ COMPILER_ARGS = --target=$(TARGET) \ RUSTC_CMD = cargo rustc $(COMPILER_ARGS) DOC_CMD = cargo doc $(COMPILER_ARGS) CLIPPY_CMD = cargo clippy $(COMPILER_ARGS) -CHECK_CMD = cargo check $(COMPILER_ARGS) OBJCOPY_CMD = rust-objcopy \ --strip-all \ -O binary diff --git a/04_safe_globals/README.md b/04_safe_globals/README.md index bfb2b4fa..8eff4a67 100644 --- a/04_safe_globals/README.md +++ b/04_safe_globals/README.md @@ -224,7 +224,7 @@ diff -uNr 03_hacky_hello_world/src/console.rs 04_safe_globals/src/console.rs diff -uNr 03_hacky_hello_world/src/main.rs 04_safe_globals/src/main.rs --- 03_hacky_hello_world/src/main.rs +++ 04_safe_globals/src/main.rs -@@ -106,6 +106,7 @@ +@@ -108,6 +108,7 @@ #![feature(format_args_nl)] #![feature(panic_info_message)] @@ -232,7 +232,7 @@ diff -uNr 03_hacky_hello_world/src/main.rs 04_safe_globals/src/main.rs #![no_main] #![no_std] -@@ -114,6 +115,7 @@ +@@ -116,6 +117,7 @@ mod cpu; mod panic_wait; mod print; @@ -240,7 +240,7 @@ diff -uNr 03_hacky_hello_world/src/main.rs 04_safe_globals/src/main.rs /// Early init code. /// -@@ -121,7 +123,15 @@ +@@ -123,7 +125,15 @@ /// /// - Only a single core must be active and running this function. unsafe fn kernel_init() -> ! { diff --git a/04_safe_globals/src/main.rs b/04_safe_globals/src/main.rs index 422dcf91..b45e3a35 100644 --- a/04_safe_globals/src/main.rs +++ b/04_safe_globals/src/main.rs @@ -3,7 +3,9 @@ // Copyright (c) 2018-2022 Andre Richter // Rust embedded logo for `make doc`. -#![doc(html_logo_url = "https://raw.githubusercontent.com/rust-embedded/wg/master/assets/logo/ewg-logo-blue-white-on-transparent.png")] +#![doc( + html_logo_url = "https://raw.githubusercontent.com/rust-embedded/wg/master/assets/logo/ewg-logo-blue-white-on-transparent.png" +)] //! The `kernel` binary. //! diff --git a/05_drivers_gpio_uart/Makefile b/05_drivers_gpio_uart/Makefile index 38afeef9..376892d8 100644 --- a/05_drivers_gpio_uart/Makefile +++ b/05_drivers_gpio_uart/Makefile @@ -84,7 +84,6 @@ COMPILER_ARGS = --target=$(TARGET) \ RUSTC_CMD = cargo rustc $(COMPILER_ARGS) DOC_CMD = cargo doc $(COMPILER_ARGS) CLIPPY_CMD = cargo clippy $(COMPILER_ARGS) -CHECK_CMD = cargo check $(COMPILER_ARGS) OBJCOPY_CMD = rust-objcopy \ --strip-all \ -O binary diff --git a/05_drivers_gpio_uart/README.md b/05_drivers_gpio_uart/README.md index 3b6f38f3..5787ac12 100644 --- a/05_drivers_gpio_uart/README.md +++ b/05_drivers_gpio_uart/README.md @@ -155,7 +155,7 @@ diff -uNr 04_safe_globals/Makefile 05_drivers_gpio_uart/Makefile ##-------------------------------------------------------------------------------------------------- -@@ -88,6 +91,7 @@ +@@ -87,6 +90,7 @@ EXEC_QEMU = $(QEMU_BINARY) -M $(QEMU_MACHINE_TYPE) EXEC_TEST_DISPATCH = ruby ../common/tests/dispatch.rb @@ -163,7 +163,7 @@ diff -uNr 04_safe_globals/Makefile 05_drivers_gpio_uart/Makefile ##------------------------------------------------------------------------------ ## Dockerization -@@ -95,18 +99,26 @@ +@@ -94,18 +98,26 @@ DOCKER_CMD = docker run -t --rm -v $(shell pwd):/work/tutorial -w /work/tutorial DOCKER_CMD_INTERACT = $(DOCKER_CMD) -i DOCKER_ARG_DIR_COMMON = -v $(shell pwd)/../common:/work/common @@ -191,7 +191,7 @@ diff -uNr 04_safe_globals/Makefile 05_drivers_gpio_uart/Makefile all: $(KERNEL_BIN) -@@ -156,9 +168,16 @@ +@@ -155,9 +167,16 @@ qemu: $(KERNEL_BIN) $(call color_header, "Launching QEMU") @$(DOCKER_QEMU) $(EXEC_QEMU) $(QEMU_RELEASE_ARGS) -kernel $(KERNEL_BIN) @@ -1337,7 +1337,7 @@ diff -uNr 04_safe_globals/src/driver.rs 05_drivers_gpio_uart/src/driver.rs diff -uNr 04_safe_globals/src/main.rs 05_drivers_gpio_uart/src/main.rs --- 04_safe_globals/src/main.rs +++ 05_drivers_gpio_uart/src/main.rs -@@ -104,6 +104,7 @@ +@@ -106,6 +106,7 @@ //! - It is implemented in `src/_arch/__arch_name__/cpu/boot.s`. //! 2. Once finished with architectural setup, the arch code calls `kernel_init()`. @@ -1345,7 +1345,7 @@ diff -uNr 04_safe_globals/src/main.rs 05_drivers_gpio_uart/src/main.rs #![feature(format_args_nl)] #![feature(panic_info_message)] #![feature(trait_alias)] -@@ -113,6 +114,7 @@ +@@ -115,6 +116,7 @@ mod bsp; mod console; mod cpu; @@ -1353,7 +1353,7 @@ diff -uNr 04_safe_globals/src/main.rs 05_drivers_gpio_uart/src/main.rs mod panic_wait; mod print; mod synchronization; -@@ -122,16 +124,54 @@ +@@ -124,16 +126,54 @@ /// # Safety /// /// - Only a single core must be active and running this function. diff --git a/05_drivers_gpio_uart/src/main.rs b/05_drivers_gpio_uart/src/main.rs index 241d9498..9ee5a43c 100644 --- a/05_drivers_gpio_uart/src/main.rs +++ b/05_drivers_gpio_uart/src/main.rs @@ -3,7 +3,9 @@ // Copyright (c) 2018-2022 Andre Richter // Rust embedded logo for `make doc`. -#![doc(html_logo_url = "https://raw.githubusercontent.com/rust-embedded/wg/master/assets/logo/ewg-logo-blue-white-on-transparent.png")] +#![doc( + html_logo_url = "https://raw.githubusercontent.com/rust-embedded/wg/master/assets/logo/ewg-logo-blue-white-on-transparent.png" +)] //! The `kernel` binary. //! diff --git a/06_uart_chainloader/Makefile b/06_uart_chainloader/Makefile index 3cde6041..812fdf4e 100644 --- a/06_uart_chainloader/Makefile +++ b/06_uart_chainloader/Makefile @@ -86,7 +86,6 @@ COMPILER_ARGS = --target=$(TARGET) \ RUSTC_CMD = cargo rustc $(COMPILER_ARGS) DOC_CMD = cargo doc $(COMPILER_ARGS) CLIPPY_CMD = cargo clippy $(COMPILER_ARGS) -CHECK_CMD = cargo check $(COMPILER_ARGS) OBJCOPY_CMD = rust-objcopy \ --strip-all \ -O binary diff --git a/06_uart_chainloader/README.md b/06_uart_chainloader/README.md index 04a21dff..8c21ccfa 100644 --- a/06_uart_chainloader/README.md +++ b/06_uart_chainloader/README.md @@ -189,7 +189,7 @@ diff -uNr 05_drivers_gpio_uart/Makefile 06_uart_chainloader/Makefile endif # Export for build.rs. -@@ -90,8 +92,8 @@ +@@ -89,8 +91,8 @@ -O binary EXEC_QEMU = $(QEMU_BINARY) -M $(QEMU_MACHINE_TYPE) @@ -200,7 +200,7 @@ diff -uNr 05_drivers_gpio_uart/Makefile 06_uart_chainloader/Makefile ##------------------------------------------------------------------------------ ## Dockerization -@@ -110,7 +112,7 @@ +@@ -109,7 +111,7 @@ ifeq ($(shell uname -s),Linux) DOCKER_CMD_DEV = $(DOCKER_CMD_INTERACT) $(DOCKER_ARG_DEV) @@ -209,7 +209,7 @@ diff -uNr 05_drivers_gpio_uart/Makefile 06_uart_chainloader/Makefile endif -@@ -118,7 +120,7 @@ +@@ -117,7 +119,7 @@ ##-------------------------------------------------------------------------------------------------- ## Targets ##-------------------------------------------------------------------------------------------------- @@ -218,7 +218,7 @@ diff -uNr 05_drivers_gpio_uart/Makefile 06_uart_chainloader/Makefile all: $(KERNEL_BIN) -@@ -160,7 +162,7 @@ +@@ -159,7 +161,7 @@ ##------------------------------------------------------------------------------ ifeq ($(QEMU_MACHINE_TYPE),) # QEMU is not supported for the board. @@ -227,7 +227,7 @@ diff -uNr 05_drivers_gpio_uart/Makefile 06_uart_chainloader/Makefile $(call color_header, "$(QEMU_MISSING_STRING)") else # QEMU is supported. -@@ -169,13 +171,17 @@ +@@ -168,13 +170,17 @@ $(call color_header, "Launching QEMU") @$(DOCKER_QEMU) $(EXEC_QEMU) $(QEMU_RELEASE_ARGS) -kernel $(KERNEL_BIN) @@ -248,7 +248,7 @@ diff -uNr 05_drivers_gpio_uart/Makefile 06_uart_chainloader/Makefile ##------------------------------------------------------------------------------ ## Run clippy -@@ -233,7 +239,8 @@ +@@ -232,7 +238,8 @@ ##------------------------------------------------------------------------------ test_boot: $(KERNEL_BIN) $(call color_header, "Boot test - $(BSP)") @@ -457,7 +457,7 @@ diff -uNr 05_drivers_gpio_uart/src/bsp/raspberrypi/memory.rs 06_uart_chainloader diff -uNr 05_drivers_gpio_uart/src/main.rs 06_uart_chainloader/src/main.rs --- 05_drivers_gpio_uart/src/main.rs +++ 06_uart_chainloader/src/main.rs -@@ -140,38 +140,56 @@ +@@ -142,38 +142,56 @@ kernel_main() } diff --git a/06_uart_chainloader/src/main.rs b/06_uart_chainloader/src/main.rs index 79f8b0b3..21ee91a4 100644 --- a/06_uart_chainloader/src/main.rs +++ b/06_uart_chainloader/src/main.rs @@ -3,7 +3,9 @@ // Copyright (c) 2018-2022 Andre Richter // Rust embedded logo for `make doc`. -#![doc(html_logo_url = "https://raw.githubusercontent.com/rust-embedded/wg/master/assets/logo/ewg-logo-blue-white-on-transparent.png")] +#![doc( + html_logo_url = "https://raw.githubusercontent.com/rust-embedded/wg/master/assets/logo/ewg-logo-blue-white-on-transparent.png" +)] //! The `kernel` binary. //! diff --git a/07_timestamps/Makefile b/07_timestamps/Makefile index d5395011..a497ad81 100644 --- a/07_timestamps/Makefile +++ b/07_timestamps/Makefile @@ -84,7 +84,6 @@ COMPILER_ARGS = --target=$(TARGET) \ RUSTC_CMD = cargo rustc $(COMPILER_ARGS) DOC_CMD = cargo doc $(COMPILER_ARGS) CLIPPY_CMD = cargo clippy $(COMPILER_ARGS) -CHECK_CMD = cargo check $(COMPILER_ARGS) OBJCOPY_CMD = rust-objcopy \ --strip-all \ -O binary diff --git a/07_timestamps/README.md b/07_timestamps/README.md index abdca348..7bfa13dd 100644 --- a/07_timestamps/README.md +++ b/07_timestamps/README.md @@ -112,7 +112,7 @@ diff -uNr 06_uart_chainloader/Makefile 07_timestamps/Makefile endif # Export for build.rs. -@@ -92,7 +90,7 @@ +@@ -91,7 +89,7 @@ -O binary EXEC_QEMU = $(QEMU_BINARY) -M $(QEMU_MACHINE_TYPE) @@ -121,7 +121,7 @@ diff -uNr 06_uart_chainloader/Makefile 07_timestamps/Makefile EXEC_MINIPUSH = ruby ../common/serial/minipush.rb ##------------------------------------------------------------------------------ -@@ -162,7 +160,7 @@ +@@ -161,7 +159,7 @@ ##------------------------------------------------------------------------------ ifeq ($(QEMU_MACHINE_TYPE),) # QEMU is not supported for the board. @@ -130,7 +130,7 @@ diff -uNr 06_uart_chainloader/Makefile 07_timestamps/Makefile $(call color_header, "$(QEMU_MISSING_STRING)") else # QEMU is supported. -@@ -171,17 +169,13 @@ +@@ -170,17 +168,13 @@ $(call color_header, "Launching QEMU") @$(DOCKER_QEMU) $(EXEC_QEMU) $(QEMU_RELEASE_ARGS) -kernel $(KERNEL_BIN) @@ -149,7 +149,7 @@ diff -uNr 06_uart_chainloader/Makefile 07_timestamps/Makefile ##------------------------------------------------------------------------------ ## Run clippy -@@ -239,8 +233,7 @@ +@@ -238,8 +232,7 @@ ##------------------------------------------------------------------------------ test_boot: $(KERNEL_BIN) $(call color_header, "Boot test - $(BSP)") @@ -538,7 +538,7 @@ diff -uNr 06_uart_chainloader/src/cpu.rs 07_timestamps/src/cpu.rs diff -uNr 06_uart_chainloader/src/main.rs 07_timestamps/src/main.rs --- 06_uart_chainloader/src/main.rs +++ 07_timestamps/src/main.rs -@@ -118,6 +118,7 @@ +@@ -120,6 +120,7 @@ mod panic_wait; mod print; mod synchronization; @@ -546,7 +546,7 @@ diff -uNr 06_uart_chainloader/src/main.rs 07_timestamps/src/main.rs /// Early init code. /// -@@ -140,56 +141,38 @@ +@@ -142,56 +143,38 @@ kernel_main() } diff --git a/07_timestamps/src/main.rs b/07_timestamps/src/main.rs index c067d90c..1805414b 100644 --- a/07_timestamps/src/main.rs +++ b/07_timestamps/src/main.rs @@ -3,7 +3,9 @@ // Copyright (c) 2018-2022 Andre Richter // Rust embedded logo for `make doc`. -#![doc(html_logo_url = "https://raw.githubusercontent.com/rust-embedded/wg/master/assets/logo/ewg-logo-blue-white-on-transparent.png")] +#![doc( + html_logo_url = "https://raw.githubusercontent.com/rust-embedded/wg/master/assets/logo/ewg-logo-blue-white-on-transparent.png" +)] //! The `kernel` binary. //! diff --git a/08_hw_debug_JTAG/Makefile b/08_hw_debug_JTAG/Makefile index 4f6b01f9..9d76237c 100644 --- a/08_hw_debug_JTAG/Makefile +++ b/08_hw_debug_JTAG/Makefile @@ -88,7 +88,6 @@ COMPILER_ARGS = --target=$(TARGET) \ RUSTC_CMD = cargo rustc $(COMPILER_ARGS) DOC_CMD = cargo doc $(COMPILER_ARGS) CLIPPY_CMD = cargo clippy $(COMPILER_ARGS) -CHECK_CMD = cargo check $(COMPILER_ARGS) OBJCOPY_CMD = rust-objcopy \ --strip-all \ -O binary diff --git a/08_hw_debug_JTAG/README.md b/08_hw_debug_JTAG/README.md index b1f5d679..7f8a1846 100644 --- a/08_hw_debug_JTAG/README.md +++ b/08_hw_debug_JTAG/README.md @@ -338,7 +338,7 @@ diff -uNr 07_timestamps/Makefile 08_hw_debug_JTAG/Makefile LD_SCRIPT_PATH = $(shell pwd)/src/bsp/raspberrypi RUSTC_MISC_ARGS = -C target-cpu=cortex-a72 endif -@@ -99,18 +103,25 @@ +@@ -98,18 +102,25 @@ DOCKER_CMD = docker run -t --rm -v $(shell pwd):/work/tutorial -w /work/tutorial DOCKER_CMD_INTERACT = $(DOCKER_CMD) -i DOCKER_ARG_DIR_COMMON = -v $(shell pwd)/../common:/work/common @@ -364,7 +364,7 @@ diff -uNr 07_timestamps/Makefile 08_hw_debug_JTAG/Makefile endif -@@ -216,6 +227,35 @@ +@@ -215,6 +226,35 @@ diff --git a/08_hw_debug_JTAG/src/main.rs b/08_hw_debug_JTAG/src/main.rs index c067d90c..1805414b 100644 --- a/08_hw_debug_JTAG/src/main.rs +++ b/08_hw_debug_JTAG/src/main.rs @@ -3,7 +3,9 @@ // Copyright (c) 2018-2022 Andre Richter // Rust embedded logo for `make doc`. -#![doc(html_logo_url = "https://raw.githubusercontent.com/rust-embedded/wg/master/assets/logo/ewg-logo-blue-white-on-transparent.png")] +#![doc( + html_logo_url = "https://raw.githubusercontent.com/rust-embedded/wg/master/assets/logo/ewg-logo-blue-white-on-transparent.png" +)] //! The `kernel` binary. //! diff --git a/09_privilege_level/Makefile b/09_privilege_level/Makefile index 4f6b01f9..9d76237c 100644 --- a/09_privilege_level/Makefile +++ b/09_privilege_level/Makefile @@ -88,7 +88,6 @@ COMPILER_ARGS = --target=$(TARGET) \ RUSTC_CMD = cargo rustc $(COMPILER_ARGS) DOC_CMD = cargo doc $(COMPILER_ARGS) CLIPPY_CMD = cargo clippy $(COMPILER_ARGS) -CHECK_CMD = cargo check $(COMPILER_ARGS) OBJCOPY_CMD = rust-objcopy \ --strip-all \ -O binary diff --git a/09_privilege_level/README.md b/09_privilege_level/README.md index 729634ac..5b0f72c7 100644 --- a/09_privilege_level/README.md +++ b/09_privilege_level/README.md @@ -502,7 +502,7 @@ diff -uNr 08_hw_debug_JTAG/src/exception.rs 09_privilege_level/src/exception.rs diff -uNr 08_hw_debug_JTAG/src/main.rs 09_privilege_level/src/main.rs --- 08_hw_debug_JTAG/src/main.rs +++ 09_privilege_level/src/main.rs -@@ -115,6 +115,7 @@ +@@ -117,6 +117,7 @@ mod console; mod cpu; mod driver; @@ -510,7 +510,7 @@ diff -uNr 08_hw_debug_JTAG/src/main.rs 09_privilege_level/src/main.rs mod panic_wait; mod print; mod synchronization; -@@ -143,6 +144,8 @@ +@@ -145,6 +146,8 @@ /// The main function running after the early init. fn kernel_main() -> ! { @@ -519,7 +519,7 @@ diff -uNr 08_hw_debug_JTAG/src/main.rs 09_privilege_level/src/main.rs use core::time::Duration; use driver::interface::DriverManager; use time::interface::TimeManager; -@@ -154,6 +157,12 @@ +@@ -156,6 +159,12 @@ ); info!("Booting on: {}", bsp::board_name()); @@ -532,7 +532,7 @@ diff -uNr 08_hw_debug_JTAG/src/main.rs 09_privilege_level/src/main.rs info!( "Architectural timer resolution: {} ns", time::time_manager().resolution().as_nanos() -@@ -168,11 +177,15 @@ +@@ -170,11 +179,15 @@ info!(" {}. {}", i + 1, driver.compatible()); } diff --git a/09_privilege_level/src/main.rs b/09_privilege_level/src/main.rs index 45dba34c..b1b1bc27 100644 --- a/09_privilege_level/src/main.rs +++ b/09_privilege_level/src/main.rs @@ -3,7 +3,9 @@ // Copyright (c) 2018-2022 Andre Richter // Rust embedded logo for `make doc`. -#![doc(html_logo_url = "https://raw.githubusercontent.com/rust-embedded/wg/master/assets/logo/ewg-logo-blue-white-on-transparent.png")] +#![doc( + html_logo_url = "https://raw.githubusercontent.com/rust-embedded/wg/master/assets/logo/ewg-logo-blue-white-on-transparent.png" +)] //! The `kernel` binary. //! diff --git a/10_virtual_mem_part1_identity_mapping/Makefile b/10_virtual_mem_part1_identity_mapping/Makefile index 4f6b01f9..9d76237c 100644 --- a/10_virtual_mem_part1_identity_mapping/Makefile +++ b/10_virtual_mem_part1_identity_mapping/Makefile @@ -88,7 +88,6 @@ COMPILER_ARGS = --target=$(TARGET) \ RUSTC_CMD = cargo rustc $(COMPILER_ARGS) DOC_CMD = cargo doc $(COMPILER_ARGS) CLIPPY_CMD = cargo clippy $(COMPILER_ARGS) -CHECK_CMD = cargo check $(COMPILER_ARGS) OBJCOPY_CMD = rust-objcopy \ --strip-all \ -O binary diff --git a/10_virtual_mem_part1_identity_mapping/README.md b/10_virtual_mem_part1_identity_mapping/README.md index 8c2de206..3a5539c9 100644 --- a/10_virtual_mem_part1_identity_mapping/README.md +++ b/10_virtual_mem_part1_identity_mapping/README.md @@ -1081,7 +1081,7 @@ diff -uNr 09_privilege_level/src/bsp.rs 10_virtual_mem_part1_identity_mapping/sr diff -uNr 09_privilege_level/src/main.rs 10_virtual_mem_part1_identity_mapping/src/main.rs --- 09_privilege_level/src/main.rs +++ 10_virtual_mem_part1_identity_mapping/src/main.rs -@@ -105,6 +105,8 @@ +@@ -107,6 +107,8 @@ //! 2. Once finished with architectural setup, the arch code calls `kernel_init()`. #![allow(clippy::upper_case_acronyms)] @@ -1090,7 +1090,7 @@ diff -uNr 09_privilege_level/src/main.rs 10_virtual_mem_part1_identity_mapping/s #![feature(format_args_nl)] #![feature(panic_info_message)] #![feature(trait_alias)] -@@ -116,6 +118,7 @@ +@@ -118,6 +120,7 @@ mod cpu; mod driver; mod exception; @@ -1098,7 +1098,7 @@ diff -uNr 09_privilege_level/src/main.rs 10_virtual_mem_part1_identity_mapping/s mod panic_wait; mod print; mod synchronization; -@@ -126,9 +129,17 @@ +@@ -128,9 +131,17 @@ /// # Safety /// /// - Only a single core must be active and running this function. @@ -1117,7 +1117,7 @@ diff -uNr 09_privilege_level/src/main.rs 10_virtual_mem_part1_identity_mapping/s for i in bsp::driver::driver_manager().all_device_drivers().iter() { if let Err(x) = i.init() { -@@ -157,6 +168,9 @@ +@@ -159,6 +170,9 @@ ); info!("Booting on: {}", bsp::board_name()); @@ -1127,7 +1127,7 @@ diff -uNr 09_privilege_level/src/main.rs 10_virtual_mem_part1_identity_mapping/s let (_, privilege_level) = exception::current_privilege_level(); info!("Current privilege level: {}", privilege_level); -@@ -180,6 +194,13 @@ +@@ -182,6 +196,13 @@ info!("Timer test, spinning for 1 second"); time::time_manager().spin_for(Duration::from_secs(1)); diff --git a/10_virtual_mem_part1_identity_mapping/src/main.rs b/10_virtual_mem_part1_identity_mapping/src/main.rs index 148cdfff..327f3ce0 100644 --- a/10_virtual_mem_part1_identity_mapping/src/main.rs +++ b/10_virtual_mem_part1_identity_mapping/src/main.rs @@ -3,7 +3,9 @@ // Copyright (c) 2018-2022 Andre Richter // Rust embedded logo for `make doc`. -#![doc(html_logo_url = "https://raw.githubusercontent.com/rust-embedded/wg/master/assets/logo/ewg-logo-blue-white-on-transparent.png")] +#![doc( + html_logo_url = "https://raw.githubusercontent.com/rust-embedded/wg/master/assets/logo/ewg-logo-blue-white-on-transparent.png" +)] //! The `kernel` binary. //! diff --git a/11_exceptions_part1_groundwork/Makefile b/11_exceptions_part1_groundwork/Makefile index 4f6b01f9..9d76237c 100644 --- a/11_exceptions_part1_groundwork/Makefile +++ b/11_exceptions_part1_groundwork/Makefile @@ -88,7 +88,6 @@ COMPILER_ARGS = --target=$(TARGET) \ RUSTC_CMD = cargo rustc $(COMPILER_ARGS) DOC_CMD = cargo doc $(COMPILER_ARGS) CLIPPY_CMD = cargo clippy $(COMPILER_ARGS) -CHECK_CMD = cargo check $(COMPILER_ARGS) OBJCOPY_CMD = rust-objcopy \ --strip-all \ -O binary diff --git a/11_exceptions_part1_groundwork/README.md b/11_exceptions_part1_groundwork/README.md index 2f90b7ff..d0b86c55 100644 --- a/11_exceptions_part1_groundwork/README.md +++ b/11_exceptions_part1_groundwork/README.md @@ -183,6 +183,7 @@ some hand-crafted assembly. Introducing `exception.s`: /// Call the function provided by parameter `\handler` after saving the exception context. Provide /// the context as the first parameter to '\handler'. .macro CALL_WITH_CONTEXT handler +__vector_\handler: // Make room on the stack for the exception context. sub sp, sp, #16 * 17 @@ -221,6 +222,9 @@ some hand-crafted assembly. Introducing `exception.s`: // After returning from exception handling code, replay the saved context and return via // `eret`. b __exception_restore_context + +.size __vector_\handler, . - __vector_\handler +.type __vector_\handler, function .endm ``` @@ -539,7 +543,7 @@ diff -uNr 10_virtual_mem_part1_identity_mapping/src/_arch/aarch64/exception.rs 1 + /// Saved program status. + spsr_el1: SpsrEL1, + -+ // Exception syndrome register. ++ /// Exception syndrome register. + esr_el1: EsrEL1, +} + @@ -793,7 +797,7 @@ diff -uNr 10_virtual_mem_part1_identity_mapping/src/_arch/aarch64/exception.rs 1 diff -uNr 10_virtual_mem_part1_identity_mapping/src/_arch/aarch64/exception.s 11_exceptions_part1_groundwork/src/_arch/aarch64/exception.s --- 10_virtual_mem_part1_identity_mapping/src/_arch/aarch64/exception.s +++ 11_exceptions_part1_groundwork/src/_arch/aarch64/exception.s -@@ -0,0 +1,150 @@ +@@ -0,0 +1,154 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2018-2022 Andre Richter @@ -805,6 +809,7 @@ diff -uNr 10_virtual_mem_part1_identity_mapping/src/_arch/aarch64/exception.s 11 +/// Call the function provided by parameter `\handler` after saving the exception context. Provide +/// the context as the first parameter to '\handler'. +.macro CALL_WITH_CONTEXT handler ++__vector_\handler: + // Make room on the stack for the exception context. + sub sp, sp, #16 * 17 + @@ -843,6 +848,9 @@ diff -uNr 10_virtual_mem_part1_identity_mapping/src/_arch/aarch64/exception.s 11 + // After returning from exception handling code, replay the saved context and return via + // `eret`. + b __exception_restore_context ++ ++.size __vector_\handler, . - __vector_\handler ++.type __vector_\handler, function +.endm + +.macro FIQ_SUSPEND @@ -1016,7 +1024,7 @@ diff -uNr 10_virtual_mem_part1_identity_mapping/src/exception.rs 11_exceptions_p diff -uNr 10_virtual_mem_part1_identity_mapping/src/main.rs 11_exceptions_part1_groundwork/src/main.rs --- 10_virtual_mem_part1_identity_mapping/src/main.rs +++ 11_exceptions_part1_groundwork/src/main.rs -@@ -137,6 +137,8 @@ +@@ -139,6 +139,8 @@ use driver::interface::DriverManager; use memory::mmu::interface::MMU; @@ -1025,7 +1033,7 @@ diff -uNr 10_virtual_mem_part1_identity_mapping/src/main.rs 11_exceptions_part1_ if let Err(string) = memory::mmu::mmu().enable_mmu_and_caching() { panic!("MMU: {}", string); } -@@ -194,13 +196,28 @@ +@@ -196,13 +198,28 @@ info!("Timer test, spinning for 1 second"); time::time_manager().spin_for(Duration::from_secs(1)); diff --git a/11_exceptions_part1_groundwork/src/_arch/aarch64/exception.rs b/11_exceptions_part1_groundwork/src/_arch/aarch64/exception.rs index e8484938..7d3b4572 100644 --- a/11_exceptions_part1_groundwork/src/_arch/aarch64/exception.rs +++ b/11_exceptions_part1_groundwork/src/_arch/aarch64/exception.rs @@ -45,7 +45,7 @@ struct ExceptionContext { /// Saved program status. spsr_el1: SpsrEL1, - // Exception syndrome register. + /// Exception syndrome register. esr_el1: EsrEL1, } diff --git a/11_exceptions_part1_groundwork/src/_arch/aarch64/exception.s b/11_exceptions_part1_groundwork/src/_arch/aarch64/exception.s index 5aae30b9..91805ee7 100644 --- a/11_exceptions_part1_groundwork/src/_arch/aarch64/exception.s +++ b/11_exceptions_part1_groundwork/src/_arch/aarch64/exception.s @@ -9,6 +9,7 @@ /// Call the function provided by parameter `\handler` after saving the exception context. Provide /// the context as the first parameter to '\handler'. .macro CALL_WITH_CONTEXT handler +__vector_\handler: // Make room on the stack for the exception context. sub sp, sp, #16 * 17 @@ -47,6 +48,9 @@ // After returning from exception handling code, replay the saved context and return via // `eret`. b __exception_restore_context + +.size __vector_\handler, . - __vector_\handler +.type __vector_\handler, function .endm .macro FIQ_SUSPEND diff --git a/11_exceptions_part1_groundwork/src/main.rs b/11_exceptions_part1_groundwork/src/main.rs index 5534750a..0c88c58e 100644 --- a/11_exceptions_part1_groundwork/src/main.rs +++ b/11_exceptions_part1_groundwork/src/main.rs @@ -3,7 +3,9 @@ // Copyright (c) 2018-2022 Andre Richter // Rust embedded logo for `make doc`. -#![doc(html_logo_url = "https://raw.githubusercontent.com/rust-embedded/wg/master/assets/logo/ewg-logo-blue-white-on-transparent.png")] +#![doc( + html_logo_url = "https://raw.githubusercontent.com/rust-embedded/wg/master/assets/logo/ewg-logo-blue-white-on-transparent.png" +)] //! The `kernel` binary. //! diff --git a/12_integrated_testing/Makefile b/12_integrated_testing/Makefile index 50986ce2..1a19e601 100644 --- a/12_integrated_testing/Makefile +++ b/12_integrated_testing/Makefile @@ -97,7 +97,6 @@ COMPILER_ARGS = --target=$(TARGET) \ RUSTC_CMD = cargo rustc $(COMPILER_ARGS) --manifest-path $(KERNEL_MANIFEST) DOC_CMD = cargo doc $(COMPILER_ARGS) CLIPPY_CMD = cargo clippy $(COMPILER_ARGS) -CHECK_CMD = cargo check $(COMPILER_ARGS) TEST_CMD = cargo test $(COMPILER_ARGS) --manifest-path $(KERNEL_MANIFEST) OBJCOPY_CMD = rust-objcopy \ --strip-all \ diff --git a/12_integrated_testing/kernel/src/_arch/aarch64/exception.rs b/12_integrated_testing/kernel/src/_arch/aarch64/exception.rs index e84699e1..0f83052c 100644 --- a/12_integrated_testing/kernel/src/_arch/aarch64/exception.rs +++ b/12_integrated_testing/kernel/src/_arch/aarch64/exception.rs @@ -45,7 +45,7 @@ struct ExceptionContext { /// Saved program status. spsr_el1: SpsrEL1, - // Exception syndrome register. + /// Exception syndrome register. esr_el1: EsrEL1, } diff --git a/12_integrated_testing/kernel/src/_arch/aarch64/exception.s b/12_integrated_testing/kernel/src/_arch/aarch64/exception.s index 5aae30b9..91805ee7 100644 --- a/12_integrated_testing/kernel/src/_arch/aarch64/exception.s +++ b/12_integrated_testing/kernel/src/_arch/aarch64/exception.s @@ -9,6 +9,7 @@ /// Call the function provided by parameter `\handler` after saving the exception context. Provide /// the context as the first parameter to '\handler'. .macro CALL_WITH_CONTEXT handler +__vector_\handler: // Make room on the stack for the exception context. sub sp, sp, #16 * 17 @@ -47,6 +48,9 @@ // After returning from exception handling code, replay the saved context and return via // `eret`. b __exception_restore_context + +.size __vector_\handler, . - __vector_\handler +.type __vector_\handler, function .endm .macro FIQ_SUSPEND diff --git a/12_integrated_testing/kernel/src/lib.rs b/12_integrated_testing/kernel/src/lib.rs index 1218e30e..442de9e0 100644 --- a/12_integrated_testing/kernel/src/lib.rs +++ b/12_integrated_testing/kernel/src/lib.rs @@ -3,7 +3,9 @@ // Copyright (c) 2018-2022 Andre Richter // Rust embedded logo for `make doc`. -#![doc(html_logo_url = "https://raw.githubusercontent.com/rust-embedded/wg/master/assets/logo/ewg-logo-blue-white-on-transparent.png")] +#![doc( + html_logo_url = "https://raw.githubusercontent.com/rust-embedded/wg/master/assets/logo/ewg-logo-blue-white-on-transparent.png" +)] //! The `kernel` library. //! diff --git a/12_integrated_testing/kernel/src/main.rs b/12_integrated_testing/kernel/src/main.rs index dfbc1166..11b6547d 100644 --- a/12_integrated_testing/kernel/src/main.rs +++ b/12_integrated_testing/kernel/src/main.rs @@ -3,7 +3,9 @@ // Copyright (c) 2018-2022 Andre Richter // Rust embedded logo for `make doc`. -#![doc(html_logo_url = "https://raw.githubusercontent.com/rust-embedded/wg/master/assets/logo/ewg-logo-blue-white-on-transparent.png")] +#![doc( + html_logo_url = "https://raw.githubusercontent.com/rust-embedded/wg/master/assets/logo/ewg-logo-blue-white-on-transparent.png" +)] //! The `kernel` binary. diff --git a/13_exceptions_part2_peripheral_IRQs/Makefile b/13_exceptions_part2_peripheral_IRQs/Makefile index 50986ce2..1a19e601 100644 --- a/13_exceptions_part2_peripheral_IRQs/Makefile +++ b/13_exceptions_part2_peripheral_IRQs/Makefile @@ -97,7 +97,6 @@ COMPILER_ARGS = --target=$(TARGET) \ RUSTC_CMD = cargo rustc $(COMPILER_ARGS) --manifest-path $(KERNEL_MANIFEST) DOC_CMD = cargo doc $(COMPILER_ARGS) CLIPPY_CMD = cargo clippy $(COMPILER_ARGS) -CHECK_CMD = cargo check $(COMPILER_ARGS) TEST_CMD = cargo test $(COMPILER_ARGS) --manifest-path $(KERNEL_MANIFEST) OBJCOPY_CMD = rust-objcopy \ --strip-all \ diff --git a/13_exceptions_part2_peripheral_IRQs/README.md b/13_exceptions_part2_peripheral_IRQs/README.md index 35e0307f..5938da9e 100644 --- a/13_exceptions_part2_peripheral_IRQs/README.md +++ b/13_exceptions_part2_peripheral_IRQs/README.md @@ -2398,7 +2398,7 @@ diff -uNr 12_integrated_testing/kernel/src/exception/asynchronous.rs 13_exceptio diff -uNr 12_integrated_testing/kernel/src/lib.rs 13_exceptions_part2_peripheral_IRQs/kernel/src/lib.rs --- 12_integrated_testing/kernel/src/lib.rs +++ 13_exceptions_part2_peripheral_IRQs/kernel/src/lib.rs -@@ -108,6 +108,7 @@ +@@ -110,6 +110,7 @@ #![allow(clippy::upper_case_acronyms)] #![allow(incomplete_features)] @@ -2406,7 +2406,7 @@ diff -uNr 12_integrated_testing/kernel/src/lib.rs 13_exceptions_part2_peripheral #![feature(core_intrinsics)] #![feature(format_args_nl)] #![feature(linkage)] -@@ -130,6 +131,7 @@ +@@ -132,6 +133,7 @@ pub mod exception; pub mod memory; pub mod print; @@ -2418,7 +2418,7 @@ diff -uNr 12_integrated_testing/kernel/src/lib.rs 13_exceptions_part2_peripheral diff -uNr 12_integrated_testing/kernel/src/main.rs 13_exceptions_part2_peripheral_IRQs/kernel/src/main.rs --- 12_integrated_testing/kernel/src/main.rs +++ 13_exceptions_part2_peripheral_IRQs/kernel/src/main.rs -@@ -11,7 +11,7 @@ +@@ -13,7 +13,7 @@ #![no_main] #![no_std] @@ -2427,7 +2427,7 @@ diff -uNr 12_integrated_testing/kernel/src/main.rs 13_exceptions_part2_periphera /// Early init code. /// -@@ -21,7 +21,7 @@ +@@ -23,7 +23,7 @@ /// - The init calls in this function must appear in the correct order: /// - MMU + Data caching must be activated at the earliest. Without it, any atomic operations, /// e.g. the yet-to-be-introduced spinlocks in the device drivers (which currently employ @@ -2436,7 +2436,7 @@ diff -uNr 12_integrated_testing/kernel/src/main.rs 13_exceptions_part2_periphera #[no_mangle] unsafe fn kernel_init() -> ! { use driver::interface::DriverManager; -@@ -41,15 +41,27 @@ +@@ -43,15 +43,27 @@ bsp::driver::driver_manager().post_device_driver_init(); // println! is usable from here on. @@ -2466,7 +2466,7 @@ diff -uNr 12_integrated_testing/kernel/src/main.rs 13_exceptions_part2_periphera info!("{}", libkernel::version()); info!("Booting on: {}", bsp::board_name()); -@@ -77,12 +89,9 @@ +@@ -79,12 +91,9 @@ info!(" {}. {}", i + 1, driver.compatible()); } diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/exception.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/exception.rs index 495dba34..662c91b9 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/exception.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/exception.rs @@ -46,7 +46,7 @@ struct ExceptionContext { /// Saved program status. spsr_el1: SpsrEL1, - // Exception syndrome register. + /// Exception syndrome register. esr_el1: EsrEL1, } diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/exception.s b/13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/exception.s index 5aae30b9..91805ee7 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/exception.s +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/exception.s @@ -9,6 +9,7 @@ /// Call the function provided by parameter `\handler` after saving the exception context. Provide /// the context as the first parameter to '\handler'. .macro CALL_WITH_CONTEXT handler +__vector_\handler: // Make room on the stack for the exception context. sub sp, sp, #16 * 17 @@ -47,6 +48,9 @@ // After returning from exception handling code, replay the saved context and return via // `eret`. b __exception_restore_context + +.size __vector_\handler, . - __vector_\handler +.type __vector_\handler, function .endm .macro FIQ_SUSPEND diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/lib.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/lib.rs index 9bd360c0..58a939f1 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/lib.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/lib.rs @@ -3,7 +3,9 @@ // Copyright (c) 2018-2022 Andre Richter // Rust embedded logo for `make doc`. -#![doc(html_logo_url = "https://raw.githubusercontent.com/rust-embedded/wg/master/assets/logo/ewg-logo-blue-white-on-transparent.png")] +#![doc( + html_logo_url = "https://raw.githubusercontent.com/rust-embedded/wg/master/assets/logo/ewg-logo-blue-white-on-transparent.png" +)] //! The `kernel` library. //! diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/main.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/main.rs index 228b984b..0f72d17f 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/main.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/main.rs @@ -3,7 +3,9 @@ // Copyright (c) 2018-2022 Andre Richter // Rust embedded logo for `make doc`. -#![doc(html_logo_url = "https://raw.githubusercontent.com/rust-embedded/wg/master/assets/logo/ewg-logo-blue-white-on-transparent.png")] +#![doc( + html_logo_url = "https://raw.githubusercontent.com/rust-embedded/wg/master/assets/logo/ewg-logo-blue-white-on-transparent.png" +)] //! The `kernel` binary. diff --git a/14_virtual_mem_part2_mmio_remap/Makefile b/14_virtual_mem_part2_mmio_remap/Makefile index 50986ce2..1a19e601 100644 --- a/14_virtual_mem_part2_mmio_remap/Makefile +++ b/14_virtual_mem_part2_mmio_remap/Makefile @@ -97,7 +97,6 @@ COMPILER_ARGS = --target=$(TARGET) \ RUSTC_CMD = cargo rustc $(COMPILER_ARGS) --manifest-path $(KERNEL_MANIFEST) DOC_CMD = cargo doc $(COMPILER_ARGS) CLIPPY_CMD = cargo clippy $(COMPILER_ARGS) -CHECK_CMD = cargo check $(COMPILER_ARGS) TEST_CMD = cargo test $(COMPILER_ARGS) --manifest-path $(KERNEL_MANIFEST) OBJCOPY_CMD = rust-objcopy \ --strip-all \ diff --git a/14_virtual_mem_part2_mmio_remap/README.md b/14_virtual_mem_part2_mmio_remap/README.md index e19cedb7..329e2105 100644 --- a/14_virtual_mem_part2_mmio_remap/README.md +++ b/14_virtual_mem_part2_mmio_remap/README.md @@ -2136,7 +2136,7 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/driver.rs 14_virtual_me diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/lib.rs 14_virtual_mem_part2_mmio_remap/kernel/src/lib.rs --- 13_exceptions_part2_peripheral_IRQs/kernel/src/lib.rs +++ 14_virtual_mem_part2_mmio_remap/kernel/src/lib.rs -@@ -111,8 +111,10 @@ +@@ -113,8 +113,10 @@ #![feature(asm_const)] #![feature(core_intrinsics)] #![feature(format_args_nl)] @@ -2147,7 +2147,7 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/lib.rs 14_virtual_mem_p #![feature(trait_alias)] #![no_std] // Testing -@@ -125,6 +127,7 @@ +@@ -127,6 +129,7 @@ mod synchronization; pub mod bsp; @@ -2155,7 +2155,7 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/lib.rs 14_virtual_mem_p pub mod console; pub mod cpu; pub mod driver; -@@ -177,6 +180,7 @@ +@@ -179,6 +182,7 @@ #[no_mangle] unsafe fn kernel_init() -> ! { exception::handling_init(); @@ -2167,7 +2167,7 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/lib.rs 14_virtual_mem_p diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/main.rs 14_virtual_mem_part2_mmio_remap/kernel/src/main.rs --- 13_exceptions_part2_peripheral_IRQs/kernel/src/main.rs +++ 14_virtual_mem_part2_mmio_remap/kernel/src/main.rs -@@ -25,21 +25,41 @@ +@@ -27,21 +27,41 @@ #[no_mangle] unsafe fn kernel_init() -> ! { use driver::interface::DriverManager; @@ -2215,7 +2215,7 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/main.rs 14_virtual_mem_ // Let device drivers register and enable their handlers with the interrupt controller. for i in bsp::driver::driver_manager().all_device_drivers() { -@@ -66,8 +86,8 @@ +@@ -68,8 +88,8 @@ info!("{}", libkernel::version()); info!("Booting on: {}", bsp::board_name()); diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/exception.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/exception.rs index 495dba34..662c91b9 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/exception.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/exception.rs @@ -46,7 +46,7 @@ struct ExceptionContext { /// Saved program status. spsr_el1: SpsrEL1, - // Exception syndrome register. + /// Exception syndrome register. esr_el1: EsrEL1, } diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/exception.s b/14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/exception.s index 5aae30b9..91805ee7 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/exception.s +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/exception.s @@ -9,6 +9,7 @@ /// Call the function provided by parameter `\handler` after saving the exception context. Provide /// the context as the first parameter to '\handler'. .macro CALL_WITH_CONTEXT handler +__vector_\handler: // Make room on the stack for the exception context. sub sp, sp, #16 * 17 @@ -47,6 +48,9 @@ // After returning from exception handling code, replay the saved context and return via // `eret`. b __exception_restore_context + +.size __vector_\handler, . - __vector_\handler +.type __vector_\handler, function .endm .macro FIQ_SUSPEND diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/lib.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/lib.rs index 2c874f18..aeab8c22 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/lib.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/lib.rs @@ -3,7 +3,9 @@ // Copyright (c) 2018-2022 Andre Richter // Rust embedded logo for `make doc`. -#![doc(html_logo_url = "https://raw.githubusercontent.com/rust-embedded/wg/master/assets/logo/ewg-logo-blue-white-on-transparent.png")] +#![doc( + html_logo_url = "https://raw.githubusercontent.com/rust-embedded/wg/master/assets/logo/ewg-logo-blue-white-on-transparent.png" +)] //! The `kernel` library. //! diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/main.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/main.rs index 68d34e35..17edcfd9 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/main.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/main.rs @@ -3,7 +3,9 @@ // Copyright (c) 2018-2022 Andre Richter // Rust embedded logo for `make doc`. -#![doc(html_logo_url = "https://raw.githubusercontent.com/rust-embedded/wg/master/assets/logo/ewg-logo-blue-white-on-transparent.png")] +#![doc( + html_logo_url = "https://raw.githubusercontent.com/rust-embedded/wg/master/assets/logo/ewg-logo-blue-white-on-transparent.png" +)] //! The `kernel` binary. diff --git a/15_virtual_mem_part3_precomputed_tables/Makefile b/15_virtual_mem_part3_precomputed_tables/Makefile index 85b8ca38..0d34c181 100644 --- a/15_virtual_mem_part3_precomputed_tables/Makefile +++ b/15_virtual_mem_part3_precomputed_tables/Makefile @@ -107,7 +107,6 @@ COMPILER_ARGS = --target=$(TARGET) \ RUSTC_CMD = cargo rustc $(COMPILER_ARGS) --manifest-path $(KERNEL_MANIFEST) DOC_CMD = cargo doc $(COMPILER_ARGS) CLIPPY_CMD = cargo clippy $(COMPILER_ARGS) -CHECK_CMD = cargo check $(COMPILER_ARGS) TEST_CMD = cargo test $(COMPILER_ARGS) --manifest-path $(KERNEL_MANIFEST) OBJCOPY_CMD = rust-objcopy \ --strip-all \ diff --git a/15_virtual_mem_part3_precomputed_tables/README.md b/15_virtual_mem_part3_precomputed_tables/README.md index b09b265b..9ec33fc0 100644 --- a/15_virtual_mem_part3_precomputed_tables/README.md +++ b/15_virtual_mem_part3_precomputed_tables/README.md @@ -1374,7 +1374,7 @@ diff -uNr 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/memory/mmu. diff -uNr 14_virtual_mem_part2_mmio_remap/kernel/src/main.rs 15_virtual_mem_part3_precomputed_tables/kernel/src/main.rs --- 14_virtual_mem_part2_mmio_remap/kernel/src/main.rs +++ 15_virtual_mem_part3_precomputed_tables/kernel/src/main.rs -@@ -15,31 +15,23 @@ +@@ -17,31 +17,23 @@ /// Early init code. /// @@ -1413,7 +1413,7 @@ diff -uNr 14_virtual_mem_part2_mmio_remap/kernel/src/main.rs 15_virtual_mem_part // Bring up the drivers needed for printing first. for i in bsp::driver::driver_manager() .early_print_device_drivers() -@@ -49,7 +41,7 @@ +@@ -51,7 +43,7 @@ i.init().unwrap_or_else(|_| cpu::wait_forever()); } bsp::driver::driver_manager().post_early_print_device_driver_init(); @@ -1860,7 +1860,7 @@ diff -uNr 14_virtual_mem_part2_mmio_remap/Makefile 15_virtual_mem_part3_precompu -@@ -104,6 +114,7 @@ +@@ -103,6 +113,7 @@ -O binary EXEC_QEMU = $(QEMU_BINARY) -M $(QEMU_MACHINE_TYPE) @@ -1868,7 +1868,7 @@ diff -uNr 14_virtual_mem_part2_mmio_remap/Makefile 15_virtual_mem_part3_precompu EXEC_TEST_DISPATCH = ruby ../common/tests/dispatch.rb EXEC_MINIPUSH = ruby ../common/serial/minipush.rb -@@ -154,16 +165,24 @@ +@@ -153,16 +164,24 @@ ##------------------------------------------------------------------------------ ## Compile the kernel ELF ##------------------------------------------------------------------------------ @@ -1896,7 +1896,7 @@ diff -uNr 14_virtual_mem_part2_mmio_remap/Makefile 15_virtual_mem_part3_precompu $(call color_progress_prefix, "Name") @echo $(KERNEL_BIN) $(call color_progress_prefix, "Size") -@@ -302,6 +321,7 @@ +@@ -301,6 +320,7 @@ TEST_ELF=$$(echo $$1 | sed -e 's/.*target/target/g') TEST_BINARY=$$(echo $$1.img | sed -e 's/.*target/target/g') diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/exception.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/exception.rs index 495dba34..662c91b9 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/exception.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/exception.rs @@ -46,7 +46,7 @@ struct ExceptionContext { /// Saved program status. spsr_el1: SpsrEL1, - // Exception syndrome register. + /// Exception syndrome register. esr_el1: EsrEL1, } diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/exception.s b/15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/exception.s index 5aae30b9..91805ee7 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/exception.s +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/exception.s @@ -9,6 +9,7 @@ /// Call the function provided by parameter `\handler` after saving the exception context. Provide /// the context as the first parameter to '\handler'. .macro CALL_WITH_CONTEXT handler +__vector_\handler: // Make room on the stack for the exception context. sub sp, sp, #16 * 17 @@ -47,6 +48,9 @@ // After returning from exception handling code, replay the saved context and return via // `eret`. b __exception_restore_context + +.size __vector_\handler, . - __vector_\handler +.type __vector_\handler, function .endm .macro FIQ_SUSPEND diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/lib.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/lib.rs index 2c874f18..aeab8c22 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/lib.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/lib.rs @@ -3,7 +3,9 @@ // Copyright (c) 2018-2022 Andre Richter // Rust embedded logo for `make doc`. -#![doc(html_logo_url = "https://raw.githubusercontent.com/rust-embedded/wg/master/assets/logo/ewg-logo-blue-white-on-transparent.png")] +#![doc( + html_logo_url = "https://raw.githubusercontent.com/rust-embedded/wg/master/assets/logo/ewg-logo-blue-white-on-transparent.png" +)] //! The `kernel` library. //! diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/main.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/main.rs index c0c18818..5150f3af 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/main.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/main.rs @@ -3,7 +3,9 @@ // Copyright (c) 2018-2022 Andre Richter // Rust embedded logo for `make doc`. -#![doc(html_logo_url = "https://raw.githubusercontent.com/rust-embedded/wg/master/assets/logo/ewg-logo-blue-white-on-transparent.png")] +#![doc( + html_logo_url = "https://raw.githubusercontent.com/rust-embedded/wg/master/assets/logo/ewg-logo-blue-white-on-transparent.png" +)] //! The `kernel` binary. diff --git a/16_virtual_mem_part4_higher_half_kernel/Makefile b/16_virtual_mem_part4_higher_half_kernel/Makefile index 85b8ca38..0d34c181 100644 --- a/16_virtual_mem_part4_higher_half_kernel/Makefile +++ b/16_virtual_mem_part4_higher_half_kernel/Makefile @@ -107,7 +107,6 @@ COMPILER_ARGS = --target=$(TARGET) \ RUSTC_CMD = cargo rustc $(COMPILER_ARGS) --manifest-path $(KERNEL_MANIFEST) DOC_CMD = cargo doc $(COMPILER_ARGS) CLIPPY_CMD = cargo clippy $(COMPILER_ARGS) -CHECK_CMD = cargo check $(COMPILER_ARGS) TEST_CMD = cargo test $(COMPILER_ARGS) --manifest-path $(KERNEL_MANIFEST) OBJCOPY_CMD = rust-objcopy \ --strip-all \ diff --git a/16_virtual_mem_part4_higher_half_kernel/README.md b/16_virtual_mem_part4_higher_half_kernel/README.md index 89f650a3..32259671 100644 --- a/16_virtual_mem_part4_higher_half_kernel/README.md +++ b/16_virtual_mem_part4_higher_half_kernel/README.md @@ -799,7 +799,7 @@ diff -uNr 15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/mem diff -uNr 15_virtual_mem_part3_precomputed_tables/kernel/src/lib.rs 16_virtual_mem_part4_higher_half_kernel/kernel/src/lib.rs --- 15_virtual_mem_part3_precomputed_tables/kernel/src/lib.rs +++ 16_virtual_mem_part4_higher_half_kernel/kernel/src/lib.rs -@@ -150,11 +150,6 @@ +@@ -152,11 +152,6 @@ ) } diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/exception.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/exception.rs index 495dba34..662c91b9 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/exception.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/exception.rs @@ -46,7 +46,7 @@ struct ExceptionContext { /// Saved program status. spsr_el1: SpsrEL1, - // Exception syndrome register. + /// Exception syndrome register. esr_el1: EsrEL1, } diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/exception.s b/16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/exception.s index 5aae30b9..91805ee7 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/exception.s +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/exception.s @@ -9,6 +9,7 @@ /// Call the function provided by parameter `\handler` after saving the exception context. Provide /// the context as the first parameter to '\handler'. .macro CALL_WITH_CONTEXT handler +__vector_\handler: // Make room on the stack for the exception context. sub sp, sp, #16 * 17 @@ -47,6 +48,9 @@ // After returning from exception handling code, replay the saved context and return via // `eret`. b __exception_restore_context + +.size __vector_\handler, . - __vector_\handler +.type __vector_\handler, function .endm .macro FIQ_SUSPEND diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/lib.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/lib.rs index 5ecc3a71..c9c03792 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/lib.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/lib.rs @@ -3,7 +3,9 @@ // Copyright (c) 2018-2022 Andre Richter // Rust embedded logo for `make doc`. -#![doc(html_logo_url = "https://raw.githubusercontent.com/rust-embedded/wg/master/assets/logo/ewg-logo-blue-white-on-transparent.png")] +#![doc( + html_logo_url = "https://raw.githubusercontent.com/rust-embedded/wg/master/assets/logo/ewg-logo-blue-white-on-transparent.png" +)] //! The `kernel` library. //! diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/main.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/main.rs index c0c18818..5150f3af 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/main.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/main.rs @@ -3,7 +3,9 @@ // Copyright (c) 2018-2022 Andre Richter // Rust embedded logo for `make doc`. -#![doc(html_logo_url = "https://raw.githubusercontent.com/rust-embedded/wg/master/assets/logo/ewg-logo-blue-white-on-transparent.png")] +#![doc( + html_logo_url = "https://raw.githubusercontent.com/rust-embedded/wg/master/assets/logo/ewg-logo-blue-white-on-transparent.png" +)] //! The `kernel` binary. diff --git a/17_kernel_symbols/Makefile b/17_kernel_symbols/Makefile index 1e9282a2..41cecae3 100644 --- a/17_kernel_symbols/Makefile +++ b/17_kernel_symbols/Makefile @@ -124,7 +124,6 @@ COMPILER_ARGS = --target=$(TARGET) \ RUSTC_CMD = cargo rustc $(COMPILER_ARGS) --manifest-path $(KERNEL_MANIFEST) DOC_CMD = cargo doc $(COMPILER_ARGS) CLIPPY_CMD = cargo clippy $(COMPILER_ARGS) -CHECK_CMD = cargo check $(COMPILER_ARGS) TEST_CMD = cargo test $(COMPILER_ARGS) --manifest-path $(KERNEL_MANIFEST) OBJCOPY_CMD = rust-objcopy \ --strip-all \ @@ -354,7 +353,7 @@ define KERNEL_TEST_RUNNER # started by the same. KERNEL_SYMBOLS_INPUT_ELF=$$TEST_ELF \ KERNEL_SYMBOLS_OUTPUT_ELF=$$TEST_ELF_SYMS \ - $(MAKE) --no-print-directory -f kernel_symbols.mk > /dev/null 2>&1 + $(MAKE) --no-print-directory -f kernel_symbols.mk > /dev/null 2>&1 $(OBJCOPY_CMD) $$TEST_ELF_SYMS $$TEST_BINARY $(DOCKER_TEST) $(EXEC_TEST_DISPATCH) $(EXEC_QEMU) $(QEMU_TEST_ARGS) -kernel $$TEST_BINARY diff --git a/17_kernel_symbols/README.md b/17_kernel_symbols/README.md index 72428c23..897e38cd 100644 --- a/17_kernel_symbols/README.md +++ b/17_kernel_symbols/README.md @@ -49,9 +49,6 @@ pub struct Symbol { } ``` -The implementation of the struct furthermore defines the two public functions `name()` and -`contains()`, which will be used to query information. - To enable the kernel to lookup symbol names, we will add an `array` to the kernel binary that contains all the kernel symbols. Because we can query the final symbol names and addresses only _after_ the kernel has been `linked`, the same approach as for the `translation tables` will be @@ -184,11 +181,11 @@ fn kernel_symbols_slice() -> &'static [Symbol] { Lookup is done by just iterating over the slice: ```rust -/// Retrieve the symbol name corresponding to a virtual address, if any. -pub fn lookup_symbol(addr: Address) -> Option<&'static str> { +/// Retrieve the symbol corresponding to a virtual address, if any. +pub fn lookup_symbol(addr: Address) -> Option<&'static Symbol> { for i in kernel_symbols_slice() { if i.contains(addr.as_usize()) { - return Some(i.name()); + return Some(i); } } @@ -277,15 +274,17 @@ diff -uNr 16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/excep use core::{arch::global_asm, cell::UnsafeCell, fmt}; use cortex_a::{asm::barrier, registers::*}; use tock_registers::{ -@@ -262,6 +262,12 @@ +@@ -262,6 +262,14 @@ writeln!(f, "{}", self.spsr_el1)?; writeln!(f, "ELR_EL1: {:#018x}", self.elr_el1)?; + writeln!( + f, + " Symbol: {}", -+ symbols::lookup_symbol(memory::Address::new(self.elr_el1 as usize)) -+ .unwrap_or("Symbol not found") ++ match symbols::lookup_symbol(memory::Address::new(self.elr_el1 as usize)) { ++ Some(sym) => sym.name(), ++ _ => "Symbol not found", ++ } + )?; writeln!(f)?; writeln!(f, "General purpose register:")?; @@ -333,7 +332,7 @@ diff -uNr 16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi/mem diff -uNr 16_virtual_mem_part4_higher_half_kernel/kernel/src/lib.rs 17_kernel_symbols/kernel/src/lib.rs --- 16_virtual_mem_part4_higher_half_kernel/kernel/src/lib.rs +++ 17_kernel_symbols/kernel/src/lib.rs -@@ -135,6 +135,7 @@ +@@ -137,6 +137,7 @@ pub mod memory; pub mod print; pub mod state; @@ -345,7 +344,7 @@ diff -uNr 16_virtual_mem_part4_higher_half_kernel/kernel/src/lib.rs 17_kernel_sy diff -uNr 16_virtual_mem_part4_higher_half_kernel/kernel/src/symbols.rs 17_kernel_symbols/kernel/src/symbols.rs --- 16_virtual_mem_part4_higher_half_kernel/kernel/src/symbols.rs +++ 17_kernel_symbols/kernel/src/symbols.rs -@@ -0,0 +1,85 @@ +@@ -0,0 +1,87 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2022 Andre Richter @@ -395,11 +394,11 @@ diff -uNr 16_virtual_mem_part4_higher_half_kernel/kernel/src/symbols.rs 17_kerne +// Public Code +//-------------------------------------------------------------------------------------------------- + -+/// Retrieve the symbol name corresponding to a virtual address, if any. -+pub fn lookup_symbol(addr: Address) -> Option<&'static str> { ++/// Retrieve the symbol corresponding to a virtual address, if any. ++pub fn lookup_symbol(addr: Address) -> Option<&'static Symbol> { + for i in kernel_symbols_slice() { + if i.contains(addr.as_usize()) { -+ return Some(i.name()); ++ return Some(i); + } + } + @@ -421,12 +420,14 @@ diff -uNr 16_virtual_mem_part4_higher_half_kernel/kernel/src/symbols.rs 17_kerne + let first_sym = lookup_symbol(Address::new( + crate::common::is_aligned as *const usize as usize, + )) -+ .unwrap(); ++ .unwrap() ++ .name(); + + assert_eq!(first_sym, "libkernel::common::is_aligned"); + -+ let second_sym = -+ lookup_symbol(Address::new(crate::version as *const usize as usize)).unwrap(); ++ let second_sym = lookup_symbol(Address::new(crate::version as *const usize as usize)) ++ .unwrap() ++ .name(); + + assert_eq!(second_sym, "libkernel::version"); + } @@ -515,7 +516,7 @@ diff -uNr 16_virtual_mem_part4_higher_half_kernel/kernel_symbols/src/main.rs 17_ diff -uNr 16_virtual_mem_part4_higher_half_kernel/kernel_symbols.mk 17_kernel_symbols/kernel_symbols.mk --- 16_virtual_mem_part4_higher_half_kernel/kernel_symbols.mk +++ 17_kernel_symbols/kernel_symbols.mk -@@ -0,0 +1,101 @@ +@@ -0,0 +1,103 @@ +## SPDX-License-Identifier: MIT OR Apache-2.0 +## +## Copyright (c) 2018-2022 Andre Richter @@ -617,6 +618,8 @@ diff -uNr 16_virtual_mem_part4_higher_half_kernel/kernel_symbols.mk 17_kernel_sy + + @$(DOCKER_TOOLS) $(EXEC_SYMBOLS_TOOL) --patch_data $(KERNEL_SYMBOLS_OUTPUT_ELF) \ + $(KERNEL_SYMBOLS_STRIPPED) ++ ++ $(call color_progress_prefix, "Finished") diff -uNr 16_virtual_mem_part4_higher_half_kernel/libraries/debug-symbol-types/Cargo.toml 17_kernel_symbols/libraries/debug-symbol-types/Cargo.toml --- 16_virtual_mem_part4_higher_half_kernel/libraries/debug-symbol-types/Cargo.toml @@ -630,7 +633,7 @@ diff -uNr 16_virtual_mem_part4_higher_half_kernel/libraries/debug-symbol-types/C diff -uNr 16_virtual_mem_part4_higher_half_kernel/libraries/debug-symbol-types/src/lib.rs 17_kernel_symbols/libraries/debug-symbol-types/src/lib.rs --- 16_virtual_mem_part4_higher_half_kernel/libraries/debug-symbol-types/src/lib.rs +++ 17_kernel_symbols/libraries/debug-symbol-types/src/lib.rs -@@ -0,0 +1,39 @@ +@@ -0,0 +1,45 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2022 Andre Richter @@ -643,6 +646,7 @@ diff -uNr 16_virtual_mem_part4_higher_half_kernel/libraries/debug-symbol-types/s + +/// A symbol containing a size. +#[repr(C)] ++#[derive(Clone)] +pub struct Symbol { + addr_range: Range, + name: &'static str, @@ -669,6 +673,11 @@ diff -uNr 16_virtual_mem_part4_higher_half_kernel/libraries/debug-symbol-types/s + pub fn name(&self) -> &'static str { + self.name + } ++ ++ /// Returns the symbol's size. ++ pub fn size(&self) -> usize { ++ self.addr_range.end - self.addr_range.start ++ } +} diff -uNr 16_virtual_mem_part4_higher_half_kernel/Makefile 17_kernel_symbols/Makefile @@ -700,7 +709,7 @@ diff -uNr 16_virtual_mem_part4_higher_half_kernel/Makefile 17_kernel_symbols/Mak -@@ -178,11 +195,18 @@ +@@ -177,11 +194,19 @@ @$(DOCKER_TOOLS) $(EXEC_TT_TOOL) $(BSP) $(KERNEL_ELF_TTABLES) ##------------------------------------------------------------------------------ @@ -708,7 +717,8 @@ diff -uNr 16_virtual_mem_part4_higher_half_kernel/Makefile 17_kernel_symbols/Mak +##------------------------------------------------------------------------------ +$(KERNEL_ELF_TTABLES_SYMS): $(KERNEL_ELF_TTABLES_SYMS_DEPS) + $(call color_header, "Generating kernel symbols and patching kernel ELF") -+ @$(MAKE) --no-print-directory -f kernel_symbols.mk ++ @time -f "in moduloes" \ ++ $(MAKE) --no-print-directory -f kernel_symbols.mk + +##------------------------------------------------------------------------------ ## Generate the stripped kernel binary @@ -721,7 +731,7 @@ diff -uNr 16_virtual_mem_part4_higher_half_kernel/Makefile 17_kernel_symbols/Mak $(call color_progress_prefix, "Name") @echo $(KERNEL_BIN) $(call color_progress_prefix, "Size") -@@ -319,10 +343,19 @@ +@@ -318,10 +343,19 @@ cd $(shell pwd) TEST_ELF=$$(echo $$1 | sed -e 's/.*target/target/g') @@ -736,7 +746,7 @@ diff -uNr 16_virtual_mem_part4_higher_half_kernel/Makefile 17_kernel_symbols/Mak + # started by the same. + KERNEL_SYMBOLS_INPUT_ELF=$$TEST_ELF \ + KERNEL_SYMBOLS_OUTPUT_ELF=$$TEST_ELF_SYMS \ -+ $(MAKE) --no-print-directory -f kernel_symbols.mk ++ $(MAKE) --no-print-directory -f kernel_symbols.mk > /dev/null 2>&1 + + $(OBJCOPY_CMD) $$TEST_ELF_SYMS $$TEST_BINARY $(DOCKER_TEST) $(EXEC_TEST_DISPATCH) $(EXEC_QEMU) $(QEMU_TEST_ARGS) -kernel $$TEST_BINARY diff --git a/17_kernel_symbols/kernel/src/_arch/aarch64/exception.rs b/17_kernel_symbols/kernel/src/_arch/aarch64/exception.rs index 3515d956..6781758a 100644 --- a/17_kernel_symbols/kernel/src/_arch/aarch64/exception.rs +++ b/17_kernel_symbols/kernel/src/_arch/aarch64/exception.rs @@ -46,7 +46,7 @@ struct ExceptionContext { /// Saved program status. spsr_el1: SpsrEL1, - // Exception syndrome register. + /// Exception syndrome register. esr_el1: EsrEL1, } @@ -265,8 +265,10 @@ impl fmt::Display for ExceptionContext { writeln!( f, " Symbol: {}", - symbols::lookup_symbol(memory::Address::new(self.elr_el1 as usize)) - .unwrap_or("Symbol not found") + match symbols::lookup_symbol(memory::Address::new(self.elr_el1 as usize)) { + Some(sym) => sym.name(), + _ => "Symbol not found", + } )?; writeln!(f)?; writeln!(f, "General purpose register:")?; diff --git a/17_kernel_symbols/kernel/src/_arch/aarch64/exception.s b/17_kernel_symbols/kernel/src/_arch/aarch64/exception.s index 5aae30b9..91805ee7 100644 --- a/17_kernel_symbols/kernel/src/_arch/aarch64/exception.s +++ b/17_kernel_symbols/kernel/src/_arch/aarch64/exception.s @@ -9,6 +9,7 @@ /// Call the function provided by parameter `\handler` after saving the exception context. Provide /// the context as the first parameter to '\handler'. .macro CALL_WITH_CONTEXT handler +__vector_\handler: // Make room on the stack for the exception context. sub sp, sp, #16 * 17 @@ -47,6 +48,9 @@ // After returning from exception handling code, replay the saved context and return via // `eret`. b __exception_restore_context + +.size __vector_\handler, . - __vector_\handler +.type __vector_\handler, function .endm .macro FIQ_SUSPEND diff --git a/17_kernel_symbols/kernel/src/lib.rs b/17_kernel_symbols/kernel/src/lib.rs index 68f7e874..8e38ad6f 100644 --- a/17_kernel_symbols/kernel/src/lib.rs +++ b/17_kernel_symbols/kernel/src/lib.rs @@ -3,7 +3,9 @@ // Copyright (c) 2018-2022 Andre Richter // Rust embedded logo for `make doc`. -#![doc(html_logo_url = "https://raw.githubusercontent.com/rust-embedded/wg/master/assets/logo/ewg-logo-blue-white-on-transparent.png")] +#![doc( + html_logo_url = "https://raw.githubusercontent.com/rust-embedded/wg/master/assets/logo/ewg-logo-blue-white-on-transparent.png" +)] //! The `kernel` library. //! diff --git a/17_kernel_symbols/kernel/src/main.rs b/17_kernel_symbols/kernel/src/main.rs index c0c18818..5150f3af 100644 --- a/17_kernel_symbols/kernel/src/main.rs +++ b/17_kernel_symbols/kernel/src/main.rs @@ -3,7 +3,9 @@ // Copyright (c) 2018-2022 Andre Richter // Rust embedded logo for `make doc`. -#![doc(html_logo_url = "https://raw.githubusercontent.com/rust-embedded/wg/master/assets/logo/ewg-logo-blue-white-on-transparent.png")] +#![doc( + html_logo_url = "https://raw.githubusercontent.com/rust-embedded/wg/master/assets/logo/ewg-logo-blue-white-on-transparent.png" +)] //! The `kernel` binary. diff --git a/17_kernel_symbols/kernel/src/symbols.rs b/17_kernel_symbols/kernel/src/symbols.rs index bde40a60..22001389 100644 --- a/17_kernel_symbols/kernel/src/symbols.rs +++ b/17_kernel_symbols/kernel/src/symbols.rs @@ -47,11 +47,11 @@ fn kernel_symbols_slice() -> &'static [Symbol] { // Public Code //-------------------------------------------------------------------------------------------------- -/// Retrieve the symbol name corresponding to a virtual address, if any. -pub fn lookup_symbol(addr: Address) -> Option<&'static str> { +/// Retrieve the symbol corresponding to a virtual address, if any. +pub fn lookup_symbol(addr: Address) -> Option<&'static Symbol> { for i in kernel_symbols_slice() { if i.contains(addr.as_usize()) { - return Some(i.name()); + return Some(i); } } @@ -73,12 +73,14 @@ mod tests { let first_sym = lookup_symbol(Address::new( crate::common::is_aligned as *const usize as usize, )) - .unwrap(); + .unwrap() + .name(); assert_eq!(first_sym, "libkernel::common::is_aligned"); - let second_sym = - lookup_symbol(Address::new(crate::version as *const usize as usize)).unwrap(); + let second_sym = lookup_symbol(Address::new(crate::version as *const usize as usize)) + .unwrap() + .name(); assert_eq!(second_sym, "libkernel::version"); } diff --git a/17_kernel_symbols/libraries/debug-symbol-types/src/lib.rs b/17_kernel_symbols/libraries/debug-symbol-types/src/lib.rs index 4c12e86f..b6dff082 100644 --- a/17_kernel_symbols/libraries/debug-symbol-types/src/lib.rs +++ b/17_kernel_symbols/libraries/debug-symbol-types/src/lib.rs @@ -10,6 +10,7 @@ use core::ops::Range; /// A symbol containing a size. #[repr(C)] +#[derive(Clone)] pub struct Symbol { addr_range: Range, name: &'static str, @@ -36,4 +37,9 @@ impl Symbol { pub fn name(&self) -> &'static str { self.name } + + /// Returns the symbol's size. + pub fn size(&self) -> usize { + self.addr_range.end - self.addr_range.start + } } diff --git a/X1_JTAG_boot/Makefile b/X1_JTAG_boot/Makefile index d5395011..a497ad81 100644 --- a/X1_JTAG_boot/Makefile +++ b/X1_JTAG_boot/Makefile @@ -84,7 +84,6 @@ COMPILER_ARGS = --target=$(TARGET) \ RUSTC_CMD = cargo rustc $(COMPILER_ARGS) DOC_CMD = cargo doc $(COMPILER_ARGS) CLIPPY_CMD = cargo clippy $(COMPILER_ARGS) -CHECK_CMD = cargo check $(COMPILER_ARGS) OBJCOPY_CMD = rust-objcopy \ --strip-all \ -O binary diff --git a/X1_JTAG_boot/src/main.rs b/X1_JTAG_boot/src/main.rs index d2f9dbde..0502e1c9 100644 --- a/X1_JTAG_boot/src/main.rs +++ b/X1_JTAG_boot/src/main.rs @@ -3,7 +3,9 @@ // Copyright (c) 2018-2022 Andre Richter // Rust embedded logo for `make doc`. -#![doc(html_logo_url = "https://raw.githubusercontent.com/rust-embedded/wg/master/assets/logo/ewg-logo-blue-white-on-transparent.png")] +#![doc( + html_logo_url = "https://raw.githubusercontent.com/rust-embedded/wg/master/assets/logo/ewg-logo-blue-white-on-transparent.png" +)] //! The `kernel` binary. //! From cc09970b2d1d0dfa5517824b365c24a83e8dbae5 Mon Sep 17 00:00:00 2001 From: Zicklag Date: Wed, 27 Apr 2022 19:21:47 -0500 Subject: [PATCH 21/75] Add VSCode Rust Analyzer Settings Fixes errors reported by rust analyzer due to differing target and a missing cargo feature. --- .vscode/settings.json | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index d77cd337..292bf2a9 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,4 +1,10 @@ { "editor.formatOnSave": true, - "editor.rulers": [100] + "editor.rulers": [100], + "rust-analyzer.cargo.target": "aarch64-unknown-none-softfloat", + "rust-analyzer.cargo.features": ["bsp_rpi3"], + "rust-analyzer.checkOnSave.allTargets": false, + "rust-analyzer.checkOnSave.extraArgs": ["--lib", "--bins"], + "rust-analyzer.lens.debug": false, + "rust-analyzer.lens.run": false } From 8ff358a50b7b46217dff5c681371467d1af104f0 Mon Sep 17 00:00:00 2001 From: Andre Richter Date: Mon, 2 May 2022 23:24:29 +0200 Subject: [PATCH 22/75] Add tutorial 18 --- 18_backtrace/.cargo/config.toml | 2 + 18_backtrace/.vscode/settings.json | 10 + 18_backtrace/Cargo.lock | 96 ++ 18_backtrace/Cargo.toml | 11 + 18_backtrace/Makefile | 389 ++++++ 18_backtrace/README.md | 1244 +++++++++++++++++ 18_backtrace/kernel/Cargo.toml | 70 + 18_backtrace/kernel/build.rs | 20 + .../kernel/src/_arch/aarch64/backtrace.rs | 136 ++ 18_backtrace/kernel/src/_arch/aarch64/cpu.rs | 49 + .../kernel/src/_arch/aarch64/cpu/boot.rs | 113 ++ .../kernel/src/_arch/aarch64/cpu/boot.s | 100 ++ .../kernel/src/_arch/aarch64/cpu/smp.rs | 30 + .../kernel/src/_arch/aarch64/exception.rs | 323 +++++ .../kernel/src/_arch/aarch64/exception.s | 190 +++ .../_arch/aarch64/exception/asynchronous.rs | 152 ++ .../kernel/src/_arch/aarch64/memory/mmu.rs | 158 +++ .../aarch64/memory/mmu/translation_table.rs | 521 +++++++ 18_backtrace/kernel/src/_arch/aarch64/time.rs | 121 ++ 18_backtrace/kernel/src/backtrace.rs | 112 ++ 18_backtrace/kernel/src/bsp.rs | 13 + 18_backtrace/kernel/src/bsp/device_driver.rs | 16 + .../kernel/src/bsp/device_driver/arm.rs | 9 + .../kernel/src/bsp/device_driver/arm/gicv2.rs | 246 ++++ .../src/bsp/device_driver/arm/gicv2/gicc.rs | 156 +++ .../src/bsp/device_driver/arm/gicv2/gicd.rs | 209 +++ .../kernel/src/bsp/device_driver/bcm.rs | 15 + .../src/bsp/device_driver/bcm/bcm2xxx_gpio.rs | 259 ++++ .../bcm/bcm2xxx_interrupt_controller.rs | 138 ++ .../peripheral_ic.rs | 192 +++ .../device_driver/bcm/bcm2xxx_pl011_uart.rs | 536 +++++++ .../kernel/src/bsp/device_driver/common.rs | 38 + 18_backtrace/kernel/src/bsp/raspberrypi.rs | 62 + .../kernel/src/bsp/raspberrypi/console.rs | 98 ++ .../kernel/src/bsp/raspberrypi/cpu.rs | 14 + .../kernel/src/bsp/raspberrypi/driver.rs | 61 + .../kernel/src/bsp/raspberrypi/exception.rs | 7 + .../bsp/raspberrypi/exception/asynchronous.rs | 36 + .../kernel/src/bsp/raspberrypi/kernel.ld | 114 ++ .../kernel_virt_addr_space_size.ld | 1 + .../kernel/src/bsp/raspberrypi/memory.rs | 227 +++ .../kernel/src/bsp/raspberrypi/memory/mmu.rs | 179 +++ 18_backtrace/kernel/src/common.rs | 29 + 18_backtrace/kernel/src/console.rs | 53 + 18_backtrace/kernel/src/cpu.rs | 21 + 18_backtrace/kernel/src/cpu/boot.rs | 9 + 18_backtrace/kernel/src/cpu/smp.rs | 14 + 18_backtrace/kernel/src/driver.rs | 62 + 18_backtrace/kernel/src/exception.rs | 48 + .../kernel/src/exception/asynchronous.rs | 152 ++ 18_backtrace/kernel/src/lib.rs | 188 +++ 18_backtrace/kernel/src/main.rs | 111 ++ 18_backtrace/kernel/src/memory.rs | 191 +++ 18_backtrace/kernel/src/memory/mmu.rs | 270 ++++ 18_backtrace/kernel/src/memory/mmu/alloc.rs | 70 + .../kernel/src/memory/mmu/mapping_record.rs | 233 +++ .../src/memory/mmu/translation_table.rs | 137 ++ 18_backtrace/kernel/src/memory/mmu/types.rs | 378 +++++ 18_backtrace/kernel/src/panic_wait.rs | 106 ++ 18_backtrace/kernel/src/print.rs | 94 ++ 18_backtrace/kernel/src/state.rs | 92 ++ 18_backtrace/kernel/src/symbols.rs | 87 ++ 18_backtrace/kernel/src/synchronization.rs | 159 +++ 18_backtrace/kernel/src/time.rs | 37 + .../kernel/tests/00_console_sanity.rb | 48 + .../kernel/tests/00_console_sanity.rs | 39 + 18_backtrace/kernel/tests/01_timer_sanity.rs | 50 + .../tests/02_exception_sync_page_fault.rs | 37 + .../tests/03_exception_restore_sanity.rb | 25 + .../tests/03_exception_restore_sanity.rs | 49 + .../kernel/tests/04_exception_irq_sanity.rs | 67 + .../kernel/tests/05_backtrace_sanity.rb | 39 + .../kernel/tests/05_backtrace_sanity.rs | 31 + .../tests/06_backtrace_invalid_frame.rb | 26 + .../tests/06_backtrace_invalid_frame.rs | 33 + .../kernel/tests/07_backtrace_invalid_link.rb | 25 + .../kernel/tests/07_backtrace_invalid_link.rs | 38 + 18_backtrace/kernel/tests/boot_test_string.rb | 3 + .../kernel/tests/panic_exit_success/mod.rs | 9 + .../kernel/tests/panic_wait_forever/mod.rs | 9 + 18_backtrace/kernel_symbols.mk | 103 ++ 18_backtrace/kernel_symbols/Cargo.toml | 15 + 18_backtrace/kernel_symbols/build.rs | 14 + 18_backtrace/kernel_symbols/kernel_symbols.ld | 15 + 18_backtrace/kernel_symbols/src/main.rs | 16 + .../libraries/debug-symbol-types/Cargo.toml | 4 + .../libraries/debug-symbol-types/src/lib.rs | 45 + 18_backtrace/libraries/test-macros/Cargo.toml | 14 + 18_backtrace/libraries/test-macros/src/lib.rs | 29 + 18_backtrace/libraries/test-types/Cargo.toml | 5 + 18_backtrace/libraries/test-types/src/lib.rs | 16 + .../tools/kernel_symbols_tool/cmds.rb | 45 + .../tools/kernel_symbols_tool/kernel_elf.rb | 74 + .../tools/kernel_symbols_tool/main.rb | 47 + .../tools/translation_table_tool/arch.rb | 314 +++++ .../tools/translation_table_tool/bsp.rb | 50 + .../tools/translation_table_tool/generic.rb | 179 +++ .../translation_table_tool/kernel_elf.rb | 96 ++ .../tools/translation_table_tool/main.rb | 46 + doc/18_stack_frames.png | Bin 0 -> 47923 bytes 100 files changed, 10669 insertions(+) create mode 100644 18_backtrace/.cargo/config.toml create mode 100644 18_backtrace/.vscode/settings.json create mode 100644 18_backtrace/Cargo.lock create mode 100644 18_backtrace/Cargo.toml create mode 100644 18_backtrace/Makefile create mode 100644 18_backtrace/README.md create mode 100644 18_backtrace/kernel/Cargo.toml create mode 100644 18_backtrace/kernel/build.rs create mode 100644 18_backtrace/kernel/src/_arch/aarch64/backtrace.rs create mode 100644 18_backtrace/kernel/src/_arch/aarch64/cpu.rs create mode 100644 18_backtrace/kernel/src/_arch/aarch64/cpu/boot.rs create mode 100644 18_backtrace/kernel/src/_arch/aarch64/cpu/boot.s create mode 100644 18_backtrace/kernel/src/_arch/aarch64/cpu/smp.rs create mode 100644 18_backtrace/kernel/src/_arch/aarch64/exception.rs create mode 100644 18_backtrace/kernel/src/_arch/aarch64/exception.s create mode 100644 18_backtrace/kernel/src/_arch/aarch64/exception/asynchronous.rs create mode 100644 18_backtrace/kernel/src/_arch/aarch64/memory/mmu.rs create mode 100644 18_backtrace/kernel/src/_arch/aarch64/memory/mmu/translation_table.rs create mode 100644 18_backtrace/kernel/src/_arch/aarch64/time.rs create mode 100644 18_backtrace/kernel/src/backtrace.rs create mode 100644 18_backtrace/kernel/src/bsp.rs create mode 100644 18_backtrace/kernel/src/bsp/device_driver.rs create mode 100644 18_backtrace/kernel/src/bsp/device_driver/arm.rs create mode 100644 18_backtrace/kernel/src/bsp/device_driver/arm/gicv2.rs create mode 100644 18_backtrace/kernel/src/bsp/device_driver/arm/gicv2/gicc.rs create mode 100644 18_backtrace/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs create mode 100644 18_backtrace/kernel/src/bsp/device_driver/bcm.rs create mode 100644 18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs create mode 100644 18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs create mode 100644 18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs create mode 100644 18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs create mode 100644 18_backtrace/kernel/src/bsp/device_driver/common.rs create mode 100644 18_backtrace/kernel/src/bsp/raspberrypi.rs create mode 100644 18_backtrace/kernel/src/bsp/raspberrypi/console.rs create mode 100644 18_backtrace/kernel/src/bsp/raspberrypi/cpu.rs create mode 100644 18_backtrace/kernel/src/bsp/raspberrypi/driver.rs create mode 100644 18_backtrace/kernel/src/bsp/raspberrypi/exception.rs create mode 100644 18_backtrace/kernel/src/bsp/raspberrypi/exception/asynchronous.rs create mode 100644 18_backtrace/kernel/src/bsp/raspberrypi/kernel.ld create mode 100644 18_backtrace/kernel/src/bsp/raspberrypi/kernel_virt_addr_space_size.ld create mode 100644 18_backtrace/kernel/src/bsp/raspberrypi/memory.rs create mode 100644 18_backtrace/kernel/src/bsp/raspberrypi/memory/mmu.rs create mode 100644 18_backtrace/kernel/src/common.rs create mode 100644 18_backtrace/kernel/src/console.rs create mode 100644 18_backtrace/kernel/src/cpu.rs create mode 100644 18_backtrace/kernel/src/cpu/boot.rs create mode 100644 18_backtrace/kernel/src/cpu/smp.rs create mode 100644 18_backtrace/kernel/src/driver.rs create mode 100644 18_backtrace/kernel/src/exception.rs create mode 100644 18_backtrace/kernel/src/exception/asynchronous.rs create mode 100644 18_backtrace/kernel/src/lib.rs create mode 100644 18_backtrace/kernel/src/main.rs create mode 100644 18_backtrace/kernel/src/memory.rs create mode 100644 18_backtrace/kernel/src/memory/mmu.rs create mode 100644 18_backtrace/kernel/src/memory/mmu/alloc.rs create mode 100644 18_backtrace/kernel/src/memory/mmu/mapping_record.rs create mode 100644 18_backtrace/kernel/src/memory/mmu/translation_table.rs create mode 100644 18_backtrace/kernel/src/memory/mmu/types.rs create mode 100644 18_backtrace/kernel/src/panic_wait.rs create mode 100644 18_backtrace/kernel/src/print.rs create mode 100644 18_backtrace/kernel/src/state.rs create mode 100644 18_backtrace/kernel/src/symbols.rs create mode 100644 18_backtrace/kernel/src/synchronization.rs create mode 100644 18_backtrace/kernel/src/time.rs create mode 100644 18_backtrace/kernel/tests/00_console_sanity.rb create mode 100644 18_backtrace/kernel/tests/00_console_sanity.rs create mode 100644 18_backtrace/kernel/tests/01_timer_sanity.rs create mode 100644 18_backtrace/kernel/tests/02_exception_sync_page_fault.rs create mode 100644 18_backtrace/kernel/tests/03_exception_restore_sanity.rb create mode 100644 18_backtrace/kernel/tests/03_exception_restore_sanity.rs create mode 100644 18_backtrace/kernel/tests/04_exception_irq_sanity.rs create mode 100644 18_backtrace/kernel/tests/05_backtrace_sanity.rb create mode 100644 18_backtrace/kernel/tests/05_backtrace_sanity.rs create mode 100644 18_backtrace/kernel/tests/06_backtrace_invalid_frame.rb create mode 100644 18_backtrace/kernel/tests/06_backtrace_invalid_frame.rs create mode 100644 18_backtrace/kernel/tests/07_backtrace_invalid_link.rb create mode 100644 18_backtrace/kernel/tests/07_backtrace_invalid_link.rs create mode 100644 18_backtrace/kernel/tests/boot_test_string.rb create mode 100644 18_backtrace/kernel/tests/panic_exit_success/mod.rs create mode 100644 18_backtrace/kernel/tests/panic_wait_forever/mod.rs create mode 100644 18_backtrace/kernel_symbols.mk create mode 100644 18_backtrace/kernel_symbols/Cargo.toml create mode 100644 18_backtrace/kernel_symbols/build.rs create mode 100644 18_backtrace/kernel_symbols/kernel_symbols.ld create mode 100644 18_backtrace/kernel_symbols/src/main.rs create mode 100644 18_backtrace/libraries/debug-symbol-types/Cargo.toml create mode 100644 18_backtrace/libraries/debug-symbol-types/src/lib.rs create mode 100644 18_backtrace/libraries/test-macros/Cargo.toml create mode 100644 18_backtrace/libraries/test-macros/src/lib.rs create mode 100644 18_backtrace/libraries/test-types/Cargo.toml create mode 100644 18_backtrace/libraries/test-types/src/lib.rs create mode 100644 18_backtrace/tools/kernel_symbols_tool/cmds.rb create mode 100644 18_backtrace/tools/kernel_symbols_tool/kernel_elf.rb create mode 100755 18_backtrace/tools/kernel_symbols_tool/main.rb create mode 100644 18_backtrace/tools/translation_table_tool/arch.rb create mode 100644 18_backtrace/tools/translation_table_tool/bsp.rb create mode 100644 18_backtrace/tools/translation_table_tool/generic.rb create mode 100644 18_backtrace/tools/translation_table_tool/kernel_elf.rb create mode 100755 18_backtrace/tools/translation_table_tool/main.rb create mode 100644 doc/18_stack_frames.png diff --git a/18_backtrace/.cargo/config.toml b/18_backtrace/.cargo/config.toml new file mode 100644 index 00000000..e3476485 --- /dev/null +++ b/18_backtrace/.cargo/config.toml @@ -0,0 +1,2 @@ +[target.'cfg(target_os = "none")'] +runner = "target/kernel_test_runner.sh" diff --git a/18_backtrace/.vscode/settings.json b/18_backtrace/.vscode/settings.json new file mode 100644 index 00000000..292bf2a9 --- /dev/null +++ b/18_backtrace/.vscode/settings.json @@ -0,0 +1,10 @@ +{ + "editor.formatOnSave": true, + "editor.rulers": [100], + "rust-analyzer.cargo.target": "aarch64-unknown-none-softfloat", + "rust-analyzer.cargo.features": ["bsp_rpi3"], + "rust-analyzer.checkOnSave.allTargets": false, + "rust-analyzer.checkOnSave.extraArgs": ["--lib", "--bins"], + "rust-analyzer.lens.debug": false, + "rust-analyzer.lens.run": false +} diff --git a/18_backtrace/Cargo.lock b/18_backtrace/Cargo.lock new file mode 100644 index 00000000..b851d8e3 --- /dev/null +++ b/18_backtrace/Cargo.lock @@ -0,0 +1,96 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "cortex-a" +version = "7.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27bd91f65ccd348bb2d043d98c5b34af141ecef7f102147f59bf5898f6e734ad" +dependencies = [ + "tock-registers", +] + +[[package]] +name = "debug-symbol-types" +version = "0.1.0" + +[[package]] +name = "kernel_symbols" +version = "0.1.0" +dependencies = [ + "debug-symbol-types", +] + +[[package]] +name = "mingo" +version = "0.18.0" +dependencies = [ + "cortex-a", + "debug-symbol-types", + "qemu-exit", + "test-macros", + "test-types", + "tock-registers", +] + +[[package]] +name = "proc-macro2" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec757218438d5fda206afc041538b2f6d889286160d649a86a24d37e1235afd1" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "qemu-exit" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ff023245bfcc73fb890e1f8d5383825b3131cc920020a5c487d6f113dfc428a" + +[[package]] +name = "quote" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "syn" +version = "1.0.91" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b683b2b825c8eef438b77c36a06dc262294da3d5a5813fac20da149241dcd44d" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "test-macros" +version = "0.1.0" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "test-types", +] + +[[package]] +name = "test-types" +version = "0.1.0" + +[[package]] +name = "tock-registers" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ee8fba06c1f4d0b396ef61a54530bb6b28f0dc61c38bc8bc5a5a48161e6282e" + +[[package]] +name = "unicode-xid" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" diff --git a/18_backtrace/Cargo.toml b/18_backtrace/Cargo.toml new file mode 100644 index 00000000..38eeb116 --- /dev/null +++ b/18_backtrace/Cargo.toml @@ -0,0 +1,11 @@ +[workspace] + +members = [ + "libraries/*", + "kernel", + "kernel_symbols" +] + +[profile.release] +lto = true +debug = true diff --git a/18_backtrace/Makefile b/18_backtrace/Makefile new file mode 100644 index 00000000..85826c12 --- /dev/null +++ b/18_backtrace/Makefile @@ -0,0 +1,389 @@ +## SPDX-License-Identifier: MIT OR Apache-2.0 +## +## Copyright (c) 2018-2022 Andre Richter + +include ../common/format.mk +include ../common/docker.mk + +##-------------------------------------------------------------------------------------------------- +## Optional, user-provided configuration values +##-------------------------------------------------------------------------------------------------- + +# Default to the RPi3. +BSP ?= rpi3 + +# Default to a serial device name that is common in Linux. +DEV_SERIAL ?= /dev/ttyUSB0 + +# Optional integration test name. +ifdef TEST + TEST_ARG = --test $(TEST) +else + TEST_ARG = --test '*' +endif + + + +##-------------------------------------------------------------------------------------------------- +## BSP-specific configuration values +##-------------------------------------------------------------------------------------------------- +QEMU_MISSING_STRING = "This board is not yet supported for QEMU." + +ifeq ($(BSP),rpi3) + TARGET = aarch64-unknown-none-softfloat + KERNEL_BIN = kernel8.img + QEMU_BINARY = qemu-system-aarch64 + QEMU_MACHINE_TYPE = raspi3 + QEMU_RELEASE_ARGS = -serial stdio -display none + QEMU_TEST_ARGS = $(QEMU_RELEASE_ARGS) -semihosting + OBJDUMP_BINARY = aarch64-none-elf-objdump + NM_BINARY = aarch64-none-elf-nm + READELF_BINARY = aarch64-none-elf-readelf + OPENOCD_ARG = -f /openocd/tcl/interface/ftdi/olimex-arm-usb-tiny-h.cfg -f /openocd/rpi3.cfg + JTAG_BOOT_IMAGE = ../X1_JTAG_boot/jtag_boot_rpi3.img + LD_SCRIPT_PATH = $(shell pwd)/kernel/src/bsp/raspberrypi + RUSTC_MISC_ARGS = -C target-cpu=cortex-a53 -C force-frame-pointers +else ifeq ($(BSP),rpi4) + TARGET = aarch64-unknown-none-softfloat + KERNEL_BIN = kernel8.img + QEMU_BINARY = qemu-system-aarch64 + QEMU_MACHINE_TYPE = + QEMU_RELEASE_ARGS = -serial stdio -display none + QEMU_TEST_ARGS = $(QEMU_RELEASE_ARGS) -semihosting + OBJDUMP_BINARY = aarch64-none-elf-objdump + NM_BINARY = aarch64-none-elf-nm + READELF_BINARY = aarch64-none-elf-readelf + OPENOCD_ARG = -f /openocd/tcl/interface/ftdi/olimex-arm-usb-tiny-h.cfg -f /openocd/rpi4.cfg + JTAG_BOOT_IMAGE = ../X1_JTAG_boot/jtag_boot_rpi4.img + LD_SCRIPT_PATH = $(shell pwd)/kernel/src/bsp/raspberrypi + RUSTC_MISC_ARGS = -C target-cpu=cortex-a72 -C force-frame-pointers +endif + +# Export for build.rs. +export LD_SCRIPT_PATH + + + +##-------------------------------------------------------------------------------------------------- +## Targets and Prerequisites +##-------------------------------------------------------------------------------------------------- +KERNEL_MANIFEST = kernel/Cargo.toml +KERNEL_LINKER_SCRIPT = kernel.ld +LAST_BUILD_CONFIG = target/$(BSP).build_config + +KERNEL_ELF_RAW = target/$(TARGET)/release/kernel +# This parses cargo's dep-info file. +# https://doc.rust-lang.org/cargo/guide/build-cache.html#dep-info-files +KERNEL_ELF_RAW_DEPS = $(filter-out %: ,$(file < $(KERNEL_ELF_RAW).d)) $(LAST_BUILD_CONFIG) + +##------------------------------------------------------------------------------ +## Translation tables +##------------------------------------------------------------------------------ +TT_TOOL_PATH = tools/translation_table_tool + +KERNEL_ELF_TTABLES = target/$(TARGET)/release/kernel+ttables +KERNEL_ELF_TTABLES_DEPS = $(KERNEL_ELF_RAW) $(wildcard $(TT_TOOL_PATH)/*) + +##------------------------------------------------------------------------------ +## Kernel symbols +##------------------------------------------------------------------------------ +export KERNEL_SYMBOLS_TOOL_PATH = tools/kernel_symbols_tool + +KERNEL_ELF_TTABLES_SYMS = target/$(TARGET)/release/kernel+ttables+symbols + +# Unlike with KERNEL_ELF_RAW, we are not relying on dep-info here. One of the reasons being that the +# name of the generated symbols file varies between runs, which can cause confusion. +KERNEL_ELF_TTABLES_SYMS_DEPS = $(KERNEL_ELF_TTABLES) \ + $(wildcard kernel_symbols/*) \ + $(wildcard $(KERNEL_SYMBOLS_TOOL_PATH)/*) + +export TARGET +export KERNEL_SYMBOLS_INPUT_ELF = $(KERNEL_ELF_TTABLES) +export KERNEL_SYMBOLS_OUTPUT_ELF = $(KERNEL_ELF_TTABLES_SYMS) + +KERNEL_ELF = $(KERNEL_ELF_TTABLES_SYMS) + + + +##-------------------------------------------------------------------------------------------------- +## Command building blocks +##-------------------------------------------------------------------------------------------------- +RUSTFLAGS = $(RUSTC_MISC_ARGS) \ + -C link-arg=--library-path=$(LD_SCRIPT_PATH) \ + -C link-arg=--script=$(KERNEL_LINKER_SCRIPT) + +RUSTFLAGS_PEDANTIC = $(RUSTFLAGS) \ + -D warnings \ + -D missing_docs + +FEATURES = --features bsp_$(BSP) +COMPILER_ARGS = --target=$(TARGET) \ + $(FEATURES) \ + --release + +# build-std can be skipped for helper commands that do not rely on correct stack frames and other +# custom compiler options. This results in a huge speedup. +RUSTC_CMD = cargo rustc $(COMPILER_ARGS) -Z build-std=core --manifest-path $(KERNEL_MANIFEST) +DOC_CMD = cargo doc $(COMPILER_ARGS) +CLIPPY_CMD = cargo clippy $(COMPILER_ARGS) +TEST_CMD = cargo test $(COMPILER_ARGS) -Z build-std=core --manifest-path $(KERNEL_MANIFEST) +OBJCOPY_CMD = rust-objcopy \ + --strip-all \ + -O binary + +EXEC_QEMU = $(QEMU_BINARY) -M $(QEMU_MACHINE_TYPE) +EXEC_TT_TOOL = ruby $(TT_TOOL_PATH)/main.rb +EXEC_TEST_DISPATCH = ruby ../common/tests/dispatch.rb +EXEC_MINIPUSH = ruby ../common/serial/minipush.rb + +##------------------------------------------------------------------------------ +## Dockerization +##------------------------------------------------------------------------------ +DOCKER_CMD = docker run -t --rm -v $(shell pwd):/work/tutorial -w /work/tutorial +DOCKER_CMD_INTERACT = $(DOCKER_CMD) -i +DOCKER_ARG_DIR_COMMON = -v $(shell pwd)/../common:/work/common +DOCKER_ARG_DIR_JTAG = -v $(shell pwd)/../X1_JTAG_boot:/work/X1_JTAG_boot +DOCKER_ARG_DEV = --privileged -v /dev:/dev +DOCKER_ARG_NET = --network host + +# DOCKER_IMAGE defined in include file (see top of this file). +DOCKER_QEMU = $(DOCKER_CMD_INTERACT) $(DOCKER_IMAGE) +DOCKER_TOOLS = $(DOCKER_CMD) $(DOCKER_IMAGE) +DOCKER_TEST = $(DOCKER_CMD) $(DOCKER_ARG_DIR_COMMON) $(DOCKER_IMAGE) +DOCKER_GDB = $(DOCKER_CMD_INTERACT) $(DOCKER_ARG_NET) $(DOCKER_IMAGE) + +# Dockerize commands, which require USB device passthrough, only on Linux. +ifeq ($(shell uname -s),Linux) + DOCKER_CMD_DEV = $(DOCKER_CMD_INTERACT) $(DOCKER_ARG_DEV) + + DOCKER_CHAINBOOT = $(DOCKER_CMD_DEV) $(DOCKER_ARG_DIR_COMMON) $(DOCKER_IMAGE) + DOCKER_JTAGBOOT = $(DOCKER_CMD_DEV) $(DOCKER_ARG_DIR_COMMON) $(DOCKER_ARG_DIR_JTAG) $(DOCKER_IMAGE) + DOCKER_OPENOCD = $(DOCKER_CMD_DEV) $(DOCKER_ARG_NET) $(DOCKER_IMAGE) +else + DOCKER_OPENOCD = echo "Not yet supported on non-Linux systems."; \# +endif + + + +##-------------------------------------------------------------------------------------------------- +## Targets +##-------------------------------------------------------------------------------------------------- +.PHONY: all doc qemu chainboot clippy clean readelf objdump nm check + +all: $(KERNEL_BIN) + +##------------------------------------------------------------------------------ +## Save the configuration as a file, so make understands if it changed. +##------------------------------------------------------------------------------ +$(LAST_BUILD_CONFIG): + @rm -f target/*.build_config + @mkdir -p target + @touch $(LAST_BUILD_CONFIG) + +##------------------------------------------------------------------------------ +## Compile the kernel ELF +##------------------------------------------------------------------------------ +$(KERNEL_ELF_RAW): $(KERNEL_ELF_RAW_DEPS) + $(call color_header, "Compiling kernel ELF - $(BSP)") + @RUSTFLAGS="$(RUSTFLAGS_PEDANTIC)" $(RUSTC_CMD) + +##------------------------------------------------------------------------------ +## Precompute the kernel translation tables and patch them into the kernel ELF +##------------------------------------------------------------------------------ +$(KERNEL_ELF_TTABLES): $(KERNEL_ELF_TTABLES_DEPS) + $(call color_header, "Precomputing kernel translation tables and patching kernel ELF") + @cp $(KERNEL_ELF_RAW) $(KERNEL_ELF_TTABLES) + @$(DOCKER_TOOLS) $(EXEC_TT_TOOL) $(BSP) $(KERNEL_ELF_TTABLES) + +##------------------------------------------------------------------------------ +## Generate kernel symbols and patch them into the kernel ELF +##------------------------------------------------------------------------------ +$(KERNEL_ELF_TTABLES_SYMS): $(KERNEL_ELF_TTABLES_SYMS_DEPS) + $(call color_header, "Generating kernel symbols and patching kernel ELF") + @time -f "in %es" \ + $(MAKE) --no-print-directory -f kernel_symbols.mk + +##------------------------------------------------------------------------------ +## Generate the stripped kernel binary +##------------------------------------------------------------------------------ +$(KERNEL_BIN): $(KERNEL_ELF_TTABLES_SYMS) + $(call color_header, "Generating stripped binary") + @$(OBJCOPY_CMD) $(KERNEL_ELF_TTABLES_SYMS) $(KERNEL_BIN) + $(call color_progress_prefix, "Name") + @echo $(KERNEL_BIN) + $(call color_progress_prefix, "Size") + @printf '%s KiB\n' `du -k $(KERNEL_BIN) | cut -f1` + +##------------------------------------------------------------------------------ +## Generate the documentation +##------------------------------------------------------------------------------ +doc: + $(call color_header, "Generating docs") + @$(DOC_CMD) --document-private-items --open + +##------------------------------------------------------------------------------ +## Run the kernel in QEMU +##------------------------------------------------------------------------------ +ifeq ($(QEMU_MACHINE_TYPE),) # QEMU is not supported for the board. + +qemu: + $(call color_header, "$(QEMU_MISSING_STRING)") + +else # QEMU is supported. + +qemu: $(KERNEL_BIN) + $(call color_header, "Launching QEMU") + @$(DOCKER_QEMU) $(EXEC_QEMU) $(QEMU_RELEASE_ARGS) -kernel $(KERNEL_BIN) + +endif + +##------------------------------------------------------------------------------ +## Push the kernel to the real HW target +##------------------------------------------------------------------------------ +chainboot: $(KERNEL_BIN) + @$(DOCKER_CHAINBOOT) $(EXEC_MINIPUSH) $(DEV_SERIAL) $(KERNEL_BIN) + +##------------------------------------------------------------------------------ +## Run clippy +##------------------------------------------------------------------------------ +clippy: + @RUSTFLAGS="$(RUSTFLAGS_PEDANTIC)" $(CLIPPY_CMD) + @RUSTFLAGS="$(RUSTFLAGS_PEDANTIC)" $(CLIPPY_CMD) --features test_build --tests \ + --manifest-path $(KERNEL_MANIFEST) + +##------------------------------------------------------------------------------ +## Clean +##------------------------------------------------------------------------------ +clean: + rm -rf target $(KERNEL_BIN) + +##------------------------------------------------------------------------------ +## Run readelf +##------------------------------------------------------------------------------ +readelf: $(KERNEL_ELF) + $(call color_header, "Launching readelf") + @$(DOCKER_TOOLS) $(READELF_BINARY) --headers $(KERNEL_ELF) + +##------------------------------------------------------------------------------ +## Run objdump +##------------------------------------------------------------------------------ +objdump: $(KERNEL_ELF) + $(call color_header, "Launching objdump") + @$(DOCKER_TOOLS) $(OBJDUMP_BINARY) --disassemble --demangle \ + --section .text \ + --section .rodata \ + --section .got \ + $(KERNEL_ELF) | rustfilt + +##------------------------------------------------------------------------------ +## Run nm +##------------------------------------------------------------------------------ +nm: $(KERNEL_ELF) + $(call color_header, "Launching nm") + @$(DOCKER_TOOLS) $(NM_BINARY) --demangle --print-size $(KERNEL_ELF) | sort | rustfilt + + + +##-------------------------------------------------------------------------------------------------- +## Debugging targets +##-------------------------------------------------------------------------------------------------- +.PHONY: jtagboot openocd gdb gdb-opt0 + +##------------------------------------------------------------------------------ +## Push the JTAG boot image to the real HW target +##------------------------------------------------------------------------------ +jtagboot: + @$(DOCKER_JTAGBOOT) $(EXEC_MINIPUSH) $(DEV_SERIAL) $(JTAG_BOOT_IMAGE) + +##------------------------------------------------------------------------------ +## Start OpenOCD session +##------------------------------------------------------------------------------ +openocd: + $(call color_header, "Launching OpenOCD") + @$(DOCKER_OPENOCD) openocd $(OPENOCD_ARG) + +##------------------------------------------------------------------------------ +## Start GDB session +##------------------------------------------------------------------------------ +gdb-opt0: RUSTC_MISC_ARGS += -C opt-level=0 +gdb gdb-opt0: $(KERNEL_ELF) + $(call color_header, "Launching GDB") + @$(DOCKER_GDB) gdb-multiarch -q $(KERNEL_ELF) + + + +##-------------------------------------------------------------------------------------------------- +## Testing targets +##-------------------------------------------------------------------------------------------------- +.PHONY: test test_boot test_unit test_integration + +test_unit test_integration: FEATURES += --features test_build + +ifeq ($(QEMU_MACHINE_TYPE),) # QEMU is not supported for the board. + +test_boot test_unit test_integration test: + $(call color_header, "$(QEMU_MISSING_STRING)") + +else # QEMU is supported. + +##------------------------------------------------------------------------------ +## Run boot test +##------------------------------------------------------------------------------ +test_boot: $(KERNEL_BIN) + $(call color_header, "Boot test - $(BSP)") + @$(DOCKER_TEST) $(EXEC_TEST_DISPATCH) $(EXEC_QEMU) $(QEMU_RELEASE_ARGS) -kernel $(KERNEL_BIN) + +##------------------------------------------------------------------------------ +## Helpers for unit and integration test targets +##------------------------------------------------------------------------------ +define KERNEL_TEST_RUNNER + #!/usr/bin/env bash + + # The cargo test runner seems to change into the crate under test's directory. Therefore, ensure + # this script executes from the root. + cd $(shell pwd) + + TEST_ELF=$$(echo $$1 | sed -e 's/.*target/target/g') + TEST_ELF_SYMS="$${TEST_ELF}_syms" + TEST_BINARY=$$(echo $$1.img | sed -e 's/.*target/target/g') + + $(DOCKER_TOOLS) $(EXEC_TT_TOOL) $(BSP) $$TEST_ELF > /dev/null + + # This overrides the two ENV variables. The other ENV variables that are required as input for + # the .mk file are set already because they are exported by this Makefile and this script is + # started by the same. + KERNEL_SYMBOLS_INPUT_ELF=$$TEST_ELF \ + KERNEL_SYMBOLS_OUTPUT_ELF=$$TEST_ELF_SYMS \ + $(MAKE) --no-print-directory -f kernel_symbols.mk > /dev/null 2>&1 + + $(OBJCOPY_CMD) $$TEST_ELF_SYMS $$TEST_BINARY + $(DOCKER_TEST) $(EXEC_TEST_DISPATCH) $(EXEC_QEMU) $(QEMU_TEST_ARGS) -kernel $$TEST_BINARY +endef + +export KERNEL_TEST_RUNNER + +define test_prepare + @mkdir -p target + @echo "$$KERNEL_TEST_RUNNER" > target/kernel_test_runner.sh + @chmod +x target/kernel_test_runner.sh +endef + +##------------------------------------------------------------------------------ +## Run unit test(s) +##------------------------------------------------------------------------------ +test_unit: + $(call color_header, "Compiling unit test(s) - $(BSP)") + $(call test_prepare) + @RUSTFLAGS="$(RUSTFLAGS_PEDANTIC)" $(TEST_CMD) --lib + +##------------------------------------------------------------------------------ +## Run integration test(s) +##------------------------------------------------------------------------------ +test_integration: + $(call color_header, "Compiling integration test(s) - $(BSP)") + $(call test_prepare) + @RUSTFLAGS="$(RUSTFLAGS_PEDANTIC)" $(TEST_CMD) $(TEST_ARG) + +test: test_boot test_unit test_integration + +endif diff --git a/18_backtrace/README.md b/18_backtrace/README.md new file mode 100644 index 00000000..0963df1d --- /dev/null +++ b/18_backtrace/README.md @@ -0,0 +1,1244 @@ +# Tutorial 18 - Backtracing + +## tl;dr + +- Support for [`backtracing`] is implemented into the kernel. + +```console +[ 0.002782] Writing to bottom of address space to address 1 GiB... +[ 0.004623] Kernel panic! + +Panic location: + File 'kernel/src/_arch/aarch64/exception.rs', line 59, column 5 + +[...] + +Backtrace: + ---------------------------------------------------------------------------------------------- + Address Function containing address + ---------------------------------------------------------------------------------------------- + 1. ffffffffc0001294 | core::fmt::write + 2. ffffffffc0005560 | libkernel::panic_wait::_panic_print + 3. ffffffffc00054a0 | rust_begin_unwind + 4. ffffffffc0002950 | core::panicking::panic_fmt + 5. ffffffffc0004898 | current_elx_synchronous + 6. ffffffffc0000a74 | __vector_current_elx_synchronous + 7. ffffffffc000111c | kernel_init + ---------------------------------------------------------------------------------------------- +``` + +[`backtracing`]: https://en.wikipedia.org/wiki/Stack_trace + +## Table of Contents + +- [Introduction](#introduction) +- [Implementation](#implementation) + - [Chasing Frames](#chasing-frames) + - [Compiler Changes](#compiler-changes) + - [Supporting Changes](#supporting-changes) +- [Test it](#test-it) +- [Diff to previous](#diff-to-previous) + +## Introduction + +Since the kernel gained support for looking up `symbol names` in the previous tutorial, it is now +possible to implement support for printing meaningful backtraces (also called `stack traces`). The +primary use-case will be printing backtraces during a `panic`, which will ease debugging. This is a +good time to add this feature, since some of the upcoming tutorials will cover complex topics and +code changes, so that this will come in handy during development. + +## Implementation + +Since backtracing is a scheme that is usually defined in the [`calling-convention`], and therefore +tightly coupled to the `processor architecture `, the heart of the backtracing code will live in the +`_arch` folder. What can be shared between different architectures is the formatting and printing +part. Hence, the code will be organized as follows: + +[`calling-convention`]: https://en.wikipedia.org/wiki/Calling_convention + +- `src/backtrace.rs` makes a generic definition of a `BacktraceItem`. It also provides code that + uses an `Iterator` to format and print the backtrace. +- `src/__arch_name__/backtrace.rs` contains the code that generates the actual iterator. + +Here is the definition of `BacktraceItem`: + +```rust +pub enum BacktraceItem { + InvalidFramePointer(Address), + InvalidLink(Address), + Link(Address), +} +``` + +In summary, it has two error cases and one valid case. This will become clearer in a minute when we +look at what a `stack frame` and a `frame pointer` is. + +### Chasing Frames + +For `AArch64`, we need to consult the [Procedure Call Standard for the Arm® 64-bit Architecture] +(`AAPCS64`). It has the following to say: + +> Conforming code shall construct a *linked list* of stack-frames. Each frame shall link to the +> frame of its caller by means of a frame record of two 64-bit values on the stack (independent of +> the data model). The frame record for the innermost frame (belonging to the most recent routine +> invocation) shall be pointed to by the frame pointer register (FP). The lowest addressed +> double-word shall point to the previous frame record and the highest addressed double-word shall +> contain the value passed in LR on entry to the current function [...]. The location of the frame +> record within a stack frame is not specified. + +[Procedure Call Standard for the Arm® 64-bit Architecture]: https://github.com/ARM-software/abi-aa/blob/main/aapcs64/aapcs64.rst + +The nature of the `linked list` becomes a bit clearer when we look into the corresponding section in +the [ARM Cortex-A Series Programmer’s Guide for ARMv8-A] as well. Here are text and picture +snippets: + +> An AAPC64 stack frame shown in Figure 9-2. The frame pointer (X29) should point to the previous +> frame pointer saved on stack, with the saved LR (X30) stored after it. The final frame pointer in +> the chain should be set to 0. The Stack Pointer must always be aligned on a 16 byte boundary. + +[ARM Cortex-A Series Programmer’s Guide for ARMv8-A]: https://developer.arm.com/documentation/den0024/latest/ + +

+ +

+ +Hence, we can define the following struct in `src/__arch_name__/backtrace.rs` for the stack frame +record: + +```rust +#[repr(C)] +struct StackFrameRecord<'a> { + previous_record: Option<&'a StackFrameRecord<'a>>, + link: Address, +} +``` + +The interesting part is the `previous_record` member. We learned from the two documents which we +inspected above that the lowest addressed double-word is either: + +- Zero. +- Or pointing to the previous stack frame record. + +Thanks to Rust's null pointer optimization [[1]][[2]], this allows us to conveniently type this as +an `Option<&StackFrameRecord>`. So whenever we inspect `previous_record` and observe it to be +`None`, we know that we've reached the end of the backtrace. + +[1]: https://doc.rust-lang.org/std/option/#representation +[2]: https://stackoverflow.com/a/46557737 + +The start of the backtrace is trivially accessed through `x29` (aka the `Frame Pointer Register`). +This is used to generate a `StackFrameIterator`: + +```rust +struct StackFrameRecordIterator<'a> { + cur: &'a StackFrameRecord<'a>, +} + +/// [...] + +fn stack_frame_record_iterator<'a>() -> Option> { + let fp = Address::::new(FP.get() as usize); + if !fp.is_valid_stack_addr() { + return None; + } + + Some(StackFrameRecordIterator { + cur: unsafe { &*(fp.as_usize() as *const _) }, + }) +} +``` + +Although it should be guaranteed by the compiler (and any hand-written assembly) that `x29` points +to a valid stack address, it makes sense to double-check this before generating a reference. There +is always a chance that corruption happens. The implementation of the iterator itself does this +sanity check as well whenever the iterator is advanced. Additionally, it is also checked whether the +`link` address points to a valid `code` section in the kernel before the address is passed on to +the caller of the iterator: + +```rust +impl<'a> Iterator for StackFrameRecordIterator<'a> { + type Item = BacktraceItem; + + fn next(&mut self) -> Option { + static ABORT_FRAME: StackFrameRecord = StackFrameRecord { + previous_record: None, + link: Address::new(0), + }; + + // If previous is None, this is the root frame, so iteration will stop here. + let previous = self.cur.previous_record?; + + // Need to abort if the pointer to the previous frame record is invalid. + let prev_addr = Address::::new(previous as *const _ as usize); + if !prev_addr.is_valid_stack_addr() { + // This allows to return the error and then stop on the next iteration. + self.cur = &ABORT_FRAME; + return Some(BacktraceItem::InvalidFramePointer(prev_addr)); + } + + let ret = if !self.cur.link.is_valid_code_addr() { + Some(BacktraceItem::InvalidLink(self.cur.link)) + } else { + // The link points to the instruction to be executed _after_ returning from a branch. + // However, we want to show the instruction that caused the branch, so subtract by one + // instruction. + // + // This might be called from panic!, so it must not panic itself on the subtraction. + let link = if self.cur.link >= Address::new(4) { + self.cur.link - 4 + } else { + self.cur.link + }; + + Some(BacktraceItem::Link(link)) + }; + + // Advance the iterator. + self.cur = previous; + + ret + } +} +``` + +This already was the gist of the architectural part of the implementation! In the generic part, +where the backtrace is printed, the address returned in `BacktraceItem::Link` is additionally used +to look up the corresponding `symbol`, so that this is conveniently printed together: + +```rust +match backtrace_res { + + // omitted + + BacktraceItem::Link(addr) => { + fmt_res = writeln!( + f, + " {:>2}. {:016x} | {:<50}", + i + 1, + addr.as_usize(), + match symbols::lookup_symbol(addr) { + Some(sym) => sym.name(), + _ => "Symbol not found", + } + ) + } +}; +``` + +Finally, we add printing of a backtrace to `panic!`: + +``` +panic_println!( + "[ {:>3}.{:06}] Kernel panic!\n\n\ + Panic location:\n File '{}', line {}, column {}\n\n\ + {}\n\n\ + {}", + timestamp.as_secs(), + timestamp.subsec_micros(), + location, + line, + column, + info.message().unwrap_or(&format_args!("")), + backtrace::Backtrace +); +``` + +### Compiler Changes + +By default, the `aarch64-unknown-none*` targets *do not* guarantee that a stack frame record is +generated on each function call. Without, the backtracing code will not work. Fortunately, +generation can be forced by modifying the `rustc codegen options`. We add the following to the +`Makefile`: + +```makefile +ifeq ($(BSP),rpi3) + + # omitted + + RUSTC_MISC_ARGS = -C target-cpu=cortex-a53 -C force-frame-pointers +``` + +But there is more! Until now, when we compiled the kernel, cargo was using a **precompiled** version +of the `Rust core library` that comes with rustup whenever a target is added. This is usually very +beneficial in terms of speeding up compilation. Unfortunately, the precompiled version was not +compiled with `-C force-frame-pointers` either. This can be solved using cargo's [`build-std` +feature]. We set it in the Makefile so that cargo also compiles the core library using our compiler +settings, which means we get the frame records thanks to `-C force-frame-pointers` for any core +library functions as well. + +```Makefile +# build-std can be skipped for helper commands that do not rely on correct stack frames and other +# custom compiler options. This results in a huge speedup. +RUSTC_CMD = cargo rustc $(COMPILER_ARGS) -Z build-std=core --manifest-path $(KERNEL_MANIFEST) +DOC_CMD = cargo doc $(COMPILER_ARGS) +CLIPPY_CMD = cargo clippy $(COMPILER_ARGS) +TEST_CMD = cargo test $(COMPILER_ARGS) -Z build-std=core --manifest-path $(KERNEL_MANIFEST) +``` + +[`build-std` feature]: https://doc.rust-lang.org/cargo/reference/unstable.html#build-std + +### Supporting Changes + +There's a couple of changes not covered in this tutorial text, but the reader should ideally skim +through them: + +- [`src/_arch/aarch64/exception.s`](`kernel/src/_arch/aarch64/exception.s`) adds some tricky code to + generate a stack frame record on exception entry. The file includes elaborate comments that can be + inspected. +- [`src/_arch/aarch64/cpu/boot.rs`](`kernel/src/_arch/aarch64/cpu/boot.rs`) adds some code that + ensures that `kernel_init()` becomes the root of the backtrace (meaning its is ensured that + `previous_frame` will be zero for `kernel_init()`'s frame record). +- In `$ROOT/Cargo.toml`, `debug = true` has been set, which ensures that the kernel ELF includes the + maximum amount of debug information. Please note that this does *not* change anything for the + kernel at runtime. However, it will allow to dig even deeper on an address that has been reported + by a kernel backtrace. For example, using the `addr2line` tool. The following two snippets show + what `addr2line` reports when the debug flag is not or is set, respectively. + +```console +$ # debug = false +$ addr2line -p -f -s -i -e target/aarch64-unknown-none-softfloat/release/kernel+ttables+symbols 0xffffffffc0001da8 | rustfilt +kernel::kernel_main at kernel.c562062a-cgu.1:? +``` + +```console +$ # debug = true +$ addr2line -p -f -s -i -e target/aarch64-unknown-none-softfloat/release/kernel+ttables+symbols 0xffffffffc0001da8 | rustfilt +libkernel::memory::mmu::mapping_record::MappingRecord::print at mapping_record.rs:136 + (inlined by) libkernel::memory::mmu::mapping_record::kernel_print::{{closure}} at mapping_record.rs:232 + (inlined by) as libkernel::synchronization::interface::ReadWriteEx>::read at synchronization.rs:139 + (inlined by) libkernel::memory::mmu::mapping_record::kernel_print at mapping_record.rs:232 + (inlined by) libkernel::memory::mmu::kernel_print_mappings at mmu.rs:269 + (inlined by) kernel::kernel_main at main.rs:84 +``` + +## Test it + +Three tests were added that check the sanity of the backtracing code. Also, any previous tests that +print a `panic` will now also include a backtrace. For example, `02_exception_sync_page_fault.rs`: + +```console +$ TEST=02_exception_sync_page_fault make test_integration +[...] + ------------------------------------------------------------------- + 🦀 Testing synchronous exception handling by causing a page fault + ------------------------------------------------------------------- + + [ 0.002782] Writing to bottom of address space to address 1 GiB... + [ 0.004623] Kernel panic! + + Panic location: + File 'kernel/src/_arch/aarch64/exception.rs', line 59, column 5 + + CPU Exception! + + ESR_EL1: 0x96000004 + Exception Class (EC) : 0x25 - Data Abort, current EL + Instr Specific Syndrome (ISS): 0x4 + FAR_EL1: 0x0000000040000000 + + [...] + + Backtrace: + ---------------------------------------------------------------------------------------------- + Address Function containing address + ---------------------------------------------------------------------------------------------- + 1. ffffffffc0001294 | core::fmt::write + 2. ffffffffc0005560 | libkernel::panic_wait::_panic_print + 3. ffffffffc00054a0 | rust_begin_unwind + 4. ffffffffc0002950 | core::panicking::panic_fmt + 5. ffffffffc0004898 | current_elx_synchronous + 6. ffffffffc0000a74 | __vector_current_elx_synchronous + 7. ffffffffc000111c | kernel_init + ---------------------------------------------------------------------------------------------- + + ------------------------------------------------------------------- + ✅ Success: 02_exception_sync_page_fault.rs + ------------------------------------------------------------------- +``` + +## Diff to previous +```diff + +diff -uNr 17_kernel_symbols/Cargo.toml 18_backtrace/Cargo.toml +--- 17_kernel_symbols/Cargo.toml ++++ 18_backtrace/Cargo.toml +@@ -8,3 +8,4 @@ + + [profile.release] + lto = true ++debug = true + +diff -uNr 17_kernel_symbols/kernel/Cargo.toml 18_backtrace/kernel/Cargo.toml +--- 17_kernel_symbols/kernel/Cargo.toml ++++ 18_backtrace/kernel/Cargo.toml +@@ -1,6 +1,6 @@ + [package] + name = "mingo" +-version = "0.17.0" ++version = "0.18.0" + authors = ["Andre Richter "] + edition = "2021" + +@@ -56,3 +56,15 @@ + [[test]] + name = "03_exception_restore_sanity" + harness = false ++ ++[[test]] ++name = "05_backtrace_sanity" ++harness = false ++ ++[[test]] ++name = "06_backtrace_invalid_frame" ++harness = false ++ ++[[test]] ++name = "07_backtrace_invalid_link" ++harness = false + +diff -uNr 17_kernel_symbols/kernel/src/_arch/aarch64/backtrace.rs 18_backtrace/kernel/src/_arch/aarch64/backtrace.rs +--- 17_kernel_symbols/kernel/src/_arch/aarch64/backtrace.rs ++++ 18_backtrace/kernel/src/_arch/aarch64/backtrace.rs +@@ -0,0 +1,136 @@ ++// SPDX-License-Identifier: MIT OR Apache-2.0 ++// ++// Copyright (c) 2022 Andre Richter ++ ++//! Architectural backtracing support. ++//! ++//! # Orientation ++//! ++//! Since arch modules are imported into generic modules using the path attribute, the path of this ++//! file is: ++//! ++//! crate::backtrace::arch_backtrace ++ ++use crate::{ ++ backtrace::BacktraceItem, ++ memory::{Address, Virtual}, ++}; ++use cortex_a::registers::*; ++use tock_registers::interfaces::Readable; ++ ++//-------------------------------------------------------------------------------------------------- ++// Private Definitions ++//-------------------------------------------------------------------------------------------------- ++ ++/// A Stack frame record. ++/// ++/// # Note ++/// ++/// The convention is that `previous_record` is valid as long as it contains a non-null value. ++/// Therefore, it is possible to type the member as `Option<&StackFrameRecord>` because of Rust's ++/// `null-pointer optimization`. ++#[repr(C)] ++struct StackFrameRecord<'a> { ++ previous_record: Option<&'a StackFrameRecord<'a>>, ++ link: Address, ++} ++ ++struct StackFrameRecordIterator<'a> { ++ cur: &'a StackFrameRecord<'a>, ++} ++ ++//-------------------------------------------------------------------------------------------------- ++// Private Code ++//-------------------------------------------------------------------------------------------------- ++ ++impl<'a> Iterator for StackFrameRecordIterator<'a> { ++ type Item = BacktraceItem; ++ ++ fn next(&mut self) -> Option { ++ static ABORT_FRAME: StackFrameRecord = StackFrameRecord { ++ previous_record: None, ++ link: Address::new(0), ++ }; ++ ++ // If previous is None, this is the root frame, so iteration will stop here. ++ let previous = self.cur.previous_record?; ++ ++ // Need to abort if the pointer to the previous frame record is invalid. ++ let prev_addr = Address::::new(previous as *const _ as usize); ++ if !prev_addr.is_valid_stack_addr() { ++ // This allows to return the error and then stop on the next iteration. ++ self.cur = &ABORT_FRAME; ++ return Some(BacktraceItem::InvalidFramePointer(prev_addr)); ++ } ++ ++ let ret = if !self.cur.link.is_valid_code_addr() { ++ Some(BacktraceItem::InvalidLink(self.cur.link)) ++ } else { ++ // The link points to the instruction to be executed _after_ returning from a branch. ++ // However, we want to show the instruction that caused the branch, so subtract by one ++ // instruction. ++ // ++ // This might be called from panic!, so it must not panic itself on the subtraction. ++ let link = if self.cur.link >= Address::new(4) { ++ self.cur.link - 4 ++ } else { ++ self.cur.link ++ }; ++ ++ Some(BacktraceItem::Link(link)) ++ }; ++ ++ // Advance the iterator. ++ self.cur = previous; ++ ++ ret ++ } ++} ++ ++fn stack_frame_record_iterator<'a>() -> Option> { ++ let fp = Address::::new(FP.get() as usize); ++ if !fp.is_valid_stack_addr() { ++ return None; ++ } ++ ++ Some(StackFrameRecordIterator { ++ cur: unsafe { &*(fp.as_usize() as *const _) }, ++ }) ++} ++ ++//-------------------------------------------------------------------------------------------------- ++// Public Code ++//-------------------------------------------------------------------------------------------------- ++ ++/// Architectural implementation of the backtrace. ++pub fn backtrace(f: impl FnOnce(Option<&mut dyn Iterator>)) { ++ f(stack_frame_record_iterator().as_mut().map(|s| s as _)) ++} ++ ++//-------------------------------------------------------------------------------------------------- ++// Testing ++//-------------------------------------------------------------------------------------------------- ++ ++#[cfg(feature = "test_build")] ++#[inline(always)] ++/// Hack for corrupting the previous frame address in the current stack frame. ++/// ++/// # Safety ++/// ++/// - To be used only by testing code. ++pub unsafe fn corrupt_previous_frame_addr() { ++ let sf = FP.get() as *mut usize; ++ *sf = 0x123; ++} ++ ++#[cfg(feature = "test_build")] ++#[inline(always)] ++/// Hack for corrupting the link in the current stack frame. ++/// ++/// # Safety ++/// ++/// - To be used only by testing code. ++pub unsafe fn corrupt_link() { ++ let sf = FP.get() as *mut StackFrameRecord; ++ (*sf).link = Address::new(0x456); ++} + +diff -uNr 17_kernel_symbols/kernel/src/_arch/aarch64/cpu/boot.rs 18_backtrace/kernel/src/_arch/aarch64/cpu/boot.rs +--- 17_kernel_symbols/kernel/src/_arch/aarch64/cpu/boot.rs ++++ 18_backtrace/kernel/src/_arch/aarch64/cpu/boot.rs +@@ -12,7 +12,10 @@ + //! crate::cpu::boot::arch_boot + + use crate::{memory, memory::Address}; +-use core::arch::global_asm; ++use core::{ ++ arch::global_asm, ++ sync::atomic::{compiler_fence, Ordering}, ++}; + use cortex_a::{asm, registers::*}; + use tock_registers::interfaces::Writeable; + +@@ -63,6 +66,18 @@ + SP_EL1.set(virt_boot_core_stack_end_exclusive_addr); + } + ++/// Reset the backtrace by setting link register and frame pointer to zero. ++/// ++/// # Safety ++/// ++/// - This function must only be used immediately before entering EL1. ++#[inline(always)] ++unsafe fn prepare_backtrace_reset() { ++ compiler_fence(Ordering::SeqCst); ++ FP.set(0); ++ LR.set(0); ++} ++ + //-------------------------------------------------------------------------------------------------- + // Public Code + //-------------------------------------------------------------------------------------------------- +@@ -89,6 +104,9 @@ + let addr = Address::new(phys_kernel_tables_base_addr as usize); + memory::mmu::enable_mmu_and_caching(addr).unwrap(); + ++ // Make the function we return to the root of a backtrace. ++ prepare_backtrace_reset(); ++ + // Use `eret` to "return" to EL1. Since virtual memory will already be enabled, this results in + // execution of kernel_init() in EL1 from its _virtual address_. + asm::eret() + +diff -uNr 17_kernel_symbols/kernel/src/_arch/aarch64/exception.s 18_backtrace/kernel/src/_arch/aarch64/exception.s +--- 17_kernel_symbols/kernel/src/_arch/aarch64/exception.s ++++ 18_backtrace/kernel/src/_arch/aarch64/exception.s +@@ -8,10 +8,10 @@ + + /// Call the function provided by parameter `\handler` after saving the exception context. Provide + /// the context as the first parameter to '\handler'. +-.macro CALL_WITH_CONTEXT handler ++.macro CALL_WITH_CONTEXT handler is_lower_el is_sync + __vector_\handler: + // Make room on the stack for the exception context. +- sub sp, sp, #16 * 17 ++ sub sp, sp, #16 * 18 + + // Store all general purpose registers on the stack. + stp x0, x1, [sp, #16 * 0] +@@ -39,6 +39,42 @@ + stp lr, x1, [sp, #16 * 15] + stp x2, x3, [sp, #16 * 16] + ++ // Build a stack frame for backtracing. ++.if \is_lower_el == 1 ++ // If we came from a lower EL, make it a root frame (by storing zero) so that the kernel ++ // does not attempt to trace into userspace. ++ stp xzr, xzr, [sp, #16 * 17] ++.else ++ // For normal branches, the link address points to the instruction to be executed _after_ ++ // returning from a branch. In a backtrace, we want to show the instruction that caused the ++ // branch, though. That is why code in backtrace.rs subtracts 4 (length of one instruction) ++ // from the link address. ++ // ++ // Here we have a special case, though, because ELR_EL1 is used instead of LR to build the ++ // stack frame, so that it becomes possible to trace beyond an exception. Hence, it must be ++ // considered that semantics for ELR_EL1 differ from case to case. ++ // ++ // Unless an "exception generating instruction" was executed, ELR_EL1 already points to the ++ // the correct instruction, and hence the subtraction by 4 in backtrace.rs would yield wrong ++ // results. To cover for this, 4 is added to ELR_EL1 below unless the cause of exception was ++ // an SVC instruction. BRK and HLT are "exception generating instructions" as well, but they ++ // are not expected and therefore left out for now. ++ // ++ // For reference: Search for "preferred exception return address" in the Architecture ++ // Reference Manual for ARMv8-A. ++.if \is_sync == 1 ++ lsr w3, w3, #26 // w3 = ESR_EL1.EC ++ cmp w3, #0x15 // w3 == SVC64 ? ++ b.eq 1f ++.endif ++ add x1, x1, #4 ++1: ++ stp x29, x1, [sp, #16 * 17] ++.endif ++ ++ // Set the frame pointer to the stack frame record. ++ add x29, sp, #16 * 17 ++ + // x0 is the first argument for the function called through `\handler`. + mov x0, sp + +@@ -81,43 +117,43 @@ + // + // - It must be ensured that `CALL_WITH_CONTEXT` <= 0x80 bytes. + .org 0x000 +- CALL_WITH_CONTEXT current_el0_synchronous ++ CALL_WITH_CONTEXT current_el0_synchronous, 0, 1 + .org 0x080 +- CALL_WITH_CONTEXT current_el0_irq ++ CALL_WITH_CONTEXT current_el0_irq, 0, 0 + .org 0x100 + FIQ_SUSPEND + .org 0x180 +- CALL_WITH_CONTEXT current_el0_serror ++ CALL_WITH_CONTEXT current_el0_serror, 0, 0 + + // Current exception level with SP_ELx, x > 0. + .org 0x200 +- CALL_WITH_CONTEXT current_elx_synchronous ++ CALL_WITH_CONTEXT current_elx_synchronous, 0, 1 + .org 0x280 +- CALL_WITH_CONTEXT current_elx_irq ++ CALL_WITH_CONTEXT current_elx_irq, 0, 0 + .org 0x300 + FIQ_SUSPEND + .org 0x380 +- CALL_WITH_CONTEXT current_elx_serror ++ CALL_WITH_CONTEXT current_elx_serror, 0, 0 + + // Lower exception level, AArch64 + .org 0x400 +- CALL_WITH_CONTEXT lower_aarch64_synchronous ++ CALL_WITH_CONTEXT lower_aarch64_synchronous, 1, 1 + .org 0x480 +- CALL_WITH_CONTEXT lower_aarch64_irq ++ CALL_WITH_CONTEXT lower_aarch64_irq, 1, 0 + .org 0x500 + FIQ_SUSPEND + .org 0x580 +- CALL_WITH_CONTEXT lower_aarch64_serror ++ CALL_WITH_CONTEXT lower_aarch64_serror, 1, 0 + + // Lower exception level, AArch32 + .org 0x600 +- CALL_WITH_CONTEXT lower_aarch32_synchronous ++ CALL_WITH_CONTEXT lower_aarch32_synchronous, 1, 0 + .org 0x680 +- CALL_WITH_CONTEXT lower_aarch32_irq ++ CALL_WITH_CONTEXT lower_aarch32_irq, 1, 0 + .org 0x700 + FIQ_SUSPEND + .org 0x780 +- CALL_WITH_CONTEXT lower_aarch32_serror ++ CALL_WITH_CONTEXT lower_aarch32_serror, 1, 0 + .org 0x800 + + //------------------------------------------------------------------------------ +@@ -146,7 +182,7 @@ + ldp x26, x27, [sp, #16 * 13] + ldp x28, x29, [sp, #16 * 14] + +- add sp, sp, #16 * 17 ++ add sp, sp, #16 * 18 + + eret + + +diff -uNr 17_kernel_symbols/kernel/src/backtrace.rs 18_backtrace/kernel/src/backtrace.rs +--- 17_kernel_symbols/kernel/src/backtrace.rs ++++ 18_backtrace/kernel/src/backtrace.rs +@@ -0,0 +1,112 @@ ++// SPDX-License-Identifier: MIT OR Apache-2.0 ++// ++// Copyright (c) 2022 Andre Richter ++ ++//! Backtracing support. ++ ++#[cfg(target_arch = "aarch64")] ++#[path = "_arch/aarch64/backtrace.rs"] ++mod arch_backtrace; ++ ++use crate::{ ++ memory::{Address, Virtual}, ++ symbols, ++}; ++use core::fmt; ++ ++//-------------------------------------------------------------------------------------------------- ++// Architectural Public Reexports ++//-------------------------------------------------------------------------------------------------- ++#[cfg(feature = "test_build")] ++pub use arch_backtrace::{corrupt_link, corrupt_previous_frame_addr}; ++ ++//-------------------------------------------------------------------------------------------------- ++// Public Definitions ++//-------------------------------------------------------------------------------------------------- ++ ++/// A backtrace item. ++#[allow(missing_docs)] ++pub enum BacktraceItem { ++ InvalidFramePointer(Address), ++ InvalidLink(Address), ++ Link(Address), ++} ++ ++/// Pseudo-struct for printing a backtrace using its fmt::Display implementation. ++pub struct Backtrace; ++ ++//-------------------------------------------------------------------------------------------------- ++// Public Code ++//-------------------------------------------------------------------------------------------------- ++ ++impl fmt::Display for Backtrace { ++ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { ++ writeln!(f, "Backtrace:")?; ++ writeln!( ++ f, ++ " ----------------------------------------------------------------------------------------------" ++ )?; ++ writeln!( ++ f, ++ " Address Function containing address" ++ )?; ++ writeln!( ++ f, ++ " ----------------------------------------------------------------------------------------------" ++ )?; ++ ++ let mut fmt_res: fmt::Result = Ok(()); ++ let trace_formatter = ++ |maybe_iter: Option<&mut dyn Iterator>| match maybe_iter { ++ None => fmt_res = writeln!(f, "ERROR! No valid stack frame found"), ++ Some(iter) => { ++ for (i, backtrace_res) in iter.enumerate() { ++ match backtrace_res { ++ BacktraceItem::InvalidFramePointer(addr) => { ++ fmt_res = writeln!( ++ f, ++ " {:>2}. ERROR! \ ++ Encountered invalid frame pointer ({}) during backtrace", ++ i + 1, ++ addr ++ ); ++ } ++ BacktraceItem::InvalidLink(addr) => { ++ fmt_res = writeln!( ++ f, ++ " {:>2}. ERROR! \ ++ Link address ({}) is not contained in kernel .text section", ++ i + 1, ++ addr ++ ); ++ } ++ BacktraceItem::Link(addr) => { ++ fmt_res = writeln!( ++ f, ++ " {:>2}. {:016x} | {:<50}", ++ i + 1, ++ addr.as_usize(), ++ match symbols::lookup_symbol(addr) { ++ Some(sym) => sym.name(), ++ _ => "Symbol not found", ++ } ++ ) ++ } ++ }; ++ ++ if fmt_res.is_err() { ++ break; ++ } ++ } ++ } ++ }; ++ ++ arch_backtrace::backtrace(trace_formatter); ++ fmt_res?; ++ ++ writeln!( ++ f, ++ " ----------------------------------------------------------------------------------------------" ++ ) ++ } ++} + +diff -uNr 17_kernel_symbols/kernel/src/bsp/raspberrypi/memory/mmu.rs 18_backtrace/kernel/src/bsp/raspberrypi/memory/mmu.rs +--- 17_kernel_symbols/kernel/src/bsp/raspberrypi/memory/mmu.rs ++++ 18_backtrace/kernel/src/bsp/raspberrypi/memory/mmu.rs +@@ -80,16 +80,6 @@ + size >> KernelGranule::SHIFT + } + +-/// The code pages of the kernel binary. +-fn virt_code_region() -> MemoryRegion { +- let num_pages = size_to_num_pages(super::code_size()); +- +- let start_page_addr = super::virt_code_start(); +- let end_exclusive_page_addr = start_page_addr.checked_offset(num_pages as isize).unwrap(); +- +- MemoryRegion::new(start_page_addr, end_exclusive_page_addr) +-} +- + /// The data pages of the kernel binary. + fn virt_data_region() -> MemoryRegion { + let num_pages = size_to_num_pages(super::data_size()); +@@ -100,16 +90,6 @@ + MemoryRegion::new(start_page_addr, end_exclusive_page_addr) + } + +-/// The boot core stack pages. +-fn virt_boot_core_stack_region() -> MemoryRegion { +- let num_pages = size_to_num_pages(super::boot_core_stack_size()); +- +- let start_page_addr = super::virt_boot_core_stack_start(); +- let end_exclusive_page_addr = start_page_addr.checked_offset(num_pages as isize).unwrap(); +- +- MemoryRegion::new(start_page_addr, end_exclusive_page_addr) +-} +- + // There is no reason to expect the following conversions to fail, since they were generated offline + // by the `translation table tool`. If it doesn't work, a panic due to the unwraps is justified. + fn kernel_virt_to_phys_region(virt_region: MemoryRegion) -> MemoryRegion { +@@ -132,6 +112,26 @@ + // Public Code + //-------------------------------------------------------------------------------------------------- + ++/// The code pages of the kernel binary. ++pub fn virt_code_region() -> MemoryRegion { ++ let num_pages = size_to_num_pages(super::code_size()); ++ ++ let start_page_addr = super::virt_code_start(); ++ let end_exclusive_page_addr = start_page_addr.checked_offset(num_pages as isize).unwrap(); ++ ++ MemoryRegion::new(start_page_addr, end_exclusive_page_addr) ++} ++ ++/// The boot core stack pages. ++pub fn virt_boot_core_stack_region() -> MemoryRegion { ++ let num_pages = size_to_num_pages(super::boot_core_stack_size()); ++ ++ let start_page_addr = super::virt_boot_core_stack_start(); ++ let end_exclusive_page_addr = start_page_addr.checked_offset(num_pages as isize).unwrap(); ++ ++ MemoryRegion::new(start_page_addr, end_exclusive_page_addr) ++} ++ + /// Return a reference to the kernel's translation tables. + pub fn kernel_translation_tables() -> &'static InitStateLock { + &KERNEL_TABLES + +diff -uNr 17_kernel_symbols/kernel/src/lib.rs 18_backtrace/kernel/src/lib.rs +--- 17_kernel_symbols/kernel/src/lib.rs ++++ 18_backtrace/kernel/src/lib.rs +@@ -128,6 +128,7 @@ + mod panic_wait; + mod synchronization; + ++pub mod backtrace; + pub mod bsp; + pub mod common; + pub mod console; + +diff -uNr 17_kernel_symbols/kernel/src/memory.rs 18_backtrace/kernel/src/memory.rs +--- 17_kernel_symbols/kernel/src/memory.rs ++++ 18_backtrace/kernel/src/memory.rs +@@ -95,6 +95,18 @@ + } + } + ++impl Sub for Address { ++ type Output = Self; ++ ++ #[inline(always)] ++ fn sub(self, rhs: usize) -> Self::Output { ++ match self.value.checked_sub(rhs) { ++ None => panic!("Overflow on Address::sub"), ++ Some(x) => Self::new(x), ++ } ++ } ++} ++ + impl Sub> for Address { + type Output = Self; + +@@ -107,6 +119,18 @@ + } + } + ++impl Address { ++ /// Checks if the address is part of the boot core stack region. ++ pub fn is_valid_stack_addr(&self) -> bool { ++ bsp::memory::mmu::virt_boot_core_stack_region().contains(*self) ++ } ++ ++ /// Checks if the address is part of the kernel code region. ++ pub fn is_valid_code_addr(&self) -> bool { ++ bsp::memory::mmu::virt_code_region().contains(*self) ++ } ++} ++ + impl fmt::Display for Address { + // Don't expect to see physical addresses greater than 40 bit. + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + +diff -uNr 17_kernel_symbols/kernel/src/panic_wait.rs 18_backtrace/kernel/src/panic_wait.rs +--- 17_kernel_symbols/kernel/src/panic_wait.rs ++++ 18_backtrace/kernel/src/panic_wait.rs +@@ -4,7 +4,7 @@ + + //! A panic handler that infinitely waits. + +-use crate::{bsp, cpu, exception}; ++use crate::{backtrace, bsp, cpu, exception}; + use core::{fmt, panic::PanicInfo}; + + //-------------------------------------------------------------------------------------------------- +@@ -91,6 +91,7 @@ + panic_println!( + "[ {:>3}.{:06}] Kernel panic!\n\n\ + Panic location:\n File '{}', line {}, column {}\n\n\ ++ {}\n\n\ + {}", + timestamp.as_secs(), + timestamp.subsec_micros(), +@@ -98,6 +99,7 @@ + line, + column, + info.message().unwrap_or(&format_args!("")), ++ backtrace::Backtrace + ); + + _panic_exit() + +diff -uNr 17_kernel_symbols/kernel/tests/05_backtrace_sanity.rb 18_backtrace/kernel/tests/05_backtrace_sanity.rb +--- 17_kernel_symbols/kernel/tests/05_backtrace_sanity.rb ++++ 18_backtrace/kernel/tests/05_backtrace_sanity.rb +@@ -0,0 +1,39 @@ ++# frozen_string_literal: true ++ ++# SPDX-License-Identifier: MIT OR Apache-2.0 ++# ++# Copyright (c) 2022 Andre Richter ++ ++require 'console_io_test' ++ ++# Verify that panic produces a backtrace. ++class PanicBacktraceTest < SubtestBase ++ def name ++ 'Panic produces backtrace' ++ end ++ ++ def run(qemu_out, _qemu_in) ++ expect_or_raise(qemu_out, 'Kernel panic!') ++ expect_or_raise(qemu_out, 'Backtrace:') ++ end ++end ++ ++# Verify backtrace correctness. ++class BacktraceCorrectnessTest < SubtestBase ++ def name ++ 'Backtrace is correct' ++ end ++ ++ def run(qemu_out, _qemu_in) ++ expect_or_raise(qemu_out, '| core::panicking::panic') ++ expect_or_raise(qemu_out, '| _05_backtrace_sanity::nested') ++ expect_or_raise(qemu_out, '| kernel_init') ++ end ++end ++ ++##-------------------------------------------------------------------------------------------------- ++## Test registration ++##-------------------------------------------------------------------------------------------------- ++def subtest_collection ++ [PanicBacktraceTest.new, BacktraceCorrectnessTest.new] ++end + +diff -uNr 17_kernel_symbols/kernel/tests/05_backtrace_sanity.rs 18_backtrace/kernel/tests/05_backtrace_sanity.rs +--- 17_kernel_symbols/kernel/tests/05_backtrace_sanity.rs ++++ 18_backtrace/kernel/tests/05_backtrace_sanity.rs +@@ -0,0 +1,31 @@ ++// SPDX-License-Identifier: MIT OR Apache-2.0 ++// ++// Copyright (c) 2022 Andre Richter ++ ++//! Test if backtracing code detects an invalid frame pointer. ++ ++#![feature(format_args_nl)] ++#![no_main] ++#![no_std] ++ ++/// Console tests should time out on the I/O harness in case of panic. ++mod panic_wait_forever; ++ ++use libkernel::{bsp, cpu, exception, memory}; ++ ++#[inline(never)] ++fn nested() { ++ panic!() ++} ++ ++#[no_mangle] ++unsafe fn kernel_init() -> ! { ++ exception::handling_init(); ++ memory::mmu::post_enable_init(); ++ bsp::console::qemu_bring_up_console(); ++ ++ nested(); ++ ++ // The QEMU process running this test will be closed by the I/O test harness. ++ cpu::wait_forever() ++} + +diff -uNr 17_kernel_symbols/kernel/tests/06_backtrace_invalid_frame.rb 18_backtrace/kernel/tests/06_backtrace_invalid_frame.rb +--- 17_kernel_symbols/kernel/tests/06_backtrace_invalid_frame.rb ++++ 18_backtrace/kernel/tests/06_backtrace_invalid_frame.rb +@@ -0,0 +1,26 @@ ++# frozen_string_literal: true ++ ++# SPDX-License-Identifier: MIT OR Apache-2.0 ++# ++# Copyright (c) 2022 Andre Richter ++ ++require 'console_io_test' ++ ++# Test detection of invalid frame pointers. ++class InvalidFramePointerTest < SubtestBase ++ def name ++ 'Detect invalid frame pointer' ++ end ++ ++ def run(qemu_out, _qemu_in) ++ expect_or_raise(qemu_out, ++ /Encountered invalid frame pointer \(.*\) during backtrace/) ++ end ++end ++ ++##-------------------------------------------------------------------------------------------------- ++## Test registration ++##-------------------------------------------------------------------------------------------------- ++def subtest_collection ++ [InvalidFramePointerTest.new] ++end + +diff -uNr 17_kernel_symbols/kernel/tests/06_backtrace_invalid_frame.rs 18_backtrace/kernel/tests/06_backtrace_invalid_frame.rs +--- 17_kernel_symbols/kernel/tests/06_backtrace_invalid_frame.rs ++++ 18_backtrace/kernel/tests/06_backtrace_invalid_frame.rs +@@ -0,0 +1,33 @@ ++// SPDX-License-Identifier: MIT OR Apache-2.0 ++// ++// Copyright (c) 2022 Andre Richter ++ ++//! Test if backtracing code detects an invalid frame pointer. ++ ++#![feature(format_args_nl)] ++#![no_main] ++#![no_std] ++ ++/// Console tests should time out on the I/O harness in case of panic. ++mod panic_wait_forever; ++ ++use libkernel::{backtrace, bsp, cpu, exception, memory}; ++ ++#[inline(never)] ++fn nested() { ++ unsafe { backtrace::corrupt_previous_frame_addr() }; ++ ++ panic!() ++} ++ ++#[no_mangle] ++unsafe fn kernel_init() -> ! { ++ exception::handling_init(); ++ memory::mmu::post_enable_init(); ++ bsp::console::qemu_bring_up_console(); ++ ++ nested(); ++ ++ // The QEMU process running this test will be closed by the I/O test harness. ++ cpu::wait_forever() ++} + +diff -uNr 17_kernel_symbols/kernel/tests/07_backtrace_invalid_link.rb 18_backtrace/kernel/tests/07_backtrace_invalid_link.rb +--- 17_kernel_symbols/kernel/tests/07_backtrace_invalid_link.rb ++++ 18_backtrace/kernel/tests/07_backtrace_invalid_link.rb +@@ -0,0 +1,25 @@ ++# frozen_string_literal: true ++ ++# SPDX-License-Identifier: MIT OR Apache-2.0 ++# ++# Copyright (c) 2022 Andre Richter ++ ++require 'console_io_test' ++ ++# Test detection of invalid link. ++class InvalidLinkTest < SubtestBase ++ def name ++ 'Detect invalid link' ++ end ++ ++ def run(qemu_out, _qemu_in) ++ expect_or_raise(qemu_out, /Link address \(.*\) is not contained in kernel .text section/) ++ end ++end ++ ++##-------------------------------------------------------------------------------------------------- ++## Test registration ++##-------------------------------------------------------------------------------------------------- ++def subtest_collection ++ [InvalidLinkTest.new] ++end + +diff -uNr 17_kernel_symbols/kernel/tests/07_backtrace_invalid_link.rs 18_backtrace/kernel/tests/07_backtrace_invalid_link.rs +--- 17_kernel_symbols/kernel/tests/07_backtrace_invalid_link.rs ++++ 18_backtrace/kernel/tests/07_backtrace_invalid_link.rs +@@ -0,0 +1,38 @@ ++// SPDX-License-Identifier: MIT OR Apache-2.0 ++// ++// Copyright (c) 2022 Andre Richter ++ ++//! Test if backtracing code detects an invalid link. ++ ++#![feature(format_args_nl)] ++#![no_main] ++#![no_std] ++ ++/// Console tests should time out on the I/O harness in case of panic. ++mod panic_wait_forever; ++ ++use libkernel::{backtrace, bsp, cpu, exception, memory}; ++ ++#[inline(never)] ++fn nested_2() -> &'static str { ++ unsafe { backtrace::corrupt_link() }; ++ libkernel::println!("{}", libkernel::backtrace::Backtrace); ++ "foo" ++} ++ ++#[inline(never)] ++fn nested_1() { ++ libkernel::println!("{}", nested_2()) ++} ++ ++#[no_mangle] ++unsafe fn kernel_init() -> ! { ++ exception::handling_init(); ++ memory::mmu::post_enable_init(); ++ bsp::console::qemu_bring_up_console(); ++ ++ nested_1(); ++ ++ // The QEMU process running this test will be closed by the I/O test harness. ++ cpu::wait_forever() ++} + +diff -uNr 17_kernel_symbols/Makefile 18_backtrace/Makefile +--- 17_kernel_symbols/Makefile ++++ 18_backtrace/Makefile +@@ -42,7 +42,7 @@ + OPENOCD_ARG = -f /openocd/tcl/interface/ftdi/olimex-arm-usb-tiny-h.cfg -f /openocd/rpi3.cfg + JTAG_BOOT_IMAGE = ../X1_JTAG_boot/jtag_boot_rpi3.img + LD_SCRIPT_PATH = $(shell pwd)/kernel/src/bsp/raspberrypi +- RUSTC_MISC_ARGS = -C target-cpu=cortex-a53 ++ RUSTC_MISC_ARGS = -C target-cpu=cortex-a53 -C force-frame-pointers + else ifeq ($(BSP),rpi4) + TARGET = aarch64-unknown-none-softfloat + KERNEL_BIN = kernel8.img +@@ -56,7 +56,7 @@ + OPENOCD_ARG = -f /openocd/tcl/interface/ftdi/olimex-arm-usb-tiny-h.cfg -f /openocd/rpi4.cfg + JTAG_BOOT_IMAGE = ../X1_JTAG_boot/jtag_boot_rpi4.img + LD_SCRIPT_PATH = $(shell pwd)/kernel/src/bsp/raspberrypi +- RUSTC_MISC_ARGS = -C target-cpu=cortex-a72 ++ RUSTC_MISC_ARGS = -C target-cpu=cortex-a72 -C force-frame-pointers + endif + + # Export for build.rs. +@@ -121,10 +121,12 @@ + $(FEATURES) \ + --release + +-RUSTC_CMD = cargo rustc $(COMPILER_ARGS) --manifest-path $(KERNEL_MANIFEST) ++# build-std can be skipped for helper commands that do not rely on correct stack frames and other ++# custom compiler options. This results in a huge speedup. ++RUSTC_CMD = cargo rustc $(COMPILER_ARGS) -Z build-std=core --manifest-path $(KERNEL_MANIFEST) + DOC_CMD = cargo doc $(COMPILER_ARGS) + CLIPPY_CMD = cargo clippy $(COMPILER_ARGS) +-TEST_CMD = cargo test $(COMPILER_ARGS) --manifest-path $(KERNEL_MANIFEST) ++TEST_CMD = cargo test $(COMPILER_ARGS) -Z build-std=core --manifest-path $(KERNEL_MANIFEST) + OBJCOPY_CMD = rust-objcopy \ + --strip-all \ + -O binary +@@ -303,8 +305,7 @@ + ##------------------------------------------------------------------------------ + ## Start GDB session + ##------------------------------------------------------------------------------ +-gdb: RUSTC_MISC_ARGS += -C debuginfo=2 +-gdb-opt0: RUSTC_MISC_ARGS += -C debuginfo=2 -C opt-level=0 ++gdb-opt0: RUSTC_MISC_ARGS += -C opt-level=0 + gdb gdb-opt0: $(KERNEL_ELF) + $(call color_header, "Launching GDB") + @$(DOCKER_GDB) gdb-multiarch -q $(KERNEL_ELF) + +``` diff --git a/18_backtrace/kernel/Cargo.toml b/18_backtrace/kernel/Cargo.toml new file mode 100644 index 00000000..9e5f55be --- /dev/null +++ b/18_backtrace/kernel/Cargo.toml @@ -0,0 +1,70 @@ +[package] +name = "mingo" +version = "0.18.0" +authors = ["Andre Richter "] +edition = "2021" + +[features] +default = [] +bsp_rpi3 = ["tock-registers"] +bsp_rpi4 = ["tock-registers"] +test_build = ["qemu-exit"] + +##-------------------------------------------------------------------------------------------------- +## Dependencies +##-------------------------------------------------------------------------------------------------- + +[dependencies] +test-types = { path = "../libraries/test-types" } +debug-symbol-types = { path = "../libraries/debug-symbol-types" } + +# Optional dependencies +tock-registers = { version = "0.7.x", default-features = false, features = ["register_types"], optional = true } +qemu-exit = { version = "3.x.x", optional = true } + +# Platform specific dependencies +[target.'cfg(target_arch = "aarch64")'.dependencies] +cortex-a = { version = "7.x.x" } + +##-------------------------------------------------------------------------------------------------- +## Testing +##-------------------------------------------------------------------------------------------------- + +[dev-dependencies] +test-macros = { path = "../libraries/test-macros" } + +# Unit tests are done in the library part of the kernel. +[lib] +name = "libkernel" +test = true + +# Disable unit tests for the kernel binary. +[[bin]] +name = "kernel" +path = "src/main.rs" +test = false + +# List of tests without harness. +[[test]] +name = "00_console_sanity" +harness = false + +[[test]] +name = "02_exception_sync_page_fault" +harness = false + +[[test]] +name = "03_exception_restore_sanity" +harness = false + +[[test]] +name = "05_backtrace_sanity" +harness = false + +[[test]] +name = "06_backtrace_invalid_frame" +harness = false + +[[test]] +name = "07_backtrace_invalid_link" +harness = false diff --git a/18_backtrace/kernel/build.rs b/18_backtrace/kernel/build.rs new file mode 100644 index 00000000..cab00bb3 --- /dev/null +++ b/18_backtrace/kernel/build.rs @@ -0,0 +1,20 @@ +use std::{env, fs, process}; + +fn main() { + let ld_script_path = match env::var("LD_SCRIPT_PATH") { + Ok(var) => var, + _ => process::exit(0), + }; + + let files = fs::read_dir(ld_script_path).unwrap(); + files + .filter_map(Result::ok) + .filter(|d| { + if let Some(e) = d.path().extension() { + e == "ld" + } else { + false + } + }) + .for_each(|f| println!("cargo:rerun-if-changed={}", f.path().display())); +} diff --git a/18_backtrace/kernel/src/_arch/aarch64/backtrace.rs b/18_backtrace/kernel/src/_arch/aarch64/backtrace.rs new file mode 100644 index 00000000..e8860984 --- /dev/null +++ b/18_backtrace/kernel/src/_arch/aarch64/backtrace.rs @@ -0,0 +1,136 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2022 Andre Richter + +//! Architectural backtracing support. +//! +//! # Orientation +//! +//! Since arch modules are imported into generic modules using the path attribute, the path of this +//! file is: +//! +//! crate::backtrace::arch_backtrace + +use crate::{ + backtrace::BacktraceItem, + memory::{Address, Virtual}, +}; +use cortex_a::registers::*; +use tock_registers::interfaces::Readable; + +//-------------------------------------------------------------------------------------------------- +// Private Definitions +//-------------------------------------------------------------------------------------------------- + +/// A Stack frame record. +/// +/// # Note +/// +/// The convention is that `previous_record` is valid as long as it contains a non-null value. +/// Therefore, it is possible to type the member as `Option<&StackFrameRecord>` because of Rust's +/// `null-pointer optimization`. +#[repr(C)] +struct StackFrameRecord<'a> { + previous_record: Option<&'a StackFrameRecord<'a>>, + link: Address, +} + +struct StackFrameRecordIterator<'a> { + cur: &'a StackFrameRecord<'a>, +} + +//-------------------------------------------------------------------------------------------------- +// Private Code +//-------------------------------------------------------------------------------------------------- + +impl<'a> Iterator for StackFrameRecordIterator<'a> { + type Item = BacktraceItem; + + fn next(&mut self) -> Option { + static ABORT_FRAME: StackFrameRecord = StackFrameRecord { + previous_record: None, + link: Address::new(0), + }; + + // If previous is None, this is the root frame, so iteration will stop here. + let previous = self.cur.previous_record?; + + // Need to abort if the pointer to the previous frame record is invalid. + let prev_addr = Address::::new(previous as *const _ as usize); + if !prev_addr.is_valid_stack_addr() { + // This allows to return the error and then stop on the next iteration. + self.cur = &ABORT_FRAME; + return Some(BacktraceItem::InvalidFramePointer(prev_addr)); + } + + let ret = if !self.cur.link.is_valid_code_addr() { + Some(BacktraceItem::InvalidLink(self.cur.link)) + } else { + // The link points to the instruction to be executed _after_ returning from a branch. + // However, we want to show the instruction that caused the branch, so subtract by one + // instruction. + // + // This might be called from panic!, so it must not panic itself on the subtraction. + let link = if self.cur.link >= Address::new(4) { + self.cur.link - 4 + } else { + self.cur.link + }; + + Some(BacktraceItem::Link(link)) + }; + + // Advance the iterator. + self.cur = previous; + + ret + } +} + +fn stack_frame_record_iterator<'a>() -> Option> { + let fp = Address::::new(FP.get() as usize); + if !fp.is_valid_stack_addr() { + return None; + } + + Some(StackFrameRecordIterator { + cur: unsafe { &*(fp.as_usize() as *const _) }, + }) +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +/// Architectural implementation of the backtrace. +pub fn backtrace(f: impl FnOnce(Option<&mut dyn Iterator>)) { + f(stack_frame_record_iterator().as_mut().map(|s| s as _)) +} + +//-------------------------------------------------------------------------------------------------- +// Testing +//-------------------------------------------------------------------------------------------------- + +#[cfg(feature = "test_build")] +#[inline(always)] +/// Hack for corrupting the previous frame address in the current stack frame. +/// +/// # Safety +/// +/// - To be used only by testing code. +pub unsafe fn corrupt_previous_frame_addr() { + let sf = FP.get() as *mut usize; + *sf = 0x123; +} + +#[cfg(feature = "test_build")] +#[inline(always)] +/// Hack for corrupting the link in the current stack frame. +/// +/// # Safety +/// +/// - To be used only by testing code. +pub unsafe fn corrupt_link() { + let sf = FP.get() as *mut StackFrameRecord; + (*sf).link = Address::new(0x456); +} diff --git a/18_backtrace/kernel/src/_arch/aarch64/cpu.rs b/18_backtrace/kernel/src/_arch/aarch64/cpu.rs new file mode 100644 index 00000000..66da661c --- /dev/null +++ b/18_backtrace/kernel/src/_arch/aarch64/cpu.rs @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2018-2022 Andre Richter + +//! Architectural processor code. +//! +//! # Orientation +//! +//! Since arch modules are imported into generic modules using the path attribute, the path of this +//! file is: +//! +//! crate::cpu::arch_cpu + +use cortex_a::asm; + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +pub use asm::nop; + +/// Pause execution on the core. +#[inline(always)] +pub fn wait_forever() -> ! { + loop { + asm::wfe() + } +} + +//-------------------------------------------------------------------------------------------------- +// Testing +//-------------------------------------------------------------------------------------------------- +#[cfg(feature = "test_build")] +use qemu_exit::QEMUExit; + +#[cfg(feature = "test_build")] +const QEMU_EXIT_HANDLE: qemu_exit::AArch64 = qemu_exit::AArch64::new(); + +/// Make the host QEMU binary execute `exit(1)`. +#[cfg(feature = "test_build")] +pub fn qemu_exit_failure() -> ! { + QEMU_EXIT_HANDLE.exit_failure() +} + +/// Make the host QEMU binary execute `exit(0)`. +#[cfg(feature = "test_build")] +pub fn qemu_exit_success() -> ! { + QEMU_EXIT_HANDLE.exit_success() +} diff --git a/18_backtrace/kernel/src/_arch/aarch64/cpu/boot.rs b/18_backtrace/kernel/src/_arch/aarch64/cpu/boot.rs new file mode 100644 index 00000000..c0bc86be --- /dev/null +++ b/18_backtrace/kernel/src/_arch/aarch64/cpu/boot.rs @@ -0,0 +1,113 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2021-2022 Andre Richter + +//! Architectural boot code. +//! +//! # Orientation +//! +//! Since arch modules are imported into generic modules using the path attribute, the path of this +//! file is: +//! +//! crate::cpu::boot::arch_boot + +use crate::{memory, memory::Address}; +use core::{ + arch::global_asm, + sync::atomic::{compiler_fence, Ordering}, +}; +use cortex_a::{asm, registers::*}; +use tock_registers::interfaces::Writeable; + +// Assembly counterpart to this file. +global_asm!(include_str!("boot.s")); + +//-------------------------------------------------------------------------------------------------- +// Private Code +//-------------------------------------------------------------------------------------------------- + +/// Prepares the transition from EL2 to EL1. +/// +/// # Safety +/// +/// - The `bss` section is not initialized yet. The code must not use or reference it in any way. +/// - The HW state of EL1 must be prepared in a sound way. +#[inline(always)] +unsafe fn prepare_el2_to_el1_transition( + virt_boot_core_stack_end_exclusive_addr: u64, + virt_kernel_init_addr: u64, +) { + // Enable timer counter registers for EL1. + CNTHCTL_EL2.write(CNTHCTL_EL2::EL1PCEN::SET + CNTHCTL_EL2::EL1PCTEN::SET); + + // No offset for reading the counters. + CNTVOFF_EL2.set(0); + + // Set EL1 execution state to AArch64. + HCR_EL2.write(HCR_EL2::RW::EL1IsAarch64); + + // Set up a simulated exception return. + // + // First, fake a saved program status where all interrupts were masked and SP_EL1 was used as a + // stack pointer. + SPSR_EL2.write( + SPSR_EL2::D::Masked + + SPSR_EL2::A::Masked + + SPSR_EL2::I::Masked + + SPSR_EL2::F::Masked + + SPSR_EL2::M::EL1h, + ); + + // Second, let the link register point to kernel_init(). + ELR_EL2.set(virt_kernel_init_addr); + + // Set up SP_EL1 (stack pointer), which will be used by EL1 once we "return" to it. Since there + // are no plans to ever return to EL2, just re-use the same stack. + SP_EL1.set(virt_boot_core_stack_end_exclusive_addr); +} + +/// Reset the backtrace by setting link register and frame pointer to zero. +/// +/// # Safety +/// +/// - This function must only be used immediately before entering EL1. +#[inline(always)] +unsafe fn prepare_backtrace_reset() { + compiler_fence(Ordering::SeqCst); + FP.set(0); + LR.set(0); +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +/// The Rust entry of the `kernel` binary. +/// +/// The function is called from the assembly `_start` function. +/// +/// # Safety +/// +/// - Exception return from EL2 must must continue execution in EL1 with `kernel_init()`. +#[no_mangle] +pub unsafe extern "C" fn _start_rust( + phys_kernel_tables_base_addr: u64, + virt_boot_core_stack_end_exclusive_addr: u64, + virt_kernel_init_addr: u64, +) -> ! { + prepare_el2_to_el1_transition( + virt_boot_core_stack_end_exclusive_addr, + virt_kernel_init_addr, + ); + + // Turn on the MMU for EL1. + let addr = Address::new(phys_kernel_tables_base_addr as usize); + memory::mmu::enable_mmu_and_caching(addr).unwrap(); + + // Make the function we return to the root of a backtrace. + prepare_backtrace_reset(); + + // Use `eret` to "return" to EL1. Since virtual memory will already be enabled, this results in + // execution of kernel_init() in EL1 from its _virtual address_. + asm::eret() +} diff --git a/18_backtrace/kernel/src/_arch/aarch64/cpu/boot.s b/18_backtrace/kernel/src/_arch/aarch64/cpu/boot.s new file mode 100644 index 00000000..d2c9270d --- /dev/null +++ b/18_backtrace/kernel/src/_arch/aarch64/cpu/boot.s @@ -0,0 +1,100 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2021-2022 Andre Richter + +//-------------------------------------------------------------------------------------------------- +// Definitions +//-------------------------------------------------------------------------------------------------- + +// Load the address of a symbol into a register, PC-relative. +// +// The symbol must lie within +/- 4 GiB of the Program Counter. +// +// # Resources +// +// - https://sourceware.org/binutils/docs-2.36/as/AArch64_002dRelocations.html +.macro ADR_REL register, symbol + adrp \register, \symbol + add \register, \register, #:lo12:\symbol +.endm + +// Load the address of a symbol into a register, absolute. +// +// # Resources +// +// - https://sourceware.org/binutils/docs-2.36/as/AArch64_002dRelocations.html +.macro ADR_ABS register, symbol + movz \register, #:abs_g3:\symbol + movk \register, #:abs_g2_nc:\symbol + movk \register, #:abs_g1_nc:\symbol + movk \register, #:abs_g0_nc:\symbol +.endm + +.equ _EL2, 0x8 +.equ _core_id_mask, 0b11 + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- +.section .text._start + +//------------------------------------------------------------------------------ +// fn _start() +//------------------------------------------------------------------------------ +_start: + // Only proceed if the core executes in EL2. Park it otherwise. + mrs x0, CurrentEL + cmp x0, _EL2 + b.ne .L_parking_loop + + // Only proceed on the boot core. Park it otherwise. + mrs x1, MPIDR_EL1 + and x1, x1, _core_id_mask + ldr x2, BOOT_CORE_ID // provided by bsp/__board_name__/cpu.rs + cmp x1, x2 + b.ne .L_parking_loop + + // If execution reaches here, it is the boot core. + + // Initialize DRAM. + ADR_REL x0, __bss_start + ADR_REL x1, __bss_end_exclusive + +.L_bss_init_loop: + cmp x0, x1 + b.eq .L_prepare_rust + stp xzr, xzr, [x0], #16 + b .L_bss_init_loop + + // Prepare the jump to Rust code. +.L_prepare_rust: + // Load the base address of the kernel's translation tables. + ldr x0, PHYS_KERNEL_TABLES_BASE_ADDR // provided by bsp/__board_name__/memory/mmu.rs + + // Load the _absolute_ addresses of the following symbols. Since the kernel is linked at + // the top of the 64 bit address space, these are effectively virtual addresses. + ADR_ABS x1, __boot_core_stack_end_exclusive + ADR_ABS x2, kernel_init + + // Load the PC-relative address of the stack and set the stack pointer. + // + // Since _start() is the first function that runs after the firmware has loaded the kernel + // into memory, retrieving this symbol PC-relative returns the "physical" address. + // + // Setting the stack pointer to this value ensures that anything that still runs in EL2, + // until the kernel returns to EL1 with the MMU enabled, works as well. After the return to + // EL1, the virtual address of the stack retrieved above will be used. + ADR_REL x4, __boot_core_stack_end_exclusive + mov sp, x4 + + // Jump to Rust code. x0, x1 and x2 hold the function arguments provided to _start_rust(). + b _start_rust + + // Infinitely wait for events (aka "park the core"). +.L_parking_loop: + wfe + b .L_parking_loop + +.size _start, . - _start +.type _start, function +.global _start diff --git a/18_backtrace/kernel/src/_arch/aarch64/cpu/smp.rs b/18_backtrace/kernel/src/_arch/aarch64/cpu/smp.rs new file mode 100644 index 00000000..351fde62 --- /dev/null +++ b/18_backtrace/kernel/src/_arch/aarch64/cpu/smp.rs @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2018-2022 Andre Richter + +//! Architectural symmetric multiprocessing. +//! +//! # Orientation +//! +//! Since arch modules are imported into generic modules using the path attribute, the path of this +//! file is: +//! +//! crate::cpu::smp::arch_smp + +use cortex_a::registers::*; +use tock_registers::interfaces::Readable; + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +/// Return the executing core's id. +#[inline(always)] +pub fn core_id() -> T +where + T: From, +{ + const CORE_MASK: u64 = 0b11; + + T::from((MPIDR_EL1.get() & CORE_MASK) as u8) +} diff --git a/18_backtrace/kernel/src/_arch/aarch64/exception.rs b/18_backtrace/kernel/src/_arch/aarch64/exception.rs new file mode 100644 index 00000000..6781758a --- /dev/null +++ b/18_backtrace/kernel/src/_arch/aarch64/exception.rs @@ -0,0 +1,323 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2018-2022 Andre Richter + +//! Architectural synchronous and asynchronous exception handling. +//! +//! # Orientation +//! +//! Since arch modules are imported into generic modules using the path attribute, the path of this +//! file is: +//! +//! crate::exception::arch_exception + +use crate::{bsp, exception, memory, symbols}; +use core::{arch::global_asm, cell::UnsafeCell, fmt}; +use cortex_a::{asm::barrier, registers::*}; +use tock_registers::{ + interfaces::{Readable, Writeable}, + registers::InMemoryRegister, +}; + +// Assembly counterpart to this file. +global_asm!(include_str!("exception.s")); + +//-------------------------------------------------------------------------------------------------- +// Private Definitions +//-------------------------------------------------------------------------------------------------- + +/// Wrapper structs for memory copies of registers. +#[repr(transparent)] +struct SpsrEL1(InMemoryRegister); +struct EsrEL1(InMemoryRegister); + +/// The exception context as it is stored on the stack on exception entry. +#[repr(C)] +struct ExceptionContext { + /// General Purpose Registers. + gpr: [u64; 30], + + /// The link register, aka x30. + lr: u64, + + /// Exception link register. The program counter at the time the exception happened. + elr_el1: u64, + + /// Saved program status. + spsr_el1: SpsrEL1, + + /// Exception syndrome register. + esr_el1: EsrEL1, +} + +//-------------------------------------------------------------------------------------------------- +// Private Code +//-------------------------------------------------------------------------------------------------- + +/// Prints verbose information about the exception and then panics. +fn default_exception_handler(exc: &ExceptionContext) { + panic!( + "CPU Exception!\n\n\ + {}", + exc + ); +} + +//------------------------------------------------------------------------------ +// Current, EL0 +//------------------------------------------------------------------------------ + +#[no_mangle] +unsafe extern "C" fn current_el0_synchronous(_e: &mut ExceptionContext) { + panic!("Should not be here. Use of SP_EL0 in EL1 is not supported.") +} + +#[no_mangle] +unsafe extern "C" fn current_el0_irq(_e: &mut ExceptionContext) { + panic!("Should not be here. Use of SP_EL0 in EL1 is not supported.") +} + +#[no_mangle] +unsafe extern "C" fn current_el0_serror(_e: &mut ExceptionContext) { + panic!("Should not be here. Use of SP_EL0 in EL1 is not supported.") +} + +//------------------------------------------------------------------------------ +// Current, ELx +//------------------------------------------------------------------------------ + +#[no_mangle] +unsafe extern "C" fn current_elx_synchronous(e: &mut ExceptionContext) { + #[cfg(feature = "test_build")] + { + const TEST_SVC_ID: u64 = 0x1337; + + if let Some(ESR_EL1::EC::Value::SVC64) = e.esr_el1.exception_class() { + if e.esr_el1.iss() == TEST_SVC_ID { + return; + } + } + } + + default_exception_handler(e); +} + +#[no_mangle] +unsafe extern "C" fn current_elx_irq(_e: &mut ExceptionContext) { + use exception::asynchronous::interface::IRQManager; + + let token = &exception::asynchronous::IRQContext::new(); + bsp::exception::asynchronous::irq_manager().handle_pending_irqs(token); +} + +#[no_mangle] +unsafe extern "C" fn current_elx_serror(e: &mut ExceptionContext) { + default_exception_handler(e); +} + +//------------------------------------------------------------------------------ +// Lower, AArch64 +//------------------------------------------------------------------------------ + +#[no_mangle] +unsafe extern "C" fn lower_aarch64_synchronous(e: &mut ExceptionContext) { + default_exception_handler(e); +} + +#[no_mangle] +unsafe extern "C" fn lower_aarch64_irq(e: &mut ExceptionContext) { + default_exception_handler(e); +} + +#[no_mangle] +unsafe extern "C" fn lower_aarch64_serror(e: &mut ExceptionContext) { + default_exception_handler(e); +} + +//------------------------------------------------------------------------------ +// Lower, AArch32 +//------------------------------------------------------------------------------ + +#[no_mangle] +unsafe extern "C" fn lower_aarch32_synchronous(e: &mut ExceptionContext) { + default_exception_handler(e); +} + +#[no_mangle] +unsafe extern "C" fn lower_aarch32_irq(e: &mut ExceptionContext) { + default_exception_handler(e); +} + +#[no_mangle] +unsafe extern "C" fn lower_aarch32_serror(e: &mut ExceptionContext) { + default_exception_handler(e); +} + +//------------------------------------------------------------------------------ +// Misc +//------------------------------------------------------------------------------ + +/// Human readable SPSR_EL1. +#[rustfmt::skip] +impl fmt::Display for SpsrEL1 { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + // Raw value. + writeln!(f, "SPSR_EL1: {:#010x}", self.0.get())?; + + let to_flag_str = |x| -> _ { + if x { "Set" } else { "Not set" } + }; + + writeln!(f, " Flags:")?; + writeln!(f, " Negative (N): {}", to_flag_str(self.0.is_set(SPSR_EL1::N)))?; + writeln!(f, " Zero (Z): {}", to_flag_str(self.0.is_set(SPSR_EL1::Z)))?; + writeln!(f, " Carry (C): {}", to_flag_str(self.0.is_set(SPSR_EL1::C)))?; + writeln!(f, " Overflow (V): {}", to_flag_str(self.0.is_set(SPSR_EL1::V)))?; + + let to_mask_str = |x| -> _ { + if x { "Masked" } else { "Unmasked" } + }; + + writeln!(f, " Exception handling state:")?; + writeln!(f, " Debug (D): {}", to_mask_str(self.0.is_set(SPSR_EL1::D)))?; + writeln!(f, " SError (A): {}", to_mask_str(self.0.is_set(SPSR_EL1::A)))?; + writeln!(f, " IRQ (I): {}", to_mask_str(self.0.is_set(SPSR_EL1::I)))?; + writeln!(f, " FIQ (F): {}", to_mask_str(self.0.is_set(SPSR_EL1::F)))?; + + write!(f, " Illegal Execution State (IL): {}", + to_flag_str(self.0.is_set(SPSR_EL1::IL)) + ) + } +} + +impl EsrEL1 { + #[inline(always)] + fn exception_class(&self) -> Option { + self.0.read_as_enum(ESR_EL1::EC) + } + + #[cfg(feature = "test_build")] + #[inline(always)] + fn iss(&self) -> u64 { + self.0.read(ESR_EL1::ISS) + } +} + +/// Human readable ESR_EL1. +#[rustfmt::skip] +impl fmt::Display for EsrEL1 { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + // Raw print of whole register. + writeln!(f, "ESR_EL1: {:#010x}", self.0.get())?; + + // Raw print of exception class. + write!(f, " Exception Class (EC) : {:#x}", self.0.read(ESR_EL1::EC))?; + + // Exception class. + let ec_translation = match self.exception_class() { + Some(ESR_EL1::EC::Value::DataAbortCurrentEL) => "Data Abort, current EL", + _ => "N/A", + }; + writeln!(f, " - {}", ec_translation)?; + + // Raw print of instruction specific syndrome. + write!(f, " Instr Specific Syndrome (ISS): {:#x}", self.0.read(ESR_EL1::ISS)) + } +} + +impl ExceptionContext { + #[inline(always)] + fn exception_class(&self) -> Option { + self.esr_el1.exception_class() + } + + #[inline(always)] + fn fault_address_valid(&self) -> bool { + use ESR_EL1::EC::Value::*; + + match self.exception_class() { + None => false, + Some(ec) => matches!( + ec, + InstrAbortLowerEL + | InstrAbortCurrentEL + | PCAlignmentFault + | DataAbortLowerEL + | DataAbortCurrentEL + | WatchpointLowerEL + | WatchpointCurrentEL + ), + } + } +} + +/// Human readable print of the exception context. +impl fmt::Display for ExceptionContext { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + writeln!(f, "{}", self.esr_el1)?; + + if self.fault_address_valid() { + writeln!(f, "FAR_EL1: {:#018x}", FAR_EL1.get() as usize)?; + } + + writeln!(f, "{}", self.spsr_el1)?; + writeln!(f, "ELR_EL1: {:#018x}", self.elr_el1)?; + writeln!( + f, + " Symbol: {}", + match symbols::lookup_symbol(memory::Address::new(self.elr_el1 as usize)) { + Some(sym) => sym.name(), + _ => "Symbol not found", + } + )?; + writeln!(f)?; + writeln!(f, "General purpose register:")?; + + #[rustfmt::skip] + let alternating = |x| -> _ { + if x % 2 == 0 { " " } else { "\n" } + }; + + // Print two registers per line. + for (i, reg) in self.gpr.iter().enumerate() { + write!(f, " x{: <2}: {: >#018x}{}", i, reg, alternating(i))?; + } + write!(f, " lr : {:#018x}", self.lr) + } +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- +use crate::exception::PrivilegeLevel; + +/// The processing element's current privilege level. +pub fn current_privilege_level() -> (PrivilegeLevel, &'static str) { + let el = CurrentEL.read_as_enum(CurrentEL::EL); + match el { + Some(CurrentEL::EL::Value::EL2) => (PrivilegeLevel::Hypervisor, "EL2"), + Some(CurrentEL::EL::Value::EL1) => (PrivilegeLevel::Kernel, "EL1"), + Some(CurrentEL::EL::Value::EL0) => (PrivilegeLevel::User, "EL0"), + _ => (PrivilegeLevel::Unknown, "Unknown"), + } +} + +/// Init exception handling by setting the exception vector base address register. +/// +/// # Safety +/// +/// - Changes the HW state of the executing core. +/// - The vector table and the symbol `__exception_vector_table_start` from the linker script must +/// adhere to the alignment and size constraints demanded by the ARMv8-A Architecture Reference +/// Manual. +pub unsafe fn handling_init() { + // Provided by exception.S. + extern "Rust" { + static __exception_vector_start: UnsafeCell<()>; + } + + VBAR_EL1.set(__exception_vector_start.get() as u64); + + // Force VBAR update to complete before next instruction. + barrier::isb(barrier::SY); +} diff --git a/18_backtrace/kernel/src/_arch/aarch64/exception.s b/18_backtrace/kernel/src/_arch/aarch64/exception.s new file mode 100644 index 00000000..17acaf59 --- /dev/null +++ b/18_backtrace/kernel/src/_arch/aarch64/exception.s @@ -0,0 +1,190 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2018-2022 Andre Richter + +//-------------------------------------------------------------------------------------------------- +// Definitions +//-------------------------------------------------------------------------------------------------- + +/// Call the function provided by parameter `\handler` after saving the exception context. Provide +/// the context as the first parameter to '\handler'. +.macro CALL_WITH_CONTEXT handler is_lower_el is_sync +__vector_\handler: + // Make room on the stack for the exception context. + sub sp, sp, #16 * 18 + + // Store all general purpose registers on the stack. + stp x0, x1, [sp, #16 * 0] + stp x2, x3, [sp, #16 * 1] + stp x4, x5, [sp, #16 * 2] + stp x6, x7, [sp, #16 * 3] + stp x8, x9, [sp, #16 * 4] + stp x10, x11, [sp, #16 * 5] + stp x12, x13, [sp, #16 * 6] + stp x14, x15, [sp, #16 * 7] + stp x16, x17, [sp, #16 * 8] + stp x18, x19, [sp, #16 * 9] + stp x20, x21, [sp, #16 * 10] + stp x22, x23, [sp, #16 * 11] + stp x24, x25, [sp, #16 * 12] + stp x26, x27, [sp, #16 * 13] + stp x28, x29, [sp, #16 * 14] + + // Add the exception link register (ELR_EL1), saved program status (SPSR_EL1) and exception + // syndrome register (ESR_EL1). + mrs x1, ELR_EL1 + mrs x2, SPSR_EL1 + mrs x3, ESR_EL1 + + stp lr, x1, [sp, #16 * 15] + stp x2, x3, [sp, #16 * 16] + + // Build a stack frame for backtracing. +.if \is_lower_el == 1 + // If we came from a lower EL, make it a root frame (by storing zero) so that the kernel + // does not attempt to trace into userspace. + stp xzr, xzr, [sp, #16 * 17] +.else + // For normal branches, the link address points to the instruction to be executed _after_ + // returning from a branch. In a backtrace, we want to show the instruction that caused the + // branch, though. That is why code in backtrace.rs subtracts 4 (length of one instruction) + // from the link address. + // + // Here we have a special case, though, because ELR_EL1 is used instead of LR to build the + // stack frame, so that it becomes possible to trace beyond an exception. Hence, it must be + // considered that semantics for ELR_EL1 differ from case to case. + // + // Unless an "exception generating instruction" was executed, ELR_EL1 already points to the + // the correct instruction, and hence the subtraction by 4 in backtrace.rs would yield wrong + // results. To cover for this, 4 is added to ELR_EL1 below unless the cause of exception was + // an SVC instruction. BRK and HLT are "exception generating instructions" as well, but they + // are not expected and therefore left out for now. + // + // For reference: Search for "preferred exception return address" in the Architecture + // Reference Manual for ARMv8-A. +.if \is_sync == 1 + lsr w3, w3, #26 // w3 = ESR_EL1.EC + cmp w3, #0x15 // w3 == SVC64 ? + b.eq 1f +.endif + add x1, x1, #4 +1: + stp x29, x1, [sp, #16 * 17] +.endif + + // Set the frame pointer to the stack frame record. + add x29, sp, #16 * 17 + + // x0 is the first argument for the function called through `\handler`. + mov x0, sp + + // Call `\handler`. + bl \handler + + // After returning from exception handling code, replay the saved context and return via + // `eret`. + b __exception_restore_context + +.size __vector_\handler, . - __vector_\handler +.type __vector_\handler, function +.endm + +.macro FIQ_SUSPEND +1: wfe + b 1b +.endm + +//-------------------------------------------------------------------------------------------------- +// Private Code +//-------------------------------------------------------------------------------------------------- +.section .text + +//------------------------------------------------------------------------------ +// The exception vector table. +//------------------------------------------------------------------------------ + +// Align by 2^11 bytes, as demanded by ARMv8-A. Same as ALIGN(2048) in an ld script. +.align 11 + +// Export a symbol for the Rust code to use. +__exception_vector_start: + +// Current exception level with SP_EL0. +// +// .org sets the offset relative to section start. +// +// # Safety +// +// - It must be ensured that `CALL_WITH_CONTEXT` <= 0x80 bytes. +.org 0x000 + CALL_WITH_CONTEXT current_el0_synchronous, 0, 1 +.org 0x080 + CALL_WITH_CONTEXT current_el0_irq, 0, 0 +.org 0x100 + FIQ_SUSPEND +.org 0x180 + CALL_WITH_CONTEXT current_el0_serror, 0, 0 + +// Current exception level with SP_ELx, x > 0. +.org 0x200 + CALL_WITH_CONTEXT current_elx_synchronous, 0, 1 +.org 0x280 + CALL_WITH_CONTEXT current_elx_irq, 0, 0 +.org 0x300 + FIQ_SUSPEND +.org 0x380 + CALL_WITH_CONTEXT current_elx_serror, 0, 0 + +// Lower exception level, AArch64 +.org 0x400 + CALL_WITH_CONTEXT lower_aarch64_synchronous, 1, 1 +.org 0x480 + CALL_WITH_CONTEXT lower_aarch64_irq, 1, 0 +.org 0x500 + FIQ_SUSPEND +.org 0x580 + CALL_WITH_CONTEXT lower_aarch64_serror, 1, 0 + +// Lower exception level, AArch32 +.org 0x600 + CALL_WITH_CONTEXT lower_aarch32_synchronous, 1, 0 +.org 0x680 + CALL_WITH_CONTEXT lower_aarch32_irq, 1, 0 +.org 0x700 + FIQ_SUSPEND +.org 0x780 + CALL_WITH_CONTEXT lower_aarch32_serror, 1, 0 +.org 0x800 + +//------------------------------------------------------------------------------ +// fn __exception_restore_context() +//------------------------------------------------------------------------------ +__exception_restore_context: + ldr w19, [sp, #16 * 16] + ldp lr, x20, [sp, #16 * 15] + + msr SPSR_EL1, x19 + msr ELR_EL1, x20 + + ldp x0, x1, [sp, #16 * 0] + ldp x2, x3, [sp, #16 * 1] + ldp x4, x5, [sp, #16 * 2] + ldp x6, x7, [sp, #16 * 3] + ldp x8, x9, [sp, #16 * 4] + ldp x10, x11, [sp, #16 * 5] + ldp x12, x13, [sp, #16 * 6] + ldp x14, x15, [sp, #16 * 7] + ldp x16, x17, [sp, #16 * 8] + ldp x18, x19, [sp, #16 * 9] + ldp x20, x21, [sp, #16 * 10] + ldp x22, x23, [sp, #16 * 11] + ldp x24, x25, [sp, #16 * 12] + ldp x26, x27, [sp, #16 * 13] + ldp x28, x29, [sp, #16 * 14] + + add sp, sp, #16 * 18 + + eret + +.size __exception_restore_context, . - __exception_restore_context +.type __exception_restore_context, function diff --git a/18_backtrace/kernel/src/_arch/aarch64/exception/asynchronous.rs b/18_backtrace/kernel/src/_arch/aarch64/exception/asynchronous.rs new file mode 100644 index 00000000..73b82e65 --- /dev/null +++ b/18_backtrace/kernel/src/_arch/aarch64/exception/asynchronous.rs @@ -0,0 +1,152 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2018-2022 Andre Richter + +//! Architectural asynchronous exception handling. +//! +//! # Orientation +//! +//! Since arch modules are imported into generic modules using the path attribute, the path of this +//! file is: +//! +//! crate::exception::asynchronous::arch_asynchronous + +use core::arch::asm; +use cortex_a::registers::*; +use tock_registers::interfaces::{Readable, Writeable}; + +//-------------------------------------------------------------------------------------------------- +// Private Definitions +//-------------------------------------------------------------------------------------------------- + +mod daif_bits { + pub const IRQ: u8 = 0b0010; +} + +trait DaifField { + fn daif_field() -> tock_registers::fields::Field; +} + +struct Debug; +struct SError; +struct IRQ; +struct FIQ; + +//-------------------------------------------------------------------------------------------------- +// Private Code +//-------------------------------------------------------------------------------------------------- + +impl DaifField for Debug { + fn daif_field() -> tock_registers::fields::Field { + DAIF::D + } +} + +impl DaifField for SError { + fn daif_field() -> tock_registers::fields::Field { + DAIF::A + } +} + +impl DaifField for IRQ { + fn daif_field() -> tock_registers::fields::Field { + DAIF::I + } +} + +impl DaifField for FIQ { + fn daif_field() -> tock_registers::fields::Field { + DAIF::F + } +} + +fn is_masked() -> bool +where + T: DaifField, +{ + DAIF.is_set(T::daif_field()) +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +/// Returns whether IRQs are masked on the executing core. +pub fn is_local_irq_masked() -> bool { + !is_masked::() +} + +/// Unmask IRQs on the executing core. +/// +/// It is not needed to place an explicit instruction synchronization barrier after the `msr`. +/// Quoting the Architecture Reference Manual for ARMv8-A, section C5.1.3: +/// +/// "Writes to PSTATE.{PAN, D, A, I, F} occur in program order without the need for additional +/// synchronization." +/// +/// # Safety +/// +/// - Changes the HW state of the executing core. +#[inline(always)] +pub unsafe fn local_irq_unmask() { + #[rustfmt::skip] + asm!( + "msr DAIFClr, {arg}", + arg = const daif_bits::IRQ, + options(nomem, nostack, preserves_flags) + ); +} + +/// Mask IRQs on the executing core. +/// +/// # Safety +/// +/// - Changes the HW state of the executing core. +#[inline(always)] +pub unsafe fn local_irq_mask() { + #[rustfmt::skip] + asm!( + "msr DAIFSet, {arg}", + arg = const daif_bits::IRQ, + options(nomem, nostack, preserves_flags) + ); +} + +/// Mask IRQs on the executing core and return the previously saved interrupt mask bits (DAIF). +/// +/// # Safety +/// +/// - Changes the HW state of the executing core. +#[inline(always)] +pub unsafe fn local_irq_mask_save() -> u64 { + let saved = DAIF.get(); + local_irq_mask(); + + saved +} + +/// Restore the interrupt mask bits (DAIF) using the callee's argument. +/// +/// # Safety +/// +/// - Changes the HW state of the executing core. +/// - No sanity checks on the input. +#[inline(always)] +pub unsafe fn local_irq_restore(saved: u64) { + DAIF.set(saved); +} + +/// Print the AArch64 exceptions status. +#[rustfmt::skip] +pub fn print_state() { + use crate::info; + + let to_mask_str = |x| -> _ { + if x { "Masked" } else { "Unmasked" } + }; + + info!(" Debug: {}", to_mask_str(is_masked::())); + info!(" SError: {}", to_mask_str(is_masked::())); + info!(" IRQ: {}", to_mask_str(is_masked::())); + info!(" FIQ: {}", to_mask_str(is_masked::())); +} diff --git a/18_backtrace/kernel/src/_arch/aarch64/memory/mmu.rs b/18_backtrace/kernel/src/_arch/aarch64/memory/mmu.rs new file mode 100644 index 00000000..3d6c18b7 --- /dev/null +++ b/18_backtrace/kernel/src/_arch/aarch64/memory/mmu.rs @@ -0,0 +1,158 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2018-2022 Andre Richter + +//! Memory Management Unit Driver. +//! +//! Only 64 KiB granule is supported. +//! +//! # Orientation +//! +//! Since arch modules are imported into generic modules using the path attribute, the path of this +//! file is: +//! +//! crate::memory::mmu::arch_mmu + +use crate::{ + bsp, memory, + memory::{mmu::TranslationGranule, Address, Physical}, +}; +use core::intrinsics::unlikely; +use cortex_a::{asm::barrier, registers::*}; +use tock_registers::interfaces::{ReadWriteable, Readable, Writeable}; + +//-------------------------------------------------------------------------------------------------- +// Private Definitions +//-------------------------------------------------------------------------------------------------- + +/// Memory Management Unit type. +struct MemoryManagementUnit; + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +pub type Granule512MiB = TranslationGranule<{ 512 * 1024 * 1024 }>; +pub type Granule64KiB = TranslationGranule<{ 64 * 1024 }>; + +/// Constants for indexing the MAIR_EL1. +#[allow(dead_code)] +pub mod mair { + pub const DEVICE: u64 = 0; + pub const NORMAL: u64 = 1; +} + +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +static MMU: MemoryManagementUnit = MemoryManagementUnit; + +//-------------------------------------------------------------------------------------------------- +// Private Code +//-------------------------------------------------------------------------------------------------- + +impl memory::mmu::AddressSpace { + /// Checks for architectural restrictions. + pub const fn arch_address_space_size_sanity_checks() { + // Size must be at least one full 512 MiB table. + assert!((AS_SIZE % Granule512MiB::SIZE) == 0); + + // Check for 48 bit virtual address size as maximum, which is supported by any ARMv8 + // version. + assert!(AS_SIZE <= (1 << 48)); + } +} + +impl MemoryManagementUnit { + /// Setup function for the MAIR_EL1 register. + #[inline(always)] + fn set_up_mair(&self) { + // Define the memory types being mapped. + MAIR_EL1.write( + // Attribute 1 - Cacheable normal DRAM. + MAIR_EL1::Attr1_Normal_Outer::WriteBack_NonTransient_ReadWriteAlloc + + MAIR_EL1::Attr1_Normal_Inner::WriteBack_NonTransient_ReadWriteAlloc + + + // Attribute 0 - Device. + MAIR_EL1::Attr0_Device::nonGathering_nonReordering_EarlyWriteAck, + ); + } + + /// Configure various settings of stage 1 of the EL1 translation regime. + #[inline(always)] + fn configure_translation_control(&self) { + let t1sz = (64 - bsp::memory::mmu::KernelVirtAddrSpace::SIZE_SHIFT) as u64; + + TCR_EL1.write( + TCR_EL1::TBI1::Used + + TCR_EL1::IPS::Bits_40 + + TCR_EL1::TG1::KiB_64 + + TCR_EL1::SH1::Inner + + TCR_EL1::ORGN1::WriteBack_ReadAlloc_WriteAlloc_Cacheable + + TCR_EL1::IRGN1::WriteBack_ReadAlloc_WriteAlloc_Cacheable + + TCR_EL1::EPD1::EnableTTBR1Walks + + TCR_EL1::A1::TTBR1 + + TCR_EL1::T1SZ.val(t1sz) + + TCR_EL1::EPD0::DisableTTBR0Walks, + ); + } +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +/// Return a reference to the MMU instance. +pub fn mmu() -> &'static impl memory::mmu::interface::MMU { + &MMU +} + +//------------------------------------------------------------------------------ +// OS Interface Code +//------------------------------------------------------------------------------ +use memory::mmu::MMUEnableError; + +impl memory::mmu::interface::MMU for MemoryManagementUnit { + unsafe fn enable_mmu_and_caching( + &self, + phys_tables_base_addr: Address, + ) -> Result<(), MMUEnableError> { + if unlikely(self.is_enabled()) { + return Err(MMUEnableError::AlreadyEnabled); + } + + // Fail early if translation granule is not supported. + if unlikely(!ID_AA64MMFR0_EL1.matches_all(ID_AA64MMFR0_EL1::TGran64::Supported)) { + return Err(MMUEnableError::Other( + "Translation granule not supported in HW", + )); + } + + // Prepare the memory attribute indirection register. + self.set_up_mair(); + + // Set the "Translation Table Base Register". + TTBR1_EL1.set_baddr(phys_tables_base_addr.as_usize() as u64); + + self.configure_translation_control(); + + // Switch the MMU on. + // + // First, force all previous changes to be seen before the MMU is enabled. + barrier::isb(barrier::SY); + + // Enable the MMU and turn on data and instruction caching. + SCTLR_EL1.modify(SCTLR_EL1::M::Enable + SCTLR_EL1::C::Cacheable + SCTLR_EL1::I::Cacheable); + + // Force MMU init to complete before next instruction. + barrier::isb(barrier::SY); + + Ok(()) + } + + #[inline(always)] + fn is_enabled(&self) -> bool { + SCTLR_EL1.matches_all(SCTLR_EL1::M::Enable) + } +} diff --git a/18_backtrace/kernel/src/_arch/aarch64/memory/mmu/translation_table.rs b/18_backtrace/kernel/src/_arch/aarch64/memory/mmu/translation_table.rs new file mode 100644 index 00000000..f0b4ac85 --- /dev/null +++ b/18_backtrace/kernel/src/_arch/aarch64/memory/mmu/translation_table.rs @@ -0,0 +1,521 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2021-2022 Andre Richter + +//! Architectural translation table. +//! +//! Only 64 KiB granule is supported. +//! +//! # Orientation +//! +//! Since arch modules are imported into generic modules using the path attribute, the path of this +//! file is: +//! +//! crate::memory::mmu::translation_table::arch_translation_table + +use crate::{ + bsp, + memory::{ + self, + mmu::{ + arch_mmu::{Granule512MiB, Granule64KiB}, + AccessPermissions, AttributeFields, MemAttributes, MemoryRegion, PageAddress, + }, + Address, Physical, Virtual, + }, +}; +use core::convert; +use tock_registers::{ + interfaces::{Readable, Writeable}, + register_bitfields, + registers::InMemoryRegister, +}; + +//-------------------------------------------------------------------------------------------------- +// Private Definitions +//-------------------------------------------------------------------------------------------------- + +// A table descriptor, as per ARMv8-A Architecture Reference Manual Figure D5-15. +register_bitfields! {u64, + STAGE1_TABLE_DESCRIPTOR [ + /// Physical address of the next descriptor. + NEXT_LEVEL_TABLE_ADDR_64KiB OFFSET(16) NUMBITS(32) [], // [47:16] + + TYPE OFFSET(1) NUMBITS(1) [ + Block = 0, + Table = 1 + ], + + VALID OFFSET(0) NUMBITS(1) [ + False = 0, + True = 1 + ] + ] +} + +// A level 3 page descriptor, as per ARMv8-A Architecture Reference Manual Figure D5-17. +register_bitfields! {u64, + STAGE1_PAGE_DESCRIPTOR [ + /// Unprivileged execute-never. + UXN OFFSET(54) NUMBITS(1) [ + False = 0, + True = 1 + ], + + /// Privileged execute-never. + PXN OFFSET(53) NUMBITS(1) [ + False = 0, + True = 1 + ], + + /// Physical address of the next table descriptor (lvl2) or the page descriptor (lvl3). + OUTPUT_ADDR_64KiB OFFSET(16) NUMBITS(32) [], // [47:16] + + /// Access flag. + AF OFFSET(10) NUMBITS(1) [ + False = 0, + True = 1 + ], + + /// Shareability field. + SH OFFSET(8) NUMBITS(2) [ + OuterShareable = 0b10, + InnerShareable = 0b11 + ], + + /// Access Permissions. + AP OFFSET(6) NUMBITS(2) [ + RW_EL1 = 0b00, + RW_EL1_EL0 = 0b01, + RO_EL1 = 0b10, + RO_EL1_EL0 = 0b11 + ], + + /// Memory attributes index into the MAIR_EL1 register. + AttrIndx OFFSET(2) NUMBITS(3) [], + + TYPE OFFSET(1) NUMBITS(1) [ + Reserved_Invalid = 0, + Page = 1 + ], + + VALID OFFSET(0) NUMBITS(1) [ + False = 0, + True = 1 + ] + ] +} + +/// A table descriptor for 64 KiB aperture. +/// +/// The output points to the next table. +#[derive(Copy, Clone)] +#[repr(C)] +struct TableDescriptor { + value: u64, +} + +/// A page descriptor with 64 KiB aperture. +/// +/// The output points to physical memory. +#[derive(Copy, Clone)] +#[repr(C)] +struct PageDescriptor { + value: u64, +} + +trait StartAddr { + fn virt_start_addr(&self) -> Address; +} + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +/// Big monolithic struct for storing the translation tables. Individual levels must be 64 KiB +/// aligned, so the lvl3 is put first. +#[repr(C)] +#[repr(align(65536))] +pub struct FixedSizeTranslationTable { + /// Page descriptors, covering 64 KiB windows per entry. + lvl3: [[PageDescriptor; 8192]; NUM_TABLES], + + /// Table descriptors, covering 512 MiB windows. + lvl2: [TableDescriptor; NUM_TABLES], + + /// Have the tables been initialized? + initialized: bool, +} + +//-------------------------------------------------------------------------------------------------- +// Private Code +//-------------------------------------------------------------------------------------------------- + +impl StartAddr for [T; N] { + fn virt_start_addr(&self) -> Address { + Address::new(self as *const _ as usize) + } +} + +impl TableDescriptor { + /// Create an instance. + /// + /// Descriptor is invalid by default. + pub const fn new_zeroed() -> Self { + Self { value: 0 } + } + + /// Create an instance pointing to the supplied address. + pub fn from_next_lvl_table_addr(phys_next_lvl_table_addr: Address) -> Self { + let val = InMemoryRegister::::new(0); + + let shifted = phys_next_lvl_table_addr.as_usize() >> Granule64KiB::SHIFT; + val.write( + STAGE1_TABLE_DESCRIPTOR::NEXT_LEVEL_TABLE_ADDR_64KiB.val(shifted as u64) + + STAGE1_TABLE_DESCRIPTOR::TYPE::Table + + STAGE1_TABLE_DESCRIPTOR::VALID::True, + ); + + TableDescriptor { value: val.get() } + } +} + +/// Convert the kernel's generic memory attributes to HW-specific attributes of the MMU. +impl convert::From + for tock_registers::fields::FieldValue +{ + fn from(attribute_fields: AttributeFields) -> Self { + // Memory attributes. + let mut desc = match attribute_fields.mem_attributes { + MemAttributes::CacheableDRAM => { + STAGE1_PAGE_DESCRIPTOR::SH::InnerShareable + + STAGE1_PAGE_DESCRIPTOR::AttrIndx.val(memory::mmu::arch_mmu::mair::NORMAL) + } + MemAttributes::Device => { + STAGE1_PAGE_DESCRIPTOR::SH::OuterShareable + + STAGE1_PAGE_DESCRIPTOR::AttrIndx.val(memory::mmu::arch_mmu::mair::DEVICE) + } + }; + + // Access Permissions. + desc += match attribute_fields.acc_perms { + AccessPermissions::ReadOnly => STAGE1_PAGE_DESCRIPTOR::AP::RO_EL1, + AccessPermissions::ReadWrite => STAGE1_PAGE_DESCRIPTOR::AP::RW_EL1, + }; + + // The execute-never attribute is mapped to PXN in AArch64. + desc += if attribute_fields.execute_never { + STAGE1_PAGE_DESCRIPTOR::PXN::True + } else { + STAGE1_PAGE_DESCRIPTOR::PXN::False + }; + + // Always set unprivileged exectue-never as long as userspace is not implemented yet. + desc += STAGE1_PAGE_DESCRIPTOR::UXN::True; + + desc + } +} + +/// Convert the HW-specific attributes of the MMU to kernel's generic memory attributes. +impl convert::TryFrom> for AttributeFields { + type Error = &'static str; + + fn try_from( + desc: InMemoryRegister, + ) -> Result { + let mem_attributes = match desc.read(STAGE1_PAGE_DESCRIPTOR::AttrIndx) { + memory::mmu::arch_mmu::mair::NORMAL => MemAttributes::CacheableDRAM, + memory::mmu::arch_mmu::mair::DEVICE => MemAttributes::Device, + _ => return Err("Unexpected memory attribute"), + }; + + let acc_perms = match desc.read_as_enum(STAGE1_PAGE_DESCRIPTOR::AP) { + Some(STAGE1_PAGE_DESCRIPTOR::AP::Value::RO_EL1) => AccessPermissions::ReadOnly, + Some(STAGE1_PAGE_DESCRIPTOR::AP::Value::RW_EL1) => AccessPermissions::ReadWrite, + _ => return Err("Unexpected access permission"), + }; + + let execute_never = desc.read(STAGE1_PAGE_DESCRIPTOR::PXN) > 0; + + Ok(AttributeFields { + mem_attributes, + acc_perms, + execute_never, + }) + } +} + +impl PageDescriptor { + /// Create an instance. + /// + /// Descriptor is invalid by default. + pub const fn new_zeroed() -> Self { + Self { value: 0 } + } + + /// Create an instance. + pub fn from_output_page_addr( + phys_output_page_addr: PageAddress, + attribute_fields: &AttributeFields, + ) -> Self { + let val = InMemoryRegister::::new(0); + + let shifted = phys_output_page_addr.into_inner().as_usize() >> Granule64KiB::SHIFT; + val.write( + STAGE1_PAGE_DESCRIPTOR::OUTPUT_ADDR_64KiB.val(shifted as u64) + + STAGE1_PAGE_DESCRIPTOR::AF::True + + STAGE1_PAGE_DESCRIPTOR::TYPE::Page + + STAGE1_PAGE_DESCRIPTOR::VALID::True + + (*attribute_fields).into(), + ); + + Self { value: val.get() } + } + + /// Returns the valid bit. + fn is_valid(&self) -> bool { + InMemoryRegister::::new(self.value) + .is_set(STAGE1_PAGE_DESCRIPTOR::VALID) + } + + /// Returns the output page. + fn output_page_addr(&self) -> PageAddress { + let shifted = InMemoryRegister::::new(self.value) + .read(STAGE1_PAGE_DESCRIPTOR::OUTPUT_ADDR_64KiB) as usize; + + PageAddress::from(shifted << Granule64KiB::SHIFT) + } + + /// Returns the attributes. + fn try_attributes(&self) -> Result { + InMemoryRegister::::new(self.value).try_into() + } +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +impl memory::mmu::AssociatedTranslationTable + for memory::mmu::AddressSpace +where + [u8; Self::SIZE >> Granule512MiB::SHIFT]: Sized, +{ + type TableStartFromTop = + FixedSizeTranslationTable<{ Self::SIZE >> Granule512MiB::SHIFT }, true>; + + type TableStartFromBottom = + FixedSizeTranslationTable<{ Self::SIZE >> Granule512MiB::SHIFT }, false>; +} + +impl + FixedSizeTranslationTable +{ + const START_FROM_TOP_OFFSET: Address = + Address::new((usize::MAX - (Granule512MiB::SIZE * NUM_TABLES)) + 1); + + /// Create an instance. + #[allow(clippy::assertions_on_constants)] + const fn _new(for_precompute: bool) -> Self { + assert!(bsp::memory::mmu::KernelGranule::SIZE == Granule64KiB::SIZE); + + // Can't have a zero-sized address space. + assert!(NUM_TABLES > 0); + + Self { + lvl3: [[PageDescriptor::new_zeroed(); 8192]; NUM_TABLES], + lvl2: [TableDescriptor::new_zeroed(); NUM_TABLES], + initialized: for_precompute, + } + } + + pub const fn new_for_precompute() -> Self { + Self::_new(true) + } + + #[cfg(test)] + pub fn new_for_runtime() -> Self { + Self::_new(false) + } + + /// Helper to calculate the lvl2 and lvl3 indices from an address. + #[inline(always)] + fn lvl2_lvl3_index_from_page_addr( + &self, + virt_page_addr: PageAddress, + ) -> Result<(usize, usize), &'static str> { + let mut addr = virt_page_addr.into_inner(); + + if START_FROM_TOP { + addr = addr - Self::START_FROM_TOP_OFFSET; + } + + let lvl2_index = addr.as_usize() >> Granule512MiB::SHIFT; + let lvl3_index = (addr.as_usize() & Granule512MiB::MASK) >> Granule64KiB::SHIFT; + + if lvl2_index > (NUM_TABLES - 1) { + return Err("Virtual page is out of bounds of translation table"); + } + + Ok((lvl2_index, lvl3_index)) + } + + /// Returns the PageDescriptor corresponding to the supplied page address. + #[inline(always)] + fn page_descriptor_from_page_addr( + &self, + virt_page_addr: PageAddress, + ) -> Result<&PageDescriptor, &'static str> { + let (lvl2_index, lvl3_index) = self.lvl2_lvl3_index_from_page_addr(virt_page_addr)?; + let desc = &self.lvl3[lvl2_index][lvl3_index]; + + Ok(desc) + } + + /// Sets the PageDescriptor corresponding to the supplied page address. + /// + /// Doesn't allow overriding an already valid page. + #[inline(always)] + fn set_page_descriptor_from_page_addr( + &mut self, + virt_page_addr: PageAddress, + new_desc: &PageDescriptor, + ) -> Result<(), &'static str> { + let (lvl2_index, lvl3_index) = self.lvl2_lvl3_index_from_page_addr(virt_page_addr)?; + let desc = &mut self.lvl3[lvl2_index][lvl3_index]; + + if desc.is_valid() { + return Err("Virtual page is already mapped"); + } + + *desc = *new_desc; + Ok(()) + } +} + +//------------------------------------------------------------------------------ +// OS Interface Code +//------------------------------------------------------------------------------ + +impl + memory::mmu::translation_table::interface::TranslationTable + for FixedSizeTranslationTable +{ + fn init(&mut self) -> Result<(), &'static str> { + if self.initialized { + return Ok(()); + } + + // Populate the l2 entries. + for (lvl2_nr, lvl2_entry) in self.lvl2.iter_mut().enumerate() { + let virt_table_addr = self.lvl3[lvl2_nr].virt_start_addr(); + let phys_table_addr = memory::mmu::try_kernel_virt_addr_to_phys_addr(virt_table_addr)?; + + let new_desc = TableDescriptor::from_next_lvl_table_addr(phys_table_addr); + *lvl2_entry = new_desc; + } + + self.initialized = true; + + Ok(()) + } + + unsafe fn map_at( + &mut self, + virt_region: &MemoryRegion, + phys_region: &MemoryRegion, + attr: &AttributeFields, + ) -> Result<(), &'static str> { + assert!(self.initialized, "Translation tables not initialized"); + + if virt_region.size() != phys_region.size() { + return Err("Tried to map memory regions with unequal sizes"); + } + + if phys_region.end_exclusive_page_addr() > bsp::memory::phys_addr_space_end_exclusive_addr() + { + return Err("Tried to map outside of physical address space"); + } + + let iter = phys_region.into_iter().zip(virt_region.into_iter()); + for (phys_page_addr, virt_page_addr) in iter { + let new_desc = PageDescriptor::from_output_page_addr(phys_page_addr, attr); + let virt_page = virt_page_addr; + + self.set_page_descriptor_from_page_addr(virt_page, &new_desc)?; + } + + Ok(()) + } + + fn try_virt_page_addr_to_phys_page_addr( + &self, + virt_page_addr: PageAddress, + ) -> Result, &'static str> { + let page_desc = self.page_descriptor_from_page_addr(virt_page_addr)?; + + if !page_desc.is_valid() { + return Err("Page marked invalid"); + } + + Ok(page_desc.output_page_addr()) + } + + fn try_page_attributes( + &self, + virt_page_addr: PageAddress, + ) -> Result { + let page_desc = self.page_descriptor_from_page_addr(virt_page_addr)?; + + if !page_desc.is_valid() { + return Err("Page marked invalid"); + } + + page_desc.try_attributes() + } + + /// Try to translate a virtual address to a physical address. + /// + /// Will only succeed if there exists a valid mapping for the input address. + fn try_virt_addr_to_phys_addr( + &self, + virt_addr: Address, + ) -> Result, &'static str> { + let virt_page = PageAddress::from(virt_addr.align_down_page()); + let phys_page = self.try_virt_page_addr_to_phys_page_addr(virt_page)?; + + Ok(phys_page.into_inner() + virt_addr.offset_into_page()) + } +} + +//-------------------------------------------------------------------------------------------------- +// Testing +//-------------------------------------------------------------------------------------------------- + +#[cfg(test)] +pub type MinSizeTranslationTable = FixedSizeTranslationTable<1, true>; + +#[cfg(test)] +mod tests { + use super::*; + use test_macros::kernel_test; + + /// Check if the size of `struct TableDescriptor` is as expected. + #[kernel_test] + fn size_of_tabledescriptor_equals_64_bit() { + assert_eq!( + core::mem::size_of::(), + core::mem::size_of::() + ); + } + + /// Check if the size of `struct PageDescriptor` is as expected. + #[kernel_test] + fn size_of_pagedescriptor_equals_64_bit() { + assert_eq!( + core::mem::size_of::(), + core::mem::size_of::() + ); + } +} diff --git a/18_backtrace/kernel/src/_arch/aarch64/time.rs b/18_backtrace/kernel/src/_arch/aarch64/time.rs new file mode 100644 index 00000000..c814219c --- /dev/null +++ b/18_backtrace/kernel/src/_arch/aarch64/time.rs @@ -0,0 +1,121 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2018-2022 Andre Richter + +//! Architectural timer primitives. +//! +//! # Orientation +//! +//! Since arch modules are imported into generic modules using the path attribute, the path of this +//! file is: +//! +//! crate::time::arch_time + +use crate::{time, warn}; +use core::time::Duration; +use cortex_a::{asm::barrier, registers::*}; +use tock_registers::interfaces::{ReadWriteable, Readable, Writeable}; + +//-------------------------------------------------------------------------------------------------- +// Private Definitions +//-------------------------------------------------------------------------------------------------- + +const NS_PER_S: u64 = 1_000_000_000; + +/// ARMv8 Generic Timer. +struct GenericTimer; + +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +static TIME_MANAGER: GenericTimer = GenericTimer; + +//-------------------------------------------------------------------------------------------------- +// Private Code +//-------------------------------------------------------------------------------------------------- + +impl GenericTimer { + #[inline(always)] + fn read_cntpct(&self) -> u64 { + // Prevent that the counter is read ahead of time due to out-of-order execution. + unsafe { barrier::isb(barrier::SY) }; + CNTPCT_EL0.get() + } +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +/// Return a reference to the time manager. +pub fn time_manager() -> &'static impl time::interface::TimeManager { + &TIME_MANAGER +} + +//------------------------------------------------------------------------------ +// OS Interface Code +//------------------------------------------------------------------------------ + +impl time::interface::TimeManager for GenericTimer { + fn resolution(&self) -> Duration { + Duration::from_nanos(NS_PER_S / (CNTFRQ_EL0.get() as u64)) + } + + fn uptime(&self) -> Duration { + let current_count: u64 = self.read_cntpct() * NS_PER_S; + let frq: u64 = CNTFRQ_EL0.get() as u64; + + Duration::from_nanos(current_count / frq) + } + + fn spin_for(&self, duration: Duration) { + // Instantly return on zero. + if duration.as_nanos() == 0 { + return; + } + + // Calculate the register compare value. + let frq = CNTFRQ_EL0.get(); + let x = match frq.checked_mul(duration.as_nanos() as u64) { + #[allow(unused_imports)] + None => { + warn!("Spin duration too long, skipping"); + return; + } + Some(val) => val, + }; + let tval = x / NS_PER_S; + + // Check if it is within supported bounds. + let warn: Option<&str> = if tval == 0 { + Some("smaller") + // The upper 32 bits of CNTP_TVAL_EL0 are reserved. + } else if tval > u32::max_value().into() { + Some("bigger") + } else { + None + }; + + #[allow(unused_imports)] + if let Some(w) = warn { + warn!( + "Spin duration {} than architecturally supported, skipping", + w + ); + return; + } + + // Set the compare value register. + CNTP_TVAL_EL0.set(tval); + + // Kick off the counting. // Disable timer interrupt. + CNTP_CTL_EL0.modify(CNTP_CTL_EL0::ENABLE::SET + CNTP_CTL_EL0::IMASK::SET); + + // ISTATUS will be '1' when cval ticks have passed. Busy-check it. + while !CNTP_CTL_EL0.matches_all(CNTP_CTL_EL0::ISTATUS::SET) {} + + // Disable counting again. + CNTP_CTL_EL0.modify(CNTP_CTL_EL0::ENABLE::CLEAR); + } +} diff --git a/18_backtrace/kernel/src/backtrace.rs b/18_backtrace/kernel/src/backtrace.rs new file mode 100644 index 00000000..7dba2e4a --- /dev/null +++ b/18_backtrace/kernel/src/backtrace.rs @@ -0,0 +1,112 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2022 Andre Richter + +//! Backtracing support. + +#[cfg(target_arch = "aarch64")] +#[path = "_arch/aarch64/backtrace.rs"] +mod arch_backtrace; + +use crate::{ + memory::{Address, Virtual}, + symbols, +}; +use core::fmt; + +//-------------------------------------------------------------------------------------------------- +// Architectural Public Reexports +//-------------------------------------------------------------------------------------------------- +#[cfg(feature = "test_build")] +pub use arch_backtrace::{corrupt_link, corrupt_previous_frame_addr}; + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +/// A backtrace item. +#[allow(missing_docs)] +pub enum BacktraceItem { + InvalidFramePointer(Address), + InvalidLink(Address), + Link(Address), +} + +/// Pseudo-struct for printing a backtrace using its fmt::Display implementation. +pub struct Backtrace; + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +impl fmt::Display for Backtrace { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + writeln!(f, "Backtrace:")?; + writeln!( + f, + " ----------------------------------------------------------------------------------------------" + )?; + writeln!( + f, + " Address Function containing address" + )?; + writeln!( + f, + " ----------------------------------------------------------------------------------------------" + )?; + + let mut fmt_res: fmt::Result = Ok(()); + let trace_formatter = + |maybe_iter: Option<&mut dyn Iterator>| match maybe_iter { + None => fmt_res = writeln!(f, "ERROR! No valid stack frame found"), + Some(iter) => { + for (i, backtrace_res) in iter.enumerate() { + match backtrace_res { + BacktraceItem::InvalidFramePointer(addr) => { + fmt_res = writeln!( + f, + " {:>2}. ERROR! \ + Encountered invalid frame pointer ({}) during backtrace", + i + 1, + addr + ); + } + BacktraceItem::InvalidLink(addr) => { + fmt_res = writeln!( + f, + " {:>2}. ERROR! \ + Link address ({}) is not contained in kernel .text section", + i + 1, + addr + ); + } + BacktraceItem::Link(addr) => { + fmt_res = writeln!( + f, + " {:>2}. {:016x} | {:<50}", + i + 1, + addr.as_usize(), + match symbols::lookup_symbol(addr) { + Some(sym) => sym.name(), + _ => "Symbol not found", + } + ) + } + }; + + if fmt_res.is_err() { + break; + } + } + } + }; + + arch_backtrace::backtrace(trace_formatter); + fmt_res?; + + writeln!( + f, + " ----------------------------------------------------------------------------------------------" + ) + } +} diff --git a/18_backtrace/kernel/src/bsp.rs b/18_backtrace/kernel/src/bsp.rs new file mode 100644 index 00000000..824787f6 --- /dev/null +++ b/18_backtrace/kernel/src/bsp.rs @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2018-2022 Andre Richter + +//! Conditional reexporting of Board Support Packages. + +mod device_driver; + +#[cfg(any(feature = "bsp_rpi3", feature = "bsp_rpi4"))] +mod raspberrypi; + +#[cfg(any(feature = "bsp_rpi3", feature = "bsp_rpi4"))] +pub use raspberrypi::*; diff --git a/18_backtrace/kernel/src/bsp/device_driver.rs b/18_backtrace/kernel/src/bsp/device_driver.rs new file mode 100644 index 00000000..eafaf775 --- /dev/null +++ b/18_backtrace/kernel/src/bsp/device_driver.rs @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2018-2022 Andre Richter + +//! Device driver. + +#[cfg(feature = "bsp_rpi4")] +mod arm; +#[cfg(any(feature = "bsp_rpi3", feature = "bsp_rpi4"))] +mod bcm; +mod common; + +#[cfg(feature = "bsp_rpi4")] +pub use arm::*; +#[cfg(any(feature = "bsp_rpi3", feature = "bsp_rpi4"))] +pub use bcm::*; diff --git a/18_backtrace/kernel/src/bsp/device_driver/arm.rs b/18_backtrace/kernel/src/bsp/device_driver/arm.rs new file mode 100644 index 00000000..e83e24c9 --- /dev/null +++ b/18_backtrace/kernel/src/bsp/device_driver/arm.rs @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2020-2022 Andre Richter + +//! ARM driver top level. + +pub mod gicv2; + +pub use gicv2::*; diff --git a/18_backtrace/kernel/src/bsp/device_driver/arm/gicv2.rs b/18_backtrace/kernel/src/bsp/device_driver/arm/gicv2.rs new file mode 100644 index 00000000..4c68a692 --- /dev/null +++ b/18_backtrace/kernel/src/bsp/device_driver/arm/gicv2.rs @@ -0,0 +1,246 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2020-2022 Andre Richter + +//! GICv2 Driver - ARM Generic Interrupt Controller v2. +//! +//! The following is a collection of excerpts with useful information from +//! - `Programmer's Guide for ARMv8-A` +//! - `ARM Generic Interrupt Controller Architecture Specification` +//! +//! # Programmer's Guide - 10.6.1 Configuration +//! +//! The GIC is accessed as a memory-mapped peripheral. +//! +//! All cores can access the common Distributor, but the CPU interface is banked, that is, each core +//! uses the same address to access its own private CPU interface. +//! +//! It is not possible for a core to access the CPU interface of another core. +//! +//! # Architecture Specification - 10.6.2 Initialization +//! +//! Both the Distributor and the CPU interfaces are disabled at reset. The GIC must be initialized +//! after reset before it can deliver interrupts to the core. +//! +//! In the Distributor, software must configure the priority, target, security and enable individual +//! interrupts. The Distributor must subsequently be enabled through its control register +//! (GICD_CTLR). For each CPU interface, software must program the priority mask and preemption +//! settings. +//! +//! Each CPU interface block itself must be enabled through its control register (GICD_CTLR). This +//! prepares the GIC to deliver interrupts to the core. +//! +//! Before interrupts are expected in the core, software prepares the core to take interrupts by +//! setting a valid interrupt vector in the vector table, and clearing interrupt mask bits in +//! PSTATE, and setting the routing controls. +//! +//! The entire interrupt mechanism in the system can be disabled by disabling the Distributor. +//! Interrupt delivery to an individual core can be disabled by disabling its CPU interface. +//! Individual interrupts can also be disabled (or enabled) in the distributor. +//! +//! For an interrupt to reach the core, the individual interrupt, Distributor and CPU interface must +//! all be enabled. The interrupt also needs to be of sufficient priority, that is, higher than the +//! core's priority mask. +//! +//! # Architecture Specification - 1.4.2 Interrupt types +//! +//! - Peripheral interrupt +//! - Private Peripheral Interrupt (PPI) +//! - This is a peripheral interrupt that is specific to a single processor. +//! - Shared Peripheral Interrupt (SPI) +//! - This is a peripheral interrupt that the Distributor can route to any of a specified +//! combination of processors. +//! +//! - Software-generated interrupt (SGI) +//! - This is an interrupt generated by software writing to a GICD_SGIR register in the GIC. The +//! system uses SGIs for interprocessor communication. +//! - An SGI has edge-triggered properties. The software triggering of the interrupt is +//! equivalent to the edge transition of the interrupt request signal. +//! - When an SGI occurs in a multiprocessor implementation, the CPUID field in the Interrupt +//! Acknowledge Register, GICC_IAR, or the Aliased Interrupt Acknowledge Register, GICC_AIAR, +//! identifies the processor that requested the interrupt. +//! +//! # Architecture Specification - 2.2.1 Interrupt IDs +//! +//! Interrupts from sources are identified using ID numbers. Each CPU interface can see up to 1020 +//! interrupts. The banking of SPIs and PPIs increases the total number of interrupts supported by +//! the Distributor. +//! +//! The GIC assigns interrupt ID numbers ID0-ID1019 as follows: +//! - Interrupt numbers 32..1019 are used for SPIs. +//! - Interrupt numbers 0..31 are used for interrupts that are private to a CPU interface. These +//! interrupts are banked in the Distributor. +//! - A banked interrupt is one where the Distributor can have multiple interrupts with the +//! same ID. A banked interrupt is identified uniquely by its ID number and its associated +//! CPU interface number. Of the banked interrupt IDs: +//! - 00..15 SGIs +//! - 16..31 PPIs + +mod gicc; +mod gicd; + +use crate::{bsp, cpu, driver, exception, memory, synchronization, synchronization::InitStateLock}; +use core::sync::atomic::{AtomicBool, Ordering}; + +//-------------------------------------------------------------------------------------------------- +// Private Definitions +//-------------------------------------------------------------------------------------------------- + +type HandlerTable = [Option; GICv2::NUM_IRQS]; + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +/// Used for the associated type of trait [`exception::asynchronous::interface::IRQManager`]. +pub type IRQNumber = exception::asynchronous::IRQNumber<{ GICv2::MAX_IRQ_NUMBER }>; + +/// Representation of the GIC. +pub struct GICv2 { + gicd_mmio_descriptor: memory::mmu::MMIODescriptor, + gicc_mmio_descriptor: memory::mmu::MMIODescriptor, + + /// The Distributor. + gicd: gicd::GICD, + + /// The CPU Interface. + gicc: gicc::GICC, + + /// Have the MMIO regions been remapped yet? + is_mmio_remapped: AtomicBool, + + /// Stores registered IRQ handlers. Writable only during kernel init. RO afterwards. + handler_table: InitStateLock, +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +impl GICv2 { + const MAX_IRQ_NUMBER: usize = 300; // Normally 1019, but keep it lower to save some space. + const NUM_IRQS: usize = Self::MAX_IRQ_NUMBER + 1; + + /// Create an instance. + /// + /// # Safety + /// + /// - The user must ensure to provide correct MMIO descriptors. + pub const unsafe fn new( + gicd_mmio_descriptor: memory::mmu::MMIODescriptor, + gicc_mmio_descriptor: memory::mmu::MMIODescriptor, + ) -> Self { + Self { + gicd_mmio_descriptor, + gicc_mmio_descriptor, + gicd: gicd::GICD::new(gicd_mmio_descriptor.start_addr().as_usize()), + gicc: gicc::GICC::new(gicc_mmio_descriptor.start_addr().as_usize()), + is_mmio_remapped: AtomicBool::new(false), + handler_table: InitStateLock::new([None; Self::NUM_IRQS]), + } + } +} + +//------------------------------------------------------------------------------ +// OS Interface Code +//------------------------------------------------------------------------------ +use synchronization::interface::ReadWriteEx; + +impl driver::interface::DeviceDriver for GICv2 { + fn compatible(&self) -> &'static str { + "GICv2 (ARM Generic Interrupt Controller v2)" + } + + unsafe fn init(&self) -> Result<(), &'static str> { + let remapped = self.is_mmio_remapped.load(Ordering::Relaxed); + if !remapped { + // GICD + let mut virt_addr = memory::mmu::kernel_map_mmio("GICD", &self.gicd_mmio_descriptor)?; + self.gicd.set_mmio(virt_addr.as_usize()); + + // GICC + virt_addr = memory::mmu::kernel_map_mmio("GICC", &self.gicc_mmio_descriptor)?; + self.gicc.set_mmio(virt_addr.as_usize()); + + // Conclude remapping. + self.is_mmio_remapped.store(true, Ordering::Relaxed); + } + + if bsp::cpu::BOOT_CORE_ID == cpu::smp::core_id() { + self.gicd.boot_core_init(); + } + + self.gicc.priority_accept_all(); + self.gicc.enable(); + + Ok(()) + } +} + +impl exception::asynchronous::interface::IRQManager for GICv2 { + type IRQNumberType = IRQNumber; + + fn register_handler( + &self, + irq_number: Self::IRQNumberType, + descriptor: exception::asynchronous::IRQDescriptor, + ) -> Result<(), &'static str> { + self.handler_table.write(|table| { + let irq_number = irq_number.get(); + + if table[irq_number].is_some() { + return Err("IRQ handler already registered"); + } + + table[irq_number] = Some(descriptor); + + Ok(()) + }) + } + + fn enable(&self, irq_number: Self::IRQNumberType) { + self.gicd.enable(irq_number); + } + + fn handle_pending_irqs<'irq_context>( + &'irq_context self, + ic: &exception::asynchronous::IRQContext<'irq_context>, + ) { + // Extract the highest priority pending IRQ number from the Interrupt Acknowledge Register + // (IAR). + let irq_number = self.gicc.pending_irq_number(ic); + + // Guard against spurious interrupts. + if irq_number > GICv2::MAX_IRQ_NUMBER { + return; + } + + // Call the IRQ handler. Panic if there is none. + self.handler_table.read(|table| { + match table[irq_number] { + None => panic!("No handler registered for IRQ {}", irq_number), + Some(descriptor) => { + // Call the IRQ handler. Panics on failure. + descriptor.handler.handle().expect("Error handling IRQ"); + } + } + }); + + // Signal completion of handling. + self.gicc.mark_comleted(irq_number as u32, ic); + } + + fn print_handler(&self) { + use crate::info; + + info!(" Peripheral handler:"); + + self.handler_table.read(|table| { + for (i, opt) in table.iter().skip(32).enumerate() { + if let Some(handler) = opt { + info!(" {: >3}. {}", i + 32, handler.name); + } + } + }); + } +} diff --git a/18_backtrace/kernel/src/bsp/device_driver/arm/gicv2/gicc.rs b/18_backtrace/kernel/src/bsp/device_driver/arm/gicv2/gicc.rs new file mode 100644 index 00000000..1a151d24 --- /dev/null +++ b/18_backtrace/kernel/src/bsp/device_driver/arm/gicv2/gicc.rs @@ -0,0 +1,156 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2020-2022 Andre Richter + +//! GICC Driver - GIC CPU interface. + +use crate::{ + bsp::device_driver::common::MMIODerefWrapper, exception, synchronization::InitStateLock, +}; +use tock_registers::{ + interfaces::{Readable, Writeable}, + register_bitfields, register_structs, + registers::ReadWrite, +}; + +//-------------------------------------------------------------------------------------------------- +// Private Definitions +//-------------------------------------------------------------------------------------------------- + +register_bitfields! { + u32, + + /// CPU Interface Control Register + CTLR [ + Enable OFFSET(0) NUMBITS(1) [] + ], + + /// Interrupt Priority Mask Register + PMR [ + Priority OFFSET(0) NUMBITS(8) [] + ], + + /// Interrupt Acknowledge Register + IAR [ + InterruptID OFFSET(0) NUMBITS(10) [] + ], + + /// End of Interrupt Register + EOIR [ + EOIINTID OFFSET(0) NUMBITS(10) [] + ] +} + +register_structs! { + #[allow(non_snake_case)] + pub RegisterBlock { + (0x000 => CTLR: ReadWrite), + (0x004 => PMR: ReadWrite), + (0x008 => _reserved1), + (0x00C => IAR: ReadWrite), + (0x010 => EOIR: ReadWrite), + (0x014 => @END), + } +} + +/// Abstraction for the associated MMIO registers. +type Registers = MMIODerefWrapper; + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +/// Representation of the GIC CPU interface. +pub struct GICC { + registers: InitStateLock, +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- +use crate::synchronization::interface::ReadWriteEx; + +impl GICC { + /// Create an instance. + /// + /// # Safety + /// + /// - The user must ensure to provide a correct MMIO start address. + pub const unsafe fn new(mmio_start_addr: usize) -> Self { + Self { + registers: InitStateLock::new(Registers::new(mmio_start_addr)), + } + } + + pub unsafe fn set_mmio(&self, new_mmio_start_addr: usize) { + self.registers + .write(|regs| *regs = Registers::new(new_mmio_start_addr)); + } + + /// Accept interrupts of any priority. + /// + /// Quoting the GICv2 Architecture Specification: + /// + /// "Writing 255 to the GICC_PMR always sets it to the largest supported priority field + /// value." + /// + /// # Safety + /// + /// - GICC MMIO registers are banked per CPU core. It is therefore safe to have `&self` instead + /// of `&mut self`. + pub fn priority_accept_all(&self) { + self.registers.read(|regs| { + regs.PMR.write(PMR::Priority.val(255)); // Comment in arch spec. + }); + } + + /// Enable the interface - start accepting IRQs. + /// + /// # Safety + /// + /// - GICC MMIO registers are banked per CPU core. It is therefore safe to have `&self` instead + /// of `&mut self`. + pub fn enable(&self) { + self.registers.read(|regs| { + regs.CTLR.write(CTLR::Enable::SET); + }); + } + + /// Extract the number of the highest-priority pending IRQ. + /// + /// Can only be called from IRQ context, which is ensured by taking an `IRQContext` token. + /// + /// # Safety + /// + /// - GICC MMIO registers are banked per CPU core. It is therefore safe to have `&self` instead + /// of `&mut self`. + #[allow(clippy::trivially_copy_pass_by_ref)] + pub fn pending_irq_number<'irq_context>( + &self, + _ic: &exception::asynchronous::IRQContext<'irq_context>, + ) -> usize { + self.registers + .read(|regs| regs.IAR.read(IAR::InterruptID) as usize) + } + + /// Complete handling of the currently active IRQ. + /// + /// Can only be called from IRQ context, which is ensured by taking an `IRQContext` token. + /// + /// To be called after `pending_irq_number()`. + /// + /// # Safety + /// + /// - GICC MMIO registers are banked per CPU core. It is therefore safe to have `&self` instead + /// of `&mut self`. + #[allow(clippy::trivially_copy_pass_by_ref)] + pub fn mark_comleted<'irq_context>( + &self, + irq_number: u32, + _ic: &exception::asynchronous::IRQContext<'irq_context>, + ) { + self.registers.read(|regs| { + regs.EOIR.write(EOIR::EOIINTID.val(irq_number)); + }); + } +} diff --git a/18_backtrace/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs b/18_backtrace/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs new file mode 100644 index 00000000..60bbc468 --- /dev/null +++ b/18_backtrace/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs @@ -0,0 +1,209 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2020-2022 Andre Richter + +//! GICD Driver - GIC Distributor. +//! +//! # Glossary +//! - SPI - Shared Peripheral Interrupt. + +use crate::{ + bsp::device_driver::common::MMIODerefWrapper, + state, synchronization, + synchronization::{IRQSafeNullLock, InitStateLock}, +}; +use tock_registers::{ + interfaces::{Readable, Writeable}, + register_bitfields, register_structs, + registers::{ReadOnly, ReadWrite}, +}; + +//-------------------------------------------------------------------------------------------------- +// Private Definitions +//-------------------------------------------------------------------------------------------------- + +register_bitfields! { + u32, + + /// Distributor Control Register + CTLR [ + Enable OFFSET(0) NUMBITS(1) [] + ], + + /// Interrupt Controller Type Register + TYPER [ + ITLinesNumber OFFSET(0) NUMBITS(5) [] + ], + + /// Interrupt Processor Targets Registers + ITARGETSR [ + Offset3 OFFSET(24) NUMBITS(8) [], + Offset2 OFFSET(16) NUMBITS(8) [], + Offset1 OFFSET(8) NUMBITS(8) [], + Offset0 OFFSET(0) NUMBITS(8) [] + ] +} + +register_structs! { + #[allow(non_snake_case)] + SharedRegisterBlock { + (0x000 => CTLR: ReadWrite), + (0x004 => TYPER: ReadOnly), + (0x008 => _reserved1), + (0x104 => ISENABLER: [ReadWrite; 31]), + (0x108 => _reserved2), + (0x820 => ITARGETSR: [ReadWrite; 248]), + (0x824 => @END), + } +} + +register_structs! { + #[allow(non_snake_case)] + BankedRegisterBlock { + (0x000 => _reserved1), + (0x100 => ISENABLER: ReadWrite), + (0x104 => _reserved2), + (0x800 => ITARGETSR: [ReadOnly; 8]), + (0x804 => @END), + } +} + +/// Abstraction for the non-banked parts of the associated MMIO registers. +type SharedRegisters = MMIODerefWrapper; + +/// Abstraction for the banked parts of the associated MMIO registers. +type BankedRegisters = MMIODerefWrapper; + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +/// Representation of the GIC Distributor. +pub struct GICD { + /// Access to shared registers is guarded with a lock. + shared_registers: IRQSafeNullLock, + + /// Access to banked registers is unguarded. + banked_registers: InitStateLock, +} + +//-------------------------------------------------------------------------------------------------- +// Private Code +//-------------------------------------------------------------------------------------------------- + +impl SharedRegisters { + /// Return the number of IRQs that this HW implements. + #[inline(always)] + fn num_irqs(&mut self) -> usize { + // Query number of implemented IRQs. + // + // Refer to GICv2 Architecture Specification, Section 4.3.2. + ((self.TYPER.read(TYPER::ITLinesNumber) as usize) + 1) * 32 + } + + /// Return a slice of the implemented ITARGETSR. + #[inline(always)] + fn implemented_itargets_slice(&mut self) -> &[ReadWrite] { + assert!(self.num_irqs() >= 36); + + // Calculate the max index of the shared ITARGETSR array. + // + // The first 32 IRQs are private, so not included in `shared_registers`. Each ITARGETS + // register has four entries, so shift right by two. Subtract one because we start + // counting at zero. + let spi_itargetsr_max_index = ((self.num_irqs() - 32) >> 2) - 1; + + // Rust automatically inserts slice range sanity check, i.e. max >= min. + &self.ITARGETSR[0..spi_itargetsr_max_index] + } +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- +use crate::synchronization::interface::ReadWriteEx; +use synchronization::interface::Mutex; + +impl GICD { + /// Create an instance. + /// + /// # Safety + /// + /// - The user must ensure to provide a correct MMIO start address. + pub const unsafe fn new(mmio_start_addr: usize) -> Self { + Self { + shared_registers: IRQSafeNullLock::new(SharedRegisters::new(mmio_start_addr)), + banked_registers: InitStateLock::new(BankedRegisters::new(mmio_start_addr)), + } + } + + pub unsafe fn set_mmio(&self, new_mmio_start_addr: usize) { + self.shared_registers + .lock(|regs| *regs = SharedRegisters::new(new_mmio_start_addr)); + self.banked_registers + .write(|regs| *regs = BankedRegisters::new(new_mmio_start_addr)); + } + + /// Use a banked ITARGETSR to retrieve the executing core's GIC target mask. + /// + /// Quoting the GICv2 Architecture Specification: + /// + /// "GICD_ITARGETSR0 to GICD_ITARGETSR7 are read-only, and each field returns a value that + /// corresponds only to the processor reading the register." + fn local_gic_target_mask(&self) -> u32 { + self.banked_registers + .read(|regs| regs.ITARGETSR[0].read(ITARGETSR::Offset0)) + } + + /// Route all SPIs to the boot core and enable the distributor. + pub fn boot_core_init(&self) { + assert!( + state::state_manager().is_init(), + "Only allowed during kernel init phase" + ); + + // Target all SPIs to the boot core only. + let mask = self.local_gic_target_mask(); + + self.shared_registers.lock(|regs| { + for i in regs.implemented_itargets_slice().iter() { + i.write( + ITARGETSR::Offset3.val(mask) + + ITARGETSR::Offset2.val(mask) + + ITARGETSR::Offset1.val(mask) + + ITARGETSR::Offset0.val(mask), + ); + } + + regs.CTLR.write(CTLR::Enable::SET); + }); + } + + /// Enable an interrupt. + pub fn enable(&self, irq_num: super::IRQNumber) { + let irq_num = irq_num.get(); + + // Each bit in the u32 enable register corresponds to one IRQ number. Shift right by 5 + // (division by 32) and arrive at the index for the respective ISENABLER[i]. + let enable_reg_index = irq_num >> 5; + let enable_bit: u32 = 1u32 << (irq_num % 32); + + // Check if we are handling a private or shared IRQ. + match irq_num { + // Private. + 0..=31 => self.banked_registers.read(|regs| { + let enable_reg = ®s.ISENABLER; + enable_reg.set(enable_reg.get() | enable_bit); + }), + // Shared. + _ => { + let enable_reg_index_shared = enable_reg_index - 1; + + self.shared_registers.lock(|regs| { + let enable_reg = ®s.ISENABLER[enable_reg_index_shared]; + enable_reg.set(enable_reg.get() | enable_bit); + }); + } + } + } +} diff --git a/18_backtrace/kernel/src/bsp/device_driver/bcm.rs b/18_backtrace/kernel/src/bsp/device_driver/bcm.rs new file mode 100644 index 00000000..5a7cc23b --- /dev/null +++ b/18_backtrace/kernel/src/bsp/device_driver/bcm.rs @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2018-2022 Andre Richter + +//! BCM driver top level. + +mod bcm2xxx_gpio; +#[cfg(feature = "bsp_rpi3")] +mod bcm2xxx_interrupt_controller; +mod bcm2xxx_pl011_uart; + +pub use bcm2xxx_gpio::*; +#[cfg(feature = "bsp_rpi3")] +pub use bcm2xxx_interrupt_controller::*; +pub use bcm2xxx_pl011_uart::*; diff --git a/18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs b/18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs new file mode 100644 index 00000000..eea07b75 --- /dev/null +++ b/18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs @@ -0,0 +1,259 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2018-2022 Andre Richter + +//! GPIO Driver. + +use crate::{ + bsp::device_driver::common::MMIODerefWrapper, driver, memory, synchronization, + synchronization::IRQSafeNullLock, +}; +use core::sync::atomic::{AtomicUsize, Ordering}; +use tock_registers::{ + interfaces::{ReadWriteable, Writeable}, + register_bitfields, register_structs, + registers::ReadWrite, +}; + +//-------------------------------------------------------------------------------------------------- +// Private Definitions +//-------------------------------------------------------------------------------------------------- + +// GPIO registers. +// +// Descriptions taken from +// - https://github.com/raspberrypi/documentation/files/1888662/BCM2837-ARM-Peripherals.-.Revised.-.V2-1.pdf +// - https://datasheets.raspberrypi.org/bcm2711/bcm2711-peripherals.pdf +register_bitfields! { + u32, + + /// GPIO Function Select 1 + GPFSEL1 [ + /// Pin 15 + FSEL15 OFFSET(15) NUMBITS(3) [ + Input = 0b000, + Output = 0b001, + AltFunc0 = 0b100 // PL011 UART RX + + ], + + /// Pin 14 + FSEL14 OFFSET(12) NUMBITS(3) [ + Input = 0b000, + Output = 0b001, + AltFunc0 = 0b100 // PL011 UART TX + ] + ], + + /// GPIO Pull-up/down Register + /// + /// BCM2837 only. + GPPUD [ + /// Controls the actuation of the internal pull-up/down control line to ALL the GPIO pins. + PUD OFFSET(0) NUMBITS(2) [ + Off = 0b00, + PullDown = 0b01, + PullUp = 0b10 + ] + ], + + /// GPIO Pull-up/down Clock Register 0 + /// + /// BCM2837 only. + GPPUDCLK0 [ + /// Pin 15 + PUDCLK15 OFFSET(15) NUMBITS(1) [ + NoEffect = 0, + AssertClock = 1 + ], + + /// Pin 14 + PUDCLK14 OFFSET(14) NUMBITS(1) [ + NoEffect = 0, + AssertClock = 1 + ] + ], + + /// GPIO Pull-up / Pull-down Register 0 + /// + /// BCM2711 only. + GPIO_PUP_PDN_CNTRL_REG0 [ + /// Pin 15 + GPIO_PUP_PDN_CNTRL15 OFFSET(30) NUMBITS(2) [ + NoResistor = 0b00, + PullUp = 0b01 + ], + + /// Pin 14 + GPIO_PUP_PDN_CNTRL14 OFFSET(28) NUMBITS(2) [ + NoResistor = 0b00, + PullUp = 0b01 + ] + ] +} + +register_structs! { + #[allow(non_snake_case)] + RegisterBlock { + (0x00 => _reserved1), + (0x04 => GPFSEL1: ReadWrite), + (0x08 => _reserved2), + (0x94 => GPPUD: ReadWrite), + (0x98 => GPPUDCLK0: ReadWrite), + (0x9C => _reserved3), + (0xE4 => GPIO_PUP_PDN_CNTRL_REG0: ReadWrite), + (0xE8 => @END), + } +} + +/// Abstraction for the associated MMIO registers. +type Registers = MMIODerefWrapper; + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +pub struct GPIOInner { + registers: Registers, +} + +// Export the inner struct so that BSPs can use it for the panic handler. +pub use GPIOInner as PanicGPIO; + +/// Representation of the GPIO HW. +pub struct GPIO { + mmio_descriptor: memory::mmu::MMIODescriptor, + virt_mmio_start_addr: AtomicUsize, + inner: IRQSafeNullLock, +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +impl GPIOInner { + /// Create an instance. + /// + /// # Safety + /// + /// - The user must ensure to provide a correct MMIO start address. + pub const unsafe fn new(mmio_start_addr: usize) -> Self { + Self { + registers: Registers::new(mmio_start_addr), + } + } + + /// Init code. + /// + /// # Safety + /// + /// - The user must ensure to provide a correct MMIO start address. + pub unsafe fn init(&mut self, new_mmio_start_addr: Option) -> Result<(), &'static str> { + if let Some(addr) = new_mmio_start_addr { + self.registers = Registers::new(addr); + } + + Ok(()) + } + + /// Disable pull-up/down on pins 14 and 15. + #[cfg(feature = "bsp_rpi3")] + fn disable_pud_14_15_bcm2837(&mut self) { + use crate::{time, time::interface::TimeManager}; + use core::time::Duration; + + // The Linux 2837 GPIO driver waits 1 µs between the steps. + const DELAY: Duration = Duration::from_micros(1); + + self.registers.GPPUD.write(GPPUD::PUD::Off); + time::time_manager().spin_for(DELAY); + + self.registers + .GPPUDCLK0 + .write(GPPUDCLK0::PUDCLK15::AssertClock + GPPUDCLK0::PUDCLK14::AssertClock); + time::time_manager().spin_for(DELAY); + + self.registers.GPPUD.write(GPPUD::PUD::Off); + self.registers.GPPUDCLK0.set(0); + } + + /// Disable pull-up/down on pins 14 and 15. + #[cfg(feature = "bsp_rpi4")] + fn disable_pud_14_15_bcm2711(&mut self) { + self.registers.GPIO_PUP_PDN_CNTRL_REG0.write( + GPIO_PUP_PDN_CNTRL_REG0::GPIO_PUP_PDN_CNTRL15::PullUp + + GPIO_PUP_PDN_CNTRL_REG0::GPIO_PUP_PDN_CNTRL14::PullUp, + ); + } + + /// Map PL011 UART as standard output. + /// + /// TX to pin 14 + /// RX to pin 15 + pub fn map_pl011_uart(&mut self) { + // Select the UART on pins 14 and 15. + self.registers + .GPFSEL1 + .modify(GPFSEL1::FSEL15::AltFunc0 + GPFSEL1::FSEL14::AltFunc0); + + // Disable pull-up/down on pins 14 and 15. + #[cfg(feature = "bsp_rpi3")] + self.disable_pud_14_15_bcm2837(); + + #[cfg(feature = "bsp_rpi4")] + self.disable_pud_14_15_bcm2711(); + } +} + +impl GPIO { + /// Create an instance. + /// + /// # Safety + /// + /// - The user must ensure to provide correct MMIO descriptors. + pub const unsafe fn new(mmio_descriptor: memory::mmu::MMIODescriptor) -> Self { + Self { + mmio_descriptor, + virt_mmio_start_addr: AtomicUsize::new(0), + inner: IRQSafeNullLock::new(GPIOInner::new(mmio_descriptor.start_addr().as_usize())), + } + } + + /// Concurrency safe version of `GPIOInner.map_pl011_uart()` + pub fn map_pl011_uart(&self) { + self.inner.lock(|inner| inner.map_pl011_uart()) + } +} + +//------------------------------------------------------------------------------ +// OS Interface Code +//------------------------------------------------------------------------------ +use synchronization::interface::Mutex; + +impl driver::interface::DeviceDriver for GPIO { + fn compatible(&self) -> &'static str { + "BCM GPIO" + } + + unsafe fn init(&self) -> Result<(), &'static str> { + let virt_addr = memory::mmu::kernel_map_mmio(self.compatible(), &self.mmio_descriptor)?; + + self.inner + .lock(|inner| inner.init(Some(virt_addr.as_usize())))?; + + self.virt_mmio_start_addr + .store(virt_addr.as_usize(), Ordering::Relaxed); + + Ok(()) + } + + fn virt_mmio_start_addr(&self) -> Option { + let addr = self.virt_mmio_start_addr.load(Ordering::Relaxed); + + if addr == 0 { + return None; + } + + Some(addr) + } +} diff --git a/18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs b/18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs new file mode 100644 index 00000000..99961fac --- /dev/null +++ b/18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs @@ -0,0 +1,138 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2020-2022 Andre Richter + +//! Interrupt Controller Driver. + +mod peripheral_ic; + +use crate::{driver, exception, memory}; + +//-------------------------------------------------------------------------------------------------- +// Private Definitions +//-------------------------------------------------------------------------------------------------- + +/// Wrapper struct for a bitmask indicating pending IRQ numbers. +struct PendingIRQs { + bitmask: u64, +} + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +pub type LocalIRQ = + exception::asynchronous::IRQNumber<{ InterruptController::MAX_LOCAL_IRQ_NUMBER }>; +pub type PeripheralIRQ = + exception::asynchronous::IRQNumber<{ InterruptController::MAX_PERIPHERAL_IRQ_NUMBER }>; + +/// Used for the associated type of trait [`exception::asynchronous::interface::IRQManager`]. +#[derive(Copy, Clone)] +pub enum IRQNumber { + Local(LocalIRQ), + Peripheral(PeripheralIRQ), +} + +/// Representation of the Interrupt Controller. +pub struct InterruptController { + periph: peripheral_ic::PeripheralIC, +} + +//-------------------------------------------------------------------------------------------------- +// Private Code +//-------------------------------------------------------------------------------------------------- + +impl PendingIRQs { + pub fn new(bitmask: u64) -> Self { + Self { bitmask } + } +} + +impl Iterator for PendingIRQs { + type Item = usize; + + fn next(&mut self) -> Option { + use core::intrinsics::cttz; + + let next = cttz(self.bitmask); + if next == 64 { + return None; + } + + self.bitmask &= !(1 << next); + + Some(next as usize) + } +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +impl InterruptController { + const MAX_LOCAL_IRQ_NUMBER: usize = 11; + const MAX_PERIPHERAL_IRQ_NUMBER: usize = 63; + const NUM_PERIPHERAL_IRQS: usize = Self::MAX_PERIPHERAL_IRQ_NUMBER + 1; + + /// Create an instance. + /// + /// # Safety + /// + /// - The user must ensure to provide correct MMIO descriptors. + pub const unsafe fn new( + _local_mmio_descriptor: memory::mmu::MMIODescriptor, + periph_mmio_descriptor: memory::mmu::MMIODescriptor, + ) -> Self { + Self { + periph: peripheral_ic::PeripheralIC::new(periph_mmio_descriptor), + } + } +} + +//------------------------------------------------------------------------------ +// OS Interface Code +//------------------------------------------------------------------------------ + +impl driver::interface::DeviceDriver for InterruptController { + fn compatible(&self) -> &'static str { + "BCM Interrupt Controller" + } + + unsafe fn init(&self) -> Result<(), &'static str> { + self.periph.init() + } +} + +impl exception::asynchronous::interface::IRQManager for InterruptController { + type IRQNumberType = IRQNumber; + + fn register_handler( + &self, + irq: Self::IRQNumberType, + descriptor: exception::asynchronous::IRQDescriptor, + ) -> Result<(), &'static str> { + match irq { + IRQNumber::Local(_) => unimplemented!("Local IRQ controller not implemented."), + IRQNumber::Peripheral(pirq) => self.periph.register_handler(pirq, descriptor), + } + } + + fn enable(&self, irq: Self::IRQNumberType) { + match irq { + IRQNumber::Local(_) => unimplemented!("Local IRQ controller not implemented."), + IRQNumber::Peripheral(pirq) => self.periph.enable(pirq), + } + } + + fn handle_pending_irqs<'irq_context>( + &'irq_context self, + ic: &exception::asynchronous::IRQContext<'irq_context>, + ) { + // It can only be a peripheral IRQ pending because enable() does not support local IRQs yet. + self.periph.handle_pending_irqs(ic) + } + + fn print_handler(&self) { + self.periph.print_handler(); + } +} diff --git a/18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs b/18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs new file mode 100644 index 00000000..f09da862 --- /dev/null +++ b/18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs @@ -0,0 +1,192 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2020-2022 Andre Richter + +//! Peripheral Interrupt Controller Driver. + +use super::{InterruptController, PendingIRQs, PeripheralIRQ}; +use crate::{ + bsp::device_driver::common::MMIODerefWrapper, + driver, exception, memory, synchronization, + synchronization::{IRQSafeNullLock, InitStateLock}, +}; +use tock_registers::{ + interfaces::{Readable, Writeable}, + register_structs, + registers::{ReadOnly, WriteOnly}, +}; + +//-------------------------------------------------------------------------------------------------- +// Private Definitions +//-------------------------------------------------------------------------------------------------- + +register_structs! { + #[allow(non_snake_case)] + WORegisterBlock { + (0x00 => _reserved1), + (0x10 => ENABLE_1: WriteOnly), + (0x14 => ENABLE_2: WriteOnly), + (0x24 => @END), + } +} + +register_structs! { + #[allow(non_snake_case)] + RORegisterBlock { + (0x00 => _reserved1), + (0x04 => PENDING_1: ReadOnly), + (0x08 => PENDING_2: ReadOnly), + (0x0c => @END), + } +} + +/// Abstraction for the WriteOnly parts of the associated MMIO registers. +type WriteOnlyRegisters = MMIODerefWrapper; + +/// Abstraction for the ReadOnly parts of the associated MMIO registers. +type ReadOnlyRegisters = MMIODerefWrapper; + +type HandlerTable = + [Option; InterruptController::NUM_PERIPHERAL_IRQS]; + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +/// Representation of the peripheral interrupt controller. +pub struct PeripheralIC { + mmio_descriptor: memory::mmu::MMIODescriptor, + + /// Access to write registers is guarded with a lock. + wo_registers: IRQSafeNullLock, + + /// Register read access is unguarded. + ro_registers: InitStateLock, + + /// Stores registered IRQ handlers. Writable only during kernel init. RO afterwards. + handler_table: InitStateLock, +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +impl PeripheralIC { + /// Create an instance. + /// + /// # Safety + /// + /// - The user must ensure to provide correct MMIO descriptors. + pub const unsafe fn new(mmio_descriptor: memory::mmu::MMIODescriptor) -> Self { + let addr = mmio_descriptor.start_addr().as_usize(); + + Self { + mmio_descriptor, + wo_registers: IRQSafeNullLock::new(WriteOnlyRegisters::new(addr)), + ro_registers: InitStateLock::new(ReadOnlyRegisters::new(addr)), + handler_table: InitStateLock::new([None; InterruptController::NUM_PERIPHERAL_IRQS]), + } + } + + /// Query the list of pending IRQs. + fn pending_irqs(&self) -> PendingIRQs { + self.ro_registers.read(|regs| { + let pending_mask: u64 = + (u64::from(regs.PENDING_2.get()) << 32) | u64::from(regs.PENDING_1.get()); + + PendingIRQs::new(pending_mask) + }) + } +} + +//------------------------------------------------------------------------------ +// OS Interface Code +//------------------------------------------------------------------------------ +use synchronization::interface::{Mutex, ReadWriteEx}; + +impl driver::interface::DeviceDriver for PeripheralIC { + fn compatible(&self) -> &'static str { + "BCM Peripheral Interrupt Controller" + } + + unsafe fn init(&self) -> Result<(), &'static str> { + let virt_addr = + memory::mmu::kernel_map_mmio(self.compatible(), &self.mmio_descriptor)?.as_usize(); + + self.wo_registers + .lock(|regs| *regs = WriteOnlyRegisters::new(virt_addr)); + self.ro_registers + .write(|regs| *regs = ReadOnlyRegisters::new(virt_addr)); + + Ok(()) + } +} + +impl exception::asynchronous::interface::IRQManager for PeripheralIC { + type IRQNumberType = PeripheralIRQ; + + fn register_handler( + &self, + irq: Self::IRQNumberType, + descriptor: exception::asynchronous::IRQDescriptor, + ) -> Result<(), &'static str> { + self.handler_table.write(|table| { + let irq_number = irq.get(); + + if table[irq_number].is_some() { + return Err("IRQ handler already registered"); + } + + table[irq_number] = Some(descriptor); + + Ok(()) + }) + } + + fn enable(&self, irq: Self::IRQNumberType) { + self.wo_registers.lock(|regs| { + let enable_reg = if irq.get() <= 31 { + ®s.ENABLE_1 + } else { + ®s.ENABLE_2 + }; + + let enable_bit: u32 = 1 << (irq.get() % 32); + + // Writing a 1 to a bit will set the corresponding IRQ enable bit. All other IRQ enable + // bits are unaffected. So we don't need read and OR'ing here. + enable_reg.set(enable_bit); + }); + } + + fn handle_pending_irqs<'irq_context>( + &'irq_context self, + _ic: &exception::asynchronous::IRQContext<'irq_context>, + ) { + self.handler_table.read(|table| { + for irq_number in self.pending_irqs() { + match table[irq_number] { + None => panic!("No handler registered for IRQ {}", irq_number), + Some(descriptor) => { + // Call the IRQ handler. Panics on failure. + descriptor.handler.handle().expect("Error handling IRQ"); + } + } + } + }) + } + + fn print_handler(&self) { + use crate::info; + + info!(" Peripheral handler:"); + + self.handler_table.read(|table| { + for (i, opt) in table.iter().enumerate() { + if let Some(handler) = opt { + info!(" {: >3}. {}", i, handler.name); + } + } + }); + } +} diff --git a/18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs b/18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs new file mode 100644 index 00000000..3133047b --- /dev/null +++ b/18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs @@ -0,0 +1,536 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2018-2022 Andre Richter + +//! PL011 UART driver. +//! +//! # Resources +//! +//! - +//! - + +use crate::{ + bsp, bsp::device_driver::common::MMIODerefWrapper, console, cpu, driver, exception, memory, + synchronization, synchronization::IRQSafeNullLock, +}; +use core::{ + fmt, + sync::atomic::{AtomicUsize, Ordering}, +}; +use tock_registers::{ + interfaces::{Readable, Writeable}, + register_bitfields, register_structs, + registers::{ReadOnly, ReadWrite, WriteOnly}, +}; + +//-------------------------------------------------------------------------------------------------- +// Private Definitions +//-------------------------------------------------------------------------------------------------- + +// PL011 UART registers. +// +// Descriptions taken from "PrimeCell UART (PL011) Technical Reference Manual" r1p5. +register_bitfields! { + u32, + + /// Flag Register. + FR [ + /// Transmit FIFO empty. The meaning of this bit depends on the state of the FEN bit in the + /// Line Control Register, LCR_H. + /// + /// - If the FIFO is disabled, this bit is set when the transmit holding register is empty. + /// - If the FIFO is enabled, the TXFE bit is set when the transmit FIFO is empty. + /// - This bit does not indicate if there is data in the transmit shift register. + TXFE OFFSET(7) NUMBITS(1) [], + + /// Transmit FIFO full. The meaning of this bit depends on the state of the FEN bit in the + /// LCR_H Register. + /// + /// - If the FIFO is disabled, this bit is set when the transmit holding register is full. + /// - If the FIFO is enabled, the TXFF bit is set when the transmit FIFO is full. + TXFF OFFSET(5) NUMBITS(1) [], + + /// Receive FIFO empty. The meaning of this bit depends on the state of the FEN bit in the + /// LCR_H Register. + /// + /// - If the FIFO is disabled, this bit is set when the receive holding register is empty. + /// - If the FIFO is enabled, the RXFE bit is set when the receive FIFO is empty. + RXFE OFFSET(4) NUMBITS(1) [], + + /// UART busy. If this bit is set to 1, the UART is busy transmitting data. This bit remains + /// set until the complete byte, including all the stop bits, has been sent from the shift + /// register. + /// + /// This bit is set as soon as the transmit FIFO becomes non-empty, regardless of whether + /// the UART is enabled or not. + BUSY OFFSET(3) NUMBITS(1) [] + ], + + /// Integer Baud Rate Divisor. + IBRD [ + /// The integer baud rate divisor. + BAUD_DIVINT OFFSET(0) NUMBITS(16) [] + ], + + /// Fractional Baud Rate Divisor. + FBRD [ + /// The fractional baud rate divisor. + BAUD_DIVFRAC OFFSET(0) NUMBITS(6) [] + ], + + /// Line Control Register. + LCR_H [ + /// Word length. These bits indicate the number of data bits transmitted or received in a + /// frame. + #[allow(clippy::enum_variant_names)] + WLEN OFFSET(5) NUMBITS(2) [ + FiveBit = 0b00, + SixBit = 0b01, + SevenBit = 0b10, + EightBit = 0b11 + ], + + /// Enable FIFOs: + /// + /// 0 = FIFOs are disabled (character mode) that is, the FIFOs become 1-byte-deep holding + /// registers. + /// + /// 1 = Transmit and receive FIFO buffers are enabled (FIFO mode). + FEN OFFSET(4) NUMBITS(1) [ + FifosDisabled = 0, + FifosEnabled = 1 + ] + ], + + /// Control Register. + CR [ + /// Receive enable. If this bit is set to 1, the receive section of the UART is enabled. + /// Data reception occurs for either UART signals or SIR signals depending on the setting of + /// the SIREN bit. When the UART is disabled in the middle of reception, it completes the + /// current character before stopping. + RXE OFFSET(9) NUMBITS(1) [ + Disabled = 0, + Enabled = 1 + ], + + /// Transmit enable. If this bit is set to 1, the transmit section of the UART is enabled. + /// Data transmission occurs for either UART signals, or SIR signals depending on the + /// setting of the SIREN bit. When the UART is disabled in the middle of transmission, it + /// completes the current character before stopping. + TXE OFFSET(8) NUMBITS(1) [ + Disabled = 0, + Enabled = 1 + ], + + /// UART enable: + /// + /// 0 = UART is disabled. If the UART is disabled in the middle of transmission or + /// reception, it completes the current character before stopping. + /// + /// 1 = The UART is enabled. Data transmission and reception occurs for either UART signals + /// or SIR signals depending on the setting of the SIREN bit + UARTEN OFFSET(0) NUMBITS(1) [ + /// If the UART is disabled in the middle of transmission or reception, it completes the + /// current character before stopping. + Disabled = 0, + Enabled = 1 + ] + ], + + /// Interrupt FIFO Level Select Register. + IFLS [ + /// Receive interrupt FIFO level select. The trigger points for the receive interrupt are as + /// follows. + RXIFLSEL OFFSET(3) NUMBITS(5) [ + OneEigth = 0b000, + OneQuarter = 0b001, + OneHalf = 0b010, + ThreeQuarters = 0b011, + SevenEights = 0b100 + ] + ], + + /// Interrupt Mask Set/Clear Register. + IMSC [ + /// Receive timeout interrupt mask. A read returns the current mask for the UARTRTINTR + /// interrupt. + /// + /// - On a write of 1, the mask of the UARTRTINTR interrupt is set. + /// - A write of 0 clears the mask. + RTIM OFFSET(6) NUMBITS(1) [ + Disabled = 0, + Enabled = 1 + ], + + /// Receive interrupt mask. A read returns the current mask for the UARTRXINTR interrupt. + /// + /// - On a write of 1, the mask of the UARTRXINTR interrupt is set. + /// - A write of 0 clears the mask. + RXIM OFFSET(4) NUMBITS(1) [ + Disabled = 0, + Enabled = 1 + ] + ], + + /// Masked Interrupt Status Register. + MIS [ + /// Receive timeout masked interrupt status. Returns the masked interrupt state of the + /// UARTRTINTR interrupt. + RTMIS OFFSET(6) NUMBITS(1) [], + + /// Receive masked interrupt status. Returns the masked interrupt state of the UARTRXINTR + /// interrupt. + RXMIS OFFSET(4) NUMBITS(1) [] + ], + + /// Interrupt Clear Register. + ICR [ + /// Meta field for all pending interrupts. + ALL OFFSET(0) NUMBITS(11) [] + ] +} + +register_structs! { + #[allow(non_snake_case)] + pub RegisterBlock { + (0x00 => DR: ReadWrite), + (0x04 => _reserved1), + (0x18 => FR: ReadOnly), + (0x1c => _reserved2), + (0x24 => IBRD: WriteOnly), + (0x28 => FBRD: WriteOnly), + (0x2c => LCR_H: WriteOnly), + (0x30 => CR: WriteOnly), + (0x34 => IFLS: ReadWrite), + (0x38 => IMSC: ReadWrite), + (0x3C => _reserved3), + (0x40 => MIS: ReadOnly), + (0x44 => ICR: WriteOnly), + (0x48 => @END), + } +} + +/// Abstraction for the associated MMIO registers. +type Registers = MMIODerefWrapper; + +#[derive(PartialEq)] +enum BlockingMode { + Blocking, + NonBlocking, +} + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +pub struct PL011UartInner { + registers: Registers, + chars_written: usize, + chars_read: usize, +} + +// Export the inner struct so that BSPs can use it for the panic handler. +pub use PL011UartInner as PanicUart; + +/// Representation of the UART. +pub struct PL011Uart { + mmio_descriptor: memory::mmu::MMIODescriptor, + virt_mmio_start_addr: AtomicUsize, + inner: IRQSafeNullLock, + irq_number: bsp::device_driver::IRQNumber, +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +impl PL011UartInner { + /// Create an instance. + /// + /// # Safety + /// + /// - The user must ensure to provide a correct MMIO start address. + pub const unsafe fn new(mmio_start_addr: usize) -> Self { + Self { + registers: Registers::new(mmio_start_addr), + chars_written: 0, + chars_read: 0, + } + } + + /// Set up baud rate and characteristics. + /// + /// This results in 8N1 and 921_600 baud. + /// + /// The calculation for the BRD is (we set the clock to 48 MHz in config.txt): + /// `(48_000_000 / 16) / 921_600 = 3.2552083`. + /// + /// This means the integer part is `3` and goes into the `IBRD`. + /// The fractional part is `0.2552083`. + /// + /// `FBRD` calculation according to the PL011 Technical Reference Manual: + /// `INTEGER((0.2552083 * 64) + 0.5) = 16`. + /// + /// Therefore, the generated baud rate divider is: `3 + 16/64 = 3.25`. Which results in a + /// genrated baud rate of `48_000_000 / (16 * 3.25) = 923_077`. + /// + /// Error = `((923_077 - 921_600) / 921_600) * 100 = 0.16%`. + /// + /// # Safety + /// + /// - The user must ensure to provide a correct MMIO start address. + pub unsafe fn init(&mut self, new_mmio_start_addr: Option) -> Result<(), &'static str> { + if let Some(addr) = new_mmio_start_addr { + self.registers = Registers::new(addr); + } + + // Execution can arrive here while there are still characters queued in the TX FIFO and + // actively being sent out by the UART hardware. If the UART is turned off in this case, + // those queued characters would be lost. + // + // For example, this can happen during runtime on a call to panic!(), because panic!() + // initializes its own UART instance and calls init(). + // + // Hence, flush first to ensure all pending characters are transmitted. + self.flush(); + + // Turn the UART off temporarily. + self.registers.CR.set(0); + + // Clear all pending interrupts. + self.registers.ICR.write(ICR::ALL::CLEAR); + + // From the PL011 Technical Reference Manual: + // + // The LCR_H, IBRD, and FBRD registers form the single 30-bit wide LCR Register that is + // updated on a single write strobe generated by a LCR_H write. So, to internally update the + // contents of IBRD or FBRD, a LCR_H write must always be performed at the end. + // + // Set the baud rate, 8N1 and FIFO enabled. + self.registers.IBRD.write(IBRD::BAUD_DIVINT.val(3)); + self.registers.FBRD.write(FBRD::BAUD_DIVFRAC.val(16)); + self.registers + .LCR_H + .write(LCR_H::WLEN::EightBit + LCR_H::FEN::FifosEnabled); + + // Set RX FIFO fill level at 1/8. + self.registers.IFLS.write(IFLS::RXIFLSEL::OneEigth); + + // Enable RX IRQ + RX timeout IRQ. + self.registers + .IMSC + .write(IMSC::RXIM::Enabled + IMSC::RTIM::Enabled); + + // Turn the UART on. + self.registers + .CR + .write(CR::UARTEN::Enabled + CR::TXE::Enabled + CR::RXE::Enabled); + + Ok(()) + } + + /// Send a character. + fn write_char(&mut self, c: char) { + // Spin while TX FIFO full is set, waiting for an empty slot. + while self.registers.FR.matches_all(FR::TXFF::SET) { + cpu::nop(); + } + + // Write the character to the buffer. + self.registers.DR.set(c as u32); + + self.chars_written += 1; + } + + /// Block execution until the last buffered character has been physically put on the TX wire. + fn flush(&self) { + // Spin until the busy bit is cleared. + while self.registers.FR.matches_all(FR::BUSY::SET) { + cpu::nop(); + } + } + + /// Retrieve a character. + fn read_char_converting(&mut self, blocking_mode: BlockingMode) -> Option { + // If RX FIFO is empty, + if self.registers.FR.matches_all(FR::RXFE::SET) { + // immediately return in non-blocking mode. + if blocking_mode == BlockingMode::NonBlocking { + return None; + } + + // Otherwise, wait until a char was received. + while self.registers.FR.matches_all(FR::RXFE::SET) { + cpu::nop(); + } + } + + // Read one character. + let mut ret = self.registers.DR.get() as u8 as char; + + // Convert carrige return to newline. + if ret == '\r' { + ret = '\n' + } + + // Update statistics. + self.chars_read += 1; + + Some(ret) + } +} + +/// Implementing `core::fmt::Write` enables usage of the `format_args!` macros, which in turn are +/// used to implement the `kernel`'s `print!` and `println!` macros. By implementing `write_str()`, +/// we get `write_fmt()` automatically. +/// +/// The function takes an `&mut self`, so it must be implemented for the inner struct. +/// +/// See [`src/print.rs`]. +/// +/// [`src/print.rs`]: ../../print/index.html +impl fmt::Write for PL011UartInner { + fn write_str(&mut self, s: &str) -> fmt::Result { + for c in s.chars() { + self.write_char(c); + } + + Ok(()) + } +} + +impl PL011Uart { + /// Create an instance. + /// + /// # Safety + /// + /// - The user must ensure to provide correct MMIO descriptors. + /// - The user must ensure to provide correct IRQ numbers. + pub const unsafe fn new( + mmio_descriptor: memory::mmu::MMIODescriptor, + irq_number: bsp::device_driver::IRQNumber, + ) -> Self { + Self { + mmio_descriptor, + virt_mmio_start_addr: AtomicUsize::new(0), + inner: IRQSafeNullLock::new(PL011UartInner::new( + mmio_descriptor.start_addr().as_usize(), + )), + irq_number, + } + } +} + +//------------------------------------------------------------------------------ +// OS Interface Code +//------------------------------------------------------------------------------ +use synchronization::interface::Mutex; + +impl driver::interface::DeviceDriver for PL011Uart { + fn compatible(&self) -> &'static str { + "BCM PL011 UART" + } + + unsafe fn init(&self) -> Result<(), &'static str> { + let virt_addr = memory::mmu::kernel_map_mmio(self.compatible(), &self.mmio_descriptor)?; + + self.inner + .lock(|inner| inner.init(Some(virt_addr.as_usize())))?; + + self.virt_mmio_start_addr + .store(virt_addr.as_usize(), Ordering::Relaxed); + + Ok(()) + } + + fn register_and_enable_irq_handler(&'static self) -> Result<(), &'static str> { + use bsp::exception::asynchronous::irq_manager; + use exception::asynchronous::{interface::IRQManager, IRQDescriptor}; + + let descriptor = IRQDescriptor { + name: "BCM PL011 UART", + handler: self, + }; + + irq_manager().register_handler(self.irq_number, descriptor)?; + irq_manager().enable(self.irq_number); + + Ok(()) + } + + fn virt_mmio_start_addr(&self) -> Option { + let addr = self.virt_mmio_start_addr.load(Ordering::Relaxed); + + if addr == 0 { + return None; + } + + Some(addr) + } +} + +impl console::interface::Write for PL011Uart { + /// Passthrough of `args` to the `core::fmt::Write` implementation, but guarded by a Mutex to + /// serialize access. + fn write_char(&self, c: char) { + self.inner.lock(|inner| inner.write_char(c)); + } + + fn write_fmt(&self, args: core::fmt::Arguments) -> fmt::Result { + // Fully qualified syntax for the call to `core::fmt::Write::write_fmt()` to increase + // readability. + self.inner.lock(|inner| fmt::Write::write_fmt(inner, args)) + } + + fn flush(&self) { + // Spin until TX FIFO empty is set. + self.inner.lock(|inner| inner.flush()); + } +} + +impl console::interface::Read for PL011Uart { + fn read_char(&self) -> char { + self.inner + .lock(|inner| inner.read_char_converting(BlockingMode::Blocking).unwrap()) + } + + fn clear_rx(&self) { + // Read from the RX FIFO until it is indicating empty. + while self + .inner + .lock(|inner| inner.read_char_converting(BlockingMode::NonBlocking)) + .is_some() + {} + } +} + +impl console::interface::Statistics for PL011Uart { + fn chars_written(&self) -> usize { + self.inner.lock(|inner| inner.chars_written) + } + + fn chars_read(&self) -> usize { + self.inner.lock(|inner| inner.chars_read) + } +} + +impl exception::asynchronous::interface::IRQHandler for PL011Uart { + fn handle(&self) -> Result<(), &'static str> { + self.inner.lock(|inner| { + let pending = inner.registers.MIS.extract(); + + // Clear all pending IRQs. + inner.registers.ICR.write(ICR::ALL::CLEAR); + + // Check for any kind of RX interrupt. + if pending.matches_any(MIS::RXMIS::SET + MIS::RTMIS::SET) { + // Echo any received characters. + while let Some(c) = inner.read_char_converting(BlockingMode::NonBlocking) { + inner.write_char(c) + } + } + }); + + Ok(()) + } +} diff --git a/18_backtrace/kernel/src/bsp/device_driver/common.rs b/18_backtrace/kernel/src/bsp/device_driver/common.rs new file mode 100644 index 00000000..fd9e988e --- /dev/null +++ b/18_backtrace/kernel/src/bsp/device_driver/common.rs @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2020-2022 Andre Richter + +//! Common device driver code. + +use core::{marker::PhantomData, ops}; + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +pub struct MMIODerefWrapper { + start_addr: usize, + phantom: PhantomData T>, +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +impl MMIODerefWrapper { + /// Create an instance. + pub const unsafe fn new(start_addr: usize) -> Self { + Self { + start_addr, + phantom: PhantomData, + } + } +} + +impl ops::Deref for MMIODerefWrapper { + type Target = T; + + fn deref(&self) -> &Self::Target { + unsafe { &*(self.start_addr as *const _) } + } +} diff --git a/18_backtrace/kernel/src/bsp/raspberrypi.rs b/18_backtrace/kernel/src/bsp/raspberrypi.rs new file mode 100644 index 00000000..fb9edf88 --- /dev/null +++ b/18_backtrace/kernel/src/bsp/raspberrypi.rs @@ -0,0 +1,62 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2018-2022 Andre Richter + +//! Top-level BSP file for the Raspberry Pi 3 and 4. + +pub mod console; +pub mod cpu; +pub mod driver; +pub mod exception; +pub mod memory; + +use super::device_driver; +use crate::memory::mmu::MMIODescriptor; +use memory::map::mmio; + +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +static GPIO: device_driver::GPIO = + unsafe { device_driver::GPIO::new(MMIODescriptor::new(mmio::GPIO_START, mmio::GPIO_SIZE)) }; + +static PL011_UART: device_driver::PL011Uart = unsafe { + device_driver::PL011Uart::new( + MMIODescriptor::new(mmio::PL011_UART_START, mmio::PL011_UART_SIZE), + exception::asynchronous::irq_map::PL011_UART, + ) +}; + +#[cfg(feature = "bsp_rpi3")] +static INTERRUPT_CONTROLLER: device_driver::InterruptController = unsafe { + device_driver::InterruptController::new( + MMIODescriptor::new(mmio::LOCAL_IC_START, mmio::LOCAL_IC_SIZE), + MMIODescriptor::new(mmio::PERIPHERAL_IC_START, mmio::PERIPHERAL_IC_SIZE), + ) +}; + +#[cfg(feature = "bsp_rpi4")] +static INTERRUPT_CONTROLLER: device_driver::GICv2 = unsafe { + device_driver::GICv2::new( + MMIODescriptor::new(mmio::GICD_START, mmio::GICD_SIZE), + MMIODescriptor::new(mmio::GICC_START, mmio::GICC_SIZE), + ) +}; + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +/// Board identification. +pub fn board_name() -> &'static str { + #[cfg(feature = "bsp_rpi3")] + { + "Raspberry Pi 3" + } + + #[cfg(feature = "bsp_rpi4")] + { + "Raspberry Pi 4" + } +} diff --git a/18_backtrace/kernel/src/bsp/raspberrypi/console.rs b/18_backtrace/kernel/src/bsp/raspberrypi/console.rs new file mode 100644 index 00000000..a0d2e687 --- /dev/null +++ b/18_backtrace/kernel/src/bsp/raspberrypi/console.rs @@ -0,0 +1,98 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2018-2022 Andre Richter + +//! BSP console facilities. + +use crate::{bsp::device_driver, console, cpu, driver}; +use core::fmt; + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +/// In case of a panic, the panic handler uses this function to take a last shot at printing +/// something before the system is halted. +/// +/// We try to init panic-versions of the GPIO and the UART. The panic versions are not protected +/// with synchronization primitives, which increases chances that we get to print something, even +/// when the kernel's default GPIO or UART instances happen to be locked at the time of the panic. +/// +/// # Safety +/// +/// - Use only for printing during a panic. +#[cfg(not(feature = "test_build"))] +pub unsafe fn panic_console_out() -> impl fmt::Write { + use driver::interface::DeviceDriver; + + // If remapping of the driver's MMIO hasn't already happened, we won't be able to print. Just + // park the CPU core in this case. + let gpio_mmio_start_addr = match super::GPIO.virt_mmio_start_addr() { + None => cpu::wait_forever(), + Some(x) => x, + }; + + let uart_mmio_start_addr = match super::PL011_UART.virt_mmio_start_addr() { + None => cpu::wait_forever(), + Some(x) => x, + }; + + let mut panic_gpio = device_driver::PanicGPIO::new(gpio_mmio_start_addr); + let mut panic_uart = device_driver::PanicUart::new(uart_mmio_start_addr); + + panic_gpio + .init(None) + .unwrap_or_else(|_| cpu::wait_forever()); + panic_gpio.map_pl011_uart(); + panic_uart + .init(None) + .unwrap_or_else(|_| cpu::wait_forever()); + + panic_uart +} + +/// Reduced version for test builds. +/// +/// # Safety +/// +/// - Use only for printing during a panic. +#[cfg(feature = "test_build")] +pub unsafe fn panic_console_out() -> impl fmt::Write { + use driver::interface::DeviceDriver; + + let uart_mmio_start_addr = match super::PL011_UART.virt_mmio_start_addr() { + None => cpu::wait_forever(), + Some(x) => x, + }; + let mut panic_uart = device_driver::PanicUart::new(uart_mmio_start_addr); + + panic_uart + .init(None) + .unwrap_or_else(|_| cpu::qemu_exit_failure()); + + panic_uart +} + +/// Return a reference to the console. +pub fn console() -> &'static impl console::interface::All { + &super::PL011_UART +} + +//-------------------------------------------------------------------------------------------------- +// Testing +//-------------------------------------------------------------------------------------------------- + +/// Minimal code needed to bring up the console in QEMU (for testing only). This is often less steps +/// than on real hardware due to QEMU's abstractions. +#[cfg(feature = "test_build")] +pub fn qemu_bring_up_console() { + use driver::interface::DeviceDriver; + + // Calling the UART's init ensures that the BSP's instance of the UART does remap the MMIO + // addresses. + unsafe { + super::PL011_UART + .init() + .unwrap_or_else(|_| cpu::qemu_exit_failure()); + } +} diff --git a/18_backtrace/kernel/src/bsp/raspberrypi/cpu.rs b/18_backtrace/kernel/src/bsp/raspberrypi/cpu.rs new file mode 100644 index 00000000..85fb89e4 --- /dev/null +++ b/18_backtrace/kernel/src/bsp/raspberrypi/cpu.rs @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2018-2022 Andre Richter + +//! BSP Processor code. + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +/// Used by `arch` code to find the early boot core. +#[no_mangle] +#[link_section = ".text._start_arguments"] +pub static BOOT_CORE_ID: u64 = 0; diff --git a/18_backtrace/kernel/src/bsp/raspberrypi/driver.rs b/18_backtrace/kernel/src/bsp/raspberrypi/driver.rs new file mode 100644 index 00000000..53168752 --- /dev/null +++ b/18_backtrace/kernel/src/bsp/raspberrypi/driver.rs @@ -0,0 +1,61 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2018-2022 Andre Richter + +//! BSP driver support. + +use crate::driver; + +//-------------------------------------------------------------------------------------------------- +// Private Definitions +//-------------------------------------------------------------------------------------------------- + +/// Device Driver Manager type. +struct BSPDriverManager { + device_drivers: [&'static (dyn DeviceDriver + Sync); 3], +} + +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +static BSP_DRIVER_MANAGER: BSPDriverManager = BSPDriverManager { + device_drivers: [ + &super::GPIO, + &super::PL011_UART, + &super::INTERRUPT_CONTROLLER, + ], +}; + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +/// Return a reference to the driver manager. +pub fn driver_manager() -> &'static impl driver::interface::DriverManager { + &BSP_DRIVER_MANAGER +} + +//------------------------------------------------------------------------------ +// OS Interface Code +//------------------------------------------------------------------------------ +use driver::interface::DeviceDriver; + +impl driver::interface::DriverManager for BSPDriverManager { + fn all_device_drivers(&self) -> &[&'static (dyn DeviceDriver + Sync)] { + &self.device_drivers[..] + } + + fn early_print_device_drivers(&self) -> &[&'static (dyn DeviceDriver + Sync)] { + &self.device_drivers[0..=1] + } + + fn non_early_print_device_drivers(&self) -> &[&'static (dyn DeviceDriver + Sync)] { + &self.device_drivers[2..] + } + + fn post_early_print_device_driver_init(&self) { + // Configure PL011Uart's output pins. + super::GPIO.map_pl011_uart(); + } +} diff --git a/18_backtrace/kernel/src/bsp/raspberrypi/exception.rs b/18_backtrace/kernel/src/bsp/raspberrypi/exception.rs new file mode 100644 index 00000000..aa6c5a63 --- /dev/null +++ b/18_backtrace/kernel/src/bsp/raspberrypi/exception.rs @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2020-2022 Andre Richter + +//! BSP synchronous and asynchronous exception handling. + +pub mod asynchronous; diff --git a/18_backtrace/kernel/src/bsp/raspberrypi/exception/asynchronous.rs b/18_backtrace/kernel/src/bsp/raspberrypi/exception/asynchronous.rs new file mode 100644 index 00000000..dc5ab421 --- /dev/null +++ b/18_backtrace/kernel/src/bsp/raspberrypi/exception/asynchronous.rs @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2020-2022 Andre Richter + +//! BSP asynchronous exception handling. + +use crate::{bsp, exception}; + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +#[cfg(feature = "bsp_rpi3")] +pub(in crate::bsp) mod irq_map { + use super::bsp::device_driver::{IRQNumber, PeripheralIRQ}; + + pub const PL011_UART: IRQNumber = IRQNumber::Peripheral(PeripheralIRQ::new(57)); +} + +#[cfg(feature = "bsp_rpi4")] +pub(in crate::bsp) mod irq_map { + use super::bsp::device_driver::IRQNumber; + + pub const PL011_UART: IRQNumber = IRQNumber::new(153); +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +/// Return a reference to the IRQ manager. +pub fn irq_manager() -> &'static impl exception::asynchronous::interface::IRQManager< + IRQNumberType = bsp::device_driver::IRQNumber, +> { + &super::super::INTERRUPT_CONTROLLER +} diff --git a/18_backtrace/kernel/src/bsp/raspberrypi/kernel.ld b/18_backtrace/kernel/src/bsp/raspberrypi/kernel.ld new file mode 100644 index 00000000..6fcbf31c --- /dev/null +++ b/18_backtrace/kernel/src/bsp/raspberrypi/kernel.ld @@ -0,0 +1,114 @@ +/* SPDX-License-Identifier: MIT OR Apache-2.0 + * + * Copyright (c) 2018-2022 Andre Richter + */ + +INCLUDE kernel_virt_addr_space_size.ld; + +PAGE_SIZE = 64K; +PAGE_MASK = PAGE_SIZE - 1; + +/* The kernel's virtual address range will be: + * + * [END_ADDRESS_INCLUSIVE, START_ADDRESS] + * [u64::MAX , (u64::MAX - __kernel_virt_addr_space_size) + 1] + */ +__kernel_virt_start_addr = ((0xffffffffffffffff - __kernel_virt_addr_space_size) + 1); + +__rpi_phys_dram_start_addr = 0; + +/* The physical address at which the the kernel binary will be loaded by the Raspberry's firmware */ +__rpi_phys_binary_load_addr = 0x80000; + + +ENTRY(__rpi_phys_binary_load_addr) + +/* Flags: + * 4 == R + * 5 == RX + * 6 == RW + * + * Segments are marked PT_LOAD below so that the ELF file provides virtual and physical addresses. + * It doesn't mean all of them need actually be loaded. + */ +PHDRS +{ + segment_code PT_LOAD FLAGS(5); + segment_data PT_LOAD FLAGS(6); + segment_boot_core_stack PT_LOAD FLAGS(6); +} + +SECTIONS +{ + . = __kernel_virt_start_addr; + + ASSERT((. & PAGE_MASK) == 0, "Start of address space is not page aligned") + + /*********************************************************************************************** + * Code + RO Data + Global Offset Table + ***********************************************************************************************/ + __code_start = .; + .text : AT(__rpi_phys_binary_load_addr) + { + KEEP(*(.text._start)) + *(.text._start_arguments) /* Constants (or statics in Rust speak) read by _start(). */ + *(.text._start_rust) /* The Rust entry point */ + *(.text*) /* Everything else */ + } :segment_code + + .rodata : ALIGN(8) { *(.rodata*) } :segment_code + .got : ALIGN(8) { *(.got) } :segment_code + .kernel_symbols : ALIGN(8) { + __kernel_symbols_start = .; + . += 32 * 1024; + } :segment_code + + . = ALIGN(PAGE_SIZE); + __code_end_exclusive = .; + + /*********************************************************************************************** + * Data + BSS + ***********************************************************************************************/ + __data_start = .; + .data : { *(.data*) } :segment_data + + /* Section is zeroed in pairs of u64. Align start and end to 16 bytes */ + .bss (NOLOAD) : ALIGN(16) + { + __bss_start = .; + *(.bss*); + . = ALIGN(16); + __bss_end_exclusive = .; + } :segment_data + + . = ALIGN(PAGE_SIZE); + __data_end_exclusive = .; + + /*********************************************************************************************** + * MMIO Remap Reserved + ***********************************************************************************************/ + __mmio_remap_start = .; + . += 8 * 1024 * 1024; + __mmio_remap_end_exclusive = .; + + ASSERT((. & PAGE_MASK) == 0, "MMIO remap reservation is not page aligned") + + /*********************************************************************************************** + * Guard Page + ***********************************************************************************************/ + . += PAGE_SIZE; + + /*********************************************************************************************** + * Boot Core Stack + ***********************************************************************************************/ + .boot_core_stack (NOLOAD) : AT(__rpi_phys_dram_start_addr) + { + __boot_core_stack_start = .; /* ^ */ + /* | stack */ + . += __rpi_phys_binary_load_addr; /* | growth */ + /* | direction */ + __boot_core_stack_end_exclusive = .; /* | */ + } :segment_boot_core_stack + + ASSERT((. & PAGE_MASK) == 0, "End of boot core stack is not page aligned") +} diff --git a/18_backtrace/kernel/src/bsp/raspberrypi/kernel_virt_addr_space_size.ld b/18_backtrace/kernel/src/bsp/raspberrypi/kernel_virt_addr_space_size.ld new file mode 100644 index 00000000..c5d58c30 --- /dev/null +++ b/18_backtrace/kernel/src/bsp/raspberrypi/kernel_virt_addr_space_size.ld @@ -0,0 +1 @@ +__kernel_virt_addr_space_size = 1024 * 1024 * 1024 diff --git a/18_backtrace/kernel/src/bsp/raspberrypi/memory.rs b/18_backtrace/kernel/src/bsp/raspberrypi/memory.rs new file mode 100644 index 00000000..01aa9441 --- /dev/null +++ b/18_backtrace/kernel/src/bsp/raspberrypi/memory.rs @@ -0,0 +1,227 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2018-2022 Andre Richter + +//! BSP Memory Management. +//! +//! The physical memory layout. +//! +//! The Raspberry's firmware copies the kernel binary to 0x8_0000. The preceding region will be used +//! as the boot core's stack. +//! +//! +---------------------------------------+ +//! | | boot_core_stack_start @ 0x0 +//! | | ^ +//! | Boot-core Stack | | stack +//! | | | growth +//! | | | direction +//! +---------------------------------------+ +//! | | code_start @ 0x8_0000 == boot_core_stack_end_exclusive +//! | .text | +//! | .rodata | +//! | .got | +//! | .kernel_symbols | +//! | | +//! +---------------------------------------+ +//! | | data_start == code_end_exclusive +//! | .data | +//! | .bss | +//! | | +//! +---------------------------------------+ +//! | | data_end_exclusive +//! | | +//! +//! +//! +//! +//! +//! The virtual memory layout is as follows: +//! +//! +---------------------------------------+ +//! | | code_start @ __kernel_virt_start_addr +//! | .text | +//! | .rodata | +//! | .got | +//! | .kernel_symbols | +//! | | +//! +---------------------------------------+ +//! | | data_start == code_end_exclusive +//! | .data | +//! | .bss | +//! | | +//! +---------------------------------------+ +//! | | mmio_remap_start == data_end_exclusive +//! | VA region for MMIO remapping | +//! | | +//! +---------------------------------------+ +//! | | mmio_remap_end_exclusive +//! | Unmapped guard page | +//! | | +//! +---------------------------------------+ +//! | | boot_core_stack_start +//! | | ^ +//! | Boot-core Stack | | stack +//! | | | growth +//! | | | direction +//! +---------------------------------------+ +//! | | boot_core_stack_end_exclusive +//! | | +pub mod mmu; + +use crate::memory::{mmu::PageAddress, Address, Physical, Virtual}; +use core::cell::UnsafeCell; + +//-------------------------------------------------------------------------------------------------- +// Private Definitions +//-------------------------------------------------------------------------------------------------- + +// Symbols from the linker script. +extern "Rust" { + static __code_start: UnsafeCell<()>; + static __code_end_exclusive: UnsafeCell<()>; + + static __data_start: UnsafeCell<()>; + static __data_end_exclusive: UnsafeCell<()>; + + static __mmio_remap_start: UnsafeCell<()>; + static __mmio_remap_end_exclusive: UnsafeCell<()>; + + static __boot_core_stack_start: UnsafeCell<()>; + static __boot_core_stack_end_exclusive: UnsafeCell<()>; +} + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +/// The board's physical memory map. +#[rustfmt::skip] +pub(super) mod map { + use super::*; + + /// Physical devices. + #[cfg(feature = "bsp_rpi3")] + pub mod mmio { + use super::*; + + pub const PERIPHERAL_IC_START: Address = Address::new(0x3F00_B200); + pub const PERIPHERAL_IC_SIZE: usize = 0x24; + + pub const GPIO_START: Address = Address::new(0x3F20_0000); + pub const GPIO_SIZE: usize = 0xA0; + + pub const PL011_UART_START: Address = Address::new(0x3F20_1000); + pub const PL011_UART_SIZE: usize = 0x48; + + pub const LOCAL_IC_START: Address = Address::new(0x4000_0000); + pub const LOCAL_IC_SIZE: usize = 0x100; + + pub const END: Address = Address::new(0x4001_0000); + } + + /// Physical devices. + #[cfg(feature = "bsp_rpi4")] + pub mod mmio { + use super::*; + + pub const GPIO_START: Address = Address::new(0xFE20_0000); + pub const GPIO_SIZE: usize = 0xA0; + + pub const PL011_UART_START: Address = Address::new(0xFE20_1000); + pub const PL011_UART_SIZE: usize = 0x48; + + pub const GICD_START: Address = Address::new(0xFF84_1000); + pub const GICD_SIZE: usize = 0x824; + + pub const GICC_START: Address = Address::new(0xFF84_2000); + pub const GICC_SIZE: usize = 0x14; + + pub const END: Address = Address::new(0xFF85_0000); + } + + pub const END: Address = mmio::END; +} + +//-------------------------------------------------------------------------------------------------- +// Private Code +//-------------------------------------------------------------------------------------------------- + +/// Start page address of the code segment. +/// +/// # Safety +/// +/// - Value is provided by the linker script and must be trusted as-is. +#[inline(always)] +fn virt_code_start() -> PageAddress { + PageAddress::from(unsafe { __code_start.get() as usize }) +} + +/// Size of the code segment. +/// +/// # Safety +/// +/// - Value is provided by the linker script and must be trusted as-is. +#[inline(always)] +fn code_size() -> usize { + unsafe { (__code_end_exclusive.get() as usize) - (__code_start.get() as usize) } +} + +/// Start page address of the data segment. +#[inline(always)] +fn virt_data_start() -> PageAddress { + PageAddress::from(unsafe { __data_start.get() as usize }) +} + +/// Size of the data segment. +/// +/// # Safety +/// +/// - Value is provided by the linker script and must be trusted as-is. +#[inline(always)] +fn data_size() -> usize { + unsafe { (__data_end_exclusive.get() as usize) - (__data_start.get() as usize) } +} + +/// Start page address of the MMIO remap reservation. +/// +/// # Safety +/// +/// - Value is provided by the linker script and must be trusted as-is. +#[inline(always)] +fn virt_mmio_remap_start() -> PageAddress { + PageAddress::from(unsafe { __mmio_remap_start.get() as usize }) +} + +/// Size of the MMIO remap reservation. +/// +/// # Safety +/// +/// - Value is provided by the linker script and must be trusted as-is. +#[inline(always)] +fn mmio_remap_size() -> usize { + unsafe { (__mmio_remap_end_exclusive.get() as usize) - (__mmio_remap_start.get() as usize) } +} + +/// Start page address of the boot core's stack. +#[inline(always)] +fn virt_boot_core_stack_start() -> PageAddress { + PageAddress::from(unsafe { __boot_core_stack_start.get() as usize }) +} + +/// Size of the boot core's stack. +#[inline(always)] +fn boot_core_stack_size() -> usize { + unsafe { + (__boot_core_stack_end_exclusive.get() as usize) - (__boot_core_stack_start.get() as usize) + } +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +/// Exclusive end address of the physical address space. +#[inline(always)] +pub fn phys_addr_space_end_exclusive_addr() -> PageAddress { + PageAddress::from(map::END) +} diff --git a/18_backtrace/kernel/src/bsp/raspberrypi/memory/mmu.rs b/18_backtrace/kernel/src/bsp/raspberrypi/memory/mmu.rs new file mode 100644 index 00000000..160c188f --- /dev/null +++ b/18_backtrace/kernel/src/bsp/raspberrypi/memory/mmu.rs @@ -0,0 +1,179 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2018-2022 Andre Richter + +//! BSP Memory Management Unit. + +use crate::{ + memory::{ + mmu::{ + self as generic_mmu, AddressSpace, AssociatedTranslationTable, AttributeFields, + MemoryRegion, PageAddress, TranslationGranule, + }, + Physical, Virtual, + }, + synchronization::InitStateLock, +}; + +//-------------------------------------------------------------------------------------------------- +// Private Definitions +//-------------------------------------------------------------------------------------------------- + +type KernelTranslationTable = + ::TableStartFromTop; + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +/// The translation granule chosen by this BSP. This will be used everywhere else in the kernel to +/// derive respective data structures and their sizes. For example, the `crate::memory::mmu::Page`. +pub type KernelGranule = TranslationGranule<{ 64 * 1024 }>; + +/// The kernel's virtual address space defined by this BSP. +pub type KernelVirtAddrSpace = AddressSpace<{ kernel_virt_addr_space_size() }>; + +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +/// The kernel translation tables. +/// +/// It is mandatory that InitStateLock is transparent. +/// +/// That is, `size_of(InitStateLock) == size_of(KernelTranslationTable)`. +/// There is a unit tests that checks this porperty. +#[link_section = ".data"] +#[no_mangle] +static KERNEL_TABLES: InitStateLock = + InitStateLock::new(KernelTranslationTable::new_for_precompute()); + +/// This value is needed during early boot for MMU setup. +/// +/// This will be patched to the correct value by the "translation table tool" after linking. This +/// given value here is just a dummy. +#[link_section = ".text._start_arguments"] +#[no_mangle] +static PHYS_KERNEL_TABLES_BASE_ADDR: u64 = 0xCCCCAAAAFFFFEEEE; + +//-------------------------------------------------------------------------------------------------- +// Private Code +//-------------------------------------------------------------------------------------------------- + +/// This is a hack for retrieving the value for the kernel's virtual address space size as a +/// constant from a common place, since it is needed as a compile-time/link-time constant in both, +/// the linker script and the Rust sources. +#[allow(clippy::needless_late_init)] +const fn kernel_virt_addr_space_size() -> usize { + let __kernel_virt_addr_space_size; + + include!("../kernel_virt_addr_space_size.ld"); + + __kernel_virt_addr_space_size +} + +/// Helper function for calculating the number of pages the given parameter spans. +const fn size_to_num_pages(size: usize) -> usize { + assert!(size > 0); + assert!(size % KernelGranule::SIZE == 0); + + size >> KernelGranule::SHIFT +} + +/// The data pages of the kernel binary. +fn virt_data_region() -> MemoryRegion { + let num_pages = size_to_num_pages(super::data_size()); + + let start_page_addr = super::virt_data_start(); + let end_exclusive_page_addr = start_page_addr.checked_offset(num_pages as isize).unwrap(); + + MemoryRegion::new(start_page_addr, end_exclusive_page_addr) +} + +// There is no reason to expect the following conversions to fail, since they were generated offline +// by the `translation table tool`. If it doesn't work, a panic due to the unwraps is justified. +fn kernel_virt_to_phys_region(virt_region: MemoryRegion) -> MemoryRegion { + let phys_start_page_addr = + generic_mmu::try_kernel_virt_page_addr_to_phys_page_addr(virt_region.start_page_addr()) + .unwrap(); + + let phys_end_exclusive_page_addr = phys_start_page_addr + .checked_offset(virt_region.num_pages() as isize) + .unwrap(); + + MemoryRegion::new(phys_start_page_addr, phys_end_exclusive_page_addr) +} + +fn kernel_page_attributes(virt_page_addr: PageAddress) -> AttributeFields { + generic_mmu::try_kernel_page_attributes(virt_page_addr).unwrap() +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +/// The code pages of the kernel binary. +pub fn virt_code_region() -> MemoryRegion { + let num_pages = size_to_num_pages(super::code_size()); + + let start_page_addr = super::virt_code_start(); + let end_exclusive_page_addr = start_page_addr.checked_offset(num_pages as isize).unwrap(); + + MemoryRegion::new(start_page_addr, end_exclusive_page_addr) +} + +/// The boot core stack pages. +pub fn virt_boot_core_stack_region() -> MemoryRegion { + let num_pages = size_to_num_pages(super::boot_core_stack_size()); + + let start_page_addr = super::virt_boot_core_stack_start(); + let end_exclusive_page_addr = start_page_addr.checked_offset(num_pages as isize).unwrap(); + + MemoryRegion::new(start_page_addr, end_exclusive_page_addr) +} + +/// Return a reference to the kernel's translation tables. +pub fn kernel_translation_tables() -> &'static InitStateLock { + &KERNEL_TABLES +} + +/// The MMIO remap pages. +pub fn virt_mmio_remap_region() -> MemoryRegion { + let num_pages = size_to_num_pages(super::mmio_remap_size()); + + let start_page_addr = super::virt_mmio_remap_start(); + let end_exclusive_page_addr = start_page_addr.checked_offset(num_pages as isize).unwrap(); + + MemoryRegion::new(start_page_addr, end_exclusive_page_addr) +} + +/// Add mapping records for the kernel binary. +/// +/// The actual translation table entries for the kernel binary are generated using the offline +/// `translation table tool` and patched into the kernel binary. This function just adds the mapping +/// record entries. +pub fn kernel_add_mapping_records_for_precomputed() { + let virt_code_region = virt_code_region(); + generic_mmu::kernel_add_mapping_record( + "Kernel code and RO data", + &virt_code_region, + &kernel_virt_to_phys_region(virt_code_region), + &kernel_page_attributes(virt_code_region.start_page_addr()), + ); + + let virt_data_region = virt_data_region(); + generic_mmu::kernel_add_mapping_record( + "Kernel data and bss", + &virt_data_region, + &kernel_virt_to_phys_region(virt_data_region), + &kernel_page_attributes(virt_data_region.start_page_addr()), + ); + + let virt_boot_core_stack_region = virt_boot_core_stack_region(); + generic_mmu::kernel_add_mapping_record( + "Kernel boot-core stack", + &virt_boot_core_stack_region, + &kernel_virt_to_phys_region(virt_boot_core_stack_region), + &kernel_page_attributes(virt_boot_core_stack_region.start_page_addr()), + ); +} diff --git a/18_backtrace/kernel/src/common.rs b/18_backtrace/kernel/src/common.rs new file mode 100644 index 00000000..678f4a6c --- /dev/null +++ b/18_backtrace/kernel/src/common.rs @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2020-2022 Andre Richter + +//! General purpose code. + +/// Check if a value is aligned to a given size. +#[inline(always)] +pub const fn is_aligned(value: usize, alignment: usize) -> bool { + assert!(alignment.is_power_of_two()); + + (value & (alignment - 1)) == 0 +} + +/// Align down. +#[inline(always)] +pub const fn align_down(value: usize, alignment: usize) -> usize { + assert!(alignment.is_power_of_two()); + + value & !(alignment - 1) +} + +/// Align up. +#[inline(always)] +pub const fn align_up(value: usize, alignment: usize) -> usize { + assert!(alignment.is_power_of_two()); + + (value + alignment - 1) & !(alignment - 1) +} diff --git a/18_backtrace/kernel/src/console.rs b/18_backtrace/kernel/src/console.rs new file mode 100644 index 00000000..e49e241f --- /dev/null +++ b/18_backtrace/kernel/src/console.rs @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2018-2022 Andre Richter + +//! System console. + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +/// Console interfaces. +pub mod interface { + use core::fmt; + + /// Console write functions. + pub trait Write { + /// Write a single character. + fn write_char(&self, c: char); + + /// Write a Rust format string. + fn write_fmt(&self, args: fmt::Arguments) -> fmt::Result; + + /// Block until the last buffered character has been physically put on the TX wire. + fn flush(&self); + } + + /// Console read functions. + pub trait Read { + /// Read a single character. + fn read_char(&self) -> char { + ' ' + } + + /// Clear RX buffers, if any. + fn clear_rx(&self); + } + + /// Console statistics. + pub trait Statistics { + /// Return the number of characters written. + fn chars_written(&self) -> usize { + 0 + } + + /// Return the number of characters read. + fn chars_read(&self) -> usize { + 0 + } + } + + /// Trait alias for a full-fledged console. + pub trait All = Write + Read + Statistics; +} diff --git a/18_backtrace/kernel/src/cpu.rs b/18_backtrace/kernel/src/cpu.rs new file mode 100644 index 00000000..e1493d1d --- /dev/null +++ b/18_backtrace/kernel/src/cpu.rs @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2020-2022 Andre Richter + +//! Processor code. + +#[cfg(target_arch = "aarch64")] +#[path = "_arch/aarch64/cpu.rs"] +mod arch_cpu; + +mod boot; + +pub mod smp; + +//-------------------------------------------------------------------------------------------------- +// Architectural Public Reexports +//-------------------------------------------------------------------------------------------------- +pub use arch_cpu::{nop, wait_forever}; + +#[cfg(feature = "test_build")] +pub use arch_cpu::{qemu_exit_failure, qemu_exit_success}; diff --git a/18_backtrace/kernel/src/cpu/boot.rs b/18_backtrace/kernel/src/cpu/boot.rs new file mode 100644 index 00000000..8091dac3 --- /dev/null +++ b/18_backtrace/kernel/src/cpu/boot.rs @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2021-2022 Andre Richter + +//! Boot code. + +#[cfg(target_arch = "aarch64")] +#[path = "../_arch/aarch64/cpu/boot.rs"] +mod arch_boot; diff --git a/18_backtrace/kernel/src/cpu/smp.rs b/18_backtrace/kernel/src/cpu/smp.rs new file mode 100644 index 00000000..57386f79 --- /dev/null +++ b/18_backtrace/kernel/src/cpu/smp.rs @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2018-2022 Andre Richter + +//! Symmetric multiprocessing. + +#[cfg(target_arch = "aarch64")] +#[path = "../_arch/aarch64/cpu/smp.rs"] +mod arch_smp; + +//-------------------------------------------------------------------------------------------------- +// Architectural Public Reexports +//-------------------------------------------------------------------------------------------------- +pub use arch_smp::core_id; diff --git a/18_backtrace/kernel/src/driver.rs b/18_backtrace/kernel/src/driver.rs new file mode 100644 index 00000000..7b800dbc --- /dev/null +++ b/18_backtrace/kernel/src/driver.rs @@ -0,0 +1,62 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2018-2022 Andre Richter + +//! Driver support. + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +/// Driver interfaces. +pub mod interface { + /// Device Driver functions. + pub trait DeviceDriver { + /// Return a compatibility string for identifying the driver. + fn compatible(&self) -> &'static str; + + /// Called by the kernel to bring up the device. + /// + /// # Safety + /// + /// - During init, drivers might do stuff with system-wide impact. + unsafe fn init(&self) -> Result<(), &'static str> { + Ok(()) + } + + /// Called by the kernel to register and enable the device's IRQ handlers, if any. + /// + /// Rust's type system will prevent a call to this function unless the calling instance + /// itself has static lifetime. + fn register_and_enable_irq_handler(&'static self) -> Result<(), &'static str> { + Ok(()) + } + + /// After MMIO remapping, returns the new virtual start address. + /// + /// This API assumes a driver has only a single, contiguous MMIO aperture, which will not be + /// the case for more complex devices. This API will likely change in future tutorials. + fn virt_mmio_start_addr(&self) -> Option { + None + } + } + + /// Device driver management functions. + /// + /// The `BSP` is supposed to supply one global instance. + pub trait DriverManager { + /// Return a slice of references to all `BSP`-instantiated drivers. + fn all_device_drivers(&self) -> &[&'static (dyn DeviceDriver + Sync)]; + + /// Return only those drivers needed for the BSP's early printing functionality. + /// + /// For example, the default UART. + fn early_print_device_drivers(&self) -> &[&'static (dyn DeviceDriver + Sync)]; + + /// Return all drivers minus early-print drivers. + fn non_early_print_device_drivers(&self) -> &[&'static (dyn DeviceDriver + Sync)]; + + /// Initialization code that runs after the early print driver init. + fn post_early_print_device_driver_init(&self); + } +} diff --git a/18_backtrace/kernel/src/exception.rs b/18_backtrace/kernel/src/exception.rs new file mode 100644 index 00000000..f4af8144 --- /dev/null +++ b/18_backtrace/kernel/src/exception.rs @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2020-2022 Andre Richter + +//! Synchronous and asynchronous exception handling. + +#[cfg(target_arch = "aarch64")] +#[path = "_arch/aarch64/exception.rs"] +mod arch_exception; + +pub mod asynchronous; + +//-------------------------------------------------------------------------------------------------- +// Architectural Public Reexports +//-------------------------------------------------------------------------------------------------- +pub use arch_exception::{current_privilege_level, handling_init}; + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +/// Kernel privilege levels. +#[allow(missing_docs)] +#[derive(PartialEq)] +pub enum PrivilegeLevel { + User, + Kernel, + Hypervisor, + Unknown, +} + +//-------------------------------------------------------------------------------------------------- +// Testing +//-------------------------------------------------------------------------------------------------- + +#[cfg(test)] +mod tests { + use super::*; + use test_macros::kernel_test; + + /// Libkernel unit tests must execute in kernel mode. + #[kernel_test] + fn test_runner_executes_in_kernel_mode() { + let (level, _) = current_privilege_level(); + + assert!(level == PrivilegeLevel::Kernel) + } +} diff --git a/18_backtrace/kernel/src/exception/asynchronous.rs b/18_backtrace/kernel/src/exception/asynchronous.rs new file mode 100644 index 00000000..fb1785c2 --- /dev/null +++ b/18_backtrace/kernel/src/exception/asynchronous.rs @@ -0,0 +1,152 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2020-2022 Andre Richter + +//! Asynchronous exception handling. + +#[cfg(target_arch = "aarch64")] +#[path = "../_arch/aarch64/exception/asynchronous.rs"] +mod arch_asynchronous; + +use core::{fmt, marker::PhantomData}; + +//-------------------------------------------------------------------------------------------------- +// Architectural Public Reexports +//-------------------------------------------------------------------------------------------------- +pub use arch_asynchronous::{ + is_local_irq_masked, local_irq_mask, local_irq_mask_save, local_irq_restore, local_irq_unmask, + print_state, +}; + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +/// Interrupt descriptor. +#[derive(Copy, Clone)] +pub struct IRQDescriptor { + /// Descriptive name. + pub name: &'static str, + + /// Reference to handler trait object. + pub handler: &'static (dyn interface::IRQHandler + Sync), +} + +/// IRQContext token. +/// +/// An instance of this type indicates that the local core is currently executing in IRQ +/// context, aka executing an interrupt vector or subcalls of it. +/// +/// Concept and implementation derived from the `CriticalSection` introduced in +/// +#[derive(Clone, Copy)] +pub struct IRQContext<'irq_context> { + _0: PhantomData<&'irq_context ()>, +} + +/// Asynchronous exception handling interfaces. +pub mod interface { + + /// Implemented by types that handle IRQs. + pub trait IRQHandler { + /// Called when the corresponding interrupt is asserted. + fn handle(&self) -> Result<(), &'static str>; + } + + /// IRQ management functions. + /// + /// The `BSP` is supposed to supply one global instance. Typically implemented by the + /// platform's interrupt controller. + pub trait IRQManager { + /// The IRQ number type depends on the implementation. + type IRQNumberType; + + /// Register a handler. + fn register_handler( + &self, + irq_number: Self::IRQNumberType, + descriptor: super::IRQDescriptor, + ) -> Result<(), &'static str>; + + /// Enable an interrupt in the controller. + fn enable(&self, irq_number: Self::IRQNumberType); + + /// Handle pending interrupts. + /// + /// This function is called directly from the CPU's IRQ exception vector. On AArch64, + /// this means that the respective CPU core has disabled exception handling. + /// This function can therefore not be preempted and runs start to finish. + /// + /// Takes an IRQContext token to ensure it can only be called from IRQ context. + #[allow(clippy::trivially_copy_pass_by_ref)] + fn handle_pending_irqs<'irq_context>( + &'irq_context self, + ic: &super::IRQContext<'irq_context>, + ); + + /// Print list of registered handlers. + fn print_handler(&self); + } +} + +/// A wrapper type for IRQ numbers with integrated range sanity check. +#[derive(Copy, Clone)] +pub struct IRQNumber(usize); + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +impl<'irq_context> IRQContext<'irq_context> { + /// Creates an IRQContext token. + /// + /// # Safety + /// + /// - This must only be called when the current core is in an interrupt context and will not + /// live beyond the end of it. That is, creation is allowed in interrupt vector functions. For + /// example, in the ARMv8-A case, in `extern "C" fn current_elx_irq()`. + /// - Note that the lifetime `'irq_context` of the returned instance is unconstrained. User code + /// must not be able to influence the lifetime picked for this type, since that might cause it + /// to be inferred to `'static`. + #[inline(always)] + pub unsafe fn new() -> Self { + IRQContext { _0: PhantomData } + } +} + +impl IRQNumber<{ MAX_INCLUSIVE }> { + /// Creates a new instance if number <= MAX_INCLUSIVE. + pub const fn new(number: usize) -> Self { + assert!(number <= MAX_INCLUSIVE); + + Self(number) + } + + /// Return the wrapped number. + pub const fn get(self) -> usize { + self.0 + } +} + +impl fmt::Display for IRQNumber<{ MAX_INCLUSIVE }> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.0) + } +} + +/// Executes the provided closure while IRQs are masked on the executing core. +/// +/// While the function temporarily changes the HW state of the executing core, it restores it to the +/// previous state before returning, so this is deemed safe. +#[inline(always)] +pub fn exec_with_irq_masked(f: impl FnOnce() -> T) -> T { + let ret: T; + + unsafe { + let saved = local_irq_mask_save(); + ret = f(); + local_irq_restore(saved); + } + + ret +} diff --git a/18_backtrace/kernel/src/lib.rs b/18_backtrace/kernel/src/lib.rs new file mode 100644 index 00000000..4d7a5f5d --- /dev/null +++ b/18_backtrace/kernel/src/lib.rs @@ -0,0 +1,188 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2018-2022 Andre Richter + +// Rust embedded logo for `make doc`. +#![doc( + html_logo_url = "https://raw.githubusercontent.com/rust-embedded/wg/master/assets/logo/ewg-logo-blue-white-on-transparent.png" +)] + +//! The `kernel` library. +//! +//! Used to compose the final kernel binary. +//! +//! # Code organization and architecture +//! +//! The code is divided into different *modules*, each representing a typical **subsystem** of the +//! `kernel`. Top-level module files of subsystems reside directly in the `src` folder. For example, +//! `src/memory.rs` contains code that is concerned with all things memory management. +//! +//! ## Visibility of processor architecture code +//! +//! Some of the `kernel`'s subsystems depend on low-level code that is specific to the target +//! processor architecture. For each supported processor architecture, there exists a subfolder in +//! `src/_arch`, for example, `src/_arch/aarch64`. +//! +//! The architecture folders mirror the subsystem modules laid out in `src`. For example, +//! architectural code that belongs to the `kernel`'s MMU subsystem (`src/memory/mmu.rs`) would go +//! into `src/_arch/aarch64/memory/mmu.rs`. The latter file is loaded as a module in +//! `src/memory/mmu.rs` using the `path attribute`. Usually, the chosen module name is the generic +//! module's name prefixed with `arch_`. +//! +//! For example, this is the top of `src/memory/mmu.rs`: +//! +//! ``` +//! #[cfg(target_arch = "aarch64")] +//! #[path = "../_arch/aarch64/memory/mmu.rs"] +//! mod arch_mmu; +//! ``` +//! +//! Often times, items from the `arch_ module` will be publicly reexported by the parent module. +//! This way, each architecture specific module can provide its implementation of an item, while the +//! caller must not be concerned which architecture has been conditionally compiled. +//! +//! ## BSP code +//! +//! `BSP` stands for Board Support Package. `BSP` code is organized under `src/bsp.rs` and contains +//! target board specific definitions and functions. These are things such as the board's memory map +//! or instances of drivers for devices that are featured on the respective board. +//! +//! Just like processor architecture code, the `BSP` code's module structure tries to mirror the +//! `kernel`'s subsystem modules, but there is no reexporting this time. That means whatever is +//! provided must be called starting from the `bsp` namespace, e.g. `bsp::driver::driver_manager()`. +//! +//! ## Kernel interfaces +//! +//! Both `arch` and `bsp` contain code that is conditionally compiled depending on the actual target +//! and board for which the kernel is compiled. For example, the `interrupt controller` hardware of +//! the `Raspberry Pi 3` and the `Raspberry Pi 4` is different, but we want the rest of the `kernel` +//! code to play nicely with any of the two without much hassle. +//! +//! In order to provide a clean abstraction between `arch`, `bsp` and `generic kernel code`, +//! `interface` traits are provided *whenever possible* and *where it makes sense*. They are defined +//! in the respective subsystem module and help to enforce the idiom of *program to an interface, +//! not an implementation*. For example, there will be a common IRQ handling interface which the two +//! different interrupt controller `drivers` of both Raspberrys will implement, and only export the +//! interface to the rest of the `kernel`. +//! +//! ``` +//! +-------------------+ +//! | Interface (Trait) | +//! | | +//! +--+-------------+--+ +//! ^ ^ +//! | | +//! | | +//! +----------+--+ +--+----------+ +//! | kernel code | | bsp code | +//! | | | arch code | +//! +-------------+ +-------------+ +//! ``` +//! +//! # Summary +//! +//! For a logical `kernel` subsystem, corresponding code can be distributed over several physical +//! locations. Here is an example for the **memory** subsystem: +//! +//! - `src/memory.rs` and `src/memory/**/*` +//! - Common code that is agnostic of target processor architecture and `BSP` characteristics. +//! - Example: A function to zero a chunk of memory. +//! - Interfaces for the memory subsystem that are implemented by `arch` or `BSP` code. +//! - Example: An `MMU` interface that defines `MMU` function prototypes. +//! - `src/bsp/__board_name__/memory.rs` and `src/bsp/__board_name__/memory/**/*` +//! - `BSP` specific code. +//! - Example: The board's memory map (physical addresses of DRAM and MMIO devices). +//! - `src/_arch/__arch_name__/memory.rs` and `src/_arch/__arch_name__/memory/**/*` +//! - Processor architecture specific code. +//! - Example: Implementation of the `MMU` interface for the `__arch_name__` processor +//! architecture. +//! +//! From a namespace perspective, **memory** subsystem code lives in: +//! +//! - `crate::memory::*` +//! - `crate::bsp::memory::*` +//! +//! # Boot flow +//! +//! 1. The kernel's entry point is the function `cpu::boot::arch_boot::_start()`. +//! - It is implemented in `src/_arch/__arch_name__/cpu/boot.s`. +//! 2. Once finished with architectural setup, the arch code calls `kernel_init()`. + +#![allow(clippy::upper_case_acronyms)] +#![allow(incomplete_features)] +#![feature(asm_const)] +#![feature(core_intrinsics)] +#![feature(format_args_nl)] +#![feature(generic_const_exprs)] +#![feature(linkage)] +#![feature(panic_info_message)] +#![feature(step_trait)] +#![feature(trait_alias)] +#![no_std] +// Testing +#![cfg_attr(test, no_main)] +#![feature(custom_test_frameworks)] +#![reexport_test_harness_main = "test_main"] +#![test_runner(crate::test_runner)] + +mod panic_wait; +mod synchronization; + +pub mod backtrace; +pub mod bsp; +pub mod common; +pub mod console; +pub mod cpu; +pub mod driver; +pub mod exception; +pub mod memory; +pub mod print; +pub mod state; +pub mod symbols; +pub mod time; + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +/// Version string. +pub fn version() -> &'static str { + concat!( + env!("CARGO_PKG_NAME"), + " version ", + env!("CARGO_PKG_VERSION") + ) +} + +//-------------------------------------------------------------------------------------------------- +// Testing +//-------------------------------------------------------------------------------------------------- + +/// The default runner for unit tests. +pub fn test_runner(tests: &[&test_types::UnitTest]) { + // This line will be printed as the test header. + println!("Running {} tests", tests.len()); + + for (i, test) in tests.iter().enumerate() { + print!("{:>3}. {:.<58}", i + 1, test.name); + + // Run the actual test. + (test.test_func)(); + + // Failed tests call panic!(). Execution reaches here only if the test has passed. + println!("[ok]") + } +} + +/// The `kernel_init()` for unit tests. +#[cfg(test)] +#[no_mangle] +unsafe fn kernel_init() -> ! { + exception::handling_init(); + memory::mmu::post_enable_init(); + bsp::console::qemu_bring_up_console(); + + test_main(); + + cpu::qemu_exit_success() +} diff --git a/18_backtrace/kernel/src/main.rs b/18_backtrace/kernel/src/main.rs new file mode 100644 index 00000000..5150f3af --- /dev/null +++ b/18_backtrace/kernel/src/main.rs @@ -0,0 +1,111 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2018-2022 Andre Richter + +// Rust embedded logo for `make doc`. +#![doc( + html_logo_url = "https://raw.githubusercontent.com/rust-embedded/wg/master/assets/logo/ewg-logo-blue-white-on-transparent.png" +)] + +//! The `kernel` binary. + +#![feature(format_args_nl)] +#![no_main] +#![no_std] + +use libkernel::{bsp, cpu, driver, exception, info, memory, state, time, warn}; + +/// Early init code. +/// +/// When this code runs, virtual memory is already enabled. +/// +/// # Safety +/// +/// - Only a single core must be active and running this function. +/// - Printing will not work until the respective driver's MMIO is remapped. +#[no_mangle] +unsafe fn kernel_init() -> ! { + use driver::interface::DriverManager; + + exception::handling_init(); + memory::mmu::post_enable_init(); + + // Add the mapping records for the precomputed entries first, so that they appear on the top of + // the list. + bsp::memory::mmu::kernel_add_mapping_records_for_precomputed(); + + // Bring up the drivers needed for printing first. + for i in bsp::driver::driver_manager() + .early_print_device_drivers() + .iter() + { + // Any encountered errors cannot be printed yet, obviously, so just safely park the CPU. + i.init().unwrap_or_else(|_| cpu::wait_forever()); + } + bsp::driver::driver_manager().post_early_print_device_driver_init(); + // Printing available from here on. + + // Now bring up the remaining drivers. + for i in bsp::driver::driver_manager() + .non_early_print_device_drivers() + .iter() + { + if let Err(x) = i.init() { + panic!("Error loading driver: {}: {}", i.compatible(), x); + } + } + + // Let device drivers register and enable their handlers with the interrupt controller. + for i in bsp::driver::driver_manager().all_device_drivers() { + if let Err(msg) = i.register_and_enable_irq_handler() { + warn!("Error registering IRQ handler: {}", msg); + } + } + + // Unmask interrupts on the boot CPU core. + exception::asynchronous::local_irq_unmask(); + + // Announce conclusion of the kernel_init() phase. + state::state_manager().transition_to_single_core_main(); + + // Transition from unsafe to safe. + kernel_main() +} + +/// The main function running after the early init. +fn kernel_main() -> ! { + use driver::interface::DriverManager; + use exception::asynchronous::interface::IRQManager; + + info!("{}", libkernel::version()); + info!("Booting on: {}", bsp::board_name()); + + info!("MMU online:"); + memory::mmu::kernel_print_mappings(); + + let (_, privilege_level) = exception::current_privilege_level(); + info!("Current privilege level: {}", privilege_level); + + info!("Exception handling state:"); + exception::asynchronous::print_state(); + + info!( + "Architectural timer resolution: {} ns", + time::time_manager().resolution().as_nanos() + ); + + info!("Drivers loaded:"); + for (i, driver) in bsp::driver::driver_manager() + .all_device_drivers() + .iter() + .enumerate() + { + info!(" {}. {}", i + 1, driver.compatible()); + } + + info!("Registered IRQ handlers:"); + bsp::exception::asynchronous::irq_manager().print_handler(); + + info!("Echoing input now"); + cpu::wait_forever(); +} diff --git a/18_backtrace/kernel/src/memory.rs b/18_backtrace/kernel/src/memory.rs new file mode 100644 index 00000000..5e8cdbce --- /dev/null +++ b/18_backtrace/kernel/src/memory.rs @@ -0,0 +1,191 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2018-2022 Andre Richter + +//! Memory Management. + +pub mod mmu; + +use crate::{bsp, common}; +use core::{ + fmt, + marker::PhantomData, + ops::{Add, Sub}, +}; + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +/// Metadata trait for marking the type of an address. +pub trait AddressType: Copy + Clone + PartialOrd + PartialEq {} + +/// Zero-sized type to mark a physical address. +#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)] +pub enum Physical {} + +/// Zero-sized type to mark a virtual address. +#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)] +pub enum Virtual {} + +/// Generic address type. +#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)] +pub struct Address { + value: usize, + _address_type: PhantomData ATYPE>, +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +impl AddressType for Physical {} +impl AddressType for Virtual {} + +impl Address { + /// Create an instance. + pub const fn new(value: usize) -> Self { + Self { + value, + _address_type: PhantomData, + } + } + + /// Convert to usize. + pub const fn as_usize(self) -> usize { + self.value + } + + /// Align down to page size. + #[must_use] + pub const fn align_down_page(self) -> Self { + let aligned = common::align_down(self.value, bsp::memory::mmu::KernelGranule::SIZE); + + Self::new(aligned) + } + + /// Align up to page size. + #[must_use] + pub const fn align_up_page(self) -> Self { + let aligned = common::align_up(self.value, bsp::memory::mmu::KernelGranule::SIZE); + + Self::new(aligned) + } + + /// Checks if the address is page aligned. + pub const fn is_page_aligned(&self) -> bool { + common::is_aligned(self.value, bsp::memory::mmu::KernelGranule::SIZE) + } + + /// Return the address' offset into the corresponding page. + pub const fn offset_into_page(&self) -> usize { + self.value & bsp::memory::mmu::KernelGranule::MASK + } +} + +impl Add for Address { + type Output = Self; + + #[inline(always)] + fn add(self, rhs: usize) -> Self::Output { + match self.value.checked_add(rhs) { + None => panic!("Overflow on Address::add"), + Some(x) => Self::new(x), + } + } +} + +impl Sub for Address { + type Output = Self; + + #[inline(always)] + fn sub(self, rhs: usize) -> Self::Output { + match self.value.checked_sub(rhs) { + None => panic!("Overflow on Address::sub"), + Some(x) => Self::new(x), + } + } +} + +impl Sub> for Address { + type Output = Self; + + #[inline(always)] + fn sub(self, rhs: Address) -> Self::Output { + match self.value.checked_sub(rhs.value) { + None => panic!("Overflow on Address::sub"), + Some(x) => Self::new(x), + } + } +} + +impl Address { + /// Checks if the address is part of the boot core stack region. + pub fn is_valid_stack_addr(&self) -> bool { + bsp::memory::mmu::virt_boot_core_stack_region().contains(*self) + } + + /// Checks if the address is part of the kernel code region. + pub fn is_valid_code_addr(&self) -> bool { + bsp::memory::mmu::virt_code_region().contains(*self) + } +} + +impl fmt::Display for Address { + // Don't expect to see physical addresses greater than 40 bit. + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let q3: u8 = ((self.value >> 32) & 0xff) as u8; + let q2: u16 = ((self.value >> 16) & 0xffff) as u16; + let q1: u16 = (self.value & 0xffff) as u16; + + write!(f, "0x")?; + write!(f, "{:02x}_", q3)?; + write!(f, "{:04x}_", q2)?; + write!(f, "{:04x}", q1) + } +} + +impl fmt::Display for Address { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let q4: u16 = ((self.value >> 48) & 0xffff) as u16; + let q3: u16 = ((self.value >> 32) & 0xffff) as u16; + let q2: u16 = ((self.value >> 16) & 0xffff) as u16; + let q1: u16 = (self.value & 0xffff) as u16; + + write!(f, "0x")?; + write!(f, "{:04x}_", q4)?; + write!(f, "{:04x}_", q3)?; + write!(f, "{:04x}_", q2)?; + write!(f, "{:04x}", q1) + } +} + +//-------------------------------------------------------------------------------------------------- +// Testing +//-------------------------------------------------------------------------------------------------- + +#[cfg(test)] +mod tests { + use super::*; + use test_macros::kernel_test; + + /// Sanity of [Address] methods. + #[kernel_test] + fn address_type_method_sanity() { + let addr = Address::::new(bsp::memory::mmu::KernelGranule::SIZE + 100); + + assert_eq!( + addr.align_down_page().as_usize(), + bsp::memory::mmu::KernelGranule::SIZE + ); + + assert_eq!( + addr.align_up_page().as_usize(), + bsp::memory::mmu::KernelGranule::SIZE * 2 + ); + + assert!(!addr.is_page_aligned()); + + assert_eq!(addr.offset_into_page(), 100); + } +} diff --git a/18_backtrace/kernel/src/memory/mmu.rs b/18_backtrace/kernel/src/memory/mmu.rs new file mode 100644 index 00000000..dfc29993 --- /dev/null +++ b/18_backtrace/kernel/src/memory/mmu.rs @@ -0,0 +1,270 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2020-2022 Andre Richter + +//! Memory Management Unit. + +#[cfg(target_arch = "aarch64")] +#[path = "../_arch/aarch64/memory/mmu.rs"] +mod arch_mmu; + +mod alloc; +mod mapping_record; +mod translation_table; +mod types; + +use crate::{ + bsp, + memory::{Address, Physical, Virtual}, + synchronization::{self, interface::Mutex}, + warn, +}; +use core::{fmt, num::NonZeroUsize}; + +pub use types::*; + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +/// MMU enable errors variants. +#[allow(missing_docs)] +#[derive(Debug)] +pub enum MMUEnableError { + AlreadyEnabled, + Other(&'static str), +} + +/// Memory Management interfaces. +pub mod interface { + use super::*; + + /// MMU functions. + pub trait MMU { + /// Turns on the MMU for the first time and enables data and instruction caching. + /// + /// # Safety + /// + /// - Changes the HW's global state. + unsafe fn enable_mmu_and_caching( + &self, + phys_tables_base_addr: Address, + ) -> Result<(), MMUEnableError>; + + /// Returns true if the MMU is enabled, false otherwise. + fn is_enabled(&self) -> bool; + } +} + +/// Describes the characteristics of a translation granule. +pub struct TranslationGranule; + +/// Describes properties of an address space. +pub struct AddressSpace; + +/// Intended to be implemented for [`AddressSpace`]. +pub trait AssociatedTranslationTable { + /// A translation table whose address range is: + /// + /// [u64::MAX, (u64::MAX - AS_SIZE) + 1] + type TableStartFromTop; + + /// A translation table whose address range is: + /// + /// [AS_SIZE - 1, 0] + type TableStartFromBottom; +} + +//-------------------------------------------------------------------------------------------------- +// Private Code +//-------------------------------------------------------------------------------------------------- +use interface::MMU; +use synchronization::interface::ReadWriteEx; +use translation_table::interface::TranslationTable; + +/// Query the BSP for the reserved virtual addresses for MMIO remapping and initialize the kernel's +/// MMIO VA allocator with it. +fn kernel_init_mmio_va_allocator() { + let region = bsp::memory::mmu::virt_mmio_remap_region(); + + alloc::kernel_mmio_va_allocator().lock(|allocator| allocator.initialize(region)); +} + +/// Map a region in the kernel's translation tables. +/// +/// No input checks done, input is passed through to the architectural implementation. +/// +/// # Safety +/// +/// - See `map_at()`. +/// - Does not prevent aliasing. +unsafe fn kernel_map_at_unchecked( + name: &'static str, + virt_region: &MemoryRegion, + phys_region: &MemoryRegion, + attr: &AttributeFields, +) -> Result<(), &'static str> { + bsp::memory::mmu::kernel_translation_tables() + .write(|tables| tables.map_at(virt_region, phys_region, attr))?; + + kernel_add_mapping_record(name, virt_region, phys_region, attr); + + Ok(()) +} + +/// Try to translate a kernel virtual address to a physical address. +/// +/// Will only succeed if there exists a valid mapping for the input address. +fn try_kernel_virt_addr_to_phys_addr( + virt_addr: Address, +) -> Result, &'static str> { + bsp::memory::mmu::kernel_translation_tables() + .read(|tables| tables.try_virt_addr_to_phys_addr(virt_addr)) +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +impl fmt::Display for MMUEnableError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + MMUEnableError::AlreadyEnabled => write!(f, "MMU is already enabled"), + MMUEnableError::Other(x) => write!(f, "{}", x), + } + } +} + +impl TranslationGranule { + /// The granule's size. + pub const SIZE: usize = Self::size_checked(); + + /// The granule's mask. + pub const MASK: usize = Self::SIZE - 1; + + /// The granule's shift, aka log2(size). + pub const SHIFT: usize = Self::SIZE.trailing_zeros() as usize; + + const fn size_checked() -> usize { + assert!(GRANULE_SIZE.is_power_of_two()); + + GRANULE_SIZE + } +} + +impl AddressSpace { + /// The address space size. + pub const SIZE: usize = Self::size_checked(); + + /// The address space shift, aka log2(size). + pub const SIZE_SHIFT: usize = Self::SIZE.trailing_zeros() as usize; + + const fn size_checked() -> usize { + assert!(AS_SIZE.is_power_of_two()); + + // Check for architectural restrictions as well. + Self::arch_address_space_size_sanity_checks(); + + AS_SIZE + } +} + +/// Add an entry to the mapping info record. +pub fn kernel_add_mapping_record( + name: &'static str, + virt_region: &MemoryRegion, + phys_region: &MemoryRegion, + attr: &AttributeFields, +) { + if let Err(x) = mapping_record::kernel_add(name, virt_region, phys_region, attr) { + warn!("{}", x); + } +} + +/// MMIO remapping in the kernel translation tables. +/// +/// Typically used by device drivers. +/// +/// # Safety +/// +/// - Same as `kernel_map_at_unchecked()`, minus the aliasing part. +pub unsafe fn kernel_map_mmio( + name: &'static str, + mmio_descriptor: &MMIODescriptor, +) -> Result, &'static str> { + let phys_region = MemoryRegion::from(*mmio_descriptor); + let offset_into_start_page = mmio_descriptor.start_addr().offset_into_page(); + + // Check if an identical region has been mapped for another driver. If so, reuse it. + let virt_addr = if let Some(addr) = + mapping_record::kernel_find_and_insert_mmio_duplicate(mmio_descriptor, name) + { + addr + // Otherwise, allocate a new region and map it. + } else { + let num_pages = match NonZeroUsize::new(phys_region.num_pages()) { + None => return Err("Requested 0 pages"), + Some(x) => x, + }; + + let virt_region = + alloc::kernel_mmio_va_allocator().lock(|allocator| allocator.alloc(num_pages))?; + + kernel_map_at_unchecked( + name, + &virt_region, + &phys_region, + &AttributeFields { + mem_attributes: MemAttributes::Device, + acc_perms: AccessPermissions::ReadWrite, + execute_never: true, + }, + )?; + + virt_region.start_addr() + }; + + Ok(virt_addr + offset_into_start_page) +} + +/// Try to translate a kernel virtual page address to a physical page address. +/// +/// Will only succeed if there exists a valid mapping for the input page. +pub fn try_kernel_virt_page_addr_to_phys_page_addr( + virt_page_addr: PageAddress, +) -> Result, &'static str> { + bsp::memory::mmu::kernel_translation_tables() + .read(|tables| tables.try_virt_page_addr_to_phys_page_addr(virt_page_addr)) +} + +/// Try to get the attributes of a kernel page. +/// +/// Will only succeed if there exists a valid mapping for the input page. +pub fn try_kernel_page_attributes( + virt_page_addr: PageAddress, +) -> Result { + bsp::memory::mmu::kernel_translation_tables() + .read(|tables| tables.try_page_attributes(virt_page_addr)) +} + +/// Enable the MMU and data + instruction caching. +/// +/// # Safety +/// +/// - Crucial function during kernel init. Changes the the complete memory view of the processor. +#[inline(always)] +pub unsafe fn enable_mmu_and_caching( + phys_tables_base_addr: Address, +) -> Result<(), MMUEnableError> { + arch_mmu::mmu().enable_mmu_and_caching(phys_tables_base_addr) +} + +/// Finish initialization of the MMU subsystem. +pub fn post_enable_init() { + kernel_init_mmio_va_allocator(); +} + +/// Human-readable print of all recorded kernel mappings. +pub fn kernel_print_mappings() { + mapping_record::kernel_print() +} diff --git a/18_backtrace/kernel/src/memory/mmu/alloc.rs b/18_backtrace/kernel/src/memory/mmu/alloc.rs new file mode 100644 index 00000000..aadb72ef --- /dev/null +++ b/18_backtrace/kernel/src/memory/mmu/alloc.rs @@ -0,0 +1,70 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2021-2022 Andre Richter + +//! Allocation. + +use super::MemoryRegion; +use crate::{ + memory::{AddressType, Virtual}, + synchronization::IRQSafeNullLock, + warn, +}; +use core::num::NonZeroUsize; + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +/// A page allocator that can be lazyily initialized. +pub struct PageAllocator { + pool: Option>, +} + +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +static KERNEL_MMIO_VA_ALLOCATOR: IRQSafeNullLock> = + IRQSafeNullLock::new(PageAllocator::new()); + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +/// Return a reference to the kernel's MMIO virtual address allocator. +pub fn kernel_mmio_va_allocator() -> &'static IRQSafeNullLock> { + &KERNEL_MMIO_VA_ALLOCATOR +} + +impl PageAllocator { + /// Create an instance. + pub const fn new() -> Self { + Self { pool: None } + } + + /// Initialize the allocator. + pub fn initialize(&mut self, pool: MemoryRegion) { + if self.pool.is_some() { + warn!("Already initialized"); + return; + } + + self.pool = Some(pool); + } + + /// Allocate a number of pages. + pub fn alloc( + &mut self, + num_requested_pages: NonZeroUsize, + ) -> Result, &'static str> { + if self.pool.is_none() { + return Err("Allocator not initialized"); + } + + self.pool + .as_mut() + .unwrap() + .take_first_n_pages(num_requested_pages) + } +} diff --git a/18_backtrace/kernel/src/memory/mmu/mapping_record.rs b/18_backtrace/kernel/src/memory/mmu/mapping_record.rs new file mode 100644 index 00000000..d171c6e6 --- /dev/null +++ b/18_backtrace/kernel/src/memory/mmu/mapping_record.rs @@ -0,0 +1,233 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2020-2022 Andre Richter + +//! A record of mapped pages. + +use super::{ + AccessPermissions, Address, AttributeFields, MMIODescriptor, MemAttributes, MemoryRegion, + Physical, Virtual, +}; +use crate::{bsp, info, synchronization, synchronization::InitStateLock, warn}; + +//-------------------------------------------------------------------------------------------------- +// Private Definitions +//-------------------------------------------------------------------------------------------------- + +/// Type describing a virtual memory mapping. +#[allow(missing_docs)] +#[derive(Copy, Clone)] +struct MappingRecordEntry { + pub users: [Option<&'static str>; 5], + pub phys_start_addr: Address, + pub virt_start_addr: Address, + pub num_pages: usize, + pub attribute_fields: AttributeFields, +} + +struct MappingRecord { + inner: [Option; 12], +} + +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +static KERNEL_MAPPING_RECORD: InitStateLock = + InitStateLock::new(MappingRecord::new()); + +//-------------------------------------------------------------------------------------------------- +// Private Code +//-------------------------------------------------------------------------------------------------- + +impl MappingRecordEntry { + pub fn new( + name: &'static str, + virt_region: &MemoryRegion, + phys_region: &MemoryRegion, + attr: &AttributeFields, + ) -> Self { + Self { + users: [Some(name), None, None, None, None], + phys_start_addr: phys_region.start_addr(), + virt_start_addr: virt_region.start_addr(), + num_pages: phys_region.num_pages(), + attribute_fields: *attr, + } + } + + fn find_next_free_user(&mut self) -> Result<&mut Option<&'static str>, &'static str> { + if let Some(x) = self.users.iter_mut().find(|x| x.is_none()) { + return Ok(x); + }; + + Err("Storage for user info exhausted") + } + + pub fn add_user(&mut self, user: &'static str) -> Result<(), &'static str> { + let x = self.find_next_free_user()?; + *x = Some(user); + Ok(()) + } +} + +impl MappingRecord { + pub const fn new() -> Self { + Self { inner: [None; 12] } + } + + fn find_next_free(&mut self) -> Result<&mut Option, &'static str> { + if let Some(x) = self.inner.iter_mut().find(|x| x.is_none()) { + return Ok(x); + } + + Err("Storage for mapping info exhausted") + } + + fn find_duplicate( + &mut self, + phys_region: &MemoryRegion, + ) -> Option<&mut MappingRecordEntry> { + self.inner + .iter_mut() + .filter(|x| x.is_some()) + .map(|x| x.as_mut().unwrap()) + .filter(|x| x.attribute_fields.mem_attributes == MemAttributes::Device) + .find(|x| { + if x.phys_start_addr != phys_region.start_addr() { + return false; + } + + if x.num_pages != phys_region.num_pages() { + return false; + } + + true + }) + } + + pub fn add( + &mut self, + name: &'static str, + virt_region: &MemoryRegion, + phys_region: &MemoryRegion, + attr: &AttributeFields, + ) -> Result<(), &'static str> { + let x = self.find_next_free()?; + + *x = Some(MappingRecordEntry::new( + name, + virt_region, + phys_region, + attr, + )); + Ok(()) + } + + pub fn print(&self) { + const KIB_RSHIFT: u32 = 10; // log2(1024). + const MIB_RSHIFT: u32 = 20; // log2(1024 * 1024). + + info!(" -------------------------------------------------------------------------------------------------------------------------------------------"); + info!( + " {:^44} {:^30} {:^7} {:^9} {:^35}", + "Virtual", "Physical", "Size", "Attr", "Entity" + ); + info!(" -------------------------------------------------------------------------------------------------------------------------------------------"); + + for i in self.inner.iter().flatten() { + let size = i.num_pages * bsp::memory::mmu::KernelGranule::SIZE; + let virt_start = i.virt_start_addr; + let virt_end_inclusive = virt_start + (size - 1); + let phys_start = i.phys_start_addr; + let phys_end_inclusive = phys_start + (size - 1); + + let (size, unit) = if (size >> MIB_RSHIFT) > 0 { + (size >> MIB_RSHIFT, "MiB") + } else if (size >> KIB_RSHIFT) > 0 { + (size >> KIB_RSHIFT, "KiB") + } else { + (size, "Byte") + }; + + let attr = match i.attribute_fields.mem_attributes { + MemAttributes::CacheableDRAM => "C", + MemAttributes::Device => "Dev", + }; + + let acc_p = match i.attribute_fields.acc_perms { + AccessPermissions::ReadOnly => "RO", + AccessPermissions::ReadWrite => "RW", + }; + + let xn = if i.attribute_fields.execute_never { + "XN" + } else { + "X" + }; + + info!( + " {}..{} --> {}..{} | \ + {: >3} {} | {: <3} {} {: <2} | {}", + virt_start, + virt_end_inclusive, + phys_start, + phys_end_inclusive, + size, + unit, + attr, + acc_p, + xn, + i.users[0].unwrap() + ); + + for k in i.users[1..].iter() { + if let Some(additional_user) = *k { + info!( + " | {}", + additional_user + ); + } + } + } + + info!(" -------------------------------------------------------------------------------------------------------------------------------------------"); + } +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- +use synchronization::interface::ReadWriteEx; + +/// Add an entry to the mapping info record. +pub fn kernel_add( + name: &'static str, + virt_region: &MemoryRegion, + phys_region: &MemoryRegion, + attr: &AttributeFields, +) -> Result<(), &'static str> { + KERNEL_MAPPING_RECORD.write(|mr| mr.add(name, virt_region, phys_region, attr)) +} + +pub fn kernel_find_and_insert_mmio_duplicate( + mmio_descriptor: &MMIODescriptor, + new_user: &'static str, +) -> Option> { + let phys_region: MemoryRegion = (*mmio_descriptor).into(); + + KERNEL_MAPPING_RECORD.write(|mr| { + let dup = mr.find_duplicate(&phys_region)?; + + if let Err(x) = dup.add_user(new_user) { + warn!("{}", x); + } + + Some(dup.virt_start_addr) + }) +} + +/// Human-readable print of all recorded kernel mappings. +pub fn kernel_print() { + KERNEL_MAPPING_RECORD.read(|mr| mr.print()); +} diff --git a/18_backtrace/kernel/src/memory/mmu/translation_table.rs b/18_backtrace/kernel/src/memory/mmu/translation_table.rs new file mode 100644 index 00000000..9d627f97 --- /dev/null +++ b/18_backtrace/kernel/src/memory/mmu/translation_table.rs @@ -0,0 +1,137 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2021-2022 Andre Richter + +//! Translation table. + +#[cfg(target_arch = "aarch64")] +#[path = "../../_arch/aarch64/memory/mmu/translation_table.rs"] +mod arch_translation_table; + +use super::{AttributeFields, MemoryRegion}; +use crate::memory::{Address, Physical, Virtual}; + +//-------------------------------------------------------------------------------------------------- +// Architectural Public Reexports +//-------------------------------------------------------------------------------------------------- +#[cfg(target_arch = "aarch64")] +pub use arch_translation_table::FixedSizeTranslationTable; + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +/// Translation table interfaces. +pub mod interface { + use crate::memory::mmu::PageAddress; + + use super::*; + + /// Translation table operations. + pub trait TranslationTable { + /// Anything that needs to run before any of the other provided functions can be used. + /// + /// # Safety + /// + /// - Implementor must ensure that this function can run only once or is harmless if invoked + /// multiple times. + fn init(&mut self) -> Result<(), &'static str>; + + /// Map the given virtual memory region to the given physical memory region. + /// + /// # Safety + /// + /// - Using wrong attributes can cause multiple issues of different nature in the system. + /// - It is not required that the architectural implementation prevents aliasing. That is, + /// mapping to the same physical memory using multiple virtual addresses, which would + /// break Rust's ownership assumptions. This should be protected against in the kernel's + /// generic MMU code. + unsafe fn map_at( + &mut self, + virt_region: &MemoryRegion, + phys_region: &MemoryRegion, + attr: &AttributeFields, + ) -> Result<(), &'static str>; + + /// Try to translate a virtual page address to a physical page address. + /// + /// Will only succeed if there exists a valid mapping for the input page. + fn try_virt_page_addr_to_phys_page_addr( + &self, + virt_page_addr: PageAddress, + ) -> Result, &'static str>; + + /// Try to get the attributes of a page. + /// + /// Will only succeed if there exists a valid mapping for the input page. + fn try_page_attributes( + &self, + virt_page_addr: PageAddress, + ) -> Result; + + /// Try to translate a virtual address to a physical address. + /// + /// Will only succeed if there exists a valid mapping for the input address. + fn try_virt_addr_to_phys_addr( + &self, + virt_addr: Address, + ) -> Result, &'static str>; + } +} + +//-------------------------------------------------------------------------------------------------- +// Testing +//-------------------------------------------------------------------------------------------------- + +#[cfg(test)] +mod tests { + use super::*; + use crate::memory::mmu::{AccessPermissions, MemAttributes, PageAddress}; + use arch_translation_table::MinSizeTranslationTable; + use interface::TranslationTable; + use test_macros::kernel_test; + + /// Sanity checks for the TranslationTable implementation. + #[kernel_test] + fn translationtable_implementation_sanity() { + // This will occupy a lot of space on the stack. + let mut tables = MinSizeTranslationTable::new_for_runtime(); + + assert!(tables.init().is_ok()); + + let virt_end_exclusive_page_addr: PageAddress = PageAddress::MAX; + let virt_start_page_addr: PageAddress = + virt_end_exclusive_page_addr.checked_offset(-5).unwrap(); + + let phys_start_page_addr: PageAddress = PageAddress::from(0); + let phys_end_exclusive_page_addr: PageAddress = + phys_start_page_addr.checked_offset(5).unwrap(); + + let virt_region = MemoryRegion::new(virt_start_page_addr, virt_end_exclusive_page_addr); + let phys_region = MemoryRegion::new(phys_start_page_addr, phys_end_exclusive_page_addr); + + let attr = AttributeFields { + mem_attributes: MemAttributes::CacheableDRAM, + acc_perms: AccessPermissions::ReadWrite, + execute_never: true, + }; + + unsafe { assert_eq!(tables.map_at(&virt_region, &phys_region, &attr), Ok(())) }; + + assert_eq!( + tables.try_virt_page_addr_to_phys_page_addr(virt_start_page_addr), + Ok(phys_start_page_addr) + ); + + assert_eq!( + tables.try_page_attributes(virt_start_page_addr.checked_offset(-1).unwrap()), + Err("Page marked invalid") + ); + + assert_eq!(tables.try_page_attributes(virt_start_page_addr), Ok(attr)); + + let virt_addr = virt_start_page_addr.into_inner() + 0x100; + let phys_addr = phys_start_page_addr.into_inner() + 0x100; + assert_eq!(tables.try_virt_addr_to_phys_addr(virt_addr), Ok(phys_addr)); + } +} diff --git a/18_backtrace/kernel/src/memory/mmu/types.rs b/18_backtrace/kernel/src/memory/mmu/types.rs new file mode 100644 index 00000000..85c852b3 --- /dev/null +++ b/18_backtrace/kernel/src/memory/mmu/types.rs @@ -0,0 +1,378 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2020-2022 Andre Richter + +//! Memory Management Unit types. + +use crate::{ + bsp, common, + memory::{Address, AddressType, Physical}, +}; +use core::{convert::From, iter::Step, num::NonZeroUsize, ops::Range}; + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +/// A wrapper type around [Address] that ensures page alignment. +#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)] +pub struct PageAddress { + inner: Address, +} + +/// A type that describes a region of memory in quantities of pages. +#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)] +pub struct MemoryRegion { + start: PageAddress, + end_exclusive: PageAddress, +} + +/// Architecture agnostic memory attributes. +#[allow(missing_docs)] +#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)] +pub enum MemAttributes { + CacheableDRAM, + Device, +} + +/// Architecture agnostic access permissions. +#[allow(missing_docs)] +#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)] +pub enum AccessPermissions { + ReadOnly, + ReadWrite, +} + +/// Collection of memory attributes. +#[allow(missing_docs)] +#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)] +pub struct AttributeFields { + pub mem_attributes: MemAttributes, + pub acc_perms: AccessPermissions, + pub execute_never: bool, +} + +/// An MMIO descriptor for use in device drivers. +#[derive(Copy, Clone)] +pub struct MMIODescriptor { + start_addr: Address, + end_addr_exclusive: Address, +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +//------------------------------------------------------------------------------ +// PageAddress +//------------------------------------------------------------------------------ +impl PageAddress { + /// The largest value that can be represented by this type. + pub const MAX: Self = PageAddress { + inner: Address::new(usize::MAX).align_down_page(), + }; + + /// Unwraps the value. + pub fn into_inner(self) -> Address { + self.inner + } + + /// Calculates the offset from the page address. + /// + /// `count` is in units of [PageAddress]. For example, a count of 2 means `result = self + 2 * + /// page_size`. + pub fn checked_offset(self, count: isize) -> Option { + if count == 0 { + return Some(self); + } + + let delta = count + .unsigned_abs() + .checked_mul(bsp::memory::mmu::KernelGranule::SIZE)?; + let result = if count.is_positive() { + self.inner.as_usize().checked_add(delta)? + } else { + self.inner.as_usize().checked_sub(delta)? + }; + + Some(Self { + inner: Address::new(result), + }) + } +} + +impl From for PageAddress { + fn from(addr: usize) -> Self { + assert!( + common::is_aligned(addr, bsp::memory::mmu::KernelGranule::SIZE), + "Input usize not page aligned" + ); + + Self { + inner: Address::new(addr), + } + } +} + +impl From> for PageAddress { + fn from(addr: Address) -> Self { + assert!(addr.is_page_aligned(), "Input Address not page aligned"); + + Self { inner: addr } + } +} + +impl Step for PageAddress { + fn steps_between(start: &Self, end: &Self) -> Option { + if start > end { + return None; + } + + // Since start <= end, do unchecked arithmetic. + Some( + (end.inner.as_usize() - start.inner.as_usize()) + >> bsp::memory::mmu::KernelGranule::SHIFT, + ) + } + + fn forward_checked(start: Self, count: usize) -> Option { + start.checked_offset(count as isize) + } + + fn backward_checked(start: Self, count: usize) -> Option { + start.checked_offset(-(count as isize)) + } +} + +//------------------------------------------------------------------------------ +// MemoryRegion +//------------------------------------------------------------------------------ +impl MemoryRegion { + /// Create an instance. + pub fn new(start: PageAddress, end_exclusive: PageAddress) -> Self { + assert!(start <= end_exclusive); + + Self { + start, + end_exclusive, + } + } + + fn as_range(&self) -> Range> { + self.into_iter() + } + + /// Returns the start page address. + pub fn start_page_addr(&self) -> PageAddress { + self.start + } + + /// Returns the start address. + pub fn start_addr(&self) -> Address { + self.start.into_inner() + } + + /// Returns the exclusive end page address. + pub fn end_exclusive_page_addr(&self) -> PageAddress { + self.end_exclusive + } + + /// Returns the exclusive end page address. + pub fn end_inclusive_page_addr(&self) -> PageAddress { + self.end_exclusive.checked_offset(-1).unwrap() + } + + /// Checks if self contains an address. + pub fn contains(&self, addr: Address) -> bool { + let page_addr = PageAddress::from(addr.align_down_page()); + self.as_range().contains(&page_addr) + } + + /// Checks if there is an overlap with another memory region. + pub fn overlaps(&self, other_region: &Self) -> bool { + let self_range = self.as_range(); + + self_range.contains(&other_region.start_page_addr()) + || self_range.contains(&other_region.end_inclusive_page_addr()) + } + + /// Returns the number of pages contained in this region. + pub fn num_pages(&self) -> usize { + PageAddress::steps_between(&self.start, &self.end_exclusive).unwrap() + } + + /// Returns the size in bytes of this region. + pub fn size(&self) -> usize { + // Invariant: start <= end_exclusive, so do unchecked arithmetic. + let end_exclusive = self.end_exclusive.into_inner().as_usize(); + let start = self.start.into_inner().as_usize(); + + end_exclusive - start + } + + /// Splits the MemoryRegion like: + /// + /// -------------------------------------------------------------------------------- + /// | | | | | | | | | | | | | | | | | | | + /// -------------------------------------------------------------------------------- + /// ^ ^ ^ + /// | | | + /// left_start left_end_exclusive | + /// | + /// ^ | + /// | | + /// right_start right_end_exclusive + /// + /// Left region is returned to the caller. Right region is the new region for this struct. + pub fn take_first_n_pages(&mut self, num_pages: NonZeroUsize) -> Result { + let count: usize = num_pages.into(); + + let left_end_exclusive = self.start.checked_offset(count as isize); + let left_end_exclusive = match left_end_exclusive { + None => return Err("Overflow while calculating left_end_exclusive"), + Some(x) => x, + }; + + if left_end_exclusive > self.end_exclusive { + return Err("Not enough free pages"); + } + + let allocation = Self { + start: self.start, + end_exclusive: left_end_exclusive, + }; + self.start = left_end_exclusive; + + Ok(allocation) + } +} + +impl IntoIterator for MemoryRegion { + type Item = PageAddress; + type IntoIter = Range; + + fn into_iter(self) -> Self::IntoIter { + Range { + start: self.start, + end: self.end_exclusive, + } + } +} + +impl From for MemoryRegion { + fn from(desc: MMIODescriptor) -> Self { + let start = PageAddress::from(desc.start_addr.align_down_page()); + let end_exclusive = PageAddress::from(desc.end_addr_exclusive().align_up_page()); + + Self { + start, + end_exclusive, + } + } +} + +//------------------------------------------------------------------------------ +// MMIODescriptor +//------------------------------------------------------------------------------ + +impl MMIODescriptor { + /// Create an instance. + pub const fn new(start_addr: Address, size: usize) -> Self { + assert!(size > 0); + let end_addr_exclusive = Address::new(start_addr.as_usize() + size); + + Self { + start_addr, + end_addr_exclusive, + } + } + + /// Return the start address. + pub const fn start_addr(&self) -> Address { + self.start_addr + } + + /// Return the exclusive end address. + pub fn end_addr_exclusive(&self) -> Address { + self.end_addr_exclusive + } +} + +//-------------------------------------------------------------------------------------------------- +// Testing +//-------------------------------------------------------------------------------------------------- + +#[cfg(test)] +mod tests { + use super::*; + use crate::memory::Virtual; + use test_macros::kernel_test; + + /// Sanity of [PageAddress] methods. + #[kernel_test] + fn pageaddress_type_method_sanity() { + let page_addr: PageAddress = + PageAddress::from(bsp::memory::mmu::KernelGranule::SIZE * 2); + + assert_eq!( + page_addr.checked_offset(-2), + Some(PageAddress::::from(0)) + ); + + assert_eq!( + page_addr.checked_offset(2), + Some(PageAddress::::from( + bsp::memory::mmu::KernelGranule::SIZE * 4 + )) + ); + + assert_eq!( + PageAddress::::from(0).checked_offset(0), + Some(PageAddress::::from(0)) + ); + assert_eq!(PageAddress::::from(0).checked_offset(-1), None); + + let max_page_addr = Address::::new(usize::MAX).align_down_page(); + assert_eq!( + PageAddress::::from(max_page_addr).checked_offset(1), + None + ); + + let zero = PageAddress::::from(0); + let three = PageAddress::::from(bsp::memory::mmu::KernelGranule::SIZE * 3); + assert_eq!(PageAddress::steps_between(&zero, &three), Some(3)); + } + + /// Sanity of [MemoryRegion] methods. + #[kernel_test] + fn memoryregion_type_method_sanity() { + let zero = PageAddress::::from(0); + let zero_region = MemoryRegion::new(zero, zero); + assert_eq!(zero_region.num_pages(), 0); + assert_eq!(zero_region.size(), 0); + + let one = PageAddress::::from(bsp::memory::mmu::KernelGranule::SIZE); + let one_region = MemoryRegion::new(zero, one); + assert_eq!(one_region.num_pages(), 1); + assert_eq!(one_region.size(), bsp::memory::mmu::KernelGranule::SIZE); + + let three = PageAddress::::from(bsp::memory::mmu::KernelGranule::SIZE * 3); + let mut three_region = MemoryRegion::new(zero, three); + assert!(three_region.contains(zero.into_inner())); + assert!(!three_region.contains(three.into_inner())); + assert!(three_region.overlaps(&one_region)); + + let allocation = three_region + .take_first_n_pages(NonZeroUsize::new(2).unwrap()) + .unwrap(); + assert_eq!(allocation.num_pages(), 2); + assert_eq!(three_region.num_pages(), 1); + + for (i, alloc) in allocation.into_iter().enumerate() { + assert_eq!( + alloc.into_inner().as_usize(), + i * bsp::memory::mmu::KernelGranule::SIZE + ); + } + } +} diff --git a/18_backtrace/kernel/src/panic_wait.rs b/18_backtrace/kernel/src/panic_wait.rs new file mode 100644 index 00000000..1b67c533 --- /dev/null +++ b/18_backtrace/kernel/src/panic_wait.rs @@ -0,0 +1,106 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2018-2022 Andre Richter + +//! A panic handler that infinitely waits. + +use crate::{backtrace, bsp, cpu, exception}; +use core::{fmt, panic::PanicInfo}; + +//-------------------------------------------------------------------------------------------------- +// Private Code +//-------------------------------------------------------------------------------------------------- + +fn _panic_print(args: fmt::Arguments) { + use fmt::Write; + + unsafe { bsp::console::panic_console_out().write_fmt(args).unwrap() }; +} + +/// The point of exit for `libkernel`. +/// +/// It is linked weakly, so that the integration tests can overload its standard behavior. +#[linkage = "weak"] +#[no_mangle] +fn _panic_exit() -> ! { + #[cfg(not(feature = "test_build"))] + { + cpu::wait_forever() + } + + #[cfg(feature = "test_build")] + { + cpu::qemu_exit_failure() + } +} + +/// Prints with a newline - only use from the panic handler. +/// +/// Carbon copy from +#[macro_export] +macro_rules! panic_println { + ($($arg:tt)*) => ({ + _panic_print(format_args_nl!($($arg)*)); + }) +} + +/// Stop immediately if called a second time. +/// +/// # Note +/// +/// Using atomics here relieves us from needing to use `unsafe` for the static variable. +/// +/// On `AArch64`, which is the only implemented architecture at the time of writing this, +/// [`AtomicBool::load`] and [`AtomicBool::store`] are lowered to ordinary load and store +/// instructions. They are therefore safe to use even with MMU + caching deactivated. +/// +/// [`AtomicBool::load`]: core::sync::atomic::AtomicBool::load +/// [`AtomicBool::store`]: core::sync::atomic::AtomicBool::store +fn panic_prevent_reenter() { + use core::sync::atomic::{AtomicBool, Ordering}; + + #[cfg(not(target_arch = "aarch64"))] + compile_error!("Add the target_arch to above's check if the following code is safe to use"); + + static PANIC_IN_PROGRESS: AtomicBool = AtomicBool::new(false); + + if !PANIC_IN_PROGRESS.load(Ordering::Relaxed) { + PANIC_IN_PROGRESS.store(true, Ordering::Relaxed); + + return; + } + + _panic_exit() +} + +#[panic_handler] +fn panic(info: &PanicInfo) -> ! { + use crate::time::interface::TimeManager; + + unsafe { exception::asynchronous::local_irq_mask() }; + + // Protect against panic infinite loops if any of the following code panics itself. + panic_prevent_reenter(); + + let timestamp = crate::time::time_manager().uptime(); + let (location, line, column) = match info.location() { + Some(loc) => (loc.file(), loc.line(), loc.column()), + _ => ("???", 0, 0), + }; + + panic_println!( + "[ {:>3}.{:06}] Kernel panic!\n\n\ + Panic location:\n File '{}', line {}, column {}\n\n\ + {}\n\n\ + {}", + timestamp.as_secs(), + timestamp.subsec_micros(), + location, + line, + column, + info.message().unwrap_or(&format_args!("")), + backtrace::Backtrace + ); + + _panic_exit() +} diff --git a/18_backtrace/kernel/src/print.rs b/18_backtrace/kernel/src/print.rs new file mode 100644 index 00000000..9ec13a28 --- /dev/null +++ b/18_backtrace/kernel/src/print.rs @@ -0,0 +1,94 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2018-2022 Andre Richter + +//! Printing. + +use crate::{bsp, console}; +use core::fmt; + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +#[doc(hidden)] +pub fn _print(args: fmt::Arguments) { + use console::interface::Write; + + bsp::console::console().write_fmt(args).unwrap(); +} + +/// Prints without a newline. +/// +/// Carbon copy from +#[macro_export] +macro_rules! print { + ($($arg:tt)*) => ($crate::print::_print(format_args!($($arg)*))); +} + +/// Prints with a newline. +/// +/// Carbon copy from +#[macro_export] +macro_rules! println { + () => ($crate::print!("\n")); + ($($arg:tt)*) => ({ + $crate::print::_print(format_args_nl!($($arg)*)); + }) +} + +/// Prints an info, with a newline. +#[macro_export] +macro_rules! info { + ($string:expr) => ({ + use $crate::time::interface::TimeManager; + + let timestamp = $crate::time::time_manager().uptime(); + + $crate::print::_print(format_args_nl!( + concat!("[ {:>3}.{:06}] ", $string), + timestamp.as_secs(), + timestamp.subsec_micros(), + )); + }); + ($format_string:expr, $($arg:tt)*) => ({ + use $crate::time::interface::TimeManager; + + let timestamp = $crate::time::time_manager().uptime(); + + $crate::print::_print(format_args_nl!( + concat!("[ {:>3}.{:06}] ", $format_string), + timestamp.as_secs(), + timestamp.subsec_micros(), + $($arg)* + )); + }) +} + +/// Prints a warning, with a newline. +#[macro_export] +macro_rules! warn { + ($string:expr) => ({ + use $crate::time::interface::TimeManager; + + let timestamp = $crate::time::time_manager().uptime(); + + $crate::print::_print(format_args_nl!( + concat!("[W {:>3}.{:06}] ", $string), + timestamp.as_secs(), + timestamp.subsec_micros(), + )); + }); + ($format_string:expr, $($arg:tt)*) => ({ + use $crate::time::interface::TimeManager; + + let timestamp = $crate::time::time_manager().uptime(); + + $crate::print::_print(format_args_nl!( + concat!("[W {:>3}.{:06}] ", $format_string), + timestamp.as_secs(), + timestamp.subsec_micros(), + $($arg)* + )); + }) +} diff --git a/18_backtrace/kernel/src/state.rs b/18_backtrace/kernel/src/state.rs new file mode 100644 index 00000000..0af3688c --- /dev/null +++ b/18_backtrace/kernel/src/state.rs @@ -0,0 +1,92 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2020-2022 Andre Richter + +//! State information about the kernel itself. + +use core::sync::atomic::{AtomicU8, Ordering}; + +//-------------------------------------------------------------------------------------------------- +// Private Definitions +//-------------------------------------------------------------------------------------------------- + +/// Different stages in the kernel execution. +#[derive(Copy, Clone, Eq, PartialEq)] +enum State { + /// The kernel starts booting in this state. + Init, + + /// The kernel transitions to this state when jumping to `kernel_main()` (at the end of + /// `kernel_init()`, after all init calls are done). + SingleCoreMain, + + /// The kernel transitions to this state when it boots the secondary cores, aka switches + /// exectution mode to symmetric multiprocessing (SMP). + MultiCoreMain, +} + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +/// Maintains the kernel state and state transitions. +pub struct StateManager(AtomicU8); + +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +static STATE_MANAGER: StateManager = StateManager::new(); + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +/// Return a reference to the global StateManager. +pub fn state_manager() -> &'static StateManager { + &STATE_MANAGER +} + +impl StateManager { + const INIT: u8 = 0; + const SINGLE_CORE_MAIN: u8 = 1; + const MULTI_CORE_MAIN: u8 = 2; + + /// Create a new instance. + pub const fn new() -> Self { + Self(AtomicU8::new(Self::INIT)) + } + + /// Return the current state. + fn state(&self) -> State { + let state = self.0.load(Ordering::Acquire); + + match state { + Self::INIT => State::Init, + Self::SINGLE_CORE_MAIN => State::SingleCoreMain, + Self::MULTI_CORE_MAIN => State::MultiCoreMain, + _ => panic!("Invalid KERNEL_STATE"), + } + } + + /// Return if the kernel is init state. + pub fn is_init(&self) -> bool { + self.state() == State::Init + } + + /// Transition from Init to SingleCoreMain. + pub fn transition_to_single_core_main(&self) { + if self + .0 + .compare_exchange( + Self::INIT, + Self::SINGLE_CORE_MAIN, + Ordering::Acquire, + Ordering::Relaxed, + ) + .is_err() + { + panic!("transition_to_single_core_main() called while state != Init"); + } + } +} diff --git a/18_backtrace/kernel/src/symbols.rs b/18_backtrace/kernel/src/symbols.rs new file mode 100644 index 00000000..22001389 --- /dev/null +++ b/18_backtrace/kernel/src/symbols.rs @@ -0,0 +1,87 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2022 Andre Richter + +//! Debug symbol support. + +use crate::memory::{Address, Virtual}; +use core::{cell::UnsafeCell, slice}; +use debug_symbol_types::Symbol; + +//-------------------------------------------------------------------------------------------------- +// Private Definitions +//-------------------------------------------------------------------------------------------------- + +// Symbol from the linker script. +extern "Rust" { + static __kernel_symbols_start: UnsafeCell<()>; +} + +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +/// This will be patched to the correct value by the "kernel symbols tool" after linking. This given +/// value here is just a (safe) dummy. +#[no_mangle] +static NUM_KERNEL_SYMBOLS: u64 = 0; + +//-------------------------------------------------------------------------------------------------- +// Private Code +//-------------------------------------------------------------------------------------------------- + +fn kernel_symbol_section_virt_start_addr() -> Address { + Address::new(unsafe { __kernel_symbols_start.get() as usize }) +} + +fn kernel_symbols_slice() -> &'static [Symbol] { + let ptr = kernel_symbol_section_virt_start_addr().as_usize() as *const Symbol; + + unsafe { + let num = core::ptr::read_volatile(&NUM_KERNEL_SYMBOLS as *const u64) as usize; + slice::from_raw_parts(ptr, num) + } +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +/// Retrieve the symbol corresponding to a virtual address, if any. +pub fn lookup_symbol(addr: Address) -> Option<&'static Symbol> { + for i in kernel_symbols_slice() { + if i.contains(addr.as_usize()) { + return Some(i); + } + } + + None +} + +//-------------------------------------------------------------------------------------------------- +// Testing +//-------------------------------------------------------------------------------------------------- + +#[cfg(test)] +mod tests { + use super::*; + use test_macros::kernel_test; + + /// Sanity of symbols module. + #[kernel_test] + fn symbols_sanity() { + let first_sym = lookup_symbol(Address::new( + crate::common::is_aligned as *const usize as usize, + )) + .unwrap() + .name(); + + assert_eq!(first_sym, "libkernel::common::is_aligned"); + + let second_sym = lookup_symbol(Address::new(crate::version as *const usize as usize)) + .unwrap() + .name(); + + assert_eq!(second_sym, "libkernel::version"); + } +} diff --git a/18_backtrace/kernel/src/synchronization.rs b/18_backtrace/kernel/src/synchronization.rs new file mode 100644 index 00000000..4b4c4c3f --- /dev/null +++ b/18_backtrace/kernel/src/synchronization.rs @@ -0,0 +1,159 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2020-2022 Andre Richter + +//! Synchronization primitives. +//! +//! # Resources +//! +//! - +//! - +//! - + +use core::cell::UnsafeCell; + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +/// Synchronization interfaces. +pub mod interface { + + /// Any object implementing this trait guarantees exclusive access to the data wrapped within + /// the Mutex for the duration of the provided closure. + pub trait Mutex { + /// The type of the data that is wrapped by this mutex. + type Data; + + /// Locks the mutex and grants the closure temporary mutable access to the wrapped data. + fn lock(&self, f: impl FnOnce(&mut Self::Data) -> R) -> R; + } + + /// A reader-writer exclusion type. + /// + /// The implementing object allows either a number of readers or at most one writer at any point + /// in time. + pub trait ReadWriteEx { + /// The type of encapsulated data. + type Data; + + /// Grants temporary mutable access to the encapsulated data. + fn write(&self, f: impl FnOnce(&mut Self::Data) -> R) -> R; + + /// Grants temporary immutable access to the encapsulated data. + fn read(&self, f: impl FnOnce(&Self::Data) -> R) -> R; + } +} + +/// A pseudo-lock for teaching purposes. +/// +/// In contrast to a real Mutex implementation, does not protect against concurrent access from +/// other cores to the contained data. This part is preserved for later lessons. +/// +/// The lock will only be used as long as it is safe to do so, i.e. as long as the kernel is +/// executing on a single core. +pub struct IRQSafeNullLock +where + T: ?Sized, +{ + data: UnsafeCell, +} + +/// A pseudo-lock that is RW during the single-core kernel init phase and RO afterwards. +/// +/// Intended to encapsulate data that is populated during kernel init when no concurrency exists. +pub struct InitStateLock +where + T: ?Sized, +{ + data: UnsafeCell, +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +unsafe impl Send for IRQSafeNullLock where T: ?Sized + Send {} +unsafe impl Sync for IRQSafeNullLock where T: ?Sized + Send {} + +impl IRQSafeNullLock { + /// Create an instance. + pub const fn new(data: T) -> Self { + Self { + data: UnsafeCell::new(data), + } + } +} + +unsafe impl Send for InitStateLock where T: ?Sized + Send {} +unsafe impl Sync for InitStateLock where T: ?Sized + Send {} + +impl InitStateLock { + /// Create an instance. + pub const fn new(data: T) -> Self { + Self { + data: UnsafeCell::new(data), + } + } +} + +//------------------------------------------------------------------------------ +// OS Interface Code +//------------------------------------------------------------------------------ +use crate::{exception, state}; + +impl interface::Mutex for IRQSafeNullLock { + type Data = T; + + fn lock(&self, f: impl FnOnce(&mut Self::Data) -> R) -> R { + // In a real lock, there would be code encapsulating this line that ensures that this + // mutable reference will ever only be given out once at a time. + let data = unsafe { &mut *self.data.get() }; + + // Execute the closure while IRQs are masked. + exception::asynchronous::exec_with_irq_masked(|| f(data)) + } +} + +impl interface::ReadWriteEx for InitStateLock { + type Data = T; + + fn write(&self, f: impl FnOnce(&mut Self::Data) -> R) -> R { + assert!( + state::state_manager().is_init(), + "InitStateLock::write called after kernel init phase" + ); + assert!( + !exception::asynchronous::is_local_irq_masked(), + "InitStateLock::write called with IRQs unmasked" + ); + + let data = unsafe { &mut *self.data.get() }; + + f(data) + } + + fn read(&self, f: impl FnOnce(&Self::Data) -> R) -> R { + let data = unsafe { &*self.data.get() }; + + f(data) + } +} + +//-------------------------------------------------------------------------------------------------- +// Testing +//-------------------------------------------------------------------------------------------------- + +#[cfg(test)] +mod tests { + use super::*; + use test_macros::kernel_test; + + /// InitStateLock must be transparent. + #[kernel_test] + fn init_state_lock_is_transparent() { + use core::mem::size_of; + + assert_eq!(size_of::>(), size_of::()); + } +} diff --git a/18_backtrace/kernel/src/time.rs b/18_backtrace/kernel/src/time.rs new file mode 100644 index 00000000..6d92b196 --- /dev/null +++ b/18_backtrace/kernel/src/time.rs @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2020-2022 Andre Richter + +//! Timer primitives. + +#[cfg(target_arch = "aarch64")] +#[path = "_arch/aarch64/time.rs"] +mod arch_time; + +//-------------------------------------------------------------------------------------------------- +// Architectural Public Reexports +//-------------------------------------------------------------------------------------------------- +pub use arch_time::time_manager; + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +/// Timekeeping interfaces. +pub mod interface { + use core::time::Duration; + + /// Time management functions. + pub trait TimeManager { + /// The timer's resolution. + fn resolution(&self) -> Duration; + + /// The uptime since power-on of the device. + /// + /// This includes time consumed by firmware and bootloaders. + fn uptime(&self) -> Duration; + + /// Spin for a given duration. + fn spin_for(&self, duration: Duration); + } +} diff --git a/18_backtrace/kernel/tests/00_console_sanity.rb b/18_backtrace/kernel/tests/00_console_sanity.rb new file mode 100644 index 00000000..4dde5576 --- /dev/null +++ b/18_backtrace/kernel/tests/00_console_sanity.rb @@ -0,0 +1,48 @@ +# frozen_string_literal: true + +# SPDX-License-Identifier: MIT OR Apache-2.0 +# +# Copyright (c) 2019-2022 Andre Richter + +require 'console_io_test' + +# Verify sending and receiving works as expected. +class TxRxHandshakeTest < SubtestBase + def name + 'Transmit and Receive handshake' + end + + def run(qemu_out, qemu_in) + qemu_in.write_nonblock('ABC') + expect_or_raise(qemu_out, 'OK1234') + end +end + +# Check for correct TX statistics implementation. Depends on test 1 being run first. +class TxStatisticsTest < SubtestBase + def name + 'Transmit statistics' + end + + def run(qemu_out, _qemu_in) + expect_or_raise(qemu_out, '6') + end +end + +# Check for correct RX statistics implementation. Depends on test 1 being run first. +class RxStatisticsTest < SubtestBase + def name + 'Receive statistics' + end + + def run(qemu_out, _qemu_in) + expect_or_raise(qemu_out, '3') + end +end + +##-------------------------------------------------------------------------------------------------- +## Test registration +##-------------------------------------------------------------------------------------------------- +def subtest_collection + [TxRxHandshakeTest.new, TxStatisticsTest.new, RxStatisticsTest.new] +end diff --git a/18_backtrace/kernel/tests/00_console_sanity.rs b/18_backtrace/kernel/tests/00_console_sanity.rs new file mode 100644 index 00000000..6595aac1 --- /dev/null +++ b/18_backtrace/kernel/tests/00_console_sanity.rs @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2019-2022 Andre Richter + +//! Console sanity tests - RX, TX and statistics. + +#![feature(format_args_nl)] +#![no_main] +#![no_std] + +/// Console tests should time out on the I/O harness in case of panic. +mod panic_wait_forever; + +use libkernel::{bsp, console, cpu, exception, memory, print}; + +#[no_mangle] +unsafe fn kernel_init() -> ! { + use bsp::console::console; + use console::interface::*; + + exception::handling_init(); + memory::mmu::post_enable_init(); + bsp::console::qemu_bring_up_console(); + + // Handshake + assert_eq!(console().read_char(), 'A'); + assert_eq!(console().read_char(), 'B'); + assert_eq!(console().read_char(), 'C'); + print!("OK1234"); + + // 6 + print!("{}", console().chars_written()); + + // 3 + print!("{}", console().chars_read()); + + // The QEMU process running this test will be closed by the I/O test harness. + cpu::wait_forever(); +} diff --git a/18_backtrace/kernel/tests/01_timer_sanity.rs b/18_backtrace/kernel/tests/01_timer_sanity.rs new file mode 100644 index 00000000..9b2b228d --- /dev/null +++ b/18_backtrace/kernel/tests/01_timer_sanity.rs @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2019-2022 Andre Richter + +//! Timer sanity tests. + +#![feature(custom_test_frameworks)] +#![no_main] +#![no_std] +#![reexport_test_harness_main = "test_main"] +#![test_runner(libkernel::test_runner)] + +use core::time::Duration; +use libkernel::{bsp, cpu, exception, memory, time, time::interface::TimeManager}; +use test_macros::kernel_test; + +#[no_mangle] +unsafe fn kernel_init() -> ! { + exception::handling_init(); + memory::mmu::post_enable_init(); + bsp::console::qemu_bring_up_console(); + + // Depending on CPU arch, some timer bring-up code could go here. Not needed for the RPi. + + test_main(); + + cpu::qemu_exit_success() +} + +/// Simple check that the timer is running. +#[kernel_test] +fn timer_is_counting() { + assert!(time::time_manager().uptime().as_nanos() > 0) +} + +/// Timer resolution must be sufficient. +#[kernel_test] +fn timer_resolution_is_sufficient() { + assert!(time::time_manager().resolution().as_nanos() < 100) +} + +/// Sanity check spin_for() implementation. +#[kernel_test] +fn spin_accuracy_check_1_second() { + let t1 = time::time_manager().uptime(); + time::time_manager().spin_for(Duration::from_secs(1)); + let t2 = time::time_manager().uptime(); + + assert_eq!((t2 - t1).as_secs(), 1) +} diff --git a/18_backtrace/kernel/tests/02_exception_sync_page_fault.rs b/18_backtrace/kernel/tests/02_exception_sync_page_fault.rs new file mode 100644 index 00000000..0d2a1e63 --- /dev/null +++ b/18_backtrace/kernel/tests/02_exception_sync_page_fault.rs @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2019-2022 Andre Richter + +//! Page faults must result in synchronous exceptions. + +#![feature(format_args_nl)] +#![no_main] +#![no_std] + +/// Overwrites libkernel's `panic_wait::_panic_exit()` so that it returns a "success" code. +/// +/// In this test, reaching the panic is a success, because it is called from the synchronous +/// exception handler, which is what this test wants to achieve. +/// +/// It also means that this integration test can not use any other code that calls panic!() directly +/// or indirectly. +mod panic_exit_success; + +use libkernel::{bsp, cpu, exception, info, memory, println}; + +#[no_mangle] +unsafe fn kernel_init() -> ! { + exception::handling_init(); + memory::mmu::post_enable_init(); + bsp::console::qemu_bring_up_console(); + + // This line will be printed as the test header. + println!("Testing synchronous exception handling by causing a page fault"); + + info!("Writing to bottom of address space to address 1 GiB..."); + let big_addr: u64 = 1024 * 1024 * 1024; + core::ptr::read_volatile(big_addr as *mut u64); + + // If execution reaches here, the memory access above did not cause a page fault exception. + cpu::qemu_exit_failure() +} diff --git a/18_backtrace/kernel/tests/03_exception_restore_sanity.rb b/18_backtrace/kernel/tests/03_exception_restore_sanity.rb new file mode 100644 index 00000000..5f52e0c7 --- /dev/null +++ b/18_backtrace/kernel/tests/03_exception_restore_sanity.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +# SPDX-License-Identifier: MIT OR Apache-2.0 +# +# Copyright (c) 2022 Andre Richter + +require 'console_io_test' + +# Verify that exception restore works. +class ExceptionRestoreTest < SubtestBase + def name + 'Exception restore' + end + + def run(qemu_out, _qemu_in) + expect_or_raise(qemu_out, 'Back from system call!') + end +end + +##-------------------------------------------------------------------------------------------------- +## Test registration +##-------------------------------------------------------------------------------------------------- +def subtest_collection + [ExceptionRestoreTest.new] +end diff --git a/18_backtrace/kernel/tests/03_exception_restore_sanity.rs b/18_backtrace/kernel/tests/03_exception_restore_sanity.rs new file mode 100644 index 00000000..983d488f --- /dev/null +++ b/18_backtrace/kernel/tests/03_exception_restore_sanity.rs @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2022 Andre Richter + +//! A simple sanity test to see if exception restore code works. + +#![feature(format_args_nl)] +#![no_main] +#![no_std] + +/// Console tests should time out on the I/O harness in case of panic. +mod panic_wait_forever; + +use core::arch::asm; +use libkernel::{bsp, cpu, exception, info, memory, println}; + +#[inline(never)] +fn nested_system_call() { + #[cfg(target_arch = "aarch64")] + unsafe { + asm!("svc #0x1337", options(nomem, nostack, preserves_flags)); + } + + #[cfg(not(target_arch = "aarch64"))] + { + info!("Not supported yet"); + cpu::wait_forever(); + } +} + +#[no_mangle] +unsafe fn kernel_init() -> ! { + exception::handling_init(); + memory::mmu::post_enable_init(); + bsp::console::qemu_bring_up_console(); + + // This line will be printed as the test header. + println!("Testing exception restore"); + + info!("Making a dummy system call"); + + // Calling this inside a function indirectly tests if the link register is restored properly. + nested_system_call(); + + info!("Back from system call!"); + + // The QEMU process running this test will be closed by the I/O test harness. + cpu::wait_forever(); +} diff --git a/18_backtrace/kernel/tests/04_exception_irq_sanity.rs b/18_backtrace/kernel/tests/04_exception_irq_sanity.rs new file mode 100644 index 00000000..9030424d --- /dev/null +++ b/18_backtrace/kernel/tests/04_exception_irq_sanity.rs @@ -0,0 +1,67 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2020-2022 Andre Richter + +//! IRQ handling sanity tests. + +#![feature(custom_test_frameworks)] +#![no_main] +#![no_std] +#![reexport_test_harness_main = "test_main"] +#![test_runner(libkernel::test_runner)] + +use libkernel::{bsp, cpu, exception, memory}; +use test_macros::kernel_test; + +#[no_mangle] +unsafe fn kernel_init() -> ! { + memory::mmu::post_enable_init(); + bsp::console::qemu_bring_up_console(); + + exception::handling_init(); + exception::asynchronous::local_irq_unmask(); + + test_main(); + + cpu::qemu_exit_success() +} + +/// Check that IRQ masking works. +#[kernel_test] +fn local_irq_mask_works() { + // Precondition: IRQs are unmasked. + assert!(exception::asynchronous::is_local_irq_masked()); + + unsafe { exception::asynchronous::local_irq_mask() }; + assert!(!exception::asynchronous::is_local_irq_masked()); + + // Restore earlier state. + unsafe { exception::asynchronous::local_irq_unmask() }; +} + +/// Check that IRQ unmasking works. +#[kernel_test] +fn local_irq_unmask_works() { + // Precondition: IRQs are masked. + unsafe { exception::asynchronous::local_irq_mask() }; + assert!(!exception::asynchronous::is_local_irq_masked()); + + unsafe { exception::asynchronous::local_irq_unmask() }; + assert!(exception::asynchronous::is_local_irq_masked()); +} + +/// Check that IRQ mask save is saving "something". +#[kernel_test] +fn local_irq_mask_save_works() { + // Precondition: IRQs are unmasked. + assert!(exception::asynchronous::is_local_irq_masked()); + + let first = unsafe { exception::asynchronous::local_irq_mask_save() }; + assert!(!exception::asynchronous::is_local_irq_masked()); + + let second = unsafe { exception::asynchronous::local_irq_mask_save() }; + assert_ne!(first, second); + + unsafe { exception::asynchronous::local_irq_restore(first) }; + assert!(exception::asynchronous::is_local_irq_masked()); +} diff --git a/18_backtrace/kernel/tests/05_backtrace_sanity.rb b/18_backtrace/kernel/tests/05_backtrace_sanity.rb new file mode 100644 index 00000000..5650f97c --- /dev/null +++ b/18_backtrace/kernel/tests/05_backtrace_sanity.rb @@ -0,0 +1,39 @@ +# frozen_string_literal: true + +# SPDX-License-Identifier: MIT OR Apache-2.0 +# +# Copyright (c) 2022 Andre Richter + +require 'console_io_test' + +# Verify that panic produces a backtrace. +class PanicBacktraceTest < SubtestBase + def name + 'Panic produces backtrace' + end + + def run(qemu_out, _qemu_in) + expect_or_raise(qemu_out, 'Kernel panic!') + expect_or_raise(qemu_out, 'Backtrace:') + end +end + +# Verify backtrace correctness. +class BacktraceCorrectnessTest < SubtestBase + def name + 'Backtrace is correct' + end + + def run(qemu_out, _qemu_in) + expect_or_raise(qemu_out, '| core::panicking::panic') + expect_or_raise(qemu_out, '| _05_backtrace_sanity::nested') + expect_or_raise(qemu_out, '| kernel_init') + end +end + +##-------------------------------------------------------------------------------------------------- +## Test registration +##-------------------------------------------------------------------------------------------------- +def subtest_collection + [PanicBacktraceTest.new, BacktraceCorrectnessTest.new] +end diff --git a/18_backtrace/kernel/tests/05_backtrace_sanity.rs b/18_backtrace/kernel/tests/05_backtrace_sanity.rs new file mode 100644 index 00000000..24229f95 --- /dev/null +++ b/18_backtrace/kernel/tests/05_backtrace_sanity.rs @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2022 Andre Richter + +//! Test if backtracing code detects an invalid frame pointer. + +#![feature(format_args_nl)] +#![no_main] +#![no_std] + +/// Console tests should time out on the I/O harness in case of panic. +mod panic_wait_forever; + +use libkernel::{bsp, cpu, exception, memory}; + +#[inline(never)] +fn nested() { + panic!() +} + +#[no_mangle] +unsafe fn kernel_init() -> ! { + exception::handling_init(); + memory::mmu::post_enable_init(); + bsp::console::qemu_bring_up_console(); + + nested(); + + // The QEMU process running this test will be closed by the I/O test harness. + cpu::wait_forever() +} diff --git a/18_backtrace/kernel/tests/06_backtrace_invalid_frame.rb b/18_backtrace/kernel/tests/06_backtrace_invalid_frame.rb new file mode 100644 index 00000000..7601cf97 --- /dev/null +++ b/18_backtrace/kernel/tests/06_backtrace_invalid_frame.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +# SPDX-License-Identifier: MIT OR Apache-2.0 +# +# Copyright (c) 2022 Andre Richter + +require 'console_io_test' + +# Test detection of invalid frame pointers. +class InvalidFramePointerTest < SubtestBase + def name + 'Detect invalid frame pointer' + end + + def run(qemu_out, _qemu_in) + expect_or_raise(qemu_out, + /Encountered invalid frame pointer \(.*\) during backtrace/) + end +end + +##-------------------------------------------------------------------------------------------------- +## Test registration +##-------------------------------------------------------------------------------------------------- +def subtest_collection + [InvalidFramePointerTest.new] +end diff --git a/18_backtrace/kernel/tests/06_backtrace_invalid_frame.rs b/18_backtrace/kernel/tests/06_backtrace_invalid_frame.rs new file mode 100644 index 00000000..a1874c4e --- /dev/null +++ b/18_backtrace/kernel/tests/06_backtrace_invalid_frame.rs @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2022 Andre Richter + +//! Test if backtracing code detects an invalid frame pointer. + +#![feature(format_args_nl)] +#![no_main] +#![no_std] + +/// Console tests should time out on the I/O harness in case of panic. +mod panic_wait_forever; + +use libkernel::{backtrace, bsp, cpu, exception, memory}; + +#[inline(never)] +fn nested() { + unsafe { backtrace::corrupt_previous_frame_addr() }; + + panic!() +} + +#[no_mangle] +unsafe fn kernel_init() -> ! { + exception::handling_init(); + memory::mmu::post_enable_init(); + bsp::console::qemu_bring_up_console(); + + nested(); + + // The QEMU process running this test will be closed by the I/O test harness. + cpu::wait_forever() +} diff --git a/18_backtrace/kernel/tests/07_backtrace_invalid_link.rb b/18_backtrace/kernel/tests/07_backtrace_invalid_link.rb new file mode 100644 index 00000000..0fabcf4c --- /dev/null +++ b/18_backtrace/kernel/tests/07_backtrace_invalid_link.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +# SPDX-License-Identifier: MIT OR Apache-2.0 +# +# Copyright (c) 2022 Andre Richter + +require 'console_io_test' + +# Test detection of invalid link. +class InvalidLinkTest < SubtestBase + def name + 'Detect invalid link' + end + + def run(qemu_out, _qemu_in) + expect_or_raise(qemu_out, /Link address \(.*\) is not contained in kernel .text section/) + end +end + +##-------------------------------------------------------------------------------------------------- +## Test registration +##-------------------------------------------------------------------------------------------------- +def subtest_collection + [InvalidLinkTest.new] +end diff --git a/18_backtrace/kernel/tests/07_backtrace_invalid_link.rs b/18_backtrace/kernel/tests/07_backtrace_invalid_link.rs new file mode 100644 index 00000000..a0731091 --- /dev/null +++ b/18_backtrace/kernel/tests/07_backtrace_invalid_link.rs @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2022 Andre Richter + +//! Test if backtracing code detects an invalid link. + +#![feature(format_args_nl)] +#![no_main] +#![no_std] + +/// Console tests should time out on the I/O harness in case of panic. +mod panic_wait_forever; + +use libkernel::{backtrace, bsp, cpu, exception, memory}; + +#[inline(never)] +fn nested_2() -> &'static str { + unsafe { backtrace::corrupt_link() }; + libkernel::println!("{}", libkernel::backtrace::Backtrace); + "foo" +} + +#[inline(never)] +fn nested_1() { + libkernel::println!("{}", nested_2()) +} + +#[no_mangle] +unsafe fn kernel_init() -> ! { + exception::handling_init(); + memory::mmu::post_enable_init(); + bsp::console::qemu_bring_up_console(); + + nested_1(); + + // The QEMU process running this test will be closed by the I/O test harness. + cpu::wait_forever() +} diff --git a/18_backtrace/kernel/tests/boot_test_string.rb b/18_backtrace/kernel/tests/boot_test_string.rb new file mode 100644 index 00000000..f778b3d8 --- /dev/null +++ b/18_backtrace/kernel/tests/boot_test_string.rb @@ -0,0 +1,3 @@ +# frozen_string_literal: true + +EXPECTED_PRINT = 'Echoing input now' diff --git a/18_backtrace/kernel/tests/panic_exit_success/mod.rs b/18_backtrace/kernel/tests/panic_exit_success/mod.rs new file mode 100644 index 00000000..908fac51 --- /dev/null +++ b/18_backtrace/kernel/tests/panic_exit_success/mod.rs @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2019-2022 Andre Richter + +/// Overwrites libkernel's `panic_wait::_panic_exit()` with the QEMU-exit version. +#[no_mangle] +fn _panic_exit() -> ! { + libkernel::cpu::qemu_exit_success() +} diff --git a/18_backtrace/kernel/tests/panic_wait_forever/mod.rs b/18_backtrace/kernel/tests/panic_wait_forever/mod.rs new file mode 100644 index 00000000..7a4effa5 --- /dev/null +++ b/18_backtrace/kernel/tests/panic_wait_forever/mod.rs @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2022 Andre Richter + +/// Overwrites libkernel's `panic_wait::_panic_exit()` with wait_forever. +#[no_mangle] +fn _panic_exit() -> ! { + libkernel::cpu::wait_forever() +} diff --git a/18_backtrace/kernel_symbols.mk b/18_backtrace/kernel_symbols.mk new file mode 100644 index 00000000..5b51ccfe --- /dev/null +++ b/18_backtrace/kernel_symbols.mk @@ -0,0 +1,103 @@ +## SPDX-License-Identifier: MIT OR Apache-2.0 +## +## Copyright (c) 2018-2022 Andre Richter + +include ../common/format.mk +include ../common/docker.mk + +##-------------------------------------------------------------------------------------------------- +## Check for input variables that need be exported by the calling Makefile +##-------------------------------------------------------------------------------------------------- +ifndef KERNEL_SYMBOLS_TOOL_PATH +$(error KERNEL_SYMBOLS_TOOL_PATH is not set) +endif + +ifndef TARGET +$(error TARGET is not set) +endif + +ifndef KERNEL_SYMBOLS_INPUT_ELF +$(error KERNEL_SYMBOLS_INPUT_ELF is not set) +endif + +ifndef KERNEL_SYMBOLS_OUTPUT_ELF +$(error KERNEL_SYMBOLS_OUTPUT_ELF is not set) +endif + + + +##-------------------------------------------------------------------------------------------------- +## Targets and Prerequisites +##-------------------------------------------------------------------------------------------------- +KERNEL_SYMBOLS_MANIFEST = kernel_symbols/Cargo.toml +KERNEL_SYMBOLS_LINKER_SCRIPT = kernel_symbols/kernel_symbols.ld + +KERNEL_SYMBOLS_RS = $(KERNEL_SYMBOLS_INPUT_ELF)_symbols.rs +KERNEL_SYMBOLS_DEMANGLED_RS = $(shell pwd)/$(KERNEL_SYMBOLS_INPUT_ELF)_symbols_demangled.rs + +KERNEL_SYMBOLS_ELF = target/$(TARGET)/release/kernel_symbols +KERNEL_SYMBOLS_STRIPPED = target/$(TARGET)/release/kernel_symbols_stripped + +# Export for build.rs of kernel_symbols crate. +export KERNEL_SYMBOLS_DEMANGLED_RS + + + +##-------------------------------------------------------------------------------------------------- +## Command building blocks +##-------------------------------------------------------------------------------------------------- +GET_SYMBOLS_SECTION_VIRT_ADDR = $(DOCKER_TOOLS) $(EXEC_SYMBOLS_TOOL) \ + --get_symbols_section_virt_addr $(KERNEL_SYMBOLS_OUTPUT_ELF) + +RUSTFLAGS = -C link-arg=--script=$(KERNEL_SYMBOLS_LINKER_SCRIPT) \ + -C link-arg=--section-start=.rodata=$$($(GET_SYMBOLS_SECTION_VIRT_ADDR)) + +RUSTFLAGS_PEDANTIC = $(RUSTFLAGS) \ + -D warnings \ + -D missing_docs + +COMPILER_ARGS = --target=$(TARGET) \ + --release + +RUSTC_CMD = cargo rustc $(COMPILER_ARGS) --manifest-path $(KERNEL_SYMBOLS_MANIFEST) +OBJCOPY_CMD = rust-objcopy \ + --strip-all \ + -O binary + +EXEC_SYMBOLS_TOOL = ruby $(KERNEL_SYMBOLS_TOOL_PATH)/main.rb + +##------------------------------------------------------------------------------ +## Dockerization +##------------------------------------------------------------------------------ +DOCKER_CMD = docker run -t --rm -v $(shell pwd):/work/tutorial -w /work/tutorial + +# DOCKER_IMAGE defined in include file (see top of this file). +DOCKER_TOOLS = $(DOCKER_CMD) $(DOCKER_IMAGE) + + + +##-------------------------------------------------------------------------------------------------- +## Targets +##-------------------------------------------------------------------------------------------------- +.PHONY: all + +all: + @cp $(KERNEL_SYMBOLS_INPUT_ELF) $(KERNEL_SYMBOLS_OUTPUT_ELF) + + @$(DOCKER_TOOLS) $(EXEC_SYMBOLS_TOOL) --gen_symbols $(KERNEL_SYMBOLS_OUTPUT_ELF) \ + $(KERNEL_SYMBOLS_RS) + + $(call color_progress_prefix, "Demangling") + @echo Symbol names + @cat $(KERNEL_SYMBOLS_RS) | rustfilt > $(KERNEL_SYMBOLS_DEMANGLED_RS) + + @RUSTFLAGS="$(RUSTFLAGS_PEDANTIC)" $(RUSTC_CMD) + + $(call color_progress_prefix, "Stripping") + @echo Symbols ELF file + @$(OBJCOPY_CMD) $(KERNEL_SYMBOLS_ELF) $(KERNEL_SYMBOLS_STRIPPED) + + @$(DOCKER_TOOLS) $(EXEC_SYMBOLS_TOOL) --patch_data $(KERNEL_SYMBOLS_OUTPUT_ELF) \ + $(KERNEL_SYMBOLS_STRIPPED) + + $(call color_progress_prefix, "Finished") diff --git a/18_backtrace/kernel_symbols/Cargo.toml b/18_backtrace/kernel_symbols/Cargo.toml new file mode 100644 index 00000000..3407aa7e --- /dev/null +++ b/18_backtrace/kernel_symbols/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "kernel_symbols" +version = "0.1.0" +edition = "2021" + +[features] +default = [] +generated_symbols_available = [] + +##-------------------------------------------------------------------------------------------------- +## Dependencies +##-------------------------------------------------------------------------------------------------- + +[dependencies] +debug-symbol-types = { path = "../libraries/debug-symbol-types" } diff --git a/18_backtrace/kernel_symbols/build.rs b/18_backtrace/kernel_symbols/build.rs new file mode 100644 index 00000000..5062df44 --- /dev/null +++ b/18_backtrace/kernel_symbols/build.rs @@ -0,0 +1,14 @@ +use std::{env, path::Path}; + +fn main() { + if let Ok(path) = env::var("KERNEL_SYMBOLS_DEMANGLED_RS") { + if Path::new(&path).exists() { + println!("cargo:rustc-cfg=feature=\"generated_symbols_available\"") + } + } + + println!( + "cargo:rerun-if-changed={}", + Path::new("kernel_symbols.ld").display() + ); +} diff --git a/18_backtrace/kernel_symbols/kernel_symbols.ld b/18_backtrace/kernel_symbols/kernel_symbols.ld new file mode 100644 index 00000000..0625f008 --- /dev/null +++ b/18_backtrace/kernel_symbols/kernel_symbols.ld @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: MIT OR Apache-2.0 + * + * Copyright (c) 2022 Andre Richter + */ + +SECTIONS +{ + .rodata : { + ASSERT(. > 0xffffffff00000000, "Expected higher half address") + + KEEP(*(.rodata.symbol_desc*)) + . = ALIGN(8); + *(.rodata*) + } +} diff --git a/18_backtrace/kernel_symbols/src/main.rs b/18_backtrace/kernel_symbols/src/main.rs new file mode 100644 index 00000000..bd90b535 --- /dev/null +++ b/18_backtrace/kernel_symbols/src/main.rs @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2022 Andre Richter + +//! Generation of kernel symbols. + +#![no_std] +#![no_main] + +#[cfg(feature = "generated_symbols_available")] +include!(env!("KERNEL_SYMBOLS_DEMANGLED_RS")); + +#[panic_handler] +fn panic(_info: &core::panic::PanicInfo) -> ! { + unimplemented!() +} diff --git a/18_backtrace/libraries/debug-symbol-types/Cargo.toml b/18_backtrace/libraries/debug-symbol-types/Cargo.toml new file mode 100644 index 00000000..e5b1fd1f --- /dev/null +++ b/18_backtrace/libraries/debug-symbol-types/Cargo.toml @@ -0,0 +1,4 @@ +[package] +name = "debug-symbol-types" +version = "0.1.0" +edition = "2021" diff --git a/18_backtrace/libraries/debug-symbol-types/src/lib.rs b/18_backtrace/libraries/debug-symbol-types/src/lib.rs new file mode 100644 index 00000000..b6dff082 --- /dev/null +++ b/18_backtrace/libraries/debug-symbol-types/src/lib.rs @@ -0,0 +1,45 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2022 Andre Richter + +//! Types for implementing debug symbol support. + +#![no_std] + +use core::ops::Range; + +/// A symbol containing a size. +#[repr(C)] +#[derive(Clone)] +pub struct Symbol { + addr_range: Range, + name: &'static str, +} + +impl Symbol { + /// Create an instance. + pub const fn new(start: usize, size: usize, name: &'static str) -> Symbol { + Symbol { + addr_range: Range { + start, + end: start + size, + }, + name, + } + } + + /// Returns true if addr is contained in the range. + pub fn contains(&self, addr: usize) -> bool { + self.addr_range.contains(&addr) + } + + /// Returns the symbol's name. + pub fn name(&self) -> &'static str { + self.name + } + + /// Returns the symbol's size. + pub fn size(&self) -> usize { + self.addr_range.end - self.addr_range.start + } +} diff --git a/18_backtrace/libraries/test-macros/Cargo.toml b/18_backtrace/libraries/test-macros/Cargo.toml new file mode 100644 index 00000000..fff98a1f --- /dev/null +++ b/18_backtrace/libraries/test-macros/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "test-macros" +version = "0.1.0" +authors = ["Andre Richter "] +edition = "2021" + +[lib] +proc-macro = true + +[dependencies] +proc-macro2 = "1.x" +quote = "1.x" +syn = { version = "1.x", features = ["full"] } +test-types = { path = "../test-types" } diff --git a/18_backtrace/libraries/test-macros/src/lib.rs b/18_backtrace/libraries/test-macros/src/lib.rs new file mode 100644 index 00000000..9879677c --- /dev/null +++ b/18_backtrace/libraries/test-macros/src/lib.rs @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2019-2022 Andre Richter + +use proc_macro::TokenStream; +use proc_macro2::Span; +use quote::quote; +use syn::{parse_macro_input, Ident, ItemFn}; + +#[proc_macro_attribute] +pub fn kernel_test(_attr: TokenStream, input: TokenStream) -> TokenStream { + let f = parse_macro_input!(input as ItemFn); + + let test_name = &format!("{}", f.sig.ident); + let test_ident = Ident::new( + &format!("{}_TEST_CONTAINER", f.sig.ident.to_string().to_uppercase()), + Span::call_site(), + ); + let test_code_block = f.block; + + quote!( + #[test_case] + const #test_ident: test_types::UnitTest = test_types::UnitTest { + name: #test_name, + test_func: || #test_code_block, + }; + ) + .into() +} diff --git a/18_backtrace/libraries/test-types/Cargo.toml b/18_backtrace/libraries/test-types/Cargo.toml new file mode 100644 index 00000000..2f20f060 --- /dev/null +++ b/18_backtrace/libraries/test-types/Cargo.toml @@ -0,0 +1,5 @@ +[package] +name = "test-types" +version = "0.1.0" +authors = ["Andre Richter "] +edition = "2021" diff --git a/18_backtrace/libraries/test-types/src/lib.rs b/18_backtrace/libraries/test-types/src/lib.rs new file mode 100644 index 00000000..922c2a1c --- /dev/null +++ b/18_backtrace/libraries/test-types/src/lib.rs @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2019-2022 Andre Richter + +//! Types for the `custom_test_frameworks` implementation. + +#![no_std] + +/// Unit test container. +pub struct UnitTest { + /// Name of the test. + pub name: &'static str, + + /// Function pointer to the test. + pub test_func: fn(), +} diff --git a/18_backtrace/tools/kernel_symbols_tool/cmds.rb b/18_backtrace/tools/kernel_symbols_tool/cmds.rb new file mode 100644 index 00000000..fe66ea71 --- /dev/null +++ b/18_backtrace/tools/kernel_symbols_tool/cmds.rb @@ -0,0 +1,45 @@ +# frozen_string_literal: true + +# SPDX-License-Identifier: MIT OR Apache-2.0 +# +# Copyright (c) 2022 Andre Richter + +def generate_symbols(kernel_elf, output_file) + File.open(output_file, 'w') do |file| + header = <<~HEREDOC + use debug_symbol_types::Symbol; + + # [no_mangle] + # [link_section = ".rodata.symbol_desc"] + static KERNEL_SYMBOLS: [Symbol; #{kernel_elf.num_symbols}] = [ + HEREDOC + + file.write(header) + kernel_elf.symbols.each do |sym| + value = sym.header.st_value + size = sym.header.st_size + name = sym.name + + file.write(" Symbol::new(#{value}, #{size}, \"#{name}\"),\n") + end + file.write("];\n") + end +end + +def get_symbols_section_virt_addr(kernel_elf) + kernel_elf.kernel_symbols_section_virt_addr +end + +def patch_symbol_data(kernel_elf, symbols_blob_path) + symbols_blob = File.binread(symbols_blob_path) + + raise if symbols_blob.size > kernel_elf.kernel_symbols_section_size + + File.binwrite(kernel_elf.path, File.binread(symbols_blob_path), + kernel_elf.kernel_symbols_section_offset_in_file) +end + +def patch_num_symbols(kernel_elf) + num_packed = [kernel_elf.num_symbols].pack('Q<*') # "Q" == uint64_t, "<" == little endian + File.binwrite(kernel_elf.path, num_packed, kernel_elf.num_kernel_symbols_offset_in_file) +end diff --git a/18_backtrace/tools/kernel_symbols_tool/kernel_elf.rb b/18_backtrace/tools/kernel_symbols_tool/kernel_elf.rb new file mode 100644 index 00000000..b1649767 --- /dev/null +++ b/18_backtrace/tools/kernel_symbols_tool/kernel_elf.rb @@ -0,0 +1,74 @@ +# frozen_string_literal: true + +# SPDX-License-Identifier: MIT OR Apache-2.0 +# +# Copyright (c) 2021-2022 Andre Richter + +# KernelELF +class KernelELF + attr_reader :path + + def initialize(kernel_elf_path, kernel_symbols_section, num_kernel_symbols) + @elf = ELFTools::ELFFile.new(File.open(kernel_elf_path)) + @symtab_section = @elf.section_by_name('.symtab') + + @path = kernel_elf_path + fetch_values(kernel_symbols_section, num_kernel_symbols) + end + + private + + def fetch_values(kernel_symbols_section, num_kernel_symbols) + sym = @symtab_section.symbol_by_name(num_kernel_symbols) + raise "Symbol \"#{num_kernel_symbols}\" not found" if sym.nil? + + @num_kernel_symbols = sym + + section = @elf.section_by_name(kernel_symbols_section) + raise "Section \"#{kernel_symbols_section}\" not found" if section.nil? + + @kernel_symbols_section = section + end + + def num_kernel_symbols_virt_addr + @num_kernel_symbols.header.st_value + end + + def segment_containing_virt_addr(virt_addr) + @elf.each_segments do |segment| + return segment if segment.vma_in?(virt_addr) + end + end + + def virt_addr_to_file_offset(virt_addr) + segment = segment_containing_virt_addr(virt_addr) + segment.vma_to_offset(virt_addr) + end + + public + + def symbols + non_zero_symbols = @symtab_section.symbols.reject { |sym| sym.header.st_size.zero? } + non_zero_symbols.sort_by { |sym| sym.header.st_value } + end + + def num_symbols + symbols.size + end + + def kernel_symbols_section_virt_addr + @kernel_symbols_section.header.sh_addr.to_i + end + + def kernel_symbols_section_size + @kernel_symbols_section.header.sh_size.to_i + end + + def kernel_symbols_section_offset_in_file + virt_addr_to_file_offset(kernel_symbols_section_virt_addr) + end + + def num_kernel_symbols_offset_in_file + virt_addr_to_file_offset(num_kernel_symbols_virt_addr) + end +end diff --git a/18_backtrace/tools/kernel_symbols_tool/main.rb b/18_backtrace/tools/kernel_symbols_tool/main.rb new file mode 100755 index 00000000..30a8be6f --- /dev/null +++ b/18_backtrace/tools/kernel_symbols_tool/main.rb @@ -0,0 +1,47 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +# SPDX-License-Identifier: MIT OR Apache-2.0 +# +# Copyright (c) 2022 Andre Richter + +require 'rubygems' +require 'bundler/setup' +require 'colorize' +require 'elftools' + +require_relative 'kernel_elf' +require_relative 'cmds' + +KERNEL_SYMBOLS_SECTION = '.kernel_symbols' +NUM_KERNEL_SYMBOLS = 'NUM_KERNEL_SYMBOLS' + +cmd = ARGV[0] + +kernel_elf_path = ARGV[1] +kernel_elf = KernelELF.new(kernel_elf_path, KERNEL_SYMBOLS_SECTION, NUM_KERNEL_SYMBOLS) + +case cmd +when '--gen_symbols' + output_file = ARGV[2] + + print 'Generating'.rjust(12).green.bold + puts ' Symbols source file' + + generate_symbols(kernel_elf, output_file) +when '--get_symbols_section_virt_addr' + addr = get_symbols_section_virt_addr(kernel_elf) + + puts "0x#{addr.to_s(16)}" +when '--patch_data' + symbols_blob_path = ARGV[2] + num_symbols = kernel_elf.num_symbols + + print 'Patching'.rjust(12).green.bold + puts " Symbols blob and number of symbols (#{num_symbols}) into ELF" + + patch_symbol_data(kernel_elf, symbols_blob_path) + patch_num_symbols(kernel_elf) +else + raise +end diff --git a/18_backtrace/tools/translation_table_tool/arch.rb b/18_backtrace/tools/translation_table_tool/arch.rb new file mode 100644 index 00000000..deceb6d0 --- /dev/null +++ b/18_backtrace/tools/translation_table_tool/arch.rb @@ -0,0 +1,314 @@ +# frozen_string_literal: true + +# SPDX-License-Identifier: MIT OR Apache-2.0 +# +# Copyright (c) 2021-2022 Andre Richter + +# Bitfield manipulation. +class BitField + def initialize + @value = 0 + end + + def self.attr_bitfield(name, offset, num_bits) + define_method("#{name}=") do |bits| + mask = (2**num_bits) - 1 + + raise "Input out of range: #{name} = 0x#{bits.to_s(16)}" if (bits & ~mask).positive? + + # Clear bitfield + @value &= ~(mask << offset) + + # Set it + @value |= (bits << offset) + end + end + + def to_i + @value + end + + def size_in_byte + 8 + end +end + +# An array class that knows its memory location. +class CArray < Array + attr_reader :phys_start_addr + + def initialize(phys_start_addr, size, &block) + @phys_start_addr = phys_start_addr + + super(size, &block) + end + + def size_in_byte + inject(0) { |sum, n| sum + n.size_in_byte } + end +end + +#--------------------------------------------------------------------------------------------------- +# Arch:: +#--------------------------------------------------------------------------------------------------- +module Arch +#--------------------------------------------------------------------------------------------------- +# Arch::ARMv8 +#--------------------------------------------------------------------------------------------------- +module ARMv8 +# ARMv8 Table Descriptor. +class Stage1TableDescriptor < BitField + module NextLevelTableAddr + OFFSET = 16 + NUMBITS = 32 + end + + module Type + OFFSET = 1 + NUMBITS = 1 + + BLOCK = 0 + TABLE = 1 + end + + module Valid + OFFSET = 0 + NUMBITS = 1 + + FALSE = 0 + TRUE = 1 + end + + attr_bitfield(:__next_level_table_addr, NextLevelTableAddr::OFFSET, NextLevelTableAddr::NUMBITS) + attr_bitfield(:type, Type::OFFSET, Type::NUMBITS) + attr_bitfield(:valid, Valid::OFFSET, Valid::NUMBITS) + + def next_level_table_addr=(addr) + addr = addr >> Granule64KiB::SHIFT + + self.__next_level_table_addr = addr + end + + private :__next_level_table_addr= +end + +# ARMv8 level 3 page descriptor. +class Stage1PageDescriptor < BitField + module UXN + OFFSET = 54 + NUMBITS = 1 + + FALSE = 0 + TRUE = 1 + end + + module PXN + OFFSET = 53 + NUMBITS = 1 + + FALSE = 0 + TRUE = 1 + end + + module OutputAddr + OFFSET = 16 + NUMBITS = 32 + end + + module AF + OFFSET = 10 + NUMBITS = 1 + + FALSE = 0 + TRUE = 1 + end + + module SH + OFFSET = 8 + NUMBITS = 2 + + INNER_SHAREABLE = 0b11 + end + + module AP + OFFSET = 6 + NUMBITS = 2 + + RW_EL1 = 0b00 + RO_EL1 = 0b10 + end + + module AttrIndx + OFFSET = 2 + NUMBITS = 3 + end + + module Type + OFFSET = 1 + NUMBITS = 1 + + RESERVED_INVALID = 0 + PAGE = 1 + end + + module Valid + OFFSET = 0 + NUMBITS = 1 + + FALSE = 0 + TRUE = 1 + end + + attr_bitfield(:uxn, UXN::OFFSET, UXN::NUMBITS) + attr_bitfield(:pxn, PXN::OFFSET, PXN::NUMBITS) + attr_bitfield(:__output_addr, OutputAddr::OFFSET, OutputAddr::NUMBITS) + attr_bitfield(:af, AF::OFFSET, AF::NUMBITS) + attr_bitfield(:sh, SH::OFFSET, SH::NUMBITS) + attr_bitfield(:ap, AP::OFFSET, AP::NUMBITS) + attr_bitfield(:attr_indx, AttrIndx::OFFSET, AttrIndx::NUMBITS) + attr_bitfield(:type, Type::OFFSET, Type::NUMBITS) + attr_bitfield(:valid, Valid::OFFSET, Valid::NUMBITS) + + def output_addr=(addr) + addr = addr >> Granule64KiB::SHIFT + + self.__output_addr = addr + end + + private :__output_addr= +end + +# Translation table representing the structure defined in translation_table.rs. +class TranslationTable + module MAIR + NORMAL = 1 + end + + def initialize + do_sanity_checks + + num_lvl2_tables = BSP.kernel_virt_addr_space_size >> Granule512MiB::SHIFT + + @lvl3 = new_lvl3(num_lvl2_tables, BSP.phys_addr_of_kernel_tables) + + @lvl2_phys_start_addr = @lvl3.phys_start_addr + @lvl3.size_in_byte + @lvl2 = new_lvl2(num_lvl2_tables, @lvl2_phys_start_addr) + + populate_lvl2_entries + end + + def map_at(virt_region, phys_region, attributes) + return if virt_region.empty? + + raise if virt_region.size != phys_region.size + raise if phys_region.last > BSP.phys_addr_space_end_page + + virt_region.zip(phys_region).each do |virt_page, phys_page| + desc = page_descriptor_from(virt_page) + set_lvl3_entry(desc, phys_page, attributes) + end + end + + def to_binary + data = @lvl3.flatten.map(&:to_i) + @lvl2.map(&:to_i) + data.pack('Q<*') # "Q" == uint64_t, "<" == little endian + end + + def phys_tables_base_addr_binary + [@lvl2_phys_start_addr].pack('Q<*') # "Q" == uint64_t, "<" == little endian + end + + def phys_tables_base_addr + @lvl2_phys_start_addr + end + + private + + def do_sanity_checks + raise unless BSP.kernel_granule::SIZE == Granule64KiB::SIZE + raise unless (BSP.kernel_virt_addr_space_size % Granule512MiB::SIZE).zero? + end + + def new_lvl3(num_lvl2_tables, start_addr) + CArray.new(start_addr, num_lvl2_tables) do + temp = CArray.new(start_addr, 8192) do + Stage1PageDescriptor.new + end + start_addr += temp.size_in_byte + + temp + end + end + + def new_lvl2(num_lvl2_tables, start_addr) + CArray.new(start_addr, num_lvl2_tables) do + Stage1TableDescriptor.new + end + end + + def populate_lvl2_entries + @lvl2.each_with_index do |descriptor, i| + descriptor.next_level_table_addr = @lvl3[i].phys_start_addr + descriptor.type = Stage1TableDescriptor::Type::TABLE + descriptor.valid = Stage1TableDescriptor::Valid::TRUE + end + end + + def lvl2_lvl3_index_from(addr) + addr -= BSP.kernel_virt_start_addr + + lvl2_index = addr >> Granule512MiB::SHIFT + lvl3_index = (addr & Granule512MiB::MASK) >> Granule64KiB::SHIFT + + raise unless lvl2_index < @lvl2.size + + [lvl2_index, lvl3_index] + end + + def page_descriptor_from(virt_addr) + lvl2_index, lvl3_index = lvl2_lvl3_index_from(virt_addr) + + @lvl3[lvl2_index][lvl3_index] + end + + # rubocop:disable Metrics/MethodLength + def set_attributes(desc, attributes) + case attributes.mem_attributes + when :CacheableDRAM + desc.sh = Stage1PageDescriptor::SH::INNER_SHAREABLE + desc.attr_indx = MAIR::NORMAL + else + raise 'Invalid input' + end + + desc.ap = case attributes.acc_perms + when :ReadOnly + Stage1PageDescriptor::AP::RO_EL1 + when :ReadWrite + Stage1PageDescriptor::AP::RW_EL1 + else + raise 'Invalid input' + + end + + desc.pxn = if attributes.execute_never + Stage1PageDescriptor::PXN::TRUE + else + Stage1PageDescriptor::PXN::FALSE + end + + desc.uxn = Stage1PageDescriptor::UXN::TRUE + end + # rubocop:enable Metrics/MethodLength + + def set_lvl3_entry(desc, output_addr, attributes) + desc.output_addr = output_addr + desc.af = Stage1PageDescriptor::AF::TRUE + desc.type = Stage1PageDescriptor::Type::PAGE + desc.valid = Stage1PageDescriptor::Valid::TRUE + + set_attributes(desc, attributes) + end +end +end +end diff --git a/18_backtrace/tools/translation_table_tool/bsp.rb b/18_backtrace/tools/translation_table_tool/bsp.rb new file mode 100644 index 00000000..536a2f21 --- /dev/null +++ b/18_backtrace/tools/translation_table_tool/bsp.rb @@ -0,0 +1,50 @@ +# frozen_string_literal: true + +# SPDX-License-Identifier: MIT OR Apache-2.0 +# +# Copyright (c) 2021-2022 Andre Richter + +# Raspberry Pi 3 + 4 +class RaspberryPi + attr_reader :kernel_granule, :kernel_virt_addr_space_size, :kernel_virt_start_addr + + MEMORY_SRC = File.read('kernel/src/bsp/raspberrypi/memory.rs').split("\n") + + def initialize + @kernel_granule = Granule64KiB + + @kernel_virt_addr_space_size = KERNEL_ELF.symbol_value('__kernel_virt_addr_space_size') + @kernel_virt_start_addr = KERNEL_ELF.symbol_value('__kernel_virt_start_addr') + + @virt_addr_of_kernel_tables = KERNEL_ELF.symbol_value('KERNEL_TABLES') + @virt_addr_of_phys_kernel_tables_base_addr = KERNEL_ELF.symbol_value( + 'PHYS_KERNEL_TABLES_BASE_ADDR' + ) + end + + def phys_addr_of_kernel_tables + KERNEL_ELF.virt_to_phys(@virt_addr_of_kernel_tables) + end + + def kernel_tables_offset_in_file + KERNEL_ELF.virt_addr_to_file_offset(@virt_addr_of_kernel_tables) + end + + def phys_kernel_tables_base_addr_offset_in_file + KERNEL_ELF.virt_addr_to_file_offset(@virt_addr_of_phys_kernel_tables_base_addr) + end + + def phys_addr_space_end_page + x = MEMORY_SRC.grep(/pub const END/) + x = case BSP_TYPE + when :rpi3 + x[0] + when :rpi4 + x[1] + else + raise + end + + x.scan(/\d+/).join.to_i(16) + end +end diff --git a/18_backtrace/tools/translation_table_tool/generic.rb b/18_backtrace/tools/translation_table_tool/generic.rb new file mode 100644 index 00000000..13df0658 --- /dev/null +++ b/18_backtrace/tools/translation_table_tool/generic.rb @@ -0,0 +1,179 @@ +# frozen_string_literal: true + +# SPDX-License-Identifier: MIT OR Apache-2.0 +# +# Copyright (c) 2021-2022 Andre Richter + +module Granule64KiB + SIZE = 64 * 1024 + SHIFT = Math.log2(SIZE).to_i +end + +module Granule512MiB + SIZE = 512 * 1024 * 1024 + SHIFT = Math.log2(SIZE).to_i + MASK = SIZE - 1 +end + +# Monkey-patch Integer with some helper functions. +class Integer + def power_of_two? + self[0].zero? + end + + def aligned?(alignment) + raise unless alignment.power_of_two? + + (self & (alignment - 1)).zero? + end + + def align_up(alignment) + raise unless alignment.power_of_two? + + (self + alignment - 1) & ~(alignment - 1) + end + + def to_hex_underscore(with_leading_zeros: false) + fmt = with_leading_zeros ? '%016x' : '%x' + value = format(fmt, self).to_s.reverse.scan(/.{4}|.+/).join('_').reverse + + format('0x%s', value) + end +end + +# An array where each value is the start address of a Page. +class MemoryRegion < Array + def initialize(start_addr, size, granule_size) + raise unless start_addr.aligned?(granule_size) + raise unless size.positive? + raise unless (size % granule_size).zero? + + num_pages = size / granule_size + super(num_pages) do |i| + (i * granule_size) + start_addr + end + end +end + +# Collection of memory attributes. +class AttributeFields + attr_reader :mem_attributes, :acc_perms, :execute_never + + def initialize(mem_attributes, acc_perms, execute_never) + @mem_attributes = mem_attributes + @acc_perms = acc_perms + @execute_never = execute_never + end + + def to_s + x = case @mem_attributes + when :CacheableDRAM + 'C' + else + '?' + end + + y = case @acc_perms + when :ReadWrite + 'RW' + when :ReadOnly + 'RO' + else + '??' + end + + z = @execute_never ? 'XN' : 'X ' + + "#{x} #{y} #{z}" + end +end + +# A container that describes a virt-to-phys region mapping. +class MappingDescriptor + @max_section_name_length = 'Sections'.length + + class << self + attr_accessor :max_section_name_length + + def update_max_section_name_length(length) + @max_section_name_length = [@max_section_name_length, length].max + end + end + + attr_reader :name, :virt_region, :phys_region, :attributes + + def initialize(name, virt_region, phys_region, attributes) + @name = name + @virt_region = virt_region + @phys_region = phys_region + @attributes = attributes + end + + def to_s + name = @name.ljust(self.class.max_section_name_length) + virt_start = @virt_region.first.to_hex_underscore(with_leading_zeros: true) + phys_start = @phys_region.first.to_hex_underscore(with_leading_zeros: true) + size = ((@virt_region.size * 65_536) / 1024).to_s.rjust(3) + + "#{name} | #{virt_start} | #{phys_start} | #{size} KiB | #{@attributes}" + end + + def self.print_divider + print ' ' + print '-' * max_section_name_length + puts '--------------------------------------------------------------------' + end + + def self.print_header + print_divider + print ' ' + print 'Sections'.center(max_section_name_length) + print ' ' + print 'Virt Start Addr'.center(21) + print ' ' + print 'Phys Start Addr'.center(21) + print ' ' + print 'Size'.center(7) + print ' ' + print 'Attr'.center(7) + puts + print_divider + end +end + +def kernel_map_binary + mapping_descriptors = KERNEL_ELF.generate_mapping_descriptors + + # Generate_mapping_descriptors updates the header being printed with this call. So it must come + # afterwards. + MappingDescriptor.print_header + + mapping_descriptors.each do |i| + print 'Generating'.rjust(12).green.bold + print ' ' + puts i.to_s + + TRANSLATION_TABLES.map_at(i.virt_region, i.phys_region, i.attributes) + end + + MappingDescriptor.print_divider +end + +def kernel_patch_tables(kernel_elf_path) + print 'Patching'.rjust(12).green.bold + print ' Kernel table struct at ELF file offset ' + puts BSP.kernel_tables_offset_in_file.to_hex_underscore + + File.binwrite(kernel_elf_path, TRANSLATION_TABLES.to_binary, BSP.kernel_tables_offset_in_file) +end + +def kernel_patch_base_addr(kernel_elf_path) + print 'Patching'.rjust(12).green.bold + print ' Kernel tables physical base address start argument to value ' + print TRANSLATION_TABLES.phys_tables_base_addr.to_hex_underscore + print ' at ELF file offset ' + puts BSP.phys_kernel_tables_base_addr_offset_in_file.to_hex_underscore + + File.binwrite(kernel_elf_path, TRANSLATION_TABLES.phys_tables_base_addr_binary, + BSP.phys_kernel_tables_base_addr_offset_in_file) +end diff --git a/18_backtrace/tools/translation_table_tool/kernel_elf.rb b/18_backtrace/tools/translation_table_tool/kernel_elf.rb new file mode 100644 index 00000000..f2d5b0b7 --- /dev/null +++ b/18_backtrace/tools/translation_table_tool/kernel_elf.rb @@ -0,0 +1,96 @@ +# frozen_string_literal: true + +# SPDX-License-Identifier: MIT OR Apache-2.0 +# +# Copyright (c) 2021-2022 Andre Richter + +# KernelELF +class KernelELF + SECTION_FLAG_ALLOC = 2 + + def initialize(kernel_elf_path) + @elf = ELFTools::ELFFile.new(File.open(kernel_elf_path)) + @symtab_section = @elf.section_by_name('.symtab') + end + + def machine + @elf.machine.to_sym + end + + def symbol_value(symbol_name) + @symtab_section.symbol_by_name(symbol_name).header.st_value + end + + def segment_containing_virt_addr(virt_addr) + @elf.each_segments do |segment| + return segment if segment.vma_in?(virt_addr) + end + end + + def virt_to_phys(virt_addr) + segment = segment_containing_virt_addr(virt_addr) + translation_offset = segment.header.p_vaddr - segment.header.p_paddr + + virt_addr - translation_offset + end + + def virt_addr_to_file_offset(virt_addr) + segment = segment_containing_virt_addr(virt_addr) + segment.vma_to_offset(virt_addr) + end + + def sections_in_segment(segment) + head = segment.mem_head + tail = segment.mem_tail + + sections = @elf.each_sections.select do |section| + file_offset = section.header.sh_addr + flags = section.header.sh_flags + + file_offset >= head && file_offset < tail && (flags & SECTION_FLAG_ALLOC != 0) + end + + sections.map(&:name).join(' ') + end + + def select_load_segments + @elf.each_segments.select do |segment| + segment.instance_of?(ELFTools::Segments::LoadSegment) + end + end + + def segment_get_acc_perms(segment) + if segment.readable? && segment.writable? + :ReadWrite + elsif segment.readable? + :ReadOnly + else + :Invalid + end + end + + def update_max_section_name_length(descriptors) + MappingDescriptor.update_max_section_name_length(descriptors.map { |i| i.name.size }.max) + end + + def generate_mapping_descriptors + descriptors = select_load_segments.map do |segment| + # Assume each segment is page aligned. + size = segment.mem_size.align_up(BSP.kernel_granule::SIZE) + virt_start_addr = segment.header.p_vaddr + phys_start_addr = segment.header.p_paddr + acc_perms = segment_get_acc_perms(segment) + execute_never = !segment.executable? + section_names = sections_in_segment(segment) + + virt_region = MemoryRegion.new(virt_start_addr, size, BSP.kernel_granule::SIZE) + phys_region = MemoryRegion.new(phys_start_addr, size, BSP.kernel_granule::SIZE) + attributes = AttributeFields.new(:CacheableDRAM, acc_perms, execute_never) + + MappingDescriptor.new(section_names, virt_region, phys_region, attributes) + end + + update_max_section_name_length(descriptors) + descriptors + end +end diff --git a/18_backtrace/tools/translation_table_tool/main.rb b/18_backtrace/tools/translation_table_tool/main.rb new file mode 100755 index 00000000..6419e364 --- /dev/null +++ b/18_backtrace/tools/translation_table_tool/main.rb @@ -0,0 +1,46 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +# SPDX-License-Identifier: MIT OR Apache-2.0 +# +# Copyright (c) 2021-2022 Andre Richter + +require 'rubygems' +require 'bundler/setup' +require 'colorize' +require 'elftools' + +require_relative 'generic' +require_relative 'kernel_elf' +require_relative 'bsp' +require_relative 'arch' + +BSP_TYPE = ARGV[0].to_sym +kernel_elf_path = ARGV[1] + +start = Time.now + +KERNEL_ELF = KernelELF.new(kernel_elf_path) + +BSP = case BSP_TYPE + when :rpi3, :rpi4 + RaspberryPi.new + else + raise + end + +TRANSLATION_TABLES = case KERNEL_ELF.machine + when :AArch64 + Arch::ARMv8::TranslationTable.new + else + raise + end + +kernel_map_binary +kernel_patch_tables(kernel_elf_path) +kernel_patch_base_addr(kernel_elf_path) + +elapsed = Time.now - start + +print 'Finished'.rjust(12).green.bold +puts " in #{elapsed.round(2)}s" diff --git a/doc/18_stack_frames.png b/doc/18_stack_frames.png new file mode 100644 index 0000000000000000000000000000000000000000..781732f6c155981444b6afac4ab0cb067694cf70 GIT binary patch literal 47923 zcmdqJby$?`w>CT`7VxNqk}9Qyh?KO7fI~M(N=r8bLmG(Ef`GI%44p%VNJvTyNDLs& z49w6y@Lhw?^V{#<-`?-L_xIoTavUDW+;iVotvJ_O=ej>CE6R{wqPYZtKuDp_pQ%D1 zXY3%5v!oZ!gHKqZZ_;60-aY*6cW z-AO8fe`fONMXTc|aHml2}y;h@TmToAP%2UKoe*C?R z+5h1o{Y-~m_kZ{9m&S0naj`btI3saHzcW04&gJj3ghVp^yHRe@x~z<9sAb9*=idLb znI*4Vj6c;`OJ4i4ng7#SC}%0spF4kklsF5#^y!m1*ff3k-^S+}kl>f6k|3NkW8SuY4wD$9_U%y`8*eJ~{h;K12 zepD$zoCk!&`1^mRX#YIzvA~T-4qxjD+qyNFKgV#3_MN}~()wKIze$Nlb@iF{7t_P99oo*r>VddnM?~WH7 z?n{$N^vRFr(zWW2#bXlEqW3hT?L)aX3E~tHMMv}+&CP6 zaAng{M1TMzBV%_gugqL$3=G2`%X+b~D`{n;OjsP%ghE3gHTk-065c#kh}@b_X@8AR zsl(n^WXQz;bD>#)qk>eb|0p?y@HDg~4z=ty-F{IEcDv08!JP2^C((u+W@#52cO*+R z=)2x@e5>}?DEQ3pbN%l0GJ_hWkfv*m2!A1d6jq#(#BNTWCUhqXlVG9C}>l+ z&I&#{n?l^;A{=37ayWuTZW+-z&D>s6_EfhsnoA$e1+F!!lhF&OPqze(X~bL=G`)Co zgM;`R+GXjJ)s~Pnk-AwA7to(vXg_~e@Yl+Cm2*V;+DzN^lY!apRNn3kq_{VYxeuNP z+2Q;5cC_S4z1QCC%#4Ya{`QIB0d3zJHXPFj!x6v#U)kM}mz#@yI@K;Y`mQe$h*knp z(o~>d^I5{z=Wl@s&ty6X!{}`CLse7moYN4f%u`r^JYpbfaO215`#PCOLpozRd(jF_ zpCcbPBn+edMMult-q{04!(4Z=jK{`;#-~(&jT$2^eya)P?lJzz`1p8KwWJ|!W;Yi3 zJVMyTwy?K8_SJw8B=p1!IHZ1m7G(Dw?V#;RB{x476!H<3vGH5jXYpMHpk7EtR6_Ro`MeM1!Geb8ogs8#E5xnBIT}>eQD~>+!O1Zh{3#8&?oi*E@sgGX>|yL> z%OTIrrBHaKGc8n>pWR}Gjwm}onr3fF1yc5{a*OkY&e*qD69SJjbbV0V*38hYxWVp0 zAxMq~9Ny8~++1HxhPw<#kuUgtW@~PK-n@3l4Wq3cH|JwmqDtI_kbM*?ea>4T`Am3) zef?f5t~&T+fCnDybDwJ3d?n6Yzjm#kQ_vUl6qRSFKj5?bw5rx=#EZ;t=EPEmH^0OE z%6hkZ{7t9D>b7NceD$s~<=xK`-Gqs}#4}UwL<8wZ$IQc{68YXcdb$Qto}2!n;^ptt zOBE)><(MFtA&|#pj%(vATUhbO*a$A^^tq>E~aH`7xbg>g|Q$Z#~a8-aI)?p=TpgCDjd5Cgqr4Pl13ryTTx* zzyuNRb6XIx`uOo97;Ydb-?PkU%dpkJR>NAW@7;)rMlpPpH_K_KOgRLm0c^z2}ohJce^m zPqRRgb`$+I+;#Rlo{kW`fGJ>I9LPDeEB!LLV(-{9+C!mg_ei$AWR7tcTpfEMrsq$l z$DoxWTXa5*-jr^#+C$De8Ll>5XaF-R{QLSXlEuCSOMaiC6i2W1c4!E_=!C!6X{V%f zm#G$`v<&`sq_;>MoSg?M3)|WS!@}0kZwl*C+YPYlBCW?g({pnyN=gSq0n8_o@mI!a zIjgA;f*~eBEvZd)lf(J(NWEVikcwNx%cf~xu*I?aYyzx9DZ}_ZI62Bjx%rWJE&fA2 zjbL-iFl5U81d@e^#A&>W%2_vi+i8Vv(jcp;uc@gKPZCh2rx7gx2N{vhE$y2Vko+ol zJ?age8$BdPAznb?_U+qN6SW?hM7s)sgg2`rR8;CFF=lj=wT^0U4R5jswM>6AIJHwR zakML$lCo{v@`MPZ+Fu*^HiQ-PAen8^MG8UYKKN>~Q$>L}5kNB(H(%|L!OJ{J0?M^2 zyl&DfJ^C`|=H$6BG)my0|H%XydHugPe*Xe0CK^zpKDVFeHSba`(5qTT{DE+OHp*Wg zp8~Ex;~Me$fAGkDHV^D4Lz_I*=|&G#T~SGQQlQ`s(VR0Ti!x6%`YU60|pf_6IQfWWPCgS*K3AdgYe}(X2lXg&iGwP_nDv zMQ@n2g`&pn8*J(D=o+nZD^$toeE4liKC8jIGrO}tA}?LKRHCy`K5Q^RZRll0XISMV zB^5|ftdk`Z#tT^dupaJs3_w*_qGO_ON z?xxypXtAw$bFeR(GUNRS6Y@WzT~k?A^`o=1({j$9*EvzI%E_!cR80F1h>#CG(Y*Af z_M^0FDsP1d_3Y8c=|2B)|4UgCy*pP;lf_=yskE>Pj=LS<^O_ZM|U;yeeS5uD9iZgdy%lhKZw9=Gd3} zHrII7%5DD_*Q=HzEwx3z9_UC%dp#G`aP-N1M57_^6En(MRZwjKqDu^pjf{*6aPOB+ zB0ZrFGv!;gEUUpkYWJW`kLH8s}x_8O8m(*OL4Yh`H$n0<|cK2LN3uaG{5d2l*tnqea_C# z4x!AVt)GO?vjdoN;?RSBRNN`Lz5O`|rtbm=DYqj3<-rre!46Ehu*-IJstGfcubYWI zIlB^-9H$KRTqA`5R~`Pgow!r^BIT-e2iVGL+IAyRQBgjRbyHHh zN6Ob(<%>ib!K|`9Hs%!wZ^$c(GTku4LG3x0Ij^05!&L_JE#7(}yu2>UPD%cHZWdOS|_5keOTSvbLwz*#@>bEYG1JOq+;r_qf5#MVEqxYalkcH*dR>9UYJ z)Oqei$Hc_s)|kToWPci2IzHb^E3Dt|K%px+9{inPXd?njzv~`z+x=_r-jdlP;b?@S zCAFW>)p5VPqVKZRzcB{mW=?W;;srPm)HLe*Pn|dQpNliCng$p2$1k1i=);e&|6byu zr$U3}x{_S<4K~=hk!H2^3r?wXB|dw{JgbYBJLh&knvs*?~vcohmXuK1vI$hXdo7?(pOsNsOyw7D2R$081ntJvo9=9tjQ0dc9$?T!n+jXLf+8p+m*f=0Xx*RdS;g_WczTP%zZ&4jnBw90(ABPTj*f!N(6x&fW5vmTVYZXg@}5`D^nPtI z_N+m6>Q_^wcpro=BImGtyLA^aM}tiJP8~8G@xy|h1Ym;wOibk*MBG;^g<&50DFu=Spr@VUA%xgH+gQ@P= zfRW#~$Oy3xX3yu{3ZoI)m(#EQOmXFW9j~It`Yr~gWfOn;`~r=HPwo3FH}62L#wzj| zJZ7&_?=0eW))tY2*c1PNCHjYwjDf*yqkQ#AT~4Z&HnzL>aqoK)8?q@m1Q$zt7dRe1 z)QKoF!!m^2;MYi#u8mEd2;z28A?)*S{@9HLX$bqw10pmyc*I``Qh8fmztI#aD>Hre zONmHBS!5^@X1C=@cu{WUksK%f3!Obyczi*u|L957ef@8-`qJlH!x#&nygd(^L%MTzi<+L|2q`as4^Y;oB=NE})w=-wt5RPf1m_v73e(R&)s}tghqFQe!mlBOT zW_guhgVFh(#Mvk=alaH;TU%S-bQuvgfIw~}2)C_laL;4I%HxA)f}iR-X&}yGvsl!E zXF$ZQaO9QLd~jjx>L|{ZAE7nq`PPsp)Wq1hd~;YrHR@n5hCd>mb!WJ{qW)CDdY=sA z(uhSe>JyWU9-0!khlR2!kUHb@ndY3SbedbI+0>k$Q1kq1=}lazqbN9(z`$xNHMAUX z<*QSUwv$&8OfrfzX%`Bd=48vZ@e&9zPjbvR|5Z*TY;D?%KnvIA;VC9t)Nj3DDsXWUH9%}2}2Ep`t8P35WNn|4T+&+``mBe zdTzEclC4+|-=TUt0av+tRR!ct3*yENl^7TpmZJ3!7R(jm>z`wfk^J2b>Qzo2Vxu`x zKsjIR9UPcdbH`HBdn-hWC#JPX_mozA&pIDm{|zt zo;ayB=wlLV@9 zD$c`}-2@S23{ZMYEs=aitJEQK{$d?g;r+O3ag-s4rd^Sa9WY6w4aeE_aoZqcmsoH> zGhC6YRIzKa!Ya142{CycB?5BK(lcyc`8RnRhHHgp28$(w_&O8Cy$z1vv-;Ot4;v4r zsM(t^a^15u-555rMgi?mylD5XB4KWQ?m1H#RQ2`gJ=KKc-v_-K*~&guRaIuNVTjr- z;`X;#HrY0}+O{sdC$$o`eX;iL-Pv;Q$`}FL2}>`nTyryiYfVFzKx#D`y@XIkiF}|{ zH_}M73Z7x-CM3&YJB5mSr}nWW<(Tm~S9CQcH*|e-Q@N(1TfN53Y|q`(8e37PgFIrC zdiLxdI|jkvn_5`^;=vOoH%p6hGJ*4qx-FYlmPdkG7vNh6A?(9A0fGoq8CZ$sM1muHeknAkL%)V9?Fl}3 zKx?2rirF70l4sUH$RP_$7wb1G1kM0cwJ^!^RJR;K$!CvygeuTrk*We_6_tUd9W8Q< zzjp1~Aa-s?9jT}h#cjxnu4vFNlaJV3m(xcrpl}^Af?*Xl=rpj^vrDl@6sn$ojXEV^ zhfPqvjdy2$q0#!}<aRCZ!fd+?`SW zjltR1S)0Al=xX>@wRFgyY^ga2k$lDk6!=#AY}1e!V>#C>#B9Qk~w0sFhe<3XOUy4I#mh`>I#5U5(s7UTDOZ!SrJfDA`hYK zGbAtfFo-Byjn9bVGjc%e1V$WKVOCvwg-)k*^Y2Aq0ea#HDf8+k>Q1SH}waOOSJpQoZlkXnH=@q+e3GY{9d zw)&>=;+^V=*H{8?Cfh4nxO`TKhh=L2YKrcwC5h)($Bi2hU6kEKZ3eiIV;i4o8BKce zqWVZl5ACVjWoS>${E071!cU%LYz;)*(>(4!<>z|#5yUS|h^3N}JIN`Bu-d7W;CM6s zU4UWV>$h!X&I{tUht{5fQEVXilq@Va>-4=Wa`r66z{f}nm+9HqE7&M5+L!VwV->dc z)lK=*TY+Rt7CNoLH`8uQzJDGuinK3ek&C_yvs>W2`*!d=nfnv{q*vC?9x_T2ZqCkX zQ5{Y2-+MinEo17r-sItw6*i>(q`26~3V&8P`6JcXhf57Gn;?-h;~*8l0tKPe;BHE? zaB2`_>Ke$eMWnB;=HZpDj6Jgbp0Av8*sA`0Gx|HMY(?bh)|frEY-jSVu-9&SX!4`{ z#YO88CtGNBxJ_?vsRcK};B6Z(`h9sgb|D>hj@z(4??)t?ob3K73Dfq!p6Uv4P;1MQ z(hj<~*VvPKsWdHdy3ed6>h5hUL?s*EMr9lHVJP%v0z*PHUcGu%p?A3*kt#*cyY3~@ zh@J@I1EA~T#fxN?v=F_I$1!G%S^4ZY)eFih459mu71qN?oaL??^IW;{1UqzvmgGcy zHoxzoZF%CZM+X=Hs_%Wiudf60piZuWkoe_^y0P0UWmYIz5L>Au z?a(gM-!GQq24#1UHp}4^ry42UY)8_PsSZ=U_DUAGeSUwR+Fot$F7uXAbr>sg4NFZc z9N{OhgSgYILo8dBg@CH{U=rJ2l)NXytRpw19C|8qMr z-?$}Er^YS+>Vyu`ExR1X5AOTXYH%u7T^Zs#IKIXVN z^f8rc38dUwNcLq1^(qw=6{~^FkfXf?MlIN72<{TttN!`!_;UD`)l*tXV+vR^_}T0W zD5PyW*rxBJR--aUga9<~b0^4GFm$Zk`*9RUj9@4XFZ9x@K>gnH5L#3;e{r!R(fm8o zG2(y4++%#DGr8-9)vS#^tbEuk3^ps*q3`_qhJE(=kfb8(JvW)l7cbtfJ@uINuV27G z&6iEFLdB9j^+++p4?;<5`K2Qz;w{wB`ZYV)J?csR&^}rr{eQRs&I{Z9?N{$j20@P$ zV{1HHkq?ar)%6<~tm#DHzEzEl5mtS*pBxW|#!S@eJYiWpCRz6c1QcVqWiXRJn-N;b zYRLmr?r*dZ)8NMQkoNnEq#(4li(79ASYLyVeis5+Gy+MmYD@tEpxq=s>@#U;>z^Vs zgGG+iOr}IfIn>pMP^+;DEGf6v5D>>t`VL|c5!czehbooKGk0&@S_ z0~>+qYdcu%0yULrf^o+iiYFCqyosu{YztP%X5AkVEFr5E9vkMwlh6w#&c{wsH(|B{ z?wV_f3Veb2xkM=?&ANi!ZjOlBH~Jw<)C_iwHyWApkNc%ZNJ1^~4J58BIvtPso!ot0 zeG!s~3K7x%r+CuD^ba5I0vs+jw8vjJ(vUS;W`~$Q@~Nh~nv*E9W7*n;523t&=5*i^ zzycBJLDcjO4SJ;{G>e2C1JvqOHD;*w@pzsUKV#qJUYKTnTomPB%JRg(?&yu7s{B}< zMrlc_w`lus!VkpQ?|cwv3p>vTk5<^`0%glqNt3>*b>7eON>C^S0HdWQg$RH?wT^X> z%1WYp)u5Va&Tm*Ialhy{1TML6Mrl*S*f_O7KdA4+ zC$$h1XQVR>HarFM#74!``BwqRG_yY_O79?vQhEHCC(90zC_w%r&8xMg-*I=<$YhpFDM?hP-m8ki zed-j+HvWF3JG4a4(Ulu_-_DxIWVyn0LJ5xD zgHeLqEw4onNWQ^B*pj_e$wgQF_P1B!m#Rk|YCPluA!)X1#w{@M*&+b~fiR25XC2^k zXNm;qZ!0k{iv7xaom=z!FQm+bPT8xJfh?t5$pEtb1AK!9NGu0)5Nqp2auo_u-|J@F z+&8wjHCTHszIrwnQ)Z`a><(miDd)ib_6&?N zuER?ccwTvlE`mzLrVHMVM%eK~kmp&*Jswc}@}rxT9w#MT-V057wf{N#xabc0Co7aK zEUAAuxksgwePwgx!#xnZYK|#_+{-u1NrXqnQ1vyRmOgzLF~~-Ls7ax96r^BGp2FZD zkJ*WZ>TpSBX69^rc9de0dYvOZ!tAtqs=8y#WZ>{pqy>fBVcE3t3^UZR*fEZ8 znO92s8Rjh%pE0uCO)I$dY`|``Mr?3t=M+TfDiBdWI^&~3|9ek$(Fa!8tsO(PQUL|E zsF0wLfkW_7$^0u76xqe!Mp^2Or4WKDDN@=$+|_TON;^EajtDorJ;(iJ61Qz^V(fZ}(NhK_hQO%1h&wHTzr1asfx#d8 zN7O8$*a`~+DL7JV_cqLP#B?k7Z%XTb9Lm^;q44D}@Hvv2UBFxHl(V!=lH&}BwSOnS z*#Y|N*RQ(*N=JwP*->>QsQtrd-qu&Uav1mrQmAiLqk^5~sJR9{^BCUaxjnb}gTXdg z@LPXCa(&@JoS-ZUH|c9PBsf5|lzeQfvFpF8zVMbKMhmN$zvZ7``KYYTW$WI%AmbH}6XDVov>6~Fyr;cg@pSH`!WUivIa}dr zpc%rMrMfImHs{n!5K9$% z`zY+a9{r&D%zE^`HKBu4v(UrzScN!8P~pfej8W7=AM`WM>4KWmzANL`#r8$@1&}as z0f!{rAf{N#+KcKktXD;iYUCM+aE%>}rX+>crhl>KiAV=L6sz3@#$WWKbbE9?iQ@K$ zo|Qga(%f##`GARYV*$jKN7@ydXt*o%sxT*2kTf|>ZfvA^mdA=@N&x?6xsgu&E^O=I zYoTLE>XFm{r-akg4R69yf(w3bYC=-Dawpu}S3oP7dtaT4!RIHY&f@!(-qphL_`$*h zh?HL7^NrCgrG&oVi-y*HU3h*++@o^L&pWy}k{t$OT|nqDD50RL)j0BZEu)y1dMAgm z#Rp01cqBY$j;VWYWyV&k=E?2XaKNgmcHM~f(LJnL^9HgMtWrPC5=1-6#>~7}72s*v zmYLWJ)3DOeY$n0vYJW5aH7m7WYXih09Z(m}dzP4yaIN=NEjU9!s)Y%5A1Rr(i%`_QVPA({Ris#LxX@;N_W$+ zr|X;}l1$=C-pH1#O6(nLT-8!>R$bR|59rH*(h>8>k*fDoa0Wk7##Q8ptap7|2;oHY_E&6&SG|P zA$+`Fs*@S2R5z$0X0TEqy0`vnXGkotii(N6_gGq6uy8WsP8qRe%-TaAGc8sIoX@6F z!_|Epwnf-^-KKgtxQZ&x5wE}(%GS+TC{qJ_u3>kKJA)ZLyr~~jjQ}i`I3A;DX+`>I zyP6?jDU-xpHP3j~o4l(Cx1!{8?5R{wtNINxc3B`}S8YVh*lqU6;d68n5jm%GdGRDW z=TBG{0T=FG|GLLv&XH|gMKRgd`rT?}-Ia#0{YcDhG7_OunFKHMcrwt|E6+36ceOsY zzI}ImV~fG^=s{G(#1C45J#Vl}wq85KjPW3g4nj1O-n-k;8EfIZ&q*`-vQR=MOWkk*$ zptV6&%)k5fwJrc--CxF-m98Vo3@k3u1R|T(WxlMb{k?;wG5!r=of0sf0ENa3nvi7m+pW53lyzGtdIJ?z{FL8I&3#z&D`I|hBcIWt^E3;9hLi6HhVcc zhf=*L9FtL?+37jIE`Rl#-SKlp+zz7_$X}AKSi7zTw34$bocbK`bOM*}nP(sY*jih! z4r&Xe^`n^it%e>u`zB`q;n2>HxoROAAQH0gREgS<*=9u5>mP*7JV`sRooKZ)U*w~i zH8Am^#>h*Y+D(yX*kpj~VD-A~*6%F5XZoW+l&)@GTwOb!IW^B~0N?YUWNi0PBl%cagM?r>yYk$T@Q8sKUVaxC$B| z8P;xGoX+0h*~uU_uq2#!!v<7-Z5@E5Aj)iy)lJ1Oua&@7;^2nlKQ?BN~epQMr~|a+TW7WZdjIo=j%+VFJw``l&w;IaKVO{_rf%F6<+$C2c=l9P3 z7$-jXOtt^OIDYszO~G0a>zjKlTby3c%yn$!pL!>CbE|Nmr0lScU+Y`p;^J$QOXzYX zT|qmg;_8XSl=ao4wAKaH*DQb$(R5`DDZuVD_Q_jj(*>IZu*<`G&;2MnvWvDA9bL|q zY8e*8}9 z;k}vGLT`AJf8)50Lx%QAC&-2_GxZm$WP4lBJO(5S)4ypV<)lmA@LCr(c;M)dtO@%gB+d1V>M#xzV{8Y&VVx1 z_fL_RM0|u%^@c;tzB1hsU%x~}#BS^)$E$e@=1pEe57&ND6A8D3Y6;tV29e6vGC1fWAqYk@%%(|mq_0F0q`#}AS-}|FDI)a45j}X8?SnY?Nng_chQ0254*=O-ht`GgQmLI0G>knDb$M-#P@Bolf3Fn;T66=F319a zpi+3McdV9VJaO9woePX$*J@o=Nt4;!@81O`Bw<+|N3tc1^%LUT3X^4-FXA(a-U$sz zdVmozC_|93{FYEmW<9CW`&+R>-mLE0RZFiP!=Du@MR#u6d|6q*XH8Zd=jAXe4GRuX zXN(SW-WGonKSW4Vz#jFjo=QW_pt82M7f-FPl^;(g<|Y}f?+h$c(#KYlTA=?HDV*a% zuino%!(sNrr-cF9d z+!Y8YcM^0 zum#4QaDp6oBz#8kUS;^=)cjfBFtk6>7)2MZf4CRVLmRkX z>dWlK0o(F!Lzzwoax{HDAE7}kjow2RwEm0{_L=PhS zoyxD_jTCKwLY=rIz2eHaz2$gP>?- z8W{-^&p|*;-St`yw@niu*=Fb}l0VGfe0^dP0fgAz+t*KvyRoliAYO+r+>%D)GuoylCMo*>W*M zM<~5$0YG@rokOBC%tfrI-?Jy}juRcW(!H(0k*&W_(dxL~Xw0D{(R^M3OPdUs<5=JY z&9&KpidgOOD<>M0qH_AKj~2nx9D7hZZ)^S_yIXtg;W0e{xfTZo0!rMXZmX58q_HpQ zB(`0$)W=S_yJvbG+!0{iI^XqU^0E`GcbBbwfhjBVSNq;PeHx8;y*T{Q3&@xKH9nRJ zo`+w?*Cg4>9J_tfL~I$Y6O9<{Jb@p-RG>HUh+)0sC&kz~)Awn~Z^fP>G?kmpNrPv0 z_PxH~GDmweeM)sSRRjIy9*Wp%IT3g{0RwJ_-`jHor(hHzK zd9~9-7qparB{KG2eNY`kBtj4Wq%IhX+qXdOyJ3^(OO^nKaI=;7OmL1BKkcA0z)<~l zM~Ssgo|Z)E48zDRG;e)MRAWtCqg&>2`S#Mp>?eJ^8>UZMX>qll>0U>IgtviGIb741 zvsC=s7q5*C@0xAv*~YK|(mq;EdwCw?JwU6C#ns$QGHOUEyy?quKcOx=h7lWyJAHp6 zlk?|t@BGa+AlUa>TvT|+$-BZ@Kt8Sg6i5Z|5wddN>rGi9mX0b~sr>Mt+94jE34jWg zeJw*a8-(is5vP@cjHgRmJp~gRATR7M$A7f6`@TFspE=br=jwpJ4TUoOMYMl_khrzp zNR2{BUM}}a_it^GfPT8F0+KrLy|v*@mX%&N zPgHX!jFX$2MZtt_wU2gxwhmMTCu8yk0n9?Bj4>e$kce?KnzGtC8Cc2Q8@D-TwVtar z#3w9SXxFH4iA~~P5Kj!+-#dAT2&gF=kfi6O76qZyvP!udCF$NQeaMXmI;#COI{CRs zttCK&E7tj-NGFt&MiP2+z#u4wy}z=zhMv-3=fau0_q>vh3~Hcg zxL8ifoLuMFu*`x|^6)+-ZQ1g{oOE^#Fn=azcDo)l^V)#S>3;nVLY$UIO11yU*Valj zl`R>c2T*9P_G2D@`pW}hmwoz%NRJh)^Hg(7h_wCcgV%c}$+p|;lqlXBP&=ke zOkC|6sooIr*!*07BdS^f%C1*dl<6ZVq(NIj^C-1p=&)K7r0OC*mvxvDShrMzlT5$A z049jLb}hllW3K-Th|&ghn?sW|L6|Ik6W}>gkdOx`IAkHt%WBe=QJyAsfUW1%ioLIF z1erg>(5j$JhUZEgsnud9qc}2m(%j>{JsCDjuS%4Et-05SedS zxZ2*O^l_11&Yd&PfAV0@K`YVLk31fo!v=d)hJ^(XD~ob3pjdpb1|j)JuqqT_CY;NT zIbR!YwJ}XR9Up9cO%klk+9B#*m*G&7l?m5#$UZtvPio^Hb{wwOxM)Qf$oLy~rLo+4ka^ z6^uCae*LfvF?|4n8X^Tbqcf^sjoTHqzS6J=NXkR`rk-)nVLp2nA9c#?3jn9NpHmG)U#&fK`IE5w zQOUle$KA1WJ}(XIsD{Y>6G3}d>W2>(ym!zr`1+47d(n#!A%&IEa!@U}Ps$+joVx+V zF>`685fBTBylQt`YJpzpAc&|t;<>{Dsdm&}I(!8=s4kcIVxD4QS3Y@ghD6Z{JVznN zEAMZ3VfZ6c7KNLrJZJ;TarbLL4Ch8${f_J+<_9NMJYDyU-#H!3YWjCHUAl7LI`6Ti z0N9sM0b=536@`pQU)bONS@Z+1%f;w(TMx+KKx|PdG31u;l{n}BxfGNzDW8kt@<_edz@`0EB~O2@m?L$RuB_Q>RV|JGWL)>f9FFn~j7| zy(Sq1oCEn`{)OWvKpU`kqc<05au3d7hn$$u0jfSk(VAweB~BurLQ@wrT> zL=3M`6aATFn2v8_ zYq|4y`(Y=cQSYQkASB;ajwR+j($l^7+zbxetlWtTRdHya>!?@i6XMc&+JWp3S==ZP zn470Q{>&`4w-UW__C;DiT>mrZZAgnvM>KbuaENt=E`y)*2^rRj*c9oyG&1ri31qPA zjt1jTay`Hy0DJ9vceAKIaV>Fl*n3dBX97@NOe}&s1`l)~bZ<|Hq(VPw88=a(-6G|- zGj5;~$#vjU744mT)bTEEsYE(sqDnmEG3ibQUczOg<_J1%b*6)yicj%oQ2~h&Nztu=lv)Dmy}qDf!}}9oW8JxA%nn>?mw>KF^Ygc zEZTAm2j6=bV5sz1liA=Cr0U%LbgNrD;&JXlbhAtr4Vq}vF`i? z00q>`5n)yVgX+WgS6nQP8LWO4xg{Nl@~?B{>o#aaxZuT**Z?6$DvUPRjl1I2vZu)+ zA|en*VYPYj)#F*oJ_gYiuOia{4RkRrr*tse(y&hKi1!6&v}mUe=L=Wrc|$L+H+Ps! z%6yNFxc0mg4Scq|`7M3o8R!J0FJ6RhKe7eSr2rtAWxJER;Vu(Xb6@vewTBNMy7YSY zT5rQH=Rf_DoQ$-4g;s}c<5R}=-P9skx76!v1B%6jgrtt?cRm{2*eXDef_En5;1@Vm z!*m1gv9O@*+Q6nf{@tf>twq3V*Fhmk^aXf3K}>FLu6b_~7d17tj9{+(uFXCj*S>8? z@kEY^b=}(j0A`>@F0|ywk9%=PdwO+(dva1zEwT~fN2V2{6_y1gAfTKors9rEArq|V zSgQhDH8}jes;a81z;tai*W_2FOz*79N_S}gkgX@5&o>u^8^>=@K4D_Q+Q51IJYekl zoMn-5Cy^*wfdOoGcPpTgtV^JsD3ZAwbWVZtum&7n{Z`k^XKCr?{#3Jl@RptanDq(< z?*uq8#5GIT?Pd=Z?ioa}YdjE7ez4|jW^PX9F3QcVw6_nR+g(^#$j6`v6xUQG=|#$h zDv!l;x2zigk3XvzKNxn*EfezttfBA;Y$uu-+(5ZB4mL?y^sM0L_IDSrgH{*cBQLb? zG2tEZG~EReL?l};4VF>S0~B%QE{zvLBjNk6I;^!YLJsP>6-TxM73HrcluZl?VZ}+G zKj%p`yCiQZ2hr$%t%^f zcNqDXA317Sn}cdfIiR~@e|IJEMIY%l~IA=LJ41;Y&QSK@+r{j1qYlW z)Ym6x0C%(T_Kk$I0=!1w&O-ZZ@b$TX@+KEC-xbTGrR8Hj!f&ak)YH?`dSJ;N4A%;x z@-bL^tv}&4W9ccN)Ys=It61-(rjsFSmb)U+o6Kr&uOuWSG*V9QcT=Ct0lb5u4=_wN zzh75sZ*ESTqCW+>dpoJJDU((H%hzI)HrWpNdaECc(7ChfC_fQT8f*i%ej!=n`&UOw za`~qt(`?WcZB}(gXRtpiy}b~BjXI!bF4951mR%ix>5Q-42)#Ptv%kdlP4~Wd+&TiG zwZl7v#Q)0j#Cd`$BfX2vG23R-XTV>?PJ+I3mqJ}*fqG&vgdcaB8sp zuVsIYzodSLJUmB2V%1V&k19&p8pumeHzlfbYpv)DdSTK}G4{G!n2qd-<5UlMPh7ncCY}ykh;x&IruSQhXqP6;-(H>udo8IHSdmF>K2?V z!}2ggV?RZ(EJT(>1crtVRB!2)nXj1VYgefRkTdqGWVUh9m%H~}@o=xy^{zKrkgyu_ zdHE@9X?8Z9H3YlVCxaVWZ9CsNP^wxymYi(T#=Y2$%pA$EYa9ZWC-~Tf{Uc~80-b}h z`1*r_o@5DbC2l2+l7Yz^kk9YazcaT;wdDYEp6v7I4ld3e!GMCA4c>1+BjjZIX=kpO zM79M8`y3bxkUgyjG8Nn;4CLkIoBZXwhKJ=~TpTM@ zr_MZ5Ja#+LfQDCevRXO}F2992zfj%X+^nCJ6g3OX5LGwr{EhudhSapQEi`O$gz(6Z z%LPAyX5G^BIlZu)uw~`pr3c7A)3&ODkVn_>o6(^5DBGP5ja09LyV5^$XvDQy4Q78r zhpEKT2;}8kGB%{hFjnb$+cTy(FQhU<)g)pwRJg?>@N^DmaLYOI!f0h31+MVI!a@eG z)h9B7XYNwyqQmukrUgKIWugd7QGs?yrEYY4#RG_-%k-wu$|!B-`rKt7+cOnU93*q# zzx}D{&}RdLz4sHS2o=%`Ju*wcg%VAM)M$fiE-Ty@oblrC7-pzNuQX8F!G5!$L;FzFrlIzoi`Mgd{?)Lw30!O9 zUwylOTN8Vks({mpJ~lR16I(^PMc&Bs=FJ;ESByHb$*@;!hYoNlUh;}MO6CZAtfvEk zu-}AA35V@OiEhN^(dStB?C+Yn75!bi^Kw3h7Mw903y5l0 zCr0Iv}Fqr({zvGr9n!T`-Z zxz44_2b@f8Ho?=Et?X1rID37E+m|lpsATVtj{j7T-h3c}q^T4aC2S6a+JUz9hzoW_ zXP)Y=JrWYi0dC!@KRqcep4iSFnUc$F6L|7UmS5o2A_9^pZ$(*tJ9R$(*2ybawj~`T zKmK_I%fX$>lxG)+_|1=SbzIrzodEdnSCisqF-lT-Ic<>E~-oXEfEVcyki*VSE=1dB;lNywIJ>@vzS-!3e8$$BAMN%nYx`HHiU|GC1^hyIhjX&?3}D0 zwzCbuf)|V#m<`G44Z52&X1c3m*)7Plz6 z6|sQ8Rw)7kO7AEN2uSaQfYN&pNNAR=s0c`xj?y6nsR2R=7C=BiS^@+JN>6}D2_>P- zFYNET_kJ^HX3jl#W}Q2Cjcd7NAte9&%3Gf2ecsn_=Z`iSmO7SwNvMHc&=?*D{*D2& zin9FYW=_5YdEp1l+q#D>tuWA9CN4I``K2c6o|bNZ{nzvITC7D&g?^|OO#Vx(kKyt; z_N2s&_u3pHUpuSfh0RM0-q)tSRPLs(1X*6mDN!07yGLv-nv*j{8rYcbG)|j!hoc*p zkG^~rQ=hZ;`uG;YRH)Zmao6ts4^7QlSf@RQj1u9@?C}1%*~|7)8-!^q z#_WkqWnRykE?h}$L!d|5gWFyS5vJK{gXg$IZbc<~e)krUnVU*oZJh;?BI~b>!5l@e z-Z#6-Q!{2_Bt-4viNSImyzA`vp;s@Xdn&MjJ~<6=w=xFHS|xGd_tM>=l2re*TJfW! z9rKjf*0aK)dRum=+QkuZE%F%lDNj8$=AxqqJUlyWwMxcgSX7I1uYXI+#rpizEvZC!X~h4Bq(@~nb$mDdK)1j05}jkpyMeVgAvR;Wag-wy=}E~?D2jcogj*zuZp8@mhwsmePj)jT9TJWnu}=GgSWvd z{P6c2X_6(`Kg*WO{l)IQM)?V+yKJwz_2$_$O-JSGcD5qy`%<*^dpHBbC-KVU@%iVW z8(R0Y@lQwuE<&|#r-pnjab>$(y=Cre1=1isBctRTDWiltpBiCP@Jxr`KKk|)d87iK1rL*&JkqrTSI;7zjLh!)@yj?3 zeLsJkn~|r0_O@II%w5=TwUM5tyceX)pbOfA$~E1xG{Ba!T=MhtGn)HoKZ2#^7#Z~^ z1`5Fv3cAd;TYghU*y5}yP+FT=blAo*N2_b`d}u$ETYqH*=U_R1PX`A_;O1XuI~ArN z$9(nr)!;F2y+Ne@xQVo?cW%tLZ}*f}M) zY<1aIcL-O*W+oSl(^)SFEDX1Tb>O;U#j?qmZ{{vH)fLLonKgbFcVR9n3mouo!ks8VS`|TAHp_y=JYre$imNYpHstb+h)}-a6#w4t=a~!Kg+Z!W`NfmA z*K7A095PRx2M0vT>)Y?N#oim5pl-#O)^4s!PT_aw*V2s5#%Du!&A{z>6{58=P;Tyg zrEaI*5q{L< z;i~AA+fWh@H;uj;YXMJ*#=OZPjAx=eF}L}({39$;A9oNIhZ&z<$nln;$Fp7ks%^L= z4W8-6Mg1UqyGdGyVzw)x>1hYJf14+9rnw;Qd@Ld)Z`zN;t^`T!PPYxtCT9?Se(y~{ zgsw4HUqo5?HfgW=Ubzy(AZ{eu{YWmeJx==80@2oCOV;7A$tv@deLXdjhZNMPQVG6& z>#?P5RqEL&l~j3E&HD1$-GaJfN8|ZyslsWr<#c&9;xxS#w^CQp&Pn5)e!5Hsy#+VRwg+Z17ihb_*x2$)|862*uoy|hu1u3IxuT`5 zt=B8-A5kUDj<`Ddd-|nY2kM{8XqDIs-qlwLMOW++YL(T!WKrDvzJvWpY{qxh2b$3| z!RKT7D?CfV$wB@i&TwPI#4q2);fSGk3YWH6RjBy-=)n zEhuTSX|3&3z?o-rnHBlfR|IioW@gf+J|9{g+x>+_b5Wv_y}!Z@5*zvW3thBo1+&DJ z!pp(+U%5v8`O||&w5fHfI(@qQxKey_V7rCNxeK{di33U$@^F5phO)egaT_kjm0j~( zLs#88i1Hzjp)b=Ymw1z|9%xudfUr+?7K}JwbA@u}mQLFGtKjTL7AwZ0@R871aTn%B3 z&jtruA#erxDdr+!DJ&AHp}f6uD+M;dR{XA&P3;Wg*IQulKxl?Ma%7`MxN7fyT}<|? zH;IGl;y6RrRinPuQd^8uT&$%DzpMS?MDsyPkgu;9%}u5CYs$OGm~#qsJM3q@u9?$l zeX0J23jSgx%{wIw#{3r?X>9jt+v|z56V$>O&vdTY^Wd#`9@0e*Z!(H+r#q3q7Zi`6 zz0#7_r$#luLd;?F9VWl%#wUq}5Srszl>_c^p?AwZ|0rap z&zUb@bliwAb0r74J3r%55)dlYnHv1)+1??dPo$6cRW!HfE&7JrWYuQg{)YEF{!4t6 z3c{oEQ=?*E1kW_=z8yN&>gN!U!NVz!a$!rPc|+sJIhC!iXy{8l$xM_^Y6d>q^&^!s z_46kZ-^EFu>Gm9`a#x%TyK9YO<_FCJmAKEwUFALrZaS9KTv&3vU%sN%Iv4C@5c+hj z7^QvCnY4{8!>sVmUB3DuEh95Cy3l$Z&qzLzMxR#7hiMbu{Yp@{7_Lp*4f~XomGzDT z6ka=)FA1b(D))%vf;gf+*?6vrO!18k3$E&EbuqA&rH*@^=ga}I^9TK5h+FrXZ<@4s z1+YtEZH+z`E~Jj^1{Kxraf3SMx23?k&Vc}Vc*^^LBRiA38Tw1JHl0zLEjA^nKKZsJf^#MLB`+;&-t9pkP|MG zwaOz6?zj_?*%BDNoX8(*IoQDgRllQGQqQ@7u`cjqH@&pJ>B zYUy1r^07-28s@7$hYze7I(CjWI&?C+dE&=X!K}t;E)@99Du(5{;I*?MO;hXT;aD$; zC&U#vbZss7>D1JegLM3ZJsX(c82Va9HkN2H8WTmZ634+G5>jd8a%_0JP;KRL*H z{CIJ(D>HJe$cl?Iobc5lleKEhy@ycX=Q&ry;Pn-zS^h&w&sM8~xCp!Tw^I-2VI19M zx%9W0*T_|nb@KTPTlDnW+VQgC54p`@c6O8S&YU>1{N@F=kQql$vYkx>fW76-T)I@@&0%oN?mfpgViPtb#}A!m}vE4)#JTdr1Ksr3j=R zT1KA{A2sUj1$$-`-~RyK&wYJ6-yD`ut)xu^V%EWELBm3TN5*zpe(WM(UMcJ-?wNaa zeA-IV;1Ud%fMP0@^D)=KmV~oa{Z=z9>k};-eK>* z77bZ^fz*21}n^F)0R##?I`!$Mgk~pns{XhxyPCc5>Kiw3~_Qoo+onRz*Lx)w3w6 z@dGO*Mp{(tZla+kfeY%2n6^C=al;TmZp@GN?odc6@M$Zw;`dZw;j@O40`osBv zJ9*)@v=md&u2R;b=LD~vsrll>O}2T`?bUN-$$VYVIwNS%A^{eLDb~0z9bAW*4>fr$ z<4Gz_qSSJ}Ljj`(e6nR6F~*%)H3%6RfZA&m0pvk+Gb|JI!cASJ&qR{^L@5B}WKfsN z;$ly9S2aaav9S3I7t(HoJm#Ap7+$3#yq0Le=EcYjn+U7H(k;$xQ`#y%J(s6nXR<)3 z-_8)AEl%B*c>q(G9wLErdXf|pxzsf2G#0)W6<;|{h?3*=G%duAj+9|lHbYTHRmz|Q zW=ZDnE42CT*T=NgRf$X`f15q%dgLy8A=bK6dFSh&%05BacG+$0C)wVVmPR>!v-uMg zUPT?%N?Yw*QR*a|I5ALtG}olqZtEhE87%^<==wPsdB7!xN3~4I_FGpK3Y>VC6|O5$ zV}Xfb`-qRsH1Pg}EUp4(TnJLR=q1PD`i2IO;RU8Ge-uG@eNjH#ts}j?yGwT>Thw@u z-RbU@?@acG4~7NN`pQXqeQctfGehHL_U>V-VHr0@>4Sjr260447h{E6dF$6r)74e8 z#R+8GZy?_{LlWaD;k9NJYQbZn#$5JT%UlHw#TDbT-91^JYbYbjssd~=5fLE4Qr(UU zo@}7Ib+{uo$B8i^O^u+PIgG`W1T&0A!>Abh}d{7`jebOYB5)KnsR+8}9Mt`xN z;sS1aAAOiu874%2@WcrdgPaJI>_Yv^m(hfF$=Lvf%SO}IFw;Q-RG0IwDMgPEOQZcy z`x?M!dw+48dW@@YqLlyDwFPtloeAafEy?+fktm`tTo;7S$hq#*`=p!74w>k}N1 z8<3kq%Ruq!=T})m5AJO1?CehQ*mjg%n->6;sUy4!qe`x>y@0cE@bmqUzB>B(ca%RbM z%*SAWp%SlRusJVQZ@dDi8GuR;AEuXT+&2w2E18>{IRIg03elUT=hlYridr?@!j%o> ze4VSa?%aGBQWCUrqJfHna!gRoJ46$0BB;m8#_EjY*M2FZ-M<_PI_s(kvDRm%X{l2~fnE9~hV=o(b?`N#fK?yyYDw7VmsW>R#X0cN}J4xQh($rhWO+A|kW&9^k!6kr?RXY0t26 zr`?zbip(YK_>dX$8QCBc^Ke2>UQwQ-J`12arU0R?aT~u`mL~J2%6~W0@Bf1G5l%{9 z2J8l)1)c$vUbJoE8u01N8iMC+^)MS#VfnnKPZl`WlyIwRD-fcZf~;b&7E$9~q7!Kb zj+o5~%Ba4%L7TpV1P}p;^Z0~Hp^F6GXj6H@6K}4<&>Mt@bRs6?h_WAvTfRf?=ZJRg zR#*6XSI@`?M>L=7wupX_2F(o-(s8eB%RdqzQvj?U*lJBi_zm40EN6G9DKG0GdPF?^ zurDQb9O@fPf9(hu1~R?^UO}G!UXZF#?P_-aUlatWWvN9Sjx19(e ziN40eBDAF;!NK~lPV3HLGQ$-x8{==+^85O$3LXsA!DAbO8ZMC(*c0MwCN^k*Xkwsa zH1!Z)RYN!bH-$G$iI0A6cANESoLC?>mL-Z8(wMb+LV3Kx9>BK z6Kg<{JX&oCtFKS0B34L9O47c$^SXJ@J(#Rwfj@=cj(Wbbx@_d;mezgej%)uq_SMTy z#KAwZ-xM7+c6J?qz3eC4n$Y~jW2g}-9=$j4`+0!Nk_S-FIPqotK^uM}yk}8>ZDQUw zfbUDsEb2@D7!(BYDZ{9^{CfB{Nx1YozQi)D1|00BannSQq&(Hsb6IT71i-wBpLR*> z>-2(br>4@h1A|C%#q`F1%fvit`d20f5tB3V!ri@xw6LuXs1c$g2(B80pdV_dgVUG2 z|H$9(F@NDK2ejVoz>b_y9zGzhg9pA81n#Qn z?J_ZLtKn*80EN)-49RG&pMNt6zXPJKv&0(EIr~ZPNRR=b%{cddpg~&4r}?V_9`-CQ zF{5OjwCjP4jo9*~)$`9vD+jFQfz~;OM_;xB+V1;?s%XDRkBWn7E1ske0Ga5C_1WYx z?YsB7H?VCa^Bu<;@4%S4+W4@Ds!oDe9N!om8pO5~6eXOv!Nk@9`zw6zoHHf^J-o|e z*l?cNKSe@VNM2p5y|}f({L*-s@Jrhiq+~Mn!gommmxfk}!8j~8yTO);M`U}BVO0s0 z{LA~O|JSsGAFKS-!xVf2Vz}&tC`Z4}CfJ%)X~6j$VQBA}U8fB?>ydc7d^{ZDgRaWKko+>g> z9W7mBAKeJ)A}%DLf~0=cE^Q?T!QqCJ^h>SumMAS5Pkkf5SIG_`pH@FjZgljtiS(?1 zvuO6w8E^#JcN--jFUlw)NWkE?t^it=zc6pcver2zkdroLpv%4Yq(Ju~ptpHQu~AV~ zrq?ZMo&2+CqA)D8;Kc~fh&K%@w^r1I5&Jf~n&_h+l+eTfc+mZbyram^9NQB(Pg=5A zXTpIXF>ScZaKLHl_S{9ghA^@CMt%Nb16cD&wF{H2)W#&Dbmr#)4QT=R8njN>Gmg_| z?q3ru%pN%Zh~ z#gf2$k-IyUv9MM58E8t~#)J}5ux0Xdvd^UwL z<-+uwFTeNurtGADqvG7_>92Eg%2IyTag-NPI6tfh%+|0`8d0b5I?H7gsbl&1vp9eg z&Tcp9fdk++hJ5F>G^(MDsg)d8?2Hw~Wrw2!%>c6;U)gZShI=#_*|<_&Miu1-jxcT6C5CDW(@d@fQOi^yi9!Cd!9}u4vS~O}n@hp1)Fy|#3)cyh{ zB58qZxf%kO)oQOGm{pRzYa1g&nuv?=ai=Y=JM+xM&*1skK+`j@ehGX#?13gPwc3G) zpBp2CKnmV=D0hlFn=2#AH9wO+GW9l+()?o*v69~oxV;K`V@Woe{A|DkJ0fk03w)CX z$`U8i2BoK?>H{&Z0sa`jWBqmEFId(V&88FpvQ8{(dJmqsKjJytz>6a+F0)yOM(R9c zYnMjK0f+MXmTDf7>N@@@i3u~xt|&fCWh^623}K4nIi?XFNqnNvDy=KLT-Su$ z13H=XXr)Hex5Y6fO&cg?*Xh{X(_K8Xo(2DP3kWe~(*E6-wJc?6>9thj9@OG1>z)Gc z5Ds>(^0z||pYbRZyyED99!CEYo#)bElI*fSdB*zkJ+ojNm8!lUhBgm#^>ie?o(45A zY>hzdMivnRR^9s(0t7J@}-rMeCx`f|1U|-^>4(H4AIRYU_8jyG*d+MjqQJ;8jm?ssk8qLPJb!4GrDZbG~WotP#}*e&}H2ztAT4N8Zda2{M5Ylw?-_2K#8XyFVEXtFe}7-=C!|{@WeEa);@-Q zPXYTzpNm!GU-0ma@P7*rN7Gq50dv#_1WVwy0`SaeqQ7t9P|9y+8rSJBoC+V%AcPjM%@%I>BRl8AXTfTpd4zppC!p_Ny^cxX zD-H7Zn0|hi4diCKY4WoX@p+)C1Kz`4UK&9aa|6h;X;>o@*~697bug9i3-12_qd|z0 z3l8h^HR`*qsLBR(_rD8{PBqkb4O86-3Br$m{~YgdJkbx@qi2>2ooPKqz#qq1LbK2p zx{rX#e1{+toV_4e4cq!yirC8RK??Y*0Dd*{v;K5_HU^WfMPq^Oi|lf zU!5!9y%Iqb2(ai2SFD_77pC$6oP9fpiw*gR`|N+t;ErOg;go0fGiU6twFYW4-Cx*(U&vsp}| z2hU*A6m}28-3XUSK@UnEn)NZ!p=>P z2%dTh0PZ2{&-YwIRXIcw30<-^H}HV%OR)bleLHczM!M4*Z#L_hy!zN)&hqWRftD!> zrS$FF^E*Ht!zq#XaO^x}0@2q1cV8UGLIE-H9weorN%jIDpt5#&y)1s^%54yV2=QIL z33oeu*6q#HQKpfa0*C?ksbW7As)S4_6JS#VX*_BobMdM?zbVsn3dq>FriclBC+SNc zDrxT_lv>QXft>9M`2MN5UM5JAH)XPg2q`fGu@};&<}Up0GNT<;U0!C1dRf*DOl%b> zhmU65FF1JU5FCt2F_NFDx&QUeCGtp3DHxDq>GPwMSxEB8-6Hs85U9ht%6GN7fCkw2 z4iGSirsL7BSbo#-&oECbDGAT8XTDn_XPx<4N-5Wg8woI1TWFOvJ2Vq**?lBG62+WT z_V1m3`=5n0{r?c*|M|+J%+L1cf3s+-`7Qs8rQbR{;0kj?&wNapaB6>Z?KiZ0b`;+} z^lgy5UwpLRDD}A=7}AjhTFi2f9S1)>(J*1<6Zew|0H3Ly-;Esst)% zF+QHPu5eBJBN)3hfQyL8FDzuX5+{$=SLLSv27ceV--Bl~hDW*B+iB;$xAP9DyYHU0 zY6UIoH^xFRSs_ku)zsXE8jc?3q&Hs`wWu?SU+d6`rQp0{uJr-Bvm;3aKARaNEH7^f zW(-+@Cj;l6d+ZwIDm&0r@@XkTuw;HvPWev#>lu|3Nc_`>%zLg7vfTCi)+Fo zEpyYP-4z-v!D=pf;VW6o`3R;W&;8J}tzh+}Vu5?cNnP#< zQ&JkGEl8d$c8=8}_k|TzP^)@k3Eb!)a|45$T4}#=fl;%M!hkSBzTqf<3-a#tAGpU@ zQ!KNoYPS%-TJ1>4(^3}QoR+j#1{III`suLvnda7Haa+B8EyKN>q5U^~dJ=a7&n1g0 zy^$NWo@E8ZwF6a}g7!O|06cki?A$SI1o*_CK7FbIdN0tAzwYPHi;CqIK&_&7JJtm# zS27jPIX2K=*=?;%Gj|Xuy#|07QH`mJp19evBwW86>j~sN$ckN(tVYLh{hYkdx4E`6 z?Ebf44b_IT=_4I2E&QYvcf1$=wfL;-4lmJ<4PY|_ri_qW@5~dA!`a3WjZK!9kAf~| z*FYz`%8O5{{`za+dk%&%H+|y@&~Pojp}(>pu5@gmpfE@^uG_oJmc=o~3lr-*8G9Ex zmzKO5sv=_T2Ky=aZZh2cBfDH%o8Vj)Ba2Wu&9x$WjuUa`-8;>-me;)14|`L{0{|Z! zF+E>O@aPNMz_}c+^sBLN)1y2UvSrH3q(kryG-{AeG2Z;*zL2Cj^cDB0%y#{lMN>tX z4iLu?^KR9*fBkBZO?>X&KLcxZF0+y`LwkXFV%RjmOP=8g*X~UA{thIaAa%W|AR#wRol!()Qct zt#}|NylvI!P(~knKom3<)XV7oplKtcW>!@|lVrbiRNq8MR{wKVvnaKbn8f2J8Rm!Wnm;_$VN4c=N^q z2};E(ET8&GPId;ju2l6Xy>$m#Z0#iBxrE~KQoYPSC#x26ZALmU)Gh-L5ByCqD$lgq zZWt}E2K2uShHF>Ja06IeElYyur!V3QHnxW9>guj@-`@e)GzomZ@Xa4b_Rrk?%Pp*4 zK=x);#@IBe(6aYS0D@l@Hno8gM|)G0wPEZ@oFHjsx}(0Ni%mD0*7^9WnV8MJfd%SW zPKxn(g!+L4rmNSeWb*rWYBB(+qjK3G{Z7XW=;bzbnJOy0vfYmNp$(u|@@cu!t zhTzhytglNoT$+&%#VRiVk!XYW3G^X4}-*7haP z-5?%xH*h$z60Ur*XG~Jje@4-s*pn$an+LLZDP&a1^WVtH(2@C=1Im@6X*+}%EE#WK zCuV)Oa+v4z>7v$Xa*6MxkF@JWluTKAk=Ga}V!ghY|LkaG6Nyl%ep^||&*dGX$hc7B zCCynJ47J09KJ`-fn<43f-hTnM29mSJAzw$M5@5!=l29Y3O{;phTp(D6&4rtx=rAx2 zy+2iQwtA-=yMi?76{u_Z@};<^>?HIybZdnt?Z!?p8_$4Fk_cmZ$XV^v;JbwN@HSD( z@idU?Bi77QXC7*FB_<9S z&G(EWXykm}h;2jA%^LqJkZiJ>P{`c8580QG$R@PswU?_ndQyq!-ko&r5;x(EYJ$G= zJ|~KpeBsK+RsbQve&>B}+i&8W1YZbfNYCT!XG%!6D%*%fIi^-PC-Hdyh&KG@N z#lX`_wxTwhOHr4K-E({#Gq$x6uKer!Lw90V*Pzpbc_gvi$FBo7DrD>|A|y0CQoF(F zFYWeM5k+(nxmeMo-?P3nR#Tw6cL#K30Mt7n3mZ9D;y8JlQl7WAFl?-oe68ZBx1fI3 zwdK|Q+w9~cnR+jc_M;RGj!EH5?Q&9PjGD03uey2;H;A;^|D0r(UV0`wSiAFwd$UC9 zJ-SCX1npuzVZ@rlAsil>|8V1`6o}LygyCfk@MzS0a zRV&oXZ1*LB^{hHtwZTU5UbTU0t(hC4!dCDV_L@Kfjx^~8^;?icNA;|XsaIyATwnl3 zPe90C8@NFAC}L2QIT_O;GFWE_lXfwHzI*pEHOhfk?)_NE3Gz>M;&oa!A!|@Mh?Hf& zhbG}o*=@r$eSMDtt!IP%_XN(Jh2Lr9VZ&RGcV9(E5n{L*Yx5c2WmVQJN6gJk1}wGu zhO5?X?NR=PG6>h7lL*g_Yg&CH@btl=c~8Wz$G6<@)lE;Hicr4B-3^nbYNkI(?@GfH z(!F1cEbnR?#qubxfqg8A*xOYITzJcr`jWyK(eQEbaUPvESpc(5WJv=?T=*Ws#5?`@ z@9*sKisUJMR46;9gK?o0ZG2Zk1S3ztbSHdmqgSLb=~fRxT&c0=uk#LHSME65_Zk4fCt zrwjsz`0KQcCN<#j`&3p@+lpJf-D!m!A`v}s4NX;5?=e{o^OBvUJRW7l*ZzKEU*GkJ_W)gp_Ly!^ zrHy>svm$mjh3Yh^WT`JvO#)s&SCOb_W+p z>WWez{fMnA1IOM*Tj(=07F05uYB+EvX6#9N;ugw^q>?#^)_3OT=VuN&j1$b|xDaeL zKR*v>jsl0gX20|z%+ecNA6Gv-bQh>k8@dJG01$ALmQk987; zGHcDSs{Xa3)RRQou&nXuHRufAw$RdQA8GJJgQ%!*U_ffH=+t{F>DwF^t?La4Zq!|{ z5g^5K!sul=#pQqB$p>nc_0T7J8A@fi4IX@Bi^u@dkQ*!E#HZg2d0Of2(^;Z+_~c-z zxiPRo)$X{*k9S#*uMu>)t%hnyprP2u+b{+64UY(5tv!lNDjKa})_yxGpEKV5^(D{a zN^aniJhIR>6q=3Ot87#fNe)Pbuoi#WPX)C}rS_U7{)|QfRu_|jl61DOS&Chx|0LQb zZc>fz2jr2t8j8x$RS9Q19&1XI&f`|P8 z|MO>^gv2*|U>WBn`6bz%X+a{OL zXkvU?Nmyiz+v+;D(n6w;ezF_}OK6QTS^Q8EBg}F0(tf8euRmdmwMMh+UH;ok77o=m z8T7alywL+6UraVc3^?dMbgJ{B2Kx({AIo;W&c&F_eslyPmn$o)cYX`%x%1qRxJ#cciS84G1T z?snNCfcX)=WDl6Op6`8A$jZJ{;_B1qqvNJPxQVX4lG{ywx+ms$U;V%Q-#vi@n+vNs zK#q(gp53d~!>p^zeGrD!?^l#38k!#5p>4i+jIV96>x~#sEd_6I0?B$)Z-3oRBxb~0 z6{!jpy9O%nWgbElJ$R_=&X{|7HLT*-IZW1}o68k3;3Gad#CCo;^xb;-S!+vDPo@`o z6kIRPzb<7r)7@a3xA!cB=@BT@ zaIvVCpUou@2PWDJd89Gk-_vj%%?GL|?&>7(%{0G)IJ6jm63jDt3m_lwa%=992fgzCNF@INjvHSx8d-{(G&5!@6Gn?4| zw2=Eg%%cRla>?yq@Bi#y};Q(|+FcXf0Uz+l`{`9OrCPzS0H8*cAqyx{}zkz!qZ z<=^Fn@`$w}zWG8^E?R#{^a&IT-mq$7+ld^`ClS zT6(7;H{*cJ!qhvW`X=bp7bBMcjoGu**#l{=MxlU`IU5b z2~;coPq)0Y3v{G4-eh^f(CgGXrqUg_qxDnbnASjVRBel#CxqCDa& zc222HQ}|Kw-WKvm?e9BOSzX=Pvh>+Q#+eAl+p>-ZS&caIYbj*=+|ty)<2sp)lcrQr z2TI))qa)nvIzs9=FdC5c&x)Wv05l&@6+J7u2T#a)_(K=-mk#(oJM#!0;iP^4gKciC z_Y z3d`_C0xn2U`uCIl=26L|YQeE;gyT7Le_v^n@iASnE;@NsZH|svVo=h}2x*ip6d1LE zTzk@o=jd{rZT_jCaVJTKN`3S?tMd7x^0T5TDbCMM7hky9eV$oK4H-OIT5yEgG&Z6K zS|dE~QmkA=??yyu#is%3v|G&q<_UsK*oI-?A6$7APdWDQ{_h-*lk3gY{k!;xubt3l z>}5Hg85M=Qzq<1;o+o&ch3R>igQm2M)PAbx7Zg|$IYfr^Zc6;a?WEo-=o4eRy1M_- z-XzMWJD3r~S{E%}9@T0}I#8>A`-s_Ze~M%=A5iYQv+Z79 zi)y*ZuU+)$fOhP-YBNfDK{fQAq^eC0yP!T44X2K3+)CP6K=44+_n+4%2e>YUbLVU) zcDM*VO*w&HGv925d8yjNwa{xuefbV88H(kSH+&Vc?<*dCSsq)cp^7kn+;b>rYTwj& z8Kk4BLTfiJnI4n^4brEm6xczI16PHa_6Ar{t^w$nLXFt3T@{<*>>Q4ib_XL1mk)Fr z8Hk7#iorf^pFFthD3i_&Q%l`|N2U&4a`?#1W+sqF2qy=nq?q%A zZA$heN96qZ{{4H)#v!DmSXY^uP9N)PaI07=7hojphQ6X6}fB0sXy4B8SGnggS-E;8!pTEc zI}Et-!-p0X6ku>}E`zw>>0K=?(Lmk{7cR(nM&(cJ*bIvc2M*v6q(R*+{A6bJ8vMU{DGKM&g*7*QPfSbL*H(t+?wc#y|JIN-r<~!Yq zncdpa*HJYDBaWH({~9P=Gtky9d9R;6_$moU**V!{6dL-T&$SZ|OOt@t7U*4o&82}g zGYI`nw)v5;*)?&HhJfjii;Jn=IA-n}hM57)no<-<65lw-$HS<{bRYgOe17l!y_c_F zo7}zoA|vB`&OwOJwOyUx{?ydvjCB9`R~vFsCndfnV7UAQ^7pG@Rn9$TVBG22bc(H0 zNaPvNF$u(xZ%P@@X=qofs?V2ONsySTAgT=;uZp#9x(t8w0m#MY6D)t4gW!ARR~>zP zbhxVG1d_$)8nXdj9Js!I99&%GQ&VT$iJhhKhe{8;ehdMVf`5C$^~f4z)}001HYqK2 zk41j>`Nw;^Wtw%YTw|Rr8=$Y6(68Oa5l34SMZt32)clU5u&Vv7xOcCw*x30@u!Pl(8@@86BP?|H z87Moe^+|(d=ELxV=?saNm>|a54KUTZ|74VNv33#!GjLxfJt;BZqgdDh{xZ4GJpQac z=5(DpA48BcjFjGkT!qiFOYA|tz*V=_8V1Fp$6dbppLF{=F@6{rDOHAX_0Q|6_rSo{ zTAtARZ!}b-?qp?gEaEp}xD^LVba^qfBZ+xpu!b|3Smc4FUq3#_=ZT-)eGmQ`Ei@fy z?zOXHRZ;uB!3oieR=2STS~Zx;8HtCS8E6b%tq$Lz+tCb*jrf(9zp!(v zhBq0Tr|DC-Y0r{V(^wo3{VuLGay){iK2QQ8Np~XP?#!X3n>K{Ro7KH^o>^ z@*tNd+d9FY-h5DU4WhyO5HBxOWgc&J2o7}6x)vAyxbnSYXL5`fa3fmr3CuVR{F#dW ze>cp`;D$kbV3PHBS9}6E2)Ym9)fH$+XvmeP#qHS z*V#~+y=-G3zyQ2T0w0Ky<`cwIuKoa=ky4<3Oc*n{`r2z; zv-hhazUesRY69~bB%UIP?F9CuTU2Y*ULDaiL#)sEGpcp6c`HR=3n0mL63tE zR&3*G~3VdzgIUcG$Qygd&uwE-L%+!9WiBJ?h` z?5Hr+mjeGTYp4ey9qKj`k`2wSR==oR+)8sN)-*cxl0J;Yf(74kSm=;Gz$eB{y6Q4EZdyQ}NhU$I; z-1pZWB0$qxFp=v`Jk~f=Y(&%n$Rj(UY)7|nu$jia&Ky?KMK{|JW+ge1R7yF3XM%&x zOm-R`;HhRPhOs}+QlM%$aC55YsCRoyeFh+=CpSvqRrF!{Sc5;VX)hSNI}&!&cb2^> zjQ1=jvYR`NvUEWC*xIBlfVq-Uo3Ku^9n{yNYqtj5wLtnVwONbe94Su+rAw>q57=~%CY^>v2gl(CVKbRj-|;h+QaG|3K4_AEh>C(zcyZYtY#w86ydxg2|SB(kN@lx6&p!g(2<0L zMnv%@g2=QiUTNglcU@TJzJQ~mRP>TfMNl3QX zz;=s>ztTqBWTDi~Q*j#Qc^RiXGMjcWT*XFyX|G$**8Sr~sUJ4^MXn%+?^<5d)`J?G z?9DnauYRc>_nz2OOF!`33@P7{Hjq1BYV+63mM;t@m3@z&#<{N4MGh8+ts2$yj6U4I zz6U^BP9A;t48KzWi(hL?hH)-`J2R%57Yo|U2%rxhKhUY=GWaKL9&eK(?(EX_Tok_u zQ>cE^hD%5@S>LGel1=YIkXuqmu&SRL%Dl=9YFti>Mc8@+;~_*|llL5{h59b1>T{kJ z7jPwGvMK5M1z#N`97`X7S4!KYx8V)QOY)dyqSNmUd1d5I+aMo0SK`yAbvnN+PCLzl=4M@GX7jAc?{3+2v5bXv+h-gx~V# zc|-GoF|4ZH3BwLny4JawmY3Ma^)eS6++|lHi2)bx^dV+k+xCstb#ccR#iYreNXd>( zi5KIid{-5$UW&yzfXE7@e7*^)-`~rZm%1f&1e1`~=YR0*HU$@EWv{&J>z5?#ikNq6 zaa+k6J}e{q`TO@aJ=LrUBOKtjx!c#0=MWvTcw0B~S5ZTdn{f#^m`t_&BZ;5&ZA*Am z*r`{_*?(${M9jSvxVLk6$qVH+SlwhLQ%$U>V%vfpmdTl?^lT9=|)QBE?DPwD!E zEG>taNYo}8^~Y|aNlp}l!E_aZsJ?L?W~EwnjI|l^%9Z4AaUvLKMkj%R>f5uGO z_V#BP>O0_d@UMqgs~xsj)U%_zXc^#sNrx;2;nx$-@fcE3!{xKT;_fO-1g41z@H0Dd zt)4CWzFA1^sUbDW(Rs2|xJtDoXDn_*0W_SZwDiM6-+!`O&}}=y$+a!(HXv!zB>Yk2 z!Qwd456M%siPmN$sG3VW1rqGFAJr8l;awO{05y)(O?zWE=GBycfdeh^>u7Y^ujD4H z>QSe!xyqq?s|d=h;*o%!<;Y^bqz#|`A;BfnyGamAt*GLLBawF>ulCfBp`L)b@4d6Q+~!B~Ngy}d};R*n$A-$O`|?lswtF7I{x_NLGR!n4%NUHAIrr1=ob&%VpYz}OWB&2s@yz#mzW4pT z@9VnmtIu(&(bf`EdKYVZ#wO_az{DYFG`?B>v7s-jn!>NwAs8NUG0Baw17?J(Qtr&$ zuE%*yf!k0li#YMMgL7~8EauqUt(dp194$)rl@*!cz%@DciRC#m7PL9Dq*vkhSLliZc2)3=JwE$(&eGg^~)3hT6uAevo4 zynqlCH*me1yh0plo_O1=r^KMK3rid-Os#R?se76W)TKl2z$@z9v*pFnl@)&{)~6$W zDS{hcJdlNzm$I*IdFzZqiH7T5Ja6)}Bu<|`^O)M04Z4Pu#>p($q(mw8GwNhkbjshI z(2_SFFjQAKM^5*S9`w;ksdwt?l()pBhKC!&Y?6GgH>=mePP|r!Ww4)sejiCHY8!+X z!v-dokzM$XZqdOL@+(|_T17~?r-AZATth#JQd{u0vs~Ot@b82_J~f5cVbyBGk)(j2 z#+iveQCWVbfjf_Z0OkR6dv}-$7_wZd8d+6 zUff+6f^NLBOBZ{(TXlr5nWT(`G(HiqBP{wNJ$&v=o}me{JxirEtS5Zd6@BCcm0|Dn zq#X>)abOR;7o(7O(4SsU-83mxN4C^ZB~lD?1>felqCI$X3?dQg@NmEL{mc>1p!GQF z1988UlbEQQFzBkwC@GQp<-aL3z!Em~G+cLz@4~5QSXXj%vV(HJ#$4h1-?RJGTD=VA z0a{s%yR@0L+eJe{X<%^aqlUv|=VEuNzsr z-+h;VwlwCb7{$%4Hbgy5VN8jE^#L@V!0}ickvatG$_-~&Z8>-RN`K8v7pkg?LF=(S{ z57d{c@K@48Qbr6#)&4?9Cp#?I++IxZS{;jLBcJ0C;YkNV8F7i0_<$@*gUz5?Zf8xH z2d!YZ7NX}6#@RESyeswf!u+}zUcu(Gzsw-N8L{!_ML81+Y(|ffVXb19YCw196)xureI1MgvP6`j5qeTUlW-uUjGs& zn6&2m5KtX`L(Ow#<{`|3ICN1>D%M2A%iOE*ZT^4W?b))|UNrW=RPr;m)U*iQCjZ$F zl|r~cUnbpuYD|qyPfWcM)7H=+yLvT`l;^z>LGHvu_$1c|&&|u+Z0|@sUJPrB`;5=I z>H8YMsTpRp$i(V+H;GM0^IPJX+$b_($h}k6PP|)0D5T>DSwt@;*k&ONz)1UeCo0oV z;^VP8PaE-BGimeia1GnEyX2IX5RA`RGY#dyG;widtq`Va8m45nGfs@V7Y;lm?#uoA z9fFE(6ZtB^S0t{A*%e(qe_mx?yrRN}x7E7VUWvs%6QBWoeF5Hr8m;5XqFR9+(9aa$^~V<#~q6 z`N`)b8Q-aM;Ue}YnU+eFTsw&vNWDC5E}a@Va9`nj+0hv`r>6b$W!%K|4|jyz^_FVU zm&RBOd!E&EEnvlvrvy8x!jsJ^Ik<&Q2!43u-;ne-i& z-P}0u(CpzkPJ2;j59e6dnbV3tDe?_;atHM>V?ztnwR0DzsC>fDEq zRGBpfSOe$0<~fk&1BuA)N-OA#!oIj(wHMvxL&|UL3tyA zZ0^BPKrM1Tcovi;z!NO9%1>rv_-g~JeSPIgcx+A*XPwGgjC$Y%z2c@4-V{Wk#DyP+ zp_GJZ^|9p4>C>(??j{9sNy#ldZgQVPT=ifc*RIl=8PR^SmTzd3CA9Qg4xB)DNciUx ztJkRd{m<=Hd7mLH%RGa*f;I%&owtCnw%V~;!=2~1t+B`}SnbO-*@;|@jDisJSVvo> z+^}rR#$3I#Um9qdx;l3c2B9q#ca{blfX26fq?8tLb#Ub(PE7sEP?-9=F~jQjr0eT* zGa=`0M*8mdbv*4=b4+83Vf&dqj>k3AZ`2D#r>Yas7;antY!@-8WD=Dhq;pKNMbyl! ztjtP7s-PjI;C0cB9MXlh8LE2EJs&SqC}r}PE11~@2Ayfp6px?#Kr@Gv}M#*Zf zy_&aopFjIp3xgGOv&c&8=C4OYq91bZm~dWxy)+zOF8?O^#Z3wn5wH4O+la^}5{vi; z3w?`RiXeej6XPl+zjbGGKuL4bxm9s26i*BXHi5~}4$WATFpei3HVR#t&gjaJCGVwTy=Cr3eMZ%7u# z$IGkdrtGj z?gLEv$H6Rp3}9X-tLMUT*%tLb-{6glEb?i!ak&viHo>#!Re0P?Rj6Pc_IiA~tveW& z;XB(=NjUR(c32`E9*RSea>}a}{=hidkP16%s?RLC%`Gn#&GWjz3Y^!^Kjgo#q@ipm zr&j82GuC`(qOz*BKS0%c=?~C0hJ9i-l3hA%_ zzyDJvoO^BW7%`X8r!(8#8eJO)Bpph7nDp^;GFr&DoA2Ha?^20Dpi$pQqw0$$qG2e~ zb1Akx8&tVyrrUW|59`tr6;zRF=otE&SsXn0wv>o2D5r`3ynQa&E)e%{>y|$&eAaM< zRu6i(%g}2|Aal%%SF0uwqzgk+O@=JexBX;Oa=K2f+LHvuM_LNM!pW4q_$~curT8Bb zzsjeKTN}|qi&G2!oUYJSKehx#Vgl6N$dT;li@_1EZTKHqb1-uk*cnZ@)VpGqmX8zr zTua)%^j3M4K@Tn;6(Ui6dg_n{W@Q6lra*w`Nm|iUa^!cq2ElrXdQja&?+=`)U=P!d z+HZ>Ja>_}zlr5z)x5b!R^%ats`tZzekL#I%FP;qi+qHum1S77 zb{@VufVQ1T!(a&BE^|nRna_mPxBF=*C_nu*f5g`h+nsAC-kFqelD?F3wgu7D^BCQE z@1-UF$aBXezd?MlHqTb**KcCCmH5tm_;!auYhxz54F71NIDIdGE+>9AxqmuQz>OA{ zICU+S7nH|}1I`=4Lf{zH7+F=Csu|#u(XZ(KeEjpMJWL4SMy0F<&)!e;sod5Axpa?C zbfKmP94)f<7flIQq{dXBFP&Om%3t+vWB5;}449T;v!RxM4%_?D_ z3s`G|TGe$=6D^lE;*&vAxisOpI3=5DQi{D(!YbGzw1Xm)IosvPGHBg*V_Urp=VyAr zU8;ygRR%=+<^~m-<6(eD7w5gubVhX6H>xx(;c%p!5)l#?rQ`n8mypR`k{yT-R8^T zN1(8}f0~{L#D3Gh5gkAmRG#LPErdV&M>W$p%WmTPk31AcLMhww$iNrrP&icUa(9aL ztSk#bv%m--SpZrs9Mcrvz?v*6BfXv>L&i~Ea1hJ?U^tja<3sZfrz(ZbB7cRTf?o?% zH?4NQmQMX$ZcFB1{lqI1rrLcI_?=kqm5+}$@JxwU>{qycB6m7p$o}K0;kV+%mUy#9 zIS7tO3_xq62cK(K84-dLZmk8Q8bt)T4yXE&u0USN>=Bx5`WFx+0|;9papVW66O zv(Xj0=7c1KBpB?O>-^~|Ze+e)z?3YJRN;4rL1LBf1HUdBXL@^C@G@+l$wky+OD~kx$2zyoN-ynnuMC*463v zo(~GDs*hi3w$fT<$Qk$8%1SEf7gV!t8Ml>9b4^OFw~J}b{9@y1?H`92yp$rw?#XCn z*YR1olAug~wQ0EjQu?9uo<2T3<-NYVYEI$Q37Z@Qe2)%TDc>x_uGxp;{^Aq7I*&#( z3Wm5xioM7;k@uMI7J(I%NK$#p$t_N;cAUK~ScCtB>17@R-${`XNh97~abI=r@J!Y` zkT@PJ^->q;aEzI-u(;-nM^K)Z5uTAuCeZJYXt?9Yz$GU{3V^n=^uUOAlQ*r zXtz!8!Dl;=oTKE?aQ%0Gk8b*-^*u>#v8^)IrH77r^&Hx$LC!tfOlt=!>3vyYvWkl5 z$b5eP2eY%ds!A=IHxBnAF)?@j`aof9CSDciO5pP8lGAhZIgIfZ(oEYHRwcKYmLyn^r^XwTerR!yW2hq z=G#}>yjIZOActa?ePAh;+3x%ak3I2c z{K+gv@0_u!|KeK^oE+5!V!A(Wp8HHqqQJ+|K<-6~^waGO0Ne_D;($wU zHE&*n`ak3rbhjWhgT8;Kx4R1soWbTP zOyjJeqeXp5td**2jY%3UnHdep@}oy}w|Th3 z*ucO{aB8@k``p^)<=g+JG0f6X|1`rem5z){&h2UI*6l=%UaK14bk3YI76mW@Fq-k8 z3E8Mh0W&j%Hxl2~HA!O-umsV*>Y6%e&Vc8d^hK2bWeReoHdkdAxROPc?}tr0MBg4W zelG(kQ-}RJRP*nT4vgN|L8r#SO|f~!9d_rL*nWYpQD zY0gFR=0El$HzNZSn1gvhDA+MQGSttvUvYP)-psDCE*_LpP-%`MRJ!($;jaI4pltW( z9~ZWwWKO`hM-BT00M%!Wz;qknOv6rz4Y{Ex zZffA+q{G?y&SJxj+rOPdX*mJuZPV|fqIssWQ^(Z@mz*fD-m5F|Y*EhVMC9LB@hoy2 zS(}x{2`Z}hr_IADh`xnB#5t6>uwATE2h<3X{x+lj7awduy;20H-R&73nHBvX+`iY?=U!O~4ZP>t5S|DrB13tGW*gkq zPfRTKv3&wV@Je{4u0!v{tHs-&f2vmE)VgP1*ccs1{@~31dVy+Mdh4BVCHdT`XDrtX^|cp9jx9#F<$^vLLRaFI_xX+85H{ zBfD25J}osa_%JXlfcpVNw6tJ1jpe$3MF!saTU|r8|J{g2z|x(%x-e#^$hA&7B>lYc zf*tpAa&mw>JF@oHJ^tfsjRy=fn8}r?C*yTBE{X3Rn1;G=;lf^F;dh`Xb{?w0;jJr6 zGWCuJP5sdn6ZEH@uA1-9Y|SJM!_>AFEKKC4FuSrMyB5YT_y4GbC*s`WkVe$-Zq>$H z%PKYogZInC%ylC^U(>nsT-C+*{1HBN7ty(^ahA7UGF>lT-l8_R+IkfvE%Wp9z&EP0 zUfqB?vSsH^3b8|{l&VVg2LXqm4UFy{>z%nK30D7#!^}DAA?z%rJ8x5 zYSwMGviR40ue-8Ko%Ml1<-5xkXK{Co=tP@cUh>uvA-$u83mZZ|*thHhVz9yt41 zgLz;Vmlb_N zqE#xkr)fn=U{VAIer3CRK};>FOA%~D0jYZ@s=-sT%Fo~5qJDtS-6qED&MZFvymAzA1)RAJf@cfuGxV%ED+qnj??dpuO^K4JsT zjIq(t=rO|YAKTXZtuCst%W=1(BHU>cqn|S0D9pLJ1VBn)mK;PqsM^&F85KrORyy~6 ze1|Qt(f5^o0<5207>!O@LOf)KRyEj5tz=lgm*c0lZWTeYZmxEt8gBLe)ITxe;B^>Nk-NI$>ukQ*e65QTirGM7jKj_tq1aw#XQdyl-mW~OidYG)euc1yVTTtkCRn7 z5XVgk7Q$d4i)2hN+@#p5Ey3{p`hJ~q&&fshTEaFo+N;|hbygjS0haF7rocoyoVN~j zMa*#U+F{>$>^U2o*kW%|yy&UGG{ClTl>pCBzG29`MCF_;s$d~$ ziOH870QBm|`1{1Woj|+V;)+6rfidyEh|Gw(NH=&}=|h#JyZ7u7-n~0xvL!y(xd$)l zZ{X0=F^X9-10?AVeF-2 VzF-T;amdegFBx3Szi{Kxe*h(}+*$wt literal 0 HcmV?d00001 From 9afda2c5b72bfddb86fb9ce733d214b77b408cd6 Mon Sep 17 00:00:00 2001 From: Andre Richter Date: Mon, 2 May 2022 23:59:55 +0200 Subject: [PATCH 23/75] Add rust-src to toolchain components --- rust-toolchain.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain.toml b/rust-toolchain.toml index a24afec2..9667a009 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,4 +1,4 @@ [toolchain] channel = "nightly-2022-04-10" -components = ["llvm-tools-preview", "rustfmt"] +components = ["rust-src", "llvm-tools-preview", "rustfmt"] targets = ["aarch64-unknown-none-softfloat"] From f0b7f819af7dbd466fcc62e27eac356dd20ef03a Mon Sep 17 00:00:00 2001 From: Andre Richter Date: Tue, 3 May 2022 00:18:19 +0200 Subject: [PATCH 24/75] Update README.md --- 18_backtrace/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/18_backtrace/README.md b/18_backtrace/README.md index 0963df1d..1ea270d8 100644 --- a/18_backtrace/README.md +++ b/18_backtrace/README.md @@ -227,7 +227,7 @@ match backtrace_res { Finally, we add printing of a backtrace to `panic!`: -``` +```rust panic_println!( "[ {:>3}.{:06}] Kernel panic!\n\n\ Panic location:\n File '{}', line {}, column {}\n\n\ From f6190f85b7e1907d06cc79aa6c6b9afa45cae891 Mon Sep 17 00:00:00 2001 From: Andre Richter Date: Tue, 3 May 2022 23:53:45 +0200 Subject: [PATCH 25/75] ASM: Remove use of .equ The LLVM assembler apparently causes the .equ directive to create symbols instead of just a local and temporary variable. Work around this by using const operands with global_asm!. --- 01_wait_forever/src/_arch/aarch64/cpu/boot.rs | 4 +- 02_runtime_init/README.md | 23 +++++--- 02_runtime_init/src/_arch/aarch64/cpu/boot.rs | 7 ++- 02_runtime_init/src/_arch/aarch64/cpu/boot.s | 4 +- 02_runtime_init/src/main.rs | 1 + 03_hacky_hello_world/README.md | 6 +- .../src/_arch/aarch64/cpu/boot.rs | 7 ++- .../src/_arch/aarch64/cpu/boot.s | 4 +- 03_hacky_hello_world/src/main.rs | 1 + 04_safe_globals/README.md | 8 +-- 04_safe_globals/src/_arch/aarch64/cpu/boot.rs | 7 ++- 04_safe_globals/src/_arch/aarch64/cpu/boot.s | 4 +- 04_safe_globals/src/main.rs | 1 + 05_drivers_gpio_uart/README.md | 6 +- .../src/_arch/aarch64/cpu/boot.rs | 7 ++- .../src/_arch/aarch64/cpu/boot.s | 4 +- 05_drivers_gpio_uart/src/main.rs | 1 + 06_uart_chainloader/README.md | 8 +-- 06_uart_chainloader/demo_payload_rpi3.img | Bin 7960 -> 7960 bytes 06_uart_chainloader/demo_payload_rpi4.img | Bin 7872 -> 7872 bytes .../src/_arch/aarch64/cpu/boot.rs | 7 ++- .../src/_arch/aarch64/cpu/boot.s | 4 +- 06_uart_chainloader/src/main.rs | 1 + 07_timestamps/README.md | 10 ++-- 07_timestamps/src/_arch/aarch64/cpu/boot.rs | 7 ++- 07_timestamps/src/_arch/aarch64/cpu/boot.s | 4 +- 07_timestamps/src/main.rs | 1 + .../src/_arch/aarch64/cpu/boot.rs | 7 ++- 08_hw_debug_JTAG/src/_arch/aarch64/cpu/boot.s | 4 +- 08_hw_debug_JTAG/src/main.rs | 1 + 09_privilege_level/README.md | 53 ++++++++---------- .../src/_arch/aarch64/cpu/boot.rs | 6 +- .../src/_arch/aarch64/cpu/boot.s | 7 +-- 09_privilege_level/src/main.rs | 1 + .../README.md | 11 ++-- .../src/_arch/aarch64/cpu/boot.rs | 6 +- .../src/_arch/aarch64/cpu/boot.s | 7 +-- .../src/main.rs | 1 + 11_exceptions_part1_groundwork/README.md | 4 +- .../src/_arch/aarch64/cpu/boot.rs | 6 +- .../src/_arch/aarch64/cpu/boot.s | 7 +-- 11_exceptions_part1_groundwork/src/main.rs | 1 + .../kernel/src/_arch/aarch64/cpu/boot.rs | 6 +- .../kernel/src/_arch/aarch64/cpu/boot.s | 7 +-- 12_integrated_testing/kernel/src/lib.rs | 1 + 13_exceptions_part2_peripheral_IRQs/README.md | 10 +--- .../kernel/src/_arch/aarch64/cpu/boot.rs | 6 +- .../kernel/src/_arch/aarch64/cpu/boot.s | 7 +-- .../kernel/src/_arch/aarch64/cpu/boot.rs | 6 +- .../kernel/src/_arch/aarch64/cpu/boot.s | 7 +-- .../README.md | 4 +- .../kernel/src/_arch/aarch64/cpu/boot.rs | 6 +- .../kernel/src/_arch/aarch64/cpu/boot.s | 7 +-- .../README.md | 14 ++--- .../kernel/src/_arch/aarch64/cpu/boot.rs | 6 +- .../kernel/src/_arch/aarch64/cpu/boot.s | 7 +-- .../kernel/src/_arch/aarch64/cpu/boot.rs | 6 +- .../kernel/src/_arch/aarch64/cpu/boot.s | 7 +-- 18_backtrace/README.md | 25 +++++++-- .../kernel/src/_arch/aarch64/cpu/boot.rs | 6 +- .../kernel/src/_arch/aarch64/cpu/boot.s | 7 +-- .../kernel/src/_arch/aarch64/exception.rs | 6 +- .../kernel/src/_arch/aarch64/exception.s | 4 +- X1_JTAG_boot/jtag_boot_rpi3.img | Bin 9000 -> 9000 bytes X1_JTAG_boot/jtag_boot_rpi4.img | Bin 7888 -> 7888 bytes X1_JTAG_boot/src/_arch/aarch64/cpu/boot.rs | 7 ++- X1_JTAG_boot/src/_arch/aarch64/cpu/boot.s | 4 +- X1_JTAG_boot/src/main.rs | 1 + 68 files changed, 244 insertions(+), 182 deletions(-) diff --git a/01_wait_forever/src/_arch/aarch64/cpu/boot.rs b/01_wait_forever/src/_arch/aarch64/cpu/boot.rs index b5cc68fc..77d3d99f 100644 --- a/01_wait_forever/src/_arch/aarch64/cpu/boot.rs +++ b/01_wait_forever/src/_arch/aarch64/cpu/boot.rs @@ -11,5 +11,7 @@ //! //! crate::cpu::boot::arch_boot +use core::arch::global_asm; + // Assembly counterpart to this file. -core::arch::global_asm!(include_str!("boot.s")); +global_asm!(include_str!("boot.s")); diff --git a/02_runtime_init/README.md b/02_runtime_init/README.md index 02ed0488..7e4f5c0a 100644 --- a/02_runtime_init/README.md +++ b/02_runtime_init/README.md @@ -65,10 +65,15 @@ diff -uNr 01_wait_forever/Makefile 02_runtime_init/Makefile diff -uNr 01_wait_forever/src/_arch/aarch64/cpu/boot.rs 02_runtime_init/src/_arch/aarch64/cpu/boot.rs --- 01_wait_forever/src/_arch/aarch64/cpu/boot.rs +++ 02_runtime_init/src/_arch/aarch64/cpu/boot.rs -@@ -13,3 +13,15 @@ +@@ -14,4 +14,19 @@ + use core::arch::global_asm; // Assembly counterpart to this file. - core::arch::global_asm!(include_str!("boot.s")); +-global_asm!(include_str!("boot.s")); ++global_asm!( ++ include_str!("boot.s"), ++ CONST_CORE_ID_MASK = const 0b11 ++); + +//-------------------------------------------------------------------------------------------------- +// Public Code @@ -85,7 +90,7 @@ diff -uNr 01_wait_forever/src/_arch/aarch64/cpu/boot.rs 02_runtime_init/src/_arc diff -uNr 01_wait_forever/src/_arch/aarch64/cpu/boot.s 02_runtime_init/src/_arch/aarch64/cpu/boot.s --- 01_wait_forever/src/_arch/aarch64/cpu/boot.s +++ 02_runtime_init/src/_arch/aarch64/cpu/boot.s -@@ -3,6 +3,24 @@ +@@ -3,6 +3,22 @@ // Copyright (c) 2021-2022 Andre Richter //-------------------------------------------------------------------------------------------------- @@ -104,19 +109,17 @@ diff -uNr 01_wait_forever/src/_arch/aarch64/cpu/boot.s 02_runtime_init/src/_arch + add \register, \register, #:lo12:\symbol +.endm + -+.equ _core_id_mask, 0b11 -+ +//-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- .section .text._start -@@ -11,6 +29,34 @@ +@@ -11,6 +27,34 @@ // fn _start() //------------------------------------------------------------------------------ _start: + // Only proceed on the boot core. Park it otherwise. + mrs x1, MPIDR_EL1 -+ and x1, x1, _core_id_mask ++ and x1, x1, {CONST_CORE_ID_MASK} + ldr x2, BOOT_CORE_ID // provided by bsp/__board_name__/cpu.rs + cmp x1, x2 + b.ne .L_parking_loop @@ -302,15 +305,17 @@ diff -uNr 01_wait_forever/src/cpu.rs 02_runtime_init/src/cpu.rs diff -uNr 01_wait_forever/src/main.rs 02_runtime_init/src/main.rs --- 01_wait_forever/src/main.rs +++ 02_runtime_init/src/main.rs -@@ -104,6 +104,7 @@ +@@ -104,7 +104,9 @@ //! //! 1. The kernel's entry point is the function `cpu::boot::arch_boot::_start()`. //! - It is implemented in `src/_arch/__arch_name__/cpu/boot.s`. +//! 2. Once finished with architectural setup, the arch code calls `kernel_init()`. ++#![feature(asm_const)] #![no_main] #![no_std] -@@ -112,4 +113,11 @@ + +@@ -112,4 +114,11 @@ mod cpu; mod panic_wait; diff --git a/02_runtime_init/src/_arch/aarch64/cpu/boot.rs b/02_runtime_init/src/_arch/aarch64/cpu/boot.rs index 2f9654c7..8390c013 100644 --- a/02_runtime_init/src/_arch/aarch64/cpu/boot.rs +++ b/02_runtime_init/src/_arch/aarch64/cpu/boot.rs @@ -11,8 +11,13 @@ //! //! crate::cpu::boot::arch_boot +use core::arch::global_asm; + // Assembly counterpart to this file. -core::arch::global_asm!(include_str!("boot.s")); +global_asm!( + include_str!("boot.s"), + CONST_CORE_ID_MASK = const 0b11 +); //-------------------------------------------------------------------------------------------------- // Public Code diff --git a/02_runtime_init/src/_arch/aarch64/cpu/boot.s b/02_runtime_init/src/_arch/aarch64/cpu/boot.s index 7d445a93..1f70169f 100644 --- a/02_runtime_init/src/_arch/aarch64/cpu/boot.s +++ b/02_runtime_init/src/_arch/aarch64/cpu/boot.s @@ -18,8 +18,6 @@ add \register, \register, #:lo12:\symbol .endm -.equ _core_id_mask, 0b11 - //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- @@ -31,7 +29,7 @@ _start: // Only proceed on the boot core. Park it otherwise. mrs x1, MPIDR_EL1 - and x1, x1, _core_id_mask + and x1, x1, {CONST_CORE_ID_MASK} ldr x2, BOOT_CORE_ID // provided by bsp/__board_name__/cpu.rs cmp x1, x2 b.ne .L_parking_loop diff --git a/02_runtime_init/src/main.rs b/02_runtime_init/src/main.rs index 42653ac4..e16354ed 100644 --- a/02_runtime_init/src/main.rs +++ b/02_runtime_init/src/main.rs @@ -106,6 +106,7 @@ //! - It is implemented in `src/_arch/__arch_name__/cpu/boot.s`. //! 2. Once finished with architectural setup, the arch code calls `kernel_init()`. +#![feature(asm_const)] #![no_main] #![no_std] diff --git a/03_hacky_hello_world/README.md b/03_hacky_hello_world/README.md index 30a717e8..d868459f 100644 --- a/03_hacky_hello_world/README.md +++ b/03_hacky_hello_world/README.md @@ -212,10 +212,10 @@ diff -uNr 02_runtime_init/src/console.rs 03_hacky_hello_world/src/console.rs diff -uNr 02_runtime_init/src/main.rs 03_hacky_hello_world/src/main.rs --- 02_runtime_init/src/main.rs +++ 03_hacky_hello_world/src/main.rs -@@ -106,12 +106,16 @@ - //! - It is implemented in `src/_arch/__arch_name__/cpu/boot.s`. +@@ -107,12 +107,16 @@ //! 2. Once finished with architectural setup, the arch code calls `kernel_init()`. + #![feature(asm_const)] +#![feature(format_args_nl)] +#![feature(panic_info_message)] #![no_main] @@ -229,7 +229,7 @@ diff -uNr 02_runtime_init/src/main.rs 03_hacky_hello_world/src/main.rs /// Early init code. /// -@@ -119,5 +123,7 @@ +@@ -120,5 +124,7 @@ /// /// - Only a single core must be active and running this function. unsafe fn kernel_init() -> ! { diff --git a/03_hacky_hello_world/src/_arch/aarch64/cpu/boot.rs b/03_hacky_hello_world/src/_arch/aarch64/cpu/boot.rs index 2f9654c7..8390c013 100644 --- a/03_hacky_hello_world/src/_arch/aarch64/cpu/boot.rs +++ b/03_hacky_hello_world/src/_arch/aarch64/cpu/boot.rs @@ -11,8 +11,13 @@ //! //! crate::cpu::boot::arch_boot +use core::arch::global_asm; + // Assembly counterpart to this file. -core::arch::global_asm!(include_str!("boot.s")); +global_asm!( + include_str!("boot.s"), + CONST_CORE_ID_MASK = const 0b11 +); //-------------------------------------------------------------------------------------------------- // Public Code diff --git a/03_hacky_hello_world/src/_arch/aarch64/cpu/boot.s b/03_hacky_hello_world/src/_arch/aarch64/cpu/boot.s index 7d445a93..1f70169f 100644 --- a/03_hacky_hello_world/src/_arch/aarch64/cpu/boot.s +++ b/03_hacky_hello_world/src/_arch/aarch64/cpu/boot.s @@ -18,8 +18,6 @@ add \register, \register, #:lo12:\symbol .endm -.equ _core_id_mask, 0b11 - //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- @@ -31,7 +29,7 @@ _start: // Only proceed on the boot core. Park it otherwise. mrs x1, MPIDR_EL1 - and x1, x1, _core_id_mask + and x1, x1, {CONST_CORE_ID_MASK} ldr x2, BOOT_CORE_ID // provided by bsp/__board_name__/cpu.rs cmp x1, x2 b.ne .L_parking_loop diff --git a/03_hacky_hello_world/src/main.rs b/03_hacky_hello_world/src/main.rs index 67b0551b..74b621de 100644 --- a/03_hacky_hello_world/src/main.rs +++ b/03_hacky_hello_world/src/main.rs @@ -106,6 +106,7 @@ //! - It is implemented in `src/_arch/__arch_name__/cpu/boot.s`. //! 2. Once finished with architectural setup, the arch code calls `kernel_init()`. +#![feature(asm_const)] #![feature(format_args_nl)] #![feature(panic_info_message)] #![no_main] diff --git a/04_safe_globals/README.md b/04_safe_globals/README.md index 8eff4a67..18827b5c 100644 --- a/04_safe_globals/README.md +++ b/04_safe_globals/README.md @@ -224,15 +224,15 @@ diff -uNr 03_hacky_hello_world/src/console.rs 04_safe_globals/src/console.rs diff -uNr 03_hacky_hello_world/src/main.rs 04_safe_globals/src/main.rs --- 03_hacky_hello_world/src/main.rs +++ 04_safe_globals/src/main.rs -@@ -108,6 +108,7 @@ - +@@ -109,6 +109,7 @@ + #![feature(asm_const)] #![feature(format_args_nl)] #![feature(panic_info_message)] +#![feature(trait_alias)] #![no_main] #![no_std] -@@ -116,6 +117,7 @@ +@@ -117,6 +118,7 @@ mod cpu; mod panic_wait; mod print; @@ -240,7 +240,7 @@ diff -uNr 03_hacky_hello_world/src/main.rs 04_safe_globals/src/main.rs /// Early init code. /// -@@ -123,7 +125,15 @@ +@@ -124,7 +126,15 @@ /// /// - Only a single core must be active and running this function. unsafe fn kernel_init() -> ! { diff --git a/04_safe_globals/src/_arch/aarch64/cpu/boot.rs b/04_safe_globals/src/_arch/aarch64/cpu/boot.rs index 2f9654c7..8390c013 100644 --- a/04_safe_globals/src/_arch/aarch64/cpu/boot.rs +++ b/04_safe_globals/src/_arch/aarch64/cpu/boot.rs @@ -11,8 +11,13 @@ //! //! crate::cpu::boot::arch_boot +use core::arch::global_asm; + // Assembly counterpart to this file. -core::arch::global_asm!(include_str!("boot.s")); +global_asm!( + include_str!("boot.s"), + CONST_CORE_ID_MASK = const 0b11 +); //-------------------------------------------------------------------------------------------------- // Public Code diff --git a/04_safe_globals/src/_arch/aarch64/cpu/boot.s b/04_safe_globals/src/_arch/aarch64/cpu/boot.s index 7d445a93..1f70169f 100644 --- a/04_safe_globals/src/_arch/aarch64/cpu/boot.s +++ b/04_safe_globals/src/_arch/aarch64/cpu/boot.s @@ -18,8 +18,6 @@ add \register, \register, #:lo12:\symbol .endm -.equ _core_id_mask, 0b11 - //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- @@ -31,7 +29,7 @@ _start: // Only proceed on the boot core. Park it otherwise. mrs x1, MPIDR_EL1 - and x1, x1, _core_id_mask + and x1, x1, {CONST_CORE_ID_MASK} ldr x2, BOOT_CORE_ID // provided by bsp/__board_name__/cpu.rs cmp x1, x2 b.ne .L_parking_loop diff --git a/04_safe_globals/src/main.rs b/04_safe_globals/src/main.rs index b45e3a35..15db4a21 100644 --- a/04_safe_globals/src/main.rs +++ b/04_safe_globals/src/main.rs @@ -106,6 +106,7 @@ //! - It is implemented in `src/_arch/__arch_name__/cpu/boot.s`. //! 2. Once finished with architectural setup, the arch code calls `kernel_init()`. +#![feature(asm_const)] #![feature(format_args_nl)] #![feature(panic_info_message)] #![feature(trait_alias)] diff --git a/05_drivers_gpio_uart/README.md b/05_drivers_gpio_uart/README.md index 5787ac12..6f0057d6 100644 --- a/05_drivers_gpio_uart/README.md +++ b/05_drivers_gpio_uart/README.md @@ -1342,10 +1342,10 @@ diff -uNr 04_safe_globals/src/main.rs 05_drivers_gpio_uart/src/main.rs //! 2. Once finished with architectural setup, the arch code calls `kernel_init()`. +#![allow(clippy::upper_case_acronyms)] + #![feature(asm_const)] #![feature(format_args_nl)] #![feature(panic_info_message)] - #![feature(trait_alias)] -@@ -115,6 +116,7 @@ +@@ -116,6 +117,7 @@ mod bsp; mod console; mod cpu; @@ -1353,7 +1353,7 @@ diff -uNr 04_safe_globals/src/main.rs 05_drivers_gpio_uart/src/main.rs mod panic_wait; mod print; mod synchronization; -@@ -124,16 +126,54 @@ +@@ -125,16 +127,54 @@ /// # Safety /// /// - Only a single core must be active and running this function. diff --git a/05_drivers_gpio_uart/src/_arch/aarch64/cpu/boot.rs b/05_drivers_gpio_uart/src/_arch/aarch64/cpu/boot.rs index 2f9654c7..8390c013 100644 --- a/05_drivers_gpio_uart/src/_arch/aarch64/cpu/boot.rs +++ b/05_drivers_gpio_uart/src/_arch/aarch64/cpu/boot.rs @@ -11,8 +11,13 @@ //! //! crate::cpu::boot::arch_boot +use core::arch::global_asm; + // Assembly counterpart to this file. -core::arch::global_asm!(include_str!("boot.s")); +global_asm!( + include_str!("boot.s"), + CONST_CORE_ID_MASK = const 0b11 +); //-------------------------------------------------------------------------------------------------- // Public Code diff --git a/05_drivers_gpio_uart/src/_arch/aarch64/cpu/boot.s b/05_drivers_gpio_uart/src/_arch/aarch64/cpu/boot.s index 7d445a93..1f70169f 100644 --- a/05_drivers_gpio_uart/src/_arch/aarch64/cpu/boot.s +++ b/05_drivers_gpio_uart/src/_arch/aarch64/cpu/boot.s @@ -18,8 +18,6 @@ add \register, \register, #:lo12:\symbol .endm -.equ _core_id_mask, 0b11 - //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- @@ -31,7 +29,7 @@ _start: // Only proceed on the boot core. Park it otherwise. mrs x1, MPIDR_EL1 - and x1, x1, _core_id_mask + and x1, x1, {CONST_CORE_ID_MASK} ldr x2, BOOT_CORE_ID // provided by bsp/__board_name__/cpu.rs cmp x1, x2 b.ne .L_parking_loop diff --git a/05_drivers_gpio_uart/src/main.rs b/05_drivers_gpio_uart/src/main.rs index 9ee5a43c..2e8bfeaa 100644 --- a/05_drivers_gpio_uart/src/main.rs +++ b/05_drivers_gpio_uart/src/main.rs @@ -107,6 +107,7 @@ //! 2. Once finished with architectural setup, the arch code calls `kernel_init()`. #![allow(clippy::upper_case_acronyms)] +#![feature(asm_const)] #![feature(format_args_nl)] #![feature(panic_info_message)] #![feature(trait_alias)] diff --git a/06_uart_chainloader/README.md b/06_uart_chainloader/README.md index 8c21ccfa..20c120d4 100644 --- a/06_uart_chainloader/README.md +++ b/06_uart_chainloader/README.md @@ -277,10 +277,10 @@ diff -uNr 05_drivers_gpio_uart/src/_arch/aarch64/cpu/boot.s 06_uart_chainloader/ + movk \register, #:abs_g0_nc:\symbol +.endm + - .equ _core_id_mask, 0b11 - //-------------------------------------------------------------------------------------------------- -@@ -39,23 +50,35 @@ + // Public Code + //-------------------------------------------------------------------------------------------------- +@@ -37,23 +48,35 @@ // If execution reaches here, it is the boot core. // Initialize DRAM. @@ -457,7 +457,7 @@ diff -uNr 05_drivers_gpio_uart/src/bsp/raspberrypi/memory.rs 06_uart_chainloader diff -uNr 05_drivers_gpio_uart/src/main.rs 06_uart_chainloader/src/main.rs --- 05_drivers_gpio_uart/src/main.rs +++ 06_uart_chainloader/src/main.rs -@@ -142,38 +142,56 @@ +@@ -143,38 +143,56 @@ kernel_main() } diff --git a/06_uart_chainloader/demo_payload_rpi3.img b/06_uart_chainloader/demo_payload_rpi3.img index b422ad25ac3df2dfa5f0d19917a13ebc15e3944a..1da3bec56b3f76bf826e7d2f7f8c513059965b8c 100755 GIT binary patch delta 14 VcmbPXH^Xj&gbZWHW=Wa `EL1` transition by calling @@ -211,19 +211,21 @@ diff -uNr 08_hw_debug_JTAG/Cargo.toml 09_privilege_level/Cargo.toml diff -uNr 08_hw_debug_JTAG/src/_arch/aarch64/cpu/boot.rs 09_privilege_level/src/_arch/aarch64/cpu/boot.rs --- 08_hw_debug_JTAG/src/_arch/aarch64/cpu/boot.rs +++ 09_privilege_level/src/_arch/aarch64/cpu/boot.rs -@@ -11,8 +11,53 @@ - //! +@@ -12,21 +12,72 @@ //! crate::cpu::boot::arch_boot -+use core::arch::global_asm; + use core::arch::global_asm; +use cortex_a::{asm, registers::*}; +use tock_registers::interfaces::Writeable; -+ + // Assembly counterpart to this file. --core::arch::global_asm!(include_str!("boot.s")); -+global_asm!(include_str!("boot.s")); -+ -+//-------------------------------------------------------------------------------------------------- + global_asm!( + include_str!("boot.s"), ++ CONST_CURRENTEL_EL2 = const 0x8, + CONST_CORE_ID_MASK = const 0b11 + ); + + //-------------------------------------------------------------------------------------------------- +// Private Code +//-------------------------------------------------------------------------------------------------- + @@ -263,10 +265,11 @@ diff -uNr 08_hw_debug_JTAG/src/_arch/aarch64/cpu/boot.rs 09_privilege_level/src/ + // are no plans to ever return to EL2, just re-use the same stack. + SP_EL1.set(phys_boot_core_stack_end_exclusive_addr); +} - - //-------------------------------------------------------------------------------------------------- ++ ++//-------------------------------------------------------------------------------------------------- // Public Code -@@ -21,7 +66,14 @@ + //-------------------------------------------------------------------------------------------------- + /// The Rust entry of the `kernel` binary. /// /// The function is called from the assembly `_start` function. @@ -287,27 +290,19 @@ diff -uNr 08_hw_debug_JTAG/src/_arch/aarch64/cpu/boot.rs 09_privilege_level/src/ diff -uNr 08_hw_debug_JTAG/src/_arch/aarch64/cpu/boot.s 09_privilege_level/src/_arch/aarch64/cpu/boot.s --- 08_hw_debug_JTAG/src/_arch/aarch64/cpu/boot.s +++ 09_privilege_level/src/_arch/aarch64/cpu/boot.s -@@ -18,6 +18,7 @@ - add \register, \register, #:lo12:\symbol - .endm - -+.equ _EL2, 0x8 - .equ _core_id_mask, 0b11 - - //-------------------------------------------------------------------------------------------------- -@@ -29,6 +30,11 @@ +@@ -27,6 +27,11 @@ // fn _start() //------------------------------------------------------------------------------ _start: + // Only proceed if the core executes in EL2. Park it otherwise. + mrs x0, CurrentEL -+ cmp x0, _EL2 ++ cmp x0, {CONST_CURRENTEL_EL2} + b.ne .L_parking_loop + // Only proceed on the boot core. Park it otherwise. mrs x1, MPIDR_EL1 - and x1, x1, _core_id_mask -@@ -50,11 +56,11 @@ + and x1, x1, {CONST_CORE_ID_MASK} +@@ -48,11 +53,11 @@ // Prepare the jump to Rust code. .L_prepare_rust: @@ -502,7 +497,7 @@ diff -uNr 08_hw_debug_JTAG/src/exception.rs 09_privilege_level/src/exception.rs diff -uNr 08_hw_debug_JTAG/src/main.rs 09_privilege_level/src/main.rs --- 08_hw_debug_JTAG/src/main.rs +++ 09_privilege_level/src/main.rs -@@ -117,6 +117,7 @@ +@@ -118,6 +118,7 @@ mod console; mod cpu; mod driver; @@ -510,7 +505,7 @@ diff -uNr 08_hw_debug_JTAG/src/main.rs 09_privilege_level/src/main.rs mod panic_wait; mod print; mod synchronization; -@@ -145,6 +146,8 @@ +@@ -146,6 +147,8 @@ /// The main function running after the early init. fn kernel_main() -> ! { @@ -519,7 +514,7 @@ diff -uNr 08_hw_debug_JTAG/src/main.rs 09_privilege_level/src/main.rs use core::time::Duration; use driver::interface::DriverManager; use time::interface::TimeManager; -@@ -156,6 +159,12 @@ +@@ -157,6 +160,12 @@ ); info!("Booting on: {}", bsp::board_name()); @@ -532,7 +527,7 @@ diff -uNr 08_hw_debug_JTAG/src/main.rs 09_privilege_level/src/main.rs info!( "Architectural timer resolution: {} ns", time::time_manager().resolution().as_nanos() -@@ -170,11 +179,15 @@ +@@ -171,11 +180,15 @@ info!(" {}. {}", i + 1, driver.compatible()); } diff --git a/09_privilege_level/src/_arch/aarch64/cpu/boot.rs b/09_privilege_level/src/_arch/aarch64/cpu/boot.rs index f677c9c4..0bf45b83 100644 --- a/09_privilege_level/src/_arch/aarch64/cpu/boot.rs +++ b/09_privilege_level/src/_arch/aarch64/cpu/boot.rs @@ -16,7 +16,11 @@ use cortex_a::{asm, registers::*}; use tock_registers::interfaces::Writeable; // Assembly counterpart to this file. -global_asm!(include_str!("boot.s")); +global_asm!( + include_str!("boot.s"), + CONST_CURRENTEL_EL2 = const 0x8, + CONST_CORE_ID_MASK = const 0b11 +); //-------------------------------------------------------------------------------------------------- // Private Code diff --git a/09_privilege_level/src/_arch/aarch64/cpu/boot.s b/09_privilege_level/src/_arch/aarch64/cpu/boot.s index 28b35087..7576dc14 100644 --- a/09_privilege_level/src/_arch/aarch64/cpu/boot.s +++ b/09_privilege_level/src/_arch/aarch64/cpu/boot.s @@ -18,9 +18,6 @@ add \register, \register, #:lo12:\symbol .endm -.equ _EL2, 0x8 -.equ _core_id_mask, 0b11 - //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- @@ -32,12 +29,12 @@ _start: // Only proceed if the core executes in EL2. Park it otherwise. mrs x0, CurrentEL - cmp x0, _EL2 + cmp x0, {CONST_CURRENTEL_EL2} b.ne .L_parking_loop // Only proceed on the boot core. Park it otherwise. mrs x1, MPIDR_EL1 - and x1, x1, _core_id_mask + and x1, x1, {CONST_CORE_ID_MASK} ldr x2, BOOT_CORE_ID // provided by bsp/__board_name__/cpu.rs cmp x1, x2 b.ne .L_parking_loop diff --git a/09_privilege_level/src/main.rs b/09_privilege_level/src/main.rs index b1b1bc27..0c6a0dec 100644 --- a/09_privilege_level/src/main.rs +++ b/09_privilege_level/src/main.rs @@ -107,6 +107,7 @@ //! 2. Once finished with architectural setup, the arch code calls `kernel_init()`. #![allow(clippy::upper_case_acronyms)] +#![feature(asm_const)] #![feature(format_args_nl)] #![feature(panic_info_message)] #![feature(trait_alias)] diff --git a/10_virtual_mem_part1_identity_mapping/README.md b/10_virtual_mem_part1_identity_mapping/README.md index 3a5539c9..802243c8 100644 --- a/10_virtual_mem_part1_identity_mapping/README.md +++ b/10_virtual_mem_part1_identity_mapping/README.md @@ -1081,16 +1081,17 @@ diff -uNr 09_privilege_level/src/bsp.rs 10_virtual_mem_part1_identity_mapping/sr diff -uNr 09_privilege_level/src/main.rs 10_virtual_mem_part1_identity_mapping/src/main.rs --- 09_privilege_level/src/main.rs +++ 10_virtual_mem_part1_identity_mapping/src/main.rs -@@ -107,6 +107,8 @@ +@@ -107,7 +107,9 @@ //! 2. Once finished with architectural setup, the arch code calls `kernel_init()`. #![allow(clippy::upper_case_acronyms)] +#![allow(incomplete_features)] + #![feature(asm_const)] +#![feature(core_intrinsics)] #![feature(format_args_nl)] #![feature(panic_info_message)] #![feature(trait_alias)] -@@ -118,6 +120,7 @@ +@@ -119,6 +121,7 @@ mod cpu; mod driver; mod exception; @@ -1098,7 +1099,7 @@ diff -uNr 09_privilege_level/src/main.rs 10_virtual_mem_part1_identity_mapping/s mod panic_wait; mod print; mod synchronization; -@@ -128,9 +131,17 @@ +@@ -129,9 +132,17 @@ /// # Safety /// /// - Only a single core must be active and running this function. @@ -1117,7 +1118,7 @@ diff -uNr 09_privilege_level/src/main.rs 10_virtual_mem_part1_identity_mapping/s for i in bsp::driver::driver_manager().all_device_drivers().iter() { if let Err(x) = i.init() { -@@ -159,6 +170,9 @@ +@@ -160,6 +171,9 @@ ); info!("Booting on: {}", bsp::board_name()); @@ -1127,7 +1128,7 @@ diff -uNr 09_privilege_level/src/main.rs 10_virtual_mem_part1_identity_mapping/s let (_, privilege_level) = exception::current_privilege_level(); info!("Current privilege level: {}", privilege_level); -@@ -182,6 +196,13 @@ +@@ -183,6 +197,13 @@ info!("Timer test, spinning for 1 second"); time::time_manager().spin_for(Duration::from_secs(1)); diff --git a/10_virtual_mem_part1_identity_mapping/src/_arch/aarch64/cpu/boot.rs b/10_virtual_mem_part1_identity_mapping/src/_arch/aarch64/cpu/boot.rs index f677c9c4..0bf45b83 100644 --- a/10_virtual_mem_part1_identity_mapping/src/_arch/aarch64/cpu/boot.rs +++ b/10_virtual_mem_part1_identity_mapping/src/_arch/aarch64/cpu/boot.rs @@ -16,7 +16,11 @@ use cortex_a::{asm, registers::*}; use tock_registers::interfaces::Writeable; // Assembly counterpart to this file. -global_asm!(include_str!("boot.s")); +global_asm!( + include_str!("boot.s"), + CONST_CURRENTEL_EL2 = const 0x8, + CONST_CORE_ID_MASK = const 0b11 +); //-------------------------------------------------------------------------------------------------- // Private Code diff --git a/10_virtual_mem_part1_identity_mapping/src/_arch/aarch64/cpu/boot.s b/10_virtual_mem_part1_identity_mapping/src/_arch/aarch64/cpu/boot.s index 28b35087..7576dc14 100644 --- a/10_virtual_mem_part1_identity_mapping/src/_arch/aarch64/cpu/boot.s +++ b/10_virtual_mem_part1_identity_mapping/src/_arch/aarch64/cpu/boot.s @@ -18,9 +18,6 @@ add \register, \register, #:lo12:\symbol .endm -.equ _EL2, 0x8 -.equ _core_id_mask, 0b11 - //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- @@ -32,12 +29,12 @@ _start: // Only proceed if the core executes in EL2. Park it otherwise. mrs x0, CurrentEL - cmp x0, _EL2 + cmp x0, {CONST_CURRENTEL_EL2} b.ne .L_parking_loop // Only proceed on the boot core. Park it otherwise. mrs x1, MPIDR_EL1 - and x1, x1, _core_id_mask + and x1, x1, {CONST_CORE_ID_MASK} ldr x2, BOOT_CORE_ID // provided by bsp/__board_name__/cpu.rs cmp x1, x2 b.ne .L_parking_loop diff --git a/10_virtual_mem_part1_identity_mapping/src/main.rs b/10_virtual_mem_part1_identity_mapping/src/main.rs index 327f3ce0..dde224e7 100644 --- a/10_virtual_mem_part1_identity_mapping/src/main.rs +++ b/10_virtual_mem_part1_identity_mapping/src/main.rs @@ -108,6 +108,7 @@ #![allow(clippy::upper_case_acronyms)] #![allow(incomplete_features)] +#![feature(asm_const)] #![feature(core_intrinsics)] #![feature(format_args_nl)] #![feature(panic_info_message)] diff --git a/11_exceptions_part1_groundwork/README.md b/11_exceptions_part1_groundwork/README.md index d0b86c55..81e633be 100644 --- a/11_exceptions_part1_groundwork/README.md +++ b/11_exceptions_part1_groundwork/README.md @@ -1024,7 +1024,7 @@ diff -uNr 10_virtual_mem_part1_identity_mapping/src/exception.rs 11_exceptions_p diff -uNr 10_virtual_mem_part1_identity_mapping/src/main.rs 11_exceptions_part1_groundwork/src/main.rs --- 10_virtual_mem_part1_identity_mapping/src/main.rs +++ 11_exceptions_part1_groundwork/src/main.rs -@@ -139,6 +139,8 @@ +@@ -140,6 +140,8 @@ use driver::interface::DriverManager; use memory::mmu::interface::MMU; @@ -1033,7 +1033,7 @@ diff -uNr 10_virtual_mem_part1_identity_mapping/src/main.rs 11_exceptions_part1_ if let Err(string) = memory::mmu::mmu().enable_mmu_and_caching() { panic!("MMU: {}", string); } -@@ -196,13 +198,28 @@ +@@ -197,13 +199,28 @@ info!("Timer test, spinning for 1 second"); time::time_manager().spin_for(Duration::from_secs(1)); diff --git a/11_exceptions_part1_groundwork/src/_arch/aarch64/cpu/boot.rs b/11_exceptions_part1_groundwork/src/_arch/aarch64/cpu/boot.rs index f677c9c4..0bf45b83 100644 --- a/11_exceptions_part1_groundwork/src/_arch/aarch64/cpu/boot.rs +++ b/11_exceptions_part1_groundwork/src/_arch/aarch64/cpu/boot.rs @@ -16,7 +16,11 @@ use cortex_a::{asm, registers::*}; use tock_registers::interfaces::Writeable; // Assembly counterpart to this file. -global_asm!(include_str!("boot.s")); +global_asm!( + include_str!("boot.s"), + CONST_CURRENTEL_EL2 = const 0x8, + CONST_CORE_ID_MASK = const 0b11 +); //-------------------------------------------------------------------------------------------------- // Private Code diff --git a/11_exceptions_part1_groundwork/src/_arch/aarch64/cpu/boot.s b/11_exceptions_part1_groundwork/src/_arch/aarch64/cpu/boot.s index 28b35087..7576dc14 100644 --- a/11_exceptions_part1_groundwork/src/_arch/aarch64/cpu/boot.s +++ b/11_exceptions_part1_groundwork/src/_arch/aarch64/cpu/boot.s @@ -18,9 +18,6 @@ add \register, \register, #:lo12:\symbol .endm -.equ _EL2, 0x8 -.equ _core_id_mask, 0b11 - //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- @@ -32,12 +29,12 @@ _start: // Only proceed if the core executes in EL2. Park it otherwise. mrs x0, CurrentEL - cmp x0, _EL2 + cmp x0, {CONST_CURRENTEL_EL2} b.ne .L_parking_loop // Only proceed on the boot core. Park it otherwise. mrs x1, MPIDR_EL1 - and x1, x1, _core_id_mask + and x1, x1, {CONST_CORE_ID_MASK} ldr x2, BOOT_CORE_ID // provided by bsp/__board_name__/cpu.rs cmp x1, x2 b.ne .L_parking_loop diff --git a/11_exceptions_part1_groundwork/src/main.rs b/11_exceptions_part1_groundwork/src/main.rs index 0c88c58e..96743601 100644 --- a/11_exceptions_part1_groundwork/src/main.rs +++ b/11_exceptions_part1_groundwork/src/main.rs @@ -108,6 +108,7 @@ #![allow(clippy::upper_case_acronyms)] #![allow(incomplete_features)] +#![feature(asm_const)] #![feature(core_intrinsics)] #![feature(format_args_nl)] #![feature(panic_info_message)] diff --git a/12_integrated_testing/kernel/src/_arch/aarch64/cpu/boot.rs b/12_integrated_testing/kernel/src/_arch/aarch64/cpu/boot.rs index f677c9c4..0bf45b83 100644 --- a/12_integrated_testing/kernel/src/_arch/aarch64/cpu/boot.rs +++ b/12_integrated_testing/kernel/src/_arch/aarch64/cpu/boot.rs @@ -16,7 +16,11 @@ use cortex_a::{asm, registers::*}; use tock_registers::interfaces::Writeable; // Assembly counterpart to this file. -global_asm!(include_str!("boot.s")); +global_asm!( + include_str!("boot.s"), + CONST_CURRENTEL_EL2 = const 0x8, + CONST_CORE_ID_MASK = const 0b11 +); //-------------------------------------------------------------------------------------------------- // Private Code diff --git a/12_integrated_testing/kernel/src/_arch/aarch64/cpu/boot.s b/12_integrated_testing/kernel/src/_arch/aarch64/cpu/boot.s index 28b35087..7576dc14 100644 --- a/12_integrated_testing/kernel/src/_arch/aarch64/cpu/boot.s +++ b/12_integrated_testing/kernel/src/_arch/aarch64/cpu/boot.s @@ -18,9 +18,6 @@ add \register, \register, #:lo12:\symbol .endm -.equ _EL2, 0x8 -.equ _core_id_mask, 0b11 - //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- @@ -32,12 +29,12 @@ _start: // Only proceed if the core executes in EL2. Park it otherwise. mrs x0, CurrentEL - cmp x0, _EL2 + cmp x0, {CONST_CURRENTEL_EL2} b.ne .L_parking_loop // Only proceed on the boot core. Park it otherwise. mrs x1, MPIDR_EL1 - and x1, x1, _core_id_mask + and x1, x1, {CONST_CORE_ID_MASK} ldr x2, BOOT_CORE_ID // provided by bsp/__board_name__/cpu.rs cmp x1, x2 b.ne .L_parking_loop diff --git a/12_integrated_testing/kernel/src/lib.rs b/12_integrated_testing/kernel/src/lib.rs index 442de9e0..2de7d6cc 100644 --- a/12_integrated_testing/kernel/src/lib.rs +++ b/12_integrated_testing/kernel/src/lib.rs @@ -110,6 +110,7 @@ #![allow(clippy::upper_case_acronyms)] #![allow(incomplete_features)] +#![feature(asm_const)] #![feature(core_intrinsics)] #![feature(format_args_nl)] #![feature(linkage)] diff --git a/13_exceptions_part2_peripheral_IRQs/README.md b/13_exceptions_part2_peripheral_IRQs/README.md index 5938da9e..d6c6a7e4 100644 --- a/13_exceptions_part2_peripheral_IRQs/README.md +++ b/13_exceptions_part2_peripheral_IRQs/README.md @@ -2398,15 +2398,7 @@ diff -uNr 12_integrated_testing/kernel/src/exception/asynchronous.rs 13_exceptio diff -uNr 12_integrated_testing/kernel/src/lib.rs 13_exceptions_part2_peripheral_IRQs/kernel/src/lib.rs --- 12_integrated_testing/kernel/src/lib.rs +++ 13_exceptions_part2_peripheral_IRQs/kernel/src/lib.rs -@@ -110,6 +110,7 @@ - - #![allow(clippy::upper_case_acronyms)] - #![allow(incomplete_features)] -+#![feature(asm_const)] - #![feature(core_intrinsics)] - #![feature(format_args_nl)] - #![feature(linkage)] -@@ -132,6 +133,7 @@ +@@ -133,6 +133,7 @@ pub mod exception; pub mod memory; pub mod print; diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/cpu/boot.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/cpu/boot.rs index f677c9c4..0bf45b83 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/cpu/boot.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/cpu/boot.rs @@ -16,7 +16,11 @@ use cortex_a::{asm, registers::*}; use tock_registers::interfaces::Writeable; // Assembly counterpart to this file. -global_asm!(include_str!("boot.s")); +global_asm!( + include_str!("boot.s"), + CONST_CURRENTEL_EL2 = const 0x8, + CONST_CORE_ID_MASK = const 0b11 +); //-------------------------------------------------------------------------------------------------- // Private Code diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/cpu/boot.s b/13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/cpu/boot.s index 28b35087..7576dc14 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/cpu/boot.s +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/cpu/boot.s @@ -18,9 +18,6 @@ add \register, \register, #:lo12:\symbol .endm -.equ _EL2, 0x8 -.equ _core_id_mask, 0b11 - //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- @@ -32,12 +29,12 @@ _start: // Only proceed if the core executes in EL2. Park it otherwise. mrs x0, CurrentEL - cmp x0, _EL2 + cmp x0, {CONST_CURRENTEL_EL2} b.ne .L_parking_loop // Only proceed on the boot core. Park it otherwise. mrs x1, MPIDR_EL1 - and x1, x1, _core_id_mask + and x1, x1, {CONST_CORE_ID_MASK} ldr x2, BOOT_CORE_ID // provided by bsp/__board_name__/cpu.rs cmp x1, x2 b.ne .L_parking_loop diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/cpu/boot.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/cpu/boot.rs index f677c9c4..0bf45b83 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/cpu/boot.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/cpu/boot.rs @@ -16,7 +16,11 @@ use cortex_a::{asm, registers::*}; use tock_registers::interfaces::Writeable; // Assembly counterpart to this file. -global_asm!(include_str!("boot.s")); +global_asm!( + include_str!("boot.s"), + CONST_CURRENTEL_EL2 = const 0x8, + CONST_CORE_ID_MASK = const 0b11 +); //-------------------------------------------------------------------------------------------------- // Private Code diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/cpu/boot.s b/14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/cpu/boot.s index 28b35087..7576dc14 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/cpu/boot.s +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/cpu/boot.s @@ -18,9 +18,6 @@ add \register, \register, #:lo12:\symbol .endm -.equ _EL2, 0x8 -.equ _core_id_mask, 0b11 - //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- @@ -32,12 +29,12 @@ _start: // Only proceed if the core executes in EL2. Park it otherwise. mrs x0, CurrentEL - cmp x0, _EL2 + cmp x0, {CONST_CURRENTEL_EL2} b.ne .L_parking_loop // Only proceed on the boot core. Park it otherwise. mrs x1, MPIDR_EL1 - and x1, x1, _core_id_mask + and x1, x1, {CONST_CORE_ID_MASK} ldr x2, BOOT_CORE_ID // provided by bsp/__board_name__/cpu.rs cmp x1, x2 b.ne .L_parking_loop diff --git a/15_virtual_mem_part3_precomputed_tables/README.md b/15_virtual_mem_part3_precomputed_tables/README.md index 9ec33fc0..5836e12f 100644 --- a/15_virtual_mem_part3_precomputed_tables/README.md +++ b/15_virtual_mem_part3_precomputed_tables/README.md @@ -819,7 +819,7 @@ diff -uNr 14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/cpu/boot.rs 1 use core::arch::global_asm; use cortex_a::{asm, registers::*}; use tock_registers::interfaces::Writeable; -@@ -71,9 +72,16 @@ +@@ -75,9 +76,16 @@ /// /// - Exception return from EL2 must must continue execution in EL1 with `kernel_init()`. #[no_mangle] @@ -841,7 +841,7 @@ diff -uNr 14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/cpu/boot.rs 1 diff -uNr 14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/cpu/boot.s 15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/cpu/boot.s --- 14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/cpu/boot.s +++ 15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/cpu/boot.s -@@ -56,11 +56,14 @@ +@@ -53,11 +53,14 @@ // Prepare the jump to Rust code. .L_prepare_rust: diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/cpu/boot.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/cpu/boot.rs index 0a606a48..a66c0cb3 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/cpu/boot.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/cpu/boot.rs @@ -17,7 +17,11 @@ use cortex_a::{asm, registers::*}; use tock_registers::interfaces::Writeable; // Assembly counterpart to this file. -global_asm!(include_str!("boot.s")); +global_asm!( + include_str!("boot.s"), + CONST_CURRENTEL_EL2 = const 0x8, + CONST_CORE_ID_MASK = const 0b11 +); //-------------------------------------------------------------------------------------------------- // Private Code diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/cpu/boot.s b/15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/cpu/boot.s index dd2b50b8..dba8c88e 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/cpu/boot.s +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/cpu/boot.s @@ -18,9 +18,6 @@ add \register, \register, #:lo12:\symbol .endm -.equ _EL2, 0x8 -.equ _core_id_mask, 0b11 - //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- @@ -32,12 +29,12 @@ _start: // Only proceed if the core executes in EL2. Park it otherwise. mrs x0, CurrentEL - cmp x0, _EL2 + cmp x0, {CONST_CURRENTEL_EL2} b.ne .L_parking_loop // Only proceed on the boot core. Park it otherwise. mrs x1, MPIDR_EL1 - and x1, x1, _core_id_mask + and x1, x1, {CONST_CORE_ID_MASK} ldr x2, BOOT_CORE_ID // provided by bsp/__board_name__/cpu.rs cmp x1, x2 b.ne .L_parking_loop diff --git a/16_virtual_mem_part4_higher_half_kernel/README.md b/16_virtual_mem_part4_higher_half_kernel/README.md index 32259671..a9282d80 100644 --- a/16_virtual_mem_part4_higher_half_kernel/README.md +++ b/16_virtual_mem_part4_higher_half_kernel/README.md @@ -340,7 +340,7 @@ diff -uNr 15_virtual_mem_part3_precomputed_tables/kernel/Cargo.toml 16_virtual_m diff -uNr 15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/cpu/boot.rs 16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/cpu/boot.rs --- 15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/cpu/boot.rs +++ 16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/cpu/boot.rs -@@ -30,7 +30,10 @@ +@@ -34,7 +34,10 @@ /// - The `bss` section is not initialized yet. The code must not use or reference it in any way. /// - The HW state of EL1 must be prepared in a sound way. #[inline(always)] @@ -352,7 +352,7 @@ diff -uNr 15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/cpu/b // Enable timer counter registers for EL1. CNTHCTL_EL2.write(CNTHCTL_EL2::EL1PCEN::SET + CNTHCTL_EL2::EL1PCTEN::SET); -@@ -53,11 +56,11 @@ +@@ -57,11 +60,11 @@ ); // Second, let the link register point to kernel_init(). @@ -366,7 +366,7 @@ diff -uNr 15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/cpu/b } //-------------------------------------------------------------------------------------------------- -@@ -74,14 +77,19 @@ +@@ -78,14 +81,19 @@ #[no_mangle] pub unsafe extern "C" fn _start_rust( phys_kernel_tables_base_addr: u64, @@ -409,10 +409,10 @@ diff -uNr 15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/cpu/b + movk \register, #:abs_g0_nc:\symbol +.endm + - .equ _EL2, 0x8 - .equ _core_id_mask, 0b11 - -@@ -59,11 +71,23 @@ + //-------------------------------------------------------------------------------------------------- + // Public Code + //-------------------------------------------------------------------------------------------------- +@@ -56,11 +68,23 @@ // Load the base address of the kernel's translation tables. ldr x0, PHYS_KERNEL_TABLES_BASE_ADDR // provided by bsp/__board_name__/memory/mmu.rs diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/cpu/boot.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/cpu/boot.rs index 3d01b0dc..293d4608 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/cpu/boot.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/cpu/boot.rs @@ -17,7 +17,11 @@ use cortex_a::{asm, registers::*}; use tock_registers::interfaces::Writeable; // Assembly counterpart to this file. -global_asm!(include_str!("boot.s")); +global_asm!( + include_str!("boot.s"), + CONST_CURRENTEL_EL2 = const 0x8, + CONST_CORE_ID_MASK = const 0b11 +); //-------------------------------------------------------------------------------------------------- // Private Code diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/cpu/boot.s b/16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/cpu/boot.s index d2c9270d..8c70d035 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/cpu/boot.s +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/cpu/boot.s @@ -30,9 +30,6 @@ movk \register, #:abs_g0_nc:\symbol .endm -.equ _EL2, 0x8 -.equ _core_id_mask, 0b11 - //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- @@ -44,12 +41,12 @@ _start: // Only proceed if the core executes in EL2. Park it otherwise. mrs x0, CurrentEL - cmp x0, _EL2 + cmp x0, {CONST_CURRENTEL_EL2} b.ne .L_parking_loop // Only proceed on the boot core. Park it otherwise. mrs x1, MPIDR_EL1 - and x1, x1, _core_id_mask + and x1, x1, {CONST_CORE_ID_MASK} ldr x2, BOOT_CORE_ID // provided by bsp/__board_name__/cpu.rs cmp x1, x2 b.ne .L_parking_loop diff --git a/17_kernel_symbols/kernel/src/_arch/aarch64/cpu/boot.rs b/17_kernel_symbols/kernel/src/_arch/aarch64/cpu/boot.rs index 3d01b0dc..293d4608 100644 --- a/17_kernel_symbols/kernel/src/_arch/aarch64/cpu/boot.rs +++ b/17_kernel_symbols/kernel/src/_arch/aarch64/cpu/boot.rs @@ -17,7 +17,11 @@ use cortex_a::{asm, registers::*}; use tock_registers::interfaces::Writeable; // Assembly counterpart to this file. -global_asm!(include_str!("boot.s")); +global_asm!( + include_str!("boot.s"), + CONST_CURRENTEL_EL2 = const 0x8, + CONST_CORE_ID_MASK = const 0b11 +); //-------------------------------------------------------------------------------------------------- // Private Code diff --git a/17_kernel_symbols/kernel/src/_arch/aarch64/cpu/boot.s b/17_kernel_symbols/kernel/src/_arch/aarch64/cpu/boot.s index d2c9270d..8c70d035 100644 --- a/17_kernel_symbols/kernel/src/_arch/aarch64/cpu/boot.s +++ b/17_kernel_symbols/kernel/src/_arch/aarch64/cpu/boot.s @@ -30,9 +30,6 @@ movk \register, #:abs_g0_nc:\symbol .endm -.equ _EL2, 0x8 -.equ _core_id_mask, 0b11 - //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- @@ -44,12 +41,12 @@ _start: // Only proceed if the core executes in EL2. Park it otherwise. mrs x0, CurrentEL - cmp x0, _EL2 + cmp x0, {CONST_CURRENTEL_EL2} b.ne .L_parking_loop // Only proceed on the boot core. Park it otherwise. mrs x1, MPIDR_EL1 - and x1, x1, _core_id_mask + and x1, x1, {CONST_CORE_ID_MASK} ldr x2, BOOT_CORE_ID // provided by bsp/__board_name__/cpu.rs cmp x1, x2 b.ne .L_parking_loop diff --git a/18_backtrace/README.md b/18_backtrace/README.md index 1ea270d8..c3cc1cc8 100644 --- a/18_backtrace/README.md +++ b/18_backtrace/README.md @@ -552,7 +552,7 @@ diff -uNr 17_kernel_symbols/kernel/src/_arch/aarch64/cpu/boot.rs 18_backtrace/ke use cortex_a::{asm, registers::*}; use tock_registers::interfaces::Writeable; -@@ -63,6 +66,18 @@ +@@ -67,6 +70,18 @@ SP_EL1.set(virt_boot_core_stack_end_exclusive_addr); } @@ -571,7 +571,7 @@ diff -uNr 17_kernel_symbols/kernel/src/_arch/aarch64/cpu/boot.rs 18_backtrace/ke //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- -@@ -89,6 +104,9 @@ +@@ -93,6 +108,9 @@ let addr = Address::new(phys_kernel_tables_base_addr as usize); memory::mmu::enable_mmu_and_caching(addr).unwrap(); @@ -582,6 +582,23 @@ diff -uNr 17_kernel_symbols/kernel/src/_arch/aarch64/cpu/boot.rs 18_backtrace/ke // execution of kernel_init() in EL1 from its _virtual address_. asm::eret() +diff -uNr 17_kernel_symbols/kernel/src/_arch/aarch64/exception.rs 18_backtrace/kernel/src/_arch/aarch64/exception.rs +--- 17_kernel_symbols/kernel/src/_arch/aarch64/exception.rs ++++ 18_backtrace/kernel/src/_arch/aarch64/exception.rs +@@ -20,7 +20,11 @@ + }; + + // Assembly counterpart to this file. +-global_asm!(include_str!("exception.s")); ++global_asm!( ++ include_str!("exception.s"), ++ CONST_ESR_EL1_EC_SHIFT = const 26, ++ CONST_ESR_EL1_EC_VALUE_SVC64 = const 0x15 ++); + + //-------------------------------------------------------------------------------------------------- + // Private Definitions + diff -uNr 17_kernel_symbols/kernel/src/_arch/aarch64/exception.s 18_backtrace/kernel/src/_arch/aarch64/exception.s --- 17_kernel_symbols/kernel/src/_arch/aarch64/exception.s +++ 18_backtrace/kernel/src/_arch/aarch64/exception.s @@ -626,8 +643,8 @@ diff -uNr 17_kernel_symbols/kernel/src/_arch/aarch64/exception.s 18_backtrace/ke + // For reference: Search for "preferred exception return address" in the Architecture + // Reference Manual for ARMv8-A. +.if \is_sync == 1 -+ lsr w3, w3, #26 // w3 = ESR_EL1.EC -+ cmp w3, #0x15 // w3 == SVC64 ? ++ lsr w3, w3, {CONST_ESR_EL1_EC_SHIFT} // w3 = ESR_EL1.EC ++ cmp w3, {CONST_ESR_EL1_EC_VALUE_SVC64} // w3 == SVC64 ? + b.eq 1f +.endif + add x1, x1, #4 diff --git a/18_backtrace/kernel/src/_arch/aarch64/cpu/boot.rs b/18_backtrace/kernel/src/_arch/aarch64/cpu/boot.rs index c0bc86be..15ab92b6 100644 --- a/18_backtrace/kernel/src/_arch/aarch64/cpu/boot.rs +++ b/18_backtrace/kernel/src/_arch/aarch64/cpu/boot.rs @@ -20,7 +20,11 @@ use cortex_a::{asm, registers::*}; use tock_registers::interfaces::Writeable; // Assembly counterpart to this file. -global_asm!(include_str!("boot.s")); +global_asm!( + include_str!("boot.s"), + CONST_CURRENTEL_EL2 = const 0x8, + CONST_CORE_ID_MASK = const 0b11 +); //-------------------------------------------------------------------------------------------------- // Private Code diff --git a/18_backtrace/kernel/src/_arch/aarch64/cpu/boot.s b/18_backtrace/kernel/src/_arch/aarch64/cpu/boot.s index d2c9270d..8c70d035 100644 --- a/18_backtrace/kernel/src/_arch/aarch64/cpu/boot.s +++ b/18_backtrace/kernel/src/_arch/aarch64/cpu/boot.s @@ -30,9 +30,6 @@ movk \register, #:abs_g0_nc:\symbol .endm -.equ _EL2, 0x8 -.equ _core_id_mask, 0b11 - //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- @@ -44,12 +41,12 @@ _start: // Only proceed if the core executes in EL2. Park it otherwise. mrs x0, CurrentEL - cmp x0, _EL2 + cmp x0, {CONST_CURRENTEL_EL2} b.ne .L_parking_loop // Only proceed on the boot core. Park it otherwise. mrs x1, MPIDR_EL1 - and x1, x1, _core_id_mask + and x1, x1, {CONST_CORE_ID_MASK} ldr x2, BOOT_CORE_ID // provided by bsp/__board_name__/cpu.rs cmp x1, x2 b.ne .L_parking_loop diff --git a/18_backtrace/kernel/src/_arch/aarch64/exception.rs b/18_backtrace/kernel/src/_arch/aarch64/exception.rs index 6781758a..30090644 100644 --- a/18_backtrace/kernel/src/_arch/aarch64/exception.rs +++ b/18_backtrace/kernel/src/_arch/aarch64/exception.rs @@ -20,7 +20,11 @@ use tock_registers::{ }; // Assembly counterpart to this file. -global_asm!(include_str!("exception.s")); +global_asm!( + include_str!("exception.s"), + CONST_ESR_EL1_EC_SHIFT = const 26, + CONST_ESR_EL1_EC_VALUE_SVC64 = const 0x15 +); //-------------------------------------------------------------------------------------------------- // Private Definitions diff --git a/18_backtrace/kernel/src/_arch/aarch64/exception.s b/18_backtrace/kernel/src/_arch/aarch64/exception.s index 17acaf59..cdef8c58 100644 --- a/18_backtrace/kernel/src/_arch/aarch64/exception.s +++ b/18_backtrace/kernel/src/_arch/aarch64/exception.s @@ -63,8 +63,8 @@ __vector_\handler: // For reference: Search for "preferred exception return address" in the Architecture // Reference Manual for ARMv8-A. .if \is_sync == 1 - lsr w3, w3, #26 // w3 = ESR_EL1.EC - cmp w3, #0x15 // w3 == SVC64 ? + lsr w3, w3, {CONST_ESR_EL1_EC_SHIFT} // w3 = ESR_EL1.EC + cmp w3, {CONST_ESR_EL1_EC_VALUE_SVC64} // w3 == SVC64 ? b.eq 1f .endif add x1, x1, #4 diff --git a/X1_JTAG_boot/jtag_boot_rpi3.img b/X1_JTAG_boot/jtag_boot_rpi3.img index 584c5a6ef4c2141a22eafa3270aabe16b117ecef..f6afca6ccb677db69ee4628043d1039905542b1a 100755 GIT binary patch delta 14 VcmZ4Cw!&?Lg92mcW=DnROaLps1#|!a delta 14 VcmZ4Cw!&?Lg92mQW=DnROaLpa1#tiX diff --git a/X1_JTAG_boot/jtag_boot_rpi4.img b/X1_JTAG_boot/jtag_boot_rpi4.img index 4ebab5bfd8dac22484d5e9dafb48c6ecc5dd4722..b12e094ded48d939c71c87f3fb3fa66a2c309048 100755 GIT binary patch delta 14 Wcmca$d% Date: Fri, 6 May 2022 22:26:37 +0200 Subject: [PATCH 26/75] Rename PageAllocator module --- 14_virtual_mem_part2_mmio_remap/README.md | 171 +++++++++--------- .../kernel/src/memory/mmu.rs | 8 +- .../memory/mmu/{alloc.rs => page_alloc.rs} | 2 +- .../README.md | 2 +- .../kernel/src/memory/mmu.rs | 6 +- .../memory/mmu/{alloc.rs => page_alloc.rs} | 2 +- .../kernel/src/memory/mmu.rs | 6 +- .../memory/mmu/{alloc.rs => page_alloc.rs} | 2 +- 17_kernel_symbols/kernel/src/memory/mmu.rs | 6 +- .../memory/mmu/{alloc.rs => page_alloc.rs} | 2 +- 18_backtrace/kernel/src/memory/mmu.rs | 6 +- 18_backtrace/kernel/src/memory/mmu/alloc.rs | 70 ------- .../kernel/src/memory/mmu/page_alloc.rs | 70 +++++++ 13 files changed, 177 insertions(+), 176 deletions(-) rename 14_virtual_mem_part2_mmio_remap/kernel/src/memory/mmu/{alloc.rs => page_alloc.rs} (99%) rename 15_virtual_mem_part3_precomputed_tables/kernel/src/memory/mmu/{alloc.rs => page_alloc.rs} (99%) rename 16_virtual_mem_part4_higher_half_kernel/kernel/src/memory/mmu/{alloc.rs => page_alloc.rs} (99%) rename 17_kernel_symbols/kernel/src/memory/mmu/{alloc.rs => page_alloc.rs} (99%) delete mode 100644 18_backtrace/kernel/src/memory/mmu/alloc.rs create mode 100644 18_backtrace/kernel/src/memory/mmu/page_alloc.rs diff --git a/14_virtual_mem_part2_mmio_remap/README.md b/14_virtual_mem_part2_mmio_remap/README.md index 329e2105..5d78e237 100644 --- a/14_virtual_mem_part2_mmio_remap/README.md +++ b/14_virtual_mem_part2_mmio_remap/README.md @@ -279,7 +279,7 @@ pub unsafe fn kernel_map_mmio( // omitted let virt_region = - alloc::kernel_mmio_va_allocator().lock(|allocator| allocator.alloc(num_pages))?; + page_alloc::kernel_mmio_va_allocator().lock(|allocator| allocator.alloc(num_pages))?; kernel_map_at_unchecked( name, @@ -296,10 +296,11 @@ pub unsafe fn kernel_map_mmio( } ``` -This allocator is defined and implemented in the added file `src/memory/mmu/alloc.rs`. Like other -parts of the mapping code, its implementation makes use of the newly introduced `PageAddress` -and `MemoryRegion` types (in [`src/memory/mmu/types.rs`](kernel/src/memory/mmu/types.rs)), -but apart from that is rather straight forward. Therefore, it won't be covered in details here. +This allocator is defined and implemented in the added file `src/memory/mmu/paeg_alloc.rs`. Like +other parts of the mapping code, its implementation makes use of the newly introduced +`PageAddress` and `MemoryRegion` types (in +[`src/memory/mmu/types.rs`](kernel/src/memory/mmu/types.rs)), but apart from that is rather straight +forward. Therefore, it won't be covered in details here. The more interesting question is: How does the allocator get to learn which VAs it can use? @@ -313,7 +314,7 @@ been turned on. fn kernel_init_mmio_va_allocator() { let region = bsp::memory::mmu::virt_mmio_remap_region(); - alloc::kernel_mmio_va_allocator().lock(|allocator| allocator.initialize(region)); + page_alloc::kernel_mmio_va_allocator().lock(|allocator| allocator.initialize(region)); } ``` @@ -2227,81 +2228,6 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/main.rs 14_virtual_mem_ let (_, privilege_level) = exception::current_privilege_level(); info!("Current privilege level: {}", privilege_level); -diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/memory/mmu/alloc.rs 14_virtual_mem_part2_mmio_remap/kernel/src/memory/mmu/alloc.rs ---- 13_exceptions_part2_peripheral_IRQs/kernel/src/memory/mmu/alloc.rs -+++ 14_virtual_mem_part2_mmio_remap/kernel/src/memory/mmu/alloc.rs -@@ -0,0 +1,70 @@ -+// SPDX-License-Identifier: MIT OR Apache-2.0 -+// -+// Copyright (c) 2021-2022 Andre Richter -+ -+//! Allocation. -+ -+use super::MemoryRegion; -+use crate::{ -+ memory::{AddressType, Virtual}, -+ synchronization::IRQSafeNullLock, -+ warn, -+}; -+use core::num::NonZeroUsize; -+ -+//-------------------------------------------------------------------------------------------------- -+// Public Definitions -+//-------------------------------------------------------------------------------------------------- -+ -+/// A page allocator that can be lazyily initialized. -+pub struct PageAllocator { -+ pool: Option>, -+} -+ -+//-------------------------------------------------------------------------------------------------- -+// Global instances -+//-------------------------------------------------------------------------------------------------- -+ -+static KERNEL_MMIO_VA_ALLOCATOR: IRQSafeNullLock> = -+ IRQSafeNullLock::new(PageAllocator::new()); -+ -+//-------------------------------------------------------------------------------------------------- -+// Public Code -+//-------------------------------------------------------------------------------------------------- -+ -+/// Return a reference to the kernel's MMIO virtual address allocator. -+pub fn kernel_mmio_va_allocator() -> &'static IRQSafeNullLock> { -+ &KERNEL_MMIO_VA_ALLOCATOR -+} -+ -+impl PageAllocator { -+ /// Create an instance. -+ pub const fn new() -> Self { -+ Self { pool: None } -+ } -+ -+ /// Initialize the allocator. -+ pub fn initialize(&mut self, pool: MemoryRegion) { -+ if self.pool.is_some() { -+ warn!("Already initialized"); -+ return; -+ } -+ -+ self.pool = Some(pool); -+ } -+ -+ /// Allocate a number of pages. -+ pub fn alloc( -+ &mut self, -+ num_requested_pages: NonZeroUsize, -+ ) -> Result, &'static str> { -+ if self.pool.is_none() { -+ return Err("Allocator not initialized"); -+ } -+ -+ self.pool -+ .as_mut() -+ .unwrap() -+ .take_first_n_pages(num_requested_pages) -+ } -+} - diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/memory/mmu/mapping_record.rs 14_virtual_mem_part2_mmio_remap/kernel/src/memory/mmu/mapping_record.rs --- 13_exceptions_part2_peripheral_IRQs/kernel/src/memory/mmu/mapping_record.rs +++ 14_virtual_mem_part2_mmio_remap/kernel/src/memory/mmu/mapping_record.rs @@ -2540,6 +2466,81 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/memory/mmu/mapping_reco + KERNEL_MAPPING_RECORD.read(|mr| mr.print()); +} +diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/memory/mmu/page_alloc.rs 14_virtual_mem_part2_mmio_remap/kernel/src/memory/mmu/page_alloc.rs +--- 13_exceptions_part2_peripheral_IRQs/kernel/src/memory/mmu/page_alloc.rs ++++ 14_virtual_mem_part2_mmio_remap/kernel/src/memory/mmu/page_alloc.rs +@@ -0,0 +1,70 @@ ++// SPDX-License-Identifier: MIT OR Apache-2.0 ++// ++// Copyright (c) 2021-2022 Andre Richter ++ ++//! Page allocation. ++ ++use super::MemoryRegion; ++use crate::{ ++ memory::{AddressType, Virtual}, ++ synchronization::IRQSafeNullLock, ++ warn, ++}; ++use core::num::NonZeroUsize; ++ ++//-------------------------------------------------------------------------------------------------- ++// Public Definitions ++//-------------------------------------------------------------------------------------------------- ++ ++/// A page allocator that can be lazyily initialized. ++pub struct PageAllocator { ++ pool: Option>, ++} ++ ++//-------------------------------------------------------------------------------------------------- ++// Global instances ++//-------------------------------------------------------------------------------------------------- ++ ++static KERNEL_MMIO_VA_ALLOCATOR: IRQSafeNullLock> = ++ IRQSafeNullLock::new(PageAllocator::new()); ++ ++//-------------------------------------------------------------------------------------------------- ++// Public Code ++//-------------------------------------------------------------------------------------------------- ++ ++/// Return a reference to the kernel's MMIO virtual address allocator. ++pub fn kernel_mmio_va_allocator() -> &'static IRQSafeNullLock> { ++ &KERNEL_MMIO_VA_ALLOCATOR ++} ++ ++impl PageAllocator { ++ /// Create an instance. ++ pub const fn new() -> Self { ++ Self { pool: None } ++ } ++ ++ /// Initialize the allocator. ++ pub fn initialize(&mut self, pool: MemoryRegion) { ++ if self.pool.is_some() { ++ warn!("Already initialized"); ++ return; ++ } ++ ++ self.pool = Some(pool); ++ } ++ ++ /// Allocate a number of pages. ++ pub fn alloc( ++ &mut self, ++ num_requested_pages: NonZeroUsize, ++ ) -> Result, &'static str> { ++ if self.pool.is_none() { ++ return Err("Allocator not initialized"); ++ } ++ ++ self.pool ++ .as_mut() ++ .unwrap() ++ .take_first_n_pages(num_requested_pages) ++ } ++} + diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/memory/mmu/translation_table.rs 14_virtual_mem_part2_mmio_remap/kernel/src/memory/mmu/translation_table.rs --- 13_exceptions_part2_peripheral_IRQs/kernel/src/memory/mmu/translation_table.rs +++ 14_virtual_mem_part2_mmio_remap/kernel/src/memory/mmu/translation_table.rs @@ -3037,8 +3038,8 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/memory/mmu.rs 14_virtua #[path = "../_arch/aarch64/memory/mmu.rs"] mod arch_mmu; -+mod alloc; +mod mapping_record; ++mod page_alloc; mod translation_table; +mod types; @@ -3140,7 +3141,7 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/memory/mmu.rs 14_virtua +fn kernel_init_mmio_va_allocator() { + let region = bsp::memory::mmu::virt_mmio_remap_region(); + -+ alloc::kernel_mmio_va_allocator().lock(|allocator| allocator.initialize(region)); ++ page_alloc::kernel_mmio_va_allocator().lock(|allocator| allocator.initialize(region)); +} + +/// Map a region in the kernel's translation tables. @@ -3280,7 +3281,7 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/memory/mmu.rs 14_virtua - "PX" - }; + let virt_region = -+ alloc::kernel_mmio_va_allocator().lock(|allocator| allocator.alloc(num_pages))?; ++ page_alloc::kernel_mmio_va_allocator().lock(|allocator| allocator.alloc(num_pages))?; - write!( - f, @@ -3399,7 +3400,7 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/memory/mmu.rs 14_virtua + let phys_region = MemoryRegion::new(phys_start_page_addr, phys_end_exclusive_page_addr); + + let num_pages = NonZeroUsize::new(phys_region.num_pages()).unwrap(); -+ let virt_region = alloc::kernel_mmio_va_allocator() ++ let virt_region = page_alloc::kernel_mmio_va_allocator() + .lock(|allocator| allocator.alloc(num_pages)) + .unwrap(); diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/memory/mmu.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/memory/mmu.rs index b0616f88..43602470 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/memory/mmu.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/memory/mmu.rs @@ -8,8 +8,8 @@ #[path = "../_arch/aarch64/memory/mmu.rs"] mod arch_mmu; -mod alloc; mod mapping_record; +mod page_alloc; mod translation_table; mod types; @@ -81,7 +81,7 @@ use translation_table::interface::TranslationTable; fn kernel_init_mmio_va_allocator() { let region = bsp::memory::mmu::virt_mmio_remap_region(); - alloc::kernel_mmio_va_allocator().lock(|allocator| allocator.initialize(region)); + page_alloc::kernel_mmio_va_allocator().lock(|allocator| allocator.initialize(region)); } /// Map a region in the kernel's translation tables. @@ -205,7 +205,7 @@ pub unsafe fn kernel_map_mmio( }; let virt_region = - alloc::kernel_mmio_va_allocator().lock(|allocator| allocator.alloc(num_pages))?; + page_alloc::kernel_mmio_va_allocator().lock(|allocator| allocator.alloc(num_pages))?; kernel_map_at_unchecked( name, @@ -281,7 +281,7 @@ mod tests { let phys_region = MemoryRegion::new(phys_start_page_addr, phys_end_exclusive_page_addr); let num_pages = NonZeroUsize::new(phys_region.num_pages()).unwrap(); - let virt_region = alloc::kernel_mmio_va_allocator() + let virt_region = page_alloc::kernel_mmio_va_allocator() .lock(|allocator| allocator.alloc(num_pages)) .unwrap(); diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/memory/mmu/alloc.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/memory/mmu/page_alloc.rs similarity index 99% rename from 14_virtual_mem_part2_mmio_remap/kernel/src/memory/mmu/alloc.rs rename to 14_virtual_mem_part2_mmio_remap/kernel/src/memory/mmu/page_alloc.rs index aadb72ef..b4c4232c 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/memory/mmu/alloc.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/memory/mmu/page_alloc.rs @@ -2,7 +2,7 @@ // // Copyright (c) 2021-2022 Andre Richter -//! Allocation. +//! Page allocation. use super::MemoryRegion; use crate::{ diff --git a/15_virtual_mem_part3_precomputed_tables/README.md b/15_virtual_mem_part3_precomputed_tables/README.md index 5836e12f..d3ec21e2 100644 --- a/15_virtual_mem_part3_precomputed_tables/README.md +++ b/15_virtual_mem_part3_precomputed_tables/README.md @@ -1663,7 +1663,7 @@ diff -uNr 14_virtual_mem_part2_mmio_remap/kernel/src/memory/mmu.rs 15_virtual_me - let phys_region = MemoryRegion::new(phys_start_page_addr, phys_end_exclusive_page_addr); - - let num_pages = NonZeroUsize::new(phys_region.num_pages()).unwrap(); -- let virt_region = alloc::kernel_mmio_va_allocator() +- let virt_region = page_alloc::kernel_mmio_va_allocator() - .lock(|allocator| allocator.alloc(num_pages)) - .unwrap(); - diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/memory/mmu.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/memory/mmu.rs index 23dc7094..c6461474 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/memory/mmu.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/memory/mmu.rs @@ -8,8 +8,8 @@ #[path = "../_arch/aarch64/memory/mmu.rs"] mod arch_mmu; -mod alloc; mod mapping_record; +mod page_alloc; mod translation_table; mod types; @@ -82,7 +82,7 @@ use translation_table::interface::TranslationTable; fn kernel_init_mmio_va_allocator() { let region = bsp::memory::mmu::virt_mmio_remap_region(); - alloc::kernel_mmio_va_allocator().lock(|allocator| allocator.initialize(region)); + page_alloc::kernel_mmio_va_allocator().lock(|allocator| allocator.initialize(region)); } /// Map a region in the kernel's translation tables. @@ -203,7 +203,7 @@ pub unsafe fn kernel_map_mmio( }; let virt_region = - alloc::kernel_mmio_va_allocator().lock(|allocator| allocator.alloc(num_pages))?; + page_alloc::kernel_mmio_va_allocator().lock(|allocator| allocator.alloc(num_pages))?; kernel_map_at_unchecked( name, diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/memory/mmu/alloc.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/memory/mmu/page_alloc.rs similarity index 99% rename from 15_virtual_mem_part3_precomputed_tables/kernel/src/memory/mmu/alloc.rs rename to 15_virtual_mem_part3_precomputed_tables/kernel/src/memory/mmu/page_alloc.rs index aadb72ef..b4c4232c 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/memory/mmu/alloc.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/memory/mmu/page_alloc.rs @@ -2,7 +2,7 @@ // // Copyright (c) 2021-2022 Andre Richter -//! Allocation. +//! Page allocation. use super::MemoryRegion; use crate::{ diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/memory/mmu.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/memory/mmu.rs index dfc29993..8806a993 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/memory/mmu.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/memory/mmu.rs @@ -8,8 +8,8 @@ #[path = "../_arch/aarch64/memory/mmu.rs"] mod arch_mmu; -mod alloc; mod mapping_record; +mod page_alloc; mod translation_table; mod types; @@ -87,7 +87,7 @@ use translation_table::interface::TranslationTable; fn kernel_init_mmio_va_allocator() { let region = bsp::memory::mmu::virt_mmio_remap_region(); - alloc::kernel_mmio_va_allocator().lock(|allocator| allocator.initialize(region)); + page_alloc::kernel_mmio_va_allocator().lock(|allocator| allocator.initialize(region)); } /// Map a region in the kernel's translation tables. @@ -208,7 +208,7 @@ pub unsafe fn kernel_map_mmio( }; let virt_region = - alloc::kernel_mmio_va_allocator().lock(|allocator| allocator.alloc(num_pages))?; + page_alloc::kernel_mmio_va_allocator().lock(|allocator| allocator.alloc(num_pages))?; kernel_map_at_unchecked( name, diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/memory/mmu/alloc.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/memory/mmu/page_alloc.rs similarity index 99% rename from 16_virtual_mem_part4_higher_half_kernel/kernel/src/memory/mmu/alloc.rs rename to 16_virtual_mem_part4_higher_half_kernel/kernel/src/memory/mmu/page_alloc.rs index aadb72ef..b4c4232c 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/memory/mmu/alloc.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/memory/mmu/page_alloc.rs @@ -2,7 +2,7 @@ // // Copyright (c) 2021-2022 Andre Richter -//! Allocation. +//! Page allocation. use super::MemoryRegion; use crate::{ diff --git a/17_kernel_symbols/kernel/src/memory/mmu.rs b/17_kernel_symbols/kernel/src/memory/mmu.rs index dfc29993..8806a993 100644 --- a/17_kernel_symbols/kernel/src/memory/mmu.rs +++ b/17_kernel_symbols/kernel/src/memory/mmu.rs @@ -8,8 +8,8 @@ #[path = "../_arch/aarch64/memory/mmu.rs"] mod arch_mmu; -mod alloc; mod mapping_record; +mod page_alloc; mod translation_table; mod types; @@ -87,7 +87,7 @@ use translation_table::interface::TranslationTable; fn kernel_init_mmio_va_allocator() { let region = bsp::memory::mmu::virt_mmio_remap_region(); - alloc::kernel_mmio_va_allocator().lock(|allocator| allocator.initialize(region)); + page_alloc::kernel_mmio_va_allocator().lock(|allocator| allocator.initialize(region)); } /// Map a region in the kernel's translation tables. @@ -208,7 +208,7 @@ pub unsafe fn kernel_map_mmio( }; let virt_region = - alloc::kernel_mmio_va_allocator().lock(|allocator| allocator.alloc(num_pages))?; + page_alloc::kernel_mmio_va_allocator().lock(|allocator| allocator.alloc(num_pages))?; kernel_map_at_unchecked( name, diff --git a/17_kernel_symbols/kernel/src/memory/mmu/alloc.rs b/17_kernel_symbols/kernel/src/memory/mmu/page_alloc.rs similarity index 99% rename from 17_kernel_symbols/kernel/src/memory/mmu/alloc.rs rename to 17_kernel_symbols/kernel/src/memory/mmu/page_alloc.rs index aadb72ef..b4c4232c 100644 --- a/17_kernel_symbols/kernel/src/memory/mmu/alloc.rs +++ b/17_kernel_symbols/kernel/src/memory/mmu/page_alloc.rs @@ -2,7 +2,7 @@ // // Copyright (c) 2021-2022 Andre Richter -//! Allocation. +//! Page allocation. use super::MemoryRegion; use crate::{ diff --git a/18_backtrace/kernel/src/memory/mmu.rs b/18_backtrace/kernel/src/memory/mmu.rs index dfc29993..8806a993 100644 --- a/18_backtrace/kernel/src/memory/mmu.rs +++ b/18_backtrace/kernel/src/memory/mmu.rs @@ -8,8 +8,8 @@ #[path = "../_arch/aarch64/memory/mmu.rs"] mod arch_mmu; -mod alloc; mod mapping_record; +mod page_alloc; mod translation_table; mod types; @@ -87,7 +87,7 @@ use translation_table::interface::TranslationTable; fn kernel_init_mmio_va_allocator() { let region = bsp::memory::mmu::virt_mmio_remap_region(); - alloc::kernel_mmio_va_allocator().lock(|allocator| allocator.initialize(region)); + page_alloc::kernel_mmio_va_allocator().lock(|allocator| allocator.initialize(region)); } /// Map a region in the kernel's translation tables. @@ -208,7 +208,7 @@ pub unsafe fn kernel_map_mmio( }; let virt_region = - alloc::kernel_mmio_va_allocator().lock(|allocator| allocator.alloc(num_pages))?; + page_alloc::kernel_mmio_va_allocator().lock(|allocator| allocator.alloc(num_pages))?; kernel_map_at_unchecked( name, diff --git a/18_backtrace/kernel/src/memory/mmu/alloc.rs b/18_backtrace/kernel/src/memory/mmu/alloc.rs deleted file mode 100644 index aadb72ef..00000000 --- a/18_backtrace/kernel/src/memory/mmu/alloc.rs +++ /dev/null @@ -1,70 +0,0 @@ -// SPDX-License-Identifier: MIT OR Apache-2.0 -// -// Copyright (c) 2021-2022 Andre Richter - -//! Allocation. - -use super::MemoryRegion; -use crate::{ - memory::{AddressType, Virtual}, - synchronization::IRQSafeNullLock, - warn, -}; -use core::num::NonZeroUsize; - -//-------------------------------------------------------------------------------------------------- -// Public Definitions -//-------------------------------------------------------------------------------------------------- - -/// A page allocator that can be lazyily initialized. -pub struct PageAllocator { - pool: Option>, -} - -//-------------------------------------------------------------------------------------------------- -// Global instances -//-------------------------------------------------------------------------------------------------- - -static KERNEL_MMIO_VA_ALLOCATOR: IRQSafeNullLock> = - IRQSafeNullLock::new(PageAllocator::new()); - -//-------------------------------------------------------------------------------------------------- -// Public Code -//-------------------------------------------------------------------------------------------------- - -/// Return a reference to the kernel's MMIO virtual address allocator. -pub fn kernel_mmio_va_allocator() -> &'static IRQSafeNullLock> { - &KERNEL_MMIO_VA_ALLOCATOR -} - -impl PageAllocator { - /// Create an instance. - pub const fn new() -> Self { - Self { pool: None } - } - - /// Initialize the allocator. - pub fn initialize(&mut self, pool: MemoryRegion) { - if self.pool.is_some() { - warn!("Already initialized"); - return; - } - - self.pool = Some(pool); - } - - /// Allocate a number of pages. - pub fn alloc( - &mut self, - num_requested_pages: NonZeroUsize, - ) -> Result, &'static str> { - if self.pool.is_none() { - return Err("Allocator not initialized"); - } - - self.pool - .as_mut() - .unwrap() - .take_first_n_pages(num_requested_pages) - } -} diff --git a/18_backtrace/kernel/src/memory/mmu/page_alloc.rs b/18_backtrace/kernel/src/memory/mmu/page_alloc.rs new file mode 100644 index 00000000..b4c4232c --- /dev/null +++ b/18_backtrace/kernel/src/memory/mmu/page_alloc.rs @@ -0,0 +1,70 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2021-2022 Andre Richter + +//! Page allocation. + +use super::MemoryRegion; +use crate::{ + memory::{AddressType, Virtual}, + synchronization::IRQSafeNullLock, + warn, +}; +use core::num::NonZeroUsize; + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +/// A page allocator that can be lazyily initialized. +pub struct PageAllocator { + pool: Option>, +} + +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +static KERNEL_MMIO_VA_ALLOCATOR: IRQSafeNullLock> = + IRQSafeNullLock::new(PageAllocator::new()); + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +/// Return a reference to the kernel's MMIO virtual address allocator. +pub fn kernel_mmio_va_allocator() -> &'static IRQSafeNullLock> { + &KERNEL_MMIO_VA_ALLOCATOR +} + +impl PageAllocator { + /// Create an instance. + pub const fn new() -> Self { + Self { pool: None } + } + + /// Initialize the allocator. + pub fn initialize(&mut self, pool: MemoryRegion) { + if self.pool.is_some() { + warn!("Already initialized"); + return; + } + + self.pool = Some(pool); + } + + /// Allocate a number of pages. + pub fn alloc( + &mut self, + num_requested_pages: NonZeroUsize, + ) -> Result, &'static str> { + if self.pool.is_none() { + return Err("Allocator not initialized"); + } + + self.pool + .as_mut() + .unwrap() + .take_first_n_pages(num_requested_pages) + } +} From 821979be41b793854f5f857fc0aa7d70c5a9054d Mon Sep 17 00:00:00 2001 From: Andre Richter Date: Mon, 9 May 2022 09:05:50 +0200 Subject: [PATCH 27/75] Fix wrong variable in Makefile --- 01_wait_forever/Makefile | 2 +- 02_runtime_init/Makefile | 2 +- 03_hacky_hello_world/Makefile | 2 +- 04_safe_globals/Makefile | 2 +- 05_drivers_gpio_uart/Makefile | 2 +- 06_uart_chainloader/Makefile | 2 +- 07_timestamps/Makefile | 2 +- 08_hw_debug_JTAG/Makefile | 2 +- 09_privilege_level/Makefile | 2 +- 10_virtual_mem_part1_identity_mapping/Makefile | 2 +- 11_exceptions_part1_groundwork/Makefile | 2 +- 12_integrated_testing/Makefile | 2 +- 13_exceptions_part2_peripheral_IRQs/Makefile | 2 +- 14_virtual_mem_part2_mmio_remap/Makefile | 2 +- 15_virtual_mem_part3_precomputed_tables/README.md | 2 +- 15 files changed, 15 insertions(+), 15 deletions(-) diff --git a/01_wait_forever/Makefile b/01_wait_forever/Makefile index 59884220..8ddb26cd 100644 --- a/01_wait_forever/Makefile +++ b/01_wait_forever/Makefile @@ -58,7 +58,7 @@ LAST_BUILD_CONFIG = target/$(BSP).build_config KERNEL_ELF = target/$(TARGET)/release/kernel # This parses cargo's dep-info file. # https://doc.rust-lang.org/cargo/guide/build-cache.html#dep-info-files -KERNEL_ELF_DEPS = $(filter-out %: ,$(file < $(KERNEL_ELF_RAW).d)) $(LAST_BUILD_CONFIG) +KERNEL_ELF_DEPS = $(filter-out %: ,$(file < $(KERNEL_ELF).d)) $(LAST_BUILD_CONFIG) diff --git a/02_runtime_init/Makefile b/02_runtime_init/Makefile index ba5f0c79..49ca7b63 100644 --- a/02_runtime_init/Makefile +++ b/02_runtime_init/Makefile @@ -58,7 +58,7 @@ LAST_BUILD_CONFIG = target/$(BSP).build_config KERNEL_ELF = target/$(TARGET)/release/kernel # This parses cargo's dep-info file. # https://doc.rust-lang.org/cargo/guide/build-cache.html#dep-info-files -KERNEL_ELF_DEPS = $(filter-out %: ,$(file < $(KERNEL_ELF_RAW).d)) $(LAST_BUILD_CONFIG) +KERNEL_ELF_DEPS = $(filter-out %: ,$(file < $(KERNEL_ELF).d)) $(LAST_BUILD_CONFIG) diff --git a/03_hacky_hello_world/Makefile b/03_hacky_hello_world/Makefile index a90b2fd6..6e5cf32d 100644 --- a/03_hacky_hello_world/Makefile +++ b/03_hacky_hello_world/Makefile @@ -58,7 +58,7 @@ LAST_BUILD_CONFIG = target/$(BSP).build_config KERNEL_ELF = target/$(TARGET)/release/kernel # This parses cargo's dep-info file. # https://doc.rust-lang.org/cargo/guide/build-cache.html#dep-info-files -KERNEL_ELF_DEPS = $(filter-out %: ,$(file < $(KERNEL_ELF_RAW).d)) $(LAST_BUILD_CONFIG) +KERNEL_ELF_DEPS = $(filter-out %: ,$(file < $(KERNEL_ELF).d)) $(LAST_BUILD_CONFIG) diff --git a/04_safe_globals/Makefile b/04_safe_globals/Makefile index a90b2fd6..6e5cf32d 100644 --- a/04_safe_globals/Makefile +++ b/04_safe_globals/Makefile @@ -58,7 +58,7 @@ LAST_BUILD_CONFIG = target/$(BSP).build_config KERNEL_ELF = target/$(TARGET)/release/kernel # This parses cargo's dep-info file. # https://doc.rust-lang.org/cargo/guide/build-cache.html#dep-info-files -KERNEL_ELF_DEPS = $(filter-out %: ,$(file < $(KERNEL_ELF_RAW).d)) $(LAST_BUILD_CONFIG) +KERNEL_ELF_DEPS = $(filter-out %: ,$(file < $(KERNEL_ELF).d)) $(LAST_BUILD_CONFIG) diff --git a/05_drivers_gpio_uart/Makefile b/05_drivers_gpio_uart/Makefile index 376892d8..cd8097c8 100644 --- a/05_drivers_gpio_uart/Makefile +++ b/05_drivers_gpio_uart/Makefile @@ -61,7 +61,7 @@ LAST_BUILD_CONFIG = target/$(BSP).build_config KERNEL_ELF = target/$(TARGET)/release/kernel # This parses cargo's dep-info file. # https://doc.rust-lang.org/cargo/guide/build-cache.html#dep-info-files -KERNEL_ELF_DEPS = $(filter-out %: ,$(file < $(KERNEL_ELF_RAW).d)) $(LAST_BUILD_CONFIG) +KERNEL_ELF_DEPS = $(filter-out %: ,$(file < $(KERNEL_ELF).d)) $(LAST_BUILD_CONFIG) diff --git a/06_uart_chainloader/Makefile b/06_uart_chainloader/Makefile index 812fdf4e..6c60e8ed 100644 --- a/06_uart_chainloader/Makefile +++ b/06_uart_chainloader/Makefile @@ -63,7 +63,7 @@ LAST_BUILD_CONFIG = target/$(BSP).build_config KERNEL_ELF = target/$(TARGET)/release/kernel # This parses cargo's dep-info file. # https://doc.rust-lang.org/cargo/guide/build-cache.html#dep-info-files -KERNEL_ELF_DEPS = $(filter-out %: ,$(file < $(KERNEL_ELF_RAW).d)) $(LAST_BUILD_CONFIG) +KERNEL_ELF_DEPS = $(filter-out %: ,$(file < $(KERNEL_ELF).d)) $(LAST_BUILD_CONFIG) diff --git a/07_timestamps/Makefile b/07_timestamps/Makefile index a497ad81..b89cee8c 100644 --- a/07_timestamps/Makefile +++ b/07_timestamps/Makefile @@ -61,7 +61,7 @@ LAST_BUILD_CONFIG = target/$(BSP).build_config KERNEL_ELF = target/$(TARGET)/release/kernel # This parses cargo's dep-info file. # https://doc.rust-lang.org/cargo/guide/build-cache.html#dep-info-files -KERNEL_ELF_DEPS = $(filter-out %: ,$(file < $(KERNEL_ELF_RAW).d)) $(LAST_BUILD_CONFIG) +KERNEL_ELF_DEPS = $(filter-out %: ,$(file < $(KERNEL_ELF).d)) $(LAST_BUILD_CONFIG) diff --git a/08_hw_debug_JTAG/Makefile b/08_hw_debug_JTAG/Makefile index 9d76237c..138c5554 100644 --- a/08_hw_debug_JTAG/Makefile +++ b/08_hw_debug_JTAG/Makefile @@ -65,7 +65,7 @@ LAST_BUILD_CONFIG = target/$(BSP).build_config KERNEL_ELF = target/$(TARGET)/release/kernel # This parses cargo's dep-info file. # https://doc.rust-lang.org/cargo/guide/build-cache.html#dep-info-files -KERNEL_ELF_DEPS = $(filter-out %: ,$(file < $(KERNEL_ELF_RAW).d)) $(LAST_BUILD_CONFIG) +KERNEL_ELF_DEPS = $(filter-out %: ,$(file < $(KERNEL_ELF).d)) $(LAST_BUILD_CONFIG) diff --git a/09_privilege_level/Makefile b/09_privilege_level/Makefile index 9d76237c..138c5554 100644 --- a/09_privilege_level/Makefile +++ b/09_privilege_level/Makefile @@ -65,7 +65,7 @@ LAST_BUILD_CONFIG = target/$(BSP).build_config KERNEL_ELF = target/$(TARGET)/release/kernel # This parses cargo's dep-info file. # https://doc.rust-lang.org/cargo/guide/build-cache.html#dep-info-files -KERNEL_ELF_DEPS = $(filter-out %: ,$(file < $(KERNEL_ELF_RAW).d)) $(LAST_BUILD_CONFIG) +KERNEL_ELF_DEPS = $(filter-out %: ,$(file < $(KERNEL_ELF).d)) $(LAST_BUILD_CONFIG) diff --git a/10_virtual_mem_part1_identity_mapping/Makefile b/10_virtual_mem_part1_identity_mapping/Makefile index 9d76237c..138c5554 100644 --- a/10_virtual_mem_part1_identity_mapping/Makefile +++ b/10_virtual_mem_part1_identity_mapping/Makefile @@ -65,7 +65,7 @@ LAST_BUILD_CONFIG = target/$(BSP).build_config KERNEL_ELF = target/$(TARGET)/release/kernel # This parses cargo's dep-info file. # https://doc.rust-lang.org/cargo/guide/build-cache.html#dep-info-files -KERNEL_ELF_DEPS = $(filter-out %: ,$(file < $(KERNEL_ELF_RAW).d)) $(LAST_BUILD_CONFIG) +KERNEL_ELF_DEPS = $(filter-out %: ,$(file < $(KERNEL_ELF).d)) $(LAST_BUILD_CONFIG) diff --git a/11_exceptions_part1_groundwork/Makefile b/11_exceptions_part1_groundwork/Makefile index 9d76237c..138c5554 100644 --- a/11_exceptions_part1_groundwork/Makefile +++ b/11_exceptions_part1_groundwork/Makefile @@ -65,7 +65,7 @@ LAST_BUILD_CONFIG = target/$(BSP).build_config KERNEL_ELF = target/$(TARGET)/release/kernel # This parses cargo's dep-info file. # https://doc.rust-lang.org/cargo/guide/build-cache.html#dep-info-files -KERNEL_ELF_DEPS = $(filter-out %: ,$(file < $(KERNEL_ELF_RAW).d)) $(LAST_BUILD_CONFIG) +KERNEL_ELF_DEPS = $(filter-out %: ,$(file < $(KERNEL_ELF).d)) $(LAST_BUILD_CONFIG) diff --git a/12_integrated_testing/Makefile b/12_integrated_testing/Makefile index 1a19e601..20007cec 100644 --- a/12_integrated_testing/Makefile +++ b/12_integrated_testing/Makefile @@ -74,7 +74,7 @@ LAST_BUILD_CONFIG = target/$(BSP).build_config KERNEL_ELF = target/$(TARGET)/release/kernel # This parses cargo's dep-info file. # https://doc.rust-lang.org/cargo/guide/build-cache.html#dep-info-files -KERNEL_ELF_DEPS = $(filter-out %: ,$(file < $(KERNEL_ELF_RAW).d)) $(LAST_BUILD_CONFIG) +KERNEL_ELF_DEPS = $(filter-out %: ,$(file < $(KERNEL_ELF).d)) $(LAST_BUILD_CONFIG) diff --git a/13_exceptions_part2_peripheral_IRQs/Makefile b/13_exceptions_part2_peripheral_IRQs/Makefile index 1a19e601..20007cec 100644 --- a/13_exceptions_part2_peripheral_IRQs/Makefile +++ b/13_exceptions_part2_peripheral_IRQs/Makefile @@ -74,7 +74,7 @@ LAST_BUILD_CONFIG = target/$(BSP).build_config KERNEL_ELF = target/$(TARGET)/release/kernel # This parses cargo's dep-info file. # https://doc.rust-lang.org/cargo/guide/build-cache.html#dep-info-files -KERNEL_ELF_DEPS = $(filter-out %: ,$(file < $(KERNEL_ELF_RAW).d)) $(LAST_BUILD_CONFIG) +KERNEL_ELF_DEPS = $(filter-out %: ,$(file < $(KERNEL_ELF).d)) $(LAST_BUILD_CONFIG) diff --git a/14_virtual_mem_part2_mmio_remap/Makefile b/14_virtual_mem_part2_mmio_remap/Makefile index 1a19e601..20007cec 100644 --- a/14_virtual_mem_part2_mmio_remap/Makefile +++ b/14_virtual_mem_part2_mmio_remap/Makefile @@ -74,7 +74,7 @@ LAST_BUILD_CONFIG = target/$(BSP).build_config KERNEL_ELF = target/$(TARGET)/release/kernel # This parses cargo's dep-info file. # https://doc.rust-lang.org/cargo/guide/build-cache.html#dep-info-files -KERNEL_ELF_DEPS = $(filter-out %: ,$(file < $(KERNEL_ELF_RAW).d)) $(LAST_BUILD_CONFIG) +KERNEL_ELF_DEPS = $(filter-out %: ,$(file < $(KERNEL_ELF).d)) $(LAST_BUILD_CONFIG) diff --git a/15_virtual_mem_part3_precomputed_tables/README.md b/15_virtual_mem_part3_precomputed_tables/README.md index d3ec21e2..b34c06b7 100644 --- a/15_virtual_mem_part3_precomputed_tables/README.md +++ b/15_virtual_mem_part3_precomputed_tables/README.md @@ -1845,7 +1845,7 @@ diff -uNr 14_virtual_mem_part2_mmio_remap/Makefile 15_virtual_mem_part3_precompu +KERNEL_ELF_RAW = target/$(TARGET)/release/kernel # This parses cargo's dep-info file. # https://doc.rust-lang.org/cargo/guide/build-cache.html#dep-info-files --KERNEL_ELF_DEPS = $(filter-out modulo: ,$(file < $(KERNEL_ELF_RAW).d)) $(LAST_BUILD_CONFIG) +-KERNEL_ELF_DEPS = $(filter-out modulo: ,$(file < $(KERNEL_ELF).d)) $(LAST_BUILD_CONFIG) +KERNEL_ELF_RAW_DEPS = $(filter-out modulo: ,$(file < $(KERNEL_ELF_RAW).d)) $(LAST_BUILD_CONFIG) + +##------------------------------------------------------------------------------ From dc4e69155ea6cdbf2107bfe25f84180ae27b0be5 Mon Sep 17 00:00:00 2001 From: Andre Richter Date: Mon, 9 May 2022 09:13:02 +0200 Subject: [PATCH 28/75] Fix rust-analyzer targets --- 01_wait_forever/.vscode/settings.json | 2 +- 02_runtime_init/.vscode/settings.json | 2 +- 03_hacky_hello_world/.vscode/settings.json | 2 +- 04_safe_globals/.vscode/settings.json | 2 +- 05_drivers_gpio_uart/.vscode/settings.json | 2 +- 06_uart_chainloader/.vscode/settings.json | 2 +- 07_timestamps/.vscode/settings.json | 2 +- 08_hw_debug_JTAG/.vscode/settings.json | 2 +- 09_privilege_level/.vscode/settings.json | 2 +- 10_virtual_mem_part1_identity_mapping/.vscode/settings.json | 2 +- 11_exceptions_part1_groundwork/.vscode/settings.json | 2 +- 11 files changed, 11 insertions(+), 11 deletions(-) diff --git a/01_wait_forever/.vscode/settings.json b/01_wait_forever/.vscode/settings.json index 292bf2a9..d1916456 100644 --- a/01_wait_forever/.vscode/settings.json +++ b/01_wait_forever/.vscode/settings.json @@ -4,7 +4,7 @@ "rust-analyzer.cargo.target": "aarch64-unknown-none-softfloat", "rust-analyzer.cargo.features": ["bsp_rpi3"], "rust-analyzer.checkOnSave.allTargets": false, - "rust-analyzer.checkOnSave.extraArgs": ["--lib", "--bins"], + "rust-analyzer.checkOnSave.extraArgs": ["--bins"], "rust-analyzer.lens.debug": false, "rust-analyzer.lens.run": false } diff --git a/02_runtime_init/.vscode/settings.json b/02_runtime_init/.vscode/settings.json index 292bf2a9..d1916456 100644 --- a/02_runtime_init/.vscode/settings.json +++ b/02_runtime_init/.vscode/settings.json @@ -4,7 +4,7 @@ "rust-analyzer.cargo.target": "aarch64-unknown-none-softfloat", "rust-analyzer.cargo.features": ["bsp_rpi3"], "rust-analyzer.checkOnSave.allTargets": false, - "rust-analyzer.checkOnSave.extraArgs": ["--lib", "--bins"], + "rust-analyzer.checkOnSave.extraArgs": ["--bins"], "rust-analyzer.lens.debug": false, "rust-analyzer.lens.run": false } diff --git a/03_hacky_hello_world/.vscode/settings.json b/03_hacky_hello_world/.vscode/settings.json index 292bf2a9..d1916456 100644 --- a/03_hacky_hello_world/.vscode/settings.json +++ b/03_hacky_hello_world/.vscode/settings.json @@ -4,7 +4,7 @@ "rust-analyzer.cargo.target": "aarch64-unknown-none-softfloat", "rust-analyzer.cargo.features": ["bsp_rpi3"], "rust-analyzer.checkOnSave.allTargets": false, - "rust-analyzer.checkOnSave.extraArgs": ["--lib", "--bins"], + "rust-analyzer.checkOnSave.extraArgs": ["--bins"], "rust-analyzer.lens.debug": false, "rust-analyzer.lens.run": false } diff --git a/04_safe_globals/.vscode/settings.json b/04_safe_globals/.vscode/settings.json index 292bf2a9..d1916456 100644 --- a/04_safe_globals/.vscode/settings.json +++ b/04_safe_globals/.vscode/settings.json @@ -4,7 +4,7 @@ "rust-analyzer.cargo.target": "aarch64-unknown-none-softfloat", "rust-analyzer.cargo.features": ["bsp_rpi3"], "rust-analyzer.checkOnSave.allTargets": false, - "rust-analyzer.checkOnSave.extraArgs": ["--lib", "--bins"], + "rust-analyzer.checkOnSave.extraArgs": ["--bins"], "rust-analyzer.lens.debug": false, "rust-analyzer.lens.run": false } diff --git a/05_drivers_gpio_uart/.vscode/settings.json b/05_drivers_gpio_uart/.vscode/settings.json index 292bf2a9..d1916456 100644 --- a/05_drivers_gpio_uart/.vscode/settings.json +++ b/05_drivers_gpio_uart/.vscode/settings.json @@ -4,7 +4,7 @@ "rust-analyzer.cargo.target": "aarch64-unknown-none-softfloat", "rust-analyzer.cargo.features": ["bsp_rpi3"], "rust-analyzer.checkOnSave.allTargets": false, - "rust-analyzer.checkOnSave.extraArgs": ["--lib", "--bins"], + "rust-analyzer.checkOnSave.extraArgs": ["--bins"], "rust-analyzer.lens.debug": false, "rust-analyzer.lens.run": false } diff --git a/06_uart_chainloader/.vscode/settings.json b/06_uart_chainloader/.vscode/settings.json index 292bf2a9..d1916456 100644 --- a/06_uart_chainloader/.vscode/settings.json +++ b/06_uart_chainloader/.vscode/settings.json @@ -4,7 +4,7 @@ "rust-analyzer.cargo.target": "aarch64-unknown-none-softfloat", "rust-analyzer.cargo.features": ["bsp_rpi3"], "rust-analyzer.checkOnSave.allTargets": false, - "rust-analyzer.checkOnSave.extraArgs": ["--lib", "--bins"], + "rust-analyzer.checkOnSave.extraArgs": ["--bins"], "rust-analyzer.lens.debug": false, "rust-analyzer.lens.run": false } diff --git a/07_timestamps/.vscode/settings.json b/07_timestamps/.vscode/settings.json index 292bf2a9..d1916456 100644 --- a/07_timestamps/.vscode/settings.json +++ b/07_timestamps/.vscode/settings.json @@ -4,7 +4,7 @@ "rust-analyzer.cargo.target": "aarch64-unknown-none-softfloat", "rust-analyzer.cargo.features": ["bsp_rpi3"], "rust-analyzer.checkOnSave.allTargets": false, - "rust-analyzer.checkOnSave.extraArgs": ["--lib", "--bins"], + "rust-analyzer.checkOnSave.extraArgs": ["--bins"], "rust-analyzer.lens.debug": false, "rust-analyzer.lens.run": false } diff --git a/08_hw_debug_JTAG/.vscode/settings.json b/08_hw_debug_JTAG/.vscode/settings.json index 292bf2a9..d1916456 100644 --- a/08_hw_debug_JTAG/.vscode/settings.json +++ b/08_hw_debug_JTAG/.vscode/settings.json @@ -4,7 +4,7 @@ "rust-analyzer.cargo.target": "aarch64-unknown-none-softfloat", "rust-analyzer.cargo.features": ["bsp_rpi3"], "rust-analyzer.checkOnSave.allTargets": false, - "rust-analyzer.checkOnSave.extraArgs": ["--lib", "--bins"], + "rust-analyzer.checkOnSave.extraArgs": ["--bins"], "rust-analyzer.lens.debug": false, "rust-analyzer.lens.run": false } diff --git a/09_privilege_level/.vscode/settings.json b/09_privilege_level/.vscode/settings.json index 292bf2a9..d1916456 100644 --- a/09_privilege_level/.vscode/settings.json +++ b/09_privilege_level/.vscode/settings.json @@ -4,7 +4,7 @@ "rust-analyzer.cargo.target": "aarch64-unknown-none-softfloat", "rust-analyzer.cargo.features": ["bsp_rpi3"], "rust-analyzer.checkOnSave.allTargets": false, - "rust-analyzer.checkOnSave.extraArgs": ["--lib", "--bins"], + "rust-analyzer.checkOnSave.extraArgs": ["--bins"], "rust-analyzer.lens.debug": false, "rust-analyzer.lens.run": false } diff --git a/10_virtual_mem_part1_identity_mapping/.vscode/settings.json b/10_virtual_mem_part1_identity_mapping/.vscode/settings.json index 292bf2a9..d1916456 100644 --- a/10_virtual_mem_part1_identity_mapping/.vscode/settings.json +++ b/10_virtual_mem_part1_identity_mapping/.vscode/settings.json @@ -4,7 +4,7 @@ "rust-analyzer.cargo.target": "aarch64-unknown-none-softfloat", "rust-analyzer.cargo.features": ["bsp_rpi3"], "rust-analyzer.checkOnSave.allTargets": false, - "rust-analyzer.checkOnSave.extraArgs": ["--lib", "--bins"], + "rust-analyzer.checkOnSave.extraArgs": ["--bins"], "rust-analyzer.lens.debug": false, "rust-analyzer.lens.run": false } diff --git a/11_exceptions_part1_groundwork/.vscode/settings.json b/11_exceptions_part1_groundwork/.vscode/settings.json index 292bf2a9..d1916456 100644 --- a/11_exceptions_part1_groundwork/.vscode/settings.json +++ b/11_exceptions_part1_groundwork/.vscode/settings.json @@ -4,7 +4,7 @@ "rust-analyzer.cargo.target": "aarch64-unknown-none-softfloat", "rust-analyzer.cargo.features": ["bsp_rpi3"], "rust-analyzer.checkOnSave.allTargets": false, - "rust-analyzer.checkOnSave.extraArgs": ["--lib", "--bins"], + "rust-analyzer.checkOnSave.extraArgs": ["--bins"], "rust-analyzer.lens.debug": false, "rust-analyzer.lens.run": false } From 4ab609ba3937876b90a55b82904cb121d0fb86ef Mon Sep 17 00:00:00 2001 From: Andre Richter Date: Mon, 9 May 2022 20:18:45 +0200 Subject: [PATCH 29/75] Update Makefile --- X1_JTAG_boot/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/X1_JTAG_boot/Makefile b/X1_JTAG_boot/Makefile index a497ad81..b89cee8c 100644 --- a/X1_JTAG_boot/Makefile +++ b/X1_JTAG_boot/Makefile @@ -61,7 +61,7 @@ LAST_BUILD_CONFIG = target/$(BSP).build_config KERNEL_ELF = target/$(TARGET)/release/kernel # This parses cargo's dep-info file. # https://doc.rust-lang.org/cargo/guide/build-cache.html#dep-info-files -KERNEL_ELF_DEPS = $(filter-out %: ,$(file < $(KERNEL_ELF_RAW).d)) $(LAST_BUILD_CONFIG) +KERNEL_ELF_DEPS = $(filter-out %: ,$(file < $(KERNEL_ELF).d)) $(LAST_BUILD_CONFIG) From fec4f9b6f284e55f5b0d96e57eccbdaf358cc447 Mon Sep 17 00:00:00 2001 From: Andre Richter Date: Mon, 16 May 2022 21:55:17 +0200 Subject: [PATCH 30/75] Rework driver subsystem - Remove the panic version of the GPIO and UART driver. While they were a neat idea, it proved tedious to drag them along different tutorials where the virtual memory situation kept on changing. Actually, not much is lost, since the benefit was only of theoretical nature until now, since everything is still single-threaded with NullLocks. It is still possible to re-introduce them later. - Refactor driver bringup starting with tutorial 14. Instantiating the drivers only when we are already capable of using the remapped MMIO address makes the kernel a lot more robust, and the drivers need not care whether their MMIO addresses are good to use already or not. - Use console and irq_manager references from the generic kernel code. This improves decoupling from the BSP, and is needed as a basis for tutorial 14. --- .gitignore | 3 +- 03_hacky_hello_world/README.md | 19 +- 03_hacky_hello_world/src/console.rs | 13 + 03_hacky_hello_world/src/print.rs | 4 +- 04_safe_globals/README.md | 46 +- .../src/bsp/raspberrypi/console.rs | 4 +- 04_safe_globals/src/console.rs | 15 +- 04_safe_globals/src/main.rs | 7 +- 04_safe_globals/src/print.rs | 6 +- 05_drivers_gpio_uart/README.md | 234 +-- .../src/bsp/device_driver/bcm/bcm2xxx_gpio.rs | 23 +- .../device_driver/bcm/bcm2xxx_pl011_uart.rs | 23 +- 05_drivers_gpio_uart/src/bsp/raspberrypi.rs | 11 - .../src/bsp/raspberrypi/console.rs | 27 +- .../src/bsp/raspberrypi/driver.rs | 12 +- 05_drivers_gpio_uart/src/console.rs | 15 +- 05_drivers_gpio_uart/src/main.rs | 12 +- 05_drivers_gpio_uart/src/panic_wait.rs | 22 +- 05_drivers_gpio_uart/src/print.rs | 6 +- 06_uart_chainloader/README.md | 51 +- .../src/bsp/device_driver/bcm/bcm2xxx_gpio.rs | 21 +- .../device_driver/bcm/bcm2xxx_pl011_uart.rs | 23 +- 06_uart_chainloader/src/bsp/raspberrypi.rs | 11 - .../src/bsp/raspberrypi/console.rs | 27 +- .../src/bsp/raspberrypi/driver.rs | 12 +- .../src/bsp/raspberrypi/memory.rs | 4 +- 06_uart_chainloader/src/console.rs | 15 +- 06_uart_chainloader/src/main.rs | 3 +- 06_uart_chainloader/src/panic_wait.rs | 22 +- 06_uart_chainloader/src/print.rs | 6 +- 07_timestamps/README.md | 51 +- .../src/bsp/device_driver/bcm/bcm2xxx_gpio.rs | 21 +- .../device_driver/bcm/bcm2xxx_pl011_uart.rs | 23 +- 07_timestamps/src/bsp/raspberrypi.rs | 11 - 07_timestamps/src/bsp/raspberrypi/console.rs | 27 +- 07_timestamps/src/bsp/raspberrypi/driver.rs | 12 +- 07_timestamps/src/console.rs | 15 +- 07_timestamps/src/panic_wait.rs | 22 +- 07_timestamps/src/print.rs | 6 +- .../src/bsp/device_driver/bcm/bcm2xxx_gpio.rs | 21 +- .../device_driver/bcm/bcm2xxx_pl011_uart.rs | 23 +- 08_hw_debug_JTAG/src/bsp/raspberrypi.rs | 11 - .../src/bsp/raspberrypi/console.rs | 27 +- .../src/bsp/raspberrypi/driver.rs | 12 +- 08_hw_debug_JTAG/src/console.rs | 15 +- 08_hw_debug_JTAG/src/panic_wait.rs | 22 +- 08_hw_debug_JTAG/src/print.rs | 6 +- 09_privilege_level/README.md | 42 +- .../src/bsp/device_driver/bcm/bcm2xxx_gpio.rs | 21 +- .../device_driver/bcm/bcm2xxx_pl011_uart.rs | 23 +- 09_privilege_level/src/bsp/raspberrypi.rs | 11 - .../src/bsp/raspberrypi/console.rs | 27 +- .../src/bsp/raspberrypi/driver.rs | 12 +- 09_privilege_level/src/console.rs | 15 +- 09_privilege_level/src/main.rs | 7 +- 09_privilege_level/src/panic_wait.rs | 22 +- 09_privilege_level/src/print.rs | 6 +- .../README.md | 50 +- .../src/bsp/device_driver/bcm/bcm2xxx_gpio.rs | 21 +- .../device_driver/bcm/bcm2xxx_pl011_uart.rs | 23 +- .../src/bsp/raspberrypi.rs | 11 - .../src/bsp/raspberrypi/console.rs | 27 +- .../src/bsp/raspberrypi/driver.rs | 12 +- .../src/console.rs | 15 +- .../src/main.rs | 7 +- .../src/panic_wait.rs | 22 +- .../src/print.rs | 6 +- 11_exceptions_part1_groundwork/README.md | 85 +- .../src/bsp/device_driver/bcm/bcm2xxx_gpio.rs | 21 +- .../device_driver/bcm/bcm2xxx_pl011_uart.rs | 23 +- .../src/bsp/raspberrypi.rs | 11 - .../src/bsp/raspberrypi/console.rs | 27 +- .../src/bsp/raspberrypi/driver.rs | 12 +- 11_exceptions_part1_groundwork/src/console.rs | 15 +- 11_exceptions_part1_groundwork/src/main.rs | 7 +- .../src/panic_wait.rs | 22 +- 11_exceptions_part1_groundwork/src/print.rs | 6 +- 12_integrated_testing/README.md | 35 +- .../src/bsp/device_driver/bcm/bcm2xxx_gpio.rs | 21 +- .../device_driver/bcm/bcm2xxx_pl011_uart.rs | 23 +- .../kernel/src/bsp/raspberrypi.rs | 11 - .../kernel/src/bsp/raspberrypi/console.rs | 38 +- .../kernel/src/bsp/raspberrypi/driver.rs | 15 +- 12_integrated_testing/kernel/src/console.rs | 15 +- 12_integrated_testing/kernel/src/driver.rs | 5 + 12_integrated_testing/kernel/src/lib.rs | 4 +- 12_integrated_testing/kernel/src/main.rs | 7 +- .../kernel/src/panic_wait.rs | 22 +- 12_integrated_testing/kernel/src/print.rs | 6 +- .../kernel/tests/00_console_sanity.rs | 8 +- .../kernel/tests/01_timer_sanity.rs | 6 +- .../tests/02_exception_sync_page_fault.rs | 5 +- .../tests/03_exception_restore_sanity.rs | 5 +- 13_exceptions_part2_peripheral_IRQs/README.md | 247 +-- .../kernel/src/_arch/aarch64/exception.rs | 6 +- .../kernel/src/bsp/device_driver/arm/gicv2.rs | 4 +- .../src/bsp/device_driver/bcm/bcm2xxx_gpio.rs | 21 +- .../bcm/bcm2xxx_interrupt_controller.rs | 7 +- .../device_driver/bcm/bcm2xxx_pl011_uart.rs | 28 +- .../kernel/src/bsp/raspberrypi.rs | 28 - .../kernel/src/bsp/raspberrypi/console.rs | 38 +- .../kernel/src/bsp/raspberrypi/driver.rs | 33 +- .../bsp/raspberrypi/exception/asynchronous.rs | 4 +- .../kernel/src/bsp/raspberrypi/memory.rs | 1 - .../kernel/src/console.rs | 15 +- .../kernel/src/driver.rs | 5 + .../kernel/src/exception/asynchronous.rs | 8 + .../kernel/src/lib.rs | 4 +- .../kernel/src/panic_wait.rs | 22 +- .../kernel/src/print.rs | 6 +- .../kernel/tests/00_console_sanity.rs | 8 +- .../kernel/tests/01_timer_sanity.rs | 6 +- .../tests/02_exception_sync_page_fault.rs | 5 +- .../tests/03_exception_restore_sanity.rs | 5 +- .../kernel/tests/04_exception_irq_sanity.rs | 5 +- 14_virtual_mem_part2_mmio_remap/README.md | 1626 ++++++++++------- .../kernel/src/_arch/aarch64/exception.rs | 6 +- .../kernel/src/bsp/device_driver/arm/gicv2.rs | 52 +- .../src/bsp/device_driver/arm/gicv2/gicc.rs | 31 +- .../src/bsp/device_driver/arm/gicv2/gicd.rs | 26 +- .../src/bsp/device_driver/bcm/bcm2xxx_gpio.rs | 72 +- .../bcm/bcm2xxx_interrupt_controller.rs | 24 +- .../peripheral_ic.rs | 45 +- .../device_driver/bcm/bcm2xxx_pl011_uart.rs | 89 +- .../kernel/src/bsp/device_driver/common.rs | 7 +- .../kernel/src/bsp/raspberrypi.rs | 35 - .../kernel/src/bsp/raspberrypi/console.rs | 62 - .../kernel/src/bsp/raspberrypi/driver.rs | 171 +- .../bsp/raspberrypi/exception/asynchronous.rs | 13 +- .../kernel/src/bsp/raspberrypi/memory.rs | 3 - .../kernel/src/console.rs | 30 +- .../kernel/src/console/null_console.rs | 41 + .../kernel/src/driver.rs | 31 +- .../kernel/src/exception/asynchronous.rs | 28 +- .../asynchronous/null_irq_manager.rs | 44 + .../kernel/src/lib.rs | 17 +- .../kernel/src/main.rs | 23 +- .../kernel/src/memory.rs | 8 +- .../kernel/src/memory/mmu/mapping_record.rs | 16 + .../kernel/src/panic_wait.rs | 22 +- .../kernel/src/print.rs | 6 +- .../kernel/tests/00_console_sanity.rs | 21 +- .../kernel/tests/01_timer_sanity.rs | 19 +- .../tests/02_exception_sync_page_fault.rs | 16 +- .../tests/03_exception_restore_sanity.rs | 16 +- .../kernel/tests/04_exception_irq_sanity.rs | 19 +- .../README.md | 304 ++- .../kernel/src/_arch/aarch64/exception.rs | 6 +- .../kernel/src/bsp/device_driver/arm/gicv2.rs | 52 +- .../src/bsp/device_driver/arm/gicv2/gicc.rs | 31 +- .../src/bsp/device_driver/arm/gicv2/gicd.rs | 26 +- .../src/bsp/device_driver/bcm/bcm2xxx_gpio.rs | 72 +- .../bcm/bcm2xxx_interrupt_controller.rs | 24 +- .../peripheral_ic.rs | 45 +- .../device_driver/bcm/bcm2xxx_pl011_uart.rs | 89 +- .../kernel/src/bsp/device_driver/common.rs | 7 +- .../kernel/src/bsp/raspberrypi.rs | 35 - .../kernel/src/bsp/raspberrypi/console.rs | 92 - .../kernel/src/bsp/raspberrypi/driver.rs | 171 +- .../bsp/raspberrypi/exception/asynchronous.rs | 13 +- .../kernel/src/bsp/raspberrypi/memory.rs | 3 - .../kernel/src/console.rs | 30 +- .../kernel/src/console/null_console.rs | 41 + .../kernel/src/driver.rs | 31 +- .../kernel/src/exception/asynchronous.rs | 28 +- .../asynchronous/null_irq_manager.rs | 44 + .../kernel/src/lib.rs | 5 +- .../kernel/src/main.rs | 28 +- .../kernel/src/memory.rs | 8 +- .../kernel/src/memory/mmu/mapping_record.rs | 16 + .../kernel/src/panic_wait.rs | 22 +- .../kernel/src/print.rs | 6 +- .../kernel/tests/00_console_sanity.rs | 8 +- .../kernel/tests/01_timer_sanity.rs | 6 +- .../tests/02_exception_sync_page_fault.rs | 6 +- .../tests/03_exception_restore_sanity.rs | 6 +- .../kernel/tests/04_exception_irq_sanity.rs | 6 +- .../README.md | 132 +- .../kernel/src/_arch/aarch64/exception.rs | 6 +- .../kernel/src/bsp/device_driver/arm/gicv2.rs | 52 +- .../src/bsp/device_driver/arm/gicv2/gicc.rs | 31 +- .../src/bsp/device_driver/arm/gicv2/gicd.rs | 26 +- .../src/bsp/device_driver/bcm/bcm2xxx_gpio.rs | 72 +- .../bcm/bcm2xxx_interrupt_controller.rs | 24 +- .../peripheral_ic.rs | 45 +- .../device_driver/bcm/bcm2xxx_pl011_uart.rs | 89 +- .../kernel/src/bsp/device_driver/common.rs | 7 +- .../kernel/src/bsp/raspberrypi.rs | 35 - .../kernel/src/bsp/raspberrypi/console.rs | 98 - .../kernel/src/bsp/raspberrypi/driver.rs | 171 +- .../bsp/raspberrypi/exception/asynchronous.rs | 13 +- .../kernel/src/bsp/raspberrypi/memory.rs | 3 - .../kernel/src/console.rs | 30 +- .../kernel/src/console/null_console.rs | 41 + .../kernel/src/driver.rs | 31 +- .../kernel/src/exception/asynchronous.rs | 28 +- .../asynchronous/null_irq_manager.rs | 44 + .../kernel/src/lib.rs | 5 +- .../kernel/src/main.rs | 28 +- .../kernel/src/memory.rs | 8 +- .../kernel/src/memory/mmu/mapping_record.rs | 16 + .../kernel/src/panic_wait.rs | 22 +- .../kernel/src/print.rs | 6 +- .../kernel/tests/00_console_sanity.rs | 8 +- .../kernel/tests/01_timer_sanity.rs | 6 +- .../tests/02_exception_sync_page_fault.rs | 6 +- .../tests/03_exception_restore_sanity.rs | 6 +- .../kernel/tests/04_exception_irq_sanity.rs | 6 +- 17_kernel_symbols/Makefile | 2 +- 17_kernel_symbols/README.md | 17 +- .../kernel/src/_arch/aarch64/exception.rs | 6 +- .../kernel/src/bsp/device_driver/arm/gicv2.rs | 52 +- .../src/bsp/device_driver/arm/gicv2/gicc.rs | 31 +- .../src/bsp/device_driver/arm/gicv2/gicd.rs | 26 +- .../src/bsp/device_driver/bcm/bcm2xxx_gpio.rs | 72 +- .../bcm/bcm2xxx_interrupt_controller.rs | 24 +- .../peripheral_ic.rs | 45 +- .../device_driver/bcm/bcm2xxx_pl011_uart.rs | 89 +- .../kernel/src/bsp/device_driver/common.rs | 7 +- .../kernel/src/bsp/raspberrypi.rs | 35 - .../kernel/src/bsp/raspberrypi/console.rs | 98 - .../kernel/src/bsp/raspberrypi/driver.rs | 171 +- .../bsp/raspberrypi/exception/asynchronous.rs | 13 +- .../kernel/src/bsp/raspberrypi/memory.rs | 3 - 17_kernel_symbols/kernel/src/console.rs | 30 +- .../kernel/src/console/null_console.rs | 41 + 17_kernel_symbols/kernel/src/driver.rs | 31 +- .../kernel/src/exception/asynchronous.rs | 28 +- .../asynchronous/null_irq_manager.rs | 44 + 17_kernel_symbols/kernel/src/lib.rs | 5 +- 17_kernel_symbols/kernel/src/main.rs | 28 +- 17_kernel_symbols/kernel/src/memory.rs | 8 +- .../kernel/src/memory/mmu/mapping_record.rs | 16 + 17_kernel_symbols/kernel/src/panic_wait.rs | 22 +- 17_kernel_symbols/kernel/src/print.rs | 6 +- .../kernel/tests/00_console_sanity.rs | 8 +- .../kernel/tests/01_timer_sanity.rs | 6 +- .../tests/02_exception_sync_page_fault.rs | 6 +- .../tests/03_exception_restore_sanity.rs | 6 +- .../kernel/tests/04_exception_irq_sanity.rs | 6 +- 18_backtrace/Makefile | 2 +- 18_backtrace/README.md | 40 +- .../kernel/src/_arch/aarch64/exception.rs | 6 +- .../kernel/src/bsp/device_driver/arm/gicv2.rs | 52 +- .../src/bsp/device_driver/arm/gicv2/gicc.rs | 31 +- .../src/bsp/device_driver/arm/gicv2/gicd.rs | 26 +- .../src/bsp/device_driver/bcm/bcm2xxx_gpio.rs | 72 +- .../bcm/bcm2xxx_interrupt_controller.rs | 24 +- .../peripheral_ic.rs | 45 +- .../device_driver/bcm/bcm2xxx_pl011_uart.rs | 89 +- .../kernel/src/bsp/device_driver/common.rs | 7 +- 18_backtrace/kernel/src/bsp/raspberrypi.rs | 35 - .../kernel/src/bsp/raspberrypi/console.rs | 98 - .../kernel/src/bsp/raspberrypi/driver.rs | 171 +- .../bsp/raspberrypi/exception/asynchronous.rs | 13 +- .../kernel/src/bsp/raspberrypi/memory.rs | 3 - 18_backtrace/kernel/src/console.rs | 30 +- .../kernel/src/console/null_console.rs | 41 + 18_backtrace/kernel/src/driver.rs | 31 +- .../kernel/src/exception/asynchronous.rs | 28 +- .../asynchronous/null_irq_manager.rs | 44 + 18_backtrace/kernel/src/lib.rs | 5 +- 18_backtrace/kernel/src/main.rs | 28 +- 18_backtrace/kernel/src/memory.rs | 8 +- .../kernel/src/memory/mmu/mapping_record.rs | 16 + 18_backtrace/kernel/src/panic_wait.rs | 22 +- 18_backtrace/kernel/src/print.rs | 6 +- .../kernel/tests/00_console_sanity.rs | 8 +- 18_backtrace/kernel/tests/01_timer_sanity.rs | 6 +- .../tests/02_exception_sync_page_fault.rs | 6 +- .../tests/03_exception_restore_sanity.rs | 6 +- .../kernel/tests/04_exception_irq_sanity.rs | 6 +- .../kernel/tests/05_backtrace_sanity.rs | 6 +- .../tests/06_backtrace_invalid_frame.rs | 6 +- .../kernel/tests/07_backtrace_invalid_link.rs | 6 +- X1_JTAG_boot/.vscode/settings.json | 2 +- .../src/bsp/device_driver/bcm/bcm2xxx_gpio.rs | 21 +- .../device_driver/bcm/bcm2xxx_pl011_uart.rs | 23 +- X1_JTAG_boot/src/bsp/raspberrypi.rs | 11 - X1_JTAG_boot/src/bsp/raspberrypi/console.rs | 27 +- X1_JTAG_boot/src/bsp/raspberrypi/driver.rs | 12 +- X1_JTAG_boot/src/console.rs | 15 +- X1_JTAG_boot/src/panic_wait.rs | 22 +- X1_JTAG_boot/src/print.rs | 6 +- 284 files changed, 4839 insertions(+), 4643 deletions(-) delete mode 100644 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/console.rs create mode 100644 14_virtual_mem_part2_mmio_remap/kernel/src/console/null_console.rs create mode 100644 14_virtual_mem_part2_mmio_remap/kernel/src/exception/asynchronous/null_irq_manager.rs delete mode 100644 15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/console.rs create mode 100644 15_virtual_mem_part3_precomputed_tables/kernel/src/console/null_console.rs create mode 100644 15_virtual_mem_part3_precomputed_tables/kernel/src/exception/asynchronous/null_irq_manager.rs delete mode 100644 16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi/console.rs create mode 100644 16_virtual_mem_part4_higher_half_kernel/kernel/src/console/null_console.rs create mode 100644 16_virtual_mem_part4_higher_half_kernel/kernel/src/exception/asynchronous/null_irq_manager.rs delete mode 100644 17_kernel_symbols/kernel/src/bsp/raspberrypi/console.rs create mode 100644 17_kernel_symbols/kernel/src/console/null_console.rs create mode 100644 17_kernel_symbols/kernel/src/exception/asynchronous/null_irq_manager.rs delete mode 100644 18_backtrace/kernel/src/bsp/raspberrypi/console.rs create mode 100644 18_backtrace/kernel/src/console/null_console.rs create mode 100644 18_backtrace/kernel/src/exception/asynchronous/null_irq_manager.rs diff --git a/.gitignore b/.gitignore index 19660052..5bc8cd8d 100644 --- a/.gitignore +++ b/.gitignore @@ -3,7 +3,8 @@ **/kernel8.img node_modules +.bundle .vendor Gemfile.lock -package-lock.json +package*.json diff --git a/03_hacky_hello_world/README.md b/03_hacky_hello_world/README.md index d868459f..71293c56 100644 --- a/03_hacky_hello_world/README.md +++ b/03_hacky_hello_world/README.md @@ -188,13 +188,15 @@ diff -uNr 02_runtime_init/src/bsp/raspberrypi.rs 03_hacky_hello_world/src/bsp/ra diff -uNr 02_runtime_init/src/console.rs 03_hacky_hello_world/src/console.rs --- 02_runtime_init/src/console.rs +++ 03_hacky_hello_world/src/console.rs -@@ -0,0 +1,19 @@ +@@ -0,0 +1,32 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2018-2022 Andre Richter + +//! System console. + ++use crate::bsp; ++ +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- @@ -208,6 +210,17 @@ diff -uNr 02_runtime_init/src/console.rs 03_hacky_hello_world/src/console.rs + /// intention. + pub use core::fmt::Write; +} ++ ++//-------------------------------------------------------------------------------------------------- ++// Public Code ++//-------------------------------------------------------------------------------------------------- ++ ++/// Return a reference to the console. ++/// ++/// This is the global console used by all printing macros. ++pub fn console() -> impl interface::Write { ++ bsp::console::console() ++} diff -uNr 02_runtime_init/src/main.rs 03_hacky_hello_world/src/main.rs --- 02_runtime_init/src/main.rs @@ -317,7 +330,7 @@ diff -uNr 02_runtime_init/src/print.rs 03_hacky_hello_world/src/print.rs + +//! Printing. + -+use crate::{bsp, console}; ++use crate::console; +use core::fmt; + +//-------------------------------------------------------------------------------------------------- @@ -328,7 +341,7 @@ diff -uNr 02_runtime_init/src/print.rs 03_hacky_hello_world/src/print.rs +pub fn _print(args: fmt::Arguments) { + use console::interface::Write; + -+ bsp::console::console().write_fmt(args).unwrap(); ++ console::console().write_fmt(args).unwrap(); +} + +/// Prints without a newline. diff --git a/03_hacky_hello_world/src/console.rs b/03_hacky_hello_world/src/console.rs index 5ab4cc45..7d940f29 100644 --- a/03_hacky_hello_world/src/console.rs +++ b/03_hacky_hello_world/src/console.rs @@ -4,6 +4,8 @@ //! System console. +use crate::bsp; + //-------------------------------------------------------------------------------------------------- // Public Definitions //-------------------------------------------------------------------------------------------------- @@ -17,3 +19,14 @@ pub mod interface { /// intention. pub use core::fmt::Write; } + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +/// Return a reference to the console. +/// +/// This is the global console used by all printing macros. +pub fn console() -> impl interface::Write { + bsp::console::console() +} diff --git a/03_hacky_hello_world/src/print.rs b/03_hacky_hello_world/src/print.rs index 81c6d179..05ef2aea 100644 --- a/03_hacky_hello_world/src/print.rs +++ b/03_hacky_hello_world/src/print.rs @@ -4,7 +4,7 @@ //! Printing. -use crate::{bsp, console}; +use crate::console; use core::fmt; //-------------------------------------------------------------------------------------------------- @@ -15,7 +15,7 @@ use core::fmt; pub fn _print(args: fmt::Arguments) { use console::interface::Write; - bsp::console::console().write_fmt(args).unwrap(); + console::console().write_fmt(args).unwrap(); } /// Prints without a newline. diff --git a/04_safe_globals/README.md b/04_safe_globals/README.md index 18827b5c..58c14dc2 100644 --- a/04_safe_globals/README.md +++ b/04_safe_globals/README.md @@ -148,7 +148,7 @@ diff -uNr 03_hacky_hello_world/src/bsp/raspberrypi/console.rs 04_safe_globals/sr } Ok(()) -@@ -41,7 +80,37 @@ +@@ -41,7 +80,39 @@ // Public Code //-------------------------------------------------------------------------------------------------- @@ -164,9 +164,9 @@ diff -uNr 03_hacky_hello_world/src/bsp/raspberrypi/console.rs 04_safe_globals/sr /// Return a reference to the console. -pub fn console() -> impl console::interface::Write { - QEMUOutput {} -+pub fn console() -> &'static impl console::interface::All { ++pub fn console() -> &'static dyn console::interface::All { + &QEMU_OUTPUT -+} + } + +//------------------------------------------------------------------------------ +// OS Interface Code @@ -187,12 +187,14 @@ diff -uNr 03_hacky_hello_world/src/bsp/raspberrypi/console.rs 04_safe_globals/sr + fn chars_written(&self) -> usize { + self.inner.lock(|inner| inner.chars_written) + } - } ++} ++ ++impl console::interface::All for QEMUOutput {} diff -uNr 03_hacky_hello_world/src/console.rs 04_safe_globals/src/console.rs --- 03_hacky_hello_world/src/console.rs +++ 04_safe_globals/src/console.rs -@@ -10,10 +10,22 @@ +@@ -12,12 +12,24 @@ /// Console interfaces. pub mod interface { @@ -218,7 +220,17 @@ diff -uNr 03_hacky_hello_world/src/console.rs 04_safe_globals/src/console.rs + } + + /// Trait alias for a full-fledged console. -+ pub trait All = Write + Statistics; ++ pub trait All: Write + Statistics {} + } + + //-------------------------------------------------------------------------------------------------- +@@ -27,6 +39,6 @@ + /// Return a reference to the console. + /// + /// This is the global console used by all printing macros. +-pub fn console() -> impl interface::Write { ++pub fn console() -> &'static dyn interface::All { + bsp::console::console() } diff -uNr 03_hacky_hello_world/src/main.rs 04_safe_globals/src/main.rs @@ -240,25 +252,35 @@ diff -uNr 03_hacky_hello_world/src/main.rs 04_safe_globals/src/main.rs /// Early init code. /// -@@ -124,7 +126,15 @@ +@@ -124,7 +126,12 @@ /// /// - Only a single core must be active and running this function. unsafe fn kernel_init() -> ! { - println!("Hello from Rust!"); -+ use console::interface::Statistics; ++ use console::console; - panic!("Stopping here.") + println!("[0] Hello from Rust!"); + -+ println!( -+ "[1] Chars written: {}", -+ bsp::console::console().chars_written() -+ ); ++ println!("[1] Chars written: {}", console().chars_written()); + + println!("[2] Stopping here."); + cpu::wait_forever() } +diff -uNr 03_hacky_hello_world/src/print.rs 04_safe_globals/src/print.rs +--- 03_hacky_hello_world/src/print.rs ++++ 04_safe_globals/src/print.rs +@@ -13,8 +13,6 @@ + + #[doc(hidden)] + pub fn _print(args: fmt::Arguments) { +- use console::interface::Write; +- + console::console().write_fmt(args).unwrap(); + } + + diff -uNr 03_hacky_hello_world/src/synchronization.rs 04_safe_globals/src/synchronization.rs --- 03_hacky_hello_world/src/synchronization.rs +++ 04_safe_globals/src/synchronization.rs diff --git a/04_safe_globals/src/bsp/raspberrypi/console.rs b/04_safe_globals/src/bsp/raspberrypi/console.rs index 774dbadb..6427e099 100644 --- a/04_safe_globals/src/bsp/raspberrypi/console.rs +++ b/04_safe_globals/src/bsp/raspberrypi/console.rs @@ -90,7 +90,7 @@ impl QEMUOutput { } /// Return a reference to the console. -pub fn console() -> &'static impl console::interface::All { +pub fn console() -> &'static dyn console::interface::All { &QEMU_OUTPUT } @@ -114,3 +114,5 @@ impl console::interface::Statistics for QEMUOutput { self.inner.lock(|inner| inner.chars_written) } } + +impl console::interface::All for QEMUOutput {} diff --git a/04_safe_globals/src/console.rs b/04_safe_globals/src/console.rs index 3894c18d..94e00f84 100644 --- a/04_safe_globals/src/console.rs +++ b/04_safe_globals/src/console.rs @@ -4,6 +4,8 @@ //! System console. +use crate::bsp; + //-------------------------------------------------------------------------------------------------- // Public Definitions //-------------------------------------------------------------------------------------------------- @@ -27,5 +29,16 @@ pub mod interface { } /// Trait alias for a full-fledged console. - pub trait All = Write + Statistics; + pub trait All: Write + Statistics {} +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +/// Return a reference to the console. +/// +/// This is the global console used by all printing macros. +pub fn console() -> &'static dyn interface::All { + bsp::console::console() } diff --git a/04_safe_globals/src/main.rs b/04_safe_globals/src/main.rs index 15db4a21..4726477d 100644 --- a/04_safe_globals/src/main.rs +++ b/04_safe_globals/src/main.rs @@ -126,14 +126,11 @@ mod synchronization; /// /// - Only a single core must be active and running this function. unsafe fn kernel_init() -> ! { - use console::interface::Statistics; + use console::console; println!("[0] Hello from Rust!"); - println!( - "[1] Chars written: {}", - bsp::console::console().chars_written() - ); + println!("[1] Chars written: {}", console().chars_written()); println!("[2] Stopping here."); cpu::wait_forever() diff --git a/04_safe_globals/src/print.rs b/04_safe_globals/src/print.rs index 81c6d179..f69bad44 100644 --- a/04_safe_globals/src/print.rs +++ b/04_safe_globals/src/print.rs @@ -4,7 +4,7 @@ //! Printing. -use crate::{bsp, console}; +use crate::console; use core::fmt; //-------------------------------------------------------------------------------------------------- @@ -13,9 +13,7 @@ use core::fmt; #[doc(hidden)] pub fn _print(args: fmt::Arguments) { - use console::interface::Write; - - bsp::console::console().write_fmt(args).unwrap(); + console::console().write_fmt(args).unwrap(); } /// Prints without a newline. diff --git a/05_drivers_gpio_uart/README.md b/05_drivers_gpio_uart/README.md index 6f0057d6..555ac031 100644 --- a/05_drivers_gpio_uart/README.md +++ b/05_drivers_gpio_uart/README.md @@ -27,12 +27,6 @@ - `BSP`s now contain a memory map in `src/bsp/raspberrypi/memory.rs`. In the specific case, they contain the Raspberry's `MMIO` addresses which are used to instantiate the respective device drivers. -- We also modify the `panic!` handler, so that it does not anymore rely on `println!`, which uses - the globally-shared instance of the `UART` that might be locked when an error is encountered (for - now, this can't happen due to the `NullLock`, but with a real lock it becomes an issue). - - Instead, it creates a new UART driver instance, re-initializes the device and uses that one to - print. This increases the chances that the system is able to print a final important message - before it suspends itself. ## Boot it from SD card @@ -98,8 +92,8 @@ Miniterm 1.0 [0] mingo version 0.5.0 [1] Booting on: Raspberry Pi 3 [2] Drivers loaded: - 1. BCM GPIO - 2. BCM PL011 UART + 1. BCM PL011 UART + 2. BCM GPIO [3] Chars written: 117 [4] Echoing input now ``` @@ -234,7 +228,7 @@ diff -uNr 04_safe_globals/src/_arch/aarch64/cpu.rs 05_drivers_gpio_uart/src/_arc diff -uNr 04_safe_globals/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs 05_drivers_gpio_uart/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs --- 04_safe_globals/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs +++ 05_drivers_gpio_uart/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs -@@ -0,0 +1,225 @@ +@@ -0,0 +1,228 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2018-2022 Andre Richter @@ -345,16 +339,13 @@ diff -uNr 04_safe_globals/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs 05_drivers_g +/// Abstraction for the associated MMIO registers. +type Registers = MMIODerefWrapper; + -+//-------------------------------------------------------------------------------------------------- -+// Public Definitions -+//-------------------------------------------------------------------------------------------------- -+ -+pub struct GPIOInner { ++struct GPIOInner { + registers: Registers, +} + -+// Export the inner struct so that BSPs can use it for the panic handler. -+pub use GPIOInner as PanicGPIO; ++//-------------------------------------------------------------------------------------------------- ++// Public Definitions ++//-------------------------------------------------------------------------------------------------- + +/// Representation of the GPIO HW. +pub struct GPIO { @@ -362,7 +353,7 @@ diff -uNr 04_safe_globals/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs 05_drivers_g +} + +//-------------------------------------------------------------------------------------------------- -+// Public Code ++// Private Code +//-------------------------------------------------------------------------------------------------- + +impl GPIOInner { @@ -385,7 +376,7 @@ diff -uNr 04_safe_globals/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs 05_drivers_g + // Make an educated guess for a good delay value (Sequence described in the BCM2837 + // peripherals PDF). + // -+ // - According to Wikipedia, the fastest Pi3 clocks around 1.4 GHz. ++ // - According to Wikipedia, the fastest RPi4 clocks around 1.5 GHz. + // - The Linux 2837 GPIO driver waits 1 µs between the steps. + // + // So lets try to be on the safe side and default to 2000 cycles, which would equal 1 µs @@ -432,7 +423,13 @@ diff -uNr 04_safe_globals/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs 05_drivers_g + } +} + ++//-------------------------------------------------------------------------------------------------- ++// Public Code ++//-------------------------------------------------------------------------------------------------- ++ +impl GPIO { ++ pub const COMPATIBLE: &'static str = "BCM GPIO"; ++ + /// Create an instance. + /// + /// # Safety @@ -457,14 +454,14 @@ diff -uNr 04_safe_globals/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs 05_drivers_g + +impl driver::interface::DeviceDriver for GPIO { + fn compatible(&self) -> &'static str { -+ "BCM GPIO" ++ Self::COMPATIBLE + } +} diff -uNr 04_safe_globals/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs 05_drivers_gpio_uart/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs --- 04_safe_globals/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs +++ 05_drivers_gpio_uart/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs -@@ -0,0 +1,402 @@ +@@ -0,0 +1,407 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2018-2022 Andre Richter @@ -634,18 +631,15 @@ diff -uNr 04_safe_globals/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs 05_dri + NonBlocking, +} + -+//-------------------------------------------------------------------------------------------------- -+// Public Definitions -+//-------------------------------------------------------------------------------------------------- -+ -+pub struct PL011UartInner { ++struct PL011UartInner { + registers: Registers, + chars_written: usize, + chars_read: usize, +} + -+// Export the inner struct so that BSPs can use it for the panic handler. -+pub use PL011UartInner as PanicUart; ++//-------------------------------------------------------------------------------------------------- ++// Public Definitions ++//-------------------------------------------------------------------------------------------------- + +/// Representation of the UART. +pub struct PL011Uart { @@ -653,7 +647,7 @@ diff -uNr 04_safe_globals/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs 05_dri +} + +//-------------------------------------------------------------------------------------------------- -+// Public Code ++// Private Code +//-------------------------------------------------------------------------------------------------- + +impl PL011UartInner { @@ -793,7 +787,13 @@ diff -uNr 04_safe_globals/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs 05_dri + } +} + ++//-------------------------------------------------------------------------------------------------- ++// Public Code ++//-------------------------------------------------------------------------------------------------- ++ +impl PL011Uart { ++ pub const COMPATIBLE: &'static str = "BCM PL011 UART"; ++ + /// Create an instance. + /// + /// # Safety @@ -813,7 +813,7 @@ diff -uNr 04_safe_globals/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs 05_dri + +impl driver::interface::DeviceDriver for PL011Uart { + fn compatible(&self) -> &'static str { -+ "BCM PL011 UART" ++ Self::COMPATIBLE + } + + unsafe fn init(&self) -> Result<(), &'static str> { @@ -867,6 +867,8 @@ diff -uNr 04_safe_globals/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs 05_dri + self.inner.lock(|inner| inner.chars_read) + } +} ++ ++impl console::interface::All for PL011Uart {} diff -uNr 04_safe_globals/src/bsp/device_driver/bcm.rs 05_drivers_gpio_uart/src/bsp/device_driver/bcm.rs --- 04_safe_globals/src/bsp/device_driver/bcm.rs @@ -947,24 +949,19 @@ diff -uNr 04_safe_globals/src/bsp/device_driver.rs 05_drivers_gpio_uart/src/bsp/ diff -uNr 04_safe_globals/src/bsp/raspberrypi/console.rs 05_drivers_gpio_uart/src/bsp/raspberrypi/console.rs --- 04_safe_globals/src/bsp/raspberrypi/console.rs +++ 05_drivers_gpio_uart/src/bsp/raspberrypi/console.rs -@@ -4,113 +4,34 @@ +@@ -4,115 +4,13 @@ //! BSP console facilities. -use crate::{console, synchronization, synchronization::NullLock}; -+use super::memory; -+use crate::{bsp::device_driver, console}; - use core::fmt; - - //-------------------------------------------------------------------------------------------------- +-use core::fmt; +- +-//-------------------------------------------------------------------------------------------------- -// Private Definitions -+// Public Code - //-------------------------------------------------------------------------------------------------- - +-//-------------------------------------------------------------------------------------------------- +- -/// A mystical, magical device for generating QEMU output out of the void. -+/// In case of a panic, the panic handler uses this function to take a last shot at printing -+/// something before the system is halted. - /// +-/// -/// The mutex protected part. -struct QEMUOutputInner { - chars_written: usize, @@ -1007,13 +1004,9 @@ diff -uNr 04_safe_globals/src/bsp/raspberrypi/console.rs 05_drivers_gpio_uart/sr -/// Implementing `core::fmt::Write` enables usage of the `format_args!` macros, which in turn are -/// used to implement the `kernel`'s `print!` and `println!` macros. By implementing `write_str()`, -/// we get `write_fmt()` automatically. -+/// We try to init panic-versions of the GPIO and the UART. The panic versions are not protected -+/// with synchronization primitives, which increases chances that we get to print something, even -+/// when the kernel's default GPIO or UART instances happen to be locked at the time of the panic. - /// +-/// -/// The function takes an `&mut self`, so it must be implemented for the inner struct. -+/// # Safety - /// +-/// -/// See [`src/print.rs`]. -/// -/// [`src/print.rs`]: ../../print/index.html @@ -1031,11 +1024,12 @@ diff -uNr 04_safe_globals/src/bsp/raspberrypi/console.rs 05_drivers_gpio_uart/sr - Ok(()) - } -} -- --//-------------------------------------------------------------------------------------------------- --// Public Code --//-------------------------------------------------------------------------------------------------- -- ++use crate::console; + + //-------------------------------------------------------------------------------------------------- + // Public Code + //-------------------------------------------------------------------------------------------------- + -impl QEMUOutput { - /// Create a new instance. - pub const fn new() -> QEMUOutput { @@ -1043,18 +1037,10 @@ diff -uNr 04_safe_globals/src/bsp/raspberrypi/console.rs 05_drivers_gpio_uart/sr - inner: NullLock::new(QEMUOutputInner::new()), - } - } -+/// - Use only for printing during a panic. -+pub unsafe fn panic_console_out() -> impl fmt::Write { -+ let mut panic_gpio = device_driver::PanicGPIO::new(memory::map::mmio::GPIO_START); -+ let mut panic_uart = device_driver::PanicUart::new(memory::map::mmio::PL011_UART_START); -+ -+ panic_gpio.map_pl011_uart(); -+ panic_uart.init(); -+ panic_uart - } - +-} +- /// Return a reference to the console. - pub fn console() -> &'static impl console::interface::All { + pub fn console() -> &'static dyn console::interface::All { - &QEMU_OUTPUT -} - @@ -1077,20 +1063,23 @@ diff -uNr 04_safe_globals/src/bsp/raspberrypi/console.rs 05_drivers_gpio_uart/sr - fn chars_written(&self) -> usize { - self.inner.lock(|inner| inner.chars_written) - } -+ &super::PL011_UART ++ &super::driver::PL011_UART } +- +-impl console::interface::All for QEMUOutput {} diff -uNr 04_safe_globals/src/bsp/raspberrypi/driver.rs 05_drivers_gpio_uart/src/bsp/raspberrypi/driver.rs --- 04_safe_globals/src/bsp/raspberrypi/driver.rs +++ 05_drivers_gpio_uart/src/bsp/raspberrypi/driver.rs -@@ -0,0 +1,49 @@ +@@ -0,0 +1,55 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2018-2022 Andre Richter + +//! BSP driver support. + -+use crate::driver; ++use super::memory::map::mmio; ++use crate::{bsp::device_driver, driver}; + +//-------------------------------------------------------------------------------------------------- +// Private Definitions @@ -1105,8 +1094,13 @@ diff -uNr 04_safe_globals/src/bsp/raspberrypi/driver.rs 05_drivers_gpio_uart/src +// Global instances +//-------------------------------------------------------------------------------------------------- + ++pub(super) static PL011_UART: device_driver::PL011Uart = ++ unsafe { device_driver::PL011Uart::new(mmio::PL011_UART_START) }; ++ ++static GPIO: device_driver::GPIO = unsafe { device_driver::GPIO::new(mmio::GPIO_START) }; ++ +static BSP_DRIVER_MANAGER: BSPDriverManager = BSPDriverManager { -+ device_drivers: [&super::GPIO, &super::PL011_UART], ++ device_drivers: [&PL011_UART, &GPIO], +}; + +//-------------------------------------------------------------------------------------------------- @@ -1130,7 +1124,7 @@ diff -uNr 04_safe_globals/src/bsp/raspberrypi/driver.rs 05_drivers_gpio_uart/src + + fn post_device_driver_init(&self) { + // Configure PL011Uart's output pins. -+ super::GPIO.map_pl011_uart(); ++ GPIO.map_pl011_uart(); + } +} @@ -1179,7 +1173,7 @@ diff -uNr 04_safe_globals/src/bsp/raspberrypi/memory.rs 05_drivers_gpio_uart/src diff -uNr 04_safe_globals/src/bsp/raspberrypi.rs 05_drivers_gpio_uart/src/bsp/raspberrypi.rs --- 04_safe_globals/src/bsp/raspberrypi.rs +++ 05_drivers_gpio_uart/src/bsp/raspberrypi.rs -@@ -6,3 +6,33 @@ +@@ -6,3 +6,22 @@ pub mod console; pub mod cpu; @@ -1187,17 +1181,6 @@ diff -uNr 04_safe_globals/src/bsp/raspberrypi.rs 05_drivers_gpio_uart/src/bsp/ra +pub mod memory; + +//-------------------------------------------------------------------------------------------------- -+// Global instances -+//-------------------------------------------------------------------------------------------------- -+use super::device_driver; -+ -+static GPIO: device_driver::GPIO = -+ unsafe { device_driver::GPIO::new(memory::map::mmio::GPIO_START) }; -+ -+static PL011_UART: device_driver::PL011Uart = -+ unsafe { device_driver::PL011Uart::new(memory::map::mmio::PL011_UART_START) }; -+ -+//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + @@ -1230,7 +1213,7 @@ diff -uNr 04_safe_globals/src/bsp.rs 05_drivers_gpio_uart/src/bsp.rs diff -uNr 04_safe_globals/src/console.rs 05_drivers_gpio_uart/src/console.rs --- 04_safe_globals/src/console.rs +++ 05_drivers_gpio_uart/src/console.rs -@@ -14,8 +14,25 @@ +@@ -16,8 +16,25 @@ /// Console write functions. pub trait Write { @@ -1256,7 +1239,7 @@ diff -uNr 04_safe_globals/src/console.rs 05_drivers_gpio_uart/src/console.rs } /// Console statistics. -@@ -24,8 +41,13 @@ +@@ -26,10 +43,15 @@ fn chars_written(&self) -> usize { 0 } @@ -1268,10 +1251,12 @@ diff -uNr 04_safe_globals/src/console.rs 05_drivers_gpio_uart/src/console.rs } /// Trait alias for a full-fledged console. -- pub trait All = Write + Statistics; -+ pub trait All = Write + Read + Statistics; +- pub trait All: Write + Statistics {} ++ pub trait All: Write + Read + Statistics {} } + //-------------------------------------------------------------------------------------------------- + diff -uNr 04_safe_globals/src/cpu.rs 05_drivers_gpio_uart/src/cpu.rs --- 04_safe_globals/src/cpu.rs +++ 05_drivers_gpio_uart/src/cpu.rs @@ -1353,16 +1338,15 @@ diff -uNr 04_safe_globals/src/main.rs 05_drivers_gpio_uart/src/main.rs mod panic_wait; mod print; mod synchronization; -@@ -125,16 +127,54 @@ +@@ -125,13 +127,50 @@ /// # Safety /// /// - Only a single core must be active and running this function. +/// - The init calls in this function must appear in the correct order. unsafe fn kernel_init() -> ! { -- use console::interface::Statistics; +- use console::console; + use driver::interface::DriverManager; - -- println!("[0] Hello from Rust!"); ++ + for i in bsp::driver::driver_manager().all_device_drivers().iter() { + if let Err(x) = i.init() { + panic!("Error loading driver: {}: {}", i.compatible(), x); @@ -1370,17 +1354,20 @@ diff -uNr 04_safe_globals/src/main.rs 05_drivers_gpio_uart/src/main.rs + } + bsp::driver::driver_manager().post_device_driver_init(); + // println! is usable from here on. -+ + +- println!("[0] Hello from Rust!"); + // Transition from unsafe to safe. + kernel_main() +} -+ + +- println!("[1] Chars written: {}", console().chars_written()); +/// The main function running after the early init. +fn kernel_main() -> ! { -+ use bsp::console::console; -+ use console::interface::All; ++ use console::console; + use driver::interface::DriverManager; -+ + +- println!("[2] Stopping here."); +- cpu::wait_forever() + println!( + "[0] {} version {}", + env!("CARGO_PKG_NAME"), @@ -1396,69 +1383,18 @@ diff -uNr 04_safe_globals/src/main.rs 05_drivers_gpio_uart/src/main.rs + { + println!(" {}. {}", i + 1, driver.compatible()); + } - - println!( -- "[1] Chars written: {}", -+ "[3] Chars written: {}", - bsp::console::console().chars_written() - ); ++ ++ println!("[3] Chars written: {}", console().chars_written()); + println!("[4] Echoing input now"); - -- println!("[2] Stopping here."); -- cpu::wait_forever() ++ + // Discard any spurious received characters before going into echo mode. + console().clear_rx(); + loop { -+ let c = bsp::console::console().read_char(); -+ bsp::console::console().write_char(c); ++ let c = console().read_char(); ++ console().write_char(c); + } } -diff -uNr 04_safe_globals/src/panic_wait.rs 05_drivers_gpio_uart/src/panic_wait.rs ---- 04_safe_globals/src/panic_wait.rs -+++ 05_drivers_gpio_uart/src/panic_wait.rs -@@ -4,13 +4,29 @@ - - //! A panic handler that infinitely waits. - --use crate::{cpu, println}; --use core::panic::PanicInfo; -+use crate::{bsp, cpu}; -+use core::{fmt, panic::PanicInfo}; - - //-------------------------------------------------------------------------------------------------- - // Private Code - //-------------------------------------------------------------------------------------------------- - -+fn _panic_print(args: fmt::Arguments) { -+ use fmt::Write; -+ -+ unsafe { bsp::console::panic_console_out().write_fmt(args).unwrap() }; -+} -+ -+/// Prints with a newline - only use from the panic handler. -+/// -+/// Carbon copy from -+#[macro_export] -+macro_rules! panic_println { -+ ($($arg:tt)*) => ({ -+ _panic_print(format_args_nl!($($arg)*)); -+ }) -+} -+ - /// Stop immediately if called a second time. - /// - /// # Note -@@ -50,7 +66,7 @@ - _ => ("???", 0, 0), - }; - -- println!( -+ panic_println!( - "Kernel panic!\n\n\ - Panic location:\n File '{}', line {}, column {}\n\n\ - {}", - diff -uNr 04_safe_globals/tests/boot_test_string.rb 05_drivers_gpio_uart/tests/boot_test_string.rb --- 04_safe_globals/tests/boot_test_string.rb +++ 05_drivers_gpio_uart/tests/boot_test_string.rb diff --git a/05_drivers_gpio_uart/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs b/05_drivers_gpio_uart/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs index 76ce3bd1..0601d58e 100644 --- a/05_drivers_gpio_uart/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs +++ b/05_drivers_gpio_uart/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs @@ -108,16 +108,13 @@ register_structs! { /// Abstraction for the associated MMIO registers. type Registers = MMIODerefWrapper; -//-------------------------------------------------------------------------------------------------- -// Public Definitions -//-------------------------------------------------------------------------------------------------- - -pub struct GPIOInner { +struct GPIOInner { registers: Registers, } -// Export the inner struct so that BSPs can use it for the panic handler. -pub use GPIOInner as PanicGPIO; +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- /// Representation of the GPIO HW. pub struct GPIO { @@ -125,7 +122,7 @@ pub struct GPIO { } //-------------------------------------------------------------------------------------------------- -// Public Code +// Private Code //-------------------------------------------------------------------------------------------------- impl GPIOInner { @@ -148,7 +145,7 @@ impl GPIOInner { // Make an educated guess for a good delay value (Sequence described in the BCM2837 // peripherals PDF). // - // - According to Wikipedia, the fastest Pi3 clocks around 1.4 GHz. + // - According to Wikipedia, the fastest RPi4 clocks around 1.5 GHz. // - The Linux 2837 GPIO driver waits 1 µs between the steps. // // So lets try to be on the safe side and default to 2000 cycles, which would equal 1 µs @@ -195,7 +192,13 @@ impl GPIOInner { } } +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + impl GPIO { + pub const COMPATIBLE: &'static str = "BCM GPIO"; + /// Create an instance. /// /// # Safety @@ -220,6 +223,6 @@ use synchronization::interface::Mutex; impl driver::interface::DeviceDriver for GPIO { fn compatible(&self) -> &'static str { - "BCM GPIO" + Self::COMPATIBLE } } diff --git a/05_drivers_gpio_uart/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs b/05_drivers_gpio_uart/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs index 85cd3154..b034e92e 100644 --- a/05_drivers_gpio_uart/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs +++ b/05_drivers_gpio_uart/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs @@ -167,18 +167,15 @@ enum BlockingMode { NonBlocking, } -//-------------------------------------------------------------------------------------------------- -// Public Definitions -//-------------------------------------------------------------------------------------------------- - -pub struct PL011UartInner { +struct PL011UartInner { registers: Registers, chars_written: usize, chars_read: usize, } -// Export the inner struct so that BSPs can use it for the panic handler. -pub use PL011UartInner as PanicUart; +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- /// Representation of the UART. pub struct PL011Uart { @@ -186,7 +183,7 @@ pub struct PL011Uart { } //-------------------------------------------------------------------------------------------------- -// Public Code +// Private Code //-------------------------------------------------------------------------------------------------- impl PL011UartInner { @@ -326,7 +323,13 @@ impl fmt::Write for PL011UartInner { } } +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + impl PL011Uart { + pub const COMPATIBLE: &'static str = "BCM PL011 UART"; + /// Create an instance. /// /// # Safety @@ -346,7 +349,7 @@ use synchronization::interface::Mutex; impl driver::interface::DeviceDriver for PL011Uart { fn compatible(&self) -> &'static str { - "BCM PL011 UART" + Self::COMPATIBLE } unsafe fn init(&self) -> Result<(), &'static str> { @@ -400,3 +403,5 @@ impl console::interface::Statistics for PL011Uart { self.inner.lock(|inner| inner.chars_read) } } + +impl console::interface::All for PL011Uart {} diff --git a/05_drivers_gpio_uart/src/bsp/raspberrypi.rs b/05_drivers_gpio_uart/src/bsp/raspberrypi.rs index 22edb4fa..a9a7261a 100644 --- a/05_drivers_gpio_uart/src/bsp/raspberrypi.rs +++ b/05_drivers_gpio_uart/src/bsp/raspberrypi.rs @@ -9,17 +9,6 @@ pub mod cpu; pub mod driver; pub mod memory; -//-------------------------------------------------------------------------------------------------- -// Global instances -//-------------------------------------------------------------------------------------------------- -use super::device_driver; - -static GPIO: device_driver::GPIO = - unsafe { device_driver::GPIO::new(memory::map::mmio::GPIO_START) }; - -static PL011_UART: device_driver::PL011Uart = - unsafe { device_driver::PL011Uart::new(memory::map::mmio::PL011_UART_START) }; - //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- diff --git a/05_drivers_gpio_uart/src/bsp/raspberrypi/console.rs b/05_drivers_gpio_uart/src/bsp/raspberrypi/console.rs index a247032f..0a630eef 100644 --- a/05_drivers_gpio_uart/src/bsp/raspberrypi/console.rs +++ b/05_drivers_gpio_uart/src/bsp/raspberrypi/console.rs @@ -4,34 +4,13 @@ //! BSP console facilities. -use super::memory; -use crate::{bsp::device_driver, console}; -use core::fmt; +use crate::console; //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- -/// In case of a panic, the panic handler uses this function to take a last shot at printing -/// something before the system is halted. -/// -/// We try to init panic-versions of the GPIO and the UART. The panic versions are not protected -/// with synchronization primitives, which increases chances that we get to print something, even -/// when the kernel's default GPIO or UART instances happen to be locked at the time of the panic. -/// -/// # Safety -/// -/// - Use only for printing during a panic. -pub unsafe fn panic_console_out() -> impl fmt::Write { - let mut panic_gpio = device_driver::PanicGPIO::new(memory::map::mmio::GPIO_START); - let mut panic_uart = device_driver::PanicUart::new(memory::map::mmio::PL011_UART_START); - - panic_gpio.map_pl011_uart(); - panic_uart.init(); - panic_uart -} - /// Return a reference to the console. -pub fn console() -> &'static impl console::interface::All { - &super::PL011_UART +pub fn console() -> &'static dyn console::interface::All { + &super::driver::PL011_UART } diff --git a/05_drivers_gpio_uart/src/bsp/raspberrypi/driver.rs b/05_drivers_gpio_uart/src/bsp/raspberrypi/driver.rs index b5538baa..8b683ed8 100644 --- a/05_drivers_gpio_uart/src/bsp/raspberrypi/driver.rs +++ b/05_drivers_gpio_uart/src/bsp/raspberrypi/driver.rs @@ -4,7 +4,8 @@ //! BSP driver support. -use crate::driver; +use super::memory::map::mmio; +use crate::{bsp::device_driver, driver}; //-------------------------------------------------------------------------------------------------- // Private Definitions @@ -19,8 +20,13 @@ struct BSPDriverManager { // Global instances //-------------------------------------------------------------------------------------------------- +pub(super) static PL011_UART: device_driver::PL011Uart = + unsafe { device_driver::PL011Uart::new(mmio::PL011_UART_START) }; + +static GPIO: device_driver::GPIO = unsafe { device_driver::GPIO::new(mmio::GPIO_START) }; + static BSP_DRIVER_MANAGER: BSPDriverManager = BSPDriverManager { - device_drivers: [&super::GPIO, &super::PL011_UART], + device_drivers: [&PL011_UART, &GPIO], }; //-------------------------------------------------------------------------------------------------- @@ -44,6 +50,6 @@ impl driver::interface::DriverManager for BSPDriverManager { fn post_device_driver_init(&self) { // Configure PL011Uart's output pins. - super::GPIO.map_pl011_uart(); + GPIO.map_pl011_uart(); } } diff --git a/05_drivers_gpio_uart/src/console.rs b/05_drivers_gpio_uart/src/console.rs index e49e241f..c1fb0e53 100644 --- a/05_drivers_gpio_uart/src/console.rs +++ b/05_drivers_gpio_uart/src/console.rs @@ -4,6 +4,8 @@ //! System console. +use crate::bsp; + //-------------------------------------------------------------------------------------------------- // Public Definitions //-------------------------------------------------------------------------------------------------- @@ -49,5 +51,16 @@ pub mod interface { } /// Trait alias for a full-fledged console. - pub trait All = Write + Read + Statistics; + pub trait All: Write + Read + Statistics {} +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +/// Return a reference to the console. +/// +/// This is the global console used by all printing macros. +pub fn console() -> &'static dyn interface::All { + bsp::console::console() } diff --git a/05_drivers_gpio_uart/src/main.rs b/05_drivers_gpio_uart/src/main.rs index 2e8bfeaa..c9b73382 100644 --- a/05_drivers_gpio_uart/src/main.rs +++ b/05_drivers_gpio_uart/src/main.rs @@ -145,8 +145,7 @@ unsafe fn kernel_init() -> ! { /// The main function running after the early init. fn kernel_main() -> ! { - use bsp::console::console; - use console::interface::All; + use console::console; use driver::interface::DriverManager; println!( @@ -165,16 +164,13 @@ fn kernel_main() -> ! { println!(" {}. {}", i + 1, driver.compatible()); } - println!( - "[3] Chars written: {}", - bsp::console::console().chars_written() - ); + println!("[3] Chars written: {}", console().chars_written()); println!("[4] Echoing input now"); // Discard any spurious received characters before going into echo mode. console().clear_rx(); loop { - let c = bsp::console::console().read_char(); - bsp::console::console().write_char(c); + let c = console().read_char(); + console().write_char(c); } } diff --git a/05_drivers_gpio_uart/src/panic_wait.rs b/05_drivers_gpio_uart/src/panic_wait.rs index e546b06d..fb30e8d4 100644 --- a/05_drivers_gpio_uart/src/panic_wait.rs +++ b/05_drivers_gpio_uart/src/panic_wait.rs @@ -4,29 +4,13 @@ //! A panic handler that infinitely waits. -use crate::{bsp, cpu}; -use core::{fmt, panic::PanicInfo}; +use crate::{cpu, println}; +use core::panic::PanicInfo; //-------------------------------------------------------------------------------------------------- // Private Code //-------------------------------------------------------------------------------------------------- -fn _panic_print(args: fmt::Arguments) { - use fmt::Write; - - unsafe { bsp::console::panic_console_out().write_fmt(args).unwrap() }; -} - -/// Prints with a newline - only use from the panic handler. -/// -/// Carbon copy from -#[macro_export] -macro_rules! panic_println { - ($($arg:tt)*) => ({ - _panic_print(format_args_nl!($($arg)*)); - }) -} - /// Stop immediately if called a second time. /// /// # Note @@ -66,7 +50,7 @@ fn panic(info: &PanicInfo) -> ! { _ => ("???", 0, 0), }; - panic_println!( + println!( "Kernel panic!\n\n\ Panic location:\n File '{}', line {}, column {}\n\n\ {}", diff --git a/05_drivers_gpio_uart/src/print.rs b/05_drivers_gpio_uart/src/print.rs index 81c6d179..f69bad44 100644 --- a/05_drivers_gpio_uart/src/print.rs +++ b/05_drivers_gpio_uart/src/print.rs @@ -4,7 +4,7 @@ //! Printing. -use crate::{bsp, console}; +use crate::console; use core::fmt; //-------------------------------------------------------------------------------------------------- @@ -13,9 +13,7 @@ use core::fmt; #[doc(hidden)] pub fn _print(args: fmt::Arguments) { - use console::interface::Write; - - bsp::console::console().write_fmt(args).unwrap(); + console::console().write_fmt(args).unwrap(); } /// Prints without a newline. diff --git a/06_uart_chainloader/README.md b/06_uart_chainloader/README.md index 20c120d4..38f9cc05 100644 --- a/06_uart_chainloader/README.md +++ b/06_uart_chainloader/README.md @@ -66,6 +66,7 @@ Minipush 1.0 [MP] ⏳ Waiting for /dev/ttyUSB0 [MP] ✅ Serial connected [MP] 🔌 Please power the target now + __ __ _ _ _ _ | \/ (_)_ _ (_) | ___ __ _ __| | | |\/| | | ' \| | |__/ _ \/ _` / _` | @@ -74,14 +75,14 @@ Minipush 1.0 Raspberry Pi 3 [ML] Requesting binary -[MP] ⏩ Pushing 6 KiB ==========================================🦀 100% 0 KiB/s Time: 00:00:00 +[MP] ⏩ Pushing 7 KiB ==========================================🦀 100% 0 KiB/s Time: 00:00:00 [ML] Loaded! Executing the payload now [0] mingo version 0.5.0 [1] Booting on: Raspberry Pi 3 [2] Drivers loaded: - 1. BCM GPIO - 2. BCM PL011 UART + 1. BCM PL011 UART + 2. BCM GPIO [3] Chars written: 117 [4] Echoing input now ``` @@ -324,23 +325,10 @@ diff -uNr 05_drivers_gpio_uart/src/_arch/aarch64/cpu/boot.s 06_uart_chainloader/ // Infinitely wait for events (aka "park the core"). .L_parking_loop: -diff -uNr 05_drivers_gpio_uart/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs 06_uart_chainloader/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs ---- 05_drivers_gpio_uart/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs -+++ 06_uart_chainloader/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs -@@ -148,7 +148,7 @@ - // Make an educated guess for a good delay value (Sequence described in the BCM2837 - // peripherals PDF). - // -- // - According to Wikipedia, the fastest Pi3 clocks around 1.4 GHz. -+ // - According to Wikipedia, the fastest RPi4 clocks around 1.5 GHz. - // - The Linux 2837 GPIO driver waits 1 µs between the steps. - // - // So lets try to be on the safe side and default to 2000 cycles, which would equal 1 µs - diff -uNr 05_drivers_gpio_uart/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs 06_uart_chainloader/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs --- 05_drivers_gpio_uart/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs +++ 06_uart_chainloader/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs -@@ -278,7 +278,7 @@ +@@ -275,7 +275,7 @@ } /// Retrieve a character. @@ -349,7 +337,7 @@ diff -uNr 05_drivers_gpio_uart/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs 0 // If RX FIFO is empty, if self.registers.FR.matches_all(FR::RXFE::SET) { // immediately return in non-blocking mode. -@@ -293,12 +293,7 @@ +@@ -290,12 +290,7 @@ } // Read one character. @@ -363,7 +351,7 @@ diff -uNr 05_drivers_gpio_uart/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs 0 // Update statistics. self.chars_read += 1; -@@ -378,14 +373,14 @@ +@@ -381,14 +376,14 @@ impl console::interface::Read for PL011Uart { fn read_char(&self) -> char { self.inner @@ -426,19 +414,14 @@ diff -uNr 05_drivers_gpio_uart/src/bsp/raspberrypi/kernel.ld 06_uart_chainloader diff -uNr 05_drivers_gpio_uart/src/bsp/raspberrypi/memory.rs 06_uart_chainloader/src/bsp/raspberrypi/memory.rs --- 05_drivers_gpio_uart/src/bsp/raspberrypi/memory.rs +++ 06_uart_chainloader/src/bsp/raspberrypi/memory.rs -@@ -11,9 +11,10 @@ +@@ -11,6 +11,7 @@ /// The board's physical memory map. #[rustfmt::skip] pub(super) mod map { + pub const BOARD_DEFAULT_LOAD_ADDRESS: usize = 0x8_0000; -- pub const GPIO_OFFSET: usize = 0x0020_0000; -- pub const UART_OFFSET: usize = 0x0020_1000; -+ pub const GPIO_OFFSET: usize = 0x0020_0000; -+ pub const UART_OFFSET: usize = 0x0020_1000; - - /// Physical devices. - #[cfg(feature = "bsp_rpi3")] + pub const GPIO_OFFSET: usize = 0x0020_0000; + pub const UART_OFFSET: usize = 0x0020_1000; @@ -35,3 +36,13 @@ pub const PL011_UART_START: usize = START + UART_OFFSET; } @@ -457,7 +440,7 @@ diff -uNr 05_drivers_gpio_uart/src/bsp/raspberrypi/memory.rs 06_uart_chainloader diff -uNr 05_drivers_gpio_uart/src/main.rs 06_uart_chainloader/src/main.rs --- 05_drivers_gpio_uart/src/main.rs +++ 06_uart_chainloader/src/main.rs -@@ -143,38 +143,56 @@ +@@ -143,34 +143,55 @@ kernel_main() } @@ -470,8 +453,7 @@ diff -uNr 05_drivers_gpio_uart/src/main.rs 06_uart_chainloader/src/main.rs + /// The main function running after the early init. fn kernel_main() -> ! { - use bsp::console::console; - use console::interface::All; + use console::console; - use driver::interface::DriverManager; - println!( @@ -502,10 +484,7 @@ diff -uNr 05_drivers_gpio_uart/src/main.rs 06_uart_chainloader/src/main.rs + console().write_char(3 as char); } -- println!( -- "[3] Chars written: {}", -- bsp::console::console().chars_written() -- ); +- println!("[3] Chars written: {}", console().chars_written()); - println!("[4] Echoing input now"); + // Read the binary's size. + let mut size: u32 = u32::from(console().read_char() as u8); @@ -516,8 +495,8 @@ diff -uNr 05_drivers_gpio_uart/src/main.rs 06_uart_chainloader/src/main.rs - // Discard any spurious received characters before going into echo mode. - console().clear_rx(); - loop { -- let c = bsp::console::console().read_char(); -- bsp::console::console().write_char(c); +- let c = console().read_char(); +- console().write_char(c); + // Trust it's not too big. + console().write_char('O'); + console().write_char('K'); diff --git a/06_uart_chainloader/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs b/06_uart_chainloader/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs index 5c68107a..0601d58e 100644 --- a/06_uart_chainloader/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs +++ b/06_uart_chainloader/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs @@ -108,16 +108,13 @@ register_structs! { /// Abstraction for the associated MMIO registers. type Registers = MMIODerefWrapper; -//-------------------------------------------------------------------------------------------------- -// Public Definitions -//-------------------------------------------------------------------------------------------------- - -pub struct GPIOInner { +struct GPIOInner { registers: Registers, } -// Export the inner struct so that BSPs can use it for the panic handler. -pub use GPIOInner as PanicGPIO; +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- /// Representation of the GPIO HW. pub struct GPIO { @@ -125,7 +122,7 @@ pub struct GPIO { } //-------------------------------------------------------------------------------------------------- -// Public Code +// Private Code //-------------------------------------------------------------------------------------------------- impl GPIOInner { @@ -195,7 +192,13 @@ impl GPIOInner { } } +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + impl GPIO { + pub const COMPATIBLE: &'static str = "BCM GPIO"; + /// Create an instance. /// /// # Safety @@ -220,6 +223,6 @@ use synchronization::interface::Mutex; impl driver::interface::DeviceDriver for GPIO { fn compatible(&self) -> &'static str { - "BCM GPIO" + Self::COMPATIBLE } } diff --git a/06_uart_chainloader/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs b/06_uart_chainloader/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs index 7d66484b..df56d7c4 100644 --- a/06_uart_chainloader/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs +++ b/06_uart_chainloader/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs @@ -167,18 +167,15 @@ enum BlockingMode { NonBlocking, } -//-------------------------------------------------------------------------------------------------- -// Public Definitions -//-------------------------------------------------------------------------------------------------- - -pub struct PL011UartInner { +struct PL011UartInner { registers: Registers, chars_written: usize, chars_read: usize, } -// Export the inner struct so that BSPs can use it for the panic handler. -pub use PL011UartInner as PanicUart; +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- /// Representation of the UART. pub struct PL011Uart { @@ -186,7 +183,7 @@ pub struct PL011Uart { } //-------------------------------------------------------------------------------------------------- -// Public Code +// Private Code //-------------------------------------------------------------------------------------------------- impl PL011UartInner { @@ -321,7 +318,13 @@ impl fmt::Write for PL011UartInner { } } +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + impl PL011Uart { + pub const COMPATIBLE: &'static str = "BCM PL011 UART"; + /// Create an instance. /// /// # Safety @@ -341,7 +344,7 @@ use synchronization::interface::Mutex; impl driver::interface::DeviceDriver for PL011Uart { fn compatible(&self) -> &'static str { - "BCM PL011 UART" + Self::COMPATIBLE } unsafe fn init(&self) -> Result<(), &'static str> { @@ -395,3 +398,5 @@ impl console::interface::Statistics for PL011Uart { self.inner.lock(|inner| inner.chars_read) } } + +impl console::interface::All for PL011Uart {} diff --git a/06_uart_chainloader/src/bsp/raspberrypi.rs b/06_uart_chainloader/src/bsp/raspberrypi.rs index 22edb4fa..a9a7261a 100644 --- a/06_uart_chainloader/src/bsp/raspberrypi.rs +++ b/06_uart_chainloader/src/bsp/raspberrypi.rs @@ -9,17 +9,6 @@ pub mod cpu; pub mod driver; pub mod memory; -//-------------------------------------------------------------------------------------------------- -// Global instances -//-------------------------------------------------------------------------------------------------- -use super::device_driver; - -static GPIO: device_driver::GPIO = - unsafe { device_driver::GPIO::new(memory::map::mmio::GPIO_START) }; - -static PL011_UART: device_driver::PL011Uart = - unsafe { device_driver::PL011Uart::new(memory::map::mmio::PL011_UART_START) }; - //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- diff --git a/06_uart_chainloader/src/bsp/raspberrypi/console.rs b/06_uart_chainloader/src/bsp/raspberrypi/console.rs index a247032f..0a630eef 100644 --- a/06_uart_chainloader/src/bsp/raspberrypi/console.rs +++ b/06_uart_chainloader/src/bsp/raspberrypi/console.rs @@ -4,34 +4,13 @@ //! BSP console facilities. -use super::memory; -use crate::{bsp::device_driver, console}; -use core::fmt; +use crate::console; //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- -/// In case of a panic, the panic handler uses this function to take a last shot at printing -/// something before the system is halted. -/// -/// We try to init panic-versions of the GPIO and the UART. The panic versions are not protected -/// with synchronization primitives, which increases chances that we get to print something, even -/// when the kernel's default GPIO or UART instances happen to be locked at the time of the panic. -/// -/// # Safety -/// -/// - Use only for printing during a panic. -pub unsafe fn panic_console_out() -> impl fmt::Write { - let mut panic_gpio = device_driver::PanicGPIO::new(memory::map::mmio::GPIO_START); - let mut panic_uart = device_driver::PanicUart::new(memory::map::mmio::PL011_UART_START); - - panic_gpio.map_pl011_uart(); - panic_uart.init(); - panic_uart -} - /// Return a reference to the console. -pub fn console() -> &'static impl console::interface::All { - &super::PL011_UART +pub fn console() -> &'static dyn console::interface::All { + &super::driver::PL011_UART } diff --git a/06_uart_chainloader/src/bsp/raspberrypi/driver.rs b/06_uart_chainloader/src/bsp/raspberrypi/driver.rs index b5538baa..8b683ed8 100644 --- a/06_uart_chainloader/src/bsp/raspberrypi/driver.rs +++ b/06_uart_chainloader/src/bsp/raspberrypi/driver.rs @@ -4,7 +4,8 @@ //! BSP driver support. -use crate::driver; +use super::memory::map::mmio; +use crate::{bsp::device_driver, driver}; //-------------------------------------------------------------------------------------------------- // Private Definitions @@ -19,8 +20,13 @@ struct BSPDriverManager { // Global instances //-------------------------------------------------------------------------------------------------- +pub(super) static PL011_UART: device_driver::PL011Uart = + unsafe { device_driver::PL011Uart::new(mmio::PL011_UART_START) }; + +static GPIO: device_driver::GPIO = unsafe { device_driver::GPIO::new(mmio::GPIO_START) }; + static BSP_DRIVER_MANAGER: BSPDriverManager = BSPDriverManager { - device_drivers: [&super::GPIO, &super::PL011_UART], + device_drivers: [&PL011_UART, &GPIO], }; //-------------------------------------------------------------------------------------------------- @@ -44,6 +50,6 @@ impl driver::interface::DriverManager for BSPDriverManager { fn post_device_driver_init(&self) { // Configure PL011Uart's output pins. - super::GPIO.map_pl011_uart(); + GPIO.map_pl011_uart(); } } diff --git a/06_uart_chainloader/src/bsp/raspberrypi/memory.rs b/06_uart_chainloader/src/bsp/raspberrypi/memory.rs index 0959bdce..6ef46c35 100644 --- a/06_uart_chainloader/src/bsp/raspberrypi/memory.rs +++ b/06_uart_chainloader/src/bsp/raspberrypi/memory.rs @@ -13,8 +13,8 @@ pub(super) mod map { pub const BOARD_DEFAULT_LOAD_ADDRESS: usize = 0x8_0000; - pub const GPIO_OFFSET: usize = 0x0020_0000; - pub const UART_OFFSET: usize = 0x0020_1000; + pub const GPIO_OFFSET: usize = 0x0020_0000; + pub const UART_OFFSET: usize = 0x0020_1000; /// Physical devices. #[cfg(feature = "bsp_rpi3")] diff --git a/06_uart_chainloader/src/console.rs b/06_uart_chainloader/src/console.rs index e49e241f..c1fb0e53 100644 --- a/06_uart_chainloader/src/console.rs +++ b/06_uart_chainloader/src/console.rs @@ -4,6 +4,8 @@ //! System console. +use crate::bsp; + //-------------------------------------------------------------------------------------------------- // Public Definitions //-------------------------------------------------------------------------------------------------- @@ -49,5 +51,16 @@ pub mod interface { } /// Trait alias for a full-fledged console. - pub trait All = Write + Read + Statistics; + pub trait All: Write + Read + Statistics {} +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +/// Return a reference to the console. +/// +/// This is the global console used by all printing macros. +pub fn console() -> &'static dyn interface::All { + bsp::console::console() } diff --git a/06_uart_chainloader/src/main.rs b/06_uart_chainloader/src/main.rs index b8e6fea4..08bd9ad9 100644 --- a/06_uart_chainloader/src/main.rs +++ b/06_uart_chainloader/src/main.rs @@ -152,8 +152,7 @@ const MINILOAD_LOGO: &str = r#" /// The main function running after the early init. fn kernel_main() -> ! { - use bsp::console::console; - use console::interface::All; + use console::console; println!("{}", MINILOAD_LOGO); println!("{:^37}", bsp::board_name()); diff --git a/06_uart_chainloader/src/panic_wait.rs b/06_uart_chainloader/src/panic_wait.rs index e546b06d..fb30e8d4 100644 --- a/06_uart_chainloader/src/panic_wait.rs +++ b/06_uart_chainloader/src/panic_wait.rs @@ -4,29 +4,13 @@ //! A panic handler that infinitely waits. -use crate::{bsp, cpu}; -use core::{fmt, panic::PanicInfo}; +use crate::{cpu, println}; +use core::panic::PanicInfo; //-------------------------------------------------------------------------------------------------- // Private Code //-------------------------------------------------------------------------------------------------- -fn _panic_print(args: fmt::Arguments) { - use fmt::Write; - - unsafe { bsp::console::panic_console_out().write_fmt(args).unwrap() }; -} - -/// Prints with a newline - only use from the panic handler. -/// -/// Carbon copy from -#[macro_export] -macro_rules! panic_println { - ($($arg:tt)*) => ({ - _panic_print(format_args_nl!($($arg)*)); - }) -} - /// Stop immediately if called a second time. /// /// # Note @@ -66,7 +50,7 @@ fn panic(info: &PanicInfo) -> ! { _ => ("???", 0, 0), }; - panic_println!( + println!( "Kernel panic!\n\n\ Panic location:\n File '{}', line {}, column {}\n\n\ {}", diff --git a/06_uart_chainloader/src/print.rs b/06_uart_chainloader/src/print.rs index 81c6d179..f69bad44 100644 --- a/06_uart_chainloader/src/print.rs +++ b/06_uart_chainloader/src/print.rs @@ -4,7 +4,7 @@ //! Printing. -use crate::{bsp, console}; +use crate::console; use core::fmt; //-------------------------------------------------------------------------------------------------- @@ -13,9 +13,7 @@ use core::fmt; #[doc(hidden)] pub fn _print(args: fmt::Arguments) { - use console::interface::Write; - - bsp::console::console().write_fmt(args).unwrap(); + console::console().write_fmt(args).unwrap(); } /// Prints without a newline. diff --git a/07_timestamps/README.md b/07_timestamps/README.md index 6b8dcbeb..2f4ab323 100644 --- a/07_timestamps/README.md +++ b/07_timestamps/README.md @@ -19,6 +19,7 @@ Minipush 1.0 [MP] ⏳ Waiting for /dev/ttyUSB0 [MP] ✅ Serial connected [MP] 🔌 Please power the target now + __ __ _ _ _ _ | \/ (_)_ _ (_) | ___ __ _ __| | | |\/| | | ' \| | |__/ _ \/ _` / _` | @@ -30,16 +31,16 @@ Minipush 1.0 [MP] ⏩ Pushing 12 KiB =========================================🦀 100% 0 KiB/s Time: 00:00:00 [ML] Loaded! Executing the payload now -[ 0.140431] mingo version 0.7.0 -[ 0.140630] Booting on: Raspberry Pi 3 -[ 0.141085] Architectural timer resolution: 52 ns -[ 0.141660] Drivers loaded: -[ 0.141995] 1. BCM GPIO -[ 0.142353] 2. BCM PL011 UART -[W 0.142777] Spin duration smaller than architecturally supported, skipping -[ 0.143621] Spinning for 1 second -[ 1.144023] Spinning for 1 second -[ 2.144245] Spinning for 1 second +[ 0.143123] mingo version 0.7.0 +[ 0.143323] Booting on: Raspberry Pi 3 +[ 0.143778] Architectural timer resolution: 52 ns +[ 0.144352] Drivers loaded: +[ 0.144688] 1. BCM PL011 UART +[ 0.145110] 2. BCM GPIO +[W 0.145469] Spin duration smaller than architecturally supported, skipping +[ 0.146313] Spinning for 1 second +[ 1.146715] Spinning for 1 second +[ 2.146938] Spinning for 1 second ``` ## Diff to previous @@ -374,7 +375,7 @@ diff -uNr 06_uart_chainloader/src/_arch/aarch64/time.rs 07_timestamps/src/_arch/ diff -uNr 06_uart_chainloader/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs 07_timestamps/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs --- 06_uart_chainloader/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs +++ 07_timestamps/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs -@@ -143,25 +143,19 @@ +@@ -140,25 +140,19 @@ /// Disable pull-up/down on pins 14 and 15. #[cfg(feature = "bsp_rpi3")] fn disable_pud_14_15_bcm2837(&mut self) { @@ -410,7 +411,7 @@ diff -uNr 06_uart_chainloader/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs 07_times diff -uNr 06_uart_chainloader/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs 07_timestamps/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs --- 06_uart_chainloader/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs +++ 07_timestamps/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs -@@ -278,7 +278,7 @@ +@@ -275,7 +275,7 @@ } /// Retrieve a character. @@ -419,7 +420,7 @@ diff -uNr 06_uart_chainloader/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs 07 // If RX FIFO is empty, if self.registers.FR.matches_all(FR::RXFE::SET) { // immediately return in non-blocking mode. -@@ -293,7 +293,12 @@ +@@ -290,7 +290,12 @@ } // Read one character. @@ -433,7 +434,7 @@ diff -uNr 06_uart_chainloader/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs 07 // Update statistics. self.chars_read += 1; -@@ -373,14 +378,14 @@ +@@ -376,14 +381,14 @@ impl console::interface::Read for PL011Uart { fn read_char(&self) -> char { self.inner @@ -496,19 +497,14 @@ diff -uNr 06_uart_chainloader/src/bsp/raspberrypi/kernel.ld 07_timestamps/src/bs diff -uNr 06_uart_chainloader/src/bsp/raspberrypi/memory.rs 07_timestamps/src/bsp/raspberrypi/memory.rs --- 06_uart_chainloader/src/bsp/raspberrypi/memory.rs +++ 07_timestamps/src/bsp/raspberrypi/memory.rs -@@ -11,10 +11,9 @@ +@@ -11,7 +11,6 @@ /// The board's physical memory map. #[rustfmt::skip] pub(super) mod map { - pub const BOARD_DEFAULT_LOAD_ADDRESS: usize = 0x8_0000; -- pub const GPIO_OFFSET: usize = 0x0020_0000; -- pub const UART_OFFSET: usize = 0x0020_1000; -+ pub const GPIO_OFFSET: usize = 0x0020_0000; -+ pub const UART_OFFSET: usize = 0x0020_1000; - - /// Physical devices. - #[cfg(feature = "bsp_rpi3")] + pub const GPIO_OFFSET: usize = 0x0020_0000; + pub const UART_OFFSET: usize = 0x0020_1000; @@ -36,13 +35,3 @@ pub const PL011_UART_START: usize = START + UART_OFFSET; } @@ -546,7 +542,7 @@ diff -uNr 06_uart_chainloader/src/main.rs 07_timestamps/src/main.rs /// Early init code. /// -@@ -143,56 +144,38 @@ +@@ -143,55 +144,38 @@ kernel_main() } @@ -559,8 +555,7 @@ diff -uNr 06_uart_chainloader/src/main.rs 07_timestamps/src/main.rs - /// The main function running after the early init. fn kernel_main() -> ! { -- use bsp::console::console; -- use console::interface::All; +- use console::console; + use core::time::Duration; + use driver::interface::DriverManager; + use time::interface::TimeManager; @@ -635,7 +630,7 @@ diff -uNr 06_uart_chainloader/src/main.rs 07_timestamps/src/main.rs diff -uNr 06_uart_chainloader/src/panic_wait.rs 07_timestamps/src/panic_wait.rs --- 06_uart_chainloader/src/panic_wait.rs +++ 07_timestamps/src/panic_wait.rs -@@ -58,18 +58,23 @@ +@@ -42,18 +42,23 @@ #[panic_handler] fn panic(info: &PanicInfo) -> ! { @@ -650,7 +645,7 @@ diff -uNr 06_uart_chainloader/src/panic_wait.rs 07_timestamps/src/panic_wait.rs _ => ("???", 0, 0), }; - panic_println!( + println!( - "Kernel panic!\n\n\ + "[ {:>3}.{:06}] Kernel panic!\n\n\ Panic location:\n File '{}', line {}, column {}\n\n\ @@ -664,7 +659,7 @@ diff -uNr 06_uart_chainloader/src/panic_wait.rs 07_timestamps/src/panic_wait.rs diff -uNr 06_uart_chainloader/src/print.rs 07_timestamps/src/print.rs --- 06_uart_chainloader/src/print.rs +++ 07_timestamps/src/print.rs -@@ -36,3 +36,59 @@ +@@ -34,3 +34,59 @@ $crate::print::_print(format_args_nl!($($arg)*)); }) } diff --git a/07_timestamps/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs b/07_timestamps/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs index dbb4beaa..24958eb5 100644 --- a/07_timestamps/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs +++ b/07_timestamps/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs @@ -108,16 +108,13 @@ register_structs! { /// Abstraction for the associated MMIO registers. type Registers = MMIODerefWrapper; -//-------------------------------------------------------------------------------------------------- -// Public Definitions -//-------------------------------------------------------------------------------------------------- - -pub struct GPIOInner { +struct GPIOInner { registers: Registers, } -// Export the inner struct so that BSPs can use it for the panic handler. -pub use GPIOInner as PanicGPIO; +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- /// Representation of the GPIO HW. pub struct GPIO { @@ -125,7 +122,7 @@ pub struct GPIO { } //-------------------------------------------------------------------------------------------------- -// Public Code +// Private Code //-------------------------------------------------------------------------------------------------- impl GPIOInner { @@ -189,7 +186,13 @@ impl GPIOInner { } } +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + impl GPIO { + pub const COMPATIBLE: &'static str = "BCM GPIO"; + /// Create an instance. /// /// # Safety @@ -214,6 +217,6 @@ use synchronization::interface::Mutex; impl driver::interface::DeviceDriver for GPIO { fn compatible(&self) -> &'static str { - "BCM GPIO" + Self::COMPATIBLE } } diff --git a/07_timestamps/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs b/07_timestamps/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs index 85cd3154..b034e92e 100644 --- a/07_timestamps/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs +++ b/07_timestamps/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs @@ -167,18 +167,15 @@ enum BlockingMode { NonBlocking, } -//-------------------------------------------------------------------------------------------------- -// Public Definitions -//-------------------------------------------------------------------------------------------------- - -pub struct PL011UartInner { +struct PL011UartInner { registers: Registers, chars_written: usize, chars_read: usize, } -// Export the inner struct so that BSPs can use it for the panic handler. -pub use PL011UartInner as PanicUart; +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- /// Representation of the UART. pub struct PL011Uart { @@ -186,7 +183,7 @@ pub struct PL011Uart { } //-------------------------------------------------------------------------------------------------- -// Public Code +// Private Code //-------------------------------------------------------------------------------------------------- impl PL011UartInner { @@ -326,7 +323,13 @@ impl fmt::Write for PL011UartInner { } } +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + impl PL011Uart { + pub const COMPATIBLE: &'static str = "BCM PL011 UART"; + /// Create an instance. /// /// # Safety @@ -346,7 +349,7 @@ use synchronization::interface::Mutex; impl driver::interface::DeviceDriver for PL011Uart { fn compatible(&self) -> &'static str { - "BCM PL011 UART" + Self::COMPATIBLE } unsafe fn init(&self) -> Result<(), &'static str> { @@ -400,3 +403,5 @@ impl console::interface::Statistics for PL011Uart { self.inner.lock(|inner| inner.chars_read) } } + +impl console::interface::All for PL011Uart {} diff --git a/07_timestamps/src/bsp/raspberrypi.rs b/07_timestamps/src/bsp/raspberrypi.rs index 22edb4fa..a9a7261a 100644 --- a/07_timestamps/src/bsp/raspberrypi.rs +++ b/07_timestamps/src/bsp/raspberrypi.rs @@ -9,17 +9,6 @@ pub mod cpu; pub mod driver; pub mod memory; -//-------------------------------------------------------------------------------------------------- -// Global instances -//-------------------------------------------------------------------------------------------------- -use super::device_driver; - -static GPIO: device_driver::GPIO = - unsafe { device_driver::GPIO::new(memory::map::mmio::GPIO_START) }; - -static PL011_UART: device_driver::PL011Uart = - unsafe { device_driver::PL011Uart::new(memory::map::mmio::PL011_UART_START) }; - //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- diff --git a/07_timestamps/src/bsp/raspberrypi/console.rs b/07_timestamps/src/bsp/raspberrypi/console.rs index a247032f..0a630eef 100644 --- a/07_timestamps/src/bsp/raspberrypi/console.rs +++ b/07_timestamps/src/bsp/raspberrypi/console.rs @@ -4,34 +4,13 @@ //! BSP console facilities. -use super::memory; -use crate::{bsp::device_driver, console}; -use core::fmt; +use crate::console; //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- -/// In case of a panic, the panic handler uses this function to take a last shot at printing -/// something before the system is halted. -/// -/// We try to init panic-versions of the GPIO and the UART. The panic versions are not protected -/// with synchronization primitives, which increases chances that we get to print something, even -/// when the kernel's default GPIO or UART instances happen to be locked at the time of the panic. -/// -/// # Safety -/// -/// - Use only for printing during a panic. -pub unsafe fn panic_console_out() -> impl fmt::Write { - let mut panic_gpio = device_driver::PanicGPIO::new(memory::map::mmio::GPIO_START); - let mut panic_uart = device_driver::PanicUart::new(memory::map::mmio::PL011_UART_START); - - panic_gpio.map_pl011_uart(); - panic_uart.init(); - panic_uart -} - /// Return a reference to the console. -pub fn console() -> &'static impl console::interface::All { - &super::PL011_UART +pub fn console() -> &'static dyn console::interface::All { + &super::driver::PL011_UART } diff --git a/07_timestamps/src/bsp/raspberrypi/driver.rs b/07_timestamps/src/bsp/raspberrypi/driver.rs index b5538baa..8b683ed8 100644 --- a/07_timestamps/src/bsp/raspberrypi/driver.rs +++ b/07_timestamps/src/bsp/raspberrypi/driver.rs @@ -4,7 +4,8 @@ //! BSP driver support. -use crate::driver; +use super::memory::map::mmio; +use crate::{bsp::device_driver, driver}; //-------------------------------------------------------------------------------------------------- // Private Definitions @@ -19,8 +20,13 @@ struct BSPDriverManager { // Global instances //-------------------------------------------------------------------------------------------------- +pub(super) static PL011_UART: device_driver::PL011Uart = + unsafe { device_driver::PL011Uart::new(mmio::PL011_UART_START) }; + +static GPIO: device_driver::GPIO = unsafe { device_driver::GPIO::new(mmio::GPIO_START) }; + static BSP_DRIVER_MANAGER: BSPDriverManager = BSPDriverManager { - device_drivers: [&super::GPIO, &super::PL011_UART], + device_drivers: [&PL011_UART, &GPIO], }; //-------------------------------------------------------------------------------------------------- @@ -44,6 +50,6 @@ impl driver::interface::DriverManager for BSPDriverManager { fn post_device_driver_init(&self) { // Configure PL011Uart's output pins. - super::GPIO.map_pl011_uart(); + GPIO.map_pl011_uart(); } } diff --git a/07_timestamps/src/console.rs b/07_timestamps/src/console.rs index e49e241f..c1fb0e53 100644 --- a/07_timestamps/src/console.rs +++ b/07_timestamps/src/console.rs @@ -4,6 +4,8 @@ //! System console. +use crate::bsp; + //-------------------------------------------------------------------------------------------------- // Public Definitions //-------------------------------------------------------------------------------------------------- @@ -49,5 +51,16 @@ pub mod interface { } /// Trait alias for a full-fledged console. - pub trait All = Write + Read + Statistics; + pub trait All: Write + Read + Statistics {} +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +/// Return a reference to the console. +/// +/// This is the global console used by all printing macros. +pub fn console() -> &'static dyn interface::All { + bsp::console::console() } diff --git a/07_timestamps/src/panic_wait.rs b/07_timestamps/src/panic_wait.rs index f851e0d8..edd83885 100644 --- a/07_timestamps/src/panic_wait.rs +++ b/07_timestamps/src/panic_wait.rs @@ -4,29 +4,13 @@ //! A panic handler that infinitely waits. -use crate::{bsp, cpu}; -use core::{fmt, panic::PanicInfo}; +use crate::{cpu, println}; +use core::panic::PanicInfo; //-------------------------------------------------------------------------------------------------- // Private Code //-------------------------------------------------------------------------------------------------- -fn _panic_print(args: fmt::Arguments) { - use fmt::Write; - - unsafe { bsp::console::panic_console_out().write_fmt(args).unwrap() }; -} - -/// Prints with a newline - only use from the panic handler. -/// -/// Carbon copy from -#[macro_export] -macro_rules! panic_println { - ($($arg:tt)*) => ({ - _panic_print(format_args_nl!($($arg)*)); - }) -} - /// Stop immediately if called a second time. /// /// # Note @@ -69,7 +53,7 @@ fn panic(info: &PanicInfo) -> ! { _ => ("???", 0, 0), }; - panic_println!( + println!( "[ {:>3}.{:06}] Kernel panic!\n\n\ Panic location:\n File '{}', line {}, column {}\n\n\ {}", diff --git a/07_timestamps/src/print.rs b/07_timestamps/src/print.rs index 9ec13a28..8705eec0 100644 --- a/07_timestamps/src/print.rs +++ b/07_timestamps/src/print.rs @@ -4,7 +4,7 @@ //! Printing. -use crate::{bsp, console}; +use crate::console; use core::fmt; //-------------------------------------------------------------------------------------------------- @@ -13,9 +13,7 @@ use core::fmt; #[doc(hidden)] pub fn _print(args: fmt::Arguments) { - use console::interface::Write; - - bsp::console::console().write_fmt(args).unwrap(); + console::console().write_fmt(args).unwrap(); } /// Prints without a newline. diff --git a/08_hw_debug_JTAG/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs b/08_hw_debug_JTAG/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs index dbb4beaa..24958eb5 100644 --- a/08_hw_debug_JTAG/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs +++ b/08_hw_debug_JTAG/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs @@ -108,16 +108,13 @@ register_structs! { /// Abstraction for the associated MMIO registers. type Registers = MMIODerefWrapper; -//-------------------------------------------------------------------------------------------------- -// Public Definitions -//-------------------------------------------------------------------------------------------------- - -pub struct GPIOInner { +struct GPIOInner { registers: Registers, } -// Export the inner struct so that BSPs can use it for the panic handler. -pub use GPIOInner as PanicGPIO; +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- /// Representation of the GPIO HW. pub struct GPIO { @@ -125,7 +122,7 @@ pub struct GPIO { } //-------------------------------------------------------------------------------------------------- -// Public Code +// Private Code //-------------------------------------------------------------------------------------------------- impl GPIOInner { @@ -189,7 +186,13 @@ impl GPIOInner { } } +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + impl GPIO { + pub const COMPATIBLE: &'static str = "BCM GPIO"; + /// Create an instance. /// /// # Safety @@ -214,6 +217,6 @@ use synchronization::interface::Mutex; impl driver::interface::DeviceDriver for GPIO { fn compatible(&self) -> &'static str { - "BCM GPIO" + Self::COMPATIBLE } } diff --git a/08_hw_debug_JTAG/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs b/08_hw_debug_JTAG/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs index 85cd3154..b034e92e 100644 --- a/08_hw_debug_JTAG/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs +++ b/08_hw_debug_JTAG/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs @@ -167,18 +167,15 @@ enum BlockingMode { NonBlocking, } -//-------------------------------------------------------------------------------------------------- -// Public Definitions -//-------------------------------------------------------------------------------------------------- - -pub struct PL011UartInner { +struct PL011UartInner { registers: Registers, chars_written: usize, chars_read: usize, } -// Export the inner struct so that BSPs can use it for the panic handler. -pub use PL011UartInner as PanicUart; +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- /// Representation of the UART. pub struct PL011Uart { @@ -186,7 +183,7 @@ pub struct PL011Uart { } //-------------------------------------------------------------------------------------------------- -// Public Code +// Private Code //-------------------------------------------------------------------------------------------------- impl PL011UartInner { @@ -326,7 +323,13 @@ impl fmt::Write for PL011UartInner { } } +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + impl PL011Uart { + pub const COMPATIBLE: &'static str = "BCM PL011 UART"; + /// Create an instance. /// /// # Safety @@ -346,7 +349,7 @@ use synchronization::interface::Mutex; impl driver::interface::DeviceDriver for PL011Uart { fn compatible(&self) -> &'static str { - "BCM PL011 UART" + Self::COMPATIBLE } unsafe fn init(&self) -> Result<(), &'static str> { @@ -400,3 +403,5 @@ impl console::interface::Statistics for PL011Uart { self.inner.lock(|inner| inner.chars_read) } } + +impl console::interface::All for PL011Uart {} diff --git a/08_hw_debug_JTAG/src/bsp/raspberrypi.rs b/08_hw_debug_JTAG/src/bsp/raspberrypi.rs index 22edb4fa..a9a7261a 100644 --- a/08_hw_debug_JTAG/src/bsp/raspberrypi.rs +++ b/08_hw_debug_JTAG/src/bsp/raspberrypi.rs @@ -9,17 +9,6 @@ pub mod cpu; pub mod driver; pub mod memory; -//-------------------------------------------------------------------------------------------------- -// Global instances -//-------------------------------------------------------------------------------------------------- -use super::device_driver; - -static GPIO: device_driver::GPIO = - unsafe { device_driver::GPIO::new(memory::map::mmio::GPIO_START) }; - -static PL011_UART: device_driver::PL011Uart = - unsafe { device_driver::PL011Uart::new(memory::map::mmio::PL011_UART_START) }; - //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- diff --git a/08_hw_debug_JTAG/src/bsp/raspberrypi/console.rs b/08_hw_debug_JTAG/src/bsp/raspberrypi/console.rs index a247032f..0a630eef 100644 --- a/08_hw_debug_JTAG/src/bsp/raspberrypi/console.rs +++ b/08_hw_debug_JTAG/src/bsp/raspberrypi/console.rs @@ -4,34 +4,13 @@ //! BSP console facilities. -use super::memory; -use crate::{bsp::device_driver, console}; -use core::fmt; +use crate::console; //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- -/// In case of a panic, the panic handler uses this function to take a last shot at printing -/// something before the system is halted. -/// -/// We try to init panic-versions of the GPIO and the UART. The panic versions are not protected -/// with synchronization primitives, which increases chances that we get to print something, even -/// when the kernel's default GPIO or UART instances happen to be locked at the time of the panic. -/// -/// # Safety -/// -/// - Use only for printing during a panic. -pub unsafe fn panic_console_out() -> impl fmt::Write { - let mut panic_gpio = device_driver::PanicGPIO::new(memory::map::mmio::GPIO_START); - let mut panic_uart = device_driver::PanicUart::new(memory::map::mmio::PL011_UART_START); - - panic_gpio.map_pl011_uart(); - panic_uart.init(); - panic_uart -} - /// Return a reference to the console. -pub fn console() -> &'static impl console::interface::All { - &super::PL011_UART +pub fn console() -> &'static dyn console::interface::All { + &super::driver::PL011_UART } diff --git a/08_hw_debug_JTAG/src/bsp/raspberrypi/driver.rs b/08_hw_debug_JTAG/src/bsp/raspberrypi/driver.rs index b5538baa..8b683ed8 100644 --- a/08_hw_debug_JTAG/src/bsp/raspberrypi/driver.rs +++ b/08_hw_debug_JTAG/src/bsp/raspberrypi/driver.rs @@ -4,7 +4,8 @@ //! BSP driver support. -use crate::driver; +use super::memory::map::mmio; +use crate::{bsp::device_driver, driver}; //-------------------------------------------------------------------------------------------------- // Private Definitions @@ -19,8 +20,13 @@ struct BSPDriverManager { // Global instances //-------------------------------------------------------------------------------------------------- +pub(super) static PL011_UART: device_driver::PL011Uart = + unsafe { device_driver::PL011Uart::new(mmio::PL011_UART_START) }; + +static GPIO: device_driver::GPIO = unsafe { device_driver::GPIO::new(mmio::GPIO_START) }; + static BSP_DRIVER_MANAGER: BSPDriverManager = BSPDriverManager { - device_drivers: [&super::GPIO, &super::PL011_UART], + device_drivers: [&PL011_UART, &GPIO], }; //-------------------------------------------------------------------------------------------------- @@ -44,6 +50,6 @@ impl driver::interface::DriverManager for BSPDriverManager { fn post_device_driver_init(&self) { // Configure PL011Uart's output pins. - super::GPIO.map_pl011_uart(); + GPIO.map_pl011_uart(); } } diff --git a/08_hw_debug_JTAG/src/console.rs b/08_hw_debug_JTAG/src/console.rs index e49e241f..c1fb0e53 100644 --- a/08_hw_debug_JTAG/src/console.rs +++ b/08_hw_debug_JTAG/src/console.rs @@ -4,6 +4,8 @@ //! System console. +use crate::bsp; + //-------------------------------------------------------------------------------------------------- // Public Definitions //-------------------------------------------------------------------------------------------------- @@ -49,5 +51,16 @@ pub mod interface { } /// Trait alias for a full-fledged console. - pub trait All = Write + Read + Statistics; + pub trait All: Write + Read + Statistics {} +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +/// Return a reference to the console. +/// +/// This is the global console used by all printing macros. +pub fn console() -> &'static dyn interface::All { + bsp::console::console() } diff --git a/08_hw_debug_JTAG/src/panic_wait.rs b/08_hw_debug_JTAG/src/panic_wait.rs index f851e0d8..edd83885 100644 --- a/08_hw_debug_JTAG/src/panic_wait.rs +++ b/08_hw_debug_JTAG/src/panic_wait.rs @@ -4,29 +4,13 @@ //! A panic handler that infinitely waits. -use crate::{bsp, cpu}; -use core::{fmt, panic::PanicInfo}; +use crate::{cpu, println}; +use core::panic::PanicInfo; //-------------------------------------------------------------------------------------------------- // Private Code //-------------------------------------------------------------------------------------------------- -fn _panic_print(args: fmt::Arguments) { - use fmt::Write; - - unsafe { bsp::console::panic_console_out().write_fmt(args).unwrap() }; -} - -/// Prints with a newline - only use from the panic handler. -/// -/// Carbon copy from -#[macro_export] -macro_rules! panic_println { - ($($arg:tt)*) => ({ - _panic_print(format_args_nl!($($arg)*)); - }) -} - /// Stop immediately if called a second time. /// /// # Note @@ -69,7 +53,7 @@ fn panic(info: &PanicInfo) -> ! { _ => ("???", 0, 0), }; - panic_println!( + println!( "[ {:>3}.{:06}] Kernel panic!\n\n\ Panic location:\n File '{}', line {}, column {}\n\n\ {}", diff --git a/08_hw_debug_JTAG/src/print.rs b/08_hw_debug_JTAG/src/print.rs index 9ec13a28..8705eec0 100644 --- a/08_hw_debug_JTAG/src/print.rs +++ b/08_hw_debug_JTAG/src/print.rs @@ -4,7 +4,7 @@ //! Printing. -use crate::{bsp, console}; +use crate::console; use core::fmt; //-------------------------------------------------------------------------------------------------- @@ -13,9 +13,7 @@ use core::fmt; #[doc(hidden)] pub fn _print(args: fmt::Arguments) { - use console::interface::Write; - - bsp::console::console().write_fmt(args).unwrap(); + console::console().write_fmt(args).unwrap(); } /// Prints without a newline. diff --git a/09_privilege_level/README.md b/09_privilege_level/README.md index 2320dfd7..63cbcb89 100644 --- a/09_privilege_level/README.md +++ b/09_privilege_level/README.md @@ -166,6 +166,7 @@ Minipush 1.0 [MP] ⏳ Waiting for /dev/ttyUSB0 [MP] ✅ Serial connected [MP] 🔌 Please power the target now + __ __ _ _ _ _ | \/ (_)_ _ (_) | ___ __ _ __| | | |\/| | | ' \| | |__/ _ \/ _` / _` | @@ -177,20 +178,20 @@ Minipush 1.0 [MP] ⏩ Pushing 14 KiB =========================================🦀 100% 0 KiB/s Time: 00:00:00 [ML] Loaded! Executing the payload now -[ 0.165757] mingo version 0.9.0 -[ 0.165957] Booting on: Raspberry Pi 3 -[ 0.166412] Current privilege level: EL1 -[ 0.166888] Exception handling state: -[ 0.167333] Debug: Masked -[ 0.167723] SError: Masked -[ 0.168112] IRQ: Masked -[ 0.168502] FIQ: Masked -[ 0.168893] Architectural timer resolution: 52 ns -[ 0.169467] Drivers loaded: -[ 0.169803] 1. BCM GPIO -[ 0.170160] 2. BCM PL011 UART -[ 0.170583] Timer test, spinning for 1 second -[ 1.171115] Echoing input now +[ 0.162546] mingo version 0.9.0 +[ 0.162745] Booting on: Raspberry Pi 3 +[ 0.163201] Current privilege level: EL1 +[ 0.163677] Exception handling state: +[ 0.164122] Debug: Masked +[ 0.164511] SError: Masked +[ 0.164901] IRQ: Masked +[ 0.165291] FIQ: Masked +[ 0.165681] Architectural timer resolution: 52 ns +[ 0.166255] Drivers loaded: +[ 0.166592] 1. BCM PL011 UART +[ 0.167014] 2. BCM GPIO +[ 0.167371] Timer test, spinning for 1 second +[ 1.167904] Echoing input now ``` ## Diff to previous @@ -505,16 +506,15 @@ diff -uNr 08_hw_debug_JTAG/src/main.rs 09_privilege_level/src/main.rs mod panic_wait; mod print; mod synchronization; -@@ -146,6 +147,8 @@ +@@ -146,6 +147,7 @@ /// The main function running after the early init. fn kernel_main() -> ! { -+ use bsp::console::console; -+ use console::interface::All; ++ use console::console; use core::time::Duration; use driver::interface::DriverManager; use time::interface::TimeManager; -@@ -157,6 +160,12 @@ +@@ -157,6 +159,12 @@ ); info!("Booting on: {}", bsp::board_name()); @@ -527,7 +527,7 @@ diff -uNr 08_hw_debug_JTAG/src/main.rs 09_privilege_level/src/main.rs info!( "Architectural timer resolution: {} ns", time::time_manager().resolution().as_nanos() -@@ -171,11 +180,15 @@ +@@ -171,11 +179,15 @@ info!(" {}. {}", i + 1, driver.compatible()); } @@ -543,8 +543,8 @@ diff -uNr 08_hw_debug_JTAG/src/main.rs 09_privilege_level/src/main.rs loop { - info!("Spinning for 1 second"); - time::time_manager().spin_for(Duration::from_secs(1)); -+ let c = bsp::console::console().read_char(); -+ bsp::console::console().write_char(c); ++ let c = console().read_char(); ++ console().write_char(c); } } diff --git a/09_privilege_level/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs b/09_privilege_level/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs index dbb4beaa..24958eb5 100644 --- a/09_privilege_level/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs +++ b/09_privilege_level/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs @@ -108,16 +108,13 @@ register_structs! { /// Abstraction for the associated MMIO registers. type Registers = MMIODerefWrapper; -//-------------------------------------------------------------------------------------------------- -// Public Definitions -//-------------------------------------------------------------------------------------------------- - -pub struct GPIOInner { +struct GPIOInner { registers: Registers, } -// Export the inner struct so that BSPs can use it for the panic handler. -pub use GPIOInner as PanicGPIO; +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- /// Representation of the GPIO HW. pub struct GPIO { @@ -125,7 +122,7 @@ pub struct GPIO { } //-------------------------------------------------------------------------------------------------- -// Public Code +// Private Code //-------------------------------------------------------------------------------------------------- impl GPIOInner { @@ -189,7 +186,13 @@ impl GPIOInner { } } +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + impl GPIO { + pub const COMPATIBLE: &'static str = "BCM GPIO"; + /// Create an instance. /// /// # Safety @@ -214,6 +217,6 @@ use synchronization::interface::Mutex; impl driver::interface::DeviceDriver for GPIO { fn compatible(&self) -> &'static str { - "BCM GPIO" + Self::COMPATIBLE } } diff --git a/09_privilege_level/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs b/09_privilege_level/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs index 85cd3154..b034e92e 100644 --- a/09_privilege_level/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs +++ b/09_privilege_level/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs @@ -167,18 +167,15 @@ enum BlockingMode { NonBlocking, } -//-------------------------------------------------------------------------------------------------- -// Public Definitions -//-------------------------------------------------------------------------------------------------- - -pub struct PL011UartInner { +struct PL011UartInner { registers: Registers, chars_written: usize, chars_read: usize, } -// Export the inner struct so that BSPs can use it for the panic handler. -pub use PL011UartInner as PanicUart; +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- /// Representation of the UART. pub struct PL011Uart { @@ -186,7 +183,7 @@ pub struct PL011Uart { } //-------------------------------------------------------------------------------------------------- -// Public Code +// Private Code //-------------------------------------------------------------------------------------------------- impl PL011UartInner { @@ -326,7 +323,13 @@ impl fmt::Write for PL011UartInner { } } +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + impl PL011Uart { + pub const COMPATIBLE: &'static str = "BCM PL011 UART"; + /// Create an instance. /// /// # Safety @@ -346,7 +349,7 @@ use synchronization::interface::Mutex; impl driver::interface::DeviceDriver for PL011Uart { fn compatible(&self) -> &'static str { - "BCM PL011 UART" + Self::COMPATIBLE } unsafe fn init(&self) -> Result<(), &'static str> { @@ -400,3 +403,5 @@ impl console::interface::Statistics for PL011Uart { self.inner.lock(|inner| inner.chars_read) } } + +impl console::interface::All for PL011Uart {} diff --git a/09_privilege_level/src/bsp/raspberrypi.rs b/09_privilege_level/src/bsp/raspberrypi.rs index 22edb4fa..a9a7261a 100644 --- a/09_privilege_level/src/bsp/raspberrypi.rs +++ b/09_privilege_level/src/bsp/raspberrypi.rs @@ -9,17 +9,6 @@ pub mod cpu; pub mod driver; pub mod memory; -//-------------------------------------------------------------------------------------------------- -// Global instances -//-------------------------------------------------------------------------------------------------- -use super::device_driver; - -static GPIO: device_driver::GPIO = - unsafe { device_driver::GPIO::new(memory::map::mmio::GPIO_START) }; - -static PL011_UART: device_driver::PL011Uart = - unsafe { device_driver::PL011Uart::new(memory::map::mmio::PL011_UART_START) }; - //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- diff --git a/09_privilege_level/src/bsp/raspberrypi/console.rs b/09_privilege_level/src/bsp/raspberrypi/console.rs index a247032f..0a630eef 100644 --- a/09_privilege_level/src/bsp/raspberrypi/console.rs +++ b/09_privilege_level/src/bsp/raspberrypi/console.rs @@ -4,34 +4,13 @@ //! BSP console facilities. -use super::memory; -use crate::{bsp::device_driver, console}; -use core::fmt; +use crate::console; //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- -/// In case of a panic, the panic handler uses this function to take a last shot at printing -/// something before the system is halted. -/// -/// We try to init panic-versions of the GPIO and the UART. The panic versions are not protected -/// with synchronization primitives, which increases chances that we get to print something, even -/// when the kernel's default GPIO or UART instances happen to be locked at the time of the panic. -/// -/// # Safety -/// -/// - Use only for printing during a panic. -pub unsafe fn panic_console_out() -> impl fmt::Write { - let mut panic_gpio = device_driver::PanicGPIO::new(memory::map::mmio::GPIO_START); - let mut panic_uart = device_driver::PanicUart::new(memory::map::mmio::PL011_UART_START); - - panic_gpio.map_pl011_uart(); - panic_uart.init(); - panic_uart -} - /// Return a reference to the console. -pub fn console() -> &'static impl console::interface::All { - &super::PL011_UART +pub fn console() -> &'static dyn console::interface::All { + &super::driver::PL011_UART } diff --git a/09_privilege_level/src/bsp/raspberrypi/driver.rs b/09_privilege_level/src/bsp/raspberrypi/driver.rs index b5538baa..8b683ed8 100644 --- a/09_privilege_level/src/bsp/raspberrypi/driver.rs +++ b/09_privilege_level/src/bsp/raspberrypi/driver.rs @@ -4,7 +4,8 @@ //! BSP driver support. -use crate::driver; +use super::memory::map::mmio; +use crate::{bsp::device_driver, driver}; //-------------------------------------------------------------------------------------------------- // Private Definitions @@ -19,8 +20,13 @@ struct BSPDriverManager { // Global instances //-------------------------------------------------------------------------------------------------- +pub(super) static PL011_UART: device_driver::PL011Uart = + unsafe { device_driver::PL011Uart::new(mmio::PL011_UART_START) }; + +static GPIO: device_driver::GPIO = unsafe { device_driver::GPIO::new(mmio::GPIO_START) }; + static BSP_DRIVER_MANAGER: BSPDriverManager = BSPDriverManager { - device_drivers: [&super::GPIO, &super::PL011_UART], + device_drivers: [&PL011_UART, &GPIO], }; //-------------------------------------------------------------------------------------------------- @@ -44,6 +50,6 @@ impl driver::interface::DriverManager for BSPDriverManager { fn post_device_driver_init(&self) { // Configure PL011Uart's output pins. - super::GPIO.map_pl011_uart(); + GPIO.map_pl011_uart(); } } diff --git a/09_privilege_level/src/console.rs b/09_privilege_level/src/console.rs index e49e241f..c1fb0e53 100644 --- a/09_privilege_level/src/console.rs +++ b/09_privilege_level/src/console.rs @@ -4,6 +4,8 @@ //! System console. +use crate::bsp; + //-------------------------------------------------------------------------------------------------- // Public Definitions //-------------------------------------------------------------------------------------------------- @@ -49,5 +51,16 @@ pub mod interface { } /// Trait alias for a full-fledged console. - pub trait All = Write + Read + Statistics; + pub trait All: Write + Read + Statistics {} +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +/// Return a reference to the console. +/// +/// This is the global console used by all printing macros. +pub fn console() -> &'static dyn interface::All { + bsp::console::console() } diff --git a/09_privilege_level/src/main.rs b/09_privilege_level/src/main.rs index 0c6a0dec..6c1ab310 100644 --- a/09_privilege_level/src/main.rs +++ b/09_privilege_level/src/main.rs @@ -147,8 +147,7 @@ unsafe fn kernel_init() -> ! { /// The main function running after the early init. fn kernel_main() -> ! { - use bsp::console::console; - use console::interface::All; + use console::console; use core::time::Duration; use driver::interface::DriverManager; use time::interface::TimeManager; @@ -188,7 +187,7 @@ fn kernel_main() -> ! { // Discard any spurious received characters before going into echo mode. console().clear_rx(); loop { - let c = bsp::console::console().read_char(); - bsp::console::console().write_char(c); + let c = console().read_char(); + console().write_char(c); } } diff --git a/09_privilege_level/src/panic_wait.rs b/09_privilege_level/src/panic_wait.rs index f851e0d8..edd83885 100644 --- a/09_privilege_level/src/panic_wait.rs +++ b/09_privilege_level/src/panic_wait.rs @@ -4,29 +4,13 @@ //! A panic handler that infinitely waits. -use crate::{bsp, cpu}; -use core::{fmt, panic::PanicInfo}; +use crate::{cpu, println}; +use core::panic::PanicInfo; //-------------------------------------------------------------------------------------------------- // Private Code //-------------------------------------------------------------------------------------------------- -fn _panic_print(args: fmt::Arguments) { - use fmt::Write; - - unsafe { bsp::console::panic_console_out().write_fmt(args).unwrap() }; -} - -/// Prints with a newline - only use from the panic handler. -/// -/// Carbon copy from -#[macro_export] -macro_rules! panic_println { - ($($arg:tt)*) => ({ - _panic_print(format_args_nl!($($arg)*)); - }) -} - /// Stop immediately if called a second time. /// /// # Note @@ -69,7 +53,7 @@ fn panic(info: &PanicInfo) -> ! { _ => ("???", 0, 0), }; - panic_println!( + println!( "[ {:>3}.{:06}] Kernel panic!\n\n\ Panic location:\n File '{}', line {}, column {}\n\n\ {}", diff --git a/09_privilege_level/src/print.rs b/09_privilege_level/src/print.rs index 9ec13a28..8705eec0 100644 --- a/09_privilege_level/src/print.rs +++ b/09_privilege_level/src/print.rs @@ -4,7 +4,7 @@ //! Printing. -use crate::{bsp, console}; +use crate::console; use core::fmt; //-------------------------------------------------------------------------------------------------- @@ -13,9 +13,7 @@ use core::fmt; #[doc(hidden)] pub fn _print(args: fmt::Arguments) { - use console::interface::Write; - - bsp::console::console().write_fmt(args).unwrap(); + console::console().write_fmt(args).unwrap(); } /// Prints without a newline. diff --git a/10_virtual_mem_part1_identity_mapping/README.md b/10_virtual_mem_part1_identity_mapping/README.md index 802243c8..04b82eca 100644 --- a/10_virtual_mem_part1_identity_mapping/README.md +++ b/10_virtual_mem_part1_identity_mapping/README.md @@ -314,6 +314,7 @@ Minipush 1.0 [MP] ⏳ Waiting for /dev/ttyUSB0 [MP] ✅ Serial connected [MP] 🔌 Please power the target now + __ __ _ _ _ _ | \/ (_)_ _ (_) | ___ __ _ __| | | |\/| | | ' \| | |__/ _ \/ _` / _` | @@ -325,25 +326,25 @@ Minipush 1.0 [MP] ⏩ Pushing 64 KiB =========================================🦀 100% 0 KiB/s Time: 00:00:00 [ML] Loaded! Executing the payload now -[ 1.034062] mingo version 0.10.0 -[ 1.034270] Booting on: Raspberry Pi 3 -[ 1.034725] MMU online. Special regions: -[ 1.035201] 0x00080000 - 0x0008ffff | 64 KiB | C RO PX | Kernel code and RO data -[ 1.036220] 0x1fff0000 - 0x1fffffff | 64 KiB | Dev RW PXN | Remapped Device MMIO -[ 1.037205] 0x3f000000 - 0x4000ffff | 16 MiB | Dev RW PXN | Device MMIO -[ 1.038094] Current privilege level: EL1 -[ 1.038570] Exception handling state: -[ 1.039015] Debug: Masked -[ 1.039405] SError: Masked -[ 1.039794] IRQ: Masked -[ 1.040184] FIQ: Masked -[ 1.040575] Architectural timer resolution: 52 ns -[ 1.041148] Drivers loaded: -[ 1.041484] 1. BCM GPIO -[ 1.041842] 2. BCM PL011 UART -[ 1.042264] Timer test, spinning for 1 second +[ 0.811167] mingo version 0.10.0 +[ 0.811374] Booting on: Raspberry Pi 3 +[ 0.811829] MMU online. Special regions: +[ 0.812306] 0x00080000 - 0x0008ffff | 64 KiB | C RO PX | Kernel code and RO data +[ 0.813324] 0x1fff0000 - 0x1fffffff | 64 KiB | Dev RW PXN | Remapped Device MMIO +[ 0.814310] 0x3f000000 - 0x4000ffff | 16 MiB | Dev RW PXN | Device MMIO +[ 0.815198] Current privilege level: EL1 +[ 0.815675] Exception handling state: +[ 0.816119] Debug: Masked +[ 0.816509] SError: Masked +[ 0.816899] IRQ: Masked +[ 0.817289] FIQ: Masked +[ 0.817679] Architectural timer resolution: 52 ns +[ 0.818253] Drivers loaded: +[ 0.818589] 1. BCM PL011 UART +[ 0.819011] 2. BCM GPIO +[ 0.819369] Timer test, spinning for 1 second [ !!! ] Writing through the remapped UART at 0x1FFF_1000 -[ 2.043305] Echoing input now +[ 1.820409] Echoing input now ``` ## Diff to previous @@ -1118,7 +1119,16 @@ diff -uNr 09_privilege_level/src/main.rs 10_virtual_mem_part1_identity_mapping/s for i in bsp::driver::driver_manager().all_device_drivers().iter() { if let Err(x) = i.init() { -@@ -160,6 +171,9 @@ +@@ -147,7 +158,7 @@ + + /// The main function running after the early init. + fn kernel_main() -> ! { +- use console::console; ++ use console::{console, interface::Write}; + use core::time::Duration; + use driver::interface::DriverManager; + use time::interface::TimeManager; +@@ -159,6 +170,9 @@ ); info!("Booting on: {}", bsp::board_name()); @@ -1128,7 +1138,7 @@ diff -uNr 09_privilege_level/src/main.rs 10_virtual_mem_part1_identity_mapping/s let (_, privilege_level) = exception::current_privilege_level(); info!("Current privilege level: {}", privilege_level); -@@ -183,6 +197,13 @@ +@@ -182,6 +196,13 @@ info!("Timer test, spinning for 1 second"); time::time_manager().spin_for(Duration::from_secs(1)); diff --git a/10_virtual_mem_part1_identity_mapping/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs b/10_virtual_mem_part1_identity_mapping/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs index dbb4beaa..24958eb5 100644 --- a/10_virtual_mem_part1_identity_mapping/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs +++ b/10_virtual_mem_part1_identity_mapping/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs @@ -108,16 +108,13 @@ register_structs! { /// Abstraction for the associated MMIO registers. type Registers = MMIODerefWrapper; -//-------------------------------------------------------------------------------------------------- -// Public Definitions -//-------------------------------------------------------------------------------------------------- - -pub struct GPIOInner { +struct GPIOInner { registers: Registers, } -// Export the inner struct so that BSPs can use it for the panic handler. -pub use GPIOInner as PanicGPIO; +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- /// Representation of the GPIO HW. pub struct GPIO { @@ -125,7 +122,7 @@ pub struct GPIO { } //-------------------------------------------------------------------------------------------------- -// Public Code +// Private Code //-------------------------------------------------------------------------------------------------- impl GPIOInner { @@ -189,7 +186,13 @@ impl GPIOInner { } } +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + impl GPIO { + pub const COMPATIBLE: &'static str = "BCM GPIO"; + /// Create an instance. /// /// # Safety @@ -214,6 +217,6 @@ use synchronization::interface::Mutex; impl driver::interface::DeviceDriver for GPIO { fn compatible(&self) -> &'static str { - "BCM GPIO" + Self::COMPATIBLE } } diff --git a/10_virtual_mem_part1_identity_mapping/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs b/10_virtual_mem_part1_identity_mapping/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs index 85cd3154..b034e92e 100644 --- a/10_virtual_mem_part1_identity_mapping/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs +++ b/10_virtual_mem_part1_identity_mapping/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs @@ -167,18 +167,15 @@ enum BlockingMode { NonBlocking, } -//-------------------------------------------------------------------------------------------------- -// Public Definitions -//-------------------------------------------------------------------------------------------------- - -pub struct PL011UartInner { +struct PL011UartInner { registers: Registers, chars_written: usize, chars_read: usize, } -// Export the inner struct so that BSPs can use it for the panic handler. -pub use PL011UartInner as PanicUart; +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- /// Representation of the UART. pub struct PL011Uart { @@ -186,7 +183,7 @@ pub struct PL011Uart { } //-------------------------------------------------------------------------------------------------- -// Public Code +// Private Code //-------------------------------------------------------------------------------------------------- impl PL011UartInner { @@ -326,7 +323,13 @@ impl fmt::Write for PL011UartInner { } } +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + impl PL011Uart { + pub const COMPATIBLE: &'static str = "BCM PL011 UART"; + /// Create an instance. /// /// # Safety @@ -346,7 +349,7 @@ use synchronization::interface::Mutex; impl driver::interface::DeviceDriver for PL011Uart { fn compatible(&self) -> &'static str { - "BCM PL011 UART" + Self::COMPATIBLE } unsafe fn init(&self) -> Result<(), &'static str> { @@ -400,3 +403,5 @@ impl console::interface::Statistics for PL011Uart { self.inner.lock(|inner| inner.chars_read) } } + +impl console::interface::All for PL011Uart {} diff --git a/10_virtual_mem_part1_identity_mapping/src/bsp/raspberrypi.rs b/10_virtual_mem_part1_identity_mapping/src/bsp/raspberrypi.rs index 22edb4fa..a9a7261a 100644 --- a/10_virtual_mem_part1_identity_mapping/src/bsp/raspberrypi.rs +++ b/10_virtual_mem_part1_identity_mapping/src/bsp/raspberrypi.rs @@ -9,17 +9,6 @@ pub mod cpu; pub mod driver; pub mod memory; -//-------------------------------------------------------------------------------------------------- -// Global instances -//-------------------------------------------------------------------------------------------------- -use super::device_driver; - -static GPIO: device_driver::GPIO = - unsafe { device_driver::GPIO::new(memory::map::mmio::GPIO_START) }; - -static PL011_UART: device_driver::PL011Uart = - unsafe { device_driver::PL011Uart::new(memory::map::mmio::PL011_UART_START) }; - //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- diff --git a/10_virtual_mem_part1_identity_mapping/src/bsp/raspberrypi/console.rs b/10_virtual_mem_part1_identity_mapping/src/bsp/raspberrypi/console.rs index a247032f..0a630eef 100644 --- a/10_virtual_mem_part1_identity_mapping/src/bsp/raspberrypi/console.rs +++ b/10_virtual_mem_part1_identity_mapping/src/bsp/raspberrypi/console.rs @@ -4,34 +4,13 @@ //! BSP console facilities. -use super::memory; -use crate::{bsp::device_driver, console}; -use core::fmt; +use crate::console; //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- -/// In case of a panic, the panic handler uses this function to take a last shot at printing -/// something before the system is halted. -/// -/// We try to init panic-versions of the GPIO and the UART. The panic versions are not protected -/// with synchronization primitives, which increases chances that we get to print something, even -/// when the kernel's default GPIO or UART instances happen to be locked at the time of the panic. -/// -/// # Safety -/// -/// - Use only for printing during a panic. -pub unsafe fn panic_console_out() -> impl fmt::Write { - let mut panic_gpio = device_driver::PanicGPIO::new(memory::map::mmio::GPIO_START); - let mut panic_uart = device_driver::PanicUart::new(memory::map::mmio::PL011_UART_START); - - panic_gpio.map_pl011_uart(); - panic_uart.init(); - panic_uart -} - /// Return a reference to the console. -pub fn console() -> &'static impl console::interface::All { - &super::PL011_UART +pub fn console() -> &'static dyn console::interface::All { + &super::driver::PL011_UART } diff --git a/10_virtual_mem_part1_identity_mapping/src/bsp/raspberrypi/driver.rs b/10_virtual_mem_part1_identity_mapping/src/bsp/raspberrypi/driver.rs index b5538baa..8b683ed8 100644 --- a/10_virtual_mem_part1_identity_mapping/src/bsp/raspberrypi/driver.rs +++ b/10_virtual_mem_part1_identity_mapping/src/bsp/raspberrypi/driver.rs @@ -4,7 +4,8 @@ //! BSP driver support. -use crate::driver; +use super::memory::map::mmio; +use crate::{bsp::device_driver, driver}; //-------------------------------------------------------------------------------------------------- // Private Definitions @@ -19,8 +20,13 @@ struct BSPDriverManager { // Global instances //-------------------------------------------------------------------------------------------------- +pub(super) static PL011_UART: device_driver::PL011Uart = + unsafe { device_driver::PL011Uart::new(mmio::PL011_UART_START) }; + +static GPIO: device_driver::GPIO = unsafe { device_driver::GPIO::new(mmio::GPIO_START) }; + static BSP_DRIVER_MANAGER: BSPDriverManager = BSPDriverManager { - device_drivers: [&super::GPIO, &super::PL011_UART], + device_drivers: [&PL011_UART, &GPIO], }; //-------------------------------------------------------------------------------------------------- @@ -44,6 +50,6 @@ impl driver::interface::DriverManager for BSPDriverManager { fn post_device_driver_init(&self) { // Configure PL011Uart's output pins. - super::GPIO.map_pl011_uart(); + GPIO.map_pl011_uart(); } } diff --git a/10_virtual_mem_part1_identity_mapping/src/console.rs b/10_virtual_mem_part1_identity_mapping/src/console.rs index e49e241f..c1fb0e53 100644 --- a/10_virtual_mem_part1_identity_mapping/src/console.rs +++ b/10_virtual_mem_part1_identity_mapping/src/console.rs @@ -4,6 +4,8 @@ //! System console. +use crate::bsp; + //-------------------------------------------------------------------------------------------------- // Public Definitions //-------------------------------------------------------------------------------------------------- @@ -49,5 +51,16 @@ pub mod interface { } /// Trait alias for a full-fledged console. - pub trait All = Write + Read + Statistics; + pub trait All: Write + Read + Statistics {} +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +/// Return a reference to the console. +/// +/// This is the global console used by all printing macros. +pub fn console() -> &'static dyn interface::All { + bsp::console::console() } diff --git a/10_virtual_mem_part1_identity_mapping/src/main.rs b/10_virtual_mem_part1_identity_mapping/src/main.rs index dde224e7..6f92c676 100644 --- a/10_virtual_mem_part1_identity_mapping/src/main.rs +++ b/10_virtual_mem_part1_identity_mapping/src/main.rs @@ -158,8 +158,7 @@ unsafe fn kernel_init() -> ! { /// The main function running after the early init. fn kernel_main() -> ! { - use bsp::console::console; - use console::interface::All; + use console::{console, interface::Write}; use core::time::Duration; use driver::interface::DriverManager; use time::interface::TimeManager; @@ -209,7 +208,7 @@ fn kernel_main() -> ! { // Discard any spurious received characters before going into echo mode. console().clear_rx(); loop { - let c = bsp::console::console().read_char(); - bsp::console::console().write_char(c); + let c = console().read_char(); + console().write_char(c); } } diff --git a/10_virtual_mem_part1_identity_mapping/src/panic_wait.rs b/10_virtual_mem_part1_identity_mapping/src/panic_wait.rs index f851e0d8..edd83885 100644 --- a/10_virtual_mem_part1_identity_mapping/src/panic_wait.rs +++ b/10_virtual_mem_part1_identity_mapping/src/panic_wait.rs @@ -4,29 +4,13 @@ //! A panic handler that infinitely waits. -use crate::{bsp, cpu}; -use core::{fmt, panic::PanicInfo}; +use crate::{cpu, println}; +use core::panic::PanicInfo; //-------------------------------------------------------------------------------------------------- // Private Code //-------------------------------------------------------------------------------------------------- -fn _panic_print(args: fmt::Arguments) { - use fmt::Write; - - unsafe { bsp::console::panic_console_out().write_fmt(args).unwrap() }; -} - -/// Prints with a newline - only use from the panic handler. -/// -/// Carbon copy from -#[macro_export] -macro_rules! panic_println { - ($($arg:tt)*) => ({ - _panic_print(format_args_nl!($($arg)*)); - }) -} - /// Stop immediately if called a second time. /// /// # Note @@ -69,7 +53,7 @@ fn panic(info: &PanicInfo) -> ! { _ => ("???", 0, 0), }; - panic_println!( + println!( "[ {:>3}.{:06}] Kernel panic!\n\n\ Panic location:\n File '{}', line {}, column {}\n\n\ {}", diff --git a/10_virtual_mem_part1_identity_mapping/src/print.rs b/10_virtual_mem_part1_identity_mapping/src/print.rs index 9ec13a28..8705eec0 100644 --- a/10_virtual_mem_part1_identity_mapping/src/print.rs +++ b/10_virtual_mem_part1_identity_mapping/src/print.rs @@ -4,7 +4,7 @@ //! Printing. -use crate::{bsp, console}; +use crate::console; use core::fmt; //-------------------------------------------------------------------------------------------------- @@ -13,9 +13,7 @@ use core::fmt; #[doc(hidden)] pub fn _print(args: fmt::Arguments) { - use console::interface::Write; - - bsp::console::console().write_fmt(args).unwrap(); + console::console().write_fmt(args).unwrap(); } /// Prints without a newline. diff --git a/11_exceptions_part1_groundwork/README.md b/11_exceptions_part1_groundwork/README.md index 81e633be..355ea297 100644 --- a/11_exceptions_part1_groundwork/README.md +++ b/11_exceptions_part1_groundwork/README.md @@ -417,31 +417,31 @@ Minipush 1.0 [MP] ⏩ Pushing 64 KiB =========================================🦀 100% 0 KiB/s Time: 00:00:00 [ML] Loaded! Executing the payload now -[ 0.787414] mingo version 0.11.0 -[ 0.787621] Booting on: Raspberry Pi 3 -[ 0.788076] MMU online. Special regions: -[ 0.788553] 0x00080000 - 0x0008ffff | 64 KiB | C RO PX | Kernel code and RO data -[ 0.789571] 0x3f000000 - 0x4000ffff | 16 MiB | Dev RW PXN | Device MMIO -[ 0.790460] Current privilege level: EL1 -[ 0.790936] Exception handling state: -[ 0.791380] Debug: Masked -[ 0.791770] SError: Masked -[ 0.792160] IRQ: Masked -[ 0.792550] FIQ: Masked -[ 0.792940] Architectural timer resolution: 52 ns -[ 0.793514] Drivers loaded: -[ 0.793850] 1. BCM GPIO -[ 0.794208] 2. BCM PL011 UART -[ 0.794630] Timer test, spinning for 1 second -[ 1.795161] -[ 1.795165] Trying to read from address 8 GiB... -[ 1.795715] ************************************************ -[ 1.796407] Whoa! We recovered from a synchronous exception! -[ 1.797100] ************************************************ -[ 1.797794] -[ 1.797967] Let's try again -[ 1.798303] Trying to read from address 9 GiB... -[ 1.798867] Kernel panic! +[ 0.798323] mingo version 0.11.0 +[ 0.798530] Booting on: Raspberry Pi 3 +[ 0.798985] MMU online. Special regions: +[ 0.799462] 0x00080000 - 0x0008ffff | 64 KiB | C RO PX | Kernel code and RO data +[ 0.800480] 0x3f000000 - 0x4000ffff | 16 MiB | Dev RW PXN | Device MMIO +[ 0.801369] Current privilege level: EL1 +[ 0.801845] Exception handling state: +[ 0.802290] Debug: Masked +[ 0.802680] SError: Masked +[ 0.803069] IRQ: Masked +[ 0.803459] FIQ: Masked +[ 0.803849] Architectural timer resolution: 52 ns +[ 0.804423] Drivers loaded: +[ 0.804759] 1. BCM PL011 UART +[ 0.805182] 2. BCM GPIO +[ 0.805539] Timer test, spinning for 1 second +[ 1.806070] +[ 1.806074] Trying to read from address 8 GiB... +[ 1.806624] ************************************************ +[ 1.807316] Whoa! We recovered from a synchronous exception! +[ 1.808009] ************************************************ +[ 1.808703] +[ 1.808876] Let's try again +[ 1.809212] Trying to read from address 9 GiB... +[ 1.809776] Kernel panic! Panic location: File 'src/_arch/aarch64/exception.rs', line 58, column 5 @@ -464,25 +464,25 @@ SPSR_EL1: 0x600003c5 IRQ (I): Masked FIQ (F): Masked Illegal Execution State (IL): Not set -ELR_EL1: 0x0000000000082194 +ELR_EL1: 0x00000000000845f8 General purpose register: - x0 : 0x0000000000000000 x1 : 0x0000000000085517 - x2 : 0x0000000000000027 x3 : 0x0000000000084380 - x4 : 0x0000000000000006 x5 : 0xfb5f341800000000 - x6 : 0x0000000000000000 x7 : 0x7f91bc012b2b0209 - x8 : 0x0000000240000000 x9 : 0x0000000000085517 + x0 : 0x0000000000000000 x1 : 0x0000000000086187 + x2 : 0x0000000000000027 x3 : 0x0000000000081280 + x4 : 0x0000000000000006 x5 : 0x1e27329c00000000 + x6 : 0x0000000000000000 x7 : 0xd3d18908028f0243 + x8 : 0x0000000240000000 x9 : 0x0000000000086187 x10: 0x0000000000000443 x11: 0x000000003f201000 x12: 0x0000000000000019 x13: 0x00000000ffffd8f0 x14: 0x000000000000147b x15: 0x00000000ffffff9c x16: 0x000000000007fd38 x17: 0x0000000005f5e0ff - x18: 0x0000000000000030 x19: 0x0000000000090008 - x20: 0x0000000000085350 x21: 0x000000003b9aca00 - x22: 0x0000000000082e4c x23: 0x0000000000082308 + x18: 0x00000000000c58fc x19: 0x0000000000090008 + x20: 0x0000000000085fc0 x21: 0x000000003b9aca00 + x22: 0x0000000000082238 x23: 0x00000000000813d4 x24: 0x0000000010624dd3 x25: 0xffffffffc4653600 - x26: 0x0000000000086638 x27: 0x0000000000085410 - x28: 0x0000000000084f90 x29: 0x0000000000086538 - lr : 0x0000000000082188 + x26: 0x0000000000086988 x27: 0x0000000000086080 + x28: 0x0000000000085f10 x29: 0x0000000000085c00 + lr : 0x00000000000845ec ``` ## Diff to previous @@ -1033,7 +1033,16 @@ diff -uNr 10_virtual_mem_part1_identity_mapping/src/main.rs 11_exceptions_part1_ if let Err(string) = memory::mmu::mmu().enable_mmu_and_caching() { panic!("MMU: {}", string); } -@@ -197,13 +199,28 @@ +@@ -158,7 +160,7 @@ + + /// The main function running after the early init. + fn kernel_main() -> ! { +- use console::{console, interface::Write}; ++ use console::console; + use core::time::Duration; + use driver::interface::DriverManager; + use time::interface::TimeManager; +@@ -196,13 +198,28 @@ info!("Timer test, spinning for 1 second"); time::time_manager().spin_for(Duration::from_secs(1)); diff --git a/11_exceptions_part1_groundwork/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs b/11_exceptions_part1_groundwork/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs index dbb4beaa..24958eb5 100644 --- a/11_exceptions_part1_groundwork/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs +++ b/11_exceptions_part1_groundwork/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs @@ -108,16 +108,13 @@ register_structs! { /// Abstraction for the associated MMIO registers. type Registers = MMIODerefWrapper; -//-------------------------------------------------------------------------------------------------- -// Public Definitions -//-------------------------------------------------------------------------------------------------- - -pub struct GPIOInner { +struct GPIOInner { registers: Registers, } -// Export the inner struct so that BSPs can use it for the panic handler. -pub use GPIOInner as PanicGPIO; +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- /// Representation of the GPIO HW. pub struct GPIO { @@ -125,7 +122,7 @@ pub struct GPIO { } //-------------------------------------------------------------------------------------------------- -// Public Code +// Private Code //-------------------------------------------------------------------------------------------------- impl GPIOInner { @@ -189,7 +186,13 @@ impl GPIOInner { } } +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + impl GPIO { + pub const COMPATIBLE: &'static str = "BCM GPIO"; + /// Create an instance. /// /// # Safety @@ -214,6 +217,6 @@ use synchronization::interface::Mutex; impl driver::interface::DeviceDriver for GPIO { fn compatible(&self) -> &'static str { - "BCM GPIO" + Self::COMPATIBLE } } diff --git a/11_exceptions_part1_groundwork/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs b/11_exceptions_part1_groundwork/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs index 85cd3154..b034e92e 100644 --- a/11_exceptions_part1_groundwork/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs +++ b/11_exceptions_part1_groundwork/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs @@ -167,18 +167,15 @@ enum BlockingMode { NonBlocking, } -//-------------------------------------------------------------------------------------------------- -// Public Definitions -//-------------------------------------------------------------------------------------------------- - -pub struct PL011UartInner { +struct PL011UartInner { registers: Registers, chars_written: usize, chars_read: usize, } -// Export the inner struct so that BSPs can use it for the panic handler. -pub use PL011UartInner as PanicUart; +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- /// Representation of the UART. pub struct PL011Uart { @@ -186,7 +183,7 @@ pub struct PL011Uart { } //-------------------------------------------------------------------------------------------------- -// Public Code +// Private Code //-------------------------------------------------------------------------------------------------- impl PL011UartInner { @@ -326,7 +323,13 @@ impl fmt::Write for PL011UartInner { } } +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + impl PL011Uart { + pub const COMPATIBLE: &'static str = "BCM PL011 UART"; + /// Create an instance. /// /// # Safety @@ -346,7 +349,7 @@ use synchronization::interface::Mutex; impl driver::interface::DeviceDriver for PL011Uart { fn compatible(&self) -> &'static str { - "BCM PL011 UART" + Self::COMPATIBLE } unsafe fn init(&self) -> Result<(), &'static str> { @@ -400,3 +403,5 @@ impl console::interface::Statistics for PL011Uart { self.inner.lock(|inner| inner.chars_read) } } + +impl console::interface::All for PL011Uart {} diff --git a/11_exceptions_part1_groundwork/src/bsp/raspberrypi.rs b/11_exceptions_part1_groundwork/src/bsp/raspberrypi.rs index 22edb4fa..a9a7261a 100644 --- a/11_exceptions_part1_groundwork/src/bsp/raspberrypi.rs +++ b/11_exceptions_part1_groundwork/src/bsp/raspberrypi.rs @@ -9,17 +9,6 @@ pub mod cpu; pub mod driver; pub mod memory; -//-------------------------------------------------------------------------------------------------- -// Global instances -//-------------------------------------------------------------------------------------------------- -use super::device_driver; - -static GPIO: device_driver::GPIO = - unsafe { device_driver::GPIO::new(memory::map::mmio::GPIO_START) }; - -static PL011_UART: device_driver::PL011Uart = - unsafe { device_driver::PL011Uart::new(memory::map::mmio::PL011_UART_START) }; - //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- diff --git a/11_exceptions_part1_groundwork/src/bsp/raspberrypi/console.rs b/11_exceptions_part1_groundwork/src/bsp/raspberrypi/console.rs index a247032f..0a630eef 100644 --- a/11_exceptions_part1_groundwork/src/bsp/raspberrypi/console.rs +++ b/11_exceptions_part1_groundwork/src/bsp/raspberrypi/console.rs @@ -4,34 +4,13 @@ //! BSP console facilities. -use super::memory; -use crate::{bsp::device_driver, console}; -use core::fmt; +use crate::console; //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- -/// In case of a panic, the panic handler uses this function to take a last shot at printing -/// something before the system is halted. -/// -/// We try to init panic-versions of the GPIO and the UART. The panic versions are not protected -/// with synchronization primitives, which increases chances that we get to print something, even -/// when the kernel's default GPIO or UART instances happen to be locked at the time of the panic. -/// -/// # Safety -/// -/// - Use only for printing during a panic. -pub unsafe fn panic_console_out() -> impl fmt::Write { - let mut panic_gpio = device_driver::PanicGPIO::new(memory::map::mmio::GPIO_START); - let mut panic_uart = device_driver::PanicUart::new(memory::map::mmio::PL011_UART_START); - - panic_gpio.map_pl011_uart(); - panic_uart.init(); - panic_uart -} - /// Return a reference to the console. -pub fn console() -> &'static impl console::interface::All { - &super::PL011_UART +pub fn console() -> &'static dyn console::interface::All { + &super::driver::PL011_UART } diff --git a/11_exceptions_part1_groundwork/src/bsp/raspberrypi/driver.rs b/11_exceptions_part1_groundwork/src/bsp/raspberrypi/driver.rs index b5538baa..8b683ed8 100644 --- a/11_exceptions_part1_groundwork/src/bsp/raspberrypi/driver.rs +++ b/11_exceptions_part1_groundwork/src/bsp/raspberrypi/driver.rs @@ -4,7 +4,8 @@ //! BSP driver support. -use crate::driver; +use super::memory::map::mmio; +use crate::{bsp::device_driver, driver}; //-------------------------------------------------------------------------------------------------- // Private Definitions @@ -19,8 +20,13 @@ struct BSPDriverManager { // Global instances //-------------------------------------------------------------------------------------------------- +pub(super) static PL011_UART: device_driver::PL011Uart = + unsafe { device_driver::PL011Uart::new(mmio::PL011_UART_START) }; + +static GPIO: device_driver::GPIO = unsafe { device_driver::GPIO::new(mmio::GPIO_START) }; + static BSP_DRIVER_MANAGER: BSPDriverManager = BSPDriverManager { - device_drivers: [&super::GPIO, &super::PL011_UART], + device_drivers: [&PL011_UART, &GPIO], }; //-------------------------------------------------------------------------------------------------- @@ -44,6 +50,6 @@ impl driver::interface::DriverManager for BSPDriverManager { fn post_device_driver_init(&self) { // Configure PL011Uart's output pins. - super::GPIO.map_pl011_uart(); + GPIO.map_pl011_uart(); } } diff --git a/11_exceptions_part1_groundwork/src/console.rs b/11_exceptions_part1_groundwork/src/console.rs index e49e241f..c1fb0e53 100644 --- a/11_exceptions_part1_groundwork/src/console.rs +++ b/11_exceptions_part1_groundwork/src/console.rs @@ -4,6 +4,8 @@ //! System console. +use crate::bsp; + //-------------------------------------------------------------------------------------------------- // Public Definitions //-------------------------------------------------------------------------------------------------- @@ -49,5 +51,16 @@ pub mod interface { } /// Trait alias for a full-fledged console. - pub trait All = Write + Read + Statistics; + pub trait All: Write + Read + Statistics {} +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +/// Return a reference to the console. +/// +/// This is the global console used by all printing macros. +pub fn console() -> &'static dyn interface::All { + bsp::console::console() } diff --git a/11_exceptions_part1_groundwork/src/main.rs b/11_exceptions_part1_groundwork/src/main.rs index 96743601..12386153 100644 --- a/11_exceptions_part1_groundwork/src/main.rs +++ b/11_exceptions_part1_groundwork/src/main.rs @@ -160,8 +160,7 @@ unsafe fn kernel_init() -> ! { /// The main function running after the early init. fn kernel_main() -> ! { - use bsp::console::console; - use console::interface::All; + use console::console; use core::time::Duration; use driver::interface::DriverManager; use time::interface::TimeManager; @@ -226,7 +225,7 @@ fn kernel_main() -> ! { // Discard any spurious received characters before going into echo mode. console().clear_rx(); loop { - let c = bsp::console::console().read_char(); - bsp::console::console().write_char(c); + let c = console().read_char(); + console().write_char(c); } } diff --git a/11_exceptions_part1_groundwork/src/panic_wait.rs b/11_exceptions_part1_groundwork/src/panic_wait.rs index f851e0d8..edd83885 100644 --- a/11_exceptions_part1_groundwork/src/panic_wait.rs +++ b/11_exceptions_part1_groundwork/src/panic_wait.rs @@ -4,29 +4,13 @@ //! A panic handler that infinitely waits. -use crate::{bsp, cpu}; -use core::{fmt, panic::PanicInfo}; +use crate::{cpu, println}; +use core::panic::PanicInfo; //-------------------------------------------------------------------------------------------------- // Private Code //-------------------------------------------------------------------------------------------------- -fn _panic_print(args: fmt::Arguments) { - use fmt::Write; - - unsafe { bsp::console::panic_console_out().write_fmt(args).unwrap() }; -} - -/// Prints with a newline - only use from the panic handler. -/// -/// Carbon copy from -#[macro_export] -macro_rules! panic_println { - ($($arg:tt)*) => ({ - _panic_print(format_args_nl!($($arg)*)); - }) -} - /// Stop immediately if called a second time. /// /// # Note @@ -69,7 +53,7 @@ fn panic(info: &PanicInfo) -> ! { _ => ("???", 0, 0), }; - panic_println!( + println!( "[ {:>3}.{:06}] Kernel panic!\n\n\ Panic location:\n File '{}', line {}, column {}\n\n\ {}", diff --git a/11_exceptions_part1_groundwork/src/print.rs b/11_exceptions_part1_groundwork/src/print.rs index 9ec13a28..8705eec0 100644 --- a/11_exceptions_part1_groundwork/src/print.rs +++ b/11_exceptions_part1_groundwork/src/print.rs @@ -4,7 +4,7 @@ //! Printing. -use crate::{bsp, console}; +use crate::console; use core::fmt; //-------------------------------------------------------------------------------------------------- @@ -13,9 +13,7 @@ use core::fmt; #[doc(hidden)] pub fn _print(args: fmt::Arguments) { - use console::interface::Write; - - bsp::console::console().write_fmt(args).unwrap(); + console::console().write_fmt(args).unwrap(); } /// Prints without a newline. diff --git a/12_integrated_testing/README.md b/12_integrated_testing/README.md index 14dc3878..e0d0dd1d 100644 --- a/12_integrated_testing/README.md +++ b/12_integrated_testing/README.md @@ -266,8 +266,10 @@ implementation in `lib.rs`: #[cfg(test)] #[no_mangle] unsafe fn kernel_init() -> ! { + use driver::interface::DriverManager; + exception::handling_init(); - bsp::console::qemu_bring_up_console(); + bsp::driver::driver_manager().qemu_bring_up_console(); test_main(); @@ -275,12 +277,12 @@ unsafe fn kernel_init() -> ! { } ``` -Note the call to `bsp::console::qemu_bring_up_console()`. Since we are running all our tests inside -`QEMU`, we need to ensure that whatever peripheral implements the kernel's `console` interface is -initialized, so that we can print from our tests. If you recall [tutorial 03], bringing up -peripherals in `QEMU` might not need the full initialization as is needed on real hardware (setting -clocks, config registers, etc...) due to the abstractions in `QEMU`'s emulation code. So this is an -opportunity to cut down on setup code. +Note the call to `bsp::driver::driver_manager().qemu_bring_up_console()`. Since we are running all +our tests inside `QEMU`, we need to ensure that whatever peripheral implements the kernel's +`console` interface is initialized, so that we can print from our tests. If you recall [tutorial +03], bringing up peripherals in `QEMU` might not need the full initialization as is needed on real +hardware (setting clocks, config registers, etc...) due to the abstractions in `QEMU`'s emulation +code. So this is an opportunity to cut down on setup code. [tutorial 03]: ../03_hacky_hello_world @@ -620,13 +622,15 @@ your test code into individual chunks. For example, take a look at `tests/01_tim #![test_runner(libkernel::test_runner)] use core::time::Duration; -use libkernel::{bsp, cpu, exception, time, time::interface::TimeManager}; +use libkernel::{bsp, cpu, driver, exception, time, time::interface::TimeManager}; use test_macros::kernel_test; #[no_mangle] unsafe fn kernel_init() -> ! { + use driver::interface::DriverManager; + exception::handling_init(); - bsp::console::qemu_bring_up_console(); + bsp::driver::driver_manager().qemu_bring_up_console(); // Depending on CPU arch, some timer bring-up code could go here. Not needed for the RPi. @@ -714,14 +718,15 @@ so the wanted outcome is a `panic!`. Here is the whole test (minus some inline c mod panic_exit_success; -use libkernel::{bsp, cpu, exception, memory, println}; +use libkernel::{bsp, cpu, driver, exception, info, memory, println}; #[no_mangle] unsafe fn kernel_init() -> ! { + use driver::interface::DriverManager; use memory::mmu::interface::MMU; exception::handling_init(); - bsp::console::qemu_bring_up_console(); + bsp::driver::driver_manager().qemu_bring_up_console(); // This line will be printed as the test header. println!("Testing synchronous exception handling by causing a page fault"); @@ -788,15 +793,15 @@ The subtest first sends `"ABC"` over the console to the kernel, and then expects /// Console tests should time out on the I/O harness in case of panic. mod panic_wait_forever; -use libkernel::{bsp, console, cpu, exception, print}; +use libkernel::{bsp, console, cpu, driver, exception, print}; #[no_mangle] unsafe fn kernel_init() -> ! { - use bsp::console::console; - use console::interface::*; + use console::console; + use driver::interface::DriverManager; exception::handling_init(); - bsp::console::qemu_bring_up_console(); + bsp::driver::driver_manager().qemu_bring_up_console(); // Handshake assert_eq!(console().read_char(), 'A'); diff --git a/12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs b/12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs index dbb4beaa..24958eb5 100644 --- a/12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs +++ b/12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs @@ -108,16 +108,13 @@ register_structs! { /// Abstraction for the associated MMIO registers. type Registers = MMIODerefWrapper; -//-------------------------------------------------------------------------------------------------- -// Public Definitions -//-------------------------------------------------------------------------------------------------- - -pub struct GPIOInner { +struct GPIOInner { registers: Registers, } -// Export the inner struct so that BSPs can use it for the panic handler. -pub use GPIOInner as PanicGPIO; +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- /// Representation of the GPIO HW. pub struct GPIO { @@ -125,7 +122,7 @@ pub struct GPIO { } //-------------------------------------------------------------------------------------------------- -// Public Code +// Private Code //-------------------------------------------------------------------------------------------------- impl GPIOInner { @@ -189,7 +186,13 @@ impl GPIOInner { } } +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + impl GPIO { + pub const COMPATIBLE: &'static str = "BCM GPIO"; + /// Create an instance. /// /// # Safety @@ -214,6 +217,6 @@ use synchronization::interface::Mutex; impl driver::interface::DeviceDriver for GPIO { fn compatible(&self) -> &'static str { - "BCM GPIO" + Self::COMPATIBLE } } diff --git a/12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs b/12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs index 85cd3154..b034e92e 100644 --- a/12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs +++ b/12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs @@ -167,18 +167,15 @@ enum BlockingMode { NonBlocking, } -//-------------------------------------------------------------------------------------------------- -// Public Definitions -//-------------------------------------------------------------------------------------------------- - -pub struct PL011UartInner { +struct PL011UartInner { registers: Registers, chars_written: usize, chars_read: usize, } -// Export the inner struct so that BSPs can use it for the panic handler. -pub use PL011UartInner as PanicUart; +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- /// Representation of the UART. pub struct PL011Uart { @@ -186,7 +183,7 @@ pub struct PL011Uart { } //-------------------------------------------------------------------------------------------------- -// Public Code +// Private Code //-------------------------------------------------------------------------------------------------- impl PL011UartInner { @@ -326,7 +323,13 @@ impl fmt::Write for PL011UartInner { } } +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + impl PL011Uart { + pub const COMPATIBLE: &'static str = "BCM PL011 UART"; + /// Create an instance. /// /// # Safety @@ -346,7 +349,7 @@ use synchronization::interface::Mutex; impl driver::interface::DeviceDriver for PL011Uart { fn compatible(&self) -> &'static str { - "BCM PL011 UART" + Self::COMPATIBLE } unsafe fn init(&self) -> Result<(), &'static str> { @@ -400,3 +403,5 @@ impl console::interface::Statistics for PL011Uart { self.inner.lock(|inner| inner.chars_read) } } + +impl console::interface::All for PL011Uart {} diff --git a/12_integrated_testing/kernel/src/bsp/raspberrypi.rs b/12_integrated_testing/kernel/src/bsp/raspberrypi.rs index 22edb4fa..a9a7261a 100644 --- a/12_integrated_testing/kernel/src/bsp/raspberrypi.rs +++ b/12_integrated_testing/kernel/src/bsp/raspberrypi.rs @@ -9,17 +9,6 @@ pub mod cpu; pub mod driver; pub mod memory; -//-------------------------------------------------------------------------------------------------- -// Global instances -//-------------------------------------------------------------------------------------------------- -use super::device_driver; - -static GPIO: device_driver::GPIO = - unsafe { device_driver::GPIO::new(memory::map::mmio::GPIO_START) }; - -static PL011_UART: device_driver::PL011Uart = - unsafe { device_driver::PL011Uart::new(memory::map::mmio::PL011_UART_START) }; - //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- diff --git a/12_integrated_testing/kernel/src/bsp/raspberrypi/console.rs b/12_integrated_testing/kernel/src/bsp/raspberrypi/console.rs index eaef0b1f..0a630eef 100644 --- a/12_integrated_testing/kernel/src/bsp/raspberrypi/console.rs +++ b/12_integrated_testing/kernel/src/bsp/raspberrypi/console.rs @@ -4,45 +4,13 @@ //! BSP console facilities. -use super::memory; -use crate::{bsp::device_driver, console}; -use core::fmt; +use crate::console; //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- -/// In case of a panic, the panic handler uses this function to take a last shot at printing -/// something before the system is halted. -/// -/// We try to init panic-versions of the GPIO and the UART. The panic versions are not protected -/// with synchronization primitives, which increases chances that we get to print something, even -/// when the kernel's default GPIO or UART instances happen to be locked at the time of the panic. -/// -/// # Safety -/// -/// - Use only for printing during a panic. -pub unsafe fn panic_console_out() -> impl fmt::Write { - let mut panic_gpio = device_driver::PanicGPIO::new(memory::map::mmio::GPIO_START); - let mut panic_uart = device_driver::PanicUart::new(memory::map::mmio::PL011_UART_START); - - panic_gpio.map_pl011_uart(); - panic_uart.init(); - panic_uart -} - /// Return a reference to the console. -pub fn console() -> &'static impl console::interface::All { - &super::PL011_UART +pub fn console() -> &'static dyn console::interface::All { + &super::driver::PL011_UART } - -//-------------------------------------------------------------------------------------------------- -// Testing -//-------------------------------------------------------------------------------------------------- - -/// Minimal code needed to bring up the console in QEMU (for testing only). This is often less steps -/// than on real hardware due to QEMU's abstractions. -/// -/// For the RPi, nothing needs to be done. -#[cfg(feature = "test_build")] -pub fn qemu_bring_up_console() {} diff --git a/12_integrated_testing/kernel/src/bsp/raspberrypi/driver.rs b/12_integrated_testing/kernel/src/bsp/raspberrypi/driver.rs index b5538baa..f8acd335 100644 --- a/12_integrated_testing/kernel/src/bsp/raspberrypi/driver.rs +++ b/12_integrated_testing/kernel/src/bsp/raspberrypi/driver.rs @@ -4,7 +4,8 @@ //! BSP driver support. -use crate::driver; +use super::memory::map::mmio; +use crate::{bsp::device_driver, driver}; //-------------------------------------------------------------------------------------------------- // Private Definitions @@ -19,8 +20,13 @@ struct BSPDriverManager { // Global instances //-------------------------------------------------------------------------------------------------- +pub(super) static PL011_UART: device_driver::PL011Uart = + unsafe { device_driver::PL011Uart::new(mmio::PL011_UART_START) }; + +static GPIO: device_driver::GPIO = unsafe { device_driver::GPIO::new(mmio::GPIO_START) }; + static BSP_DRIVER_MANAGER: BSPDriverManager = BSPDriverManager { - device_drivers: [&super::GPIO, &super::PL011_UART], + device_drivers: [&PL011_UART, &GPIO], }; //-------------------------------------------------------------------------------------------------- @@ -44,6 +50,9 @@ impl driver::interface::DriverManager for BSPDriverManager { fn post_device_driver_init(&self) { // Configure PL011Uart's output pins. - super::GPIO.map_pl011_uart(); + GPIO.map_pl011_uart(); } + + #[cfg(feature = "test_build")] + fn qemu_bring_up_console(&self) {} } diff --git a/12_integrated_testing/kernel/src/console.rs b/12_integrated_testing/kernel/src/console.rs index e49e241f..c1fb0e53 100644 --- a/12_integrated_testing/kernel/src/console.rs +++ b/12_integrated_testing/kernel/src/console.rs @@ -4,6 +4,8 @@ //! System console. +use crate::bsp; + //-------------------------------------------------------------------------------------------------- // Public Definitions //-------------------------------------------------------------------------------------------------- @@ -49,5 +51,16 @@ pub mod interface { } /// Trait alias for a full-fledged console. - pub trait All = Write + Read + Statistics; + pub trait All: Write + Read + Statistics {} +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +/// Return a reference to the console. +/// +/// This is the global console used by all printing macros. +pub fn console() -> &'static dyn interface::All { + bsp::console::console() } diff --git a/12_integrated_testing/kernel/src/driver.rs b/12_integrated_testing/kernel/src/driver.rs index 2fcc7562..12d60ad4 100644 --- a/12_integrated_testing/kernel/src/driver.rs +++ b/12_integrated_testing/kernel/src/driver.rs @@ -40,5 +40,10 @@ pub mod interface { /// /// For example, device driver code that depends on other drivers already being online. fn post_device_driver_init(&self); + + /// Minimal code needed to bring up the console in QEMU (for testing only). This is often + /// less steps than on real hardware due to QEMU's abstractions. + #[cfg(feature = "test_build")] + fn qemu_bring_up_console(&self); } } diff --git a/12_integrated_testing/kernel/src/lib.rs b/12_integrated_testing/kernel/src/lib.rs index 2de7d6cc..eef112f0 100644 --- a/12_integrated_testing/kernel/src/lib.rs +++ b/12_integrated_testing/kernel/src/lib.rs @@ -177,8 +177,10 @@ pub fn test_runner(tests: &[&test_types::UnitTest]) { #[cfg(test)] #[no_mangle] unsafe fn kernel_init() -> ! { + use driver::interface::DriverManager; + exception::handling_init(); - bsp::console::qemu_bring_up_console(); + bsp::driver::driver_manager().qemu_bring_up_console(); test_main(); diff --git a/12_integrated_testing/kernel/src/main.rs b/12_integrated_testing/kernel/src/main.rs index 11b6547d..bf4d7fe3 100644 --- a/12_integrated_testing/kernel/src/main.rs +++ b/12_integrated_testing/kernel/src/main.rs @@ -49,8 +49,7 @@ unsafe fn kernel_init() -> ! { /// The main function running after the early init. fn kernel_main() -> ! { - use bsp::console::console; - use console::interface::All; + use console::console; use driver::interface::DriverManager; info!("{}", libkernel::version()); @@ -84,7 +83,7 @@ fn kernel_main() -> ! { // Discard any spurious received characters before going into echo mode. console().clear_rx(); loop { - let c = bsp::console::console().read_char(); - bsp::console::console().write_char(c); + let c = console().read_char(); + console().write_char(c); } } diff --git a/12_integrated_testing/kernel/src/panic_wait.rs b/12_integrated_testing/kernel/src/panic_wait.rs index 6f09f11c..8bedfded 100644 --- a/12_integrated_testing/kernel/src/panic_wait.rs +++ b/12_integrated_testing/kernel/src/panic_wait.rs @@ -4,19 +4,13 @@ //! A panic handler that infinitely waits. -use crate::{bsp, cpu}; -use core::{fmt, panic::PanicInfo}; +use crate::{cpu, println}; +use core::panic::PanicInfo; //-------------------------------------------------------------------------------------------------- // Private Code //-------------------------------------------------------------------------------------------------- -fn _panic_print(args: fmt::Arguments) { - use fmt::Write; - - unsafe { bsp::console::panic_console_out().write_fmt(args).unwrap() }; -} - /// The point of exit for `libkernel`. /// /// It is linked weakly, so that the integration tests can overload its standard behavior. @@ -34,16 +28,6 @@ fn _panic_exit() -> ! { } } -/// Prints with a newline - only use from the panic handler. -/// -/// Carbon copy from -#[macro_export] -macro_rules! panic_println { - ($($arg:tt)*) => ({ - _panic_print(format_args_nl!($($arg)*)); - }) -} - /// Stop immediately if called a second time. /// /// # Note @@ -86,7 +70,7 @@ fn panic(info: &PanicInfo) -> ! { _ => ("???", 0, 0), }; - panic_println!( + println!( "[ {:>3}.{:06}] Kernel panic!\n\n\ Panic location:\n File '{}', line {}, column {}\n\n\ {}", diff --git a/12_integrated_testing/kernel/src/print.rs b/12_integrated_testing/kernel/src/print.rs index 9ec13a28..8705eec0 100644 --- a/12_integrated_testing/kernel/src/print.rs +++ b/12_integrated_testing/kernel/src/print.rs @@ -4,7 +4,7 @@ //! Printing. -use crate::{bsp, console}; +use crate::console; use core::fmt; //-------------------------------------------------------------------------------------------------- @@ -13,9 +13,7 @@ use core::fmt; #[doc(hidden)] pub fn _print(args: fmt::Arguments) { - use console::interface::Write; - - bsp::console::console().write_fmt(args).unwrap(); + console::console().write_fmt(args).unwrap(); } /// Prints without a newline. diff --git a/12_integrated_testing/kernel/tests/00_console_sanity.rs b/12_integrated_testing/kernel/tests/00_console_sanity.rs index dccb6cc2..e12a711f 100644 --- a/12_integrated_testing/kernel/tests/00_console_sanity.rs +++ b/12_integrated_testing/kernel/tests/00_console_sanity.rs @@ -11,15 +11,15 @@ /// Console tests should time out on the I/O harness in case of panic. mod panic_wait_forever; -use libkernel::{bsp, console, cpu, exception, print}; +use libkernel::{bsp, console, cpu, driver, exception, print}; #[no_mangle] unsafe fn kernel_init() -> ! { - use bsp::console::console; - use console::interface::*; + use console::console; + use driver::interface::DriverManager; exception::handling_init(); - bsp::console::qemu_bring_up_console(); + bsp::driver::driver_manager().qemu_bring_up_console(); // Handshake assert_eq!(console().read_char(), 'A'); diff --git a/12_integrated_testing/kernel/tests/01_timer_sanity.rs b/12_integrated_testing/kernel/tests/01_timer_sanity.rs index 59ef4a7f..390cdee5 100644 --- a/12_integrated_testing/kernel/tests/01_timer_sanity.rs +++ b/12_integrated_testing/kernel/tests/01_timer_sanity.rs @@ -11,13 +11,15 @@ #![test_runner(libkernel::test_runner)] use core::time::Duration; -use libkernel::{bsp, cpu, exception, time, time::interface::TimeManager}; +use libkernel::{bsp, cpu, driver, exception, time, time::interface::TimeManager}; use test_macros::kernel_test; #[no_mangle] unsafe fn kernel_init() -> ! { + use driver::interface::DriverManager; + exception::handling_init(); - bsp::console::qemu_bring_up_console(); + bsp::driver::driver_manager().qemu_bring_up_console(); // Depending on CPU arch, some timer bring-up code could go here. Not needed for the RPi. diff --git a/12_integrated_testing/kernel/tests/02_exception_sync_page_fault.rs b/12_integrated_testing/kernel/tests/02_exception_sync_page_fault.rs index 9be94acd..62908377 100644 --- a/12_integrated_testing/kernel/tests/02_exception_sync_page_fault.rs +++ b/12_integrated_testing/kernel/tests/02_exception_sync_page_fault.rs @@ -17,14 +17,15 @@ /// or indirectly. mod panic_exit_success; -use libkernel::{bsp, cpu, exception, info, memory, println}; +use libkernel::{bsp, cpu, driver, exception, info, memory, println}; #[no_mangle] unsafe fn kernel_init() -> ! { + use driver::interface::DriverManager; use memory::mmu::interface::MMU; exception::handling_init(); - bsp::console::qemu_bring_up_console(); + bsp::driver::driver_manager().qemu_bring_up_console(); // This line will be printed as the test header. println!("Testing synchronous exception handling by causing a page fault"); diff --git a/12_integrated_testing/kernel/tests/03_exception_restore_sanity.rs b/12_integrated_testing/kernel/tests/03_exception_restore_sanity.rs index f25ed645..3f4eae79 100644 --- a/12_integrated_testing/kernel/tests/03_exception_restore_sanity.rs +++ b/12_integrated_testing/kernel/tests/03_exception_restore_sanity.rs @@ -12,7 +12,7 @@ mod panic_wait_forever; use core::arch::asm; -use libkernel::{bsp, cpu, exception, info, memory, println}; +use libkernel::{bsp, cpu, driver, exception, info, memory, println}; #[inline(never)] fn nested_system_call() { @@ -30,10 +30,11 @@ fn nested_system_call() { #[no_mangle] unsafe fn kernel_init() -> ! { + use driver::interface::DriverManager; use memory::mmu::interface::MMU; exception::handling_init(); - bsp::console::qemu_bring_up_console(); + bsp::driver::driver_manager().qemu_bring_up_console(); // This line will be printed as the test header. println!("Testing exception restore"); diff --git a/13_exceptions_part2_peripheral_IRQs/README.md b/13_exceptions_part2_peripheral_IRQs/README.md index d6c6a7e4..bc468be8 100644 --- a/13_exceptions_part2_peripheral_IRQs/README.md +++ b/13_exceptions_part2_peripheral_IRQs/README.md @@ -29,7 +29,6 @@ + [The GICv2 Driver (Pi 4)](#the-gicv2-driver-pi-4) - [GICC Details](#gicc-details) - [GICD Details](#gicd-details) -- [UART hack](#uart-hack) - [Test it](#test-it) - [Diff to previous](#diff-to-previous) @@ -282,7 +281,7 @@ fn register_and_enable_irq_handler(&'static self) -> Result<(), &'static str> { use exception::asynchronous::{interface::IRQManager, IRQDescriptor}; let descriptor = IRQDescriptor { - name: "BCM PL011 UART", + name: Self::COMPATIBLE, handler: self, }; @@ -667,6 +666,7 @@ Minipush 1.0 [MP] ⏳ Waiting for /dev/ttyUSB0 [MP] ✅ Serial connected [MP] 🔌 Please power the target now + __ __ _ _ _ _ | \/ (_)_ _ (_) | ___ __ _ __| | | |\/| | | ' \| | |__/ _ \/ _` / _` | @@ -678,26 +678,26 @@ Minipush 1.0 [MP] ⏩ Pushing 66 KiB =========================================🦀 100% 0 KiB/s Time: 00:00:00 [ML] Loaded! Executing the payload now -[ 1.010579] mingo version 0.13.0 -[ 1.010787] Booting on: Raspberry Pi 3 -[ 1.011242] MMU online. Special regions: -[ 1.011718] 0x00080000 - 0x0008ffff | 64 KiB | C RO PX | Kernel code and RO data -[ 1.012737] 0x3f000000 - 0x4000ffff | 16 MiB | Dev RW PXN | Device MMIO -[ 1.013625] Current privilege level: EL1 -[ 1.014102] Exception handling state: -[ 1.014546] Debug: Masked -[ 1.014936] SError: Masked -[ 1.015326] IRQ: Unmasked -[ 1.015738] FIQ: Masked -[ 1.016127] Architectural timer resolution: 52 ns -[ 1.016702] Drivers loaded: -[ 1.017038] 1. BCM GPIO -[ 1.017395] 2. BCM PL011 UART -[ 1.017817] 3. BCM Interrupt Controller -[ 1.018348] Registered IRQ handlers: -[ 1.018782] Peripheral handler: -[ 1.019228] 57. BCM PL011 UART -[ 1.019735] Echoing input now +[ 0.822492] mingo version 0.13.0 +[ 0.822700] Booting on: Raspberry Pi 3 +[ 0.823155] MMU online. Special regions: +[ 0.823632] 0x00080000 - 0x0008ffff | 64 KiB | C RO PX | Kernel code and RO data +[ 0.824650] 0x3f000000 - 0x4000ffff | 16 MiB | Dev RW PXN | Device MMIO +[ 0.825539] Current privilege level: EL1 +[ 0.826015] Exception handling state: +[ 0.826459] Debug: Masked +[ 0.826849] SError: Masked +[ 0.827239] IRQ: Unmasked +[ 0.827651] FIQ: Masked +[ 0.828041] Architectural timer resolution: 52 ns +[ 0.828615] Drivers loaded: +[ 0.828951] 1. BCM PL011 UART +[ 0.829373] 2. BCM GPIO +[ 0.829731] 3. BCM Interrupt Controller +[ 0.830262] Registered IRQ handlers: +[ 0.830695] Peripheral handler: +[ 0.831141] 57. BCM PL011 UART +[ 0.831649] Echoing input now ``` Raspberry Pi 4: @@ -710,6 +710,7 @@ Minipush 1.0 [MP] ⏳ Waiting for /dev/ttyUSB0 [MP] ✅ Serial connected [MP] 🔌 Please power the target now + __ __ _ _ _ _ | \/ (_)_ _ (_) | ___ __ _ __| | | |\/| | | ' \| | |__/ _ \/ _` / _` | @@ -721,26 +722,26 @@ Minipush 1.0 [MP] ⏩ Pushing 73 KiB =========================================🦀 100% 0 KiB/s Time: 00:00:00 [ML] Loaded! Executing the payload now -[ 1.030536] mingo version 0.13.0 -[ 1.030569] Booting on: Raspberry Pi 4 -[ 1.031024] MMU online. Special regions: -[ 1.031501] 0x00080000 - 0x0008ffff | 64 KiB | C RO PX | Kernel code and RO data -[ 1.032519] 0xfe000000 - 0xff84ffff | 24 MiB | Dev RW PXN | Device MMIO -[ 1.033408] Current privilege level: EL1 -[ 1.033884] Exception handling state: -[ 1.034328] Debug: Masked -[ 1.034718] SError: Masked -[ 1.035108] IRQ: Unmasked -[ 1.035520] FIQ: Masked -[ 1.035910] Architectural timer resolution: 18 ns -[ 1.036484] Drivers loaded: -[ 1.036820] 1. BCM GPIO -[ 1.037178] 2. BCM PL011 UART -[ 1.037600] 3. GICv2 (ARM Generic Interrupt Controller v2) -[ 1.038337] Registered IRQ handlers: -[ 1.038770] Peripheral handler: -[ 1.039217] 153. BCM PL011 UART -[ 1.039725] Echoing input now +[ 0.886853] mingo version 0.13.0 +[ 0.886886] Booting on: Raspberry Pi 4 +[ 0.887341] MMU online. Special regions: +[ 0.887818] 0x00080000 - 0x0008ffff | 64 KiB | C RO PX | Kernel code and RO data +[ 0.888836] 0xfe000000 - 0xff84ffff | 24 MiB | Dev RW PXN | Device MMIO +[ 0.889725] Current privilege level: EL1 +[ 0.890201] Exception handling state: +[ 0.890645] Debug: Masked +[ 0.891035] SError: Masked +[ 0.891425] IRQ: Unmasked +[ 0.891837] FIQ: Masked +[ 0.892227] Architectural timer resolution: 18 ns +[ 0.892801] Drivers loaded: +[ 0.893137] 1. BCM PL011 UART +[ 0.893560] 2. BCM GPIO +[ 0.893917] 3. GICv2 (ARM Generic Interrupt Controller v2) +[ 0.894654] Registered IRQ handlers: +[ 0.895087] Peripheral handler: +[ 0.895534] 153. BCM PL011 UART +[ 0.896042] Echoing input now ``` ## Diff to previous @@ -896,21 +897,19 @@ diff -uNr 12_integrated_testing/kernel/src/_arch/aarch64/exception.rs 13_excepti //! //! crate::exception::arch_exception -+use crate::{bsp, exception}; ++use crate::exception; use core::{arch::global_asm, cell::UnsafeCell, fmt}; use cortex_a::{asm::barrier, registers::*}; use tock_registers::{ -@@ -102,8 +103,11 @@ +@@ -102,8 +103,9 @@ } #[no_mangle] -unsafe extern "C" fn current_elx_irq(e: &mut ExceptionContext) { - default_exception_handler(e); +unsafe extern "C" fn current_elx_irq(_e: &mut ExceptionContext) { -+ use exception::asynchronous::interface::IRQManager; -+ + let token = &exception::asynchronous::IRQContext::new(); -+ bsp::exception::asynchronous::irq_manager().handle_pending_irqs(token); ++ exception::asynchronous::irq_manager().handle_pending_irqs(token); } #[no_mangle] @@ -1268,7 +1267,7 @@ diff -uNr 12_integrated_testing/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs 1 diff -uNr 12_integrated_testing/kernel/src/bsp/device_driver/arm/gicv2.rs 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/arm/gicv2.rs --- 12_integrated_testing/kernel/src/bsp/device_driver/arm/gicv2.rs +++ 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/arm/gicv2.rs -@@ -0,0 +1,219 @@ +@@ -0,0 +1,221 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2020-2022 Andre Richter @@ -1385,6 +1384,8 @@ diff -uNr 12_integrated_testing/kernel/src/bsp/device_driver/arm/gicv2.rs 13_exc + const MAX_IRQ_NUMBER: usize = 300; // Normally 1019, but keep it lower to save some space. + const NUM_IRQS: usize = Self::MAX_IRQ_NUMBER + 1; + ++ pub const COMPATIBLE: &'static str = "GICv2 (ARM Generic Interrupt Controller v2)"; ++ + /// Create an instance. + /// + /// # Safety @@ -1406,7 +1407,7 @@ diff -uNr 12_integrated_testing/kernel/src/bsp/device_driver/arm/gicv2.rs 13_exc + +impl driver::interface::DeviceDriver for GICv2 { + fn compatible(&self) -> &'static str { -+ "GICv2 (ARM Generic Interrupt Controller v2)" ++ Self::COMPATIBLE + } + + unsafe fn init(&self) -> Result<(), &'static str> { @@ -1515,7 +1516,7 @@ diff -uNr 12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs }; use tock_registers::{ interfaces::{ReadWriteable, Writeable}, -@@ -121,7 +121,7 @@ +@@ -118,7 +118,7 @@ /// Representation of the GPIO HW. pub struct GPIO { @@ -1524,7 +1525,7 @@ diff -uNr 12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs } //-------------------------------------------------------------------------------------------------- -@@ -197,7 +197,7 @@ +@@ -200,7 +200,7 @@ /// - The user must ensure to provide a correct MMIO start address. pub const unsafe fn new(mmio_start_addr: usize) -> Self { Self { @@ -1709,7 +1710,7 @@ diff -uNr 12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_interru diff -uNr 12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs --- 12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs +++ 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs -@@ -0,0 +1,131 @@ +@@ -0,0 +1,134 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2020-2022 Andre Richter @@ -1740,6 +1741,7 @@ diff -uNr 12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_interru + +/// Used for the associated type of trait [`exception::asynchronous::interface::IRQManager`]. +#[derive(Copy, Clone)] ++#[allow(missing_docs)] +pub enum IRQNumber { + Local(LocalIRQ), + Peripheral(PeripheralIRQ), @@ -1786,12 +1788,14 @@ diff -uNr 12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_interru + const MAX_PERIPHERAL_IRQ_NUMBER: usize = 63; + const NUM_PERIPHERAL_IRQS: usize = Self::MAX_PERIPHERAL_IRQ_NUMBER + 1; + ++ pub const COMPATIBLE: &'static str = "BCM Interrupt Controller"; ++ + /// Create an instance. + /// + /// # Safety + /// + /// - The user must ensure to provide a correct MMIO start address. -+ pub const unsafe fn new(_local_mmio_start_addr: usize, periph_mmio_start_addr: usize) -> Self { ++ pub const unsafe fn new(periph_mmio_start_addr: usize) -> Self { + Self { + periph: peripheral_ic::PeripheralIC::new(periph_mmio_start_addr), + } @@ -1804,7 +1808,7 @@ diff -uNr 12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_interru + +impl driver::interface::DeviceDriver for InterruptController { + fn compatible(&self) -> &'static str { -+ "BCM Interrupt Controller" ++ Self::COMPATIBLE + } +} + @@ -1921,7 +1925,7 @@ diff -uNr 12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_u (0x44 => ICR: WriteOnly), (0x48 => @END), } -@@ -182,7 +231,8 @@ +@@ -179,7 +228,8 @@ /// Representation of the UART. pub struct PL011Uart { @@ -1931,7 +1935,7 @@ diff -uNr 12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_u } //-------------------------------------------------------------------------------------------------- -@@ -250,6 +300,14 @@ +@@ -247,6 +297,14 @@ .LCR_H .write(LCR_H::WLEN::EightBit + LCR_H::FEN::FifosEnabled); @@ -1946,7 +1950,7 @@ diff -uNr 12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_u // Turn the UART on. self.registers .CR -@@ -332,9 +390,13 @@ +@@ -335,9 +393,13 @@ /// # Safety /// /// - The user must ensure to provide a correct MMIO start address. @@ -1962,17 +1966,16 @@ diff -uNr 12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_u } } } -@@ -354,6 +416,21 @@ +@@ -357,6 +419,20 @@ Ok(()) } + + fn register_and_enable_irq_handler(&'static self) -> Result<(), &'static str> { -+ use bsp::exception::asynchronous::irq_manager; -+ use exception::asynchronous::{interface::IRQManager, IRQDescriptor}; ++ use exception::asynchronous::{irq_manager, IRQDescriptor}; + + let descriptor = IRQDescriptor { -+ name: "BCM PL011 UART", ++ name: Self::COMPATIBLE, + handler: self, + }; + @@ -1984,10 +1987,10 @@ diff -uNr 12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_u } impl console::interface::Write for PL011Uart { -@@ -400,3 +477,24 @@ - self.inner.lock(|inner| inner.chars_read) - } +@@ -405,3 +481,24 @@ } + + impl console::interface::All for PL011Uart {} + +impl exception::asynchronous::interface::IRQHandler for PL011Uart { + fn handle(&self) -> Result<(), &'static str> { @@ -2047,7 +2050,19 @@ diff -uNr 12_integrated_testing/kernel/src/bsp/device_driver.rs 13_exceptions_pa diff -uNr 12_integrated_testing/kernel/src/bsp/raspberrypi/driver.rs 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/driver.rs --- 12_integrated_testing/kernel/src/bsp/raspberrypi/driver.rs +++ 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/driver.rs -@@ -12,7 +12,7 @@ +@@ -4,29 +4,43 @@ + + //! BSP driver support. + +-use super::memory::map::mmio; ++use super::{exception, memory::map::mmio}; + use crate::{bsp::device_driver, driver}; + ++pub use device_driver::IRQNumber; ++ + //-------------------------------------------------------------------------------------------------- + // Private Definitions + //-------------------------------------------------------------------------------------------------- /// Device Driver Manager type. struct BSPDriverManager { @@ -2056,16 +2071,31 @@ diff -uNr 12_integrated_testing/kernel/src/bsp/raspberrypi/driver.rs 13_exceptio } //-------------------------------------------------------------------------------------------------- -@@ -20,7 +20,11 @@ + // Global instances //-------------------------------------------------------------------------------------------------- +-pub(super) static PL011_UART: device_driver::PL011Uart = +- unsafe { device_driver::PL011Uart::new(mmio::PL011_UART_START) }; ++pub(super) static PL011_UART: device_driver::PL011Uart = unsafe { ++ device_driver::PL011Uart::new( ++ mmio::PL011_UART_START, ++ exception::asynchronous::irq_map::PL011_UART, ++ ) ++}; + + static GPIO: device_driver::GPIO = unsafe { device_driver::GPIO::new(mmio::GPIO_START) }; + ++#[cfg(feature = "bsp_rpi3")] ++pub(super) static INTERRUPT_CONTROLLER: device_driver::InterruptController = ++ unsafe { device_driver::InterruptController::new(mmio::PERIPHERAL_INTERRUPT_CONTROLLER_START) }; ++ ++#[cfg(feature = "bsp_rpi4")] ++pub(super) static INTERRUPT_CONTROLLER: device_driver::GICv2 = ++ unsafe { device_driver::GICv2::new(mmio::GICD_START, mmio::GICC_START) }; ++ static BSP_DRIVER_MANAGER: BSPDriverManager = BSPDriverManager { -- device_drivers: [&super::GPIO, &super::PL011_UART], -+ device_drivers: [ -+ &super::GPIO, -+ &super::PL011_UART, -+ &super::INTERRUPT_CONTROLLER, -+ ], +- device_drivers: [&PL011_UART, &GPIO], ++ device_drivers: [&PL011_UART, &GPIO, &INTERRUPT_CONTROLLER], }; //-------------------------------------------------------------------------------------------------- @@ -2080,7 +2110,7 @@ diff -uNr 12_integrated_testing/kernel/src/bsp/raspberrypi/exception/asynchronou + +//! BSP asynchronous exception handling. + -+use crate::{bsp, exception}; ++use crate::{bsp, bsp::driver, exception}; + +//-------------------------------------------------------------------------------------------------- +// Public Definitions @@ -2108,7 +2138,7 @@ diff -uNr 12_integrated_testing/kernel/src/bsp/raspberrypi/exception/asynchronou +pub fn irq_manager() -> &'static impl exception::asynchronous::interface::IRQManager< + IRQNumberType = bsp::device_driver::IRQNumber, +> { -+ &super::super::INTERRUPT_CONTROLLER ++ &driver::INTERRUPT_CONTROLLER +} diff -uNr 12_integrated_testing/kernel/src/bsp/raspberrypi/exception.rs 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/exception.rs @@ -2126,7 +2156,7 @@ diff -uNr 12_integrated_testing/kernel/src/bsp/raspberrypi/exception.rs 13_excep diff -uNr 12_integrated_testing/kernel/src/bsp/raspberrypi/memory.rs 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/memory.rs --- 12_integrated_testing/kernel/src/bsp/raspberrypi/memory.rs +++ 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/memory.rs -@@ -73,10 +73,12 @@ +@@ -73,10 +73,11 @@ pub mod mmio { use super::*; @@ -2138,12 +2168,11 @@ diff -uNr 12_integrated_testing/kernel/src/bsp/raspberrypi/memory.rs 13_exceptio + pub const PERIPHERAL_INTERRUPT_CONTROLLER_START: usize = START + 0x0000_B200; + pub const GPIO_START: usize = START + GPIO_OFFSET; + pub const PL011_UART_START: usize = START + UART_OFFSET; -+ pub const LOCAL_INTERRUPT_CONTROLLER_START: usize = 0x4000_0000; + pub const END_INCLUSIVE: usize = 0x4000_FFFF; } /// Physical devices. -@@ -87,6 +89,8 @@ +@@ -87,6 +88,8 @@ pub const START: usize = 0xFE00_0000; pub const GPIO_START: usize = START + GPIO_OFFSET; pub const PL011_UART_START: usize = START + UART_OFFSET; @@ -2164,34 +2193,6 @@ diff -uNr 12_integrated_testing/kernel/src/bsp/raspberrypi.rs 13_exceptions_part pub mod memory; //-------------------------------------------------------------------------------------------------- -@@ -17,8 +18,25 @@ - static GPIO: device_driver::GPIO = - unsafe { device_driver::GPIO::new(memory::map::mmio::GPIO_START) }; - --static PL011_UART: device_driver::PL011Uart = -- unsafe { device_driver::PL011Uart::new(memory::map::mmio::PL011_UART_START) }; -+static PL011_UART: device_driver::PL011Uart = unsafe { -+ device_driver::PL011Uart::new( -+ memory::map::mmio::PL011_UART_START, -+ exception::asynchronous::irq_map::PL011_UART, -+ ) -+}; -+ -+#[cfg(feature = "bsp_rpi3")] -+static INTERRUPT_CONTROLLER: device_driver::InterruptController = unsafe { -+ device_driver::InterruptController::new( -+ memory::map::mmio::LOCAL_INTERRUPT_CONTROLLER_START, -+ memory::map::mmio::PERIPHERAL_INTERRUPT_CONTROLLER_START, -+ ) -+}; -+ -+#[cfg(feature = "bsp_rpi4")] -+static INTERRUPT_CONTROLLER: device_driver::GICv2 = unsafe { -+ device_driver::GICv2::new(memory::map::mmio::GICD_START, memory::map::mmio::GICC_START) -+}; - - //-------------------------------------------------------------------------------------------------- - // Public Code diff -uNr 12_integrated_testing/kernel/src/cpu/smp.rs 13_exceptions_part2_peripheral_IRQs/kernel/src/cpu/smp.rs --- 12_integrated_testing/kernel/src/cpu/smp.rs @@ -2247,10 +2248,11 @@ diff -uNr 12_integrated_testing/kernel/src/driver.rs 13_exceptions_part2_periphe diff -uNr 12_integrated_testing/kernel/src/exception/asynchronous.rs 13_exceptions_part2_peripheral_IRQs/kernel/src/exception/asynchronous.rs --- 12_integrated_testing/kernel/src/exception/asynchronous.rs +++ 13_exceptions_part2_peripheral_IRQs/kernel/src/exception/asynchronous.rs -@@ -8,7 +8,145 @@ +@@ -8,7 +8,153 @@ #[path = "../_arch/aarch64/exception/asynchronous.rs"] mod arch_asynchronous; ++use crate::bsp; +use core::{fmt, marker::PhantomData}; + //-------------------------------------------------------------------------------------------------- @@ -2394,6 +2396,13 @@ diff -uNr 12_integrated_testing/kernel/src/exception/asynchronous.rs 13_exceptio + + ret +} ++ ++/// Return a reference to the IRQ manager. ++/// ++/// This is the IRQ manager used by the architectural interrupt handling code. ++pub fn irq_manager() -> &'static dyn interface::IRQManager { ++ bsp::exception::asynchronous::irq_manager() ++} diff -uNr 12_integrated_testing/kernel/src/lib.rs 13_exceptions_part2_peripheral_IRQs/kernel/src/lib.rs --- 12_integrated_testing/kernel/src/lib.rs @@ -2428,7 +2437,7 @@ diff -uNr 12_integrated_testing/kernel/src/main.rs 13_exceptions_part2_periphera #[no_mangle] unsafe fn kernel_init() -> ! { use driver::interface::DriverManager; -@@ -43,15 +43,27 @@ +@@ -43,14 +43,27 @@ bsp::driver::driver_manager().post_device_driver_init(); // println! is usable from here on. @@ -2451,14 +2460,13 @@ diff -uNr 12_integrated_testing/kernel/src/main.rs 13_exceptions_part2_periphera /// The main function running after the early init. fn kernel_main() -> ! { -- use bsp::console::console; -- use console::interface::All; +- use console::console; use driver::interface::DriverManager; + use exception::asynchronous::interface::IRQManager; info!("{}", libkernel::version()); info!("Booting on: {}", bsp::board_name()); -@@ -79,12 +91,9 @@ +@@ -78,12 +91,9 @@ info!(" {}. {}", i + 1, driver.compatible()); } @@ -2469,8 +2477,8 @@ diff -uNr 12_integrated_testing/kernel/src/main.rs 13_exceptions_part2_periphera - // Discard any spurious received characters before going into echo mode. - console().clear_rx(); - loop { -- let c = bsp::console::console().read_char(); -- bsp::console::console().write_char(c); +- let c = console().read_char(); +- console().write_char(c); - } + info!("Echoing input now"); + cpu::wait_forever(); @@ -2483,12 +2491,12 @@ diff -uNr 12_integrated_testing/kernel/src/panic_wait.rs 13_exceptions_part2_per //! A panic handler that infinitely waits. --use crate::{bsp, cpu}; -+use crate::{bsp, cpu, exception}; - use core::{fmt, panic::PanicInfo}; +-use crate::{cpu, println}; ++use crate::{cpu, exception, println}; + use core::panic::PanicInfo; //-------------------------------------------------------------------------------------------------- -@@ -77,6 +77,8 @@ +@@ -61,6 +61,8 @@ fn panic(info: &PanicInfo) -> ! { use crate::time::interface::TimeManager; @@ -2733,7 +2741,7 @@ diff -uNr 12_integrated_testing/kernel/src/synchronization.rs 13_exceptions_part diff -uNr 12_integrated_testing/kernel/tests/04_exception_irq_sanity.rs 13_exceptions_part2_peripheral_IRQs/kernel/tests/04_exception_irq_sanity.rs --- 12_integrated_testing/kernel/tests/04_exception_irq_sanity.rs +++ 13_exceptions_part2_peripheral_IRQs/kernel/tests/04_exception_irq_sanity.rs -@@ -0,0 +1,66 @@ +@@ -0,0 +1,67 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2020-2022 Andre Richter @@ -2746,12 +2754,13 @@ diff -uNr 12_integrated_testing/kernel/tests/04_exception_irq_sanity.rs 13_excep +#![reexport_test_harness_main = "test_main"] +#![test_runner(libkernel::test_runner)] + -+use libkernel::{bsp, cpu, exception}; ++use libkernel::{bsp, cpu, driver, exception}; +use test_macros::kernel_test; + +#[no_mangle] +unsafe fn kernel_init() -> ! { -+ bsp::console::qemu_bring_up_console(); ++ use driver::interface::DriverManager; ++ bsp::driver::driver_manager().qemu_bring_up_console(); + + exception::handling_init(); + exception::asynchronous::local_irq_unmask(); diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/exception.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/exception.rs index 662c91b9..fa6748a6 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/exception.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/exception.rs @@ -11,7 +11,7 @@ //! //! crate::exception::arch_exception -use crate::{bsp, exception}; +use crate::exception; use core::{arch::global_asm, cell::UnsafeCell, fmt}; use cortex_a::{asm::barrier, registers::*}; use tock_registers::{ @@ -104,10 +104,8 @@ unsafe extern "C" fn current_elx_synchronous(e: &mut ExceptionContext) { #[no_mangle] unsafe extern "C" fn current_elx_irq(_e: &mut ExceptionContext) { - use exception::asynchronous::interface::IRQManager; - let token = &exception::asynchronous::IRQContext::new(); - bsp::exception::asynchronous::irq_manager().handle_pending_irqs(token); + exception::asynchronous::irq_manager().handle_pending_irqs(token); } #[no_mangle] diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/arm/gicv2.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/arm/gicv2.rs index 09a0cdf4..03c1fa0f 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/arm/gicv2.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/arm/gicv2.rs @@ -114,6 +114,8 @@ impl GICv2 { const MAX_IRQ_NUMBER: usize = 300; // Normally 1019, but keep it lower to save some space. const NUM_IRQS: usize = Self::MAX_IRQ_NUMBER + 1; + pub const COMPATIBLE: &'static str = "GICv2 (ARM Generic Interrupt Controller v2)"; + /// Create an instance. /// /// # Safety @@ -135,7 +137,7 @@ use synchronization::interface::ReadWriteEx; impl driver::interface::DeviceDriver for GICv2 { fn compatible(&self) -> &'static str { - "GICv2 (ARM Generic Interrupt Controller v2)" + Self::COMPATIBLE } unsafe fn init(&self) -> Result<(), &'static str> { diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs index c0dc838a..b5603b40 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs @@ -108,16 +108,13 @@ register_structs! { /// Abstraction for the associated MMIO registers. type Registers = MMIODerefWrapper; -//-------------------------------------------------------------------------------------------------- -// Public Definitions -//-------------------------------------------------------------------------------------------------- - -pub struct GPIOInner { +struct GPIOInner { registers: Registers, } -// Export the inner struct so that BSPs can use it for the panic handler. -pub use GPIOInner as PanicGPIO; +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- /// Representation of the GPIO HW. pub struct GPIO { @@ -125,7 +122,7 @@ pub struct GPIO { } //-------------------------------------------------------------------------------------------------- -// Public Code +// Private Code //-------------------------------------------------------------------------------------------------- impl GPIOInner { @@ -189,7 +186,13 @@ impl GPIOInner { } } +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + impl GPIO { + pub const COMPATIBLE: &'static str = "BCM GPIO"; + /// Create an instance. /// /// # Safety @@ -214,6 +217,6 @@ use synchronization::interface::Mutex; impl driver::interface::DeviceDriver for GPIO { fn compatible(&self) -> &'static str { - "BCM GPIO" + Self::COMPATIBLE } } diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs index 577470d4..d4acd275 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs @@ -28,6 +28,7 @@ pub type PeripheralIRQ = /// Used for the associated type of trait [`exception::asynchronous::interface::IRQManager`]. #[derive(Copy, Clone)] +#[allow(missing_docs)] pub enum IRQNumber { Local(LocalIRQ), Peripheral(PeripheralIRQ), @@ -74,12 +75,14 @@ impl InterruptController { const MAX_PERIPHERAL_IRQ_NUMBER: usize = 63; const NUM_PERIPHERAL_IRQS: usize = Self::MAX_PERIPHERAL_IRQ_NUMBER + 1; + pub const COMPATIBLE: &'static str = "BCM Interrupt Controller"; + /// Create an instance. /// /// # Safety /// /// - The user must ensure to provide a correct MMIO start address. - pub const unsafe fn new(_local_mmio_start_addr: usize, periph_mmio_start_addr: usize) -> Self { + pub const unsafe fn new(periph_mmio_start_addr: usize) -> Self { Self { periph: peripheral_ic::PeripheralIC::new(periph_mmio_start_addr), } @@ -92,7 +95,7 @@ impl InterruptController { impl driver::interface::DeviceDriver for InterruptController { fn compatible(&self) -> &'static str { - "BCM Interrupt Controller" + Self::COMPATIBLE } } diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs index 4d000ad5..a96ebf7e 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs @@ -216,18 +216,15 @@ enum BlockingMode { NonBlocking, } -//-------------------------------------------------------------------------------------------------- -// Public Definitions -//-------------------------------------------------------------------------------------------------- - -pub struct PL011UartInner { +struct PL011UartInner { registers: Registers, chars_written: usize, chars_read: usize, } -// Export the inner struct so that BSPs can use it for the panic handler. -pub use PL011UartInner as PanicUart; +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- /// Representation of the UART. pub struct PL011Uart { @@ -236,7 +233,7 @@ pub struct PL011Uart { } //-------------------------------------------------------------------------------------------------- -// Public Code +// Private Code //-------------------------------------------------------------------------------------------------- impl PL011UartInner { @@ -384,7 +381,13 @@ impl fmt::Write for PL011UartInner { } } +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + impl PL011Uart { + pub const COMPATIBLE: &'static str = "BCM PL011 UART"; + /// Create an instance. /// /// # Safety @@ -408,7 +411,7 @@ use synchronization::interface::Mutex; impl driver::interface::DeviceDriver for PL011Uart { fn compatible(&self) -> &'static str { - "BCM PL011 UART" + Self::COMPATIBLE } unsafe fn init(&self) -> Result<(), &'static str> { @@ -418,11 +421,10 @@ impl driver::interface::DeviceDriver for PL011Uart { } fn register_and_enable_irq_handler(&'static self) -> Result<(), &'static str> { - use bsp::exception::asynchronous::irq_manager; - use exception::asynchronous::{interface::IRQManager, IRQDescriptor}; + use exception::asynchronous::{irq_manager, IRQDescriptor}; let descriptor = IRQDescriptor { - name: "BCM PL011 UART", + name: Self::COMPATIBLE, handler: self, }; @@ -478,6 +480,8 @@ impl console::interface::Statistics for PL011Uart { } } +impl console::interface::All for PL011Uart {} + impl exception::asynchronous::interface::IRQHandler for PL011Uart { fn handle(&self) -> Result<(), &'static str> { self.inner.lock(|inner| { diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi.rs index 97656a27..50b36762 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi.rs @@ -10,34 +10,6 @@ pub mod driver; pub mod exception; pub mod memory; -//-------------------------------------------------------------------------------------------------- -// Global instances -//-------------------------------------------------------------------------------------------------- -use super::device_driver; - -static GPIO: device_driver::GPIO = - unsafe { device_driver::GPIO::new(memory::map::mmio::GPIO_START) }; - -static PL011_UART: device_driver::PL011Uart = unsafe { - device_driver::PL011Uart::new( - memory::map::mmio::PL011_UART_START, - exception::asynchronous::irq_map::PL011_UART, - ) -}; - -#[cfg(feature = "bsp_rpi3")] -static INTERRUPT_CONTROLLER: device_driver::InterruptController = unsafe { - device_driver::InterruptController::new( - memory::map::mmio::LOCAL_INTERRUPT_CONTROLLER_START, - memory::map::mmio::PERIPHERAL_INTERRUPT_CONTROLLER_START, - ) -}; - -#[cfg(feature = "bsp_rpi4")] -static INTERRUPT_CONTROLLER: device_driver::GICv2 = unsafe { - device_driver::GICv2::new(memory::map::mmio::GICD_START, memory::map::mmio::GICC_START) -}; - //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/console.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/console.rs index eaef0b1f..0a630eef 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/console.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/console.rs @@ -4,45 +4,13 @@ //! BSP console facilities. -use super::memory; -use crate::{bsp::device_driver, console}; -use core::fmt; +use crate::console; //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- -/// In case of a panic, the panic handler uses this function to take a last shot at printing -/// something before the system is halted. -/// -/// We try to init panic-versions of the GPIO and the UART. The panic versions are not protected -/// with synchronization primitives, which increases chances that we get to print something, even -/// when the kernel's default GPIO or UART instances happen to be locked at the time of the panic. -/// -/// # Safety -/// -/// - Use only for printing during a panic. -pub unsafe fn panic_console_out() -> impl fmt::Write { - let mut panic_gpio = device_driver::PanicGPIO::new(memory::map::mmio::GPIO_START); - let mut panic_uart = device_driver::PanicUart::new(memory::map::mmio::PL011_UART_START); - - panic_gpio.map_pl011_uart(); - panic_uart.init(); - panic_uart -} - /// Return a reference to the console. -pub fn console() -> &'static impl console::interface::All { - &super::PL011_UART +pub fn console() -> &'static dyn console::interface::All { + &super::driver::PL011_UART } - -//-------------------------------------------------------------------------------------------------- -// Testing -//-------------------------------------------------------------------------------------------------- - -/// Minimal code needed to bring up the console in QEMU (for testing only). This is often less steps -/// than on real hardware due to QEMU's abstractions. -/// -/// For the RPi, nothing needs to be done. -#[cfg(feature = "test_build")] -pub fn qemu_bring_up_console() {} diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/driver.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/driver.rs index 1cf6d23c..568f1096 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/driver.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/driver.rs @@ -4,7 +4,10 @@ //! BSP driver support. -use crate::driver; +use super::{exception, memory::map::mmio}; +use crate::{bsp::device_driver, driver}; + +pub use device_driver::IRQNumber; //-------------------------------------------------------------------------------------------------- // Private Definitions @@ -19,12 +22,25 @@ struct BSPDriverManager { // Global instances //-------------------------------------------------------------------------------------------------- +pub(super) static PL011_UART: device_driver::PL011Uart = unsafe { + device_driver::PL011Uart::new( + mmio::PL011_UART_START, + exception::asynchronous::irq_map::PL011_UART, + ) +}; + +static GPIO: device_driver::GPIO = unsafe { device_driver::GPIO::new(mmio::GPIO_START) }; + +#[cfg(feature = "bsp_rpi3")] +pub(super) static INTERRUPT_CONTROLLER: device_driver::InterruptController = + unsafe { device_driver::InterruptController::new(mmio::PERIPHERAL_INTERRUPT_CONTROLLER_START) }; + +#[cfg(feature = "bsp_rpi4")] +pub(super) static INTERRUPT_CONTROLLER: device_driver::GICv2 = + unsafe { device_driver::GICv2::new(mmio::GICD_START, mmio::GICC_START) }; + static BSP_DRIVER_MANAGER: BSPDriverManager = BSPDriverManager { - device_drivers: [ - &super::GPIO, - &super::PL011_UART, - &super::INTERRUPT_CONTROLLER, - ], + device_drivers: [&PL011_UART, &GPIO, &INTERRUPT_CONTROLLER], }; //-------------------------------------------------------------------------------------------------- @@ -48,6 +64,9 @@ impl driver::interface::DriverManager for BSPDriverManager { fn post_device_driver_init(&self) { // Configure PL011Uart's output pins. - super::GPIO.map_pl011_uart(); + GPIO.map_pl011_uart(); } + + #[cfg(feature = "test_build")] + fn qemu_bring_up_console(&self) {} } diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/exception/asynchronous.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/exception/asynchronous.rs index dc5ab421..a13b2444 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/exception/asynchronous.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/exception/asynchronous.rs @@ -4,7 +4,7 @@ //! BSP asynchronous exception handling. -use crate::{bsp, exception}; +use crate::{bsp, bsp::driver, exception}; //-------------------------------------------------------------------------------------------------- // Public Definitions @@ -32,5 +32,5 @@ pub(in crate::bsp) mod irq_map { pub fn irq_manager() -> &'static impl exception::asynchronous::interface::IRQManager< IRQNumberType = bsp::device_driver::IRQNumber, > { - &super::super::INTERRUPT_CONTROLLER + &driver::INTERRUPT_CONTROLLER } diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/memory.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/memory.rs index 51b334c0..a383c9fe 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/memory.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/memory.rs @@ -77,7 +77,6 @@ pub(super) mod map { pub const PERIPHERAL_INTERRUPT_CONTROLLER_START: usize = START + 0x0000_B200; pub const GPIO_START: usize = START + GPIO_OFFSET; pub const PL011_UART_START: usize = START + UART_OFFSET; - pub const LOCAL_INTERRUPT_CONTROLLER_START: usize = 0x4000_0000; pub const END_INCLUSIVE: usize = 0x4000_FFFF; } diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/console.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/console.rs index e49e241f..c1fb0e53 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/console.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/console.rs @@ -4,6 +4,8 @@ //! System console. +use crate::bsp; + //-------------------------------------------------------------------------------------------------- // Public Definitions //-------------------------------------------------------------------------------------------------- @@ -49,5 +51,16 @@ pub mod interface { } /// Trait alias for a full-fledged console. - pub trait All = Write + Read + Statistics; + pub trait All: Write + Read + Statistics {} +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +/// Return a reference to the console. +/// +/// This is the global console used by all printing macros. +pub fn console() -> &'static dyn interface::All { + bsp::console::console() } diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/driver.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/driver.rs index 8c5c5e16..c39e5eaf 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/driver.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/driver.rs @@ -48,5 +48,10 @@ pub mod interface { /// /// For example, device driver code that depends on other drivers already being online. fn post_device_driver_init(&self); + + /// Minimal code needed to bring up the console in QEMU (for testing only). This is often + /// less steps than on real hardware due to QEMU's abstractions. + #[cfg(feature = "test_build")] + fn qemu_bring_up_console(&self); } } diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/exception/asynchronous.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/exception/asynchronous.rs index fb1785c2..17938692 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/exception/asynchronous.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/exception/asynchronous.rs @@ -8,6 +8,7 @@ #[path = "../_arch/aarch64/exception/asynchronous.rs"] mod arch_asynchronous; +use crate::bsp; use core::{fmt, marker::PhantomData}; //-------------------------------------------------------------------------------------------------- @@ -150,3 +151,10 @@ pub fn exec_with_irq_masked(f: impl FnOnce() -> T) -> T { ret } + +/// Return a reference to the IRQ manager. +/// +/// This is the IRQ manager used by the architectural interrupt handling code. +pub fn irq_manager() -> &'static dyn interface::IRQManager { + bsp::exception::asynchronous::irq_manager() +} diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/lib.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/lib.rs index 58a939f1..c4b07809 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/lib.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/lib.rs @@ -178,8 +178,10 @@ pub fn test_runner(tests: &[&test_types::UnitTest]) { #[cfg(test)] #[no_mangle] unsafe fn kernel_init() -> ! { + use driver::interface::DriverManager; + exception::handling_init(); - bsp::console::qemu_bring_up_console(); + bsp::driver::driver_manager().qemu_bring_up_console(); test_main(); diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/panic_wait.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/panic_wait.rs index 08d7d453..e4256b61 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/panic_wait.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/panic_wait.rs @@ -4,19 +4,13 @@ //! A panic handler that infinitely waits. -use crate::{bsp, cpu, exception}; -use core::{fmt, panic::PanicInfo}; +use crate::{cpu, exception, println}; +use core::panic::PanicInfo; //-------------------------------------------------------------------------------------------------- // Private Code //-------------------------------------------------------------------------------------------------- -fn _panic_print(args: fmt::Arguments) { - use fmt::Write; - - unsafe { bsp::console::panic_console_out().write_fmt(args).unwrap() }; -} - /// The point of exit for `libkernel`. /// /// It is linked weakly, so that the integration tests can overload its standard behavior. @@ -34,16 +28,6 @@ fn _panic_exit() -> ! { } } -/// Prints with a newline - only use from the panic handler. -/// -/// Carbon copy from -#[macro_export] -macro_rules! panic_println { - ($($arg:tt)*) => ({ - _panic_print(format_args_nl!($($arg)*)); - }) -} - /// Stop immediately if called a second time. /// /// # Note @@ -88,7 +72,7 @@ fn panic(info: &PanicInfo) -> ! { _ => ("???", 0, 0), }; - panic_println!( + println!( "[ {:>3}.{:06}] Kernel panic!\n\n\ Panic location:\n File '{}', line {}, column {}\n\n\ {}", diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/print.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/print.rs index 9ec13a28..8705eec0 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/print.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/print.rs @@ -4,7 +4,7 @@ //! Printing. -use crate::{bsp, console}; +use crate::console; use core::fmt; //-------------------------------------------------------------------------------------------------- @@ -13,9 +13,7 @@ use core::fmt; #[doc(hidden)] pub fn _print(args: fmt::Arguments) { - use console::interface::Write; - - bsp::console::console().write_fmt(args).unwrap(); + console::console().write_fmt(args).unwrap(); } /// Prints without a newline. diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/tests/00_console_sanity.rs b/13_exceptions_part2_peripheral_IRQs/kernel/tests/00_console_sanity.rs index dccb6cc2..e12a711f 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/tests/00_console_sanity.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/tests/00_console_sanity.rs @@ -11,15 +11,15 @@ /// Console tests should time out on the I/O harness in case of panic. mod panic_wait_forever; -use libkernel::{bsp, console, cpu, exception, print}; +use libkernel::{bsp, console, cpu, driver, exception, print}; #[no_mangle] unsafe fn kernel_init() -> ! { - use bsp::console::console; - use console::interface::*; + use console::console; + use driver::interface::DriverManager; exception::handling_init(); - bsp::console::qemu_bring_up_console(); + bsp::driver::driver_manager().qemu_bring_up_console(); // Handshake assert_eq!(console().read_char(), 'A'); diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/tests/01_timer_sanity.rs b/13_exceptions_part2_peripheral_IRQs/kernel/tests/01_timer_sanity.rs index 59ef4a7f..390cdee5 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/tests/01_timer_sanity.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/tests/01_timer_sanity.rs @@ -11,13 +11,15 @@ #![test_runner(libkernel::test_runner)] use core::time::Duration; -use libkernel::{bsp, cpu, exception, time, time::interface::TimeManager}; +use libkernel::{bsp, cpu, driver, exception, time, time::interface::TimeManager}; use test_macros::kernel_test; #[no_mangle] unsafe fn kernel_init() -> ! { + use driver::interface::DriverManager; + exception::handling_init(); - bsp::console::qemu_bring_up_console(); + bsp::driver::driver_manager().qemu_bring_up_console(); // Depending on CPU arch, some timer bring-up code could go here. Not needed for the RPi. diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/tests/02_exception_sync_page_fault.rs b/13_exceptions_part2_peripheral_IRQs/kernel/tests/02_exception_sync_page_fault.rs index 9be94acd..62908377 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/tests/02_exception_sync_page_fault.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/tests/02_exception_sync_page_fault.rs @@ -17,14 +17,15 @@ /// or indirectly. mod panic_exit_success; -use libkernel::{bsp, cpu, exception, info, memory, println}; +use libkernel::{bsp, cpu, driver, exception, info, memory, println}; #[no_mangle] unsafe fn kernel_init() -> ! { + use driver::interface::DriverManager; use memory::mmu::interface::MMU; exception::handling_init(); - bsp::console::qemu_bring_up_console(); + bsp::driver::driver_manager().qemu_bring_up_console(); // This line will be printed as the test header. println!("Testing synchronous exception handling by causing a page fault"); diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/tests/03_exception_restore_sanity.rs b/13_exceptions_part2_peripheral_IRQs/kernel/tests/03_exception_restore_sanity.rs index f25ed645..3f4eae79 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/tests/03_exception_restore_sanity.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/tests/03_exception_restore_sanity.rs @@ -12,7 +12,7 @@ mod panic_wait_forever; use core::arch::asm; -use libkernel::{bsp, cpu, exception, info, memory, println}; +use libkernel::{bsp, cpu, driver, exception, info, memory, println}; #[inline(never)] fn nested_system_call() { @@ -30,10 +30,11 @@ fn nested_system_call() { #[no_mangle] unsafe fn kernel_init() -> ! { + use driver::interface::DriverManager; use memory::mmu::interface::MMU; exception::handling_init(); - bsp::console::qemu_bring_up_console(); + bsp::driver::driver_manager().qemu_bring_up_console(); // This line will be printed as the test header. println!("Testing exception restore"); diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/tests/04_exception_irq_sanity.rs b/13_exceptions_part2_peripheral_IRQs/kernel/tests/04_exception_irq_sanity.rs index e1e02554..1204dca4 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/tests/04_exception_irq_sanity.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/tests/04_exception_irq_sanity.rs @@ -10,12 +10,13 @@ #![reexport_test_harness_main = "test_main"] #![test_runner(libkernel::test_runner)] -use libkernel::{bsp, cpu, exception}; +use libkernel::{bsp, cpu, driver, exception}; use test_macros::kernel_test; #[no_mangle] unsafe fn kernel_init() -> ! { - bsp::console::qemu_bring_up_console(); + use driver::interface::DriverManager; + bsp::driver::driver_manager().qemu_bring_up_console(); exception::handling_init(); exception::asynchronous::local_irq_unmask(); diff --git a/14_virtual_mem_part2_mmio_remap/README.md b/14_virtual_mem_part2_mmio_remap/README.md index 5d78e237..b5caac52 100644 --- a/14_virtual_mem_part2_mmio_remap/README.md +++ b/14_virtual_mem_part2_mmio_remap/README.md @@ -8,8 +8,7 @@ whole of the board's address space. - Instead, only ranges that are actually needed are mapped: - The `kernel binary` stays `identity mapped` for now. - - Device `MMIO regions` are remapped lazily (to a special reserved virtual address region) - during the device driver's `init()`. + - Device `MMIO regions` are remapped lazily (to a special reserved virtual address region). ## Table of Contents @@ -59,7 +58,8 @@ separation, this tutorial makes a start by changing the following things: parts that are needed will be mapped. 1. For now, the `kernel binary` stays identity mapped. This will be changed in the coming tutorials as it is a quite difficult and peculiar exercise to remap the kernel. -1. Device `MMIO regions` are lazily remapped during a device driver's `init()`. +1. Device `MMIO regions` are lazily remapped during device driver bringup (using the new + `DriverManage` function `instantiate_drivers()`). 1. A dedicated region of virtual addresses that we reserve using `BSP` code and the `linker script` is used for this. 1. We keep using `TTBR0` for the kernel translation tables for now. This will be changed when we @@ -232,43 +232,111 @@ pub unsafe fn kernel_map_binary() -> Result<(), &'static str> { } ``` -Another user of the new APIs are device drivers, which now expect an `MMIODescriptor` type instead -of a raw address. The following is an example for the `UART`: +Another user of the new APIs is the **driver subsystem**. As has been said in the introduction, the +goal is to remap the `MMIO` regions of the drivers. To achieve this in a seamless way, some changes +to the architecture of the driver subsystem were needed. + +Until now, the drivers were `static instances` which had their `MMIO addresses` statically set in +the constructor. This was fine, because even if virtual memory was activated, only `identity +mapping` was used, so the hardcoded addresses would be valid with and without the MMU being active. + +With `remapped MMIO addresses`, this is not possible anymore, since the remapping will only happen +at runtime. Therefore, the new approach is to defer the whole instantiation of the drivers until the +remapped addresses are known. To achieve this, in `src/bsp/raspberrypi/drivers.rs`, the static +driver instances are now wrapped into a `MaybeUninit` (and are also `mut` now): ```rust -impl PL011Uart { - /// Create an instance. - pub const unsafe fn new( - mmio_descriptor: memory::mmu::MMIODescriptor, - irq_number: bsp::device_driver::IRQNumber, - ) -> Self { - Self { - // omitted for brevity. - } +static mut PL011_UART: MaybeUninit = MaybeUninit::uninit(); +static mut GPIO: MaybeUninit = MaybeUninit::uninit(); + +#[cfg(feature = "bsp_rpi3")] +static mut INTERRUPT_CONTROLLER: MaybeUninit = + MaybeUninit::uninit(); + +#[cfg(feature = "bsp_rpi4")] +static mut INTERRUPT_CONTROLLER: MaybeUninit = MaybeUninit::uninit(); +``` + +`BSPDriverManager` implements the new `instantiate_drivers()` interface function, which will be +called early during `kernel_init()`, short after virtual memory has been activated: + +```rust +unsafe fn instantiate_drivers(&self) -> Result<(), &'static str> { + if self.init_done.load(Ordering::Relaxed) { + return Err("Drivers already instantiated"); } + + self.instantiate_uart()?; + self.instantiate_gpio()?; + self.instantiate_interrupt_controller()?; + + self.register_drivers(); + + self.init_done.store(true, Ordering::Relaxed); + Ok(()) } ``` -When the kernel calls the driver's implementation of `driver::interface::DeviceDriver::init()` -during kernel boot, the MMIO Descriptor is used to remap the MMIO region on demand: +As can be seen, for each driver, this `BSP` code calls a dedicated instantiation function. In this +tutorial text, only the `UART` will be discussed in detail: ```rust -unsafe fn init(&self) -> Result<(), &'static str> { - let virt_addr = memory::mmu::kernel_map_mmio(self.compatible(), &self.mmio_descriptor)?; - - self.inner - .lock(|inner| inner.init(Some(virt_addr.as_usize())))?; +unsafe fn instantiate_uart(&self) -> Result<(), &'static str> { + let mmio_descriptor = MMIODescriptor::new(mmio::PL011_UART_START, mmio::PL011_UART_SIZE); + let virt_addr = + memory::mmu::kernel_map_mmio(device_driver::PL011Uart::COMPATIBLE, &mmio_descriptor)?; + + // This is safe to do, because it is only called from the init'ed instance itself. + fn uart_post_init() { + console::register_console(unsafe { PL011_UART.assume_init_ref() }); + } - // omitted for brevity. + PL011_UART.write(device_driver::PL011Uart::new( + virt_addr, + exception::asynchronous::irq_map::PL011_UART, + uart_post_init, + )); Ok(()) } ``` +A couple of things are happening here. First, an `MMIODescriptor` is created and then used to remap +the MMIO region using `memory::mmu::kernel_map_mmio()`. This function will be discussed in detail in +the next chapter. What's important for now is that it returns the new `Virtual Address` of the +remapped MMIO region. The constructor of the `UART` driver now also expects a virtual address. + +Next, a new instance of the `PL011Uart` driver is created, and written into the `PL011_UART` global +variable (remember, it is defined as `MaybeUninit = +MaybeUninit::uninit()`). Meaning, after this line of code, `PL011_UART` is properly initialized. + +Another new feature is the function `uart_post_init()`, which is supplied to the UART constructor. +This is a callback that will be called by the UART driver when it concludes its `init()` function +(remember that the driver's init functions are called from `kernel_init()`). This callback, in turn, +registers the `PL011_UART` as the new console of the kernel. + +A look into `src/console.rs` should make clear what is happening. The classic `console::console()` +now dynamically points to whoever registered itself using the `console::register_console()` +function, instead of using a hardcoded static reference (from the `BSP`). This has been introduced +to accommodate the run-time instantiation of the device drivers (the same feature has been +implemented for the `IRQManager` as well). Until `console::register_console()` has been called for +the first time, an instance of the newly introduced `NullConsole` is used as the default. +`NullConsole` implements all the console traits, but does nothing. It discards outputs, and returns +dummy input. For example, should one of the printing macros be called before the UART driver has +been instantiated and registered, the kernel does not need to crash because the driver is not +brought up yet. Instead, it can just discards the output. With this new scheme of things, it is +possible to safely switch global references like the UART or the IRQ Manager at runtime. + +That all the post-driver-init work has now been moved to callbacks is motivated by the idea that +this fully enables a driver once it has concluded its `init()` function, and not only after all the +drivers have been init'ed and then the post-init code would be called, as earlier. In our example, +printing through the UART will now be available already before the interrupt controller driver runs +its init function. + ### MMIO Virtual Address Allocation -Peeking inside `memory::mmu::kernel_map_mmio()`, we can see that a `virtual address region` is -obtained from an `allocator` before remapping: +Getting back to the remapping part, let's peek inside `memory::mmu::kernel_map_mmio()`. We can see +that a `virtual address region` is obtained from an `allocator` before remapping: ```rust pub unsafe fn kernel_map_mmio( @@ -296,7 +364,7 @@ pub unsafe fn kernel_map_mmio( } ``` -This allocator is defined and implemented in the added file `src/memory/mmu/paeg_alloc.rs`. Like +This allocator is defined and implemented in the added file `src/memory/mmu/page_alloc.rs`. Like other parts of the mapping code, its implementation makes use of the newly introduced `PageAddress` and `MemoryRegion` types (in [`src/memory/mmu/types.rs`](kernel/src/memory/mmu/types.rs)), but apart from that is rather straight @@ -339,13 +407,13 @@ the VA range. ### Supporting Changes -There's a couple of changes not covered in this tutorial text, but the reader should ideally skim -through them: +There's a couple of changes more not covered in this tutorial text, but the reader should ideally +skim through them: - [`src/memory.rs`](kernel/src/memory.rs) and - [`src/memory/mmu/types.rs`](kernel/src/memory/mmu/types.rs) introduce a couple of supporting - types, like`Address`, `PageAddress` and `MemoryRegion`. It is worth reading - their implementations. + [`src/memory/mmu/types.rs`](kernel/src/memory/mmu/types.rs) introduce supporting types, + like`Address`, `PageAddress` and `MemoryRegion`. It is worth reading their + implementations. - [`src/memory/mmu/mapping_record.rs`](kernel/src/memory/mmu/mapping_record.rs) provides the generic kernel code's way of tracking previous memory mappings for use cases such as reusing existing mappings (in case of drivers that have their MMIO ranges in the same `64 KiB` page) or printing @@ -375,22 +443,22 @@ Minipush 1.0 Raspberry Pi 3 [ML] Requesting binary -[MP] ⏩ Pushing 67 KiB =========================================🦀 100% 0 KiB/s Time: 00:00:00 +[MP] ⏩ Pushing 65 KiB =========================================🦀 100% 0 KiB/s Time: 00:00:00 [ML] Loaded! Executing the payload now -[ 0.758253] mingo version 0.14.0 -[ 0.758460] Booting on: Raspberry Pi 3 -[ 0.758915] MMU online: -[ 0.759208] ------------------------------------------------------------------------------------------------------------------------------------------- -[ 0.760952] Virtual Physical Size Attr Entity -[ 0.762696] ------------------------------------------------------------------------------------------------------------------------------------------- -[ 0.764441] 0x0000_0000_0000_0000..0x0000_0000_0007_ffff --> 0x00_0000_0000..0x00_0007_ffff | 512 KiB | C RW XN | Kernel boot-core stack -[ 0.766044] 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.767658] 0x0000_0000_0009_0000..0x0000_0000_000d_ffff --> 0x00_0009_0000..0x00_000d_ffff | 320 KiB | C RW XN | Kernel data and bss -[ 0.769229] 0x0000_0000_000e_0000..0x0000_0000_000e_ffff --> 0x00_3f20_0000..0x00_3f20_ffff | 64 KiB | Dev RW XN | BCM GPIO -[ 0.770680] | BCM PL011 UART -[ 0.772197] 0x0000_0000_000f_0000..0x0000_0000_000f_ffff --> 0x00_3f00_0000..0x00_3f00_ffff | 64 KiB | Dev RW XN | BCM Peripheral Interrupt Controller -[ 0.773941] ------------------------------------------------------------------------------------------------------------------------------------------- +[ 0.740694] mingo version 0.14.0 +[ 0.740902] Booting on: Raspberry Pi 3 +[ 0.741357] MMU online: +[ 0.741649] ------------------------------------------------------------------------------------------------------------------------------------------- +[ 0.743393] Virtual Physical Size Attr Entity +[ 0.745138] ------------------------------------------------------------------------------------------------------------------------------------------- +[ 0.746883] 0x0000_0000_0000_0000..0x0000_0000_0007_ffff --> 0x00_0000_0000..0x00_0007_ffff | 512 KiB | C RW XN | Kernel boot-core stack +[ 0.748486] 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.750099] 0x0000_0000_0009_0000..0x0000_0000_000e_ffff --> 0x00_0009_0000..0x00_000e_ffff | 384 KiB | C RW XN | Kernel data and bss +[ 0.751670] 0x0000_0000_000f_0000..0x0000_0000_000f_ffff --> 0x00_3f20_0000..0x00_3f20_ffff | 64 KiB | Dev RW XN | BCM PL011 UART +[ 0.753187] | BCM GPIO +[ 0.754638] 0x0000_0000_0010_0000..0x0000_0000_0010_ffff --> 0x00_3f00_0000..0x00_3f00_ffff | 64 KiB | Dev RW XN | BCM Interrupt Controller +[ 0.756264] ------------------------------------------------------------------------------------------------------------------------------------------- ``` Raspberry Pi 4: @@ -412,24 +480,23 @@ Minipush 1.0 Raspberry Pi 4 [ML] Requesting binary -[MP] ⏩ Pushing 74 KiB =========================================🦀 100% 0 KiB/s Time: 00:00:00 +[MP] ⏩ Pushing 65 KiB =========================================🦀 100% 0 KiB/s Time: 00:00:00 [ML] Loaded! Executing the payload now -[ 0.842275] mingo version 0.14.0 -[ 0.842308] Booting on: Raspberry Pi 4 -[ 0.842763] MMU online: -[ 0.843055] ------------------------------------------------------------------------------------------------------------------------------------------- -[ 0.844800] Virtual Physical Size Attr Entity -[ 0.846544] ------------------------------------------------------------------------------------------------------------------------------------------- -[ 0.848288] 0x0000_0000_0000_0000..0x0000_0000_0007_ffff --> 0x00_0000_0000..0x00_0007_ffff | 512 KiB | C RW XN | Kernel boot-core stack -[ 0.849892] 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.851505] 0x0000_0000_0009_0000..0x0000_0000_000d_ffff --> 0x00_0009_0000..0x00_000d_ffff | 320 KiB | C RW XN | Kernel data and bss -[ 0.853076] 0x0000_0000_000e_0000..0x0000_0000_000e_ffff --> 0x00_fe20_0000..0x00_fe20_ffff | 64 KiB | Dev RW XN | BCM GPIO -[ 0.854528] | BCM PL011 UART -[ 0.856045] 0x0000_0000_000f_0000..0x0000_0000_000f_ffff --> 0x00_ff84_0000..0x00_ff84_ffff | 64 KiB | Dev RW XN | GICD -[ 0.857453] | GICC -[ 0.858862] ------------------------------------------------------------------------------------------------------------------------------------------- - +[ 0.736136] mingo version 0.14.0 +[ 0.736170] Booting on: Raspberry Pi 4 +[ 0.736625] MMU online: +[ 0.736918] ------------------------------------------------------------------------------------------------------------------------------------------- +[ 0.738662] Virtual Physical Size Attr Entity +[ 0.740406] ------------------------------------------------------------------------------------------------------------------------------------------- +[ 0.742151] 0x0000_0000_0000_0000..0x0000_0000_0007_ffff --> 0x00_0000_0000..0x00_0007_ffff | 512 KiB | C RW XN | Kernel boot-core stack +[ 0.743754] 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.745368] 0x0000_0000_0009_0000..0x0000_0000_000d_ffff --> 0x00_0009_0000..0x00_000d_ffff | 320 KiB | C RW XN | Kernel data and bss +[ 0.746938] 0x0000_0000_000e_0000..0x0000_0000_000e_ffff --> 0x00_fe20_0000..0x00_fe20_ffff | 64 KiB | Dev RW XN | BCM PL011 UART +[ 0.748455] | BCM GPIO +[ 0.749907] 0x0000_0000_000f_0000..0x0000_0000_000f_ffff --> 0x00_ff84_0000..0x00_ff84_ffff | 64 KiB | Dev RW XN | GICv2 GICD +[ 0.751380] | GICV2 GICC +[ 0.752853] ------------------------------------------------------------------------------------------------------------------------------------------- ``` ## Diff to previous @@ -807,455 +874,235 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/memory/mm diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/arm/gicv2/gicc.rs 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/arm/gicv2/gicc.rs --- 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/arm/gicv2/gicc.rs +++ 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/arm/gicv2/gicc.rs -@@ -4,7 +4,9 @@ +@@ -4,7 +4,11 @@ //! GICC Driver - GIC CPU interface. -use crate::{bsp::device_driver::common::MMIODerefWrapper, exception}; +use crate::{ -+ bsp::device_driver::common::MMIODerefWrapper, exception, synchronization::InitStateLock, ++ bsp::device_driver::common::MMIODerefWrapper, ++ exception, ++ memory::{Address, Virtual}, +}; use tock_registers::{ interfaces::{Readable, Writeable}, register_bitfields, register_structs, -@@ -60,12 +62,13 @@ - - /// Representation of the GIC CPU interface. - pub struct GICC { -- registers: Registers, -+ registers: InitStateLock, - } - - //-------------------------------------------------------------------------------------------------- - // Public Code - //-------------------------------------------------------------------------------------------------- -+use crate::synchronization::interface::ReadWriteEx; - - impl GICC { - /// Create an instance. -@@ -75,10 +78,15 @@ +@@ -73,7 +77,7 @@ + /// # Safety + /// /// - The user must ensure to provide a correct MMIO start address. - pub const unsafe fn new(mmio_start_addr: usize) -> Self { +- pub const unsafe fn new(mmio_start_addr: usize) -> Self { ++ pub const unsafe fn new(mmio_start_addr: Address) -> Self { Self { -- registers: Registers::new(mmio_start_addr), -+ registers: InitStateLock::new(Registers::new(mmio_start_addr)), + registers: Registers::new(mmio_start_addr), } - } - -+ pub unsafe fn set_mmio(&self, new_mmio_start_addr: usize) { -+ self.registers -+ .write(|regs| *regs = Registers::new(new_mmio_start_addr)); -+ } -+ - /// Accept interrupts of any priority. - /// - /// Quoting the GICv2 Architecture Specification: -@@ -91,7 +99,9 @@ - /// - GICC MMIO registers are banked per CPU core. It is therefore safe to have `&self` instead - /// of `&mut self`. - pub fn priority_accept_all(&self) { -- self.registers.PMR.write(PMR::Priority.val(255)); // Comment in arch spec. -+ self.registers.read(|regs| { -+ regs.PMR.write(PMR::Priority.val(255)); // Comment in arch spec. -+ }); - } - - /// Enable the interface - start accepting IRQs. -@@ -101,7 +111,9 @@ - /// - GICC MMIO registers are banked per CPU core. It is therefore safe to have `&self` instead - /// of `&mut self`. - pub fn enable(&self) { -- self.registers.CTLR.write(CTLR::Enable::SET); -+ self.registers.read(|regs| { -+ regs.CTLR.write(CTLR::Enable::SET); -+ }); - } - - /// Extract the number of the highest-priority pending IRQ. -@@ -117,7 +129,8 @@ - &self, - _ic: &exception::asynchronous::IRQContext<'irq_context>, - ) -> usize { -- self.registers.IAR.read(IAR::InterruptID) as usize -+ self.registers -+ .read(|regs| regs.IAR.read(IAR::InterruptID) as usize) - } - - /// Complete handling of the currently active IRQ. -@@ -136,6 +149,8 @@ - irq_number: u32, - _ic: &exception::asynchronous::IRQContext<'irq_context>, - ) { -- self.registers.EOIR.write(EOIR::EOIINTID.val(irq_number)); -+ self.registers.read(|regs| { -+ regs.EOIR.write(EOIR::EOIINTID.val(irq_number)); -+ }); - } - } diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs --- 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs +++ 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs -@@ -8,8 +8,9 @@ +@@ -8,7 +8,9 @@ //! - SPI - Shared Peripheral Interrupt. use crate::{ - bsp::device_driver::common::MMIODerefWrapper, state, synchronization, -- synchronization::IRQSafeNullLock, + bsp::device_driver::common::MMIODerefWrapper, ++ memory::{Address, Virtual}, + state, synchronization, -+ synchronization::{IRQSafeNullLock, InitStateLock}, + synchronization::IRQSafeNullLock, }; use tock_registers::{ - interfaces::{Readable, Writeable}, -@@ -83,7 +84,7 @@ - shared_registers: IRQSafeNullLock, - - /// Access to banked registers is unguarded. -- banked_registers: BankedRegisters, -+ banked_registers: InitStateLock, - } - - //-------------------------------------------------------------------------------------------------- -@@ -120,6 +121,7 @@ - //-------------------------------------------------------------------------------------------------- - // Public Code - //-------------------------------------------------------------------------------------------------- -+use crate::synchronization::interface::ReadWriteEx; - use synchronization::interface::Mutex; - - impl GICD { -@@ -131,10 +133,17 @@ - pub const unsafe fn new(mmio_start_addr: usize) -> Self { +@@ -128,7 +130,7 @@ + /// # Safety + /// + /// - The user must ensure to provide a correct MMIO start address. +- pub const unsafe fn new(mmio_start_addr: usize) -> Self { ++ pub const unsafe fn new(mmio_start_addr: Address) -> Self { Self { shared_registers: IRQSafeNullLock::new(SharedRegisters::new(mmio_start_addr)), -- banked_registers: BankedRegisters::new(mmio_start_addr), -+ banked_registers: InitStateLock::new(BankedRegisters::new(mmio_start_addr)), - } - } - -+ pub unsafe fn set_mmio(&self, new_mmio_start_addr: usize) { -+ self.shared_registers -+ .lock(|regs| *regs = SharedRegisters::new(new_mmio_start_addr)); -+ self.banked_registers -+ .write(|regs| *regs = BankedRegisters::new(new_mmio_start_addr)); -+ } -+ - /// Use a banked ITARGETSR to retrieve the executing core's GIC target mask. - /// - /// Quoting the GICv2 Architecture Specification: -@@ -142,7 +151,8 @@ - /// "GICD_ITARGETSR0 to GICD_ITARGETSR7 are read-only, and each field returns a value that - /// corresponds only to the processor reading the register." - fn local_gic_target_mask(&self) -> u32 { -- self.banked_registers.ITARGETSR[0].read(ITARGETSR::Offset0) -+ self.banked_registers -+ .read(|regs| regs.ITARGETSR[0].read(ITARGETSR::Offset0)) - } - - /// Route all SPIs to the boot core and enable the distributor. -@@ -181,10 +191,10 @@ - // Check if we are handling a private or shared IRQ. - match irq_num { - // Private. -- 0..=31 => { -- let enable_reg = &self.banked_registers.ISENABLER; -+ 0..=31 => self.banked_registers.read(|regs| { -+ let enable_reg = ®s.ISENABLER; - enable_reg.set(enable_reg.get() | enable_bit); -- } -+ }), - // Shared. - _ => { - let enable_reg_index_shared = enable_reg_index - 1; + banked_registers: BankedRegisters::new(mmio_start_addr), diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/arm/gicv2.rs 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/arm/gicv2.rs --- 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/arm/gicv2.rs +++ 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/arm/gicv2.rs -@@ -79,7 +79,8 @@ +@@ -79,7 +79,12 @@ mod gicc; mod gicd; -use crate::{bsp, cpu, driver, exception, synchronization, synchronization::InitStateLock}; -+use crate::{bsp, cpu, driver, exception, memory, synchronization, synchronization::InitStateLock}; -+use core::sync::atomic::{AtomicBool, Ordering}; ++use crate::{ ++ bsp, cpu, driver, exception, ++ memory::{Address, Virtual}, ++ synchronization, ++ synchronization::InitStateLock, ++}; //-------------------------------------------------------------------------------------------------- // Private Definitions -@@ -96,12 +97,18 @@ +@@ -104,6 +109,9 @@ - /// Representation of the GIC. - pub struct GICv2 { -+ gicd_mmio_descriptor: memory::mmu::MMIODescriptor, -+ gicc_mmio_descriptor: memory::mmu::MMIODescriptor, -+ - /// The Distributor. - gicd: gicd::GICD, - - /// The CPU Interface. - gicc: gicc::GICC, - -+ /// Have the MMIO regions been remapped yet? -+ is_mmio_remapped: AtomicBool, -+ /// Stores registered IRQ handlers. Writable only during kernel init. RO afterwards. handler_table: InitStateLock, ++ ++ /// Callback to be invoked after successful init. ++ post_init_callback: fn(), } -@@ -118,11 +125,17 @@ - /// + + //-------------------------------------------------------------------------------------------------- +@@ -121,11 +129,16 @@ /// # Safety /// -- /// - The user must ensure to provide a correct MMIO start address. + /// - The user must ensure to provide a correct MMIO start address. - pub const unsafe fn new(gicd_mmio_start_addr: usize, gicc_mmio_start_addr: usize) -> Self { -+ /// - The user must ensure to provide correct MMIO descriptors. + pub const unsafe fn new( -+ gicd_mmio_descriptor: memory::mmu::MMIODescriptor, -+ gicc_mmio_descriptor: memory::mmu::MMIODescriptor, ++ gicd_mmio_start_addr: Address, ++ gicc_mmio_start_addr: Address, ++ post_init_callback: fn(), + ) -> Self { Self { -- gicd: gicd::GICD::new(gicd_mmio_start_addr), -- gicc: gicc::GICC::new(gicc_mmio_start_addr), -+ gicd_mmio_descriptor, -+ gicc_mmio_descriptor, -+ gicd: gicd::GICD::new(gicd_mmio_descriptor.start_addr().as_usize()), -+ gicc: gicc::GICC::new(gicc_mmio_descriptor.start_addr().as_usize()), -+ is_mmio_remapped: AtomicBool::new(false), + gicd: gicd::GICD::new(gicd_mmio_start_addr), + gicc: gicc::GICC::new(gicc_mmio_start_addr), handler_table: InitStateLock::new([None; Self::NUM_IRQS]), ++ post_init_callback, } } -@@ -139,6 +152,20 @@ - } + } +@@ -148,6 +161,8 @@ + self.gicc.priority_accept_all(); + self.gicc.enable(); - unsafe fn init(&self) -> Result<(), &'static str> { -+ let remapped = self.is_mmio_remapped.load(Ordering::Relaxed); -+ if !remapped { -+ // GICD -+ let mut virt_addr = memory::mmu::kernel_map_mmio("GICD", &self.gicd_mmio_descriptor)?; -+ self.gicd.set_mmio(virt_addr.as_usize()); -+ -+ // GICC -+ virt_addr = memory::mmu::kernel_map_mmio("GICC", &self.gicc_mmio_descriptor)?; -+ self.gicc.set_mmio(virt_addr.as_usize()); -+ -+ // Conclude remapping. -+ self.is_mmio_remapped.store(true, Ordering::Relaxed); -+ } ++ (self.post_init_callback)(); + - if bsp::cpu::BOOT_CORE_ID == cpu::smp::core_id() { - self.gicd.boot_core_init(); - } + Ok(()) + } + } diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs --- 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs +++ 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs -@@ -5,9 +5,10 @@ +@@ -5,7 +5,10 @@ //! GPIO Driver. use crate::{ - bsp::device_driver::common::MMIODerefWrapper, driver, synchronization, -+ bsp::device_driver::common::MMIODerefWrapper, driver, memory, synchronization, ++ bsp::device_driver::common::MMIODerefWrapper, ++ driver, ++ memory::{Address, Virtual}, ++ synchronization, synchronization::IRQSafeNullLock, }; -+use core::sync::atomic::{AtomicUsize, Ordering}; use tock_registers::{ - interfaces::{ReadWriteable, Writeable}, - register_bitfields, register_structs, -@@ -121,6 +122,8 @@ - +@@ -119,6 +122,7 @@ /// Representation of the GPIO HW. pub struct GPIO { -+ mmio_descriptor: memory::mmu::MMIODescriptor, -+ virt_mmio_start_addr: AtomicUsize, inner: IRQSafeNullLock, ++ post_init_callback: fn(), } -@@ -140,6 +143,19 @@ - } - } - -+ /// Init code. -+ /// -+ /// # Safety -+ /// -+ /// - The user must ensure to provide a correct MMIO start address. -+ pub unsafe fn init(&mut self, new_mmio_start_addr: Option) -> Result<(), &'static str> { -+ if let Some(addr) = new_mmio_start_addr { -+ self.registers = Registers::new(addr); -+ } -+ -+ Ok(()) -+ } -+ - /// Disable pull-up/down on pins 14 and 15. - #[cfg(feature = "bsp_rpi3")] - fn disable_pud_14_15_bcm2837(&mut self) { -@@ -194,10 +210,12 @@ + //-------------------------------------------------------------------------------------------------- +@@ -131,7 +135,7 @@ + /// # Safety /// + /// - The user must ensure to provide a correct MMIO start address. +- pub const unsafe fn new(mmio_start_addr: usize) -> Self { ++ pub const unsafe fn new(mmio_start_addr: Address) -> Self { + Self { + registers: Registers::new(mmio_start_addr), + } +@@ -198,9 +202,10 @@ /// # Safety /// -- /// - The user must ensure to provide a correct MMIO start address. + /// - The user must ensure to provide a correct MMIO start address. - pub const unsafe fn new(mmio_start_addr: usize) -> Self { -+ /// - The user must ensure to provide correct MMIO descriptors. -+ pub const unsafe fn new(mmio_descriptor: memory::mmu::MMIODescriptor) -> Self { ++ pub const unsafe fn new(mmio_start_addr: Address, post_init_callback: fn()) -> Self { Self { -- inner: IRQSafeNullLock::new(GPIOInner::new(mmio_start_addr)), -+ mmio_descriptor, -+ virt_mmio_start_addr: AtomicUsize::new(0), -+ inner: IRQSafeNullLock::new(GPIOInner::new(mmio_descriptor.start_addr().as_usize())), + inner: IRQSafeNullLock::new(GPIOInner::new(mmio_start_addr)), ++ post_init_callback, } } -@@ -216,4 +234,26 @@ +@@ -219,4 +224,10 @@ fn compatible(&self) -> &'static str { - "BCM GPIO" + Self::COMPATIBLE } + + unsafe fn init(&self) -> Result<(), &'static str> { -+ let virt_addr = memory::mmu::kernel_map_mmio(self.compatible(), &self.mmio_descriptor)?; -+ -+ self.inner -+ .lock(|inner| inner.init(Some(virt_addr.as_usize())))?; -+ -+ self.virt_mmio_start_addr -+ .store(virt_addr.as_usize(), Ordering::Relaxed); ++ (self.post_init_callback)(); + + Ok(()) -+ } -+ -+ fn virt_mmio_start_addr(&self) -> Option { -+ let addr = self.virt_mmio_start_addr.load(Ordering::Relaxed); -+ -+ if addr == 0 { -+ return None; -+ } -+ -+ Some(addr) + } } diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs --- 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs +++ 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs -@@ -7,7 +7,7 @@ +@@ -7,7 +7,9 @@ use super::{InterruptController, PendingIRQs, PeripheralIRQ}; use crate::{ bsp::device_driver::common::MMIODerefWrapper, - exception, synchronization, -+ driver, exception, memory, synchronization, ++ exception, ++ memory::{Address, Virtual}, ++ synchronization, synchronization::{IRQSafeNullLock, InitStateLock}, }; use tock_registers::{ -@@ -55,11 +55,13 @@ - - /// Representation of the peripheral interrupt controller. - pub struct PeripheralIC { -+ mmio_descriptor: memory::mmu::MMIODescriptor, -+ - /// Access to write registers is guarded with a lock. - wo_registers: IRQSafeNullLock, - - /// Register read access is unguarded. -- ro_registers: ReadOnlyRegisters, -+ ro_registers: InitStateLock, - - /// Stores registered IRQ handlers. Writable only during kernel init. RO afterwards. - handler_table: InitStateLock, -@@ -74,21 +76,26 @@ - /// +@@ -75,7 +77,7 @@ /// # Safety /// -- /// - The user must ensure to provide a correct MMIO start address. + /// - The user must ensure to provide a correct MMIO start address. - pub const unsafe fn new(mmio_start_addr: usize) -> Self { -+ /// - The user must ensure to provide correct MMIO descriptors. -+ pub const unsafe fn new(mmio_descriptor: memory::mmu::MMIODescriptor) -> Self { -+ let addr = mmio_descriptor.start_addr().as_usize(); -+ ++ pub const unsafe fn new(mmio_start_addr: Address) -> Self { Self { -- wo_registers: IRQSafeNullLock::new(WriteOnlyRegisters::new(mmio_start_addr)), -- ro_registers: ReadOnlyRegisters::new(mmio_start_addr), -+ mmio_descriptor, -+ wo_registers: IRQSafeNullLock::new(WriteOnlyRegisters::new(addr)), -+ ro_registers: InitStateLock::new(ReadOnlyRegisters::new(addr)), - handler_table: InitStateLock::new([None; InterruptController::NUM_PERIPHERAL_IRQS]), - } - } - - /// Query the list of pending IRQs. - fn pending_irqs(&self) -> PendingIRQs { -- let pending_mask: u64 = (u64::from(self.ro_registers.PENDING_2.get()) << 32) -- | u64::from(self.ro_registers.PENDING_1.get()); -+ self.ro_registers.read(|regs| { -+ let pending_mask: u64 = -+ (u64::from(regs.PENDING_2.get()) << 32) | u64::from(regs.PENDING_1.get()); - -- PendingIRQs::new(pending_mask) -+ PendingIRQs::new(pending_mask) -+ }) - } - } - -@@ -97,6 +104,24 @@ - //------------------------------------------------------------------------------ - use synchronization::interface::{Mutex, ReadWriteEx}; - -+impl driver::interface::DeviceDriver for PeripheralIC { -+ fn compatible(&self) -> &'static str { -+ "BCM Peripheral Interrupt Controller" -+ } -+ -+ unsafe fn init(&self) -> Result<(), &'static str> { -+ let virt_addr = -+ memory::mmu::kernel_map_mmio(self.compatible(), &self.mmio_descriptor)?.as_usize(); -+ -+ self.wo_registers -+ .lock(|regs| *regs = WriteOnlyRegisters::new(virt_addr)); -+ self.ro_registers -+ .write(|regs| *regs = ReadOnlyRegisters::new(virt_addr)); -+ -+ Ok(()) -+ } -+} -+ - impl exception::asynchronous::interface::IRQManager for PeripheralIC { - type IRQNumberType = PeripheralIRQ; - + wo_registers: IRQSafeNullLock::new(WriteOnlyRegisters::new(mmio_start_addr)), + ro_registers: ReadOnlyRegisters::new(mmio_start_addr), diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs --- 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs +++ 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs -@@ -6,7 +6,7 @@ +@@ -6,7 +6,10 @@ mod peripheral_ic; -use crate::{driver, exception}; -+use crate::{driver, exception, memory}; ++use crate::{ ++ driver, exception, ++ memory::{Address, Virtual}, ++}; //-------------------------------------------------------------------------------------------------- // Private Definitions -@@ -78,10 +78,13 @@ - /// +@@ -37,6 +40,7 @@ + /// Representation of the Interrupt Controller. + pub struct InterruptController { + periph: peripheral_ic::PeripheralIC, ++ post_init_callback: fn(), + } + + //-------------------------------------------------------------------------------------------------- +@@ -82,9 +86,13 @@ /// # Safety /// -- /// - The user must ensure to provide a correct MMIO start address. -- pub const unsafe fn new(_local_mmio_start_addr: usize, periph_mmio_start_addr: usize) -> Self { -+ /// - The user must ensure to provide correct MMIO descriptors. + /// - The user must ensure to provide a correct MMIO start address. +- pub const unsafe fn new(periph_mmio_start_addr: usize) -> Self { + pub const unsafe fn new( -+ _local_mmio_descriptor: memory::mmu::MMIODescriptor, -+ periph_mmio_descriptor: memory::mmu::MMIODescriptor, ++ periph_mmio_start_addr: Address, ++ post_init_callback: fn(), + ) -> Self { Self { -- periph: peripheral_ic::PeripheralIC::new(periph_mmio_start_addr), -+ periph: peripheral_ic::PeripheralIC::new(periph_mmio_descriptor), + periph: peripheral_ic::PeripheralIC::new(periph_mmio_start_addr), ++ post_init_callback, } } } -@@ -94,6 +97,10 @@ +@@ -97,6 +105,12 @@ fn compatible(&self) -> &'static str { - "BCM Interrupt Controller" + Self::COMPATIBLE } + + unsafe fn init(&self) -> Result<(), &'static str> { -+ self.periph.init() ++ (self.post_init_callback)(); ++ ++ Ok(()) + } } @@ -1264,175 +1111,363 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/b diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs --- 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs +++ 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs -@@ -10,10 +10,13 @@ +@@ -10,8 +10,12 @@ //! - use crate::{ - bsp, bsp::device_driver::common::MMIODerefWrapper, console, cpu, driver, exception, -+ bsp, bsp::device_driver::common::MMIODerefWrapper, console, cpu, driver, exception, memory, - synchronization, synchronization::IRQSafeNullLock, +- synchronization, synchronization::IRQSafeNullLock, ++ bsp, ++ bsp::device_driver::common::MMIODerefWrapper, ++ console, cpu, driver, exception, ++ memory::{Address, Virtual}, ++ synchronization, ++ synchronization::IRQSafeNullLock, }; --use core::fmt; -+use core::{ -+ fmt, -+ sync::atomic::{AtomicUsize, Ordering}, -+}; + use core::fmt; use tock_registers::{ - interfaces::{Readable, Writeable}, - register_bitfields, register_structs, -@@ -231,6 +234,8 @@ - - /// Representation of the UART. +@@ -230,6 +234,7 @@ pub struct PL011Uart { -+ mmio_descriptor: memory::mmu::MMIODescriptor, -+ virt_mmio_start_addr: AtomicUsize, inner: IRQSafeNullLock, irq_number: bsp::device_driver::IRQNumber, ++ post_init_callback: fn(), } -@@ -270,7 +275,15 @@ - /// genrated baud rate of `48_000_000 / (16 * 3.25) = 923_077`. - /// - /// Error = `((923_077 - 921_600) / 921_600) * 100 = 0.16modulo`. -- pub fn init(&mut self) { -+ /// -+ /// # Safety -+ /// -+ /// - The user must ensure to provide a correct MMIO start address. -+ pub unsafe fn init(&mut self, new_mmio_start_addr: Option) -> Result<(), &'static str> { -+ if let Some(addr) = new_mmio_start_addr { -+ self.registers = Registers::new(addr); -+ } -+ - // Execution can arrive here while there are still characters queued in the TX FIFO and - // actively being sent out by the UART hardware. If the UART is turned off in this case, - // those queued characters would be lost. -@@ -312,6 +325,8 @@ - self.registers - .CR - .write(CR::UARTEN::Enabled + CR::TXE::Enabled + CR::RXE::Enabled); -+ -+ Ok(()) - } - /// Send a character. -@@ -389,13 +404,18 @@ + //-------------------------------------------------------------------------------------------------- +@@ -242,7 +247,7 @@ + /// # Safety /// + /// - The user must ensure to provide a correct MMIO start address. +- pub const unsafe fn new(mmio_start_addr: usize) -> Self { ++ pub const unsafe fn new(mmio_start_addr: Address) -> Self { + Self { + registers: Registers::new(mmio_start_addr), + chars_written: 0, +@@ -393,13 +398,16 @@ /// # Safety /// -- /// - The user must ensure to provide a correct MMIO start address. -+ /// - The user must ensure to provide correct MMIO descriptors. + /// - The user must ensure to provide a correct MMIO start address. + /// - The user must ensure to provide correct IRQ numbers. pub const unsafe fn new( - mmio_start_addr: usize, -+ mmio_descriptor: memory::mmu::MMIODescriptor, ++ mmio_start_addr: Address, irq_number: bsp::device_driver::IRQNumber, ++ post_init_callback: fn(), ) -> Self { Self { -- inner: IRQSafeNullLock::new(PL011UartInner::new(mmio_start_addr)), -+ mmio_descriptor, -+ virt_mmio_start_addr: AtomicUsize::new(0), -+ inner: IRQSafeNullLock::new(PL011UartInner::new( -+ mmio_descriptor.start_addr().as_usize(), -+ )), + inner: IRQSafeNullLock::new(PL011UartInner::new(mmio_start_addr)), irq_number, ++ post_init_callback, } } -@@ -412,7 +432,13 @@ - } + } +@@ -416,6 +424,7 @@ unsafe fn init(&self) -> Result<(), &'static str> { -- self.inner.lock(|inner| inner.init()); -+ let virt_addr = memory::mmu::kernel_map_mmio(self.compatible(), &self.mmio_descriptor)?; -+ -+ self.inner -+ .lock(|inner| inner.init(Some(virt_addr.as_usize())))?; -+ -+ self.virt_mmio_start_addr -+ .store(virt_addr.as_usize(), Ordering::Relaxed); + self.inner.lock(|inner| inner.init()); ++ (self.post_init_callback)(); Ok(()) } -@@ -431,6 +457,16 @@ - Ok(()) - } -+ -+ fn virt_mmio_start_addr(&self) -> Option { -+ let addr = self.virt_mmio_start_addr.load(Ordering::Relaxed); -+ -+ if addr == 0 { -+ return None; -+ } -+ -+ Some(addr) -+ } +diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/common.rs 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/common.rs +--- 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/common.rs ++++ 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/common.rs +@@ -4,6 +4,7 @@ + + //! Common device driver code. + ++use crate::memory::{Address, Virtual}; + use core::{marker::PhantomData, ops}; + + //-------------------------------------------------------------------------------------------------- +@@ -11,7 +12,7 @@ + //-------------------------------------------------------------------------------------------------- + + pub struct MMIODerefWrapper { +- start_addr: usize, ++ start_addr: Address, + phantom: PhantomData T>, } - impl console::interface::Write for PL011Uart { +@@ -21,7 +22,7 @@ + + impl MMIODerefWrapper { + /// Create an instance. +- pub const unsafe fn new(start_addr: usize) -> Self { ++ pub const unsafe fn new(start_addr: Address) -> Self { + Self { + start_addr, + phantom: PhantomData, +@@ -33,6 +34,6 @@ + type Target = T; + + fn deref(&self) -> &Self::Target { +- unsafe { &*(self.start_addr as *const _) } ++ unsafe { &*(self.start_addr.as_usize() as *const _) } + } + } diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/console.rs 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/console.rs --- 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/console.rs +++ 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/console.rs -@@ -5,7 +5,7 @@ - //! BSP console facilities. +@@ -1,16 +0,0 @@ +-// SPDX-License-Identifier: MIT OR Apache-2.0 +-// +-// Copyright (c) 2018-2022 Andre Richter +- +-//! BSP console facilities. +- +-use crate::console; +- +-//-------------------------------------------------------------------------------------------------- +-// Public Code +-//-------------------------------------------------------------------------------------------------- +- +-/// Return a reference to the console. +-pub fn console() -> &'static dyn console::interface::All { +- &super::driver::PL011_UART +-} - use super::memory; --use crate::{bsp::device_driver, console}; -+use crate::{bsp::device_driver, console, cpu, driver}; - use core::fmt; +diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/driver.rs 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/driver.rs +--- 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/driver.rs ++++ 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/driver.rs +@@ -5,7 +5,16 @@ + //! BSP driver support. - //-------------------------------------------------------------------------------------------------- -@@ -23,11 +23,25 @@ - /// - /// - Use only for printing during a panic. - pub unsafe fn panic_console_out() -> impl fmt::Write { -- let mut panic_gpio = device_driver::PanicGPIO::new(memory::map::mmio::GPIO_START); -- let mut panic_uart = device_driver::PanicUart::new(memory::map::mmio::PL011_UART_START); -+ use driver::interface::DeviceDriver; - -+ let mut panic_gpio = device_driver::PanicGPIO::new(memory::map::mmio::GPIO_START.as_usize()); -+ let mut panic_uart = -+ device_driver::PanicUart::new(memory::map::mmio::PL011_UART_START.as_usize()); -+ -+ // If remapping of the driver's MMIO already happened, take the remapped start address. -+ // Otherwise, take a chance with the default physical address. -+ let maybe_gpio_mmio_start_addr = super::GPIO.virt_mmio_start_addr(); -+ let maybe_uart_mmio_start_addr = super::PL011_UART.virt_mmio_start_addr(); -+ -+ panic_gpio -+ .init(maybe_gpio_mmio_start_addr) -+ .unwrap_or_else(|_| cpu::wait_forever()); - panic_gpio.map_pl011_uart(); -- panic_uart.init(); -+ panic_uart -+ .init(maybe_uart_mmio_start_addr) -+ .unwrap_or_else(|_| cpu::wait_forever()); -+ - panic_uart + use super::{exception, memory::map::mmio}; +-use crate::{bsp::device_driver, driver}; ++use crate::{ ++ bsp::device_driver, ++ console, driver, exception as generic_exception, memory, ++ memory::mmu::MMIODescriptor, ++ synchronization::{interface::ReadWriteEx, InitStateLock}, ++}; ++use core::{ ++ mem::MaybeUninit, ++ sync::atomic::{AtomicBool, Ordering}, ++}; + + pub use device_driver::IRQNumber; + +@@ -15,35 +24,133 @@ + + /// Device Driver Manager type. + struct BSPDriverManager { +- device_drivers: [&'static (dyn DeviceDriver + Sync); 3], ++ device_drivers: InitStateLock<[Option<&'static (dyn DeviceDriver + Sync)>; NUM_DRIVERS]>, ++ init_done: AtomicBool, } + //-------------------------------------------------------------------------------------------------- +-// Global instances ++// Public Definitions + //-------------------------------------------------------------------------------------------------- + +-pub(super) static PL011_UART: device_driver::PL011Uart = unsafe { +- device_driver::PL011Uart::new( +- mmio::PL011_UART_START, +- exception::asynchronous::irq_map::PL011_UART, +- ) +-}; ++/// The number of active drivers provided by this BSP. ++pub const NUM_DRIVERS: usize = 3; ++ ++//-------------------------------------------------------------------------------------------------- ++// Global instances ++//-------------------------------------------------------------------------------------------------- -diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/driver.rs 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/driver.rs ---- 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/driver.rs -+++ 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/driver.rs -@@ -46,7 +46,15 @@ - &self.device_drivers[..] - } +-static GPIO: device_driver::GPIO = unsafe { device_driver::GPIO::new(mmio::GPIO_START) }; ++static mut PL011_UART: MaybeUninit = MaybeUninit::uninit(); ++static mut GPIO: MaybeUninit = MaybeUninit::uninit(); -- fn post_device_driver_init(&self) { -+ fn early_print_device_drivers(&self) -> &[&'static (dyn DeviceDriver + Sync)] { -+ &self.device_drivers[0..=1] + #[cfg(feature = "bsp_rpi3")] +-pub(super) static INTERRUPT_CONTROLLER: device_driver::InterruptController = +- unsafe { device_driver::InterruptController::new(mmio::PERIPHERAL_INTERRUPT_CONTROLLER_START) }; ++static mut INTERRUPT_CONTROLLER: MaybeUninit = ++ MaybeUninit::uninit(); + + #[cfg(feature = "bsp_rpi4")] +-pub(super) static INTERRUPT_CONTROLLER: device_driver::GICv2 = +- unsafe { device_driver::GICv2::new(mmio::GICD_START, mmio::GICC_START) }; ++static mut INTERRUPT_CONTROLLER: MaybeUninit = MaybeUninit::uninit(); + + static BSP_DRIVER_MANAGER: BSPDriverManager = BSPDriverManager { +- device_drivers: [&PL011_UART, &GPIO, &INTERRUPT_CONTROLLER], ++ device_drivers: InitStateLock::new([None; NUM_DRIVERS]), ++ init_done: AtomicBool::new(false), + }; + + //-------------------------------------------------------------------------------------------------- ++// Private Code ++//-------------------------------------------------------------------------------------------------- ++ ++impl BSPDriverManager { ++ unsafe fn instantiate_uart(&self) -> Result<(), &'static str> { ++ let mmio_descriptor = MMIODescriptor::new(mmio::PL011_UART_START, mmio::PL011_UART_SIZE); ++ let virt_addr = ++ memory::mmu::kernel_map_mmio(device_driver::PL011Uart::COMPATIBLE, &mmio_descriptor)?; ++ ++ // This is safe to do, because it is only called from the init'ed instance itself. ++ fn uart_post_init() { ++ console::register_console(unsafe { PL011_UART.assume_init_ref() }); ++ } ++ ++ PL011_UART.write(device_driver::PL011Uart::new( ++ virt_addr, ++ exception::asynchronous::irq_map::PL011_UART, ++ uart_post_init, ++ )); ++ ++ Ok(()) + } + -+ fn non_early_print_device_drivers(&self) -> &[&'static (dyn DeviceDriver + Sync)] { -+ &self.device_drivers[2..] ++ unsafe fn instantiate_gpio(&self) -> Result<(), &'static str> { ++ let mmio_descriptor = MMIODescriptor::new(mmio::GPIO_START, mmio::GPIO_SIZE); ++ let virt_addr = ++ memory::mmu::kernel_map_mmio(device_driver::GPIO::COMPATIBLE, &mmio_descriptor)?; ++ ++ // This is safe to do, because it is only called from the init'ed instance itself. ++ fn gpio_post_init() { ++ unsafe { GPIO.assume_init_ref().map_pl011_uart() }; ++ } ++ ++ GPIO.write(device_driver::GPIO::new(virt_addr, gpio_post_init)); ++ ++ Ok(()) ++ } ++ ++ #[cfg(feature = "bsp_rpi3")] ++ unsafe fn instantiate_interrupt_controller(&self) -> Result<(), &'static str> { ++ let periph_mmio_descriptor = ++ MMIODescriptor::new(mmio::PERIPHERAL_IC_START, mmio::PERIPHERAL_IC_SIZE); ++ let periph_virt_addr = memory::mmu::kernel_map_mmio( ++ device_driver::InterruptController::COMPATIBLE, ++ &periph_mmio_descriptor, ++ )?; ++ ++ // This is safe to do, because it is only called from the init'ed instance itself. ++ fn interrupt_controller_post_init() { ++ generic_exception::asynchronous::register_irq_manager(unsafe { ++ INTERRUPT_CONTROLLER.assume_init_ref() ++ }); ++ } ++ ++ INTERRUPT_CONTROLLER.write(device_driver::InterruptController::new( ++ periph_virt_addr, ++ interrupt_controller_post_init, ++ )); ++ ++ Ok(()) ++ } ++ ++ #[cfg(feature = "bsp_rpi4")] ++ unsafe fn instantiate_interrupt_controller(&self) -> Result<(), &'static str> { ++ let gicd_mmio_descriptor = MMIODescriptor::new(mmio::GICD_START, mmio::GICD_SIZE); ++ let gicd_virt_addr = memory::mmu::kernel_map_mmio("GICv2 GICD", &gicd_mmio_descriptor)?; ++ ++ let gicc_mmio_descriptor = MMIODescriptor::new(mmio::GICC_START, mmio::GICC_SIZE); ++ let gicc_virt_addr = memory::mmu::kernel_map_mmio("GICV2 GICC", &gicc_mmio_descriptor)?; ++ ++ // This is safe to do, because it is only called from the init'ed instance itself. ++ fn interrupt_controller_post_init() { ++ generic_exception::asynchronous::register_irq_manager(unsafe { ++ INTERRUPT_CONTROLLER.assume_init_ref() ++ }); ++ } ++ ++ INTERRUPT_CONTROLLER.write(device_driver::GICv2::new( ++ gicd_virt_addr, ++ gicc_virt_addr, ++ interrupt_controller_post_init, ++ )); ++ ++ Ok(()) + } + -+ fn post_early_print_device_driver_init(&self) { - // Configure PL011Uart's output pins. - super::GPIO.map_pl011_uart(); ++ unsafe fn register_drivers(&self) { ++ self.device_drivers.write(|drivers| { ++ drivers[0] = Some(PL011_UART.assume_init_ref()); ++ drivers[1] = Some(GPIO.assume_init_ref()); ++ drivers[2] = Some(INTERRUPT_CONTROLLER.assume_init_ref()); ++ }); ++ } ++} ++ ++//-------------------------------------------------------------------------------------------------- + // Public Code + //-------------------------------------------------------------------------------------------------- + +@@ -58,15 +165,34 @@ + use driver::interface::DeviceDriver; + + impl driver::interface::DriverManager for BSPDriverManager { +- fn all_device_drivers(&self) -> &[&'static (dyn DeviceDriver + Sync)] { +- &self.device_drivers[..] ++ unsafe fn instantiate_drivers(&self) -> Result<(), &'static str> { ++ if self.init_done.load(Ordering::Relaxed) { ++ return Err("Drivers already instantiated"); ++ } ++ ++ self.instantiate_uart()?; ++ self.instantiate_gpio()?; ++ self.instantiate_interrupt_controller()?; ++ ++ self.register_drivers(); ++ ++ self.init_done.store(true, Ordering::Relaxed); ++ Ok(()) } +- fn post_device_driver_init(&self) { +- // Configure PL011Uart's output pins. +- GPIO.map_pl011_uart(); ++ fn all_device_drivers(&self) -> [&(dyn DeviceDriver + Sync); NUM_DRIVERS] { ++ self.device_drivers ++ .read(|drivers| drivers.map(|drivers| drivers.unwrap())) + } + + #[cfg(feature = "test_build")] +- fn qemu_bring_up_console(&self) {} ++ fn qemu_bring_up_console(&self) { ++ use crate::cpu; ++ ++ unsafe { ++ self.instantiate_uart() ++ .unwrap_or_else(|_| cpu::qemu_exit_failure()); ++ console::register_console(PL011_UART.assume_init_ref()); ++ }; ++ } + } + +diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/exception/asynchronous.rs 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/exception/asynchronous.rs +--- 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/exception/asynchronous.rs ++++ 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/exception/asynchronous.rs +@@ -4,7 +4,7 @@ + + //! BSP asynchronous exception handling. + +-use crate::{bsp, bsp::driver, exception}; ++use crate::bsp; + + //-------------------------------------------------------------------------------------------------- + // Public Definitions +@@ -23,14 +23,3 @@ + + pub const PL011_UART: IRQNumber = IRQNumber::new(153); + } +- +-//-------------------------------------------------------------------------------------------------- +-// Public Code +-//-------------------------------------------------------------------------------------------------- +- +-/// Return a reference to the IRQ manager. +-pub fn irq_manager() -> &'static impl exception::asynchronous::interface::IRQManager< +- IRQNumberType = bsp::device_driver::IRQNumber, +-> { +- &driver::INTERRUPT_CONTROLLER +-} + diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/kernel.ld 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/kernel.ld --- 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/kernel.ld +++ 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/kernel.ld @@ -1845,7 +1880,7 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/memory. } //-------------------------------------------------------------------------------------------------- -@@ -50,35 +91,26 @@ +@@ -50,34 +91,23 @@ /// The board's physical memory map. #[rustfmt::skip] pub(super) mod map { @@ -1877,7 +1912,6 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/memory. - pub const PERIPHERAL_INTERRUPT_CONTROLLER_START: usize = START + 0x0000_B200; - pub const GPIO_START: usize = START + GPIO_OFFSET; - pub const PL011_UART_START: usize = START + UART_OFFSET; -- pub const LOCAL_INTERRUPT_CONTROLLER_START: usize = 0x4000_0000; - pub const END_INCLUSIVE: usize = 0x4000_FFFF; + pub const PERIPHERAL_IC_START: Address = Address::new(0x3F00_B200); + pub const PERIPHERAL_IC_SIZE: usize = 0x24; @@ -1888,14 +1922,11 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/memory. + pub const PL011_UART_START: Address = Address::new(0x3F20_1000); + pub const PL011_UART_SIZE: usize = 0x48; + -+ pub const LOCAL_IC_START: Address = Address::new(0x4000_0000); -+ pub const LOCAL_IC_SIZE: usize = 0x100; -+ + pub const END: Address = Address::new(0x4001_0000); } /// Physical devices. -@@ -86,13 +118,22 @@ +@@ -85,13 +115,22 @@ pub mod mmio { use super::*; @@ -1924,7 +1955,7 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/memory. } //-------------------------------------------------------------------------------------------------- -@@ -105,15 +146,76 @@ +@@ -104,15 +143,76 @@ /// /// - Value is provided by the linker script and must be trusted as-is. #[inline(always)] @@ -1932,19 +1963,21 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/memory. - unsafe { __code_start.get() as usize } +fn virt_code_start() -> PageAddress { + PageAddress::from(unsafe { __code_start.get() as usize }) -+} -+ + } + +-/// Exclusive end page address of the code segment. +/// Size of the code segment. +/// -+/// # Safety -+/// -+/// - Value is provided by the linker script and must be trusted as-is. -+#[inline(always)] + /// # Safety + /// + /// - Value is provided by the linker script and must be trusted as-is. + #[inline(always)] +-fn code_end_exclusive() -> usize { +- unsafe { __code_end_exclusive.get() as usize } +fn code_size() -> usize { + unsafe { (__code_end_exclusive.get() as usize) - (__code_start.get() as usize) } - } - --/// Exclusive end page address of the code segment. ++} ++ +/// Start page address of the data segment. +#[inline(always)] +fn virt_data_start() -> PageAddress { @@ -1953,12 +1986,10 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/memory. + +/// Size of the data segment. +/// - /// # Safety - /// - /// - Value is provided by the linker script and must be trusted as-is. - #[inline(always)] --fn code_end_exclusive() -> usize { -- unsafe { __code_end_exclusive.get() as usize } ++/// # Safety ++/// ++/// - Value is provided by the linker script and must be trusted as-is. ++#[inline(always)] +fn data_size() -> usize { + unsafe { (__data_end_exclusive.get() as usize) - (__data_start.get() as usize) } +} @@ -2010,51 +2041,14 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/memory. diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi.rs 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi.rs --- 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi.rs +++ 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi.rs -@@ -10,17 +10,20 @@ - pub mod exception; - pub mod memory; - -+use super::device_driver; -+use crate::memory::mmu::MMIODescriptor; -+use memory::map::mmio; -+ - //-------------------------------------------------------------------------------------------------- - // Global instances - //-------------------------------------------------------------------------------------------------- --use super::device_driver; - - static GPIO: device_driver::GPIO = -- unsafe { device_driver::GPIO::new(memory::map::mmio::GPIO_START) }; -+ unsafe { device_driver::GPIO::new(MMIODescriptor::new(mmio::GPIO_START, mmio::GPIO_SIZE)) }; - - static PL011_UART: device_driver::PL011Uart = unsafe { - device_driver::PL011Uart::new( -- memory::map::mmio::PL011_UART_START, -+ MMIODescriptor::new(mmio::PL011_UART_START, mmio::PL011_UART_SIZE), - exception::asynchronous::irq_map::PL011_UART, - ) - }; -@@ -28,14 +31,17 @@ - #[cfg(feature = "bsp_rpi3")] - static INTERRUPT_CONTROLLER: device_driver::InterruptController = unsafe { - device_driver::InterruptController::new( -- memory::map::mmio::LOCAL_INTERRUPT_CONTROLLER_START, -- memory::map::mmio::PERIPHERAL_INTERRUPT_CONTROLLER_START, -+ MMIODescriptor::new(mmio::LOCAL_IC_START, mmio::LOCAL_IC_SIZE), -+ MMIODescriptor::new(mmio::PERIPHERAL_IC_START, mmio::PERIPHERAL_IC_SIZE), - ) - }; +@@ -4,7 +4,6 @@ - #[cfg(feature = "bsp_rpi4")] - static INTERRUPT_CONTROLLER: device_driver::GICv2 = unsafe { -- device_driver::GICv2::new(memory::map::mmio::GICD_START, memory::map::mmio::GICC_START) -+ device_driver::GICv2::new( -+ MMIODescriptor::new(mmio::GICD_START, mmio::GICD_SIZE), -+ MMIODescriptor::new(mmio::GICC_START, mmio::GICC_SIZE), -+ ) - }; + //! Top-level BSP file for the Raspberry Pi 3 and 4. - //-------------------------------------------------------------------------------------------------- +-pub mod console; + pub mod cpu; + pub mod driver; + pub mod exception; diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/common.rs 14_virtual_mem_part2_mmio_remap/kernel/src/common.rs --- 13_exceptions_part2_peripheral_IRQs/kernel/src/common.rs @@ -2090,65 +2084,258 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/common.rs 14_virtual_me + (value + alignment - 1) & !(alignment - 1) +} +diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/console/null_console.rs 14_virtual_mem_part2_mmio_remap/kernel/src/console/null_console.rs +--- 13_exceptions_part2_peripheral_IRQs/kernel/src/console/null_console.rs ++++ 14_virtual_mem_part2_mmio_remap/kernel/src/console/null_console.rs +@@ -0,0 +1,41 @@ ++// SPDX-License-Identifier: MIT OR Apache-2.0 ++// ++// Copyright (c) 2022 Andre Richter ++ ++//! Null console. ++ ++use super::interface; ++use core::fmt; ++ ++//-------------------------------------------------------------------------------------------------- ++// Public Definitions ++//-------------------------------------------------------------------------------------------------- ++ ++pub struct NullConsole; ++ ++//-------------------------------------------------------------------------------------------------- ++// Global instances ++//-------------------------------------------------------------------------------------------------- ++ ++pub static NULL_CONSOLE: NullConsole = NullConsole {}; ++ ++//-------------------------------------------------------------------------------------------------- ++// Private Code ++//-------------------------------------------------------------------------------------------------- ++ ++impl interface::Write for NullConsole { ++ fn write_char(&self, _c: char) {} ++ ++ fn write_fmt(&self, _args: fmt::Arguments) -> fmt::Result { ++ fmt::Result::Ok(()) ++ } ++ ++ fn flush(&self) {} ++} ++ ++impl interface::Read for NullConsole { ++ fn clear_rx(&self) {} ++} ++ ++impl interface::Statistics for NullConsole {} ++impl interface::All for NullConsole {} + +diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/console.rs 14_virtual_mem_part2_mmio_remap/kernel/src/console.rs +--- 13_exceptions_part2_peripheral_IRQs/kernel/src/console.rs ++++ 14_virtual_mem_part2_mmio_remap/kernel/src/console.rs +@@ -4,7 +4,9 @@ + + //! System console. + +-use crate::bsp; ++mod null_console; ++ ++use crate::synchronization; + + //-------------------------------------------------------------------------------------------------- + // Public Definitions +@@ -55,12 +57,25 @@ + } + + //-------------------------------------------------------------------------------------------------- ++// Global instances ++//-------------------------------------------------------------------------------------------------- ++ ++static CUR_CONSOLE: InitStateLock<&'static (dyn interface::All + Sync)> = ++ InitStateLock::new(&null_console::NULL_CONSOLE); ++ ++//-------------------------------------------------------------------------------------------------- + // Public Code + //-------------------------------------------------------------------------------------------------- ++use synchronization::{interface::ReadWriteEx, InitStateLock}; ++ ++/// Register a new console. ++pub fn register_console(new_console: &'static (dyn interface::All + Sync)) { ++ CUR_CONSOLE.write(|con| *con = new_console); ++} + +-/// Return a reference to the console. ++/// Return a reference to the currently registered console. + /// + /// This is the global console used by all printing macros. + pub fn console() -> &'static dyn interface::All { +- bsp::console::console() ++ CUR_CONSOLE.read(|con| *con) + } + diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/driver.rs 14_virtual_mem_part2_mmio_remap/kernel/src/driver.rs --- 13_exceptions_part2_peripheral_IRQs/kernel/src/driver.rs +++ 14_virtual_mem_part2_mmio_remap/kernel/src/driver.rs -@@ -31,6 +31,14 @@ - fn register_and_enable_irq_handler(&'static self) -> Result<(), &'static str> { - Ok(()) - } -+ -+ /// After MMIO remapping, returns the new virtual start address. -+ /// -+ /// This API assumes a driver has only a single, contiguous MMIO aperture, which will not be -+ /// the case for more complex devices. This API will likely change in future tutorials. -+ fn virt_mmio_start_addr(&self) -> Option { -+ None -+ } - } +@@ -10,6 +10,8 @@ - /// Device driver management functions. -@@ -38,15 +46,17 @@ + /// Driver interfaces. + pub mod interface { ++ use crate::bsp; ++ + /// Device Driver functions. + pub trait DeviceDriver { + /// Return a compatibility string for identifying the driver. +@@ -37,17 +39,15 @@ + /// /// The `BSP` is supposed to supply one global instance. pub trait DriverManager { - /// Return a slice of references to all `BSP`-instantiated drivers. -- /// -- /// # Safety -- /// +- /// Return a slice of references to all `BSP`-instantiated drivers. ++ /// Instantiate all drivers. + /// + /// # Safety + /// - /// - The order of devices is the order in which `DeviceDriver::init()` is called. - fn all_device_drivers(&self) -> &[&'static (dyn DeviceDriver + Sync)]; +- fn all_device_drivers(&self) -> &[&'static (dyn DeviceDriver + Sync)]; ++ /// Must be called before `all_device_drivers`. ++ unsafe fn instantiate_drivers(&self) -> Result<(), &'static str>; - /// Initialization code that runs after driver init. -+ /// Return only those drivers needed for the BSP's early printing functionality. - /// +- /// - /// For example, device driver code that depends on other drivers already being online. - fn post_device_driver_init(&self); -+ /// For example, the default UART. -+ fn early_print_device_drivers(&self) -> &[&'static (dyn DeviceDriver + Sync)]; ++ /// Return a slice of references to all `BSP`-instantiated drivers. ++ fn all_device_drivers(&self) -> [&(dyn DeviceDriver + Sync); bsp::driver::NUM_DRIVERS]; + + /// Minimal code needed to bring up the console in QEMU (for testing only). This is often + /// less steps than on real hardware due to QEMU's abstractions. + +diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/exception/asynchronous/null_irq_manager.rs 14_virtual_mem_part2_mmio_remap/kernel/src/exception/asynchronous/null_irq_manager.rs +--- 13_exceptions_part2_peripheral_IRQs/kernel/src/exception/asynchronous/null_irq_manager.rs ++++ 14_virtual_mem_part2_mmio_remap/kernel/src/exception/asynchronous/null_irq_manager.rs +@@ -0,0 +1,44 @@ ++// SPDX-License-Identifier: MIT OR Apache-2.0 ++// ++// Copyright (c) 2022 Andre Richter ++ ++//! Null IRQ Manager. ++ ++use super::{interface, IRQContext, IRQDescriptor}; ++use crate::bsp; ++ ++//-------------------------------------------------------------------------------------------------- ++// Public Definitions ++//-------------------------------------------------------------------------------------------------- ++ ++pub struct NullIRQManager; ++ ++//-------------------------------------------------------------------------------------------------- ++// Global instances ++//-------------------------------------------------------------------------------------------------- ++ ++pub static NULL_IRQ_MANAGER: NullIRQManager = NullIRQManager {}; ++ ++//-------------------------------------------------------------------------------------------------- ++// Public Code ++//-------------------------------------------------------------------------------------------------- ++ ++impl interface::IRQManager for NullIRQManager { ++ type IRQNumberType = bsp::driver::IRQNumber; ++ ++ fn register_handler( ++ &self, ++ _irq_number: Self::IRQNumberType, ++ _descriptor: IRQDescriptor, ++ ) -> Result<(), &'static str> { ++ panic!("No IRQ Manager registered yet"); ++ } + -+ /// Return all drivers minus early-print drivers. -+ fn non_early_print_device_drivers(&self) -> &[&'static (dyn DeviceDriver + Sync)]; ++ fn enable(&self, _irq_number: Self::IRQNumberType) { ++ panic!("No IRQ Manager registered yet"); ++ } + -+ /// Initialization code that runs after the early print driver init. -+ fn post_early_print_device_driver_init(&self); ++ fn handle_pending_irqs<'irq_context>(&'irq_context self, _ic: &IRQContext<'irq_context>) { ++ panic!("No IRQ Manager registered yet"); ++ } ++} + +diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/exception/asynchronous.rs 14_virtual_mem_part2_mmio_remap/kernel/src/exception/asynchronous.rs +--- 13_exceptions_part2_peripheral_IRQs/kernel/src/exception/asynchronous.rs ++++ 14_virtual_mem_part2_mmio_remap/kernel/src/exception/asynchronous.rs +@@ -7,8 +7,9 @@ + #[cfg(target_arch = "aarch64")] + #[path = "../_arch/aarch64/exception/asynchronous.rs"] + mod arch_asynchronous; ++mod null_irq_manager; + +-use crate::bsp; ++use crate::{bsp, synchronization}; + use core::{fmt, marker::PhantomData}; + + //-------------------------------------------------------------------------------------------------- +@@ -86,7 +87,7 @@ + ); + + /// Print list of registered handlers. +- fn print_handler(&self); ++ fn print_handler(&self) {} } } +@@ -95,8 +96,17 @@ + pub struct IRQNumber(usize); + + //-------------------------------------------------------------------------------------------------- ++// Global instances ++//-------------------------------------------------------------------------------------------------- ++ ++static CUR_IRQ_MANAGER: InitStateLock< ++ &'static (dyn interface::IRQManager + Sync), ++> = InitStateLock::new(&null_irq_manager::NULL_IRQ_MANAGER); ++ ++//-------------------------------------------------------------------------------------------------- + // Public Code + //-------------------------------------------------------------------------------------------------- ++use synchronization::{interface::ReadWriteEx, InitStateLock}; + + impl<'irq_context> IRQContext<'irq_context> { + /// Creates an IRQContext token. +@@ -152,9 +162,17 @@ + ret + } + +-/// Return a reference to the IRQ manager. ++/// Register a new IRQ manager. ++pub fn register_irq_manager( ++ new_manager: &'static (dyn interface::IRQManager ++ + Sync), ++) { ++ CUR_IRQ_MANAGER.write(|manager| *manager = new_manager); ++} ++ ++/// Return a reference to the currently registered IRQ manager. + /// + /// This is the IRQ manager used by the architectural interrupt handling code. + pub fn irq_manager() -> &'static dyn interface::IRQManager { +- bsp::exception::asynchronous::irq_manager() ++ CUR_IRQ_MANAGER.read(|manager| *manager) + } + diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/lib.rs 14_virtual_mem_part2_mmio_remap/kernel/src/lib.rs --- 13_exceptions_part2_peripheral_IRQs/kernel/src/lib.rs +++ 14_virtual_mem_part2_mmio_remap/kernel/src/lib.rs -@@ -113,8 +113,10 @@ +@@ -113,8 +113,11 @@ #![feature(asm_const)] #![feature(core_intrinsics)] #![feature(format_args_nl)] +#![feature(generic_const_exprs)] ++#![feature(is_sorted)] #![feature(linkage)] #![feature(panic_info_message)] +#![feature(step_trait)] #![feature(trait_alias)] #![no_std] // Testing -@@ -127,6 +129,7 @@ +@@ -127,6 +130,7 @@ mod synchronization; pub mod bsp; @@ -2156,19 +2343,32 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/lib.rs 14_virtual_mem_p pub mod console; pub mod cpu; pub mod driver; -@@ -179,6 +182,7 @@ - #[no_mangle] - unsafe fn kernel_init() -> ! { +@@ -181,7 +185,20 @@ + use driver::interface::DriverManager; + exception::handling_init(); ++ ++ let phys_kernel_tables_base_addr = match memory::mmu::kernel_map_binary() { ++ Err(string) => panic!("Error mapping kernel binary: {}", string), ++ Ok(addr) => addr, ++ }; ++ ++ if let Err(e) = memory::mmu::enable_mmu_and_caching(phys_kernel_tables_base_addr) { ++ panic!("Enabling MMU failed: {}", e); ++ } ++ // Printing will silently fail from here on, because the driver's MMIO is not remapped yet. ++ + memory::mmu::post_enable_init(); - bsp::console::qemu_bring_up_console(); + bsp::driver::driver_manager().qemu_bring_up_console(); ++ // Printing available again from here on. test_main(); + diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/main.rs 14_virtual_mem_part2_mmio_remap/kernel/src/main.rs --- 13_exceptions_part2_peripheral_IRQs/kernel/src/main.rs +++ 14_virtual_mem_part2_mmio_remap/kernel/src/main.rs -@@ -27,21 +27,41 @@ +@@ -27,21 +27,31 @@ #[no_mangle] unsafe fn kernel_init() -> ! { use driver::interface::DriverManager; @@ -2185,38 +2385,32 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/main.rs 14_virtual_mem_ + + if let Err(e) = memory::mmu::enable_mmu_and_caching(phys_kernel_tables_base_addr) { + panic!("Enabling MMU failed: {}", e); -+ } + } + // Printing will silently fail from here on, because the driver's MMIO is not remapped yet. + + memory::mmu::post_enable_init(); -+ -+ // Bring up the drivers needed for printing first. -+ for i in bsp::driver::driver_manager() -+ .early_print_device_drivers() -+ .iter() -+ { -+ // Any encountered errors cannot be printed yet, obviously, so just safely park the CPU. -+ i.init().unwrap_or_else(|_| cpu::wait_forever()); - } -+ bsp::driver::driver_manager().post_early_print_device_driver_init(); -+ // Printing available again from here on. -- for i in bsp::driver::driver_manager().all_device_drivers().iter() { -+ // Now bring up the remaining drivers. -+ for i in bsp::driver::driver_manager() -+ .non_early_print_device_drivers() -+ .iter() -+ { ++ // Instantiate and init all device drivers. ++ if let Err(x) = bsp::driver::driver_manager().instantiate_drivers() { ++ panic!("Error instantiating drivers: {}", x); ++ } + for i in bsp::driver::driver_manager().all_device_drivers().iter() { if let Err(x) = i.init() { panic!("Error loading driver: {}: {}", i.compatible(), x); } } - bsp::driver::driver_manager().post_device_driver_init(); - // println! is usable from here on. ++ // Printing available again from here on. // Let device drivers register and enable their handlers with the interrupt controller. for i in bsp::driver::driver_manager().all_device_drivers() { -@@ -68,8 +88,8 @@ +@@ -63,13 +73,12 @@ + /// The main function running after the early init. + fn kernel_main() -> ! { + use driver::interface::DriverManager; +- use exception::asynchronous::interface::IRQManager; + info!("{}", libkernel::version()); info!("Booting on: {}", bsp::board_name()); @@ -2227,11 +2421,20 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/main.rs 14_virtual_mem_ let (_, privilege_level) = exception::current_privilege_level(); info!("Current privilege level: {}", privilege_level); +@@ -92,7 +101,7 @@ + } + + info!("Registered IRQ handlers:"); +- bsp::exception::asynchronous::irq_manager().print_handler(); ++ exception::asynchronous::irq_manager().print_handler(); + + info!("Echoing input now"); + cpu::wait_forever(); diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/memory/mmu/mapping_record.rs 14_virtual_mem_part2_mmio_remap/kernel/src/memory/mmu/mapping_record.rs --- 13_exceptions_part2_peripheral_IRQs/kernel/src/memory/mmu/mapping_record.rs +++ 14_virtual_mem_part2_mmio_remap/kernel/src/memory/mmu/mapping_record.rs -@@ -0,0 +1,233 @@ +@@ -0,0 +1,249 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2020-2022 Andre Richter @@ -2310,6 +2513,19 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/memory/mmu/mapping_reco + Self { inner: [None; 12] } + } + ++ fn size(&self) -> usize { ++ self.inner.iter().filter(|x| x.is_some()).count() ++ } ++ ++ fn sort(&mut self) { ++ let upper_bound_exclusive = self.size(); ++ let entries = &mut self.inner[0..upper_bound_exclusive]; ++ ++ if !entries.is_sorted_by_key(|item| item.unwrap().virt_start_addr) { ++ entries.sort_unstable_by_key(|item| item.unwrap().virt_start_addr) ++ } ++ } ++ + fn find_next_free(&mut self) -> Result<&mut Option, &'static str> { + if let Some(x) = self.inner.iter_mut().find(|x| x.is_none()) { + return Ok(x); @@ -2355,6 +2571,9 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/memory/mmu/mapping_reco + phys_region, + attr, + )); ++ ++ self.sort(); ++ + Ok(()) + } + @@ -3446,18 +3665,18 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/memory.rs 14_virtual_me +//-------------------------------------------------------------------------------------------------- + +/// Metadata trait for marking the type of an address. -+pub trait AddressType: Copy + Clone + PartialOrd + PartialEq {} ++pub trait AddressType: Copy + Clone + PartialOrd + PartialEq + Ord + Eq {} + +/// Zero-sized type to mark a physical address. -+#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)] ++#[derive(Copy, Clone, Debug, PartialOrd, PartialEq, Ord, Eq)] +pub enum Physical {} + +/// Zero-sized type to mark a virtual address. -+#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)] ++#[derive(Copy, Clone, Debug, PartialOrd, PartialEq, Ord, Eq)] +pub enum Virtual {} + +/// Generic address type. -+#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)] ++#[derive(Copy, Clone, Debug, PartialOrd, PartialEq, Ord, Eq)] +pub struct Address { + value: usize, + _address_type: PhantomData ATYPE>, @@ -3594,18 +3813,85 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/memory.rs 14_virtual_me + } +} +diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/tests/00_console_sanity.rs 14_virtual_mem_part2_mmio_remap/kernel/tests/00_console_sanity.rs +--- 13_exceptions_part2_peripheral_IRQs/kernel/tests/00_console_sanity.rs ++++ 14_virtual_mem_part2_mmio_remap/kernel/tests/00_console_sanity.rs +@@ -11,7 +11,7 @@ + /// Console tests should time out on the I/O harness in case of panic. + mod panic_wait_forever; + +-use libkernel::{bsp, console, cpu, driver, exception, print}; ++use libkernel::{bsp, console, cpu, driver, exception, memory, print}; + + #[no_mangle] + unsafe fn kernel_init() -> ! { +@@ -19,7 +19,20 @@ + use driver::interface::DriverManager; + + exception::handling_init(); ++ ++ let phys_kernel_tables_base_addr = match memory::mmu::kernel_map_binary() { ++ Err(string) => panic!("Error mapping kernel binary: {}", string), ++ Ok(addr) => addr, ++ }; ++ ++ if let Err(e) = memory::mmu::enable_mmu_and_caching(phys_kernel_tables_base_addr) { ++ panic!("Enabling MMU failed: {}", e); ++ } ++ // Printing will silently fail from here on, because the driver's MMIO is not remapped yet. ++ ++ memory::mmu::post_enable_init(); + bsp::driver::driver_manager().qemu_bring_up_console(); ++ // Printing available again from here on. + + // Handshake + assert_eq!(console().read_char(), 'A'); + +diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/tests/01_timer_sanity.rs 14_virtual_mem_part2_mmio_remap/kernel/tests/01_timer_sanity.rs +--- 13_exceptions_part2_peripheral_IRQs/kernel/tests/01_timer_sanity.rs ++++ 14_virtual_mem_part2_mmio_remap/kernel/tests/01_timer_sanity.rs +@@ -11,7 +11,7 @@ + #![test_runner(libkernel::test_runner)] + + use core::time::Duration; +-use libkernel::{bsp, cpu, driver, exception, time, time::interface::TimeManager}; ++use libkernel::{bsp, cpu, driver, exception, memory, time, time::interface::TimeManager}; + use test_macros::kernel_test; + + #[no_mangle] +@@ -19,7 +19,20 @@ + use driver::interface::DriverManager; + + exception::handling_init(); ++ ++ let phys_kernel_tables_base_addr = match memory::mmu::kernel_map_binary() { ++ Err(string) => panic!("Error mapping kernel binary: {}", string), ++ Ok(addr) => addr, ++ }; ++ ++ if let Err(e) = memory::mmu::enable_mmu_and_caching(phys_kernel_tables_base_addr) { ++ panic!("Enabling MMU failed: {}", e); ++ } ++ // Printing will silently fail from here on, because the driver's MMIO is not remapped yet. ++ ++ memory::mmu::post_enable_init(); + bsp::driver::driver_manager().qemu_bring_up_console(); ++ // Printing available again from here on. + + // Depending on CPU arch, some timer bring-up code could go here. Not needed for the RPi. + + diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/tests/02_exception_sync_page_fault.rs 14_virtual_mem_part2_mmio_remap/kernel/tests/02_exception_sync_page_fault.rs --- 13_exceptions_part2_peripheral_IRQs/kernel/tests/02_exception_sync_page_fault.rs +++ 14_virtual_mem_part2_mmio_remap/kernel/tests/02_exception_sync_page_fault.rs -@@ -21,18 +21,40 @@ - +@@ -22,18 +22,29 @@ #[no_mangle] unsafe fn kernel_init() -> ! { + use driver::interface::DriverManager; - use memory::mmu::interface::MMU; -+ use libkernel::driver::interface::DriverManager; exception::handling_init(); -- bsp::console::qemu_bring_up_console(); +- bsp::driver::driver_manager().qemu_bring_up_console(); // This line will be printed as the test header. println!("Testing synchronous exception handling by causing a page fault"); @@ -3627,17 +3913,7 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/tests/02_exception_sync_pag + // Printing will silently fail from here on, because the driver's MMIO is not remapped yet. + + memory::mmu::post_enable_init(); -+ bsp::console::qemu_bring_up_console(); -+ -+ // Bring up the drivers needed for printing first. -+ for i in bsp::driver::driver_manager() -+ .early_print_device_drivers() -+ .iter() -+ { -+ // Any encountered errors cannot be printed yet, obviously, so just safely park the CPU. -+ i.init().unwrap_or_else(|_| cpu::qemu_exit_failure()); -+ } -+ bsp::driver::driver_manager().post_early_print_device_driver_init(); ++ bsp::driver::driver_manager().qemu_bring_up_console(); + // Printing available again from here on. info!("Writing beyond mapped area to address 9 GiB..."); @@ -3646,15 +3922,14 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/tests/02_exception_sync_pag diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/tests/03_exception_restore_sanity.rs 14_virtual_mem_part2_mmio_remap/kernel/tests/03_exception_restore_sanity.rs --- 13_exceptions_part2_peripheral_IRQs/kernel/tests/03_exception_restore_sanity.rs +++ 14_virtual_mem_part2_mmio_remap/kernel/tests/03_exception_restore_sanity.rs -@@ -30,18 +30,40 @@ - +@@ -31,18 +31,29 @@ #[no_mangle] unsafe fn kernel_init() -> ! { + use driver::interface::DriverManager; - use memory::mmu::interface::MMU; -+ use libkernel::driver::interface::DriverManager; exception::handling_init(); -- bsp::console::qemu_bring_up_console(); +- bsp::driver::driver_manager().qemu_bring_up_console(); // This line will be printed as the test header. println!("Testing exception restore"); @@ -3676,19 +3951,46 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/tests/03_exception_restore_ + // Printing will silently fail from here on, because the driver's MMIO is not remapped yet. + + memory::mmu::post_enable_init(); -+ bsp::console::qemu_bring_up_console(); ++ bsp::driver::driver_manager().qemu_bring_up_console(); ++ // Printing available again from here on. + + info!("Making a dummy system call"); + + +diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/tests/04_exception_irq_sanity.rs 14_virtual_mem_part2_mmio_remap/kernel/tests/04_exception_irq_sanity.rs +--- 13_exceptions_part2_peripheral_IRQs/kernel/tests/04_exception_irq_sanity.rs ++++ 14_virtual_mem_part2_mmio_remap/kernel/tests/04_exception_irq_sanity.rs +@@ -10,15 +10,29 @@ + #![reexport_test_harness_main = "test_main"] + #![test_runner(libkernel::test_runner)] + +-use libkernel::{bsp, cpu, driver, exception}; ++use libkernel::{bsp, cpu, driver, exception, memory}; + use test_macros::kernel_test; + + #[no_mangle] + unsafe fn kernel_init() -> ! { + use driver::interface::DriverManager; +- bsp::driver::driver_manager().qemu_bring_up_console(); + + exception::handling_init(); + -+ // Bring up the drivers needed for printing first. -+ for i in bsp::driver::driver_manager() -+ .early_print_device_drivers() -+ .iter() -+ { -+ // Any encountered errors cannot be printed yet, obviously, so just safely park the CPU. -+ i.init().unwrap_or_else(|_| cpu::qemu_exit_failure()); ++ let phys_kernel_tables_base_addr = match memory::mmu::kernel_map_binary() { ++ Err(string) => panic!("Error mapping kernel binary: {}", string), ++ Ok(addr) => addr, ++ }; ++ ++ if let Err(e) = memory::mmu::enable_mmu_and_caching(phys_kernel_tables_base_addr) { ++ panic!("Enabling MMU failed: {}", e); + } -+ bsp::driver::driver_manager().post_early_print_device_driver_init(); ++ // Printing will silently fail from here on, because the driver's MMIO is not remapped yet. ++ ++ memory::mmu::post_enable_init(); ++ bsp::driver::driver_manager().qemu_bring_up_console(); + // Printing available again from here on. ++ + exception::asynchronous::local_irq_unmask(); - info!("Making a dummy system call"); + test_main(); ``` diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/exception.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/exception.rs index 662c91b9..fa6748a6 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/exception.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/exception.rs @@ -11,7 +11,7 @@ //! //! crate::exception::arch_exception -use crate::{bsp, exception}; +use crate::exception; use core::{arch::global_asm, cell::UnsafeCell, fmt}; use cortex_a::{asm::barrier, registers::*}; use tock_registers::{ @@ -104,10 +104,8 @@ unsafe extern "C" fn current_elx_synchronous(e: &mut ExceptionContext) { #[no_mangle] unsafe extern "C" fn current_elx_irq(_e: &mut ExceptionContext) { - use exception::asynchronous::interface::IRQManager; - let token = &exception::asynchronous::IRQContext::new(); - bsp::exception::asynchronous::irq_manager().handle_pending_irqs(token); + exception::asynchronous::irq_manager().handle_pending_irqs(token); } #[no_mangle] diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/arm/gicv2.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/arm/gicv2.rs index 4c68a692..e72fde7b 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/arm/gicv2.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/arm/gicv2.rs @@ -79,8 +79,12 @@ mod gicc; mod gicd; -use crate::{bsp, cpu, driver, exception, memory, synchronization, synchronization::InitStateLock}; -use core::sync::atomic::{AtomicBool, Ordering}; +use crate::{ + bsp, cpu, driver, exception, + memory::{Address, Virtual}, + synchronization, + synchronization::InitStateLock, +}; //-------------------------------------------------------------------------------------------------- // Private Definitions @@ -97,20 +101,17 @@ pub type IRQNumber = exception::asynchronous::IRQNumber<{ GICv2::MAX_IRQ_NUMBER /// Representation of the GIC. pub struct GICv2 { - gicd_mmio_descriptor: memory::mmu::MMIODescriptor, - gicc_mmio_descriptor: memory::mmu::MMIODescriptor, - /// The Distributor. gicd: gicd::GICD, /// The CPU Interface. gicc: gicc::GICC, - /// Have the MMIO regions been remapped yet? - is_mmio_remapped: AtomicBool, - /// Stores registered IRQ handlers. Writable only during kernel init. RO afterwards. handler_table: InitStateLock, + + /// Callback to be invoked after successful init. + post_init_callback: fn(), } //-------------------------------------------------------------------------------------------------- @@ -121,22 +122,23 @@ impl GICv2 { const MAX_IRQ_NUMBER: usize = 300; // Normally 1019, but keep it lower to save some space. const NUM_IRQS: usize = Self::MAX_IRQ_NUMBER + 1; + pub const COMPATIBLE: &'static str = "GICv2 (ARM Generic Interrupt Controller v2)"; + /// Create an instance. /// /// # Safety /// - /// - The user must ensure to provide correct MMIO descriptors. + /// - The user must ensure to provide a correct MMIO start address. pub const unsafe fn new( - gicd_mmio_descriptor: memory::mmu::MMIODescriptor, - gicc_mmio_descriptor: memory::mmu::MMIODescriptor, + gicd_mmio_start_addr: Address, + gicc_mmio_start_addr: Address, + post_init_callback: fn(), ) -> Self { Self { - gicd_mmio_descriptor, - gicc_mmio_descriptor, - gicd: gicd::GICD::new(gicd_mmio_descriptor.start_addr().as_usize()), - gicc: gicc::GICC::new(gicc_mmio_descriptor.start_addr().as_usize()), - is_mmio_remapped: AtomicBool::new(false), + gicd: gicd::GICD::new(gicd_mmio_start_addr), + gicc: gicc::GICC::new(gicc_mmio_start_addr), handler_table: InitStateLock::new([None; Self::NUM_IRQS]), + post_init_callback, } } } @@ -148,24 +150,10 @@ use synchronization::interface::ReadWriteEx; impl driver::interface::DeviceDriver for GICv2 { fn compatible(&self) -> &'static str { - "GICv2 (ARM Generic Interrupt Controller v2)" + Self::COMPATIBLE } unsafe fn init(&self) -> Result<(), &'static str> { - let remapped = self.is_mmio_remapped.load(Ordering::Relaxed); - if !remapped { - // GICD - let mut virt_addr = memory::mmu::kernel_map_mmio("GICD", &self.gicd_mmio_descriptor)?; - self.gicd.set_mmio(virt_addr.as_usize()); - - // GICC - virt_addr = memory::mmu::kernel_map_mmio("GICC", &self.gicc_mmio_descriptor)?; - self.gicc.set_mmio(virt_addr.as_usize()); - - // Conclude remapping. - self.is_mmio_remapped.store(true, Ordering::Relaxed); - } - if bsp::cpu::BOOT_CORE_ID == cpu::smp::core_id() { self.gicd.boot_core_init(); } @@ -173,6 +161,8 @@ impl driver::interface::DeviceDriver for GICv2 { self.gicc.priority_accept_all(); self.gicc.enable(); + (self.post_init_callback)(); + Ok(()) } } diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/arm/gicv2/gicc.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/arm/gicv2/gicc.rs index 1a151d24..1a02fc65 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/arm/gicv2/gicc.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/arm/gicv2/gicc.rs @@ -5,7 +5,9 @@ //! GICC Driver - GIC CPU interface. use crate::{ - bsp::device_driver::common::MMIODerefWrapper, exception, synchronization::InitStateLock, + bsp::device_driver::common::MMIODerefWrapper, + exception, + memory::{Address, Virtual}, }; use tock_registers::{ interfaces::{Readable, Writeable}, @@ -62,13 +64,12 @@ type Registers = MMIODerefWrapper; /// Representation of the GIC CPU interface. pub struct GICC { - registers: InitStateLock, + registers: Registers, } //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- -use crate::synchronization::interface::ReadWriteEx; impl GICC { /// Create an instance. @@ -76,17 +77,12 @@ impl GICC { /// # Safety /// /// - The user must ensure to provide a correct MMIO start address. - pub const unsafe fn new(mmio_start_addr: usize) -> Self { + pub const unsafe fn new(mmio_start_addr: Address) -> Self { Self { - registers: InitStateLock::new(Registers::new(mmio_start_addr)), + registers: Registers::new(mmio_start_addr), } } - pub unsafe fn set_mmio(&self, new_mmio_start_addr: usize) { - self.registers - .write(|regs| *regs = Registers::new(new_mmio_start_addr)); - } - /// Accept interrupts of any priority. /// /// Quoting the GICv2 Architecture Specification: @@ -99,9 +95,7 @@ impl GICC { /// - GICC MMIO registers are banked per CPU core. It is therefore safe to have `&self` instead /// of `&mut self`. pub fn priority_accept_all(&self) { - self.registers.read(|regs| { - regs.PMR.write(PMR::Priority.val(255)); // Comment in arch spec. - }); + self.registers.PMR.write(PMR::Priority.val(255)); // Comment in arch spec. } /// Enable the interface - start accepting IRQs. @@ -111,9 +105,7 @@ impl GICC { /// - GICC MMIO registers are banked per CPU core. It is therefore safe to have `&self` instead /// of `&mut self`. pub fn enable(&self) { - self.registers.read(|regs| { - regs.CTLR.write(CTLR::Enable::SET); - }); + self.registers.CTLR.write(CTLR::Enable::SET); } /// Extract the number of the highest-priority pending IRQ. @@ -129,8 +121,7 @@ impl GICC { &self, _ic: &exception::asynchronous::IRQContext<'irq_context>, ) -> usize { - self.registers - .read(|regs| regs.IAR.read(IAR::InterruptID) as usize) + self.registers.IAR.read(IAR::InterruptID) as usize } /// Complete handling of the currently active IRQ. @@ -149,8 +140,6 @@ impl GICC { irq_number: u32, _ic: &exception::asynchronous::IRQContext<'irq_context>, ) { - self.registers.read(|regs| { - regs.EOIR.write(EOIR::EOIINTID.val(irq_number)); - }); + self.registers.EOIR.write(EOIR::EOIINTID.val(irq_number)); } } diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs index 60bbc468..d9f63d1b 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs @@ -9,8 +9,9 @@ use crate::{ bsp::device_driver::common::MMIODerefWrapper, + memory::{Address, Virtual}, state, synchronization, - synchronization::{IRQSafeNullLock, InitStateLock}, + synchronization::IRQSafeNullLock, }; use tock_registers::{ interfaces::{Readable, Writeable}, @@ -84,7 +85,7 @@ pub struct GICD { shared_registers: IRQSafeNullLock, /// Access to banked registers is unguarded. - banked_registers: InitStateLock, + banked_registers: BankedRegisters, } //-------------------------------------------------------------------------------------------------- @@ -121,7 +122,6 @@ impl SharedRegisters { //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- -use crate::synchronization::interface::ReadWriteEx; use synchronization::interface::Mutex; impl GICD { @@ -130,20 +130,13 @@ impl GICD { /// # Safety /// /// - The user must ensure to provide a correct MMIO start address. - pub const unsafe fn new(mmio_start_addr: usize) -> Self { + pub const unsafe fn new(mmio_start_addr: Address) -> Self { Self { shared_registers: IRQSafeNullLock::new(SharedRegisters::new(mmio_start_addr)), - banked_registers: InitStateLock::new(BankedRegisters::new(mmio_start_addr)), + banked_registers: BankedRegisters::new(mmio_start_addr), } } - pub unsafe fn set_mmio(&self, new_mmio_start_addr: usize) { - self.shared_registers - .lock(|regs| *regs = SharedRegisters::new(new_mmio_start_addr)); - self.banked_registers - .write(|regs| *regs = BankedRegisters::new(new_mmio_start_addr)); - } - /// Use a banked ITARGETSR to retrieve the executing core's GIC target mask. /// /// Quoting the GICv2 Architecture Specification: @@ -151,8 +144,7 @@ impl GICD { /// "GICD_ITARGETSR0 to GICD_ITARGETSR7 are read-only, and each field returns a value that /// corresponds only to the processor reading the register." fn local_gic_target_mask(&self) -> u32 { - self.banked_registers - .read(|regs| regs.ITARGETSR[0].read(ITARGETSR::Offset0)) + self.banked_registers.ITARGETSR[0].read(ITARGETSR::Offset0) } /// Route all SPIs to the boot core and enable the distributor. @@ -191,10 +183,10 @@ impl GICD { // Check if we are handling a private or shared IRQ. match irq_num { // Private. - 0..=31 => self.banked_registers.read(|regs| { - let enable_reg = ®s.ISENABLER; + 0..=31 => { + let enable_reg = &self.banked_registers.ISENABLER; enable_reg.set(enable_reg.get() | enable_bit); - }), + } // Shared. _ => { let enable_reg_index_shared = enable_reg_index - 1; diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs index eea07b75..a3361c2c 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs @@ -5,10 +5,12 @@ //! GPIO Driver. use crate::{ - bsp::device_driver::common::MMIODerefWrapper, driver, memory, synchronization, + bsp::device_driver::common::MMIODerefWrapper, + driver, + memory::{Address, Virtual}, + synchronization, synchronization::IRQSafeNullLock, }; -use core::sync::atomic::{AtomicUsize, Ordering}; use tock_registers::{ interfaces::{ReadWriteable, Writeable}, register_bitfields, register_structs, @@ -109,26 +111,22 @@ register_structs! { /// Abstraction for the associated MMIO registers. type Registers = MMIODerefWrapper; -//-------------------------------------------------------------------------------------------------- -// Public Definitions -//-------------------------------------------------------------------------------------------------- - -pub struct GPIOInner { +struct GPIOInner { registers: Registers, } -// Export the inner struct so that BSPs can use it for the panic handler. -pub use GPIOInner as PanicGPIO; +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- /// Representation of the GPIO HW. pub struct GPIO { - mmio_descriptor: memory::mmu::MMIODescriptor, - virt_mmio_start_addr: AtomicUsize, inner: IRQSafeNullLock, + post_init_callback: fn(), } //-------------------------------------------------------------------------------------------------- -// Public Code +// Private Code //-------------------------------------------------------------------------------------------------- impl GPIOInner { @@ -137,25 +135,12 @@ impl GPIOInner { /// # Safety /// /// - The user must ensure to provide a correct MMIO start address. - pub const unsafe fn new(mmio_start_addr: usize) -> Self { + pub const unsafe fn new(mmio_start_addr: Address) -> Self { Self { registers: Registers::new(mmio_start_addr), } } - /// Init code. - /// - /// # Safety - /// - /// - The user must ensure to provide a correct MMIO start address. - pub unsafe fn init(&mut self, new_mmio_start_addr: Option) -> Result<(), &'static str> { - if let Some(addr) = new_mmio_start_addr { - self.registers = Registers::new(addr); - } - - Ok(()) - } - /// Disable pull-up/down on pins 14 and 15. #[cfg(feature = "bsp_rpi3")] fn disable_pud_14_15_bcm2837(&mut self) { @@ -205,17 +190,22 @@ impl GPIOInner { } } +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + impl GPIO { + pub const COMPATIBLE: &'static str = "BCM GPIO"; + /// Create an instance. /// /// # Safety /// - /// - The user must ensure to provide correct MMIO descriptors. - pub const unsafe fn new(mmio_descriptor: memory::mmu::MMIODescriptor) -> Self { + /// - The user must ensure to provide a correct MMIO start address. + pub const unsafe fn new(mmio_start_addr: Address, post_init_callback: fn()) -> Self { Self { - mmio_descriptor, - virt_mmio_start_addr: AtomicUsize::new(0), - inner: IRQSafeNullLock::new(GPIOInner::new(mmio_descriptor.start_addr().as_usize())), + inner: IRQSafeNullLock::new(GPIOInner::new(mmio_start_addr)), + post_init_callback, } } @@ -232,28 +222,12 @@ use synchronization::interface::Mutex; impl driver::interface::DeviceDriver for GPIO { fn compatible(&self) -> &'static str { - "BCM GPIO" + Self::COMPATIBLE } unsafe fn init(&self) -> Result<(), &'static str> { - let virt_addr = memory::mmu::kernel_map_mmio(self.compatible(), &self.mmio_descriptor)?; - - self.inner - .lock(|inner| inner.init(Some(virt_addr.as_usize())))?; - - self.virt_mmio_start_addr - .store(virt_addr.as_usize(), Ordering::Relaxed); + (self.post_init_callback)(); Ok(()) } - - fn virt_mmio_start_addr(&self) -> Option { - let addr = self.virt_mmio_start_addr.load(Ordering::Relaxed); - - if addr == 0 { - return None; - } - - Some(addr) - } } diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs index 99961fac..4908b8b6 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs @@ -6,7 +6,10 @@ mod peripheral_ic; -use crate::{driver, exception, memory}; +use crate::{ + driver, exception, + memory::{Address, Virtual}, +}; //-------------------------------------------------------------------------------------------------- // Private Definitions @@ -28,6 +31,7 @@ pub type PeripheralIRQ = /// Used for the associated type of trait [`exception::asynchronous::interface::IRQManager`]. #[derive(Copy, Clone)] +#[allow(missing_docs)] pub enum IRQNumber { Local(LocalIRQ), Peripheral(PeripheralIRQ), @@ -36,6 +40,7 @@ pub enum IRQNumber { /// Representation of the Interrupt Controller. pub struct InterruptController { periph: peripheral_ic::PeripheralIC, + post_init_callback: fn(), } //-------------------------------------------------------------------------------------------------- @@ -74,17 +79,20 @@ impl InterruptController { const MAX_PERIPHERAL_IRQ_NUMBER: usize = 63; const NUM_PERIPHERAL_IRQS: usize = Self::MAX_PERIPHERAL_IRQ_NUMBER + 1; + pub const COMPATIBLE: &'static str = "BCM Interrupt Controller"; + /// Create an instance. /// /// # Safety /// - /// - The user must ensure to provide correct MMIO descriptors. + /// - The user must ensure to provide a correct MMIO start address. pub const unsafe fn new( - _local_mmio_descriptor: memory::mmu::MMIODescriptor, - periph_mmio_descriptor: memory::mmu::MMIODescriptor, + periph_mmio_start_addr: Address, + post_init_callback: fn(), ) -> Self { Self { - periph: peripheral_ic::PeripheralIC::new(periph_mmio_descriptor), + periph: peripheral_ic::PeripheralIC::new(periph_mmio_start_addr), + post_init_callback, } } } @@ -95,11 +103,13 @@ impl InterruptController { impl driver::interface::DeviceDriver for InterruptController { fn compatible(&self) -> &'static str { - "BCM Interrupt Controller" + Self::COMPATIBLE } unsafe fn init(&self) -> Result<(), &'static str> { - self.periph.init() + (self.post_init_callback)(); + + Ok(()) } } diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs index f09da862..145d8961 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs @@ -7,7 +7,9 @@ use super::{InterruptController, PendingIRQs, PeripheralIRQ}; use crate::{ bsp::device_driver::common::MMIODerefWrapper, - driver, exception, memory, synchronization, + exception, + memory::{Address, Virtual}, + synchronization, synchronization::{IRQSafeNullLock, InitStateLock}, }; use tock_registers::{ @@ -55,13 +57,11 @@ type HandlerTable = /// Representation of the peripheral interrupt controller. pub struct PeripheralIC { - mmio_descriptor: memory::mmu::MMIODescriptor, - /// Access to write registers is guarded with a lock. wo_registers: IRQSafeNullLock, /// Register read access is unguarded. - ro_registers: InitStateLock, + ro_registers: ReadOnlyRegisters, /// Stores registered IRQ handlers. Writable only during kernel init. RO afterwards. handler_table: InitStateLock, @@ -76,26 +76,21 @@ impl PeripheralIC { /// /// # Safety /// - /// - The user must ensure to provide correct MMIO descriptors. - pub const unsafe fn new(mmio_descriptor: memory::mmu::MMIODescriptor) -> Self { - let addr = mmio_descriptor.start_addr().as_usize(); - + /// - The user must ensure to provide a correct MMIO start address. + pub const unsafe fn new(mmio_start_addr: Address) -> Self { Self { - mmio_descriptor, - wo_registers: IRQSafeNullLock::new(WriteOnlyRegisters::new(addr)), - ro_registers: InitStateLock::new(ReadOnlyRegisters::new(addr)), + wo_registers: IRQSafeNullLock::new(WriteOnlyRegisters::new(mmio_start_addr)), + ro_registers: ReadOnlyRegisters::new(mmio_start_addr), handler_table: InitStateLock::new([None; InterruptController::NUM_PERIPHERAL_IRQS]), } } /// Query the list of pending IRQs. fn pending_irqs(&self) -> PendingIRQs { - self.ro_registers.read(|regs| { - let pending_mask: u64 = - (u64::from(regs.PENDING_2.get()) << 32) | u64::from(regs.PENDING_1.get()); + let pending_mask: u64 = (u64::from(self.ro_registers.PENDING_2.get()) << 32) + | u64::from(self.ro_registers.PENDING_1.get()); - PendingIRQs::new(pending_mask) - }) + PendingIRQs::new(pending_mask) } } @@ -104,24 +99,6 @@ impl PeripheralIC { //------------------------------------------------------------------------------ use synchronization::interface::{Mutex, ReadWriteEx}; -impl driver::interface::DeviceDriver for PeripheralIC { - fn compatible(&self) -> &'static str { - "BCM Peripheral Interrupt Controller" - } - - unsafe fn init(&self) -> Result<(), &'static str> { - let virt_addr = - memory::mmu::kernel_map_mmio(self.compatible(), &self.mmio_descriptor)?.as_usize(); - - self.wo_registers - .lock(|regs| *regs = WriteOnlyRegisters::new(virt_addr)); - self.ro_registers - .write(|regs| *regs = ReadOnlyRegisters::new(virt_addr)); - - Ok(()) - } -} - impl exception::asynchronous::interface::IRQManager for PeripheralIC { type IRQNumberType = PeripheralIRQ; diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs index 3133047b..f67d70df 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs @@ -10,13 +10,14 @@ //! - use crate::{ - bsp, bsp::device_driver::common::MMIODerefWrapper, console, cpu, driver, exception, memory, - synchronization, synchronization::IRQSafeNullLock, -}; -use core::{ - fmt, - sync::atomic::{AtomicUsize, Ordering}, + bsp, + bsp::device_driver::common::MMIODerefWrapper, + console, cpu, driver, exception, + memory::{Address, Virtual}, + synchronization, + synchronization::IRQSafeNullLock, }; +use core::fmt; use tock_registers::{ interfaces::{Readable, Writeable}, register_bitfields, register_structs, @@ -219,29 +220,25 @@ enum BlockingMode { NonBlocking, } -//-------------------------------------------------------------------------------------------------- -// Public Definitions -//-------------------------------------------------------------------------------------------------- - -pub struct PL011UartInner { +struct PL011UartInner { registers: Registers, chars_written: usize, chars_read: usize, } -// Export the inner struct so that BSPs can use it for the panic handler. -pub use PL011UartInner as PanicUart; +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- /// Representation of the UART. pub struct PL011Uart { - mmio_descriptor: memory::mmu::MMIODescriptor, - virt_mmio_start_addr: AtomicUsize, inner: IRQSafeNullLock, irq_number: bsp::device_driver::IRQNumber, + post_init_callback: fn(), } //-------------------------------------------------------------------------------------------------- -// Public Code +// Private Code //-------------------------------------------------------------------------------------------------- impl PL011UartInner { @@ -250,7 +247,7 @@ impl PL011UartInner { /// # Safety /// /// - The user must ensure to provide a correct MMIO start address. - pub const unsafe fn new(mmio_start_addr: usize) -> Self { + pub const unsafe fn new(mmio_start_addr: Address) -> Self { Self { registers: Registers::new(mmio_start_addr), chars_written: 0, @@ -275,15 +272,7 @@ impl PL011UartInner { /// genrated baud rate of `48_000_000 / (16 * 3.25) = 923_077`. /// /// Error = `((923_077 - 921_600) / 921_600) * 100 = 0.16%`. - /// - /// # Safety - /// - /// - The user must ensure to provide a correct MMIO start address. - pub unsafe fn init(&mut self, new_mmio_start_addr: Option) -> Result<(), &'static str> { - if let Some(addr) = new_mmio_start_addr { - self.registers = Registers::new(addr); - } - + pub fn init(&mut self) { // Execution can arrive here while there are still characters queued in the TX FIFO and // actively being sent out by the UART hardware. If the UART is turned off in this case, // those queued characters would be lost. @@ -325,8 +314,6 @@ impl PL011UartInner { self.registers .CR .write(CR::UARTEN::Enabled + CR::TXE::Enabled + CR::RXE::Enabled); - - Ok(()) } /// Send a character. @@ -399,24 +386,28 @@ impl fmt::Write for PL011UartInner { } } +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + impl PL011Uart { + pub const COMPATIBLE: &'static str = "BCM PL011 UART"; + /// Create an instance. /// /// # Safety /// - /// - The user must ensure to provide correct MMIO descriptors. + /// - The user must ensure to provide a correct MMIO start address. /// - The user must ensure to provide correct IRQ numbers. pub const unsafe fn new( - mmio_descriptor: memory::mmu::MMIODescriptor, + mmio_start_addr: Address, irq_number: bsp::device_driver::IRQNumber, + post_init_callback: fn(), ) -> Self { Self { - mmio_descriptor, - virt_mmio_start_addr: AtomicUsize::new(0), - inner: IRQSafeNullLock::new(PL011UartInner::new( - mmio_descriptor.start_addr().as_usize(), - )), + inner: IRQSafeNullLock::new(PL011UartInner::new(mmio_start_addr)), irq_number, + post_init_callback, } } } @@ -428,27 +419,21 @@ use synchronization::interface::Mutex; impl driver::interface::DeviceDriver for PL011Uart { fn compatible(&self) -> &'static str { - "BCM PL011 UART" + Self::COMPATIBLE } unsafe fn init(&self) -> Result<(), &'static str> { - let virt_addr = memory::mmu::kernel_map_mmio(self.compatible(), &self.mmio_descriptor)?; - - self.inner - .lock(|inner| inner.init(Some(virt_addr.as_usize())))?; - - self.virt_mmio_start_addr - .store(virt_addr.as_usize(), Ordering::Relaxed); + self.inner.lock(|inner| inner.init()); + (self.post_init_callback)(); Ok(()) } fn register_and_enable_irq_handler(&'static self) -> Result<(), &'static str> { - use bsp::exception::asynchronous::irq_manager; - use exception::asynchronous::{interface::IRQManager, IRQDescriptor}; + use exception::asynchronous::{irq_manager, IRQDescriptor}; let descriptor = IRQDescriptor { - name: "BCM PL011 UART", + name: Self::COMPATIBLE, handler: self, }; @@ -457,16 +442,6 @@ impl driver::interface::DeviceDriver for PL011Uart { Ok(()) } - - fn virt_mmio_start_addr(&self) -> Option { - let addr = self.virt_mmio_start_addr.load(Ordering::Relaxed); - - if addr == 0 { - return None; - } - - Some(addr) - } } impl console::interface::Write for PL011Uart { @@ -514,6 +489,8 @@ impl console::interface::Statistics for PL011Uart { } } +impl console::interface::All for PL011Uart {} + impl exception::asynchronous::interface::IRQHandler for PL011Uart { fn handle(&self) -> Result<(), &'static str> { self.inner.lock(|inner| { diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/common.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/common.rs index fd9e988e..69f038d4 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/common.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/common.rs @@ -4,6 +4,7 @@ //! Common device driver code. +use crate::memory::{Address, Virtual}; use core::{marker::PhantomData, ops}; //-------------------------------------------------------------------------------------------------- @@ -11,7 +12,7 @@ use core::{marker::PhantomData, ops}; //-------------------------------------------------------------------------------------------------- pub struct MMIODerefWrapper { - start_addr: usize, + start_addr: Address, phantom: PhantomData T>, } @@ -21,7 +22,7 @@ pub struct MMIODerefWrapper { impl MMIODerefWrapper { /// Create an instance. - pub const unsafe fn new(start_addr: usize) -> Self { + pub const unsafe fn new(start_addr: Address) -> Self { Self { start_addr, phantom: PhantomData, @@ -33,6 +34,6 @@ impl ops::Deref for MMIODerefWrapper { type Target = T; fn deref(&self) -> &Self::Target { - unsafe { &*(self.start_addr as *const _) } + unsafe { &*(self.start_addr.as_usize() as *const _) } } } diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi.rs index fb9edf88..474419f4 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi.rs @@ -4,46 +4,11 @@ //! Top-level BSP file for the Raspberry Pi 3 and 4. -pub mod console; pub mod cpu; pub mod driver; pub mod exception; pub mod memory; -use super::device_driver; -use crate::memory::mmu::MMIODescriptor; -use memory::map::mmio; - -//-------------------------------------------------------------------------------------------------- -// Global instances -//-------------------------------------------------------------------------------------------------- - -static GPIO: device_driver::GPIO = - unsafe { device_driver::GPIO::new(MMIODescriptor::new(mmio::GPIO_START, mmio::GPIO_SIZE)) }; - -static PL011_UART: device_driver::PL011Uart = unsafe { - device_driver::PL011Uart::new( - MMIODescriptor::new(mmio::PL011_UART_START, mmio::PL011_UART_SIZE), - exception::asynchronous::irq_map::PL011_UART, - ) -}; - -#[cfg(feature = "bsp_rpi3")] -static INTERRUPT_CONTROLLER: device_driver::InterruptController = unsafe { - device_driver::InterruptController::new( - MMIODescriptor::new(mmio::LOCAL_IC_START, mmio::LOCAL_IC_SIZE), - MMIODescriptor::new(mmio::PERIPHERAL_IC_START, mmio::PERIPHERAL_IC_SIZE), - ) -}; - -#[cfg(feature = "bsp_rpi4")] -static INTERRUPT_CONTROLLER: device_driver::GICv2 = unsafe { - device_driver::GICv2::new( - MMIODescriptor::new(mmio::GICD_START, mmio::GICD_SIZE), - MMIODescriptor::new(mmio::GICC_START, mmio::GICC_SIZE), - ) -}; - //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/console.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/console.rs deleted file mode 100644 index c75bf9be..00000000 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/console.rs +++ /dev/null @@ -1,62 +0,0 @@ -// SPDX-License-Identifier: MIT OR Apache-2.0 -// -// Copyright (c) 2018-2022 Andre Richter - -//! BSP console facilities. - -use super::memory; -use crate::{bsp::device_driver, console, cpu, driver}; -use core::fmt; - -//-------------------------------------------------------------------------------------------------- -// Public Code -//-------------------------------------------------------------------------------------------------- - -/// In case of a panic, the panic handler uses this function to take a last shot at printing -/// something before the system is halted. -/// -/// We try to init panic-versions of the GPIO and the UART. The panic versions are not protected -/// with synchronization primitives, which increases chances that we get to print something, even -/// when the kernel's default GPIO or UART instances happen to be locked at the time of the panic. -/// -/// # Safety -/// -/// - Use only for printing during a panic. -pub unsafe fn panic_console_out() -> impl fmt::Write { - use driver::interface::DeviceDriver; - - let mut panic_gpio = device_driver::PanicGPIO::new(memory::map::mmio::GPIO_START.as_usize()); - let mut panic_uart = - device_driver::PanicUart::new(memory::map::mmio::PL011_UART_START.as_usize()); - - // If remapping of the driver's MMIO already happened, take the remapped start address. - // Otherwise, take a chance with the default physical address. - let maybe_gpio_mmio_start_addr = super::GPIO.virt_mmio_start_addr(); - let maybe_uart_mmio_start_addr = super::PL011_UART.virt_mmio_start_addr(); - - panic_gpio - .init(maybe_gpio_mmio_start_addr) - .unwrap_or_else(|_| cpu::wait_forever()); - panic_gpio.map_pl011_uart(); - panic_uart - .init(maybe_uart_mmio_start_addr) - .unwrap_or_else(|_| cpu::wait_forever()); - - panic_uart -} - -/// Return a reference to the console. -pub fn console() -> &'static impl console::interface::All { - &super::PL011_UART -} - -//-------------------------------------------------------------------------------------------------- -// Testing -//-------------------------------------------------------------------------------------------------- - -/// Minimal code needed to bring up the console in QEMU (for testing only). This is often less steps -/// than on real hardware due to QEMU's abstractions. -/// -/// For the RPi, nothing needs to be done. -#[cfg(feature = "test_build")] -pub fn qemu_bring_up_console() {} diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/driver.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/driver.rs index 53168752..e1db4a00 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/driver.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/driver.rs @@ -4,7 +4,19 @@ //! BSP driver support. -use crate::driver; +use super::{exception, memory::map::mmio}; +use crate::{ + bsp::device_driver, + console, driver, exception as generic_exception, memory, + memory::mmu::MMIODescriptor, + synchronization::{interface::ReadWriteEx, InitStateLock}, +}; +use core::{ + mem::MaybeUninit, + sync::atomic::{AtomicBool, Ordering}, +}; + +pub use device_driver::IRQNumber; //-------------------------------------------------------------------------------------------------- // Private Definitions @@ -12,21 +24,132 @@ use crate::driver; /// Device Driver Manager type. struct BSPDriverManager { - device_drivers: [&'static (dyn DeviceDriver + Sync); 3], + device_drivers: InitStateLock<[Option<&'static (dyn DeviceDriver + Sync)>; NUM_DRIVERS]>, + init_done: AtomicBool, } +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +/// The number of active drivers provided by this BSP. +pub const NUM_DRIVERS: usize = 3; + //-------------------------------------------------------------------------------------------------- // Global instances //-------------------------------------------------------------------------------------------------- +static mut PL011_UART: MaybeUninit = MaybeUninit::uninit(); +static mut GPIO: MaybeUninit = MaybeUninit::uninit(); + +#[cfg(feature = "bsp_rpi3")] +static mut INTERRUPT_CONTROLLER: MaybeUninit = + MaybeUninit::uninit(); + +#[cfg(feature = "bsp_rpi4")] +static mut INTERRUPT_CONTROLLER: MaybeUninit = MaybeUninit::uninit(); + static BSP_DRIVER_MANAGER: BSPDriverManager = BSPDriverManager { - device_drivers: [ - &super::GPIO, - &super::PL011_UART, - &super::INTERRUPT_CONTROLLER, - ], + device_drivers: InitStateLock::new([None; NUM_DRIVERS]), + init_done: AtomicBool::new(false), }; +//-------------------------------------------------------------------------------------------------- +// Private Code +//-------------------------------------------------------------------------------------------------- + +impl BSPDriverManager { + unsafe fn instantiate_uart(&self) -> Result<(), &'static str> { + let mmio_descriptor = MMIODescriptor::new(mmio::PL011_UART_START, mmio::PL011_UART_SIZE); + let virt_addr = + memory::mmu::kernel_map_mmio(device_driver::PL011Uart::COMPATIBLE, &mmio_descriptor)?; + + // This is safe to do, because it is only called from the init'ed instance itself. + fn uart_post_init() { + console::register_console(unsafe { PL011_UART.assume_init_ref() }); + } + + PL011_UART.write(device_driver::PL011Uart::new( + virt_addr, + exception::asynchronous::irq_map::PL011_UART, + uart_post_init, + )); + + Ok(()) + } + + unsafe fn instantiate_gpio(&self) -> Result<(), &'static str> { + let mmio_descriptor = MMIODescriptor::new(mmio::GPIO_START, mmio::GPIO_SIZE); + let virt_addr = + memory::mmu::kernel_map_mmio(device_driver::GPIO::COMPATIBLE, &mmio_descriptor)?; + + // This is safe to do, because it is only called from the init'ed instance itself. + fn gpio_post_init() { + unsafe { GPIO.assume_init_ref().map_pl011_uart() }; + } + + GPIO.write(device_driver::GPIO::new(virt_addr, gpio_post_init)); + + Ok(()) + } + + #[cfg(feature = "bsp_rpi3")] + unsafe fn instantiate_interrupt_controller(&self) -> Result<(), &'static str> { + let periph_mmio_descriptor = + MMIODescriptor::new(mmio::PERIPHERAL_IC_START, mmio::PERIPHERAL_IC_SIZE); + let periph_virt_addr = memory::mmu::kernel_map_mmio( + device_driver::InterruptController::COMPATIBLE, + &periph_mmio_descriptor, + )?; + + // This is safe to do, because it is only called from the init'ed instance itself. + fn interrupt_controller_post_init() { + generic_exception::asynchronous::register_irq_manager(unsafe { + INTERRUPT_CONTROLLER.assume_init_ref() + }); + } + + INTERRUPT_CONTROLLER.write(device_driver::InterruptController::new( + periph_virt_addr, + interrupt_controller_post_init, + )); + + Ok(()) + } + + #[cfg(feature = "bsp_rpi4")] + unsafe fn instantiate_interrupt_controller(&self) -> Result<(), &'static str> { + let gicd_mmio_descriptor = MMIODescriptor::new(mmio::GICD_START, mmio::GICD_SIZE); + let gicd_virt_addr = memory::mmu::kernel_map_mmio("GICv2 GICD", &gicd_mmio_descriptor)?; + + let gicc_mmio_descriptor = MMIODescriptor::new(mmio::GICC_START, mmio::GICC_SIZE); + let gicc_virt_addr = memory::mmu::kernel_map_mmio("GICV2 GICC", &gicc_mmio_descriptor)?; + + // This is safe to do, because it is only called from the init'ed instance itself. + fn interrupt_controller_post_init() { + generic_exception::asynchronous::register_irq_manager(unsafe { + INTERRUPT_CONTROLLER.assume_init_ref() + }); + } + + INTERRUPT_CONTROLLER.write(device_driver::GICv2::new( + gicd_virt_addr, + gicc_virt_addr, + interrupt_controller_post_init, + )); + + Ok(()) + } + + unsafe fn register_drivers(&self) { + self.device_drivers.write(|drivers| { + drivers[0] = Some(PL011_UART.assume_init_ref()); + drivers[1] = Some(GPIO.assume_init_ref()); + drivers[2] = Some(INTERRUPT_CONTROLLER.assume_init_ref()); + }); + } +} + //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- @@ -42,20 +165,34 @@ pub fn driver_manager() -> &'static impl driver::interface::DriverManager { use driver::interface::DeviceDriver; impl driver::interface::DriverManager for BSPDriverManager { - fn all_device_drivers(&self) -> &[&'static (dyn DeviceDriver + Sync)] { - &self.device_drivers[..] - } + unsafe fn instantiate_drivers(&self) -> Result<(), &'static str> { + if self.init_done.load(Ordering::Relaxed) { + return Err("Drivers already instantiated"); + } + + self.instantiate_uart()?; + self.instantiate_gpio()?; + self.instantiate_interrupt_controller()?; - fn early_print_device_drivers(&self) -> &[&'static (dyn DeviceDriver + Sync)] { - &self.device_drivers[0..=1] + self.register_drivers(); + + self.init_done.store(true, Ordering::Relaxed); + Ok(()) } - fn non_early_print_device_drivers(&self) -> &[&'static (dyn DeviceDriver + Sync)] { - &self.device_drivers[2..] + fn all_device_drivers(&self) -> [&(dyn DeviceDriver + Sync); NUM_DRIVERS] { + self.device_drivers + .read(|drivers| drivers.map(|drivers| drivers.unwrap())) } - fn post_early_print_device_driver_init(&self) { - // Configure PL011Uart's output pins. - super::GPIO.map_pl011_uart(); + #[cfg(feature = "test_build")] + fn qemu_bring_up_console(&self) { + use crate::cpu; + + unsafe { + self.instantiate_uart() + .unwrap_or_else(|_| cpu::qemu_exit_failure()); + console::register_console(PL011_UART.assume_init_ref()); + }; } } diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/exception/asynchronous.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/exception/asynchronous.rs index dc5ab421..ab20d86d 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/exception/asynchronous.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/exception/asynchronous.rs @@ -4,7 +4,7 @@ //! BSP asynchronous exception handling. -use crate::{bsp, exception}; +use crate::bsp; //-------------------------------------------------------------------------------------------------- // Public Definitions @@ -23,14 +23,3 @@ pub(in crate::bsp) mod irq_map { pub const PL011_UART: IRQNumber = IRQNumber::new(153); } - -//-------------------------------------------------------------------------------------------------- -// Public Code -//-------------------------------------------------------------------------------------------------- - -/// Return a reference to the IRQ manager. -pub fn irq_manager() -> &'static impl exception::asynchronous::interface::IRQManager< - IRQNumberType = bsp::device_driver::IRQNumber, -> { - &super::super::INTERRUPT_CONTROLLER -} diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/memory.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/memory.rs index 660409bb..7d6e7911 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/memory.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/memory.rs @@ -107,9 +107,6 @@ pub(super) mod map { pub const PL011_UART_START: Address = Address::new(0x3F20_1000); pub const PL011_UART_SIZE: usize = 0x48; - pub const LOCAL_IC_START: Address = Address::new(0x4000_0000); - pub const LOCAL_IC_SIZE: usize = 0x100; - pub const END: Address = Address::new(0x4001_0000); } diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/console.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/console.rs index e49e241f..a85bcffe 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/console.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/console.rs @@ -4,6 +4,10 @@ //! System console. +mod null_console; + +use crate::synchronization; + //-------------------------------------------------------------------------------------------------- // Public Definitions //-------------------------------------------------------------------------------------------------- @@ -49,5 +53,29 @@ pub mod interface { } /// Trait alias for a full-fledged console. - pub trait All = Write + Read + Statistics; + pub trait All: Write + Read + Statistics {} +} + +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +static CUR_CONSOLE: InitStateLock<&'static (dyn interface::All + Sync)> = + InitStateLock::new(&null_console::NULL_CONSOLE); + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- +use synchronization::{interface::ReadWriteEx, InitStateLock}; + +/// Register a new console. +pub fn register_console(new_console: &'static (dyn interface::All + Sync)) { + CUR_CONSOLE.write(|con| *con = new_console); +} + +/// Return a reference to the currently registered console. +/// +/// This is the global console used by all printing macros. +pub fn console() -> &'static dyn interface::All { + CUR_CONSOLE.read(|con| *con) } diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/console/null_console.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/console/null_console.rs new file mode 100644 index 00000000..10c3bedc --- /dev/null +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/console/null_console.rs @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2022 Andre Richter + +//! Null console. + +use super::interface; +use core::fmt; + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +pub struct NullConsole; + +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +pub static NULL_CONSOLE: NullConsole = NullConsole {}; + +//-------------------------------------------------------------------------------------------------- +// Private Code +//-------------------------------------------------------------------------------------------------- + +impl interface::Write for NullConsole { + fn write_char(&self, _c: char) {} + + fn write_fmt(&self, _args: fmt::Arguments) -> fmt::Result { + fmt::Result::Ok(()) + } + + fn flush(&self) {} +} + +impl interface::Read for NullConsole { + fn clear_rx(&self) {} +} + +impl interface::Statistics for NullConsole {} +impl interface::All for NullConsole {} diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/driver.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/driver.rs index 7b800dbc..98197fef 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/driver.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/driver.rs @@ -10,6 +10,8 @@ /// Driver interfaces. pub mod interface { + use crate::bsp; + /// Device Driver functions. pub trait DeviceDriver { /// Return a compatibility string for identifying the driver. @@ -31,32 +33,25 @@ pub mod interface { fn register_and_enable_irq_handler(&'static self) -> Result<(), &'static str> { Ok(()) } - - /// After MMIO remapping, returns the new virtual start address. - /// - /// This API assumes a driver has only a single, contiguous MMIO aperture, which will not be - /// the case for more complex devices. This API will likely change in future tutorials. - fn virt_mmio_start_addr(&self) -> Option { - None - } } /// Device driver management functions. /// /// The `BSP` is supposed to supply one global instance. pub trait DriverManager { - /// Return a slice of references to all `BSP`-instantiated drivers. - fn all_device_drivers(&self) -> &[&'static (dyn DeviceDriver + Sync)]; - - /// Return only those drivers needed for the BSP's early printing functionality. + /// Instantiate all drivers. + /// + /// # Safety /// - /// For example, the default UART. - fn early_print_device_drivers(&self) -> &[&'static (dyn DeviceDriver + Sync)]; + /// Must be called before `all_device_drivers`. + unsafe fn instantiate_drivers(&self) -> Result<(), &'static str>; - /// Return all drivers minus early-print drivers. - fn non_early_print_device_drivers(&self) -> &[&'static (dyn DeviceDriver + Sync)]; + /// Return a slice of references to all `BSP`-instantiated drivers. + fn all_device_drivers(&self) -> [&(dyn DeviceDriver + Sync); bsp::driver::NUM_DRIVERS]; - /// Initialization code that runs after the early print driver init. - fn post_early_print_device_driver_init(&self); + /// Minimal code needed to bring up the console in QEMU (for testing only). This is often + /// less steps than on real hardware due to QEMU's abstractions. + #[cfg(feature = "test_build")] + fn qemu_bring_up_console(&self); } } diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/exception/asynchronous.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/exception/asynchronous.rs index fb1785c2..d9d2767c 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/exception/asynchronous.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/exception/asynchronous.rs @@ -7,7 +7,9 @@ #[cfg(target_arch = "aarch64")] #[path = "../_arch/aarch64/exception/asynchronous.rs"] mod arch_asynchronous; +mod null_irq_manager; +use crate::{bsp, synchronization}; use core::{fmt, marker::PhantomData}; //-------------------------------------------------------------------------------------------------- @@ -85,7 +87,7 @@ pub mod interface { ); /// Print list of registered handlers. - fn print_handler(&self); + fn print_handler(&self) {} } } @@ -93,9 +95,18 @@ pub mod interface { #[derive(Copy, Clone)] pub struct IRQNumber(usize); +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +static CUR_IRQ_MANAGER: InitStateLock< + &'static (dyn interface::IRQManager + Sync), +> = InitStateLock::new(&null_irq_manager::NULL_IRQ_MANAGER); + //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- +use synchronization::{interface::ReadWriteEx, InitStateLock}; impl<'irq_context> IRQContext<'irq_context> { /// Creates an IRQContext token. @@ -150,3 +161,18 @@ pub fn exec_with_irq_masked(f: impl FnOnce() -> T) -> T { ret } + +/// Register a new IRQ manager. +pub fn register_irq_manager( + new_manager: &'static (dyn interface::IRQManager + + Sync), +) { + CUR_IRQ_MANAGER.write(|manager| *manager = new_manager); +} + +/// Return a reference to the currently registered IRQ manager. +/// +/// This is the IRQ manager used by the architectural interrupt handling code. +pub fn irq_manager() -> &'static dyn interface::IRQManager { + CUR_IRQ_MANAGER.read(|manager| *manager) +} diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/exception/asynchronous/null_irq_manager.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/exception/asynchronous/null_irq_manager.rs new file mode 100644 index 00000000..560e3ce4 --- /dev/null +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/exception/asynchronous/null_irq_manager.rs @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2022 Andre Richter + +//! Null IRQ Manager. + +use super::{interface, IRQContext, IRQDescriptor}; +use crate::bsp; + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +pub struct NullIRQManager; + +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +pub static NULL_IRQ_MANAGER: NullIRQManager = NullIRQManager {}; + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +impl interface::IRQManager for NullIRQManager { + type IRQNumberType = bsp::driver::IRQNumber; + + fn register_handler( + &self, + _irq_number: Self::IRQNumberType, + _descriptor: IRQDescriptor, + ) -> Result<(), &'static str> { + panic!("No IRQ Manager registered yet"); + } + + fn enable(&self, _irq_number: Self::IRQNumberType) { + panic!("No IRQ Manager registered yet"); + } + + fn handle_pending_irqs<'irq_context>(&'irq_context self, _ic: &IRQContext<'irq_context>) { + panic!("No IRQ Manager registered yet"); + } +} diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/lib.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/lib.rs index aeab8c22..ac57da95 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/lib.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/lib.rs @@ -114,6 +114,7 @@ #![feature(core_intrinsics)] #![feature(format_args_nl)] #![feature(generic_const_exprs)] +#![feature(is_sorted)] #![feature(linkage)] #![feature(panic_info_message)] #![feature(step_trait)] @@ -181,9 +182,23 @@ pub fn test_runner(tests: &[&test_types::UnitTest]) { #[cfg(test)] #[no_mangle] unsafe fn kernel_init() -> ! { + use driver::interface::DriverManager; + exception::handling_init(); + + let phys_kernel_tables_base_addr = match memory::mmu::kernel_map_binary() { + Err(string) => panic!("Error mapping kernel binary: {}", string), + Ok(addr) => addr, + }; + + if let Err(e) = memory::mmu::enable_mmu_and_caching(phys_kernel_tables_base_addr) { + panic!("Enabling MMU failed: {}", e); + } + // Printing will silently fail from here on, because the driver's MMIO is not remapped yet. + memory::mmu::post_enable_init(); - bsp::console::qemu_bring_up_console(); + bsp::driver::driver_manager().qemu_bring_up_console(); + // Printing available again from here on. test_main(); diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/main.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/main.rs index 17edcfd9..7574522c 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/main.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/main.rs @@ -42,26 +42,16 @@ unsafe fn kernel_init() -> ! { memory::mmu::post_enable_init(); - // Bring up the drivers needed for printing first. - for i in bsp::driver::driver_manager() - .early_print_device_drivers() - .iter() - { - // Any encountered errors cannot be printed yet, obviously, so just safely park the CPU. - i.init().unwrap_or_else(|_| cpu::wait_forever()); + // Instantiate and init all device drivers. + if let Err(x) = bsp::driver::driver_manager().instantiate_drivers() { + panic!("Error instantiating drivers: {}", x); } - bsp::driver::driver_manager().post_early_print_device_driver_init(); - // Printing available again from here on. - - // Now bring up the remaining drivers. - for i in bsp::driver::driver_manager() - .non_early_print_device_drivers() - .iter() - { + for i in bsp::driver::driver_manager().all_device_drivers().iter() { if let Err(x) = i.init() { panic!("Error loading driver: {}: {}", i.compatible(), x); } } + // Printing available again from here on. // Let device drivers register and enable their handlers with the interrupt controller. for i in bsp::driver::driver_manager().all_device_drivers() { @@ -83,7 +73,6 @@ unsafe fn kernel_init() -> ! { /// The main function running after the early init. fn kernel_main() -> ! { use driver::interface::DriverManager; - use exception::asynchronous::interface::IRQManager; info!("{}", libkernel::version()); info!("Booting on: {}", bsp::board_name()); @@ -112,7 +101,7 @@ fn kernel_main() -> ! { } info!("Registered IRQ handlers:"); - bsp::exception::asynchronous::irq_manager().print_handler(); + exception::asynchronous::irq_manager().print_handler(); info!("Echoing input now"); cpu::wait_forever(); diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/memory.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/memory.rs index f20719bb..64d8cf64 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/memory.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/memory.rs @@ -18,18 +18,18 @@ use core::{ //-------------------------------------------------------------------------------------------------- /// Metadata trait for marking the type of an address. -pub trait AddressType: Copy + Clone + PartialOrd + PartialEq {} +pub trait AddressType: Copy + Clone + PartialOrd + PartialEq + Ord + Eq {} /// Zero-sized type to mark a physical address. -#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)] +#[derive(Copy, Clone, Debug, PartialOrd, PartialEq, Ord, Eq)] pub enum Physical {} /// Zero-sized type to mark a virtual address. -#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)] +#[derive(Copy, Clone, Debug, PartialOrd, PartialEq, Ord, Eq)] pub enum Virtual {} /// Generic address type. -#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)] +#[derive(Copy, Clone, Debug, PartialOrd, PartialEq, Ord, Eq)] pub struct Address { value: usize, _address_type: PhantomData ATYPE>, diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/memory/mmu/mapping_record.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/memory/mmu/mapping_record.rs index d171c6e6..7d3a6c60 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/memory/mmu/mapping_record.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/memory/mmu/mapping_record.rs @@ -76,6 +76,19 @@ impl MappingRecord { Self { inner: [None; 12] } } + fn size(&self) -> usize { + self.inner.iter().filter(|x| x.is_some()).count() + } + + fn sort(&mut self) { + let upper_bound_exclusive = self.size(); + let entries = &mut self.inner[0..upper_bound_exclusive]; + + if !entries.is_sorted_by_key(|item| item.unwrap().virt_start_addr) { + entries.sort_unstable_by_key(|item| item.unwrap().virt_start_addr) + } + } + fn find_next_free(&mut self) -> Result<&mut Option, &'static str> { if let Some(x) = self.inner.iter_mut().find(|x| x.is_none()) { return Ok(x); @@ -121,6 +134,9 @@ impl MappingRecord { phys_region, attr, )); + + self.sort(); + Ok(()) } diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/panic_wait.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/panic_wait.rs index 08d7d453..e4256b61 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/panic_wait.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/panic_wait.rs @@ -4,19 +4,13 @@ //! A panic handler that infinitely waits. -use crate::{bsp, cpu, exception}; -use core::{fmt, panic::PanicInfo}; +use crate::{cpu, exception, println}; +use core::panic::PanicInfo; //-------------------------------------------------------------------------------------------------- // Private Code //-------------------------------------------------------------------------------------------------- -fn _panic_print(args: fmt::Arguments) { - use fmt::Write; - - unsafe { bsp::console::panic_console_out().write_fmt(args).unwrap() }; -} - /// The point of exit for `libkernel`. /// /// It is linked weakly, so that the integration tests can overload its standard behavior. @@ -34,16 +28,6 @@ fn _panic_exit() -> ! { } } -/// Prints with a newline - only use from the panic handler. -/// -/// Carbon copy from -#[macro_export] -macro_rules! panic_println { - ($($arg:tt)*) => ({ - _panic_print(format_args_nl!($($arg)*)); - }) -} - /// Stop immediately if called a second time. /// /// # Note @@ -88,7 +72,7 @@ fn panic(info: &PanicInfo) -> ! { _ => ("???", 0, 0), }; - panic_println!( + println!( "[ {:>3}.{:06}] Kernel panic!\n\n\ Panic location:\n File '{}', line {}, column {}\n\n\ {}", diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/print.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/print.rs index 9ec13a28..8705eec0 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/print.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/print.rs @@ -4,7 +4,7 @@ //! Printing. -use crate::{bsp, console}; +use crate::console; use core::fmt; //-------------------------------------------------------------------------------------------------- @@ -13,9 +13,7 @@ use core::fmt; #[doc(hidden)] pub fn _print(args: fmt::Arguments) { - use console::interface::Write; - - bsp::console::console().write_fmt(args).unwrap(); + console::console().write_fmt(args).unwrap(); } /// Prints without a newline. diff --git a/14_virtual_mem_part2_mmio_remap/kernel/tests/00_console_sanity.rs b/14_virtual_mem_part2_mmio_remap/kernel/tests/00_console_sanity.rs index dccb6cc2..a2338d2f 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/tests/00_console_sanity.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/tests/00_console_sanity.rs @@ -11,15 +11,28 @@ /// Console tests should time out on the I/O harness in case of panic. mod panic_wait_forever; -use libkernel::{bsp, console, cpu, exception, print}; +use libkernel::{bsp, console, cpu, driver, exception, memory, print}; #[no_mangle] unsafe fn kernel_init() -> ! { - use bsp::console::console; - use console::interface::*; + use console::console; + use driver::interface::DriverManager; exception::handling_init(); - bsp::console::qemu_bring_up_console(); + + let phys_kernel_tables_base_addr = match memory::mmu::kernel_map_binary() { + Err(string) => panic!("Error mapping kernel binary: {}", string), + Ok(addr) => addr, + }; + + if let Err(e) = memory::mmu::enable_mmu_and_caching(phys_kernel_tables_base_addr) { + panic!("Enabling MMU failed: {}", e); + } + // Printing will silently fail from here on, because the driver's MMIO is not remapped yet. + + memory::mmu::post_enable_init(); + bsp::driver::driver_manager().qemu_bring_up_console(); + // Printing available again from here on. // Handshake assert_eq!(console().read_char(), 'A'); diff --git a/14_virtual_mem_part2_mmio_remap/kernel/tests/01_timer_sanity.rs b/14_virtual_mem_part2_mmio_remap/kernel/tests/01_timer_sanity.rs index 59ef4a7f..4b4e90e4 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/tests/01_timer_sanity.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/tests/01_timer_sanity.rs @@ -11,13 +11,28 @@ #![test_runner(libkernel::test_runner)] use core::time::Duration; -use libkernel::{bsp, cpu, exception, time, time::interface::TimeManager}; +use libkernel::{bsp, cpu, driver, exception, memory, time, time::interface::TimeManager}; use test_macros::kernel_test; #[no_mangle] unsafe fn kernel_init() -> ! { + use driver::interface::DriverManager; + exception::handling_init(); - bsp::console::qemu_bring_up_console(); + + let phys_kernel_tables_base_addr = match memory::mmu::kernel_map_binary() { + Err(string) => panic!("Error mapping kernel binary: {}", string), + Ok(addr) => addr, + }; + + if let Err(e) = memory::mmu::enable_mmu_and_caching(phys_kernel_tables_base_addr) { + panic!("Enabling MMU failed: {}", e); + } + // Printing will silently fail from here on, because the driver's MMIO is not remapped yet. + + memory::mmu::post_enable_init(); + bsp::driver::driver_manager().qemu_bring_up_console(); + // Printing available again from here on. // Depending on CPU arch, some timer bring-up code could go here. Not needed for the RPi. diff --git a/14_virtual_mem_part2_mmio_remap/kernel/tests/02_exception_sync_page_fault.rs b/14_virtual_mem_part2_mmio_remap/kernel/tests/02_exception_sync_page_fault.rs index e146aa3e..209517ac 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/tests/02_exception_sync_page_fault.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/tests/02_exception_sync_page_fault.rs @@ -17,11 +17,11 @@ /// or indirectly. mod panic_exit_success; -use libkernel::{bsp, cpu, exception, info, memory, println}; +use libkernel::{bsp, cpu, driver, exception, info, memory, println}; #[no_mangle] unsafe fn kernel_init() -> ! { - use libkernel::driver::interface::DriverManager; + use driver::interface::DriverManager; exception::handling_init(); @@ -43,17 +43,7 @@ unsafe fn kernel_init() -> ! { // Printing will silently fail from here on, because the driver's MMIO is not remapped yet. memory::mmu::post_enable_init(); - bsp::console::qemu_bring_up_console(); - - // Bring up the drivers needed for printing first. - for i in bsp::driver::driver_manager() - .early_print_device_drivers() - .iter() - { - // Any encountered errors cannot be printed yet, obviously, so just safely park the CPU. - i.init().unwrap_or_else(|_| cpu::qemu_exit_failure()); - } - bsp::driver::driver_manager().post_early_print_device_driver_init(); + bsp::driver::driver_manager().qemu_bring_up_console(); // Printing available again from here on. info!("Writing beyond mapped area to address 9 GiB..."); diff --git a/14_virtual_mem_part2_mmio_remap/kernel/tests/03_exception_restore_sanity.rs b/14_virtual_mem_part2_mmio_remap/kernel/tests/03_exception_restore_sanity.rs index c6ff7b3d..babc31e2 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/tests/03_exception_restore_sanity.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/tests/03_exception_restore_sanity.rs @@ -12,7 +12,7 @@ mod panic_wait_forever; use core::arch::asm; -use libkernel::{bsp, cpu, exception, info, memory, println}; +use libkernel::{bsp, cpu, driver, exception, info, memory, println}; #[inline(never)] fn nested_system_call() { @@ -30,7 +30,7 @@ fn nested_system_call() { #[no_mangle] unsafe fn kernel_init() -> ! { - use libkernel::driver::interface::DriverManager; + use driver::interface::DriverManager; exception::handling_init(); @@ -52,17 +52,7 @@ unsafe fn kernel_init() -> ! { // Printing will silently fail from here on, because the driver's MMIO is not remapped yet. memory::mmu::post_enable_init(); - bsp::console::qemu_bring_up_console(); - - // Bring up the drivers needed for printing first. - for i in bsp::driver::driver_manager() - .early_print_device_drivers() - .iter() - { - // Any encountered errors cannot be printed yet, obviously, so just safely park the CPU. - i.init().unwrap_or_else(|_| cpu::qemu_exit_failure()); - } - bsp::driver::driver_manager().post_early_print_device_driver_init(); + bsp::driver::driver_manager().qemu_bring_up_console(); // Printing available again from here on. info!("Making a dummy system call"); diff --git a/14_virtual_mem_part2_mmio_remap/kernel/tests/04_exception_irq_sanity.rs b/14_virtual_mem_part2_mmio_remap/kernel/tests/04_exception_irq_sanity.rs index e1e02554..872cc008 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/tests/04_exception_irq_sanity.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/tests/04_exception_irq_sanity.rs @@ -10,14 +10,29 @@ #![reexport_test_harness_main = "test_main"] #![test_runner(libkernel::test_runner)] -use libkernel::{bsp, cpu, exception}; +use libkernel::{bsp, cpu, driver, exception, memory}; use test_macros::kernel_test; #[no_mangle] unsafe fn kernel_init() -> ! { - bsp::console::qemu_bring_up_console(); + use driver::interface::DriverManager; exception::handling_init(); + + let phys_kernel_tables_base_addr = match memory::mmu::kernel_map_binary() { + Err(string) => panic!("Error mapping kernel binary: {}", string), + Ok(addr) => addr, + }; + + if let Err(e) = memory::mmu::enable_mmu_and_caching(phys_kernel_tables_base_addr) { + panic!("Enabling MMU failed: {}", e); + } + // Printing will silently fail from here on, because the driver's MMIO is not remapped yet. + + memory::mmu::post_enable_init(); + bsp::driver::driver_manager().qemu_bring_up_console(); + // Printing available again from here on. + exception::asynchronous::local_irq_unmask(); test_main(); diff --git a/15_virtual_mem_part3_precomputed_tables/README.md b/15_virtual_mem_part3_precomputed_tables/README.md index b34c06b7..5a07f34b 100644 --- a/15_virtual_mem_part3_precomputed_tables/README.md +++ b/15_virtual_mem_part3_precomputed_tables/README.md @@ -775,22 +775,22 @@ Minipush 1.0 Raspberry Pi 3 [ML] Requesting binary -[MP] ⏩ Pushing 259 KiB ======================================🦀 100% 129 KiB/s Time: 00:00:02 +[MP] ⏩ Pushing 257 KiB ======================================🦀 100% 128 KiB/s Time: 00:00:02 [ML] Loaded! Executing the payload now -[ 2.891133] mingo version 0.15.0 -[ 2.891341] Booting on: Raspberry Pi 3 -[ 2.891796] MMU online: -[ 2.892088] ------------------------------------------------------------------------------------------------------------------------------------------- -[ 2.893833] Virtual Physical Size Attr Entity -[ 2.895577] ------------------------------------------------------------------------------------------------------------------------------------------- -[ 2.897322] 0x0000_0000_0000_0000..0x0000_0000_0007_ffff --> 0x00_0000_0000..0x00_0007_ffff | 512 KiB | C RW XN | Kernel boot-core stack -[ 2.898925] 0x0000_0000_0008_0000..0x0000_0000_0008_ffff --> 0x00_0008_0000..0x00_0008_ffff | 64 KiB | C RO X | Kernel code and RO data -[ 2.900538] 0x0000_0000_0009_0000..0x0000_0000_000c_ffff --> 0x00_0009_0000..0x00_000c_ffff | 256 KiB | C RW XN | Kernel data and bss -[ 2.902109] 0x0000_0000_000d_0000..0x0000_0000_000d_ffff --> 0x00_3f20_0000..0x00_3f20_ffff | 64 KiB | Dev RW XN | BCM GPIO -[ 2.903561] | BCM PL011 UART -[ 2.905078] 0x0000_0000_000e_0000..0x0000_0000_000e_ffff --> 0x00_3f00_0000..0x00_3f00_ffff | 64 KiB | Dev RW XN | BCM Peripheral Interrupt Controller -[ 2.906822] ------------------------------------------------------------------------------------------------------------------------------------------- +[ 2.866917] mingo version 0.15.0 +[ 2.867125] Booting on: Raspberry Pi 3 +[ 2.867580] MMU online: +[ 2.867872] ------------------------------------------------------------------------------------------------------------------------------------------- +[ 2.869616] Virtual Physical Size Attr Entity +[ 2.871360] ------------------------------------------------------------------------------------------------------------------------------------------- +[ 2.873105] 0x0000_0000_0000_0000..0x0000_0000_0007_ffff --> 0x00_0000_0000..0x00_0007_ffff | 512 KiB | C RW XN | Kernel boot-core stack +[ 2.874709] 0x0000_0000_0008_0000..0x0000_0000_0008_ffff --> 0x00_0008_0000..0x00_0008_ffff | 64 KiB | C RO X | Kernel code and RO data +[ 2.876322] 0x0000_0000_0009_0000..0x0000_0000_000c_ffff --> 0x00_0009_0000..0x00_000c_ffff | 256 KiB | C RW XN | Kernel data and bss +[ 2.877893] 0x0000_0000_000d_0000..0x0000_0000_000d_ffff --> 0x00_3f20_0000..0x00_3f20_ffff | 64 KiB | Dev RW XN | BCM PL011 UART +[ 2.879410] | BCM GPIO +[ 2.880861] 0x0000_0000_000e_0000..0x0000_0000_000e_ffff --> 0x00_3f00_0000..0x00_3f00_ffff | 64 KiB | Dev RW XN | BCM Interrupt Controller +[ 2.882487] ------------------------------------------------------------------------------------------------------------------------------------------- ``` ## Diff to previous @@ -1065,65 +1065,6 @@ diff -uNr 14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/memory/mmu/tr //-------------------------------------------------------------------------------------------------- -diff -uNr 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/console.rs 15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/console.rs ---- 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/console.rs -+++ 15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/console.rs -@@ -22,6 +22,7 @@ - /// # Safety - /// - /// - Use only for printing during a panic. -+#[cfg(not(feature = "test_build"))] - pub unsafe fn panic_console_out() -> impl fmt::Write { - use driver::interface::DeviceDriver; - -@@ -45,6 +46,27 @@ - panic_uart - } - -+/// Reduced version for test builds. -+/// -+/// # Safety -+/// -+/// - Use only for printing during a panic. -+#[cfg(feature = "test_build")] -+pub unsafe fn panic_console_out() -> impl fmt::Write { -+ use driver::interface::DeviceDriver; -+ -+ let mut panic_uart = -+ device_driver::PanicUart::new(memory::map::mmio::PL011_UART_START.as_usize()); -+ -+ let maybe_uart_mmio_start_addr = super::PL011_UART.virt_mmio_start_addr(); -+ -+ panic_uart -+ .init(maybe_uart_mmio_start_addr) -+ .unwrap_or_else(|_| cpu::qemu_exit_failure()); -+ -+ panic_uart -+} -+ - /// Return a reference to the console. - pub fn console() -> &'static impl console::interface::All { - &super::PL011_UART -@@ -56,7 +78,15 @@ - - /// Minimal code needed to bring up the console in QEMU (for testing only). This is often less steps - /// than on real hardware due to QEMU's abstractions. --/// --/// For the RPi, nothing needs to be done. - #[cfg(feature = "test_build")] --pub fn qemu_bring_up_console() {} -+pub fn qemu_bring_up_console() { -+ use driver::interface::DeviceDriver; -+ -+ // Calling the UART's init ensures that the BSP's instance of the UART does remap the MMIO -+ // addresses. -+ unsafe { -+ super::PL011_UART -+ .init() -+ .unwrap_or_else(|_| cpu::qemu_exit_failure()); -+ } -+} - diff -uNr 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/kernel.ld 15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/kernel.ld --- 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/kernel.ld +++ 15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/kernel.ld @@ -1371,10 +1312,35 @@ diff -uNr 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/memory/mmu. + ); } +diff -uNr 14_virtual_mem_part2_mmio_remap/kernel/src/lib.rs 15_virtual_mem_part3_precomputed_tables/kernel/src/lib.rs +--- 14_virtual_mem_part2_mmio_remap/kernel/src/lib.rs ++++ 15_virtual_mem_part3_precomputed_tables/kernel/src/lib.rs +@@ -185,20 +185,8 @@ + use driver::interface::DriverManager; + + exception::handling_init(); +- +- let phys_kernel_tables_base_addr = match memory::mmu::kernel_map_binary() { +- Err(string) => panic!("Error mapping kernel binary: {}", string), +- Ok(addr) => addr, +- }; +- +- if let Err(e) = memory::mmu::enable_mmu_and_caching(phys_kernel_tables_base_addr) { +- panic!("Enabling MMU failed: {}", e); +- } +- // Printing will silently fail from here on, because the driver's MMIO is not remapped yet. +- + memory::mmu::post_enable_init(); + bsp::driver::driver_manager().qemu_bring_up_console(); +- // Printing available again from here on. + + test_main(); + + diff -uNr 14_virtual_mem_part2_mmio_remap/kernel/src/main.rs 15_virtual_mem_part3_precomputed_tables/kernel/src/main.rs --- 14_virtual_mem_part2_mmio_remap/kernel/src/main.rs +++ 15_virtual_mem_part3_precomputed_tables/kernel/src/main.rs -@@ -17,31 +17,23 @@ +@@ -17,29 +17,17 @@ /// Early init code. /// @@ -1406,22 +1372,24 @@ diff -uNr 14_virtual_mem_part2_mmio_remap/kernel/src/main.rs 15_virtual_mem_part - memory::mmu::post_enable_init(); -+ // Add the mapping records for the precomputed entries first, so that they appear on the top of -+ // the list. -+ bsp::memory::mmu::kernel_add_mapping_records_for_precomputed(); -+ - // Bring up the drivers needed for printing first. - for i in bsp::driver::driver_manager() - .early_print_device_drivers() -@@ -51,7 +43,7 @@ - i.init().unwrap_or_else(|_| cpu::wait_forever()); + // Instantiate and init all device drivers. +@@ -51,7 +39,6 @@ + panic!("Error loading driver: {}: {}", i.compatible(), x); + } } - bsp::driver::driver_manager().post_early_print_device_driver_init(); - // Printing available again from here on. -+ // Printing available from here on. - // Now bring up the remaining drivers. - for i in bsp::driver::driver_manager() + // Let device drivers register and enable their handlers with the interrupt controller. + for i in bsp::driver::driver_manager().all_device_drivers() { +@@ -60,6 +47,8 @@ + } + } + ++ bsp::memory::mmu::kernel_add_mapping_records_for_precomputed(); ++ + // Unmask interrupts on the boot CPU core. + exception::asynchronous::local_irq_unmask(); + diff -uNr 14_virtual_mem_part2_mmio_remap/kernel/src/memory/mmu/translation_table.rs 15_virtual_mem_part3_precomputed_tables/kernel/src/memory/mmu/translation_table.rs --- 14_virtual_mem_part2_mmio_remap/kernel/src/memory/mmu/translation_table.rs @@ -1685,57 +1653,66 @@ diff -uNr 14_virtual_mem_part2_mmio_remap/kernel/src/memory/mmu.rs 15_virtual_me diff -uNr 14_virtual_mem_part2_mmio_remap/kernel/tests/00_console_sanity.rs 15_virtual_mem_part3_precomputed_tables/kernel/tests/00_console_sanity.rs --- 14_virtual_mem_part2_mmio_remap/kernel/tests/00_console_sanity.rs +++ 15_virtual_mem_part3_precomputed_tables/kernel/tests/00_console_sanity.rs -@@ -11,7 +11,7 @@ - /// Console tests should time out on the I/O harness in case of panic. - mod panic_wait_forever; - --use libkernel::{bsp, console, cpu, exception, print}; -+use libkernel::{bsp, console, cpu, exception, memory, print}; - - #[no_mangle] - unsafe fn kernel_init() -> ! { -@@ -19,6 +19,7 @@ - use console::interface::*; +@@ -19,20 +19,8 @@ + use driver::interface::DriverManager; exception::handling_init(); -+ memory::mmu::post_enable_init(); - bsp::console::qemu_bring_up_console(); +- +- let phys_kernel_tables_base_addr = match memory::mmu::kernel_map_binary() { +- Err(string) => panic!("Error mapping kernel binary: {}", string), +- Ok(addr) => addr, +- }; +- +- if let Err(e) = memory::mmu::enable_mmu_and_caching(phys_kernel_tables_base_addr) { +- panic!("Enabling MMU failed: {}", e); +- } +- // Printing will silently fail from here on, because the driver's MMIO is not remapped yet. +- + memory::mmu::post_enable_init(); + bsp::driver::driver_manager().qemu_bring_up_console(); +- // Printing available again from here on. // Handshake + assert_eq!(console().read_char(), 'A'); diff -uNr 14_virtual_mem_part2_mmio_remap/kernel/tests/01_timer_sanity.rs 15_virtual_mem_part3_precomputed_tables/kernel/tests/01_timer_sanity.rs --- 14_virtual_mem_part2_mmio_remap/kernel/tests/01_timer_sanity.rs +++ 15_virtual_mem_part3_precomputed_tables/kernel/tests/01_timer_sanity.rs -@@ -11,12 +11,13 @@ - #![test_runner(libkernel::test_runner)] - - use core::time::Duration; --use libkernel::{bsp, cpu, exception, time, time::interface::TimeManager}; -+use libkernel::{bsp, cpu, exception, memory, time, time::interface::TimeManager}; - use test_macros::kernel_test; +@@ -19,20 +19,8 @@ + use driver::interface::DriverManager; - #[no_mangle] - unsafe fn kernel_init() -> ! { exception::handling_init(); -+ memory::mmu::post_enable_init(); - bsp::console::qemu_bring_up_console(); +- +- let phys_kernel_tables_base_addr = match memory::mmu::kernel_map_binary() { +- Err(string) => panic!("Error mapping kernel binary: {}", string), +- Ok(addr) => addr, +- }; +- +- if let Err(e) = memory::mmu::enable_mmu_and_caching(phys_kernel_tables_base_addr) { +- panic!("Enabling MMU failed: {}", e); +- } +- // Printing will silently fail from here on, because the driver's MMIO is not remapped yet. +- + memory::mmu::post_enable_init(); + bsp::driver::driver_manager().qemu_bring_up_console(); +- // Printing available again from here on. // Depending on CPU arch, some timer bring-up code could go here. Not needed for the RPi. + diff -uNr 14_virtual_mem_part2_mmio_remap/kernel/tests/02_exception_sync_page_fault.rs 15_virtual_mem_part3_precomputed_tables/kernel/tests/02_exception_sync_page_fault.rs --- 14_virtual_mem_part2_mmio_remap/kernel/tests/02_exception_sync_page_fault.rs +++ 15_virtual_mem_part3_precomputed_tables/kernel/tests/02_exception_sync_page_fault.rs -@@ -21,40 +21,12 @@ +@@ -24,28 +24,12 @@ + use driver::interface::DriverManager; - #[no_mangle] - unsafe fn kernel_init() -> ! { -- use libkernel::driver::interface::DriverManager; -- exception::handling_init(); -- -- // This line will be printed as the test header. -- println!("Testing synchronous exception handling by causing a page fault"); -- ++ memory::mmu::post_enable_init(); ++ bsp::driver::driver_manager().qemu_bring_up_console(); + + // This line will be printed as the test header. + println!("Testing synchronous exception handling by causing a page fault"); + - let phys_kernel_tables_base_addr = match memory::mmu::kernel_map_binary() { - Err(string) => { - info!("Error mapping kernel binary: {}", string); @@ -1750,39 +1727,27 @@ diff -uNr 14_virtual_mem_part2_mmio_remap/kernel/tests/02_exception_sync_page_fa - } - // Printing will silently fail from here on, because the driver's MMIO is not remapped yet. - - memory::mmu::post_enable_init(); - bsp::console::qemu_bring_up_console(); - -- // Bring up the drivers needed for printing first. -- for i in bsp::driver::driver_manager() -- .early_print_device_drivers() -- .iter() -- { -- // Any encountered errors cannot be printed yet, obviously, so just safely park the CPU. -- i.init().unwrap_or_else(|_| cpu::qemu_exit_failure()); -- } -- bsp::driver::driver_manager().post_early_print_device_driver_init(); +- memory::mmu::post_enable_init(); +- bsp::driver::driver_manager().qemu_bring_up_console(); - // Printing available again from here on. -+ // This line will be printed as the test header. -+ println!("Testing synchronous exception handling by causing a page fault"); - +- info!("Writing beyond mapped area to address 9 GiB..."); let big_addr: u64 = 9 * 1024 * 1024 * 1024; + core::ptr::read_volatile(big_addr as *mut u64); diff -uNr 14_virtual_mem_part2_mmio_remap/kernel/tests/03_exception_restore_sanity.rs 15_virtual_mem_part3_precomputed_tables/kernel/tests/03_exception_restore_sanity.rs --- 14_virtual_mem_part2_mmio_remap/kernel/tests/03_exception_restore_sanity.rs +++ 15_virtual_mem_part3_precomputed_tables/kernel/tests/03_exception_restore_sanity.rs -@@ -30,40 +30,12 @@ +@@ -33,28 +33,12 @@ + use driver::interface::DriverManager; - #[no_mangle] - unsafe fn kernel_init() -> ! { -- use libkernel::driver::interface::DriverManager; -- exception::handling_init(); -- -- // This line will be printed as the test header. -- println!("Testing exception restore"); -- ++ memory::mmu::post_enable_init(); ++ bsp::driver::driver_manager().qemu_bring_up_console(); + + // This line will be printed as the test header. + println!("Testing exception restore"); + - let phys_kernel_tables_base_addr = match memory::mmu::kernel_map_binary() { - Err(string) => { - info!("Error mapping kernel binary: {}", string); @@ -1797,42 +1762,41 @@ diff -uNr 14_virtual_mem_part2_mmio_remap/kernel/tests/03_exception_restore_sani - } - // Printing will silently fail from here on, because the driver's MMIO is not remapped yet. - - memory::mmu::post_enable_init(); - bsp::console::qemu_bring_up_console(); - -- // Bring up the drivers needed for printing first. -- for i in bsp::driver::driver_manager() -- .early_print_device_drivers() -- .iter() -- { -- // Any encountered errors cannot be printed yet, obviously, so just safely park the CPU. -- i.init().unwrap_or_else(|_| cpu::qemu_exit_failure()); -- } -- bsp::driver::driver_manager().post_early_print_device_driver_init(); +- memory::mmu::post_enable_init(); +- bsp::driver::driver_manager().qemu_bring_up_console(); - // Printing available again from here on. -+ // This line will be printed as the test header. -+ println!("Testing exception restore"); - +- info!("Making a dummy system call"); + // Calling this inside a function indirectly tests if the link register is restored properly. diff -uNr 14_virtual_mem_part2_mmio_remap/kernel/tests/04_exception_irq_sanity.rs 15_virtual_mem_part3_precomputed_tables/kernel/tests/04_exception_irq_sanity.rs --- 14_virtual_mem_part2_mmio_remap/kernel/tests/04_exception_irq_sanity.rs +++ 15_virtual_mem_part3_precomputed_tables/kernel/tests/04_exception_irq_sanity.rs -@@ -10,11 +10,12 @@ - #![reexport_test_harness_main = "test_main"] - #![test_runner(libkernel::test_runner)] +@@ -17,22 +17,10 @@ + unsafe fn kernel_init() -> ! { + use driver::interface::DriverManager; --use libkernel::{bsp, cpu, exception}; -+use libkernel::{bsp, cpu, exception, memory}; - use test_macros::kernel_test; +- exception::handling_init(); +- +- let phys_kernel_tables_base_addr = match memory::mmu::kernel_map_binary() { +- Err(string) => panic!("Error mapping kernel binary: {}", string), +- Ok(addr) => addr, +- }; +- +- if let Err(e) = memory::mmu::enable_mmu_and_caching(phys_kernel_tables_base_addr) { +- panic!("Enabling MMU failed: {}", e); +- } +- // Printing will silently fail from here on, because the driver's MMIO is not remapped yet. +- + memory::mmu::post_enable_init(); + bsp::driver::driver_manager().qemu_bring_up_console(); +- // Printing available again from here on. - #[no_mangle] - unsafe fn kernel_init() -> ! { -+ memory::mmu::post_enable_init(); - bsp::console::qemu_bring_up_console(); ++ exception::handling_init(); + exception::asynchronous::local_irq_unmask(); - exception::handling_init(); + test_main(); diff -uNr 14_virtual_mem_part2_mmio_remap/Makefile 15_virtual_mem_part3_precomputed_tables/Makefile --- 14_virtual_mem_part2_mmio_remap/Makefile diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/exception.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/exception.rs index 662c91b9..fa6748a6 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/exception.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/exception.rs @@ -11,7 +11,7 @@ //! //! crate::exception::arch_exception -use crate::{bsp, exception}; +use crate::exception; use core::{arch::global_asm, cell::UnsafeCell, fmt}; use cortex_a::{asm::barrier, registers::*}; use tock_registers::{ @@ -104,10 +104,8 @@ unsafe extern "C" fn current_elx_synchronous(e: &mut ExceptionContext) { #[no_mangle] unsafe extern "C" fn current_elx_irq(_e: &mut ExceptionContext) { - use exception::asynchronous::interface::IRQManager; - let token = &exception::asynchronous::IRQContext::new(); - bsp::exception::asynchronous::irq_manager().handle_pending_irqs(token); + exception::asynchronous::irq_manager().handle_pending_irqs(token); } #[no_mangle] diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/arm/gicv2.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/arm/gicv2.rs index 4c68a692..e72fde7b 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/arm/gicv2.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/arm/gicv2.rs @@ -79,8 +79,12 @@ mod gicc; mod gicd; -use crate::{bsp, cpu, driver, exception, memory, synchronization, synchronization::InitStateLock}; -use core::sync::atomic::{AtomicBool, Ordering}; +use crate::{ + bsp, cpu, driver, exception, + memory::{Address, Virtual}, + synchronization, + synchronization::InitStateLock, +}; //-------------------------------------------------------------------------------------------------- // Private Definitions @@ -97,20 +101,17 @@ pub type IRQNumber = exception::asynchronous::IRQNumber<{ GICv2::MAX_IRQ_NUMBER /// Representation of the GIC. pub struct GICv2 { - gicd_mmio_descriptor: memory::mmu::MMIODescriptor, - gicc_mmio_descriptor: memory::mmu::MMIODescriptor, - /// The Distributor. gicd: gicd::GICD, /// The CPU Interface. gicc: gicc::GICC, - /// Have the MMIO regions been remapped yet? - is_mmio_remapped: AtomicBool, - /// Stores registered IRQ handlers. Writable only during kernel init. RO afterwards. handler_table: InitStateLock, + + /// Callback to be invoked after successful init. + post_init_callback: fn(), } //-------------------------------------------------------------------------------------------------- @@ -121,22 +122,23 @@ impl GICv2 { const MAX_IRQ_NUMBER: usize = 300; // Normally 1019, but keep it lower to save some space. const NUM_IRQS: usize = Self::MAX_IRQ_NUMBER + 1; + pub const COMPATIBLE: &'static str = "GICv2 (ARM Generic Interrupt Controller v2)"; + /// Create an instance. /// /// # Safety /// - /// - The user must ensure to provide correct MMIO descriptors. + /// - The user must ensure to provide a correct MMIO start address. pub const unsafe fn new( - gicd_mmio_descriptor: memory::mmu::MMIODescriptor, - gicc_mmio_descriptor: memory::mmu::MMIODescriptor, + gicd_mmio_start_addr: Address, + gicc_mmio_start_addr: Address, + post_init_callback: fn(), ) -> Self { Self { - gicd_mmio_descriptor, - gicc_mmio_descriptor, - gicd: gicd::GICD::new(gicd_mmio_descriptor.start_addr().as_usize()), - gicc: gicc::GICC::new(gicc_mmio_descriptor.start_addr().as_usize()), - is_mmio_remapped: AtomicBool::new(false), + gicd: gicd::GICD::new(gicd_mmio_start_addr), + gicc: gicc::GICC::new(gicc_mmio_start_addr), handler_table: InitStateLock::new([None; Self::NUM_IRQS]), + post_init_callback, } } } @@ -148,24 +150,10 @@ use synchronization::interface::ReadWriteEx; impl driver::interface::DeviceDriver for GICv2 { fn compatible(&self) -> &'static str { - "GICv2 (ARM Generic Interrupt Controller v2)" + Self::COMPATIBLE } unsafe fn init(&self) -> Result<(), &'static str> { - let remapped = self.is_mmio_remapped.load(Ordering::Relaxed); - if !remapped { - // GICD - let mut virt_addr = memory::mmu::kernel_map_mmio("GICD", &self.gicd_mmio_descriptor)?; - self.gicd.set_mmio(virt_addr.as_usize()); - - // GICC - virt_addr = memory::mmu::kernel_map_mmio("GICC", &self.gicc_mmio_descriptor)?; - self.gicc.set_mmio(virt_addr.as_usize()); - - // Conclude remapping. - self.is_mmio_remapped.store(true, Ordering::Relaxed); - } - if bsp::cpu::BOOT_CORE_ID == cpu::smp::core_id() { self.gicd.boot_core_init(); } @@ -173,6 +161,8 @@ impl driver::interface::DeviceDriver for GICv2 { self.gicc.priority_accept_all(); self.gicc.enable(); + (self.post_init_callback)(); + Ok(()) } } diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/arm/gicv2/gicc.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/arm/gicv2/gicc.rs index 1a151d24..1a02fc65 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/arm/gicv2/gicc.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/arm/gicv2/gicc.rs @@ -5,7 +5,9 @@ //! GICC Driver - GIC CPU interface. use crate::{ - bsp::device_driver::common::MMIODerefWrapper, exception, synchronization::InitStateLock, + bsp::device_driver::common::MMIODerefWrapper, + exception, + memory::{Address, Virtual}, }; use tock_registers::{ interfaces::{Readable, Writeable}, @@ -62,13 +64,12 @@ type Registers = MMIODerefWrapper; /// Representation of the GIC CPU interface. pub struct GICC { - registers: InitStateLock, + registers: Registers, } //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- -use crate::synchronization::interface::ReadWriteEx; impl GICC { /// Create an instance. @@ -76,17 +77,12 @@ impl GICC { /// # Safety /// /// - The user must ensure to provide a correct MMIO start address. - pub const unsafe fn new(mmio_start_addr: usize) -> Self { + pub const unsafe fn new(mmio_start_addr: Address) -> Self { Self { - registers: InitStateLock::new(Registers::new(mmio_start_addr)), + registers: Registers::new(mmio_start_addr), } } - pub unsafe fn set_mmio(&self, new_mmio_start_addr: usize) { - self.registers - .write(|regs| *regs = Registers::new(new_mmio_start_addr)); - } - /// Accept interrupts of any priority. /// /// Quoting the GICv2 Architecture Specification: @@ -99,9 +95,7 @@ impl GICC { /// - GICC MMIO registers are banked per CPU core. It is therefore safe to have `&self` instead /// of `&mut self`. pub fn priority_accept_all(&self) { - self.registers.read(|regs| { - regs.PMR.write(PMR::Priority.val(255)); // Comment in arch spec. - }); + self.registers.PMR.write(PMR::Priority.val(255)); // Comment in arch spec. } /// Enable the interface - start accepting IRQs. @@ -111,9 +105,7 @@ impl GICC { /// - GICC MMIO registers are banked per CPU core. It is therefore safe to have `&self` instead /// of `&mut self`. pub fn enable(&self) { - self.registers.read(|regs| { - regs.CTLR.write(CTLR::Enable::SET); - }); + self.registers.CTLR.write(CTLR::Enable::SET); } /// Extract the number of the highest-priority pending IRQ. @@ -129,8 +121,7 @@ impl GICC { &self, _ic: &exception::asynchronous::IRQContext<'irq_context>, ) -> usize { - self.registers - .read(|regs| regs.IAR.read(IAR::InterruptID) as usize) + self.registers.IAR.read(IAR::InterruptID) as usize } /// Complete handling of the currently active IRQ. @@ -149,8 +140,6 @@ impl GICC { irq_number: u32, _ic: &exception::asynchronous::IRQContext<'irq_context>, ) { - self.registers.read(|regs| { - regs.EOIR.write(EOIR::EOIINTID.val(irq_number)); - }); + self.registers.EOIR.write(EOIR::EOIINTID.val(irq_number)); } } diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs index 60bbc468..d9f63d1b 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs @@ -9,8 +9,9 @@ use crate::{ bsp::device_driver::common::MMIODerefWrapper, + memory::{Address, Virtual}, state, synchronization, - synchronization::{IRQSafeNullLock, InitStateLock}, + synchronization::IRQSafeNullLock, }; use tock_registers::{ interfaces::{Readable, Writeable}, @@ -84,7 +85,7 @@ pub struct GICD { shared_registers: IRQSafeNullLock, /// Access to banked registers is unguarded. - banked_registers: InitStateLock, + banked_registers: BankedRegisters, } //-------------------------------------------------------------------------------------------------- @@ -121,7 +122,6 @@ impl SharedRegisters { //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- -use crate::synchronization::interface::ReadWriteEx; use synchronization::interface::Mutex; impl GICD { @@ -130,20 +130,13 @@ impl GICD { /// # Safety /// /// - The user must ensure to provide a correct MMIO start address. - pub const unsafe fn new(mmio_start_addr: usize) -> Self { + pub const unsafe fn new(mmio_start_addr: Address) -> Self { Self { shared_registers: IRQSafeNullLock::new(SharedRegisters::new(mmio_start_addr)), - banked_registers: InitStateLock::new(BankedRegisters::new(mmio_start_addr)), + banked_registers: BankedRegisters::new(mmio_start_addr), } } - pub unsafe fn set_mmio(&self, new_mmio_start_addr: usize) { - self.shared_registers - .lock(|regs| *regs = SharedRegisters::new(new_mmio_start_addr)); - self.banked_registers - .write(|regs| *regs = BankedRegisters::new(new_mmio_start_addr)); - } - /// Use a banked ITARGETSR to retrieve the executing core's GIC target mask. /// /// Quoting the GICv2 Architecture Specification: @@ -151,8 +144,7 @@ impl GICD { /// "GICD_ITARGETSR0 to GICD_ITARGETSR7 are read-only, and each field returns a value that /// corresponds only to the processor reading the register." fn local_gic_target_mask(&self) -> u32 { - self.banked_registers - .read(|regs| regs.ITARGETSR[0].read(ITARGETSR::Offset0)) + self.banked_registers.ITARGETSR[0].read(ITARGETSR::Offset0) } /// Route all SPIs to the boot core and enable the distributor. @@ -191,10 +183,10 @@ impl GICD { // Check if we are handling a private or shared IRQ. match irq_num { // Private. - 0..=31 => self.banked_registers.read(|regs| { - let enable_reg = ®s.ISENABLER; + 0..=31 => { + let enable_reg = &self.banked_registers.ISENABLER; enable_reg.set(enable_reg.get() | enable_bit); - }), + } // Shared. _ => { let enable_reg_index_shared = enable_reg_index - 1; diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs index eea07b75..a3361c2c 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs @@ -5,10 +5,12 @@ //! GPIO Driver. use crate::{ - bsp::device_driver::common::MMIODerefWrapper, driver, memory, synchronization, + bsp::device_driver::common::MMIODerefWrapper, + driver, + memory::{Address, Virtual}, + synchronization, synchronization::IRQSafeNullLock, }; -use core::sync::atomic::{AtomicUsize, Ordering}; use tock_registers::{ interfaces::{ReadWriteable, Writeable}, register_bitfields, register_structs, @@ -109,26 +111,22 @@ register_structs! { /// Abstraction for the associated MMIO registers. type Registers = MMIODerefWrapper; -//-------------------------------------------------------------------------------------------------- -// Public Definitions -//-------------------------------------------------------------------------------------------------- - -pub struct GPIOInner { +struct GPIOInner { registers: Registers, } -// Export the inner struct so that BSPs can use it for the panic handler. -pub use GPIOInner as PanicGPIO; +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- /// Representation of the GPIO HW. pub struct GPIO { - mmio_descriptor: memory::mmu::MMIODescriptor, - virt_mmio_start_addr: AtomicUsize, inner: IRQSafeNullLock, + post_init_callback: fn(), } //-------------------------------------------------------------------------------------------------- -// Public Code +// Private Code //-------------------------------------------------------------------------------------------------- impl GPIOInner { @@ -137,25 +135,12 @@ impl GPIOInner { /// # Safety /// /// - The user must ensure to provide a correct MMIO start address. - pub const unsafe fn new(mmio_start_addr: usize) -> Self { + pub const unsafe fn new(mmio_start_addr: Address) -> Self { Self { registers: Registers::new(mmio_start_addr), } } - /// Init code. - /// - /// # Safety - /// - /// - The user must ensure to provide a correct MMIO start address. - pub unsafe fn init(&mut self, new_mmio_start_addr: Option) -> Result<(), &'static str> { - if let Some(addr) = new_mmio_start_addr { - self.registers = Registers::new(addr); - } - - Ok(()) - } - /// Disable pull-up/down on pins 14 and 15. #[cfg(feature = "bsp_rpi3")] fn disable_pud_14_15_bcm2837(&mut self) { @@ -205,17 +190,22 @@ impl GPIOInner { } } +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + impl GPIO { + pub const COMPATIBLE: &'static str = "BCM GPIO"; + /// Create an instance. /// /// # Safety /// - /// - The user must ensure to provide correct MMIO descriptors. - pub const unsafe fn new(mmio_descriptor: memory::mmu::MMIODescriptor) -> Self { + /// - The user must ensure to provide a correct MMIO start address. + pub const unsafe fn new(mmio_start_addr: Address, post_init_callback: fn()) -> Self { Self { - mmio_descriptor, - virt_mmio_start_addr: AtomicUsize::new(0), - inner: IRQSafeNullLock::new(GPIOInner::new(mmio_descriptor.start_addr().as_usize())), + inner: IRQSafeNullLock::new(GPIOInner::new(mmio_start_addr)), + post_init_callback, } } @@ -232,28 +222,12 @@ use synchronization::interface::Mutex; impl driver::interface::DeviceDriver for GPIO { fn compatible(&self) -> &'static str { - "BCM GPIO" + Self::COMPATIBLE } unsafe fn init(&self) -> Result<(), &'static str> { - let virt_addr = memory::mmu::kernel_map_mmio(self.compatible(), &self.mmio_descriptor)?; - - self.inner - .lock(|inner| inner.init(Some(virt_addr.as_usize())))?; - - self.virt_mmio_start_addr - .store(virt_addr.as_usize(), Ordering::Relaxed); + (self.post_init_callback)(); Ok(()) } - - fn virt_mmio_start_addr(&self) -> Option { - let addr = self.virt_mmio_start_addr.load(Ordering::Relaxed); - - if addr == 0 { - return None; - } - - Some(addr) - } } diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs index 99961fac..4908b8b6 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs @@ -6,7 +6,10 @@ mod peripheral_ic; -use crate::{driver, exception, memory}; +use crate::{ + driver, exception, + memory::{Address, Virtual}, +}; //-------------------------------------------------------------------------------------------------- // Private Definitions @@ -28,6 +31,7 @@ pub type PeripheralIRQ = /// Used for the associated type of trait [`exception::asynchronous::interface::IRQManager`]. #[derive(Copy, Clone)] +#[allow(missing_docs)] pub enum IRQNumber { Local(LocalIRQ), Peripheral(PeripheralIRQ), @@ -36,6 +40,7 @@ pub enum IRQNumber { /// Representation of the Interrupt Controller. pub struct InterruptController { periph: peripheral_ic::PeripheralIC, + post_init_callback: fn(), } //-------------------------------------------------------------------------------------------------- @@ -74,17 +79,20 @@ impl InterruptController { const MAX_PERIPHERAL_IRQ_NUMBER: usize = 63; const NUM_PERIPHERAL_IRQS: usize = Self::MAX_PERIPHERAL_IRQ_NUMBER + 1; + pub const COMPATIBLE: &'static str = "BCM Interrupt Controller"; + /// Create an instance. /// /// # Safety /// - /// - The user must ensure to provide correct MMIO descriptors. + /// - The user must ensure to provide a correct MMIO start address. pub const unsafe fn new( - _local_mmio_descriptor: memory::mmu::MMIODescriptor, - periph_mmio_descriptor: memory::mmu::MMIODescriptor, + periph_mmio_start_addr: Address, + post_init_callback: fn(), ) -> Self { Self { - periph: peripheral_ic::PeripheralIC::new(periph_mmio_descriptor), + periph: peripheral_ic::PeripheralIC::new(periph_mmio_start_addr), + post_init_callback, } } } @@ -95,11 +103,13 @@ impl InterruptController { impl driver::interface::DeviceDriver for InterruptController { fn compatible(&self) -> &'static str { - "BCM Interrupt Controller" + Self::COMPATIBLE } unsafe fn init(&self) -> Result<(), &'static str> { - self.periph.init() + (self.post_init_callback)(); + + Ok(()) } } diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs index f09da862..145d8961 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs @@ -7,7 +7,9 @@ use super::{InterruptController, PendingIRQs, PeripheralIRQ}; use crate::{ bsp::device_driver::common::MMIODerefWrapper, - driver, exception, memory, synchronization, + exception, + memory::{Address, Virtual}, + synchronization, synchronization::{IRQSafeNullLock, InitStateLock}, }; use tock_registers::{ @@ -55,13 +57,11 @@ type HandlerTable = /// Representation of the peripheral interrupt controller. pub struct PeripheralIC { - mmio_descriptor: memory::mmu::MMIODescriptor, - /// Access to write registers is guarded with a lock. wo_registers: IRQSafeNullLock, /// Register read access is unguarded. - ro_registers: InitStateLock, + ro_registers: ReadOnlyRegisters, /// Stores registered IRQ handlers. Writable only during kernel init. RO afterwards. handler_table: InitStateLock, @@ -76,26 +76,21 @@ impl PeripheralIC { /// /// # Safety /// - /// - The user must ensure to provide correct MMIO descriptors. - pub const unsafe fn new(mmio_descriptor: memory::mmu::MMIODescriptor) -> Self { - let addr = mmio_descriptor.start_addr().as_usize(); - + /// - The user must ensure to provide a correct MMIO start address. + pub const unsafe fn new(mmio_start_addr: Address) -> Self { Self { - mmio_descriptor, - wo_registers: IRQSafeNullLock::new(WriteOnlyRegisters::new(addr)), - ro_registers: InitStateLock::new(ReadOnlyRegisters::new(addr)), + wo_registers: IRQSafeNullLock::new(WriteOnlyRegisters::new(mmio_start_addr)), + ro_registers: ReadOnlyRegisters::new(mmio_start_addr), handler_table: InitStateLock::new([None; InterruptController::NUM_PERIPHERAL_IRQS]), } } /// Query the list of pending IRQs. fn pending_irqs(&self) -> PendingIRQs { - self.ro_registers.read(|regs| { - let pending_mask: u64 = - (u64::from(regs.PENDING_2.get()) << 32) | u64::from(regs.PENDING_1.get()); + let pending_mask: u64 = (u64::from(self.ro_registers.PENDING_2.get()) << 32) + | u64::from(self.ro_registers.PENDING_1.get()); - PendingIRQs::new(pending_mask) - }) + PendingIRQs::new(pending_mask) } } @@ -104,24 +99,6 @@ impl PeripheralIC { //------------------------------------------------------------------------------ use synchronization::interface::{Mutex, ReadWriteEx}; -impl driver::interface::DeviceDriver for PeripheralIC { - fn compatible(&self) -> &'static str { - "BCM Peripheral Interrupt Controller" - } - - unsafe fn init(&self) -> Result<(), &'static str> { - let virt_addr = - memory::mmu::kernel_map_mmio(self.compatible(), &self.mmio_descriptor)?.as_usize(); - - self.wo_registers - .lock(|regs| *regs = WriteOnlyRegisters::new(virt_addr)); - self.ro_registers - .write(|regs| *regs = ReadOnlyRegisters::new(virt_addr)); - - Ok(()) - } -} - impl exception::asynchronous::interface::IRQManager for PeripheralIC { type IRQNumberType = PeripheralIRQ; diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs index 3133047b..f67d70df 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs @@ -10,13 +10,14 @@ //! - use crate::{ - bsp, bsp::device_driver::common::MMIODerefWrapper, console, cpu, driver, exception, memory, - synchronization, synchronization::IRQSafeNullLock, -}; -use core::{ - fmt, - sync::atomic::{AtomicUsize, Ordering}, + bsp, + bsp::device_driver::common::MMIODerefWrapper, + console, cpu, driver, exception, + memory::{Address, Virtual}, + synchronization, + synchronization::IRQSafeNullLock, }; +use core::fmt; use tock_registers::{ interfaces::{Readable, Writeable}, register_bitfields, register_structs, @@ -219,29 +220,25 @@ enum BlockingMode { NonBlocking, } -//-------------------------------------------------------------------------------------------------- -// Public Definitions -//-------------------------------------------------------------------------------------------------- - -pub struct PL011UartInner { +struct PL011UartInner { registers: Registers, chars_written: usize, chars_read: usize, } -// Export the inner struct so that BSPs can use it for the panic handler. -pub use PL011UartInner as PanicUart; +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- /// Representation of the UART. pub struct PL011Uart { - mmio_descriptor: memory::mmu::MMIODescriptor, - virt_mmio_start_addr: AtomicUsize, inner: IRQSafeNullLock, irq_number: bsp::device_driver::IRQNumber, + post_init_callback: fn(), } //-------------------------------------------------------------------------------------------------- -// Public Code +// Private Code //-------------------------------------------------------------------------------------------------- impl PL011UartInner { @@ -250,7 +247,7 @@ impl PL011UartInner { /// # Safety /// /// - The user must ensure to provide a correct MMIO start address. - pub const unsafe fn new(mmio_start_addr: usize) -> Self { + pub const unsafe fn new(mmio_start_addr: Address) -> Self { Self { registers: Registers::new(mmio_start_addr), chars_written: 0, @@ -275,15 +272,7 @@ impl PL011UartInner { /// genrated baud rate of `48_000_000 / (16 * 3.25) = 923_077`. /// /// Error = `((923_077 - 921_600) / 921_600) * 100 = 0.16%`. - /// - /// # Safety - /// - /// - The user must ensure to provide a correct MMIO start address. - pub unsafe fn init(&mut self, new_mmio_start_addr: Option) -> Result<(), &'static str> { - if let Some(addr) = new_mmio_start_addr { - self.registers = Registers::new(addr); - } - + pub fn init(&mut self) { // Execution can arrive here while there are still characters queued in the TX FIFO and // actively being sent out by the UART hardware. If the UART is turned off in this case, // those queued characters would be lost. @@ -325,8 +314,6 @@ impl PL011UartInner { self.registers .CR .write(CR::UARTEN::Enabled + CR::TXE::Enabled + CR::RXE::Enabled); - - Ok(()) } /// Send a character. @@ -399,24 +386,28 @@ impl fmt::Write for PL011UartInner { } } +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + impl PL011Uart { + pub const COMPATIBLE: &'static str = "BCM PL011 UART"; + /// Create an instance. /// /// # Safety /// - /// - The user must ensure to provide correct MMIO descriptors. + /// - The user must ensure to provide a correct MMIO start address. /// - The user must ensure to provide correct IRQ numbers. pub const unsafe fn new( - mmio_descriptor: memory::mmu::MMIODescriptor, + mmio_start_addr: Address, irq_number: bsp::device_driver::IRQNumber, + post_init_callback: fn(), ) -> Self { Self { - mmio_descriptor, - virt_mmio_start_addr: AtomicUsize::new(0), - inner: IRQSafeNullLock::new(PL011UartInner::new( - mmio_descriptor.start_addr().as_usize(), - )), + inner: IRQSafeNullLock::new(PL011UartInner::new(mmio_start_addr)), irq_number, + post_init_callback, } } } @@ -428,27 +419,21 @@ use synchronization::interface::Mutex; impl driver::interface::DeviceDriver for PL011Uart { fn compatible(&self) -> &'static str { - "BCM PL011 UART" + Self::COMPATIBLE } unsafe fn init(&self) -> Result<(), &'static str> { - let virt_addr = memory::mmu::kernel_map_mmio(self.compatible(), &self.mmio_descriptor)?; - - self.inner - .lock(|inner| inner.init(Some(virt_addr.as_usize())))?; - - self.virt_mmio_start_addr - .store(virt_addr.as_usize(), Ordering::Relaxed); + self.inner.lock(|inner| inner.init()); + (self.post_init_callback)(); Ok(()) } fn register_and_enable_irq_handler(&'static self) -> Result<(), &'static str> { - use bsp::exception::asynchronous::irq_manager; - use exception::asynchronous::{interface::IRQManager, IRQDescriptor}; + use exception::asynchronous::{irq_manager, IRQDescriptor}; let descriptor = IRQDescriptor { - name: "BCM PL011 UART", + name: Self::COMPATIBLE, handler: self, }; @@ -457,16 +442,6 @@ impl driver::interface::DeviceDriver for PL011Uart { Ok(()) } - - fn virt_mmio_start_addr(&self) -> Option { - let addr = self.virt_mmio_start_addr.load(Ordering::Relaxed); - - if addr == 0 { - return None; - } - - Some(addr) - } } impl console::interface::Write for PL011Uart { @@ -514,6 +489,8 @@ impl console::interface::Statistics for PL011Uart { } } +impl console::interface::All for PL011Uart {} + impl exception::asynchronous::interface::IRQHandler for PL011Uart { fn handle(&self) -> Result<(), &'static str> { self.inner.lock(|inner| { diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/common.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/common.rs index fd9e988e..69f038d4 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/common.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/common.rs @@ -4,6 +4,7 @@ //! Common device driver code. +use crate::memory::{Address, Virtual}; use core::{marker::PhantomData, ops}; //-------------------------------------------------------------------------------------------------- @@ -11,7 +12,7 @@ use core::{marker::PhantomData, ops}; //-------------------------------------------------------------------------------------------------- pub struct MMIODerefWrapper { - start_addr: usize, + start_addr: Address, phantom: PhantomData T>, } @@ -21,7 +22,7 @@ pub struct MMIODerefWrapper { impl MMIODerefWrapper { /// Create an instance. - pub const unsafe fn new(start_addr: usize) -> Self { + pub const unsafe fn new(start_addr: Address) -> Self { Self { start_addr, phantom: PhantomData, @@ -33,6 +34,6 @@ impl ops::Deref for MMIODerefWrapper { type Target = T; fn deref(&self) -> &Self::Target { - unsafe { &*(self.start_addr as *const _) } + unsafe { &*(self.start_addr.as_usize() as *const _) } } } diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi.rs index fb9edf88..474419f4 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi.rs @@ -4,46 +4,11 @@ //! Top-level BSP file for the Raspberry Pi 3 and 4. -pub mod console; pub mod cpu; pub mod driver; pub mod exception; pub mod memory; -use super::device_driver; -use crate::memory::mmu::MMIODescriptor; -use memory::map::mmio; - -//-------------------------------------------------------------------------------------------------- -// Global instances -//-------------------------------------------------------------------------------------------------- - -static GPIO: device_driver::GPIO = - unsafe { device_driver::GPIO::new(MMIODescriptor::new(mmio::GPIO_START, mmio::GPIO_SIZE)) }; - -static PL011_UART: device_driver::PL011Uart = unsafe { - device_driver::PL011Uart::new( - MMIODescriptor::new(mmio::PL011_UART_START, mmio::PL011_UART_SIZE), - exception::asynchronous::irq_map::PL011_UART, - ) -}; - -#[cfg(feature = "bsp_rpi3")] -static INTERRUPT_CONTROLLER: device_driver::InterruptController = unsafe { - device_driver::InterruptController::new( - MMIODescriptor::new(mmio::LOCAL_IC_START, mmio::LOCAL_IC_SIZE), - MMIODescriptor::new(mmio::PERIPHERAL_IC_START, mmio::PERIPHERAL_IC_SIZE), - ) -}; - -#[cfg(feature = "bsp_rpi4")] -static INTERRUPT_CONTROLLER: device_driver::GICv2 = unsafe { - device_driver::GICv2::new( - MMIODescriptor::new(mmio::GICD_START, mmio::GICD_SIZE), - MMIODescriptor::new(mmio::GICC_START, mmio::GICC_SIZE), - ) -}; - //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/console.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/console.rs deleted file mode 100644 index f4105ed7..00000000 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/console.rs +++ /dev/null @@ -1,92 +0,0 @@ -// SPDX-License-Identifier: MIT OR Apache-2.0 -// -// Copyright (c) 2018-2022 Andre Richter - -//! BSP console facilities. - -use super::memory; -use crate::{bsp::device_driver, console, cpu, driver}; -use core::fmt; - -//-------------------------------------------------------------------------------------------------- -// Public Code -//-------------------------------------------------------------------------------------------------- - -/// In case of a panic, the panic handler uses this function to take a last shot at printing -/// something before the system is halted. -/// -/// We try to init panic-versions of the GPIO and the UART. The panic versions are not protected -/// with synchronization primitives, which increases chances that we get to print something, even -/// when the kernel's default GPIO or UART instances happen to be locked at the time of the panic. -/// -/// # Safety -/// -/// - Use only for printing during a panic. -#[cfg(not(feature = "test_build"))] -pub unsafe fn panic_console_out() -> impl fmt::Write { - use driver::interface::DeviceDriver; - - let mut panic_gpio = device_driver::PanicGPIO::new(memory::map::mmio::GPIO_START.as_usize()); - let mut panic_uart = - device_driver::PanicUart::new(memory::map::mmio::PL011_UART_START.as_usize()); - - // If remapping of the driver's MMIO already happened, take the remapped start address. - // Otherwise, take a chance with the default physical address. - let maybe_gpio_mmio_start_addr = super::GPIO.virt_mmio_start_addr(); - let maybe_uart_mmio_start_addr = super::PL011_UART.virt_mmio_start_addr(); - - panic_gpio - .init(maybe_gpio_mmio_start_addr) - .unwrap_or_else(|_| cpu::wait_forever()); - panic_gpio.map_pl011_uart(); - panic_uart - .init(maybe_uart_mmio_start_addr) - .unwrap_or_else(|_| cpu::wait_forever()); - - panic_uart -} - -/// Reduced version for test builds. -/// -/// # Safety -/// -/// - Use only for printing during a panic. -#[cfg(feature = "test_build")] -pub unsafe fn panic_console_out() -> impl fmt::Write { - use driver::interface::DeviceDriver; - - let mut panic_uart = - device_driver::PanicUart::new(memory::map::mmio::PL011_UART_START.as_usize()); - - let maybe_uart_mmio_start_addr = super::PL011_UART.virt_mmio_start_addr(); - - panic_uart - .init(maybe_uart_mmio_start_addr) - .unwrap_or_else(|_| cpu::qemu_exit_failure()); - - panic_uart -} - -/// Return a reference to the console. -pub fn console() -> &'static impl console::interface::All { - &super::PL011_UART -} - -//-------------------------------------------------------------------------------------------------- -// Testing -//-------------------------------------------------------------------------------------------------- - -/// Minimal code needed to bring up the console in QEMU (for testing only). This is often less steps -/// than on real hardware due to QEMU's abstractions. -#[cfg(feature = "test_build")] -pub fn qemu_bring_up_console() { - use driver::interface::DeviceDriver; - - // Calling the UART's init ensures that the BSP's instance of the UART does remap the MMIO - // addresses. - unsafe { - super::PL011_UART - .init() - .unwrap_or_else(|_| cpu::qemu_exit_failure()); - } -} diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/driver.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/driver.rs index 53168752..e1db4a00 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/driver.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/driver.rs @@ -4,7 +4,19 @@ //! BSP driver support. -use crate::driver; +use super::{exception, memory::map::mmio}; +use crate::{ + bsp::device_driver, + console, driver, exception as generic_exception, memory, + memory::mmu::MMIODescriptor, + synchronization::{interface::ReadWriteEx, InitStateLock}, +}; +use core::{ + mem::MaybeUninit, + sync::atomic::{AtomicBool, Ordering}, +}; + +pub use device_driver::IRQNumber; //-------------------------------------------------------------------------------------------------- // Private Definitions @@ -12,21 +24,132 @@ use crate::driver; /// Device Driver Manager type. struct BSPDriverManager { - device_drivers: [&'static (dyn DeviceDriver + Sync); 3], + device_drivers: InitStateLock<[Option<&'static (dyn DeviceDriver + Sync)>; NUM_DRIVERS]>, + init_done: AtomicBool, } +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +/// The number of active drivers provided by this BSP. +pub const NUM_DRIVERS: usize = 3; + //-------------------------------------------------------------------------------------------------- // Global instances //-------------------------------------------------------------------------------------------------- +static mut PL011_UART: MaybeUninit = MaybeUninit::uninit(); +static mut GPIO: MaybeUninit = MaybeUninit::uninit(); + +#[cfg(feature = "bsp_rpi3")] +static mut INTERRUPT_CONTROLLER: MaybeUninit = + MaybeUninit::uninit(); + +#[cfg(feature = "bsp_rpi4")] +static mut INTERRUPT_CONTROLLER: MaybeUninit = MaybeUninit::uninit(); + static BSP_DRIVER_MANAGER: BSPDriverManager = BSPDriverManager { - device_drivers: [ - &super::GPIO, - &super::PL011_UART, - &super::INTERRUPT_CONTROLLER, - ], + device_drivers: InitStateLock::new([None; NUM_DRIVERS]), + init_done: AtomicBool::new(false), }; +//-------------------------------------------------------------------------------------------------- +// Private Code +//-------------------------------------------------------------------------------------------------- + +impl BSPDriverManager { + unsafe fn instantiate_uart(&self) -> Result<(), &'static str> { + let mmio_descriptor = MMIODescriptor::new(mmio::PL011_UART_START, mmio::PL011_UART_SIZE); + let virt_addr = + memory::mmu::kernel_map_mmio(device_driver::PL011Uart::COMPATIBLE, &mmio_descriptor)?; + + // This is safe to do, because it is only called from the init'ed instance itself. + fn uart_post_init() { + console::register_console(unsafe { PL011_UART.assume_init_ref() }); + } + + PL011_UART.write(device_driver::PL011Uart::new( + virt_addr, + exception::asynchronous::irq_map::PL011_UART, + uart_post_init, + )); + + Ok(()) + } + + unsafe fn instantiate_gpio(&self) -> Result<(), &'static str> { + let mmio_descriptor = MMIODescriptor::new(mmio::GPIO_START, mmio::GPIO_SIZE); + let virt_addr = + memory::mmu::kernel_map_mmio(device_driver::GPIO::COMPATIBLE, &mmio_descriptor)?; + + // This is safe to do, because it is only called from the init'ed instance itself. + fn gpio_post_init() { + unsafe { GPIO.assume_init_ref().map_pl011_uart() }; + } + + GPIO.write(device_driver::GPIO::new(virt_addr, gpio_post_init)); + + Ok(()) + } + + #[cfg(feature = "bsp_rpi3")] + unsafe fn instantiate_interrupt_controller(&self) -> Result<(), &'static str> { + let periph_mmio_descriptor = + MMIODescriptor::new(mmio::PERIPHERAL_IC_START, mmio::PERIPHERAL_IC_SIZE); + let periph_virt_addr = memory::mmu::kernel_map_mmio( + device_driver::InterruptController::COMPATIBLE, + &periph_mmio_descriptor, + )?; + + // This is safe to do, because it is only called from the init'ed instance itself. + fn interrupt_controller_post_init() { + generic_exception::asynchronous::register_irq_manager(unsafe { + INTERRUPT_CONTROLLER.assume_init_ref() + }); + } + + INTERRUPT_CONTROLLER.write(device_driver::InterruptController::new( + periph_virt_addr, + interrupt_controller_post_init, + )); + + Ok(()) + } + + #[cfg(feature = "bsp_rpi4")] + unsafe fn instantiate_interrupt_controller(&self) -> Result<(), &'static str> { + let gicd_mmio_descriptor = MMIODescriptor::new(mmio::GICD_START, mmio::GICD_SIZE); + let gicd_virt_addr = memory::mmu::kernel_map_mmio("GICv2 GICD", &gicd_mmio_descriptor)?; + + let gicc_mmio_descriptor = MMIODescriptor::new(mmio::GICC_START, mmio::GICC_SIZE); + let gicc_virt_addr = memory::mmu::kernel_map_mmio("GICV2 GICC", &gicc_mmio_descriptor)?; + + // This is safe to do, because it is only called from the init'ed instance itself. + fn interrupt_controller_post_init() { + generic_exception::asynchronous::register_irq_manager(unsafe { + INTERRUPT_CONTROLLER.assume_init_ref() + }); + } + + INTERRUPT_CONTROLLER.write(device_driver::GICv2::new( + gicd_virt_addr, + gicc_virt_addr, + interrupt_controller_post_init, + )); + + Ok(()) + } + + unsafe fn register_drivers(&self) { + self.device_drivers.write(|drivers| { + drivers[0] = Some(PL011_UART.assume_init_ref()); + drivers[1] = Some(GPIO.assume_init_ref()); + drivers[2] = Some(INTERRUPT_CONTROLLER.assume_init_ref()); + }); + } +} + //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- @@ -42,20 +165,34 @@ pub fn driver_manager() -> &'static impl driver::interface::DriverManager { use driver::interface::DeviceDriver; impl driver::interface::DriverManager for BSPDriverManager { - fn all_device_drivers(&self) -> &[&'static (dyn DeviceDriver + Sync)] { - &self.device_drivers[..] - } + unsafe fn instantiate_drivers(&self) -> Result<(), &'static str> { + if self.init_done.load(Ordering::Relaxed) { + return Err("Drivers already instantiated"); + } + + self.instantiate_uart()?; + self.instantiate_gpio()?; + self.instantiate_interrupt_controller()?; - fn early_print_device_drivers(&self) -> &[&'static (dyn DeviceDriver + Sync)] { - &self.device_drivers[0..=1] + self.register_drivers(); + + self.init_done.store(true, Ordering::Relaxed); + Ok(()) } - fn non_early_print_device_drivers(&self) -> &[&'static (dyn DeviceDriver + Sync)] { - &self.device_drivers[2..] + fn all_device_drivers(&self) -> [&(dyn DeviceDriver + Sync); NUM_DRIVERS] { + self.device_drivers + .read(|drivers| drivers.map(|drivers| drivers.unwrap())) } - fn post_early_print_device_driver_init(&self) { - // Configure PL011Uart's output pins. - super::GPIO.map_pl011_uart(); + #[cfg(feature = "test_build")] + fn qemu_bring_up_console(&self) { + use crate::cpu; + + unsafe { + self.instantiate_uart() + .unwrap_or_else(|_| cpu::qemu_exit_failure()); + console::register_console(PL011_UART.assume_init_ref()); + }; } } diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/exception/asynchronous.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/exception/asynchronous.rs index dc5ab421..ab20d86d 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/exception/asynchronous.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/exception/asynchronous.rs @@ -4,7 +4,7 @@ //! BSP asynchronous exception handling. -use crate::{bsp, exception}; +use crate::bsp; //-------------------------------------------------------------------------------------------------- // Public Definitions @@ -23,14 +23,3 @@ pub(in crate::bsp) mod irq_map { pub const PL011_UART: IRQNumber = IRQNumber::new(153); } - -//-------------------------------------------------------------------------------------------------- -// Public Code -//-------------------------------------------------------------------------------------------------- - -/// Return a reference to the IRQ manager. -pub fn irq_manager() -> &'static impl exception::asynchronous::interface::IRQManager< - IRQNumberType = bsp::device_driver::IRQNumber, -> { - &super::super::INTERRUPT_CONTROLLER -} diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/memory.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/memory.rs index 660409bb..7d6e7911 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/memory.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/memory.rs @@ -107,9 +107,6 @@ pub(super) mod map { pub const PL011_UART_START: Address = Address::new(0x3F20_1000); pub const PL011_UART_SIZE: usize = 0x48; - pub const LOCAL_IC_START: Address = Address::new(0x4000_0000); - pub const LOCAL_IC_SIZE: usize = 0x100; - pub const END: Address = Address::new(0x4001_0000); } diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/console.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/console.rs index e49e241f..a85bcffe 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/console.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/console.rs @@ -4,6 +4,10 @@ //! System console. +mod null_console; + +use crate::synchronization; + //-------------------------------------------------------------------------------------------------- // Public Definitions //-------------------------------------------------------------------------------------------------- @@ -49,5 +53,29 @@ pub mod interface { } /// Trait alias for a full-fledged console. - pub trait All = Write + Read + Statistics; + pub trait All: Write + Read + Statistics {} +} + +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +static CUR_CONSOLE: InitStateLock<&'static (dyn interface::All + Sync)> = + InitStateLock::new(&null_console::NULL_CONSOLE); + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- +use synchronization::{interface::ReadWriteEx, InitStateLock}; + +/// Register a new console. +pub fn register_console(new_console: &'static (dyn interface::All + Sync)) { + CUR_CONSOLE.write(|con| *con = new_console); +} + +/// Return a reference to the currently registered console. +/// +/// This is the global console used by all printing macros. +pub fn console() -> &'static dyn interface::All { + CUR_CONSOLE.read(|con| *con) } diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/console/null_console.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/console/null_console.rs new file mode 100644 index 00000000..10c3bedc --- /dev/null +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/console/null_console.rs @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2022 Andre Richter + +//! Null console. + +use super::interface; +use core::fmt; + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +pub struct NullConsole; + +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +pub static NULL_CONSOLE: NullConsole = NullConsole {}; + +//-------------------------------------------------------------------------------------------------- +// Private Code +//-------------------------------------------------------------------------------------------------- + +impl interface::Write for NullConsole { + fn write_char(&self, _c: char) {} + + fn write_fmt(&self, _args: fmt::Arguments) -> fmt::Result { + fmt::Result::Ok(()) + } + + fn flush(&self) {} +} + +impl interface::Read for NullConsole { + fn clear_rx(&self) {} +} + +impl interface::Statistics for NullConsole {} +impl interface::All for NullConsole {} diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/driver.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/driver.rs index 7b800dbc..98197fef 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/driver.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/driver.rs @@ -10,6 +10,8 @@ /// Driver interfaces. pub mod interface { + use crate::bsp; + /// Device Driver functions. pub trait DeviceDriver { /// Return a compatibility string for identifying the driver. @@ -31,32 +33,25 @@ pub mod interface { fn register_and_enable_irq_handler(&'static self) -> Result<(), &'static str> { Ok(()) } - - /// After MMIO remapping, returns the new virtual start address. - /// - /// This API assumes a driver has only a single, contiguous MMIO aperture, which will not be - /// the case for more complex devices. This API will likely change in future tutorials. - fn virt_mmio_start_addr(&self) -> Option { - None - } } /// Device driver management functions. /// /// The `BSP` is supposed to supply one global instance. pub trait DriverManager { - /// Return a slice of references to all `BSP`-instantiated drivers. - fn all_device_drivers(&self) -> &[&'static (dyn DeviceDriver + Sync)]; - - /// Return only those drivers needed for the BSP's early printing functionality. + /// Instantiate all drivers. + /// + /// # Safety /// - /// For example, the default UART. - fn early_print_device_drivers(&self) -> &[&'static (dyn DeviceDriver + Sync)]; + /// Must be called before `all_device_drivers`. + unsafe fn instantiate_drivers(&self) -> Result<(), &'static str>; - /// Return all drivers minus early-print drivers. - fn non_early_print_device_drivers(&self) -> &[&'static (dyn DeviceDriver + Sync)]; + /// Return a slice of references to all `BSP`-instantiated drivers. + fn all_device_drivers(&self) -> [&(dyn DeviceDriver + Sync); bsp::driver::NUM_DRIVERS]; - /// Initialization code that runs after the early print driver init. - fn post_early_print_device_driver_init(&self); + /// Minimal code needed to bring up the console in QEMU (for testing only). This is often + /// less steps than on real hardware due to QEMU's abstractions. + #[cfg(feature = "test_build")] + fn qemu_bring_up_console(&self); } } diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/exception/asynchronous.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/exception/asynchronous.rs index fb1785c2..d9d2767c 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/exception/asynchronous.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/exception/asynchronous.rs @@ -7,7 +7,9 @@ #[cfg(target_arch = "aarch64")] #[path = "../_arch/aarch64/exception/asynchronous.rs"] mod arch_asynchronous; +mod null_irq_manager; +use crate::{bsp, synchronization}; use core::{fmt, marker::PhantomData}; //-------------------------------------------------------------------------------------------------- @@ -85,7 +87,7 @@ pub mod interface { ); /// Print list of registered handlers. - fn print_handler(&self); + fn print_handler(&self) {} } } @@ -93,9 +95,18 @@ pub mod interface { #[derive(Copy, Clone)] pub struct IRQNumber(usize); +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +static CUR_IRQ_MANAGER: InitStateLock< + &'static (dyn interface::IRQManager + Sync), +> = InitStateLock::new(&null_irq_manager::NULL_IRQ_MANAGER); + //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- +use synchronization::{interface::ReadWriteEx, InitStateLock}; impl<'irq_context> IRQContext<'irq_context> { /// Creates an IRQContext token. @@ -150,3 +161,18 @@ pub fn exec_with_irq_masked(f: impl FnOnce() -> T) -> T { ret } + +/// Register a new IRQ manager. +pub fn register_irq_manager( + new_manager: &'static (dyn interface::IRQManager + + Sync), +) { + CUR_IRQ_MANAGER.write(|manager| *manager = new_manager); +} + +/// Return a reference to the currently registered IRQ manager. +/// +/// This is the IRQ manager used by the architectural interrupt handling code. +pub fn irq_manager() -> &'static dyn interface::IRQManager { + CUR_IRQ_MANAGER.read(|manager| *manager) +} diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/exception/asynchronous/null_irq_manager.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/exception/asynchronous/null_irq_manager.rs new file mode 100644 index 00000000..560e3ce4 --- /dev/null +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/exception/asynchronous/null_irq_manager.rs @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2022 Andre Richter + +//! Null IRQ Manager. + +use super::{interface, IRQContext, IRQDescriptor}; +use crate::bsp; + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +pub struct NullIRQManager; + +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +pub static NULL_IRQ_MANAGER: NullIRQManager = NullIRQManager {}; + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +impl interface::IRQManager for NullIRQManager { + type IRQNumberType = bsp::driver::IRQNumber; + + fn register_handler( + &self, + _irq_number: Self::IRQNumberType, + _descriptor: IRQDescriptor, + ) -> Result<(), &'static str> { + panic!("No IRQ Manager registered yet"); + } + + fn enable(&self, _irq_number: Self::IRQNumberType) { + panic!("No IRQ Manager registered yet"); + } + + fn handle_pending_irqs<'irq_context>(&'irq_context self, _ic: &IRQContext<'irq_context>) { + panic!("No IRQ Manager registered yet"); + } +} diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/lib.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/lib.rs index aeab8c22..1787ce02 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/lib.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/lib.rs @@ -114,6 +114,7 @@ #![feature(core_intrinsics)] #![feature(format_args_nl)] #![feature(generic_const_exprs)] +#![feature(is_sorted)] #![feature(linkage)] #![feature(panic_info_message)] #![feature(step_trait)] @@ -181,9 +182,11 @@ pub fn test_runner(tests: &[&test_types::UnitTest]) { #[cfg(test)] #[no_mangle] unsafe fn kernel_init() -> ! { + use driver::interface::DriverManager; + exception::handling_init(); memory::mmu::post_enable_init(); - bsp::console::qemu_bring_up_console(); + bsp::driver::driver_manager().qemu_bring_up_console(); test_main(); diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/main.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/main.rs index 5150f3af..928f12c2 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/main.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/main.rs @@ -30,26 +30,11 @@ unsafe fn kernel_init() -> ! { exception::handling_init(); memory::mmu::post_enable_init(); - // Add the mapping records for the precomputed entries first, so that they appear on the top of - // the list. - bsp::memory::mmu::kernel_add_mapping_records_for_precomputed(); - - // Bring up the drivers needed for printing first. - for i in bsp::driver::driver_manager() - .early_print_device_drivers() - .iter() - { - // Any encountered errors cannot be printed yet, obviously, so just safely park the CPU. - i.init().unwrap_or_else(|_| cpu::wait_forever()); + // Instantiate and init all device drivers. + if let Err(x) = bsp::driver::driver_manager().instantiate_drivers() { + panic!("Error instantiating drivers: {}", x); } - bsp::driver::driver_manager().post_early_print_device_driver_init(); - // Printing available from here on. - - // Now bring up the remaining drivers. - for i in bsp::driver::driver_manager() - .non_early_print_device_drivers() - .iter() - { + for i in bsp::driver::driver_manager().all_device_drivers().iter() { if let Err(x) = i.init() { panic!("Error loading driver: {}: {}", i.compatible(), x); } @@ -62,6 +47,8 @@ unsafe fn kernel_init() -> ! { } } + bsp::memory::mmu::kernel_add_mapping_records_for_precomputed(); + // Unmask interrupts on the boot CPU core. exception::asynchronous::local_irq_unmask(); @@ -75,7 +62,6 @@ unsafe fn kernel_init() -> ! { /// The main function running after the early init. fn kernel_main() -> ! { use driver::interface::DriverManager; - use exception::asynchronous::interface::IRQManager; info!("{}", libkernel::version()); info!("Booting on: {}", bsp::board_name()); @@ -104,7 +90,7 @@ fn kernel_main() -> ! { } info!("Registered IRQ handlers:"); - bsp::exception::asynchronous::irq_manager().print_handler(); + exception::asynchronous::irq_manager().print_handler(); info!("Echoing input now"); cpu::wait_forever(); diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/memory.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/memory.rs index f20719bb..64d8cf64 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/memory.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/memory.rs @@ -18,18 +18,18 @@ use core::{ //-------------------------------------------------------------------------------------------------- /// Metadata trait for marking the type of an address. -pub trait AddressType: Copy + Clone + PartialOrd + PartialEq {} +pub trait AddressType: Copy + Clone + PartialOrd + PartialEq + Ord + Eq {} /// Zero-sized type to mark a physical address. -#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)] +#[derive(Copy, Clone, Debug, PartialOrd, PartialEq, Ord, Eq)] pub enum Physical {} /// Zero-sized type to mark a virtual address. -#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)] +#[derive(Copy, Clone, Debug, PartialOrd, PartialEq, Ord, Eq)] pub enum Virtual {} /// Generic address type. -#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)] +#[derive(Copy, Clone, Debug, PartialOrd, PartialEq, Ord, Eq)] pub struct Address { value: usize, _address_type: PhantomData ATYPE>, diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/memory/mmu/mapping_record.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/memory/mmu/mapping_record.rs index d171c6e6..7d3a6c60 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/memory/mmu/mapping_record.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/memory/mmu/mapping_record.rs @@ -76,6 +76,19 @@ impl MappingRecord { Self { inner: [None; 12] } } + fn size(&self) -> usize { + self.inner.iter().filter(|x| x.is_some()).count() + } + + fn sort(&mut self) { + let upper_bound_exclusive = self.size(); + let entries = &mut self.inner[0..upper_bound_exclusive]; + + if !entries.is_sorted_by_key(|item| item.unwrap().virt_start_addr) { + entries.sort_unstable_by_key(|item| item.unwrap().virt_start_addr) + } + } + fn find_next_free(&mut self) -> Result<&mut Option, &'static str> { if let Some(x) = self.inner.iter_mut().find(|x| x.is_none()) { return Ok(x); @@ -121,6 +134,9 @@ impl MappingRecord { phys_region, attr, )); + + self.sort(); + Ok(()) } diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/panic_wait.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/panic_wait.rs index 08d7d453..e4256b61 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/panic_wait.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/panic_wait.rs @@ -4,19 +4,13 @@ //! A panic handler that infinitely waits. -use crate::{bsp, cpu, exception}; -use core::{fmt, panic::PanicInfo}; +use crate::{cpu, exception, println}; +use core::panic::PanicInfo; //-------------------------------------------------------------------------------------------------- // Private Code //-------------------------------------------------------------------------------------------------- -fn _panic_print(args: fmt::Arguments) { - use fmt::Write; - - unsafe { bsp::console::panic_console_out().write_fmt(args).unwrap() }; -} - /// The point of exit for `libkernel`. /// /// It is linked weakly, so that the integration tests can overload its standard behavior. @@ -34,16 +28,6 @@ fn _panic_exit() -> ! { } } -/// Prints with a newline - only use from the panic handler. -/// -/// Carbon copy from -#[macro_export] -macro_rules! panic_println { - ($($arg:tt)*) => ({ - _panic_print(format_args_nl!($($arg)*)); - }) -} - /// Stop immediately if called a second time. /// /// # Note @@ -88,7 +72,7 @@ fn panic(info: &PanicInfo) -> ! { _ => ("???", 0, 0), }; - panic_println!( + println!( "[ {:>3}.{:06}] Kernel panic!\n\n\ Panic location:\n File '{}', line {}, column {}\n\n\ {}", diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/print.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/print.rs index 9ec13a28..8705eec0 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/print.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/print.rs @@ -4,7 +4,7 @@ //! Printing. -use crate::{bsp, console}; +use crate::console; use core::fmt; //-------------------------------------------------------------------------------------------------- @@ -13,9 +13,7 @@ use core::fmt; #[doc(hidden)] pub fn _print(args: fmt::Arguments) { - use console::interface::Write; - - bsp::console::console().write_fmt(args).unwrap(); + console::console().write_fmt(args).unwrap(); } /// Prints without a newline. diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/tests/00_console_sanity.rs b/15_virtual_mem_part3_precomputed_tables/kernel/tests/00_console_sanity.rs index 6595aac1..f2a1f3ed 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/tests/00_console_sanity.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/tests/00_console_sanity.rs @@ -11,16 +11,16 @@ /// Console tests should time out on the I/O harness in case of panic. mod panic_wait_forever; -use libkernel::{bsp, console, cpu, exception, memory, print}; +use libkernel::{bsp, console, cpu, driver, exception, memory, print}; #[no_mangle] unsafe fn kernel_init() -> ! { - use bsp::console::console; - use console::interface::*; + use console::console; + use driver::interface::DriverManager; exception::handling_init(); memory::mmu::post_enable_init(); - bsp::console::qemu_bring_up_console(); + bsp::driver::driver_manager().qemu_bring_up_console(); // Handshake assert_eq!(console().read_char(), 'A'); diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/tests/01_timer_sanity.rs b/15_virtual_mem_part3_precomputed_tables/kernel/tests/01_timer_sanity.rs index 9b2b228d..caeca3cd 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/tests/01_timer_sanity.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/tests/01_timer_sanity.rs @@ -11,14 +11,16 @@ #![test_runner(libkernel::test_runner)] use core::time::Duration; -use libkernel::{bsp, cpu, exception, memory, time, time::interface::TimeManager}; +use libkernel::{bsp, cpu, driver, exception, memory, time, time::interface::TimeManager}; use test_macros::kernel_test; #[no_mangle] unsafe fn kernel_init() -> ! { + use driver::interface::DriverManager; + exception::handling_init(); memory::mmu::post_enable_init(); - bsp::console::qemu_bring_up_console(); + bsp::driver::driver_manager().qemu_bring_up_console(); // Depending on CPU arch, some timer bring-up code could go here. Not needed for the RPi. diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/tests/02_exception_sync_page_fault.rs b/15_virtual_mem_part3_precomputed_tables/kernel/tests/02_exception_sync_page_fault.rs index 2d4b0977..feb84d9b 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/tests/02_exception_sync_page_fault.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/tests/02_exception_sync_page_fault.rs @@ -17,13 +17,15 @@ /// or indirectly. mod panic_exit_success; -use libkernel::{bsp, cpu, exception, info, memory, println}; +use libkernel::{bsp, cpu, driver, exception, info, memory, println}; #[no_mangle] unsafe fn kernel_init() -> ! { + use driver::interface::DriverManager; + exception::handling_init(); memory::mmu::post_enable_init(); - bsp::console::qemu_bring_up_console(); + bsp::driver::driver_manager().qemu_bring_up_console(); // This line will be printed as the test header. println!("Testing synchronous exception handling by causing a page fault"); diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/tests/03_exception_restore_sanity.rs b/15_virtual_mem_part3_precomputed_tables/kernel/tests/03_exception_restore_sanity.rs index 983d488f..a521a871 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/tests/03_exception_restore_sanity.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/tests/03_exception_restore_sanity.rs @@ -12,7 +12,7 @@ mod panic_wait_forever; use core::arch::asm; -use libkernel::{bsp, cpu, exception, info, memory, println}; +use libkernel::{bsp, cpu, driver, exception, info, memory, println}; #[inline(never)] fn nested_system_call() { @@ -30,9 +30,11 @@ fn nested_system_call() { #[no_mangle] unsafe fn kernel_init() -> ! { + use driver::interface::DriverManager; + exception::handling_init(); memory::mmu::post_enable_init(); - bsp::console::qemu_bring_up_console(); + bsp::driver::driver_manager().qemu_bring_up_console(); // This line will be printed as the test header. println!("Testing exception restore"); diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/tests/04_exception_irq_sanity.rs b/15_virtual_mem_part3_precomputed_tables/kernel/tests/04_exception_irq_sanity.rs index 9030424d..cd2d29d6 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/tests/04_exception_irq_sanity.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/tests/04_exception_irq_sanity.rs @@ -10,13 +10,15 @@ #![reexport_test_harness_main = "test_main"] #![test_runner(libkernel::test_runner)] -use libkernel::{bsp, cpu, exception, memory}; +use libkernel::{bsp, cpu, driver, exception, memory}; use test_macros::kernel_test; #[no_mangle] unsafe fn kernel_init() -> ! { + use driver::interface::DriverManager; + memory::mmu::post_enable_init(); - bsp::console::qemu_bring_up_console(); + bsp::driver::driver_manager().qemu_bring_up_console(); exception::handling_init(); exception::asynchronous::local_irq_unmask(); diff --git a/16_virtual_mem_part4_higher_half_kernel/README.md b/16_virtual_mem_part4_higher_half_kernel/README.md index a9282d80..943273c0 100644 --- a/16_virtual_mem_part4_higher_half_kernel/README.md +++ b/16_virtual_mem_part4_higher_half_kernel/README.md @@ -253,22 +253,22 @@ Minipush 1.0 Raspberry Pi 3 [ML] Requesting binary -[MP] ⏩ Pushing 259 KiB ======================================🦀 100% 129 KiB/s Time: 00:00:02 +[MP] ⏩ Pushing 257 KiB ======================================🦀 100% 128 KiB/s Time: 00:00:02 [ML] Loaded! Executing the payload now -[ 2.893480] mingo version 0.16.0 -[ 2.893687] Booting on: Raspberry Pi 3 -[ 2.894142] MMU online: -[ 2.894434] ------------------------------------------------------------------------------------------------------------------------------------------- -[ 2.896179] Virtual Physical Size Attr Entity -[ 2.897923] ------------------------------------------------------------------------------------------------------------------------------------------- -[ 2.899668] 0xffff_ffff_c000_0000..0xffff_ffff_c000_ffff --> 0x00_0008_0000..0x00_0008_ffff | 64 KiB | C RO X | Kernel code and RO data -[ 2.901282] 0xffff_ffff_c001_0000..0xffff_ffff_c004_ffff --> 0x00_0009_0000..0x00_000c_ffff | 256 KiB | C RW XN | Kernel data and bss -[ 2.902852] 0xffff_ffff_c086_0000..0xffff_ffff_c08d_ffff --> 0x00_0000_0000..0x00_0007_ffff | 512 KiB | C RW XN | Kernel boot-core stack -[ 2.904455] 0xffff_ffff_c005_0000..0xffff_ffff_c005_ffff --> 0x00_3f20_0000..0x00_3f20_ffff | 64 KiB | Dev RW XN | BCM GPIO -[ 2.905907] | BCM PL011 UART -[ 2.907424] 0xffff_ffff_c006_0000..0xffff_ffff_c006_ffff --> 0x00_3f00_0000..0x00_3f00_ffff | 64 KiB | Dev RW XN | BCM Peripheral Interrupt Controller -[ 2.909168] ------------------------------------------------------------------------------------------------------------------------------------------- +[ 2.870248] mingo version 0.16.0 +[ 2.870456] Booting on: Raspberry Pi 3 +[ 2.870911] MMU online: +[ 2.871203] ------------------------------------------------------------------------------------------------------------------------------------------- +[ 2.872947] Virtual Physical Size Attr Entity +[ 2.874691] ------------------------------------------------------------------------------------------------------------------------------------------- +[ 2.876436] 0xffff_ffff_c000_0000..0xffff_ffff_c000_ffff --> 0x00_0008_0000..0x00_0008_ffff | 64 KiB | C RO X | Kernel code and RO data +[ 2.878050] 0xffff_ffff_c001_0000..0xffff_ffff_c004_ffff --> 0x00_0009_0000..0x00_000c_ffff | 256 KiB | C RW XN | Kernel data and bss +[ 2.879621] 0xffff_ffff_c005_0000..0xffff_ffff_c005_ffff --> 0x00_3f20_0000..0x00_3f20_ffff | 64 KiB | Dev RW XN | BCM PL011 UART +[ 2.881137] | BCM GPIO +[ 2.882589] 0xffff_ffff_c006_0000..0xffff_ffff_c006_ffff --> 0x00_3f00_0000..0x00_3f00_ffff | 64 KiB | Dev RW XN | BCM Interrupt Controller +[ 2.884214] 0xffff_ffff_c086_0000..0xffff_ffff_c08d_ffff --> 0x00_0000_0000..0x00_0007_ffff | 512 KiB | C RW XN | Kernel boot-core stack +[ 2.885818] ------------------------------------------------------------------------------------------------------------------------------------------- ``` Raspberry Pi 4: @@ -303,23 +303,23 @@ Minipush 1.0 Raspberry Pi 4 [ML] Requesting binary -[MP] ⏩ Pushing 266 KiB ======================================🦀 100% 133 KiB/s Time: 00:00:02 +[MP] ⏩ Pushing 257 KiB ======================================🦀 100% 128 KiB/s Time: 00:00:02 [ML] Loaded! Executing the payload now -[ 2.973300] mingo version 0.16.0 -[ 2.973334] Booting on: Raspberry Pi 4 -[ 2.973789] MMU online: -[ 2.974081] ------------------------------------------------------------------------------------------------------------------------------------------- -[ 2.975825] Virtual Physical Size Attr Entity -[ 2.977569] ------------------------------------------------------------------------------------------------------------------------------------------- -[ 2.979314] 0xffff_ffff_c000_0000..0xffff_ffff_c000_ffff --> 0x00_0008_0000..0x00_0008_ffff | 64 KiB | C RO X | Kernel code and RO data -[ 2.980929] 0xffff_ffff_c001_0000..0xffff_ffff_c004_ffff --> 0x00_0009_0000..0x00_000c_ffff | 256 KiB | C RW XN | Kernel data and bss -[ 2.982499] 0xffff_ffff_c086_0000..0xffff_ffff_c08d_ffff --> 0x00_0000_0000..0x00_0007_ffff | 512 KiB | C RW XN | Kernel boot-core stack -[ 2.984102] 0xffff_ffff_c005_0000..0xffff_ffff_c005_ffff --> 0x00_fe20_0000..0x00_fe20_ffff | 64 KiB | Dev RW XN | BCM GPIO -[ 2.985554] | BCM PL011 UART -[ 2.987070] 0xffff_ffff_c006_0000..0xffff_ffff_c006_ffff --> 0x00_ff84_0000..0x00_ff84_ffff | 64 KiB | Dev RW XN | GICD -[ 2.988479] | GICC -[ 2.989887] ------------------------------------------------------------------------------------------------------------------------------------------- +[ 2.871960] mingo version 0.16.0 +[ 2.871994] Booting on: Raspberry Pi 4 +[ 2.872449] MMU online: +[ 2.872742] ------------------------------------------------------------------------------------------------------------------------------------------- +[ 2.874486] Virtual Physical Size Attr Entity +[ 2.876230] ------------------------------------------------------------------------------------------------------------------------------------------- +[ 2.877975] 0xffff_ffff_c000_0000..0xffff_ffff_c000_ffff --> 0x00_0008_0000..0x00_0008_ffff | 64 KiB | C RO X | Kernel code and RO data +[ 2.879589] 0xffff_ffff_c001_0000..0xffff_ffff_c004_ffff --> 0x00_0009_0000..0x00_000c_ffff | 256 KiB | C RW XN | Kernel data and bss +[ 2.881159] 0xffff_ffff_c005_0000..0xffff_ffff_c005_ffff --> 0x00_fe20_0000..0x00_fe20_ffff | 64 KiB | Dev RW XN | BCM PL011 UART +[ 2.882676] | BCM GPIO +[ 2.884128] 0xffff_ffff_c006_0000..0xffff_ffff_c006_ffff --> 0x00_ff84_0000..0x00_ff84_ffff | 64 KiB | Dev RW XN | GICv2 GICD +[ 2.885601] | GICV2 GICC +[ 2.887074] 0xffff_ffff_c086_0000..0xffff_ffff_c08d_ffff --> 0x00_0000_0000..0x00_0007_ffff | 512 KiB | C RW XN | Kernel boot-core stack +[ 2.888678] ------------------------------------------------------------------------------------------------------------------------------------------- ``` ## Diff to previous @@ -568,76 +568,6 @@ diff -uNr 15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/memor self.configure_translation_control(); -diff -uNr 15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/console.rs 16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi/console.rs ---- 15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/console.rs -+++ 16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi/console.rs -@@ -4,7 +4,6 @@ - - //! BSP console facilities. - --use super::memory; - use crate::{bsp::device_driver, console, cpu, driver}; - use core::fmt; - -@@ -26,21 +25,27 @@ - pub unsafe fn panic_console_out() -> impl fmt::Write { - use driver::interface::DeviceDriver; - -- let mut panic_gpio = device_driver::PanicGPIO::new(memory::map::mmio::GPIO_START.as_usize()); -- let mut panic_uart = -- device_driver::PanicUart::new(memory::map::mmio::PL011_UART_START.as_usize()); -- -- // If remapping of the driver's MMIO already happened, take the remapped start address. -- // Otherwise, take a chance with the default physical address. -- let maybe_gpio_mmio_start_addr = super::GPIO.virt_mmio_start_addr(); -- let maybe_uart_mmio_start_addr = super::PL011_UART.virt_mmio_start_addr(); -+ // If remapping of the driver's MMIO hasn't already happened, we won't be able to print. Just -+ // park the CPU core in this case. -+ let gpio_mmio_start_addr = match super::GPIO.virt_mmio_start_addr() { -+ None => cpu::wait_forever(), -+ Some(x) => x, -+ }; -+ -+ let uart_mmio_start_addr = match super::PL011_UART.virt_mmio_start_addr() { -+ None => cpu::wait_forever(), -+ Some(x) => x, -+ }; -+ -+ let mut panic_gpio = device_driver::PanicGPIO::new(gpio_mmio_start_addr); -+ let mut panic_uart = device_driver::PanicUart::new(uart_mmio_start_addr); - - panic_gpio -- .init(maybe_gpio_mmio_start_addr) -+ .init(None) - .unwrap_or_else(|_| cpu::wait_forever()); - panic_gpio.map_pl011_uart(); - panic_uart -- .init(maybe_uart_mmio_start_addr) -+ .init(None) - .unwrap_or_else(|_| cpu::wait_forever()); - - panic_uart -@@ -55,13 +60,14 @@ - pub unsafe fn panic_console_out() -> impl fmt::Write { - use driver::interface::DeviceDriver; - -- let mut panic_uart = -- device_driver::PanicUart::new(memory::map::mmio::PL011_UART_START.as_usize()); -- -- let maybe_uart_mmio_start_addr = super::PL011_UART.virt_mmio_start_addr(); -+ let uart_mmio_start_addr = match super::PL011_UART.virt_mmio_start_addr() { -+ None => cpu::wait_forever(), -+ Some(x) => x, -+ }; -+ let mut panic_uart = device_driver::PanicUart::new(uart_mmio_start_addr); - - panic_uart -- .init(maybe_uart_mmio_start_addr) -+ .init(None) - .unwrap_or_else(|_| cpu::qemu_exit_failure()); - - panic_uart - diff -uNr 15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/kernel.ld 16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi/kernel.ld --- 15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/kernel.ld +++ 16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi/kernel.ld @@ -799,7 +729,7 @@ diff -uNr 15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/mem diff -uNr 15_virtual_mem_part3_precomputed_tables/kernel/src/lib.rs 16_virtual_mem_part4_higher_half_kernel/kernel/src/lib.rs --- 15_virtual_mem_part3_precomputed_tables/kernel/src/lib.rs +++ 16_virtual_mem_part4_higher_half_kernel/kernel/src/lib.rs -@@ -152,11 +152,6 @@ +@@ -153,11 +153,6 @@ ) } @@ -873,7 +803,7 @@ diff -uNr 15_virtual_mem_part3_precomputed_tables/kernel/src/memory/mmu.rs 16_vi diff -uNr 15_virtual_mem_part3_precomputed_tables/kernel/tests/02_exception_sync_page_fault.rs 16_virtual_mem_part4_higher_half_kernel/kernel/tests/02_exception_sync_page_fault.rs --- 15_virtual_mem_part3_precomputed_tables/kernel/tests/02_exception_sync_page_fault.rs +++ 16_virtual_mem_part4_higher_half_kernel/kernel/tests/02_exception_sync_page_fault.rs -@@ -28,8 +28,8 @@ +@@ -30,8 +30,8 @@ // This line will be printed as the test header. println!("Testing synchronous exception handling by causing a page fault"); diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/exception.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/exception.rs index 662c91b9..fa6748a6 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/exception.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/exception.rs @@ -11,7 +11,7 @@ //! //! crate::exception::arch_exception -use crate::{bsp, exception}; +use crate::exception; use core::{arch::global_asm, cell::UnsafeCell, fmt}; use cortex_a::{asm::barrier, registers::*}; use tock_registers::{ @@ -104,10 +104,8 @@ unsafe extern "C" fn current_elx_synchronous(e: &mut ExceptionContext) { #[no_mangle] unsafe extern "C" fn current_elx_irq(_e: &mut ExceptionContext) { - use exception::asynchronous::interface::IRQManager; - let token = &exception::asynchronous::IRQContext::new(); - bsp::exception::asynchronous::irq_manager().handle_pending_irqs(token); + exception::asynchronous::irq_manager().handle_pending_irqs(token); } #[no_mangle] diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/arm/gicv2.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/arm/gicv2.rs index 4c68a692..e72fde7b 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/arm/gicv2.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/arm/gicv2.rs @@ -79,8 +79,12 @@ mod gicc; mod gicd; -use crate::{bsp, cpu, driver, exception, memory, synchronization, synchronization::InitStateLock}; -use core::sync::atomic::{AtomicBool, Ordering}; +use crate::{ + bsp, cpu, driver, exception, + memory::{Address, Virtual}, + synchronization, + synchronization::InitStateLock, +}; //-------------------------------------------------------------------------------------------------- // Private Definitions @@ -97,20 +101,17 @@ pub type IRQNumber = exception::asynchronous::IRQNumber<{ GICv2::MAX_IRQ_NUMBER /// Representation of the GIC. pub struct GICv2 { - gicd_mmio_descriptor: memory::mmu::MMIODescriptor, - gicc_mmio_descriptor: memory::mmu::MMIODescriptor, - /// The Distributor. gicd: gicd::GICD, /// The CPU Interface. gicc: gicc::GICC, - /// Have the MMIO regions been remapped yet? - is_mmio_remapped: AtomicBool, - /// Stores registered IRQ handlers. Writable only during kernel init. RO afterwards. handler_table: InitStateLock, + + /// Callback to be invoked after successful init. + post_init_callback: fn(), } //-------------------------------------------------------------------------------------------------- @@ -121,22 +122,23 @@ impl GICv2 { const MAX_IRQ_NUMBER: usize = 300; // Normally 1019, but keep it lower to save some space. const NUM_IRQS: usize = Self::MAX_IRQ_NUMBER + 1; + pub const COMPATIBLE: &'static str = "GICv2 (ARM Generic Interrupt Controller v2)"; + /// Create an instance. /// /// # Safety /// - /// - The user must ensure to provide correct MMIO descriptors. + /// - The user must ensure to provide a correct MMIO start address. pub const unsafe fn new( - gicd_mmio_descriptor: memory::mmu::MMIODescriptor, - gicc_mmio_descriptor: memory::mmu::MMIODescriptor, + gicd_mmio_start_addr: Address, + gicc_mmio_start_addr: Address, + post_init_callback: fn(), ) -> Self { Self { - gicd_mmio_descriptor, - gicc_mmio_descriptor, - gicd: gicd::GICD::new(gicd_mmio_descriptor.start_addr().as_usize()), - gicc: gicc::GICC::new(gicc_mmio_descriptor.start_addr().as_usize()), - is_mmio_remapped: AtomicBool::new(false), + gicd: gicd::GICD::new(gicd_mmio_start_addr), + gicc: gicc::GICC::new(gicc_mmio_start_addr), handler_table: InitStateLock::new([None; Self::NUM_IRQS]), + post_init_callback, } } } @@ -148,24 +150,10 @@ use synchronization::interface::ReadWriteEx; impl driver::interface::DeviceDriver for GICv2 { fn compatible(&self) -> &'static str { - "GICv2 (ARM Generic Interrupt Controller v2)" + Self::COMPATIBLE } unsafe fn init(&self) -> Result<(), &'static str> { - let remapped = self.is_mmio_remapped.load(Ordering::Relaxed); - if !remapped { - // GICD - let mut virt_addr = memory::mmu::kernel_map_mmio("GICD", &self.gicd_mmio_descriptor)?; - self.gicd.set_mmio(virt_addr.as_usize()); - - // GICC - virt_addr = memory::mmu::kernel_map_mmio("GICC", &self.gicc_mmio_descriptor)?; - self.gicc.set_mmio(virt_addr.as_usize()); - - // Conclude remapping. - self.is_mmio_remapped.store(true, Ordering::Relaxed); - } - if bsp::cpu::BOOT_CORE_ID == cpu::smp::core_id() { self.gicd.boot_core_init(); } @@ -173,6 +161,8 @@ impl driver::interface::DeviceDriver for GICv2 { self.gicc.priority_accept_all(); self.gicc.enable(); + (self.post_init_callback)(); + Ok(()) } } diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/arm/gicv2/gicc.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/arm/gicv2/gicc.rs index 1a151d24..1a02fc65 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/arm/gicv2/gicc.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/arm/gicv2/gicc.rs @@ -5,7 +5,9 @@ //! GICC Driver - GIC CPU interface. use crate::{ - bsp::device_driver::common::MMIODerefWrapper, exception, synchronization::InitStateLock, + bsp::device_driver::common::MMIODerefWrapper, + exception, + memory::{Address, Virtual}, }; use tock_registers::{ interfaces::{Readable, Writeable}, @@ -62,13 +64,12 @@ type Registers = MMIODerefWrapper; /// Representation of the GIC CPU interface. pub struct GICC { - registers: InitStateLock, + registers: Registers, } //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- -use crate::synchronization::interface::ReadWriteEx; impl GICC { /// Create an instance. @@ -76,17 +77,12 @@ impl GICC { /// # Safety /// /// - The user must ensure to provide a correct MMIO start address. - pub const unsafe fn new(mmio_start_addr: usize) -> Self { + pub const unsafe fn new(mmio_start_addr: Address) -> Self { Self { - registers: InitStateLock::new(Registers::new(mmio_start_addr)), + registers: Registers::new(mmio_start_addr), } } - pub unsafe fn set_mmio(&self, new_mmio_start_addr: usize) { - self.registers - .write(|regs| *regs = Registers::new(new_mmio_start_addr)); - } - /// Accept interrupts of any priority. /// /// Quoting the GICv2 Architecture Specification: @@ -99,9 +95,7 @@ impl GICC { /// - GICC MMIO registers are banked per CPU core. It is therefore safe to have `&self` instead /// of `&mut self`. pub fn priority_accept_all(&self) { - self.registers.read(|regs| { - regs.PMR.write(PMR::Priority.val(255)); // Comment in arch spec. - }); + self.registers.PMR.write(PMR::Priority.val(255)); // Comment in arch spec. } /// Enable the interface - start accepting IRQs. @@ -111,9 +105,7 @@ impl GICC { /// - GICC MMIO registers are banked per CPU core. It is therefore safe to have `&self` instead /// of `&mut self`. pub fn enable(&self) { - self.registers.read(|regs| { - regs.CTLR.write(CTLR::Enable::SET); - }); + self.registers.CTLR.write(CTLR::Enable::SET); } /// Extract the number of the highest-priority pending IRQ. @@ -129,8 +121,7 @@ impl GICC { &self, _ic: &exception::asynchronous::IRQContext<'irq_context>, ) -> usize { - self.registers - .read(|regs| regs.IAR.read(IAR::InterruptID) as usize) + self.registers.IAR.read(IAR::InterruptID) as usize } /// Complete handling of the currently active IRQ. @@ -149,8 +140,6 @@ impl GICC { irq_number: u32, _ic: &exception::asynchronous::IRQContext<'irq_context>, ) { - self.registers.read(|regs| { - regs.EOIR.write(EOIR::EOIINTID.val(irq_number)); - }); + self.registers.EOIR.write(EOIR::EOIINTID.val(irq_number)); } } diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs index 60bbc468..d9f63d1b 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs @@ -9,8 +9,9 @@ use crate::{ bsp::device_driver::common::MMIODerefWrapper, + memory::{Address, Virtual}, state, synchronization, - synchronization::{IRQSafeNullLock, InitStateLock}, + synchronization::IRQSafeNullLock, }; use tock_registers::{ interfaces::{Readable, Writeable}, @@ -84,7 +85,7 @@ pub struct GICD { shared_registers: IRQSafeNullLock, /// Access to banked registers is unguarded. - banked_registers: InitStateLock, + banked_registers: BankedRegisters, } //-------------------------------------------------------------------------------------------------- @@ -121,7 +122,6 @@ impl SharedRegisters { //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- -use crate::synchronization::interface::ReadWriteEx; use synchronization::interface::Mutex; impl GICD { @@ -130,20 +130,13 @@ impl GICD { /// # Safety /// /// - The user must ensure to provide a correct MMIO start address. - pub const unsafe fn new(mmio_start_addr: usize) -> Self { + pub const unsafe fn new(mmio_start_addr: Address) -> Self { Self { shared_registers: IRQSafeNullLock::new(SharedRegisters::new(mmio_start_addr)), - banked_registers: InitStateLock::new(BankedRegisters::new(mmio_start_addr)), + banked_registers: BankedRegisters::new(mmio_start_addr), } } - pub unsafe fn set_mmio(&self, new_mmio_start_addr: usize) { - self.shared_registers - .lock(|regs| *regs = SharedRegisters::new(new_mmio_start_addr)); - self.banked_registers - .write(|regs| *regs = BankedRegisters::new(new_mmio_start_addr)); - } - /// Use a banked ITARGETSR to retrieve the executing core's GIC target mask. /// /// Quoting the GICv2 Architecture Specification: @@ -151,8 +144,7 @@ impl GICD { /// "GICD_ITARGETSR0 to GICD_ITARGETSR7 are read-only, and each field returns a value that /// corresponds only to the processor reading the register." fn local_gic_target_mask(&self) -> u32 { - self.banked_registers - .read(|regs| regs.ITARGETSR[0].read(ITARGETSR::Offset0)) + self.banked_registers.ITARGETSR[0].read(ITARGETSR::Offset0) } /// Route all SPIs to the boot core and enable the distributor. @@ -191,10 +183,10 @@ impl GICD { // Check if we are handling a private or shared IRQ. match irq_num { // Private. - 0..=31 => self.banked_registers.read(|regs| { - let enable_reg = ®s.ISENABLER; + 0..=31 => { + let enable_reg = &self.banked_registers.ISENABLER; enable_reg.set(enable_reg.get() | enable_bit); - }), + } // Shared. _ => { let enable_reg_index_shared = enable_reg_index - 1; diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs index eea07b75..a3361c2c 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs @@ -5,10 +5,12 @@ //! GPIO Driver. use crate::{ - bsp::device_driver::common::MMIODerefWrapper, driver, memory, synchronization, + bsp::device_driver::common::MMIODerefWrapper, + driver, + memory::{Address, Virtual}, + synchronization, synchronization::IRQSafeNullLock, }; -use core::sync::atomic::{AtomicUsize, Ordering}; use tock_registers::{ interfaces::{ReadWriteable, Writeable}, register_bitfields, register_structs, @@ -109,26 +111,22 @@ register_structs! { /// Abstraction for the associated MMIO registers. type Registers = MMIODerefWrapper; -//-------------------------------------------------------------------------------------------------- -// Public Definitions -//-------------------------------------------------------------------------------------------------- - -pub struct GPIOInner { +struct GPIOInner { registers: Registers, } -// Export the inner struct so that BSPs can use it for the panic handler. -pub use GPIOInner as PanicGPIO; +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- /// Representation of the GPIO HW. pub struct GPIO { - mmio_descriptor: memory::mmu::MMIODescriptor, - virt_mmio_start_addr: AtomicUsize, inner: IRQSafeNullLock, + post_init_callback: fn(), } //-------------------------------------------------------------------------------------------------- -// Public Code +// Private Code //-------------------------------------------------------------------------------------------------- impl GPIOInner { @@ -137,25 +135,12 @@ impl GPIOInner { /// # Safety /// /// - The user must ensure to provide a correct MMIO start address. - pub const unsafe fn new(mmio_start_addr: usize) -> Self { + pub const unsafe fn new(mmio_start_addr: Address) -> Self { Self { registers: Registers::new(mmio_start_addr), } } - /// Init code. - /// - /// # Safety - /// - /// - The user must ensure to provide a correct MMIO start address. - pub unsafe fn init(&mut self, new_mmio_start_addr: Option) -> Result<(), &'static str> { - if let Some(addr) = new_mmio_start_addr { - self.registers = Registers::new(addr); - } - - Ok(()) - } - /// Disable pull-up/down on pins 14 and 15. #[cfg(feature = "bsp_rpi3")] fn disable_pud_14_15_bcm2837(&mut self) { @@ -205,17 +190,22 @@ impl GPIOInner { } } +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + impl GPIO { + pub const COMPATIBLE: &'static str = "BCM GPIO"; + /// Create an instance. /// /// # Safety /// - /// - The user must ensure to provide correct MMIO descriptors. - pub const unsafe fn new(mmio_descriptor: memory::mmu::MMIODescriptor) -> Self { + /// - The user must ensure to provide a correct MMIO start address. + pub const unsafe fn new(mmio_start_addr: Address, post_init_callback: fn()) -> Self { Self { - mmio_descriptor, - virt_mmio_start_addr: AtomicUsize::new(0), - inner: IRQSafeNullLock::new(GPIOInner::new(mmio_descriptor.start_addr().as_usize())), + inner: IRQSafeNullLock::new(GPIOInner::new(mmio_start_addr)), + post_init_callback, } } @@ -232,28 +222,12 @@ use synchronization::interface::Mutex; impl driver::interface::DeviceDriver for GPIO { fn compatible(&self) -> &'static str { - "BCM GPIO" + Self::COMPATIBLE } unsafe fn init(&self) -> Result<(), &'static str> { - let virt_addr = memory::mmu::kernel_map_mmio(self.compatible(), &self.mmio_descriptor)?; - - self.inner - .lock(|inner| inner.init(Some(virt_addr.as_usize())))?; - - self.virt_mmio_start_addr - .store(virt_addr.as_usize(), Ordering::Relaxed); + (self.post_init_callback)(); Ok(()) } - - fn virt_mmio_start_addr(&self) -> Option { - let addr = self.virt_mmio_start_addr.load(Ordering::Relaxed); - - if addr == 0 { - return None; - } - - Some(addr) - } } diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs index 99961fac..4908b8b6 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs @@ -6,7 +6,10 @@ mod peripheral_ic; -use crate::{driver, exception, memory}; +use crate::{ + driver, exception, + memory::{Address, Virtual}, +}; //-------------------------------------------------------------------------------------------------- // Private Definitions @@ -28,6 +31,7 @@ pub type PeripheralIRQ = /// Used for the associated type of trait [`exception::asynchronous::interface::IRQManager`]. #[derive(Copy, Clone)] +#[allow(missing_docs)] pub enum IRQNumber { Local(LocalIRQ), Peripheral(PeripheralIRQ), @@ -36,6 +40,7 @@ pub enum IRQNumber { /// Representation of the Interrupt Controller. pub struct InterruptController { periph: peripheral_ic::PeripheralIC, + post_init_callback: fn(), } //-------------------------------------------------------------------------------------------------- @@ -74,17 +79,20 @@ impl InterruptController { const MAX_PERIPHERAL_IRQ_NUMBER: usize = 63; const NUM_PERIPHERAL_IRQS: usize = Self::MAX_PERIPHERAL_IRQ_NUMBER + 1; + pub const COMPATIBLE: &'static str = "BCM Interrupt Controller"; + /// Create an instance. /// /// # Safety /// - /// - The user must ensure to provide correct MMIO descriptors. + /// - The user must ensure to provide a correct MMIO start address. pub const unsafe fn new( - _local_mmio_descriptor: memory::mmu::MMIODescriptor, - periph_mmio_descriptor: memory::mmu::MMIODescriptor, + periph_mmio_start_addr: Address, + post_init_callback: fn(), ) -> Self { Self { - periph: peripheral_ic::PeripheralIC::new(periph_mmio_descriptor), + periph: peripheral_ic::PeripheralIC::new(periph_mmio_start_addr), + post_init_callback, } } } @@ -95,11 +103,13 @@ impl InterruptController { impl driver::interface::DeviceDriver for InterruptController { fn compatible(&self) -> &'static str { - "BCM Interrupt Controller" + Self::COMPATIBLE } unsafe fn init(&self) -> Result<(), &'static str> { - self.periph.init() + (self.post_init_callback)(); + + Ok(()) } } diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs index f09da862..145d8961 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs @@ -7,7 +7,9 @@ use super::{InterruptController, PendingIRQs, PeripheralIRQ}; use crate::{ bsp::device_driver::common::MMIODerefWrapper, - driver, exception, memory, synchronization, + exception, + memory::{Address, Virtual}, + synchronization, synchronization::{IRQSafeNullLock, InitStateLock}, }; use tock_registers::{ @@ -55,13 +57,11 @@ type HandlerTable = /// Representation of the peripheral interrupt controller. pub struct PeripheralIC { - mmio_descriptor: memory::mmu::MMIODescriptor, - /// Access to write registers is guarded with a lock. wo_registers: IRQSafeNullLock, /// Register read access is unguarded. - ro_registers: InitStateLock, + ro_registers: ReadOnlyRegisters, /// Stores registered IRQ handlers. Writable only during kernel init. RO afterwards. handler_table: InitStateLock, @@ -76,26 +76,21 @@ impl PeripheralIC { /// /// # Safety /// - /// - The user must ensure to provide correct MMIO descriptors. - pub const unsafe fn new(mmio_descriptor: memory::mmu::MMIODescriptor) -> Self { - let addr = mmio_descriptor.start_addr().as_usize(); - + /// - The user must ensure to provide a correct MMIO start address. + pub const unsafe fn new(mmio_start_addr: Address) -> Self { Self { - mmio_descriptor, - wo_registers: IRQSafeNullLock::new(WriteOnlyRegisters::new(addr)), - ro_registers: InitStateLock::new(ReadOnlyRegisters::new(addr)), + wo_registers: IRQSafeNullLock::new(WriteOnlyRegisters::new(mmio_start_addr)), + ro_registers: ReadOnlyRegisters::new(mmio_start_addr), handler_table: InitStateLock::new([None; InterruptController::NUM_PERIPHERAL_IRQS]), } } /// Query the list of pending IRQs. fn pending_irqs(&self) -> PendingIRQs { - self.ro_registers.read(|regs| { - let pending_mask: u64 = - (u64::from(regs.PENDING_2.get()) << 32) | u64::from(regs.PENDING_1.get()); + let pending_mask: u64 = (u64::from(self.ro_registers.PENDING_2.get()) << 32) + | u64::from(self.ro_registers.PENDING_1.get()); - PendingIRQs::new(pending_mask) - }) + PendingIRQs::new(pending_mask) } } @@ -104,24 +99,6 @@ impl PeripheralIC { //------------------------------------------------------------------------------ use synchronization::interface::{Mutex, ReadWriteEx}; -impl driver::interface::DeviceDriver for PeripheralIC { - fn compatible(&self) -> &'static str { - "BCM Peripheral Interrupt Controller" - } - - unsafe fn init(&self) -> Result<(), &'static str> { - let virt_addr = - memory::mmu::kernel_map_mmio(self.compatible(), &self.mmio_descriptor)?.as_usize(); - - self.wo_registers - .lock(|regs| *regs = WriteOnlyRegisters::new(virt_addr)); - self.ro_registers - .write(|regs| *regs = ReadOnlyRegisters::new(virt_addr)); - - Ok(()) - } -} - impl exception::asynchronous::interface::IRQManager for PeripheralIC { type IRQNumberType = PeripheralIRQ; diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs index 3133047b..f67d70df 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs @@ -10,13 +10,14 @@ //! - use crate::{ - bsp, bsp::device_driver::common::MMIODerefWrapper, console, cpu, driver, exception, memory, - synchronization, synchronization::IRQSafeNullLock, -}; -use core::{ - fmt, - sync::atomic::{AtomicUsize, Ordering}, + bsp, + bsp::device_driver::common::MMIODerefWrapper, + console, cpu, driver, exception, + memory::{Address, Virtual}, + synchronization, + synchronization::IRQSafeNullLock, }; +use core::fmt; use tock_registers::{ interfaces::{Readable, Writeable}, register_bitfields, register_structs, @@ -219,29 +220,25 @@ enum BlockingMode { NonBlocking, } -//-------------------------------------------------------------------------------------------------- -// Public Definitions -//-------------------------------------------------------------------------------------------------- - -pub struct PL011UartInner { +struct PL011UartInner { registers: Registers, chars_written: usize, chars_read: usize, } -// Export the inner struct so that BSPs can use it for the panic handler. -pub use PL011UartInner as PanicUart; +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- /// Representation of the UART. pub struct PL011Uart { - mmio_descriptor: memory::mmu::MMIODescriptor, - virt_mmio_start_addr: AtomicUsize, inner: IRQSafeNullLock, irq_number: bsp::device_driver::IRQNumber, + post_init_callback: fn(), } //-------------------------------------------------------------------------------------------------- -// Public Code +// Private Code //-------------------------------------------------------------------------------------------------- impl PL011UartInner { @@ -250,7 +247,7 @@ impl PL011UartInner { /// # Safety /// /// - The user must ensure to provide a correct MMIO start address. - pub const unsafe fn new(mmio_start_addr: usize) -> Self { + pub const unsafe fn new(mmio_start_addr: Address) -> Self { Self { registers: Registers::new(mmio_start_addr), chars_written: 0, @@ -275,15 +272,7 @@ impl PL011UartInner { /// genrated baud rate of `48_000_000 / (16 * 3.25) = 923_077`. /// /// Error = `((923_077 - 921_600) / 921_600) * 100 = 0.16%`. - /// - /// # Safety - /// - /// - The user must ensure to provide a correct MMIO start address. - pub unsafe fn init(&mut self, new_mmio_start_addr: Option) -> Result<(), &'static str> { - if let Some(addr) = new_mmio_start_addr { - self.registers = Registers::new(addr); - } - + pub fn init(&mut self) { // Execution can arrive here while there are still characters queued in the TX FIFO and // actively being sent out by the UART hardware. If the UART is turned off in this case, // those queued characters would be lost. @@ -325,8 +314,6 @@ impl PL011UartInner { self.registers .CR .write(CR::UARTEN::Enabled + CR::TXE::Enabled + CR::RXE::Enabled); - - Ok(()) } /// Send a character. @@ -399,24 +386,28 @@ impl fmt::Write for PL011UartInner { } } +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + impl PL011Uart { + pub const COMPATIBLE: &'static str = "BCM PL011 UART"; + /// Create an instance. /// /// # Safety /// - /// - The user must ensure to provide correct MMIO descriptors. + /// - The user must ensure to provide a correct MMIO start address. /// - The user must ensure to provide correct IRQ numbers. pub const unsafe fn new( - mmio_descriptor: memory::mmu::MMIODescriptor, + mmio_start_addr: Address, irq_number: bsp::device_driver::IRQNumber, + post_init_callback: fn(), ) -> Self { Self { - mmio_descriptor, - virt_mmio_start_addr: AtomicUsize::new(0), - inner: IRQSafeNullLock::new(PL011UartInner::new( - mmio_descriptor.start_addr().as_usize(), - )), + inner: IRQSafeNullLock::new(PL011UartInner::new(mmio_start_addr)), irq_number, + post_init_callback, } } } @@ -428,27 +419,21 @@ use synchronization::interface::Mutex; impl driver::interface::DeviceDriver for PL011Uart { fn compatible(&self) -> &'static str { - "BCM PL011 UART" + Self::COMPATIBLE } unsafe fn init(&self) -> Result<(), &'static str> { - let virt_addr = memory::mmu::kernel_map_mmio(self.compatible(), &self.mmio_descriptor)?; - - self.inner - .lock(|inner| inner.init(Some(virt_addr.as_usize())))?; - - self.virt_mmio_start_addr - .store(virt_addr.as_usize(), Ordering::Relaxed); + self.inner.lock(|inner| inner.init()); + (self.post_init_callback)(); Ok(()) } fn register_and_enable_irq_handler(&'static self) -> Result<(), &'static str> { - use bsp::exception::asynchronous::irq_manager; - use exception::asynchronous::{interface::IRQManager, IRQDescriptor}; + use exception::asynchronous::{irq_manager, IRQDescriptor}; let descriptor = IRQDescriptor { - name: "BCM PL011 UART", + name: Self::COMPATIBLE, handler: self, }; @@ -457,16 +442,6 @@ impl driver::interface::DeviceDriver for PL011Uart { Ok(()) } - - fn virt_mmio_start_addr(&self) -> Option { - let addr = self.virt_mmio_start_addr.load(Ordering::Relaxed); - - if addr == 0 { - return None; - } - - Some(addr) - } } impl console::interface::Write for PL011Uart { @@ -514,6 +489,8 @@ impl console::interface::Statistics for PL011Uart { } } +impl console::interface::All for PL011Uart {} + impl exception::asynchronous::interface::IRQHandler for PL011Uart { fn handle(&self) -> Result<(), &'static str> { self.inner.lock(|inner| { diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/common.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/common.rs index fd9e988e..69f038d4 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/common.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/common.rs @@ -4,6 +4,7 @@ //! Common device driver code. +use crate::memory::{Address, Virtual}; use core::{marker::PhantomData, ops}; //-------------------------------------------------------------------------------------------------- @@ -11,7 +12,7 @@ use core::{marker::PhantomData, ops}; //-------------------------------------------------------------------------------------------------- pub struct MMIODerefWrapper { - start_addr: usize, + start_addr: Address, phantom: PhantomData T>, } @@ -21,7 +22,7 @@ pub struct MMIODerefWrapper { impl MMIODerefWrapper { /// Create an instance. - pub const unsafe fn new(start_addr: usize) -> Self { + pub const unsafe fn new(start_addr: Address) -> Self { Self { start_addr, phantom: PhantomData, @@ -33,6 +34,6 @@ impl ops::Deref for MMIODerefWrapper { type Target = T; fn deref(&self) -> &Self::Target { - unsafe { &*(self.start_addr as *const _) } + unsafe { &*(self.start_addr.as_usize() as *const _) } } } diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi.rs index fb9edf88..474419f4 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi.rs @@ -4,46 +4,11 @@ //! Top-level BSP file for the Raspberry Pi 3 and 4. -pub mod console; pub mod cpu; pub mod driver; pub mod exception; pub mod memory; -use super::device_driver; -use crate::memory::mmu::MMIODescriptor; -use memory::map::mmio; - -//-------------------------------------------------------------------------------------------------- -// Global instances -//-------------------------------------------------------------------------------------------------- - -static GPIO: device_driver::GPIO = - unsafe { device_driver::GPIO::new(MMIODescriptor::new(mmio::GPIO_START, mmio::GPIO_SIZE)) }; - -static PL011_UART: device_driver::PL011Uart = unsafe { - device_driver::PL011Uart::new( - MMIODescriptor::new(mmio::PL011_UART_START, mmio::PL011_UART_SIZE), - exception::asynchronous::irq_map::PL011_UART, - ) -}; - -#[cfg(feature = "bsp_rpi3")] -static INTERRUPT_CONTROLLER: device_driver::InterruptController = unsafe { - device_driver::InterruptController::new( - MMIODescriptor::new(mmio::LOCAL_IC_START, mmio::LOCAL_IC_SIZE), - MMIODescriptor::new(mmio::PERIPHERAL_IC_START, mmio::PERIPHERAL_IC_SIZE), - ) -}; - -#[cfg(feature = "bsp_rpi4")] -static INTERRUPT_CONTROLLER: device_driver::GICv2 = unsafe { - device_driver::GICv2::new( - MMIODescriptor::new(mmio::GICD_START, mmio::GICD_SIZE), - MMIODescriptor::new(mmio::GICC_START, mmio::GICC_SIZE), - ) -}; - //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi/console.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi/console.rs deleted file mode 100644 index a0d2e687..00000000 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi/console.rs +++ /dev/null @@ -1,98 +0,0 @@ -// SPDX-License-Identifier: MIT OR Apache-2.0 -// -// Copyright (c) 2018-2022 Andre Richter - -//! BSP console facilities. - -use crate::{bsp::device_driver, console, cpu, driver}; -use core::fmt; - -//-------------------------------------------------------------------------------------------------- -// Public Code -//-------------------------------------------------------------------------------------------------- - -/// In case of a panic, the panic handler uses this function to take a last shot at printing -/// something before the system is halted. -/// -/// We try to init panic-versions of the GPIO and the UART. The panic versions are not protected -/// with synchronization primitives, which increases chances that we get to print something, even -/// when the kernel's default GPIO or UART instances happen to be locked at the time of the panic. -/// -/// # Safety -/// -/// - Use only for printing during a panic. -#[cfg(not(feature = "test_build"))] -pub unsafe fn panic_console_out() -> impl fmt::Write { - use driver::interface::DeviceDriver; - - // If remapping of the driver's MMIO hasn't already happened, we won't be able to print. Just - // park the CPU core in this case. - let gpio_mmio_start_addr = match super::GPIO.virt_mmio_start_addr() { - None => cpu::wait_forever(), - Some(x) => x, - }; - - let uart_mmio_start_addr = match super::PL011_UART.virt_mmio_start_addr() { - None => cpu::wait_forever(), - Some(x) => x, - }; - - let mut panic_gpio = device_driver::PanicGPIO::new(gpio_mmio_start_addr); - let mut panic_uart = device_driver::PanicUart::new(uart_mmio_start_addr); - - panic_gpio - .init(None) - .unwrap_or_else(|_| cpu::wait_forever()); - panic_gpio.map_pl011_uart(); - panic_uart - .init(None) - .unwrap_or_else(|_| cpu::wait_forever()); - - panic_uart -} - -/// Reduced version for test builds. -/// -/// # Safety -/// -/// - Use only for printing during a panic. -#[cfg(feature = "test_build")] -pub unsafe fn panic_console_out() -> impl fmt::Write { - use driver::interface::DeviceDriver; - - let uart_mmio_start_addr = match super::PL011_UART.virt_mmio_start_addr() { - None => cpu::wait_forever(), - Some(x) => x, - }; - let mut panic_uart = device_driver::PanicUart::new(uart_mmio_start_addr); - - panic_uart - .init(None) - .unwrap_or_else(|_| cpu::qemu_exit_failure()); - - panic_uart -} - -/// Return a reference to the console. -pub fn console() -> &'static impl console::interface::All { - &super::PL011_UART -} - -//-------------------------------------------------------------------------------------------------- -// Testing -//-------------------------------------------------------------------------------------------------- - -/// Minimal code needed to bring up the console in QEMU (for testing only). This is often less steps -/// than on real hardware due to QEMU's abstractions. -#[cfg(feature = "test_build")] -pub fn qemu_bring_up_console() { - use driver::interface::DeviceDriver; - - // Calling the UART's init ensures that the BSP's instance of the UART does remap the MMIO - // addresses. - unsafe { - super::PL011_UART - .init() - .unwrap_or_else(|_| cpu::qemu_exit_failure()); - } -} diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi/driver.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi/driver.rs index 53168752..e1db4a00 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi/driver.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi/driver.rs @@ -4,7 +4,19 @@ //! BSP driver support. -use crate::driver; +use super::{exception, memory::map::mmio}; +use crate::{ + bsp::device_driver, + console, driver, exception as generic_exception, memory, + memory::mmu::MMIODescriptor, + synchronization::{interface::ReadWriteEx, InitStateLock}, +}; +use core::{ + mem::MaybeUninit, + sync::atomic::{AtomicBool, Ordering}, +}; + +pub use device_driver::IRQNumber; //-------------------------------------------------------------------------------------------------- // Private Definitions @@ -12,21 +24,132 @@ use crate::driver; /// Device Driver Manager type. struct BSPDriverManager { - device_drivers: [&'static (dyn DeviceDriver + Sync); 3], + device_drivers: InitStateLock<[Option<&'static (dyn DeviceDriver + Sync)>; NUM_DRIVERS]>, + init_done: AtomicBool, } +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +/// The number of active drivers provided by this BSP. +pub const NUM_DRIVERS: usize = 3; + //-------------------------------------------------------------------------------------------------- // Global instances //-------------------------------------------------------------------------------------------------- +static mut PL011_UART: MaybeUninit = MaybeUninit::uninit(); +static mut GPIO: MaybeUninit = MaybeUninit::uninit(); + +#[cfg(feature = "bsp_rpi3")] +static mut INTERRUPT_CONTROLLER: MaybeUninit = + MaybeUninit::uninit(); + +#[cfg(feature = "bsp_rpi4")] +static mut INTERRUPT_CONTROLLER: MaybeUninit = MaybeUninit::uninit(); + static BSP_DRIVER_MANAGER: BSPDriverManager = BSPDriverManager { - device_drivers: [ - &super::GPIO, - &super::PL011_UART, - &super::INTERRUPT_CONTROLLER, - ], + device_drivers: InitStateLock::new([None; NUM_DRIVERS]), + init_done: AtomicBool::new(false), }; +//-------------------------------------------------------------------------------------------------- +// Private Code +//-------------------------------------------------------------------------------------------------- + +impl BSPDriverManager { + unsafe fn instantiate_uart(&self) -> Result<(), &'static str> { + let mmio_descriptor = MMIODescriptor::new(mmio::PL011_UART_START, mmio::PL011_UART_SIZE); + let virt_addr = + memory::mmu::kernel_map_mmio(device_driver::PL011Uart::COMPATIBLE, &mmio_descriptor)?; + + // This is safe to do, because it is only called from the init'ed instance itself. + fn uart_post_init() { + console::register_console(unsafe { PL011_UART.assume_init_ref() }); + } + + PL011_UART.write(device_driver::PL011Uart::new( + virt_addr, + exception::asynchronous::irq_map::PL011_UART, + uart_post_init, + )); + + Ok(()) + } + + unsafe fn instantiate_gpio(&self) -> Result<(), &'static str> { + let mmio_descriptor = MMIODescriptor::new(mmio::GPIO_START, mmio::GPIO_SIZE); + let virt_addr = + memory::mmu::kernel_map_mmio(device_driver::GPIO::COMPATIBLE, &mmio_descriptor)?; + + // This is safe to do, because it is only called from the init'ed instance itself. + fn gpio_post_init() { + unsafe { GPIO.assume_init_ref().map_pl011_uart() }; + } + + GPIO.write(device_driver::GPIO::new(virt_addr, gpio_post_init)); + + Ok(()) + } + + #[cfg(feature = "bsp_rpi3")] + unsafe fn instantiate_interrupt_controller(&self) -> Result<(), &'static str> { + let periph_mmio_descriptor = + MMIODescriptor::new(mmio::PERIPHERAL_IC_START, mmio::PERIPHERAL_IC_SIZE); + let periph_virt_addr = memory::mmu::kernel_map_mmio( + device_driver::InterruptController::COMPATIBLE, + &periph_mmio_descriptor, + )?; + + // This is safe to do, because it is only called from the init'ed instance itself. + fn interrupt_controller_post_init() { + generic_exception::asynchronous::register_irq_manager(unsafe { + INTERRUPT_CONTROLLER.assume_init_ref() + }); + } + + INTERRUPT_CONTROLLER.write(device_driver::InterruptController::new( + periph_virt_addr, + interrupt_controller_post_init, + )); + + Ok(()) + } + + #[cfg(feature = "bsp_rpi4")] + unsafe fn instantiate_interrupt_controller(&self) -> Result<(), &'static str> { + let gicd_mmio_descriptor = MMIODescriptor::new(mmio::GICD_START, mmio::GICD_SIZE); + let gicd_virt_addr = memory::mmu::kernel_map_mmio("GICv2 GICD", &gicd_mmio_descriptor)?; + + let gicc_mmio_descriptor = MMIODescriptor::new(mmio::GICC_START, mmio::GICC_SIZE); + let gicc_virt_addr = memory::mmu::kernel_map_mmio("GICV2 GICC", &gicc_mmio_descriptor)?; + + // This is safe to do, because it is only called from the init'ed instance itself. + fn interrupt_controller_post_init() { + generic_exception::asynchronous::register_irq_manager(unsafe { + INTERRUPT_CONTROLLER.assume_init_ref() + }); + } + + INTERRUPT_CONTROLLER.write(device_driver::GICv2::new( + gicd_virt_addr, + gicc_virt_addr, + interrupt_controller_post_init, + )); + + Ok(()) + } + + unsafe fn register_drivers(&self) { + self.device_drivers.write(|drivers| { + drivers[0] = Some(PL011_UART.assume_init_ref()); + drivers[1] = Some(GPIO.assume_init_ref()); + drivers[2] = Some(INTERRUPT_CONTROLLER.assume_init_ref()); + }); + } +} + //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- @@ -42,20 +165,34 @@ pub fn driver_manager() -> &'static impl driver::interface::DriverManager { use driver::interface::DeviceDriver; impl driver::interface::DriverManager for BSPDriverManager { - fn all_device_drivers(&self) -> &[&'static (dyn DeviceDriver + Sync)] { - &self.device_drivers[..] - } + unsafe fn instantiate_drivers(&self) -> Result<(), &'static str> { + if self.init_done.load(Ordering::Relaxed) { + return Err("Drivers already instantiated"); + } + + self.instantiate_uart()?; + self.instantiate_gpio()?; + self.instantiate_interrupt_controller()?; - fn early_print_device_drivers(&self) -> &[&'static (dyn DeviceDriver + Sync)] { - &self.device_drivers[0..=1] + self.register_drivers(); + + self.init_done.store(true, Ordering::Relaxed); + Ok(()) } - fn non_early_print_device_drivers(&self) -> &[&'static (dyn DeviceDriver + Sync)] { - &self.device_drivers[2..] + fn all_device_drivers(&self) -> [&(dyn DeviceDriver + Sync); NUM_DRIVERS] { + self.device_drivers + .read(|drivers| drivers.map(|drivers| drivers.unwrap())) } - fn post_early_print_device_driver_init(&self) { - // Configure PL011Uart's output pins. - super::GPIO.map_pl011_uart(); + #[cfg(feature = "test_build")] + fn qemu_bring_up_console(&self) { + use crate::cpu; + + unsafe { + self.instantiate_uart() + .unwrap_or_else(|_| cpu::qemu_exit_failure()); + console::register_console(PL011_UART.assume_init_ref()); + }; } } diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi/exception/asynchronous.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi/exception/asynchronous.rs index dc5ab421..ab20d86d 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi/exception/asynchronous.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi/exception/asynchronous.rs @@ -4,7 +4,7 @@ //! BSP asynchronous exception handling. -use crate::{bsp, exception}; +use crate::bsp; //-------------------------------------------------------------------------------------------------- // Public Definitions @@ -23,14 +23,3 @@ pub(in crate::bsp) mod irq_map { pub const PL011_UART: IRQNumber = IRQNumber::new(153); } - -//-------------------------------------------------------------------------------------------------- -// Public Code -//-------------------------------------------------------------------------------------------------- - -/// Return a reference to the IRQ manager. -pub fn irq_manager() -> &'static impl exception::asynchronous::interface::IRQManager< - IRQNumberType = bsp::device_driver::IRQNumber, -> { - &super::super::INTERRUPT_CONTROLLER -} diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi/memory.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi/memory.rs index 9e071726..f34009de 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi/memory.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi/memory.rs @@ -111,9 +111,6 @@ pub(super) mod map { pub const PL011_UART_START: Address = Address::new(0x3F20_1000); pub const PL011_UART_SIZE: usize = 0x48; - pub const LOCAL_IC_START: Address = Address::new(0x4000_0000); - pub const LOCAL_IC_SIZE: usize = 0x100; - pub const END: Address = Address::new(0x4001_0000); } diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/console.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/console.rs index e49e241f..a85bcffe 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/console.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/console.rs @@ -4,6 +4,10 @@ //! System console. +mod null_console; + +use crate::synchronization; + //-------------------------------------------------------------------------------------------------- // Public Definitions //-------------------------------------------------------------------------------------------------- @@ -49,5 +53,29 @@ pub mod interface { } /// Trait alias for a full-fledged console. - pub trait All = Write + Read + Statistics; + pub trait All: Write + Read + Statistics {} +} + +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +static CUR_CONSOLE: InitStateLock<&'static (dyn interface::All + Sync)> = + InitStateLock::new(&null_console::NULL_CONSOLE); + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- +use synchronization::{interface::ReadWriteEx, InitStateLock}; + +/// Register a new console. +pub fn register_console(new_console: &'static (dyn interface::All + Sync)) { + CUR_CONSOLE.write(|con| *con = new_console); +} + +/// Return a reference to the currently registered console. +/// +/// This is the global console used by all printing macros. +pub fn console() -> &'static dyn interface::All { + CUR_CONSOLE.read(|con| *con) } diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/console/null_console.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/console/null_console.rs new file mode 100644 index 00000000..10c3bedc --- /dev/null +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/console/null_console.rs @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2022 Andre Richter + +//! Null console. + +use super::interface; +use core::fmt; + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +pub struct NullConsole; + +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +pub static NULL_CONSOLE: NullConsole = NullConsole {}; + +//-------------------------------------------------------------------------------------------------- +// Private Code +//-------------------------------------------------------------------------------------------------- + +impl interface::Write for NullConsole { + fn write_char(&self, _c: char) {} + + fn write_fmt(&self, _args: fmt::Arguments) -> fmt::Result { + fmt::Result::Ok(()) + } + + fn flush(&self) {} +} + +impl interface::Read for NullConsole { + fn clear_rx(&self) {} +} + +impl interface::Statistics for NullConsole {} +impl interface::All for NullConsole {} diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/driver.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/driver.rs index 7b800dbc..98197fef 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/driver.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/driver.rs @@ -10,6 +10,8 @@ /// Driver interfaces. pub mod interface { + use crate::bsp; + /// Device Driver functions. pub trait DeviceDriver { /// Return a compatibility string for identifying the driver. @@ -31,32 +33,25 @@ pub mod interface { fn register_and_enable_irq_handler(&'static self) -> Result<(), &'static str> { Ok(()) } - - /// After MMIO remapping, returns the new virtual start address. - /// - /// This API assumes a driver has only a single, contiguous MMIO aperture, which will not be - /// the case for more complex devices. This API will likely change in future tutorials. - fn virt_mmio_start_addr(&self) -> Option { - None - } } /// Device driver management functions. /// /// The `BSP` is supposed to supply one global instance. pub trait DriverManager { - /// Return a slice of references to all `BSP`-instantiated drivers. - fn all_device_drivers(&self) -> &[&'static (dyn DeviceDriver + Sync)]; - - /// Return only those drivers needed for the BSP's early printing functionality. + /// Instantiate all drivers. + /// + /// # Safety /// - /// For example, the default UART. - fn early_print_device_drivers(&self) -> &[&'static (dyn DeviceDriver + Sync)]; + /// Must be called before `all_device_drivers`. + unsafe fn instantiate_drivers(&self) -> Result<(), &'static str>; - /// Return all drivers minus early-print drivers. - fn non_early_print_device_drivers(&self) -> &[&'static (dyn DeviceDriver + Sync)]; + /// Return a slice of references to all `BSP`-instantiated drivers. + fn all_device_drivers(&self) -> [&(dyn DeviceDriver + Sync); bsp::driver::NUM_DRIVERS]; - /// Initialization code that runs after the early print driver init. - fn post_early_print_device_driver_init(&self); + /// Minimal code needed to bring up the console in QEMU (for testing only). This is often + /// less steps than on real hardware due to QEMU's abstractions. + #[cfg(feature = "test_build")] + fn qemu_bring_up_console(&self); } } diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/exception/asynchronous.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/exception/asynchronous.rs index fb1785c2..d9d2767c 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/exception/asynchronous.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/exception/asynchronous.rs @@ -7,7 +7,9 @@ #[cfg(target_arch = "aarch64")] #[path = "../_arch/aarch64/exception/asynchronous.rs"] mod arch_asynchronous; +mod null_irq_manager; +use crate::{bsp, synchronization}; use core::{fmt, marker::PhantomData}; //-------------------------------------------------------------------------------------------------- @@ -85,7 +87,7 @@ pub mod interface { ); /// Print list of registered handlers. - fn print_handler(&self); + fn print_handler(&self) {} } } @@ -93,9 +95,18 @@ pub mod interface { #[derive(Copy, Clone)] pub struct IRQNumber(usize); +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +static CUR_IRQ_MANAGER: InitStateLock< + &'static (dyn interface::IRQManager + Sync), +> = InitStateLock::new(&null_irq_manager::NULL_IRQ_MANAGER); + //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- +use synchronization::{interface::ReadWriteEx, InitStateLock}; impl<'irq_context> IRQContext<'irq_context> { /// Creates an IRQContext token. @@ -150,3 +161,18 @@ pub fn exec_with_irq_masked(f: impl FnOnce() -> T) -> T { ret } + +/// Register a new IRQ manager. +pub fn register_irq_manager( + new_manager: &'static (dyn interface::IRQManager + + Sync), +) { + CUR_IRQ_MANAGER.write(|manager| *manager = new_manager); +} + +/// Return a reference to the currently registered IRQ manager. +/// +/// This is the IRQ manager used by the architectural interrupt handling code. +pub fn irq_manager() -> &'static dyn interface::IRQManager { + CUR_IRQ_MANAGER.read(|manager| *manager) +} diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/exception/asynchronous/null_irq_manager.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/exception/asynchronous/null_irq_manager.rs new file mode 100644 index 00000000..560e3ce4 --- /dev/null +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/exception/asynchronous/null_irq_manager.rs @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2022 Andre Richter + +//! Null IRQ Manager. + +use super::{interface, IRQContext, IRQDescriptor}; +use crate::bsp; + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +pub struct NullIRQManager; + +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +pub static NULL_IRQ_MANAGER: NullIRQManager = NullIRQManager {}; + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +impl interface::IRQManager for NullIRQManager { + type IRQNumberType = bsp::driver::IRQNumber; + + fn register_handler( + &self, + _irq_number: Self::IRQNumberType, + _descriptor: IRQDescriptor, + ) -> Result<(), &'static str> { + panic!("No IRQ Manager registered yet"); + } + + fn enable(&self, _irq_number: Self::IRQNumberType) { + panic!("No IRQ Manager registered yet"); + } + + fn handle_pending_irqs<'irq_context>(&'irq_context self, _ic: &IRQContext<'irq_context>) { + panic!("No IRQ Manager registered yet"); + } +} diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/lib.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/lib.rs index c9c03792..f023d683 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/lib.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/lib.rs @@ -114,6 +114,7 @@ #![feature(core_intrinsics)] #![feature(format_args_nl)] #![feature(generic_const_exprs)] +#![feature(is_sorted)] #![feature(linkage)] #![feature(panic_info_message)] #![feature(step_trait)] @@ -176,9 +177,11 @@ pub fn test_runner(tests: &[&test_types::UnitTest]) { #[cfg(test)] #[no_mangle] unsafe fn kernel_init() -> ! { + use driver::interface::DriverManager; + exception::handling_init(); memory::mmu::post_enable_init(); - bsp::console::qemu_bring_up_console(); + bsp::driver::driver_manager().qemu_bring_up_console(); test_main(); diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/main.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/main.rs index 5150f3af..928f12c2 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/main.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/main.rs @@ -30,26 +30,11 @@ unsafe fn kernel_init() -> ! { exception::handling_init(); memory::mmu::post_enable_init(); - // Add the mapping records for the precomputed entries first, so that they appear on the top of - // the list. - bsp::memory::mmu::kernel_add_mapping_records_for_precomputed(); - - // Bring up the drivers needed for printing first. - for i in bsp::driver::driver_manager() - .early_print_device_drivers() - .iter() - { - // Any encountered errors cannot be printed yet, obviously, so just safely park the CPU. - i.init().unwrap_or_else(|_| cpu::wait_forever()); + // Instantiate and init all device drivers. + if let Err(x) = bsp::driver::driver_manager().instantiate_drivers() { + panic!("Error instantiating drivers: {}", x); } - bsp::driver::driver_manager().post_early_print_device_driver_init(); - // Printing available from here on. - - // Now bring up the remaining drivers. - for i in bsp::driver::driver_manager() - .non_early_print_device_drivers() - .iter() - { + for i in bsp::driver::driver_manager().all_device_drivers().iter() { if let Err(x) = i.init() { panic!("Error loading driver: {}: {}", i.compatible(), x); } @@ -62,6 +47,8 @@ unsafe fn kernel_init() -> ! { } } + bsp::memory::mmu::kernel_add_mapping_records_for_precomputed(); + // Unmask interrupts on the boot CPU core. exception::asynchronous::local_irq_unmask(); @@ -75,7 +62,6 @@ unsafe fn kernel_init() -> ! { /// The main function running after the early init. fn kernel_main() -> ! { use driver::interface::DriverManager; - use exception::asynchronous::interface::IRQManager; info!("{}", libkernel::version()); info!("Booting on: {}", bsp::board_name()); @@ -104,7 +90,7 @@ fn kernel_main() -> ! { } info!("Registered IRQ handlers:"); - bsp::exception::asynchronous::irq_manager().print_handler(); + exception::asynchronous::irq_manager().print_handler(); info!("Echoing input now"); cpu::wait_forever(); diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/memory.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/memory.rs index f20719bb..64d8cf64 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/memory.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/memory.rs @@ -18,18 +18,18 @@ use core::{ //-------------------------------------------------------------------------------------------------- /// Metadata trait for marking the type of an address. -pub trait AddressType: Copy + Clone + PartialOrd + PartialEq {} +pub trait AddressType: Copy + Clone + PartialOrd + PartialEq + Ord + Eq {} /// Zero-sized type to mark a physical address. -#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)] +#[derive(Copy, Clone, Debug, PartialOrd, PartialEq, Ord, Eq)] pub enum Physical {} /// Zero-sized type to mark a virtual address. -#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)] +#[derive(Copy, Clone, Debug, PartialOrd, PartialEq, Ord, Eq)] pub enum Virtual {} /// Generic address type. -#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)] +#[derive(Copy, Clone, Debug, PartialOrd, PartialEq, Ord, Eq)] pub struct Address { value: usize, _address_type: PhantomData ATYPE>, diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/memory/mmu/mapping_record.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/memory/mmu/mapping_record.rs index d171c6e6..7d3a6c60 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/memory/mmu/mapping_record.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/memory/mmu/mapping_record.rs @@ -76,6 +76,19 @@ impl MappingRecord { Self { inner: [None; 12] } } + fn size(&self) -> usize { + self.inner.iter().filter(|x| x.is_some()).count() + } + + fn sort(&mut self) { + let upper_bound_exclusive = self.size(); + let entries = &mut self.inner[0..upper_bound_exclusive]; + + if !entries.is_sorted_by_key(|item| item.unwrap().virt_start_addr) { + entries.sort_unstable_by_key(|item| item.unwrap().virt_start_addr) + } + } + fn find_next_free(&mut self) -> Result<&mut Option, &'static str> { if let Some(x) = self.inner.iter_mut().find(|x| x.is_none()) { return Ok(x); @@ -121,6 +134,9 @@ impl MappingRecord { phys_region, attr, )); + + self.sort(); + Ok(()) } diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/panic_wait.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/panic_wait.rs index 08d7d453..e4256b61 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/panic_wait.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/panic_wait.rs @@ -4,19 +4,13 @@ //! A panic handler that infinitely waits. -use crate::{bsp, cpu, exception}; -use core::{fmt, panic::PanicInfo}; +use crate::{cpu, exception, println}; +use core::panic::PanicInfo; //-------------------------------------------------------------------------------------------------- // Private Code //-------------------------------------------------------------------------------------------------- -fn _panic_print(args: fmt::Arguments) { - use fmt::Write; - - unsafe { bsp::console::panic_console_out().write_fmt(args).unwrap() }; -} - /// The point of exit for `libkernel`. /// /// It is linked weakly, so that the integration tests can overload its standard behavior. @@ -34,16 +28,6 @@ fn _panic_exit() -> ! { } } -/// Prints with a newline - only use from the panic handler. -/// -/// Carbon copy from -#[macro_export] -macro_rules! panic_println { - ($($arg:tt)*) => ({ - _panic_print(format_args_nl!($($arg)*)); - }) -} - /// Stop immediately if called a second time. /// /// # Note @@ -88,7 +72,7 @@ fn panic(info: &PanicInfo) -> ! { _ => ("???", 0, 0), }; - panic_println!( + println!( "[ {:>3}.{:06}] Kernel panic!\n\n\ Panic location:\n File '{}', line {}, column {}\n\n\ {}", diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/print.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/print.rs index 9ec13a28..8705eec0 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/print.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/print.rs @@ -4,7 +4,7 @@ //! Printing. -use crate::{bsp, console}; +use crate::console; use core::fmt; //-------------------------------------------------------------------------------------------------- @@ -13,9 +13,7 @@ use core::fmt; #[doc(hidden)] pub fn _print(args: fmt::Arguments) { - use console::interface::Write; - - bsp::console::console().write_fmt(args).unwrap(); + console::console().write_fmt(args).unwrap(); } /// Prints without a newline. diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/tests/00_console_sanity.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/tests/00_console_sanity.rs index 6595aac1..f2a1f3ed 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/tests/00_console_sanity.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/tests/00_console_sanity.rs @@ -11,16 +11,16 @@ /// Console tests should time out on the I/O harness in case of panic. mod panic_wait_forever; -use libkernel::{bsp, console, cpu, exception, memory, print}; +use libkernel::{bsp, console, cpu, driver, exception, memory, print}; #[no_mangle] unsafe fn kernel_init() -> ! { - use bsp::console::console; - use console::interface::*; + use console::console; + use driver::interface::DriverManager; exception::handling_init(); memory::mmu::post_enable_init(); - bsp::console::qemu_bring_up_console(); + bsp::driver::driver_manager().qemu_bring_up_console(); // Handshake assert_eq!(console().read_char(), 'A'); diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/tests/01_timer_sanity.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/tests/01_timer_sanity.rs index 9b2b228d..caeca3cd 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/tests/01_timer_sanity.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/tests/01_timer_sanity.rs @@ -11,14 +11,16 @@ #![test_runner(libkernel::test_runner)] use core::time::Duration; -use libkernel::{bsp, cpu, exception, memory, time, time::interface::TimeManager}; +use libkernel::{bsp, cpu, driver, exception, memory, time, time::interface::TimeManager}; use test_macros::kernel_test; #[no_mangle] unsafe fn kernel_init() -> ! { + use driver::interface::DriverManager; + exception::handling_init(); memory::mmu::post_enable_init(); - bsp::console::qemu_bring_up_console(); + bsp::driver::driver_manager().qemu_bring_up_console(); // Depending on CPU arch, some timer bring-up code could go here. Not needed for the RPi. diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/tests/02_exception_sync_page_fault.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/tests/02_exception_sync_page_fault.rs index 0d2a1e63..33463e0a 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/tests/02_exception_sync_page_fault.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/tests/02_exception_sync_page_fault.rs @@ -17,13 +17,15 @@ /// or indirectly. mod panic_exit_success; -use libkernel::{bsp, cpu, exception, info, memory, println}; +use libkernel::{bsp, cpu, driver, exception, info, memory, println}; #[no_mangle] unsafe fn kernel_init() -> ! { + use driver::interface::DriverManager; + exception::handling_init(); memory::mmu::post_enable_init(); - bsp::console::qemu_bring_up_console(); + bsp::driver::driver_manager().qemu_bring_up_console(); // This line will be printed as the test header. println!("Testing synchronous exception handling by causing a page fault"); diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/tests/03_exception_restore_sanity.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/tests/03_exception_restore_sanity.rs index 983d488f..a521a871 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/tests/03_exception_restore_sanity.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/tests/03_exception_restore_sanity.rs @@ -12,7 +12,7 @@ mod panic_wait_forever; use core::arch::asm; -use libkernel::{bsp, cpu, exception, info, memory, println}; +use libkernel::{bsp, cpu, driver, exception, info, memory, println}; #[inline(never)] fn nested_system_call() { @@ -30,9 +30,11 @@ fn nested_system_call() { #[no_mangle] unsafe fn kernel_init() -> ! { + use driver::interface::DriverManager; + exception::handling_init(); memory::mmu::post_enable_init(); - bsp::console::qemu_bring_up_console(); + bsp::driver::driver_manager().qemu_bring_up_console(); // This line will be printed as the test header. println!("Testing exception restore"); diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/tests/04_exception_irq_sanity.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/tests/04_exception_irq_sanity.rs index 9030424d..cd2d29d6 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/tests/04_exception_irq_sanity.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/tests/04_exception_irq_sanity.rs @@ -10,13 +10,15 @@ #![reexport_test_harness_main = "test_main"] #![test_runner(libkernel::test_runner)] -use libkernel::{bsp, cpu, exception, memory}; +use libkernel::{bsp, cpu, driver, exception, memory}; use test_macros::kernel_test; #[no_mangle] unsafe fn kernel_init() -> ! { + use driver::interface::DriverManager; + memory::mmu::post_enable_init(); - bsp::console::qemu_bring_up_console(); + bsp::driver::driver_manager().qemu_bring_up_console(); exception::handling_init(); exception::asynchronous::local_irq_unmask(); diff --git a/17_kernel_symbols/Makefile b/17_kernel_symbols/Makefile index 41cecae3..ec71b493 100644 --- a/17_kernel_symbols/Makefile +++ b/17_kernel_symbols/Makefile @@ -215,7 +215,7 @@ $(KERNEL_BIN): $(KERNEL_ELF_TTABLES_SYMS) ##------------------------------------------------------------------------------ ## Generate the documentation ##------------------------------------------------------------------------------ -doc: +doc: clean $(call color_header, "Generating docs") @$(DOC_CMD) --document-private-items --open diff --git a/17_kernel_symbols/README.md b/17_kernel_symbols/README.md index 897e38cd..84378fff 100644 --- a/17_kernel_symbols/README.md +++ b/17_kernel_symbols/README.md @@ -269,12 +269,12 @@ diff -uNr 16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/excep //! //! crate::exception::arch_exception --use crate::{bsp, exception}; -+use crate::{bsp, exception, memory, symbols}; +-use crate::exception; ++use crate::{exception, memory, symbols}; use core::{arch::global_asm, cell::UnsafeCell, fmt}; use cortex_a::{asm::barrier, registers::*}; use tock_registers::{ -@@ -262,6 +262,14 @@ +@@ -260,6 +260,14 @@ writeln!(f, "{}", self.spsr_el1)?; writeln!(f, "ELR_EL1: {:#018x}", self.elr_el1)?; @@ -332,7 +332,7 @@ diff -uNr 16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi/mem diff -uNr 16_virtual_mem_part4_higher_half_kernel/kernel/src/lib.rs 17_kernel_symbols/kernel/src/lib.rs --- 16_virtual_mem_part4_higher_half_kernel/kernel/src/lib.rs +++ 17_kernel_symbols/kernel/src/lib.rs -@@ -137,6 +137,7 @@ +@@ -138,6 +138,7 @@ pub mod memory; pub mod print; pub mod state; @@ -731,6 +731,15 @@ diff -uNr 16_virtual_mem_part4_higher_half_kernel/Makefile 17_kernel_symbols/Mak $(call color_progress_prefix, "Name") @echo $(KERNEL_BIN) $(call color_progress_prefix, "Size") +@@ -190,7 +215,7 @@ + ##------------------------------------------------------------------------------ + ## Generate the documentation + ##------------------------------------------------------------------------------ +-doc: ++doc: clean + $(call color_header, "Generating docs") + @$(DOC_CMD) --document-private-items --open + @@ -318,10 +343,19 @@ cd $(shell pwd) diff --git a/17_kernel_symbols/kernel/src/_arch/aarch64/exception.rs b/17_kernel_symbols/kernel/src/_arch/aarch64/exception.rs index 6781758a..3672466c 100644 --- a/17_kernel_symbols/kernel/src/_arch/aarch64/exception.rs +++ b/17_kernel_symbols/kernel/src/_arch/aarch64/exception.rs @@ -11,7 +11,7 @@ //! //! crate::exception::arch_exception -use crate::{bsp, exception, memory, symbols}; +use crate::{exception, memory, symbols}; use core::{arch::global_asm, cell::UnsafeCell, fmt}; use cortex_a::{asm::barrier, registers::*}; use tock_registers::{ @@ -104,10 +104,8 @@ unsafe extern "C" fn current_elx_synchronous(e: &mut ExceptionContext) { #[no_mangle] unsafe extern "C" fn current_elx_irq(_e: &mut ExceptionContext) { - use exception::asynchronous::interface::IRQManager; - let token = &exception::asynchronous::IRQContext::new(); - bsp::exception::asynchronous::irq_manager().handle_pending_irqs(token); + exception::asynchronous::irq_manager().handle_pending_irqs(token); } #[no_mangle] diff --git a/17_kernel_symbols/kernel/src/bsp/device_driver/arm/gicv2.rs b/17_kernel_symbols/kernel/src/bsp/device_driver/arm/gicv2.rs index 4c68a692..e72fde7b 100644 --- a/17_kernel_symbols/kernel/src/bsp/device_driver/arm/gicv2.rs +++ b/17_kernel_symbols/kernel/src/bsp/device_driver/arm/gicv2.rs @@ -79,8 +79,12 @@ mod gicc; mod gicd; -use crate::{bsp, cpu, driver, exception, memory, synchronization, synchronization::InitStateLock}; -use core::sync::atomic::{AtomicBool, Ordering}; +use crate::{ + bsp, cpu, driver, exception, + memory::{Address, Virtual}, + synchronization, + synchronization::InitStateLock, +}; //-------------------------------------------------------------------------------------------------- // Private Definitions @@ -97,20 +101,17 @@ pub type IRQNumber = exception::asynchronous::IRQNumber<{ GICv2::MAX_IRQ_NUMBER /// Representation of the GIC. pub struct GICv2 { - gicd_mmio_descriptor: memory::mmu::MMIODescriptor, - gicc_mmio_descriptor: memory::mmu::MMIODescriptor, - /// The Distributor. gicd: gicd::GICD, /// The CPU Interface. gicc: gicc::GICC, - /// Have the MMIO regions been remapped yet? - is_mmio_remapped: AtomicBool, - /// Stores registered IRQ handlers. Writable only during kernel init. RO afterwards. handler_table: InitStateLock, + + /// Callback to be invoked after successful init. + post_init_callback: fn(), } //-------------------------------------------------------------------------------------------------- @@ -121,22 +122,23 @@ impl GICv2 { const MAX_IRQ_NUMBER: usize = 300; // Normally 1019, but keep it lower to save some space. const NUM_IRQS: usize = Self::MAX_IRQ_NUMBER + 1; + pub const COMPATIBLE: &'static str = "GICv2 (ARM Generic Interrupt Controller v2)"; + /// Create an instance. /// /// # Safety /// - /// - The user must ensure to provide correct MMIO descriptors. + /// - The user must ensure to provide a correct MMIO start address. pub const unsafe fn new( - gicd_mmio_descriptor: memory::mmu::MMIODescriptor, - gicc_mmio_descriptor: memory::mmu::MMIODescriptor, + gicd_mmio_start_addr: Address, + gicc_mmio_start_addr: Address, + post_init_callback: fn(), ) -> Self { Self { - gicd_mmio_descriptor, - gicc_mmio_descriptor, - gicd: gicd::GICD::new(gicd_mmio_descriptor.start_addr().as_usize()), - gicc: gicc::GICC::new(gicc_mmio_descriptor.start_addr().as_usize()), - is_mmio_remapped: AtomicBool::new(false), + gicd: gicd::GICD::new(gicd_mmio_start_addr), + gicc: gicc::GICC::new(gicc_mmio_start_addr), handler_table: InitStateLock::new([None; Self::NUM_IRQS]), + post_init_callback, } } } @@ -148,24 +150,10 @@ use synchronization::interface::ReadWriteEx; impl driver::interface::DeviceDriver for GICv2 { fn compatible(&self) -> &'static str { - "GICv2 (ARM Generic Interrupt Controller v2)" + Self::COMPATIBLE } unsafe fn init(&self) -> Result<(), &'static str> { - let remapped = self.is_mmio_remapped.load(Ordering::Relaxed); - if !remapped { - // GICD - let mut virt_addr = memory::mmu::kernel_map_mmio("GICD", &self.gicd_mmio_descriptor)?; - self.gicd.set_mmio(virt_addr.as_usize()); - - // GICC - virt_addr = memory::mmu::kernel_map_mmio("GICC", &self.gicc_mmio_descriptor)?; - self.gicc.set_mmio(virt_addr.as_usize()); - - // Conclude remapping. - self.is_mmio_remapped.store(true, Ordering::Relaxed); - } - if bsp::cpu::BOOT_CORE_ID == cpu::smp::core_id() { self.gicd.boot_core_init(); } @@ -173,6 +161,8 @@ impl driver::interface::DeviceDriver for GICv2 { self.gicc.priority_accept_all(); self.gicc.enable(); + (self.post_init_callback)(); + Ok(()) } } diff --git a/17_kernel_symbols/kernel/src/bsp/device_driver/arm/gicv2/gicc.rs b/17_kernel_symbols/kernel/src/bsp/device_driver/arm/gicv2/gicc.rs index 1a151d24..1a02fc65 100644 --- a/17_kernel_symbols/kernel/src/bsp/device_driver/arm/gicv2/gicc.rs +++ b/17_kernel_symbols/kernel/src/bsp/device_driver/arm/gicv2/gicc.rs @@ -5,7 +5,9 @@ //! GICC Driver - GIC CPU interface. use crate::{ - bsp::device_driver::common::MMIODerefWrapper, exception, synchronization::InitStateLock, + bsp::device_driver::common::MMIODerefWrapper, + exception, + memory::{Address, Virtual}, }; use tock_registers::{ interfaces::{Readable, Writeable}, @@ -62,13 +64,12 @@ type Registers = MMIODerefWrapper; /// Representation of the GIC CPU interface. pub struct GICC { - registers: InitStateLock, + registers: Registers, } //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- -use crate::synchronization::interface::ReadWriteEx; impl GICC { /// Create an instance. @@ -76,17 +77,12 @@ impl GICC { /// # Safety /// /// - The user must ensure to provide a correct MMIO start address. - pub const unsafe fn new(mmio_start_addr: usize) -> Self { + pub const unsafe fn new(mmio_start_addr: Address) -> Self { Self { - registers: InitStateLock::new(Registers::new(mmio_start_addr)), + registers: Registers::new(mmio_start_addr), } } - pub unsafe fn set_mmio(&self, new_mmio_start_addr: usize) { - self.registers - .write(|regs| *regs = Registers::new(new_mmio_start_addr)); - } - /// Accept interrupts of any priority. /// /// Quoting the GICv2 Architecture Specification: @@ -99,9 +95,7 @@ impl GICC { /// - GICC MMIO registers are banked per CPU core. It is therefore safe to have `&self` instead /// of `&mut self`. pub fn priority_accept_all(&self) { - self.registers.read(|regs| { - regs.PMR.write(PMR::Priority.val(255)); // Comment in arch spec. - }); + self.registers.PMR.write(PMR::Priority.val(255)); // Comment in arch spec. } /// Enable the interface - start accepting IRQs. @@ -111,9 +105,7 @@ impl GICC { /// - GICC MMIO registers are banked per CPU core. It is therefore safe to have `&self` instead /// of `&mut self`. pub fn enable(&self) { - self.registers.read(|regs| { - regs.CTLR.write(CTLR::Enable::SET); - }); + self.registers.CTLR.write(CTLR::Enable::SET); } /// Extract the number of the highest-priority pending IRQ. @@ -129,8 +121,7 @@ impl GICC { &self, _ic: &exception::asynchronous::IRQContext<'irq_context>, ) -> usize { - self.registers - .read(|regs| regs.IAR.read(IAR::InterruptID) as usize) + self.registers.IAR.read(IAR::InterruptID) as usize } /// Complete handling of the currently active IRQ. @@ -149,8 +140,6 @@ impl GICC { irq_number: u32, _ic: &exception::asynchronous::IRQContext<'irq_context>, ) { - self.registers.read(|regs| { - regs.EOIR.write(EOIR::EOIINTID.val(irq_number)); - }); + self.registers.EOIR.write(EOIR::EOIINTID.val(irq_number)); } } diff --git a/17_kernel_symbols/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs b/17_kernel_symbols/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs index 60bbc468..d9f63d1b 100644 --- a/17_kernel_symbols/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs +++ b/17_kernel_symbols/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs @@ -9,8 +9,9 @@ use crate::{ bsp::device_driver::common::MMIODerefWrapper, + memory::{Address, Virtual}, state, synchronization, - synchronization::{IRQSafeNullLock, InitStateLock}, + synchronization::IRQSafeNullLock, }; use tock_registers::{ interfaces::{Readable, Writeable}, @@ -84,7 +85,7 @@ pub struct GICD { shared_registers: IRQSafeNullLock, /// Access to banked registers is unguarded. - banked_registers: InitStateLock, + banked_registers: BankedRegisters, } //-------------------------------------------------------------------------------------------------- @@ -121,7 +122,6 @@ impl SharedRegisters { //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- -use crate::synchronization::interface::ReadWriteEx; use synchronization::interface::Mutex; impl GICD { @@ -130,20 +130,13 @@ impl GICD { /// # Safety /// /// - The user must ensure to provide a correct MMIO start address. - pub const unsafe fn new(mmio_start_addr: usize) -> Self { + pub const unsafe fn new(mmio_start_addr: Address) -> Self { Self { shared_registers: IRQSafeNullLock::new(SharedRegisters::new(mmio_start_addr)), - banked_registers: InitStateLock::new(BankedRegisters::new(mmio_start_addr)), + banked_registers: BankedRegisters::new(mmio_start_addr), } } - pub unsafe fn set_mmio(&self, new_mmio_start_addr: usize) { - self.shared_registers - .lock(|regs| *regs = SharedRegisters::new(new_mmio_start_addr)); - self.banked_registers - .write(|regs| *regs = BankedRegisters::new(new_mmio_start_addr)); - } - /// Use a banked ITARGETSR to retrieve the executing core's GIC target mask. /// /// Quoting the GICv2 Architecture Specification: @@ -151,8 +144,7 @@ impl GICD { /// "GICD_ITARGETSR0 to GICD_ITARGETSR7 are read-only, and each field returns a value that /// corresponds only to the processor reading the register." fn local_gic_target_mask(&self) -> u32 { - self.banked_registers - .read(|regs| regs.ITARGETSR[0].read(ITARGETSR::Offset0)) + self.banked_registers.ITARGETSR[0].read(ITARGETSR::Offset0) } /// Route all SPIs to the boot core and enable the distributor. @@ -191,10 +183,10 @@ impl GICD { // Check if we are handling a private or shared IRQ. match irq_num { // Private. - 0..=31 => self.banked_registers.read(|regs| { - let enable_reg = ®s.ISENABLER; + 0..=31 => { + let enable_reg = &self.banked_registers.ISENABLER; enable_reg.set(enable_reg.get() | enable_bit); - }), + } // Shared. _ => { let enable_reg_index_shared = enable_reg_index - 1; diff --git a/17_kernel_symbols/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs b/17_kernel_symbols/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs index eea07b75..a3361c2c 100644 --- a/17_kernel_symbols/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs +++ b/17_kernel_symbols/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs @@ -5,10 +5,12 @@ //! GPIO Driver. use crate::{ - bsp::device_driver::common::MMIODerefWrapper, driver, memory, synchronization, + bsp::device_driver::common::MMIODerefWrapper, + driver, + memory::{Address, Virtual}, + synchronization, synchronization::IRQSafeNullLock, }; -use core::sync::atomic::{AtomicUsize, Ordering}; use tock_registers::{ interfaces::{ReadWriteable, Writeable}, register_bitfields, register_structs, @@ -109,26 +111,22 @@ register_structs! { /// Abstraction for the associated MMIO registers. type Registers = MMIODerefWrapper; -//-------------------------------------------------------------------------------------------------- -// Public Definitions -//-------------------------------------------------------------------------------------------------- - -pub struct GPIOInner { +struct GPIOInner { registers: Registers, } -// Export the inner struct so that BSPs can use it for the panic handler. -pub use GPIOInner as PanicGPIO; +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- /// Representation of the GPIO HW. pub struct GPIO { - mmio_descriptor: memory::mmu::MMIODescriptor, - virt_mmio_start_addr: AtomicUsize, inner: IRQSafeNullLock, + post_init_callback: fn(), } //-------------------------------------------------------------------------------------------------- -// Public Code +// Private Code //-------------------------------------------------------------------------------------------------- impl GPIOInner { @@ -137,25 +135,12 @@ impl GPIOInner { /// # Safety /// /// - The user must ensure to provide a correct MMIO start address. - pub const unsafe fn new(mmio_start_addr: usize) -> Self { + pub const unsafe fn new(mmio_start_addr: Address) -> Self { Self { registers: Registers::new(mmio_start_addr), } } - /// Init code. - /// - /// # Safety - /// - /// - The user must ensure to provide a correct MMIO start address. - pub unsafe fn init(&mut self, new_mmio_start_addr: Option) -> Result<(), &'static str> { - if let Some(addr) = new_mmio_start_addr { - self.registers = Registers::new(addr); - } - - Ok(()) - } - /// Disable pull-up/down on pins 14 and 15. #[cfg(feature = "bsp_rpi3")] fn disable_pud_14_15_bcm2837(&mut self) { @@ -205,17 +190,22 @@ impl GPIOInner { } } +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + impl GPIO { + pub const COMPATIBLE: &'static str = "BCM GPIO"; + /// Create an instance. /// /// # Safety /// - /// - The user must ensure to provide correct MMIO descriptors. - pub const unsafe fn new(mmio_descriptor: memory::mmu::MMIODescriptor) -> Self { + /// - The user must ensure to provide a correct MMIO start address. + pub const unsafe fn new(mmio_start_addr: Address, post_init_callback: fn()) -> Self { Self { - mmio_descriptor, - virt_mmio_start_addr: AtomicUsize::new(0), - inner: IRQSafeNullLock::new(GPIOInner::new(mmio_descriptor.start_addr().as_usize())), + inner: IRQSafeNullLock::new(GPIOInner::new(mmio_start_addr)), + post_init_callback, } } @@ -232,28 +222,12 @@ use synchronization::interface::Mutex; impl driver::interface::DeviceDriver for GPIO { fn compatible(&self) -> &'static str { - "BCM GPIO" + Self::COMPATIBLE } unsafe fn init(&self) -> Result<(), &'static str> { - let virt_addr = memory::mmu::kernel_map_mmio(self.compatible(), &self.mmio_descriptor)?; - - self.inner - .lock(|inner| inner.init(Some(virt_addr.as_usize())))?; - - self.virt_mmio_start_addr - .store(virt_addr.as_usize(), Ordering::Relaxed); + (self.post_init_callback)(); Ok(()) } - - fn virt_mmio_start_addr(&self) -> Option { - let addr = self.virt_mmio_start_addr.load(Ordering::Relaxed); - - if addr == 0 { - return None; - } - - Some(addr) - } } diff --git a/17_kernel_symbols/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs b/17_kernel_symbols/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs index 99961fac..4908b8b6 100644 --- a/17_kernel_symbols/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs +++ b/17_kernel_symbols/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs @@ -6,7 +6,10 @@ mod peripheral_ic; -use crate::{driver, exception, memory}; +use crate::{ + driver, exception, + memory::{Address, Virtual}, +}; //-------------------------------------------------------------------------------------------------- // Private Definitions @@ -28,6 +31,7 @@ pub type PeripheralIRQ = /// Used for the associated type of trait [`exception::asynchronous::interface::IRQManager`]. #[derive(Copy, Clone)] +#[allow(missing_docs)] pub enum IRQNumber { Local(LocalIRQ), Peripheral(PeripheralIRQ), @@ -36,6 +40,7 @@ pub enum IRQNumber { /// Representation of the Interrupt Controller. pub struct InterruptController { periph: peripheral_ic::PeripheralIC, + post_init_callback: fn(), } //-------------------------------------------------------------------------------------------------- @@ -74,17 +79,20 @@ impl InterruptController { const MAX_PERIPHERAL_IRQ_NUMBER: usize = 63; const NUM_PERIPHERAL_IRQS: usize = Self::MAX_PERIPHERAL_IRQ_NUMBER + 1; + pub const COMPATIBLE: &'static str = "BCM Interrupt Controller"; + /// Create an instance. /// /// # Safety /// - /// - The user must ensure to provide correct MMIO descriptors. + /// - The user must ensure to provide a correct MMIO start address. pub const unsafe fn new( - _local_mmio_descriptor: memory::mmu::MMIODescriptor, - periph_mmio_descriptor: memory::mmu::MMIODescriptor, + periph_mmio_start_addr: Address, + post_init_callback: fn(), ) -> Self { Self { - periph: peripheral_ic::PeripheralIC::new(periph_mmio_descriptor), + periph: peripheral_ic::PeripheralIC::new(periph_mmio_start_addr), + post_init_callback, } } } @@ -95,11 +103,13 @@ impl InterruptController { impl driver::interface::DeviceDriver for InterruptController { fn compatible(&self) -> &'static str { - "BCM Interrupt Controller" + Self::COMPATIBLE } unsafe fn init(&self) -> Result<(), &'static str> { - self.periph.init() + (self.post_init_callback)(); + + Ok(()) } } diff --git a/17_kernel_symbols/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs b/17_kernel_symbols/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs index f09da862..145d8961 100644 --- a/17_kernel_symbols/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs +++ b/17_kernel_symbols/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs @@ -7,7 +7,9 @@ use super::{InterruptController, PendingIRQs, PeripheralIRQ}; use crate::{ bsp::device_driver::common::MMIODerefWrapper, - driver, exception, memory, synchronization, + exception, + memory::{Address, Virtual}, + synchronization, synchronization::{IRQSafeNullLock, InitStateLock}, }; use tock_registers::{ @@ -55,13 +57,11 @@ type HandlerTable = /// Representation of the peripheral interrupt controller. pub struct PeripheralIC { - mmio_descriptor: memory::mmu::MMIODescriptor, - /// Access to write registers is guarded with a lock. wo_registers: IRQSafeNullLock, /// Register read access is unguarded. - ro_registers: InitStateLock, + ro_registers: ReadOnlyRegisters, /// Stores registered IRQ handlers. Writable only during kernel init. RO afterwards. handler_table: InitStateLock, @@ -76,26 +76,21 @@ impl PeripheralIC { /// /// # Safety /// - /// - The user must ensure to provide correct MMIO descriptors. - pub const unsafe fn new(mmio_descriptor: memory::mmu::MMIODescriptor) -> Self { - let addr = mmio_descriptor.start_addr().as_usize(); - + /// - The user must ensure to provide a correct MMIO start address. + pub const unsafe fn new(mmio_start_addr: Address) -> Self { Self { - mmio_descriptor, - wo_registers: IRQSafeNullLock::new(WriteOnlyRegisters::new(addr)), - ro_registers: InitStateLock::new(ReadOnlyRegisters::new(addr)), + wo_registers: IRQSafeNullLock::new(WriteOnlyRegisters::new(mmio_start_addr)), + ro_registers: ReadOnlyRegisters::new(mmio_start_addr), handler_table: InitStateLock::new([None; InterruptController::NUM_PERIPHERAL_IRQS]), } } /// Query the list of pending IRQs. fn pending_irqs(&self) -> PendingIRQs { - self.ro_registers.read(|regs| { - let pending_mask: u64 = - (u64::from(regs.PENDING_2.get()) << 32) | u64::from(regs.PENDING_1.get()); + let pending_mask: u64 = (u64::from(self.ro_registers.PENDING_2.get()) << 32) + | u64::from(self.ro_registers.PENDING_1.get()); - PendingIRQs::new(pending_mask) - }) + PendingIRQs::new(pending_mask) } } @@ -104,24 +99,6 @@ impl PeripheralIC { //------------------------------------------------------------------------------ use synchronization::interface::{Mutex, ReadWriteEx}; -impl driver::interface::DeviceDriver for PeripheralIC { - fn compatible(&self) -> &'static str { - "BCM Peripheral Interrupt Controller" - } - - unsafe fn init(&self) -> Result<(), &'static str> { - let virt_addr = - memory::mmu::kernel_map_mmio(self.compatible(), &self.mmio_descriptor)?.as_usize(); - - self.wo_registers - .lock(|regs| *regs = WriteOnlyRegisters::new(virt_addr)); - self.ro_registers - .write(|regs| *regs = ReadOnlyRegisters::new(virt_addr)); - - Ok(()) - } -} - impl exception::asynchronous::interface::IRQManager for PeripheralIC { type IRQNumberType = PeripheralIRQ; diff --git a/17_kernel_symbols/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs b/17_kernel_symbols/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs index 3133047b..f67d70df 100644 --- a/17_kernel_symbols/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs +++ b/17_kernel_symbols/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs @@ -10,13 +10,14 @@ //! - use crate::{ - bsp, bsp::device_driver::common::MMIODerefWrapper, console, cpu, driver, exception, memory, - synchronization, synchronization::IRQSafeNullLock, -}; -use core::{ - fmt, - sync::atomic::{AtomicUsize, Ordering}, + bsp, + bsp::device_driver::common::MMIODerefWrapper, + console, cpu, driver, exception, + memory::{Address, Virtual}, + synchronization, + synchronization::IRQSafeNullLock, }; +use core::fmt; use tock_registers::{ interfaces::{Readable, Writeable}, register_bitfields, register_structs, @@ -219,29 +220,25 @@ enum BlockingMode { NonBlocking, } -//-------------------------------------------------------------------------------------------------- -// Public Definitions -//-------------------------------------------------------------------------------------------------- - -pub struct PL011UartInner { +struct PL011UartInner { registers: Registers, chars_written: usize, chars_read: usize, } -// Export the inner struct so that BSPs can use it for the panic handler. -pub use PL011UartInner as PanicUart; +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- /// Representation of the UART. pub struct PL011Uart { - mmio_descriptor: memory::mmu::MMIODescriptor, - virt_mmio_start_addr: AtomicUsize, inner: IRQSafeNullLock, irq_number: bsp::device_driver::IRQNumber, + post_init_callback: fn(), } //-------------------------------------------------------------------------------------------------- -// Public Code +// Private Code //-------------------------------------------------------------------------------------------------- impl PL011UartInner { @@ -250,7 +247,7 @@ impl PL011UartInner { /// # Safety /// /// - The user must ensure to provide a correct MMIO start address. - pub const unsafe fn new(mmio_start_addr: usize) -> Self { + pub const unsafe fn new(mmio_start_addr: Address) -> Self { Self { registers: Registers::new(mmio_start_addr), chars_written: 0, @@ -275,15 +272,7 @@ impl PL011UartInner { /// genrated baud rate of `48_000_000 / (16 * 3.25) = 923_077`. /// /// Error = `((923_077 - 921_600) / 921_600) * 100 = 0.16%`. - /// - /// # Safety - /// - /// - The user must ensure to provide a correct MMIO start address. - pub unsafe fn init(&mut self, new_mmio_start_addr: Option) -> Result<(), &'static str> { - if let Some(addr) = new_mmio_start_addr { - self.registers = Registers::new(addr); - } - + pub fn init(&mut self) { // Execution can arrive here while there are still characters queued in the TX FIFO and // actively being sent out by the UART hardware. If the UART is turned off in this case, // those queued characters would be lost. @@ -325,8 +314,6 @@ impl PL011UartInner { self.registers .CR .write(CR::UARTEN::Enabled + CR::TXE::Enabled + CR::RXE::Enabled); - - Ok(()) } /// Send a character. @@ -399,24 +386,28 @@ impl fmt::Write for PL011UartInner { } } +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + impl PL011Uart { + pub const COMPATIBLE: &'static str = "BCM PL011 UART"; + /// Create an instance. /// /// # Safety /// - /// - The user must ensure to provide correct MMIO descriptors. + /// - The user must ensure to provide a correct MMIO start address. /// - The user must ensure to provide correct IRQ numbers. pub const unsafe fn new( - mmio_descriptor: memory::mmu::MMIODescriptor, + mmio_start_addr: Address, irq_number: bsp::device_driver::IRQNumber, + post_init_callback: fn(), ) -> Self { Self { - mmio_descriptor, - virt_mmio_start_addr: AtomicUsize::new(0), - inner: IRQSafeNullLock::new(PL011UartInner::new( - mmio_descriptor.start_addr().as_usize(), - )), + inner: IRQSafeNullLock::new(PL011UartInner::new(mmio_start_addr)), irq_number, + post_init_callback, } } } @@ -428,27 +419,21 @@ use synchronization::interface::Mutex; impl driver::interface::DeviceDriver for PL011Uart { fn compatible(&self) -> &'static str { - "BCM PL011 UART" + Self::COMPATIBLE } unsafe fn init(&self) -> Result<(), &'static str> { - let virt_addr = memory::mmu::kernel_map_mmio(self.compatible(), &self.mmio_descriptor)?; - - self.inner - .lock(|inner| inner.init(Some(virt_addr.as_usize())))?; - - self.virt_mmio_start_addr - .store(virt_addr.as_usize(), Ordering::Relaxed); + self.inner.lock(|inner| inner.init()); + (self.post_init_callback)(); Ok(()) } fn register_and_enable_irq_handler(&'static self) -> Result<(), &'static str> { - use bsp::exception::asynchronous::irq_manager; - use exception::asynchronous::{interface::IRQManager, IRQDescriptor}; + use exception::asynchronous::{irq_manager, IRQDescriptor}; let descriptor = IRQDescriptor { - name: "BCM PL011 UART", + name: Self::COMPATIBLE, handler: self, }; @@ -457,16 +442,6 @@ impl driver::interface::DeviceDriver for PL011Uart { Ok(()) } - - fn virt_mmio_start_addr(&self) -> Option { - let addr = self.virt_mmio_start_addr.load(Ordering::Relaxed); - - if addr == 0 { - return None; - } - - Some(addr) - } } impl console::interface::Write for PL011Uart { @@ -514,6 +489,8 @@ impl console::interface::Statistics for PL011Uart { } } +impl console::interface::All for PL011Uart {} + impl exception::asynchronous::interface::IRQHandler for PL011Uart { fn handle(&self) -> Result<(), &'static str> { self.inner.lock(|inner| { diff --git a/17_kernel_symbols/kernel/src/bsp/device_driver/common.rs b/17_kernel_symbols/kernel/src/bsp/device_driver/common.rs index fd9e988e..69f038d4 100644 --- a/17_kernel_symbols/kernel/src/bsp/device_driver/common.rs +++ b/17_kernel_symbols/kernel/src/bsp/device_driver/common.rs @@ -4,6 +4,7 @@ //! Common device driver code. +use crate::memory::{Address, Virtual}; use core::{marker::PhantomData, ops}; //-------------------------------------------------------------------------------------------------- @@ -11,7 +12,7 @@ use core::{marker::PhantomData, ops}; //-------------------------------------------------------------------------------------------------- pub struct MMIODerefWrapper { - start_addr: usize, + start_addr: Address, phantom: PhantomData T>, } @@ -21,7 +22,7 @@ pub struct MMIODerefWrapper { impl MMIODerefWrapper { /// Create an instance. - pub const unsafe fn new(start_addr: usize) -> Self { + pub const unsafe fn new(start_addr: Address) -> Self { Self { start_addr, phantom: PhantomData, @@ -33,6 +34,6 @@ impl ops::Deref for MMIODerefWrapper { type Target = T; fn deref(&self) -> &Self::Target { - unsafe { &*(self.start_addr as *const _) } + unsafe { &*(self.start_addr.as_usize() as *const _) } } } diff --git a/17_kernel_symbols/kernel/src/bsp/raspberrypi.rs b/17_kernel_symbols/kernel/src/bsp/raspberrypi.rs index fb9edf88..474419f4 100644 --- a/17_kernel_symbols/kernel/src/bsp/raspberrypi.rs +++ b/17_kernel_symbols/kernel/src/bsp/raspberrypi.rs @@ -4,46 +4,11 @@ //! Top-level BSP file for the Raspberry Pi 3 and 4. -pub mod console; pub mod cpu; pub mod driver; pub mod exception; pub mod memory; -use super::device_driver; -use crate::memory::mmu::MMIODescriptor; -use memory::map::mmio; - -//-------------------------------------------------------------------------------------------------- -// Global instances -//-------------------------------------------------------------------------------------------------- - -static GPIO: device_driver::GPIO = - unsafe { device_driver::GPIO::new(MMIODescriptor::new(mmio::GPIO_START, mmio::GPIO_SIZE)) }; - -static PL011_UART: device_driver::PL011Uart = unsafe { - device_driver::PL011Uart::new( - MMIODescriptor::new(mmio::PL011_UART_START, mmio::PL011_UART_SIZE), - exception::asynchronous::irq_map::PL011_UART, - ) -}; - -#[cfg(feature = "bsp_rpi3")] -static INTERRUPT_CONTROLLER: device_driver::InterruptController = unsafe { - device_driver::InterruptController::new( - MMIODescriptor::new(mmio::LOCAL_IC_START, mmio::LOCAL_IC_SIZE), - MMIODescriptor::new(mmio::PERIPHERAL_IC_START, mmio::PERIPHERAL_IC_SIZE), - ) -}; - -#[cfg(feature = "bsp_rpi4")] -static INTERRUPT_CONTROLLER: device_driver::GICv2 = unsafe { - device_driver::GICv2::new( - MMIODescriptor::new(mmio::GICD_START, mmio::GICD_SIZE), - MMIODescriptor::new(mmio::GICC_START, mmio::GICC_SIZE), - ) -}; - //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- diff --git a/17_kernel_symbols/kernel/src/bsp/raspberrypi/console.rs b/17_kernel_symbols/kernel/src/bsp/raspberrypi/console.rs deleted file mode 100644 index a0d2e687..00000000 --- a/17_kernel_symbols/kernel/src/bsp/raspberrypi/console.rs +++ /dev/null @@ -1,98 +0,0 @@ -// SPDX-License-Identifier: MIT OR Apache-2.0 -// -// Copyright (c) 2018-2022 Andre Richter - -//! BSP console facilities. - -use crate::{bsp::device_driver, console, cpu, driver}; -use core::fmt; - -//-------------------------------------------------------------------------------------------------- -// Public Code -//-------------------------------------------------------------------------------------------------- - -/// In case of a panic, the panic handler uses this function to take a last shot at printing -/// something before the system is halted. -/// -/// We try to init panic-versions of the GPIO and the UART. The panic versions are not protected -/// with synchronization primitives, which increases chances that we get to print something, even -/// when the kernel's default GPIO or UART instances happen to be locked at the time of the panic. -/// -/// # Safety -/// -/// - Use only for printing during a panic. -#[cfg(not(feature = "test_build"))] -pub unsafe fn panic_console_out() -> impl fmt::Write { - use driver::interface::DeviceDriver; - - // If remapping of the driver's MMIO hasn't already happened, we won't be able to print. Just - // park the CPU core in this case. - let gpio_mmio_start_addr = match super::GPIO.virt_mmio_start_addr() { - None => cpu::wait_forever(), - Some(x) => x, - }; - - let uart_mmio_start_addr = match super::PL011_UART.virt_mmio_start_addr() { - None => cpu::wait_forever(), - Some(x) => x, - }; - - let mut panic_gpio = device_driver::PanicGPIO::new(gpio_mmio_start_addr); - let mut panic_uart = device_driver::PanicUart::new(uart_mmio_start_addr); - - panic_gpio - .init(None) - .unwrap_or_else(|_| cpu::wait_forever()); - panic_gpio.map_pl011_uart(); - panic_uart - .init(None) - .unwrap_or_else(|_| cpu::wait_forever()); - - panic_uart -} - -/// Reduced version for test builds. -/// -/// # Safety -/// -/// - Use only for printing during a panic. -#[cfg(feature = "test_build")] -pub unsafe fn panic_console_out() -> impl fmt::Write { - use driver::interface::DeviceDriver; - - let uart_mmio_start_addr = match super::PL011_UART.virt_mmio_start_addr() { - None => cpu::wait_forever(), - Some(x) => x, - }; - let mut panic_uart = device_driver::PanicUart::new(uart_mmio_start_addr); - - panic_uart - .init(None) - .unwrap_or_else(|_| cpu::qemu_exit_failure()); - - panic_uart -} - -/// Return a reference to the console. -pub fn console() -> &'static impl console::interface::All { - &super::PL011_UART -} - -//-------------------------------------------------------------------------------------------------- -// Testing -//-------------------------------------------------------------------------------------------------- - -/// Minimal code needed to bring up the console in QEMU (for testing only). This is often less steps -/// than on real hardware due to QEMU's abstractions. -#[cfg(feature = "test_build")] -pub fn qemu_bring_up_console() { - use driver::interface::DeviceDriver; - - // Calling the UART's init ensures that the BSP's instance of the UART does remap the MMIO - // addresses. - unsafe { - super::PL011_UART - .init() - .unwrap_or_else(|_| cpu::qemu_exit_failure()); - } -} diff --git a/17_kernel_symbols/kernel/src/bsp/raspberrypi/driver.rs b/17_kernel_symbols/kernel/src/bsp/raspberrypi/driver.rs index 53168752..e1db4a00 100644 --- a/17_kernel_symbols/kernel/src/bsp/raspberrypi/driver.rs +++ b/17_kernel_symbols/kernel/src/bsp/raspberrypi/driver.rs @@ -4,7 +4,19 @@ //! BSP driver support. -use crate::driver; +use super::{exception, memory::map::mmio}; +use crate::{ + bsp::device_driver, + console, driver, exception as generic_exception, memory, + memory::mmu::MMIODescriptor, + synchronization::{interface::ReadWriteEx, InitStateLock}, +}; +use core::{ + mem::MaybeUninit, + sync::atomic::{AtomicBool, Ordering}, +}; + +pub use device_driver::IRQNumber; //-------------------------------------------------------------------------------------------------- // Private Definitions @@ -12,21 +24,132 @@ use crate::driver; /// Device Driver Manager type. struct BSPDriverManager { - device_drivers: [&'static (dyn DeviceDriver + Sync); 3], + device_drivers: InitStateLock<[Option<&'static (dyn DeviceDriver + Sync)>; NUM_DRIVERS]>, + init_done: AtomicBool, } +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +/// The number of active drivers provided by this BSP. +pub const NUM_DRIVERS: usize = 3; + //-------------------------------------------------------------------------------------------------- // Global instances //-------------------------------------------------------------------------------------------------- +static mut PL011_UART: MaybeUninit = MaybeUninit::uninit(); +static mut GPIO: MaybeUninit = MaybeUninit::uninit(); + +#[cfg(feature = "bsp_rpi3")] +static mut INTERRUPT_CONTROLLER: MaybeUninit = + MaybeUninit::uninit(); + +#[cfg(feature = "bsp_rpi4")] +static mut INTERRUPT_CONTROLLER: MaybeUninit = MaybeUninit::uninit(); + static BSP_DRIVER_MANAGER: BSPDriverManager = BSPDriverManager { - device_drivers: [ - &super::GPIO, - &super::PL011_UART, - &super::INTERRUPT_CONTROLLER, - ], + device_drivers: InitStateLock::new([None; NUM_DRIVERS]), + init_done: AtomicBool::new(false), }; +//-------------------------------------------------------------------------------------------------- +// Private Code +//-------------------------------------------------------------------------------------------------- + +impl BSPDriverManager { + unsafe fn instantiate_uart(&self) -> Result<(), &'static str> { + let mmio_descriptor = MMIODescriptor::new(mmio::PL011_UART_START, mmio::PL011_UART_SIZE); + let virt_addr = + memory::mmu::kernel_map_mmio(device_driver::PL011Uart::COMPATIBLE, &mmio_descriptor)?; + + // This is safe to do, because it is only called from the init'ed instance itself. + fn uart_post_init() { + console::register_console(unsafe { PL011_UART.assume_init_ref() }); + } + + PL011_UART.write(device_driver::PL011Uart::new( + virt_addr, + exception::asynchronous::irq_map::PL011_UART, + uart_post_init, + )); + + Ok(()) + } + + unsafe fn instantiate_gpio(&self) -> Result<(), &'static str> { + let mmio_descriptor = MMIODescriptor::new(mmio::GPIO_START, mmio::GPIO_SIZE); + let virt_addr = + memory::mmu::kernel_map_mmio(device_driver::GPIO::COMPATIBLE, &mmio_descriptor)?; + + // This is safe to do, because it is only called from the init'ed instance itself. + fn gpio_post_init() { + unsafe { GPIO.assume_init_ref().map_pl011_uart() }; + } + + GPIO.write(device_driver::GPIO::new(virt_addr, gpio_post_init)); + + Ok(()) + } + + #[cfg(feature = "bsp_rpi3")] + unsafe fn instantiate_interrupt_controller(&self) -> Result<(), &'static str> { + let periph_mmio_descriptor = + MMIODescriptor::new(mmio::PERIPHERAL_IC_START, mmio::PERIPHERAL_IC_SIZE); + let periph_virt_addr = memory::mmu::kernel_map_mmio( + device_driver::InterruptController::COMPATIBLE, + &periph_mmio_descriptor, + )?; + + // This is safe to do, because it is only called from the init'ed instance itself. + fn interrupt_controller_post_init() { + generic_exception::asynchronous::register_irq_manager(unsafe { + INTERRUPT_CONTROLLER.assume_init_ref() + }); + } + + INTERRUPT_CONTROLLER.write(device_driver::InterruptController::new( + periph_virt_addr, + interrupt_controller_post_init, + )); + + Ok(()) + } + + #[cfg(feature = "bsp_rpi4")] + unsafe fn instantiate_interrupt_controller(&self) -> Result<(), &'static str> { + let gicd_mmio_descriptor = MMIODescriptor::new(mmio::GICD_START, mmio::GICD_SIZE); + let gicd_virt_addr = memory::mmu::kernel_map_mmio("GICv2 GICD", &gicd_mmio_descriptor)?; + + let gicc_mmio_descriptor = MMIODescriptor::new(mmio::GICC_START, mmio::GICC_SIZE); + let gicc_virt_addr = memory::mmu::kernel_map_mmio("GICV2 GICC", &gicc_mmio_descriptor)?; + + // This is safe to do, because it is only called from the init'ed instance itself. + fn interrupt_controller_post_init() { + generic_exception::asynchronous::register_irq_manager(unsafe { + INTERRUPT_CONTROLLER.assume_init_ref() + }); + } + + INTERRUPT_CONTROLLER.write(device_driver::GICv2::new( + gicd_virt_addr, + gicc_virt_addr, + interrupt_controller_post_init, + )); + + Ok(()) + } + + unsafe fn register_drivers(&self) { + self.device_drivers.write(|drivers| { + drivers[0] = Some(PL011_UART.assume_init_ref()); + drivers[1] = Some(GPIO.assume_init_ref()); + drivers[2] = Some(INTERRUPT_CONTROLLER.assume_init_ref()); + }); + } +} + //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- @@ -42,20 +165,34 @@ pub fn driver_manager() -> &'static impl driver::interface::DriverManager { use driver::interface::DeviceDriver; impl driver::interface::DriverManager for BSPDriverManager { - fn all_device_drivers(&self) -> &[&'static (dyn DeviceDriver + Sync)] { - &self.device_drivers[..] - } + unsafe fn instantiate_drivers(&self) -> Result<(), &'static str> { + if self.init_done.load(Ordering::Relaxed) { + return Err("Drivers already instantiated"); + } + + self.instantiate_uart()?; + self.instantiate_gpio()?; + self.instantiate_interrupt_controller()?; - fn early_print_device_drivers(&self) -> &[&'static (dyn DeviceDriver + Sync)] { - &self.device_drivers[0..=1] + self.register_drivers(); + + self.init_done.store(true, Ordering::Relaxed); + Ok(()) } - fn non_early_print_device_drivers(&self) -> &[&'static (dyn DeviceDriver + Sync)] { - &self.device_drivers[2..] + fn all_device_drivers(&self) -> [&(dyn DeviceDriver + Sync); NUM_DRIVERS] { + self.device_drivers + .read(|drivers| drivers.map(|drivers| drivers.unwrap())) } - fn post_early_print_device_driver_init(&self) { - // Configure PL011Uart's output pins. - super::GPIO.map_pl011_uart(); + #[cfg(feature = "test_build")] + fn qemu_bring_up_console(&self) { + use crate::cpu; + + unsafe { + self.instantiate_uart() + .unwrap_or_else(|_| cpu::qemu_exit_failure()); + console::register_console(PL011_UART.assume_init_ref()); + }; } } diff --git a/17_kernel_symbols/kernel/src/bsp/raspberrypi/exception/asynchronous.rs b/17_kernel_symbols/kernel/src/bsp/raspberrypi/exception/asynchronous.rs index dc5ab421..ab20d86d 100644 --- a/17_kernel_symbols/kernel/src/bsp/raspberrypi/exception/asynchronous.rs +++ b/17_kernel_symbols/kernel/src/bsp/raspberrypi/exception/asynchronous.rs @@ -4,7 +4,7 @@ //! BSP asynchronous exception handling. -use crate::{bsp, exception}; +use crate::bsp; //-------------------------------------------------------------------------------------------------- // Public Definitions @@ -23,14 +23,3 @@ pub(in crate::bsp) mod irq_map { pub const PL011_UART: IRQNumber = IRQNumber::new(153); } - -//-------------------------------------------------------------------------------------------------- -// Public Code -//-------------------------------------------------------------------------------------------------- - -/// Return a reference to the IRQ manager. -pub fn irq_manager() -> &'static impl exception::asynchronous::interface::IRQManager< - IRQNumberType = bsp::device_driver::IRQNumber, -> { - &super::super::INTERRUPT_CONTROLLER -} diff --git a/17_kernel_symbols/kernel/src/bsp/raspberrypi/memory.rs b/17_kernel_symbols/kernel/src/bsp/raspberrypi/memory.rs index 01aa9441..32416e6c 100644 --- a/17_kernel_symbols/kernel/src/bsp/raspberrypi/memory.rs +++ b/17_kernel_symbols/kernel/src/bsp/raspberrypi/memory.rs @@ -113,9 +113,6 @@ pub(super) mod map { pub const PL011_UART_START: Address = Address::new(0x3F20_1000); pub const PL011_UART_SIZE: usize = 0x48; - pub const LOCAL_IC_START: Address = Address::new(0x4000_0000); - pub const LOCAL_IC_SIZE: usize = 0x100; - pub const END: Address = Address::new(0x4001_0000); } diff --git a/17_kernel_symbols/kernel/src/console.rs b/17_kernel_symbols/kernel/src/console.rs index e49e241f..a85bcffe 100644 --- a/17_kernel_symbols/kernel/src/console.rs +++ b/17_kernel_symbols/kernel/src/console.rs @@ -4,6 +4,10 @@ //! System console. +mod null_console; + +use crate::synchronization; + //-------------------------------------------------------------------------------------------------- // Public Definitions //-------------------------------------------------------------------------------------------------- @@ -49,5 +53,29 @@ pub mod interface { } /// Trait alias for a full-fledged console. - pub trait All = Write + Read + Statistics; + pub trait All: Write + Read + Statistics {} +} + +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +static CUR_CONSOLE: InitStateLock<&'static (dyn interface::All + Sync)> = + InitStateLock::new(&null_console::NULL_CONSOLE); + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- +use synchronization::{interface::ReadWriteEx, InitStateLock}; + +/// Register a new console. +pub fn register_console(new_console: &'static (dyn interface::All + Sync)) { + CUR_CONSOLE.write(|con| *con = new_console); +} + +/// Return a reference to the currently registered console. +/// +/// This is the global console used by all printing macros. +pub fn console() -> &'static dyn interface::All { + CUR_CONSOLE.read(|con| *con) } diff --git a/17_kernel_symbols/kernel/src/console/null_console.rs b/17_kernel_symbols/kernel/src/console/null_console.rs new file mode 100644 index 00000000..10c3bedc --- /dev/null +++ b/17_kernel_symbols/kernel/src/console/null_console.rs @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2022 Andre Richter + +//! Null console. + +use super::interface; +use core::fmt; + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +pub struct NullConsole; + +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +pub static NULL_CONSOLE: NullConsole = NullConsole {}; + +//-------------------------------------------------------------------------------------------------- +// Private Code +//-------------------------------------------------------------------------------------------------- + +impl interface::Write for NullConsole { + fn write_char(&self, _c: char) {} + + fn write_fmt(&self, _args: fmt::Arguments) -> fmt::Result { + fmt::Result::Ok(()) + } + + fn flush(&self) {} +} + +impl interface::Read for NullConsole { + fn clear_rx(&self) {} +} + +impl interface::Statistics for NullConsole {} +impl interface::All for NullConsole {} diff --git a/17_kernel_symbols/kernel/src/driver.rs b/17_kernel_symbols/kernel/src/driver.rs index 7b800dbc..98197fef 100644 --- a/17_kernel_symbols/kernel/src/driver.rs +++ b/17_kernel_symbols/kernel/src/driver.rs @@ -10,6 +10,8 @@ /// Driver interfaces. pub mod interface { + use crate::bsp; + /// Device Driver functions. pub trait DeviceDriver { /// Return a compatibility string for identifying the driver. @@ -31,32 +33,25 @@ pub mod interface { fn register_and_enable_irq_handler(&'static self) -> Result<(), &'static str> { Ok(()) } - - /// After MMIO remapping, returns the new virtual start address. - /// - /// This API assumes a driver has only a single, contiguous MMIO aperture, which will not be - /// the case for more complex devices. This API will likely change in future tutorials. - fn virt_mmio_start_addr(&self) -> Option { - None - } } /// Device driver management functions. /// /// The `BSP` is supposed to supply one global instance. pub trait DriverManager { - /// Return a slice of references to all `BSP`-instantiated drivers. - fn all_device_drivers(&self) -> &[&'static (dyn DeviceDriver + Sync)]; - - /// Return only those drivers needed for the BSP's early printing functionality. + /// Instantiate all drivers. + /// + /// # Safety /// - /// For example, the default UART. - fn early_print_device_drivers(&self) -> &[&'static (dyn DeviceDriver + Sync)]; + /// Must be called before `all_device_drivers`. + unsafe fn instantiate_drivers(&self) -> Result<(), &'static str>; - /// Return all drivers minus early-print drivers. - fn non_early_print_device_drivers(&self) -> &[&'static (dyn DeviceDriver + Sync)]; + /// Return a slice of references to all `BSP`-instantiated drivers. + fn all_device_drivers(&self) -> [&(dyn DeviceDriver + Sync); bsp::driver::NUM_DRIVERS]; - /// Initialization code that runs after the early print driver init. - fn post_early_print_device_driver_init(&self); + /// Minimal code needed to bring up the console in QEMU (for testing only). This is often + /// less steps than on real hardware due to QEMU's abstractions. + #[cfg(feature = "test_build")] + fn qemu_bring_up_console(&self); } } diff --git a/17_kernel_symbols/kernel/src/exception/asynchronous.rs b/17_kernel_symbols/kernel/src/exception/asynchronous.rs index fb1785c2..d9d2767c 100644 --- a/17_kernel_symbols/kernel/src/exception/asynchronous.rs +++ b/17_kernel_symbols/kernel/src/exception/asynchronous.rs @@ -7,7 +7,9 @@ #[cfg(target_arch = "aarch64")] #[path = "../_arch/aarch64/exception/asynchronous.rs"] mod arch_asynchronous; +mod null_irq_manager; +use crate::{bsp, synchronization}; use core::{fmt, marker::PhantomData}; //-------------------------------------------------------------------------------------------------- @@ -85,7 +87,7 @@ pub mod interface { ); /// Print list of registered handlers. - fn print_handler(&self); + fn print_handler(&self) {} } } @@ -93,9 +95,18 @@ pub mod interface { #[derive(Copy, Clone)] pub struct IRQNumber(usize); +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +static CUR_IRQ_MANAGER: InitStateLock< + &'static (dyn interface::IRQManager + Sync), +> = InitStateLock::new(&null_irq_manager::NULL_IRQ_MANAGER); + //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- +use synchronization::{interface::ReadWriteEx, InitStateLock}; impl<'irq_context> IRQContext<'irq_context> { /// Creates an IRQContext token. @@ -150,3 +161,18 @@ pub fn exec_with_irq_masked(f: impl FnOnce() -> T) -> T { ret } + +/// Register a new IRQ manager. +pub fn register_irq_manager( + new_manager: &'static (dyn interface::IRQManager + + Sync), +) { + CUR_IRQ_MANAGER.write(|manager| *manager = new_manager); +} + +/// Return a reference to the currently registered IRQ manager. +/// +/// This is the IRQ manager used by the architectural interrupt handling code. +pub fn irq_manager() -> &'static dyn interface::IRQManager { + CUR_IRQ_MANAGER.read(|manager| *manager) +} diff --git a/17_kernel_symbols/kernel/src/exception/asynchronous/null_irq_manager.rs b/17_kernel_symbols/kernel/src/exception/asynchronous/null_irq_manager.rs new file mode 100644 index 00000000..560e3ce4 --- /dev/null +++ b/17_kernel_symbols/kernel/src/exception/asynchronous/null_irq_manager.rs @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2022 Andre Richter + +//! Null IRQ Manager. + +use super::{interface, IRQContext, IRQDescriptor}; +use crate::bsp; + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +pub struct NullIRQManager; + +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +pub static NULL_IRQ_MANAGER: NullIRQManager = NullIRQManager {}; + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +impl interface::IRQManager for NullIRQManager { + type IRQNumberType = bsp::driver::IRQNumber; + + fn register_handler( + &self, + _irq_number: Self::IRQNumberType, + _descriptor: IRQDescriptor, + ) -> Result<(), &'static str> { + panic!("No IRQ Manager registered yet"); + } + + fn enable(&self, _irq_number: Self::IRQNumberType) { + panic!("No IRQ Manager registered yet"); + } + + fn handle_pending_irqs<'irq_context>(&'irq_context self, _ic: &IRQContext<'irq_context>) { + panic!("No IRQ Manager registered yet"); + } +} diff --git a/17_kernel_symbols/kernel/src/lib.rs b/17_kernel_symbols/kernel/src/lib.rs index 8e38ad6f..e70468e5 100644 --- a/17_kernel_symbols/kernel/src/lib.rs +++ b/17_kernel_symbols/kernel/src/lib.rs @@ -114,6 +114,7 @@ #![feature(core_intrinsics)] #![feature(format_args_nl)] #![feature(generic_const_exprs)] +#![feature(is_sorted)] #![feature(linkage)] #![feature(panic_info_message)] #![feature(step_trait)] @@ -177,9 +178,11 @@ pub fn test_runner(tests: &[&test_types::UnitTest]) { #[cfg(test)] #[no_mangle] unsafe fn kernel_init() -> ! { + use driver::interface::DriverManager; + exception::handling_init(); memory::mmu::post_enable_init(); - bsp::console::qemu_bring_up_console(); + bsp::driver::driver_manager().qemu_bring_up_console(); test_main(); diff --git a/17_kernel_symbols/kernel/src/main.rs b/17_kernel_symbols/kernel/src/main.rs index 5150f3af..928f12c2 100644 --- a/17_kernel_symbols/kernel/src/main.rs +++ b/17_kernel_symbols/kernel/src/main.rs @@ -30,26 +30,11 @@ unsafe fn kernel_init() -> ! { exception::handling_init(); memory::mmu::post_enable_init(); - // Add the mapping records for the precomputed entries first, so that they appear on the top of - // the list. - bsp::memory::mmu::kernel_add_mapping_records_for_precomputed(); - - // Bring up the drivers needed for printing first. - for i in bsp::driver::driver_manager() - .early_print_device_drivers() - .iter() - { - // Any encountered errors cannot be printed yet, obviously, so just safely park the CPU. - i.init().unwrap_or_else(|_| cpu::wait_forever()); + // Instantiate and init all device drivers. + if let Err(x) = bsp::driver::driver_manager().instantiate_drivers() { + panic!("Error instantiating drivers: {}", x); } - bsp::driver::driver_manager().post_early_print_device_driver_init(); - // Printing available from here on. - - // Now bring up the remaining drivers. - for i in bsp::driver::driver_manager() - .non_early_print_device_drivers() - .iter() - { + for i in bsp::driver::driver_manager().all_device_drivers().iter() { if let Err(x) = i.init() { panic!("Error loading driver: {}: {}", i.compatible(), x); } @@ -62,6 +47,8 @@ unsafe fn kernel_init() -> ! { } } + bsp::memory::mmu::kernel_add_mapping_records_for_precomputed(); + // Unmask interrupts on the boot CPU core. exception::asynchronous::local_irq_unmask(); @@ -75,7 +62,6 @@ unsafe fn kernel_init() -> ! { /// The main function running after the early init. fn kernel_main() -> ! { use driver::interface::DriverManager; - use exception::asynchronous::interface::IRQManager; info!("{}", libkernel::version()); info!("Booting on: {}", bsp::board_name()); @@ -104,7 +90,7 @@ fn kernel_main() -> ! { } info!("Registered IRQ handlers:"); - bsp::exception::asynchronous::irq_manager().print_handler(); + exception::asynchronous::irq_manager().print_handler(); info!("Echoing input now"); cpu::wait_forever(); diff --git a/17_kernel_symbols/kernel/src/memory.rs b/17_kernel_symbols/kernel/src/memory.rs index f20719bb..64d8cf64 100644 --- a/17_kernel_symbols/kernel/src/memory.rs +++ b/17_kernel_symbols/kernel/src/memory.rs @@ -18,18 +18,18 @@ use core::{ //-------------------------------------------------------------------------------------------------- /// Metadata trait for marking the type of an address. -pub trait AddressType: Copy + Clone + PartialOrd + PartialEq {} +pub trait AddressType: Copy + Clone + PartialOrd + PartialEq + Ord + Eq {} /// Zero-sized type to mark a physical address. -#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)] +#[derive(Copy, Clone, Debug, PartialOrd, PartialEq, Ord, Eq)] pub enum Physical {} /// Zero-sized type to mark a virtual address. -#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)] +#[derive(Copy, Clone, Debug, PartialOrd, PartialEq, Ord, Eq)] pub enum Virtual {} /// Generic address type. -#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)] +#[derive(Copy, Clone, Debug, PartialOrd, PartialEq, Ord, Eq)] pub struct Address { value: usize, _address_type: PhantomData ATYPE>, diff --git a/17_kernel_symbols/kernel/src/memory/mmu/mapping_record.rs b/17_kernel_symbols/kernel/src/memory/mmu/mapping_record.rs index d171c6e6..7d3a6c60 100644 --- a/17_kernel_symbols/kernel/src/memory/mmu/mapping_record.rs +++ b/17_kernel_symbols/kernel/src/memory/mmu/mapping_record.rs @@ -76,6 +76,19 @@ impl MappingRecord { Self { inner: [None; 12] } } + fn size(&self) -> usize { + self.inner.iter().filter(|x| x.is_some()).count() + } + + fn sort(&mut self) { + let upper_bound_exclusive = self.size(); + let entries = &mut self.inner[0..upper_bound_exclusive]; + + if !entries.is_sorted_by_key(|item| item.unwrap().virt_start_addr) { + entries.sort_unstable_by_key(|item| item.unwrap().virt_start_addr) + } + } + fn find_next_free(&mut self) -> Result<&mut Option, &'static str> { if let Some(x) = self.inner.iter_mut().find(|x| x.is_none()) { return Ok(x); @@ -121,6 +134,9 @@ impl MappingRecord { phys_region, attr, )); + + self.sort(); + Ok(()) } diff --git a/17_kernel_symbols/kernel/src/panic_wait.rs b/17_kernel_symbols/kernel/src/panic_wait.rs index 08d7d453..e4256b61 100644 --- a/17_kernel_symbols/kernel/src/panic_wait.rs +++ b/17_kernel_symbols/kernel/src/panic_wait.rs @@ -4,19 +4,13 @@ //! A panic handler that infinitely waits. -use crate::{bsp, cpu, exception}; -use core::{fmt, panic::PanicInfo}; +use crate::{cpu, exception, println}; +use core::panic::PanicInfo; //-------------------------------------------------------------------------------------------------- // Private Code //-------------------------------------------------------------------------------------------------- -fn _panic_print(args: fmt::Arguments) { - use fmt::Write; - - unsafe { bsp::console::panic_console_out().write_fmt(args).unwrap() }; -} - /// The point of exit for `libkernel`. /// /// It is linked weakly, so that the integration tests can overload its standard behavior. @@ -34,16 +28,6 @@ fn _panic_exit() -> ! { } } -/// Prints with a newline - only use from the panic handler. -/// -/// Carbon copy from -#[macro_export] -macro_rules! panic_println { - ($($arg:tt)*) => ({ - _panic_print(format_args_nl!($($arg)*)); - }) -} - /// Stop immediately if called a second time. /// /// # Note @@ -88,7 +72,7 @@ fn panic(info: &PanicInfo) -> ! { _ => ("???", 0, 0), }; - panic_println!( + println!( "[ {:>3}.{:06}] Kernel panic!\n\n\ Panic location:\n File '{}', line {}, column {}\n\n\ {}", diff --git a/17_kernel_symbols/kernel/src/print.rs b/17_kernel_symbols/kernel/src/print.rs index 9ec13a28..8705eec0 100644 --- a/17_kernel_symbols/kernel/src/print.rs +++ b/17_kernel_symbols/kernel/src/print.rs @@ -4,7 +4,7 @@ //! Printing. -use crate::{bsp, console}; +use crate::console; use core::fmt; //-------------------------------------------------------------------------------------------------- @@ -13,9 +13,7 @@ use core::fmt; #[doc(hidden)] pub fn _print(args: fmt::Arguments) { - use console::interface::Write; - - bsp::console::console().write_fmt(args).unwrap(); + console::console().write_fmt(args).unwrap(); } /// Prints without a newline. diff --git a/17_kernel_symbols/kernel/tests/00_console_sanity.rs b/17_kernel_symbols/kernel/tests/00_console_sanity.rs index 6595aac1..f2a1f3ed 100644 --- a/17_kernel_symbols/kernel/tests/00_console_sanity.rs +++ b/17_kernel_symbols/kernel/tests/00_console_sanity.rs @@ -11,16 +11,16 @@ /// Console tests should time out on the I/O harness in case of panic. mod panic_wait_forever; -use libkernel::{bsp, console, cpu, exception, memory, print}; +use libkernel::{bsp, console, cpu, driver, exception, memory, print}; #[no_mangle] unsafe fn kernel_init() -> ! { - use bsp::console::console; - use console::interface::*; + use console::console; + use driver::interface::DriverManager; exception::handling_init(); memory::mmu::post_enable_init(); - bsp::console::qemu_bring_up_console(); + bsp::driver::driver_manager().qemu_bring_up_console(); // Handshake assert_eq!(console().read_char(), 'A'); diff --git a/17_kernel_symbols/kernel/tests/01_timer_sanity.rs b/17_kernel_symbols/kernel/tests/01_timer_sanity.rs index 9b2b228d..caeca3cd 100644 --- a/17_kernel_symbols/kernel/tests/01_timer_sanity.rs +++ b/17_kernel_symbols/kernel/tests/01_timer_sanity.rs @@ -11,14 +11,16 @@ #![test_runner(libkernel::test_runner)] use core::time::Duration; -use libkernel::{bsp, cpu, exception, memory, time, time::interface::TimeManager}; +use libkernel::{bsp, cpu, driver, exception, memory, time, time::interface::TimeManager}; use test_macros::kernel_test; #[no_mangle] unsafe fn kernel_init() -> ! { + use driver::interface::DriverManager; + exception::handling_init(); memory::mmu::post_enable_init(); - bsp::console::qemu_bring_up_console(); + bsp::driver::driver_manager().qemu_bring_up_console(); // Depending on CPU arch, some timer bring-up code could go here. Not needed for the RPi. diff --git a/17_kernel_symbols/kernel/tests/02_exception_sync_page_fault.rs b/17_kernel_symbols/kernel/tests/02_exception_sync_page_fault.rs index 0d2a1e63..33463e0a 100644 --- a/17_kernel_symbols/kernel/tests/02_exception_sync_page_fault.rs +++ b/17_kernel_symbols/kernel/tests/02_exception_sync_page_fault.rs @@ -17,13 +17,15 @@ /// or indirectly. mod panic_exit_success; -use libkernel::{bsp, cpu, exception, info, memory, println}; +use libkernel::{bsp, cpu, driver, exception, info, memory, println}; #[no_mangle] unsafe fn kernel_init() -> ! { + use driver::interface::DriverManager; + exception::handling_init(); memory::mmu::post_enable_init(); - bsp::console::qemu_bring_up_console(); + bsp::driver::driver_manager().qemu_bring_up_console(); // This line will be printed as the test header. println!("Testing synchronous exception handling by causing a page fault"); diff --git a/17_kernel_symbols/kernel/tests/03_exception_restore_sanity.rs b/17_kernel_symbols/kernel/tests/03_exception_restore_sanity.rs index 983d488f..a521a871 100644 --- a/17_kernel_symbols/kernel/tests/03_exception_restore_sanity.rs +++ b/17_kernel_symbols/kernel/tests/03_exception_restore_sanity.rs @@ -12,7 +12,7 @@ mod panic_wait_forever; use core::arch::asm; -use libkernel::{bsp, cpu, exception, info, memory, println}; +use libkernel::{bsp, cpu, driver, exception, info, memory, println}; #[inline(never)] fn nested_system_call() { @@ -30,9 +30,11 @@ fn nested_system_call() { #[no_mangle] unsafe fn kernel_init() -> ! { + use driver::interface::DriverManager; + exception::handling_init(); memory::mmu::post_enable_init(); - bsp::console::qemu_bring_up_console(); + bsp::driver::driver_manager().qemu_bring_up_console(); // This line will be printed as the test header. println!("Testing exception restore"); diff --git a/17_kernel_symbols/kernel/tests/04_exception_irq_sanity.rs b/17_kernel_symbols/kernel/tests/04_exception_irq_sanity.rs index 9030424d..cd2d29d6 100644 --- a/17_kernel_symbols/kernel/tests/04_exception_irq_sanity.rs +++ b/17_kernel_symbols/kernel/tests/04_exception_irq_sanity.rs @@ -10,13 +10,15 @@ #![reexport_test_harness_main = "test_main"] #![test_runner(libkernel::test_runner)] -use libkernel::{bsp, cpu, exception, memory}; +use libkernel::{bsp, cpu, driver, exception, memory}; use test_macros::kernel_test; #[no_mangle] unsafe fn kernel_init() -> ! { + use driver::interface::DriverManager; + memory::mmu::post_enable_init(); - bsp::console::qemu_bring_up_console(); + bsp::driver::driver_manager().qemu_bring_up_console(); exception::handling_init(); exception::asynchronous::local_irq_unmask(); diff --git a/18_backtrace/Makefile b/18_backtrace/Makefile index 85826c12..5d660332 100644 --- a/18_backtrace/Makefile +++ b/18_backtrace/Makefile @@ -217,7 +217,7 @@ $(KERNEL_BIN): $(KERNEL_ELF_TTABLES_SYMS) ##------------------------------------------------------------------------------ ## Generate the documentation ##------------------------------------------------------------------------------ -doc: +doc: clean $(call color_header, "Generating docs") @$(DOC_CMD) --document-private-items --open diff --git a/18_backtrace/README.md b/18_backtrace/README.md index c3cc1cc8..fd173703 100644 --- a/18_backtrace/README.md +++ b/18_backtrace/README.md @@ -228,7 +228,7 @@ match backtrace_res { Finally, we add printing of a backtrace to `panic!`: ```rust -panic_println!( +println!( "[ {:>3}.{:06}] Kernel panic!\n\n\ Panic location:\n File '{}', line {}, column {}\n\n\ {}\n\n\ @@ -909,7 +909,7 @@ diff -uNr 17_kernel_symbols/kernel/src/bsp/raspberrypi/memory/mmu.rs 18_backtrac diff -uNr 17_kernel_symbols/kernel/src/lib.rs 18_backtrace/kernel/src/lib.rs --- 17_kernel_symbols/kernel/src/lib.rs +++ 18_backtrace/kernel/src/lib.rs -@@ -128,6 +128,7 @@ +@@ -129,6 +129,7 @@ mod panic_wait; mod synchronization; @@ -967,20 +967,20 @@ diff -uNr 17_kernel_symbols/kernel/src/panic_wait.rs 18_backtrace/kernel/src/pan //! A panic handler that infinitely waits. --use crate::{bsp, cpu, exception}; -+use crate::{backtrace, bsp, cpu, exception}; - use core::{fmt, panic::PanicInfo}; +-use crate::{cpu, exception, println}; ++use crate::{backtrace, cpu, exception, println}; + use core::panic::PanicInfo; //-------------------------------------------------------------------------------------------------- -@@ -91,6 +91,7 @@ - panic_println!( +@@ -75,6 +75,7 @@ + println!( "[ {:>3}.{:06}] Kernel panic!\n\n\ Panic location:\n File '{}', line {}, column {}\n\n\ + {}\n\n\ {}", timestamp.as_secs(), timestamp.subsec_micros(), -@@ -98,6 +99,7 @@ +@@ -82,6 +83,7 @@ line, column, info.message().unwrap_or(&format_args!("")), @@ -1036,7 +1036,7 @@ diff -uNr 17_kernel_symbols/kernel/tests/05_backtrace_sanity.rb 18_backtrace/ker diff -uNr 17_kernel_symbols/kernel/tests/05_backtrace_sanity.rs 18_backtrace/kernel/tests/05_backtrace_sanity.rs --- 17_kernel_symbols/kernel/tests/05_backtrace_sanity.rs +++ 18_backtrace/kernel/tests/05_backtrace_sanity.rs -@@ -0,0 +1,31 @@ +@@ -0,0 +1,33 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2022 Andre Richter @@ -1050,7 +1050,7 @@ diff -uNr 17_kernel_symbols/kernel/tests/05_backtrace_sanity.rs 18_backtrace/ker +/// Console tests should time out on the I/O harness in case of panic. +mod panic_wait_forever; + -+use libkernel::{bsp, cpu, exception, memory}; ++use libkernel::{bsp, cpu, driver, exception, memory}; + +#[inline(never)] +fn nested() { @@ -1059,9 +1059,11 @@ diff -uNr 17_kernel_symbols/kernel/tests/05_backtrace_sanity.rs 18_backtrace/ker + +#[no_mangle] +unsafe fn kernel_init() -> ! { ++ use driver::interface::DriverManager; ++ + exception::handling_init(); + memory::mmu::post_enable_init(); -+ bsp::console::qemu_bring_up_console(); ++ bsp::driver::driver_manager().qemu_bring_up_console(); + + nested(); + @@ -1103,7 +1105,7 @@ diff -uNr 17_kernel_symbols/kernel/tests/06_backtrace_invalid_frame.rb 18_backtr diff -uNr 17_kernel_symbols/kernel/tests/06_backtrace_invalid_frame.rs 18_backtrace/kernel/tests/06_backtrace_invalid_frame.rs --- 17_kernel_symbols/kernel/tests/06_backtrace_invalid_frame.rs +++ 18_backtrace/kernel/tests/06_backtrace_invalid_frame.rs -@@ -0,0 +1,33 @@ +@@ -0,0 +1,35 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2022 Andre Richter @@ -1117,7 +1119,7 @@ diff -uNr 17_kernel_symbols/kernel/tests/06_backtrace_invalid_frame.rs 18_backtr +/// Console tests should time out on the I/O harness in case of panic. +mod panic_wait_forever; + -+use libkernel::{backtrace, bsp, cpu, exception, memory}; ++use libkernel::{backtrace, bsp, cpu, driver, exception, memory}; + +#[inline(never)] +fn nested() { @@ -1128,9 +1130,11 @@ diff -uNr 17_kernel_symbols/kernel/tests/06_backtrace_invalid_frame.rs 18_backtr + +#[no_mangle] +unsafe fn kernel_init() -> ! { ++ use driver::interface::DriverManager; ++ + exception::handling_init(); + memory::mmu::post_enable_init(); -+ bsp::console::qemu_bring_up_console(); ++ bsp::driver::driver_manager().qemu_bring_up_console(); + + nested(); + @@ -1171,7 +1175,7 @@ diff -uNr 17_kernel_symbols/kernel/tests/07_backtrace_invalid_link.rb 18_backtra diff -uNr 17_kernel_symbols/kernel/tests/07_backtrace_invalid_link.rs 18_backtrace/kernel/tests/07_backtrace_invalid_link.rs --- 17_kernel_symbols/kernel/tests/07_backtrace_invalid_link.rs +++ 18_backtrace/kernel/tests/07_backtrace_invalid_link.rs -@@ -0,0 +1,38 @@ +@@ -0,0 +1,40 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2022 Andre Richter @@ -1185,7 +1189,7 @@ diff -uNr 17_kernel_symbols/kernel/tests/07_backtrace_invalid_link.rs 18_backtra +/// Console tests should time out on the I/O harness in case of panic. +mod panic_wait_forever; + -+use libkernel::{backtrace, bsp, cpu, exception, memory}; ++use libkernel::{backtrace, bsp, cpu, driver, exception, memory}; + +#[inline(never)] +fn nested_2() -> &'static str { @@ -1201,9 +1205,11 @@ diff -uNr 17_kernel_symbols/kernel/tests/07_backtrace_invalid_link.rs 18_backtra + +#[no_mangle] +unsafe fn kernel_init() -> ! { ++ use driver::interface::DriverManager; ++ + exception::handling_init(); + memory::mmu::post_enable_init(); -+ bsp::console::qemu_bring_up_console(); ++ bsp::driver::driver_manager().qemu_bring_up_console(); + + nested_1(); + diff --git a/18_backtrace/kernel/src/_arch/aarch64/exception.rs b/18_backtrace/kernel/src/_arch/aarch64/exception.rs index 30090644..17ec3009 100644 --- a/18_backtrace/kernel/src/_arch/aarch64/exception.rs +++ b/18_backtrace/kernel/src/_arch/aarch64/exception.rs @@ -11,7 +11,7 @@ //! //! crate::exception::arch_exception -use crate::{bsp, exception, memory, symbols}; +use crate::{exception, memory, symbols}; use core::{arch::global_asm, cell::UnsafeCell, fmt}; use cortex_a::{asm::barrier, registers::*}; use tock_registers::{ @@ -108,10 +108,8 @@ unsafe extern "C" fn current_elx_synchronous(e: &mut ExceptionContext) { #[no_mangle] unsafe extern "C" fn current_elx_irq(_e: &mut ExceptionContext) { - use exception::asynchronous::interface::IRQManager; - let token = &exception::asynchronous::IRQContext::new(); - bsp::exception::asynchronous::irq_manager().handle_pending_irqs(token); + exception::asynchronous::irq_manager().handle_pending_irqs(token); } #[no_mangle] diff --git a/18_backtrace/kernel/src/bsp/device_driver/arm/gicv2.rs b/18_backtrace/kernel/src/bsp/device_driver/arm/gicv2.rs index 4c68a692..e72fde7b 100644 --- a/18_backtrace/kernel/src/bsp/device_driver/arm/gicv2.rs +++ b/18_backtrace/kernel/src/bsp/device_driver/arm/gicv2.rs @@ -79,8 +79,12 @@ mod gicc; mod gicd; -use crate::{bsp, cpu, driver, exception, memory, synchronization, synchronization::InitStateLock}; -use core::sync::atomic::{AtomicBool, Ordering}; +use crate::{ + bsp, cpu, driver, exception, + memory::{Address, Virtual}, + synchronization, + synchronization::InitStateLock, +}; //-------------------------------------------------------------------------------------------------- // Private Definitions @@ -97,20 +101,17 @@ pub type IRQNumber = exception::asynchronous::IRQNumber<{ GICv2::MAX_IRQ_NUMBER /// Representation of the GIC. pub struct GICv2 { - gicd_mmio_descriptor: memory::mmu::MMIODescriptor, - gicc_mmio_descriptor: memory::mmu::MMIODescriptor, - /// The Distributor. gicd: gicd::GICD, /// The CPU Interface. gicc: gicc::GICC, - /// Have the MMIO regions been remapped yet? - is_mmio_remapped: AtomicBool, - /// Stores registered IRQ handlers. Writable only during kernel init. RO afterwards. handler_table: InitStateLock, + + /// Callback to be invoked after successful init. + post_init_callback: fn(), } //-------------------------------------------------------------------------------------------------- @@ -121,22 +122,23 @@ impl GICv2 { const MAX_IRQ_NUMBER: usize = 300; // Normally 1019, but keep it lower to save some space. const NUM_IRQS: usize = Self::MAX_IRQ_NUMBER + 1; + pub const COMPATIBLE: &'static str = "GICv2 (ARM Generic Interrupt Controller v2)"; + /// Create an instance. /// /// # Safety /// - /// - The user must ensure to provide correct MMIO descriptors. + /// - The user must ensure to provide a correct MMIO start address. pub const unsafe fn new( - gicd_mmio_descriptor: memory::mmu::MMIODescriptor, - gicc_mmio_descriptor: memory::mmu::MMIODescriptor, + gicd_mmio_start_addr: Address, + gicc_mmio_start_addr: Address, + post_init_callback: fn(), ) -> Self { Self { - gicd_mmio_descriptor, - gicc_mmio_descriptor, - gicd: gicd::GICD::new(gicd_mmio_descriptor.start_addr().as_usize()), - gicc: gicc::GICC::new(gicc_mmio_descriptor.start_addr().as_usize()), - is_mmio_remapped: AtomicBool::new(false), + gicd: gicd::GICD::new(gicd_mmio_start_addr), + gicc: gicc::GICC::new(gicc_mmio_start_addr), handler_table: InitStateLock::new([None; Self::NUM_IRQS]), + post_init_callback, } } } @@ -148,24 +150,10 @@ use synchronization::interface::ReadWriteEx; impl driver::interface::DeviceDriver for GICv2 { fn compatible(&self) -> &'static str { - "GICv2 (ARM Generic Interrupt Controller v2)" + Self::COMPATIBLE } unsafe fn init(&self) -> Result<(), &'static str> { - let remapped = self.is_mmio_remapped.load(Ordering::Relaxed); - if !remapped { - // GICD - let mut virt_addr = memory::mmu::kernel_map_mmio("GICD", &self.gicd_mmio_descriptor)?; - self.gicd.set_mmio(virt_addr.as_usize()); - - // GICC - virt_addr = memory::mmu::kernel_map_mmio("GICC", &self.gicc_mmio_descriptor)?; - self.gicc.set_mmio(virt_addr.as_usize()); - - // Conclude remapping. - self.is_mmio_remapped.store(true, Ordering::Relaxed); - } - if bsp::cpu::BOOT_CORE_ID == cpu::smp::core_id() { self.gicd.boot_core_init(); } @@ -173,6 +161,8 @@ impl driver::interface::DeviceDriver for GICv2 { self.gicc.priority_accept_all(); self.gicc.enable(); + (self.post_init_callback)(); + Ok(()) } } diff --git a/18_backtrace/kernel/src/bsp/device_driver/arm/gicv2/gicc.rs b/18_backtrace/kernel/src/bsp/device_driver/arm/gicv2/gicc.rs index 1a151d24..1a02fc65 100644 --- a/18_backtrace/kernel/src/bsp/device_driver/arm/gicv2/gicc.rs +++ b/18_backtrace/kernel/src/bsp/device_driver/arm/gicv2/gicc.rs @@ -5,7 +5,9 @@ //! GICC Driver - GIC CPU interface. use crate::{ - bsp::device_driver::common::MMIODerefWrapper, exception, synchronization::InitStateLock, + bsp::device_driver::common::MMIODerefWrapper, + exception, + memory::{Address, Virtual}, }; use tock_registers::{ interfaces::{Readable, Writeable}, @@ -62,13 +64,12 @@ type Registers = MMIODerefWrapper; /// Representation of the GIC CPU interface. pub struct GICC { - registers: InitStateLock, + registers: Registers, } //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- -use crate::synchronization::interface::ReadWriteEx; impl GICC { /// Create an instance. @@ -76,17 +77,12 @@ impl GICC { /// # Safety /// /// - The user must ensure to provide a correct MMIO start address. - pub const unsafe fn new(mmio_start_addr: usize) -> Self { + pub const unsafe fn new(mmio_start_addr: Address) -> Self { Self { - registers: InitStateLock::new(Registers::new(mmio_start_addr)), + registers: Registers::new(mmio_start_addr), } } - pub unsafe fn set_mmio(&self, new_mmio_start_addr: usize) { - self.registers - .write(|regs| *regs = Registers::new(new_mmio_start_addr)); - } - /// Accept interrupts of any priority. /// /// Quoting the GICv2 Architecture Specification: @@ -99,9 +95,7 @@ impl GICC { /// - GICC MMIO registers are banked per CPU core. It is therefore safe to have `&self` instead /// of `&mut self`. pub fn priority_accept_all(&self) { - self.registers.read(|regs| { - regs.PMR.write(PMR::Priority.val(255)); // Comment in arch spec. - }); + self.registers.PMR.write(PMR::Priority.val(255)); // Comment in arch spec. } /// Enable the interface - start accepting IRQs. @@ -111,9 +105,7 @@ impl GICC { /// - GICC MMIO registers are banked per CPU core. It is therefore safe to have `&self` instead /// of `&mut self`. pub fn enable(&self) { - self.registers.read(|regs| { - regs.CTLR.write(CTLR::Enable::SET); - }); + self.registers.CTLR.write(CTLR::Enable::SET); } /// Extract the number of the highest-priority pending IRQ. @@ -129,8 +121,7 @@ impl GICC { &self, _ic: &exception::asynchronous::IRQContext<'irq_context>, ) -> usize { - self.registers - .read(|regs| regs.IAR.read(IAR::InterruptID) as usize) + self.registers.IAR.read(IAR::InterruptID) as usize } /// Complete handling of the currently active IRQ. @@ -149,8 +140,6 @@ impl GICC { irq_number: u32, _ic: &exception::asynchronous::IRQContext<'irq_context>, ) { - self.registers.read(|regs| { - regs.EOIR.write(EOIR::EOIINTID.val(irq_number)); - }); + self.registers.EOIR.write(EOIR::EOIINTID.val(irq_number)); } } diff --git a/18_backtrace/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs b/18_backtrace/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs index 60bbc468..d9f63d1b 100644 --- a/18_backtrace/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs +++ b/18_backtrace/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs @@ -9,8 +9,9 @@ use crate::{ bsp::device_driver::common::MMIODerefWrapper, + memory::{Address, Virtual}, state, synchronization, - synchronization::{IRQSafeNullLock, InitStateLock}, + synchronization::IRQSafeNullLock, }; use tock_registers::{ interfaces::{Readable, Writeable}, @@ -84,7 +85,7 @@ pub struct GICD { shared_registers: IRQSafeNullLock, /// Access to banked registers is unguarded. - banked_registers: InitStateLock, + banked_registers: BankedRegisters, } //-------------------------------------------------------------------------------------------------- @@ -121,7 +122,6 @@ impl SharedRegisters { //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- -use crate::synchronization::interface::ReadWriteEx; use synchronization::interface::Mutex; impl GICD { @@ -130,20 +130,13 @@ impl GICD { /// # Safety /// /// - The user must ensure to provide a correct MMIO start address. - pub const unsafe fn new(mmio_start_addr: usize) -> Self { + pub const unsafe fn new(mmio_start_addr: Address) -> Self { Self { shared_registers: IRQSafeNullLock::new(SharedRegisters::new(mmio_start_addr)), - banked_registers: InitStateLock::new(BankedRegisters::new(mmio_start_addr)), + banked_registers: BankedRegisters::new(mmio_start_addr), } } - pub unsafe fn set_mmio(&self, new_mmio_start_addr: usize) { - self.shared_registers - .lock(|regs| *regs = SharedRegisters::new(new_mmio_start_addr)); - self.banked_registers - .write(|regs| *regs = BankedRegisters::new(new_mmio_start_addr)); - } - /// Use a banked ITARGETSR to retrieve the executing core's GIC target mask. /// /// Quoting the GICv2 Architecture Specification: @@ -151,8 +144,7 @@ impl GICD { /// "GICD_ITARGETSR0 to GICD_ITARGETSR7 are read-only, and each field returns a value that /// corresponds only to the processor reading the register." fn local_gic_target_mask(&self) -> u32 { - self.banked_registers - .read(|regs| regs.ITARGETSR[0].read(ITARGETSR::Offset0)) + self.banked_registers.ITARGETSR[0].read(ITARGETSR::Offset0) } /// Route all SPIs to the boot core and enable the distributor. @@ -191,10 +183,10 @@ impl GICD { // Check if we are handling a private or shared IRQ. match irq_num { // Private. - 0..=31 => self.banked_registers.read(|regs| { - let enable_reg = ®s.ISENABLER; + 0..=31 => { + let enable_reg = &self.banked_registers.ISENABLER; enable_reg.set(enable_reg.get() | enable_bit); - }), + } // Shared. _ => { let enable_reg_index_shared = enable_reg_index - 1; diff --git a/18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs b/18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs index eea07b75..a3361c2c 100644 --- a/18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs +++ b/18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs @@ -5,10 +5,12 @@ //! GPIO Driver. use crate::{ - bsp::device_driver::common::MMIODerefWrapper, driver, memory, synchronization, + bsp::device_driver::common::MMIODerefWrapper, + driver, + memory::{Address, Virtual}, + synchronization, synchronization::IRQSafeNullLock, }; -use core::sync::atomic::{AtomicUsize, Ordering}; use tock_registers::{ interfaces::{ReadWriteable, Writeable}, register_bitfields, register_structs, @@ -109,26 +111,22 @@ register_structs! { /// Abstraction for the associated MMIO registers. type Registers = MMIODerefWrapper; -//-------------------------------------------------------------------------------------------------- -// Public Definitions -//-------------------------------------------------------------------------------------------------- - -pub struct GPIOInner { +struct GPIOInner { registers: Registers, } -// Export the inner struct so that BSPs can use it for the panic handler. -pub use GPIOInner as PanicGPIO; +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- /// Representation of the GPIO HW. pub struct GPIO { - mmio_descriptor: memory::mmu::MMIODescriptor, - virt_mmio_start_addr: AtomicUsize, inner: IRQSafeNullLock, + post_init_callback: fn(), } //-------------------------------------------------------------------------------------------------- -// Public Code +// Private Code //-------------------------------------------------------------------------------------------------- impl GPIOInner { @@ -137,25 +135,12 @@ impl GPIOInner { /// # Safety /// /// - The user must ensure to provide a correct MMIO start address. - pub const unsafe fn new(mmio_start_addr: usize) -> Self { + pub const unsafe fn new(mmio_start_addr: Address) -> Self { Self { registers: Registers::new(mmio_start_addr), } } - /// Init code. - /// - /// # Safety - /// - /// - The user must ensure to provide a correct MMIO start address. - pub unsafe fn init(&mut self, new_mmio_start_addr: Option) -> Result<(), &'static str> { - if let Some(addr) = new_mmio_start_addr { - self.registers = Registers::new(addr); - } - - Ok(()) - } - /// Disable pull-up/down on pins 14 and 15. #[cfg(feature = "bsp_rpi3")] fn disable_pud_14_15_bcm2837(&mut self) { @@ -205,17 +190,22 @@ impl GPIOInner { } } +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + impl GPIO { + pub const COMPATIBLE: &'static str = "BCM GPIO"; + /// Create an instance. /// /// # Safety /// - /// - The user must ensure to provide correct MMIO descriptors. - pub const unsafe fn new(mmio_descriptor: memory::mmu::MMIODescriptor) -> Self { + /// - The user must ensure to provide a correct MMIO start address. + pub const unsafe fn new(mmio_start_addr: Address, post_init_callback: fn()) -> Self { Self { - mmio_descriptor, - virt_mmio_start_addr: AtomicUsize::new(0), - inner: IRQSafeNullLock::new(GPIOInner::new(mmio_descriptor.start_addr().as_usize())), + inner: IRQSafeNullLock::new(GPIOInner::new(mmio_start_addr)), + post_init_callback, } } @@ -232,28 +222,12 @@ use synchronization::interface::Mutex; impl driver::interface::DeviceDriver for GPIO { fn compatible(&self) -> &'static str { - "BCM GPIO" + Self::COMPATIBLE } unsafe fn init(&self) -> Result<(), &'static str> { - let virt_addr = memory::mmu::kernel_map_mmio(self.compatible(), &self.mmio_descriptor)?; - - self.inner - .lock(|inner| inner.init(Some(virt_addr.as_usize())))?; - - self.virt_mmio_start_addr - .store(virt_addr.as_usize(), Ordering::Relaxed); + (self.post_init_callback)(); Ok(()) } - - fn virt_mmio_start_addr(&self) -> Option { - let addr = self.virt_mmio_start_addr.load(Ordering::Relaxed); - - if addr == 0 { - return None; - } - - Some(addr) - } } diff --git a/18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs b/18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs index 99961fac..4908b8b6 100644 --- a/18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs +++ b/18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs @@ -6,7 +6,10 @@ mod peripheral_ic; -use crate::{driver, exception, memory}; +use crate::{ + driver, exception, + memory::{Address, Virtual}, +}; //-------------------------------------------------------------------------------------------------- // Private Definitions @@ -28,6 +31,7 @@ pub type PeripheralIRQ = /// Used for the associated type of trait [`exception::asynchronous::interface::IRQManager`]. #[derive(Copy, Clone)] +#[allow(missing_docs)] pub enum IRQNumber { Local(LocalIRQ), Peripheral(PeripheralIRQ), @@ -36,6 +40,7 @@ pub enum IRQNumber { /// Representation of the Interrupt Controller. pub struct InterruptController { periph: peripheral_ic::PeripheralIC, + post_init_callback: fn(), } //-------------------------------------------------------------------------------------------------- @@ -74,17 +79,20 @@ impl InterruptController { const MAX_PERIPHERAL_IRQ_NUMBER: usize = 63; const NUM_PERIPHERAL_IRQS: usize = Self::MAX_PERIPHERAL_IRQ_NUMBER + 1; + pub const COMPATIBLE: &'static str = "BCM Interrupt Controller"; + /// Create an instance. /// /// # Safety /// - /// - The user must ensure to provide correct MMIO descriptors. + /// - The user must ensure to provide a correct MMIO start address. pub const unsafe fn new( - _local_mmio_descriptor: memory::mmu::MMIODescriptor, - periph_mmio_descriptor: memory::mmu::MMIODescriptor, + periph_mmio_start_addr: Address, + post_init_callback: fn(), ) -> Self { Self { - periph: peripheral_ic::PeripheralIC::new(periph_mmio_descriptor), + periph: peripheral_ic::PeripheralIC::new(periph_mmio_start_addr), + post_init_callback, } } } @@ -95,11 +103,13 @@ impl InterruptController { impl driver::interface::DeviceDriver for InterruptController { fn compatible(&self) -> &'static str { - "BCM Interrupt Controller" + Self::COMPATIBLE } unsafe fn init(&self) -> Result<(), &'static str> { - self.periph.init() + (self.post_init_callback)(); + + Ok(()) } } diff --git a/18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs b/18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs index f09da862..145d8961 100644 --- a/18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs +++ b/18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs @@ -7,7 +7,9 @@ use super::{InterruptController, PendingIRQs, PeripheralIRQ}; use crate::{ bsp::device_driver::common::MMIODerefWrapper, - driver, exception, memory, synchronization, + exception, + memory::{Address, Virtual}, + synchronization, synchronization::{IRQSafeNullLock, InitStateLock}, }; use tock_registers::{ @@ -55,13 +57,11 @@ type HandlerTable = /// Representation of the peripheral interrupt controller. pub struct PeripheralIC { - mmio_descriptor: memory::mmu::MMIODescriptor, - /// Access to write registers is guarded with a lock. wo_registers: IRQSafeNullLock, /// Register read access is unguarded. - ro_registers: InitStateLock, + ro_registers: ReadOnlyRegisters, /// Stores registered IRQ handlers. Writable only during kernel init. RO afterwards. handler_table: InitStateLock, @@ -76,26 +76,21 @@ impl PeripheralIC { /// /// # Safety /// - /// - The user must ensure to provide correct MMIO descriptors. - pub const unsafe fn new(mmio_descriptor: memory::mmu::MMIODescriptor) -> Self { - let addr = mmio_descriptor.start_addr().as_usize(); - + /// - The user must ensure to provide a correct MMIO start address. + pub const unsafe fn new(mmio_start_addr: Address) -> Self { Self { - mmio_descriptor, - wo_registers: IRQSafeNullLock::new(WriteOnlyRegisters::new(addr)), - ro_registers: InitStateLock::new(ReadOnlyRegisters::new(addr)), + wo_registers: IRQSafeNullLock::new(WriteOnlyRegisters::new(mmio_start_addr)), + ro_registers: ReadOnlyRegisters::new(mmio_start_addr), handler_table: InitStateLock::new([None; InterruptController::NUM_PERIPHERAL_IRQS]), } } /// Query the list of pending IRQs. fn pending_irqs(&self) -> PendingIRQs { - self.ro_registers.read(|regs| { - let pending_mask: u64 = - (u64::from(regs.PENDING_2.get()) << 32) | u64::from(regs.PENDING_1.get()); + let pending_mask: u64 = (u64::from(self.ro_registers.PENDING_2.get()) << 32) + | u64::from(self.ro_registers.PENDING_1.get()); - PendingIRQs::new(pending_mask) - }) + PendingIRQs::new(pending_mask) } } @@ -104,24 +99,6 @@ impl PeripheralIC { //------------------------------------------------------------------------------ use synchronization::interface::{Mutex, ReadWriteEx}; -impl driver::interface::DeviceDriver for PeripheralIC { - fn compatible(&self) -> &'static str { - "BCM Peripheral Interrupt Controller" - } - - unsafe fn init(&self) -> Result<(), &'static str> { - let virt_addr = - memory::mmu::kernel_map_mmio(self.compatible(), &self.mmio_descriptor)?.as_usize(); - - self.wo_registers - .lock(|regs| *regs = WriteOnlyRegisters::new(virt_addr)); - self.ro_registers - .write(|regs| *regs = ReadOnlyRegisters::new(virt_addr)); - - Ok(()) - } -} - impl exception::asynchronous::interface::IRQManager for PeripheralIC { type IRQNumberType = PeripheralIRQ; diff --git a/18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs b/18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs index 3133047b..f67d70df 100644 --- a/18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs +++ b/18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs @@ -10,13 +10,14 @@ //! - use crate::{ - bsp, bsp::device_driver::common::MMIODerefWrapper, console, cpu, driver, exception, memory, - synchronization, synchronization::IRQSafeNullLock, -}; -use core::{ - fmt, - sync::atomic::{AtomicUsize, Ordering}, + bsp, + bsp::device_driver::common::MMIODerefWrapper, + console, cpu, driver, exception, + memory::{Address, Virtual}, + synchronization, + synchronization::IRQSafeNullLock, }; +use core::fmt; use tock_registers::{ interfaces::{Readable, Writeable}, register_bitfields, register_structs, @@ -219,29 +220,25 @@ enum BlockingMode { NonBlocking, } -//-------------------------------------------------------------------------------------------------- -// Public Definitions -//-------------------------------------------------------------------------------------------------- - -pub struct PL011UartInner { +struct PL011UartInner { registers: Registers, chars_written: usize, chars_read: usize, } -// Export the inner struct so that BSPs can use it for the panic handler. -pub use PL011UartInner as PanicUart; +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- /// Representation of the UART. pub struct PL011Uart { - mmio_descriptor: memory::mmu::MMIODescriptor, - virt_mmio_start_addr: AtomicUsize, inner: IRQSafeNullLock, irq_number: bsp::device_driver::IRQNumber, + post_init_callback: fn(), } //-------------------------------------------------------------------------------------------------- -// Public Code +// Private Code //-------------------------------------------------------------------------------------------------- impl PL011UartInner { @@ -250,7 +247,7 @@ impl PL011UartInner { /// # Safety /// /// - The user must ensure to provide a correct MMIO start address. - pub const unsafe fn new(mmio_start_addr: usize) -> Self { + pub const unsafe fn new(mmio_start_addr: Address) -> Self { Self { registers: Registers::new(mmio_start_addr), chars_written: 0, @@ -275,15 +272,7 @@ impl PL011UartInner { /// genrated baud rate of `48_000_000 / (16 * 3.25) = 923_077`. /// /// Error = `((923_077 - 921_600) / 921_600) * 100 = 0.16%`. - /// - /// # Safety - /// - /// - The user must ensure to provide a correct MMIO start address. - pub unsafe fn init(&mut self, new_mmio_start_addr: Option) -> Result<(), &'static str> { - if let Some(addr) = new_mmio_start_addr { - self.registers = Registers::new(addr); - } - + pub fn init(&mut self) { // Execution can arrive here while there are still characters queued in the TX FIFO and // actively being sent out by the UART hardware. If the UART is turned off in this case, // those queued characters would be lost. @@ -325,8 +314,6 @@ impl PL011UartInner { self.registers .CR .write(CR::UARTEN::Enabled + CR::TXE::Enabled + CR::RXE::Enabled); - - Ok(()) } /// Send a character. @@ -399,24 +386,28 @@ impl fmt::Write for PL011UartInner { } } +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + impl PL011Uart { + pub const COMPATIBLE: &'static str = "BCM PL011 UART"; + /// Create an instance. /// /// # Safety /// - /// - The user must ensure to provide correct MMIO descriptors. + /// - The user must ensure to provide a correct MMIO start address. /// - The user must ensure to provide correct IRQ numbers. pub const unsafe fn new( - mmio_descriptor: memory::mmu::MMIODescriptor, + mmio_start_addr: Address, irq_number: bsp::device_driver::IRQNumber, + post_init_callback: fn(), ) -> Self { Self { - mmio_descriptor, - virt_mmio_start_addr: AtomicUsize::new(0), - inner: IRQSafeNullLock::new(PL011UartInner::new( - mmio_descriptor.start_addr().as_usize(), - )), + inner: IRQSafeNullLock::new(PL011UartInner::new(mmio_start_addr)), irq_number, + post_init_callback, } } } @@ -428,27 +419,21 @@ use synchronization::interface::Mutex; impl driver::interface::DeviceDriver for PL011Uart { fn compatible(&self) -> &'static str { - "BCM PL011 UART" + Self::COMPATIBLE } unsafe fn init(&self) -> Result<(), &'static str> { - let virt_addr = memory::mmu::kernel_map_mmio(self.compatible(), &self.mmio_descriptor)?; - - self.inner - .lock(|inner| inner.init(Some(virt_addr.as_usize())))?; - - self.virt_mmio_start_addr - .store(virt_addr.as_usize(), Ordering::Relaxed); + self.inner.lock(|inner| inner.init()); + (self.post_init_callback)(); Ok(()) } fn register_and_enable_irq_handler(&'static self) -> Result<(), &'static str> { - use bsp::exception::asynchronous::irq_manager; - use exception::asynchronous::{interface::IRQManager, IRQDescriptor}; + use exception::asynchronous::{irq_manager, IRQDescriptor}; let descriptor = IRQDescriptor { - name: "BCM PL011 UART", + name: Self::COMPATIBLE, handler: self, }; @@ -457,16 +442,6 @@ impl driver::interface::DeviceDriver for PL011Uart { Ok(()) } - - fn virt_mmio_start_addr(&self) -> Option { - let addr = self.virt_mmio_start_addr.load(Ordering::Relaxed); - - if addr == 0 { - return None; - } - - Some(addr) - } } impl console::interface::Write for PL011Uart { @@ -514,6 +489,8 @@ impl console::interface::Statistics for PL011Uart { } } +impl console::interface::All for PL011Uart {} + impl exception::asynchronous::interface::IRQHandler for PL011Uart { fn handle(&self) -> Result<(), &'static str> { self.inner.lock(|inner| { diff --git a/18_backtrace/kernel/src/bsp/device_driver/common.rs b/18_backtrace/kernel/src/bsp/device_driver/common.rs index fd9e988e..69f038d4 100644 --- a/18_backtrace/kernel/src/bsp/device_driver/common.rs +++ b/18_backtrace/kernel/src/bsp/device_driver/common.rs @@ -4,6 +4,7 @@ //! Common device driver code. +use crate::memory::{Address, Virtual}; use core::{marker::PhantomData, ops}; //-------------------------------------------------------------------------------------------------- @@ -11,7 +12,7 @@ use core::{marker::PhantomData, ops}; //-------------------------------------------------------------------------------------------------- pub struct MMIODerefWrapper { - start_addr: usize, + start_addr: Address, phantom: PhantomData T>, } @@ -21,7 +22,7 @@ pub struct MMIODerefWrapper { impl MMIODerefWrapper { /// Create an instance. - pub const unsafe fn new(start_addr: usize) -> Self { + pub const unsafe fn new(start_addr: Address) -> Self { Self { start_addr, phantom: PhantomData, @@ -33,6 +34,6 @@ impl ops::Deref for MMIODerefWrapper { type Target = T; fn deref(&self) -> &Self::Target { - unsafe { &*(self.start_addr as *const _) } + unsafe { &*(self.start_addr.as_usize() as *const _) } } } diff --git a/18_backtrace/kernel/src/bsp/raspberrypi.rs b/18_backtrace/kernel/src/bsp/raspberrypi.rs index fb9edf88..474419f4 100644 --- a/18_backtrace/kernel/src/bsp/raspberrypi.rs +++ b/18_backtrace/kernel/src/bsp/raspberrypi.rs @@ -4,46 +4,11 @@ //! Top-level BSP file for the Raspberry Pi 3 and 4. -pub mod console; pub mod cpu; pub mod driver; pub mod exception; pub mod memory; -use super::device_driver; -use crate::memory::mmu::MMIODescriptor; -use memory::map::mmio; - -//-------------------------------------------------------------------------------------------------- -// Global instances -//-------------------------------------------------------------------------------------------------- - -static GPIO: device_driver::GPIO = - unsafe { device_driver::GPIO::new(MMIODescriptor::new(mmio::GPIO_START, mmio::GPIO_SIZE)) }; - -static PL011_UART: device_driver::PL011Uart = unsafe { - device_driver::PL011Uart::new( - MMIODescriptor::new(mmio::PL011_UART_START, mmio::PL011_UART_SIZE), - exception::asynchronous::irq_map::PL011_UART, - ) -}; - -#[cfg(feature = "bsp_rpi3")] -static INTERRUPT_CONTROLLER: device_driver::InterruptController = unsafe { - device_driver::InterruptController::new( - MMIODescriptor::new(mmio::LOCAL_IC_START, mmio::LOCAL_IC_SIZE), - MMIODescriptor::new(mmio::PERIPHERAL_IC_START, mmio::PERIPHERAL_IC_SIZE), - ) -}; - -#[cfg(feature = "bsp_rpi4")] -static INTERRUPT_CONTROLLER: device_driver::GICv2 = unsafe { - device_driver::GICv2::new( - MMIODescriptor::new(mmio::GICD_START, mmio::GICD_SIZE), - MMIODescriptor::new(mmio::GICC_START, mmio::GICC_SIZE), - ) -}; - //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- diff --git a/18_backtrace/kernel/src/bsp/raspberrypi/console.rs b/18_backtrace/kernel/src/bsp/raspberrypi/console.rs deleted file mode 100644 index a0d2e687..00000000 --- a/18_backtrace/kernel/src/bsp/raspberrypi/console.rs +++ /dev/null @@ -1,98 +0,0 @@ -// SPDX-License-Identifier: MIT OR Apache-2.0 -// -// Copyright (c) 2018-2022 Andre Richter - -//! BSP console facilities. - -use crate::{bsp::device_driver, console, cpu, driver}; -use core::fmt; - -//-------------------------------------------------------------------------------------------------- -// Public Code -//-------------------------------------------------------------------------------------------------- - -/// In case of a panic, the panic handler uses this function to take a last shot at printing -/// something before the system is halted. -/// -/// We try to init panic-versions of the GPIO and the UART. The panic versions are not protected -/// with synchronization primitives, which increases chances that we get to print something, even -/// when the kernel's default GPIO or UART instances happen to be locked at the time of the panic. -/// -/// # Safety -/// -/// - Use only for printing during a panic. -#[cfg(not(feature = "test_build"))] -pub unsafe fn panic_console_out() -> impl fmt::Write { - use driver::interface::DeviceDriver; - - // If remapping of the driver's MMIO hasn't already happened, we won't be able to print. Just - // park the CPU core in this case. - let gpio_mmio_start_addr = match super::GPIO.virt_mmio_start_addr() { - None => cpu::wait_forever(), - Some(x) => x, - }; - - let uart_mmio_start_addr = match super::PL011_UART.virt_mmio_start_addr() { - None => cpu::wait_forever(), - Some(x) => x, - }; - - let mut panic_gpio = device_driver::PanicGPIO::new(gpio_mmio_start_addr); - let mut panic_uart = device_driver::PanicUart::new(uart_mmio_start_addr); - - panic_gpio - .init(None) - .unwrap_or_else(|_| cpu::wait_forever()); - panic_gpio.map_pl011_uart(); - panic_uart - .init(None) - .unwrap_or_else(|_| cpu::wait_forever()); - - panic_uart -} - -/// Reduced version for test builds. -/// -/// # Safety -/// -/// - Use only for printing during a panic. -#[cfg(feature = "test_build")] -pub unsafe fn panic_console_out() -> impl fmt::Write { - use driver::interface::DeviceDriver; - - let uart_mmio_start_addr = match super::PL011_UART.virt_mmio_start_addr() { - None => cpu::wait_forever(), - Some(x) => x, - }; - let mut panic_uart = device_driver::PanicUart::new(uart_mmio_start_addr); - - panic_uart - .init(None) - .unwrap_or_else(|_| cpu::qemu_exit_failure()); - - panic_uart -} - -/// Return a reference to the console. -pub fn console() -> &'static impl console::interface::All { - &super::PL011_UART -} - -//-------------------------------------------------------------------------------------------------- -// Testing -//-------------------------------------------------------------------------------------------------- - -/// Minimal code needed to bring up the console in QEMU (for testing only). This is often less steps -/// than on real hardware due to QEMU's abstractions. -#[cfg(feature = "test_build")] -pub fn qemu_bring_up_console() { - use driver::interface::DeviceDriver; - - // Calling the UART's init ensures that the BSP's instance of the UART does remap the MMIO - // addresses. - unsafe { - super::PL011_UART - .init() - .unwrap_or_else(|_| cpu::qemu_exit_failure()); - } -} diff --git a/18_backtrace/kernel/src/bsp/raspberrypi/driver.rs b/18_backtrace/kernel/src/bsp/raspberrypi/driver.rs index 53168752..e1db4a00 100644 --- a/18_backtrace/kernel/src/bsp/raspberrypi/driver.rs +++ b/18_backtrace/kernel/src/bsp/raspberrypi/driver.rs @@ -4,7 +4,19 @@ //! BSP driver support. -use crate::driver; +use super::{exception, memory::map::mmio}; +use crate::{ + bsp::device_driver, + console, driver, exception as generic_exception, memory, + memory::mmu::MMIODescriptor, + synchronization::{interface::ReadWriteEx, InitStateLock}, +}; +use core::{ + mem::MaybeUninit, + sync::atomic::{AtomicBool, Ordering}, +}; + +pub use device_driver::IRQNumber; //-------------------------------------------------------------------------------------------------- // Private Definitions @@ -12,21 +24,132 @@ use crate::driver; /// Device Driver Manager type. struct BSPDriverManager { - device_drivers: [&'static (dyn DeviceDriver + Sync); 3], + device_drivers: InitStateLock<[Option<&'static (dyn DeviceDriver + Sync)>; NUM_DRIVERS]>, + init_done: AtomicBool, } +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +/// The number of active drivers provided by this BSP. +pub const NUM_DRIVERS: usize = 3; + //-------------------------------------------------------------------------------------------------- // Global instances //-------------------------------------------------------------------------------------------------- +static mut PL011_UART: MaybeUninit = MaybeUninit::uninit(); +static mut GPIO: MaybeUninit = MaybeUninit::uninit(); + +#[cfg(feature = "bsp_rpi3")] +static mut INTERRUPT_CONTROLLER: MaybeUninit = + MaybeUninit::uninit(); + +#[cfg(feature = "bsp_rpi4")] +static mut INTERRUPT_CONTROLLER: MaybeUninit = MaybeUninit::uninit(); + static BSP_DRIVER_MANAGER: BSPDriverManager = BSPDriverManager { - device_drivers: [ - &super::GPIO, - &super::PL011_UART, - &super::INTERRUPT_CONTROLLER, - ], + device_drivers: InitStateLock::new([None; NUM_DRIVERS]), + init_done: AtomicBool::new(false), }; +//-------------------------------------------------------------------------------------------------- +// Private Code +//-------------------------------------------------------------------------------------------------- + +impl BSPDriverManager { + unsafe fn instantiate_uart(&self) -> Result<(), &'static str> { + let mmio_descriptor = MMIODescriptor::new(mmio::PL011_UART_START, mmio::PL011_UART_SIZE); + let virt_addr = + memory::mmu::kernel_map_mmio(device_driver::PL011Uart::COMPATIBLE, &mmio_descriptor)?; + + // This is safe to do, because it is only called from the init'ed instance itself. + fn uart_post_init() { + console::register_console(unsafe { PL011_UART.assume_init_ref() }); + } + + PL011_UART.write(device_driver::PL011Uart::new( + virt_addr, + exception::asynchronous::irq_map::PL011_UART, + uart_post_init, + )); + + Ok(()) + } + + unsafe fn instantiate_gpio(&self) -> Result<(), &'static str> { + let mmio_descriptor = MMIODescriptor::new(mmio::GPIO_START, mmio::GPIO_SIZE); + let virt_addr = + memory::mmu::kernel_map_mmio(device_driver::GPIO::COMPATIBLE, &mmio_descriptor)?; + + // This is safe to do, because it is only called from the init'ed instance itself. + fn gpio_post_init() { + unsafe { GPIO.assume_init_ref().map_pl011_uart() }; + } + + GPIO.write(device_driver::GPIO::new(virt_addr, gpio_post_init)); + + Ok(()) + } + + #[cfg(feature = "bsp_rpi3")] + unsafe fn instantiate_interrupt_controller(&self) -> Result<(), &'static str> { + let periph_mmio_descriptor = + MMIODescriptor::new(mmio::PERIPHERAL_IC_START, mmio::PERIPHERAL_IC_SIZE); + let periph_virt_addr = memory::mmu::kernel_map_mmio( + device_driver::InterruptController::COMPATIBLE, + &periph_mmio_descriptor, + )?; + + // This is safe to do, because it is only called from the init'ed instance itself. + fn interrupt_controller_post_init() { + generic_exception::asynchronous::register_irq_manager(unsafe { + INTERRUPT_CONTROLLER.assume_init_ref() + }); + } + + INTERRUPT_CONTROLLER.write(device_driver::InterruptController::new( + periph_virt_addr, + interrupt_controller_post_init, + )); + + Ok(()) + } + + #[cfg(feature = "bsp_rpi4")] + unsafe fn instantiate_interrupt_controller(&self) -> Result<(), &'static str> { + let gicd_mmio_descriptor = MMIODescriptor::new(mmio::GICD_START, mmio::GICD_SIZE); + let gicd_virt_addr = memory::mmu::kernel_map_mmio("GICv2 GICD", &gicd_mmio_descriptor)?; + + let gicc_mmio_descriptor = MMIODescriptor::new(mmio::GICC_START, mmio::GICC_SIZE); + let gicc_virt_addr = memory::mmu::kernel_map_mmio("GICV2 GICC", &gicc_mmio_descriptor)?; + + // This is safe to do, because it is only called from the init'ed instance itself. + fn interrupt_controller_post_init() { + generic_exception::asynchronous::register_irq_manager(unsafe { + INTERRUPT_CONTROLLER.assume_init_ref() + }); + } + + INTERRUPT_CONTROLLER.write(device_driver::GICv2::new( + gicd_virt_addr, + gicc_virt_addr, + interrupt_controller_post_init, + )); + + Ok(()) + } + + unsafe fn register_drivers(&self) { + self.device_drivers.write(|drivers| { + drivers[0] = Some(PL011_UART.assume_init_ref()); + drivers[1] = Some(GPIO.assume_init_ref()); + drivers[2] = Some(INTERRUPT_CONTROLLER.assume_init_ref()); + }); + } +} + //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- @@ -42,20 +165,34 @@ pub fn driver_manager() -> &'static impl driver::interface::DriverManager { use driver::interface::DeviceDriver; impl driver::interface::DriverManager for BSPDriverManager { - fn all_device_drivers(&self) -> &[&'static (dyn DeviceDriver + Sync)] { - &self.device_drivers[..] - } + unsafe fn instantiate_drivers(&self) -> Result<(), &'static str> { + if self.init_done.load(Ordering::Relaxed) { + return Err("Drivers already instantiated"); + } + + self.instantiate_uart()?; + self.instantiate_gpio()?; + self.instantiate_interrupt_controller()?; - fn early_print_device_drivers(&self) -> &[&'static (dyn DeviceDriver + Sync)] { - &self.device_drivers[0..=1] + self.register_drivers(); + + self.init_done.store(true, Ordering::Relaxed); + Ok(()) } - fn non_early_print_device_drivers(&self) -> &[&'static (dyn DeviceDriver + Sync)] { - &self.device_drivers[2..] + fn all_device_drivers(&self) -> [&(dyn DeviceDriver + Sync); NUM_DRIVERS] { + self.device_drivers + .read(|drivers| drivers.map(|drivers| drivers.unwrap())) } - fn post_early_print_device_driver_init(&self) { - // Configure PL011Uart's output pins. - super::GPIO.map_pl011_uart(); + #[cfg(feature = "test_build")] + fn qemu_bring_up_console(&self) { + use crate::cpu; + + unsafe { + self.instantiate_uart() + .unwrap_or_else(|_| cpu::qemu_exit_failure()); + console::register_console(PL011_UART.assume_init_ref()); + }; } } diff --git a/18_backtrace/kernel/src/bsp/raspberrypi/exception/asynchronous.rs b/18_backtrace/kernel/src/bsp/raspberrypi/exception/asynchronous.rs index dc5ab421..ab20d86d 100644 --- a/18_backtrace/kernel/src/bsp/raspberrypi/exception/asynchronous.rs +++ b/18_backtrace/kernel/src/bsp/raspberrypi/exception/asynchronous.rs @@ -4,7 +4,7 @@ //! BSP asynchronous exception handling. -use crate::{bsp, exception}; +use crate::bsp; //-------------------------------------------------------------------------------------------------- // Public Definitions @@ -23,14 +23,3 @@ pub(in crate::bsp) mod irq_map { pub const PL011_UART: IRQNumber = IRQNumber::new(153); } - -//-------------------------------------------------------------------------------------------------- -// Public Code -//-------------------------------------------------------------------------------------------------- - -/// Return a reference to the IRQ manager. -pub fn irq_manager() -> &'static impl exception::asynchronous::interface::IRQManager< - IRQNumberType = bsp::device_driver::IRQNumber, -> { - &super::super::INTERRUPT_CONTROLLER -} diff --git a/18_backtrace/kernel/src/bsp/raspberrypi/memory.rs b/18_backtrace/kernel/src/bsp/raspberrypi/memory.rs index 01aa9441..32416e6c 100644 --- a/18_backtrace/kernel/src/bsp/raspberrypi/memory.rs +++ b/18_backtrace/kernel/src/bsp/raspberrypi/memory.rs @@ -113,9 +113,6 @@ pub(super) mod map { pub const PL011_UART_START: Address = Address::new(0x3F20_1000); pub const PL011_UART_SIZE: usize = 0x48; - pub const LOCAL_IC_START: Address = Address::new(0x4000_0000); - pub const LOCAL_IC_SIZE: usize = 0x100; - pub const END: Address = Address::new(0x4001_0000); } diff --git a/18_backtrace/kernel/src/console.rs b/18_backtrace/kernel/src/console.rs index e49e241f..a85bcffe 100644 --- a/18_backtrace/kernel/src/console.rs +++ b/18_backtrace/kernel/src/console.rs @@ -4,6 +4,10 @@ //! System console. +mod null_console; + +use crate::synchronization; + //-------------------------------------------------------------------------------------------------- // Public Definitions //-------------------------------------------------------------------------------------------------- @@ -49,5 +53,29 @@ pub mod interface { } /// Trait alias for a full-fledged console. - pub trait All = Write + Read + Statistics; + pub trait All: Write + Read + Statistics {} +} + +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +static CUR_CONSOLE: InitStateLock<&'static (dyn interface::All + Sync)> = + InitStateLock::new(&null_console::NULL_CONSOLE); + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- +use synchronization::{interface::ReadWriteEx, InitStateLock}; + +/// Register a new console. +pub fn register_console(new_console: &'static (dyn interface::All + Sync)) { + CUR_CONSOLE.write(|con| *con = new_console); +} + +/// Return a reference to the currently registered console. +/// +/// This is the global console used by all printing macros. +pub fn console() -> &'static dyn interface::All { + CUR_CONSOLE.read(|con| *con) } diff --git a/18_backtrace/kernel/src/console/null_console.rs b/18_backtrace/kernel/src/console/null_console.rs new file mode 100644 index 00000000..10c3bedc --- /dev/null +++ b/18_backtrace/kernel/src/console/null_console.rs @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2022 Andre Richter + +//! Null console. + +use super::interface; +use core::fmt; + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +pub struct NullConsole; + +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +pub static NULL_CONSOLE: NullConsole = NullConsole {}; + +//-------------------------------------------------------------------------------------------------- +// Private Code +//-------------------------------------------------------------------------------------------------- + +impl interface::Write for NullConsole { + fn write_char(&self, _c: char) {} + + fn write_fmt(&self, _args: fmt::Arguments) -> fmt::Result { + fmt::Result::Ok(()) + } + + fn flush(&self) {} +} + +impl interface::Read for NullConsole { + fn clear_rx(&self) {} +} + +impl interface::Statistics for NullConsole {} +impl interface::All for NullConsole {} diff --git a/18_backtrace/kernel/src/driver.rs b/18_backtrace/kernel/src/driver.rs index 7b800dbc..98197fef 100644 --- a/18_backtrace/kernel/src/driver.rs +++ b/18_backtrace/kernel/src/driver.rs @@ -10,6 +10,8 @@ /// Driver interfaces. pub mod interface { + use crate::bsp; + /// Device Driver functions. pub trait DeviceDriver { /// Return a compatibility string for identifying the driver. @@ -31,32 +33,25 @@ pub mod interface { fn register_and_enable_irq_handler(&'static self) -> Result<(), &'static str> { Ok(()) } - - /// After MMIO remapping, returns the new virtual start address. - /// - /// This API assumes a driver has only a single, contiguous MMIO aperture, which will not be - /// the case for more complex devices. This API will likely change in future tutorials. - fn virt_mmio_start_addr(&self) -> Option { - None - } } /// Device driver management functions. /// /// The `BSP` is supposed to supply one global instance. pub trait DriverManager { - /// Return a slice of references to all `BSP`-instantiated drivers. - fn all_device_drivers(&self) -> &[&'static (dyn DeviceDriver + Sync)]; - - /// Return only those drivers needed for the BSP's early printing functionality. + /// Instantiate all drivers. + /// + /// # Safety /// - /// For example, the default UART. - fn early_print_device_drivers(&self) -> &[&'static (dyn DeviceDriver + Sync)]; + /// Must be called before `all_device_drivers`. + unsafe fn instantiate_drivers(&self) -> Result<(), &'static str>; - /// Return all drivers minus early-print drivers. - fn non_early_print_device_drivers(&self) -> &[&'static (dyn DeviceDriver + Sync)]; + /// Return a slice of references to all `BSP`-instantiated drivers. + fn all_device_drivers(&self) -> [&(dyn DeviceDriver + Sync); bsp::driver::NUM_DRIVERS]; - /// Initialization code that runs after the early print driver init. - fn post_early_print_device_driver_init(&self); + /// Minimal code needed to bring up the console in QEMU (for testing only). This is often + /// less steps than on real hardware due to QEMU's abstractions. + #[cfg(feature = "test_build")] + fn qemu_bring_up_console(&self); } } diff --git a/18_backtrace/kernel/src/exception/asynchronous.rs b/18_backtrace/kernel/src/exception/asynchronous.rs index fb1785c2..d9d2767c 100644 --- a/18_backtrace/kernel/src/exception/asynchronous.rs +++ b/18_backtrace/kernel/src/exception/asynchronous.rs @@ -7,7 +7,9 @@ #[cfg(target_arch = "aarch64")] #[path = "../_arch/aarch64/exception/asynchronous.rs"] mod arch_asynchronous; +mod null_irq_manager; +use crate::{bsp, synchronization}; use core::{fmt, marker::PhantomData}; //-------------------------------------------------------------------------------------------------- @@ -85,7 +87,7 @@ pub mod interface { ); /// Print list of registered handlers. - fn print_handler(&self); + fn print_handler(&self) {} } } @@ -93,9 +95,18 @@ pub mod interface { #[derive(Copy, Clone)] pub struct IRQNumber(usize); +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +static CUR_IRQ_MANAGER: InitStateLock< + &'static (dyn interface::IRQManager + Sync), +> = InitStateLock::new(&null_irq_manager::NULL_IRQ_MANAGER); + //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- +use synchronization::{interface::ReadWriteEx, InitStateLock}; impl<'irq_context> IRQContext<'irq_context> { /// Creates an IRQContext token. @@ -150,3 +161,18 @@ pub fn exec_with_irq_masked(f: impl FnOnce() -> T) -> T { ret } + +/// Register a new IRQ manager. +pub fn register_irq_manager( + new_manager: &'static (dyn interface::IRQManager + + Sync), +) { + CUR_IRQ_MANAGER.write(|manager| *manager = new_manager); +} + +/// Return a reference to the currently registered IRQ manager. +/// +/// This is the IRQ manager used by the architectural interrupt handling code. +pub fn irq_manager() -> &'static dyn interface::IRQManager { + CUR_IRQ_MANAGER.read(|manager| *manager) +} diff --git a/18_backtrace/kernel/src/exception/asynchronous/null_irq_manager.rs b/18_backtrace/kernel/src/exception/asynchronous/null_irq_manager.rs new file mode 100644 index 00000000..560e3ce4 --- /dev/null +++ b/18_backtrace/kernel/src/exception/asynchronous/null_irq_manager.rs @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2022 Andre Richter + +//! Null IRQ Manager. + +use super::{interface, IRQContext, IRQDescriptor}; +use crate::bsp; + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +pub struct NullIRQManager; + +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +pub static NULL_IRQ_MANAGER: NullIRQManager = NullIRQManager {}; + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +impl interface::IRQManager for NullIRQManager { + type IRQNumberType = bsp::driver::IRQNumber; + + fn register_handler( + &self, + _irq_number: Self::IRQNumberType, + _descriptor: IRQDescriptor, + ) -> Result<(), &'static str> { + panic!("No IRQ Manager registered yet"); + } + + fn enable(&self, _irq_number: Self::IRQNumberType) { + panic!("No IRQ Manager registered yet"); + } + + fn handle_pending_irqs<'irq_context>(&'irq_context self, _ic: &IRQContext<'irq_context>) { + panic!("No IRQ Manager registered yet"); + } +} diff --git a/18_backtrace/kernel/src/lib.rs b/18_backtrace/kernel/src/lib.rs index 4d7a5f5d..688fc1a4 100644 --- a/18_backtrace/kernel/src/lib.rs +++ b/18_backtrace/kernel/src/lib.rs @@ -114,6 +114,7 @@ #![feature(core_intrinsics)] #![feature(format_args_nl)] #![feature(generic_const_exprs)] +#![feature(is_sorted)] #![feature(linkage)] #![feature(panic_info_message)] #![feature(step_trait)] @@ -178,9 +179,11 @@ pub fn test_runner(tests: &[&test_types::UnitTest]) { #[cfg(test)] #[no_mangle] unsafe fn kernel_init() -> ! { + use driver::interface::DriverManager; + exception::handling_init(); memory::mmu::post_enable_init(); - bsp::console::qemu_bring_up_console(); + bsp::driver::driver_manager().qemu_bring_up_console(); test_main(); diff --git a/18_backtrace/kernel/src/main.rs b/18_backtrace/kernel/src/main.rs index 5150f3af..928f12c2 100644 --- a/18_backtrace/kernel/src/main.rs +++ b/18_backtrace/kernel/src/main.rs @@ -30,26 +30,11 @@ unsafe fn kernel_init() -> ! { exception::handling_init(); memory::mmu::post_enable_init(); - // Add the mapping records for the precomputed entries first, so that they appear on the top of - // the list. - bsp::memory::mmu::kernel_add_mapping_records_for_precomputed(); - - // Bring up the drivers needed for printing first. - for i in bsp::driver::driver_manager() - .early_print_device_drivers() - .iter() - { - // Any encountered errors cannot be printed yet, obviously, so just safely park the CPU. - i.init().unwrap_or_else(|_| cpu::wait_forever()); + // Instantiate and init all device drivers. + if let Err(x) = bsp::driver::driver_manager().instantiate_drivers() { + panic!("Error instantiating drivers: {}", x); } - bsp::driver::driver_manager().post_early_print_device_driver_init(); - // Printing available from here on. - - // Now bring up the remaining drivers. - for i in bsp::driver::driver_manager() - .non_early_print_device_drivers() - .iter() - { + for i in bsp::driver::driver_manager().all_device_drivers().iter() { if let Err(x) = i.init() { panic!("Error loading driver: {}: {}", i.compatible(), x); } @@ -62,6 +47,8 @@ unsafe fn kernel_init() -> ! { } } + bsp::memory::mmu::kernel_add_mapping_records_for_precomputed(); + // Unmask interrupts on the boot CPU core. exception::asynchronous::local_irq_unmask(); @@ -75,7 +62,6 @@ unsafe fn kernel_init() -> ! { /// The main function running after the early init. fn kernel_main() -> ! { use driver::interface::DriverManager; - use exception::asynchronous::interface::IRQManager; info!("{}", libkernel::version()); info!("Booting on: {}", bsp::board_name()); @@ -104,7 +90,7 @@ fn kernel_main() -> ! { } info!("Registered IRQ handlers:"); - bsp::exception::asynchronous::irq_manager().print_handler(); + exception::asynchronous::irq_manager().print_handler(); info!("Echoing input now"); cpu::wait_forever(); diff --git a/18_backtrace/kernel/src/memory.rs b/18_backtrace/kernel/src/memory.rs index 5e8cdbce..34c34429 100644 --- a/18_backtrace/kernel/src/memory.rs +++ b/18_backtrace/kernel/src/memory.rs @@ -18,18 +18,18 @@ use core::{ //-------------------------------------------------------------------------------------------------- /// Metadata trait for marking the type of an address. -pub trait AddressType: Copy + Clone + PartialOrd + PartialEq {} +pub trait AddressType: Copy + Clone + PartialOrd + PartialEq + Ord + Eq {} /// Zero-sized type to mark a physical address. -#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)] +#[derive(Copy, Clone, Debug, PartialOrd, PartialEq, Ord, Eq)] pub enum Physical {} /// Zero-sized type to mark a virtual address. -#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)] +#[derive(Copy, Clone, Debug, PartialOrd, PartialEq, Ord, Eq)] pub enum Virtual {} /// Generic address type. -#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)] +#[derive(Copy, Clone, Debug, PartialOrd, PartialEq, Ord, Eq)] pub struct Address { value: usize, _address_type: PhantomData ATYPE>, diff --git a/18_backtrace/kernel/src/memory/mmu/mapping_record.rs b/18_backtrace/kernel/src/memory/mmu/mapping_record.rs index d171c6e6..7d3a6c60 100644 --- a/18_backtrace/kernel/src/memory/mmu/mapping_record.rs +++ b/18_backtrace/kernel/src/memory/mmu/mapping_record.rs @@ -76,6 +76,19 @@ impl MappingRecord { Self { inner: [None; 12] } } + fn size(&self) -> usize { + self.inner.iter().filter(|x| x.is_some()).count() + } + + fn sort(&mut self) { + let upper_bound_exclusive = self.size(); + let entries = &mut self.inner[0..upper_bound_exclusive]; + + if !entries.is_sorted_by_key(|item| item.unwrap().virt_start_addr) { + entries.sort_unstable_by_key(|item| item.unwrap().virt_start_addr) + } + } + fn find_next_free(&mut self) -> Result<&mut Option, &'static str> { if let Some(x) = self.inner.iter_mut().find(|x| x.is_none()) { return Ok(x); @@ -121,6 +134,9 @@ impl MappingRecord { phys_region, attr, )); + + self.sort(); + Ok(()) } diff --git a/18_backtrace/kernel/src/panic_wait.rs b/18_backtrace/kernel/src/panic_wait.rs index 1b67c533..c8e86fbd 100644 --- a/18_backtrace/kernel/src/panic_wait.rs +++ b/18_backtrace/kernel/src/panic_wait.rs @@ -4,19 +4,13 @@ //! A panic handler that infinitely waits. -use crate::{backtrace, bsp, cpu, exception}; -use core::{fmt, panic::PanicInfo}; +use crate::{backtrace, cpu, exception, println}; +use core::panic::PanicInfo; //-------------------------------------------------------------------------------------------------- // Private Code //-------------------------------------------------------------------------------------------------- -fn _panic_print(args: fmt::Arguments) { - use fmt::Write; - - unsafe { bsp::console::panic_console_out().write_fmt(args).unwrap() }; -} - /// The point of exit for `libkernel`. /// /// It is linked weakly, so that the integration tests can overload its standard behavior. @@ -34,16 +28,6 @@ fn _panic_exit() -> ! { } } -/// Prints with a newline - only use from the panic handler. -/// -/// Carbon copy from -#[macro_export] -macro_rules! panic_println { - ($($arg:tt)*) => ({ - _panic_print(format_args_nl!($($arg)*)); - }) -} - /// Stop immediately if called a second time. /// /// # Note @@ -88,7 +72,7 @@ fn panic(info: &PanicInfo) -> ! { _ => ("???", 0, 0), }; - panic_println!( + println!( "[ {:>3}.{:06}] Kernel panic!\n\n\ Panic location:\n File '{}', line {}, column {}\n\n\ {}\n\n\ diff --git a/18_backtrace/kernel/src/print.rs b/18_backtrace/kernel/src/print.rs index 9ec13a28..8705eec0 100644 --- a/18_backtrace/kernel/src/print.rs +++ b/18_backtrace/kernel/src/print.rs @@ -4,7 +4,7 @@ //! Printing. -use crate::{bsp, console}; +use crate::console; use core::fmt; //-------------------------------------------------------------------------------------------------- @@ -13,9 +13,7 @@ use core::fmt; #[doc(hidden)] pub fn _print(args: fmt::Arguments) { - use console::interface::Write; - - bsp::console::console().write_fmt(args).unwrap(); + console::console().write_fmt(args).unwrap(); } /// Prints without a newline. diff --git a/18_backtrace/kernel/tests/00_console_sanity.rs b/18_backtrace/kernel/tests/00_console_sanity.rs index 6595aac1..f2a1f3ed 100644 --- a/18_backtrace/kernel/tests/00_console_sanity.rs +++ b/18_backtrace/kernel/tests/00_console_sanity.rs @@ -11,16 +11,16 @@ /// Console tests should time out on the I/O harness in case of panic. mod panic_wait_forever; -use libkernel::{bsp, console, cpu, exception, memory, print}; +use libkernel::{bsp, console, cpu, driver, exception, memory, print}; #[no_mangle] unsafe fn kernel_init() -> ! { - use bsp::console::console; - use console::interface::*; + use console::console; + use driver::interface::DriverManager; exception::handling_init(); memory::mmu::post_enable_init(); - bsp::console::qemu_bring_up_console(); + bsp::driver::driver_manager().qemu_bring_up_console(); // Handshake assert_eq!(console().read_char(), 'A'); diff --git a/18_backtrace/kernel/tests/01_timer_sanity.rs b/18_backtrace/kernel/tests/01_timer_sanity.rs index 9b2b228d..caeca3cd 100644 --- a/18_backtrace/kernel/tests/01_timer_sanity.rs +++ b/18_backtrace/kernel/tests/01_timer_sanity.rs @@ -11,14 +11,16 @@ #![test_runner(libkernel::test_runner)] use core::time::Duration; -use libkernel::{bsp, cpu, exception, memory, time, time::interface::TimeManager}; +use libkernel::{bsp, cpu, driver, exception, memory, time, time::interface::TimeManager}; use test_macros::kernel_test; #[no_mangle] unsafe fn kernel_init() -> ! { + use driver::interface::DriverManager; + exception::handling_init(); memory::mmu::post_enable_init(); - bsp::console::qemu_bring_up_console(); + bsp::driver::driver_manager().qemu_bring_up_console(); // Depending on CPU arch, some timer bring-up code could go here. Not needed for the RPi. diff --git a/18_backtrace/kernel/tests/02_exception_sync_page_fault.rs b/18_backtrace/kernel/tests/02_exception_sync_page_fault.rs index 0d2a1e63..33463e0a 100644 --- a/18_backtrace/kernel/tests/02_exception_sync_page_fault.rs +++ b/18_backtrace/kernel/tests/02_exception_sync_page_fault.rs @@ -17,13 +17,15 @@ /// or indirectly. mod panic_exit_success; -use libkernel::{bsp, cpu, exception, info, memory, println}; +use libkernel::{bsp, cpu, driver, exception, info, memory, println}; #[no_mangle] unsafe fn kernel_init() -> ! { + use driver::interface::DriverManager; + exception::handling_init(); memory::mmu::post_enable_init(); - bsp::console::qemu_bring_up_console(); + bsp::driver::driver_manager().qemu_bring_up_console(); // This line will be printed as the test header. println!("Testing synchronous exception handling by causing a page fault"); diff --git a/18_backtrace/kernel/tests/03_exception_restore_sanity.rs b/18_backtrace/kernel/tests/03_exception_restore_sanity.rs index 983d488f..a521a871 100644 --- a/18_backtrace/kernel/tests/03_exception_restore_sanity.rs +++ b/18_backtrace/kernel/tests/03_exception_restore_sanity.rs @@ -12,7 +12,7 @@ mod panic_wait_forever; use core::arch::asm; -use libkernel::{bsp, cpu, exception, info, memory, println}; +use libkernel::{bsp, cpu, driver, exception, info, memory, println}; #[inline(never)] fn nested_system_call() { @@ -30,9 +30,11 @@ fn nested_system_call() { #[no_mangle] unsafe fn kernel_init() -> ! { + use driver::interface::DriverManager; + exception::handling_init(); memory::mmu::post_enable_init(); - bsp::console::qemu_bring_up_console(); + bsp::driver::driver_manager().qemu_bring_up_console(); // This line will be printed as the test header. println!("Testing exception restore"); diff --git a/18_backtrace/kernel/tests/04_exception_irq_sanity.rs b/18_backtrace/kernel/tests/04_exception_irq_sanity.rs index 9030424d..cd2d29d6 100644 --- a/18_backtrace/kernel/tests/04_exception_irq_sanity.rs +++ b/18_backtrace/kernel/tests/04_exception_irq_sanity.rs @@ -10,13 +10,15 @@ #![reexport_test_harness_main = "test_main"] #![test_runner(libkernel::test_runner)] -use libkernel::{bsp, cpu, exception, memory}; +use libkernel::{bsp, cpu, driver, exception, memory}; use test_macros::kernel_test; #[no_mangle] unsafe fn kernel_init() -> ! { + use driver::interface::DriverManager; + memory::mmu::post_enable_init(); - bsp::console::qemu_bring_up_console(); + bsp::driver::driver_manager().qemu_bring_up_console(); exception::handling_init(); exception::asynchronous::local_irq_unmask(); diff --git a/18_backtrace/kernel/tests/05_backtrace_sanity.rs b/18_backtrace/kernel/tests/05_backtrace_sanity.rs index 24229f95..4475fafd 100644 --- a/18_backtrace/kernel/tests/05_backtrace_sanity.rs +++ b/18_backtrace/kernel/tests/05_backtrace_sanity.rs @@ -11,7 +11,7 @@ /// Console tests should time out on the I/O harness in case of panic. mod panic_wait_forever; -use libkernel::{bsp, cpu, exception, memory}; +use libkernel::{bsp, cpu, driver, exception, memory}; #[inline(never)] fn nested() { @@ -20,9 +20,11 @@ fn nested() { #[no_mangle] unsafe fn kernel_init() -> ! { + use driver::interface::DriverManager; + exception::handling_init(); memory::mmu::post_enable_init(); - bsp::console::qemu_bring_up_console(); + bsp::driver::driver_manager().qemu_bring_up_console(); nested(); diff --git a/18_backtrace/kernel/tests/06_backtrace_invalid_frame.rs b/18_backtrace/kernel/tests/06_backtrace_invalid_frame.rs index a1874c4e..74dad8d8 100644 --- a/18_backtrace/kernel/tests/06_backtrace_invalid_frame.rs +++ b/18_backtrace/kernel/tests/06_backtrace_invalid_frame.rs @@ -11,7 +11,7 @@ /// Console tests should time out on the I/O harness in case of panic. mod panic_wait_forever; -use libkernel::{backtrace, bsp, cpu, exception, memory}; +use libkernel::{backtrace, bsp, cpu, driver, exception, memory}; #[inline(never)] fn nested() { @@ -22,9 +22,11 @@ fn nested() { #[no_mangle] unsafe fn kernel_init() -> ! { + use driver::interface::DriverManager; + exception::handling_init(); memory::mmu::post_enable_init(); - bsp::console::qemu_bring_up_console(); + bsp::driver::driver_manager().qemu_bring_up_console(); nested(); diff --git a/18_backtrace/kernel/tests/07_backtrace_invalid_link.rs b/18_backtrace/kernel/tests/07_backtrace_invalid_link.rs index a0731091..ba6c9f57 100644 --- a/18_backtrace/kernel/tests/07_backtrace_invalid_link.rs +++ b/18_backtrace/kernel/tests/07_backtrace_invalid_link.rs @@ -11,7 +11,7 @@ /// Console tests should time out on the I/O harness in case of panic. mod panic_wait_forever; -use libkernel::{backtrace, bsp, cpu, exception, memory}; +use libkernel::{backtrace, bsp, cpu, driver, exception, memory}; #[inline(never)] fn nested_2() -> &'static str { @@ -27,9 +27,11 @@ fn nested_1() { #[no_mangle] unsafe fn kernel_init() -> ! { + use driver::interface::DriverManager; + exception::handling_init(); memory::mmu::post_enable_init(); - bsp::console::qemu_bring_up_console(); + bsp::driver::driver_manager().qemu_bring_up_console(); nested_1(); diff --git a/X1_JTAG_boot/.vscode/settings.json b/X1_JTAG_boot/.vscode/settings.json index 292bf2a9..d1916456 100644 --- a/X1_JTAG_boot/.vscode/settings.json +++ b/X1_JTAG_boot/.vscode/settings.json @@ -4,7 +4,7 @@ "rust-analyzer.cargo.target": "aarch64-unknown-none-softfloat", "rust-analyzer.cargo.features": ["bsp_rpi3"], "rust-analyzer.checkOnSave.allTargets": false, - "rust-analyzer.checkOnSave.extraArgs": ["--lib", "--bins"], + "rust-analyzer.checkOnSave.extraArgs": ["--bins"], "rust-analyzer.lens.debug": false, "rust-analyzer.lens.run": false } diff --git a/X1_JTAG_boot/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs b/X1_JTAG_boot/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs index dbb4beaa..24958eb5 100644 --- a/X1_JTAG_boot/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs +++ b/X1_JTAG_boot/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs @@ -108,16 +108,13 @@ register_structs! { /// Abstraction for the associated MMIO registers. type Registers = MMIODerefWrapper; -//-------------------------------------------------------------------------------------------------- -// Public Definitions -//-------------------------------------------------------------------------------------------------- - -pub struct GPIOInner { +struct GPIOInner { registers: Registers, } -// Export the inner struct so that BSPs can use it for the panic handler. -pub use GPIOInner as PanicGPIO; +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- /// Representation of the GPIO HW. pub struct GPIO { @@ -125,7 +122,7 @@ pub struct GPIO { } //-------------------------------------------------------------------------------------------------- -// Public Code +// Private Code //-------------------------------------------------------------------------------------------------- impl GPIOInner { @@ -189,7 +186,13 @@ impl GPIOInner { } } +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + impl GPIO { + pub const COMPATIBLE: &'static str = "BCM GPIO"; + /// Create an instance. /// /// # Safety @@ -214,6 +217,6 @@ use synchronization::interface::Mutex; impl driver::interface::DeviceDriver for GPIO { fn compatible(&self) -> &'static str { - "BCM GPIO" + Self::COMPATIBLE } } diff --git a/X1_JTAG_boot/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs b/X1_JTAG_boot/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs index 85cd3154..b034e92e 100644 --- a/X1_JTAG_boot/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs +++ b/X1_JTAG_boot/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs @@ -167,18 +167,15 @@ enum BlockingMode { NonBlocking, } -//-------------------------------------------------------------------------------------------------- -// Public Definitions -//-------------------------------------------------------------------------------------------------- - -pub struct PL011UartInner { +struct PL011UartInner { registers: Registers, chars_written: usize, chars_read: usize, } -// Export the inner struct so that BSPs can use it for the panic handler. -pub use PL011UartInner as PanicUart; +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- /// Representation of the UART. pub struct PL011Uart { @@ -186,7 +183,7 @@ pub struct PL011Uart { } //-------------------------------------------------------------------------------------------------- -// Public Code +// Private Code //-------------------------------------------------------------------------------------------------- impl PL011UartInner { @@ -326,7 +323,13 @@ impl fmt::Write for PL011UartInner { } } +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + impl PL011Uart { + pub const COMPATIBLE: &'static str = "BCM PL011 UART"; + /// Create an instance. /// /// # Safety @@ -346,7 +349,7 @@ use synchronization::interface::Mutex; impl driver::interface::DeviceDriver for PL011Uart { fn compatible(&self) -> &'static str { - "BCM PL011 UART" + Self::COMPATIBLE } unsafe fn init(&self) -> Result<(), &'static str> { @@ -400,3 +403,5 @@ impl console::interface::Statistics for PL011Uart { self.inner.lock(|inner| inner.chars_read) } } + +impl console::interface::All for PL011Uart {} diff --git a/X1_JTAG_boot/src/bsp/raspberrypi.rs b/X1_JTAG_boot/src/bsp/raspberrypi.rs index f8dbc1f4..eb6be81a 100644 --- a/X1_JTAG_boot/src/bsp/raspberrypi.rs +++ b/X1_JTAG_boot/src/bsp/raspberrypi.rs @@ -8,14 +8,3 @@ pub mod console; pub mod cpu; pub mod driver; pub mod memory; - -//-------------------------------------------------------------------------------------------------- -// Global instances -//-------------------------------------------------------------------------------------------------- -use super::device_driver; - -static GPIO: device_driver::GPIO = - unsafe { device_driver::GPIO::new(memory::map::mmio::GPIO_START) }; - -static PL011_UART: device_driver::PL011Uart = - unsafe { device_driver::PL011Uart::new(memory::map::mmio::PL011_UART_START) }; diff --git a/X1_JTAG_boot/src/bsp/raspberrypi/console.rs b/X1_JTAG_boot/src/bsp/raspberrypi/console.rs index a247032f..0a630eef 100644 --- a/X1_JTAG_boot/src/bsp/raspberrypi/console.rs +++ b/X1_JTAG_boot/src/bsp/raspberrypi/console.rs @@ -4,34 +4,13 @@ //! BSP console facilities. -use super::memory; -use crate::{bsp::device_driver, console}; -use core::fmt; +use crate::console; //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- -/// In case of a panic, the panic handler uses this function to take a last shot at printing -/// something before the system is halted. -/// -/// We try to init panic-versions of the GPIO and the UART. The panic versions are not protected -/// with synchronization primitives, which increases chances that we get to print something, even -/// when the kernel's default GPIO or UART instances happen to be locked at the time of the panic. -/// -/// # Safety -/// -/// - Use only for printing during a panic. -pub unsafe fn panic_console_out() -> impl fmt::Write { - let mut panic_gpio = device_driver::PanicGPIO::new(memory::map::mmio::GPIO_START); - let mut panic_uart = device_driver::PanicUart::new(memory::map::mmio::PL011_UART_START); - - panic_gpio.map_pl011_uart(); - panic_uart.init(); - panic_uart -} - /// Return a reference to the console. -pub fn console() -> &'static impl console::interface::All { - &super::PL011_UART +pub fn console() -> &'static dyn console::interface::All { + &super::driver::PL011_UART } diff --git a/X1_JTAG_boot/src/bsp/raspberrypi/driver.rs b/X1_JTAG_boot/src/bsp/raspberrypi/driver.rs index b5538baa..8b683ed8 100644 --- a/X1_JTAG_boot/src/bsp/raspberrypi/driver.rs +++ b/X1_JTAG_boot/src/bsp/raspberrypi/driver.rs @@ -4,7 +4,8 @@ //! BSP driver support. -use crate::driver; +use super::memory::map::mmio; +use crate::{bsp::device_driver, driver}; //-------------------------------------------------------------------------------------------------- // Private Definitions @@ -19,8 +20,13 @@ struct BSPDriverManager { // Global instances //-------------------------------------------------------------------------------------------------- +pub(super) static PL011_UART: device_driver::PL011Uart = + unsafe { device_driver::PL011Uart::new(mmio::PL011_UART_START) }; + +static GPIO: device_driver::GPIO = unsafe { device_driver::GPIO::new(mmio::GPIO_START) }; + static BSP_DRIVER_MANAGER: BSPDriverManager = BSPDriverManager { - device_drivers: [&super::GPIO, &super::PL011_UART], + device_drivers: [&PL011_UART, &GPIO], }; //-------------------------------------------------------------------------------------------------- @@ -44,6 +50,6 @@ impl driver::interface::DriverManager for BSPDriverManager { fn post_device_driver_init(&self) { // Configure PL011Uart's output pins. - super::GPIO.map_pl011_uart(); + GPIO.map_pl011_uart(); } } diff --git a/X1_JTAG_boot/src/console.rs b/X1_JTAG_boot/src/console.rs index e49e241f..c1fb0e53 100644 --- a/X1_JTAG_boot/src/console.rs +++ b/X1_JTAG_boot/src/console.rs @@ -4,6 +4,8 @@ //! System console. +use crate::bsp; + //-------------------------------------------------------------------------------------------------- // Public Definitions //-------------------------------------------------------------------------------------------------- @@ -49,5 +51,16 @@ pub mod interface { } /// Trait alias for a full-fledged console. - pub trait All = Write + Read + Statistics; + pub trait All: Write + Read + Statistics {} +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +/// Return a reference to the console. +/// +/// This is the global console used by all printing macros. +pub fn console() -> &'static dyn interface::All { + bsp::console::console() } diff --git a/X1_JTAG_boot/src/panic_wait.rs b/X1_JTAG_boot/src/panic_wait.rs index f851e0d8..edd83885 100644 --- a/X1_JTAG_boot/src/panic_wait.rs +++ b/X1_JTAG_boot/src/panic_wait.rs @@ -4,29 +4,13 @@ //! A panic handler that infinitely waits. -use crate::{bsp, cpu}; -use core::{fmt, panic::PanicInfo}; +use crate::{cpu, println}; +use core::panic::PanicInfo; //-------------------------------------------------------------------------------------------------- // Private Code //-------------------------------------------------------------------------------------------------- -fn _panic_print(args: fmt::Arguments) { - use fmt::Write; - - unsafe { bsp::console::panic_console_out().write_fmt(args).unwrap() }; -} - -/// Prints with a newline - only use from the panic handler. -/// -/// Carbon copy from -#[macro_export] -macro_rules! panic_println { - ($($arg:tt)*) => ({ - _panic_print(format_args_nl!($($arg)*)); - }) -} - /// Stop immediately if called a second time. /// /// # Note @@ -69,7 +53,7 @@ fn panic(info: &PanicInfo) -> ! { _ => ("???", 0, 0), }; - panic_println!( + println!( "[ {:>3}.{:06}] Kernel panic!\n\n\ Panic location:\n File '{}', line {}, column {}\n\n\ {}", diff --git a/X1_JTAG_boot/src/print.rs b/X1_JTAG_boot/src/print.rs index 9ec13a28..8705eec0 100644 --- a/X1_JTAG_boot/src/print.rs +++ b/X1_JTAG_boot/src/print.rs @@ -4,7 +4,7 @@ //! Printing. -use crate::{bsp, console}; +use crate::console; use core::fmt; //-------------------------------------------------------------------------------------------------- @@ -13,9 +13,7 @@ use core::fmt; #[doc(hidden)] pub fn _print(args: fmt::Arguments) { - use console::interface::Write; - - bsp::console::console().write_fmt(args).unwrap(); + console::console().write_fmt(args).unwrap(); } /// Prints without a newline. From 7aa99d52c03b50c8c6137bd2e5ca0e3751157a81 Mon Sep 17 00:00:00 2001 From: Andre Richter Date: Mon, 16 May 2022 22:14:02 +0200 Subject: [PATCH 31/75] Misc fixes/streamlining --- .../README.md | 64 ++++-- .../src/common.rs | 22 ++ .../src/main.rs | 2 + .../src/memory/mmu.rs | 15 +- 11_exceptions_part1_groundwork/README.md | 8 +- 11_exceptions_part1_groundwork/src/common.rs | 22 ++ 11_exceptions_part1_groundwork/src/main.rs | 2 + .../src/memory/mmu.rs | 15 +- 12_integrated_testing/kernel/src/common.rs | 22 ++ 12_integrated_testing/kernel/src/lib.rs | 2 + .../kernel/src/memory/mmu.rs | 15 +- 13_exceptions_part2_peripheral_IRQs/README.md | 6 +- .../kernel/src/common.rs | 22 ++ .../kernel/src/lib.rs | 2 + .../kernel/src/memory/mmu.rs | 15 +- 14_virtual_mem_part2_mmio_remap/README.md | 217 +++++++----------- .../kernel/src/common.rs | 17 ++ .../kernel/src/console/null_console.rs | 2 +- .../kernel/src/lib.rs | 3 +- .../kernel/src/main.rs | 2 - .../kernel/src/memory/mmu.rs | 2 +- .../kernel/src/memory/mmu/mapping_record.rs | 16 +- .../kernel/src/memory/mmu/page_alloc.rs | 2 +- .../kernel/tests/00_console_sanity.rs | 2 - .../kernel/tests/01_timer_sanity.rs | 2 - .../tests/02_exception_sync_page_fault.rs | 2 - .../tests/03_exception_restore_sanity.rs | 2 - .../kernel/tests/04_exception_irq_sanity.rs | 2 - .../README.md | 134 ++++++----- .../kernel/src/common.rs | 17 ++ .../kernel/src/console/null_console.rs | 2 +- .../kernel/src/lib.rs | 3 +- .../kernel/src/main.rs | 2 +- .../kernel/src/memory.rs | 5 + .../kernel/src/memory/mmu.rs | 31 ++- .../kernel/src/memory/mmu/mapping_record.rs | 16 +- .../kernel/src/memory/mmu/page_alloc.rs | 2 +- .../kernel/tests/00_console_sanity.rs | 2 +- .../kernel/tests/01_timer_sanity.rs | 2 +- .../tests/02_exception_sync_page_fault.rs | 2 +- .../tests/03_exception_restore_sanity.rs | 2 +- .../kernel/tests/04_exception_irq_sanity.rs | 2 +- .../README.md | 2 +- .../kernel/src/common.rs | 17 ++ .../kernel/src/console/null_console.rs | 2 +- .../kernel/src/lib.rs | 3 +- .../kernel/src/main.rs | 2 +- .../kernel/src/memory.rs | 5 + .../kernel/src/memory/mmu.rs | 31 ++- .../kernel/src/memory/mmu/mapping_record.rs | 16 +- .../kernel/src/memory/mmu/page_alloc.rs | 2 +- .../kernel/tests/00_console_sanity.rs | 2 +- .../kernel/tests/01_timer_sanity.rs | 2 +- .../tests/02_exception_sync_page_fault.rs | 2 +- .../tests/03_exception_restore_sanity.rs | 2 +- .../kernel/tests/04_exception_irq_sanity.rs | 2 +- 17_kernel_symbols/README.md | 2 +- 17_kernel_symbols/kernel/src/common.rs | 17 ++ .../kernel/src/console/null_console.rs | 2 +- 17_kernel_symbols/kernel/src/lib.rs | 3 +- 17_kernel_symbols/kernel/src/main.rs | 2 +- 17_kernel_symbols/kernel/src/memory.rs | 5 + 17_kernel_symbols/kernel/src/memory/mmu.rs | 31 ++- .../kernel/src/memory/mmu/mapping_record.rs | 16 +- .../kernel/src/memory/mmu/page_alloc.rs | 2 +- .../kernel/tests/00_console_sanity.rs | 2 +- .../kernel/tests/01_timer_sanity.rs | 2 +- .../tests/02_exception_sync_page_fault.rs | 2 +- .../tests/03_exception_restore_sanity.rs | 2 +- .../kernel/tests/04_exception_irq_sanity.rs | 2 +- 18_backtrace/README.md | 60 ++++- 18_backtrace/kernel/src/backtrace.rs | 4 +- 18_backtrace/kernel/src/common.rs | 17 ++ .../kernel/src/console/null_console.rs | 2 +- 18_backtrace/kernel/src/lib.rs | 3 +- 18_backtrace/kernel/src/main.rs | 2 +- 18_backtrace/kernel/src/memory.rs | 5 + 18_backtrace/kernel/src/memory/mmu.rs | 31 ++- .../kernel/src/memory/mmu/mapping_record.rs | 16 +- .../kernel/src/memory/mmu/page_alloc.rs | 2 +- .../kernel/tests/00_console_sanity.rs | 2 +- 18_backtrace/kernel/tests/01_timer_sanity.rs | 2 +- .../tests/02_exception_sync_page_fault.rs | 2 +- .../tests/03_exception_restore_sanity.rs | 2 +- .../kernel/tests/04_exception_irq_sanity.rs | 2 +- .../kernel/tests/05_backtrace_sanity.rs | 2 +- .../tests/06_backtrace_invalid_frame.rs | 2 +- .../kernel/tests/07_backtrace_invalid_link.rs | 2 +- .../tools/translation_table_tool/bsp.rb | 6 +- .../tools/translation_table_tool/generic.rb | 14 +- 90 files changed, 618 insertions(+), 467 deletions(-) create mode 100644 10_virtual_mem_part1_identity_mapping/src/common.rs create mode 100644 11_exceptions_part1_groundwork/src/common.rs create mode 100644 12_integrated_testing/kernel/src/common.rs create mode 100644 13_exceptions_part2_peripheral_IRQs/kernel/src/common.rs diff --git a/10_virtual_mem_part1_identity_mapping/README.md b/10_virtual_mem_part1_identity_mapping/README.md index 04b82eca..8bfd54fa 100644 --- a/10_virtual_mem_part1_identity_mapping/README.md +++ b/10_virtual_mem_part1_identity_mapping/README.md @@ -331,7 +331,7 @@ Minipush 1.0 [ 0.811829] MMU online. Special regions: [ 0.812306] 0x00080000 - 0x0008ffff | 64 KiB | C RO PX | Kernel code and RO data [ 0.813324] 0x1fff0000 - 0x1fffffff | 64 KiB | Dev RW PXN | Remapped Device MMIO -[ 0.814310] 0x3f000000 - 0x4000ffff | 16 MiB | Dev RW PXN | Device MMIO +[ 0.814310] 0x3f000000 - 0x4000ffff | 17 MiB | Dev RW PXN | Device MMIO [ 0.815198] Current privilege level: EL1 [ 0.815675] Exception handling state: [ 0.816119] Debug: Masked @@ -1079,10 +1079,37 @@ diff -uNr 09_privilege_level/src/bsp.rs 10_virtual_mem_part1_identity_mapping/sr #[cfg(any(feature = "bsp_rpi3", feature = "bsp_rpi4"))] mod raspberrypi; +diff -uNr 09_privilege_level/src/common.rs 10_virtual_mem_part1_identity_mapping/src/common.rs +--- 09_privilege_level/src/common.rs ++++ 10_virtual_mem_part1_identity_mapping/src/common.rs +@@ -0,0 +1,22 @@ ++// SPDX-License-Identifier: MIT OR Apache-2.0 ++// ++// Copyright (c) 2020-2022 Andre Richter ++ ++//! General purpose code. ++ ++/// Convert a size into human readable format. ++pub const fn size_human_readable_ceil(size: usize) -> (usize, &'static str) { ++ const KIB: usize = 1024; ++ const MIB: usize = 1024 * 1024; ++ const GIB: usize = 1024 * 1024 * 1024; ++ ++ if (size / GIB) > 0 { ++ (size.div_ceil(GIB), "GiB") ++ } else if (size / MIB) > 0 { ++ (size.div_ceil(MIB), "MiB") ++ } else if (size / KIB) > 0 { ++ (size.div_ceil(KIB), "KiB") ++ } else { ++ (size, "Byte") ++ } ++} + diff -uNr 09_privilege_level/src/main.rs 10_virtual_mem_part1_identity_mapping/src/main.rs --- 09_privilege_level/src/main.rs +++ 10_virtual_mem_part1_identity_mapping/src/main.rs -@@ -107,7 +107,9 @@ +@@ -107,18 +107,23 @@ //! 2. Once finished with architectural setup, the arch code calls `kernel_init()`. #![allow(clippy::upper_case_acronyms)] @@ -1090,9 +1117,15 @@ diff -uNr 09_privilege_level/src/main.rs 10_virtual_mem_part1_identity_mapping/s #![feature(asm_const)] +#![feature(core_intrinsics)] #![feature(format_args_nl)] ++#![feature(int_roundings)] #![feature(panic_info_message)] #![feature(trait_alias)] -@@ -119,6 +121,7 @@ + #![no_main] + #![no_std] + + mod bsp; ++mod common; + mod console; mod cpu; mod driver; mod exception; @@ -1100,7 +1133,7 @@ diff -uNr 09_privilege_level/src/main.rs 10_virtual_mem_part1_identity_mapping/s mod panic_wait; mod print; mod synchronization; -@@ -129,9 +132,17 @@ +@@ -129,9 +134,17 @@ /// # Safety /// /// - Only a single core must be active and running this function. @@ -1119,7 +1152,7 @@ diff -uNr 09_privilege_level/src/main.rs 10_virtual_mem_part1_identity_mapping/s for i in bsp::driver::driver_manager().all_device_drivers().iter() { if let Err(x) = i.init() { -@@ -147,7 +158,7 @@ +@@ -147,7 +160,7 @@ /// The main function running after the early init. fn kernel_main() -> ! { @@ -1128,7 +1161,7 @@ diff -uNr 09_privilege_level/src/main.rs 10_virtual_mem_part1_identity_mapping/s use core::time::Duration; use driver::interface::DriverManager; use time::interface::TimeManager; -@@ -159,6 +170,9 @@ +@@ -159,6 +172,9 @@ ); info!("Booting on: {}", bsp::board_name()); @@ -1138,7 +1171,7 @@ diff -uNr 09_privilege_level/src/main.rs 10_virtual_mem_part1_identity_mapping/s let (_, privilege_level) = exception::current_privilege_level(); info!("Current privilege level: {}", privilege_level); -@@ -182,6 +196,13 @@ +@@ -182,6 +198,13 @@ info!("Timer test, spinning for 1 second"); time::time_manager().spin_for(Duration::from_secs(1)); @@ -1175,7 +1208,7 @@ diff -uNr 09_privilege_level/src/memory/mmu/translation_table.rs 10_virtual_mem_ diff -uNr 09_privilege_level/src/memory/mmu.rs 10_virtual_mem_part1_identity_mapping/src/memory/mmu.rs --- 09_privilege_level/src/memory/mmu.rs +++ 10_virtual_mem_part1_identity_mapping/src/memory/mmu.rs -@@ -0,0 +1,264 @@ +@@ -0,0 +1,253 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2020-2022 Andre Richter @@ -1198,6 +1231,7 @@ diff -uNr 09_privilege_level/src/memory/mmu.rs 10_virtual_mem_part1_identity_map + +mod translation_table; + ++use crate::common; +use core::{fmt, ops::RangeInclusive}; + +//-------------------------------------------------------------------------------------------------- @@ -1357,19 +1391,7 @@ diff -uNr 09_privilege_level/src/memory/mmu.rs 10_virtual_mem_part1_identity_map + let end = *(self.virtual_range)().end(); + let size = end - start + 1; + -+ // log2(1024). -+ const KIB_RSHIFT: u32 = 10; -+ -+ // log2(1024 * 1024). -+ const MIB_RSHIFT: u32 = 20; -+ -+ let (size, unit) = if (size >> MIB_RSHIFT) > 0 { -+ (size >> MIB_RSHIFT, "MiB") -+ } else if (size >> KIB_RSHIFT) > 0 { -+ (size >> KIB_RSHIFT, "KiB") -+ } else { -+ (size, "Byte") -+ }; ++ let (size, unit) = common::size_human_readable_ceil(size); + + let attr = match self.attribute_fields.mem_attributes { + MemAttributes::CacheableDRAM => "C", diff --git a/10_virtual_mem_part1_identity_mapping/src/common.rs b/10_virtual_mem_part1_identity_mapping/src/common.rs new file mode 100644 index 00000000..27679aea --- /dev/null +++ b/10_virtual_mem_part1_identity_mapping/src/common.rs @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2020-2022 Andre Richter + +//! General purpose code. + +/// Convert a size into human readable format. +pub const fn size_human_readable_ceil(size: usize) -> (usize, &'static str) { + const KIB: usize = 1024; + const MIB: usize = 1024 * 1024; + const GIB: usize = 1024 * 1024 * 1024; + + if (size / GIB) > 0 { + (size.div_ceil(GIB), "GiB") + } else if (size / MIB) > 0 { + (size.div_ceil(MIB), "MiB") + } else if (size / KIB) > 0 { + (size.div_ceil(KIB), "KiB") + } else { + (size, "Byte") + } +} diff --git a/10_virtual_mem_part1_identity_mapping/src/main.rs b/10_virtual_mem_part1_identity_mapping/src/main.rs index 6f92c676..40b6d13b 100644 --- a/10_virtual_mem_part1_identity_mapping/src/main.rs +++ b/10_virtual_mem_part1_identity_mapping/src/main.rs @@ -111,12 +111,14 @@ #![feature(asm_const)] #![feature(core_intrinsics)] #![feature(format_args_nl)] +#![feature(int_roundings)] #![feature(panic_info_message)] #![feature(trait_alias)] #![no_main] #![no_std] mod bsp; +mod common; mod console; mod cpu; mod driver; diff --git a/10_virtual_mem_part1_identity_mapping/src/memory/mmu.rs b/10_virtual_mem_part1_identity_mapping/src/memory/mmu.rs index 17a98274..bef4c1d1 100644 --- a/10_virtual_mem_part1_identity_mapping/src/memory/mmu.rs +++ b/10_virtual_mem_part1_identity_mapping/src/memory/mmu.rs @@ -20,6 +20,7 @@ mod arch_mmu; mod translation_table; +use crate::common; use core::{fmt, ops::RangeInclusive}; //-------------------------------------------------------------------------------------------------- @@ -179,19 +180,7 @@ impl fmt::Display for TranslationDescriptor { let end = *(self.virtual_range)().end(); let size = end - start + 1; - // log2(1024). - const KIB_RSHIFT: u32 = 10; - - // log2(1024 * 1024). - const MIB_RSHIFT: u32 = 20; - - let (size, unit) = if (size >> MIB_RSHIFT) > 0 { - (size >> MIB_RSHIFT, "MiB") - } else if (size >> KIB_RSHIFT) > 0 { - (size >> KIB_RSHIFT, "KiB") - } else { - (size, "Byte") - }; + let (size, unit) = common::size_human_readable_ceil(size); let attr = match self.attribute_fields.mem_attributes { MemAttributes::CacheableDRAM => "C", diff --git a/11_exceptions_part1_groundwork/README.md b/11_exceptions_part1_groundwork/README.md index 355ea297..d0b4b7f7 100644 --- a/11_exceptions_part1_groundwork/README.md +++ b/11_exceptions_part1_groundwork/README.md @@ -421,7 +421,7 @@ Minipush 1.0 [ 0.798530] Booting on: Raspberry Pi 3 [ 0.798985] MMU online. Special regions: [ 0.799462] 0x00080000 - 0x0008ffff | 64 KiB | C RO PX | Kernel code and RO data -[ 0.800480] 0x3f000000 - 0x4000ffff | 16 MiB | Dev RW PXN | Device MMIO +[ 0.800480] 0x3f000000 - 0x4000ffff | 17 MiB | Dev RW PXN | Device MMIO [ 0.801369] Current privilege level: EL1 [ 0.801845] Exception handling state: [ 0.802290] Debug: Masked @@ -1024,7 +1024,7 @@ diff -uNr 10_virtual_mem_part1_identity_mapping/src/exception.rs 11_exceptions_p diff -uNr 10_virtual_mem_part1_identity_mapping/src/main.rs 11_exceptions_part1_groundwork/src/main.rs --- 10_virtual_mem_part1_identity_mapping/src/main.rs +++ 11_exceptions_part1_groundwork/src/main.rs -@@ -140,6 +140,8 @@ +@@ -142,6 +142,8 @@ use driver::interface::DriverManager; use memory::mmu::interface::MMU; @@ -1033,7 +1033,7 @@ diff -uNr 10_virtual_mem_part1_identity_mapping/src/main.rs 11_exceptions_part1_ if let Err(string) = memory::mmu::mmu().enable_mmu_and_caching() { panic!("MMU: {}", string); } -@@ -158,7 +160,7 @@ +@@ -160,7 +162,7 @@ /// The main function running after the early init. fn kernel_main() -> ! { @@ -1042,7 +1042,7 @@ diff -uNr 10_virtual_mem_part1_identity_mapping/src/main.rs 11_exceptions_part1_ use core::time::Duration; use driver::interface::DriverManager; use time::interface::TimeManager; -@@ -196,13 +198,28 @@ +@@ -198,13 +200,28 @@ info!("Timer test, spinning for 1 second"); time::time_manager().spin_for(Duration::from_secs(1)); diff --git a/11_exceptions_part1_groundwork/src/common.rs b/11_exceptions_part1_groundwork/src/common.rs new file mode 100644 index 00000000..27679aea --- /dev/null +++ b/11_exceptions_part1_groundwork/src/common.rs @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2020-2022 Andre Richter + +//! General purpose code. + +/// Convert a size into human readable format. +pub const fn size_human_readable_ceil(size: usize) -> (usize, &'static str) { + const KIB: usize = 1024; + const MIB: usize = 1024 * 1024; + const GIB: usize = 1024 * 1024 * 1024; + + if (size / GIB) > 0 { + (size.div_ceil(GIB), "GiB") + } else if (size / MIB) > 0 { + (size.div_ceil(MIB), "MiB") + } else if (size / KIB) > 0 { + (size.div_ceil(KIB), "KiB") + } else { + (size, "Byte") + } +} diff --git a/11_exceptions_part1_groundwork/src/main.rs b/11_exceptions_part1_groundwork/src/main.rs index 12386153..585382a5 100644 --- a/11_exceptions_part1_groundwork/src/main.rs +++ b/11_exceptions_part1_groundwork/src/main.rs @@ -111,12 +111,14 @@ #![feature(asm_const)] #![feature(core_intrinsics)] #![feature(format_args_nl)] +#![feature(int_roundings)] #![feature(panic_info_message)] #![feature(trait_alias)] #![no_main] #![no_std] mod bsp; +mod common; mod console; mod cpu; mod driver; diff --git a/11_exceptions_part1_groundwork/src/memory/mmu.rs b/11_exceptions_part1_groundwork/src/memory/mmu.rs index 17a98274..bef4c1d1 100644 --- a/11_exceptions_part1_groundwork/src/memory/mmu.rs +++ b/11_exceptions_part1_groundwork/src/memory/mmu.rs @@ -20,6 +20,7 @@ mod arch_mmu; mod translation_table; +use crate::common; use core::{fmt, ops::RangeInclusive}; //-------------------------------------------------------------------------------------------------- @@ -179,19 +180,7 @@ impl fmt::Display for TranslationDescriptor { let end = *(self.virtual_range)().end(); let size = end - start + 1; - // log2(1024). - const KIB_RSHIFT: u32 = 10; - - // log2(1024 * 1024). - const MIB_RSHIFT: u32 = 20; - - let (size, unit) = if (size >> MIB_RSHIFT) > 0 { - (size >> MIB_RSHIFT, "MiB") - } else if (size >> KIB_RSHIFT) > 0 { - (size >> KIB_RSHIFT, "KiB") - } else { - (size, "Byte") - }; + let (size, unit) = common::size_human_readable_ceil(size); let attr = match self.attribute_fields.mem_attributes { MemAttributes::CacheableDRAM => "C", diff --git a/12_integrated_testing/kernel/src/common.rs b/12_integrated_testing/kernel/src/common.rs new file mode 100644 index 00000000..27679aea --- /dev/null +++ b/12_integrated_testing/kernel/src/common.rs @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2020-2022 Andre Richter + +//! General purpose code. + +/// Convert a size into human readable format. +pub const fn size_human_readable_ceil(size: usize) -> (usize, &'static str) { + const KIB: usize = 1024; + const MIB: usize = 1024 * 1024; + const GIB: usize = 1024 * 1024 * 1024; + + if (size / GIB) > 0 { + (size.div_ceil(GIB), "GiB") + } else if (size / MIB) > 0 { + (size.div_ceil(MIB), "MiB") + } else if (size / KIB) > 0 { + (size.div_ceil(KIB), "KiB") + } else { + (size, "Byte") + } +} diff --git a/12_integrated_testing/kernel/src/lib.rs b/12_integrated_testing/kernel/src/lib.rs index eef112f0..4a41bbfe 100644 --- a/12_integrated_testing/kernel/src/lib.rs +++ b/12_integrated_testing/kernel/src/lib.rs @@ -113,6 +113,7 @@ #![feature(asm_const)] #![feature(core_intrinsics)] #![feature(format_args_nl)] +#![feature(int_roundings)] #![feature(linkage)] #![feature(panic_info_message)] #![feature(trait_alias)] @@ -127,6 +128,7 @@ mod panic_wait; mod synchronization; pub mod bsp; +pub mod common; pub mod console; pub mod cpu; pub mod driver; diff --git a/12_integrated_testing/kernel/src/memory/mmu.rs b/12_integrated_testing/kernel/src/memory/mmu.rs index a68973e7..b313d7d4 100644 --- a/12_integrated_testing/kernel/src/memory/mmu.rs +++ b/12_integrated_testing/kernel/src/memory/mmu.rs @@ -20,6 +20,7 @@ mod arch_mmu; mod translation_table; +use crate::common; use core::{fmt, ops::RangeInclusive}; //-------------------------------------------------------------------------------------------------- @@ -178,19 +179,7 @@ impl fmt::Display for TranslationDescriptor { let end = *(self.virtual_range)().end(); let size = end - start + 1; - // log2(1024). - const KIB_RSHIFT: u32 = 10; - - // log2(1024 * 1024). - const MIB_RSHIFT: u32 = 20; - - let (size, unit) = if (size >> MIB_RSHIFT) > 0 { - (size >> MIB_RSHIFT, "MiB") - } else if (size >> KIB_RSHIFT) > 0 { - (size >> KIB_RSHIFT, "KiB") - } else { - (size, "Byte") - }; + let (size, unit) = common::size_human_readable_ceil(size); let attr = match self.attribute_fields.mem_attributes { MemAttributes::CacheableDRAM => "C", diff --git a/13_exceptions_part2_peripheral_IRQs/README.md b/13_exceptions_part2_peripheral_IRQs/README.md index bc468be8..e2e2e169 100644 --- a/13_exceptions_part2_peripheral_IRQs/README.md +++ b/13_exceptions_part2_peripheral_IRQs/README.md @@ -682,7 +682,7 @@ Minipush 1.0 [ 0.822700] Booting on: Raspberry Pi 3 [ 0.823155] MMU online. Special regions: [ 0.823632] 0x00080000 - 0x0008ffff | 64 KiB | C RO PX | Kernel code and RO data -[ 0.824650] 0x3f000000 - 0x4000ffff | 16 MiB | Dev RW PXN | Device MMIO +[ 0.824650] 0x3f000000 - 0x4000ffff | 17 MiB | Dev RW PXN | Device MMIO [ 0.825539] Current privilege level: EL1 [ 0.826015] Exception handling state: [ 0.826459] Debug: Masked @@ -726,7 +726,7 @@ Minipush 1.0 [ 0.886886] Booting on: Raspberry Pi 4 [ 0.887341] MMU online. Special regions: [ 0.887818] 0x00080000 - 0x0008ffff | 64 KiB | C RO PX | Kernel code and RO data -[ 0.888836] 0xfe000000 - 0xff84ffff | 24 MiB | Dev RW PXN | Device MMIO +[ 0.888836] 0xfe000000 - 0xff84ffff | 25 MiB | Dev RW PXN | Device MMIO [ 0.889725] Current privilege level: EL1 [ 0.890201] Exception handling state: [ 0.890645] Debug: Masked @@ -2407,7 +2407,7 @@ diff -uNr 12_integrated_testing/kernel/src/exception/asynchronous.rs 13_exceptio diff -uNr 12_integrated_testing/kernel/src/lib.rs 13_exceptions_part2_peripheral_IRQs/kernel/src/lib.rs --- 12_integrated_testing/kernel/src/lib.rs +++ 13_exceptions_part2_peripheral_IRQs/kernel/src/lib.rs -@@ -133,6 +133,7 @@ +@@ -135,6 +135,7 @@ pub mod exception; pub mod memory; pub mod print; diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/common.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/common.rs new file mode 100644 index 00000000..27679aea --- /dev/null +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/common.rs @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2020-2022 Andre Richter + +//! General purpose code. + +/// Convert a size into human readable format. +pub const fn size_human_readable_ceil(size: usize) -> (usize, &'static str) { + const KIB: usize = 1024; + const MIB: usize = 1024 * 1024; + const GIB: usize = 1024 * 1024 * 1024; + + if (size / GIB) > 0 { + (size.div_ceil(GIB), "GiB") + } else if (size / MIB) > 0 { + (size.div_ceil(MIB), "MiB") + } else if (size / KIB) > 0 { + (size.div_ceil(KIB), "KiB") + } else { + (size, "Byte") + } +} diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/lib.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/lib.rs index c4b07809..6c5bc6b3 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/lib.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/lib.rs @@ -113,6 +113,7 @@ #![feature(asm_const)] #![feature(core_intrinsics)] #![feature(format_args_nl)] +#![feature(int_roundings)] #![feature(linkage)] #![feature(panic_info_message)] #![feature(trait_alias)] @@ -127,6 +128,7 @@ mod panic_wait; mod synchronization; pub mod bsp; +pub mod common; pub mod console; pub mod cpu; pub mod driver; diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/memory/mmu.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/memory/mmu.rs index a68973e7..b313d7d4 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/memory/mmu.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/memory/mmu.rs @@ -20,6 +20,7 @@ mod arch_mmu; mod translation_table; +use crate::common; use core::{fmt, ops::RangeInclusive}; //-------------------------------------------------------------------------------------------------- @@ -178,19 +179,7 @@ impl fmt::Display for TranslationDescriptor { let end = *(self.virtual_range)().end(); let size = end - start + 1; - // log2(1024). - const KIB_RSHIFT: u32 = 10; - - // log2(1024 * 1024). - const MIB_RSHIFT: u32 = 20; - - let (size, unit) = if (size >> MIB_RSHIFT) > 0 { - (size >> MIB_RSHIFT, "MiB") - } else if (size >> KIB_RSHIFT) > 0 { - (size >> KIB_RSHIFT, "KiB") - } else { - (size, "Byte") - }; + let (size, unit) = common::size_human_readable_ceil(size); let attr = match self.attribute_fields.mem_attributes { MemAttributes::CacheableDRAM => "C", diff --git a/14_virtual_mem_part2_mmio_remap/README.md b/14_virtual_mem_part2_mmio_remap/README.md index b5caac52..be0997ac 100644 --- a/14_virtual_mem_part2_mmio_remap/README.md +++ b/14_virtual_mem_part2_mmio_remap/README.md @@ -2053,13 +2053,10 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi.rs 14_v diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/common.rs 14_virtual_mem_part2_mmio_remap/kernel/src/common.rs --- 13_exceptions_part2_peripheral_IRQs/kernel/src/common.rs +++ 14_virtual_mem_part2_mmio_remap/kernel/src/common.rs -@@ -0,0 +1,29 @@ -+// SPDX-License-Identifier: MIT OR Apache-2.0 -+// -+// Copyright (c) 2020-2022 Andre Richter -+ -+//! General purpose code. -+ +@@ -4,6 +4,30 @@ + + //! General purpose code. + +/// Check if a value is aligned to a given size. +#[inline(always)] +pub const fn is_aligned(value: usize, alignment: usize) -> bool { @@ -2083,6 +2080,10 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/common.rs 14_virtual_me + + (value + alignment - 1) & !(alignment - 1) +} ++ + /// Convert a size into human readable format. + pub const fn size_human_readable_ceil(size: usize) -> (usize, &'static str) { + const KIB: usize = 1024; diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/console/null_console.rs 14_virtual_mem_part2_mmio_remap/kernel/src/console/null_console.rs --- 13_exceptions_part2_peripheral_IRQs/kernel/src/console/null_console.rs @@ -2110,7 +2111,7 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/console/null_console.rs +pub static NULL_CONSOLE: NullConsole = NullConsole {}; + +//-------------------------------------------------------------------------------------------------- -+// Private Code ++// Public Code +//-------------------------------------------------------------------------------------------------- + +impl interface::Write for NullConsole { @@ -2323,11 +2324,12 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/exception/asynchronous. diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/lib.rs 14_virtual_mem_part2_mmio_remap/kernel/src/lib.rs --- 13_exceptions_part2_peripheral_IRQs/kernel/src/lib.rs +++ 14_virtual_mem_part2_mmio_remap/kernel/src/lib.rs -@@ -113,8 +113,11 @@ +@@ -113,9 +113,12 @@ #![feature(asm_const)] #![feature(core_intrinsics)] #![feature(format_args_nl)] +#![feature(generic_const_exprs)] + #![feature(int_roundings)] +#![feature(is_sorted)] #![feature(linkage)] #![feature(panic_info_message)] @@ -2335,15 +2337,7 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/lib.rs 14_virtual_mem_p #![feature(trait_alias)] #![no_std] // Testing -@@ -127,6 +130,7 @@ - mod synchronization; - - pub mod bsp; -+pub mod common; - pub mod console; - pub mod cpu; - pub mod driver; -@@ -181,7 +185,20 @@ +@@ -183,6 +186,17 @@ use driver::interface::DriverManager; exception::handling_init(); @@ -2356,19 +2350,16 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/lib.rs 14_virtual_mem_p + if let Err(e) = memory::mmu::enable_mmu_and_caching(phys_kernel_tables_base_addr) { + panic!("Enabling MMU failed: {}", e); + } -+ // Printing will silently fail from here on, because the driver's MMIO is not remapped yet. + + memory::mmu::post_enable_init(); bsp::driver::driver_manager().qemu_bring_up_console(); -+ // Printing available again from here on. test_main(); - diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/main.rs 14_virtual_mem_part2_mmio_remap/kernel/src/main.rs --- 13_exceptions_part2_peripheral_IRQs/kernel/src/main.rs +++ 14_virtual_mem_part2_mmio_remap/kernel/src/main.rs -@@ -27,21 +27,31 @@ +@@ -27,21 +27,29 @@ #[no_mangle] unsafe fn kernel_init() -> ! { use driver::interface::DriverManager; @@ -2386,10 +2377,9 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/main.rs 14_virtual_mem_ + if let Err(e) = memory::mmu::enable_mmu_and_caching(phys_kernel_tables_base_addr) { + panic!("Enabling MMU failed: {}", e); } -+ // Printing will silently fail from here on, because the driver's MMIO is not remapped yet. -+ -+ memory::mmu::post_enable_init(); ++ memory::mmu::post_enable_init(); ++ + // Instantiate and init all device drivers. + if let Err(x) = bsp::driver::driver_manager().instantiate_drivers() { + panic!("Error instantiating drivers: {}", x); @@ -2401,11 +2391,10 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/main.rs 14_virtual_mem_ } - bsp::driver::driver_manager().post_device_driver_init(); - // println! is usable from here on. -+ // Printing available again from here on. // Let device drivers register and enable their handlers with the interrupt controller. for i in bsp::driver::driver_manager().all_device_drivers() { -@@ -63,13 +73,12 @@ +@@ -63,13 +71,12 @@ /// The main function running after the early init. fn kernel_main() -> ! { use driver::interface::DriverManager; @@ -2421,7 +2410,7 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/main.rs 14_virtual_mem_ let (_, privilege_level) = exception::current_privilege_level(); info!("Current privilege level: {}", privilege_level); -@@ -92,7 +101,7 @@ +@@ -92,7 +99,7 @@ } info!("Registered IRQ handlers:"); @@ -2434,7 +2423,7 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/main.rs 14_virtual_mem_ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/memory/mmu/mapping_record.rs 14_virtual_mem_part2_mmio_remap/kernel/src/memory/mmu/mapping_record.rs --- 13_exceptions_part2_peripheral_IRQs/kernel/src/memory/mmu/mapping_record.rs +++ 14_virtual_mem_part2_mmio_remap/kernel/src/memory/mmu/mapping_record.rs -@@ -0,0 +1,249 @@ +@@ -0,0 +1,239 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2020-2022 Andre Richter @@ -2445,7 +2434,7 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/memory/mmu/mapping_reco + AccessPermissions, Address, AttributeFields, MMIODescriptor, MemAttributes, MemoryRegion, + Physical, Virtual, +}; -+use crate::{bsp, info, synchronization, synchronization::InitStateLock, warn}; ++use crate::{bsp, common, info, synchronization, synchronization::InitStateLock, warn}; + +//-------------------------------------------------------------------------------------------------- +// Private Definitions @@ -2578,9 +2567,6 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/memory/mmu/mapping_reco + } + + pub fn print(&self) { -+ const KIB_RSHIFT: u32 = 10; // log2(1024). -+ const MIB_RSHIFT: u32 = 20; // log2(1024 * 1024). -+ + info!(" -------------------------------------------------------------------------------------------------------------------------------------------"); + info!( + " {:^44} {:^30} {:^7} {:^9} {:^35}", @@ -2595,13 +2581,7 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/memory/mmu/mapping_reco + let phys_start = i.phys_start_addr; + let phys_end_inclusive = phys_start + (size - 1); + -+ let (size, unit) = if (size >> MIB_RSHIFT) > 0 { -+ (size >> MIB_RSHIFT, "MiB") -+ } else if (size >> KIB_RSHIFT) > 0 { -+ (size >> KIB_RSHIFT, "KiB") -+ } else { -+ (size, "Byte") -+ }; ++ let (size, unit) = common::size_human_readable_ceil(size); + + let attr = match i.attribute_fields.mem_attributes { + MemAttributes::CacheableDRAM => "C", @@ -2620,8 +2600,7 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/memory/mmu/mapping_reco + }; + + info!( -+ " {}..{} --> {}..{} | \ -+ {: >3} {} | {: <3} {} {: <2} | {}", ++ " {}..{} --> {}..{} | {:>3} {} | {:<3} {} {:<2} | {}", + virt_start, + virt_end_inclusive, + phys_start, @@ -2735,7 +2714,7 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/memory/mmu/page_alloc.r + } + + /// Initialize the allocator. -+ pub fn initialize(&mut self, pool: MemoryRegion) { ++ pub fn init(&mut self, pool: MemoryRegion) { + if self.pool.is_some() { + warn!("Already initialized"); + return; @@ -3238,7 +3217,7 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/memory/mmu/types.rs 14_ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/memory/mmu.rs 14_virtual_mem_part2_mmio_remap/kernel/src/memory/mmu.rs --- 13_exceptions_part2_peripheral_IRQs/kernel/src/memory/mmu.rs +++ 14_virtual_mem_part2_mmio_remap/kernel/src/memory/mmu.rs -@@ -3,29 +3,24 @@ +@@ -3,30 +3,24 @@ // Copyright (c) 2020-2022 Andre Richter //! Memory Management Unit. @@ -3262,6 +3241,7 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/memory/mmu.rs 14_virtua mod translation_table; +mod types; +-use crate::common; -use core::{fmt, ops::RangeInclusive}; +use crate::{ + bsp, @@ -3278,7 +3258,7 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/memory/mmu.rs 14_virtua //-------------------------------------------------------------------------------------------------- // Public Definitions -@@ -45,13 +40,15 @@ +@@ -46,13 +40,15 @@ /// MMU functions. pub trait MMU { @@ -3297,7 +3277,7 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/memory/mmu.rs 14_virtua /// Returns true if the MMU is enabled, false otherwise. fn is_enabled(&self) -> bool; -@@ -64,55 +61,51 @@ +@@ -65,55 +61,51 @@ /// Describes properties of an address space. pub struct AddressSpace; @@ -3360,7 +3340,7 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/memory/mmu.rs 14_virtua +fn kernel_init_mmio_va_allocator() { + let region = bsp::memory::mmu::virt_mmio_remap_region(); + -+ page_alloc::kernel_mmio_va_allocator().lock(|allocator| allocator.initialize(region)); ++ page_alloc::kernel_mmio_va_allocator().lock(|allocator| allocator.init(region)); +} + +/// Map a region in the kernel's translation tables. @@ -3394,7 +3374,7 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/memory/mmu.rs 14_virtua } //-------------------------------------------------------------------------------------------------- -@@ -132,6 +125,9 @@ +@@ -133,6 +125,9 @@ /// The granule's size. pub const SIZE: usize = Self::size_checked(); @@ -3404,7 +3384,7 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/memory/mmu.rs 14_virtua /// The granule's shift, aka log2(size). pub const SHIFT: usize = Self::SIZE.trailing_zeros() as usize; -@@ -159,110 +155,147 @@ +@@ -160,98 +155,147 @@ } } @@ -3443,31 +3423,42 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/memory/mmu.rs 14_virtua - let end = *(self.virtual_range)().end(); - let size = end - start + 1; - -- // log2(1024). -- const KIB_RSHIFT: u32 = 10; -- -- // log2(1024 * 1024). -- const MIB_RSHIFT: u32 = 20; +- let (size, unit) = common::size_human_readable_ceil(size); - -- let (size, unit) = if (size >> MIB_RSHIFT) > 0 { -- (size >> MIB_RSHIFT, "MiB") -- } else if (size >> KIB_RSHIFT) > 0 { -- (size >> KIB_RSHIFT, "KiB") -- } else { -- (size, "Byte") -- }; -+ kernel_map_at_unchecked(name, virt_region, phys_region, attr)?; - - let attr = match self.attribute_fields.mem_attributes { - MemAttributes::CacheableDRAM => "C", - MemAttributes::Device => "Dev", - }; -+ Ok(()) -+} - +- - let acc_p = match self.attribute_fields.acc_perms { - AccessPermissions::ReadOnly => "RO", - AccessPermissions::ReadWrite => "RW", +- }; ++ kernel_map_at_unchecked(name, virt_region, phys_region, attr)?; + +- let xn = if self.attribute_fields.execute_never { +- "PXN" +- } else { +- "PX" +- }; +- +- write!( +- f, +- " {:#010x} - {:#010x} | {: >3} {} | {: <3} {} {: <3} | {}", +- start, end, size, unit, attr, acc_p, xn, self.name +- ) +- } ++ Ok(()) + } + +-impl KernelVirtualLayout<{ NUM_SPECIAL_RANGES }> { +- /// Create a new instance. +- pub const fn new(max: usize, layout: [TranslationDescriptor; NUM_SPECIAL_RANGES]) -> Self { +- Self { +- max_virt_addr_inclusive: max, +- inner: layout, +- } +- } +/// MMIO remapping in the kernel translation tables. +/// +/// Typically used by device drivers. @@ -3492,22 +3483,29 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/memory/mmu.rs 14_virtua + let num_pages = match NonZeroUsize::new(phys_region.num_pages()) { + None => return Err("Requested 0 pages"), + Some(x) => x, - }; ++ }; -- let xn = if self.attribute_fields.execute_never { -- "PXN" -- } else { -- "PX" -- }; +- /// For a virtual address, find and return the physical output address and corresponding +- /// attributes. +- /// +- /// If the address is not found in `inner`, return an identity mapped default with normal +- /// cacheable DRAM attributes. +- pub fn virt_addr_properties( +- &self, +- virt_addr: usize, +- ) -> Result<(usize, AttributeFields), &'static str> { +- if virt_addr > self.max_virt_addr_inclusive { +- return Err("Address out of range"); +- } + let virt_region = + page_alloc::kernel_mmio_va_allocator().lock(|allocator| allocator.alloc(num_pages))?; -- write!( -- f, -- " {:#010x} - {:#010x} | {: >3} {} | {: <3} {} {: <3} | {}", -- start, end, size, unit, attr, acc_p, xn, self.name -- ) -- } +- for i in self.inner.iter() { +- if (i.virtual_range)().contains(&virt_addr) { +- let output_addr = match i.physical_range_translation { +- Translation::Identity => virt_addr, +- Translation::Offset(a) => a + (virt_addr - (i.virtual_range)().start()), +- }; + kernel_map_at_unchecked( + name, + &virt_region, @@ -3561,37 +3559,8 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/memory/mmu.rs 14_virtua +/// Human-readable print of all recorded kernel mappings. +pub fn kernel_print_mappings() { + mapping_record::kernel_print() - } ++} --impl KernelVirtualLayout<{ NUM_SPECIAL_RANGES }> { -- /// Create a new instance. -- pub const fn new(max: usize, layout: [TranslationDescriptor; NUM_SPECIAL_RANGES]) -> Self { -- Self { -- max_virt_addr_inclusive: max, -- inner: layout, -- } -- } -- -- /// For a virtual address, find and return the physical output address and corresponding -- /// attributes. -- /// -- /// If the address is not found in `inner`, return an identity mapped default with normal -- /// cacheable DRAM attributes. -- pub fn virt_addr_properties( -- &self, -- virt_addr: usize, -- ) -> Result<(usize, AttributeFields), &'static str> { -- if virt_addr > self.max_virt_addr_inclusive { -- return Err("Address out of range"); -- } -- -- for i in self.inner.iter() { -- if (i.virtual_range)().contains(&virt_addr) { -- let output_addr = match i.physical_range_translation { -- Translation::Identity => virt_addr, -- Translation::Offset(a) => a + (virt_addr - (i.virtual_range)().start()), -- }; -- - return Ok((output_addr, i.attribute_fields)); - } - } @@ -3825,7 +3794,7 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/tests/00_console_sanity.rs #[no_mangle] unsafe fn kernel_init() -> ! { -@@ -19,7 +19,20 @@ +@@ -19,6 +19,17 @@ use driver::interface::DriverManager; exception::handling_init(); @@ -3838,14 +3807,11 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/tests/00_console_sanity.rs + if let Err(e) = memory::mmu::enable_mmu_and_caching(phys_kernel_tables_base_addr) { + panic!("Enabling MMU failed: {}", e); + } -+ // Printing will silently fail from here on, because the driver's MMIO is not remapped yet. + + memory::mmu::post_enable_init(); bsp::driver::driver_manager().qemu_bring_up_console(); -+ // Printing available again from here on. // Handshake - assert_eq!(console().read_char(), 'A'); diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/tests/01_timer_sanity.rs 14_virtual_mem_part2_mmio_remap/kernel/tests/01_timer_sanity.rs --- 13_exceptions_part2_peripheral_IRQs/kernel/tests/01_timer_sanity.rs @@ -3859,7 +3825,7 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/tests/01_timer_sanity.rs 14 use test_macros::kernel_test; #[no_mangle] -@@ -19,7 +19,20 @@ +@@ -19,6 +19,17 @@ use driver::interface::DriverManager; exception::handling_init(); @@ -3872,19 +3838,16 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/tests/01_timer_sanity.rs 14 + if let Err(e) = memory::mmu::enable_mmu_and_caching(phys_kernel_tables_base_addr) { + panic!("Enabling MMU failed: {}", e); + } -+ // Printing will silently fail from here on, because the driver's MMIO is not remapped yet. + + memory::mmu::post_enable_init(); bsp::driver::driver_manager().qemu_bring_up_console(); -+ // Printing available again from here on. // Depending on CPU arch, some timer bring-up code could go here. Not needed for the RPi. - diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/tests/02_exception_sync_page_fault.rs 14_virtual_mem_part2_mmio_remap/kernel/tests/02_exception_sync_page_fault.rs --- 13_exceptions_part2_peripheral_IRQs/kernel/tests/02_exception_sync_page_fault.rs +++ 14_virtual_mem_part2_mmio_remap/kernel/tests/02_exception_sync_page_fault.rs -@@ -22,18 +22,29 @@ +@@ -22,19 +22,28 @@ #[no_mangle] unsafe fn kernel_init() -> ! { use driver::interface::DriverManager; @@ -3910,19 +3873,18 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/tests/02_exception_sync_pag + info!("Enabling MMU failed: {}", e); cpu::qemu_exit_failure() } -+ // Printing will silently fail from here on, because the driver's MMIO is not remapped yet. -+ + + memory::mmu::post_enable_init(); + bsp::driver::driver_manager().qemu_bring_up_console(); -+ // Printing available again from here on. - ++ info!("Writing beyond mapped area to address 9 GiB..."); let big_addr: u64 = 9 * 1024 * 1024 * 1024; + core::ptr::read_volatile(big_addr as *mut u64); diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/tests/03_exception_restore_sanity.rs 14_virtual_mem_part2_mmio_remap/kernel/tests/03_exception_restore_sanity.rs --- 13_exceptions_part2_peripheral_IRQs/kernel/tests/03_exception_restore_sanity.rs +++ 14_virtual_mem_part2_mmio_remap/kernel/tests/03_exception_restore_sanity.rs -@@ -31,18 +31,29 @@ +@@ -31,19 +31,28 @@ #[no_mangle] unsafe fn kernel_init() -> ! { use driver::interface::DriverManager; @@ -3948,19 +3910,18 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/tests/03_exception_restore_ + info!("Enabling MMU failed: {}", e); cpu::qemu_exit_failure() } -+ // Printing will silently fail from here on, because the driver's MMIO is not remapped yet. -+ + + memory::mmu::post_enable_init(); + bsp::driver::driver_manager().qemu_bring_up_console(); -+ // Printing available again from here on. - ++ info!("Making a dummy system call"); + // Calling this inside a function indirectly tests if the link register is restored properly. diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/tests/04_exception_irq_sanity.rs 14_virtual_mem_part2_mmio_remap/kernel/tests/04_exception_irq_sanity.rs --- 13_exceptions_part2_peripheral_IRQs/kernel/tests/04_exception_irq_sanity.rs +++ 14_virtual_mem_part2_mmio_remap/kernel/tests/04_exception_irq_sanity.rs -@@ -10,15 +10,29 @@ +@@ -10,15 +10,27 @@ #![reexport_test_harness_main = "test_main"] #![test_runner(libkernel::test_runner)] @@ -3983,11 +3944,9 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/tests/04_exception_irq_sani + if let Err(e) = memory::mmu::enable_mmu_and_caching(phys_kernel_tables_base_addr) { + panic!("Enabling MMU failed: {}", e); + } -+ // Printing will silently fail from here on, because the driver's MMIO is not remapped yet. + + memory::mmu::post_enable_init(); + bsp::driver::driver_manager().qemu_bring_up_console(); -+ // Printing available again from here on. + exception::asynchronous::local_irq_unmask(); diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/common.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/common.rs index 678f4a6c..f32f650f 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/common.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/common.rs @@ -27,3 +27,20 @@ pub const fn align_up(value: usize, alignment: usize) -> usize { (value + alignment - 1) & !(alignment - 1) } + +/// Convert a size into human readable format. +pub const fn size_human_readable_ceil(size: usize) -> (usize, &'static str) { + const KIB: usize = 1024; + const MIB: usize = 1024 * 1024; + const GIB: usize = 1024 * 1024 * 1024; + + if (size / GIB) > 0 { + (size.div_ceil(GIB), "GiB") + } else if (size / MIB) > 0 { + (size.div_ceil(MIB), "MiB") + } else if (size / KIB) > 0 { + (size.div_ceil(KIB), "KiB") + } else { + (size, "Byte") + } +} diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/console/null_console.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/console/null_console.rs index 10c3bedc..2c64d499 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/console/null_console.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/console/null_console.rs @@ -20,7 +20,7 @@ pub struct NullConsole; pub static NULL_CONSOLE: NullConsole = NullConsole {}; //-------------------------------------------------------------------------------------------------- -// Private Code +// Public Code //-------------------------------------------------------------------------------------------------- impl interface::Write for NullConsole { diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/lib.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/lib.rs index ac57da95..c40cb4e7 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/lib.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/lib.rs @@ -114,6 +114,7 @@ #![feature(core_intrinsics)] #![feature(format_args_nl)] #![feature(generic_const_exprs)] +#![feature(int_roundings)] #![feature(is_sorted)] #![feature(linkage)] #![feature(panic_info_message)] @@ -194,11 +195,9 @@ unsafe fn kernel_init() -> ! { if let Err(e) = memory::mmu::enable_mmu_and_caching(phys_kernel_tables_base_addr) { panic!("Enabling MMU failed: {}", e); } - // Printing will silently fail from here on, because the driver's MMIO is not remapped yet. memory::mmu::post_enable_init(); bsp::driver::driver_manager().qemu_bring_up_console(); - // Printing available again from here on. test_main(); diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/main.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/main.rs index 7574522c..776b28fa 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/main.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/main.rs @@ -38,7 +38,6 @@ unsafe fn kernel_init() -> ! { if let Err(e) = memory::mmu::enable_mmu_and_caching(phys_kernel_tables_base_addr) { panic!("Enabling MMU failed: {}", e); } - // Printing will silently fail from here on, because the driver's MMIO is not remapped yet. memory::mmu::post_enable_init(); @@ -51,7 +50,6 @@ unsafe fn kernel_init() -> ! { panic!("Error loading driver: {}: {}", i.compatible(), x); } } - // Printing available again from here on. // Let device drivers register and enable their handlers with the interrupt controller. for i in bsp::driver::driver_manager().all_device_drivers() { diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/memory/mmu.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/memory/mmu.rs index 43602470..bd1f56ff 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/memory/mmu.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/memory/mmu.rs @@ -81,7 +81,7 @@ use translation_table::interface::TranslationTable; fn kernel_init_mmio_va_allocator() { let region = bsp::memory::mmu::virt_mmio_remap_region(); - page_alloc::kernel_mmio_va_allocator().lock(|allocator| allocator.initialize(region)); + page_alloc::kernel_mmio_va_allocator().lock(|allocator| allocator.init(region)); } /// Map a region in the kernel's translation tables. diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/memory/mmu/mapping_record.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/memory/mmu/mapping_record.rs index 7d3a6c60..5bc32445 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/memory/mmu/mapping_record.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/memory/mmu/mapping_record.rs @@ -8,7 +8,7 @@ use super::{ AccessPermissions, Address, AttributeFields, MMIODescriptor, MemAttributes, MemoryRegion, Physical, Virtual, }; -use crate::{bsp, info, synchronization, synchronization::InitStateLock, warn}; +use crate::{bsp, common, info, synchronization, synchronization::InitStateLock, warn}; //-------------------------------------------------------------------------------------------------- // Private Definitions @@ -141,9 +141,6 @@ impl MappingRecord { } pub fn print(&self) { - const KIB_RSHIFT: u32 = 10; // log2(1024). - const MIB_RSHIFT: u32 = 20; // log2(1024 * 1024). - info!(" -------------------------------------------------------------------------------------------------------------------------------------------"); info!( " {:^44} {:^30} {:^7} {:^9} {:^35}", @@ -158,13 +155,7 @@ impl MappingRecord { let phys_start = i.phys_start_addr; let phys_end_inclusive = phys_start + (size - 1); - let (size, unit) = if (size >> MIB_RSHIFT) > 0 { - (size >> MIB_RSHIFT, "MiB") - } else if (size >> KIB_RSHIFT) > 0 { - (size >> KIB_RSHIFT, "KiB") - } else { - (size, "Byte") - }; + let (size, unit) = common::size_human_readable_ceil(size); let attr = match i.attribute_fields.mem_attributes { MemAttributes::CacheableDRAM => "C", @@ -183,8 +174,7 @@ impl MappingRecord { }; info!( - " {}..{} --> {}..{} | \ - {: >3} {} | {: <3} {} {: <2} | {}", + " {}..{} --> {}..{} | {:>3} {} | {:<3} {} {:<2} | {}", virt_start, virt_end_inclusive, phys_start, diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/memory/mmu/page_alloc.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/memory/mmu/page_alloc.rs index b4c4232c..347fcd34 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/memory/mmu/page_alloc.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/memory/mmu/page_alloc.rs @@ -44,7 +44,7 @@ impl PageAllocator { } /// Initialize the allocator. - pub fn initialize(&mut self, pool: MemoryRegion) { + pub fn init(&mut self, pool: MemoryRegion) { if self.pool.is_some() { warn!("Already initialized"); return; diff --git a/14_virtual_mem_part2_mmio_remap/kernel/tests/00_console_sanity.rs b/14_virtual_mem_part2_mmio_remap/kernel/tests/00_console_sanity.rs index a2338d2f..9c6e9cef 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/tests/00_console_sanity.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/tests/00_console_sanity.rs @@ -28,11 +28,9 @@ unsafe fn kernel_init() -> ! { if let Err(e) = memory::mmu::enable_mmu_and_caching(phys_kernel_tables_base_addr) { panic!("Enabling MMU failed: {}", e); } - // Printing will silently fail from here on, because the driver's MMIO is not remapped yet. memory::mmu::post_enable_init(); bsp::driver::driver_manager().qemu_bring_up_console(); - // Printing available again from here on. // Handshake assert_eq!(console().read_char(), 'A'); diff --git a/14_virtual_mem_part2_mmio_remap/kernel/tests/01_timer_sanity.rs b/14_virtual_mem_part2_mmio_remap/kernel/tests/01_timer_sanity.rs index 4b4e90e4..dc3337e2 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/tests/01_timer_sanity.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/tests/01_timer_sanity.rs @@ -28,11 +28,9 @@ unsafe fn kernel_init() -> ! { if let Err(e) = memory::mmu::enable_mmu_and_caching(phys_kernel_tables_base_addr) { panic!("Enabling MMU failed: {}", e); } - // Printing will silently fail from here on, because the driver's MMIO is not remapped yet. memory::mmu::post_enable_init(); bsp::driver::driver_manager().qemu_bring_up_console(); - // Printing available again from here on. // Depending on CPU arch, some timer bring-up code could go here. Not needed for the RPi. diff --git a/14_virtual_mem_part2_mmio_remap/kernel/tests/02_exception_sync_page_fault.rs b/14_virtual_mem_part2_mmio_remap/kernel/tests/02_exception_sync_page_fault.rs index 209517ac..594ffb40 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/tests/02_exception_sync_page_fault.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/tests/02_exception_sync_page_fault.rs @@ -40,11 +40,9 @@ unsafe fn kernel_init() -> ! { info!("Enabling MMU failed: {}", e); cpu::qemu_exit_failure() } - // Printing will silently fail from here on, because the driver's MMIO is not remapped yet. memory::mmu::post_enable_init(); bsp::driver::driver_manager().qemu_bring_up_console(); - // Printing available again from here on. info!("Writing beyond mapped area to address 9 GiB..."); let big_addr: u64 = 9 * 1024 * 1024 * 1024; diff --git a/14_virtual_mem_part2_mmio_remap/kernel/tests/03_exception_restore_sanity.rs b/14_virtual_mem_part2_mmio_remap/kernel/tests/03_exception_restore_sanity.rs index babc31e2..32001b2a 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/tests/03_exception_restore_sanity.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/tests/03_exception_restore_sanity.rs @@ -49,11 +49,9 @@ unsafe fn kernel_init() -> ! { info!("Enabling MMU failed: {}", e); cpu::qemu_exit_failure() } - // Printing will silently fail from here on, because the driver's MMIO is not remapped yet. memory::mmu::post_enable_init(); bsp::driver::driver_manager().qemu_bring_up_console(); - // Printing available again from here on. info!("Making a dummy system call"); diff --git a/14_virtual_mem_part2_mmio_remap/kernel/tests/04_exception_irq_sanity.rs b/14_virtual_mem_part2_mmio_remap/kernel/tests/04_exception_irq_sanity.rs index 872cc008..7a344874 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/tests/04_exception_irq_sanity.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/tests/04_exception_irq_sanity.rs @@ -27,11 +27,9 @@ unsafe fn kernel_init() -> ! { if let Err(e) = memory::mmu::enable_mmu_and_caching(phys_kernel_tables_base_addr) { panic!("Enabling MMU failed: {}", e); } - // Printing will silently fail from here on, because the driver's MMIO is not remapped yet. memory::mmu::post_enable_init(); bsp::driver::driver_manager().qemu_bring_up_console(); - // Printing available again from here on. exception::asynchronous::local_irq_unmask(); diff --git a/15_virtual_mem_part3_precomputed_tables/README.md b/15_virtual_mem_part3_precomputed_tables/README.md index 5a07f34b..186acc2a 100644 --- a/15_virtual_mem_part3_precomputed_tables/README.md +++ b/15_virtual_mem_part3_precomputed_tables/README.md @@ -1315,7 +1315,7 @@ diff -uNr 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/memory/mmu. diff -uNr 14_virtual_mem_part2_mmio_remap/kernel/src/lib.rs 15_virtual_mem_part3_precomputed_tables/kernel/src/lib.rs --- 14_virtual_mem_part2_mmio_remap/kernel/src/lib.rs +++ 15_virtual_mem_part3_precomputed_tables/kernel/src/lib.rs -@@ -185,20 +185,8 @@ +@@ -186,17 +186,7 @@ use driver::interface::DriverManager; exception::handling_init(); @@ -1328,19 +1328,17 @@ diff -uNr 14_virtual_mem_part2_mmio_remap/kernel/src/lib.rs 15_virtual_mem_part3 - if let Err(e) = memory::mmu::enable_mmu_and_caching(phys_kernel_tables_base_addr) { - panic!("Enabling MMU failed: {}", e); - } -- // Printing will silently fail from here on, because the driver's MMIO is not remapped yet. - - memory::mmu::post_enable_init(); +- memory::mmu::post_enable_init(); ++ memory::init(); bsp::driver::driver_manager().qemu_bring_up_console(); -- // Printing available again from here on. test_main(); - diff -uNr 14_virtual_mem_part2_mmio_remap/kernel/src/main.rs 15_virtual_mem_part3_precomputed_tables/kernel/src/main.rs --- 14_virtual_mem_part2_mmio_remap/kernel/src/main.rs +++ 15_virtual_mem_part3_precomputed_tables/kernel/src/main.rs -@@ -17,29 +17,17 @@ +@@ -17,29 +17,18 @@ /// Early init code. /// @@ -1368,20 +1366,13 @@ diff -uNr 14_virtual_mem_part2_mmio_remap/kernel/src/main.rs 15_virtual_mem_part - if let Err(e) = memory::mmu::enable_mmu_and_caching(phys_kernel_tables_base_addr) { - panic!("Enabling MMU failed: {}", e); - } -- // Printing will silently fail from here on, because the driver's MMIO is not remapped yet. - - memory::mmu::post_enable_init(); +- memory::mmu::post_enable_init(); ++ memory::init(); // Instantiate and init all device drivers. -@@ -51,7 +39,6 @@ - panic!("Error loading driver: {}: {}", i.compatible(), x); - } - } -- // Printing available again from here on. - - // Let device drivers register and enable their handlers with the interrupt controller. - for i in bsp::driver::driver_manager().all_device_drivers() { -@@ -60,6 +47,8 @@ + if let Err(x) = bsp::driver::driver_manager().instantiate_drivers() { +@@ -58,6 +47,8 @@ } } @@ -1494,7 +1485,7 @@ diff -uNr 14_virtual_mem_part2_mmio_remap/kernel/src/memory/mmu.rs 15_virtual_me }; use core::{fmt, num::NonZeroUsize}; -@@ -73,7 +74,7 @@ +@@ -73,17 +74,9 @@ // Private Code //-------------------------------------------------------------------------------------------------- use interface::MMU; @@ -1502,8 +1493,18 @@ diff -uNr 14_virtual_mem_part2_mmio_remap/kernel/src/memory/mmu.rs 15_virtual_me +use synchronization::interface::ReadWriteEx; use translation_table::interface::TranslationTable; - /// Query the BSP for the reserved virtual addresses for MMIO remapping and initialize the kernel's -@@ -101,13 +102,21 @@ +-/// Query the BSP for the reserved virtual addresses for MMIO remapping and initialize the kernel's +-/// MMIO VA allocator with it. +-fn kernel_init_mmio_va_allocator() { +- let region = bsp::memory::mmu::virt_mmio_remap_region(); +- +- page_alloc::kernel_mmio_va_allocator().lock(|allocator| allocator.init(region)); +-} +- + /// Map a region in the kernel's translation tables. + /// + /// No input checks done, input is passed through to the architectural implementation. +@@ -101,13 +94,21 @@ bsp::memory::mmu::kernel_translation_tables() .write(|tables| tables.map_at(virt_region, phys_region, attr))?; @@ -1528,7 +1529,7 @@ diff -uNr 14_virtual_mem_part2_mmio_remap/kernel/src/memory/mmu.rs 15_virtual_me //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- -@@ -155,27 +164,16 @@ +@@ -155,27 +156,24 @@ } } @@ -1541,6 +1542,14 @@ diff -uNr 14_virtual_mem_part2_mmio_remap/kernel/src/memory/mmu.rs 15_virtual_me -/// - See `kernel_map_at_unchecked()`. -/// - Does not prevent aliasing. Currently, the callers must be trusted. -pub unsafe fn kernel_map_at( ++/// Query the BSP for the reserved virtual addresses for MMIO remapping and initialize the kernel's ++/// MMIO VA allocator with it. ++pub fn kernel_init_mmio_va_allocator() { ++ let region = bsp::memory::mmu::virt_mmio_remap_region(); ++ ++ page_alloc::kernel_mmio_va_allocator().lock(|allocator| allocator.init(region)); ++} ++ +/// Add an entry to the mapping info record. +pub fn kernel_add_mapping_record( name: &'static str, @@ -1561,15 +1570,15 @@ diff -uNr 14_virtual_mem_part2_mmio_remap/kernel/src/memory/mmu.rs 15_virtual_me } /// MMIO remapping in the kernel translation tables. -@@ -224,21 +222,24 @@ +@@ -224,21 +222,29 @@ Ok(virt_addr + offset_into_start_page) } -/// Map the kernel's binary. Returns the translation table's base address. +-/// +-/// # Safety +/// Try to translate a kernel virtual page address to a physical page address. /// --/// # Safety --/// -/// - See [`bsp::memory::mmu::kernel_map_binary()`]. -pub unsafe fn kernel_map_binary() -> Result, &'static str> { - let phys_kernel_tables_base_addr = @@ -1577,8 +1586,6 @@ diff -uNr 14_virtual_mem_part2_mmio_remap/kernel/src/memory/mmu.rs 15_virtual_me - tables.init(); - tables.phys_base_address() - }); -- -- bsp::memory::mmu::kernel_map_binary()?; +/// Will only succeed if there exists a valid mapping for the input page. +pub fn try_kernel_virt_page_addr_to_phys_page_addr( + virt_page_addr: PageAddress, @@ -1587,7 +1594,7 @@ diff -uNr 14_virtual_mem_part2_mmio_remap/kernel/src/memory/mmu.rs 15_virtual_me + .read(|tables| tables.try_virt_page_addr_to_phys_page_addr(virt_page_addr)) +} -- Ok(phys_kernel_tables_base_addr) +- bsp::memory::mmu::kernel_map_binary()?; +/// Try to get the attributes of a kernel page. +/// +/// Will only succeed if there exists a valid mapping for the input page. @@ -1596,10 +1603,16 @@ diff -uNr 14_virtual_mem_part2_mmio_remap/kernel/src/memory/mmu.rs 15_virtual_me +) -> Result { + bsp::memory::mmu::kernel_translation_tables() + .read(|tables| tables.try_page_attributes(virt_page_addr)) ++} + +- Ok(phys_kernel_tables_base_addr) ++/// Human-readable print of all recorded kernel mappings. ++pub fn kernel_print_mappings() { ++ mapping_record::kernel_print() } /// Enable the MMU and data + instruction caching. -@@ -246,6 +247,7 @@ +@@ -246,56 +252,9 @@ /// # Safety /// /// - Crucial function during kernel init. Changes the the complete memory view of the processor. @@ -1607,11 +1620,19 @@ diff -uNr 14_virtual_mem_part2_mmio_remap/kernel/src/memory/mmu.rs 15_virtual_me pub unsafe fn enable_mmu_and_caching( phys_tables_base_addr: Address, ) -> Result<(), MMUEnableError> { -@@ -261,41 +263,3 @@ - pub fn kernel_print_mappings() { - mapping_record::kernel_print() + arch_mmu::mmu().enable_mmu_and_caching(phys_tables_base_addr) } - +-/// Finish initialization of the MMU subsystem. +-pub fn post_enable_init() { +- kernel_init_mmio_va_allocator(); +-} +- +-/// Human-readable print of all recorded kernel mappings. +-pub fn kernel_print_mappings() { +- mapping_record::kernel_print() +-} +- -//-------------------------------------------------------------------------------------------------- -// Testing -//-------------------------------------------------------------------------------------------------- @@ -1650,10 +1671,26 @@ diff -uNr 14_virtual_mem_part2_mmio_remap/kernel/src/memory/mmu.rs 15_virtual_me - } -} +diff -uNr 14_virtual_mem_part2_mmio_remap/kernel/src/memory.rs 15_virtual_mem_part3_precomputed_tables/kernel/src/memory.rs +--- 14_virtual_mem_part2_mmio_remap/kernel/src/memory.rs ++++ 15_virtual_mem_part3_precomputed_tables/kernel/src/memory.rs +@@ -136,6 +136,11 @@ + } + } + ++/// Initialize the memory subsystem. ++pub fn init() { ++ mmu::kernel_init_mmio_va_allocator(); ++} ++ + //-------------------------------------------------------------------------------------------------- + // Testing + //-------------------------------------------------------------------------------------------------- + diff -uNr 14_virtual_mem_part2_mmio_remap/kernel/tests/00_console_sanity.rs 15_virtual_mem_part3_precomputed_tables/kernel/tests/00_console_sanity.rs --- 14_virtual_mem_part2_mmio_remap/kernel/tests/00_console_sanity.rs +++ 15_virtual_mem_part3_precomputed_tables/kernel/tests/00_console_sanity.rs -@@ -19,20 +19,8 @@ +@@ -19,17 +19,7 @@ use driver::interface::DriverManager; exception::handling_init(); @@ -1666,19 +1703,17 @@ diff -uNr 14_virtual_mem_part2_mmio_remap/kernel/tests/00_console_sanity.rs 15_v - if let Err(e) = memory::mmu::enable_mmu_and_caching(phys_kernel_tables_base_addr) { - panic!("Enabling MMU failed: {}", e); - } -- // Printing will silently fail from here on, because the driver's MMIO is not remapped yet. - - memory::mmu::post_enable_init(); +- memory::mmu::post_enable_init(); ++ memory::init(); bsp::driver::driver_manager().qemu_bring_up_console(); -- // Printing available again from here on. // Handshake - assert_eq!(console().read_char(), 'A'); diff -uNr 14_virtual_mem_part2_mmio_remap/kernel/tests/01_timer_sanity.rs 15_virtual_mem_part3_precomputed_tables/kernel/tests/01_timer_sanity.rs --- 14_virtual_mem_part2_mmio_remap/kernel/tests/01_timer_sanity.rs +++ 15_virtual_mem_part3_precomputed_tables/kernel/tests/01_timer_sanity.rs -@@ -19,20 +19,8 @@ +@@ -19,17 +19,7 @@ use driver::interface::DriverManager; exception::handling_init(); @@ -1691,23 +1726,21 @@ diff -uNr 14_virtual_mem_part2_mmio_remap/kernel/tests/01_timer_sanity.rs 15_vir - if let Err(e) = memory::mmu::enable_mmu_and_caching(phys_kernel_tables_base_addr) { - panic!("Enabling MMU failed: {}", e); - } -- // Printing will silently fail from here on, because the driver's MMIO is not remapped yet. - - memory::mmu::post_enable_init(); +- memory::mmu::post_enable_init(); ++ memory::init(); bsp::driver::driver_manager().qemu_bring_up_console(); -- // Printing available again from here on. // Depending on CPU arch, some timer bring-up code could go here. Not needed for the RPi. - diff -uNr 14_virtual_mem_part2_mmio_remap/kernel/tests/02_exception_sync_page_fault.rs 15_virtual_mem_part3_precomputed_tables/kernel/tests/02_exception_sync_page_fault.rs --- 14_virtual_mem_part2_mmio_remap/kernel/tests/02_exception_sync_page_fault.rs +++ 15_virtual_mem_part3_precomputed_tables/kernel/tests/02_exception_sync_page_fault.rs -@@ -24,28 +24,12 @@ +@@ -24,26 +24,12 @@ use driver::interface::DriverManager; exception::handling_init(); -+ memory::mmu::post_enable_init(); ++ memory::init(); + bsp::driver::driver_manager().qemu_bring_up_console(); // This line will be printed as the test header. @@ -1725,11 +1758,9 @@ diff -uNr 14_virtual_mem_part2_mmio_remap/kernel/tests/02_exception_sync_page_fa - info!("Enabling MMU failed: {}", e); - cpu::qemu_exit_failure() - } -- // Printing will silently fail from here on, because the driver's MMIO is not remapped yet. - - memory::mmu::post_enable_init(); - bsp::driver::driver_manager().qemu_bring_up_console(); -- // Printing available again from here on. - info!("Writing beyond mapped area to address 9 GiB..."); let big_addr: u64 = 9 * 1024 * 1024 * 1024; @@ -1738,11 +1769,11 @@ diff -uNr 14_virtual_mem_part2_mmio_remap/kernel/tests/02_exception_sync_page_fa diff -uNr 14_virtual_mem_part2_mmio_remap/kernel/tests/03_exception_restore_sanity.rs 15_virtual_mem_part3_precomputed_tables/kernel/tests/03_exception_restore_sanity.rs --- 14_virtual_mem_part2_mmio_remap/kernel/tests/03_exception_restore_sanity.rs +++ 15_virtual_mem_part3_precomputed_tables/kernel/tests/03_exception_restore_sanity.rs -@@ -33,28 +33,12 @@ +@@ -33,26 +33,12 @@ use driver::interface::DriverManager; exception::handling_init(); -+ memory::mmu::post_enable_init(); ++ memory::init(); + bsp::driver::driver_manager().qemu_bring_up_console(); // This line will be printed as the test header. @@ -1760,11 +1791,9 @@ diff -uNr 14_virtual_mem_part2_mmio_remap/kernel/tests/03_exception_restore_sani - info!("Enabling MMU failed: {}", e); - cpu::qemu_exit_failure() - } -- // Printing will silently fail from here on, because the driver's MMIO is not remapped yet. - - memory::mmu::post_enable_init(); - bsp::driver::driver_manager().qemu_bring_up_console(); -- // Printing available again from here on. - info!("Making a dummy system call"); @@ -1773,7 +1802,7 @@ diff -uNr 14_virtual_mem_part2_mmio_remap/kernel/tests/03_exception_restore_sani diff -uNr 14_virtual_mem_part2_mmio_remap/kernel/tests/04_exception_irq_sanity.rs 15_virtual_mem_part3_precomputed_tables/kernel/tests/04_exception_irq_sanity.rs --- 14_virtual_mem_part2_mmio_remap/kernel/tests/04_exception_irq_sanity.rs +++ 15_virtual_mem_part3_precomputed_tables/kernel/tests/04_exception_irq_sanity.rs -@@ -17,22 +17,10 @@ +@@ -17,20 +17,10 @@ unsafe fn kernel_init() -> ! { use driver::interface::DriverManager; @@ -1787,11 +1816,10 @@ diff -uNr 14_virtual_mem_part2_mmio_remap/kernel/tests/04_exception_irq_sanity.r - if let Err(e) = memory::mmu::enable_mmu_and_caching(phys_kernel_tables_base_addr) { - panic!("Enabling MMU failed: {}", e); - } -- // Printing will silently fail from here on, because the driver's MMIO is not remapped yet. - - memory::mmu::post_enable_init(); +- memory::mmu::post_enable_init(); ++ memory::init(); bsp::driver::driver_manager().qemu_bring_up_console(); -- // Printing available again from here on. + exception::handling_init(); exception::asynchronous::local_irq_unmask(); diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/common.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/common.rs index 678f4a6c..f32f650f 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/common.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/common.rs @@ -27,3 +27,20 @@ pub const fn align_up(value: usize, alignment: usize) -> usize { (value + alignment - 1) & !(alignment - 1) } + +/// Convert a size into human readable format. +pub const fn size_human_readable_ceil(size: usize) -> (usize, &'static str) { + const KIB: usize = 1024; + const MIB: usize = 1024 * 1024; + const GIB: usize = 1024 * 1024 * 1024; + + if (size / GIB) > 0 { + (size.div_ceil(GIB), "GiB") + } else if (size / MIB) > 0 { + (size.div_ceil(MIB), "MiB") + } else if (size / KIB) > 0 { + (size.div_ceil(KIB), "KiB") + } else { + (size, "Byte") + } +} diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/console/null_console.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/console/null_console.rs index 10c3bedc..2c64d499 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/console/null_console.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/console/null_console.rs @@ -20,7 +20,7 @@ pub struct NullConsole; pub static NULL_CONSOLE: NullConsole = NullConsole {}; //-------------------------------------------------------------------------------------------------- -// Private Code +// Public Code //-------------------------------------------------------------------------------------------------- impl interface::Write for NullConsole { diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/lib.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/lib.rs index 1787ce02..a9577868 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/lib.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/lib.rs @@ -114,6 +114,7 @@ #![feature(core_intrinsics)] #![feature(format_args_nl)] #![feature(generic_const_exprs)] +#![feature(int_roundings)] #![feature(is_sorted)] #![feature(linkage)] #![feature(panic_info_message)] @@ -185,7 +186,7 @@ unsafe fn kernel_init() -> ! { use driver::interface::DriverManager; exception::handling_init(); - memory::mmu::post_enable_init(); + memory::init(); bsp::driver::driver_manager().qemu_bring_up_console(); test_main(); diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/main.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/main.rs index 928f12c2..9aeb4438 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/main.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/main.rs @@ -28,7 +28,7 @@ unsafe fn kernel_init() -> ! { use driver::interface::DriverManager; exception::handling_init(); - memory::mmu::post_enable_init(); + memory::init(); // Instantiate and init all device drivers. if let Err(x) = bsp::driver::driver_manager().instantiate_drivers() { diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/memory.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/memory.rs index 64d8cf64..3b6868e7 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/memory.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/memory.rs @@ -136,6 +136,11 @@ impl fmt::Display for Address { } } +/// Initialize the memory subsystem. +pub fn init() { + mmu::kernel_init_mmio_va_allocator(); +} + //-------------------------------------------------------------------------------------------------- // Testing //-------------------------------------------------------------------------------------------------- diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/memory/mmu.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/memory/mmu.rs index c6461474..698f2095 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/memory/mmu.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/memory/mmu.rs @@ -77,14 +77,6 @@ use interface::MMU; use synchronization::interface::ReadWriteEx; use translation_table::interface::TranslationTable; -/// Query the BSP for the reserved virtual addresses for MMIO remapping and initialize the kernel's -/// MMIO VA allocator with it. -fn kernel_init_mmio_va_allocator() { - let region = bsp::memory::mmu::virt_mmio_remap_region(); - - page_alloc::kernel_mmio_va_allocator().lock(|allocator| allocator.initialize(region)); -} - /// Map a region in the kernel's translation tables. /// /// No input checks done, input is passed through to the architectural implementation. @@ -164,6 +156,14 @@ impl AddressSpace { } } +/// Query the BSP for the reserved virtual addresses for MMIO remapping and initialize the kernel's +/// MMIO VA allocator with it. +pub fn kernel_init_mmio_va_allocator() { + let region = bsp::memory::mmu::virt_mmio_remap_region(); + + page_alloc::kernel_mmio_va_allocator().lock(|allocator| allocator.init(region)); +} + /// Add an entry to the mapping info record. pub fn kernel_add_mapping_record( name: &'static str, @@ -242,6 +242,11 @@ pub fn try_kernel_page_attributes( .read(|tables| tables.try_page_attributes(virt_page_addr)) } +/// Human-readable print of all recorded kernel mappings. +pub fn kernel_print_mappings() { + mapping_record::kernel_print() +} + /// Enable the MMU and data + instruction caching. /// /// # Safety @@ -253,13 +258,3 @@ pub unsafe fn enable_mmu_and_caching( ) -> Result<(), MMUEnableError> { arch_mmu::mmu().enable_mmu_and_caching(phys_tables_base_addr) } - -/// Finish initialization of the MMU subsystem. -pub fn post_enable_init() { - kernel_init_mmio_va_allocator(); -} - -/// Human-readable print of all recorded kernel mappings. -pub fn kernel_print_mappings() { - mapping_record::kernel_print() -} diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/memory/mmu/mapping_record.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/memory/mmu/mapping_record.rs index 7d3a6c60..5bc32445 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/memory/mmu/mapping_record.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/memory/mmu/mapping_record.rs @@ -8,7 +8,7 @@ use super::{ AccessPermissions, Address, AttributeFields, MMIODescriptor, MemAttributes, MemoryRegion, Physical, Virtual, }; -use crate::{bsp, info, synchronization, synchronization::InitStateLock, warn}; +use crate::{bsp, common, info, synchronization, synchronization::InitStateLock, warn}; //-------------------------------------------------------------------------------------------------- // Private Definitions @@ -141,9 +141,6 @@ impl MappingRecord { } pub fn print(&self) { - const KIB_RSHIFT: u32 = 10; // log2(1024). - const MIB_RSHIFT: u32 = 20; // log2(1024 * 1024). - info!(" -------------------------------------------------------------------------------------------------------------------------------------------"); info!( " {:^44} {:^30} {:^7} {:^9} {:^35}", @@ -158,13 +155,7 @@ impl MappingRecord { let phys_start = i.phys_start_addr; let phys_end_inclusive = phys_start + (size - 1); - let (size, unit) = if (size >> MIB_RSHIFT) > 0 { - (size >> MIB_RSHIFT, "MiB") - } else if (size >> KIB_RSHIFT) > 0 { - (size >> KIB_RSHIFT, "KiB") - } else { - (size, "Byte") - }; + let (size, unit) = common::size_human_readable_ceil(size); let attr = match i.attribute_fields.mem_attributes { MemAttributes::CacheableDRAM => "C", @@ -183,8 +174,7 @@ impl MappingRecord { }; info!( - " {}..{} --> {}..{} | \ - {: >3} {} | {: <3} {} {: <2} | {}", + " {}..{} --> {}..{} | {:>3} {} | {:<3} {} {:<2} | {}", virt_start, virt_end_inclusive, phys_start, diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/memory/mmu/page_alloc.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/memory/mmu/page_alloc.rs index b4c4232c..347fcd34 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/memory/mmu/page_alloc.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/memory/mmu/page_alloc.rs @@ -44,7 +44,7 @@ impl PageAllocator { } /// Initialize the allocator. - pub fn initialize(&mut self, pool: MemoryRegion) { + pub fn init(&mut self, pool: MemoryRegion) { if self.pool.is_some() { warn!("Already initialized"); return; diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/tests/00_console_sanity.rs b/15_virtual_mem_part3_precomputed_tables/kernel/tests/00_console_sanity.rs index f2a1f3ed..305510ce 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/tests/00_console_sanity.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/tests/00_console_sanity.rs @@ -19,7 +19,7 @@ unsafe fn kernel_init() -> ! { use driver::interface::DriverManager; exception::handling_init(); - memory::mmu::post_enable_init(); + memory::init(); bsp::driver::driver_manager().qemu_bring_up_console(); // Handshake diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/tests/01_timer_sanity.rs b/15_virtual_mem_part3_precomputed_tables/kernel/tests/01_timer_sanity.rs index caeca3cd..d5d76a5c 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/tests/01_timer_sanity.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/tests/01_timer_sanity.rs @@ -19,7 +19,7 @@ unsafe fn kernel_init() -> ! { use driver::interface::DriverManager; exception::handling_init(); - memory::mmu::post_enable_init(); + memory::init(); bsp::driver::driver_manager().qemu_bring_up_console(); // Depending on CPU arch, some timer bring-up code could go here. Not needed for the RPi. diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/tests/02_exception_sync_page_fault.rs b/15_virtual_mem_part3_precomputed_tables/kernel/tests/02_exception_sync_page_fault.rs index feb84d9b..ec7a365a 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/tests/02_exception_sync_page_fault.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/tests/02_exception_sync_page_fault.rs @@ -24,7 +24,7 @@ unsafe fn kernel_init() -> ! { use driver::interface::DriverManager; exception::handling_init(); - memory::mmu::post_enable_init(); + memory::init(); bsp::driver::driver_manager().qemu_bring_up_console(); // This line will be printed as the test header. diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/tests/03_exception_restore_sanity.rs b/15_virtual_mem_part3_precomputed_tables/kernel/tests/03_exception_restore_sanity.rs index a521a871..47dd2714 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/tests/03_exception_restore_sanity.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/tests/03_exception_restore_sanity.rs @@ -33,7 +33,7 @@ unsafe fn kernel_init() -> ! { use driver::interface::DriverManager; exception::handling_init(); - memory::mmu::post_enable_init(); + memory::init(); bsp::driver::driver_manager().qemu_bring_up_console(); // This line will be printed as the test header. diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/tests/04_exception_irq_sanity.rs b/15_virtual_mem_part3_precomputed_tables/kernel/tests/04_exception_irq_sanity.rs index cd2d29d6..7b9628d5 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/tests/04_exception_irq_sanity.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/tests/04_exception_irq_sanity.rs @@ -17,7 +17,7 @@ use test_macros::kernel_test; unsafe fn kernel_init() -> ! { use driver::interface::DriverManager; - memory::mmu::post_enable_init(); + memory::init(); bsp::driver::driver_manager().qemu_bring_up_console(); exception::handling_init(); diff --git a/16_virtual_mem_part4_higher_half_kernel/README.md b/16_virtual_mem_part4_higher_half_kernel/README.md index 943273c0..0a30a2aa 100644 --- a/16_virtual_mem_part4_higher_half_kernel/README.md +++ b/16_virtual_mem_part4_higher_half_kernel/README.md @@ -729,7 +729,7 @@ diff -uNr 15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/mem diff -uNr 15_virtual_mem_part3_precomputed_tables/kernel/src/lib.rs 16_virtual_mem_part4_higher_half_kernel/kernel/src/lib.rs --- 15_virtual_mem_part3_precomputed_tables/kernel/src/lib.rs +++ 16_virtual_mem_part4_higher_half_kernel/kernel/src/lib.rs -@@ -153,11 +153,6 @@ +@@ -154,11 +154,6 @@ ) } diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/common.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/common.rs index 678f4a6c..f32f650f 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/common.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/common.rs @@ -27,3 +27,20 @@ pub const fn align_up(value: usize, alignment: usize) -> usize { (value + alignment - 1) & !(alignment - 1) } + +/// Convert a size into human readable format. +pub const fn size_human_readable_ceil(size: usize) -> (usize, &'static str) { + const KIB: usize = 1024; + const MIB: usize = 1024 * 1024; + const GIB: usize = 1024 * 1024 * 1024; + + if (size / GIB) > 0 { + (size.div_ceil(GIB), "GiB") + } else if (size / MIB) > 0 { + (size.div_ceil(MIB), "MiB") + } else if (size / KIB) > 0 { + (size.div_ceil(KIB), "KiB") + } else { + (size, "Byte") + } +} diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/console/null_console.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/console/null_console.rs index 10c3bedc..2c64d499 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/console/null_console.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/console/null_console.rs @@ -20,7 +20,7 @@ pub struct NullConsole; pub static NULL_CONSOLE: NullConsole = NullConsole {}; //-------------------------------------------------------------------------------------------------- -// Private Code +// Public Code //-------------------------------------------------------------------------------------------------- impl interface::Write for NullConsole { diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/lib.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/lib.rs index f023d683..1483c5a3 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/lib.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/lib.rs @@ -114,6 +114,7 @@ #![feature(core_intrinsics)] #![feature(format_args_nl)] #![feature(generic_const_exprs)] +#![feature(int_roundings)] #![feature(is_sorted)] #![feature(linkage)] #![feature(panic_info_message)] @@ -180,7 +181,7 @@ unsafe fn kernel_init() -> ! { use driver::interface::DriverManager; exception::handling_init(); - memory::mmu::post_enable_init(); + memory::init(); bsp::driver::driver_manager().qemu_bring_up_console(); test_main(); diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/main.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/main.rs index 928f12c2..9aeb4438 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/main.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/main.rs @@ -28,7 +28,7 @@ unsafe fn kernel_init() -> ! { use driver::interface::DriverManager; exception::handling_init(); - memory::mmu::post_enable_init(); + memory::init(); // Instantiate and init all device drivers. if let Err(x) = bsp::driver::driver_manager().instantiate_drivers() { diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/memory.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/memory.rs index 64d8cf64..3b6868e7 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/memory.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/memory.rs @@ -136,6 +136,11 @@ impl fmt::Display for Address { } } +/// Initialize the memory subsystem. +pub fn init() { + mmu::kernel_init_mmio_va_allocator(); +} + //-------------------------------------------------------------------------------------------------- // Testing //-------------------------------------------------------------------------------------------------- diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/memory/mmu.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/memory/mmu.rs index 8806a993..7f02dad9 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/memory/mmu.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/memory/mmu.rs @@ -82,14 +82,6 @@ use interface::MMU; use synchronization::interface::ReadWriteEx; use translation_table::interface::TranslationTable; -/// Query the BSP for the reserved virtual addresses for MMIO remapping and initialize the kernel's -/// MMIO VA allocator with it. -fn kernel_init_mmio_va_allocator() { - let region = bsp::memory::mmu::virt_mmio_remap_region(); - - page_alloc::kernel_mmio_va_allocator().lock(|allocator| allocator.initialize(region)); -} - /// Map a region in the kernel's translation tables. /// /// No input checks done, input is passed through to the architectural implementation. @@ -169,6 +161,14 @@ impl AddressSpace { } } +/// Query the BSP for the reserved virtual addresses for MMIO remapping and initialize the kernel's +/// MMIO VA allocator with it. +pub fn kernel_init_mmio_va_allocator() { + let region = bsp::memory::mmu::virt_mmio_remap_region(); + + page_alloc::kernel_mmio_va_allocator().lock(|allocator| allocator.init(region)); +} + /// Add an entry to the mapping info record. pub fn kernel_add_mapping_record( name: &'static str, @@ -247,6 +247,11 @@ pub fn try_kernel_page_attributes( .read(|tables| tables.try_page_attributes(virt_page_addr)) } +/// Human-readable print of all recorded kernel mappings. +pub fn kernel_print_mappings() { + mapping_record::kernel_print() +} + /// Enable the MMU and data + instruction caching. /// /// # Safety @@ -258,13 +263,3 @@ pub unsafe fn enable_mmu_and_caching( ) -> Result<(), MMUEnableError> { arch_mmu::mmu().enable_mmu_and_caching(phys_tables_base_addr) } - -/// Finish initialization of the MMU subsystem. -pub fn post_enable_init() { - kernel_init_mmio_va_allocator(); -} - -/// Human-readable print of all recorded kernel mappings. -pub fn kernel_print_mappings() { - mapping_record::kernel_print() -} diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/memory/mmu/mapping_record.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/memory/mmu/mapping_record.rs index 7d3a6c60..5bc32445 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/memory/mmu/mapping_record.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/memory/mmu/mapping_record.rs @@ -8,7 +8,7 @@ use super::{ AccessPermissions, Address, AttributeFields, MMIODescriptor, MemAttributes, MemoryRegion, Physical, Virtual, }; -use crate::{bsp, info, synchronization, synchronization::InitStateLock, warn}; +use crate::{bsp, common, info, synchronization, synchronization::InitStateLock, warn}; //-------------------------------------------------------------------------------------------------- // Private Definitions @@ -141,9 +141,6 @@ impl MappingRecord { } pub fn print(&self) { - const KIB_RSHIFT: u32 = 10; // log2(1024). - const MIB_RSHIFT: u32 = 20; // log2(1024 * 1024). - info!(" -------------------------------------------------------------------------------------------------------------------------------------------"); info!( " {:^44} {:^30} {:^7} {:^9} {:^35}", @@ -158,13 +155,7 @@ impl MappingRecord { let phys_start = i.phys_start_addr; let phys_end_inclusive = phys_start + (size - 1); - let (size, unit) = if (size >> MIB_RSHIFT) > 0 { - (size >> MIB_RSHIFT, "MiB") - } else if (size >> KIB_RSHIFT) > 0 { - (size >> KIB_RSHIFT, "KiB") - } else { - (size, "Byte") - }; + let (size, unit) = common::size_human_readable_ceil(size); let attr = match i.attribute_fields.mem_attributes { MemAttributes::CacheableDRAM => "C", @@ -183,8 +174,7 @@ impl MappingRecord { }; info!( - " {}..{} --> {}..{} | \ - {: >3} {} | {: <3} {} {: <2} | {}", + " {}..{} --> {}..{} | {:>3} {} | {:<3} {} {:<2} | {}", virt_start, virt_end_inclusive, phys_start, diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/memory/mmu/page_alloc.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/memory/mmu/page_alloc.rs index b4c4232c..347fcd34 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/memory/mmu/page_alloc.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/memory/mmu/page_alloc.rs @@ -44,7 +44,7 @@ impl PageAllocator { } /// Initialize the allocator. - pub fn initialize(&mut self, pool: MemoryRegion) { + pub fn init(&mut self, pool: MemoryRegion) { if self.pool.is_some() { warn!("Already initialized"); return; diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/tests/00_console_sanity.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/tests/00_console_sanity.rs index f2a1f3ed..305510ce 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/tests/00_console_sanity.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/tests/00_console_sanity.rs @@ -19,7 +19,7 @@ unsafe fn kernel_init() -> ! { use driver::interface::DriverManager; exception::handling_init(); - memory::mmu::post_enable_init(); + memory::init(); bsp::driver::driver_manager().qemu_bring_up_console(); // Handshake diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/tests/01_timer_sanity.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/tests/01_timer_sanity.rs index caeca3cd..d5d76a5c 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/tests/01_timer_sanity.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/tests/01_timer_sanity.rs @@ -19,7 +19,7 @@ unsafe fn kernel_init() -> ! { use driver::interface::DriverManager; exception::handling_init(); - memory::mmu::post_enable_init(); + memory::init(); bsp::driver::driver_manager().qemu_bring_up_console(); // Depending on CPU arch, some timer bring-up code could go here. Not needed for the RPi. diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/tests/02_exception_sync_page_fault.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/tests/02_exception_sync_page_fault.rs index 33463e0a..a6d15b69 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/tests/02_exception_sync_page_fault.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/tests/02_exception_sync_page_fault.rs @@ -24,7 +24,7 @@ unsafe fn kernel_init() -> ! { use driver::interface::DriverManager; exception::handling_init(); - memory::mmu::post_enable_init(); + memory::init(); bsp::driver::driver_manager().qemu_bring_up_console(); // This line will be printed as the test header. diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/tests/03_exception_restore_sanity.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/tests/03_exception_restore_sanity.rs index a521a871..47dd2714 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/tests/03_exception_restore_sanity.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/tests/03_exception_restore_sanity.rs @@ -33,7 +33,7 @@ unsafe fn kernel_init() -> ! { use driver::interface::DriverManager; exception::handling_init(); - memory::mmu::post_enable_init(); + memory::init(); bsp::driver::driver_manager().qemu_bring_up_console(); // This line will be printed as the test header. diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/tests/04_exception_irq_sanity.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/tests/04_exception_irq_sanity.rs index cd2d29d6..7b9628d5 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/tests/04_exception_irq_sanity.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/tests/04_exception_irq_sanity.rs @@ -17,7 +17,7 @@ use test_macros::kernel_test; unsafe fn kernel_init() -> ! { use driver::interface::DriverManager; - memory::mmu::post_enable_init(); + memory::init(); bsp::driver::driver_manager().qemu_bring_up_console(); exception::handling_init(); diff --git a/17_kernel_symbols/README.md b/17_kernel_symbols/README.md index 84378fff..d3b42b65 100644 --- a/17_kernel_symbols/README.md +++ b/17_kernel_symbols/README.md @@ -332,7 +332,7 @@ diff -uNr 16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi/mem diff -uNr 16_virtual_mem_part4_higher_half_kernel/kernel/src/lib.rs 17_kernel_symbols/kernel/src/lib.rs --- 16_virtual_mem_part4_higher_half_kernel/kernel/src/lib.rs +++ 17_kernel_symbols/kernel/src/lib.rs -@@ -138,6 +138,7 @@ +@@ -139,6 +139,7 @@ pub mod memory; pub mod print; pub mod state; diff --git a/17_kernel_symbols/kernel/src/common.rs b/17_kernel_symbols/kernel/src/common.rs index 678f4a6c..f32f650f 100644 --- a/17_kernel_symbols/kernel/src/common.rs +++ b/17_kernel_symbols/kernel/src/common.rs @@ -27,3 +27,20 @@ pub const fn align_up(value: usize, alignment: usize) -> usize { (value + alignment - 1) & !(alignment - 1) } + +/// Convert a size into human readable format. +pub const fn size_human_readable_ceil(size: usize) -> (usize, &'static str) { + const KIB: usize = 1024; + const MIB: usize = 1024 * 1024; + const GIB: usize = 1024 * 1024 * 1024; + + if (size / GIB) > 0 { + (size.div_ceil(GIB), "GiB") + } else if (size / MIB) > 0 { + (size.div_ceil(MIB), "MiB") + } else if (size / KIB) > 0 { + (size.div_ceil(KIB), "KiB") + } else { + (size, "Byte") + } +} diff --git a/17_kernel_symbols/kernel/src/console/null_console.rs b/17_kernel_symbols/kernel/src/console/null_console.rs index 10c3bedc..2c64d499 100644 --- a/17_kernel_symbols/kernel/src/console/null_console.rs +++ b/17_kernel_symbols/kernel/src/console/null_console.rs @@ -20,7 +20,7 @@ pub struct NullConsole; pub static NULL_CONSOLE: NullConsole = NullConsole {}; //-------------------------------------------------------------------------------------------------- -// Private Code +// Public Code //-------------------------------------------------------------------------------------------------- impl interface::Write for NullConsole { diff --git a/17_kernel_symbols/kernel/src/lib.rs b/17_kernel_symbols/kernel/src/lib.rs index e70468e5..1f6d11b1 100644 --- a/17_kernel_symbols/kernel/src/lib.rs +++ b/17_kernel_symbols/kernel/src/lib.rs @@ -114,6 +114,7 @@ #![feature(core_intrinsics)] #![feature(format_args_nl)] #![feature(generic_const_exprs)] +#![feature(int_roundings)] #![feature(is_sorted)] #![feature(linkage)] #![feature(panic_info_message)] @@ -181,7 +182,7 @@ unsafe fn kernel_init() -> ! { use driver::interface::DriverManager; exception::handling_init(); - memory::mmu::post_enable_init(); + memory::init(); bsp::driver::driver_manager().qemu_bring_up_console(); test_main(); diff --git a/17_kernel_symbols/kernel/src/main.rs b/17_kernel_symbols/kernel/src/main.rs index 928f12c2..9aeb4438 100644 --- a/17_kernel_symbols/kernel/src/main.rs +++ b/17_kernel_symbols/kernel/src/main.rs @@ -28,7 +28,7 @@ unsafe fn kernel_init() -> ! { use driver::interface::DriverManager; exception::handling_init(); - memory::mmu::post_enable_init(); + memory::init(); // Instantiate and init all device drivers. if let Err(x) = bsp::driver::driver_manager().instantiate_drivers() { diff --git a/17_kernel_symbols/kernel/src/memory.rs b/17_kernel_symbols/kernel/src/memory.rs index 64d8cf64..3b6868e7 100644 --- a/17_kernel_symbols/kernel/src/memory.rs +++ b/17_kernel_symbols/kernel/src/memory.rs @@ -136,6 +136,11 @@ impl fmt::Display for Address { } } +/// Initialize the memory subsystem. +pub fn init() { + mmu::kernel_init_mmio_va_allocator(); +} + //-------------------------------------------------------------------------------------------------- // Testing //-------------------------------------------------------------------------------------------------- diff --git a/17_kernel_symbols/kernel/src/memory/mmu.rs b/17_kernel_symbols/kernel/src/memory/mmu.rs index 8806a993..7f02dad9 100644 --- a/17_kernel_symbols/kernel/src/memory/mmu.rs +++ b/17_kernel_symbols/kernel/src/memory/mmu.rs @@ -82,14 +82,6 @@ use interface::MMU; use synchronization::interface::ReadWriteEx; use translation_table::interface::TranslationTable; -/// Query the BSP for the reserved virtual addresses for MMIO remapping and initialize the kernel's -/// MMIO VA allocator with it. -fn kernel_init_mmio_va_allocator() { - let region = bsp::memory::mmu::virt_mmio_remap_region(); - - page_alloc::kernel_mmio_va_allocator().lock(|allocator| allocator.initialize(region)); -} - /// Map a region in the kernel's translation tables. /// /// No input checks done, input is passed through to the architectural implementation. @@ -169,6 +161,14 @@ impl AddressSpace { } } +/// Query the BSP for the reserved virtual addresses for MMIO remapping and initialize the kernel's +/// MMIO VA allocator with it. +pub fn kernel_init_mmio_va_allocator() { + let region = bsp::memory::mmu::virt_mmio_remap_region(); + + page_alloc::kernel_mmio_va_allocator().lock(|allocator| allocator.init(region)); +} + /// Add an entry to the mapping info record. pub fn kernel_add_mapping_record( name: &'static str, @@ -247,6 +247,11 @@ pub fn try_kernel_page_attributes( .read(|tables| tables.try_page_attributes(virt_page_addr)) } +/// Human-readable print of all recorded kernel mappings. +pub fn kernel_print_mappings() { + mapping_record::kernel_print() +} + /// Enable the MMU and data + instruction caching. /// /// # Safety @@ -258,13 +263,3 @@ pub unsafe fn enable_mmu_and_caching( ) -> Result<(), MMUEnableError> { arch_mmu::mmu().enable_mmu_and_caching(phys_tables_base_addr) } - -/// Finish initialization of the MMU subsystem. -pub fn post_enable_init() { - kernel_init_mmio_va_allocator(); -} - -/// Human-readable print of all recorded kernel mappings. -pub fn kernel_print_mappings() { - mapping_record::kernel_print() -} diff --git a/17_kernel_symbols/kernel/src/memory/mmu/mapping_record.rs b/17_kernel_symbols/kernel/src/memory/mmu/mapping_record.rs index 7d3a6c60..5bc32445 100644 --- a/17_kernel_symbols/kernel/src/memory/mmu/mapping_record.rs +++ b/17_kernel_symbols/kernel/src/memory/mmu/mapping_record.rs @@ -8,7 +8,7 @@ use super::{ AccessPermissions, Address, AttributeFields, MMIODescriptor, MemAttributes, MemoryRegion, Physical, Virtual, }; -use crate::{bsp, info, synchronization, synchronization::InitStateLock, warn}; +use crate::{bsp, common, info, synchronization, synchronization::InitStateLock, warn}; //-------------------------------------------------------------------------------------------------- // Private Definitions @@ -141,9 +141,6 @@ impl MappingRecord { } pub fn print(&self) { - const KIB_RSHIFT: u32 = 10; // log2(1024). - const MIB_RSHIFT: u32 = 20; // log2(1024 * 1024). - info!(" -------------------------------------------------------------------------------------------------------------------------------------------"); info!( " {:^44} {:^30} {:^7} {:^9} {:^35}", @@ -158,13 +155,7 @@ impl MappingRecord { let phys_start = i.phys_start_addr; let phys_end_inclusive = phys_start + (size - 1); - let (size, unit) = if (size >> MIB_RSHIFT) > 0 { - (size >> MIB_RSHIFT, "MiB") - } else if (size >> KIB_RSHIFT) > 0 { - (size >> KIB_RSHIFT, "KiB") - } else { - (size, "Byte") - }; + let (size, unit) = common::size_human_readable_ceil(size); let attr = match i.attribute_fields.mem_attributes { MemAttributes::CacheableDRAM => "C", @@ -183,8 +174,7 @@ impl MappingRecord { }; info!( - " {}..{} --> {}..{} | \ - {: >3} {} | {: <3} {} {: <2} | {}", + " {}..{} --> {}..{} | {:>3} {} | {:<3} {} {:<2} | {}", virt_start, virt_end_inclusive, phys_start, diff --git a/17_kernel_symbols/kernel/src/memory/mmu/page_alloc.rs b/17_kernel_symbols/kernel/src/memory/mmu/page_alloc.rs index b4c4232c..347fcd34 100644 --- a/17_kernel_symbols/kernel/src/memory/mmu/page_alloc.rs +++ b/17_kernel_symbols/kernel/src/memory/mmu/page_alloc.rs @@ -44,7 +44,7 @@ impl PageAllocator { } /// Initialize the allocator. - pub fn initialize(&mut self, pool: MemoryRegion) { + pub fn init(&mut self, pool: MemoryRegion) { if self.pool.is_some() { warn!("Already initialized"); return; diff --git a/17_kernel_symbols/kernel/tests/00_console_sanity.rs b/17_kernel_symbols/kernel/tests/00_console_sanity.rs index f2a1f3ed..305510ce 100644 --- a/17_kernel_symbols/kernel/tests/00_console_sanity.rs +++ b/17_kernel_symbols/kernel/tests/00_console_sanity.rs @@ -19,7 +19,7 @@ unsafe fn kernel_init() -> ! { use driver::interface::DriverManager; exception::handling_init(); - memory::mmu::post_enable_init(); + memory::init(); bsp::driver::driver_manager().qemu_bring_up_console(); // Handshake diff --git a/17_kernel_symbols/kernel/tests/01_timer_sanity.rs b/17_kernel_symbols/kernel/tests/01_timer_sanity.rs index caeca3cd..d5d76a5c 100644 --- a/17_kernel_symbols/kernel/tests/01_timer_sanity.rs +++ b/17_kernel_symbols/kernel/tests/01_timer_sanity.rs @@ -19,7 +19,7 @@ unsafe fn kernel_init() -> ! { use driver::interface::DriverManager; exception::handling_init(); - memory::mmu::post_enable_init(); + memory::init(); bsp::driver::driver_manager().qemu_bring_up_console(); // Depending on CPU arch, some timer bring-up code could go here. Not needed for the RPi. diff --git a/17_kernel_symbols/kernel/tests/02_exception_sync_page_fault.rs b/17_kernel_symbols/kernel/tests/02_exception_sync_page_fault.rs index 33463e0a..a6d15b69 100644 --- a/17_kernel_symbols/kernel/tests/02_exception_sync_page_fault.rs +++ b/17_kernel_symbols/kernel/tests/02_exception_sync_page_fault.rs @@ -24,7 +24,7 @@ unsafe fn kernel_init() -> ! { use driver::interface::DriverManager; exception::handling_init(); - memory::mmu::post_enable_init(); + memory::init(); bsp::driver::driver_manager().qemu_bring_up_console(); // This line will be printed as the test header. diff --git a/17_kernel_symbols/kernel/tests/03_exception_restore_sanity.rs b/17_kernel_symbols/kernel/tests/03_exception_restore_sanity.rs index a521a871..47dd2714 100644 --- a/17_kernel_symbols/kernel/tests/03_exception_restore_sanity.rs +++ b/17_kernel_symbols/kernel/tests/03_exception_restore_sanity.rs @@ -33,7 +33,7 @@ unsafe fn kernel_init() -> ! { use driver::interface::DriverManager; exception::handling_init(); - memory::mmu::post_enable_init(); + memory::init(); bsp::driver::driver_manager().qemu_bring_up_console(); // This line will be printed as the test header. diff --git a/17_kernel_symbols/kernel/tests/04_exception_irq_sanity.rs b/17_kernel_symbols/kernel/tests/04_exception_irq_sanity.rs index cd2d29d6..7b9628d5 100644 --- a/17_kernel_symbols/kernel/tests/04_exception_irq_sanity.rs +++ b/17_kernel_symbols/kernel/tests/04_exception_irq_sanity.rs @@ -17,7 +17,7 @@ use test_macros::kernel_test; unsafe fn kernel_init() -> ! { use driver::interface::DriverManager; - memory::mmu::post_enable_init(); + memory::init(); bsp::driver::driver_manager().qemu_bring_up_console(); exception::handling_init(); diff --git a/18_backtrace/README.md b/18_backtrace/README.md index fd173703..2c4dc127 100644 --- a/18_backtrace/README.md +++ b/18_backtrace/README.md @@ -727,7 +727,7 @@ diff -uNr 17_kernel_symbols/kernel/src/_arch/aarch64/exception.s 18_backtrace/ke diff -uNr 17_kernel_symbols/kernel/src/backtrace.rs 18_backtrace/kernel/src/backtrace.rs --- 17_kernel_symbols/kernel/src/backtrace.rs +++ 18_backtrace/kernel/src/backtrace.rs -@@ -0,0 +1,112 @@ +@@ -0,0 +1,114 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2022 Andre Richter @@ -790,7 +790,9 @@ diff -uNr 17_kernel_symbols/kernel/src/backtrace.rs 18_backtrace/kernel/src/back + |maybe_iter: Option<&mut dyn Iterator>| match maybe_iter { + None => fmt_res = writeln!(f, "ERROR! No valid stack frame found"), + Some(iter) => { -+ for (i, backtrace_res) in iter.enumerate() { ++ // Since the backtrace is printed, the first function is always ++ // core::fmt::write. Skip 1 so it is excluded and doesn't bloat the output. ++ for (i, backtrace_res) in iter.skip(1).enumerate() { + match backtrace_res { + BacktraceItem::InvalidFramePointer(addr) => { + fmt_res = writeln!( @@ -909,7 +911,7 @@ diff -uNr 17_kernel_symbols/kernel/src/bsp/raspberrypi/memory/mmu.rs 18_backtrac diff -uNr 17_kernel_symbols/kernel/src/lib.rs 18_backtrace/kernel/src/lib.rs --- 17_kernel_symbols/kernel/src/lib.rs +++ 18_backtrace/kernel/src/lib.rs -@@ -129,6 +129,7 @@ +@@ -130,6 +130,7 @@ mod panic_wait; mod synchronization; @@ -1062,7 +1064,7 @@ diff -uNr 17_kernel_symbols/kernel/tests/05_backtrace_sanity.rs 18_backtrace/ker + use driver::interface::DriverManager; + + exception::handling_init(); -+ memory::mmu::post_enable_init(); ++ memory::init(); + bsp::driver::driver_manager().qemu_bring_up_console(); + + nested(); @@ -1133,7 +1135,7 @@ diff -uNr 17_kernel_symbols/kernel/tests/06_backtrace_invalid_frame.rs 18_backtr + use driver::interface::DriverManager; + + exception::handling_init(); -+ memory::mmu::post_enable_init(); ++ memory::init(); + bsp::driver::driver_manager().qemu_bring_up_console(); + + nested(); @@ -1208,7 +1210,7 @@ diff -uNr 17_kernel_symbols/kernel/tests/07_backtrace_invalid_link.rs 18_backtra + use driver::interface::DriverManager; + + exception::handling_init(); -+ memory::mmu::post_enable_init(); ++ memory::init(); + bsp::driver::driver_manager().qemu_bring_up_console(); + + nested_1(); @@ -1264,4 +1266,50 @@ diff -uNr 17_kernel_symbols/Makefile 18_backtrace/Makefile $(call color_header, "Launching GDB") @$(DOCKER_GDB) gdb-multiarch -q $(KERNEL_ELF) +diff -uNr 17_kernel_symbols/tools/translation_table_tool/bsp.rb 18_backtrace/tools/translation_table_tool/bsp.rb +--- 17_kernel_symbols/tools/translation_table_tool/bsp.rb ++++ 18_backtrace/tools/translation_table_tool/bsp.rb +@@ -45,6 +45,10 @@ + raise + end + +- x.scan(/\d+/).join.to_i(16) ++ # Extract the hex literal with underscores like 0x0123_abcd. ++ x = x.scan(/0x[\h_]*/)[0] ++ ++ # Further remove x and _ and convert to int. ++ x.scan(/\h+/).join.to_i(16) + end + end + +diff -uNr 17_kernel_symbols/tools/translation_table_tool/generic.rb 18_backtrace/tools/translation_table_tool/generic.rb +--- 17_kernel_symbols/tools/translation_table_tool/generic.rb ++++ 18_backtrace/tools/translation_table_tool/generic.rb +@@ -109,13 +109,23 @@ + @attributes = attributes + end + ++ def size_human_readable(size) ++ if size >= (1024 * 1024) ++ "#{(size / (1024 * 1024)).to_s.rjust(3)} MiB" ++ elsif size >= 1024 ++ "#{(size / 1024).to_s.rjust(3)} KiB" ++ else ++ raise ++ end ++ end ++ + def to_s + name = @name.ljust(self.class.max_section_name_length) + virt_start = @virt_region.first.to_hex_underscore(with_leading_zeros: true) + phys_start = @phys_region.first.to_hex_underscore(with_leading_zeros: true) +- size = ((@virt_region.size * 65_536) / 1024).to_s.rjust(3) ++ size = size_human_readable(@virt_region.size * 65_536) + +- "#{name} | #{virt_start} | #{phys_start} | #{size} KiB | #{@attributes}" ++ "#{name} | #{virt_start} | #{phys_start} | #{size} | #{@attributes}" + end + + def self.print_divider + ``` diff --git a/18_backtrace/kernel/src/backtrace.rs b/18_backtrace/kernel/src/backtrace.rs index 7dba2e4a..22de6c48 100644 --- a/18_backtrace/kernel/src/backtrace.rs +++ b/18_backtrace/kernel/src/backtrace.rs @@ -60,7 +60,9 @@ impl fmt::Display for Backtrace { |maybe_iter: Option<&mut dyn Iterator>| match maybe_iter { None => fmt_res = writeln!(f, "ERROR! No valid stack frame found"), Some(iter) => { - for (i, backtrace_res) in iter.enumerate() { + // Since the backtrace is printed, the first function is always + // core::fmt::write. Skip 1 so it is excluded and doesn't bloat the output. + for (i, backtrace_res) in iter.skip(1).enumerate() { match backtrace_res { BacktraceItem::InvalidFramePointer(addr) => { fmt_res = writeln!( diff --git a/18_backtrace/kernel/src/common.rs b/18_backtrace/kernel/src/common.rs index 678f4a6c..f32f650f 100644 --- a/18_backtrace/kernel/src/common.rs +++ b/18_backtrace/kernel/src/common.rs @@ -27,3 +27,20 @@ pub const fn align_up(value: usize, alignment: usize) -> usize { (value + alignment - 1) & !(alignment - 1) } + +/// Convert a size into human readable format. +pub const fn size_human_readable_ceil(size: usize) -> (usize, &'static str) { + const KIB: usize = 1024; + const MIB: usize = 1024 * 1024; + const GIB: usize = 1024 * 1024 * 1024; + + if (size / GIB) > 0 { + (size.div_ceil(GIB), "GiB") + } else if (size / MIB) > 0 { + (size.div_ceil(MIB), "MiB") + } else if (size / KIB) > 0 { + (size.div_ceil(KIB), "KiB") + } else { + (size, "Byte") + } +} diff --git a/18_backtrace/kernel/src/console/null_console.rs b/18_backtrace/kernel/src/console/null_console.rs index 10c3bedc..2c64d499 100644 --- a/18_backtrace/kernel/src/console/null_console.rs +++ b/18_backtrace/kernel/src/console/null_console.rs @@ -20,7 +20,7 @@ pub struct NullConsole; pub static NULL_CONSOLE: NullConsole = NullConsole {}; //-------------------------------------------------------------------------------------------------- -// Private Code +// Public Code //-------------------------------------------------------------------------------------------------- impl interface::Write for NullConsole { diff --git a/18_backtrace/kernel/src/lib.rs b/18_backtrace/kernel/src/lib.rs index 688fc1a4..2c13a342 100644 --- a/18_backtrace/kernel/src/lib.rs +++ b/18_backtrace/kernel/src/lib.rs @@ -114,6 +114,7 @@ #![feature(core_intrinsics)] #![feature(format_args_nl)] #![feature(generic_const_exprs)] +#![feature(int_roundings)] #![feature(is_sorted)] #![feature(linkage)] #![feature(panic_info_message)] @@ -182,7 +183,7 @@ unsafe fn kernel_init() -> ! { use driver::interface::DriverManager; exception::handling_init(); - memory::mmu::post_enable_init(); + memory::init(); bsp::driver::driver_manager().qemu_bring_up_console(); test_main(); diff --git a/18_backtrace/kernel/src/main.rs b/18_backtrace/kernel/src/main.rs index 928f12c2..9aeb4438 100644 --- a/18_backtrace/kernel/src/main.rs +++ b/18_backtrace/kernel/src/main.rs @@ -28,7 +28,7 @@ unsafe fn kernel_init() -> ! { use driver::interface::DriverManager; exception::handling_init(); - memory::mmu::post_enable_init(); + memory::init(); // Instantiate and init all device drivers. if let Err(x) = bsp::driver::driver_manager().instantiate_drivers() { diff --git a/18_backtrace/kernel/src/memory.rs b/18_backtrace/kernel/src/memory.rs index 34c34429..840db396 100644 --- a/18_backtrace/kernel/src/memory.rs +++ b/18_backtrace/kernel/src/memory.rs @@ -160,6 +160,11 @@ impl fmt::Display for Address { } } +/// Initialize the memory subsystem. +pub fn init() { + mmu::kernel_init_mmio_va_allocator(); +} + //-------------------------------------------------------------------------------------------------- // Testing //-------------------------------------------------------------------------------------------------- diff --git a/18_backtrace/kernel/src/memory/mmu.rs b/18_backtrace/kernel/src/memory/mmu.rs index 8806a993..7f02dad9 100644 --- a/18_backtrace/kernel/src/memory/mmu.rs +++ b/18_backtrace/kernel/src/memory/mmu.rs @@ -82,14 +82,6 @@ use interface::MMU; use synchronization::interface::ReadWriteEx; use translation_table::interface::TranslationTable; -/// Query the BSP for the reserved virtual addresses for MMIO remapping and initialize the kernel's -/// MMIO VA allocator with it. -fn kernel_init_mmio_va_allocator() { - let region = bsp::memory::mmu::virt_mmio_remap_region(); - - page_alloc::kernel_mmio_va_allocator().lock(|allocator| allocator.initialize(region)); -} - /// Map a region in the kernel's translation tables. /// /// No input checks done, input is passed through to the architectural implementation. @@ -169,6 +161,14 @@ impl AddressSpace { } } +/// Query the BSP for the reserved virtual addresses for MMIO remapping and initialize the kernel's +/// MMIO VA allocator with it. +pub fn kernel_init_mmio_va_allocator() { + let region = bsp::memory::mmu::virt_mmio_remap_region(); + + page_alloc::kernel_mmio_va_allocator().lock(|allocator| allocator.init(region)); +} + /// Add an entry to the mapping info record. pub fn kernel_add_mapping_record( name: &'static str, @@ -247,6 +247,11 @@ pub fn try_kernel_page_attributes( .read(|tables| tables.try_page_attributes(virt_page_addr)) } +/// Human-readable print of all recorded kernel mappings. +pub fn kernel_print_mappings() { + mapping_record::kernel_print() +} + /// Enable the MMU and data + instruction caching. /// /// # Safety @@ -258,13 +263,3 @@ pub unsafe fn enable_mmu_and_caching( ) -> Result<(), MMUEnableError> { arch_mmu::mmu().enable_mmu_and_caching(phys_tables_base_addr) } - -/// Finish initialization of the MMU subsystem. -pub fn post_enable_init() { - kernel_init_mmio_va_allocator(); -} - -/// Human-readable print of all recorded kernel mappings. -pub fn kernel_print_mappings() { - mapping_record::kernel_print() -} diff --git a/18_backtrace/kernel/src/memory/mmu/mapping_record.rs b/18_backtrace/kernel/src/memory/mmu/mapping_record.rs index 7d3a6c60..5bc32445 100644 --- a/18_backtrace/kernel/src/memory/mmu/mapping_record.rs +++ b/18_backtrace/kernel/src/memory/mmu/mapping_record.rs @@ -8,7 +8,7 @@ use super::{ AccessPermissions, Address, AttributeFields, MMIODescriptor, MemAttributes, MemoryRegion, Physical, Virtual, }; -use crate::{bsp, info, synchronization, synchronization::InitStateLock, warn}; +use crate::{bsp, common, info, synchronization, synchronization::InitStateLock, warn}; //-------------------------------------------------------------------------------------------------- // Private Definitions @@ -141,9 +141,6 @@ impl MappingRecord { } pub fn print(&self) { - const KIB_RSHIFT: u32 = 10; // log2(1024). - const MIB_RSHIFT: u32 = 20; // log2(1024 * 1024). - info!(" -------------------------------------------------------------------------------------------------------------------------------------------"); info!( " {:^44} {:^30} {:^7} {:^9} {:^35}", @@ -158,13 +155,7 @@ impl MappingRecord { let phys_start = i.phys_start_addr; let phys_end_inclusive = phys_start + (size - 1); - let (size, unit) = if (size >> MIB_RSHIFT) > 0 { - (size >> MIB_RSHIFT, "MiB") - } else if (size >> KIB_RSHIFT) > 0 { - (size >> KIB_RSHIFT, "KiB") - } else { - (size, "Byte") - }; + let (size, unit) = common::size_human_readable_ceil(size); let attr = match i.attribute_fields.mem_attributes { MemAttributes::CacheableDRAM => "C", @@ -183,8 +174,7 @@ impl MappingRecord { }; info!( - " {}..{} --> {}..{} | \ - {: >3} {} | {: <3} {} {: <2} | {}", + " {}..{} --> {}..{} | {:>3} {} | {:<3} {} {:<2} | {}", virt_start, virt_end_inclusive, phys_start, diff --git a/18_backtrace/kernel/src/memory/mmu/page_alloc.rs b/18_backtrace/kernel/src/memory/mmu/page_alloc.rs index b4c4232c..347fcd34 100644 --- a/18_backtrace/kernel/src/memory/mmu/page_alloc.rs +++ b/18_backtrace/kernel/src/memory/mmu/page_alloc.rs @@ -44,7 +44,7 @@ impl PageAllocator { } /// Initialize the allocator. - pub fn initialize(&mut self, pool: MemoryRegion) { + pub fn init(&mut self, pool: MemoryRegion) { if self.pool.is_some() { warn!("Already initialized"); return; diff --git a/18_backtrace/kernel/tests/00_console_sanity.rs b/18_backtrace/kernel/tests/00_console_sanity.rs index f2a1f3ed..305510ce 100644 --- a/18_backtrace/kernel/tests/00_console_sanity.rs +++ b/18_backtrace/kernel/tests/00_console_sanity.rs @@ -19,7 +19,7 @@ unsafe fn kernel_init() -> ! { use driver::interface::DriverManager; exception::handling_init(); - memory::mmu::post_enable_init(); + memory::init(); bsp::driver::driver_manager().qemu_bring_up_console(); // Handshake diff --git a/18_backtrace/kernel/tests/01_timer_sanity.rs b/18_backtrace/kernel/tests/01_timer_sanity.rs index caeca3cd..d5d76a5c 100644 --- a/18_backtrace/kernel/tests/01_timer_sanity.rs +++ b/18_backtrace/kernel/tests/01_timer_sanity.rs @@ -19,7 +19,7 @@ unsafe fn kernel_init() -> ! { use driver::interface::DriverManager; exception::handling_init(); - memory::mmu::post_enable_init(); + memory::init(); bsp::driver::driver_manager().qemu_bring_up_console(); // Depending on CPU arch, some timer bring-up code could go here. Not needed for the RPi. diff --git a/18_backtrace/kernel/tests/02_exception_sync_page_fault.rs b/18_backtrace/kernel/tests/02_exception_sync_page_fault.rs index 33463e0a..a6d15b69 100644 --- a/18_backtrace/kernel/tests/02_exception_sync_page_fault.rs +++ b/18_backtrace/kernel/tests/02_exception_sync_page_fault.rs @@ -24,7 +24,7 @@ unsafe fn kernel_init() -> ! { use driver::interface::DriverManager; exception::handling_init(); - memory::mmu::post_enable_init(); + memory::init(); bsp::driver::driver_manager().qemu_bring_up_console(); // This line will be printed as the test header. diff --git a/18_backtrace/kernel/tests/03_exception_restore_sanity.rs b/18_backtrace/kernel/tests/03_exception_restore_sanity.rs index a521a871..47dd2714 100644 --- a/18_backtrace/kernel/tests/03_exception_restore_sanity.rs +++ b/18_backtrace/kernel/tests/03_exception_restore_sanity.rs @@ -33,7 +33,7 @@ unsafe fn kernel_init() -> ! { use driver::interface::DriverManager; exception::handling_init(); - memory::mmu::post_enable_init(); + memory::init(); bsp::driver::driver_manager().qemu_bring_up_console(); // This line will be printed as the test header. diff --git a/18_backtrace/kernel/tests/04_exception_irq_sanity.rs b/18_backtrace/kernel/tests/04_exception_irq_sanity.rs index cd2d29d6..7b9628d5 100644 --- a/18_backtrace/kernel/tests/04_exception_irq_sanity.rs +++ b/18_backtrace/kernel/tests/04_exception_irq_sanity.rs @@ -17,7 +17,7 @@ use test_macros::kernel_test; unsafe fn kernel_init() -> ! { use driver::interface::DriverManager; - memory::mmu::post_enable_init(); + memory::init(); bsp::driver::driver_manager().qemu_bring_up_console(); exception::handling_init(); diff --git a/18_backtrace/kernel/tests/05_backtrace_sanity.rs b/18_backtrace/kernel/tests/05_backtrace_sanity.rs index 4475fafd..ea425f68 100644 --- a/18_backtrace/kernel/tests/05_backtrace_sanity.rs +++ b/18_backtrace/kernel/tests/05_backtrace_sanity.rs @@ -23,7 +23,7 @@ unsafe fn kernel_init() -> ! { use driver::interface::DriverManager; exception::handling_init(); - memory::mmu::post_enable_init(); + memory::init(); bsp::driver::driver_manager().qemu_bring_up_console(); nested(); diff --git a/18_backtrace/kernel/tests/06_backtrace_invalid_frame.rs b/18_backtrace/kernel/tests/06_backtrace_invalid_frame.rs index 74dad8d8..8769c7b6 100644 --- a/18_backtrace/kernel/tests/06_backtrace_invalid_frame.rs +++ b/18_backtrace/kernel/tests/06_backtrace_invalid_frame.rs @@ -25,7 +25,7 @@ unsafe fn kernel_init() -> ! { use driver::interface::DriverManager; exception::handling_init(); - memory::mmu::post_enable_init(); + memory::init(); bsp::driver::driver_manager().qemu_bring_up_console(); nested(); diff --git a/18_backtrace/kernel/tests/07_backtrace_invalid_link.rs b/18_backtrace/kernel/tests/07_backtrace_invalid_link.rs index ba6c9f57..28f3cdda 100644 --- a/18_backtrace/kernel/tests/07_backtrace_invalid_link.rs +++ b/18_backtrace/kernel/tests/07_backtrace_invalid_link.rs @@ -30,7 +30,7 @@ unsafe fn kernel_init() -> ! { use driver::interface::DriverManager; exception::handling_init(); - memory::mmu::post_enable_init(); + memory::init(); bsp::driver::driver_manager().qemu_bring_up_console(); nested_1(); diff --git a/18_backtrace/tools/translation_table_tool/bsp.rb b/18_backtrace/tools/translation_table_tool/bsp.rb index 536a2f21..dbab5ab6 100644 --- a/18_backtrace/tools/translation_table_tool/bsp.rb +++ b/18_backtrace/tools/translation_table_tool/bsp.rb @@ -45,6 +45,10 @@ class RaspberryPi raise end - x.scan(/\d+/).join.to_i(16) + # Extract the hex literal with underscores like 0x0123_abcd. + x = x.scan(/0x[\h_]*/)[0] + + # Further remove x and _ and convert to int. + x.scan(/\h+/).join.to_i(16) end end diff --git a/18_backtrace/tools/translation_table_tool/generic.rb b/18_backtrace/tools/translation_table_tool/generic.rb index 13df0658..eee8ccda 100644 --- a/18_backtrace/tools/translation_table_tool/generic.rb +++ b/18_backtrace/tools/translation_table_tool/generic.rb @@ -109,13 +109,23 @@ class MappingDescriptor @attributes = attributes end + def size_human_readable(size) + if size >= (1024 * 1024) + "#{(size / (1024 * 1024)).to_s.rjust(3)} MiB" + elsif size >= 1024 + "#{(size / 1024).to_s.rjust(3)} KiB" + else + raise + end + end + def to_s name = @name.ljust(self.class.max_section_name_length) virt_start = @virt_region.first.to_hex_underscore(with_leading_zeros: true) phys_start = @phys_region.first.to_hex_underscore(with_leading_zeros: true) - size = ((@virt_region.size * 65_536) / 1024).to_s.rjust(3) + size = size_human_readable(@virt_region.size * 65_536) - "#{name} | #{virt_start} | #{phys_start} | #{size} KiB | #{@attributes}" + "#{name} | #{virt_start} | #{phys_start} | #{size} | #{@attributes}" end def self.print_divider From 5f581cf86d60984d13e4752bf84dd66678342988 Mon Sep 17 00:00:00 2001 From: Andre Richter Date: Mon, 16 May 2022 22:27:06 +0200 Subject: [PATCH 32/75] Update README.md --- 03_hacky_hello_world/README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/03_hacky_hello_world/README.md b/03_hacky_hello_world/README.md index 71293c56..0f9e9c85 100644 --- a/03_hacky_hello_world/README.md +++ b/03_hacky_hello_world/README.md @@ -2,16 +2,17 @@ ## tl;dr -- Introducing global `print!()` macros to enable "printf debugging" at the earliest. +- Introducing global `println!()` macros to enable "printf debugging" at the earliest. - To keep tutorial length reasonable, printing functions for now "abuse" a QEMU property that lets us use the Raspberry's `UART` without setting it up properly. - Using the real hardware `UART` is enabled step-by-step in following tutorials. ## Notable additions -- `src/console.rs` introduces interface `Traits` for console commands. +- `src/console.rs` introduces interface `Traits` for console commands and a global reference to the + kernel's console through `console::console()`. - `src/bsp/raspberrypi/console.rs` implements the interface for QEMU's emulated UART. -- The panic handler makes use of the new `print!()` to display user error messages. +- The panic handler makes use of the new `println!()` to display user error messages. - There is a new Makefile target, `make test`, intended for automated testing. It boots the compiled kernel in `QEMU`, and checks for an expected output string produced by the kernel. - In this tutorial, it checks for the string `Stopping here`, which is emitted by the `panic!()` From 99e937c4de5a6be6de4f0b3c35104e5c77cb0069 Mon Sep 17 00:00:00 2001 From: Andre Richter Date: Mon, 16 May 2022 22:28:34 +0200 Subject: [PATCH 33/75] Update README.md --- 03_hacky_hello_world/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/03_hacky_hello_world/README.md b/03_hacky_hello_world/README.md index 0f9e9c85..348e626a 100644 --- a/03_hacky_hello_world/README.md +++ b/03_hacky_hello_world/README.md @@ -9,7 +9,7 @@ ## Notable additions -- `src/console.rs` introduces interface `Traits` for console commands and a global reference to the +- `src/console.rs` introduces interface `Traits` for console commands and global access to the kernel's console through `console::console()`. - `src/bsp/raspberrypi/console.rs` implements the interface for QEMU's emulated UART. - The panic handler makes use of the new `println!()` to display user error messages. From b0452e3a1fb7482911d88468de45307ae9b91e2c Mon Sep 17 00:00:00 2001 From: Andre Richter Date: Mon, 16 May 2022 23:01:47 +0200 Subject: [PATCH 34/75] More README fixes --- 13_exceptions_part2_peripheral_IRQs/README.md | 7 ++----- 14_virtual_mem_part2_mmio_remap/README.md | 4 ++-- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/13_exceptions_part2_peripheral_IRQs/README.md b/13_exceptions_part2_peripheral_IRQs/README.md index e2e2e169..634686d6 100644 --- a/13_exceptions_part2_peripheral_IRQs/README.md +++ b/13_exceptions_part2_peripheral_IRQs/README.md @@ -277,8 +277,7 @@ Here is the implementation for the `PL011Uart`: ```rust fn register_and_enable_irq_handler(&'static self) -> Result<(), &'static str> { - use bsp::exception::asynchronous::irq_manager; - use exception::asynchronous::{interface::IRQManager, IRQDescriptor}; + use exception::asynchronous::{irq_manager, IRQDescriptor}; let descriptor = IRQDescriptor { name: Self::COMPATIBLE, @@ -369,10 +368,8 @@ the the implementation of the trait's handling function: ```rust #[no_mangle] unsafe extern "C" fn current_elx_irq(_e: &mut ExceptionContext) { - use exception::asynchronous::interface::IRQManager; - let token = &exception::asynchronous::IRQContext::new(); - bsp::exception::asynchronous::irq_manager().handle_pending_irqs(token); + exception::asynchronous::irq_manager().handle_pending_irqs(token); } ``` diff --git a/14_virtual_mem_part2_mmio_remap/README.md b/14_virtual_mem_part2_mmio_remap/README.md index be0997ac..911a2d76 100644 --- a/14_virtual_mem_part2_mmio_remap/README.md +++ b/14_virtual_mem_part2_mmio_remap/README.md @@ -324,7 +324,7 @@ the first time, an instance of the newly introduced `NullConsole` is used as the `NullConsole` implements all the console traits, but does nothing. It discards outputs, and returns dummy input. For example, should one of the printing macros be called before the UART driver has been instantiated and registered, the kernel does not need to crash because the driver is not -brought up yet. Instead, it can just discards the output. With this new scheme of things, it is +brought up yet. Instead, it can just discard the output. With this new scheme of things, it is possible to safely switch global references like the UART or the IRQ Manager at runtime. That all the post-driver-init work has now been moved to callbacks is motivated by the idea that @@ -382,7 +382,7 @@ been turned on. fn kernel_init_mmio_va_allocator() { let region = bsp::memory::mmu::virt_mmio_remap_region(); - page_alloc::kernel_mmio_va_allocator().lock(|allocator| allocator.initialize(region)); + page_alloc::kernel_mmio_va_allocator().lock(|allocator| allocator.init(region)); } ``` From 96ba61ace93edaa8979beb085a043c372f563a6c Mon Sep 17 00:00:00 2001 From: Andre Richter Date: Tue, 17 May 2022 00:32:05 +0200 Subject: [PATCH 35/75] Update README.md --- 18_backtrace/README.md | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/18_backtrace/README.md b/18_backtrace/README.md index 2c4dc127..f98eafc7 100644 --- a/18_backtrace/README.md +++ b/18_backtrace/README.md @@ -17,13 +17,12 @@ Backtrace: ---------------------------------------------------------------------------------------------- Address Function containing address ---------------------------------------------------------------------------------------------- - 1. ffffffffc0001294 | core::fmt::write - 2. ffffffffc0005560 | libkernel::panic_wait::_panic_print - 3. ffffffffc00054a0 | rust_begin_unwind - 4. ffffffffc0002950 | core::panicking::panic_fmt - 5. ffffffffc0004898 | current_elx_synchronous - 6. ffffffffc0000a74 | __vector_current_elx_synchronous - 7. ffffffffc000111c | kernel_init + 1. ffffffffc0005560 | libkernel::panic_wait::_panic_print + 2. ffffffffc00054a0 | rust_begin_unwind + 3. ffffffffc0002950 | core::panicking::panic_fmt + 4. ffffffffc0004898 | current_elx_synchronous + 5. ffffffffc0000a74 | __vector_current_elx_synchronous + 6. ffffffffc000111c | kernel_init ---------------------------------------------------------------------------------------------- ``` @@ -342,13 +341,12 @@ $ TEST=02_exception_sync_page_fault make test_integration ---------------------------------------------------------------------------------------------- Address Function containing address ---------------------------------------------------------------------------------------------- - 1. ffffffffc0001294 | core::fmt::write - 2. ffffffffc0005560 | libkernel::panic_wait::_panic_print - 3. ffffffffc00054a0 | rust_begin_unwind - 4. ffffffffc0002950 | core::panicking::panic_fmt - 5. ffffffffc0004898 | current_elx_synchronous - 6. ffffffffc0000a74 | __vector_current_elx_synchronous - 7. ffffffffc000111c | kernel_init + 1. ffffffffc0005560 | libkernel::panic_wait::_panic_print + 2. ffffffffc00054a0 | rust_begin_unwind + 3. ffffffffc0002950 | core::panicking::panic_fmt + 4. ffffffffc0004898 | current_elx_synchronous + 5. ffffffffc0000a74 | __vector_current_elx_synchronous + 6. ffffffffc000111c | kernel_init ---------------------------------------------------------------------------------------------- ------------------------------------------------------------------- From f45275591963e34c6f7b93e8109ad0512f08587c Mon Sep 17 00:00:00 2001 From: Andre Richter Date: Tue, 17 May 2022 23:24:33 +0200 Subject: [PATCH 36/75] Annotate sync functions --- 04_safe_globals/README.md | 4 ++-- 04_safe_globals/src/synchronization.rs | 4 ++-- 05_drivers_gpio_uart/src/synchronization.rs | 4 ++-- 06_uart_chainloader/src/synchronization.rs | 4 ++-- 07_timestamps/src/synchronization.rs | 4 ++-- 08_hw_debug_JTAG/src/synchronization.rs | 4 ++-- 09_privilege_level/src/synchronization.rs | 4 ++-- .../src/synchronization.rs | 4 ++-- .../src/synchronization.rs | 4 ++-- 12_integrated_testing/kernel/src/synchronization.rs | 4 ++-- 13_exceptions_part2_peripheral_IRQs/README.md | 12 ++++++------ .../kernel/src/synchronization.rs | 12 ++++++------ .../kernel/src/synchronization.rs | 12 ++++++------ .../kernel/src/synchronization.rs | 12 ++++++------ .../kernel/src/synchronization.rs | 12 ++++++------ 17_kernel_symbols/kernel/src/synchronization.rs | 12 ++++++------ 18_backtrace/kernel/src/synchronization.rs | 12 ++++++------ X1_JTAG_boot/src/synchronization.rs | 4 ++-- 18 files changed, 64 insertions(+), 64 deletions(-) diff --git a/04_safe_globals/README.md b/04_safe_globals/README.md index 58c14dc2..b34c04f9 100644 --- a/04_safe_globals/README.md +++ b/04_safe_globals/README.md @@ -313,7 +313,7 @@ diff -uNr 03_hacky_hello_world/src/synchronization.rs 04_safe_globals/src/synchr + type Data; + + /// Locks the mutex and grants the closure temporary mutable access to the wrapped data. -+ fn lock(&self, f: impl FnOnce(&mut Self::Data) -> R) -> R; ++ fn lock<'a, R>(&'a self, f: impl FnOnce(&'a mut Self::Data) -> R) -> R; + } +} + @@ -354,7 +354,7 @@ diff -uNr 03_hacky_hello_world/src/synchronization.rs 04_safe_globals/src/synchr +impl interface::Mutex for NullLock { + type Data = T; + -+ fn lock(&self, f: impl FnOnce(&mut Self::Data) -> R) -> R { ++ fn lock<'a, R>(&'a self, f: impl FnOnce(&'a mut Self::Data) -> R) -> R { + // In a real lock, there would be code encapsulating this line that ensures that this + // mutable reference will ever only be given out once at a time. + let data = unsafe { &mut *self.data.get() }; diff --git a/04_safe_globals/src/synchronization.rs b/04_safe_globals/src/synchronization.rs index d5653a19..d3937b0d 100644 --- a/04_safe_globals/src/synchronization.rs +++ b/04_safe_globals/src/synchronization.rs @@ -26,7 +26,7 @@ pub mod interface { type Data; /// Locks the mutex and grants the closure temporary mutable access to the wrapped data. - fn lock(&self, f: impl FnOnce(&mut Self::Data) -> R) -> R; + fn lock<'a, R>(&'a self, f: impl FnOnce(&'a mut Self::Data) -> R) -> R; } } @@ -67,7 +67,7 @@ impl NullLock { impl interface::Mutex for NullLock { type Data = T; - fn lock(&self, f: impl FnOnce(&mut Self::Data) -> R) -> R { + fn lock<'a, R>(&'a self, f: impl FnOnce(&'a mut Self::Data) -> R) -> R { // In a real lock, there would be code encapsulating this line that ensures that this // mutable reference will ever only be given out once at a time. let data = unsafe { &mut *self.data.get() }; diff --git a/05_drivers_gpio_uart/src/synchronization.rs b/05_drivers_gpio_uart/src/synchronization.rs index d5653a19..d3937b0d 100644 --- a/05_drivers_gpio_uart/src/synchronization.rs +++ b/05_drivers_gpio_uart/src/synchronization.rs @@ -26,7 +26,7 @@ pub mod interface { type Data; /// Locks the mutex and grants the closure temporary mutable access to the wrapped data. - fn lock(&self, f: impl FnOnce(&mut Self::Data) -> R) -> R; + fn lock<'a, R>(&'a self, f: impl FnOnce(&'a mut Self::Data) -> R) -> R; } } @@ -67,7 +67,7 @@ impl NullLock { impl interface::Mutex for NullLock { type Data = T; - fn lock(&self, f: impl FnOnce(&mut Self::Data) -> R) -> R { + fn lock<'a, R>(&'a self, f: impl FnOnce(&'a mut Self::Data) -> R) -> R { // In a real lock, there would be code encapsulating this line that ensures that this // mutable reference will ever only be given out once at a time. let data = unsafe { &mut *self.data.get() }; diff --git a/06_uart_chainloader/src/synchronization.rs b/06_uart_chainloader/src/synchronization.rs index d5653a19..d3937b0d 100644 --- a/06_uart_chainloader/src/synchronization.rs +++ b/06_uart_chainloader/src/synchronization.rs @@ -26,7 +26,7 @@ pub mod interface { type Data; /// Locks the mutex and grants the closure temporary mutable access to the wrapped data. - fn lock(&self, f: impl FnOnce(&mut Self::Data) -> R) -> R; + fn lock<'a, R>(&'a self, f: impl FnOnce(&'a mut Self::Data) -> R) -> R; } } @@ -67,7 +67,7 @@ impl NullLock { impl interface::Mutex for NullLock { type Data = T; - fn lock(&self, f: impl FnOnce(&mut Self::Data) -> R) -> R { + fn lock<'a, R>(&'a self, f: impl FnOnce(&'a mut Self::Data) -> R) -> R { // In a real lock, there would be code encapsulating this line that ensures that this // mutable reference will ever only be given out once at a time. let data = unsafe { &mut *self.data.get() }; diff --git a/07_timestamps/src/synchronization.rs b/07_timestamps/src/synchronization.rs index d5653a19..d3937b0d 100644 --- a/07_timestamps/src/synchronization.rs +++ b/07_timestamps/src/synchronization.rs @@ -26,7 +26,7 @@ pub mod interface { type Data; /// Locks the mutex and grants the closure temporary mutable access to the wrapped data. - fn lock(&self, f: impl FnOnce(&mut Self::Data) -> R) -> R; + fn lock<'a, R>(&'a self, f: impl FnOnce(&'a mut Self::Data) -> R) -> R; } } @@ -67,7 +67,7 @@ impl NullLock { impl interface::Mutex for NullLock { type Data = T; - fn lock(&self, f: impl FnOnce(&mut Self::Data) -> R) -> R { + fn lock<'a, R>(&'a self, f: impl FnOnce(&'a mut Self::Data) -> R) -> R { // In a real lock, there would be code encapsulating this line that ensures that this // mutable reference will ever only be given out once at a time. let data = unsafe { &mut *self.data.get() }; diff --git a/08_hw_debug_JTAG/src/synchronization.rs b/08_hw_debug_JTAG/src/synchronization.rs index d5653a19..d3937b0d 100644 --- a/08_hw_debug_JTAG/src/synchronization.rs +++ b/08_hw_debug_JTAG/src/synchronization.rs @@ -26,7 +26,7 @@ pub mod interface { type Data; /// Locks the mutex and grants the closure temporary mutable access to the wrapped data. - fn lock(&self, f: impl FnOnce(&mut Self::Data) -> R) -> R; + fn lock<'a, R>(&'a self, f: impl FnOnce(&'a mut Self::Data) -> R) -> R; } } @@ -67,7 +67,7 @@ impl NullLock { impl interface::Mutex for NullLock { type Data = T; - fn lock(&self, f: impl FnOnce(&mut Self::Data) -> R) -> R { + fn lock<'a, R>(&'a self, f: impl FnOnce(&'a mut Self::Data) -> R) -> R { // In a real lock, there would be code encapsulating this line that ensures that this // mutable reference will ever only be given out once at a time. let data = unsafe { &mut *self.data.get() }; diff --git a/09_privilege_level/src/synchronization.rs b/09_privilege_level/src/synchronization.rs index d5653a19..d3937b0d 100644 --- a/09_privilege_level/src/synchronization.rs +++ b/09_privilege_level/src/synchronization.rs @@ -26,7 +26,7 @@ pub mod interface { type Data; /// Locks the mutex and grants the closure temporary mutable access to the wrapped data. - fn lock(&self, f: impl FnOnce(&mut Self::Data) -> R) -> R; + fn lock<'a, R>(&'a self, f: impl FnOnce(&'a mut Self::Data) -> R) -> R; } } @@ -67,7 +67,7 @@ impl NullLock { impl interface::Mutex for NullLock { type Data = T; - fn lock(&self, f: impl FnOnce(&mut Self::Data) -> R) -> R { + fn lock<'a, R>(&'a self, f: impl FnOnce(&'a mut Self::Data) -> R) -> R { // In a real lock, there would be code encapsulating this line that ensures that this // mutable reference will ever only be given out once at a time. let data = unsafe { &mut *self.data.get() }; diff --git a/10_virtual_mem_part1_identity_mapping/src/synchronization.rs b/10_virtual_mem_part1_identity_mapping/src/synchronization.rs index d5653a19..d3937b0d 100644 --- a/10_virtual_mem_part1_identity_mapping/src/synchronization.rs +++ b/10_virtual_mem_part1_identity_mapping/src/synchronization.rs @@ -26,7 +26,7 @@ pub mod interface { type Data; /// Locks the mutex and grants the closure temporary mutable access to the wrapped data. - fn lock(&self, f: impl FnOnce(&mut Self::Data) -> R) -> R; + fn lock<'a, R>(&'a self, f: impl FnOnce(&'a mut Self::Data) -> R) -> R; } } @@ -67,7 +67,7 @@ impl NullLock { impl interface::Mutex for NullLock { type Data = T; - fn lock(&self, f: impl FnOnce(&mut Self::Data) -> R) -> R { + fn lock<'a, R>(&'a self, f: impl FnOnce(&'a mut Self::Data) -> R) -> R { // In a real lock, there would be code encapsulating this line that ensures that this // mutable reference will ever only be given out once at a time. let data = unsafe { &mut *self.data.get() }; diff --git a/11_exceptions_part1_groundwork/src/synchronization.rs b/11_exceptions_part1_groundwork/src/synchronization.rs index d5653a19..d3937b0d 100644 --- a/11_exceptions_part1_groundwork/src/synchronization.rs +++ b/11_exceptions_part1_groundwork/src/synchronization.rs @@ -26,7 +26,7 @@ pub mod interface { type Data; /// Locks the mutex and grants the closure temporary mutable access to the wrapped data. - fn lock(&self, f: impl FnOnce(&mut Self::Data) -> R) -> R; + fn lock<'a, R>(&'a self, f: impl FnOnce(&'a mut Self::Data) -> R) -> R; } } @@ -67,7 +67,7 @@ impl NullLock { impl interface::Mutex for NullLock { type Data = T; - fn lock(&self, f: impl FnOnce(&mut Self::Data) -> R) -> R { + fn lock<'a, R>(&'a self, f: impl FnOnce(&'a mut Self::Data) -> R) -> R { // In a real lock, there would be code encapsulating this line that ensures that this // mutable reference will ever only be given out once at a time. let data = unsafe { &mut *self.data.get() }; diff --git a/12_integrated_testing/kernel/src/synchronization.rs b/12_integrated_testing/kernel/src/synchronization.rs index d5653a19..d3937b0d 100644 --- a/12_integrated_testing/kernel/src/synchronization.rs +++ b/12_integrated_testing/kernel/src/synchronization.rs @@ -26,7 +26,7 @@ pub mod interface { type Data; /// Locks the mutex and grants the closure temporary mutable access to the wrapped data. - fn lock(&self, f: impl FnOnce(&mut Self::Data) -> R) -> R; + fn lock<'a, R>(&'a self, f: impl FnOnce(&'a mut Self::Data) -> R) -> R; } } @@ -67,7 +67,7 @@ impl NullLock { impl interface::Mutex for NullLock { type Data = T; - fn lock(&self, f: impl FnOnce(&mut Self::Data) -> R) -> R { + fn lock<'a, R>(&'a self, f: impl FnOnce(&'a mut Self::Data) -> R) -> R { // In a real lock, there would be code encapsulating this line that ensures that this // mutable reference will ever only be given out once at a time. let data = unsafe { &mut *self.data.get() }; diff --git a/13_exceptions_part2_peripheral_IRQs/README.md b/13_exceptions_part2_peripheral_IRQs/README.md index 634686d6..9a5b7b4f 100644 --- a/13_exceptions_part2_peripheral_IRQs/README.md +++ b/13_exceptions_part2_peripheral_IRQs/README.md @@ -2605,7 +2605,7 @@ diff -uNr 12_integrated_testing/kernel/src/synchronization.rs 13_exceptions_part +++ 13_exceptions_part2_peripheral_IRQs/kernel/src/synchronization.rs @@ -28,6 +28,21 @@ /// Locks the mutex and grants the closure temporary mutable access to the wrapped data. - fn lock(&self, f: impl FnOnce(&mut Self::Data) -> R) -> R; + fn lock<'a, R>(&'a self, f: impl FnOnce(&'a mut Self::Data) -> R) -> R; } + + /// A reader-writer exclusion type. @@ -2617,10 +2617,10 @@ diff -uNr 12_integrated_testing/kernel/src/synchronization.rs 13_exceptions_part + type Data; + + /// Grants temporary mutable access to the encapsulated data. -+ fn write(&self, f: impl FnOnce(&mut Self::Data) -> R) -> R; ++ fn write<'a, R>(&'a self, f: impl FnOnce(&'a mut Self::Data) -> R) -> R; + + /// Grants temporary immutable access to the encapsulated data. -+ fn read(&self, f: impl FnOnce(&Self::Data) -> R) -> R; ++ fn read<'a, R>(&'a self, f: impl FnOnce(&'a Self::Data) -> R) -> R; + } } @@ -2682,7 +2682,7 @@ diff -uNr 12_integrated_testing/kernel/src/synchronization.rs 13_exceptions_part +impl interface::Mutex for IRQSafeNullLock { type Data = T; - fn lock(&self, f: impl FnOnce(&mut Self::Data) -> R) -> R { + fn lock<'a, R>(&'a self, f: impl FnOnce(&'a mut Self::Data) -> R) -> R { @@ -72,6 +110,50 @@ // mutable reference will ever only be given out once at a time. let data = unsafe { &mut *self.data.get() }; @@ -2695,7 +2695,7 @@ diff -uNr 12_integrated_testing/kernel/src/synchronization.rs 13_exceptions_part +impl interface::ReadWriteEx for InitStateLock { + type Data = T; + -+ fn write(&self, f: impl FnOnce(&mut Self::Data) -> R) -> R { ++ fn write<'a, R>(&'a self, f: impl FnOnce(&'a mut Self::Data) -> R) -> R { + assert!( + state::state_manager().is_init(), + "InitStateLock::write called after kernel init phase" @@ -2710,7 +2710,7 @@ diff -uNr 12_integrated_testing/kernel/src/synchronization.rs 13_exceptions_part f(data) } + -+ fn read(&self, f: impl FnOnce(&Self::Data) -> R) -> R { ++ fn read<'a, R>(&'a self, f: impl FnOnce(&'a Self::Data) -> R) -> R { + let data = unsafe { &*self.data.get() }; + + f(data) diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/synchronization.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/synchronization.rs index 4b4c4c3f..ab2b86e6 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/synchronization.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/synchronization.rs @@ -26,7 +26,7 @@ pub mod interface { type Data; /// Locks the mutex and grants the closure temporary mutable access to the wrapped data. - fn lock(&self, f: impl FnOnce(&mut Self::Data) -> R) -> R; + fn lock<'a, R>(&'a self, f: impl FnOnce(&'a mut Self::Data) -> R) -> R; } /// A reader-writer exclusion type. @@ -38,10 +38,10 @@ pub mod interface { type Data; /// Grants temporary mutable access to the encapsulated data. - fn write(&self, f: impl FnOnce(&mut Self::Data) -> R) -> R; + fn write<'a, R>(&'a self, f: impl FnOnce(&'a mut Self::Data) -> R) -> R; /// Grants temporary immutable access to the encapsulated data. - fn read(&self, f: impl FnOnce(&Self::Data) -> R) -> R; + fn read<'a, R>(&'a self, f: impl FnOnce(&'a Self::Data) -> R) -> R; } } @@ -105,7 +105,7 @@ use crate::{exception, state}; impl interface::Mutex for IRQSafeNullLock { type Data = T; - fn lock(&self, f: impl FnOnce(&mut Self::Data) -> R) -> R { + fn lock<'a, R>(&'a self, f: impl FnOnce(&'a mut Self::Data) -> R) -> R { // In a real lock, there would be code encapsulating this line that ensures that this // mutable reference will ever only be given out once at a time. let data = unsafe { &mut *self.data.get() }; @@ -118,7 +118,7 @@ impl interface::Mutex for IRQSafeNullLock { impl interface::ReadWriteEx for InitStateLock { type Data = T; - fn write(&self, f: impl FnOnce(&mut Self::Data) -> R) -> R { + fn write<'a, R>(&'a self, f: impl FnOnce(&'a mut Self::Data) -> R) -> R { assert!( state::state_manager().is_init(), "InitStateLock::write called after kernel init phase" @@ -133,7 +133,7 @@ impl interface::ReadWriteEx for InitStateLock { f(data) } - fn read(&self, f: impl FnOnce(&Self::Data) -> R) -> R { + fn read<'a, R>(&'a self, f: impl FnOnce(&'a Self::Data) -> R) -> R { let data = unsafe { &*self.data.get() }; f(data) diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/synchronization.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/synchronization.rs index 4b4c4c3f..ab2b86e6 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/synchronization.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/synchronization.rs @@ -26,7 +26,7 @@ pub mod interface { type Data; /// Locks the mutex and grants the closure temporary mutable access to the wrapped data. - fn lock(&self, f: impl FnOnce(&mut Self::Data) -> R) -> R; + fn lock<'a, R>(&'a self, f: impl FnOnce(&'a mut Self::Data) -> R) -> R; } /// A reader-writer exclusion type. @@ -38,10 +38,10 @@ pub mod interface { type Data; /// Grants temporary mutable access to the encapsulated data. - fn write(&self, f: impl FnOnce(&mut Self::Data) -> R) -> R; + fn write<'a, R>(&'a self, f: impl FnOnce(&'a mut Self::Data) -> R) -> R; /// Grants temporary immutable access to the encapsulated data. - fn read(&self, f: impl FnOnce(&Self::Data) -> R) -> R; + fn read<'a, R>(&'a self, f: impl FnOnce(&'a Self::Data) -> R) -> R; } } @@ -105,7 +105,7 @@ use crate::{exception, state}; impl interface::Mutex for IRQSafeNullLock { type Data = T; - fn lock(&self, f: impl FnOnce(&mut Self::Data) -> R) -> R { + fn lock<'a, R>(&'a self, f: impl FnOnce(&'a mut Self::Data) -> R) -> R { // In a real lock, there would be code encapsulating this line that ensures that this // mutable reference will ever only be given out once at a time. let data = unsafe { &mut *self.data.get() }; @@ -118,7 +118,7 @@ impl interface::Mutex for IRQSafeNullLock { impl interface::ReadWriteEx for InitStateLock { type Data = T; - fn write(&self, f: impl FnOnce(&mut Self::Data) -> R) -> R { + fn write<'a, R>(&'a self, f: impl FnOnce(&'a mut Self::Data) -> R) -> R { assert!( state::state_manager().is_init(), "InitStateLock::write called after kernel init phase" @@ -133,7 +133,7 @@ impl interface::ReadWriteEx for InitStateLock { f(data) } - fn read(&self, f: impl FnOnce(&Self::Data) -> R) -> R { + fn read<'a, R>(&'a self, f: impl FnOnce(&'a Self::Data) -> R) -> R { let data = unsafe { &*self.data.get() }; f(data) diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/synchronization.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/synchronization.rs index 4b4c4c3f..ab2b86e6 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/synchronization.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/synchronization.rs @@ -26,7 +26,7 @@ pub mod interface { type Data; /// Locks the mutex and grants the closure temporary mutable access to the wrapped data. - fn lock(&self, f: impl FnOnce(&mut Self::Data) -> R) -> R; + fn lock<'a, R>(&'a self, f: impl FnOnce(&'a mut Self::Data) -> R) -> R; } /// A reader-writer exclusion type. @@ -38,10 +38,10 @@ pub mod interface { type Data; /// Grants temporary mutable access to the encapsulated data. - fn write(&self, f: impl FnOnce(&mut Self::Data) -> R) -> R; + fn write<'a, R>(&'a self, f: impl FnOnce(&'a mut Self::Data) -> R) -> R; /// Grants temporary immutable access to the encapsulated data. - fn read(&self, f: impl FnOnce(&Self::Data) -> R) -> R; + fn read<'a, R>(&'a self, f: impl FnOnce(&'a Self::Data) -> R) -> R; } } @@ -105,7 +105,7 @@ use crate::{exception, state}; impl interface::Mutex for IRQSafeNullLock { type Data = T; - fn lock(&self, f: impl FnOnce(&mut Self::Data) -> R) -> R { + fn lock<'a, R>(&'a self, f: impl FnOnce(&'a mut Self::Data) -> R) -> R { // In a real lock, there would be code encapsulating this line that ensures that this // mutable reference will ever only be given out once at a time. let data = unsafe { &mut *self.data.get() }; @@ -118,7 +118,7 @@ impl interface::Mutex for IRQSafeNullLock { impl interface::ReadWriteEx for InitStateLock { type Data = T; - fn write(&self, f: impl FnOnce(&mut Self::Data) -> R) -> R { + fn write<'a, R>(&'a self, f: impl FnOnce(&'a mut Self::Data) -> R) -> R { assert!( state::state_manager().is_init(), "InitStateLock::write called after kernel init phase" @@ -133,7 +133,7 @@ impl interface::ReadWriteEx for InitStateLock { f(data) } - fn read(&self, f: impl FnOnce(&Self::Data) -> R) -> R { + fn read<'a, R>(&'a self, f: impl FnOnce(&'a Self::Data) -> R) -> R { let data = unsafe { &*self.data.get() }; f(data) diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/synchronization.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/synchronization.rs index 4b4c4c3f..ab2b86e6 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/synchronization.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/synchronization.rs @@ -26,7 +26,7 @@ pub mod interface { type Data; /// Locks the mutex and grants the closure temporary mutable access to the wrapped data. - fn lock(&self, f: impl FnOnce(&mut Self::Data) -> R) -> R; + fn lock<'a, R>(&'a self, f: impl FnOnce(&'a mut Self::Data) -> R) -> R; } /// A reader-writer exclusion type. @@ -38,10 +38,10 @@ pub mod interface { type Data; /// Grants temporary mutable access to the encapsulated data. - fn write(&self, f: impl FnOnce(&mut Self::Data) -> R) -> R; + fn write<'a, R>(&'a self, f: impl FnOnce(&'a mut Self::Data) -> R) -> R; /// Grants temporary immutable access to the encapsulated data. - fn read(&self, f: impl FnOnce(&Self::Data) -> R) -> R; + fn read<'a, R>(&'a self, f: impl FnOnce(&'a Self::Data) -> R) -> R; } } @@ -105,7 +105,7 @@ use crate::{exception, state}; impl interface::Mutex for IRQSafeNullLock { type Data = T; - fn lock(&self, f: impl FnOnce(&mut Self::Data) -> R) -> R { + fn lock<'a, R>(&'a self, f: impl FnOnce(&'a mut Self::Data) -> R) -> R { // In a real lock, there would be code encapsulating this line that ensures that this // mutable reference will ever only be given out once at a time. let data = unsafe { &mut *self.data.get() }; @@ -118,7 +118,7 @@ impl interface::Mutex for IRQSafeNullLock { impl interface::ReadWriteEx for InitStateLock { type Data = T; - fn write(&self, f: impl FnOnce(&mut Self::Data) -> R) -> R { + fn write<'a, R>(&'a self, f: impl FnOnce(&'a mut Self::Data) -> R) -> R { assert!( state::state_manager().is_init(), "InitStateLock::write called after kernel init phase" @@ -133,7 +133,7 @@ impl interface::ReadWriteEx for InitStateLock { f(data) } - fn read(&self, f: impl FnOnce(&Self::Data) -> R) -> R { + fn read<'a, R>(&'a self, f: impl FnOnce(&'a Self::Data) -> R) -> R { let data = unsafe { &*self.data.get() }; f(data) diff --git a/17_kernel_symbols/kernel/src/synchronization.rs b/17_kernel_symbols/kernel/src/synchronization.rs index 4b4c4c3f..ab2b86e6 100644 --- a/17_kernel_symbols/kernel/src/synchronization.rs +++ b/17_kernel_symbols/kernel/src/synchronization.rs @@ -26,7 +26,7 @@ pub mod interface { type Data; /// Locks the mutex and grants the closure temporary mutable access to the wrapped data. - fn lock(&self, f: impl FnOnce(&mut Self::Data) -> R) -> R; + fn lock<'a, R>(&'a self, f: impl FnOnce(&'a mut Self::Data) -> R) -> R; } /// A reader-writer exclusion type. @@ -38,10 +38,10 @@ pub mod interface { type Data; /// Grants temporary mutable access to the encapsulated data. - fn write(&self, f: impl FnOnce(&mut Self::Data) -> R) -> R; + fn write<'a, R>(&'a self, f: impl FnOnce(&'a mut Self::Data) -> R) -> R; /// Grants temporary immutable access to the encapsulated data. - fn read(&self, f: impl FnOnce(&Self::Data) -> R) -> R; + fn read<'a, R>(&'a self, f: impl FnOnce(&'a Self::Data) -> R) -> R; } } @@ -105,7 +105,7 @@ use crate::{exception, state}; impl interface::Mutex for IRQSafeNullLock { type Data = T; - fn lock(&self, f: impl FnOnce(&mut Self::Data) -> R) -> R { + fn lock<'a, R>(&'a self, f: impl FnOnce(&'a mut Self::Data) -> R) -> R { // In a real lock, there would be code encapsulating this line that ensures that this // mutable reference will ever only be given out once at a time. let data = unsafe { &mut *self.data.get() }; @@ -118,7 +118,7 @@ impl interface::Mutex for IRQSafeNullLock { impl interface::ReadWriteEx for InitStateLock { type Data = T; - fn write(&self, f: impl FnOnce(&mut Self::Data) -> R) -> R { + fn write<'a, R>(&'a self, f: impl FnOnce(&'a mut Self::Data) -> R) -> R { assert!( state::state_manager().is_init(), "InitStateLock::write called after kernel init phase" @@ -133,7 +133,7 @@ impl interface::ReadWriteEx for InitStateLock { f(data) } - fn read(&self, f: impl FnOnce(&Self::Data) -> R) -> R { + fn read<'a, R>(&'a self, f: impl FnOnce(&'a Self::Data) -> R) -> R { let data = unsafe { &*self.data.get() }; f(data) diff --git a/18_backtrace/kernel/src/synchronization.rs b/18_backtrace/kernel/src/synchronization.rs index 4b4c4c3f..ab2b86e6 100644 --- a/18_backtrace/kernel/src/synchronization.rs +++ b/18_backtrace/kernel/src/synchronization.rs @@ -26,7 +26,7 @@ pub mod interface { type Data; /// Locks the mutex and grants the closure temporary mutable access to the wrapped data. - fn lock(&self, f: impl FnOnce(&mut Self::Data) -> R) -> R; + fn lock<'a, R>(&'a self, f: impl FnOnce(&'a mut Self::Data) -> R) -> R; } /// A reader-writer exclusion type. @@ -38,10 +38,10 @@ pub mod interface { type Data; /// Grants temporary mutable access to the encapsulated data. - fn write(&self, f: impl FnOnce(&mut Self::Data) -> R) -> R; + fn write<'a, R>(&'a self, f: impl FnOnce(&'a mut Self::Data) -> R) -> R; /// Grants temporary immutable access to the encapsulated data. - fn read(&self, f: impl FnOnce(&Self::Data) -> R) -> R; + fn read<'a, R>(&'a self, f: impl FnOnce(&'a Self::Data) -> R) -> R; } } @@ -105,7 +105,7 @@ use crate::{exception, state}; impl interface::Mutex for IRQSafeNullLock { type Data = T; - fn lock(&self, f: impl FnOnce(&mut Self::Data) -> R) -> R { + fn lock<'a, R>(&'a self, f: impl FnOnce(&'a mut Self::Data) -> R) -> R { // In a real lock, there would be code encapsulating this line that ensures that this // mutable reference will ever only be given out once at a time. let data = unsafe { &mut *self.data.get() }; @@ -118,7 +118,7 @@ impl interface::Mutex for IRQSafeNullLock { impl interface::ReadWriteEx for InitStateLock { type Data = T; - fn write(&self, f: impl FnOnce(&mut Self::Data) -> R) -> R { + fn write<'a, R>(&'a self, f: impl FnOnce(&'a mut Self::Data) -> R) -> R { assert!( state::state_manager().is_init(), "InitStateLock::write called after kernel init phase" @@ -133,7 +133,7 @@ impl interface::ReadWriteEx for InitStateLock { f(data) } - fn read(&self, f: impl FnOnce(&Self::Data) -> R) -> R { + fn read<'a, R>(&'a self, f: impl FnOnce(&'a Self::Data) -> R) -> R { let data = unsafe { &*self.data.get() }; f(data) diff --git a/X1_JTAG_boot/src/synchronization.rs b/X1_JTAG_boot/src/synchronization.rs index d5653a19..d3937b0d 100644 --- a/X1_JTAG_boot/src/synchronization.rs +++ b/X1_JTAG_boot/src/synchronization.rs @@ -26,7 +26,7 @@ pub mod interface { type Data; /// Locks the mutex and grants the closure temporary mutable access to the wrapped data. - fn lock(&self, f: impl FnOnce(&mut Self::Data) -> R) -> R; + fn lock<'a, R>(&'a self, f: impl FnOnce(&'a mut Self::Data) -> R) -> R; } } @@ -67,7 +67,7 @@ impl NullLock { impl interface::Mutex for NullLock { type Data = T; - fn lock(&self, f: impl FnOnce(&mut Self::Data) -> R) -> R { + fn lock<'a, R>(&'a self, f: impl FnOnce(&'a mut Self::Data) -> R) -> R { // In a real lock, there would be code encapsulating this line that ensures that this // mutable reference will ever only be given out once at a time. let data = unsafe { &mut *self.data.get() }; From 2cd44c3e7f3f6b829f351041a75053b9ca3795d8 Mon Sep 17 00:00:00 2001 From: Andre Richter Date: Tue, 17 May 2022 23:24:45 +0200 Subject: [PATCH 37/75] Add tutorial 19 --- 19_kernel_heap/.cargo/config.toml | 2 + 19_kernel_heap/.vscode/settings.json | 10 + 19_kernel_heap/Cargo.lock | 103 ++ 19_kernel_heap/Cargo.toml | 11 + 19_kernel_heap/Makefile | 394 +++++ 19_kernel_heap/README.md | 1356 +++++++++++++++++ 19_kernel_heap/kernel/Cargo.lock | 96 ++ 19_kernel_heap/kernel/Cargo.toml | 72 + 19_kernel_heap/kernel/build.rs | 20 + .../kernel/src/_arch/aarch64/backtrace.rs | 136 ++ .../kernel/src/_arch/aarch64/cpu.rs | 49 + .../kernel/src/_arch/aarch64/cpu/boot.rs | 117 ++ .../kernel/src/_arch/aarch64/cpu/boot.s | 97 ++ .../kernel/src/_arch/aarch64/cpu/smp.rs | 30 + .../kernel/src/_arch/aarch64/exception.rs | 325 ++++ .../kernel/src/_arch/aarch64/exception.s | 190 +++ .../_arch/aarch64/exception/asynchronous.rs | 152 ++ .../kernel/src/_arch/aarch64/memory/mmu.rs | 158 ++ .../aarch64/memory/mmu/translation_table.rs | 521 +++++++ .../kernel/src/_arch/aarch64/time.rs | 121 ++ 19_kernel_heap/kernel/src/backtrace.rs | 114 ++ 19_kernel_heap/kernel/src/bsp.rs | 13 + .../kernel/src/bsp/device_driver.rs | 16 + .../kernel/src/bsp/device_driver/arm.rs | 9 + .../kernel/src/bsp/device_driver/arm/gicv2.rs | 242 +++ .../src/bsp/device_driver/arm/gicv2/gicc.rs | 145 ++ .../src/bsp/device_driver/arm/gicv2/gicd.rs | 201 +++ .../kernel/src/bsp/device_driver/bcm.rs | 15 + .../src/bsp/device_driver/bcm/bcm2xxx_gpio.rs | 233 +++ .../bcm/bcm2xxx_interrupt_controller.rs | 147 ++ .../peripheral_ic.rs | 175 +++ .../device_driver/bcm/bcm2xxx_pl011_uart.rs | 524 +++++++ .../kernel/src/bsp/device_driver/common.rs | 39 + 19_kernel_heap/kernel/src/bsp/raspberrypi.rs | 27 + .../kernel/src/bsp/raspberrypi/cpu.rs | 14 + .../kernel/src/bsp/raspberrypi/driver.rs | 190 +++ .../kernel/src/bsp/raspberrypi/exception.rs | 7 + .../bsp/raspberrypi/exception/asynchronous.rs | 25 + .../kernel/src/bsp/raspberrypi/kernel.ld | 127 ++ .../kernel_virt_addr_space_size.ld | 1 + .../kernel/src/bsp/raspberrypi/memory.rs | 251 +++ .../kernel/src/bsp/raspberrypi/memory/mmu.rs | 197 +++ 19_kernel_heap/kernel/src/common.rs | 46 + 19_kernel_heap/kernel/src/console.rs | 93 ++ .../kernel/src/console/buffer_console.rs | 108 ++ 19_kernel_heap/kernel/src/cpu.rs | 21 + 19_kernel_heap/kernel/src/cpu/boot.rs | 9 + 19_kernel_heap/kernel/src/cpu/smp.rs | 14 + 19_kernel_heap/kernel/src/driver.rs | 57 + 19_kernel_heap/kernel/src/exception.rs | 48 + .../kernel/src/exception/asynchronous.rs | 178 +++ .../asynchronous/null_irq_manager.rs | 44 + 19_kernel_heap/kernel/src/lib.rs | 195 +++ 19_kernel_heap/kernel/src/main.rs | 102 ++ 19_kernel_heap/kernel/src/memory.rs | 198 +++ .../kernel/src/memory/heap_alloc.rs | 137 ++ 19_kernel_heap/kernel/src/memory/mmu.rs | 262 ++++ .../kernel/src/memory/mmu/mapping_record.rs | 204 +++ .../kernel/src/memory/mmu/page_alloc.rs | 70 + .../src/memory/mmu/translation_table.rs | 137 ++ 19_kernel_heap/kernel/src/memory/mmu/types.rs | 378 +++++ 19_kernel_heap/kernel/src/panic_wait.rs | 90 ++ 19_kernel_heap/kernel/src/print.rs | 124 ++ 19_kernel_heap/kernel/src/state.rs | 92 ++ 19_kernel_heap/kernel/src/symbols.rs | 87 ++ 19_kernel_heap/kernel/src/synchronization.rs | 159 ++ 19_kernel_heap/kernel/src/time.rs | 37 + .../kernel/tests/00_console_sanity.rb | 48 + .../kernel/tests/00_console_sanity.rs | 39 + .../kernel/tests/01_timer_sanity.rs | 52 + .../tests/02_exception_sync_page_fault.rs | 39 + .../tests/03_exception_restore_sanity.rb | 25 + .../tests/03_exception_restore_sanity.rs | 51 + .../kernel/tests/04_exception_irq_sanity.rs | 69 + .../kernel/tests/05_backtrace_sanity.rb | 39 + .../kernel/tests/05_backtrace_sanity.rs | 33 + .../tests/06_backtrace_invalid_frame.rb | 26 + .../tests/06_backtrace_invalid_frame.rs | 35 + .../kernel/tests/07_backtrace_invalid_link.rb | 25 + .../kernel/tests/07_backtrace_invalid_link.rs | 40 + .../kernel/tests/boot_test_string.rb | 3 + .../kernel/tests/panic_exit_success/mod.rs | 9 + .../kernel/tests/panic_wait_forever/mod.rs | 9 + 19_kernel_heap/kernel_symbols.mk | 103 ++ 19_kernel_heap/kernel_symbols/Cargo.lock | 14 + 19_kernel_heap/kernel_symbols/Cargo.toml | 15 + 19_kernel_heap/kernel_symbols/build.rs | 14 + .../kernel_symbols/kernel_symbols.ld | 15 + 19_kernel_heap/kernel_symbols/src/main.rs | 16 + .../libraries/debug-symbol-types/Cargo.toml | 4 + .../libraries/debug-symbol-types/src/lib.rs | 45 + .../libraries/test-macros/Cargo.toml | 14 + .../libraries/test-macros/src/lib.rs | 29 + .../libraries/test-types/Cargo.toml | 5 + .../libraries/test-types/src/lib.rs | 16 + .../tools/kernel_symbols_tool/cmds.rb | 45 + .../tools/kernel_symbols_tool/kernel_elf.rb | 74 + .../tools/kernel_symbols_tool/main.rb | 47 + .../tools/translation_table_tool/arch.rb | 314 ++++ .../tools/translation_table_tool/bsp.rb | 54 + .../tools/translation_table_tool/generic.rb | 189 +++ .../translation_table_tool/kernel_elf.rb | 96 ++ .../tools/translation_table_tool/main.rb | 46 + 103 files changed, 11259 insertions(+) create mode 100644 19_kernel_heap/.cargo/config.toml create mode 100644 19_kernel_heap/.vscode/settings.json create mode 100644 19_kernel_heap/Cargo.lock create mode 100644 19_kernel_heap/Cargo.toml create mode 100644 19_kernel_heap/Makefile create mode 100644 19_kernel_heap/README.md create mode 100644 19_kernel_heap/kernel/Cargo.lock create mode 100644 19_kernel_heap/kernel/Cargo.toml create mode 100644 19_kernel_heap/kernel/build.rs create mode 100644 19_kernel_heap/kernel/src/_arch/aarch64/backtrace.rs create mode 100644 19_kernel_heap/kernel/src/_arch/aarch64/cpu.rs create mode 100644 19_kernel_heap/kernel/src/_arch/aarch64/cpu/boot.rs create mode 100644 19_kernel_heap/kernel/src/_arch/aarch64/cpu/boot.s create mode 100644 19_kernel_heap/kernel/src/_arch/aarch64/cpu/smp.rs create mode 100644 19_kernel_heap/kernel/src/_arch/aarch64/exception.rs create mode 100644 19_kernel_heap/kernel/src/_arch/aarch64/exception.s create mode 100644 19_kernel_heap/kernel/src/_arch/aarch64/exception/asynchronous.rs create mode 100644 19_kernel_heap/kernel/src/_arch/aarch64/memory/mmu.rs create mode 100644 19_kernel_heap/kernel/src/_arch/aarch64/memory/mmu/translation_table.rs create mode 100644 19_kernel_heap/kernel/src/_arch/aarch64/time.rs create mode 100644 19_kernel_heap/kernel/src/backtrace.rs create mode 100644 19_kernel_heap/kernel/src/bsp.rs create mode 100644 19_kernel_heap/kernel/src/bsp/device_driver.rs create mode 100644 19_kernel_heap/kernel/src/bsp/device_driver/arm.rs create mode 100644 19_kernel_heap/kernel/src/bsp/device_driver/arm/gicv2.rs create mode 100644 19_kernel_heap/kernel/src/bsp/device_driver/arm/gicv2/gicc.rs create mode 100644 19_kernel_heap/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs create mode 100644 19_kernel_heap/kernel/src/bsp/device_driver/bcm.rs create mode 100644 19_kernel_heap/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs create mode 100644 19_kernel_heap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs create mode 100644 19_kernel_heap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs create mode 100644 19_kernel_heap/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs create mode 100644 19_kernel_heap/kernel/src/bsp/device_driver/common.rs create mode 100644 19_kernel_heap/kernel/src/bsp/raspberrypi.rs create mode 100644 19_kernel_heap/kernel/src/bsp/raspberrypi/cpu.rs create mode 100644 19_kernel_heap/kernel/src/bsp/raspberrypi/driver.rs create mode 100644 19_kernel_heap/kernel/src/bsp/raspberrypi/exception.rs create mode 100644 19_kernel_heap/kernel/src/bsp/raspberrypi/exception/asynchronous.rs create mode 100644 19_kernel_heap/kernel/src/bsp/raspberrypi/kernel.ld create mode 100644 19_kernel_heap/kernel/src/bsp/raspberrypi/kernel_virt_addr_space_size.ld create mode 100644 19_kernel_heap/kernel/src/bsp/raspberrypi/memory.rs create mode 100644 19_kernel_heap/kernel/src/bsp/raspberrypi/memory/mmu.rs create mode 100644 19_kernel_heap/kernel/src/common.rs create mode 100644 19_kernel_heap/kernel/src/console.rs create mode 100644 19_kernel_heap/kernel/src/console/buffer_console.rs create mode 100644 19_kernel_heap/kernel/src/cpu.rs create mode 100644 19_kernel_heap/kernel/src/cpu/boot.rs create mode 100644 19_kernel_heap/kernel/src/cpu/smp.rs create mode 100644 19_kernel_heap/kernel/src/driver.rs create mode 100644 19_kernel_heap/kernel/src/exception.rs create mode 100644 19_kernel_heap/kernel/src/exception/asynchronous.rs create mode 100644 19_kernel_heap/kernel/src/exception/asynchronous/null_irq_manager.rs create mode 100644 19_kernel_heap/kernel/src/lib.rs create mode 100644 19_kernel_heap/kernel/src/main.rs create mode 100644 19_kernel_heap/kernel/src/memory.rs create mode 100644 19_kernel_heap/kernel/src/memory/heap_alloc.rs create mode 100644 19_kernel_heap/kernel/src/memory/mmu.rs create mode 100644 19_kernel_heap/kernel/src/memory/mmu/mapping_record.rs create mode 100644 19_kernel_heap/kernel/src/memory/mmu/page_alloc.rs create mode 100644 19_kernel_heap/kernel/src/memory/mmu/translation_table.rs create mode 100644 19_kernel_heap/kernel/src/memory/mmu/types.rs create mode 100644 19_kernel_heap/kernel/src/panic_wait.rs create mode 100644 19_kernel_heap/kernel/src/print.rs create mode 100644 19_kernel_heap/kernel/src/state.rs create mode 100644 19_kernel_heap/kernel/src/symbols.rs create mode 100644 19_kernel_heap/kernel/src/synchronization.rs create mode 100644 19_kernel_heap/kernel/src/time.rs create mode 100644 19_kernel_heap/kernel/tests/00_console_sanity.rb create mode 100644 19_kernel_heap/kernel/tests/00_console_sanity.rs create mode 100644 19_kernel_heap/kernel/tests/01_timer_sanity.rs create mode 100644 19_kernel_heap/kernel/tests/02_exception_sync_page_fault.rs create mode 100644 19_kernel_heap/kernel/tests/03_exception_restore_sanity.rb create mode 100644 19_kernel_heap/kernel/tests/03_exception_restore_sanity.rs create mode 100644 19_kernel_heap/kernel/tests/04_exception_irq_sanity.rs create mode 100644 19_kernel_heap/kernel/tests/05_backtrace_sanity.rb create mode 100644 19_kernel_heap/kernel/tests/05_backtrace_sanity.rs create mode 100644 19_kernel_heap/kernel/tests/06_backtrace_invalid_frame.rb create mode 100644 19_kernel_heap/kernel/tests/06_backtrace_invalid_frame.rs create mode 100644 19_kernel_heap/kernel/tests/07_backtrace_invalid_link.rb create mode 100644 19_kernel_heap/kernel/tests/07_backtrace_invalid_link.rs create mode 100644 19_kernel_heap/kernel/tests/boot_test_string.rb create mode 100644 19_kernel_heap/kernel/tests/panic_exit_success/mod.rs create mode 100644 19_kernel_heap/kernel/tests/panic_wait_forever/mod.rs create mode 100644 19_kernel_heap/kernel_symbols.mk create mode 100644 19_kernel_heap/kernel_symbols/Cargo.lock create mode 100644 19_kernel_heap/kernel_symbols/Cargo.toml create mode 100644 19_kernel_heap/kernel_symbols/build.rs create mode 100644 19_kernel_heap/kernel_symbols/kernel_symbols.ld create mode 100644 19_kernel_heap/kernel_symbols/src/main.rs create mode 100644 19_kernel_heap/libraries/debug-symbol-types/Cargo.toml create mode 100644 19_kernel_heap/libraries/debug-symbol-types/src/lib.rs create mode 100644 19_kernel_heap/libraries/test-macros/Cargo.toml create mode 100644 19_kernel_heap/libraries/test-macros/src/lib.rs create mode 100644 19_kernel_heap/libraries/test-types/Cargo.toml create mode 100644 19_kernel_heap/libraries/test-types/src/lib.rs create mode 100644 19_kernel_heap/tools/kernel_symbols_tool/cmds.rb create mode 100644 19_kernel_heap/tools/kernel_symbols_tool/kernel_elf.rb create mode 100755 19_kernel_heap/tools/kernel_symbols_tool/main.rb create mode 100644 19_kernel_heap/tools/translation_table_tool/arch.rb create mode 100644 19_kernel_heap/tools/translation_table_tool/bsp.rb create mode 100644 19_kernel_heap/tools/translation_table_tool/generic.rb create mode 100644 19_kernel_heap/tools/translation_table_tool/kernel_elf.rb create mode 100755 19_kernel_heap/tools/translation_table_tool/main.rb diff --git a/19_kernel_heap/.cargo/config.toml b/19_kernel_heap/.cargo/config.toml new file mode 100644 index 00000000..e3476485 --- /dev/null +++ b/19_kernel_heap/.cargo/config.toml @@ -0,0 +1,2 @@ +[target.'cfg(target_os = "none")'] +runner = "target/kernel_test_runner.sh" diff --git a/19_kernel_heap/.vscode/settings.json b/19_kernel_heap/.vscode/settings.json new file mode 100644 index 00000000..292bf2a9 --- /dev/null +++ b/19_kernel_heap/.vscode/settings.json @@ -0,0 +1,10 @@ +{ + "editor.formatOnSave": true, + "editor.rulers": [100], + "rust-analyzer.cargo.target": "aarch64-unknown-none-softfloat", + "rust-analyzer.cargo.features": ["bsp_rpi3"], + "rust-analyzer.checkOnSave.allTargets": false, + "rust-analyzer.checkOnSave.extraArgs": ["--lib", "--bins"], + "rust-analyzer.lens.debug": false, + "rust-analyzer.lens.run": false +} diff --git a/19_kernel_heap/Cargo.lock b/19_kernel_heap/Cargo.lock new file mode 100644 index 00000000..e1d35499 --- /dev/null +++ b/19_kernel_heap/Cargo.lock @@ -0,0 +1,103 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "cortex-a" +version = "7.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27bd91f65ccd348bb2d043d98c5b34af141ecef7f102147f59bf5898f6e734ad" +dependencies = [ + "tock-registers", +] + +[[package]] +name = "debug-symbol-types" +version = "0.1.0" + +[[package]] +name = "kernel_symbols" +version = "0.1.0" +dependencies = [ + "debug-symbol-types", +] + +[[package]] +name = "linked_list_allocator" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "549ce1740e46b291953c4340adcd74c59bcf4308f4cac050fd33ba91b7168f4a" + +[[package]] +name = "mingo" +version = "0.19.0" +dependencies = [ + "cortex-a", + "debug-symbol-types", + "linked_list_allocator", + "qemu-exit", + "test-macros", + "test-types", + "tock-registers", +] + +[[package]] +name = "proc-macro2" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec757218438d5fda206afc041538b2f6d889286160d649a86a24d37e1235afd1" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "qemu-exit" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ff023245bfcc73fb890e1f8d5383825b3131cc920020a5c487d6f113dfc428a" + +[[package]] +name = "quote" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "syn" +version = "1.0.91" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b683b2b825c8eef438b77c36a06dc262294da3d5a5813fac20da149241dcd44d" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "test-macros" +version = "0.1.0" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "test-types", +] + +[[package]] +name = "test-types" +version = "0.1.0" + +[[package]] +name = "tock-registers" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ee8fba06c1f4d0b396ef61a54530bb6b28f0dc61c38bc8bc5a5a48161e6282e" + +[[package]] +name = "unicode-xid" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" diff --git a/19_kernel_heap/Cargo.toml b/19_kernel_heap/Cargo.toml new file mode 100644 index 00000000..38eeb116 --- /dev/null +++ b/19_kernel_heap/Cargo.toml @@ -0,0 +1,11 @@ +[workspace] + +members = [ + "libraries/*", + "kernel", + "kernel_symbols" +] + +[profile.release] +lto = true +debug = true diff --git a/19_kernel_heap/Makefile b/19_kernel_heap/Makefile new file mode 100644 index 00000000..bd1bc803 --- /dev/null +++ b/19_kernel_heap/Makefile @@ -0,0 +1,394 @@ +## SPDX-License-Identifier: MIT OR Apache-2.0 +## +## Copyright (c) 2018-2022 Andre Richter + +include ../common/format.mk +include ../common/docker.mk + +##-------------------------------------------------------------------------------------------------- +## Optional, user-provided configuration values +##-------------------------------------------------------------------------------------------------- + +# Default to the RPi3. +BSP ?= rpi3 + +# Default to a serial device name that is common in Linux. +DEV_SERIAL ?= /dev/ttyUSB0 + +# Optional debug prints. +ifdef DEBUG_PRINTS + FEATURES = --features debug_prints +endif + +# Optional integration test name. +ifdef TEST + TEST_ARG = --test $(TEST) +else + TEST_ARG = --test '*' +endif + + + +##-------------------------------------------------------------------------------------------------- +## BSP-specific configuration values +##-------------------------------------------------------------------------------------------------- +QEMU_MISSING_STRING = "This board is not yet supported for QEMU." + +ifeq ($(BSP),rpi3) + TARGET = aarch64-unknown-none-softfloat + KERNEL_BIN = kernel8.img + QEMU_BINARY = qemu-system-aarch64 + QEMU_MACHINE_TYPE = raspi3 + QEMU_RELEASE_ARGS = -serial stdio -display none + QEMU_TEST_ARGS = $(QEMU_RELEASE_ARGS) -semihosting + OBJDUMP_BINARY = aarch64-none-elf-objdump + NM_BINARY = aarch64-none-elf-nm + READELF_BINARY = aarch64-none-elf-readelf + OPENOCD_ARG = -f /openocd/tcl/interface/ftdi/olimex-arm-usb-tiny-h.cfg -f /openocd/rpi3.cfg + JTAG_BOOT_IMAGE = ../X1_JTAG_boot/jtag_boot_rpi3.img + LD_SCRIPT_PATH = $(shell pwd)/kernel/src/bsp/raspberrypi + RUSTC_MISC_ARGS = -C target-cpu=cortex-a53 -C force-frame-pointers +else ifeq ($(BSP),rpi4) + TARGET = aarch64-unknown-none-softfloat + KERNEL_BIN = kernel8.img + QEMU_BINARY = qemu-system-aarch64 + QEMU_MACHINE_TYPE = + QEMU_RELEASE_ARGS = -serial stdio -display none + QEMU_TEST_ARGS = $(QEMU_RELEASE_ARGS) -semihosting + OBJDUMP_BINARY = aarch64-none-elf-objdump + NM_BINARY = aarch64-none-elf-nm + READELF_BINARY = aarch64-none-elf-readelf + OPENOCD_ARG = -f /openocd/tcl/interface/ftdi/olimex-arm-usb-tiny-h.cfg -f /openocd/rpi4.cfg + JTAG_BOOT_IMAGE = ../X1_JTAG_boot/jtag_boot_rpi4.img + LD_SCRIPT_PATH = $(shell pwd)/kernel/src/bsp/raspberrypi + RUSTC_MISC_ARGS = -C target-cpu=cortex-a72 -C force-frame-pointers +endif + +# Export for build.rs. +export LD_SCRIPT_PATH + + + +##-------------------------------------------------------------------------------------------------- +## Targets and Prerequisites +##-------------------------------------------------------------------------------------------------- +KERNEL_MANIFEST = kernel/Cargo.toml +KERNEL_LINKER_SCRIPT = kernel.ld +LAST_BUILD_CONFIG = target/$(BSP)_$(DEBUG_PRINTS).build_config + +KERNEL_ELF_RAW = target/$(TARGET)/release/kernel +# This parses cargo's dep-info file. +# https://doc.rust-lang.org/cargo/guide/build-cache.html#dep-info-files +KERNEL_ELF_RAW_DEPS = $(filter-out %: ,$(file < $(KERNEL_ELF_RAW).d)) $(LAST_BUILD_CONFIG) + +##------------------------------------------------------------------------------ +## Translation tables +##------------------------------------------------------------------------------ +TT_TOOL_PATH = tools/translation_table_tool + +KERNEL_ELF_TTABLES = target/$(TARGET)/release/kernel+ttables +KERNEL_ELF_TTABLES_DEPS = $(KERNEL_ELF_RAW) $(wildcard $(TT_TOOL_PATH)/*) + +##------------------------------------------------------------------------------ +## Kernel symbols +##------------------------------------------------------------------------------ +export KERNEL_SYMBOLS_TOOL_PATH = tools/kernel_symbols_tool + +KERNEL_ELF_TTABLES_SYMS = target/$(TARGET)/release/kernel+ttables+symbols + +# Unlike with KERNEL_ELF_RAW, we are not relying on dep-info here. One of the reasons being that the +# name of the generated symbols file varies between runs, which can cause confusion. +KERNEL_ELF_TTABLES_SYMS_DEPS = $(KERNEL_ELF_TTABLES) \ + $(wildcard kernel_symbols/*) \ + $(wildcard $(KERNEL_SYMBOLS_TOOL_PATH)/*) + +export TARGET +export KERNEL_SYMBOLS_INPUT_ELF = $(KERNEL_ELF_TTABLES) +export KERNEL_SYMBOLS_OUTPUT_ELF = $(KERNEL_ELF_TTABLES_SYMS) + +KERNEL_ELF = $(KERNEL_ELF_TTABLES_SYMS) + + + +##-------------------------------------------------------------------------------------------------- +## Command building blocks +##-------------------------------------------------------------------------------------------------- +RUSTFLAGS = $(RUSTC_MISC_ARGS) \ + -C link-arg=--library-path=$(LD_SCRIPT_PATH) \ + -C link-arg=--script=$(KERNEL_LINKER_SCRIPT) + +RUSTFLAGS_PEDANTIC = $(RUSTFLAGS) \ + -D warnings \ + -D missing_docs + +FEATURES += --features bsp_$(BSP) +COMPILER_ARGS = --target=$(TARGET) \ + $(FEATURES) \ + --release + +# build-std can be skipped for helper commands that do not rely on correct stack frames and other +# custom compiler options. This results in a huge speedup. +RUSTC_CMD = cargo rustc $(COMPILER_ARGS) -Z build-std=core,alloc --manifest-path $(KERNEL_MANIFEST) +DOC_CMD = cargo doc $(COMPILER_ARGS) +CLIPPY_CMD = cargo clippy $(COMPILER_ARGS) +TEST_CMD = cargo test $(COMPILER_ARGS) -Z build-std=core,alloc --manifest-path $(KERNEL_MANIFEST) +OBJCOPY_CMD = rust-objcopy \ + --strip-all \ + -O binary + +EXEC_QEMU = $(QEMU_BINARY) -M $(QEMU_MACHINE_TYPE) +EXEC_TT_TOOL = ruby $(TT_TOOL_PATH)/main.rb +EXEC_TEST_DISPATCH = ruby ../common/tests/dispatch.rb +EXEC_MINIPUSH = ruby ../common/serial/minipush.rb + +##------------------------------------------------------------------------------ +## Dockerization +##------------------------------------------------------------------------------ +DOCKER_CMD = docker run -t --rm -v $(shell pwd):/work/tutorial -w /work/tutorial +DOCKER_CMD_INTERACT = $(DOCKER_CMD) -i +DOCKER_ARG_DIR_COMMON = -v $(shell pwd)/../common:/work/common +DOCKER_ARG_DIR_JTAG = -v $(shell pwd)/../X1_JTAG_boot:/work/X1_JTAG_boot +DOCKER_ARG_DEV = --privileged -v /dev:/dev +DOCKER_ARG_NET = --network host + +# DOCKER_IMAGE defined in include file (see top of this file). +DOCKER_QEMU = $(DOCKER_CMD_INTERACT) $(DOCKER_IMAGE) +DOCKER_TOOLS = $(DOCKER_CMD) $(DOCKER_IMAGE) +DOCKER_TEST = $(DOCKER_CMD) $(DOCKER_ARG_DIR_COMMON) $(DOCKER_IMAGE) +DOCKER_GDB = $(DOCKER_CMD_INTERACT) $(DOCKER_ARG_NET) $(DOCKER_IMAGE) + +# Dockerize commands, which require USB device passthrough, only on Linux. +ifeq ($(shell uname -s),Linux) + DOCKER_CMD_DEV = $(DOCKER_CMD_INTERACT) $(DOCKER_ARG_DEV) + + DOCKER_CHAINBOOT = $(DOCKER_CMD_DEV) $(DOCKER_ARG_DIR_COMMON) $(DOCKER_IMAGE) + DOCKER_JTAGBOOT = $(DOCKER_CMD_DEV) $(DOCKER_ARG_DIR_COMMON) $(DOCKER_ARG_DIR_JTAG) $(DOCKER_IMAGE) + DOCKER_OPENOCD = $(DOCKER_CMD_DEV) $(DOCKER_ARG_NET) $(DOCKER_IMAGE) +else + DOCKER_OPENOCD = echo "Not yet supported on non-Linux systems."; \# +endif + + + +##-------------------------------------------------------------------------------------------------- +## Targets +##-------------------------------------------------------------------------------------------------- +.PHONY: all doc qemu chainboot clippy clean readelf objdump nm check + +all: $(KERNEL_BIN) + +##------------------------------------------------------------------------------ +## Save the configuration as a file, so make understands if it changed. +##------------------------------------------------------------------------------ +$(LAST_BUILD_CONFIG): + @rm -f target/*.build_config + @mkdir -p target + @touch $(LAST_BUILD_CONFIG) + +##------------------------------------------------------------------------------ +## Compile the kernel ELF +##------------------------------------------------------------------------------ +$(KERNEL_ELF_RAW): $(KERNEL_ELF_RAW_DEPS) + $(call color_header, "Compiling kernel ELF - $(BSP)") + @RUSTFLAGS="$(RUSTFLAGS_PEDANTIC)" $(RUSTC_CMD) + +##------------------------------------------------------------------------------ +## Precompute the kernel translation tables and patch them into the kernel ELF +##------------------------------------------------------------------------------ +$(KERNEL_ELF_TTABLES): $(KERNEL_ELF_TTABLES_DEPS) + $(call color_header, "Precomputing kernel translation tables and patching kernel ELF") + @cp $(KERNEL_ELF_RAW) $(KERNEL_ELF_TTABLES) + @$(DOCKER_TOOLS) $(EXEC_TT_TOOL) $(BSP) $(KERNEL_ELF_TTABLES) + +##------------------------------------------------------------------------------ +## Generate kernel symbols and patch them into the kernel ELF +##------------------------------------------------------------------------------ +$(KERNEL_ELF_TTABLES_SYMS): $(KERNEL_ELF_TTABLES_SYMS_DEPS) + $(call color_header, "Generating kernel symbols and patching kernel ELF") + @time -f "in %es" \ + $(MAKE) --no-print-directory -f kernel_symbols.mk + +##------------------------------------------------------------------------------ +## Generate the stripped kernel binary +##------------------------------------------------------------------------------ +$(KERNEL_BIN): $(KERNEL_ELF_TTABLES_SYMS) + $(call color_header, "Generating stripped binary") + @$(OBJCOPY_CMD) $(KERNEL_ELF_TTABLES_SYMS) $(KERNEL_BIN) + $(call color_progress_prefix, "Name") + @echo $(KERNEL_BIN) + $(call color_progress_prefix, "Size") + @printf '%s KiB\n' `du -k $(KERNEL_BIN) | cut -f1` + +##------------------------------------------------------------------------------ +## Generate the documentation +##------------------------------------------------------------------------------ +doc: clean + $(call color_header, "Generating docs") + @$(DOC_CMD) --document-private-items --open + +##------------------------------------------------------------------------------ +## Run the kernel in QEMU +##------------------------------------------------------------------------------ +ifeq ($(QEMU_MACHINE_TYPE),) # QEMU is not supported for the board. + +qemu: + $(call color_header, "$(QEMU_MISSING_STRING)") + +else # QEMU is supported. + +qemu: $(KERNEL_BIN) + $(call color_header, "Launching QEMU") + @$(DOCKER_QEMU) $(EXEC_QEMU) $(QEMU_RELEASE_ARGS) -kernel $(KERNEL_BIN) + +endif + +##------------------------------------------------------------------------------ +## Push the kernel to the real HW target +##------------------------------------------------------------------------------ +chainboot: $(KERNEL_BIN) + @$(DOCKER_CHAINBOOT) $(EXEC_MINIPUSH) $(DEV_SERIAL) $(KERNEL_BIN) + +##------------------------------------------------------------------------------ +## Run clippy +##------------------------------------------------------------------------------ +clippy: + @RUSTFLAGS="$(RUSTFLAGS_PEDANTIC)" $(CLIPPY_CMD) + @RUSTFLAGS="$(RUSTFLAGS_PEDANTIC)" $(CLIPPY_CMD) --features test_build --tests \ + --manifest-path $(KERNEL_MANIFEST) + +##------------------------------------------------------------------------------ +## Clean +##------------------------------------------------------------------------------ +clean: + rm -rf target $(KERNEL_BIN) + +##------------------------------------------------------------------------------ +## Run readelf +##------------------------------------------------------------------------------ +readelf: $(KERNEL_ELF) + $(call color_header, "Launching readelf") + @$(DOCKER_TOOLS) $(READELF_BINARY) --headers $(KERNEL_ELF) + +##------------------------------------------------------------------------------ +## Run objdump +##------------------------------------------------------------------------------ +objdump: $(KERNEL_ELF) + $(call color_header, "Launching objdump") + @$(DOCKER_TOOLS) $(OBJDUMP_BINARY) --disassemble --demangle \ + --section .text \ + --section .rodata \ + --section .got \ + $(KERNEL_ELF) | rustfilt + +##------------------------------------------------------------------------------ +## Run nm +##------------------------------------------------------------------------------ +nm: $(KERNEL_ELF) + $(call color_header, "Launching nm") + @$(DOCKER_TOOLS) $(NM_BINARY) --demangle --print-size $(KERNEL_ELF) | sort | rustfilt + + + +##-------------------------------------------------------------------------------------------------- +## Debugging targets +##-------------------------------------------------------------------------------------------------- +.PHONY: jtagboot openocd gdb gdb-opt0 + +##------------------------------------------------------------------------------ +## Push the JTAG boot image to the real HW target +##------------------------------------------------------------------------------ +jtagboot: + @$(DOCKER_JTAGBOOT) $(EXEC_MINIPUSH) $(DEV_SERIAL) $(JTAG_BOOT_IMAGE) + +##------------------------------------------------------------------------------ +## Start OpenOCD session +##------------------------------------------------------------------------------ +openocd: + $(call color_header, "Launching OpenOCD") + @$(DOCKER_OPENOCD) openocd $(OPENOCD_ARG) + +##------------------------------------------------------------------------------ +## Start GDB session +##------------------------------------------------------------------------------ +gdb-opt0: RUSTC_MISC_ARGS += -C opt-level=0 +gdb gdb-opt0: $(KERNEL_ELF) + $(call color_header, "Launching GDB") + @$(DOCKER_GDB) gdb-multiarch -q $(KERNEL_ELF) + + + +##-------------------------------------------------------------------------------------------------- +## Testing targets +##-------------------------------------------------------------------------------------------------- +.PHONY: test test_boot test_unit test_integration + +test_unit test_integration: FEATURES += --features test_build + +ifeq ($(QEMU_MACHINE_TYPE),) # QEMU is not supported for the board. + +test_boot test_unit test_integration test: + $(call color_header, "$(QEMU_MISSING_STRING)") + +else # QEMU is supported. + +##------------------------------------------------------------------------------ +## Run boot test +##------------------------------------------------------------------------------ +test_boot: $(KERNEL_BIN) + $(call color_header, "Boot test - $(BSP)") + @$(DOCKER_TEST) $(EXEC_TEST_DISPATCH) $(EXEC_QEMU) $(QEMU_RELEASE_ARGS) -kernel $(KERNEL_BIN) + +##------------------------------------------------------------------------------ +## Helpers for unit and integration test targets +##------------------------------------------------------------------------------ +define KERNEL_TEST_RUNNER + #!/usr/bin/env bash + + # The cargo test runner seems to change into the crate under test's directory. Therefore, ensure + # this script executes from the root. + cd $(shell pwd) + + TEST_ELF=$$(echo $$1 | sed -e 's/.*target/target/g') + TEST_ELF_SYMS="$${TEST_ELF}_syms" + TEST_BINARY=$$(echo $$1.img | sed -e 's/.*target/target/g') + + $(DOCKER_TOOLS) $(EXEC_TT_TOOL) $(BSP) $$TEST_ELF > /dev/null + + # This overrides the two ENV variables. The other ENV variables that are required as input for + # the .mk file are set already because they are exported by this Makefile and this script is + # started by the same. + KERNEL_SYMBOLS_INPUT_ELF=$$TEST_ELF \ + KERNEL_SYMBOLS_OUTPUT_ELF=$$TEST_ELF_SYMS \ + $(MAKE) --no-print-directory -f kernel_symbols.mk > /dev/null 2>&1 + + $(OBJCOPY_CMD) $$TEST_ELF_SYMS $$TEST_BINARY + $(DOCKER_TEST) $(EXEC_TEST_DISPATCH) $(EXEC_QEMU) $(QEMU_TEST_ARGS) -kernel $$TEST_BINARY +endef + +export KERNEL_TEST_RUNNER + +define test_prepare + @mkdir -p target + @echo "$$KERNEL_TEST_RUNNER" > target/kernel_test_runner.sh + @chmod +x target/kernel_test_runner.sh +endef + +##------------------------------------------------------------------------------ +## Run unit test(s) +##------------------------------------------------------------------------------ +test_unit: + $(call color_header, "Compiling unit test(s) - $(BSP)") + $(call test_prepare) + @RUSTFLAGS="$(RUSTFLAGS_PEDANTIC)" $(TEST_CMD) --lib + +##------------------------------------------------------------------------------ +## Run integration test(s) +##------------------------------------------------------------------------------ +test_integration: + $(call color_header, "Compiling integration test(s) - $(BSP)") + $(call test_prepare) + @RUSTFLAGS="$(RUSTFLAGS_PEDANTIC)" $(TEST_CMD) $(TEST_ARG) + +test: test_boot test_unit test_integration + +endif diff --git a/19_kernel_heap/README.md b/19_kernel_heap/README.md new file mode 100644 index 00000000..430ff2fb --- /dev/null +++ b/19_kernel_heap/README.md @@ -0,0 +1,1356 @@ +# Tutorial 19 - Kernel Heap + +## tl;dr + +- A global heap for the kernel is added, which enables runtime dynamic memory allocation (`Box`, + `Vec`, etc.). +- Heap memory management is using a `linked list allocator`. +- A `debug!` printing macro is added that is only effective when `make` is invoked with + `DEBUG_PRINTS=y`. + +## Table of Contents + +- [Introduction](#introduction) +- [Implementation](#implementation) + - [Debug Prints](#debug-prints) + - [Pre-UART Console Output](#pre-uart-console-output) +- [Test it](#test-it) +- [Diff to previous](#diff-to-previous) + +## Introduction + +The kernel is finally in a good place to add dynamic memory management. The entire kernel runs in +the higher half of the address space by now, and it has decent backtracing support, which can be +leveraged to get rich tracing/debugging support for heap allocations. + +Although it is a vital part of implementing a heap, this tutorial will **not** cover +`allocation/deallocation` of heap memory. Instead, we will re-use [@phil-opp]'s excellent +[`linked_list_allocator`]. The reason is that while dynamic memory allocation algorithms are an +interesting topic, there would not be much added benefit in implementing a `linked list allocator` +of our own, since it would turn out very similar to what Philipp and the other contributors have +implemented already. So we might just re-use that, even more so because it can be plugged seamlessly +into our kernel. [@phil-opp] has also written two great articles on [Heap Allocation] and [Allocator +Designs]. I really recommend to read those now before continuing with this tutorial. + +[@phil-opp]: https://github.com/phil-opp +[`linked_list_allocator`]: https://crates.io/crates/linked_list_allocator +[Heap Allocation]: https://os.phil-opp.com/heap-allocation/ +[Allocator Designs]: https://os.phil-opp.com/allocator-designs/ + +That being said, what this tutorial text will cover is supporting changes for _enabling_ the +linked_list_allocator, and changes to kernel code leveraging the heap. + +## Implementation + +First of all, we need to reserve some DRAM for the heap. Traditionally, this is done in the `linker +script`. We place it after the `.data` section and before the `MMIO remap` section. + +```ld.s + __data_end_exclusive = .; + + /*********************************************************************************************** + * Heap + ***********************************************************************************************/ + __heap_start = .; + .heap (NOLOAD) : + { + . += 16 * 1024 * 1024; + } :segment_heap + __heap_end_exclusive = .; + + ASSERT((. & PAGE_MASK) == 0, "Heap is not page aligned") + + /*********************************************************************************************** + * MMIO Remap Reserved + ***********************************************************************************************/ + __mmio_remap_start = .; +``` + +In the Rust code, the heap properties can now be queried using the added BSP-function +`bsp::memory::mmu::virt_heap_region()`. The heap allocator itself is added in +`src/memory/heap_alloc.rs`. There, we add the `linked_list_allocator`, wrap it into an +`IRQSafeNullock`, and instantiate it the wrapper in a `static`. This way, global access to the +allocator becomes concurrency-safe: + +```rust +use linked_list_allocator::Heap as LinkedListHeap; + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +/// A heap allocator that can be lazyily initialized. +pub struct HeapAllocator { + inner: IRQSafeNullLock, +} + +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +#[global_allocator] +static KERNEL_HEAP_ALLOCATOR: HeapAllocator = HeapAllocator::new(); +``` + +All that is left to do now is to implement the [`GlobalAlloc`] trait for `HeapAllocator`: + +[`GlobalAlloc`]: https://doc.rust-lang.org/stable/core/alloc/trait.GlobalAlloc.html + +```rust +unsafe impl GlobalAlloc for HeapAllocator { + unsafe fn alloc(&self, layout: Layout) -> *mut u8 { + let result = KERNEL_HEAP_ALLOCATOR + .inner + .lock(|inner| inner.allocate_first_fit(layout).ok()); + + match result { + None => core::ptr::null_mut(), + Some(allocation) => { + let ptr = allocation.as_ptr(); + + debug_print_alloc_dealloc("Allocation", ptr, layout); + + ptr + } + } + } + + unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) { + KERNEL_HEAP_ALLOCATOR + .inner + .lock(|inner| inner.deallocate(core::ptr::NonNull::new_unchecked(ptr), layout)); + + debug_print_alloc_dealloc("Free", ptr, layout); + } +} +``` + +During kernel init, `kernel_init_heap_allocator()` will be called, which basically points the +wrapped allocator to the heap that we defined earlier: + +```rust +/// Query the BSP for the heap region and initialize the kernel's heap allocator with it. +pub fn kernel_init_heap_allocator() { + let region = bsp::memory::mmu::virt_heap_region(); + + KERNEL_HEAP_ALLOCATOR + .inner + .lock(|inner| unsafe { inner.init(region.start_addr().as_usize(), region.size()) }); +} +``` + +That's it already! We can now use `Box`, `Vec` and friends 🥳. + +### Debug Prints + +You might have noticed the `debug_print_alloc_dealloc()` calls in above's snippet. Under the hood, +this function makes use of the `debug!` macro that has been added in this tutorial. This macro will +only print to the console when `make` is invoked with the `ENV` variable `DEBUG_PRINTS` set to +"**y**". As you can see in the following snippet, this enables rich debug output for heap +allocations and deallocations, containing information such as `size`, `start` and `end exclusive` +addresses, as well as a backtrace that shows from where the (de)allocation originated. + +```console +$ DEBUG_PRINTS=y make qemu + +[...] + + Kernel Heap: Allocation + Size: 0x10 (16 Byte) + Start: 0xffff_ffff_c00a_0010 + End excl: 0xffff_ffff_c00a_0020 + + Backtrace: + ---------------------------------------------------------------------------------------------- + Address Function containing address + ---------------------------------------------------------------------------------------------- + 1. ffffffffc000cdf8 | ::write_fmt + 2. ffffffffc000b4f8 | ::alloc + 3. ffffffffc000d940 | libkernel::memory::mmu::mapping_record::kernel_add + 4. ffffffffc000adec | libkernel::bsp::raspberrypi::memory::mmu::kernel_add_mapping_records_for_precomputed + 5. ffffffffc00016ac | kernel_init + ---------------------------------------------------------------------------------------------- + +[ 0.042872] mingo version 0.19.0 +[ 0.043080] Booting on: Raspberry Pi 3 +``` + +### Pre-UART Console Output + +Having a heap allows us to simplify a few modules by switching static-length arrays to the dynamic +`Vec` data structure. Examples are the `interrupt controller drivers` for their handler tables, +`src/memory/mmu/mapping_record.rs` for bookkeeping virtual memory mappings and the `BSP driver +manager` for its instantiated device drivers. + +However, many of those allocations happen already **before** the UART driver comes online. +Therefore, a lot of the (de)allocation debug prints would go into the void with the way pre-UART +prints have been handled so far, which is undesirable. To solve this problem, the kernel's initial +(aka pre-UART) console is now not a `NullConsole` anymore, but a `BufferConsole`. The latter owns a +small static array of `chars`, that records any console prints before the actual UART driver comes +online. Once the UART driver is registered in the kernel to become the default console, the first +thing that is done is to print any buffered records of the `BufferConsole`: + +```rust +pub fn register_console(new_console: &'static (dyn interface::All + Sync)) { + CUR_CONSOLE.write(|con| *con = new_console); + + static FIRST_SWITCH: InitStateLock = InitStateLock::new(true); + FIRST_SWITCH.write(|first| { + if *first == true { + *first = false; + + buffer_console::BUFFER_CONSOLE.dump(); + } + }); +} +``` + +`BUFFER_CONSOLE.dump()` just drains its buffer to using the newly registered console. + +## Test it + +If compiled without `DEBUG_PRINTS`, the heap can be observed in the mapping overview and through the +newly added usage statistics: + +```console +$ make chainboot +[...] +Minipush 1.0 + +[MP] ⏳ Waiting for /dev/ttyUSB0 +[MP] ✅ Serial connected +[MP] 🔌 Please power the target now + + __ __ _ _ _ _ +| \/ (_)_ _ (_) | ___ __ _ __| | +| |\/| | | ' \| | |__/ _ \/ _` / _` | +|_| |_|_|_||_|_|____\___/\__,_\__,_| + + Raspberry Pi 3 + +[ML] Requesting binary +[MP] ⏩ Pushing 320 KiB ======================================🦀 100% 106 KiB/s Time: 00:00:03 +[ML] Loaded! Executing the payload now + +[ 3.572716] mingo version 0.19.0 +[ 3.572924] Booting on: Raspberry Pi 3 +[ 3.573379] MMU online: +[ 3.573672] ------------------------------------------------------------------------------------------------------------------------------------------- +[ 3.575416] Virtual Physical Size Attr Entity +[ 3.577160] ------------------------------------------------------------------------------------------------------------------------------------------- +[ 3.578905] 0xffff_ffff_c000_0000..0xffff_ffff_c001_ffff --> 0x00_0008_0000..0x00_0009_ffff | 128 KiB | C RO X | Kernel code and RO data +[ 3.580519] 0xffff_ffff_c002_0000..0xffff_ffff_c009_ffff --> 0x00_000a_0000..0x00_0011_ffff | 512 KiB | C RW XN | Kernel data and bss +[ 3.582089] 0xffff_ffff_c00a_0000..0xffff_ffff_c109_ffff --> 0x00_0012_0000..0x00_0111_ffff | 16 MiB | C RW XN | Kernel heap +[ 3.583573] 0xffff_ffff_c10a_0000..0xffff_ffff_c10a_ffff --> 0x00_3f20_0000..0x00_3f20_ffff | 64 KiB | Dev RW XN | BCM PL011 UART +[ 3.585090] | BCM GPIO +[ 3.586542] 0xffff_ffff_c10b_0000..0xffff_ffff_c10b_ffff --> 0x00_3f00_0000..0x00_3f00_ffff | 64 KiB | Dev RW XN | BCM Interrupt Controller +[ 3.588167] 0xffff_ffff_c18b_0000..0xffff_ffff_c192_ffff --> 0x00_0000_0000..0x00_0007_ffff | 512 KiB | C RW XN | Kernel boot-core stack +[ 3.589770] ------------------------------------------------------------------------------------------------------------------------------------------- +[ 3.591515] Current privilege level: EL1 + +[...] + +[ 3.597624] Kernel heap: +[ 3.597928] Used: 2512 Byte (3 KiB) +[ 3.598415] Free: 16774704 Byte (16 MiB) +[ 3.598957] Echoing input now +``` + +## Diff to previous +```diff + +diff -uNr 18_backtrace/kernel/Cargo.toml 19_kernel_heap/kernel/Cargo.toml +--- 18_backtrace/kernel/Cargo.toml ++++ 19_kernel_heap/kernel/Cargo.toml +@@ -1,11 +1,12 @@ + [package] + name = "mingo" +-version = "0.18.0" ++version = "0.19.0" + authors = ["Andre Richter "] + edition = "2021" + + [features] + default = [] ++debug_prints = [] + bsp_rpi3 = ["tock-registers"] + bsp_rpi4 = ["tock-registers"] + test_build = ["qemu-exit"] +@@ -17,6 +18,7 @@ + [dependencies] + test-types = { path = "../libraries/test-types" } + debug-symbol-types = { path = "../libraries/debug-symbol-types" } ++linked_list_allocator = { version = "0.9.x", default-features = false, features = ["const_mut_refs"] } + + # Optional dependencies + tock-registers = { version = "0.7.x", default-features = false, features = ["register_types"], optional = true } + +diff -uNr 18_backtrace/kernel/src/bsp/device_driver/arm/gicv2.rs 19_kernel_heap/kernel/src/bsp/device_driver/arm/gicv2.rs +--- 18_backtrace/kernel/src/bsp/device_driver/arm/gicv2.rs ++++ 19_kernel_heap/kernel/src/bsp/device_driver/arm/gicv2.rs +@@ -85,12 +85,13 @@ + synchronization, + synchronization::InitStateLock, + }; ++use alloc::vec::Vec; + + //-------------------------------------------------------------------------------------------------- + // Private Definitions + //-------------------------------------------------------------------------------------------------- + +-type HandlerTable = [Option; GICv2::NUM_IRQS]; ++type HandlerTable = Vec>; + + //-------------------------------------------------------------------------------------------------- + // Public Definitions +@@ -119,8 +120,7 @@ + //-------------------------------------------------------------------------------------------------- + + impl GICv2 { +- const MAX_IRQ_NUMBER: usize = 300; // Normally 1019, but keep it lower to save some space. +- const NUM_IRQS: usize = Self::MAX_IRQ_NUMBER + 1; ++ const MAX_IRQ_NUMBER: usize = 1019; + + pub const COMPATIBLE: &'static str = "GICv2 (ARM Generic Interrupt Controller v2)"; + +@@ -137,7 +137,7 @@ + Self { + gicd: gicd::GICD::new(gicd_mmio_start_addr), + gicc: gicc::GICC::new(gicc_mmio_start_addr), +- handler_table: InitStateLock::new([None; Self::NUM_IRQS]), ++ handler_table: InitStateLock::new(Vec::new()), + post_init_callback, + } + } +@@ -178,6 +178,12 @@ + self.handler_table.write(|table| { + let irq_number = irq_number.get(); + ++ if table.len() < irq_number { ++ // IRQDescriptor has an integrated range sanity check on construction, so this ++ // vector can't grow arbitrarily big. ++ table.resize(irq_number + 1, None); ++ } ++ + if table[irq_number].is_some() { + return Err("IRQ handler already registered"); + } + +diff -uNr 18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs 19_kernel_heap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs +--- 18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs ++++ 19_kernel_heap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs +@@ -4,7 +4,7 @@ + + //! Peripheral Interrupt Controller Driver. + +-use super::{InterruptController, PendingIRQs, PeripheralIRQ}; ++use super::{PendingIRQs, PeripheralIRQ}; + use crate::{ + bsp::device_driver::common::MMIODerefWrapper, + exception, +@@ -12,6 +12,7 @@ + synchronization, + synchronization::{IRQSafeNullLock, InitStateLock}, + }; ++use alloc::vec::Vec; + use tock_registers::{ + interfaces::{Readable, Writeable}, + register_structs, +@@ -48,8 +49,7 @@ + /// Abstraction for the ReadOnly parts of the associated MMIO registers. + type ReadOnlyRegisters = MMIODerefWrapper; + +-type HandlerTable = +- [Option; InterruptController::NUM_PERIPHERAL_IRQS]; ++type HandlerTable = Vec>; + + //-------------------------------------------------------------------------------------------------- + // Public Definitions +@@ -81,7 +81,7 @@ + Self { + wo_registers: IRQSafeNullLock::new(WriteOnlyRegisters::new(mmio_start_addr)), + ro_registers: ReadOnlyRegisters::new(mmio_start_addr), +- handler_table: InitStateLock::new([None; InterruptController::NUM_PERIPHERAL_IRQS]), ++ handler_table: InitStateLock::new(Vec::new()), + } + } + +@@ -110,6 +110,12 @@ + self.handler_table.write(|table| { + let irq_number = irq.get(); + ++ if table.len() < irq_number { ++ // IRQDescriptor has an integrated range sanity check on construction, so this ++ // vector can't grow arbitrarily big. ++ table.resize(irq_number + 1, None); ++ } ++ + if table[irq_number].is_some() { + return Err("IRQ handler already registered"); + } + +diff -uNr 18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs 19_kernel_heap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs +--- 18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs ++++ 19_kernel_heap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs +@@ -77,7 +77,6 @@ + impl InterruptController { + const MAX_LOCAL_IRQ_NUMBER: usize = 11; + const MAX_PERIPHERAL_IRQ_NUMBER: usize = 63; +- const NUM_PERIPHERAL_IRQS: usize = Self::MAX_PERIPHERAL_IRQ_NUMBER + 1; + + pub const COMPATIBLE: &'static str = "BCM Interrupt Controller"; + + +diff -uNr 18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs 19_kernel_heap/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs +--- 18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs ++++ 19_kernel_heap/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs +@@ -329,6 +329,13 @@ + self.chars_written += 1; + } + ++ /// Send a slice of characters. ++ fn write_array(&mut self, a: &[char]) { ++ for c in a { ++ self.write_char(*c); ++ } ++ } ++ + /// Block execution until the last buffered character has been physically put on the TX wire. + fn flush(&self) { + // Spin until the busy bit is cleared. +@@ -451,6 +458,10 @@ + self.inner.lock(|inner| inner.write_char(c)); + } + ++ fn write_array(&self, a: &[char]) { ++ self.inner.lock(|inner| inner.write_array(a)); ++ } ++ + fn write_fmt(&self, args: core::fmt::Arguments) -> fmt::Result { + // Fully qualified syntax for the call to `core::fmt::Write::write_fmt()` to increase + // readability. + +diff -uNr 18_backtrace/kernel/src/bsp/raspberrypi/driver.rs 19_kernel_heap/kernel/src/bsp/raspberrypi/driver.rs +--- 18_backtrace/kernel/src/bsp/raspberrypi/driver.rs ++++ 19_kernel_heap/kernel/src/bsp/raspberrypi/driver.rs +@@ -11,11 +11,11 @@ + memory::mmu::MMIODescriptor, + synchronization::{interface::ReadWriteEx, InitStateLock}, + }; ++use alloc::vec::Vec; + use core::{ + mem::MaybeUninit, + sync::atomic::{AtomicBool, Ordering}, + }; +- + pub use device_driver::IRQNumber; + + //-------------------------------------------------------------------------------------------------- +@@ -24,18 +24,11 @@ + + /// Device Driver Manager type. + struct BSPDriverManager { +- device_drivers: InitStateLock<[Option<&'static (dyn DeviceDriver + Sync)>; NUM_DRIVERS]>, ++ device_drivers: InitStateLock>, + init_done: AtomicBool, + } + + //-------------------------------------------------------------------------------------------------- +-// Public Definitions +-//-------------------------------------------------------------------------------------------------- +- +-/// The number of active drivers provided by this BSP. +-pub const NUM_DRIVERS: usize = 3; +- +-//-------------------------------------------------------------------------------------------------- + // Global instances + //-------------------------------------------------------------------------------------------------- + +@@ -50,7 +43,7 @@ + static mut INTERRUPT_CONTROLLER: MaybeUninit = MaybeUninit::uninit(); + + static BSP_DRIVER_MANAGER: BSPDriverManager = BSPDriverManager { +- device_drivers: InitStateLock::new([None; NUM_DRIVERS]), ++ device_drivers: InitStateLock::new(Vec::new()), + init_done: AtomicBool::new(false), + }; + +@@ -143,9 +136,9 @@ + + unsafe fn register_drivers(&self) { + self.device_drivers.write(|drivers| { +- drivers[0] = Some(PL011_UART.assume_init_ref()); +- drivers[1] = Some(GPIO.assume_init_ref()); +- drivers[2] = Some(INTERRUPT_CONTROLLER.assume_init_ref()); ++ drivers.push(PL011_UART.assume_init_ref()); ++ drivers.push(GPIO.assume_init_ref()); ++ drivers.push(INTERRUPT_CONTROLLER.assume_init_ref()); + }); + } + } +@@ -180,9 +173,8 @@ + Ok(()) + } + +- fn all_device_drivers(&self) -> [&(dyn DeviceDriver + Sync); NUM_DRIVERS] { +- self.device_drivers +- .read(|drivers| drivers.map(|drivers| drivers.unwrap())) ++ fn all_device_drivers(&self) -> &Vec<&(dyn DeviceDriver + Sync)> { ++ self.device_drivers.read(|drivers| drivers) + } + + #[cfg(feature = "test_build")] + +diff -uNr 18_backtrace/kernel/src/bsp/raspberrypi/kernel.ld 19_kernel_heap/kernel/src/bsp/raspberrypi/kernel.ld +--- 18_backtrace/kernel/src/bsp/raspberrypi/kernel.ld ++++ 19_kernel_heap/kernel/src/bsp/raspberrypi/kernel.ld +@@ -35,6 +35,7 @@ + { + segment_code PT_LOAD FLAGS(5); + segment_data PT_LOAD FLAGS(6); ++ segment_heap PT_LOAD FLAGS(6); + segment_boot_core_stack PT_LOAD FLAGS(6); + } + +@@ -85,6 +86,18 @@ + __data_end_exclusive = .; + + /*********************************************************************************************** ++ * Heap ++ ***********************************************************************************************/ ++ __heap_start = .; ++ .heap (NOLOAD) : ++ { ++ . += 16 * 1024 * 1024; ++ } :segment_heap ++ __heap_end_exclusive = .; ++ ++ ASSERT((. & PAGE_MASK) == 0, "Heap is not page aligned") ++ ++ /*********************************************************************************************** + * MMIO Remap Reserved + ***********************************************************************************************/ + __mmio_remap_start = .; + +diff -uNr 18_backtrace/kernel/src/bsp/raspberrypi/memory/mmu.rs 19_kernel_heap/kernel/src/bsp/raspberrypi/memory/mmu.rs +--- 18_backtrace/kernel/src/bsp/raspberrypi/memory/mmu.rs ++++ 19_kernel_heap/kernel/src/bsp/raspberrypi/memory/mmu.rs +@@ -122,6 +122,16 @@ + MemoryRegion::new(start_page_addr, end_exclusive_page_addr) + } + ++/// The heap pages. ++pub fn virt_heap_region() -> MemoryRegion { ++ let num_pages = size_to_num_pages(super::heap_size()); ++ ++ let start_page_addr = super::virt_heap_start(); ++ let end_exclusive_page_addr = start_page_addr.checked_offset(num_pages as isize).unwrap(); ++ ++ MemoryRegion::new(start_page_addr, end_exclusive_page_addr) ++} ++ + /// The boot core stack pages. + pub fn virt_boot_core_stack_region() -> MemoryRegion { + let num_pages = size_to_num_pages(super::boot_core_stack_size()); +@@ -169,6 +179,14 @@ + &kernel_page_attributes(virt_data_region.start_page_addr()), + ); + ++ let virt_heap_region = virt_heap_region(); ++ generic_mmu::kernel_add_mapping_record( ++ "Kernel heap", ++ &virt_heap_region, ++ &kernel_virt_to_phys_region(virt_heap_region), ++ &kernel_page_attributes(virt_heap_region.start_page_addr()), ++ ); ++ + let virt_boot_core_stack_region = virt_boot_core_stack_region(); + generic_mmu::kernel_add_mapping_record( + "Kernel boot-core stack", + +diff -uNr 18_backtrace/kernel/src/bsp/raspberrypi/memory.rs 19_kernel_heap/kernel/src/bsp/raspberrypi/memory.rs +--- 18_backtrace/kernel/src/bsp/raspberrypi/memory.rs ++++ 19_kernel_heap/kernel/src/bsp/raspberrypi/memory.rs +@@ -28,7 +28,11 @@ + //! | .bss | + //! | | + //! +---------------------------------------+ +-//! | | data_end_exclusive ++//! | | heap_start == data_end_exclusive ++//! | .heap | ++//! | | ++//! +---------------------------------------+ ++//! | | heap_end_exclusive + //! | | + //! + //! +@@ -50,7 +54,11 @@ + //! | .bss | + //! | | + //! +---------------------------------------+ +-//! | | mmio_remap_start == data_end_exclusive ++//! | | heap_start == data_end_exclusive ++//! | .heap | ++//! | | ++//! +---------------------------------------+ ++//! | | mmio_remap_start == heap_end_exclusive + //! | VA region for MMIO remapping | + //! | | + //! +---------------------------------------+ +@@ -83,6 +91,9 @@ + static __data_start: UnsafeCell<()>; + static __data_end_exclusive: UnsafeCell<()>; + ++ static __heap_start: UnsafeCell<()>; ++ static __heap_end_exclusive: UnsafeCell<()>; ++ + static __mmio_remap_start: UnsafeCell<()>; + static __mmio_remap_end_exclusive: UnsafeCell<()>; + +@@ -179,6 +190,22 @@ + unsafe { (__data_end_exclusive.get() as usize) - (__data_start.get() as usize) } + } + ++/// Start page address of the heap segment. ++#[inline(always)] ++fn virt_heap_start() -> PageAddress { ++ PageAddress::from(unsafe { __heap_start.get() as usize }) ++} ++ ++/// Size of the heap segment. ++/// ++/// # Safety ++/// ++/// - Value is provided by the linker script and must be trusted as-is. ++#[inline(always)] ++fn heap_size() -> usize { ++ unsafe { (__heap_end_exclusive.get() as usize) - (__heap_start.get() as usize) } ++} ++ + /// Start page address of the MMIO remap reservation. + /// + /// # Safety + +diff -uNr 18_backtrace/kernel/src/console/buffer_console.rs 19_kernel_heap/kernel/src/console/buffer_console.rs +--- 18_backtrace/kernel/src/console/buffer_console.rs ++++ 19_kernel_heap/kernel/src/console/buffer_console.rs +@@ -0,0 +1,108 @@ ++// SPDX-License-Identifier: MIT OR Apache-2.0 ++// ++// Copyright (c) 2022 Andre Richter ++ ++//! A console that buffers input during the init phase. ++ ++use super::interface; ++use crate::{console, info, synchronization, synchronization::InitStateLock}; ++use core::fmt; ++ ++//-------------------------------------------------------------------------------------------------- ++// Private Definitions ++//-------------------------------------------------------------------------------------------------- ++ ++const BUF_SIZE: usize = 1024 * 64; ++ ++pub struct BufferConsoleInner { ++ buf: [char; BUF_SIZE], ++ write_ptr: usize, ++} ++ ++//-------------------------------------------------------------------------------------------------- ++// Public Definitions ++//-------------------------------------------------------------------------------------------------- ++ ++pub struct BufferConsole { ++ inner: InitStateLock, ++} ++ ++//-------------------------------------------------------------------------------------------------- ++// Global instances ++//-------------------------------------------------------------------------------------------------- ++ ++pub static BUFFER_CONSOLE: BufferConsole = BufferConsole { ++ inner: InitStateLock::new(BufferConsoleInner { ++ // Use the null character, so this lands in .bss and does not waste space in the binary. ++ buf: ['\0'; BUF_SIZE], ++ write_ptr: 0, ++ }), ++}; ++ ++//-------------------------------------------------------------------------------------------------- ++// Private Code ++//-------------------------------------------------------------------------------------------------- ++ ++impl BufferConsoleInner { ++ fn write_char(&mut self, c: char) { ++ if self.write_ptr < (BUF_SIZE - 1) { ++ self.buf[self.write_ptr] = c; ++ self.write_ptr += 1; ++ } ++ } ++} ++ ++impl fmt::Write for BufferConsoleInner { ++ fn write_str(&mut self, s: &str) -> fmt::Result { ++ for c in s.chars() { ++ self.write_char(c); ++ } ++ ++ Ok(()) ++ } ++} ++ ++//-------------------------------------------------------------------------------------------------- ++// Public Code ++//-------------------------------------------------------------------------------------------------- ++use synchronization::interface::ReadWriteEx; ++ ++impl BufferConsole { ++ /// Dump the buffer. ++ /// ++ /// # Invariant ++ /// ++ /// It is expected that this is only called when self != crate::console::console(). ++ pub fn dump(&self) { ++ self.inner.read(|inner| { ++ console::console().write_array(&inner.buf[0..inner.write_ptr]); ++ ++ if inner.write_ptr == (BUF_SIZE - 1) { ++ info!("Pre-UART buffer overflowed"); ++ } else if inner.write_ptr > 0 { ++ info!("End of pre-UART buffer") ++ } ++ }); ++ } ++} ++ ++impl interface::Write for BufferConsole { ++ fn write_char(&self, c: char) { ++ self.inner.write(|inner| inner.write_char(c)); ++ } ++ ++ fn write_array(&self, _a: &[char]) {} ++ ++ fn write_fmt(&self, args: fmt::Arguments) -> fmt::Result { ++ self.inner.write(|inner| fmt::Write::write_fmt(inner, args)) ++ } ++ ++ fn flush(&self) {} ++} ++ ++impl interface::Read for BufferConsole { ++ fn clear_rx(&self) {} ++} ++ ++impl interface::Statistics for BufferConsole {} ++impl interface::All for BufferConsole {} + +diff -uNr 18_backtrace/kernel/src/console/null_console.rs 19_kernel_heap/kernel/src/console/null_console.rs +--- 18_backtrace/kernel/src/console/null_console.rs ++++ 19_kernel_heap/kernel/src/console/null_console.rs +@@ -1,41 +0,0 @@ +-// SPDX-License-Identifier: MIT OR Apache-2.0 +-// +-// Copyright (c) 2022 Andre Richter +- +-//! Null console. +- +-use super::interface; +-use core::fmt; +- +-//-------------------------------------------------------------------------------------------------- +-// Public Definitions +-//-------------------------------------------------------------------------------------------------- +- +-pub struct NullConsole; +- +-//-------------------------------------------------------------------------------------------------- +-// Global instances +-//-------------------------------------------------------------------------------------------------- +- +-pub static NULL_CONSOLE: NullConsole = NullConsole {}; +- +-//-------------------------------------------------------------------------------------------------- +-// Public Code +-//-------------------------------------------------------------------------------------------------- +- +-impl interface::Write for NullConsole { +- fn write_char(&self, _c: char) {} +- +- fn write_fmt(&self, _args: fmt::Arguments) -> fmt::Result { +- fmt::Result::Ok(()) +- } +- +- fn flush(&self) {} +-} +- +-impl interface::Read for NullConsole { +- fn clear_rx(&self) {} +-} +- +-impl interface::Statistics for NullConsole {} +-impl interface::All for NullConsole {} + +diff -uNr 18_backtrace/kernel/src/console.rs 19_kernel_heap/kernel/src/console.rs +--- 18_backtrace/kernel/src/console.rs ++++ 19_kernel_heap/kernel/src/console.rs +@@ -4,7 +4,7 @@ + + //! System console. + +-mod null_console; ++mod buffer_console; + + use crate::synchronization; + +@@ -21,6 +21,9 @@ + /// Write a single character. + fn write_char(&self, c: char); + ++ /// Write a slice of characters. ++ fn write_array(&self, a: &[char]); ++ + /// Write a Rust format string. + fn write_fmt(&self, args: fmt::Arguments) -> fmt::Result; + +@@ -61,7 +64,7 @@ + //-------------------------------------------------------------------------------------------------- + + static CUR_CONSOLE: InitStateLock<&'static (dyn interface::All + Sync)> = +- InitStateLock::new(&null_console::NULL_CONSOLE); ++ InitStateLock::new(&buffer_console::BUFFER_CONSOLE); + + //-------------------------------------------------------------------------------------------------- + // Public Code +@@ -71,6 +74,15 @@ + /// Register a new console. + pub fn register_console(new_console: &'static (dyn interface::All + Sync)) { + CUR_CONSOLE.write(|con| *con = new_console); ++ ++ static FIRST_SWITCH: InitStateLock = InitStateLock::new(true); ++ FIRST_SWITCH.write(|first| { ++ if *first == true { ++ *first = false; ++ ++ buffer_console::BUFFER_CONSOLE.dump(); ++ } ++ }); + } + + /// Return a reference to the currently registered console. + +diff -uNr 18_backtrace/kernel/src/driver.rs 19_kernel_heap/kernel/src/driver.rs +--- 18_backtrace/kernel/src/driver.rs ++++ 19_kernel_heap/kernel/src/driver.rs +@@ -10,7 +10,7 @@ + + /// Driver interfaces. + pub mod interface { +- use crate::bsp; ++ use alloc::vec::Vec; + + /// Device Driver functions. + pub trait DeviceDriver { +@@ -46,8 +46,8 @@ + /// Must be called before `all_device_drivers`. + unsafe fn instantiate_drivers(&self) -> Result<(), &'static str>; + +- /// Return a slice of references to all `BSP`-instantiated drivers. +- fn all_device_drivers(&self) -> [&(dyn DeviceDriver + Sync); bsp::driver::NUM_DRIVERS]; ++ /// Return a vector of references to all `BSP`-instantiated drivers. ++ fn all_device_drivers(&self) -> &Vec<&(dyn DeviceDriver + Sync)>; + + /// Minimal code needed to bring up the console in QEMU (for testing only). This is often + /// less steps than on real hardware due to QEMU's abstractions. + +diff -uNr 18_backtrace/kernel/src/lib.rs 19_kernel_heap/kernel/src/lib.rs +--- 18_backtrace/kernel/src/lib.rs ++++ 19_kernel_heap/kernel/src/lib.rs +@@ -110,6 +110,7 @@ + + #![allow(clippy::upper_case_acronyms)] + #![allow(incomplete_features)] ++#![feature(alloc_error_handler)] + #![feature(asm_const)] + #![feature(core_intrinsics)] + #![feature(format_args_nl)] +@@ -127,6 +128,8 @@ + #![reexport_test_harness_main = "test_main"] + #![test_runner(crate::test_runner)] + ++extern crate alloc; ++ + mod panic_wait; + mod synchronization; + + +diff -uNr 18_backtrace/kernel/src/main.rs 19_kernel_heap/kernel/src/main.rs +--- 18_backtrace/kernel/src/main.rs ++++ 19_kernel_heap/kernel/src/main.rs +@@ -13,6 +13,8 @@ + #![no_main] + #![no_std] + ++extern crate alloc; ++ + use libkernel::{bsp, cpu, driver, exception, info, memory, state, time, warn}; + + /// Early init code. +@@ -92,6 +94,9 @@ + info!("Registered IRQ handlers:"); + exception::asynchronous::irq_manager().print_handler(); + ++ info!("Kernel heap:"); ++ memory::heap_alloc::kernel_heap_allocator().print_usage(); ++ + info!("Echoing input now"); + cpu::wait_forever(); + } + +diff -uNr 18_backtrace/kernel/src/memory/heap_alloc.rs 19_kernel_heap/kernel/src/memory/heap_alloc.rs +--- 18_backtrace/kernel/src/memory/heap_alloc.rs ++++ 19_kernel_heap/kernel/src/memory/heap_alloc.rs +@@ -0,0 +1,137 @@ ++// SPDX-License-Identifier: MIT OR Apache-2.0 ++// ++// Copyright (c) 2022 Andre Richter ++ ++//! Heap allocation. ++ ++use crate::{ ++ backtrace, bsp, common, debug, info, ++ memory::{Address, Virtual}, ++ synchronization, ++ synchronization::IRQSafeNullLock, ++}; ++use alloc::alloc::{GlobalAlloc, Layout}; ++use linked_list_allocator::Heap as LinkedListHeap; ++ ++//-------------------------------------------------------------------------------------------------- ++// Public Definitions ++//-------------------------------------------------------------------------------------------------- ++ ++/// A heap allocator that can be lazyily initialized. ++pub struct HeapAllocator { ++ inner: IRQSafeNullLock, ++} ++ ++//-------------------------------------------------------------------------------------------------- ++// Global instances ++//-------------------------------------------------------------------------------------------------- ++ ++#[global_allocator] ++static KERNEL_HEAP_ALLOCATOR: HeapAllocator = HeapAllocator::new(); ++ ++//-------------------------------------------------------------------------------------------------- ++// Private Code ++//-------------------------------------------------------------------------------------------------- ++ ++#[inline(always)] ++fn debug_print_alloc_dealloc(operation: &'static str, ptr: *mut u8, layout: Layout) { ++ let size = layout.size(); ++ let (size_h, size_unit) = common::size_human_readable_ceil(size); ++ let addr = Address::::new(ptr as usize); ++ ++ debug!( ++ "Kernel Heap: {}\n \ ++ Size: {:#x} ({} {})\n \ ++ Start: {}\n \ ++ End excl: {}\n\n \ ++ {}", ++ operation, ++ size, ++ size_h, ++ size_unit, ++ addr, ++ addr + size, ++ backtrace::Backtrace ++ ); ++} ++ ++//-------------------------------------------------------------------------------------------------- ++// Public Code ++//-------------------------------------------------------------------------------------------------- ++use synchronization::interface::Mutex; ++ ++#[alloc_error_handler] ++fn alloc_error_handler(layout: Layout) -> ! { ++ panic!("Allocation error: {:?}", layout) ++} ++ ++/// Return a reference to the kernel's heap allocator. ++pub fn kernel_heap_allocator() -> &'static HeapAllocator { ++ &KERNEL_HEAP_ALLOCATOR ++} ++ ++impl HeapAllocator { ++ /// Create an instance. ++ pub const fn new() -> Self { ++ Self { ++ inner: IRQSafeNullLock::new(LinkedListHeap::empty()), ++ } ++ } ++ ++ /// Print the current heap usage. ++ pub fn print_usage(&self) { ++ let (used, free) = KERNEL_HEAP_ALLOCATOR ++ .inner ++ .lock(|inner| (inner.used(), inner.free())); ++ ++ if used >= 1024 { ++ let (used_h, used_unit) = common::size_human_readable_ceil(used); ++ info!(" Used: {} Byte ({} {})", used, used_h, used_unit); ++ } else { ++ info!(" Used: {} Byte", used); ++ } ++ ++ if free >= 1024 { ++ let (free_h, free_unit) = common::size_human_readable_ceil(free); ++ info!(" Free: {} Byte ({} {})", free, free_h, free_unit); ++ } else { ++ info!(" Free: {} Byte", free); ++ } ++ } ++} ++ ++unsafe impl GlobalAlloc for HeapAllocator { ++ unsafe fn alloc(&self, layout: Layout) -> *mut u8 { ++ let result = KERNEL_HEAP_ALLOCATOR ++ .inner ++ .lock(|inner| inner.allocate_first_fit(layout).ok()); ++ ++ match result { ++ None => core::ptr::null_mut(), ++ Some(allocation) => { ++ let ptr = allocation.as_ptr(); ++ ++ debug_print_alloc_dealloc("Allocation", ptr, layout); ++ ++ ptr ++ } ++ } ++ } ++ ++ unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) { ++ KERNEL_HEAP_ALLOCATOR ++ .inner ++ .lock(|inner| inner.deallocate(core::ptr::NonNull::new_unchecked(ptr), layout)); ++ ++ debug_print_alloc_dealloc("Free", ptr, layout); ++ } ++} ++ ++/// Query the BSP for the heap region and initialize the kernel's heap allocator with it. ++pub fn kernel_init_heap_allocator() { ++ let region = bsp::memory::mmu::virt_heap_region(); ++ ++ KERNEL_HEAP_ALLOCATOR ++ .inner ++ .lock(|inner| unsafe { inner.init(region.start_addr().as_usize(), region.size()) }); ++} + +diff -uNr 18_backtrace/kernel/src/memory/mmu/mapping_record.rs 19_kernel_heap/kernel/src/memory/mmu/mapping_record.rs +--- 18_backtrace/kernel/src/memory/mmu/mapping_record.rs ++++ 19_kernel_heap/kernel/src/memory/mmu/mapping_record.rs +@@ -8,7 +8,8 @@ + AccessPermissions, Address, AttributeFields, MMIODescriptor, MemAttributes, MemoryRegion, + Physical, Virtual, + }; +-use crate::{bsp, common, info, synchronization, synchronization::InitStateLock, warn}; ++use crate::{bsp, common, info, synchronization, synchronization::InitStateLock}; ++use alloc::{vec, vec::Vec}; + + //-------------------------------------------------------------------------------------------------- + // Private Definitions +@@ -16,9 +17,8 @@ + + /// Type describing a virtual memory mapping. + #[allow(missing_docs)] +-#[derive(Copy, Clone)] + struct MappingRecordEntry { +- pub users: [Option<&'static str>; 5], ++ pub users: Vec<&'static str>, + pub phys_start_addr: Address, + pub virt_start_addr: Address, + pub num_pages: usize, +@@ -26,7 +26,7 @@ + } + + struct MappingRecord { +- inner: [Option; 12], ++ inner: Vec, + } + + //-------------------------------------------------------------------------------------------------- +@@ -48,7 +48,7 @@ + attr: &AttributeFields, + ) -> Self { + Self { +- users: [Some(name), None, None, None, None], ++ users: vec![name], + phys_start_addr: phys_region.start_addr(), + virt_start_addr: virt_region.start_addr(), + num_pages: phys_region.num_pages(), +@@ -56,55 +56,28 @@ + } + } + +- fn find_next_free_user(&mut self) -> Result<&mut Option<&'static str>, &'static str> { +- if let Some(x) = self.users.iter_mut().find(|x| x.is_none()) { +- return Ok(x); +- }; +- +- Err("Storage for user info exhausted") +- } +- +- pub fn add_user(&mut self, user: &'static str) -> Result<(), &'static str> { +- let x = self.find_next_free_user()?; +- *x = Some(user); +- Ok(()) ++ pub fn add_user(&mut self, user: &'static str) { ++ self.users.push(user); + } + } + + impl MappingRecord { + pub const fn new() -> Self { +- Self { inner: [None; 12] } +- } +- +- fn size(&self) -> usize { +- self.inner.iter().filter(|x| x.is_some()).count() ++ Self { inner: Vec::new() } + } + + fn sort(&mut self) { +- let upper_bound_exclusive = self.size(); +- let entries = &mut self.inner[0..upper_bound_exclusive]; +- +- if !entries.is_sorted_by_key(|item| item.unwrap().virt_start_addr) { +- entries.sort_unstable_by_key(|item| item.unwrap().virt_start_addr) ++ if !self.inner.is_sorted_by_key(|item| item.virt_start_addr) { ++ self.inner.sort_unstable_by_key(|item| item.virt_start_addr) + } + } + +- fn find_next_free(&mut self) -> Result<&mut Option, &'static str> { +- if let Some(x) = self.inner.iter_mut().find(|x| x.is_none()) { +- return Ok(x); +- } +- +- Err("Storage for mapping info exhausted") +- } +- + fn find_duplicate( + &mut self, + phys_region: &MemoryRegion, + ) -> Option<&mut MappingRecordEntry> { + self.inner + .iter_mut() +- .filter(|x| x.is_some()) +- .map(|x| x.as_mut().unwrap()) + .filter(|x| x.attribute_fields.mem_attributes == MemAttributes::Device) + .find(|x| { + if x.phys_start_addr != phys_region.start_addr() { +@@ -125,10 +98,8 @@ + virt_region: &MemoryRegion, + phys_region: &MemoryRegion, + attr: &AttributeFields, +- ) -> Result<(), &'static str> { +- let x = self.find_next_free()?; +- +- *x = Some(MappingRecordEntry::new( ++ ) { ++ self.inner.push(MappingRecordEntry::new( + name, + virt_region, + phys_region, +@@ -136,8 +107,6 @@ + )); + + self.sort(); +- +- Ok(()) + } + + pub fn print(&self) { +@@ -148,7 +117,7 @@ + ); + info!(" -------------------------------------------------------------------------------------------------------------------------------------------"); + +- for i in self.inner.iter().flatten() { ++ for i in self.inner.iter() { + let size = i.num_pages * bsp::memory::mmu::KernelGranule::SIZE; + let virt_start = i.virt_start_addr; + let virt_end_inclusive = virt_start + (size - 1); +@@ -184,16 +153,14 @@ + attr, + acc_p, + xn, +- i.users[0].unwrap() ++ i.users[0] + ); + +- for k in i.users[1..].iter() { +- if let Some(additional_user) = *k { +- info!( ++ for k in &i.users[1..] { ++ info!( + " | {}", +- additional_user ++ k + ); +- } + } + } + +@@ -212,7 +179,7 @@ + virt_region: &MemoryRegion, + phys_region: &MemoryRegion, + attr: &AttributeFields, +-) -> Result<(), &'static str> { ++) { + KERNEL_MAPPING_RECORD.write(|mr| mr.add(name, virt_region, phys_region, attr)) + } + +@@ -225,9 +192,7 @@ + KERNEL_MAPPING_RECORD.write(|mr| { + let dup = mr.find_duplicate(&phys_region)?; + +- if let Err(x) = dup.add_user(new_user) { +- warn!("{}", x); +- } ++ dup.add_user(new_user); + + Some(dup.virt_start_addr) + }) + +diff -uNr 18_backtrace/kernel/src/memory/mmu.rs 19_kernel_heap/kernel/src/memory/mmu.rs +--- 18_backtrace/kernel/src/memory/mmu.rs ++++ 19_kernel_heap/kernel/src/memory/mmu.rs +@@ -17,7 +17,6 @@ + bsp, + memory::{Address, Physical, Virtual}, + synchronization::{self, interface::Mutex}, +- warn, + }; + use core::{fmt, num::NonZeroUsize}; + +@@ -176,9 +175,7 @@ + phys_region: &MemoryRegion, + attr: &AttributeFields, + ) { +- if let Err(x) = mapping_record::kernel_add(name, virt_region, phys_region, attr) { +- warn!("{}", x); +- } ++ mapping_record::kernel_add(name, virt_region, phys_region, attr); + } + + /// MMIO remapping in the kernel translation tables. + +diff -uNr 18_backtrace/kernel/src/memory.rs 19_kernel_heap/kernel/src/memory.rs +--- 18_backtrace/kernel/src/memory.rs ++++ 19_kernel_heap/kernel/src/memory.rs +@@ -4,6 +4,7 @@ + + //! Memory Management. + ++pub mod heap_alloc; + pub mod mmu; + + use crate::{bsp, common}; +@@ -163,6 +164,7 @@ + /// Initialize the memory subsystem. + pub fn init() { + mmu::kernel_init_mmio_va_allocator(); ++ heap_alloc::kernel_init_heap_allocator(); + } + + //-------------------------------------------------------------------------------------------------- + +diff -uNr 18_backtrace/kernel/src/print.rs 19_kernel_heap/kernel/src/print.rs +--- 18_backtrace/kernel/src/print.rs ++++ 19_kernel_heap/kernel/src/print.rs +@@ -90,3 +90,35 @@ + )); + }) + } ++ ++/// Debug print, with a newline. ++#[macro_export] ++macro_rules! debug { ++ ($string:expr) => ({ ++ if cfg!(feature = "debug_prints") { ++ use $crate::time::interface::TimeManager; ++ ++ let timestamp = $crate::time::time_manager().uptime(); ++ ++ $crate::print::_print(format_args_nl!( ++ concat!("<[>D {:>3}.{:06}> ", $string), ++ timestamp.as_secs(), ++ timestamp.subsec_micros(), ++ )); ++ } ++ }); ++ ($format_string:expr, $($arg:tt)*) => ({ ++ if cfg!(feature = "debug_prints") { ++ use $crate::time::interface::TimeManager; ++ ++ let timestamp = $crate::time::time_manager().uptime(); ++ ++ $crate::print::_print(format_args_nl!( ++ concat!("3}.{:06}> ", $format_string), ++ timestamp.as_secs(), ++ timestamp.subsec_micros(), ++ $($arg)* ++ )); ++ } ++ }) ++} + +diff -uNr 18_backtrace/Makefile 19_kernel_heap/Makefile +--- 18_backtrace/Makefile ++++ 19_kernel_heap/Makefile +@@ -15,6 +15,11 @@ + # Default to a serial device name that is common in Linux. + DEV_SERIAL ?= /dev/ttyUSB0 + ++# Optional debug prints. ++ifdef DEBUG_PRINTS ++ FEATURES = --features debug_prints ++endif ++ + # Optional integration test name. + ifdef TEST + TEST_ARG = --test $(TEST) +@@ -69,7 +74,7 @@ + ##-------------------------------------------------------------------------------------------------- + KERNEL_MANIFEST = kernel/Cargo.toml + KERNEL_LINKER_SCRIPT = kernel.ld +-LAST_BUILD_CONFIG = target/$(BSP).build_config ++LAST_BUILD_CONFIG = target/$(BSP)_$(DEBUG_PRINTS).build_config + + KERNEL_ELF_RAW = target/$(TARGET)/release/kernel + # This parses cargo's dep-info file. +@@ -116,17 +121,17 @@ + -D warnings \ + -D missing_docs + +-FEATURES = --features bsp_$(BSP) ++FEATURES += --features bsp_$(BSP) + COMPILER_ARGS = --target=$(TARGET) \ + $(FEATURES) \ + --release + + # build-std can be skipped for helper commands that do not rely on correct stack frames and other + # custom compiler options. This results in a huge speedup. +-RUSTC_CMD = cargo rustc $(COMPILER_ARGS) -Z build-std=core --manifest-path $(KERNEL_MANIFEST) ++RUSTC_CMD = cargo rustc $(COMPILER_ARGS) -Z build-std=core,alloc --manifest-path $(KERNEL_MANIFEST) + DOC_CMD = cargo doc $(COMPILER_ARGS) + CLIPPY_CMD = cargo clippy $(COMPILER_ARGS) +-TEST_CMD = cargo test $(COMPILER_ARGS) -Z build-std=core --manifest-path $(KERNEL_MANIFEST) ++TEST_CMD = cargo test $(COMPILER_ARGS) -Z build-std=core,alloc --manifest-path $(KERNEL_MANIFEST) + OBJCOPY_CMD = rust-objcopy \ + --strip-all \ + -O binary + +``` diff --git a/19_kernel_heap/kernel/Cargo.lock b/19_kernel_heap/kernel/Cargo.lock new file mode 100644 index 00000000..9149faf0 --- /dev/null +++ b/19_kernel_heap/kernel/Cargo.lock @@ -0,0 +1,96 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "cortex-a" +version = "7.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27bd91f65ccd348bb2d043d98c5b34af141ecef7f102147f59bf5898f6e734ad" +dependencies = [ + "tock-registers", +] + +[[package]] +name = "debug-symbol-types" +version = "0.1.0" + +[[package]] +name = "linked_list_allocator" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "549ce1740e46b291953c4340adcd74c59bcf4308f4cac050fd33ba91b7168f4a" + +[[package]] +name = "mingo" +version = "0.19.0" +dependencies = [ + "cortex-a", + "debug-symbol-types", + "linked_list_allocator", + "qemu-exit", + "test-macros", + "test-types", + "tock-registers", +] + +[[package]] +name = "proc-macro2" +version = "1.0.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9027b48e9d4c9175fa2218adf3557f91c1137021739951d4932f5f8268ac48aa" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "qemu-exit" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ff023245bfcc73fb890e1f8d5383825b3131cc920020a5c487d6f113dfc428a" + +[[package]] +name = "quote" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "syn" +version = "1.0.94" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a07e33e919ebcd69113d5be0e4d70c5707004ff45188910106854f38b960df4a" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "test-macros" +version = "0.1.0" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "test-types", +] + +[[package]] +name = "test-types" +version = "0.1.0" + +[[package]] +name = "tock-registers" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ee8fba06c1f4d0b396ef61a54530bb6b28f0dc61c38bc8bc5a5a48161e6282e" + +[[package]] +name = "unicode-xid" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "957e51f3646910546462e67d5f7599b9e4fb8acdd304b087a6494730f9eebf04" diff --git a/19_kernel_heap/kernel/Cargo.toml b/19_kernel_heap/kernel/Cargo.toml new file mode 100644 index 00000000..2f5d0592 --- /dev/null +++ b/19_kernel_heap/kernel/Cargo.toml @@ -0,0 +1,72 @@ +[package] +name = "mingo" +version = "0.19.0" +authors = ["Andre Richter "] +edition = "2021" + +[features] +default = [] +debug_prints = [] +bsp_rpi3 = ["tock-registers"] +bsp_rpi4 = ["tock-registers"] +test_build = ["qemu-exit"] + +##-------------------------------------------------------------------------------------------------- +## Dependencies +##-------------------------------------------------------------------------------------------------- + +[dependencies] +test-types = { path = "../libraries/test-types" } +debug-symbol-types = { path = "../libraries/debug-symbol-types" } +linked_list_allocator = { version = "0.9.x", default-features = false, features = ["const_mut_refs"] } + +# Optional dependencies +tock-registers = { version = "0.7.x", default-features = false, features = ["register_types"], optional = true } +qemu-exit = { version = "3.x.x", optional = true } + +# Platform specific dependencies +[target.'cfg(target_arch = "aarch64")'.dependencies] +cortex-a = { version = "7.x.x" } + +##-------------------------------------------------------------------------------------------------- +## Testing +##-------------------------------------------------------------------------------------------------- + +[dev-dependencies] +test-macros = { path = "../libraries/test-macros" } + +# Unit tests are done in the library part of the kernel. +[lib] +name = "libkernel" +test = true + +# Disable unit tests for the kernel binary. +[[bin]] +name = "kernel" +path = "src/main.rs" +test = false + +# List of tests without harness. +[[test]] +name = "00_console_sanity" +harness = false + +[[test]] +name = "02_exception_sync_page_fault" +harness = false + +[[test]] +name = "03_exception_restore_sanity" +harness = false + +[[test]] +name = "05_backtrace_sanity" +harness = false + +[[test]] +name = "06_backtrace_invalid_frame" +harness = false + +[[test]] +name = "07_backtrace_invalid_link" +harness = false diff --git a/19_kernel_heap/kernel/build.rs b/19_kernel_heap/kernel/build.rs new file mode 100644 index 00000000..cab00bb3 --- /dev/null +++ b/19_kernel_heap/kernel/build.rs @@ -0,0 +1,20 @@ +use std::{env, fs, process}; + +fn main() { + let ld_script_path = match env::var("LD_SCRIPT_PATH") { + Ok(var) => var, + _ => process::exit(0), + }; + + let files = fs::read_dir(ld_script_path).unwrap(); + files + .filter_map(Result::ok) + .filter(|d| { + if let Some(e) = d.path().extension() { + e == "ld" + } else { + false + } + }) + .for_each(|f| println!("cargo:rerun-if-changed={}", f.path().display())); +} diff --git a/19_kernel_heap/kernel/src/_arch/aarch64/backtrace.rs b/19_kernel_heap/kernel/src/_arch/aarch64/backtrace.rs new file mode 100644 index 00000000..e8860984 --- /dev/null +++ b/19_kernel_heap/kernel/src/_arch/aarch64/backtrace.rs @@ -0,0 +1,136 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2022 Andre Richter + +//! Architectural backtracing support. +//! +//! # Orientation +//! +//! Since arch modules are imported into generic modules using the path attribute, the path of this +//! file is: +//! +//! crate::backtrace::arch_backtrace + +use crate::{ + backtrace::BacktraceItem, + memory::{Address, Virtual}, +}; +use cortex_a::registers::*; +use tock_registers::interfaces::Readable; + +//-------------------------------------------------------------------------------------------------- +// Private Definitions +//-------------------------------------------------------------------------------------------------- + +/// A Stack frame record. +/// +/// # Note +/// +/// The convention is that `previous_record` is valid as long as it contains a non-null value. +/// Therefore, it is possible to type the member as `Option<&StackFrameRecord>` because of Rust's +/// `null-pointer optimization`. +#[repr(C)] +struct StackFrameRecord<'a> { + previous_record: Option<&'a StackFrameRecord<'a>>, + link: Address, +} + +struct StackFrameRecordIterator<'a> { + cur: &'a StackFrameRecord<'a>, +} + +//-------------------------------------------------------------------------------------------------- +// Private Code +//-------------------------------------------------------------------------------------------------- + +impl<'a> Iterator for StackFrameRecordIterator<'a> { + type Item = BacktraceItem; + + fn next(&mut self) -> Option { + static ABORT_FRAME: StackFrameRecord = StackFrameRecord { + previous_record: None, + link: Address::new(0), + }; + + // If previous is None, this is the root frame, so iteration will stop here. + let previous = self.cur.previous_record?; + + // Need to abort if the pointer to the previous frame record is invalid. + let prev_addr = Address::::new(previous as *const _ as usize); + if !prev_addr.is_valid_stack_addr() { + // This allows to return the error and then stop on the next iteration. + self.cur = &ABORT_FRAME; + return Some(BacktraceItem::InvalidFramePointer(prev_addr)); + } + + let ret = if !self.cur.link.is_valid_code_addr() { + Some(BacktraceItem::InvalidLink(self.cur.link)) + } else { + // The link points to the instruction to be executed _after_ returning from a branch. + // However, we want to show the instruction that caused the branch, so subtract by one + // instruction. + // + // This might be called from panic!, so it must not panic itself on the subtraction. + let link = if self.cur.link >= Address::new(4) { + self.cur.link - 4 + } else { + self.cur.link + }; + + Some(BacktraceItem::Link(link)) + }; + + // Advance the iterator. + self.cur = previous; + + ret + } +} + +fn stack_frame_record_iterator<'a>() -> Option> { + let fp = Address::::new(FP.get() as usize); + if !fp.is_valid_stack_addr() { + return None; + } + + Some(StackFrameRecordIterator { + cur: unsafe { &*(fp.as_usize() as *const _) }, + }) +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +/// Architectural implementation of the backtrace. +pub fn backtrace(f: impl FnOnce(Option<&mut dyn Iterator>)) { + f(stack_frame_record_iterator().as_mut().map(|s| s as _)) +} + +//-------------------------------------------------------------------------------------------------- +// Testing +//-------------------------------------------------------------------------------------------------- + +#[cfg(feature = "test_build")] +#[inline(always)] +/// Hack for corrupting the previous frame address in the current stack frame. +/// +/// # Safety +/// +/// - To be used only by testing code. +pub unsafe fn corrupt_previous_frame_addr() { + let sf = FP.get() as *mut usize; + *sf = 0x123; +} + +#[cfg(feature = "test_build")] +#[inline(always)] +/// Hack for corrupting the link in the current stack frame. +/// +/// # Safety +/// +/// - To be used only by testing code. +pub unsafe fn corrupt_link() { + let sf = FP.get() as *mut StackFrameRecord; + (*sf).link = Address::new(0x456); +} diff --git a/19_kernel_heap/kernel/src/_arch/aarch64/cpu.rs b/19_kernel_heap/kernel/src/_arch/aarch64/cpu.rs new file mode 100644 index 00000000..66da661c --- /dev/null +++ b/19_kernel_heap/kernel/src/_arch/aarch64/cpu.rs @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2018-2022 Andre Richter + +//! Architectural processor code. +//! +//! # Orientation +//! +//! Since arch modules are imported into generic modules using the path attribute, the path of this +//! file is: +//! +//! crate::cpu::arch_cpu + +use cortex_a::asm; + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +pub use asm::nop; + +/// Pause execution on the core. +#[inline(always)] +pub fn wait_forever() -> ! { + loop { + asm::wfe() + } +} + +//-------------------------------------------------------------------------------------------------- +// Testing +//-------------------------------------------------------------------------------------------------- +#[cfg(feature = "test_build")] +use qemu_exit::QEMUExit; + +#[cfg(feature = "test_build")] +const QEMU_EXIT_HANDLE: qemu_exit::AArch64 = qemu_exit::AArch64::new(); + +/// Make the host QEMU binary execute `exit(1)`. +#[cfg(feature = "test_build")] +pub fn qemu_exit_failure() -> ! { + QEMU_EXIT_HANDLE.exit_failure() +} + +/// Make the host QEMU binary execute `exit(0)`. +#[cfg(feature = "test_build")] +pub fn qemu_exit_success() -> ! { + QEMU_EXIT_HANDLE.exit_success() +} diff --git a/19_kernel_heap/kernel/src/_arch/aarch64/cpu/boot.rs b/19_kernel_heap/kernel/src/_arch/aarch64/cpu/boot.rs new file mode 100644 index 00000000..15ab92b6 --- /dev/null +++ b/19_kernel_heap/kernel/src/_arch/aarch64/cpu/boot.rs @@ -0,0 +1,117 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2021-2022 Andre Richter + +//! Architectural boot code. +//! +//! # Orientation +//! +//! Since arch modules are imported into generic modules using the path attribute, the path of this +//! file is: +//! +//! crate::cpu::boot::arch_boot + +use crate::{memory, memory::Address}; +use core::{ + arch::global_asm, + sync::atomic::{compiler_fence, Ordering}, +}; +use cortex_a::{asm, registers::*}; +use tock_registers::interfaces::Writeable; + +// Assembly counterpart to this file. +global_asm!( + include_str!("boot.s"), + CONST_CURRENTEL_EL2 = const 0x8, + CONST_CORE_ID_MASK = const 0b11 +); + +//-------------------------------------------------------------------------------------------------- +// Private Code +//-------------------------------------------------------------------------------------------------- + +/// Prepares the transition from EL2 to EL1. +/// +/// # Safety +/// +/// - The `bss` section is not initialized yet. The code must not use or reference it in any way. +/// - The HW state of EL1 must be prepared in a sound way. +#[inline(always)] +unsafe fn prepare_el2_to_el1_transition( + virt_boot_core_stack_end_exclusive_addr: u64, + virt_kernel_init_addr: u64, +) { + // Enable timer counter registers for EL1. + CNTHCTL_EL2.write(CNTHCTL_EL2::EL1PCEN::SET + CNTHCTL_EL2::EL1PCTEN::SET); + + // No offset for reading the counters. + CNTVOFF_EL2.set(0); + + // Set EL1 execution state to AArch64. + HCR_EL2.write(HCR_EL2::RW::EL1IsAarch64); + + // Set up a simulated exception return. + // + // First, fake a saved program status where all interrupts were masked and SP_EL1 was used as a + // stack pointer. + SPSR_EL2.write( + SPSR_EL2::D::Masked + + SPSR_EL2::A::Masked + + SPSR_EL2::I::Masked + + SPSR_EL2::F::Masked + + SPSR_EL2::M::EL1h, + ); + + // Second, let the link register point to kernel_init(). + ELR_EL2.set(virt_kernel_init_addr); + + // Set up SP_EL1 (stack pointer), which will be used by EL1 once we "return" to it. Since there + // are no plans to ever return to EL2, just re-use the same stack. + SP_EL1.set(virt_boot_core_stack_end_exclusive_addr); +} + +/// Reset the backtrace by setting link register and frame pointer to zero. +/// +/// # Safety +/// +/// - This function must only be used immediately before entering EL1. +#[inline(always)] +unsafe fn prepare_backtrace_reset() { + compiler_fence(Ordering::SeqCst); + FP.set(0); + LR.set(0); +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +/// The Rust entry of the `kernel` binary. +/// +/// The function is called from the assembly `_start` function. +/// +/// # Safety +/// +/// - Exception return from EL2 must must continue execution in EL1 with `kernel_init()`. +#[no_mangle] +pub unsafe extern "C" fn _start_rust( + phys_kernel_tables_base_addr: u64, + virt_boot_core_stack_end_exclusive_addr: u64, + virt_kernel_init_addr: u64, +) -> ! { + prepare_el2_to_el1_transition( + virt_boot_core_stack_end_exclusive_addr, + virt_kernel_init_addr, + ); + + // Turn on the MMU for EL1. + let addr = Address::new(phys_kernel_tables_base_addr as usize); + memory::mmu::enable_mmu_and_caching(addr).unwrap(); + + // Make the function we return to the root of a backtrace. + prepare_backtrace_reset(); + + // Use `eret` to "return" to EL1. Since virtual memory will already be enabled, this results in + // execution of kernel_init() in EL1 from its _virtual address_. + asm::eret() +} diff --git a/19_kernel_heap/kernel/src/_arch/aarch64/cpu/boot.s b/19_kernel_heap/kernel/src/_arch/aarch64/cpu/boot.s new file mode 100644 index 00000000..8c70d035 --- /dev/null +++ b/19_kernel_heap/kernel/src/_arch/aarch64/cpu/boot.s @@ -0,0 +1,97 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2021-2022 Andre Richter + +//-------------------------------------------------------------------------------------------------- +// Definitions +//-------------------------------------------------------------------------------------------------- + +// Load the address of a symbol into a register, PC-relative. +// +// The symbol must lie within +/- 4 GiB of the Program Counter. +// +// # Resources +// +// - https://sourceware.org/binutils/docs-2.36/as/AArch64_002dRelocations.html +.macro ADR_REL register, symbol + adrp \register, \symbol + add \register, \register, #:lo12:\symbol +.endm + +// Load the address of a symbol into a register, absolute. +// +// # Resources +// +// - https://sourceware.org/binutils/docs-2.36/as/AArch64_002dRelocations.html +.macro ADR_ABS register, symbol + movz \register, #:abs_g3:\symbol + movk \register, #:abs_g2_nc:\symbol + movk \register, #:abs_g1_nc:\symbol + movk \register, #:abs_g0_nc:\symbol +.endm + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- +.section .text._start + +//------------------------------------------------------------------------------ +// fn _start() +//------------------------------------------------------------------------------ +_start: + // Only proceed if the core executes in EL2. Park it otherwise. + mrs x0, CurrentEL + cmp x0, {CONST_CURRENTEL_EL2} + b.ne .L_parking_loop + + // Only proceed on the boot core. Park it otherwise. + mrs x1, MPIDR_EL1 + and x1, x1, {CONST_CORE_ID_MASK} + ldr x2, BOOT_CORE_ID // provided by bsp/__board_name__/cpu.rs + cmp x1, x2 + b.ne .L_parking_loop + + // If execution reaches here, it is the boot core. + + // Initialize DRAM. + ADR_REL x0, __bss_start + ADR_REL x1, __bss_end_exclusive + +.L_bss_init_loop: + cmp x0, x1 + b.eq .L_prepare_rust + stp xzr, xzr, [x0], #16 + b .L_bss_init_loop + + // Prepare the jump to Rust code. +.L_prepare_rust: + // Load the base address of the kernel's translation tables. + ldr x0, PHYS_KERNEL_TABLES_BASE_ADDR // provided by bsp/__board_name__/memory/mmu.rs + + // Load the _absolute_ addresses of the following symbols. Since the kernel is linked at + // the top of the 64 bit address space, these are effectively virtual addresses. + ADR_ABS x1, __boot_core_stack_end_exclusive + ADR_ABS x2, kernel_init + + // Load the PC-relative address of the stack and set the stack pointer. + // + // Since _start() is the first function that runs after the firmware has loaded the kernel + // into memory, retrieving this symbol PC-relative returns the "physical" address. + // + // Setting the stack pointer to this value ensures that anything that still runs in EL2, + // until the kernel returns to EL1 with the MMU enabled, works as well. After the return to + // EL1, the virtual address of the stack retrieved above will be used. + ADR_REL x4, __boot_core_stack_end_exclusive + mov sp, x4 + + // Jump to Rust code. x0, x1 and x2 hold the function arguments provided to _start_rust(). + b _start_rust + + // Infinitely wait for events (aka "park the core"). +.L_parking_loop: + wfe + b .L_parking_loop + +.size _start, . - _start +.type _start, function +.global _start diff --git a/19_kernel_heap/kernel/src/_arch/aarch64/cpu/smp.rs b/19_kernel_heap/kernel/src/_arch/aarch64/cpu/smp.rs new file mode 100644 index 00000000..351fde62 --- /dev/null +++ b/19_kernel_heap/kernel/src/_arch/aarch64/cpu/smp.rs @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2018-2022 Andre Richter + +//! Architectural symmetric multiprocessing. +//! +//! # Orientation +//! +//! Since arch modules are imported into generic modules using the path attribute, the path of this +//! file is: +//! +//! crate::cpu::smp::arch_smp + +use cortex_a::registers::*; +use tock_registers::interfaces::Readable; + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +/// Return the executing core's id. +#[inline(always)] +pub fn core_id() -> T +where + T: From, +{ + const CORE_MASK: u64 = 0b11; + + T::from((MPIDR_EL1.get() & CORE_MASK) as u8) +} diff --git a/19_kernel_heap/kernel/src/_arch/aarch64/exception.rs b/19_kernel_heap/kernel/src/_arch/aarch64/exception.rs new file mode 100644 index 00000000..17ec3009 --- /dev/null +++ b/19_kernel_heap/kernel/src/_arch/aarch64/exception.rs @@ -0,0 +1,325 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2018-2022 Andre Richter + +//! Architectural synchronous and asynchronous exception handling. +//! +//! # Orientation +//! +//! Since arch modules are imported into generic modules using the path attribute, the path of this +//! file is: +//! +//! crate::exception::arch_exception + +use crate::{exception, memory, symbols}; +use core::{arch::global_asm, cell::UnsafeCell, fmt}; +use cortex_a::{asm::barrier, registers::*}; +use tock_registers::{ + interfaces::{Readable, Writeable}, + registers::InMemoryRegister, +}; + +// Assembly counterpart to this file. +global_asm!( + include_str!("exception.s"), + CONST_ESR_EL1_EC_SHIFT = const 26, + CONST_ESR_EL1_EC_VALUE_SVC64 = const 0x15 +); + +//-------------------------------------------------------------------------------------------------- +// Private Definitions +//-------------------------------------------------------------------------------------------------- + +/// Wrapper structs for memory copies of registers. +#[repr(transparent)] +struct SpsrEL1(InMemoryRegister); +struct EsrEL1(InMemoryRegister); + +/// The exception context as it is stored on the stack on exception entry. +#[repr(C)] +struct ExceptionContext { + /// General Purpose Registers. + gpr: [u64; 30], + + /// The link register, aka x30. + lr: u64, + + /// Exception link register. The program counter at the time the exception happened. + elr_el1: u64, + + /// Saved program status. + spsr_el1: SpsrEL1, + + /// Exception syndrome register. + esr_el1: EsrEL1, +} + +//-------------------------------------------------------------------------------------------------- +// Private Code +//-------------------------------------------------------------------------------------------------- + +/// Prints verbose information about the exception and then panics. +fn default_exception_handler(exc: &ExceptionContext) { + panic!( + "CPU Exception!\n\n\ + {}", + exc + ); +} + +//------------------------------------------------------------------------------ +// Current, EL0 +//------------------------------------------------------------------------------ + +#[no_mangle] +unsafe extern "C" fn current_el0_synchronous(_e: &mut ExceptionContext) { + panic!("Should not be here. Use of SP_EL0 in EL1 is not supported.") +} + +#[no_mangle] +unsafe extern "C" fn current_el0_irq(_e: &mut ExceptionContext) { + panic!("Should not be here. Use of SP_EL0 in EL1 is not supported.") +} + +#[no_mangle] +unsafe extern "C" fn current_el0_serror(_e: &mut ExceptionContext) { + panic!("Should not be here. Use of SP_EL0 in EL1 is not supported.") +} + +//------------------------------------------------------------------------------ +// Current, ELx +//------------------------------------------------------------------------------ + +#[no_mangle] +unsafe extern "C" fn current_elx_synchronous(e: &mut ExceptionContext) { + #[cfg(feature = "test_build")] + { + const TEST_SVC_ID: u64 = 0x1337; + + if let Some(ESR_EL1::EC::Value::SVC64) = e.esr_el1.exception_class() { + if e.esr_el1.iss() == TEST_SVC_ID { + return; + } + } + } + + default_exception_handler(e); +} + +#[no_mangle] +unsafe extern "C" fn current_elx_irq(_e: &mut ExceptionContext) { + let token = &exception::asynchronous::IRQContext::new(); + exception::asynchronous::irq_manager().handle_pending_irqs(token); +} + +#[no_mangle] +unsafe extern "C" fn current_elx_serror(e: &mut ExceptionContext) { + default_exception_handler(e); +} + +//------------------------------------------------------------------------------ +// Lower, AArch64 +//------------------------------------------------------------------------------ + +#[no_mangle] +unsafe extern "C" fn lower_aarch64_synchronous(e: &mut ExceptionContext) { + default_exception_handler(e); +} + +#[no_mangle] +unsafe extern "C" fn lower_aarch64_irq(e: &mut ExceptionContext) { + default_exception_handler(e); +} + +#[no_mangle] +unsafe extern "C" fn lower_aarch64_serror(e: &mut ExceptionContext) { + default_exception_handler(e); +} + +//------------------------------------------------------------------------------ +// Lower, AArch32 +//------------------------------------------------------------------------------ + +#[no_mangle] +unsafe extern "C" fn lower_aarch32_synchronous(e: &mut ExceptionContext) { + default_exception_handler(e); +} + +#[no_mangle] +unsafe extern "C" fn lower_aarch32_irq(e: &mut ExceptionContext) { + default_exception_handler(e); +} + +#[no_mangle] +unsafe extern "C" fn lower_aarch32_serror(e: &mut ExceptionContext) { + default_exception_handler(e); +} + +//------------------------------------------------------------------------------ +// Misc +//------------------------------------------------------------------------------ + +/// Human readable SPSR_EL1. +#[rustfmt::skip] +impl fmt::Display for SpsrEL1 { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + // Raw value. + writeln!(f, "SPSR_EL1: {:#010x}", self.0.get())?; + + let to_flag_str = |x| -> _ { + if x { "Set" } else { "Not set" } + }; + + writeln!(f, " Flags:")?; + writeln!(f, " Negative (N): {}", to_flag_str(self.0.is_set(SPSR_EL1::N)))?; + writeln!(f, " Zero (Z): {}", to_flag_str(self.0.is_set(SPSR_EL1::Z)))?; + writeln!(f, " Carry (C): {}", to_flag_str(self.0.is_set(SPSR_EL1::C)))?; + writeln!(f, " Overflow (V): {}", to_flag_str(self.0.is_set(SPSR_EL1::V)))?; + + let to_mask_str = |x| -> _ { + if x { "Masked" } else { "Unmasked" } + }; + + writeln!(f, " Exception handling state:")?; + writeln!(f, " Debug (D): {}", to_mask_str(self.0.is_set(SPSR_EL1::D)))?; + writeln!(f, " SError (A): {}", to_mask_str(self.0.is_set(SPSR_EL1::A)))?; + writeln!(f, " IRQ (I): {}", to_mask_str(self.0.is_set(SPSR_EL1::I)))?; + writeln!(f, " FIQ (F): {}", to_mask_str(self.0.is_set(SPSR_EL1::F)))?; + + write!(f, " Illegal Execution State (IL): {}", + to_flag_str(self.0.is_set(SPSR_EL1::IL)) + ) + } +} + +impl EsrEL1 { + #[inline(always)] + fn exception_class(&self) -> Option { + self.0.read_as_enum(ESR_EL1::EC) + } + + #[cfg(feature = "test_build")] + #[inline(always)] + fn iss(&self) -> u64 { + self.0.read(ESR_EL1::ISS) + } +} + +/// Human readable ESR_EL1. +#[rustfmt::skip] +impl fmt::Display for EsrEL1 { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + // Raw print of whole register. + writeln!(f, "ESR_EL1: {:#010x}", self.0.get())?; + + // Raw print of exception class. + write!(f, " Exception Class (EC) : {:#x}", self.0.read(ESR_EL1::EC))?; + + // Exception class. + let ec_translation = match self.exception_class() { + Some(ESR_EL1::EC::Value::DataAbortCurrentEL) => "Data Abort, current EL", + _ => "N/A", + }; + writeln!(f, " - {}", ec_translation)?; + + // Raw print of instruction specific syndrome. + write!(f, " Instr Specific Syndrome (ISS): {:#x}", self.0.read(ESR_EL1::ISS)) + } +} + +impl ExceptionContext { + #[inline(always)] + fn exception_class(&self) -> Option { + self.esr_el1.exception_class() + } + + #[inline(always)] + fn fault_address_valid(&self) -> bool { + use ESR_EL1::EC::Value::*; + + match self.exception_class() { + None => false, + Some(ec) => matches!( + ec, + InstrAbortLowerEL + | InstrAbortCurrentEL + | PCAlignmentFault + | DataAbortLowerEL + | DataAbortCurrentEL + | WatchpointLowerEL + | WatchpointCurrentEL + ), + } + } +} + +/// Human readable print of the exception context. +impl fmt::Display for ExceptionContext { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + writeln!(f, "{}", self.esr_el1)?; + + if self.fault_address_valid() { + writeln!(f, "FAR_EL1: {:#018x}", FAR_EL1.get() as usize)?; + } + + writeln!(f, "{}", self.spsr_el1)?; + writeln!(f, "ELR_EL1: {:#018x}", self.elr_el1)?; + writeln!( + f, + " Symbol: {}", + match symbols::lookup_symbol(memory::Address::new(self.elr_el1 as usize)) { + Some(sym) => sym.name(), + _ => "Symbol not found", + } + )?; + writeln!(f)?; + writeln!(f, "General purpose register:")?; + + #[rustfmt::skip] + let alternating = |x| -> _ { + if x % 2 == 0 { " " } else { "\n" } + }; + + // Print two registers per line. + for (i, reg) in self.gpr.iter().enumerate() { + write!(f, " x{: <2}: {: >#018x}{}", i, reg, alternating(i))?; + } + write!(f, " lr : {:#018x}", self.lr) + } +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- +use crate::exception::PrivilegeLevel; + +/// The processing element's current privilege level. +pub fn current_privilege_level() -> (PrivilegeLevel, &'static str) { + let el = CurrentEL.read_as_enum(CurrentEL::EL); + match el { + Some(CurrentEL::EL::Value::EL2) => (PrivilegeLevel::Hypervisor, "EL2"), + Some(CurrentEL::EL::Value::EL1) => (PrivilegeLevel::Kernel, "EL1"), + Some(CurrentEL::EL::Value::EL0) => (PrivilegeLevel::User, "EL0"), + _ => (PrivilegeLevel::Unknown, "Unknown"), + } +} + +/// Init exception handling by setting the exception vector base address register. +/// +/// # Safety +/// +/// - Changes the HW state of the executing core. +/// - The vector table and the symbol `__exception_vector_table_start` from the linker script must +/// adhere to the alignment and size constraints demanded by the ARMv8-A Architecture Reference +/// Manual. +pub unsafe fn handling_init() { + // Provided by exception.S. + extern "Rust" { + static __exception_vector_start: UnsafeCell<()>; + } + + VBAR_EL1.set(__exception_vector_start.get() as u64); + + // Force VBAR update to complete before next instruction. + barrier::isb(barrier::SY); +} diff --git a/19_kernel_heap/kernel/src/_arch/aarch64/exception.s b/19_kernel_heap/kernel/src/_arch/aarch64/exception.s new file mode 100644 index 00000000..cdef8c58 --- /dev/null +++ b/19_kernel_heap/kernel/src/_arch/aarch64/exception.s @@ -0,0 +1,190 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2018-2022 Andre Richter + +//-------------------------------------------------------------------------------------------------- +// Definitions +//-------------------------------------------------------------------------------------------------- + +/// Call the function provided by parameter `\handler` after saving the exception context. Provide +/// the context as the first parameter to '\handler'. +.macro CALL_WITH_CONTEXT handler is_lower_el is_sync +__vector_\handler: + // Make room on the stack for the exception context. + sub sp, sp, #16 * 18 + + // Store all general purpose registers on the stack. + stp x0, x1, [sp, #16 * 0] + stp x2, x3, [sp, #16 * 1] + stp x4, x5, [sp, #16 * 2] + stp x6, x7, [sp, #16 * 3] + stp x8, x9, [sp, #16 * 4] + stp x10, x11, [sp, #16 * 5] + stp x12, x13, [sp, #16 * 6] + stp x14, x15, [sp, #16 * 7] + stp x16, x17, [sp, #16 * 8] + stp x18, x19, [sp, #16 * 9] + stp x20, x21, [sp, #16 * 10] + stp x22, x23, [sp, #16 * 11] + stp x24, x25, [sp, #16 * 12] + stp x26, x27, [sp, #16 * 13] + stp x28, x29, [sp, #16 * 14] + + // Add the exception link register (ELR_EL1), saved program status (SPSR_EL1) and exception + // syndrome register (ESR_EL1). + mrs x1, ELR_EL1 + mrs x2, SPSR_EL1 + mrs x3, ESR_EL1 + + stp lr, x1, [sp, #16 * 15] + stp x2, x3, [sp, #16 * 16] + + // Build a stack frame for backtracing. +.if \is_lower_el == 1 + // If we came from a lower EL, make it a root frame (by storing zero) so that the kernel + // does not attempt to trace into userspace. + stp xzr, xzr, [sp, #16 * 17] +.else + // For normal branches, the link address points to the instruction to be executed _after_ + // returning from a branch. In a backtrace, we want to show the instruction that caused the + // branch, though. That is why code in backtrace.rs subtracts 4 (length of one instruction) + // from the link address. + // + // Here we have a special case, though, because ELR_EL1 is used instead of LR to build the + // stack frame, so that it becomes possible to trace beyond an exception. Hence, it must be + // considered that semantics for ELR_EL1 differ from case to case. + // + // Unless an "exception generating instruction" was executed, ELR_EL1 already points to the + // the correct instruction, and hence the subtraction by 4 in backtrace.rs would yield wrong + // results. To cover for this, 4 is added to ELR_EL1 below unless the cause of exception was + // an SVC instruction. BRK and HLT are "exception generating instructions" as well, but they + // are not expected and therefore left out for now. + // + // For reference: Search for "preferred exception return address" in the Architecture + // Reference Manual for ARMv8-A. +.if \is_sync == 1 + lsr w3, w3, {CONST_ESR_EL1_EC_SHIFT} // w3 = ESR_EL1.EC + cmp w3, {CONST_ESR_EL1_EC_VALUE_SVC64} // w3 == SVC64 ? + b.eq 1f +.endif + add x1, x1, #4 +1: + stp x29, x1, [sp, #16 * 17] +.endif + + // Set the frame pointer to the stack frame record. + add x29, sp, #16 * 17 + + // x0 is the first argument for the function called through `\handler`. + mov x0, sp + + // Call `\handler`. + bl \handler + + // After returning from exception handling code, replay the saved context and return via + // `eret`. + b __exception_restore_context + +.size __vector_\handler, . - __vector_\handler +.type __vector_\handler, function +.endm + +.macro FIQ_SUSPEND +1: wfe + b 1b +.endm + +//-------------------------------------------------------------------------------------------------- +// Private Code +//-------------------------------------------------------------------------------------------------- +.section .text + +//------------------------------------------------------------------------------ +// The exception vector table. +//------------------------------------------------------------------------------ + +// Align by 2^11 bytes, as demanded by ARMv8-A. Same as ALIGN(2048) in an ld script. +.align 11 + +// Export a symbol for the Rust code to use. +__exception_vector_start: + +// Current exception level with SP_EL0. +// +// .org sets the offset relative to section start. +// +// # Safety +// +// - It must be ensured that `CALL_WITH_CONTEXT` <= 0x80 bytes. +.org 0x000 + CALL_WITH_CONTEXT current_el0_synchronous, 0, 1 +.org 0x080 + CALL_WITH_CONTEXT current_el0_irq, 0, 0 +.org 0x100 + FIQ_SUSPEND +.org 0x180 + CALL_WITH_CONTEXT current_el0_serror, 0, 0 + +// Current exception level with SP_ELx, x > 0. +.org 0x200 + CALL_WITH_CONTEXT current_elx_synchronous, 0, 1 +.org 0x280 + CALL_WITH_CONTEXT current_elx_irq, 0, 0 +.org 0x300 + FIQ_SUSPEND +.org 0x380 + CALL_WITH_CONTEXT current_elx_serror, 0, 0 + +// Lower exception level, AArch64 +.org 0x400 + CALL_WITH_CONTEXT lower_aarch64_synchronous, 1, 1 +.org 0x480 + CALL_WITH_CONTEXT lower_aarch64_irq, 1, 0 +.org 0x500 + FIQ_SUSPEND +.org 0x580 + CALL_WITH_CONTEXT lower_aarch64_serror, 1, 0 + +// Lower exception level, AArch32 +.org 0x600 + CALL_WITH_CONTEXT lower_aarch32_synchronous, 1, 0 +.org 0x680 + CALL_WITH_CONTEXT lower_aarch32_irq, 1, 0 +.org 0x700 + FIQ_SUSPEND +.org 0x780 + CALL_WITH_CONTEXT lower_aarch32_serror, 1, 0 +.org 0x800 + +//------------------------------------------------------------------------------ +// fn __exception_restore_context() +//------------------------------------------------------------------------------ +__exception_restore_context: + ldr w19, [sp, #16 * 16] + ldp lr, x20, [sp, #16 * 15] + + msr SPSR_EL1, x19 + msr ELR_EL1, x20 + + ldp x0, x1, [sp, #16 * 0] + ldp x2, x3, [sp, #16 * 1] + ldp x4, x5, [sp, #16 * 2] + ldp x6, x7, [sp, #16 * 3] + ldp x8, x9, [sp, #16 * 4] + ldp x10, x11, [sp, #16 * 5] + ldp x12, x13, [sp, #16 * 6] + ldp x14, x15, [sp, #16 * 7] + ldp x16, x17, [sp, #16 * 8] + ldp x18, x19, [sp, #16 * 9] + ldp x20, x21, [sp, #16 * 10] + ldp x22, x23, [sp, #16 * 11] + ldp x24, x25, [sp, #16 * 12] + ldp x26, x27, [sp, #16 * 13] + ldp x28, x29, [sp, #16 * 14] + + add sp, sp, #16 * 18 + + eret + +.size __exception_restore_context, . - __exception_restore_context +.type __exception_restore_context, function diff --git a/19_kernel_heap/kernel/src/_arch/aarch64/exception/asynchronous.rs b/19_kernel_heap/kernel/src/_arch/aarch64/exception/asynchronous.rs new file mode 100644 index 00000000..73b82e65 --- /dev/null +++ b/19_kernel_heap/kernel/src/_arch/aarch64/exception/asynchronous.rs @@ -0,0 +1,152 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2018-2022 Andre Richter + +//! Architectural asynchronous exception handling. +//! +//! # Orientation +//! +//! Since arch modules are imported into generic modules using the path attribute, the path of this +//! file is: +//! +//! crate::exception::asynchronous::arch_asynchronous + +use core::arch::asm; +use cortex_a::registers::*; +use tock_registers::interfaces::{Readable, Writeable}; + +//-------------------------------------------------------------------------------------------------- +// Private Definitions +//-------------------------------------------------------------------------------------------------- + +mod daif_bits { + pub const IRQ: u8 = 0b0010; +} + +trait DaifField { + fn daif_field() -> tock_registers::fields::Field; +} + +struct Debug; +struct SError; +struct IRQ; +struct FIQ; + +//-------------------------------------------------------------------------------------------------- +// Private Code +//-------------------------------------------------------------------------------------------------- + +impl DaifField for Debug { + fn daif_field() -> tock_registers::fields::Field { + DAIF::D + } +} + +impl DaifField for SError { + fn daif_field() -> tock_registers::fields::Field { + DAIF::A + } +} + +impl DaifField for IRQ { + fn daif_field() -> tock_registers::fields::Field { + DAIF::I + } +} + +impl DaifField for FIQ { + fn daif_field() -> tock_registers::fields::Field { + DAIF::F + } +} + +fn is_masked() -> bool +where + T: DaifField, +{ + DAIF.is_set(T::daif_field()) +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +/// Returns whether IRQs are masked on the executing core. +pub fn is_local_irq_masked() -> bool { + !is_masked::() +} + +/// Unmask IRQs on the executing core. +/// +/// It is not needed to place an explicit instruction synchronization barrier after the `msr`. +/// Quoting the Architecture Reference Manual for ARMv8-A, section C5.1.3: +/// +/// "Writes to PSTATE.{PAN, D, A, I, F} occur in program order without the need for additional +/// synchronization." +/// +/// # Safety +/// +/// - Changes the HW state of the executing core. +#[inline(always)] +pub unsafe fn local_irq_unmask() { + #[rustfmt::skip] + asm!( + "msr DAIFClr, {arg}", + arg = const daif_bits::IRQ, + options(nomem, nostack, preserves_flags) + ); +} + +/// Mask IRQs on the executing core. +/// +/// # Safety +/// +/// - Changes the HW state of the executing core. +#[inline(always)] +pub unsafe fn local_irq_mask() { + #[rustfmt::skip] + asm!( + "msr DAIFSet, {arg}", + arg = const daif_bits::IRQ, + options(nomem, nostack, preserves_flags) + ); +} + +/// Mask IRQs on the executing core and return the previously saved interrupt mask bits (DAIF). +/// +/// # Safety +/// +/// - Changes the HW state of the executing core. +#[inline(always)] +pub unsafe fn local_irq_mask_save() -> u64 { + let saved = DAIF.get(); + local_irq_mask(); + + saved +} + +/// Restore the interrupt mask bits (DAIF) using the callee's argument. +/// +/// # Safety +/// +/// - Changes the HW state of the executing core. +/// - No sanity checks on the input. +#[inline(always)] +pub unsafe fn local_irq_restore(saved: u64) { + DAIF.set(saved); +} + +/// Print the AArch64 exceptions status. +#[rustfmt::skip] +pub fn print_state() { + use crate::info; + + let to_mask_str = |x| -> _ { + if x { "Masked" } else { "Unmasked" } + }; + + info!(" Debug: {}", to_mask_str(is_masked::())); + info!(" SError: {}", to_mask_str(is_masked::())); + info!(" IRQ: {}", to_mask_str(is_masked::())); + info!(" FIQ: {}", to_mask_str(is_masked::())); +} diff --git a/19_kernel_heap/kernel/src/_arch/aarch64/memory/mmu.rs b/19_kernel_heap/kernel/src/_arch/aarch64/memory/mmu.rs new file mode 100644 index 00000000..3d6c18b7 --- /dev/null +++ b/19_kernel_heap/kernel/src/_arch/aarch64/memory/mmu.rs @@ -0,0 +1,158 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2018-2022 Andre Richter + +//! Memory Management Unit Driver. +//! +//! Only 64 KiB granule is supported. +//! +//! # Orientation +//! +//! Since arch modules are imported into generic modules using the path attribute, the path of this +//! file is: +//! +//! crate::memory::mmu::arch_mmu + +use crate::{ + bsp, memory, + memory::{mmu::TranslationGranule, Address, Physical}, +}; +use core::intrinsics::unlikely; +use cortex_a::{asm::barrier, registers::*}; +use tock_registers::interfaces::{ReadWriteable, Readable, Writeable}; + +//-------------------------------------------------------------------------------------------------- +// Private Definitions +//-------------------------------------------------------------------------------------------------- + +/// Memory Management Unit type. +struct MemoryManagementUnit; + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +pub type Granule512MiB = TranslationGranule<{ 512 * 1024 * 1024 }>; +pub type Granule64KiB = TranslationGranule<{ 64 * 1024 }>; + +/// Constants for indexing the MAIR_EL1. +#[allow(dead_code)] +pub mod mair { + pub const DEVICE: u64 = 0; + pub const NORMAL: u64 = 1; +} + +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +static MMU: MemoryManagementUnit = MemoryManagementUnit; + +//-------------------------------------------------------------------------------------------------- +// Private Code +//-------------------------------------------------------------------------------------------------- + +impl memory::mmu::AddressSpace { + /// Checks for architectural restrictions. + pub const fn arch_address_space_size_sanity_checks() { + // Size must be at least one full 512 MiB table. + assert!((AS_SIZE % Granule512MiB::SIZE) == 0); + + // Check for 48 bit virtual address size as maximum, which is supported by any ARMv8 + // version. + assert!(AS_SIZE <= (1 << 48)); + } +} + +impl MemoryManagementUnit { + /// Setup function for the MAIR_EL1 register. + #[inline(always)] + fn set_up_mair(&self) { + // Define the memory types being mapped. + MAIR_EL1.write( + // Attribute 1 - Cacheable normal DRAM. + MAIR_EL1::Attr1_Normal_Outer::WriteBack_NonTransient_ReadWriteAlloc + + MAIR_EL1::Attr1_Normal_Inner::WriteBack_NonTransient_ReadWriteAlloc + + + // Attribute 0 - Device. + MAIR_EL1::Attr0_Device::nonGathering_nonReordering_EarlyWriteAck, + ); + } + + /// Configure various settings of stage 1 of the EL1 translation regime. + #[inline(always)] + fn configure_translation_control(&self) { + let t1sz = (64 - bsp::memory::mmu::KernelVirtAddrSpace::SIZE_SHIFT) as u64; + + TCR_EL1.write( + TCR_EL1::TBI1::Used + + TCR_EL1::IPS::Bits_40 + + TCR_EL1::TG1::KiB_64 + + TCR_EL1::SH1::Inner + + TCR_EL1::ORGN1::WriteBack_ReadAlloc_WriteAlloc_Cacheable + + TCR_EL1::IRGN1::WriteBack_ReadAlloc_WriteAlloc_Cacheable + + TCR_EL1::EPD1::EnableTTBR1Walks + + TCR_EL1::A1::TTBR1 + + TCR_EL1::T1SZ.val(t1sz) + + TCR_EL1::EPD0::DisableTTBR0Walks, + ); + } +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +/// Return a reference to the MMU instance. +pub fn mmu() -> &'static impl memory::mmu::interface::MMU { + &MMU +} + +//------------------------------------------------------------------------------ +// OS Interface Code +//------------------------------------------------------------------------------ +use memory::mmu::MMUEnableError; + +impl memory::mmu::interface::MMU for MemoryManagementUnit { + unsafe fn enable_mmu_and_caching( + &self, + phys_tables_base_addr: Address, + ) -> Result<(), MMUEnableError> { + if unlikely(self.is_enabled()) { + return Err(MMUEnableError::AlreadyEnabled); + } + + // Fail early if translation granule is not supported. + if unlikely(!ID_AA64MMFR0_EL1.matches_all(ID_AA64MMFR0_EL1::TGran64::Supported)) { + return Err(MMUEnableError::Other( + "Translation granule not supported in HW", + )); + } + + // Prepare the memory attribute indirection register. + self.set_up_mair(); + + // Set the "Translation Table Base Register". + TTBR1_EL1.set_baddr(phys_tables_base_addr.as_usize() as u64); + + self.configure_translation_control(); + + // Switch the MMU on. + // + // First, force all previous changes to be seen before the MMU is enabled. + barrier::isb(barrier::SY); + + // Enable the MMU and turn on data and instruction caching. + SCTLR_EL1.modify(SCTLR_EL1::M::Enable + SCTLR_EL1::C::Cacheable + SCTLR_EL1::I::Cacheable); + + // Force MMU init to complete before next instruction. + barrier::isb(barrier::SY); + + Ok(()) + } + + #[inline(always)] + fn is_enabled(&self) -> bool { + SCTLR_EL1.matches_all(SCTLR_EL1::M::Enable) + } +} diff --git a/19_kernel_heap/kernel/src/_arch/aarch64/memory/mmu/translation_table.rs b/19_kernel_heap/kernel/src/_arch/aarch64/memory/mmu/translation_table.rs new file mode 100644 index 00000000..f0b4ac85 --- /dev/null +++ b/19_kernel_heap/kernel/src/_arch/aarch64/memory/mmu/translation_table.rs @@ -0,0 +1,521 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2021-2022 Andre Richter + +//! Architectural translation table. +//! +//! Only 64 KiB granule is supported. +//! +//! # Orientation +//! +//! Since arch modules are imported into generic modules using the path attribute, the path of this +//! file is: +//! +//! crate::memory::mmu::translation_table::arch_translation_table + +use crate::{ + bsp, + memory::{ + self, + mmu::{ + arch_mmu::{Granule512MiB, Granule64KiB}, + AccessPermissions, AttributeFields, MemAttributes, MemoryRegion, PageAddress, + }, + Address, Physical, Virtual, + }, +}; +use core::convert; +use tock_registers::{ + interfaces::{Readable, Writeable}, + register_bitfields, + registers::InMemoryRegister, +}; + +//-------------------------------------------------------------------------------------------------- +// Private Definitions +//-------------------------------------------------------------------------------------------------- + +// A table descriptor, as per ARMv8-A Architecture Reference Manual Figure D5-15. +register_bitfields! {u64, + STAGE1_TABLE_DESCRIPTOR [ + /// Physical address of the next descriptor. + NEXT_LEVEL_TABLE_ADDR_64KiB OFFSET(16) NUMBITS(32) [], // [47:16] + + TYPE OFFSET(1) NUMBITS(1) [ + Block = 0, + Table = 1 + ], + + VALID OFFSET(0) NUMBITS(1) [ + False = 0, + True = 1 + ] + ] +} + +// A level 3 page descriptor, as per ARMv8-A Architecture Reference Manual Figure D5-17. +register_bitfields! {u64, + STAGE1_PAGE_DESCRIPTOR [ + /// Unprivileged execute-never. + UXN OFFSET(54) NUMBITS(1) [ + False = 0, + True = 1 + ], + + /// Privileged execute-never. + PXN OFFSET(53) NUMBITS(1) [ + False = 0, + True = 1 + ], + + /// Physical address of the next table descriptor (lvl2) or the page descriptor (lvl3). + OUTPUT_ADDR_64KiB OFFSET(16) NUMBITS(32) [], // [47:16] + + /// Access flag. + AF OFFSET(10) NUMBITS(1) [ + False = 0, + True = 1 + ], + + /// Shareability field. + SH OFFSET(8) NUMBITS(2) [ + OuterShareable = 0b10, + InnerShareable = 0b11 + ], + + /// Access Permissions. + AP OFFSET(6) NUMBITS(2) [ + RW_EL1 = 0b00, + RW_EL1_EL0 = 0b01, + RO_EL1 = 0b10, + RO_EL1_EL0 = 0b11 + ], + + /// Memory attributes index into the MAIR_EL1 register. + AttrIndx OFFSET(2) NUMBITS(3) [], + + TYPE OFFSET(1) NUMBITS(1) [ + Reserved_Invalid = 0, + Page = 1 + ], + + VALID OFFSET(0) NUMBITS(1) [ + False = 0, + True = 1 + ] + ] +} + +/// A table descriptor for 64 KiB aperture. +/// +/// The output points to the next table. +#[derive(Copy, Clone)] +#[repr(C)] +struct TableDescriptor { + value: u64, +} + +/// A page descriptor with 64 KiB aperture. +/// +/// The output points to physical memory. +#[derive(Copy, Clone)] +#[repr(C)] +struct PageDescriptor { + value: u64, +} + +trait StartAddr { + fn virt_start_addr(&self) -> Address; +} + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +/// Big monolithic struct for storing the translation tables. Individual levels must be 64 KiB +/// aligned, so the lvl3 is put first. +#[repr(C)] +#[repr(align(65536))] +pub struct FixedSizeTranslationTable { + /// Page descriptors, covering 64 KiB windows per entry. + lvl3: [[PageDescriptor; 8192]; NUM_TABLES], + + /// Table descriptors, covering 512 MiB windows. + lvl2: [TableDescriptor; NUM_TABLES], + + /// Have the tables been initialized? + initialized: bool, +} + +//-------------------------------------------------------------------------------------------------- +// Private Code +//-------------------------------------------------------------------------------------------------- + +impl StartAddr for [T; N] { + fn virt_start_addr(&self) -> Address { + Address::new(self as *const _ as usize) + } +} + +impl TableDescriptor { + /// Create an instance. + /// + /// Descriptor is invalid by default. + pub const fn new_zeroed() -> Self { + Self { value: 0 } + } + + /// Create an instance pointing to the supplied address. + pub fn from_next_lvl_table_addr(phys_next_lvl_table_addr: Address) -> Self { + let val = InMemoryRegister::::new(0); + + let shifted = phys_next_lvl_table_addr.as_usize() >> Granule64KiB::SHIFT; + val.write( + STAGE1_TABLE_DESCRIPTOR::NEXT_LEVEL_TABLE_ADDR_64KiB.val(shifted as u64) + + STAGE1_TABLE_DESCRIPTOR::TYPE::Table + + STAGE1_TABLE_DESCRIPTOR::VALID::True, + ); + + TableDescriptor { value: val.get() } + } +} + +/// Convert the kernel's generic memory attributes to HW-specific attributes of the MMU. +impl convert::From + for tock_registers::fields::FieldValue +{ + fn from(attribute_fields: AttributeFields) -> Self { + // Memory attributes. + let mut desc = match attribute_fields.mem_attributes { + MemAttributes::CacheableDRAM => { + STAGE1_PAGE_DESCRIPTOR::SH::InnerShareable + + STAGE1_PAGE_DESCRIPTOR::AttrIndx.val(memory::mmu::arch_mmu::mair::NORMAL) + } + MemAttributes::Device => { + STAGE1_PAGE_DESCRIPTOR::SH::OuterShareable + + STAGE1_PAGE_DESCRIPTOR::AttrIndx.val(memory::mmu::arch_mmu::mair::DEVICE) + } + }; + + // Access Permissions. + desc += match attribute_fields.acc_perms { + AccessPermissions::ReadOnly => STAGE1_PAGE_DESCRIPTOR::AP::RO_EL1, + AccessPermissions::ReadWrite => STAGE1_PAGE_DESCRIPTOR::AP::RW_EL1, + }; + + // The execute-never attribute is mapped to PXN in AArch64. + desc += if attribute_fields.execute_never { + STAGE1_PAGE_DESCRIPTOR::PXN::True + } else { + STAGE1_PAGE_DESCRIPTOR::PXN::False + }; + + // Always set unprivileged exectue-never as long as userspace is not implemented yet. + desc += STAGE1_PAGE_DESCRIPTOR::UXN::True; + + desc + } +} + +/// Convert the HW-specific attributes of the MMU to kernel's generic memory attributes. +impl convert::TryFrom> for AttributeFields { + type Error = &'static str; + + fn try_from( + desc: InMemoryRegister, + ) -> Result { + let mem_attributes = match desc.read(STAGE1_PAGE_DESCRIPTOR::AttrIndx) { + memory::mmu::arch_mmu::mair::NORMAL => MemAttributes::CacheableDRAM, + memory::mmu::arch_mmu::mair::DEVICE => MemAttributes::Device, + _ => return Err("Unexpected memory attribute"), + }; + + let acc_perms = match desc.read_as_enum(STAGE1_PAGE_DESCRIPTOR::AP) { + Some(STAGE1_PAGE_DESCRIPTOR::AP::Value::RO_EL1) => AccessPermissions::ReadOnly, + Some(STAGE1_PAGE_DESCRIPTOR::AP::Value::RW_EL1) => AccessPermissions::ReadWrite, + _ => return Err("Unexpected access permission"), + }; + + let execute_never = desc.read(STAGE1_PAGE_DESCRIPTOR::PXN) > 0; + + Ok(AttributeFields { + mem_attributes, + acc_perms, + execute_never, + }) + } +} + +impl PageDescriptor { + /// Create an instance. + /// + /// Descriptor is invalid by default. + pub const fn new_zeroed() -> Self { + Self { value: 0 } + } + + /// Create an instance. + pub fn from_output_page_addr( + phys_output_page_addr: PageAddress, + attribute_fields: &AttributeFields, + ) -> Self { + let val = InMemoryRegister::::new(0); + + let shifted = phys_output_page_addr.into_inner().as_usize() >> Granule64KiB::SHIFT; + val.write( + STAGE1_PAGE_DESCRIPTOR::OUTPUT_ADDR_64KiB.val(shifted as u64) + + STAGE1_PAGE_DESCRIPTOR::AF::True + + STAGE1_PAGE_DESCRIPTOR::TYPE::Page + + STAGE1_PAGE_DESCRIPTOR::VALID::True + + (*attribute_fields).into(), + ); + + Self { value: val.get() } + } + + /// Returns the valid bit. + fn is_valid(&self) -> bool { + InMemoryRegister::::new(self.value) + .is_set(STAGE1_PAGE_DESCRIPTOR::VALID) + } + + /// Returns the output page. + fn output_page_addr(&self) -> PageAddress { + let shifted = InMemoryRegister::::new(self.value) + .read(STAGE1_PAGE_DESCRIPTOR::OUTPUT_ADDR_64KiB) as usize; + + PageAddress::from(shifted << Granule64KiB::SHIFT) + } + + /// Returns the attributes. + fn try_attributes(&self) -> Result { + InMemoryRegister::::new(self.value).try_into() + } +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +impl memory::mmu::AssociatedTranslationTable + for memory::mmu::AddressSpace +where + [u8; Self::SIZE >> Granule512MiB::SHIFT]: Sized, +{ + type TableStartFromTop = + FixedSizeTranslationTable<{ Self::SIZE >> Granule512MiB::SHIFT }, true>; + + type TableStartFromBottom = + FixedSizeTranslationTable<{ Self::SIZE >> Granule512MiB::SHIFT }, false>; +} + +impl + FixedSizeTranslationTable +{ + const START_FROM_TOP_OFFSET: Address = + Address::new((usize::MAX - (Granule512MiB::SIZE * NUM_TABLES)) + 1); + + /// Create an instance. + #[allow(clippy::assertions_on_constants)] + const fn _new(for_precompute: bool) -> Self { + assert!(bsp::memory::mmu::KernelGranule::SIZE == Granule64KiB::SIZE); + + // Can't have a zero-sized address space. + assert!(NUM_TABLES > 0); + + Self { + lvl3: [[PageDescriptor::new_zeroed(); 8192]; NUM_TABLES], + lvl2: [TableDescriptor::new_zeroed(); NUM_TABLES], + initialized: for_precompute, + } + } + + pub const fn new_for_precompute() -> Self { + Self::_new(true) + } + + #[cfg(test)] + pub fn new_for_runtime() -> Self { + Self::_new(false) + } + + /// Helper to calculate the lvl2 and lvl3 indices from an address. + #[inline(always)] + fn lvl2_lvl3_index_from_page_addr( + &self, + virt_page_addr: PageAddress, + ) -> Result<(usize, usize), &'static str> { + let mut addr = virt_page_addr.into_inner(); + + if START_FROM_TOP { + addr = addr - Self::START_FROM_TOP_OFFSET; + } + + let lvl2_index = addr.as_usize() >> Granule512MiB::SHIFT; + let lvl3_index = (addr.as_usize() & Granule512MiB::MASK) >> Granule64KiB::SHIFT; + + if lvl2_index > (NUM_TABLES - 1) { + return Err("Virtual page is out of bounds of translation table"); + } + + Ok((lvl2_index, lvl3_index)) + } + + /// Returns the PageDescriptor corresponding to the supplied page address. + #[inline(always)] + fn page_descriptor_from_page_addr( + &self, + virt_page_addr: PageAddress, + ) -> Result<&PageDescriptor, &'static str> { + let (lvl2_index, lvl3_index) = self.lvl2_lvl3_index_from_page_addr(virt_page_addr)?; + let desc = &self.lvl3[lvl2_index][lvl3_index]; + + Ok(desc) + } + + /// Sets the PageDescriptor corresponding to the supplied page address. + /// + /// Doesn't allow overriding an already valid page. + #[inline(always)] + fn set_page_descriptor_from_page_addr( + &mut self, + virt_page_addr: PageAddress, + new_desc: &PageDescriptor, + ) -> Result<(), &'static str> { + let (lvl2_index, lvl3_index) = self.lvl2_lvl3_index_from_page_addr(virt_page_addr)?; + let desc = &mut self.lvl3[lvl2_index][lvl3_index]; + + if desc.is_valid() { + return Err("Virtual page is already mapped"); + } + + *desc = *new_desc; + Ok(()) + } +} + +//------------------------------------------------------------------------------ +// OS Interface Code +//------------------------------------------------------------------------------ + +impl + memory::mmu::translation_table::interface::TranslationTable + for FixedSizeTranslationTable +{ + fn init(&mut self) -> Result<(), &'static str> { + if self.initialized { + return Ok(()); + } + + // Populate the l2 entries. + for (lvl2_nr, lvl2_entry) in self.lvl2.iter_mut().enumerate() { + let virt_table_addr = self.lvl3[lvl2_nr].virt_start_addr(); + let phys_table_addr = memory::mmu::try_kernel_virt_addr_to_phys_addr(virt_table_addr)?; + + let new_desc = TableDescriptor::from_next_lvl_table_addr(phys_table_addr); + *lvl2_entry = new_desc; + } + + self.initialized = true; + + Ok(()) + } + + unsafe fn map_at( + &mut self, + virt_region: &MemoryRegion, + phys_region: &MemoryRegion, + attr: &AttributeFields, + ) -> Result<(), &'static str> { + assert!(self.initialized, "Translation tables not initialized"); + + if virt_region.size() != phys_region.size() { + return Err("Tried to map memory regions with unequal sizes"); + } + + if phys_region.end_exclusive_page_addr() > bsp::memory::phys_addr_space_end_exclusive_addr() + { + return Err("Tried to map outside of physical address space"); + } + + let iter = phys_region.into_iter().zip(virt_region.into_iter()); + for (phys_page_addr, virt_page_addr) in iter { + let new_desc = PageDescriptor::from_output_page_addr(phys_page_addr, attr); + let virt_page = virt_page_addr; + + self.set_page_descriptor_from_page_addr(virt_page, &new_desc)?; + } + + Ok(()) + } + + fn try_virt_page_addr_to_phys_page_addr( + &self, + virt_page_addr: PageAddress, + ) -> Result, &'static str> { + let page_desc = self.page_descriptor_from_page_addr(virt_page_addr)?; + + if !page_desc.is_valid() { + return Err("Page marked invalid"); + } + + Ok(page_desc.output_page_addr()) + } + + fn try_page_attributes( + &self, + virt_page_addr: PageAddress, + ) -> Result { + let page_desc = self.page_descriptor_from_page_addr(virt_page_addr)?; + + if !page_desc.is_valid() { + return Err("Page marked invalid"); + } + + page_desc.try_attributes() + } + + /// Try to translate a virtual address to a physical address. + /// + /// Will only succeed if there exists a valid mapping for the input address. + fn try_virt_addr_to_phys_addr( + &self, + virt_addr: Address, + ) -> Result, &'static str> { + let virt_page = PageAddress::from(virt_addr.align_down_page()); + let phys_page = self.try_virt_page_addr_to_phys_page_addr(virt_page)?; + + Ok(phys_page.into_inner() + virt_addr.offset_into_page()) + } +} + +//-------------------------------------------------------------------------------------------------- +// Testing +//-------------------------------------------------------------------------------------------------- + +#[cfg(test)] +pub type MinSizeTranslationTable = FixedSizeTranslationTable<1, true>; + +#[cfg(test)] +mod tests { + use super::*; + use test_macros::kernel_test; + + /// Check if the size of `struct TableDescriptor` is as expected. + #[kernel_test] + fn size_of_tabledescriptor_equals_64_bit() { + assert_eq!( + core::mem::size_of::(), + core::mem::size_of::() + ); + } + + /// Check if the size of `struct PageDescriptor` is as expected. + #[kernel_test] + fn size_of_pagedescriptor_equals_64_bit() { + assert_eq!( + core::mem::size_of::(), + core::mem::size_of::() + ); + } +} diff --git a/19_kernel_heap/kernel/src/_arch/aarch64/time.rs b/19_kernel_heap/kernel/src/_arch/aarch64/time.rs new file mode 100644 index 00000000..c814219c --- /dev/null +++ b/19_kernel_heap/kernel/src/_arch/aarch64/time.rs @@ -0,0 +1,121 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2018-2022 Andre Richter + +//! Architectural timer primitives. +//! +//! # Orientation +//! +//! Since arch modules are imported into generic modules using the path attribute, the path of this +//! file is: +//! +//! crate::time::arch_time + +use crate::{time, warn}; +use core::time::Duration; +use cortex_a::{asm::barrier, registers::*}; +use tock_registers::interfaces::{ReadWriteable, Readable, Writeable}; + +//-------------------------------------------------------------------------------------------------- +// Private Definitions +//-------------------------------------------------------------------------------------------------- + +const NS_PER_S: u64 = 1_000_000_000; + +/// ARMv8 Generic Timer. +struct GenericTimer; + +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +static TIME_MANAGER: GenericTimer = GenericTimer; + +//-------------------------------------------------------------------------------------------------- +// Private Code +//-------------------------------------------------------------------------------------------------- + +impl GenericTimer { + #[inline(always)] + fn read_cntpct(&self) -> u64 { + // Prevent that the counter is read ahead of time due to out-of-order execution. + unsafe { barrier::isb(barrier::SY) }; + CNTPCT_EL0.get() + } +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +/// Return a reference to the time manager. +pub fn time_manager() -> &'static impl time::interface::TimeManager { + &TIME_MANAGER +} + +//------------------------------------------------------------------------------ +// OS Interface Code +//------------------------------------------------------------------------------ + +impl time::interface::TimeManager for GenericTimer { + fn resolution(&self) -> Duration { + Duration::from_nanos(NS_PER_S / (CNTFRQ_EL0.get() as u64)) + } + + fn uptime(&self) -> Duration { + let current_count: u64 = self.read_cntpct() * NS_PER_S; + let frq: u64 = CNTFRQ_EL0.get() as u64; + + Duration::from_nanos(current_count / frq) + } + + fn spin_for(&self, duration: Duration) { + // Instantly return on zero. + if duration.as_nanos() == 0 { + return; + } + + // Calculate the register compare value. + let frq = CNTFRQ_EL0.get(); + let x = match frq.checked_mul(duration.as_nanos() as u64) { + #[allow(unused_imports)] + None => { + warn!("Spin duration too long, skipping"); + return; + } + Some(val) => val, + }; + let tval = x / NS_PER_S; + + // Check if it is within supported bounds. + let warn: Option<&str> = if tval == 0 { + Some("smaller") + // The upper 32 bits of CNTP_TVAL_EL0 are reserved. + } else if tval > u32::max_value().into() { + Some("bigger") + } else { + None + }; + + #[allow(unused_imports)] + if let Some(w) = warn { + warn!( + "Spin duration {} than architecturally supported, skipping", + w + ); + return; + } + + // Set the compare value register. + CNTP_TVAL_EL0.set(tval); + + // Kick off the counting. // Disable timer interrupt. + CNTP_CTL_EL0.modify(CNTP_CTL_EL0::ENABLE::SET + CNTP_CTL_EL0::IMASK::SET); + + // ISTATUS will be '1' when cval ticks have passed. Busy-check it. + while !CNTP_CTL_EL0.matches_all(CNTP_CTL_EL0::ISTATUS::SET) {} + + // Disable counting again. + CNTP_CTL_EL0.modify(CNTP_CTL_EL0::ENABLE::CLEAR); + } +} diff --git a/19_kernel_heap/kernel/src/backtrace.rs b/19_kernel_heap/kernel/src/backtrace.rs new file mode 100644 index 00000000..22de6c48 --- /dev/null +++ b/19_kernel_heap/kernel/src/backtrace.rs @@ -0,0 +1,114 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2022 Andre Richter + +//! Backtracing support. + +#[cfg(target_arch = "aarch64")] +#[path = "_arch/aarch64/backtrace.rs"] +mod arch_backtrace; + +use crate::{ + memory::{Address, Virtual}, + symbols, +}; +use core::fmt; + +//-------------------------------------------------------------------------------------------------- +// Architectural Public Reexports +//-------------------------------------------------------------------------------------------------- +#[cfg(feature = "test_build")] +pub use arch_backtrace::{corrupt_link, corrupt_previous_frame_addr}; + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +/// A backtrace item. +#[allow(missing_docs)] +pub enum BacktraceItem { + InvalidFramePointer(Address), + InvalidLink(Address), + Link(Address), +} + +/// Pseudo-struct for printing a backtrace using its fmt::Display implementation. +pub struct Backtrace; + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +impl fmt::Display for Backtrace { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + writeln!(f, "Backtrace:")?; + writeln!( + f, + " ----------------------------------------------------------------------------------------------" + )?; + writeln!( + f, + " Address Function containing address" + )?; + writeln!( + f, + " ----------------------------------------------------------------------------------------------" + )?; + + let mut fmt_res: fmt::Result = Ok(()); + let trace_formatter = + |maybe_iter: Option<&mut dyn Iterator>| match maybe_iter { + None => fmt_res = writeln!(f, "ERROR! No valid stack frame found"), + Some(iter) => { + // Since the backtrace is printed, the first function is always + // core::fmt::write. Skip 1 so it is excluded and doesn't bloat the output. + for (i, backtrace_res) in iter.skip(1).enumerate() { + match backtrace_res { + BacktraceItem::InvalidFramePointer(addr) => { + fmt_res = writeln!( + f, + " {:>2}. ERROR! \ + Encountered invalid frame pointer ({}) during backtrace", + i + 1, + addr + ); + } + BacktraceItem::InvalidLink(addr) => { + fmt_res = writeln!( + f, + " {:>2}. ERROR! \ + Link address ({}) is not contained in kernel .text section", + i + 1, + addr + ); + } + BacktraceItem::Link(addr) => { + fmt_res = writeln!( + f, + " {:>2}. {:016x} | {:<50}", + i + 1, + addr.as_usize(), + match symbols::lookup_symbol(addr) { + Some(sym) => sym.name(), + _ => "Symbol not found", + } + ) + } + }; + + if fmt_res.is_err() { + break; + } + } + } + }; + + arch_backtrace::backtrace(trace_formatter); + fmt_res?; + + writeln!( + f, + " ----------------------------------------------------------------------------------------------" + ) + } +} diff --git a/19_kernel_heap/kernel/src/bsp.rs b/19_kernel_heap/kernel/src/bsp.rs new file mode 100644 index 00000000..824787f6 --- /dev/null +++ b/19_kernel_heap/kernel/src/bsp.rs @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2018-2022 Andre Richter + +//! Conditional reexporting of Board Support Packages. + +mod device_driver; + +#[cfg(any(feature = "bsp_rpi3", feature = "bsp_rpi4"))] +mod raspberrypi; + +#[cfg(any(feature = "bsp_rpi3", feature = "bsp_rpi4"))] +pub use raspberrypi::*; diff --git a/19_kernel_heap/kernel/src/bsp/device_driver.rs b/19_kernel_heap/kernel/src/bsp/device_driver.rs new file mode 100644 index 00000000..eafaf775 --- /dev/null +++ b/19_kernel_heap/kernel/src/bsp/device_driver.rs @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2018-2022 Andre Richter + +//! Device driver. + +#[cfg(feature = "bsp_rpi4")] +mod arm; +#[cfg(any(feature = "bsp_rpi3", feature = "bsp_rpi4"))] +mod bcm; +mod common; + +#[cfg(feature = "bsp_rpi4")] +pub use arm::*; +#[cfg(any(feature = "bsp_rpi3", feature = "bsp_rpi4"))] +pub use bcm::*; diff --git a/19_kernel_heap/kernel/src/bsp/device_driver/arm.rs b/19_kernel_heap/kernel/src/bsp/device_driver/arm.rs new file mode 100644 index 00000000..e83e24c9 --- /dev/null +++ b/19_kernel_heap/kernel/src/bsp/device_driver/arm.rs @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2020-2022 Andre Richter + +//! ARM driver top level. + +pub mod gicv2; + +pub use gicv2::*; diff --git a/19_kernel_heap/kernel/src/bsp/device_driver/arm/gicv2.rs b/19_kernel_heap/kernel/src/bsp/device_driver/arm/gicv2.rs new file mode 100644 index 00000000..cb7c69ee --- /dev/null +++ b/19_kernel_heap/kernel/src/bsp/device_driver/arm/gicv2.rs @@ -0,0 +1,242 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2020-2022 Andre Richter + +//! GICv2 Driver - ARM Generic Interrupt Controller v2. +//! +//! The following is a collection of excerpts with useful information from +//! - `Programmer's Guide for ARMv8-A` +//! - `ARM Generic Interrupt Controller Architecture Specification` +//! +//! # Programmer's Guide - 10.6.1 Configuration +//! +//! The GIC is accessed as a memory-mapped peripheral. +//! +//! All cores can access the common Distributor, but the CPU interface is banked, that is, each core +//! uses the same address to access its own private CPU interface. +//! +//! It is not possible for a core to access the CPU interface of another core. +//! +//! # Architecture Specification - 10.6.2 Initialization +//! +//! Both the Distributor and the CPU interfaces are disabled at reset. The GIC must be initialized +//! after reset before it can deliver interrupts to the core. +//! +//! In the Distributor, software must configure the priority, target, security and enable individual +//! interrupts. The Distributor must subsequently be enabled through its control register +//! (GICD_CTLR). For each CPU interface, software must program the priority mask and preemption +//! settings. +//! +//! Each CPU interface block itself must be enabled through its control register (GICD_CTLR). This +//! prepares the GIC to deliver interrupts to the core. +//! +//! Before interrupts are expected in the core, software prepares the core to take interrupts by +//! setting a valid interrupt vector in the vector table, and clearing interrupt mask bits in +//! PSTATE, and setting the routing controls. +//! +//! The entire interrupt mechanism in the system can be disabled by disabling the Distributor. +//! Interrupt delivery to an individual core can be disabled by disabling its CPU interface. +//! Individual interrupts can also be disabled (or enabled) in the distributor. +//! +//! For an interrupt to reach the core, the individual interrupt, Distributor and CPU interface must +//! all be enabled. The interrupt also needs to be of sufficient priority, that is, higher than the +//! core's priority mask. +//! +//! # Architecture Specification - 1.4.2 Interrupt types +//! +//! - Peripheral interrupt +//! - Private Peripheral Interrupt (PPI) +//! - This is a peripheral interrupt that is specific to a single processor. +//! - Shared Peripheral Interrupt (SPI) +//! - This is a peripheral interrupt that the Distributor can route to any of a specified +//! combination of processors. +//! +//! - Software-generated interrupt (SGI) +//! - This is an interrupt generated by software writing to a GICD_SGIR register in the GIC. The +//! system uses SGIs for interprocessor communication. +//! - An SGI has edge-triggered properties. The software triggering of the interrupt is +//! equivalent to the edge transition of the interrupt request signal. +//! - When an SGI occurs in a multiprocessor implementation, the CPUID field in the Interrupt +//! Acknowledge Register, GICC_IAR, or the Aliased Interrupt Acknowledge Register, GICC_AIAR, +//! identifies the processor that requested the interrupt. +//! +//! # Architecture Specification - 2.2.1 Interrupt IDs +//! +//! Interrupts from sources are identified using ID numbers. Each CPU interface can see up to 1020 +//! interrupts. The banking of SPIs and PPIs increases the total number of interrupts supported by +//! the Distributor. +//! +//! The GIC assigns interrupt ID numbers ID0-ID1019 as follows: +//! - Interrupt numbers 32..1019 are used for SPIs. +//! - Interrupt numbers 0..31 are used for interrupts that are private to a CPU interface. These +//! interrupts are banked in the Distributor. +//! - A banked interrupt is one where the Distributor can have multiple interrupts with the +//! same ID. A banked interrupt is identified uniquely by its ID number and its associated +//! CPU interface number. Of the banked interrupt IDs: +//! - 00..15 SGIs +//! - 16..31 PPIs + +mod gicc; +mod gicd; + +use crate::{ + bsp, cpu, driver, exception, + memory::{Address, Virtual}, + synchronization, + synchronization::InitStateLock, +}; +use alloc::vec::Vec; + +//-------------------------------------------------------------------------------------------------- +// Private Definitions +//-------------------------------------------------------------------------------------------------- + +type HandlerTable = Vec>; + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +/// Used for the associated type of trait [`exception::asynchronous::interface::IRQManager`]. +pub type IRQNumber = exception::asynchronous::IRQNumber<{ GICv2::MAX_IRQ_NUMBER }>; + +/// Representation of the GIC. +pub struct GICv2 { + /// The Distributor. + gicd: gicd::GICD, + + /// The CPU Interface. + gicc: gicc::GICC, + + /// Stores registered IRQ handlers. Writable only during kernel init. RO afterwards. + handler_table: InitStateLock, + + /// Callback to be invoked after successful init. + post_init_callback: fn(), +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +impl GICv2 { + const MAX_IRQ_NUMBER: usize = 1019; + + pub const COMPATIBLE: &'static str = "GICv2 (ARM Generic Interrupt Controller v2)"; + + /// Create an instance. + /// + /// # Safety + /// + /// - The user must ensure to provide a correct MMIO start address. + pub const unsafe fn new( + gicd_mmio_start_addr: Address, + gicc_mmio_start_addr: Address, + post_init_callback: fn(), + ) -> Self { + Self { + gicd: gicd::GICD::new(gicd_mmio_start_addr), + gicc: gicc::GICC::new(gicc_mmio_start_addr), + handler_table: InitStateLock::new(Vec::new()), + post_init_callback, + } + } +} + +//------------------------------------------------------------------------------ +// OS Interface Code +//------------------------------------------------------------------------------ +use synchronization::interface::ReadWriteEx; + +impl driver::interface::DeviceDriver for GICv2 { + fn compatible(&self) -> &'static str { + Self::COMPATIBLE + } + + unsafe fn init(&self) -> Result<(), &'static str> { + if bsp::cpu::BOOT_CORE_ID == cpu::smp::core_id() { + self.gicd.boot_core_init(); + } + + self.gicc.priority_accept_all(); + self.gicc.enable(); + + (self.post_init_callback)(); + + Ok(()) + } +} + +impl exception::asynchronous::interface::IRQManager for GICv2 { + type IRQNumberType = IRQNumber; + + fn register_handler( + &self, + irq_number: Self::IRQNumberType, + descriptor: exception::asynchronous::IRQDescriptor, + ) -> Result<(), &'static str> { + self.handler_table.write(|table| { + let irq_number = irq_number.get(); + + if table.len() < irq_number { + // IRQDescriptor has an integrated range sanity check on construction, so this + // vector can't grow arbitrarily big. + table.resize(irq_number + 1, None); + } + + if table[irq_number].is_some() { + return Err("IRQ handler already registered"); + } + + table[irq_number] = Some(descriptor); + + Ok(()) + }) + } + + fn enable(&self, irq_number: Self::IRQNumberType) { + self.gicd.enable(irq_number); + } + + fn handle_pending_irqs<'irq_context>( + &'irq_context self, + ic: &exception::asynchronous::IRQContext<'irq_context>, + ) { + // Extract the highest priority pending IRQ number from the Interrupt Acknowledge Register + // (IAR). + let irq_number = self.gicc.pending_irq_number(ic); + + // Guard against spurious interrupts. + if irq_number > GICv2::MAX_IRQ_NUMBER { + return; + } + + // Call the IRQ handler. Panic if there is none. + self.handler_table.read(|table| { + match table[irq_number] { + None => panic!("No handler registered for IRQ {}", irq_number), + Some(descriptor) => { + // Call the IRQ handler. Panics on failure. + descriptor.handler.handle().expect("Error handling IRQ"); + } + } + }); + + // Signal completion of handling. + self.gicc.mark_comleted(irq_number as u32, ic); + } + + fn print_handler(&self) { + use crate::info; + + info!(" Peripheral handler:"); + + self.handler_table.read(|table| { + for (i, opt) in table.iter().skip(32).enumerate() { + if let Some(handler) = opt { + info!(" {: >3}. {}", i + 32, handler.name); + } + } + }); + } +} diff --git a/19_kernel_heap/kernel/src/bsp/device_driver/arm/gicv2/gicc.rs b/19_kernel_heap/kernel/src/bsp/device_driver/arm/gicv2/gicc.rs new file mode 100644 index 00000000..1a02fc65 --- /dev/null +++ b/19_kernel_heap/kernel/src/bsp/device_driver/arm/gicv2/gicc.rs @@ -0,0 +1,145 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2020-2022 Andre Richter + +//! GICC Driver - GIC CPU interface. + +use crate::{ + bsp::device_driver::common::MMIODerefWrapper, + exception, + memory::{Address, Virtual}, +}; +use tock_registers::{ + interfaces::{Readable, Writeable}, + register_bitfields, register_structs, + registers::ReadWrite, +}; + +//-------------------------------------------------------------------------------------------------- +// Private Definitions +//-------------------------------------------------------------------------------------------------- + +register_bitfields! { + u32, + + /// CPU Interface Control Register + CTLR [ + Enable OFFSET(0) NUMBITS(1) [] + ], + + /// Interrupt Priority Mask Register + PMR [ + Priority OFFSET(0) NUMBITS(8) [] + ], + + /// Interrupt Acknowledge Register + IAR [ + InterruptID OFFSET(0) NUMBITS(10) [] + ], + + /// End of Interrupt Register + EOIR [ + EOIINTID OFFSET(0) NUMBITS(10) [] + ] +} + +register_structs! { + #[allow(non_snake_case)] + pub RegisterBlock { + (0x000 => CTLR: ReadWrite), + (0x004 => PMR: ReadWrite), + (0x008 => _reserved1), + (0x00C => IAR: ReadWrite), + (0x010 => EOIR: ReadWrite), + (0x014 => @END), + } +} + +/// Abstraction for the associated MMIO registers. +type Registers = MMIODerefWrapper; + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +/// Representation of the GIC CPU interface. +pub struct GICC { + registers: Registers, +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +impl GICC { + /// Create an instance. + /// + /// # Safety + /// + /// - The user must ensure to provide a correct MMIO start address. + pub const unsafe fn new(mmio_start_addr: Address) -> Self { + Self { + registers: Registers::new(mmio_start_addr), + } + } + + /// Accept interrupts of any priority. + /// + /// Quoting the GICv2 Architecture Specification: + /// + /// "Writing 255 to the GICC_PMR always sets it to the largest supported priority field + /// value." + /// + /// # Safety + /// + /// - GICC MMIO registers are banked per CPU core. It is therefore safe to have `&self` instead + /// of `&mut self`. + pub fn priority_accept_all(&self) { + self.registers.PMR.write(PMR::Priority.val(255)); // Comment in arch spec. + } + + /// Enable the interface - start accepting IRQs. + /// + /// # Safety + /// + /// - GICC MMIO registers are banked per CPU core. It is therefore safe to have `&self` instead + /// of `&mut self`. + pub fn enable(&self) { + self.registers.CTLR.write(CTLR::Enable::SET); + } + + /// Extract the number of the highest-priority pending IRQ. + /// + /// Can only be called from IRQ context, which is ensured by taking an `IRQContext` token. + /// + /// # Safety + /// + /// - GICC MMIO registers are banked per CPU core. It is therefore safe to have `&self` instead + /// of `&mut self`. + #[allow(clippy::trivially_copy_pass_by_ref)] + pub fn pending_irq_number<'irq_context>( + &self, + _ic: &exception::asynchronous::IRQContext<'irq_context>, + ) -> usize { + self.registers.IAR.read(IAR::InterruptID) as usize + } + + /// Complete handling of the currently active IRQ. + /// + /// Can only be called from IRQ context, which is ensured by taking an `IRQContext` token. + /// + /// To be called after `pending_irq_number()`. + /// + /// # Safety + /// + /// - GICC MMIO registers are banked per CPU core. It is therefore safe to have `&self` instead + /// of `&mut self`. + #[allow(clippy::trivially_copy_pass_by_ref)] + pub fn mark_comleted<'irq_context>( + &self, + irq_number: u32, + _ic: &exception::asynchronous::IRQContext<'irq_context>, + ) { + self.registers.EOIR.write(EOIR::EOIINTID.val(irq_number)); + } +} diff --git a/19_kernel_heap/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs b/19_kernel_heap/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs new file mode 100644 index 00000000..d9f63d1b --- /dev/null +++ b/19_kernel_heap/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs @@ -0,0 +1,201 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2020-2022 Andre Richter + +//! GICD Driver - GIC Distributor. +//! +//! # Glossary +//! - SPI - Shared Peripheral Interrupt. + +use crate::{ + bsp::device_driver::common::MMIODerefWrapper, + memory::{Address, Virtual}, + state, synchronization, + synchronization::IRQSafeNullLock, +}; +use tock_registers::{ + interfaces::{Readable, Writeable}, + register_bitfields, register_structs, + registers::{ReadOnly, ReadWrite}, +}; + +//-------------------------------------------------------------------------------------------------- +// Private Definitions +//-------------------------------------------------------------------------------------------------- + +register_bitfields! { + u32, + + /// Distributor Control Register + CTLR [ + Enable OFFSET(0) NUMBITS(1) [] + ], + + /// Interrupt Controller Type Register + TYPER [ + ITLinesNumber OFFSET(0) NUMBITS(5) [] + ], + + /// Interrupt Processor Targets Registers + ITARGETSR [ + Offset3 OFFSET(24) NUMBITS(8) [], + Offset2 OFFSET(16) NUMBITS(8) [], + Offset1 OFFSET(8) NUMBITS(8) [], + Offset0 OFFSET(0) NUMBITS(8) [] + ] +} + +register_structs! { + #[allow(non_snake_case)] + SharedRegisterBlock { + (0x000 => CTLR: ReadWrite), + (0x004 => TYPER: ReadOnly), + (0x008 => _reserved1), + (0x104 => ISENABLER: [ReadWrite; 31]), + (0x108 => _reserved2), + (0x820 => ITARGETSR: [ReadWrite; 248]), + (0x824 => @END), + } +} + +register_structs! { + #[allow(non_snake_case)] + BankedRegisterBlock { + (0x000 => _reserved1), + (0x100 => ISENABLER: ReadWrite), + (0x104 => _reserved2), + (0x800 => ITARGETSR: [ReadOnly; 8]), + (0x804 => @END), + } +} + +/// Abstraction for the non-banked parts of the associated MMIO registers. +type SharedRegisters = MMIODerefWrapper; + +/// Abstraction for the banked parts of the associated MMIO registers. +type BankedRegisters = MMIODerefWrapper; + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +/// Representation of the GIC Distributor. +pub struct GICD { + /// Access to shared registers is guarded with a lock. + shared_registers: IRQSafeNullLock, + + /// Access to banked registers is unguarded. + banked_registers: BankedRegisters, +} + +//-------------------------------------------------------------------------------------------------- +// Private Code +//-------------------------------------------------------------------------------------------------- + +impl SharedRegisters { + /// Return the number of IRQs that this HW implements. + #[inline(always)] + fn num_irqs(&mut self) -> usize { + // Query number of implemented IRQs. + // + // Refer to GICv2 Architecture Specification, Section 4.3.2. + ((self.TYPER.read(TYPER::ITLinesNumber) as usize) + 1) * 32 + } + + /// Return a slice of the implemented ITARGETSR. + #[inline(always)] + fn implemented_itargets_slice(&mut self) -> &[ReadWrite] { + assert!(self.num_irqs() >= 36); + + // Calculate the max index of the shared ITARGETSR array. + // + // The first 32 IRQs are private, so not included in `shared_registers`. Each ITARGETS + // register has four entries, so shift right by two. Subtract one because we start + // counting at zero. + let spi_itargetsr_max_index = ((self.num_irqs() - 32) >> 2) - 1; + + // Rust automatically inserts slice range sanity check, i.e. max >= min. + &self.ITARGETSR[0..spi_itargetsr_max_index] + } +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- +use synchronization::interface::Mutex; + +impl GICD { + /// Create an instance. + /// + /// # Safety + /// + /// - The user must ensure to provide a correct MMIO start address. + pub const unsafe fn new(mmio_start_addr: Address) -> Self { + Self { + shared_registers: IRQSafeNullLock::new(SharedRegisters::new(mmio_start_addr)), + banked_registers: BankedRegisters::new(mmio_start_addr), + } + } + + /// Use a banked ITARGETSR to retrieve the executing core's GIC target mask. + /// + /// Quoting the GICv2 Architecture Specification: + /// + /// "GICD_ITARGETSR0 to GICD_ITARGETSR7 are read-only, and each field returns a value that + /// corresponds only to the processor reading the register." + fn local_gic_target_mask(&self) -> u32 { + self.banked_registers.ITARGETSR[0].read(ITARGETSR::Offset0) + } + + /// Route all SPIs to the boot core and enable the distributor. + pub fn boot_core_init(&self) { + assert!( + state::state_manager().is_init(), + "Only allowed during kernel init phase" + ); + + // Target all SPIs to the boot core only. + let mask = self.local_gic_target_mask(); + + self.shared_registers.lock(|regs| { + for i in regs.implemented_itargets_slice().iter() { + i.write( + ITARGETSR::Offset3.val(mask) + + ITARGETSR::Offset2.val(mask) + + ITARGETSR::Offset1.val(mask) + + ITARGETSR::Offset0.val(mask), + ); + } + + regs.CTLR.write(CTLR::Enable::SET); + }); + } + + /// Enable an interrupt. + pub fn enable(&self, irq_num: super::IRQNumber) { + let irq_num = irq_num.get(); + + // Each bit in the u32 enable register corresponds to one IRQ number. Shift right by 5 + // (division by 32) and arrive at the index for the respective ISENABLER[i]. + let enable_reg_index = irq_num >> 5; + let enable_bit: u32 = 1u32 << (irq_num % 32); + + // Check if we are handling a private or shared IRQ. + match irq_num { + // Private. + 0..=31 => { + let enable_reg = &self.banked_registers.ISENABLER; + enable_reg.set(enable_reg.get() | enable_bit); + } + // Shared. + _ => { + let enable_reg_index_shared = enable_reg_index - 1; + + self.shared_registers.lock(|regs| { + let enable_reg = ®s.ISENABLER[enable_reg_index_shared]; + enable_reg.set(enable_reg.get() | enable_bit); + }); + } + } + } +} diff --git a/19_kernel_heap/kernel/src/bsp/device_driver/bcm.rs b/19_kernel_heap/kernel/src/bsp/device_driver/bcm.rs new file mode 100644 index 00000000..5a7cc23b --- /dev/null +++ b/19_kernel_heap/kernel/src/bsp/device_driver/bcm.rs @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2018-2022 Andre Richter + +//! BCM driver top level. + +mod bcm2xxx_gpio; +#[cfg(feature = "bsp_rpi3")] +mod bcm2xxx_interrupt_controller; +mod bcm2xxx_pl011_uart; + +pub use bcm2xxx_gpio::*; +#[cfg(feature = "bsp_rpi3")] +pub use bcm2xxx_interrupt_controller::*; +pub use bcm2xxx_pl011_uart::*; diff --git a/19_kernel_heap/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs b/19_kernel_heap/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs new file mode 100644 index 00000000..a3361c2c --- /dev/null +++ b/19_kernel_heap/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs @@ -0,0 +1,233 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2018-2022 Andre Richter + +//! GPIO Driver. + +use crate::{ + bsp::device_driver::common::MMIODerefWrapper, + driver, + memory::{Address, Virtual}, + synchronization, + synchronization::IRQSafeNullLock, +}; +use tock_registers::{ + interfaces::{ReadWriteable, Writeable}, + register_bitfields, register_structs, + registers::ReadWrite, +}; + +//-------------------------------------------------------------------------------------------------- +// Private Definitions +//-------------------------------------------------------------------------------------------------- + +// GPIO registers. +// +// Descriptions taken from +// - https://github.com/raspberrypi/documentation/files/1888662/BCM2837-ARM-Peripherals.-.Revised.-.V2-1.pdf +// - https://datasheets.raspberrypi.org/bcm2711/bcm2711-peripherals.pdf +register_bitfields! { + u32, + + /// GPIO Function Select 1 + GPFSEL1 [ + /// Pin 15 + FSEL15 OFFSET(15) NUMBITS(3) [ + Input = 0b000, + Output = 0b001, + AltFunc0 = 0b100 // PL011 UART RX + + ], + + /// Pin 14 + FSEL14 OFFSET(12) NUMBITS(3) [ + Input = 0b000, + Output = 0b001, + AltFunc0 = 0b100 // PL011 UART TX + ] + ], + + /// GPIO Pull-up/down Register + /// + /// BCM2837 only. + GPPUD [ + /// Controls the actuation of the internal pull-up/down control line to ALL the GPIO pins. + PUD OFFSET(0) NUMBITS(2) [ + Off = 0b00, + PullDown = 0b01, + PullUp = 0b10 + ] + ], + + /// GPIO Pull-up/down Clock Register 0 + /// + /// BCM2837 only. + GPPUDCLK0 [ + /// Pin 15 + PUDCLK15 OFFSET(15) NUMBITS(1) [ + NoEffect = 0, + AssertClock = 1 + ], + + /// Pin 14 + PUDCLK14 OFFSET(14) NUMBITS(1) [ + NoEffect = 0, + AssertClock = 1 + ] + ], + + /// GPIO Pull-up / Pull-down Register 0 + /// + /// BCM2711 only. + GPIO_PUP_PDN_CNTRL_REG0 [ + /// Pin 15 + GPIO_PUP_PDN_CNTRL15 OFFSET(30) NUMBITS(2) [ + NoResistor = 0b00, + PullUp = 0b01 + ], + + /// Pin 14 + GPIO_PUP_PDN_CNTRL14 OFFSET(28) NUMBITS(2) [ + NoResistor = 0b00, + PullUp = 0b01 + ] + ] +} + +register_structs! { + #[allow(non_snake_case)] + RegisterBlock { + (0x00 => _reserved1), + (0x04 => GPFSEL1: ReadWrite), + (0x08 => _reserved2), + (0x94 => GPPUD: ReadWrite), + (0x98 => GPPUDCLK0: ReadWrite), + (0x9C => _reserved3), + (0xE4 => GPIO_PUP_PDN_CNTRL_REG0: ReadWrite), + (0xE8 => @END), + } +} + +/// Abstraction for the associated MMIO registers. +type Registers = MMIODerefWrapper; + +struct GPIOInner { + registers: Registers, +} + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +/// Representation of the GPIO HW. +pub struct GPIO { + inner: IRQSafeNullLock, + post_init_callback: fn(), +} + +//-------------------------------------------------------------------------------------------------- +// Private Code +//-------------------------------------------------------------------------------------------------- + +impl GPIOInner { + /// Create an instance. + /// + /// # Safety + /// + /// - The user must ensure to provide a correct MMIO start address. + pub const unsafe fn new(mmio_start_addr: Address) -> Self { + Self { + registers: Registers::new(mmio_start_addr), + } + } + + /// Disable pull-up/down on pins 14 and 15. + #[cfg(feature = "bsp_rpi3")] + fn disable_pud_14_15_bcm2837(&mut self) { + use crate::{time, time::interface::TimeManager}; + use core::time::Duration; + + // The Linux 2837 GPIO driver waits 1 µs between the steps. + const DELAY: Duration = Duration::from_micros(1); + + self.registers.GPPUD.write(GPPUD::PUD::Off); + time::time_manager().spin_for(DELAY); + + self.registers + .GPPUDCLK0 + .write(GPPUDCLK0::PUDCLK15::AssertClock + GPPUDCLK0::PUDCLK14::AssertClock); + time::time_manager().spin_for(DELAY); + + self.registers.GPPUD.write(GPPUD::PUD::Off); + self.registers.GPPUDCLK0.set(0); + } + + /// Disable pull-up/down on pins 14 and 15. + #[cfg(feature = "bsp_rpi4")] + fn disable_pud_14_15_bcm2711(&mut self) { + self.registers.GPIO_PUP_PDN_CNTRL_REG0.write( + GPIO_PUP_PDN_CNTRL_REG0::GPIO_PUP_PDN_CNTRL15::PullUp + + GPIO_PUP_PDN_CNTRL_REG0::GPIO_PUP_PDN_CNTRL14::PullUp, + ); + } + + /// Map PL011 UART as standard output. + /// + /// TX to pin 14 + /// RX to pin 15 + pub fn map_pl011_uart(&mut self) { + // Select the UART on pins 14 and 15. + self.registers + .GPFSEL1 + .modify(GPFSEL1::FSEL15::AltFunc0 + GPFSEL1::FSEL14::AltFunc0); + + // Disable pull-up/down on pins 14 and 15. + #[cfg(feature = "bsp_rpi3")] + self.disable_pud_14_15_bcm2837(); + + #[cfg(feature = "bsp_rpi4")] + self.disable_pud_14_15_bcm2711(); + } +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +impl GPIO { + pub const COMPATIBLE: &'static str = "BCM GPIO"; + + /// Create an instance. + /// + /// # Safety + /// + /// - The user must ensure to provide a correct MMIO start address. + pub const unsafe fn new(mmio_start_addr: Address, post_init_callback: fn()) -> Self { + Self { + inner: IRQSafeNullLock::new(GPIOInner::new(mmio_start_addr)), + post_init_callback, + } + } + + /// Concurrency safe version of `GPIOInner.map_pl011_uart()` + pub fn map_pl011_uart(&self) { + self.inner.lock(|inner| inner.map_pl011_uart()) + } +} + +//------------------------------------------------------------------------------ +// OS Interface Code +//------------------------------------------------------------------------------ +use synchronization::interface::Mutex; + +impl driver::interface::DeviceDriver for GPIO { + fn compatible(&self) -> &'static str { + Self::COMPATIBLE + } + + unsafe fn init(&self) -> Result<(), &'static str> { + (self.post_init_callback)(); + + Ok(()) + } +} diff --git a/19_kernel_heap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs b/19_kernel_heap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs new file mode 100644 index 00000000..a93b0bc9 --- /dev/null +++ b/19_kernel_heap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs @@ -0,0 +1,147 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2020-2022 Andre Richter + +//! Interrupt Controller Driver. + +mod peripheral_ic; + +use crate::{ + driver, exception, + memory::{Address, Virtual}, +}; + +//-------------------------------------------------------------------------------------------------- +// Private Definitions +//-------------------------------------------------------------------------------------------------- + +/// Wrapper struct for a bitmask indicating pending IRQ numbers. +struct PendingIRQs { + bitmask: u64, +} + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +pub type LocalIRQ = + exception::asynchronous::IRQNumber<{ InterruptController::MAX_LOCAL_IRQ_NUMBER }>; +pub type PeripheralIRQ = + exception::asynchronous::IRQNumber<{ InterruptController::MAX_PERIPHERAL_IRQ_NUMBER }>; + +/// Used for the associated type of trait [`exception::asynchronous::interface::IRQManager`]. +#[derive(Copy, Clone)] +#[allow(missing_docs)] +pub enum IRQNumber { + Local(LocalIRQ), + Peripheral(PeripheralIRQ), +} + +/// Representation of the Interrupt Controller. +pub struct InterruptController { + periph: peripheral_ic::PeripheralIC, + post_init_callback: fn(), +} + +//-------------------------------------------------------------------------------------------------- +// Private Code +//-------------------------------------------------------------------------------------------------- + +impl PendingIRQs { + pub fn new(bitmask: u64) -> Self { + Self { bitmask } + } +} + +impl Iterator for PendingIRQs { + type Item = usize; + + fn next(&mut self) -> Option { + use core::intrinsics::cttz; + + let next = cttz(self.bitmask); + if next == 64 { + return None; + } + + self.bitmask &= !(1 << next); + + Some(next as usize) + } +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +impl InterruptController { + const MAX_LOCAL_IRQ_NUMBER: usize = 11; + const MAX_PERIPHERAL_IRQ_NUMBER: usize = 63; + + pub const COMPATIBLE: &'static str = "BCM Interrupt Controller"; + + /// Create an instance. + /// + /// # Safety + /// + /// - The user must ensure to provide a correct MMIO start address. + pub const unsafe fn new( + periph_mmio_start_addr: Address, + post_init_callback: fn(), + ) -> Self { + Self { + periph: peripheral_ic::PeripheralIC::new(periph_mmio_start_addr), + post_init_callback, + } + } +} + +//------------------------------------------------------------------------------ +// OS Interface Code +//------------------------------------------------------------------------------ + +impl driver::interface::DeviceDriver for InterruptController { + fn compatible(&self) -> &'static str { + Self::COMPATIBLE + } + + unsafe fn init(&self) -> Result<(), &'static str> { + (self.post_init_callback)(); + + Ok(()) + } +} + +impl exception::asynchronous::interface::IRQManager for InterruptController { + type IRQNumberType = IRQNumber; + + fn register_handler( + &self, + irq: Self::IRQNumberType, + descriptor: exception::asynchronous::IRQDescriptor, + ) -> Result<(), &'static str> { + match irq { + IRQNumber::Local(_) => unimplemented!("Local IRQ controller not implemented."), + IRQNumber::Peripheral(pirq) => self.periph.register_handler(pirq, descriptor), + } + } + + fn enable(&self, irq: Self::IRQNumberType) { + match irq { + IRQNumber::Local(_) => unimplemented!("Local IRQ controller not implemented."), + IRQNumber::Peripheral(pirq) => self.periph.enable(pirq), + } + } + + fn handle_pending_irqs<'irq_context>( + &'irq_context self, + ic: &exception::asynchronous::IRQContext<'irq_context>, + ) { + // It can only be a peripheral IRQ pending because enable() does not support local IRQs yet. + self.periph.handle_pending_irqs(ic) + } + + fn print_handler(&self) { + self.periph.print_handler(); + } +} diff --git a/19_kernel_heap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs b/19_kernel_heap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs new file mode 100644 index 00000000..a2034e3b --- /dev/null +++ b/19_kernel_heap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs @@ -0,0 +1,175 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2020-2022 Andre Richter + +//! Peripheral Interrupt Controller Driver. + +use super::{PendingIRQs, PeripheralIRQ}; +use crate::{ + bsp::device_driver::common::MMIODerefWrapper, + exception, + memory::{Address, Virtual}, + synchronization, + synchronization::{IRQSafeNullLock, InitStateLock}, +}; +use alloc::vec::Vec; +use tock_registers::{ + interfaces::{Readable, Writeable}, + register_structs, + registers::{ReadOnly, WriteOnly}, +}; + +//-------------------------------------------------------------------------------------------------- +// Private Definitions +//-------------------------------------------------------------------------------------------------- + +register_structs! { + #[allow(non_snake_case)] + WORegisterBlock { + (0x00 => _reserved1), + (0x10 => ENABLE_1: WriteOnly), + (0x14 => ENABLE_2: WriteOnly), + (0x24 => @END), + } +} + +register_structs! { + #[allow(non_snake_case)] + RORegisterBlock { + (0x00 => _reserved1), + (0x04 => PENDING_1: ReadOnly), + (0x08 => PENDING_2: ReadOnly), + (0x0c => @END), + } +} + +/// Abstraction for the WriteOnly parts of the associated MMIO registers. +type WriteOnlyRegisters = MMIODerefWrapper; + +/// Abstraction for the ReadOnly parts of the associated MMIO registers. +type ReadOnlyRegisters = MMIODerefWrapper; + +type HandlerTable = Vec>; + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +/// Representation of the peripheral interrupt controller. +pub struct PeripheralIC { + /// Access to write registers is guarded with a lock. + wo_registers: IRQSafeNullLock, + + /// Register read access is unguarded. + ro_registers: ReadOnlyRegisters, + + /// Stores registered IRQ handlers. Writable only during kernel init. RO afterwards. + handler_table: InitStateLock, +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +impl PeripheralIC { + /// Create an instance. + /// + /// # Safety + /// + /// - The user must ensure to provide a correct MMIO start address. + pub const unsafe fn new(mmio_start_addr: Address) -> Self { + Self { + wo_registers: IRQSafeNullLock::new(WriteOnlyRegisters::new(mmio_start_addr)), + ro_registers: ReadOnlyRegisters::new(mmio_start_addr), + handler_table: InitStateLock::new(Vec::new()), + } + } + + /// Query the list of pending IRQs. + fn pending_irqs(&self) -> PendingIRQs { + let pending_mask: u64 = (u64::from(self.ro_registers.PENDING_2.get()) << 32) + | u64::from(self.ro_registers.PENDING_1.get()); + + PendingIRQs::new(pending_mask) + } +} + +//------------------------------------------------------------------------------ +// OS Interface Code +//------------------------------------------------------------------------------ +use synchronization::interface::{Mutex, ReadWriteEx}; + +impl exception::asynchronous::interface::IRQManager for PeripheralIC { + type IRQNumberType = PeripheralIRQ; + + fn register_handler( + &self, + irq: Self::IRQNumberType, + descriptor: exception::asynchronous::IRQDescriptor, + ) -> Result<(), &'static str> { + self.handler_table.write(|table| { + let irq_number = irq.get(); + + if table.len() < irq_number { + // IRQDescriptor has an integrated range sanity check on construction, so this + // vector can't grow arbitrarily big. + table.resize(irq_number + 1, None); + } + + if table[irq_number].is_some() { + return Err("IRQ handler already registered"); + } + + table[irq_number] = Some(descriptor); + + Ok(()) + }) + } + + fn enable(&self, irq: Self::IRQNumberType) { + self.wo_registers.lock(|regs| { + let enable_reg = if irq.get() <= 31 { + ®s.ENABLE_1 + } else { + ®s.ENABLE_2 + }; + + let enable_bit: u32 = 1 << (irq.get() % 32); + + // Writing a 1 to a bit will set the corresponding IRQ enable bit. All other IRQ enable + // bits are unaffected. So we don't need read and OR'ing here. + enable_reg.set(enable_bit); + }); + } + + fn handle_pending_irqs<'irq_context>( + &'irq_context self, + _ic: &exception::asynchronous::IRQContext<'irq_context>, + ) { + self.handler_table.read(|table| { + for irq_number in self.pending_irqs() { + match table[irq_number] { + None => panic!("No handler registered for IRQ {}", irq_number), + Some(descriptor) => { + // Call the IRQ handler. Panics on failure. + descriptor.handler.handle().expect("Error handling IRQ"); + } + } + } + }) + } + + fn print_handler(&self) { + use crate::info; + + info!(" Peripheral handler:"); + + self.handler_table.read(|table| { + for (i, opt) in table.iter().enumerate() { + if let Some(handler) = opt { + info!(" {: >3}. {}", i, handler.name); + } + } + }); + } +} diff --git a/19_kernel_heap/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs b/19_kernel_heap/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs new file mode 100644 index 00000000..26593039 --- /dev/null +++ b/19_kernel_heap/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs @@ -0,0 +1,524 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2018-2022 Andre Richter + +//! PL011 UART driver. +//! +//! # Resources +//! +//! - +//! - + +use crate::{ + bsp, + bsp::device_driver::common::MMIODerefWrapper, + console, cpu, driver, exception, + memory::{Address, Virtual}, + synchronization, + synchronization::IRQSafeNullLock, +}; +use core::fmt; +use tock_registers::{ + interfaces::{Readable, Writeable}, + register_bitfields, register_structs, + registers::{ReadOnly, ReadWrite, WriteOnly}, +}; + +//-------------------------------------------------------------------------------------------------- +// Private Definitions +//-------------------------------------------------------------------------------------------------- + +// PL011 UART registers. +// +// Descriptions taken from "PrimeCell UART (PL011) Technical Reference Manual" r1p5. +register_bitfields! { + u32, + + /// Flag Register. + FR [ + /// Transmit FIFO empty. The meaning of this bit depends on the state of the FEN bit in the + /// Line Control Register, LCR_H. + /// + /// - If the FIFO is disabled, this bit is set when the transmit holding register is empty. + /// - If the FIFO is enabled, the TXFE bit is set when the transmit FIFO is empty. + /// - This bit does not indicate if there is data in the transmit shift register. + TXFE OFFSET(7) NUMBITS(1) [], + + /// Transmit FIFO full. The meaning of this bit depends on the state of the FEN bit in the + /// LCR_H Register. + /// + /// - If the FIFO is disabled, this bit is set when the transmit holding register is full. + /// - If the FIFO is enabled, the TXFF bit is set when the transmit FIFO is full. + TXFF OFFSET(5) NUMBITS(1) [], + + /// Receive FIFO empty. The meaning of this bit depends on the state of the FEN bit in the + /// LCR_H Register. + /// + /// - If the FIFO is disabled, this bit is set when the receive holding register is empty. + /// - If the FIFO is enabled, the RXFE bit is set when the receive FIFO is empty. + RXFE OFFSET(4) NUMBITS(1) [], + + /// UART busy. If this bit is set to 1, the UART is busy transmitting data. This bit remains + /// set until the complete byte, including all the stop bits, has been sent from the shift + /// register. + /// + /// This bit is set as soon as the transmit FIFO becomes non-empty, regardless of whether + /// the UART is enabled or not. + BUSY OFFSET(3) NUMBITS(1) [] + ], + + /// Integer Baud Rate Divisor. + IBRD [ + /// The integer baud rate divisor. + BAUD_DIVINT OFFSET(0) NUMBITS(16) [] + ], + + /// Fractional Baud Rate Divisor. + FBRD [ + /// The fractional baud rate divisor. + BAUD_DIVFRAC OFFSET(0) NUMBITS(6) [] + ], + + /// Line Control Register. + LCR_H [ + /// Word length. These bits indicate the number of data bits transmitted or received in a + /// frame. + #[allow(clippy::enum_variant_names)] + WLEN OFFSET(5) NUMBITS(2) [ + FiveBit = 0b00, + SixBit = 0b01, + SevenBit = 0b10, + EightBit = 0b11 + ], + + /// Enable FIFOs: + /// + /// 0 = FIFOs are disabled (character mode) that is, the FIFOs become 1-byte-deep holding + /// registers. + /// + /// 1 = Transmit and receive FIFO buffers are enabled (FIFO mode). + FEN OFFSET(4) NUMBITS(1) [ + FifosDisabled = 0, + FifosEnabled = 1 + ] + ], + + /// Control Register. + CR [ + /// Receive enable. If this bit is set to 1, the receive section of the UART is enabled. + /// Data reception occurs for either UART signals or SIR signals depending on the setting of + /// the SIREN bit. When the UART is disabled in the middle of reception, it completes the + /// current character before stopping. + RXE OFFSET(9) NUMBITS(1) [ + Disabled = 0, + Enabled = 1 + ], + + /// Transmit enable. If this bit is set to 1, the transmit section of the UART is enabled. + /// Data transmission occurs for either UART signals, or SIR signals depending on the + /// setting of the SIREN bit. When the UART is disabled in the middle of transmission, it + /// completes the current character before stopping. + TXE OFFSET(8) NUMBITS(1) [ + Disabled = 0, + Enabled = 1 + ], + + /// UART enable: + /// + /// 0 = UART is disabled. If the UART is disabled in the middle of transmission or + /// reception, it completes the current character before stopping. + /// + /// 1 = The UART is enabled. Data transmission and reception occurs for either UART signals + /// or SIR signals depending on the setting of the SIREN bit + UARTEN OFFSET(0) NUMBITS(1) [ + /// If the UART is disabled in the middle of transmission or reception, it completes the + /// current character before stopping. + Disabled = 0, + Enabled = 1 + ] + ], + + /// Interrupt FIFO Level Select Register. + IFLS [ + /// Receive interrupt FIFO level select. The trigger points for the receive interrupt are as + /// follows. + RXIFLSEL OFFSET(3) NUMBITS(5) [ + OneEigth = 0b000, + OneQuarter = 0b001, + OneHalf = 0b010, + ThreeQuarters = 0b011, + SevenEights = 0b100 + ] + ], + + /// Interrupt Mask Set/Clear Register. + IMSC [ + /// Receive timeout interrupt mask. A read returns the current mask for the UARTRTINTR + /// interrupt. + /// + /// - On a write of 1, the mask of the UARTRTINTR interrupt is set. + /// - A write of 0 clears the mask. + RTIM OFFSET(6) NUMBITS(1) [ + Disabled = 0, + Enabled = 1 + ], + + /// Receive interrupt mask. A read returns the current mask for the UARTRXINTR interrupt. + /// + /// - On a write of 1, the mask of the UARTRXINTR interrupt is set. + /// - A write of 0 clears the mask. + RXIM OFFSET(4) NUMBITS(1) [ + Disabled = 0, + Enabled = 1 + ] + ], + + /// Masked Interrupt Status Register. + MIS [ + /// Receive timeout masked interrupt status. Returns the masked interrupt state of the + /// UARTRTINTR interrupt. + RTMIS OFFSET(6) NUMBITS(1) [], + + /// Receive masked interrupt status. Returns the masked interrupt state of the UARTRXINTR + /// interrupt. + RXMIS OFFSET(4) NUMBITS(1) [] + ], + + /// Interrupt Clear Register. + ICR [ + /// Meta field for all pending interrupts. + ALL OFFSET(0) NUMBITS(11) [] + ] +} + +register_structs! { + #[allow(non_snake_case)] + pub RegisterBlock { + (0x00 => DR: ReadWrite), + (0x04 => _reserved1), + (0x18 => FR: ReadOnly), + (0x1c => _reserved2), + (0x24 => IBRD: WriteOnly), + (0x28 => FBRD: WriteOnly), + (0x2c => LCR_H: WriteOnly), + (0x30 => CR: WriteOnly), + (0x34 => IFLS: ReadWrite), + (0x38 => IMSC: ReadWrite), + (0x3C => _reserved3), + (0x40 => MIS: ReadOnly), + (0x44 => ICR: WriteOnly), + (0x48 => @END), + } +} + +/// Abstraction for the associated MMIO registers. +type Registers = MMIODerefWrapper; + +#[derive(PartialEq)] +enum BlockingMode { + Blocking, + NonBlocking, +} + +struct PL011UartInner { + registers: Registers, + chars_written: usize, + chars_read: usize, +} + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +/// Representation of the UART. +pub struct PL011Uart { + inner: IRQSafeNullLock, + irq_number: bsp::device_driver::IRQNumber, + post_init_callback: fn(), +} + +//-------------------------------------------------------------------------------------------------- +// Private Code +//-------------------------------------------------------------------------------------------------- + +impl PL011UartInner { + /// Create an instance. + /// + /// # Safety + /// + /// - The user must ensure to provide a correct MMIO start address. + pub const unsafe fn new(mmio_start_addr: Address) -> Self { + Self { + registers: Registers::new(mmio_start_addr), + chars_written: 0, + chars_read: 0, + } + } + + /// Set up baud rate and characteristics. + /// + /// This results in 8N1 and 921_600 baud. + /// + /// The calculation for the BRD is (we set the clock to 48 MHz in config.txt): + /// `(48_000_000 / 16) / 921_600 = 3.2552083`. + /// + /// This means the integer part is `3` and goes into the `IBRD`. + /// The fractional part is `0.2552083`. + /// + /// `FBRD` calculation according to the PL011 Technical Reference Manual: + /// `INTEGER((0.2552083 * 64) + 0.5) = 16`. + /// + /// Therefore, the generated baud rate divider is: `3 + 16/64 = 3.25`. Which results in a + /// genrated baud rate of `48_000_000 / (16 * 3.25) = 923_077`. + /// + /// Error = `((923_077 - 921_600) / 921_600) * 100 = 0.16%`. + pub fn init(&mut self) { + // Execution can arrive here while there are still characters queued in the TX FIFO and + // actively being sent out by the UART hardware. If the UART is turned off in this case, + // those queued characters would be lost. + // + // For example, this can happen during runtime on a call to panic!(), because panic!() + // initializes its own UART instance and calls init(). + // + // Hence, flush first to ensure all pending characters are transmitted. + self.flush(); + + // Turn the UART off temporarily. + self.registers.CR.set(0); + + // Clear all pending interrupts. + self.registers.ICR.write(ICR::ALL::CLEAR); + + // From the PL011 Technical Reference Manual: + // + // The LCR_H, IBRD, and FBRD registers form the single 30-bit wide LCR Register that is + // updated on a single write strobe generated by a LCR_H write. So, to internally update the + // contents of IBRD or FBRD, a LCR_H write must always be performed at the end. + // + // Set the baud rate, 8N1 and FIFO enabled. + self.registers.IBRD.write(IBRD::BAUD_DIVINT.val(3)); + self.registers.FBRD.write(FBRD::BAUD_DIVFRAC.val(16)); + self.registers + .LCR_H + .write(LCR_H::WLEN::EightBit + LCR_H::FEN::FifosEnabled); + + // Set RX FIFO fill level at 1/8. + self.registers.IFLS.write(IFLS::RXIFLSEL::OneEigth); + + // Enable RX IRQ + RX timeout IRQ. + self.registers + .IMSC + .write(IMSC::RXIM::Enabled + IMSC::RTIM::Enabled); + + // Turn the UART on. + self.registers + .CR + .write(CR::UARTEN::Enabled + CR::TXE::Enabled + CR::RXE::Enabled); + } + + /// Send a character. + fn write_char(&mut self, c: char) { + // Spin while TX FIFO full is set, waiting for an empty slot. + while self.registers.FR.matches_all(FR::TXFF::SET) { + cpu::nop(); + } + + // Write the character to the buffer. + self.registers.DR.set(c as u32); + + self.chars_written += 1; + } + + /// Send a slice of characters. + fn write_array(&mut self, a: &[char]) { + for c in a { + self.write_char(*c); + } + } + + /// Block execution until the last buffered character has been physically put on the TX wire. + fn flush(&self) { + // Spin until the busy bit is cleared. + while self.registers.FR.matches_all(FR::BUSY::SET) { + cpu::nop(); + } + } + + /// Retrieve a character. + fn read_char_converting(&mut self, blocking_mode: BlockingMode) -> Option { + // If RX FIFO is empty, + if self.registers.FR.matches_all(FR::RXFE::SET) { + // immediately return in non-blocking mode. + if blocking_mode == BlockingMode::NonBlocking { + return None; + } + + // Otherwise, wait until a char was received. + while self.registers.FR.matches_all(FR::RXFE::SET) { + cpu::nop(); + } + } + + // Read one character. + let mut ret = self.registers.DR.get() as u8 as char; + + // Convert carrige return to newline. + if ret == '\r' { + ret = '\n' + } + + // Update statistics. + self.chars_read += 1; + + Some(ret) + } +} + +/// Implementing `core::fmt::Write` enables usage of the `format_args!` macros, which in turn are +/// used to implement the `kernel`'s `print!` and `println!` macros. By implementing `write_str()`, +/// we get `write_fmt()` automatically. +/// +/// The function takes an `&mut self`, so it must be implemented for the inner struct. +/// +/// See [`src/print.rs`]. +/// +/// [`src/print.rs`]: ../../print/index.html +impl fmt::Write for PL011UartInner { + fn write_str(&mut self, s: &str) -> fmt::Result { + for c in s.chars() { + self.write_char(c); + } + + Ok(()) + } +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +impl PL011Uart { + pub const COMPATIBLE: &'static str = "BCM PL011 UART"; + + /// Create an instance. + /// + /// # Safety + /// + /// - The user must ensure to provide a correct MMIO start address. + /// - The user must ensure to provide correct IRQ numbers. + pub const unsafe fn new( + mmio_start_addr: Address, + irq_number: bsp::device_driver::IRQNumber, + post_init_callback: fn(), + ) -> Self { + Self { + inner: IRQSafeNullLock::new(PL011UartInner::new(mmio_start_addr)), + irq_number, + post_init_callback, + } + } +} + +//------------------------------------------------------------------------------ +// OS Interface Code +//------------------------------------------------------------------------------ +use synchronization::interface::Mutex; + +impl driver::interface::DeviceDriver for PL011Uart { + fn compatible(&self) -> &'static str { + Self::COMPATIBLE + } + + unsafe fn init(&self) -> Result<(), &'static str> { + self.inner.lock(|inner| inner.init()); + (self.post_init_callback)(); + + Ok(()) + } + + fn register_and_enable_irq_handler(&'static self) -> Result<(), &'static str> { + use exception::asynchronous::{irq_manager, IRQDescriptor}; + + let descriptor = IRQDescriptor { + name: Self::COMPATIBLE, + handler: self, + }; + + irq_manager().register_handler(self.irq_number, descriptor)?; + irq_manager().enable(self.irq_number); + + Ok(()) + } +} + +impl console::interface::Write for PL011Uart { + /// Passthrough of `args` to the `core::fmt::Write` implementation, but guarded by a Mutex to + /// serialize access. + fn write_char(&self, c: char) { + self.inner.lock(|inner| inner.write_char(c)); + } + + fn write_array(&self, a: &[char]) { + self.inner.lock(|inner| inner.write_array(a)); + } + + fn write_fmt(&self, args: core::fmt::Arguments) -> fmt::Result { + // Fully qualified syntax for the call to `core::fmt::Write::write_fmt()` to increase + // readability. + self.inner.lock(|inner| fmt::Write::write_fmt(inner, args)) + } + + fn flush(&self) { + // Spin until TX FIFO empty is set. + self.inner.lock(|inner| inner.flush()); + } +} + +impl console::interface::Read for PL011Uart { + fn read_char(&self) -> char { + self.inner + .lock(|inner| inner.read_char_converting(BlockingMode::Blocking).unwrap()) + } + + fn clear_rx(&self) { + // Read from the RX FIFO until it is indicating empty. + while self + .inner + .lock(|inner| inner.read_char_converting(BlockingMode::NonBlocking)) + .is_some() + {} + } +} + +impl console::interface::Statistics for PL011Uart { + fn chars_written(&self) -> usize { + self.inner.lock(|inner| inner.chars_written) + } + + fn chars_read(&self) -> usize { + self.inner.lock(|inner| inner.chars_read) + } +} + +impl console::interface::All for PL011Uart {} + +impl exception::asynchronous::interface::IRQHandler for PL011Uart { + fn handle(&self) -> Result<(), &'static str> { + self.inner.lock(|inner| { + let pending = inner.registers.MIS.extract(); + + // Clear all pending IRQs. + inner.registers.ICR.write(ICR::ALL::CLEAR); + + // Check for any kind of RX interrupt. + if pending.matches_any(MIS::RXMIS::SET + MIS::RTMIS::SET) { + // Echo any received characters. + while let Some(c) = inner.read_char_converting(BlockingMode::NonBlocking) { + inner.write_char(c) + } + } + }); + + Ok(()) + } +} diff --git a/19_kernel_heap/kernel/src/bsp/device_driver/common.rs b/19_kernel_heap/kernel/src/bsp/device_driver/common.rs new file mode 100644 index 00000000..69f038d4 --- /dev/null +++ b/19_kernel_heap/kernel/src/bsp/device_driver/common.rs @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2020-2022 Andre Richter + +//! Common device driver code. + +use crate::memory::{Address, Virtual}; +use core::{marker::PhantomData, ops}; + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +pub struct MMIODerefWrapper { + start_addr: Address, + phantom: PhantomData T>, +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +impl MMIODerefWrapper { + /// Create an instance. + pub const unsafe fn new(start_addr: Address) -> Self { + Self { + start_addr, + phantom: PhantomData, + } + } +} + +impl ops::Deref for MMIODerefWrapper { + type Target = T; + + fn deref(&self) -> &Self::Target { + unsafe { &*(self.start_addr.as_usize() as *const _) } + } +} diff --git a/19_kernel_heap/kernel/src/bsp/raspberrypi.rs b/19_kernel_heap/kernel/src/bsp/raspberrypi.rs new file mode 100644 index 00000000..474419f4 --- /dev/null +++ b/19_kernel_heap/kernel/src/bsp/raspberrypi.rs @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2018-2022 Andre Richter + +//! Top-level BSP file for the Raspberry Pi 3 and 4. + +pub mod cpu; +pub mod driver; +pub mod exception; +pub mod memory; + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +/// Board identification. +pub fn board_name() -> &'static str { + #[cfg(feature = "bsp_rpi3")] + { + "Raspberry Pi 3" + } + + #[cfg(feature = "bsp_rpi4")] + { + "Raspberry Pi 4" + } +} diff --git a/19_kernel_heap/kernel/src/bsp/raspberrypi/cpu.rs b/19_kernel_heap/kernel/src/bsp/raspberrypi/cpu.rs new file mode 100644 index 00000000..85fb89e4 --- /dev/null +++ b/19_kernel_heap/kernel/src/bsp/raspberrypi/cpu.rs @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2018-2022 Andre Richter + +//! BSP Processor code. + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +/// Used by `arch` code to find the early boot core. +#[no_mangle] +#[link_section = ".text._start_arguments"] +pub static BOOT_CORE_ID: u64 = 0; diff --git a/19_kernel_heap/kernel/src/bsp/raspberrypi/driver.rs b/19_kernel_heap/kernel/src/bsp/raspberrypi/driver.rs new file mode 100644 index 00000000..3eb01f27 --- /dev/null +++ b/19_kernel_heap/kernel/src/bsp/raspberrypi/driver.rs @@ -0,0 +1,190 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2018-2022 Andre Richter + +//! BSP driver support. + +use super::{exception, memory::map::mmio}; +use crate::{ + bsp::device_driver, + console, driver, exception as generic_exception, memory, + memory::mmu::MMIODescriptor, + synchronization::{interface::ReadWriteEx, InitStateLock}, +}; +use alloc::vec::Vec; +use core::{ + mem::MaybeUninit, + sync::atomic::{AtomicBool, Ordering}, +}; +pub use device_driver::IRQNumber; + +//-------------------------------------------------------------------------------------------------- +// Private Definitions +//-------------------------------------------------------------------------------------------------- + +/// Device Driver Manager type. +struct BSPDriverManager { + device_drivers: InitStateLock>, + init_done: AtomicBool, +} + +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +static mut PL011_UART: MaybeUninit = MaybeUninit::uninit(); +static mut GPIO: MaybeUninit = MaybeUninit::uninit(); + +#[cfg(feature = "bsp_rpi3")] +static mut INTERRUPT_CONTROLLER: MaybeUninit = + MaybeUninit::uninit(); + +#[cfg(feature = "bsp_rpi4")] +static mut INTERRUPT_CONTROLLER: MaybeUninit = MaybeUninit::uninit(); + +static BSP_DRIVER_MANAGER: BSPDriverManager = BSPDriverManager { + device_drivers: InitStateLock::new(Vec::new()), + init_done: AtomicBool::new(false), +}; + +//-------------------------------------------------------------------------------------------------- +// Private Code +//-------------------------------------------------------------------------------------------------- + +impl BSPDriverManager { + unsafe fn instantiate_uart(&self) -> Result<(), &'static str> { + let mmio_descriptor = MMIODescriptor::new(mmio::PL011_UART_START, mmio::PL011_UART_SIZE); + let virt_addr = + memory::mmu::kernel_map_mmio(device_driver::PL011Uart::COMPATIBLE, &mmio_descriptor)?; + + // This is safe to do, because it is only called from the init'ed instance itself. + fn uart_post_init() { + console::register_console(unsafe { PL011_UART.assume_init_ref() }); + } + + PL011_UART.write(device_driver::PL011Uart::new( + virt_addr, + exception::asynchronous::irq_map::PL011_UART, + uart_post_init, + )); + + Ok(()) + } + + unsafe fn instantiate_gpio(&self) -> Result<(), &'static str> { + let mmio_descriptor = MMIODescriptor::new(mmio::GPIO_START, mmio::GPIO_SIZE); + let virt_addr = + memory::mmu::kernel_map_mmio(device_driver::GPIO::COMPATIBLE, &mmio_descriptor)?; + + // This is safe to do, because it is only called from the init'ed instance itself. + fn gpio_post_init() { + unsafe { GPIO.assume_init_ref().map_pl011_uart() }; + } + + GPIO.write(device_driver::GPIO::new(virt_addr, gpio_post_init)); + + Ok(()) + } + + #[cfg(feature = "bsp_rpi3")] + unsafe fn instantiate_interrupt_controller(&self) -> Result<(), &'static str> { + let periph_mmio_descriptor = + MMIODescriptor::new(mmio::PERIPHERAL_IC_START, mmio::PERIPHERAL_IC_SIZE); + let periph_virt_addr = memory::mmu::kernel_map_mmio( + device_driver::InterruptController::COMPATIBLE, + &periph_mmio_descriptor, + )?; + + // This is safe to do, because it is only called from the init'ed instance itself. + fn interrupt_controller_post_init() { + generic_exception::asynchronous::register_irq_manager(unsafe { + INTERRUPT_CONTROLLER.assume_init_ref() + }); + } + + INTERRUPT_CONTROLLER.write(device_driver::InterruptController::new( + periph_virt_addr, + interrupt_controller_post_init, + )); + + Ok(()) + } + + #[cfg(feature = "bsp_rpi4")] + unsafe fn instantiate_interrupt_controller(&self) -> Result<(), &'static str> { + let gicd_mmio_descriptor = MMIODescriptor::new(mmio::GICD_START, mmio::GICD_SIZE); + let gicd_virt_addr = memory::mmu::kernel_map_mmio("GICv2 GICD", &gicd_mmio_descriptor)?; + + let gicc_mmio_descriptor = MMIODescriptor::new(mmio::GICC_START, mmio::GICC_SIZE); + let gicc_virt_addr = memory::mmu::kernel_map_mmio("GICV2 GICC", &gicc_mmio_descriptor)?; + + // This is safe to do, because it is only called from the init'ed instance itself. + fn interrupt_controller_post_init() { + generic_exception::asynchronous::register_irq_manager(unsafe { + INTERRUPT_CONTROLLER.assume_init_ref() + }); + } + + INTERRUPT_CONTROLLER.write(device_driver::GICv2::new( + gicd_virt_addr, + gicc_virt_addr, + interrupt_controller_post_init, + )); + + Ok(()) + } + + unsafe fn register_drivers(&self) { + self.device_drivers.write(|drivers| { + drivers.push(PL011_UART.assume_init_ref()); + drivers.push(GPIO.assume_init_ref()); + drivers.push(INTERRUPT_CONTROLLER.assume_init_ref()); + }); + } +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +/// Return a reference to the driver manager. +pub fn driver_manager() -> &'static impl driver::interface::DriverManager { + &BSP_DRIVER_MANAGER +} + +//------------------------------------------------------------------------------ +// OS Interface Code +//------------------------------------------------------------------------------ +use driver::interface::DeviceDriver; + +impl driver::interface::DriverManager for BSPDriverManager { + unsafe fn instantiate_drivers(&self) -> Result<(), &'static str> { + if self.init_done.load(Ordering::Relaxed) { + return Err("Drivers already instantiated"); + } + + self.instantiate_uart()?; + self.instantiate_gpio()?; + self.instantiate_interrupt_controller()?; + + self.register_drivers(); + + self.init_done.store(true, Ordering::Relaxed); + Ok(()) + } + + fn all_device_drivers(&self) -> &Vec<&(dyn DeviceDriver + Sync)> { + self.device_drivers.read(|drivers| drivers) + } + + #[cfg(feature = "test_build")] + fn qemu_bring_up_console(&self) { + use crate::cpu; + + unsafe { + self.instantiate_uart() + .unwrap_or_else(|_| cpu::qemu_exit_failure()); + console::register_console(PL011_UART.assume_init_ref()); + }; + } +} diff --git a/19_kernel_heap/kernel/src/bsp/raspberrypi/exception.rs b/19_kernel_heap/kernel/src/bsp/raspberrypi/exception.rs new file mode 100644 index 00000000..aa6c5a63 --- /dev/null +++ b/19_kernel_heap/kernel/src/bsp/raspberrypi/exception.rs @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2020-2022 Andre Richter + +//! BSP synchronous and asynchronous exception handling. + +pub mod asynchronous; diff --git a/19_kernel_heap/kernel/src/bsp/raspberrypi/exception/asynchronous.rs b/19_kernel_heap/kernel/src/bsp/raspberrypi/exception/asynchronous.rs new file mode 100644 index 00000000..ab20d86d --- /dev/null +++ b/19_kernel_heap/kernel/src/bsp/raspberrypi/exception/asynchronous.rs @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2020-2022 Andre Richter + +//! BSP asynchronous exception handling. + +use crate::bsp; + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +#[cfg(feature = "bsp_rpi3")] +pub(in crate::bsp) mod irq_map { + use super::bsp::device_driver::{IRQNumber, PeripheralIRQ}; + + pub const PL011_UART: IRQNumber = IRQNumber::Peripheral(PeripheralIRQ::new(57)); +} + +#[cfg(feature = "bsp_rpi4")] +pub(in crate::bsp) mod irq_map { + use super::bsp::device_driver::IRQNumber; + + pub const PL011_UART: IRQNumber = IRQNumber::new(153); +} diff --git a/19_kernel_heap/kernel/src/bsp/raspberrypi/kernel.ld b/19_kernel_heap/kernel/src/bsp/raspberrypi/kernel.ld new file mode 100644 index 00000000..cbfbb5b5 --- /dev/null +++ b/19_kernel_heap/kernel/src/bsp/raspberrypi/kernel.ld @@ -0,0 +1,127 @@ +/* SPDX-License-Identifier: MIT OR Apache-2.0 + * + * Copyright (c) 2018-2022 Andre Richter + */ + +INCLUDE kernel_virt_addr_space_size.ld; + +PAGE_SIZE = 64K; +PAGE_MASK = PAGE_SIZE - 1; + +/* The kernel's virtual address range will be: + * + * [END_ADDRESS_INCLUSIVE, START_ADDRESS] + * [u64::MAX , (u64::MAX - __kernel_virt_addr_space_size) + 1] + */ +__kernel_virt_start_addr = ((0xffffffffffffffff - __kernel_virt_addr_space_size) + 1); + +__rpi_phys_dram_start_addr = 0; + +/* The physical address at which the the kernel binary will be loaded by the Raspberry's firmware */ +__rpi_phys_binary_load_addr = 0x80000; + + +ENTRY(__rpi_phys_binary_load_addr) + +/* Flags: + * 4 == R + * 5 == RX + * 6 == RW + * + * Segments are marked PT_LOAD below so that the ELF file provides virtual and physical addresses. + * It doesn't mean all of them need actually be loaded. + */ +PHDRS +{ + segment_code PT_LOAD FLAGS(5); + segment_data PT_LOAD FLAGS(6); + segment_heap PT_LOAD FLAGS(6); + segment_boot_core_stack PT_LOAD FLAGS(6); +} + +SECTIONS +{ + . = __kernel_virt_start_addr; + + ASSERT((. & PAGE_MASK) == 0, "Start of address space is not page aligned") + + /*********************************************************************************************** + * Code + RO Data + Global Offset Table + ***********************************************************************************************/ + __code_start = .; + .text : AT(__rpi_phys_binary_load_addr) + { + KEEP(*(.text._start)) + *(.text._start_arguments) /* Constants (or statics in Rust speak) read by _start(). */ + *(.text._start_rust) /* The Rust entry point */ + *(.text*) /* Everything else */ + } :segment_code + + .rodata : ALIGN(8) { *(.rodata*) } :segment_code + .got : ALIGN(8) { *(.got) } :segment_code + .kernel_symbols : ALIGN(8) { + __kernel_symbols_start = .; + . += 32 * 1024; + } :segment_code + + . = ALIGN(PAGE_SIZE); + __code_end_exclusive = .; + + /*********************************************************************************************** + * Data + BSS + ***********************************************************************************************/ + __data_start = .; + .data : { *(.data*) } :segment_data + + /* Section is zeroed in pairs of u64. Align start and end to 16 bytes */ + .bss (NOLOAD) : ALIGN(16) + { + __bss_start = .; + *(.bss*); + . = ALIGN(16); + __bss_end_exclusive = .; + } :segment_data + + . = ALIGN(PAGE_SIZE); + __data_end_exclusive = .; + + /*********************************************************************************************** + * Heap + ***********************************************************************************************/ + __heap_start = .; + .heap (NOLOAD) : + { + . += 16 * 1024 * 1024; + } :segment_heap + __heap_end_exclusive = .; + + ASSERT((. & PAGE_MASK) == 0, "Heap is not page aligned") + + /*********************************************************************************************** + * MMIO Remap Reserved + ***********************************************************************************************/ + __mmio_remap_start = .; + . += 8 * 1024 * 1024; + __mmio_remap_end_exclusive = .; + + ASSERT((. & PAGE_MASK) == 0, "MMIO remap reservation is not page aligned") + + /*********************************************************************************************** + * Guard Page + ***********************************************************************************************/ + . += PAGE_SIZE; + + /*********************************************************************************************** + * Boot Core Stack + ***********************************************************************************************/ + .boot_core_stack (NOLOAD) : AT(__rpi_phys_dram_start_addr) + { + __boot_core_stack_start = .; /* ^ */ + /* | stack */ + . += __rpi_phys_binary_load_addr; /* | growth */ + /* | direction */ + __boot_core_stack_end_exclusive = .; /* | */ + } :segment_boot_core_stack + + ASSERT((. & PAGE_MASK) == 0, "End of boot core stack is not page aligned") +} diff --git a/19_kernel_heap/kernel/src/bsp/raspberrypi/kernel_virt_addr_space_size.ld b/19_kernel_heap/kernel/src/bsp/raspberrypi/kernel_virt_addr_space_size.ld new file mode 100644 index 00000000..c5d58c30 --- /dev/null +++ b/19_kernel_heap/kernel/src/bsp/raspberrypi/kernel_virt_addr_space_size.ld @@ -0,0 +1 @@ +__kernel_virt_addr_space_size = 1024 * 1024 * 1024 diff --git a/19_kernel_heap/kernel/src/bsp/raspberrypi/memory.rs b/19_kernel_heap/kernel/src/bsp/raspberrypi/memory.rs new file mode 100644 index 00000000..760128d3 --- /dev/null +++ b/19_kernel_heap/kernel/src/bsp/raspberrypi/memory.rs @@ -0,0 +1,251 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2018-2022 Andre Richter + +//! BSP Memory Management. +//! +//! The physical memory layout. +//! +//! The Raspberry's firmware copies the kernel binary to 0x8_0000. The preceding region will be used +//! as the boot core's stack. +//! +//! +---------------------------------------+ +//! | | boot_core_stack_start @ 0x0 +//! | | ^ +//! | Boot-core Stack | | stack +//! | | | growth +//! | | | direction +//! +---------------------------------------+ +//! | | code_start @ 0x8_0000 == boot_core_stack_end_exclusive +//! | .text | +//! | .rodata | +//! | .got | +//! | .kernel_symbols | +//! | | +//! +---------------------------------------+ +//! | | data_start == code_end_exclusive +//! | .data | +//! | .bss | +//! | | +//! +---------------------------------------+ +//! | | heap_start == data_end_exclusive +//! | .heap | +//! | | +//! +---------------------------------------+ +//! | | heap_end_exclusive +//! | | +//! +//! +//! +//! +//! +//! The virtual memory layout is as follows: +//! +//! +---------------------------------------+ +//! | | code_start @ __kernel_virt_start_addr +//! | .text | +//! | .rodata | +//! | .got | +//! | .kernel_symbols | +//! | | +//! +---------------------------------------+ +//! | | data_start == code_end_exclusive +//! | .data | +//! | .bss | +//! | | +//! +---------------------------------------+ +//! | | heap_start == data_end_exclusive +//! | .heap | +//! | | +//! +---------------------------------------+ +//! | | mmio_remap_start == heap_end_exclusive +//! | VA region for MMIO remapping | +//! | | +//! +---------------------------------------+ +//! | | mmio_remap_end_exclusive +//! | Unmapped guard page | +//! | | +//! +---------------------------------------+ +//! | | boot_core_stack_start +//! | | ^ +//! | Boot-core Stack | | stack +//! | | | growth +//! | | | direction +//! +---------------------------------------+ +//! | | boot_core_stack_end_exclusive +//! | | +pub mod mmu; + +use crate::memory::{mmu::PageAddress, Address, Physical, Virtual}; +use core::cell::UnsafeCell; + +//-------------------------------------------------------------------------------------------------- +// Private Definitions +//-------------------------------------------------------------------------------------------------- + +// Symbols from the linker script. +extern "Rust" { + static __code_start: UnsafeCell<()>; + static __code_end_exclusive: UnsafeCell<()>; + + static __data_start: UnsafeCell<()>; + static __data_end_exclusive: UnsafeCell<()>; + + static __heap_start: UnsafeCell<()>; + static __heap_end_exclusive: UnsafeCell<()>; + + static __mmio_remap_start: UnsafeCell<()>; + static __mmio_remap_end_exclusive: UnsafeCell<()>; + + static __boot_core_stack_start: UnsafeCell<()>; + static __boot_core_stack_end_exclusive: UnsafeCell<()>; +} + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +/// The board's physical memory map. +#[rustfmt::skip] +pub(super) mod map { + use super::*; + + /// Physical devices. + #[cfg(feature = "bsp_rpi3")] + pub mod mmio { + use super::*; + + pub const PERIPHERAL_IC_START: Address = Address::new(0x3F00_B200); + pub const PERIPHERAL_IC_SIZE: usize = 0x24; + + pub const GPIO_START: Address = Address::new(0x3F20_0000); + pub const GPIO_SIZE: usize = 0xA0; + + pub const PL011_UART_START: Address = Address::new(0x3F20_1000); + pub const PL011_UART_SIZE: usize = 0x48; + + pub const END: Address = Address::new(0x4001_0000); + } + + /// Physical devices. + #[cfg(feature = "bsp_rpi4")] + pub mod mmio { + use super::*; + + pub const GPIO_START: Address = Address::new(0xFE20_0000); + pub const GPIO_SIZE: usize = 0xA0; + + pub const PL011_UART_START: Address = Address::new(0xFE20_1000); + pub const PL011_UART_SIZE: usize = 0x48; + + pub const GICD_START: Address = Address::new(0xFF84_1000); + pub const GICD_SIZE: usize = 0x824; + + pub const GICC_START: Address = Address::new(0xFF84_2000); + pub const GICC_SIZE: usize = 0x14; + + pub const END: Address = Address::new(0xFF85_0000); + } + + pub const END: Address = mmio::END; +} + +//-------------------------------------------------------------------------------------------------- +// Private Code +//-------------------------------------------------------------------------------------------------- + +/// Start page address of the code segment. +/// +/// # Safety +/// +/// - Value is provided by the linker script and must be trusted as-is. +#[inline(always)] +fn virt_code_start() -> PageAddress { + PageAddress::from(unsafe { __code_start.get() as usize }) +} + +/// Size of the code segment. +/// +/// # Safety +/// +/// - Value is provided by the linker script and must be trusted as-is. +#[inline(always)] +fn code_size() -> usize { + unsafe { (__code_end_exclusive.get() as usize) - (__code_start.get() as usize) } +} + +/// Start page address of the data segment. +#[inline(always)] +fn virt_data_start() -> PageAddress { + PageAddress::from(unsafe { __data_start.get() as usize }) +} + +/// Size of the data segment. +/// +/// # Safety +/// +/// - Value is provided by the linker script and must be trusted as-is. +#[inline(always)] +fn data_size() -> usize { + unsafe { (__data_end_exclusive.get() as usize) - (__data_start.get() as usize) } +} + +/// Start page address of the heap segment. +#[inline(always)] +fn virt_heap_start() -> PageAddress { + PageAddress::from(unsafe { __heap_start.get() as usize }) +} + +/// Size of the heap segment. +/// +/// # Safety +/// +/// - Value is provided by the linker script and must be trusted as-is. +#[inline(always)] +fn heap_size() -> usize { + unsafe { (__heap_end_exclusive.get() as usize) - (__heap_start.get() as usize) } +} + +/// Start page address of the MMIO remap reservation. +/// +/// # Safety +/// +/// - Value is provided by the linker script and must be trusted as-is. +#[inline(always)] +fn virt_mmio_remap_start() -> PageAddress { + PageAddress::from(unsafe { __mmio_remap_start.get() as usize }) +} + +/// Size of the MMIO remap reservation. +/// +/// # Safety +/// +/// - Value is provided by the linker script and must be trusted as-is. +#[inline(always)] +fn mmio_remap_size() -> usize { + unsafe { (__mmio_remap_end_exclusive.get() as usize) - (__mmio_remap_start.get() as usize) } +} + +/// Start page address of the boot core's stack. +#[inline(always)] +fn virt_boot_core_stack_start() -> PageAddress { + PageAddress::from(unsafe { __boot_core_stack_start.get() as usize }) +} + +/// Size of the boot core's stack. +#[inline(always)] +fn boot_core_stack_size() -> usize { + unsafe { + (__boot_core_stack_end_exclusive.get() as usize) - (__boot_core_stack_start.get() as usize) + } +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +/// Exclusive end address of the physical address space. +#[inline(always)] +pub fn phys_addr_space_end_exclusive_addr() -> PageAddress { + PageAddress::from(map::END) +} diff --git a/19_kernel_heap/kernel/src/bsp/raspberrypi/memory/mmu.rs b/19_kernel_heap/kernel/src/bsp/raspberrypi/memory/mmu.rs new file mode 100644 index 00000000..bb2f8208 --- /dev/null +++ b/19_kernel_heap/kernel/src/bsp/raspberrypi/memory/mmu.rs @@ -0,0 +1,197 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2018-2022 Andre Richter + +//! BSP Memory Management Unit. + +use crate::{ + memory::{ + mmu::{ + self as generic_mmu, AddressSpace, AssociatedTranslationTable, AttributeFields, + MemoryRegion, PageAddress, TranslationGranule, + }, + Physical, Virtual, + }, + synchronization::InitStateLock, +}; + +//-------------------------------------------------------------------------------------------------- +// Private Definitions +//-------------------------------------------------------------------------------------------------- + +type KernelTranslationTable = + ::TableStartFromTop; + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +/// The translation granule chosen by this BSP. This will be used everywhere else in the kernel to +/// derive respective data structures and their sizes. For example, the `crate::memory::mmu::Page`. +pub type KernelGranule = TranslationGranule<{ 64 * 1024 }>; + +/// The kernel's virtual address space defined by this BSP. +pub type KernelVirtAddrSpace = AddressSpace<{ kernel_virt_addr_space_size() }>; + +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +/// The kernel translation tables. +/// +/// It is mandatory that InitStateLock is transparent. +/// +/// That is, `size_of(InitStateLock) == size_of(KernelTranslationTable)`. +/// There is a unit tests that checks this porperty. +#[link_section = ".data"] +#[no_mangle] +static KERNEL_TABLES: InitStateLock = + InitStateLock::new(KernelTranslationTable::new_for_precompute()); + +/// This value is needed during early boot for MMU setup. +/// +/// This will be patched to the correct value by the "translation table tool" after linking. This +/// given value here is just a dummy. +#[link_section = ".text._start_arguments"] +#[no_mangle] +static PHYS_KERNEL_TABLES_BASE_ADDR: u64 = 0xCCCCAAAAFFFFEEEE; + +//-------------------------------------------------------------------------------------------------- +// Private Code +//-------------------------------------------------------------------------------------------------- + +/// This is a hack for retrieving the value for the kernel's virtual address space size as a +/// constant from a common place, since it is needed as a compile-time/link-time constant in both, +/// the linker script and the Rust sources. +#[allow(clippy::needless_late_init)] +const fn kernel_virt_addr_space_size() -> usize { + let __kernel_virt_addr_space_size; + + include!("../kernel_virt_addr_space_size.ld"); + + __kernel_virt_addr_space_size +} + +/// Helper function for calculating the number of pages the given parameter spans. +const fn size_to_num_pages(size: usize) -> usize { + assert!(size > 0); + assert!(size % KernelGranule::SIZE == 0); + + size >> KernelGranule::SHIFT +} + +/// The data pages of the kernel binary. +fn virt_data_region() -> MemoryRegion { + let num_pages = size_to_num_pages(super::data_size()); + + let start_page_addr = super::virt_data_start(); + let end_exclusive_page_addr = start_page_addr.checked_offset(num_pages as isize).unwrap(); + + MemoryRegion::new(start_page_addr, end_exclusive_page_addr) +} + +// There is no reason to expect the following conversions to fail, since they were generated offline +// by the `translation table tool`. If it doesn't work, a panic due to the unwraps is justified. +fn kernel_virt_to_phys_region(virt_region: MemoryRegion) -> MemoryRegion { + let phys_start_page_addr = + generic_mmu::try_kernel_virt_page_addr_to_phys_page_addr(virt_region.start_page_addr()) + .unwrap(); + + let phys_end_exclusive_page_addr = phys_start_page_addr + .checked_offset(virt_region.num_pages() as isize) + .unwrap(); + + MemoryRegion::new(phys_start_page_addr, phys_end_exclusive_page_addr) +} + +fn kernel_page_attributes(virt_page_addr: PageAddress) -> AttributeFields { + generic_mmu::try_kernel_page_attributes(virt_page_addr).unwrap() +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +/// The code pages of the kernel binary. +pub fn virt_code_region() -> MemoryRegion { + let num_pages = size_to_num_pages(super::code_size()); + + let start_page_addr = super::virt_code_start(); + let end_exclusive_page_addr = start_page_addr.checked_offset(num_pages as isize).unwrap(); + + MemoryRegion::new(start_page_addr, end_exclusive_page_addr) +} + +/// The heap pages. +pub fn virt_heap_region() -> MemoryRegion { + let num_pages = size_to_num_pages(super::heap_size()); + + let start_page_addr = super::virt_heap_start(); + let end_exclusive_page_addr = start_page_addr.checked_offset(num_pages as isize).unwrap(); + + MemoryRegion::new(start_page_addr, end_exclusive_page_addr) +} + +/// The boot core stack pages. +pub fn virt_boot_core_stack_region() -> MemoryRegion { + let num_pages = size_to_num_pages(super::boot_core_stack_size()); + + let start_page_addr = super::virt_boot_core_stack_start(); + let end_exclusive_page_addr = start_page_addr.checked_offset(num_pages as isize).unwrap(); + + MemoryRegion::new(start_page_addr, end_exclusive_page_addr) +} + +/// Return a reference to the kernel's translation tables. +pub fn kernel_translation_tables() -> &'static InitStateLock { + &KERNEL_TABLES +} + +/// The MMIO remap pages. +pub fn virt_mmio_remap_region() -> MemoryRegion { + let num_pages = size_to_num_pages(super::mmio_remap_size()); + + let start_page_addr = super::virt_mmio_remap_start(); + let end_exclusive_page_addr = start_page_addr.checked_offset(num_pages as isize).unwrap(); + + MemoryRegion::new(start_page_addr, end_exclusive_page_addr) +} + +/// Add mapping records for the kernel binary. +/// +/// The actual translation table entries for the kernel binary are generated using the offline +/// `translation table tool` and patched into the kernel binary. This function just adds the mapping +/// record entries. +pub fn kernel_add_mapping_records_for_precomputed() { + let virt_code_region = virt_code_region(); + generic_mmu::kernel_add_mapping_record( + "Kernel code and RO data", + &virt_code_region, + &kernel_virt_to_phys_region(virt_code_region), + &kernel_page_attributes(virt_code_region.start_page_addr()), + ); + + let virt_data_region = virt_data_region(); + generic_mmu::kernel_add_mapping_record( + "Kernel data and bss", + &virt_data_region, + &kernel_virt_to_phys_region(virt_data_region), + &kernel_page_attributes(virt_data_region.start_page_addr()), + ); + + let virt_heap_region = virt_heap_region(); + generic_mmu::kernel_add_mapping_record( + "Kernel heap", + &virt_heap_region, + &kernel_virt_to_phys_region(virt_heap_region), + &kernel_page_attributes(virt_heap_region.start_page_addr()), + ); + + let virt_boot_core_stack_region = virt_boot_core_stack_region(); + generic_mmu::kernel_add_mapping_record( + "Kernel boot-core stack", + &virt_boot_core_stack_region, + &kernel_virt_to_phys_region(virt_boot_core_stack_region), + &kernel_page_attributes(virt_boot_core_stack_region.start_page_addr()), + ); +} diff --git a/19_kernel_heap/kernel/src/common.rs b/19_kernel_heap/kernel/src/common.rs new file mode 100644 index 00000000..f32f650f --- /dev/null +++ b/19_kernel_heap/kernel/src/common.rs @@ -0,0 +1,46 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2020-2022 Andre Richter + +//! General purpose code. + +/// Check if a value is aligned to a given size. +#[inline(always)] +pub const fn is_aligned(value: usize, alignment: usize) -> bool { + assert!(alignment.is_power_of_two()); + + (value & (alignment - 1)) == 0 +} + +/// Align down. +#[inline(always)] +pub const fn align_down(value: usize, alignment: usize) -> usize { + assert!(alignment.is_power_of_two()); + + value & !(alignment - 1) +} + +/// Align up. +#[inline(always)] +pub const fn align_up(value: usize, alignment: usize) -> usize { + assert!(alignment.is_power_of_two()); + + (value + alignment - 1) & !(alignment - 1) +} + +/// Convert a size into human readable format. +pub const fn size_human_readable_ceil(size: usize) -> (usize, &'static str) { + const KIB: usize = 1024; + const MIB: usize = 1024 * 1024; + const GIB: usize = 1024 * 1024 * 1024; + + if (size / GIB) > 0 { + (size.div_ceil(GIB), "GiB") + } else if (size / MIB) > 0 { + (size.div_ceil(MIB), "MiB") + } else if (size / KIB) > 0 { + (size.div_ceil(KIB), "KiB") + } else { + (size, "Byte") + } +} diff --git a/19_kernel_heap/kernel/src/console.rs b/19_kernel_heap/kernel/src/console.rs new file mode 100644 index 00000000..20a89cd7 --- /dev/null +++ b/19_kernel_heap/kernel/src/console.rs @@ -0,0 +1,93 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2018-2022 Andre Richter + +//! System console. + +mod buffer_console; + +use crate::synchronization; + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +/// Console interfaces. +pub mod interface { + use core::fmt; + + /// Console write functions. + pub trait Write { + /// Write a single character. + fn write_char(&self, c: char); + + /// Write a slice of characters. + fn write_array(&self, a: &[char]); + + /// Write a Rust format string. + fn write_fmt(&self, args: fmt::Arguments) -> fmt::Result; + + /// Block until the last buffered character has been physically put on the TX wire. + fn flush(&self); + } + + /// Console read functions. + pub trait Read { + /// Read a single character. + fn read_char(&self) -> char { + ' ' + } + + /// Clear RX buffers, if any. + fn clear_rx(&self); + } + + /// Console statistics. + pub trait Statistics { + /// Return the number of characters written. + fn chars_written(&self) -> usize { + 0 + } + + /// Return the number of characters read. + fn chars_read(&self) -> usize { + 0 + } + } + + /// Trait alias for a full-fledged console. + pub trait All: Write + Read + Statistics {} +} + +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +static CUR_CONSOLE: InitStateLock<&'static (dyn interface::All + Sync)> = + InitStateLock::new(&buffer_console::BUFFER_CONSOLE); + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- +use synchronization::{interface::ReadWriteEx, InitStateLock}; + +/// Register a new console. +pub fn register_console(new_console: &'static (dyn interface::All + Sync)) { + CUR_CONSOLE.write(|con| *con = new_console); + + static FIRST_SWITCH: InitStateLock = InitStateLock::new(true); + FIRST_SWITCH.write(|first| { + if *first == true { + *first = false; + + buffer_console::BUFFER_CONSOLE.dump(); + } + }); +} + +/// Return a reference to the currently registered console. +/// +/// This is the global console used by all printing macros. +pub fn console() -> &'static dyn interface::All { + CUR_CONSOLE.read(|con| *con) +} diff --git a/19_kernel_heap/kernel/src/console/buffer_console.rs b/19_kernel_heap/kernel/src/console/buffer_console.rs new file mode 100644 index 00000000..c3259f89 --- /dev/null +++ b/19_kernel_heap/kernel/src/console/buffer_console.rs @@ -0,0 +1,108 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2022 Andre Richter + +//! A console that buffers input during the init phase. + +use super::interface; +use crate::{console, info, synchronization, synchronization::InitStateLock}; +use core::fmt; + +//-------------------------------------------------------------------------------------------------- +// Private Definitions +//-------------------------------------------------------------------------------------------------- + +const BUF_SIZE: usize = 1024 * 64; + +pub struct BufferConsoleInner { + buf: [char; BUF_SIZE], + write_ptr: usize, +} + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +pub struct BufferConsole { + inner: InitStateLock, +} + +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +pub static BUFFER_CONSOLE: BufferConsole = BufferConsole { + inner: InitStateLock::new(BufferConsoleInner { + // Use the null character, so this lands in .bss and does not waste space in the binary. + buf: ['\0'; BUF_SIZE], + write_ptr: 0, + }), +}; + +//-------------------------------------------------------------------------------------------------- +// Private Code +//-------------------------------------------------------------------------------------------------- + +impl BufferConsoleInner { + fn write_char(&mut self, c: char) { + if self.write_ptr < (BUF_SIZE - 1) { + self.buf[self.write_ptr] = c; + self.write_ptr += 1; + } + } +} + +impl fmt::Write for BufferConsoleInner { + fn write_str(&mut self, s: &str) -> fmt::Result { + for c in s.chars() { + self.write_char(c); + } + + Ok(()) + } +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- +use synchronization::interface::ReadWriteEx; + +impl BufferConsole { + /// Dump the buffer. + /// + /// # Invariant + /// + /// It is expected that this is only called when self != crate::console::console(). + pub fn dump(&self) { + self.inner.read(|inner| { + console::console().write_array(&inner.buf[0..inner.write_ptr]); + + if inner.write_ptr == (BUF_SIZE - 1) { + info!("Pre-UART buffer overflowed"); + } else if inner.write_ptr > 0 { + info!("End of pre-UART buffer") + } + }); + } +} + +impl interface::Write for BufferConsole { + fn write_char(&self, c: char) { + self.inner.write(|inner| inner.write_char(c)); + } + + fn write_array(&self, _a: &[char]) {} + + fn write_fmt(&self, args: fmt::Arguments) -> fmt::Result { + self.inner.write(|inner| fmt::Write::write_fmt(inner, args)) + } + + fn flush(&self) {} +} + +impl interface::Read for BufferConsole { + fn clear_rx(&self) {} +} + +impl interface::Statistics for BufferConsole {} +impl interface::All for BufferConsole {} diff --git a/19_kernel_heap/kernel/src/cpu.rs b/19_kernel_heap/kernel/src/cpu.rs new file mode 100644 index 00000000..e1493d1d --- /dev/null +++ b/19_kernel_heap/kernel/src/cpu.rs @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2020-2022 Andre Richter + +//! Processor code. + +#[cfg(target_arch = "aarch64")] +#[path = "_arch/aarch64/cpu.rs"] +mod arch_cpu; + +mod boot; + +pub mod smp; + +//-------------------------------------------------------------------------------------------------- +// Architectural Public Reexports +//-------------------------------------------------------------------------------------------------- +pub use arch_cpu::{nop, wait_forever}; + +#[cfg(feature = "test_build")] +pub use arch_cpu::{qemu_exit_failure, qemu_exit_success}; diff --git a/19_kernel_heap/kernel/src/cpu/boot.rs b/19_kernel_heap/kernel/src/cpu/boot.rs new file mode 100644 index 00000000..8091dac3 --- /dev/null +++ b/19_kernel_heap/kernel/src/cpu/boot.rs @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2021-2022 Andre Richter + +//! Boot code. + +#[cfg(target_arch = "aarch64")] +#[path = "../_arch/aarch64/cpu/boot.rs"] +mod arch_boot; diff --git a/19_kernel_heap/kernel/src/cpu/smp.rs b/19_kernel_heap/kernel/src/cpu/smp.rs new file mode 100644 index 00000000..57386f79 --- /dev/null +++ b/19_kernel_heap/kernel/src/cpu/smp.rs @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2018-2022 Andre Richter + +//! Symmetric multiprocessing. + +#[cfg(target_arch = "aarch64")] +#[path = "../_arch/aarch64/cpu/smp.rs"] +mod arch_smp; + +//-------------------------------------------------------------------------------------------------- +// Architectural Public Reexports +//-------------------------------------------------------------------------------------------------- +pub use arch_smp::core_id; diff --git a/19_kernel_heap/kernel/src/driver.rs b/19_kernel_heap/kernel/src/driver.rs new file mode 100644 index 00000000..d884d471 --- /dev/null +++ b/19_kernel_heap/kernel/src/driver.rs @@ -0,0 +1,57 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2018-2022 Andre Richter + +//! Driver support. + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +/// Driver interfaces. +pub mod interface { + use alloc::vec::Vec; + + /// Device Driver functions. + pub trait DeviceDriver { + /// Return a compatibility string for identifying the driver. + fn compatible(&self) -> &'static str; + + /// Called by the kernel to bring up the device. + /// + /// # Safety + /// + /// - During init, drivers might do stuff with system-wide impact. + unsafe fn init(&self) -> Result<(), &'static str> { + Ok(()) + } + + /// Called by the kernel to register and enable the device's IRQ handlers, if any. + /// + /// Rust's type system will prevent a call to this function unless the calling instance + /// itself has static lifetime. + fn register_and_enable_irq_handler(&'static self) -> Result<(), &'static str> { + Ok(()) + } + } + + /// Device driver management functions. + /// + /// The `BSP` is supposed to supply one global instance. + pub trait DriverManager { + /// Instantiate all drivers. + /// + /// # Safety + /// + /// Must be called before `all_device_drivers`. + unsafe fn instantiate_drivers(&self) -> Result<(), &'static str>; + + /// Return a vector of references to all `BSP`-instantiated drivers. + fn all_device_drivers(&self) -> &Vec<&(dyn DeviceDriver + Sync)>; + + /// Minimal code needed to bring up the console in QEMU (for testing only). This is often + /// less steps than on real hardware due to QEMU's abstractions. + #[cfg(feature = "test_build")] + fn qemu_bring_up_console(&self); + } +} diff --git a/19_kernel_heap/kernel/src/exception.rs b/19_kernel_heap/kernel/src/exception.rs new file mode 100644 index 00000000..f4af8144 --- /dev/null +++ b/19_kernel_heap/kernel/src/exception.rs @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2020-2022 Andre Richter + +//! Synchronous and asynchronous exception handling. + +#[cfg(target_arch = "aarch64")] +#[path = "_arch/aarch64/exception.rs"] +mod arch_exception; + +pub mod asynchronous; + +//-------------------------------------------------------------------------------------------------- +// Architectural Public Reexports +//-------------------------------------------------------------------------------------------------- +pub use arch_exception::{current_privilege_level, handling_init}; + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +/// Kernel privilege levels. +#[allow(missing_docs)] +#[derive(PartialEq)] +pub enum PrivilegeLevel { + User, + Kernel, + Hypervisor, + Unknown, +} + +//-------------------------------------------------------------------------------------------------- +// Testing +//-------------------------------------------------------------------------------------------------- + +#[cfg(test)] +mod tests { + use super::*; + use test_macros::kernel_test; + + /// Libkernel unit tests must execute in kernel mode. + #[kernel_test] + fn test_runner_executes_in_kernel_mode() { + let (level, _) = current_privilege_level(); + + assert!(level == PrivilegeLevel::Kernel) + } +} diff --git a/19_kernel_heap/kernel/src/exception/asynchronous.rs b/19_kernel_heap/kernel/src/exception/asynchronous.rs new file mode 100644 index 00000000..d9d2767c --- /dev/null +++ b/19_kernel_heap/kernel/src/exception/asynchronous.rs @@ -0,0 +1,178 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2020-2022 Andre Richter + +//! Asynchronous exception handling. + +#[cfg(target_arch = "aarch64")] +#[path = "../_arch/aarch64/exception/asynchronous.rs"] +mod arch_asynchronous; +mod null_irq_manager; + +use crate::{bsp, synchronization}; +use core::{fmt, marker::PhantomData}; + +//-------------------------------------------------------------------------------------------------- +// Architectural Public Reexports +//-------------------------------------------------------------------------------------------------- +pub use arch_asynchronous::{ + is_local_irq_masked, local_irq_mask, local_irq_mask_save, local_irq_restore, local_irq_unmask, + print_state, +}; + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +/// Interrupt descriptor. +#[derive(Copy, Clone)] +pub struct IRQDescriptor { + /// Descriptive name. + pub name: &'static str, + + /// Reference to handler trait object. + pub handler: &'static (dyn interface::IRQHandler + Sync), +} + +/// IRQContext token. +/// +/// An instance of this type indicates that the local core is currently executing in IRQ +/// context, aka executing an interrupt vector or subcalls of it. +/// +/// Concept and implementation derived from the `CriticalSection` introduced in +/// +#[derive(Clone, Copy)] +pub struct IRQContext<'irq_context> { + _0: PhantomData<&'irq_context ()>, +} + +/// Asynchronous exception handling interfaces. +pub mod interface { + + /// Implemented by types that handle IRQs. + pub trait IRQHandler { + /// Called when the corresponding interrupt is asserted. + fn handle(&self) -> Result<(), &'static str>; + } + + /// IRQ management functions. + /// + /// The `BSP` is supposed to supply one global instance. Typically implemented by the + /// platform's interrupt controller. + pub trait IRQManager { + /// The IRQ number type depends on the implementation. + type IRQNumberType; + + /// Register a handler. + fn register_handler( + &self, + irq_number: Self::IRQNumberType, + descriptor: super::IRQDescriptor, + ) -> Result<(), &'static str>; + + /// Enable an interrupt in the controller. + fn enable(&self, irq_number: Self::IRQNumberType); + + /// Handle pending interrupts. + /// + /// This function is called directly from the CPU's IRQ exception vector. On AArch64, + /// this means that the respective CPU core has disabled exception handling. + /// This function can therefore not be preempted and runs start to finish. + /// + /// Takes an IRQContext token to ensure it can only be called from IRQ context. + #[allow(clippy::trivially_copy_pass_by_ref)] + fn handle_pending_irqs<'irq_context>( + &'irq_context self, + ic: &super::IRQContext<'irq_context>, + ); + + /// Print list of registered handlers. + fn print_handler(&self) {} + } +} + +/// A wrapper type for IRQ numbers with integrated range sanity check. +#[derive(Copy, Clone)] +pub struct IRQNumber(usize); + +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +static CUR_IRQ_MANAGER: InitStateLock< + &'static (dyn interface::IRQManager + Sync), +> = InitStateLock::new(&null_irq_manager::NULL_IRQ_MANAGER); + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- +use synchronization::{interface::ReadWriteEx, InitStateLock}; + +impl<'irq_context> IRQContext<'irq_context> { + /// Creates an IRQContext token. + /// + /// # Safety + /// + /// - This must only be called when the current core is in an interrupt context and will not + /// live beyond the end of it. That is, creation is allowed in interrupt vector functions. For + /// example, in the ARMv8-A case, in `extern "C" fn current_elx_irq()`. + /// - Note that the lifetime `'irq_context` of the returned instance is unconstrained. User code + /// must not be able to influence the lifetime picked for this type, since that might cause it + /// to be inferred to `'static`. + #[inline(always)] + pub unsafe fn new() -> Self { + IRQContext { _0: PhantomData } + } +} + +impl IRQNumber<{ MAX_INCLUSIVE }> { + /// Creates a new instance if number <= MAX_INCLUSIVE. + pub const fn new(number: usize) -> Self { + assert!(number <= MAX_INCLUSIVE); + + Self(number) + } + + /// Return the wrapped number. + pub const fn get(self) -> usize { + self.0 + } +} + +impl fmt::Display for IRQNumber<{ MAX_INCLUSIVE }> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.0) + } +} + +/// Executes the provided closure while IRQs are masked on the executing core. +/// +/// While the function temporarily changes the HW state of the executing core, it restores it to the +/// previous state before returning, so this is deemed safe. +#[inline(always)] +pub fn exec_with_irq_masked(f: impl FnOnce() -> T) -> T { + let ret: T; + + unsafe { + let saved = local_irq_mask_save(); + ret = f(); + local_irq_restore(saved); + } + + ret +} + +/// Register a new IRQ manager. +pub fn register_irq_manager( + new_manager: &'static (dyn interface::IRQManager + + Sync), +) { + CUR_IRQ_MANAGER.write(|manager| *manager = new_manager); +} + +/// Return a reference to the currently registered IRQ manager. +/// +/// This is the IRQ manager used by the architectural interrupt handling code. +pub fn irq_manager() -> &'static dyn interface::IRQManager { + CUR_IRQ_MANAGER.read(|manager| *manager) +} diff --git a/19_kernel_heap/kernel/src/exception/asynchronous/null_irq_manager.rs b/19_kernel_heap/kernel/src/exception/asynchronous/null_irq_manager.rs new file mode 100644 index 00000000..560e3ce4 --- /dev/null +++ b/19_kernel_heap/kernel/src/exception/asynchronous/null_irq_manager.rs @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2022 Andre Richter + +//! Null IRQ Manager. + +use super::{interface, IRQContext, IRQDescriptor}; +use crate::bsp; + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +pub struct NullIRQManager; + +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +pub static NULL_IRQ_MANAGER: NullIRQManager = NullIRQManager {}; + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +impl interface::IRQManager for NullIRQManager { + type IRQNumberType = bsp::driver::IRQNumber; + + fn register_handler( + &self, + _irq_number: Self::IRQNumberType, + _descriptor: IRQDescriptor, + ) -> Result<(), &'static str> { + panic!("No IRQ Manager registered yet"); + } + + fn enable(&self, _irq_number: Self::IRQNumberType) { + panic!("No IRQ Manager registered yet"); + } + + fn handle_pending_irqs<'irq_context>(&'irq_context self, _ic: &IRQContext<'irq_context>) { + panic!("No IRQ Manager registered yet"); + } +} diff --git a/19_kernel_heap/kernel/src/lib.rs b/19_kernel_heap/kernel/src/lib.rs new file mode 100644 index 00000000..20dc3bfd --- /dev/null +++ b/19_kernel_heap/kernel/src/lib.rs @@ -0,0 +1,195 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2018-2022 Andre Richter + +// Rust embedded logo for `make doc`. +#![doc( + html_logo_url = "https://raw.githubusercontent.com/rust-embedded/wg/master/assets/logo/ewg-logo-blue-white-on-transparent.png" +)] + +//! The `kernel` library. +//! +//! Used to compose the final kernel binary. +//! +//! # Code organization and architecture +//! +//! The code is divided into different *modules*, each representing a typical **subsystem** of the +//! `kernel`. Top-level module files of subsystems reside directly in the `src` folder. For example, +//! `src/memory.rs` contains code that is concerned with all things memory management. +//! +//! ## Visibility of processor architecture code +//! +//! Some of the `kernel`'s subsystems depend on low-level code that is specific to the target +//! processor architecture. For each supported processor architecture, there exists a subfolder in +//! `src/_arch`, for example, `src/_arch/aarch64`. +//! +//! The architecture folders mirror the subsystem modules laid out in `src`. For example, +//! architectural code that belongs to the `kernel`'s MMU subsystem (`src/memory/mmu.rs`) would go +//! into `src/_arch/aarch64/memory/mmu.rs`. The latter file is loaded as a module in +//! `src/memory/mmu.rs` using the `path attribute`. Usually, the chosen module name is the generic +//! module's name prefixed with `arch_`. +//! +//! For example, this is the top of `src/memory/mmu.rs`: +//! +//! ``` +//! #[cfg(target_arch = "aarch64")] +//! #[path = "../_arch/aarch64/memory/mmu.rs"] +//! mod arch_mmu; +//! ``` +//! +//! Often times, items from the `arch_ module` will be publicly reexported by the parent module. +//! This way, each architecture specific module can provide its implementation of an item, while the +//! caller must not be concerned which architecture has been conditionally compiled. +//! +//! ## BSP code +//! +//! `BSP` stands for Board Support Package. `BSP` code is organized under `src/bsp.rs` and contains +//! target board specific definitions and functions. These are things such as the board's memory map +//! or instances of drivers for devices that are featured on the respective board. +//! +//! Just like processor architecture code, the `BSP` code's module structure tries to mirror the +//! `kernel`'s subsystem modules, but there is no reexporting this time. That means whatever is +//! provided must be called starting from the `bsp` namespace, e.g. `bsp::driver::driver_manager()`. +//! +//! ## Kernel interfaces +//! +//! Both `arch` and `bsp` contain code that is conditionally compiled depending on the actual target +//! and board for which the kernel is compiled. For example, the `interrupt controller` hardware of +//! the `Raspberry Pi 3` and the `Raspberry Pi 4` is different, but we want the rest of the `kernel` +//! code to play nicely with any of the two without much hassle. +//! +//! In order to provide a clean abstraction between `arch`, `bsp` and `generic kernel code`, +//! `interface` traits are provided *whenever possible* and *where it makes sense*. They are defined +//! in the respective subsystem module and help to enforce the idiom of *program to an interface, +//! not an implementation*. For example, there will be a common IRQ handling interface which the two +//! different interrupt controller `drivers` of both Raspberrys will implement, and only export the +//! interface to the rest of the `kernel`. +//! +//! ``` +//! +-------------------+ +//! | Interface (Trait) | +//! | | +//! +--+-------------+--+ +//! ^ ^ +//! | | +//! | | +//! +----------+--+ +--+----------+ +//! | kernel code | | bsp code | +//! | | | arch code | +//! +-------------+ +-------------+ +//! ``` +//! +//! # Summary +//! +//! For a logical `kernel` subsystem, corresponding code can be distributed over several physical +//! locations. Here is an example for the **memory** subsystem: +//! +//! - `src/memory.rs` and `src/memory/**/*` +//! - Common code that is agnostic of target processor architecture and `BSP` characteristics. +//! - Example: A function to zero a chunk of memory. +//! - Interfaces for the memory subsystem that are implemented by `arch` or `BSP` code. +//! - Example: An `MMU` interface that defines `MMU` function prototypes. +//! - `src/bsp/__board_name__/memory.rs` and `src/bsp/__board_name__/memory/**/*` +//! - `BSP` specific code. +//! - Example: The board's memory map (physical addresses of DRAM and MMIO devices). +//! - `src/_arch/__arch_name__/memory.rs` and `src/_arch/__arch_name__/memory/**/*` +//! - Processor architecture specific code. +//! - Example: Implementation of the `MMU` interface for the `__arch_name__` processor +//! architecture. +//! +//! From a namespace perspective, **memory** subsystem code lives in: +//! +//! - `crate::memory::*` +//! - `crate::bsp::memory::*` +//! +//! # Boot flow +//! +//! 1. The kernel's entry point is the function `cpu::boot::arch_boot::_start()`. +//! - It is implemented in `src/_arch/__arch_name__/cpu/boot.s`. +//! 2. Once finished with architectural setup, the arch code calls `kernel_init()`. + +#![allow(clippy::upper_case_acronyms)] +#![allow(incomplete_features)] +#![feature(alloc_error_handler)] +#![feature(asm_const)] +#![feature(core_intrinsics)] +#![feature(format_args_nl)] +#![feature(generic_const_exprs)] +#![feature(int_roundings)] +#![feature(is_sorted)] +#![feature(linkage)] +#![feature(panic_info_message)] +#![feature(step_trait)] +#![feature(trait_alias)] +#![no_std] +// Testing +#![cfg_attr(test, no_main)] +#![feature(custom_test_frameworks)] +#![reexport_test_harness_main = "test_main"] +#![test_runner(crate::test_runner)] + +extern crate alloc; + +mod panic_wait; +mod synchronization; + +pub mod backtrace; +pub mod bsp; +pub mod common; +pub mod console; +pub mod cpu; +pub mod driver; +pub mod exception; +pub mod memory; +pub mod print; +pub mod state; +pub mod symbols; +pub mod time; + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +/// Version string. +pub fn version() -> &'static str { + concat!( + env!("CARGO_PKG_NAME"), + " version ", + env!("CARGO_PKG_VERSION") + ) +} + +//-------------------------------------------------------------------------------------------------- +// Testing +//-------------------------------------------------------------------------------------------------- + +/// The default runner for unit tests. +pub fn test_runner(tests: &[&test_types::UnitTest]) { + // This line will be printed as the test header. + println!("Running {} tests", tests.len()); + + for (i, test) in tests.iter().enumerate() { + print!("{:>3}. {:.<58}", i + 1, test.name); + + // Run the actual test. + (test.test_func)(); + + // Failed tests call panic!(). Execution reaches here only if the test has passed. + println!("[ok]") + } +} + +/// The `kernel_init()` for unit tests. +#[cfg(test)] +#[no_mangle] +unsafe fn kernel_init() -> ! { + use driver::interface::DriverManager; + + exception::handling_init(); + memory::init(); + bsp::driver::driver_manager().qemu_bring_up_console(); + + test_main(); + + cpu::qemu_exit_success() +} diff --git a/19_kernel_heap/kernel/src/main.rs b/19_kernel_heap/kernel/src/main.rs new file mode 100644 index 00000000..d2044c29 --- /dev/null +++ b/19_kernel_heap/kernel/src/main.rs @@ -0,0 +1,102 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2018-2022 Andre Richter + +// Rust embedded logo for `make doc`. +#![doc( + html_logo_url = "https://raw.githubusercontent.com/rust-embedded/wg/master/assets/logo/ewg-logo-blue-white-on-transparent.png" +)] + +//! The `kernel` binary. + +#![feature(format_args_nl)] +#![no_main] +#![no_std] + +extern crate alloc; + +use libkernel::{bsp, cpu, driver, exception, info, memory, state, time, warn}; + +/// Early init code. +/// +/// When this code runs, virtual memory is already enabled. +/// +/// # Safety +/// +/// - Only a single core must be active and running this function. +/// - Printing will not work until the respective driver's MMIO is remapped. +#[no_mangle] +unsafe fn kernel_init() -> ! { + use driver::interface::DriverManager; + + exception::handling_init(); + memory::init(); + + // Instantiate and init all device drivers. + if let Err(x) = bsp::driver::driver_manager().instantiate_drivers() { + panic!("Error instantiating drivers: {}", x); + } + for i in bsp::driver::driver_manager().all_device_drivers().iter() { + if let Err(x) = i.init() { + panic!("Error loading driver: {}: {}", i.compatible(), x); + } + } + + // Let device drivers register and enable their handlers with the interrupt controller. + for i in bsp::driver::driver_manager().all_device_drivers() { + if let Err(msg) = i.register_and_enable_irq_handler() { + warn!("Error registering IRQ handler: {}", msg); + } + } + + bsp::memory::mmu::kernel_add_mapping_records_for_precomputed(); + + // Unmask interrupts on the boot CPU core. + exception::asynchronous::local_irq_unmask(); + + // Announce conclusion of the kernel_init() phase. + state::state_manager().transition_to_single_core_main(); + + // Transition from unsafe to safe. + kernel_main() +} + +/// The main function running after the early init. +fn kernel_main() -> ! { + use driver::interface::DriverManager; + + info!("{}", libkernel::version()); + info!("Booting on: {}", bsp::board_name()); + + info!("MMU online:"); + memory::mmu::kernel_print_mappings(); + + let (_, privilege_level) = exception::current_privilege_level(); + info!("Current privilege level: {}", privilege_level); + + info!("Exception handling state:"); + exception::asynchronous::print_state(); + + info!( + "Architectural timer resolution: {} ns", + time::time_manager().resolution().as_nanos() + ); + + info!("Drivers loaded:"); + for (i, driver) in bsp::driver::driver_manager() + .all_device_drivers() + .iter() + .enumerate() + { + info!(" {}. {}", i + 1, driver.compatible()); + } + + info!("Registered IRQ handlers:"); + exception::asynchronous::irq_manager().print_handler(); + + info!("Kernel heap:"); + memory::heap_alloc::kernel_heap_allocator().print_usage(); + + info!("Echoing input now"); + cpu::wait_forever(); +} diff --git a/19_kernel_heap/kernel/src/memory.rs b/19_kernel_heap/kernel/src/memory.rs new file mode 100644 index 00000000..a64bfbae --- /dev/null +++ b/19_kernel_heap/kernel/src/memory.rs @@ -0,0 +1,198 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2018-2022 Andre Richter + +//! Memory Management. + +pub mod heap_alloc; +pub mod mmu; + +use crate::{bsp, common}; +use core::{ + fmt, + marker::PhantomData, + ops::{Add, Sub}, +}; + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +/// Metadata trait for marking the type of an address. +pub trait AddressType: Copy + Clone + PartialOrd + PartialEq + Ord + Eq {} + +/// Zero-sized type to mark a physical address. +#[derive(Copy, Clone, Debug, PartialOrd, PartialEq, Ord, Eq)] +pub enum Physical {} + +/// Zero-sized type to mark a virtual address. +#[derive(Copy, Clone, Debug, PartialOrd, PartialEq, Ord, Eq)] +pub enum Virtual {} + +/// Generic address type. +#[derive(Copy, Clone, Debug, PartialOrd, PartialEq, Ord, Eq)] +pub struct Address { + value: usize, + _address_type: PhantomData ATYPE>, +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +impl AddressType for Physical {} +impl AddressType for Virtual {} + +impl Address { + /// Create an instance. + pub const fn new(value: usize) -> Self { + Self { + value, + _address_type: PhantomData, + } + } + + /// Convert to usize. + pub const fn as_usize(self) -> usize { + self.value + } + + /// Align down to page size. + #[must_use] + pub const fn align_down_page(self) -> Self { + let aligned = common::align_down(self.value, bsp::memory::mmu::KernelGranule::SIZE); + + Self::new(aligned) + } + + /// Align up to page size. + #[must_use] + pub const fn align_up_page(self) -> Self { + let aligned = common::align_up(self.value, bsp::memory::mmu::KernelGranule::SIZE); + + Self::new(aligned) + } + + /// Checks if the address is page aligned. + pub const fn is_page_aligned(&self) -> bool { + common::is_aligned(self.value, bsp::memory::mmu::KernelGranule::SIZE) + } + + /// Return the address' offset into the corresponding page. + pub const fn offset_into_page(&self) -> usize { + self.value & bsp::memory::mmu::KernelGranule::MASK + } +} + +impl Add for Address { + type Output = Self; + + #[inline(always)] + fn add(self, rhs: usize) -> Self::Output { + match self.value.checked_add(rhs) { + None => panic!("Overflow on Address::add"), + Some(x) => Self::new(x), + } + } +} + +impl Sub for Address { + type Output = Self; + + #[inline(always)] + fn sub(self, rhs: usize) -> Self::Output { + match self.value.checked_sub(rhs) { + None => panic!("Overflow on Address::sub"), + Some(x) => Self::new(x), + } + } +} + +impl Sub> for Address { + type Output = Self; + + #[inline(always)] + fn sub(self, rhs: Address) -> Self::Output { + match self.value.checked_sub(rhs.value) { + None => panic!("Overflow on Address::sub"), + Some(x) => Self::new(x), + } + } +} + +impl Address { + /// Checks if the address is part of the boot core stack region. + pub fn is_valid_stack_addr(&self) -> bool { + bsp::memory::mmu::virt_boot_core_stack_region().contains(*self) + } + + /// Checks if the address is part of the kernel code region. + pub fn is_valid_code_addr(&self) -> bool { + bsp::memory::mmu::virt_code_region().contains(*self) + } +} + +impl fmt::Display for Address { + // Don't expect to see physical addresses greater than 40 bit. + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let q3: u8 = ((self.value >> 32) & 0xff) as u8; + let q2: u16 = ((self.value >> 16) & 0xffff) as u16; + let q1: u16 = (self.value & 0xffff) as u16; + + write!(f, "0x")?; + write!(f, "{:02x}_", q3)?; + write!(f, "{:04x}_", q2)?; + write!(f, "{:04x}", q1) + } +} + +impl fmt::Display for Address { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let q4: u16 = ((self.value >> 48) & 0xffff) as u16; + let q3: u16 = ((self.value >> 32) & 0xffff) as u16; + let q2: u16 = ((self.value >> 16) & 0xffff) as u16; + let q1: u16 = (self.value & 0xffff) as u16; + + write!(f, "0x")?; + write!(f, "{:04x}_", q4)?; + write!(f, "{:04x}_", q3)?; + write!(f, "{:04x}_", q2)?; + write!(f, "{:04x}", q1) + } +} + +/// Initialize the memory subsystem. +pub fn init() { + mmu::kernel_init_mmio_va_allocator(); + heap_alloc::kernel_init_heap_allocator(); +} + +//-------------------------------------------------------------------------------------------------- +// Testing +//-------------------------------------------------------------------------------------------------- + +#[cfg(test)] +mod tests { + use super::*; + use test_macros::kernel_test; + + /// Sanity of [Address] methods. + #[kernel_test] + fn address_type_method_sanity() { + let addr = Address::::new(bsp::memory::mmu::KernelGranule::SIZE + 100); + + assert_eq!( + addr.align_down_page().as_usize(), + bsp::memory::mmu::KernelGranule::SIZE + ); + + assert_eq!( + addr.align_up_page().as_usize(), + bsp::memory::mmu::KernelGranule::SIZE * 2 + ); + + assert!(!addr.is_page_aligned()); + + assert_eq!(addr.offset_into_page(), 100); + } +} diff --git a/19_kernel_heap/kernel/src/memory/heap_alloc.rs b/19_kernel_heap/kernel/src/memory/heap_alloc.rs new file mode 100644 index 00000000..81a5009c --- /dev/null +++ b/19_kernel_heap/kernel/src/memory/heap_alloc.rs @@ -0,0 +1,137 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2022 Andre Richter + +//! Heap allocation. + +use crate::{ + backtrace, bsp, common, debug, info, + memory::{Address, Virtual}, + synchronization, + synchronization::IRQSafeNullLock, +}; +use alloc::alloc::{GlobalAlloc, Layout}; +use linked_list_allocator::Heap as LinkedListHeap; + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +/// A heap allocator that can be lazyily initialized. +pub struct HeapAllocator { + inner: IRQSafeNullLock, +} + +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +#[global_allocator] +static KERNEL_HEAP_ALLOCATOR: HeapAllocator = HeapAllocator::new(); + +//-------------------------------------------------------------------------------------------------- +// Private Code +//-------------------------------------------------------------------------------------------------- + +#[inline(always)] +fn debug_print_alloc_dealloc(operation: &'static str, ptr: *mut u8, layout: Layout) { + let size = layout.size(); + let (size_h, size_unit) = common::size_human_readable_ceil(size); + let addr = Address::::new(ptr as usize); + + debug!( + "Kernel Heap: {}\n \ + Size: {:#x} ({} {})\n \ + Start: {}\n \ + End excl: {}\n\n \ + {}", + operation, + size, + size_h, + size_unit, + addr, + addr + size, + backtrace::Backtrace + ); +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- +use synchronization::interface::Mutex; + +#[alloc_error_handler] +fn alloc_error_handler(layout: Layout) -> ! { + panic!("Allocation error: {:?}", layout) +} + +/// Return a reference to the kernel's heap allocator. +pub fn kernel_heap_allocator() -> &'static HeapAllocator { + &KERNEL_HEAP_ALLOCATOR +} + +impl HeapAllocator { + /// Create an instance. + pub const fn new() -> Self { + Self { + inner: IRQSafeNullLock::new(LinkedListHeap::empty()), + } + } + + /// Print the current heap usage. + pub fn print_usage(&self) { + let (used, free) = KERNEL_HEAP_ALLOCATOR + .inner + .lock(|inner| (inner.used(), inner.free())); + + if used >= 1024 { + let (used_h, used_unit) = common::size_human_readable_ceil(used); + info!(" Used: {} Byte ({} {})", used, used_h, used_unit); + } else { + info!(" Used: {} Byte", used); + } + + if free >= 1024 { + let (free_h, free_unit) = common::size_human_readable_ceil(free); + info!(" Free: {} Byte ({} {})", free, free_h, free_unit); + } else { + info!(" Free: {} Byte", free); + } + } +} + +unsafe impl GlobalAlloc for HeapAllocator { + unsafe fn alloc(&self, layout: Layout) -> *mut u8 { + let result = KERNEL_HEAP_ALLOCATOR + .inner + .lock(|inner| inner.allocate_first_fit(layout).ok()); + + match result { + None => core::ptr::null_mut(), + Some(allocation) => { + let ptr = allocation.as_ptr(); + + debug_print_alloc_dealloc("Allocation", ptr, layout); + + ptr + } + } + } + + unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) { + KERNEL_HEAP_ALLOCATOR + .inner + .lock(|inner| inner.deallocate(core::ptr::NonNull::new_unchecked(ptr), layout)); + + debug_print_alloc_dealloc("Free", ptr, layout); + } +} + +/// Query the BSP for the heap region and initialize the kernel's heap allocator with it. +pub fn kernel_init_heap_allocator() { + let region = bsp::memory::mmu::virt_heap_region(); + + KERNEL_HEAP_ALLOCATOR + .inner + .lock(|inner| unsafe { inner.init(region.start_addr().as_usize(), region.size()) }); +} diff --git a/19_kernel_heap/kernel/src/memory/mmu.rs b/19_kernel_heap/kernel/src/memory/mmu.rs new file mode 100644 index 00000000..8d204a4e --- /dev/null +++ b/19_kernel_heap/kernel/src/memory/mmu.rs @@ -0,0 +1,262 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2020-2022 Andre Richter + +//! Memory Management Unit. + +#[cfg(target_arch = "aarch64")] +#[path = "../_arch/aarch64/memory/mmu.rs"] +mod arch_mmu; + +mod mapping_record; +mod page_alloc; +mod translation_table; +mod types; + +use crate::{ + bsp, + memory::{Address, Physical, Virtual}, + synchronization::{self, interface::Mutex}, +}; +use core::{fmt, num::NonZeroUsize}; + +pub use types::*; + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +/// MMU enable errors variants. +#[allow(missing_docs)] +#[derive(Debug)] +pub enum MMUEnableError { + AlreadyEnabled, + Other(&'static str), +} + +/// Memory Management interfaces. +pub mod interface { + use super::*; + + /// MMU functions. + pub trait MMU { + /// Turns on the MMU for the first time and enables data and instruction caching. + /// + /// # Safety + /// + /// - Changes the HW's global state. + unsafe fn enable_mmu_and_caching( + &self, + phys_tables_base_addr: Address, + ) -> Result<(), MMUEnableError>; + + /// Returns true if the MMU is enabled, false otherwise. + fn is_enabled(&self) -> bool; + } +} + +/// Describes the characteristics of a translation granule. +pub struct TranslationGranule; + +/// Describes properties of an address space. +pub struct AddressSpace; + +/// Intended to be implemented for [`AddressSpace`]. +pub trait AssociatedTranslationTable { + /// A translation table whose address range is: + /// + /// [u64::MAX, (u64::MAX - AS_SIZE) + 1] + type TableStartFromTop; + + /// A translation table whose address range is: + /// + /// [AS_SIZE - 1, 0] + type TableStartFromBottom; +} + +//-------------------------------------------------------------------------------------------------- +// Private Code +//-------------------------------------------------------------------------------------------------- +use interface::MMU; +use synchronization::interface::ReadWriteEx; +use translation_table::interface::TranslationTable; + +/// Map a region in the kernel's translation tables. +/// +/// No input checks done, input is passed through to the architectural implementation. +/// +/// # Safety +/// +/// - See `map_at()`. +/// - Does not prevent aliasing. +unsafe fn kernel_map_at_unchecked( + name: &'static str, + virt_region: &MemoryRegion, + phys_region: &MemoryRegion, + attr: &AttributeFields, +) -> Result<(), &'static str> { + bsp::memory::mmu::kernel_translation_tables() + .write(|tables| tables.map_at(virt_region, phys_region, attr))?; + + kernel_add_mapping_record(name, virt_region, phys_region, attr); + + Ok(()) +} + +/// Try to translate a kernel virtual address to a physical address. +/// +/// Will only succeed if there exists a valid mapping for the input address. +fn try_kernel_virt_addr_to_phys_addr( + virt_addr: Address, +) -> Result, &'static str> { + bsp::memory::mmu::kernel_translation_tables() + .read(|tables| tables.try_virt_addr_to_phys_addr(virt_addr)) +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +impl fmt::Display for MMUEnableError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + MMUEnableError::AlreadyEnabled => write!(f, "MMU is already enabled"), + MMUEnableError::Other(x) => write!(f, "{}", x), + } + } +} + +impl TranslationGranule { + /// The granule's size. + pub const SIZE: usize = Self::size_checked(); + + /// The granule's mask. + pub const MASK: usize = Self::SIZE - 1; + + /// The granule's shift, aka log2(size). + pub const SHIFT: usize = Self::SIZE.trailing_zeros() as usize; + + const fn size_checked() -> usize { + assert!(GRANULE_SIZE.is_power_of_two()); + + GRANULE_SIZE + } +} + +impl AddressSpace { + /// The address space size. + pub const SIZE: usize = Self::size_checked(); + + /// The address space shift, aka log2(size). + pub const SIZE_SHIFT: usize = Self::SIZE.trailing_zeros() as usize; + + const fn size_checked() -> usize { + assert!(AS_SIZE.is_power_of_two()); + + // Check for architectural restrictions as well. + Self::arch_address_space_size_sanity_checks(); + + AS_SIZE + } +} + +/// Query the BSP for the reserved virtual addresses for MMIO remapping and initialize the kernel's +/// MMIO VA allocator with it. +pub fn kernel_init_mmio_va_allocator() { + let region = bsp::memory::mmu::virt_mmio_remap_region(); + + page_alloc::kernel_mmio_va_allocator().lock(|allocator| allocator.init(region)); +} + +/// Add an entry to the mapping info record. +pub fn kernel_add_mapping_record( + name: &'static str, + virt_region: &MemoryRegion, + phys_region: &MemoryRegion, + attr: &AttributeFields, +) { + mapping_record::kernel_add(name, virt_region, phys_region, attr); +} + +/// MMIO remapping in the kernel translation tables. +/// +/// Typically used by device drivers. +/// +/// # Safety +/// +/// - Same as `kernel_map_at_unchecked()`, minus the aliasing part. +pub unsafe fn kernel_map_mmio( + name: &'static str, + mmio_descriptor: &MMIODescriptor, +) -> Result, &'static str> { + let phys_region = MemoryRegion::from(*mmio_descriptor); + let offset_into_start_page = mmio_descriptor.start_addr().offset_into_page(); + + // Check if an identical region has been mapped for another driver. If so, reuse it. + let virt_addr = if let Some(addr) = + mapping_record::kernel_find_and_insert_mmio_duplicate(mmio_descriptor, name) + { + addr + // Otherwise, allocate a new region and map it. + } else { + let num_pages = match NonZeroUsize::new(phys_region.num_pages()) { + None => return Err("Requested 0 pages"), + Some(x) => x, + }; + + let virt_region = + page_alloc::kernel_mmio_va_allocator().lock(|allocator| allocator.alloc(num_pages))?; + + kernel_map_at_unchecked( + name, + &virt_region, + &phys_region, + &AttributeFields { + mem_attributes: MemAttributes::Device, + acc_perms: AccessPermissions::ReadWrite, + execute_never: true, + }, + )?; + + virt_region.start_addr() + }; + + Ok(virt_addr + offset_into_start_page) +} + +/// Try to translate a kernel virtual page address to a physical page address. +/// +/// Will only succeed if there exists a valid mapping for the input page. +pub fn try_kernel_virt_page_addr_to_phys_page_addr( + virt_page_addr: PageAddress, +) -> Result, &'static str> { + bsp::memory::mmu::kernel_translation_tables() + .read(|tables| tables.try_virt_page_addr_to_phys_page_addr(virt_page_addr)) +} + +/// Try to get the attributes of a kernel page. +/// +/// Will only succeed if there exists a valid mapping for the input page. +pub fn try_kernel_page_attributes( + virt_page_addr: PageAddress, +) -> Result { + bsp::memory::mmu::kernel_translation_tables() + .read(|tables| tables.try_page_attributes(virt_page_addr)) +} + +/// Human-readable print of all recorded kernel mappings. +pub fn kernel_print_mappings() { + mapping_record::kernel_print() +} + +/// Enable the MMU and data + instruction caching. +/// +/// # Safety +/// +/// - Crucial function during kernel init. Changes the the complete memory view of the processor. +#[inline(always)] +pub unsafe fn enable_mmu_and_caching( + phys_tables_base_addr: Address, +) -> Result<(), MMUEnableError> { + arch_mmu::mmu().enable_mmu_and_caching(phys_tables_base_addr) +} diff --git a/19_kernel_heap/kernel/src/memory/mmu/mapping_record.rs b/19_kernel_heap/kernel/src/memory/mmu/mapping_record.rs new file mode 100644 index 00000000..4e9395da --- /dev/null +++ b/19_kernel_heap/kernel/src/memory/mmu/mapping_record.rs @@ -0,0 +1,204 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2020-2022 Andre Richter + +//! A record of mapped pages. + +use super::{ + AccessPermissions, Address, AttributeFields, MMIODescriptor, MemAttributes, MemoryRegion, + Physical, Virtual, +}; +use crate::{bsp, common, info, synchronization, synchronization::InitStateLock}; +use alloc::{vec, vec::Vec}; + +//-------------------------------------------------------------------------------------------------- +// Private Definitions +//-------------------------------------------------------------------------------------------------- + +/// Type describing a virtual memory mapping. +#[allow(missing_docs)] +struct MappingRecordEntry { + pub users: Vec<&'static str>, + pub phys_start_addr: Address, + pub virt_start_addr: Address, + pub num_pages: usize, + pub attribute_fields: AttributeFields, +} + +struct MappingRecord { + inner: Vec, +} + +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +static KERNEL_MAPPING_RECORD: InitStateLock = + InitStateLock::new(MappingRecord::new()); + +//-------------------------------------------------------------------------------------------------- +// Private Code +//-------------------------------------------------------------------------------------------------- + +impl MappingRecordEntry { + pub fn new( + name: &'static str, + virt_region: &MemoryRegion, + phys_region: &MemoryRegion, + attr: &AttributeFields, + ) -> Self { + Self { + users: vec![name], + phys_start_addr: phys_region.start_addr(), + virt_start_addr: virt_region.start_addr(), + num_pages: phys_region.num_pages(), + attribute_fields: *attr, + } + } + + pub fn add_user(&mut self, user: &'static str) { + self.users.push(user); + } +} + +impl MappingRecord { + pub const fn new() -> Self { + Self { inner: Vec::new() } + } + + fn sort(&mut self) { + if !self.inner.is_sorted_by_key(|item| item.virt_start_addr) { + self.inner.sort_unstable_by_key(|item| item.virt_start_addr) + } + } + + fn find_duplicate( + &mut self, + phys_region: &MemoryRegion, + ) -> Option<&mut MappingRecordEntry> { + self.inner + .iter_mut() + .filter(|x| x.attribute_fields.mem_attributes == MemAttributes::Device) + .find(|x| { + if x.phys_start_addr != phys_region.start_addr() { + return false; + } + + if x.num_pages != phys_region.num_pages() { + return false; + } + + true + }) + } + + pub fn add( + &mut self, + name: &'static str, + virt_region: &MemoryRegion, + phys_region: &MemoryRegion, + attr: &AttributeFields, + ) { + self.inner.push(MappingRecordEntry::new( + name, + virt_region, + phys_region, + attr, + )); + + self.sort(); + } + + pub fn print(&self) { + info!(" -------------------------------------------------------------------------------------------------------------------------------------------"); + info!( + " {:^44} {:^30} {:^7} {:^9} {:^35}", + "Virtual", "Physical", "Size", "Attr", "Entity" + ); + info!(" -------------------------------------------------------------------------------------------------------------------------------------------"); + + for i in self.inner.iter() { + let size = i.num_pages * bsp::memory::mmu::KernelGranule::SIZE; + let virt_start = i.virt_start_addr; + let virt_end_inclusive = virt_start + (size - 1); + let phys_start = i.phys_start_addr; + let phys_end_inclusive = phys_start + (size - 1); + + let (size, unit) = common::size_human_readable_ceil(size); + + let attr = match i.attribute_fields.mem_attributes { + MemAttributes::CacheableDRAM => "C", + MemAttributes::Device => "Dev", + }; + + let acc_p = match i.attribute_fields.acc_perms { + AccessPermissions::ReadOnly => "RO", + AccessPermissions::ReadWrite => "RW", + }; + + let xn = if i.attribute_fields.execute_never { + "XN" + } else { + "X" + }; + + info!( + " {}..{} --> {}..{} | {:>3} {} | {:<3} {} {:<2} | {}", + virt_start, + virt_end_inclusive, + phys_start, + phys_end_inclusive, + size, + unit, + attr, + acc_p, + xn, + i.users[0] + ); + + for k in &i.users[1..] { + info!( + " | {}", + k + ); + } + } + + info!(" -------------------------------------------------------------------------------------------------------------------------------------------"); + } +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- +use synchronization::interface::ReadWriteEx; + +/// Add an entry to the mapping info record. +pub fn kernel_add( + name: &'static str, + virt_region: &MemoryRegion, + phys_region: &MemoryRegion, + attr: &AttributeFields, +) { + KERNEL_MAPPING_RECORD.write(|mr| mr.add(name, virt_region, phys_region, attr)) +} + +pub fn kernel_find_and_insert_mmio_duplicate( + mmio_descriptor: &MMIODescriptor, + new_user: &'static str, +) -> Option> { + let phys_region: MemoryRegion = (*mmio_descriptor).into(); + + KERNEL_MAPPING_RECORD.write(|mr| { + let dup = mr.find_duplicate(&phys_region)?; + + dup.add_user(new_user); + + Some(dup.virt_start_addr) + }) +} + +/// Human-readable print of all recorded kernel mappings. +pub fn kernel_print() { + KERNEL_MAPPING_RECORD.read(|mr| mr.print()); +} diff --git a/19_kernel_heap/kernel/src/memory/mmu/page_alloc.rs b/19_kernel_heap/kernel/src/memory/mmu/page_alloc.rs new file mode 100644 index 00000000..347fcd34 --- /dev/null +++ b/19_kernel_heap/kernel/src/memory/mmu/page_alloc.rs @@ -0,0 +1,70 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2021-2022 Andre Richter + +//! Page allocation. + +use super::MemoryRegion; +use crate::{ + memory::{AddressType, Virtual}, + synchronization::IRQSafeNullLock, + warn, +}; +use core::num::NonZeroUsize; + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +/// A page allocator that can be lazyily initialized. +pub struct PageAllocator { + pool: Option>, +} + +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +static KERNEL_MMIO_VA_ALLOCATOR: IRQSafeNullLock> = + IRQSafeNullLock::new(PageAllocator::new()); + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +/// Return a reference to the kernel's MMIO virtual address allocator. +pub fn kernel_mmio_va_allocator() -> &'static IRQSafeNullLock> { + &KERNEL_MMIO_VA_ALLOCATOR +} + +impl PageAllocator { + /// Create an instance. + pub const fn new() -> Self { + Self { pool: None } + } + + /// Initialize the allocator. + pub fn init(&mut self, pool: MemoryRegion) { + if self.pool.is_some() { + warn!("Already initialized"); + return; + } + + self.pool = Some(pool); + } + + /// Allocate a number of pages. + pub fn alloc( + &mut self, + num_requested_pages: NonZeroUsize, + ) -> Result, &'static str> { + if self.pool.is_none() { + return Err("Allocator not initialized"); + } + + self.pool + .as_mut() + .unwrap() + .take_first_n_pages(num_requested_pages) + } +} diff --git a/19_kernel_heap/kernel/src/memory/mmu/translation_table.rs b/19_kernel_heap/kernel/src/memory/mmu/translation_table.rs new file mode 100644 index 00000000..9d627f97 --- /dev/null +++ b/19_kernel_heap/kernel/src/memory/mmu/translation_table.rs @@ -0,0 +1,137 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2021-2022 Andre Richter + +//! Translation table. + +#[cfg(target_arch = "aarch64")] +#[path = "../../_arch/aarch64/memory/mmu/translation_table.rs"] +mod arch_translation_table; + +use super::{AttributeFields, MemoryRegion}; +use crate::memory::{Address, Physical, Virtual}; + +//-------------------------------------------------------------------------------------------------- +// Architectural Public Reexports +//-------------------------------------------------------------------------------------------------- +#[cfg(target_arch = "aarch64")] +pub use arch_translation_table::FixedSizeTranslationTable; + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +/// Translation table interfaces. +pub mod interface { + use crate::memory::mmu::PageAddress; + + use super::*; + + /// Translation table operations. + pub trait TranslationTable { + /// Anything that needs to run before any of the other provided functions can be used. + /// + /// # Safety + /// + /// - Implementor must ensure that this function can run only once or is harmless if invoked + /// multiple times. + fn init(&mut self) -> Result<(), &'static str>; + + /// Map the given virtual memory region to the given physical memory region. + /// + /// # Safety + /// + /// - Using wrong attributes can cause multiple issues of different nature in the system. + /// - It is not required that the architectural implementation prevents aliasing. That is, + /// mapping to the same physical memory using multiple virtual addresses, which would + /// break Rust's ownership assumptions. This should be protected against in the kernel's + /// generic MMU code. + unsafe fn map_at( + &mut self, + virt_region: &MemoryRegion, + phys_region: &MemoryRegion, + attr: &AttributeFields, + ) -> Result<(), &'static str>; + + /// Try to translate a virtual page address to a physical page address. + /// + /// Will only succeed if there exists a valid mapping for the input page. + fn try_virt_page_addr_to_phys_page_addr( + &self, + virt_page_addr: PageAddress, + ) -> Result, &'static str>; + + /// Try to get the attributes of a page. + /// + /// Will only succeed if there exists a valid mapping for the input page. + fn try_page_attributes( + &self, + virt_page_addr: PageAddress, + ) -> Result; + + /// Try to translate a virtual address to a physical address. + /// + /// Will only succeed if there exists a valid mapping for the input address. + fn try_virt_addr_to_phys_addr( + &self, + virt_addr: Address, + ) -> Result, &'static str>; + } +} + +//-------------------------------------------------------------------------------------------------- +// Testing +//-------------------------------------------------------------------------------------------------- + +#[cfg(test)] +mod tests { + use super::*; + use crate::memory::mmu::{AccessPermissions, MemAttributes, PageAddress}; + use arch_translation_table::MinSizeTranslationTable; + use interface::TranslationTable; + use test_macros::kernel_test; + + /// Sanity checks for the TranslationTable implementation. + #[kernel_test] + fn translationtable_implementation_sanity() { + // This will occupy a lot of space on the stack. + let mut tables = MinSizeTranslationTable::new_for_runtime(); + + assert!(tables.init().is_ok()); + + let virt_end_exclusive_page_addr: PageAddress = PageAddress::MAX; + let virt_start_page_addr: PageAddress = + virt_end_exclusive_page_addr.checked_offset(-5).unwrap(); + + let phys_start_page_addr: PageAddress = PageAddress::from(0); + let phys_end_exclusive_page_addr: PageAddress = + phys_start_page_addr.checked_offset(5).unwrap(); + + let virt_region = MemoryRegion::new(virt_start_page_addr, virt_end_exclusive_page_addr); + let phys_region = MemoryRegion::new(phys_start_page_addr, phys_end_exclusive_page_addr); + + let attr = AttributeFields { + mem_attributes: MemAttributes::CacheableDRAM, + acc_perms: AccessPermissions::ReadWrite, + execute_never: true, + }; + + unsafe { assert_eq!(tables.map_at(&virt_region, &phys_region, &attr), Ok(())) }; + + assert_eq!( + tables.try_virt_page_addr_to_phys_page_addr(virt_start_page_addr), + Ok(phys_start_page_addr) + ); + + assert_eq!( + tables.try_page_attributes(virt_start_page_addr.checked_offset(-1).unwrap()), + Err("Page marked invalid") + ); + + assert_eq!(tables.try_page_attributes(virt_start_page_addr), Ok(attr)); + + let virt_addr = virt_start_page_addr.into_inner() + 0x100; + let phys_addr = phys_start_page_addr.into_inner() + 0x100; + assert_eq!(tables.try_virt_addr_to_phys_addr(virt_addr), Ok(phys_addr)); + } +} diff --git a/19_kernel_heap/kernel/src/memory/mmu/types.rs b/19_kernel_heap/kernel/src/memory/mmu/types.rs new file mode 100644 index 00000000..85c852b3 --- /dev/null +++ b/19_kernel_heap/kernel/src/memory/mmu/types.rs @@ -0,0 +1,378 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2020-2022 Andre Richter + +//! Memory Management Unit types. + +use crate::{ + bsp, common, + memory::{Address, AddressType, Physical}, +}; +use core::{convert::From, iter::Step, num::NonZeroUsize, ops::Range}; + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +/// A wrapper type around [Address] that ensures page alignment. +#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)] +pub struct PageAddress { + inner: Address, +} + +/// A type that describes a region of memory in quantities of pages. +#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)] +pub struct MemoryRegion { + start: PageAddress, + end_exclusive: PageAddress, +} + +/// Architecture agnostic memory attributes. +#[allow(missing_docs)] +#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)] +pub enum MemAttributes { + CacheableDRAM, + Device, +} + +/// Architecture agnostic access permissions. +#[allow(missing_docs)] +#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)] +pub enum AccessPermissions { + ReadOnly, + ReadWrite, +} + +/// Collection of memory attributes. +#[allow(missing_docs)] +#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)] +pub struct AttributeFields { + pub mem_attributes: MemAttributes, + pub acc_perms: AccessPermissions, + pub execute_never: bool, +} + +/// An MMIO descriptor for use in device drivers. +#[derive(Copy, Clone)] +pub struct MMIODescriptor { + start_addr: Address, + end_addr_exclusive: Address, +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +//------------------------------------------------------------------------------ +// PageAddress +//------------------------------------------------------------------------------ +impl PageAddress { + /// The largest value that can be represented by this type. + pub const MAX: Self = PageAddress { + inner: Address::new(usize::MAX).align_down_page(), + }; + + /// Unwraps the value. + pub fn into_inner(self) -> Address { + self.inner + } + + /// Calculates the offset from the page address. + /// + /// `count` is in units of [PageAddress]. For example, a count of 2 means `result = self + 2 * + /// page_size`. + pub fn checked_offset(self, count: isize) -> Option { + if count == 0 { + return Some(self); + } + + let delta = count + .unsigned_abs() + .checked_mul(bsp::memory::mmu::KernelGranule::SIZE)?; + let result = if count.is_positive() { + self.inner.as_usize().checked_add(delta)? + } else { + self.inner.as_usize().checked_sub(delta)? + }; + + Some(Self { + inner: Address::new(result), + }) + } +} + +impl From for PageAddress { + fn from(addr: usize) -> Self { + assert!( + common::is_aligned(addr, bsp::memory::mmu::KernelGranule::SIZE), + "Input usize not page aligned" + ); + + Self { + inner: Address::new(addr), + } + } +} + +impl From> for PageAddress { + fn from(addr: Address) -> Self { + assert!(addr.is_page_aligned(), "Input Address not page aligned"); + + Self { inner: addr } + } +} + +impl Step for PageAddress { + fn steps_between(start: &Self, end: &Self) -> Option { + if start > end { + return None; + } + + // Since start <= end, do unchecked arithmetic. + Some( + (end.inner.as_usize() - start.inner.as_usize()) + >> bsp::memory::mmu::KernelGranule::SHIFT, + ) + } + + fn forward_checked(start: Self, count: usize) -> Option { + start.checked_offset(count as isize) + } + + fn backward_checked(start: Self, count: usize) -> Option { + start.checked_offset(-(count as isize)) + } +} + +//------------------------------------------------------------------------------ +// MemoryRegion +//------------------------------------------------------------------------------ +impl MemoryRegion { + /// Create an instance. + pub fn new(start: PageAddress, end_exclusive: PageAddress) -> Self { + assert!(start <= end_exclusive); + + Self { + start, + end_exclusive, + } + } + + fn as_range(&self) -> Range> { + self.into_iter() + } + + /// Returns the start page address. + pub fn start_page_addr(&self) -> PageAddress { + self.start + } + + /// Returns the start address. + pub fn start_addr(&self) -> Address { + self.start.into_inner() + } + + /// Returns the exclusive end page address. + pub fn end_exclusive_page_addr(&self) -> PageAddress { + self.end_exclusive + } + + /// Returns the exclusive end page address. + pub fn end_inclusive_page_addr(&self) -> PageAddress { + self.end_exclusive.checked_offset(-1).unwrap() + } + + /// Checks if self contains an address. + pub fn contains(&self, addr: Address) -> bool { + let page_addr = PageAddress::from(addr.align_down_page()); + self.as_range().contains(&page_addr) + } + + /// Checks if there is an overlap with another memory region. + pub fn overlaps(&self, other_region: &Self) -> bool { + let self_range = self.as_range(); + + self_range.contains(&other_region.start_page_addr()) + || self_range.contains(&other_region.end_inclusive_page_addr()) + } + + /// Returns the number of pages contained in this region. + pub fn num_pages(&self) -> usize { + PageAddress::steps_between(&self.start, &self.end_exclusive).unwrap() + } + + /// Returns the size in bytes of this region. + pub fn size(&self) -> usize { + // Invariant: start <= end_exclusive, so do unchecked arithmetic. + let end_exclusive = self.end_exclusive.into_inner().as_usize(); + let start = self.start.into_inner().as_usize(); + + end_exclusive - start + } + + /// Splits the MemoryRegion like: + /// + /// -------------------------------------------------------------------------------- + /// | | | | | | | | | | | | | | | | | | | + /// -------------------------------------------------------------------------------- + /// ^ ^ ^ + /// | | | + /// left_start left_end_exclusive | + /// | + /// ^ | + /// | | + /// right_start right_end_exclusive + /// + /// Left region is returned to the caller. Right region is the new region for this struct. + pub fn take_first_n_pages(&mut self, num_pages: NonZeroUsize) -> Result { + let count: usize = num_pages.into(); + + let left_end_exclusive = self.start.checked_offset(count as isize); + let left_end_exclusive = match left_end_exclusive { + None => return Err("Overflow while calculating left_end_exclusive"), + Some(x) => x, + }; + + if left_end_exclusive > self.end_exclusive { + return Err("Not enough free pages"); + } + + let allocation = Self { + start: self.start, + end_exclusive: left_end_exclusive, + }; + self.start = left_end_exclusive; + + Ok(allocation) + } +} + +impl IntoIterator for MemoryRegion { + type Item = PageAddress; + type IntoIter = Range; + + fn into_iter(self) -> Self::IntoIter { + Range { + start: self.start, + end: self.end_exclusive, + } + } +} + +impl From for MemoryRegion { + fn from(desc: MMIODescriptor) -> Self { + let start = PageAddress::from(desc.start_addr.align_down_page()); + let end_exclusive = PageAddress::from(desc.end_addr_exclusive().align_up_page()); + + Self { + start, + end_exclusive, + } + } +} + +//------------------------------------------------------------------------------ +// MMIODescriptor +//------------------------------------------------------------------------------ + +impl MMIODescriptor { + /// Create an instance. + pub const fn new(start_addr: Address, size: usize) -> Self { + assert!(size > 0); + let end_addr_exclusive = Address::new(start_addr.as_usize() + size); + + Self { + start_addr, + end_addr_exclusive, + } + } + + /// Return the start address. + pub const fn start_addr(&self) -> Address { + self.start_addr + } + + /// Return the exclusive end address. + pub fn end_addr_exclusive(&self) -> Address { + self.end_addr_exclusive + } +} + +//-------------------------------------------------------------------------------------------------- +// Testing +//-------------------------------------------------------------------------------------------------- + +#[cfg(test)] +mod tests { + use super::*; + use crate::memory::Virtual; + use test_macros::kernel_test; + + /// Sanity of [PageAddress] methods. + #[kernel_test] + fn pageaddress_type_method_sanity() { + let page_addr: PageAddress = + PageAddress::from(bsp::memory::mmu::KernelGranule::SIZE * 2); + + assert_eq!( + page_addr.checked_offset(-2), + Some(PageAddress::::from(0)) + ); + + assert_eq!( + page_addr.checked_offset(2), + Some(PageAddress::::from( + bsp::memory::mmu::KernelGranule::SIZE * 4 + )) + ); + + assert_eq!( + PageAddress::::from(0).checked_offset(0), + Some(PageAddress::::from(0)) + ); + assert_eq!(PageAddress::::from(0).checked_offset(-1), None); + + let max_page_addr = Address::::new(usize::MAX).align_down_page(); + assert_eq!( + PageAddress::::from(max_page_addr).checked_offset(1), + None + ); + + let zero = PageAddress::::from(0); + let three = PageAddress::::from(bsp::memory::mmu::KernelGranule::SIZE * 3); + assert_eq!(PageAddress::steps_between(&zero, &three), Some(3)); + } + + /// Sanity of [MemoryRegion] methods. + #[kernel_test] + fn memoryregion_type_method_sanity() { + let zero = PageAddress::::from(0); + let zero_region = MemoryRegion::new(zero, zero); + assert_eq!(zero_region.num_pages(), 0); + assert_eq!(zero_region.size(), 0); + + let one = PageAddress::::from(bsp::memory::mmu::KernelGranule::SIZE); + let one_region = MemoryRegion::new(zero, one); + assert_eq!(one_region.num_pages(), 1); + assert_eq!(one_region.size(), bsp::memory::mmu::KernelGranule::SIZE); + + let three = PageAddress::::from(bsp::memory::mmu::KernelGranule::SIZE * 3); + let mut three_region = MemoryRegion::new(zero, three); + assert!(three_region.contains(zero.into_inner())); + assert!(!three_region.contains(three.into_inner())); + assert!(three_region.overlaps(&one_region)); + + let allocation = three_region + .take_first_n_pages(NonZeroUsize::new(2).unwrap()) + .unwrap(); + assert_eq!(allocation.num_pages(), 2); + assert_eq!(three_region.num_pages(), 1); + + for (i, alloc) in allocation.into_iter().enumerate() { + assert_eq!( + alloc.into_inner().as_usize(), + i * bsp::memory::mmu::KernelGranule::SIZE + ); + } + } +} diff --git a/19_kernel_heap/kernel/src/panic_wait.rs b/19_kernel_heap/kernel/src/panic_wait.rs new file mode 100644 index 00000000..c8e86fbd --- /dev/null +++ b/19_kernel_heap/kernel/src/panic_wait.rs @@ -0,0 +1,90 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2018-2022 Andre Richter + +//! A panic handler that infinitely waits. + +use crate::{backtrace, cpu, exception, println}; +use core::panic::PanicInfo; + +//-------------------------------------------------------------------------------------------------- +// Private Code +//-------------------------------------------------------------------------------------------------- + +/// The point of exit for `libkernel`. +/// +/// It is linked weakly, so that the integration tests can overload its standard behavior. +#[linkage = "weak"] +#[no_mangle] +fn _panic_exit() -> ! { + #[cfg(not(feature = "test_build"))] + { + cpu::wait_forever() + } + + #[cfg(feature = "test_build")] + { + cpu::qemu_exit_failure() + } +} + +/// Stop immediately if called a second time. +/// +/// # Note +/// +/// Using atomics here relieves us from needing to use `unsafe` for the static variable. +/// +/// On `AArch64`, which is the only implemented architecture at the time of writing this, +/// [`AtomicBool::load`] and [`AtomicBool::store`] are lowered to ordinary load and store +/// instructions. They are therefore safe to use even with MMU + caching deactivated. +/// +/// [`AtomicBool::load`]: core::sync::atomic::AtomicBool::load +/// [`AtomicBool::store`]: core::sync::atomic::AtomicBool::store +fn panic_prevent_reenter() { + use core::sync::atomic::{AtomicBool, Ordering}; + + #[cfg(not(target_arch = "aarch64"))] + compile_error!("Add the target_arch to above's check if the following code is safe to use"); + + static PANIC_IN_PROGRESS: AtomicBool = AtomicBool::new(false); + + if !PANIC_IN_PROGRESS.load(Ordering::Relaxed) { + PANIC_IN_PROGRESS.store(true, Ordering::Relaxed); + + return; + } + + _panic_exit() +} + +#[panic_handler] +fn panic(info: &PanicInfo) -> ! { + use crate::time::interface::TimeManager; + + unsafe { exception::asynchronous::local_irq_mask() }; + + // Protect against panic infinite loops if any of the following code panics itself. + panic_prevent_reenter(); + + let timestamp = crate::time::time_manager().uptime(); + let (location, line, column) = match info.location() { + Some(loc) => (loc.file(), loc.line(), loc.column()), + _ => ("???", 0, 0), + }; + + println!( + "[ {:>3}.{:06}] Kernel panic!\n\n\ + Panic location:\n File '{}', line {}, column {}\n\n\ + {}\n\n\ + {}", + timestamp.as_secs(), + timestamp.subsec_micros(), + location, + line, + column, + info.message().unwrap_or(&format_args!("")), + backtrace::Backtrace + ); + + _panic_exit() +} diff --git a/19_kernel_heap/kernel/src/print.rs b/19_kernel_heap/kernel/src/print.rs new file mode 100644 index 00000000..5e41ef9f --- /dev/null +++ b/19_kernel_heap/kernel/src/print.rs @@ -0,0 +1,124 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2018-2022 Andre Richter + +//! Printing. + +use crate::console; +use core::fmt; + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +#[doc(hidden)] +pub fn _print(args: fmt::Arguments) { + console::console().write_fmt(args).unwrap(); +} + +/// Prints without a newline. +/// +/// Carbon copy from +#[macro_export] +macro_rules! print { + ($($arg:tt)*) => ($crate::print::_print(format_args!($($arg)*))); +} + +/// Prints with a newline. +/// +/// Carbon copy from +#[macro_export] +macro_rules! println { + () => ($crate::print!("\n")); + ($($arg:tt)*) => ({ + $crate::print::_print(format_args_nl!($($arg)*)); + }) +} + +/// Prints an info, with a newline. +#[macro_export] +macro_rules! info { + ($string:expr) => ({ + use $crate::time::interface::TimeManager; + + let timestamp = $crate::time::time_manager().uptime(); + + $crate::print::_print(format_args_nl!( + concat!("[ {:>3}.{:06}] ", $string), + timestamp.as_secs(), + timestamp.subsec_micros(), + )); + }); + ($format_string:expr, $($arg:tt)*) => ({ + use $crate::time::interface::TimeManager; + + let timestamp = $crate::time::time_manager().uptime(); + + $crate::print::_print(format_args_nl!( + concat!("[ {:>3}.{:06}] ", $format_string), + timestamp.as_secs(), + timestamp.subsec_micros(), + $($arg)* + )); + }) +} + +/// Prints a warning, with a newline. +#[macro_export] +macro_rules! warn { + ($string:expr) => ({ + use $crate::time::interface::TimeManager; + + let timestamp = $crate::time::time_manager().uptime(); + + $crate::print::_print(format_args_nl!( + concat!("[W {:>3}.{:06}] ", $string), + timestamp.as_secs(), + timestamp.subsec_micros(), + )); + }); + ($format_string:expr, $($arg:tt)*) => ({ + use $crate::time::interface::TimeManager; + + let timestamp = $crate::time::time_manager().uptime(); + + $crate::print::_print(format_args_nl!( + concat!("[W {:>3}.{:06}] ", $format_string), + timestamp.as_secs(), + timestamp.subsec_micros(), + $($arg)* + )); + }) +} + +/// Debug print, with a newline. +#[macro_export] +macro_rules! debug { + ($string:expr) => ({ + if cfg!(feature = "debug_prints") { + use $crate::time::interface::TimeManager; + + let timestamp = $crate::time::time_manager().uptime(); + + $crate::print::_print(format_args_nl!( + concat!("<[>D {:>3}.{:06}> ", $string), + timestamp.as_secs(), + timestamp.subsec_micros(), + )); + } + }); + ($format_string:expr, $($arg:tt)*) => ({ + if cfg!(feature = "debug_prints") { + use $crate::time::interface::TimeManager; + + let timestamp = $crate::time::time_manager().uptime(); + + $crate::print::_print(format_args_nl!( + concat!("3}.{:06}> ", $format_string), + timestamp.as_secs(), + timestamp.subsec_micros(), + $($arg)* + )); + } + }) +} diff --git a/19_kernel_heap/kernel/src/state.rs b/19_kernel_heap/kernel/src/state.rs new file mode 100644 index 00000000..0af3688c --- /dev/null +++ b/19_kernel_heap/kernel/src/state.rs @@ -0,0 +1,92 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2020-2022 Andre Richter + +//! State information about the kernel itself. + +use core::sync::atomic::{AtomicU8, Ordering}; + +//-------------------------------------------------------------------------------------------------- +// Private Definitions +//-------------------------------------------------------------------------------------------------- + +/// Different stages in the kernel execution. +#[derive(Copy, Clone, Eq, PartialEq)] +enum State { + /// The kernel starts booting in this state. + Init, + + /// The kernel transitions to this state when jumping to `kernel_main()` (at the end of + /// `kernel_init()`, after all init calls are done). + SingleCoreMain, + + /// The kernel transitions to this state when it boots the secondary cores, aka switches + /// exectution mode to symmetric multiprocessing (SMP). + MultiCoreMain, +} + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +/// Maintains the kernel state and state transitions. +pub struct StateManager(AtomicU8); + +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +static STATE_MANAGER: StateManager = StateManager::new(); + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +/// Return a reference to the global StateManager. +pub fn state_manager() -> &'static StateManager { + &STATE_MANAGER +} + +impl StateManager { + const INIT: u8 = 0; + const SINGLE_CORE_MAIN: u8 = 1; + const MULTI_CORE_MAIN: u8 = 2; + + /// Create a new instance. + pub const fn new() -> Self { + Self(AtomicU8::new(Self::INIT)) + } + + /// Return the current state. + fn state(&self) -> State { + let state = self.0.load(Ordering::Acquire); + + match state { + Self::INIT => State::Init, + Self::SINGLE_CORE_MAIN => State::SingleCoreMain, + Self::MULTI_CORE_MAIN => State::MultiCoreMain, + _ => panic!("Invalid KERNEL_STATE"), + } + } + + /// Return if the kernel is init state. + pub fn is_init(&self) -> bool { + self.state() == State::Init + } + + /// Transition from Init to SingleCoreMain. + pub fn transition_to_single_core_main(&self) { + if self + .0 + .compare_exchange( + Self::INIT, + Self::SINGLE_CORE_MAIN, + Ordering::Acquire, + Ordering::Relaxed, + ) + .is_err() + { + panic!("transition_to_single_core_main() called while state != Init"); + } + } +} diff --git a/19_kernel_heap/kernel/src/symbols.rs b/19_kernel_heap/kernel/src/symbols.rs new file mode 100644 index 00000000..22001389 --- /dev/null +++ b/19_kernel_heap/kernel/src/symbols.rs @@ -0,0 +1,87 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2022 Andre Richter + +//! Debug symbol support. + +use crate::memory::{Address, Virtual}; +use core::{cell::UnsafeCell, slice}; +use debug_symbol_types::Symbol; + +//-------------------------------------------------------------------------------------------------- +// Private Definitions +//-------------------------------------------------------------------------------------------------- + +// Symbol from the linker script. +extern "Rust" { + static __kernel_symbols_start: UnsafeCell<()>; +} + +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +/// This will be patched to the correct value by the "kernel symbols tool" after linking. This given +/// value here is just a (safe) dummy. +#[no_mangle] +static NUM_KERNEL_SYMBOLS: u64 = 0; + +//-------------------------------------------------------------------------------------------------- +// Private Code +//-------------------------------------------------------------------------------------------------- + +fn kernel_symbol_section_virt_start_addr() -> Address { + Address::new(unsafe { __kernel_symbols_start.get() as usize }) +} + +fn kernel_symbols_slice() -> &'static [Symbol] { + let ptr = kernel_symbol_section_virt_start_addr().as_usize() as *const Symbol; + + unsafe { + let num = core::ptr::read_volatile(&NUM_KERNEL_SYMBOLS as *const u64) as usize; + slice::from_raw_parts(ptr, num) + } +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +/// Retrieve the symbol corresponding to a virtual address, if any. +pub fn lookup_symbol(addr: Address) -> Option<&'static Symbol> { + for i in kernel_symbols_slice() { + if i.contains(addr.as_usize()) { + return Some(i); + } + } + + None +} + +//-------------------------------------------------------------------------------------------------- +// Testing +//-------------------------------------------------------------------------------------------------- + +#[cfg(test)] +mod tests { + use super::*; + use test_macros::kernel_test; + + /// Sanity of symbols module. + #[kernel_test] + fn symbols_sanity() { + let first_sym = lookup_symbol(Address::new( + crate::common::is_aligned as *const usize as usize, + )) + .unwrap() + .name(); + + assert_eq!(first_sym, "libkernel::common::is_aligned"); + + let second_sym = lookup_symbol(Address::new(crate::version as *const usize as usize)) + .unwrap() + .name(); + + assert_eq!(second_sym, "libkernel::version"); + } +} diff --git a/19_kernel_heap/kernel/src/synchronization.rs b/19_kernel_heap/kernel/src/synchronization.rs new file mode 100644 index 00000000..ab2b86e6 --- /dev/null +++ b/19_kernel_heap/kernel/src/synchronization.rs @@ -0,0 +1,159 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2020-2022 Andre Richter + +//! Synchronization primitives. +//! +//! # Resources +//! +//! - +//! - +//! - + +use core::cell::UnsafeCell; + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +/// Synchronization interfaces. +pub mod interface { + + /// Any object implementing this trait guarantees exclusive access to the data wrapped within + /// the Mutex for the duration of the provided closure. + pub trait Mutex { + /// The type of the data that is wrapped by this mutex. + type Data; + + /// Locks the mutex and grants the closure temporary mutable access to the wrapped data. + fn lock<'a, R>(&'a self, f: impl FnOnce(&'a mut Self::Data) -> R) -> R; + } + + /// A reader-writer exclusion type. + /// + /// The implementing object allows either a number of readers or at most one writer at any point + /// in time. + pub trait ReadWriteEx { + /// The type of encapsulated data. + type Data; + + /// Grants temporary mutable access to the encapsulated data. + fn write<'a, R>(&'a self, f: impl FnOnce(&'a mut Self::Data) -> R) -> R; + + /// Grants temporary immutable access to the encapsulated data. + fn read<'a, R>(&'a self, f: impl FnOnce(&'a Self::Data) -> R) -> R; + } +} + +/// A pseudo-lock for teaching purposes. +/// +/// In contrast to a real Mutex implementation, does not protect against concurrent access from +/// other cores to the contained data. This part is preserved for later lessons. +/// +/// The lock will only be used as long as it is safe to do so, i.e. as long as the kernel is +/// executing on a single core. +pub struct IRQSafeNullLock +where + T: ?Sized, +{ + data: UnsafeCell, +} + +/// A pseudo-lock that is RW during the single-core kernel init phase and RO afterwards. +/// +/// Intended to encapsulate data that is populated during kernel init when no concurrency exists. +pub struct InitStateLock +where + T: ?Sized, +{ + data: UnsafeCell, +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +unsafe impl Send for IRQSafeNullLock where T: ?Sized + Send {} +unsafe impl Sync for IRQSafeNullLock where T: ?Sized + Send {} + +impl IRQSafeNullLock { + /// Create an instance. + pub const fn new(data: T) -> Self { + Self { + data: UnsafeCell::new(data), + } + } +} + +unsafe impl Send for InitStateLock where T: ?Sized + Send {} +unsafe impl Sync for InitStateLock where T: ?Sized + Send {} + +impl InitStateLock { + /// Create an instance. + pub const fn new(data: T) -> Self { + Self { + data: UnsafeCell::new(data), + } + } +} + +//------------------------------------------------------------------------------ +// OS Interface Code +//------------------------------------------------------------------------------ +use crate::{exception, state}; + +impl interface::Mutex for IRQSafeNullLock { + type Data = T; + + fn lock<'a, R>(&'a self, f: impl FnOnce(&'a mut Self::Data) -> R) -> R { + // In a real lock, there would be code encapsulating this line that ensures that this + // mutable reference will ever only be given out once at a time. + let data = unsafe { &mut *self.data.get() }; + + // Execute the closure while IRQs are masked. + exception::asynchronous::exec_with_irq_masked(|| f(data)) + } +} + +impl interface::ReadWriteEx for InitStateLock { + type Data = T; + + fn write<'a, R>(&'a self, f: impl FnOnce(&'a mut Self::Data) -> R) -> R { + assert!( + state::state_manager().is_init(), + "InitStateLock::write called after kernel init phase" + ); + assert!( + !exception::asynchronous::is_local_irq_masked(), + "InitStateLock::write called with IRQs unmasked" + ); + + let data = unsafe { &mut *self.data.get() }; + + f(data) + } + + fn read<'a, R>(&'a self, f: impl FnOnce(&'a Self::Data) -> R) -> R { + let data = unsafe { &*self.data.get() }; + + f(data) + } +} + +//-------------------------------------------------------------------------------------------------- +// Testing +//-------------------------------------------------------------------------------------------------- + +#[cfg(test)] +mod tests { + use super::*; + use test_macros::kernel_test; + + /// InitStateLock must be transparent. + #[kernel_test] + fn init_state_lock_is_transparent() { + use core::mem::size_of; + + assert_eq!(size_of::>(), size_of::()); + } +} diff --git a/19_kernel_heap/kernel/src/time.rs b/19_kernel_heap/kernel/src/time.rs new file mode 100644 index 00000000..6d92b196 --- /dev/null +++ b/19_kernel_heap/kernel/src/time.rs @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2020-2022 Andre Richter + +//! Timer primitives. + +#[cfg(target_arch = "aarch64")] +#[path = "_arch/aarch64/time.rs"] +mod arch_time; + +//-------------------------------------------------------------------------------------------------- +// Architectural Public Reexports +//-------------------------------------------------------------------------------------------------- +pub use arch_time::time_manager; + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +/// Timekeeping interfaces. +pub mod interface { + use core::time::Duration; + + /// Time management functions. + pub trait TimeManager { + /// The timer's resolution. + fn resolution(&self) -> Duration; + + /// The uptime since power-on of the device. + /// + /// This includes time consumed by firmware and bootloaders. + fn uptime(&self) -> Duration; + + /// Spin for a given duration. + fn spin_for(&self, duration: Duration); + } +} diff --git a/19_kernel_heap/kernel/tests/00_console_sanity.rb b/19_kernel_heap/kernel/tests/00_console_sanity.rb new file mode 100644 index 00000000..4dde5576 --- /dev/null +++ b/19_kernel_heap/kernel/tests/00_console_sanity.rb @@ -0,0 +1,48 @@ +# frozen_string_literal: true + +# SPDX-License-Identifier: MIT OR Apache-2.0 +# +# Copyright (c) 2019-2022 Andre Richter + +require 'console_io_test' + +# Verify sending and receiving works as expected. +class TxRxHandshakeTest < SubtestBase + def name + 'Transmit and Receive handshake' + end + + def run(qemu_out, qemu_in) + qemu_in.write_nonblock('ABC') + expect_or_raise(qemu_out, 'OK1234') + end +end + +# Check for correct TX statistics implementation. Depends on test 1 being run first. +class TxStatisticsTest < SubtestBase + def name + 'Transmit statistics' + end + + def run(qemu_out, _qemu_in) + expect_or_raise(qemu_out, '6') + end +end + +# Check for correct RX statistics implementation. Depends on test 1 being run first. +class RxStatisticsTest < SubtestBase + def name + 'Receive statistics' + end + + def run(qemu_out, _qemu_in) + expect_or_raise(qemu_out, '3') + end +end + +##-------------------------------------------------------------------------------------------------- +## Test registration +##-------------------------------------------------------------------------------------------------- +def subtest_collection + [TxRxHandshakeTest.new, TxStatisticsTest.new, RxStatisticsTest.new] +end diff --git a/19_kernel_heap/kernel/tests/00_console_sanity.rs b/19_kernel_heap/kernel/tests/00_console_sanity.rs new file mode 100644 index 00000000..305510ce --- /dev/null +++ b/19_kernel_heap/kernel/tests/00_console_sanity.rs @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2019-2022 Andre Richter + +//! Console sanity tests - RX, TX and statistics. + +#![feature(format_args_nl)] +#![no_main] +#![no_std] + +/// Console tests should time out on the I/O harness in case of panic. +mod panic_wait_forever; + +use libkernel::{bsp, console, cpu, driver, exception, memory, print}; + +#[no_mangle] +unsafe fn kernel_init() -> ! { + use console::console; + use driver::interface::DriverManager; + + exception::handling_init(); + memory::init(); + bsp::driver::driver_manager().qemu_bring_up_console(); + + // Handshake + assert_eq!(console().read_char(), 'A'); + assert_eq!(console().read_char(), 'B'); + assert_eq!(console().read_char(), 'C'); + print!("OK1234"); + + // 6 + print!("{}", console().chars_written()); + + // 3 + print!("{}", console().chars_read()); + + // The QEMU process running this test will be closed by the I/O test harness. + cpu::wait_forever(); +} diff --git a/19_kernel_heap/kernel/tests/01_timer_sanity.rs b/19_kernel_heap/kernel/tests/01_timer_sanity.rs new file mode 100644 index 00000000..d5d76a5c --- /dev/null +++ b/19_kernel_heap/kernel/tests/01_timer_sanity.rs @@ -0,0 +1,52 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2019-2022 Andre Richter + +//! Timer sanity tests. + +#![feature(custom_test_frameworks)] +#![no_main] +#![no_std] +#![reexport_test_harness_main = "test_main"] +#![test_runner(libkernel::test_runner)] + +use core::time::Duration; +use libkernel::{bsp, cpu, driver, exception, memory, time, time::interface::TimeManager}; +use test_macros::kernel_test; + +#[no_mangle] +unsafe fn kernel_init() -> ! { + use driver::interface::DriverManager; + + exception::handling_init(); + memory::init(); + bsp::driver::driver_manager().qemu_bring_up_console(); + + // Depending on CPU arch, some timer bring-up code could go here. Not needed for the RPi. + + test_main(); + + cpu::qemu_exit_success() +} + +/// Simple check that the timer is running. +#[kernel_test] +fn timer_is_counting() { + assert!(time::time_manager().uptime().as_nanos() > 0) +} + +/// Timer resolution must be sufficient. +#[kernel_test] +fn timer_resolution_is_sufficient() { + assert!(time::time_manager().resolution().as_nanos() < 100) +} + +/// Sanity check spin_for() implementation. +#[kernel_test] +fn spin_accuracy_check_1_second() { + let t1 = time::time_manager().uptime(); + time::time_manager().spin_for(Duration::from_secs(1)); + let t2 = time::time_manager().uptime(); + + assert_eq!((t2 - t1).as_secs(), 1) +} diff --git a/19_kernel_heap/kernel/tests/02_exception_sync_page_fault.rs b/19_kernel_heap/kernel/tests/02_exception_sync_page_fault.rs new file mode 100644 index 00000000..a6d15b69 --- /dev/null +++ b/19_kernel_heap/kernel/tests/02_exception_sync_page_fault.rs @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2019-2022 Andre Richter + +//! Page faults must result in synchronous exceptions. + +#![feature(format_args_nl)] +#![no_main] +#![no_std] + +/// Overwrites libkernel's `panic_wait::_panic_exit()` so that it returns a "success" code. +/// +/// In this test, reaching the panic is a success, because it is called from the synchronous +/// exception handler, which is what this test wants to achieve. +/// +/// It also means that this integration test can not use any other code that calls panic!() directly +/// or indirectly. +mod panic_exit_success; + +use libkernel::{bsp, cpu, driver, exception, info, memory, println}; + +#[no_mangle] +unsafe fn kernel_init() -> ! { + use driver::interface::DriverManager; + + exception::handling_init(); + memory::init(); + bsp::driver::driver_manager().qemu_bring_up_console(); + + // This line will be printed as the test header. + println!("Testing synchronous exception handling by causing a page fault"); + + info!("Writing to bottom of address space to address 1 GiB..."); + let big_addr: u64 = 1024 * 1024 * 1024; + core::ptr::read_volatile(big_addr as *mut u64); + + // If execution reaches here, the memory access above did not cause a page fault exception. + cpu::qemu_exit_failure() +} diff --git a/19_kernel_heap/kernel/tests/03_exception_restore_sanity.rb b/19_kernel_heap/kernel/tests/03_exception_restore_sanity.rb new file mode 100644 index 00000000..5f52e0c7 --- /dev/null +++ b/19_kernel_heap/kernel/tests/03_exception_restore_sanity.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +# SPDX-License-Identifier: MIT OR Apache-2.0 +# +# Copyright (c) 2022 Andre Richter + +require 'console_io_test' + +# Verify that exception restore works. +class ExceptionRestoreTest < SubtestBase + def name + 'Exception restore' + end + + def run(qemu_out, _qemu_in) + expect_or_raise(qemu_out, 'Back from system call!') + end +end + +##-------------------------------------------------------------------------------------------------- +## Test registration +##-------------------------------------------------------------------------------------------------- +def subtest_collection + [ExceptionRestoreTest.new] +end diff --git a/19_kernel_heap/kernel/tests/03_exception_restore_sanity.rs b/19_kernel_heap/kernel/tests/03_exception_restore_sanity.rs new file mode 100644 index 00000000..47dd2714 --- /dev/null +++ b/19_kernel_heap/kernel/tests/03_exception_restore_sanity.rs @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2022 Andre Richter + +//! A simple sanity test to see if exception restore code works. + +#![feature(format_args_nl)] +#![no_main] +#![no_std] + +/// Console tests should time out on the I/O harness in case of panic. +mod panic_wait_forever; + +use core::arch::asm; +use libkernel::{bsp, cpu, driver, exception, info, memory, println}; + +#[inline(never)] +fn nested_system_call() { + #[cfg(target_arch = "aarch64")] + unsafe { + asm!("svc #0x1337", options(nomem, nostack, preserves_flags)); + } + + #[cfg(not(target_arch = "aarch64"))] + { + info!("Not supported yet"); + cpu::wait_forever(); + } +} + +#[no_mangle] +unsafe fn kernel_init() -> ! { + use driver::interface::DriverManager; + + exception::handling_init(); + memory::init(); + bsp::driver::driver_manager().qemu_bring_up_console(); + + // This line will be printed as the test header. + println!("Testing exception restore"); + + info!("Making a dummy system call"); + + // Calling this inside a function indirectly tests if the link register is restored properly. + nested_system_call(); + + info!("Back from system call!"); + + // The QEMU process running this test will be closed by the I/O test harness. + cpu::wait_forever(); +} diff --git a/19_kernel_heap/kernel/tests/04_exception_irq_sanity.rs b/19_kernel_heap/kernel/tests/04_exception_irq_sanity.rs new file mode 100644 index 00000000..7b9628d5 --- /dev/null +++ b/19_kernel_heap/kernel/tests/04_exception_irq_sanity.rs @@ -0,0 +1,69 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2020-2022 Andre Richter + +//! IRQ handling sanity tests. + +#![feature(custom_test_frameworks)] +#![no_main] +#![no_std] +#![reexport_test_harness_main = "test_main"] +#![test_runner(libkernel::test_runner)] + +use libkernel::{bsp, cpu, driver, exception, memory}; +use test_macros::kernel_test; + +#[no_mangle] +unsafe fn kernel_init() -> ! { + use driver::interface::DriverManager; + + memory::init(); + bsp::driver::driver_manager().qemu_bring_up_console(); + + exception::handling_init(); + exception::asynchronous::local_irq_unmask(); + + test_main(); + + cpu::qemu_exit_success() +} + +/// Check that IRQ masking works. +#[kernel_test] +fn local_irq_mask_works() { + // Precondition: IRQs are unmasked. + assert!(exception::asynchronous::is_local_irq_masked()); + + unsafe { exception::asynchronous::local_irq_mask() }; + assert!(!exception::asynchronous::is_local_irq_masked()); + + // Restore earlier state. + unsafe { exception::asynchronous::local_irq_unmask() }; +} + +/// Check that IRQ unmasking works. +#[kernel_test] +fn local_irq_unmask_works() { + // Precondition: IRQs are masked. + unsafe { exception::asynchronous::local_irq_mask() }; + assert!(!exception::asynchronous::is_local_irq_masked()); + + unsafe { exception::asynchronous::local_irq_unmask() }; + assert!(exception::asynchronous::is_local_irq_masked()); +} + +/// Check that IRQ mask save is saving "something". +#[kernel_test] +fn local_irq_mask_save_works() { + // Precondition: IRQs are unmasked. + assert!(exception::asynchronous::is_local_irq_masked()); + + let first = unsafe { exception::asynchronous::local_irq_mask_save() }; + assert!(!exception::asynchronous::is_local_irq_masked()); + + let second = unsafe { exception::asynchronous::local_irq_mask_save() }; + assert_ne!(first, second); + + unsafe { exception::asynchronous::local_irq_restore(first) }; + assert!(exception::asynchronous::is_local_irq_masked()); +} diff --git a/19_kernel_heap/kernel/tests/05_backtrace_sanity.rb b/19_kernel_heap/kernel/tests/05_backtrace_sanity.rb new file mode 100644 index 00000000..5650f97c --- /dev/null +++ b/19_kernel_heap/kernel/tests/05_backtrace_sanity.rb @@ -0,0 +1,39 @@ +# frozen_string_literal: true + +# SPDX-License-Identifier: MIT OR Apache-2.0 +# +# Copyright (c) 2022 Andre Richter + +require 'console_io_test' + +# Verify that panic produces a backtrace. +class PanicBacktraceTest < SubtestBase + def name + 'Panic produces backtrace' + end + + def run(qemu_out, _qemu_in) + expect_or_raise(qemu_out, 'Kernel panic!') + expect_or_raise(qemu_out, 'Backtrace:') + end +end + +# Verify backtrace correctness. +class BacktraceCorrectnessTest < SubtestBase + def name + 'Backtrace is correct' + end + + def run(qemu_out, _qemu_in) + expect_or_raise(qemu_out, '| core::panicking::panic') + expect_or_raise(qemu_out, '| _05_backtrace_sanity::nested') + expect_or_raise(qemu_out, '| kernel_init') + end +end + +##-------------------------------------------------------------------------------------------------- +## Test registration +##-------------------------------------------------------------------------------------------------- +def subtest_collection + [PanicBacktraceTest.new, BacktraceCorrectnessTest.new] +end diff --git a/19_kernel_heap/kernel/tests/05_backtrace_sanity.rs b/19_kernel_heap/kernel/tests/05_backtrace_sanity.rs new file mode 100644 index 00000000..ea425f68 --- /dev/null +++ b/19_kernel_heap/kernel/tests/05_backtrace_sanity.rs @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2022 Andre Richter + +//! Test if backtracing code detects an invalid frame pointer. + +#![feature(format_args_nl)] +#![no_main] +#![no_std] + +/// Console tests should time out on the I/O harness in case of panic. +mod panic_wait_forever; + +use libkernel::{bsp, cpu, driver, exception, memory}; + +#[inline(never)] +fn nested() { + panic!() +} + +#[no_mangle] +unsafe fn kernel_init() -> ! { + use driver::interface::DriverManager; + + exception::handling_init(); + memory::init(); + bsp::driver::driver_manager().qemu_bring_up_console(); + + nested(); + + // The QEMU process running this test will be closed by the I/O test harness. + cpu::wait_forever() +} diff --git a/19_kernel_heap/kernel/tests/06_backtrace_invalid_frame.rb b/19_kernel_heap/kernel/tests/06_backtrace_invalid_frame.rb new file mode 100644 index 00000000..7601cf97 --- /dev/null +++ b/19_kernel_heap/kernel/tests/06_backtrace_invalid_frame.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +# SPDX-License-Identifier: MIT OR Apache-2.0 +# +# Copyright (c) 2022 Andre Richter + +require 'console_io_test' + +# Test detection of invalid frame pointers. +class InvalidFramePointerTest < SubtestBase + def name + 'Detect invalid frame pointer' + end + + def run(qemu_out, _qemu_in) + expect_or_raise(qemu_out, + /Encountered invalid frame pointer \(.*\) during backtrace/) + end +end + +##-------------------------------------------------------------------------------------------------- +## Test registration +##-------------------------------------------------------------------------------------------------- +def subtest_collection + [InvalidFramePointerTest.new] +end diff --git a/19_kernel_heap/kernel/tests/06_backtrace_invalid_frame.rs b/19_kernel_heap/kernel/tests/06_backtrace_invalid_frame.rs new file mode 100644 index 00000000..8769c7b6 --- /dev/null +++ b/19_kernel_heap/kernel/tests/06_backtrace_invalid_frame.rs @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2022 Andre Richter + +//! Test if backtracing code detects an invalid frame pointer. + +#![feature(format_args_nl)] +#![no_main] +#![no_std] + +/// Console tests should time out on the I/O harness in case of panic. +mod panic_wait_forever; + +use libkernel::{backtrace, bsp, cpu, driver, exception, memory}; + +#[inline(never)] +fn nested() { + unsafe { backtrace::corrupt_previous_frame_addr() }; + + panic!() +} + +#[no_mangle] +unsafe fn kernel_init() -> ! { + use driver::interface::DriverManager; + + exception::handling_init(); + memory::init(); + bsp::driver::driver_manager().qemu_bring_up_console(); + + nested(); + + // The QEMU process running this test will be closed by the I/O test harness. + cpu::wait_forever() +} diff --git a/19_kernel_heap/kernel/tests/07_backtrace_invalid_link.rb b/19_kernel_heap/kernel/tests/07_backtrace_invalid_link.rb new file mode 100644 index 00000000..0fabcf4c --- /dev/null +++ b/19_kernel_heap/kernel/tests/07_backtrace_invalid_link.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +# SPDX-License-Identifier: MIT OR Apache-2.0 +# +# Copyright (c) 2022 Andre Richter + +require 'console_io_test' + +# Test detection of invalid link. +class InvalidLinkTest < SubtestBase + def name + 'Detect invalid link' + end + + def run(qemu_out, _qemu_in) + expect_or_raise(qemu_out, /Link address \(.*\) is not contained in kernel .text section/) + end +end + +##-------------------------------------------------------------------------------------------------- +## Test registration +##-------------------------------------------------------------------------------------------------- +def subtest_collection + [InvalidLinkTest.new] +end diff --git a/19_kernel_heap/kernel/tests/07_backtrace_invalid_link.rs b/19_kernel_heap/kernel/tests/07_backtrace_invalid_link.rs new file mode 100644 index 00000000..28f3cdda --- /dev/null +++ b/19_kernel_heap/kernel/tests/07_backtrace_invalid_link.rs @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2022 Andre Richter + +//! Test if backtracing code detects an invalid link. + +#![feature(format_args_nl)] +#![no_main] +#![no_std] + +/// Console tests should time out on the I/O harness in case of panic. +mod panic_wait_forever; + +use libkernel::{backtrace, bsp, cpu, driver, exception, memory}; + +#[inline(never)] +fn nested_2() -> &'static str { + unsafe { backtrace::corrupt_link() }; + libkernel::println!("{}", libkernel::backtrace::Backtrace); + "foo" +} + +#[inline(never)] +fn nested_1() { + libkernel::println!("{}", nested_2()) +} + +#[no_mangle] +unsafe fn kernel_init() -> ! { + use driver::interface::DriverManager; + + exception::handling_init(); + memory::init(); + bsp::driver::driver_manager().qemu_bring_up_console(); + + nested_1(); + + // The QEMU process running this test will be closed by the I/O test harness. + cpu::wait_forever() +} diff --git a/19_kernel_heap/kernel/tests/boot_test_string.rb b/19_kernel_heap/kernel/tests/boot_test_string.rb new file mode 100644 index 00000000..f778b3d8 --- /dev/null +++ b/19_kernel_heap/kernel/tests/boot_test_string.rb @@ -0,0 +1,3 @@ +# frozen_string_literal: true + +EXPECTED_PRINT = 'Echoing input now' diff --git a/19_kernel_heap/kernel/tests/panic_exit_success/mod.rs b/19_kernel_heap/kernel/tests/panic_exit_success/mod.rs new file mode 100644 index 00000000..908fac51 --- /dev/null +++ b/19_kernel_heap/kernel/tests/panic_exit_success/mod.rs @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2019-2022 Andre Richter + +/// Overwrites libkernel's `panic_wait::_panic_exit()` with the QEMU-exit version. +#[no_mangle] +fn _panic_exit() -> ! { + libkernel::cpu::qemu_exit_success() +} diff --git a/19_kernel_heap/kernel/tests/panic_wait_forever/mod.rs b/19_kernel_heap/kernel/tests/panic_wait_forever/mod.rs new file mode 100644 index 00000000..7a4effa5 --- /dev/null +++ b/19_kernel_heap/kernel/tests/panic_wait_forever/mod.rs @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2022 Andre Richter + +/// Overwrites libkernel's `panic_wait::_panic_exit()` with wait_forever. +#[no_mangle] +fn _panic_exit() -> ! { + libkernel::cpu::wait_forever() +} diff --git a/19_kernel_heap/kernel_symbols.mk b/19_kernel_heap/kernel_symbols.mk new file mode 100644 index 00000000..5b51ccfe --- /dev/null +++ b/19_kernel_heap/kernel_symbols.mk @@ -0,0 +1,103 @@ +## SPDX-License-Identifier: MIT OR Apache-2.0 +## +## Copyright (c) 2018-2022 Andre Richter + +include ../common/format.mk +include ../common/docker.mk + +##-------------------------------------------------------------------------------------------------- +## Check for input variables that need be exported by the calling Makefile +##-------------------------------------------------------------------------------------------------- +ifndef KERNEL_SYMBOLS_TOOL_PATH +$(error KERNEL_SYMBOLS_TOOL_PATH is not set) +endif + +ifndef TARGET +$(error TARGET is not set) +endif + +ifndef KERNEL_SYMBOLS_INPUT_ELF +$(error KERNEL_SYMBOLS_INPUT_ELF is not set) +endif + +ifndef KERNEL_SYMBOLS_OUTPUT_ELF +$(error KERNEL_SYMBOLS_OUTPUT_ELF is not set) +endif + + + +##-------------------------------------------------------------------------------------------------- +## Targets and Prerequisites +##-------------------------------------------------------------------------------------------------- +KERNEL_SYMBOLS_MANIFEST = kernel_symbols/Cargo.toml +KERNEL_SYMBOLS_LINKER_SCRIPT = kernel_symbols/kernel_symbols.ld + +KERNEL_SYMBOLS_RS = $(KERNEL_SYMBOLS_INPUT_ELF)_symbols.rs +KERNEL_SYMBOLS_DEMANGLED_RS = $(shell pwd)/$(KERNEL_SYMBOLS_INPUT_ELF)_symbols_demangled.rs + +KERNEL_SYMBOLS_ELF = target/$(TARGET)/release/kernel_symbols +KERNEL_SYMBOLS_STRIPPED = target/$(TARGET)/release/kernel_symbols_stripped + +# Export for build.rs of kernel_symbols crate. +export KERNEL_SYMBOLS_DEMANGLED_RS + + + +##-------------------------------------------------------------------------------------------------- +## Command building blocks +##-------------------------------------------------------------------------------------------------- +GET_SYMBOLS_SECTION_VIRT_ADDR = $(DOCKER_TOOLS) $(EXEC_SYMBOLS_TOOL) \ + --get_symbols_section_virt_addr $(KERNEL_SYMBOLS_OUTPUT_ELF) + +RUSTFLAGS = -C link-arg=--script=$(KERNEL_SYMBOLS_LINKER_SCRIPT) \ + -C link-arg=--section-start=.rodata=$$($(GET_SYMBOLS_SECTION_VIRT_ADDR)) + +RUSTFLAGS_PEDANTIC = $(RUSTFLAGS) \ + -D warnings \ + -D missing_docs + +COMPILER_ARGS = --target=$(TARGET) \ + --release + +RUSTC_CMD = cargo rustc $(COMPILER_ARGS) --manifest-path $(KERNEL_SYMBOLS_MANIFEST) +OBJCOPY_CMD = rust-objcopy \ + --strip-all \ + -O binary + +EXEC_SYMBOLS_TOOL = ruby $(KERNEL_SYMBOLS_TOOL_PATH)/main.rb + +##------------------------------------------------------------------------------ +## Dockerization +##------------------------------------------------------------------------------ +DOCKER_CMD = docker run -t --rm -v $(shell pwd):/work/tutorial -w /work/tutorial + +# DOCKER_IMAGE defined in include file (see top of this file). +DOCKER_TOOLS = $(DOCKER_CMD) $(DOCKER_IMAGE) + + + +##-------------------------------------------------------------------------------------------------- +## Targets +##-------------------------------------------------------------------------------------------------- +.PHONY: all + +all: + @cp $(KERNEL_SYMBOLS_INPUT_ELF) $(KERNEL_SYMBOLS_OUTPUT_ELF) + + @$(DOCKER_TOOLS) $(EXEC_SYMBOLS_TOOL) --gen_symbols $(KERNEL_SYMBOLS_OUTPUT_ELF) \ + $(KERNEL_SYMBOLS_RS) + + $(call color_progress_prefix, "Demangling") + @echo Symbol names + @cat $(KERNEL_SYMBOLS_RS) | rustfilt > $(KERNEL_SYMBOLS_DEMANGLED_RS) + + @RUSTFLAGS="$(RUSTFLAGS_PEDANTIC)" $(RUSTC_CMD) + + $(call color_progress_prefix, "Stripping") + @echo Symbols ELF file + @$(OBJCOPY_CMD) $(KERNEL_SYMBOLS_ELF) $(KERNEL_SYMBOLS_STRIPPED) + + @$(DOCKER_TOOLS) $(EXEC_SYMBOLS_TOOL) --patch_data $(KERNEL_SYMBOLS_OUTPUT_ELF) \ + $(KERNEL_SYMBOLS_STRIPPED) + + $(call color_progress_prefix, "Finished") diff --git a/19_kernel_heap/kernel_symbols/Cargo.lock b/19_kernel_heap/kernel_symbols/Cargo.lock new file mode 100644 index 00000000..70b7fa66 --- /dev/null +++ b/19_kernel_heap/kernel_symbols/Cargo.lock @@ -0,0 +1,14 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "debug-symbol-types" +version = "0.1.0" + +[[package]] +name = "kernel_symbols" +version = "0.1.0" +dependencies = [ + "debug-symbol-types", +] diff --git a/19_kernel_heap/kernel_symbols/Cargo.toml b/19_kernel_heap/kernel_symbols/Cargo.toml new file mode 100644 index 00000000..3407aa7e --- /dev/null +++ b/19_kernel_heap/kernel_symbols/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "kernel_symbols" +version = "0.1.0" +edition = "2021" + +[features] +default = [] +generated_symbols_available = [] + +##-------------------------------------------------------------------------------------------------- +## Dependencies +##-------------------------------------------------------------------------------------------------- + +[dependencies] +debug-symbol-types = { path = "../libraries/debug-symbol-types" } diff --git a/19_kernel_heap/kernel_symbols/build.rs b/19_kernel_heap/kernel_symbols/build.rs new file mode 100644 index 00000000..5062df44 --- /dev/null +++ b/19_kernel_heap/kernel_symbols/build.rs @@ -0,0 +1,14 @@ +use std::{env, path::Path}; + +fn main() { + if let Ok(path) = env::var("KERNEL_SYMBOLS_DEMANGLED_RS") { + if Path::new(&path).exists() { + println!("cargo:rustc-cfg=feature=\"generated_symbols_available\"") + } + } + + println!( + "cargo:rerun-if-changed={}", + Path::new("kernel_symbols.ld").display() + ); +} diff --git a/19_kernel_heap/kernel_symbols/kernel_symbols.ld b/19_kernel_heap/kernel_symbols/kernel_symbols.ld new file mode 100644 index 00000000..0625f008 --- /dev/null +++ b/19_kernel_heap/kernel_symbols/kernel_symbols.ld @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: MIT OR Apache-2.0 + * + * Copyright (c) 2022 Andre Richter + */ + +SECTIONS +{ + .rodata : { + ASSERT(. > 0xffffffff00000000, "Expected higher half address") + + KEEP(*(.rodata.symbol_desc*)) + . = ALIGN(8); + *(.rodata*) + } +} diff --git a/19_kernel_heap/kernel_symbols/src/main.rs b/19_kernel_heap/kernel_symbols/src/main.rs new file mode 100644 index 00000000..bd90b535 --- /dev/null +++ b/19_kernel_heap/kernel_symbols/src/main.rs @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2022 Andre Richter + +//! Generation of kernel symbols. + +#![no_std] +#![no_main] + +#[cfg(feature = "generated_symbols_available")] +include!(env!("KERNEL_SYMBOLS_DEMANGLED_RS")); + +#[panic_handler] +fn panic(_info: &core::panic::PanicInfo) -> ! { + unimplemented!() +} diff --git a/19_kernel_heap/libraries/debug-symbol-types/Cargo.toml b/19_kernel_heap/libraries/debug-symbol-types/Cargo.toml new file mode 100644 index 00000000..e5b1fd1f --- /dev/null +++ b/19_kernel_heap/libraries/debug-symbol-types/Cargo.toml @@ -0,0 +1,4 @@ +[package] +name = "debug-symbol-types" +version = "0.1.0" +edition = "2021" diff --git a/19_kernel_heap/libraries/debug-symbol-types/src/lib.rs b/19_kernel_heap/libraries/debug-symbol-types/src/lib.rs new file mode 100644 index 00000000..b6dff082 --- /dev/null +++ b/19_kernel_heap/libraries/debug-symbol-types/src/lib.rs @@ -0,0 +1,45 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2022 Andre Richter + +//! Types for implementing debug symbol support. + +#![no_std] + +use core::ops::Range; + +/// A symbol containing a size. +#[repr(C)] +#[derive(Clone)] +pub struct Symbol { + addr_range: Range, + name: &'static str, +} + +impl Symbol { + /// Create an instance. + pub const fn new(start: usize, size: usize, name: &'static str) -> Symbol { + Symbol { + addr_range: Range { + start, + end: start + size, + }, + name, + } + } + + /// Returns true if addr is contained in the range. + pub fn contains(&self, addr: usize) -> bool { + self.addr_range.contains(&addr) + } + + /// Returns the symbol's name. + pub fn name(&self) -> &'static str { + self.name + } + + /// Returns the symbol's size. + pub fn size(&self) -> usize { + self.addr_range.end - self.addr_range.start + } +} diff --git a/19_kernel_heap/libraries/test-macros/Cargo.toml b/19_kernel_heap/libraries/test-macros/Cargo.toml new file mode 100644 index 00000000..fff98a1f --- /dev/null +++ b/19_kernel_heap/libraries/test-macros/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "test-macros" +version = "0.1.0" +authors = ["Andre Richter "] +edition = "2021" + +[lib] +proc-macro = true + +[dependencies] +proc-macro2 = "1.x" +quote = "1.x" +syn = { version = "1.x", features = ["full"] } +test-types = { path = "../test-types" } diff --git a/19_kernel_heap/libraries/test-macros/src/lib.rs b/19_kernel_heap/libraries/test-macros/src/lib.rs new file mode 100644 index 00000000..9879677c --- /dev/null +++ b/19_kernel_heap/libraries/test-macros/src/lib.rs @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2019-2022 Andre Richter + +use proc_macro::TokenStream; +use proc_macro2::Span; +use quote::quote; +use syn::{parse_macro_input, Ident, ItemFn}; + +#[proc_macro_attribute] +pub fn kernel_test(_attr: TokenStream, input: TokenStream) -> TokenStream { + let f = parse_macro_input!(input as ItemFn); + + let test_name = &format!("{}", f.sig.ident); + let test_ident = Ident::new( + &format!("{}_TEST_CONTAINER", f.sig.ident.to_string().to_uppercase()), + Span::call_site(), + ); + let test_code_block = f.block; + + quote!( + #[test_case] + const #test_ident: test_types::UnitTest = test_types::UnitTest { + name: #test_name, + test_func: || #test_code_block, + }; + ) + .into() +} diff --git a/19_kernel_heap/libraries/test-types/Cargo.toml b/19_kernel_heap/libraries/test-types/Cargo.toml new file mode 100644 index 00000000..2f20f060 --- /dev/null +++ b/19_kernel_heap/libraries/test-types/Cargo.toml @@ -0,0 +1,5 @@ +[package] +name = "test-types" +version = "0.1.0" +authors = ["Andre Richter "] +edition = "2021" diff --git a/19_kernel_heap/libraries/test-types/src/lib.rs b/19_kernel_heap/libraries/test-types/src/lib.rs new file mode 100644 index 00000000..922c2a1c --- /dev/null +++ b/19_kernel_heap/libraries/test-types/src/lib.rs @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2019-2022 Andre Richter + +//! Types for the `custom_test_frameworks` implementation. + +#![no_std] + +/// Unit test container. +pub struct UnitTest { + /// Name of the test. + pub name: &'static str, + + /// Function pointer to the test. + pub test_func: fn(), +} diff --git a/19_kernel_heap/tools/kernel_symbols_tool/cmds.rb b/19_kernel_heap/tools/kernel_symbols_tool/cmds.rb new file mode 100644 index 00000000..fe66ea71 --- /dev/null +++ b/19_kernel_heap/tools/kernel_symbols_tool/cmds.rb @@ -0,0 +1,45 @@ +# frozen_string_literal: true + +# SPDX-License-Identifier: MIT OR Apache-2.0 +# +# Copyright (c) 2022 Andre Richter + +def generate_symbols(kernel_elf, output_file) + File.open(output_file, 'w') do |file| + header = <<~HEREDOC + use debug_symbol_types::Symbol; + + # [no_mangle] + # [link_section = ".rodata.symbol_desc"] + static KERNEL_SYMBOLS: [Symbol; #{kernel_elf.num_symbols}] = [ + HEREDOC + + file.write(header) + kernel_elf.symbols.each do |sym| + value = sym.header.st_value + size = sym.header.st_size + name = sym.name + + file.write(" Symbol::new(#{value}, #{size}, \"#{name}\"),\n") + end + file.write("];\n") + end +end + +def get_symbols_section_virt_addr(kernel_elf) + kernel_elf.kernel_symbols_section_virt_addr +end + +def patch_symbol_data(kernel_elf, symbols_blob_path) + symbols_blob = File.binread(symbols_blob_path) + + raise if symbols_blob.size > kernel_elf.kernel_symbols_section_size + + File.binwrite(kernel_elf.path, File.binread(symbols_blob_path), + kernel_elf.kernel_symbols_section_offset_in_file) +end + +def patch_num_symbols(kernel_elf) + num_packed = [kernel_elf.num_symbols].pack('Q<*') # "Q" == uint64_t, "<" == little endian + File.binwrite(kernel_elf.path, num_packed, kernel_elf.num_kernel_symbols_offset_in_file) +end diff --git a/19_kernel_heap/tools/kernel_symbols_tool/kernel_elf.rb b/19_kernel_heap/tools/kernel_symbols_tool/kernel_elf.rb new file mode 100644 index 00000000..b1649767 --- /dev/null +++ b/19_kernel_heap/tools/kernel_symbols_tool/kernel_elf.rb @@ -0,0 +1,74 @@ +# frozen_string_literal: true + +# SPDX-License-Identifier: MIT OR Apache-2.0 +# +# Copyright (c) 2021-2022 Andre Richter + +# KernelELF +class KernelELF + attr_reader :path + + def initialize(kernel_elf_path, kernel_symbols_section, num_kernel_symbols) + @elf = ELFTools::ELFFile.new(File.open(kernel_elf_path)) + @symtab_section = @elf.section_by_name('.symtab') + + @path = kernel_elf_path + fetch_values(kernel_symbols_section, num_kernel_symbols) + end + + private + + def fetch_values(kernel_symbols_section, num_kernel_symbols) + sym = @symtab_section.symbol_by_name(num_kernel_symbols) + raise "Symbol \"#{num_kernel_symbols}\" not found" if sym.nil? + + @num_kernel_symbols = sym + + section = @elf.section_by_name(kernel_symbols_section) + raise "Section \"#{kernel_symbols_section}\" not found" if section.nil? + + @kernel_symbols_section = section + end + + def num_kernel_symbols_virt_addr + @num_kernel_symbols.header.st_value + end + + def segment_containing_virt_addr(virt_addr) + @elf.each_segments do |segment| + return segment if segment.vma_in?(virt_addr) + end + end + + def virt_addr_to_file_offset(virt_addr) + segment = segment_containing_virt_addr(virt_addr) + segment.vma_to_offset(virt_addr) + end + + public + + def symbols + non_zero_symbols = @symtab_section.symbols.reject { |sym| sym.header.st_size.zero? } + non_zero_symbols.sort_by { |sym| sym.header.st_value } + end + + def num_symbols + symbols.size + end + + def kernel_symbols_section_virt_addr + @kernel_symbols_section.header.sh_addr.to_i + end + + def kernel_symbols_section_size + @kernel_symbols_section.header.sh_size.to_i + end + + def kernel_symbols_section_offset_in_file + virt_addr_to_file_offset(kernel_symbols_section_virt_addr) + end + + def num_kernel_symbols_offset_in_file + virt_addr_to_file_offset(num_kernel_symbols_virt_addr) + end +end diff --git a/19_kernel_heap/tools/kernel_symbols_tool/main.rb b/19_kernel_heap/tools/kernel_symbols_tool/main.rb new file mode 100755 index 00000000..30a8be6f --- /dev/null +++ b/19_kernel_heap/tools/kernel_symbols_tool/main.rb @@ -0,0 +1,47 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +# SPDX-License-Identifier: MIT OR Apache-2.0 +# +# Copyright (c) 2022 Andre Richter + +require 'rubygems' +require 'bundler/setup' +require 'colorize' +require 'elftools' + +require_relative 'kernel_elf' +require_relative 'cmds' + +KERNEL_SYMBOLS_SECTION = '.kernel_symbols' +NUM_KERNEL_SYMBOLS = 'NUM_KERNEL_SYMBOLS' + +cmd = ARGV[0] + +kernel_elf_path = ARGV[1] +kernel_elf = KernelELF.new(kernel_elf_path, KERNEL_SYMBOLS_SECTION, NUM_KERNEL_SYMBOLS) + +case cmd +when '--gen_symbols' + output_file = ARGV[2] + + print 'Generating'.rjust(12).green.bold + puts ' Symbols source file' + + generate_symbols(kernel_elf, output_file) +when '--get_symbols_section_virt_addr' + addr = get_symbols_section_virt_addr(kernel_elf) + + puts "0x#{addr.to_s(16)}" +when '--patch_data' + symbols_blob_path = ARGV[2] + num_symbols = kernel_elf.num_symbols + + print 'Patching'.rjust(12).green.bold + puts " Symbols blob and number of symbols (#{num_symbols}) into ELF" + + patch_symbol_data(kernel_elf, symbols_blob_path) + patch_num_symbols(kernel_elf) +else + raise +end diff --git a/19_kernel_heap/tools/translation_table_tool/arch.rb b/19_kernel_heap/tools/translation_table_tool/arch.rb new file mode 100644 index 00000000..deceb6d0 --- /dev/null +++ b/19_kernel_heap/tools/translation_table_tool/arch.rb @@ -0,0 +1,314 @@ +# frozen_string_literal: true + +# SPDX-License-Identifier: MIT OR Apache-2.0 +# +# Copyright (c) 2021-2022 Andre Richter + +# Bitfield manipulation. +class BitField + def initialize + @value = 0 + end + + def self.attr_bitfield(name, offset, num_bits) + define_method("#{name}=") do |bits| + mask = (2**num_bits) - 1 + + raise "Input out of range: #{name} = 0x#{bits.to_s(16)}" if (bits & ~mask).positive? + + # Clear bitfield + @value &= ~(mask << offset) + + # Set it + @value |= (bits << offset) + end + end + + def to_i + @value + end + + def size_in_byte + 8 + end +end + +# An array class that knows its memory location. +class CArray < Array + attr_reader :phys_start_addr + + def initialize(phys_start_addr, size, &block) + @phys_start_addr = phys_start_addr + + super(size, &block) + end + + def size_in_byte + inject(0) { |sum, n| sum + n.size_in_byte } + end +end + +#--------------------------------------------------------------------------------------------------- +# Arch:: +#--------------------------------------------------------------------------------------------------- +module Arch +#--------------------------------------------------------------------------------------------------- +# Arch::ARMv8 +#--------------------------------------------------------------------------------------------------- +module ARMv8 +# ARMv8 Table Descriptor. +class Stage1TableDescriptor < BitField + module NextLevelTableAddr + OFFSET = 16 + NUMBITS = 32 + end + + module Type + OFFSET = 1 + NUMBITS = 1 + + BLOCK = 0 + TABLE = 1 + end + + module Valid + OFFSET = 0 + NUMBITS = 1 + + FALSE = 0 + TRUE = 1 + end + + attr_bitfield(:__next_level_table_addr, NextLevelTableAddr::OFFSET, NextLevelTableAddr::NUMBITS) + attr_bitfield(:type, Type::OFFSET, Type::NUMBITS) + attr_bitfield(:valid, Valid::OFFSET, Valid::NUMBITS) + + def next_level_table_addr=(addr) + addr = addr >> Granule64KiB::SHIFT + + self.__next_level_table_addr = addr + end + + private :__next_level_table_addr= +end + +# ARMv8 level 3 page descriptor. +class Stage1PageDescriptor < BitField + module UXN + OFFSET = 54 + NUMBITS = 1 + + FALSE = 0 + TRUE = 1 + end + + module PXN + OFFSET = 53 + NUMBITS = 1 + + FALSE = 0 + TRUE = 1 + end + + module OutputAddr + OFFSET = 16 + NUMBITS = 32 + end + + module AF + OFFSET = 10 + NUMBITS = 1 + + FALSE = 0 + TRUE = 1 + end + + module SH + OFFSET = 8 + NUMBITS = 2 + + INNER_SHAREABLE = 0b11 + end + + module AP + OFFSET = 6 + NUMBITS = 2 + + RW_EL1 = 0b00 + RO_EL1 = 0b10 + end + + module AttrIndx + OFFSET = 2 + NUMBITS = 3 + end + + module Type + OFFSET = 1 + NUMBITS = 1 + + RESERVED_INVALID = 0 + PAGE = 1 + end + + module Valid + OFFSET = 0 + NUMBITS = 1 + + FALSE = 0 + TRUE = 1 + end + + attr_bitfield(:uxn, UXN::OFFSET, UXN::NUMBITS) + attr_bitfield(:pxn, PXN::OFFSET, PXN::NUMBITS) + attr_bitfield(:__output_addr, OutputAddr::OFFSET, OutputAddr::NUMBITS) + attr_bitfield(:af, AF::OFFSET, AF::NUMBITS) + attr_bitfield(:sh, SH::OFFSET, SH::NUMBITS) + attr_bitfield(:ap, AP::OFFSET, AP::NUMBITS) + attr_bitfield(:attr_indx, AttrIndx::OFFSET, AttrIndx::NUMBITS) + attr_bitfield(:type, Type::OFFSET, Type::NUMBITS) + attr_bitfield(:valid, Valid::OFFSET, Valid::NUMBITS) + + def output_addr=(addr) + addr = addr >> Granule64KiB::SHIFT + + self.__output_addr = addr + end + + private :__output_addr= +end + +# Translation table representing the structure defined in translation_table.rs. +class TranslationTable + module MAIR + NORMAL = 1 + end + + def initialize + do_sanity_checks + + num_lvl2_tables = BSP.kernel_virt_addr_space_size >> Granule512MiB::SHIFT + + @lvl3 = new_lvl3(num_lvl2_tables, BSP.phys_addr_of_kernel_tables) + + @lvl2_phys_start_addr = @lvl3.phys_start_addr + @lvl3.size_in_byte + @lvl2 = new_lvl2(num_lvl2_tables, @lvl2_phys_start_addr) + + populate_lvl2_entries + end + + def map_at(virt_region, phys_region, attributes) + return if virt_region.empty? + + raise if virt_region.size != phys_region.size + raise if phys_region.last > BSP.phys_addr_space_end_page + + virt_region.zip(phys_region).each do |virt_page, phys_page| + desc = page_descriptor_from(virt_page) + set_lvl3_entry(desc, phys_page, attributes) + end + end + + def to_binary + data = @lvl3.flatten.map(&:to_i) + @lvl2.map(&:to_i) + data.pack('Q<*') # "Q" == uint64_t, "<" == little endian + end + + def phys_tables_base_addr_binary + [@lvl2_phys_start_addr].pack('Q<*') # "Q" == uint64_t, "<" == little endian + end + + def phys_tables_base_addr + @lvl2_phys_start_addr + end + + private + + def do_sanity_checks + raise unless BSP.kernel_granule::SIZE == Granule64KiB::SIZE + raise unless (BSP.kernel_virt_addr_space_size % Granule512MiB::SIZE).zero? + end + + def new_lvl3(num_lvl2_tables, start_addr) + CArray.new(start_addr, num_lvl2_tables) do + temp = CArray.new(start_addr, 8192) do + Stage1PageDescriptor.new + end + start_addr += temp.size_in_byte + + temp + end + end + + def new_lvl2(num_lvl2_tables, start_addr) + CArray.new(start_addr, num_lvl2_tables) do + Stage1TableDescriptor.new + end + end + + def populate_lvl2_entries + @lvl2.each_with_index do |descriptor, i| + descriptor.next_level_table_addr = @lvl3[i].phys_start_addr + descriptor.type = Stage1TableDescriptor::Type::TABLE + descriptor.valid = Stage1TableDescriptor::Valid::TRUE + end + end + + def lvl2_lvl3_index_from(addr) + addr -= BSP.kernel_virt_start_addr + + lvl2_index = addr >> Granule512MiB::SHIFT + lvl3_index = (addr & Granule512MiB::MASK) >> Granule64KiB::SHIFT + + raise unless lvl2_index < @lvl2.size + + [lvl2_index, lvl3_index] + end + + def page_descriptor_from(virt_addr) + lvl2_index, lvl3_index = lvl2_lvl3_index_from(virt_addr) + + @lvl3[lvl2_index][lvl3_index] + end + + # rubocop:disable Metrics/MethodLength + def set_attributes(desc, attributes) + case attributes.mem_attributes + when :CacheableDRAM + desc.sh = Stage1PageDescriptor::SH::INNER_SHAREABLE + desc.attr_indx = MAIR::NORMAL + else + raise 'Invalid input' + end + + desc.ap = case attributes.acc_perms + when :ReadOnly + Stage1PageDescriptor::AP::RO_EL1 + when :ReadWrite + Stage1PageDescriptor::AP::RW_EL1 + else + raise 'Invalid input' + + end + + desc.pxn = if attributes.execute_never + Stage1PageDescriptor::PXN::TRUE + else + Stage1PageDescriptor::PXN::FALSE + end + + desc.uxn = Stage1PageDescriptor::UXN::TRUE + end + # rubocop:enable Metrics/MethodLength + + def set_lvl3_entry(desc, output_addr, attributes) + desc.output_addr = output_addr + desc.af = Stage1PageDescriptor::AF::TRUE + desc.type = Stage1PageDescriptor::Type::PAGE + desc.valid = Stage1PageDescriptor::Valid::TRUE + + set_attributes(desc, attributes) + end +end +end +end diff --git a/19_kernel_heap/tools/translation_table_tool/bsp.rb b/19_kernel_heap/tools/translation_table_tool/bsp.rb new file mode 100644 index 00000000..dbab5ab6 --- /dev/null +++ b/19_kernel_heap/tools/translation_table_tool/bsp.rb @@ -0,0 +1,54 @@ +# frozen_string_literal: true + +# SPDX-License-Identifier: MIT OR Apache-2.0 +# +# Copyright (c) 2021-2022 Andre Richter + +# Raspberry Pi 3 + 4 +class RaspberryPi + attr_reader :kernel_granule, :kernel_virt_addr_space_size, :kernel_virt_start_addr + + MEMORY_SRC = File.read('kernel/src/bsp/raspberrypi/memory.rs').split("\n") + + def initialize + @kernel_granule = Granule64KiB + + @kernel_virt_addr_space_size = KERNEL_ELF.symbol_value('__kernel_virt_addr_space_size') + @kernel_virt_start_addr = KERNEL_ELF.symbol_value('__kernel_virt_start_addr') + + @virt_addr_of_kernel_tables = KERNEL_ELF.symbol_value('KERNEL_TABLES') + @virt_addr_of_phys_kernel_tables_base_addr = KERNEL_ELF.symbol_value( + 'PHYS_KERNEL_TABLES_BASE_ADDR' + ) + end + + def phys_addr_of_kernel_tables + KERNEL_ELF.virt_to_phys(@virt_addr_of_kernel_tables) + end + + def kernel_tables_offset_in_file + KERNEL_ELF.virt_addr_to_file_offset(@virt_addr_of_kernel_tables) + end + + def phys_kernel_tables_base_addr_offset_in_file + KERNEL_ELF.virt_addr_to_file_offset(@virt_addr_of_phys_kernel_tables_base_addr) + end + + def phys_addr_space_end_page + x = MEMORY_SRC.grep(/pub const END/) + x = case BSP_TYPE + when :rpi3 + x[0] + when :rpi4 + x[1] + else + raise + end + + # Extract the hex literal with underscores like 0x0123_abcd. + x = x.scan(/0x[\h_]*/)[0] + + # Further remove x and _ and convert to int. + x.scan(/\h+/).join.to_i(16) + end +end diff --git a/19_kernel_heap/tools/translation_table_tool/generic.rb b/19_kernel_heap/tools/translation_table_tool/generic.rb new file mode 100644 index 00000000..eee8ccda --- /dev/null +++ b/19_kernel_heap/tools/translation_table_tool/generic.rb @@ -0,0 +1,189 @@ +# frozen_string_literal: true + +# SPDX-License-Identifier: MIT OR Apache-2.0 +# +# Copyright (c) 2021-2022 Andre Richter + +module Granule64KiB + SIZE = 64 * 1024 + SHIFT = Math.log2(SIZE).to_i +end + +module Granule512MiB + SIZE = 512 * 1024 * 1024 + SHIFT = Math.log2(SIZE).to_i + MASK = SIZE - 1 +end + +# Monkey-patch Integer with some helper functions. +class Integer + def power_of_two? + self[0].zero? + end + + def aligned?(alignment) + raise unless alignment.power_of_two? + + (self & (alignment - 1)).zero? + end + + def align_up(alignment) + raise unless alignment.power_of_two? + + (self + alignment - 1) & ~(alignment - 1) + end + + def to_hex_underscore(with_leading_zeros: false) + fmt = with_leading_zeros ? '%016x' : '%x' + value = format(fmt, self).to_s.reverse.scan(/.{4}|.+/).join('_').reverse + + format('0x%s', value) + end +end + +# An array where each value is the start address of a Page. +class MemoryRegion < Array + def initialize(start_addr, size, granule_size) + raise unless start_addr.aligned?(granule_size) + raise unless size.positive? + raise unless (size % granule_size).zero? + + num_pages = size / granule_size + super(num_pages) do |i| + (i * granule_size) + start_addr + end + end +end + +# Collection of memory attributes. +class AttributeFields + attr_reader :mem_attributes, :acc_perms, :execute_never + + def initialize(mem_attributes, acc_perms, execute_never) + @mem_attributes = mem_attributes + @acc_perms = acc_perms + @execute_never = execute_never + end + + def to_s + x = case @mem_attributes + when :CacheableDRAM + 'C' + else + '?' + end + + y = case @acc_perms + when :ReadWrite + 'RW' + when :ReadOnly + 'RO' + else + '??' + end + + z = @execute_never ? 'XN' : 'X ' + + "#{x} #{y} #{z}" + end +end + +# A container that describes a virt-to-phys region mapping. +class MappingDescriptor + @max_section_name_length = 'Sections'.length + + class << self + attr_accessor :max_section_name_length + + def update_max_section_name_length(length) + @max_section_name_length = [@max_section_name_length, length].max + end + end + + attr_reader :name, :virt_region, :phys_region, :attributes + + def initialize(name, virt_region, phys_region, attributes) + @name = name + @virt_region = virt_region + @phys_region = phys_region + @attributes = attributes + end + + def size_human_readable(size) + if size >= (1024 * 1024) + "#{(size / (1024 * 1024)).to_s.rjust(3)} MiB" + elsif size >= 1024 + "#{(size / 1024).to_s.rjust(3)} KiB" + else + raise + end + end + + def to_s + name = @name.ljust(self.class.max_section_name_length) + virt_start = @virt_region.first.to_hex_underscore(with_leading_zeros: true) + phys_start = @phys_region.first.to_hex_underscore(with_leading_zeros: true) + size = size_human_readable(@virt_region.size * 65_536) + + "#{name} | #{virt_start} | #{phys_start} | #{size} | #{@attributes}" + end + + def self.print_divider + print ' ' + print '-' * max_section_name_length + puts '--------------------------------------------------------------------' + end + + def self.print_header + print_divider + print ' ' + print 'Sections'.center(max_section_name_length) + print ' ' + print 'Virt Start Addr'.center(21) + print ' ' + print 'Phys Start Addr'.center(21) + print ' ' + print 'Size'.center(7) + print ' ' + print 'Attr'.center(7) + puts + print_divider + end +end + +def kernel_map_binary + mapping_descriptors = KERNEL_ELF.generate_mapping_descriptors + + # Generate_mapping_descriptors updates the header being printed with this call. So it must come + # afterwards. + MappingDescriptor.print_header + + mapping_descriptors.each do |i| + print 'Generating'.rjust(12).green.bold + print ' ' + puts i.to_s + + TRANSLATION_TABLES.map_at(i.virt_region, i.phys_region, i.attributes) + end + + MappingDescriptor.print_divider +end + +def kernel_patch_tables(kernel_elf_path) + print 'Patching'.rjust(12).green.bold + print ' Kernel table struct at ELF file offset ' + puts BSP.kernel_tables_offset_in_file.to_hex_underscore + + File.binwrite(kernel_elf_path, TRANSLATION_TABLES.to_binary, BSP.kernel_tables_offset_in_file) +end + +def kernel_patch_base_addr(kernel_elf_path) + print 'Patching'.rjust(12).green.bold + print ' Kernel tables physical base address start argument to value ' + print TRANSLATION_TABLES.phys_tables_base_addr.to_hex_underscore + print ' at ELF file offset ' + puts BSP.phys_kernel_tables_base_addr_offset_in_file.to_hex_underscore + + File.binwrite(kernel_elf_path, TRANSLATION_TABLES.phys_tables_base_addr_binary, + BSP.phys_kernel_tables_base_addr_offset_in_file) +end diff --git a/19_kernel_heap/tools/translation_table_tool/kernel_elf.rb b/19_kernel_heap/tools/translation_table_tool/kernel_elf.rb new file mode 100644 index 00000000..f2d5b0b7 --- /dev/null +++ b/19_kernel_heap/tools/translation_table_tool/kernel_elf.rb @@ -0,0 +1,96 @@ +# frozen_string_literal: true + +# SPDX-License-Identifier: MIT OR Apache-2.0 +# +# Copyright (c) 2021-2022 Andre Richter + +# KernelELF +class KernelELF + SECTION_FLAG_ALLOC = 2 + + def initialize(kernel_elf_path) + @elf = ELFTools::ELFFile.new(File.open(kernel_elf_path)) + @symtab_section = @elf.section_by_name('.symtab') + end + + def machine + @elf.machine.to_sym + end + + def symbol_value(symbol_name) + @symtab_section.symbol_by_name(symbol_name).header.st_value + end + + def segment_containing_virt_addr(virt_addr) + @elf.each_segments do |segment| + return segment if segment.vma_in?(virt_addr) + end + end + + def virt_to_phys(virt_addr) + segment = segment_containing_virt_addr(virt_addr) + translation_offset = segment.header.p_vaddr - segment.header.p_paddr + + virt_addr - translation_offset + end + + def virt_addr_to_file_offset(virt_addr) + segment = segment_containing_virt_addr(virt_addr) + segment.vma_to_offset(virt_addr) + end + + def sections_in_segment(segment) + head = segment.mem_head + tail = segment.mem_tail + + sections = @elf.each_sections.select do |section| + file_offset = section.header.sh_addr + flags = section.header.sh_flags + + file_offset >= head && file_offset < tail && (flags & SECTION_FLAG_ALLOC != 0) + end + + sections.map(&:name).join(' ') + end + + def select_load_segments + @elf.each_segments.select do |segment| + segment.instance_of?(ELFTools::Segments::LoadSegment) + end + end + + def segment_get_acc_perms(segment) + if segment.readable? && segment.writable? + :ReadWrite + elsif segment.readable? + :ReadOnly + else + :Invalid + end + end + + def update_max_section_name_length(descriptors) + MappingDescriptor.update_max_section_name_length(descriptors.map { |i| i.name.size }.max) + end + + def generate_mapping_descriptors + descriptors = select_load_segments.map do |segment| + # Assume each segment is page aligned. + size = segment.mem_size.align_up(BSP.kernel_granule::SIZE) + virt_start_addr = segment.header.p_vaddr + phys_start_addr = segment.header.p_paddr + acc_perms = segment_get_acc_perms(segment) + execute_never = !segment.executable? + section_names = sections_in_segment(segment) + + virt_region = MemoryRegion.new(virt_start_addr, size, BSP.kernel_granule::SIZE) + phys_region = MemoryRegion.new(phys_start_addr, size, BSP.kernel_granule::SIZE) + attributes = AttributeFields.new(:CacheableDRAM, acc_perms, execute_never) + + MappingDescriptor.new(section_names, virt_region, phys_region, attributes) + end + + update_max_section_name_length(descriptors) + descriptors + end +end diff --git a/19_kernel_heap/tools/translation_table_tool/main.rb b/19_kernel_heap/tools/translation_table_tool/main.rb new file mode 100755 index 00000000..6419e364 --- /dev/null +++ b/19_kernel_heap/tools/translation_table_tool/main.rb @@ -0,0 +1,46 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +# SPDX-License-Identifier: MIT OR Apache-2.0 +# +# Copyright (c) 2021-2022 Andre Richter + +require 'rubygems' +require 'bundler/setup' +require 'colorize' +require 'elftools' + +require_relative 'generic' +require_relative 'kernel_elf' +require_relative 'bsp' +require_relative 'arch' + +BSP_TYPE = ARGV[0].to_sym +kernel_elf_path = ARGV[1] + +start = Time.now + +KERNEL_ELF = KernelELF.new(kernel_elf_path) + +BSP = case BSP_TYPE + when :rpi3, :rpi4 + RaspberryPi.new + else + raise + end + +TRANSLATION_TABLES = case KERNEL_ELF.machine + when :AArch64 + Arch::ARMv8::TranslationTable.new + else + raise + end + +kernel_map_binary +kernel_patch_tables(kernel_elf_path) +kernel_patch_base_addr(kernel_elf_path) + +elapsed = Time.now - start + +print 'Finished'.rjust(12).green.bold +puts " in #{elapsed.round(2)}s" From f222d73b90c2ff5c5359e608512408b4196a63e3 Mon Sep 17 00:00:00 2001 From: Andre Richter Date: Tue, 17 May 2022 23:36:25 +0200 Subject: [PATCH 38/75] Fix clippy --- 19_kernel_heap/README.md | 2 +- 19_kernel_heap/kernel/src/console.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/19_kernel_heap/README.md b/19_kernel_heap/README.md index 430ff2fb..0b4e2348 100644 --- a/19_kernel_heap/README.md +++ b/19_kernel_heap/README.md @@ -828,7 +828,7 @@ diff -uNr 18_backtrace/kernel/src/console.rs 19_kernel_heap/kernel/src/console.r + + static FIRST_SWITCH: InitStateLock = InitStateLock::new(true); + FIRST_SWITCH.write(|first| { -+ if *first == true { ++ if *first { + *first = false; + + buffer_console::BUFFER_CONSOLE.dump(); diff --git a/19_kernel_heap/kernel/src/console.rs b/19_kernel_heap/kernel/src/console.rs index 20a89cd7..ff1d8ddc 100644 --- a/19_kernel_heap/kernel/src/console.rs +++ b/19_kernel_heap/kernel/src/console.rs @@ -77,7 +77,7 @@ pub fn register_console(new_console: &'static (dyn interface::All + Sync)) { static FIRST_SWITCH: InitStateLock = InitStateLock::new(true); FIRST_SWITCH.write(|first| { - if *first == true { + if *first { *first = false; buffer_console::BUFFER_CONSOLE.dump(); From 5e1fdf8605e0c8f9052a26f41efbfb10f225c33a Mon Sep 17 00:00:00 2001 From: Andre Richter Date: Thu, 19 May 2022 22:52:32 +0200 Subject: [PATCH 39/75] Remove unsafe from certain IRQ related code While turning IRQs on or off is something that "sounds critical", it is not unsafe in these sense of compromising memory safety. Rust's unsafe should be about memory safety only, hence removing it from certain functions. --- 13_exceptions_part2_peripheral_IRQs/README.md | 89 ++++++++----------- .../_arch/aarch64/exception/asynchronous.rs | 49 ++++------ .../kernel/src/exception/asynchronous.rs | 10 +-- .../kernel/src/panic_wait.rs | 2 +- .../kernel/tests/04_exception_irq_sanity.rs | 14 +-- 14_virtual_mem_part2_mmio_remap/README.md | 2 +- .../_arch/aarch64/exception/asynchronous.rs | 49 ++++------ .../kernel/src/exception/asynchronous.rs | 10 +-- .../kernel/src/panic_wait.rs | 2 +- .../kernel/tests/04_exception_irq_sanity.rs | 14 +-- .../_arch/aarch64/exception/asynchronous.rs | 49 ++++------ .../kernel/src/exception/asynchronous.rs | 10 +-- .../kernel/src/panic_wait.rs | 2 +- .../kernel/tests/04_exception_irq_sanity.rs | 14 +-- .../_arch/aarch64/exception/asynchronous.rs | 49 ++++------ .../kernel/src/exception/asynchronous.rs | 10 +-- .../kernel/src/panic_wait.rs | 2 +- .../kernel/tests/04_exception_irq_sanity.rs | 14 +-- .../_arch/aarch64/exception/asynchronous.rs | 49 ++++------ .../kernel/src/exception/asynchronous.rs | 10 +-- 17_kernel_symbols/kernel/src/panic_wait.rs | 2 +- .../kernel/tests/04_exception_irq_sanity.rs | 14 +-- .../_arch/aarch64/exception/asynchronous.rs | 49 ++++------ .../kernel/src/exception/asynchronous.rs | 10 +-- 18_backtrace/kernel/src/panic_wait.rs | 2 +- .../kernel/tests/04_exception_irq_sanity.rs | 14 +-- .../_arch/aarch64/exception/asynchronous.rs | 49 ++++------ .../kernel/src/exception/asynchronous.rs | 10 +-- 19_kernel_heap/kernel/src/panic_wait.rs | 2 +- .../kernel/tests/04_exception_irq_sanity.rs | 14 +-- 30 files changed, 246 insertions(+), 370 deletions(-) diff --git a/13_exceptions_part2_peripheral_IRQs/README.md b/13_exceptions_part2_peripheral_IRQs/README.md index 9a5b7b4f..65be428a 100644 --- a/13_exceptions_part2_peripheral_IRQs/README.md +++ b/13_exceptions_part2_peripheral_IRQs/README.md @@ -421,13 +421,9 @@ core are masked before the `f(data)` is being executed, and restored afterwards: /// previous state before returning, so this is deemed safe. #[inline(always)] pub fn exec_with_irq_masked(f: impl FnOnce() -> T) -> T { - let ret: T; - - unsafe { - let saved = local_irq_mask_save(); - ret = f(); - local_irq_restore(saved); - } + let saved = local_irq_mask_save(); + let ret = f(); + local_irq_restore(saved); ret } @@ -814,7 +810,7 @@ diff -uNr 12_integrated_testing/kernel/src/_arch/aarch64/exception/asynchronous. trait DaifField { fn daif_field() -> tock_registers::fields::Field; } -@@ -66,6 +71,71 @@ +@@ -66,6 +71,60 @@ // Public Code //-------------------------------------------------------------------------------------------------- @@ -830,42 +826,32 @@ diff -uNr 12_integrated_testing/kernel/src/_arch/aarch64/exception/asynchronous. +/// +/// "Writes to PSTATE.{PAN, D, A, I, F} occur in program order without the need for additional +/// synchronization." -+/// -+/// # Safety -+/// -+/// - Changes the HW state of the executing core. +#[inline(always)] -+pub unsafe fn local_irq_unmask() { -+ #[rustfmt::skip] -+ asm!( -+ "msr DAIFClr, {arg}", -+ arg = const daif_bits::IRQ, -+ options(nomem, nostack, preserves_flags) -+ ); ++pub fn local_irq_unmask() { ++ unsafe { ++ asm!( ++ "msr DAIFClr, {arg}", ++ arg = const daif_bits::IRQ, ++ options(nomem, nostack, preserves_flags) ++ ); ++ } +} + +/// Mask IRQs on the executing core. -+/// -+/// # Safety -+/// -+/// - Changes the HW state of the executing core. +#[inline(always)] -+pub unsafe fn local_irq_mask() { -+ #[rustfmt::skip] -+ asm!( -+ "msr DAIFSet, {arg}", -+ arg = const daif_bits::IRQ, -+ options(nomem, nostack, preserves_flags) -+ ); ++pub fn local_irq_mask() { ++ unsafe { ++ asm!( ++ "msr DAIFSet, {arg}", ++ arg = const daif_bits::IRQ, ++ options(nomem, nostack, preserves_flags) ++ ); ++ } +} + +/// Mask IRQs on the executing core and return the previously saved interrupt mask bits (DAIF). -+/// -+/// # Safety -+/// -+/// - Changes the HW state of the executing core. +#[inline(always)] -+pub unsafe fn local_irq_mask_save() -> u64 { ++pub fn local_irq_mask_save() -> u64 { + let saved = DAIF.get(); + local_irq_mask(); + @@ -874,12 +860,11 @@ diff -uNr 12_integrated_testing/kernel/src/_arch/aarch64/exception/asynchronous. + +/// Restore the interrupt mask bits (DAIF) using the callee's argument. +/// -+/// # Safety ++/// # Invariant +/// -+/// - Changes the HW state of the executing core. +/// - No sanity checks on the input. +#[inline(always)] -+pub unsafe fn local_irq_restore(saved: u64) { ++pub fn local_irq_restore(saved: u64) { + DAIF.set(saved); +} + @@ -2245,7 +2230,7 @@ diff -uNr 12_integrated_testing/kernel/src/driver.rs 13_exceptions_part2_periphe diff -uNr 12_integrated_testing/kernel/src/exception/asynchronous.rs 13_exceptions_part2_peripheral_IRQs/kernel/src/exception/asynchronous.rs --- 12_integrated_testing/kernel/src/exception/asynchronous.rs +++ 13_exceptions_part2_peripheral_IRQs/kernel/src/exception/asynchronous.rs -@@ -8,7 +8,153 @@ +@@ -8,7 +8,149 @@ #[path = "../_arch/aarch64/exception/asynchronous.rs"] mod arch_asynchronous; @@ -2383,13 +2368,9 @@ diff -uNr 12_integrated_testing/kernel/src/exception/asynchronous.rs 13_exceptio +/// previous state before returning, so this is deemed safe. +#[inline(always)] +pub fn exec_with_irq_masked(f: impl FnOnce() -> T) -> T { -+ let ret: T; -+ -+ unsafe { -+ let saved = local_irq_mask_save(); -+ ret = f(); -+ local_irq_restore(saved); -+ } ++ let saved = local_irq_mask_save(); ++ let ret = f(); ++ local_irq_restore(saved); + + ret +} @@ -2497,7 +2478,7 @@ diff -uNr 12_integrated_testing/kernel/src/panic_wait.rs 13_exceptions_part2_per fn panic(info: &PanicInfo) -> ! { use crate::time::interface::TimeManager; -+ unsafe { exception::asynchronous::local_irq_mask() }; ++ exception::asynchronous::local_irq_mask(); + // Protect against panic infinite loops if any of the following code panics itself. panic_prevent_reenter(); @@ -2773,21 +2754,21 @@ diff -uNr 12_integrated_testing/kernel/tests/04_exception_irq_sanity.rs 13_excep + // Precondition: IRQs are unmasked. + assert!(exception::asynchronous::is_local_irq_masked()); + -+ unsafe { exception::asynchronous::local_irq_mask() }; ++ exception::asynchronous::local_irq_mask(); + assert!(!exception::asynchronous::is_local_irq_masked()); + + // Restore earlier state. -+ unsafe { exception::asynchronous::local_irq_unmask() }; ++ exception::asynchronous::local_irq_unmask(); +} + +/// Check that IRQ unmasking works. +#[kernel_test] +fn local_irq_unmask_works() { + // Precondition: IRQs are masked. -+ unsafe { exception::asynchronous::local_irq_mask() }; ++ exception::asynchronous::local_irq_mask(); + assert!(!exception::asynchronous::is_local_irq_masked()); + -+ unsafe { exception::asynchronous::local_irq_unmask() }; ++ exception::asynchronous::local_irq_unmask(); + assert!(exception::asynchronous::is_local_irq_masked()); +} + @@ -2797,13 +2778,13 @@ diff -uNr 12_integrated_testing/kernel/tests/04_exception_irq_sanity.rs 13_excep + // Precondition: IRQs are unmasked. + assert!(exception::asynchronous::is_local_irq_masked()); + -+ let first = unsafe { exception::asynchronous::local_irq_mask_save() }; ++ let first = exception::asynchronous::local_irq_mask_save(); + assert!(!exception::asynchronous::is_local_irq_masked()); + -+ let second = unsafe { exception::asynchronous::local_irq_mask_save() }; ++ let second = exception::asynchronous::local_irq_mask_save(); + assert_ne!(first, second); + -+ unsafe { exception::asynchronous::local_irq_restore(first) }; ++ exception::asynchronous::local_irq_restore(first); + assert!(exception::asynchronous::is_local_irq_masked()); +} diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/exception/asynchronous.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/exception/asynchronous.rs index 73b82e65..cf6f97ac 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/exception/asynchronous.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/exception/asynchronous.rs @@ -83,42 +83,32 @@ pub fn is_local_irq_masked() -> bool { /// /// "Writes to PSTATE.{PAN, D, A, I, F} occur in program order without the need for additional /// synchronization." -/// -/// # Safety -/// -/// - Changes the HW state of the executing core. #[inline(always)] -pub unsafe fn local_irq_unmask() { - #[rustfmt::skip] - asm!( - "msr DAIFClr, {arg}", - arg = const daif_bits::IRQ, - options(nomem, nostack, preserves_flags) - ); +pub fn local_irq_unmask() { + unsafe { + asm!( + "msr DAIFClr, {arg}", + arg = const daif_bits::IRQ, + options(nomem, nostack, preserves_flags) + ); + } } /// Mask IRQs on the executing core. -/// -/// # Safety -/// -/// - Changes the HW state of the executing core. #[inline(always)] -pub unsafe fn local_irq_mask() { - #[rustfmt::skip] - asm!( - "msr DAIFSet, {arg}", - arg = const daif_bits::IRQ, - options(nomem, nostack, preserves_flags) - ); +pub fn local_irq_mask() { + unsafe { + asm!( + "msr DAIFSet, {arg}", + arg = const daif_bits::IRQ, + options(nomem, nostack, preserves_flags) + ); + } } /// Mask IRQs on the executing core and return the previously saved interrupt mask bits (DAIF). -/// -/// # Safety -/// -/// - Changes the HW state of the executing core. #[inline(always)] -pub unsafe fn local_irq_mask_save() -> u64 { +pub fn local_irq_mask_save() -> u64 { let saved = DAIF.get(); local_irq_mask(); @@ -127,12 +117,11 @@ pub unsafe fn local_irq_mask_save() -> u64 { /// Restore the interrupt mask bits (DAIF) using the callee's argument. /// -/// # Safety +/// # Invariant /// -/// - Changes the HW state of the executing core. /// - No sanity checks on the input. #[inline(always)] -pub unsafe fn local_irq_restore(saved: u64) { +pub fn local_irq_restore(saved: u64) { DAIF.set(saved); } diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/exception/asynchronous.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/exception/asynchronous.rs index 17938692..31800ffe 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/exception/asynchronous.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/exception/asynchronous.rs @@ -141,13 +141,9 @@ impl fmt::Display for IRQNumber<{ MAX_INCLUSIVE }> { /// previous state before returning, so this is deemed safe. #[inline(always)] pub fn exec_with_irq_masked(f: impl FnOnce() -> T) -> T { - let ret: T; - - unsafe { - let saved = local_irq_mask_save(); - ret = f(); - local_irq_restore(saved); - } + let saved = local_irq_mask_save(); + let ret = f(); + local_irq_restore(saved); ret } diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/panic_wait.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/panic_wait.rs index e4256b61..61831213 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/panic_wait.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/panic_wait.rs @@ -61,7 +61,7 @@ fn panic_prevent_reenter() { fn panic(info: &PanicInfo) -> ! { use crate::time::interface::TimeManager; - unsafe { exception::asynchronous::local_irq_mask() }; + exception::asynchronous::local_irq_mask(); // Protect against panic infinite loops if any of the following code panics itself. panic_prevent_reenter(); diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/tests/04_exception_irq_sanity.rs b/13_exceptions_part2_peripheral_IRQs/kernel/tests/04_exception_irq_sanity.rs index 1204dca4..9deac6cc 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/tests/04_exception_irq_sanity.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/tests/04_exception_irq_sanity.rs @@ -32,21 +32,21 @@ fn local_irq_mask_works() { // Precondition: IRQs are unmasked. assert!(exception::asynchronous::is_local_irq_masked()); - unsafe { exception::asynchronous::local_irq_mask() }; + exception::asynchronous::local_irq_mask(); assert!(!exception::asynchronous::is_local_irq_masked()); // Restore earlier state. - unsafe { exception::asynchronous::local_irq_unmask() }; + exception::asynchronous::local_irq_unmask(); } /// Check that IRQ unmasking works. #[kernel_test] fn local_irq_unmask_works() { // Precondition: IRQs are masked. - unsafe { exception::asynchronous::local_irq_mask() }; + exception::asynchronous::local_irq_mask(); assert!(!exception::asynchronous::is_local_irq_masked()); - unsafe { exception::asynchronous::local_irq_unmask() }; + exception::asynchronous::local_irq_unmask(); assert!(exception::asynchronous::is_local_irq_masked()); } @@ -56,12 +56,12 @@ fn local_irq_mask_save_works() { // Precondition: IRQs are unmasked. assert!(exception::asynchronous::is_local_irq_masked()); - let first = unsafe { exception::asynchronous::local_irq_mask_save() }; + let first = exception::asynchronous::local_irq_mask_save(); assert!(!exception::asynchronous::is_local_irq_masked()); - let second = unsafe { exception::asynchronous::local_irq_mask_save() }; + let second = exception::asynchronous::local_irq_mask_save(); assert_ne!(first, second); - unsafe { exception::asynchronous::local_irq_restore(first) }; + exception::asynchronous::local_irq_restore(first); assert!(exception::asynchronous::is_local_irq_masked()); } diff --git a/14_virtual_mem_part2_mmio_remap/README.md b/14_virtual_mem_part2_mmio_remap/README.md index 911a2d76..30aa848b 100644 --- a/14_virtual_mem_part2_mmio_remap/README.md +++ b/14_virtual_mem_part2_mmio_remap/README.md @@ -2300,7 +2300,7 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/exception/asynchronous. impl<'irq_context> IRQContext<'irq_context> { /// Creates an IRQContext token. -@@ -152,9 +162,17 @@ +@@ -148,9 +158,17 @@ ret } diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/exception/asynchronous.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/exception/asynchronous.rs index 73b82e65..cf6f97ac 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/exception/asynchronous.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/exception/asynchronous.rs @@ -83,42 +83,32 @@ pub fn is_local_irq_masked() -> bool { /// /// "Writes to PSTATE.{PAN, D, A, I, F} occur in program order without the need for additional /// synchronization." -/// -/// # Safety -/// -/// - Changes the HW state of the executing core. #[inline(always)] -pub unsafe fn local_irq_unmask() { - #[rustfmt::skip] - asm!( - "msr DAIFClr, {arg}", - arg = const daif_bits::IRQ, - options(nomem, nostack, preserves_flags) - ); +pub fn local_irq_unmask() { + unsafe { + asm!( + "msr DAIFClr, {arg}", + arg = const daif_bits::IRQ, + options(nomem, nostack, preserves_flags) + ); + } } /// Mask IRQs on the executing core. -/// -/// # Safety -/// -/// - Changes the HW state of the executing core. #[inline(always)] -pub unsafe fn local_irq_mask() { - #[rustfmt::skip] - asm!( - "msr DAIFSet, {arg}", - arg = const daif_bits::IRQ, - options(nomem, nostack, preserves_flags) - ); +pub fn local_irq_mask() { + unsafe { + asm!( + "msr DAIFSet, {arg}", + arg = const daif_bits::IRQ, + options(nomem, nostack, preserves_flags) + ); + } } /// Mask IRQs on the executing core and return the previously saved interrupt mask bits (DAIF). -/// -/// # Safety -/// -/// - Changes the HW state of the executing core. #[inline(always)] -pub unsafe fn local_irq_mask_save() -> u64 { +pub fn local_irq_mask_save() -> u64 { let saved = DAIF.get(); local_irq_mask(); @@ -127,12 +117,11 @@ pub unsafe fn local_irq_mask_save() -> u64 { /// Restore the interrupt mask bits (DAIF) using the callee's argument. /// -/// # Safety +/// # Invariant /// -/// - Changes the HW state of the executing core. /// - No sanity checks on the input. #[inline(always)] -pub unsafe fn local_irq_restore(saved: u64) { +pub fn local_irq_restore(saved: u64) { DAIF.set(saved); } diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/exception/asynchronous.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/exception/asynchronous.rs index d9d2767c..3544e621 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/exception/asynchronous.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/exception/asynchronous.rs @@ -151,13 +151,9 @@ impl fmt::Display for IRQNumber<{ MAX_INCLUSIVE }> { /// previous state before returning, so this is deemed safe. #[inline(always)] pub fn exec_with_irq_masked(f: impl FnOnce() -> T) -> T { - let ret: T; - - unsafe { - let saved = local_irq_mask_save(); - ret = f(); - local_irq_restore(saved); - } + let saved = local_irq_mask_save(); + let ret = f(); + local_irq_restore(saved); ret } diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/panic_wait.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/panic_wait.rs index e4256b61..61831213 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/panic_wait.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/panic_wait.rs @@ -61,7 +61,7 @@ fn panic_prevent_reenter() { fn panic(info: &PanicInfo) -> ! { use crate::time::interface::TimeManager; - unsafe { exception::asynchronous::local_irq_mask() }; + exception::asynchronous::local_irq_mask(); // Protect against panic infinite loops if any of the following code panics itself. panic_prevent_reenter(); diff --git a/14_virtual_mem_part2_mmio_remap/kernel/tests/04_exception_irq_sanity.rs b/14_virtual_mem_part2_mmio_remap/kernel/tests/04_exception_irq_sanity.rs index 7a344874..c9e244ce 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/tests/04_exception_irq_sanity.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/tests/04_exception_irq_sanity.rs @@ -44,21 +44,21 @@ fn local_irq_mask_works() { // Precondition: IRQs are unmasked. assert!(exception::asynchronous::is_local_irq_masked()); - unsafe { exception::asynchronous::local_irq_mask() }; + exception::asynchronous::local_irq_mask(); assert!(!exception::asynchronous::is_local_irq_masked()); // Restore earlier state. - unsafe { exception::asynchronous::local_irq_unmask() }; + exception::asynchronous::local_irq_unmask(); } /// Check that IRQ unmasking works. #[kernel_test] fn local_irq_unmask_works() { // Precondition: IRQs are masked. - unsafe { exception::asynchronous::local_irq_mask() }; + exception::asynchronous::local_irq_mask(); assert!(!exception::asynchronous::is_local_irq_masked()); - unsafe { exception::asynchronous::local_irq_unmask() }; + exception::asynchronous::local_irq_unmask(); assert!(exception::asynchronous::is_local_irq_masked()); } @@ -68,12 +68,12 @@ fn local_irq_mask_save_works() { // Precondition: IRQs are unmasked. assert!(exception::asynchronous::is_local_irq_masked()); - let first = unsafe { exception::asynchronous::local_irq_mask_save() }; + let first = exception::asynchronous::local_irq_mask_save(); assert!(!exception::asynchronous::is_local_irq_masked()); - let second = unsafe { exception::asynchronous::local_irq_mask_save() }; + let second = exception::asynchronous::local_irq_mask_save(); assert_ne!(first, second); - unsafe { exception::asynchronous::local_irq_restore(first) }; + exception::asynchronous::local_irq_restore(first); assert!(exception::asynchronous::is_local_irq_masked()); } diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/exception/asynchronous.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/exception/asynchronous.rs index 73b82e65..cf6f97ac 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/exception/asynchronous.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/exception/asynchronous.rs @@ -83,42 +83,32 @@ pub fn is_local_irq_masked() -> bool { /// /// "Writes to PSTATE.{PAN, D, A, I, F} occur in program order without the need for additional /// synchronization." -/// -/// # Safety -/// -/// - Changes the HW state of the executing core. #[inline(always)] -pub unsafe fn local_irq_unmask() { - #[rustfmt::skip] - asm!( - "msr DAIFClr, {arg}", - arg = const daif_bits::IRQ, - options(nomem, nostack, preserves_flags) - ); +pub fn local_irq_unmask() { + unsafe { + asm!( + "msr DAIFClr, {arg}", + arg = const daif_bits::IRQ, + options(nomem, nostack, preserves_flags) + ); + } } /// Mask IRQs on the executing core. -/// -/// # Safety -/// -/// - Changes the HW state of the executing core. #[inline(always)] -pub unsafe fn local_irq_mask() { - #[rustfmt::skip] - asm!( - "msr DAIFSet, {arg}", - arg = const daif_bits::IRQ, - options(nomem, nostack, preserves_flags) - ); +pub fn local_irq_mask() { + unsafe { + asm!( + "msr DAIFSet, {arg}", + arg = const daif_bits::IRQ, + options(nomem, nostack, preserves_flags) + ); + } } /// Mask IRQs on the executing core and return the previously saved interrupt mask bits (DAIF). -/// -/// # Safety -/// -/// - Changes the HW state of the executing core. #[inline(always)] -pub unsafe fn local_irq_mask_save() -> u64 { +pub fn local_irq_mask_save() -> u64 { let saved = DAIF.get(); local_irq_mask(); @@ -127,12 +117,11 @@ pub unsafe fn local_irq_mask_save() -> u64 { /// Restore the interrupt mask bits (DAIF) using the callee's argument. /// -/// # Safety +/// # Invariant /// -/// - Changes the HW state of the executing core. /// - No sanity checks on the input. #[inline(always)] -pub unsafe fn local_irq_restore(saved: u64) { +pub fn local_irq_restore(saved: u64) { DAIF.set(saved); } diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/exception/asynchronous.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/exception/asynchronous.rs index d9d2767c..3544e621 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/exception/asynchronous.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/exception/asynchronous.rs @@ -151,13 +151,9 @@ impl fmt::Display for IRQNumber<{ MAX_INCLUSIVE }> { /// previous state before returning, so this is deemed safe. #[inline(always)] pub fn exec_with_irq_masked(f: impl FnOnce() -> T) -> T { - let ret: T; - - unsafe { - let saved = local_irq_mask_save(); - ret = f(); - local_irq_restore(saved); - } + let saved = local_irq_mask_save(); + let ret = f(); + local_irq_restore(saved); ret } diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/panic_wait.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/panic_wait.rs index e4256b61..61831213 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/panic_wait.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/panic_wait.rs @@ -61,7 +61,7 @@ fn panic_prevent_reenter() { fn panic(info: &PanicInfo) -> ! { use crate::time::interface::TimeManager; - unsafe { exception::asynchronous::local_irq_mask() }; + exception::asynchronous::local_irq_mask(); // Protect against panic infinite loops if any of the following code panics itself. panic_prevent_reenter(); diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/tests/04_exception_irq_sanity.rs b/15_virtual_mem_part3_precomputed_tables/kernel/tests/04_exception_irq_sanity.rs index 7b9628d5..e93a4caf 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/tests/04_exception_irq_sanity.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/tests/04_exception_irq_sanity.rs @@ -34,21 +34,21 @@ fn local_irq_mask_works() { // Precondition: IRQs are unmasked. assert!(exception::asynchronous::is_local_irq_masked()); - unsafe { exception::asynchronous::local_irq_mask() }; + exception::asynchronous::local_irq_mask(); assert!(!exception::asynchronous::is_local_irq_masked()); // Restore earlier state. - unsafe { exception::asynchronous::local_irq_unmask() }; + exception::asynchronous::local_irq_unmask(); } /// Check that IRQ unmasking works. #[kernel_test] fn local_irq_unmask_works() { // Precondition: IRQs are masked. - unsafe { exception::asynchronous::local_irq_mask() }; + exception::asynchronous::local_irq_mask(); assert!(!exception::asynchronous::is_local_irq_masked()); - unsafe { exception::asynchronous::local_irq_unmask() }; + exception::asynchronous::local_irq_unmask(); assert!(exception::asynchronous::is_local_irq_masked()); } @@ -58,12 +58,12 @@ fn local_irq_mask_save_works() { // Precondition: IRQs are unmasked. assert!(exception::asynchronous::is_local_irq_masked()); - let first = unsafe { exception::asynchronous::local_irq_mask_save() }; + let first = exception::asynchronous::local_irq_mask_save(); assert!(!exception::asynchronous::is_local_irq_masked()); - let second = unsafe { exception::asynchronous::local_irq_mask_save() }; + let second = exception::asynchronous::local_irq_mask_save(); assert_ne!(first, second); - unsafe { exception::asynchronous::local_irq_restore(first) }; + exception::asynchronous::local_irq_restore(first); assert!(exception::asynchronous::is_local_irq_masked()); } diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/exception/asynchronous.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/exception/asynchronous.rs index 73b82e65..cf6f97ac 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/exception/asynchronous.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/exception/asynchronous.rs @@ -83,42 +83,32 @@ pub fn is_local_irq_masked() -> bool { /// /// "Writes to PSTATE.{PAN, D, A, I, F} occur in program order without the need for additional /// synchronization." -/// -/// # Safety -/// -/// - Changes the HW state of the executing core. #[inline(always)] -pub unsafe fn local_irq_unmask() { - #[rustfmt::skip] - asm!( - "msr DAIFClr, {arg}", - arg = const daif_bits::IRQ, - options(nomem, nostack, preserves_flags) - ); +pub fn local_irq_unmask() { + unsafe { + asm!( + "msr DAIFClr, {arg}", + arg = const daif_bits::IRQ, + options(nomem, nostack, preserves_flags) + ); + } } /// Mask IRQs on the executing core. -/// -/// # Safety -/// -/// - Changes the HW state of the executing core. #[inline(always)] -pub unsafe fn local_irq_mask() { - #[rustfmt::skip] - asm!( - "msr DAIFSet, {arg}", - arg = const daif_bits::IRQ, - options(nomem, nostack, preserves_flags) - ); +pub fn local_irq_mask() { + unsafe { + asm!( + "msr DAIFSet, {arg}", + arg = const daif_bits::IRQ, + options(nomem, nostack, preserves_flags) + ); + } } /// Mask IRQs on the executing core and return the previously saved interrupt mask bits (DAIF). -/// -/// # Safety -/// -/// - Changes the HW state of the executing core. #[inline(always)] -pub unsafe fn local_irq_mask_save() -> u64 { +pub fn local_irq_mask_save() -> u64 { let saved = DAIF.get(); local_irq_mask(); @@ -127,12 +117,11 @@ pub unsafe fn local_irq_mask_save() -> u64 { /// Restore the interrupt mask bits (DAIF) using the callee's argument. /// -/// # Safety +/// # Invariant /// -/// - Changes the HW state of the executing core. /// - No sanity checks on the input. #[inline(always)] -pub unsafe fn local_irq_restore(saved: u64) { +pub fn local_irq_restore(saved: u64) { DAIF.set(saved); } diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/exception/asynchronous.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/exception/asynchronous.rs index d9d2767c..3544e621 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/exception/asynchronous.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/exception/asynchronous.rs @@ -151,13 +151,9 @@ impl fmt::Display for IRQNumber<{ MAX_INCLUSIVE }> { /// previous state before returning, so this is deemed safe. #[inline(always)] pub fn exec_with_irq_masked(f: impl FnOnce() -> T) -> T { - let ret: T; - - unsafe { - let saved = local_irq_mask_save(); - ret = f(); - local_irq_restore(saved); - } + let saved = local_irq_mask_save(); + let ret = f(); + local_irq_restore(saved); ret } diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/panic_wait.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/panic_wait.rs index e4256b61..61831213 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/panic_wait.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/panic_wait.rs @@ -61,7 +61,7 @@ fn panic_prevent_reenter() { fn panic(info: &PanicInfo) -> ! { use crate::time::interface::TimeManager; - unsafe { exception::asynchronous::local_irq_mask() }; + exception::asynchronous::local_irq_mask(); // Protect against panic infinite loops if any of the following code panics itself. panic_prevent_reenter(); diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/tests/04_exception_irq_sanity.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/tests/04_exception_irq_sanity.rs index 7b9628d5..e93a4caf 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/tests/04_exception_irq_sanity.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/tests/04_exception_irq_sanity.rs @@ -34,21 +34,21 @@ fn local_irq_mask_works() { // Precondition: IRQs are unmasked. assert!(exception::asynchronous::is_local_irq_masked()); - unsafe { exception::asynchronous::local_irq_mask() }; + exception::asynchronous::local_irq_mask(); assert!(!exception::asynchronous::is_local_irq_masked()); // Restore earlier state. - unsafe { exception::asynchronous::local_irq_unmask() }; + exception::asynchronous::local_irq_unmask(); } /// Check that IRQ unmasking works. #[kernel_test] fn local_irq_unmask_works() { // Precondition: IRQs are masked. - unsafe { exception::asynchronous::local_irq_mask() }; + exception::asynchronous::local_irq_mask(); assert!(!exception::asynchronous::is_local_irq_masked()); - unsafe { exception::asynchronous::local_irq_unmask() }; + exception::asynchronous::local_irq_unmask(); assert!(exception::asynchronous::is_local_irq_masked()); } @@ -58,12 +58,12 @@ fn local_irq_mask_save_works() { // Precondition: IRQs are unmasked. assert!(exception::asynchronous::is_local_irq_masked()); - let first = unsafe { exception::asynchronous::local_irq_mask_save() }; + let first = exception::asynchronous::local_irq_mask_save(); assert!(!exception::asynchronous::is_local_irq_masked()); - let second = unsafe { exception::asynchronous::local_irq_mask_save() }; + let second = exception::asynchronous::local_irq_mask_save(); assert_ne!(first, second); - unsafe { exception::asynchronous::local_irq_restore(first) }; + exception::asynchronous::local_irq_restore(first); assert!(exception::asynchronous::is_local_irq_masked()); } diff --git a/17_kernel_symbols/kernel/src/_arch/aarch64/exception/asynchronous.rs b/17_kernel_symbols/kernel/src/_arch/aarch64/exception/asynchronous.rs index 73b82e65..cf6f97ac 100644 --- a/17_kernel_symbols/kernel/src/_arch/aarch64/exception/asynchronous.rs +++ b/17_kernel_symbols/kernel/src/_arch/aarch64/exception/asynchronous.rs @@ -83,42 +83,32 @@ pub fn is_local_irq_masked() -> bool { /// /// "Writes to PSTATE.{PAN, D, A, I, F} occur in program order without the need for additional /// synchronization." -/// -/// # Safety -/// -/// - Changes the HW state of the executing core. #[inline(always)] -pub unsafe fn local_irq_unmask() { - #[rustfmt::skip] - asm!( - "msr DAIFClr, {arg}", - arg = const daif_bits::IRQ, - options(nomem, nostack, preserves_flags) - ); +pub fn local_irq_unmask() { + unsafe { + asm!( + "msr DAIFClr, {arg}", + arg = const daif_bits::IRQ, + options(nomem, nostack, preserves_flags) + ); + } } /// Mask IRQs on the executing core. -/// -/// # Safety -/// -/// - Changes the HW state of the executing core. #[inline(always)] -pub unsafe fn local_irq_mask() { - #[rustfmt::skip] - asm!( - "msr DAIFSet, {arg}", - arg = const daif_bits::IRQ, - options(nomem, nostack, preserves_flags) - ); +pub fn local_irq_mask() { + unsafe { + asm!( + "msr DAIFSet, {arg}", + arg = const daif_bits::IRQ, + options(nomem, nostack, preserves_flags) + ); + } } /// Mask IRQs on the executing core and return the previously saved interrupt mask bits (DAIF). -/// -/// # Safety -/// -/// - Changes the HW state of the executing core. #[inline(always)] -pub unsafe fn local_irq_mask_save() -> u64 { +pub fn local_irq_mask_save() -> u64 { let saved = DAIF.get(); local_irq_mask(); @@ -127,12 +117,11 @@ pub unsafe fn local_irq_mask_save() -> u64 { /// Restore the interrupt mask bits (DAIF) using the callee's argument. /// -/// # Safety +/// # Invariant /// -/// - Changes the HW state of the executing core. /// - No sanity checks on the input. #[inline(always)] -pub unsafe fn local_irq_restore(saved: u64) { +pub fn local_irq_restore(saved: u64) { DAIF.set(saved); } diff --git a/17_kernel_symbols/kernel/src/exception/asynchronous.rs b/17_kernel_symbols/kernel/src/exception/asynchronous.rs index d9d2767c..3544e621 100644 --- a/17_kernel_symbols/kernel/src/exception/asynchronous.rs +++ b/17_kernel_symbols/kernel/src/exception/asynchronous.rs @@ -151,13 +151,9 @@ impl fmt::Display for IRQNumber<{ MAX_INCLUSIVE }> { /// previous state before returning, so this is deemed safe. #[inline(always)] pub fn exec_with_irq_masked(f: impl FnOnce() -> T) -> T { - let ret: T; - - unsafe { - let saved = local_irq_mask_save(); - ret = f(); - local_irq_restore(saved); - } + let saved = local_irq_mask_save(); + let ret = f(); + local_irq_restore(saved); ret } diff --git a/17_kernel_symbols/kernel/src/panic_wait.rs b/17_kernel_symbols/kernel/src/panic_wait.rs index e4256b61..61831213 100644 --- a/17_kernel_symbols/kernel/src/panic_wait.rs +++ b/17_kernel_symbols/kernel/src/panic_wait.rs @@ -61,7 +61,7 @@ fn panic_prevent_reenter() { fn panic(info: &PanicInfo) -> ! { use crate::time::interface::TimeManager; - unsafe { exception::asynchronous::local_irq_mask() }; + exception::asynchronous::local_irq_mask(); // Protect against panic infinite loops if any of the following code panics itself. panic_prevent_reenter(); diff --git a/17_kernel_symbols/kernel/tests/04_exception_irq_sanity.rs b/17_kernel_symbols/kernel/tests/04_exception_irq_sanity.rs index 7b9628d5..e93a4caf 100644 --- a/17_kernel_symbols/kernel/tests/04_exception_irq_sanity.rs +++ b/17_kernel_symbols/kernel/tests/04_exception_irq_sanity.rs @@ -34,21 +34,21 @@ fn local_irq_mask_works() { // Precondition: IRQs are unmasked. assert!(exception::asynchronous::is_local_irq_masked()); - unsafe { exception::asynchronous::local_irq_mask() }; + exception::asynchronous::local_irq_mask(); assert!(!exception::asynchronous::is_local_irq_masked()); // Restore earlier state. - unsafe { exception::asynchronous::local_irq_unmask() }; + exception::asynchronous::local_irq_unmask(); } /// Check that IRQ unmasking works. #[kernel_test] fn local_irq_unmask_works() { // Precondition: IRQs are masked. - unsafe { exception::asynchronous::local_irq_mask() }; + exception::asynchronous::local_irq_mask(); assert!(!exception::asynchronous::is_local_irq_masked()); - unsafe { exception::asynchronous::local_irq_unmask() }; + exception::asynchronous::local_irq_unmask(); assert!(exception::asynchronous::is_local_irq_masked()); } @@ -58,12 +58,12 @@ fn local_irq_mask_save_works() { // Precondition: IRQs are unmasked. assert!(exception::asynchronous::is_local_irq_masked()); - let first = unsafe { exception::asynchronous::local_irq_mask_save() }; + let first = exception::asynchronous::local_irq_mask_save(); assert!(!exception::asynchronous::is_local_irq_masked()); - let second = unsafe { exception::asynchronous::local_irq_mask_save() }; + let second = exception::asynchronous::local_irq_mask_save(); assert_ne!(first, second); - unsafe { exception::asynchronous::local_irq_restore(first) }; + exception::asynchronous::local_irq_restore(first); assert!(exception::asynchronous::is_local_irq_masked()); } diff --git a/18_backtrace/kernel/src/_arch/aarch64/exception/asynchronous.rs b/18_backtrace/kernel/src/_arch/aarch64/exception/asynchronous.rs index 73b82e65..cf6f97ac 100644 --- a/18_backtrace/kernel/src/_arch/aarch64/exception/asynchronous.rs +++ b/18_backtrace/kernel/src/_arch/aarch64/exception/asynchronous.rs @@ -83,42 +83,32 @@ pub fn is_local_irq_masked() -> bool { /// /// "Writes to PSTATE.{PAN, D, A, I, F} occur in program order without the need for additional /// synchronization." -/// -/// # Safety -/// -/// - Changes the HW state of the executing core. #[inline(always)] -pub unsafe fn local_irq_unmask() { - #[rustfmt::skip] - asm!( - "msr DAIFClr, {arg}", - arg = const daif_bits::IRQ, - options(nomem, nostack, preserves_flags) - ); +pub fn local_irq_unmask() { + unsafe { + asm!( + "msr DAIFClr, {arg}", + arg = const daif_bits::IRQ, + options(nomem, nostack, preserves_flags) + ); + } } /// Mask IRQs on the executing core. -/// -/// # Safety -/// -/// - Changes the HW state of the executing core. #[inline(always)] -pub unsafe fn local_irq_mask() { - #[rustfmt::skip] - asm!( - "msr DAIFSet, {arg}", - arg = const daif_bits::IRQ, - options(nomem, nostack, preserves_flags) - ); +pub fn local_irq_mask() { + unsafe { + asm!( + "msr DAIFSet, {arg}", + arg = const daif_bits::IRQ, + options(nomem, nostack, preserves_flags) + ); + } } /// Mask IRQs on the executing core and return the previously saved interrupt mask bits (DAIF). -/// -/// # Safety -/// -/// - Changes the HW state of the executing core. #[inline(always)] -pub unsafe fn local_irq_mask_save() -> u64 { +pub fn local_irq_mask_save() -> u64 { let saved = DAIF.get(); local_irq_mask(); @@ -127,12 +117,11 @@ pub unsafe fn local_irq_mask_save() -> u64 { /// Restore the interrupt mask bits (DAIF) using the callee's argument. /// -/// # Safety +/// # Invariant /// -/// - Changes the HW state of the executing core. /// - No sanity checks on the input. #[inline(always)] -pub unsafe fn local_irq_restore(saved: u64) { +pub fn local_irq_restore(saved: u64) { DAIF.set(saved); } diff --git a/18_backtrace/kernel/src/exception/asynchronous.rs b/18_backtrace/kernel/src/exception/asynchronous.rs index d9d2767c..3544e621 100644 --- a/18_backtrace/kernel/src/exception/asynchronous.rs +++ b/18_backtrace/kernel/src/exception/asynchronous.rs @@ -151,13 +151,9 @@ impl fmt::Display for IRQNumber<{ MAX_INCLUSIVE }> { /// previous state before returning, so this is deemed safe. #[inline(always)] pub fn exec_with_irq_masked(f: impl FnOnce() -> T) -> T { - let ret: T; - - unsafe { - let saved = local_irq_mask_save(); - ret = f(); - local_irq_restore(saved); - } + let saved = local_irq_mask_save(); + let ret = f(); + local_irq_restore(saved); ret } diff --git a/18_backtrace/kernel/src/panic_wait.rs b/18_backtrace/kernel/src/panic_wait.rs index c8e86fbd..c11ec67e 100644 --- a/18_backtrace/kernel/src/panic_wait.rs +++ b/18_backtrace/kernel/src/panic_wait.rs @@ -61,7 +61,7 @@ fn panic_prevent_reenter() { fn panic(info: &PanicInfo) -> ! { use crate::time::interface::TimeManager; - unsafe { exception::asynchronous::local_irq_mask() }; + exception::asynchronous::local_irq_mask(); // Protect against panic infinite loops if any of the following code panics itself. panic_prevent_reenter(); diff --git a/18_backtrace/kernel/tests/04_exception_irq_sanity.rs b/18_backtrace/kernel/tests/04_exception_irq_sanity.rs index 7b9628d5..e93a4caf 100644 --- a/18_backtrace/kernel/tests/04_exception_irq_sanity.rs +++ b/18_backtrace/kernel/tests/04_exception_irq_sanity.rs @@ -34,21 +34,21 @@ fn local_irq_mask_works() { // Precondition: IRQs are unmasked. assert!(exception::asynchronous::is_local_irq_masked()); - unsafe { exception::asynchronous::local_irq_mask() }; + exception::asynchronous::local_irq_mask(); assert!(!exception::asynchronous::is_local_irq_masked()); // Restore earlier state. - unsafe { exception::asynchronous::local_irq_unmask() }; + exception::asynchronous::local_irq_unmask(); } /// Check that IRQ unmasking works. #[kernel_test] fn local_irq_unmask_works() { // Precondition: IRQs are masked. - unsafe { exception::asynchronous::local_irq_mask() }; + exception::asynchronous::local_irq_mask(); assert!(!exception::asynchronous::is_local_irq_masked()); - unsafe { exception::asynchronous::local_irq_unmask() }; + exception::asynchronous::local_irq_unmask(); assert!(exception::asynchronous::is_local_irq_masked()); } @@ -58,12 +58,12 @@ fn local_irq_mask_save_works() { // Precondition: IRQs are unmasked. assert!(exception::asynchronous::is_local_irq_masked()); - let first = unsafe { exception::asynchronous::local_irq_mask_save() }; + let first = exception::asynchronous::local_irq_mask_save(); assert!(!exception::asynchronous::is_local_irq_masked()); - let second = unsafe { exception::asynchronous::local_irq_mask_save() }; + let second = exception::asynchronous::local_irq_mask_save(); assert_ne!(first, second); - unsafe { exception::asynchronous::local_irq_restore(first) }; + exception::asynchronous::local_irq_restore(first); assert!(exception::asynchronous::is_local_irq_masked()); } diff --git a/19_kernel_heap/kernel/src/_arch/aarch64/exception/asynchronous.rs b/19_kernel_heap/kernel/src/_arch/aarch64/exception/asynchronous.rs index 73b82e65..cf6f97ac 100644 --- a/19_kernel_heap/kernel/src/_arch/aarch64/exception/asynchronous.rs +++ b/19_kernel_heap/kernel/src/_arch/aarch64/exception/asynchronous.rs @@ -83,42 +83,32 @@ pub fn is_local_irq_masked() -> bool { /// /// "Writes to PSTATE.{PAN, D, A, I, F} occur in program order without the need for additional /// synchronization." -/// -/// # Safety -/// -/// - Changes the HW state of the executing core. #[inline(always)] -pub unsafe fn local_irq_unmask() { - #[rustfmt::skip] - asm!( - "msr DAIFClr, {arg}", - arg = const daif_bits::IRQ, - options(nomem, nostack, preserves_flags) - ); +pub fn local_irq_unmask() { + unsafe { + asm!( + "msr DAIFClr, {arg}", + arg = const daif_bits::IRQ, + options(nomem, nostack, preserves_flags) + ); + } } /// Mask IRQs on the executing core. -/// -/// # Safety -/// -/// - Changes the HW state of the executing core. #[inline(always)] -pub unsafe fn local_irq_mask() { - #[rustfmt::skip] - asm!( - "msr DAIFSet, {arg}", - arg = const daif_bits::IRQ, - options(nomem, nostack, preserves_flags) - ); +pub fn local_irq_mask() { + unsafe { + asm!( + "msr DAIFSet, {arg}", + arg = const daif_bits::IRQ, + options(nomem, nostack, preserves_flags) + ); + } } /// Mask IRQs on the executing core and return the previously saved interrupt mask bits (DAIF). -/// -/// # Safety -/// -/// - Changes the HW state of the executing core. #[inline(always)] -pub unsafe fn local_irq_mask_save() -> u64 { +pub fn local_irq_mask_save() -> u64 { let saved = DAIF.get(); local_irq_mask(); @@ -127,12 +117,11 @@ pub unsafe fn local_irq_mask_save() -> u64 { /// Restore the interrupt mask bits (DAIF) using the callee's argument. /// -/// # Safety +/// # Invariant /// -/// - Changes the HW state of the executing core. /// - No sanity checks on the input. #[inline(always)] -pub unsafe fn local_irq_restore(saved: u64) { +pub fn local_irq_restore(saved: u64) { DAIF.set(saved); } diff --git a/19_kernel_heap/kernel/src/exception/asynchronous.rs b/19_kernel_heap/kernel/src/exception/asynchronous.rs index d9d2767c..3544e621 100644 --- a/19_kernel_heap/kernel/src/exception/asynchronous.rs +++ b/19_kernel_heap/kernel/src/exception/asynchronous.rs @@ -151,13 +151,9 @@ impl fmt::Display for IRQNumber<{ MAX_INCLUSIVE }> { /// previous state before returning, so this is deemed safe. #[inline(always)] pub fn exec_with_irq_masked(f: impl FnOnce() -> T) -> T { - let ret: T; - - unsafe { - let saved = local_irq_mask_save(); - ret = f(); - local_irq_restore(saved); - } + let saved = local_irq_mask_save(); + let ret = f(); + local_irq_restore(saved); ret } diff --git a/19_kernel_heap/kernel/src/panic_wait.rs b/19_kernel_heap/kernel/src/panic_wait.rs index c8e86fbd..c11ec67e 100644 --- a/19_kernel_heap/kernel/src/panic_wait.rs +++ b/19_kernel_heap/kernel/src/panic_wait.rs @@ -61,7 +61,7 @@ fn panic_prevent_reenter() { fn panic(info: &PanicInfo) -> ! { use crate::time::interface::TimeManager; - unsafe { exception::asynchronous::local_irq_mask() }; + exception::asynchronous::local_irq_mask(); // Protect against panic infinite loops if any of the following code panics itself. panic_prevent_reenter(); diff --git a/19_kernel_heap/kernel/tests/04_exception_irq_sanity.rs b/19_kernel_heap/kernel/tests/04_exception_irq_sanity.rs index 7b9628d5..e93a4caf 100644 --- a/19_kernel_heap/kernel/tests/04_exception_irq_sanity.rs +++ b/19_kernel_heap/kernel/tests/04_exception_irq_sanity.rs @@ -34,21 +34,21 @@ fn local_irq_mask_works() { // Precondition: IRQs are unmasked. assert!(exception::asynchronous::is_local_irq_masked()); - unsafe { exception::asynchronous::local_irq_mask() }; + exception::asynchronous::local_irq_mask(); assert!(!exception::asynchronous::is_local_irq_masked()); // Restore earlier state. - unsafe { exception::asynchronous::local_irq_unmask() }; + exception::asynchronous::local_irq_unmask(); } /// Check that IRQ unmasking works. #[kernel_test] fn local_irq_unmask_works() { // Precondition: IRQs are masked. - unsafe { exception::asynchronous::local_irq_mask() }; + exception::asynchronous::local_irq_mask(); assert!(!exception::asynchronous::is_local_irq_masked()); - unsafe { exception::asynchronous::local_irq_unmask() }; + exception::asynchronous::local_irq_unmask(); assert!(exception::asynchronous::is_local_irq_masked()); } @@ -58,12 +58,12 @@ fn local_irq_mask_save_works() { // Precondition: IRQs are unmasked. assert!(exception::asynchronous::is_local_irq_masked()); - let first = unsafe { exception::asynchronous::local_irq_mask_save() }; + let first = exception::asynchronous::local_irq_mask_save(); assert!(!exception::asynchronous::is_local_irq_masked()); - let second = unsafe { exception::asynchronous::local_irq_mask_save() }; + let second = exception::asynchronous::local_irq_mask_save(); assert_ne!(first, second); - unsafe { exception::asynchronous::local_irq_restore(first) }; + exception::asynchronous::local_irq_restore(first); assert!(exception::asynchronous::is_local_irq_masked()); } From bb2f1c79b7cc61c528d0ed0bb40597e88cff814b Mon Sep 17 00:00:00 2001 From: Andre Richter Date: Thu, 19 May 2022 23:19:25 +0200 Subject: [PATCH 40/75] Remove more unjustified unsafe --- 11_exceptions_part1_groundwork/README.md | 28 +++++++++---------- .../src/_arch/aarch64/exception.rs | 24 ++++++++-------- .../kernel/src/_arch/aarch64/exception.rs | 24 ++++++++-------- 13_exceptions_part2_peripheral_IRQs/README.md | 10 +++---- .../kernel/src/_arch/aarch64/exception.rs | 26 ++++++++--------- .../kernel/src/_arch/aarch64/exception.rs | 26 ++++++++--------- .../kernel/src/_arch/aarch64/exception.rs | 26 ++++++++--------- .../kernel/src/_arch/aarch64/exception.rs | 26 ++++++++--------- .../kernel/src/_arch/aarch64/exception.rs | 26 ++++++++--------- .../kernel/src/_arch/aarch64/exception.rs | 26 ++++++++--------- .../kernel/src/_arch/aarch64/exception.rs | 26 ++++++++--------- 11 files changed, 134 insertions(+), 134 deletions(-) diff --git a/11_exceptions_part1_groundwork/README.md b/11_exceptions_part1_groundwork/README.md index d0b4b7f7..4fc713a5 100644 --- a/11_exceptions_part1_groundwork/README.md +++ b/11_exceptions_part1_groundwork/README.md @@ -328,7 +328,7 @@ The actual handlers referenced from the assembly can now branch to it for the ti ```rust #[no_mangle] -unsafe extern "C" fn current_elx_irq(e: &mut ExceptionContext) { +extern "C" fn current_elx_irq(e: &mut ExceptionContext) { default_exception_handler(e); } ``` @@ -367,7 +367,7 @@ To survive this exception, the respective handler has a special demo case: ```rust #[no_mangle] -unsafe extern "C" fn current_elx_synchronous(e: &mut ExceptionContext) { +extern "C" fn current_elx_synchronous(e: &mut ExceptionContext) { if e.fault_address_valid() { let far_el1 = FAR_EL1.get(); @@ -565,17 +565,17 @@ diff -uNr 10_virtual_mem_part1_identity_mapping/src/_arch/aarch64/exception.rs 1 +//------------------------------------------------------------------------------ + +#[no_mangle] -+unsafe extern "C" fn current_el0_synchronous(_e: &mut ExceptionContext) { ++extern "C" fn current_el0_synchronous(_e: &mut ExceptionContext) { + panic!("Should not be here. Use of SP_EL0 in EL1 is not supported.") +} + +#[no_mangle] -+unsafe extern "C" fn current_el0_irq(_e: &mut ExceptionContext) { ++extern "C" fn current_el0_irq(_e: &mut ExceptionContext) { + panic!("Should not be here. Use of SP_EL0 in EL1 is not supported.") +} + +#[no_mangle] -+unsafe extern "C" fn current_el0_serror(_e: &mut ExceptionContext) { ++extern "C" fn current_el0_serror(_e: &mut ExceptionContext) { + panic!("Should not be here. Use of SP_EL0 in EL1 is not supported.") +} + @@ -584,7 +584,7 @@ diff -uNr 10_virtual_mem_part1_identity_mapping/src/_arch/aarch64/exception.rs 1 +//------------------------------------------------------------------------------ + +#[no_mangle] -+unsafe extern "C" fn current_elx_synchronous(e: &mut ExceptionContext) { ++extern "C" fn current_elx_synchronous(e: &mut ExceptionContext) { + if e.fault_address_valid() { + let far_el1 = FAR_EL1.get(); + @@ -601,12 +601,12 @@ diff -uNr 10_virtual_mem_part1_identity_mapping/src/_arch/aarch64/exception.rs 1 +} + +#[no_mangle] -+unsafe extern "C" fn current_elx_irq(e: &mut ExceptionContext) { ++extern "C" fn current_elx_irq(e: &mut ExceptionContext) { + default_exception_handler(e); +} + +#[no_mangle] -+unsafe extern "C" fn current_elx_serror(e: &mut ExceptionContext) { ++extern "C" fn current_elx_serror(e: &mut ExceptionContext) { + default_exception_handler(e); +} + @@ -615,17 +615,17 @@ diff -uNr 10_virtual_mem_part1_identity_mapping/src/_arch/aarch64/exception.rs 1 +//------------------------------------------------------------------------------ + +#[no_mangle] -+unsafe extern "C" fn lower_aarch64_synchronous(e: &mut ExceptionContext) { ++extern "C" fn lower_aarch64_synchronous(e: &mut ExceptionContext) { + default_exception_handler(e); +} + +#[no_mangle] -+unsafe extern "C" fn lower_aarch64_irq(e: &mut ExceptionContext) { ++extern "C" fn lower_aarch64_irq(e: &mut ExceptionContext) { + default_exception_handler(e); +} + +#[no_mangle] -+unsafe extern "C" fn lower_aarch64_serror(e: &mut ExceptionContext) { ++extern "C" fn lower_aarch64_serror(e: &mut ExceptionContext) { + default_exception_handler(e); +} + @@ -634,17 +634,17 @@ diff -uNr 10_virtual_mem_part1_identity_mapping/src/_arch/aarch64/exception.rs 1 +//------------------------------------------------------------------------------ + +#[no_mangle] -+unsafe extern "C" fn lower_aarch32_synchronous(e: &mut ExceptionContext) { ++extern "C" fn lower_aarch32_synchronous(e: &mut ExceptionContext) { + default_exception_handler(e); +} + +#[no_mangle] -+unsafe extern "C" fn lower_aarch32_irq(e: &mut ExceptionContext) { ++extern "C" fn lower_aarch32_irq(e: &mut ExceptionContext) { + default_exception_handler(e); +} + +#[no_mangle] -+unsafe extern "C" fn lower_aarch32_serror(e: &mut ExceptionContext) { ++extern "C" fn lower_aarch32_serror(e: &mut ExceptionContext) { + default_exception_handler(e); +} + diff --git a/11_exceptions_part1_groundwork/src/_arch/aarch64/exception.rs b/11_exceptions_part1_groundwork/src/_arch/aarch64/exception.rs index 7d3b4572..c72fb885 100644 --- a/11_exceptions_part1_groundwork/src/_arch/aarch64/exception.rs +++ b/11_exceptions_part1_groundwork/src/_arch/aarch64/exception.rs @@ -67,17 +67,17 @@ fn default_exception_handler(exc: &ExceptionContext) { //------------------------------------------------------------------------------ #[no_mangle] -unsafe extern "C" fn current_el0_synchronous(_e: &mut ExceptionContext) { +extern "C" fn current_el0_synchronous(_e: &mut ExceptionContext) { panic!("Should not be here. Use of SP_EL0 in EL1 is not supported.") } #[no_mangle] -unsafe extern "C" fn current_el0_irq(_e: &mut ExceptionContext) { +extern "C" fn current_el0_irq(_e: &mut ExceptionContext) { panic!("Should not be here. Use of SP_EL0 in EL1 is not supported.") } #[no_mangle] -unsafe extern "C" fn current_el0_serror(_e: &mut ExceptionContext) { +extern "C" fn current_el0_serror(_e: &mut ExceptionContext) { panic!("Should not be here. Use of SP_EL0 in EL1 is not supported.") } @@ -86,7 +86,7 @@ unsafe extern "C" fn current_el0_serror(_e: &mut ExceptionContext) { //------------------------------------------------------------------------------ #[no_mangle] -unsafe extern "C" fn current_elx_synchronous(e: &mut ExceptionContext) { +extern "C" fn current_elx_synchronous(e: &mut ExceptionContext) { if e.fault_address_valid() { let far_el1 = FAR_EL1.get(); @@ -103,12 +103,12 @@ unsafe extern "C" fn current_elx_synchronous(e: &mut ExceptionContext) { } #[no_mangle] -unsafe extern "C" fn current_elx_irq(e: &mut ExceptionContext) { +extern "C" fn current_elx_irq(e: &mut ExceptionContext) { default_exception_handler(e); } #[no_mangle] -unsafe extern "C" fn current_elx_serror(e: &mut ExceptionContext) { +extern "C" fn current_elx_serror(e: &mut ExceptionContext) { default_exception_handler(e); } @@ -117,17 +117,17 @@ unsafe extern "C" fn current_elx_serror(e: &mut ExceptionContext) { //------------------------------------------------------------------------------ #[no_mangle] -unsafe extern "C" fn lower_aarch64_synchronous(e: &mut ExceptionContext) { +extern "C" fn lower_aarch64_synchronous(e: &mut ExceptionContext) { default_exception_handler(e); } #[no_mangle] -unsafe extern "C" fn lower_aarch64_irq(e: &mut ExceptionContext) { +extern "C" fn lower_aarch64_irq(e: &mut ExceptionContext) { default_exception_handler(e); } #[no_mangle] -unsafe extern "C" fn lower_aarch64_serror(e: &mut ExceptionContext) { +extern "C" fn lower_aarch64_serror(e: &mut ExceptionContext) { default_exception_handler(e); } @@ -136,17 +136,17 @@ unsafe extern "C" fn lower_aarch64_serror(e: &mut ExceptionContext) { //------------------------------------------------------------------------------ #[no_mangle] -unsafe extern "C" fn lower_aarch32_synchronous(e: &mut ExceptionContext) { +extern "C" fn lower_aarch32_synchronous(e: &mut ExceptionContext) { default_exception_handler(e); } #[no_mangle] -unsafe extern "C" fn lower_aarch32_irq(e: &mut ExceptionContext) { +extern "C" fn lower_aarch32_irq(e: &mut ExceptionContext) { default_exception_handler(e); } #[no_mangle] -unsafe extern "C" fn lower_aarch32_serror(e: &mut ExceptionContext) { +extern "C" fn lower_aarch32_serror(e: &mut ExceptionContext) { default_exception_handler(e); } diff --git a/12_integrated_testing/kernel/src/_arch/aarch64/exception.rs b/12_integrated_testing/kernel/src/_arch/aarch64/exception.rs index 0f83052c..5664605e 100644 --- a/12_integrated_testing/kernel/src/_arch/aarch64/exception.rs +++ b/12_integrated_testing/kernel/src/_arch/aarch64/exception.rs @@ -67,17 +67,17 @@ fn default_exception_handler(exc: &ExceptionContext) { //------------------------------------------------------------------------------ #[no_mangle] -unsafe extern "C" fn current_el0_synchronous(_e: &mut ExceptionContext) { +extern "C" fn current_el0_synchronous(_e: &mut ExceptionContext) { panic!("Should not be here. Use of SP_EL0 in EL1 is not supported.") } #[no_mangle] -unsafe extern "C" fn current_el0_irq(_e: &mut ExceptionContext) { +extern "C" fn current_el0_irq(_e: &mut ExceptionContext) { panic!("Should not be here. Use of SP_EL0 in EL1 is not supported.") } #[no_mangle] -unsafe extern "C" fn current_el0_serror(_e: &mut ExceptionContext) { +extern "C" fn current_el0_serror(_e: &mut ExceptionContext) { panic!("Should not be here. Use of SP_EL0 in EL1 is not supported.") } @@ -86,7 +86,7 @@ unsafe extern "C" fn current_el0_serror(_e: &mut ExceptionContext) { //------------------------------------------------------------------------------ #[no_mangle] -unsafe extern "C" fn current_elx_synchronous(e: &mut ExceptionContext) { +extern "C" fn current_elx_synchronous(e: &mut ExceptionContext) { #[cfg(feature = "test_build")] { const TEST_SVC_ID: u64 = 0x1337; @@ -102,12 +102,12 @@ unsafe extern "C" fn current_elx_synchronous(e: &mut ExceptionContext) { } #[no_mangle] -unsafe extern "C" fn current_elx_irq(e: &mut ExceptionContext) { +extern "C" fn current_elx_irq(e: &mut ExceptionContext) { default_exception_handler(e); } #[no_mangle] -unsafe extern "C" fn current_elx_serror(e: &mut ExceptionContext) { +extern "C" fn current_elx_serror(e: &mut ExceptionContext) { default_exception_handler(e); } @@ -116,17 +116,17 @@ unsafe extern "C" fn current_elx_serror(e: &mut ExceptionContext) { //------------------------------------------------------------------------------ #[no_mangle] -unsafe extern "C" fn lower_aarch64_synchronous(e: &mut ExceptionContext) { +extern "C" fn lower_aarch64_synchronous(e: &mut ExceptionContext) { default_exception_handler(e); } #[no_mangle] -unsafe extern "C" fn lower_aarch64_irq(e: &mut ExceptionContext) { +extern "C" fn lower_aarch64_irq(e: &mut ExceptionContext) { default_exception_handler(e); } #[no_mangle] -unsafe extern "C" fn lower_aarch64_serror(e: &mut ExceptionContext) { +extern "C" fn lower_aarch64_serror(e: &mut ExceptionContext) { default_exception_handler(e); } @@ -135,17 +135,17 @@ unsafe extern "C" fn lower_aarch64_serror(e: &mut ExceptionContext) { //------------------------------------------------------------------------------ #[no_mangle] -unsafe extern "C" fn lower_aarch32_synchronous(e: &mut ExceptionContext) { +extern "C" fn lower_aarch32_synchronous(e: &mut ExceptionContext) { default_exception_handler(e); } #[no_mangle] -unsafe extern "C" fn lower_aarch32_irq(e: &mut ExceptionContext) { +extern "C" fn lower_aarch32_irq(e: &mut ExceptionContext) { default_exception_handler(e); } #[no_mangle] -unsafe extern "C" fn lower_aarch32_serror(e: &mut ExceptionContext) { +extern "C" fn lower_aarch32_serror(e: &mut ExceptionContext) { default_exception_handler(e); } diff --git a/13_exceptions_part2_peripheral_IRQs/README.md b/13_exceptions_part2_peripheral_IRQs/README.md index 65be428a..74eb28c3 100644 --- a/13_exceptions_part2_peripheral_IRQs/README.md +++ b/13_exceptions_part2_peripheral_IRQs/README.md @@ -367,8 +367,8 @@ the the implementation of the trait's handling function: ```rust #[no_mangle] -unsafe extern "C" fn current_elx_irq(_e: &mut ExceptionContext) { - let token = &exception::asynchronous::IRQContext::new(); +extern "C" fn current_elx_irq(_e: &mut ExceptionContext) { + let token = unsafe { &exception::asynchronous::IRQContext::new() }; exception::asynchronous::irq_manager().handle_pending_irqs(token); } ``` @@ -887,10 +887,10 @@ diff -uNr 12_integrated_testing/kernel/src/_arch/aarch64/exception.rs 13_excepti } #[no_mangle] --unsafe extern "C" fn current_elx_irq(e: &mut ExceptionContext) { +-extern "C" fn current_elx_irq(e: &mut ExceptionContext) { - default_exception_handler(e); -+unsafe extern "C" fn current_elx_irq(_e: &mut ExceptionContext) { -+ let token = &exception::asynchronous::IRQContext::new(); ++extern "C" fn current_elx_irq(_e: &mut ExceptionContext) { ++ let token = unsafe { &exception::asynchronous::IRQContext::new() }; + exception::asynchronous::irq_manager().handle_pending_irqs(token); } diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/exception.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/exception.rs index fa6748a6..3aa6fb24 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/exception.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/exception.rs @@ -68,17 +68,17 @@ fn default_exception_handler(exc: &ExceptionContext) { //------------------------------------------------------------------------------ #[no_mangle] -unsafe extern "C" fn current_el0_synchronous(_e: &mut ExceptionContext) { +extern "C" fn current_el0_synchronous(_e: &mut ExceptionContext) { panic!("Should not be here. Use of SP_EL0 in EL1 is not supported.") } #[no_mangle] -unsafe extern "C" fn current_el0_irq(_e: &mut ExceptionContext) { +extern "C" fn current_el0_irq(_e: &mut ExceptionContext) { panic!("Should not be here. Use of SP_EL0 in EL1 is not supported.") } #[no_mangle] -unsafe extern "C" fn current_el0_serror(_e: &mut ExceptionContext) { +extern "C" fn current_el0_serror(_e: &mut ExceptionContext) { panic!("Should not be here. Use of SP_EL0 in EL1 is not supported.") } @@ -87,7 +87,7 @@ unsafe extern "C" fn current_el0_serror(_e: &mut ExceptionContext) { //------------------------------------------------------------------------------ #[no_mangle] -unsafe extern "C" fn current_elx_synchronous(e: &mut ExceptionContext) { +extern "C" fn current_elx_synchronous(e: &mut ExceptionContext) { #[cfg(feature = "test_build")] { const TEST_SVC_ID: u64 = 0x1337; @@ -103,13 +103,13 @@ unsafe extern "C" fn current_elx_synchronous(e: &mut ExceptionContext) { } #[no_mangle] -unsafe extern "C" fn current_elx_irq(_e: &mut ExceptionContext) { - let token = &exception::asynchronous::IRQContext::new(); +extern "C" fn current_elx_irq(_e: &mut ExceptionContext) { + let token = unsafe { &exception::asynchronous::IRQContext::new() }; exception::asynchronous::irq_manager().handle_pending_irqs(token); } #[no_mangle] -unsafe extern "C" fn current_elx_serror(e: &mut ExceptionContext) { +extern "C" fn current_elx_serror(e: &mut ExceptionContext) { default_exception_handler(e); } @@ -118,17 +118,17 @@ unsafe extern "C" fn current_elx_serror(e: &mut ExceptionContext) { //------------------------------------------------------------------------------ #[no_mangle] -unsafe extern "C" fn lower_aarch64_synchronous(e: &mut ExceptionContext) { +extern "C" fn lower_aarch64_synchronous(e: &mut ExceptionContext) { default_exception_handler(e); } #[no_mangle] -unsafe extern "C" fn lower_aarch64_irq(e: &mut ExceptionContext) { +extern "C" fn lower_aarch64_irq(e: &mut ExceptionContext) { default_exception_handler(e); } #[no_mangle] -unsafe extern "C" fn lower_aarch64_serror(e: &mut ExceptionContext) { +extern "C" fn lower_aarch64_serror(e: &mut ExceptionContext) { default_exception_handler(e); } @@ -137,17 +137,17 @@ unsafe extern "C" fn lower_aarch64_serror(e: &mut ExceptionContext) { //------------------------------------------------------------------------------ #[no_mangle] -unsafe extern "C" fn lower_aarch32_synchronous(e: &mut ExceptionContext) { +extern "C" fn lower_aarch32_synchronous(e: &mut ExceptionContext) { default_exception_handler(e); } #[no_mangle] -unsafe extern "C" fn lower_aarch32_irq(e: &mut ExceptionContext) { +extern "C" fn lower_aarch32_irq(e: &mut ExceptionContext) { default_exception_handler(e); } #[no_mangle] -unsafe extern "C" fn lower_aarch32_serror(e: &mut ExceptionContext) { +extern "C" fn lower_aarch32_serror(e: &mut ExceptionContext) { default_exception_handler(e); } diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/exception.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/exception.rs index fa6748a6..3aa6fb24 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/exception.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/exception.rs @@ -68,17 +68,17 @@ fn default_exception_handler(exc: &ExceptionContext) { //------------------------------------------------------------------------------ #[no_mangle] -unsafe extern "C" fn current_el0_synchronous(_e: &mut ExceptionContext) { +extern "C" fn current_el0_synchronous(_e: &mut ExceptionContext) { panic!("Should not be here. Use of SP_EL0 in EL1 is not supported.") } #[no_mangle] -unsafe extern "C" fn current_el0_irq(_e: &mut ExceptionContext) { +extern "C" fn current_el0_irq(_e: &mut ExceptionContext) { panic!("Should not be here. Use of SP_EL0 in EL1 is not supported.") } #[no_mangle] -unsafe extern "C" fn current_el0_serror(_e: &mut ExceptionContext) { +extern "C" fn current_el0_serror(_e: &mut ExceptionContext) { panic!("Should not be here. Use of SP_EL0 in EL1 is not supported.") } @@ -87,7 +87,7 @@ unsafe extern "C" fn current_el0_serror(_e: &mut ExceptionContext) { //------------------------------------------------------------------------------ #[no_mangle] -unsafe extern "C" fn current_elx_synchronous(e: &mut ExceptionContext) { +extern "C" fn current_elx_synchronous(e: &mut ExceptionContext) { #[cfg(feature = "test_build")] { const TEST_SVC_ID: u64 = 0x1337; @@ -103,13 +103,13 @@ unsafe extern "C" fn current_elx_synchronous(e: &mut ExceptionContext) { } #[no_mangle] -unsafe extern "C" fn current_elx_irq(_e: &mut ExceptionContext) { - let token = &exception::asynchronous::IRQContext::new(); +extern "C" fn current_elx_irq(_e: &mut ExceptionContext) { + let token = unsafe { &exception::asynchronous::IRQContext::new() }; exception::asynchronous::irq_manager().handle_pending_irqs(token); } #[no_mangle] -unsafe extern "C" fn current_elx_serror(e: &mut ExceptionContext) { +extern "C" fn current_elx_serror(e: &mut ExceptionContext) { default_exception_handler(e); } @@ -118,17 +118,17 @@ unsafe extern "C" fn current_elx_serror(e: &mut ExceptionContext) { //------------------------------------------------------------------------------ #[no_mangle] -unsafe extern "C" fn lower_aarch64_synchronous(e: &mut ExceptionContext) { +extern "C" fn lower_aarch64_synchronous(e: &mut ExceptionContext) { default_exception_handler(e); } #[no_mangle] -unsafe extern "C" fn lower_aarch64_irq(e: &mut ExceptionContext) { +extern "C" fn lower_aarch64_irq(e: &mut ExceptionContext) { default_exception_handler(e); } #[no_mangle] -unsafe extern "C" fn lower_aarch64_serror(e: &mut ExceptionContext) { +extern "C" fn lower_aarch64_serror(e: &mut ExceptionContext) { default_exception_handler(e); } @@ -137,17 +137,17 @@ unsafe extern "C" fn lower_aarch64_serror(e: &mut ExceptionContext) { //------------------------------------------------------------------------------ #[no_mangle] -unsafe extern "C" fn lower_aarch32_synchronous(e: &mut ExceptionContext) { +extern "C" fn lower_aarch32_synchronous(e: &mut ExceptionContext) { default_exception_handler(e); } #[no_mangle] -unsafe extern "C" fn lower_aarch32_irq(e: &mut ExceptionContext) { +extern "C" fn lower_aarch32_irq(e: &mut ExceptionContext) { default_exception_handler(e); } #[no_mangle] -unsafe extern "C" fn lower_aarch32_serror(e: &mut ExceptionContext) { +extern "C" fn lower_aarch32_serror(e: &mut ExceptionContext) { default_exception_handler(e); } diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/exception.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/exception.rs index fa6748a6..3aa6fb24 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/exception.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/exception.rs @@ -68,17 +68,17 @@ fn default_exception_handler(exc: &ExceptionContext) { //------------------------------------------------------------------------------ #[no_mangle] -unsafe extern "C" fn current_el0_synchronous(_e: &mut ExceptionContext) { +extern "C" fn current_el0_synchronous(_e: &mut ExceptionContext) { panic!("Should not be here. Use of SP_EL0 in EL1 is not supported.") } #[no_mangle] -unsafe extern "C" fn current_el0_irq(_e: &mut ExceptionContext) { +extern "C" fn current_el0_irq(_e: &mut ExceptionContext) { panic!("Should not be here. Use of SP_EL0 in EL1 is not supported.") } #[no_mangle] -unsafe extern "C" fn current_el0_serror(_e: &mut ExceptionContext) { +extern "C" fn current_el0_serror(_e: &mut ExceptionContext) { panic!("Should not be here. Use of SP_EL0 in EL1 is not supported.") } @@ -87,7 +87,7 @@ unsafe extern "C" fn current_el0_serror(_e: &mut ExceptionContext) { //------------------------------------------------------------------------------ #[no_mangle] -unsafe extern "C" fn current_elx_synchronous(e: &mut ExceptionContext) { +extern "C" fn current_elx_synchronous(e: &mut ExceptionContext) { #[cfg(feature = "test_build")] { const TEST_SVC_ID: u64 = 0x1337; @@ -103,13 +103,13 @@ unsafe extern "C" fn current_elx_synchronous(e: &mut ExceptionContext) { } #[no_mangle] -unsafe extern "C" fn current_elx_irq(_e: &mut ExceptionContext) { - let token = &exception::asynchronous::IRQContext::new(); +extern "C" fn current_elx_irq(_e: &mut ExceptionContext) { + let token = unsafe { &exception::asynchronous::IRQContext::new() }; exception::asynchronous::irq_manager().handle_pending_irqs(token); } #[no_mangle] -unsafe extern "C" fn current_elx_serror(e: &mut ExceptionContext) { +extern "C" fn current_elx_serror(e: &mut ExceptionContext) { default_exception_handler(e); } @@ -118,17 +118,17 @@ unsafe extern "C" fn current_elx_serror(e: &mut ExceptionContext) { //------------------------------------------------------------------------------ #[no_mangle] -unsafe extern "C" fn lower_aarch64_synchronous(e: &mut ExceptionContext) { +extern "C" fn lower_aarch64_synchronous(e: &mut ExceptionContext) { default_exception_handler(e); } #[no_mangle] -unsafe extern "C" fn lower_aarch64_irq(e: &mut ExceptionContext) { +extern "C" fn lower_aarch64_irq(e: &mut ExceptionContext) { default_exception_handler(e); } #[no_mangle] -unsafe extern "C" fn lower_aarch64_serror(e: &mut ExceptionContext) { +extern "C" fn lower_aarch64_serror(e: &mut ExceptionContext) { default_exception_handler(e); } @@ -137,17 +137,17 @@ unsafe extern "C" fn lower_aarch64_serror(e: &mut ExceptionContext) { //------------------------------------------------------------------------------ #[no_mangle] -unsafe extern "C" fn lower_aarch32_synchronous(e: &mut ExceptionContext) { +extern "C" fn lower_aarch32_synchronous(e: &mut ExceptionContext) { default_exception_handler(e); } #[no_mangle] -unsafe extern "C" fn lower_aarch32_irq(e: &mut ExceptionContext) { +extern "C" fn lower_aarch32_irq(e: &mut ExceptionContext) { default_exception_handler(e); } #[no_mangle] -unsafe extern "C" fn lower_aarch32_serror(e: &mut ExceptionContext) { +extern "C" fn lower_aarch32_serror(e: &mut ExceptionContext) { default_exception_handler(e); } diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/exception.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/exception.rs index fa6748a6..3aa6fb24 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/exception.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/exception.rs @@ -68,17 +68,17 @@ fn default_exception_handler(exc: &ExceptionContext) { //------------------------------------------------------------------------------ #[no_mangle] -unsafe extern "C" fn current_el0_synchronous(_e: &mut ExceptionContext) { +extern "C" fn current_el0_synchronous(_e: &mut ExceptionContext) { panic!("Should not be here. Use of SP_EL0 in EL1 is not supported.") } #[no_mangle] -unsafe extern "C" fn current_el0_irq(_e: &mut ExceptionContext) { +extern "C" fn current_el0_irq(_e: &mut ExceptionContext) { panic!("Should not be here. Use of SP_EL0 in EL1 is not supported.") } #[no_mangle] -unsafe extern "C" fn current_el0_serror(_e: &mut ExceptionContext) { +extern "C" fn current_el0_serror(_e: &mut ExceptionContext) { panic!("Should not be here. Use of SP_EL0 in EL1 is not supported.") } @@ -87,7 +87,7 @@ unsafe extern "C" fn current_el0_serror(_e: &mut ExceptionContext) { //------------------------------------------------------------------------------ #[no_mangle] -unsafe extern "C" fn current_elx_synchronous(e: &mut ExceptionContext) { +extern "C" fn current_elx_synchronous(e: &mut ExceptionContext) { #[cfg(feature = "test_build")] { const TEST_SVC_ID: u64 = 0x1337; @@ -103,13 +103,13 @@ unsafe extern "C" fn current_elx_synchronous(e: &mut ExceptionContext) { } #[no_mangle] -unsafe extern "C" fn current_elx_irq(_e: &mut ExceptionContext) { - let token = &exception::asynchronous::IRQContext::new(); +extern "C" fn current_elx_irq(_e: &mut ExceptionContext) { + let token = unsafe { &exception::asynchronous::IRQContext::new() }; exception::asynchronous::irq_manager().handle_pending_irqs(token); } #[no_mangle] -unsafe extern "C" fn current_elx_serror(e: &mut ExceptionContext) { +extern "C" fn current_elx_serror(e: &mut ExceptionContext) { default_exception_handler(e); } @@ -118,17 +118,17 @@ unsafe extern "C" fn current_elx_serror(e: &mut ExceptionContext) { //------------------------------------------------------------------------------ #[no_mangle] -unsafe extern "C" fn lower_aarch64_synchronous(e: &mut ExceptionContext) { +extern "C" fn lower_aarch64_synchronous(e: &mut ExceptionContext) { default_exception_handler(e); } #[no_mangle] -unsafe extern "C" fn lower_aarch64_irq(e: &mut ExceptionContext) { +extern "C" fn lower_aarch64_irq(e: &mut ExceptionContext) { default_exception_handler(e); } #[no_mangle] -unsafe extern "C" fn lower_aarch64_serror(e: &mut ExceptionContext) { +extern "C" fn lower_aarch64_serror(e: &mut ExceptionContext) { default_exception_handler(e); } @@ -137,17 +137,17 @@ unsafe extern "C" fn lower_aarch64_serror(e: &mut ExceptionContext) { //------------------------------------------------------------------------------ #[no_mangle] -unsafe extern "C" fn lower_aarch32_synchronous(e: &mut ExceptionContext) { +extern "C" fn lower_aarch32_synchronous(e: &mut ExceptionContext) { default_exception_handler(e); } #[no_mangle] -unsafe extern "C" fn lower_aarch32_irq(e: &mut ExceptionContext) { +extern "C" fn lower_aarch32_irq(e: &mut ExceptionContext) { default_exception_handler(e); } #[no_mangle] -unsafe extern "C" fn lower_aarch32_serror(e: &mut ExceptionContext) { +extern "C" fn lower_aarch32_serror(e: &mut ExceptionContext) { default_exception_handler(e); } diff --git a/17_kernel_symbols/kernel/src/_arch/aarch64/exception.rs b/17_kernel_symbols/kernel/src/_arch/aarch64/exception.rs index 3672466c..1d720f3e 100644 --- a/17_kernel_symbols/kernel/src/_arch/aarch64/exception.rs +++ b/17_kernel_symbols/kernel/src/_arch/aarch64/exception.rs @@ -68,17 +68,17 @@ fn default_exception_handler(exc: &ExceptionContext) { //------------------------------------------------------------------------------ #[no_mangle] -unsafe extern "C" fn current_el0_synchronous(_e: &mut ExceptionContext) { +extern "C" fn current_el0_synchronous(_e: &mut ExceptionContext) { panic!("Should not be here. Use of SP_EL0 in EL1 is not supported.") } #[no_mangle] -unsafe extern "C" fn current_el0_irq(_e: &mut ExceptionContext) { +extern "C" fn current_el0_irq(_e: &mut ExceptionContext) { panic!("Should not be here. Use of SP_EL0 in EL1 is not supported.") } #[no_mangle] -unsafe extern "C" fn current_el0_serror(_e: &mut ExceptionContext) { +extern "C" fn current_el0_serror(_e: &mut ExceptionContext) { panic!("Should not be here. Use of SP_EL0 in EL1 is not supported.") } @@ -87,7 +87,7 @@ unsafe extern "C" fn current_el0_serror(_e: &mut ExceptionContext) { //------------------------------------------------------------------------------ #[no_mangle] -unsafe extern "C" fn current_elx_synchronous(e: &mut ExceptionContext) { +extern "C" fn current_elx_synchronous(e: &mut ExceptionContext) { #[cfg(feature = "test_build")] { const TEST_SVC_ID: u64 = 0x1337; @@ -103,13 +103,13 @@ unsafe extern "C" fn current_elx_synchronous(e: &mut ExceptionContext) { } #[no_mangle] -unsafe extern "C" fn current_elx_irq(_e: &mut ExceptionContext) { - let token = &exception::asynchronous::IRQContext::new(); +extern "C" fn current_elx_irq(_e: &mut ExceptionContext) { + let token = unsafe { &exception::asynchronous::IRQContext::new() }; exception::asynchronous::irq_manager().handle_pending_irqs(token); } #[no_mangle] -unsafe extern "C" fn current_elx_serror(e: &mut ExceptionContext) { +extern "C" fn current_elx_serror(e: &mut ExceptionContext) { default_exception_handler(e); } @@ -118,17 +118,17 @@ unsafe extern "C" fn current_elx_serror(e: &mut ExceptionContext) { //------------------------------------------------------------------------------ #[no_mangle] -unsafe extern "C" fn lower_aarch64_synchronous(e: &mut ExceptionContext) { +extern "C" fn lower_aarch64_synchronous(e: &mut ExceptionContext) { default_exception_handler(e); } #[no_mangle] -unsafe extern "C" fn lower_aarch64_irq(e: &mut ExceptionContext) { +extern "C" fn lower_aarch64_irq(e: &mut ExceptionContext) { default_exception_handler(e); } #[no_mangle] -unsafe extern "C" fn lower_aarch64_serror(e: &mut ExceptionContext) { +extern "C" fn lower_aarch64_serror(e: &mut ExceptionContext) { default_exception_handler(e); } @@ -137,17 +137,17 @@ unsafe extern "C" fn lower_aarch64_serror(e: &mut ExceptionContext) { //------------------------------------------------------------------------------ #[no_mangle] -unsafe extern "C" fn lower_aarch32_synchronous(e: &mut ExceptionContext) { +extern "C" fn lower_aarch32_synchronous(e: &mut ExceptionContext) { default_exception_handler(e); } #[no_mangle] -unsafe extern "C" fn lower_aarch32_irq(e: &mut ExceptionContext) { +extern "C" fn lower_aarch32_irq(e: &mut ExceptionContext) { default_exception_handler(e); } #[no_mangle] -unsafe extern "C" fn lower_aarch32_serror(e: &mut ExceptionContext) { +extern "C" fn lower_aarch32_serror(e: &mut ExceptionContext) { default_exception_handler(e); } diff --git a/18_backtrace/kernel/src/_arch/aarch64/exception.rs b/18_backtrace/kernel/src/_arch/aarch64/exception.rs index 17ec3009..e03e382f 100644 --- a/18_backtrace/kernel/src/_arch/aarch64/exception.rs +++ b/18_backtrace/kernel/src/_arch/aarch64/exception.rs @@ -72,17 +72,17 @@ fn default_exception_handler(exc: &ExceptionContext) { //------------------------------------------------------------------------------ #[no_mangle] -unsafe extern "C" fn current_el0_synchronous(_e: &mut ExceptionContext) { +extern "C" fn current_el0_synchronous(_e: &mut ExceptionContext) { panic!("Should not be here. Use of SP_EL0 in EL1 is not supported.") } #[no_mangle] -unsafe extern "C" fn current_el0_irq(_e: &mut ExceptionContext) { +extern "C" fn current_el0_irq(_e: &mut ExceptionContext) { panic!("Should not be here. Use of SP_EL0 in EL1 is not supported.") } #[no_mangle] -unsafe extern "C" fn current_el0_serror(_e: &mut ExceptionContext) { +extern "C" fn current_el0_serror(_e: &mut ExceptionContext) { panic!("Should not be here. Use of SP_EL0 in EL1 is not supported.") } @@ -91,7 +91,7 @@ unsafe extern "C" fn current_el0_serror(_e: &mut ExceptionContext) { //------------------------------------------------------------------------------ #[no_mangle] -unsafe extern "C" fn current_elx_synchronous(e: &mut ExceptionContext) { +extern "C" fn current_elx_synchronous(e: &mut ExceptionContext) { #[cfg(feature = "test_build")] { const TEST_SVC_ID: u64 = 0x1337; @@ -107,13 +107,13 @@ unsafe extern "C" fn current_elx_synchronous(e: &mut ExceptionContext) { } #[no_mangle] -unsafe extern "C" fn current_elx_irq(_e: &mut ExceptionContext) { - let token = &exception::asynchronous::IRQContext::new(); +extern "C" fn current_elx_irq(_e: &mut ExceptionContext) { + let token = unsafe { &exception::asynchronous::IRQContext::new() }; exception::asynchronous::irq_manager().handle_pending_irqs(token); } #[no_mangle] -unsafe extern "C" fn current_elx_serror(e: &mut ExceptionContext) { +extern "C" fn current_elx_serror(e: &mut ExceptionContext) { default_exception_handler(e); } @@ -122,17 +122,17 @@ unsafe extern "C" fn current_elx_serror(e: &mut ExceptionContext) { //------------------------------------------------------------------------------ #[no_mangle] -unsafe extern "C" fn lower_aarch64_synchronous(e: &mut ExceptionContext) { +extern "C" fn lower_aarch64_synchronous(e: &mut ExceptionContext) { default_exception_handler(e); } #[no_mangle] -unsafe extern "C" fn lower_aarch64_irq(e: &mut ExceptionContext) { +extern "C" fn lower_aarch64_irq(e: &mut ExceptionContext) { default_exception_handler(e); } #[no_mangle] -unsafe extern "C" fn lower_aarch64_serror(e: &mut ExceptionContext) { +extern "C" fn lower_aarch64_serror(e: &mut ExceptionContext) { default_exception_handler(e); } @@ -141,17 +141,17 @@ unsafe extern "C" fn lower_aarch64_serror(e: &mut ExceptionContext) { //------------------------------------------------------------------------------ #[no_mangle] -unsafe extern "C" fn lower_aarch32_synchronous(e: &mut ExceptionContext) { +extern "C" fn lower_aarch32_synchronous(e: &mut ExceptionContext) { default_exception_handler(e); } #[no_mangle] -unsafe extern "C" fn lower_aarch32_irq(e: &mut ExceptionContext) { +extern "C" fn lower_aarch32_irq(e: &mut ExceptionContext) { default_exception_handler(e); } #[no_mangle] -unsafe extern "C" fn lower_aarch32_serror(e: &mut ExceptionContext) { +extern "C" fn lower_aarch32_serror(e: &mut ExceptionContext) { default_exception_handler(e); } diff --git a/19_kernel_heap/kernel/src/_arch/aarch64/exception.rs b/19_kernel_heap/kernel/src/_arch/aarch64/exception.rs index 17ec3009..e03e382f 100644 --- a/19_kernel_heap/kernel/src/_arch/aarch64/exception.rs +++ b/19_kernel_heap/kernel/src/_arch/aarch64/exception.rs @@ -72,17 +72,17 @@ fn default_exception_handler(exc: &ExceptionContext) { //------------------------------------------------------------------------------ #[no_mangle] -unsafe extern "C" fn current_el0_synchronous(_e: &mut ExceptionContext) { +extern "C" fn current_el0_synchronous(_e: &mut ExceptionContext) { panic!("Should not be here. Use of SP_EL0 in EL1 is not supported.") } #[no_mangle] -unsafe extern "C" fn current_el0_irq(_e: &mut ExceptionContext) { +extern "C" fn current_el0_irq(_e: &mut ExceptionContext) { panic!("Should not be here. Use of SP_EL0 in EL1 is not supported.") } #[no_mangle] -unsafe extern "C" fn current_el0_serror(_e: &mut ExceptionContext) { +extern "C" fn current_el0_serror(_e: &mut ExceptionContext) { panic!("Should not be here. Use of SP_EL0 in EL1 is not supported.") } @@ -91,7 +91,7 @@ unsafe extern "C" fn current_el0_serror(_e: &mut ExceptionContext) { //------------------------------------------------------------------------------ #[no_mangle] -unsafe extern "C" fn current_elx_synchronous(e: &mut ExceptionContext) { +extern "C" fn current_elx_synchronous(e: &mut ExceptionContext) { #[cfg(feature = "test_build")] { const TEST_SVC_ID: u64 = 0x1337; @@ -107,13 +107,13 @@ unsafe extern "C" fn current_elx_synchronous(e: &mut ExceptionContext) { } #[no_mangle] -unsafe extern "C" fn current_elx_irq(_e: &mut ExceptionContext) { - let token = &exception::asynchronous::IRQContext::new(); +extern "C" fn current_elx_irq(_e: &mut ExceptionContext) { + let token = unsafe { &exception::asynchronous::IRQContext::new() }; exception::asynchronous::irq_manager().handle_pending_irqs(token); } #[no_mangle] -unsafe extern "C" fn current_elx_serror(e: &mut ExceptionContext) { +extern "C" fn current_elx_serror(e: &mut ExceptionContext) { default_exception_handler(e); } @@ -122,17 +122,17 @@ unsafe extern "C" fn current_elx_serror(e: &mut ExceptionContext) { //------------------------------------------------------------------------------ #[no_mangle] -unsafe extern "C" fn lower_aarch64_synchronous(e: &mut ExceptionContext) { +extern "C" fn lower_aarch64_synchronous(e: &mut ExceptionContext) { default_exception_handler(e); } #[no_mangle] -unsafe extern "C" fn lower_aarch64_irq(e: &mut ExceptionContext) { +extern "C" fn lower_aarch64_irq(e: &mut ExceptionContext) { default_exception_handler(e); } #[no_mangle] -unsafe extern "C" fn lower_aarch64_serror(e: &mut ExceptionContext) { +extern "C" fn lower_aarch64_serror(e: &mut ExceptionContext) { default_exception_handler(e); } @@ -141,17 +141,17 @@ unsafe extern "C" fn lower_aarch64_serror(e: &mut ExceptionContext) { //------------------------------------------------------------------------------ #[no_mangle] -unsafe extern "C" fn lower_aarch32_synchronous(e: &mut ExceptionContext) { +extern "C" fn lower_aarch32_synchronous(e: &mut ExceptionContext) { default_exception_handler(e); } #[no_mangle] -unsafe extern "C" fn lower_aarch32_irq(e: &mut ExceptionContext) { +extern "C" fn lower_aarch32_irq(e: &mut ExceptionContext) { default_exception_handler(e); } #[no_mangle] -unsafe extern "C" fn lower_aarch32_serror(e: &mut ExceptionContext) { +extern "C" fn lower_aarch32_serror(e: &mut ExceptionContext) { default_exception_handler(e); } From e6c3790cacc4edb7a0784cd9f7f615db0eb59b4a Mon Sep 17 00:00:00 2001 From: Andre Richter Date: Mon, 23 May 2022 22:33:32 +0200 Subject: [PATCH 41/75] Remove .got section again It seems that whatever bug or config mistake gave us .got entries back then has since been resolved. Also add a sanity check to recognize should this happen again. --- 02_runtime_init/Makefile | 1 - 02_runtime_init/README.md | 14 ++++++++++---- 02_runtime_init/src/bsp/raspberrypi/kernel.ld | 9 ++++++++- 03_hacky_hello_world/Makefile | 1 - 03_hacky_hello_world/README.md | 2 +- .../src/bsp/raspberrypi/kernel.ld | 9 ++++++++- 04_safe_globals/Makefile | 1 - 04_safe_globals/src/bsp/raspberrypi/kernel.ld | 9 ++++++++- 05_drivers_gpio_uart/Makefile | 1 - .../src/bsp/raspberrypi/kernel.ld | 9 ++++++++- 06_uart_chainloader/Makefile | 1 - 06_uart_chainloader/README.md | 4 ++-- .../src/bsp/raspberrypi/kernel.ld | 9 ++++++++- 07_timestamps/Makefile | 1 - 07_timestamps/README.md | 4 ++-- 07_timestamps/src/bsp/raspberrypi/kernel.ld | 9 ++++++++- 08_hw_debug_JTAG/Makefile | 1 - 08_hw_debug_JTAG/README.md | 2 +- 08_hw_debug_JTAG/src/bsp/raspberrypi/kernel.ld | 9 ++++++++- 09_privilege_level/Makefile | 1 - 09_privilege_level/src/bsp/raspberrypi/kernel.ld | 9 ++++++++- 10_virtual_mem_part1_identity_mapping/Makefile | 1 - 10_virtual_mem_part1_identity_mapping/README.md | 4 ++-- .../src/bsp/raspberrypi/kernel.ld | 9 ++++++++- 11_exceptions_part1_groundwork/Makefile | 1 - .../src/bsp/raspberrypi/kernel.ld | 9 ++++++++- 12_integrated_testing/Makefile | 1 - .../kernel/src/bsp/raspberrypi/kernel.ld | 9 ++++++++- 13_exceptions_part2_peripheral_IRQs/Makefile | 1 - .../kernel/src/bsp/raspberrypi/kernel.ld | 9 ++++++++- 14_virtual_mem_part2_mmio_remap/Makefile | 1 - 14_virtual_mem_part2_mmio_remap/README.md | 12 +++++++----- .../kernel/src/bsp/raspberrypi/kernel.ld | 9 ++++++++- 15_virtual_mem_part3_precomputed_tables/Makefile | 1 - .../README.md | 11 ++++++++++- .../kernel/src/bsp/raspberrypi/kernel.ld | 11 +++++++++-- 16_virtual_mem_part4_higher_half_kernel/Makefile | 1 - .../README.md | 16 +++++++++------- .../kernel/src/bsp/raspberrypi/kernel.ld | 9 ++++++++- 17_kernel_symbols/Makefile | 1 - 17_kernel_symbols/README.md | 6 ++---- .../kernel/src/bsp/raspberrypi/kernel.ld | 9 ++++++++- 18_backtrace/Makefile | 1 - 18_backtrace/README.md | 2 +- .../kernel/src/bsp/raspberrypi/kernel.ld | 9 ++++++++- 19_kernel_heap/Makefile | 1 - 19_kernel_heap/README.md | 2 +- .../kernel/src/bsp/raspberrypi/kernel.ld | 9 ++++++++- X1_JTAG_boot/Makefile | 1 - X1_JTAG_boot/src/bsp/raspberrypi/kernel.ld | 9 ++++++++- 50 files changed, 201 insertions(+), 70 deletions(-) diff --git a/02_runtime_init/Makefile b/02_runtime_init/Makefile index 49ca7b63..af9bbc27 100644 --- a/02_runtime_init/Makefile +++ b/02_runtime_init/Makefile @@ -181,7 +181,6 @@ objdump: $(KERNEL_ELF) @$(DOCKER_TOOLS) $(OBJDUMP_BINARY) --disassemble --demangle \ --section .text \ --section .rodata \ - --section .got \ $(KERNEL_ELF) | rustfilt ##------------------------------------------------------------------------------ diff --git a/02_runtime_init/README.md b/02_runtime_init/README.md index 7e4f5c0a..f9d59b30 100644 --- a/02_runtime_init/README.md +++ b/02_runtime_init/README.md @@ -52,12 +52,11 @@ diff -uNr 01_wait_forever/Cargo.toml 02_runtime_init/Cargo.toml diff -uNr 01_wait_forever/Makefile 02_runtime_init/Makefile --- 01_wait_forever/Makefile +++ 02_runtime_init/Makefile -@@ -180,6 +180,8 @@ +@@ -180,6 +180,7 @@ $(call color_header, "Launching objdump") @$(DOCKER_TOOLS) $(OBJDUMP_BINARY) --disassemble --demangle \ --section .text \ + --section .rodata \ -+ --section .got \ $(KERNEL_ELF) | rustfilt ##------------------------------------------------------------------------------ @@ -211,7 +210,7 @@ diff -uNr 01_wait_forever/src/bsp/raspberrypi/kernel.ld 02_runtime_init/src/bsp/ /* The physical address at which the the kernel binary will be loaded by the Raspberry's firmware */ __rpi_phys_binary_load_addr = 0x80000; -@@ -13,21 +15,58 @@ +@@ -13,21 +15,65 @@ * 4 == R * 5 == RX * 6 == RW @@ -257,7 +256,6 @@ diff -uNr 01_wait_forever/src/bsp/raspberrypi/kernel.ld 02_runtime_init/src/bsp/ } :segment_code + + .rodata : ALIGN(8) { *(.rodata*) } :segment_code -+ .got : ALIGN(8) { *(.got) } :segment_code + + /*********************************************************************************************** + * Data + BSS @@ -272,6 +270,14 @@ diff -uNr 01_wait_forever/src/bsp/raspberrypi/kernel.ld 02_runtime_init/src/bsp/ + . = ALIGN(16); + __bss_end_exclusive = .; + } :segment_data ++ ++ /*********************************************************************************************** ++ * Misc ++ ***********************************************************************************************/ ++ .got : { *(.got*) } ++ ASSERT(SIZEOF(.got) == 0, "Relocation support not expected") ++ ++ /DISCARD/ : { *(.comment*) } } diff -uNr 01_wait_forever/src/bsp/raspberrypi.rs 02_runtime_init/src/bsp/raspberrypi.rs diff --git a/02_runtime_init/src/bsp/raspberrypi/kernel.ld b/02_runtime_init/src/bsp/raspberrypi/kernel.ld index 007afd4a..f6c18843 100644 --- a/02_runtime_init/src/bsp/raspberrypi/kernel.ld +++ b/02_runtime_init/src/bsp/raspberrypi/kernel.ld @@ -54,7 +54,6 @@ SECTIONS } :segment_code .rodata : ALIGN(8) { *(.rodata*) } :segment_code - .got : ALIGN(8) { *(.got) } :segment_code /*********************************************************************************************** * Data + BSS @@ -69,4 +68,12 @@ SECTIONS . = ALIGN(16); __bss_end_exclusive = .; } :segment_data + + /*********************************************************************************************** + * Misc + ***********************************************************************************************/ + .got : { *(.got*) } + ASSERT(SIZEOF(.got) == 0, "Relocation support not expected") + + /DISCARD/ : { *(.comment*) } } diff --git a/03_hacky_hello_world/Makefile b/03_hacky_hello_world/Makefile index 6e5cf32d..8ddaf9e7 100644 --- a/03_hacky_hello_world/Makefile +++ b/03_hacky_hello_world/Makefile @@ -184,7 +184,6 @@ objdump: $(KERNEL_ELF) @$(DOCKER_TOOLS) $(OBJDUMP_BINARY) --disassemble --demangle \ --section .text \ --section .rodata \ - --section .got \ $(KERNEL_ELF) | rustfilt ##------------------------------------------------------------------------------ diff --git a/03_hacky_hello_world/README.md b/03_hacky_hello_world/README.md index 348e626a..416cab02 100644 --- a/03_hacky_hello_world/README.md +++ b/03_hacky_hello_world/README.md @@ -95,7 +95,7 @@ diff -uNr 02_runtime_init/Makefile 03_hacky_hello_world/Makefile -@@ -191,3 +194,27 @@ +@@ -190,3 +193,27 @@ $(call color_header, "Launching nm") @$(DOCKER_TOOLS) $(NM_BINARY) --demangle --print-size $(KERNEL_ELF) | sort | rustfilt diff --git a/03_hacky_hello_world/src/bsp/raspberrypi/kernel.ld b/03_hacky_hello_world/src/bsp/raspberrypi/kernel.ld index 007afd4a..f6c18843 100644 --- a/03_hacky_hello_world/src/bsp/raspberrypi/kernel.ld +++ b/03_hacky_hello_world/src/bsp/raspberrypi/kernel.ld @@ -54,7 +54,6 @@ SECTIONS } :segment_code .rodata : ALIGN(8) { *(.rodata*) } :segment_code - .got : ALIGN(8) { *(.got) } :segment_code /*********************************************************************************************** * Data + BSS @@ -69,4 +68,12 @@ SECTIONS . = ALIGN(16); __bss_end_exclusive = .; } :segment_data + + /*********************************************************************************************** + * Misc + ***********************************************************************************************/ + .got : { *(.got*) } + ASSERT(SIZEOF(.got) == 0, "Relocation support not expected") + + /DISCARD/ : { *(.comment*) } } diff --git a/04_safe_globals/Makefile b/04_safe_globals/Makefile index 6e5cf32d..8ddaf9e7 100644 --- a/04_safe_globals/Makefile +++ b/04_safe_globals/Makefile @@ -184,7 +184,6 @@ objdump: $(KERNEL_ELF) @$(DOCKER_TOOLS) $(OBJDUMP_BINARY) --disassemble --demangle \ --section .text \ --section .rodata \ - --section .got \ $(KERNEL_ELF) | rustfilt ##------------------------------------------------------------------------------ diff --git a/04_safe_globals/src/bsp/raspberrypi/kernel.ld b/04_safe_globals/src/bsp/raspberrypi/kernel.ld index 007afd4a..f6c18843 100644 --- a/04_safe_globals/src/bsp/raspberrypi/kernel.ld +++ b/04_safe_globals/src/bsp/raspberrypi/kernel.ld @@ -54,7 +54,6 @@ SECTIONS } :segment_code .rodata : ALIGN(8) { *(.rodata*) } :segment_code - .got : ALIGN(8) { *(.got) } :segment_code /*********************************************************************************************** * Data + BSS @@ -69,4 +68,12 @@ SECTIONS . = ALIGN(16); __bss_end_exclusive = .; } :segment_data + + /*********************************************************************************************** + * Misc + ***********************************************************************************************/ + .got : { *(.got*) } + ASSERT(SIZEOF(.got) == 0, "Relocation support not expected") + + /DISCARD/ : { *(.comment*) } } diff --git a/05_drivers_gpio_uart/Makefile b/05_drivers_gpio_uart/Makefile index cd8097c8..183d7864 100644 --- a/05_drivers_gpio_uart/Makefile +++ b/05_drivers_gpio_uart/Makefile @@ -203,7 +203,6 @@ objdump: $(KERNEL_ELF) @$(DOCKER_TOOLS) $(OBJDUMP_BINARY) --disassemble --demangle \ --section .text \ --section .rodata \ - --section .got \ $(KERNEL_ELF) | rustfilt ##------------------------------------------------------------------------------ diff --git a/05_drivers_gpio_uart/src/bsp/raspberrypi/kernel.ld b/05_drivers_gpio_uart/src/bsp/raspberrypi/kernel.ld index 007afd4a..f6c18843 100644 --- a/05_drivers_gpio_uart/src/bsp/raspberrypi/kernel.ld +++ b/05_drivers_gpio_uart/src/bsp/raspberrypi/kernel.ld @@ -54,7 +54,6 @@ SECTIONS } :segment_code .rodata : ALIGN(8) { *(.rodata*) } :segment_code - .got : ALIGN(8) { *(.got) } :segment_code /*********************************************************************************************** * Data + BSS @@ -69,4 +68,12 @@ SECTIONS . = ALIGN(16); __bss_end_exclusive = .; } :segment_data + + /*********************************************************************************************** + * Misc + ***********************************************************************************************/ + .got : { *(.got*) } + ASSERT(SIZEOF(.got) == 0, "Relocation support not expected") + + /DISCARD/ : { *(.comment*) } } diff --git a/06_uart_chainloader/Makefile b/06_uart_chainloader/Makefile index 6c60e8ed..91245573 100644 --- a/06_uart_chainloader/Makefile +++ b/06_uart_chainloader/Makefile @@ -209,7 +209,6 @@ objdump: $(KERNEL_ELF) @$(DOCKER_TOOLS) $(OBJDUMP_BINARY) --disassemble --demangle \ --section .text \ --section .rodata \ - --section .got \ $(KERNEL_ELF) | rustfilt ##------------------------------------------------------------------------------ diff --git a/06_uart_chainloader/README.md b/06_uart_chainloader/README.md index 38f9cc05..6e4e4530 100644 --- a/06_uart_chainloader/README.md +++ b/06_uart_chainloader/README.md @@ -249,7 +249,7 @@ diff -uNr 05_drivers_gpio_uart/Makefile 06_uart_chainloader/Makefile ##------------------------------------------------------------------------------ ## Run clippy -@@ -232,7 +238,8 @@ +@@ -231,7 +237,8 @@ ##------------------------------------------------------------------------------ test_boot: $(KERNEL_BIN) $(call color_header, "Boot test - $(BSP)") @@ -399,7 +399,7 @@ diff -uNr 05_drivers_gpio_uart/src/bsp/raspberrypi/kernel.ld 06_uart_chainloader .text : { KEEP(*(.text._start)) -@@ -61,6 +61,10 @@ +@@ -60,6 +60,10 @@ ***********************************************************************************************/ .data : { *(.data*) } :segment_data diff --git a/06_uart_chainloader/src/bsp/raspberrypi/kernel.ld b/06_uart_chainloader/src/bsp/raspberrypi/kernel.ld index 4fd5bf6a..c84b6238 100644 --- a/06_uart_chainloader/src/bsp/raspberrypi/kernel.ld +++ b/06_uart_chainloader/src/bsp/raspberrypi/kernel.ld @@ -54,7 +54,6 @@ SECTIONS } :segment_code .rodata : ALIGN(8) { *(.rodata*) } :segment_code - .got : ALIGN(8) { *(.got) } :segment_code /*********************************************************************************************** * Data + BSS @@ -73,4 +72,12 @@ SECTIONS . = ALIGN(16); __bss_end_exclusive = .; } :segment_data + + /*********************************************************************************************** + * Misc + ***********************************************************************************************/ + .got : { *(.got*) } + ASSERT(SIZEOF(.got) == 0, "Relocation support not expected") + + /DISCARD/ : { *(.comment*) } } diff --git a/07_timestamps/Makefile b/07_timestamps/Makefile index b89cee8c..c183c606 100644 --- a/07_timestamps/Makefile +++ b/07_timestamps/Makefile @@ -203,7 +203,6 @@ objdump: $(KERNEL_ELF) @$(DOCKER_TOOLS) $(OBJDUMP_BINARY) --disassemble --demangle \ --section .text \ --section .rodata \ - --section .got \ $(KERNEL_ELF) | rustfilt ##------------------------------------------------------------------------------ diff --git a/07_timestamps/README.md b/07_timestamps/README.md index 2f4ab323..1126d9b7 100644 --- a/07_timestamps/README.md +++ b/07_timestamps/README.md @@ -150,7 +150,7 @@ diff -uNr 06_uart_chainloader/Makefile 07_timestamps/Makefile ##------------------------------------------------------------------------------ ## Run clippy -@@ -238,8 +232,7 @@ +@@ -237,8 +231,7 @@ ##------------------------------------------------------------------------------ test_boot: $(KERNEL_BIN) $(call color_header, "Boot test - $(BSP)") @@ -482,7 +482,7 @@ diff -uNr 06_uart_chainloader/src/bsp/raspberrypi/kernel.ld 07_timestamps/src/bs .text : { KEEP(*(.text._start)) -@@ -61,10 +61,6 @@ +@@ -60,10 +60,6 @@ ***********************************************************************************************/ .data : { *(.data*) } :segment_data diff --git a/07_timestamps/src/bsp/raspberrypi/kernel.ld b/07_timestamps/src/bsp/raspberrypi/kernel.ld index 007afd4a..f6c18843 100644 --- a/07_timestamps/src/bsp/raspberrypi/kernel.ld +++ b/07_timestamps/src/bsp/raspberrypi/kernel.ld @@ -54,7 +54,6 @@ SECTIONS } :segment_code .rodata : ALIGN(8) { *(.rodata*) } :segment_code - .got : ALIGN(8) { *(.got) } :segment_code /*********************************************************************************************** * Data + BSS @@ -69,4 +68,12 @@ SECTIONS . = ALIGN(16); __bss_end_exclusive = .; } :segment_data + + /*********************************************************************************************** + * Misc + ***********************************************************************************************/ + .got : { *(.got*) } + ASSERT(SIZEOF(.got) == 0, "Relocation support not expected") + + /DISCARD/ : { *(.comment*) } } diff --git a/08_hw_debug_JTAG/Makefile b/08_hw_debug_JTAG/Makefile index 138c5554..3202f53a 100644 --- a/08_hw_debug_JTAG/Makefile +++ b/08_hw_debug_JTAG/Makefile @@ -214,7 +214,6 @@ objdump: $(KERNEL_ELF) @$(DOCKER_TOOLS) $(OBJDUMP_BINARY) --disassemble --demangle \ --section .text \ --section .rodata \ - --section .got \ $(KERNEL_ELF) | rustfilt ##------------------------------------------------------------------------------ diff --git a/08_hw_debug_JTAG/README.md b/08_hw_debug_JTAG/README.md index 7f8a1846..53f86807 100644 --- a/08_hw_debug_JTAG/README.md +++ b/08_hw_debug_JTAG/README.md @@ -364,7 +364,7 @@ diff -uNr 07_timestamps/Makefile 08_hw_debug_JTAG/Makefile endif -@@ -215,6 +226,35 @@ +@@ -214,6 +225,35 @@ diff --git a/08_hw_debug_JTAG/src/bsp/raspberrypi/kernel.ld b/08_hw_debug_JTAG/src/bsp/raspberrypi/kernel.ld index 007afd4a..f6c18843 100644 --- a/08_hw_debug_JTAG/src/bsp/raspberrypi/kernel.ld +++ b/08_hw_debug_JTAG/src/bsp/raspberrypi/kernel.ld @@ -54,7 +54,6 @@ SECTIONS } :segment_code .rodata : ALIGN(8) { *(.rodata*) } :segment_code - .got : ALIGN(8) { *(.got) } :segment_code /*********************************************************************************************** * Data + BSS @@ -69,4 +68,12 @@ SECTIONS . = ALIGN(16); __bss_end_exclusive = .; } :segment_data + + /*********************************************************************************************** + * Misc + ***********************************************************************************************/ + .got : { *(.got*) } + ASSERT(SIZEOF(.got) == 0, "Relocation support not expected") + + /DISCARD/ : { *(.comment*) } } diff --git a/09_privilege_level/Makefile b/09_privilege_level/Makefile index 138c5554..3202f53a 100644 --- a/09_privilege_level/Makefile +++ b/09_privilege_level/Makefile @@ -214,7 +214,6 @@ objdump: $(KERNEL_ELF) @$(DOCKER_TOOLS) $(OBJDUMP_BINARY) --disassemble --demangle \ --section .text \ --section .rodata \ - --section .got \ $(KERNEL_ELF) | rustfilt ##------------------------------------------------------------------------------ diff --git a/09_privilege_level/src/bsp/raspberrypi/kernel.ld b/09_privilege_level/src/bsp/raspberrypi/kernel.ld index 007afd4a..f6c18843 100644 --- a/09_privilege_level/src/bsp/raspberrypi/kernel.ld +++ b/09_privilege_level/src/bsp/raspberrypi/kernel.ld @@ -54,7 +54,6 @@ SECTIONS } :segment_code .rodata : ALIGN(8) { *(.rodata*) } :segment_code - .got : ALIGN(8) { *(.got) } :segment_code /*********************************************************************************************** * Data + BSS @@ -69,4 +68,12 @@ SECTIONS . = ALIGN(16); __bss_end_exclusive = .; } :segment_data + + /*********************************************************************************************** + * Misc + ***********************************************************************************************/ + .got : { *(.got*) } + ASSERT(SIZEOF(.got) == 0, "Relocation support not expected") + + /DISCARD/ : { *(.comment*) } } diff --git a/10_virtual_mem_part1_identity_mapping/Makefile b/10_virtual_mem_part1_identity_mapping/Makefile index 138c5554..3202f53a 100644 --- a/10_virtual_mem_part1_identity_mapping/Makefile +++ b/10_virtual_mem_part1_identity_mapping/Makefile @@ -214,7 +214,6 @@ objdump: $(KERNEL_ELF) @$(DOCKER_TOOLS) $(OBJDUMP_BINARY) --disassemble --demangle \ --section .text \ --section .rodata \ - --section .got \ $(KERNEL_ELF) | rustfilt ##------------------------------------------------------------------------------ diff --git a/10_virtual_mem_part1_identity_mapping/README.md b/10_virtual_mem_part1_identity_mapping/README.md index 8bfd54fa..8345aef0 100644 --- a/10_virtual_mem_part1_identity_mapping/README.md +++ b/10_virtual_mem_part1_identity_mapping/README.md @@ -855,9 +855,9 @@ diff -uNr 09_privilege_level/src/bsp/raspberrypi/kernel.ld 10_virtual_mem_part1_ .text : { KEEP(*(.text._start)) -@@ -56,6 +62,9 @@ +@@ -55,6 +61,9 @@ + .rodata : ALIGN(8) { *(.rodata*) } :segment_code - .got : ALIGN(8) { *(.got) } :segment_code + . = ALIGN(PAGE_SIZE); + __code_end_exclusive = .; diff --git a/10_virtual_mem_part1_identity_mapping/src/bsp/raspberrypi/kernel.ld b/10_virtual_mem_part1_identity_mapping/src/bsp/raspberrypi/kernel.ld index 2ce4b44b..6d939889 100644 --- a/10_virtual_mem_part1_identity_mapping/src/bsp/raspberrypi/kernel.ld +++ b/10_virtual_mem_part1_identity_mapping/src/bsp/raspberrypi/kernel.ld @@ -60,7 +60,6 @@ SECTIONS } :segment_code .rodata : ALIGN(8) { *(.rodata*) } :segment_code - .got : ALIGN(8) { *(.got) } :segment_code . = ALIGN(PAGE_SIZE); __code_end_exclusive = .; @@ -78,4 +77,12 @@ SECTIONS . = ALIGN(16); __bss_end_exclusive = .; } :segment_data + + /*********************************************************************************************** + * Misc + ***********************************************************************************************/ + .got : { *(.got*) } + ASSERT(SIZEOF(.got) == 0, "Relocation support not expected") + + /DISCARD/ : { *(.comment*) } } diff --git a/11_exceptions_part1_groundwork/Makefile b/11_exceptions_part1_groundwork/Makefile index 138c5554..3202f53a 100644 --- a/11_exceptions_part1_groundwork/Makefile +++ b/11_exceptions_part1_groundwork/Makefile @@ -214,7 +214,6 @@ objdump: $(KERNEL_ELF) @$(DOCKER_TOOLS) $(OBJDUMP_BINARY) --disassemble --demangle \ --section .text \ --section .rodata \ - --section .got \ $(KERNEL_ELF) | rustfilt ##------------------------------------------------------------------------------ diff --git a/11_exceptions_part1_groundwork/src/bsp/raspberrypi/kernel.ld b/11_exceptions_part1_groundwork/src/bsp/raspberrypi/kernel.ld index 2ce4b44b..6d939889 100644 --- a/11_exceptions_part1_groundwork/src/bsp/raspberrypi/kernel.ld +++ b/11_exceptions_part1_groundwork/src/bsp/raspberrypi/kernel.ld @@ -60,7 +60,6 @@ SECTIONS } :segment_code .rodata : ALIGN(8) { *(.rodata*) } :segment_code - .got : ALIGN(8) { *(.got) } :segment_code . = ALIGN(PAGE_SIZE); __code_end_exclusive = .; @@ -78,4 +77,12 @@ SECTIONS . = ALIGN(16); __bss_end_exclusive = .; } :segment_data + + /*********************************************************************************************** + * Misc + ***********************************************************************************************/ + .got : { *(.got*) } + ASSERT(SIZEOF(.got) == 0, "Relocation support not expected") + + /DISCARD/ : { *(.comment*) } } diff --git a/12_integrated_testing/Makefile b/12_integrated_testing/Makefile index 20007cec..c7552461 100644 --- a/12_integrated_testing/Makefile +++ b/12_integrated_testing/Makefile @@ -226,7 +226,6 @@ objdump: $(KERNEL_ELF) @$(DOCKER_TOOLS) $(OBJDUMP_BINARY) --disassemble --demangle \ --section .text \ --section .rodata \ - --section .got \ $(KERNEL_ELF) | rustfilt ##------------------------------------------------------------------------------ diff --git a/12_integrated_testing/kernel/src/bsp/raspberrypi/kernel.ld b/12_integrated_testing/kernel/src/bsp/raspberrypi/kernel.ld index 2ce4b44b..6d939889 100644 --- a/12_integrated_testing/kernel/src/bsp/raspberrypi/kernel.ld +++ b/12_integrated_testing/kernel/src/bsp/raspberrypi/kernel.ld @@ -60,7 +60,6 @@ SECTIONS } :segment_code .rodata : ALIGN(8) { *(.rodata*) } :segment_code - .got : ALIGN(8) { *(.got) } :segment_code . = ALIGN(PAGE_SIZE); __code_end_exclusive = .; @@ -78,4 +77,12 @@ SECTIONS . = ALIGN(16); __bss_end_exclusive = .; } :segment_data + + /*********************************************************************************************** + * Misc + ***********************************************************************************************/ + .got : { *(.got*) } + ASSERT(SIZEOF(.got) == 0, "Relocation support not expected") + + /DISCARD/ : { *(.comment*) } } diff --git a/13_exceptions_part2_peripheral_IRQs/Makefile b/13_exceptions_part2_peripheral_IRQs/Makefile index 20007cec..c7552461 100644 --- a/13_exceptions_part2_peripheral_IRQs/Makefile +++ b/13_exceptions_part2_peripheral_IRQs/Makefile @@ -226,7 +226,6 @@ objdump: $(KERNEL_ELF) @$(DOCKER_TOOLS) $(OBJDUMP_BINARY) --disassemble --demangle \ --section .text \ --section .rodata \ - --section .got \ $(KERNEL_ELF) | rustfilt ##------------------------------------------------------------------------------ diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/kernel.ld b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/kernel.ld index 2ce4b44b..6d939889 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/kernel.ld +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/kernel.ld @@ -60,7 +60,6 @@ SECTIONS } :segment_code .rodata : ALIGN(8) { *(.rodata*) } :segment_code - .got : ALIGN(8) { *(.got) } :segment_code . = ALIGN(PAGE_SIZE); __code_end_exclusive = .; @@ -78,4 +77,12 @@ SECTIONS . = ALIGN(16); __bss_end_exclusive = .; } :segment_data + + /*********************************************************************************************** + * Misc + ***********************************************************************************************/ + .got : { *(.got*) } + ASSERT(SIZEOF(.got) == 0, "Relocation support not expected") + + /DISCARD/ : { *(.comment*) } } diff --git a/14_virtual_mem_part2_mmio_remap/Makefile b/14_virtual_mem_part2_mmio_remap/Makefile index 20007cec..c7552461 100644 --- a/14_virtual_mem_part2_mmio_remap/Makefile +++ b/14_virtual_mem_part2_mmio_remap/Makefile @@ -226,7 +226,6 @@ objdump: $(KERNEL_ELF) @$(DOCKER_TOOLS) $(OBJDUMP_BINARY) --disassemble --demangle \ --section .text \ --section .rodata \ - --section .got \ $(KERNEL_ELF) | rustfilt ##------------------------------------------------------------------------------ diff --git a/14_virtual_mem_part2_mmio_remap/README.md b/14_virtual_mem_part2_mmio_remap/README.md index 30aa848b..ff6e2416 100644 --- a/14_virtual_mem_part2_mmio_remap/README.md +++ b/14_virtual_mem_part2_mmio_remap/README.md @@ -1480,7 +1480,7 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/kernel. /* | stack */ . += __rpi_phys_binary_load_addr; /* | growth */ /* | direction */ -@@ -68,6 +68,7 @@ +@@ -67,6 +67,7 @@ /*********************************************************************************************** * Data + BSS ***********************************************************************************************/ @@ -1488,11 +1488,10 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/kernel. .data : { *(.data*) } :segment_data /* Section is zeroed in pairs of u64. Align start and end to 16 bytes */ -@@ -78,4 +79,16 @@ - . = ALIGN(16); +@@ -78,6 +79,18 @@ __bss_end_exclusive = .; } :segment_data -+ + + . = ALIGN(PAGE_SIZE); + __data_end_exclusive = .; + @@ -1504,7 +1503,10 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/kernel. + __mmio_remap_end_exclusive = .; + + ASSERT((. & PAGE_MASK) == 0, "MMIO remap reservation is not page aligned") - } ++ + /*********************************************************************************************** + * Misc + ***********************************************************************************************/ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/memory/mmu.rs 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/memory/mmu.rs --- 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/memory/mmu.rs diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/kernel.ld b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/kernel.ld index c4a0b6a4..3f5f7043 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/kernel.ld +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/kernel.ld @@ -60,7 +60,6 @@ SECTIONS } :segment_code .rodata : ALIGN(8) { *(.rodata*) } :segment_code - .got : ALIGN(8) { *(.got) } :segment_code . = ALIGN(PAGE_SIZE); __code_end_exclusive = .; @@ -91,4 +90,12 @@ SECTIONS __mmio_remap_end_exclusive = .; ASSERT((. & PAGE_MASK) == 0, "MMIO remap reservation is not page aligned") + + /*********************************************************************************************** + * Misc + ***********************************************************************************************/ + .got : { *(.got*) } + ASSERT(SIZEOF(.got) == 0, "Relocation support not expected") + + /DISCARD/ : { *(.comment*) } } diff --git a/15_virtual_mem_part3_precomputed_tables/Makefile b/15_virtual_mem_part3_precomputed_tables/Makefile index 0d34c181..6edf29a4 100644 --- a/15_virtual_mem_part3_precomputed_tables/Makefile +++ b/15_virtual_mem_part3_precomputed_tables/Makefile @@ -245,7 +245,6 @@ objdump: $(KERNEL_ELF) @$(DOCKER_TOOLS) $(OBJDUMP_BINARY) --disassemble --demangle \ --section .text \ --section .rodata \ - --section .got \ $(KERNEL_ELF) | rustfilt ##------------------------------------------------------------------------------ diff --git a/15_virtual_mem_part3_precomputed_tables/README.md b/15_virtual_mem_part3_precomputed_tables/README.md index 186acc2a..be59abb1 100644 --- a/15_virtual_mem_part3_precomputed_tables/README.md +++ b/15_virtual_mem_part3_precomputed_tables/README.md @@ -1077,6 +1077,15 @@ diff -uNr 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/kernel.ld 1 PAGE_SIZE = 64K; PAGE_MASK = PAGE_SIZE - 1; +@@ -89,7 +91,7 @@ + . += 8 * 1024 * 1024; + __mmio_remap_end_exclusive = .; + +- ASSERT((. & PAGE_MASK) == 0, "MMIO remap reservation is not page aligned") ++ ASSERT((. & PAGE_MASK) == 0, "End of boot core stack is not page aligned") + + /*********************************************************************************************** + * Misc diff -uNr 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/kernel_virt_addr_space_size.ld 15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/kernel_virt_addr_space_size.ld --- 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/kernel_virt_addr_space_size.ld @@ -1888,7 +1897,7 @@ diff -uNr 14_virtual_mem_part2_mmio_remap/Makefile 15_virtual_mem_part3_precompu $(call color_progress_prefix, "Name") @echo $(KERNEL_BIN) $(call color_progress_prefix, "Size") -@@ -301,6 +320,7 @@ +@@ -300,6 +319,7 @@ TEST_ELF=$$(echo $$1 | sed -e 's/.*target/target/g') TEST_BINARY=$$(echo $$1.img | sed -e 's/.*target/target/g') diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/kernel.ld b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/kernel.ld index 717d817e..63393bae 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/kernel.ld +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/kernel.ld @@ -62,7 +62,6 @@ SECTIONS } :segment_code .rodata : ALIGN(8) { *(.rodata*) } :segment_code - .got : ALIGN(8) { *(.got) } :segment_code . = ALIGN(PAGE_SIZE); __code_end_exclusive = .; @@ -92,5 +91,13 @@ SECTIONS . += 8 * 1024 * 1024; __mmio_remap_end_exclusive = .; - ASSERT((. & PAGE_MASK) == 0, "MMIO remap reservation is not page aligned") + ASSERT((. & PAGE_MASK) == 0, "End of boot core stack is not page aligned") + + /*********************************************************************************************** + * Misc + ***********************************************************************************************/ + .got : { *(.got*) } + ASSERT(SIZEOF(.got) == 0, "Relocation support not expected") + + /DISCARD/ : { *(.comment*) } } diff --git a/16_virtual_mem_part4_higher_half_kernel/Makefile b/16_virtual_mem_part4_higher_half_kernel/Makefile index 0d34c181..6edf29a4 100644 --- a/16_virtual_mem_part4_higher_half_kernel/Makefile +++ b/16_virtual_mem_part4_higher_half_kernel/Makefile @@ -245,7 +245,6 @@ objdump: $(KERNEL_ELF) @$(DOCKER_TOOLS) $(OBJDUMP_BINARY) --disassemble --demangle \ --section .text \ --section .rodata \ - --section .got \ $(KERNEL_ELF) | rustfilt ##------------------------------------------------------------------------------ diff --git a/16_virtual_mem_part4_higher_half_kernel/README.md b/16_virtual_mem_part4_higher_half_kernel/README.md index 0a30a2aa..cb50cab0 100644 --- a/16_virtual_mem_part4_higher_half_kernel/README.md +++ b/16_virtual_mem_part4_higher_half_kernel/README.md @@ -598,8 +598,7 @@ diff -uNr 15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/ker SECTIONS { - . = __rpi_phys_dram_start_addr; -+ . = __kernel_virt_start_addr; - +- - /*********************************************************************************************** - * Boot Core Stack - ***********************************************************************************************/ @@ -611,7 +610,8 @@ diff -uNr 15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/ker - /* | direction */ - __boot_core_stack_end_exclusive = .; /* | */ - } :segment_boot_core_stack -- ++ . = __kernel_virt_start_addr; + - ASSERT((. & PAGE_MASK) == 0, "End of boot core stack is not page aligned") + ASSERT((. & PAGE_MASK) == 0, "Start of address space is not page aligned") @@ -624,10 +624,11 @@ diff -uNr 15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/ker { KEEP(*(.text._start)) *(.text._start_arguments) /* Constants (or statics in Rust speak) read by _start(). */ -@@ -93,4 +88,23 @@ +@@ -91,6 +86,25 @@ + . += 8 * 1024 * 1024; __mmio_remap_end_exclusive = .; - ASSERT((. & PAGE_MASK) == 0, "MMIO remap reservation is not page aligned") ++ ASSERT((. & PAGE_MASK) == 0, "MMIO remap reservation is not page aligned") + + /*********************************************************************************************** + * Guard Page @@ -646,8 +647,9 @@ diff -uNr 15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/ker + __boot_core_stack_end_exclusive = .; /* | */ + } :segment_boot_core_stack + -+ ASSERT((. & PAGE_MASK) == 0, "End of boot core stack is not page aligned") - } + ASSERT((. & PAGE_MASK) == 0, "End of boot core stack is not page aligned") + + /*********************************************************************************************** diff -uNr 15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/memory/mmu.rs 16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi/memory/mmu.rs --- 15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/memory/mmu.rs diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi/kernel.ld b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi/kernel.ld index 14619829..c17b61f9 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi/kernel.ld +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi/kernel.ld @@ -57,7 +57,6 @@ SECTIONS } :segment_code .rodata : ALIGN(8) { *(.rodata*) } :segment_code - .got : ALIGN(8) { *(.got) } :segment_code . = ALIGN(PAGE_SIZE); __code_end_exclusive = .; @@ -107,4 +106,12 @@ SECTIONS } :segment_boot_core_stack ASSERT((. & PAGE_MASK) == 0, "End of boot core stack is not page aligned") + + /*********************************************************************************************** + * Misc + ***********************************************************************************************/ + .got : { *(.got*) } + ASSERT(SIZEOF(.got) == 0, "Relocation support not expected") + + /DISCARD/ : { *(.comment*) } } diff --git a/17_kernel_symbols/Makefile b/17_kernel_symbols/Makefile index ec71b493..3a7465a3 100644 --- a/17_kernel_symbols/Makefile +++ b/17_kernel_symbols/Makefile @@ -270,7 +270,6 @@ objdump: $(KERNEL_ELF) @$(DOCKER_TOOLS) $(OBJDUMP_BINARY) --disassemble --demangle \ --section .text \ --section .rodata \ - --section .got \ $(KERNEL_ELF) | rustfilt ##------------------------------------------------------------------------------ diff --git a/17_kernel_symbols/README.md b/17_kernel_symbols/README.md index d3b42b65..b9d21aec 100644 --- a/17_kernel_symbols/README.md +++ b/17_kernel_symbols/README.md @@ -293,14 +293,12 @@ diff -uNr 16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/excep diff -uNr 16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi/kernel.ld 17_kernel_symbols/kernel/src/bsp/raspberrypi/kernel.ld --- 16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi/kernel.ld +++ 17_kernel_symbols/kernel/src/bsp/raspberrypi/kernel.ld -@@ -56,8 +56,12 @@ +@@ -56,7 +56,11 @@ *(.text*) /* Everything else */ } :segment_code - .rodata : ALIGN(8) { *(.rodata*) } :segment_code -- .got : ALIGN(8) { *(.got) } :segment_code + .rodata : ALIGN(8) { *(.rodata*) } :segment_code -+ .got : ALIGN(8) { *(.got) } :segment_code + .kernel_symbols : ALIGN(8) { + __kernel_symbols_start = .; + . += 32 * 1024; @@ -740,7 +738,7 @@ diff -uNr 16_virtual_mem_part4_higher_half_kernel/Makefile 17_kernel_symbols/Mak $(call color_header, "Generating docs") @$(DOC_CMD) --document-private-items --open -@@ -318,10 +343,19 @@ +@@ -317,10 +342,19 @@ cd $(shell pwd) TEST_ELF=$$(echo $$1 | sed -e 's/.*target/target/g') diff --git a/17_kernel_symbols/kernel/src/bsp/raspberrypi/kernel.ld b/17_kernel_symbols/kernel/src/bsp/raspberrypi/kernel.ld index 6fcbf31c..193a5200 100644 --- a/17_kernel_symbols/kernel/src/bsp/raspberrypi/kernel.ld +++ b/17_kernel_symbols/kernel/src/bsp/raspberrypi/kernel.ld @@ -57,7 +57,6 @@ SECTIONS } :segment_code .rodata : ALIGN(8) { *(.rodata*) } :segment_code - .got : ALIGN(8) { *(.got) } :segment_code .kernel_symbols : ALIGN(8) { __kernel_symbols_start = .; . += 32 * 1024; @@ -111,4 +110,12 @@ SECTIONS } :segment_boot_core_stack ASSERT((. & PAGE_MASK) == 0, "End of boot core stack is not page aligned") + + /*********************************************************************************************** + * Misc + ***********************************************************************************************/ + .got : { *(.got*) } + ASSERT(SIZEOF(.got) == 0, "Relocation support not expected") + + /DISCARD/ : { *(.comment*) } } diff --git a/18_backtrace/Makefile b/18_backtrace/Makefile index 5d660332..eba659f0 100644 --- a/18_backtrace/Makefile +++ b/18_backtrace/Makefile @@ -272,7 +272,6 @@ objdump: $(KERNEL_ELF) @$(DOCKER_TOOLS) $(OBJDUMP_BINARY) --disassemble --demangle \ --section .text \ --section .rodata \ - --section .got \ $(KERNEL_ELF) | rustfilt ##------------------------------------------------------------------------------ diff --git a/18_backtrace/README.md b/18_backtrace/README.md index f98eafc7..c6417bdd 100644 --- a/18_backtrace/README.md +++ b/18_backtrace/README.md @@ -1253,7 +1253,7 @@ diff -uNr 17_kernel_symbols/Makefile 18_backtrace/Makefile OBJCOPY_CMD = rust-objcopy \ --strip-all \ -O binary -@@ -303,8 +305,7 @@ +@@ -302,8 +304,7 @@ ##------------------------------------------------------------------------------ ## Start GDB session ##------------------------------------------------------------------------------ diff --git a/18_backtrace/kernel/src/bsp/raspberrypi/kernel.ld b/18_backtrace/kernel/src/bsp/raspberrypi/kernel.ld index 6fcbf31c..193a5200 100644 --- a/18_backtrace/kernel/src/bsp/raspberrypi/kernel.ld +++ b/18_backtrace/kernel/src/bsp/raspberrypi/kernel.ld @@ -57,7 +57,6 @@ SECTIONS } :segment_code .rodata : ALIGN(8) { *(.rodata*) } :segment_code - .got : ALIGN(8) { *(.got) } :segment_code .kernel_symbols : ALIGN(8) { __kernel_symbols_start = .; . += 32 * 1024; @@ -111,4 +110,12 @@ SECTIONS } :segment_boot_core_stack ASSERT((. & PAGE_MASK) == 0, "End of boot core stack is not page aligned") + + /*********************************************************************************************** + * Misc + ***********************************************************************************************/ + .got : { *(.got*) } + ASSERT(SIZEOF(.got) == 0, "Relocation support not expected") + + /DISCARD/ : { *(.comment*) } } diff --git a/19_kernel_heap/Makefile b/19_kernel_heap/Makefile index bd1bc803..c9a7d593 100644 --- a/19_kernel_heap/Makefile +++ b/19_kernel_heap/Makefile @@ -277,7 +277,6 @@ objdump: $(KERNEL_ELF) @$(DOCKER_TOOLS) $(OBJDUMP_BINARY) --disassemble --demangle \ --section .text \ --section .rodata \ - --section .got \ $(KERNEL_ELF) | rustfilt ##------------------------------------------------------------------------------ diff --git a/19_kernel_heap/README.md b/19_kernel_heap/README.md index 0b4e2348..8a39a231 100644 --- a/19_kernel_heap/README.md +++ b/19_kernel_heap/README.md @@ -512,7 +512,7 @@ diff -uNr 18_backtrace/kernel/src/bsp/raspberrypi/kernel.ld 19_kernel_heap/kerne segment_boot_core_stack PT_LOAD FLAGS(6); } -@@ -85,6 +86,18 @@ +@@ -84,6 +85,18 @@ __data_end_exclusive = .; /*********************************************************************************************** diff --git a/19_kernel_heap/kernel/src/bsp/raspberrypi/kernel.ld b/19_kernel_heap/kernel/src/bsp/raspberrypi/kernel.ld index cbfbb5b5..2408b63c 100644 --- a/19_kernel_heap/kernel/src/bsp/raspberrypi/kernel.ld +++ b/19_kernel_heap/kernel/src/bsp/raspberrypi/kernel.ld @@ -58,7 +58,6 @@ SECTIONS } :segment_code .rodata : ALIGN(8) { *(.rodata*) } :segment_code - .got : ALIGN(8) { *(.got) } :segment_code .kernel_symbols : ALIGN(8) { __kernel_symbols_start = .; . += 32 * 1024; @@ -124,4 +123,12 @@ SECTIONS } :segment_boot_core_stack ASSERT((. & PAGE_MASK) == 0, "End of boot core stack is not page aligned") + + /*********************************************************************************************** + * Misc + ***********************************************************************************************/ + .got : { *(.got*) } + ASSERT(SIZEOF(.got) == 0, "Relocation support not expected") + + /DISCARD/ : { *(.comment*) } } diff --git a/X1_JTAG_boot/Makefile b/X1_JTAG_boot/Makefile index b89cee8c..c183c606 100644 --- a/X1_JTAG_boot/Makefile +++ b/X1_JTAG_boot/Makefile @@ -203,7 +203,6 @@ objdump: $(KERNEL_ELF) @$(DOCKER_TOOLS) $(OBJDUMP_BINARY) --disassemble --demangle \ --section .text \ --section .rodata \ - --section .got \ $(KERNEL_ELF) | rustfilt ##------------------------------------------------------------------------------ diff --git a/X1_JTAG_boot/src/bsp/raspberrypi/kernel.ld b/X1_JTAG_boot/src/bsp/raspberrypi/kernel.ld index 007afd4a..f6c18843 100644 --- a/X1_JTAG_boot/src/bsp/raspberrypi/kernel.ld +++ b/X1_JTAG_boot/src/bsp/raspberrypi/kernel.ld @@ -54,7 +54,6 @@ SECTIONS } :segment_code .rodata : ALIGN(8) { *(.rodata*) } :segment_code - .got : ALIGN(8) { *(.got) } :segment_code /*********************************************************************************************** * Data + BSS @@ -69,4 +68,12 @@ SECTIONS . = ALIGN(16); __bss_end_exclusive = .; } :segment_data + + /*********************************************************************************************** + * Misc + ***********************************************************************************************/ + .got : { *(.got*) } + ASSERT(SIZEOF(.got) == 0, "Relocation support not expected") + + /DISCARD/ : { *(.comment*) } } From 728ca1b6addc29f0320b5e927a0f9737d62086a6 Mon Sep 17 00:00:00 2001 From: Andre Richter Date: Mon, 23 May 2022 23:25:00 +0200 Subject: [PATCH 42/75] Bump dependencies --- 02_runtime_init/Cargo.lock | 4 ++-- 03_hacky_hello_world/Cargo.lock | 4 ++-- 04_safe_globals/Cargo.lock | 4 ++-- 05_drivers_gpio_uart/Cargo.lock | 4 ++-- 06_uart_chainloader/Cargo.lock | 4 ++-- 06_uart_chainloader/demo_payload_rpi3.img | Bin 7960 -> 7728 bytes 06_uart_chainloader/demo_payload_rpi4.img | Bin 7872 -> 7664 bytes 07_timestamps/Cargo.lock | 4 ++-- 08_hw_debug_JTAG/Cargo.lock | 4 ++-- 09_privilege_level/Cargo.lock | 4 ++-- .../Cargo.lock | 4 ++-- 11_exceptions_part1_groundwork/Cargo.lock | 4 ++-- 12_integrated_testing/Cargo.lock | 22 +++++++++--------- .../Cargo.lock | 22 +++++++++--------- 14_virtual_mem_part2_mmio_remap/Cargo.lock | 22 +++++++++--------- .../Cargo.lock | 22 +++++++++--------- .../Cargo.lock | 22 +++++++++--------- 17_kernel_symbols/Cargo.lock | 22 +++++++++--------- 18_backtrace/Cargo.lock | 22 +++++++++--------- 19_kernel_heap/Cargo.lock | 22 +++++++++--------- X1_JTAG_boot/Cargo.lock | 4 ++-- X1_JTAG_boot/jtag_boot_rpi3.img | Bin 9000 -> 8792 bytes X1_JTAG_boot/jtag_boot_rpi4.img | Bin 7888 -> 7704 bytes 23 files changed, 110 insertions(+), 110 deletions(-) diff --git a/02_runtime_init/Cargo.lock b/02_runtime_init/Cargo.lock index 6e58e97a..648c82ba 100644 --- a/02_runtime_init/Cargo.lock +++ b/02_runtime_init/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "cortex-a" -version = "7.2.0" +version = "7.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27bd91f65ccd348bb2d043d98c5b34af141ecef7f102147f59bf5898f6e734ad" +checksum = "342880ec3cd4f86ab0b7c42c7f51b0ff104de4311a53e01b97388971bb5b42a2" dependencies = [ "tock-registers", ] diff --git a/03_hacky_hello_world/Cargo.lock b/03_hacky_hello_world/Cargo.lock index 9b44f7de..dfb1e441 100644 --- a/03_hacky_hello_world/Cargo.lock +++ b/03_hacky_hello_world/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "cortex-a" -version = "7.2.0" +version = "7.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27bd91f65ccd348bb2d043d98c5b34af141ecef7f102147f59bf5898f6e734ad" +checksum = "342880ec3cd4f86ab0b7c42c7f51b0ff104de4311a53e01b97388971bb5b42a2" dependencies = [ "tock-registers", ] diff --git a/04_safe_globals/Cargo.lock b/04_safe_globals/Cargo.lock index c8a669d9..a8102471 100644 --- a/04_safe_globals/Cargo.lock +++ b/04_safe_globals/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "cortex-a" -version = "7.2.0" +version = "7.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27bd91f65ccd348bb2d043d98c5b34af141ecef7f102147f59bf5898f6e734ad" +checksum = "342880ec3cd4f86ab0b7c42c7f51b0ff104de4311a53e01b97388971bb5b42a2" dependencies = [ "tock-registers", ] diff --git a/05_drivers_gpio_uart/Cargo.lock b/05_drivers_gpio_uart/Cargo.lock index caf94f7c..d8521864 100644 --- a/05_drivers_gpio_uart/Cargo.lock +++ b/05_drivers_gpio_uart/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "cortex-a" -version = "7.2.0" +version = "7.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27bd91f65ccd348bb2d043d98c5b34af141ecef7f102147f59bf5898f6e734ad" +checksum = "342880ec3cd4f86ab0b7c42c7f51b0ff104de4311a53e01b97388971bb5b42a2" dependencies = [ "tock-registers", ] diff --git a/06_uart_chainloader/Cargo.lock b/06_uart_chainloader/Cargo.lock index a92a3ab5..0c2a9aca 100644 --- a/06_uart_chainloader/Cargo.lock +++ b/06_uart_chainloader/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "cortex-a" -version = "7.2.0" +version = "7.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27bd91f65ccd348bb2d043d98c5b34af141ecef7f102147f59bf5898f6e734ad" +checksum = "342880ec3cd4f86ab0b7c42c7f51b0ff104de4311a53e01b97388971bb5b42a2" dependencies = [ "tock-registers", ] diff --git a/06_uart_chainloader/demo_payload_rpi3.img b/06_uart_chainloader/demo_payload_rpi3.img index 1da3bec56b3f76bf826e7d2f7f8c513059965b8c..75bf414ecc24836e41b9a216a9670b10068fce17 100755 GIT binary patch delta 2167 zcmZuxTTB#J82-=BUS=1?m5b=Y!mQh}EFvOuwZ<;cs>K?WHZjo}Kw?}3!AoswO&uE3 zsKEzLhX!kUvGt*zwTZUGv?Q&8_+;!uO%xxRrbB(1rKXXvAOphmKeMx`wmr%2od5ov z@Bh!au<`nazU7|b$KWlHg!^QIuG~nz`LgR` z$8G1X4f>Xr6Q#o8&#Nn^;gLeBo*_&P0@c0-Rs=mw+GVKSsT^`_vDK9ie($&~l2d~p zqz~9^w>M#I6WQ+u=!-gfn!>GBl-EAE8@%!05Q`heV@&`WURq1lRfLTMj?I!0R0k3_qgrs zPVfovIj-jgNMXSGQCS+yxF`s=RG`9N+(|iJ(Y_OK>~A~!Cb>$sN{aj@W%miTlmX0 zG99fi=fg$$rUIh1*#1nQ<`Cwm8zTuO&Z9;gbLF)au5D|5zx50gbvw_7Nq zPjGNlmteM8zYO%rM@#4o9&Xk;m|4dHum28g=7CID3h^8w-HSzf(xCd&`sBp*ZvyWg zvtU+i4h#N(Jx>)lyAo(S+7bx#zljN(!a^FdF&nb8FJxeeZYO({=NF+m>Wt`|4I<-T zIIxyBVj?pMqBZ-2f&8RXh?2J`zRJ!_HV|Y5CTVd(wV5DACHa3Ac?@SSgfYW*sBHH{ z^r$VO7dyb5898l5Wath^)deInRGjV78_~dZy+)|25&Qn9AjVuc*>WWu*-CnSX#|Ek z$|LMN`gJ-%??m78M5^w<_>%0+dWRn}xUB?pEkfJt3u~(Q4dMHrjWyMO8Ags7vk>BX z`TjgARP6BtA~dI7u-~0;1AU=+F;06rPWuvb+TA1X*0uvwG-EOYW5USJqyRDZNKLJZ zu?gJ2kKZZ$szO$5S|G7gC_fRPn9C<{uQuDle0HYx0K1E_2r~3}kU|lkutvO~X}B){ znCO@gX#6zx52-6BJr^}uWc)>nH&`!`7jHpOpxRZ!v^P+H4XM#!^w$@<&131Nal6cU~v^JpUaIb~Z*pKtrV}Q!kX;nlU?C`$*M~|M6cC<_Dl$*IeeAnQPFX@cWg}Kmq zJU5?+iaRePm*pmnW^OcBSTbG+bB$V+@SQQ&q4ur=-MBk!`8h0oS!rcy8Sc;iOTTCB zUa7vj`)v%9y1Uj(mn^$C87IJKp7LE@;rd@JeU_C^GFPcIW9glie!-G$mW<&U{=$qh z3nsqX=0bI&zi@HXQkzFt=KZD7`i5=N<{htX50yxr?Opq&5~;1b^Z21I$>Z@riq=(D zmRnYMitIa4{`1SMygl9EPNvicfvZmM3=+>$^NZDHr*ZU#}(a@Qcbx Z|2FbSIg*=`ty$JZ7CKI0kusGZ{2N}is`LN= delta 2361 zcmZuyZERCj7=G`)Yj@iY=ssYdT`!a{%AkB~Z5>;nj347e0v6-c1-H2nsDl+Zh!`Qa zb%`?ZqsKcl^cS+2aT5D~1Itpx&5WK#Or)BnZPEa#d)(l@y$)=Zv#6Q_}=~bhaK;7G2u` zuuo}P?Er9a1$i-m29o!eHjo6k@(c(4%K`c&kZv+zu?6e`K#_=Y;>Yz$bK$D|5gW-M z3dvlvo^5-h@@`?V900o}V~#G4rUjO#K%3DhGo%T^=xjKbP9GBKRI7zfHe2b$UK?db zm+FQ$k}KD2#DeES{M;iO2ty^+47!IijbQKL8^|Pj#rl%uAP_`{q?$Q;7?FEW45~bV zL`^nf0699~lL-8KvzS!@c$uT?2#*-`5SG=pwP0t>!i-G*!eik;*I@x@H%!zW-9%Da zj@}&)hOn@HP*0()h#kC4W*L4gK-N9(_8M}F_sQAFFhXYZfdDEC)K;L=2ub>eK(#+idenOv0#@+1pm0(sj6X(4(Z@(b2h6YzAIeW)p!3G& zZ9PQeh>q%%qjVx{ru8fV5&VbE0lk^}>cP(J?2_lA!3g!*AZ)9V_7H<&^~oTd3|a=| z8Z;6xgP%e94~!$;|3#3Y$B=WN&iR~dDJ{_^m6dc&X&{jS$-k8gBxGw}le)_U#M+mu zGR8|N>MkI(;TPmN6bcj^UWZ0DPpeZ5`>5JoqYbWE`Vr6QIvv zZ_en>l*7NB3_ox$V;xG&<{m+s}rCNA<3%ZT35 z?Cc3kA+$D>Ny#E*Ph01&INVez(Trcem%%!MawH>w_^6yCP-}kAe$vNrJlVFv)6eaE~Ja6 zn^Y&0MLK)0m6IhC%CXY6f`|j{|7+bWSH?^4R3POTEaV^%`ns)*If{KJ%d^}(gIa+5 zI{bp|J;z==*xmiAv@aypG;ZG`HSOEEw`#3)B-C|KQob)MEBMM##RpDb=yJNOlABUW z%d2FmB5OCtV6HUoh_b$Xm0A8=G)F^Shr-BdGvrK$+y;-=vjNX1|3h!tctC0lhmWJ0 z6zFzPqelq0qjXT=|$~zUF=hjLc z;Ug!Gc1c#N6~F+c+7SD~Ksak0pxWTifmmzY=YyUHRXI{xVUr58gbjtF;&QBWOc@Gi Qj2)a={v~!-7FD|b1_x>H3jhEB diff --git a/06_uart_chainloader/demo_payload_rpi4.img b/06_uart_chainloader/demo_payload_rpi4.img index f76cbd1fa891b177444764c8d47c4fd43c13526d..0d66373c74c01beda4fb6de40142a3d3d7adbbe5 100755 GIT binary patch delta 1952 zcmZ8hZEO=|9RJ^4yR{wQv5j@C>w2STw{C0$>FO9rvnmX9Vipt=T(+?gS{WTMl*E|b zh>4;=vg1h57?U9%8~XgXk16ZWlqWoYE0eZs*V967e^ zEYCZi#o%^suM=P>W*=;?ZVM_DBiI6B)}JC-!?>RjK&f8dq-Zr9xf2D`eh%&0+lUab z6YAf3(=Z8Fhe0%Cf!y)ukyb>``gxL#a!S^3BOj~Z6uRZM1;Z^#ErdhFPtc1VWwX~zp73IN3p40PODukKp$gg9@AnShPZN@;vjJ+;CoS8l`_ zvEElPGmWN9jHqCu&i6UUgMCgi+vy@Ry9&tEjwNOvj&HICm!8Fp*TB?WKwahf#%QIQuJ* z2Ux@d>;eTyJ!KJ%A)t<%L93^g&oQFsd`MJgOkYBf!2$?>)Pkcxr+EaTNp?ojNhnUf zLI;gtCI|u?UxjOlUC1SuWgt_Oc)wN1csYpEm^;^rO*Fp)!m+%FK8-|k<7u1-fw&z3 zX|imM#j*Iaa*J}#09PUq>{QBQRzj6mad9PC}(^L$)WIRuBE<4%+naFE)+E<#SCUvD1h zz36+AlfwHke!mwAYp1v9)K-hRHZDQq^NaP3v`_T^k4Am?9zGf~Xfa^w7f{xaU=|6o z$B`bc2T{FLTrNAaTaYQTu?@Drwxak+WSw%L&I!qO=O2(76FMKhRzt8|S?B?Mv2!V| z;xc>-j}iK~oa0BE;sEPAk%WO@lL92^iaE!_P2VHv6w2LrPvbp}$^5VHa(+4CI9M6H)QF`<52RMJ6yp%0pl&2Cb0 zbcdD9KDOz#AQC#(fD;$bMKV30yl2V<=5lgQIy^zS9p#nb1sp3tC|81px>M?C>70#z z4Ad`Hb``dIvDQaUg-2agc0+CTG@tgAuKBCbvi2YDsXur)o;Xr>xSu*}WtM&kixly$ zQg4=f3LPHHQo<~l&*iP)BOW#A^{+-{j5(MTQ0`?iE|qx()I(nPwhK&aXWE9kP+bH5 zAN!wv_u3ArrLXTuJh4yeOKgy?Gdm?j&wzTx8)$NrTcnCDB}nF}lNy*lkLeqk%rkjF zU0V@Y9%EYk0Gek&jaLMuVW!O$+7fM(w!XM+N1#^fjVJa>>Idaj*x}MOmrE>gjosH- z$FH*lmva-Kx0?3Uy<98x^!2`eAR)P2F31h2hM`|(VOCOreiokV-&;(6SOb$e^}~w5 Ezf90!dH?_b delta 2262 zcmZuyYitx%6h1Sv+wN{3Ods^U?3Di4me$hHE^FHW3zf7~8ej=&48f%o(k_oJE-FTT zOlzYQF|p$iOZ-LX54f9{hz-K}LrXA9jX!JCy5qLNmSU#Wpy&QP!28`g_5+5Z~()X(V|?dR)nlT@*sHb0|b%}myJST z-y?yGIcx!<369twhEZq?+9sFIWRvHiRb;+XB(uA6hy&v|xigJnfQAsFFwkyBfLKx5 zJHeuFzK&L54ky>#_^n}#%nBgKy74fF2J;wP6Y^t+k$)z@I(iOK-F_fih_BLwyx0xo z&C=RI)a5i{$mv9v9mE6hR3GFN7uWxZsb4U}1hyzK$`Kt~L}kutL)5SEMBhuBj&17Z zP%aDi63Er_O_ig>b9jo)}ogBoS5DPk|Anq7^ z_2v*1ZKT2J`Htc7djyDk3L)N0%9ZPE~=Zjq=K)+q`ma*%&zp;0v+V(&Vrac2j!DZ%yRm7eSmt z+mqNW38bG=*T?8EWY#Gh*B=}gLibgzAYXRuX-zuqE2^}!Du07GHCh?K5ctXEW<-t& zrJW%Dj!A%n>u56!mztD|i^hlsaD5u(Qf+-t9ncm5fJWPD*a+5MsXn}8Q0x@iM*@j)WlX=WcS7aVng(BEm2C_IiiYW1i zldqIw>$P0)QDtQ%h!faCoEtL#GjBSyA=sHwf$YE_2?K-PwOgC*w-Vke#$p~@u^bqy zUj!d+hS|wV^sPca8oOWv0>)MtGDU?`PK8s2ATA=p=LkeYN&!7v!db`$UnQ*~&kEFl zvqU%NG`3$mYXQ5_V~7ibpe%%dBu7C>VmF4?T77Q7S<&wbgbu7uLH}tt9}1m@5~6jnlme1Sm%Y2cp`)aBJ4Ig8eBX$WdA z*}!K$N&8xpl&&id#HT^>Z^5N@9cWFq+d*+1NKaDvQNz2j9WON<$5i&gYcF%>OR90< z!?gi&4DF7kL9!a{&U2E#8vT#CAvY6ae1N)4j8TKStvi?3n=b-oelXVi={spUEqhJ* z67uvy$5&fR`zY5M*$V9Q6qXZF8;ce{au=z)i`#OwGQ_;%n=eyi#Sb}9zbYxIdys1> zPer@epNxhhuh<QCq3hl4mlFKfK(ZIjCV49 z8RL1zcepJ}{5Mh;%iQ8PeJ}9)kx}(QS*3hwjU_zEoUbzeBICD5qkU27cwg7yaHK~% z91XvDB-$i3NvUoYuw?W9NlqJiqAMI>eS{(gCWF}zA zbH17R=5#Or?&V;*#gimh?TR$qnM87zh!R40(oX<#ns@P$r6MM4a1HLVak%lpoo zh}j*w0>q6bHBMqGo;V_jJz79up?SbKgu!;Oh5{n%r=5v5VKY6PSR@SgeUsQFite@g zg~Am|lI)vgfMAoU!{`2_jPO8j9azK80T$M@`yo8oJyJo`e1VNsgKoc!cJ%|qHqWGA zwDKoS&$*@wtXe=~W6oH%5`l%CA`4dwB3#2_PqjD2_V^w zXPX(j2A1iE@Ftr&ireKzJ@kd?rt2>qs$a!F0|#;z-yA5%cbzV_seW zya@YE18LcTz0+EkM}V?=gsN#;8c$E;DR!Wb)ZwcFAg`kjPe;81WSbV<8&#QEf`ZWD zgA*m>l2m_7mFztu`0+h=Fwga{QAy~*RPlegXIJzdZVK=p6i;N`w0^m+P1kc?N1yl1pS03~=3k7zWz0#<~qY^2tYFV3(nDn;rG(+RNQD05r*TW2zk@ z(_5@;vVIPGRF}ja*4mgEN}*Totf^=QD4nSQ=dRo-SNu{b4ZGCE!!mwXEpX1_IpX_6 zf*x-hy=BWQT!_Waa9T2Rupkfd@6WJEf8wf2$vuxS+0Rk`OM*PEpP#0M$*F~|K=-l9 zO679pLwHwMaNU+(O4uGY%T3jdz&(lV1q%HmbKJoHv2-dC+;^nM}sd z#IWm}sruM*yTn4T0un?dTEN0WXQDH(??H41uDyh_b1D`yhF-Hl9kvjxV?_xp6o5#G z)500gLX9{-MTzY0lunBU|I3Rn(MjipB#|M5BUDYBE3TYPW78M^L(%Khn_iyN5c@9~ zS3E(+>L?jMPR|xj(=XDUfzeo4XF;4{#N?domY*Hg%JvxE;o%!&BAI}KhD-nqIatv|FgGVRuR`d_v#ZhUwxZgK{b(Ei< zl{t>%usZ&v|6abxFoxD=SW+A!8LyPsL4@GKZt;#ZFQM;eqzCeeiZu@7TQcU1W25+v zv|t%7O=_ho?$;Y-uz0>7^0wW1P$^i(B{7=MRi4kUPv;Y!)cTS3PmSFIqr6StgG27A znww3wa}Pp&8PAmqbam#&BsCkG`Gk~Y(XTUqXk6y^Z}%%L+Z#4Ew{B53`kQxd@-I>r zDd?G<6^%$WqDl-M=UtaJe`C?MhUV5nf19qqX4q#L_Wiix`vP>8QdW)Y3<7-Kbg5CI z=Obx#=`iAp4ZW&*jk02GP3^n_rKP!blR^ixT=Ya%MqWxZ&T6cl+^9Zj#4j{-CEHB5 z+SimQwy2%s-QjO;ecJ$h!Kg^Qai0}e7k=v%g>J~6A1F{7x3|2rtyQsDu+PuNf7>{3 zK6ggBZ{UgE4q(lR?r<=5$uRVpdS)8BQ4iYXV0192oAxS-sM_g}vZr{tQL_Ikq1UkU WRJgpM&;yR2bDtHq!$A+^9{(GPWo9Y> delta 2193 zcmah}eQZ-z6hHS}I@&U}Zr#?xTKY;MTlq9lJ_e4p8}d<5NFl+5=r$Ix3v=KQjWMLf z1t#JjyIyn(QN9w`?LrtC#1#|R!XFNe35X*SqjVFs-4GB3H*tHO*FL@y3^#f2zVmVK z`JLZ6=Y7Ahc~PU)*kL6mhfKT47&d-^v{`pzoh0QB>0l25XpQ|0%;}xVdMPkl+gnl= zA=CJ7`UW}E_CnSS!aX{>-REI$-!v9$AR^`h7C#E25W<1@VJO-`d97}-z{GE5=Y-h5N|OxocX3K0Jrp7_Dn)v!KH?ivEV5iG5N+cj6=}r`Mn`)G zE5LCX9$CXH&I-(~b=Qb+z`VmZ7)g!)_e;2H?5mTsJ6}lA1oFD>mP>32N+$|6_W`qN3arI@6_QDF} zwcgR5pp+TUIoge?9(~oMx=O+1-#(Xpjpx;Yh*eS6TTfZy@Mw`hUAzide*-4mk|FvJ zXNnhxm8Js#vr;t+DVE8oP&*8prcuI&;sYJUtkmmaRq`y>gO?Q}tD4Uvz2zPB3@euV z3jGAH=*6nVuseIGL9N~co95FEiHw7*w;0Z2;2% z1_c7A(9{avbhi4Q(i8(YwE*=_q*DcyWWWO^1f8RnTTeW^!CYXnus#YbHZmz zGv>U!YCo71oZ5tohy*2AODgu?<9+5e248xzL%zAd{W(rg>&-btxUoA&W9UL>dcInS zjYMKKNa(RjBTJaE`+mp2QYQM1>ev~$j)WXznQW=y{N9^LN6Y)|b!wm8m`RwQ z=vbklYwt~rivEq)k)9eH#+x`OhKZx{`;mg>IFvUgO9IdEt5#!frH=KNP_Y{!6yj{E zg-Uq&u+_Q=dlZK#;Yt&Iu92d*jIfnRQ^$bf!R#Mz!TU6!PmxBG(R<}v|CZlwmk?ur z6-niJUd?mj6Y?BTPMO-ak6A|eg|QXcCOfvsBWu{fOY?u=cDpSzFJ&=lJ0GwWhV-tK z@_nT5Qdc#7b7gIHRr#Bh)vr&h+oIW@(O_h0vbuZmc}ZTj zzOHtCjhsB>wN^G7k?7=FBB#RP2qf1S zXG*>gr$P%iRkMGn$@js3s>%5GORgiDjQ;|_{s(B*6ohxm$N5}GGY{IA5F0;Xw^%zI zscX`cM**^NR|9do&6*w8jCq<7`S#n!<;xmi{JkdEE_|zj*2*#u+h)0+me4Zo{0x4@ oQ6RO-T#|Rr$kVd^KNiMnc2g=QOmgzm@=xQRcFa4TpLTxs9|UWgj{pDw diff --git a/X1_JTAG_boot/jtag_boot_rpi4.img b/X1_JTAG_boot/jtag_boot_rpi4.img index b12e094ded48d939c71c87f3fb3fa66a2c309048..ea37301f05b97d1219a77b74eac3910f376f12f3 100755 GIT binary patch delta 1478 zcmah}ZD?Cn7=F(^%}lzs+&0P5d^EXjT$A);o!WJ&buPA3>Lw}?6)dbpvDT?j`b#I8 zgvn-6q1Q8MVG3J|))NqvShfDD6k!zw$Ce4o^tLM8bR87d&4!X*-}{mN@rN&*``+jM zJm-1Oy+0qCx^JSsGO-R~NTT`7y4-ZXaK!e-vx4B>Z-cYC@xo^yDu05!LP4(2y(a7? z!q6w|G(9OeKF%Gly_>L3TSFidkz<)gSvfU&usqU)yAR zOkD&yh92b($`vfROognLB3z9C*V|nj08vc|e2!&moMf1NP}4yIx$kSH1ahy@jw~{{ zF7&(uU}D6UPR91$CF^-d9|f@xp63NkTUW7eY`I%jS_xn61H=Cv`ju0-vxv>;(|=7f z&b-tHqL!k3HN1=W^O}Pjpz5uv^r57g3wji zkwo#zw&p3r6-u)9iUgj}o?X*4j~#OzrH6_ww#58973t&&x9gr38_e6$=74O{@i)vb z(7~O08ns<2y$;3g7sNw+bFh}*e!7ltJm%y^q0Fn@F9LK9;;}U>uG8tr#Jm4EO!HBt zC-1yFj-O=HA>DXn*!s#S`_nR?q*x{enw8;&09!7l&^=;g(LS5Me;(sW# z=LGb$63PU=%pXehgkt2`l%3YWHfplHNFTz+dyn*;)L zA*r3_hx$O=z(NYZ+!*RcfU|m0z4=86L<->2r)Ym5!hUf!*Iq}0B1i-hqlcV0$ZA|6 z$3Z*=QuN~%>vA1C@UkYZodWqr4&=2C^E5ZDC{Dd(EDHy+O5yU?9Y~a34VH5R3 zb&7Wf8`i4A9LSU*VGH92 zXh^wlyM^68vyk}&Xs|H;A`EG^uwdb+FZXNUIAPbk{wBk;?l)7tR=|U(gVsB+YF~iG zgB{*cC^s-&)Cd%#Al6jcgjk}x zEwL@e2d=k~CVe60f!_6{1hK49i`EC4sIgX*#54|=n%T8AG}79wh4I{-*`$3i-sJAN z=V!k2bHBSMw|~E5*poSP6I9Jl=A>J6{bTYs854VD*|pmNCxo$d0#yAspo;{kZ}KfU zOOkcYj*>(2(3#2Ic@Imh#!=$y4AP3m0M(C4Tn_*>#(|eZBxH<1U6So{G|QdA$#V|s ztaAdKtss$*v$32?curgZT8WXRdKuL*g;7ShNZZ^CY9a{S3`^Vy%Y1^pnOh+3W$)$& zrLB`wxhG|5M=HH^o*mBDws$)sAw3Y|anoEf5T~NFo+g@rE@WXvgD44!nqk6?GDix3 z_KKP6xn&EeY$?AmOz)Z_e(?Wj5GlGqAgU8Nx=5VS#ud};_dm|D*x}Qn(2g=navG8y zp#22*t%l_Ms_9Of77@pp(ZF@Y_`@{a*!ZyXg{P8=qapTQMkLhYDttt7Kum#XNVy7a zu^G~SAD~I(ORL);DW);n2I^ga6ClA9CKv|2p5Fe)9MJ)$5~ev)iat@ih@Gtkl>ii` z5;ksP=Uf}}?wG1kmchkfM96Ek>`#}bV4#j8dg3lCDr&7AFx6`~sOytJui@ZDT<=v= zy&jZ!%i9-EWzHN8Mc<$9%fj@%3-u|S%{A=9qB5z5eNnVNeAtI@V-j7w0JMMA92o_u zZATCjo8N_cy1q!W#kQ|nEJ<2HUBGW%#6Cn!dVuDj7N9>4QyKEK^wz;8WY$d{jS zanYC3I8fIEP?N^5fJkXbY1~%#>rOIPu5X)Da98BQ$A95Xde$5XdA>g1$L0&l!*wgI zmlbSL95YtIPR6{H=w(crWjj)2;%|z~IaSh;x(Iiu+6k*}Qobb@=cpc+X zYQ)Z;O*LL1)A*Ro;yOG3CZi z8V_f4vlo(zbPv5Gn_deLa}K^VeH=VnvA*z}P-ac-QH?-Mb3?3K05xgTP8sDO%3PEe zwCVB=lo(?WVkNG`#>R7a0^?JSR)cyG&xx^IZghzvAK>w07G=N8L^^a4x;RK^eC1v` z>@wY-p&`wOnXMKNjs$EzJcxY2kG``xlj8f!4^c^qgv1-siG~kUi;6Sb;9h2aPe=Z| z7in?N`eZHp!1D`R@_JoYiY-^M?S2yFI#%WLv0{&w6A=#+*RYUmUvXv0*>#p>%UVlL z+j^VO+2=lQ{;2IKN_`1{$r8SGo_X7hFC?{w@HYoH+fY)oQCP}-79zgR)T*>~{A;n6 zmmMm3=ehl0g{7@&x39pmAL#1}?(ck~r>nicv*%!S-vK-DwmpM9TNknc_a48$n(4() z_xxY}&2~LiHbAGXr_1TFb;b7g*}81&2W?$qhfDgI>eX3`FSr)|vmZu%Zr5>pyxBHL LKFTU~vn22@*De5{ From bd5ee7d9cd10d4881f69a3b356f4306c3a6087b9 Mon Sep 17 00:00:00 2001 From: Andre Richter Date: Mon, 27 Jun 2022 09:53:10 +0200 Subject: [PATCH 43/75] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 66e60d44..745dd3c5 100644 --- a/README.md +++ b/README.md @@ -61,7 +61,7 @@ The tutorials are primarily targeted at **Linux**-based distributions. Most stuf ### 🚀 The tl;dr Version -1. [Install Docker Desktop][install_docker]. +1. [Install Docker Engine][install_docker]. 1. (**Linux only**) Ensure your user account is in the [docker group]. 1. Prepare the `Rust` toolchain. Most of it will be handled on first use through the [rust-toolchain](rust-toolchain) file. What's left for us to do is: @@ -113,7 +113,7 @@ accompanying container that has all the needed tools or dependencies pre-install pulled in automagically once it is needed. If you want to know more about Docker and peek at the provided container, please refer to the repository's [docker](docker) folder. -[install_docker]: https://docs.docker.com/get-docker/ +[install_docker]: https://docs.docker.com/engine/install/#server ## 📟 USB Serial Output From b48a89faf01d8e0ec8812346d89c90981cd8f9bb Mon Sep 17 00:00:00 2001 From: Andre Richter Date: Mon, 27 Jun 2022 10:38:04 +0200 Subject: [PATCH 44/75] Bump dependencies --- 02_runtime_init/Cargo.lock | 4 +-- 03_hacky_hello_world/Cargo.lock | 4 +-- 04_safe_globals/Cargo.lock | 4 +-- 05_drivers_gpio_uart/Cargo.lock | 4 +-- 06_uart_chainloader/Cargo.lock | 4 +-- 06_uart_chainloader/demo_payload_rpi3.img | Bin 7728 -> 7736 bytes 06_uart_chainloader/demo_payload_rpi4.img | Bin 7664 -> 7672 bytes 07_timestamps/Cargo.lock | 4 +-- 08_hw_debug_JTAG/Cargo.lock | 4 +-- 09_privilege_level/Cargo.lock | 4 +-- .../Cargo.lock | 4 +-- 11_exceptions_part1_groundwork/Cargo.lock | 4 +-- 12_integrated_testing/Cargo.lock | 20 +++++++-------- .../Cargo.lock | 20 +++++++-------- 14_virtual_mem_part2_mmio_remap/Cargo.lock | 20 +++++++-------- .../Cargo.lock | 20 +++++++-------- .../Cargo.lock | 20 +++++++-------- 17_kernel_symbols/Cargo.lock | 20 +++++++-------- 18_backtrace/Cargo.lock | 20 +++++++-------- 19_kernel_heap/Cargo.lock | 24 +++++++++--------- 19_kernel_heap/README.md | 8 +++--- 19_kernel_heap/kernel/Cargo.toml | 2 +- .../kernel/src/memory/heap_alloc.rs | 6 ++--- X1_JTAG_boot/Cargo.lock | 4 +-- X1_JTAG_boot/jtag_boot_rpi3.img | Bin 8792 -> 8792 bytes X1_JTAG_boot/jtag_boot_rpi4.img | Bin 7704 -> 7712 bytes 26 files changed, 112 insertions(+), 112 deletions(-) diff --git a/02_runtime_init/Cargo.lock b/02_runtime_init/Cargo.lock index 648c82ba..d164c36b 100644 --- a/02_runtime_init/Cargo.lock +++ b/02_runtime_init/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "cortex-a" -version = "7.3.0" +version = "7.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "342880ec3cd4f86ab0b7c42c7f51b0ff104de4311a53e01b97388971bb5b42a2" +checksum = "f75db6964ed6748e88ff46f9aa209249a0aefe6b06d4b9e9ab820c867586d51a" dependencies = [ "tock-registers", ] diff --git a/03_hacky_hello_world/Cargo.lock b/03_hacky_hello_world/Cargo.lock index dfb1e441..0609efb6 100644 --- a/03_hacky_hello_world/Cargo.lock +++ b/03_hacky_hello_world/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "cortex-a" -version = "7.3.0" +version = "7.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "342880ec3cd4f86ab0b7c42c7f51b0ff104de4311a53e01b97388971bb5b42a2" +checksum = "f75db6964ed6748e88ff46f9aa209249a0aefe6b06d4b9e9ab820c867586d51a" dependencies = [ "tock-registers", ] diff --git a/04_safe_globals/Cargo.lock b/04_safe_globals/Cargo.lock index a8102471..d5be2861 100644 --- a/04_safe_globals/Cargo.lock +++ b/04_safe_globals/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "cortex-a" -version = "7.3.0" +version = "7.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "342880ec3cd4f86ab0b7c42c7f51b0ff104de4311a53e01b97388971bb5b42a2" +checksum = "f75db6964ed6748e88ff46f9aa209249a0aefe6b06d4b9e9ab820c867586d51a" dependencies = [ "tock-registers", ] diff --git a/05_drivers_gpio_uart/Cargo.lock b/05_drivers_gpio_uart/Cargo.lock index d8521864..9958f13c 100644 --- a/05_drivers_gpio_uart/Cargo.lock +++ b/05_drivers_gpio_uart/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "cortex-a" -version = "7.3.0" +version = "7.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "342880ec3cd4f86ab0b7c42c7f51b0ff104de4311a53e01b97388971bb5b42a2" +checksum = "f75db6964ed6748e88ff46f9aa209249a0aefe6b06d4b9e9ab820c867586d51a" dependencies = [ "tock-registers", ] diff --git a/06_uart_chainloader/Cargo.lock b/06_uart_chainloader/Cargo.lock index 0c2a9aca..e0cea178 100644 --- a/06_uart_chainloader/Cargo.lock +++ b/06_uart_chainloader/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "cortex-a" -version = "7.3.0" +version = "7.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "342880ec3cd4f86ab0b7c42c7f51b0ff104de4311a53e01b97388971bb5b42a2" +checksum = "f75db6964ed6748e88ff46f9aa209249a0aefe6b06d4b9e9ab820c867586d51a" dependencies = [ "tock-registers", ] diff --git a/06_uart_chainloader/demo_payload_rpi3.img b/06_uart_chainloader/demo_payload_rpi3.img index 75bf414ecc24836e41b9a216a9670b10068fce17..c0f226a7df2660c157a6e1360a4de8143631c965 100755 GIT binary patch delta 1448 zcmZ8gT}&KR6h3!`g;@$@*k9OXVYXYL!?p_*7Feud0UNLli6O>Xi2<4tp(-S+X{x5# z-TKhR)`pu~gK3Ouqluk;XfPYp>I*&+eXxmA-yGT()(5JAu8su8bBCc4PjYkbIrsd0 z-?`_`AN}U&Y>hMdC&&$o_)C_Cdj!St=EfeQhOkhoGwba715bnGfn@V zYdj{6AGZIqNdU7~N;1RF$^oO>uGCtz+LA*nPI7tt@-=dys!2&c_%Ri&_0S_ zOw6bv`gIX7k4HfJ2z6e$ z9G8UMIo?~rqJCAlrLvd&jr9kMrd((O!->~sx?EFxV|4X|L*pS*mfi3N(wS{@ZVVv4 zi%9Pm=$n{T0p({TIZH@p7=AoV7sb(KU2MQ!H01c1_rer~d)v=|!Tli9MQ?AKb3kB$ zw^|tvK_s*g5w%B~>|1yAaQJDu&{sh@GdC`^_Xx$&nO(gPR{UfK$ZuWjqD35& zu+Chb=5!-6RooEgBsj<+$eh%RHL z(8&otA=lf%d%5Nf2>C5m?u(FG7W4H~)(#l2hro5!0rXHUd)F6}F7Q_4W9QG;yi8nr z5L>=Sib3|Ew!k8xW6?!E11LY)yHdZS{~FlYYiu2Y61!4&A`LKTCyUw%-?R1I67SnO z0=MLO3kE{H)h7qOijP0oJmccn@Dvl-O4U#d|gY5JP+Fn1cjP9 z76?WT;Fn9?22BRr+RT-sU)Frn{AS z`(C!=hS>MPri5-=J+@V`B&JBA9bTojy~@^~@MhtS$u2oh`*-rLt<-nK`q4MEaZUX93@RXRcw4Hw*atJNML?`t= zGFO4XI#1(22kHw1Rt$jkdfWp5D}M0b;kL!IpvnMF1>=;!2^MmN)Bt@T12sxZbnY?P z!^T{is~c2vLDI89qGx47vq4#Z^$}ZgH8!Q2=z4#EIxs^Ot}tn$$jWl&E?Du?J)pib z)k*h}fxrg4=ZY+Rnm1SdRnX3hZjtzivKO)XO*epQ+$Z!N7T7;0>zpv2_7sv9-fX5j zy^u2(?05;AMdWUOF1fGEo8@MYGi$;f=8$G>;U@v){BJak0GCd)PIUd&38npV)yu>te(1X5}x8 z=5Ni`s*X%;zSlJa&^C^*YMQ1N#v(g1BpjQaT?YE?;`uV}d$=32GqEp|#60SM%MjuE z`*=3Sr7)*!Zxr-x)cF&Z;Zktchx-Do#u=8d=AqYac}F&*C>n^6#VB(CL6jpP4GEcd}r6HQ6%iP(2Jek5&DyA nLdWrDzj#hIM%{(TnAqL51--#n*j1sQ@hR*x-)khpNNvZzhhUAB diff --git a/06_uart_chainloader/demo_payload_rpi4.img b/06_uart_chainloader/demo_payload_rpi4.img index 0d66373c74c01beda4fb6de40142a3d3d7adbbe5..82f75d6aef373994ecde6e7c8236afcbe19e5107 100755 GIT binary patch delta 747 zcmYjOPiWI{82$ayWwcT;Ym-KkcFitpt+O4iGi{2nDw`-cN4JZ3=*lKrhg%_qDF~wz zDFZz;euCn`;judiV<`0EpM#=1h?hB!dg~5DVV4F5HEF-1-zo3C@8!LG`IBy@t0!Hf zzX=yq9J^~<1H&xMK$e}Qne8|1JGU#JFl=RU8dg31%&%#9;o0EIs=*(%o)Su4+u{sd z^U5dIuM*Bd2=64M>KsVG9q$MeNx~~{Kl3sPU%m0DQ|rX+Hd|a{kJM~$*y0*{wC1&3 zrTeOJC==7>8|NX)PcRJ?R(b9CXO(cLNjYmPEAWxeF{u$46fV*yP!Mv=l{oAO8WWB~ zukSK7VZwLGWsaMVSYiyB@Z6^{$`E|_1%-ogGs2G6ANG{9ivpjBu%zxhfMa4zqIXjT zLeAx^fL5y|9y-XT9q6J-m=Z5A&L}(I!Se{qr^uo$5T~jory$Mps<3nE!F@w0I&&HPWh2^MTYBS#?$jXDMCa(41 z+7V(G;tE!wh?lJBqV=4FEm@?K@I?;xEy$f{uIm9)4yB$U%Ok6_C#t+hz8CpVh`U8A zaKj(!Ya(m?!uC|a@Q3Iy)cr-}Cw5x!cXEFqt|A7I&QbzzrMM7A$&IhED~4e#kj`{( YdVX#fBK delta 768 zcmYjOPiWI%6#tSgBhe1CHf^-&pY&q2y0+-L+SI{Tan3_~s9t19t=m{D+X^Xc7l}Jg z^sxF4f(JKmT@Qi`g`V6Fg7YA|Z0k{P?L~x9SV4$M^NK$B`11Snc)$1MH1#{Rah}`# zMfiYhJET4YV+<9995YJ=cRn$n?OY~YHI;B0G>4ylmxi~FP5x1$D*Vx36N-E^MHw(!~^Lf-*FnBK&2tmNS(x_#))##tpdWN>lftZ_@J!S&+v#75d_mFXBVh?3`Wgc`7mn@=Z06mL{Im8;SKp|c-B9)Er8ca$ewF?iV zz;F|L%=~6)@LUQdS+A8=ut*~JDk8^_A4Gl(aeoU9+EQq^h^+DJd!<3p8=|)0uD9%K oVx}f~4*Jh*-jMO7Ci@S61-lQ>X(b}0f*t)WpCbO3Vc!@13kdL_Qvd(} diff --git a/07_timestamps/Cargo.lock b/07_timestamps/Cargo.lock index c85a8846..fcc1ddd2 100644 --- a/07_timestamps/Cargo.lock +++ b/07_timestamps/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "cortex-a" -version = "7.3.0" +version = "7.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "342880ec3cd4f86ab0b7c42c7f51b0ff104de4311a53e01b97388971bb5b42a2" +checksum = "f75db6964ed6748e88ff46f9aa209249a0aefe6b06d4b9e9ab820c867586d51a" dependencies = [ "tock-registers", ] diff --git a/08_hw_debug_JTAG/Cargo.lock b/08_hw_debug_JTAG/Cargo.lock index dfe5e8e3..7c8e75a8 100644 --- a/08_hw_debug_JTAG/Cargo.lock +++ b/08_hw_debug_JTAG/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "cortex-a" -version = "7.3.0" +version = "7.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "342880ec3cd4f86ab0b7c42c7f51b0ff104de4311a53e01b97388971bb5b42a2" +checksum = "f75db6964ed6748e88ff46f9aa209249a0aefe6b06d4b9e9ab820c867586d51a" dependencies = [ "tock-registers", ] diff --git a/09_privilege_level/Cargo.lock b/09_privilege_level/Cargo.lock index 76f33c94..0f3104f5 100644 --- a/09_privilege_level/Cargo.lock +++ b/09_privilege_level/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "cortex-a" -version = "7.3.0" +version = "7.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "342880ec3cd4f86ab0b7c42c7f51b0ff104de4311a53e01b97388971bb5b42a2" +checksum = "f75db6964ed6748e88ff46f9aa209249a0aefe6b06d4b9e9ab820c867586d51a" dependencies = [ "tock-registers", ] diff --git a/10_virtual_mem_part1_identity_mapping/Cargo.lock b/10_virtual_mem_part1_identity_mapping/Cargo.lock index c93cf0e1..544f7715 100644 --- a/10_virtual_mem_part1_identity_mapping/Cargo.lock +++ b/10_virtual_mem_part1_identity_mapping/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "cortex-a" -version = "7.3.0" +version = "7.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "342880ec3cd4f86ab0b7c42c7f51b0ff104de4311a53e01b97388971bb5b42a2" +checksum = "f75db6964ed6748e88ff46f9aa209249a0aefe6b06d4b9e9ab820c867586d51a" dependencies = [ "tock-registers", ] diff --git a/11_exceptions_part1_groundwork/Cargo.lock b/11_exceptions_part1_groundwork/Cargo.lock index 7fe1386d..285a75b0 100644 --- a/11_exceptions_part1_groundwork/Cargo.lock +++ b/11_exceptions_part1_groundwork/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "cortex-a" -version = "7.3.0" +version = "7.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "342880ec3cd4f86ab0b7c42c7f51b0ff104de4311a53e01b97388971bb5b42a2" +checksum = "f75db6964ed6748e88ff46f9aa209249a0aefe6b06d4b9e9ab820c867586d51a" dependencies = [ "tock-registers", ] diff --git a/12_integrated_testing/Cargo.lock b/12_integrated_testing/Cargo.lock index 9c675b52..ab04eab7 100644 --- a/12_integrated_testing/Cargo.lock +++ b/12_integrated_testing/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "cortex-a" -version = "7.3.0" +version = "7.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "342880ec3cd4f86ab0b7c42c7f51b0ff104de4311a53e01b97388971bb5b42a2" +checksum = "f75db6964ed6748e88ff46f9aa209249a0aefe6b06d4b9e9ab820c867586d51a" dependencies = [ "tock-registers", ] @@ -24,9 +24,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.39" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c54b25569025b7fc9651de43004ae593a75ad88543b17178aa5e1b9c4f15f56f" +checksum = "dd96a1e8ed2596c337f8eae5f24924ec83f5ad5ab21ea8e455d3566c69fbcaf7" dependencies = [ "unicode-ident", ] @@ -39,18 +39,18 @@ checksum = "9ff023245bfcc73fb890e1f8d5383825b3131cc920020a5c487d6f113dfc428a" [[package]] name = "quote" -version = "1.0.18" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1" +checksum = "3bcdf212e9776fbcb2d23ab029360416bb1706b1aea2d1a5ba002727cbcab804" dependencies = [ "proc-macro2", ] [[package]] name = "syn" -version = "1.0.95" +version = "1.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbaf6116ab8924f39d52792136fb74fd60a80194cf1b1c6ffa6453eef1c3f942" +checksum = "c50aef8a904de4c23c788f104b7dddc7d6f79c647c7c8ce4cc8f73eb0ca773dd" dependencies = [ "proc-macro2", "quote", @@ -79,6 +79,6 @@ checksum = "4ee8fba06c1f4d0b396ef61a54530bb6b28f0dc61c38bc8bc5a5a48161e6282e" [[package]] name = "unicode-ident" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d22af068fba1eb5edcb4aea19d382b2a3deb4c8f9d475c589b6ada9e0fd493ee" +checksum = "5bd2fe26506023ed7b5e1e315add59d6f584c621d037f9368fea9cfb988f368c" diff --git a/13_exceptions_part2_peripheral_IRQs/Cargo.lock b/13_exceptions_part2_peripheral_IRQs/Cargo.lock index f69ea07e..05e524aa 100644 --- a/13_exceptions_part2_peripheral_IRQs/Cargo.lock +++ b/13_exceptions_part2_peripheral_IRQs/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "cortex-a" -version = "7.3.0" +version = "7.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "342880ec3cd4f86ab0b7c42c7f51b0ff104de4311a53e01b97388971bb5b42a2" +checksum = "f75db6964ed6748e88ff46f9aa209249a0aefe6b06d4b9e9ab820c867586d51a" dependencies = [ "tock-registers", ] @@ -24,9 +24,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.39" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c54b25569025b7fc9651de43004ae593a75ad88543b17178aa5e1b9c4f15f56f" +checksum = "dd96a1e8ed2596c337f8eae5f24924ec83f5ad5ab21ea8e455d3566c69fbcaf7" dependencies = [ "unicode-ident", ] @@ -39,18 +39,18 @@ checksum = "9ff023245bfcc73fb890e1f8d5383825b3131cc920020a5c487d6f113dfc428a" [[package]] name = "quote" -version = "1.0.18" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1" +checksum = "3bcdf212e9776fbcb2d23ab029360416bb1706b1aea2d1a5ba002727cbcab804" dependencies = [ "proc-macro2", ] [[package]] name = "syn" -version = "1.0.95" +version = "1.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbaf6116ab8924f39d52792136fb74fd60a80194cf1b1c6ffa6453eef1c3f942" +checksum = "c50aef8a904de4c23c788f104b7dddc7d6f79c647c7c8ce4cc8f73eb0ca773dd" dependencies = [ "proc-macro2", "quote", @@ -79,6 +79,6 @@ checksum = "4ee8fba06c1f4d0b396ef61a54530bb6b28f0dc61c38bc8bc5a5a48161e6282e" [[package]] name = "unicode-ident" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d22af068fba1eb5edcb4aea19d382b2a3deb4c8f9d475c589b6ada9e0fd493ee" +checksum = "5bd2fe26506023ed7b5e1e315add59d6f584c621d037f9368fea9cfb988f368c" diff --git a/14_virtual_mem_part2_mmio_remap/Cargo.lock b/14_virtual_mem_part2_mmio_remap/Cargo.lock index e93b2098..c732a7ab 100644 --- a/14_virtual_mem_part2_mmio_remap/Cargo.lock +++ b/14_virtual_mem_part2_mmio_remap/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "cortex-a" -version = "7.3.0" +version = "7.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "342880ec3cd4f86ab0b7c42c7f51b0ff104de4311a53e01b97388971bb5b42a2" +checksum = "f75db6964ed6748e88ff46f9aa209249a0aefe6b06d4b9e9ab820c867586d51a" dependencies = [ "tock-registers", ] @@ -24,9 +24,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.39" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c54b25569025b7fc9651de43004ae593a75ad88543b17178aa5e1b9c4f15f56f" +checksum = "dd96a1e8ed2596c337f8eae5f24924ec83f5ad5ab21ea8e455d3566c69fbcaf7" dependencies = [ "unicode-ident", ] @@ -39,18 +39,18 @@ checksum = "9ff023245bfcc73fb890e1f8d5383825b3131cc920020a5c487d6f113dfc428a" [[package]] name = "quote" -version = "1.0.18" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1" +checksum = "3bcdf212e9776fbcb2d23ab029360416bb1706b1aea2d1a5ba002727cbcab804" dependencies = [ "proc-macro2", ] [[package]] name = "syn" -version = "1.0.95" +version = "1.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbaf6116ab8924f39d52792136fb74fd60a80194cf1b1c6ffa6453eef1c3f942" +checksum = "c50aef8a904de4c23c788f104b7dddc7d6f79c647c7c8ce4cc8f73eb0ca773dd" dependencies = [ "proc-macro2", "quote", @@ -79,6 +79,6 @@ checksum = "4ee8fba06c1f4d0b396ef61a54530bb6b28f0dc61c38bc8bc5a5a48161e6282e" [[package]] name = "unicode-ident" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d22af068fba1eb5edcb4aea19d382b2a3deb4c8f9d475c589b6ada9e0fd493ee" +checksum = "5bd2fe26506023ed7b5e1e315add59d6f584c621d037f9368fea9cfb988f368c" diff --git a/15_virtual_mem_part3_precomputed_tables/Cargo.lock b/15_virtual_mem_part3_precomputed_tables/Cargo.lock index 33d507a7..8aa6b75d 100644 --- a/15_virtual_mem_part3_precomputed_tables/Cargo.lock +++ b/15_virtual_mem_part3_precomputed_tables/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "cortex-a" -version = "7.3.0" +version = "7.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "342880ec3cd4f86ab0b7c42c7f51b0ff104de4311a53e01b97388971bb5b42a2" +checksum = "f75db6964ed6748e88ff46f9aa209249a0aefe6b06d4b9e9ab820c867586d51a" dependencies = [ "tock-registers", ] @@ -24,9 +24,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.39" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c54b25569025b7fc9651de43004ae593a75ad88543b17178aa5e1b9c4f15f56f" +checksum = "dd96a1e8ed2596c337f8eae5f24924ec83f5ad5ab21ea8e455d3566c69fbcaf7" dependencies = [ "unicode-ident", ] @@ -39,18 +39,18 @@ checksum = "9ff023245bfcc73fb890e1f8d5383825b3131cc920020a5c487d6f113dfc428a" [[package]] name = "quote" -version = "1.0.18" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1" +checksum = "3bcdf212e9776fbcb2d23ab029360416bb1706b1aea2d1a5ba002727cbcab804" dependencies = [ "proc-macro2", ] [[package]] name = "syn" -version = "1.0.95" +version = "1.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbaf6116ab8924f39d52792136fb74fd60a80194cf1b1c6ffa6453eef1c3f942" +checksum = "c50aef8a904de4c23c788f104b7dddc7d6f79c647c7c8ce4cc8f73eb0ca773dd" dependencies = [ "proc-macro2", "quote", @@ -79,6 +79,6 @@ checksum = "4ee8fba06c1f4d0b396ef61a54530bb6b28f0dc61c38bc8bc5a5a48161e6282e" [[package]] name = "unicode-ident" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d22af068fba1eb5edcb4aea19d382b2a3deb4c8f9d475c589b6ada9e0fd493ee" +checksum = "5bd2fe26506023ed7b5e1e315add59d6f584c621d037f9368fea9cfb988f368c" diff --git a/16_virtual_mem_part4_higher_half_kernel/Cargo.lock b/16_virtual_mem_part4_higher_half_kernel/Cargo.lock index c31c4665..66ac8733 100644 --- a/16_virtual_mem_part4_higher_half_kernel/Cargo.lock +++ b/16_virtual_mem_part4_higher_half_kernel/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "cortex-a" -version = "7.3.0" +version = "7.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "342880ec3cd4f86ab0b7c42c7f51b0ff104de4311a53e01b97388971bb5b42a2" +checksum = "f75db6964ed6748e88ff46f9aa209249a0aefe6b06d4b9e9ab820c867586d51a" dependencies = [ "tock-registers", ] @@ -24,9 +24,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.39" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c54b25569025b7fc9651de43004ae593a75ad88543b17178aa5e1b9c4f15f56f" +checksum = "dd96a1e8ed2596c337f8eae5f24924ec83f5ad5ab21ea8e455d3566c69fbcaf7" dependencies = [ "unicode-ident", ] @@ -39,18 +39,18 @@ checksum = "9ff023245bfcc73fb890e1f8d5383825b3131cc920020a5c487d6f113dfc428a" [[package]] name = "quote" -version = "1.0.18" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1" +checksum = "3bcdf212e9776fbcb2d23ab029360416bb1706b1aea2d1a5ba002727cbcab804" dependencies = [ "proc-macro2", ] [[package]] name = "syn" -version = "1.0.95" +version = "1.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbaf6116ab8924f39d52792136fb74fd60a80194cf1b1c6ffa6453eef1c3f942" +checksum = "c50aef8a904de4c23c788f104b7dddc7d6f79c647c7c8ce4cc8f73eb0ca773dd" dependencies = [ "proc-macro2", "quote", @@ -79,6 +79,6 @@ checksum = "4ee8fba06c1f4d0b396ef61a54530bb6b28f0dc61c38bc8bc5a5a48161e6282e" [[package]] name = "unicode-ident" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d22af068fba1eb5edcb4aea19d382b2a3deb4c8f9d475c589b6ada9e0fd493ee" +checksum = "5bd2fe26506023ed7b5e1e315add59d6f584c621d037f9368fea9cfb988f368c" diff --git a/17_kernel_symbols/Cargo.lock b/17_kernel_symbols/Cargo.lock index 098cfbb5..a0da4e21 100644 --- a/17_kernel_symbols/Cargo.lock +++ b/17_kernel_symbols/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "cortex-a" -version = "7.3.0" +version = "7.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "342880ec3cd4f86ab0b7c42c7f51b0ff104de4311a53e01b97388971bb5b42a2" +checksum = "f75db6964ed6748e88ff46f9aa209249a0aefe6b06d4b9e9ab820c867586d51a" dependencies = [ "tock-registers", ] @@ -36,9 +36,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.39" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c54b25569025b7fc9651de43004ae593a75ad88543b17178aa5e1b9c4f15f56f" +checksum = "dd96a1e8ed2596c337f8eae5f24924ec83f5ad5ab21ea8e455d3566c69fbcaf7" dependencies = [ "unicode-ident", ] @@ -51,18 +51,18 @@ checksum = "9ff023245bfcc73fb890e1f8d5383825b3131cc920020a5c487d6f113dfc428a" [[package]] name = "quote" -version = "1.0.18" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1" +checksum = "3bcdf212e9776fbcb2d23ab029360416bb1706b1aea2d1a5ba002727cbcab804" dependencies = [ "proc-macro2", ] [[package]] name = "syn" -version = "1.0.95" +version = "1.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbaf6116ab8924f39d52792136fb74fd60a80194cf1b1c6ffa6453eef1c3f942" +checksum = "c50aef8a904de4c23c788f104b7dddc7d6f79c647c7c8ce4cc8f73eb0ca773dd" dependencies = [ "proc-macro2", "quote", @@ -91,6 +91,6 @@ checksum = "4ee8fba06c1f4d0b396ef61a54530bb6b28f0dc61c38bc8bc5a5a48161e6282e" [[package]] name = "unicode-ident" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d22af068fba1eb5edcb4aea19d382b2a3deb4c8f9d475c589b6ada9e0fd493ee" +checksum = "5bd2fe26506023ed7b5e1e315add59d6f584c621d037f9368fea9cfb988f368c" diff --git a/18_backtrace/Cargo.lock b/18_backtrace/Cargo.lock index e1cf54bc..e0ab66b1 100644 --- a/18_backtrace/Cargo.lock +++ b/18_backtrace/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "cortex-a" -version = "7.3.0" +version = "7.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "342880ec3cd4f86ab0b7c42c7f51b0ff104de4311a53e01b97388971bb5b42a2" +checksum = "f75db6964ed6748e88ff46f9aa209249a0aefe6b06d4b9e9ab820c867586d51a" dependencies = [ "tock-registers", ] @@ -36,9 +36,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.39" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c54b25569025b7fc9651de43004ae593a75ad88543b17178aa5e1b9c4f15f56f" +checksum = "dd96a1e8ed2596c337f8eae5f24924ec83f5ad5ab21ea8e455d3566c69fbcaf7" dependencies = [ "unicode-ident", ] @@ -51,18 +51,18 @@ checksum = "9ff023245bfcc73fb890e1f8d5383825b3131cc920020a5c487d6f113dfc428a" [[package]] name = "quote" -version = "1.0.18" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1" +checksum = "3bcdf212e9776fbcb2d23ab029360416bb1706b1aea2d1a5ba002727cbcab804" dependencies = [ "proc-macro2", ] [[package]] name = "syn" -version = "1.0.95" +version = "1.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbaf6116ab8924f39d52792136fb74fd60a80194cf1b1c6ffa6453eef1c3f942" +checksum = "c50aef8a904de4c23c788f104b7dddc7d6f79c647c7c8ce4cc8f73eb0ca773dd" dependencies = [ "proc-macro2", "quote", @@ -91,6 +91,6 @@ checksum = "4ee8fba06c1f4d0b396ef61a54530bb6b28f0dc61c38bc8bc5a5a48161e6282e" [[package]] name = "unicode-ident" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d22af068fba1eb5edcb4aea19d382b2a3deb4c8f9d475c589b6ada9e0fd493ee" +checksum = "5bd2fe26506023ed7b5e1e315add59d6f584c621d037f9368fea9cfb988f368c" diff --git a/19_kernel_heap/Cargo.lock b/19_kernel_heap/Cargo.lock index 7fb79026..09f99f4a 100644 --- a/19_kernel_heap/Cargo.lock +++ b/19_kernel_heap/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "cortex-a" -version = "7.3.0" +version = "7.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "342880ec3cd4f86ab0b7c42c7f51b0ff104de4311a53e01b97388971bb5b42a2" +checksum = "f75db6964ed6748e88ff46f9aa209249a0aefe6b06d4b9e9ab820c867586d51a" dependencies = [ "tock-registers", ] @@ -24,9 +24,9 @@ dependencies = [ [[package]] name = "linked_list_allocator" -version = "0.9.1" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "549ce1740e46b291953c4340adcd74c59bcf4308f4cac050fd33ba91b7168f4a" +checksum = "222d00bf23b303e0c82c7a4d5f04dc90f33a58b26a3adb1a09c6fbcf56cbd2a9" [[package]] name = "mingo" @@ -43,9 +43,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.39" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c54b25569025b7fc9651de43004ae593a75ad88543b17178aa5e1b9c4f15f56f" +checksum = "dd96a1e8ed2596c337f8eae5f24924ec83f5ad5ab21ea8e455d3566c69fbcaf7" dependencies = [ "unicode-ident", ] @@ -58,18 +58,18 @@ checksum = "9ff023245bfcc73fb890e1f8d5383825b3131cc920020a5c487d6f113dfc428a" [[package]] name = "quote" -version = "1.0.18" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1" +checksum = "3bcdf212e9776fbcb2d23ab029360416bb1706b1aea2d1a5ba002727cbcab804" dependencies = [ "proc-macro2", ] [[package]] name = "syn" -version = "1.0.95" +version = "1.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbaf6116ab8924f39d52792136fb74fd60a80194cf1b1c6ffa6453eef1c3f942" +checksum = "c50aef8a904de4c23c788f104b7dddc7d6f79c647c7c8ce4cc8f73eb0ca773dd" dependencies = [ "proc-macro2", "quote", @@ -98,6 +98,6 @@ checksum = "4ee8fba06c1f4d0b396ef61a54530bb6b28f0dc61c38bc8bc5a5a48161e6282e" [[package]] name = "unicode-ident" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d22af068fba1eb5edcb4aea19d382b2a3deb4c8f9d475c589b6ada9e0fd493ee" +checksum = "5bd2fe26506023ed7b5e1e315add59d6f584c621d037f9368fea9cfb988f368c" diff --git a/19_kernel_heap/README.md b/19_kernel_heap/README.md index 8a39a231..45f5f9e3 100644 --- a/19_kernel_heap/README.md +++ b/19_kernel_heap/README.md @@ -280,7 +280,7 @@ diff -uNr 18_backtrace/kernel/Cargo.toml 19_kernel_heap/kernel/Cargo.toml [dependencies] test-types = { path = "../libraries/test-types" } debug-symbol-types = { path = "../libraries/debug-symbol-types" } -+linked_list_allocator = { version = "0.9.x", default-features = false, features = ["const_mut_refs"] } ++linked_list_allocator = { version = "0.10.x", default-features = false, features = ["const_mut_refs"] } # Optional dependencies tock-registers = { version = "0.7.x", default-features = false, features = ["register_types"], optional = true } @@ -1043,9 +1043,9 @@ diff -uNr 18_backtrace/kernel/src/memory/heap_alloc.rs 19_kernel_heap/kernel/src +pub fn kernel_init_heap_allocator() { + let region = bsp::memory::mmu::virt_heap_region(); + -+ KERNEL_HEAP_ALLOCATOR -+ .inner -+ .lock(|inner| unsafe { inner.init(region.start_addr().as_usize(), region.size()) }); ++ KERNEL_HEAP_ALLOCATOR.inner.lock(|inner| unsafe { ++ inner.init(region.start_addr().as_usize() as *mut u8, region.size()) ++ }); +} diff -uNr 18_backtrace/kernel/src/memory/mmu/mapping_record.rs 19_kernel_heap/kernel/src/memory/mmu/mapping_record.rs diff --git a/19_kernel_heap/kernel/Cargo.toml b/19_kernel_heap/kernel/Cargo.toml index 2f5d0592..61a16158 100644 --- a/19_kernel_heap/kernel/Cargo.toml +++ b/19_kernel_heap/kernel/Cargo.toml @@ -18,7 +18,7 @@ test_build = ["qemu-exit"] [dependencies] test-types = { path = "../libraries/test-types" } debug-symbol-types = { path = "../libraries/debug-symbol-types" } -linked_list_allocator = { version = "0.9.x", default-features = false, features = ["const_mut_refs"] } +linked_list_allocator = { version = "0.10.x", default-features = false, features = ["const_mut_refs"] } # Optional dependencies tock-registers = { version = "0.7.x", default-features = false, features = ["register_types"], optional = true } diff --git a/19_kernel_heap/kernel/src/memory/heap_alloc.rs b/19_kernel_heap/kernel/src/memory/heap_alloc.rs index 81a5009c..c290be4d 100644 --- a/19_kernel_heap/kernel/src/memory/heap_alloc.rs +++ b/19_kernel_heap/kernel/src/memory/heap_alloc.rs @@ -131,7 +131,7 @@ unsafe impl GlobalAlloc for HeapAllocator { pub fn kernel_init_heap_allocator() { let region = bsp::memory::mmu::virt_heap_region(); - KERNEL_HEAP_ALLOCATOR - .inner - .lock(|inner| unsafe { inner.init(region.start_addr().as_usize(), region.size()) }); + KERNEL_HEAP_ALLOCATOR.inner.lock(|inner| unsafe { + inner.init(region.start_addr().as_usize() as *mut u8, region.size()) + }); } diff --git a/X1_JTAG_boot/Cargo.lock b/X1_JTAG_boot/Cargo.lock index dfe5e8e3..7c8e75a8 100644 --- a/X1_JTAG_boot/Cargo.lock +++ b/X1_JTAG_boot/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "cortex-a" -version = "7.3.0" +version = "7.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "342880ec3cd4f86ab0b7c42c7f51b0ff104de4311a53e01b97388971bb5b42a2" +checksum = "f75db6964ed6748e88ff46f9aa209249a0aefe6b06d4b9e9ab820c867586d51a" dependencies = [ "tock-registers", ] diff --git a/X1_JTAG_boot/jtag_boot_rpi3.img b/X1_JTAG_boot/jtag_boot_rpi3.img index f6d2df49fd719b98dd9f1ed641c087f99c32e336..4f2c13b0dc1a7ab85bbd5dcc18f7810c00c8b275 100755 GIT binary patch delta 1269 zcma)4Z)jUp6hHUfbtb8n*yi8XH1B2Ex~AlP}CsSL-@;o=W6G3ENc<mu)HHTuW>EV@3&un=)hMiSW?B&tD<6Pa2btcLQ?Tba$C0vb z7MuC3>=Oq&ibpEaY++`$;x>;i$Axb2rG)`-=OS}v&bC)qIEd)-9$_^wGv5J4d+H!w zsyv48dta;l)V8N?bI9%^`8!FAd$NCUmfcVIPY(4G_t@Cws|`()N(Z==>(GP)U?R#g z?>SDyiW$=@_?9ouQh34FP{YA3S)|*E#i@-Z`JQnwXVEX(h86zJW3LzNsU(A)2guE~ zZ9h;tjXs!f6Jeg|ZBMp|r^v?u<6Db!afC|CJ3w;%V4>(wApnl8N%KcyYjH<*nLD$u zmU0zs@@I4H>p~pX>3RmhDJJjOQ@|iLEBW=k1nyygNef`Mg27~%?y`uqy)g)G4&W(r zpLXDQRqewmkI2(7tp_%m(xtx(zo_ziJHc&_X=X0M%p7MT7vbi$JD9I}L0kL|)1Fh2!;M)q>J6$^p- zXEIcGe$8&NI+z$$<98*mUP{0G^KS{}y2&-z@1iw*C39{|i2Qaie@O79dMm!3(|B>y8eZJo zS7`)k2md%-A#AU{M!Nz0sb4R)TP^!VZO>R2A>leO_UwvL8~I9xOa0bwf(Q@SO1x?$%FZO)yXyQ)PWB zjEJX$q3R)}E?4R|Ny;qG83ty8I~(rD7FB#R4Pc;V(A%xLc~IqZldQw*dW0QAW{fvq zR`&nu{(EJYaq{GK{M@(^ystWO7SMeyKcnE4&(Z;3HeM F{RJ~mUIzdG delta 1279 zcmah|Z){Ul6hHS}7;P2ugm&%N`ra)yW9>%bhD(PduB@QaWFnJfG7@2$5in&gF}h^? zK$n|;?yl+eV*5M<%=;p$;o-Y zd;Z+t`Q7&V?(4fx9nsFO`Q#-{V>c#ywL4l(N+xzSNPC1?b{ypV8L;Xg-#LF8cC256 zeQTd#smXI|KlQO8d}TwHU7noUu*ef1HA_?Q*=!f+#rU*Ubey~M9Asi{hqUXNwUB{w z{!$mtZ0z5oT`jf3G5|~f_@#c|83P7W?g0A@&~pIq*Z@<56l3H9#5Znk^jXk3K+p$p z%GcA31EJbShJ$i}?y=WZSZ+zr9vlyaLmAMWlbThGGpop%EXKLjbsxVEy{L8E!Y3+I zfw?A`qoqEMt;3yGnQu1e3(W!juUp7X)e1w$QaLewgbq6RO2$SzW{l{!JC!U zZ69uz7y03DZEhCk$lY)11mB}+>nF|%HuurFzcAoUbW_UG%LhtM7)Prb>V{~+W5%v! zKfKrJe;=j?6gJ<5X_Ihi-=(weVBERs&0528#uhmgE)bVLDcU?(_=|4(jPTzak}f`1 z!e2Ml8h$D@0e&xLH0cVKVEGSx!zu5TW-%FTWy5$hSRcLT=&o{K?WC7GU13q}gpc{l zbyf?G2RFC;wz9f9pHod)9nR&9QVR9(F|Ffk91N!dJrxfGzYuO@XYfuq>6<9h8)R1i z%}6(~8H|{rm?m$xaqDeL)U6!7<}y3}B#uXt2Xl18#UCXHG1}$`?fZS-0{9%ftO?HdI)(Dpt@@F+~n_EnFSKaHe0MHHZ%kQP3N@4m#m91J~ zwKR4K3rC}8vELNTMrn>TJ*8y%Kbf*B?{4B+x4^8pnOLo@KjsmO<9;!KEnCDt^A%V= diff --git a/X1_JTAG_boot/jtag_boot_rpi4.img b/X1_JTAG_boot/jtag_boot_rpi4.img index ea37301f05b97d1219a77b74eac3910f376f12f3..ee1f6fc4c545edda38bc7b5ccb60381b0ebb4ad2 100755 GIT binary patch delta 1017 zcmah{O-NKx6h8OeF=qVZHO`Dq&ge7CaYh}<%pVe($%Q|(8VHIOiY25rF4_o{IU*!c z3t!hV2tsjTZ(50nx(TCA(jt{|Q7xVZ^%M;Q`x!7_=e@ati=YGdo%@}0-go})4jb9ay3^y@72Z40g$(*K;A3|#R%;Bs*79YL}}_>c#=AQ zClbFudp!+_y9#PdqS7+<$mJtt?1k%SUw(vS$Ggy!y9 zV(F1ir{iQG1?H@zf!)k{SX6U8W`n>b|7#mZJ4S$$e5hzrKzeHn^&86Sc#)AWv| z;vha#d5uyT{xOKr>f|8Ws*;0P{=)}>@n85*u<0SNl*@#~BJ;FmMWy-iRXoO>;Cfr? zfR$u#F)63jK9q~2I3NRV_8{jYoA=~6(HeCpy)GVs-VIM)&NFVtb((S)zZrPgF>hs& zVcBQJ$7BlQSundPi*9zqdz&?R%2|)+g!A{2WSVsD7Eu?osJp&WG&Y4Iac#}xc)x6p z8#%rtNkOK%&vpE-f?@tcnMn_@z;TiuV2NWJ_kZA6;P?~Ag!OxS#>HGBjCz^fQ_a46 GeSZN^Y#N&Y delta 1010 zcmah`O-NKx6h8MoCuU6LHGj^GGy2qYe$-U58D)ef6)6dcS+o&yD2lKQaT5g9NRdfD z_`HTvo6Lp1*@;NGiK#XU1r;hmo97fU<_In(Q$%0)zISWWq6_z(``vTS_s;j-r_JNd z!!fSSFnyNeP~FUVF2lJ8ypn&QR8j_!tdxV4o&wni@o0Jynuc(%;W#(ooq1uHHgfY_ zxTl~4xo2hzvb?{dUMdm!rH)PzR?Fw)RaMP12P&|21patYrgl2UI$+S&crmbhQHrNyV)@}AUawvhT2W)ZF~ z%#z9Vg+)iqtT_K-?RMFXM;u?Ur>M2=lub{?ScGC7_pz2OkB-L~#-l|idnt*?62vEM zl{1VO{`1cohHWmLNdE$O7&ftdCBq!UK86vlcU_%Kx)HZggx`2V__?bVe|FV5#@#wq z9%~Rt^pTBwoep!7CG9Lp6hC$rySLai@n2g*ADj(k|5J6)g9EM`BgNux DoqQqW From 840f6d6f425e578708d660d7f424e3bb8ee4e3b5 Mon Sep 17 00:00:00 2001 From: Andre Richter Date: Mon, 27 Jun 2022 11:06:06 +0200 Subject: [PATCH 45/75] Add Cargo.toml to dependencies --- 01_wait_forever/Makefile | 6 +++--- 02_runtime_init/Makefile | 6 +++--- 03_hacky_hello_world/Makefile | 6 +++--- 04_safe_globals/Makefile | 6 +++--- 05_drivers_gpio_uart/Makefile | 6 +++--- 06_uart_chainloader/Makefile | 6 +++--- 07_timestamps/Makefile | 6 +++--- 08_hw_debug_JTAG/Makefile | 6 +++--- 09_privilege_level/Makefile | 6 +++--- 10_virtual_mem_part1_identity_mapping/Makefile | 6 +++--- 11_exceptions_part1_groundwork/Makefile | 6 +++--- 12_integrated_testing/Makefile | 2 +- 13_exceptions_part2_peripheral_IRQs/Makefile | 2 +- 14_virtual_mem_part2_mmio_remap/Makefile | 2 +- 15_virtual_mem_part3_precomputed_tables/Makefile | 2 +- 15_virtual_mem_part3_precomputed_tables/README.md | 4 ++-- 16_virtual_mem_part4_higher_half_kernel/Makefile | 2 +- 17_kernel_symbols/Makefile | 2 +- 18_backtrace/Makefile | 2 +- 19_kernel_heap/Makefile | 2 +- X1_JTAG_boot/Makefile | 6 +++--- 21 files changed, 46 insertions(+), 46 deletions(-) diff --git a/01_wait_forever/Makefile b/01_wait_forever/Makefile index 8ddb26cd..679b23b4 100644 --- a/01_wait_forever/Makefile +++ b/01_wait_forever/Makefile @@ -51,14 +51,14 @@ export LD_SCRIPT_PATH ##-------------------------------------------------------------------------------------------------- ## Targets and Prerequisites ##-------------------------------------------------------------------------------------------------- +KERNEL_MANIFEST = Cargo.toml KERNEL_LINKER_SCRIPT = kernel.ld - -LAST_BUILD_CONFIG = target/$(BSP).build_config +LAST_BUILD_CONFIG = target/$(BSP).build_config KERNEL_ELF = target/$(TARGET)/release/kernel # This parses cargo's dep-info file. # https://doc.rust-lang.org/cargo/guide/build-cache.html#dep-info-files -KERNEL_ELF_DEPS = $(filter-out %: ,$(file < $(KERNEL_ELF).d)) $(LAST_BUILD_CONFIG) +KERNEL_ELF_DEPS = $(filter-out %: ,$(file < $(KERNEL_ELF).d)) $(KERNEL_MANIFEST) $(LAST_BUILD_CONFIG) diff --git a/02_runtime_init/Makefile b/02_runtime_init/Makefile index af9bbc27..0abb67cc 100644 --- a/02_runtime_init/Makefile +++ b/02_runtime_init/Makefile @@ -51,14 +51,14 @@ export LD_SCRIPT_PATH ##-------------------------------------------------------------------------------------------------- ## Targets and Prerequisites ##-------------------------------------------------------------------------------------------------- +KERNEL_MANIFEST = Cargo.toml KERNEL_LINKER_SCRIPT = kernel.ld - -LAST_BUILD_CONFIG = target/$(BSP).build_config +LAST_BUILD_CONFIG = target/$(BSP).build_config KERNEL_ELF = target/$(TARGET)/release/kernel # This parses cargo's dep-info file. # https://doc.rust-lang.org/cargo/guide/build-cache.html#dep-info-files -KERNEL_ELF_DEPS = $(filter-out %: ,$(file < $(KERNEL_ELF).d)) $(LAST_BUILD_CONFIG) +KERNEL_ELF_DEPS = $(filter-out %: ,$(file < $(KERNEL_ELF).d)) $(KERNEL_MANIFEST) $(LAST_BUILD_CONFIG) diff --git a/03_hacky_hello_world/Makefile b/03_hacky_hello_world/Makefile index 8ddaf9e7..cfd5dc6e 100644 --- a/03_hacky_hello_world/Makefile +++ b/03_hacky_hello_world/Makefile @@ -51,14 +51,14 @@ export LD_SCRIPT_PATH ##-------------------------------------------------------------------------------------------------- ## Targets and Prerequisites ##-------------------------------------------------------------------------------------------------- +KERNEL_MANIFEST = Cargo.toml KERNEL_LINKER_SCRIPT = kernel.ld - -LAST_BUILD_CONFIG = target/$(BSP).build_config +LAST_BUILD_CONFIG = target/$(BSP).build_config KERNEL_ELF = target/$(TARGET)/release/kernel # This parses cargo's dep-info file. # https://doc.rust-lang.org/cargo/guide/build-cache.html#dep-info-files -KERNEL_ELF_DEPS = $(filter-out %: ,$(file < $(KERNEL_ELF).d)) $(LAST_BUILD_CONFIG) +KERNEL_ELF_DEPS = $(filter-out %: ,$(file < $(KERNEL_ELF).d)) $(KERNEL_MANIFEST) $(LAST_BUILD_CONFIG) diff --git a/04_safe_globals/Makefile b/04_safe_globals/Makefile index 8ddaf9e7..cfd5dc6e 100644 --- a/04_safe_globals/Makefile +++ b/04_safe_globals/Makefile @@ -51,14 +51,14 @@ export LD_SCRIPT_PATH ##-------------------------------------------------------------------------------------------------- ## Targets and Prerequisites ##-------------------------------------------------------------------------------------------------- +KERNEL_MANIFEST = Cargo.toml KERNEL_LINKER_SCRIPT = kernel.ld - -LAST_BUILD_CONFIG = target/$(BSP).build_config +LAST_BUILD_CONFIG = target/$(BSP).build_config KERNEL_ELF = target/$(TARGET)/release/kernel # This parses cargo's dep-info file. # https://doc.rust-lang.org/cargo/guide/build-cache.html#dep-info-files -KERNEL_ELF_DEPS = $(filter-out %: ,$(file < $(KERNEL_ELF).d)) $(LAST_BUILD_CONFIG) +KERNEL_ELF_DEPS = $(filter-out %: ,$(file < $(KERNEL_ELF).d)) $(KERNEL_MANIFEST) $(LAST_BUILD_CONFIG) diff --git a/05_drivers_gpio_uart/Makefile b/05_drivers_gpio_uart/Makefile index 183d7864..29d6729f 100644 --- a/05_drivers_gpio_uart/Makefile +++ b/05_drivers_gpio_uart/Makefile @@ -54,14 +54,14 @@ export LD_SCRIPT_PATH ##-------------------------------------------------------------------------------------------------- ## Targets and Prerequisites ##-------------------------------------------------------------------------------------------------- +KERNEL_MANIFEST = Cargo.toml KERNEL_LINKER_SCRIPT = kernel.ld - -LAST_BUILD_CONFIG = target/$(BSP).build_config +LAST_BUILD_CONFIG = target/$(BSP).build_config KERNEL_ELF = target/$(TARGET)/release/kernel # This parses cargo's dep-info file. # https://doc.rust-lang.org/cargo/guide/build-cache.html#dep-info-files -KERNEL_ELF_DEPS = $(filter-out %: ,$(file < $(KERNEL_ELF).d)) $(LAST_BUILD_CONFIG) +KERNEL_ELF_DEPS = $(filter-out %: ,$(file < $(KERNEL_ELF).d)) $(KERNEL_MANIFEST) $(LAST_BUILD_CONFIG) diff --git a/06_uart_chainloader/Makefile b/06_uart_chainloader/Makefile index 91245573..d7b102ae 100644 --- a/06_uart_chainloader/Makefile +++ b/06_uart_chainloader/Makefile @@ -56,14 +56,14 @@ export LD_SCRIPT_PATH ##-------------------------------------------------------------------------------------------------- ## Targets and Prerequisites ##-------------------------------------------------------------------------------------------------- +KERNEL_MANIFEST = Cargo.toml KERNEL_LINKER_SCRIPT = kernel.ld - -LAST_BUILD_CONFIG = target/$(BSP).build_config +LAST_BUILD_CONFIG = target/$(BSP).build_config KERNEL_ELF = target/$(TARGET)/release/kernel # This parses cargo's dep-info file. # https://doc.rust-lang.org/cargo/guide/build-cache.html#dep-info-files -KERNEL_ELF_DEPS = $(filter-out %: ,$(file < $(KERNEL_ELF).d)) $(LAST_BUILD_CONFIG) +KERNEL_ELF_DEPS = $(filter-out %: ,$(file < $(KERNEL_ELF).d)) $(KERNEL_MANIFEST) $(LAST_BUILD_CONFIG) diff --git a/07_timestamps/Makefile b/07_timestamps/Makefile index c183c606..76ddb186 100644 --- a/07_timestamps/Makefile +++ b/07_timestamps/Makefile @@ -54,14 +54,14 @@ export LD_SCRIPT_PATH ##-------------------------------------------------------------------------------------------------- ## Targets and Prerequisites ##-------------------------------------------------------------------------------------------------- +KERNEL_MANIFEST = Cargo.toml KERNEL_LINKER_SCRIPT = kernel.ld - -LAST_BUILD_CONFIG = target/$(BSP).build_config +LAST_BUILD_CONFIG = target/$(BSP).build_config KERNEL_ELF = target/$(TARGET)/release/kernel # This parses cargo's dep-info file. # https://doc.rust-lang.org/cargo/guide/build-cache.html#dep-info-files -KERNEL_ELF_DEPS = $(filter-out %: ,$(file < $(KERNEL_ELF).d)) $(LAST_BUILD_CONFIG) +KERNEL_ELF_DEPS = $(filter-out %: ,$(file < $(KERNEL_ELF).d)) $(KERNEL_MANIFEST) $(LAST_BUILD_CONFIG) diff --git a/08_hw_debug_JTAG/Makefile b/08_hw_debug_JTAG/Makefile index 3202f53a..ce0ebc31 100644 --- a/08_hw_debug_JTAG/Makefile +++ b/08_hw_debug_JTAG/Makefile @@ -58,14 +58,14 @@ export LD_SCRIPT_PATH ##-------------------------------------------------------------------------------------------------- ## Targets and Prerequisites ##-------------------------------------------------------------------------------------------------- +KERNEL_MANIFEST = Cargo.toml KERNEL_LINKER_SCRIPT = kernel.ld - -LAST_BUILD_CONFIG = target/$(BSP).build_config +LAST_BUILD_CONFIG = target/$(BSP).build_config KERNEL_ELF = target/$(TARGET)/release/kernel # This parses cargo's dep-info file. # https://doc.rust-lang.org/cargo/guide/build-cache.html#dep-info-files -KERNEL_ELF_DEPS = $(filter-out %: ,$(file < $(KERNEL_ELF).d)) $(LAST_BUILD_CONFIG) +KERNEL_ELF_DEPS = $(filter-out %: ,$(file < $(KERNEL_ELF).d)) $(KERNEL_MANIFEST) $(LAST_BUILD_CONFIG) diff --git a/09_privilege_level/Makefile b/09_privilege_level/Makefile index 3202f53a..ce0ebc31 100644 --- a/09_privilege_level/Makefile +++ b/09_privilege_level/Makefile @@ -58,14 +58,14 @@ export LD_SCRIPT_PATH ##-------------------------------------------------------------------------------------------------- ## Targets and Prerequisites ##-------------------------------------------------------------------------------------------------- +KERNEL_MANIFEST = Cargo.toml KERNEL_LINKER_SCRIPT = kernel.ld - -LAST_BUILD_CONFIG = target/$(BSP).build_config +LAST_BUILD_CONFIG = target/$(BSP).build_config KERNEL_ELF = target/$(TARGET)/release/kernel # This parses cargo's dep-info file. # https://doc.rust-lang.org/cargo/guide/build-cache.html#dep-info-files -KERNEL_ELF_DEPS = $(filter-out %: ,$(file < $(KERNEL_ELF).d)) $(LAST_BUILD_CONFIG) +KERNEL_ELF_DEPS = $(filter-out %: ,$(file < $(KERNEL_ELF).d)) $(KERNEL_MANIFEST) $(LAST_BUILD_CONFIG) diff --git a/10_virtual_mem_part1_identity_mapping/Makefile b/10_virtual_mem_part1_identity_mapping/Makefile index 3202f53a..ce0ebc31 100644 --- a/10_virtual_mem_part1_identity_mapping/Makefile +++ b/10_virtual_mem_part1_identity_mapping/Makefile @@ -58,14 +58,14 @@ export LD_SCRIPT_PATH ##-------------------------------------------------------------------------------------------------- ## Targets and Prerequisites ##-------------------------------------------------------------------------------------------------- +KERNEL_MANIFEST = Cargo.toml KERNEL_LINKER_SCRIPT = kernel.ld - -LAST_BUILD_CONFIG = target/$(BSP).build_config +LAST_BUILD_CONFIG = target/$(BSP).build_config KERNEL_ELF = target/$(TARGET)/release/kernel # This parses cargo's dep-info file. # https://doc.rust-lang.org/cargo/guide/build-cache.html#dep-info-files -KERNEL_ELF_DEPS = $(filter-out %: ,$(file < $(KERNEL_ELF).d)) $(LAST_BUILD_CONFIG) +KERNEL_ELF_DEPS = $(filter-out %: ,$(file < $(KERNEL_ELF).d)) $(KERNEL_MANIFEST) $(LAST_BUILD_CONFIG) diff --git a/11_exceptions_part1_groundwork/Makefile b/11_exceptions_part1_groundwork/Makefile index 3202f53a..ce0ebc31 100644 --- a/11_exceptions_part1_groundwork/Makefile +++ b/11_exceptions_part1_groundwork/Makefile @@ -58,14 +58,14 @@ export LD_SCRIPT_PATH ##-------------------------------------------------------------------------------------------------- ## Targets and Prerequisites ##-------------------------------------------------------------------------------------------------- +KERNEL_MANIFEST = Cargo.toml KERNEL_LINKER_SCRIPT = kernel.ld - -LAST_BUILD_CONFIG = target/$(BSP).build_config +LAST_BUILD_CONFIG = target/$(BSP).build_config KERNEL_ELF = target/$(TARGET)/release/kernel # This parses cargo's dep-info file. # https://doc.rust-lang.org/cargo/guide/build-cache.html#dep-info-files -KERNEL_ELF_DEPS = $(filter-out %: ,$(file < $(KERNEL_ELF).d)) $(LAST_BUILD_CONFIG) +KERNEL_ELF_DEPS = $(filter-out %: ,$(file < $(KERNEL_ELF).d)) $(KERNEL_MANIFEST) $(LAST_BUILD_CONFIG) diff --git a/12_integrated_testing/Makefile b/12_integrated_testing/Makefile index c7552461..670c30c4 100644 --- a/12_integrated_testing/Makefile +++ b/12_integrated_testing/Makefile @@ -74,7 +74,7 @@ LAST_BUILD_CONFIG = target/$(BSP).build_config KERNEL_ELF = target/$(TARGET)/release/kernel # This parses cargo's dep-info file. # https://doc.rust-lang.org/cargo/guide/build-cache.html#dep-info-files -KERNEL_ELF_DEPS = $(filter-out %: ,$(file < $(KERNEL_ELF).d)) $(LAST_BUILD_CONFIG) +KERNEL_ELF_DEPS = $(filter-out %: ,$(file < $(KERNEL_ELF).d)) $(KERNEL_MANIFEST) $(LAST_BUILD_CONFIG) diff --git a/13_exceptions_part2_peripheral_IRQs/Makefile b/13_exceptions_part2_peripheral_IRQs/Makefile index c7552461..670c30c4 100644 --- a/13_exceptions_part2_peripheral_IRQs/Makefile +++ b/13_exceptions_part2_peripheral_IRQs/Makefile @@ -74,7 +74,7 @@ LAST_BUILD_CONFIG = target/$(BSP).build_config KERNEL_ELF = target/$(TARGET)/release/kernel # This parses cargo's dep-info file. # https://doc.rust-lang.org/cargo/guide/build-cache.html#dep-info-files -KERNEL_ELF_DEPS = $(filter-out %: ,$(file < $(KERNEL_ELF).d)) $(LAST_BUILD_CONFIG) +KERNEL_ELF_DEPS = $(filter-out %: ,$(file < $(KERNEL_ELF).d)) $(KERNEL_MANIFEST) $(LAST_BUILD_CONFIG) diff --git a/14_virtual_mem_part2_mmio_remap/Makefile b/14_virtual_mem_part2_mmio_remap/Makefile index c7552461..670c30c4 100644 --- a/14_virtual_mem_part2_mmio_remap/Makefile +++ b/14_virtual_mem_part2_mmio_remap/Makefile @@ -74,7 +74,7 @@ LAST_BUILD_CONFIG = target/$(BSP).build_config KERNEL_ELF = target/$(TARGET)/release/kernel # This parses cargo's dep-info file. # https://doc.rust-lang.org/cargo/guide/build-cache.html#dep-info-files -KERNEL_ELF_DEPS = $(filter-out %: ,$(file < $(KERNEL_ELF).d)) $(LAST_BUILD_CONFIG) +KERNEL_ELF_DEPS = $(filter-out %: ,$(file < $(KERNEL_ELF).d)) $(KERNEL_MANIFEST) $(LAST_BUILD_CONFIG) diff --git a/15_virtual_mem_part3_precomputed_tables/Makefile b/15_virtual_mem_part3_precomputed_tables/Makefile index 6edf29a4..2e0a3462 100644 --- a/15_virtual_mem_part3_precomputed_tables/Makefile +++ b/15_virtual_mem_part3_precomputed_tables/Makefile @@ -74,7 +74,7 @@ LAST_BUILD_CONFIG = target/$(BSP).build_config KERNEL_ELF_RAW = target/$(TARGET)/release/kernel # This parses cargo's dep-info file. # https://doc.rust-lang.org/cargo/guide/build-cache.html#dep-info-files -KERNEL_ELF_RAW_DEPS = $(filter-out %: ,$(file < $(KERNEL_ELF_RAW).d)) $(LAST_BUILD_CONFIG) +KERNEL_ELF_RAW_DEPS = $(filter-out %: ,$(file < $(KERNEL_ELF_RAW).d)) $(KERNEL_MANIFEST) $(LAST_BUILD_CONFIG) ##------------------------------------------------------------------------------ ## Translation tables diff --git a/15_virtual_mem_part3_precomputed_tables/README.md b/15_virtual_mem_part3_precomputed_tables/README.md index be59abb1..40f72ba7 100644 --- a/15_virtual_mem_part3_precomputed_tables/README.md +++ b/15_virtual_mem_part3_precomputed_tables/README.md @@ -1846,8 +1846,8 @@ diff -uNr 14_virtual_mem_part2_mmio_remap/Makefile 15_virtual_mem_part3_precompu +KERNEL_ELF_RAW = target/$(TARGET)/release/kernel # This parses cargo's dep-info file. # https://doc.rust-lang.org/cargo/guide/build-cache.html#dep-info-files --KERNEL_ELF_DEPS = $(filter-out modulo: ,$(file < $(KERNEL_ELF).d)) $(LAST_BUILD_CONFIG) -+KERNEL_ELF_RAW_DEPS = $(filter-out modulo: ,$(file < $(KERNEL_ELF_RAW).d)) $(LAST_BUILD_CONFIG) +-KERNEL_ELF_DEPS = $(filter-out modulo: ,$(file < $(KERNEL_ELF).d)) $(KERNEL_MANIFEST) $(LAST_BUILD_CONFIG) ++KERNEL_ELF_RAW_DEPS = $(filter-out modulo: ,$(file < $(KERNEL_ELF_RAW).d)) $(KERNEL_MANIFEST) $(LAST_BUILD_CONFIG) + +##------------------------------------------------------------------------------ +## Translation tables diff --git a/16_virtual_mem_part4_higher_half_kernel/Makefile b/16_virtual_mem_part4_higher_half_kernel/Makefile index 6edf29a4..2e0a3462 100644 --- a/16_virtual_mem_part4_higher_half_kernel/Makefile +++ b/16_virtual_mem_part4_higher_half_kernel/Makefile @@ -74,7 +74,7 @@ LAST_BUILD_CONFIG = target/$(BSP).build_config KERNEL_ELF_RAW = target/$(TARGET)/release/kernel # This parses cargo's dep-info file. # https://doc.rust-lang.org/cargo/guide/build-cache.html#dep-info-files -KERNEL_ELF_RAW_DEPS = $(filter-out %: ,$(file < $(KERNEL_ELF_RAW).d)) $(LAST_BUILD_CONFIG) +KERNEL_ELF_RAW_DEPS = $(filter-out %: ,$(file < $(KERNEL_ELF_RAW).d)) $(KERNEL_MANIFEST) $(LAST_BUILD_CONFIG) ##------------------------------------------------------------------------------ ## Translation tables diff --git a/17_kernel_symbols/Makefile b/17_kernel_symbols/Makefile index 3a7465a3..9af33140 100644 --- a/17_kernel_symbols/Makefile +++ b/17_kernel_symbols/Makefile @@ -74,7 +74,7 @@ LAST_BUILD_CONFIG = target/$(BSP).build_config KERNEL_ELF_RAW = target/$(TARGET)/release/kernel # This parses cargo's dep-info file. # https://doc.rust-lang.org/cargo/guide/build-cache.html#dep-info-files -KERNEL_ELF_RAW_DEPS = $(filter-out %: ,$(file < $(KERNEL_ELF_RAW).d)) $(LAST_BUILD_CONFIG) +KERNEL_ELF_RAW_DEPS = $(filter-out %: ,$(file < $(KERNEL_ELF_RAW).d)) $(KERNEL_MANIFEST) $(LAST_BUILD_CONFIG) ##------------------------------------------------------------------------------ ## Translation tables diff --git a/18_backtrace/Makefile b/18_backtrace/Makefile index eba659f0..1dda95a4 100644 --- a/18_backtrace/Makefile +++ b/18_backtrace/Makefile @@ -74,7 +74,7 @@ LAST_BUILD_CONFIG = target/$(BSP).build_config KERNEL_ELF_RAW = target/$(TARGET)/release/kernel # This parses cargo's dep-info file. # https://doc.rust-lang.org/cargo/guide/build-cache.html#dep-info-files -KERNEL_ELF_RAW_DEPS = $(filter-out %: ,$(file < $(KERNEL_ELF_RAW).d)) $(LAST_BUILD_CONFIG) +KERNEL_ELF_RAW_DEPS = $(filter-out %: ,$(file < $(KERNEL_ELF_RAW).d)) $(KERNEL_MANIFEST) $(LAST_BUILD_CONFIG) ##------------------------------------------------------------------------------ ## Translation tables diff --git a/19_kernel_heap/Makefile b/19_kernel_heap/Makefile index c9a7d593..7b1673f3 100644 --- a/19_kernel_heap/Makefile +++ b/19_kernel_heap/Makefile @@ -79,7 +79,7 @@ LAST_BUILD_CONFIG = target/$(BSP)_$(DEBUG_PRINTS).build_config KERNEL_ELF_RAW = target/$(TARGET)/release/kernel # This parses cargo's dep-info file. # https://doc.rust-lang.org/cargo/guide/build-cache.html#dep-info-files -KERNEL_ELF_RAW_DEPS = $(filter-out %: ,$(file < $(KERNEL_ELF_RAW).d)) $(LAST_BUILD_CONFIG) +KERNEL_ELF_RAW_DEPS = $(filter-out %: ,$(file < $(KERNEL_ELF_RAW).d)) $(KERNEL_MANIFEST) $(LAST_BUILD_CONFIG) ##------------------------------------------------------------------------------ ## Translation tables diff --git a/X1_JTAG_boot/Makefile b/X1_JTAG_boot/Makefile index c183c606..76ddb186 100644 --- a/X1_JTAG_boot/Makefile +++ b/X1_JTAG_boot/Makefile @@ -54,14 +54,14 @@ export LD_SCRIPT_PATH ##-------------------------------------------------------------------------------------------------- ## Targets and Prerequisites ##-------------------------------------------------------------------------------------------------- +KERNEL_MANIFEST = Cargo.toml KERNEL_LINKER_SCRIPT = kernel.ld - -LAST_BUILD_CONFIG = target/$(BSP).build_config +LAST_BUILD_CONFIG = target/$(BSP).build_config KERNEL_ELF = target/$(TARGET)/release/kernel # This parses cargo's dep-info file. # https://doc.rust-lang.org/cargo/guide/build-cache.html#dep-info-files -KERNEL_ELF_DEPS = $(filter-out %: ,$(file < $(KERNEL_ELF).d)) $(LAST_BUILD_CONFIG) +KERNEL_ELF_DEPS = $(filter-out %: ,$(file < $(KERNEL_ELF).d)) $(KERNEL_MANIFEST) $(LAST_BUILD_CONFIG) From f7d3645d88ace0272d5510266ec8c11fb34c3a81 Mon Sep 17 00:00:00 2001 From: Hamish Poole Date: Sat, 30 Jul 2022 18:25:09 +1000 Subject: [PATCH 46/75] Copy editing and UART clarification. --- 05_drivers_gpio_uart/README.md | 1 + common/serial/minipush.rb | 4 ++-- common/serial/miniterm.rb | 8 ++++---- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/05_drivers_gpio_uart/README.md b/05_drivers_gpio_uart/README.md index 555ac031..85f53650 100644 --- a/05_drivers_gpio_uart/README.md +++ b/05_drivers_gpio_uart/README.md @@ -81,6 +81,7 @@ $ DEV_SERIAL=/dev/tty.usbserial-0001 make miniterm 7. Connect the USB serial to your host PC. - Wiring diagram at [top-level README](../README.md#-usb-serial-output). + - \## **NOTE** ## TX (transmit) wire connects to the RX (receive) pin. - Make sure that you **DID NOT** connect the power pin of the USB serial. Only RX/TX and GND. 8. Connect the RPi to the (USB) power cable and observe the output: diff --git a/common/serial/minipush.rb b/common/serial/minipush.rb index 62feebf2..262ce20a 100755 --- a/common/serial/minipush.rb +++ b/common/serial/minipush.rb @@ -82,7 +82,7 @@ class MiniPush < MiniTerm # override def handle_reconnect(_error) - connetion_reset + connection_reset puts puts "[#{@name_short}] ⚡ " \ @@ -107,7 +107,7 @@ class MiniPush < MiniTerm rescue StandardError => e handle_unexpected(e) ensure - connetion_reset + connection_reset puts puts "[#{@name_short}] Bye 👋" end diff --git a/common/serial/miniterm.rb b/common/serial/miniterm.rb index 996e1d3f..038ed978 100755 --- a/common/serial/miniterm.rb +++ b/common/serial/miniterm.rb @@ -88,7 +88,7 @@ class MiniTerm end end - def connetion_reset + def connection_reset @target_serial&.close @target_serial = nil @host_console.cooked! @@ -96,14 +96,14 @@ class MiniTerm # When the serial lost power or was removed during R/W operation. def handle_reconnect(_error) - connetion_reset + connection_reset puts puts "[#{@name_short}] ⚡ #{'Connection Error: Reinsert the USB serial again'.light_red}" end def handle_unexpected(error) - connetion_reset + connection_reset puts puts "[#{@name_short}] ⚡ #{"Unexpected Error: #{error.inspect}".light_red}" @@ -120,7 +120,7 @@ class MiniTerm rescue StandardError => e handle_unexpected(e) ensure - connetion_reset + connection_reset puts puts "[#{@name_short}] Bye 👋" end From 2daf3ea7fd508dbceecb77eb01ab43917684a34b Mon Sep 17 00:00:00 2001 From: Andre Richter Date: Sun, 31 Jul 2022 16:55:48 +0200 Subject: [PATCH 47/75] Update README.md --- 05_drivers_gpio_uart/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/05_drivers_gpio_uart/README.md b/05_drivers_gpio_uart/README.md index 85f53650..572cd1a8 100644 --- a/05_drivers_gpio_uart/README.md +++ b/05_drivers_gpio_uart/README.md @@ -81,7 +81,7 @@ $ DEV_SERIAL=/dev/tty.usbserial-0001 make miniterm 7. Connect the USB serial to your host PC. - Wiring diagram at [top-level README](../README.md#-usb-serial-output). - - \## **NOTE** ## TX (transmit) wire connects to the RX (receive) pin. + - **NOTE**: TX (transmit) wire connects to the RX (receive) pin. - Make sure that you **DID NOT** connect the power pin of the USB serial. Only RX/TX and GND. 8. Connect the RPi to the (USB) power cable and observe the output: From 08439f33d2bba2851dd0334cee6fe1114d235907 Mon Sep 17 00:00:00 2001 From: Andre Richter Date: Mon, 8 Aug 2022 00:05:25 +0200 Subject: [PATCH 48/75] Bump compiler and dependencies --- .rustfmt.toml | 2 -- 06_uart_chainloader/demo_payload_rpi3.img | Bin 7736 -> 7640 bytes 06_uart_chainloader/demo_payload_rpi4.img | Bin 7672 -> 7584 bytes 09_privilege_level/README.md | 2 +- 09_privilege_level/src/exception.rs | 2 +- .../src/exception.rs | 2 +- .../src/exception.rs | 2 +- 12_integrated_testing/Cargo.lock | 16 ++++++------- 12_integrated_testing/kernel/src/exception.rs | 2 +- .../Cargo.lock | 16 ++++++------- .../kernel/src/exception.rs | 2 +- 14_virtual_mem_part2_mmio_remap/Cargo.lock | 16 ++++++------- 14_virtual_mem_part2_mmio_remap/README.md | 15 ++++++------ .../kernel/src/exception.rs | 2 +- .../kernel/src/memory/mmu/mapping_record.rs | 3 +-- .../kernel/src/memory/mmu/types.rs | 10 ++++---- .../Cargo.lock | 16 ++++++------- .../README.md | 2 +- .../kernel/src/exception.rs | 2 +- .../kernel/src/memory/mmu/mapping_record.rs | 3 +-- .../src/memory/mmu/translation_table.rs | 2 +- .../kernel/src/memory/mmu/types.rs | 10 ++++---- .../Cargo.lock | 16 ++++++------- .../README.md | 2 +- .../kernel/src/exception.rs | 2 +- .../kernel/src/memory/mmu/mapping_record.rs | 3 +-- .../src/memory/mmu/translation_table.rs | 2 +- .../kernel/src/memory/mmu/types.rs | 10 ++++---- 17_kernel_symbols/Cargo.lock | 16 ++++++------- 17_kernel_symbols/README.md | 22 ++++++------------ 17_kernel_symbols/kernel/src/exception.rs | 2 +- .../kernel/src/memory/mmu/mapping_record.rs | 3 +-- .../src/memory/mmu/translation_table.rs | 2 +- .../kernel/src/memory/mmu/types.rs | 10 ++++---- 17_kernel_symbols/kernel/src/symbols.rs | 10 +++----- 18_backtrace/Cargo.lock | 16 ++++++------- 18_backtrace/kernel/src/exception.rs | 2 +- .../kernel/src/memory/mmu/mapping_record.rs | 3 +-- .../src/memory/mmu/translation_table.rs | 2 +- 18_backtrace/kernel/src/memory/mmu/types.rs | 10 ++++---- 18_backtrace/kernel/src/symbols.rs | 10 +++----- 19_kernel_heap/Cargo.lock | 20 ++++++++-------- 19_kernel_heap/README.md | 17 +++++++------- 19_kernel_heap/kernel/src/exception.rs | 2 +- .../src/memory/mmu/translation_table.rs | 2 +- 19_kernel_heap/kernel/src/memory/mmu/types.rs | 10 ++++---- 19_kernel_heap/kernel/src/symbols.rs | 10 +++----- X1_JTAG_boot/jtag_boot_rpi3.img | Bin 8792 -> 8680 bytes X1_JTAG_boot/jtag_boot_rpi4.img | Bin 7712 -> 7648 bytes rust-toolchain.toml | 2 +- 50 files changed, 152 insertions(+), 181 deletions(-) diff --git a/.rustfmt.toml b/.rustfmt.toml index 33aca681..c05f1817 100644 --- a/.rustfmt.toml +++ b/.rustfmt.toml @@ -5,5 +5,3 @@ format_code_in_doc_comments = true normalize_comments = true wrap_comments = true comment_width = 100 -report_fixme = "Always" -report_todo = "Always" diff --git a/06_uart_chainloader/demo_payload_rpi3.img b/06_uart_chainloader/demo_payload_rpi3.img index c0f226a7df2660c157a6e1360a4de8143631c965..bcb46b6137cabbe4e9a0e4e1bb1bda93b04267d1 100755 GIT binary patch delta 2223 zcmZuxT}%{L6h1SvyY8-t3%dxyB7>`07Z4~5EK~yv_=na?2x_8jQ3+A30%2_%U%E?q z@HZ*9Lt_7uqCD8UO%oDIif=ScQ%%#PXsb_wPlTbRplxG zk7G@&+3AWkr{G+HGtiVCEZC9~+*o7_7I`3;2txG*h&3le(mw8?)WmyMzH5a64q#ZG z0+JtFHxl7jaeR2abU`@K{yj|C(d58s?=2^R-t|O2!%^7>M7aud10pFyQ2nz721F2l z9T!?}i=&_2lz;qsTDIJq7XO-`W_y~zO)Tbs>V&YW2wc4J`IcL?KR6zLJLx4d&1UeqwPGsJQG02$6LQ+9lv%ltq&F zf@=ZQkO4;T;X5BEQ+qrV$$OmHQ!m7LsXn?&1yR<38?edZ&<|Hq( z>D&+3NN;6iW^886k*$xT2~;`Z6R3MZI-gM#EheM&UV>%rcjFAyZ6u7mvLE#0$7;Y8 z;X`B&A+bYf%YdI?AO*n_eo()N0-f!$(cLV79YV)!VU_hn zBX%SM+qpyz3G3xS~g z$3NHycehEc?z$*zeh&Kr!sUcr6EgnhlQ`M8@t=g%Tlg~>-vIV?VTy^xvB}ZT5uaLo zVPig8pD?kwX9Z=k9lh^WcL0>PqClFaWd=|PY>T*~H&i`_91$x@okjHly$|p%OO^^^j>v61x!=bVj6szWi*cW*+cms^tOi>IOXou5OJo^1TtTL>KR=Nov*eUw3oBLw! zf9-SGQgZd5(qL|(^h<8m#_@E+9O-E*>F(+1JXPEiVduxPjr|k@4P5xPN_TU-X{G`H zQGFnu)0@ZTNCjRWt9UraIEeSTKDL-^)Kee(Og>9IPj+-3?Lte;^s}0NrNtG+rTG2v z|Mm~Q@}^kd)pZJwiCvwqio>Rz5wx+h`*Nk5UVpW@?O|IuM12&CcCSHCcg6iwbIt2s z`suPi~^TP5fWA(^P7qSNVwrIHq!akET>rTDwd^^)W* m=K4jBhUZcVnh!_1kF@vnoEDop#2^C|YjtRs`39+AP3pe^cb1O; delta 2234 zcmZuzT}%{L6h1SvyX^8ivdix-GPu=cSwvuEf!dY@Oh7G>AjSsLf)XRBfQn5tw%J7= z{B5(>p`o>H)Y?R6+e8~eQ_>e2pGI_S$RHdYkSmBRGg*`fZVH@VzB=brPO zbG~!#gxhO=cq5c$nF2mn;C}0$BFo-l1tZy3V_avd@cD@3H6Axq`0~j_m9LAf@MQql z68K<~`-9X?p0$bIf+R<2BFag)*X2O!{c@;03Bjh7g(h#I4ZM?Hv59$*2rn$r&)QOs z8exC|xFX*Jk|!@8>R{6u_S_2b5Z5B+80_q|%R>+NQl>c_U|_-SkE$F)M!B|e^(u^+ z(a(b0+`o#rCsq*oC?m;EAj(CM@-en@0V+S@U_b!jSL)NAe)8sMoXCpb&^fvRFl zUtIp^&kN6W$aUzXA=qR|s*4sF{rt$zG@G};2qTtf!6tK3op?6A+OBejvH1>&F0>^{ zvs;p->5VB8b+j-C#j1?-08?4{wW-E)%BmsZt0!;0i;z;BOLzI9?DrJIalz>^HbVhU<&%2RECr6ZT z7%8A^!i&qS6zO2d-CCBYfjCLI%xV1Q&#HXH1yLNRkQ#`W+|@-y*R>xSSsV69MG|Gi?Z$*@bCAvu!vve)`bs*q?~KbhVH3Eu z@xWV^W5*WOK$IFnu!3BgQwM>8VcKxH9{6d>1iN=1$}L9f#L6GrAv%pZHDE+=gH(^YS*J-_foup? zD5Hs8!^+KR9&MV>XJZ@gA?t`SyM>dK0KQQgoI1K0FL_)A(M7O))J-Fp6~RV%D5G}x z{zEiDdgq?-lJUc<==Xxq_fA0{$3c`PGKVt7nWlkoCRoHcmkedpkIs{l0nydSav&SQ zI#JnDyP7<~Hz>z(+M|hH0P^H?3VDjvJ<}`G0_oXD{{-nNvap!&93~o>R|kU$Q2s?t z?CmyJ0N<(ww1wv|U?**(j(=et2v3t!J|6onpI-u)i`^)#UcJXx9AIVKy`}SehN!t^6l){nW@X598zZ~+eKatsgPh%O_u+B&7ntS&b=VwPHk;+<^A65RlY zT3c9Jygiq3hy`|M00a7U2aQy;SgXs60bT;c`|hru9ldx4bvvVm3Q$~BR#c3?KYc~t zTJo+?)7!fr-Gttr*M%$kJ&(2~>f7KDZ`xgzy4prnxCCt#3Fe$wJ(?-%lXdxdy<(}u zwM5tA=S5qHxzpiF(Y1@Ei{06trP}=-eO`3)|K{N@@w@Dd^oP3N;(rh{)qD`Y&sp{_ Dia42a diff --git a/06_uart_chainloader/demo_payload_rpi4.img b/06_uart_chainloader/demo_payload_rpi4.img index 82f75d6aef373994ecde6e7c8236afcbe19e5107..9299570333f80d8105d93af4cd7fd54112b6c208 100755 GIT binary patch delta 2061 zcmZuyeP~lx6hHU9q)XcBUYjn_rnN6kU6QueVb-)+m8Pw@b=0q-xPhz{aax(37?^|o zkz{4F-DLFf3iS)tEq}-j+Ze=d^gm^cDI!=u2OIKQ8GGr3sa0wG=-avP-Ao3%aC39d zIrp63`JHp`TWFhT8(r?a15%AFUQgXoYCpDzidrMh3Ju!_Y^{-iGSeRH7Fr{2fC}e| zWN)#Q>@C3=+EO0Qg&|ss{~Okqh8r7;!fFp$P`3yb#e3{9#vJ<2WCsN|5wvgAPsP4H zKf$yE;Cm-d$4poWrRo&z2%(xE6#X>NAS8SBG(;zDFeZb1?X1{$L!LZ&Mf>I3`mtc?KU;sb{b%Pr7O|UVE6di9QX9b7qBoXDTSXnVuM%d$ z*&pr4MSo7L$;{zIgNkU6m$vF(}Rk>yTG07kz? z3*SUg5tqdB{ZMlQ_&{1mo#!^>>+P|r&uz)x{V!F7>+LY*K$#OVz0N;iicwdvX9(mN zNQ5MNnOs9gW^fj43{jX~Y=b=7uN?(BqDW7TaUd|s4o++Z>49O4YXFn8xcZQ5RxhSI z-wKk5)G|Phj(YX5Yh^k0fusj)l+nU$>es2?xoRBikPsvX)a$OsM7!02+gG6J4zL(P znZAQi7rKhqMwEFEJ>_q#g z7>N0}hE>i=Q$oCg75Qp`sXee@SW%X}lJGl+*7o&VOB)97OX?V|{%1Dw&qkY_!v zr-`EDe`Ysq!zRl40q?Cq_1#vZ=Pnx9_#)Ng?B3%A7$W8cpdxD&y9ut?7cphSt3aX% zYA)@>H>4PCK^eilkuIURy;hJJC$g|xP-ce&W$GDH2hdzdN*fYZDqr&K0SEG%aoA#1 z6CIf|i-rgAwLFPWNjA1jB4tSdnZc0+YmKS9mV4INY}U?H;SWAJ=5TQNLe+ouJzh1l z{I@!^ImrDiE1cl#L6OH%N2+S-C6~36`8r%}?O&u8DXpPi}79!}kK;#}DmZePGwXVAG+vDLLp> zXDeTh9^+>CRWQdXzQ<3MIhr`I0wD(m2KT;?nqSopuZP@K-}cs&IXF2C9~({Th&K>z z<nIeaf!oO( VzeNUspW`p&)5!PFqg|+8{SU~kbHxAv delta 2143 zcmZ8iYfKbZ6h3!m7k5GE2-`(>m+T-~c41YNF3XlSEMl#gsuVG8`T|NC!BnbZ)TB*j z(Z+(0gy|)*rD;Oz4>Fs+5<(l&KNy>)B>mx|Y8%sZ*FG|syzugy>>?FW<1ZG8D?H3>HB?-9%;=!-7R)oGbgF9R^s2wy#EB<=li5 zzn};B7FuNUauc78{3EO*&2E5!d2dY9c_NSVEtmDPaNYs%r4zTKE-VLAE9K<7L`jx_ ztPX<`fOwO78lt;xFd%~XBlBr>AHOi(`04G|i)U}g_TIQn57}37b>Wd=`v-i5#y zV2uqa4{o_vW1--6QjP7syhF zEv6)SM}p-6AvR__U9mCxgCKIwr;Q@WIa-__sB5c~S+TpCK}eU3DQR8*SLHztE{V#? za-v+X2ScAieewuaQ)*Y3{ia`ZqYc3bJ(lm0KAO`{vBFfIBvL#il028Vh5)wQ*9%2) zy+Q!`KS2_Tp-kp;V_GZtFE8L7Ut`+Ec^w;Pu4@=4Q^XBjFVuPN{Co{)sO^V%M0R05 zATY|Hv^GOP_#Hcv1Q`7jpT)Qt7^dvq3<8fNVt4u-#g+76!OHyLoGz%PHigy6Y|5(X z=LLR8HCBk#zDzF_grq0TDZ4a_rdPlyIe=&C6`~YisP4lNdD06Sb62ZC=wuDXkh)}7 zW=cTbgz`*Dmf_b{3c}P`kdwHvF8RHARILY zETA9z9{}BfN#Z#W`EWf_j5c$ah{YJFM;n~%7gz%^myzR&M3mm;IBg4pOA;tk40*R% z$r&FA)5t=GiKkcs2ShruV%jtU&9tXs9SEB-A&ZqRH$k#WGi>&F5C9g%mv4dpvLl(F|$ znC>M|k}X^i`=1y^nYG8U8fOS+N0$~Us^n1o0Jqd5M9wDhL8kA$staiz#Gt4RKc911?m{-(xWC@LxpV`G@ZLk|)9X%0Q-D%E2FOs7eOgk}IHu`|vXUI9m ztPv+;oR_cFbMnxAY!g736{+LbA&F-v5ilbfzcj9vC*hXU4$XMMNA467@?t-S+~A5c zo^dr=^7{HMV&k(FYuAc9>YADX_S;RpVT3;z%vgu4^Twiw^@@i!ExSqs-ar`bsK?a0 zEic8AIZN)|*S= @@ -2531,8 +2531,7 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/memory/mmu/mapping_reco + ) -> Option<&mut MappingRecordEntry> { + self.inner + .iter_mut() -+ .filter(|x| x.is_some()) -+ .map(|x| x.as_mut().unwrap()) ++ .filter_map(|x| x.as_mut()) + .filter(|x| x.attribute_fields.mem_attributes == MemAttributes::Device) + .find(|x| { + if x.phys_start_addr != phys_region.start_addr() { @@ -2859,13 +2858,13 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/memory/mmu/types.rs 14_ +//-------------------------------------------------------------------------------------------------- + +/// A wrapper type around [Address] that ensures page alignment. -+#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)] ++#[derive(Copy, Clone, Debug, Eq, PartialOrd, PartialEq)] +pub struct PageAddress { + inner: Address, +} + +/// A type that describes a region of memory in quantities of pages. -+#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)] ++#[derive(Copy, Clone, Debug, Eq, PartialOrd, PartialEq)] +pub struct MemoryRegion { + start: PageAddress, + end_exclusive: PageAddress, @@ -2873,7 +2872,7 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/memory/mmu/types.rs 14_ + +/// Architecture agnostic memory attributes. +#[allow(missing_docs)] -+#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)] ++#[derive(Copy, Clone, Debug, Eq, PartialOrd, PartialEq)] +pub enum MemAttributes { + CacheableDRAM, + Device, @@ -2881,7 +2880,7 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/memory/mmu/types.rs 14_ + +/// Architecture agnostic access permissions. +#[allow(missing_docs)] -+#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)] ++#[derive(Copy, Clone, Debug, Eq, PartialOrd, PartialEq)] +pub enum AccessPermissions { + ReadOnly, + ReadWrite, @@ -2889,7 +2888,7 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/memory/mmu/types.rs 14_ + +/// Collection of memory attributes. +#[allow(missing_docs)] -+#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)] ++#[derive(Copy, Clone, Debug, Eq, PartialOrd, PartialEq)] +pub struct AttributeFields { + pub mem_attributes: MemAttributes, + pub acc_perms: AccessPermissions, diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/exception.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/exception.rs index f4af8144..7ea7cd80 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/exception.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/exception.rs @@ -21,7 +21,7 @@ pub use arch_exception::{current_privilege_level, handling_init}; /// Kernel privilege levels. #[allow(missing_docs)] -#[derive(PartialEq)] +#[derive(Eq, PartialEq)] pub enum PrivilegeLevel { User, Kernel, diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/memory/mmu/mapping_record.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/memory/mmu/mapping_record.rs index 5bc32445..b893fee3 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/memory/mmu/mapping_record.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/memory/mmu/mapping_record.rs @@ -103,8 +103,7 @@ impl MappingRecord { ) -> Option<&mut MappingRecordEntry> { self.inner .iter_mut() - .filter(|x| x.is_some()) - .map(|x| x.as_mut().unwrap()) + .filter_map(|x| x.as_mut()) .filter(|x| x.attribute_fields.mem_attributes == MemAttributes::Device) .find(|x| { if x.phys_start_addr != phys_region.start_addr() { diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/memory/mmu/types.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/memory/mmu/types.rs index 7a4fb071..362438fd 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/memory/mmu/types.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/memory/mmu/types.rs @@ -15,13 +15,13 @@ use core::{convert::From, iter::Step, num::NonZeroUsize, ops::Range}; //-------------------------------------------------------------------------------------------------- /// A wrapper type around [Address] that ensures page alignment. -#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)] +#[derive(Copy, Clone, Debug, Eq, PartialOrd, PartialEq)] pub struct PageAddress { inner: Address, } /// A type that describes a region of memory in quantities of pages. -#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)] +#[derive(Copy, Clone, Debug, Eq, PartialOrd, PartialEq)] pub struct MemoryRegion { start: PageAddress, end_exclusive: PageAddress, @@ -29,7 +29,7 @@ pub struct MemoryRegion { /// Architecture agnostic memory attributes. #[allow(missing_docs)] -#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)] +#[derive(Copy, Clone, Debug, Eq, PartialOrd, PartialEq)] pub enum MemAttributes { CacheableDRAM, Device, @@ -37,7 +37,7 @@ pub enum MemAttributes { /// Architecture agnostic access permissions. #[allow(missing_docs)] -#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)] +#[derive(Copy, Clone, Debug, Eq, PartialOrd, PartialEq)] pub enum AccessPermissions { ReadOnly, ReadWrite, @@ -45,7 +45,7 @@ pub enum AccessPermissions { /// Collection of memory attributes. #[allow(missing_docs)] -#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)] +#[derive(Copy, Clone, Debug, Eq, PartialOrd, PartialEq)] pub struct AttributeFields { pub mem_attributes: MemAttributes, pub acc_perms: AccessPermissions, diff --git a/15_virtual_mem_part3_precomputed_tables/Cargo.lock b/15_virtual_mem_part3_precomputed_tables/Cargo.lock index 8aa6b75d..72cc4866 100644 --- a/15_virtual_mem_part3_precomputed_tables/Cargo.lock +++ b/15_virtual_mem_part3_precomputed_tables/Cargo.lock @@ -24,9 +24,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.40" +version = "1.0.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd96a1e8ed2596c337f8eae5f24924ec83f5ad5ab21ea8e455d3566c69fbcaf7" +checksum = "0a2ca2c61bc9f3d74d2886294ab7b9853abd9c1ad903a3ac7815c58989bb7bab" dependencies = [ "unicode-ident", ] @@ -39,18 +39,18 @@ checksum = "9ff023245bfcc73fb890e1f8d5383825b3131cc920020a5c487d6f113dfc428a" [[package]] name = "quote" -version = "1.0.20" +version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3bcdf212e9776fbcb2d23ab029360416bb1706b1aea2d1a5ba002727cbcab804" +checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179" dependencies = [ "proc-macro2", ] [[package]] name = "syn" -version = "1.0.98" +version = "1.0.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c50aef8a904de4c23c788f104b7dddc7d6f79c647c7c8ce4cc8f73eb0ca773dd" +checksum = "58dbef6ec655055e20b86b15a8cc6d439cca19b667537ac6a1369572d151ab13" dependencies = [ "proc-macro2", "quote", @@ -79,6 +79,6 @@ checksum = "4ee8fba06c1f4d0b396ef61a54530bb6b28f0dc61c38bc8bc5a5a48161e6282e" [[package]] name = "unicode-ident" -version = "1.0.1" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bd2fe26506023ed7b5e1e315add59d6f584c621d037f9368fea9cfb988f368c" +checksum = "c4f5b37a154999a8f3f98cc23a628d850e154479cd94decf3414696e12e31aaf" diff --git a/15_virtual_mem_part3_precomputed_tables/README.md b/15_virtual_mem_part3_precomputed_tables/README.md index 40f72ba7..25c26c0a 100644 --- a/15_virtual_mem_part3_precomputed_tables/README.md +++ b/15_virtual_mem_part3_precomputed_tables/README.md @@ -1454,7 +1454,7 @@ diff -uNr 14_virtual_mem_part2_mmio_remap/kernel/src/memory/mmu/translation_tabl + let mut tables = MinSizeTranslationTable::new_for_runtime(); - tables.init(); -+ assert!(tables.init().is_ok()); ++ assert_eq!(tables.init(), Ok(())); let virt_start_page_addr: PageAddress = PageAddress::from(0); let virt_end_exclusive_page_addr: PageAddress = diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/exception.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/exception.rs index f4af8144..7ea7cd80 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/exception.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/exception.rs @@ -21,7 +21,7 @@ pub use arch_exception::{current_privilege_level, handling_init}; /// Kernel privilege levels. #[allow(missing_docs)] -#[derive(PartialEq)] +#[derive(Eq, PartialEq)] pub enum PrivilegeLevel { User, Kernel, diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/memory/mmu/mapping_record.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/memory/mmu/mapping_record.rs index 5bc32445..b893fee3 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/memory/mmu/mapping_record.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/memory/mmu/mapping_record.rs @@ -103,8 +103,7 @@ impl MappingRecord { ) -> Option<&mut MappingRecordEntry> { self.inner .iter_mut() - .filter(|x| x.is_some()) - .map(|x| x.as_mut().unwrap()) + .filter_map(|x| x.as_mut()) .filter(|x| x.attribute_fields.mem_attributes == MemAttributes::Device) .find(|x| { if x.phys_start_addr != phys_region.start_addr() { diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/memory/mmu/translation_table.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/memory/mmu/translation_table.rs index 5a34a1e6..c36fb3d6 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/memory/mmu/translation_table.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/memory/mmu/translation_table.rs @@ -97,7 +97,7 @@ mod tests { // This will occupy a lot of space on the stack. let mut tables = MinSizeTranslationTable::new_for_runtime(); - assert!(tables.init().is_ok()); + assert_eq!(tables.init(), Ok(())); let virt_start_page_addr: PageAddress = PageAddress::from(0); let virt_end_exclusive_page_addr: PageAddress = diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/memory/mmu/types.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/memory/mmu/types.rs index 7a4fb071..362438fd 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/memory/mmu/types.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/memory/mmu/types.rs @@ -15,13 +15,13 @@ use core::{convert::From, iter::Step, num::NonZeroUsize, ops::Range}; //-------------------------------------------------------------------------------------------------- /// A wrapper type around [Address] that ensures page alignment. -#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)] +#[derive(Copy, Clone, Debug, Eq, PartialOrd, PartialEq)] pub struct PageAddress { inner: Address, } /// A type that describes a region of memory in quantities of pages. -#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)] +#[derive(Copy, Clone, Debug, Eq, PartialOrd, PartialEq)] pub struct MemoryRegion { start: PageAddress, end_exclusive: PageAddress, @@ -29,7 +29,7 @@ pub struct MemoryRegion { /// Architecture agnostic memory attributes. #[allow(missing_docs)] -#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)] +#[derive(Copy, Clone, Debug, Eq, PartialOrd, PartialEq)] pub enum MemAttributes { CacheableDRAM, Device, @@ -37,7 +37,7 @@ pub enum MemAttributes { /// Architecture agnostic access permissions. #[allow(missing_docs)] -#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)] +#[derive(Copy, Clone, Debug, Eq, PartialOrd, PartialEq)] pub enum AccessPermissions { ReadOnly, ReadWrite, @@ -45,7 +45,7 @@ pub enum AccessPermissions { /// Collection of memory attributes. #[allow(missing_docs)] -#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)] +#[derive(Copy, Clone, Debug, Eq, PartialOrd, PartialEq)] pub struct AttributeFields { pub mem_attributes: MemAttributes, pub acc_perms: AccessPermissions, diff --git a/16_virtual_mem_part4_higher_half_kernel/Cargo.lock b/16_virtual_mem_part4_higher_half_kernel/Cargo.lock index 66ac8733..ac4f39a2 100644 --- a/16_virtual_mem_part4_higher_half_kernel/Cargo.lock +++ b/16_virtual_mem_part4_higher_half_kernel/Cargo.lock @@ -24,9 +24,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.40" +version = "1.0.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd96a1e8ed2596c337f8eae5f24924ec83f5ad5ab21ea8e455d3566c69fbcaf7" +checksum = "0a2ca2c61bc9f3d74d2886294ab7b9853abd9c1ad903a3ac7815c58989bb7bab" dependencies = [ "unicode-ident", ] @@ -39,18 +39,18 @@ checksum = "9ff023245bfcc73fb890e1f8d5383825b3131cc920020a5c487d6f113dfc428a" [[package]] name = "quote" -version = "1.0.20" +version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3bcdf212e9776fbcb2d23ab029360416bb1706b1aea2d1a5ba002727cbcab804" +checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179" dependencies = [ "proc-macro2", ] [[package]] name = "syn" -version = "1.0.98" +version = "1.0.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c50aef8a904de4c23c788f104b7dddc7d6f79c647c7c8ce4cc8f73eb0ca773dd" +checksum = "58dbef6ec655055e20b86b15a8cc6d439cca19b667537ac6a1369572d151ab13" dependencies = [ "proc-macro2", "quote", @@ -79,6 +79,6 @@ checksum = "4ee8fba06c1f4d0b396ef61a54530bb6b28f0dc61c38bc8bc5a5a48161e6282e" [[package]] name = "unicode-ident" -version = "1.0.1" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bd2fe26506023ed7b5e1e315add59d6f584c621d037f9368fea9cfb988f368c" +checksum = "c4f5b37a154999a8f3f98cc23a628d850e154479cd94decf3414696e12e31aaf" diff --git a/16_virtual_mem_part4_higher_half_kernel/README.md b/16_virtual_mem_part4_higher_half_kernel/README.md index cb50cab0..443c7223 100644 --- a/16_virtual_mem_part4_higher_half_kernel/README.md +++ b/16_virtual_mem_part4_higher_half_kernel/README.md @@ -749,7 +749,7 @@ diff -uNr 15_virtual_mem_part3_precomputed_tables/kernel/src/memory/mmu/translat +++ 16_virtual_mem_part4_higher_half_kernel/kernel/src/memory/mmu/translation_table.rs @@ -99,9 +99,9 @@ - assert!(tables.init().is_ok()); + assert_eq!(tables.init(), Ok(())); - let virt_start_page_addr: PageAddress = PageAddress::from(0); - let virt_end_exclusive_page_addr: PageAddress = diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/exception.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/exception.rs index f4af8144..7ea7cd80 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/exception.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/exception.rs @@ -21,7 +21,7 @@ pub use arch_exception::{current_privilege_level, handling_init}; /// Kernel privilege levels. #[allow(missing_docs)] -#[derive(PartialEq)] +#[derive(Eq, PartialEq)] pub enum PrivilegeLevel { User, Kernel, diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/memory/mmu/mapping_record.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/memory/mmu/mapping_record.rs index 5bc32445..b893fee3 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/memory/mmu/mapping_record.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/memory/mmu/mapping_record.rs @@ -103,8 +103,7 @@ impl MappingRecord { ) -> Option<&mut MappingRecordEntry> { self.inner .iter_mut() - .filter(|x| x.is_some()) - .map(|x| x.as_mut().unwrap()) + .filter_map(|x| x.as_mut()) .filter(|x| x.attribute_fields.mem_attributes == MemAttributes::Device) .find(|x| { if x.phys_start_addr != phys_region.start_addr() { diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/memory/mmu/translation_table.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/memory/mmu/translation_table.rs index 9d627f97..9301bb0c 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/memory/mmu/translation_table.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/memory/mmu/translation_table.rs @@ -97,7 +97,7 @@ mod tests { // This will occupy a lot of space on the stack. let mut tables = MinSizeTranslationTable::new_for_runtime(); - assert!(tables.init().is_ok()); + assert_eq!(tables.init(), Ok(())); let virt_end_exclusive_page_addr: PageAddress = PageAddress::MAX; let virt_start_page_addr: PageAddress = diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/memory/mmu/types.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/memory/mmu/types.rs index 85c852b3..62f3926e 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/memory/mmu/types.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/memory/mmu/types.rs @@ -15,13 +15,13 @@ use core::{convert::From, iter::Step, num::NonZeroUsize, ops::Range}; //-------------------------------------------------------------------------------------------------- /// A wrapper type around [Address] that ensures page alignment. -#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)] +#[derive(Copy, Clone, Debug, Eq, PartialOrd, PartialEq)] pub struct PageAddress { inner: Address, } /// A type that describes a region of memory in quantities of pages. -#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)] +#[derive(Copy, Clone, Debug, Eq, PartialOrd, PartialEq)] pub struct MemoryRegion { start: PageAddress, end_exclusive: PageAddress, @@ -29,7 +29,7 @@ pub struct MemoryRegion { /// Architecture agnostic memory attributes. #[allow(missing_docs)] -#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)] +#[derive(Copy, Clone, Debug, Eq, PartialOrd, PartialEq)] pub enum MemAttributes { CacheableDRAM, Device, @@ -37,7 +37,7 @@ pub enum MemAttributes { /// Architecture agnostic access permissions. #[allow(missing_docs)] -#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)] +#[derive(Copy, Clone, Debug, Eq, PartialOrd, PartialEq)] pub enum AccessPermissions { ReadOnly, ReadWrite, @@ -45,7 +45,7 @@ pub enum AccessPermissions { /// Collection of memory attributes. #[allow(missing_docs)] -#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)] +#[derive(Copy, Clone, Debug, Eq, PartialOrd, PartialEq)] pub struct AttributeFields { pub mem_attributes: MemAttributes, pub acc_perms: AccessPermissions, diff --git a/17_kernel_symbols/Cargo.lock b/17_kernel_symbols/Cargo.lock index a0da4e21..cd3793ed 100644 --- a/17_kernel_symbols/Cargo.lock +++ b/17_kernel_symbols/Cargo.lock @@ -36,9 +36,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.40" +version = "1.0.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd96a1e8ed2596c337f8eae5f24924ec83f5ad5ab21ea8e455d3566c69fbcaf7" +checksum = "0a2ca2c61bc9f3d74d2886294ab7b9853abd9c1ad903a3ac7815c58989bb7bab" dependencies = [ "unicode-ident", ] @@ -51,18 +51,18 @@ checksum = "9ff023245bfcc73fb890e1f8d5383825b3131cc920020a5c487d6f113dfc428a" [[package]] name = "quote" -version = "1.0.20" +version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3bcdf212e9776fbcb2d23ab029360416bb1706b1aea2d1a5ba002727cbcab804" +checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179" dependencies = [ "proc-macro2", ] [[package]] name = "syn" -version = "1.0.98" +version = "1.0.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c50aef8a904de4c23c788f104b7dddc7d6f79c647c7c8ce4cc8f73eb0ca773dd" +checksum = "58dbef6ec655055e20b86b15a8cc6d439cca19b667537ac6a1369572d151ab13" dependencies = [ "proc-macro2", "quote", @@ -91,6 +91,6 @@ checksum = "4ee8fba06c1f4d0b396ef61a54530bb6b28f0dc61c38bc8bc5a5a48161e6282e" [[package]] name = "unicode-ident" -version = "1.0.1" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bd2fe26506023ed7b5e1e315add59d6f584c621d037f9368fea9cfb988f368c" +checksum = "c4f5b37a154999a8f3f98cc23a628d850e154479cd94decf3414696e12e31aaf" diff --git a/17_kernel_symbols/README.md b/17_kernel_symbols/README.md index b9d21aec..ace1ed6e 100644 --- a/17_kernel_symbols/README.md +++ b/17_kernel_symbols/README.md @@ -183,13 +183,9 @@ Lookup is done by just iterating over the slice: ```rust /// Retrieve the symbol corresponding to a virtual address, if any. pub fn lookup_symbol(addr: Address) -> Option<&'static Symbol> { - for i in kernel_symbols_slice() { - if i.contains(addr.as_usize()) { - return Some(i); - } - } - - None + kernel_symbols_slice() + .iter() + .find(|&i| i.contains(addr.as_usize())) } ``` @@ -342,7 +338,7 @@ diff -uNr 16_virtual_mem_part4_higher_half_kernel/kernel/src/lib.rs 17_kernel_sy diff -uNr 16_virtual_mem_part4_higher_half_kernel/kernel/src/symbols.rs 17_kernel_symbols/kernel/src/symbols.rs --- 16_virtual_mem_part4_higher_half_kernel/kernel/src/symbols.rs +++ 17_kernel_symbols/kernel/src/symbols.rs -@@ -0,0 +1,87 @@ +@@ -0,0 +1,83 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2022 Andre Richter @@ -394,13 +390,9 @@ diff -uNr 16_virtual_mem_part4_higher_half_kernel/kernel/src/symbols.rs 17_kerne + +/// Retrieve the symbol corresponding to a virtual address, if any. +pub fn lookup_symbol(addr: Address) -> Option<&'static Symbol> { -+ for i in kernel_symbols_slice() { -+ if i.contains(addr.as_usize()) { -+ return Some(i); -+ } -+ } -+ -+ None ++ kernel_symbols_slice() ++ .iter() ++ .find(|&i| i.contains(addr.as_usize())) +} + +//-------------------------------------------------------------------------------------------------- diff --git a/17_kernel_symbols/kernel/src/exception.rs b/17_kernel_symbols/kernel/src/exception.rs index f4af8144..7ea7cd80 100644 --- a/17_kernel_symbols/kernel/src/exception.rs +++ b/17_kernel_symbols/kernel/src/exception.rs @@ -21,7 +21,7 @@ pub use arch_exception::{current_privilege_level, handling_init}; /// Kernel privilege levels. #[allow(missing_docs)] -#[derive(PartialEq)] +#[derive(Eq, PartialEq)] pub enum PrivilegeLevel { User, Kernel, diff --git a/17_kernel_symbols/kernel/src/memory/mmu/mapping_record.rs b/17_kernel_symbols/kernel/src/memory/mmu/mapping_record.rs index 5bc32445..b893fee3 100644 --- a/17_kernel_symbols/kernel/src/memory/mmu/mapping_record.rs +++ b/17_kernel_symbols/kernel/src/memory/mmu/mapping_record.rs @@ -103,8 +103,7 @@ impl MappingRecord { ) -> Option<&mut MappingRecordEntry> { self.inner .iter_mut() - .filter(|x| x.is_some()) - .map(|x| x.as_mut().unwrap()) + .filter_map(|x| x.as_mut()) .filter(|x| x.attribute_fields.mem_attributes == MemAttributes::Device) .find(|x| { if x.phys_start_addr != phys_region.start_addr() { diff --git a/17_kernel_symbols/kernel/src/memory/mmu/translation_table.rs b/17_kernel_symbols/kernel/src/memory/mmu/translation_table.rs index 9d627f97..9301bb0c 100644 --- a/17_kernel_symbols/kernel/src/memory/mmu/translation_table.rs +++ b/17_kernel_symbols/kernel/src/memory/mmu/translation_table.rs @@ -97,7 +97,7 @@ mod tests { // This will occupy a lot of space on the stack. let mut tables = MinSizeTranslationTable::new_for_runtime(); - assert!(tables.init().is_ok()); + assert_eq!(tables.init(), Ok(())); let virt_end_exclusive_page_addr: PageAddress = PageAddress::MAX; let virt_start_page_addr: PageAddress = diff --git a/17_kernel_symbols/kernel/src/memory/mmu/types.rs b/17_kernel_symbols/kernel/src/memory/mmu/types.rs index 85c852b3..62f3926e 100644 --- a/17_kernel_symbols/kernel/src/memory/mmu/types.rs +++ b/17_kernel_symbols/kernel/src/memory/mmu/types.rs @@ -15,13 +15,13 @@ use core::{convert::From, iter::Step, num::NonZeroUsize, ops::Range}; //-------------------------------------------------------------------------------------------------- /// A wrapper type around [Address] that ensures page alignment. -#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)] +#[derive(Copy, Clone, Debug, Eq, PartialOrd, PartialEq)] pub struct PageAddress { inner: Address, } /// A type that describes a region of memory in quantities of pages. -#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)] +#[derive(Copy, Clone, Debug, Eq, PartialOrd, PartialEq)] pub struct MemoryRegion { start: PageAddress, end_exclusive: PageAddress, @@ -29,7 +29,7 @@ pub struct MemoryRegion { /// Architecture agnostic memory attributes. #[allow(missing_docs)] -#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)] +#[derive(Copy, Clone, Debug, Eq, PartialOrd, PartialEq)] pub enum MemAttributes { CacheableDRAM, Device, @@ -37,7 +37,7 @@ pub enum MemAttributes { /// Architecture agnostic access permissions. #[allow(missing_docs)] -#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)] +#[derive(Copy, Clone, Debug, Eq, PartialOrd, PartialEq)] pub enum AccessPermissions { ReadOnly, ReadWrite, @@ -45,7 +45,7 @@ pub enum AccessPermissions { /// Collection of memory attributes. #[allow(missing_docs)] -#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)] +#[derive(Copy, Clone, Debug, Eq, PartialOrd, PartialEq)] pub struct AttributeFields { pub mem_attributes: MemAttributes, pub acc_perms: AccessPermissions, diff --git a/17_kernel_symbols/kernel/src/symbols.rs b/17_kernel_symbols/kernel/src/symbols.rs index 22001389..7f439ce2 100644 --- a/17_kernel_symbols/kernel/src/symbols.rs +++ b/17_kernel_symbols/kernel/src/symbols.rs @@ -49,13 +49,9 @@ fn kernel_symbols_slice() -> &'static [Symbol] { /// Retrieve the symbol corresponding to a virtual address, if any. pub fn lookup_symbol(addr: Address) -> Option<&'static Symbol> { - for i in kernel_symbols_slice() { - if i.contains(addr.as_usize()) { - return Some(i); - } - } - - None + kernel_symbols_slice() + .iter() + .find(|&i| i.contains(addr.as_usize())) } //-------------------------------------------------------------------------------------------------- diff --git a/18_backtrace/Cargo.lock b/18_backtrace/Cargo.lock index e0ab66b1..3e5338e8 100644 --- a/18_backtrace/Cargo.lock +++ b/18_backtrace/Cargo.lock @@ -36,9 +36,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.40" +version = "1.0.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd96a1e8ed2596c337f8eae5f24924ec83f5ad5ab21ea8e455d3566c69fbcaf7" +checksum = "0a2ca2c61bc9f3d74d2886294ab7b9853abd9c1ad903a3ac7815c58989bb7bab" dependencies = [ "unicode-ident", ] @@ -51,18 +51,18 @@ checksum = "9ff023245bfcc73fb890e1f8d5383825b3131cc920020a5c487d6f113dfc428a" [[package]] name = "quote" -version = "1.0.20" +version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3bcdf212e9776fbcb2d23ab029360416bb1706b1aea2d1a5ba002727cbcab804" +checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179" dependencies = [ "proc-macro2", ] [[package]] name = "syn" -version = "1.0.98" +version = "1.0.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c50aef8a904de4c23c788f104b7dddc7d6f79c647c7c8ce4cc8f73eb0ca773dd" +checksum = "58dbef6ec655055e20b86b15a8cc6d439cca19b667537ac6a1369572d151ab13" dependencies = [ "proc-macro2", "quote", @@ -91,6 +91,6 @@ checksum = "4ee8fba06c1f4d0b396ef61a54530bb6b28f0dc61c38bc8bc5a5a48161e6282e" [[package]] name = "unicode-ident" -version = "1.0.1" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bd2fe26506023ed7b5e1e315add59d6f584c621d037f9368fea9cfb988f368c" +checksum = "c4f5b37a154999a8f3f98cc23a628d850e154479cd94decf3414696e12e31aaf" diff --git a/18_backtrace/kernel/src/exception.rs b/18_backtrace/kernel/src/exception.rs index f4af8144..7ea7cd80 100644 --- a/18_backtrace/kernel/src/exception.rs +++ b/18_backtrace/kernel/src/exception.rs @@ -21,7 +21,7 @@ pub use arch_exception::{current_privilege_level, handling_init}; /// Kernel privilege levels. #[allow(missing_docs)] -#[derive(PartialEq)] +#[derive(Eq, PartialEq)] pub enum PrivilegeLevel { User, Kernel, diff --git a/18_backtrace/kernel/src/memory/mmu/mapping_record.rs b/18_backtrace/kernel/src/memory/mmu/mapping_record.rs index 5bc32445..b893fee3 100644 --- a/18_backtrace/kernel/src/memory/mmu/mapping_record.rs +++ b/18_backtrace/kernel/src/memory/mmu/mapping_record.rs @@ -103,8 +103,7 @@ impl MappingRecord { ) -> Option<&mut MappingRecordEntry> { self.inner .iter_mut() - .filter(|x| x.is_some()) - .map(|x| x.as_mut().unwrap()) + .filter_map(|x| x.as_mut()) .filter(|x| x.attribute_fields.mem_attributes == MemAttributes::Device) .find(|x| { if x.phys_start_addr != phys_region.start_addr() { diff --git a/18_backtrace/kernel/src/memory/mmu/translation_table.rs b/18_backtrace/kernel/src/memory/mmu/translation_table.rs index 9d627f97..9301bb0c 100644 --- a/18_backtrace/kernel/src/memory/mmu/translation_table.rs +++ b/18_backtrace/kernel/src/memory/mmu/translation_table.rs @@ -97,7 +97,7 @@ mod tests { // This will occupy a lot of space on the stack. let mut tables = MinSizeTranslationTable::new_for_runtime(); - assert!(tables.init().is_ok()); + assert_eq!(tables.init(), Ok(())); let virt_end_exclusive_page_addr: PageAddress = PageAddress::MAX; let virt_start_page_addr: PageAddress = diff --git a/18_backtrace/kernel/src/memory/mmu/types.rs b/18_backtrace/kernel/src/memory/mmu/types.rs index 85c852b3..62f3926e 100644 --- a/18_backtrace/kernel/src/memory/mmu/types.rs +++ b/18_backtrace/kernel/src/memory/mmu/types.rs @@ -15,13 +15,13 @@ use core::{convert::From, iter::Step, num::NonZeroUsize, ops::Range}; //-------------------------------------------------------------------------------------------------- /// A wrapper type around [Address] that ensures page alignment. -#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)] +#[derive(Copy, Clone, Debug, Eq, PartialOrd, PartialEq)] pub struct PageAddress { inner: Address, } /// A type that describes a region of memory in quantities of pages. -#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)] +#[derive(Copy, Clone, Debug, Eq, PartialOrd, PartialEq)] pub struct MemoryRegion { start: PageAddress, end_exclusive: PageAddress, @@ -29,7 +29,7 @@ pub struct MemoryRegion { /// Architecture agnostic memory attributes. #[allow(missing_docs)] -#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)] +#[derive(Copy, Clone, Debug, Eq, PartialOrd, PartialEq)] pub enum MemAttributes { CacheableDRAM, Device, @@ -37,7 +37,7 @@ pub enum MemAttributes { /// Architecture agnostic access permissions. #[allow(missing_docs)] -#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)] +#[derive(Copy, Clone, Debug, Eq, PartialOrd, PartialEq)] pub enum AccessPermissions { ReadOnly, ReadWrite, @@ -45,7 +45,7 @@ pub enum AccessPermissions { /// Collection of memory attributes. #[allow(missing_docs)] -#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)] +#[derive(Copy, Clone, Debug, Eq, PartialOrd, PartialEq)] pub struct AttributeFields { pub mem_attributes: MemAttributes, pub acc_perms: AccessPermissions, diff --git a/18_backtrace/kernel/src/symbols.rs b/18_backtrace/kernel/src/symbols.rs index 22001389..7f439ce2 100644 --- a/18_backtrace/kernel/src/symbols.rs +++ b/18_backtrace/kernel/src/symbols.rs @@ -49,13 +49,9 @@ fn kernel_symbols_slice() -> &'static [Symbol] { /// Retrieve the symbol corresponding to a virtual address, if any. pub fn lookup_symbol(addr: Address) -> Option<&'static Symbol> { - for i in kernel_symbols_slice() { - if i.contains(addr.as_usize()) { - return Some(i); - } - } - - None + kernel_symbols_slice() + .iter() + .find(|&i| i.contains(addr.as_usize())) } //-------------------------------------------------------------------------------------------------- diff --git a/19_kernel_heap/Cargo.lock b/19_kernel_heap/Cargo.lock index 09f99f4a..1739c78b 100644 --- a/19_kernel_heap/Cargo.lock +++ b/19_kernel_heap/Cargo.lock @@ -24,9 +24,9 @@ dependencies = [ [[package]] name = "linked_list_allocator" -version = "0.10.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "222d00bf23b303e0c82c7a4d5f04dc90f33a58b26a3adb1a09c6fbcf56cbd2a9" +checksum = "636c3bc929db632724303109c88d5d559a2a60f62243bb041387f03fa081d94a" [[package]] name = "mingo" @@ -43,9 +43,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.40" +version = "1.0.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd96a1e8ed2596c337f8eae5f24924ec83f5ad5ab21ea8e455d3566c69fbcaf7" +checksum = "0a2ca2c61bc9f3d74d2886294ab7b9853abd9c1ad903a3ac7815c58989bb7bab" dependencies = [ "unicode-ident", ] @@ -58,18 +58,18 @@ checksum = "9ff023245bfcc73fb890e1f8d5383825b3131cc920020a5c487d6f113dfc428a" [[package]] name = "quote" -version = "1.0.20" +version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3bcdf212e9776fbcb2d23ab029360416bb1706b1aea2d1a5ba002727cbcab804" +checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179" dependencies = [ "proc-macro2", ] [[package]] name = "syn" -version = "1.0.98" +version = "1.0.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c50aef8a904de4c23c788f104b7dddc7d6f79c647c7c8ce4cc8f73eb0ca773dd" +checksum = "58dbef6ec655055e20b86b15a8cc6d439cca19b667537ac6a1369572d151ab13" dependencies = [ "proc-macro2", "quote", @@ -98,6 +98,6 @@ checksum = "4ee8fba06c1f4d0b396ef61a54530bb6b28f0dc61c38bc8bc5a5a48161e6282e" [[package]] name = "unicode-ident" -version = "1.0.1" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bd2fe26506023ed7b5e1e315add59d6f584c621d037f9368fea9cfb988f368c" +checksum = "c4f5b37a154999a8f3f98cc23a628d850e154479cd94decf3414696e12e31aaf" diff --git a/19_kernel_heap/README.md b/19_kernel_heap/README.md index 45f5f9e3..ecb3f8f7 100644 --- a/19_kernel_heap/README.md +++ b/19_kernel_heap/README.md @@ -1090,7 +1090,7 @@ diff -uNr 18_backtrace/kernel/src/memory/mmu/mapping_record.rs 19_kernel_heap/ke phys_start_addr: phys_region.start_addr(), virt_start_addr: virt_region.start_addr(), num_pages: phys_region.num_pages(), -@@ -56,55 +56,28 @@ +@@ -56,54 +56,28 @@ } } @@ -1146,12 +1146,11 @@ diff -uNr 18_backtrace/kernel/src/memory/mmu/mapping_record.rs 19_kernel_heap/ke ) -> Option<&mut MappingRecordEntry> { self.inner .iter_mut() -- .filter(|x| x.is_some()) -- .map(|x| x.as_mut().unwrap()) +- .filter_map(|x| x.as_mut()) .filter(|x| x.attribute_fields.mem_attributes == MemAttributes::Device) .find(|x| { if x.phys_start_addr != phys_region.start_addr() { -@@ -125,10 +98,8 @@ +@@ -124,10 +98,8 @@ virt_region: &MemoryRegion, phys_region: &MemoryRegion, attr: &AttributeFields, @@ -1164,7 +1163,7 @@ diff -uNr 18_backtrace/kernel/src/memory/mmu/mapping_record.rs 19_kernel_heap/ke name, virt_region, phys_region, -@@ -136,8 +107,6 @@ +@@ -135,8 +107,6 @@ )); self.sort(); @@ -1173,7 +1172,7 @@ diff -uNr 18_backtrace/kernel/src/memory/mmu/mapping_record.rs 19_kernel_heap/ke } pub fn print(&self) { -@@ -148,7 +117,7 @@ +@@ -147,7 +117,7 @@ ); info!(" -------------------------------------------------------------------------------------------------------------------------------------------"); @@ -1182,7 +1181,7 @@ diff -uNr 18_backtrace/kernel/src/memory/mmu/mapping_record.rs 19_kernel_heap/ke let size = i.num_pages * bsp::memory::mmu::KernelGranule::SIZE; let virt_start = i.virt_start_addr; let virt_end_inclusive = virt_start + (size - 1); -@@ -184,16 +153,14 @@ +@@ -183,16 +153,14 @@ attr, acc_p, xn, @@ -1203,7 +1202,7 @@ diff -uNr 18_backtrace/kernel/src/memory/mmu/mapping_record.rs 19_kernel_heap/ke } } -@@ -212,7 +179,7 @@ +@@ -211,7 +179,7 @@ virt_region: &MemoryRegion, phys_region: &MemoryRegion, attr: &AttributeFields, @@ -1212,7 +1211,7 @@ diff -uNr 18_backtrace/kernel/src/memory/mmu/mapping_record.rs 19_kernel_heap/ke KERNEL_MAPPING_RECORD.write(|mr| mr.add(name, virt_region, phys_region, attr)) } -@@ -225,9 +192,7 @@ +@@ -224,9 +192,7 @@ KERNEL_MAPPING_RECORD.write(|mr| { let dup = mr.find_duplicate(&phys_region)?; diff --git a/19_kernel_heap/kernel/src/exception.rs b/19_kernel_heap/kernel/src/exception.rs index f4af8144..7ea7cd80 100644 --- a/19_kernel_heap/kernel/src/exception.rs +++ b/19_kernel_heap/kernel/src/exception.rs @@ -21,7 +21,7 @@ pub use arch_exception::{current_privilege_level, handling_init}; /// Kernel privilege levels. #[allow(missing_docs)] -#[derive(PartialEq)] +#[derive(Eq, PartialEq)] pub enum PrivilegeLevel { User, Kernel, diff --git a/19_kernel_heap/kernel/src/memory/mmu/translation_table.rs b/19_kernel_heap/kernel/src/memory/mmu/translation_table.rs index 9d627f97..9301bb0c 100644 --- a/19_kernel_heap/kernel/src/memory/mmu/translation_table.rs +++ b/19_kernel_heap/kernel/src/memory/mmu/translation_table.rs @@ -97,7 +97,7 @@ mod tests { // This will occupy a lot of space on the stack. let mut tables = MinSizeTranslationTable::new_for_runtime(); - assert!(tables.init().is_ok()); + assert_eq!(tables.init(), Ok(())); let virt_end_exclusive_page_addr: PageAddress = PageAddress::MAX; let virt_start_page_addr: PageAddress = diff --git a/19_kernel_heap/kernel/src/memory/mmu/types.rs b/19_kernel_heap/kernel/src/memory/mmu/types.rs index 85c852b3..62f3926e 100644 --- a/19_kernel_heap/kernel/src/memory/mmu/types.rs +++ b/19_kernel_heap/kernel/src/memory/mmu/types.rs @@ -15,13 +15,13 @@ use core::{convert::From, iter::Step, num::NonZeroUsize, ops::Range}; //-------------------------------------------------------------------------------------------------- /// A wrapper type around [Address] that ensures page alignment. -#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)] +#[derive(Copy, Clone, Debug, Eq, PartialOrd, PartialEq)] pub struct PageAddress { inner: Address, } /// A type that describes a region of memory in quantities of pages. -#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)] +#[derive(Copy, Clone, Debug, Eq, PartialOrd, PartialEq)] pub struct MemoryRegion { start: PageAddress, end_exclusive: PageAddress, @@ -29,7 +29,7 @@ pub struct MemoryRegion { /// Architecture agnostic memory attributes. #[allow(missing_docs)] -#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)] +#[derive(Copy, Clone, Debug, Eq, PartialOrd, PartialEq)] pub enum MemAttributes { CacheableDRAM, Device, @@ -37,7 +37,7 @@ pub enum MemAttributes { /// Architecture agnostic access permissions. #[allow(missing_docs)] -#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)] +#[derive(Copy, Clone, Debug, Eq, PartialOrd, PartialEq)] pub enum AccessPermissions { ReadOnly, ReadWrite, @@ -45,7 +45,7 @@ pub enum AccessPermissions { /// Collection of memory attributes. #[allow(missing_docs)] -#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)] +#[derive(Copy, Clone, Debug, Eq, PartialOrd, PartialEq)] pub struct AttributeFields { pub mem_attributes: MemAttributes, pub acc_perms: AccessPermissions, diff --git a/19_kernel_heap/kernel/src/symbols.rs b/19_kernel_heap/kernel/src/symbols.rs index 22001389..7f439ce2 100644 --- a/19_kernel_heap/kernel/src/symbols.rs +++ b/19_kernel_heap/kernel/src/symbols.rs @@ -49,13 +49,9 @@ fn kernel_symbols_slice() -> &'static [Symbol] { /// Retrieve the symbol corresponding to a virtual address, if any. pub fn lookup_symbol(addr: Address) -> Option<&'static Symbol> { - for i in kernel_symbols_slice() { - if i.contains(addr.as_usize()) { - return Some(i); - } - } - - None + kernel_symbols_slice() + .iter() + .find(|&i| i.contains(addr.as_usize())) } //-------------------------------------------------------------------------------------------------- diff --git a/X1_JTAG_boot/jtag_boot_rpi3.img b/X1_JTAG_boot/jtag_boot_rpi3.img index 4f2c13b0dc1a7ab85bbd5dcc18f7810c00c8b275..0c43ac469d8e20830ad0043edcbda3c99edc87e8 100755 GIT binary patch delta 2116 zcmah~YfKbZ6h1Sv3p;?aycZVOUDwJEf;<)ww73gv!$W*@)mCj9AjVdrZ4pdN+FF+Q zLr@dBy%?*cY1AKeR{&h;7br4Xen?4Dn@kBYX$4g zVXpCK>tNpv=~Dk=Nq6V5_4d=p3Qy*kk!dr8W568_aE!lhYWb+^B0s65b!Bj1RYEZn zrvvDnHoL=km(VVKK5MHSIHy0t*@K+LAHt0nl3h&FM5ipT3vtQ*Mg}I^+3usg?7o3^ zem%=IvdqA>*w0zMYcCiB9jy2^-7(k0d_xE49$=gU)$unNT9}Z@cCS)BGFNG5qNA$0 zj3{B`ZUSS_J|qTZ`B8uaA{?tA(n3ZIc|esPL%FmE)6UV0%6-QjS*?obrlG_Pr|Td2 zu!4Y+-53XciDUiaoWWl+C8t@f)gl7ia~#pKNs9zEB3Y>D<#{}W`FZi63l_H zVYk1p9_b*4jD@5>rDf^QP0NRy=wzD3_G1*Ri$Sd*-l(rEB%vG-e|KTx($ZTz?mAjz zGId}Wb^Mj157GT83`bFT;ABaCf{rMm1zb8Y9(nf{GvfB|y1fsX`GkKZ);xiTHN+in zd$5od6&+#s>Aw2rA~NCPM5WyvQ}2u_sCB!*sDvIk2t!+uA1ctR2xGWJvNI$jXpa&@ z_Goe3!;sw=yY#nQBH3B8MW**m*1Z3R&4=YdK#MGH7%m_-&gZReDj?OcBXjJ? z^il}pm9yZECLceQ4+8^(N-#~$V7!T4CjktO<7vaK)KHOiHG+}DhEuxVFcw93r7TFm zTtk?r6dk2@z*sdslaiVuy1^)8vjy#p7{uNU+BtC>{WYaF{RJicbCfPg&38Ok#wD|5 zOnR=2=u0W%!PG4FuPJ&a)wFpwy^B+kev>W$xq&z-abu3pmb^zdGW8LJr{6S+PgW<0 z>J*=^sb~QxX~g_wSxytM0Q~vr3Z)AiS{LxNGih;033l3{c`@dGw7eC|{KN&}S}ZT` zaEm8DIoTImSS?6glHY)34K4&Ruos3VoUHH#-bYV8az~7)ycdBEUJP`^icJ7tOEnNy z5Dj=(62NbD(C#usK$sN7V=l?Yi6oX_d(gGXi7OH9iBqgN;Zac_;~a-i4krfI0z%B9 zOebE$1Olfb^Vp>absqPgtC(ya9)PhBv+X2QdkoXrIpK z-FnX*=5zJ#p}Lf0C$Gm5K!)WI41J*BtO(&VFMkAvwngZHYw20cMjwli;_^Y{bZd0A zXQg#bLt#;ob$yk09e_?3k=bR>Z8GPG+ypf07uX+S@i4w6?Xp zzjIMryJ9b(-HOwUD^Bz@KiiyO%#LW_Z%mq8+Y-o9zT7!m3zUH=5qaz^#bZa!e?dtkeqw(2NSFc7h==Lkx qm35L{wwa8rTtwfeo%DK!Nsvqt<|FOAZi~;H+7BGe|$;-T% zdGF24Z)SF5&EGGJ6lTkIV)J;#(*t%oyPj0j?q+jqR&7lURjSN`rrMeS9dD@V6>4h= z0Gv6ta8P>DzNTzhZq>ZJ;>ui<^KiA6fIYbc>RyL%aDI7KRk;(Y5>+fnF66>3#ALxa zjh|Xvyfy=|f(5`-AaCC!ptspjlee~0u zcLnQ_r@$5q3CaQ1J-wM6WA9IYgY=J9&NxX5Ehbq}MN5=>1)DskbEiD^=1i|3t=2Ol zhuKwvZHT!VNzpe{Xa#dS0r z*!F_Oq1ws&P8IpH-5+b(jz2JlHOQ~(u{fjGFs=@i{}f@KilDaRzUSazQ0)|?mfXF4 zs_2MbU5`}@eYpF21EegI8&Abvg|R(&&I52c-YigzCnAyXE?#X8L0e3-B^?5duY?rB z7P=G*Srv)Sps`Sn5<5?5a-X0i5kH>1dS1k~APTliM8~($iFT9nH3vm5qZ1;xi%M(_ z(70cqS}0qI?aN^Ong}}9ZB1CC_p)?gEX1k@A=QH|u`o}Gh1lDLcHxyYOS=j~_0%VZ zgH3WheIT7FjEe6+iOKLH0m!Mx(i%=shAel<$^-($8)jUzMz^LMPn#+T&mov7LD(Eqg5NtNgoXV%`Z6 zs5&i6@1yP&ES>MlmzIG|!&Z*_i4w;Ni~B|8CnmXCiV)BJZ+y}hupZgPM@=&FKK>mW za?KBn1bn$}j_)SlQo0$j{HWVZ;|?s~OVQnJD96zk;>*stN`xF8oaHyc`DM}o=P=OA z22ecVTPQ+EI0)5?^qE(2JjZe2G_f3qL|WKlhg2-kw%Y}HoW0=iRgYX;A}A7eXC5YS zBj7!zn*n17-3Yij6Yw{V67#1RUzlBXczhFC(2olMFi|pq%dUoYC~>nzTdlgRmGx3-nEUv4uGxZjD5;Ef}ztkL+>sAuYCm@ zpY<~i0kBn`RU7%yNNMH-S91EnlaZ%hntEY=#tdtX7pLBR#E@|ublPahh>}h{#iM_D z9wp3HS~#=9@P&UbomQ~AQjfdG(B>H0LFCw*u-@xsTS^y8cZ!f1_bVAKX|M1)GLiN7 zZCJRaulMP#3;O!`!!1T$Q~z8W>H@gfXKwdwegL)@CyI0lU^((qV-M_icR5+Wii+zi z&lu-!huDvXoqOPv@UWrcv(lZefiDxdpV8vy*@M19TUg9!A_iw$W)(`8Tp1-4WVk## Q!;cu(YYq7l`_eb}U+(9V@Bjb+ diff --git a/X1_JTAG_boot/jtag_boot_rpi4.img b/X1_JTAG_boot/jtag_boot_rpi4.img index ee1f6fc4c545edda38bc7b5ccb60381b0ebb4ad2..83c4176a7b375931bf248cd0bf1b840093ffbed2 100755 GIT binary patch delta 1644 zcmah}Z%k8H6hHU9*7cQ&4_f(G7_WdU#Ufw@Bu*({rc51O!7P4Qa4|aZ4|A|(Cd<|~ zCW1;9UM>r9#sqW;zGh37RI;%T3!7QQEm?vLlO@JIFfI@L6E%ET!{F`Q*VhkQmh2>_ z_ug|(&pE%}Iqk^H>bAjr;R%Sv5uO~sVC}MOt@FxrjpeP} z*18-3m+)dVY!{>93{+nzJFpOd1_$0Z?sNqF{xt!*m;6aXoXcKng&~&J^F^YY%ORZl zIX%mF9=-w7Hh`}LR9jP}?2AdV+D8<%6l84-lyZoMwX4vu-2y`rNWV_a0Q{B=%(m2>FS|vde>WKAAO9(FEc`>4dVN z>rXWvWZ!6mtZpRAVhb4lQS_^45VY5-u=w(Ox-kSFUC4Gv8voLV8GHt9j)%C)bMblJ z7T>j^=SotuLI4J@AXT1`GMQf+Odf>dJAlG6O;$rSA<;0SNky1*sO--CI?qk7Zi6IV z2SKWrMXUn^#@Y8q+Cf~>^vO2Gk3G=;GrlqO^W=>ymx)Y&bsf zO-}~qJ?^PD^7#Gqh|5d-^b=P}gcM-9t3;l^0dn7}J{%-a+lj?=UC(7jqk+`&Hg5*e z!$-phFord)V*C+A!|n`uTJ$rP>6H&5x%!5vEVX4R43H4}prH$3OFFL)nH6I74Zk$+mK2M(cwKm3PJi7|+`7N0zjRpy(01qD3;4g8z8TRM;%D>eO{jDdAaaEXqH||(L7(4qWQ^+Ni)VTV|)kW+2C^Sm1KoA zIB~%e4If+Y3RGBO!iF{h;$h(dOr$q4HIHEODQ`oZnf8$TpZ<0#=iL=q zmR+INHm_eg(baueq9^m+S=;kdp*d!Xc6u?tn4G2)`E8zb8l0RV?Pl6^xe@9sxLLWB zoyySLbExW6PgnPQn|gX#_*6m4o`xx+%}Os9m2yuD=nq9Z=%BkM;+GD+bK?Dz-ICpo zGlu`G*kN{1$qJyd0#iw#aX_H&3aHbxT Vc}^9j-XZgxG|$sTHo9E2;cr-I;{X5v delta 1666 zcmah}Z){Ul6hHUfmh^Q4-`cWKYS}9b**dyTHm#i~E6ijYNSKwW#KaEfAI6_48!Cxl zyO2mGeCXpYAwo!hN`#J&+1oV1{5GE;p3gpEt0UV>0R|R*v7AAPGD;KIj4_yS0DK|ha%>DM!M=c^ z9V4n%0g65hY89m7`Z;LGQ5cXx{*nKuqxATd(Y8&_~?#&xP znyDC3XAEObr=SF<8We3UQD>XLw10zk?I;4Pw5!~|9g35z~CB%E{)|np!`~a0fPz?i|ZkWdK%=YB4I2baFJ(` z+d-PcwrcGwhAe*r5z;9-f^#S1&gpFl{S?_;7)tO>~nXyBaFo( zkQdpcdrRb#BZhPfq1?`ba;p|hID3CLq}#PbZ9Ou6#yR?aJaghwPZ1WhHxM=BglgFH zo=Q@~-t(+Z_W3Z}IigIDfpTooI29xCSOSw7hEc|ordq6#-P8YUl!Zv`}ymX%YLP4Zk$f$trFAq=;*r z1((+*qYGQEir5Pkd*Q7ReRWv+JtX%BgmWMF2UwZB5)N+73dXu0yNGfz% zZ-$(HgO~)2?=vKQn5ep2Fm?4B*9B`9?;Gsq^3};d49SVD+Kim(!%Iw)qZ*{yB;;oJ zTdXWL@AMEzkS*xX8481yrjZvz|k%YOs8srR`6 diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 9667a009..0a525545 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,4 +1,4 @@ [toolchain] -channel = "nightly-2022-04-10" +channel = "nightly-2022-08-01" components = ["rust-src", "llvm-tools-preview", "rustfmt"] targets = ["aarch64-unknown-none-softfloat"] From 8ab5417c776ddf8bbab3f6d01f4b75f1864e2ed2 Mon Sep 17 00:00:00 2001 From: Andre Richter Date: Mon, 19 Sep 2022 08:45:36 +0200 Subject: [PATCH 49/75] Bump dependencies --- 02_runtime_init/Cargo.lock | 4 ++-- 03_hacky_hello_world/Cargo.lock | 4 ++-- 04_safe_globals/Cargo.lock | 4 ++-- 05_drivers_gpio_uart/Cargo.lock | 4 ++-- 06_uart_chainloader/Cargo.lock | 4 ++-- 06_uart_chainloader/demo_payload_rpi3.img | Bin 7640 -> 7648 bytes 06_uart_chainloader/demo_payload_rpi4.img | Bin 7584 -> 7576 bytes 07_timestamps/Cargo.lock | 4 ++-- 08_hw_debug_JTAG/Cargo.lock | 4 ++-- 09_privilege_level/Cargo.lock | 4 ++-- .../Cargo.lock | 4 ++-- 11_exceptions_part1_groundwork/Cargo.lock | 4 ++-- 12_integrated_testing/Cargo.lock | 12 ++++++------ .../Cargo.lock | 12 ++++++------ 14_virtual_mem_part2_mmio_remap/Cargo.lock | 12 ++++++------ .../Cargo.lock | 12 ++++++------ .../Cargo.lock | 12 ++++++------ 17_kernel_symbols/Cargo.lock | 12 ++++++------ 18_backtrace/Cargo.lock | 12 ++++++------ 19_kernel_heap/Cargo.lock | 16 ++++++++-------- X1_JTAG_boot/Cargo.lock | 4 ++-- X1_JTAG_boot/jtag_boot_rpi3.img | Bin 8680 -> 8712 bytes X1_JTAG_boot/jtag_boot_rpi4.img | Bin 7648 -> 7616 bytes 23 files changed, 72 insertions(+), 72 deletions(-) diff --git a/02_runtime_init/Cargo.lock b/02_runtime_init/Cargo.lock index d164c36b..bae18da0 100644 --- a/02_runtime_init/Cargo.lock +++ b/02_runtime_init/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "cortex-a" -version = "7.4.0" +version = "7.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f75db6964ed6748e88ff46f9aa209249a0aefe6b06d4b9e9ab820c867586d51a" +checksum = "bdecfbb28672ad3664e71ae05a398a52df430d86d660691501b28968cc4467e6" dependencies = [ "tock-registers", ] diff --git a/03_hacky_hello_world/Cargo.lock b/03_hacky_hello_world/Cargo.lock index 0609efb6..baa9f9c4 100644 --- a/03_hacky_hello_world/Cargo.lock +++ b/03_hacky_hello_world/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "cortex-a" -version = "7.4.0" +version = "7.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f75db6964ed6748e88ff46f9aa209249a0aefe6b06d4b9e9ab820c867586d51a" +checksum = "bdecfbb28672ad3664e71ae05a398a52df430d86d660691501b28968cc4467e6" dependencies = [ "tock-registers", ] diff --git a/04_safe_globals/Cargo.lock b/04_safe_globals/Cargo.lock index d5be2861..72bdf630 100644 --- a/04_safe_globals/Cargo.lock +++ b/04_safe_globals/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "cortex-a" -version = "7.4.0" +version = "7.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f75db6964ed6748e88ff46f9aa209249a0aefe6b06d4b9e9ab820c867586d51a" +checksum = "bdecfbb28672ad3664e71ae05a398a52df430d86d660691501b28968cc4467e6" dependencies = [ "tock-registers", ] diff --git a/05_drivers_gpio_uart/Cargo.lock b/05_drivers_gpio_uart/Cargo.lock index 9958f13c..87686e39 100644 --- a/05_drivers_gpio_uart/Cargo.lock +++ b/05_drivers_gpio_uart/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "cortex-a" -version = "7.4.0" +version = "7.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f75db6964ed6748e88ff46f9aa209249a0aefe6b06d4b9e9ab820c867586d51a" +checksum = "bdecfbb28672ad3664e71ae05a398a52df430d86d660691501b28968cc4467e6" dependencies = [ "tock-registers", ] diff --git a/06_uart_chainloader/Cargo.lock b/06_uart_chainloader/Cargo.lock index e0cea178..0936e7c6 100644 --- a/06_uart_chainloader/Cargo.lock +++ b/06_uart_chainloader/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "cortex-a" -version = "7.4.0" +version = "7.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f75db6964ed6748e88ff46f9aa209249a0aefe6b06d4b9e9ab820c867586d51a" +checksum = "bdecfbb28672ad3664e71ae05a398a52df430d86d660691501b28968cc4467e6" dependencies = [ "tock-registers", ] diff --git a/06_uart_chainloader/demo_payload_rpi3.img b/06_uart_chainloader/demo_payload_rpi3.img index bcb46b6137cabbe4e9a0e4e1bb1bda93b04267d1..2016c14e26bd5edce571ca2424a5cfa9b916d826 100755 GIT binary patch delta 1298 zcmZ8gZ)jUp6hH61rcJUrUh}u+&w9JGP1A&!rHkoW*lG$LlZvAV3PYDp$JV+eqf^9B zY3T=XiuCRZE$F1$582CxGHS<)Ut0XK;TJ19$3%D)KO}{M=%-kg=eh4)=br7;f1{1V!L&=tc0Z$jm`B?{T)fuBS32v(E4C@qP7A@x0KbUQjugSwOX-# zwm-HWr=3Lk;mR1O^~kzbH;mtE3eecrAl2iNwlfOmyL5uhxQYku01NN6%uYDA#~S^% zk@ab>XQ1B(>yAHXC+yqo6JL&{{C&|c4P(*XJ)$`ixtOlFtGt1orjT-yhpDbUOc^fv3gB*BVU0He^JCAK9>F*VX_AX~(IJMe5(E5337%Tg< zYfWP@50E*7Gz`P=>+>?5$3g_i_h8CMW4>wltvdj3>=#9<>WaO(tvIR-W5nCIsSQQm zY7RpKjRhcCy0K?0f&^=PPRl1j{T1Lt9boM$7U{w}FT~&Ora)ByJiK}PGjSGmN7Z(^ zgVWU8S~ZT?9%8S!eLigvRHH0w^@ya^6^Yg(iuT1GyW)=be43_fxpvCAyYa*}4^s(s z?L{yX)P_L4e26`Crvt~3HgQ9SSGyt?1k2m1}A=RfX#T*{s-vJw?dY8@VNTs)9fp6 zSpMb_d+3cwyR7Lw{>1KBg#N_2mXV1;dyiHC` zkpWf+#M?w-wiHNpj0CN){lclDw&7tU9G}jOK1WWRI{ADwK`u@e&yfUqwRG{#LXkL~ z02f4LTtt2(Y%3qYim-7|rrZ>^EbM~dh(pA3KL>)3S>s|&LDtUTL3uF5`h$@&mduNg z76Euo*ngM!PfElTri$lFsFwwf6XTLfW|Aq?cmC%;efVXPE0x~BFj6WGk#EI2A4)3^ zEQHv1!QLSdGxl&F3Na-~`h?%aqCY9@e<-tbsMnPjZu~n;!K~Av-UCa*ZP919!-xI? DwMb9? delta 1277 zcmZ8gO>7fK6n?vFC${;~%D<_9noXU=Z0tH|u;PoFIiw&tNh;y06 zs`KVfbx9@diuCAM0c112qM4TU+>n5%4_+gBQqb0iz>a@kpfldm5la#uGzOp!0M`I= zq;u1{4gxH(68c*pZvuR!11$Z5dj~EBl!q*K?@f>;0KW_KTtbF^=TFE{vW|`P))tL1 zMi0!iP&8e3=Ni8*hVMVB!GC zmqa=h=nvm)Sl1OFWLdZSLZ#@s@v1$*MHoyLd`RPt23|tDhV}Rav{%M`>kPx zXvUXGEMrd=^rQ-^Ee3vK>%Ee?z;JA0S*@CDE<>;S60WE%e)2xO>q`&ssayD=IW9cT>Dv`dxa=01Z$tg1KPP!F|cy%7ZN4E_Vd!jFjZ4r7b8lOcd zA8DpKIN=cY@$R;r;+^r$Y@41ejhFFM;XEhD`_kETAD+MdAAb6kca%c8{2rz$<>`wqeyzW8J$x z;IKVDoemG>^qMpAsdZMJ}{!#wDT~0np0VKo7(8KzSZ|ei9aT zgs%xnEL^jfL^8DSPV;XfP-|_q*kA!AIgD32qfc_O}l;3rs+H8Yz`nbgc+u3 z$_DyALk1PpUzpl$ffU7tjBW^G@hijuGS$mFY`2yv*lz5kp^DZFK&Q60ZO#ILMOHzs z7o@uYR}6r~FOhQ(o*A!`fiE5aNdRz(m?)AsJ?jj%Y@1R!)S$B=v5;sF{l@8c^kB6( zs+Dbe(;3^J28m&Vn;3f>baoD-uY8>7PNbT$b!zJ}RGGirMH4RnGYUu>^Pm~{VK>@Q z>{xX|ibaUef>a`Shau1(+_Kf!%H8w>m%rde)jL*38Z%ZTNUaMN?`k(l5xjZE@ZHm> zjWwGEyZ)fiSYtTU2GX_w+6Jl_xHHu#a?CYDs`g@>P-QoD5@)q}5i7f7DW9D*rOhGG zx8^}>+QNpIKu;$Py8XLckIHGG{cd^J6)eIKT*VVORQj%af20+p`*)BGKPFgxXwFWH z(Dhbhrg|Sq>qF`7pg+6)hn~P}lwpx&jLbDcSG~P(ht=NWZS84hidN3=4{6jBASHU# zlXaAiR6ntU7BA5+Jc;(JY`)g(nSp=f8o~Lp$7=}w;-C1jGcC&-)M(4KEcx*M|F^Ew z{wM#SbKV$T^CrnTN_;X+dNZ*#*@`pxKE2zr=e*W_j@zqVk*+Jr!r|;I>I;3nuZH64 z*y#9(8dpzEjJldq5D^XJvR zQS|`8^Z8JIBCn2344)nye^Wi3AANr$e^5QB*1Pra#Orj}=O_2*1z-Ch*44&&8#t_R zyI#lRx@VAm0%K3`I6KcvCQ^wco+lN$<$J32BMwU(-lx#05+qBsUy=739Bky^-`sxG dEB#mrwzl#4;xATP$nm2Rbo6nzho0XZ`VZ?Ng6aSO delta 1356 zcmYjQU1%Fe5T4aZMp8_;ShB9wPqem-EXlU2;!6HeLS;Km38ZZ-a1;7a+fCfY!Lbv$ zZTbVXOdb;G4>`8frb(&659#TlP#hQZmiEbMF~pFjc_`)LP>@R>40eK*A6;j4E0Tp} zZ)U#vzL}l9`Se2i(g?Zs)94lTUvykW$RK! z`hk$nrK`3ZcJlVp+1+=f=xj_4Qt1!p0gyLBMQy_{HcJwy(Y0<>ZzI~j15l069$>kK z>6u>+mSeU|@pEfFd#cgh8M8srjy?wzvW|bCcwHL44PtRtngN-Re3tulDOk9RyM{3& z%UUH3WrSY>no{M*#vBk>=6MT)Aa5JSoDQ(Oj%O3V*A(b27Z0vQ@zGj=CVp5%v_wH?Xr(D`*e?v{czj``BlV!I@@M zy=P{8iW%2sNN!0c@5(-qqc{%E@N=J8voT}S9?aBL8Tu&5k0emHQBB8_tDZuRh24;> zj?o2WU2+w!JTm5X&SPa4OyzSQ8S>6BXb%@bbw0#~xIj-Y3wwg~{-@;(vO$khe+!4A zOYXu+yjb?Wrz7eG`Tjj5!_5VIP%v+Yu9J0{@_i(&UCN;@_M0czr(ib9aAX9LBX!VK zYcJAew#P^DY+Fqpu4v}?DlDdi$SQkX8E~u~EPr7GwSAR+tHkYpBORYIlU60uHKXa0y>P8!C;*xAH2NJT&j8Ji2448JpYo2*w9}_m~@V42iOzfC9F}f+-^@3c+lZX2UUZbxb zIrK(rJDnJx9HZIM=`-()<#Hd>Bjfa?S8}5Ix`0E3fm%V1Um!ahI!$}Ke4*d-5&_=x+&b)5ZmQT syxC5VPfdJqdXhSwPN?+gl{S%toei}94|TzPZU6uP diff --git a/07_timestamps/Cargo.lock b/07_timestamps/Cargo.lock index fcc1ddd2..64174c53 100644 --- a/07_timestamps/Cargo.lock +++ b/07_timestamps/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "cortex-a" -version = "7.4.0" +version = "7.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f75db6964ed6748e88ff46f9aa209249a0aefe6b06d4b9e9ab820c867586d51a" +checksum = "bdecfbb28672ad3664e71ae05a398a52df430d86d660691501b28968cc4467e6" dependencies = [ "tock-registers", ] diff --git a/08_hw_debug_JTAG/Cargo.lock b/08_hw_debug_JTAG/Cargo.lock index 7c8e75a8..6e628b86 100644 --- a/08_hw_debug_JTAG/Cargo.lock +++ b/08_hw_debug_JTAG/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "cortex-a" -version = "7.4.0" +version = "7.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f75db6964ed6748e88ff46f9aa209249a0aefe6b06d4b9e9ab820c867586d51a" +checksum = "bdecfbb28672ad3664e71ae05a398a52df430d86d660691501b28968cc4467e6" dependencies = [ "tock-registers", ] diff --git a/09_privilege_level/Cargo.lock b/09_privilege_level/Cargo.lock index 0f3104f5..5dc791a2 100644 --- a/09_privilege_level/Cargo.lock +++ b/09_privilege_level/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "cortex-a" -version = "7.4.0" +version = "7.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f75db6964ed6748e88ff46f9aa209249a0aefe6b06d4b9e9ab820c867586d51a" +checksum = "bdecfbb28672ad3664e71ae05a398a52df430d86d660691501b28968cc4467e6" dependencies = [ "tock-registers", ] diff --git a/10_virtual_mem_part1_identity_mapping/Cargo.lock b/10_virtual_mem_part1_identity_mapping/Cargo.lock index 544f7715..1115edab 100644 --- a/10_virtual_mem_part1_identity_mapping/Cargo.lock +++ b/10_virtual_mem_part1_identity_mapping/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "cortex-a" -version = "7.4.0" +version = "7.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f75db6964ed6748e88ff46f9aa209249a0aefe6b06d4b9e9ab820c867586d51a" +checksum = "bdecfbb28672ad3664e71ae05a398a52df430d86d660691501b28968cc4467e6" dependencies = [ "tock-registers", ] diff --git a/11_exceptions_part1_groundwork/Cargo.lock b/11_exceptions_part1_groundwork/Cargo.lock index 285a75b0..f1d4af57 100644 --- a/11_exceptions_part1_groundwork/Cargo.lock +++ b/11_exceptions_part1_groundwork/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "cortex-a" -version = "7.4.0" +version = "7.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f75db6964ed6748e88ff46f9aa209249a0aefe6b06d4b9e9ab820c867586d51a" +checksum = "bdecfbb28672ad3664e71ae05a398a52df430d86d660691501b28968cc4467e6" dependencies = [ "tock-registers", ] diff --git a/12_integrated_testing/Cargo.lock b/12_integrated_testing/Cargo.lock index a4e82af3..f188bfe0 100644 --- a/12_integrated_testing/Cargo.lock +++ b/12_integrated_testing/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "cortex-a" -version = "7.4.0" +version = "7.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f75db6964ed6748e88ff46f9aa209249a0aefe6b06d4b9e9ab820c867586d51a" +checksum = "bdecfbb28672ad3664e71ae05a398a52df430d86d660691501b28968cc4467e6" dependencies = [ "tock-registers", ] @@ -48,9 +48,9 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.99" +version = "1.0.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58dbef6ec655055e20b86b15a8cc6d439cca19b667537ac6a1369572d151ab13" +checksum = "52205623b1b0f064a4e71182c3b18ae902267282930c6d5462c91b859668426e" dependencies = [ "proc-macro2", "quote", @@ -79,6 +79,6 @@ checksum = "4ee8fba06c1f4d0b396ef61a54530bb6b28f0dc61c38bc8bc5a5a48161e6282e" [[package]] name = "unicode-ident" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4f5b37a154999a8f3f98cc23a628d850e154479cd94decf3414696e12e31aaf" +checksum = "dcc811dc4066ac62f84f11307873c4850cb653bfa9b1719cee2bd2204a4bc5dd" diff --git a/13_exceptions_part2_peripheral_IRQs/Cargo.lock b/13_exceptions_part2_peripheral_IRQs/Cargo.lock index 12cd705a..e5a8e81c 100644 --- a/13_exceptions_part2_peripheral_IRQs/Cargo.lock +++ b/13_exceptions_part2_peripheral_IRQs/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "cortex-a" -version = "7.4.0" +version = "7.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f75db6964ed6748e88ff46f9aa209249a0aefe6b06d4b9e9ab820c867586d51a" +checksum = "bdecfbb28672ad3664e71ae05a398a52df430d86d660691501b28968cc4467e6" dependencies = [ "tock-registers", ] @@ -48,9 +48,9 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.99" +version = "1.0.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58dbef6ec655055e20b86b15a8cc6d439cca19b667537ac6a1369572d151ab13" +checksum = "52205623b1b0f064a4e71182c3b18ae902267282930c6d5462c91b859668426e" dependencies = [ "proc-macro2", "quote", @@ -79,6 +79,6 @@ checksum = "4ee8fba06c1f4d0b396ef61a54530bb6b28f0dc61c38bc8bc5a5a48161e6282e" [[package]] name = "unicode-ident" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4f5b37a154999a8f3f98cc23a628d850e154479cd94decf3414696e12e31aaf" +checksum = "dcc811dc4066ac62f84f11307873c4850cb653bfa9b1719cee2bd2204a4bc5dd" diff --git a/14_virtual_mem_part2_mmio_remap/Cargo.lock b/14_virtual_mem_part2_mmio_remap/Cargo.lock index c4b4f779..163a6526 100644 --- a/14_virtual_mem_part2_mmio_remap/Cargo.lock +++ b/14_virtual_mem_part2_mmio_remap/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "cortex-a" -version = "7.4.0" +version = "7.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f75db6964ed6748e88ff46f9aa209249a0aefe6b06d4b9e9ab820c867586d51a" +checksum = "bdecfbb28672ad3664e71ae05a398a52df430d86d660691501b28968cc4467e6" dependencies = [ "tock-registers", ] @@ -48,9 +48,9 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.99" +version = "1.0.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58dbef6ec655055e20b86b15a8cc6d439cca19b667537ac6a1369572d151ab13" +checksum = "52205623b1b0f064a4e71182c3b18ae902267282930c6d5462c91b859668426e" dependencies = [ "proc-macro2", "quote", @@ -79,6 +79,6 @@ checksum = "4ee8fba06c1f4d0b396ef61a54530bb6b28f0dc61c38bc8bc5a5a48161e6282e" [[package]] name = "unicode-ident" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4f5b37a154999a8f3f98cc23a628d850e154479cd94decf3414696e12e31aaf" +checksum = "dcc811dc4066ac62f84f11307873c4850cb653bfa9b1719cee2bd2204a4bc5dd" diff --git a/15_virtual_mem_part3_precomputed_tables/Cargo.lock b/15_virtual_mem_part3_precomputed_tables/Cargo.lock index 72cc4866..6cac9dcb 100644 --- a/15_virtual_mem_part3_precomputed_tables/Cargo.lock +++ b/15_virtual_mem_part3_precomputed_tables/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "cortex-a" -version = "7.4.0" +version = "7.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f75db6964ed6748e88ff46f9aa209249a0aefe6b06d4b9e9ab820c867586d51a" +checksum = "bdecfbb28672ad3664e71ae05a398a52df430d86d660691501b28968cc4467e6" dependencies = [ "tock-registers", ] @@ -48,9 +48,9 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.99" +version = "1.0.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58dbef6ec655055e20b86b15a8cc6d439cca19b667537ac6a1369572d151ab13" +checksum = "52205623b1b0f064a4e71182c3b18ae902267282930c6d5462c91b859668426e" dependencies = [ "proc-macro2", "quote", @@ -79,6 +79,6 @@ checksum = "4ee8fba06c1f4d0b396ef61a54530bb6b28f0dc61c38bc8bc5a5a48161e6282e" [[package]] name = "unicode-ident" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4f5b37a154999a8f3f98cc23a628d850e154479cd94decf3414696e12e31aaf" +checksum = "dcc811dc4066ac62f84f11307873c4850cb653bfa9b1719cee2bd2204a4bc5dd" diff --git a/16_virtual_mem_part4_higher_half_kernel/Cargo.lock b/16_virtual_mem_part4_higher_half_kernel/Cargo.lock index ac4f39a2..a529e673 100644 --- a/16_virtual_mem_part4_higher_half_kernel/Cargo.lock +++ b/16_virtual_mem_part4_higher_half_kernel/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "cortex-a" -version = "7.4.0" +version = "7.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f75db6964ed6748e88ff46f9aa209249a0aefe6b06d4b9e9ab820c867586d51a" +checksum = "bdecfbb28672ad3664e71ae05a398a52df430d86d660691501b28968cc4467e6" dependencies = [ "tock-registers", ] @@ -48,9 +48,9 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.99" +version = "1.0.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58dbef6ec655055e20b86b15a8cc6d439cca19b667537ac6a1369572d151ab13" +checksum = "52205623b1b0f064a4e71182c3b18ae902267282930c6d5462c91b859668426e" dependencies = [ "proc-macro2", "quote", @@ -79,6 +79,6 @@ checksum = "4ee8fba06c1f4d0b396ef61a54530bb6b28f0dc61c38bc8bc5a5a48161e6282e" [[package]] name = "unicode-ident" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4f5b37a154999a8f3f98cc23a628d850e154479cd94decf3414696e12e31aaf" +checksum = "dcc811dc4066ac62f84f11307873c4850cb653bfa9b1719cee2bd2204a4bc5dd" diff --git a/17_kernel_symbols/Cargo.lock b/17_kernel_symbols/Cargo.lock index cd3793ed..d52e3863 100644 --- a/17_kernel_symbols/Cargo.lock +++ b/17_kernel_symbols/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "cortex-a" -version = "7.4.0" +version = "7.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f75db6964ed6748e88ff46f9aa209249a0aefe6b06d4b9e9ab820c867586d51a" +checksum = "bdecfbb28672ad3664e71ae05a398a52df430d86d660691501b28968cc4467e6" dependencies = [ "tock-registers", ] @@ -60,9 +60,9 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.99" +version = "1.0.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58dbef6ec655055e20b86b15a8cc6d439cca19b667537ac6a1369572d151ab13" +checksum = "52205623b1b0f064a4e71182c3b18ae902267282930c6d5462c91b859668426e" dependencies = [ "proc-macro2", "quote", @@ -91,6 +91,6 @@ checksum = "4ee8fba06c1f4d0b396ef61a54530bb6b28f0dc61c38bc8bc5a5a48161e6282e" [[package]] name = "unicode-ident" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4f5b37a154999a8f3f98cc23a628d850e154479cd94decf3414696e12e31aaf" +checksum = "dcc811dc4066ac62f84f11307873c4850cb653bfa9b1719cee2bd2204a4bc5dd" diff --git a/18_backtrace/Cargo.lock b/18_backtrace/Cargo.lock index 3e5338e8..82df825a 100644 --- a/18_backtrace/Cargo.lock +++ b/18_backtrace/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "cortex-a" -version = "7.4.0" +version = "7.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f75db6964ed6748e88ff46f9aa209249a0aefe6b06d4b9e9ab820c867586d51a" +checksum = "bdecfbb28672ad3664e71ae05a398a52df430d86d660691501b28968cc4467e6" dependencies = [ "tock-registers", ] @@ -60,9 +60,9 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.99" +version = "1.0.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58dbef6ec655055e20b86b15a8cc6d439cca19b667537ac6a1369572d151ab13" +checksum = "52205623b1b0f064a4e71182c3b18ae902267282930c6d5462c91b859668426e" dependencies = [ "proc-macro2", "quote", @@ -91,6 +91,6 @@ checksum = "4ee8fba06c1f4d0b396ef61a54530bb6b28f0dc61c38bc8bc5a5a48161e6282e" [[package]] name = "unicode-ident" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4f5b37a154999a8f3f98cc23a628d850e154479cd94decf3414696e12e31aaf" +checksum = "dcc811dc4066ac62f84f11307873c4850cb653bfa9b1719cee2bd2204a4bc5dd" diff --git a/19_kernel_heap/Cargo.lock b/19_kernel_heap/Cargo.lock index 1739c78b..cc7a9c20 100644 --- a/19_kernel_heap/Cargo.lock +++ b/19_kernel_heap/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "cortex-a" -version = "7.4.0" +version = "7.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f75db6964ed6748e88ff46f9aa209249a0aefe6b06d4b9e9ab820c867586d51a" +checksum = "bdecfbb28672ad3664e71ae05a398a52df430d86d660691501b28968cc4467e6" dependencies = [ "tock-registers", ] @@ -24,9 +24,9 @@ dependencies = [ [[package]] name = "linked_list_allocator" -version = "0.10.1" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "636c3bc929db632724303109c88d5d559a2a60f62243bb041387f03fa081d94a" +checksum = "2e8da0e6283aace40e4e0395fe5ad7a147fac6ff47bda1f038b5044fb11683c2" [[package]] name = "mingo" @@ -67,9 +67,9 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.99" +version = "1.0.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58dbef6ec655055e20b86b15a8cc6d439cca19b667537ac6a1369572d151ab13" +checksum = "52205623b1b0f064a4e71182c3b18ae902267282930c6d5462c91b859668426e" dependencies = [ "proc-macro2", "quote", @@ -98,6 +98,6 @@ checksum = "4ee8fba06c1f4d0b396ef61a54530bb6b28f0dc61c38bc8bc5a5a48161e6282e" [[package]] name = "unicode-ident" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4f5b37a154999a8f3f98cc23a628d850e154479cd94decf3414696e12e31aaf" +checksum = "dcc811dc4066ac62f84f11307873c4850cb653bfa9b1719cee2bd2204a4bc5dd" diff --git a/X1_JTAG_boot/Cargo.lock b/X1_JTAG_boot/Cargo.lock index 7c8e75a8..6e628b86 100644 --- a/X1_JTAG_boot/Cargo.lock +++ b/X1_JTAG_boot/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "cortex-a" -version = "7.4.0" +version = "7.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f75db6964ed6748e88ff46f9aa209249a0aefe6b06d4b9e9ab820c867586d51a" +checksum = "bdecfbb28672ad3664e71ae05a398a52df430d86d660691501b28968cc4467e6" dependencies = [ "tock-registers", ] diff --git a/X1_JTAG_boot/jtag_boot_rpi3.img b/X1_JTAG_boot/jtag_boot_rpi3.img index 0c43ac469d8e20830ad0043edcbda3c99edc87e8..6b717dffa6c5b3ef5507a10f0b1e95bdcea9f241 100755 GIT binary patch delta 1548 zcmah|Z%kWN6hHSpO5dw&R7zW*rG1a8Q2r_-n2iNmnAyM~TQjGbF#{*+0z)&iEN&7= zOmw1Vy}2`+*(Y6=`RYtq2pUYLC4O*o{)tXZ%#!T^AJ)=14KdRi+UI%gW#h}@Np9Z# z-E;1_zw#N8MW8CwPVEz1gv8kq z@kMXAl?F*2)!!nT9srs+2U-n`M-pdXHU|B0{)z>YU|*BwTup?OESL zKA$?f{-_|xedui_Y*$H8R$Hj~a_mX=W{Iyt-3@mA4a`_=(ahtT>qd@PFwDLz>DsL{ zQE^=;-4Fg>0nHGFpR#R`#_c4;t+Z^#I0*!%&71lmu)hm%LI;>Wh+h?#0?IF@PwEA` z2v8~kM5Xx+>>KAp_lF&HNd&4}3v&+-Y++fa%N6VdyD=tc$pF!kBB9BEs99H7t?May z)|w-J;3k`JHPlSjs6`%BD?0SyBXk(G_;lVvlMYBrqp{OHh?AHcRb)3@mBR5X%evfS zp$@8wD>jVP@M=lqBbbQxW+Cm^sX`>GUJc_RW4A z7x(6*#z&%rj7I=ksd=W0ek9_LnR~X`UG55R+qfT~WiQHWAh{rxEQcjF~D8N-Nc+>PdNl?DyJ`sI7vj4ai2i7g4mMOCxVvh$}87bR^?sJ zkHfc{!Ja%*sA0NEi8n%H@0EGT3d^|4{A-l`A;XmwMS6{^%S?A!_fSJT;jYuA0;Mc01V3`V+^oH+a6(WYL!LFHk*T&Rn6k z6tHRwU4)KeHTpkBiyjc@Ag{(2`t9eQS8pzN5L-$VU{@!outsNuyy_dCBZJB_io&-08^-FDeJ>9mIxwQxY$y^+ z!0+FS9pnB6GZ^g{$9Yx&agK3hb9R|yR5xc=IOf$(S(TlHUG#XWa^5J{qMS!RhF>4w t1N+@mPa0Xdx4ro`kGmJkf4SeR-ZY!SCcM{!|94H{Vg?xX9%h$Rx@H+3UqH!yjfYW_#%37J>;TQ;0D-lSMbSCB|evz-T{o8vJM7(mv1oAn=dbN$$J% zob&GQ{LaT6c{&k}JNY8U>J_+KOfgx%gKalmetwxL{=o!e48SFM35ahtGf%5NiLz$B^W;2lLHCW-W`l5nwH zN4RxjrU$&Y0fkx}z5LDs4dCdX^ti*<82|eTRtjZz&#wcB2YrPu%pg8+_HiQG(eQ=2fnvEnronCEkOXBWO?6o1~N;fyjP_B>nkP%3mNY zh8Z%PQ^w_cN~7#&NuQ#O3n1LIh(F)xc=eCv7RHk1SlGW+4R#fQI;u94Q~;!3Td+=Y z(=A?I8D$zP5NC10Y(4RDu}EuAJ!#F+I%lL!;n?fBCdl9~mq08aCmtx{z`(T1v!@rV zHvz_EfayiteYn*4s&AwltQ@8hAjzv>jOK$Y1lcqO>-+rVHCwyI@<>1q8?WqC=&X?7vxhy3`R^lhC(W zy*lzYKyF~wRHm4fCUmgOX`gG`)(_CwjqDXgafGm7{9FN@DBH_k%+XX?UGYbF4HJqh zQHx~uHPe8-w%YQYVolpvqBcxk;&6l+iN|vS$%HWD^rx(p4(r6C_VsQPXmfb#DX=Eb z5T!+q znUpy*+WE=Xa*9LGb>%B&4rW(vxz4X88}{l{UMzCtcQNxMZxUyAm6dMcO*n*T@O}U@ zLl|5=^Kd4@e+V-JhOYX&sOLK8F3=Osdo)(jQ_}9m+}6lO4_&VKg~q+EvMVm#L{(OjkbpO z3T@Bs>I~EfgZ;<)gc{+{(BSJwj|mnFK2dlW>K>yGwFalR3|(gmFly*Heww^*==iiX p;l~UEgS0-U3C{(3#w}LMOaS#sRsZ6 diff --git a/X1_JTAG_boot/jtag_boot_rpi4.img b/X1_JTAG_boot/jtag_boot_rpi4.img index 83c4176a7b375931bf248cd0bf1b840093ffbed2..195a9fa2897dec9ff58270824d17ee341181bd88 100755 GIT binary patch delta 1014 zcmah{T}TvB6h3#xjamN~-JR9lRoC^Wb=OwKQZO-A#6Tm>H6nV@4WHB=DkzJ{9|A)R zbU1+zy{t;;7zDBeE=dTz=wndQL&a!VYq=2FgNx~OXZ8v`1l^Z2=bZ0+_xtV{wSJ|3 z(r%7}=qlvjjl|`mGh})3>Mlujo8Yltn|>DQ;%tP3@D_h9Z^I{h8w+LiAyL#~kYjV8 zl)-Q?HVbvlc)-_lYvIW0lzzf(_#$(rMS&A~@JePY$%s77yvK24b+lVe@M5-4sFrnl zUnh=cyX>7Hst+ii$E4`hvQL^JNGZox*-bT}5}D5kBtqa?2jc`19}cygnKTh7%CYT^zR8IORxQwfI9@hwe^R}!V={@Rn&mC@kB zqotc^l(v7m*5Ene$4gcZ@#CPis9_|R(#;Zi^EJprhuTztKutGQr7_J=l3W8<45FJK z4t7vXAr!tS)MIpWaN+A+?b@?3F50%QbCE_qpo98L7PB1~oND zl$eDx#I(HEbIuUH8q@H*V)x=aPxRnZy%^gejNnMU26Mm>Gz8wk18yNJ&p$4wxs3-#yg)hCzK1<~L^(K2sn%o-!Ql zldLCwCWs2OW`>2Jc?+T|eD^x4wmnpHLRm`=I`Y?eG<{NZp)etWWGXWeER3()V( z!v?!k(u;Q)!p0C2*lTx@B^>k2$6%+O$yxyyFN-LVj{SouNb;O?W=P$y;Sfb^3MUdNzpXv9RW~v3Y$e$em`#T^eS0o$oZiB1D(IRjg z(lj7=DraXx__D!TbPPBaz^DP3(mcoa3^jU@2QK4Mi5V7@YX^P!wZX3Sk!$yX02}zH z;c#c-rESAlZ^yVkQxU#-lRzVIh-@rnxfZQ zF9Ph^YI2jO)kblf=?Dto+opP5lO#>cOyfTM!c z1=~Mna@6E!N>}G+TFcRyNd50k>9{hWya?^516hySzc`_a1P4vVCXX5xH6*8ncu@NV z7L#nhvRrw=0RHTHPAbix0n#jrYgB$Q#cJY+JSKi`{-u&Z{HpY9Nw<~o|79T@C|kkT zd22}rpGV9T4PlYDqY=E!A9ZeZksn2|5M@C$p24k_FkY|?lr35EEQJ)|h*y&j`*>@m zl3S-0JgwMId<8uNKFQngyyf8O|J~R_75HdpGgZGeU6kTlir=9zL*q$nqSxAoa6`G@ X%^C7t4(gZ6^Km!zN$N-N{c_hIeQ*@K From d942e0f9535724ba9c323db60794074ec3915a82 Mon Sep 17 00:00:00 2001 From: Andre Richter Date: Tue, 20 Sep 2022 23:13:12 +0200 Subject: [PATCH 50/75] Fix bug in register_structs description --- 13_exceptions_part2_peripheral_IRQs/README.md | 2 +- .../bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs | 2 +- .../bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs | 2 +- .../bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs | 2 +- .../bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs | 2 +- .../bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs | 2 +- .../bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs | 2 +- .../bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/13_exceptions_part2_peripheral_IRQs/README.md b/13_exceptions_part2_peripheral_IRQs/README.md index 74eb28c3..77bcc2f2 100644 --- a/13_exceptions_part2_peripheral_IRQs/README.md +++ b/13_exceptions_part2_peripheral_IRQs/README.md @@ -1549,7 +1549,7 @@ diff -uNr 12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_interru + (0x00 => _reserved1), + (0x10 => ENABLE_1: WriteOnly), + (0x14 => ENABLE_2: WriteOnly), -+ (0x24 => @END), ++ (0x18 => @END), + } +} + diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs index 3107d296..0900635e 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs @@ -26,7 +26,7 @@ register_structs! { (0x00 => _reserved1), (0x10 => ENABLE_1: WriteOnly), (0x14 => ENABLE_2: WriteOnly), - (0x24 => @END), + (0x18 => @END), } } diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs index 145d8961..c9711049 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs @@ -28,7 +28,7 @@ register_structs! { (0x00 => _reserved1), (0x10 => ENABLE_1: WriteOnly), (0x14 => ENABLE_2: WriteOnly), - (0x24 => @END), + (0x18 => @END), } } diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs index 145d8961..c9711049 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs @@ -28,7 +28,7 @@ register_structs! { (0x00 => _reserved1), (0x10 => ENABLE_1: WriteOnly), (0x14 => ENABLE_2: WriteOnly), - (0x24 => @END), + (0x18 => @END), } } diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs index 145d8961..c9711049 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs @@ -28,7 +28,7 @@ register_structs! { (0x00 => _reserved1), (0x10 => ENABLE_1: WriteOnly), (0x14 => ENABLE_2: WriteOnly), - (0x24 => @END), + (0x18 => @END), } } diff --git a/17_kernel_symbols/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs b/17_kernel_symbols/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs index 145d8961..c9711049 100644 --- a/17_kernel_symbols/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs +++ b/17_kernel_symbols/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs @@ -28,7 +28,7 @@ register_structs! { (0x00 => _reserved1), (0x10 => ENABLE_1: WriteOnly), (0x14 => ENABLE_2: WriteOnly), - (0x24 => @END), + (0x18 => @END), } } diff --git a/18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs b/18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs index 145d8961..c9711049 100644 --- a/18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs +++ b/18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs @@ -28,7 +28,7 @@ register_structs! { (0x00 => _reserved1), (0x10 => ENABLE_1: WriteOnly), (0x14 => ENABLE_2: WriteOnly), - (0x24 => @END), + (0x18 => @END), } } diff --git a/19_kernel_heap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs b/19_kernel_heap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs index a2034e3b..65a9e7a0 100644 --- a/19_kernel_heap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs +++ b/19_kernel_heap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs @@ -29,7 +29,7 @@ register_structs! { (0x00 => _reserved1), (0x10 => ENABLE_1: WriteOnly), (0x14 => ENABLE_2: WriteOnly), - (0x24 => @END), + (0x18 => @END), } } From c8c422e995017daf310d86f5b1bf2cf7ee5e54df Mon Sep 17 00:00:00 2001 From: James Zow Date: Thu, 22 Sep 2022 15:37:26 +0800 Subject: [PATCH 51/75] Translation tutorial 3 (#167) * Translation tutorial 3 * Update README.CN.md * Update README.CN.md * Update README.CN.md * Update README.CN.md * Translate Chapter 4 Safe Globals * remove Chapter 4 Translation, modify the diff in Chapter 2 and Chapter 3 Co-authored-by: Fengqixian <570311238@qq.com> --- 02_runtime_init/README.CN.md | 2 +- 03_hacky_hello_world/README.CN.md | 35 +++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 03_hacky_hello_world/README.CN.md diff --git a/02_runtime_init/README.CN.md b/02_runtime_init/README.CN.md index 46c52467..f8d64f6f 100644 --- a/02_runtime_init/README.CN.md +++ b/02_runtime_init/README.CN.md @@ -19,5 +19,5 @@ [bss]: https://en.wikipedia.org/wiki/.bss ## 相比之前的变化(diff) +请检查[英文版本](README.md#diff-to-previous),这是最新的。 -Please check [the english version](README.md#diff-to-previous), which is kept up-to-date. diff --git a/03_hacky_hello_world/README.CN.md b/03_hacky_hello_world/README.CN.md new file mode 100644 index 00000000..ac08fae5 --- /dev/null +++ b/03_hacky_hello_world/README.CN.md @@ -0,0 +1,35 @@ +# 教程 03 - Hacky Hello World + +## tl;dr + +- 介绍全局的`println!()`宏以便尽早启用"printf debugging"。 +- 为了保持教程长度合理,打印函数目前 "滥用" 了 QEMU 属性,该属性允许我们在没有正确设置的情况下使用树莓派的`UART`。 +- 在接下来的教程中将逐步使用真实硬件的`UART`。 + +## 值得注意的补充 + +- `src/console.rs`为控制台命令和通过`console::console()`对内核控制台的全局访问引入了接口`Traits`。 +- `src/bsp/raspberrypi/console.rs` 实现QEMU仿真UART的接口。 +- 紧急处理程序使用新的`println!()`以显示用户错误消息。 +- 有一个新的Makefile目录`make test`,用于自动测试。它在`QEMU`中引导编译后的内核,并检查内核生成的预期输出字符串。 + - 在本教程中,它检查字符串`Stopping here`,该字符串由`panic!()`在`main.rs`的末尾。 + +## 测试一下 + +QEMU不再以汇编模式运行。从现在起,它将显示`console`的输出。 + +```console +$ make qemu +[...] + +Hello from Rust! +Kernel panic! + +Panic location: + File 'src/main.rs', line 126, column 5 + +Stopping here. +``` + +## 相比之前的变化(diff) +请检查[英文版本](README.md#diff-to-previous),这是最新的。 From b7b2d31c2457ec4ee153e3345a954f7582c40533 Mon Sep 17 00:00:00 2001 From: Andre Richter Date: Fri, 23 Sep 2022 22:38:10 +0200 Subject: [PATCH 52/75] Rewrite timer subsystem --- 07_timestamps/README.md | 290 +++++++++++------- 07_timestamps/src/_arch/aarch64/cpu/boot.s | 8 + 07_timestamps/src/_arch/aarch64/time.rs | 187 ++++++----- .../src/bsp/device_driver/bcm/bcm2xxx_gpio.rs | 2 +- 07_timestamps/src/main.rs | 4 +- 07_timestamps/src/panic_wait.rs | 2 - 07_timestamps/src/print.rs | 8 - 07_timestamps/src/time.rs | 52 +++- 08_hw_debug_JTAG/src/_arch/aarch64/cpu/boot.s | 8 + 08_hw_debug_JTAG/src/_arch/aarch64/time.rs | 187 ++++++----- .../src/bsp/device_driver/bcm/bcm2xxx_gpio.rs | 2 +- 08_hw_debug_JTAG/src/main.rs | 4 +- 08_hw_debug_JTAG/src/panic_wait.rs | 2 - 08_hw_debug_JTAG/src/print.rs | 8 - 08_hw_debug_JTAG/src/time.rs | 52 +++- 09_privilege_level/README.md | 16 +- .../src/_arch/aarch64/cpu/boot.s | 8 + 09_privilege_level/src/_arch/aarch64/time.rs | 187 ++++++----- .../src/bsp/device_driver/bcm/bcm2xxx_gpio.rs | 2 +- 09_privilege_level/src/main.rs | 4 +- 09_privilege_level/src/panic_wait.rs | 2 - 09_privilege_level/src/print.rs | 8 - 09_privilege_level/src/time.rs | 52 +++- .../README.md | 16 +- .../src/_arch/aarch64/cpu/boot.s | 8 + .../src/_arch/aarch64/time.rs | 187 ++++++----- .../src/bsp/device_driver/bcm/bcm2xxx_gpio.rs | 2 +- .../src/main.rs | 4 +- .../src/panic_wait.rs | 2 - .../src/print.rs | 8 - .../src/time.rs | 52 +++- 11_exceptions_part1_groundwork/README.md | 8 +- .../src/_arch/aarch64/cpu/boot.s | 8 + .../src/_arch/aarch64/time.rs | 187 ++++++----- .../src/bsp/device_driver/bcm/bcm2xxx_gpio.rs | 2 +- 11_exceptions_part1_groundwork/src/main.rs | 4 +- .../src/panic_wait.rs | 2 - 11_exceptions_part1_groundwork/src/print.rs | 8 - 11_exceptions_part1_groundwork/src/time.rs | 52 +++- 12_integrated_testing/README.md | 3 +- .../kernel/src/_arch/aarch64/cpu/boot.s | 8 + .../kernel/src/_arch/aarch64/time.rs | 187 ++++++----- .../src/bsp/device_driver/bcm/bcm2xxx_gpio.rs | 2 +- 12_integrated_testing/kernel/src/lib.rs | 3 + .../kernel/src/panic_wait.rs | 2 - 12_integrated_testing/kernel/src/print.rs | 8 - 12_integrated_testing/kernel/src/time.rs | 52 +++- .../kernel/tests/01_timer_sanity.rs | 3 +- 13_exceptions_part2_peripheral_IRQs/README.md | 8 +- .../kernel/src/_arch/aarch64/cpu/boot.s | 8 + .../kernel/src/_arch/aarch64/time.rs | 187 ++++++----- .../src/bsp/device_driver/bcm/bcm2xxx_gpio.rs | 2 +- .../kernel/src/lib.rs | 3 + .../kernel/src/panic_wait.rs | 2 - .../kernel/src/print.rs | 8 - .../kernel/src/time.rs | 52 +++- .../kernel/tests/01_timer_sanity.rs | 3 +- 14_virtual_mem_part2_mmio_remap/README.md | 13 +- .../kernel/src/_arch/aarch64/cpu/boot.s | 8 + .../kernel/src/_arch/aarch64/time.rs | 187 ++++++----- .../src/bsp/device_driver/bcm/bcm2xxx_gpio.rs | 2 +- .../kernel/src/lib.rs | 3 + .../kernel/src/panic_wait.rs | 2 - .../kernel/src/print.rs | 8 - .../kernel/src/time.rs | 52 +++- .../kernel/tests/01_timer_sanity.rs | 3 +- .../README.md | 16 +- .../kernel/src/_arch/aarch64/cpu/boot.s | 8 + .../kernel/src/_arch/aarch64/time.rs | 187 ++++++----- .../src/bsp/device_driver/bcm/bcm2xxx_gpio.rs | 2 +- .../kernel/src/lib.rs | 3 + .../kernel/src/panic_wait.rs | 2 - .../kernel/src/print.rs | 8 - .../kernel/src/time.rs | 52 +++- .../kernel/tests/01_timer_sanity.rs | 3 +- .../README.md | 16 +- .../kernel/src/_arch/aarch64/cpu/boot.s | 8 + .../kernel/src/_arch/aarch64/time.rs | 187 ++++++----- .../src/bsp/device_driver/bcm/bcm2xxx_gpio.rs | 2 +- .../kernel/src/lib.rs | 3 + .../kernel/src/panic_wait.rs | 2 - .../kernel/src/print.rs | 8 - .../kernel/src/time.rs | 52 +++- .../kernel/tests/01_timer_sanity.rs | 3 +- 17_kernel_symbols/README.md | 2 +- .../kernel/src/_arch/aarch64/cpu/boot.s | 8 + .../kernel/src/_arch/aarch64/time.rs | 187 ++++++----- .../src/bsp/device_driver/bcm/bcm2xxx_gpio.rs | 2 +- 17_kernel_symbols/kernel/src/lib.rs | 3 + 17_kernel_symbols/kernel/src/panic_wait.rs | 2 - 17_kernel_symbols/kernel/src/print.rs | 8 - 17_kernel_symbols/kernel/src/time.rs | 52 +++- .../kernel/tests/01_timer_sanity.rs | 3 +- 18_backtrace/README.md | 6 +- .../kernel/src/_arch/aarch64/cpu/boot.s | 8 + 18_backtrace/kernel/src/_arch/aarch64/time.rs | 187 ++++++----- .../src/bsp/device_driver/bcm/bcm2xxx_gpio.rs | 2 +- 18_backtrace/kernel/src/lib.rs | 3 + 18_backtrace/kernel/src/panic_wait.rs | 2 - 18_backtrace/kernel/src/print.rs | 8 - 18_backtrace/kernel/src/time.rs | 52 +++- 18_backtrace/kernel/tests/01_timer_sanity.rs | 3 +- 19_kernel_heap/README.md | 25 +- .../kernel/src/_arch/aarch64/cpu/boot.s | 8 + .../kernel/src/_arch/aarch64/time.rs | 187 ++++++----- .../src/bsp/device_driver/bcm/bcm2xxx_gpio.rs | 2 +- .../kernel/src/bsp/raspberrypi/driver.rs | 1 + 19_kernel_heap/kernel/src/lib.rs | 3 + 19_kernel_heap/kernel/src/panic_wait.rs | 2 - 19_kernel_heap/kernel/src/print.rs | 12 - 19_kernel_heap/kernel/src/time.rs | 52 +++- .../kernel/tests/01_timer_sanity.rs | 3 +- X1_JTAG_boot/jtag_boot_rpi3.img | Bin 8712 -> 8656 bytes X1_JTAG_boot/jtag_boot_rpi4.img | Bin 7616 -> 7752 bytes X1_JTAG_boot/src/_arch/aarch64/cpu/boot.s | 8 + X1_JTAG_boot/src/_arch/aarch64/time.rs | 189 +++++++----- .../src/bsp/device_driver/bcm/bcm2xxx_gpio.rs | 2 +- X1_JTAG_boot/src/main.rs | 3 + X1_JTAG_boot/src/panic_wait.rs | 2 - X1_JTAG_boot/src/print.rs | 8 - X1_JTAG_boot/src/time.rs | 48 ++- 121 files changed, 2538 insertions(+), 1581 deletions(-) diff --git a/07_timestamps/README.md b/07_timestamps/README.md index 1126d9b7..a78e508b 100644 --- a/07_timestamps/README.md +++ b/07_timestamps/README.md @@ -182,7 +182,7 @@ diff -uNr 06_uart_chainloader/src/_arch/aarch64/cpu/boot.s 07_timestamps/src/_ar //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- -@@ -48,35 +37,23 @@ +@@ -48,35 +37,31 @@ // If execution reaches here, it is the boot core. // Initialize DRAM. @@ -220,6 +220,14 @@ diff -uNr 06_uart_chainloader/src/_arch/aarch64/cpu/boot.s 07_timestamps/src/_ar - // Jump to the relocated Rust code. - ADR_ABS x1, _start_rust - br x1 ++ // Read the CPU's timer counter frequency and store it in ARCH_TIMER_COUNTER_FREQUENCY. ++ // Abort if the frequency read back as 0. ++ ADR_REL x1, ARCH_TIMER_COUNTER_FREQUENCY // provided by aarch64/time.rs ++ mrs x2, CNTFRQ_EL0 ++ cmp x2, xzr ++ b.eq .L_parking_loop ++ str w2, [x1] ++ + // Jump to Rust code. + b _start_rust @@ -249,7 +257,7 @@ diff -uNr 06_uart_chainloader/src/_arch/aarch64/cpu.rs 07_timestamps/src/_arch/a diff -uNr 06_uart_chainloader/src/_arch/aarch64/time.rs 07_timestamps/src/_arch/aarch64/time.rs --- 06_uart_chainloader/src/_arch/aarch64/time.rs +++ 07_timestamps/src/_arch/aarch64/time.rs -@@ -0,0 +1,121 @@ +@@ -0,0 +1,162 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2018-2022 Andre Richter @@ -263,114 +271,155 @@ diff -uNr 06_uart_chainloader/src/_arch/aarch64/time.rs 07_timestamps/src/_arch/ +//! +//! crate::time::arch_time + -+use crate::{time, warn}; -+use core::time::Duration; ++use crate::warn; ++use core::{ ++ num::{NonZeroU128, NonZeroU32, NonZeroU64}, ++ ops::{Add, Div}, ++ time::Duration, ++}; +use cortex_a::{asm::barrier, registers::*}; -+use tock_registers::interfaces::{ReadWriteable, Readable, Writeable}; ++use tock_registers::interfaces::Readable; + +//-------------------------------------------------------------------------------------------------- +// Private Definitions +//-------------------------------------------------------------------------------------------------- + -+const NS_PER_S: u64 = 1_000_000_000; ++const NANOSEC_PER_SEC: NonZeroU64 = NonZeroU64::new(1_000_000_000).unwrap(); + -+/// ARMv8 Generic Timer. -+struct GenericTimer; ++#[derive(Copy, Clone, PartialOrd, PartialEq)] ++struct GenericTimerCounterValue(u64); + +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + -+static TIME_MANAGER: GenericTimer = GenericTimer; ++/// Boot assembly code overwrites this value with the value of CNTFRQ_EL0 before any Rust code is ++/// executed. This given value here is just a (safe) dummy. ++#[no_mangle] ++static ARCH_TIMER_COUNTER_FREQUENCY: NonZeroU32 = NonZeroU32::MIN; + +//-------------------------------------------------------------------------------------------------- +// Private Code +//-------------------------------------------------------------------------------------------------- + -+impl GenericTimer { -+ #[inline(always)] -+ fn read_cntpct(&self) -> u64 { -+ // Prevent that the counter is read ahead of time due to out-of-order execution. -+ unsafe { barrier::isb(barrier::SY) }; -+ CNTPCT_EL0.get() -+ } ++impl GenericTimerCounterValue { ++ pub const MAX: Self = GenericTimerCounterValue(u64::MAX); +} + -+//-------------------------------------------------------------------------------------------------- -+// Public Code -+//-------------------------------------------------------------------------------------------------- ++impl Add for GenericTimerCounterValue { ++ type Output = Self; + -+/// Return a reference to the time manager. -+pub fn time_manager() -> &'static impl time::interface::TimeManager { -+ &TIME_MANAGER ++ fn add(self, other: Self) -> Self { ++ GenericTimerCounterValue(self.0.wrapping_add(other.0)) ++ } +} + -+//------------------------------------------------------------------------------ -+// OS Interface Code -+//------------------------------------------------------------------------------ ++impl From for Duration { ++ fn from(counter_value: GenericTimerCounterValue) -> Self { ++ if counter_value.0 == 0 { ++ return Duration::ZERO; ++ } + -+impl time::interface::TimeManager for GenericTimer { -+ fn resolution(&self) -> Duration { -+ Duration::from_nanos(NS_PER_S / (CNTFRQ_EL0.get() as u64)) ++ // Read volatile is needed here to prevent the compiler from optimizing ++ // ARCH_TIMER_COUNTER_FREQUENCY away. ++ // ++ // This is safe, because all the safety requirements as stated in read_volatile()'s ++ // documentation are fulfilled. ++ let frequency: NonZeroU64 = ++ unsafe { core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY) }.into(); ++ ++ // Div implementation for u64 cannot panic. ++ let secs = counter_value.0.div(frequency); ++ ++ // This is safe, because frequency can never be greater than u32::MAX, which means the ++ // largest theoretical value for sub_second_counter_value is (u32::MAX - 1). Therefore, ++ // (sub_second_counter_value * NANOSEC_PER_SEC) cannot overflow an u64. ++ // ++ // The subsequent division ensures the result fits into u32, since the max result is smaller ++ // than NANOSEC_PER_SEC. Therefore, just cast it to u32 using `as`. ++ let sub_second_counter_value = counter_value.0 modulo frequency; ++ let nanos = unsafe { sub_second_counter_value.unchecked_mul(u64::from(NANOSEC_PER_SEC)) } ++ .div(frequency) as u32; ++ ++ Duration::new(secs, nanos) + } ++} + -+ fn uptime(&self) -> Duration { -+ let current_count: u64 = self.read_cntpct() * NS_PER_S; -+ let frq: u64 = CNTFRQ_EL0.get() as u64; ++fn max_duration() -> Duration { ++ Duration::from(GenericTimerCounterValue::MAX) ++} + -+ Duration::from_nanos(current_count / frq) -+ } ++impl TryFrom for GenericTimerCounterValue { ++ type Error = &'static str; + -+ fn spin_for(&self, duration: Duration) { -+ // Instantly return on zero. -+ if duration.as_nanos() == 0 { -+ return; ++ fn try_from(duration: Duration) -> Result { ++ if duration < resolution() { ++ return Ok(GenericTimerCounterValue(0)); + } + -+ // Calculate the register compare value. -+ let frq = CNTFRQ_EL0.get(); -+ let x = match frq.checked_mul(duration.as_nanos() as u64) { -+ #[allow(unused_imports)] -+ None => { -+ warn!("Spin duration too long, skipping"); -+ return; -+ } -+ Some(val) => val, -+ }; -+ let tval = x / NS_PER_S; -+ -+ // Check if it is within supported bounds. -+ let warn: Option<&str> = if tval == 0 { -+ Some("smaller") -+ // The upper 32 bits of CNTP_TVAL_EL0 are reserved. -+ } else if tval > u32::max_value().into() { -+ Some("bigger") -+ } else { -+ None -+ }; -+ -+ #[allow(unused_imports)] -+ if let Some(w) = warn { -+ warn!( -+ "Spin duration {} than architecturally supported, skipping", -+ w -+ ); -+ return; ++ if duration > max_duration() { ++ return Err("Conversion error. Duration too big"); + } + -+ // Set the compare value register. -+ CNTP_TVAL_EL0.set(tval); ++ // This is safe, because all the safety requirements as stated in read_volatile()'s ++ // documentation are fulfilled. ++ let frequency: u128 = ++ unsafe { u32::from(core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY)) as u128 }; ++ let duration: u128 = duration.as_nanos(); + -+ // Kick off the counting. // Disable timer interrupt. -+ CNTP_CTL_EL0.modify(CNTP_CTL_EL0::ENABLE::SET + CNTP_CTL_EL0::IMASK::SET); ++ // This is safe, because frequency can never be greater than u32::MAX, and ++ // (Duration::MAX.as_nanos() * u32::MAX) < u128::MAX. ++ let counter_value = ++ unsafe { duration.unchecked_mul(frequency) }.div(NonZeroU128::from(NANOSEC_PER_SEC)); + -+ // ISTATUS will be '1' when cval ticks have passed. Busy-check it. -+ while !CNTP_CTL_EL0.matches_all(CNTP_CTL_EL0::ISTATUS::SET) {} -+ -+ // Disable counting again. -+ CNTP_CTL_EL0.modify(CNTP_CTL_EL0::ENABLE::CLEAR); ++ // Since we checked above that we are <= max_duration(), just cast to u64. ++ Ok(GenericTimerCounterValue(counter_value as u64)) + } +} ++ ++#[inline(always)] ++fn read_cntpct() -> GenericTimerCounterValue { ++ // Prevent that the counter is read ahead of time due to out-of-order execution. ++ unsafe { barrier::isb(barrier::SY) }; ++ let cnt = CNTPCT_EL0.get(); ++ ++ GenericTimerCounterValue(cnt) ++} ++ ++//-------------------------------------------------------------------------------------------------- ++// Public Code ++//-------------------------------------------------------------------------------------------------- ++ ++/// The timer's resolution. ++pub fn resolution() -> Duration { ++ Duration::from(GenericTimerCounterValue(1)) ++} ++ ++/// The uptime since power-on of the device. ++/// ++/// This includes time consumed by firmware and bootloaders. ++pub fn uptime() -> Duration { ++ read_cntpct().into() ++} ++ ++/// Spin for a given duration. ++pub fn spin_for(duration: Duration) { ++ let curr_counter_value = read_cntpct(); ++ ++ let counter_value_delta: GenericTimerCounterValue = match duration.try_into() { ++ Err(msg) => { ++ warn!("spin_for: {}. Skipping", msg); ++ return; ++ } ++ Ok(val) => val, ++ }; ++ let counter_value_target = curr_counter_value + counter_value_delta; ++ ++ // Busy wait. ++ // ++ // Read CNTPCT_EL0 directly to avoid the ISB that is part of [`read_cntpct`]. ++ while GenericTimerCounterValue(CNTPCT_EL0.get()) < counter_value_target {} ++} diff -uNr 06_uart_chainloader/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs 07_timestamps/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs --- 06_uart_chainloader/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs @@ -380,7 +429,7 @@ diff -uNr 06_uart_chainloader/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs 07_times #[cfg(feature = "bsp_rpi3")] fn disable_pud_14_15_bcm2837(&mut self) { - use crate::cpu; -+ use crate::{time, time::interface::TimeManager}; ++ use crate::time; + use core::time::Duration; - // Make an educated guess for a good delay value (Sequence described in the BCM2837 @@ -534,7 +583,20 @@ diff -uNr 06_uart_chainloader/src/cpu.rs 07_timestamps/src/cpu.rs diff -uNr 06_uart_chainloader/src/main.rs 07_timestamps/src/main.rs --- 06_uart_chainloader/src/main.rs +++ 07_timestamps/src/main.rs -@@ -121,6 +121,7 @@ +@@ -108,9 +108,12 @@ + + #![allow(clippy::upper_case_acronyms)] + #![feature(asm_const)] ++#![feature(const_option)] + #![feature(format_args_nl)] ++#![feature(nonzero_min_max)] + #![feature(panic_info_message)] + #![feature(trait_alias)] ++#![feature(unchecked_math)] + #![no_main] + #![no_std] + +@@ -121,6 +124,7 @@ mod panic_wait; mod print; mod synchronization; @@ -542,7 +604,7 @@ diff -uNr 06_uart_chainloader/src/main.rs 07_timestamps/src/main.rs /// Early init code. /// -@@ -143,55 +144,38 @@ +@@ -143,55 +147,37 @@ kernel_main() } @@ -558,7 +620,6 @@ diff -uNr 06_uart_chainloader/src/main.rs 07_timestamps/src/main.rs - use console::console; + use core::time::Duration; + use driver::interface::DriverManager; -+ use time::interface::TimeManager; - println!("{}", MINILOAD_LOGO); - println!("{:^37}", bsp::board_name()); @@ -630,12 +691,7 @@ diff -uNr 06_uart_chainloader/src/main.rs 07_timestamps/src/main.rs diff -uNr 06_uart_chainloader/src/panic_wait.rs 07_timestamps/src/panic_wait.rs --- 06_uart_chainloader/src/panic_wait.rs +++ 07_timestamps/src/panic_wait.rs -@@ -42,18 +42,23 @@ - - #[panic_handler] - fn panic(info: &PanicInfo) -> ! { -+ use crate::time::interface::TimeManager; -+ +@@ -45,15 +45,18 @@ // Protect against panic infinite loops if any of the following code panics itself. panic_prevent_reenter(); @@ -659,7 +715,7 @@ diff -uNr 06_uart_chainloader/src/panic_wait.rs 07_timestamps/src/panic_wait.rs diff -uNr 06_uart_chainloader/src/print.rs 07_timestamps/src/print.rs --- 06_uart_chainloader/src/print.rs +++ 07_timestamps/src/print.rs -@@ -34,3 +34,59 @@ +@@ -34,3 +34,51 @@ $crate::print::_print(format_args_nl!($($arg)*)); }) } @@ -668,8 +724,6 @@ diff -uNr 06_uart_chainloader/src/print.rs 07_timestamps/src/print.rs +#[macro_export] +macro_rules! info { + ($string:expr) => ({ -+ use $crate::time::interface::TimeManager; -+ + let timestamp = $crate::time::time_manager().uptime(); + + $crate::print::_print(format_args_nl!( @@ -679,8 +733,6 @@ diff -uNr 06_uart_chainloader/src/print.rs 07_timestamps/src/print.rs + )); + }); + ($format_string:expr, $($arg:tt)*) => ({ -+ use $crate::time::interface::TimeManager; -+ + let timestamp = $crate::time::time_manager().uptime(); + + $crate::print::_print(format_args_nl!( @@ -696,8 +748,6 @@ diff -uNr 06_uart_chainloader/src/print.rs 07_timestamps/src/print.rs +#[macro_export] +macro_rules! warn { + ($string:expr) => ({ -+ use $crate::time::interface::TimeManager; -+ + let timestamp = $crate::time::time_manager().uptime(); + + $crate::print::_print(format_args_nl!( @@ -707,8 +757,6 @@ diff -uNr 06_uart_chainloader/src/print.rs 07_timestamps/src/print.rs + )); + }); + ($format_string:expr, $($arg:tt)*) => ({ -+ use $crate::time::interface::TimeManager; -+ + let timestamp = $crate::time::time_manager().uptime(); + + $crate::print::_print(format_args_nl!( @@ -723,7 +771,7 @@ diff -uNr 06_uart_chainloader/src/print.rs 07_timestamps/src/print.rs diff -uNr 06_uart_chainloader/src/time.rs 07_timestamps/src/time.rs --- 06_uart_chainloader/src/time.rs +++ 07_timestamps/src/time.rs -@@ -0,0 +1,37 @@ +@@ -0,0 +1,57 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2020-2022 Andre Richter @@ -734,31 +782,51 @@ diff -uNr 06_uart_chainloader/src/time.rs 07_timestamps/src/time.rs +#[path = "_arch/aarch64/time.rs"] +mod arch_time; + ++use core::time::Duration; ++ +//-------------------------------------------------------------------------------------------------- -+// Architectural Public Reexports ++// Public Definitions +//-------------------------------------------------------------------------------------------------- -+pub use arch_time::time_manager; ++ ++/// Provides time management functions. ++pub struct TimeManager; + +//-------------------------------------------------------------------------------------------------- -+// Public Definitions ++// Global instances +//-------------------------------------------------------------------------------------------------- + -+/// Timekeeping interfaces. -+pub mod interface { -+ use core::time::Duration; ++static TIME_MANAGER: TimeManager = TimeManager::new(); + -+ /// Time management functions. -+ pub trait TimeManager { -+ /// The timer's resolution. -+ fn resolution(&self) -> Duration; ++//-------------------------------------------------------------------------------------------------- ++// Public Code ++//-------------------------------------------------------------------------------------------------- + -+ /// The uptime since power-on of the device. -+ /// -+ /// This includes time consumed by firmware and bootloaders. -+ fn uptime(&self) -> Duration; ++/// Return a reference to the global TimeManager. ++pub fn time_manager() -> &'static TimeManager { ++ &TIME_MANAGER ++} ++ ++impl TimeManager { ++ /// Create an instance. ++ pub const fn new() -> Self { ++ Self ++ } ++ ++ /// The timer's resolution. ++ pub fn resolution(&self) -> Duration { ++ arch_time::resolution() ++ } ++ ++ /// The uptime since power-on of the device. ++ /// ++ /// This includes time consumed by firmware and bootloaders. ++ pub fn uptime(&self) -> Duration { ++ arch_time::uptime() ++ } + -+ /// Spin for a given duration. -+ fn spin_for(&self, duration: Duration); ++ /// Spin for a given duration. ++ pub fn spin_for(&self, duration: Duration) { ++ arch_time::spin_for(duration) + } +} diff --git a/07_timestamps/src/_arch/aarch64/cpu/boot.s b/07_timestamps/src/_arch/aarch64/cpu/boot.s index 1f70169f..aa701fd1 100644 --- a/07_timestamps/src/_arch/aarch64/cpu/boot.s +++ b/07_timestamps/src/_arch/aarch64/cpu/boot.s @@ -52,6 +52,14 @@ _start: ADR_REL x0, __boot_core_stack_end_exclusive mov sp, x0 + // Read the CPU's timer counter frequency and store it in ARCH_TIMER_COUNTER_FREQUENCY. + // Abort if the frequency read back as 0. + ADR_REL x1, ARCH_TIMER_COUNTER_FREQUENCY // provided by aarch64/time.rs + mrs x2, CNTFRQ_EL0 + cmp x2, xzr + b.eq .L_parking_loop + str w2, [x1] + // Jump to Rust code. b _start_rust diff --git a/07_timestamps/src/_arch/aarch64/time.rs b/07_timestamps/src/_arch/aarch64/time.rs index c814219c..255a5a45 100644 --- a/07_timestamps/src/_arch/aarch64/time.rs +++ b/07_timestamps/src/_arch/aarch64/time.rs @@ -11,111 +11,152 @@ //! //! crate::time::arch_time -use crate::{time, warn}; -use core::time::Duration; +use crate::warn; +use core::{ + num::{NonZeroU128, NonZeroU32, NonZeroU64}, + ops::{Add, Div}, + time::Duration, +}; use cortex_a::{asm::barrier, registers::*}; -use tock_registers::interfaces::{ReadWriteable, Readable, Writeable}; +use tock_registers::interfaces::Readable; //-------------------------------------------------------------------------------------------------- // Private Definitions //-------------------------------------------------------------------------------------------------- -const NS_PER_S: u64 = 1_000_000_000; +const NANOSEC_PER_SEC: NonZeroU64 = NonZeroU64::new(1_000_000_000).unwrap(); -/// ARMv8 Generic Timer. -struct GenericTimer; +#[derive(Copy, Clone, PartialOrd, PartialEq)] +struct GenericTimerCounterValue(u64); //-------------------------------------------------------------------------------------------------- // Global instances //-------------------------------------------------------------------------------------------------- -static TIME_MANAGER: GenericTimer = GenericTimer; +/// Boot assembly code overwrites this value with the value of CNTFRQ_EL0 before any Rust code is +/// executed. This given value here is just a (safe) dummy. +#[no_mangle] +static ARCH_TIMER_COUNTER_FREQUENCY: NonZeroU32 = NonZeroU32::MIN; //-------------------------------------------------------------------------------------------------- // Private Code //-------------------------------------------------------------------------------------------------- -impl GenericTimer { - #[inline(always)] - fn read_cntpct(&self) -> u64 { - // Prevent that the counter is read ahead of time due to out-of-order execution. - unsafe { barrier::isb(barrier::SY) }; - CNTPCT_EL0.get() - } +impl GenericTimerCounterValue { + pub const MAX: Self = GenericTimerCounterValue(u64::MAX); } -//-------------------------------------------------------------------------------------------------- -// Public Code -//-------------------------------------------------------------------------------------------------- +impl Add for GenericTimerCounterValue { + type Output = Self; -/// Return a reference to the time manager. -pub fn time_manager() -> &'static impl time::interface::TimeManager { - &TIME_MANAGER + fn add(self, other: Self) -> Self { + GenericTimerCounterValue(self.0.wrapping_add(other.0)) + } } -//------------------------------------------------------------------------------ -// OS Interface Code -//------------------------------------------------------------------------------ +impl From for Duration { + fn from(counter_value: GenericTimerCounterValue) -> Self { + if counter_value.0 == 0 { + return Duration::ZERO; + } -impl time::interface::TimeManager for GenericTimer { - fn resolution(&self) -> Duration { - Duration::from_nanos(NS_PER_S / (CNTFRQ_EL0.get() as u64)) + // Read volatile is needed here to prevent the compiler from optimizing + // ARCH_TIMER_COUNTER_FREQUENCY away. + // + // This is safe, because all the safety requirements as stated in read_volatile()'s + // documentation are fulfilled. + let frequency: NonZeroU64 = + unsafe { core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY) }.into(); + + // Div implementation for u64 cannot panic. + let secs = counter_value.0.div(frequency); + + // This is safe, because frequency can never be greater than u32::MAX, which means the + // largest theoretical value for sub_second_counter_value is (u32::MAX - 1). Therefore, + // (sub_second_counter_value * NANOSEC_PER_SEC) cannot overflow an u64. + // + // The subsequent division ensures the result fits into u32, since the max result is smaller + // than NANOSEC_PER_SEC. Therefore, just cast it to u32 using `as`. + let sub_second_counter_value = counter_value.0 % frequency; + let nanos = unsafe { sub_second_counter_value.unchecked_mul(u64::from(NANOSEC_PER_SEC)) } + .div(frequency) as u32; + + Duration::new(secs, nanos) } +} - fn uptime(&self) -> Duration { - let current_count: u64 = self.read_cntpct() * NS_PER_S; - let frq: u64 = CNTFRQ_EL0.get() as u64; +fn max_duration() -> Duration { + Duration::from(GenericTimerCounterValue::MAX) +} - Duration::from_nanos(current_count / frq) - } +impl TryFrom for GenericTimerCounterValue { + type Error = &'static str; - fn spin_for(&self, duration: Duration) { - // Instantly return on zero. - if duration.as_nanos() == 0 { - return; + fn try_from(duration: Duration) -> Result { + if duration < resolution() { + return Ok(GenericTimerCounterValue(0)); } - // Calculate the register compare value. - let frq = CNTFRQ_EL0.get(); - let x = match frq.checked_mul(duration.as_nanos() as u64) { - #[allow(unused_imports)] - None => { - warn!("Spin duration too long, skipping"); - return; - } - Some(val) => val, - }; - let tval = x / NS_PER_S; - - // Check if it is within supported bounds. - let warn: Option<&str> = if tval == 0 { - Some("smaller") - // The upper 32 bits of CNTP_TVAL_EL0 are reserved. - } else if tval > u32::max_value().into() { - Some("bigger") - } else { - None - }; - - #[allow(unused_imports)] - if let Some(w) = warn { - warn!( - "Spin duration {} than architecturally supported, skipping", - w - ); - return; + if duration > max_duration() { + return Err("Conversion error. Duration too big"); } - // Set the compare value register. - CNTP_TVAL_EL0.set(tval); + // This is safe, because all the safety requirements as stated in read_volatile()'s + // documentation are fulfilled. + let frequency: u128 = + unsafe { u32::from(core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY)) as u128 }; + let duration: u128 = duration.as_nanos(); - // Kick off the counting. // Disable timer interrupt. - CNTP_CTL_EL0.modify(CNTP_CTL_EL0::ENABLE::SET + CNTP_CTL_EL0::IMASK::SET); + // This is safe, because frequency can never be greater than u32::MAX, and + // (Duration::MAX.as_nanos() * u32::MAX) < u128::MAX. + let counter_value = + unsafe { duration.unchecked_mul(frequency) }.div(NonZeroU128::from(NANOSEC_PER_SEC)); - // ISTATUS will be '1' when cval ticks have passed. Busy-check it. - while !CNTP_CTL_EL0.matches_all(CNTP_CTL_EL0::ISTATUS::SET) {} - - // Disable counting again. - CNTP_CTL_EL0.modify(CNTP_CTL_EL0::ENABLE::CLEAR); + // Since we checked above that we are <= max_duration(), just cast to u64. + Ok(GenericTimerCounterValue(counter_value as u64)) } } + +#[inline(always)] +fn read_cntpct() -> GenericTimerCounterValue { + // Prevent that the counter is read ahead of time due to out-of-order execution. + unsafe { barrier::isb(barrier::SY) }; + let cnt = CNTPCT_EL0.get(); + + GenericTimerCounterValue(cnt) +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +/// The timer's resolution. +pub fn resolution() -> Duration { + Duration::from(GenericTimerCounterValue(1)) +} + +/// The uptime since power-on of the device. +/// +/// This includes time consumed by firmware and bootloaders. +pub fn uptime() -> Duration { + read_cntpct().into() +} + +/// Spin for a given duration. +pub fn spin_for(duration: Duration) { + let curr_counter_value = read_cntpct(); + + let counter_value_delta: GenericTimerCounterValue = match duration.try_into() { + Err(msg) => { + warn!("spin_for: {}. Skipping", msg); + return; + } + Ok(val) => val, + }; + let counter_value_target = curr_counter_value + counter_value_delta; + + // Busy wait. + // + // Read CNTPCT_EL0 directly to avoid the ISB that is part of [`read_cntpct`]. + while GenericTimerCounterValue(CNTPCT_EL0.get()) < counter_value_target {} +} diff --git a/07_timestamps/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs b/07_timestamps/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs index 24958eb5..24e537cf 100644 --- a/07_timestamps/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs +++ b/07_timestamps/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs @@ -140,7 +140,7 @@ impl GPIOInner { /// Disable pull-up/down on pins 14 and 15. #[cfg(feature = "bsp_rpi3")] fn disable_pud_14_15_bcm2837(&mut self) { - use crate::{time, time::interface::TimeManager}; + use crate::time; use core::time::Duration; // The Linux 2837 GPIO driver waits 1 µs between the steps. diff --git a/07_timestamps/src/main.rs b/07_timestamps/src/main.rs index 9ecf3f97..90c39a37 100644 --- a/07_timestamps/src/main.rs +++ b/07_timestamps/src/main.rs @@ -108,9 +108,12 @@ #![allow(clippy::upper_case_acronyms)] #![feature(asm_const)] +#![feature(const_option)] #![feature(format_args_nl)] +#![feature(nonzero_min_max)] #![feature(panic_info_message)] #![feature(trait_alias)] +#![feature(unchecked_math)] #![no_main] #![no_std] @@ -148,7 +151,6 @@ unsafe fn kernel_init() -> ! { fn kernel_main() -> ! { use core::time::Duration; use driver::interface::DriverManager; - use time::interface::TimeManager; info!( "{} version {}", diff --git a/07_timestamps/src/panic_wait.rs b/07_timestamps/src/panic_wait.rs index edd83885..ccf54f61 100644 --- a/07_timestamps/src/panic_wait.rs +++ b/07_timestamps/src/panic_wait.rs @@ -42,8 +42,6 @@ fn panic_prevent_reenter() { #[panic_handler] fn panic(info: &PanicInfo) -> ! { - use crate::time::interface::TimeManager; - // Protect against panic infinite loops if any of the following code panics itself. panic_prevent_reenter(); diff --git a/07_timestamps/src/print.rs b/07_timestamps/src/print.rs index 8705eec0..fe13b334 100644 --- a/07_timestamps/src/print.rs +++ b/07_timestamps/src/print.rs @@ -39,8 +39,6 @@ macro_rules! println { #[macro_export] macro_rules! info { ($string:expr) => ({ - use $crate::time::interface::TimeManager; - let timestamp = $crate::time::time_manager().uptime(); $crate::print::_print(format_args_nl!( @@ -50,8 +48,6 @@ macro_rules! info { )); }); ($format_string:expr, $($arg:tt)*) => ({ - use $crate::time::interface::TimeManager; - let timestamp = $crate::time::time_manager().uptime(); $crate::print::_print(format_args_nl!( @@ -67,8 +63,6 @@ macro_rules! info { #[macro_export] macro_rules! warn { ($string:expr) => ({ - use $crate::time::interface::TimeManager; - let timestamp = $crate::time::time_manager().uptime(); $crate::print::_print(format_args_nl!( @@ -78,8 +72,6 @@ macro_rules! warn { )); }); ($format_string:expr, $($arg:tt)*) => ({ - use $crate::time::interface::TimeManager; - let timestamp = $crate::time::time_manager().uptime(); $crate::print::_print(format_args_nl!( diff --git a/07_timestamps/src/time.rs b/07_timestamps/src/time.rs index 6d92b196..a6c0c5b6 100644 --- a/07_timestamps/src/time.rs +++ b/07_timestamps/src/time.rs @@ -8,30 +8,50 @@ #[path = "_arch/aarch64/time.rs"] mod arch_time; +use core::time::Duration; + //-------------------------------------------------------------------------------------------------- -// Architectural Public Reexports +// Public Definitions //-------------------------------------------------------------------------------------------------- -pub use arch_time::time_manager; + +/// Provides time management functions. +pub struct TimeManager; //-------------------------------------------------------------------------------------------------- -// Public Definitions +// Global instances //-------------------------------------------------------------------------------------------------- -/// Timekeeping interfaces. -pub mod interface { - use core::time::Duration; +static TIME_MANAGER: TimeManager = TimeManager::new(); - /// Time management functions. - pub trait TimeManager { - /// The timer's resolution. - fn resolution(&self) -> Duration; +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- - /// The uptime since power-on of the device. - /// - /// This includes time consumed by firmware and bootloaders. - fn uptime(&self) -> Duration; +/// Return a reference to the global TimeManager. +pub fn time_manager() -> &'static TimeManager { + &TIME_MANAGER +} + +impl TimeManager { + /// Create an instance. + pub const fn new() -> Self { + Self + } + + /// The timer's resolution. + pub fn resolution(&self) -> Duration { + arch_time::resolution() + } + + /// The uptime since power-on of the device. + /// + /// This includes time consumed by firmware and bootloaders. + pub fn uptime(&self) -> Duration { + arch_time::uptime() + } - /// Spin for a given duration. - fn spin_for(&self, duration: Duration); + /// Spin for a given duration. + pub fn spin_for(&self, duration: Duration) { + arch_time::spin_for(duration) } } diff --git a/08_hw_debug_JTAG/src/_arch/aarch64/cpu/boot.s b/08_hw_debug_JTAG/src/_arch/aarch64/cpu/boot.s index 1f70169f..aa701fd1 100644 --- a/08_hw_debug_JTAG/src/_arch/aarch64/cpu/boot.s +++ b/08_hw_debug_JTAG/src/_arch/aarch64/cpu/boot.s @@ -52,6 +52,14 @@ _start: ADR_REL x0, __boot_core_stack_end_exclusive mov sp, x0 + // Read the CPU's timer counter frequency and store it in ARCH_TIMER_COUNTER_FREQUENCY. + // Abort if the frequency read back as 0. + ADR_REL x1, ARCH_TIMER_COUNTER_FREQUENCY // provided by aarch64/time.rs + mrs x2, CNTFRQ_EL0 + cmp x2, xzr + b.eq .L_parking_loop + str w2, [x1] + // Jump to Rust code. b _start_rust diff --git a/08_hw_debug_JTAG/src/_arch/aarch64/time.rs b/08_hw_debug_JTAG/src/_arch/aarch64/time.rs index c814219c..255a5a45 100644 --- a/08_hw_debug_JTAG/src/_arch/aarch64/time.rs +++ b/08_hw_debug_JTAG/src/_arch/aarch64/time.rs @@ -11,111 +11,152 @@ //! //! crate::time::arch_time -use crate::{time, warn}; -use core::time::Duration; +use crate::warn; +use core::{ + num::{NonZeroU128, NonZeroU32, NonZeroU64}, + ops::{Add, Div}, + time::Duration, +}; use cortex_a::{asm::barrier, registers::*}; -use tock_registers::interfaces::{ReadWriteable, Readable, Writeable}; +use tock_registers::interfaces::Readable; //-------------------------------------------------------------------------------------------------- // Private Definitions //-------------------------------------------------------------------------------------------------- -const NS_PER_S: u64 = 1_000_000_000; +const NANOSEC_PER_SEC: NonZeroU64 = NonZeroU64::new(1_000_000_000).unwrap(); -/// ARMv8 Generic Timer. -struct GenericTimer; +#[derive(Copy, Clone, PartialOrd, PartialEq)] +struct GenericTimerCounterValue(u64); //-------------------------------------------------------------------------------------------------- // Global instances //-------------------------------------------------------------------------------------------------- -static TIME_MANAGER: GenericTimer = GenericTimer; +/// Boot assembly code overwrites this value with the value of CNTFRQ_EL0 before any Rust code is +/// executed. This given value here is just a (safe) dummy. +#[no_mangle] +static ARCH_TIMER_COUNTER_FREQUENCY: NonZeroU32 = NonZeroU32::MIN; //-------------------------------------------------------------------------------------------------- // Private Code //-------------------------------------------------------------------------------------------------- -impl GenericTimer { - #[inline(always)] - fn read_cntpct(&self) -> u64 { - // Prevent that the counter is read ahead of time due to out-of-order execution. - unsafe { barrier::isb(barrier::SY) }; - CNTPCT_EL0.get() - } +impl GenericTimerCounterValue { + pub const MAX: Self = GenericTimerCounterValue(u64::MAX); } -//-------------------------------------------------------------------------------------------------- -// Public Code -//-------------------------------------------------------------------------------------------------- +impl Add for GenericTimerCounterValue { + type Output = Self; -/// Return a reference to the time manager. -pub fn time_manager() -> &'static impl time::interface::TimeManager { - &TIME_MANAGER + fn add(self, other: Self) -> Self { + GenericTimerCounterValue(self.0.wrapping_add(other.0)) + } } -//------------------------------------------------------------------------------ -// OS Interface Code -//------------------------------------------------------------------------------ +impl From for Duration { + fn from(counter_value: GenericTimerCounterValue) -> Self { + if counter_value.0 == 0 { + return Duration::ZERO; + } -impl time::interface::TimeManager for GenericTimer { - fn resolution(&self) -> Duration { - Duration::from_nanos(NS_PER_S / (CNTFRQ_EL0.get() as u64)) + // Read volatile is needed here to prevent the compiler from optimizing + // ARCH_TIMER_COUNTER_FREQUENCY away. + // + // This is safe, because all the safety requirements as stated in read_volatile()'s + // documentation are fulfilled. + let frequency: NonZeroU64 = + unsafe { core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY) }.into(); + + // Div implementation for u64 cannot panic. + let secs = counter_value.0.div(frequency); + + // This is safe, because frequency can never be greater than u32::MAX, which means the + // largest theoretical value for sub_second_counter_value is (u32::MAX - 1). Therefore, + // (sub_second_counter_value * NANOSEC_PER_SEC) cannot overflow an u64. + // + // The subsequent division ensures the result fits into u32, since the max result is smaller + // than NANOSEC_PER_SEC. Therefore, just cast it to u32 using `as`. + let sub_second_counter_value = counter_value.0 % frequency; + let nanos = unsafe { sub_second_counter_value.unchecked_mul(u64::from(NANOSEC_PER_SEC)) } + .div(frequency) as u32; + + Duration::new(secs, nanos) } +} - fn uptime(&self) -> Duration { - let current_count: u64 = self.read_cntpct() * NS_PER_S; - let frq: u64 = CNTFRQ_EL0.get() as u64; +fn max_duration() -> Duration { + Duration::from(GenericTimerCounterValue::MAX) +} - Duration::from_nanos(current_count / frq) - } +impl TryFrom for GenericTimerCounterValue { + type Error = &'static str; - fn spin_for(&self, duration: Duration) { - // Instantly return on zero. - if duration.as_nanos() == 0 { - return; + fn try_from(duration: Duration) -> Result { + if duration < resolution() { + return Ok(GenericTimerCounterValue(0)); } - // Calculate the register compare value. - let frq = CNTFRQ_EL0.get(); - let x = match frq.checked_mul(duration.as_nanos() as u64) { - #[allow(unused_imports)] - None => { - warn!("Spin duration too long, skipping"); - return; - } - Some(val) => val, - }; - let tval = x / NS_PER_S; - - // Check if it is within supported bounds. - let warn: Option<&str> = if tval == 0 { - Some("smaller") - // The upper 32 bits of CNTP_TVAL_EL0 are reserved. - } else if tval > u32::max_value().into() { - Some("bigger") - } else { - None - }; - - #[allow(unused_imports)] - if let Some(w) = warn { - warn!( - "Spin duration {} than architecturally supported, skipping", - w - ); - return; + if duration > max_duration() { + return Err("Conversion error. Duration too big"); } - // Set the compare value register. - CNTP_TVAL_EL0.set(tval); + // This is safe, because all the safety requirements as stated in read_volatile()'s + // documentation are fulfilled. + let frequency: u128 = + unsafe { u32::from(core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY)) as u128 }; + let duration: u128 = duration.as_nanos(); - // Kick off the counting. // Disable timer interrupt. - CNTP_CTL_EL0.modify(CNTP_CTL_EL0::ENABLE::SET + CNTP_CTL_EL0::IMASK::SET); + // This is safe, because frequency can never be greater than u32::MAX, and + // (Duration::MAX.as_nanos() * u32::MAX) < u128::MAX. + let counter_value = + unsafe { duration.unchecked_mul(frequency) }.div(NonZeroU128::from(NANOSEC_PER_SEC)); - // ISTATUS will be '1' when cval ticks have passed. Busy-check it. - while !CNTP_CTL_EL0.matches_all(CNTP_CTL_EL0::ISTATUS::SET) {} - - // Disable counting again. - CNTP_CTL_EL0.modify(CNTP_CTL_EL0::ENABLE::CLEAR); + // Since we checked above that we are <= max_duration(), just cast to u64. + Ok(GenericTimerCounterValue(counter_value as u64)) } } + +#[inline(always)] +fn read_cntpct() -> GenericTimerCounterValue { + // Prevent that the counter is read ahead of time due to out-of-order execution. + unsafe { barrier::isb(barrier::SY) }; + let cnt = CNTPCT_EL0.get(); + + GenericTimerCounterValue(cnt) +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +/// The timer's resolution. +pub fn resolution() -> Duration { + Duration::from(GenericTimerCounterValue(1)) +} + +/// The uptime since power-on of the device. +/// +/// This includes time consumed by firmware and bootloaders. +pub fn uptime() -> Duration { + read_cntpct().into() +} + +/// Spin for a given duration. +pub fn spin_for(duration: Duration) { + let curr_counter_value = read_cntpct(); + + let counter_value_delta: GenericTimerCounterValue = match duration.try_into() { + Err(msg) => { + warn!("spin_for: {}. Skipping", msg); + return; + } + Ok(val) => val, + }; + let counter_value_target = curr_counter_value + counter_value_delta; + + // Busy wait. + // + // Read CNTPCT_EL0 directly to avoid the ISB that is part of [`read_cntpct`]. + while GenericTimerCounterValue(CNTPCT_EL0.get()) < counter_value_target {} +} diff --git a/08_hw_debug_JTAG/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs b/08_hw_debug_JTAG/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs index 24958eb5..24e537cf 100644 --- a/08_hw_debug_JTAG/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs +++ b/08_hw_debug_JTAG/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs @@ -140,7 +140,7 @@ impl GPIOInner { /// Disable pull-up/down on pins 14 and 15. #[cfg(feature = "bsp_rpi3")] fn disable_pud_14_15_bcm2837(&mut self) { - use crate::{time, time::interface::TimeManager}; + use crate::time; use core::time::Duration; // The Linux 2837 GPIO driver waits 1 µs between the steps. diff --git a/08_hw_debug_JTAG/src/main.rs b/08_hw_debug_JTAG/src/main.rs index 9ecf3f97..90c39a37 100644 --- a/08_hw_debug_JTAG/src/main.rs +++ b/08_hw_debug_JTAG/src/main.rs @@ -108,9 +108,12 @@ #![allow(clippy::upper_case_acronyms)] #![feature(asm_const)] +#![feature(const_option)] #![feature(format_args_nl)] +#![feature(nonzero_min_max)] #![feature(panic_info_message)] #![feature(trait_alias)] +#![feature(unchecked_math)] #![no_main] #![no_std] @@ -148,7 +151,6 @@ unsafe fn kernel_init() -> ! { fn kernel_main() -> ! { use core::time::Duration; use driver::interface::DriverManager; - use time::interface::TimeManager; info!( "{} version {}", diff --git a/08_hw_debug_JTAG/src/panic_wait.rs b/08_hw_debug_JTAG/src/panic_wait.rs index edd83885..ccf54f61 100644 --- a/08_hw_debug_JTAG/src/panic_wait.rs +++ b/08_hw_debug_JTAG/src/panic_wait.rs @@ -42,8 +42,6 @@ fn panic_prevent_reenter() { #[panic_handler] fn panic(info: &PanicInfo) -> ! { - use crate::time::interface::TimeManager; - // Protect against panic infinite loops if any of the following code panics itself. panic_prevent_reenter(); diff --git a/08_hw_debug_JTAG/src/print.rs b/08_hw_debug_JTAG/src/print.rs index 8705eec0..fe13b334 100644 --- a/08_hw_debug_JTAG/src/print.rs +++ b/08_hw_debug_JTAG/src/print.rs @@ -39,8 +39,6 @@ macro_rules! println { #[macro_export] macro_rules! info { ($string:expr) => ({ - use $crate::time::interface::TimeManager; - let timestamp = $crate::time::time_manager().uptime(); $crate::print::_print(format_args_nl!( @@ -50,8 +48,6 @@ macro_rules! info { )); }); ($format_string:expr, $($arg:tt)*) => ({ - use $crate::time::interface::TimeManager; - let timestamp = $crate::time::time_manager().uptime(); $crate::print::_print(format_args_nl!( @@ -67,8 +63,6 @@ macro_rules! info { #[macro_export] macro_rules! warn { ($string:expr) => ({ - use $crate::time::interface::TimeManager; - let timestamp = $crate::time::time_manager().uptime(); $crate::print::_print(format_args_nl!( @@ -78,8 +72,6 @@ macro_rules! warn { )); }); ($format_string:expr, $($arg:tt)*) => ({ - use $crate::time::interface::TimeManager; - let timestamp = $crate::time::time_manager().uptime(); $crate::print::_print(format_args_nl!( diff --git a/08_hw_debug_JTAG/src/time.rs b/08_hw_debug_JTAG/src/time.rs index 6d92b196..a6c0c5b6 100644 --- a/08_hw_debug_JTAG/src/time.rs +++ b/08_hw_debug_JTAG/src/time.rs @@ -8,30 +8,50 @@ #[path = "_arch/aarch64/time.rs"] mod arch_time; +use core::time::Duration; + //-------------------------------------------------------------------------------------------------- -// Architectural Public Reexports +// Public Definitions //-------------------------------------------------------------------------------------------------- -pub use arch_time::time_manager; + +/// Provides time management functions. +pub struct TimeManager; //-------------------------------------------------------------------------------------------------- -// Public Definitions +// Global instances //-------------------------------------------------------------------------------------------------- -/// Timekeeping interfaces. -pub mod interface { - use core::time::Duration; +static TIME_MANAGER: TimeManager = TimeManager::new(); - /// Time management functions. - pub trait TimeManager { - /// The timer's resolution. - fn resolution(&self) -> Duration; +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- - /// The uptime since power-on of the device. - /// - /// This includes time consumed by firmware and bootloaders. - fn uptime(&self) -> Duration; +/// Return a reference to the global TimeManager. +pub fn time_manager() -> &'static TimeManager { + &TIME_MANAGER +} + +impl TimeManager { + /// Create an instance. + pub const fn new() -> Self { + Self + } + + /// The timer's resolution. + pub fn resolution(&self) -> Duration { + arch_time::resolution() + } + + /// The uptime since power-on of the device. + /// + /// This includes time consumed by firmware and bootloaders. + pub fn uptime(&self) -> Duration { + arch_time::uptime() + } - /// Spin for a given duration. - fn spin_for(&self, duration: Duration); + /// Spin for a given duration. + pub fn spin_for(&self, duration: Duration) { + arch_time::spin_for(duration) } } diff --git a/09_privilege_level/README.md b/09_privilege_level/README.md index dcf0f929..afcfe8f6 100644 --- a/09_privilege_level/README.md +++ b/09_privilege_level/README.md @@ -303,7 +303,7 @@ diff -uNr 08_hw_debug_JTAG/src/_arch/aarch64/cpu/boot.s 09_privilege_level/src/_ // Only proceed on the boot core. Park it otherwise. mrs x1, MPIDR_EL1 and x1, x1, {CONST_CORE_ID_MASK} -@@ -48,11 +53,11 @@ +@@ -48,7 +53,7 @@ // Prepare the jump to Rust code. .L_prepare_rust: @@ -312,6 +312,10 @@ diff -uNr 08_hw_debug_JTAG/src/_arch/aarch64/cpu/boot.s 09_privilege_level/src/_ ADR_REL x0, __boot_core_stack_end_exclusive mov sp, x0 +@@ -60,7 +65,7 @@ + b.eq .L_parking_loop + str w2, [x1] + - // Jump to Rust code. + // Jump to Rust code. x0 holds the function argument provided to _start_rust(). b _start_rust @@ -498,7 +502,7 @@ diff -uNr 08_hw_debug_JTAG/src/exception.rs 09_privilege_level/src/exception.rs diff -uNr 08_hw_debug_JTAG/src/main.rs 09_privilege_level/src/main.rs --- 08_hw_debug_JTAG/src/main.rs +++ 09_privilege_level/src/main.rs -@@ -118,6 +118,7 @@ +@@ -121,6 +121,7 @@ mod console; mod cpu; mod driver; @@ -506,15 +510,15 @@ diff -uNr 08_hw_debug_JTAG/src/main.rs 09_privilege_level/src/main.rs mod panic_wait; mod print; mod synchronization; -@@ -146,6 +147,7 @@ +@@ -149,6 +150,7 @@ /// The main function running after the early init. fn kernel_main() -> ! { + use console::console; use core::time::Duration; use driver::interface::DriverManager; - use time::interface::TimeManager; -@@ -157,6 +159,12 @@ + +@@ -159,6 +161,12 @@ ); info!("Booting on: {}", bsp::board_name()); @@ -527,7 +531,7 @@ diff -uNr 08_hw_debug_JTAG/src/main.rs 09_privilege_level/src/main.rs info!( "Architectural timer resolution: {} ns", time::time_manager().resolution().as_nanos() -@@ -171,11 +179,15 @@ +@@ -173,11 +181,15 @@ info!(" {}. {}", i + 1, driver.compatible()); } diff --git a/09_privilege_level/src/_arch/aarch64/cpu/boot.s b/09_privilege_level/src/_arch/aarch64/cpu/boot.s index 7576dc14..f6df2123 100644 --- a/09_privilege_level/src/_arch/aarch64/cpu/boot.s +++ b/09_privilege_level/src/_arch/aarch64/cpu/boot.s @@ -57,6 +57,14 @@ _start: ADR_REL x0, __boot_core_stack_end_exclusive mov sp, x0 + // Read the CPU's timer counter frequency and store it in ARCH_TIMER_COUNTER_FREQUENCY. + // Abort if the frequency read back as 0. + ADR_REL x1, ARCH_TIMER_COUNTER_FREQUENCY // provided by aarch64/time.rs + mrs x2, CNTFRQ_EL0 + cmp x2, xzr + b.eq .L_parking_loop + str w2, [x1] + // Jump to Rust code. x0 holds the function argument provided to _start_rust(). b _start_rust diff --git a/09_privilege_level/src/_arch/aarch64/time.rs b/09_privilege_level/src/_arch/aarch64/time.rs index c814219c..255a5a45 100644 --- a/09_privilege_level/src/_arch/aarch64/time.rs +++ b/09_privilege_level/src/_arch/aarch64/time.rs @@ -11,111 +11,152 @@ //! //! crate::time::arch_time -use crate::{time, warn}; -use core::time::Duration; +use crate::warn; +use core::{ + num::{NonZeroU128, NonZeroU32, NonZeroU64}, + ops::{Add, Div}, + time::Duration, +}; use cortex_a::{asm::barrier, registers::*}; -use tock_registers::interfaces::{ReadWriteable, Readable, Writeable}; +use tock_registers::interfaces::Readable; //-------------------------------------------------------------------------------------------------- // Private Definitions //-------------------------------------------------------------------------------------------------- -const NS_PER_S: u64 = 1_000_000_000; +const NANOSEC_PER_SEC: NonZeroU64 = NonZeroU64::new(1_000_000_000).unwrap(); -/// ARMv8 Generic Timer. -struct GenericTimer; +#[derive(Copy, Clone, PartialOrd, PartialEq)] +struct GenericTimerCounterValue(u64); //-------------------------------------------------------------------------------------------------- // Global instances //-------------------------------------------------------------------------------------------------- -static TIME_MANAGER: GenericTimer = GenericTimer; +/// Boot assembly code overwrites this value with the value of CNTFRQ_EL0 before any Rust code is +/// executed. This given value here is just a (safe) dummy. +#[no_mangle] +static ARCH_TIMER_COUNTER_FREQUENCY: NonZeroU32 = NonZeroU32::MIN; //-------------------------------------------------------------------------------------------------- // Private Code //-------------------------------------------------------------------------------------------------- -impl GenericTimer { - #[inline(always)] - fn read_cntpct(&self) -> u64 { - // Prevent that the counter is read ahead of time due to out-of-order execution. - unsafe { barrier::isb(barrier::SY) }; - CNTPCT_EL0.get() - } +impl GenericTimerCounterValue { + pub const MAX: Self = GenericTimerCounterValue(u64::MAX); } -//-------------------------------------------------------------------------------------------------- -// Public Code -//-------------------------------------------------------------------------------------------------- +impl Add for GenericTimerCounterValue { + type Output = Self; -/// Return a reference to the time manager. -pub fn time_manager() -> &'static impl time::interface::TimeManager { - &TIME_MANAGER + fn add(self, other: Self) -> Self { + GenericTimerCounterValue(self.0.wrapping_add(other.0)) + } } -//------------------------------------------------------------------------------ -// OS Interface Code -//------------------------------------------------------------------------------ +impl From for Duration { + fn from(counter_value: GenericTimerCounterValue) -> Self { + if counter_value.0 == 0 { + return Duration::ZERO; + } -impl time::interface::TimeManager for GenericTimer { - fn resolution(&self) -> Duration { - Duration::from_nanos(NS_PER_S / (CNTFRQ_EL0.get() as u64)) + // Read volatile is needed here to prevent the compiler from optimizing + // ARCH_TIMER_COUNTER_FREQUENCY away. + // + // This is safe, because all the safety requirements as stated in read_volatile()'s + // documentation are fulfilled. + let frequency: NonZeroU64 = + unsafe { core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY) }.into(); + + // Div implementation for u64 cannot panic. + let secs = counter_value.0.div(frequency); + + // This is safe, because frequency can never be greater than u32::MAX, which means the + // largest theoretical value for sub_second_counter_value is (u32::MAX - 1). Therefore, + // (sub_second_counter_value * NANOSEC_PER_SEC) cannot overflow an u64. + // + // The subsequent division ensures the result fits into u32, since the max result is smaller + // than NANOSEC_PER_SEC. Therefore, just cast it to u32 using `as`. + let sub_second_counter_value = counter_value.0 % frequency; + let nanos = unsafe { sub_second_counter_value.unchecked_mul(u64::from(NANOSEC_PER_SEC)) } + .div(frequency) as u32; + + Duration::new(secs, nanos) } +} - fn uptime(&self) -> Duration { - let current_count: u64 = self.read_cntpct() * NS_PER_S; - let frq: u64 = CNTFRQ_EL0.get() as u64; +fn max_duration() -> Duration { + Duration::from(GenericTimerCounterValue::MAX) +} - Duration::from_nanos(current_count / frq) - } +impl TryFrom for GenericTimerCounterValue { + type Error = &'static str; - fn spin_for(&self, duration: Duration) { - // Instantly return on zero. - if duration.as_nanos() == 0 { - return; + fn try_from(duration: Duration) -> Result { + if duration < resolution() { + return Ok(GenericTimerCounterValue(0)); } - // Calculate the register compare value. - let frq = CNTFRQ_EL0.get(); - let x = match frq.checked_mul(duration.as_nanos() as u64) { - #[allow(unused_imports)] - None => { - warn!("Spin duration too long, skipping"); - return; - } - Some(val) => val, - }; - let tval = x / NS_PER_S; - - // Check if it is within supported bounds. - let warn: Option<&str> = if tval == 0 { - Some("smaller") - // The upper 32 bits of CNTP_TVAL_EL0 are reserved. - } else if tval > u32::max_value().into() { - Some("bigger") - } else { - None - }; - - #[allow(unused_imports)] - if let Some(w) = warn { - warn!( - "Spin duration {} than architecturally supported, skipping", - w - ); - return; + if duration > max_duration() { + return Err("Conversion error. Duration too big"); } - // Set the compare value register. - CNTP_TVAL_EL0.set(tval); + // This is safe, because all the safety requirements as stated in read_volatile()'s + // documentation are fulfilled. + let frequency: u128 = + unsafe { u32::from(core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY)) as u128 }; + let duration: u128 = duration.as_nanos(); - // Kick off the counting. // Disable timer interrupt. - CNTP_CTL_EL0.modify(CNTP_CTL_EL0::ENABLE::SET + CNTP_CTL_EL0::IMASK::SET); + // This is safe, because frequency can never be greater than u32::MAX, and + // (Duration::MAX.as_nanos() * u32::MAX) < u128::MAX. + let counter_value = + unsafe { duration.unchecked_mul(frequency) }.div(NonZeroU128::from(NANOSEC_PER_SEC)); - // ISTATUS will be '1' when cval ticks have passed. Busy-check it. - while !CNTP_CTL_EL0.matches_all(CNTP_CTL_EL0::ISTATUS::SET) {} - - // Disable counting again. - CNTP_CTL_EL0.modify(CNTP_CTL_EL0::ENABLE::CLEAR); + // Since we checked above that we are <= max_duration(), just cast to u64. + Ok(GenericTimerCounterValue(counter_value as u64)) } } + +#[inline(always)] +fn read_cntpct() -> GenericTimerCounterValue { + // Prevent that the counter is read ahead of time due to out-of-order execution. + unsafe { barrier::isb(barrier::SY) }; + let cnt = CNTPCT_EL0.get(); + + GenericTimerCounterValue(cnt) +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +/// The timer's resolution. +pub fn resolution() -> Duration { + Duration::from(GenericTimerCounterValue(1)) +} + +/// The uptime since power-on of the device. +/// +/// This includes time consumed by firmware and bootloaders. +pub fn uptime() -> Duration { + read_cntpct().into() +} + +/// Spin for a given duration. +pub fn spin_for(duration: Duration) { + let curr_counter_value = read_cntpct(); + + let counter_value_delta: GenericTimerCounterValue = match duration.try_into() { + Err(msg) => { + warn!("spin_for: {}. Skipping", msg); + return; + } + Ok(val) => val, + }; + let counter_value_target = curr_counter_value + counter_value_delta; + + // Busy wait. + // + // Read CNTPCT_EL0 directly to avoid the ISB that is part of [`read_cntpct`]. + while GenericTimerCounterValue(CNTPCT_EL0.get()) < counter_value_target {} +} diff --git a/09_privilege_level/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs b/09_privilege_level/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs index 24958eb5..24e537cf 100644 --- a/09_privilege_level/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs +++ b/09_privilege_level/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs @@ -140,7 +140,7 @@ impl GPIOInner { /// Disable pull-up/down on pins 14 and 15. #[cfg(feature = "bsp_rpi3")] fn disable_pud_14_15_bcm2837(&mut self) { - use crate::{time, time::interface::TimeManager}; + use crate::time; use core::time::Duration; // The Linux 2837 GPIO driver waits 1 µs between the steps. diff --git a/09_privilege_level/src/main.rs b/09_privilege_level/src/main.rs index 6c1ab310..79a6716e 100644 --- a/09_privilege_level/src/main.rs +++ b/09_privilege_level/src/main.rs @@ -108,9 +108,12 @@ #![allow(clippy::upper_case_acronyms)] #![feature(asm_const)] +#![feature(const_option)] #![feature(format_args_nl)] +#![feature(nonzero_min_max)] #![feature(panic_info_message)] #![feature(trait_alias)] +#![feature(unchecked_math)] #![no_main] #![no_std] @@ -150,7 +153,6 @@ fn kernel_main() -> ! { use console::console; use core::time::Duration; use driver::interface::DriverManager; - use time::interface::TimeManager; info!( "{} version {}", diff --git a/09_privilege_level/src/panic_wait.rs b/09_privilege_level/src/panic_wait.rs index edd83885..ccf54f61 100644 --- a/09_privilege_level/src/panic_wait.rs +++ b/09_privilege_level/src/panic_wait.rs @@ -42,8 +42,6 @@ fn panic_prevent_reenter() { #[panic_handler] fn panic(info: &PanicInfo) -> ! { - use crate::time::interface::TimeManager; - // Protect against panic infinite loops if any of the following code panics itself. panic_prevent_reenter(); diff --git a/09_privilege_level/src/print.rs b/09_privilege_level/src/print.rs index 8705eec0..fe13b334 100644 --- a/09_privilege_level/src/print.rs +++ b/09_privilege_level/src/print.rs @@ -39,8 +39,6 @@ macro_rules! println { #[macro_export] macro_rules! info { ($string:expr) => ({ - use $crate::time::interface::TimeManager; - let timestamp = $crate::time::time_manager().uptime(); $crate::print::_print(format_args_nl!( @@ -50,8 +48,6 @@ macro_rules! info { )); }); ($format_string:expr, $($arg:tt)*) => ({ - use $crate::time::interface::TimeManager; - let timestamp = $crate::time::time_manager().uptime(); $crate::print::_print(format_args_nl!( @@ -67,8 +63,6 @@ macro_rules! info { #[macro_export] macro_rules! warn { ($string:expr) => ({ - use $crate::time::interface::TimeManager; - let timestamp = $crate::time::time_manager().uptime(); $crate::print::_print(format_args_nl!( @@ -78,8 +72,6 @@ macro_rules! warn { )); }); ($format_string:expr, $($arg:tt)*) => ({ - use $crate::time::interface::TimeManager; - let timestamp = $crate::time::time_manager().uptime(); $crate::print::_print(format_args_nl!( diff --git a/09_privilege_level/src/time.rs b/09_privilege_level/src/time.rs index 6d92b196..a6c0c5b6 100644 --- a/09_privilege_level/src/time.rs +++ b/09_privilege_level/src/time.rs @@ -8,30 +8,50 @@ #[path = "_arch/aarch64/time.rs"] mod arch_time; +use core::time::Duration; + //-------------------------------------------------------------------------------------------------- -// Architectural Public Reexports +// Public Definitions //-------------------------------------------------------------------------------------------------- -pub use arch_time::time_manager; + +/// Provides time management functions. +pub struct TimeManager; //-------------------------------------------------------------------------------------------------- -// Public Definitions +// Global instances //-------------------------------------------------------------------------------------------------- -/// Timekeeping interfaces. -pub mod interface { - use core::time::Duration; +static TIME_MANAGER: TimeManager = TimeManager::new(); - /// Time management functions. - pub trait TimeManager { - /// The timer's resolution. - fn resolution(&self) -> Duration; +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- - /// The uptime since power-on of the device. - /// - /// This includes time consumed by firmware and bootloaders. - fn uptime(&self) -> Duration; +/// Return a reference to the global TimeManager. +pub fn time_manager() -> &'static TimeManager { + &TIME_MANAGER +} + +impl TimeManager { + /// Create an instance. + pub const fn new() -> Self { + Self + } + + /// The timer's resolution. + pub fn resolution(&self) -> Duration { + arch_time::resolution() + } + + /// The uptime since power-on of the device. + /// + /// This includes time consumed by firmware and bootloaders. + pub fn uptime(&self) -> Duration { + arch_time::uptime() + } - /// Spin for a given duration. - fn spin_for(&self, duration: Duration); + /// Spin for a given duration. + pub fn spin_for(&self, duration: Duration) { + arch_time::spin_for(duration) } } diff --git a/10_virtual_mem_part1_identity_mapping/README.md b/10_virtual_mem_part1_identity_mapping/README.md index 8345aef0..f1d22d98 100644 --- a/10_virtual_mem_part1_identity_mapping/README.md +++ b/10_virtual_mem_part1_identity_mapping/README.md @@ -1109,18 +1109,20 @@ diff -uNr 09_privilege_level/src/common.rs 10_virtual_mem_part1_identity_mapping diff -uNr 09_privilege_level/src/main.rs 10_virtual_mem_part1_identity_mapping/src/main.rs --- 09_privilege_level/src/main.rs +++ 10_virtual_mem_part1_identity_mapping/src/main.rs -@@ -107,18 +107,23 @@ +@@ -107,9 +107,12 @@ //! 2. Once finished with architectural setup, the arch code calls `kernel_init()`. #![allow(clippy::upper_case_acronyms)] +#![allow(incomplete_features)] #![feature(asm_const)] + #![feature(const_option)] +#![feature(core_intrinsics)] #![feature(format_args_nl)] +#![feature(int_roundings)] + #![feature(nonzero_min_max)] #![feature(panic_info_message)] #![feature(trait_alias)] - #![no_main] +@@ -118,10 +121,12 @@ #![no_std] mod bsp; @@ -1133,7 +1135,7 @@ diff -uNr 09_privilege_level/src/main.rs 10_virtual_mem_part1_identity_mapping/s mod panic_wait; mod print; mod synchronization; -@@ -129,9 +134,17 @@ +@@ -132,9 +137,17 @@ /// # Safety /// /// - Only a single core must be active and running this function. @@ -1152,7 +1154,7 @@ diff -uNr 09_privilege_level/src/main.rs 10_virtual_mem_part1_identity_mapping/s for i in bsp::driver::driver_manager().all_device_drivers().iter() { if let Err(x) = i.init() { -@@ -147,7 +160,7 @@ +@@ -150,7 +163,7 @@ /// The main function running after the early init. fn kernel_main() -> ! { @@ -1160,8 +1162,8 @@ diff -uNr 09_privilege_level/src/main.rs 10_virtual_mem_part1_identity_mapping/s + use console::{console, interface::Write}; use core::time::Duration; use driver::interface::DriverManager; - use time::interface::TimeManager; -@@ -159,6 +172,9 @@ + +@@ -161,6 +174,9 @@ ); info!("Booting on: {}", bsp::board_name()); @@ -1171,7 +1173,7 @@ diff -uNr 09_privilege_level/src/main.rs 10_virtual_mem_part1_identity_mapping/s let (_, privilege_level) = exception::current_privilege_level(); info!("Current privilege level: {}", privilege_level); -@@ -182,6 +198,13 @@ +@@ -184,6 +200,13 @@ info!("Timer test, spinning for 1 second"); time::time_manager().spin_for(Duration::from_secs(1)); diff --git a/10_virtual_mem_part1_identity_mapping/src/_arch/aarch64/cpu/boot.s b/10_virtual_mem_part1_identity_mapping/src/_arch/aarch64/cpu/boot.s index 7576dc14..f6df2123 100644 --- a/10_virtual_mem_part1_identity_mapping/src/_arch/aarch64/cpu/boot.s +++ b/10_virtual_mem_part1_identity_mapping/src/_arch/aarch64/cpu/boot.s @@ -57,6 +57,14 @@ _start: ADR_REL x0, __boot_core_stack_end_exclusive mov sp, x0 + // Read the CPU's timer counter frequency and store it in ARCH_TIMER_COUNTER_FREQUENCY. + // Abort if the frequency read back as 0. + ADR_REL x1, ARCH_TIMER_COUNTER_FREQUENCY // provided by aarch64/time.rs + mrs x2, CNTFRQ_EL0 + cmp x2, xzr + b.eq .L_parking_loop + str w2, [x1] + // Jump to Rust code. x0 holds the function argument provided to _start_rust(). b _start_rust diff --git a/10_virtual_mem_part1_identity_mapping/src/_arch/aarch64/time.rs b/10_virtual_mem_part1_identity_mapping/src/_arch/aarch64/time.rs index c814219c..255a5a45 100644 --- a/10_virtual_mem_part1_identity_mapping/src/_arch/aarch64/time.rs +++ b/10_virtual_mem_part1_identity_mapping/src/_arch/aarch64/time.rs @@ -11,111 +11,152 @@ //! //! crate::time::arch_time -use crate::{time, warn}; -use core::time::Duration; +use crate::warn; +use core::{ + num::{NonZeroU128, NonZeroU32, NonZeroU64}, + ops::{Add, Div}, + time::Duration, +}; use cortex_a::{asm::barrier, registers::*}; -use tock_registers::interfaces::{ReadWriteable, Readable, Writeable}; +use tock_registers::interfaces::Readable; //-------------------------------------------------------------------------------------------------- // Private Definitions //-------------------------------------------------------------------------------------------------- -const NS_PER_S: u64 = 1_000_000_000; +const NANOSEC_PER_SEC: NonZeroU64 = NonZeroU64::new(1_000_000_000).unwrap(); -/// ARMv8 Generic Timer. -struct GenericTimer; +#[derive(Copy, Clone, PartialOrd, PartialEq)] +struct GenericTimerCounterValue(u64); //-------------------------------------------------------------------------------------------------- // Global instances //-------------------------------------------------------------------------------------------------- -static TIME_MANAGER: GenericTimer = GenericTimer; +/// Boot assembly code overwrites this value with the value of CNTFRQ_EL0 before any Rust code is +/// executed. This given value here is just a (safe) dummy. +#[no_mangle] +static ARCH_TIMER_COUNTER_FREQUENCY: NonZeroU32 = NonZeroU32::MIN; //-------------------------------------------------------------------------------------------------- // Private Code //-------------------------------------------------------------------------------------------------- -impl GenericTimer { - #[inline(always)] - fn read_cntpct(&self) -> u64 { - // Prevent that the counter is read ahead of time due to out-of-order execution. - unsafe { barrier::isb(barrier::SY) }; - CNTPCT_EL0.get() - } +impl GenericTimerCounterValue { + pub const MAX: Self = GenericTimerCounterValue(u64::MAX); } -//-------------------------------------------------------------------------------------------------- -// Public Code -//-------------------------------------------------------------------------------------------------- +impl Add for GenericTimerCounterValue { + type Output = Self; -/// Return a reference to the time manager. -pub fn time_manager() -> &'static impl time::interface::TimeManager { - &TIME_MANAGER + fn add(self, other: Self) -> Self { + GenericTimerCounterValue(self.0.wrapping_add(other.0)) + } } -//------------------------------------------------------------------------------ -// OS Interface Code -//------------------------------------------------------------------------------ +impl From for Duration { + fn from(counter_value: GenericTimerCounterValue) -> Self { + if counter_value.0 == 0 { + return Duration::ZERO; + } -impl time::interface::TimeManager for GenericTimer { - fn resolution(&self) -> Duration { - Duration::from_nanos(NS_PER_S / (CNTFRQ_EL0.get() as u64)) + // Read volatile is needed here to prevent the compiler from optimizing + // ARCH_TIMER_COUNTER_FREQUENCY away. + // + // This is safe, because all the safety requirements as stated in read_volatile()'s + // documentation are fulfilled. + let frequency: NonZeroU64 = + unsafe { core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY) }.into(); + + // Div implementation for u64 cannot panic. + let secs = counter_value.0.div(frequency); + + // This is safe, because frequency can never be greater than u32::MAX, which means the + // largest theoretical value for sub_second_counter_value is (u32::MAX - 1). Therefore, + // (sub_second_counter_value * NANOSEC_PER_SEC) cannot overflow an u64. + // + // The subsequent division ensures the result fits into u32, since the max result is smaller + // than NANOSEC_PER_SEC. Therefore, just cast it to u32 using `as`. + let sub_second_counter_value = counter_value.0 % frequency; + let nanos = unsafe { sub_second_counter_value.unchecked_mul(u64::from(NANOSEC_PER_SEC)) } + .div(frequency) as u32; + + Duration::new(secs, nanos) } +} - fn uptime(&self) -> Duration { - let current_count: u64 = self.read_cntpct() * NS_PER_S; - let frq: u64 = CNTFRQ_EL0.get() as u64; +fn max_duration() -> Duration { + Duration::from(GenericTimerCounterValue::MAX) +} - Duration::from_nanos(current_count / frq) - } +impl TryFrom for GenericTimerCounterValue { + type Error = &'static str; - fn spin_for(&self, duration: Duration) { - // Instantly return on zero. - if duration.as_nanos() == 0 { - return; + fn try_from(duration: Duration) -> Result { + if duration < resolution() { + return Ok(GenericTimerCounterValue(0)); } - // Calculate the register compare value. - let frq = CNTFRQ_EL0.get(); - let x = match frq.checked_mul(duration.as_nanos() as u64) { - #[allow(unused_imports)] - None => { - warn!("Spin duration too long, skipping"); - return; - } - Some(val) => val, - }; - let tval = x / NS_PER_S; - - // Check if it is within supported bounds. - let warn: Option<&str> = if tval == 0 { - Some("smaller") - // The upper 32 bits of CNTP_TVAL_EL0 are reserved. - } else if tval > u32::max_value().into() { - Some("bigger") - } else { - None - }; - - #[allow(unused_imports)] - if let Some(w) = warn { - warn!( - "Spin duration {} than architecturally supported, skipping", - w - ); - return; + if duration > max_duration() { + return Err("Conversion error. Duration too big"); } - // Set the compare value register. - CNTP_TVAL_EL0.set(tval); + // This is safe, because all the safety requirements as stated in read_volatile()'s + // documentation are fulfilled. + let frequency: u128 = + unsafe { u32::from(core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY)) as u128 }; + let duration: u128 = duration.as_nanos(); - // Kick off the counting. // Disable timer interrupt. - CNTP_CTL_EL0.modify(CNTP_CTL_EL0::ENABLE::SET + CNTP_CTL_EL0::IMASK::SET); + // This is safe, because frequency can never be greater than u32::MAX, and + // (Duration::MAX.as_nanos() * u32::MAX) < u128::MAX. + let counter_value = + unsafe { duration.unchecked_mul(frequency) }.div(NonZeroU128::from(NANOSEC_PER_SEC)); - // ISTATUS will be '1' when cval ticks have passed. Busy-check it. - while !CNTP_CTL_EL0.matches_all(CNTP_CTL_EL0::ISTATUS::SET) {} - - // Disable counting again. - CNTP_CTL_EL0.modify(CNTP_CTL_EL0::ENABLE::CLEAR); + // Since we checked above that we are <= max_duration(), just cast to u64. + Ok(GenericTimerCounterValue(counter_value as u64)) } } + +#[inline(always)] +fn read_cntpct() -> GenericTimerCounterValue { + // Prevent that the counter is read ahead of time due to out-of-order execution. + unsafe { barrier::isb(barrier::SY) }; + let cnt = CNTPCT_EL0.get(); + + GenericTimerCounterValue(cnt) +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +/// The timer's resolution. +pub fn resolution() -> Duration { + Duration::from(GenericTimerCounterValue(1)) +} + +/// The uptime since power-on of the device. +/// +/// This includes time consumed by firmware and bootloaders. +pub fn uptime() -> Duration { + read_cntpct().into() +} + +/// Spin for a given duration. +pub fn spin_for(duration: Duration) { + let curr_counter_value = read_cntpct(); + + let counter_value_delta: GenericTimerCounterValue = match duration.try_into() { + Err(msg) => { + warn!("spin_for: {}. Skipping", msg); + return; + } + Ok(val) => val, + }; + let counter_value_target = curr_counter_value + counter_value_delta; + + // Busy wait. + // + // Read CNTPCT_EL0 directly to avoid the ISB that is part of [`read_cntpct`]. + while GenericTimerCounterValue(CNTPCT_EL0.get()) < counter_value_target {} +} diff --git a/10_virtual_mem_part1_identity_mapping/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs b/10_virtual_mem_part1_identity_mapping/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs index 24958eb5..24e537cf 100644 --- a/10_virtual_mem_part1_identity_mapping/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs +++ b/10_virtual_mem_part1_identity_mapping/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs @@ -140,7 +140,7 @@ impl GPIOInner { /// Disable pull-up/down on pins 14 and 15. #[cfg(feature = "bsp_rpi3")] fn disable_pud_14_15_bcm2837(&mut self) { - use crate::{time, time::interface::TimeManager}; + use crate::time; use core::time::Duration; // The Linux 2837 GPIO driver waits 1 µs between the steps. diff --git a/10_virtual_mem_part1_identity_mapping/src/main.rs b/10_virtual_mem_part1_identity_mapping/src/main.rs index 40b6d13b..e038e093 100644 --- a/10_virtual_mem_part1_identity_mapping/src/main.rs +++ b/10_virtual_mem_part1_identity_mapping/src/main.rs @@ -109,11 +109,14 @@ #![allow(clippy::upper_case_acronyms)] #![allow(incomplete_features)] #![feature(asm_const)] +#![feature(const_option)] #![feature(core_intrinsics)] #![feature(format_args_nl)] #![feature(int_roundings)] +#![feature(nonzero_min_max)] #![feature(panic_info_message)] #![feature(trait_alias)] +#![feature(unchecked_math)] #![no_main] #![no_std] @@ -163,7 +166,6 @@ fn kernel_main() -> ! { use console::{console, interface::Write}; use core::time::Duration; use driver::interface::DriverManager; - use time::interface::TimeManager; info!( "{} version {}", diff --git a/10_virtual_mem_part1_identity_mapping/src/panic_wait.rs b/10_virtual_mem_part1_identity_mapping/src/panic_wait.rs index edd83885..ccf54f61 100644 --- a/10_virtual_mem_part1_identity_mapping/src/panic_wait.rs +++ b/10_virtual_mem_part1_identity_mapping/src/panic_wait.rs @@ -42,8 +42,6 @@ fn panic_prevent_reenter() { #[panic_handler] fn panic(info: &PanicInfo) -> ! { - use crate::time::interface::TimeManager; - // Protect against panic infinite loops if any of the following code panics itself. panic_prevent_reenter(); diff --git a/10_virtual_mem_part1_identity_mapping/src/print.rs b/10_virtual_mem_part1_identity_mapping/src/print.rs index 8705eec0..fe13b334 100644 --- a/10_virtual_mem_part1_identity_mapping/src/print.rs +++ b/10_virtual_mem_part1_identity_mapping/src/print.rs @@ -39,8 +39,6 @@ macro_rules! println { #[macro_export] macro_rules! info { ($string:expr) => ({ - use $crate::time::interface::TimeManager; - let timestamp = $crate::time::time_manager().uptime(); $crate::print::_print(format_args_nl!( @@ -50,8 +48,6 @@ macro_rules! info { )); }); ($format_string:expr, $($arg:tt)*) => ({ - use $crate::time::interface::TimeManager; - let timestamp = $crate::time::time_manager().uptime(); $crate::print::_print(format_args_nl!( @@ -67,8 +63,6 @@ macro_rules! info { #[macro_export] macro_rules! warn { ($string:expr) => ({ - use $crate::time::interface::TimeManager; - let timestamp = $crate::time::time_manager().uptime(); $crate::print::_print(format_args_nl!( @@ -78,8 +72,6 @@ macro_rules! warn { )); }); ($format_string:expr, $($arg:tt)*) => ({ - use $crate::time::interface::TimeManager; - let timestamp = $crate::time::time_manager().uptime(); $crate::print::_print(format_args_nl!( diff --git a/10_virtual_mem_part1_identity_mapping/src/time.rs b/10_virtual_mem_part1_identity_mapping/src/time.rs index 6d92b196..a6c0c5b6 100644 --- a/10_virtual_mem_part1_identity_mapping/src/time.rs +++ b/10_virtual_mem_part1_identity_mapping/src/time.rs @@ -8,30 +8,50 @@ #[path = "_arch/aarch64/time.rs"] mod arch_time; +use core::time::Duration; + //-------------------------------------------------------------------------------------------------- -// Architectural Public Reexports +// Public Definitions //-------------------------------------------------------------------------------------------------- -pub use arch_time::time_manager; + +/// Provides time management functions. +pub struct TimeManager; //-------------------------------------------------------------------------------------------------- -// Public Definitions +// Global instances //-------------------------------------------------------------------------------------------------- -/// Timekeeping interfaces. -pub mod interface { - use core::time::Duration; +static TIME_MANAGER: TimeManager = TimeManager::new(); - /// Time management functions. - pub trait TimeManager { - /// The timer's resolution. - fn resolution(&self) -> Duration; +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- - /// The uptime since power-on of the device. - /// - /// This includes time consumed by firmware and bootloaders. - fn uptime(&self) -> Duration; +/// Return a reference to the global TimeManager. +pub fn time_manager() -> &'static TimeManager { + &TIME_MANAGER +} + +impl TimeManager { + /// Create an instance. + pub const fn new() -> Self { + Self + } + + /// The timer's resolution. + pub fn resolution(&self) -> Duration { + arch_time::resolution() + } + + /// The uptime since power-on of the device. + /// + /// This includes time consumed by firmware and bootloaders. + pub fn uptime(&self) -> Duration { + arch_time::uptime() + } - /// Spin for a given duration. - fn spin_for(&self, duration: Duration); + /// Spin for a given duration. + pub fn spin_for(&self, duration: Duration) { + arch_time::spin_for(duration) } } diff --git a/11_exceptions_part1_groundwork/README.md b/11_exceptions_part1_groundwork/README.md index 4fc713a5..3e7ca05e 100644 --- a/11_exceptions_part1_groundwork/README.md +++ b/11_exceptions_part1_groundwork/README.md @@ -1024,7 +1024,7 @@ diff -uNr 10_virtual_mem_part1_identity_mapping/src/exception.rs 11_exceptions_p diff -uNr 10_virtual_mem_part1_identity_mapping/src/main.rs 11_exceptions_part1_groundwork/src/main.rs --- 10_virtual_mem_part1_identity_mapping/src/main.rs +++ 11_exceptions_part1_groundwork/src/main.rs -@@ -142,6 +142,8 @@ +@@ -145,6 +145,8 @@ use driver::interface::DriverManager; use memory::mmu::interface::MMU; @@ -1033,7 +1033,7 @@ diff -uNr 10_virtual_mem_part1_identity_mapping/src/main.rs 11_exceptions_part1_ if let Err(string) = memory::mmu::mmu().enable_mmu_and_caching() { panic!("MMU: {}", string); } -@@ -160,7 +162,7 @@ +@@ -163,7 +165,7 @@ /// The main function running after the early init. fn kernel_main() -> ! { @@ -1041,8 +1041,8 @@ diff -uNr 10_virtual_mem_part1_identity_mapping/src/main.rs 11_exceptions_part1_ + use console::console; use core::time::Duration; use driver::interface::DriverManager; - use time::interface::TimeManager; -@@ -198,13 +200,28 @@ + +@@ -200,13 +202,28 @@ info!("Timer test, spinning for 1 second"); time::time_manager().spin_for(Duration::from_secs(1)); diff --git a/11_exceptions_part1_groundwork/src/_arch/aarch64/cpu/boot.s b/11_exceptions_part1_groundwork/src/_arch/aarch64/cpu/boot.s index 7576dc14..f6df2123 100644 --- a/11_exceptions_part1_groundwork/src/_arch/aarch64/cpu/boot.s +++ b/11_exceptions_part1_groundwork/src/_arch/aarch64/cpu/boot.s @@ -57,6 +57,14 @@ _start: ADR_REL x0, __boot_core_stack_end_exclusive mov sp, x0 + // Read the CPU's timer counter frequency and store it in ARCH_TIMER_COUNTER_FREQUENCY. + // Abort if the frequency read back as 0. + ADR_REL x1, ARCH_TIMER_COUNTER_FREQUENCY // provided by aarch64/time.rs + mrs x2, CNTFRQ_EL0 + cmp x2, xzr + b.eq .L_parking_loop + str w2, [x1] + // Jump to Rust code. x0 holds the function argument provided to _start_rust(). b _start_rust diff --git a/11_exceptions_part1_groundwork/src/_arch/aarch64/time.rs b/11_exceptions_part1_groundwork/src/_arch/aarch64/time.rs index c814219c..255a5a45 100644 --- a/11_exceptions_part1_groundwork/src/_arch/aarch64/time.rs +++ b/11_exceptions_part1_groundwork/src/_arch/aarch64/time.rs @@ -11,111 +11,152 @@ //! //! crate::time::arch_time -use crate::{time, warn}; -use core::time::Duration; +use crate::warn; +use core::{ + num::{NonZeroU128, NonZeroU32, NonZeroU64}, + ops::{Add, Div}, + time::Duration, +}; use cortex_a::{asm::barrier, registers::*}; -use tock_registers::interfaces::{ReadWriteable, Readable, Writeable}; +use tock_registers::interfaces::Readable; //-------------------------------------------------------------------------------------------------- // Private Definitions //-------------------------------------------------------------------------------------------------- -const NS_PER_S: u64 = 1_000_000_000; +const NANOSEC_PER_SEC: NonZeroU64 = NonZeroU64::new(1_000_000_000).unwrap(); -/// ARMv8 Generic Timer. -struct GenericTimer; +#[derive(Copy, Clone, PartialOrd, PartialEq)] +struct GenericTimerCounterValue(u64); //-------------------------------------------------------------------------------------------------- // Global instances //-------------------------------------------------------------------------------------------------- -static TIME_MANAGER: GenericTimer = GenericTimer; +/// Boot assembly code overwrites this value with the value of CNTFRQ_EL0 before any Rust code is +/// executed. This given value here is just a (safe) dummy. +#[no_mangle] +static ARCH_TIMER_COUNTER_FREQUENCY: NonZeroU32 = NonZeroU32::MIN; //-------------------------------------------------------------------------------------------------- // Private Code //-------------------------------------------------------------------------------------------------- -impl GenericTimer { - #[inline(always)] - fn read_cntpct(&self) -> u64 { - // Prevent that the counter is read ahead of time due to out-of-order execution. - unsafe { barrier::isb(barrier::SY) }; - CNTPCT_EL0.get() - } +impl GenericTimerCounterValue { + pub const MAX: Self = GenericTimerCounterValue(u64::MAX); } -//-------------------------------------------------------------------------------------------------- -// Public Code -//-------------------------------------------------------------------------------------------------- +impl Add for GenericTimerCounterValue { + type Output = Self; -/// Return a reference to the time manager. -pub fn time_manager() -> &'static impl time::interface::TimeManager { - &TIME_MANAGER + fn add(self, other: Self) -> Self { + GenericTimerCounterValue(self.0.wrapping_add(other.0)) + } } -//------------------------------------------------------------------------------ -// OS Interface Code -//------------------------------------------------------------------------------ +impl From for Duration { + fn from(counter_value: GenericTimerCounterValue) -> Self { + if counter_value.0 == 0 { + return Duration::ZERO; + } -impl time::interface::TimeManager for GenericTimer { - fn resolution(&self) -> Duration { - Duration::from_nanos(NS_PER_S / (CNTFRQ_EL0.get() as u64)) + // Read volatile is needed here to prevent the compiler from optimizing + // ARCH_TIMER_COUNTER_FREQUENCY away. + // + // This is safe, because all the safety requirements as stated in read_volatile()'s + // documentation are fulfilled. + let frequency: NonZeroU64 = + unsafe { core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY) }.into(); + + // Div implementation for u64 cannot panic. + let secs = counter_value.0.div(frequency); + + // This is safe, because frequency can never be greater than u32::MAX, which means the + // largest theoretical value for sub_second_counter_value is (u32::MAX - 1). Therefore, + // (sub_second_counter_value * NANOSEC_PER_SEC) cannot overflow an u64. + // + // The subsequent division ensures the result fits into u32, since the max result is smaller + // than NANOSEC_PER_SEC. Therefore, just cast it to u32 using `as`. + let sub_second_counter_value = counter_value.0 % frequency; + let nanos = unsafe { sub_second_counter_value.unchecked_mul(u64::from(NANOSEC_PER_SEC)) } + .div(frequency) as u32; + + Duration::new(secs, nanos) } +} - fn uptime(&self) -> Duration { - let current_count: u64 = self.read_cntpct() * NS_PER_S; - let frq: u64 = CNTFRQ_EL0.get() as u64; +fn max_duration() -> Duration { + Duration::from(GenericTimerCounterValue::MAX) +} - Duration::from_nanos(current_count / frq) - } +impl TryFrom for GenericTimerCounterValue { + type Error = &'static str; - fn spin_for(&self, duration: Duration) { - // Instantly return on zero. - if duration.as_nanos() == 0 { - return; + fn try_from(duration: Duration) -> Result { + if duration < resolution() { + return Ok(GenericTimerCounterValue(0)); } - // Calculate the register compare value. - let frq = CNTFRQ_EL0.get(); - let x = match frq.checked_mul(duration.as_nanos() as u64) { - #[allow(unused_imports)] - None => { - warn!("Spin duration too long, skipping"); - return; - } - Some(val) => val, - }; - let tval = x / NS_PER_S; - - // Check if it is within supported bounds. - let warn: Option<&str> = if tval == 0 { - Some("smaller") - // The upper 32 bits of CNTP_TVAL_EL0 are reserved. - } else if tval > u32::max_value().into() { - Some("bigger") - } else { - None - }; - - #[allow(unused_imports)] - if let Some(w) = warn { - warn!( - "Spin duration {} than architecturally supported, skipping", - w - ); - return; + if duration > max_duration() { + return Err("Conversion error. Duration too big"); } - // Set the compare value register. - CNTP_TVAL_EL0.set(tval); + // This is safe, because all the safety requirements as stated in read_volatile()'s + // documentation are fulfilled. + let frequency: u128 = + unsafe { u32::from(core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY)) as u128 }; + let duration: u128 = duration.as_nanos(); - // Kick off the counting. // Disable timer interrupt. - CNTP_CTL_EL0.modify(CNTP_CTL_EL0::ENABLE::SET + CNTP_CTL_EL0::IMASK::SET); + // This is safe, because frequency can never be greater than u32::MAX, and + // (Duration::MAX.as_nanos() * u32::MAX) < u128::MAX. + let counter_value = + unsafe { duration.unchecked_mul(frequency) }.div(NonZeroU128::from(NANOSEC_PER_SEC)); - // ISTATUS will be '1' when cval ticks have passed. Busy-check it. - while !CNTP_CTL_EL0.matches_all(CNTP_CTL_EL0::ISTATUS::SET) {} - - // Disable counting again. - CNTP_CTL_EL0.modify(CNTP_CTL_EL0::ENABLE::CLEAR); + // Since we checked above that we are <= max_duration(), just cast to u64. + Ok(GenericTimerCounterValue(counter_value as u64)) } } + +#[inline(always)] +fn read_cntpct() -> GenericTimerCounterValue { + // Prevent that the counter is read ahead of time due to out-of-order execution. + unsafe { barrier::isb(barrier::SY) }; + let cnt = CNTPCT_EL0.get(); + + GenericTimerCounterValue(cnt) +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +/// The timer's resolution. +pub fn resolution() -> Duration { + Duration::from(GenericTimerCounterValue(1)) +} + +/// The uptime since power-on of the device. +/// +/// This includes time consumed by firmware and bootloaders. +pub fn uptime() -> Duration { + read_cntpct().into() +} + +/// Spin for a given duration. +pub fn spin_for(duration: Duration) { + let curr_counter_value = read_cntpct(); + + let counter_value_delta: GenericTimerCounterValue = match duration.try_into() { + Err(msg) => { + warn!("spin_for: {}. Skipping", msg); + return; + } + Ok(val) => val, + }; + let counter_value_target = curr_counter_value + counter_value_delta; + + // Busy wait. + // + // Read CNTPCT_EL0 directly to avoid the ISB that is part of [`read_cntpct`]. + while GenericTimerCounterValue(CNTPCT_EL0.get()) < counter_value_target {} +} diff --git a/11_exceptions_part1_groundwork/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs b/11_exceptions_part1_groundwork/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs index 24958eb5..24e537cf 100644 --- a/11_exceptions_part1_groundwork/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs +++ b/11_exceptions_part1_groundwork/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs @@ -140,7 +140,7 @@ impl GPIOInner { /// Disable pull-up/down on pins 14 and 15. #[cfg(feature = "bsp_rpi3")] fn disable_pud_14_15_bcm2837(&mut self) { - use crate::{time, time::interface::TimeManager}; + use crate::time; use core::time::Duration; // The Linux 2837 GPIO driver waits 1 µs between the steps. diff --git a/11_exceptions_part1_groundwork/src/main.rs b/11_exceptions_part1_groundwork/src/main.rs index 585382a5..8e632fa5 100644 --- a/11_exceptions_part1_groundwork/src/main.rs +++ b/11_exceptions_part1_groundwork/src/main.rs @@ -109,11 +109,14 @@ #![allow(clippy::upper_case_acronyms)] #![allow(incomplete_features)] #![feature(asm_const)] +#![feature(const_option)] #![feature(core_intrinsics)] #![feature(format_args_nl)] #![feature(int_roundings)] +#![feature(nonzero_min_max)] #![feature(panic_info_message)] #![feature(trait_alias)] +#![feature(unchecked_math)] #![no_main] #![no_std] @@ -165,7 +168,6 @@ fn kernel_main() -> ! { use console::console; use core::time::Duration; use driver::interface::DriverManager; - use time::interface::TimeManager; info!( "{} version {}", diff --git a/11_exceptions_part1_groundwork/src/panic_wait.rs b/11_exceptions_part1_groundwork/src/panic_wait.rs index edd83885..ccf54f61 100644 --- a/11_exceptions_part1_groundwork/src/panic_wait.rs +++ b/11_exceptions_part1_groundwork/src/panic_wait.rs @@ -42,8 +42,6 @@ fn panic_prevent_reenter() { #[panic_handler] fn panic(info: &PanicInfo) -> ! { - use crate::time::interface::TimeManager; - // Protect against panic infinite loops if any of the following code panics itself. panic_prevent_reenter(); diff --git a/11_exceptions_part1_groundwork/src/print.rs b/11_exceptions_part1_groundwork/src/print.rs index 8705eec0..fe13b334 100644 --- a/11_exceptions_part1_groundwork/src/print.rs +++ b/11_exceptions_part1_groundwork/src/print.rs @@ -39,8 +39,6 @@ macro_rules! println { #[macro_export] macro_rules! info { ($string:expr) => ({ - use $crate::time::interface::TimeManager; - let timestamp = $crate::time::time_manager().uptime(); $crate::print::_print(format_args_nl!( @@ -50,8 +48,6 @@ macro_rules! info { )); }); ($format_string:expr, $($arg:tt)*) => ({ - use $crate::time::interface::TimeManager; - let timestamp = $crate::time::time_manager().uptime(); $crate::print::_print(format_args_nl!( @@ -67,8 +63,6 @@ macro_rules! info { #[macro_export] macro_rules! warn { ($string:expr) => ({ - use $crate::time::interface::TimeManager; - let timestamp = $crate::time::time_manager().uptime(); $crate::print::_print(format_args_nl!( @@ -78,8 +72,6 @@ macro_rules! warn { )); }); ($format_string:expr, $($arg:tt)*) => ({ - use $crate::time::interface::TimeManager; - let timestamp = $crate::time::time_manager().uptime(); $crate::print::_print(format_args_nl!( diff --git a/11_exceptions_part1_groundwork/src/time.rs b/11_exceptions_part1_groundwork/src/time.rs index 6d92b196..a6c0c5b6 100644 --- a/11_exceptions_part1_groundwork/src/time.rs +++ b/11_exceptions_part1_groundwork/src/time.rs @@ -8,30 +8,50 @@ #[path = "_arch/aarch64/time.rs"] mod arch_time; +use core::time::Duration; + //-------------------------------------------------------------------------------------------------- -// Architectural Public Reexports +// Public Definitions //-------------------------------------------------------------------------------------------------- -pub use arch_time::time_manager; + +/// Provides time management functions. +pub struct TimeManager; //-------------------------------------------------------------------------------------------------- -// Public Definitions +// Global instances //-------------------------------------------------------------------------------------------------- -/// Timekeeping interfaces. -pub mod interface { - use core::time::Duration; +static TIME_MANAGER: TimeManager = TimeManager::new(); - /// Time management functions. - pub trait TimeManager { - /// The timer's resolution. - fn resolution(&self) -> Duration; +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- - /// The uptime since power-on of the device. - /// - /// This includes time consumed by firmware and bootloaders. - fn uptime(&self) -> Duration; +/// Return a reference to the global TimeManager. +pub fn time_manager() -> &'static TimeManager { + &TIME_MANAGER +} + +impl TimeManager { + /// Create an instance. + pub const fn new() -> Self { + Self + } + + /// The timer's resolution. + pub fn resolution(&self) -> Duration { + arch_time::resolution() + } + + /// The uptime since power-on of the device. + /// + /// This includes time consumed by firmware and bootloaders. + pub fn uptime(&self) -> Duration { + arch_time::uptime() + } - /// Spin for a given duration. - fn spin_for(&self, duration: Duration); + /// Spin for a given duration. + pub fn spin_for(&self, duration: Duration) { + arch_time::spin_for(duration) } } diff --git a/12_integrated_testing/README.md b/12_integrated_testing/README.md index e0d0dd1d..c5d032e8 100644 --- a/12_integrated_testing/README.md +++ b/12_integrated_testing/README.md @@ -622,7 +622,7 @@ your test code into individual chunks. For example, take a look at `tests/01_tim #![test_runner(libkernel::test_runner)] use core::time::Duration; -use libkernel::{bsp, cpu, driver, exception, time, time::interface::TimeManager}; +use libkernel::{bsp, cpu, driver, exception, time}; use test_macros::kernel_test; #[no_mangle] @@ -643,6 +643,7 @@ unsafe fn kernel_init() -> ! { #[kernel_test] fn timer_is_counting() { assert!(time::time_manager().uptime().as_nanos() > 0) + assert!(time::time_manager().resolution().as_nanos() < 100) } /// Timer resolution must be sufficient. diff --git a/12_integrated_testing/kernel/src/_arch/aarch64/cpu/boot.s b/12_integrated_testing/kernel/src/_arch/aarch64/cpu/boot.s index 7576dc14..f6df2123 100644 --- a/12_integrated_testing/kernel/src/_arch/aarch64/cpu/boot.s +++ b/12_integrated_testing/kernel/src/_arch/aarch64/cpu/boot.s @@ -57,6 +57,14 @@ _start: ADR_REL x0, __boot_core_stack_end_exclusive mov sp, x0 + // Read the CPU's timer counter frequency and store it in ARCH_TIMER_COUNTER_FREQUENCY. + // Abort if the frequency read back as 0. + ADR_REL x1, ARCH_TIMER_COUNTER_FREQUENCY // provided by aarch64/time.rs + mrs x2, CNTFRQ_EL0 + cmp x2, xzr + b.eq .L_parking_loop + str w2, [x1] + // Jump to Rust code. x0 holds the function argument provided to _start_rust(). b _start_rust diff --git a/12_integrated_testing/kernel/src/_arch/aarch64/time.rs b/12_integrated_testing/kernel/src/_arch/aarch64/time.rs index c814219c..255a5a45 100644 --- a/12_integrated_testing/kernel/src/_arch/aarch64/time.rs +++ b/12_integrated_testing/kernel/src/_arch/aarch64/time.rs @@ -11,111 +11,152 @@ //! //! crate::time::arch_time -use crate::{time, warn}; -use core::time::Duration; +use crate::warn; +use core::{ + num::{NonZeroU128, NonZeroU32, NonZeroU64}, + ops::{Add, Div}, + time::Duration, +}; use cortex_a::{asm::barrier, registers::*}; -use tock_registers::interfaces::{ReadWriteable, Readable, Writeable}; +use tock_registers::interfaces::Readable; //-------------------------------------------------------------------------------------------------- // Private Definitions //-------------------------------------------------------------------------------------------------- -const NS_PER_S: u64 = 1_000_000_000; +const NANOSEC_PER_SEC: NonZeroU64 = NonZeroU64::new(1_000_000_000).unwrap(); -/// ARMv8 Generic Timer. -struct GenericTimer; +#[derive(Copy, Clone, PartialOrd, PartialEq)] +struct GenericTimerCounterValue(u64); //-------------------------------------------------------------------------------------------------- // Global instances //-------------------------------------------------------------------------------------------------- -static TIME_MANAGER: GenericTimer = GenericTimer; +/// Boot assembly code overwrites this value with the value of CNTFRQ_EL0 before any Rust code is +/// executed. This given value here is just a (safe) dummy. +#[no_mangle] +static ARCH_TIMER_COUNTER_FREQUENCY: NonZeroU32 = NonZeroU32::MIN; //-------------------------------------------------------------------------------------------------- // Private Code //-------------------------------------------------------------------------------------------------- -impl GenericTimer { - #[inline(always)] - fn read_cntpct(&self) -> u64 { - // Prevent that the counter is read ahead of time due to out-of-order execution. - unsafe { barrier::isb(barrier::SY) }; - CNTPCT_EL0.get() - } +impl GenericTimerCounterValue { + pub const MAX: Self = GenericTimerCounterValue(u64::MAX); } -//-------------------------------------------------------------------------------------------------- -// Public Code -//-------------------------------------------------------------------------------------------------- +impl Add for GenericTimerCounterValue { + type Output = Self; -/// Return a reference to the time manager. -pub fn time_manager() -> &'static impl time::interface::TimeManager { - &TIME_MANAGER + fn add(self, other: Self) -> Self { + GenericTimerCounterValue(self.0.wrapping_add(other.0)) + } } -//------------------------------------------------------------------------------ -// OS Interface Code -//------------------------------------------------------------------------------ +impl From for Duration { + fn from(counter_value: GenericTimerCounterValue) -> Self { + if counter_value.0 == 0 { + return Duration::ZERO; + } -impl time::interface::TimeManager for GenericTimer { - fn resolution(&self) -> Duration { - Duration::from_nanos(NS_PER_S / (CNTFRQ_EL0.get() as u64)) + // Read volatile is needed here to prevent the compiler from optimizing + // ARCH_TIMER_COUNTER_FREQUENCY away. + // + // This is safe, because all the safety requirements as stated in read_volatile()'s + // documentation are fulfilled. + let frequency: NonZeroU64 = + unsafe { core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY) }.into(); + + // Div implementation for u64 cannot panic. + let secs = counter_value.0.div(frequency); + + // This is safe, because frequency can never be greater than u32::MAX, which means the + // largest theoretical value for sub_second_counter_value is (u32::MAX - 1). Therefore, + // (sub_second_counter_value * NANOSEC_PER_SEC) cannot overflow an u64. + // + // The subsequent division ensures the result fits into u32, since the max result is smaller + // than NANOSEC_PER_SEC. Therefore, just cast it to u32 using `as`. + let sub_second_counter_value = counter_value.0 % frequency; + let nanos = unsafe { sub_second_counter_value.unchecked_mul(u64::from(NANOSEC_PER_SEC)) } + .div(frequency) as u32; + + Duration::new(secs, nanos) } +} - fn uptime(&self) -> Duration { - let current_count: u64 = self.read_cntpct() * NS_PER_S; - let frq: u64 = CNTFRQ_EL0.get() as u64; +fn max_duration() -> Duration { + Duration::from(GenericTimerCounterValue::MAX) +} - Duration::from_nanos(current_count / frq) - } +impl TryFrom for GenericTimerCounterValue { + type Error = &'static str; - fn spin_for(&self, duration: Duration) { - // Instantly return on zero. - if duration.as_nanos() == 0 { - return; + fn try_from(duration: Duration) -> Result { + if duration < resolution() { + return Ok(GenericTimerCounterValue(0)); } - // Calculate the register compare value. - let frq = CNTFRQ_EL0.get(); - let x = match frq.checked_mul(duration.as_nanos() as u64) { - #[allow(unused_imports)] - None => { - warn!("Spin duration too long, skipping"); - return; - } - Some(val) => val, - }; - let tval = x / NS_PER_S; - - // Check if it is within supported bounds. - let warn: Option<&str> = if tval == 0 { - Some("smaller") - // The upper 32 bits of CNTP_TVAL_EL0 are reserved. - } else if tval > u32::max_value().into() { - Some("bigger") - } else { - None - }; - - #[allow(unused_imports)] - if let Some(w) = warn { - warn!( - "Spin duration {} than architecturally supported, skipping", - w - ); - return; + if duration > max_duration() { + return Err("Conversion error. Duration too big"); } - // Set the compare value register. - CNTP_TVAL_EL0.set(tval); + // This is safe, because all the safety requirements as stated in read_volatile()'s + // documentation are fulfilled. + let frequency: u128 = + unsafe { u32::from(core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY)) as u128 }; + let duration: u128 = duration.as_nanos(); - // Kick off the counting. // Disable timer interrupt. - CNTP_CTL_EL0.modify(CNTP_CTL_EL0::ENABLE::SET + CNTP_CTL_EL0::IMASK::SET); + // This is safe, because frequency can never be greater than u32::MAX, and + // (Duration::MAX.as_nanos() * u32::MAX) < u128::MAX. + let counter_value = + unsafe { duration.unchecked_mul(frequency) }.div(NonZeroU128::from(NANOSEC_PER_SEC)); - // ISTATUS will be '1' when cval ticks have passed. Busy-check it. - while !CNTP_CTL_EL0.matches_all(CNTP_CTL_EL0::ISTATUS::SET) {} - - // Disable counting again. - CNTP_CTL_EL0.modify(CNTP_CTL_EL0::ENABLE::CLEAR); + // Since we checked above that we are <= max_duration(), just cast to u64. + Ok(GenericTimerCounterValue(counter_value as u64)) } } + +#[inline(always)] +fn read_cntpct() -> GenericTimerCounterValue { + // Prevent that the counter is read ahead of time due to out-of-order execution. + unsafe { barrier::isb(barrier::SY) }; + let cnt = CNTPCT_EL0.get(); + + GenericTimerCounterValue(cnt) +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +/// The timer's resolution. +pub fn resolution() -> Duration { + Duration::from(GenericTimerCounterValue(1)) +} + +/// The uptime since power-on of the device. +/// +/// This includes time consumed by firmware and bootloaders. +pub fn uptime() -> Duration { + read_cntpct().into() +} + +/// Spin for a given duration. +pub fn spin_for(duration: Duration) { + let curr_counter_value = read_cntpct(); + + let counter_value_delta: GenericTimerCounterValue = match duration.try_into() { + Err(msg) => { + warn!("spin_for: {}. Skipping", msg); + return; + } + Ok(val) => val, + }; + let counter_value_target = curr_counter_value + counter_value_delta; + + // Busy wait. + // + // Read CNTPCT_EL0 directly to avoid the ISB that is part of [`read_cntpct`]. + while GenericTimerCounterValue(CNTPCT_EL0.get()) < counter_value_target {} +} diff --git a/12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs b/12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs index 24958eb5..24e537cf 100644 --- a/12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs +++ b/12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs @@ -140,7 +140,7 @@ impl GPIOInner { /// Disable pull-up/down on pins 14 and 15. #[cfg(feature = "bsp_rpi3")] fn disable_pud_14_15_bcm2837(&mut self) { - use crate::{time, time::interface::TimeManager}; + use crate::time; use core::time::Duration; // The Linux 2837 GPIO driver waits 1 µs between the steps. diff --git a/12_integrated_testing/kernel/src/lib.rs b/12_integrated_testing/kernel/src/lib.rs index 4a41bbfe..35698c74 100644 --- a/12_integrated_testing/kernel/src/lib.rs +++ b/12_integrated_testing/kernel/src/lib.rs @@ -111,12 +111,15 @@ #![allow(clippy::upper_case_acronyms)] #![allow(incomplete_features)] #![feature(asm_const)] +#![feature(const_option)] #![feature(core_intrinsics)] #![feature(format_args_nl)] #![feature(int_roundings)] #![feature(linkage)] +#![feature(nonzero_min_max)] #![feature(panic_info_message)] #![feature(trait_alias)] +#![feature(unchecked_math)] #![no_std] // Testing #![cfg_attr(test, no_main)] diff --git a/12_integrated_testing/kernel/src/panic_wait.rs b/12_integrated_testing/kernel/src/panic_wait.rs index 8bedfded..da779008 100644 --- a/12_integrated_testing/kernel/src/panic_wait.rs +++ b/12_integrated_testing/kernel/src/panic_wait.rs @@ -59,8 +59,6 @@ fn panic_prevent_reenter() { #[panic_handler] fn panic(info: &PanicInfo) -> ! { - use crate::time::interface::TimeManager; - // Protect against panic infinite loops if any of the following code panics itself. panic_prevent_reenter(); diff --git a/12_integrated_testing/kernel/src/print.rs b/12_integrated_testing/kernel/src/print.rs index 8705eec0..fe13b334 100644 --- a/12_integrated_testing/kernel/src/print.rs +++ b/12_integrated_testing/kernel/src/print.rs @@ -39,8 +39,6 @@ macro_rules! println { #[macro_export] macro_rules! info { ($string:expr) => ({ - use $crate::time::interface::TimeManager; - let timestamp = $crate::time::time_manager().uptime(); $crate::print::_print(format_args_nl!( @@ -50,8 +48,6 @@ macro_rules! info { )); }); ($format_string:expr, $($arg:tt)*) => ({ - use $crate::time::interface::TimeManager; - let timestamp = $crate::time::time_manager().uptime(); $crate::print::_print(format_args_nl!( @@ -67,8 +63,6 @@ macro_rules! info { #[macro_export] macro_rules! warn { ($string:expr) => ({ - use $crate::time::interface::TimeManager; - let timestamp = $crate::time::time_manager().uptime(); $crate::print::_print(format_args_nl!( @@ -78,8 +72,6 @@ macro_rules! warn { )); }); ($format_string:expr, $($arg:tt)*) => ({ - use $crate::time::interface::TimeManager; - let timestamp = $crate::time::time_manager().uptime(); $crate::print::_print(format_args_nl!( diff --git a/12_integrated_testing/kernel/src/time.rs b/12_integrated_testing/kernel/src/time.rs index 6d92b196..a6c0c5b6 100644 --- a/12_integrated_testing/kernel/src/time.rs +++ b/12_integrated_testing/kernel/src/time.rs @@ -8,30 +8,50 @@ #[path = "_arch/aarch64/time.rs"] mod arch_time; +use core::time::Duration; + //-------------------------------------------------------------------------------------------------- -// Architectural Public Reexports +// Public Definitions //-------------------------------------------------------------------------------------------------- -pub use arch_time::time_manager; + +/// Provides time management functions. +pub struct TimeManager; //-------------------------------------------------------------------------------------------------- -// Public Definitions +// Global instances //-------------------------------------------------------------------------------------------------- -/// Timekeeping interfaces. -pub mod interface { - use core::time::Duration; +static TIME_MANAGER: TimeManager = TimeManager::new(); - /// Time management functions. - pub trait TimeManager { - /// The timer's resolution. - fn resolution(&self) -> Duration; +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- - /// The uptime since power-on of the device. - /// - /// This includes time consumed by firmware and bootloaders. - fn uptime(&self) -> Duration; +/// Return a reference to the global TimeManager. +pub fn time_manager() -> &'static TimeManager { + &TIME_MANAGER +} + +impl TimeManager { + /// Create an instance. + pub const fn new() -> Self { + Self + } + + /// The timer's resolution. + pub fn resolution(&self) -> Duration { + arch_time::resolution() + } + + /// The uptime since power-on of the device. + /// + /// This includes time consumed by firmware and bootloaders. + pub fn uptime(&self) -> Duration { + arch_time::uptime() + } - /// Spin for a given duration. - fn spin_for(&self, duration: Duration); + /// Spin for a given duration. + pub fn spin_for(&self, duration: Duration) { + arch_time::spin_for(duration) } } diff --git a/12_integrated_testing/kernel/tests/01_timer_sanity.rs b/12_integrated_testing/kernel/tests/01_timer_sanity.rs index 390cdee5..a0eb732b 100644 --- a/12_integrated_testing/kernel/tests/01_timer_sanity.rs +++ b/12_integrated_testing/kernel/tests/01_timer_sanity.rs @@ -11,7 +11,7 @@ #![test_runner(libkernel::test_runner)] use core::time::Duration; -use libkernel::{bsp, cpu, driver, exception, time, time::interface::TimeManager}; +use libkernel::{bsp, cpu, driver, exception, time}; use test_macros::kernel_test; #[no_mangle] @@ -37,6 +37,7 @@ fn timer_is_counting() { /// Timer resolution must be sufficient. #[kernel_test] fn timer_resolution_is_sufficient() { + assert!(time::time_manager().resolution().as_nanos() > 0); assert!(time::time_manager().resolution().as_nanos() < 100) } diff --git a/13_exceptions_part2_peripheral_IRQs/README.md b/13_exceptions_part2_peripheral_IRQs/README.md index 77bcc2f2..3b7a8f64 100644 --- a/13_exceptions_part2_peripheral_IRQs/README.md +++ b/13_exceptions_part2_peripheral_IRQs/README.md @@ -2385,7 +2385,7 @@ diff -uNr 12_integrated_testing/kernel/src/exception/asynchronous.rs 13_exceptio diff -uNr 12_integrated_testing/kernel/src/lib.rs 13_exceptions_part2_peripheral_IRQs/kernel/src/lib.rs --- 12_integrated_testing/kernel/src/lib.rs +++ 13_exceptions_part2_peripheral_IRQs/kernel/src/lib.rs -@@ -135,6 +135,7 @@ +@@ -138,6 +138,7 @@ pub mod exception; pub mod memory; pub mod print; @@ -2474,10 +2474,10 @@ diff -uNr 12_integrated_testing/kernel/src/panic_wait.rs 13_exceptions_part2_per use core::panic::PanicInfo; //-------------------------------------------------------------------------------------------------- -@@ -61,6 +61,8 @@ - fn panic(info: &PanicInfo) -> ! { - use crate::time::interface::TimeManager; +@@ -59,6 +59,8 @@ + #[panic_handler] + fn panic(info: &PanicInfo) -> ! { + exception::asynchronous::local_irq_mask(); + // Protect against panic infinite loops if any of the following code panics itself. diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/cpu/boot.s b/13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/cpu/boot.s index 7576dc14..f6df2123 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/cpu/boot.s +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/cpu/boot.s @@ -57,6 +57,14 @@ _start: ADR_REL x0, __boot_core_stack_end_exclusive mov sp, x0 + // Read the CPU's timer counter frequency and store it in ARCH_TIMER_COUNTER_FREQUENCY. + // Abort if the frequency read back as 0. + ADR_REL x1, ARCH_TIMER_COUNTER_FREQUENCY // provided by aarch64/time.rs + mrs x2, CNTFRQ_EL0 + cmp x2, xzr + b.eq .L_parking_loop + str w2, [x1] + // Jump to Rust code. x0 holds the function argument provided to _start_rust(). b _start_rust diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/time.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/time.rs index c814219c..255a5a45 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/time.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/time.rs @@ -11,111 +11,152 @@ //! //! crate::time::arch_time -use crate::{time, warn}; -use core::time::Duration; +use crate::warn; +use core::{ + num::{NonZeroU128, NonZeroU32, NonZeroU64}, + ops::{Add, Div}, + time::Duration, +}; use cortex_a::{asm::barrier, registers::*}; -use tock_registers::interfaces::{ReadWriteable, Readable, Writeable}; +use tock_registers::interfaces::Readable; //-------------------------------------------------------------------------------------------------- // Private Definitions //-------------------------------------------------------------------------------------------------- -const NS_PER_S: u64 = 1_000_000_000; +const NANOSEC_PER_SEC: NonZeroU64 = NonZeroU64::new(1_000_000_000).unwrap(); -/// ARMv8 Generic Timer. -struct GenericTimer; +#[derive(Copy, Clone, PartialOrd, PartialEq)] +struct GenericTimerCounterValue(u64); //-------------------------------------------------------------------------------------------------- // Global instances //-------------------------------------------------------------------------------------------------- -static TIME_MANAGER: GenericTimer = GenericTimer; +/// Boot assembly code overwrites this value with the value of CNTFRQ_EL0 before any Rust code is +/// executed. This given value here is just a (safe) dummy. +#[no_mangle] +static ARCH_TIMER_COUNTER_FREQUENCY: NonZeroU32 = NonZeroU32::MIN; //-------------------------------------------------------------------------------------------------- // Private Code //-------------------------------------------------------------------------------------------------- -impl GenericTimer { - #[inline(always)] - fn read_cntpct(&self) -> u64 { - // Prevent that the counter is read ahead of time due to out-of-order execution. - unsafe { barrier::isb(barrier::SY) }; - CNTPCT_EL0.get() - } +impl GenericTimerCounterValue { + pub const MAX: Self = GenericTimerCounterValue(u64::MAX); } -//-------------------------------------------------------------------------------------------------- -// Public Code -//-------------------------------------------------------------------------------------------------- +impl Add for GenericTimerCounterValue { + type Output = Self; -/// Return a reference to the time manager. -pub fn time_manager() -> &'static impl time::interface::TimeManager { - &TIME_MANAGER + fn add(self, other: Self) -> Self { + GenericTimerCounterValue(self.0.wrapping_add(other.0)) + } } -//------------------------------------------------------------------------------ -// OS Interface Code -//------------------------------------------------------------------------------ +impl From for Duration { + fn from(counter_value: GenericTimerCounterValue) -> Self { + if counter_value.0 == 0 { + return Duration::ZERO; + } -impl time::interface::TimeManager for GenericTimer { - fn resolution(&self) -> Duration { - Duration::from_nanos(NS_PER_S / (CNTFRQ_EL0.get() as u64)) + // Read volatile is needed here to prevent the compiler from optimizing + // ARCH_TIMER_COUNTER_FREQUENCY away. + // + // This is safe, because all the safety requirements as stated in read_volatile()'s + // documentation are fulfilled. + let frequency: NonZeroU64 = + unsafe { core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY) }.into(); + + // Div implementation for u64 cannot panic. + let secs = counter_value.0.div(frequency); + + // This is safe, because frequency can never be greater than u32::MAX, which means the + // largest theoretical value for sub_second_counter_value is (u32::MAX - 1). Therefore, + // (sub_second_counter_value * NANOSEC_PER_SEC) cannot overflow an u64. + // + // The subsequent division ensures the result fits into u32, since the max result is smaller + // than NANOSEC_PER_SEC. Therefore, just cast it to u32 using `as`. + let sub_second_counter_value = counter_value.0 % frequency; + let nanos = unsafe { sub_second_counter_value.unchecked_mul(u64::from(NANOSEC_PER_SEC)) } + .div(frequency) as u32; + + Duration::new(secs, nanos) } +} - fn uptime(&self) -> Duration { - let current_count: u64 = self.read_cntpct() * NS_PER_S; - let frq: u64 = CNTFRQ_EL0.get() as u64; +fn max_duration() -> Duration { + Duration::from(GenericTimerCounterValue::MAX) +} - Duration::from_nanos(current_count / frq) - } +impl TryFrom for GenericTimerCounterValue { + type Error = &'static str; - fn spin_for(&self, duration: Duration) { - // Instantly return on zero. - if duration.as_nanos() == 0 { - return; + fn try_from(duration: Duration) -> Result { + if duration < resolution() { + return Ok(GenericTimerCounterValue(0)); } - // Calculate the register compare value. - let frq = CNTFRQ_EL0.get(); - let x = match frq.checked_mul(duration.as_nanos() as u64) { - #[allow(unused_imports)] - None => { - warn!("Spin duration too long, skipping"); - return; - } - Some(val) => val, - }; - let tval = x / NS_PER_S; - - // Check if it is within supported bounds. - let warn: Option<&str> = if tval == 0 { - Some("smaller") - // The upper 32 bits of CNTP_TVAL_EL0 are reserved. - } else if tval > u32::max_value().into() { - Some("bigger") - } else { - None - }; - - #[allow(unused_imports)] - if let Some(w) = warn { - warn!( - "Spin duration {} than architecturally supported, skipping", - w - ); - return; + if duration > max_duration() { + return Err("Conversion error. Duration too big"); } - // Set the compare value register. - CNTP_TVAL_EL0.set(tval); + // This is safe, because all the safety requirements as stated in read_volatile()'s + // documentation are fulfilled. + let frequency: u128 = + unsafe { u32::from(core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY)) as u128 }; + let duration: u128 = duration.as_nanos(); - // Kick off the counting. // Disable timer interrupt. - CNTP_CTL_EL0.modify(CNTP_CTL_EL0::ENABLE::SET + CNTP_CTL_EL0::IMASK::SET); + // This is safe, because frequency can never be greater than u32::MAX, and + // (Duration::MAX.as_nanos() * u32::MAX) < u128::MAX. + let counter_value = + unsafe { duration.unchecked_mul(frequency) }.div(NonZeroU128::from(NANOSEC_PER_SEC)); - // ISTATUS will be '1' when cval ticks have passed. Busy-check it. - while !CNTP_CTL_EL0.matches_all(CNTP_CTL_EL0::ISTATUS::SET) {} - - // Disable counting again. - CNTP_CTL_EL0.modify(CNTP_CTL_EL0::ENABLE::CLEAR); + // Since we checked above that we are <= max_duration(), just cast to u64. + Ok(GenericTimerCounterValue(counter_value as u64)) } } + +#[inline(always)] +fn read_cntpct() -> GenericTimerCounterValue { + // Prevent that the counter is read ahead of time due to out-of-order execution. + unsafe { barrier::isb(barrier::SY) }; + let cnt = CNTPCT_EL0.get(); + + GenericTimerCounterValue(cnt) +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +/// The timer's resolution. +pub fn resolution() -> Duration { + Duration::from(GenericTimerCounterValue(1)) +} + +/// The uptime since power-on of the device. +/// +/// This includes time consumed by firmware and bootloaders. +pub fn uptime() -> Duration { + read_cntpct().into() +} + +/// Spin for a given duration. +pub fn spin_for(duration: Duration) { + let curr_counter_value = read_cntpct(); + + let counter_value_delta: GenericTimerCounterValue = match duration.try_into() { + Err(msg) => { + warn!("spin_for: {}. Skipping", msg); + return; + } + Ok(val) => val, + }; + let counter_value_target = curr_counter_value + counter_value_delta; + + // Busy wait. + // + // Read CNTPCT_EL0 directly to avoid the ISB that is part of [`read_cntpct`]. + while GenericTimerCounterValue(CNTPCT_EL0.get()) < counter_value_target {} +} diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs index b5603b40..0f3e701f 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs @@ -140,7 +140,7 @@ impl GPIOInner { /// Disable pull-up/down on pins 14 and 15. #[cfg(feature = "bsp_rpi3")] fn disable_pud_14_15_bcm2837(&mut self) { - use crate::{time, time::interface::TimeManager}; + use crate::time; use core::time::Duration; // The Linux 2837 GPIO driver waits 1 µs between the steps. diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/lib.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/lib.rs index 6c5bc6b3..194e2455 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/lib.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/lib.rs @@ -111,12 +111,15 @@ #![allow(clippy::upper_case_acronyms)] #![allow(incomplete_features)] #![feature(asm_const)] +#![feature(const_option)] #![feature(core_intrinsics)] #![feature(format_args_nl)] #![feature(int_roundings)] #![feature(linkage)] +#![feature(nonzero_min_max)] #![feature(panic_info_message)] #![feature(trait_alias)] +#![feature(unchecked_math)] #![no_std] // Testing #![cfg_attr(test, no_main)] diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/panic_wait.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/panic_wait.rs index 61831213..ae4651e7 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/panic_wait.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/panic_wait.rs @@ -59,8 +59,6 @@ fn panic_prevent_reenter() { #[panic_handler] fn panic(info: &PanicInfo) -> ! { - use crate::time::interface::TimeManager; - exception::asynchronous::local_irq_mask(); // Protect against panic infinite loops if any of the following code panics itself. diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/print.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/print.rs index 8705eec0..fe13b334 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/print.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/print.rs @@ -39,8 +39,6 @@ macro_rules! println { #[macro_export] macro_rules! info { ($string:expr) => ({ - use $crate::time::interface::TimeManager; - let timestamp = $crate::time::time_manager().uptime(); $crate::print::_print(format_args_nl!( @@ -50,8 +48,6 @@ macro_rules! info { )); }); ($format_string:expr, $($arg:tt)*) => ({ - use $crate::time::interface::TimeManager; - let timestamp = $crate::time::time_manager().uptime(); $crate::print::_print(format_args_nl!( @@ -67,8 +63,6 @@ macro_rules! info { #[macro_export] macro_rules! warn { ($string:expr) => ({ - use $crate::time::interface::TimeManager; - let timestamp = $crate::time::time_manager().uptime(); $crate::print::_print(format_args_nl!( @@ -78,8 +72,6 @@ macro_rules! warn { )); }); ($format_string:expr, $($arg:tt)*) => ({ - use $crate::time::interface::TimeManager; - let timestamp = $crate::time::time_manager().uptime(); $crate::print::_print(format_args_nl!( diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/time.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/time.rs index 6d92b196..a6c0c5b6 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/time.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/time.rs @@ -8,30 +8,50 @@ #[path = "_arch/aarch64/time.rs"] mod arch_time; +use core::time::Duration; + //-------------------------------------------------------------------------------------------------- -// Architectural Public Reexports +// Public Definitions //-------------------------------------------------------------------------------------------------- -pub use arch_time::time_manager; + +/// Provides time management functions. +pub struct TimeManager; //-------------------------------------------------------------------------------------------------- -// Public Definitions +// Global instances //-------------------------------------------------------------------------------------------------- -/// Timekeeping interfaces. -pub mod interface { - use core::time::Duration; +static TIME_MANAGER: TimeManager = TimeManager::new(); - /// Time management functions. - pub trait TimeManager { - /// The timer's resolution. - fn resolution(&self) -> Duration; +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- - /// The uptime since power-on of the device. - /// - /// This includes time consumed by firmware and bootloaders. - fn uptime(&self) -> Duration; +/// Return a reference to the global TimeManager. +pub fn time_manager() -> &'static TimeManager { + &TIME_MANAGER +} + +impl TimeManager { + /// Create an instance. + pub const fn new() -> Self { + Self + } + + /// The timer's resolution. + pub fn resolution(&self) -> Duration { + arch_time::resolution() + } + + /// The uptime since power-on of the device. + /// + /// This includes time consumed by firmware and bootloaders. + pub fn uptime(&self) -> Duration { + arch_time::uptime() + } - /// Spin for a given duration. - fn spin_for(&self, duration: Duration); + /// Spin for a given duration. + pub fn spin_for(&self, duration: Duration) { + arch_time::spin_for(duration) } } diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/tests/01_timer_sanity.rs b/13_exceptions_part2_peripheral_IRQs/kernel/tests/01_timer_sanity.rs index 390cdee5..a0eb732b 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/tests/01_timer_sanity.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/tests/01_timer_sanity.rs @@ -11,7 +11,7 @@ #![test_runner(libkernel::test_runner)] use core::time::Duration; -use libkernel::{bsp, cpu, driver, exception, time, time::interface::TimeManager}; +use libkernel::{bsp, cpu, driver, exception, time}; use test_macros::kernel_test; #[no_mangle] @@ -37,6 +37,7 @@ fn timer_is_counting() { /// Timer resolution must be sufficient. #[kernel_test] fn timer_resolution_is_sufficient() { + assert!(time::time_manager().resolution().as_nanos() > 0); assert!(time::time_manager().resolution().as_nanos() < 100) } diff --git a/14_virtual_mem_part2_mmio_remap/README.md b/14_virtual_mem_part2_mmio_remap/README.md index c6ef13f7..7dc0c7a3 100644 --- a/14_virtual_mem_part2_mmio_remap/README.md +++ b/14_virtual_mem_part2_mmio_remap/README.md @@ -2326,20 +2326,21 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/exception/asynchronous. diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/lib.rs 14_virtual_mem_part2_mmio_remap/kernel/src/lib.rs --- 13_exceptions_part2_peripheral_IRQs/kernel/src/lib.rs +++ 14_virtual_mem_part2_mmio_remap/kernel/src/lib.rs -@@ -113,9 +113,12 @@ - #![feature(asm_const)] +@@ -114,10 +114,13 @@ + #![feature(const_option)] #![feature(core_intrinsics)] #![feature(format_args_nl)] +#![feature(generic_const_exprs)] #![feature(int_roundings)] +#![feature(is_sorted)] #![feature(linkage)] + #![feature(nonzero_min_max)] #![feature(panic_info_message)] +#![feature(step_trait)] #![feature(trait_alias)] + #![feature(unchecked_math)] #![no_std] - // Testing -@@ -183,6 +186,17 @@ +@@ -186,6 +189,17 @@ use driver::interface::DriverManager; exception::handling_init(); @@ -3821,8 +3822,8 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/tests/01_timer_sanity.rs 14 #![test_runner(libkernel::test_runner)] use core::time::Duration; --use libkernel::{bsp, cpu, driver, exception, time, time::interface::TimeManager}; -+use libkernel::{bsp, cpu, driver, exception, memory, time, time::interface::TimeManager}; +-use libkernel::{bsp, cpu, driver, exception, time}; ++use libkernel::{bsp, cpu, driver, exception, memory, time}; use test_macros::kernel_test; #[no_mangle] diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/cpu/boot.s b/14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/cpu/boot.s index 7576dc14..f6df2123 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/cpu/boot.s +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/cpu/boot.s @@ -57,6 +57,14 @@ _start: ADR_REL x0, __boot_core_stack_end_exclusive mov sp, x0 + // Read the CPU's timer counter frequency and store it in ARCH_TIMER_COUNTER_FREQUENCY. + // Abort if the frequency read back as 0. + ADR_REL x1, ARCH_TIMER_COUNTER_FREQUENCY // provided by aarch64/time.rs + mrs x2, CNTFRQ_EL0 + cmp x2, xzr + b.eq .L_parking_loop + str w2, [x1] + // Jump to Rust code. x0 holds the function argument provided to _start_rust(). b _start_rust diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/time.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/time.rs index c814219c..255a5a45 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/time.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/time.rs @@ -11,111 +11,152 @@ //! //! crate::time::arch_time -use crate::{time, warn}; -use core::time::Duration; +use crate::warn; +use core::{ + num::{NonZeroU128, NonZeroU32, NonZeroU64}, + ops::{Add, Div}, + time::Duration, +}; use cortex_a::{asm::barrier, registers::*}; -use tock_registers::interfaces::{ReadWriteable, Readable, Writeable}; +use tock_registers::interfaces::Readable; //-------------------------------------------------------------------------------------------------- // Private Definitions //-------------------------------------------------------------------------------------------------- -const NS_PER_S: u64 = 1_000_000_000; +const NANOSEC_PER_SEC: NonZeroU64 = NonZeroU64::new(1_000_000_000).unwrap(); -/// ARMv8 Generic Timer. -struct GenericTimer; +#[derive(Copy, Clone, PartialOrd, PartialEq)] +struct GenericTimerCounterValue(u64); //-------------------------------------------------------------------------------------------------- // Global instances //-------------------------------------------------------------------------------------------------- -static TIME_MANAGER: GenericTimer = GenericTimer; +/// Boot assembly code overwrites this value with the value of CNTFRQ_EL0 before any Rust code is +/// executed. This given value here is just a (safe) dummy. +#[no_mangle] +static ARCH_TIMER_COUNTER_FREQUENCY: NonZeroU32 = NonZeroU32::MIN; //-------------------------------------------------------------------------------------------------- // Private Code //-------------------------------------------------------------------------------------------------- -impl GenericTimer { - #[inline(always)] - fn read_cntpct(&self) -> u64 { - // Prevent that the counter is read ahead of time due to out-of-order execution. - unsafe { barrier::isb(barrier::SY) }; - CNTPCT_EL0.get() - } +impl GenericTimerCounterValue { + pub const MAX: Self = GenericTimerCounterValue(u64::MAX); } -//-------------------------------------------------------------------------------------------------- -// Public Code -//-------------------------------------------------------------------------------------------------- +impl Add for GenericTimerCounterValue { + type Output = Self; -/// Return a reference to the time manager. -pub fn time_manager() -> &'static impl time::interface::TimeManager { - &TIME_MANAGER + fn add(self, other: Self) -> Self { + GenericTimerCounterValue(self.0.wrapping_add(other.0)) + } } -//------------------------------------------------------------------------------ -// OS Interface Code -//------------------------------------------------------------------------------ +impl From for Duration { + fn from(counter_value: GenericTimerCounterValue) -> Self { + if counter_value.0 == 0 { + return Duration::ZERO; + } -impl time::interface::TimeManager for GenericTimer { - fn resolution(&self) -> Duration { - Duration::from_nanos(NS_PER_S / (CNTFRQ_EL0.get() as u64)) + // Read volatile is needed here to prevent the compiler from optimizing + // ARCH_TIMER_COUNTER_FREQUENCY away. + // + // This is safe, because all the safety requirements as stated in read_volatile()'s + // documentation are fulfilled. + let frequency: NonZeroU64 = + unsafe { core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY) }.into(); + + // Div implementation for u64 cannot panic. + let secs = counter_value.0.div(frequency); + + // This is safe, because frequency can never be greater than u32::MAX, which means the + // largest theoretical value for sub_second_counter_value is (u32::MAX - 1). Therefore, + // (sub_second_counter_value * NANOSEC_PER_SEC) cannot overflow an u64. + // + // The subsequent division ensures the result fits into u32, since the max result is smaller + // than NANOSEC_PER_SEC. Therefore, just cast it to u32 using `as`. + let sub_second_counter_value = counter_value.0 % frequency; + let nanos = unsafe { sub_second_counter_value.unchecked_mul(u64::from(NANOSEC_PER_SEC)) } + .div(frequency) as u32; + + Duration::new(secs, nanos) } +} - fn uptime(&self) -> Duration { - let current_count: u64 = self.read_cntpct() * NS_PER_S; - let frq: u64 = CNTFRQ_EL0.get() as u64; +fn max_duration() -> Duration { + Duration::from(GenericTimerCounterValue::MAX) +} - Duration::from_nanos(current_count / frq) - } +impl TryFrom for GenericTimerCounterValue { + type Error = &'static str; - fn spin_for(&self, duration: Duration) { - // Instantly return on zero. - if duration.as_nanos() == 0 { - return; + fn try_from(duration: Duration) -> Result { + if duration < resolution() { + return Ok(GenericTimerCounterValue(0)); } - // Calculate the register compare value. - let frq = CNTFRQ_EL0.get(); - let x = match frq.checked_mul(duration.as_nanos() as u64) { - #[allow(unused_imports)] - None => { - warn!("Spin duration too long, skipping"); - return; - } - Some(val) => val, - }; - let tval = x / NS_PER_S; - - // Check if it is within supported bounds. - let warn: Option<&str> = if tval == 0 { - Some("smaller") - // The upper 32 bits of CNTP_TVAL_EL0 are reserved. - } else if tval > u32::max_value().into() { - Some("bigger") - } else { - None - }; - - #[allow(unused_imports)] - if let Some(w) = warn { - warn!( - "Spin duration {} than architecturally supported, skipping", - w - ); - return; + if duration > max_duration() { + return Err("Conversion error. Duration too big"); } - // Set the compare value register. - CNTP_TVAL_EL0.set(tval); + // This is safe, because all the safety requirements as stated in read_volatile()'s + // documentation are fulfilled. + let frequency: u128 = + unsafe { u32::from(core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY)) as u128 }; + let duration: u128 = duration.as_nanos(); - // Kick off the counting. // Disable timer interrupt. - CNTP_CTL_EL0.modify(CNTP_CTL_EL0::ENABLE::SET + CNTP_CTL_EL0::IMASK::SET); + // This is safe, because frequency can never be greater than u32::MAX, and + // (Duration::MAX.as_nanos() * u32::MAX) < u128::MAX. + let counter_value = + unsafe { duration.unchecked_mul(frequency) }.div(NonZeroU128::from(NANOSEC_PER_SEC)); - // ISTATUS will be '1' when cval ticks have passed. Busy-check it. - while !CNTP_CTL_EL0.matches_all(CNTP_CTL_EL0::ISTATUS::SET) {} - - // Disable counting again. - CNTP_CTL_EL0.modify(CNTP_CTL_EL0::ENABLE::CLEAR); + // Since we checked above that we are <= max_duration(), just cast to u64. + Ok(GenericTimerCounterValue(counter_value as u64)) } } + +#[inline(always)] +fn read_cntpct() -> GenericTimerCounterValue { + // Prevent that the counter is read ahead of time due to out-of-order execution. + unsafe { barrier::isb(barrier::SY) }; + let cnt = CNTPCT_EL0.get(); + + GenericTimerCounterValue(cnt) +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +/// The timer's resolution. +pub fn resolution() -> Duration { + Duration::from(GenericTimerCounterValue(1)) +} + +/// The uptime since power-on of the device. +/// +/// This includes time consumed by firmware and bootloaders. +pub fn uptime() -> Duration { + read_cntpct().into() +} + +/// Spin for a given duration. +pub fn spin_for(duration: Duration) { + let curr_counter_value = read_cntpct(); + + let counter_value_delta: GenericTimerCounterValue = match duration.try_into() { + Err(msg) => { + warn!("spin_for: {}. Skipping", msg); + return; + } + Ok(val) => val, + }; + let counter_value_target = curr_counter_value + counter_value_delta; + + // Busy wait. + // + // Read CNTPCT_EL0 directly to avoid the ISB that is part of [`read_cntpct`]. + while GenericTimerCounterValue(CNTPCT_EL0.get()) < counter_value_target {} +} diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs index a3361c2c..2281e66a 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs @@ -144,7 +144,7 @@ impl GPIOInner { /// Disable pull-up/down on pins 14 and 15. #[cfg(feature = "bsp_rpi3")] fn disable_pud_14_15_bcm2837(&mut self) { - use crate::{time, time::interface::TimeManager}; + use crate::time; use core::time::Duration; // The Linux 2837 GPIO driver waits 1 µs between the steps. diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/lib.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/lib.rs index c40cb4e7..22fb5fea 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/lib.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/lib.rs @@ -111,15 +111,18 @@ #![allow(clippy::upper_case_acronyms)] #![allow(incomplete_features)] #![feature(asm_const)] +#![feature(const_option)] #![feature(core_intrinsics)] #![feature(format_args_nl)] #![feature(generic_const_exprs)] #![feature(int_roundings)] #![feature(is_sorted)] #![feature(linkage)] +#![feature(nonzero_min_max)] #![feature(panic_info_message)] #![feature(step_trait)] #![feature(trait_alias)] +#![feature(unchecked_math)] #![no_std] // Testing #![cfg_attr(test, no_main)] diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/panic_wait.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/panic_wait.rs index 61831213..ae4651e7 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/panic_wait.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/panic_wait.rs @@ -59,8 +59,6 @@ fn panic_prevent_reenter() { #[panic_handler] fn panic(info: &PanicInfo) -> ! { - use crate::time::interface::TimeManager; - exception::asynchronous::local_irq_mask(); // Protect against panic infinite loops if any of the following code panics itself. diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/print.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/print.rs index 8705eec0..fe13b334 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/print.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/print.rs @@ -39,8 +39,6 @@ macro_rules! println { #[macro_export] macro_rules! info { ($string:expr) => ({ - use $crate::time::interface::TimeManager; - let timestamp = $crate::time::time_manager().uptime(); $crate::print::_print(format_args_nl!( @@ -50,8 +48,6 @@ macro_rules! info { )); }); ($format_string:expr, $($arg:tt)*) => ({ - use $crate::time::interface::TimeManager; - let timestamp = $crate::time::time_manager().uptime(); $crate::print::_print(format_args_nl!( @@ -67,8 +63,6 @@ macro_rules! info { #[macro_export] macro_rules! warn { ($string:expr) => ({ - use $crate::time::interface::TimeManager; - let timestamp = $crate::time::time_manager().uptime(); $crate::print::_print(format_args_nl!( @@ -78,8 +72,6 @@ macro_rules! warn { )); }); ($format_string:expr, $($arg:tt)*) => ({ - use $crate::time::interface::TimeManager; - let timestamp = $crate::time::time_manager().uptime(); $crate::print::_print(format_args_nl!( diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/time.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/time.rs index 6d92b196..a6c0c5b6 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/time.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/time.rs @@ -8,30 +8,50 @@ #[path = "_arch/aarch64/time.rs"] mod arch_time; +use core::time::Duration; + //-------------------------------------------------------------------------------------------------- -// Architectural Public Reexports +// Public Definitions //-------------------------------------------------------------------------------------------------- -pub use arch_time::time_manager; + +/// Provides time management functions. +pub struct TimeManager; //-------------------------------------------------------------------------------------------------- -// Public Definitions +// Global instances //-------------------------------------------------------------------------------------------------- -/// Timekeeping interfaces. -pub mod interface { - use core::time::Duration; +static TIME_MANAGER: TimeManager = TimeManager::new(); - /// Time management functions. - pub trait TimeManager { - /// The timer's resolution. - fn resolution(&self) -> Duration; +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- - /// The uptime since power-on of the device. - /// - /// This includes time consumed by firmware and bootloaders. - fn uptime(&self) -> Duration; +/// Return a reference to the global TimeManager. +pub fn time_manager() -> &'static TimeManager { + &TIME_MANAGER +} + +impl TimeManager { + /// Create an instance. + pub const fn new() -> Self { + Self + } + + /// The timer's resolution. + pub fn resolution(&self) -> Duration { + arch_time::resolution() + } + + /// The uptime since power-on of the device. + /// + /// This includes time consumed by firmware and bootloaders. + pub fn uptime(&self) -> Duration { + arch_time::uptime() + } - /// Spin for a given duration. - fn spin_for(&self, duration: Duration); + /// Spin for a given duration. + pub fn spin_for(&self, duration: Duration) { + arch_time::spin_for(duration) } } diff --git a/14_virtual_mem_part2_mmio_remap/kernel/tests/01_timer_sanity.rs b/14_virtual_mem_part2_mmio_remap/kernel/tests/01_timer_sanity.rs index dc3337e2..dd34b06c 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/tests/01_timer_sanity.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/tests/01_timer_sanity.rs @@ -11,7 +11,7 @@ #![test_runner(libkernel::test_runner)] use core::time::Duration; -use libkernel::{bsp, cpu, driver, exception, memory, time, time::interface::TimeManager}; +use libkernel::{bsp, cpu, driver, exception, memory, time}; use test_macros::kernel_test; #[no_mangle] @@ -48,6 +48,7 @@ fn timer_is_counting() { /// Timer resolution must be sufficient. #[kernel_test] fn timer_resolution_is_sufficient() { + assert!(time::time_manager().resolution().as_nanos() > 0); assert!(time::time_manager().resolution().as_nanos() < 100) } diff --git a/15_virtual_mem_part3_precomputed_tables/README.md b/15_virtual_mem_part3_precomputed_tables/README.md index 25c26c0a..a6ebe332 100644 --- a/15_virtual_mem_part3_precomputed_tables/README.md +++ b/15_virtual_mem_part3_precomputed_tables/README.md @@ -841,7 +841,7 @@ diff -uNr 14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/cpu/boot.rs 1 diff -uNr 14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/cpu/boot.s 15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/cpu/boot.s --- 14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/cpu/boot.s +++ 15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/cpu/boot.s -@@ -53,11 +53,14 @@ +@@ -53,19 +53,22 @@ // Prepare the jump to Rust code. .L_prepare_rust: @@ -854,6 +854,18 @@ diff -uNr 14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/cpu/boot.s 15 + ADR_REL x1, __boot_core_stack_end_exclusive + mov sp, x1 + // Read the CPU's timer counter frequency and store it in ARCH_TIMER_COUNTER_FREQUENCY. + // Abort if the frequency read back as 0. +- ADR_REL x1, ARCH_TIMER_COUNTER_FREQUENCY // provided by aarch64/time.rs +- mrs x2, CNTFRQ_EL0 +- cmp x2, xzr ++ ADR_REL x2, ARCH_TIMER_COUNTER_FREQUENCY // provided by aarch64/time.rs ++ mrs x3, CNTFRQ_EL0 ++ cmp x3, xzr + b.eq .L_parking_loop +- str w2, [x1] ++ str w3, [x2] + - // Jump to Rust code. x0 holds the function argument provided to _start_rust(). + // Jump to Rust code. x0 and x1 hold the function arguments provided to _start_rust(). b _start_rust @@ -1324,7 +1336,7 @@ diff -uNr 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/memory/mmu. diff -uNr 14_virtual_mem_part2_mmio_remap/kernel/src/lib.rs 15_virtual_mem_part3_precomputed_tables/kernel/src/lib.rs --- 14_virtual_mem_part2_mmio_remap/kernel/src/lib.rs +++ 15_virtual_mem_part3_precomputed_tables/kernel/src/lib.rs -@@ -186,17 +186,7 @@ +@@ -189,17 +189,7 @@ use driver::interface::DriverManager; exception::handling_init(); diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/cpu/boot.s b/15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/cpu/boot.s index dba8c88e..48c3f8a7 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/cpu/boot.s +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/cpu/boot.s @@ -60,6 +60,14 @@ _start: ADR_REL x1, __boot_core_stack_end_exclusive mov sp, x1 + // Read the CPU's timer counter frequency and store it in ARCH_TIMER_COUNTER_FREQUENCY. + // Abort if the frequency read back as 0. + ADR_REL x2, ARCH_TIMER_COUNTER_FREQUENCY // provided by aarch64/time.rs + mrs x3, CNTFRQ_EL0 + cmp x3, xzr + b.eq .L_parking_loop + str w3, [x2] + // Jump to Rust code. x0 and x1 hold the function arguments provided to _start_rust(). b _start_rust diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/time.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/time.rs index c814219c..255a5a45 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/time.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/time.rs @@ -11,111 +11,152 @@ //! //! crate::time::arch_time -use crate::{time, warn}; -use core::time::Duration; +use crate::warn; +use core::{ + num::{NonZeroU128, NonZeroU32, NonZeroU64}, + ops::{Add, Div}, + time::Duration, +}; use cortex_a::{asm::barrier, registers::*}; -use tock_registers::interfaces::{ReadWriteable, Readable, Writeable}; +use tock_registers::interfaces::Readable; //-------------------------------------------------------------------------------------------------- // Private Definitions //-------------------------------------------------------------------------------------------------- -const NS_PER_S: u64 = 1_000_000_000; +const NANOSEC_PER_SEC: NonZeroU64 = NonZeroU64::new(1_000_000_000).unwrap(); -/// ARMv8 Generic Timer. -struct GenericTimer; +#[derive(Copy, Clone, PartialOrd, PartialEq)] +struct GenericTimerCounterValue(u64); //-------------------------------------------------------------------------------------------------- // Global instances //-------------------------------------------------------------------------------------------------- -static TIME_MANAGER: GenericTimer = GenericTimer; +/// Boot assembly code overwrites this value with the value of CNTFRQ_EL0 before any Rust code is +/// executed. This given value here is just a (safe) dummy. +#[no_mangle] +static ARCH_TIMER_COUNTER_FREQUENCY: NonZeroU32 = NonZeroU32::MIN; //-------------------------------------------------------------------------------------------------- // Private Code //-------------------------------------------------------------------------------------------------- -impl GenericTimer { - #[inline(always)] - fn read_cntpct(&self) -> u64 { - // Prevent that the counter is read ahead of time due to out-of-order execution. - unsafe { barrier::isb(barrier::SY) }; - CNTPCT_EL0.get() - } +impl GenericTimerCounterValue { + pub const MAX: Self = GenericTimerCounterValue(u64::MAX); } -//-------------------------------------------------------------------------------------------------- -// Public Code -//-------------------------------------------------------------------------------------------------- +impl Add for GenericTimerCounterValue { + type Output = Self; -/// Return a reference to the time manager. -pub fn time_manager() -> &'static impl time::interface::TimeManager { - &TIME_MANAGER + fn add(self, other: Self) -> Self { + GenericTimerCounterValue(self.0.wrapping_add(other.0)) + } } -//------------------------------------------------------------------------------ -// OS Interface Code -//------------------------------------------------------------------------------ +impl From for Duration { + fn from(counter_value: GenericTimerCounterValue) -> Self { + if counter_value.0 == 0 { + return Duration::ZERO; + } -impl time::interface::TimeManager for GenericTimer { - fn resolution(&self) -> Duration { - Duration::from_nanos(NS_PER_S / (CNTFRQ_EL0.get() as u64)) + // Read volatile is needed here to prevent the compiler from optimizing + // ARCH_TIMER_COUNTER_FREQUENCY away. + // + // This is safe, because all the safety requirements as stated in read_volatile()'s + // documentation are fulfilled. + let frequency: NonZeroU64 = + unsafe { core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY) }.into(); + + // Div implementation for u64 cannot panic. + let secs = counter_value.0.div(frequency); + + // This is safe, because frequency can never be greater than u32::MAX, which means the + // largest theoretical value for sub_second_counter_value is (u32::MAX - 1). Therefore, + // (sub_second_counter_value * NANOSEC_PER_SEC) cannot overflow an u64. + // + // The subsequent division ensures the result fits into u32, since the max result is smaller + // than NANOSEC_PER_SEC. Therefore, just cast it to u32 using `as`. + let sub_second_counter_value = counter_value.0 % frequency; + let nanos = unsafe { sub_second_counter_value.unchecked_mul(u64::from(NANOSEC_PER_SEC)) } + .div(frequency) as u32; + + Duration::new(secs, nanos) } +} - fn uptime(&self) -> Duration { - let current_count: u64 = self.read_cntpct() * NS_PER_S; - let frq: u64 = CNTFRQ_EL0.get() as u64; +fn max_duration() -> Duration { + Duration::from(GenericTimerCounterValue::MAX) +} - Duration::from_nanos(current_count / frq) - } +impl TryFrom for GenericTimerCounterValue { + type Error = &'static str; - fn spin_for(&self, duration: Duration) { - // Instantly return on zero. - if duration.as_nanos() == 0 { - return; + fn try_from(duration: Duration) -> Result { + if duration < resolution() { + return Ok(GenericTimerCounterValue(0)); } - // Calculate the register compare value. - let frq = CNTFRQ_EL0.get(); - let x = match frq.checked_mul(duration.as_nanos() as u64) { - #[allow(unused_imports)] - None => { - warn!("Spin duration too long, skipping"); - return; - } - Some(val) => val, - }; - let tval = x / NS_PER_S; - - // Check if it is within supported bounds. - let warn: Option<&str> = if tval == 0 { - Some("smaller") - // The upper 32 bits of CNTP_TVAL_EL0 are reserved. - } else if tval > u32::max_value().into() { - Some("bigger") - } else { - None - }; - - #[allow(unused_imports)] - if let Some(w) = warn { - warn!( - "Spin duration {} than architecturally supported, skipping", - w - ); - return; + if duration > max_duration() { + return Err("Conversion error. Duration too big"); } - // Set the compare value register. - CNTP_TVAL_EL0.set(tval); + // This is safe, because all the safety requirements as stated in read_volatile()'s + // documentation are fulfilled. + let frequency: u128 = + unsafe { u32::from(core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY)) as u128 }; + let duration: u128 = duration.as_nanos(); - // Kick off the counting. // Disable timer interrupt. - CNTP_CTL_EL0.modify(CNTP_CTL_EL0::ENABLE::SET + CNTP_CTL_EL0::IMASK::SET); + // This is safe, because frequency can never be greater than u32::MAX, and + // (Duration::MAX.as_nanos() * u32::MAX) < u128::MAX. + let counter_value = + unsafe { duration.unchecked_mul(frequency) }.div(NonZeroU128::from(NANOSEC_PER_SEC)); - // ISTATUS will be '1' when cval ticks have passed. Busy-check it. - while !CNTP_CTL_EL0.matches_all(CNTP_CTL_EL0::ISTATUS::SET) {} - - // Disable counting again. - CNTP_CTL_EL0.modify(CNTP_CTL_EL0::ENABLE::CLEAR); + // Since we checked above that we are <= max_duration(), just cast to u64. + Ok(GenericTimerCounterValue(counter_value as u64)) } } + +#[inline(always)] +fn read_cntpct() -> GenericTimerCounterValue { + // Prevent that the counter is read ahead of time due to out-of-order execution. + unsafe { barrier::isb(barrier::SY) }; + let cnt = CNTPCT_EL0.get(); + + GenericTimerCounterValue(cnt) +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +/// The timer's resolution. +pub fn resolution() -> Duration { + Duration::from(GenericTimerCounterValue(1)) +} + +/// The uptime since power-on of the device. +/// +/// This includes time consumed by firmware and bootloaders. +pub fn uptime() -> Duration { + read_cntpct().into() +} + +/// Spin for a given duration. +pub fn spin_for(duration: Duration) { + let curr_counter_value = read_cntpct(); + + let counter_value_delta: GenericTimerCounterValue = match duration.try_into() { + Err(msg) => { + warn!("spin_for: {}. Skipping", msg); + return; + } + Ok(val) => val, + }; + let counter_value_target = curr_counter_value + counter_value_delta; + + // Busy wait. + // + // Read CNTPCT_EL0 directly to avoid the ISB that is part of [`read_cntpct`]. + while GenericTimerCounterValue(CNTPCT_EL0.get()) < counter_value_target {} +} diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs index a3361c2c..2281e66a 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs @@ -144,7 +144,7 @@ impl GPIOInner { /// Disable pull-up/down on pins 14 and 15. #[cfg(feature = "bsp_rpi3")] fn disable_pud_14_15_bcm2837(&mut self) { - use crate::{time, time::interface::TimeManager}; + use crate::time; use core::time::Duration; // The Linux 2837 GPIO driver waits 1 µs between the steps. diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/lib.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/lib.rs index a9577868..26c147d6 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/lib.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/lib.rs @@ -111,15 +111,18 @@ #![allow(clippy::upper_case_acronyms)] #![allow(incomplete_features)] #![feature(asm_const)] +#![feature(const_option)] #![feature(core_intrinsics)] #![feature(format_args_nl)] #![feature(generic_const_exprs)] #![feature(int_roundings)] #![feature(is_sorted)] #![feature(linkage)] +#![feature(nonzero_min_max)] #![feature(panic_info_message)] #![feature(step_trait)] #![feature(trait_alias)] +#![feature(unchecked_math)] #![no_std] // Testing #![cfg_attr(test, no_main)] diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/panic_wait.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/panic_wait.rs index 61831213..ae4651e7 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/panic_wait.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/panic_wait.rs @@ -59,8 +59,6 @@ fn panic_prevent_reenter() { #[panic_handler] fn panic(info: &PanicInfo) -> ! { - use crate::time::interface::TimeManager; - exception::asynchronous::local_irq_mask(); // Protect against panic infinite loops if any of the following code panics itself. diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/print.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/print.rs index 8705eec0..fe13b334 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/print.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/print.rs @@ -39,8 +39,6 @@ macro_rules! println { #[macro_export] macro_rules! info { ($string:expr) => ({ - use $crate::time::interface::TimeManager; - let timestamp = $crate::time::time_manager().uptime(); $crate::print::_print(format_args_nl!( @@ -50,8 +48,6 @@ macro_rules! info { )); }); ($format_string:expr, $($arg:tt)*) => ({ - use $crate::time::interface::TimeManager; - let timestamp = $crate::time::time_manager().uptime(); $crate::print::_print(format_args_nl!( @@ -67,8 +63,6 @@ macro_rules! info { #[macro_export] macro_rules! warn { ($string:expr) => ({ - use $crate::time::interface::TimeManager; - let timestamp = $crate::time::time_manager().uptime(); $crate::print::_print(format_args_nl!( @@ -78,8 +72,6 @@ macro_rules! warn { )); }); ($format_string:expr, $($arg:tt)*) => ({ - use $crate::time::interface::TimeManager; - let timestamp = $crate::time::time_manager().uptime(); $crate::print::_print(format_args_nl!( diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/time.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/time.rs index 6d92b196..a6c0c5b6 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/time.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/time.rs @@ -8,30 +8,50 @@ #[path = "_arch/aarch64/time.rs"] mod arch_time; +use core::time::Duration; + //-------------------------------------------------------------------------------------------------- -// Architectural Public Reexports +// Public Definitions //-------------------------------------------------------------------------------------------------- -pub use arch_time::time_manager; + +/// Provides time management functions. +pub struct TimeManager; //-------------------------------------------------------------------------------------------------- -// Public Definitions +// Global instances //-------------------------------------------------------------------------------------------------- -/// Timekeeping interfaces. -pub mod interface { - use core::time::Duration; +static TIME_MANAGER: TimeManager = TimeManager::new(); - /// Time management functions. - pub trait TimeManager { - /// The timer's resolution. - fn resolution(&self) -> Duration; +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- - /// The uptime since power-on of the device. - /// - /// This includes time consumed by firmware and bootloaders. - fn uptime(&self) -> Duration; +/// Return a reference to the global TimeManager. +pub fn time_manager() -> &'static TimeManager { + &TIME_MANAGER +} + +impl TimeManager { + /// Create an instance. + pub const fn new() -> Self { + Self + } + + /// The timer's resolution. + pub fn resolution(&self) -> Duration { + arch_time::resolution() + } + + /// The uptime since power-on of the device. + /// + /// This includes time consumed by firmware and bootloaders. + pub fn uptime(&self) -> Duration { + arch_time::uptime() + } - /// Spin for a given duration. - fn spin_for(&self, duration: Duration); + /// Spin for a given duration. + pub fn spin_for(&self, duration: Duration) { + arch_time::spin_for(duration) } } diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/tests/01_timer_sanity.rs b/15_virtual_mem_part3_precomputed_tables/kernel/tests/01_timer_sanity.rs index d5d76a5c..39899332 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/tests/01_timer_sanity.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/tests/01_timer_sanity.rs @@ -11,7 +11,7 @@ #![test_runner(libkernel::test_runner)] use core::time::Duration; -use libkernel::{bsp, cpu, driver, exception, memory, time, time::interface::TimeManager}; +use libkernel::{bsp, cpu, driver, exception, memory, time}; use test_macros::kernel_test; #[no_mangle] @@ -38,6 +38,7 @@ fn timer_is_counting() { /// Timer resolution must be sufficient. #[kernel_test] fn timer_resolution_is_sufficient() { + assert!(time::time_manager().resolution().as_nanos() > 0); assert!(time::time_manager().resolution().as_nanos() < 100) } diff --git a/16_virtual_mem_part4_higher_half_kernel/README.md b/16_virtual_mem_part4_higher_half_kernel/README.md index 443c7223..6918f897 100644 --- a/16_virtual_mem_part4_higher_half_kernel/README.md +++ b/16_virtual_mem_part4_higher_half_kernel/README.md @@ -412,7 +412,7 @@ diff -uNr 15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/cpu/b //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- -@@ -56,11 +68,23 @@ +@@ -56,19 +68,31 @@ // Load the base address of the kernel's translation tables. ldr x0, PHYS_KERNEL_TABLES_BASE_ADDR // provided by bsp/__board_name__/memory/mmu.rs @@ -435,6 +435,18 @@ diff -uNr 15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/cpu/b + ADR_REL x4, __boot_core_stack_end_exclusive + mov sp, x4 + // Read the CPU's timer counter frequency and store it in ARCH_TIMER_COUNTER_FREQUENCY. + // Abort if the frequency read back as 0. +- ADR_REL x2, ARCH_TIMER_COUNTER_FREQUENCY // provided by aarch64/time.rs +- mrs x3, CNTFRQ_EL0 +- cmp x3, xzr ++ ADR_REL x5, ARCH_TIMER_COUNTER_FREQUENCY // provided by aarch64/time.rs ++ mrs x6, CNTFRQ_EL0 ++ cmp x6, xzr + b.eq .L_parking_loop +- str w3, [x2] ++ str w6, [x5] + - // Jump to Rust code. x0 and x1 hold the function arguments provided to _start_rust(). + // Jump to Rust code. x0, x1 and x2 hold the function arguments provided to _start_rust(). b _start_rust @@ -731,7 +743,7 @@ diff -uNr 15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/mem diff -uNr 15_virtual_mem_part3_precomputed_tables/kernel/src/lib.rs 16_virtual_mem_part4_higher_half_kernel/kernel/src/lib.rs --- 15_virtual_mem_part3_precomputed_tables/kernel/src/lib.rs +++ 16_virtual_mem_part4_higher_half_kernel/kernel/src/lib.rs -@@ -154,11 +154,6 @@ +@@ -157,11 +157,6 @@ ) } diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/cpu/boot.s b/16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/cpu/boot.s index 8c70d035..bf6e32e4 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/cpu/boot.s +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/cpu/boot.s @@ -84,6 +84,14 @@ _start: ADR_REL x4, __boot_core_stack_end_exclusive mov sp, x4 + // Read the CPU's timer counter frequency and store it in ARCH_TIMER_COUNTER_FREQUENCY. + // Abort if the frequency read back as 0. + ADR_REL x5, ARCH_TIMER_COUNTER_FREQUENCY // provided by aarch64/time.rs + mrs x6, CNTFRQ_EL0 + cmp x6, xzr + b.eq .L_parking_loop + str w6, [x5] + // Jump to Rust code. x0, x1 and x2 hold the function arguments provided to _start_rust(). b _start_rust diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/time.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/time.rs index c814219c..255a5a45 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/time.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/time.rs @@ -11,111 +11,152 @@ //! //! crate::time::arch_time -use crate::{time, warn}; -use core::time::Duration; +use crate::warn; +use core::{ + num::{NonZeroU128, NonZeroU32, NonZeroU64}, + ops::{Add, Div}, + time::Duration, +}; use cortex_a::{asm::barrier, registers::*}; -use tock_registers::interfaces::{ReadWriteable, Readable, Writeable}; +use tock_registers::interfaces::Readable; //-------------------------------------------------------------------------------------------------- // Private Definitions //-------------------------------------------------------------------------------------------------- -const NS_PER_S: u64 = 1_000_000_000; +const NANOSEC_PER_SEC: NonZeroU64 = NonZeroU64::new(1_000_000_000).unwrap(); -/// ARMv8 Generic Timer. -struct GenericTimer; +#[derive(Copy, Clone, PartialOrd, PartialEq)] +struct GenericTimerCounterValue(u64); //-------------------------------------------------------------------------------------------------- // Global instances //-------------------------------------------------------------------------------------------------- -static TIME_MANAGER: GenericTimer = GenericTimer; +/// Boot assembly code overwrites this value with the value of CNTFRQ_EL0 before any Rust code is +/// executed. This given value here is just a (safe) dummy. +#[no_mangle] +static ARCH_TIMER_COUNTER_FREQUENCY: NonZeroU32 = NonZeroU32::MIN; //-------------------------------------------------------------------------------------------------- // Private Code //-------------------------------------------------------------------------------------------------- -impl GenericTimer { - #[inline(always)] - fn read_cntpct(&self) -> u64 { - // Prevent that the counter is read ahead of time due to out-of-order execution. - unsafe { barrier::isb(barrier::SY) }; - CNTPCT_EL0.get() - } +impl GenericTimerCounterValue { + pub const MAX: Self = GenericTimerCounterValue(u64::MAX); } -//-------------------------------------------------------------------------------------------------- -// Public Code -//-------------------------------------------------------------------------------------------------- +impl Add for GenericTimerCounterValue { + type Output = Self; -/// Return a reference to the time manager. -pub fn time_manager() -> &'static impl time::interface::TimeManager { - &TIME_MANAGER + fn add(self, other: Self) -> Self { + GenericTimerCounterValue(self.0.wrapping_add(other.0)) + } } -//------------------------------------------------------------------------------ -// OS Interface Code -//------------------------------------------------------------------------------ +impl From for Duration { + fn from(counter_value: GenericTimerCounterValue) -> Self { + if counter_value.0 == 0 { + return Duration::ZERO; + } -impl time::interface::TimeManager for GenericTimer { - fn resolution(&self) -> Duration { - Duration::from_nanos(NS_PER_S / (CNTFRQ_EL0.get() as u64)) + // Read volatile is needed here to prevent the compiler from optimizing + // ARCH_TIMER_COUNTER_FREQUENCY away. + // + // This is safe, because all the safety requirements as stated in read_volatile()'s + // documentation are fulfilled. + let frequency: NonZeroU64 = + unsafe { core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY) }.into(); + + // Div implementation for u64 cannot panic. + let secs = counter_value.0.div(frequency); + + // This is safe, because frequency can never be greater than u32::MAX, which means the + // largest theoretical value for sub_second_counter_value is (u32::MAX - 1). Therefore, + // (sub_second_counter_value * NANOSEC_PER_SEC) cannot overflow an u64. + // + // The subsequent division ensures the result fits into u32, since the max result is smaller + // than NANOSEC_PER_SEC. Therefore, just cast it to u32 using `as`. + let sub_second_counter_value = counter_value.0 % frequency; + let nanos = unsafe { sub_second_counter_value.unchecked_mul(u64::from(NANOSEC_PER_SEC)) } + .div(frequency) as u32; + + Duration::new(secs, nanos) } +} - fn uptime(&self) -> Duration { - let current_count: u64 = self.read_cntpct() * NS_PER_S; - let frq: u64 = CNTFRQ_EL0.get() as u64; +fn max_duration() -> Duration { + Duration::from(GenericTimerCounterValue::MAX) +} - Duration::from_nanos(current_count / frq) - } +impl TryFrom for GenericTimerCounterValue { + type Error = &'static str; - fn spin_for(&self, duration: Duration) { - // Instantly return on zero. - if duration.as_nanos() == 0 { - return; + fn try_from(duration: Duration) -> Result { + if duration < resolution() { + return Ok(GenericTimerCounterValue(0)); } - // Calculate the register compare value. - let frq = CNTFRQ_EL0.get(); - let x = match frq.checked_mul(duration.as_nanos() as u64) { - #[allow(unused_imports)] - None => { - warn!("Spin duration too long, skipping"); - return; - } - Some(val) => val, - }; - let tval = x / NS_PER_S; - - // Check if it is within supported bounds. - let warn: Option<&str> = if tval == 0 { - Some("smaller") - // The upper 32 bits of CNTP_TVAL_EL0 are reserved. - } else if tval > u32::max_value().into() { - Some("bigger") - } else { - None - }; - - #[allow(unused_imports)] - if let Some(w) = warn { - warn!( - "Spin duration {} than architecturally supported, skipping", - w - ); - return; + if duration > max_duration() { + return Err("Conversion error. Duration too big"); } - // Set the compare value register. - CNTP_TVAL_EL0.set(tval); + // This is safe, because all the safety requirements as stated in read_volatile()'s + // documentation are fulfilled. + let frequency: u128 = + unsafe { u32::from(core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY)) as u128 }; + let duration: u128 = duration.as_nanos(); - // Kick off the counting. // Disable timer interrupt. - CNTP_CTL_EL0.modify(CNTP_CTL_EL0::ENABLE::SET + CNTP_CTL_EL0::IMASK::SET); + // This is safe, because frequency can never be greater than u32::MAX, and + // (Duration::MAX.as_nanos() * u32::MAX) < u128::MAX. + let counter_value = + unsafe { duration.unchecked_mul(frequency) }.div(NonZeroU128::from(NANOSEC_PER_SEC)); - // ISTATUS will be '1' when cval ticks have passed. Busy-check it. - while !CNTP_CTL_EL0.matches_all(CNTP_CTL_EL0::ISTATUS::SET) {} - - // Disable counting again. - CNTP_CTL_EL0.modify(CNTP_CTL_EL0::ENABLE::CLEAR); + // Since we checked above that we are <= max_duration(), just cast to u64. + Ok(GenericTimerCounterValue(counter_value as u64)) } } + +#[inline(always)] +fn read_cntpct() -> GenericTimerCounterValue { + // Prevent that the counter is read ahead of time due to out-of-order execution. + unsafe { barrier::isb(barrier::SY) }; + let cnt = CNTPCT_EL0.get(); + + GenericTimerCounterValue(cnt) +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +/// The timer's resolution. +pub fn resolution() -> Duration { + Duration::from(GenericTimerCounterValue(1)) +} + +/// The uptime since power-on of the device. +/// +/// This includes time consumed by firmware and bootloaders. +pub fn uptime() -> Duration { + read_cntpct().into() +} + +/// Spin for a given duration. +pub fn spin_for(duration: Duration) { + let curr_counter_value = read_cntpct(); + + let counter_value_delta: GenericTimerCounterValue = match duration.try_into() { + Err(msg) => { + warn!("spin_for: {}. Skipping", msg); + return; + } + Ok(val) => val, + }; + let counter_value_target = curr_counter_value + counter_value_delta; + + // Busy wait. + // + // Read CNTPCT_EL0 directly to avoid the ISB that is part of [`read_cntpct`]. + while GenericTimerCounterValue(CNTPCT_EL0.get()) < counter_value_target {} +} diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs index a3361c2c..2281e66a 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs @@ -144,7 +144,7 @@ impl GPIOInner { /// Disable pull-up/down on pins 14 and 15. #[cfg(feature = "bsp_rpi3")] fn disable_pud_14_15_bcm2837(&mut self) { - use crate::{time, time::interface::TimeManager}; + use crate::time; use core::time::Duration; // The Linux 2837 GPIO driver waits 1 µs between the steps. diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/lib.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/lib.rs index 1483c5a3..59ef14ac 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/lib.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/lib.rs @@ -111,15 +111,18 @@ #![allow(clippy::upper_case_acronyms)] #![allow(incomplete_features)] #![feature(asm_const)] +#![feature(const_option)] #![feature(core_intrinsics)] #![feature(format_args_nl)] #![feature(generic_const_exprs)] #![feature(int_roundings)] #![feature(is_sorted)] #![feature(linkage)] +#![feature(nonzero_min_max)] #![feature(panic_info_message)] #![feature(step_trait)] #![feature(trait_alias)] +#![feature(unchecked_math)] #![no_std] // Testing #![cfg_attr(test, no_main)] diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/panic_wait.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/panic_wait.rs index 61831213..ae4651e7 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/panic_wait.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/panic_wait.rs @@ -59,8 +59,6 @@ fn panic_prevent_reenter() { #[panic_handler] fn panic(info: &PanicInfo) -> ! { - use crate::time::interface::TimeManager; - exception::asynchronous::local_irq_mask(); // Protect against panic infinite loops if any of the following code panics itself. diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/print.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/print.rs index 8705eec0..fe13b334 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/print.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/print.rs @@ -39,8 +39,6 @@ macro_rules! println { #[macro_export] macro_rules! info { ($string:expr) => ({ - use $crate::time::interface::TimeManager; - let timestamp = $crate::time::time_manager().uptime(); $crate::print::_print(format_args_nl!( @@ -50,8 +48,6 @@ macro_rules! info { )); }); ($format_string:expr, $($arg:tt)*) => ({ - use $crate::time::interface::TimeManager; - let timestamp = $crate::time::time_manager().uptime(); $crate::print::_print(format_args_nl!( @@ -67,8 +63,6 @@ macro_rules! info { #[macro_export] macro_rules! warn { ($string:expr) => ({ - use $crate::time::interface::TimeManager; - let timestamp = $crate::time::time_manager().uptime(); $crate::print::_print(format_args_nl!( @@ -78,8 +72,6 @@ macro_rules! warn { )); }); ($format_string:expr, $($arg:tt)*) => ({ - use $crate::time::interface::TimeManager; - let timestamp = $crate::time::time_manager().uptime(); $crate::print::_print(format_args_nl!( diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/time.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/time.rs index 6d92b196..a6c0c5b6 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/time.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/time.rs @@ -8,30 +8,50 @@ #[path = "_arch/aarch64/time.rs"] mod arch_time; +use core::time::Duration; + //-------------------------------------------------------------------------------------------------- -// Architectural Public Reexports +// Public Definitions //-------------------------------------------------------------------------------------------------- -pub use arch_time::time_manager; + +/// Provides time management functions. +pub struct TimeManager; //-------------------------------------------------------------------------------------------------- -// Public Definitions +// Global instances //-------------------------------------------------------------------------------------------------- -/// Timekeeping interfaces. -pub mod interface { - use core::time::Duration; +static TIME_MANAGER: TimeManager = TimeManager::new(); - /// Time management functions. - pub trait TimeManager { - /// The timer's resolution. - fn resolution(&self) -> Duration; +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- - /// The uptime since power-on of the device. - /// - /// This includes time consumed by firmware and bootloaders. - fn uptime(&self) -> Duration; +/// Return a reference to the global TimeManager. +pub fn time_manager() -> &'static TimeManager { + &TIME_MANAGER +} + +impl TimeManager { + /// Create an instance. + pub const fn new() -> Self { + Self + } + + /// The timer's resolution. + pub fn resolution(&self) -> Duration { + arch_time::resolution() + } + + /// The uptime since power-on of the device. + /// + /// This includes time consumed by firmware and bootloaders. + pub fn uptime(&self) -> Duration { + arch_time::uptime() + } - /// Spin for a given duration. - fn spin_for(&self, duration: Duration); + /// Spin for a given duration. + pub fn spin_for(&self, duration: Duration) { + arch_time::spin_for(duration) } } diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/tests/01_timer_sanity.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/tests/01_timer_sanity.rs index d5d76a5c..39899332 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/tests/01_timer_sanity.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/tests/01_timer_sanity.rs @@ -11,7 +11,7 @@ #![test_runner(libkernel::test_runner)] use core::time::Duration; -use libkernel::{bsp, cpu, driver, exception, memory, time, time::interface::TimeManager}; +use libkernel::{bsp, cpu, driver, exception, memory, time}; use test_macros::kernel_test; #[no_mangle] @@ -38,6 +38,7 @@ fn timer_is_counting() { /// Timer resolution must be sufficient. #[kernel_test] fn timer_resolution_is_sufficient() { + assert!(time::time_manager().resolution().as_nanos() > 0); assert!(time::time_manager().resolution().as_nanos() < 100) } diff --git a/17_kernel_symbols/README.md b/17_kernel_symbols/README.md index ace1ed6e..699cfe2c 100644 --- a/17_kernel_symbols/README.md +++ b/17_kernel_symbols/README.md @@ -326,7 +326,7 @@ diff -uNr 16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi/mem diff -uNr 16_virtual_mem_part4_higher_half_kernel/kernel/src/lib.rs 17_kernel_symbols/kernel/src/lib.rs --- 16_virtual_mem_part4_higher_half_kernel/kernel/src/lib.rs +++ 17_kernel_symbols/kernel/src/lib.rs -@@ -139,6 +139,7 @@ +@@ -142,6 +142,7 @@ pub mod memory; pub mod print; pub mod state; diff --git a/17_kernel_symbols/kernel/src/_arch/aarch64/cpu/boot.s b/17_kernel_symbols/kernel/src/_arch/aarch64/cpu/boot.s index 8c70d035..bf6e32e4 100644 --- a/17_kernel_symbols/kernel/src/_arch/aarch64/cpu/boot.s +++ b/17_kernel_symbols/kernel/src/_arch/aarch64/cpu/boot.s @@ -84,6 +84,14 @@ _start: ADR_REL x4, __boot_core_stack_end_exclusive mov sp, x4 + // Read the CPU's timer counter frequency and store it in ARCH_TIMER_COUNTER_FREQUENCY. + // Abort if the frequency read back as 0. + ADR_REL x5, ARCH_TIMER_COUNTER_FREQUENCY // provided by aarch64/time.rs + mrs x6, CNTFRQ_EL0 + cmp x6, xzr + b.eq .L_parking_loop + str w6, [x5] + // Jump to Rust code. x0, x1 and x2 hold the function arguments provided to _start_rust(). b _start_rust diff --git a/17_kernel_symbols/kernel/src/_arch/aarch64/time.rs b/17_kernel_symbols/kernel/src/_arch/aarch64/time.rs index c814219c..255a5a45 100644 --- a/17_kernel_symbols/kernel/src/_arch/aarch64/time.rs +++ b/17_kernel_symbols/kernel/src/_arch/aarch64/time.rs @@ -11,111 +11,152 @@ //! //! crate::time::arch_time -use crate::{time, warn}; -use core::time::Duration; +use crate::warn; +use core::{ + num::{NonZeroU128, NonZeroU32, NonZeroU64}, + ops::{Add, Div}, + time::Duration, +}; use cortex_a::{asm::barrier, registers::*}; -use tock_registers::interfaces::{ReadWriteable, Readable, Writeable}; +use tock_registers::interfaces::Readable; //-------------------------------------------------------------------------------------------------- // Private Definitions //-------------------------------------------------------------------------------------------------- -const NS_PER_S: u64 = 1_000_000_000; +const NANOSEC_PER_SEC: NonZeroU64 = NonZeroU64::new(1_000_000_000).unwrap(); -/// ARMv8 Generic Timer. -struct GenericTimer; +#[derive(Copy, Clone, PartialOrd, PartialEq)] +struct GenericTimerCounterValue(u64); //-------------------------------------------------------------------------------------------------- // Global instances //-------------------------------------------------------------------------------------------------- -static TIME_MANAGER: GenericTimer = GenericTimer; +/// Boot assembly code overwrites this value with the value of CNTFRQ_EL0 before any Rust code is +/// executed. This given value here is just a (safe) dummy. +#[no_mangle] +static ARCH_TIMER_COUNTER_FREQUENCY: NonZeroU32 = NonZeroU32::MIN; //-------------------------------------------------------------------------------------------------- // Private Code //-------------------------------------------------------------------------------------------------- -impl GenericTimer { - #[inline(always)] - fn read_cntpct(&self) -> u64 { - // Prevent that the counter is read ahead of time due to out-of-order execution. - unsafe { barrier::isb(barrier::SY) }; - CNTPCT_EL0.get() - } +impl GenericTimerCounterValue { + pub const MAX: Self = GenericTimerCounterValue(u64::MAX); } -//-------------------------------------------------------------------------------------------------- -// Public Code -//-------------------------------------------------------------------------------------------------- +impl Add for GenericTimerCounterValue { + type Output = Self; -/// Return a reference to the time manager. -pub fn time_manager() -> &'static impl time::interface::TimeManager { - &TIME_MANAGER + fn add(self, other: Self) -> Self { + GenericTimerCounterValue(self.0.wrapping_add(other.0)) + } } -//------------------------------------------------------------------------------ -// OS Interface Code -//------------------------------------------------------------------------------ +impl From for Duration { + fn from(counter_value: GenericTimerCounterValue) -> Self { + if counter_value.0 == 0 { + return Duration::ZERO; + } -impl time::interface::TimeManager for GenericTimer { - fn resolution(&self) -> Duration { - Duration::from_nanos(NS_PER_S / (CNTFRQ_EL0.get() as u64)) + // Read volatile is needed here to prevent the compiler from optimizing + // ARCH_TIMER_COUNTER_FREQUENCY away. + // + // This is safe, because all the safety requirements as stated in read_volatile()'s + // documentation are fulfilled. + let frequency: NonZeroU64 = + unsafe { core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY) }.into(); + + // Div implementation for u64 cannot panic. + let secs = counter_value.0.div(frequency); + + // This is safe, because frequency can never be greater than u32::MAX, which means the + // largest theoretical value for sub_second_counter_value is (u32::MAX - 1). Therefore, + // (sub_second_counter_value * NANOSEC_PER_SEC) cannot overflow an u64. + // + // The subsequent division ensures the result fits into u32, since the max result is smaller + // than NANOSEC_PER_SEC. Therefore, just cast it to u32 using `as`. + let sub_second_counter_value = counter_value.0 % frequency; + let nanos = unsafe { sub_second_counter_value.unchecked_mul(u64::from(NANOSEC_PER_SEC)) } + .div(frequency) as u32; + + Duration::new(secs, nanos) } +} - fn uptime(&self) -> Duration { - let current_count: u64 = self.read_cntpct() * NS_PER_S; - let frq: u64 = CNTFRQ_EL0.get() as u64; +fn max_duration() -> Duration { + Duration::from(GenericTimerCounterValue::MAX) +} - Duration::from_nanos(current_count / frq) - } +impl TryFrom for GenericTimerCounterValue { + type Error = &'static str; - fn spin_for(&self, duration: Duration) { - // Instantly return on zero. - if duration.as_nanos() == 0 { - return; + fn try_from(duration: Duration) -> Result { + if duration < resolution() { + return Ok(GenericTimerCounterValue(0)); } - // Calculate the register compare value. - let frq = CNTFRQ_EL0.get(); - let x = match frq.checked_mul(duration.as_nanos() as u64) { - #[allow(unused_imports)] - None => { - warn!("Spin duration too long, skipping"); - return; - } - Some(val) => val, - }; - let tval = x / NS_PER_S; - - // Check if it is within supported bounds. - let warn: Option<&str> = if tval == 0 { - Some("smaller") - // The upper 32 bits of CNTP_TVAL_EL0 are reserved. - } else if tval > u32::max_value().into() { - Some("bigger") - } else { - None - }; - - #[allow(unused_imports)] - if let Some(w) = warn { - warn!( - "Spin duration {} than architecturally supported, skipping", - w - ); - return; + if duration > max_duration() { + return Err("Conversion error. Duration too big"); } - // Set the compare value register. - CNTP_TVAL_EL0.set(tval); + // This is safe, because all the safety requirements as stated in read_volatile()'s + // documentation are fulfilled. + let frequency: u128 = + unsafe { u32::from(core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY)) as u128 }; + let duration: u128 = duration.as_nanos(); - // Kick off the counting. // Disable timer interrupt. - CNTP_CTL_EL0.modify(CNTP_CTL_EL0::ENABLE::SET + CNTP_CTL_EL0::IMASK::SET); + // This is safe, because frequency can never be greater than u32::MAX, and + // (Duration::MAX.as_nanos() * u32::MAX) < u128::MAX. + let counter_value = + unsafe { duration.unchecked_mul(frequency) }.div(NonZeroU128::from(NANOSEC_PER_SEC)); - // ISTATUS will be '1' when cval ticks have passed. Busy-check it. - while !CNTP_CTL_EL0.matches_all(CNTP_CTL_EL0::ISTATUS::SET) {} - - // Disable counting again. - CNTP_CTL_EL0.modify(CNTP_CTL_EL0::ENABLE::CLEAR); + // Since we checked above that we are <= max_duration(), just cast to u64. + Ok(GenericTimerCounterValue(counter_value as u64)) } } + +#[inline(always)] +fn read_cntpct() -> GenericTimerCounterValue { + // Prevent that the counter is read ahead of time due to out-of-order execution. + unsafe { barrier::isb(barrier::SY) }; + let cnt = CNTPCT_EL0.get(); + + GenericTimerCounterValue(cnt) +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +/// The timer's resolution. +pub fn resolution() -> Duration { + Duration::from(GenericTimerCounterValue(1)) +} + +/// The uptime since power-on of the device. +/// +/// This includes time consumed by firmware and bootloaders. +pub fn uptime() -> Duration { + read_cntpct().into() +} + +/// Spin for a given duration. +pub fn spin_for(duration: Duration) { + let curr_counter_value = read_cntpct(); + + let counter_value_delta: GenericTimerCounterValue = match duration.try_into() { + Err(msg) => { + warn!("spin_for: {}. Skipping", msg); + return; + } + Ok(val) => val, + }; + let counter_value_target = curr_counter_value + counter_value_delta; + + // Busy wait. + // + // Read CNTPCT_EL0 directly to avoid the ISB that is part of [`read_cntpct`]. + while GenericTimerCounterValue(CNTPCT_EL0.get()) < counter_value_target {} +} diff --git a/17_kernel_symbols/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs b/17_kernel_symbols/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs index a3361c2c..2281e66a 100644 --- a/17_kernel_symbols/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs +++ b/17_kernel_symbols/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs @@ -144,7 +144,7 @@ impl GPIOInner { /// Disable pull-up/down on pins 14 and 15. #[cfg(feature = "bsp_rpi3")] fn disable_pud_14_15_bcm2837(&mut self) { - use crate::{time, time::interface::TimeManager}; + use crate::time; use core::time::Duration; // The Linux 2837 GPIO driver waits 1 µs between the steps. diff --git a/17_kernel_symbols/kernel/src/lib.rs b/17_kernel_symbols/kernel/src/lib.rs index 1f6d11b1..975bad2e 100644 --- a/17_kernel_symbols/kernel/src/lib.rs +++ b/17_kernel_symbols/kernel/src/lib.rs @@ -111,15 +111,18 @@ #![allow(clippy::upper_case_acronyms)] #![allow(incomplete_features)] #![feature(asm_const)] +#![feature(const_option)] #![feature(core_intrinsics)] #![feature(format_args_nl)] #![feature(generic_const_exprs)] #![feature(int_roundings)] #![feature(is_sorted)] #![feature(linkage)] +#![feature(nonzero_min_max)] #![feature(panic_info_message)] #![feature(step_trait)] #![feature(trait_alias)] +#![feature(unchecked_math)] #![no_std] // Testing #![cfg_attr(test, no_main)] diff --git a/17_kernel_symbols/kernel/src/panic_wait.rs b/17_kernel_symbols/kernel/src/panic_wait.rs index 61831213..ae4651e7 100644 --- a/17_kernel_symbols/kernel/src/panic_wait.rs +++ b/17_kernel_symbols/kernel/src/panic_wait.rs @@ -59,8 +59,6 @@ fn panic_prevent_reenter() { #[panic_handler] fn panic(info: &PanicInfo) -> ! { - use crate::time::interface::TimeManager; - exception::asynchronous::local_irq_mask(); // Protect against panic infinite loops if any of the following code panics itself. diff --git a/17_kernel_symbols/kernel/src/print.rs b/17_kernel_symbols/kernel/src/print.rs index 8705eec0..fe13b334 100644 --- a/17_kernel_symbols/kernel/src/print.rs +++ b/17_kernel_symbols/kernel/src/print.rs @@ -39,8 +39,6 @@ macro_rules! println { #[macro_export] macro_rules! info { ($string:expr) => ({ - use $crate::time::interface::TimeManager; - let timestamp = $crate::time::time_manager().uptime(); $crate::print::_print(format_args_nl!( @@ -50,8 +48,6 @@ macro_rules! info { )); }); ($format_string:expr, $($arg:tt)*) => ({ - use $crate::time::interface::TimeManager; - let timestamp = $crate::time::time_manager().uptime(); $crate::print::_print(format_args_nl!( @@ -67,8 +63,6 @@ macro_rules! info { #[macro_export] macro_rules! warn { ($string:expr) => ({ - use $crate::time::interface::TimeManager; - let timestamp = $crate::time::time_manager().uptime(); $crate::print::_print(format_args_nl!( @@ -78,8 +72,6 @@ macro_rules! warn { )); }); ($format_string:expr, $($arg:tt)*) => ({ - use $crate::time::interface::TimeManager; - let timestamp = $crate::time::time_manager().uptime(); $crate::print::_print(format_args_nl!( diff --git a/17_kernel_symbols/kernel/src/time.rs b/17_kernel_symbols/kernel/src/time.rs index 6d92b196..a6c0c5b6 100644 --- a/17_kernel_symbols/kernel/src/time.rs +++ b/17_kernel_symbols/kernel/src/time.rs @@ -8,30 +8,50 @@ #[path = "_arch/aarch64/time.rs"] mod arch_time; +use core::time::Duration; + //-------------------------------------------------------------------------------------------------- -// Architectural Public Reexports +// Public Definitions //-------------------------------------------------------------------------------------------------- -pub use arch_time::time_manager; + +/// Provides time management functions. +pub struct TimeManager; //-------------------------------------------------------------------------------------------------- -// Public Definitions +// Global instances //-------------------------------------------------------------------------------------------------- -/// Timekeeping interfaces. -pub mod interface { - use core::time::Duration; +static TIME_MANAGER: TimeManager = TimeManager::new(); - /// Time management functions. - pub trait TimeManager { - /// The timer's resolution. - fn resolution(&self) -> Duration; +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- - /// The uptime since power-on of the device. - /// - /// This includes time consumed by firmware and bootloaders. - fn uptime(&self) -> Duration; +/// Return a reference to the global TimeManager. +pub fn time_manager() -> &'static TimeManager { + &TIME_MANAGER +} + +impl TimeManager { + /// Create an instance. + pub const fn new() -> Self { + Self + } + + /// The timer's resolution. + pub fn resolution(&self) -> Duration { + arch_time::resolution() + } + + /// The uptime since power-on of the device. + /// + /// This includes time consumed by firmware and bootloaders. + pub fn uptime(&self) -> Duration { + arch_time::uptime() + } - /// Spin for a given duration. - fn spin_for(&self, duration: Duration); + /// Spin for a given duration. + pub fn spin_for(&self, duration: Duration) { + arch_time::spin_for(duration) } } diff --git a/17_kernel_symbols/kernel/tests/01_timer_sanity.rs b/17_kernel_symbols/kernel/tests/01_timer_sanity.rs index d5d76a5c..39899332 100644 --- a/17_kernel_symbols/kernel/tests/01_timer_sanity.rs +++ b/17_kernel_symbols/kernel/tests/01_timer_sanity.rs @@ -11,7 +11,7 @@ #![test_runner(libkernel::test_runner)] use core::time::Duration; -use libkernel::{bsp, cpu, driver, exception, memory, time, time::interface::TimeManager}; +use libkernel::{bsp, cpu, driver, exception, memory, time}; use test_macros::kernel_test; #[no_mangle] @@ -38,6 +38,7 @@ fn timer_is_counting() { /// Timer resolution must be sufficient. #[kernel_test] fn timer_resolution_is_sufficient() { + assert!(time::time_manager().resolution().as_nanos() > 0); assert!(time::time_manager().resolution().as_nanos() < 100) } diff --git a/18_backtrace/README.md b/18_backtrace/README.md index c6417bdd..77222e3a 100644 --- a/18_backtrace/README.md +++ b/18_backtrace/README.md @@ -909,7 +909,7 @@ diff -uNr 17_kernel_symbols/kernel/src/bsp/raspberrypi/memory/mmu.rs 18_backtrac diff -uNr 17_kernel_symbols/kernel/src/lib.rs 18_backtrace/kernel/src/lib.rs --- 17_kernel_symbols/kernel/src/lib.rs +++ 18_backtrace/kernel/src/lib.rs -@@ -130,6 +130,7 @@ +@@ -133,6 +133,7 @@ mod panic_wait; mod synchronization; @@ -972,7 +972,7 @@ diff -uNr 17_kernel_symbols/kernel/src/panic_wait.rs 18_backtrace/kernel/src/pan use core::panic::PanicInfo; //-------------------------------------------------------------------------------------------------- -@@ -75,6 +75,7 @@ +@@ -73,6 +73,7 @@ println!( "[ {:>3}.{:06}] Kernel panic!\n\n\ Panic location:\n File '{}', line {}, column {}\n\n\ @@ -980,7 +980,7 @@ diff -uNr 17_kernel_symbols/kernel/src/panic_wait.rs 18_backtrace/kernel/src/pan {}", timestamp.as_secs(), timestamp.subsec_micros(), -@@ -82,6 +83,7 @@ +@@ -80,6 +81,7 @@ line, column, info.message().unwrap_or(&format_args!("")), diff --git a/18_backtrace/kernel/src/_arch/aarch64/cpu/boot.s b/18_backtrace/kernel/src/_arch/aarch64/cpu/boot.s index 8c70d035..bf6e32e4 100644 --- a/18_backtrace/kernel/src/_arch/aarch64/cpu/boot.s +++ b/18_backtrace/kernel/src/_arch/aarch64/cpu/boot.s @@ -84,6 +84,14 @@ _start: ADR_REL x4, __boot_core_stack_end_exclusive mov sp, x4 + // Read the CPU's timer counter frequency and store it in ARCH_TIMER_COUNTER_FREQUENCY. + // Abort if the frequency read back as 0. + ADR_REL x5, ARCH_TIMER_COUNTER_FREQUENCY // provided by aarch64/time.rs + mrs x6, CNTFRQ_EL0 + cmp x6, xzr + b.eq .L_parking_loop + str w6, [x5] + // Jump to Rust code. x0, x1 and x2 hold the function arguments provided to _start_rust(). b _start_rust diff --git a/18_backtrace/kernel/src/_arch/aarch64/time.rs b/18_backtrace/kernel/src/_arch/aarch64/time.rs index c814219c..255a5a45 100644 --- a/18_backtrace/kernel/src/_arch/aarch64/time.rs +++ b/18_backtrace/kernel/src/_arch/aarch64/time.rs @@ -11,111 +11,152 @@ //! //! crate::time::arch_time -use crate::{time, warn}; -use core::time::Duration; +use crate::warn; +use core::{ + num::{NonZeroU128, NonZeroU32, NonZeroU64}, + ops::{Add, Div}, + time::Duration, +}; use cortex_a::{asm::barrier, registers::*}; -use tock_registers::interfaces::{ReadWriteable, Readable, Writeable}; +use tock_registers::interfaces::Readable; //-------------------------------------------------------------------------------------------------- // Private Definitions //-------------------------------------------------------------------------------------------------- -const NS_PER_S: u64 = 1_000_000_000; +const NANOSEC_PER_SEC: NonZeroU64 = NonZeroU64::new(1_000_000_000).unwrap(); -/// ARMv8 Generic Timer. -struct GenericTimer; +#[derive(Copy, Clone, PartialOrd, PartialEq)] +struct GenericTimerCounterValue(u64); //-------------------------------------------------------------------------------------------------- // Global instances //-------------------------------------------------------------------------------------------------- -static TIME_MANAGER: GenericTimer = GenericTimer; +/// Boot assembly code overwrites this value with the value of CNTFRQ_EL0 before any Rust code is +/// executed. This given value here is just a (safe) dummy. +#[no_mangle] +static ARCH_TIMER_COUNTER_FREQUENCY: NonZeroU32 = NonZeroU32::MIN; //-------------------------------------------------------------------------------------------------- // Private Code //-------------------------------------------------------------------------------------------------- -impl GenericTimer { - #[inline(always)] - fn read_cntpct(&self) -> u64 { - // Prevent that the counter is read ahead of time due to out-of-order execution. - unsafe { barrier::isb(barrier::SY) }; - CNTPCT_EL0.get() - } +impl GenericTimerCounterValue { + pub const MAX: Self = GenericTimerCounterValue(u64::MAX); } -//-------------------------------------------------------------------------------------------------- -// Public Code -//-------------------------------------------------------------------------------------------------- +impl Add for GenericTimerCounterValue { + type Output = Self; -/// Return a reference to the time manager. -pub fn time_manager() -> &'static impl time::interface::TimeManager { - &TIME_MANAGER + fn add(self, other: Self) -> Self { + GenericTimerCounterValue(self.0.wrapping_add(other.0)) + } } -//------------------------------------------------------------------------------ -// OS Interface Code -//------------------------------------------------------------------------------ +impl From for Duration { + fn from(counter_value: GenericTimerCounterValue) -> Self { + if counter_value.0 == 0 { + return Duration::ZERO; + } -impl time::interface::TimeManager for GenericTimer { - fn resolution(&self) -> Duration { - Duration::from_nanos(NS_PER_S / (CNTFRQ_EL0.get() as u64)) + // Read volatile is needed here to prevent the compiler from optimizing + // ARCH_TIMER_COUNTER_FREQUENCY away. + // + // This is safe, because all the safety requirements as stated in read_volatile()'s + // documentation are fulfilled. + let frequency: NonZeroU64 = + unsafe { core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY) }.into(); + + // Div implementation for u64 cannot panic. + let secs = counter_value.0.div(frequency); + + // This is safe, because frequency can never be greater than u32::MAX, which means the + // largest theoretical value for sub_second_counter_value is (u32::MAX - 1). Therefore, + // (sub_second_counter_value * NANOSEC_PER_SEC) cannot overflow an u64. + // + // The subsequent division ensures the result fits into u32, since the max result is smaller + // than NANOSEC_PER_SEC. Therefore, just cast it to u32 using `as`. + let sub_second_counter_value = counter_value.0 % frequency; + let nanos = unsafe { sub_second_counter_value.unchecked_mul(u64::from(NANOSEC_PER_SEC)) } + .div(frequency) as u32; + + Duration::new(secs, nanos) } +} - fn uptime(&self) -> Duration { - let current_count: u64 = self.read_cntpct() * NS_PER_S; - let frq: u64 = CNTFRQ_EL0.get() as u64; +fn max_duration() -> Duration { + Duration::from(GenericTimerCounterValue::MAX) +} - Duration::from_nanos(current_count / frq) - } +impl TryFrom for GenericTimerCounterValue { + type Error = &'static str; - fn spin_for(&self, duration: Duration) { - // Instantly return on zero. - if duration.as_nanos() == 0 { - return; + fn try_from(duration: Duration) -> Result { + if duration < resolution() { + return Ok(GenericTimerCounterValue(0)); } - // Calculate the register compare value. - let frq = CNTFRQ_EL0.get(); - let x = match frq.checked_mul(duration.as_nanos() as u64) { - #[allow(unused_imports)] - None => { - warn!("Spin duration too long, skipping"); - return; - } - Some(val) => val, - }; - let tval = x / NS_PER_S; - - // Check if it is within supported bounds. - let warn: Option<&str> = if tval == 0 { - Some("smaller") - // The upper 32 bits of CNTP_TVAL_EL0 are reserved. - } else if tval > u32::max_value().into() { - Some("bigger") - } else { - None - }; - - #[allow(unused_imports)] - if let Some(w) = warn { - warn!( - "Spin duration {} than architecturally supported, skipping", - w - ); - return; + if duration > max_duration() { + return Err("Conversion error. Duration too big"); } - // Set the compare value register. - CNTP_TVAL_EL0.set(tval); + // This is safe, because all the safety requirements as stated in read_volatile()'s + // documentation are fulfilled. + let frequency: u128 = + unsafe { u32::from(core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY)) as u128 }; + let duration: u128 = duration.as_nanos(); - // Kick off the counting. // Disable timer interrupt. - CNTP_CTL_EL0.modify(CNTP_CTL_EL0::ENABLE::SET + CNTP_CTL_EL0::IMASK::SET); + // This is safe, because frequency can never be greater than u32::MAX, and + // (Duration::MAX.as_nanos() * u32::MAX) < u128::MAX. + let counter_value = + unsafe { duration.unchecked_mul(frequency) }.div(NonZeroU128::from(NANOSEC_PER_SEC)); - // ISTATUS will be '1' when cval ticks have passed. Busy-check it. - while !CNTP_CTL_EL0.matches_all(CNTP_CTL_EL0::ISTATUS::SET) {} - - // Disable counting again. - CNTP_CTL_EL0.modify(CNTP_CTL_EL0::ENABLE::CLEAR); + // Since we checked above that we are <= max_duration(), just cast to u64. + Ok(GenericTimerCounterValue(counter_value as u64)) } } + +#[inline(always)] +fn read_cntpct() -> GenericTimerCounterValue { + // Prevent that the counter is read ahead of time due to out-of-order execution. + unsafe { barrier::isb(barrier::SY) }; + let cnt = CNTPCT_EL0.get(); + + GenericTimerCounterValue(cnt) +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +/// The timer's resolution. +pub fn resolution() -> Duration { + Duration::from(GenericTimerCounterValue(1)) +} + +/// The uptime since power-on of the device. +/// +/// This includes time consumed by firmware and bootloaders. +pub fn uptime() -> Duration { + read_cntpct().into() +} + +/// Spin for a given duration. +pub fn spin_for(duration: Duration) { + let curr_counter_value = read_cntpct(); + + let counter_value_delta: GenericTimerCounterValue = match duration.try_into() { + Err(msg) => { + warn!("spin_for: {}. Skipping", msg); + return; + } + Ok(val) => val, + }; + let counter_value_target = curr_counter_value + counter_value_delta; + + // Busy wait. + // + // Read CNTPCT_EL0 directly to avoid the ISB that is part of [`read_cntpct`]. + while GenericTimerCounterValue(CNTPCT_EL0.get()) < counter_value_target {} +} diff --git a/18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs b/18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs index a3361c2c..2281e66a 100644 --- a/18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs +++ b/18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs @@ -144,7 +144,7 @@ impl GPIOInner { /// Disable pull-up/down on pins 14 and 15. #[cfg(feature = "bsp_rpi3")] fn disable_pud_14_15_bcm2837(&mut self) { - use crate::{time, time::interface::TimeManager}; + use crate::time; use core::time::Duration; // The Linux 2837 GPIO driver waits 1 µs between the steps. diff --git a/18_backtrace/kernel/src/lib.rs b/18_backtrace/kernel/src/lib.rs index 2c13a342..2545b20b 100644 --- a/18_backtrace/kernel/src/lib.rs +++ b/18_backtrace/kernel/src/lib.rs @@ -111,15 +111,18 @@ #![allow(clippy::upper_case_acronyms)] #![allow(incomplete_features)] #![feature(asm_const)] +#![feature(const_option)] #![feature(core_intrinsics)] #![feature(format_args_nl)] #![feature(generic_const_exprs)] #![feature(int_roundings)] #![feature(is_sorted)] #![feature(linkage)] +#![feature(nonzero_min_max)] #![feature(panic_info_message)] #![feature(step_trait)] #![feature(trait_alias)] +#![feature(unchecked_math)] #![no_std] // Testing #![cfg_attr(test, no_main)] diff --git a/18_backtrace/kernel/src/panic_wait.rs b/18_backtrace/kernel/src/panic_wait.rs index c11ec67e..bc95f77c 100644 --- a/18_backtrace/kernel/src/panic_wait.rs +++ b/18_backtrace/kernel/src/panic_wait.rs @@ -59,8 +59,6 @@ fn panic_prevent_reenter() { #[panic_handler] fn panic(info: &PanicInfo) -> ! { - use crate::time::interface::TimeManager; - exception::asynchronous::local_irq_mask(); // Protect against panic infinite loops if any of the following code panics itself. diff --git a/18_backtrace/kernel/src/print.rs b/18_backtrace/kernel/src/print.rs index 8705eec0..fe13b334 100644 --- a/18_backtrace/kernel/src/print.rs +++ b/18_backtrace/kernel/src/print.rs @@ -39,8 +39,6 @@ macro_rules! println { #[macro_export] macro_rules! info { ($string:expr) => ({ - use $crate::time::interface::TimeManager; - let timestamp = $crate::time::time_manager().uptime(); $crate::print::_print(format_args_nl!( @@ -50,8 +48,6 @@ macro_rules! info { )); }); ($format_string:expr, $($arg:tt)*) => ({ - use $crate::time::interface::TimeManager; - let timestamp = $crate::time::time_manager().uptime(); $crate::print::_print(format_args_nl!( @@ -67,8 +63,6 @@ macro_rules! info { #[macro_export] macro_rules! warn { ($string:expr) => ({ - use $crate::time::interface::TimeManager; - let timestamp = $crate::time::time_manager().uptime(); $crate::print::_print(format_args_nl!( @@ -78,8 +72,6 @@ macro_rules! warn { )); }); ($format_string:expr, $($arg:tt)*) => ({ - use $crate::time::interface::TimeManager; - let timestamp = $crate::time::time_manager().uptime(); $crate::print::_print(format_args_nl!( diff --git a/18_backtrace/kernel/src/time.rs b/18_backtrace/kernel/src/time.rs index 6d92b196..a6c0c5b6 100644 --- a/18_backtrace/kernel/src/time.rs +++ b/18_backtrace/kernel/src/time.rs @@ -8,30 +8,50 @@ #[path = "_arch/aarch64/time.rs"] mod arch_time; +use core::time::Duration; + //-------------------------------------------------------------------------------------------------- -// Architectural Public Reexports +// Public Definitions //-------------------------------------------------------------------------------------------------- -pub use arch_time::time_manager; + +/// Provides time management functions. +pub struct TimeManager; //-------------------------------------------------------------------------------------------------- -// Public Definitions +// Global instances //-------------------------------------------------------------------------------------------------- -/// Timekeeping interfaces. -pub mod interface { - use core::time::Duration; +static TIME_MANAGER: TimeManager = TimeManager::new(); - /// Time management functions. - pub trait TimeManager { - /// The timer's resolution. - fn resolution(&self) -> Duration; +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- - /// The uptime since power-on of the device. - /// - /// This includes time consumed by firmware and bootloaders. - fn uptime(&self) -> Duration; +/// Return a reference to the global TimeManager. +pub fn time_manager() -> &'static TimeManager { + &TIME_MANAGER +} + +impl TimeManager { + /// Create an instance. + pub const fn new() -> Self { + Self + } + + /// The timer's resolution. + pub fn resolution(&self) -> Duration { + arch_time::resolution() + } + + /// The uptime since power-on of the device. + /// + /// This includes time consumed by firmware and bootloaders. + pub fn uptime(&self) -> Duration { + arch_time::uptime() + } - /// Spin for a given duration. - fn spin_for(&self, duration: Duration); + /// Spin for a given duration. + pub fn spin_for(&self, duration: Duration) { + arch_time::spin_for(duration) } } diff --git a/18_backtrace/kernel/tests/01_timer_sanity.rs b/18_backtrace/kernel/tests/01_timer_sanity.rs index d5d76a5c..39899332 100644 --- a/18_backtrace/kernel/tests/01_timer_sanity.rs +++ b/18_backtrace/kernel/tests/01_timer_sanity.rs @@ -11,7 +11,7 @@ #![test_runner(libkernel::test_runner)] use core::time::Duration; -use libkernel::{bsp, cpu, driver, exception, memory, time, time::interface::TimeManager}; +use libkernel::{bsp, cpu, driver, exception, memory, time}; use test_macros::kernel_test; #[no_mangle] @@ -38,6 +38,7 @@ fn timer_is_counting() { /// Timer resolution must be sufficient. #[kernel_test] fn timer_resolution_is_sufficient() { + assert!(time::time_manager().resolution().as_nanos() > 0); assert!(time::time_manager().resolution().as_nanos() < 100) } diff --git a/19_kernel_heap/README.md b/19_kernel_heap/README.md index ecb3f8f7..11417c2f 100644 --- a/19_kernel_heap/README.md +++ b/19_kernel_heap/README.md @@ -433,7 +433,7 @@ diff -uNr 18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs 19 diff -uNr 18_backtrace/kernel/src/bsp/raspberrypi/driver.rs 19_kernel_heap/kernel/src/bsp/raspberrypi/driver.rs --- 18_backtrace/kernel/src/bsp/raspberrypi/driver.rs +++ 19_kernel_heap/kernel/src/bsp/raspberrypi/driver.rs -@@ -11,11 +11,11 @@ +@@ -11,6 +11,7 @@ memory::mmu::MMIODescriptor, synchronization::{interface::ReadWriteEx, InitStateLock}, }; @@ -441,12 +441,7 @@ diff -uNr 18_backtrace/kernel/src/bsp/raspberrypi/driver.rs 19_kernel_heap/kerne use core::{ mem::MaybeUninit, sync::atomic::{AtomicBool, Ordering}, - }; -- - pub use device_driver::IRQNumber; - - //-------------------------------------------------------------------------------------------------- -@@ -24,18 +24,11 @@ +@@ -24,18 +25,11 @@ /// Device Driver Manager type. struct BSPDriverManager { @@ -466,7 +461,7 @@ diff -uNr 18_backtrace/kernel/src/bsp/raspberrypi/driver.rs 19_kernel_heap/kerne // Global instances //-------------------------------------------------------------------------------------------------- -@@ -50,7 +43,7 @@ +@@ -50,7 +44,7 @@ static mut INTERRUPT_CONTROLLER: MaybeUninit = MaybeUninit::uninit(); static BSP_DRIVER_MANAGER: BSPDriverManager = BSPDriverManager { @@ -475,7 +470,7 @@ diff -uNr 18_backtrace/kernel/src/bsp/raspberrypi/driver.rs 19_kernel_heap/kerne init_done: AtomicBool::new(false), }; -@@ -143,9 +136,9 @@ +@@ -143,9 +137,9 @@ unsafe fn register_drivers(&self) { self.device_drivers.write(|drivers| { @@ -488,7 +483,7 @@ diff -uNr 18_backtrace/kernel/src/bsp/raspberrypi/driver.rs 19_kernel_heap/kerne }); } } -@@ -180,9 +173,8 @@ +@@ -180,9 +174,8 @@ Ok(()) } @@ -871,9 +866,9 @@ diff -uNr 18_backtrace/kernel/src/lib.rs 19_kernel_heap/kernel/src/lib.rs #![allow(incomplete_features)] +#![feature(alloc_error_handler)] #![feature(asm_const)] + #![feature(const_option)] #![feature(core_intrinsics)] - #![feature(format_args_nl)] -@@ -127,6 +128,8 @@ +@@ -130,6 +131,8 @@ #![reexport_test_harness_main = "test_main"] #![test_runner(crate::test_runner)] @@ -1269,7 +1264,7 @@ diff -uNr 18_backtrace/kernel/src/memory.rs 19_kernel_heap/kernel/src/memory.rs diff -uNr 18_backtrace/kernel/src/print.rs 19_kernel_heap/kernel/src/print.rs --- 18_backtrace/kernel/src/print.rs +++ 19_kernel_heap/kernel/src/print.rs -@@ -90,3 +90,35 @@ +@@ -82,3 +82,31 @@ )); }) } @@ -1279,8 +1274,6 @@ diff -uNr 18_backtrace/kernel/src/print.rs 19_kernel_heap/kernel/src/print.rs +macro_rules! debug { + ($string:expr) => ({ + if cfg!(feature = "debug_prints") { -+ use $crate::time::interface::TimeManager; -+ + let timestamp = $crate::time::time_manager().uptime(); + + $crate::print::_print(format_args_nl!( @@ -1292,8 +1285,6 @@ diff -uNr 18_backtrace/kernel/src/print.rs 19_kernel_heap/kernel/src/print.rs + }); + ($format_string:expr, $($arg:tt)*) => ({ + if cfg!(feature = "debug_prints") { -+ use $crate::time::interface::TimeManager; -+ + let timestamp = $crate::time::time_manager().uptime(); + + $crate::print::_print(format_args_nl!( diff --git a/19_kernel_heap/kernel/src/_arch/aarch64/cpu/boot.s b/19_kernel_heap/kernel/src/_arch/aarch64/cpu/boot.s index 8c70d035..bf6e32e4 100644 --- a/19_kernel_heap/kernel/src/_arch/aarch64/cpu/boot.s +++ b/19_kernel_heap/kernel/src/_arch/aarch64/cpu/boot.s @@ -84,6 +84,14 @@ _start: ADR_REL x4, __boot_core_stack_end_exclusive mov sp, x4 + // Read the CPU's timer counter frequency and store it in ARCH_TIMER_COUNTER_FREQUENCY. + // Abort if the frequency read back as 0. + ADR_REL x5, ARCH_TIMER_COUNTER_FREQUENCY // provided by aarch64/time.rs + mrs x6, CNTFRQ_EL0 + cmp x6, xzr + b.eq .L_parking_loop + str w6, [x5] + // Jump to Rust code. x0, x1 and x2 hold the function arguments provided to _start_rust(). b _start_rust diff --git a/19_kernel_heap/kernel/src/_arch/aarch64/time.rs b/19_kernel_heap/kernel/src/_arch/aarch64/time.rs index c814219c..255a5a45 100644 --- a/19_kernel_heap/kernel/src/_arch/aarch64/time.rs +++ b/19_kernel_heap/kernel/src/_arch/aarch64/time.rs @@ -11,111 +11,152 @@ //! //! crate::time::arch_time -use crate::{time, warn}; -use core::time::Duration; +use crate::warn; +use core::{ + num::{NonZeroU128, NonZeroU32, NonZeroU64}, + ops::{Add, Div}, + time::Duration, +}; use cortex_a::{asm::barrier, registers::*}; -use tock_registers::interfaces::{ReadWriteable, Readable, Writeable}; +use tock_registers::interfaces::Readable; //-------------------------------------------------------------------------------------------------- // Private Definitions //-------------------------------------------------------------------------------------------------- -const NS_PER_S: u64 = 1_000_000_000; +const NANOSEC_PER_SEC: NonZeroU64 = NonZeroU64::new(1_000_000_000).unwrap(); -/// ARMv8 Generic Timer. -struct GenericTimer; +#[derive(Copy, Clone, PartialOrd, PartialEq)] +struct GenericTimerCounterValue(u64); //-------------------------------------------------------------------------------------------------- // Global instances //-------------------------------------------------------------------------------------------------- -static TIME_MANAGER: GenericTimer = GenericTimer; +/// Boot assembly code overwrites this value with the value of CNTFRQ_EL0 before any Rust code is +/// executed. This given value here is just a (safe) dummy. +#[no_mangle] +static ARCH_TIMER_COUNTER_FREQUENCY: NonZeroU32 = NonZeroU32::MIN; //-------------------------------------------------------------------------------------------------- // Private Code //-------------------------------------------------------------------------------------------------- -impl GenericTimer { - #[inline(always)] - fn read_cntpct(&self) -> u64 { - // Prevent that the counter is read ahead of time due to out-of-order execution. - unsafe { barrier::isb(barrier::SY) }; - CNTPCT_EL0.get() - } +impl GenericTimerCounterValue { + pub const MAX: Self = GenericTimerCounterValue(u64::MAX); } -//-------------------------------------------------------------------------------------------------- -// Public Code -//-------------------------------------------------------------------------------------------------- +impl Add for GenericTimerCounterValue { + type Output = Self; -/// Return a reference to the time manager. -pub fn time_manager() -> &'static impl time::interface::TimeManager { - &TIME_MANAGER + fn add(self, other: Self) -> Self { + GenericTimerCounterValue(self.0.wrapping_add(other.0)) + } } -//------------------------------------------------------------------------------ -// OS Interface Code -//------------------------------------------------------------------------------ +impl From for Duration { + fn from(counter_value: GenericTimerCounterValue) -> Self { + if counter_value.0 == 0 { + return Duration::ZERO; + } -impl time::interface::TimeManager for GenericTimer { - fn resolution(&self) -> Duration { - Duration::from_nanos(NS_PER_S / (CNTFRQ_EL0.get() as u64)) + // Read volatile is needed here to prevent the compiler from optimizing + // ARCH_TIMER_COUNTER_FREQUENCY away. + // + // This is safe, because all the safety requirements as stated in read_volatile()'s + // documentation are fulfilled. + let frequency: NonZeroU64 = + unsafe { core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY) }.into(); + + // Div implementation for u64 cannot panic. + let secs = counter_value.0.div(frequency); + + // This is safe, because frequency can never be greater than u32::MAX, which means the + // largest theoretical value for sub_second_counter_value is (u32::MAX - 1). Therefore, + // (sub_second_counter_value * NANOSEC_PER_SEC) cannot overflow an u64. + // + // The subsequent division ensures the result fits into u32, since the max result is smaller + // than NANOSEC_PER_SEC. Therefore, just cast it to u32 using `as`. + let sub_second_counter_value = counter_value.0 % frequency; + let nanos = unsafe { sub_second_counter_value.unchecked_mul(u64::from(NANOSEC_PER_SEC)) } + .div(frequency) as u32; + + Duration::new(secs, nanos) } +} - fn uptime(&self) -> Duration { - let current_count: u64 = self.read_cntpct() * NS_PER_S; - let frq: u64 = CNTFRQ_EL0.get() as u64; +fn max_duration() -> Duration { + Duration::from(GenericTimerCounterValue::MAX) +} - Duration::from_nanos(current_count / frq) - } +impl TryFrom for GenericTimerCounterValue { + type Error = &'static str; - fn spin_for(&self, duration: Duration) { - // Instantly return on zero. - if duration.as_nanos() == 0 { - return; + fn try_from(duration: Duration) -> Result { + if duration < resolution() { + return Ok(GenericTimerCounterValue(0)); } - // Calculate the register compare value. - let frq = CNTFRQ_EL0.get(); - let x = match frq.checked_mul(duration.as_nanos() as u64) { - #[allow(unused_imports)] - None => { - warn!("Spin duration too long, skipping"); - return; - } - Some(val) => val, - }; - let tval = x / NS_PER_S; - - // Check if it is within supported bounds. - let warn: Option<&str> = if tval == 0 { - Some("smaller") - // The upper 32 bits of CNTP_TVAL_EL0 are reserved. - } else if tval > u32::max_value().into() { - Some("bigger") - } else { - None - }; - - #[allow(unused_imports)] - if let Some(w) = warn { - warn!( - "Spin duration {} than architecturally supported, skipping", - w - ); - return; + if duration > max_duration() { + return Err("Conversion error. Duration too big"); } - // Set the compare value register. - CNTP_TVAL_EL0.set(tval); + // This is safe, because all the safety requirements as stated in read_volatile()'s + // documentation are fulfilled. + let frequency: u128 = + unsafe { u32::from(core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY)) as u128 }; + let duration: u128 = duration.as_nanos(); - // Kick off the counting. // Disable timer interrupt. - CNTP_CTL_EL0.modify(CNTP_CTL_EL0::ENABLE::SET + CNTP_CTL_EL0::IMASK::SET); + // This is safe, because frequency can never be greater than u32::MAX, and + // (Duration::MAX.as_nanos() * u32::MAX) < u128::MAX. + let counter_value = + unsafe { duration.unchecked_mul(frequency) }.div(NonZeroU128::from(NANOSEC_PER_SEC)); - // ISTATUS will be '1' when cval ticks have passed. Busy-check it. - while !CNTP_CTL_EL0.matches_all(CNTP_CTL_EL0::ISTATUS::SET) {} - - // Disable counting again. - CNTP_CTL_EL0.modify(CNTP_CTL_EL0::ENABLE::CLEAR); + // Since we checked above that we are <= max_duration(), just cast to u64. + Ok(GenericTimerCounterValue(counter_value as u64)) } } + +#[inline(always)] +fn read_cntpct() -> GenericTimerCounterValue { + // Prevent that the counter is read ahead of time due to out-of-order execution. + unsafe { barrier::isb(barrier::SY) }; + let cnt = CNTPCT_EL0.get(); + + GenericTimerCounterValue(cnt) +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +/// The timer's resolution. +pub fn resolution() -> Duration { + Duration::from(GenericTimerCounterValue(1)) +} + +/// The uptime since power-on of the device. +/// +/// This includes time consumed by firmware and bootloaders. +pub fn uptime() -> Duration { + read_cntpct().into() +} + +/// Spin for a given duration. +pub fn spin_for(duration: Duration) { + let curr_counter_value = read_cntpct(); + + let counter_value_delta: GenericTimerCounterValue = match duration.try_into() { + Err(msg) => { + warn!("spin_for: {}. Skipping", msg); + return; + } + Ok(val) => val, + }; + let counter_value_target = curr_counter_value + counter_value_delta; + + // Busy wait. + // + // Read CNTPCT_EL0 directly to avoid the ISB that is part of [`read_cntpct`]. + while GenericTimerCounterValue(CNTPCT_EL0.get()) < counter_value_target {} +} diff --git a/19_kernel_heap/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs b/19_kernel_heap/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs index a3361c2c..2281e66a 100644 --- a/19_kernel_heap/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs +++ b/19_kernel_heap/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs @@ -144,7 +144,7 @@ impl GPIOInner { /// Disable pull-up/down on pins 14 and 15. #[cfg(feature = "bsp_rpi3")] fn disable_pud_14_15_bcm2837(&mut self) { - use crate::{time, time::interface::TimeManager}; + use crate::time; use core::time::Duration; // The Linux 2837 GPIO driver waits 1 µs between the steps. diff --git a/19_kernel_heap/kernel/src/bsp/raspberrypi/driver.rs b/19_kernel_heap/kernel/src/bsp/raspberrypi/driver.rs index 3eb01f27..5571c392 100644 --- a/19_kernel_heap/kernel/src/bsp/raspberrypi/driver.rs +++ b/19_kernel_heap/kernel/src/bsp/raspberrypi/driver.rs @@ -16,6 +16,7 @@ use core::{ mem::MaybeUninit, sync::atomic::{AtomicBool, Ordering}, }; + pub use device_driver::IRQNumber; //-------------------------------------------------------------------------------------------------- diff --git a/19_kernel_heap/kernel/src/lib.rs b/19_kernel_heap/kernel/src/lib.rs index 20dc3bfd..8e4195e0 100644 --- a/19_kernel_heap/kernel/src/lib.rs +++ b/19_kernel_heap/kernel/src/lib.rs @@ -112,15 +112,18 @@ #![allow(incomplete_features)] #![feature(alloc_error_handler)] #![feature(asm_const)] +#![feature(const_option)] #![feature(core_intrinsics)] #![feature(format_args_nl)] #![feature(generic_const_exprs)] #![feature(int_roundings)] #![feature(is_sorted)] #![feature(linkage)] +#![feature(nonzero_min_max)] #![feature(panic_info_message)] #![feature(step_trait)] #![feature(trait_alias)] +#![feature(unchecked_math)] #![no_std] // Testing #![cfg_attr(test, no_main)] diff --git a/19_kernel_heap/kernel/src/panic_wait.rs b/19_kernel_heap/kernel/src/panic_wait.rs index c11ec67e..bc95f77c 100644 --- a/19_kernel_heap/kernel/src/panic_wait.rs +++ b/19_kernel_heap/kernel/src/panic_wait.rs @@ -59,8 +59,6 @@ fn panic_prevent_reenter() { #[panic_handler] fn panic(info: &PanicInfo) -> ! { - use crate::time::interface::TimeManager; - exception::asynchronous::local_irq_mask(); // Protect against panic infinite loops if any of the following code panics itself. diff --git a/19_kernel_heap/kernel/src/print.rs b/19_kernel_heap/kernel/src/print.rs index 5e41ef9f..8d56d2e4 100644 --- a/19_kernel_heap/kernel/src/print.rs +++ b/19_kernel_heap/kernel/src/print.rs @@ -39,8 +39,6 @@ macro_rules! println { #[macro_export] macro_rules! info { ($string:expr) => ({ - use $crate::time::interface::TimeManager; - let timestamp = $crate::time::time_manager().uptime(); $crate::print::_print(format_args_nl!( @@ -50,8 +48,6 @@ macro_rules! info { )); }); ($format_string:expr, $($arg:tt)*) => ({ - use $crate::time::interface::TimeManager; - let timestamp = $crate::time::time_manager().uptime(); $crate::print::_print(format_args_nl!( @@ -67,8 +63,6 @@ macro_rules! info { #[macro_export] macro_rules! warn { ($string:expr) => ({ - use $crate::time::interface::TimeManager; - let timestamp = $crate::time::time_manager().uptime(); $crate::print::_print(format_args_nl!( @@ -78,8 +72,6 @@ macro_rules! warn { )); }); ($format_string:expr, $($arg:tt)*) => ({ - use $crate::time::interface::TimeManager; - let timestamp = $crate::time::time_manager().uptime(); $crate::print::_print(format_args_nl!( @@ -96,8 +88,6 @@ macro_rules! warn { macro_rules! debug { ($string:expr) => ({ if cfg!(feature = "debug_prints") { - use $crate::time::interface::TimeManager; - let timestamp = $crate::time::time_manager().uptime(); $crate::print::_print(format_args_nl!( @@ -109,8 +99,6 @@ macro_rules! debug { }); ($format_string:expr, $($arg:tt)*) => ({ if cfg!(feature = "debug_prints") { - use $crate::time::interface::TimeManager; - let timestamp = $crate::time::time_manager().uptime(); $crate::print::_print(format_args_nl!( diff --git a/19_kernel_heap/kernel/src/time.rs b/19_kernel_heap/kernel/src/time.rs index 6d92b196..a6c0c5b6 100644 --- a/19_kernel_heap/kernel/src/time.rs +++ b/19_kernel_heap/kernel/src/time.rs @@ -8,30 +8,50 @@ #[path = "_arch/aarch64/time.rs"] mod arch_time; +use core::time::Duration; + //-------------------------------------------------------------------------------------------------- -// Architectural Public Reexports +// Public Definitions //-------------------------------------------------------------------------------------------------- -pub use arch_time::time_manager; + +/// Provides time management functions. +pub struct TimeManager; //-------------------------------------------------------------------------------------------------- -// Public Definitions +// Global instances //-------------------------------------------------------------------------------------------------- -/// Timekeeping interfaces. -pub mod interface { - use core::time::Duration; +static TIME_MANAGER: TimeManager = TimeManager::new(); - /// Time management functions. - pub trait TimeManager { - /// The timer's resolution. - fn resolution(&self) -> Duration; +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- - /// The uptime since power-on of the device. - /// - /// This includes time consumed by firmware and bootloaders. - fn uptime(&self) -> Duration; +/// Return a reference to the global TimeManager. +pub fn time_manager() -> &'static TimeManager { + &TIME_MANAGER +} + +impl TimeManager { + /// Create an instance. + pub const fn new() -> Self { + Self + } + + /// The timer's resolution. + pub fn resolution(&self) -> Duration { + arch_time::resolution() + } + + /// The uptime since power-on of the device. + /// + /// This includes time consumed by firmware and bootloaders. + pub fn uptime(&self) -> Duration { + arch_time::uptime() + } - /// Spin for a given duration. - fn spin_for(&self, duration: Duration); + /// Spin for a given duration. + pub fn spin_for(&self, duration: Duration) { + arch_time::spin_for(duration) } } diff --git a/19_kernel_heap/kernel/tests/01_timer_sanity.rs b/19_kernel_heap/kernel/tests/01_timer_sanity.rs index d5d76a5c..39899332 100644 --- a/19_kernel_heap/kernel/tests/01_timer_sanity.rs +++ b/19_kernel_heap/kernel/tests/01_timer_sanity.rs @@ -11,7 +11,7 @@ #![test_runner(libkernel::test_runner)] use core::time::Duration; -use libkernel::{bsp, cpu, driver, exception, memory, time, time::interface::TimeManager}; +use libkernel::{bsp, cpu, driver, exception, memory, time}; use test_macros::kernel_test; #[no_mangle] @@ -38,6 +38,7 @@ fn timer_is_counting() { /// Timer resolution must be sufficient. #[kernel_test] fn timer_resolution_is_sufficient() { + assert!(time::time_manager().resolution().as_nanos() > 0); assert!(time::time_manager().resolution().as_nanos() < 100) } diff --git a/X1_JTAG_boot/jtag_boot_rpi3.img b/X1_JTAG_boot/jtag_boot_rpi3.img index 6b717dffa6c5b3ef5507a10f0b1e95bdcea9f241..844015333d4c9c99ddbb059320b89f37229f2328 100755 GIT binary patch delta 2665 zcmah~eQZzu)g%kL;dn`|$*9zvsyFyw0%j>@HxIx)|`;dG_ATB4VLEDaIbi z(ow+q7harPQ4}kk_hc2E2a%4GEU_?&o%cGyuI}3e5X%=^tjrC=yZ$do>0b@-1_8L1 zcmSf~rc+#CK{U?<84Dr9(l6MqO>;(E<>DYZ<5gnfWg;gkK}=l%c?%4CQ{Z$N7n*|VXrfpr)J&pGq9v9V{%$iK1*Rn&ehFgVk?ms+q7H7aXs-8=CRoz z(_3!&C*BzQ+tQ!clpomtALT6`_z!6KBn#05%S0D21>cHd<@r__?>qJmX75N;i)@i6 za}?|!g5J2tJn{mbqbVm@WAsxgxwb@@&nnj34yBE`n{9)P8F9J4i@jHc=o&q5d)o)D zgadI;%x-}GkJI|SkIrY&xf%$aW6=I-@|tZH zlO-(piV%{HykYP3qiXS!tsv(vc7laJoQw;e*a73;E=FZ@qyqzW;CLSfl8Je0Qvvt_ zPOkjKAJ2O`3f~EHL(vGg(mTHjU~P)ENAt0#s08OC-eC76t{ZVZJkJr+t4>627vYv} zDT?ngZGTl7&!i4QEQQRcDTExXVB2wZ`QsPjkiAqLHR}z)}k)&ctqf8ds zh`3nEsB?kOHAzHwQYo=AM`fJMSLJ1F2Fs!=Urz0T%n15RR~qCLN-O0mkWXY$JPb5s z+dLVhTD-}2e(0fxow$)}A*zFx=TUzcOcBtDuEEq{u%v_nIr_DxKDyqjXk+P2X_>I6 zIS5eSi858NP^r6rqd1K%1gi-lO zJYexTATs7Xrj}~lEG|tk@)F{SJV`>CW8>rljf<-7$i?OSZ*x&E{iVz%JX}%U!gs78 z2Ty`!#g8ZzSjYc^{sBb48$?B6WEz^Ll-i5vE390rqo1o*y&uEp%nQDHmCghrki?Ht zOV<^a*?l*=6EZly28n#J5S;*l>(nvt1EbT?WJq$j0T8N+x{lR2GGB{2EXwdt#3mtq)*UAJKEWU@k!~0^17= zbBsY2v5kS&AJXmCwgdd3{qC9?{+Sl957Cq2Hmhx2p0>-)YrT3De~RtW7q)*0ZK1xO z_Jjw5p+3GR91ex6`Q2y3U4zsf425`q@c5C#{7?9SGr_*j-cWc4U(G*#GI$2f<0jqJ z{c_DS>Pu}$?3#^lpxPGn^+MfV)@}S-0%?%HD!o~;RiMf5In;h|^EUoeu&;;T#&?HK zoju*hn@qVl&+2}^FHUNM7WW5woQev~)_wsV*KMqSwN>jj3JnZ&#ywNBv6D!5%Ga&= za-(*tOx>xX^;P-C4Q@RJnmTQx_~9QC9O3zD$-SZ8`Tuf!UUyI{_4DV15JKO3Ds+wy z_I(5UjvakH=csRNInLH=Cb+_92L`)cz0KYJuEx5i`o?4K-rnBrHI20mZhx)6tI6Nw zZuB=Ct3TG=>vp?cr-J@)SNP|y?ohbLH4yH04F*s5REGzSYFcQ8y}IK+VPA@0jEgd_}bY delta 2789 zcmah~eQaCR6+ibqJ9&1$3~rM)X~}cFQ9CK5twTxyVJC*sctveZVMtK5ZekKIjvZcH zSO=M1A&q_^{CJ>J^3Oswwa*kSEbY1=p#}O+OE=8FA2_IIss& z+6y@U;=$7kx?WG`0~HZ_$WdSepj&6~)7NX7s!B}@a0S@gYjDMZgxY+YgL}te#}F=e@eh_YYm*W2Tp|hLr4D-8agHQ zJI~IStbdvJmjgE5hnN0}3lEx~r_tr#*HLl%q3q8&*%j0|=SUmCF^qd8=+4M})ot-aBOc=RDzU-_ZD z6-lyr0_y2soE}-Uq0_6a<()Z-da(u6!pksG@^M}#9-so$({>fhTyfXkxd|0P^?77U zca)r*Oi9(Q@mTdlMTKOI%0i)*-r>|z&>&TLq0V*3p?R~KK7IhJ@MMjOZpQ?sCiPzB z{kn$qw^-pf^ZWnwe!^Y>jpyZ08P$3aODssWgpeUj&BGT*W>Dleir%yAmZDFas&|v` zSN$JR^;luE_-YuU=Wi1I*xY9BX3@K>*G0eX2GN`N$n@D07SdGlR#beAS_o3b*Q)s- zkVj^j^GzjG@%dt@(jM6H2Y>IoUU3p z8^SYRU|BCi;1{7VKF37fMKZfkKyygMJ84u3bu#PY<}7Vx{TwYe z4!;|pgifZJJ}eV2mPa3!N&!pd5SEDtwIX172>C|ulqZibq&4tcPrlI@7xemeW3HTj zjm}jmP=2=R8+_ERw?XCEhI(&?Ls4VPfY}F_-5GpT+_7!L#*O0R9pPO77UjK$`Ub&b z?#iw)`>MBVjY_`Z)9!~QDJhBZWTYpS=oNdU*mF_oKJh*gxBaQnJWdXv(GKG;4PSY>scko%sfK|6H%2QrnFo+LqitXgHZgmUCAgB= z)dU84bChAd0Za3a73S<-)_>_T?Khd%0<$MqE1O*HtE$eKZ>R?Gm2%Kk-|{3wYcX4P zU~k2bV*JRCuI=mAi}6?@Dn2EON@4X~>GfiFGQNKxA=>Sz(_5#iF#mVa&DahxyPD!8 zv+=1j+9hUJvA@i07WMe4H9JX~60#>Eb@#PK=x=*lYbrJnt8-I;v^$0K@%RC8X#e0~Qc6X8){8^^u|Yi2YoPNr3*`HR@E^8LQK!u= mnz%G8qicS%^ShU)l1UVBqW3$Oz^!f(nIPQg^?7B?CH@yERC#&; diff --git a/X1_JTAG_boot/jtag_boot_rpi4.img b/X1_JTAG_boot/jtag_boot_rpi4.img index 195a9fa2897dec9ff58270824d17ee341181bd88..90e8668b1951ee773dc86acaba14c1afe08781fc 100755 GIT binary patch delta 1940 zcmah}eP|PB7=PZo#^n;*U9D;QVeG}?n$(Y^wVzQiZ5=jFQ9^}%F-_9OMr-S?ts<;T zs-Sar(DMYD-C(WE_R4*-E+_L zK40(e_q;c~{_2L;Mxo)BGsl05qT$tzKs^jm&{oFLx2AswR+Z!tN+1t+1KQsioS0J- zyK48(D`*En{T{s!EG4hMwF}BLzZC$fMM9IEDl&Z$ene~@6P#B4LKlFQe+FTe2EjTN zqpXDD&Wi`>eU8y;!5wl6@^K=`i;nKO7A#t9(Z&n}X7(L85j+W>@a}=h z5%=7lnKr^qh8bwHOdks-hrZ%nPD^R*>l4Ai;xUYqMr?D@86OR>^a)*7`Is)lrVEl6 z6y*%V`K3%bNDSBP&XiN`#~UI0*)8j-+7f>3Ef%~dX zX%KZ5foLss#;+9uYr+1vTy8-27HNAEtAKqFhipb=vSP7jdv7hU*EBs>N=HlvZfX5Ng3>nEboH z^&og|DKvFsem!K-Gz`-X!e{6M1TLzHEEm2kQjJ z34;6rNI?8q7ZJ}F6fTkSfK6BANa|>*=^j*x-xn;8hpMrg77#vqt{deFxiP;Evj0WD z6{+q-`YlNR7L9((2!l2k(!Uq!e;?^L4Odc^on-%GwMEV0Ot)+XB{w+wq z8-3h!(fAC7ZD)}FbOCbVft1=?=i3UKISPV00_iEe-`H*C8HW`*wq_4f|R))jSM7% z%rB5ya8?5V{MkErbM%PR-NL^}LcC$OyN4;vj%!%0f@_DNH@9r# zc5L-lRdG9;f^CShm|tWsDaz5kCYI?^3&Gd1Qn9({2k}zLnz$Occ}HM-#cHlA*4@Fa z<{~{^{rkH)iv=&y^-?_$$4y%^hK~OiZFLmu`)dsStf4QI8#8qLpJ;2+&~Xm5b%7L5 zy)kdb!*xMD;1@cq4g5l^%+ z5)Rd^tFNhR_eP`9hN`;iT5q^I9I6l3d+Wlr?KSO@sMqWDbj8Aah(GL!^za>?UOwXK zi|y}N%lF>Z2`PbABk?7aHhdO>9z#1MMYLkNPM)ll(6NsE>(k} z>^3Hl0>+LPL!^J&V$#m~M^lJYi6P-n%MX(ZMH7wA)}Ygt8dLg%4R*(KXJ&&EjW@aX z+HlCHZ9 zd0Iz4$O1rq3+m~}r)|ag+*RA>(FIcAw!=B5H~1-t>MtNq^B@qhHwH7aDY)OlsFb z_M)n~oL5xzo8-BK9wUn80fogB+CkJ}obuX|eqI9Umd29=5rU{IB=*tWIewB&dveZ_ zjiWh_{Z6>vfDwk=pzCuh8 z#tNo>OzST54ls?W3pO+L`3&@as3jyGy2iKMR{8Qo5;wau8=dDS(_5iFh4(%f*dz;> z2oSi;avRtU;-apfR{<`618~lbo8iM`$wxUco)%}9|ifY-~7chcXV;yPn4$aiGJs`lcB`f zE727IvAzR?n~Z#_szIFF3@Pu@&YK4i%e#JFsdPI_X7V5v{<1gJlreBq?_w^KFQ5T6keI4XjT0b8o@I(tH#@d?sfYs(Wa1~`By7_o$ zH!3mgR5W-UF=cm#1l4j&W8|Gc7@#iWfc2__Y!3V#9fuPx-NVLs6d?y9(upW_B1*G} z(rHA=+kKpWk1@0<9!!#Fc}oB?Lj_w3CXy*#ezba}oz=KW0-`0f>K_IaFrUe5m)PzP3;pbiz7nEq&}9T;QXPbJrVZv;>smw7&< zan9t#ElH3z6uLIpY#BYn2yiHkC0P6`#s8FlP()7`{_tw!w&$cBFEs7)R7nTJhdZRB z(RP1JTeN+@zm1)n>ik{dLmf5IqX5-KriUWS^LC_VxZAqAIu1p;q^={<-tgPuy&cjU z$E0^VqDN??q%fm=%rahS8DsbhC1r(IEH=)9v3l{$#!YXP)U9QlOxifk#`?-CBU7GQ zM18AH*j|yO8ro4*9jlVsj~smK&|%5x#NYm3^Q)G-YRml^E1wKjGnU+8$rr3QXT296 zNr!G(6`_5_D*ddqmPBZ>)U|#w*L22^jYPwTy9_Y#J4;P|mgP!BYR4U+4W+J^BfKe% dTlBx0p*GLd3tDu<@>*-r0gLWol&&eO_zP&8Bsc&7 diff --git a/X1_JTAG_boot/src/_arch/aarch64/cpu/boot.s b/X1_JTAG_boot/src/_arch/aarch64/cpu/boot.s index 1f70169f..aa701fd1 100644 --- a/X1_JTAG_boot/src/_arch/aarch64/cpu/boot.s +++ b/X1_JTAG_boot/src/_arch/aarch64/cpu/boot.s @@ -52,6 +52,14 @@ _start: ADR_REL x0, __boot_core_stack_end_exclusive mov sp, x0 + // Read the CPU's timer counter frequency and store it in ARCH_TIMER_COUNTER_FREQUENCY. + // Abort if the frequency read back as 0. + ADR_REL x1, ARCH_TIMER_COUNTER_FREQUENCY // provided by aarch64/time.rs + mrs x2, CNTFRQ_EL0 + cmp x2, xzr + b.eq .L_parking_loop + str w2, [x1] + // Jump to Rust code. b _start_rust diff --git a/X1_JTAG_boot/src/_arch/aarch64/time.rs b/X1_JTAG_boot/src/_arch/aarch64/time.rs index c814219c..3d3a20d7 100644 --- a/X1_JTAG_boot/src/_arch/aarch64/time.rs +++ b/X1_JTAG_boot/src/_arch/aarch64/time.rs @@ -11,111 +11,154 @@ //! //! crate::time::arch_time -use crate::{time, warn}; -use core::time::Duration; +#[cfg(feature = "bsp_rpi3")] +use crate::warn; +use core::{ + num::{NonZeroU128, NonZeroU32, NonZeroU64}, + ops::{Add, Div}, + time::Duration, +}; use cortex_a::{asm::barrier, registers::*}; -use tock_registers::interfaces::{ReadWriteable, Readable, Writeable}; +use tock_registers::interfaces::Readable; //-------------------------------------------------------------------------------------------------- // Private Definitions //-------------------------------------------------------------------------------------------------- -const NS_PER_S: u64 = 1_000_000_000; +const NANOSEC_PER_SEC: NonZeroU64 = NonZeroU64::new(1_000_000_000).unwrap(); -/// ARMv8 Generic Timer. -struct GenericTimer; +#[derive(Copy, Clone, PartialOrd, PartialEq)] +struct GenericTimerCounterValue(u64); //-------------------------------------------------------------------------------------------------- // Global instances //-------------------------------------------------------------------------------------------------- -static TIME_MANAGER: GenericTimer = GenericTimer; +/// Boot assembly code overwrites this value with the value of CNTFRQ_EL0 before any Rust code is +/// executed. This given value here is just a (safe) dummy. +#[no_mangle] +static ARCH_TIMER_COUNTER_FREQUENCY: NonZeroU32 = NonZeroU32::MIN; //-------------------------------------------------------------------------------------------------- // Private Code //-------------------------------------------------------------------------------------------------- -impl GenericTimer { - #[inline(always)] - fn read_cntpct(&self) -> u64 { - // Prevent that the counter is read ahead of time due to out-of-order execution. - unsafe { barrier::isb(barrier::SY) }; - CNTPCT_EL0.get() - } +impl GenericTimerCounterValue { + pub const MAX: Self = GenericTimerCounterValue(u64::MAX); } -//-------------------------------------------------------------------------------------------------- -// Public Code -//-------------------------------------------------------------------------------------------------- +impl Add for GenericTimerCounterValue { + type Output = Self; -/// Return a reference to the time manager. -pub fn time_manager() -> &'static impl time::interface::TimeManager { - &TIME_MANAGER + fn add(self, other: Self) -> Self { + GenericTimerCounterValue(self.0.wrapping_add(other.0)) + } } -//------------------------------------------------------------------------------ -// OS Interface Code -//------------------------------------------------------------------------------ +impl From for Duration { + fn from(counter_value: GenericTimerCounterValue) -> Self { + if counter_value.0 == 0 { + return Duration::ZERO; + } -impl time::interface::TimeManager for GenericTimer { - fn resolution(&self) -> Duration { - Duration::from_nanos(NS_PER_S / (CNTFRQ_EL0.get() as u64)) + // Read volatile is needed here to prevent the compiler from optimizing + // ARCH_TIMER_COUNTER_FREQUENCY away. + // + // This is safe, because all the safety requirements as stated in read_volatile()'s + // documentation are fulfilled. + let frequency: NonZeroU64 = + unsafe { core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY) }.into(); + + // Div implementation for u64 cannot panic. + let secs = counter_value.0.div(frequency); + + // This is safe, because frequency can never be greater than u32::MAX, which means the + // largest theoretical value for sub_second_counter_value is (u32::MAX - 1). Therefore, + // (sub_second_counter_value * NANOSEC_PER_SEC) cannot overflow an u64. + // + // The subsequent division ensures the result fits into u32, since the max result is smaller + // than NANOSEC_PER_SEC. Therefore, just cast it to u32 using `as`. + let sub_second_counter_value = counter_value.0 % frequency; + let nanos = unsafe { sub_second_counter_value.unchecked_mul(u64::from(NANOSEC_PER_SEC)) } + .div(frequency) as u32; + + Duration::new(secs, nanos) } +} - fn uptime(&self) -> Duration { - let current_count: u64 = self.read_cntpct() * NS_PER_S; - let frq: u64 = CNTFRQ_EL0.get() as u64; +fn max_duration() -> Duration { + Duration::from(GenericTimerCounterValue::MAX) +} - Duration::from_nanos(current_count / frq) - } +impl TryFrom for GenericTimerCounterValue { + type Error = &'static str; - fn spin_for(&self, duration: Duration) { - // Instantly return on zero. - if duration.as_nanos() == 0 { - return; + fn try_from(duration: Duration) -> Result { + if duration < resolution() { + return Ok(GenericTimerCounterValue(0)); } - // Calculate the register compare value. - let frq = CNTFRQ_EL0.get(); - let x = match frq.checked_mul(duration.as_nanos() as u64) { - #[allow(unused_imports)] - None => { - warn!("Spin duration too long, skipping"); - return; - } - Some(val) => val, - }; - let tval = x / NS_PER_S; - - // Check if it is within supported bounds. - let warn: Option<&str> = if tval == 0 { - Some("smaller") - // The upper 32 bits of CNTP_TVAL_EL0 are reserved. - } else if tval > u32::max_value().into() { - Some("bigger") - } else { - None - }; - - #[allow(unused_imports)] - if let Some(w) = warn { - warn!( - "Spin duration {} than architecturally supported, skipping", - w - ); - return; + if duration > max_duration() { + return Err("Conversion error. Duration too big"); } - // Set the compare value register. - CNTP_TVAL_EL0.set(tval); + // This is safe, because all the safety requirements as stated in read_volatile()'s + // documentation are fulfilled. + let frequency: u128 = + unsafe { u32::from(core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY)) as u128 }; + let duration: u128 = duration.as_nanos(); - // Kick off the counting. // Disable timer interrupt. - CNTP_CTL_EL0.modify(CNTP_CTL_EL0::ENABLE::SET + CNTP_CTL_EL0::IMASK::SET); + // This is safe, because frequency can never be greater than u32::MAX, and + // (Duration::MAX.as_nanos() * u32::MAX) < u128::MAX. + let counter_value = + unsafe { duration.unchecked_mul(frequency) }.div(NonZeroU128::from(NANOSEC_PER_SEC)); - // ISTATUS will be '1' when cval ticks have passed. Busy-check it. - while !CNTP_CTL_EL0.matches_all(CNTP_CTL_EL0::ISTATUS::SET) {} - - // Disable counting again. - CNTP_CTL_EL0.modify(CNTP_CTL_EL0::ENABLE::CLEAR); + // Since we checked above that we are <= max_duration(), just cast to u64. + Ok(GenericTimerCounterValue(counter_value as u64)) } } + +#[inline(always)] +fn read_cntpct() -> GenericTimerCounterValue { + // Prevent that the counter is read ahead of time due to out-of-order execution. + unsafe { barrier::isb(barrier::SY) }; + let cnt = CNTPCT_EL0.get(); + + GenericTimerCounterValue(cnt) +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +/// The timer's resolution. +pub fn resolution() -> Duration { + Duration::from(GenericTimerCounterValue(1)) +} + +/// The uptime since power-on of the device. +/// +/// This includes time consumed by firmware and bootloaders. +pub fn uptime() -> Duration { + read_cntpct().into() +} + +/// Spin for a given duration. +#[cfg(feature = "bsp_rpi3")] +pub fn spin_for(duration: Duration) { + let curr_counter_value = read_cntpct(); + + let counter_value_delta: GenericTimerCounterValue = match duration.try_into() { + Err(msg) => { + warn!("spin_for: {}. Skipping", msg); + return; + } + Ok(val) => val, + }; + let counter_value_target = curr_counter_value + counter_value_delta; + + // Busy wait. + // + // Read CNTPCT_EL0 directly to avoid the ISB that is part of [`read_cntpct`]. + while GenericTimerCounterValue(CNTPCT_EL0.get()) < counter_value_target {} +} diff --git a/X1_JTAG_boot/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs b/X1_JTAG_boot/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs index 24958eb5..24e537cf 100644 --- a/X1_JTAG_boot/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs +++ b/X1_JTAG_boot/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs @@ -140,7 +140,7 @@ impl GPIOInner { /// Disable pull-up/down on pins 14 and 15. #[cfg(feature = "bsp_rpi3")] fn disable_pud_14_15_bcm2837(&mut self) { - use crate::{time, time::interface::TimeManager}; + use crate::time; use core::time::Duration; // The Linux 2837 GPIO driver waits 1 µs between the steps. diff --git a/X1_JTAG_boot/src/main.rs b/X1_JTAG_boot/src/main.rs index a985c679..a38b1ef5 100644 --- a/X1_JTAG_boot/src/main.rs +++ b/X1_JTAG_boot/src/main.rs @@ -108,9 +108,12 @@ #![allow(clippy::upper_case_acronyms)] #![feature(asm_const)] +#![feature(const_option)] #![feature(format_args_nl)] +#![feature(nonzero_min_max)] #![feature(panic_info_message)] #![feature(trait_alias)] +#![feature(unchecked_math)] #![no_main] #![no_std] diff --git a/X1_JTAG_boot/src/panic_wait.rs b/X1_JTAG_boot/src/panic_wait.rs index edd83885..ccf54f61 100644 --- a/X1_JTAG_boot/src/panic_wait.rs +++ b/X1_JTAG_boot/src/panic_wait.rs @@ -42,8 +42,6 @@ fn panic_prevent_reenter() { #[panic_handler] fn panic(info: &PanicInfo) -> ! { - use crate::time::interface::TimeManager; - // Protect against panic infinite loops if any of the following code panics itself. panic_prevent_reenter(); diff --git a/X1_JTAG_boot/src/print.rs b/X1_JTAG_boot/src/print.rs index 8705eec0..fe13b334 100644 --- a/X1_JTAG_boot/src/print.rs +++ b/X1_JTAG_boot/src/print.rs @@ -39,8 +39,6 @@ macro_rules! println { #[macro_export] macro_rules! info { ($string:expr) => ({ - use $crate::time::interface::TimeManager; - let timestamp = $crate::time::time_manager().uptime(); $crate::print::_print(format_args_nl!( @@ -50,8 +48,6 @@ macro_rules! info { )); }); ($format_string:expr, $($arg:tt)*) => ({ - use $crate::time::interface::TimeManager; - let timestamp = $crate::time::time_manager().uptime(); $crate::print::_print(format_args_nl!( @@ -67,8 +63,6 @@ macro_rules! info { #[macro_export] macro_rules! warn { ($string:expr) => ({ - use $crate::time::interface::TimeManager; - let timestamp = $crate::time::time_manager().uptime(); $crate::print::_print(format_args_nl!( @@ -78,8 +72,6 @@ macro_rules! warn { )); }); ($format_string:expr, $($arg:tt)*) => ({ - use $crate::time::interface::TimeManager; - let timestamp = $crate::time::time_manager().uptime(); $crate::print::_print(format_args_nl!( diff --git a/X1_JTAG_boot/src/time.rs b/X1_JTAG_boot/src/time.rs index 6d92b196..c6b40068 100644 --- a/X1_JTAG_boot/src/time.rs +++ b/X1_JTAG_boot/src/time.rs @@ -8,30 +8,46 @@ #[path = "_arch/aarch64/time.rs"] mod arch_time; +use core::time::Duration; + //-------------------------------------------------------------------------------------------------- -// Architectural Public Reexports +// Public Definitions //-------------------------------------------------------------------------------------------------- -pub use arch_time::time_manager; + +/// Provides time management functions. +pub struct TimeManager; //-------------------------------------------------------------------------------------------------- -// Public Definitions +// Global instances //-------------------------------------------------------------------------------------------------- -/// Timekeeping interfaces. -pub mod interface { - use core::time::Duration; +static TIME_MANAGER: TimeManager = TimeManager::new(); - /// Time management functions. - pub trait TimeManager { - /// The timer's resolution. - fn resolution(&self) -> Duration; +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- - /// The uptime since power-on of the device. - /// - /// This includes time consumed by firmware and bootloaders. - fn uptime(&self) -> Duration; +/// Return a reference to the global TimeManager. +pub fn time_manager() -> &'static TimeManager { + &TIME_MANAGER +} + +impl TimeManager { + /// Create an instance. + pub const fn new() -> Self { + Self + } + + /// The uptime since power-on of the device. + /// + /// This includes time consumed by firmware and bootloaders. + pub fn uptime(&self) -> Duration { + arch_time::uptime() + } - /// Spin for a given duration. - fn spin_for(&self, duration: Duration); + /// Spin for a given duration. + #[cfg(feature = "bsp_rpi3")] + pub fn spin_for(&self, duration: Duration) { + arch_time::spin_for(duration) } } From c21641e9b551d4fc1b574720b97a74beaba883ee Mon Sep 17 00:00:00 2001 From: Andre Richter Date: Fri, 23 Sep 2022 22:54:40 +0200 Subject: [PATCH 53/75] devtool: Fix boot test discovery --- utils/devtool.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/devtool.rb b/utils/devtool.rb index 00417125..47141c1d 100755 --- a/utils/devtool.rb +++ b/utils/devtool.rb @@ -94,7 +94,7 @@ class TutorialCrate private def boot_test? - Dir.exist?("#{@folder}/kernel/tests") + Dir.exist?("#{@folder}/tests") || Dir.exist?("#{@folder}/kernel/tests") end def unit_integration_tests? From b22b0b179217007b02a437f305c20443e1643f18 Mon Sep 17 00:00:00 2001 From: Andre Richter Date: Fri, 23 Sep 2022 22:56:32 +0200 Subject: [PATCH 54/75] Be more consistent in boot.rs GPR choices --- 02_runtime_init/README.md | 8 ++++---- 02_runtime_init/src/_arch/aarch64/cpu/boot.s | 8 ++++---- 03_hacky_hello_world/src/_arch/aarch64/cpu/boot.s | 8 ++++---- 04_safe_globals/src/_arch/aarch64/cpu/boot.s | 8 ++++---- 05_drivers_gpio_uart/src/_arch/aarch64/cpu/boot.s | 8 ++++---- 06_uart_chainloader/src/_arch/aarch64/cpu/boot.s | 8 ++++---- 07_timestamps/src/_arch/aarch64/cpu/boot.s | 8 ++++---- 08_hw_debug_JTAG/src/_arch/aarch64/cpu/boot.s | 8 ++++---- 09_privilege_level/README.md | 15 ++++++++++++--- 16_virtual_mem_part4_higher_half_kernel/README.md | 12 ++++++------ .../kernel/src/_arch/aarch64/cpu/boot.s | 12 ++++++------ .../kernel/src/_arch/aarch64/cpu/boot.s | 12 ++++++------ 18_backtrace/kernel/src/_arch/aarch64/cpu/boot.s | 12 ++++++------ .../kernel/src/_arch/aarch64/cpu/boot.s | 12 ++++++------ 14 files changed, 74 insertions(+), 65 deletions(-) diff --git a/02_runtime_init/README.md b/02_runtime_init/README.md index f9d59b30..f5b9355c 100644 --- a/02_runtime_init/README.md +++ b/02_runtime_init/README.md @@ -117,10 +117,10 @@ diff -uNr 01_wait_forever/src/_arch/aarch64/cpu/boot.s 02_runtime_init/src/_arch //------------------------------------------------------------------------------ _start: + // Only proceed on the boot core. Park it otherwise. -+ mrs x1, MPIDR_EL1 -+ and x1, x1, {CONST_CORE_ID_MASK} -+ ldr x2, BOOT_CORE_ID // provided by bsp/__board_name__/cpu.rs -+ cmp x1, x2 ++ mrs x0, MPIDR_EL1 ++ and x0, x0, {CONST_CORE_ID_MASK} ++ ldr x1, BOOT_CORE_ID // provided by bsp/__board_name__/cpu.rs ++ cmp x0, x1 + b.ne .L_parking_loop + + // If execution reaches here, it is the boot core. diff --git a/02_runtime_init/src/_arch/aarch64/cpu/boot.s b/02_runtime_init/src/_arch/aarch64/cpu/boot.s index 1f70169f..0011c607 100644 --- a/02_runtime_init/src/_arch/aarch64/cpu/boot.s +++ b/02_runtime_init/src/_arch/aarch64/cpu/boot.s @@ -28,10 +28,10 @@ //------------------------------------------------------------------------------ _start: // Only proceed on the boot core. Park it otherwise. - mrs x1, MPIDR_EL1 - and x1, x1, {CONST_CORE_ID_MASK} - ldr x2, BOOT_CORE_ID // provided by bsp/__board_name__/cpu.rs - cmp x1, x2 + mrs x0, MPIDR_EL1 + and x0, x0, {CONST_CORE_ID_MASK} + ldr x1, BOOT_CORE_ID // provided by bsp/__board_name__/cpu.rs + cmp x0, x1 b.ne .L_parking_loop // If execution reaches here, it is the boot core. diff --git a/03_hacky_hello_world/src/_arch/aarch64/cpu/boot.s b/03_hacky_hello_world/src/_arch/aarch64/cpu/boot.s index 1f70169f..0011c607 100644 --- a/03_hacky_hello_world/src/_arch/aarch64/cpu/boot.s +++ b/03_hacky_hello_world/src/_arch/aarch64/cpu/boot.s @@ -28,10 +28,10 @@ //------------------------------------------------------------------------------ _start: // Only proceed on the boot core. Park it otherwise. - mrs x1, MPIDR_EL1 - and x1, x1, {CONST_CORE_ID_MASK} - ldr x2, BOOT_CORE_ID // provided by bsp/__board_name__/cpu.rs - cmp x1, x2 + mrs x0, MPIDR_EL1 + and x0, x0, {CONST_CORE_ID_MASK} + ldr x1, BOOT_CORE_ID // provided by bsp/__board_name__/cpu.rs + cmp x0, x1 b.ne .L_parking_loop // If execution reaches here, it is the boot core. diff --git a/04_safe_globals/src/_arch/aarch64/cpu/boot.s b/04_safe_globals/src/_arch/aarch64/cpu/boot.s index 1f70169f..0011c607 100644 --- a/04_safe_globals/src/_arch/aarch64/cpu/boot.s +++ b/04_safe_globals/src/_arch/aarch64/cpu/boot.s @@ -28,10 +28,10 @@ //------------------------------------------------------------------------------ _start: // Only proceed on the boot core. Park it otherwise. - mrs x1, MPIDR_EL1 - and x1, x1, {CONST_CORE_ID_MASK} - ldr x2, BOOT_CORE_ID // provided by bsp/__board_name__/cpu.rs - cmp x1, x2 + mrs x0, MPIDR_EL1 + and x0, x0, {CONST_CORE_ID_MASK} + ldr x1, BOOT_CORE_ID // provided by bsp/__board_name__/cpu.rs + cmp x0, x1 b.ne .L_parking_loop // If execution reaches here, it is the boot core. diff --git a/05_drivers_gpio_uart/src/_arch/aarch64/cpu/boot.s b/05_drivers_gpio_uart/src/_arch/aarch64/cpu/boot.s index 1f70169f..0011c607 100644 --- a/05_drivers_gpio_uart/src/_arch/aarch64/cpu/boot.s +++ b/05_drivers_gpio_uart/src/_arch/aarch64/cpu/boot.s @@ -28,10 +28,10 @@ //------------------------------------------------------------------------------ _start: // Only proceed on the boot core. Park it otherwise. - mrs x1, MPIDR_EL1 - and x1, x1, {CONST_CORE_ID_MASK} - ldr x2, BOOT_CORE_ID // provided by bsp/__board_name__/cpu.rs - cmp x1, x2 + mrs x0, MPIDR_EL1 + and x0, x0, {CONST_CORE_ID_MASK} + ldr x1, BOOT_CORE_ID // provided by bsp/__board_name__/cpu.rs + cmp x0, x1 b.ne .L_parking_loop // If execution reaches here, it is the boot core. diff --git a/06_uart_chainloader/src/_arch/aarch64/cpu/boot.s b/06_uart_chainloader/src/_arch/aarch64/cpu/boot.s index 322573ca..3ed0d494 100644 --- a/06_uart_chainloader/src/_arch/aarch64/cpu/boot.s +++ b/06_uart_chainloader/src/_arch/aarch64/cpu/boot.s @@ -39,10 +39,10 @@ //------------------------------------------------------------------------------ _start: // Only proceed on the boot core. Park it otherwise. - mrs x1, MPIDR_EL1 - and x1, x1, {CONST_CORE_ID_MASK} - ldr x2, BOOT_CORE_ID // provided by bsp/__board_name__/cpu.rs - cmp x1, x2 + mrs x0, MPIDR_EL1 + and x0, x0, {CONST_CORE_ID_MASK} + ldr x1, BOOT_CORE_ID // provided by bsp/__board_name__/cpu.rs + cmp x0, x1 b.ne .L_parking_loop // If execution reaches here, it is the boot core. diff --git a/07_timestamps/src/_arch/aarch64/cpu/boot.s b/07_timestamps/src/_arch/aarch64/cpu/boot.s index aa701fd1..0b801b4b 100644 --- a/07_timestamps/src/_arch/aarch64/cpu/boot.s +++ b/07_timestamps/src/_arch/aarch64/cpu/boot.s @@ -28,10 +28,10 @@ //------------------------------------------------------------------------------ _start: // Only proceed on the boot core. Park it otherwise. - mrs x1, MPIDR_EL1 - and x1, x1, {CONST_CORE_ID_MASK} - ldr x2, BOOT_CORE_ID // provided by bsp/__board_name__/cpu.rs - cmp x1, x2 + mrs x0, MPIDR_EL1 + and x0, x0, {CONST_CORE_ID_MASK} + ldr x1, BOOT_CORE_ID // provided by bsp/__board_name__/cpu.rs + cmp x0, x1 b.ne .L_parking_loop // If execution reaches here, it is the boot core. diff --git a/08_hw_debug_JTAG/src/_arch/aarch64/cpu/boot.s b/08_hw_debug_JTAG/src/_arch/aarch64/cpu/boot.s index aa701fd1..0b801b4b 100644 --- a/08_hw_debug_JTAG/src/_arch/aarch64/cpu/boot.s +++ b/08_hw_debug_JTAG/src/_arch/aarch64/cpu/boot.s @@ -28,10 +28,10 @@ //------------------------------------------------------------------------------ _start: // Only proceed on the boot core. Park it otherwise. - mrs x1, MPIDR_EL1 - and x1, x1, {CONST_CORE_ID_MASK} - ldr x2, BOOT_CORE_ID // provided by bsp/__board_name__/cpu.rs - cmp x1, x2 + mrs x0, MPIDR_EL1 + and x0, x0, {CONST_CORE_ID_MASK} + ldr x1, BOOT_CORE_ID // provided by bsp/__board_name__/cpu.rs + cmp x0, x1 b.ne .L_parking_loop // If execution reaches here, it is the boot core. diff --git a/09_privilege_level/README.md b/09_privilege_level/README.md index afcfe8f6..7f7c58d1 100644 --- a/09_privilege_level/README.md +++ b/09_privilege_level/README.md @@ -291,7 +291,7 @@ diff -uNr 08_hw_debug_JTAG/src/_arch/aarch64/cpu/boot.rs 09_privilege_level/src/ diff -uNr 08_hw_debug_JTAG/src/_arch/aarch64/cpu/boot.s 09_privilege_level/src/_arch/aarch64/cpu/boot.s --- 08_hw_debug_JTAG/src/_arch/aarch64/cpu/boot.s +++ 09_privilege_level/src/_arch/aarch64/cpu/boot.s -@@ -27,6 +27,11 @@ +@@ -27,11 +27,16 @@ // fn _start() //------------------------------------------------------------------------------ _start: @@ -301,8 +301,17 @@ diff -uNr 08_hw_debug_JTAG/src/_arch/aarch64/cpu/boot.s 09_privilege_level/src/_ + b.ne .L_parking_loop + // Only proceed on the boot core. Park it otherwise. - mrs x1, MPIDR_EL1 - and x1, x1, {CONST_CORE_ID_MASK} +- mrs x0, MPIDR_EL1 +- and x0, x0, {CONST_CORE_ID_MASK} +- ldr x1, BOOT_CORE_ID // provided by bsp/__board_name__/cpu.rs +- cmp x0, x1 ++ mrs x1, MPIDR_EL1 ++ and x1, x1, {CONST_CORE_ID_MASK} ++ ldr x2, BOOT_CORE_ID // provided by bsp/__board_name__/cpu.rs ++ cmp x1, x2 + b.ne .L_parking_loop + + // If execution reaches here, it is the boot core. @@ -48,7 +53,7 @@ // Prepare the jump to Rust code. diff --git a/16_virtual_mem_part4_higher_half_kernel/README.md b/16_virtual_mem_part4_higher_half_kernel/README.md index 6918f897..494506da 100644 --- a/16_virtual_mem_part4_higher_half_kernel/README.md +++ b/16_virtual_mem_part4_higher_half_kernel/README.md @@ -432,20 +432,20 @@ diff -uNr 15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/cpu/b + // Setting the stack pointer to this value ensures that anything that still runs in EL2, + // until the kernel returns to EL1 with the MMU enabled, works as well. After the return to + // EL1, the virtual address of the stack retrieved above will be used. -+ ADR_REL x4, __boot_core_stack_end_exclusive -+ mov sp, x4 ++ ADR_REL x3, __boot_core_stack_end_exclusive ++ mov sp, x3 // Read the CPU's timer counter frequency and store it in ARCH_TIMER_COUNTER_FREQUENCY. // Abort if the frequency read back as 0. - ADR_REL x2, ARCH_TIMER_COUNTER_FREQUENCY // provided by aarch64/time.rs - mrs x3, CNTFRQ_EL0 - cmp x3, xzr -+ ADR_REL x5, ARCH_TIMER_COUNTER_FREQUENCY // provided by aarch64/time.rs -+ mrs x6, CNTFRQ_EL0 -+ cmp x6, xzr ++ ADR_REL x4, ARCH_TIMER_COUNTER_FREQUENCY // provided by aarch64/time.rs ++ mrs x5, CNTFRQ_EL0 ++ cmp x5, xzr b.eq .L_parking_loop - str w3, [x2] -+ str w6, [x5] ++ str w5, [x4] - // Jump to Rust code. x0 and x1 hold the function arguments provided to _start_rust(). + // Jump to Rust code. x0, x1 and x2 hold the function arguments provided to _start_rust(). diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/cpu/boot.s b/16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/cpu/boot.s index bf6e32e4..1a8c8801 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/cpu/boot.s +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/cpu/boot.s @@ -81,16 +81,16 @@ _start: // Setting the stack pointer to this value ensures that anything that still runs in EL2, // until the kernel returns to EL1 with the MMU enabled, works as well. After the return to // EL1, the virtual address of the stack retrieved above will be used. - ADR_REL x4, __boot_core_stack_end_exclusive - mov sp, x4 + ADR_REL x3, __boot_core_stack_end_exclusive + mov sp, x3 // Read the CPU's timer counter frequency and store it in ARCH_TIMER_COUNTER_FREQUENCY. // Abort if the frequency read back as 0. - ADR_REL x5, ARCH_TIMER_COUNTER_FREQUENCY // provided by aarch64/time.rs - mrs x6, CNTFRQ_EL0 - cmp x6, xzr + ADR_REL x4, ARCH_TIMER_COUNTER_FREQUENCY // provided by aarch64/time.rs + mrs x5, CNTFRQ_EL0 + cmp x5, xzr b.eq .L_parking_loop - str w6, [x5] + str w5, [x4] // Jump to Rust code. x0, x1 and x2 hold the function arguments provided to _start_rust(). b _start_rust diff --git a/17_kernel_symbols/kernel/src/_arch/aarch64/cpu/boot.s b/17_kernel_symbols/kernel/src/_arch/aarch64/cpu/boot.s index bf6e32e4..1a8c8801 100644 --- a/17_kernel_symbols/kernel/src/_arch/aarch64/cpu/boot.s +++ b/17_kernel_symbols/kernel/src/_arch/aarch64/cpu/boot.s @@ -81,16 +81,16 @@ _start: // Setting the stack pointer to this value ensures that anything that still runs in EL2, // until the kernel returns to EL1 with the MMU enabled, works as well. After the return to // EL1, the virtual address of the stack retrieved above will be used. - ADR_REL x4, __boot_core_stack_end_exclusive - mov sp, x4 + ADR_REL x3, __boot_core_stack_end_exclusive + mov sp, x3 // Read the CPU's timer counter frequency and store it in ARCH_TIMER_COUNTER_FREQUENCY. // Abort if the frequency read back as 0. - ADR_REL x5, ARCH_TIMER_COUNTER_FREQUENCY // provided by aarch64/time.rs - mrs x6, CNTFRQ_EL0 - cmp x6, xzr + ADR_REL x4, ARCH_TIMER_COUNTER_FREQUENCY // provided by aarch64/time.rs + mrs x5, CNTFRQ_EL0 + cmp x5, xzr b.eq .L_parking_loop - str w6, [x5] + str w5, [x4] // Jump to Rust code. x0, x1 and x2 hold the function arguments provided to _start_rust(). b _start_rust diff --git a/18_backtrace/kernel/src/_arch/aarch64/cpu/boot.s b/18_backtrace/kernel/src/_arch/aarch64/cpu/boot.s index bf6e32e4..1a8c8801 100644 --- a/18_backtrace/kernel/src/_arch/aarch64/cpu/boot.s +++ b/18_backtrace/kernel/src/_arch/aarch64/cpu/boot.s @@ -81,16 +81,16 @@ _start: // Setting the stack pointer to this value ensures that anything that still runs in EL2, // until the kernel returns to EL1 with the MMU enabled, works as well. After the return to // EL1, the virtual address of the stack retrieved above will be used. - ADR_REL x4, __boot_core_stack_end_exclusive - mov sp, x4 + ADR_REL x3, __boot_core_stack_end_exclusive + mov sp, x3 // Read the CPU's timer counter frequency and store it in ARCH_TIMER_COUNTER_FREQUENCY. // Abort if the frequency read back as 0. - ADR_REL x5, ARCH_TIMER_COUNTER_FREQUENCY // provided by aarch64/time.rs - mrs x6, CNTFRQ_EL0 - cmp x6, xzr + ADR_REL x4, ARCH_TIMER_COUNTER_FREQUENCY // provided by aarch64/time.rs + mrs x5, CNTFRQ_EL0 + cmp x5, xzr b.eq .L_parking_loop - str w6, [x5] + str w5, [x4] // Jump to Rust code. x0, x1 and x2 hold the function arguments provided to _start_rust(). b _start_rust diff --git a/19_kernel_heap/kernel/src/_arch/aarch64/cpu/boot.s b/19_kernel_heap/kernel/src/_arch/aarch64/cpu/boot.s index bf6e32e4..1a8c8801 100644 --- a/19_kernel_heap/kernel/src/_arch/aarch64/cpu/boot.s +++ b/19_kernel_heap/kernel/src/_arch/aarch64/cpu/boot.s @@ -81,16 +81,16 @@ _start: // Setting the stack pointer to this value ensures that anything that still runs in EL2, // until the kernel returns to EL1 with the MMU enabled, works as well. After the return to // EL1, the virtual address of the stack retrieved above will be used. - ADR_REL x4, __boot_core_stack_end_exclusive - mov sp, x4 + ADR_REL x3, __boot_core_stack_end_exclusive + mov sp, x3 // Read the CPU's timer counter frequency and store it in ARCH_TIMER_COUNTER_FREQUENCY. // Abort if the frequency read back as 0. - ADR_REL x5, ARCH_TIMER_COUNTER_FREQUENCY // provided by aarch64/time.rs - mrs x6, CNTFRQ_EL0 - cmp x6, xzr + ADR_REL x4, ARCH_TIMER_COUNTER_FREQUENCY // provided by aarch64/time.rs + mrs x5, CNTFRQ_EL0 + cmp x5, xzr b.eq .L_parking_loop - str w6, [x5] + str w5, [x4] // Jump to Rust code. x0, x1 and x2 hold the function arguments provided to _start_rust(). b _start_rust From 2345214367cfc9a82dfdf39da257b3859e95da98 Mon Sep 17 00:00:00 2001 From: Andre Richter Date: Mon, 26 Sep 2022 22:38:55 +0200 Subject: [PATCH 55/75] Various minor improvements --- 07_timestamps/README.md | 22 ++--- 07_timestamps/src/_arch/aarch64/time.rs | 22 ++--- 08_hw_debug_JTAG/src/_arch/aarch64/time.rs | 22 ++--- 09_privilege_level/src/_arch/aarch64/time.rs | 22 ++--- .../src/_arch/aarch64/time.rs | 22 ++--- .../src/_arch/aarch64/time.rs | 22 ++--- .../kernel/src/_arch/aarch64/time.rs | 22 ++--- 13_exceptions_part2_peripheral_IRQs/README.md | 42 +++++----- .../kernel/src/_arch/aarch64/time.rs | 22 ++--- .../kernel/src/bsp/device_driver/arm/gicv2.rs | 5 +- .../bcm/bcm2xxx_interrupt_controller.rs | 15 ++-- .../peripheral_ic.rs | 11 ++- .../kernel/src/exception/asynchronous.rs | 3 + 14_virtual_mem_part2_mmio_remap/README.md | 18 ++-- .../kernel/src/_arch/aarch64/time.rs | 22 ++--- .../kernel/src/bsp/device_driver/arm/gicv2.rs | 5 +- .../bcm/bcm2xxx_interrupt_controller.rs | 15 ++-- .../peripheral_ic.rs | 11 ++- .../kernel/src/exception/asynchronous.rs | 3 + .../kernel/src/_arch/aarch64/time.rs | 22 ++--- .../kernel/src/bsp/device_driver/arm/gicv2.rs | 5 +- .../bcm/bcm2xxx_interrupt_controller.rs | 15 ++-- .../peripheral_ic.rs | 11 ++- .../kernel/src/exception/asynchronous.rs | 3 + .../kernel/src/_arch/aarch64/time.rs | 22 ++--- .../kernel/src/bsp/device_driver/arm/gicv2.rs | 5 +- .../bcm/bcm2xxx_interrupt_controller.rs | 15 ++-- .../peripheral_ic.rs | 11 ++- .../kernel/src/exception/asynchronous.rs | 3 + 17_kernel_symbols/README.md | 28 +++++-- .../kernel/src/_arch/aarch64/time.rs | 22 ++--- .../kernel/src/bsp/device_driver/arm/gicv2.rs | 5 +- .../bcm/bcm2xxx_interrupt_controller.rs | 15 ++-- .../peripheral_ic.rs | 11 ++- .../kernel/src/exception/asynchronous.rs | 3 + 17_kernel_symbols/kernel/src/symbols.rs | 13 ++- 18_backtrace/kernel/src/_arch/aarch64/time.rs | 22 ++--- .../kernel/src/bsp/device_driver/arm/gicv2.rs | 5 +- .../bcm/bcm2xxx_interrupt_controller.rs | 15 ++-- .../peripheral_ic.rs | 11 ++- .../kernel/src/exception/asynchronous.rs | 3 + 18_backtrace/kernel/src/symbols.rs | 13 ++- 19_kernel_heap/README.md | 83 ++++++++----------- .../kernel/src/_arch/aarch64/time.rs | 22 ++--- .../kernel/src/bsp/device_driver/arm/gicv2.rs | 9 +- .../bcm/bcm2xxx_interrupt_controller.rs | 16 ++-- .../peripheral_ic.rs | 16 ++-- .../kernel/src/exception/asynchronous.rs | 3 + 19_kernel_heap/kernel/src/symbols.rs | 13 ++- X1_JTAG_boot/src/_arch/aarch64/time.rs | 22 ++--- 50 files changed, 407 insertions(+), 381 deletions(-) diff --git a/07_timestamps/README.md b/07_timestamps/README.md index a78e508b..c96a30e4 100644 --- a/07_timestamps/README.md +++ b/07_timestamps/README.md @@ -302,6 +302,15 @@ diff -uNr 06_uart_chainloader/src/_arch/aarch64/time.rs 07_timestamps/src/_arch/ +// Private Code +//-------------------------------------------------------------------------------------------------- + ++fn arch_timer_counter_frequency() -> NonZeroU32 { ++ // Read volatile is needed here to prevent the compiler from optimizing ++ // ARCH_TIMER_COUNTER_FREQUENCY away. ++ // ++ // This is safe, because all the safety requirements as stated in read_volatile()'s ++ // documentation are fulfilled. ++ unsafe { core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY) } ++} ++ +impl GenericTimerCounterValue { + pub const MAX: Self = GenericTimerCounterValue(u64::MAX); +} @@ -320,13 +329,7 @@ diff -uNr 06_uart_chainloader/src/_arch/aarch64/time.rs 07_timestamps/src/_arch/ + return Duration::ZERO; + } + -+ // Read volatile is needed here to prevent the compiler from optimizing -+ // ARCH_TIMER_COUNTER_FREQUENCY away. -+ // -+ // This is safe, because all the safety requirements as stated in read_volatile()'s -+ // documentation are fulfilled. -+ let frequency: NonZeroU64 = -+ unsafe { core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY) }.into(); ++ let frequency: NonZeroU64 = arch_timer_counter_frequency().into(); + + // Div implementation for u64 cannot panic. + let secs = counter_value.0.div(frequency); @@ -361,10 +364,7 @@ diff -uNr 06_uart_chainloader/src/_arch/aarch64/time.rs 07_timestamps/src/_arch/ + return Err("Conversion error. Duration too big"); + } + -+ // This is safe, because all the safety requirements as stated in read_volatile()'s -+ // documentation are fulfilled. -+ let frequency: u128 = -+ unsafe { u32::from(core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY)) as u128 }; ++ let frequency: u128 = u32::from(arch_timer_counter_frequency()) as u128; + let duration: u128 = duration.as_nanos(); + + // This is safe, because frequency can never be greater than u32::MAX, and diff --git a/07_timestamps/src/_arch/aarch64/time.rs b/07_timestamps/src/_arch/aarch64/time.rs index 255a5a45..ad8ba84d 100644 --- a/07_timestamps/src/_arch/aarch64/time.rs +++ b/07_timestamps/src/_arch/aarch64/time.rs @@ -42,6 +42,15 @@ static ARCH_TIMER_COUNTER_FREQUENCY: NonZeroU32 = NonZeroU32::MIN; // Private Code //-------------------------------------------------------------------------------------------------- +fn arch_timer_counter_frequency() -> NonZeroU32 { + // Read volatile is needed here to prevent the compiler from optimizing + // ARCH_TIMER_COUNTER_FREQUENCY away. + // + // This is safe, because all the safety requirements as stated in read_volatile()'s + // documentation are fulfilled. + unsafe { core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY) } +} + impl GenericTimerCounterValue { pub const MAX: Self = GenericTimerCounterValue(u64::MAX); } @@ -60,13 +69,7 @@ impl From for Duration { return Duration::ZERO; } - // Read volatile is needed here to prevent the compiler from optimizing - // ARCH_TIMER_COUNTER_FREQUENCY away. - // - // This is safe, because all the safety requirements as stated in read_volatile()'s - // documentation are fulfilled. - let frequency: NonZeroU64 = - unsafe { core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY) }.into(); + let frequency: NonZeroU64 = arch_timer_counter_frequency().into(); // Div implementation for u64 cannot panic. let secs = counter_value.0.div(frequency); @@ -101,10 +104,7 @@ impl TryFrom for GenericTimerCounterValue { return Err("Conversion error. Duration too big"); } - // This is safe, because all the safety requirements as stated in read_volatile()'s - // documentation are fulfilled. - let frequency: u128 = - unsafe { u32::from(core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY)) as u128 }; + let frequency: u128 = u32::from(arch_timer_counter_frequency()) as u128; let duration: u128 = duration.as_nanos(); // This is safe, because frequency can never be greater than u32::MAX, and diff --git a/08_hw_debug_JTAG/src/_arch/aarch64/time.rs b/08_hw_debug_JTAG/src/_arch/aarch64/time.rs index 255a5a45..ad8ba84d 100644 --- a/08_hw_debug_JTAG/src/_arch/aarch64/time.rs +++ b/08_hw_debug_JTAG/src/_arch/aarch64/time.rs @@ -42,6 +42,15 @@ static ARCH_TIMER_COUNTER_FREQUENCY: NonZeroU32 = NonZeroU32::MIN; // Private Code //-------------------------------------------------------------------------------------------------- +fn arch_timer_counter_frequency() -> NonZeroU32 { + // Read volatile is needed here to prevent the compiler from optimizing + // ARCH_TIMER_COUNTER_FREQUENCY away. + // + // This is safe, because all the safety requirements as stated in read_volatile()'s + // documentation are fulfilled. + unsafe { core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY) } +} + impl GenericTimerCounterValue { pub const MAX: Self = GenericTimerCounterValue(u64::MAX); } @@ -60,13 +69,7 @@ impl From for Duration { return Duration::ZERO; } - // Read volatile is needed here to prevent the compiler from optimizing - // ARCH_TIMER_COUNTER_FREQUENCY away. - // - // This is safe, because all the safety requirements as stated in read_volatile()'s - // documentation are fulfilled. - let frequency: NonZeroU64 = - unsafe { core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY) }.into(); + let frequency: NonZeroU64 = arch_timer_counter_frequency().into(); // Div implementation for u64 cannot panic. let secs = counter_value.0.div(frequency); @@ -101,10 +104,7 @@ impl TryFrom for GenericTimerCounterValue { return Err("Conversion error. Duration too big"); } - // This is safe, because all the safety requirements as stated in read_volatile()'s - // documentation are fulfilled. - let frequency: u128 = - unsafe { u32::from(core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY)) as u128 }; + let frequency: u128 = u32::from(arch_timer_counter_frequency()) as u128; let duration: u128 = duration.as_nanos(); // This is safe, because frequency can never be greater than u32::MAX, and diff --git a/09_privilege_level/src/_arch/aarch64/time.rs b/09_privilege_level/src/_arch/aarch64/time.rs index 255a5a45..ad8ba84d 100644 --- a/09_privilege_level/src/_arch/aarch64/time.rs +++ b/09_privilege_level/src/_arch/aarch64/time.rs @@ -42,6 +42,15 @@ static ARCH_TIMER_COUNTER_FREQUENCY: NonZeroU32 = NonZeroU32::MIN; // Private Code //-------------------------------------------------------------------------------------------------- +fn arch_timer_counter_frequency() -> NonZeroU32 { + // Read volatile is needed here to prevent the compiler from optimizing + // ARCH_TIMER_COUNTER_FREQUENCY away. + // + // This is safe, because all the safety requirements as stated in read_volatile()'s + // documentation are fulfilled. + unsafe { core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY) } +} + impl GenericTimerCounterValue { pub const MAX: Self = GenericTimerCounterValue(u64::MAX); } @@ -60,13 +69,7 @@ impl From for Duration { return Duration::ZERO; } - // Read volatile is needed here to prevent the compiler from optimizing - // ARCH_TIMER_COUNTER_FREQUENCY away. - // - // This is safe, because all the safety requirements as stated in read_volatile()'s - // documentation are fulfilled. - let frequency: NonZeroU64 = - unsafe { core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY) }.into(); + let frequency: NonZeroU64 = arch_timer_counter_frequency().into(); // Div implementation for u64 cannot panic. let secs = counter_value.0.div(frequency); @@ -101,10 +104,7 @@ impl TryFrom for GenericTimerCounterValue { return Err("Conversion error. Duration too big"); } - // This is safe, because all the safety requirements as stated in read_volatile()'s - // documentation are fulfilled. - let frequency: u128 = - unsafe { u32::from(core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY)) as u128 }; + let frequency: u128 = u32::from(arch_timer_counter_frequency()) as u128; let duration: u128 = duration.as_nanos(); // This is safe, because frequency can never be greater than u32::MAX, and diff --git a/10_virtual_mem_part1_identity_mapping/src/_arch/aarch64/time.rs b/10_virtual_mem_part1_identity_mapping/src/_arch/aarch64/time.rs index 255a5a45..ad8ba84d 100644 --- a/10_virtual_mem_part1_identity_mapping/src/_arch/aarch64/time.rs +++ b/10_virtual_mem_part1_identity_mapping/src/_arch/aarch64/time.rs @@ -42,6 +42,15 @@ static ARCH_TIMER_COUNTER_FREQUENCY: NonZeroU32 = NonZeroU32::MIN; // Private Code //-------------------------------------------------------------------------------------------------- +fn arch_timer_counter_frequency() -> NonZeroU32 { + // Read volatile is needed here to prevent the compiler from optimizing + // ARCH_TIMER_COUNTER_FREQUENCY away. + // + // This is safe, because all the safety requirements as stated in read_volatile()'s + // documentation are fulfilled. + unsafe { core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY) } +} + impl GenericTimerCounterValue { pub const MAX: Self = GenericTimerCounterValue(u64::MAX); } @@ -60,13 +69,7 @@ impl From for Duration { return Duration::ZERO; } - // Read volatile is needed here to prevent the compiler from optimizing - // ARCH_TIMER_COUNTER_FREQUENCY away. - // - // This is safe, because all the safety requirements as stated in read_volatile()'s - // documentation are fulfilled. - let frequency: NonZeroU64 = - unsafe { core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY) }.into(); + let frequency: NonZeroU64 = arch_timer_counter_frequency().into(); // Div implementation for u64 cannot panic. let secs = counter_value.0.div(frequency); @@ -101,10 +104,7 @@ impl TryFrom for GenericTimerCounterValue { return Err("Conversion error. Duration too big"); } - // This is safe, because all the safety requirements as stated in read_volatile()'s - // documentation are fulfilled. - let frequency: u128 = - unsafe { u32::from(core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY)) as u128 }; + let frequency: u128 = u32::from(arch_timer_counter_frequency()) as u128; let duration: u128 = duration.as_nanos(); // This is safe, because frequency can never be greater than u32::MAX, and diff --git a/11_exceptions_part1_groundwork/src/_arch/aarch64/time.rs b/11_exceptions_part1_groundwork/src/_arch/aarch64/time.rs index 255a5a45..ad8ba84d 100644 --- a/11_exceptions_part1_groundwork/src/_arch/aarch64/time.rs +++ b/11_exceptions_part1_groundwork/src/_arch/aarch64/time.rs @@ -42,6 +42,15 @@ static ARCH_TIMER_COUNTER_FREQUENCY: NonZeroU32 = NonZeroU32::MIN; // Private Code //-------------------------------------------------------------------------------------------------- +fn arch_timer_counter_frequency() -> NonZeroU32 { + // Read volatile is needed here to prevent the compiler from optimizing + // ARCH_TIMER_COUNTER_FREQUENCY away. + // + // This is safe, because all the safety requirements as stated in read_volatile()'s + // documentation are fulfilled. + unsafe { core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY) } +} + impl GenericTimerCounterValue { pub const MAX: Self = GenericTimerCounterValue(u64::MAX); } @@ -60,13 +69,7 @@ impl From for Duration { return Duration::ZERO; } - // Read volatile is needed here to prevent the compiler from optimizing - // ARCH_TIMER_COUNTER_FREQUENCY away. - // - // This is safe, because all the safety requirements as stated in read_volatile()'s - // documentation are fulfilled. - let frequency: NonZeroU64 = - unsafe { core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY) }.into(); + let frequency: NonZeroU64 = arch_timer_counter_frequency().into(); // Div implementation for u64 cannot panic. let secs = counter_value.0.div(frequency); @@ -101,10 +104,7 @@ impl TryFrom for GenericTimerCounterValue { return Err("Conversion error. Duration too big"); } - // This is safe, because all the safety requirements as stated in read_volatile()'s - // documentation are fulfilled. - let frequency: u128 = - unsafe { u32::from(core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY)) as u128 }; + let frequency: u128 = u32::from(arch_timer_counter_frequency()) as u128; let duration: u128 = duration.as_nanos(); // This is safe, because frequency can never be greater than u32::MAX, and diff --git a/12_integrated_testing/kernel/src/_arch/aarch64/time.rs b/12_integrated_testing/kernel/src/_arch/aarch64/time.rs index 255a5a45..ad8ba84d 100644 --- a/12_integrated_testing/kernel/src/_arch/aarch64/time.rs +++ b/12_integrated_testing/kernel/src/_arch/aarch64/time.rs @@ -42,6 +42,15 @@ static ARCH_TIMER_COUNTER_FREQUENCY: NonZeroU32 = NonZeroU32::MIN; // Private Code //-------------------------------------------------------------------------------------------------- +fn arch_timer_counter_frequency() -> NonZeroU32 { + // Read volatile is needed here to prevent the compiler from optimizing + // ARCH_TIMER_COUNTER_FREQUENCY away. + // + // This is safe, because all the safety requirements as stated in read_volatile()'s + // documentation are fulfilled. + unsafe { core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY) } +} + impl GenericTimerCounterValue { pub const MAX: Self = GenericTimerCounterValue(u64::MAX); } @@ -60,13 +69,7 @@ impl From for Duration { return Duration::ZERO; } - // Read volatile is needed here to prevent the compiler from optimizing - // ARCH_TIMER_COUNTER_FREQUENCY away. - // - // This is safe, because all the safety requirements as stated in read_volatile()'s - // documentation are fulfilled. - let frequency: NonZeroU64 = - unsafe { core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY) }.into(); + let frequency: NonZeroU64 = arch_timer_counter_frequency().into(); // Div implementation for u64 cannot panic. let secs = counter_value.0.div(frequency); @@ -101,10 +104,7 @@ impl TryFrom for GenericTimerCounterValue { return Err("Conversion error. Duration too big"); } - // This is safe, because all the safety requirements as stated in read_volatile()'s - // documentation are fulfilled. - let frequency: u128 = - unsafe { u32::from(core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY)) as u128 }; + let frequency: u128 = u32::from(arch_timer_counter_frequency()) as u128; let duration: u128 = duration.as_nanos(); // This is safe, because frequency can never be greater than u32::MAX, and diff --git a/13_exceptions_part2_peripheral_IRQs/README.md b/13_exceptions_part2_peripheral_IRQs/README.md index 3b7a8f64..0bb676db 100644 --- a/13_exceptions_part2_peripheral_IRQs/README.md +++ b/13_exceptions_part2_peripheral_IRQs/README.md @@ -1249,7 +1249,7 @@ diff -uNr 12_integrated_testing/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs 1 diff -uNr 12_integrated_testing/kernel/src/bsp/device_driver/arm/gicv2.rs 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/arm/gicv2.rs --- 12_integrated_testing/kernel/src/bsp/device_driver/arm/gicv2.rs +++ 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/arm/gicv2.rs -@@ -0,0 +1,221 @@ +@@ -0,0 +1,220 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2020-2022 Andre Richter @@ -1337,7 +1337,7 @@ diff -uNr 12_integrated_testing/kernel/src/bsp/device_driver/arm/gicv2.rs 13_exc +// Private Definitions +//-------------------------------------------------------------------------------------------------- + -+type HandlerTable = [Option; GICv2::NUM_IRQS]; ++type HandlerTable = [Option; IRQNumber::NUM_TOTAL]; + +//-------------------------------------------------------------------------------------------------- +// Public Definitions @@ -1364,7 +1364,6 @@ diff -uNr 12_integrated_testing/kernel/src/bsp/device_driver/arm/gicv2.rs 13_exc + +impl GICv2 { + const MAX_IRQ_NUMBER: usize = 300; // Normally 1019, but keep it lower to save some space. -+ const NUM_IRQS: usize = Self::MAX_IRQ_NUMBER + 1; + + pub const COMPATIBLE: &'static str = "GICv2 (ARM Generic Interrupt Controller v2)"; + @@ -1377,7 +1376,7 @@ diff -uNr 12_integrated_testing/kernel/src/bsp/device_driver/arm/gicv2.rs 13_exc + Self { + gicd: gicd::GICD::new(gicd_mmio_start_addr), + gicc: gicc::GICC::new(gicc_mmio_start_addr), -+ handler_table: InitStateLock::new([None; Self::NUM_IRQS]), ++ handler_table: InitStateLock::new([None; IRQNumber::NUM_TOTAL]), + } + } +} @@ -1520,14 +1519,18 @@ diff -uNr 12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs diff -uNr 12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs --- 12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs +++ 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs -@@ -0,0 +1,167 @@ +@@ -0,0 +1,170 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2020-2022 Andre Richter + +//! Peripheral Interrupt Controller Driver. ++//! ++//! # Resources ++//! ++//! - + -+use super::{InterruptController, PendingIRQs, PeripheralIRQ}; ++use super::{PendingIRQs, PeripheralIRQ}; +use crate::{ + bsp::device_driver::common::MMIODerefWrapper, + exception, synchronization, @@ -1569,8 +1572,7 @@ diff -uNr 12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_interru +/// Abstraction for the ReadOnly parts of the associated MMIO registers. +type ReadOnlyRegisters = MMIODerefWrapper; + -+type HandlerTable = -+ [Option; InterruptController::NUM_PERIPHERAL_IRQS]; ++type HandlerTable = [Option; PeripheralIRQ::NUM_TOTAL]; + +//-------------------------------------------------------------------------------------------------- +// Public Definitions @@ -1602,7 +1604,7 @@ diff -uNr 12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_interru + Self { + wo_registers: IRQSafeNullLock::new(WriteOnlyRegisters::new(mmio_start_addr)), + ro_registers: ReadOnlyRegisters::new(mmio_start_addr), -+ handler_table: InitStateLock::new([None; InterruptController::NUM_PERIPHERAL_IRQS]), ++ handler_table: InitStateLock::new([None; PeripheralIRQ::NUM_TOTAL]), + } + } + @@ -1692,7 +1694,7 @@ diff -uNr 12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_interru diff -uNr 12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs --- 12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs +++ 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs -@@ -0,0 +1,134 @@ +@@ -0,0 +1,131 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2020-2022 Andre Richter @@ -1748,16 +1750,13 @@ diff -uNr 12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_interru + type Item = usize; + + fn next(&mut self) -> Option { -+ use core::intrinsics::cttz; -+ -+ let next = cttz(self.bitmask); -+ if next == 64 { ++ if self.bitmask == 0 { + return None; + } + -+ self.bitmask &= !(1 << next); -+ -+ Some(next as usize) ++ let next = self.bitmask.trailing_zeros() as usize; ++ self.bitmask &= self.bitmask.wrapping_sub(1); ++ Some(next) + } +} + @@ -1766,9 +1765,9 @@ diff -uNr 12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_interru +//-------------------------------------------------------------------------------------------------- + +impl InterruptController { -+ const MAX_LOCAL_IRQ_NUMBER: usize = 11; ++ // Restrict to 3 for now. This makes future code for local_ic.rs more straight forward. ++ const MAX_LOCAL_IRQ_NUMBER: usize = 3; + const MAX_PERIPHERAL_IRQ_NUMBER: usize = 63; -+ const NUM_PERIPHERAL_IRQS: usize = Self::MAX_PERIPHERAL_IRQ_NUMBER + 1; + + pub const COMPATIBLE: &'static str = "BCM Interrupt Controller"; + @@ -2230,7 +2229,7 @@ diff -uNr 12_integrated_testing/kernel/src/driver.rs 13_exceptions_part2_periphe diff -uNr 12_integrated_testing/kernel/src/exception/asynchronous.rs 13_exceptions_part2_peripheral_IRQs/kernel/src/exception/asynchronous.rs --- 12_integrated_testing/kernel/src/exception/asynchronous.rs +++ 13_exceptions_part2_peripheral_IRQs/kernel/src/exception/asynchronous.rs -@@ -8,7 +8,149 @@ +@@ -8,7 +8,152 @@ #[path = "../_arch/aarch64/exception/asynchronous.rs"] mod arch_asynchronous; @@ -2343,6 +2342,9 @@ diff -uNr 12_integrated_testing/kernel/src/exception/asynchronous.rs 13_exceptio +} + +impl IRQNumber<{ MAX_INCLUSIVE }> { ++ /// The total number of IRQs this type supports. ++ pub const NUM_TOTAL: usize = MAX_INCLUSIVE + 1; ++ + /// Creates a new instance if number <= MAX_INCLUSIVE. + pub const fn new(number: usize) -> Self { + assert!(number <= MAX_INCLUSIVE); diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/time.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/time.rs index 255a5a45..ad8ba84d 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/time.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/time.rs @@ -42,6 +42,15 @@ static ARCH_TIMER_COUNTER_FREQUENCY: NonZeroU32 = NonZeroU32::MIN; // Private Code //-------------------------------------------------------------------------------------------------- +fn arch_timer_counter_frequency() -> NonZeroU32 { + // Read volatile is needed here to prevent the compiler from optimizing + // ARCH_TIMER_COUNTER_FREQUENCY away. + // + // This is safe, because all the safety requirements as stated in read_volatile()'s + // documentation are fulfilled. + unsafe { core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY) } +} + impl GenericTimerCounterValue { pub const MAX: Self = GenericTimerCounterValue(u64::MAX); } @@ -60,13 +69,7 @@ impl From for Duration { return Duration::ZERO; } - // Read volatile is needed here to prevent the compiler from optimizing - // ARCH_TIMER_COUNTER_FREQUENCY away. - // - // This is safe, because all the safety requirements as stated in read_volatile()'s - // documentation are fulfilled. - let frequency: NonZeroU64 = - unsafe { core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY) }.into(); + let frequency: NonZeroU64 = arch_timer_counter_frequency().into(); // Div implementation for u64 cannot panic. let secs = counter_value.0.div(frequency); @@ -101,10 +104,7 @@ impl TryFrom for GenericTimerCounterValue { return Err("Conversion error. Duration too big"); } - // This is safe, because all the safety requirements as stated in read_volatile()'s - // documentation are fulfilled. - let frequency: u128 = - unsafe { u32::from(core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY)) as u128 }; + let frequency: u128 = u32::from(arch_timer_counter_frequency()) as u128; let duration: u128 = duration.as_nanos(); // This is safe, because frequency can never be greater than u32::MAX, and diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/arm/gicv2.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/arm/gicv2.rs index 03c1fa0f..c810a59a 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/arm/gicv2.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/arm/gicv2.rs @@ -85,7 +85,7 @@ use crate::{bsp, cpu, driver, exception, synchronization, synchronization::InitS // Private Definitions //-------------------------------------------------------------------------------------------------- -type HandlerTable = [Option; GICv2::NUM_IRQS]; +type HandlerTable = [Option; IRQNumber::NUM_TOTAL]; //-------------------------------------------------------------------------------------------------- // Public Definitions @@ -112,7 +112,6 @@ pub struct GICv2 { impl GICv2 { const MAX_IRQ_NUMBER: usize = 300; // Normally 1019, but keep it lower to save some space. - const NUM_IRQS: usize = Self::MAX_IRQ_NUMBER + 1; pub const COMPATIBLE: &'static str = "GICv2 (ARM Generic Interrupt Controller v2)"; @@ -125,7 +124,7 @@ impl GICv2 { Self { gicd: gicd::GICD::new(gicd_mmio_start_addr), gicc: gicc::GICC::new(gicc_mmio_start_addr), - handler_table: InitStateLock::new([None; Self::NUM_IRQS]), + handler_table: InitStateLock::new([None; IRQNumber::NUM_TOTAL]), } } } diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs index d4acd275..a88899c2 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs @@ -53,16 +53,13 @@ impl Iterator for PendingIRQs { type Item = usize; fn next(&mut self) -> Option { - use core::intrinsics::cttz; - - let next = cttz(self.bitmask); - if next == 64 { + if self.bitmask == 0 { return None; } - self.bitmask &= !(1 << next); - - Some(next as usize) + let next = self.bitmask.trailing_zeros() as usize; + self.bitmask &= self.bitmask.wrapping_sub(1); + Some(next) } } @@ -71,9 +68,9 @@ impl Iterator for PendingIRQs { //-------------------------------------------------------------------------------------------------- impl InterruptController { - const MAX_LOCAL_IRQ_NUMBER: usize = 11; + // Restrict to 3 for now. This makes future code for local_ic.rs more straight forward. + const MAX_LOCAL_IRQ_NUMBER: usize = 3; const MAX_PERIPHERAL_IRQ_NUMBER: usize = 63; - const NUM_PERIPHERAL_IRQS: usize = Self::MAX_PERIPHERAL_IRQ_NUMBER + 1; pub const COMPATIBLE: &'static str = "BCM Interrupt Controller"; diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs index 0900635e..90d9dd81 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs @@ -3,8 +3,12 @@ // Copyright (c) 2020-2022 Andre Richter //! Peripheral Interrupt Controller Driver. +//! +//! # Resources +//! +//! - -use super::{InterruptController, PendingIRQs, PeripheralIRQ}; +use super::{PendingIRQs, PeripheralIRQ}; use crate::{ bsp::device_driver::common::MMIODerefWrapper, exception, synchronization, @@ -46,8 +50,7 @@ type WriteOnlyRegisters = MMIODerefWrapper; /// Abstraction for the ReadOnly parts of the associated MMIO registers. type ReadOnlyRegisters = MMIODerefWrapper; -type HandlerTable = - [Option; InterruptController::NUM_PERIPHERAL_IRQS]; +type HandlerTable = [Option; PeripheralIRQ::NUM_TOTAL]; //-------------------------------------------------------------------------------------------------- // Public Definitions @@ -79,7 +82,7 @@ impl PeripheralIC { Self { wo_registers: IRQSafeNullLock::new(WriteOnlyRegisters::new(mmio_start_addr)), ro_registers: ReadOnlyRegisters::new(mmio_start_addr), - handler_table: InitStateLock::new([None; InterruptController::NUM_PERIPHERAL_IRQS]), + handler_table: InitStateLock::new([None; PeripheralIRQ::NUM_TOTAL]), } } diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/exception/asynchronous.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/exception/asynchronous.rs index 31800ffe..d55ce642 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/exception/asynchronous.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/exception/asynchronous.rs @@ -116,6 +116,9 @@ impl<'irq_context> IRQContext<'irq_context> { } impl IRQNumber<{ MAX_INCLUSIVE }> { + /// The total number of IRQs this type supports. + pub const NUM_TOTAL: usize = MAX_INCLUSIVE + 1; + /// Creates a new instance if number <= MAX_INCLUSIVE. pub const fn new(number: usize) -> Self { assert!(number <= MAX_INCLUSIVE); diff --git a/14_virtual_mem_part2_mmio_remap/README.md b/14_virtual_mem_part2_mmio_remap/README.md index 7dc0c7a3..c0db9938 100644 --- a/14_virtual_mem_part2_mmio_remap/README.md +++ b/14_virtual_mem_part2_mmio_remap/README.md @@ -948,7 +948,7 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/arm/g } //-------------------------------------------------------------------------------------------------- -@@ -121,11 +129,16 @@ +@@ -120,11 +128,16 @@ /// # Safety /// /// - The user must ensure to provide a correct MMIO start address. @@ -961,12 +961,12 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/arm/g Self { gicd: gicd::GICD::new(gicd_mmio_start_addr), gicc: gicc::GICC::new(gicc_mmio_start_addr), - handler_table: InitStateLock::new([None; Self::NUM_IRQS]), + handler_table: InitStateLock::new([None; IRQNumber::NUM_TOTAL]), + post_init_callback, } } } -@@ -148,6 +161,8 @@ +@@ -147,6 +160,8 @@ self.gicc.priority_accept_all(); self.gicc.enable(); @@ -1035,8 +1035,8 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/b diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs --- 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs +++ 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs -@@ -7,7 +7,9 @@ - use super::{InterruptController, PendingIRQs, PeripheralIRQ}; +@@ -11,7 +11,9 @@ + use super::{PendingIRQs, PeripheralIRQ}; use crate::{ bsp::device_driver::common::MMIODerefWrapper, - exception, synchronization, @@ -1046,7 +1046,7 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/b synchronization::{IRQSafeNullLock, InitStateLock}, }; use tock_registers::{ -@@ -75,7 +77,7 @@ +@@ -78,7 +80,7 @@ /// # Safety /// /// - The user must ensure to provide a correct MMIO start address. @@ -1079,7 +1079,7 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/b } //-------------------------------------------------------------------------------------------------- -@@ -82,9 +86,13 @@ +@@ -79,9 +83,13 @@ /// # Safety /// /// - The user must ensure to provide a correct MMIO start address. @@ -1094,7 +1094,7 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/b } } } -@@ -97,6 +105,12 @@ +@@ -94,6 +102,12 @@ fn compatible(&self) -> &'static str { Self::COMPATIBLE } @@ -2302,7 +2302,7 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/exception/asynchronous. impl<'irq_context> IRQContext<'irq_context> { /// Creates an IRQContext token. -@@ -148,9 +158,17 @@ +@@ -151,9 +161,17 @@ ret } diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/time.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/time.rs index 255a5a45..ad8ba84d 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/time.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/time.rs @@ -42,6 +42,15 @@ static ARCH_TIMER_COUNTER_FREQUENCY: NonZeroU32 = NonZeroU32::MIN; // Private Code //-------------------------------------------------------------------------------------------------- +fn arch_timer_counter_frequency() -> NonZeroU32 { + // Read volatile is needed here to prevent the compiler from optimizing + // ARCH_TIMER_COUNTER_FREQUENCY away. + // + // This is safe, because all the safety requirements as stated in read_volatile()'s + // documentation are fulfilled. + unsafe { core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY) } +} + impl GenericTimerCounterValue { pub const MAX: Self = GenericTimerCounterValue(u64::MAX); } @@ -60,13 +69,7 @@ impl From for Duration { return Duration::ZERO; } - // Read volatile is needed here to prevent the compiler from optimizing - // ARCH_TIMER_COUNTER_FREQUENCY away. - // - // This is safe, because all the safety requirements as stated in read_volatile()'s - // documentation are fulfilled. - let frequency: NonZeroU64 = - unsafe { core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY) }.into(); + let frequency: NonZeroU64 = arch_timer_counter_frequency().into(); // Div implementation for u64 cannot panic. let secs = counter_value.0.div(frequency); @@ -101,10 +104,7 @@ impl TryFrom for GenericTimerCounterValue { return Err("Conversion error. Duration too big"); } - // This is safe, because all the safety requirements as stated in read_volatile()'s - // documentation are fulfilled. - let frequency: u128 = - unsafe { u32::from(core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY)) as u128 }; + let frequency: u128 = u32::from(arch_timer_counter_frequency()) as u128; let duration: u128 = duration.as_nanos(); // This is safe, because frequency can never be greater than u32::MAX, and diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/arm/gicv2.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/arm/gicv2.rs index e72fde7b..ec65f1b2 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/arm/gicv2.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/arm/gicv2.rs @@ -90,7 +90,7 @@ use crate::{ // Private Definitions //-------------------------------------------------------------------------------------------------- -type HandlerTable = [Option; GICv2::NUM_IRQS]; +type HandlerTable = [Option; IRQNumber::NUM_TOTAL]; //-------------------------------------------------------------------------------------------------- // Public Definitions @@ -120,7 +120,6 @@ pub struct GICv2 { impl GICv2 { const MAX_IRQ_NUMBER: usize = 300; // Normally 1019, but keep it lower to save some space. - const NUM_IRQS: usize = Self::MAX_IRQ_NUMBER + 1; pub const COMPATIBLE: &'static str = "GICv2 (ARM Generic Interrupt Controller v2)"; @@ -137,7 +136,7 @@ impl GICv2 { Self { gicd: gicd::GICD::new(gicd_mmio_start_addr), gicc: gicc::GICC::new(gicc_mmio_start_addr), - handler_table: InitStateLock::new([None; Self::NUM_IRQS]), + handler_table: InitStateLock::new([None; IRQNumber::NUM_TOTAL]), post_init_callback, } } diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs index 4908b8b6..b4dd530d 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs @@ -57,16 +57,13 @@ impl Iterator for PendingIRQs { type Item = usize; fn next(&mut self) -> Option { - use core::intrinsics::cttz; - - let next = cttz(self.bitmask); - if next == 64 { + if self.bitmask == 0 { return None; } - self.bitmask &= !(1 << next); - - Some(next as usize) + let next = self.bitmask.trailing_zeros() as usize; + self.bitmask &= self.bitmask.wrapping_sub(1); + Some(next) } } @@ -75,9 +72,9 @@ impl Iterator for PendingIRQs { //-------------------------------------------------------------------------------------------------- impl InterruptController { - const MAX_LOCAL_IRQ_NUMBER: usize = 11; + // Restrict to 3 for now. This makes future code for local_ic.rs more straight forward. + const MAX_LOCAL_IRQ_NUMBER: usize = 3; const MAX_PERIPHERAL_IRQ_NUMBER: usize = 63; - const NUM_PERIPHERAL_IRQS: usize = Self::MAX_PERIPHERAL_IRQ_NUMBER + 1; pub const COMPATIBLE: &'static str = "BCM Interrupt Controller"; diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs index c9711049..06802d27 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs @@ -3,8 +3,12 @@ // Copyright (c) 2020-2022 Andre Richter //! Peripheral Interrupt Controller Driver. +//! +//! # Resources +//! +//! - -use super::{InterruptController, PendingIRQs, PeripheralIRQ}; +use super::{PendingIRQs, PeripheralIRQ}; use crate::{ bsp::device_driver::common::MMIODerefWrapper, exception, @@ -48,8 +52,7 @@ type WriteOnlyRegisters = MMIODerefWrapper; /// Abstraction for the ReadOnly parts of the associated MMIO registers. type ReadOnlyRegisters = MMIODerefWrapper; -type HandlerTable = - [Option; InterruptController::NUM_PERIPHERAL_IRQS]; +type HandlerTable = [Option; PeripheralIRQ::NUM_TOTAL]; //-------------------------------------------------------------------------------------------------- // Public Definitions @@ -81,7 +84,7 @@ impl PeripheralIC { Self { wo_registers: IRQSafeNullLock::new(WriteOnlyRegisters::new(mmio_start_addr)), ro_registers: ReadOnlyRegisters::new(mmio_start_addr), - handler_table: InitStateLock::new([None; InterruptController::NUM_PERIPHERAL_IRQS]), + handler_table: InitStateLock::new([None; PeripheralIRQ::NUM_TOTAL]), } } diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/exception/asynchronous.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/exception/asynchronous.rs index 3544e621..83ca1aa6 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/exception/asynchronous.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/exception/asynchronous.rs @@ -126,6 +126,9 @@ impl<'irq_context> IRQContext<'irq_context> { } impl IRQNumber<{ MAX_INCLUSIVE }> { + /// The total number of IRQs this type supports. + pub const NUM_TOTAL: usize = MAX_INCLUSIVE + 1; + /// Creates a new instance if number <= MAX_INCLUSIVE. pub const fn new(number: usize) -> Self { assert!(number <= MAX_INCLUSIVE); diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/time.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/time.rs index 255a5a45..ad8ba84d 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/time.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/time.rs @@ -42,6 +42,15 @@ static ARCH_TIMER_COUNTER_FREQUENCY: NonZeroU32 = NonZeroU32::MIN; // Private Code //-------------------------------------------------------------------------------------------------- +fn arch_timer_counter_frequency() -> NonZeroU32 { + // Read volatile is needed here to prevent the compiler from optimizing + // ARCH_TIMER_COUNTER_FREQUENCY away. + // + // This is safe, because all the safety requirements as stated in read_volatile()'s + // documentation are fulfilled. + unsafe { core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY) } +} + impl GenericTimerCounterValue { pub const MAX: Self = GenericTimerCounterValue(u64::MAX); } @@ -60,13 +69,7 @@ impl From for Duration { return Duration::ZERO; } - // Read volatile is needed here to prevent the compiler from optimizing - // ARCH_TIMER_COUNTER_FREQUENCY away. - // - // This is safe, because all the safety requirements as stated in read_volatile()'s - // documentation are fulfilled. - let frequency: NonZeroU64 = - unsafe { core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY) }.into(); + let frequency: NonZeroU64 = arch_timer_counter_frequency().into(); // Div implementation for u64 cannot panic. let secs = counter_value.0.div(frequency); @@ -101,10 +104,7 @@ impl TryFrom for GenericTimerCounterValue { return Err("Conversion error. Duration too big"); } - // This is safe, because all the safety requirements as stated in read_volatile()'s - // documentation are fulfilled. - let frequency: u128 = - unsafe { u32::from(core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY)) as u128 }; + let frequency: u128 = u32::from(arch_timer_counter_frequency()) as u128; let duration: u128 = duration.as_nanos(); // This is safe, because frequency can never be greater than u32::MAX, and diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/arm/gicv2.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/arm/gicv2.rs index e72fde7b..ec65f1b2 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/arm/gicv2.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/arm/gicv2.rs @@ -90,7 +90,7 @@ use crate::{ // Private Definitions //-------------------------------------------------------------------------------------------------- -type HandlerTable = [Option; GICv2::NUM_IRQS]; +type HandlerTable = [Option; IRQNumber::NUM_TOTAL]; //-------------------------------------------------------------------------------------------------- // Public Definitions @@ -120,7 +120,6 @@ pub struct GICv2 { impl GICv2 { const MAX_IRQ_NUMBER: usize = 300; // Normally 1019, but keep it lower to save some space. - const NUM_IRQS: usize = Self::MAX_IRQ_NUMBER + 1; pub const COMPATIBLE: &'static str = "GICv2 (ARM Generic Interrupt Controller v2)"; @@ -137,7 +136,7 @@ impl GICv2 { Self { gicd: gicd::GICD::new(gicd_mmio_start_addr), gicc: gicc::GICC::new(gicc_mmio_start_addr), - handler_table: InitStateLock::new([None; Self::NUM_IRQS]), + handler_table: InitStateLock::new([None; IRQNumber::NUM_TOTAL]), post_init_callback, } } diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs index 4908b8b6..b4dd530d 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs @@ -57,16 +57,13 @@ impl Iterator for PendingIRQs { type Item = usize; fn next(&mut self) -> Option { - use core::intrinsics::cttz; - - let next = cttz(self.bitmask); - if next == 64 { + if self.bitmask == 0 { return None; } - self.bitmask &= !(1 << next); - - Some(next as usize) + let next = self.bitmask.trailing_zeros() as usize; + self.bitmask &= self.bitmask.wrapping_sub(1); + Some(next) } } @@ -75,9 +72,9 @@ impl Iterator for PendingIRQs { //-------------------------------------------------------------------------------------------------- impl InterruptController { - const MAX_LOCAL_IRQ_NUMBER: usize = 11; + // Restrict to 3 for now. This makes future code for local_ic.rs more straight forward. + const MAX_LOCAL_IRQ_NUMBER: usize = 3; const MAX_PERIPHERAL_IRQ_NUMBER: usize = 63; - const NUM_PERIPHERAL_IRQS: usize = Self::MAX_PERIPHERAL_IRQ_NUMBER + 1; pub const COMPATIBLE: &'static str = "BCM Interrupt Controller"; diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs index c9711049..06802d27 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs @@ -3,8 +3,12 @@ // Copyright (c) 2020-2022 Andre Richter //! Peripheral Interrupt Controller Driver. +//! +//! # Resources +//! +//! - -use super::{InterruptController, PendingIRQs, PeripheralIRQ}; +use super::{PendingIRQs, PeripheralIRQ}; use crate::{ bsp::device_driver::common::MMIODerefWrapper, exception, @@ -48,8 +52,7 @@ type WriteOnlyRegisters = MMIODerefWrapper; /// Abstraction for the ReadOnly parts of the associated MMIO registers. type ReadOnlyRegisters = MMIODerefWrapper; -type HandlerTable = - [Option; InterruptController::NUM_PERIPHERAL_IRQS]; +type HandlerTable = [Option; PeripheralIRQ::NUM_TOTAL]; //-------------------------------------------------------------------------------------------------- // Public Definitions @@ -81,7 +84,7 @@ impl PeripheralIC { Self { wo_registers: IRQSafeNullLock::new(WriteOnlyRegisters::new(mmio_start_addr)), ro_registers: ReadOnlyRegisters::new(mmio_start_addr), - handler_table: InitStateLock::new([None; InterruptController::NUM_PERIPHERAL_IRQS]), + handler_table: InitStateLock::new([None; PeripheralIRQ::NUM_TOTAL]), } } diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/exception/asynchronous.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/exception/asynchronous.rs index 3544e621..83ca1aa6 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/exception/asynchronous.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/exception/asynchronous.rs @@ -126,6 +126,9 @@ impl<'irq_context> IRQContext<'irq_context> { } impl IRQNumber<{ MAX_INCLUSIVE }> { + /// The total number of IRQs this type supports. + pub const NUM_TOTAL: usize = MAX_INCLUSIVE + 1; + /// Creates a new instance if number <= MAX_INCLUSIVE. pub const fn new(number: usize) -> Self { assert!(number <= MAX_INCLUSIVE); diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/time.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/time.rs index 255a5a45..ad8ba84d 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/time.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/time.rs @@ -42,6 +42,15 @@ static ARCH_TIMER_COUNTER_FREQUENCY: NonZeroU32 = NonZeroU32::MIN; // Private Code //-------------------------------------------------------------------------------------------------- +fn arch_timer_counter_frequency() -> NonZeroU32 { + // Read volatile is needed here to prevent the compiler from optimizing + // ARCH_TIMER_COUNTER_FREQUENCY away. + // + // This is safe, because all the safety requirements as stated in read_volatile()'s + // documentation are fulfilled. + unsafe { core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY) } +} + impl GenericTimerCounterValue { pub const MAX: Self = GenericTimerCounterValue(u64::MAX); } @@ -60,13 +69,7 @@ impl From for Duration { return Duration::ZERO; } - // Read volatile is needed here to prevent the compiler from optimizing - // ARCH_TIMER_COUNTER_FREQUENCY away. - // - // This is safe, because all the safety requirements as stated in read_volatile()'s - // documentation are fulfilled. - let frequency: NonZeroU64 = - unsafe { core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY) }.into(); + let frequency: NonZeroU64 = arch_timer_counter_frequency().into(); // Div implementation for u64 cannot panic. let secs = counter_value.0.div(frequency); @@ -101,10 +104,7 @@ impl TryFrom for GenericTimerCounterValue { return Err("Conversion error. Duration too big"); } - // This is safe, because all the safety requirements as stated in read_volatile()'s - // documentation are fulfilled. - let frequency: u128 = - unsafe { u32::from(core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY)) as u128 }; + let frequency: u128 = u32::from(arch_timer_counter_frequency()) as u128; let duration: u128 = duration.as_nanos(); // This is safe, because frequency can never be greater than u32::MAX, and diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/arm/gicv2.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/arm/gicv2.rs index e72fde7b..ec65f1b2 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/arm/gicv2.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/arm/gicv2.rs @@ -90,7 +90,7 @@ use crate::{ // Private Definitions //-------------------------------------------------------------------------------------------------- -type HandlerTable = [Option; GICv2::NUM_IRQS]; +type HandlerTable = [Option; IRQNumber::NUM_TOTAL]; //-------------------------------------------------------------------------------------------------- // Public Definitions @@ -120,7 +120,6 @@ pub struct GICv2 { impl GICv2 { const MAX_IRQ_NUMBER: usize = 300; // Normally 1019, but keep it lower to save some space. - const NUM_IRQS: usize = Self::MAX_IRQ_NUMBER + 1; pub const COMPATIBLE: &'static str = "GICv2 (ARM Generic Interrupt Controller v2)"; @@ -137,7 +136,7 @@ impl GICv2 { Self { gicd: gicd::GICD::new(gicd_mmio_start_addr), gicc: gicc::GICC::new(gicc_mmio_start_addr), - handler_table: InitStateLock::new([None; Self::NUM_IRQS]), + handler_table: InitStateLock::new([None; IRQNumber::NUM_TOTAL]), post_init_callback, } } diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs index 4908b8b6..b4dd530d 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs @@ -57,16 +57,13 @@ impl Iterator for PendingIRQs { type Item = usize; fn next(&mut self) -> Option { - use core::intrinsics::cttz; - - let next = cttz(self.bitmask); - if next == 64 { + if self.bitmask == 0 { return None; } - self.bitmask &= !(1 << next); - - Some(next as usize) + let next = self.bitmask.trailing_zeros() as usize; + self.bitmask &= self.bitmask.wrapping_sub(1); + Some(next) } } @@ -75,9 +72,9 @@ impl Iterator for PendingIRQs { //-------------------------------------------------------------------------------------------------- impl InterruptController { - const MAX_LOCAL_IRQ_NUMBER: usize = 11; + // Restrict to 3 for now. This makes future code for local_ic.rs more straight forward. + const MAX_LOCAL_IRQ_NUMBER: usize = 3; const MAX_PERIPHERAL_IRQ_NUMBER: usize = 63; - const NUM_PERIPHERAL_IRQS: usize = Self::MAX_PERIPHERAL_IRQ_NUMBER + 1; pub const COMPATIBLE: &'static str = "BCM Interrupt Controller"; diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs index c9711049..06802d27 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs @@ -3,8 +3,12 @@ // Copyright (c) 2020-2022 Andre Richter //! Peripheral Interrupt Controller Driver. +//! +//! # Resources +//! +//! - -use super::{InterruptController, PendingIRQs, PeripheralIRQ}; +use super::{PendingIRQs, PeripheralIRQ}; use crate::{ bsp::device_driver::common::MMIODerefWrapper, exception, @@ -48,8 +52,7 @@ type WriteOnlyRegisters = MMIODerefWrapper; /// Abstraction for the ReadOnly parts of the associated MMIO registers. type ReadOnlyRegisters = MMIODerefWrapper; -type HandlerTable = - [Option; InterruptController::NUM_PERIPHERAL_IRQS]; +type HandlerTable = [Option; PeripheralIRQ::NUM_TOTAL]; //-------------------------------------------------------------------------------------------------- // Public Definitions @@ -81,7 +84,7 @@ impl PeripheralIC { Self { wo_registers: IRQSafeNullLock::new(WriteOnlyRegisters::new(mmio_start_addr)), ro_registers: ReadOnlyRegisters::new(mmio_start_addr), - handler_table: InitStateLock::new([None; InterruptController::NUM_PERIPHERAL_IRQS]), + handler_table: InitStateLock::new([None; PeripheralIRQ::NUM_TOTAL]), } } diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/exception/asynchronous.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/exception/asynchronous.rs index 3544e621..83ca1aa6 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/exception/asynchronous.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/exception/asynchronous.rs @@ -126,6 +126,9 @@ impl<'irq_context> IRQContext<'irq_context> { } impl IRQNumber<{ MAX_INCLUSIVE }> { + /// The total number of IRQs this type supports. + pub const NUM_TOTAL: usize = MAX_INCLUSIVE + 1; + /// Creates a new instance if number <= MAX_INCLUSIVE. pub const fn new(number: usize) -> Self { assert!(number <= MAX_INCLUSIVE); diff --git a/17_kernel_symbols/README.md b/17_kernel_symbols/README.md index 699cfe2c..e88795ab 100644 --- a/17_kernel_symbols/README.md +++ b/17_kernel_symbols/README.md @@ -168,13 +168,18 @@ fn kernel_symbol_section_virt_start_addr() -> Address { Address::new(unsafe { __kernel_symbols_start.get() as usize }) } +fn num_kernel_symbols() -> usize { + unsafe { + // Read volatile is needed here to prevent the compiler from optimizing NUM_KERNEL_SYMBOLS + // away. + core::ptr::read_volatile(&NUM_KERNEL_SYMBOLS as *const u64) as usize + } +} + fn kernel_symbols_slice() -> &'static [Symbol] { let ptr = kernel_symbol_section_virt_start_addr().as_usize() as *const Symbol; - unsafe { - let num = core::ptr::read_volatile(&NUM_KERNEL_SYMBOLS as *const u64) as usize; - slice::from_raw_parts(ptr, num) - } + unsafe { slice::from_raw_parts(ptr, num_kernel_symbols()) } } ``` @@ -338,7 +343,7 @@ diff -uNr 16_virtual_mem_part4_higher_half_kernel/kernel/src/lib.rs 17_kernel_sy diff -uNr 16_virtual_mem_part4_higher_half_kernel/kernel/src/symbols.rs 17_kernel_symbols/kernel/src/symbols.rs --- 16_virtual_mem_part4_higher_half_kernel/kernel/src/symbols.rs +++ 17_kernel_symbols/kernel/src/symbols.rs -@@ -0,0 +1,83 @@ +@@ -0,0 +1,88 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2022 Andre Richter @@ -375,13 +380,18 @@ diff -uNr 16_virtual_mem_part4_higher_half_kernel/kernel/src/symbols.rs 17_kerne + Address::new(unsafe { __kernel_symbols_start.get() as usize }) +} + ++fn num_kernel_symbols() -> usize { ++ unsafe { ++ // Read volatile is needed here to prevent the compiler from optimizing NUM_KERNEL_SYMBOLS ++ // away. ++ core::ptr::read_volatile(&NUM_KERNEL_SYMBOLS as *const u64) as usize ++ } ++} ++ +fn kernel_symbols_slice() -> &'static [Symbol] { + let ptr = kernel_symbol_section_virt_start_addr().as_usize() as *const Symbol; + -+ unsafe { -+ let num = core::ptr::read_volatile(&NUM_KERNEL_SYMBOLS as *const u64) as usize; -+ slice::from_raw_parts(ptr, num) -+ } ++ unsafe { slice::from_raw_parts(ptr, num_kernel_symbols()) } +} + +//-------------------------------------------------------------------------------------------------- diff --git a/17_kernel_symbols/kernel/src/_arch/aarch64/time.rs b/17_kernel_symbols/kernel/src/_arch/aarch64/time.rs index 255a5a45..ad8ba84d 100644 --- a/17_kernel_symbols/kernel/src/_arch/aarch64/time.rs +++ b/17_kernel_symbols/kernel/src/_arch/aarch64/time.rs @@ -42,6 +42,15 @@ static ARCH_TIMER_COUNTER_FREQUENCY: NonZeroU32 = NonZeroU32::MIN; // Private Code //-------------------------------------------------------------------------------------------------- +fn arch_timer_counter_frequency() -> NonZeroU32 { + // Read volatile is needed here to prevent the compiler from optimizing + // ARCH_TIMER_COUNTER_FREQUENCY away. + // + // This is safe, because all the safety requirements as stated in read_volatile()'s + // documentation are fulfilled. + unsafe { core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY) } +} + impl GenericTimerCounterValue { pub const MAX: Self = GenericTimerCounterValue(u64::MAX); } @@ -60,13 +69,7 @@ impl From for Duration { return Duration::ZERO; } - // Read volatile is needed here to prevent the compiler from optimizing - // ARCH_TIMER_COUNTER_FREQUENCY away. - // - // This is safe, because all the safety requirements as stated in read_volatile()'s - // documentation are fulfilled. - let frequency: NonZeroU64 = - unsafe { core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY) }.into(); + let frequency: NonZeroU64 = arch_timer_counter_frequency().into(); // Div implementation for u64 cannot panic. let secs = counter_value.0.div(frequency); @@ -101,10 +104,7 @@ impl TryFrom for GenericTimerCounterValue { return Err("Conversion error. Duration too big"); } - // This is safe, because all the safety requirements as stated in read_volatile()'s - // documentation are fulfilled. - let frequency: u128 = - unsafe { u32::from(core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY)) as u128 }; + let frequency: u128 = u32::from(arch_timer_counter_frequency()) as u128; let duration: u128 = duration.as_nanos(); // This is safe, because frequency can never be greater than u32::MAX, and diff --git a/17_kernel_symbols/kernel/src/bsp/device_driver/arm/gicv2.rs b/17_kernel_symbols/kernel/src/bsp/device_driver/arm/gicv2.rs index e72fde7b..ec65f1b2 100644 --- a/17_kernel_symbols/kernel/src/bsp/device_driver/arm/gicv2.rs +++ b/17_kernel_symbols/kernel/src/bsp/device_driver/arm/gicv2.rs @@ -90,7 +90,7 @@ use crate::{ // Private Definitions //-------------------------------------------------------------------------------------------------- -type HandlerTable = [Option; GICv2::NUM_IRQS]; +type HandlerTable = [Option; IRQNumber::NUM_TOTAL]; //-------------------------------------------------------------------------------------------------- // Public Definitions @@ -120,7 +120,6 @@ pub struct GICv2 { impl GICv2 { const MAX_IRQ_NUMBER: usize = 300; // Normally 1019, but keep it lower to save some space. - const NUM_IRQS: usize = Self::MAX_IRQ_NUMBER + 1; pub const COMPATIBLE: &'static str = "GICv2 (ARM Generic Interrupt Controller v2)"; @@ -137,7 +136,7 @@ impl GICv2 { Self { gicd: gicd::GICD::new(gicd_mmio_start_addr), gicc: gicc::GICC::new(gicc_mmio_start_addr), - handler_table: InitStateLock::new([None; Self::NUM_IRQS]), + handler_table: InitStateLock::new([None; IRQNumber::NUM_TOTAL]), post_init_callback, } } diff --git a/17_kernel_symbols/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs b/17_kernel_symbols/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs index 4908b8b6..b4dd530d 100644 --- a/17_kernel_symbols/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs +++ b/17_kernel_symbols/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs @@ -57,16 +57,13 @@ impl Iterator for PendingIRQs { type Item = usize; fn next(&mut self) -> Option { - use core::intrinsics::cttz; - - let next = cttz(self.bitmask); - if next == 64 { + if self.bitmask == 0 { return None; } - self.bitmask &= !(1 << next); - - Some(next as usize) + let next = self.bitmask.trailing_zeros() as usize; + self.bitmask &= self.bitmask.wrapping_sub(1); + Some(next) } } @@ -75,9 +72,9 @@ impl Iterator for PendingIRQs { //-------------------------------------------------------------------------------------------------- impl InterruptController { - const MAX_LOCAL_IRQ_NUMBER: usize = 11; + // Restrict to 3 for now. This makes future code for local_ic.rs more straight forward. + const MAX_LOCAL_IRQ_NUMBER: usize = 3; const MAX_PERIPHERAL_IRQ_NUMBER: usize = 63; - const NUM_PERIPHERAL_IRQS: usize = Self::MAX_PERIPHERAL_IRQ_NUMBER + 1; pub const COMPATIBLE: &'static str = "BCM Interrupt Controller"; diff --git a/17_kernel_symbols/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs b/17_kernel_symbols/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs index c9711049..06802d27 100644 --- a/17_kernel_symbols/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs +++ b/17_kernel_symbols/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs @@ -3,8 +3,12 @@ // Copyright (c) 2020-2022 Andre Richter //! Peripheral Interrupt Controller Driver. +//! +//! # Resources +//! +//! - -use super::{InterruptController, PendingIRQs, PeripheralIRQ}; +use super::{PendingIRQs, PeripheralIRQ}; use crate::{ bsp::device_driver::common::MMIODerefWrapper, exception, @@ -48,8 +52,7 @@ type WriteOnlyRegisters = MMIODerefWrapper; /// Abstraction for the ReadOnly parts of the associated MMIO registers. type ReadOnlyRegisters = MMIODerefWrapper; -type HandlerTable = - [Option; InterruptController::NUM_PERIPHERAL_IRQS]; +type HandlerTable = [Option; PeripheralIRQ::NUM_TOTAL]; //-------------------------------------------------------------------------------------------------- // Public Definitions @@ -81,7 +84,7 @@ impl PeripheralIC { Self { wo_registers: IRQSafeNullLock::new(WriteOnlyRegisters::new(mmio_start_addr)), ro_registers: ReadOnlyRegisters::new(mmio_start_addr), - handler_table: InitStateLock::new([None; InterruptController::NUM_PERIPHERAL_IRQS]), + handler_table: InitStateLock::new([None; PeripheralIRQ::NUM_TOTAL]), } } diff --git a/17_kernel_symbols/kernel/src/exception/asynchronous.rs b/17_kernel_symbols/kernel/src/exception/asynchronous.rs index 3544e621..83ca1aa6 100644 --- a/17_kernel_symbols/kernel/src/exception/asynchronous.rs +++ b/17_kernel_symbols/kernel/src/exception/asynchronous.rs @@ -126,6 +126,9 @@ impl<'irq_context> IRQContext<'irq_context> { } impl IRQNumber<{ MAX_INCLUSIVE }> { + /// The total number of IRQs this type supports. + pub const NUM_TOTAL: usize = MAX_INCLUSIVE + 1; + /// Creates a new instance if number <= MAX_INCLUSIVE. pub const fn new(number: usize) -> Self { assert!(number <= MAX_INCLUSIVE); diff --git a/17_kernel_symbols/kernel/src/symbols.rs b/17_kernel_symbols/kernel/src/symbols.rs index 7f439ce2..680b8eaf 100644 --- a/17_kernel_symbols/kernel/src/symbols.rs +++ b/17_kernel_symbols/kernel/src/symbols.rs @@ -34,13 +34,18 @@ fn kernel_symbol_section_virt_start_addr() -> Address { Address::new(unsafe { __kernel_symbols_start.get() as usize }) } +fn num_kernel_symbols() -> usize { + unsafe { + // Read volatile is needed here to prevent the compiler from optimizing NUM_KERNEL_SYMBOLS + // away. + core::ptr::read_volatile(&NUM_KERNEL_SYMBOLS as *const u64) as usize + } +} + fn kernel_symbols_slice() -> &'static [Symbol] { let ptr = kernel_symbol_section_virt_start_addr().as_usize() as *const Symbol; - unsafe { - let num = core::ptr::read_volatile(&NUM_KERNEL_SYMBOLS as *const u64) as usize; - slice::from_raw_parts(ptr, num) - } + unsafe { slice::from_raw_parts(ptr, num_kernel_symbols()) } } //-------------------------------------------------------------------------------------------------- diff --git a/18_backtrace/kernel/src/_arch/aarch64/time.rs b/18_backtrace/kernel/src/_arch/aarch64/time.rs index 255a5a45..ad8ba84d 100644 --- a/18_backtrace/kernel/src/_arch/aarch64/time.rs +++ b/18_backtrace/kernel/src/_arch/aarch64/time.rs @@ -42,6 +42,15 @@ static ARCH_TIMER_COUNTER_FREQUENCY: NonZeroU32 = NonZeroU32::MIN; // Private Code //-------------------------------------------------------------------------------------------------- +fn arch_timer_counter_frequency() -> NonZeroU32 { + // Read volatile is needed here to prevent the compiler from optimizing + // ARCH_TIMER_COUNTER_FREQUENCY away. + // + // This is safe, because all the safety requirements as stated in read_volatile()'s + // documentation are fulfilled. + unsafe { core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY) } +} + impl GenericTimerCounterValue { pub const MAX: Self = GenericTimerCounterValue(u64::MAX); } @@ -60,13 +69,7 @@ impl From for Duration { return Duration::ZERO; } - // Read volatile is needed here to prevent the compiler from optimizing - // ARCH_TIMER_COUNTER_FREQUENCY away. - // - // This is safe, because all the safety requirements as stated in read_volatile()'s - // documentation are fulfilled. - let frequency: NonZeroU64 = - unsafe { core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY) }.into(); + let frequency: NonZeroU64 = arch_timer_counter_frequency().into(); // Div implementation for u64 cannot panic. let secs = counter_value.0.div(frequency); @@ -101,10 +104,7 @@ impl TryFrom for GenericTimerCounterValue { return Err("Conversion error. Duration too big"); } - // This is safe, because all the safety requirements as stated in read_volatile()'s - // documentation are fulfilled. - let frequency: u128 = - unsafe { u32::from(core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY)) as u128 }; + let frequency: u128 = u32::from(arch_timer_counter_frequency()) as u128; let duration: u128 = duration.as_nanos(); // This is safe, because frequency can never be greater than u32::MAX, and diff --git a/18_backtrace/kernel/src/bsp/device_driver/arm/gicv2.rs b/18_backtrace/kernel/src/bsp/device_driver/arm/gicv2.rs index e72fde7b..ec65f1b2 100644 --- a/18_backtrace/kernel/src/bsp/device_driver/arm/gicv2.rs +++ b/18_backtrace/kernel/src/bsp/device_driver/arm/gicv2.rs @@ -90,7 +90,7 @@ use crate::{ // Private Definitions //-------------------------------------------------------------------------------------------------- -type HandlerTable = [Option; GICv2::NUM_IRQS]; +type HandlerTable = [Option; IRQNumber::NUM_TOTAL]; //-------------------------------------------------------------------------------------------------- // Public Definitions @@ -120,7 +120,6 @@ pub struct GICv2 { impl GICv2 { const MAX_IRQ_NUMBER: usize = 300; // Normally 1019, but keep it lower to save some space. - const NUM_IRQS: usize = Self::MAX_IRQ_NUMBER + 1; pub const COMPATIBLE: &'static str = "GICv2 (ARM Generic Interrupt Controller v2)"; @@ -137,7 +136,7 @@ impl GICv2 { Self { gicd: gicd::GICD::new(gicd_mmio_start_addr), gicc: gicc::GICC::new(gicc_mmio_start_addr), - handler_table: InitStateLock::new([None; Self::NUM_IRQS]), + handler_table: InitStateLock::new([None; IRQNumber::NUM_TOTAL]), post_init_callback, } } diff --git a/18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs b/18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs index 4908b8b6..b4dd530d 100644 --- a/18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs +++ b/18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs @@ -57,16 +57,13 @@ impl Iterator for PendingIRQs { type Item = usize; fn next(&mut self) -> Option { - use core::intrinsics::cttz; - - let next = cttz(self.bitmask); - if next == 64 { + if self.bitmask == 0 { return None; } - self.bitmask &= !(1 << next); - - Some(next as usize) + let next = self.bitmask.trailing_zeros() as usize; + self.bitmask &= self.bitmask.wrapping_sub(1); + Some(next) } } @@ -75,9 +72,9 @@ impl Iterator for PendingIRQs { //-------------------------------------------------------------------------------------------------- impl InterruptController { - const MAX_LOCAL_IRQ_NUMBER: usize = 11; + // Restrict to 3 for now. This makes future code for local_ic.rs more straight forward. + const MAX_LOCAL_IRQ_NUMBER: usize = 3; const MAX_PERIPHERAL_IRQ_NUMBER: usize = 63; - const NUM_PERIPHERAL_IRQS: usize = Self::MAX_PERIPHERAL_IRQ_NUMBER + 1; pub const COMPATIBLE: &'static str = "BCM Interrupt Controller"; diff --git a/18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs b/18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs index c9711049..06802d27 100644 --- a/18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs +++ b/18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs @@ -3,8 +3,12 @@ // Copyright (c) 2020-2022 Andre Richter //! Peripheral Interrupt Controller Driver. +//! +//! # Resources +//! +//! - -use super::{InterruptController, PendingIRQs, PeripheralIRQ}; +use super::{PendingIRQs, PeripheralIRQ}; use crate::{ bsp::device_driver::common::MMIODerefWrapper, exception, @@ -48,8 +52,7 @@ type WriteOnlyRegisters = MMIODerefWrapper; /// Abstraction for the ReadOnly parts of the associated MMIO registers. type ReadOnlyRegisters = MMIODerefWrapper; -type HandlerTable = - [Option; InterruptController::NUM_PERIPHERAL_IRQS]; +type HandlerTable = [Option; PeripheralIRQ::NUM_TOTAL]; //-------------------------------------------------------------------------------------------------- // Public Definitions @@ -81,7 +84,7 @@ impl PeripheralIC { Self { wo_registers: IRQSafeNullLock::new(WriteOnlyRegisters::new(mmio_start_addr)), ro_registers: ReadOnlyRegisters::new(mmio_start_addr), - handler_table: InitStateLock::new([None; InterruptController::NUM_PERIPHERAL_IRQS]), + handler_table: InitStateLock::new([None; PeripheralIRQ::NUM_TOTAL]), } } diff --git a/18_backtrace/kernel/src/exception/asynchronous.rs b/18_backtrace/kernel/src/exception/asynchronous.rs index 3544e621..83ca1aa6 100644 --- a/18_backtrace/kernel/src/exception/asynchronous.rs +++ b/18_backtrace/kernel/src/exception/asynchronous.rs @@ -126,6 +126,9 @@ impl<'irq_context> IRQContext<'irq_context> { } impl IRQNumber<{ MAX_INCLUSIVE }> { + /// The total number of IRQs this type supports. + pub const NUM_TOTAL: usize = MAX_INCLUSIVE + 1; + /// Creates a new instance if number <= MAX_INCLUSIVE. pub const fn new(number: usize) -> Self { assert!(number <= MAX_INCLUSIVE); diff --git a/18_backtrace/kernel/src/symbols.rs b/18_backtrace/kernel/src/symbols.rs index 7f439ce2..680b8eaf 100644 --- a/18_backtrace/kernel/src/symbols.rs +++ b/18_backtrace/kernel/src/symbols.rs @@ -34,13 +34,18 @@ fn kernel_symbol_section_virt_start_addr() -> Address { Address::new(unsafe { __kernel_symbols_start.get() as usize }) } +fn num_kernel_symbols() -> usize { + unsafe { + // Read volatile is needed here to prevent the compiler from optimizing NUM_KERNEL_SYMBOLS + // away. + core::ptr::read_volatile(&NUM_KERNEL_SYMBOLS as *const u64) as usize + } +} + fn kernel_symbols_slice() -> &'static [Symbol] { let ptr = kernel_symbol_section_virt_start_addr().as_usize() as *const Symbol; - unsafe { - let num = core::ptr::read_volatile(&NUM_KERNEL_SYMBOLS as *const u64) as usize; - slice::from_raw_parts(ptr, num) - } + unsafe { slice::from_raw_parts(ptr, num_kernel_symbols()) } } //-------------------------------------------------------------------------------------------------- diff --git a/19_kernel_heap/README.md b/19_kernel_heap/README.md index 11417c2f..b1463fc5 100644 --- a/19_kernel_heap/README.md +++ b/19_kernel_heap/README.md @@ -298,57 +298,44 @@ diff -uNr 18_backtrace/kernel/src/bsp/device_driver/arm/gicv2.rs 19_kernel_heap/ // Private Definitions //-------------------------------------------------------------------------------------------------- --type HandlerTable = [Option; GICv2::NUM_IRQS]; +-type HandlerTable = [Option; IRQNumber::NUM_TOTAL]; +type HandlerTable = Vec>; //-------------------------------------------------------------------------------------------------- // Public Definitions -@@ -119,8 +120,7 @@ +@@ -119,7 +120,7 @@ //-------------------------------------------------------------------------------------------------- impl GICv2 { - const MAX_IRQ_NUMBER: usize = 300; // Normally 1019, but keep it lower to save some space. -- const NUM_IRQS: usize = Self::MAX_IRQ_NUMBER + 1; + const MAX_IRQ_NUMBER: usize = 1019; pub const COMPATIBLE: &'static str = "GICv2 (ARM Generic Interrupt Controller v2)"; -@@ -137,7 +137,7 @@ +@@ -136,7 +137,7 @@ Self { gicd: gicd::GICD::new(gicd_mmio_start_addr), gicc: gicc::GICC::new(gicc_mmio_start_addr), -- handler_table: InitStateLock::new([None; Self::NUM_IRQS]), +- handler_table: InitStateLock::new([None; IRQNumber::NUM_TOTAL]), + handler_table: InitStateLock::new(Vec::new()), post_init_callback, } } -@@ -178,6 +178,12 @@ - self.handler_table.write(|table| { - let irq_number = irq_number.get(); - -+ if table.len() < irq_number { -+ // IRQDescriptor has an integrated range sanity check on construction, so this -+ // vector can't grow arbitrarily big. -+ table.resize(irq_number + 1, None); -+ } +@@ -153,6 +154,9 @@ + } + + unsafe fn init(&self) -> Result<(), &'static str> { ++ self.handler_table ++ .write(|table| table.resize(IRQNumber::NUM_TOTAL, None)); + - if table[irq_number].is_some() { - return Err("IRQ handler already registered"); - } + if bsp::cpu::BOOT_CORE_ID == cpu::smp::core_id() { + self.gicd.boot_core_init(); + } diff -uNr 18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs 19_kernel_heap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs --- 18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs +++ 19_kernel_heap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs -@@ -4,7 +4,7 @@ - - //! Peripheral Interrupt Controller Driver. - --use super::{InterruptController, PendingIRQs, PeripheralIRQ}; -+use super::{PendingIRQs, PeripheralIRQ}; - use crate::{ - bsp::device_driver::common::MMIODerefWrapper, - exception, -@@ -12,6 +12,7 @@ +@@ -16,6 +16,7 @@ synchronization, synchronization::{IRQSafeNullLock, InitStateLock}, }; @@ -356,50 +343,46 @@ diff -uNr 18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_contro use tock_registers::{ interfaces::{Readable, Writeable}, register_structs, -@@ -48,8 +49,7 @@ +@@ -52,7 +53,7 @@ /// Abstraction for the ReadOnly parts of the associated MMIO registers. type ReadOnlyRegisters = MMIODerefWrapper; --type HandlerTable = -- [Option; InterruptController::NUM_PERIPHERAL_IRQS]; +-type HandlerTable = [Option; PeripheralIRQ::NUM_TOTAL]; +type HandlerTable = Vec>; //-------------------------------------------------------------------------------------------------- // Public Definitions -@@ -81,7 +81,7 @@ +@@ -84,10 +85,16 @@ Self { wo_registers: IRQSafeNullLock::new(WriteOnlyRegisters::new(mmio_start_addr)), ro_registers: ReadOnlyRegisters::new(mmio_start_addr), -- handler_table: InitStateLock::new([None; InterruptController::NUM_PERIPHERAL_IRQS]), +- handler_table: InitStateLock::new([None; PeripheralIRQ::NUM_TOTAL]), + handler_table: InitStateLock::new(Vec::new()), } } -@@ -110,6 +110,12 @@ - self.handler_table.write(|table| { - let irq_number = irq.get(); - -+ if table.len() < irq_number { -+ // IRQDescriptor has an integrated range sanity check on construction, so this -+ // vector can't grow arbitrarily big. -+ table.resize(irq_number + 1, None); -+ } ++ /// Called by the kernel to bring up the device. ++ pub fn init(&self) { ++ self.handler_table ++ .write(|table| table.resize(PeripheralIRQ::NUM_TOTAL, None)); ++ } + - if table[irq_number].is_some() { - return Err("IRQ handler already registered"); - } + /// Query the list of pending IRQs. + fn pending_irqs(&self) -> PendingIRQs { + let pending_mask: u64 = (u64::from(self.ro_registers.PENDING_2.get()) << 32) diff -uNr 18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs 19_kernel_heap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs --- 18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs +++ 19_kernel_heap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs -@@ -77,7 +77,6 @@ - impl InterruptController { - const MAX_LOCAL_IRQ_NUMBER: usize = 11; - const MAX_PERIPHERAL_IRQ_NUMBER: usize = 63; -- const NUM_PERIPHERAL_IRQS: usize = Self::MAX_PERIPHERAL_IRQ_NUMBER + 1; +@@ -104,6 +104,8 @@ + } - pub const COMPATIBLE: &'static str = "BCM Interrupt Controller"; + unsafe fn init(&self) -> Result<(), &'static str> { ++ self.periph.init(); ++ + (self.post_init_callback)(); + Ok(()) diff -uNr 18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs 19_kernel_heap/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs --- 18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs diff --git a/19_kernel_heap/kernel/src/_arch/aarch64/time.rs b/19_kernel_heap/kernel/src/_arch/aarch64/time.rs index 255a5a45..ad8ba84d 100644 --- a/19_kernel_heap/kernel/src/_arch/aarch64/time.rs +++ b/19_kernel_heap/kernel/src/_arch/aarch64/time.rs @@ -42,6 +42,15 @@ static ARCH_TIMER_COUNTER_FREQUENCY: NonZeroU32 = NonZeroU32::MIN; // Private Code //-------------------------------------------------------------------------------------------------- +fn arch_timer_counter_frequency() -> NonZeroU32 { + // Read volatile is needed here to prevent the compiler from optimizing + // ARCH_TIMER_COUNTER_FREQUENCY away. + // + // This is safe, because all the safety requirements as stated in read_volatile()'s + // documentation are fulfilled. + unsafe { core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY) } +} + impl GenericTimerCounterValue { pub const MAX: Self = GenericTimerCounterValue(u64::MAX); } @@ -60,13 +69,7 @@ impl From for Duration { return Duration::ZERO; } - // Read volatile is needed here to prevent the compiler from optimizing - // ARCH_TIMER_COUNTER_FREQUENCY away. - // - // This is safe, because all the safety requirements as stated in read_volatile()'s - // documentation are fulfilled. - let frequency: NonZeroU64 = - unsafe { core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY) }.into(); + let frequency: NonZeroU64 = arch_timer_counter_frequency().into(); // Div implementation for u64 cannot panic. let secs = counter_value.0.div(frequency); @@ -101,10 +104,7 @@ impl TryFrom for GenericTimerCounterValue { return Err("Conversion error. Duration too big"); } - // This is safe, because all the safety requirements as stated in read_volatile()'s - // documentation are fulfilled. - let frequency: u128 = - unsafe { u32::from(core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY)) as u128 }; + let frequency: u128 = u32::from(arch_timer_counter_frequency()) as u128; let duration: u128 = duration.as_nanos(); // This is safe, because frequency can never be greater than u32::MAX, and diff --git a/19_kernel_heap/kernel/src/bsp/device_driver/arm/gicv2.rs b/19_kernel_heap/kernel/src/bsp/device_driver/arm/gicv2.rs index cb7c69ee..69ba8513 100644 --- a/19_kernel_heap/kernel/src/bsp/device_driver/arm/gicv2.rs +++ b/19_kernel_heap/kernel/src/bsp/device_driver/arm/gicv2.rs @@ -154,6 +154,9 @@ impl driver::interface::DeviceDriver for GICv2 { } unsafe fn init(&self) -> Result<(), &'static str> { + self.handler_table + .write(|table| table.resize(IRQNumber::NUM_TOTAL, None)); + if bsp::cpu::BOOT_CORE_ID == cpu::smp::core_id() { self.gicd.boot_core_init(); } @@ -178,12 +181,6 @@ impl exception::asynchronous::interface::IRQManager for GICv2 { self.handler_table.write(|table| { let irq_number = irq_number.get(); - if table.len() < irq_number { - // IRQDescriptor has an integrated range sanity check on construction, so this - // vector can't grow arbitrarily big. - table.resize(irq_number + 1, None); - } - if table[irq_number].is_some() { return Err("IRQ handler already registered"); } diff --git a/19_kernel_heap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs b/19_kernel_heap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs index a93b0bc9..658d3705 100644 --- a/19_kernel_heap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs +++ b/19_kernel_heap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs @@ -57,16 +57,13 @@ impl Iterator for PendingIRQs { type Item = usize; fn next(&mut self) -> Option { - use core::intrinsics::cttz; - - let next = cttz(self.bitmask); - if next == 64 { + if self.bitmask == 0 { return None; } - self.bitmask &= !(1 << next); - - Some(next as usize) + let next = self.bitmask.trailing_zeros() as usize; + self.bitmask &= self.bitmask.wrapping_sub(1); + Some(next) } } @@ -75,7 +72,8 @@ impl Iterator for PendingIRQs { //-------------------------------------------------------------------------------------------------- impl InterruptController { - const MAX_LOCAL_IRQ_NUMBER: usize = 11; + // Restrict to 3 for now. This makes future code for local_ic.rs more straight forward. + const MAX_LOCAL_IRQ_NUMBER: usize = 3; const MAX_PERIPHERAL_IRQ_NUMBER: usize = 63; pub const COMPATIBLE: &'static str = "BCM Interrupt Controller"; @@ -106,6 +104,8 @@ impl driver::interface::DeviceDriver for InterruptController { } unsafe fn init(&self) -> Result<(), &'static str> { + self.periph.init(); + (self.post_init_callback)(); Ok(()) diff --git a/19_kernel_heap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs b/19_kernel_heap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs index 65a9e7a0..90b56378 100644 --- a/19_kernel_heap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs +++ b/19_kernel_heap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs @@ -3,6 +3,10 @@ // Copyright (c) 2020-2022 Andre Richter //! Peripheral Interrupt Controller Driver. +//! +//! # Resources +//! +//! - use super::{PendingIRQs, PeripheralIRQ}; use crate::{ @@ -85,6 +89,12 @@ impl PeripheralIC { } } + /// Called by the kernel to bring up the device. + pub fn init(&self) { + self.handler_table + .write(|table| table.resize(PeripheralIRQ::NUM_TOTAL, None)); + } + /// Query the list of pending IRQs. fn pending_irqs(&self) -> PendingIRQs { let pending_mask: u64 = (u64::from(self.ro_registers.PENDING_2.get()) << 32) @@ -110,12 +120,6 @@ impl exception::asynchronous::interface::IRQManager for PeripheralIC { self.handler_table.write(|table| { let irq_number = irq.get(); - if table.len() < irq_number { - // IRQDescriptor has an integrated range sanity check on construction, so this - // vector can't grow arbitrarily big. - table.resize(irq_number + 1, None); - } - if table[irq_number].is_some() { return Err("IRQ handler already registered"); } diff --git a/19_kernel_heap/kernel/src/exception/asynchronous.rs b/19_kernel_heap/kernel/src/exception/asynchronous.rs index 3544e621..83ca1aa6 100644 --- a/19_kernel_heap/kernel/src/exception/asynchronous.rs +++ b/19_kernel_heap/kernel/src/exception/asynchronous.rs @@ -126,6 +126,9 @@ impl<'irq_context> IRQContext<'irq_context> { } impl IRQNumber<{ MAX_INCLUSIVE }> { + /// The total number of IRQs this type supports. + pub const NUM_TOTAL: usize = MAX_INCLUSIVE + 1; + /// Creates a new instance if number <= MAX_INCLUSIVE. pub const fn new(number: usize) -> Self { assert!(number <= MAX_INCLUSIVE); diff --git a/19_kernel_heap/kernel/src/symbols.rs b/19_kernel_heap/kernel/src/symbols.rs index 7f439ce2..680b8eaf 100644 --- a/19_kernel_heap/kernel/src/symbols.rs +++ b/19_kernel_heap/kernel/src/symbols.rs @@ -34,13 +34,18 @@ fn kernel_symbol_section_virt_start_addr() -> Address { Address::new(unsafe { __kernel_symbols_start.get() as usize }) } +fn num_kernel_symbols() -> usize { + unsafe { + // Read volatile is needed here to prevent the compiler from optimizing NUM_KERNEL_SYMBOLS + // away. + core::ptr::read_volatile(&NUM_KERNEL_SYMBOLS as *const u64) as usize + } +} + fn kernel_symbols_slice() -> &'static [Symbol] { let ptr = kernel_symbol_section_virt_start_addr().as_usize() as *const Symbol; - unsafe { - let num = core::ptr::read_volatile(&NUM_KERNEL_SYMBOLS as *const u64) as usize; - slice::from_raw_parts(ptr, num) - } + unsafe { slice::from_raw_parts(ptr, num_kernel_symbols()) } } //-------------------------------------------------------------------------------------------------- diff --git a/X1_JTAG_boot/src/_arch/aarch64/time.rs b/X1_JTAG_boot/src/_arch/aarch64/time.rs index 3d3a20d7..54db51c3 100644 --- a/X1_JTAG_boot/src/_arch/aarch64/time.rs +++ b/X1_JTAG_boot/src/_arch/aarch64/time.rs @@ -43,6 +43,15 @@ static ARCH_TIMER_COUNTER_FREQUENCY: NonZeroU32 = NonZeroU32::MIN; // Private Code //-------------------------------------------------------------------------------------------------- +fn arch_timer_counter_frequency() -> NonZeroU32 { + // Read volatile is needed here to prevent the compiler from optimizing + // ARCH_TIMER_COUNTER_FREQUENCY away. + // + // This is safe, because all the safety requirements as stated in read_volatile()'s + // documentation are fulfilled. + unsafe { core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY) } +} + impl GenericTimerCounterValue { pub const MAX: Self = GenericTimerCounterValue(u64::MAX); } @@ -61,13 +70,7 @@ impl From for Duration { return Duration::ZERO; } - // Read volatile is needed here to prevent the compiler from optimizing - // ARCH_TIMER_COUNTER_FREQUENCY away. - // - // This is safe, because all the safety requirements as stated in read_volatile()'s - // documentation are fulfilled. - let frequency: NonZeroU64 = - unsafe { core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY) }.into(); + let frequency: NonZeroU64 = arch_timer_counter_frequency().into(); // Div implementation for u64 cannot panic. let secs = counter_value.0.div(frequency); @@ -102,10 +105,7 @@ impl TryFrom for GenericTimerCounterValue { return Err("Conversion error. Duration too big"); } - // This is safe, because all the safety requirements as stated in read_volatile()'s - // documentation are fulfilled. - let frequency: u128 = - unsafe { u32::from(core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY)) as u128 }; + let frequency: u128 = u32::from(arch_timer_counter_frequency()) as u128; let duration: u128 = duration.as_nanos(); // This is safe, because frequency can never be greater than u32::MAX, and From 7014c0cdfd6c5bff4cb5a6267ae03e2186cf4467 Mon Sep 17 00:00:00 2001 From: Andre Richter Date: Mon, 26 Sep 2022 23:15:07 +0200 Subject: [PATCH 56/75] Bump dependencies --- 02_runtime_init/Cargo.lock | 8 ++++---- 02_runtime_init/Cargo.toml | 2 +- 02_runtime_init/README.md | 2 +- 03_hacky_hello_world/Cargo.lock | 8 ++++---- 03_hacky_hello_world/Cargo.toml | 2 +- 04_safe_globals/Cargo.lock | 8 ++++---- 04_safe_globals/Cargo.toml | 2 +- 05_drivers_gpio_uart/Cargo.lock | 8 ++++---- 05_drivers_gpio_uart/Cargo.toml | 4 ++-- 05_drivers_gpio_uart/README.md | 4 ++-- 06_uart_chainloader/Cargo.lock | 8 ++++---- 06_uart_chainloader/Cargo.toml | 4 ++-- 06_uart_chainloader/demo_payload_rpi3.img | Bin 7648 -> 7648 bytes 06_uart_chainloader/demo_payload_rpi4.img | Bin 7576 -> 7584 bytes 07_timestamps/Cargo.lock | 8 ++++---- 07_timestamps/Cargo.toml | 4 ++-- 07_timestamps/README.md | 2 +- 07_timestamps/src/_arch/aarch64/time.rs | 2 +- 08_hw_debug_JTAG/Cargo.lock | 8 ++++---- 08_hw_debug_JTAG/Cargo.toml | 4 ++-- 08_hw_debug_JTAG/src/_arch/aarch64/time.rs | 2 +- 09_privilege_level/Cargo.lock | 8 ++++---- 09_privilege_level/Cargo.toml | 4 ++-- 09_privilege_level/src/_arch/aarch64/time.rs | 2 +- .../Cargo.lock | 8 ++++---- .../Cargo.toml | 4 ++-- .../src/_arch/aarch64/time.rs | 2 +- 11_exceptions_part1_groundwork/Cargo.lock | 8 ++++---- 11_exceptions_part1_groundwork/Cargo.toml | 4 ++-- .../src/_arch/aarch64/time.rs | 2 +- 12_integrated_testing/Cargo.lock | 16 ++++++++-------- 12_integrated_testing/kernel/Cargo.toml | 4 ++-- .../kernel/src/_arch/aarch64/time.rs | 2 +- .../Cargo.lock | 16 ++++++++-------- 13_exceptions_part2_peripheral_IRQs/README.md | 12 ++++++------ .../kernel/Cargo.toml | 4 ++-- .../kernel/src/_arch/aarch64/time.rs | 2 +- .../src/bsp/device_driver/arm/gicv2/gicd.rs | 6 +++--- 14_virtual_mem_part2_mmio_remap/Cargo.lock | 16 ++++++++-------- .../kernel/Cargo.toml | 4 ++-- .../kernel/src/_arch/aarch64/time.rs | 2 +- .../src/bsp/device_driver/arm/gicv2/gicd.rs | 6 +++--- .../Cargo.lock | 16 ++++++++-------- .../kernel/Cargo.toml | 4 ++-- .../kernel/src/_arch/aarch64/time.rs | 2 +- .../src/bsp/device_driver/arm/gicv2/gicd.rs | 6 +++--- .../Cargo.lock | 16 ++++++++-------- .../kernel/Cargo.toml | 4 ++-- .../kernel/src/_arch/aarch64/time.rs | 2 +- .../src/bsp/device_driver/arm/gicv2/gicd.rs | 6 +++--- 17_kernel_symbols/Cargo.lock | 16 ++++++++-------- 17_kernel_symbols/README.md | 2 +- 17_kernel_symbols/kernel/Cargo.toml | 4 ++-- .../kernel/src/_arch/aarch64/time.rs | 2 +- .../src/bsp/device_driver/arm/gicv2/gicd.rs | 6 +++--- 18_backtrace/Cargo.lock | 16 ++++++++-------- 18_backtrace/kernel/Cargo.toml | 4 ++-- 18_backtrace/kernel/src/_arch/aarch64/time.rs | 2 +- .../src/bsp/device_driver/arm/gicv2/gicd.rs | 6 +++--- 19_kernel_heap/Cargo.lock | 16 ++++++++-------- 19_kernel_heap/README.md | 2 +- 19_kernel_heap/kernel/Cargo.toml | 4 ++-- .../kernel/src/_arch/aarch64/time.rs | 2 +- .../src/bsp/device_driver/arm/gicv2/gicd.rs | 6 +++--- X1_JTAG_boot/Cargo.lock | 8 ++++---- X1_JTAG_boot/Cargo.toml | 4 ++-- X1_JTAG_boot/jtag_boot_rpi3.img | Bin 8656 -> 8648 bytes X1_JTAG_boot/jtag_boot_rpi4.img | Bin 7752 -> 7744 bytes X1_JTAG_boot/src/_arch/aarch64/time.rs | 2 +- 69 files changed, 190 insertions(+), 190 deletions(-) diff --git a/02_runtime_init/Cargo.lock b/02_runtime_init/Cargo.lock index bae18da0..17e64197 100644 --- a/02_runtime_init/Cargo.lock +++ b/02_runtime_init/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "cortex-a" -version = "7.5.0" +version = "8.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdecfbb28672ad3664e71ae05a398a52df430d86d660691501b28968cc4467e6" +checksum = "0cd4524931a4e0ec50ae91f0d55f571f31ffe11dd9ce2f9905b8343c018c25bb" dependencies = [ "tock-registers", ] @@ -20,6 +20,6 @@ dependencies = [ [[package]] name = "tock-registers" -version = "0.7.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ee8fba06c1f4d0b396ef61a54530bb6b28f0dc61c38bc8bc5a5a48161e6282e" +checksum = "696941a0aee7e276a165a978b37918fd5d22c55c3d6bda197813070ca9c0f21c" diff --git a/02_runtime_init/Cargo.toml b/02_runtime_init/Cargo.toml index 52786a40..59566db0 100644 --- a/02_runtime_init/Cargo.toml +++ b/02_runtime_init/Cargo.toml @@ -24,4 +24,4 @@ path = "src/main.rs" # Platform specific dependencies [target.'cfg(target_arch = "aarch64")'.dependencies] -cortex-a = { version = "7.x.x" } +cortex-a = { version = "8.x.x" } diff --git a/02_runtime_init/README.md b/02_runtime_init/README.md index f5b9355c..80fd77a4 100644 --- a/02_runtime_init/README.md +++ b/02_runtime_init/README.md @@ -47,7 +47,7 @@ diff -uNr 01_wait_forever/Cargo.toml 02_runtime_init/Cargo.toml + +# Platform specific dependencies +[target.'cfg(target_arch = "aarch64")'.dependencies] -+cortex-a = { version = "7.x.x" } ++cortex-a = { version = "8.x.x" } diff -uNr 01_wait_forever/Makefile 02_runtime_init/Makefile --- 01_wait_forever/Makefile diff --git a/03_hacky_hello_world/Cargo.lock b/03_hacky_hello_world/Cargo.lock index baa9f9c4..6b68a92e 100644 --- a/03_hacky_hello_world/Cargo.lock +++ b/03_hacky_hello_world/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "cortex-a" -version = "7.5.0" +version = "8.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdecfbb28672ad3664e71ae05a398a52df430d86d660691501b28968cc4467e6" +checksum = "0cd4524931a4e0ec50ae91f0d55f571f31ffe11dd9ce2f9905b8343c018c25bb" dependencies = [ "tock-registers", ] @@ -20,6 +20,6 @@ dependencies = [ [[package]] name = "tock-registers" -version = "0.7.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ee8fba06c1f4d0b396ef61a54530bb6b28f0dc61c38bc8bc5a5a48161e6282e" +checksum = "696941a0aee7e276a165a978b37918fd5d22c55c3d6bda197813070ca9c0f21c" diff --git a/03_hacky_hello_world/Cargo.toml b/03_hacky_hello_world/Cargo.toml index cca92834..e3e95003 100644 --- a/03_hacky_hello_world/Cargo.toml +++ b/03_hacky_hello_world/Cargo.toml @@ -24,4 +24,4 @@ path = "src/main.rs" # Platform specific dependencies [target.'cfg(target_arch = "aarch64")'.dependencies] -cortex-a = { version = "7.x.x" } +cortex-a = { version = "8.x.x" } diff --git a/04_safe_globals/Cargo.lock b/04_safe_globals/Cargo.lock index 72bdf630..21c1ad6f 100644 --- a/04_safe_globals/Cargo.lock +++ b/04_safe_globals/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "cortex-a" -version = "7.5.0" +version = "8.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdecfbb28672ad3664e71ae05a398a52df430d86d660691501b28968cc4467e6" +checksum = "0cd4524931a4e0ec50ae91f0d55f571f31ffe11dd9ce2f9905b8343c018c25bb" dependencies = [ "tock-registers", ] @@ -20,6 +20,6 @@ dependencies = [ [[package]] name = "tock-registers" -version = "0.7.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ee8fba06c1f4d0b396ef61a54530bb6b28f0dc61c38bc8bc5a5a48161e6282e" +checksum = "696941a0aee7e276a165a978b37918fd5d22c55c3d6bda197813070ca9c0f21c" diff --git a/04_safe_globals/Cargo.toml b/04_safe_globals/Cargo.toml index cb51da55..51ddd52b 100644 --- a/04_safe_globals/Cargo.toml +++ b/04_safe_globals/Cargo.toml @@ -24,4 +24,4 @@ path = "src/main.rs" # Platform specific dependencies [target.'cfg(target_arch = "aarch64")'.dependencies] -cortex-a = { version = "7.x.x" } +cortex-a = { version = "8.x.x" } diff --git a/05_drivers_gpio_uart/Cargo.lock b/05_drivers_gpio_uart/Cargo.lock index 87686e39..93873c45 100644 --- a/05_drivers_gpio_uart/Cargo.lock +++ b/05_drivers_gpio_uart/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "cortex-a" -version = "7.5.0" +version = "8.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdecfbb28672ad3664e71ae05a398a52df430d86d660691501b28968cc4467e6" +checksum = "0cd4524931a4e0ec50ae91f0d55f571f31ffe11dd9ce2f9905b8343c018c25bb" dependencies = [ "tock-registers", ] @@ -21,6 +21,6 @@ dependencies = [ [[package]] name = "tock-registers" -version = "0.7.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ee8fba06c1f4d0b396ef61a54530bb6b28f0dc61c38bc8bc5a5a48161e6282e" +checksum = "696941a0aee7e276a165a978b37918fd5d22c55c3d6bda197813070ca9c0f21c" diff --git a/05_drivers_gpio_uart/Cargo.toml b/05_drivers_gpio_uart/Cargo.toml index b2f17d8d..1f6db5de 100644 --- a/05_drivers_gpio_uart/Cargo.toml +++ b/05_drivers_gpio_uart/Cargo.toml @@ -23,8 +23,8 @@ path = "src/main.rs" [dependencies] # Optional dependencies -tock-registers = { version = "0.7.x", default-features = false, features = ["register_types"], optional = true } +tock-registers = { version = "0.8.x", default-features = false, features = ["register_types"], optional = true } # Platform specific dependencies [target.'cfg(target_arch = "aarch64")'.dependencies] -cortex-a = { version = "7.x.x" } +cortex-a = { version = "8.x.x" } diff --git a/05_drivers_gpio_uart/README.md b/05_drivers_gpio_uart/README.md index 572cd1a8..cbd43e71 100644 --- a/05_drivers_gpio_uart/README.md +++ b/05_drivers_gpio_uart/README.md @@ -131,11 +131,11 @@ diff -uNr 04_safe_globals/Cargo.toml 05_drivers_gpio_uart/Cargo.toml [dependencies] +# Optional dependencies -+tock-registers = { version = "0.7.x", default-features = false, features = ["register_types"], optional = true } ++tock-registers = { version = "0.8.x", default-features = false, features = ["register_types"], optional = true } + # Platform specific dependencies [target.'cfg(target_arch = "aarch64")'.dependencies] - cortex-a = { version = "7.x.x" } + cortex-a = { version = "8.x.x" } diff -uNr 04_safe_globals/Makefile 05_drivers_gpio_uart/Makefile --- 04_safe_globals/Makefile diff --git a/06_uart_chainloader/Cargo.lock b/06_uart_chainloader/Cargo.lock index 0936e7c6..c26c68d1 100644 --- a/06_uart_chainloader/Cargo.lock +++ b/06_uart_chainloader/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "cortex-a" -version = "7.5.0" +version = "8.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdecfbb28672ad3664e71ae05a398a52df430d86d660691501b28968cc4467e6" +checksum = "0cd4524931a4e0ec50ae91f0d55f571f31ffe11dd9ce2f9905b8343c018c25bb" dependencies = [ "tock-registers", ] @@ -21,6 +21,6 @@ dependencies = [ [[package]] name = "tock-registers" -version = "0.7.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ee8fba06c1f4d0b396ef61a54530bb6b28f0dc61c38bc8bc5a5a48161e6282e" +checksum = "696941a0aee7e276a165a978b37918fd5d22c55c3d6bda197813070ca9c0f21c" diff --git a/06_uart_chainloader/Cargo.toml b/06_uart_chainloader/Cargo.toml index f00c87a8..8770d7a0 100644 --- a/06_uart_chainloader/Cargo.toml +++ b/06_uart_chainloader/Cargo.toml @@ -23,8 +23,8 @@ path = "src/main.rs" [dependencies] # Optional dependencies -tock-registers = { version = "0.7.x", default-features = false, features = ["register_types"], optional = true } +tock-registers = { version = "0.8.x", default-features = false, features = ["register_types"], optional = true } # Platform specific dependencies [target.'cfg(target_arch = "aarch64")'.dependencies] -cortex-a = { version = "7.x.x" } +cortex-a = { version = "8.x.x" } diff --git a/06_uart_chainloader/demo_payload_rpi3.img b/06_uart_chainloader/demo_payload_rpi3.img index 2016c14e26bd5edce571ca2424a5cfa9b916d826..20f13981c87fa20c518e3039149ff063beb0eb3d 100755 GIT binary patch delta 1090 zcmYjPO-vI(6n?u?U@0O^w?9H#yQTcJ(iFs&s%TR1;9rbbO*GMng&?4S1fz);D8Yp2 zMTRkQF$VO|Y)=}*7!L+wV!+_RC|ta(UTisNqQ=+|yUuP0@g=)E^S$rA_w6^MG%L+z z)3AF54AIFJ9?rOd!(}J5#*W)VgG0~R>nD5@d8dKLH0o+mVN|#-Wq0eD9Q0N zq1j}?!!6tbIb!}b0uar<%Bgl>Ayh@>&xlJYNJxD`#i{q|W{y!NI4%)`L>-<-?W+oM zQ=U7et+l+0_;8%jfa0Q8}vJE4s6 zc$^KN4QxBbnSCxgWCQ~vEVDgzNRRVO19eM}{@#J^D|96| z^NkA_-Vh828|Ydh3r@FrH_Mt>_PmRHch>CfVX%e4k{&^6g5iY>zsL6cW_iq2V_sx1 zy_b5>uD4w^rNAWW|46zV!OH=u^Ge^f{sGBoG{T09b*w5~kyoC71Ds^#8-IL`?Kg+# ZnHvto;#UVdx`u{sNNv5+F7nb<`4=y6B{Kj3 delta 1118 zcmZ8fU1$?o6h3!ut!b2+=C`&Jb8FkQp&`cpm^KwH5fMdMErLZK+GvZ0ZCaVK3qGZ# zu(JEG^!5rB{Gr;1I8hX>1@&QR*_W-pSkSU>I~5-ipF}|jV#j+YH_NgIhPmgv=R4>7 z=8Vy6^zOI=-ESKz`eqXf3>*Z7?l`4XYgZ(Hx&hrS5DrvUrM=gq7{=%;Lz{;QZ|+V%W2(85J1nhV?XTbt(G5J1-; zXPKtyGo}?f&HEA{Z@`Ma;`FBJE1dy^j&~U43~bA7;Hn(sobsJ`n^;-f?1dsf&H#zg z<*(*k5D+X0S@TE1@gCrs0kAa7hcxiB7$olgin5okPDc&>fPorYD|G>G#96i5>(RTx zVP+J)(1`Q`Mzqj~^+&A79d5YOPL~ojw2Du2@h7yhmm>bop8<=XkF#Ig`|1vGlf(sG z;$y9%$$r~ZoAsHJ^=#c8XrJn!d9%V=#OEy5^D!v4amKO(xG0N~@Yd z+!-8?&}BThZr}i4Par4Gi{aYS$O$TU|DW)xi?cg-A-kitgp*qKqApn7pPaaSeniu* zkdrCW!9LbS*{=FytkvI^NgO&sj+{LDLra*9rp87{m|Pei{V6?0>~?@l^`$m#a>Nap zmxnIMoO`k2fy@<|r=>jZ(~85IHm;G;@#Ju7>>?S~Qa^W(XmJuJWgmPiR(K_`+-O3( zuqT~NjYYHx>%LoMPwE@@bBRN;vO+S4WnPx_e+g+md7RhIvl`Whp0SV`aK4rthwPD7 z*;zFh2Y<<@Tf)SO2x*mgrNkpLFN@{$7i!QsBw_vwTfyN^YOwmcgiBW0AO79n0rA2r A9RL6T diff --git a/06_uart_chainloader/demo_payload_rpi4.img b/06_uart_chainloader/demo_payload_rpi4.img index 7be0ece0ad39e99544280e4fe3d9f82d0d874875..779cc308d9b2decf926e6ea6a4e3f8764183ede1 100755 GIT binary patch delta 908 zcmYjPT}V@57=FKv7d`JhBCV_lEii64=AZr(u~NP8eJI) zd3pn_2u3$?23>@C;hhRWUJR1dg1VU1#f*p`kyhmCJKHDq!pHkP@AJOzd7h865Y0x9 zWg)Z$`q;g=4pJ^4&yRKL$mn99ZkFgs+u|o~t(>14)_F3pc%}9o=W7heE{WSZ-3`L- z@nvOKRlgTGkbN5=x!@8`D7T^Og%S&mY~Hi6O!p&;Rd%0oGZ6Ok9MaVsGM%& zAPS{&pA?i||5oRLz>+30OC|29>U;rU=?Tqlfcp|in;Q439Rv=*tbLM?H_Jvh$b~9U zfW%5(dia`H3CJnDYpxX|oy9(VC2cpw;@Uw5J~w?LJ0p#eSlg z=<2Dap!`FGl2-SIu+>qkm=RB_wl7=kWAxA zYodBH1VVu`=f5Rhl(`+>*zKVzA*OM{>MArW80n z_u@bm0b->`e^e2_ihFwP*|5+sRJUTM?*EHzJlpsIAKMZ>L3Clap^>5>j-9>&Pad^U#qoSqko$@CbK2#K7n6TMPboC^? z58<#wB-e4;;i{WsJ(>GD6o22$PR)ketUJ4-`-j~nmfdx2ldNrZ1E-cm3oJ#^F6pU5r_2tXYU>mz z2<60=pZ=6*@+B&qT zZ&}uMi3csQp3#gX(ZA-PtiM$8TJ4BusoiW4)WtDJzUPWZZf+1@QCz~`wU>y97u|8< zz}xPmhX<(?6Lb+^;s8mP>sL>k?b^O#7SFBkX2GOr z0wAre?O0PlVBTJFs1u~m0Fws5{3FYniqJR=;WxI{aSS9LK(E~ctfZ@HaQS1&V^#hC*SXNW&c&drUSMgRLGYI2(wyEHGBCkPt3gDr_)* fALG9;{BLhpFy^Xb--7-NWs72GFh(xmaPY_ GenericTimerCounterValue { + // Prevent that the counter is read ahead of time due to out-of-order execution. -+ unsafe { barrier::isb(barrier::SY) }; ++ barrier::isb(barrier::SY); + let cnt = CNTPCT_EL0.get(); + + GenericTimerCounterValue(cnt) diff --git a/07_timestamps/src/_arch/aarch64/time.rs b/07_timestamps/src/_arch/aarch64/time.rs index ad8ba84d..1e2efbec 100644 --- a/07_timestamps/src/_arch/aarch64/time.rs +++ b/07_timestamps/src/_arch/aarch64/time.rs @@ -120,7 +120,7 @@ impl TryFrom for GenericTimerCounterValue { #[inline(always)] fn read_cntpct() -> GenericTimerCounterValue { // Prevent that the counter is read ahead of time due to out-of-order execution. - unsafe { barrier::isb(barrier::SY) }; + barrier::isb(barrier::SY); let cnt = CNTPCT_EL0.get(); GenericTimerCounterValue(cnt) diff --git a/08_hw_debug_JTAG/Cargo.lock b/08_hw_debug_JTAG/Cargo.lock index 6e628b86..bcfb442a 100644 --- a/08_hw_debug_JTAG/Cargo.lock +++ b/08_hw_debug_JTAG/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "cortex-a" -version = "7.5.0" +version = "8.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdecfbb28672ad3664e71ae05a398a52df430d86d660691501b28968cc4467e6" +checksum = "0cd4524931a4e0ec50ae91f0d55f571f31ffe11dd9ce2f9905b8343c018c25bb" dependencies = [ "tock-registers", ] @@ -21,6 +21,6 @@ dependencies = [ [[package]] name = "tock-registers" -version = "0.7.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ee8fba06c1f4d0b396ef61a54530bb6b28f0dc61c38bc8bc5a5a48161e6282e" +checksum = "696941a0aee7e276a165a978b37918fd5d22c55c3d6bda197813070ca9c0f21c" diff --git a/08_hw_debug_JTAG/Cargo.toml b/08_hw_debug_JTAG/Cargo.toml index 638d4de1..55963c38 100644 --- a/08_hw_debug_JTAG/Cargo.toml +++ b/08_hw_debug_JTAG/Cargo.toml @@ -23,8 +23,8 @@ path = "src/main.rs" [dependencies] # Optional dependencies -tock-registers = { version = "0.7.x", default-features = false, features = ["register_types"], optional = true } +tock-registers = { version = "0.8.x", default-features = false, features = ["register_types"], optional = true } # Platform specific dependencies [target.'cfg(target_arch = "aarch64")'.dependencies] -cortex-a = { version = "7.x.x" } +cortex-a = { version = "8.x.x" } diff --git a/08_hw_debug_JTAG/src/_arch/aarch64/time.rs b/08_hw_debug_JTAG/src/_arch/aarch64/time.rs index ad8ba84d..1e2efbec 100644 --- a/08_hw_debug_JTAG/src/_arch/aarch64/time.rs +++ b/08_hw_debug_JTAG/src/_arch/aarch64/time.rs @@ -120,7 +120,7 @@ impl TryFrom for GenericTimerCounterValue { #[inline(always)] fn read_cntpct() -> GenericTimerCounterValue { // Prevent that the counter is read ahead of time due to out-of-order execution. - unsafe { barrier::isb(barrier::SY) }; + barrier::isb(barrier::SY); let cnt = CNTPCT_EL0.get(); GenericTimerCounterValue(cnt) diff --git a/09_privilege_level/Cargo.lock b/09_privilege_level/Cargo.lock index 5dc791a2..29c6ef54 100644 --- a/09_privilege_level/Cargo.lock +++ b/09_privilege_level/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "cortex-a" -version = "7.5.0" +version = "8.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdecfbb28672ad3664e71ae05a398a52df430d86d660691501b28968cc4467e6" +checksum = "0cd4524931a4e0ec50ae91f0d55f571f31ffe11dd9ce2f9905b8343c018c25bb" dependencies = [ "tock-registers", ] @@ -21,6 +21,6 @@ dependencies = [ [[package]] name = "tock-registers" -version = "0.7.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ee8fba06c1f4d0b396ef61a54530bb6b28f0dc61c38bc8bc5a5a48161e6282e" +checksum = "696941a0aee7e276a165a978b37918fd5d22c55c3d6bda197813070ca9c0f21c" diff --git a/09_privilege_level/Cargo.toml b/09_privilege_level/Cargo.toml index dccb5622..a89435bc 100644 --- a/09_privilege_level/Cargo.toml +++ b/09_privilege_level/Cargo.toml @@ -23,8 +23,8 @@ path = "src/main.rs" [dependencies] # Optional dependencies -tock-registers = { version = "0.7.x", default-features = false, features = ["register_types"], optional = true } +tock-registers = { version = "0.8.x", default-features = false, features = ["register_types"], optional = true } # Platform specific dependencies [target.'cfg(target_arch = "aarch64")'.dependencies] -cortex-a = { version = "7.x.x" } +cortex-a = { version = "8.x.x" } diff --git a/09_privilege_level/src/_arch/aarch64/time.rs b/09_privilege_level/src/_arch/aarch64/time.rs index ad8ba84d..1e2efbec 100644 --- a/09_privilege_level/src/_arch/aarch64/time.rs +++ b/09_privilege_level/src/_arch/aarch64/time.rs @@ -120,7 +120,7 @@ impl TryFrom for GenericTimerCounterValue { #[inline(always)] fn read_cntpct() -> GenericTimerCounterValue { // Prevent that the counter is read ahead of time due to out-of-order execution. - unsafe { barrier::isb(barrier::SY) }; + barrier::isb(barrier::SY); let cnt = CNTPCT_EL0.get(); GenericTimerCounterValue(cnt) diff --git a/10_virtual_mem_part1_identity_mapping/Cargo.lock b/10_virtual_mem_part1_identity_mapping/Cargo.lock index 1115edab..4bfff935 100644 --- a/10_virtual_mem_part1_identity_mapping/Cargo.lock +++ b/10_virtual_mem_part1_identity_mapping/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "cortex-a" -version = "7.5.0" +version = "8.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdecfbb28672ad3664e71ae05a398a52df430d86d660691501b28968cc4467e6" +checksum = "0cd4524931a4e0ec50ae91f0d55f571f31ffe11dd9ce2f9905b8343c018c25bb" dependencies = [ "tock-registers", ] @@ -21,6 +21,6 @@ dependencies = [ [[package]] name = "tock-registers" -version = "0.7.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ee8fba06c1f4d0b396ef61a54530bb6b28f0dc61c38bc8bc5a5a48161e6282e" +checksum = "696941a0aee7e276a165a978b37918fd5d22c55c3d6bda197813070ca9c0f21c" diff --git a/10_virtual_mem_part1_identity_mapping/Cargo.toml b/10_virtual_mem_part1_identity_mapping/Cargo.toml index 144767d3..d3e2582d 100644 --- a/10_virtual_mem_part1_identity_mapping/Cargo.toml +++ b/10_virtual_mem_part1_identity_mapping/Cargo.toml @@ -23,8 +23,8 @@ path = "src/main.rs" [dependencies] # Optional dependencies -tock-registers = { version = "0.7.x", default-features = false, features = ["register_types"], optional = true } +tock-registers = { version = "0.8.x", default-features = false, features = ["register_types"], optional = true } # Platform specific dependencies [target.'cfg(target_arch = "aarch64")'.dependencies] -cortex-a = { version = "7.x.x" } +cortex-a = { version = "8.x.x" } diff --git a/10_virtual_mem_part1_identity_mapping/src/_arch/aarch64/time.rs b/10_virtual_mem_part1_identity_mapping/src/_arch/aarch64/time.rs index ad8ba84d..1e2efbec 100644 --- a/10_virtual_mem_part1_identity_mapping/src/_arch/aarch64/time.rs +++ b/10_virtual_mem_part1_identity_mapping/src/_arch/aarch64/time.rs @@ -120,7 +120,7 @@ impl TryFrom for GenericTimerCounterValue { #[inline(always)] fn read_cntpct() -> GenericTimerCounterValue { // Prevent that the counter is read ahead of time due to out-of-order execution. - unsafe { barrier::isb(barrier::SY) }; + barrier::isb(barrier::SY); let cnt = CNTPCT_EL0.get(); GenericTimerCounterValue(cnt) diff --git a/11_exceptions_part1_groundwork/Cargo.lock b/11_exceptions_part1_groundwork/Cargo.lock index f1d4af57..c7bfdadd 100644 --- a/11_exceptions_part1_groundwork/Cargo.lock +++ b/11_exceptions_part1_groundwork/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "cortex-a" -version = "7.5.0" +version = "8.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdecfbb28672ad3664e71ae05a398a52df430d86d660691501b28968cc4467e6" +checksum = "0cd4524931a4e0ec50ae91f0d55f571f31ffe11dd9ce2f9905b8343c018c25bb" dependencies = [ "tock-registers", ] @@ -21,6 +21,6 @@ dependencies = [ [[package]] name = "tock-registers" -version = "0.7.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ee8fba06c1f4d0b396ef61a54530bb6b28f0dc61c38bc8bc5a5a48161e6282e" +checksum = "696941a0aee7e276a165a978b37918fd5d22c55c3d6bda197813070ca9c0f21c" diff --git a/11_exceptions_part1_groundwork/Cargo.toml b/11_exceptions_part1_groundwork/Cargo.toml index aa8a870c..c8d3613f 100644 --- a/11_exceptions_part1_groundwork/Cargo.toml +++ b/11_exceptions_part1_groundwork/Cargo.toml @@ -23,8 +23,8 @@ path = "src/main.rs" [dependencies] # Optional dependencies -tock-registers = { version = "0.7.x", default-features = false, features = ["register_types"], optional = true } +tock-registers = { version = "0.8.x", default-features = false, features = ["register_types"], optional = true } # Platform specific dependencies [target.'cfg(target_arch = "aarch64")'.dependencies] -cortex-a = { version = "7.x.x" } +cortex-a = { version = "8.x.x" } diff --git a/11_exceptions_part1_groundwork/src/_arch/aarch64/time.rs b/11_exceptions_part1_groundwork/src/_arch/aarch64/time.rs index ad8ba84d..1e2efbec 100644 --- a/11_exceptions_part1_groundwork/src/_arch/aarch64/time.rs +++ b/11_exceptions_part1_groundwork/src/_arch/aarch64/time.rs @@ -120,7 +120,7 @@ impl TryFrom for GenericTimerCounterValue { #[inline(always)] fn read_cntpct() -> GenericTimerCounterValue { // Prevent that the counter is read ahead of time due to out-of-order execution. - unsafe { barrier::isb(barrier::SY) }; + barrier::isb(barrier::SY); let cnt = CNTPCT_EL0.get(); GenericTimerCounterValue(cnt) diff --git a/12_integrated_testing/Cargo.lock b/12_integrated_testing/Cargo.lock index f188bfe0..7af740b1 100644 --- a/12_integrated_testing/Cargo.lock +++ b/12_integrated_testing/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "cortex-a" -version = "7.5.0" +version = "8.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdecfbb28672ad3664e71ae05a398a52df430d86d660691501b28968cc4467e6" +checksum = "0cd4524931a4e0ec50ae91f0d55f571f31ffe11dd9ce2f9905b8343c018c25bb" dependencies = [ "tock-registers", ] @@ -24,9 +24,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.43" +version = "1.0.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a2ca2c61bc9f3d74d2886294ab7b9853abd9c1ad903a3ac7815c58989bb7bab" +checksum = "7bd7356a8122b6c4a24a82b278680c73357984ca2fc79a0f9fa6dea7dced7c58" dependencies = [ "unicode-ident", ] @@ -48,9 +48,9 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.100" +version = "1.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52205623b1b0f064a4e71182c3b18ae902267282930c6d5462c91b859668426e" +checksum = "e90cde112c4b9690b8cbe810cba9ddd8bc1d7472e2cae317b69e9438c1cba7d2" dependencies = [ "proc-macro2", "quote", @@ -73,9 +73,9 @@ version = "0.1.0" [[package]] name = "tock-registers" -version = "0.7.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ee8fba06c1f4d0b396ef61a54530bb6b28f0dc61c38bc8bc5a5a48161e6282e" +checksum = "696941a0aee7e276a165a978b37918fd5d22c55c3d6bda197813070ca9c0f21c" [[package]] name = "unicode-ident" diff --git a/12_integrated_testing/kernel/Cargo.toml b/12_integrated_testing/kernel/Cargo.toml index 864cfb61..7bbca0b4 100644 --- a/12_integrated_testing/kernel/Cargo.toml +++ b/12_integrated_testing/kernel/Cargo.toml @@ -18,12 +18,12 @@ test_build = ["qemu-exit"] test-types = { path = "../libraries/test-types" } # Optional dependencies -tock-registers = { version = "0.7.x", default-features = false, features = ["register_types"], optional = true } +tock-registers = { version = "0.8.x", default-features = false, features = ["register_types"], optional = true } qemu-exit = { version = "3.x.x", optional = true } # Platform specific dependencies [target.'cfg(target_arch = "aarch64")'.dependencies] -cortex-a = { version = "7.x.x" } +cortex-a = { version = "8.x.x" } ##-------------------------------------------------------------------------------------------------- ## Testing diff --git a/12_integrated_testing/kernel/src/_arch/aarch64/time.rs b/12_integrated_testing/kernel/src/_arch/aarch64/time.rs index ad8ba84d..1e2efbec 100644 --- a/12_integrated_testing/kernel/src/_arch/aarch64/time.rs +++ b/12_integrated_testing/kernel/src/_arch/aarch64/time.rs @@ -120,7 +120,7 @@ impl TryFrom for GenericTimerCounterValue { #[inline(always)] fn read_cntpct() -> GenericTimerCounterValue { // Prevent that the counter is read ahead of time due to out-of-order execution. - unsafe { barrier::isb(barrier::SY) }; + barrier::isb(barrier::SY); let cnt = CNTPCT_EL0.get(); GenericTimerCounterValue(cnt) diff --git a/13_exceptions_part2_peripheral_IRQs/Cargo.lock b/13_exceptions_part2_peripheral_IRQs/Cargo.lock index e5a8e81c..59d40ee6 100644 --- a/13_exceptions_part2_peripheral_IRQs/Cargo.lock +++ b/13_exceptions_part2_peripheral_IRQs/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "cortex-a" -version = "7.5.0" +version = "8.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdecfbb28672ad3664e71ae05a398a52df430d86d660691501b28968cc4467e6" +checksum = "0cd4524931a4e0ec50ae91f0d55f571f31ffe11dd9ce2f9905b8343c018c25bb" dependencies = [ "tock-registers", ] @@ -24,9 +24,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.43" +version = "1.0.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a2ca2c61bc9f3d74d2886294ab7b9853abd9c1ad903a3ac7815c58989bb7bab" +checksum = "7bd7356a8122b6c4a24a82b278680c73357984ca2fc79a0f9fa6dea7dced7c58" dependencies = [ "unicode-ident", ] @@ -48,9 +48,9 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.100" +version = "1.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52205623b1b0f064a4e71182c3b18ae902267282930c6d5462c91b859668426e" +checksum = "e90cde112c4b9690b8cbe810cba9ddd8bc1d7472e2cae317b69e9438c1cba7d2" dependencies = [ "proc-macro2", "quote", @@ -73,9 +73,9 @@ version = "0.1.0" [[package]] name = "tock-registers" -version = "0.7.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ee8fba06c1f4d0b396ef61a54530bb6b28f0dc61c38bc8bc5a5a48161e6282e" +checksum = "696941a0aee7e276a165a978b37918fd5d22c55c3d6bda197813070ca9c0f21c" [[package]] name = "unicode-ident" diff --git a/13_exceptions_part2_peripheral_IRQs/README.md b/13_exceptions_part2_peripheral_IRQs/README.md index 0bb676db..3d6d5f16 100644 --- a/13_exceptions_part2_peripheral_IRQs/README.md +++ b/13_exceptions_part2_peripheral_IRQs/README.md @@ -609,9 +609,9 @@ register_structs! { (0x004 => TYPER: ReadOnly), (0x008 => _reserved1), (0x104 => ISENABLER: [ReadWrite; 31]), - (0x108 => _reserved2), + (0x180 => _reserved2), (0x820 => ITARGETSR: [ReadWrite; 248]), - (0x824 => @END), + (0xC00 => @END), } } @@ -622,7 +622,7 @@ register_structs! { (0x100 => ISENABLER: ReadWrite), (0x104 => _reserved2), (0x800 => ITARGETSR: [ReadOnly; 8]), - (0x804 => @END), + (0x820 => @END), } } ``` @@ -1098,9 +1098,9 @@ diff -uNr 12_integrated_testing/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs 1 + (0x004 => TYPER: ReadOnly), + (0x008 => _reserved1), + (0x104 => ISENABLER: [ReadWrite; 31]), -+ (0x108 => _reserved2), ++ (0x180 => _reserved2), + (0x820 => ITARGETSR: [ReadWrite; 248]), -+ (0x824 => @END), ++ (0xC00 => @END), + } +} + @@ -1111,7 +1111,7 @@ diff -uNr 12_integrated_testing/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs 1 + (0x100 => ISENABLER: ReadWrite), + (0x104 => _reserved2), + (0x800 => ITARGETSR: [ReadOnly; 8]), -+ (0x804 => @END), ++ (0x820 => @END), + } +} + diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/Cargo.toml b/13_exceptions_part2_peripheral_IRQs/kernel/Cargo.toml index f45458f9..5f371dda 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/Cargo.toml +++ b/13_exceptions_part2_peripheral_IRQs/kernel/Cargo.toml @@ -18,12 +18,12 @@ test_build = ["qemu-exit"] test-types = { path = "../libraries/test-types" } # Optional dependencies -tock-registers = { version = "0.7.x", default-features = false, features = ["register_types"], optional = true } +tock-registers = { version = "0.8.x", default-features = false, features = ["register_types"], optional = true } qemu-exit = { version = "3.x.x", optional = true } # Platform specific dependencies [target.'cfg(target_arch = "aarch64")'.dependencies] -cortex-a = { version = "7.x.x" } +cortex-a = { version = "8.x.x" } ##-------------------------------------------------------------------------------------------------- ## Testing diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/time.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/time.rs index ad8ba84d..1e2efbec 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/time.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/time.rs @@ -120,7 +120,7 @@ impl TryFrom for GenericTimerCounterValue { #[inline(always)] fn read_cntpct() -> GenericTimerCounterValue { // Prevent that the counter is read ahead of time due to out-of-order execution. - unsafe { barrier::isb(barrier::SY) }; + barrier::isb(barrier::SY); let cnt = CNTPCT_EL0.get(); GenericTimerCounterValue(cnt) diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs index bc7f7f23..54aab60c 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs @@ -50,9 +50,9 @@ register_structs! { (0x004 => TYPER: ReadOnly), (0x008 => _reserved1), (0x104 => ISENABLER: [ReadWrite; 31]), - (0x108 => _reserved2), + (0x180 => _reserved2), (0x820 => ITARGETSR: [ReadWrite; 248]), - (0x824 => @END), + (0xC00 => @END), } } @@ -63,7 +63,7 @@ register_structs! { (0x100 => ISENABLER: ReadWrite), (0x104 => _reserved2), (0x800 => ITARGETSR: [ReadOnly; 8]), - (0x804 => @END), + (0x820 => @END), } } diff --git a/14_virtual_mem_part2_mmio_remap/Cargo.lock b/14_virtual_mem_part2_mmio_remap/Cargo.lock index 163a6526..a66dec99 100644 --- a/14_virtual_mem_part2_mmio_remap/Cargo.lock +++ b/14_virtual_mem_part2_mmio_remap/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "cortex-a" -version = "7.5.0" +version = "8.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdecfbb28672ad3664e71ae05a398a52df430d86d660691501b28968cc4467e6" +checksum = "0cd4524931a4e0ec50ae91f0d55f571f31ffe11dd9ce2f9905b8343c018c25bb" dependencies = [ "tock-registers", ] @@ -24,9 +24,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.43" +version = "1.0.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a2ca2c61bc9f3d74d2886294ab7b9853abd9c1ad903a3ac7815c58989bb7bab" +checksum = "7bd7356a8122b6c4a24a82b278680c73357984ca2fc79a0f9fa6dea7dced7c58" dependencies = [ "unicode-ident", ] @@ -48,9 +48,9 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.100" +version = "1.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52205623b1b0f064a4e71182c3b18ae902267282930c6d5462c91b859668426e" +checksum = "e90cde112c4b9690b8cbe810cba9ddd8bc1d7472e2cae317b69e9438c1cba7d2" dependencies = [ "proc-macro2", "quote", @@ -73,9 +73,9 @@ version = "0.1.0" [[package]] name = "tock-registers" -version = "0.7.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ee8fba06c1f4d0b396ef61a54530bb6b28f0dc61c38bc8bc5a5a48161e6282e" +checksum = "696941a0aee7e276a165a978b37918fd5d22c55c3d6bda197813070ca9c0f21c" [[package]] name = "unicode-ident" diff --git a/14_virtual_mem_part2_mmio_remap/kernel/Cargo.toml b/14_virtual_mem_part2_mmio_remap/kernel/Cargo.toml index f187a467..fe4e48e7 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/Cargo.toml +++ b/14_virtual_mem_part2_mmio_remap/kernel/Cargo.toml @@ -18,12 +18,12 @@ test_build = ["qemu-exit"] test-types = { path = "../libraries/test-types" } # Optional dependencies -tock-registers = { version = "0.7.x", default-features = false, features = ["register_types"], optional = true } +tock-registers = { version = "0.8.x", default-features = false, features = ["register_types"], optional = true } qemu-exit = { version = "3.x.x", optional = true } # Platform specific dependencies [target.'cfg(target_arch = "aarch64")'.dependencies] -cortex-a = { version = "7.x.x" } +cortex-a = { version = "8.x.x" } ##-------------------------------------------------------------------------------------------------- ## Testing diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/time.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/time.rs index ad8ba84d..1e2efbec 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/time.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/time.rs @@ -120,7 +120,7 @@ impl TryFrom for GenericTimerCounterValue { #[inline(always)] fn read_cntpct() -> GenericTimerCounterValue { // Prevent that the counter is read ahead of time due to out-of-order execution. - unsafe { barrier::isb(barrier::SY) }; + barrier::isb(barrier::SY); let cnt = CNTPCT_EL0.get(); GenericTimerCounterValue(cnt) diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs index d9f63d1b..a9c97a8e 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs @@ -52,9 +52,9 @@ register_structs! { (0x004 => TYPER: ReadOnly), (0x008 => _reserved1), (0x104 => ISENABLER: [ReadWrite; 31]), - (0x108 => _reserved2), + (0x180 => _reserved2), (0x820 => ITARGETSR: [ReadWrite; 248]), - (0x824 => @END), + (0xC00 => @END), } } @@ -65,7 +65,7 @@ register_structs! { (0x100 => ISENABLER: ReadWrite), (0x104 => _reserved2), (0x800 => ITARGETSR: [ReadOnly; 8]), - (0x804 => @END), + (0x820 => @END), } } diff --git a/15_virtual_mem_part3_precomputed_tables/Cargo.lock b/15_virtual_mem_part3_precomputed_tables/Cargo.lock index 6cac9dcb..e0c25535 100644 --- a/15_virtual_mem_part3_precomputed_tables/Cargo.lock +++ b/15_virtual_mem_part3_precomputed_tables/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "cortex-a" -version = "7.5.0" +version = "8.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdecfbb28672ad3664e71ae05a398a52df430d86d660691501b28968cc4467e6" +checksum = "0cd4524931a4e0ec50ae91f0d55f571f31ffe11dd9ce2f9905b8343c018c25bb" dependencies = [ "tock-registers", ] @@ -24,9 +24,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.43" +version = "1.0.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a2ca2c61bc9f3d74d2886294ab7b9853abd9c1ad903a3ac7815c58989bb7bab" +checksum = "7bd7356a8122b6c4a24a82b278680c73357984ca2fc79a0f9fa6dea7dced7c58" dependencies = [ "unicode-ident", ] @@ -48,9 +48,9 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.100" +version = "1.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52205623b1b0f064a4e71182c3b18ae902267282930c6d5462c91b859668426e" +checksum = "e90cde112c4b9690b8cbe810cba9ddd8bc1d7472e2cae317b69e9438c1cba7d2" dependencies = [ "proc-macro2", "quote", @@ -73,9 +73,9 @@ version = "0.1.0" [[package]] name = "tock-registers" -version = "0.7.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ee8fba06c1f4d0b396ef61a54530bb6b28f0dc61c38bc8bc5a5a48161e6282e" +checksum = "696941a0aee7e276a165a978b37918fd5d22c55c3d6bda197813070ca9c0f21c" [[package]] name = "unicode-ident" diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/Cargo.toml b/15_virtual_mem_part3_precomputed_tables/kernel/Cargo.toml index 4641b0e8..9a0408ad 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/Cargo.toml +++ b/15_virtual_mem_part3_precomputed_tables/kernel/Cargo.toml @@ -18,12 +18,12 @@ test_build = ["qemu-exit"] test-types = { path = "../libraries/test-types" } # Optional dependencies -tock-registers = { version = "0.7.x", default-features = false, features = ["register_types"], optional = true } +tock-registers = { version = "0.8.x", default-features = false, features = ["register_types"], optional = true } qemu-exit = { version = "3.x.x", optional = true } # Platform specific dependencies [target.'cfg(target_arch = "aarch64")'.dependencies] -cortex-a = { version = "7.x.x" } +cortex-a = { version = "8.x.x" } ##-------------------------------------------------------------------------------------------------- ## Testing diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/time.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/time.rs index ad8ba84d..1e2efbec 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/time.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/time.rs @@ -120,7 +120,7 @@ impl TryFrom for GenericTimerCounterValue { #[inline(always)] fn read_cntpct() -> GenericTimerCounterValue { // Prevent that the counter is read ahead of time due to out-of-order execution. - unsafe { barrier::isb(barrier::SY) }; + barrier::isb(barrier::SY); let cnt = CNTPCT_EL0.get(); GenericTimerCounterValue(cnt) diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs index d9f63d1b..a9c97a8e 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs @@ -52,9 +52,9 @@ register_structs! { (0x004 => TYPER: ReadOnly), (0x008 => _reserved1), (0x104 => ISENABLER: [ReadWrite; 31]), - (0x108 => _reserved2), + (0x180 => _reserved2), (0x820 => ITARGETSR: [ReadWrite; 248]), - (0x824 => @END), + (0xC00 => @END), } } @@ -65,7 +65,7 @@ register_structs! { (0x100 => ISENABLER: ReadWrite), (0x104 => _reserved2), (0x800 => ITARGETSR: [ReadOnly; 8]), - (0x804 => @END), + (0x820 => @END), } } diff --git a/16_virtual_mem_part4_higher_half_kernel/Cargo.lock b/16_virtual_mem_part4_higher_half_kernel/Cargo.lock index a529e673..95941be4 100644 --- a/16_virtual_mem_part4_higher_half_kernel/Cargo.lock +++ b/16_virtual_mem_part4_higher_half_kernel/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "cortex-a" -version = "7.5.0" +version = "8.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdecfbb28672ad3664e71ae05a398a52df430d86d660691501b28968cc4467e6" +checksum = "0cd4524931a4e0ec50ae91f0d55f571f31ffe11dd9ce2f9905b8343c018c25bb" dependencies = [ "tock-registers", ] @@ -24,9 +24,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.43" +version = "1.0.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a2ca2c61bc9f3d74d2886294ab7b9853abd9c1ad903a3ac7815c58989bb7bab" +checksum = "7bd7356a8122b6c4a24a82b278680c73357984ca2fc79a0f9fa6dea7dced7c58" dependencies = [ "unicode-ident", ] @@ -48,9 +48,9 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.100" +version = "1.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52205623b1b0f064a4e71182c3b18ae902267282930c6d5462c91b859668426e" +checksum = "e90cde112c4b9690b8cbe810cba9ddd8bc1d7472e2cae317b69e9438c1cba7d2" dependencies = [ "proc-macro2", "quote", @@ -73,9 +73,9 @@ version = "0.1.0" [[package]] name = "tock-registers" -version = "0.7.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ee8fba06c1f4d0b396ef61a54530bb6b28f0dc61c38bc8bc5a5a48161e6282e" +checksum = "696941a0aee7e276a165a978b37918fd5d22c55c3d6bda197813070ca9c0f21c" [[package]] name = "unicode-ident" diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/Cargo.toml b/16_virtual_mem_part4_higher_half_kernel/kernel/Cargo.toml index 28f87a50..06b2573c 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/Cargo.toml +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/Cargo.toml @@ -18,12 +18,12 @@ test_build = ["qemu-exit"] test-types = { path = "../libraries/test-types" } # Optional dependencies -tock-registers = { version = "0.7.x", default-features = false, features = ["register_types"], optional = true } +tock-registers = { version = "0.8.x", default-features = false, features = ["register_types"], optional = true } qemu-exit = { version = "3.x.x", optional = true } # Platform specific dependencies [target.'cfg(target_arch = "aarch64")'.dependencies] -cortex-a = { version = "7.x.x" } +cortex-a = { version = "8.x.x" } ##-------------------------------------------------------------------------------------------------- ## Testing diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/time.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/time.rs index ad8ba84d..1e2efbec 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/time.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/time.rs @@ -120,7 +120,7 @@ impl TryFrom for GenericTimerCounterValue { #[inline(always)] fn read_cntpct() -> GenericTimerCounterValue { // Prevent that the counter is read ahead of time due to out-of-order execution. - unsafe { barrier::isb(barrier::SY) }; + barrier::isb(barrier::SY); let cnt = CNTPCT_EL0.get(); GenericTimerCounterValue(cnt) diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs index d9f63d1b..a9c97a8e 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs @@ -52,9 +52,9 @@ register_structs! { (0x004 => TYPER: ReadOnly), (0x008 => _reserved1), (0x104 => ISENABLER: [ReadWrite; 31]), - (0x108 => _reserved2), + (0x180 => _reserved2), (0x820 => ITARGETSR: [ReadWrite; 248]), - (0x824 => @END), + (0xC00 => @END), } } @@ -65,7 +65,7 @@ register_structs! { (0x100 => ISENABLER: ReadWrite), (0x104 => _reserved2), (0x800 => ITARGETSR: [ReadOnly; 8]), - (0x804 => @END), + (0x820 => @END), } } diff --git a/17_kernel_symbols/Cargo.lock b/17_kernel_symbols/Cargo.lock index d52e3863..8c84705d 100644 --- a/17_kernel_symbols/Cargo.lock +++ b/17_kernel_symbols/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "cortex-a" -version = "7.5.0" +version = "8.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdecfbb28672ad3664e71ae05a398a52df430d86d660691501b28968cc4467e6" +checksum = "0cd4524931a4e0ec50ae91f0d55f571f31ffe11dd9ce2f9905b8343c018c25bb" dependencies = [ "tock-registers", ] @@ -36,9 +36,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.43" +version = "1.0.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a2ca2c61bc9f3d74d2886294ab7b9853abd9c1ad903a3ac7815c58989bb7bab" +checksum = "7bd7356a8122b6c4a24a82b278680c73357984ca2fc79a0f9fa6dea7dced7c58" dependencies = [ "unicode-ident", ] @@ -60,9 +60,9 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.100" +version = "1.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52205623b1b0f064a4e71182c3b18ae902267282930c6d5462c91b859668426e" +checksum = "e90cde112c4b9690b8cbe810cba9ddd8bc1d7472e2cae317b69e9438c1cba7d2" dependencies = [ "proc-macro2", "quote", @@ -85,9 +85,9 @@ version = "0.1.0" [[package]] name = "tock-registers" -version = "0.7.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ee8fba06c1f4d0b396ef61a54530bb6b28f0dc61c38bc8bc5a5a48161e6282e" +checksum = "696941a0aee7e276a165a978b37918fd5d22c55c3d6bda197813070ca9c0f21c" [[package]] name = "unicode-ident" diff --git a/17_kernel_symbols/README.md b/17_kernel_symbols/README.md index e88795ab..87264162 100644 --- a/17_kernel_symbols/README.md +++ b/17_kernel_symbols/README.md @@ -261,7 +261,7 @@ diff -uNr 16_virtual_mem_part4_higher_half_kernel/kernel/Cargo.toml 17_kernel_sy +debug-symbol-types = { path = "../libraries/debug-symbol-types" } # Optional dependencies - tock-registers = { version = "0.7.x", default-features = false, features = ["register_types"], optional = true } + tock-registers = { version = "0.8.x", default-features = false, features = ["register_types"], optional = true } diff -uNr 16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/exception.rs 17_kernel_symbols/kernel/src/_arch/aarch64/exception.rs --- 16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/exception.rs diff --git a/17_kernel_symbols/kernel/Cargo.toml b/17_kernel_symbols/kernel/Cargo.toml index c040d60c..a2a83aad 100644 --- a/17_kernel_symbols/kernel/Cargo.toml +++ b/17_kernel_symbols/kernel/Cargo.toml @@ -19,12 +19,12 @@ test-types = { path = "../libraries/test-types" } debug-symbol-types = { path = "../libraries/debug-symbol-types" } # Optional dependencies -tock-registers = { version = "0.7.x", default-features = false, features = ["register_types"], optional = true } +tock-registers = { version = "0.8.x", default-features = false, features = ["register_types"], optional = true } qemu-exit = { version = "3.x.x", optional = true } # Platform specific dependencies [target.'cfg(target_arch = "aarch64")'.dependencies] -cortex-a = { version = "7.x.x" } +cortex-a = { version = "8.x.x" } ##-------------------------------------------------------------------------------------------------- ## Testing diff --git a/17_kernel_symbols/kernel/src/_arch/aarch64/time.rs b/17_kernel_symbols/kernel/src/_arch/aarch64/time.rs index ad8ba84d..1e2efbec 100644 --- a/17_kernel_symbols/kernel/src/_arch/aarch64/time.rs +++ b/17_kernel_symbols/kernel/src/_arch/aarch64/time.rs @@ -120,7 +120,7 @@ impl TryFrom for GenericTimerCounterValue { #[inline(always)] fn read_cntpct() -> GenericTimerCounterValue { // Prevent that the counter is read ahead of time due to out-of-order execution. - unsafe { barrier::isb(barrier::SY) }; + barrier::isb(barrier::SY); let cnt = CNTPCT_EL0.get(); GenericTimerCounterValue(cnt) diff --git a/17_kernel_symbols/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs b/17_kernel_symbols/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs index d9f63d1b..a9c97a8e 100644 --- a/17_kernel_symbols/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs +++ b/17_kernel_symbols/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs @@ -52,9 +52,9 @@ register_structs! { (0x004 => TYPER: ReadOnly), (0x008 => _reserved1), (0x104 => ISENABLER: [ReadWrite; 31]), - (0x108 => _reserved2), + (0x180 => _reserved2), (0x820 => ITARGETSR: [ReadWrite; 248]), - (0x824 => @END), + (0xC00 => @END), } } @@ -65,7 +65,7 @@ register_structs! { (0x100 => ISENABLER: ReadWrite), (0x104 => _reserved2), (0x800 => ITARGETSR: [ReadOnly; 8]), - (0x804 => @END), + (0x820 => @END), } } diff --git a/18_backtrace/Cargo.lock b/18_backtrace/Cargo.lock index 82df825a..f662e8a6 100644 --- a/18_backtrace/Cargo.lock +++ b/18_backtrace/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "cortex-a" -version = "7.5.0" +version = "8.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdecfbb28672ad3664e71ae05a398a52df430d86d660691501b28968cc4467e6" +checksum = "0cd4524931a4e0ec50ae91f0d55f571f31ffe11dd9ce2f9905b8343c018c25bb" dependencies = [ "tock-registers", ] @@ -36,9 +36,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.43" +version = "1.0.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a2ca2c61bc9f3d74d2886294ab7b9853abd9c1ad903a3ac7815c58989bb7bab" +checksum = "7bd7356a8122b6c4a24a82b278680c73357984ca2fc79a0f9fa6dea7dced7c58" dependencies = [ "unicode-ident", ] @@ -60,9 +60,9 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.100" +version = "1.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52205623b1b0f064a4e71182c3b18ae902267282930c6d5462c91b859668426e" +checksum = "e90cde112c4b9690b8cbe810cba9ddd8bc1d7472e2cae317b69e9438c1cba7d2" dependencies = [ "proc-macro2", "quote", @@ -85,9 +85,9 @@ version = "0.1.0" [[package]] name = "tock-registers" -version = "0.7.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ee8fba06c1f4d0b396ef61a54530bb6b28f0dc61c38bc8bc5a5a48161e6282e" +checksum = "696941a0aee7e276a165a978b37918fd5d22c55c3d6bda197813070ca9c0f21c" [[package]] name = "unicode-ident" diff --git a/18_backtrace/kernel/Cargo.toml b/18_backtrace/kernel/Cargo.toml index 9e5f55be..5a443538 100644 --- a/18_backtrace/kernel/Cargo.toml +++ b/18_backtrace/kernel/Cargo.toml @@ -19,12 +19,12 @@ test-types = { path = "../libraries/test-types" } debug-symbol-types = { path = "../libraries/debug-symbol-types" } # Optional dependencies -tock-registers = { version = "0.7.x", default-features = false, features = ["register_types"], optional = true } +tock-registers = { version = "0.8.x", default-features = false, features = ["register_types"], optional = true } qemu-exit = { version = "3.x.x", optional = true } # Platform specific dependencies [target.'cfg(target_arch = "aarch64")'.dependencies] -cortex-a = { version = "7.x.x" } +cortex-a = { version = "8.x.x" } ##-------------------------------------------------------------------------------------------------- ## Testing diff --git a/18_backtrace/kernel/src/_arch/aarch64/time.rs b/18_backtrace/kernel/src/_arch/aarch64/time.rs index ad8ba84d..1e2efbec 100644 --- a/18_backtrace/kernel/src/_arch/aarch64/time.rs +++ b/18_backtrace/kernel/src/_arch/aarch64/time.rs @@ -120,7 +120,7 @@ impl TryFrom for GenericTimerCounterValue { #[inline(always)] fn read_cntpct() -> GenericTimerCounterValue { // Prevent that the counter is read ahead of time due to out-of-order execution. - unsafe { barrier::isb(barrier::SY) }; + barrier::isb(barrier::SY); let cnt = CNTPCT_EL0.get(); GenericTimerCounterValue(cnt) diff --git a/18_backtrace/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs b/18_backtrace/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs index d9f63d1b..a9c97a8e 100644 --- a/18_backtrace/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs +++ b/18_backtrace/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs @@ -52,9 +52,9 @@ register_structs! { (0x004 => TYPER: ReadOnly), (0x008 => _reserved1), (0x104 => ISENABLER: [ReadWrite; 31]), - (0x108 => _reserved2), + (0x180 => _reserved2), (0x820 => ITARGETSR: [ReadWrite; 248]), - (0x824 => @END), + (0xC00 => @END), } } @@ -65,7 +65,7 @@ register_structs! { (0x100 => ISENABLER: ReadWrite), (0x104 => _reserved2), (0x800 => ITARGETSR: [ReadOnly; 8]), - (0x804 => @END), + (0x820 => @END), } } diff --git a/19_kernel_heap/Cargo.lock b/19_kernel_heap/Cargo.lock index cc7a9c20..f8d4b6f8 100644 --- a/19_kernel_heap/Cargo.lock +++ b/19_kernel_heap/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "cortex-a" -version = "7.5.0" +version = "8.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdecfbb28672ad3664e71ae05a398a52df430d86d660691501b28968cc4467e6" +checksum = "0cd4524931a4e0ec50ae91f0d55f571f31ffe11dd9ce2f9905b8343c018c25bb" dependencies = [ "tock-registers", ] @@ -43,9 +43,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.43" +version = "1.0.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a2ca2c61bc9f3d74d2886294ab7b9853abd9c1ad903a3ac7815c58989bb7bab" +checksum = "7bd7356a8122b6c4a24a82b278680c73357984ca2fc79a0f9fa6dea7dced7c58" dependencies = [ "unicode-ident", ] @@ -67,9 +67,9 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.100" +version = "1.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52205623b1b0f064a4e71182c3b18ae902267282930c6d5462c91b859668426e" +checksum = "e90cde112c4b9690b8cbe810cba9ddd8bc1d7472e2cae317b69e9438c1cba7d2" dependencies = [ "proc-macro2", "quote", @@ -92,9 +92,9 @@ version = "0.1.0" [[package]] name = "tock-registers" -version = "0.7.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ee8fba06c1f4d0b396ef61a54530bb6b28f0dc61c38bc8bc5a5a48161e6282e" +checksum = "696941a0aee7e276a165a978b37918fd5d22c55c3d6bda197813070ca9c0f21c" [[package]] name = "unicode-ident" diff --git a/19_kernel_heap/README.md b/19_kernel_heap/README.md index b1463fc5..4eafd344 100644 --- a/19_kernel_heap/README.md +++ b/19_kernel_heap/README.md @@ -283,7 +283,7 @@ diff -uNr 18_backtrace/kernel/Cargo.toml 19_kernel_heap/kernel/Cargo.toml +linked_list_allocator = { version = "0.10.x", default-features = false, features = ["const_mut_refs"] } # Optional dependencies - tock-registers = { version = "0.7.x", default-features = false, features = ["register_types"], optional = true } + tock-registers = { version = "0.8.x", default-features = false, features = ["register_types"], optional = true } diff -uNr 18_backtrace/kernel/src/bsp/device_driver/arm/gicv2.rs 19_kernel_heap/kernel/src/bsp/device_driver/arm/gicv2.rs --- 18_backtrace/kernel/src/bsp/device_driver/arm/gicv2.rs diff --git a/19_kernel_heap/kernel/Cargo.toml b/19_kernel_heap/kernel/Cargo.toml index 61a16158..bccd0882 100644 --- a/19_kernel_heap/kernel/Cargo.toml +++ b/19_kernel_heap/kernel/Cargo.toml @@ -21,12 +21,12 @@ debug-symbol-types = { path = "../libraries/debug-symbol-types" } linked_list_allocator = { version = "0.10.x", default-features = false, features = ["const_mut_refs"] } # Optional dependencies -tock-registers = { version = "0.7.x", default-features = false, features = ["register_types"], optional = true } +tock-registers = { version = "0.8.x", default-features = false, features = ["register_types"], optional = true } qemu-exit = { version = "3.x.x", optional = true } # Platform specific dependencies [target.'cfg(target_arch = "aarch64")'.dependencies] -cortex-a = { version = "7.x.x" } +cortex-a = { version = "8.x.x" } ##-------------------------------------------------------------------------------------------------- ## Testing diff --git a/19_kernel_heap/kernel/src/_arch/aarch64/time.rs b/19_kernel_heap/kernel/src/_arch/aarch64/time.rs index ad8ba84d..1e2efbec 100644 --- a/19_kernel_heap/kernel/src/_arch/aarch64/time.rs +++ b/19_kernel_heap/kernel/src/_arch/aarch64/time.rs @@ -120,7 +120,7 @@ impl TryFrom for GenericTimerCounterValue { #[inline(always)] fn read_cntpct() -> GenericTimerCounterValue { // Prevent that the counter is read ahead of time due to out-of-order execution. - unsafe { barrier::isb(barrier::SY) }; + barrier::isb(barrier::SY); let cnt = CNTPCT_EL0.get(); GenericTimerCounterValue(cnt) diff --git a/19_kernel_heap/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs b/19_kernel_heap/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs index d9f63d1b..a9c97a8e 100644 --- a/19_kernel_heap/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs +++ b/19_kernel_heap/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs @@ -52,9 +52,9 @@ register_structs! { (0x004 => TYPER: ReadOnly), (0x008 => _reserved1), (0x104 => ISENABLER: [ReadWrite; 31]), - (0x108 => _reserved2), + (0x180 => _reserved2), (0x820 => ITARGETSR: [ReadWrite; 248]), - (0x824 => @END), + (0xC00 => @END), } } @@ -65,7 +65,7 @@ register_structs! { (0x100 => ISENABLER: ReadWrite), (0x104 => _reserved2), (0x800 => ITARGETSR: [ReadOnly; 8]), - (0x804 => @END), + (0x820 => @END), } } diff --git a/X1_JTAG_boot/Cargo.lock b/X1_JTAG_boot/Cargo.lock index 6e628b86..bcfb442a 100644 --- a/X1_JTAG_boot/Cargo.lock +++ b/X1_JTAG_boot/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "cortex-a" -version = "7.5.0" +version = "8.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdecfbb28672ad3664e71ae05a398a52df430d86d660691501b28968cc4467e6" +checksum = "0cd4524931a4e0ec50ae91f0d55f571f31ffe11dd9ce2f9905b8343c018c25bb" dependencies = [ "tock-registers", ] @@ -21,6 +21,6 @@ dependencies = [ [[package]] name = "tock-registers" -version = "0.7.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ee8fba06c1f4d0b396ef61a54530bb6b28f0dc61c38bc8bc5a5a48161e6282e" +checksum = "696941a0aee7e276a165a978b37918fd5d22c55c3d6bda197813070ca9c0f21c" diff --git a/X1_JTAG_boot/Cargo.toml b/X1_JTAG_boot/Cargo.toml index 638d4de1..55963c38 100644 --- a/X1_JTAG_boot/Cargo.toml +++ b/X1_JTAG_boot/Cargo.toml @@ -23,8 +23,8 @@ path = "src/main.rs" [dependencies] # Optional dependencies -tock-registers = { version = "0.7.x", default-features = false, features = ["register_types"], optional = true } +tock-registers = { version = "0.8.x", default-features = false, features = ["register_types"], optional = true } # Platform specific dependencies [target.'cfg(target_arch = "aarch64")'.dependencies] -cortex-a = { version = "7.x.x" } +cortex-a = { version = "8.x.x" } diff --git a/X1_JTAG_boot/jtag_boot_rpi3.img b/X1_JTAG_boot/jtag_boot_rpi3.img index 844015333d4c9c99ddbb059320b89f37229f2328..8c67b2dd87ca95ac69ab1567d94595d9cb5bc53f 100755 GIT binary patch delta 322 zcmccMe8PExE7NU;jqXB190yq@$}2Em<(ix*B+uA5xlw49$b|d$%vZG@SYPFIm>J|* zyu2vmp!Z~Z;b=zh$+Lx%#02#xzSU+}2~(8C%&;XJs6bf69;hH#q>b_5Pi5Fy{O|vC z5Sx=>MiA#rhMoCf{^l&nU?z432B2*W43qat+b}+x%qSx-_);2Z5fJczNd|_mn+;|9 hStg%Q2$0;M2$4FV0HIev`7b6LDyB0wOrEJ|4gj%_YEA$E delta 327 zcmX@%e8G8wD-$#0Mt310j)yE0J|* zyu2vmpu=Q);b=yO$+Lx%#J=iHe5=i{5~e7NnPE#dP=Th=ce);#F2dA6t+BT#&k*lNKCY!i8Y|DVpl$gmY;u|m+~JaH+$4j%>qW(Eck4hDt| z91AB;6K~|%zy&nG3u3@zWr9b#FQR#|NoZXZ?WUk&jxKaXP*7A9&JjdE zH#>boti;LMv6AsW(7-}wo>>%IAS-k;}v-iL3oZ=o;S zR2N+bzRg1yGwV`&J4#ANgUIvh>IULM3{2<+uX34kA*wWk@6nf-OjruU@Gm+}9eb`+ z`7pwFmW>Ci(2Z$llB2LjKA2$5V{pf0USt>X-(5y8#LqtFdpYnB=WVNF8WKoMV5xw96&bE zg~N>xksr@D4xw6H>+ty*;Oj``_*9Ri&eqDhhS4DKYiX#I35zP$8@VBT%HcvWoN@%y zqcPz14eBg1YHC05nnua0MjO~W0DS2JNXwhr6AySk!M0eXQJ$@d$|ai3-y~`QqLoBd zf6dTn>SMJRDgeB2ckV`Ac+xp?=!(Xd?}AkJfvhTKcdDpu`5>BiEry5>2ceQO zd@yf&*@+Je!j5nCgmoH8tM5SKa8hVI@}p`VtFLCsPQxJ49J;@k7?dW`(u`ry+c23X zlY?6ZWxi{ zEB*wr)yJ-)UrKvB$|%P|$TL5&iG(l*5A;Mry~4N=<9mju*~?req68E8HydZ}&Z<>0 zg77U)Mj7=jx6Gq}nzG+yP+8p)M^Ip~SJC@zBOsPL3b`^NKQtDUphH$lA(Yz~0wbTo zsX8|!gz-$>5SqeY>-=4VH{>Kh&nWFCgt#|Z$OmC6E)2@@x5Mmepwz$0v+!B~NC#yc zslSKD@j`tJd2p?>Bj5tjMl&ZD`xI@iHmC294S~2Z36(OPqWSk2+#P({=|(A>bcW7l z2SL;ov^iwt0#OhNVR9N_4V)MPv2+2H<-g>S4}2@ID+tSctoB2NQfVmmDKBUZAb6we zmQG;1)M$?#1(5}C^0b6c;a for GenericTimerCounterValue { #[inline(always)] fn read_cntpct() -> GenericTimerCounterValue { // Prevent that the counter is read ahead of time due to out-of-order execution. - unsafe { barrier::isb(barrier::SY) }; + barrier::isb(barrier::SY); let cnt = CNTPCT_EL0.get(); GenericTimerCounterValue(cnt) From 2e72a8408f65f86fc4234d2bf0d76c0ae2cdb78d Mon Sep 17 00:00:00 2001 From: Andre Richter Date: Sun, 23 Oct 2022 17:34:28 +0200 Subject: [PATCH 57/75] Rework driver subsystem This update significantly decouples the generic kernel code from the BSP code. Prior to this patch, the BSP had way too much business logic that should have always been the generic kernel's concern. --- 05_drivers_gpio_uart/README.md | 442 ++++++-- 05_drivers_gpio_uart/src/bsp/raspberrypi.rs | 1 - .../src/bsp/raspberrypi/driver.rs | 76 +- 05_drivers_gpio_uart/src/console.rs | 21 +- .../src/console/null_console.rs | 41 + 05_drivers_gpio_uart/src/driver.rs | 149 ++- 05_drivers_gpio_uart/src/main.rs | 22 +- 06_uart_chainloader/README.md | 87 +- 06_uart_chainloader/src/bsp/raspberrypi.rs | 1 - .../src/bsp/raspberrypi/console.rs | 16 - .../src/bsp/raspberrypi/driver.rs | 76 +- 06_uart_chainloader/src/console.rs | 21 +- .../src/console/null_console.rs | 41 + 06_uart_chainloader/src/driver.rs | 136 ++- 06_uart_chainloader/src/main.rs | 13 +- 07_timestamps/README.md | 108 +- 07_timestamps/src/bsp/raspberrypi.rs | 1 - 07_timestamps/src/bsp/raspberrypi/console.rs | 16 - 07_timestamps/src/bsp/raspberrypi/driver.rs | 87 +- 07_timestamps/src/console.rs | 21 +- 07_timestamps/src/console/null_console.rs | 41 + 07_timestamps/src/driver.rs | 149 ++- 07_timestamps/src/main.rs | 22 +- 08_hw_debug_JTAG/README.md | 22 + 08_hw_debug_JTAG/src/bsp/raspberrypi.rs | 1 - .../src/bsp/raspberrypi/console.rs | 16 - .../src/bsp/raspberrypi/driver.rs | 76 +- 08_hw_debug_JTAG/src/console.rs | 21 +- 08_hw_debug_JTAG/src/console/null_console.rs | 41 + 08_hw_debug_JTAG/src/driver.rs | 149 ++- 08_hw_debug_JTAG/src/main.rs | 22 +- 09_privilege_level/README.md | 12 +- 09_privilege_level/src/bsp/raspberrypi.rs | 1 - .../src/bsp/raspberrypi/console.rs | 16 - .../src/bsp/raspberrypi/driver.rs | 76 +- 09_privilege_level/src/console.rs | 21 +- .../src/console/null_console.rs | 41 + 09_privilege_level/src/driver.rs | 149 ++- 09_privilege_level/src/main.rs | 22 +- .../README.md | 19 +- .../src/bsp/raspberrypi.rs | 1 - .../src/bsp/raspberrypi/console.rs | 16 - .../src/bsp/raspberrypi/driver.rs | 76 +- .../src/console.rs | 21 +- .../src/console/null_console.rs | 41 + .../src/driver.rs | 149 ++- .../src/main.rs | 21 +- 11_exceptions_part1_groundwork/README.md | 8 +- .../src/bsp/raspberrypi.rs | 1 - .../src/bsp/raspberrypi/console.rs | 16 - .../src/bsp/raspberrypi/driver.rs | 76 +- 11_exceptions_part1_groundwork/src/console.rs | 21 +- .../src/console/null_console.rs | 41 + 11_exceptions_part1_groundwork/src/driver.rs | 149 ++- 11_exceptions_part1_groundwork/src/main.rs | 21 +- 12_integrated_testing/Makefile | 2 +- 12_integrated_testing/README.md | 34 +- .../kernel/src/bsp/raspberrypi.rs | 1 - .../kernel/src/bsp/raspberrypi/console.rs | 16 - .../kernel/src/bsp/raspberrypi/driver.rs | 84 +- 12_integrated_testing/kernel/src/console.rs | 21 +- .../kernel/src/console/null_console.rs | 41 + 12_integrated_testing/kernel/src/driver.rs | 152 ++- 12_integrated_testing/kernel/src/lib.rs | 4 +- 12_integrated_testing/kernel/src/main.rs | 21 +- .../kernel/tests/00_console_sanity.rs | 5 +- .../kernel/tests/01_timer_sanity.rs | 6 +- .../tests/02_exception_sync_page_fault.rs | 5 +- .../tests/03_exception_restore_sanity.rs | 5 +- 13_exceptions_part2_peripheral_IRQs/Makefile | 2 +- 13_exceptions_part2_peripheral_IRQs/README.md | 916 ++++++++++++----- .../kernel/src/bsp/device_driver/arm/gicv2.rs | 28 +- .../src/bsp/device_driver/arm/gicv2/gicd.rs | 2 +- .../src/bsp/device_driver/bcm/bcm2xxx_gpio.rs | 6 +- .../bcm/bcm2xxx_interrupt_controller.rs | 41 +- .../peripheral_ic.rs | 18 +- .../device_driver/bcm/bcm2xxx_pl011_uart.rs | 32 +- .../kernel/src/bsp/device_driver/common.rs | 28 +- .../kernel/src/bsp/raspberrypi.rs | 1 - .../kernel/src/bsp/raspberrypi/console.rs | 16 - .../kernel/src/bsp/raspberrypi/driver.rs | 127 ++- .../bsp/raspberrypi/exception/asynchronous.rs | 16 +- .../kernel/src/bsp/raspberrypi/memory.rs | 10 +- .../kernel/src/console.rs | 21 +- .../kernel/src/console/null_console.rs | 41 + .../kernel/src/driver.rs | 204 +++- .../kernel/src/exception/asynchronous.rs | 109 +- .../asynchronous/null_irq_manager.rs | 42 + .../kernel/src/lib.rs | 4 +- .../kernel/src/main.rs | 35 +- .../kernel/tests/00_console_sanity.rs | 5 +- .../kernel/tests/01_timer_sanity.rs | 6 +- .../tests/02_exception_sync_page_fault.rs | 5 +- .../tests/03_exception_restore_sanity.rs | 5 +- .../kernel/tests/04_exception_irq_sanity.rs | 5 +- 14_virtual_mem_part2_mmio_remap/Makefile | 2 +- 14_virtual_mem_part2_mmio_remap/README.md | 968 +++++------------- .../kernel/src/bsp/device_driver/arm/gicv2.rs | 32 +- .../src/bsp/device_driver/arm/gicv2/gicd.rs | 2 +- .../src/bsp/device_driver/bcm/bcm2xxx_gpio.rs | 13 +- .../bcm/bcm2xxx_interrupt_controller.rs | 52 +- .../peripheral_ic.rs | 18 +- .../device_driver/bcm/bcm2xxx_pl011_uart.rs | 34 +- .../kernel/src/bsp/device_driver/common.rs | 28 +- .../kernel/src/bsp/raspberrypi/driver.rs | 258 +++-- .../bsp/raspberrypi/exception/asynchronous.rs | 3 + .../kernel/src/driver.rs | 204 +++- .../kernel/src/exception/asynchronous.rs | 91 +- .../asynchronous/null_irq_manager.rs | 10 +- .../kernel/src/lib.rs | 4 +- .../kernel/src/main.rs | 33 +- .../kernel/tests/00_console_sanity.rs | 5 +- .../kernel/tests/01_timer_sanity.rs | 6 +- .../tests/02_exception_sync_page_fault.rs | 6 +- .../tests/03_exception_restore_sanity.rs | 6 +- .../kernel/tests/04_exception_irq_sanity.rs | 6 +- .../Makefile | 2 +- .../README.md | 64 +- .../kernel/src/bsp/device_driver/arm/gicv2.rs | 32 +- .../src/bsp/device_driver/arm/gicv2/gicd.rs | 2 +- .../src/bsp/device_driver/bcm/bcm2xxx_gpio.rs | 13 +- .../bcm/bcm2xxx_interrupt_controller.rs | 52 +- .../peripheral_ic.rs | 18 +- .../device_driver/bcm/bcm2xxx_pl011_uart.rs | 34 +- .../kernel/src/bsp/device_driver/common.rs | 28 +- .../kernel/src/bsp/raspberrypi/driver.rs | 258 +++-- .../bsp/raspberrypi/exception/asynchronous.rs | 3 + .../kernel/src/driver.rs | 204 +++- .../kernel/src/exception/asynchronous.rs | 91 +- .../asynchronous/null_irq_manager.rs | 10 +- .../kernel/src/lib.rs | 4 +- .../kernel/src/main.rs | 33 +- .../kernel/tests/00_console_sanity.rs | 5 +- .../kernel/tests/01_timer_sanity.rs | 6 +- .../tests/02_exception_sync_page_fault.rs | 6 +- .../tests/03_exception_restore_sanity.rs | 6 +- .../kernel/tests/04_exception_irq_sanity.rs | 6 +- .../Makefile | 2 +- .../README.md | 2 +- .../kernel/src/bsp/device_driver/arm/gicv2.rs | 32 +- .../src/bsp/device_driver/arm/gicv2/gicd.rs | 2 +- .../src/bsp/device_driver/bcm/bcm2xxx_gpio.rs | 13 +- .../bcm/bcm2xxx_interrupt_controller.rs | 52 +- .../peripheral_ic.rs | 18 +- .../device_driver/bcm/bcm2xxx_pl011_uart.rs | 34 +- .../kernel/src/bsp/device_driver/common.rs | 28 +- .../kernel/src/bsp/raspberrypi/driver.rs | 258 +++-- .../bsp/raspberrypi/exception/asynchronous.rs | 3 + .../kernel/src/driver.rs | 204 +++- .../kernel/src/exception/asynchronous.rs | 91 +- .../asynchronous/null_irq_manager.rs | 10 +- .../kernel/src/lib.rs | 4 +- .../kernel/src/main.rs | 33 +- .../kernel/tests/00_console_sanity.rs | 5 +- .../kernel/tests/01_timer_sanity.rs | 6 +- .../tests/02_exception_sync_page_fault.rs | 6 +- .../tests/03_exception_restore_sanity.rs | 6 +- .../kernel/tests/04_exception_irq_sanity.rs | 6 +- 17_kernel_symbols/Makefile | 2 +- .../kernel/src/bsp/device_driver/arm/gicv2.rs | 32 +- .../src/bsp/device_driver/arm/gicv2/gicd.rs | 2 +- .../src/bsp/device_driver/bcm/bcm2xxx_gpio.rs | 13 +- .../bcm/bcm2xxx_interrupt_controller.rs | 52 +- .../peripheral_ic.rs | 18 +- .../device_driver/bcm/bcm2xxx_pl011_uart.rs | 34 +- .../kernel/src/bsp/device_driver/common.rs | 28 +- .../kernel/src/bsp/raspberrypi/driver.rs | 258 +++-- .../bsp/raspberrypi/exception/asynchronous.rs | 3 + 17_kernel_symbols/kernel/src/driver.rs | 204 +++- .../kernel/src/exception/asynchronous.rs | 91 +- .../asynchronous/null_irq_manager.rs | 10 +- 17_kernel_symbols/kernel/src/lib.rs | 4 +- 17_kernel_symbols/kernel/src/main.rs | 33 +- .../kernel/tests/00_console_sanity.rs | 5 +- .../kernel/tests/01_timer_sanity.rs | 6 +- .../tests/02_exception_sync_page_fault.rs | 6 +- .../tests/03_exception_restore_sanity.rs | 6 +- .../kernel/tests/04_exception_irq_sanity.rs | 6 +- 18_backtrace/Makefile | 2 +- 18_backtrace/README.md | 37 +- .../kernel/src/bsp/device_driver/arm/gicv2.rs | 32 +- .../src/bsp/device_driver/arm/gicv2/gicd.rs | 2 +- .../src/bsp/device_driver/bcm/bcm2xxx_gpio.rs | 13 +- .../bcm/bcm2xxx_interrupt_controller.rs | 52 +- .../peripheral_ic.rs | 18 +- .../device_driver/bcm/bcm2xxx_pl011_uart.rs | 34 +- .../kernel/src/bsp/device_driver/common.rs | 28 +- .../kernel/src/bsp/raspberrypi/driver.rs | 258 +++-- .../bsp/raspberrypi/exception/asynchronous.rs | 3 + 18_backtrace/kernel/src/driver.rs | 204 +++- .../kernel/src/exception/asynchronous.rs | 91 +- .../asynchronous/null_irq_manager.rs | 10 +- 18_backtrace/kernel/src/lib.rs | 4 +- 18_backtrace/kernel/src/main.rs | 33 +- 18_backtrace/kernel/src/state.rs | 2 +- .../kernel/tests/00_console_sanity.rs | 5 +- 18_backtrace/kernel/tests/01_timer_sanity.rs | 6 +- .../tests/02_exception_sync_page_fault.rs | 6 +- .../tests/03_exception_restore_sanity.rs | 6 +- .../kernel/tests/04_exception_irq_sanity.rs | 6 +- .../kernel/tests/05_backtrace_sanity.rs | 6 +- .../tests/06_backtrace_invalid_frame.rs | 6 +- .../kernel/tests/07_backtrace_invalid_link.rs | 6 +- 19_kernel_heap/Makefile | 2 +- 19_kernel_heap/README.md | 363 +++++-- .../kernel/src/bsp/device_driver/arm/gicv2.rs | 31 +- .../src/bsp/device_driver/arm/gicv2/gicd.rs | 2 +- .../src/bsp/device_driver/bcm/bcm2xxx_gpio.rs | 13 +- .../bcm/bcm2xxx_interrupt_controller.rs | 48 +- .../peripheral_ic.rs | 17 +- .../device_driver/bcm/bcm2xxx_pl011_uart.rs | 34 +- .../kernel/src/bsp/device_driver/common.rs | 28 +- .../kernel/src/bsp/raspberrypi/driver.rs | 251 +++-- .../bsp/raspberrypi/exception/asynchronous.rs | 3 + 19_kernel_heap/kernel/src/driver.rs | 161 ++- .../kernel/src/exception/asynchronous.rs | 91 +- .../asynchronous/null_irq_manager.rs | 10 +- 19_kernel_heap/kernel/src/lib.rs | 4 +- 19_kernel_heap/kernel/src/main.rs | 33 +- .../kernel/src/memory/heap_alloc.rs | 10 + .../kernel/tests/00_console_sanity.rs | 5 +- .../kernel/tests/01_timer_sanity.rs | 6 +- .../tests/02_exception_sync_page_fault.rs | 6 +- .../tests/03_exception_restore_sanity.rs | 6 +- .../kernel/tests/04_exception_irq_sanity.rs | 6 +- .../kernel/tests/05_backtrace_sanity.rs | 6 +- .../tests/06_backtrace_invalid_frame.rs | 6 +- .../kernel/tests/07_backtrace_invalid_link.rs | 6 +- X1_JTAG_boot/src/bsp/raspberrypi.rs | 1 - X1_JTAG_boot/src/bsp/raspberrypi/console.rs | 16 - X1_JTAG_boot/src/bsp/raspberrypi/driver.rs | 76 +- X1_JTAG_boot/src/console.rs | 21 +- X1_JTAG_boot/src/console/null_console.rs | 41 + X1_JTAG_boot/src/driver.rs | 136 ++- X1_JTAG_boot/src/main.rs | 13 +- rust-toolchain.toml | 2 +- 236 files changed, 7448 insertions(+), 4235 deletions(-) create mode 100644 05_drivers_gpio_uart/src/console/null_console.rs delete mode 100644 06_uart_chainloader/src/bsp/raspberrypi/console.rs create mode 100644 06_uart_chainloader/src/console/null_console.rs delete mode 100644 07_timestamps/src/bsp/raspberrypi/console.rs create mode 100644 07_timestamps/src/console/null_console.rs delete mode 100644 08_hw_debug_JTAG/src/bsp/raspberrypi/console.rs create mode 100644 08_hw_debug_JTAG/src/console/null_console.rs delete mode 100644 09_privilege_level/src/bsp/raspberrypi/console.rs create mode 100644 09_privilege_level/src/console/null_console.rs delete mode 100644 10_virtual_mem_part1_identity_mapping/src/bsp/raspberrypi/console.rs create mode 100644 10_virtual_mem_part1_identity_mapping/src/console/null_console.rs delete mode 100644 11_exceptions_part1_groundwork/src/bsp/raspberrypi/console.rs create mode 100644 11_exceptions_part1_groundwork/src/console/null_console.rs delete mode 100644 12_integrated_testing/kernel/src/bsp/raspberrypi/console.rs create mode 100644 12_integrated_testing/kernel/src/console/null_console.rs delete mode 100644 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/console.rs create mode 100644 13_exceptions_part2_peripheral_IRQs/kernel/src/console/null_console.rs create mode 100644 13_exceptions_part2_peripheral_IRQs/kernel/src/exception/asynchronous/null_irq_manager.rs delete mode 100644 X1_JTAG_boot/src/bsp/raspberrypi/console.rs create mode 100644 X1_JTAG_boot/src/console/null_console.rs diff --git a/05_drivers_gpio_uart/README.md b/05_drivers_gpio_uart/README.md index cbd43e71..3fe5e7b2 100644 --- a/05_drivers_gpio_uart/README.md +++ b/05_drivers_gpio_uart/README.md @@ -2,35 +2,81 @@ ## tl;dr -- Now that we enabled safe globals in the previous tutorial, the infrastructure is laid for adding - the first real device drivers. -- We throw out the magic QEMU console and use a real `UART` now. Like serious embedded hackers do! - -## Notable additions - -- For the first time, we will be able to run the code on the real hardware. - - Therefore, building is now differentiated between the **RPi 3** and the **RPi4**. - - By default, all `Makefile` targets will build for the **RPi 3**. - - In order to build for the the **RPi4**, prepend `BSP=rpi4` to each target. For example: - - `BSP=rpi4 make` - - `BSP=rpi4 make doc` - - Unfortunately, QEMU does not yet support the **RPi4**, so `BSP=rpi4 make qemu` won't work. -- A `driver::interface::DeviceDriver` trait is added for abstracting `BSP` driver implementations - from kernel code. -- Drivers are stored in `src/bsp/device_driver`, and can be reused between `BSP`s. - - We introduce the `GPIO` driver, which pinmuxes (that is, routing signals from inside the `SoC` - to actual HW pins) the RPi's PL011 UART. - - Note how this driver differentiates between **RPi 3** and **RPi4**. Their HW is different, - so we have to account for it in SW. - - Most importantly, the `PL011Uart` driver: It implements the `console::interface::*` traits and - is from now on used as the main system console output. -- `BSP`s now contain a memory map in `src/bsp/raspberrypi/memory.rs`. In the specific case, they - contain the Raspberry's `MMIO` addresses which are used to instantiate the respective device - drivers. +- Drivers for the real `UART` and the `GPIO` controller are added. +- **For the first time, we will be able to run the code on the real hardware** (scroll down for + instructions). + +## Introduction + +Now that we enabled safe globals in the previous tutorial, the infrastructure is laid for adding the +first real device drivers. We throw out the magic QEMU console and introduce a `driver manager`, +which allows the `BSP` to register device drivers with the `kernel`. + +## Driver Manager + +The first step consists of adding a `driver subsystem` to the kernel. The corresponding code will +live in `src/driver.rs`. The subsystem introduces `interface::DeviceDriver`, a common trait that +every device driver will need to implement and that is known to the kernel. A global +`DRIVER_MANAGER` instance (of type `DriverManager`) that is instantiated in the same file serves as +the central entity that can be called to manage all things device drivers in the kernel. For +example, by using the globally accessible `crate::driver::driver_manager().register_driver(...)`, +any code can can register an object with static lifetime that implements the +`interface::DeviceDriver` trait. + +During kernel init, a call to `crate::driver::driver_manager().init_drivers(...)` will let the +driver manager loop over all registered drivers and kick off their initialization, and also execute +an optional `post-init callback` that can be registered alongside the driver. For example, this +mechanism is used to switch over to the `UART` driver as the main system console after the `UART` +driver has been initialized. + +## BSP Driver Implementation + +In `src/bsp/raspberrypi/driver.rs`, the function `init()` takes care of registering the `UART` and +`GPIO` drivers. It is therefore important that during kernel init, the correct order of (i) first +initializing the BSP driver subsystem, and only then (ii) calling the `driver_manager()` is +followed, like the following excerpt from `main.rs` shows: + +```rust +unsafe fn kernel_init() -> ! { + // Initialize the BSP driver subsystem. + if let Err(x) = bsp::driver::init() { + panic!("Error initializing BSP driver subsystem: {}", x); + } + + // Initialize all device drivers. + driver::driver_manager().init_drivers(); + // println! is usable from here on. +``` + + + +The drivers themselves are stored in `src/bsp/device_driver`, and can be reused between `BSP`s. The +first driver added in these tutorials is the `PL011Uart` driver: It implements the +`console::interface::*` traits and is from now on used as the main system console. The second driver +is the `GPIO` driver, which pinmuxes (that is, routing signals from inside the `SoC` to actual HW +pins) the RPi's PL011 UART accordingly. Note how the `GPIO` driver differentiates between **RPi3** +and **RPi4**. Their HW is different, so we have to account for it in SW. + +The `BSP`s now also contain a memory map in `src/bsp/raspberrypi/memory.rs`. It provides the +Raspberry's `MMIO` addresses which are used by the `BSP` to instantiate the respective device +drivers, so that the driver code knows where to find the device's registers in memory. ## Boot it from SD card -Some steps for preparing the SD card differ between RPi3 and RPi4, so be careful. +Since we have real `UART` output now, we can run the code on the real hardware. Building is +differentiated between the **RPi 3** and the **RPi4** due to before mentioned differences in the +`GPIO` driver. By default, all `Makefile` targets will build for the **RPi 3**. In order to build +for the the **RPi4**, prepend `BSP=rpi4` to each target. For example: + +```console +$ BSP=rpi4 make +$ BSP=rpi4 make doc +``` + +Unfortunately, QEMU does not yet support the **RPi4**, so `BSP=rpi4 make qemu` won't work. + +**Some steps for preparing the SD card differ between RPi3 and RPi4, so be careful in the +following.** ### Common for both @@ -1072,7 +1118,7 @@ diff -uNr 04_safe_globals/src/bsp/raspberrypi/console.rs 05_drivers_gpio_uart/sr diff -uNr 04_safe_globals/src/bsp/raspberrypi/driver.rs 05_drivers_gpio_uart/src/bsp/raspberrypi/driver.rs --- 04_safe_globals/src/bsp/raspberrypi/driver.rs +++ 05_drivers_gpio_uart/src/bsp/raspberrypi/driver.rs -@@ -0,0 +1,55 @@ +@@ -0,0 +1,71 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2018-2022 Andre Richter @@ -1080,53 +1126,69 @@ diff -uNr 04_safe_globals/src/bsp/raspberrypi/driver.rs 05_drivers_gpio_uart/src +//! BSP driver support. + +use super::memory::map::mmio; -+use crate::{bsp::device_driver, driver}; ++use crate::{bsp::device_driver, console, driver as generic_driver}; ++use core::sync::atomic::{AtomicBool, Ordering}; + +//-------------------------------------------------------------------------------------------------- -+// Private Definitions ++// Global instances +//-------------------------------------------------------------------------------------------------- + -+/// Device Driver Manager type. -+struct BSPDriverManager { -+ device_drivers: [&'static (dyn DeviceDriver + Sync); 2], -+} ++static PL011_UART: device_driver::PL011Uart = ++ unsafe { device_driver::PL011Uart::new(mmio::PL011_UART_START) }; ++static GPIO: device_driver::GPIO = unsafe { device_driver::GPIO::new(mmio::GPIO_START) }; + +//-------------------------------------------------------------------------------------------------- -+// Global instances ++// Private Code +//-------------------------------------------------------------------------------------------------- + -+pub(super) static PL011_UART: device_driver::PL011Uart = -+ unsafe { device_driver::PL011Uart::new(mmio::PL011_UART_START) }; ++/// This must be called only after successful init of the UART driver. ++fn post_init_uart() -> Result<(), &'static str> { ++ console::register_console(&PL011_UART); + -+static GPIO: device_driver::GPIO = unsafe { device_driver::GPIO::new(mmio::GPIO_START) }; ++ Ok(()) ++} + -+static BSP_DRIVER_MANAGER: BSPDriverManager = BSPDriverManager { -+ device_drivers: [&PL011_UART, &GPIO], -+}; ++/// This must be called only after successful init of the GPIO driver. ++fn post_init_gpio() -> Result<(), &'static str> { ++ GPIO.map_pl011_uart(); ++ Ok(()) ++} + -+//-------------------------------------------------------------------------------------------------- -+// Public Code -+//-------------------------------------------------------------------------------------------------- ++fn driver_uart() -> Result<(), &'static str> { ++ let uart_descriptor = ++ generic_driver::DeviceDriverDescriptor::new(&PL011_UART, Some(post_init_uart)); ++ generic_driver::driver_manager().register_driver(uart_descriptor); + -+/// Return a reference to the driver manager. -+pub fn driver_manager() -> &'static impl driver::interface::DriverManager { -+ &BSP_DRIVER_MANAGER ++ Ok(()) +} + -+//------------------------------------------------------------------------------ -+// OS Interface Code -+//------------------------------------------------------------------------------ -+use driver::interface::DeviceDriver; ++fn driver_gpio() -> Result<(), &'static str> { ++ let gpio_descriptor = generic_driver::DeviceDriverDescriptor::new(&GPIO, Some(post_init_gpio)); ++ generic_driver::driver_manager().register_driver(gpio_descriptor); + -+impl driver::interface::DriverManager for BSPDriverManager { -+ fn all_device_drivers(&self) -> &[&'static (dyn DeviceDriver + Sync)] { -+ &self.device_drivers[..] -+ } ++ Ok(()) ++} + -+ fn post_device_driver_init(&self) { -+ // Configure PL011Uart's output pins. -+ GPIO.map_pl011_uart(); ++//-------------------------------------------------------------------------------------------------- ++// Public Code ++//-------------------------------------------------------------------------------------------------- ++ ++/// Initialize the driver subsystem. ++/// ++/// # Safety ++/// ++/// See child function calls. ++pub unsafe fn init() -> Result<(), &'static str> { ++ static INIT_DONE: AtomicBool = AtomicBool::new(false); ++ if INIT_DONE.load(Ordering::Relaxed) { ++ return Err("Init already done"); + } ++ ++ driver_uart()?; ++ driver_gpio()?; ++ ++ INIT_DONE.store(true, Ordering::Relaxed); ++ Ok(()) +} diff -uNr 04_safe_globals/src/bsp/raspberrypi/memory.rs 05_drivers_gpio_uart/src/bsp/raspberrypi/memory.rs @@ -1174,9 +1236,11 @@ diff -uNr 04_safe_globals/src/bsp/raspberrypi/memory.rs 05_drivers_gpio_uart/src diff -uNr 04_safe_globals/src/bsp/raspberrypi.rs 05_drivers_gpio_uart/src/bsp/raspberrypi.rs --- 04_safe_globals/src/bsp/raspberrypi.rs +++ 05_drivers_gpio_uart/src/bsp/raspberrypi.rs -@@ -6,3 +6,22 @@ +@@ -4,5 +4,23 @@ + + //! Top-level BSP file for the Raspberry Pi 3 and 4. - pub mod console; +-pub mod console; pub mod cpu; +pub mod driver; +pub mod memory; @@ -1211,10 +1275,67 @@ diff -uNr 04_safe_globals/src/bsp.rs 05_drivers_gpio_uart/src/bsp.rs mod raspberrypi; +diff -uNr 04_safe_globals/src/console/null_console.rs 05_drivers_gpio_uart/src/console/null_console.rs +--- 04_safe_globals/src/console/null_console.rs ++++ 05_drivers_gpio_uart/src/console/null_console.rs +@@ -0,0 +1,41 @@ ++// SPDX-License-Identifier: MIT OR Apache-2.0 ++// ++// Copyright (c) 2022 Andre Richter ++ ++//! Null console. ++ ++use super::interface; ++use core::fmt; ++ ++//-------------------------------------------------------------------------------------------------- ++// Public Definitions ++//-------------------------------------------------------------------------------------------------- ++ ++pub struct NullConsole; ++ ++//-------------------------------------------------------------------------------------------------- ++// Global instances ++//-------------------------------------------------------------------------------------------------- ++ ++pub static NULL_CONSOLE: NullConsole = NullConsole {}; ++ ++//-------------------------------------------------------------------------------------------------- ++// Public Code ++//-------------------------------------------------------------------------------------------------- ++ ++impl interface::Write for NullConsole { ++ fn write_char(&self, _c: char) {} ++ ++ fn write_fmt(&self, _args: fmt::Arguments) -> fmt::Result { ++ fmt::Result::Ok(()) ++ } ++ ++ fn flush(&self) {} ++} ++ ++impl interface::Read for NullConsole { ++ fn clear_rx(&self) {} ++} ++ ++impl interface::Statistics for NullConsole {} ++impl interface::All for NullConsole {} + diff -uNr 04_safe_globals/src/console.rs 05_drivers_gpio_uart/src/console.rs --- 04_safe_globals/src/console.rs +++ 05_drivers_gpio_uart/src/console.rs -@@ -16,8 +16,25 @@ +@@ -4,7 +4,9 @@ + + //! System console. + +-use crate::bsp; ++mod null_console; ++ ++use crate::synchronization::{self, NullLock}; + + //-------------------------------------------------------------------------------------------------- + // Public Definitions +@@ -16,8 +18,25 @@ /// Console write functions. pub trait Write { @@ -1240,7 +1361,7 @@ diff -uNr 04_safe_globals/src/console.rs 05_drivers_gpio_uart/src/console.rs } /// Console statistics. -@@ -26,10 +43,15 @@ +@@ -26,19 +45,37 @@ fn chars_written(&self) -> usize { 0 } @@ -1257,6 +1378,30 @@ diff -uNr 04_safe_globals/src/console.rs 05_drivers_gpio_uart/src/console.rs } //-------------------------------------------------------------------------------------------------- ++// Global instances ++//-------------------------------------------------------------------------------------------------- ++ ++static CUR_CONSOLE: NullLock<&'static (dyn interface::All + Sync)> = ++ NullLock::new(&null_console::NULL_CONSOLE); ++ ++//-------------------------------------------------------------------------------------------------- + // Public Code + //-------------------------------------------------------------------------------------------------- ++use synchronization::interface::Mutex; ++ ++/// Register a new console. ++pub fn register_console(new_console: &'static (dyn interface::All + Sync)) { ++ CUR_CONSOLE.lock(|con| *con = new_console); ++} + +-/// Return a reference to the console. ++/// Return a reference to the currently registered console. + /// + /// This is the global console used by all printing macros. + pub fn console() -> &'static dyn interface::All { +- bsp::console::console() ++ CUR_CONSOLE.lock(|con| *con) + } diff -uNr 04_safe_globals/src/cpu.rs 05_drivers_gpio_uart/src/cpu.rs --- 04_safe_globals/src/cpu.rs @@ -1274,13 +1419,29 @@ diff -uNr 04_safe_globals/src/cpu.rs 05_drivers_gpio_uart/src/cpu.rs diff -uNr 04_safe_globals/src/driver.rs 05_drivers_gpio_uart/src/driver.rs --- 04_safe_globals/src/driver.rs +++ 05_drivers_gpio_uart/src/driver.rs -@@ -0,0 +1,44 @@ +@@ -0,0 +1,167 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2018-2022 Andre Richter + +//! Driver support. + ++use crate::{ ++ println, ++ synchronization::{interface::Mutex, NullLock}, ++}; ++ ++//-------------------------------------------------------------------------------------------------- ++// Private Definitions ++//-------------------------------------------------------------------------------------------------- ++ ++const NUM_DRIVERS: usize = 5; ++ ++struct DriverManagerInner { ++ next_index: usize, ++ descriptors: [Option; NUM_DRIVERS], ++} ++ +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- @@ -1301,22 +1462,129 @@ diff -uNr 04_safe_globals/src/driver.rs 05_drivers_gpio_uart/src/driver.rs + Ok(()) + } + } ++} ++ ++/// Tpye to be used as an optional callback after a driver's init() has run. ++pub type DeviceDriverPostInitCallback = unsafe fn() -> Result<(), &'static str>; ++ ++/// A descriptor for device drivers. ++#[derive(Copy, Clone)] ++pub struct DeviceDriverDescriptor { ++ device_driver: &'static (dyn interface::DeviceDriver + Sync), ++ post_init_callback: Option, ++} ++ ++/// Provides device driver management functions. ++pub struct DriverManager { ++ inner: NullLock, ++} ++ ++//-------------------------------------------------------------------------------------------------- ++// Global instances ++//-------------------------------------------------------------------------------------------------- ++ ++static DRIVER_MANAGER: DriverManager = DriverManager::new(); ++ ++//-------------------------------------------------------------------------------------------------- ++// Private Code ++//-------------------------------------------------------------------------------------------------- ++ ++impl DriverManagerInner { ++ /// Create an instance. ++ pub const fn new() -> Self { ++ Self { ++ next_index: 0, ++ descriptors: [None; NUM_DRIVERS], ++ } ++ } ++} ++ ++//-------------------------------------------------------------------------------------------------- ++// Public Code ++//-------------------------------------------------------------------------------------------------- ++ ++impl DeviceDriverDescriptor { ++ /// Create an instance. ++ pub fn new( ++ device_driver: &'static (dyn interface::DeviceDriver + Sync), ++ post_init_callback: Option, ++ ) -> Self { ++ Self { ++ device_driver, ++ post_init_callback, ++ } ++ } ++} ++ ++/// Return a reference to the global DriverManager. ++pub fn driver_manager() -> &'static DriverManager { ++ &DRIVER_MANAGER ++} ++ ++impl DriverManager { ++ /// Create an instance. ++ pub const fn new() -> Self { ++ Self { ++ inner: NullLock::new(DriverManagerInner::new()), ++ } ++ } ++ ++ /// Register a device driver with the kernel. ++ pub fn register_driver(&self, descriptor: DeviceDriverDescriptor) { ++ self.inner.lock(|inner| { ++ inner.descriptors[inner.next_index] = Some(descriptor); ++ inner.next_index += 1; ++ }) ++ } ++ ++ /// Helper for iterating over registered drivers. ++ fn for_each_descriptor<'a>(&'a self, f: impl FnMut(&'a DeviceDriverDescriptor)) { ++ self.inner.lock(|inner| { ++ inner ++ .descriptors ++ .iter() ++ .filter_map(|x| x.as_ref()) ++ .for_each(f) ++ }) ++ } + -+ /// Device driver management functions. ++ /// Fully initialize all drivers. + /// -+ /// The `BSP` is supposed to supply one global instance. -+ pub trait DriverManager { -+ /// Return a slice of references to all `BSP`-instantiated drivers. -+ /// -+ /// # Safety -+ /// -+ /// - The order of devices is the order in which `DeviceDriver::init()` is called. -+ fn all_device_drivers(&self) -> &[&'static (dyn DeviceDriver + Sync)]; ++ /// # Safety ++ /// ++ /// - During init, drivers might do stuff with system-wide impact. ++ pub unsafe fn init_drivers(&self) { ++ self.for_each_descriptor(|descriptor| { ++ // 1. Initialize driver. ++ if let Err(x) = descriptor.device_driver.init() { ++ panic!( ++ "Error initializing driver: {}: {}", ++ descriptor.device_driver.compatible(), ++ x ++ ); ++ } + -+ /// Initialization code that runs after driver init. -+ /// -+ /// For example, device driver code that depends on other drivers already being online. -+ fn post_device_driver_init(&self); ++ // 2. Call corresponding post init callback. ++ if let Some(callback) = &descriptor.post_init_callback { ++ if let Err(x) = callback() { ++ panic!( ++ "Error during driver post-init callback: {}: {}", ++ descriptor.device_driver.compatible(), ++ x ++ ); ++ } ++ } ++ }); ++ } ++ ++ /// Enumerate all registered device drivers. ++ pub fn enumerate(&self) { ++ let mut i: usize = 1; ++ self.for_each_descriptor(|descriptor| { ++ println!(" {}. {}", i, descriptor.device_driver.compatible()); ++ ++ i += 1; ++ }); + } +} @@ -1339,21 +1607,20 @@ diff -uNr 04_safe_globals/src/main.rs 05_drivers_gpio_uart/src/main.rs mod panic_wait; mod print; mod synchronization; -@@ -125,13 +127,50 @@ +@@ -125,13 +127,42 @@ /// # Safety /// /// - Only a single core must be active and running this function. +/// - The init calls in this function must appear in the correct order. unsafe fn kernel_init() -> ! { - use console::console; -+ use driver::interface::DriverManager; -+ -+ for i in bsp::driver::driver_manager().all_device_drivers().iter() { -+ if let Err(x) = i.init() { -+ panic!("Error loading driver: {}: {}", i.compatible(), x); -+ } ++ // Initialize the BSP driver subsystem. ++ if let Err(x) = bsp::driver::init() { ++ panic!("Error initializing BSP driver subsystem: {}", x); + } -+ bsp::driver::driver_manager().post_device_driver_init(); ++ ++ // Initialize all device drivers. ++ driver::driver_manager().init_drivers(); + // println! is usable from here on. - println!("[0] Hello from Rust!"); @@ -1365,7 +1632,6 @@ diff -uNr 04_safe_globals/src/main.rs 05_drivers_gpio_uart/src/main.rs +/// The main function running after the early init. +fn kernel_main() -> ! { + use console::console; -+ use driver::interface::DriverManager; - println!("[2] Stopping here."); - cpu::wait_forever() @@ -1377,13 +1643,7 @@ diff -uNr 04_safe_globals/src/main.rs 05_drivers_gpio_uart/src/main.rs + println!("[1] Booting on: {}", bsp::board_name()); + + println!("[2] Drivers loaded:"); -+ for (i, driver) in bsp::driver::driver_manager() -+ .all_device_drivers() -+ .iter() -+ .enumerate() -+ { -+ println!(" {}. {}", i + 1, driver.compatible()); -+ } ++ driver::driver_manager().enumerate(); + + println!("[3] Chars written: {}", console().chars_written()); + println!("[4] Echoing input now"); diff --git a/05_drivers_gpio_uart/src/bsp/raspberrypi.rs b/05_drivers_gpio_uart/src/bsp/raspberrypi.rs index a9a7261a..fe940677 100644 --- a/05_drivers_gpio_uart/src/bsp/raspberrypi.rs +++ b/05_drivers_gpio_uart/src/bsp/raspberrypi.rs @@ -4,7 +4,6 @@ //! Top-level BSP file for the Raspberry Pi 3 and 4. -pub mod console; pub mod cpu; pub mod driver; pub mod memory; diff --git a/05_drivers_gpio_uart/src/bsp/raspberrypi/driver.rs b/05_drivers_gpio_uart/src/bsp/raspberrypi/driver.rs index 8b683ed8..ea843066 100644 --- a/05_drivers_gpio_uart/src/bsp/raspberrypi/driver.rs +++ b/05_drivers_gpio_uart/src/bsp/raspberrypi/driver.rs @@ -5,51 +5,67 @@ //! BSP driver support. use super::memory::map::mmio; -use crate::{bsp::device_driver, driver}; +use crate::{bsp::device_driver, console, driver as generic_driver}; +use core::sync::atomic::{AtomicBool, Ordering}; //-------------------------------------------------------------------------------------------------- -// Private Definitions +// Global instances //-------------------------------------------------------------------------------------------------- -/// Device Driver Manager type. -struct BSPDriverManager { - device_drivers: [&'static (dyn DeviceDriver + Sync); 2], -} +static PL011_UART: device_driver::PL011Uart = + unsafe { device_driver::PL011Uart::new(mmio::PL011_UART_START) }; +static GPIO: device_driver::GPIO = unsafe { device_driver::GPIO::new(mmio::GPIO_START) }; //-------------------------------------------------------------------------------------------------- -// Global instances +// Private Code //-------------------------------------------------------------------------------------------------- -pub(super) static PL011_UART: device_driver::PL011Uart = - unsafe { device_driver::PL011Uart::new(mmio::PL011_UART_START) }; +/// This must be called only after successful init of the UART driver. +fn post_init_uart() -> Result<(), &'static str> { + console::register_console(&PL011_UART); -static GPIO: device_driver::GPIO = unsafe { device_driver::GPIO::new(mmio::GPIO_START) }; + Ok(()) +} -static BSP_DRIVER_MANAGER: BSPDriverManager = BSPDriverManager { - device_drivers: [&PL011_UART, &GPIO], -}; +/// This must be called only after successful init of the GPIO driver. +fn post_init_gpio() -> Result<(), &'static str> { + GPIO.map_pl011_uart(); + Ok(()) +} -//-------------------------------------------------------------------------------------------------- -// Public Code -//-------------------------------------------------------------------------------------------------- +fn driver_uart() -> Result<(), &'static str> { + let uart_descriptor = + generic_driver::DeviceDriverDescriptor::new(&PL011_UART, Some(post_init_uart)); + generic_driver::driver_manager().register_driver(uart_descriptor); -/// Return a reference to the driver manager. -pub fn driver_manager() -> &'static impl driver::interface::DriverManager { - &BSP_DRIVER_MANAGER + Ok(()) } -//------------------------------------------------------------------------------ -// OS Interface Code -//------------------------------------------------------------------------------ -use driver::interface::DeviceDriver; +fn driver_gpio() -> Result<(), &'static str> { + let gpio_descriptor = generic_driver::DeviceDriverDescriptor::new(&GPIO, Some(post_init_gpio)); + generic_driver::driver_manager().register_driver(gpio_descriptor); -impl driver::interface::DriverManager for BSPDriverManager { - fn all_device_drivers(&self) -> &[&'static (dyn DeviceDriver + Sync)] { - &self.device_drivers[..] - } + Ok(()) +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- - fn post_device_driver_init(&self) { - // Configure PL011Uart's output pins. - GPIO.map_pl011_uart(); +/// Initialize the driver subsystem. +/// +/// # Safety +/// +/// See child function calls. +pub unsafe fn init() -> Result<(), &'static str> { + static INIT_DONE: AtomicBool = AtomicBool::new(false); + if INIT_DONE.load(Ordering::Relaxed) { + return Err("Init already done"); } + + driver_uart()?; + driver_gpio()?; + + INIT_DONE.store(true, Ordering::Relaxed); + Ok(()) } diff --git a/05_drivers_gpio_uart/src/console.rs b/05_drivers_gpio_uart/src/console.rs index c1fb0e53..02b43df9 100644 --- a/05_drivers_gpio_uart/src/console.rs +++ b/05_drivers_gpio_uart/src/console.rs @@ -4,7 +4,9 @@ //! System console. -use crate::bsp; +mod null_console; + +use crate::synchronization::{self, NullLock}; //-------------------------------------------------------------------------------------------------- // Public Definitions @@ -54,13 +56,26 @@ pub mod interface { pub trait All: Write + Read + Statistics {} } +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +static CUR_CONSOLE: NullLock<&'static (dyn interface::All + Sync)> = + NullLock::new(&null_console::NULL_CONSOLE); + //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- +use synchronization::interface::Mutex; + +/// Register a new console. +pub fn register_console(new_console: &'static (dyn interface::All + Sync)) { + CUR_CONSOLE.lock(|con| *con = new_console); +} -/// Return a reference to the console. +/// Return a reference to the currently registered console. /// /// This is the global console used by all printing macros. pub fn console() -> &'static dyn interface::All { - bsp::console::console() + CUR_CONSOLE.lock(|con| *con) } diff --git a/05_drivers_gpio_uart/src/console/null_console.rs b/05_drivers_gpio_uart/src/console/null_console.rs new file mode 100644 index 00000000..2c64d499 --- /dev/null +++ b/05_drivers_gpio_uart/src/console/null_console.rs @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2022 Andre Richter + +//! Null console. + +use super::interface; +use core::fmt; + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +pub struct NullConsole; + +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +pub static NULL_CONSOLE: NullConsole = NullConsole {}; + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +impl interface::Write for NullConsole { + fn write_char(&self, _c: char) {} + + fn write_fmt(&self, _args: fmt::Arguments) -> fmt::Result { + fmt::Result::Ok(()) + } + + fn flush(&self) {} +} + +impl interface::Read for NullConsole { + fn clear_rx(&self) {} +} + +impl interface::Statistics for NullConsole {} +impl interface::All for NullConsole {} diff --git a/05_drivers_gpio_uart/src/driver.rs b/05_drivers_gpio_uart/src/driver.rs index 2fcc7562..e324ecf8 100644 --- a/05_drivers_gpio_uart/src/driver.rs +++ b/05_drivers_gpio_uart/src/driver.rs @@ -4,6 +4,22 @@ //! Driver support. +use crate::{ + println, + synchronization::{interface::Mutex, NullLock}, +}; + +//-------------------------------------------------------------------------------------------------- +// Private Definitions +//-------------------------------------------------------------------------------------------------- + +const NUM_DRIVERS: usize = 5; + +struct DriverManagerInner { + next_index: usize, + descriptors: [Option; NUM_DRIVERS], +} + //-------------------------------------------------------------------------------------------------- // Public Definitions //-------------------------------------------------------------------------------------------------- @@ -24,21 +40,128 @@ pub mod interface { Ok(()) } } +} + +/// Tpye to be used as an optional callback after a driver's init() has run. +pub type DeviceDriverPostInitCallback = unsafe fn() -> Result<(), &'static str>; + +/// A descriptor for device drivers. +#[derive(Copy, Clone)] +pub struct DeviceDriverDescriptor { + device_driver: &'static (dyn interface::DeviceDriver + Sync), + post_init_callback: Option, +} + +/// Provides device driver management functions. +pub struct DriverManager { + inner: NullLock, +} + +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +static DRIVER_MANAGER: DriverManager = DriverManager::new(); + +//-------------------------------------------------------------------------------------------------- +// Private Code +//-------------------------------------------------------------------------------------------------- + +impl DriverManagerInner { + /// Create an instance. + pub const fn new() -> Self { + Self { + next_index: 0, + descriptors: [None; NUM_DRIVERS], + } + } +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +impl DeviceDriverDescriptor { + /// Create an instance. + pub fn new( + device_driver: &'static (dyn interface::DeviceDriver + Sync), + post_init_callback: Option, + ) -> Self { + Self { + device_driver, + post_init_callback, + } + } +} + +/// Return a reference to the global DriverManager. +pub fn driver_manager() -> &'static DriverManager { + &DRIVER_MANAGER +} + +impl DriverManager { + /// Create an instance. + pub const fn new() -> Self { + Self { + inner: NullLock::new(DriverManagerInner::new()), + } + } - /// Device driver management functions. + /// Register a device driver with the kernel. + pub fn register_driver(&self, descriptor: DeviceDriverDescriptor) { + self.inner.lock(|inner| { + inner.descriptors[inner.next_index] = Some(descriptor); + inner.next_index += 1; + }) + } + + /// Helper for iterating over registered drivers. + fn for_each_descriptor<'a>(&'a self, f: impl FnMut(&'a DeviceDriverDescriptor)) { + self.inner.lock(|inner| { + inner + .descriptors + .iter() + .filter_map(|x| x.as_ref()) + .for_each(f) + }) + } + + /// Fully initialize all drivers. /// - /// The `BSP` is supposed to supply one global instance. - pub trait DriverManager { - /// Return a slice of references to all `BSP`-instantiated drivers. - /// - /// # Safety - /// - /// - The order of devices is the order in which `DeviceDriver::init()` is called. - fn all_device_drivers(&self) -> &[&'static (dyn DeviceDriver + Sync)]; + /// # Safety + /// + /// - During init, drivers might do stuff with system-wide impact. + pub unsafe fn init_drivers(&self) { + self.for_each_descriptor(|descriptor| { + // 1. Initialize driver. + if let Err(x) = descriptor.device_driver.init() { + panic!( + "Error initializing driver: {}: {}", + descriptor.device_driver.compatible(), + x + ); + } - /// Initialization code that runs after driver init. - /// - /// For example, device driver code that depends on other drivers already being online. - fn post_device_driver_init(&self); + // 2. Call corresponding post init callback. + if let Some(callback) = &descriptor.post_init_callback { + if let Err(x) = callback() { + panic!( + "Error during driver post-init callback: {}: {}", + descriptor.device_driver.compatible(), + x + ); + } + } + }); + } + + /// Enumerate all registered device drivers. + pub fn enumerate(&self) { + let mut i: usize = 1; + self.for_each_descriptor(|descriptor| { + println!(" {}. {}", i, descriptor.device_driver.compatible()); + + i += 1; + }); } } diff --git a/05_drivers_gpio_uart/src/main.rs b/05_drivers_gpio_uart/src/main.rs index c9b73382..9d158238 100644 --- a/05_drivers_gpio_uart/src/main.rs +++ b/05_drivers_gpio_uart/src/main.rs @@ -129,14 +129,13 @@ mod synchronization; /// - Only a single core must be active and running this function. /// - The init calls in this function must appear in the correct order. unsafe fn kernel_init() -> ! { - use driver::interface::DriverManager; - - for i in bsp::driver::driver_manager().all_device_drivers().iter() { - if let Err(x) = i.init() { - panic!("Error loading driver: {}: {}", i.compatible(), x); - } + // Initialize the BSP driver subsystem. + if let Err(x) = bsp::driver::init() { + panic!("Error initializing BSP driver subsystem: {}", x); } - bsp::driver::driver_manager().post_device_driver_init(); + + // Initialize all device drivers. + driver::driver_manager().init_drivers(); // println! is usable from here on. // Transition from unsafe to safe. @@ -146,7 +145,6 @@ unsafe fn kernel_init() -> ! { /// The main function running after the early init. fn kernel_main() -> ! { use console::console; - use driver::interface::DriverManager; println!( "[0] {} version {}", @@ -156,13 +154,7 @@ fn kernel_main() -> ! { println!("[1] Booting on: {}", bsp::board_name()); println!("[2] Drivers loaded:"); - for (i, driver) in bsp::driver::driver_manager() - .all_device_drivers() - .iter() - .enumerate() - { - println!(" {}. {}", i + 1, driver.compatible()); - } + driver::driver_manager().enumerate(); println!("[3] Chars written: {}", console().chars_written()); println!("[4] Echoing input now"); diff --git a/06_uart_chainloader/README.md b/06_uart_chainloader/README.md index 6e4e4530..e321e603 100644 --- a/06_uart_chainloader/README.md +++ b/06_uart_chainloader/README.md @@ -369,6 +369,27 @@ diff -uNr 05_drivers_gpio_uart/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs 0 {} } +diff -uNr 05_drivers_gpio_uart/src/bsp/raspberrypi/console.rs 06_uart_chainloader/src/bsp/raspberrypi/console.rs +--- 05_drivers_gpio_uart/src/bsp/raspberrypi/console.rs ++++ 06_uart_chainloader/src/bsp/raspberrypi/console.rs +@@ -1,16 +0,0 @@ +-// SPDX-License-Identifier: MIT OR Apache-2.0 +-// +-// Copyright (c) 2018-2022 Andre Richter +- +-//! BSP console facilities. +- +-use crate::console; +- +-//-------------------------------------------------------------------------------------------------- +-// Public Code +-//-------------------------------------------------------------------------------------------------- +- +-/// Return a reference to the console. +-pub fn console() -> &'static dyn console::interface::All { +- &super::driver::PL011_UART +-} + diff -uNr 05_drivers_gpio_uart/src/bsp/raspberrypi/kernel.ld 06_uart_chainloader/src/bsp/raspberrypi/kernel.ld --- 05_drivers_gpio_uart/src/bsp/raspberrypi/kernel.ld +++ 06_uart_chainloader/src/bsp/raspberrypi/kernel.ld @@ -437,10 +458,41 @@ diff -uNr 05_drivers_gpio_uart/src/bsp/raspberrypi/memory.rs 06_uart_chainloader + map::BOARD_DEFAULT_LOAD_ADDRESS as _ +} +diff -uNr 05_drivers_gpio_uart/src/driver.rs 06_uart_chainloader/src/driver.rs +--- 05_drivers_gpio_uart/src/driver.rs ++++ 06_uart_chainloader/src/driver.rs +@@ -4,10 +4,7 @@ + + //! Driver support. + +-use crate::{ +- println, +- synchronization::{interface::Mutex, NullLock}, +-}; ++use crate::synchronization::{interface::Mutex, NullLock}; + + //-------------------------------------------------------------------------------------------------- + // Private Definitions +@@ -154,14 +151,4 @@ + } + }); + } +- +- /// Enumerate all registered device drivers. +- pub fn enumerate(&self) { +- let mut i: usize = 1; +- self.for_each_descriptor(|descriptor| { +- println!(" {}. {}", i, descriptor.device_driver.compatible()); +- +- i += 1; +- }); +- } + } + diff -uNr 05_drivers_gpio_uart/src/main.rs 06_uart_chainloader/src/main.rs --- 05_drivers_gpio_uart/src/main.rs +++ 06_uart_chainloader/src/main.rs -@@ -143,34 +143,55 @@ +@@ -142,27 +142,55 @@ kernel_main() } @@ -454,7 +506,6 @@ diff -uNr 05_drivers_gpio_uart/src/main.rs 06_uart_chainloader/src/main.rs /// The main function running after the early init. fn kernel_main() -> ! { use console::console; -- use driver::interface::DriverManager; - println!( - "[0] {} version {}", @@ -462,41 +513,35 @@ diff -uNr 05_drivers_gpio_uart/src/main.rs 06_uart_chainloader/src/main.rs - env!("CARGO_PKG_VERSION") - ); - println!("[1] Booting on: {}", bsp::board_name()); -- -- println!("[2] Drivers loaded:"); -- for (i, driver) in bsp::driver::driver_manager() -- .all_device_drivers() -- .iter() -- .enumerate() -- { -- println!(" {}. {}", i + 1, driver.compatible()); + println!("{}", MINILOAD_LOGO); + println!("{:^37}", bsp::board_name()); + println!(); + println!("[ML] Requesting binary"); + console().flush(); -+ + +- println!("[2] Drivers loaded:"); +- driver::driver_manager().enumerate(); + // Discard any spurious received characters before starting with the loader protocol. + console().clear_rx(); -+ -+ // Notify `Minipush` to send the binary. -+ for _ in 0..3 { -+ console().write_char(3 as char); - } - println!("[3] Chars written: {}", console().chars_written()); - println!("[4] Echoing input now"); -+ // Read the binary's size. -+ let mut size: u32 = u32::from(console().read_char() as u8); -+ size |= u32::from(console().read_char() as u8) << 8; -+ size |= u32::from(console().read_char() as u8) << 16; -+ size |= u32::from(console().read_char() as u8) << 24; ++ // Notify `Minipush` to send the binary. ++ for _ in 0..3 { ++ console().write_char(3 as char); ++ } - // Discard any spurious received characters before going into echo mode. - console().clear_rx(); - loop { - let c = console().read_char(); - console().write_char(c); ++ // Read the binary's size. ++ let mut size: u32 = u32::from(console().read_char() as u8); ++ size |= u32::from(console().read_char() as u8) << 8; ++ size |= u32::from(console().read_char() as u8) << 16; ++ size |= u32::from(console().read_char() as u8) << 24; ++ + // Trust it's not too big. + console().write_char('O'); + console().write_char('K'); diff --git a/06_uart_chainloader/src/bsp/raspberrypi.rs b/06_uart_chainloader/src/bsp/raspberrypi.rs index a9a7261a..fe940677 100644 --- a/06_uart_chainloader/src/bsp/raspberrypi.rs +++ b/06_uart_chainloader/src/bsp/raspberrypi.rs @@ -4,7 +4,6 @@ //! Top-level BSP file for the Raspberry Pi 3 and 4. -pub mod console; pub mod cpu; pub mod driver; pub mod memory; diff --git a/06_uart_chainloader/src/bsp/raspberrypi/console.rs b/06_uart_chainloader/src/bsp/raspberrypi/console.rs deleted file mode 100644 index 0a630eef..00000000 --- a/06_uart_chainloader/src/bsp/raspberrypi/console.rs +++ /dev/null @@ -1,16 +0,0 @@ -// SPDX-License-Identifier: MIT OR Apache-2.0 -// -// Copyright (c) 2018-2022 Andre Richter - -//! BSP console facilities. - -use crate::console; - -//-------------------------------------------------------------------------------------------------- -// Public Code -//-------------------------------------------------------------------------------------------------- - -/// Return a reference to the console. -pub fn console() -> &'static dyn console::interface::All { - &super::driver::PL011_UART -} diff --git a/06_uart_chainloader/src/bsp/raspberrypi/driver.rs b/06_uart_chainloader/src/bsp/raspberrypi/driver.rs index 8b683ed8..ea843066 100644 --- a/06_uart_chainloader/src/bsp/raspberrypi/driver.rs +++ b/06_uart_chainloader/src/bsp/raspberrypi/driver.rs @@ -5,51 +5,67 @@ //! BSP driver support. use super::memory::map::mmio; -use crate::{bsp::device_driver, driver}; +use crate::{bsp::device_driver, console, driver as generic_driver}; +use core::sync::atomic::{AtomicBool, Ordering}; //-------------------------------------------------------------------------------------------------- -// Private Definitions +// Global instances //-------------------------------------------------------------------------------------------------- -/// Device Driver Manager type. -struct BSPDriverManager { - device_drivers: [&'static (dyn DeviceDriver + Sync); 2], -} +static PL011_UART: device_driver::PL011Uart = + unsafe { device_driver::PL011Uart::new(mmio::PL011_UART_START) }; +static GPIO: device_driver::GPIO = unsafe { device_driver::GPIO::new(mmio::GPIO_START) }; //-------------------------------------------------------------------------------------------------- -// Global instances +// Private Code //-------------------------------------------------------------------------------------------------- -pub(super) static PL011_UART: device_driver::PL011Uart = - unsafe { device_driver::PL011Uart::new(mmio::PL011_UART_START) }; +/// This must be called only after successful init of the UART driver. +fn post_init_uart() -> Result<(), &'static str> { + console::register_console(&PL011_UART); -static GPIO: device_driver::GPIO = unsafe { device_driver::GPIO::new(mmio::GPIO_START) }; + Ok(()) +} -static BSP_DRIVER_MANAGER: BSPDriverManager = BSPDriverManager { - device_drivers: [&PL011_UART, &GPIO], -}; +/// This must be called only after successful init of the GPIO driver. +fn post_init_gpio() -> Result<(), &'static str> { + GPIO.map_pl011_uart(); + Ok(()) +} -//-------------------------------------------------------------------------------------------------- -// Public Code -//-------------------------------------------------------------------------------------------------- +fn driver_uart() -> Result<(), &'static str> { + let uart_descriptor = + generic_driver::DeviceDriverDescriptor::new(&PL011_UART, Some(post_init_uart)); + generic_driver::driver_manager().register_driver(uart_descriptor); -/// Return a reference to the driver manager. -pub fn driver_manager() -> &'static impl driver::interface::DriverManager { - &BSP_DRIVER_MANAGER + Ok(()) } -//------------------------------------------------------------------------------ -// OS Interface Code -//------------------------------------------------------------------------------ -use driver::interface::DeviceDriver; +fn driver_gpio() -> Result<(), &'static str> { + let gpio_descriptor = generic_driver::DeviceDriverDescriptor::new(&GPIO, Some(post_init_gpio)); + generic_driver::driver_manager().register_driver(gpio_descriptor); -impl driver::interface::DriverManager for BSPDriverManager { - fn all_device_drivers(&self) -> &[&'static (dyn DeviceDriver + Sync)] { - &self.device_drivers[..] - } + Ok(()) +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- - fn post_device_driver_init(&self) { - // Configure PL011Uart's output pins. - GPIO.map_pl011_uart(); +/// Initialize the driver subsystem. +/// +/// # Safety +/// +/// See child function calls. +pub unsafe fn init() -> Result<(), &'static str> { + static INIT_DONE: AtomicBool = AtomicBool::new(false); + if INIT_DONE.load(Ordering::Relaxed) { + return Err("Init already done"); } + + driver_uart()?; + driver_gpio()?; + + INIT_DONE.store(true, Ordering::Relaxed); + Ok(()) } diff --git a/06_uart_chainloader/src/console.rs b/06_uart_chainloader/src/console.rs index c1fb0e53..02b43df9 100644 --- a/06_uart_chainloader/src/console.rs +++ b/06_uart_chainloader/src/console.rs @@ -4,7 +4,9 @@ //! System console. -use crate::bsp; +mod null_console; + +use crate::synchronization::{self, NullLock}; //-------------------------------------------------------------------------------------------------- // Public Definitions @@ -54,13 +56,26 @@ pub mod interface { pub trait All: Write + Read + Statistics {} } +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +static CUR_CONSOLE: NullLock<&'static (dyn interface::All + Sync)> = + NullLock::new(&null_console::NULL_CONSOLE); + //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- +use synchronization::interface::Mutex; + +/// Register a new console. +pub fn register_console(new_console: &'static (dyn interface::All + Sync)) { + CUR_CONSOLE.lock(|con| *con = new_console); +} -/// Return a reference to the console. +/// Return a reference to the currently registered console. /// /// This is the global console used by all printing macros. pub fn console() -> &'static dyn interface::All { - bsp::console::console() + CUR_CONSOLE.lock(|con| *con) } diff --git a/06_uart_chainloader/src/console/null_console.rs b/06_uart_chainloader/src/console/null_console.rs new file mode 100644 index 00000000..2c64d499 --- /dev/null +++ b/06_uart_chainloader/src/console/null_console.rs @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2022 Andre Richter + +//! Null console. + +use super::interface; +use core::fmt; + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +pub struct NullConsole; + +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +pub static NULL_CONSOLE: NullConsole = NullConsole {}; + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +impl interface::Write for NullConsole { + fn write_char(&self, _c: char) {} + + fn write_fmt(&self, _args: fmt::Arguments) -> fmt::Result { + fmt::Result::Ok(()) + } + + fn flush(&self) {} +} + +impl interface::Read for NullConsole { + fn clear_rx(&self) {} +} + +impl interface::Statistics for NullConsole {} +impl interface::All for NullConsole {} diff --git a/06_uart_chainloader/src/driver.rs b/06_uart_chainloader/src/driver.rs index 2fcc7562..fb44bbd9 100644 --- a/06_uart_chainloader/src/driver.rs +++ b/06_uart_chainloader/src/driver.rs @@ -4,6 +4,19 @@ //! Driver support. +use crate::synchronization::{interface::Mutex, NullLock}; + +//-------------------------------------------------------------------------------------------------- +// Private Definitions +//-------------------------------------------------------------------------------------------------- + +const NUM_DRIVERS: usize = 5; + +struct DriverManagerInner { + next_index: usize, + descriptors: [Option; NUM_DRIVERS], +} + //-------------------------------------------------------------------------------------------------- // Public Definitions //-------------------------------------------------------------------------------------------------- @@ -24,21 +37,118 @@ pub mod interface { Ok(()) } } +} + +/// Tpye to be used as an optional callback after a driver's init() has run. +pub type DeviceDriverPostInitCallback = unsafe fn() -> Result<(), &'static str>; - /// Device driver management functions. +/// A descriptor for device drivers. +#[derive(Copy, Clone)] +pub struct DeviceDriverDescriptor { + device_driver: &'static (dyn interface::DeviceDriver + Sync), + post_init_callback: Option, +} + +/// Provides device driver management functions. +pub struct DriverManager { + inner: NullLock, +} + +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +static DRIVER_MANAGER: DriverManager = DriverManager::new(); + +//-------------------------------------------------------------------------------------------------- +// Private Code +//-------------------------------------------------------------------------------------------------- + +impl DriverManagerInner { + /// Create an instance. + pub const fn new() -> Self { + Self { + next_index: 0, + descriptors: [None; NUM_DRIVERS], + } + } +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +impl DeviceDriverDescriptor { + /// Create an instance. + pub fn new( + device_driver: &'static (dyn interface::DeviceDriver + Sync), + post_init_callback: Option, + ) -> Self { + Self { + device_driver, + post_init_callback, + } + } +} + +/// Return a reference to the global DriverManager. +pub fn driver_manager() -> &'static DriverManager { + &DRIVER_MANAGER +} + +impl DriverManager { + /// Create an instance. + pub const fn new() -> Self { + Self { + inner: NullLock::new(DriverManagerInner::new()), + } + } + + /// Register a device driver with the kernel. + pub fn register_driver(&self, descriptor: DeviceDriverDescriptor) { + self.inner.lock(|inner| { + inner.descriptors[inner.next_index] = Some(descriptor); + inner.next_index += 1; + }) + } + + /// Helper for iterating over registered drivers. + fn for_each_descriptor<'a>(&'a self, f: impl FnMut(&'a DeviceDriverDescriptor)) { + self.inner.lock(|inner| { + inner + .descriptors + .iter() + .filter_map(|x| x.as_ref()) + .for_each(f) + }) + } + + /// Fully initialize all drivers. /// - /// The `BSP` is supposed to supply one global instance. - pub trait DriverManager { - /// Return a slice of references to all `BSP`-instantiated drivers. - /// - /// # Safety - /// - /// - The order of devices is the order in which `DeviceDriver::init()` is called. - fn all_device_drivers(&self) -> &[&'static (dyn DeviceDriver + Sync)]; + /// # Safety + /// + /// - During init, drivers might do stuff with system-wide impact. + pub unsafe fn init_drivers(&self) { + self.for_each_descriptor(|descriptor| { + // 1. Initialize driver. + if let Err(x) = descriptor.device_driver.init() { + panic!( + "Error initializing driver: {}: {}", + descriptor.device_driver.compatible(), + x + ); + } - /// Initialization code that runs after driver init. - /// - /// For example, device driver code that depends on other drivers already being online. - fn post_device_driver_init(&self); + // 2. Call corresponding post init callback. + if let Some(callback) = &descriptor.post_init_callback { + if let Err(x) = callback() { + panic!( + "Error during driver post-init callback: {}: {}", + descriptor.device_driver.compatible(), + x + ); + } + } + }); } } diff --git a/06_uart_chainloader/src/main.rs b/06_uart_chainloader/src/main.rs index 08bd9ad9..bef62822 100644 --- a/06_uart_chainloader/src/main.rs +++ b/06_uart_chainloader/src/main.rs @@ -129,14 +129,13 @@ mod synchronization; /// - Only a single core must be active and running this function. /// - The init calls in this function must appear in the correct order. unsafe fn kernel_init() -> ! { - use driver::interface::DriverManager; - - for i in bsp::driver::driver_manager().all_device_drivers().iter() { - if let Err(x) = i.init() { - panic!("Error loading driver: {}: {}", i.compatible(), x); - } + // Initialize the BSP driver subsystem. + if let Err(x) = bsp::driver::init() { + panic!("Error initializing BSP driver subsystem: {}", x); } - bsp::driver::driver_manager().post_device_driver_init(); + + // Initialize all device drivers. + driver::driver_manager().init_drivers(); // println! is usable from here on. // Transition from unsafe to safe. diff --git a/07_timestamps/README.md b/07_timestamps/README.md index 2e8df3c2..4a5905b4 100644 --- a/07_timestamps/README.md +++ b/07_timestamps/README.md @@ -501,6 +501,28 @@ diff -uNr 06_uart_chainloader/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs 07 {} } +diff -uNr 06_uart_chainloader/src/bsp/raspberrypi/driver.rs 07_timestamps/src/bsp/raspberrypi/driver.rs +--- 06_uart_chainloader/src/bsp/raspberrypi/driver.rs ++++ 07_timestamps/src/bsp/raspberrypi/driver.rs +@@ -57,6 +57,17 @@ + /// # Safety + /// + /// See child function calls. ++/// ++/// # Note ++/// ++/// Using atomics here relieves us from needing to use `unsafe` for the static variable. ++/// ++/// On `AArch64`, which is the only implemented architecture at the time of writing this, ++/// [`AtomicBool::load`] and [`AtomicBool::store`] are lowered to ordinary load and store ++/// instructions. They are therefore safe to use even with MMU + caching deactivated. ++/// ++/// [`AtomicBool::load`]: core::sync::atomic::AtomicBool::load ++/// [`AtomicBool::store`]: core::sync::atomic::AtomicBool::store + pub unsafe fn init() -> Result<(), &'static str> { + static INIT_DONE: AtomicBool = AtomicBool::new(false); + if INIT_DONE.load(Ordering::Relaxed) { + diff -uNr 06_uart_chainloader/src/bsp/raspberrypi/kernel.ld 07_timestamps/src/bsp/raspberrypi/kernel.ld --- 06_uart_chainloader/src/bsp/raspberrypi/kernel.ld +++ 07_timestamps/src/bsp/raspberrypi/kernel.ld @@ -580,6 +602,37 @@ diff -uNr 06_uart_chainloader/src/cpu.rs 07_timestamps/src/cpu.rs -#[cfg(feature = "bsp_rpi3")] -pub use arch_cpu::spin_for_cycles; +diff -uNr 06_uart_chainloader/src/driver.rs 07_timestamps/src/driver.rs +--- 06_uart_chainloader/src/driver.rs ++++ 07_timestamps/src/driver.rs +@@ -4,7 +4,10 @@ + + //! Driver support. + +-use crate::synchronization::{interface::Mutex, NullLock}; ++use crate::{ ++ info, ++ synchronization::{interface::Mutex, NullLock}, ++}; + + //-------------------------------------------------------------------------------------------------- + // Private Definitions +@@ -151,4 +154,14 @@ + } + }); + } ++ ++ /// Enumerate all registered device drivers. ++ pub fn enumerate(&self) { ++ let mut i: usize = 1; ++ self.for_each_descriptor(|descriptor| { ++ info!(" {}. {}", i, descriptor.device_driver.compatible()); ++ ++ i += 1; ++ }); ++ } + } + diff -uNr 06_uart_chainloader/src/main.rs 07_timestamps/src/main.rs --- 06_uart_chainloader/src/main.rs +++ 07_timestamps/src/main.rs @@ -604,7 +657,7 @@ diff -uNr 06_uart_chainloader/src/main.rs 07_timestamps/src/main.rs /// Early init code. /// -@@ -143,55 +147,37 @@ +@@ -142,55 +146,30 @@ kernel_main() } @@ -618,9 +671,7 @@ diff -uNr 06_uart_chainloader/src/main.rs 07_timestamps/src/main.rs /// The main function running after the early init. fn kernel_main() -> ! { - use console::console; -+ use core::time::Duration; -+ use driver::interface::DriverManager; - +- - println!("{}", MINILOAD_LOGO); - println!("{:^37}", bsp::board_name()); - println!(); @@ -633,26 +684,8 @@ diff -uNr 06_uart_chainloader/src/main.rs 07_timestamps/src/main.rs - // Notify `Minipush` to send the binary. - for _ in 0..3 { - console().write_char(3 as char); -+ info!( -+ "{} version {}", -+ env!("CARGO_PKG_NAME"), -+ env!("CARGO_PKG_VERSION") -+ ); -+ info!("Booting on: {}", bsp::board_name()); -+ -+ info!( -+ "Architectural timer resolution: {} ns", -+ time::time_manager().resolution().as_nanos() -+ ); -+ -+ info!("Drivers loaded:"); -+ for (i, driver) in bsp::driver::driver_manager() -+ .all_device_drivers() -+ .iter() -+ .enumerate() -+ { -+ info!(" {}. {}", i + 1, driver.compatible()); - } +- } ++ use core::time::Duration; - // Read the binary's size. - let mut size: u32 = u32::from(console().read_char() as u8); @@ -670,10 +703,29 @@ diff -uNr 06_uart_chainloader/src/main.rs 07_timestamps/src/main.rs - for i in 0..size { - core::ptr::write_volatile(kernel_addr.offset(i as isize), console().read_char() as u8) - } -- } ++ info!( ++ "{} version {}", ++ env!("CARGO_PKG_NAME"), ++ env!("CARGO_PKG_VERSION") ++ ); ++ info!("Booting on: {}", bsp::board_name()); ++ ++ info!( ++ "Architectural timer resolution: {} ns", ++ time::time_manager().resolution().as_nanos() ++ ); ++ ++ info!("Drivers loaded:"); ++ driver::driver_manager().enumerate(); ++ + // Test a failing timer case. + time::time_manager().spin_for(Duration::from_nanos(1)); - ++ ++ loop { ++ info!("Spinning for 1 second"); ++ time::time_manager().spin_for(Duration::from_secs(1)); + } +- - println!("[ML] Loaded! Executing the payload now\n"); - console().flush(); - @@ -682,10 +734,6 @@ diff -uNr 06_uart_chainloader/src/main.rs 07_timestamps/src/main.rs - - // Jump to loaded kernel! - kernel() -+ loop { -+ info!("Spinning for 1 second"); -+ time::time_manager().spin_for(Duration::from_secs(1)); -+ } } diff -uNr 06_uart_chainloader/src/panic_wait.rs 07_timestamps/src/panic_wait.rs diff --git a/07_timestamps/src/bsp/raspberrypi.rs b/07_timestamps/src/bsp/raspberrypi.rs index a9a7261a..fe940677 100644 --- a/07_timestamps/src/bsp/raspberrypi.rs +++ b/07_timestamps/src/bsp/raspberrypi.rs @@ -4,7 +4,6 @@ //! Top-level BSP file for the Raspberry Pi 3 and 4. -pub mod console; pub mod cpu; pub mod driver; pub mod memory; diff --git a/07_timestamps/src/bsp/raspberrypi/console.rs b/07_timestamps/src/bsp/raspberrypi/console.rs deleted file mode 100644 index 0a630eef..00000000 --- a/07_timestamps/src/bsp/raspberrypi/console.rs +++ /dev/null @@ -1,16 +0,0 @@ -// SPDX-License-Identifier: MIT OR Apache-2.0 -// -// Copyright (c) 2018-2022 Andre Richter - -//! BSP console facilities. - -use crate::console; - -//-------------------------------------------------------------------------------------------------- -// Public Code -//-------------------------------------------------------------------------------------------------- - -/// Return a reference to the console. -pub fn console() -> &'static dyn console::interface::All { - &super::driver::PL011_UART -} diff --git a/07_timestamps/src/bsp/raspberrypi/driver.rs b/07_timestamps/src/bsp/raspberrypi/driver.rs index 8b683ed8..4a42b84f 100644 --- a/07_timestamps/src/bsp/raspberrypi/driver.rs +++ b/07_timestamps/src/bsp/raspberrypi/driver.rs @@ -5,51 +5,78 @@ //! BSP driver support. use super::memory::map::mmio; -use crate::{bsp::device_driver, driver}; +use crate::{bsp::device_driver, console, driver as generic_driver}; +use core::sync::atomic::{AtomicBool, Ordering}; //-------------------------------------------------------------------------------------------------- -// Private Definitions +// Global instances //-------------------------------------------------------------------------------------------------- -/// Device Driver Manager type. -struct BSPDriverManager { - device_drivers: [&'static (dyn DeviceDriver + Sync); 2], -} +static PL011_UART: device_driver::PL011Uart = + unsafe { device_driver::PL011Uart::new(mmio::PL011_UART_START) }; +static GPIO: device_driver::GPIO = unsafe { device_driver::GPIO::new(mmio::GPIO_START) }; //-------------------------------------------------------------------------------------------------- -// Global instances +// Private Code //-------------------------------------------------------------------------------------------------- -pub(super) static PL011_UART: device_driver::PL011Uart = - unsafe { device_driver::PL011Uart::new(mmio::PL011_UART_START) }; +/// This must be called only after successful init of the UART driver. +fn post_init_uart() -> Result<(), &'static str> { + console::register_console(&PL011_UART); -static GPIO: device_driver::GPIO = unsafe { device_driver::GPIO::new(mmio::GPIO_START) }; + Ok(()) +} -static BSP_DRIVER_MANAGER: BSPDriverManager = BSPDriverManager { - device_drivers: [&PL011_UART, &GPIO], -}; +/// This must be called only after successful init of the GPIO driver. +fn post_init_gpio() -> Result<(), &'static str> { + GPIO.map_pl011_uart(); + Ok(()) +} -//-------------------------------------------------------------------------------------------------- -// Public Code -//-------------------------------------------------------------------------------------------------- +fn driver_uart() -> Result<(), &'static str> { + let uart_descriptor = + generic_driver::DeviceDriverDescriptor::new(&PL011_UART, Some(post_init_uart)); + generic_driver::driver_manager().register_driver(uart_descriptor); -/// Return a reference to the driver manager. -pub fn driver_manager() -> &'static impl driver::interface::DriverManager { - &BSP_DRIVER_MANAGER + Ok(()) } -//------------------------------------------------------------------------------ -// OS Interface Code -//------------------------------------------------------------------------------ -use driver::interface::DeviceDriver; +fn driver_gpio() -> Result<(), &'static str> { + let gpio_descriptor = generic_driver::DeviceDriverDescriptor::new(&GPIO, Some(post_init_gpio)); + generic_driver::driver_manager().register_driver(gpio_descriptor); -impl driver::interface::DriverManager for BSPDriverManager { - fn all_device_drivers(&self) -> &[&'static (dyn DeviceDriver + Sync)] { - &self.device_drivers[..] - } + Ok(()) +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- - fn post_device_driver_init(&self) { - // Configure PL011Uart's output pins. - GPIO.map_pl011_uart(); +/// Initialize the driver subsystem. +/// +/// # Safety +/// +/// See child function calls. +/// +/// # Note +/// +/// Using atomics here relieves us from needing to use `unsafe` for the static variable. +/// +/// On `AArch64`, which is the only implemented architecture at the time of writing this, +/// [`AtomicBool::load`] and [`AtomicBool::store`] are lowered to ordinary load and store +/// instructions. They are therefore safe to use even with MMU + caching deactivated. +/// +/// [`AtomicBool::load`]: core::sync::atomic::AtomicBool::load +/// [`AtomicBool::store`]: core::sync::atomic::AtomicBool::store +pub unsafe fn init() -> Result<(), &'static str> { + static INIT_DONE: AtomicBool = AtomicBool::new(false); + if INIT_DONE.load(Ordering::Relaxed) { + return Err("Init already done"); } + + driver_uart()?; + driver_gpio()?; + + INIT_DONE.store(true, Ordering::Relaxed); + Ok(()) } diff --git a/07_timestamps/src/console.rs b/07_timestamps/src/console.rs index c1fb0e53..02b43df9 100644 --- a/07_timestamps/src/console.rs +++ b/07_timestamps/src/console.rs @@ -4,7 +4,9 @@ //! System console. -use crate::bsp; +mod null_console; + +use crate::synchronization::{self, NullLock}; //-------------------------------------------------------------------------------------------------- // Public Definitions @@ -54,13 +56,26 @@ pub mod interface { pub trait All: Write + Read + Statistics {} } +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +static CUR_CONSOLE: NullLock<&'static (dyn interface::All + Sync)> = + NullLock::new(&null_console::NULL_CONSOLE); + //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- +use synchronization::interface::Mutex; + +/// Register a new console. +pub fn register_console(new_console: &'static (dyn interface::All + Sync)) { + CUR_CONSOLE.lock(|con| *con = new_console); +} -/// Return a reference to the console. +/// Return a reference to the currently registered console. /// /// This is the global console used by all printing macros. pub fn console() -> &'static dyn interface::All { - bsp::console::console() + CUR_CONSOLE.lock(|con| *con) } diff --git a/07_timestamps/src/console/null_console.rs b/07_timestamps/src/console/null_console.rs new file mode 100644 index 00000000..2c64d499 --- /dev/null +++ b/07_timestamps/src/console/null_console.rs @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2022 Andre Richter + +//! Null console. + +use super::interface; +use core::fmt; + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +pub struct NullConsole; + +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +pub static NULL_CONSOLE: NullConsole = NullConsole {}; + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +impl interface::Write for NullConsole { + fn write_char(&self, _c: char) {} + + fn write_fmt(&self, _args: fmt::Arguments) -> fmt::Result { + fmt::Result::Ok(()) + } + + fn flush(&self) {} +} + +impl interface::Read for NullConsole { + fn clear_rx(&self) {} +} + +impl interface::Statistics for NullConsole {} +impl interface::All for NullConsole {} diff --git a/07_timestamps/src/driver.rs b/07_timestamps/src/driver.rs index 2fcc7562..a798c86d 100644 --- a/07_timestamps/src/driver.rs +++ b/07_timestamps/src/driver.rs @@ -4,6 +4,22 @@ //! Driver support. +use crate::{ + info, + synchronization::{interface::Mutex, NullLock}, +}; + +//-------------------------------------------------------------------------------------------------- +// Private Definitions +//-------------------------------------------------------------------------------------------------- + +const NUM_DRIVERS: usize = 5; + +struct DriverManagerInner { + next_index: usize, + descriptors: [Option; NUM_DRIVERS], +} + //-------------------------------------------------------------------------------------------------- // Public Definitions //-------------------------------------------------------------------------------------------------- @@ -24,21 +40,128 @@ pub mod interface { Ok(()) } } +} + +/// Tpye to be used as an optional callback after a driver's init() has run. +pub type DeviceDriverPostInitCallback = unsafe fn() -> Result<(), &'static str>; + +/// A descriptor for device drivers. +#[derive(Copy, Clone)] +pub struct DeviceDriverDescriptor { + device_driver: &'static (dyn interface::DeviceDriver + Sync), + post_init_callback: Option, +} + +/// Provides device driver management functions. +pub struct DriverManager { + inner: NullLock, +} + +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +static DRIVER_MANAGER: DriverManager = DriverManager::new(); + +//-------------------------------------------------------------------------------------------------- +// Private Code +//-------------------------------------------------------------------------------------------------- + +impl DriverManagerInner { + /// Create an instance. + pub const fn new() -> Self { + Self { + next_index: 0, + descriptors: [None; NUM_DRIVERS], + } + } +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +impl DeviceDriverDescriptor { + /// Create an instance. + pub fn new( + device_driver: &'static (dyn interface::DeviceDriver + Sync), + post_init_callback: Option, + ) -> Self { + Self { + device_driver, + post_init_callback, + } + } +} + +/// Return a reference to the global DriverManager. +pub fn driver_manager() -> &'static DriverManager { + &DRIVER_MANAGER +} + +impl DriverManager { + /// Create an instance. + pub const fn new() -> Self { + Self { + inner: NullLock::new(DriverManagerInner::new()), + } + } - /// Device driver management functions. + /// Register a device driver with the kernel. + pub fn register_driver(&self, descriptor: DeviceDriverDescriptor) { + self.inner.lock(|inner| { + inner.descriptors[inner.next_index] = Some(descriptor); + inner.next_index += 1; + }) + } + + /// Helper for iterating over registered drivers. + fn for_each_descriptor<'a>(&'a self, f: impl FnMut(&'a DeviceDriverDescriptor)) { + self.inner.lock(|inner| { + inner + .descriptors + .iter() + .filter_map(|x| x.as_ref()) + .for_each(f) + }) + } + + /// Fully initialize all drivers. /// - /// The `BSP` is supposed to supply one global instance. - pub trait DriverManager { - /// Return a slice of references to all `BSP`-instantiated drivers. - /// - /// # Safety - /// - /// - The order of devices is the order in which `DeviceDriver::init()` is called. - fn all_device_drivers(&self) -> &[&'static (dyn DeviceDriver + Sync)]; + /// # Safety + /// + /// - During init, drivers might do stuff with system-wide impact. + pub unsafe fn init_drivers(&self) { + self.for_each_descriptor(|descriptor| { + // 1. Initialize driver. + if let Err(x) = descriptor.device_driver.init() { + panic!( + "Error initializing driver: {}: {}", + descriptor.device_driver.compatible(), + x + ); + } - /// Initialization code that runs after driver init. - /// - /// For example, device driver code that depends on other drivers already being online. - fn post_device_driver_init(&self); + // 2. Call corresponding post init callback. + if let Some(callback) = &descriptor.post_init_callback { + if let Err(x) = callback() { + panic!( + "Error during driver post-init callback: {}: {}", + descriptor.device_driver.compatible(), + x + ); + } + } + }); + } + + /// Enumerate all registered device drivers. + pub fn enumerate(&self) { + let mut i: usize = 1; + self.for_each_descriptor(|descriptor| { + info!(" {}. {}", i, descriptor.device_driver.compatible()); + + i += 1; + }); } } diff --git a/07_timestamps/src/main.rs b/07_timestamps/src/main.rs index 90c39a37..df863f32 100644 --- a/07_timestamps/src/main.rs +++ b/07_timestamps/src/main.rs @@ -133,14 +133,13 @@ mod time; /// - Only a single core must be active and running this function. /// - The init calls in this function must appear in the correct order. unsafe fn kernel_init() -> ! { - use driver::interface::DriverManager; - - for i in bsp::driver::driver_manager().all_device_drivers().iter() { - if let Err(x) = i.init() { - panic!("Error loading driver: {}: {}", i.compatible(), x); - } + // Initialize the BSP driver subsystem. + if let Err(x) = bsp::driver::init() { + panic!("Error initializing BSP driver subsystem: {}", x); } - bsp::driver::driver_manager().post_device_driver_init(); + + // Initialize all device drivers. + driver::driver_manager().init_drivers(); // println! is usable from here on. // Transition from unsafe to safe. @@ -150,7 +149,6 @@ unsafe fn kernel_init() -> ! { /// The main function running after the early init. fn kernel_main() -> ! { use core::time::Duration; - use driver::interface::DriverManager; info!( "{} version {}", @@ -165,13 +163,7 @@ fn kernel_main() -> ! { ); info!("Drivers loaded:"); - for (i, driver) in bsp::driver::driver_manager() - .all_device_drivers() - .iter() - .enumerate() - { - info!(" {}. {}", i + 1, driver.compatible()); - } + driver::driver_manager().enumerate(); // Test a failing timer case. time::time_manager().spin_for(Duration::from_nanos(1)); diff --git a/08_hw_debug_JTAG/README.md b/08_hw_debug_JTAG/README.md index 53f86807..69b6b82e 100644 --- a/08_hw_debug_JTAG/README.md +++ b/08_hw_debug_JTAG/README.md @@ -401,4 +401,26 @@ diff -uNr 07_timestamps/Makefile 08_hw_debug_JTAG/Makefile ## Testing targets ##-------------------------------------------------------------------------------------------------- +diff -uNr 07_timestamps/src/bsp/raspberrypi/driver.rs 08_hw_debug_JTAG/src/bsp/raspberrypi/driver.rs +--- 07_timestamps/src/bsp/raspberrypi/driver.rs ++++ 08_hw_debug_JTAG/src/bsp/raspberrypi/driver.rs +@@ -57,17 +57,6 @@ + /// # Safety + /// + /// See child function calls. +-/// +-/// # Note +-/// +-/// Using atomics here relieves us from needing to use `unsafe` for the static variable. +-/// +-/// On `AArch64`, which is the only implemented architecture at the time of writing this, +-/// [`AtomicBool::load`] and [`AtomicBool::store`] are lowered to ordinary load and store +-/// instructions. They are therefore safe to use even with MMU + caching deactivated. +-/// +-/// [`AtomicBool::load`]: core::sync::atomic::AtomicBool::load +-/// [`AtomicBool::store`]: core::sync::atomic::AtomicBool::store + pub unsafe fn init() -> Result<(), &'static str> { + static INIT_DONE: AtomicBool = AtomicBool::new(false); + if INIT_DONE.load(Ordering::Relaxed) { + ``` diff --git a/08_hw_debug_JTAG/src/bsp/raspberrypi.rs b/08_hw_debug_JTAG/src/bsp/raspberrypi.rs index a9a7261a..fe940677 100644 --- a/08_hw_debug_JTAG/src/bsp/raspberrypi.rs +++ b/08_hw_debug_JTAG/src/bsp/raspberrypi.rs @@ -4,7 +4,6 @@ //! Top-level BSP file for the Raspberry Pi 3 and 4. -pub mod console; pub mod cpu; pub mod driver; pub mod memory; diff --git a/08_hw_debug_JTAG/src/bsp/raspberrypi/console.rs b/08_hw_debug_JTAG/src/bsp/raspberrypi/console.rs deleted file mode 100644 index 0a630eef..00000000 --- a/08_hw_debug_JTAG/src/bsp/raspberrypi/console.rs +++ /dev/null @@ -1,16 +0,0 @@ -// SPDX-License-Identifier: MIT OR Apache-2.0 -// -// Copyright (c) 2018-2022 Andre Richter - -//! BSP console facilities. - -use crate::console; - -//-------------------------------------------------------------------------------------------------- -// Public Code -//-------------------------------------------------------------------------------------------------- - -/// Return a reference to the console. -pub fn console() -> &'static dyn console::interface::All { - &super::driver::PL011_UART -} diff --git a/08_hw_debug_JTAG/src/bsp/raspberrypi/driver.rs b/08_hw_debug_JTAG/src/bsp/raspberrypi/driver.rs index 8b683ed8..ea843066 100644 --- a/08_hw_debug_JTAG/src/bsp/raspberrypi/driver.rs +++ b/08_hw_debug_JTAG/src/bsp/raspberrypi/driver.rs @@ -5,51 +5,67 @@ //! BSP driver support. use super::memory::map::mmio; -use crate::{bsp::device_driver, driver}; +use crate::{bsp::device_driver, console, driver as generic_driver}; +use core::sync::atomic::{AtomicBool, Ordering}; //-------------------------------------------------------------------------------------------------- -// Private Definitions +// Global instances //-------------------------------------------------------------------------------------------------- -/// Device Driver Manager type. -struct BSPDriverManager { - device_drivers: [&'static (dyn DeviceDriver + Sync); 2], -} +static PL011_UART: device_driver::PL011Uart = + unsafe { device_driver::PL011Uart::new(mmio::PL011_UART_START) }; +static GPIO: device_driver::GPIO = unsafe { device_driver::GPIO::new(mmio::GPIO_START) }; //-------------------------------------------------------------------------------------------------- -// Global instances +// Private Code //-------------------------------------------------------------------------------------------------- -pub(super) static PL011_UART: device_driver::PL011Uart = - unsafe { device_driver::PL011Uart::new(mmio::PL011_UART_START) }; +/// This must be called only after successful init of the UART driver. +fn post_init_uart() -> Result<(), &'static str> { + console::register_console(&PL011_UART); -static GPIO: device_driver::GPIO = unsafe { device_driver::GPIO::new(mmio::GPIO_START) }; + Ok(()) +} -static BSP_DRIVER_MANAGER: BSPDriverManager = BSPDriverManager { - device_drivers: [&PL011_UART, &GPIO], -}; +/// This must be called only after successful init of the GPIO driver. +fn post_init_gpio() -> Result<(), &'static str> { + GPIO.map_pl011_uart(); + Ok(()) +} -//-------------------------------------------------------------------------------------------------- -// Public Code -//-------------------------------------------------------------------------------------------------- +fn driver_uart() -> Result<(), &'static str> { + let uart_descriptor = + generic_driver::DeviceDriverDescriptor::new(&PL011_UART, Some(post_init_uart)); + generic_driver::driver_manager().register_driver(uart_descriptor); -/// Return a reference to the driver manager. -pub fn driver_manager() -> &'static impl driver::interface::DriverManager { - &BSP_DRIVER_MANAGER + Ok(()) } -//------------------------------------------------------------------------------ -// OS Interface Code -//------------------------------------------------------------------------------ -use driver::interface::DeviceDriver; +fn driver_gpio() -> Result<(), &'static str> { + let gpio_descriptor = generic_driver::DeviceDriverDescriptor::new(&GPIO, Some(post_init_gpio)); + generic_driver::driver_manager().register_driver(gpio_descriptor); -impl driver::interface::DriverManager for BSPDriverManager { - fn all_device_drivers(&self) -> &[&'static (dyn DeviceDriver + Sync)] { - &self.device_drivers[..] - } + Ok(()) +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- - fn post_device_driver_init(&self) { - // Configure PL011Uart's output pins. - GPIO.map_pl011_uart(); +/// Initialize the driver subsystem. +/// +/// # Safety +/// +/// See child function calls. +pub unsafe fn init() -> Result<(), &'static str> { + static INIT_DONE: AtomicBool = AtomicBool::new(false); + if INIT_DONE.load(Ordering::Relaxed) { + return Err("Init already done"); } + + driver_uart()?; + driver_gpio()?; + + INIT_DONE.store(true, Ordering::Relaxed); + Ok(()) } diff --git a/08_hw_debug_JTAG/src/console.rs b/08_hw_debug_JTAG/src/console.rs index c1fb0e53..02b43df9 100644 --- a/08_hw_debug_JTAG/src/console.rs +++ b/08_hw_debug_JTAG/src/console.rs @@ -4,7 +4,9 @@ //! System console. -use crate::bsp; +mod null_console; + +use crate::synchronization::{self, NullLock}; //-------------------------------------------------------------------------------------------------- // Public Definitions @@ -54,13 +56,26 @@ pub mod interface { pub trait All: Write + Read + Statistics {} } +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +static CUR_CONSOLE: NullLock<&'static (dyn interface::All + Sync)> = + NullLock::new(&null_console::NULL_CONSOLE); + //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- +use synchronization::interface::Mutex; + +/// Register a new console. +pub fn register_console(new_console: &'static (dyn interface::All + Sync)) { + CUR_CONSOLE.lock(|con| *con = new_console); +} -/// Return a reference to the console. +/// Return a reference to the currently registered console. /// /// This is the global console used by all printing macros. pub fn console() -> &'static dyn interface::All { - bsp::console::console() + CUR_CONSOLE.lock(|con| *con) } diff --git a/08_hw_debug_JTAG/src/console/null_console.rs b/08_hw_debug_JTAG/src/console/null_console.rs new file mode 100644 index 00000000..2c64d499 --- /dev/null +++ b/08_hw_debug_JTAG/src/console/null_console.rs @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2022 Andre Richter + +//! Null console. + +use super::interface; +use core::fmt; + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +pub struct NullConsole; + +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +pub static NULL_CONSOLE: NullConsole = NullConsole {}; + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +impl interface::Write for NullConsole { + fn write_char(&self, _c: char) {} + + fn write_fmt(&self, _args: fmt::Arguments) -> fmt::Result { + fmt::Result::Ok(()) + } + + fn flush(&self) {} +} + +impl interface::Read for NullConsole { + fn clear_rx(&self) {} +} + +impl interface::Statistics for NullConsole {} +impl interface::All for NullConsole {} diff --git a/08_hw_debug_JTAG/src/driver.rs b/08_hw_debug_JTAG/src/driver.rs index 2fcc7562..a798c86d 100644 --- a/08_hw_debug_JTAG/src/driver.rs +++ b/08_hw_debug_JTAG/src/driver.rs @@ -4,6 +4,22 @@ //! Driver support. +use crate::{ + info, + synchronization::{interface::Mutex, NullLock}, +}; + +//-------------------------------------------------------------------------------------------------- +// Private Definitions +//-------------------------------------------------------------------------------------------------- + +const NUM_DRIVERS: usize = 5; + +struct DriverManagerInner { + next_index: usize, + descriptors: [Option; NUM_DRIVERS], +} + //-------------------------------------------------------------------------------------------------- // Public Definitions //-------------------------------------------------------------------------------------------------- @@ -24,21 +40,128 @@ pub mod interface { Ok(()) } } +} + +/// Tpye to be used as an optional callback after a driver's init() has run. +pub type DeviceDriverPostInitCallback = unsafe fn() -> Result<(), &'static str>; + +/// A descriptor for device drivers. +#[derive(Copy, Clone)] +pub struct DeviceDriverDescriptor { + device_driver: &'static (dyn interface::DeviceDriver + Sync), + post_init_callback: Option, +} + +/// Provides device driver management functions. +pub struct DriverManager { + inner: NullLock, +} + +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +static DRIVER_MANAGER: DriverManager = DriverManager::new(); + +//-------------------------------------------------------------------------------------------------- +// Private Code +//-------------------------------------------------------------------------------------------------- + +impl DriverManagerInner { + /// Create an instance. + pub const fn new() -> Self { + Self { + next_index: 0, + descriptors: [None; NUM_DRIVERS], + } + } +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +impl DeviceDriverDescriptor { + /// Create an instance. + pub fn new( + device_driver: &'static (dyn interface::DeviceDriver + Sync), + post_init_callback: Option, + ) -> Self { + Self { + device_driver, + post_init_callback, + } + } +} + +/// Return a reference to the global DriverManager. +pub fn driver_manager() -> &'static DriverManager { + &DRIVER_MANAGER +} + +impl DriverManager { + /// Create an instance. + pub const fn new() -> Self { + Self { + inner: NullLock::new(DriverManagerInner::new()), + } + } - /// Device driver management functions. + /// Register a device driver with the kernel. + pub fn register_driver(&self, descriptor: DeviceDriverDescriptor) { + self.inner.lock(|inner| { + inner.descriptors[inner.next_index] = Some(descriptor); + inner.next_index += 1; + }) + } + + /// Helper for iterating over registered drivers. + fn for_each_descriptor<'a>(&'a self, f: impl FnMut(&'a DeviceDriverDescriptor)) { + self.inner.lock(|inner| { + inner + .descriptors + .iter() + .filter_map(|x| x.as_ref()) + .for_each(f) + }) + } + + /// Fully initialize all drivers. /// - /// The `BSP` is supposed to supply one global instance. - pub trait DriverManager { - /// Return a slice of references to all `BSP`-instantiated drivers. - /// - /// # Safety - /// - /// - The order of devices is the order in which `DeviceDriver::init()` is called. - fn all_device_drivers(&self) -> &[&'static (dyn DeviceDriver + Sync)]; + /// # Safety + /// + /// - During init, drivers might do stuff with system-wide impact. + pub unsafe fn init_drivers(&self) { + self.for_each_descriptor(|descriptor| { + // 1. Initialize driver. + if let Err(x) = descriptor.device_driver.init() { + panic!( + "Error initializing driver: {}: {}", + descriptor.device_driver.compatible(), + x + ); + } - /// Initialization code that runs after driver init. - /// - /// For example, device driver code that depends on other drivers already being online. - fn post_device_driver_init(&self); + // 2. Call corresponding post init callback. + if let Some(callback) = &descriptor.post_init_callback { + if let Err(x) = callback() { + panic!( + "Error during driver post-init callback: {}: {}", + descriptor.device_driver.compatible(), + x + ); + } + } + }); + } + + /// Enumerate all registered device drivers. + pub fn enumerate(&self) { + let mut i: usize = 1; + self.for_each_descriptor(|descriptor| { + info!(" {}. {}", i, descriptor.device_driver.compatible()); + + i += 1; + }); } } diff --git a/08_hw_debug_JTAG/src/main.rs b/08_hw_debug_JTAG/src/main.rs index 90c39a37..df863f32 100644 --- a/08_hw_debug_JTAG/src/main.rs +++ b/08_hw_debug_JTAG/src/main.rs @@ -133,14 +133,13 @@ mod time; /// - Only a single core must be active and running this function. /// - The init calls in this function must appear in the correct order. unsafe fn kernel_init() -> ! { - use driver::interface::DriverManager; - - for i in bsp::driver::driver_manager().all_device_drivers().iter() { - if let Err(x) = i.init() { - panic!("Error loading driver: {}: {}", i.compatible(), x); - } + // Initialize the BSP driver subsystem. + if let Err(x) = bsp::driver::init() { + panic!("Error initializing BSP driver subsystem: {}", x); } - bsp::driver::driver_manager().post_device_driver_init(); + + // Initialize all device drivers. + driver::driver_manager().init_drivers(); // println! is usable from here on. // Transition from unsafe to safe. @@ -150,7 +149,6 @@ unsafe fn kernel_init() -> ! { /// The main function running after the early init. fn kernel_main() -> ! { use core::time::Duration; - use driver::interface::DriverManager; info!( "{} version {}", @@ -165,13 +163,7 @@ fn kernel_main() -> ! { ); info!("Drivers loaded:"); - for (i, driver) in bsp::driver::driver_manager() - .all_device_drivers() - .iter() - .enumerate() - { - info!(" {}. {}", i + 1, driver.compatible()); - } + driver::driver_manager().enumerate(); // Test a failing timer case. time::time_manager().spin_for(Duration::from_nanos(1)); diff --git a/09_privilege_level/README.md b/09_privilege_level/README.md index 7f7c58d1..5710fdb8 100644 --- a/09_privilege_level/README.md +++ b/09_privilege_level/README.md @@ -519,15 +519,15 @@ diff -uNr 08_hw_debug_JTAG/src/main.rs 09_privilege_level/src/main.rs mod panic_wait; mod print; mod synchronization; -@@ -149,6 +150,7 @@ +@@ -148,6 +149,7 @@ /// The main function running after the early init. fn kernel_main() -> ! { + use console::console; use core::time::Duration; - use driver::interface::DriverManager; -@@ -159,6 +161,12 @@ + info!( +@@ -157,6 +159,12 @@ ); info!("Booting on: {}", bsp::board_name()); @@ -540,9 +540,9 @@ diff -uNr 08_hw_debug_JTAG/src/main.rs 09_privilege_level/src/main.rs info!( "Architectural timer resolution: {} ns", time::time_manager().resolution().as_nanos() -@@ -173,11 +181,15 @@ - info!(" {}. {}", i + 1, driver.compatible()); - } +@@ -165,11 +173,15 @@ + info!("Drivers loaded:"); + driver::driver_manager().enumerate(); - // Test a failing timer case. - time::time_manager().spin_for(Duration::from_nanos(1)); diff --git a/09_privilege_level/src/bsp/raspberrypi.rs b/09_privilege_level/src/bsp/raspberrypi.rs index a9a7261a..fe940677 100644 --- a/09_privilege_level/src/bsp/raspberrypi.rs +++ b/09_privilege_level/src/bsp/raspberrypi.rs @@ -4,7 +4,6 @@ //! Top-level BSP file for the Raspberry Pi 3 and 4. -pub mod console; pub mod cpu; pub mod driver; pub mod memory; diff --git a/09_privilege_level/src/bsp/raspberrypi/console.rs b/09_privilege_level/src/bsp/raspberrypi/console.rs deleted file mode 100644 index 0a630eef..00000000 --- a/09_privilege_level/src/bsp/raspberrypi/console.rs +++ /dev/null @@ -1,16 +0,0 @@ -// SPDX-License-Identifier: MIT OR Apache-2.0 -// -// Copyright (c) 2018-2022 Andre Richter - -//! BSP console facilities. - -use crate::console; - -//-------------------------------------------------------------------------------------------------- -// Public Code -//-------------------------------------------------------------------------------------------------- - -/// Return a reference to the console. -pub fn console() -> &'static dyn console::interface::All { - &super::driver::PL011_UART -} diff --git a/09_privilege_level/src/bsp/raspberrypi/driver.rs b/09_privilege_level/src/bsp/raspberrypi/driver.rs index 8b683ed8..ea843066 100644 --- a/09_privilege_level/src/bsp/raspberrypi/driver.rs +++ b/09_privilege_level/src/bsp/raspberrypi/driver.rs @@ -5,51 +5,67 @@ //! BSP driver support. use super::memory::map::mmio; -use crate::{bsp::device_driver, driver}; +use crate::{bsp::device_driver, console, driver as generic_driver}; +use core::sync::atomic::{AtomicBool, Ordering}; //-------------------------------------------------------------------------------------------------- -// Private Definitions +// Global instances //-------------------------------------------------------------------------------------------------- -/// Device Driver Manager type. -struct BSPDriverManager { - device_drivers: [&'static (dyn DeviceDriver + Sync); 2], -} +static PL011_UART: device_driver::PL011Uart = + unsafe { device_driver::PL011Uart::new(mmio::PL011_UART_START) }; +static GPIO: device_driver::GPIO = unsafe { device_driver::GPIO::new(mmio::GPIO_START) }; //-------------------------------------------------------------------------------------------------- -// Global instances +// Private Code //-------------------------------------------------------------------------------------------------- -pub(super) static PL011_UART: device_driver::PL011Uart = - unsafe { device_driver::PL011Uart::new(mmio::PL011_UART_START) }; +/// This must be called only after successful init of the UART driver. +fn post_init_uart() -> Result<(), &'static str> { + console::register_console(&PL011_UART); -static GPIO: device_driver::GPIO = unsafe { device_driver::GPIO::new(mmio::GPIO_START) }; + Ok(()) +} -static BSP_DRIVER_MANAGER: BSPDriverManager = BSPDriverManager { - device_drivers: [&PL011_UART, &GPIO], -}; +/// This must be called only after successful init of the GPIO driver. +fn post_init_gpio() -> Result<(), &'static str> { + GPIO.map_pl011_uart(); + Ok(()) +} -//-------------------------------------------------------------------------------------------------- -// Public Code -//-------------------------------------------------------------------------------------------------- +fn driver_uart() -> Result<(), &'static str> { + let uart_descriptor = + generic_driver::DeviceDriverDescriptor::new(&PL011_UART, Some(post_init_uart)); + generic_driver::driver_manager().register_driver(uart_descriptor); -/// Return a reference to the driver manager. -pub fn driver_manager() -> &'static impl driver::interface::DriverManager { - &BSP_DRIVER_MANAGER + Ok(()) } -//------------------------------------------------------------------------------ -// OS Interface Code -//------------------------------------------------------------------------------ -use driver::interface::DeviceDriver; +fn driver_gpio() -> Result<(), &'static str> { + let gpio_descriptor = generic_driver::DeviceDriverDescriptor::new(&GPIO, Some(post_init_gpio)); + generic_driver::driver_manager().register_driver(gpio_descriptor); -impl driver::interface::DriverManager for BSPDriverManager { - fn all_device_drivers(&self) -> &[&'static (dyn DeviceDriver + Sync)] { - &self.device_drivers[..] - } + Ok(()) +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- - fn post_device_driver_init(&self) { - // Configure PL011Uart's output pins. - GPIO.map_pl011_uart(); +/// Initialize the driver subsystem. +/// +/// # Safety +/// +/// See child function calls. +pub unsafe fn init() -> Result<(), &'static str> { + static INIT_DONE: AtomicBool = AtomicBool::new(false); + if INIT_DONE.load(Ordering::Relaxed) { + return Err("Init already done"); } + + driver_uart()?; + driver_gpio()?; + + INIT_DONE.store(true, Ordering::Relaxed); + Ok(()) } diff --git a/09_privilege_level/src/console.rs b/09_privilege_level/src/console.rs index c1fb0e53..02b43df9 100644 --- a/09_privilege_level/src/console.rs +++ b/09_privilege_level/src/console.rs @@ -4,7 +4,9 @@ //! System console. -use crate::bsp; +mod null_console; + +use crate::synchronization::{self, NullLock}; //-------------------------------------------------------------------------------------------------- // Public Definitions @@ -54,13 +56,26 @@ pub mod interface { pub trait All: Write + Read + Statistics {} } +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +static CUR_CONSOLE: NullLock<&'static (dyn interface::All + Sync)> = + NullLock::new(&null_console::NULL_CONSOLE); + //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- +use synchronization::interface::Mutex; + +/// Register a new console. +pub fn register_console(new_console: &'static (dyn interface::All + Sync)) { + CUR_CONSOLE.lock(|con| *con = new_console); +} -/// Return a reference to the console. +/// Return a reference to the currently registered console. /// /// This is the global console used by all printing macros. pub fn console() -> &'static dyn interface::All { - bsp::console::console() + CUR_CONSOLE.lock(|con| *con) } diff --git a/09_privilege_level/src/console/null_console.rs b/09_privilege_level/src/console/null_console.rs new file mode 100644 index 00000000..2c64d499 --- /dev/null +++ b/09_privilege_level/src/console/null_console.rs @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2022 Andre Richter + +//! Null console. + +use super::interface; +use core::fmt; + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +pub struct NullConsole; + +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +pub static NULL_CONSOLE: NullConsole = NullConsole {}; + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +impl interface::Write for NullConsole { + fn write_char(&self, _c: char) {} + + fn write_fmt(&self, _args: fmt::Arguments) -> fmt::Result { + fmt::Result::Ok(()) + } + + fn flush(&self) {} +} + +impl interface::Read for NullConsole { + fn clear_rx(&self) {} +} + +impl interface::Statistics for NullConsole {} +impl interface::All for NullConsole {} diff --git a/09_privilege_level/src/driver.rs b/09_privilege_level/src/driver.rs index 2fcc7562..a798c86d 100644 --- a/09_privilege_level/src/driver.rs +++ b/09_privilege_level/src/driver.rs @@ -4,6 +4,22 @@ //! Driver support. +use crate::{ + info, + synchronization::{interface::Mutex, NullLock}, +}; + +//-------------------------------------------------------------------------------------------------- +// Private Definitions +//-------------------------------------------------------------------------------------------------- + +const NUM_DRIVERS: usize = 5; + +struct DriverManagerInner { + next_index: usize, + descriptors: [Option; NUM_DRIVERS], +} + //-------------------------------------------------------------------------------------------------- // Public Definitions //-------------------------------------------------------------------------------------------------- @@ -24,21 +40,128 @@ pub mod interface { Ok(()) } } +} + +/// Tpye to be used as an optional callback after a driver's init() has run. +pub type DeviceDriverPostInitCallback = unsafe fn() -> Result<(), &'static str>; + +/// A descriptor for device drivers. +#[derive(Copy, Clone)] +pub struct DeviceDriverDescriptor { + device_driver: &'static (dyn interface::DeviceDriver + Sync), + post_init_callback: Option, +} + +/// Provides device driver management functions. +pub struct DriverManager { + inner: NullLock, +} + +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +static DRIVER_MANAGER: DriverManager = DriverManager::new(); + +//-------------------------------------------------------------------------------------------------- +// Private Code +//-------------------------------------------------------------------------------------------------- + +impl DriverManagerInner { + /// Create an instance. + pub const fn new() -> Self { + Self { + next_index: 0, + descriptors: [None; NUM_DRIVERS], + } + } +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +impl DeviceDriverDescriptor { + /// Create an instance. + pub fn new( + device_driver: &'static (dyn interface::DeviceDriver + Sync), + post_init_callback: Option, + ) -> Self { + Self { + device_driver, + post_init_callback, + } + } +} + +/// Return a reference to the global DriverManager. +pub fn driver_manager() -> &'static DriverManager { + &DRIVER_MANAGER +} + +impl DriverManager { + /// Create an instance. + pub const fn new() -> Self { + Self { + inner: NullLock::new(DriverManagerInner::new()), + } + } - /// Device driver management functions. + /// Register a device driver with the kernel. + pub fn register_driver(&self, descriptor: DeviceDriverDescriptor) { + self.inner.lock(|inner| { + inner.descriptors[inner.next_index] = Some(descriptor); + inner.next_index += 1; + }) + } + + /// Helper for iterating over registered drivers. + fn for_each_descriptor<'a>(&'a self, f: impl FnMut(&'a DeviceDriverDescriptor)) { + self.inner.lock(|inner| { + inner + .descriptors + .iter() + .filter_map(|x| x.as_ref()) + .for_each(f) + }) + } + + /// Fully initialize all drivers. /// - /// The `BSP` is supposed to supply one global instance. - pub trait DriverManager { - /// Return a slice of references to all `BSP`-instantiated drivers. - /// - /// # Safety - /// - /// - The order of devices is the order in which `DeviceDriver::init()` is called. - fn all_device_drivers(&self) -> &[&'static (dyn DeviceDriver + Sync)]; + /// # Safety + /// + /// - During init, drivers might do stuff with system-wide impact. + pub unsafe fn init_drivers(&self) { + self.for_each_descriptor(|descriptor| { + // 1. Initialize driver. + if let Err(x) = descriptor.device_driver.init() { + panic!( + "Error initializing driver: {}: {}", + descriptor.device_driver.compatible(), + x + ); + } - /// Initialization code that runs after driver init. - /// - /// For example, device driver code that depends on other drivers already being online. - fn post_device_driver_init(&self); + // 2. Call corresponding post init callback. + if let Some(callback) = &descriptor.post_init_callback { + if let Err(x) = callback() { + panic!( + "Error during driver post-init callback: {}: {}", + descriptor.device_driver.compatible(), + x + ); + } + } + }); + } + + /// Enumerate all registered device drivers. + pub fn enumerate(&self) { + let mut i: usize = 1; + self.for_each_descriptor(|descriptor| { + info!(" {}. {}", i, descriptor.device_driver.compatible()); + + i += 1; + }); } } diff --git a/09_privilege_level/src/main.rs b/09_privilege_level/src/main.rs index 79a6716e..c60aee8e 100644 --- a/09_privilege_level/src/main.rs +++ b/09_privilege_level/src/main.rs @@ -134,14 +134,13 @@ mod time; /// - Only a single core must be active and running this function. /// - The init calls in this function must appear in the correct order. unsafe fn kernel_init() -> ! { - use driver::interface::DriverManager; - - for i in bsp::driver::driver_manager().all_device_drivers().iter() { - if let Err(x) = i.init() { - panic!("Error loading driver: {}: {}", i.compatible(), x); - } + // Initialize the BSP driver subsystem. + if let Err(x) = bsp::driver::init() { + panic!("Error initializing BSP driver subsystem: {}", x); } - bsp::driver::driver_manager().post_device_driver_init(); + + // Initialize all device drivers. + driver::driver_manager().init_drivers(); // println! is usable from here on. // Transition from unsafe to safe. @@ -152,7 +151,6 @@ unsafe fn kernel_init() -> ! { fn kernel_main() -> ! { use console::console; use core::time::Duration; - use driver::interface::DriverManager; info!( "{} version {}", @@ -173,13 +171,7 @@ fn kernel_main() -> ! { ); info!("Drivers loaded:"); - for (i, driver) in bsp::driver::driver_manager() - .all_device_drivers() - .iter() - .enumerate() - { - info!(" {}. {}", i + 1, driver.compatible()); - } + driver::driver_manager().enumerate(); info!("Timer test, spinning for 1 second"); time::time_manager().spin_for(Duration::from_secs(1)); diff --git a/10_virtual_mem_part1_identity_mapping/README.md b/10_virtual_mem_part1_identity_mapping/README.md index f1d22d98..946500dc 100644 --- a/10_virtual_mem_part1_identity_mapping/README.md +++ b/10_virtual_mem_part1_identity_mapping/README.md @@ -296,7 +296,6 @@ Turning on virtual memory is now the first thing we do during kernel init: ```rust unsafe fn kernel_init() -> ! { - use driver::interface::DriverManager; use memory::mmu::interface::MMU; if let Err(string) = memory::mmu::mmu().enable_mmu_and_caching() { @@ -1135,7 +1134,7 @@ diff -uNr 09_privilege_level/src/main.rs 10_virtual_mem_part1_identity_mapping/s mod panic_wait; mod print; mod synchronization; -@@ -132,9 +137,17 @@ +@@ -132,8 +137,17 @@ /// # Safety /// /// - Only a single core must be active and running this function. @@ -1145,25 +1144,25 @@ diff -uNr 09_privilege_level/src/main.rs 10_virtual_mem_part1_identity_mapping/s +/// e.g. the yet-to-be-introduced spinlocks in the device drivers (which currently employ +/// NullLocks instead of spinlocks), will fail to work (properly) on the RPi SoCs. unsafe fn kernel_init() -> ! { - use driver::interface::DriverManager; + use memory::mmu::interface::MMU; + + if let Err(string) = memory::mmu::mmu().enable_mmu_and_caching() { + panic!("MMU: {}", string); + } - - for i in bsp::driver::driver_manager().all_device_drivers().iter() { - if let Err(x) = i.init() { -@@ -150,7 +163,7 @@ ++ + // Initialize the BSP driver subsystem. + if let Err(x) = bsp::driver::init() { + panic!("Error initializing BSP driver subsystem: {}", x); +@@ -149,7 +163,7 @@ /// The main function running after the early init. fn kernel_main() -> ! { - use console::console; + use console::{console, interface::Write}; use core::time::Duration; - use driver::interface::DriverManager; -@@ -161,6 +174,9 @@ + info!( +@@ -159,6 +173,9 @@ ); info!("Booting on: {}", bsp::board_name()); @@ -1173,7 +1172,7 @@ diff -uNr 09_privilege_level/src/main.rs 10_virtual_mem_part1_identity_mapping/s let (_, privilege_level) = exception::current_privilege_level(); info!("Current privilege level: {}", privilege_level); -@@ -184,6 +200,13 @@ +@@ -176,6 +193,13 @@ info!("Timer test, spinning for 1 second"); time::time_manager().spin_for(Duration::from_secs(1)); diff --git a/10_virtual_mem_part1_identity_mapping/src/bsp/raspberrypi.rs b/10_virtual_mem_part1_identity_mapping/src/bsp/raspberrypi.rs index a9a7261a..fe940677 100644 --- a/10_virtual_mem_part1_identity_mapping/src/bsp/raspberrypi.rs +++ b/10_virtual_mem_part1_identity_mapping/src/bsp/raspberrypi.rs @@ -4,7 +4,6 @@ //! Top-level BSP file for the Raspberry Pi 3 and 4. -pub mod console; pub mod cpu; pub mod driver; pub mod memory; diff --git a/10_virtual_mem_part1_identity_mapping/src/bsp/raspberrypi/console.rs b/10_virtual_mem_part1_identity_mapping/src/bsp/raspberrypi/console.rs deleted file mode 100644 index 0a630eef..00000000 --- a/10_virtual_mem_part1_identity_mapping/src/bsp/raspberrypi/console.rs +++ /dev/null @@ -1,16 +0,0 @@ -// SPDX-License-Identifier: MIT OR Apache-2.0 -// -// Copyright (c) 2018-2022 Andre Richter - -//! BSP console facilities. - -use crate::console; - -//-------------------------------------------------------------------------------------------------- -// Public Code -//-------------------------------------------------------------------------------------------------- - -/// Return a reference to the console. -pub fn console() -> &'static dyn console::interface::All { - &super::driver::PL011_UART -} diff --git a/10_virtual_mem_part1_identity_mapping/src/bsp/raspberrypi/driver.rs b/10_virtual_mem_part1_identity_mapping/src/bsp/raspberrypi/driver.rs index 8b683ed8..ea843066 100644 --- a/10_virtual_mem_part1_identity_mapping/src/bsp/raspberrypi/driver.rs +++ b/10_virtual_mem_part1_identity_mapping/src/bsp/raspberrypi/driver.rs @@ -5,51 +5,67 @@ //! BSP driver support. use super::memory::map::mmio; -use crate::{bsp::device_driver, driver}; +use crate::{bsp::device_driver, console, driver as generic_driver}; +use core::sync::atomic::{AtomicBool, Ordering}; //-------------------------------------------------------------------------------------------------- -// Private Definitions +// Global instances //-------------------------------------------------------------------------------------------------- -/// Device Driver Manager type. -struct BSPDriverManager { - device_drivers: [&'static (dyn DeviceDriver + Sync); 2], -} +static PL011_UART: device_driver::PL011Uart = + unsafe { device_driver::PL011Uart::new(mmio::PL011_UART_START) }; +static GPIO: device_driver::GPIO = unsafe { device_driver::GPIO::new(mmio::GPIO_START) }; //-------------------------------------------------------------------------------------------------- -// Global instances +// Private Code //-------------------------------------------------------------------------------------------------- -pub(super) static PL011_UART: device_driver::PL011Uart = - unsafe { device_driver::PL011Uart::new(mmio::PL011_UART_START) }; +/// This must be called only after successful init of the UART driver. +fn post_init_uart() -> Result<(), &'static str> { + console::register_console(&PL011_UART); -static GPIO: device_driver::GPIO = unsafe { device_driver::GPIO::new(mmio::GPIO_START) }; + Ok(()) +} -static BSP_DRIVER_MANAGER: BSPDriverManager = BSPDriverManager { - device_drivers: [&PL011_UART, &GPIO], -}; +/// This must be called only after successful init of the GPIO driver. +fn post_init_gpio() -> Result<(), &'static str> { + GPIO.map_pl011_uart(); + Ok(()) +} -//-------------------------------------------------------------------------------------------------- -// Public Code -//-------------------------------------------------------------------------------------------------- +fn driver_uart() -> Result<(), &'static str> { + let uart_descriptor = + generic_driver::DeviceDriverDescriptor::new(&PL011_UART, Some(post_init_uart)); + generic_driver::driver_manager().register_driver(uart_descriptor); -/// Return a reference to the driver manager. -pub fn driver_manager() -> &'static impl driver::interface::DriverManager { - &BSP_DRIVER_MANAGER + Ok(()) } -//------------------------------------------------------------------------------ -// OS Interface Code -//------------------------------------------------------------------------------ -use driver::interface::DeviceDriver; +fn driver_gpio() -> Result<(), &'static str> { + let gpio_descriptor = generic_driver::DeviceDriverDescriptor::new(&GPIO, Some(post_init_gpio)); + generic_driver::driver_manager().register_driver(gpio_descriptor); -impl driver::interface::DriverManager for BSPDriverManager { - fn all_device_drivers(&self) -> &[&'static (dyn DeviceDriver + Sync)] { - &self.device_drivers[..] - } + Ok(()) +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- - fn post_device_driver_init(&self) { - // Configure PL011Uart's output pins. - GPIO.map_pl011_uart(); +/// Initialize the driver subsystem. +/// +/// # Safety +/// +/// See child function calls. +pub unsafe fn init() -> Result<(), &'static str> { + static INIT_DONE: AtomicBool = AtomicBool::new(false); + if INIT_DONE.load(Ordering::Relaxed) { + return Err("Init already done"); } + + driver_uart()?; + driver_gpio()?; + + INIT_DONE.store(true, Ordering::Relaxed); + Ok(()) } diff --git a/10_virtual_mem_part1_identity_mapping/src/console.rs b/10_virtual_mem_part1_identity_mapping/src/console.rs index c1fb0e53..02b43df9 100644 --- a/10_virtual_mem_part1_identity_mapping/src/console.rs +++ b/10_virtual_mem_part1_identity_mapping/src/console.rs @@ -4,7 +4,9 @@ //! System console. -use crate::bsp; +mod null_console; + +use crate::synchronization::{self, NullLock}; //-------------------------------------------------------------------------------------------------- // Public Definitions @@ -54,13 +56,26 @@ pub mod interface { pub trait All: Write + Read + Statistics {} } +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +static CUR_CONSOLE: NullLock<&'static (dyn interface::All + Sync)> = + NullLock::new(&null_console::NULL_CONSOLE); + //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- +use synchronization::interface::Mutex; + +/// Register a new console. +pub fn register_console(new_console: &'static (dyn interface::All + Sync)) { + CUR_CONSOLE.lock(|con| *con = new_console); +} -/// Return a reference to the console. +/// Return a reference to the currently registered console. /// /// This is the global console used by all printing macros. pub fn console() -> &'static dyn interface::All { - bsp::console::console() + CUR_CONSOLE.lock(|con| *con) } diff --git a/10_virtual_mem_part1_identity_mapping/src/console/null_console.rs b/10_virtual_mem_part1_identity_mapping/src/console/null_console.rs new file mode 100644 index 00000000..2c64d499 --- /dev/null +++ b/10_virtual_mem_part1_identity_mapping/src/console/null_console.rs @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2022 Andre Richter + +//! Null console. + +use super::interface; +use core::fmt; + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +pub struct NullConsole; + +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +pub static NULL_CONSOLE: NullConsole = NullConsole {}; + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +impl interface::Write for NullConsole { + fn write_char(&self, _c: char) {} + + fn write_fmt(&self, _args: fmt::Arguments) -> fmt::Result { + fmt::Result::Ok(()) + } + + fn flush(&self) {} +} + +impl interface::Read for NullConsole { + fn clear_rx(&self) {} +} + +impl interface::Statistics for NullConsole {} +impl interface::All for NullConsole {} diff --git a/10_virtual_mem_part1_identity_mapping/src/driver.rs b/10_virtual_mem_part1_identity_mapping/src/driver.rs index 2fcc7562..a798c86d 100644 --- a/10_virtual_mem_part1_identity_mapping/src/driver.rs +++ b/10_virtual_mem_part1_identity_mapping/src/driver.rs @@ -4,6 +4,22 @@ //! Driver support. +use crate::{ + info, + synchronization::{interface::Mutex, NullLock}, +}; + +//-------------------------------------------------------------------------------------------------- +// Private Definitions +//-------------------------------------------------------------------------------------------------- + +const NUM_DRIVERS: usize = 5; + +struct DriverManagerInner { + next_index: usize, + descriptors: [Option; NUM_DRIVERS], +} + //-------------------------------------------------------------------------------------------------- // Public Definitions //-------------------------------------------------------------------------------------------------- @@ -24,21 +40,128 @@ pub mod interface { Ok(()) } } +} + +/// Tpye to be used as an optional callback after a driver's init() has run. +pub type DeviceDriverPostInitCallback = unsafe fn() -> Result<(), &'static str>; + +/// A descriptor for device drivers. +#[derive(Copy, Clone)] +pub struct DeviceDriverDescriptor { + device_driver: &'static (dyn interface::DeviceDriver + Sync), + post_init_callback: Option, +} + +/// Provides device driver management functions. +pub struct DriverManager { + inner: NullLock, +} + +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +static DRIVER_MANAGER: DriverManager = DriverManager::new(); + +//-------------------------------------------------------------------------------------------------- +// Private Code +//-------------------------------------------------------------------------------------------------- + +impl DriverManagerInner { + /// Create an instance. + pub const fn new() -> Self { + Self { + next_index: 0, + descriptors: [None; NUM_DRIVERS], + } + } +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +impl DeviceDriverDescriptor { + /// Create an instance. + pub fn new( + device_driver: &'static (dyn interface::DeviceDriver + Sync), + post_init_callback: Option, + ) -> Self { + Self { + device_driver, + post_init_callback, + } + } +} + +/// Return a reference to the global DriverManager. +pub fn driver_manager() -> &'static DriverManager { + &DRIVER_MANAGER +} + +impl DriverManager { + /// Create an instance. + pub const fn new() -> Self { + Self { + inner: NullLock::new(DriverManagerInner::new()), + } + } - /// Device driver management functions. + /// Register a device driver with the kernel. + pub fn register_driver(&self, descriptor: DeviceDriverDescriptor) { + self.inner.lock(|inner| { + inner.descriptors[inner.next_index] = Some(descriptor); + inner.next_index += 1; + }) + } + + /// Helper for iterating over registered drivers. + fn for_each_descriptor<'a>(&'a self, f: impl FnMut(&'a DeviceDriverDescriptor)) { + self.inner.lock(|inner| { + inner + .descriptors + .iter() + .filter_map(|x| x.as_ref()) + .for_each(f) + }) + } + + /// Fully initialize all drivers. /// - /// The `BSP` is supposed to supply one global instance. - pub trait DriverManager { - /// Return a slice of references to all `BSP`-instantiated drivers. - /// - /// # Safety - /// - /// - The order of devices is the order in which `DeviceDriver::init()` is called. - fn all_device_drivers(&self) -> &[&'static (dyn DeviceDriver + Sync)]; + /// # Safety + /// + /// - During init, drivers might do stuff with system-wide impact. + pub unsafe fn init_drivers(&self) { + self.for_each_descriptor(|descriptor| { + // 1. Initialize driver. + if let Err(x) = descriptor.device_driver.init() { + panic!( + "Error initializing driver: {}: {}", + descriptor.device_driver.compatible(), + x + ); + } - /// Initialization code that runs after driver init. - /// - /// For example, device driver code that depends on other drivers already being online. - fn post_device_driver_init(&self); + // 2. Call corresponding post init callback. + if let Some(callback) = &descriptor.post_init_callback { + if let Err(x) = callback() { + panic!( + "Error during driver post-init callback: {}: {}", + descriptor.device_driver.compatible(), + x + ); + } + } + }); + } + + /// Enumerate all registered device drivers. + pub fn enumerate(&self) { + let mut i: usize = 1; + self.for_each_descriptor(|descriptor| { + info!(" {}. {}", i, descriptor.device_driver.compatible()); + + i += 1; + }); } } diff --git a/10_virtual_mem_part1_identity_mapping/src/main.rs b/10_virtual_mem_part1_identity_mapping/src/main.rs index e038e093..b40a37bf 100644 --- a/10_virtual_mem_part1_identity_mapping/src/main.rs +++ b/10_virtual_mem_part1_identity_mapping/src/main.rs @@ -142,19 +142,19 @@ mod time; /// e.g. the yet-to-be-introduced spinlocks in the device drivers (which currently employ /// NullLocks instead of spinlocks), will fail to work (properly) on the RPi SoCs. unsafe fn kernel_init() -> ! { - use driver::interface::DriverManager; use memory::mmu::interface::MMU; if let Err(string) = memory::mmu::mmu().enable_mmu_and_caching() { panic!("MMU: {}", string); } - for i in bsp::driver::driver_manager().all_device_drivers().iter() { - if let Err(x) = i.init() { - panic!("Error loading driver: {}: {}", i.compatible(), x); - } + // Initialize the BSP driver subsystem. + if let Err(x) = bsp::driver::init() { + panic!("Error initializing BSP driver subsystem: {}", x); } - bsp::driver::driver_manager().post_device_driver_init(); + + // Initialize all device drivers. + driver::driver_manager().init_drivers(); // println! is usable from here on. // Transition from unsafe to safe. @@ -165,7 +165,6 @@ unsafe fn kernel_init() -> ! { fn kernel_main() -> ! { use console::{console, interface::Write}; use core::time::Duration; - use driver::interface::DriverManager; info!( "{} version {}", @@ -189,13 +188,7 @@ fn kernel_main() -> ! { ); info!("Drivers loaded:"); - for (i, driver) in bsp::driver::driver_manager() - .all_device_drivers() - .iter() - .enumerate() - { - info!(" {}. {}", i + 1, driver.compatible()); - } + driver::driver_manager().enumerate(); info!("Timer test, spinning for 1 second"); time::time_manager().spin_for(Duration::from_secs(1)); diff --git a/11_exceptions_part1_groundwork/README.md b/11_exceptions_part1_groundwork/README.md index 3e7ca05e..12812acb 100644 --- a/11_exceptions_part1_groundwork/README.md +++ b/11_exceptions_part1_groundwork/README.md @@ -1024,8 +1024,8 @@ diff -uNr 10_virtual_mem_part1_identity_mapping/src/exception.rs 11_exceptions_p diff -uNr 10_virtual_mem_part1_identity_mapping/src/main.rs 11_exceptions_part1_groundwork/src/main.rs --- 10_virtual_mem_part1_identity_mapping/src/main.rs +++ 11_exceptions_part1_groundwork/src/main.rs -@@ -145,6 +145,8 @@ - use driver::interface::DriverManager; +@@ -144,6 +144,8 @@ + unsafe fn kernel_init() -> ! { use memory::mmu::interface::MMU; + exception::handling_init(); @@ -1040,9 +1040,9 @@ diff -uNr 10_virtual_mem_part1_identity_mapping/src/main.rs 11_exceptions_part1_ - use console::{console, interface::Write}; + use console::console; use core::time::Duration; - use driver::interface::DriverManager; -@@ -200,13 +202,28 @@ + info!( +@@ -193,13 +195,28 @@ info!("Timer test, spinning for 1 second"); time::time_manager().spin_for(Duration::from_secs(1)); diff --git a/11_exceptions_part1_groundwork/src/bsp/raspberrypi.rs b/11_exceptions_part1_groundwork/src/bsp/raspberrypi.rs index a9a7261a..fe940677 100644 --- a/11_exceptions_part1_groundwork/src/bsp/raspberrypi.rs +++ b/11_exceptions_part1_groundwork/src/bsp/raspberrypi.rs @@ -4,7 +4,6 @@ //! Top-level BSP file for the Raspberry Pi 3 and 4. -pub mod console; pub mod cpu; pub mod driver; pub mod memory; diff --git a/11_exceptions_part1_groundwork/src/bsp/raspberrypi/console.rs b/11_exceptions_part1_groundwork/src/bsp/raspberrypi/console.rs deleted file mode 100644 index 0a630eef..00000000 --- a/11_exceptions_part1_groundwork/src/bsp/raspberrypi/console.rs +++ /dev/null @@ -1,16 +0,0 @@ -// SPDX-License-Identifier: MIT OR Apache-2.0 -// -// Copyright (c) 2018-2022 Andre Richter - -//! BSP console facilities. - -use crate::console; - -//-------------------------------------------------------------------------------------------------- -// Public Code -//-------------------------------------------------------------------------------------------------- - -/// Return a reference to the console. -pub fn console() -> &'static dyn console::interface::All { - &super::driver::PL011_UART -} diff --git a/11_exceptions_part1_groundwork/src/bsp/raspberrypi/driver.rs b/11_exceptions_part1_groundwork/src/bsp/raspberrypi/driver.rs index 8b683ed8..ea843066 100644 --- a/11_exceptions_part1_groundwork/src/bsp/raspberrypi/driver.rs +++ b/11_exceptions_part1_groundwork/src/bsp/raspberrypi/driver.rs @@ -5,51 +5,67 @@ //! BSP driver support. use super::memory::map::mmio; -use crate::{bsp::device_driver, driver}; +use crate::{bsp::device_driver, console, driver as generic_driver}; +use core::sync::atomic::{AtomicBool, Ordering}; //-------------------------------------------------------------------------------------------------- -// Private Definitions +// Global instances //-------------------------------------------------------------------------------------------------- -/// Device Driver Manager type. -struct BSPDriverManager { - device_drivers: [&'static (dyn DeviceDriver + Sync); 2], -} +static PL011_UART: device_driver::PL011Uart = + unsafe { device_driver::PL011Uart::new(mmio::PL011_UART_START) }; +static GPIO: device_driver::GPIO = unsafe { device_driver::GPIO::new(mmio::GPIO_START) }; //-------------------------------------------------------------------------------------------------- -// Global instances +// Private Code //-------------------------------------------------------------------------------------------------- -pub(super) static PL011_UART: device_driver::PL011Uart = - unsafe { device_driver::PL011Uart::new(mmio::PL011_UART_START) }; +/// This must be called only after successful init of the UART driver. +fn post_init_uart() -> Result<(), &'static str> { + console::register_console(&PL011_UART); -static GPIO: device_driver::GPIO = unsafe { device_driver::GPIO::new(mmio::GPIO_START) }; + Ok(()) +} -static BSP_DRIVER_MANAGER: BSPDriverManager = BSPDriverManager { - device_drivers: [&PL011_UART, &GPIO], -}; +/// This must be called only after successful init of the GPIO driver. +fn post_init_gpio() -> Result<(), &'static str> { + GPIO.map_pl011_uart(); + Ok(()) +} -//-------------------------------------------------------------------------------------------------- -// Public Code -//-------------------------------------------------------------------------------------------------- +fn driver_uart() -> Result<(), &'static str> { + let uart_descriptor = + generic_driver::DeviceDriverDescriptor::new(&PL011_UART, Some(post_init_uart)); + generic_driver::driver_manager().register_driver(uart_descriptor); -/// Return a reference to the driver manager. -pub fn driver_manager() -> &'static impl driver::interface::DriverManager { - &BSP_DRIVER_MANAGER + Ok(()) } -//------------------------------------------------------------------------------ -// OS Interface Code -//------------------------------------------------------------------------------ -use driver::interface::DeviceDriver; +fn driver_gpio() -> Result<(), &'static str> { + let gpio_descriptor = generic_driver::DeviceDriverDescriptor::new(&GPIO, Some(post_init_gpio)); + generic_driver::driver_manager().register_driver(gpio_descriptor); -impl driver::interface::DriverManager for BSPDriverManager { - fn all_device_drivers(&self) -> &[&'static (dyn DeviceDriver + Sync)] { - &self.device_drivers[..] - } + Ok(()) +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- - fn post_device_driver_init(&self) { - // Configure PL011Uart's output pins. - GPIO.map_pl011_uart(); +/// Initialize the driver subsystem. +/// +/// # Safety +/// +/// See child function calls. +pub unsafe fn init() -> Result<(), &'static str> { + static INIT_DONE: AtomicBool = AtomicBool::new(false); + if INIT_DONE.load(Ordering::Relaxed) { + return Err("Init already done"); } + + driver_uart()?; + driver_gpio()?; + + INIT_DONE.store(true, Ordering::Relaxed); + Ok(()) } diff --git a/11_exceptions_part1_groundwork/src/console.rs b/11_exceptions_part1_groundwork/src/console.rs index c1fb0e53..02b43df9 100644 --- a/11_exceptions_part1_groundwork/src/console.rs +++ b/11_exceptions_part1_groundwork/src/console.rs @@ -4,7 +4,9 @@ //! System console. -use crate::bsp; +mod null_console; + +use crate::synchronization::{self, NullLock}; //-------------------------------------------------------------------------------------------------- // Public Definitions @@ -54,13 +56,26 @@ pub mod interface { pub trait All: Write + Read + Statistics {} } +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +static CUR_CONSOLE: NullLock<&'static (dyn interface::All + Sync)> = + NullLock::new(&null_console::NULL_CONSOLE); + //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- +use synchronization::interface::Mutex; + +/// Register a new console. +pub fn register_console(new_console: &'static (dyn interface::All + Sync)) { + CUR_CONSOLE.lock(|con| *con = new_console); +} -/// Return a reference to the console. +/// Return a reference to the currently registered console. /// /// This is the global console used by all printing macros. pub fn console() -> &'static dyn interface::All { - bsp::console::console() + CUR_CONSOLE.lock(|con| *con) } diff --git a/11_exceptions_part1_groundwork/src/console/null_console.rs b/11_exceptions_part1_groundwork/src/console/null_console.rs new file mode 100644 index 00000000..2c64d499 --- /dev/null +++ b/11_exceptions_part1_groundwork/src/console/null_console.rs @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2022 Andre Richter + +//! Null console. + +use super::interface; +use core::fmt; + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +pub struct NullConsole; + +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +pub static NULL_CONSOLE: NullConsole = NullConsole {}; + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +impl interface::Write for NullConsole { + fn write_char(&self, _c: char) {} + + fn write_fmt(&self, _args: fmt::Arguments) -> fmt::Result { + fmt::Result::Ok(()) + } + + fn flush(&self) {} +} + +impl interface::Read for NullConsole { + fn clear_rx(&self) {} +} + +impl interface::Statistics for NullConsole {} +impl interface::All for NullConsole {} diff --git a/11_exceptions_part1_groundwork/src/driver.rs b/11_exceptions_part1_groundwork/src/driver.rs index 2fcc7562..a798c86d 100644 --- a/11_exceptions_part1_groundwork/src/driver.rs +++ b/11_exceptions_part1_groundwork/src/driver.rs @@ -4,6 +4,22 @@ //! Driver support. +use crate::{ + info, + synchronization::{interface::Mutex, NullLock}, +}; + +//-------------------------------------------------------------------------------------------------- +// Private Definitions +//-------------------------------------------------------------------------------------------------- + +const NUM_DRIVERS: usize = 5; + +struct DriverManagerInner { + next_index: usize, + descriptors: [Option; NUM_DRIVERS], +} + //-------------------------------------------------------------------------------------------------- // Public Definitions //-------------------------------------------------------------------------------------------------- @@ -24,21 +40,128 @@ pub mod interface { Ok(()) } } +} + +/// Tpye to be used as an optional callback after a driver's init() has run. +pub type DeviceDriverPostInitCallback = unsafe fn() -> Result<(), &'static str>; + +/// A descriptor for device drivers. +#[derive(Copy, Clone)] +pub struct DeviceDriverDescriptor { + device_driver: &'static (dyn interface::DeviceDriver + Sync), + post_init_callback: Option, +} + +/// Provides device driver management functions. +pub struct DriverManager { + inner: NullLock, +} + +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +static DRIVER_MANAGER: DriverManager = DriverManager::new(); + +//-------------------------------------------------------------------------------------------------- +// Private Code +//-------------------------------------------------------------------------------------------------- + +impl DriverManagerInner { + /// Create an instance. + pub const fn new() -> Self { + Self { + next_index: 0, + descriptors: [None; NUM_DRIVERS], + } + } +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +impl DeviceDriverDescriptor { + /// Create an instance. + pub fn new( + device_driver: &'static (dyn interface::DeviceDriver + Sync), + post_init_callback: Option, + ) -> Self { + Self { + device_driver, + post_init_callback, + } + } +} + +/// Return a reference to the global DriverManager. +pub fn driver_manager() -> &'static DriverManager { + &DRIVER_MANAGER +} + +impl DriverManager { + /// Create an instance. + pub const fn new() -> Self { + Self { + inner: NullLock::new(DriverManagerInner::new()), + } + } - /// Device driver management functions. + /// Register a device driver with the kernel. + pub fn register_driver(&self, descriptor: DeviceDriverDescriptor) { + self.inner.lock(|inner| { + inner.descriptors[inner.next_index] = Some(descriptor); + inner.next_index += 1; + }) + } + + /// Helper for iterating over registered drivers. + fn for_each_descriptor<'a>(&'a self, f: impl FnMut(&'a DeviceDriverDescriptor)) { + self.inner.lock(|inner| { + inner + .descriptors + .iter() + .filter_map(|x| x.as_ref()) + .for_each(f) + }) + } + + /// Fully initialize all drivers. /// - /// The `BSP` is supposed to supply one global instance. - pub trait DriverManager { - /// Return a slice of references to all `BSP`-instantiated drivers. - /// - /// # Safety - /// - /// - The order of devices is the order in which `DeviceDriver::init()` is called. - fn all_device_drivers(&self) -> &[&'static (dyn DeviceDriver + Sync)]; + /// # Safety + /// + /// - During init, drivers might do stuff with system-wide impact. + pub unsafe fn init_drivers(&self) { + self.for_each_descriptor(|descriptor| { + // 1. Initialize driver. + if let Err(x) = descriptor.device_driver.init() { + panic!( + "Error initializing driver: {}: {}", + descriptor.device_driver.compatible(), + x + ); + } - /// Initialization code that runs after driver init. - /// - /// For example, device driver code that depends on other drivers already being online. - fn post_device_driver_init(&self); + // 2. Call corresponding post init callback. + if let Some(callback) = &descriptor.post_init_callback { + if let Err(x) = callback() { + panic!( + "Error during driver post-init callback: {}: {}", + descriptor.device_driver.compatible(), + x + ); + } + } + }); + } + + /// Enumerate all registered device drivers. + pub fn enumerate(&self) { + let mut i: usize = 1; + self.for_each_descriptor(|descriptor| { + info!(" {}. {}", i, descriptor.device_driver.compatible()); + + i += 1; + }); } } diff --git a/11_exceptions_part1_groundwork/src/main.rs b/11_exceptions_part1_groundwork/src/main.rs index 8e632fa5..9d300bf0 100644 --- a/11_exceptions_part1_groundwork/src/main.rs +++ b/11_exceptions_part1_groundwork/src/main.rs @@ -142,7 +142,6 @@ mod time; /// e.g. the yet-to-be-introduced spinlocks in the device drivers (which currently employ /// NullLocks instead of spinlocks), will fail to work (properly) on the RPi SoCs. unsafe fn kernel_init() -> ! { - use driver::interface::DriverManager; use memory::mmu::interface::MMU; exception::handling_init(); @@ -151,12 +150,13 @@ unsafe fn kernel_init() -> ! { panic!("MMU: {}", string); } - for i in bsp::driver::driver_manager().all_device_drivers().iter() { - if let Err(x) = i.init() { - panic!("Error loading driver: {}: {}", i.compatible(), x); - } + // Initialize the BSP driver subsystem. + if let Err(x) = bsp::driver::init() { + panic!("Error initializing BSP driver subsystem: {}", x); } - bsp::driver::driver_manager().post_device_driver_init(); + + // Initialize all device drivers. + driver::driver_manager().init_drivers(); // println! is usable from here on. // Transition from unsafe to safe. @@ -167,7 +167,6 @@ unsafe fn kernel_init() -> ! { fn kernel_main() -> ! { use console::console; use core::time::Duration; - use driver::interface::DriverManager; info!( "{} version {}", @@ -191,13 +190,7 @@ fn kernel_main() -> ! { ); info!("Drivers loaded:"); - for (i, driver) in bsp::driver::driver_manager() - .all_device_drivers() - .iter() - .enumerate() - { - info!(" {}. {}", i + 1, driver.compatible()); - } + driver::driver_manager().enumerate(); info!("Timer test, spinning for 1 second"); time::time_manager().spin_for(Duration::from_secs(1)); diff --git a/12_integrated_testing/Makefile b/12_integrated_testing/Makefile index 670c30c4..2d480119 100644 --- a/12_integrated_testing/Makefile +++ b/12_integrated_testing/Makefile @@ -291,7 +291,7 @@ test_boot: $(KERNEL_BIN) ## Helpers for unit and integration test targets ##------------------------------------------------------------------------------ define KERNEL_TEST_RUNNER - #!/usr/bin/env bash +#!/usr/bin/env bash # The cargo test runner seems to change into the crate under test's directory. Therefore, ensure # this script executes from the root. diff --git a/12_integrated_testing/README.md b/12_integrated_testing/README.md index c5d032e8..ae68d269 100644 --- a/12_integrated_testing/README.md +++ b/12_integrated_testing/README.md @@ -266,10 +266,8 @@ implementation in `lib.rs`: #[cfg(test)] #[no_mangle] unsafe fn kernel_init() -> ! { - use driver::interface::DriverManager; - exception::handling_init(); - bsp::driver::driver_manager().qemu_bring_up_console(); + bsp::driver::qemu_bring_up_console(); test_main(); @@ -277,12 +275,12 @@ unsafe fn kernel_init() -> ! { } ``` -Note the call to `bsp::driver::driver_manager().qemu_bring_up_console()`. Since we are running all -our tests inside `QEMU`, we need to ensure that whatever peripheral implements the kernel's -`console` interface is initialized, so that we can print from our tests. If you recall [tutorial -03], bringing up peripherals in `QEMU` might not need the full initialization as is needed on real -hardware (setting clocks, config registers, etc...) due to the abstractions in `QEMU`'s emulation -code. So this is an opportunity to cut down on setup code. +Note the call to `bsp::driver::qemu_bring_up_console()`. Since we are running all our tests inside +`QEMU`, we need to ensure that whatever peripheral implements the kernel's `console` interface is +initialized, so that we can print from our tests. If you recall [tutorial 03], bringing up +peripherals in `QEMU` might not need the full initialization as is needed on real hardware (setting +clocks, config registers, etc...) due to the abstractions in `QEMU`'s emulation code. So this is an +opportunity to cut down on setup code. [tutorial 03]: ../03_hacky_hello_world @@ -622,15 +620,13 @@ your test code into individual chunks. For example, take a look at `tests/01_tim #![test_runner(libkernel::test_runner)] use core::time::Duration; -use libkernel::{bsp, cpu, driver, exception, time}; +use libkernel::{bsp, cpu, exception, time}; use test_macros::kernel_test; #[no_mangle] unsafe fn kernel_init() -> ! { - use driver::interface::DriverManager; - exception::handling_init(); - bsp::driver::driver_manager().qemu_bring_up_console(); + bsp::driver::qemu_bring_up_console(); // Depending on CPU arch, some timer bring-up code could go here. Not needed for the RPi. @@ -643,12 +639,12 @@ unsafe fn kernel_init() -> ! { #[kernel_test] fn timer_is_counting() { assert!(time::time_manager().uptime().as_nanos() > 0) - assert!(time::time_manager().resolution().as_nanos() < 100) } /// Timer resolution must be sufficient. #[kernel_test] fn timer_resolution_is_sufficient() { + assert!(time::time_manager().resolution().as_nanos() > 0); assert!(time::time_manager().resolution().as_nanos() < 100) } ``` @@ -719,15 +715,14 @@ so the wanted outcome is a `panic!`. Here is the whole test (minus some inline c mod panic_exit_success; -use libkernel::{bsp, cpu, driver, exception, info, memory, println}; +use libkernel::{bsp, cpu, exception, info, memory, println}; #[no_mangle] unsafe fn kernel_init() -> ! { - use driver::interface::DriverManager; use memory::mmu::interface::MMU; exception::handling_init(); - bsp::driver::driver_manager().qemu_bring_up_console(); + bsp::driver::qemu_bring_up_console(); // This line will be printed as the test header. println!("Testing synchronous exception handling by causing a page fault"); @@ -794,15 +789,14 @@ The subtest first sends `"ABC"` over the console to the kernel, and then expects /// Console tests should time out on the I/O harness in case of panic. mod panic_wait_forever; -use libkernel::{bsp, console, cpu, driver, exception, print}; +use libkernel::{bsp, console, cpu, exception, print}; #[no_mangle] unsafe fn kernel_init() -> ! { use console::console; - use driver::interface::DriverManager; exception::handling_init(); - bsp::driver::driver_manager().qemu_bring_up_console(); + bsp::driver::qemu_bring_up_console(); // Handshake assert_eq!(console().read_char(), 'A'); diff --git a/12_integrated_testing/kernel/src/bsp/raspberrypi.rs b/12_integrated_testing/kernel/src/bsp/raspberrypi.rs index a9a7261a..fe940677 100644 --- a/12_integrated_testing/kernel/src/bsp/raspberrypi.rs +++ b/12_integrated_testing/kernel/src/bsp/raspberrypi.rs @@ -4,7 +4,6 @@ //! Top-level BSP file for the Raspberry Pi 3 and 4. -pub mod console; pub mod cpu; pub mod driver; pub mod memory; diff --git a/12_integrated_testing/kernel/src/bsp/raspberrypi/console.rs b/12_integrated_testing/kernel/src/bsp/raspberrypi/console.rs deleted file mode 100644 index 0a630eef..00000000 --- a/12_integrated_testing/kernel/src/bsp/raspberrypi/console.rs +++ /dev/null @@ -1,16 +0,0 @@ -// SPDX-License-Identifier: MIT OR Apache-2.0 -// -// Copyright (c) 2018-2022 Andre Richter - -//! BSP console facilities. - -use crate::console; - -//-------------------------------------------------------------------------------------------------- -// Public Code -//-------------------------------------------------------------------------------------------------- - -/// Return a reference to the console. -pub fn console() -> &'static dyn console::interface::All { - &super::driver::PL011_UART -} diff --git a/12_integrated_testing/kernel/src/bsp/raspberrypi/driver.rs b/12_integrated_testing/kernel/src/bsp/raspberrypi/driver.rs index f8acd335..beaee16b 100644 --- a/12_integrated_testing/kernel/src/bsp/raspberrypi/driver.rs +++ b/12_integrated_testing/kernel/src/bsp/raspberrypi/driver.rs @@ -5,54 +5,74 @@ //! BSP driver support. use super::memory::map::mmio; -use crate::{bsp::device_driver, driver}; +use crate::{bsp::device_driver, console, driver as generic_driver}; +use core::sync::atomic::{AtomicBool, Ordering}; //-------------------------------------------------------------------------------------------------- -// Private Definitions +// Global instances //-------------------------------------------------------------------------------------------------- -/// Device Driver Manager type. -struct BSPDriverManager { - device_drivers: [&'static (dyn DeviceDriver + Sync); 2], -} +static PL011_UART: device_driver::PL011Uart = + unsafe { device_driver::PL011Uart::new(mmio::PL011_UART_START) }; +static GPIO: device_driver::GPIO = unsafe { device_driver::GPIO::new(mmio::GPIO_START) }; //-------------------------------------------------------------------------------------------------- -// Global instances +// Private Code //-------------------------------------------------------------------------------------------------- -pub(super) static PL011_UART: device_driver::PL011Uart = - unsafe { device_driver::PL011Uart::new(mmio::PL011_UART_START) }; +/// This must be called only after successful init of the UART driver. +fn post_init_uart() -> Result<(), &'static str> { + console::register_console(&PL011_UART); -static GPIO: device_driver::GPIO = unsafe { device_driver::GPIO::new(mmio::GPIO_START) }; + Ok(()) +} -static BSP_DRIVER_MANAGER: BSPDriverManager = BSPDriverManager { - device_drivers: [&PL011_UART, &GPIO], -}; +/// This must be called only after successful init of the GPIO driver. +fn post_init_gpio() -> Result<(), &'static str> { + GPIO.map_pl011_uart(); + Ok(()) +} -//-------------------------------------------------------------------------------------------------- -// Public Code -//-------------------------------------------------------------------------------------------------- +fn driver_uart() -> Result<(), &'static str> { + let uart_descriptor = + generic_driver::DeviceDriverDescriptor::new(&PL011_UART, Some(post_init_uart)); + generic_driver::driver_manager().register_driver(uart_descriptor); -/// Return a reference to the driver manager. -pub fn driver_manager() -> &'static impl driver::interface::DriverManager { - &BSP_DRIVER_MANAGER + Ok(()) } -//------------------------------------------------------------------------------ -// OS Interface Code -//------------------------------------------------------------------------------ -use driver::interface::DeviceDriver; +fn driver_gpio() -> Result<(), &'static str> { + let gpio_descriptor = generic_driver::DeviceDriverDescriptor::new(&GPIO, Some(post_init_gpio)); + generic_driver::driver_manager().register_driver(gpio_descriptor); -impl driver::interface::DriverManager for BSPDriverManager { - fn all_device_drivers(&self) -> &[&'static (dyn DeviceDriver + Sync)] { - &self.device_drivers[..] - } + Ok(()) +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- - fn post_device_driver_init(&self) { - // Configure PL011Uart's output pins. - GPIO.map_pl011_uart(); +/// Initialize the driver subsystem. +/// +/// # Safety +/// +/// See child function calls. +pub unsafe fn init() -> Result<(), &'static str> { + static INIT_DONE: AtomicBool = AtomicBool::new(false); + if INIT_DONE.load(Ordering::Relaxed) { + return Err("Init already done"); } - #[cfg(feature = "test_build")] - fn qemu_bring_up_console(&self) {} + driver_uart()?; + driver_gpio()?; + + INIT_DONE.store(true, Ordering::Relaxed); + Ok(()) +} + +/// Minimal code needed to bring up the console in QEMU (for testing only). This is often less steps +/// than on real hardware due to QEMU's abstractions. +#[cfg(feature = "test_build")] +pub fn qemu_bring_up_console() { + console::register_console(&PL011_UART); } diff --git a/12_integrated_testing/kernel/src/console.rs b/12_integrated_testing/kernel/src/console.rs index c1fb0e53..02b43df9 100644 --- a/12_integrated_testing/kernel/src/console.rs +++ b/12_integrated_testing/kernel/src/console.rs @@ -4,7 +4,9 @@ //! System console. -use crate::bsp; +mod null_console; + +use crate::synchronization::{self, NullLock}; //-------------------------------------------------------------------------------------------------- // Public Definitions @@ -54,13 +56,26 @@ pub mod interface { pub trait All: Write + Read + Statistics {} } +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +static CUR_CONSOLE: NullLock<&'static (dyn interface::All + Sync)> = + NullLock::new(&null_console::NULL_CONSOLE); + //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- +use synchronization::interface::Mutex; + +/// Register a new console. +pub fn register_console(new_console: &'static (dyn interface::All + Sync)) { + CUR_CONSOLE.lock(|con| *con = new_console); +} -/// Return a reference to the console. +/// Return a reference to the currently registered console. /// /// This is the global console used by all printing macros. pub fn console() -> &'static dyn interface::All { - bsp::console::console() + CUR_CONSOLE.lock(|con| *con) } diff --git a/12_integrated_testing/kernel/src/console/null_console.rs b/12_integrated_testing/kernel/src/console/null_console.rs new file mode 100644 index 00000000..2c64d499 --- /dev/null +++ b/12_integrated_testing/kernel/src/console/null_console.rs @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2022 Andre Richter + +//! Null console. + +use super::interface; +use core::fmt; + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +pub struct NullConsole; + +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +pub static NULL_CONSOLE: NullConsole = NullConsole {}; + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +impl interface::Write for NullConsole { + fn write_char(&self, _c: char) {} + + fn write_fmt(&self, _args: fmt::Arguments) -> fmt::Result { + fmt::Result::Ok(()) + } + + fn flush(&self) {} +} + +impl interface::Read for NullConsole { + fn clear_rx(&self) {} +} + +impl interface::Statistics for NullConsole {} +impl interface::All for NullConsole {} diff --git a/12_integrated_testing/kernel/src/driver.rs b/12_integrated_testing/kernel/src/driver.rs index 12d60ad4..a798c86d 100644 --- a/12_integrated_testing/kernel/src/driver.rs +++ b/12_integrated_testing/kernel/src/driver.rs @@ -4,6 +4,22 @@ //! Driver support. +use crate::{ + info, + synchronization::{interface::Mutex, NullLock}, +}; + +//-------------------------------------------------------------------------------------------------- +// Private Definitions +//-------------------------------------------------------------------------------------------------- + +const NUM_DRIVERS: usize = 5; + +struct DriverManagerInner { + next_index: usize, + descriptors: [Option; NUM_DRIVERS], +} + //-------------------------------------------------------------------------------------------------- // Public Definitions //-------------------------------------------------------------------------------------------------- @@ -24,26 +40,128 @@ pub mod interface { Ok(()) } } +} + +/// Tpye to be used as an optional callback after a driver's init() has run. +pub type DeviceDriverPostInitCallback = unsafe fn() -> Result<(), &'static str>; + +/// A descriptor for device drivers. +#[derive(Copy, Clone)] +pub struct DeviceDriverDescriptor { + device_driver: &'static (dyn interface::DeviceDriver + Sync), + post_init_callback: Option, +} + +/// Provides device driver management functions. +pub struct DriverManager { + inner: NullLock, +} + +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +static DRIVER_MANAGER: DriverManager = DriverManager::new(); + +//-------------------------------------------------------------------------------------------------- +// Private Code +//-------------------------------------------------------------------------------------------------- + +impl DriverManagerInner { + /// Create an instance. + pub const fn new() -> Self { + Self { + next_index: 0, + descriptors: [None; NUM_DRIVERS], + } + } +} - /// Device driver management functions. +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +impl DeviceDriverDescriptor { + /// Create an instance. + pub fn new( + device_driver: &'static (dyn interface::DeviceDriver + Sync), + post_init_callback: Option, + ) -> Self { + Self { + device_driver, + post_init_callback, + } + } +} + +/// Return a reference to the global DriverManager. +pub fn driver_manager() -> &'static DriverManager { + &DRIVER_MANAGER +} + +impl DriverManager { + /// Create an instance. + pub const fn new() -> Self { + Self { + inner: NullLock::new(DriverManagerInner::new()), + } + } + + /// Register a device driver with the kernel. + pub fn register_driver(&self, descriptor: DeviceDriverDescriptor) { + self.inner.lock(|inner| { + inner.descriptors[inner.next_index] = Some(descriptor); + inner.next_index += 1; + }) + } + + /// Helper for iterating over registered drivers. + fn for_each_descriptor<'a>(&'a self, f: impl FnMut(&'a DeviceDriverDescriptor)) { + self.inner.lock(|inner| { + inner + .descriptors + .iter() + .filter_map(|x| x.as_ref()) + .for_each(f) + }) + } + + /// Fully initialize all drivers. /// - /// The `BSP` is supposed to supply one global instance. - pub trait DriverManager { - /// Return a slice of references to all `BSP`-instantiated drivers. - /// - /// # Safety - /// - /// - The order of devices is the order in which `DeviceDriver::init()` is called. - fn all_device_drivers(&self) -> &[&'static (dyn DeviceDriver + Sync)]; + /// # Safety + /// + /// - During init, drivers might do stuff with system-wide impact. + pub unsafe fn init_drivers(&self) { + self.for_each_descriptor(|descriptor| { + // 1. Initialize driver. + if let Err(x) = descriptor.device_driver.init() { + panic!( + "Error initializing driver: {}: {}", + descriptor.device_driver.compatible(), + x + ); + } - /// Initialization code that runs after driver init. - /// - /// For example, device driver code that depends on other drivers already being online. - fn post_device_driver_init(&self); + // 2. Call corresponding post init callback. + if let Some(callback) = &descriptor.post_init_callback { + if let Err(x) = callback() { + panic!( + "Error during driver post-init callback: {}: {}", + descriptor.device_driver.compatible(), + x + ); + } + } + }); + } + + /// Enumerate all registered device drivers. + pub fn enumerate(&self) { + let mut i: usize = 1; + self.for_each_descriptor(|descriptor| { + info!(" {}. {}", i, descriptor.device_driver.compatible()); - /// Minimal code needed to bring up the console in QEMU (for testing only). This is often - /// less steps than on real hardware due to QEMU's abstractions. - #[cfg(feature = "test_build")] - fn qemu_bring_up_console(&self); + i += 1; + }); } } diff --git a/12_integrated_testing/kernel/src/lib.rs b/12_integrated_testing/kernel/src/lib.rs index 35698c74..3f5a846f 100644 --- a/12_integrated_testing/kernel/src/lib.rs +++ b/12_integrated_testing/kernel/src/lib.rs @@ -182,10 +182,8 @@ pub fn test_runner(tests: &[&test_types::UnitTest]) { #[cfg(test)] #[no_mangle] unsafe fn kernel_init() -> ! { - use driver::interface::DriverManager; - exception::handling_init(); - bsp::driver::driver_manager().qemu_bring_up_console(); + bsp::driver::qemu_bring_up_console(); test_main(); diff --git a/12_integrated_testing/kernel/src/main.rs b/12_integrated_testing/kernel/src/main.rs index bf4d7fe3..9cfcf315 100644 --- a/12_integrated_testing/kernel/src/main.rs +++ b/12_integrated_testing/kernel/src/main.rs @@ -26,7 +26,6 @@ use libkernel::{bsp, console, driver, exception, info, memory, time}; /// NullLocks instead of spinlocks), will fail to work (properly) on the RPi SoCs. #[no_mangle] unsafe fn kernel_init() -> ! { - use driver::interface::DriverManager; use memory::mmu::interface::MMU; exception::handling_init(); @@ -35,12 +34,13 @@ unsafe fn kernel_init() -> ! { panic!("MMU: {}", string); } - for i in bsp::driver::driver_manager().all_device_drivers().iter() { - if let Err(x) = i.init() { - panic!("Error loading driver: {}: {}", i.compatible(), x); - } + // Initialize the BSP driver subsystem. + if let Err(x) = bsp::driver::init() { + panic!("Error initializing BSP driver subsystem: {}", x); } - bsp::driver::driver_manager().post_device_driver_init(); + + // Initialize all device drivers. + driver::driver_manager().init_drivers(); // println! is usable from here on. // Transition from unsafe to safe. @@ -50,7 +50,6 @@ unsafe fn kernel_init() -> ! { /// The main function running after the early init. fn kernel_main() -> ! { use console::console; - use driver::interface::DriverManager; info!("{}", libkernel::version()); info!("Booting on: {}", bsp::board_name()); @@ -70,13 +69,7 @@ fn kernel_main() -> ! { ); info!("Drivers loaded:"); - for (i, driver) in bsp::driver::driver_manager() - .all_device_drivers() - .iter() - .enumerate() - { - info!(" {}. {}", i + 1, driver.compatible()); - } + driver::driver_manager().enumerate(); info!("Echoing input now"); diff --git a/12_integrated_testing/kernel/tests/00_console_sanity.rs b/12_integrated_testing/kernel/tests/00_console_sanity.rs index e12a711f..69313428 100644 --- a/12_integrated_testing/kernel/tests/00_console_sanity.rs +++ b/12_integrated_testing/kernel/tests/00_console_sanity.rs @@ -11,15 +11,14 @@ /// Console tests should time out on the I/O harness in case of panic. mod panic_wait_forever; -use libkernel::{bsp, console, cpu, driver, exception, print}; +use libkernel::{bsp, console, cpu, exception, print}; #[no_mangle] unsafe fn kernel_init() -> ! { use console::console; - use driver::interface::DriverManager; exception::handling_init(); - bsp::driver::driver_manager().qemu_bring_up_console(); + bsp::driver::qemu_bring_up_console(); // Handshake assert_eq!(console().read_char(), 'A'); diff --git a/12_integrated_testing/kernel/tests/01_timer_sanity.rs b/12_integrated_testing/kernel/tests/01_timer_sanity.rs index a0eb732b..b86016b6 100644 --- a/12_integrated_testing/kernel/tests/01_timer_sanity.rs +++ b/12_integrated_testing/kernel/tests/01_timer_sanity.rs @@ -11,15 +11,13 @@ #![test_runner(libkernel::test_runner)] use core::time::Duration; -use libkernel::{bsp, cpu, driver, exception, time}; +use libkernel::{bsp, cpu, exception, time}; use test_macros::kernel_test; #[no_mangle] unsafe fn kernel_init() -> ! { - use driver::interface::DriverManager; - exception::handling_init(); - bsp::driver::driver_manager().qemu_bring_up_console(); + bsp::driver::qemu_bring_up_console(); // Depending on CPU arch, some timer bring-up code could go here. Not needed for the RPi. diff --git a/12_integrated_testing/kernel/tests/02_exception_sync_page_fault.rs b/12_integrated_testing/kernel/tests/02_exception_sync_page_fault.rs index 62908377..46501960 100644 --- a/12_integrated_testing/kernel/tests/02_exception_sync_page_fault.rs +++ b/12_integrated_testing/kernel/tests/02_exception_sync_page_fault.rs @@ -17,15 +17,14 @@ /// or indirectly. mod panic_exit_success; -use libkernel::{bsp, cpu, driver, exception, info, memory, println}; +use libkernel::{bsp, cpu, exception, info, memory, println}; #[no_mangle] unsafe fn kernel_init() -> ! { - use driver::interface::DriverManager; use memory::mmu::interface::MMU; exception::handling_init(); - bsp::driver::driver_manager().qemu_bring_up_console(); + bsp::driver::qemu_bring_up_console(); // This line will be printed as the test header. println!("Testing synchronous exception handling by causing a page fault"); diff --git a/12_integrated_testing/kernel/tests/03_exception_restore_sanity.rs b/12_integrated_testing/kernel/tests/03_exception_restore_sanity.rs index 3f4eae79..cba9285f 100644 --- a/12_integrated_testing/kernel/tests/03_exception_restore_sanity.rs +++ b/12_integrated_testing/kernel/tests/03_exception_restore_sanity.rs @@ -12,7 +12,7 @@ mod panic_wait_forever; use core::arch::asm; -use libkernel::{bsp, cpu, driver, exception, info, memory, println}; +use libkernel::{bsp, cpu, exception, info, memory, println}; #[inline(never)] fn nested_system_call() { @@ -30,11 +30,10 @@ fn nested_system_call() { #[no_mangle] unsafe fn kernel_init() -> ! { - use driver::interface::DriverManager; use memory::mmu::interface::MMU; exception::handling_init(); - bsp::driver::driver_manager().qemu_bring_up_console(); + bsp::driver::qemu_bring_up_console(); // This line will be printed as the test header. println!("Testing exception restore"); diff --git a/13_exceptions_part2_peripheral_IRQs/Makefile b/13_exceptions_part2_peripheral_IRQs/Makefile index 670c30c4..2d480119 100644 --- a/13_exceptions_part2_peripheral_IRQs/Makefile +++ b/13_exceptions_part2_peripheral_IRQs/Makefile @@ -291,7 +291,7 @@ test_boot: $(KERNEL_BIN) ## Helpers for unit and integration test targets ##------------------------------------------------------------------------------ define KERNEL_TEST_RUNNER - #!/usr/bin/env bash +#!/usr/bin/env bash # The cargo test runner seems to change into the crate under test's directory. Therefore, ensure # this script executes from the root. diff --git a/13_exceptions_part2_peripheral_IRQs/README.md b/13_exceptions_part2_peripheral_IRQs/README.md index 3d6d5f16..a8c503d5 100644 --- a/13_exceptions_part2_peripheral_IRQs/README.md +++ b/13_exceptions_part2_peripheral_IRQs/README.md @@ -110,17 +110,16 @@ The trait is defined as `exception::asynchronous::interface::IRQManager`: ```rust pub trait IRQManager { /// The IRQ number type depends on the implementation. - type IRQNumberType; + type IRQNumberType: Copy; /// Register a handler. fn register_handler( &self, - irq_number: Self::IRQNumberType, - descriptor: super::IRQDescriptor, + irq_handler_descriptor: super::IRQHandlerDescriptor, ) -> Result<(), &'static str>; /// Enable an interrupt in the controller. - fn enable(&self, irq_number: Self::IRQNumberType); + fn enable(&self, irq_number: &Self::IRQNumberType); /// Handle pending interrupts. /// @@ -136,7 +135,7 @@ pub trait IRQManager { ); /// Print list of registered handlers. - fn print_handler(&self); + fn print_handler(&self) {} } ``` @@ -175,22 +174,21 @@ sufficient to uniquely encode the IRQs, because their ranges overlap. In the dri controller, we therefore define the associated type as follows: ```rust -pub type LocalIRQ = - exception::asynchronous::IRQNumber<{ InterruptController::MAX_LOCAL_IRQ_NUMBER }>; -pub type PeripheralIRQ = - exception::asynchronous::IRQNumber<{ InterruptController::MAX_PERIPHERAL_IRQ_NUMBER }>; +pub type LocalIRQ = BoundedUsize<{ InterruptController::MAX_LOCAL_IRQ_NUMBER }>; +pub type PeripheralIRQ = BoundedUsize<{ InterruptController::MAX_PERIPHERAL_IRQ_NUMBER }>; -/// Used for the associated type of trait [`exception::asynchronous::interface::IRQManager`]. +/// Used for the associated type of trait [`exception::asynchronous::interface::IRQManager`]. #[derive(Copy, Clone)] +#[allow(missing_docs)] pub enum IRQNumber { Local(LocalIRQ), Peripheral(PeripheralIRQ), } ``` -The type `exception::asynchronous::IRQNumber` is a newtype around an `usize` that uses a [const -generic] to ensure that the value of the encapsulated IRQ number is in the allowed range (e.g. -`0..MAX_LOCAL_IRQ_NUMBER` for `LocalIRQ`, with `MAX_LOCAL_IRQ_NUMBER == 11`). +The type `BoundedUsize` is a newtype around an `usize` that uses a [const generic] to ensure that +the value of the encapsulated IRQ number is in the allowed range (e.g. `0..MAX_LOCAL_IRQ_NUMBER` for +`LocalIRQ`, with `MAX_LOCAL_IRQ_NUMBER == 11`). [const generic]: https://github.com/rust-lang/rfcs/blob/master/text/2000-const-generics.md @@ -206,7 +204,7 @@ identifier for the IRQs. We define the type as follows: ```rust /// Used for the associated type of trait [`exception::asynchronous::interface::IRQManager`]. -pub type IRQNumber = exception::asynchronous::IRQNumber<{ GICv2::MAX_IRQ_NUMBER }>; +pub type IRQNumber = BoundedUsize<{ GICv2::MAX_IRQ_NUMBER }>; ``` #### Registering IRQ Handlers @@ -264,34 +262,41 @@ respective drivers themselves. Therefore, we added a new function to the standar trait in `driver::interface::DeviceDriver` that must be implemented if IRQ handling is supported: ```rust -/// Called by the kernel to register and enable the device's IRQ handlers, if any. +/// Called by the kernel to register and enable the device's IRQ handler. /// /// Rust's type system will prevent a call to this function unless the calling instance /// itself has static lifetime. -fn register_and_enable_irq_handler(&'static self) -> Result<(), &'static str> { - Ok(()) +fn register_and_enable_irq_handler( + &'static self, + irq_number: &Self::IRQNumberType, +) -> Result<(), &'static str> { + panic!( + "Attempt to enable IRQ {} for device {}, but driver does not support this", + irq_number, + self.compatible() + ) } ``` Here is the implementation for the `PL011Uart`: ```rust -fn register_and_enable_irq_handler(&'static self) -> Result<(), &'static str> { - use exception::asynchronous::{irq_manager, IRQDescriptor}; +fn register_and_enable_irq_handler( + &'static self, + irq_number: &Self::IRQNumberType, +) -> Result<(), &'static str> { + use exception::asynchronous::{irq_manager, IRQHandlerDescriptor}; - let descriptor = IRQDescriptor { - name: Self::COMPATIBLE, - handler: self, - }; + let descriptor = IRQHandlerDescriptor::new(*irq_number, Self::COMPATIBLE, self); - irq_manager().register_handler(self.irq_number, descriptor)?; - irq_manager().enable(self.irq_number); + irq_manager().register_handler(descriptor)?; + irq_manager().enable(irq_number); Ok(()) } ``` -The `bsp::exception::asynchronous::irq_manager()` function used here returns a reference to an +The `exception::asynchronous::irq_manager()` function used here returns a reference to an implementor of the `IRQManager` trait. Since the implementation is supposed to be done by the platform's interrupt controller, this call will redirect to the `kernel`'s instance of either the driver for the `BCM` controller (`Raspberry Pi 3`) or the driver for the `GICv2` (`Pi 4`). We will @@ -300,33 +305,57 @@ later. The gist here is that the calls on `irq_manager()` will make the platform controller aware that the `UART` driver (i) wants to handle its interrupt and (ii) which function it provides to do so. -Also note how `irq_number` is a member of the `PL011Uart` struct and not hardcoded. The reason is -that the `UART` driver code is agnostic about the **IRQ numbers** that are associated to it. This is +Also note how `irq_number` is supplied as a function argument and not hardcoded. The reason is that +the `UART` driver code is agnostic about the **IRQ numbers** that are associated to it. This is vendor-supplied information and as such typically part of the Board Support Package (`BSP`). It can vary from `BSP` to `BSP`, same like the board's memory map, which provides the `UART`'s MMIO -register addresses. Therefore, we extend the instantiation of the `UART` driver accordingly, so that -the `BSP` now additionally provides the IRQ number as an argument: +register addresses. + +With all this in place, we can finally let drivers register and enable their IRQ handlers with the +interrupt controller, and unmask IRQ reception on the boot CPU core during the kernel init phase. +The global `driver_manager` takes care of this in the function `init_drivers_and_irqs()` (before +this tutorial, the function's name was `init_drivers()`), where this happens as the third and last +step of initializing all registered device drivers: ```rust -static PL011_UART: device_driver::PL011Uart = unsafe { - device_driver::PL011Uart::new( - memory::map::mmio::PL011_UART_BASE, - exception::asynchronous::irq_map::PL011_UART, - ) -}; +pub unsafe fn init_drivers_and_irqs(&self) { + self.for_each_descriptor(|descriptor| { + // 1. Initialize driver. + if let Err(x) = descriptor.device_driver.init() { + // omitted for brevity + } + + // 2. Call corresponding post init callback. + if let Some(callback) = &descriptor.post_init_callback { + // omitted for brevity + } + }); + + // 3. After all post-init callbacks were done, the interrupt controller should be + // registered and functional. So let drivers register with it now. + self.for_each_descriptor(|descriptor| { + if let Some(irq_number) = &descriptor.irq_number { + if let Err(x) = descriptor + .device_driver + .register_and_enable_irq_handler(irq_number) + { + panic!( + "Error during driver interrupt handler registration: {}: {}", + descriptor.device_driver.compatible(), + x + ); + } + } + }); +} ``` -With all this in place, we can finally let drivers register and enable their IRQ handlers with the -interrupt controller, and unmask IRQ reception on the boot CPU core during the kernel init phase in -`main.rs`. After unmasking, IRQ handling is live: + +In `main.rs`, IRQs are unmasked right afterwards, after which point IRQ handling is live: ```rust -// Let device drivers register and enable their handlers with the interrupt controller. -for i in bsp::driver::driver_manager().all_device_drivers() { - if let Err(msg) = i.register_and_enable_irq_handler() { - warn!("Error registering IRQ handler: {}", msg); - } -} +// Initialize all device drivers. +driver::driver_manager().init_drivers_and_irqs(); // Unmask interrupts on the boot CPU core. exception::asynchronous::local_irq_unmask(); @@ -489,8 +518,8 @@ Calls to `register_handler()` result in the driver inserting the provided handle specific table (the handler reference is a member of `IRQDescriptor`): ```rust -type HandlerTable = - [Option; InterruptController::NUM_PERIPHERAL_IRQS]; +type HandlerTable = [Option>; + PeripheralIRQ::MAX_INCLUSIVE + 1]; ``` One of the requirements for safe operation of the `kernel` is that those handlers are not @@ -547,6 +576,10 @@ only call is happening before the transition from `kernel_init()` to `kernel_mai state::state_manager().transition_to_single_core_main(); ``` +P.S.: Since the use case for the `InitStateLock` also applies to a few other places in the kernel +(for example, registering the system-wide console during early boot), `InitStateLock`s have been +incorporated in those other places as well. + #### The GICv2 Driver (Pi 4) As we learned earlier, the ARM `GICv2` in the `Raspberry Pi 4` features a continuous interrupt @@ -1218,7 +1251,7 @@ diff -uNr 12_integrated_testing/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs 1 + } + + /// Enable an interrupt. -+ pub fn enable(&self, irq_num: super::IRQNumber) { ++ pub fn enable(&self, irq_num: &super::IRQNumber) { + let irq_num = irq_num.get(); + + // Each bit in the u32 enable register corresponds to one IRQ number. Shift right by 5 @@ -1249,7 +1282,7 @@ diff -uNr 12_integrated_testing/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs 1 diff -uNr 12_integrated_testing/kernel/src/bsp/device_driver/arm/gicv2.rs 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/arm/gicv2.rs --- 12_integrated_testing/kernel/src/bsp/device_driver/arm/gicv2.rs +++ 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/arm/gicv2.rs -@@ -0,0 +1,220 @@ +@@ -0,0 +1,226 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2020-2022 Andre Richter @@ -1331,20 +1364,25 @@ diff -uNr 12_integrated_testing/kernel/src/bsp/device_driver/arm/gicv2.rs 13_exc +mod gicc; +mod gicd; + -+use crate::{bsp, cpu, driver, exception, synchronization, synchronization::InitStateLock}; ++use crate::{ ++ bsp::{self, device_driver::common::BoundedUsize}, ++ cpu, driver, exception, synchronization, ++ synchronization::InitStateLock, ++}; + +//-------------------------------------------------------------------------------------------------- +// Private Definitions +//-------------------------------------------------------------------------------------------------- + -+type HandlerTable = [Option; IRQNumber::NUM_TOTAL]; ++type HandlerTable = [Option>; ++ IRQNumber::MAX_INCLUSIVE + 1]; + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +/// Used for the associated type of trait [`exception::asynchronous::interface::IRQManager`]. -+pub type IRQNumber = exception::asynchronous::IRQNumber<{ GICv2::MAX_IRQ_NUMBER }>; ++pub type IRQNumber = BoundedUsize<{ GICv2::MAX_IRQ_NUMBER }>; + +/// Representation of the GIC. +pub struct GICv2 { @@ -1376,7 +1414,7 @@ diff -uNr 12_integrated_testing/kernel/src/bsp/device_driver/arm/gicv2.rs 13_exc + Self { + gicd: gicd::GICD::new(gicd_mmio_start_addr), + gicc: gicc::GICC::new(gicc_mmio_start_addr), -+ handler_table: InitStateLock::new([None; IRQNumber::NUM_TOTAL]), ++ handler_table: InitStateLock::new([None; IRQNumber::MAX_INCLUSIVE + 1]), + } + } +} @@ -1387,6 +1425,8 @@ diff -uNr 12_integrated_testing/kernel/src/bsp/device_driver/arm/gicv2.rs 13_exc +use synchronization::interface::ReadWriteEx; + +impl driver::interface::DeviceDriver for GICv2 { ++ type IRQNumberType = IRQNumber; ++ + fn compatible(&self) -> &'static str { + Self::COMPATIBLE + } @@ -1408,23 +1448,22 @@ diff -uNr 12_integrated_testing/kernel/src/bsp/device_driver/arm/gicv2.rs 13_exc + + fn register_handler( + &self, -+ irq_number: Self::IRQNumberType, -+ descriptor: exception::asynchronous::IRQDescriptor, ++ irq_handler_descriptor: exception::asynchronous::IRQHandlerDescriptor, + ) -> Result<(), &'static str> { + self.handler_table.write(|table| { -+ let irq_number = irq_number.get(); ++ let irq_number = irq_handler_descriptor.number().get(); + + if table[irq_number].is_some() { + return Err("IRQ handler already registered"); + } + -+ table[irq_number] = Some(descriptor); ++ table[irq_number] = Some(irq_handler_descriptor); + + Ok(()) + }) + } + -+ fn enable(&self, irq_number: Self::IRQNumberType) { ++ fn enable(&self, irq_number: &Self::IRQNumberType) { + self.gicd.enable(irq_number); + } + @@ -1447,7 +1486,7 @@ diff -uNr 12_integrated_testing/kernel/src/bsp/device_driver/arm/gicv2.rs 13_exc + None => panic!("No handler registered for IRQ {}", irq_number), + Some(descriptor) => { + // Call the IRQ handler. Panics on failure. -+ descriptor.handler.handle().expect("Error handling IRQ"); ++ descriptor.handler().handle().expect("Error handling IRQ"); + } + } + }); @@ -1464,7 +1503,7 @@ diff -uNr 12_integrated_testing/kernel/src/bsp/device_driver/arm/gicv2.rs 13_exc + self.handler_table.read(|table| { + for (i, opt) in table.iter().skip(32).enumerate() { + if let Some(handler) = opt { -+ info!(" {: >3}. {}", i + 32, handler.name); ++ info!(" {: >3}. {}", i + 32, handler.name()); + } + } + }); @@ -1488,12 +1527,14 @@ diff -uNr 12_integrated_testing/kernel/src/bsp/device_driver/arm.rs 13_exception diff -uNr 12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs --- 12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs +++ 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs -@@ -6,7 +6,7 @@ +@@ -5,8 +5,8 @@ + //! GPIO Driver. use crate::{ - bsp::device_driver::common::MMIODerefWrapper, driver, synchronization, +- bsp::device_driver::common::MMIODerefWrapper, driver, synchronization, - synchronization::NullLock, -+ synchronization::IRQSafeNullLock, ++ bsp::device_driver::common::MMIODerefWrapper, driver, exception::asynchronous::IRQNumber, ++ synchronization, synchronization::IRQSafeNullLock, }; use tock_registers::{ interfaces::{ReadWriteable, Writeable}, @@ -1515,6 +1556,15 @@ diff -uNr 12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs } } +@@ -216,6 +216,8 @@ + use synchronization::interface::Mutex; + + impl driver::interface::DeviceDriver for GPIO { ++ type IRQNumberType = IRQNumber; ++ + fn compatible(&self) -> &'static str { + Self::COMPATIBLE + } diff -uNr 12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs --- 12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs @@ -1572,7 +1622,8 @@ diff -uNr 12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_interru +/// Abstraction for the ReadOnly parts of the associated MMIO registers. +type ReadOnlyRegisters = MMIODerefWrapper; + -+type HandlerTable = [Option; PeripheralIRQ::NUM_TOTAL]; ++type HandlerTable = [Option>; ++ PeripheralIRQ::MAX_INCLUSIVE + 1]; + +//-------------------------------------------------------------------------------------------------- +// Public Definitions @@ -1604,7 +1655,7 @@ diff -uNr 12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_interru + Self { + wo_registers: IRQSafeNullLock::new(WriteOnlyRegisters::new(mmio_start_addr)), + ro_registers: ReadOnlyRegisters::new(mmio_start_addr), -+ handler_table: InitStateLock::new([None; PeripheralIRQ::NUM_TOTAL]), ++ handler_table: InitStateLock::new([None; PeripheralIRQ::MAX_INCLUSIVE + 1]), + } + } + @@ -1627,23 +1678,22 @@ diff -uNr 12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_interru + + fn register_handler( + &self, -+ irq: Self::IRQNumberType, -+ descriptor: exception::asynchronous::IRQDescriptor, ++ irq_handler_descriptor: exception::asynchronous::IRQHandlerDescriptor, + ) -> Result<(), &'static str> { + self.handler_table.write(|table| { -+ let irq_number = irq.get(); ++ let irq_number = irq_handler_descriptor.number().get(); + + if table[irq_number].is_some() { + return Err("IRQ handler already registered"); + } + -+ table[irq_number] = Some(descriptor); ++ table[irq_number] = Some(irq_handler_descriptor); + + Ok(()) + }) + } + -+ fn enable(&self, irq: Self::IRQNumberType) { ++ fn enable(&self, irq: &Self::IRQNumberType) { + self.wo_registers.lock(|regs| { + let enable_reg = if irq.get() <= 31 { + ®s.ENABLE_1 @@ -1669,7 +1719,7 @@ diff -uNr 12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_interru + None => panic!("No handler registered for IRQ {}", irq_number), + Some(descriptor) => { + // Call the IRQ handler. Panics on failure. -+ descriptor.handler.handle().expect("Error handling IRQ"); ++ descriptor.handler().handle().expect("Error handling IRQ"); + } + } + } @@ -1684,7 +1734,7 @@ diff -uNr 12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_interru + self.handler_table.read(|table| { + for (i, opt) in table.iter().enumerate() { + if let Some(handler) = opt { -+ info!(" {: >3}. {}", i, handler.name); ++ info!(" {: >3}. {}", i, handler.name()); + } + } + }); @@ -1694,7 +1744,7 @@ diff -uNr 12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_interru diff -uNr 12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs --- 12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs +++ 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs -@@ -0,0 +1,131 @@ +@@ -0,0 +1,152 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2020-2022 Andre Richter @@ -1703,7 +1753,12 @@ diff -uNr 12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_interru + +mod peripheral_ic; + -+use crate::{driver, exception}; ++use crate::{ ++ bsp::device_driver::common::BoundedUsize, ++ driver, ++ exception::{self, asynchronous::IRQHandlerDescriptor}, ++}; ++use core::fmt; + +//-------------------------------------------------------------------------------------------------- +// Private Definitions @@ -1718,10 +1773,8 @@ diff -uNr 12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_interru +// Public Definitions +//-------------------------------------------------------------------------------------------------- + -+pub type LocalIRQ = -+ exception::asynchronous::IRQNumber<{ InterruptController::MAX_LOCAL_IRQ_NUMBER }>; -+pub type PeripheralIRQ = -+ exception::asynchronous::IRQNumber<{ InterruptController::MAX_PERIPHERAL_IRQ_NUMBER }>; ++pub type LocalIRQ = BoundedUsize<{ InterruptController::MAX_LOCAL_IRQ_NUMBER }>; ++pub type PeripheralIRQ = BoundedUsize<{ InterruptController::MAX_PERIPHERAL_IRQ_NUMBER }>; + +/// Used for the associated type of trait [`exception::asynchronous::interface::IRQManager`]. +#[derive(Copy, Clone)] @@ -1764,6 +1817,15 @@ diff -uNr 12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_interru +// Public Code +//-------------------------------------------------------------------------------------------------- + ++impl fmt::Display for IRQNumber { ++ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { ++ match self { ++ Self::Local(number) => write!(f, "Local({})", number), ++ Self::Peripheral(number) => write!(f, "Peripheral({})", number), ++ } ++ } ++} ++ +impl InterruptController { + // Restrict to 3 for now. This makes future code for local_ic.rs more straight forward. + const MAX_LOCAL_IRQ_NUMBER: usize = 3; @@ -1788,6 +1850,8 @@ diff -uNr 12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_interru +//------------------------------------------------------------------------------ + +impl driver::interface::DeviceDriver for InterruptController { ++ type IRQNumberType = IRQNumber; ++ + fn compatible(&self) -> &'static str { + Self::COMPATIBLE + } @@ -1798,16 +1862,23 @@ diff -uNr 12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_interru + + fn register_handler( + &self, -+ irq: Self::IRQNumberType, -+ descriptor: exception::asynchronous::IRQDescriptor, ++ irq_handler_descriptor: exception::asynchronous::IRQHandlerDescriptor, + ) -> Result<(), &'static str> { -+ match irq { ++ match irq_handler_descriptor.number() { + IRQNumber::Local(_) => unimplemented!("Local IRQ controller not implemented."), -+ IRQNumber::Peripheral(pirq) => self.periph.register_handler(pirq, descriptor), ++ IRQNumber::Peripheral(pirq) => { ++ let periph_descriptor = IRQHandlerDescriptor::new( ++ pirq, ++ irq_handler_descriptor.name(), ++ irq_handler_descriptor.handler(), ++ ); ++ ++ self.periph.register_handler(periph_descriptor) ++ } + } + } + -+ fn enable(&self, irq: Self::IRQNumberType) { ++ fn enable(&self, irq: &Self::IRQNumberType) { + match irq { + IRQNumber::Local(_) => unimplemented!("Local IRQ controller not implemented."), + IRQNumber::Peripheral(pirq) => self.periph.enable(pirq), @@ -1830,18 +1901,21 @@ diff -uNr 12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_interru diff -uNr 12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs --- 12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs +++ 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs -@@ -10,8 +10,8 @@ +@@ -10,8 +10,11 @@ //! - use crate::{ - bsp::device_driver::common::MMIODerefWrapper, console, cpu, driver, synchronization, - synchronization::NullLock, -+ bsp, bsp::device_driver::common::MMIODerefWrapper, console, cpu, driver, exception, -+ synchronization, synchronization::IRQSafeNullLock, ++ bsp::device_driver::common::MMIODerefWrapper, ++ console, cpu, driver, ++ exception::{self, asynchronous::IRQNumber}, ++ synchronization, ++ synchronization::IRQSafeNullLock, }; use core::fmt; use tock_registers::{ -@@ -134,6 +134,52 @@ +@@ -134,6 +137,52 @@ ] ], @@ -1894,7 +1968,7 @@ diff -uNr 12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_u /// Interrupt Clear Register. ICR [ /// Meta field for all pending interrupts. -@@ -152,7 +198,10 @@ +@@ -152,7 +201,10 @@ (0x28 => FBRD: WriteOnly), (0x2c => LCR_H: WriteOnly), (0x30 => CR: WriteOnly), @@ -1906,17 +1980,16 @@ diff -uNr 12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_u (0x44 => ICR: WriteOnly), (0x48 => @END), } -@@ -179,7 +228,8 @@ +@@ -179,7 +231,7 @@ /// Representation of the UART. pub struct PL011Uart { - inner: NullLock, + inner: IRQSafeNullLock, -+ irq_number: bsp::device_driver::IRQNumber, } //-------------------------------------------------------------------------------------------------- -@@ -247,6 +297,14 @@ +@@ -247,6 +299,14 @@ .LCR_H .write(LCR_H::WLEN::EightBit + LCR_H::FEN::FifosEnabled); @@ -1931,37 +2004,39 @@ diff -uNr 12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_u // Turn the UART on. self.registers .CR -@@ -335,9 +393,13 @@ - /// # Safety - /// +@@ -337,7 +397,7 @@ /// - The user must ensure to provide a correct MMIO start address. -- pub const unsafe fn new(mmio_start_addr: usize) -> Self { -+ pub const unsafe fn new( -+ mmio_start_addr: usize, -+ irq_number: bsp::device_driver::IRQNumber, -+ ) -> Self { + pub const unsafe fn new(mmio_start_addr: usize) -> Self { Self { - inner: NullLock::new(PL011UartInner::new(mmio_start_addr)), + inner: IRQSafeNullLock::new(PL011UartInner::new(mmio_start_addr)), -+ irq_number, } } } +@@ -348,6 +408,8 @@ + use synchronization::interface::Mutex; + + impl driver::interface::DeviceDriver for PL011Uart { ++ type IRQNumberType = IRQNumber; ++ + fn compatible(&self) -> &'static str { + Self::COMPATIBLE + } @@ -357,6 +419,20 @@ Ok(()) } + -+ fn register_and_enable_irq_handler(&'static self) -> Result<(), &'static str> { -+ use exception::asynchronous::{irq_manager, IRQDescriptor}; ++ fn register_and_enable_irq_handler( ++ &'static self, ++ irq_number: &Self::IRQNumberType, ++ ) -> Result<(), &'static str> { ++ use exception::asynchronous::{irq_manager, IRQHandlerDescriptor}; + -+ let descriptor = IRQDescriptor { -+ name: Self::COMPATIBLE, -+ handler: self, -+ }; ++ let descriptor = IRQHandlerDescriptor::new(*irq_number, Self::COMPATIBLE, self); + -+ irq_manager().register_handler(self.irq_number, descriptor)?; -+ irq_manager().enable(self.irq_number); ++ irq_manager().register_handler(descriptor)?; ++ irq_manager().enable(irq_number); + + Ok(()) + } @@ -2010,6 +2085,56 @@ diff -uNr 12_integrated_testing/kernel/src/bsp/device_driver/bcm.rs 13_exception +pub use bcm2xxx_interrupt_controller::*; pub use bcm2xxx_pl011_uart::*; +diff -uNr 12_integrated_testing/kernel/src/bsp/device_driver/common.rs 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/common.rs +--- 12_integrated_testing/kernel/src/bsp/device_driver/common.rs ++++ 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/common.rs +@@ -4,7 +4,7 @@ + + //! Common device driver code. + +-use core::{marker::PhantomData, ops}; ++use core::{fmt, marker::PhantomData, ops}; + + //-------------------------------------------------------------------------------------------------- + // Public Definitions +@@ -15,6 +15,10 @@ + phantom: PhantomData T>, + } + ++/// A wrapper type for usize with integrated range bound check. ++#[derive(Copy, Clone)] ++pub struct BoundedUsize(usize); ++ + //-------------------------------------------------------------------------------------------------- + // Public Code + //-------------------------------------------------------------------------------------------------- +@@ -36,3 +40,25 @@ + unsafe { &*(self.start_addr as *const _) } + } + } ++ ++impl BoundedUsize<{ MAX_INCLUSIVE }> { ++ pub const MAX_INCLUSIVE: usize = MAX_INCLUSIVE; ++ ++ /// Creates a new instance if number <= MAX_INCLUSIVE. ++ pub const fn new(number: usize) -> Self { ++ assert!(number <= MAX_INCLUSIVE); ++ ++ Self(number) ++ } ++ ++ /// Return the wrapped number. ++ pub const fn get(self) -> usize { ++ self.0 ++ } ++} ++ ++impl fmt::Display for BoundedUsize<{ MAX_INCLUSIVE }> { ++ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { ++ write!(f, "{}", self.0) ++ } ++} + diff -uNr 12_integrated_testing/kernel/src/bsp/device_driver.rs 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver.rs --- 12_integrated_testing/kernel/src/bsp/device_driver.rs +++ 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver.rs @@ -2031,72 +2156,111 @@ diff -uNr 12_integrated_testing/kernel/src/bsp/device_driver.rs 13_exceptions_pa diff -uNr 12_integrated_testing/kernel/src/bsp/raspberrypi/driver.rs 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/driver.rs --- 12_integrated_testing/kernel/src/bsp/raspberrypi/driver.rs +++ 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/driver.rs -@@ -4,29 +4,43 @@ +@@ -4,8 +4,12 @@ //! BSP driver support. -use super::memory::map::mmio; +-use crate::{bsp::device_driver, console, driver as generic_driver}; +use super::{exception, memory::map::mmio}; - use crate::{bsp::device_driver, driver}; ++use crate::{ ++ bsp::device_driver, ++ console, driver as generic_driver, ++ exception::{self as generic_exception}, ++}; + use core::sync::atomic::{AtomicBool, Ordering}; -+pub use device_driver::IRQNumber; + //-------------------------------------------------------------------------------------------------- +@@ -16,6 +20,14 @@ + unsafe { device_driver::PL011Uart::new(mmio::PL011_UART_START) }; + static GPIO: device_driver::GPIO = unsafe { device_driver::GPIO::new(mmio::GPIO_START) }; + ++#[cfg(feature = "bsp_rpi3")] ++static INTERRUPT_CONTROLLER: device_driver::InterruptController = ++ unsafe { device_driver::InterruptController::new(mmio::PERIPHERAL_IC_START) }; ++ ++#[cfg(feature = "bsp_rpi4")] ++static INTERRUPT_CONTROLLER: device_driver::GICv2 = ++ unsafe { device_driver::GICv2::new(mmio::GICD_START, mmio::GICC_START) }; + //-------------------------------------------------------------------------------------------------- - // Private Definitions + // Private Code //-------------------------------------------------------------------------------------------------- - - /// Device Driver Manager type. - struct BSPDriverManager { -- device_drivers: [&'static (dyn DeviceDriver + Sync); 2], -+ device_drivers: [&'static (dyn DeviceDriver + Sync); 3], +@@ -33,21 +45,43 @@ + Ok(()) } - //-------------------------------------------------------------------------------------------------- - // Global instances - //-------------------------------------------------------------------------------------------------- ++/// This must be called only after successful init of the interrupt controller driver. ++fn post_init_interrupt_controller() -> Result<(), &'static str> { ++ generic_exception::asynchronous::register_irq_manager(&INTERRUPT_CONTROLLER); ++ ++ Ok(()) ++} ++ + fn driver_uart() -> Result<(), &'static str> { +- let uart_descriptor = +- generic_driver::DeviceDriverDescriptor::new(&PL011_UART, Some(post_init_uart)); ++ let uart_descriptor = generic_driver::DeviceDriverDescriptor::new( ++ &PL011_UART, ++ Some(post_init_uart), ++ Some(exception::asynchronous::irq_map::PL011_UART), ++ ); + generic_driver::driver_manager().register_driver(uart_descriptor); + + Ok(()) + } --pub(super) static PL011_UART: device_driver::PL011Uart = -- unsafe { device_driver::PL011Uart::new(mmio::PL011_UART_START) }; -+pub(super) static PL011_UART: device_driver::PL011Uart = unsafe { -+ device_driver::PL011Uart::new( -+ mmio::PL011_UART_START, -+ exception::asynchronous::irq_map::PL011_UART, -+ ) -+}; + fn driver_gpio() -> Result<(), &'static str> { +- let gpio_descriptor = generic_driver::DeviceDriverDescriptor::new(&GPIO, Some(post_init_gpio)); ++ let gpio_descriptor = ++ generic_driver::DeviceDriverDescriptor::new(&GPIO, Some(post_init_gpio), None); + generic_driver::driver_manager().register_driver(gpio_descriptor); - static GPIO: device_driver::GPIO = unsafe { device_driver::GPIO::new(mmio::GPIO_START) }; + Ok(()) + } -+#[cfg(feature = "bsp_rpi3")] -+pub(super) static INTERRUPT_CONTROLLER: device_driver::InterruptController = -+ unsafe { device_driver::InterruptController::new(mmio::PERIPHERAL_INTERRUPT_CONTROLLER_START) }; ++fn driver_interrupt_controller() -> Result<(), &'static str> { ++ let interrupt_controller_descriptor = generic_driver::DeviceDriverDescriptor::new( ++ &INTERRUPT_CONTROLLER, ++ Some(post_init_interrupt_controller), ++ None, ++ ); ++ generic_driver::driver_manager().register_driver(interrupt_controller_descriptor); + -+#[cfg(feature = "bsp_rpi4")] -+pub(super) static INTERRUPT_CONTROLLER: device_driver::GICv2 = -+ unsafe { device_driver::GICv2::new(mmio::GICD_START, mmio::GICC_START) }; ++ Ok(()) ++} + - static BSP_DRIVER_MANAGER: BSPDriverManager = BSPDriverManager { -- device_drivers: [&PL011_UART, &GPIO], -+ device_drivers: [&PL011_UART, &GPIO, &INTERRUPT_CONTROLLER], - }; - //-------------------------------------------------------------------------------------------------- + // Public Code + //-------------------------------------------------------------------------------------------------- +@@ -65,6 +99,7 @@ + + driver_uart()?; + driver_gpio()?; ++ driver_interrupt_controller()?; + + INIT_DONE.store(true, Ordering::Relaxed); + Ok(()) diff -uNr 12_integrated_testing/kernel/src/bsp/raspberrypi/exception/asynchronous.rs 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/exception/asynchronous.rs --- 12_integrated_testing/kernel/src/bsp/raspberrypi/exception/asynchronous.rs +++ 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/exception/asynchronous.rs -@@ -0,0 +1,36 @@ +@@ -0,0 +1,28 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2020-2022 Andre Richter + +//! BSP asynchronous exception handling. + -+use crate::{bsp, bsp::driver, exception}; ++use crate::bsp; + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + ++/// Export for reuse in generic asynchronous.rs. ++pub use bsp::device_driver::IRQNumber; ++ +#[cfg(feature = "bsp_rpi3")] +pub(in crate::bsp) mod irq_map { + use super::bsp::device_driver::{IRQNumber, PeripheralIRQ}; @@ -2110,17 +2274,6 @@ diff -uNr 12_integrated_testing/kernel/src/bsp/raspberrypi/exception/asynchronou + + pub const PL011_UART: IRQNumber = IRQNumber::new(153); +} -+ -+//-------------------------------------------------------------------------------------------------- -+// Public Code -+//-------------------------------------------------------------------------------------------------- -+ -+/// Return a reference to the IRQ manager. -+pub fn irq_manager() -> &'static impl exception::asynchronous::interface::IRQManager< -+ IRQNumberType = bsp::device_driver::IRQNumber, -+> { -+ &driver::INTERRUPT_CONTROLLER -+} diff -uNr 12_integrated_testing/kernel/src/bsp/raspberrypi/exception.rs 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/exception.rs --- 12_integrated_testing/kernel/src/bsp/raspberrypi/exception.rs @@ -2145,11 +2298,11 @@ diff -uNr 12_integrated_testing/kernel/src/bsp/raspberrypi/memory.rs 13_exceptio - pub const GPIO_START: usize = START + GPIO_OFFSET; - pub const PL011_UART_START: usize = START + UART_OFFSET; - pub const END_INCLUSIVE: usize = 0x4000_FFFF; -+ pub const START: usize = 0x3F00_0000; -+ pub const PERIPHERAL_INTERRUPT_CONTROLLER_START: usize = START + 0x0000_B200; -+ pub const GPIO_START: usize = START + GPIO_OFFSET; -+ pub const PL011_UART_START: usize = START + UART_OFFSET; -+ pub const END_INCLUSIVE: usize = 0x4000_FFFF; ++ pub const START: usize = 0x3F00_0000; ++ pub const PERIPHERAL_IC_START: usize = START + 0x0000_B200; ++ pub const GPIO_START: usize = START + GPIO_OFFSET; ++ pub const PL011_UART_START: usize = START + UART_OFFSET; ++ pub const END_INCLUSIVE: usize = 0x4000_FFFF; } /// Physical devices. @@ -2166,8 +2319,8 @@ diff -uNr 12_integrated_testing/kernel/src/bsp/raspberrypi/memory.rs 13_exceptio diff -uNr 12_integrated_testing/kernel/src/bsp/raspberrypi.rs 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi.rs --- 12_integrated_testing/kernel/src/bsp/raspberrypi.rs +++ 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi.rs -@@ -7,6 +7,7 @@ - pub mod console; +@@ -6,6 +6,7 @@ + pub mod cpu; pub mod driver; +pub mod exception; @@ -2175,6 +2328,47 @@ diff -uNr 12_integrated_testing/kernel/src/bsp/raspberrypi.rs 13_exceptions_part //-------------------------------------------------------------------------------------------------- +diff -uNr 12_integrated_testing/kernel/src/console.rs 13_exceptions_part2_peripheral_IRQs/kernel/src/console.rs +--- 12_integrated_testing/kernel/src/console.rs ++++ 13_exceptions_part2_peripheral_IRQs/kernel/src/console.rs +@@ -6,7 +6,7 @@ + + mod null_console; + +-use crate::synchronization::{self, NullLock}; ++use crate::synchronization; + + //-------------------------------------------------------------------------------------------------- + // Public Definitions +@@ -60,22 +60,22 @@ + // Global instances + //-------------------------------------------------------------------------------------------------- + +-static CUR_CONSOLE: NullLock<&'static (dyn interface::All + Sync)> = +- NullLock::new(&null_console::NULL_CONSOLE); ++static CUR_CONSOLE: InitStateLock<&'static (dyn interface::All + Sync)> = ++ InitStateLock::new(&null_console::NULL_CONSOLE); + + //-------------------------------------------------------------------------------------------------- + // Public Code + //-------------------------------------------------------------------------------------------------- +-use synchronization::interface::Mutex; ++use synchronization::{interface::ReadWriteEx, InitStateLock}; + + /// Register a new console. + pub fn register_console(new_console: &'static (dyn interface::All + Sync)) { +- CUR_CONSOLE.lock(|con| *con = new_console); ++ CUR_CONSOLE.write(|con| *con = new_console); + } + + /// Return a reference to the currently registered console. + /// + /// This is the global console used by all printing macros. + pub fn console() -> &'static dyn interface::All { +- CUR_CONSOLE.lock(|con| *con) ++ CUR_CONSOLE.read(|con| *con) + } + diff -uNr 12_integrated_testing/kernel/src/cpu/smp.rs 13_exceptions_part2_peripheral_IRQs/kernel/src/cpu/smp.rs --- 12_integrated_testing/kernel/src/cpu/smp.rs +++ 13_exceptions_part2_peripheral_IRQs/kernel/src/cpu/smp.rs @@ -2210,32 +2404,267 @@ diff -uNr 12_integrated_testing/kernel/src/cpu.rs 13_exceptions_part2_peripheral diff -uNr 12_integrated_testing/kernel/src/driver.rs 13_exceptions_part2_peripheral_IRQs/kernel/src/driver.rs --- 12_integrated_testing/kernel/src/driver.rs +++ 13_exceptions_part2_peripheral_IRQs/kernel/src/driver.rs -@@ -23,6 +23,14 @@ +@@ -5,9 +5,10 @@ + //! Driver support. + + use crate::{ +- info, +- synchronization::{interface::Mutex, NullLock}, ++ exception, info, ++ synchronization::{interface::ReadWriteEx, InitStateLock}, + }; ++use core::fmt; + + //-------------------------------------------------------------------------------------------------- + // Private Definitions +@@ -15,9 +16,12 @@ + + const NUM_DRIVERS: usize = 5; + +-struct DriverManagerInner { ++struct DriverManagerInner ++where ++ T: 'static, ++{ + next_index: usize, +- descriptors: [Option; NUM_DRIVERS], ++ descriptors: [Option>; NUM_DRIVERS], + } + + //-------------------------------------------------------------------------------------------------- +@@ -28,6 +32,9 @@ + pub mod interface { + /// Device Driver functions. + pub trait DeviceDriver { ++ /// Different interrupt controllers might use different types for IRQ number. ++ type IRQNumberType: super::fmt::Display; ++ + /// Return a compatibility string for identifying the driver. + fn compatible(&self) -> &'static str; + +@@ -39,6 +46,21 @@ unsafe fn init(&self) -> Result<(), &'static str> { Ok(()) } + -+ /// Called by the kernel to register and enable the device's IRQ handlers, if any. ++ /// Called by the kernel to register and enable the device's IRQ handler. + /// + /// Rust's type system will prevent a call to this function unless the calling instance + /// itself has static lifetime. -+ fn register_and_enable_irq_handler(&'static self) -> Result<(), &'static str> { -+ Ok(()) ++ fn register_and_enable_irq_handler( ++ &'static self, ++ irq_number: &Self::IRQNumberType, ++ ) -> Result<(), &'static str> { ++ panic!( ++ "Attempt to enable IRQ {} for device {}, but driver does not support this", ++ irq_number, ++ self.compatible() ++ ) + } } + } + +@@ -47,27 +69,37 @@ + + /// A descriptor for device drivers. + #[derive(Copy, Clone)] +-pub struct DeviceDriverDescriptor { +- device_driver: &'static (dyn interface::DeviceDriver + Sync), ++pub struct DeviceDriverDescriptor ++where ++ T: 'static, ++{ ++ device_driver: &'static (dyn interface::DeviceDriver + Sync), + post_init_callback: Option, ++ irq_number: Option, + } + + /// Provides device driver management functions. +-pub struct DriverManager { +- inner: NullLock, ++pub struct DriverManager ++where ++ T: 'static, ++{ ++ inner: InitStateLock>, + } + + //-------------------------------------------------------------------------------------------------- + // Global instances + //-------------------------------------------------------------------------------------------------- - /// Device driver management functions. +-static DRIVER_MANAGER: DriverManager = DriverManager::new(); ++static DRIVER_MANAGER: DriverManager = DriverManager::new(); + + //-------------------------------------------------------------------------------------------------- + // Private Code + //-------------------------------------------------------------------------------------------------- + +-impl DriverManagerInner { ++impl DriverManagerInner ++where ++ T: 'static + Copy, ++{ + /// Create an instance. + pub const fn new() -> Self { + Self { +@@ -81,43 +113,48 @@ + // Public Code + //-------------------------------------------------------------------------------------------------- + +-impl DeviceDriverDescriptor { ++impl DeviceDriverDescriptor { + /// Create an instance. + pub fn new( +- device_driver: &'static (dyn interface::DeviceDriver + Sync), ++ device_driver: &'static (dyn interface::DeviceDriver + Sync), + post_init_callback: Option, ++ irq_number: Option, + ) -> Self { + Self { + device_driver, + post_init_callback, ++ irq_number, + } + } + } + + /// Return a reference to the global DriverManager. +-pub fn driver_manager() -> &'static DriverManager { ++pub fn driver_manager() -> &'static DriverManager { + &DRIVER_MANAGER + } + +-impl DriverManager { ++impl DriverManager ++where ++ T: fmt::Display + Copy, ++{ + /// Create an instance. + pub const fn new() -> Self { + Self { +- inner: NullLock::new(DriverManagerInner::new()), ++ inner: InitStateLock::new(DriverManagerInner::new()), + } + } + + /// Register a device driver with the kernel. +- pub fn register_driver(&self, descriptor: DeviceDriverDescriptor) { +- self.inner.lock(|inner| { ++ pub fn register_driver(&self, descriptor: DeviceDriverDescriptor) { ++ self.inner.write(|inner| { + inner.descriptors[inner.next_index] = Some(descriptor); + inner.next_index += 1; + }) + } + + /// Helper for iterating over registered drivers. +- fn for_each_descriptor<'a>(&'a self, f: impl FnMut(&'a DeviceDriverDescriptor)) { +- self.inner.lock(|inner| { ++ fn for_each_descriptor<'a>(&'a self, f: impl FnMut(&'a DeviceDriverDescriptor)) { ++ self.inner.read(|inner| { + inner + .descriptors + .iter() +@@ -126,12 +163,12 @@ + }) + } + +- /// Fully initialize all drivers. ++ /// Fully initialize all drivers and their interrupts handlers. + /// + /// # Safety + /// + /// - During init, drivers might do stuff with system-wide impact. +- pub unsafe fn init_drivers(&self) { ++ pub unsafe fn init_drivers_and_irqs(&self) { + self.for_each_descriptor(|descriptor| { + // 1. Initialize driver. + if let Err(x) = descriptor.device_driver.init() { +@@ -150,6 +187,23 @@ + descriptor.device_driver.compatible(), + x + ); ++ } ++ } ++ }); ++ ++ // 3. After all post-init callbacks were done, the interrupt controller should be ++ // registered and functional. So let drivers register with it now. ++ self.for_each_descriptor(|descriptor| { ++ if let Some(irq_number) = &descriptor.irq_number { ++ if let Err(x) = descriptor ++ .device_driver ++ .register_and_enable_irq_handler(irq_number) ++ { ++ panic!( ++ "Error during driver interrupt handler registration: {}: {}", ++ descriptor.device_driver.compatible(), ++ x ++ ); + } + } + }); + +diff -uNr 12_integrated_testing/kernel/src/exception/asynchronous/null_irq_manager.rs 13_exceptions_part2_peripheral_IRQs/kernel/src/exception/asynchronous/null_irq_manager.rs +--- 12_integrated_testing/kernel/src/exception/asynchronous/null_irq_manager.rs ++++ 13_exceptions_part2_peripheral_IRQs/kernel/src/exception/asynchronous/null_irq_manager.rs +@@ -0,0 +1,42 @@ ++// SPDX-License-Identifier: MIT OR Apache-2.0 ++// ++// Copyright (c) 2022 Andre Richter ++ ++//! Null IRQ Manager. ++ ++use super::{interface, IRQContext, IRQHandlerDescriptor}; ++ ++//-------------------------------------------------------------------------------------------------- ++// Public Definitions ++//-------------------------------------------------------------------------------------------------- ++ ++pub struct NullIRQManager; ++ ++//-------------------------------------------------------------------------------------------------- ++// Global instances ++//-------------------------------------------------------------------------------------------------- ++ ++pub static NULL_IRQ_MANAGER: NullIRQManager = NullIRQManager {}; ++ ++//-------------------------------------------------------------------------------------------------- ++// Public Code ++//-------------------------------------------------------------------------------------------------- ++ ++impl interface::IRQManager for NullIRQManager { ++ type IRQNumberType = super::IRQNumber; ++ ++ fn register_handler( ++ &self, ++ _descriptor: IRQHandlerDescriptor, ++ ) -> Result<(), &'static str> { ++ panic!("No IRQ Manager registered yet"); ++ } ++ ++ fn enable(&self, _irq_number: &Self::IRQNumberType) { ++ panic!("No IRQ Manager registered yet"); ++ } ++ ++ fn handle_pending_irqs<'irq_context>(&'irq_context self, _ic: &IRQContext<'irq_context>) { ++ panic!("No IRQ Manager registered yet"); ++ } ++} diff -uNr 12_integrated_testing/kernel/src/exception/asynchronous.rs 13_exceptions_part2_peripheral_IRQs/kernel/src/exception/asynchronous.rs --- 12_integrated_testing/kernel/src/exception/asynchronous.rs +++ 13_exceptions_part2_peripheral_IRQs/kernel/src/exception/asynchronous.rs -@@ -8,7 +8,152 @@ +@@ -7,8 +7,184 @@ + #[cfg(target_arch = "aarch64")] #[path = "../_arch/aarch64/exception/asynchronous.rs"] mod arch_asynchronous; - -+use crate::bsp; -+use core::{fmt, marker::PhantomData}; ++mod null_irq_manager; + ++use crate::{bsp, synchronization}; ++use core::marker::PhantomData; + //-------------------------------------------------------------------------------------------------- // Architectural Public Reexports //-------------------------------------------------------------------------------------------------- @@ -2249,14 +2678,23 @@ diff -uNr 12_integrated_testing/kernel/src/exception/asynchronous.rs 13_exceptio +// Public Definitions +//-------------------------------------------------------------------------------------------------- + ++/// Interrupt number as defined by the BSP. ++pub type IRQNumber = bsp::exception::asynchronous::IRQNumber; ++ +/// Interrupt descriptor. +#[derive(Copy, Clone)] -+pub struct IRQDescriptor { ++pub struct IRQHandlerDescriptor ++where ++ T: Copy, ++{ ++ /// The IRQ number. ++ number: T, ++ + /// Descriptive name. -+ pub name: &'static str, ++ name: &'static str, + + /// Reference to handler trait object. -+ pub handler: &'static (dyn interface::IRQHandler + Sync), ++ handler: &'static (dyn interface::IRQHandler + Sync), +} + +/// IRQContext token. @@ -2286,17 +2724,16 @@ diff -uNr 12_integrated_testing/kernel/src/exception/asynchronous.rs 13_exceptio + /// platform's interrupt controller. + pub trait IRQManager { + /// The IRQ number type depends on the implementation. -+ type IRQNumberType; ++ type IRQNumberType: Copy; + + /// Register a handler. + fn register_handler( + &self, -+ irq_number: Self::IRQNumberType, -+ descriptor: super::IRQDescriptor, ++ irq_handler_descriptor: super::IRQHandlerDescriptor, + ) -> Result<(), &'static str>; + + /// Enable an interrupt in the controller. -+ fn enable(&self, irq_number: Self::IRQNumberType); ++ fn enable(&self, irq_number: &Self::IRQNumberType); + + /// Handle pending interrupts. + /// @@ -2312,17 +2749,55 @@ diff -uNr 12_integrated_testing/kernel/src/exception/asynchronous.rs 13_exceptio + ); + + /// Print list of registered handlers. -+ fn print_handler(&self); ++ fn print_handler(&self) {} + } +} + -+/// A wrapper type for IRQ numbers with integrated range sanity check. -+#[derive(Copy, Clone)] -+pub struct IRQNumber(usize); ++//-------------------------------------------------------------------------------------------------- ++// Global instances ++//-------------------------------------------------------------------------------------------------- ++ ++static CUR_IRQ_MANAGER: InitStateLock< ++ &'static (dyn interface::IRQManager + Sync), ++> = InitStateLock::new(&null_irq_manager::NULL_IRQ_MANAGER); + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- ++use synchronization::{interface::ReadWriteEx, InitStateLock}; ++ ++impl IRQHandlerDescriptor ++where ++ T: Copy, ++{ ++ /// Create an instance. ++ pub const fn new( ++ number: T, ++ name: &'static str, ++ handler: &'static (dyn interface::IRQHandler + Sync), ++ ) -> Self { ++ Self { ++ number, ++ name, ++ handler, ++ } ++ } ++ ++ /// Return the number. ++ pub const fn number(&self) -> T { ++ self.number ++ } ++ ++ /// Return the name. ++ pub const fn name(&self) -> &'static str { ++ self.name ++ } ++ ++ /// Return the handler. ++ pub const fn handler(&self) -> &'static (dyn interface::IRQHandler + Sync) { ++ self.handler ++ } ++} + +impl<'irq_context> IRQContext<'irq_context> { + /// Creates an IRQContext token. @@ -2341,29 +2816,6 @@ diff -uNr 12_integrated_testing/kernel/src/exception/asynchronous.rs 13_exceptio + } +} + -+impl IRQNumber<{ MAX_INCLUSIVE }> { -+ /// The total number of IRQs this type supports. -+ pub const NUM_TOTAL: usize = MAX_INCLUSIVE + 1; -+ -+ /// Creates a new instance if number <= MAX_INCLUSIVE. -+ pub const fn new(number: usize) -> Self { -+ assert!(number <= MAX_INCLUSIVE); -+ -+ Self(number) -+ } -+ -+ /// Return the wrapped number. -+ pub const fn get(self) -> usize { -+ self.0 -+ } -+} -+ -+impl fmt::Display for IRQNumber<{ MAX_INCLUSIVE }> { -+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { -+ write!(f, "{}", self.0) -+ } -+} -+ +/// Executes the provided closure while IRQs are masked on the executing core. +/// +/// While the function temporarily changes the HW state of the executing core, it restores it to the @@ -2377,11 +2829,18 @@ diff -uNr 12_integrated_testing/kernel/src/exception/asynchronous.rs 13_exceptio + ret +} + -+/// Return a reference to the IRQ manager. ++/// Register a new IRQ manager. ++pub fn register_irq_manager( ++ new_manager: &'static (dyn interface::IRQManager + Sync), ++) { ++ CUR_IRQ_MANAGER.write(|manager| *manager = new_manager); ++} ++ ++/// Return a reference to the currently registered IRQ manager. +/// +/// This is the IRQ manager used by the architectural interrupt handling code. -+pub fn irq_manager() -> &'static dyn interface::IRQManager { -+ bsp::exception::asynchronous::irq_manager() ++pub fn irq_manager() -> &'static dyn interface::IRQManager { ++ CUR_IRQ_MANAGER.read(|manager| *manager) +} diff -uNr 12_integrated_testing/kernel/src/lib.rs 13_exceptions_part2_peripheral_IRQs/kernel/src/lib.rs @@ -2404,7 +2863,7 @@ diff -uNr 12_integrated_testing/kernel/src/main.rs 13_exceptions_part2_periphera #![no_std] -use libkernel::{bsp, console, driver, exception, info, memory, time}; -+use libkernel::{bsp, cpu, driver, exception, info, memory, state, time, warn}; ++use libkernel::{bsp, cpu, driver, exception, info, memory, state, time}; /// Early init code. /// @@ -2416,43 +2875,39 @@ diff -uNr 12_integrated_testing/kernel/src/main.rs 13_exceptions_part2_periphera +/// IRQSafeNullLocks instead of spinlocks), will fail to work (properly) on the RPi SoCs. #[no_mangle] unsafe fn kernel_init() -> ! { - use driver::interface::DriverManager; -@@ -43,14 +43,27 @@ - bsp::driver::driver_manager().post_device_driver_init(); - // println! is usable from here on. - -+ // Let device drivers register and enable their handlers with the interrupt controller. -+ for i in bsp::driver::driver_manager().all_device_drivers() { -+ if let Err(msg) = i.register_and_enable_irq_handler() { -+ warn!("Error registering IRQ handler: {}", msg); -+ } -+ } + use memory::mmu::interface::MMU; +@@ -40,8 +40,13 @@ + } + + // Initialize all device drivers. +- driver::driver_manager().init_drivers(); +- // println! is usable from here on. ++ driver::driver_manager().init_drivers_and_irqs(); + + // Unmask interrupts on the boot CPU core. + exception::asynchronous::local_irq_unmask(); + + // Announce conclusion of the kernel_init() phase. + state::state_manager().transition_to_single_core_main(); -+ + // Transition from unsafe to safe. kernel_main() - } +@@ -49,8 +54,6 @@ /// The main function running after the early init. fn kernel_main() -> ! { - use console::console; - use driver::interface::DriverManager; -+ use exception::asynchronous::interface::IRQManager; - +- info!("{}", libkernel::version()); info!("Booting on: {}", bsp::board_name()); -@@ -78,12 +91,9 @@ - info!(" {}. {}", i + 1, driver.compatible()); - } + +@@ -71,12 +74,9 @@ + info!("Drivers loaded:"); + driver::driver_manager().enumerate(); - info!("Echoing input now"); + info!("Registered IRQ handlers:"); -+ bsp::exception::asynchronous::irq_manager().print_handler(); ++ exception::asynchronous::irq_manager().print_handler(); - // Discard any spurious received characters before going into echo mode. - console().clear_rx(); @@ -2721,7 +3176,7 @@ diff -uNr 12_integrated_testing/kernel/src/synchronization.rs 13_exceptions_part diff -uNr 12_integrated_testing/kernel/tests/04_exception_irq_sanity.rs 13_exceptions_part2_peripheral_IRQs/kernel/tests/04_exception_irq_sanity.rs --- 12_integrated_testing/kernel/tests/04_exception_irq_sanity.rs +++ 13_exceptions_part2_peripheral_IRQs/kernel/tests/04_exception_irq_sanity.rs -@@ -0,0 +1,67 @@ +@@ -0,0 +1,66 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2020-2022 Andre Richter @@ -2734,13 +3189,12 @@ diff -uNr 12_integrated_testing/kernel/tests/04_exception_irq_sanity.rs 13_excep +#![reexport_test_harness_main = "test_main"] +#![test_runner(libkernel::test_runner)] + -+use libkernel::{bsp, cpu, driver, exception}; ++use libkernel::{bsp, cpu, exception}; +use test_macros::kernel_test; + +#[no_mangle] +unsafe fn kernel_init() -> ! { -+ use driver::interface::DriverManager; -+ bsp::driver::driver_manager().qemu_bring_up_console(); ++ bsp::driver::qemu_bring_up_console(); + + exception::handling_init(); + exception::asynchronous::local_irq_unmask(); diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/arm/gicv2.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/arm/gicv2.rs index c810a59a..2623c305 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/arm/gicv2.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/arm/gicv2.rs @@ -79,20 +79,25 @@ mod gicc; mod gicd; -use crate::{bsp, cpu, driver, exception, synchronization, synchronization::InitStateLock}; +use crate::{ + bsp::{self, device_driver::common::BoundedUsize}, + cpu, driver, exception, synchronization, + synchronization::InitStateLock, +}; //-------------------------------------------------------------------------------------------------- // Private Definitions //-------------------------------------------------------------------------------------------------- -type HandlerTable = [Option; IRQNumber::NUM_TOTAL]; +type HandlerTable = [Option>; + IRQNumber::MAX_INCLUSIVE + 1]; //-------------------------------------------------------------------------------------------------- // Public Definitions //-------------------------------------------------------------------------------------------------- /// Used for the associated type of trait [`exception::asynchronous::interface::IRQManager`]. -pub type IRQNumber = exception::asynchronous::IRQNumber<{ GICv2::MAX_IRQ_NUMBER }>; +pub type IRQNumber = BoundedUsize<{ GICv2::MAX_IRQ_NUMBER }>; /// Representation of the GIC. pub struct GICv2 { @@ -124,7 +129,7 @@ impl GICv2 { Self { gicd: gicd::GICD::new(gicd_mmio_start_addr), gicc: gicc::GICC::new(gicc_mmio_start_addr), - handler_table: InitStateLock::new([None; IRQNumber::NUM_TOTAL]), + handler_table: InitStateLock::new([None; IRQNumber::MAX_INCLUSIVE + 1]), } } } @@ -135,6 +140,8 @@ impl GICv2 { use synchronization::interface::ReadWriteEx; impl driver::interface::DeviceDriver for GICv2 { + type IRQNumberType = IRQNumber; + fn compatible(&self) -> &'static str { Self::COMPATIBLE } @@ -156,23 +163,22 @@ impl exception::asynchronous::interface::IRQManager for GICv2 { fn register_handler( &self, - irq_number: Self::IRQNumberType, - descriptor: exception::asynchronous::IRQDescriptor, + irq_handler_descriptor: exception::asynchronous::IRQHandlerDescriptor, ) -> Result<(), &'static str> { self.handler_table.write(|table| { - let irq_number = irq_number.get(); + let irq_number = irq_handler_descriptor.number().get(); if table[irq_number].is_some() { return Err("IRQ handler already registered"); } - table[irq_number] = Some(descriptor); + table[irq_number] = Some(irq_handler_descriptor); Ok(()) }) } - fn enable(&self, irq_number: Self::IRQNumberType) { + fn enable(&self, irq_number: &Self::IRQNumberType) { self.gicd.enable(irq_number); } @@ -195,7 +201,7 @@ impl exception::asynchronous::interface::IRQManager for GICv2 { None => panic!("No handler registered for IRQ {}", irq_number), Some(descriptor) => { // Call the IRQ handler. Panics on failure. - descriptor.handler.handle().expect("Error handling IRQ"); + descriptor.handler().handle().expect("Error handling IRQ"); } } }); @@ -212,7 +218,7 @@ impl exception::asynchronous::interface::IRQManager for GICv2 { self.handler_table.read(|table| { for (i, opt) in table.iter().skip(32).enumerate() { if let Some(handler) = opt { - info!(" {: >3}. {}", i + 32, handler.name); + info!(" {: >3}. {}", i + 32, handler.name()); } } }); diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs index 54aab60c..2d18be9c 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs @@ -170,7 +170,7 @@ impl GICD { } /// Enable an interrupt. - pub fn enable(&self, irq_num: super::IRQNumber) { + pub fn enable(&self, irq_num: &super::IRQNumber) { let irq_num = irq_num.get(); // Each bit in the u32 enable register corresponds to one IRQ number. Shift right by 5 diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs index 0f3e701f..336cc8f7 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs @@ -5,8 +5,8 @@ //! GPIO Driver. use crate::{ - bsp::device_driver::common::MMIODerefWrapper, driver, synchronization, - synchronization::IRQSafeNullLock, + bsp::device_driver::common::MMIODerefWrapper, driver, exception::asynchronous::IRQNumber, + synchronization, synchronization::IRQSafeNullLock, }; use tock_registers::{ interfaces::{ReadWriteable, Writeable}, @@ -216,6 +216,8 @@ impl GPIO { use synchronization::interface::Mutex; impl driver::interface::DeviceDriver for GPIO { + type IRQNumberType = IRQNumber; + fn compatible(&self) -> &'static str { Self::COMPATIBLE } diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs index a88899c2..22298f1c 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs @@ -6,7 +6,12 @@ mod peripheral_ic; -use crate::{driver, exception}; +use crate::{ + bsp::device_driver::common::BoundedUsize, + driver, + exception::{self, asynchronous::IRQHandlerDescriptor}, +}; +use core::fmt; //-------------------------------------------------------------------------------------------------- // Private Definitions @@ -21,10 +26,8 @@ struct PendingIRQs { // Public Definitions //-------------------------------------------------------------------------------------------------- -pub type LocalIRQ = - exception::asynchronous::IRQNumber<{ InterruptController::MAX_LOCAL_IRQ_NUMBER }>; -pub type PeripheralIRQ = - exception::asynchronous::IRQNumber<{ InterruptController::MAX_PERIPHERAL_IRQ_NUMBER }>; +pub type LocalIRQ = BoundedUsize<{ InterruptController::MAX_LOCAL_IRQ_NUMBER }>; +pub type PeripheralIRQ = BoundedUsize<{ InterruptController::MAX_PERIPHERAL_IRQ_NUMBER }>; /// Used for the associated type of trait [`exception::asynchronous::interface::IRQManager`]. #[derive(Copy, Clone)] @@ -67,6 +70,15 @@ impl Iterator for PendingIRQs { // Public Code //-------------------------------------------------------------------------------------------------- +impl fmt::Display for IRQNumber { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Self::Local(number) => write!(f, "Local({})", number), + Self::Peripheral(number) => write!(f, "Peripheral({})", number), + } + } +} + impl InterruptController { // Restrict to 3 for now. This makes future code for local_ic.rs more straight forward. const MAX_LOCAL_IRQ_NUMBER: usize = 3; @@ -91,6 +103,8 @@ impl InterruptController { //------------------------------------------------------------------------------ impl driver::interface::DeviceDriver for InterruptController { + type IRQNumberType = IRQNumber; + fn compatible(&self) -> &'static str { Self::COMPATIBLE } @@ -101,16 +115,23 @@ impl exception::asynchronous::interface::IRQManager for InterruptController { fn register_handler( &self, - irq: Self::IRQNumberType, - descriptor: exception::asynchronous::IRQDescriptor, + irq_handler_descriptor: exception::asynchronous::IRQHandlerDescriptor, ) -> Result<(), &'static str> { - match irq { + match irq_handler_descriptor.number() { IRQNumber::Local(_) => unimplemented!("Local IRQ controller not implemented."), - IRQNumber::Peripheral(pirq) => self.periph.register_handler(pirq, descriptor), + IRQNumber::Peripheral(pirq) => { + let periph_descriptor = IRQHandlerDescriptor::new( + pirq, + irq_handler_descriptor.name(), + irq_handler_descriptor.handler(), + ); + + self.periph.register_handler(periph_descriptor) + } } } - fn enable(&self, irq: Self::IRQNumberType) { + fn enable(&self, irq: &Self::IRQNumberType) { match irq { IRQNumber::Local(_) => unimplemented!("Local IRQ controller not implemented."), IRQNumber::Peripheral(pirq) => self.periph.enable(pirq), diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs index 90d9dd81..1af6f22f 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs @@ -50,7 +50,8 @@ type WriteOnlyRegisters = MMIODerefWrapper; /// Abstraction for the ReadOnly parts of the associated MMIO registers. type ReadOnlyRegisters = MMIODerefWrapper; -type HandlerTable = [Option; PeripheralIRQ::NUM_TOTAL]; +type HandlerTable = [Option>; + PeripheralIRQ::MAX_INCLUSIVE + 1]; //-------------------------------------------------------------------------------------------------- // Public Definitions @@ -82,7 +83,7 @@ impl PeripheralIC { Self { wo_registers: IRQSafeNullLock::new(WriteOnlyRegisters::new(mmio_start_addr)), ro_registers: ReadOnlyRegisters::new(mmio_start_addr), - handler_table: InitStateLock::new([None; PeripheralIRQ::NUM_TOTAL]), + handler_table: InitStateLock::new([None; PeripheralIRQ::MAX_INCLUSIVE + 1]), } } @@ -105,23 +106,22 @@ impl exception::asynchronous::interface::IRQManager for PeripheralIC { fn register_handler( &self, - irq: Self::IRQNumberType, - descriptor: exception::asynchronous::IRQDescriptor, + irq_handler_descriptor: exception::asynchronous::IRQHandlerDescriptor, ) -> Result<(), &'static str> { self.handler_table.write(|table| { - let irq_number = irq.get(); + let irq_number = irq_handler_descriptor.number().get(); if table[irq_number].is_some() { return Err("IRQ handler already registered"); } - table[irq_number] = Some(descriptor); + table[irq_number] = Some(irq_handler_descriptor); Ok(()) }) } - fn enable(&self, irq: Self::IRQNumberType) { + fn enable(&self, irq: &Self::IRQNumberType) { self.wo_registers.lock(|regs| { let enable_reg = if irq.get() <= 31 { ®s.ENABLE_1 @@ -147,7 +147,7 @@ impl exception::asynchronous::interface::IRQManager for PeripheralIC { None => panic!("No handler registered for IRQ {}", irq_number), Some(descriptor) => { // Call the IRQ handler. Panics on failure. - descriptor.handler.handle().expect("Error handling IRQ"); + descriptor.handler().handle().expect("Error handling IRQ"); } } } @@ -162,7 +162,7 @@ impl exception::asynchronous::interface::IRQManager for PeripheralIC { self.handler_table.read(|table| { for (i, opt) in table.iter().enumerate() { if let Some(handler) = opt { - info!(" {: >3}. {}", i, handler.name); + info!(" {: >3}. {}", i, handler.name()); } } }); diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs index a96ebf7e..71b3e254 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs @@ -10,8 +10,11 @@ //! - use crate::{ - bsp, bsp::device_driver::common::MMIODerefWrapper, console, cpu, driver, exception, - synchronization, synchronization::IRQSafeNullLock, + bsp::device_driver::common::MMIODerefWrapper, + console, cpu, driver, + exception::{self, asynchronous::IRQNumber}, + synchronization, + synchronization::IRQSafeNullLock, }; use core::fmt; use tock_registers::{ @@ -229,7 +232,6 @@ struct PL011UartInner { /// Representation of the UART. pub struct PL011Uart { inner: IRQSafeNullLock, - irq_number: bsp::device_driver::IRQNumber, } //-------------------------------------------------------------------------------------------------- @@ -393,13 +395,9 @@ impl PL011Uart { /// # Safety /// /// - The user must ensure to provide a correct MMIO start address. - pub const unsafe fn new( - mmio_start_addr: usize, - irq_number: bsp::device_driver::IRQNumber, - ) -> Self { + pub const unsafe fn new(mmio_start_addr: usize) -> Self { Self { inner: IRQSafeNullLock::new(PL011UartInner::new(mmio_start_addr)), - irq_number, } } } @@ -410,6 +408,8 @@ impl PL011Uart { use synchronization::interface::Mutex; impl driver::interface::DeviceDriver for PL011Uart { + type IRQNumberType = IRQNumber; + fn compatible(&self) -> &'static str { Self::COMPATIBLE } @@ -420,16 +420,16 @@ impl driver::interface::DeviceDriver for PL011Uart { Ok(()) } - fn register_and_enable_irq_handler(&'static self) -> Result<(), &'static str> { - use exception::asynchronous::{irq_manager, IRQDescriptor}; + fn register_and_enable_irq_handler( + &'static self, + irq_number: &Self::IRQNumberType, + ) -> Result<(), &'static str> { + use exception::asynchronous::{irq_manager, IRQHandlerDescriptor}; - let descriptor = IRQDescriptor { - name: Self::COMPATIBLE, - handler: self, - }; + let descriptor = IRQHandlerDescriptor::new(*irq_number, Self::COMPATIBLE, self); - irq_manager().register_handler(self.irq_number, descriptor)?; - irq_manager().enable(self.irq_number); + irq_manager().register_handler(descriptor)?; + irq_manager().enable(irq_number); Ok(()) } diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/common.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/common.rs index fd9e988e..c368534a 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/common.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/common.rs @@ -4,7 +4,7 @@ //! Common device driver code. -use core::{marker::PhantomData, ops}; +use core::{fmt, marker::PhantomData, ops}; //-------------------------------------------------------------------------------------------------- // Public Definitions @@ -15,6 +15,10 @@ pub struct MMIODerefWrapper { phantom: PhantomData T>, } +/// A wrapper type for usize with integrated range bound check. +#[derive(Copy, Clone)] +pub struct BoundedUsize(usize); + //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- @@ -36,3 +40,25 @@ impl ops::Deref for MMIODerefWrapper { unsafe { &*(self.start_addr as *const _) } } } + +impl BoundedUsize<{ MAX_INCLUSIVE }> { + pub const MAX_INCLUSIVE: usize = MAX_INCLUSIVE; + + /// Creates a new instance if number <= MAX_INCLUSIVE. + pub const fn new(number: usize) -> Self { + assert!(number <= MAX_INCLUSIVE); + + Self(number) + } + + /// Return the wrapped number. + pub const fn get(self) -> usize { + self.0 + } +} + +impl fmt::Display for BoundedUsize<{ MAX_INCLUSIVE }> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.0) + } +} diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi.rs index 50b36762..474419f4 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi.rs @@ -4,7 +4,6 @@ //! Top-level BSP file for the Raspberry Pi 3 and 4. -pub mod console; pub mod cpu; pub mod driver; pub mod exception; diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/console.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/console.rs deleted file mode 100644 index 0a630eef..00000000 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/console.rs +++ /dev/null @@ -1,16 +0,0 @@ -// SPDX-License-Identifier: MIT OR Apache-2.0 -// -// Copyright (c) 2018-2022 Andre Richter - -//! BSP console facilities. - -use crate::console; - -//-------------------------------------------------------------------------------------------------- -// Public Code -//-------------------------------------------------------------------------------------------------- - -/// Return a reference to the console. -pub fn console() -> &'static dyn console::interface::All { - &super::driver::PL011_UART -} diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/driver.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/driver.rs index 568f1096..91dd6133 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/driver.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/driver.rs @@ -5,68 +5,109 @@ //! BSP driver support. use super::{exception, memory::map::mmio}; -use crate::{bsp::device_driver, driver}; - -pub use device_driver::IRQNumber; - -//-------------------------------------------------------------------------------------------------- -// Private Definitions -//-------------------------------------------------------------------------------------------------- - -/// Device Driver Manager type. -struct BSPDriverManager { - device_drivers: [&'static (dyn DeviceDriver + Sync); 3], -} +use crate::{ + bsp::device_driver, + console, driver as generic_driver, + exception::{self as generic_exception}, +}; +use core::sync::atomic::{AtomicBool, Ordering}; //-------------------------------------------------------------------------------------------------- // Global instances //-------------------------------------------------------------------------------------------------- -pub(super) static PL011_UART: device_driver::PL011Uart = unsafe { - device_driver::PL011Uart::new( - mmio::PL011_UART_START, - exception::asynchronous::irq_map::PL011_UART, - ) -}; - +static PL011_UART: device_driver::PL011Uart = + unsafe { device_driver::PL011Uart::new(mmio::PL011_UART_START) }; static GPIO: device_driver::GPIO = unsafe { device_driver::GPIO::new(mmio::GPIO_START) }; #[cfg(feature = "bsp_rpi3")] -pub(super) static INTERRUPT_CONTROLLER: device_driver::InterruptController = - unsafe { device_driver::InterruptController::new(mmio::PERIPHERAL_INTERRUPT_CONTROLLER_START) }; +static INTERRUPT_CONTROLLER: device_driver::InterruptController = + unsafe { device_driver::InterruptController::new(mmio::PERIPHERAL_IC_START) }; #[cfg(feature = "bsp_rpi4")] -pub(super) static INTERRUPT_CONTROLLER: device_driver::GICv2 = +static INTERRUPT_CONTROLLER: device_driver::GICv2 = unsafe { device_driver::GICv2::new(mmio::GICD_START, mmio::GICC_START) }; -static BSP_DRIVER_MANAGER: BSPDriverManager = BSPDriverManager { - device_drivers: [&PL011_UART, &GPIO, &INTERRUPT_CONTROLLER], -}; - //-------------------------------------------------------------------------------------------------- -// Public Code +// Private Code //-------------------------------------------------------------------------------------------------- -/// Return a reference to the driver manager. -pub fn driver_manager() -> &'static impl driver::interface::DriverManager { - &BSP_DRIVER_MANAGER +/// This must be called only after successful init of the UART driver. +fn post_init_uart() -> Result<(), &'static str> { + console::register_console(&PL011_UART); + + Ok(()) } -//------------------------------------------------------------------------------ -// OS Interface Code -//------------------------------------------------------------------------------ -use driver::interface::DeviceDriver; +/// This must be called only after successful init of the GPIO driver. +fn post_init_gpio() -> Result<(), &'static str> { + GPIO.map_pl011_uart(); + Ok(()) +} -impl driver::interface::DriverManager for BSPDriverManager { - fn all_device_drivers(&self) -> &[&'static (dyn DeviceDriver + Sync)] { - &self.device_drivers[..] - } +/// This must be called only after successful init of the interrupt controller driver. +fn post_init_interrupt_controller() -> Result<(), &'static str> { + generic_exception::asynchronous::register_irq_manager(&INTERRUPT_CONTROLLER); + + Ok(()) +} - fn post_device_driver_init(&self) { - // Configure PL011Uart's output pins. - GPIO.map_pl011_uart(); +fn driver_uart() -> Result<(), &'static str> { + let uart_descriptor = generic_driver::DeviceDriverDescriptor::new( + &PL011_UART, + Some(post_init_uart), + Some(exception::asynchronous::irq_map::PL011_UART), + ); + generic_driver::driver_manager().register_driver(uart_descriptor); + + Ok(()) +} + +fn driver_gpio() -> Result<(), &'static str> { + let gpio_descriptor = + generic_driver::DeviceDriverDescriptor::new(&GPIO, Some(post_init_gpio), None); + generic_driver::driver_manager().register_driver(gpio_descriptor); + + Ok(()) +} + +fn driver_interrupt_controller() -> Result<(), &'static str> { + let interrupt_controller_descriptor = generic_driver::DeviceDriverDescriptor::new( + &INTERRUPT_CONTROLLER, + Some(post_init_interrupt_controller), + None, + ); + generic_driver::driver_manager().register_driver(interrupt_controller_descriptor); + + Ok(()) +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +/// Initialize the driver subsystem. +/// +/// # Safety +/// +/// See child function calls. +pub unsafe fn init() -> Result<(), &'static str> { + static INIT_DONE: AtomicBool = AtomicBool::new(false); + if INIT_DONE.load(Ordering::Relaxed) { + return Err("Init already done"); } - #[cfg(feature = "test_build")] - fn qemu_bring_up_console(&self) {} + driver_uart()?; + driver_gpio()?; + driver_interrupt_controller()?; + + INIT_DONE.store(true, Ordering::Relaxed); + Ok(()) +} + +/// Minimal code needed to bring up the console in QEMU (for testing only). This is often less steps +/// than on real hardware due to QEMU's abstractions. +#[cfg(feature = "test_build")] +pub fn qemu_bring_up_console() { + console::register_console(&PL011_UART); } diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/exception/asynchronous.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/exception/asynchronous.rs index a13b2444..06a67558 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/exception/asynchronous.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/exception/asynchronous.rs @@ -4,12 +4,15 @@ //! BSP asynchronous exception handling. -use crate::{bsp, bsp::driver, exception}; +use crate::bsp; //-------------------------------------------------------------------------------------------------- // Public Definitions //-------------------------------------------------------------------------------------------------- +/// Export for reuse in generic asynchronous.rs. +pub use bsp::device_driver::IRQNumber; + #[cfg(feature = "bsp_rpi3")] pub(in crate::bsp) mod irq_map { use super::bsp::device_driver::{IRQNumber, PeripheralIRQ}; @@ -23,14 +26,3 @@ pub(in crate::bsp) mod irq_map { pub const PL011_UART: IRQNumber = IRQNumber::new(153); } - -//-------------------------------------------------------------------------------------------------- -// Public Code -//-------------------------------------------------------------------------------------------------- - -/// Return a reference to the IRQ manager. -pub fn irq_manager() -> &'static impl exception::asynchronous::interface::IRQManager< - IRQNumberType = bsp::device_driver::IRQNumber, -> { - &driver::INTERRUPT_CONTROLLER -} diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/memory.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/memory.rs index a383c9fe..be13bb7a 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/memory.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/memory.rs @@ -73,11 +73,11 @@ pub(super) mod map { pub mod mmio { use super::*; - pub const START: usize = 0x3F00_0000; - pub const PERIPHERAL_INTERRUPT_CONTROLLER_START: usize = START + 0x0000_B200; - pub const GPIO_START: usize = START + GPIO_OFFSET; - pub const PL011_UART_START: usize = START + UART_OFFSET; - pub const END_INCLUSIVE: usize = 0x4000_FFFF; + pub const START: usize = 0x3F00_0000; + pub const PERIPHERAL_IC_START: usize = START + 0x0000_B200; + pub const GPIO_START: usize = START + GPIO_OFFSET; + pub const PL011_UART_START: usize = START + UART_OFFSET; + pub const END_INCLUSIVE: usize = 0x4000_FFFF; } /// Physical devices. diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/console.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/console.rs index c1fb0e53..a85bcffe 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/console.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/console.rs @@ -4,7 +4,9 @@ //! System console. -use crate::bsp; +mod null_console; + +use crate::synchronization; //-------------------------------------------------------------------------------------------------- // Public Definitions @@ -54,13 +56,26 @@ pub mod interface { pub trait All: Write + Read + Statistics {} } +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +static CUR_CONSOLE: InitStateLock<&'static (dyn interface::All + Sync)> = + InitStateLock::new(&null_console::NULL_CONSOLE); + //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- +use synchronization::{interface::ReadWriteEx, InitStateLock}; + +/// Register a new console. +pub fn register_console(new_console: &'static (dyn interface::All + Sync)) { + CUR_CONSOLE.write(|con| *con = new_console); +} -/// Return a reference to the console. +/// Return a reference to the currently registered console. /// /// This is the global console used by all printing macros. pub fn console() -> &'static dyn interface::All { - bsp::console::console() + CUR_CONSOLE.read(|con| *con) } diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/console/null_console.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/console/null_console.rs new file mode 100644 index 00000000..2c64d499 --- /dev/null +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/console/null_console.rs @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2022 Andre Richter + +//! Null console. + +use super::interface; +use core::fmt; + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +pub struct NullConsole; + +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +pub static NULL_CONSOLE: NullConsole = NullConsole {}; + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +impl interface::Write for NullConsole { + fn write_char(&self, _c: char) {} + + fn write_fmt(&self, _args: fmt::Arguments) -> fmt::Result { + fmt::Result::Ok(()) + } + + fn flush(&self) {} +} + +impl interface::Read for NullConsole { + fn clear_rx(&self) {} +} + +impl interface::Statistics for NullConsole {} +impl interface::All for NullConsole {} diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/driver.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/driver.rs index c39e5eaf..18066c31 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/driver.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/driver.rs @@ -4,6 +4,26 @@ //! Driver support. +use crate::{ + exception, info, + synchronization::{interface::ReadWriteEx, InitStateLock}, +}; +use core::fmt; + +//-------------------------------------------------------------------------------------------------- +// Private Definitions +//-------------------------------------------------------------------------------------------------- + +const NUM_DRIVERS: usize = 5; + +struct DriverManagerInner +where + T: 'static, +{ + next_index: usize, + descriptors: [Option>; NUM_DRIVERS], +} + //-------------------------------------------------------------------------------------------------- // Public Definitions //-------------------------------------------------------------------------------------------------- @@ -12,6 +32,9 @@ pub mod interface { /// Device Driver functions. pub trait DeviceDriver { + /// Different interrupt controllers might use different types for IRQ number. + type IRQNumberType: super::fmt::Display; + /// Return a compatibility string for identifying the driver. fn compatible(&self) -> &'static str; @@ -24,34 +47,175 @@ pub mod interface { Ok(()) } - /// Called by the kernel to register and enable the device's IRQ handlers, if any. + /// Called by the kernel to register and enable the device's IRQ handler. /// /// Rust's type system will prevent a call to this function unless the calling instance /// itself has static lifetime. - fn register_and_enable_irq_handler(&'static self) -> Result<(), &'static str> { - Ok(()) + fn register_and_enable_irq_handler( + &'static self, + irq_number: &Self::IRQNumberType, + ) -> Result<(), &'static str> { + panic!( + "Attempt to enable IRQ {} for device {}, but driver does not support this", + irq_number, + self.compatible() + ) + } + } +} + +/// Tpye to be used as an optional callback after a driver's init() has run. +pub type DeviceDriverPostInitCallback = unsafe fn() -> Result<(), &'static str>; + +/// A descriptor for device drivers. +#[derive(Copy, Clone)] +pub struct DeviceDriverDescriptor +where + T: 'static, +{ + device_driver: &'static (dyn interface::DeviceDriver + Sync), + post_init_callback: Option, + irq_number: Option, +} + +/// Provides device driver management functions. +pub struct DriverManager +where + T: 'static, +{ + inner: InitStateLock>, +} + +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +static DRIVER_MANAGER: DriverManager = DriverManager::new(); + +//-------------------------------------------------------------------------------------------------- +// Private Code +//-------------------------------------------------------------------------------------------------- + +impl DriverManagerInner +where + T: 'static + Copy, +{ + /// Create an instance. + pub const fn new() -> Self { + Self { + next_index: 0, + descriptors: [None; NUM_DRIVERS], + } + } +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +impl DeviceDriverDescriptor { + /// Create an instance. + pub fn new( + device_driver: &'static (dyn interface::DeviceDriver + Sync), + post_init_callback: Option, + irq_number: Option, + ) -> Self { + Self { + device_driver, + post_init_callback, + irq_number, + } + } +} + +/// Return a reference to the global DriverManager. +pub fn driver_manager() -> &'static DriverManager { + &DRIVER_MANAGER +} + +impl DriverManager +where + T: fmt::Display + Copy, +{ + /// Create an instance. + pub const fn new() -> Self { + Self { + inner: InitStateLock::new(DriverManagerInner::new()), } } - /// Device driver management functions. + /// Register a device driver with the kernel. + pub fn register_driver(&self, descriptor: DeviceDriverDescriptor) { + self.inner.write(|inner| { + inner.descriptors[inner.next_index] = Some(descriptor); + inner.next_index += 1; + }) + } + + /// Helper for iterating over registered drivers. + fn for_each_descriptor<'a>(&'a self, f: impl FnMut(&'a DeviceDriverDescriptor)) { + self.inner.read(|inner| { + inner + .descriptors + .iter() + .filter_map(|x| x.as_ref()) + .for_each(f) + }) + } + + /// Fully initialize all drivers and their interrupts handlers. /// - /// The `BSP` is supposed to supply one global instance. - pub trait DriverManager { - /// Return a slice of references to all `BSP`-instantiated drivers. - /// - /// # Safety - /// - /// - The order of devices is the order in which `DeviceDriver::init()` is called. - fn all_device_drivers(&self) -> &[&'static (dyn DeviceDriver + Sync)]; + /// # Safety + /// + /// - During init, drivers might do stuff with system-wide impact. + pub unsafe fn init_drivers_and_irqs(&self) { + self.for_each_descriptor(|descriptor| { + // 1. Initialize driver. + if let Err(x) = descriptor.device_driver.init() { + panic!( + "Error initializing driver: {}: {}", + descriptor.device_driver.compatible(), + x + ); + } - /// Initialization code that runs after driver init. - /// - /// For example, device driver code that depends on other drivers already being online. - fn post_device_driver_init(&self); + // 2. Call corresponding post init callback. + if let Some(callback) = &descriptor.post_init_callback { + if let Err(x) = callback() { + panic!( + "Error during driver post-init callback: {}: {}", + descriptor.device_driver.compatible(), + x + ); + } + } + }); + + // 3. After all post-init callbacks were done, the interrupt controller should be + // registered and functional. So let drivers register with it now. + self.for_each_descriptor(|descriptor| { + if let Some(irq_number) = &descriptor.irq_number { + if let Err(x) = descriptor + .device_driver + .register_and_enable_irq_handler(irq_number) + { + panic!( + "Error during driver interrupt handler registration: {}: {}", + descriptor.device_driver.compatible(), + x + ); + } + } + }); + } + + /// Enumerate all registered device drivers. + pub fn enumerate(&self) { + let mut i: usize = 1; + self.for_each_descriptor(|descriptor| { + info!(" {}. {}", i, descriptor.device_driver.compatible()); - /// Minimal code needed to bring up the console in QEMU (for testing only). This is often - /// less steps than on real hardware due to QEMU's abstractions. - #[cfg(feature = "test_build")] - fn qemu_bring_up_console(&self); + i += 1; + }); } } diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/exception/asynchronous.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/exception/asynchronous.rs index d55ce642..c1f2a27b 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/exception/asynchronous.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/exception/asynchronous.rs @@ -7,9 +7,10 @@ #[cfg(target_arch = "aarch64")] #[path = "../_arch/aarch64/exception/asynchronous.rs"] mod arch_asynchronous; +mod null_irq_manager; -use crate::bsp; -use core::{fmt, marker::PhantomData}; +use crate::{bsp, synchronization}; +use core::marker::PhantomData; //-------------------------------------------------------------------------------------------------- // Architectural Public Reexports @@ -23,14 +24,23 @@ pub use arch_asynchronous::{ // Public Definitions //-------------------------------------------------------------------------------------------------- +/// Interrupt number as defined by the BSP. +pub type IRQNumber = bsp::exception::asynchronous::IRQNumber; + /// Interrupt descriptor. #[derive(Copy, Clone)] -pub struct IRQDescriptor { +pub struct IRQHandlerDescriptor +where + T: Copy, +{ + /// The IRQ number. + number: T, + /// Descriptive name. - pub name: &'static str, + name: &'static str, /// Reference to handler trait object. - pub handler: &'static (dyn interface::IRQHandler + Sync), + handler: &'static (dyn interface::IRQHandler + Sync), } /// IRQContext token. @@ -60,17 +70,16 @@ pub mod interface { /// platform's interrupt controller. pub trait IRQManager { /// The IRQ number type depends on the implementation. - type IRQNumberType; + type IRQNumberType: Copy; /// Register a handler. fn register_handler( &self, - irq_number: Self::IRQNumberType, - descriptor: super::IRQDescriptor, + irq_handler_descriptor: super::IRQHandlerDescriptor, ) -> Result<(), &'static str>; /// Enable an interrupt in the controller. - fn enable(&self, irq_number: Self::IRQNumberType); + fn enable(&self, irq_number: &Self::IRQNumberType); /// Handle pending interrupts. /// @@ -86,17 +95,55 @@ pub mod interface { ); /// Print list of registered handlers. - fn print_handler(&self); + fn print_handler(&self) {} } } -/// A wrapper type for IRQ numbers with integrated range sanity check. -#[derive(Copy, Clone)] -pub struct IRQNumber(usize); +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +static CUR_IRQ_MANAGER: InitStateLock< + &'static (dyn interface::IRQManager + Sync), +> = InitStateLock::new(&null_irq_manager::NULL_IRQ_MANAGER); //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- +use synchronization::{interface::ReadWriteEx, InitStateLock}; + +impl IRQHandlerDescriptor +where + T: Copy, +{ + /// Create an instance. + pub const fn new( + number: T, + name: &'static str, + handler: &'static (dyn interface::IRQHandler + Sync), + ) -> Self { + Self { + number, + name, + handler, + } + } + + /// Return the number. + pub const fn number(&self) -> T { + self.number + } + + /// Return the name. + pub const fn name(&self) -> &'static str { + self.name + } + + /// Return the handler. + pub const fn handler(&self) -> &'static (dyn interface::IRQHandler + Sync) { + self.handler + } +} impl<'irq_context> IRQContext<'irq_context> { /// Creates an IRQContext token. @@ -115,29 +162,6 @@ impl<'irq_context> IRQContext<'irq_context> { } } -impl IRQNumber<{ MAX_INCLUSIVE }> { - /// The total number of IRQs this type supports. - pub const NUM_TOTAL: usize = MAX_INCLUSIVE + 1; - - /// Creates a new instance if number <= MAX_INCLUSIVE. - pub const fn new(number: usize) -> Self { - assert!(number <= MAX_INCLUSIVE); - - Self(number) - } - - /// Return the wrapped number. - pub const fn get(self) -> usize { - self.0 - } -} - -impl fmt::Display for IRQNumber<{ MAX_INCLUSIVE }> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}", self.0) - } -} - /// Executes the provided closure while IRQs are masked on the executing core. /// /// While the function temporarily changes the HW state of the executing core, it restores it to the @@ -151,9 +175,16 @@ pub fn exec_with_irq_masked(f: impl FnOnce() -> T) -> T { ret } -/// Return a reference to the IRQ manager. +/// Register a new IRQ manager. +pub fn register_irq_manager( + new_manager: &'static (dyn interface::IRQManager + Sync), +) { + CUR_IRQ_MANAGER.write(|manager| *manager = new_manager); +} + +/// Return a reference to the currently registered IRQ manager. /// /// This is the IRQ manager used by the architectural interrupt handling code. -pub fn irq_manager() -> &'static dyn interface::IRQManager { - bsp::exception::asynchronous::irq_manager() +pub fn irq_manager() -> &'static dyn interface::IRQManager { + CUR_IRQ_MANAGER.read(|manager| *manager) } diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/exception/asynchronous/null_irq_manager.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/exception/asynchronous/null_irq_manager.rs new file mode 100644 index 00000000..438f9649 --- /dev/null +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/exception/asynchronous/null_irq_manager.rs @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2022 Andre Richter + +//! Null IRQ Manager. + +use super::{interface, IRQContext, IRQHandlerDescriptor}; + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +pub struct NullIRQManager; + +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +pub static NULL_IRQ_MANAGER: NullIRQManager = NullIRQManager {}; + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +impl interface::IRQManager for NullIRQManager { + type IRQNumberType = super::IRQNumber; + + fn register_handler( + &self, + _descriptor: IRQHandlerDescriptor, + ) -> Result<(), &'static str> { + panic!("No IRQ Manager registered yet"); + } + + fn enable(&self, _irq_number: &Self::IRQNumberType) { + panic!("No IRQ Manager registered yet"); + } + + fn handle_pending_irqs<'irq_context>(&'irq_context self, _ic: &IRQContext<'irq_context>) { + panic!("No IRQ Manager registered yet"); + } +} diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/lib.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/lib.rs index 194e2455..93b863d7 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/lib.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/lib.rs @@ -183,10 +183,8 @@ pub fn test_runner(tests: &[&test_types::UnitTest]) { #[cfg(test)] #[no_mangle] unsafe fn kernel_init() -> ! { - use driver::interface::DriverManager; - exception::handling_init(); - bsp::driver::driver_manager().qemu_bring_up_console(); + bsp::driver::qemu_bring_up_console(); test_main(); diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/main.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/main.rs index 0f72d17f..d3bdf394 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/main.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/main.rs @@ -13,7 +13,7 @@ #![no_main] #![no_std] -use libkernel::{bsp, cpu, driver, exception, info, memory, state, time, warn}; +use libkernel::{bsp, cpu, driver, exception, info, memory, state, time}; /// Early init code. /// @@ -26,7 +26,6 @@ use libkernel::{bsp, cpu, driver, exception, info, memory, state, time, warn}; /// IRQSafeNullLocks instead of spinlocks), will fail to work (properly) on the RPi SoCs. #[no_mangle] unsafe fn kernel_init() -> ! { - use driver::interface::DriverManager; use memory::mmu::interface::MMU; exception::handling_init(); @@ -35,21 +34,14 @@ unsafe fn kernel_init() -> ! { panic!("MMU: {}", string); } - for i in bsp::driver::driver_manager().all_device_drivers().iter() { - if let Err(x) = i.init() { - panic!("Error loading driver: {}: {}", i.compatible(), x); - } - } - bsp::driver::driver_manager().post_device_driver_init(); - // println! is usable from here on. - - // Let device drivers register and enable their handlers with the interrupt controller. - for i in bsp::driver::driver_manager().all_device_drivers() { - if let Err(msg) = i.register_and_enable_irq_handler() { - warn!("Error registering IRQ handler: {}", msg); - } + // Initialize the BSP driver subsystem. + if let Err(x) = bsp::driver::init() { + panic!("Error initializing BSP driver subsystem: {}", x); } + // Initialize all device drivers. + driver::driver_manager().init_drivers_and_irqs(); + // Unmask interrupts on the boot CPU core. exception::asynchronous::local_irq_unmask(); @@ -62,9 +54,6 @@ unsafe fn kernel_init() -> ! { /// The main function running after the early init. fn kernel_main() -> ! { - use driver::interface::DriverManager; - use exception::asynchronous::interface::IRQManager; - info!("{}", libkernel::version()); info!("Booting on: {}", bsp::board_name()); @@ -83,16 +72,10 @@ fn kernel_main() -> ! { ); info!("Drivers loaded:"); - for (i, driver) in bsp::driver::driver_manager() - .all_device_drivers() - .iter() - .enumerate() - { - info!(" {}. {}", i + 1, driver.compatible()); - } + driver::driver_manager().enumerate(); info!("Registered IRQ handlers:"); - bsp::exception::asynchronous::irq_manager().print_handler(); + exception::asynchronous::irq_manager().print_handler(); info!("Echoing input now"); cpu::wait_forever(); diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/tests/00_console_sanity.rs b/13_exceptions_part2_peripheral_IRQs/kernel/tests/00_console_sanity.rs index e12a711f..69313428 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/tests/00_console_sanity.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/tests/00_console_sanity.rs @@ -11,15 +11,14 @@ /// Console tests should time out on the I/O harness in case of panic. mod panic_wait_forever; -use libkernel::{bsp, console, cpu, driver, exception, print}; +use libkernel::{bsp, console, cpu, exception, print}; #[no_mangle] unsafe fn kernel_init() -> ! { use console::console; - use driver::interface::DriverManager; exception::handling_init(); - bsp::driver::driver_manager().qemu_bring_up_console(); + bsp::driver::qemu_bring_up_console(); // Handshake assert_eq!(console().read_char(), 'A'); diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/tests/01_timer_sanity.rs b/13_exceptions_part2_peripheral_IRQs/kernel/tests/01_timer_sanity.rs index a0eb732b..b86016b6 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/tests/01_timer_sanity.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/tests/01_timer_sanity.rs @@ -11,15 +11,13 @@ #![test_runner(libkernel::test_runner)] use core::time::Duration; -use libkernel::{bsp, cpu, driver, exception, time}; +use libkernel::{bsp, cpu, exception, time}; use test_macros::kernel_test; #[no_mangle] unsafe fn kernel_init() -> ! { - use driver::interface::DriverManager; - exception::handling_init(); - bsp::driver::driver_manager().qemu_bring_up_console(); + bsp::driver::qemu_bring_up_console(); // Depending on CPU arch, some timer bring-up code could go here. Not needed for the RPi. diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/tests/02_exception_sync_page_fault.rs b/13_exceptions_part2_peripheral_IRQs/kernel/tests/02_exception_sync_page_fault.rs index 62908377..46501960 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/tests/02_exception_sync_page_fault.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/tests/02_exception_sync_page_fault.rs @@ -17,15 +17,14 @@ /// or indirectly. mod panic_exit_success; -use libkernel::{bsp, cpu, driver, exception, info, memory, println}; +use libkernel::{bsp, cpu, exception, info, memory, println}; #[no_mangle] unsafe fn kernel_init() -> ! { - use driver::interface::DriverManager; use memory::mmu::interface::MMU; exception::handling_init(); - bsp::driver::driver_manager().qemu_bring_up_console(); + bsp::driver::qemu_bring_up_console(); // This line will be printed as the test header. println!("Testing synchronous exception handling by causing a page fault"); diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/tests/03_exception_restore_sanity.rs b/13_exceptions_part2_peripheral_IRQs/kernel/tests/03_exception_restore_sanity.rs index 3f4eae79..cba9285f 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/tests/03_exception_restore_sanity.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/tests/03_exception_restore_sanity.rs @@ -12,7 +12,7 @@ mod panic_wait_forever; use core::arch::asm; -use libkernel::{bsp, cpu, driver, exception, info, memory, println}; +use libkernel::{bsp, cpu, exception, info, memory, println}; #[inline(never)] fn nested_system_call() { @@ -30,11 +30,10 @@ fn nested_system_call() { #[no_mangle] unsafe fn kernel_init() -> ! { - use driver::interface::DriverManager; use memory::mmu::interface::MMU; exception::handling_init(); - bsp::driver::driver_manager().qemu_bring_up_console(); + bsp::driver::qemu_bring_up_console(); // This line will be printed as the test header. println!("Testing exception restore"); diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/tests/04_exception_irq_sanity.rs b/13_exceptions_part2_peripheral_IRQs/kernel/tests/04_exception_irq_sanity.rs index 9deac6cc..8f2b924e 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/tests/04_exception_irq_sanity.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/tests/04_exception_irq_sanity.rs @@ -10,13 +10,12 @@ #![reexport_test_harness_main = "test_main"] #![test_runner(libkernel::test_runner)] -use libkernel::{bsp, cpu, driver, exception}; +use libkernel::{bsp, cpu, exception}; use test_macros::kernel_test; #[no_mangle] unsafe fn kernel_init() -> ! { - use driver::interface::DriverManager; - bsp::driver::driver_manager().qemu_bring_up_console(); + bsp::driver::qemu_bring_up_console(); exception::handling_init(); exception::asynchronous::local_irq_unmask(); diff --git a/14_virtual_mem_part2_mmio_remap/Makefile b/14_virtual_mem_part2_mmio_remap/Makefile index 670c30c4..2d480119 100644 --- a/14_virtual_mem_part2_mmio_remap/Makefile +++ b/14_virtual_mem_part2_mmio_remap/Makefile @@ -291,7 +291,7 @@ test_boot: $(KERNEL_BIN) ## Helpers for unit and integration test targets ##------------------------------------------------------------------------------ define KERNEL_TEST_RUNNER - #!/usr/bin/env bash +#!/usr/bin/env bash # The cargo test runner seems to change into the crate under test's directory. Therefore, ensure # this script executes from the root. diff --git a/14_virtual_mem_part2_mmio_remap/README.md b/14_virtual_mem_part2_mmio_remap/README.md index c0db9938..61117358 100644 --- a/14_virtual_mem_part2_mmio_remap/README.md +++ b/14_virtual_mem_part2_mmio_remap/README.md @@ -257,81 +257,48 @@ static mut INTERRUPT_CONTROLLER: MaybeUninit static mut INTERRUPT_CONTROLLER: MaybeUninit = MaybeUninit::uninit(); ``` -`BSPDriverManager` implements the new `instantiate_drivers()` interface function, which will be -called early during `kernel_init()`, short after virtual memory has been activated: +Accordingly, new dedicated `instantiate_xyz()` functions have been added, which will be called by +the corresponding `driver_xyz()` functions. Here is an example for the `UART`: ```rust -unsafe fn instantiate_drivers(&self) -> Result<(), &'static str> { - if self.init_done.load(Ordering::Relaxed) { - return Err("Drivers already instantiated"); - } - - self.instantiate_uart()?; - self.instantiate_gpio()?; - self.instantiate_interrupt_controller()?; +/// This must be called only after successful init of the memory subsystem. +unsafe fn instantiate_uart() -> Result<(), &'static str> { + let mmio_descriptor = MMIODescriptor::new(mmio::PL011_UART_START, mmio::PL011_UART_SIZE); + let virt_addr = + memory::mmu::kernel_map_mmio(device_driver::PL011Uart::COMPATIBLE, &mmio_descriptor)?; - self.register_drivers(); + PL011_UART.write(device_driver::PL011Uart::new(virt_addr)); - self.init_done.store(true, Ordering::Relaxed); Ok(()) } ``` -As can be seen, for each driver, this `BSP` code calls a dedicated instantiation function. In this -tutorial text, only the `UART` will be discussed in detail: - ```rust -unsafe fn instantiate_uart(&self) -> Result<(), &'static str> { - let mmio_descriptor = MMIODescriptor::new(mmio::PL011_UART_START, mmio::PL011_UART_SIZE); - let virt_addr = - memory::mmu::kernel_map_mmio(device_driver::PL011Uart::COMPATIBLE, &mmio_descriptor)?; +/// Function needs to ensure that driver registration happens only after correct instantiation. +unsafe fn driver_uart() -> Result<(), &'static str> { + instantiate_uart()?; - // This is safe to do, because it is only called from the init'ed instance itself. - fn uart_post_init() { - console::register_console(unsafe { PL011_UART.assume_init_ref() }); - } - - PL011_UART.write(device_driver::PL011Uart::new( - virt_addr, - exception::asynchronous::irq_map::PL011_UART, - uart_post_init, - )); + let uart_descriptor = generic_driver::DeviceDriverDescriptor::new( + PL011_UART.assume_init_ref(), + Some(post_init_uart), + Some(exception::asynchronous::irq_map::PL011_UART), + ); + generic_driver::driver_manager().register_driver(uart_descriptor); Ok(()) } ``` -A couple of things are happening here. First, an `MMIODescriptor` is created and then used to remap -the MMIO region using `memory::mmu::kernel_map_mmio()`. This function will be discussed in detail in -the next chapter. What's important for now is that it returns the new `Virtual Address` of the -remapped MMIO region. The constructor of the `UART` driver now also expects a virtual address. +The code shows that an `MMIODescriptor` is created first, and then used to remap the MMIO region +using `memory::mmu::kernel_map_mmio()`. This function will be discussed in detail in the next +chapter. What's important for now is that it returns the new `Virtual Address` of the remapped MMIO +region. The constructor of the `UART` driver now also expects a virtual address. Next, a new instance of the `PL011Uart` driver is created, and written into the `PL011_UART` global variable (remember, it is defined as `MaybeUninit = MaybeUninit::uninit()`). Meaning, after this line of code, `PL011_UART` is properly initialized. - -Another new feature is the function `uart_post_init()`, which is supplied to the UART constructor. -This is a callback that will be called by the UART driver when it concludes its `init()` function -(remember that the driver's init functions are called from `kernel_init()`). This callback, in turn, -registers the `PL011_UART` as the new console of the kernel. - -A look into `src/console.rs` should make clear what is happening. The classic `console::console()` -now dynamically points to whoever registered itself using the `console::register_console()` -function, instead of using a hardcoded static reference (from the `BSP`). This has been introduced -to accommodate the run-time instantiation of the device drivers (the same feature has been -implemented for the `IRQManager` as well). Until `console::register_console()` has been called for -the first time, an instance of the newly introduced `NullConsole` is used as the default. -`NullConsole` implements all the console traits, but does nothing. It discards outputs, and returns -dummy input. For example, should one of the printing macros be called before the UART driver has -been instantiated and registered, the kernel does not need to crash because the driver is not -brought up yet. Instead, it can just discard the output. With this new scheme of things, it is -possible to safely switch global references like the UART or the IRQ Manager at runtime. - -That all the post-driver-init work has now been moved to callbacks is motivated by the idea that -this fully enables a driver once it has concluded its `init()` function, and not only after all the -drivers have been init'ed and then the post-init code would be called, as earlier. In our example, -printing through the UART will now be available already before the interrupt controller driver runs -its init function. +Only then, the driver is registered with the kernel and thus becomes accessible for the first time. +This ensures that nobody can use the UART before its memory has been initialized properly. ### MMIO Virtual Address Allocation @@ -924,31 +891,18 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/arm/g diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/arm/gicv2.rs 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/arm/gicv2.rs --- 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/arm/gicv2.rs +++ 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/arm/gicv2.rs -@@ -79,7 +79,12 @@ - mod gicc; - mod gicd; +@@ -81,7 +81,9 @@ --use crate::{bsp, cpu, driver, exception, synchronization, synchronization::InitStateLock}; -+use crate::{ -+ bsp, cpu, driver, exception, + use crate::{ + bsp::{self, device_driver::common::BoundedUsize}, +- cpu, driver, exception, synchronization, ++ cpu, driver, exception, + memory::{Address, Virtual}, + synchronization, -+ synchronization::InitStateLock, -+}; - - //-------------------------------------------------------------------------------------------------- - // Private Definitions -@@ -104,6 +109,9 @@ - - /// Stores registered IRQ handlers. Writable only during kernel init. RO afterwards. - handler_table: InitStateLock, -+ -+ /// Callback to be invoked after successful init. -+ post_init_callback: fn(), - } + synchronization::InitStateLock, + }; - //-------------------------------------------------------------------------------------------------- -@@ -120,11 +128,16 @@ +@@ -125,7 +127,10 @@ /// # Safety /// /// - The user must ensure to provide a correct MMIO start address. @@ -956,49 +910,29 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/arm/g + pub const unsafe fn new( + gicd_mmio_start_addr: Address, + gicc_mmio_start_addr: Address, -+ post_init_callback: fn(), + ) -> Self { Self { gicd: gicd::GICD::new(gicd_mmio_start_addr), gicc: gicc::GICC::new(gicc_mmio_start_addr), - handler_table: InitStateLock::new([None; IRQNumber::NUM_TOTAL]), -+ post_init_callback, - } - } - } -@@ -147,6 +160,8 @@ - self.gicc.priority_accept_all(); - self.gicc.enable(); - -+ (self.post_init_callback)(); -+ - Ok(()) - } - } diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs --- 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs +++ 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs -@@ -5,7 +5,10 @@ +@@ -5,8 +5,12 @@ //! GPIO Driver. use crate::{ -- bsp::device_driver::common::MMIODerefWrapper, driver, synchronization, +- bsp::device_driver::common::MMIODerefWrapper, driver, exception::asynchronous::IRQNumber, +- synchronization, synchronization::IRQSafeNullLock, + bsp::device_driver::common::MMIODerefWrapper, + driver, ++ exception::asynchronous::IRQNumber, + memory::{Address, Virtual}, + synchronization, - synchronization::IRQSafeNullLock, ++ synchronization::IRQSafeNullLock, }; use tock_registers::{ -@@ -119,6 +122,7 @@ - /// Representation of the GPIO HW. - pub struct GPIO { - inner: IRQSafeNullLock, -+ post_init_callback: fn(), - } - - //-------------------------------------------------------------------------------------------------- + interfaces::{ReadWriteable, Writeable}, @@ -131,7 +135,7 @@ /// # Safety /// @@ -1008,29 +942,15 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/b Self { registers: Registers::new(mmio_start_addr), } -@@ -198,9 +202,10 @@ +@@ -198,7 +202,7 @@ /// # Safety /// /// - The user must ensure to provide a correct MMIO start address. - pub const unsafe fn new(mmio_start_addr: usize) -> Self { -+ pub const unsafe fn new(mmio_start_addr: Address, post_init_callback: fn()) -> Self { ++ pub const unsafe fn new(mmio_start_addr: Address) -> Self { Self { inner: IRQSafeNullLock::new(GPIOInner::new(mmio_start_addr)), -+ post_init_callback, } - } - -@@ -219,4 +224,10 @@ - fn compatible(&self) -> &'static str { - Self::COMPATIBLE - } -+ -+ unsafe fn init(&self) -> Result<(), &'static str> { -+ (self.post_init_callback)(); -+ -+ Ok(()) -+ } - } diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs --- 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs @@ -1046,7 +966,7 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/b synchronization::{IRQSafeNullLock, InitStateLock}, }; use tock_registers::{ -@@ -78,7 +80,7 @@ +@@ -79,7 +81,7 @@ /// # Safety /// /// - The user must ensure to provide a correct MMIO start address. @@ -1059,82 +979,36 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/b diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs --- 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs +++ 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs -@@ -6,7 +6,10 @@ - - mod peripheral_ic; - --use crate::{driver, exception}; -+use crate::{ -+ driver, exception, +@@ -10,6 +10,7 @@ + bsp::device_driver::common::BoundedUsize, + driver, + exception::{self, asynchronous::IRQHandlerDescriptor}, + memory::{Address, Virtual}, -+}; - - //-------------------------------------------------------------------------------------------------- - // Private Definitions -@@ -37,6 +40,7 @@ - /// Representation of the Interrupt Controller. - pub struct InterruptController { - periph: peripheral_ic::PeripheralIC, -+ post_init_callback: fn(), - } + }; + use core::fmt; - //-------------------------------------------------------------------------------------------------- -@@ -79,9 +83,13 @@ +@@ -91,7 +92,7 @@ /// # Safety /// /// - The user must ensure to provide a correct MMIO start address. - pub const unsafe fn new(periph_mmio_start_addr: usize) -> Self { -+ pub const unsafe fn new( -+ periph_mmio_start_addr: Address, -+ post_init_callback: fn(), -+ ) -> Self { ++ pub const unsafe fn new(periph_mmio_start_addr: Address) -> Self { Self { periph: peripheral_ic::PeripheralIC::new(periph_mmio_start_addr), -+ post_init_callback, } - } - } -@@ -94,6 +102,12 @@ - fn compatible(&self) -> &'static str { - Self::COMPATIBLE - } -+ -+ unsafe fn init(&self) -> Result<(), &'static str> { -+ (self.post_init_callback)(); -+ -+ Ok(()) -+ } - } - - impl exception::asynchronous::interface::IRQManager for InterruptController { diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs --- 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs +++ 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs -@@ -10,8 +10,12 @@ - //! - - - use crate::{ -- bsp, bsp::device_driver::common::MMIODerefWrapper, console, cpu, driver, exception, -- synchronization, synchronization::IRQSafeNullLock, -+ bsp, -+ bsp::device_driver::common::MMIODerefWrapper, -+ console, cpu, driver, exception, +@@ -13,6 +13,7 @@ + bsp::device_driver::common::MMIODerefWrapper, + console, cpu, driver, + exception::{self, asynchronous::IRQNumber}, + memory::{Address, Virtual}, -+ synchronization, -+ synchronization::IRQSafeNullLock, + synchronization, + synchronization::IRQSafeNullLock, }; - use core::fmt; - use tock_registers::{ -@@ -230,6 +234,7 @@ - pub struct PL011Uart { - inner: IRQSafeNullLock, - irq_number: bsp::device_driver::IRQNumber, -+ post_init_callback: fn(), - } - - //-------------------------------------------------------------------------------------------------- -@@ -242,7 +247,7 @@ +@@ -244,7 +245,7 @@ /// # Safety /// /// - The user must ensure to provide a correct MMIO start address. @@ -1143,32 +1017,15 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/b Self { registers: Registers::new(mmio_start_addr), chars_written: 0, -@@ -393,13 +398,16 @@ +@@ -395,7 +396,7 @@ /// # Safety /// /// - The user must ensure to provide a correct MMIO start address. -+ /// - The user must ensure to provide correct IRQ numbers. - pub const unsafe fn new( -- mmio_start_addr: usize, -+ mmio_start_addr: Address, - irq_number: bsp::device_driver::IRQNumber, -+ post_init_callback: fn(), - ) -> Self { +- pub const unsafe fn new(mmio_start_addr: usize) -> Self { ++ pub const unsafe fn new(mmio_start_addr: Address) -> Self { Self { inner: IRQSafeNullLock::new(PL011UartInner::new(mmio_start_addr)), - irq_number, -+ post_init_callback, } - } - } -@@ -416,6 +424,7 @@ - - unsafe fn init(&self) -> Result<(), &'static str> { - self.inner.lock(|inner| inner.init()); -+ (self.post_init_callback)(); - - Ok(()) - } diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/common.rs 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/common.rs --- 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/common.rs @@ -1178,7 +1035,7 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/commo //! Common device driver code. +use crate::memory::{Address, Virtual}; - use core::{marker::PhantomData, ops}; + use core::{fmt, marker::PhantomData, ops}; //-------------------------------------------------------------------------------------------------- @@ -11,7 +12,7 @@ @@ -1190,7 +1047,7 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/commo phantom: PhantomData T>, } -@@ -21,7 +22,7 @@ +@@ -25,7 +26,7 @@ impl MMIODerefWrapper { /// Create an instance. @@ -1199,7 +1056,7 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/commo Self { start_addr, phantom: PhantomData, -@@ -33,6 +34,6 @@ +@@ -37,7 +38,7 @@ type Target = T; fn deref(&self) -> &Self::Target { @@ -1208,265 +1065,180 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/commo } } -diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/console.rs 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/console.rs ---- 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/console.rs -+++ 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/console.rs -@@ -1,16 +0,0 @@ --// SPDX-License-Identifier: MIT OR Apache-2.0 --// --// Copyright (c) 2018-2022 Andre Richter -- --//! BSP console facilities. -- --use crate::console; -- --//-------------------------------------------------------------------------------------------------- --// Public Code --//-------------------------------------------------------------------------------------------------- -- --/// Return a reference to the console. --pub fn console() -> &'static dyn console::interface::All { -- &super::driver::PL011_UART --} diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/driver.rs 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/driver.rs --- 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/driver.rs +++ 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/driver.rs -@@ -5,7 +5,16 @@ - //! BSP driver support. - - use super::{exception, memory::map::mmio}; --use crate::{bsp::device_driver, driver}; -+use crate::{ -+ bsp::device_driver, -+ console, driver, exception as generic_exception, memory, +@@ -9,52 +9,109 @@ + bsp::device_driver, + console, driver as generic_driver, + exception::{self as generic_exception}, ++ memory, + memory::mmu::MMIODescriptor, -+ synchronization::{interface::ReadWriteEx, InitStateLock}, +}; +use core::{ + mem::MaybeUninit, + sync::atomic::{AtomicBool, Ordering}, -+}; - - pub use device_driver::IRQNumber; - -@@ -15,35 +24,133 @@ - - /// Device Driver Manager type. - struct BSPDriverManager { -- device_drivers: [&'static (dyn DeviceDriver + Sync); 3], -+ device_drivers: InitStateLock<[Option<&'static (dyn DeviceDriver + Sync)>; NUM_DRIVERS]>, -+ init_done: AtomicBool, - } + }; +-use core::sync::atomic::{AtomicBool, Ordering}; //-------------------------------------------------------------------------------------------------- --// Global instances -+// Public Definitions + // Global instances //-------------------------------------------------------------------------------------------------- --pub(super) static PL011_UART: device_driver::PL011Uart = unsafe { -- device_driver::PL011Uart::new( -- mmio::PL011_UART_START, -- exception::asynchronous::irq_map::PL011_UART, -- ) --}; -+/// The number of active drivers provided by this BSP. -+pub const NUM_DRIVERS: usize = 3; -+ -+//-------------------------------------------------------------------------------------------------- -+// Global instances -+//-------------------------------------------------------------------------------------------------- - +-static PL011_UART: device_driver::PL011Uart = +- unsafe { device_driver::PL011Uart::new(mmio::PL011_UART_START) }; -static GPIO: device_driver::GPIO = unsafe { device_driver::GPIO::new(mmio::GPIO_START) }; +static mut PL011_UART: MaybeUninit = MaybeUninit::uninit(); +static mut GPIO: MaybeUninit = MaybeUninit::uninit(); #[cfg(feature = "bsp_rpi3")] --pub(super) static INTERRUPT_CONTROLLER: device_driver::InterruptController = -- unsafe { device_driver::InterruptController::new(mmio::PERIPHERAL_INTERRUPT_CONTROLLER_START) }; +-static INTERRUPT_CONTROLLER: device_driver::InterruptController = +- unsafe { device_driver::InterruptController::new(mmio::PERIPHERAL_IC_START) }; +static mut INTERRUPT_CONTROLLER: MaybeUninit = + MaybeUninit::uninit(); #[cfg(feature = "bsp_rpi4")] --pub(super) static INTERRUPT_CONTROLLER: device_driver::GICv2 = +-static INTERRUPT_CONTROLLER: device_driver::GICv2 = - unsafe { device_driver::GICv2::new(mmio::GICD_START, mmio::GICC_START) }; +static mut INTERRUPT_CONTROLLER: MaybeUninit = MaybeUninit::uninit(); - static BSP_DRIVER_MANAGER: BSPDriverManager = BSPDriverManager { -- device_drivers: [&PL011_UART, &GPIO, &INTERRUPT_CONTROLLER], -+ device_drivers: InitStateLock::new([None; NUM_DRIVERS]), -+ init_done: AtomicBool::new(false), - }; - //-------------------------------------------------------------------------------------------------- -+// Private Code -+//-------------------------------------------------------------------------------------------------- -+ -+impl BSPDriverManager { -+ unsafe fn instantiate_uart(&self) -> Result<(), &'static str> { -+ let mmio_descriptor = MMIODescriptor::new(mmio::PL011_UART_START, mmio::PL011_UART_SIZE); -+ let virt_addr = -+ memory::mmu::kernel_map_mmio(device_driver::PL011Uart::COMPATIBLE, &mmio_descriptor)?; -+ -+ // This is safe to do, because it is only called from the init'ed instance itself. -+ fn uart_post_init() { -+ console::register_console(unsafe { PL011_UART.assume_init_ref() }); -+ } -+ -+ PL011_UART.write(device_driver::PL011Uart::new( -+ virt_addr, -+ exception::asynchronous::irq_map::PL011_UART, -+ uart_post_init, -+ )); -+ -+ Ok(()) -+ } -+ -+ unsafe fn instantiate_gpio(&self) -> Result<(), &'static str> { -+ let mmio_descriptor = MMIODescriptor::new(mmio::GPIO_START, mmio::GPIO_SIZE); -+ let virt_addr = -+ memory::mmu::kernel_map_mmio(device_driver::GPIO::COMPATIBLE, &mmio_descriptor)?; -+ -+ // This is safe to do, because it is only called from the init'ed instance itself. -+ fn gpio_post_init() { -+ unsafe { GPIO.assume_init_ref().map_pl011_uart() }; -+ } -+ -+ GPIO.write(device_driver::GPIO::new(virt_addr, gpio_post_init)); -+ -+ Ok(()) -+ } -+ -+ #[cfg(feature = "bsp_rpi3")] -+ unsafe fn instantiate_interrupt_controller(&self) -> Result<(), &'static str> { -+ let periph_mmio_descriptor = -+ MMIODescriptor::new(mmio::PERIPHERAL_IC_START, mmio::PERIPHERAL_IC_SIZE); -+ let periph_virt_addr = memory::mmu::kernel_map_mmio( -+ device_driver::InterruptController::COMPATIBLE, -+ &periph_mmio_descriptor, -+ )?; + // Private Code + //-------------------------------------------------------------------------------------------------- + ++/// This must be called only after successful init of the memory subsystem. ++unsafe fn instantiate_uart() -> Result<(), &'static str> { ++ let mmio_descriptor = MMIODescriptor::new(mmio::PL011_UART_START, mmio::PL011_UART_SIZE); ++ let virt_addr = ++ memory::mmu::kernel_map_mmio(device_driver::PL011Uart::COMPATIBLE, &mmio_descriptor)?; + -+ // This is safe to do, because it is only called from the init'ed instance itself. -+ fn interrupt_controller_post_init() { -+ generic_exception::asynchronous::register_irq_manager(unsafe { -+ INTERRUPT_CONTROLLER.assume_init_ref() -+ }); -+ } ++ PL011_UART.write(device_driver::PL011Uart::new(virt_addr)); + -+ INTERRUPT_CONTROLLER.write(device_driver::InterruptController::new( -+ periph_virt_addr, -+ interrupt_controller_post_init, -+ )); ++ Ok(()) ++} + -+ Ok(()) -+ } + /// This must be called only after successful init of the UART driver. +-fn post_init_uart() -> Result<(), &'static str> { +- console::register_console(&PL011_UART); ++unsafe fn post_init_uart() -> Result<(), &'static str> { ++ console::register_console(PL011_UART.assume_init_ref()); + -+ #[cfg(feature = "bsp_rpi4")] -+ unsafe fn instantiate_interrupt_controller(&self) -> Result<(), &'static str> { -+ let gicd_mmio_descriptor = MMIODescriptor::new(mmio::GICD_START, mmio::GICD_SIZE); -+ let gicd_virt_addr = memory::mmu::kernel_map_mmio("GICv2 GICD", &gicd_mmio_descriptor)?; ++ Ok(()) ++} + -+ let gicc_mmio_descriptor = MMIODescriptor::new(mmio::GICC_START, mmio::GICC_SIZE); -+ let gicc_virt_addr = memory::mmu::kernel_map_mmio("GICV2 GICC", &gicc_mmio_descriptor)?; ++/// This must be called only after successful init of the memory subsystem. ++unsafe fn instantiate_gpio() -> Result<(), &'static str> { ++ let mmio_descriptor = MMIODescriptor::new(mmio::GPIO_START, mmio::GPIO_SIZE); ++ let virt_addr = ++ memory::mmu::kernel_map_mmio(device_driver::GPIO::COMPATIBLE, &mmio_descriptor)?; + -+ // This is safe to do, because it is only called from the init'ed instance itself. -+ fn interrupt_controller_post_init() { -+ generic_exception::asynchronous::register_irq_manager(unsafe { -+ INTERRUPT_CONTROLLER.assume_init_ref() -+ }); -+ } ++ GPIO.write(device_driver::GPIO::new(virt_addr)); + + Ok(()) + } + + /// This must be called only after successful init of the GPIO driver. +-fn post_init_gpio() -> Result<(), &'static str> { +- GPIO.map_pl011_uart(); ++unsafe fn post_init_gpio() -> Result<(), &'static str> { ++ GPIO.assume_init_ref().map_pl011_uart(); ++ Ok(()) ++} + -+ INTERRUPT_CONTROLLER.write(device_driver::GICv2::new( -+ gicd_virt_addr, -+ gicc_virt_addr, -+ interrupt_controller_post_init, -+ )); ++/// This must be called only after successful init of the memory subsystem. ++#[cfg(feature = "bsp_rpi3")] ++unsafe fn instantiate_interrupt_controller() -> Result<(), &'static str> { ++ let periph_mmio_descriptor = ++ MMIODescriptor::new(mmio::PERIPHERAL_IC_START, mmio::PERIPHERAL_IC_SIZE); ++ let periph_virt_addr = memory::mmu::kernel_map_mmio( ++ device_driver::InterruptController::COMPATIBLE, ++ &periph_mmio_descriptor, ++ )?; + -+ Ok(()) -+ } ++ INTERRUPT_CONTROLLER.write(device_driver::InterruptController::new(periph_virt_addr)); + -+ unsafe fn register_drivers(&self) { -+ self.device_drivers.write(|drivers| { -+ drivers[0] = Some(PL011_UART.assume_init_ref()); -+ drivers[1] = Some(GPIO.assume_init_ref()); -+ drivers[2] = Some(INTERRUPT_CONTROLLER.assume_init_ref()); -+ }); -+ } ++ Ok(()) +} + -+//-------------------------------------------------------------------------------------------------- - // Public Code - //-------------------------------------------------------------------------------------------------- - -@@ -58,15 +165,34 @@ - use driver::interface::DeviceDriver; - - impl driver::interface::DriverManager for BSPDriverManager { -- fn all_device_drivers(&self) -> &[&'static (dyn DeviceDriver + Sync)] { -- &self.device_drivers[..] -+ unsafe fn instantiate_drivers(&self) -> Result<(), &'static str> { -+ if self.init_done.load(Ordering::Relaxed) { -+ return Err("Drivers already instantiated"); -+ } ++/// This must be called only after successful init of the memory subsystem. ++#[cfg(feature = "bsp_rpi4")] ++unsafe fn instantiate_interrupt_controller() -> Result<(), &'static str> { ++ let gicd_mmio_descriptor = MMIODescriptor::new(mmio::GICD_START, mmio::GICD_SIZE); ++ let gicd_virt_addr = memory::mmu::kernel_map_mmio("GICv2 GICD", &gicd_mmio_descriptor)?; + -+ self.instantiate_uart()?; -+ self.instantiate_gpio()?; -+ self.instantiate_interrupt_controller()?; ++ let gicc_mmio_descriptor = MMIODescriptor::new(mmio::GICC_START, mmio::GICC_SIZE); ++ let gicc_virt_addr = memory::mmu::kernel_map_mmio("GICV2 GICC", &gicc_mmio_descriptor)?; + -+ self.register_drivers(); ++ INTERRUPT_CONTROLLER.write(device_driver::GICv2::new(gicd_virt_addr, gicc_virt_addr)); + -+ self.init_done.store(true, Ordering::Relaxed); -+ Ok(()) - } - -- fn post_device_driver_init(&self) { -- // Configure PL011Uart's output pins. -- GPIO.map_pl011_uart(); -+ fn all_device_drivers(&self) -> [&(dyn DeviceDriver + Sync); NUM_DRIVERS] { -+ self.device_drivers -+ .read(|drivers| drivers.map(|drivers| drivers.unwrap())) - } - - #[cfg(feature = "test_build")] -- fn qemu_bring_up_console(&self) {} -+ fn qemu_bring_up_console(&self) { -+ use crate::cpu; -+ -+ unsafe { -+ self.instantiate_uart() -+ .unwrap_or_else(|_| cpu::qemu_exit_failure()); -+ console::register_console(PL011_UART.assume_init_ref()); -+ }; -+ } + Ok(()) } -diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/exception/asynchronous.rs 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/exception/asynchronous.rs ---- 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/exception/asynchronous.rs -+++ 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/exception/asynchronous.rs -@@ -4,7 +4,7 @@ + /// This must be called only after successful init of the interrupt controller driver. +-fn post_init_interrupt_controller() -> Result<(), &'static str> { +- generic_exception::asynchronous::register_irq_manager(&INTERRUPT_CONTROLLER); ++unsafe fn post_init_interrupt_controller() -> Result<(), &'static str> { ++ generic_exception::asynchronous::register_irq_manager(INTERRUPT_CONTROLLER.assume_init_ref()); - //! BSP asynchronous exception handling. + Ok(()) + } --use crate::{bsp, bsp::driver, exception}; -+use crate::bsp; +-fn driver_uart() -> Result<(), &'static str> { ++/// Function needs to ensure that driver registration happens only after correct instantiation. ++unsafe fn driver_uart() -> Result<(), &'static str> { ++ instantiate_uart()?; ++ + let uart_descriptor = generic_driver::DeviceDriverDescriptor::new( +- &PL011_UART, ++ PL011_UART.assume_init_ref(), + Some(post_init_uart), + Some(exception::asynchronous::irq_map::PL011_UART), + ); +@@ -63,17 +120,26 @@ + Ok(()) + } - //-------------------------------------------------------------------------------------------------- - // Public Definitions -@@ -23,14 +23,3 @@ +-fn driver_gpio() -> Result<(), &'static str> { +- let gpio_descriptor = +- generic_driver::DeviceDriverDescriptor::new(&GPIO, Some(post_init_gpio), None); ++/// Function needs to ensure that driver registration happens only after correct instantiation. ++unsafe fn driver_gpio() -> Result<(), &'static str> { ++ instantiate_gpio()?; ++ ++ let gpio_descriptor = generic_driver::DeviceDriverDescriptor::new( ++ GPIO.assume_init_ref(), ++ Some(post_init_gpio), ++ None, ++ ); + generic_driver::driver_manager().register_driver(gpio_descriptor); + + Ok(()) + } - pub const PL011_UART: IRQNumber = IRQNumber::new(153); +-fn driver_interrupt_controller() -> Result<(), &'static str> { ++/// Function needs to ensure that driver registration happens only after correct instantiation. ++unsafe fn driver_interrupt_controller() -> Result<(), &'static str> { ++ instantiate_interrupt_controller()?; ++ + let interrupt_controller_descriptor = generic_driver::DeviceDriverDescriptor::new( +- &INTERRUPT_CONTROLLER, ++ INTERRUPT_CONTROLLER.assume_init_ref(), + Some(post_init_interrupt_controller), + None, + ); +@@ -109,5 +175,10 @@ + /// than on real hardware due to QEMU's abstractions. + #[cfg(feature = "test_build")] + pub fn qemu_bring_up_console() { +- console::register_console(&PL011_UART); ++ use crate::cpu; ++ ++ unsafe { ++ instantiate_uart().unwrap_or_else(|_| cpu::qemu_exit_failure()); ++ console::register_console(PL011_UART.assume_init_ref()); ++ }; } -- --//-------------------------------------------------------------------------------------------------- --// Public Code --//-------------------------------------------------------------------------------------------------- -- --/// Return a reference to the IRQ manager. --pub fn irq_manager() -> &'static impl exception::asynchronous::interface::IRQManager< -- IRQNumberType = bsp::device_driver::IRQNumber, --> { -- &driver::INTERRUPT_CONTROLLER --} diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/kernel.ld 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/kernel.ld --- 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/kernel.ld @@ -1910,11 +1682,11 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/memory. pub mod mmio { use super::*; -- pub const START: usize = 0x3F00_0000; -- pub const PERIPHERAL_INTERRUPT_CONTROLLER_START: usize = START + 0x0000_B200; -- pub const GPIO_START: usize = START + GPIO_OFFSET; -- pub const PL011_UART_START: usize = START + UART_OFFSET; -- pub const END_INCLUSIVE: usize = 0x4000_FFFF; +- pub const START: usize = 0x3F00_0000; +- pub const PERIPHERAL_IC_START: usize = START + 0x0000_B200; +- pub const GPIO_START: usize = START + GPIO_OFFSET; +- pub const PL011_UART_START: usize = START + UART_OFFSET; +- pub const END_INCLUSIVE: usize = 0x4000_FFFF; + pub const PERIPHERAL_IC_START: Address = Address::new(0x3F00_B200); + pub const PERIPHERAL_IC_SIZE: usize = 0x24; + @@ -2040,18 +1812,6 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/memory. + PageAddress::from(map::END) } -diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi.rs 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi.rs ---- 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi.rs -+++ 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi.rs -@@ -4,7 +4,6 @@ - - //! Top-level BSP file for the Raspberry Pi 3 and 4. - --pub mod console; - pub mod cpu; - pub mod driver; - pub mod exception; - diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/common.rs 14_virtual_mem_part2_mmio_remap/kernel/src/common.rs --- 13_exceptions_part2_peripheral_IRQs/kernel/src/common.rs +++ 14_virtual_mem_part2_mmio_remap/kernel/src/common.rs @@ -2087,242 +1847,6 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/common.rs 14_virtual_me pub const fn size_human_readable_ceil(size: usize) -> (usize, &'static str) { const KIB: usize = 1024; -diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/console/null_console.rs 14_virtual_mem_part2_mmio_remap/kernel/src/console/null_console.rs ---- 13_exceptions_part2_peripheral_IRQs/kernel/src/console/null_console.rs -+++ 14_virtual_mem_part2_mmio_remap/kernel/src/console/null_console.rs -@@ -0,0 +1,41 @@ -+// SPDX-License-Identifier: MIT OR Apache-2.0 -+// -+// Copyright (c) 2022 Andre Richter -+ -+//! Null console. -+ -+use super::interface; -+use core::fmt; -+ -+//-------------------------------------------------------------------------------------------------- -+// Public Definitions -+//-------------------------------------------------------------------------------------------------- -+ -+pub struct NullConsole; -+ -+//-------------------------------------------------------------------------------------------------- -+// Global instances -+//-------------------------------------------------------------------------------------------------- -+ -+pub static NULL_CONSOLE: NullConsole = NullConsole {}; -+ -+//-------------------------------------------------------------------------------------------------- -+// Public Code -+//-------------------------------------------------------------------------------------------------- -+ -+impl interface::Write for NullConsole { -+ fn write_char(&self, _c: char) {} -+ -+ fn write_fmt(&self, _args: fmt::Arguments) -> fmt::Result { -+ fmt::Result::Ok(()) -+ } -+ -+ fn flush(&self) {} -+} -+ -+impl interface::Read for NullConsole { -+ fn clear_rx(&self) {} -+} -+ -+impl interface::Statistics for NullConsole {} -+impl interface::All for NullConsole {} - -diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/console.rs 14_virtual_mem_part2_mmio_remap/kernel/src/console.rs ---- 13_exceptions_part2_peripheral_IRQs/kernel/src/console.rs -+++ 14_virtual_mem_part2_mmio_remap/kernel/src/console.rs -@@ -4,7 +4,9 @@ - - //! System console. - --use crate::bsp; -+mod null_console; -+ -+use crate::synchronization; - - //-------------------------------------------------------------------------------------------------- - // Public Definitions -@@ -55,12 +57,25 @@ - } - - //-------------------------------------------------------------------------------------------------- -+// Global instances -+//-------------------------------------------------------------------------------------------------- -+ -+static CUR_CONSOLE: InitStateLock<&'static (dyn interface::All + Sync)> = -+ InitStateLock::new(&null_console::NULL_CONSOLE); -+ -+//-------------------------------------------------------------------------------------------------- - // Public Code - //-------------------------------------------------------------------------------------------------- -+use synchronization::{interface::ReadWriteEx, InitStateLock}; -+ -+/// Register a new console. -+pub fn register_console(new_console: &'static (dyn interface::All + Sync)) { -+ CUR_CONSOLE.write(|con| *con = new_console); -+} - --/// Return a reference to the console. -+/// Return a reference to the currently registered console. - /// - /// This is the global console used by all printing macros. - pub fn console() -> &'static dyn interface::All { -- bsp::console::console() -+ CUR_CONSOLE.read(|con| *con) - } - -diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/driver.rs 14_virtual_mem_part2_mmio_remap/kernel/src/driver.rs ---- 13_exceptions_part2_peripheral_IRQs/kernel/src/driver.rs -+++ 14_virtual_mem_part2_mmio_remap/kernel/src/driver.rs -@@ -10,6 +10,8 @@ - - /// Driver interfaces. - pub mod interface { -+ use crate::bsp; -+ - /// Device Driver functions. - pub trait DeviceDriver { - /// Return a compatibility string for identifying the driver. -@@ -37,17 +39,15 @@ - /// - /// The `BSP` is supposed to supply one global instance. - pub trait DriverManager { -- /// Return a slice of references to all `BSP`-instantiated drivers. -+ /// Instantiate all drivers. - /// - /// # Safety - /// -- /// - The order of devices is the order in which `DeviceDriver::init()` is called. -- fn all_device_drivers(&self) -> &[&'static (dyn DeviceDriver + Sync)]; -+ /// Must be called before `all_device_drivers`. -+ unsafe fn instantiate_drivers(&self) -> Result<(), &'static str>; - -- /// Initialization code that runs after driver init. -- /// -- /// For example, device driver code that depends on other drivers already being online. -- fn post_device_driver_init(&self); -+ /// Return a slice of references to all `BSP`-instantiated drivers. -+ fn all_device_drivers(&self) -> [&(dyn DeviceDriver + Sync); bsp::driver::NUM_DRIVERS]; - - /// Minimal code needed to bring up the console in QEMU (for testing only). This is often - /// less steps than on real hardware due to QEMU's abstractions. - -diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/exception/asynchronous/null_irq_manager.rs 14_virtual_mem_part2_mmio_remap/kernel/src/exception/asynchronous/null_irq_manager.rs ---- 13_exceptions_part2_peripheral_IRQs/kernel/src/exception/asynchronous/null_irq_manager.rs -+++ 14_virtual_mem_part2_mmio_remap/kernel/src/exception/asynchronous/null_irq_manager.rs -@@ -0,0 +1,44 @@ -+// SPDX-License-Identifier: MIT OR Apache-2.0 -+// -+// Copyright (c) 2022 Andre Richter -+ -+//! Null IRQ Manager. -+ -+use super::{interface, IRQContext, IRQDescriptor}; -+use crate::bsp; -+ -+//-------------------------------------------------------------------------------------------------- -+// Public Definitions -+//-------------------------------------------------------------------------------------------------- -+ -+pub struct NullIRQManager; -+ -+//-------------------------------------------------------------------------------------------------- -+// Global instances -+//-------------------------------------------------------------------------------------------------- -+ -+pub static NULL_IRQ_MANAGER: NullIRQManager = NullIRQManager {}; -+ -+//-------------------------------------------------------------------------------------------------- -+// Public Code -+//-------------------------------------------------------------------------------------------------- -+ -+impl interface::IRQManager for NullIRQManager { -+ type IRQNumberType = bsp::driver::IRQNumber; -+ -+ fn register_handler( -+ &self, -+ _irq_number: Self::IRQNumberType, -+ _descriptor: IRQDescriptor, -+ ) -> Result<(), &'static str> { -+ panic!("No IRQ Manager registered yet"); -+ } -+ -+ fn enable(&self, _irq_number: Self::IRQNumberType) { -+ panic!("No IRQ Manager registered yet"); -+ } -+ -+ fn handle_pending_irqs<'irq_context>(&'irq_context self, _ic: &IRQContext<'irq_context>) { -+ panic!("No IRQ Manager registered yet"); -+ } -+} - -diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/exception/asynchronous.rs 14_virtual_mem_part2_mmio_remap/kernel/src/exception/asynchronous.rs ---- 13_exceptions_part2_peripheral_IRQs/kernel/src/exception/asynchronous.rs -+++ 14_virtual_mem_part2_mmio_remap/kernel/src/exception/asynchronous.rs -@@ -7,8 +7,9 @@ - #[cfg(target_arch = "aarch64")] - #[path = "../_arch/aarch64/exception/asynchronous.rs"] - mod arch_asynchronous; -+mod null_irq_manager; - --use crate::bsp; -+use crate::{bsp, synchronization}; - use core::{fmt, marker::PhantomData}; - - //-------------------------------------------------------------------------------------------------- -@@ -86,7 +87,7 @@ - ); - - /// Print list of registered handlers. -- fn print_handler(&self); -+ fn print_handler(&self) {} - } - } - -@@ -95,8 +96,17 @@ - pub struct IRQNumber(usize); - - //-------------------------------------------------------------------------------------------------- -+// Global instances -+//-------------------------------------------------------------------------------------------------- -+ -+static CUR_IRQ_MANAGER: InitStateLock< -+ &'static (dyn interface::IRQManager + Sync), -+> = InitStateLock::new(&null_irq_manager::NULL_IRQ_MANAGER); -+ -+//-------------------------------------------------------------------------------------------------- - // Public Code - //-------------------------------------------------------------------------------------------------- -+use synchronization::{interface::ReadWriteEx, InitStateLock}; - - impl<'irq_context> IRQContext<'irq_context> { - /// Creates an IRQContext token. -@@ -151,9 +161,17 @@ - ret - } - --/// Return a reference to the IRQ manager. -+/// Register a new IRQ manager. -+pub fn register_irq_manager( -+ new_manager: &'static (dyn interface::IRQManager -+ + Sync), -+) { -+ CUR_IRQ_MANAGER.write(|manager| *manager = new_manager); -+} -+ -+/// Return a reference to the currently registered IRQ manager. - /// - /// This is the IRQ manager used by the architectural interrupt handling code. - pub fn irq_manager() -> &'static dyn interface::IRQManager { -- bsp::exception::asynchronous::irq_manager() -+ CUR_IRQ_MANAGER.read(|manager| *manager) - } - diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/lib.rs 14_virtual_mem_part2_mmio_remap/kernel/src/lib.rs --- 13_exceptions_part2_peripheral_IRQs/kernel/src/lib.rs +++ 14_virtual_mem_part2_mmio_remap/kernel/src/lib.rs @@ -2340,9 +1864,9 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/lib.rs 14_virtual_mem_p #![feature(trait_alias)] #![feature(unchecked_math)] #![no_std] -@@ -186,6 +189,17 @@ - use driver::interface::DriverManager; - +@@ -184,6 +187,17 @@ + #[no_mangle] + unsafe fn kernel_init() -> ! { exception::handling_init(); + + let phys_kernel_tables_base_addr = match memory::mmu::kernel_map_binary() { @@ -2355,19 +1879,19 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/lib.rs 14_virtual_mem_p + } + + memory::mmu::post_enable_init(); - bsp::driver::driver_manager().qemu_bring_up_console(); + bsp::driver::qemu_bring_up_console(); test_main(); diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/main.rs 14_virtual_mem_part2_mmio_remap/kernel/src/main.rs --- 13_exceptions_part2_peripheral_IRQs/kernel/src/main.rs +++ 14_virtual_mem_part2_mmio_remap/kernel/src/main.rs -@@ -27,21 +27,29 @@ +@@ -26,14 +26,19 @@ + /// IRQSafeNullLocks instead of spinlocks), will fail to work (properly) on the RPi SoCs. #[no_mangle] unsafe fn kernel_init() -> ! { - use driver::interface::DriverManager; - use memory::mmu::interface::MMU; - +- exception::handling_init(); - if let Err(string) = memory::mmu::mmu().enable_mmu_and_caching() { @@ -2383,26 +1907,10 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/main.rs 14_virtual_mem_ + memory::mmu::post_enable_init(); + -+ // Instantiate and init all device drivers. -+ if let Err(x) = bsp::driver::driver_manager().instantiate_drivers() { -+ panic!("Error instantiating drivers: {}", x); -+ } - for i in bsp::driver::driver_manager().all_device_drivers().iter() { - if let Err(x) = i.init() { - panic!("Error loading driver: {}: {}", i.compatible(), x); - } - } -- bsp::driver::driver_manager().post_device_driver_init(); -- // println! is usable from here on. - - // Let device drivers register and enable their handlers with the interrupt controller. - for i in bsp::driver::driver_manager().all_device_drivers() { -@@ -63,13 +71,12 @@ - /// The main function running after the early init. - fn kernel_main() -> ! { - use driver::interface::DriverManager; -- use exception::asynchronous::interface::IRQManager; - + // Initialize the BSP driver subsystem. + if let Err(x) = bsp::driver::init() { + panic!("Error initializing BSP driver subsystem: {}", x); +@@ -57,8 +62,8 @@ info!("{}", libkernel::version()); info!("Booting on: {}", bsp::board_name()); @@ -2413,15 +1921,6 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/main.rs 14_virtual_mem_ let (_, privilege_level) = exception::current_privilege_level(); info!("Current privilege level: {}", privilege_level); -@@ -92,7 +99,7 @@ - } - - info!("Registered IRQ handlers:"); -- bsp::exception::asynchronous::irq_manager().print_handler(); -+ exception::asynchronous::irq_manager().print_handler(); - - info!("Echoing input now"); - cpu::wait_forever(); diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/memory/mmu/mapping_record.rs 14_virtual_mem_part2_mmio_remap/kernel/src/memory/mmu/mapping_record.rs --- 13_exceptions_part2_peripheral_IRQs/kernel/src/memory/mmu/mapping_record.rs @@ -3787,17 +3286,16 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/memory.rs 14_virtual_me diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/tests/00_console_sanity.rs 14_virtual_mem_part2_mmio_remap/kernel/tests/00_console_sanity.rs --- 13_exceptions_part2_peripheral_IRQs/kernel/tests/00_console_sanity.rs +++ 14_virtual_mem_part2_mmio_remap/kernel/tests/00_console_sanity.rs -@@ -11,7 +11,7 @@ +@@ -11,13 +11,24 @@ /// Console tests should time out on the I/O harness in case of panic. mod panic_wait_forever; --use libkernel::{bsp, console, cpu, driver, exception, print}; -+use libkernel::{bsp, console, cpu, driver, exception, memory, print}; +-use libkernel::{bsp, console, cpu, exception, print}; ++use libkernel::{bsp, console, cpu, exception, memory, print}; #[no_mangle] unsafe fn kernel_init() -> ! { -@@ -19,6 +19,17 @@ - use driver::interface::DriverManager; + use console::console; exception::handling_init(); + @@ -3811,25 +3309,23 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/tests/00_console_sanity.rs + } + + memory::mmu::post_enable_init(); - bsp::driver::driver_manager().qemu_bring_up_console(); + bsp::driver::qemu_bring_up_console(); // Handshake diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/tests/01_timer_sanity.rs 14_virtual_mem_part2_mmio_remap/kernel/tests/01_timer_sanity.rs --- 13_exceptions_part2_peripheral_IRQs/kernel/tests/01_timer_sanity.rs +++ 14_virtual_mem_part2_mmio_remap/kernel/tests/01_timer_sanity.rs -@@ -11,7 +11,7 @@ +@@ -11,12 +11,23 @@ #![test_runner(libkernel::test_runner)] use core::time::Duration; --use libkernel::{bsp, cpu, driver, exception, time}; -+use libkernel::{bsp, cpu, driver, exception, memory, time}; +-use libkernel::{bsp, cpu, exception, time}; ++use libkernel::{bsp, cpu, exception, memory, time}; use test_macros::kernel_test; #[no_mangle] -@@ -19,6 +19,17 @@ - use driver::interface::DriverManager; - + unsafe fn kernel_init() -> ! { exception::handling_init(); + + let phys_kernel_tables_base_addr = match memory::mmu::kernel_map_binary() { @@ -3842,21 +3338,21 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/tests/01_timer_sanity.rs 14 + } + + memory::mmu::post_enable_init(); - bsp::driver::driver_manager().qemu_bring_up_console(); + bsp::driver::qemu_bring_up_console(); // Depending on CPU arch, some timer bring-up code could go here. Not needed for the RPi. diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/tests/02_exception_sync_page_fault.rs 14_virtual_mem_part2_mmio_remap/kernel/tests/02_exception_sync_page_fault.rs --- 13_exceptions_part2_peripheral_IRQs/kernel/tests/02_exception_sync_page_fault.rs +++ 14_virtual_mem_part2_mmio_remap/kernel/tests/02_exception_sync_page_fault.rs -@@ -22,19 +22,28 @@ +@@ -21,19 +21,27 @@ + #[no_mangle] unsafe fn kernel_init() -> ! { - use driver::interface::DriverManager; - use memory::mmu::interface::MMU; - +- exception::handling_init(); -- bsp::driver::driver_manager().qemu_bring_up_console(); +- bsp::driver::qemu_bring_up_console(); // This line will be printed as the test header. println!("Testing synchronous exception handling by causing a page fault"); @@ -3877,7 +3373,7 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/tests/02_exception_sync_pag } + memory::mmu::post_enable_init(); -+ bsp::driver::driver_manager().qemu_bring_up_console(); ++ bsp::driver::qemu_bring_up_console(); + info!("Writing beyond mapped area to address 9 GiB..."); let big_addr: u64 = 9 * 1024 * 1024 * 1024; @@ -3886,14 +3382,14 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/tests/02_exception_sync_pag diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/tests/03_exception_restore_sanity.rs 14_virtual_mem_part2_mmio_remap/kernel/tests/03_exception_restore_sanity.rs --- 13_exceptions_part2_peripheral_IRQs/kernel/tests/03_exception_restore_sanity.rs +++ 14_virtual_mem_part2_mmio_remap/kernel/tests/03_exception_restore_sanity.rs -@@ -31,19 +31,28 @@ +@@ -30,19 +30,27 @@ + #[no_mangle] unsafe fn kernel_init() -> ! { - use driver::interface::DriverManager; - use memory::mmu::interface::MMU; - +- exception::handling_init(); -- bsp::driver::driver_manager().qemu_bring_up_console(); +- bsp::driver::qemu_bring_up_console(); // This line will be printed as the test header. println!("Testing exception restore"); @@ -3914,7 +3410,7 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/tests/03_exception_restore_ } + memory::mmu::post_enable_init(); -+ bsp::driver::driver_manager().qemu_bring_up_console(); ++ bsp::driver::qemu_bring_up_console(); + info!("Making a dummy system call"); @@ -3923,20 +3419,17 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/tests/03_exception_restore_ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/tests/04_exception_irq_sanity.rs 14_virtual_mem_part2_mmio_remap/kernel/tests/04_exception_irq_sanity.rs --- 13_exceptions_part2_peripheral_IRQs/kernel/tests/04_exception_irq_sanity.rs +++ 14_virtual_mem_part2_mmio_remap/kernel/tests/04_exception_irq_sanity.rs -@@ -10,15 +10,27 @@ +@@ -10,14 +10,25 @@ #![reexport_test_harness_main = "test_main"] #![test_runner(libkernel::test_runner)] --use libkernel::{bsp, cpu, driver, exception}; -+use libkernel::{bsp, cpu, driver, exception, memory}; +-use libkernel::{bsp, cpu, exception}; ++use libkernel::{bsp, cpu, exception, memory}; use test_macros::kernel_test; #[no_mangle] unsafe fn kernel_init() -> ! { - use driver::interface::DriverManager; -- bsp::driver::driver_manager().qemu_bring_up_console(); - - exception::handling_init(); ++ exception::handling_init(); + + let phys_kernel_tables_base_addr = match memory::mmu::kernel_map_binary() { + Err(string) => panic!("Error mapping kernel binary: {}", string), @@ -3948,8 +3441,9 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/tests/04_exception_irq_sani + } + + memory::mmu::post_enable_init(); -+ bsp::driver::driver_manager().qemu_bring_up_console(); -+ + bsp::driver::qemu_bring_up_console(); + +- exception::handling_init(); exception::asynchronous::local_irq_unmask(); test_main(); diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/arm/gicv2.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/arm/gicv2.rs index ec65f1b2..3cc35b5e 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/arm/gicv2.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/arm/gicv2.rs @@ -80,7 +80,8 @@ mod gicc; mod gicd; use crate::{ - bsp, cpu, driver, exception, + bsp::{self, device_driver::common::BoundedUsize}, + cpu, driver, exception, memory::{Address, Virtual}, synchronization, synchronization::InitStateLock, @@ -90,14 +91,15 @@ use crate::{ // Private Definitions //-------------------------------------------------------------------------------------------------- -type HandlerTable = [Option; IRQNumber::NUM_TOTAL]; +type HandlerTable = [Option>; + IRQNumber::MAX_INCLUSIVE + 1]; //-------------------------------------------------------------------------------------------------- // Public Definitions //-------------------------------------------------------------------------------------------------- /// Used for the associated type of trait [`exception::asynchronous::interface::IRQManager`]. -pub type IRQNumber = exception::asynchronous::IRQNumber<{ GICv2::MAX_IRQ_NUMBER }>; +pub type IRQNumber = BoundedUsize<{ GICv2::MAX_IRQ_NUMBER }>; /// Representation of the GIC. pub struct GICv2 { @@ -109,9 +111,6 @@ pub struct GICv2 { /// Stores registered IRQ handlers. Writable only during kernel init. RO afterwards. handler_table: InitStateLock, - - /// Callback to be invoked after successful init. - post_init_callback: fn(), } //-------------------------------------------------------------------------------------------------- @@ -131,13 +130,11 @@ impl GICv2 { pub const unsafe fn new( gicd_mmio_start_addr: Address, gicc_mmio_start_addr: Address, - post_init_callback: fn(), ) -> Self { Self { gicd: gicd::GICD::new(gicd_mmio_start_addr), gicc: gicc::GICC::new(gicc_mmio_start_addr), - handler_table: InitStateLock::new([None; IRQNumber::NUM_TOTAL]), - post_init_callback, + handler_table: InitStateLock::new([None; IRQNumber::MAX_INCLUSIVE + 1]), } } } @@ -148,6 +145,8 @@ impl GICv2 { use synchronization::interface::ReadWriteEx; impl driver::interface::DeviceDriver for GICv2 { + type IRQNumberType = IRQNumber; + fn compatible(&self) -> &'static str { Self::COMPATIBLE } @@ -160,8 +159,6 @@ impl driver::interface::DeviceDriver for GICv2 { self.gicc.priority_accept_all(); self.gicc.enable(); - (self.post_init_callback)(); - Ok(()) } } @@ -171,23 +168,22 @@ impl exception::asynchronous::interface::IRQManager for GICv2 { fn register_handler( &self, - irq_number: Self::IRQNumberType, - descriptor: exception::asynchronous::IRQDescriptor, + irq_handler_descriptor: exception::asynchronous::IRQHandlerDescriptor, ) -> Result<(), &'static str> { self.handler_table.write(|table| { - let irq_number = irq_number.get(); + let irq_number = irq_handler_descriptor.number().get(); if table[irq_number].is_some() { return Err("IRQ handler already registered"); } - table[irq_number] = Some(descriptor); + table[irq_number] = Some(irq_handler_descriptor); Ok(()) }) } - fn enable(&self, irq_number: Self::IRQNumberType) { + fn enable(&self, irq_number: &Self::IRQNumberType) { self.gicd.enable(irq_number); } @@ -210,7 +206,7 @@ impl exception::asynchronous::interface::IRQManager for GICv2 { None => panic!("No handler registered for IRQ {}", irq_number), Some(descriptor) => { // Call the IRQ handler. Panics on failure. - descriptor.handler.handle().expect("Error handling IRQ"); + descriptor.handler().handle().expect("Error handling IRQ"); } } }); @@ -227,7 +223,7 @@ impl exception::asynchronous::interface::IRQManager for GICv2 { self.handler_table.read(|table| { for (i, opt) in table.iter().skip(32).enumerate() { if let Some(handler) = opt { - info!(" {: >3}. {}", i + 32, handler.name); + info!(" {: >3}. {}", i + 32, handler.name()); } } }); diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs index a9c97a8e..8aebcf2b 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs @@ -172,7 +172,7 @@ impl GICD { } /// Enable an interrupt. - pub fn enable(&self, irq_num: super::IRQNumber) { + pub fn enable(&self, irq_num: &super::IRQNumber) { let irq_num = irq_num.get(); // Each bit in the u32 enable register corresponds to one IRQ number. Shift right by 5 diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs index 2281e66a..fb61a651 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs @@ -7,6 +7,7 @@ use crate::{ bsp::device_driver::common::MMIODerefWrapper, driver, + exception::asynchronous::IRQNumber, memory::{Address, Virtual}, synchronization, synchronization::IRQSafeNullLock, @@ -122,7 +123,6 @@ struct GPIOInner { /// Representation of the GPIO HW. pub struct GPIO { inner: IRQSafeNullLock, - post_init_callback: fn(), } //-------------------------------------------------------------------------------------------------- @@ -202,10 +202,9 @@ impl GPIO { /// # Safety /// /// - The user must ensure to provide a correct MMIO start address. - pub const unsafe fn new(mmio_start_addr: Address, post_init_callback: fn()) -> Self { + pub const unsafe fn new(mmio_start_addr: Address) -> Self { Self { inner: IRQSafeNullLock::new(GPIOInner::new(mmio_start_addr)), - post_init_callback, } } @@ -221,13 +220,9 @@ impl GPIO { use synchronization::interface::Mutex; impl driver::interface::DeviceDriver for GPIO { + type IRQNumberType = IRQNumber; + fn compatible(&self) -> &'static str { Self::COMPATIBLE } - - unsafe fn init(&self) -> Result<(), &'static str> { - (self.post_init_callback)(); - - Ok(()) - } } diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs index b4dd530d..c93a9fa1 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs @@ -7,9 +7,12 @@ mod peripheral_ic; use crate::{ - driver, exception, + bsp::device_driver::common::BoundedUsize, + driver, + exception::{self, asynchronous::IRQHandlerDescriptor}, memory::{Address, Virtual}, }; +use core::fmt; //-------------------------------------------------------------------------------------------------- // Private Definitions @@ -24,10 +27,8 @@ struct PendingIRQs { // Public Definitions //-------------------------------------------------------------------------------------------------- -pub type LocalIRQ = - exception::asynchronous::IRQNumber<{ InterruptController::MAX_LOCAL_IRQ_NUMBER }>; -pub type PeripheralIRQ = - exception::asynchronous::IRQNumber<{ InterruptController::MAX_PERIPHERAL_IRQ_NUMBER }>; +pub type LocalIRQ = BoundedUsize<{ InterruptController::MAX_LOCAL_IRQ_NUMBER }>; +pub type PeripheralIRQ = BoundedUsize<{ InterruptController::MAX_PERIPHERAL_IRQ_NUMBER }>; /// Used for the associated type of trait [`exception::asynchronous::interface::IRQManager`]. #[derive(Copy, Clone)] @@ -40,7 +41,6 @@ pub enum IRQNumber { /// Representation of the Interrupt Controller. pub struct InterruptController { periph: peripheral_ic::PeripheralIC, - post_init_callback: fn(), } //-------------------------------------------------------------------------------------------------- @@ -71,6 +71,15 @@ impl Iterator for PendingIRQs { // Public Code //-------------------------------------------------------------------------------------------------- +impl fmt::Display for IRQNumber { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Self::Local(number) => write!(f, "Local({})", number), + Self::Peripheral(number) => write!(f, "Peripheral({})", number), + } + } +} + impl InterruptController { // Restrict to 3 for now. This makes future code for local_ic.rs more straight forward. const MAX_LOCAL_IRQ_NUMBER: usize = 3; @@ -83,13 +92,9 @@ impl InterruptController { /// # Safety /// /// - The user must ensure to provide a correct MMIO start address. - pub const unsafe fn new( - periph_mmio_start_addr: Address, - post_init_callback: fn(), - ) -> Self { + pub const unsafe fn new(periph_mmio_start_addr: Address) -> Self { Self { periph: peripheral_ic::PeripheralIC::new(periph_mmio_start_addr), - post_init_callback, } } } @@ -99,15 +104,11 @@ impl InterruptController { //------------------------------------------------------------------------------ impl driver::interface::DeviceDriver for InterruptController { + type IRQNumberType = IRQNumber; + fn compatible(&self) -> &'static str { Self::COMPATIBLE } - - unsafe fn init(&self) -> Result<(), &'static str> { - (self.post_init_callback)(); - - Ok(()) - } } impl exception::asynchronous::interface::IRQManager for InterruptController { @@ -115,16 +116,23 @@ impl exception::asynchronous::interface::IRQManager for InterruptController { fn register_handler( &self, - irq: Self::IRQNumberType, - descriptor: exception::asynchronous::IRQDescriptor, + irq_handler_descriptor: exception::asynchronous::IRQHandlerDescriptor, ) -> Result<(), &'static str> { - match irq { + match irq_handler_descriptor.number() { IRQNumber::Local(_) => unimplemented!("Local IRQ controller not implemented."), - IRQNumber::Peripheral(pirq) => self.periph.register_handler(pirq, descriptor), + IRQNumber::Peripheral(pirq) => { + let periph_descriptor = IRQHandlerDescriptor::new( + pirq, + irq_handler_descriptor.name(), + irq_handler_descriptor.handler(), + ); + + self.periph.register_handler(periph_descriptor) + } } } - fn enable(&self, irq: Self::IRQNumberType) { + fn enable(&self, irq: &Self::IRQNumberType) { match irq { IRQNumber::Local(_) => unimplemented!("Local IRQ controller not implemented."), IRQNumber::Peripheral(pirq) => self.periph.enable(pirq), diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs index 06802d27..0a20bd87 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs @@ -52,7 +52,8 @@ type WriteOnlyRegisters = MMIODerefWrapper; /// Abstraction for the ReadOnly parts of the associated MMIO registers. type ReadOnlyRegisters = MMIODerefWrapper; -type HandlerTable = [Option; PeripheralIRQ::NUM_TOTAL]; +type HandlerTable = [Option>; + PeripheralIRQ::MAX_INCLUSIVE + 1]; //-------------------------------------------------------------------------------------------------- // Public Definitions @@ -84,7 +85,7 @@ impl PeripheralIC { Self { wo_registers: IRQSafeNullLock::new(WriteOnlyRegisters::new(mmio_start_addr)), ro_registers: ReadOnlyRegisters::new(mmio_start_addr), - handler_table: InitStateLock::new([None; PeripheralIRQ::NUM_TOTAL]), + handler_table: InitStateLock::new([None; PeripheralIRQ::MAX_INCLUSIVE + 1]), } } @@ -107,23 +108,22 @@ impl exception::asynchronous::interface::IRQManager for PeripheralIC { fn register_handler( &self, - irq: Self::IRQNumberType, - descriptor: exception::asynchronous::IRQDescriptor, + irq_handler_descriptor: exception::asynchronous::IRQHandlerDescriptor, ) -> Result<(), &'static str> { self.handler_table.write(|table| { - let irq_number = irq.get(); + let irq_number = irq_handler_descriptor.number().get(); if table[irq_number].is_some() { return Err("IRQ handler already registered"); } - table[irq_number] = Some(descriptor); + table[irq_number] = Some(irq_handler_descriptor); Ok(()) }) } - fn enable(&self, irq: Self::IRQNumberType) { + fn enable(&self, irq: &Self::IRQNumberType) { self.wo_registers.lock(|regs| { let enable_reg = if irq.get() <= 31 { ®s.ENABLE_1 @@ -149,7 +149,7 @@ impl exception::asynchronous::interface::IRQManager for PeripheralIC { None => panic!("No handler registered for IRQ {}", irq_number), Some(descriptor) => { // Call the IRQ handler. Panics on failure. - descriptor.handler.handle().expect("Error handling IRQ"); + descriptor.handler().handle().expect("Error handling IRQ"); } } } @@ -164,7 +164,7 @@ impl exception::asynchronous::interface::IRQManager for PeripheralIC { self.handler_table.read(|table| { for (i, opt) in table.iter().enumerate() { if let Some(handler) = opt { - info!(" {: >3}. {}", i, handler.name); + info!(" {: >3}. {}", i, handler.name()); } } }); diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs index f67d70df..0ee7feb7 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs @@ -10,9 +10,9 @@ //! - use crate::{ - bsp, bsp::device_driver::common::MMIODerefWrapper, - console, cpu, driver, exception, + console, cpu, driver, + exception::{self, asynchronous::IRQNumber}, memory::{Address, Virtual}, synchronization, synchronization::IRQSafeNullLock, @@ -233,8 +233,6 @@ struct PL011UartInner { /// Representation of the UART. pub struct PL011Uart { inner: IRQSafeNullLock, - irq_number: bsp::device_driver::IRQNumber, - post_init_callback: fn(), } //-------------------------------------------------------------------------------------------------- @@ -398,16 +396,9 @@ impl PL011Uart { /// # Safety /// /// - The user must ensure to provide a correct MMIO start address. - /// - The user must ensure to provide correct IRQ numbers. - pub const unsafe fn new( - mmio_start_addr: Address, - irq_number: bsp::device_driver::IRQNumber, - post_init_callback: fn(), - ) -> Self { + pub const unsafe fn new(mmio_start_addr: Address) -> Self { Self { inner: IRQSafeNullLock::new(PL011UartInner::new(mmio_start_addr)), - irq_number, - post_init_callback, } } } @@ -418,27 +409,28 @@ impl PL011Uart { use synchronization::interface::Mutex; impl driver::interface::DeviceDriver for PL011Uart { + type IRQNumberType = IRQNumber; + fn compatible(&self) -> &'static str { Self::COMPATIBLE } unsafe fn init(&self) -> Result<(), &'static str> { self.inner.lock(|inner| inner.init()); - (self.post_init_callback)(); Ok(()) } - fn register_and_enable_irq_handler(&'static self) -> Result<(), &'static str> { - use exception::asynchronous::{irq_manager, IRQDescriptor}; + fn register_and_enable_irq_handler( + &'static self, + irq_number: &Self::IRQNumberType, + ) -> Result<(), &'static str> { + use exception::asynchronous::{irq_manager, IRQHandlerDescriptor}; - let descriptor = IRQDescriptor { - name: Self::COMPATIBLE, - handler: self, - }; + let descriptor = IRQHandlerDescriptor::new(*irq_number, Self::COMPATIBLE, self); - irq_manager().register_handler(self.irq_number, descriptor)?; - irq_manager().enable(self.irq_number); + irq_manager().register_handler(descriptor)?; + irq_manager().enable(irq_number); Ok(()) } diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/common.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/common.rs index 69f038d4..ca7aeb76 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/common.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/common.rs @@ -5,7 +5,7 @@ //! Common device driver code. use crate::memory::{Address, Virtual}; -use core::{marker::PhantomData, ops}; +use core::{fmt, marker::PhantomData, ops}; //-------------------------------------------------------------------------------------------------- // Public Definitions @@ -16,6 +16,10 @@ pub struct MMIODerefWrapper { phantom: PhantomData T>, } +/// A wrapper type for usize with integrated range bound check. +#[derive(Copy, Clone)] +pub struct BoundedUsize(usize); + //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- @@ -37,3 +41,25 @@ impl ops::Deref for MMIODerefWrapper { unsafe { &*(self.start_addr.as_usize() as *const _) } } } + +impl BoundedUsize<{ MAX_INCLUSIVE }> { + pub const MAX_INCLUSIVE: usize = MAX_INCLUSIVE; + + /// Creates a new instance if number <= MAX_INCLUSIVE. + pub const fn new(number: usize) -> Self { + assert!(number <= MAX_INCLUSIVE); + + Self(number) + } + + /// Return the wrapped number. + pub const fn get(self) -> usize { + self.0 + } +} + +impl fmt::Display for BoundedUsize<{ MAX_INCLUSIVE }> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.0) + } +} diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/driver.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/driver.rs index e1db4a00..ca3435aa 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/driver.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/driver.rs @@ -7,34 +7,16 @@ use super::{exception, memory::map::mmio}; use crate::{ bsp::device_driver, - console, driver, exception as generic_exception, memory, + console, driver as generic_driver, + exception::{self as generic_exception}, + memory, memory::mmu::MMIODescriptor, - synchronization::{interface::ReadWriteEx, InitStateLock}, }; use core::{ mem::MaybeUninit, sync::atomic::{AtomicBool, Ordering}, }; -pub use device_driver::IRQNumber; - -//-------------------------------------------------------------------------------------------------- -// Private Definitions -//-------------------------------------------------------------------------------------------------- - -/// Device Driver Manager type. -struct BSPDriverManager { - device_drivers: InitStateLock<[Option<&'static (dyn DeviceDriver + Sync)>; NUM_DRIVERS]>, - init_done: AtomicBool, -} - -//-------------------------------------------------------------------------------------------------- -// Public Definitions -//-------------------------------------------------------------------------------------------------- - -/// The number of active drivers provided by this BSP. -pub const NUM_DRIVERS: usize = 3; - //-------------------------------------------------------------------------------------------------- // Global instances //-------------------------------------------------------------------------------------------------- @@ -49,150 +31,154 @@ static mut INTERRUPT_CONTROLLER: MaybeUninit #[cfg(feature = "bsp_rpi4")] static mut INTERRUPT_CONTROLLER: MaybeUninit = MaybeUninit::uninit(); -static BSP_DRIVER_MANAGER: BSPDriverManager = BSPDriverManager { - device_drivers: InitStateLock::new([None; NUM_DRIVERS]), - init_done: AtomicBool::new(false), -}; - //-------------------------------------------------------------------------------------------------- // Private Code //-------------------------------------------------------------------------------------------------- -impl BSPDriverManager { - unsafe fn instantiate_uart(&self) -> Result<(), &'static str> { - let mmio_descriptor = MMIODescriptor::new(mmio::PL011_UART_START, mmio::PL011_UART_SIZE); - let virt_addr = - memory::mmu::kernel_map_mmio(device_driver::PL011Uart::COMPATIBLE, &mmio_descriptor)?; +/// This must be called only after successful init of the memory subsystem. +unsafe fn instantiate_uart() -> Result<(), &'static str> { + let mmio_descriptor = MMIODescriptor::new(mmio::PL011_UART_START, mmio::PL011_UART_SIZE); + let virt_addr = + memory::mmu::kernel_map_mmio(device_driver::PL011Uart::COMPATIBLE, &mmio_descriptor)?; - // This is safe to do, because it is only called from the init'ed instance itself. - fn uart_post_init() { - console::register_console(unsafe { PL011_UART.assume_init_ref() }); - } + PL011_UART.write(device_driver::PL011Uart::new(virt_addr)); - PL011_UART.write(device_driver::PL011Uart::new( - virt_addr, - exception::asynchronous::irq_map::PL011_UART, - uart_post_init, - )); + Ok(()) +} - Ok(()) - } +/// This must be called only after successful init of the UART driver. +unsafe fn post_init_uart() -> Result<(), &'static str> { + console::register_console(PL011_UART.assume_init_ref()); - unsafe fn instantiate_gpio(&self) -> Result<(), &'static str> { - let mmio_descriptor = MMIODescriptor::new(mmio::GPIO_START, mmio::GPIO_SIZE); - let virt_addr = - memory::mmu::kernel_map_mmio(device_driver::GPIO::COMPATIBLE, &mmio_descriptor)?; + Ok(()) +} - // This is safe to do, because it is only called from the init'ed instance itself. - fn gpio_post_init() { - unsafe { GPIO.assume_init_ref().map_pl011_uart() }; - } +/// This must be called only after successful init of the memory subsystem. +unsafe fn instantiate_gpio() -> Result<(), &'static str> { + let mmio_descriptor = MMIODescriptor::new(mmio::GPIO_START, mmio::GPIO_SIZE); + let virt_addr = + memory::mmu::kernel_map_mmio(device_driver::GPIO::COMPATIBLE, &mmio_descriptor)?; - GPIO.write(device_driver::GPIO::new(virt_addr, gpio_post_init)); + GPIO.write(device_driver::GPIO::new(virt_addr)); - Ok(()) - } + Ok(()) +} - #[cfg(feature = "bsp_rpi3")] - unsafe fn instantiate_interrupt_controller(&self) -> Result<(), &'static str> { - let periph_mmio_descriptor = - MMIODescriptor::new(mmio::PERIPHERAL_IC_START, mmio::PERIPHERAL_IC_SIZE); - let periph_virt_addr = memory::mmu::kernel_map_mmio( - device_driver::InterruptController::COMPATIBLE, - &periph_mmio_descriptor, - )?; - - // This is safe to do, because it is only called from the init'ed instance itself. - fn interrupt_controller_post_init() { - generic_exception::asynchronous::register_irq_manager(unsafe { - INTERRUPT_CONTROLLER.assume_init_ref() - }); - } - - INTERRUPT_CONTROLLER.write(device_driver::InterruptController::new( - periph_virt_addr, - interrupt_controller_post_init, - )); - - Ok(()) - } +/// This must be called only after successful init of the GPIO driver. +unsafe fn post_init_gpio() -> Result<(), &'static str> { + GPIO.assume_init_ref().map_pl011_uart(); + Ok(()) +} + +/// This must be called only after successful init of the memory subsystem. +#[cfg(feature = "bsp_rpi3")] +unsafe fn instantiate_interrupt_controller() -> Result<(), &'static str> { + let periph_mmio_descriptor = + MMIODescriptor::new(mmio::PERIPHERAL_IC_START, mmio::PERIPHERAL_IC_SIZE); + let periph_virt_addr = memory::mmu::kernel_map_mmio( + device_driver::InterruptController::COMPATIBLE, + &periph_mmio_descriptor, + )?; + + INTERRUPT_CONTROLLER.write(device_driver::InterruptController::new(periph_virt_addr)); - #[cfg(feature = "bsp_rpi4")] - unsafe fn instantiate_interrupt_controller(&self) -> Result<(), &'static str> { - let gicd_mmio_descriptor = MMIODescriptor::new(mmio::GICD_START, mmio::GICD_SIZE); - let gicd_virt_addr = memory::mmu::kernel_map_mmio("GICv2 GICD", &gicd_mmio_descriptor)?; + Ok(()) +} - let gicc_mmio_descriptor = MMIODescriptor::new(mmio::GICC_START, mmio::GICC_SIZE); - let gicc_virt_addr = memory::mmu::kernel_map_mmio("GICV2 GICC", &gicc_mmio_descriptor)?; +/// This must be called only after successful init of the memory subsystem. +#[cfg(feature = "bsp_rpi4")] +unsafe fn instantiate_interrupt_controller() -> Result<(), &'static str> { + let gicd_mmio_descriptor = MMIODescriptor::new(mmio::GICD_START, mmio::GICD_SIZE); + let gicd_virt_addr = memory::mmu::kernel_map_mmio("GICv2 GICD", &gicd_mmio_descriptor)?; - // This is safe to do, because it is only called from the init'ed instance itself. - fn interrupt_controller_post_init() { - generic_exception::asynchronous::register_irq_manager(unsafe { - INTERRUPT_CONTROLLER.assume_init_ref() - }); - } + let gicc_mmio_descriptor = MMIODescriptor::new(mmio::GICC_START, mmio::GICC_SIZE); + let gicc_virt_addr = memory::mmu::kernel_map_mmio("GICV2 GICC", &gicc_mmio_descriptor)?; - INTERRUPT_CONTROLLER.write(device_driver::GICv2::new( - gicd_virt_addr, - gicc_virt_addr, - interrupt_controller_post_init, - )); + INTERRUPT_CONTROLLER.write(device_driver::GICv2::new(gicd_virt_addr, gicc_virt_addr)); - Ok(()) - } + Ok(()) +} - unsafe fn register_drivers(&self) { - self.device_drivers.write(|drivers| { - drivers[0] = Some(PL011_UART.assume_init_ref()); - drivers[1] = Some(GPIO.assume_init_ref()); - drivers[2] = Some(INTERRUPT_CONTROLLER.assume_init_ref()); - }); - } +/// This must be called only after successful init of the interrupt controller driver. +unsafe fn post_init_interrupt_controller() -> Result<(), &'static str> { + generic_exception::asynchronous::register_irq_manager(INTERRUPT_CONTROLLER.assume_init_ref()); + + Ok(()) } -//-------------------------------------------------------------------------------------------------- -// Public Code -//-------------------------------------------------------------------------------------------------- +/// Function needs to ensure that driver registration happens only after correct instantiation. +unsafe fn driver_uart() -> Result<(), &'static str> { + instantiate_uart()?; + + let uart_descriptor = generic_driver::DeviceDriverDescriptor::new( + PL011_UART.assume_init_ref(), + Some(post_init_uart), + Some(exception::asynchronous::irq_map::PL011_UART), + ); + generic_driver::driver_manager().register_driver(uart_descriptor); + + Ok(()) +} + +/// Function needs to ensure that driver registration happens only after correct instantiation. +unsafe fn driver_gpio() -> Result<(), &'static str> { + instantiate_gpio()?; + + let gpio_descriptor = generic_driver::DeviceDriverDescriptor::new( + GPIO.assume_init_ref(), + Some(post_init_gpio), + None, + ); + generic_driver::driver_manager().register_driver(gpio_descriptor); -/// Return a reference to the driver manager. -pub fn driver_manager() -> &'static impl driver::interface::DriverManager { - &BSP_DRIVER_MANAGER + Ok(()) } -//------------------------------------------------------------------------------ -// OS Interface Code -//------------------------------------------------------------------------------ -use driver::interface::DeviceDriver; +/// Function needs to ensure that driver registration happens only after correct instantiation. +unsafe fn driver_interrupt_controller() -> Result<(), &'static str> { + instantiate_interrupt_controller()?; -impl driver::interface::DriverManager for BSPDriverManager { - unsafe fn instantiate_drivers(&self) -> Result<(), &'static str> { - if self.init_done.load(Ordering::Relaxed) { - return Err("Drivers already instantiated"); - } + let interrupt_controller_descriptor = generic_driver::DeviceDriverDescriptor::new( + INTERRUPT_CONTROLLER.assume_init_ref(), + Some(post_init_interrupt_controller), + None, + ); + generic_driver::driver_manager().register_driver(interrupt_controller_descriptor); - self.instantiate_uart()?; - self.instantiate_gpio()?; - self.instantiate_interrupt_controller()?; + Ok(()) +} - self.register_drivers(); +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- - self.init_done.store(true, Ordering::Relaxed); - Ok(()) +/// Initialize the driver subsystem. +/// +/// # Safety +/// +/// See child function calls. +pub unsafe fn init() -> Result<(), &'static str> { + static INIT_DONE: AtomicBool = AtomicBool::new(false); + if INIT_DONE.load(Ordering::Relaxed) { + return Err("Init already done"); } - fn all_device_drivers(&self) -> [&(dyn DeviceDriver + Sync); NUM_DRIVERS] { - self.device_drivers - .read(|drivers| drivers.map(|drivers| drivers.unwrap())) - } + driver_uart()?; + driver_gpio()?; + driver_interrupt_controller()?; - #[cfg(feature = "test_build")] - fn qemu_bring_up_console(&self) { - use crate::cpu; + INIT_DONE.store(true, Ordering::Relaxed); + Ok(()) +} - unsafe { - self.instantiate_uart() - .unwrap_or_else(|_| cpu::qemu_exit_failure()); - console::register_console(PL011_UART.assume_init_ref()); - }; - } +/// Minimal code needed to bring up the console in QEMU (for testing only). This is often less steps +/// than on real hardware due to QEMU's abstractions. +#[cfg(feature = "test_build")] +pub fn qemu_bring_up_console() { + use crate::cpu; + + unsafe { + instantiate_uart().unwrap_or_else(|_| cpu::qemu_exit_failure()); + console::register_console(PL011_UART.assume_init_ref()); + }; } diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/exception/asynchronous.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/exception/asynchronous.rs index ab20d86d..06a67558 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/exception/asynchronous.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/exception/asynchronous.rs @@ -10,6 +10,9 @@ use crate::bsp; // Public Definitions //-------------------------------------------------------------------------------------------------- +/// Export for reuse in generic asynchronous.rs. +pub use bsp::device_driver::IRQNumber; + #[cfg(feature = "bsp_rpi3")] pub(in crate::bsp) mod irq_map { use super::bsp::device_driver::{IRQNumber, PeripheralIRQ}; diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/driver.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/driver.rs index 98197fef..18066c31 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/driver.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/driver.rs @@ -4,16 +4,37 @@ //! Driver support. +use crate::{ + exception, info, + synchronization::{interface::ReadWriteEx, InitStateLock}, +}; +use core::fmt; + +//-------------------------------------------------------------------------------------------------- +// Private Definitions +//-------------------------------------------------------------------------------------------------- + +const NUM_DRIVERS: usize = 5; + +struct DriverManagerInner +where + T: 'static, +{ + next_index: usize, + descriptors: [Option>; NUM_DRIVERS], +} + //-------------------------------------------------------------------------------------------------- // Public Definitions //-------------------------------------------------------------------------------------------------- /// Driver interfaces. pub mod interface { - use crate::bsp; - /// Device Driver functions. pub trait DeviceDriver { + /// Different interrupt controllers might use different types for IRQ number. + type IRQNumberType: super::fmt::Display; + /// Return a compatibility string for identifying the driver. fn compatible(&self) -> &'static str; @@ -26,32 +47,175 @@ pub mod interface { Ok(()) } - /// Called by the kernel to register and enable the device's IRQ handlers, if any. + /// Called by the kernel to register and enable the device's IRQ handler. /// /// Rust's type system will prevent a call to this function unless the calling instance /// itself has static lifetime. - fn register_and_enable_irq_handler(&'static self) -> Result<(), &'static str> { - Ok(()) + fn register_and_enable_irq_handler( + &'static self, + irq_number: &Self::IRQNumberType, + ) -> Result<(), &'static str> { + panic!( + "Attempt to enable IRQ {} for device {}, but driver does not support this", + irq_number, + self.compatible() + ) + } + } +} + +/// Tpye to be used as an optional callback after a driver's init() has run. +pub type DeviceDriverPostInitCallback = unsafe fn() -> Result<(), &'static str>; + +/// A descriptor for device drivers. +#[derive(Copy, Clone)] +pub struct DeviceDriverDescriptor +where + T: 'static, +{ + device_driver: &'static (dyn interface::DeviceDriver + Sync), + post_init_callback: Option, + irq_number: Option, +} + +/// Provides device driver management functions. +pub struct DriverManager +where + T: 'static, +{ + inner: InitStateLock>, +} + +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +static DRIVER_MANAGER: DriverManager = DriverManager::new(); + +//-------------------------------------------------------------------------------------------------- +// Private Code +//-------------------------------------------------------------------------------------------------- + +impl DriverManagerInner +where + T: 'static + Copy, +{ + /// Create an instance. + pub const fn new() -> Self { + Self { + next_index: 0, + descriptors: [None; NUM_DRIVERS], } } +} - /// Device driver management functions. +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +impl DeviceDriverDescriptor { + /// Create an instance. + pub fn new( + device_driver: &'static (dyn interface::DeviceDriver + Sync), + post_init_callback: Option, + irq_number: Option, + ) -> Self { + Self { + device_driver, + post_init_callback, + irq_number, + } + } +} + +/// Return a reference to the global DriverManager. +pub fn driver_manager() -> &'static DriverManager { + &DRIVER_MANAGER +} + +impl DriverManager +where + T: fmt::Display + Copy, +{ + /// Create an instance. + pub const fn new() -> Self { + Self { + inner: InitStateLock::new(DriverManagerInner::new()), + } + } + + /// Register a device driver with the kernel. + pub fn register_driver(&self, descriptor: DeviceDriverDescriptor) { + self.inner.write(|inner| { + inner.descriptors[inner.next_index] = Some(descriptor); + inner.next_index += 1; + }) + } + + /// Helper for iterating over registered drivers. + fn for_each_descriptor<'a>(&'a self, f: impl FnMut(&'a DeviceDriverDescriptor)) { + self.inner.read(|inner| { + inner + .descriptors + .iter() + .filter_map(|x| x.as_ref()) + .for_each(f) + }) + } + + /// Fully initialize all drivers and their interrupts handlers. /// - /// The `BSP` is supposed to supply one global instance. - pub trait DriverManager { - /// Instantiate all drivers. - /// - /// # Safety - /// - /// Must be called before `all_device_drivers`. - unsafe fn instantiate_drivers(&self) -> Result<(), &'static str>; + /// # Safety + /// + /// - During init, drivers might do stuff with system-wide impact. + pub unsafe fn init_drivers_and_irqs(&self) { + self.for_each_descriptor(|descriptor| { + // 1. Initialize driver. + if let Err(x) = descriptor.device_driver.init() { + panic!( + "Error initializing driver: {}: {}", + descriptor.device_driver.compatible(), + x + ); + } + + // 2. Call corresponding post init callback. + if let Some(callback) = &descriptor.post_init_callback { + if let Err(x) = callback() { + panic!( + "Error during driver post-init callback: {}: {}", + descriptor.device_driver.compatible(), + x + ); + } + } + }); + + // 3. After all post-init callbacks were done, the interrupt controller should be + // registered and functional. So let drivers register with it now. + self.for_each_descriptor(|descriptor| { + if let Some(irq_number) = &descriptor.irq_number { + if let Err(x) = descriptor + .device_driver + .register_and_enable_irq_handler(irq_number) + { + panic!( + "Error during driver interrupt handler registration: {}: {}", + descriptor.device_driver.compatible(), + x + ); + } + } + }); + } - /// Return a slice of references to all `BSP`-instantiated drivers. - fn all_device_drivers(&self) -> [&(dyn DeviceDriver + Sync); bsp::driver::NUM_DRIVERS]; + /// Enumerate all registered device drivers. + pub fn enumerate(&self) { + let mut i: usize = 1; + self.for_each_descriptor(|descriptor| { + info!(" {}. {}", i, descriptor.device_driver.compatible()); - /// Minimal code needed to bring up the console in QEMU (for testing only). This is often - /// less steps than on real hardware due to QEMU's abstractions. - #[cfg(feature = "test_build")] - fn qemu_bring_up_console(&self); + i += 1; + }); } } diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/exception/asynchronous.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/exception/asynchronous.rs index 83ca1aa6..c1f2a27b 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/exception/asynchronous.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/exception/asynchronous.rs @@ -10,7 +10,7 @@ mod arch_asynchronous; mod null_irq_manager; use crate::{bsp, synchronization}; -use core::{fmt, marker::PhantomData}; +use core::marker::PhantomData; //-------------------------------------------------------------------------------------------------- // Architectural Public Reexports @@ -24,14 +24,23 @@ pub use arch_asynchronous::{ // Public Definitions //-------------------------------------------------------------------------------------------------- +/// Interrupt number as defined by the BSP. +pub type IRQNumber = bsp::exception::asynchronous::IRQNumber; + /// Interrupt descriptor. #[derive(Copy, Clone)] -pub struct IRQDescriptor { +pub struct IRQHandlerDescriptor +where + T: Copy, +{ + /// The IRQ number. + number: T, + /// Descriptive name. - pub name: &'static str, + name: &'static str, /// Reference to handler trait object. - pub handler: &'static (dyn interface::IRQHandler + Sync), + handler: &'static (dyn interface::IRQHandler + Sync), } /// IRQContext token. @@ -61,17 +70,16 @@ pub mod interface { /// platform's interrupt controller. pub trait IRQManager { /// The IRQ number type depends on the implementation. - type IRQNumberType; + type IRQNumberType: Copy; /// Register a handler. fn register_handler( &self, - irq_number: Self::IRQNumberType, - descriptor: super::IRQDescriptor, + irq_handler_descriptor: super::IRQHandlerDescriptor, ) -> Result<(), &'static str>; /// Enable an interrupt in the controller. - fn enable(&self, irq_number: Self::IRQNumberType); + fn enable(&self, irq_number: &Self::IRQNumberType); /// Handle pending interrupts. /// @@ -91,16 +99,12 @@ pub mod interface { } } -/// A wrapper type for IRQ numbers with integrated range sanity check. -#[derive(Copy, Clone)] -pub struct IRQNumber(usize); - //-------------------------------------------------------------------------------------------------- // Global instances //-------------------------------------------------------------------------------------------------- static CUR_IRQ_MANAGER: InitStateLock< - &'static (dyn interface::IRQManager + Sync), + &'static (dyn interface::IRQManager + Sync), > = InitStateLock::new(&null_irq_manager::NULL_IRQ_MANAGER); //-------------------------------------------------------------------------------------------------- @@ -108,6 +112,39 @@ static CUR_IRQ_MANAGER: InitStateLock< //-------------------------------------------------------------------------------------------------- use synchronization::{interface::ReadWriteEx, InitStateLock}; +impl IRQHandlerDescriptor +where + T: Copy, +{ + /// Create an instance. + pub const fn new( + number: T, + name: &'static str, + handler: &'static (dyn interface::IRQHandler + Sync), + ) -> Self { + Self { + number, + name, + handler, + } + } + + /// Return the number. + pub const fn number(&self) -> T { + self.number + } + + /// Return the name. + pub const fn name(&self) -> &'static str { + self.name + } + + /// Return the handler. + pub const fn handler(&self) -> &'static (dyn interface::IRQHandler + Sync) { + self.handler + } +} + impl<'irq_context> IRQContext<'irq_context> { /// Creates an IRQContext token. /// @@ -125,29 +162,6 @@ impl<'irq_context> IRQContext<'irq_context> { } } -impl IRQNumber<{ MAX_INCLUSIVE }> { - /// The total number of IRQs this type supports. - pub const NUM_TOTAL: usize = MAX_INCLUSIVE + 1; - - /// Creates a new instance if number <= MAX_INCLUSIVE. - pub const fn new(number: usize) -> Self { - assert!(number <= MAX_INCLUSIVE); - - Self(number) - } - - /// Return the wrapped number. - pub const fn get(self) -> usize { - self.0 - } -} - -impl fmt::Display for IRQNumber<{ MAX_INCLUSIVE }> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}", self.0) - } -} - /// Executes the provided closure while IRQs are masked on the executing core. /// /// While the function temporarily changes the HW state of the executing core, it restores it to the @@ -163,8 +177,7 @@ pub fn exec_with_irq_masked(f: impl FnOnce() -> T) -> T { /// Register a new IRQ manager. pub fn register_irq_manager( - new_manager: &'static (dyn interface::IRQManager - + Sync), + new_manager: &'static (dyn interface::IRQManager + Sync), ) { CUR_IRQ_MANAGER.write(|manager| *manager = new_manager); } @@ -172,6 +185,6 @@ pub fn register_irq_manager( /// Return a reference to the currently registered IRQ manager. /// /// This is the IRQ manager used by the architectural interrupt handling code. -pub fn irq_manager() -> &'static dyn interface::IRQManager { +pub fn irq_manager() -> &'static dyn interface::IRQManager { CUR_IRQ_MANAGER.read(|manager| *manager) } diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/exception/asynchronous/null_irq_manager.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/exception/asynchronous/null_irq_manager.rs index 560e3ce4..438f9649 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/exception/asynchronous/null_irq_manager.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/exception/asynchronous/null_irq_manager.rs @@ -4,8 +4,7 @@ //! Null IRQ Manager. -use super::{interface, IRQContext, IRQDescriptor}; -use crate::bsp; +use super::{interface, IRQContext, IRQHandlerDescriptor}; //-------------------------------------------------------------------------------------------------- // Public Definitions @@ -24,17 +23,16 @@ pub static NULL_IRQ_MANAGER: NullIRQManager = NullIRQManager {}; //-------------------------------------------------------------------------------------------------- impl interface::IRQManager for NullIRQManager { - type IRQNumberType = bsp::driver::IRQNumber; + type IRQNumberType = super::IRQNumber; fn register_handler( &self, - _irq_number: Self::IRQNumberType, - _descriptor: IRQDescriptor, + _descriptor: IRQHandlerDescriptor, ) -> Result<(), &'static str> { panic!("No IRQ Manager registered yet"); } - fn enable(&self, _irq_number: Self::IRQNumberType) { + fn enable(&self, _irq_number: &Self::IRQNumberType) { panic!("No IRQ Manager registered yet"); } diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/lib.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/lib.rs index 22fb5fea..25f66be3 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/lib.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/lib.rs @@ -186,8 +186,6 @@ pub fn test_runner(tests: &[&test_types::UnitTest]) { #[cfg(test)] #[no_mangle] unsafe fn kernel_init() -> ! { - use driver::interface::DriverManager; - exception::handling_init(); let phys_kernel_tables_base_addr = match memory::mmu::kernel_map_binary() { @@ -200,7 +198,7 @@ unsafe fn kernel_init() -> ! { } memory::mmu::post_enable_init(); - bsp::driver::driver_manager().qemu_bring_up_console(); + bsp::driver::qemu_bring_up_console(); test_main(); diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/main.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/main.rs index 776b28fa..045d1200 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/main.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/main.rs @@ -13,7 +13,7 @@ #![no_main] #![no_std] -use libkernel::{bsp, cpu, driver, exception, info, memory, state, time, warn}; +use libkernel::{bsp, cpu, driver, exception, info, memory, state, time}; /// Early init code. /// @@ -26,8 +26,6 @@ use libkernel::{bsp, cpu, driver, exception, info, memory, state, time, warn}; /// IRQSafeNullLocks instead of spinlocks), will fail to work (properly) on the RPi SoCs. #[no_mangle] unsafe fn kernel_init() -> ! { - use driver::interface::DriverManager; - exception::handling_init(); let phys_kernel_tables_base_addr = match memory::mmu::kernel_map_binary() { @@ -41,22 +39,13 @@ unsafe fn kernel_init() -> ! { memory::mmu::post_enable_init(); - // Instantiate and init all device drivers. - if let Err(x) = bsp::driver::driver_manager().instantiate_drivers() { - panic!("Error instantiating drivers: {}", x); - } - for i in bsp::driver::driver_manager().all_device_drivers().iter() { - if let Err(x) = i.init() { - panic!("Error loading driver: {}: {}", i.compatible(), x); - } + // Initialize the BSP driver subsystem. + if let Err(x) = bsp::driver::init() { + panic!("Error initializing BSP driver subsystem: {}", x); } - // Let device drivers register and enable their handlers with the interrupt controller. - for i in bsp::driver::driver_manager().all_device_drivers() { - if let Err(msg) = i.register_and_enable_irq_handler() { - warn!("Error registering IRQ handler: {}", msg); - } - } + // Initialize all device drivers. + driver::driver_manager().init_drivers_and_irqs(); // Unmask interrupts on the boot CPU core. exception::asynchronous::local_irq_unmask(); @@ -70,8 +59,6 @@ unsafe fn kernel_init() -> ! { /// The main function running after the early init. fn kernel_main() -> ! { - use driver::interface::DriverManager; - info!("{}", libkernel::version()); info!("Booting on: {}", bsp::board_name()); @@ -90,13 +77,7 @@ fn kernel_main() -> ! { ); info!("Drivers loaded:"); - for (i, driver) in bsp::driver::driver_manager() - .all_device_drivers() - .iter() - .enumerate() - { - info!(" {}. {}", i + 1, driver.compatible()); - } + driver::driver_manager().enumerate(); info!("Registered IRQ handlers:"); exception::asynchronous::irq_manager().print_handler(); diff --git a/14_virtual_mem_part2_mmio_remap/kernel/tests/00_console_sanity.rs b/14_virtual_mem_part2_mmio_remap/kernel/tests/00_console_sanity.rs index 9c6e9cef..b27822d5 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/tests/00_console_sanity.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/tests/00_console_sanity.rs @@ -11,12 +11,11 @@ /// Console tests should time out on the I/O harness in case of panic. mod panic_wait_forever; -use libkernel::{bsp, console, cpu, driver, exception, memory, print}; +use libkernel::{bsp, console, cpu, exception, memory, print}; #[no_mangle] unsafe fn kernel_init() -> ! { use console::console; - use driver::interface::DriverManager; exception::handling_init(); @@ -30,7 +29,7 @@ unsafe fn kernel_init() -> ! { } memory::mmu::post_enable_init(); - bsp::driver::driver_manager().qemu_bring_up_console(); + bsp::driver::qemu_bring_up_console(); // Handshake assert_eq!(console().read_char(), 'A'); diff --git a/14_virtual_mem_part2_mmio_remap/kernel/tests/01_timer_sanity.rs b/14_virtual_mem_part2_mmio_remap/kernel/tests/01_timer_sanity.rs index dd34b06c..691b511d 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/tests/01_timer_sanity.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/tests/01_timer_sanity.rs @@ -11,13 +11,11 @@ #![test_runner(libkernel::test_runner)] use core::time::Duration; -use libkernel::{bsp, cpu, driver, exception, memory, time}; +use libkernel::{bsp, cpu, exception, memory, time}; use test_macros::kernel_test; #[no_mangle] unsafe fn kernel_init() -> ! { - use driver::interface::DriverManager; - exception::handling_init(); let phys_kernel_tables_base_addr = match memory::mmu::kernel_map_binary() { @@ -30,7 +28,7 @@ unsafe fn kernel_init() -> ! { } memory::mmu::post_enable_init(); - bsp::driver::driver_manager().qemu_bring_up_console(); + bsp::driver::qemu_bring_up_console(); // Depending on CPU arch, some timer bring-up code could go here. Not needed for the RPi. diff --git a/14_virtual_mem_part2_mmio_remap/kernel/tests/02_exception_sync_page_fault.rs b/14_virtual_mem_part2_mmio_remap/kernel/tests/02_exception_sync_page_fault.rs index 594ffb40..c3053961 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/tests/02_exception_sync_page_fault.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/tests/02_exception_sync_page_fault.rs @@ -17,12 +17,10 @@ /// or indirectly. mod panic_exit_success; -use libkernel::{bsp, cpu, driver, exception, info, memory, println}; +use libkernel::{bsp, cpu, exception, info, memory, println}; #[no_mangle] unsafe fn kernel_init() -> ! { - use driver::interface::DriverManager; - exception::handling_init(); // This line will be printed as the test header. @@ -42,7 +40,7 @@ unsafe fn kernel_init() -> ! { } memory::mmu::post_enable_init(); - bsp::driver::driver_manager().qemu_bring_up_console(); + bsp::driver::qemu_bring_up_console(); info!("Writing beyond mapped area to address 9 GiB..."); let big_addr: u64 = 9 * 1024 * 1024 * 1024; diff --git a/14_virtual_mem_part2_mmio_remap/kernel/tests/03_exception_restore_sanity.rs b/14_virtual_mem_part2_mmio_remap/kernel/tests/03_exception_restore_sanity.rs index 32001b2a..6351e80c 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/tests/03_exception_restore_sanity.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/tests/03_exception_restore_sanity.rs @@ -12,7 +12,7 @@ mod panic_wait_forever; use core::arch::asm; -use libkernel::{bsp, cpu, driver, exception, info, memory, println}; +use libkernel::{bsp, cpu, exception, info, memory, println}; #[inline(never)] fn nested_system_call() { @@ -30,8 +30,6 @@ fn nested_system_call() { #[no_mangle] unsafe fn kernel_init() -> ! { - use driver::interface::DriverManager; - exception::handling_init(); // This line will be printed as the test header. @@ -51,7 +49,7 @@ unsafe fn kernel_init() -> ! { } memory::mmu::post_enable_init(); - bsp::driver::driver_manager().qemu_bring_up_console(); + bsp::driver::qemu_bring_up_console(); info!("Making a dummy system call"); diff --git a/14_virtual_mem_part2_mmio_remap/kernel/tests/04_exception_irq_sanity.rs b/14_virtual_mem_part2_mmio_remap/kernel/tests/04_exception_irq_sanity.rs index c9e244ce..35bf51b6 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/tests/04_exception_irq_sanity.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/tests/04_exception_irq_sanity.rs @@ -10,13 +10,11 @@ #![reexport_test_harness_main = "test_main"] #![test_runner(libkernel::test_runner)] -use libkernel::{bsp, cpu, driver, exception, memory}; +use libkernel::{bsp, cpu, exception, memory}; use test_macros::kernel_test; #[no_mangle] unsafe fn kernel_init() -> ! { - use driver::interface::DriverManager; - exception::handling_init(); let phys_kernel_tables_base_addr = match memory::mmu::kernel_map_binary() { @@ -29,7 +27,7 @@ unsafe fn kernel_init() -> ! { } memory::mmu::post_enable_init(); - bsp::driver::driver_manager().qemu_bring_up_console(); + bsp::driver::qemu_bring_up_console(); exception::asynchronous::local_irq_unmask(); diff --git a/15_virtual_mem_part3_precomputed_tables/Makefile b/15_virtual_mem_part3_precomputed_tables/Makefile index 2e0a3462..4092ec8f 100644 --- a/15_virtual_mem_part3_precomputed_tables/Makefile +++ b/15_virtual_mem_part3_precomputed_tables/Makefile @@ -310,7 +310,7 @@ test_boot: $(KERNEL_BIN) ## Helpers for unit and integration test targets ##------------------------------------------------------------------------------ define KERNEL_TEST_RUNNER - #!/usr/bin/env bash +#!/usr/bin/env bash # The cargo test runner seems to change into the crate under test's directory. Therefore, ensure # this script executes from the root. diff --git a/15_virtual_mem_part3_precomputed_tables/README.md b/15_virtual_mem_part3_precomputed_tables/README.md index a6ebe332..00586235 100644 --- a/15_virtual_mem_part3_precomputed_tables/README.md +++ b/15_virtual_mem_part3_precomputed_tables/README.md @@ -1336,9 +1336,9 @@ diff -uNr 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/memory/mmu. diff -uNr 14_virtual_mem_part2_mmio_remap/kernel/src/lib.rs 15_virtual_mem_part3_precomputed_tables/kernel/src/lib.rs --- 14_virtual_mem_part2_mmio_remap/kernel/src/lib.rs +++ 15_virtual_mem_part3_precomputed_tables/kernel/src/lib.rs -@@ -189,17 +189,7 @@ - use driver::interface::DriverManager; - +@@ -187,17 +187,7 @@ + #[no_mangle] + unsafe fn kernel_init() -> ! { exception::handling_init(); - - let phys_kernel_tables_base_addr = match memory::mmu::kernel_map_binary() { @@ -1352,14 +1352,14 @@ diff -uNr 14_virtual_mem_part2_mmio_remap/kernel/src/lib.rs 15_virtual_mem_part3 - - memory::mmu::post_enable_init(); + memory::init(); - bsp::driver::driver_manager().qemu_bring_up_console(); + bsp::driver::qemu_bring_up_console(); test_main(); diff -uNr 14_virtual_mem_part2_mmio_remap/kernel/src/main.rs 15_virtual_mem_part3_precomputed_tables/kernel/src/main.rs --- 14_virtual_mem_part2_mmio_remap/kernel/src/main.rs +++ 15_virtual_mem_part3_precomputed_tables/kernel/src/main.rs -@@ -17,29 +17,18 @@ +@@ -17,27 +17,16 @@ /// Early init code. /// @@ -1375,8 +1375,6 @@ diff -uNr 14_virtual_mem_part2_mmio_remap/kernel/src/main.rs 15_virtual_mem_part +/// - Printing will not work until the respective driver's MMIO is remapped. #[no_mangle] unsafe fn kernel_init() -> ! { - use driver::interface::DriverManager; - exception::handling_init(); - - let phys_kernel_tables_base_addr = match memory::mmu::kernel_map_binary() { @@ -1391,11 +1389,11 @@ diff -uNr 14_virtual_mem_part2_mmio_remap/kernel/src/main.rs 15_virtual_mem_part - memory::mmu::post_enable_init(); + memory::init(); - // Instantiate and init all device drivers. - if let Err(x) = bsp::driver::driver_manager().instantiate_drivers() { -@@ -58,6 +47,8 @@ - } - } + // Initialize the BSP driver subsystem. + if let Err(x) = bsp::driver::init() { +@@ -47,6 +36,8 @@ + // Initialize all device drivers. + driver::driver_manager().init_drivers_and_irqs(); + bsp::memory::mmu::kernel_add_mapping_records_for_precomputed(); + @@ -1711,8 +1709,8 @@ diff -uNr 14_virtual_mem_part2_mmio_remap/kernel/src/memory.rs 15_virtual_mem_pa diff -uNr 14_virtual_mem_part2_mmio_remap/kernel/tests/00_console_sanity.rs 15_virtual_mem_part3_precomputed_tables/kernel/tests/00_console_sanity.rs --- 14_virtual_mem_part2_mmio_remap/kernel/tests/00_console_sanity.rs +++ 15_virtual_mem_part3_precomputed_tables/kernel/tests/00_console_sanity.rs -@@ -19,17 +19,7 @@ - use driver::interface::DriverManager; +@@ -18,17 +18,7 @@ + use console::console; exception::handling_init(); - @@ -1727,16 +1725,16 @@ diff -uNr 14_virtual_mem_part2_mmio_remap/kernel/tests/00_console_sanity.rs 15_v - - memory::mmu::post_enable_init(); + memory::init(); - bsp::driver::driver_manager().qemu_bring_up_console(); + bsp::driver::qemu_bring_up_console(); // Handshake diff -uNr 14_virtual_mem_part2_mmio_remap/kernel/tests/01_timer_sanity.rs 15_virtual_mem_part3_precomputed_tables/kernel/tests/01_timer_sanity.rs --- 14_virtual_mem_part2_mmio_remap/kernel/tests/01_timer_sanity.rs +++ 15_virtual_mem_part3_precomputed_tables/kernel/tests/01_timer_sanity.rs -@@ -19,17 +19,7 @@ - use driver::interface::DriverManager; - +@@ -17,17 +17,7 @@ + #[no_mangle] + unsafe fn kernel_init() -> ! { exception::handling_init(); - - let phys_kernel_tables_base_addr = match memory::mmu::kernel_map_binary() { @@ -1750,19 +1748,19 @@ diff -uNr 14_virtual_mem_part2_mmio_remap/kernel/tests/01_timer_sanity.rs 15_vir - - memory::mmu::post_enable_init(); + memory::init(); - bsp::driver::driver_manager().qemu_bring_up_console(); + bsp::driver::qemu_bring_up_console(); // Depending on CPU arch, some timer bring-up code could go here. Not needed for the RPi. diff -uNr 14_virtual_mem_part2_mmio_remap/kernel/tests/02_exception_sync_page_fault.rs 15_virtual_mem_part3_precomputed_tables/kernel/tests/02_exception_sync_page_fault.rs --- 14_virtual_mem_part2_mmio_remap/kernel/tests/02_exception_sync_page_fault.rs +++ 15_virtual_mem_part3_precomputed_tables/kernel/tests/02_exception_sync_page_fault.rs -@@ -24,26 +24,12 @@ - use driver::interface::DriverManager; - +@@ -22,26 +22,12 @@ + #[no_mangle] + unsafe fn kernel_init() -> ! { exception::handling_init(); + memory::init(); -+ bsp::driver::driver_manager().qemu_bring_up_console(); ++ bsp::driver::qemu_bring_up_console(); // This line will be printed as the test header. println!("Testing synchronous exception handling by causing a page fault"); @@ -1781,7 +1779,7 @@ diff -uNr 14_virtual_mem_part2_mmio_remap/kernel/tests/02_exception_sync_page_fa - } - - memory::mmu::post_enable_init(); -- bsp::driver::driver_manager().qemu_bring_up_console(); +- bsp::driver::qemu_bring_up_console(); - info!("Writing beyond mapped area to address 9 GiB..."); let big_addr: u64 = 9 * 1024 * 1024 * 1024; @@ -1790,12 +1788,12 @@ diff -uNr 14_virtual_mem_part2_mmio_remap/kernel/tests/02_exception_sync_page_fa diff -uNr 14_virtual_mem_part2_mmio_remap/kernel/tests/03_exception_restore_sanity.rs 15_virtual_mem_part3_precomputed_tables/kernel/tests/03_exception_restore_sanity.rs --- 14_virtual_mem_part2_mmio_remap/kernel/tests/03_exception_restore_sanity.rs +++ 15_virtual_mem_part3_precomputed_tables/kernel/tests/03_exception_restore_sanity.rs -@@ -33,26 +33,12 @@ - use driver::interface::DriverManager; - +@@ -31,26 +31,12 @@ + #[no_mangle] + unsafe fn kernel_init() -> ! { exception::handling_init(); + memory::init(); -+ bsp::driver::driver_manager().qemu_bring_up_console(); ++ bsp::driver::qemu_bring_up_console(); // This line will be printed as the test header. println!("Testing exception restore"); @@ -1814,7 +1812,7 @@ diff -uNr 14_virtual_mem_part2_mmio_remap/kernel/tests/03_exception_restore_sani - } - - memory::mmu::post_enable_init(); -- bsp::driver::driver_manager().qemu_bring_up_console(); +- bsp::driver::qemu_bring_up_console(); - info!("Making a dummy system call"); @@ -1823,10 +1821,10 @@ diff -uNr 14_virtual_mem_part2_mmio_remap/kernel/tests/03_exception_restore_sani diff -uNr 14_virtual_mem_part2_mmio_remap/kernel/tests/04_exception_irq_sanity.rs 15_virtual_mem_part3_precomputed_tables/kernel/tests/04_exception_irq_sanity.rs --- 14_virtual_mem_part2_mmio_remap/kernel/tests/04_exception_irq_sanity.rs +++ 15_virtual_mem_part3_precomputed_tables/kernel/tests/04_exception_irq_sanity.rs -@@ -17,20 +17,10 @@ - unsafe fn kernel_init() -> ! { - use driver::interface::DriverManager; +@@ -15,20 +15,10 @@ + #[no_mangle] + unsafe fn kernel_init() -> ! { - exception::handling_init(); - - let phys_kernel_tables_base_addr = match memory::mmu::kernel_map_binary() { @@ -1840,7 +1838,7 @@ diff -uNr 14_virtual_mem_part2_mmio_remap/kernel/tests/04_exception_irq_sanity.r - - memory::mmu::post_enable_init(); + memory::init(); - bsp::driver::driver_manager().qemu_bring_up_console(); + bsp::driver::qemu_bring_up_console(); + exception::handling_init(); exception::asynchronous::local_irq_unmask(); diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/arm/gicv2.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/arm/gicv2.rs index ec65f1b2..3cc35b5e 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/arm/gicv2.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/arm/gicv2.rs @@ -80,7 +80,8 @@ mod gicc; mod gicd; use crate::{ - bsp, cpu, driver, exception, + bsp::{self, device_driver::common::BoundedUsize}, + cpu, driver, exception, memory::{Address, Virtual}, synchronization, synchronization::InitStateLock, @@ -90,14 +91,15 @@ use crate::{ // Private Definitions //-------------------------------------------------------------------------------------------------- -type HandlerTable = [Option; IRQNumber::NUM_TOTAL]; +type HandlerTable = [Option>; + IRQNumber::MAX_INCLUSIVE + 1]; //-------------------------------------------------------------------------------------------------- // Public Definitions //-------------------------------------------------------------------------------------------------- /// Used for the associated type of trait [`exception::asynchronous::interface::IRQManager`]. -pub type IRQNumber = exception::asynchronous::IRQNumber<{ GICv2::MAX_IRQ_NUMBER }>; +pub type IRQNumber = BoundedUsize<{ GICv2::MAX_IRQ_NUMBER }>; /// Representation of the GIC. pub struct GICv2 { @@ -109,9 +111,6 @@ pub struct GICv2 { /// Stores registered IRQ handlers. Writable only during kernel init. RO afterwards. handler_table: InitStateLock, - - /// Callback to be invoked after successful init. - post_init_callback: fn(), } //-------------------------------------------------------------------------------------------------- @@ -131,13 +130,11 @@ impl GICv2 { pub const unsafe fn new( gicd_mmio_start_addr: Address, gicc_mmio_start_addr: Address, - post_init_callback: fn(), ) -> Self { Self { gicd: gicd::GICD::new(gicd_mmio_start_addr), gicc: gicc::GICC::new(gicc_mmio_start_addr), - handler_table: InitStateLock::new([None; IRQNumber::NUM_TOTAL]), - post_init_callback, + handler_table: InitStateLock::new([None; IRQNumber::MAX_INCLUSIVE + 1]), } } } @@ -148,6 +145,8 @@ impl GICv2 { use synchronization::interface::ReadWriteEx; impl driver::interface::DeviceDriver for GICv2 { + type IRQNumberType = IRQNumber; + fn compatible(&self) -> &'static str { Self::COMPATIBLE } @@ -160,8 +159,6 @@ impl driver::interface::DeviceDriver for GICv2 { self.gicc.priority_accept_all(); self.gicc.enable(); - (self.post_init_callback)(); - Ok(()) } } @@ -171,23 +168,22 @@ impl exception::asynchronous::interface::IRQManager for GICv2 { fn register_handler( &self, - irq_number: Self::IRQNumberType, - descriptor: exception::asynchronous::IRQDescriptor, + irq_handler_descriptor: exception::asynchronous::IRQHandlerDescriptor, ) -> Result<(), &'static str> { self.handler_table.write(|table| { - let irq_number = irq_number.get(); + let irq_number = irq_handler_descriptor.number().get(); if table[irq_number].is_some() { return Err("IRQ handler already registered"); } - table[irq_number] = Some(descriptor); + table[irq_number] = Some(irq_handler_descriptor); Ok(()) }) } - fn enable(&self, irq_number: Self::IRQNumberType) { + fn enable(&self, irq_number: &Self::IRQNumberType) { self.gicd.enable(irq_number); } @@ -210,7 +206,7 @@ impl exception::asynchronous::interface::IRQManager for GICv2 { None => panic!("No handler registered for IRQ {}", irq_number), Some(descriptor) => { // Call the IRQ handler. Panics on failure. - descriptor.handler.handle().expect("Error handling IRQ"); + descriptor.handler().handle().expect("Error handling IRQ"); } } }); @@ -227,7 +223,7 @@ impl exception::asynchronous::interface::IRQManager for GICv2 { self.handler_table.read(|table| { for (i, opt) in table.iter().skip(32).enumerate() { if let Some(handler) = opt { - info!(" {: >3}. {}", i + 32, handler.name); + info!(" {: >3}. {}", i + 32, handler.name()); } } }); diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs index a9c97a8e..8aebcf2b 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs @@ -172,7 +172,7 @@ impl GICD { } /// Enable an interrupt. - pub fn enable(&self, irq_num: super::IRQNumber) { + pub fn enable(&self, irq_num: &super::IRQNumber) { let irq_num = irq_num.get(); // Each bit in the u32 enable register corresponds to one IRQ number. Shift right by 5 diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs index 2281e66a..fb61a651 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs @@ -7,6 +7,7 @@ use crate::{ bsp::device_driver::common::MMIODerefWrapper, driver, + exception::asynchronous::IRQNumber, memory::{Address, Virtual}, synchronization, synchronization::IRQSafeNullLock, @@ -122,7 +123,6 @@ struct GPIOInner { /// Representation of the GPIO HW. pub struct GPIO { inner: IRQSafeNullLock, - post_init_callback: fn(), } //-------------------------------------------------------------------------------------------------- @@ -202,10 +202,9 @@ impl GPIO { /// # Safety /// /// - The user must ensure to provide a correct MMIO start address. - pub const unsafe fn new(mmio_start_addr: Address, post_init_callback: fn()) -> Self { + pub const unsafe fn new(mmio_start_addr: Address) -> Self { Self { inner: IRQSafeNullLock::new(GPIOInner::new(mmio_start_addr)), - post_init_callback, } } @@ -221,13 +220,9 @@ impl GPIO { use synchronization::interface::Mutex; impl driver::interface::DeviceDriver for GPIO { + type IRQNumberType = IRQNumber; + fn compatible(&self) -> &'static str { Self::COMPATIBLE } - - unsafe fn init(&self) -> Result<(), &'static str> { - (self.post_init_callback)(); - - Ok(()) - } } diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs index b4dd530d..c93a9fa1 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs @@ -7,9 +7,12 @@ mod peripheral_ic; use crate::{ - driver, exception, + bsp::device_driver::common::BoundedUsize, + driver, + exception::{self, asynchronous::IRQHandlerDescriptor}, memory::{Address, Virtual}, }; +use core::fmt; //-------------------------------------------------------------------------------------------------- // Private Definitions @@ -24,10 +27,8 @@ struct PendingIRQs { // Public Definitions //-------------------------------------------------------------------------------------------------- -pub type LocalIRQ = - exception::asynchronous::IRQNumber<{ InterruptController::MAX_LOCAL_IRQ_NUMBER }>; -pub type PeripheralIRQ = - exception::asynchronous::IRQNumber<{ InterruptController::MAX_PERIPHERAL_IRQ_NUMBER }>; +pub type LocalIRQ = BoundedUsize<{ InterruptController::MAX_LOCAL_IRQ_NUMBER }>; +pub type PeripheralIRQ = BoundedUsize<{ InterruptController::MAX_PERIPHERAL_IRQ_NUMBER }>; /// Used for the associated type of trait [`exception::asynchronous::interface::IRQManager`]. #[derive(Copy, Clone)] @@ -40,7 +41,6 @@ pub enum IRQNumber { /// Representation of the Interrupt Controller. pub struct InterruptController { periph: peripheral_ic::PeripheralIC, - post_init_callback: fn(), } //-------------------------------------------------------------------------------------------------- @@ -71,6 +71,15 @@ impl Iterator for PendingIRQs { // Public Code //-------------------------------------------------------------------------------------------------- +impl fmt::Display for IRQNumber { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Self::Local(number) => write!(f, "Local({})", number), + Self::Peripheral(number) => write!(f, "Peripheral({})", number), + } + } +} + impl InterruptController { // Restrict to 3 for now. This makes future code for local_ic.rs more straight forward. const MAX_LOCAL_IRQ_NUMBER: usize = 3; @@ -83,13 +92,9 @@ impl InterruptController { /// # Safety /// /// - The user must ensure to provide a correct MMIO start address. - pub const unsafe fn new( - periph_mmio_start_addr: Address, - post_init_callback: fn(), - ) -> Self { + pub const unsafe fn new(periph_mmio_start_addr: Address) -> Self { Self { periph: peripheral_ic::PeripheralIC::new(periph_mmio_start_addr), - post_init_callback, } } } @@ -99,15 +104,11 @@ impl InterruptController { //------------------------------------------------------------------------------ impl driver::interface::DeviceDriver for InterruptController { + type IRQNumberType = IRQNumber; + fn compatible(&self) -> &'static str { Self::COMPATIBLE } - - unsafe fn init(&self) -> Result<(), &'static str> { - (self.post_init_callback)(); - - Ok(()) - } } impl exception::asynchronous::interface::IRQManager for InterruptController { @@ -115,16 +116,23 @@ impl exception::asynchronous::interface::IRQManager for InterruptController { fn register_handler( &self, - irq: Self::IRQNumberType, - descriptor: exception::asynchronous::IRQDescriptor, + irq_handler_descriptor: exception::asynchronous::IRQHandlerDescriptor, ) -> Result<(), &'static str> { - match irq { + match irq_handler_descriptor.number() { IRQNumber::Local(_) => unimplemented!("Local IRQ controller not implemented."), - IRQNumber::Peripheral(pirq) => self.periph.register_handler(pirq, descriptor), + IRQNumber::Peripheral(pirq) => { + let periph_descriptor = IRQHandlerDescriptor::new( + pirq, + irq_handler_descriptor.name(), + irq_handler_descriptor.handler(), + ); + + self.periph.register_handler(periph_descriptor) + } } } - fn enable(&self, irq: Self::IRQNumberType) { + fn enable(&self, irq: &Self::IRQNumberType) { match irq { IRQNumber::Local(_) => unimplemented!("Local IRQ controller not implemented."), IRQNumber::Peripheral(pirq) => self.periph.enable(pirq), diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs index 06802d27..0a20bd87 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs @@ -52,7 +52,8 @@ type WriteOnlyRegisters = MMIODerefWrapper; /// Abstraction for the ReadOnly parts of the associated MMIO registers. type ReadOnlyRegisters = MMIODerefWrapper; -type HandlerTable = [Option; PeripheralIRQ::NUM_TOTAL]; +type HandlerTable = [Option>; + PeripheralIRQ::MAX_INCLUSIVE + 1]; //-------------------------------------------------------------------------------------------------- // Public Definitions @@ -84,7 +85,7 @@ impl PeripheralIC { Self { wo_registers: IRQSafeNullLock::new(WriteOnlyRegisters::new(mmio_start_addr)), ro_registers: ReadOnlyRegisters::new(mmio_start_addr), - handler_table: InitStateLock::new([None; PeripheralIRQ::NUM_TOTAL]), + handler_table: InitStateLock::new([None; PeripheralIRQ::MAX_INCLUSIVE + 1]), } } @@ -107,23 +108,22 @@ impl exception::asynchronous::interface::IRQManager for PeripheralIC { fn register_handler( &self, - irq: Self::IRQNumberType, - descriptor: exception::asynchronous::IRQDescriptor, + irq_handler_descriptor: exception::asynchronous::IRQHandlerDescriptor, ) -> Result<(), &'static str> { self.handler_table.write(|table| { - let irq_number = irq.get(); + let irq_number = irq_handler_descriptor.number().get(); if table[irq_number].is_some() { return Err("IRQ handler already registered"); } - table[irq_number] = Some(descriptor); + table[irq_number] = Some(irq_handler_descriptor); Ok(()) }) } - fn enable(&self, irq: Self::IRQNumberType) { + fn enable(&self, irq: &Self::IRQNumberType) { self.wo_registers.lock(|regs| { let enable_reg = if irq.get() <= 31 { ®s.ENABLE_1 @@ -149,7 +149,7 @@ impl exception::asynchronous::interface::IRQManager for PeripheralIC { None => panic!("No handler registered for IRQ {}", irq_number), Some(descriptor) => { // Call the IRQ handler. Panics on failure. - descriptor.handler.handle().expect("Error handling IRQ"); + descriptor.handler().handle().expect("Error handling IRQ"); } } } @@ -164,7 +164,7 @@ impl exception::asynchronous::interface::IRQManager for PeripheralIC { self.handler_table.read(|table| { for (i, opt) in table.iter().enumerate() { if let Some(handler) = opt { - info!(" {: >3}. {}", i, handler.name); + info!(" {: >3}. {}", i, handler.name()); } } }); diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs index f67d70df..0ee7feb7 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs @@ -10,9 +10,9 @@ //! - use crate::{ - bsp, bsp::device_driver::common::MMIODerefWrapper, - console, cpu, driver, exception, + console, cpu, driver, + exception::{self, asynchronous::IRQNumber}, memory::{Address, Virtual}, synchronization, synchronization::IRQSafeNullLock, @@ -233,8 +233,6 @@ struct PL011UartInner { /// Representation of the UART. pub struct PL011Uart { inner: IRQSafeNullLock, - irq_number: bsp::device_driver::IRQNumber, - post_init_callback: fn(), } //-------------------------------------------------------------------------------------------------- @@ -398,16 +396,9 @@ impl PL011Uart { /// # Safety /// /// - The user must ensure to provide a correct MMIO start address. - /// - The user must ensure to provide correct IRQ numbers. - pub const unsafe fn new( - mmio_start_addr: Address, - irq_number: bsp::device_driver::IRQNumber, - post_init_callback: fn(), - ) -> Self { + pub const unsafe fn new(mmio_start_addr: Address) -> Self { Self { inner: IRQSafeNullLock::new(PL011UartInner::new(mmio_start_addr)), - irq_number, - post_init_callback, } } } @@ -418,27 +409,28 @@ impl PL011Uart { use synchronization::interface::Mutex; impl driver::interface::DeviceDriver for PL011Uart { + type IRQNumberType = IRQNumber; + fn compatible(&self) -> &'static str { Self::COMPATIBLE } unsafe fn init(&self) -> Result<(), &'static str> { self.inner.lock(|inner| inner.init()); - (self.post_init_callback)(); Ok(()) } - fn register_and_enable_irq_handler(&'static self) -> Result<(), &'static str> { - use exception::asynchronous::{irq_manager, IRQDescriptor}; + fn register_and_enable_irq_handler( + &'static self, + irq_number: &Self::IRQNumberType, + ) -> Result<(), &'static str> { + use exception::asynchronous::{irq_manager, IRQHandlerDescriptor}; - let descriptor = IRQDescriptor { - name: Self::COMPATIBLE, - handler: self, - }; + let descriptor = IRQHandlerDescriptor::new(*irq_number, Self::COMPATIBLE, self); - irq_manager().register_handler(self.irq_number, descriptor)?; - irq_manager().enable(self.irq_number); + irq_manager().register_handler(descriptor)?; + irq_manager().enable(irq_number); Ok(()) } diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/common.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/common.rs index 69f038d4..ca7aeb76 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/common.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/common.rs @@ -5,7 +5,7 @@ //! Common device driver code. use crate::memory::{Address, Virtual}; -use core::{marker::PhantomData, ops}; +use core::{fmt, marker::PhantomData, ops}; //-------------------------------------------------------------------------------------------------- // Public Definitions @@ -16,6 +16,10 @@ pub struct MMIODerefWrapper { phantom: PhantomData T>, } +/// A wrapper type for usize with integrated range bound check. +#[derive(Copy, Clone)] +pub struct BoundedUsize(usize); + //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- @@ -37,3 +41,25 @@ impl ops::Deref for MMIODerefWrapper { unsafe { &*(self.start_addr.as_usize() as *const _) } } } + +impl BoundedUsize<{ MAX_INCLUSIVE }> { + pub const MAX_INCLUSIVE: usize = MAX_INCLUSIVE; + + /// Creates a new instance if number <= MAX_INCLUSIVE. + pub const fn new(number: usize) -> Self { + assert!(number <= MAX_INCLUSIVE); + + Self(number) + } + + /// Return the wrapped number. + pub const fn get(self) -> usize { + self.0 + } +} + +impl fmt::Display for BoundedUsize<{ MAX_INCLUSIVE }> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.0) + } +} diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/driver.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/driver.rs index e1db4a00..ca3435aa 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/driver.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/driver.rs @@ -7,34 +7,16 @@ use super::{exception, memory::map::mmio}; use crate::{ bsp::device_driver, - console, driver, exception as generic_exception, memory, + console, driver as generic_driver, + exception::{self as generic_exception}, + memory, memory::mmu::MMIODescriptor, - synchronization::{interface::ReadWriteEx, InitStateLock}, }; use core::{ mem::MaybeUninit, sync::atomic::{AtomicBool, Ordering}, }; -pub use device_driver::IRQNumber; - -//-------------------------------------------------------------------------------------------------- -// Private Definitions -//-------------------------------------------------------------------------------------------------- - -/// Device Driver Manager type. -struct BSPDriverManager { - device_drivers: InitStateLock<[Option<&'static (dyn DeviceDriver + Sync)>; NUM_DRIVERS]>, - init_done: AtomicBool, -} - -//-------------------------------------------------------------------------------------------------- -// Public Definitions -//-------------------------------------------------------------------------------------------------- - -/// The number of active drivers provided by this BSP. -pub const NUM_DRIVERS: usize = 3; - //-------------------------------------------------------------------------------------------------- // Global instances //-------------------------------------------------------------------------------------------------- @@ -49,150 +31,154 @@ static mut INTERRUPT_CONTROLLER: MaybeUninit #[cfg(feature = "bsp_rpi4")] static mut INTERRUPT_CONTROLLER: MaybeUninit = MaybeUninit::uninit(); -static BSP_DRIVER_MANAGER: BSPDriverManager = BSPDriverManager { - device_drivers: InitStateLock::new([None; NUM_DRIVERS]), - init_done: AtomicBool::new(false), -}; - //-------------------------------------------------------------------------------------------------- // Private Code //-------------------------------------------------------------------------------------------------- -impl BSPDriverManager { - unsafe fn instantiate_uart(&self) -> Result<(), &'static str> { - let mmio_descriptor = MMIODescriptor::new(mmio::PL011_UART_START, mmio::PL011_UART_SIZE); - let virt_addr = - memory::mmu::kernel_map_mmio(device_driver::PL011Uart::COMPATIBLE, &mmio_descriptor)?; +/// This must be called only after successful init of the memory subsystem. +unsafe fn instantiate_uart() -> Result<(), &'static str> { + let mmio_descriptor = MMIODescriptor::new(mmio::PL011_UART_START, mmio::PL011_UART_SIZE); + let virt_addr = + memory::mmu::kernel_map_mmio(device_driver::PL011Uart::COMPATIBLE, &mmio_descriptor)?; - // This is safe to do, because it is only called from the init'ed instance itself. - fn uart_post_init() { - console::register_console(unsafe { PL011_UART.assume_init_ref() }); - } + PL011_UART.write(device_driver::PL011Uart::new(virt_addr)); - PL011_UART.write(device_driver::PL011Uart::new( - virt_addr, - exception::asynchronous::irq_map::PL011_UART, - uart_post_init, - )); + Ok(()) +} - Ok(()) - } +/// This must be called only after successful init of the UART driver. +unsafe fn post_init_uart() -> Result<(), &'static str> { + console::register_console(PL011_UART.assume_init_ref()); - unsafe fn instantiate_gpio(&self) -> Result<(), &'static str> { - let mmio_descriptor = MMIODescriptor::new(mmio::GPIO_START, mmio::GPIO_SIZE); - let virt_addr = - memory::mmu::kernel_map_mmio(device_driver::GPIO::COMPATIBLE, &mmio_descriptor)?; + Ok(()) +} - // This is safe to do, because it is only called from the init'ed instance itself. - fn gpio_post_init() { - unsafe { GPIO.assume_init_ref().map_pl011_uart() }; - } +/// This must be called only after successful init of the memory subsystem. +unsafe fn instantiate_gpio() -> Result<(), &'static str> { + let mmio_descriptor = MMIODescriptor::new(mmio::GPIO_START, mmio::GPIO_SIZE); + let virt_addr = + memory::mmu::kernel_map_mmio(device_driver::GPIO::COMPATIBLE, &mmio_descriptor)?; - GPIO.write(device_driver::GPIO::new(virt_addr, gpio_post_init)); + GPIO.write(device_driver::GPIO::new(virt_addr)); - Ok(()) - } + Ok(()) +} - #[cfg(feature = "bsp_rpi3")] - unsafe fn instantiate_interrupt_controller(&self) -> Result<(), &'static str> { - let periph_mmio_descriptor = - MMIODescriptor::new(mmio::PERIPHERAL_IC_START, mmio::PERIPHERAL_IC_SIZE); - let periph_virt_addr = memory::mmu::kernel_map_mmio( - device_driver::InterruptController::COMPATIBLE, - &periph_mmio_descriptor, - )?; - - // This is safe to do, because it is only called from the init'ed instance itself. - fn interrupt_controller_post_init() { - generic_exception::asynchronous::register_irq_manager(unsafe { - INTERRUPT_CONTROLLER.assume_init_ref() - }); - } - - INTERRUPT_CONTROLLER.write(device_driver::InterruptController::new( - periph_virt_addr, - interrupt_controller_post_init, - )); - - Ok(()) - } +/// This must be called only after successful init of the GPIO driver. +unsafe fn post_init_gpio() -> Result<(), &'static str> { + GPIO.assume_init_ref().map_pl011_uart(); + Ok(()) +} + +/// This must be called only after successful init of the memory subsystem. +#[cfg(feature = "bsp_rpi3")] +unsafe fn instantiate_interrupt_controller() -> Result<(), &'static str> { + let periph_mmio_descriptor = + MMIODescriptor::new(mmio::PERIPHERAL_IC_START, mmio::PERIPHERAL_IC_SIZE); + let periph_virt_addr = memory::mmu::kernel_map_mmio( + device_driver::InterruptController::COMPATIBLE, + &periph_mmio_descriptor, + )?; + + INTERRUPT_CONTROLLER.write(device_driver::InterruptController::new(periph_virt_addr)); - #[cfg(feature = "bsp_rpi4")] - unsafe fn instantiate_interrupt_controller(&self) -> Result<(), &'static str> { - let gicd_mmio_descriptor = MMIODescriptor::new(mmio::GICD_START, mmio::GICD_SIZE); - let gicd_virt_addr = memory::mmu::kernel_map_mmio("GICv2 GICD", &gicd_mmio_descriptor)?; + Ok(()) +} - let gicc_mmio_descriptor = MMIODescriptor::new(mmio::GICC_START, mmio::GICC_SIZE); - let gicc_virt_addr = memory::mmu::kernel_map_mmio("GICV2 GICC", &gicc_mmio_descriptor)?; +/// This must be called only after successful init of the memory subsystem. +#[cfg(feature = "bsp_rpi4")] +unsafe fn instantiate_interrupt_controller() -> Result<(), &'static str> { + let gicd_mmio_descriptor = MMIODescriptor::new(mmio::GICD_START, mmio::GICD_SIZE); + let gicd_virt_addr = memory::mmu::kernel_map_mmio("GICv2 GICD", &gicd_mmio_descriptor)?; - // This is safe to do, because it is only called from the init'ed instance itself. - fn interrupt_controller_post_init() { - generic_exception::asynchronous::register_irq_manager(unsafe { - INTERRUPT_CONTROLLER.assume_init_ref() - }); - } + let gicc_mmio_descriptor = MMIODescriptor::new(mmio::GICC_START, mmio::GICC_SIZE); + let gicc_virt_addr = memory::mmu::kernel_map_mmio("GICV2 GICC", &gicc_mmio_descriptor)?; - INTERRUPT_CONTROLLER.write(device_driver::GICv2::new( - gicd_virt_addr, - gicc_virt_addr, - interrupt_controller_post_init, - )); + INTERRUPT_CONTROLLER.write(device_driver::GICv2::new(gicd_virt_addr, gicc_virt_addr)); - Ok(()) - } + Ok(()) +} - unsafe fn register_drivers(&self) { - self.device_drivers.write(|drivers| { - drivers[0] = Some(PL011_UART.assume_init_ref()); - drivers[1] = Some(GPIO.assume_init_ref()); - drivers[2] = Some(INTERRUPT_CONTROLLER.assume_init_ref()); - }); - } +/// This must be called only after successful init of the interrupt controller driver. +unsafe fn post_init_interrupt_controller() -> Result<(), &'static str> { + generic_exception::asynchronous::register_irq_manager(INTERRUPT_CONTROLLER.assume_init_ref()); + + Ok(()) } -//-------------------------------------------------------------------------------------------------- -// Public Code -//-------------------------------------------------------------------------------------------------- +/// Function needs to ensure that driver registration happens only after correct instantiation. +unsafe fn driver_uart() -> Result<(), &'static str> { + instantiate_uart()?; + + let uart_descriptor = generic_driver::DeviceDriverDescriptor::new( + PL011_UART.assume_init_ref(), + Some(post_init_uart), + Some(exception::asynchronous::irq_map::PL011_UART), + ); + generic_driver::driver_manager().register_driver(uart_descriptor); + + Ok(()) +} + +/// Function needs to ensure that driver registration happens only after correct instantiation. +unsafe fn driver_gpio() -> Result<(), &'static str> { + instantiate_gpio()?; + + let gpio_descriptor = generic_driver::DeviceDriverDescriptor::new( + GPIO.assume_init_ref(), + Some(post_init_gpio), + None, + ); + generic_driver::driver_manager().register_driver(gpio_descriptor); -/// Return a reference to the driver manager. -pub fn driver_manager() -> &'static impl driver::interface::DriverManager { - &BSP_DRIVER_MANAGER + Ok(()) } -//------------------------------------------------------------------------------ -// OS Interface Code -//------------------------------------------------------------------------------ -use driver::interface::DeviceDriver; +/// Function needs to ensure that driver registration happens only after correct instantiation. +unsafe fn driver_interrupt_controller() -> Result<(), &'static str> { + instantiate_interrupt_controller()?; -impl driver::interface::DriverManager for BSPDriverManager { - unsafe fn instantiate_drivers(&self) -> Result<(), &'static str> { - if self.init_done.load(Ordering::Relaxed) { - return Err("Drivers already instantiated"); - } + let interrupt_controller_descriptor = generic_driver::DeviceDriverDescriptor::new( + INTERRUPT_CONTROLLER.assume_init_ref(), + Some(post_init_interrupt_controller), + None, + ); + generic_driver::driver_manager().register_driver(interrupt_controller_descriptor); - self.instantiate_uart()?; - self.instantiate_gpio()?; - self.instantiate_interrupt_controller()?; + Ok(()) +} - self.register_drivers(); +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- - self.init_done.store(true, Ordering::Relaxed); - Ok(()) +/// Initialize the driver subsystem. +/// +/// # Safety +/// +/// See child function calls. +pub unsafe fn init() -> Result<(), &'static str> { + static INIT_DONE: AtomicBool = AtomicBool::new(false); + if INIT_DONE.load(Ordering::Relaxed) { + return Err("Init already done"); } - fn all_device_drivers(&self) -> [&(dyn DeviceDriver + Sync); NUM_DRIVERS] { - self.device_drivers - .read(|drivers| drivers.map(|drivers| drivers.unwrap())) - } + driver_uart()?; + driver_gpio()?; + driver_interrupt_controller()?; - #[cfg(feature = "test_build")] - fn qemu_bring_up_console(&self) { - use crate::cpu; + INIT_DONE.store(true, Ordering::Relaxed); + Ok(()) +} - unsafe { - self.instantiate_uart() - .unwrap_or_else(|_| cpu::qemu_exit_failure()); - console::register_console(PL011_UART.assume_init_ref()); - }; - } +/// Minimal code needed to bring up the console in QEMU (for testing only). This is often less steps +/// than on real hardware due to QEMU's abstractions. +#[cfg(feature = "test_build")] +pub fn qemu_bring_up_console() { + use crate::cpu; + + unsafe { + instantiate_uart().unwrap_or_else(|_| cpu::qemu_exit_failure()); + console::register_console(PL011_UART.assume_init_ref()); + }; } diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/exception/asynchronous.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/exception/asynchronous.rs index ab20d86d..06a67558 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/exception/asynchronous.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/exception/asynchronous.rs @@ -10,6 +10,9 @@ use crate::bsp; // Public Definitions //-------------------------------------------------------------------------------------------------- +/// Export for reuse in generic asynchronous.rs. +pub use bsp::device_driver::IRQNumber; + #[cfg(feature = "bsp_rpi3")] pub(in crate::bsp) mod irq_map { use super::bsp::device_driver::{IRQNumber, PeripheralIRQ}; diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/driver.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/driver.rs index 98197fef..18066c31 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/driver.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/driver.rs @@ -4,16 +4,37 @@ //! Driver support. +use crate::{ + exception, info, + synchronization::{interface::ReadWriteEx, InitStateLock}, +}; +use core::fmt; + +//-------------------------------------------------------------------------------------------------- +// Private Definitions +//-------------------------------------------------------------------------------------------------- + +const NUM_DRIVERS: usize = 5; + +struct DriverManagerInner +where + T: 'static, +{ + next_index: usize, + descriptors: [Option>; NUM_DRIVERS], +} + //-------------------------------------------------------------------------------------------------- // Public Definitions //-------------------------------------------------------------------------------------------------- /// Driver interfaces. pub mod interface { - use crate::bsp; - /// Device Driver functions. pub trait DeviceDriver { + /// Different interrupt controllers might use different types for IRQ number. + type IRQNumberType: super::fmt::Display; + /// Return a compatibility string for identifying the driver. fn compatible(&self) -> &'static str; @@ -26,32 +47,175 @@ pub mod interface { Ok(()) } - /// Called by the kernel to register and enable the device's IRQ handlers, if any. + /// Called by the kernel to register and enable the device's IRQ handler. /// /// Rust's type system will prevent a call to this function unless the calling instance /// itself has static lifetime. - fn register_and_enable_irq_handler(&'static self) -> Result<(), &'static str> { - Ok(()) + fn register_and_enable_irq_handler( + &'static self, + irq_number: &Self::IRQNumberType, + ) -> Result<(), &'static str> { + panic!( + "Attempt to enable IRQ {} for device {}, but driver does not support this", + irq_number, + self.compatible() + ) + } + } +} + +/// Tpye to be used as an optional callback after a driver's init() has run. +pub type DeviceDriverPostInitCallback = unsafe fn() -> Result<(), &'static str>; + +/// A descriptor for device drivers. +#[derive(Copy, Clone)] +pub struct DeviceDriverDescriptor +where + T: 'static, +{ + device_driver: &'static (dyn interface::DeviceDriver + Sync), + post_init_callback: Option, + irq_number: Option, +} + +/// Provides device driver management functions. +pub struct DriverManager +where + T: 'static, +{ + inner: InitStateLock>, +} + +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +static DRIVER_MANAGER: DriverManager = DriverManager::new(); + +//-------------------------------------------------------------------------------------------------- +// Private Code +//-------------------------------------------------------------------------------------------------- + +impl DriverManagerInner +where + T: 'static + Copy, +{ + /// Create an instance. + pub const fn new() -> Self { + Self { + next_index: 0, + descriptors: [None; NUM_DRIVERS], } } +} - /// Device driver management functions. +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +impl DeviceDriverDescriptor { + /// Create an instance. + pub fn new( + device_driver: &'static (dyn interface::DeviceDriver + Sync), + post_init_callback: Option, + irq_number: Option, + ) -> Self { + Self { + device_driver, + post_init_callback, + irq_number, + } + } +} + +/// Return a reference to the global DriverManager. +pub fn driver_manager() -> &'static DriverManager { + &DRIVER_MANAGER +} + +impl DriverManager +where + T: fmt::Display + Copy, +{ + /// Create an instance. + pub const fn new() -> Self { + Self { + inner: InitStateLock::new(DriverManagerInner::new()), + } + } + + /// Register a device driver with the kernel. + pub fn register_driver(&self, descriptor: DeviceDriverDescriptor) { + self.inner.write(|inner| { + inner.descriptors[inner.next_index] = Some(descriptor); + inner.next_index += 1; + }) + } + + /// Helper for iterating over registered drivers. + fn for_each_descriptor<'a>(&'a self, f: impl FnMut(&'a DeviceDriverDescriptor)) { + self.inner.read(|inner| { + inner + .descriptors + .iter() + .filter_map(|x| x.as_ref()) + .for_each(f) + }) + } + + /// Fully initialize all drivers and their interrupts handlers. /// - /// The `BSP` is supposed to supply one global instance. - pub trait DriverManager { - /// Instantiate all drivers. - /// - /// # Safety - /// - /// Must be called before `all_device_drivers`. - unsafe fn instantiate_drivers(&self) -> Result<(), &'static str>; + /// # Safety + /// + /// - During init, drivers might do stuff with system-wide impact. + pub unsafe fn init_drivers_and_irqs(&self) { + self.for_each_descriptor(|descriptor| { + // 1. Initialize driver. + if let Err(x) = descriptor.device_driver.init() { + panic!( + "Error initializing driver: {}: {}", + descriptor.device_driver.compatible(), + x + ); + } + + // 2. Call corresponding post init callback. + if let Some(callback) = &descriptor.post_init_callback { + if let Err(x) = callback() { + panic!( + "Error during driver post-init callback: {}: {}", + descriptor.device_driver.compatible(), + x + ); + } + } + }); + + // 3. After all post-init callbacks were done, the interrupt controller should be + // registered and functional. So let drivers register with it now. + self.for_each_descriptor(|descriptor| { + if let Some(irq_number) = &descriptor.irq_number { + if let Err(x) = descriptor + .device_driver + .register_and_enable_irq_handler(irq_number) + { + panic!( + "Error during driver interrupt handler registration: {}: {}", + descriptor.device_driver.compatible(), + x + ); + } + } + }); + } - /// Return a slice of references to all `BSP`-instantiated drivers. - fn all_device_drivers(&self) -> [&(dyn DeviceDriver + Sync); bsp::driver::NUM_DRIVERS]; + /// Enumerate all registered device drivers. + pub fn enumerate(&self) { + let mut i: usize = 1; + self.for_each_descriptor(|descriptor| { + info!(" {}. {}", i, descriptor.device_driver.compatible()); - /// Minimal code needed to bring up the console in QEMU (for testing only). This is often - /// less steps than on real hardware due to QEMU's abstractions. - #[cfg(feature = "test_build")] - fn qemu_bring_up_console(&self); + i += 1; + }); } } diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/exception/asynchronous.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/exception/asynchronous.rs index 83ca1aa6..c1f2a27b 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/exception/asynchronous.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/exception/asynchronous.rs @@ -10,7 +10,7 @@ mod arch_asynchronous; mod null_irq_manager; use crate::{bsp, synchronization}; -use core::{fmt, marker::PhantomData}; +use core::marker::PhantomData; //-------------------------------------------------------------------------------------------------- // Architectural Public Reexports @@ -24,14 +24,23 @@ pub use arch_asynchronous::{ // Public Definitions //-------------------------------------------------------------------------------------------------- +/// Interrupt number as defined by the BSP. +pub type IRQNumber = bsp::exception::asynchronous::IRQNumber; + /// Interrupt descriptor. #[derive(Copy, Clone)] -pub struct IRQDescriptor { +pub struct IRQHandlerDescriptor +where + T: Copy, +{ + /// The IRQ number. + number: T, + /// Descriptive name. - pub name: &'static str, + name: &'static str, /// Reference to handler trait object. - pub handler: &'static (dyn interface::IRQHandler + Sync), + handler: &'static (dyn interface::IRQHandler + Sync), } /// IRQContext token. @@ -61,17 +70,16 @@ pub mod interface { /// platform's interrupt controller. pub trait IRQManager { /// The IRQ number type depends on the implementation. - type IRQNumberType; + type IRQNumberType: Copy; /// Register a handler. fn register_handler( &self, - irq_number: Self::IRQNumberType, - descriptor: super::IRQDescriptor, + irq_handler_descriptor: super::IRQHandlerDescriptor, ) -> Result<(), &'static str>; /// Enable an interrupt in the controller. - fn enable(&self, irq_number: Self::IRQNumberType); + fn enable(&self, irq_number: &Self::IRQNumberType); /// Handle pending interrupts. /// @@ -91,16 +99,12 @@ pub mod interface { } } -/// A wrapper type for IRQ numbers with integrated range sanity check. -#[derive(Copy, Clone)] -pub struct IRQNumber(usize); - //-------------------------------------------------------------------------------------------------- // Global instances //-------------------------------------------------------------------------------------------------- static CUR_IRQ_MANAGER: InitStateLock< - &'static (dyn interface::IRQManager + Sync), + &'static (dyn interface::IRQManager + Sync), > = InitStateLock::new(&null_irq_manager::NULL_IRQ_MANAGER); //-------------------------------------------------------------------------------------------------- @@ -108,6 +112,39 @@ static CUR_IRQ_MANAGER: InitStateLock< //-------------------------------------------------------------------------------------------------- use synchronization::{interface::ReadWriteEx, InitStateLock}; +impl IRQHandlerDescriptor +where + T: Copy, +{ + /// Create an instance. + pub const fn new( + number: T, + name: &'static str, + handler: &'static (dyn interface::IRQHandler + Sync), + ) -> Self { + Self { + number, + name, + handler, + } + } + + /// Return the number. + pub const fn number(&self) -> T { + self.number + } + + /// Return the name. + pub const fn name(&self) -> &'static str { + self.name + } + + /// Return the handler. + pub const fn handler(&self) -> &'static (dyn interface::IRQHandler + Sync) { + self.handler + } +} + impl<'irq_context> IRQContext<'irq_context> { /// Creates an IRQContext token. /// @@ -125,29 +162,6 @@ impl<'irq_context> IRQContext<'irq_context> { } } -impl IRQNumber<{ MAX_INCLUSIVE }> { - /// The total number of IRQs this type supports. - pub const NUM_TOTAL: usize = MAX_INCLUSIVE + 1; - - /// Creates a new instance if number <= MAX_INCLUSIVE. - pub const fn new(number: usize) -> Self { - assert!(number <= MAX_INCLUSIVE); - - Self(number) - } - - /// Return the wrapped number. - pub const fn get(self) -> usize { - self.0 - } -} - -impl fmt::Display for IRQNumber<{ MAX_INCLUSIVE }> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}", self.0) - } -} - /// Executes the provided closure while IRQs are masked on the executing core. /// /// While the function temporarily changes the HW state of the executing core, it restores it to the @@ -163,8 +177,7 @@ pub fn exec_with_irq_masked(f: impl FnOnce() -> T) -> T { /// Register a new IRQ manager. pub fn register_irq_manager( - new_manager: &'static (dyn interface::IRQManager - + Sync), + new_manager: &'static (dyn interface::IRQManager + Sync), ) { CUR_IRQ_MANAGER.write(|manager| *manager = new_manager); } @@ -172,6 +185,6 @@ pub fn register_irq_manager( /// Return a reference to the currently registered IRQ manager. /// /// This is the IRQ manager used by the architectural interrupt handling code. -pub fn irq_manager() -> &'static dyn interface::IRQManager { +pub fn irq_manager() -> &'static dyn interface::IRQManager { CUR_IRQ_MANAGER.read(|manager| *manager) } diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/exception/asynchronous/null_irq_manager.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/exception/asynchronous/null_irq_manager.rs index 560e3ce4..438f9649 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/exception/asynchronous/null_irq_manager.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/exception/asynchronous/null_irq_manager.rs @@ -4,8 +4,7 @@ //! Null IRQ Manager. -use super::{interface, IRQContext, IRQDescriptor}; -use crate::bsp; +use super::{interface, IRQContext, IRQHandlerDescriptor}; //-------------------------------------------------------------------------------------------------- // Public Definitions @@ -24,17 +23,16 @@ pub static NULL_IRQ_MANAGER: NullIRQManager = NullIRQManager {}; //-------------------------------------------------------------------------------------------------- impl interface::IRQManager for NullIRQManager { - type IRQNumberType = bsp::driver::IRQNumber; + type IRQNumberType = super::IRQNumber; fn register_handler( &self, - _irq_number: Self::IRQNumberType, - _descriptor: IRQDescriptor, + _descriptor: IRQHandlerDescriptor, ) -> Result<(), &'static str> { panic!("No IRQ Manager registered yet"); } - fn enable(&self, _irq_number: Self::IRQNumberType) { + fn enable(&self, _irq_number: &Self::IRQNumberType) { panic!("No IRQ Manager registered yet"); } diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/lib.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/lib.rs index 26c147d6..197b1f41 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/lib.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/lib.rs @@ -186,11 +186,9 @@ pub fn test_runner(tests: &[&test_types::UnitTest]) { #[cfg(test)] #[no_mangle] unsafe fn kernel_init() -> ! { - use driver::interface::DriverManager; - exception::handling_init(); memory::init(); - bsp::driver::driver_manager().qemu_bring_up_console(); + bsp::driver::qemu_bring_up_console(); test_main(); diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/main.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/main.rs index 9aeb4438..65905258 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/main.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/main.rs @@ -13,7 +13,7 @@ #![no_main] #![no_std] -use libkernel::{bsp, cpu, driver, exception, info, memory, state, time, warn}; +use libkernel::{bsp, cpu, driver, exception, info, memory, state, time}; /// Early init code. /// @@ -25,27 +25,16 @@ use libkernel::{bsp, cpu, driver, exception, info, memory, state, time, warn}; /// - Printing will not work until the respective driver's MMIO is remapped. #[no_mangle] unsafe fn kernel_init() -> ! { - use driver::interface::DriverManager; - exception::handling_init(); memory::init(); - // Instantiate and init all device drivers. - if let Err(x) = bsp::driver::driver_manager().instantiate_drivers() { - panic!("Error instantiating drivers: {}", x); - } - for i in bsp::driver::driver_manager().all_device_drivers().iter() { - if let Err(x) = i.init() { - panic!("Error loading driver: {}: {}", i.compatible(), x); - } + // Initialize the BSP driver subsystem. + if let Err(x) = bsp::driver::init() { + panic!("Error initializing BSP driver subsystem: {}", x); } - // Let device drivers register and enable their handlers with the interrupt controller. - for i in bsp::driver::driver_manager().all_device_drivers() { - if let Err(msg) = i.register_and_enable_irq_handler() { - warn!("Error registering IRQ handler: {}", msg); - } - } + // Initialize all device drivers. + driver::driver_manager().init_drivers_and_irqs(); bsp::memory::mmu::kernel_add_mapping_records_for_precomputed(); @@ -61,8 +50,6 @@ unsafe fn kernel_init() -> ! { /// The main function running after the early init. fn kernel_main() -> ! { - use driver::interface::DriverManager; - info!("{}", libkernel::version()); info!("Booting on: {}", bsp::board_name()); @@ -81,13 +68,7 @@ fn kernel_main() -> ! { ); info!("Drivers loaded:"); - for (i, driver) in bsp::driver::driver_manager() - .all_device_drivers() - .iter() - .enumerate() - { - info!(" {}. {}", i + 1, driver.compatible()); - } + driver::driver_manager().enumerate(); info!("Registered IRQ handlers:"); exception::asynchronous::irq_manager().print_handler(); diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/tests/00_console_sanity.rs b/15_virtual_mem_part3_precomputed_tables/kernel/tests/00_console_sanity.rs index 305510ce..2c0225b7 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/tests/00_console_sanity.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/tests/00_console_sanity.rs @@ -11,16 +11,15 @@ /// Console tests should time out on the I/O harness in case of panic. mod panic_wait_forever; -use libkernel::{bsp, console, cpu, driver, exception, memory, print}; +use libkernel::{bsp, console, cpu, exception, memory, print}; #[no_mangle] unsafe fn kernel_init() -> ! { use console::console; - use driver::interface::DriverManager; exception::handling_init(); memory::init(); - bsp::driver::driver_manager().qemu_bring_up_console(); + bsp::driver::qemu_bring_up_console(); // Handshake assert_eq!(console().read_char(), 'A'); diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/tests/01_timer_sanity.rs b/15_virtual_mem_part3_precomputed_tables/kernel/tests/01_timer_sanity.rs index 39899332..8188b942 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/tests/01_timer_sanity.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/tests/01_timer_sanity.rs @@ -11,16 +11,14 @@ #![test_runner(libkernel::test_runner)] use core::time::Duration; -use libkernel::{bsp, cpu, driver, exception, memory, time}; +use libkernel::{bsp, cpu, exception, memory, time}; use test_macros::kernel_test; #[no_mangle] unsafe fn kernel_init() -> ! { - use driver::interface::DriverManager; - exception::handling_init(); memory::init(); - bsp::driver::driver_manager().qemu_bring_up_console(); + bsp::driver::qemu_bring_up_console(); // Depending on CPU arch, some timer bring-up code could go here. Not needed for the RPi. diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/tests/02_exception_sync_page_fault.rs b/15_virtual_mem_part3_precomputed_tables/kernel/tests/02_exception_sync_page_fault.rs index ec7a365a..c4b801ce 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/tests/02_exception_sync_page_fault.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/tests/02_exception_sync_page_fault.rs @@ -17,15 +17,13 @@ /// or indirectly. mod panic_exit_success; -use libkernel::{bsp, cpu, driver, exception, info, memory, println}; +use libkernel::{bsp, cpu, exception, info, memory, println}; #[no_mangle] unsafe fn kernel_init() -> ! { - use driver::interface::DriverManager; - exception::handling_init(); memory::init(); - bsp::driver::driver_manager().qemu_bring_up_console(); + bsp::driver::qemu_bring_up_console(); // This line will be printed as the test header. println!("Testing synchronous exception handling by causing a page fault"); diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/tests/03_exception_restore_sanity.rs b/15_virtual_mem_part3_precomputed_tables/kernel/tests/03_exception_restore_sanity.rs index 47dd2714..f176c6a6 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/tests/03_exception_restore_sanity.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/tests/03_exception_restore_sanity.rs @@ -12,7 +12,7 @@ mod panic_wait_forever; use core::arch::asm; -use libkernel::{bsp, cpu, driver, exception, info, memory, println}; +use libkernel::{bsp, cpu, exception, info, memory, println}; #[inline(never)] fn nested_system_call() { @@ -30,11 +30,9 @@ fn nested_system_call() { #[no_mangle] unsafe fn kernel_init() -> ! { - use driver::interface::DriverManager; - exception::handling_init(); memory::init(); - bsp::driver::driver_manager().qemu_bring_up_console(); + bsp::driver::qemu_bring_up_console(); // This line will be printed as the test header. println!("Testing exception restore"); diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/tests/04_exception_irq_sanity.rs b/15_virtual_mem_part3_precomputed_tables/kernel/tests/04_exception_irq_sanity.rs index e93a4caf..e6f94c91 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/tests/04_exception_irq_sanity.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/tests/04_exception_irq_sanity.rs @@ -10,15 +10,13 @@ #![reexport_test_harness_main = "test_main"] #![test_runner(libkernel::test_runner)] -use libkernel::{bsp, cpu, driver, exception, memory}; +use libkernel::{bsp, cpu, exception, memory}; use test_macros::kernel_test; #[no_mangle] unsafe fn kernel_init() -> ! { - use driver::interface::DriverManager; - memory::init(); - bsp::driver::driver_manager().qemu_bring_up_console(); + bsp::driver::qemu_bring_up_console(); exception::handling_init(); exception::asynchronous::local_irq_unmask(); diff --git a/16_virtual_mem_part4_higher_half_kernel/Makefile b/16_virtual_mem_part4_higher_half_kernel/Makefile index 2e0a3462..4092ec8f 100644 --- a/16_virtual_mem_part4_higher_half_kernel/Makefile +++ b/16_virtual_mem_part4_higher_half_kernel/Makefile @@ -310,7 +310,7 @@ test_boot: $(KERNEL_BIN) ## Helpers for unit and integration test targets ##------------------------------------------------------------------------------ define KERNEL_TEST_RUNNER - #!/usr/bin/env bash +#!/usr/bin/env bash # The cargo test runner seems to change into the crate under test's directory. Therefore, ensure # this script executes from the root. diff --git a/16_virtual_mem_part4_higher_half_kernel/README.md b/16_virtual_mem_part4_higher_half_kernel/README.md index 494506da..8082ab45 100644 --- a/16_virtual_mem_part4_higher_half_kernel/README.md +++ b/16_virtual_mem_part4_higher_half_kernel/README.md @@ -817,7 +817,7 @@ diff -uNr 15_virtual_mem_part3_precomputed_tables/kernel/src/memory/mmu.rs 16_vi diff -uNr 15_virtual_mem_part3_precomputed_tables/kernel/tests/02_exception_sync_page_fault.rs 16_virtual_mem_part4_higher_half_kernel/kernel/tests/02_exception_sync_page_fault.rs --- 15_virtual_mem_part3_precomputed_tables/kernel/tests/02_exception_sync_page_fault.rs +++ 16_virtual_mem_part4_higher_half_kernel/kernel/tests/02_exception_sync_page_fault.rs -@@ -30,8 +30,8 @@ +@@ -28,8 +28,8 @@ // This line will be printed as the test header. println!("Testing synchronous exception handling by causing a page fault"); diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/arm/gicv2.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/arm/gicv2.rs index ec65f1b2..3cc35b5e 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/arm/gicv2.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/arm/gicv2.rs @@ -80,7 +80,8 @@ mod gicc; mod gicd; use crate::{ - bsp, cpu, driver, exception, + bsp::{self, device_driver::common::BoundedUsize}, + cpu, driver, exception, memory::{Address, Virtual}, synchronization, synchronization::InitStateLock, @@ -90,14 +91,15 @@ use crate::{ // Private Definitions //-------------------------------------------------------------------------------------------------- -type HandlerTable = [Option; IRQNumber::NUM_TOTAL]; +type HandlerTable = [Option>; + IRQNumber::MAX_INCLUSIVE + 1]; //-------------------------------------------------------------------------------------------------- // Public Definitions //-------------------------------------------------------------------------------------------------- /// Used for the associated type of trait [`exception::asynchronous::interface::IRQManager`]. -pub type IRQNumber = exception::asynchronous::IRQNumber<{ GICv2::MAX_IRQ_NUMBER }>; +pub type IRQNumber = BoundedUsize<{ GICv2::MAX_IRQ_NUMBER }>; /// Representation of the GIC. pub struct GICv2 { @@ -109,9 +111,6 @@ pub struct GICv2 { /// Stores registered IRQ handlers. Writable only during kernel init. RO afterwards. handler_table: InitStateLock, - - /// Callback to be invoked after successful init. - post_init_callback: fn(), } //-------------------------------------------------------------------------------------------------- @@ -131,13 +130,11 @@ impl GICv2 { pub const unsafe fn new( gicd_mmio_start_addr: Address, gicc_mmio_start_addr: Address, - post_init_callback: fn(), ) -> Self { Self { gicd: gicd::GICD::new(gicd_mmio_start_addr), gicc: gicc::GICC::new(gicc_mmio_start_addr), - handler_table: InitStateLock::new([None; IRQNumber::NUM_TOTAL]), - post_init_callback, + handler_table: InitStateLock::new([None; IRQNumber::MAX_INCLUSIVE + 1]), } } } @@ -148,6 +145,8 @@ impl GICv2 { use synchronization::interface::ReadWriteEx; impl driver::interface::DeviceDriver for GICv2 { + type IRQNumberType = IRQNumber; + fn compatible(&self) -> &'static str { Self::COMPATIBLE } @@ -160,8 +159,6 @@ impl driver::interface::DeviceDriver for GICv2 { self.gicc.priority_accept_all(); self.gicc.enable(); - (self.post_init_callback)(); - Ok(()) } } @@ -171,23 +168,22 @@ impl exception::asynchronous::interface::IRQManager for GICv2 { fn register_handler( &self, - irq_number: Self::IRQNumberType, - descriptor: exception::asynchronous::IRQDescriptor, + irq_handler_descriptor: exception::asynchronous::IRQHandlerDescriptor, ) -> Result<(), &'static str> { self.handler_table.write(|table| { - let irq_number = irq_number.get(); + let irq_number = irq_handler_descriptor.number().get(); if table[irq_number].is_some() { return Err("IRQ handler already registered"); } - table[irq_number] = Some(descriptor); + table[irq_number] = Some(irq_handler_descriptor); Ok(()) }) } - fn enable(&self, irq_number: Self::IRQNumberType) { + fn enable(&self, irq_number: &Self::IRQNumberType) { self.gicd.enable(irq_number); } @@ -210,7 +206,7 @@ impl exception::asynchronous::interface::IRQManager for GICv2 { None => panic!("No handler registered for IRQ {}", irq_number), Some(descriptor) => { // Call the IRQ handler. Panics on failure. - descriptor.handler.handle().expect("Error handling IRQ"); + descriptor.handler().handle().expect("Error handling IRQ"); } } }); @@ -227,7 +223,7 @@ impl exception::asynchronous::interface::IRQManager for GICv2 { self.handler_table.read(|table| { for (i, opt) in table.iter().skip(32).enumerate() { if let Some(handler) = opt { - info!(" {: >3}. {}", i + 32, handler.name); + info!(" {: >3}. {}", i + 32, handler.name()); } } }); diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs index a9c97a8e..8aebcf2b 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs @@ -172,7 +172,7 @@ impl GICD { } /// Enable an interrupt. - pub fn enable(&self, irq_num: super::IRQNumber) { + pub fn enable(&self, irq_num: &super::IRQNumber) { let irq_num = irq_num.get(); // Each bit in the u32 enable register corresponds to one IRQ number. Shift right by 5 diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs index 2281e66a..fb61a651 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs @@ -7,6 +7,7 @@ use crate::{ bsp::device_driver::common::MMIODerefWrapper, driver, + exception::asynchronous::IRQNumber, memory::{Address, Virtual}, synchronization, synchronization::IRQSafeNullLock, @@ -122,7 +123,6 @@ struct GPIOInner { /// Representation of the GPIO HW. pub struct GPIO { inner: IRQSafeNullLock, - post_init_callback: fn(), } //-------------------------------------------------------------------------------------------------- @@ -202,10 +202,9 @@ impl GPIO { /// # Safety /// /// - The user must ensure to provide a correct MMIO start address. - pub const unsafe fn new(mmio_start_addr: Address, post_init_callback: fn()) -> Self { + pub const unsafe fn new(mmio_start_addr: Address) -> Self { Self { inner: IRQSafeNullLock::new(GPIOInner::new(mmio_start_addr)), - post_init_callback, } } @@ -221,13 +220,9 @@ impl GPIO { use synchronization::interface::Mutex; impl driver::interface::DeviceDriver for GPIO { + type IRQNumberType = IRQNumber; + fn compatible(&self) -> &'static str { Self::COMPATIBLE } - - unsafe fn init(&self) -> Result<(), &'static str> { - (self.post_init_callback)(); - - Ok(()) - } } diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs index b4dd530d..c93a9fa1 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs @@ -7,9 +7,12 @@ mod peripheral_ic; use crate::{ - driver, exception, + bsp::device_driver::common::BoundedUsize, + driver, + exception::{self, asynchronous::IRQHandlerDescriptor}, memory::{Address, Virtual}, }; +use core::fmt; //-------------------------------------------------------------------------------------------------- // Private Definitions @@ -24,10 +27,8 @@ struct PendingIRQs { // Public Definitions //-------------------------------------------------------------------------------------------------- -pub type LocalIRQ = - exception::asynchronous::IRQNumber<{ InterruptController::MAX_LOCAL_IRQ_NUMBER }>; -pub type PeripheralIRQ = - exception::asynchronous::IRQNumber<{ InterruptController::MAX_PERIPHERAL_IRQ_NUMBER }>; +pub type LocalIRQ = BoundedUsize<{ InterruptController::MAX_LOCAL_IRQ_NUMBER }>; +pub type PeripheralIRQ = BoundedUsize<{ InterruptController::MAX_PERIPHERAL_IRQ_NUMBER }>; /// Used for the associated type of trait [`exception::asynchronous::interface::IRQManager`]. #[derive(Copy, Clone)] @@ -40,7 +41,6 @@ pub enum IRQNumber { /// Representation of the Interrupt Controller. pub struct InterruptController { periph: peripheral_ic::PeripheralIC, - post_init_callback: fn(), } //-------------------------------------------------------------------------------------------------- @@ -71,6 +71,15 @@ impl Iterator for PendingIRQs { // Public Code //-------------------------------------------------------------------------------------------------- +impl fmt::Display for IRQNumber { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Self::Local(number) => write!(f, "Local({})", number), + Self::Peripheral(number) => write!(f, "Peripheral({})", number), + } + } +} + impl InterruptController { // Restrict to 3 for now. This makes future code for local_ic.rs more straight forward. const MAX_LOCAL_IRQ_NUMBER: usize = 3; @@ -83,13 +92,9 @@ impl InterruptController { /// # Safety /// /// - The user must ensure to provide a correct MMIO start address. - pub const unsafe fn new( - periph_mmio_start_addr: Address, - post_init_callback: fn(), - ) -> Self { + pub const unsafe fn new(periph_mmio_start_addr: Address) -> Self { Self { periph: peripheral_ic::PeripheralIC::new(periph_mmio_start_addr), - post_init_callback, } } } @@ -99,15 +104,11 @@ impl InterruptController { //------------------------------------------------------------------------------ impl driver::interface::DeviceDriver for InterruptController { + type IRQNumberType = IRQNumber; + fn compatible(&self) -> &'static str { Self::COMPATIBLE } - - unsafe fn init(&self) -> Result<(), &'static str> { - (self.post_init_callback)(); - - Ok(()) - } } impl exception::asynchronous::interface::IRQManager for InterruptController { @@ -115,16 +116,23 @@ impl exception::asynchronous::interface::IRQManager for InterruptController { fn register_handler( &self, - irq: Self::IRQNumberType, - descriptor: exception::asynchronous::IRQDescriptor, + irq_handler_descriptor: exception::asynchronous::IRQHandlerDescriptor, ) -> Result<(), &'static str> { - match irq { + match irq_handler_descriptor.number() { IRQNumber::Local(_) => unimplemented!("Local IRQ controller not implemented."), - IRQNumber::Peripheral(pirq) => self.periph.register_handler(pirq, descriptor), + IRQNumber::Peripheral(pirq) => { + let periph_descriptor = IRQHandlerDescriptor::new( + pirq, + irq_handler_descriptor.name(), + irq_handler_descriptor.handler(), + ); + + self.periph.register_handler(periph_descriptor) + } } } - fn enable(&self, irq: Self::IRQNumberType) { + fn enable(&self, irq: &Self::IRQNumberType) { match irq { IRQNumber::Local(_) => unimplemented!("Local IRQ controller not implemented."), IRQNumber::Peripheral(pirq) => self.periph.enable(pirq), diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs index 06802d27..0a20bd87 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs @@ -52,7 +52,8 @@ type WriteOnlyRegisters = MMIODerefWrapper; /// Abstraction for the ReadOnly parts of the associated MMIO registers. type ReadOnlyRegisters = MMIODerefWrapper; -type HandlerTable = [Option; PeripheralIRQ::NUM_TOTAL]; +type HandlerTable = [Option>; + PeripheralIRQ::MAX_INCLUSIVE + 1]; //-------------------------------------------------------------------------------------------------- // Public Definitions @@ -84,7 +85,7 @@ impl PeripheralIC { Self { wo_registers: IRQSafeNullLock::new(WriteOnlyRegisters::new(mmio_start_addr)), ro_registers: ReadOnlyRegisters::new(mmio_start_addr), - handler_table: InitStateLock::new([None; PeripheralIRQ::NUM_TOTAL]), + handler_table: InitStateLock::new([None; PeripheralIRQ::MAX_INCLUSIVE + 1]), } } @@ -107,23 +108,22 @@ impl exception::asynchronous::interface::IRQManager for PeripheralIC { fn register_handler( &self, - irq: Self::IRQNumberType, - descriptor: exception::asynchronous::IRQDescriptor, + irq_handler_descriptor: exception::asynchronous::IRQHandlerDescriptor, ) -> Result<(), &'static str> { self.handler_table.write(|table| { - let irq_number = irq.get(); + let irq_number = irq_handler_descriptor.number().get(); if table[irq_number].is_some() { return Err("IRQ handler already registered"); } - table[irq_number] = Some(descriptor); + table[irq_number] = Some(irq_handler_descriptor); Ok(()) }) } - fn enable(&self, irq: Self::IRQNumberType) { + fn enable(&self, irq: &Self::IRQNumberType) { self.wo_registers.lock(|regs| { let enable_reg = if irq.get() <= 31 { ®s.ENABLE_1 @@ -149,7 +149,7 @@ impl exception::asynchronous::interface::IRQManager for PeripheralIC { None => panic!("No handler registered for IRQ {}", irq_number), Some(descriptor) => { // Call the IRQ handler. Panics on failure. - descriptor.handler.handle().expect("Error handling IRQ"); + descriptor.handler().handle().expect("Error handling IRQ"); } } } @@ -164,7 +164,7 @@ impl exception::asynchronous::interface::IRQManager for PeripheralIC { self.handler_table.read(|table| { for (i, opt) in table.iter().enumerate() { if let Some(handler) = opt { - info!(" {: >3}. {}", i, handler.name); + info!(" {: >3}. {}", i, handler.name()); } } }); diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs index f67d70df..0ee7feb7 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs @@ -10,9 +10,9 @@ //! - use crate::{ - bsp, bsp::device_driver::common::MMIODerefWrapper, - console, cpu, driver, exception, + console, cpu, driver, + exception::{self, asynchronous::IRQNumber}, memory::{Address, Virtual}, synchronization, synchronization::IRQSafeNullLock, @@ -233,8 +233,6 @@ struct PL011UartInner { /// Representation of the UART. pub struct PL011Uart { inner: IRQSafeNullLock, - irq_number: bsp::device_driver::IRQNumber, - post_init_callback: fn(), } //-------------------------------------------------------------------------------------------------- @@ -398,16 +396,9 @@ impl PL011Uart { /// # Safety /// /// - The user must ensure to provide a correct MMIO start address. - /// - The user must ensure to provide correct IRQ numbers. - pub const unsafe fn new( - mmio_start_addr: Address, - irq_number: bsp::device_driver::IRQNumber, - post_init_callback: fn(), - ) -> Self { + pub const unsafe fn new(mmio_start_addr: Address) -> Self { Self { inner: IRQSafeNullLock::new(PL011UartInner::new(mmio_start_addr)), - irq_number, - post_init_callback, } } } @@ -418,27 +409,28 @@ impl PL011Uart { use synchronization::interface::Mutex; impl driver::interface::DeviceDriver for PL011Uart { + type IRQNumberType = IRQNumber; + fn compatible(&self) -> &'static str { Self::COMPATIBLE } unsafe fn init(&self) -> Result<(), &'static str> { self.inner.lock(|inner| inner.init()); - (self.post_init_callback)(); Ok(()) } - fn register_and_enable_irq_handler(&'static self) -> Result<(), &'static str> { - use exception::asynchronous::{irq_manager, IRQDescriptor}; + fn register_and_enable_irq_handler( + &'static self, + irq_number: &Self::IRQNumberType, + ) -> Result<(), &'static str> { + use exception::asynchronous::{irq_manager, IRQHandlerDescriptor}; - let descriptor = IRQDescriptor { - name: Self::COMPATIBLE, - handler: self, - }; + let descriptor = IRQHandlerDescriptor::new(*irq_number, Self::COMPATIBLE, self); - irq_manager().register_handler(self.irq_number, descriptor)?; - irq_manager().enable(self.irq_number); + irq_manager().register_handler(descriptor)?; + irq_manager().enable(irq_number); Ok(()) } diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/common.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/common.rs index 69f038d4..ca7aeb76 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/common.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/common.rs @@ -5,7 +5,7 @@ //! Common device driver code. use crate::memory::{Address, Virtual}; -use core::{marker::PhantomData, ops}; +use core::{fmt, marker::PhantomData, ops}; //-------------------------------------------------------------------------------------------------- // Public Definitions @@ -16,6 +16,10 @@ pub struct MMIODerefWrapper { phantom: PhantomData T>, } +/// A wrapper type for usize with integrated range bound check. +#[derive(Copy, Clone)] +pub struct BoundedUsize(usize); + //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- @@ -37,3 +41,25 @@ impl ops::Deref for MMIODerefWrapper { unsafe { &*(self.start_addr.as_usize() as *const _) } } } + +impl BoundedUsize<{ MAX_INCLUSIVE }> { + pub const MAX_INCLUSIVE: usize = MAX_INCLUSIVE; + + /// Creates a new instance if number <= MAX_INCLUSIVE. + pub const fn new(number: usize) -> Self { + assert!(number <= MAX_INCLUSIVE); + + Self(number) + } + + /// Return the wrapped number. + pub const fn get(self) -> usize { + self.0 + } +} + +impl fmt::Display for BoundedUsize<{ MAX_INCLUSIVE }> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.0) + } +} diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi/driver.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi/driver.rs index e1db4a00..ca3435aa 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi/driver.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi/driver.rs @@ -7,34 +7,16 @@ use super::{exception, memory::map::mmio}; use crate::{ bsp::device_driver, - console, driver, exception as generic_exception, memory, + console, driver as generic_driver, + exception::{self as generic_exception}, + memory, memory::mmu::MMIODescriptor, - synchronization::{interface::ReadWriteEx, InitStateLock}, }; use core::{ mem::MaybeUninit, sync::atomic::{AtomicBool, Ordering}, }; -pub use device_driver::IRQNumber; - -//-------------------------------------------------------------------------------------------------- -// Private Definitions -//-------------------------------------------------------------------------------------------------- - -/// Device Driver Manager type. -struct BSPDriverManager { - device_drivers: InitStateLock<[Option<&'static (dyn DeviceDriver + Sync)>; NUM_DRIVERS]>, - init_done: AtomicBool, -} - -//-------------------------------------------------------------------------------------------------- -// Public Definitions -//-------------------------------------------------------------------------------------------------- - -/// The number of active drivers provided by this BSP. -pub const NUM_DRIVERS: usize = 3; - //-------------------------------------------------------------------------------------------------- // Global instances //-------------------------------------------------------------------------------------------------- @@ -49,150 +31,154 @@ static mut INTERRUPT_CONTROLLER: MaybeUninit #[cfg(feature = "bsp_rpi4")] static mut INTERRUPT_CONTROLLER: MaybeUninit = MaybeUninit::uninit(); -static BSP_DRIVER_MANAGER: BSPDriverManager = BSPDriverManager { - device_drivers: InitStateLock::new([None; NUM_DRIVERS]), - init_done: AtomicBool::new(false), -}; - //-------------------------------------------------------------------------------------------------- // Private Code //-------------------------------------------------------------------------------------------------- -impl BSPDriverManager { - unsafe fn instantiate_uart(&self) -> Result<(), &'static str> { - let mmio_descriptor = MMIODescriptor::new(mmio::PL011_UART_START, mmio::PL011_UART_SIZE); - let virt_addr = - memory::mmu::kernel_map_mmio(device_driver::PL011Uart::COMPATIBLE, &mmio_descriptor)?; +/// This must be called only after successful init of the memory subsystem. +unsafe fn instantiate_uart() -> Result<(), &'static str> { + let mmio_descriptor = MMIODescriptor::new(mmio::PL011_UART_START, mmio::PL011_UART_SIZE); + let virt_addr = + memory::mmu::kernel_map_mmio(device_driver::PL011Uart::COMPATIBLE, &mmio_descriptor)?; - // This is safe to do, because it is only called from the init'ed instance itself. - fn uart_post_init() { - console::register_console(unsafe { PL011_UART.assume_init_ref() }); - } + PL011_UART.write(device_driver::PL011Uart::new(virt_addr)); - PL011_UART.write(device_driver::PL011Uart::new( - virt_addr, - exception::asynchronous::irq_map::PL011_UART, - uart_post_init, - )); + Ok(()) +} - Ok(()) - } +/// This must be called only after successful init of the UART driver. +unsafe fn post_init_uart() -> Result<(), &'static str> { + console::register_console(PL011_UART.assume_init_ref()); - unsafe fn instantiate_gpio(&self) -> Result<(), &'static str> { - let mmio_descriptor = MMIODescriptor::new(mmio::GPIO_START, mmio::GPIO_SIZE); - let virt_addr = - memory::mmu::kernel_map_mmio(device_driver::GPIO::COMPATIBLE, &mmio_descriptor)?; + Ok(()) +} - // This is safe to do, because it is only called from the init'ed instance itself. - fn gpio_post_init() { - unsafe { GPIO.assume_init_ref().map_pl011_uart() }; - } +/// This must be called only after successful init of the memory subsystem. +unsafe fn instantiate_gpio() -> Result<(), &'static str> { + let mmio_descriptor = MMIODescriptor::new(mmio::GPIO_START, mmio::GPIO_SIZE); + let virt_addr = + memory::mmu::kernel_map_mmio(device_driver::GPIO::COMPATIBLE, &mmio_descriptor)?; - GPIO.write(device_driver::GPIO::new(virt_addr, gpio_post_init)); + GPIO.write(device_driver::GPIO::new(virt_addr)); - Ok(()) - } + Ok(()) +} - #[cfg(feature = "bsp_rpi3")] - unsafe fn instantiate_interrupt_controller(&self) -> Result<(), &'static str> { - let periph_mmio_descriptor = - MMIODescriptor::new(mmio::PERIPHERAL_IC_START, mmio::PERIPHERAL_IC_SIZE); - let periph_virt_addr = memory::mmu::kernel_map_mmio( - device_driver::InterruptController::COMPATIBLE, - &periph_mmio_descriptor, - )?; - - // This is safe to do, because it is only called from the init'ed instance itself. - fn interrupt_controller_post_init() { - generic_exception::asynchronous::register_irq_manager(unsafe { - INTERRUPT_CONTROLLER.assume_init_ref() - }); - } - - INTERRUPT_CONTROLLER.write(device_driver::InterruptController::new( - periph_virt_addr, - interrupt_controller_post_init, - )); - - Ok(()) - } +/// This must be called only after successful init of the GPIO driver. +unsafe fn post_init_gpio() -> Result<(), &'static str> { + GPIO.assume_init_ref().map_pl011_uart(); + Ok(()) +} + +/// This must be called only after successful init of the memory subsystem. +#[cfg(feature = "bsp_rpi3")] +unsafe fn instantiate_interrupt_controller() -> Result<(), &'static str> { + let periph_mmio_descriptor = + MMIODescriptor::new(mmio::PERIPHERAL_IC_START, mmio::PERIPHERAL_IC_SIZE); + let periph_virt_addr = memory::mmu::kernel_map_mmio( + device_driver::InterruptController::COMPATIBLE, + &periph_mmio_descriptor, + )?; + + INTERRUPT_CONTROLLER.write(device_driver::InterruptController::new(periph_virt_addr)); - #[cfg(feature = "bsp_rpi4")] - unsafe fn instantiate_interrupt_controller(&self) -> Result<(), &'static str> { - let gicd_mmio_descriptor = MMIODescriptor::new(mmio::GICD_START, mmio::GICD_SIZE); - let gicd_virt_addr = memory::mmu::kernel_map_mmio("GICv2 GICD", &gicd_mmio_descriptor)?; + Ok(()) +} - let gicc_mmio_descriptor = MMIODescriptor::new(mmio::GICC_START, mmio::GICC_SIZE); - let gicc_virt_addr = memory::mmu::kernel_map_mmio("GICV2 GICC", &gicc_mmio_descriptor)?; +/// This must be called only after successful init of the memory subsystem. +#[cfg(feature = "bsp_rpi4")] +unsafe fn instantiate_interrupt_controller() -> Result<(), &'static str> { + let gicd_mmio_descriptor = MMIODescriptor::new(mmio::GICD_START, mmio::GICD_SIZE); + let gicd_virt_addr = memory::mmu::kernel_map_mmio("GICv2 GICD", &gicd_mmio_descriptor)?; - // This is safe to do, because it is only called from the init'ed instance itself. - fn interrupt_controller_post_init() { - generic_exception::asynchronous::register_irq_manager(unsafe { - INTERRUPT_CONTROLLER.assume_init_ref() - }); - } + let gicc_mmio_descriptor = MMIODescriptor::new(mmio::GICC_START, mmio::GICC_SIZE); + let gicc_virt_addr = memory::mmu::kernel_map_mmio("GICV2 GICC", &gicc_mmio_descriptor)?; - INTERRUPT_CONTROLLER.write(device_driver::GICv2::new( - gicd_virt_addr, - gicc_virt_addr, - interrupt_controller_post_init, - )); + INTERRUPT_CONTROLLER.write(device_driver::GICv2::new(gicd_virt_addr, gicc_virt_addr)); - Ok(()) - } + Ok(()) +} - unsafe fn register_drivers(&self) { - self.device_drivers.write(|drivers| { - drivers[0] = Some(PL011_UART.assume_init_ref()); - drivers[1] = Some(GPIO.assume_init_ref()); - drivers[2] = Some(INTERRUPT_CONTROLLER.assume_init_ref()); - }); - } +/// This must be called only after successful init of the interrupt controller driver. +unsafe fn post_init_interrupt_controller() -> Result<(), &'static str> { + generic_exception::asynchronous::register_irq_manager(INTERRUPT_CONTROLLER.assume_init_ref()); + + Ok(()) } -//-------------------------------------------------------------------------------------------------- -// Public Code -//-------------------------------------------------------------------------------------------------- +/// Function needs to ensure that driver registration happens only after correct instantiation. +unsafe fn driver_uart() -> Result<(), &'static str> { + instantiate_uart()?; + + let uart_descriptor = generic_driver::DeviceDriverDescriptor::new( + PL011_UART.assume_init_ref(), + Some(post_init_uart), + Some(exception::asynchronous::irq_map::PL011_UART), + ); + generic_driver::driver_manager().register_driver(uart_descriptor); + + Ok(()) +} + +/// Function needs to ensure that driver registration happens only after correct instantiation. +unsafe fn driver_gpio() -> Result<(), &'static str> { + instantiate_gpio()?; + + let gpio_descriptor = generic_driver::DeviceDriverDescriptor::new( + GPIO.assume_init_ref(), + Some(post_init_gpio), + None, + ); + generic_driver::driver_manager().register_driver(gpio_descriptor); -/// Return a reference to the driver manager. -pub fn driver_manager() -> &'static impl driver::interface::DriverManager { - &BSP_DRIVER_MANAGER + Ok(()) } -//------------------------------------------------------------------------------ -// OS Interface Code -//------------------------------------------------------------------------------ -use driver::interface::DeviceDriver; +/// Function needs to ensure that driver registration happens only after correct instantiation. +unsafe fn driver_interrupt_controller() -> Result<(), &'static str> { + instantiate_interrupt_controller()?; -impl driver::interface::DriverManager for BSPDriverManager { - unsafe fn instantiate_drivers(&self) -> Result<(), &'static str> { - if self.init_done.load(Ordering::Relaxed) { - return Err("Drivers already instantiated"); - } + let interrupt_controller_descriptor = generic_driver::DeviceDriverDescriptor::new( + INTERRUPT_CONTROLLER.assume_init_ref(), + Some(post_init_interrupt_controller), + None, + ); + generic_driver::driver_manager().register_driver(interrupt_controller_descriptor); - self.instantiate_uart()?; - self.instantiate_gpio()?; - self.instantiate_interrupt_controller()?; + Ok(()) +} - self.register_drivers(); +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- - self.init_done.store(true, Ordering::Relaxed); - Ok(()) +/// Initialize the driver subsystem. +/// +/// # Safety +/// +/// See child function calls. +pub unsafe fn init() -> Result<(), &'static str> { + static INIT_DONE: AtomicBool = AtomicBool::new(false); + if INIT_DONE.load(Ordering::Relaxed) { + return Err("Init already done"); } - fn all_device_drivers(&self) -> [&(dyn DeviceDriver + Sync); NUM_DRIVERS] { - self.device_drivers - .read(|drivers| drivers.map(|drivers| drivers.unwrap())) - } + driver_uart()?; + driver_gpio()?; + driver_interrupt_controller()?; - #[cfg(feature = "test_build")] - fn qemu_bring_up_console(&self) { - use crate::cpu; + INIT_DONE.store(true, Ordering::Relaxed); + Ok(()) +} - unsafe { - self.instantiate_uart() - .unwrap_or_else(|_| cpu::qemu_exit_failure()); - console::register_console(PL011_UART.assume_init_ref()); - }; - } +/// Minimal code needed to bring up the console in QEMU (for testing only). This is often less steps +/// than on real hardware due to QEMU's abstractions. +#[cfg(feature = "test_build")] +pub fn qemu_bring_up_console() { + use crate::cpu; + + unsafe { + instantiate_uart().unwrap_or_else(|_| cpu::qemu_exit_failure()); + console::register_console(PL011_UART.assume_init_ref()); + }; } diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi/exception/asynchronous.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi/exception/asynchronous.rs index ab20d86d..06a67558 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi/exception/asynchronous.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi/exception/asynchronous.rs @@ -10,6 +10,9 @@ use crate::bsp; // Public Definitions //-------------------------------------------------------------------------------------------------- +/// Export for reuse in generic asynchronous.rs. +pub use bsp::device_driver::IRQNumber; + #[cfg(feature = "bsp_rpi3")] pub(in crate::bsp) mod irq_map { use super::bsp::device_driver::{IRQNumber, PeripheralIRQ}; diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/driver.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/driver.rs index 98197fef..18066c31 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/driver.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/driver.rs @@ -4,16 +4,37 @@ //! Driver support. +use crate::{ + exception, info, + synchronization::{interface::ReadWriteEx, InitStateLock}, +}; +use core::fmt; + +//-------------------------------------------------------------------------------------------------- +// Private Definitions +//-------------------------------------------------------------------------------------------------- + +const NUM_DRIVERS: usize = 5; + +struct DriverManagerInner +where + T: 'static, +{ + next_index: usize, + descriptors: [Option>; NUM_DRIVERS], +} + //-------------------------------------------------------------------------------------------------- // Public Definitions //-------------------------------------------------------------------------------------------------- /// Driver interfaces. pub mod interface { - use crate::bsp; - /// Device Driver functions. pub trait DeviceDriver { + /// Different interrupt controllers might use different types for IRQ number. + type IRQNumberType: super::fmt::Display; + /// Return a compatibility string for identifying the driver. fn compatible(&self) -> &'static str; @@ -26,32 +47,175 @@ pub mod interface { Ok(()) } - /// Called by the kernel to register and enable the device's IRQ handlers, if any. + /// Called by the kernel to register and enable the device's IRQ handler. /// /// Rust's type system will prevent a call to this function unless the calling instance /// itself has static lifetime. - fn register_and_enable_irq_handler(&'static self) -> Result<(), &'static str> { - Ok(()) + fn register_and_enable_irq_handler( + &'static self, + irq_number: &Self::IRQNumberType, + ) -> Result<(), &'static str> { + panic!( + "Attempt to enable IRQ {} for device {}, but driver does not support this", + irq_number, + self.compatible() + ) + } + } +} + +/// Tpye to be used as an optional callback after a driver's init() has run. +pub type DeviceDriverPostInitCallback = unsafe fn() -> Result<(), &'static str>; + +/// A descriptor for device drivers. +#[derive(Copy, Clone)] +pub struct DeviceDriverDescriptor +where + T: 'static, +{ + device_driver: &'static (dyn interface::DeviceDriver + Sync), + post_init_callback: Option, + irq_number: Option, +} + +/// Provides device driver management functions. +pub struct DriverManager +where + T: 'static, +{ + inner: InitStateLock>, +} + +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +static DRIVER_MANAGER: DriverManager = DriverManager::new(); + +//-------------------------------------------------------------------------------------------------- +// Private Code +//-------------------------------------------------------------------------------------------------- + +impl DriverManagerInner +where + T: 'static + Copy, +{ + /// Create an instance. + pub const fn new() -> Self { + Self { + next_index: 0, + descriptors: [None; NUM_DRIVERS], } } +} - /// Device driver management functions. +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +impl DeviceDriverDescriptor { + /// Create an instance. + pub fn new( + device_driver: &'static (dyn interface::DeviceDriver + Sync), + post_init_callback: Option, + irq_number: Option, + ) -> Self { + Self { + device_driver, + post_init_callback, + irq_number, + } + } +} + +/// Return a reference to the global DriverManager. +pub fn driver_manager() -> &'static DriverManager { + &DRIVER_MANAGER +} + +impl DriverManager +where + T: fmt::Display + Copy, +{ + /// Create an instance. + pub const fn new() -> Self { + Self { + inner: InitStateLock::new(DriverManagerInner::new()), + } + } + + /// Register a device driver with the kernel. + pub fn register_driver(&self, descriptor: DeviceDriverDescriptor) { + self.inner.write(|inner| { + inner.descriptors[inner.next_index] = Some(descriptor); + inner.next_index += 1; + }) + } + + /// Helper for iterating over registered drivers. + fn for_each_descriptor<'a>(&'a self, f: impl FnMut(&'a DeviceDriverDescriptor)) { + self.inner.read(|inner| { + inner + .descriptors + .iter() + .filter_map(|x| x.as_ref()) + .for_each(f) + }) + } + + /// Fully initialize all drivers and their interrupts handlers. /// - /// The `BSP` is supposed to supply one global instance. - pub trait DriverManager { - /// Instantiate all drivers. - /// - /// # Safety - /// - /// Must be called before `all_device_drivers`. - unsafe fn instantiate_drivers(&self) -> Result<(), &'static str>; + /// # Safety + /// + /// - During init, drivers might do stuff with system-wide impact. + pub unsafe fn init_drivers_and_irqs(&self) { + self.for_each_descriptor(|descriptor| { + // 1. Initialize driver. + if let Err(x) = descriptor.device_driver.init() { + panic!( + "Error initializing driver: {}: {}", + descriptor.device_driver.compatible(), + x + ); + } + + // 2. Call corresponding post init callback. + if let Some(callback) = &descriptor.post_init_callback { + if let Err(x) = callback() { + panic!( + "Error during driver post-init callback: {}: {}", + descriptor.device_driver.compatible(), + x + ); + } + } + }); + + // 3. After all post-init callbacks were done, the interrupt controller should be + // registered and functional. So let drivers register with it now. + self.for_each_descriptor(|descriptor| { + if let Some(irq_number) = &descriptor.irq_number { + if let Err(x) = descriptor + .device_driver + .register_and_enable_irq_handler(irq_number) + { + panic!( + "Error during driver interrupt handler registration: {}: {}", + descriptor.device_driver.compatible(), + x + ); + } + } + }); + } - /// Return a slice of references to all `BSP`-instantiated drivers. - fn all_device_drivers(&self) -> [&(dyn DeviceDriver + Sync); bsp::driver::NUM_DRIVERS]; + /// Enumerate all registered device drivers. + pub fn enumerate(&self) { + let mut i: usize = 1; + self.for_each_descriptor(|descriptor| { + info!(" {}. {}", i, descriptor.device_driver.compatible()); - /// Minimal code needed to bring up the console in QEMU (for testing only). This is often - /// less steps than on real hardware due to QEMU's abstractions. - #[cfg(feature = "test_build")] - fn qemu_bring_up_console(&self); + i += 1; + }); } } diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/exception/asynchronous.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/exception/asynchronous.rs index 83ca1aa6..c1f2a27b 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/exception/asynchronous.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/exception/asynchronous.rs @@ -10,7 +10,7 @@ mod arch_asynchronous; mod null_irq_manager; use crate::{bsp, synchronization}; -use core::{fmt, marker::PhantomData}; +use core::marker::PhantomData; //-------------------------------------------------------------------------------------------------- // Architectural Public Reexports @@ -24,14 +24,23 @@ pub use arch_asynchronous::{ // Public Definitions //-------------------------------------------------------------------------------------------------- +/// Interrupt number as defined by the BSP. +pub type IRQNumber = bsp::exception::asynchronous::IRQNumber; + /// Interrupt descriptor. #[derive(Copy, Clone)] -pub struct IRQDescriptor { +pub struct IRQHandlerDescriptor +where + T: Copy, +{ + /// The IRQ number. + number: T, + /// Descriptive name. - pub name: &'static str, + name: &'static str, /// Reference to handler trait object. - pub handler: &'static (dyn interface::IRQHandler + Sync), + handler: &'static (dyn interface::IRQHandler + Sync), } /// IRQContext token. @@ -61,17 +70,16 @@ pub mod interface { /// platform's interrupt controller. pub trait IRQManager { /// The IRQ number type depends on the implementation. - type IRQNumberType; + type IRQNumberType: Copy; /// Register a handler. fn register_handler( &self, - irq_number: Self::IRQNumberType, - descriptor: super::IRQDescriptor, + irq_handler_descriptor: super::IRQHandlerDescriptor, ) -> Result<(), &'static str>; /// Enable an interrupt in the controller. - fn enable(&self, irq_number: Self::IRQNumberType); + fn enable(&self, irq_number: &Self::IRQNumberType); /// Handle pending interrupts. /// @@ -91,16 +99,12 @@ pub mod interface { } } -/// A wrapper type for IRQ numbers with integrated range sanity check. -#[derive(Copy, Clone)] -pub struct IRQNumber(usize); - //-------------------------------------------------------------------------------------------------- // Global instances //-------------------------------------------------------------------------------------------------- static CUR_IRQ_MANAGER: InitStateLock< - &'static (dyn interface::IRQManager + Sync), + &'static (dyn interface::IRQManager + Sync), > = InitStateLock::new(&null_irq_manager::NULL_IRQ_MANAGER); //-------------------------------------------------------------------------------------------------- @@ -108,6 +112,39 @@ static CUR_IRQ_MANAGER: InitStateLock< //-------------------------------------------------------------------------------------------------- use synchronization::{interface::ReadWriteEx, InitStateLock}; +impl IRQHandlerDescriptor +where + T: Copy, +{ + /// Create an instance. + pub const fn new( + number: T, + name: &'static str, + handler: &'static (dyn interface::IRQHandler + Sync), + ) -> Self { + Self { + number, + name, + handler, + } + } + + /// Return the number. + pub const fn number(&self) -> T { + self.number + } + + /// Return the name. + pub const fn name(&self) -> &'static str { + self.name + } + + /// Return the handler. + pub const fn handler(&self) -> &'static (dyn interface::IRQHandler + Sync) { + self.handler + } +} + impl<'irq_context> IRQContext<'irq_context> { /// Creates an IRQContext token. /// @@ -125,29 +162,6 @@ impl<'irq_context> IRQContext<'irq_context> { } } -impl IRQNumber<{ MAX_INCLUSIVE }> { - /// The total number of IRQs this type supports. - pub const NUM_TOTAL: usize = MAX_INCLUSIVE + 1; - - /// Creates a new instance if number <= MAX_INCLUSIVE. - pub const fn new(number: usize) -> Self { - assert!(number <= MAX_INCLUSIVE); - - Self(number) - } - - /// Return the wrapped number. - pub const fn get(self) -> usize { - self.0 - } -} - -impl fmt::Display for IRQNumber<{ MAX_INCLUSIVE }> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}", self.0) - } -} - /// Executes the provided closure while IRQs are masked on the executing core. /// /// While the function temporarily changes the HW state of the executing core, it restores it to the @@ -163,8 +177,7 @@ pub fn exec_with_irq_masked(f: impl FnOnce() -> T) -> T { /// Register a new IRQ manager. pub fn register_irq_manager( - new_manager: &'static (dyn interface::IRQManager - + Sync), + new_manager: &'static (dyn interface::IRQManager + Sync), ) { CUR_IRQ_MANAGER.write(|manager| *manager = new_manager); } @@ -172,6 +185,6 @@ pub fn register_irq_manager( /// Return a reference to the currently registered IRQ manager. /// /// This is the IRQ manager used by the architectural interrupt handling code. -pub fn irq_manager() -> &'static dyn interface::IRQManager { +pub fn irq_manager() -> &'static dyn interface::IRQManager { CUR_IRQ_MANAGER.read(|manager| *manager) } diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/exception/asynchronous/null_irq_manager.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/exception/asynchronous/null_irq_manager.rs index 560e3ce4..438f9649 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/exception/asynchronous/null_irq_manager.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/exception/asynchronous/null_irq_manager.rs @@ -4,8 +4,7 @@ //! Null IRQ Manager. -use super::{interface, IRQContext, IRQDescriptor}; -use crate::bsp; +use super::{interface, IRQContext, IRQHandlerDescriptor}; //-------------------------------------------------------------------------------------------------- // Public Definitions @@ -24,17 +23,16 @@ pub static NULL_IRQ_MANAGER: NullIRQManager = NullIRQManager {}; //-------------------------------------------------------------------------------------------------- impl interface::IRQManager for NullIRQManager { - type IRQNumberType = bsp::driver::IRQNumber; + type IRQNumberType = super::IRQNumber; fn register_handler( &self, - _irq_number: Self::IRQNumberType, - _descriptor: IRQDescriptor, + _descriptor: IRQHandlerDescriptor, ) -> Result<(), &'static str> { panic!("No IRQ Manager registered yet"); } - fn enable(&self, _irq_number: Self::IRQNumberType) { + fn enable(&self, _irq_number: &Self::IRQNumberType) { panic!("No IRQ Manager registered yet"); } diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/lib.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/lib.rs index 59ef14ac..f595b587 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/lib.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/lib.rs @@ -181,11 +181,9 @@ pub fn test_runner(tests: &[&test_types::UnitTest]) { #[cfg(test)] #[no_mangle] unsafe fn kernel_init() -> ! { - use driver::interface::DriverManager; - exception::handling_init(); memory::init(); - bsp::driver::driver_manager().qemu_bring_up_console(); + bsp::driver::qemu_bring_up_console(); test_main(); diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/main.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/main.rs index 9aeb4438..65905258 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/main.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/main.rs @@ -13,7 +13,7 @@ #![no_main] #![no_std] -use libkernel::{bsp, cpu, driver, exception, info, memory, state, time, warn}; +use libkernel::{bsp, cpu, driver, exception, info, memory, state, time}; /// Early init code. /// @@ -25,27 +25,16 @@ use libkernel::{bsp, cpu, driver, exception, info, memory, state, time, warn}; /// - Printing will not work until the respective driver's MMIO is remapped. #[no_mangle] unsafe fn kernel_init() -> ! { - use driver::interface::DriverManager; - exception::handling_init(); memory::init(); - // Instantiate and init all device drivers. - if let Err(x) = bsp::driver::driver_manager().instantiate_drivers() { - panic!("Error instantiating drivers: {}", x); - } - for i in bsp::driver::driver_manager().all_device_drivers().iter() { - if let Err(x) = i.init() { - panic!("Error loading driver: {}: {}", i.compatible(), x); - } + // Initialize the BSP driver subsystem. + if let Err(x) = bsp::driver::init() { + panic!("Error initializing BSP driver subsystem: {}", x); } - // Let device drivers register and enable their handlers with the interrupt controller. - for i in bsp::driver::driver_manager().all_device_drivers() { - if let Err(msg) = i.register_and_enable_irq_handler() { - warn!("Error registering IRQ handler: {}", msg); - } - } + // Initialize all device drivers. + driver::driver_manager().init_drivers_and_irqs(); bsp::memory::mmu::kernel_add_mapping_records_for_precomputed(); @@ -61,8 +50,6 @@ unsafe fn kernel_init() -> ! { /// The main function running after the early init. fn kernel_main() -> ! { - use driver::interface::DriverManager; - info!("{}", libkernel::version()); info!("Booting on: {}", bsp::board_name()); @@ -81,13 +68,7 @@ fn kernel_main() -> ! { ); info!("Drivers loaded:"); - for (i, driver) in bsp::driver::driver_manager() - .all_device_drivers() - .iter() - .enumerate() - { - info!(" {}. {}", i + 1, driver.compatible()); - } + driver::driver_manager().enumerate(); info!("Registered IRQ handlers:"); exception::asynchronous::irq_manager().print_handler(); diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/tests/00_console_sanity.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/tests/00_console_sanity.rs index 305510ce..2c0225b7 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/tests/00_console_sanity.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/tests/00_console_sanity.rs @@ -11,16 +11,15 @@ /// Console tests should time out on the I/O harness in case of panic. mod panic_wait_forever; -use libkernel::{bsp, console, cpu, driver, exception, memory, print}; +use libkernel::{bsp, console, cpu, exception, memory, print}; #[no_mangle] unsafe fn kernel_init() -> ! { use console::console; - use driver::interface::DriverManager; exception::handling_init(); memory::init(); - bsp::driver::driver_manager().qemu_bring_up_console(); + bsp::driver::qemu_bring_up_console(); // Handshake assert_eq!(console().read_char(), 'A'); diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/tests/01_timer_sanity.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/tests/01_timer_sanity.rs index 39899332..8188b942 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/tests/01_timer_sanity.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/tests/01_timer_sanity.rs @@ -11,16 +11,14 @@ #![test_runner(libkernel::test_runner)] use core::time::Duration; -use libkernel::{bsp, cpu, driver, exception, memory, time}; +use libkernel::{bsp, cpu, exception, memory, time}; use test_macros::kernel_test; #[no_mangle] unsafe fn kernel_init() -> ! { - use driver::interface::DriverManager; - exception::handling_init(); memory::init(); - bsp::driver::driver_manager().qemu_bring_up_console(); + bsp::driver::qemu_bring_up_console(); // Depending on CPU arch, some timer bring-up code could go here. Not needed for the RPi. diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/tests/02_exception_sync_page_fault.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/tests/02_exception_sync_page_fault.rs index a6d15b69..fab44c8f 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/tests/02_exception_sync_page_fault.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/tests/02_exception_sync_page_fault.rs @@ -17,15 +17,13 @@ /// or indirectly. mod panic_exit_success; -use libkernel::{bsp, cpu, driver, exception, info, memory, println}; +use libkernel::{bsp, cpu, exception, info, memory, println}; #[no_mangle] unsafe fn kernel_init() -> ! { - use driver::interface::DriverManager; - exception::handling_init(); memory::init(); - bsp::driver::driver_manager().qemu_bring_up_console(); + bsp::driver::qemu_bring_up_console(); // This line will be printed as the test header. println!("Testing synchronous exception handling by causing a page fault"); diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/tests/03_exception_restore_sanity.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/tests/03_exception_restore_sanity.rs index 47dd2714..f176c6a6 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/tests/03_exception_restore_sanity.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/tests/03_exception_restore_sanity.rs @@ -12,7 +12,7 @@ mod panic_wait_forever; use core::arch::asm; -use libkernel::{bsp, cpu, driver, exception, info, memory, println}; +use libkernel::{bsp, cpu, exception, info, memory, println}; #[inline(never)] fn nested_system_call() { @@ -30,11 +30,9 @@ fn nested_system_call() { #[no_mangle] unsafe fn kernel_init() -> ! { - use driver::interface::DriverManager; - exception::handling_init(); memory::init(); - bsp::driver::driver_manager().qemu_bring_up_console(); + bsp::driver::qemu_bring_up_console(); // This line will be printed as the test header. println!("Testing exception restore"); diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/tests/04_exception_irq_sanity.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/tests/04_exception_irq_sanity.rs index e93a4caf..e6f94c91 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/tests/04_exception_irq_sanity.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/tests/04_exception_irq_sanity.rs @@ -10,15 +10,13 @@ #![reexport_test_harness_main = "test_main"] #![test_runner(libkernel::test_runner)] -use libkernel::{bsp, cpu, driver, exception, memory}; +use libkernel::{bsp, cpu, exception, memory}; use test_macros::kernel_test; #[no_mangle] unsafe fn kernel_init() -> ! { - use driver::interface::DriverManager; - memory::init(); - bsp::driver::driver_manager().qemu_bring_up_console(); + bsp::driver::qemu_bring_up_console(); exception::handling_init(); exception::asynchronous::local_irq_unmask(); diff --git a/17_kernel_symbols/Makefile b/17_kernel_symbols/Makefile index 9af33140..7bed51da 100644 --- a/17_kernel_symbols/Makefile +++ b/17_kernel_symbols/Makefile @@ -335,7 +335,7 @@ test_boot: $(KERNEL_BIN) ## Helpers for unit and integration test targets ##------------------------------------------------------------------------------ define KERNEL_TEST_RUNNER - #!/usr/bin/env bash +#!/usr/bin/env bash # The cargo test runner seems to change into the crate under test's directory. Therefore, ensure # this script executes from the root. diff --git a/17_kernel_symbols/kernel/src/bsp/device_driver/arm/gicv2.rs b/17_kernel_symbols/kernel/src/bsp/device_driver/arm/gicv2.rs index ec65f1b2..3cc35b5e 100644 --- a/17_kernel_symbols/kernel/src/bsp/device_driver/arm/gicv2.rs +++ b/17_kernel_symbols/kernel/src/bsp/device_driver/arm/gicv2.rs @@ -80,7 +80,8 @@ mod gicc; mod gicd; use crate::{ - bsp, cpu, driver, exception, + bsp::{self, device_driver::common::BoundedUsize}, + cpu, driver, exception, memory::{Address, Virtual}, synchronization, synchronization::InitStateLock, @@ -90,14 +91,15 @@ use crate::{ // Private Definitions //-------------------------------------------------------------------------------------------------- -type HandlerTable = [Option; IRQNumber::NUM_TOTAL]; +type HandlerTable = [Option>; + IRQNumber::MAX_INCLUSIVE + 1]; //-------------------------------------------------------------------------------------------------- // Public Definitions //-------------------------------------------------------------------------------------------------- /// Used for the associated type of trait [`exception::asynchronous::interface::IRQManager`]. -pub type IRQNumber = exception::asynchronous::IRQNumber<{ GICv2::MAX_IRQ_NUMBER }>; +pub type IRQNumber = BoundedUsize<{ GICv2::MAX_IRQ_NUMBER }>; /// Representation of the GIC. pub struct GICv2 { @@ -109,9 +111,6 @@ pub struct GICv2 { /// Stores registered IRQ handlers. Writable only during kernel init. RO afterwards. handler_table: InitStateLock, - - /// Callback to be invoked after successful init. - post_init_callback: fn(), } //-------------------------------------------------------------------------------------------------- @@ -131,13 +130,11 @@ impl GICv2 { pub const unsafe fn new( gicd_mmio_start_addr: Address, gicc_mmio_start_addr: Address, - post_init_callback: fn(), ) -> Self { Self { gicd: gicd::GICD::new(gicd_mmio_start_addr), gicc: gicc::GICC::new(gicc_mmio_start_addr), - handler_table: InitStateLock::new([None; IRQNumber::NUM_TOTAL]), - post_init_callback, + handler_table: InitStateLock::new([None; IRQNumber::MAX_INCLUSIVE + 1]), } } } @@ -148,6 +145,8 @@ impl GICv2 { use synchronization::interface::ReadWriteEx; impl driver::interface::DeviceDriver for GICv2 { + type IRQNumberType = IRQNumber; + fn compatible(&self) -> &'static str { Self::COMPATIBLE } @@ -160,8 +159,6 @@ impl driver::interface::DeviceDriver for GICv2 { self.gicc.priority_accept_all(); self.gicc.enable(); - (self.post_init_callback)(); - Ok(()) } } @@ -171,23 +168,22 @@ impl exception::asynchronous::interface::IRQManager for GICv2 { fn register_handler( &self, - irq_number: Self::IRQNumberType, - descriptor: exception::asynchronous::IRQDescriptor, + irq_handler_descriptor: exception::asynchronous::IRQHandlerDescriptor, ) -> Result<(), &'static str> { self.handler_table.write(|table| { - let irq_number = irq_number.get(); + let irq_number = irq_handler_descriptor.number().get(); if table[irq_number].is_some() { return Err("IRQ handler already registered"); } - table[irq_number] = Some(descriptor); + table[irq_number] = Some(irq_handler_descriptor); Ok(()) }) } - fn enable(&self, irq_number: Self::IRQNumberType) { + fn enable(&self, irq_number: &Self::IRQNumberType) { self.gicd.enable(irq_number); } @@ -210,7 +206,7 @@ impl exception::asynchronous::interface::IRQManager for GICv2 { None => panic!("No handler registered for IRQ {}", irq_number), Some(descriptor) => { // Call the IRQ handler. Panics on failure. - descriptor.handler.handle().expect("Error handling IRQ"); + descriptor.handler().handle().expect("Error handling IRQ"); } } }); @@ -227,7 +223,7 @@ impl exception::asynchronous::interface::IRQManager for GICv2 { self.handler_table.read(|table| { for (i, opt) in table.iter().skip(32).enumerate() { if let Some(handler) = opt { - info!(" {: >3}. {}", i + 32, handler.name); + info!(" {: >3}. {}", i + 32, handler.name()); } } }); diff --git a/17_kernel_symbols/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs b/17_kernel_symbols/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs index a9c97a8e..8aebcf2b 100644 --- a/17_kernel_symbols/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs +++ b/17_kernel_symbols/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs @@ -172,7 +172,7 @@ impl GICD { } /// Enable an interrupt. - pub fn enable(&self, irq_num: super::IRQNumber) { + pub fn enable(&self, irq_num: &super::IRQNumber) { let irq_num = irq_num.get(); // Each bit in the u32 enable register corresponds to one IRQ number. Shift right by 5 diff --git a/17_kernel_symbols/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs b/17_kernel_symbols/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs index 2281e66a..fb61a651 100644 --- a/17_kernel_symbols/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs +++ b/17_kernel_symbols/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs @@ -7,6 +7,7 @@ use crate::{ bsp::device_driver::common::MMIODerefWrapper, driver, + exception::asynchronous::IRQNumber, memory::{Address, Virtual}, synchronization, synchronization::IRQSafeNullLock, @@ -122,7 +123,6 @@ struct GPIOInner { /// Representation of the GPIO HW. pub struct GPIO { inner: IRQSafeNullLock, - post_init_callback: fn(), } //-------------------------------------------------------------------------------------------------- @@ -202,10 +202,9 @@ impl GPIO { /// # Safety /// /// - The user must ensure to provide a correct MMIO start address. - pub const unsafe fn new(mmio_start_addr: Address, post_init_callback: fn()) -> Self { + pub const unsafe fn new(mmio_start_addr: Address) -> Self { Self { inner: IRQSafeNullLock::new(GPIOInner::new(mmio_start_addr)), - post_init_callback, } } @@ -221,13 +220,9 @@ impl GPIO { use synchronization::interface::Mutex; impl driver::interface::DeviceDriver for GPIO { + type IRQNumberType = IRQNumber; + fn compatible(&self) -> &'static str { Self::COMPATIBLE } - - unsafe fn init(&self) -> Result<(), &'static str> { - (self.post_init_callback)(); - - Ok(()) - } } diff --git a/17_kernel_symbols/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs b/17_kernel_symbols/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs index b4dd530d..c93a9fa1 100644 --- a/17_kernel_symbols/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs +++ b/17_kernel_symbols/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs @@ -7,9 +7,12 @@ mod peripheral_ic; use crate::{ - driver, exception, + bsp::device_driver::common::BoundedUsize, + driver, + exception::{self, asynchronous::IRQHandlerDescriptor}, memory::{Address, Virtual}, }; +use core::fmt; //-------------------------------------------------------------------------------------------------- // Private Definitions @@ -24,10 +27,8 @@ struct PendingIRQs { // Public Definitions //-------------------------------------------------------------------------------------------------- -pub type LocalIRQ = - exception::asynchronous::IRQNumber<{ InterruptController::MAX_LOCAL_IRQ_NUMBER }>; -pub type PeripheralIRQ = - exception::asynchronous::IRQNumber<{ InterruptController::MAX_PERIPHERAL_IRQ_NUMBER }>; +pub type LocalIRQ = BoundedUsize<{ InterruptController::MAX_LOCAL_IRQ_NUMBER }>; +pub type PeripheralIRQ = BoundedUsize<{ InterruptController::MAX_PERIPHERAL_IRQ_NUMBER }>; /// Used for the associated type of trait [`exception::asynchronous::interface::IRQManager`]. #[derive(Copy, Clone)] @@ -40,7 +41,6 @@ pub enum IRQNumber { /// Representation of the Interrupt Controller. pub struct InterruptController { periph: peripheral_ic::PeripheralIC, - post_init_callback: fn(), } //-------------------------------------------------------------------------------------------------- @@ -71,6 +71,15 @@ impl Iterator for PendingIRQs { // Public Code //-------------------------------------------------------------------------------------------------- +impl fmt::Display for IRQNumber { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Self::Local(number) => write!(f, "Local({})", number), + Self::Peripheral(number) => write!(f, "Peripheral({})", number), + } + } +} + impl InterruptController { // Restrict to 3 for now. This makes future code for local_ic.rs more straight forward. const MAX_LOCAL_IRQ_NUMBER: usize = 3; @@ -83,13 +92,9 @@ impl InterruptController { /// # Safety /// /// - The user must ensure to provide a correct MMIO start address. - pub const unsafe fn new( - periph_mmio_start_addr: Address, - post_init_callback: fn(), - ) -> Self { + pub const unsafe fn new(periph_mmio_start_addr: Address) -> Self { Self { periph: peripheral_ic::PeripheralIC::new(periph_mmio_start_addr), - post_init_callback, } } } @@ -99,15 +104,11 @@ impl InterruptController { //------------------------------------------------------------------------------ impl driver::interface::DeviceDriver for InterruptController { + type IRQNumberType = IRQNumber; + fn compatible(&self) -> &'static str { Self::COMPATIBLE } - - unsafe fn init(&self) -> Result<(), &'static str> { - (self.post_init_callback)(); - - Ok(()) - } } impl exception::asynchronous::interface::IRQManager for InterruptController { @@ -115,16 +116,23 @@ impl exception::asynchronous::interface::IRQManager for InterruptController { fn register_handler( &self, - irq: Self::IRQNumberType, - descriptor: exception::asynchronous::IRQDescriptor, + irq_handler_descriptor: exception::asynchronous::IRQHandlerDescriptor, ) -> Result<(), &'static str> { - match irq { + match irq_handler_descriptor.number() { IRQNumber::Local(_) => unimplemented!("Local IRQ controller not implemented."), - IRQNumber::Peripheral(pirq) => self.periph.register_handler(pirq, descriptor), + IRQNumber::Peripheral(pirq) => { + let periph_descriptor = IRQHandlerDescriptor::new( + pirq, + irq_handler_descriptor.name(), + irq_handler_descriptor.handler(), + ); + + self.periph.register_handler(periph_descriptor) + } } } - fn enable(&self, irq: Self::IRQNumberType) { + fn enable(&self, irq: &Self::IRQNumberType) { match irq { IRQNumber::Local(_) => unimplemented!("Local IRQ controller not implemented."), IRQNumber::Peripheral(pirq) => self.periph.enable(pirq), diff --git a/17_kernel_symbols/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs b/17_kernel_symbols/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs index 06802d27..0a20bd87 100644 --- a/17_kernel_symbols/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs +++ b/17_kernel_symbols/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs @@ -52,7 +52,8 @@ type WriteOnlyRegisters = MMIODerefWrapper; /// Abstraction for the ReadOnly parts of the associated MMIO registers. type ReadOnlyRegisters = MMIODerefWrapper; -type HandlerTable = [Option; PeripheralIRQ::NUM_TOTAL]; +type HandlerTable = [Option>; + PeripheralIRQ::MAX_INCLUSIVE + 1]; //-------------------------------------------------------------------------------------------------- // Public Definitions @@ -84,7 +85,7 @@ impl PeripheralIC { Self { wo_registers: IRQSafeNullLock::new(WriteOnlyRegisters::new(mmio_start_addr)), ro_registers: ReadOnlyRegisters::new(mmio_start_addr), - handler_table: InitStateLock::new([None; PeripheralIRQ::NUM_TOTAL]), + handler_table: InitStateLock::new([None; PeripheralIRQ::MAX_INCLUSIVE + 1]), } } @@ -107,23 +108,22 @@ impl exception::asynchronous::interface::IRQManager for PeripheralIC { fn register_handler( &self, - irq: Self::IRQNumberType, - descriptor: exception::asynchronous::IRQDescriptor, + irq_handler_descriptor: exception::asynchronous::IRQHandlerDescriptor, ) -> Result<(), &'static str> { self.handler_table.write(|table| { - let irq_number = irq.get(); + let irq_number = irq_handler_descriptor.number().get(); if table[irq_number].is_some() { return Err("IRQ handler already registered"); } - table[irq_number] = Some(descriptor); + table[irq_number] = Some(irq_handler_descriptor); Ok(()) }) } - fn enable(&self, irq: Self::IRQNumberType) { + fn enable(&self, irq: &Self::IRQNumberType) { self.wo_registers.lock(|regs| { let enable_reg = if irq.get() <= 31 { ®s.ENABLE_1 @@ -149,7 +149,7 @@ impl exception::asynchronous::interface::IRQManager for PeripheralIC { None => panic!("No handler registered for IRQ {}", irq_number), Some(descriptor) => { // Call the IRQ handler. Panics on failure. - descriptor.handler.handle().expect("Error handling IRQ"); + descriptor.handler().handle().expect("Error handling IRQ"); } } } @@ -164,7 +164,7 @@ impl exception::asynchronous::interface::IRQManager for PeripheralIC { self.handler_table.read(|table| { for (i, opt) in table.iter().enumerate() { if let Some(handler) = opt { - info!(" {: >3}. {}", i, handler.name); + info!(" {: >3}. {}", i, handler.name()); } } }); diff --git a/17_kernel_symbols/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs b/17_kernel_symbols/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs index f67d70df..0ee7feb7 100644 --- a/17_kernel_symbols/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs +++ b/17_kernel_symbols/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs @@ -10,9 +10,9 @@ //! - use crate::{ - bsp, bsp::device_driver::common::MMIODerefWrapper, - console, cpu, driver, exception, + console, cpu, driver, + exception::{self, asynchronous::IRQNumber}, memory::{Address, Virtual}, synchronization, synchronization::IRQSafeNullLock, @@ -233,8 +233,6 @@ struct PL011UartInner { /// Representation of the UART. pub struct PL011Uart { inner: IRQSafeNullLock, - irq_number: bsp::device_driver::IRQNumber, - post_init_callback: fn(), } //-------------------------------------------------------------------------------------------------- @@ -398,16 +396,9 @@ impl PL011Uart { /// # Safety /// /// - The user must ensure to provide a correct MMIO start address. - /// - The user must ensure to provide correct IRQ numbers. - pub const unsafe fn new( - mmio_start_addr: Address, - irq_number: bsp::device_driver::IRQNumber, - post_init_callback: fn(), - ) -> Self { + pub const unsafe fn new(mmio_start_addr: Address) -> Self { Self { inner: IRQSafeNullLock::new(PL011UartInner::new(mmio_start_addr)), - irq_number, - post_init_callback, } } } @@ -418,27 +409,28 @@ impl PL011Uart { use synchronization::interface::Mutex; impl driver::interface::DeviceDriver for PL011Uart { + type IRQNumberType = IRQNumber; + fn compatible(&self) -> &'static str { Self::COMPATIBLE } unsafe fn init(&self) -> Result<(), &'static str> { self.inner.lock(|inner| inner.init()); - (self.post_init_callback)(); Ok(()) } - fn register_and_enable_irq_handler(&'static self) -> Result<(), &'static str> { - use exception::asynchronous::{irq_manager, IRQDescriptor}; + fn register_and_enable_irq_handler( + &'static self, + irq_number: &Self::IRQNumberType, + ) -> Result<(), &'static str> { + use exception::asynchronous::{irq_manager, IRQHandlerDescriptor}; - let descriptor = IRQDescriptor { - name: Self::COMPATIBLE, - handler: self, - }; + let descriptor = IRQHandlerDescriptor::new(*irq_number, Self::COMPATIBLE, self); - irq_manager().register_handler(self.irq_number, descriptor)?; - irq_manager().enable(self.irq_number); + irq_manager().register_handler(descriptor)?; + irq_manager().enable(irq_number); Ok(()) } diff --git a/17_kernel_symbols/kernel/src/bsp/device_driver/common.rs b/17_kernel_symbols/kernel/src/bsp/device_driver/common.rs index 69f038d4..ca7aeb76 100644 --- a/17_kernel_symbols/kernel/src/bsp/device_driver/common.rs +++ b/17_kernel_symbols/kernel/src/bsp/device_driver/common.rs @@ -5,7 +5,7 @@ //! Common device driver code. use crate::memory::{Address, Virtual}; -use core::{marker::PhantomData, ops}; +use core::{fmt, marker::PhantomData, ops}; //-------------------------------------------------------------------------------------------------- // Public Definitions @@ -16,6 +16,10 @@ pub struct MMIODerefWrapper { phantom: PhantomData T>, } +/// A wrapper type for usize with integrated range bound check. +#[derive(Copy, Clone)] +pub struct BoundedUsize(usize); + //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- @@ -37,3 +41,25 @@ impl ops::Deref for MMIODerefWrapper { unsafe { &*(self.start_addr.as_usize() as *const _) } } } + +impl BoundedUsize<{ MAX_INCLUSIVE }> { + pub const MAX_INCLUSIVE: usize = MAX_INCLUSIVE; + + /// Creates a new instance if number <= MAX_INCLUSIVE. + pub const fn new(number: usize) -> Self { + assert!(number <= MAX_INCLUSIVE); + + Self(number) + } + + /// Return the wrapped number. + pub const fn get(self) -> usize { + self.0 + } +} + +impl fmt::Display for BoundedUsize<{ MAX_INCLUSIVE }> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.0) + } +} diff --git a/17_kernel_symbols/kernel/src/bsp/raspberrypi/driver.rs b/17_kernel_symbols/kernel/src/bsp/raspberrypi/driver.rs index e1db4a00..ca3435aa 100644 --- a/17_kernel_symbols/kernel/src/bsp/raspberrypi/driver.rs +++ b/17_kernel_symbols/kernel/src/bsp/raspberrypi/driver.rs @@ -7,34 +7,16 @@ use super::{exception, memory::map::mmio}; use crate::{ bsp::device_driver, - console, driver, exception as generic_exception, memory, + console, driver as generic_driver, + exception::{self as generic_exception}, + memory, memory::mmu::MMIODescriptor, - synchronization::{interface::ReadWriteEx, InitStateLock}, }; use core::{ mem::MaybeUninit, sync::atomic::{AtomicBool, Ordering}, }; -pub use device_driver::IRQNumber; - -//-------------------------------------------------------------------------------------------------- -// Private Definitions -//-------------------------------------------------------------------------------------------------- - -/// Device Driver Manager type. -struct BSPDriverManager { - device_drivers: InitStateLock<[Option<&'static (dyn DeviceDriver + Sync)>; NUM_DRIVERS]>, - init_done: AtomicBool, -} - -//-------------------------------------------------------------------------------------------------- -// Public Definitions -//-------------------------------------------------------------------------------------------------- - -/// The number of active drivers provided by this BSP. -pub const NUM_DRIVERS: usize = 3; - //-------------------------------------------------------------------------------------------------- // Global instances //-------------------------------------------------------------------------------------------------- @@ -49,150 +31,154 @@ static mut INTERRUPT_CONTROLLER: MaybeUninit #[cfg(feature = "bsp_rpi4")] static mut INTERRUPT_CONTROLLER: MaybeUninit = MaybeUninit::uninit(); -static BSP_DRIVER_MANAGER: BSPDriverManager = BSPDriverManager { - device_drivers: InitStateLock::new([None; NUM_DRIVERS]), - init_done: AtomicBool::new(false), -}; - //-------------------------------------------------------------------------------------------------- // Private Code //-------------------------------------------------------------------------------------------------- -impl BSPDriverManager { - unsafe fn instantiate_uart(&self) -> Result<(), &'static str> { - let mmio_descriptor = MMIODescriptor::new(mmio::PL011_UART_START, mmio::PL011_UART_SIZE); - let virt_addr = - memory::mmu::kernel_map_mmio(device_driver::PL011Uart::COMPATIBLE, &mmio_descriptor)?; +/// This must be called only after successful init of the memory subsystem. +unsafe fn instantiate_uart() -> Result<(), &'static str> { + let mmio_descriptor = MMIODescriptor::new(mmio::PL011_UART_START, mmio::PL011_UART_SIZE); + let virt_addr = + memory::mmu::kernel_map_mmio(device_driver::PL011Uart::COMPATIBLE, &mmio_descriptor)?; - // This is safe to do, because it is only called from the init'ed instance itself. - fn uart_post_init() { - console::register_console(unsafe { PL011_UART.assume_init_ref() }); - } + PL011_UART.write(device_driver::PL011Uart::new(virt_addr)); - PL011_UART.write(device_driver::PL011Uart::new( - virt_addr, - exception::asynchronous::irq_map::PL011_UART, - uart_post_init, - )); + Ok(()) +} - Ok(()) - } +/// This must be called only after successful init of the UART driver. +unsafe fn post_init_uart() -> Result<(), &'static str> { + console::register_console(PL011_UART.assume_init_ref()); - unsafe fn instantiate_gpio(&self) -> Result<(), &'static str> { - let mmio_descriptor = MMIODescriptor::new(mmio::GPIO_START, mmio::GPIO_SIZE); - let virt_addr = - memory::mmu::kernel_map_mmio(device_driver::GPIO::COMPATIBLE, &mmio_descriptor)?; + Ok(()) +} - // This is safe to do, because it is only called from the init'ed instance itself. - fn gpio_post_init() { - unsafe { GPIO.assume_init_ref().map_pl011_uart() }; - } +/// This must be called only after successful init of the memory subsystem. +unsafe fn instantiate_gpio() -> Result<(), &'static str> { + let mmio_descriptor = MMIODescriptor::new(mmio::GPIO_START, mmio::GPIO_SIZE); + let virt_addr = + memory::mmu::kernel_map_mmio(device_driver::GPIO::COMPATIBLE, &mmio_descriptor)?; - GPIO.write(device_driver::GPIO::new(virt_addr, gpio_post_init)); + GPIO.write(device_driver::GPIO::new(virt_addr)); - Ok(()) - } + Ok(()) +} - #[cfg(feature = "bsp_rpi3")] - unsafe fn instantiate_interrupt_controller(&self) -> Result<(), &'static str> { - let periph_mmio_descriptor = - MMIODescriptor::new(mmio::PERIPHERAL_IC_START, mmio::PERIPHERAL_IC_SIZE); - let periph_virt_addr = memory::mmu::kernel_map_mmio( - device_driver::InterruptController::COMPATIBLE, - &periph_mmio_descriptor, - )?; - - // This is safe to do, because it is only called from the init'ed instance itself. - fn interrupt_controller_post_init() { - generic_exception::asynchronous::register_irq_manager(unsafe { - INTERRUPT_CONTROLLER.assume_init_ref() - }); - } - - INTERRUPT_CONTROLLER.write(device_driver::InterruptController::new( - periph_virt_addr, - interrupt_controller_post_init, - )); - - Ok(()) - } +/// This must be called only after successful init of the GPIO driver. +unsafe fn post_init_gpio() -> Result<(), &'static str> { + GPIO.assume_init_ref().map_pl011_uart(); + Ok(()) +} + +/// This must be called only after successful init of the memory subsystem. +#[cfg(feature = "bsp_rpi3")] +unsafe fn instantiate_interrupt_controller() -> Result<(), &'static str> { + let periph_mmio_descriptor = + MMIODescriptor::new(mmio::PERIPHERAL_IC_START, mmio::PERIPHERAL_IC_SIZE); + let periph_virt_addr = memory::mmu::kernel_map_mmio( + device_driver::InterruptController::COMPATIBLE, + &periph_mmio_descriptor, + )?; + + INTERRUPT_CONTROLLER.write(device_driver::InterruptController::new(periph_virt_addr)); - #[cfg(feature = "bsp_rpi4")] - unsafe fn instantiate_interrupt_controller(&self) -> Result<(), &'static str> { - let gicd_mmio_descriptor = MMIODescriptor::new(mmio::GICD_START, mmio::GICD_SIZE); - let gicd_virt_addr = memory::mmu::kernel_map_mmio("GICv2 GICD", &gicd_mmio_descriptor)?; + Ok(()) +} - let gicc_mmio_descriptor = MMIODescriptor::new(mmio::GICC_START, mmio::GICC_SIZE); - let gicc_virt_addr = memory::mmu::kernel_map_mmio("GICV2 GICC", &gicc_mmio_descriptor)?; +/// This must be called only after successful init of the memory subsystem. +#[cfg(feature = "bsp_rpi4")] +unsafe fn instantiate_interrupt_controller() -> Result<(), &'static str> { + let gicd_mmio_descriptor = MMIODescriptor::new(mmio::GICD_START, mmio::GICD_SIZE); + let gicd_virt_addr = memory::mmu::kernel_map_mmio("GICv2 GICD", &gicd_mmio_descriptor)?; - // This is safe to do, because it is only called from the init'ed instance itself. - fn interrupt_controller_post_init() { - generic_exception::asynchronous::register_irq_manager(unsafe { - INTERRUPT_CONTROLLER.assume_init_ref() - }); - } + let gicc_mmio_descriptor = MMIODescriptor::new(mmio::GICC_START, mmio::GICC_SIZE); + let gicc_virt_addr = memory::mmu::kernel_map_mmio("GICV2 GICC", &gicc_mmio_descriptor)?; - INTERRUPT_CONTROLLER.write(device_driver::GICv2::new( - gicd_virt_addr, - gicc_virt_addr, - interrupt_controller_post_init, - )); + INTERRUPT_CONTROLLER.write(device_driver::GICv2::new(gicd_virt_addr, gicc_virt_addr)); - Ok(()) - } + Ok(()) +} - unsafe fn register_drivers(&self) { - self.device_drivers.write(|drivers| { - drivers[0] = Some(PL011_UART.assume_init_ref()); - drivers[1] = Some(GPIO.assume_init_ref()); - drivers[2] = Some(INTERRUPT_CONTROLLER.assume_init_ref()); - }); - } +/// This must be called only after successful init of the interrupt controller driver. +unsafe fn post_init_interrupt_controller() -> Result<(), &'static str> { + generic_exception::asynchronous::register_irq_manager(INTERRUPT_CONTROLLER.assume_init_ref()); + + Ok(()) } -//-------------------------------------------------------------------------------------------------- -// Public Code -//-------------------------------------------------------------------------------------------------- +/// Function needs to ensure that driver registration happens only after correct instantiation. +unsafe fn driver_uart() -> Result<(), &'static str> { + instantiate_uart()?; + + let uart_descriptor = generic_driver::DeviceDriverDescriptor::new( + PL011_UART.assume_init_ref(), + Some(post_init_uart), + Some(exception::asynchronous::irq_map::PL011_UART), + ); + generic_driver::driver_manager().register_driver(uart_descriptor); + + Ok(()) +} + +/// Function needs to ensure that driver registration happens only after correct instantiation. +unsafe fn driver_gpio() -> Result<(), &'static str> { + instantiate_gpio()?; + + let gpio_descriptor = generic_driver::DeviceDriverDescriptor::new( + GPIO.assume_init_ref(), + Some(post_init_gpio), + None, + ); + generic_driver::driver_manager().register_driver(gpio_descriptor); -/// Return a reference to the driver manager. -pub fn driver_manager() -> &'static impl driver::interface::DriverManager { - &BSP_DRIVER_MANAGER + Ok(()) } -//------------------------------------------------------------------------------ -// OS Interface Code -//------------------------------------------------------------------------------ -use driver::interface::DeviceDriver; +/// Function needs to ensure that driver registration happens only after correct instantiation. +unsafe fn driver_interrupt_controller() -> Result<(), &'static str> { + instantiate_interrupt_controller()?; -impl driver::interface::DriverManager for BSPDriverManager { - unsafe fn instantiate_drivers(&self) -> Result<(), &'static str> { - if self.init_done.load(Ordering::Relaxed) { - return Err("Drivers already instantiated"); - } + let interrupt_controller_descriptor = generic_driver::DeviceDriverDescriptor::new( + INTERRUPT_CONTROLLER.assume_init_ref(), + Some(post_init_interrupt_controller), + None, + ); + generic_driver::driver_manager().register_driver(interrupt_controller_descriptor); - self.instantiate_uart()?; - self.instantiate_gpio()?; - self.instantiate_interrupt_controller()?; + Ok(()) +} - self.register_drivers(); +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- - self.init_done.store(true, Ordering::Relaxed); - Ok(()) +/// Initialize the driver subsystem. +/// +/// # Safety +/// +/// See child function calls. +pub unsafe fn init() -> Result<(), &'static str> { + static INIT_DONE: AtomicBool = AtomicBool::new(false); + if INIT_DONE.load(Ordering::Relaxed) { + return Err("Init already done"); } - fn all_device_drivers(&self) -> [&(dyn DeviceDriver + Sync); NUM_DRIVERS] { - self.device_drivers - .read(|drivers| drivers.map(|drivers| drivers.unwrap())) - } + driver_uart()?; + driver_gpio()?; + driver_interrupt_controller()?; - #[cfg(feature = "test_build")] - fn qemu_bring_up_console(&self) { - use crate::cpu; + INIT_DONE.store(true, Ordering::Relaxed); + Ok(()) +} - unsafe { - self.instantiate_uart() - .unwrap_or_else(|_| cpu::qemu_exit_failure()); - console::register_console(PL011_UART.assume_init_ref()); - }; - } +/// Minimal code needed to bring up the console in QEMU (for testing only). This is often less steps +/// than on real hardware due to QEMU's abstractions. +#[cfg(feature = "test_build")] +pub fn qemu_bring_up_console() { + use crate::cpu; + + unsafe { + instantiate_uart().unwrap_or_else(|_| cpu::qemu_exit_failure()); + console::register_console(PL011_UART.assume_init_ref()); + }; } diff --git a/17_kernel_symbols/kernel/src/bsp/raspberrypi/exception/asynchronous.rs b/17_kernel_symbols/kernel/src/bsp/raspberrypi/exception/asynchronous.rs index ab20d86d..06a67558 100644 --- a/17_kernel_symbols/kernel/src/bsp/raspberrypi/exception/asynchronous.rs +++ b/17_kernel_symbols/kernel/src/bsp/raspberrypi/exception/asynchronous.rs @@ -10,6 +10,9 @@ use crate::bsp; // Public Definitions //-------------------------------------------------------------------------------------------------- +/// Export for reuse in generic asynchronous.rs. +pub use bsp::device_driver::IRQNumber; + #[cfg(feature = "bsp_rpi3")] pub(in crate::bsp) mod irq_map { use super::bsp::device_driver::{IRQNumber, PeripheralIRQ}; diff --git a/17_kernel_symbols/kernel/src/driver.rs b/17_kernel_symbols/kernel/src/driver.rs index 98197fef..18066c31 100644 --- a/17_kernel_symbols/kernel/src/driver.rs +++ b/17_kernel_symbols/kernel/src/driver.rs @@ -4,16 +4,37 @@ //! Driver support. +use crate::{ + exception, info, + synchronization::{interface::ReadWriteEx, InitStateLock}, +}; +use core::fmt; + +//-------------------------------------------------------------------------------------------------- +// Private Definitions +//-------------------------------------------------------------------------------------------------- + +const NUM_DRIVERS: usize = 5; + +struct DriverManagerInner +where + T: 'static, +{ + next_index: usize, + descriptors: [Option>; NUM_DRIVERS], +} + //-------------------------------------------------------------------------------------------------- // Public Definitions //-------------------------------------------------------------------------------------------------- /// Driver interfaces. pub mod interface { - use crate::bsp; - /// Device Driver functions. pub trait DeviceDriver { + /// Different interrupt controllers might use different types for IRQ number. + type IRQNumberType: super::fmt::Display; + /// Return a compatibility string for identifying the driver. fn compatible(&self) -> &'static str; @@ -26,32 +47,175 @@ pub mod interface { Ok(()) } - /// Called by the kernel to register and enable the device's IRQ handlers, if any. + /// Called by the kernel to register and enable the device's IRQ handler. /// /// Rust's type system will prevent a call to this function unless the calling instance /// itself has static lifetime. - fn register_and_enable_irq_handler(&'static self) -> Result<(), &'static str> { - Ok(()) + fn register_and_enable_irq_handler( + &'static self, + irq_number: &Self::IRQNumberType, + ) -> Result<(), &'static str> { + panic!( + "Attempt to enable IRQ {} for device {}, but driver does not support this", + irq_number, + self.compatible() + ) + } + } +} + +/// Tpye to be used as an optional callback after a driver's init() has run. +pub type DeviceDriverPostInitCallback = unsafe fn() -> Result<(), &'static str>; + +/// A descriptor for device drivers. +#[derive(Copy, Clone)] +pub struct DeviceDriverDescriptor +where + T: 'static, +{ + device_driver: &'static (dyn interface::DeviceDriver + Sync), + post_init_callback: Option, + irq_number: Option, +} + +/// Provides device driver management functions. +pub struct DriverManager +where + T: 'static, +{ + inner: InitStateLock>, +} + +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +static DRIVER_MANAGER: DriverManager = DriverManager::new(); + +//-------------------------------------------------------------------------------------------------- +// Private Code +//-------------------------------------------------------------------------------------------------- + +impl DriverManagerInner +where + T: 'static + Copy, +{ + /// Create an instance. + pub const fn new() -> Self { + Self { + next_index: 0, + descriptors: [None; NUM_DRIVERS], } } +} - /// Device driver management functions. +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +impl DeviceDriverDescriptor { + /// Create an instance. + pub fn new( + device_driver: &'static (dyn interface::DeviceDriver + Sync), + post_init_callback: Option, + irq_number: Option, + ) -> Self { + Self { + device_driver, + post_init_callback, + irq_number, + } + } +} + +/// Return a reference to the global DriverManager. +pub fn driver_manager() -> &'static DriverManager { + &DRIVER_MANAGER +} + +impl DriverManager +where + T: fmt::Display + Copy, +{ + /// Create an instance. + pub const fn new() -> Self { + Self { + inner: InitStateLock::new(DriverManagerInner::new()), + } + } + + /// Register a device driver with the kernel. + pub fn register_driver(&self, descriptor: DeviceDriverDescriptor) { + self.inner.write(|inner| { + inner.descriptors[inner.next_index] = Some(descriptor); + inner.next_index += 1; + }) + } + + /// Helper for iterating over registered drivers. + fn for_each_descriptor<'a>(&'a self, f: impl FnMut(&'a DeviceDriverDescriptor)) { + self.inner.read(|inner| { + inner + .descriptors + .iter() + .filter_map(|x| x.as_ref()) + .for_each(f) + }) + } + + /// Fully initialize all drivers and their interrupts handlers. /// - /// The `BSP` is supposed to supply one global instance. - pub trait DriverManager { - /// Instantiate all drivers. - /// - /// # Safety - /// - /// Must be called before `all_device_drivers`. - unsafe fn instantiate_drivers(&self) -> Result<(), &'static str>; + /// # Safety + /// + /// - During init, drivers might do stuff with system-wide impact. + pub unsafe fn init_drivers_and_irqs(&self) { + self.for_each_descriptor(|descriptor| { + // 1. Initialize driver. + if let Err(x) = descriptor.device_driver.init() { + panic!( + "Error initializing driver: {}: {}", + descriptor.device_driver.compatible(), + x + ); + } + + // 2. Call corresponding post init callback. + if let Some(callback) = &descriptor.post_init_callback { + if let Err(x) = callback() { + panic!( + "Error during driver post-init callback: {}: {}", + descriptor.device_driver.compatible(), + x + ); + } + } + }); + + // 3. After all post-init callbacks were done, the interrupt controller should be + // registered and functional. So let drivers register with it now. + self.for_each_descriptor(|descriptor| { + if let Some(irq_number) = &descriptor.irq_number { + if let Err(x) = descriptor + .device_driver + .register_and_enable_irq_handler(irq_number) + { + panic!( + "Error during driver interrupt handler registration: {}: {}", + descriptor.device_driver.compatible(), + x + ); + } + } + }); + } - /// Return a slice of references to all `BSP`-instantiated drivers. - fn all_device_drivers(&self) -> [&(dyn DeviceDriver + Sync); bsp::driver::NUM_DRIVERS]; + /// Enumerate all registered device drivers. + pub fn enumerate(&self) { + let mut i: usize = 1; + self.for_each_descriptor(|descriptor| { + info!(" {}. {}", i, descriptor.device_driver.compatible()); - /// Minimal code needed to bring up the console in QEMU (for testing only). This is often - /// less steps than on real hardware due to QEMU's abstractions. - #[cfg(feature = "test_build")] - fn qemu_bring_up_console(&self); + i += 1; + }); } } diff --git a/17_kernel_symbols/kernel/src/exception/asynchronous.rs b/17_kernel_symbols/kernel/src/exception/asynchronous.rs index 83ca1aa6..c1f2a27b 100644 --- a/17_kernel_symbols/kernel/src/exception/asynchronous.rs +++ b/17_kernel_symbols/kernel/src/exception/asynchronous.rs @@ -10,7 +10,7 @@ mod arch_asynchronous; mod null_irq_manager; use crate::{bsp, synchronization}; -use core::{fmt, marker::PhantomData}; +use core::marker::PhantomData; //-------------------------------------------------------------------------------------------------- // Architectural Public Reexports @@ -24,14 +24,23 @@ pub use arch_asynchronous::{ // Public Definitions //-------------------------------------------------------------------------------------------------- +/// Interrupt number as defined by the BSP. +pub type IRQNumber = bsp::exception::asynchronous::IRQNumber; + /// Interrupt descriptor. #[derive(Copy, Clone)] -pub struct IRQDescriptor { +pub struct IRQHandlerDescriptor +where + T: Copy, +{ + /// The IRQ number. + number: T, + /// Descriptive name. - pub name: &'static str, + name: &'static str, /// Reference to handler trait object. - pub handler: &'static (dyn interface::IRQHandler + Sync), + handler: &'static (dyn interface::IRQHandler + Sync), } /// IRQContext token. @@ -61,17 +70,16 @@ pub mod interface { /// platform's interrupt controller. pub trait IRQManager { /// The IRQ number type depends on the implementation. - type IRQNumberType; + type IRQNumberType: Copy; /// Register a handler. fn register_handler( &self, - irq_number: Self::IRQNumberType, - descriptor: super::IRQDescriptor, + irq_handler_descriptor: super::IRQHandlerDescriptor, ) -> Result<(), &'static str>; /// Enable an interrupt in the controller. - fn enable(&self, irq_number: Self::IRQNumberType); + fn enable(&self, irq_number: &Self::IRQNumberType); /// Handle pending interrupts. /// @@ -91,16 +99,12 @@ pub mod interface { } } -/// A wrapper type for IRQ numbers with integrated range sanity check. -#[derive(Copy, Clone)] -pub struct IRQNumber(usize); - //-------------------------------------------------------------------------------------------------- // Global instances //-------------------------------------------------------------------------------------------------- static CUR_IRQ_MANAGER: InitStateLock< - &'static (dyn interface::IRQManager + Sync), + &'static (dyn interface::IRQManager + Sync), > = InitStateLock::new(&null_irq_manager::NULL_IRQ_MANAGER); //-------------------------------------------------------------------------------------------------- @@ -108,6 +112,39 @@ static CUR_IRQ_MANAGER: InitStateLock< //-------------------------------------------------------------------------------------------------- use synchronization::{interface::ReadWriteEx, InitStateLock}; +impl IRQHandlerDescriptor +where + T: Copy, +{ + /// Create an instance. + pub const fn new( + number: T, + name: &'static str, + handler: &'static (dyn interface::IRQHandler + Sync), + ) -> Self { + Self { + number, + name, + handler, + } + } + + /// Return the number. + pub const fn number(&self) -> T { + self.number + } + + /// Return the name. + pub const fn name(&self) -> &'static str { + self.name + } + + /// Return the handler. + pub const fn handler(&self) -> &'static (dyn interface::IRQHandler + Sync) { + self.handler + } +} + impl<'irq_context> IRQContext<'irq_context> { /// Creates an IRQContext token. /// @@ -125,29 +162,6 @@ impl<'irq_context> IRQContext<'irq_context> { } } -impl IRQNumber<{ MAX_INCLUSIVE }> { - /// The total number of IRQs this type supports. - pub const NUM_TOTAL: usize = MAX_INCLUSIVE + 1; - - /// Creates a new instance if number <= MAX_INCLUSIVE. - pub const fn new(number: usize) -> Self { - assert!(number <= MAX_INCLUSIVE); - - Self(number) - } - - /// Return the wrapped number. - pub const fn get(self) -> usize { - self.0 - } -} - -impl fmt::Display for IRQNumber<{ MAX_INCLUSIVE }> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}", self.0) - } -} - /// Executes the provided closure while IRQs are masked on the executing core. /// /// While the function temporarily changes the HW state of the executing core, it restores it to the @@ -163,8 +177,7 @@ pub fn exec_with_irq_masked(f: impl FnOnce() -> T) -> T { /// Register a new IRQ manager. pub fn register_irq_manager( - new_manager: &'static (dyn interface::IRQManager - + Sync), + new_manager: &'static (dyn interface::IRQManager + Sync), ) { CUR_IRQ_MANAGER.write(|manager| *manager = new_manager); } @@ -172,6 +185,6 @@ pub fn register_irq_manager( /// Return a reference to the currently registered IRQ manager. /// /// This is the IRQ manager used by the architectural interrupt handling code. -pub fn irq_manager() -> &'static dyn interface::IRQManager { +pub fn irq_manager() -> &'static dyn interface::IRQManager { CUR_IRQ_MANAGER.read(|manager| *manager) } diff --git a/17_kernel_symbols/kernel/src/exception/asynchronous/null_irq_manager.rs b/17_kernel_symbols/kernel/src/exception/asynchronous/null_irq_manager.rs index 560e3ce4..438f9649 100644 --- a/17_kernel_symbols/kernel/src/exception/asynchronous/null_irq_manager.rs +++ b/17_kernel_symbols/kernel/src/exception/asynchronous/null_irq_manager.rs @@ -4,8 +4,7 @@ //! Null IRQ Manager. -use super::{interface, IRQContext, IRQDescriptor}; -use crate::bsp; +use super::{interface, IRQContext, IRQHandlerDescriptor}; //-------------------------------------------------------------------------------------------------- // Public Definitions @@ -24,17 +23,16 @@ pub static NULL_IRQ_MANAGER: NullIRQManager = NullIRQManager {}; //-------------------------------------------------------------------------------------------------- impl interface::IRQManager for NullIRQManager { - type IRQNumberType = bsp::driver::IRQNumber; + type IRQNumberType = super::IRQNumber; fn register_handler( &self, - _irq_number: Self::IRQNumberType, - _descriptor: IRQDescriptor, + _descriptor: IRQHandlerDescriptor, ) -> Result<(), &'static str> { panic!("No IRQ Manager registered yet"); } - fn enable(&self, _irq_number: Self::IRQNumberType) { + fn enable(&self, _irq_number: &Self::IRQNumberType) { panic!("No IRQ Manager registered yet"); } diff --git a/17_kernel_symbols/kernel/src/lib.rs b/17_kernel_symbols/kernel/src/lib.rs index 975bad2e..22572709 100644 --- a/17_kernel_symbols/kernel/src/lib.rs +++ b/17_kernel_symbols/kernel/src/lib.rs @@ -182,11 +182,9 @@ pub fn test_runner(tests: &[&test_types::UnitTest]) { #[cfg(test)] #[no_mangle] unsafe fn kernel_init() -> ! { - use driver::interface::DriverManager; - exception::handling_init(); memory::init(); - bsp::driver::driver_manager().qemu_bring_up_console(); + bsp::driver::qemu_bring_up_console(); test_main(); diff --git a/17_kernel_symbols/kernel/src/main.rs b/17_kernel_symbols/kernel/src/main.rs index 9aeb4438..65905258 100644 --- a/17_kernel_symbols/kernel/src/main.rs +++ b/17_kernel_symbols/kernel/src/main.rs @@ -13,7 +13,7 @@ #![no_main] #![no_std] -use libkernel::{bsp, cpu, driver, exception, info, memory, state, time, warn}; +use libkernel::{bsp, cpu, driver, exception, info, memory, state, time}; /// Early init code. /// @@ -25,27 +25,16 @@ use libkernel::{bsp, cpu, driver, exception, info, memory, state, time, warn}; /// - Printing will not work until the respective driver's MMIO is remapped. #[no_mangle] unsafe fn kernel_init() -> ! { - use driver::interface::DriverManager; - exception::handling_init(); memory::init(); - // Instantiate and init all device drivers. - if let Err(x) = bsp::driver::driver_manager().instantiate_drivers() { - panic!("Error instantiating drivers: {}", x); - } - for i in bsp::driver::driver_manager().all_device_drivers().iter() { - if let Err(x) = i.init() { - panic!("Error loading driver: {}: {}", i.compatible(), x); - } + // Initialize the BSP driver subsystem. + if let Err(x) = bsp::driver::init() { + panic!("Error initializing BSP driver subsystem: {}", x); } - // Let device drivers register and enable their handlers with the interrupt controller. - for i in bsp::driver::driver_manager().all_device_drivers() { - if let Err(msg) = i.register_and_enable_irq_handler() { - warn!("Error registering IRQ handler: {}", msg); - } - } + // Initialize all device drivers. + driver::driver_manager().init_drivers_and_irqs(); bsp::memory::mmu::kernel_add_mapping_records_for_precomputed(); @@ -61,8 +50,6 @@ unsafe fn kernel_init() -> ! { /// The main function running after the early init. fn kernel_main() -> ! { - use driver::interface::DriverManager; - info!("{}", libkernel::version()); info!("Booting on: {}", bsp::board_name()); @@ -81,13 +68,7 @@ fn kernel_main() -> ! { ); info!("Drivers loaded:"); - for (i, driver) in bsp::driver::driver_manager() - .all_device_drivers() - .iter() - .enumerate() - { - info!(" {}. {}", i + 1, driver.compatible()); - } + driver::driver_manager().enumerate(); info!("Registered IRQ handlers:"); exception::asynchronous::irq_manager().print_handler(); diff --git a/17_kernel_symbols/kernel/tests/00_console_sanity.rs b/17_kernel_symbols/kernel/tests/00_console_sanity.rs index 305510ce..2c0225b7 100644 --- a/17_kernel_symbols/kernel/tests/00_console_sanity.rs +++ b/17_kernel_symbols/kernel/tests/00_console_sanity.rs @@ -11,16 +11,15 @@ /// Console tests should time out on the I/O harness in case of panic. mod panic_wait_forever; -use libkernel::{bsp, console, cpu, driver, exception, memory, print}; +use libkernel::{bsp, console, cpu, exception, memory, print}; #[no_mangle] unsafe fn kernel_init() -> ! { use console::console; - use driver::interface::DriverManager; exception::handling_init(); memory::init(); - bsp::driver::driver_manager().qemu_bring_up_console(); + bsp::driver::qemu_bring_up_console(); // Handshake assert_eq!(console().read_char(), 'A'); diff --git a/17_kernel_symbols/kernel/tests/01_timer_sanity.rs b/17_kernel_symbols/kernel/tests/01_timer_sanity.rs index 39899332..8188b942 100644 --- a/17_kernel_symbols/kernel/tests/01_timer_sanity.rs +++ b/17_kernel_symbols/kernel/tests/01_timer_sanity.rs @@ -11,16 +11,14 @@ #![test_runner(libkernel::test_runner)] use core::time::Duration; -use libkernel::{bsp, cpu, driver, exception, memory, time}; +use libkernel::{bsp, cpu, exception, memory, time}; use test_macros::kernel_test; #[no_mangle] unsafe fn kernel_init() -> ! { - use driver::interface::DriverManager; - exception::handling_init(); memory::init(); - bsp::driver::driver_manager().qemu_bring_up_console(); + bsp::driver::qemu_bring_up_console(); // Depending on CPU arch, some timer bring-up code could go here. Not needed for the RPi. diff --git a/17_kernel_symbols/kernel/tests/02_exception_sync_page_fault.rs b/17_kernel_symbols/kernel/tests/02_exception_sync_page_fault.rs index a6d15b69..fab44c8f 100644 --- a/17_kernel_symbols/kernel/tests/02_exception_sync_page_fault.rs +++ b/17_kernel_symbols/kernel/tests/02_exception_sync_page_fault.rs @@ -17,15 +17,13 @@ /// or indirectly. mod panic_exit_success; -use libkernel::{bsp, cpu, driver, exception, info, memory, println}; +use libkernel::{bsp, cpu, exception, info, memory, println}; #[no_mangle] unsafe fn kernel_init() -> ! { - use driver::interface::DriverManager; - exception::handling_init(); memory::init(); - bsp::driver::driver_manager().qemu_bring_up_console(); + bsp::driver::qemu_bring_up_console(); // This line will be printed as the test header. println!("Testing synchronous exception handling by causing a page fault"); diff --git a/17_kernel_symbols/kernel/tests/03_exception_restore_sanity.rs b/17_kernel_symbols/kernel/tests/03_exception_restore_sanity.rs index 47dd2714..f176c6a6 100644 --- a/17_kernel_symbols/kernel/tests/03_exception_restore_sanity.rs +++ b/17_kernel_symbols/kernel/tests/03_exception_restore_sanity.rs @@ -12,7 +12,7 @@ mod panic_wait_forever; use core::arch::asm; -use libkernel::{bsp, cpu, driver, exception, info, memory, println}; +use libkernel::{bsp, cpu, exception, info, memory, println}; #[inline(never)] fn nested_system_call() { @@ -30,11 +30,9 @@ fn nested_system_call() { #[no_mangle] unsafe fn kernel_init() -> ! { - use driver::interface::DriverManager; - exception::handling_init(); memory::init(); - bsp::driver::driver_manager().qemu_bring_up_console(); + bsp::driver::qemu_bring_up_console(); // This line will be printed as the test header. println!("Testing exception restore"); diff --git a/17_kernel_symbols/kernel/tests/04_exception_irq_sanity.rs b/17_kernel_symbols/kernel/tests/04_exception_irq_sanity.rs index e93a4caf..e6f94c91 100644 --- a/17_kernel_symbols/kernel/tests/04_exception_irq_sanity.rs +++ b/17_kernel_symbols/kernel/tests/04_exception_irq_sanity.rs @@ -10,15 +10,13 @@ #![reexport_test_harness_main = "test_main"] #![test_runner(libkernel::test_runner)] -use libkernel::{bsp, cpu, driver, exception, memory}; +use libkernel::{bsp, cpu, exception, memory}; use test_macros::kernel_test; #[no_mangle] unsafe fn kernel_init() -> ! { - use driver::interface::DriverManager; - memory::init(); - bsp::driver::driver_manager().qemu_bring_up_console(); + bsp::driver::qemu_bring_up_console(); exception::handling_init(); exception::asynchronous::local_irq_unmask(); diff --git a/18_backtrace/Makefile b/18_backtrace/Makefile index 1dda95a4..789ed5cd 100644 --- a/18_backtrace/Makefile +++ b/18_backtrace/Makefile @@ -336,7 +336,7 @@ test_boot: $(KERNEL_BIN) ## Helpers for unit and integration test targets ##------------------------------------------------------------------------------ define KERNEL_TEST_RUNNER - #!/usr/bin/env bash +#!/usr/bin/env bash # The cargo test runner seems to change into the crate under test's directory. Therefore, ensure # this script executes from the root. diff --git a/18_backtrace/README.md b/18_backtrace/README.md index 77222e3a..021b8435 100644 --- a/18_backtrace/README.md +++ b/18_backtrace/README.md @@ -989,6 +989,19 @@ diff -uNr 17_kernel_symbols/kernel/src/panic_wait.rs 18_backtrace/kernel/src/pan _panic_exit() +diff -uNr 17_kernel_symbols/kernel/src/state.rs 18_backtrace/kernel/src/state.rs +--- 17_kernel_symbols/kernel/src/state.rs ++++ 18_backtrace/kernel/src/state.rs +@@ -52,7 +52,7 @@ + const SINGLE_CORE_MAIN: u8 = 1; + const MULTI_CORE_MAIN: u8 = 2; + +- /// Create a new instance. ++ /// Create an instance. + pub const fn new() -> Self { + Self(AtomicU8::new(Self::INIT)) + } + diff -uNr 17_kernel_symbols/kernel/tests/05_backtrace_sanity.rb 18_backtrace/kernel/tests/05_backtrace_sanity.rb --- 17_kernel_symbols/kernel/tests/05_backtrace_sanity.rb +++ 18_backtrace/kernel/tests/05_backtrace_sanity.rb @@ -1036,7 +1049,7 @@ diff -uNr 17_kernel_symbols/kernel/tests/05_backtrace_sanity.rb 18_backtrace/ker diff -uNr 17_kernel_symbols/kernel/tests/05_backtrace_sanity.rs 18_backtrace/kernel/tests/05_backtrace_sanity.rs --- 17_kernel_symbols/kernel/tests/05_backtrace_sanity.rs +++ 18_backtrace/kernel/tests/05_backtrace_sanity.rs -@@ -0,0 +1,33 @@ +@@ -0,0 +1,31 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2022 Andre Richter @@ -1050,7 +1063,7 @@ diff -uNr 17_kernel_symbols/kernel/tests/05_backtrace_sanity.rs 18_backtrace/ker +/// Console tests should time out on the I/O harness in case of panic. +mod panic_wait_forever; + -+use libkernel::{bsp, cpu, driver, exception, memory}; ++use libkernel::{bsp, cpu, exception, memory}; + +#[inline(never)] +fn nested() { @@ -1059,11 +1072,9 @@ diff -uNr 17_kernel_symbols/kernel/tests/05_backtrace_sanity.rs 18_backtrace/ker + +#[no_mangle] +unsafe fn kernel_init() -> ! { -+ use driver::interface::DriverManager; -+ + exception::handling_init(); + memory::init(); -+ bsp::driver::driver_manager().qemu_bring_up_console(); ++ bsp::driver::qemu_bring_up_console(); + + nested(); + @@ -1105,7 +1116,7 @@ diff -uNr 17_kernel_symbols/kernel/tests/06_backtrace_invalid_frame.rb 18_backtr diff -uNr 17_kernel_symbols/kernel/tests/06_backtrace_invalid_frame.rs 18_backtrace/kernel/tests/06_backtrace_invalid_frame.rs --- 17_kernel_symbols/kernel/tests/06_backtrace_invalid_frame.rs +++ 18_backtrace/kernel/tests/06_backtrace_invalid_frame.rs -@@ -0,0 +1,35 @@ +@@ -0,0 +1,33 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2022 Andre Richter @@ -1119,7 +1130,7 @@ diff -uNr 17_kernel_symbols/kernel/tests/06_backtrace_invalid_frame.rs 18_backtr +/// Console tests should time out on the I/O harness in case of panic. +mod panic_wait_forever; + -+use libkernel::{backtrace, bsp, cpu, driver, exception, memory}; ++use libkernel::{backtrace, bsp, cpu, exception, memory}; + +#[inline(never)] +fn nested() { @@ -1130,11 +1141,9 @@ diff -uNr 17_kernel_symbols/kernel/tests/06_backtrace_invalid_frame.rs 18_backtr + +#[no_mangle] +unsafe fn kernel_init() -> ! { -+ use driver::interface::DriverManager; -+ + exception::handling_init(); + memory::init(); -+ bsp::driver::driver_manager().qemu_bring_up_console(); ++ bsp::driver::qemu_bring_up_console(); + + nested(); + @@ -1175,7 +1184,7 @@ diff -uNr 17_kernel_symbols/kernel/tests/07_backtrace_invalid_link.rb 18_backtra diff -uNr 17_kernel_symbols/kernel/tests/07_backtrace_invalid_link.rs 18_backtrace/kernel/tests/07_backtrace_invalid_link.rs --- 17_kernel_symbols/kernel/tests/07_backtrace_invalid_link.rs +++ 18_backtrace/kernel/tests/07_backtrace_invalid_link.rs -@@ -0,0 +1,40 @@ +@@ -0,0 +1,38 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2022 Andre Richter @@ -1189,7 +1198,7 @@ diff -uNr 17_kernel_symbols/kernel/tests/07_backtrace_invalid_link.rs 18_backtra +/// Console tests should time out on the I/O harness in case of panic. +mod panic_wait_forever; + -+use libkernel::{backtrace, bsp, cpu, driver, exception, memory}; ++use libkernel::{backtrace, bsp, cpu, exception, memory}; + +#[inline(never)] +fn nested_2() -> &'static str { @@ -1205,11 +1214,9 @@ diff -uNr 17_kernel_symbols/kernel/tests/07_backtrace_invalid_link.rs 18_backtra + +#[no_mangle] +unsafe fn kernel_init() -> ! { -+ use driver::interface::DriverManager; -+ + exception::handling_init(); + memory::init(); -+ bsp::driver::driver_manager().qemu_bring_up_console(); ++ bsp::driver::qemu_bring_up_console(); + + nested_1(); + diff --git a/18_backtrace/kernel/src/bsp/device_driver/arm/gicv2.rs b/18_backtrace/kernel/src/bsp/device_driver/arm/gicv2.rs index ec65f1b2..3cc35b5e 100644 --- a/18_backtrace/kernel/src/bsp/device_driver/arm/gicv2.rs +++ b/18_backtrace/kernel/src/bsp/device_driver/arm/gicv2.rs @@ -80,7 +80,8 @@ mod gicc; mod gicd; use crate::{ - bsp, cpu, driver, exception, + bsp::{self, device_driver::common::BoundedUsize}, + cpu, driver, exception, memory::{Address, Virtual}, synchronization, synchronization::InitStateLock, @@ -90,14 +91,15 @@ use crate::{ // Private Definitions //-------------------------------------------------------------------------------------------------- -type HandlerTable = [Option; IRQNumber::NUM_TOTAL]; +type HandlerTable = [Option>; + IRQNumber::MAX_INCLUSIVE + 1]; //-------------------------------------------------------------------------------------------------- // Public Definitions //-------------------------------------------------------------------------------------------------- /// Used for the associated type of trait [`exception::asynchronous::interface::IRQManager`]. -pub type IRQNumber = exception::asynchronous::IRQNumber<{ GICv2::MAX_IRQ_NUMBER }>; +pub type IRQNumber = BoundedUsize<{ GICv2::MAX_IRQ_NUMBER }>; /// Representation of the GIC. pub struct GICv2 { @@ -109,9 +111,6 @@ pub struct GICv2 { /// Stores registered IRQ handlers. Writable only during kernel init. RO afterwards. handler_table: InitStateLock, - - /// Callback to be invoked after successful init. - post_init_callback: fn(), } //-------------------------------------------------------------------------------------------------- @@ -131,13 +130,11 @@ impl GICv2 { pub const unsafe fn new( gicd_mmio_start_addr: Address, gicc_mmio_start_addr: Address, - post_init_callback: fn(), ) -> Self { Self { gicd: gicd::GICD::new(gicd_mmio_start_addr), gicc: gicc::GICC::new(gicc_mmio_start_addr), - handler_table: InitStateLock::new([None; IRQNumber::NUM_TOTAL]), - post_init_callback, + handler_table: InitStateLock::new([None; IRQNumber::MAX_INCLUSIVE + 1]), } } } @@ -148,6 +145,8 @@ impl GICv2 { use synchronization::interface::ReadWriteEx; impl driver::interface::DeviceDriver for GICv2 { + type IRQNumberType = IRQNumber; + fn compatible(&self) -> &'static str { Self::COMPATIBLE } @@ -160,8 +159,6 @@ impl driver::interface::DeviceDriver for GICv2 { self.gicc.priority_accept_all(); self.gicc.enable(); - (self.post_init_callback)(); - Ok(()) } } @@ -171,23 +168,22 @@ impl exception::asynchronous::interface::IRQManager for GICv2 { fn register_handler( &self, - irq_number: Self::IRQNumberType, - descriptor: exception::asynchronous::IRQDescriptor, + irq_handler_descriptor: exception::asynchronous::IRQHandlerDescriptor, ) -> Result<(), &'static str> { self.handler_table.write(|table| { - let irq_number = irq_number.get(); + let irq_number = irq_handler_descriptor.number().get(); if table[irq_number].is_some() { return Err("IRQ handler already registered"); } - table[irq_number] = Some(descriptor); + table[irq_number] = Some(irq_handler_descriptor); Ok(()) }) } - fn enable(&self, irq_number: Self::IRQNumberType) { + fn enable(&self, irq_number: &Self::IRQNumberType) { self.gicd.enable(irq_number); } @@ -210,7 +206,7 @@ impl exception::asynchronous::interface::IRQManager for GICv2 { None => panic!("No handler registered for IRQ {}", irq_number), Some(descriptor) => { // Call the IRQ handler. Panics on failure. - descriptor.handler.handle().expect("Error handling IRQ"); + descriptor.handler().handle().expect("Error handling IRQ"); } } }); @@ -227,7 +223,7 @@ impl exception::asynchronous::interface::IRQManager for GICv2 { self.handler_table.read(|table| { for (i, opt) in table.iter().skip(32).enumerate() { if let Some(handler) = opt { - info!(" {: >3}. {}", i + 32, handler.name); + info!(" {: >3}. {}", i + 32, handler.name()); } } }); diff --git a/18_backtrace/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs b/18_backtrace/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs index a9c97a8e..8aebcf2b 100644 --- a/18_backtrace/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs +++ b/18_backtrace/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs @@ -172,7 +172,7 @@ impl GICD { } /// Enable an interrupt. - pub fn enable(&self, irq_num: super::IRQNumber) { + pub fn enable(&self, irq_num: &super::IRQNumber) { let irq_num = irq_num.get(); // Each bit in the u32 enable register corresponds to one IRQ number. Shift right by 5 diff --git a/18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs b/18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs index 2281e66a..fb61a651 100644 --- a/18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs +++ b/18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs @@ -7,6 +7,7 @@ use crate::{ bsp::device_driver::common::MMIODerefWrapper, driver, + exception::asynchronous::IRQNumber, memory::{Address, Virtual}, synchronization, synchronization::IRQSafeNullLock, @@ -122,7 +123,6 @@ struct GPIOInner { /// Representation of the GPIO HW. pub struct GPIO { inner: IRQSafeNullLock, - post_init_callback: fn(), } //-------------------------------------------------------------------------------------------------- @@ -202,10 +202,9 @@ impl GPIO { /// # Safety /// /// - The user must ensure to provide a correct MMIO start address. - pub const unsafe fn new(mmio_start_addr: Address, post_init_callback: fn()) -> Self { + pub const unsafe fn new(mmio_start_addr: Address) -> Self { Self { inner: IRQSafeNullLock::new(GPIOInner::new(mmio_start_addr)), - post_init_callback, } } @@ -221,13 +220,9 @@ impl GPIO { use synchronization::interface::Mutex; impl driver::interface::DeviceDriver for GPIO { + type IRQNumberType = IRQNumber; + fn compatible(&self) -> &'static str { Self::COMPATIBLE } - - unsafe fn init(&self) -> Result<(), &'static str> { - (self.post_init_callback)(); - - Ok(()) - } } diff --git a/18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs b/18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs index b4dd530d..c93a9fa1 100644 --- a/18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs +++ b/18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs @@ -7,9 +7,12 @@ mod peripheral_ic; use crate::{ - driver, exception, + bsp::device_driver::common::BoundedUsize, + driver, + exception::{self, asynchronous::IRQHandlerDescriptor}, memory::{Address, Virtual}, }; +use core::fmt; //-------------------------------------------------------------------------------------------------- // Private Definitions @@ -24,10 +27,8 @@ struct PendingIRQs { // Public Definitions //-------------------------------------------------------------------------------------------------- -pub type LocalIRQ = - exception::asynchronous::IRQNumber<{ InterruptController::MAX_LOCAL_IRQ_NUMBER }>; -pub type PeripheralIRQ = - exception::asynchronous::IRQNumber<{ InterruptController::MAX_PERIPHERAL_IRQ_NUMBER }>; +pub type LocalIRQ = BoundedUsize<{ InterruptController::MAX_LOCAL_IRQ_NUMBER }>; +pub type PeripheralIRQ = BoundedUsize<{ InterruptController::MAX_PERIPHERAL_IRQ_NUMBER }>; /// Used for the associated type of trait [`exception::asynchronous::interface::IRQManager`]. #[derive(Copy, Clone)] @@ -40,7 +41,6 @@ pub enum IRQNumber { /// Representation of the Interrupt Controller. pub struct InterruptController { periph: peripheral_ic::PeripheralIC, - post_init_callback: fn(), } //-------------------------------------------------------------------------------------------------- @@ -71,6 +71,15 @@ impl Iterator for PendingIRQs { // Public Code //-------------------------------------------------------------------------------------------------- +impl fmt::Display for IRQNumber { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Self::Local(number) => write!(f, "Local({})", number), + Self::Peripheral(number) => write!(f, "Peripheral({})", number), + } + } +} + impl InterruptController { // Restrict to 3 for now. This makes future code for local_ic.rs more straight forward. const MAX_LOCAL_IRQ_NUMBER: usize = 3; @@ -83,13 +92,9 @@ impl InterruptController { /// # Safety /// /// - The user must ensure to provide a correct MMIO start address. - pub const unsafe fn new( - periph_mmio_start_addr: Address, - post_init_callback: fn(), - ) -> Self { + pub const unsafe fn new(periph_mmio_start_addr: Address) -> Self { Self { periph: peripheral_ic::PeripheralIC::new(periph_mmio_start_addr), - post_init_callback, } } } @@ -99,15 +104,11 @@ impl InterruptController { //------------------------------------------------------------------------------ impl driver::interface::DeviceDriver for InterruptController { + type IRQNumberType = IRQNumber; + fn compatible(&self) -> &'static str { Self::COMPATIBLE } - - unsafe fn init(&self) -> Result<(), &'static str> { - (self.post_init_callback)(); - - Ok(()) - } } impl exception::asynchronous::interface::IRQManager for InterruptController { @@ -115,16 +116,23 @@ impl exception::asynchronous::interface::IRQManager for InterruptController { fn register_handler( &self, - irq: Self::IRQNumberType, - descriptor: exception::asynchronous::IRQDescriptor, + irq_handler_descriptor: exception::asynchronous::IRQHandlerDescriptor, ) -> Result<(), &'static str> { - match irq { + match irq_handler_descriptor.number() { IRQNumber::Local(_) => unimplemented!("Local IRQ controller not implemented."), - IRQNumber::Peripheral(pirq) => self.periph.register_handler(pirq, descriptor), + IRQNumber::Peripheral(pirq) => { + let periph_descriptor = IRQHandlerDescriptor::new( + pirq, + irq_handler_descriptor.name(), + irq_handler_descriptor.handler(), + ); + + self.periph.register_handler(periph_descriptor) + } } } - fn enable(&self, irq: Self::IRQNumberType) { + fn enable(&self, irq: &Self::IRQNumberType) { match irq { IRQNumber::Local(_) => unimplemented!("Local IRQ controller not implemented."), IRQNumber::Peripheral(pirq) => self.periph.enable(pirq), diff --git a/18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs b/18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs index 06802d27..0a20bd87 100644 --- a/18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs +++ b/18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs @@ -52,7 +52,8 @@ type WriteOnlyRegisters = MMIODerefWrapper; /// Abstraction for the ReadOnly parts of the associated MMIO registers. type ReadOnlyRegisters = MMIODerefWrapper; -type HandlerTable = [Option; PeripheralIRQ::NUM_TOTAL]; +type HandlerTable = [Option>; + PeripheralIRQ::MAX_INCLUSIVE + 1]; //-------------------------------------------------------------------------------------------------- // Public Definitions @@ -84,7 +85,7 @@ impl PeripheralIC { Self { wo_registers: IRQSafeNullLock::new(WriteOnlyRegisters::new(mmio_start_addr)), ro_registers: ReadOnlyRegisters::new(mmio_start_addr), - handler_table: InitStateLock::new([None; PeripheralIRQ::NUM_TOTAL]), + handler_table: InitStateLock::new([None; PeripheralIRQ::MAX_INCLUSIVE + 1]), } } @@ -107,23 +108,22 @@ impl exception::asynchronous::interface::IRQManager for PeripheralIC { fn register_handler( &self, - irq: Self::IRQNumberType, - descriptor: exception::asynchronous::IRQDescriptor, + irq_handler_descriptor: exception::asynchronous::IRQHandlerDescriptor, ) -> Result<(), &'static str> { self.handler_table.write(|table| { - let irq_number = irq.get(); + let irq_number = irq_handler_descriptor.number().get(); if table[irq_number].is_some() { return Err("IRQ handler already registered"); } - table[irq_number] = Some(descriptor); + table[irq_number] = Some(irq_handler_descriptor); Ok(()) }) } - fn enable(&self, irq: Self::IRQNumberType) { + fn enable(&self, irq: &Self::IRQNumberType) { self.wo_registers.lock(|regs| { let enable_reg = if irq.get() <= 31 { ®s.ENABLE_1 @@ -149,7 +149,7 @@ impl exception::asynchronous::interface::IRQManager for PeripheralIC { None => panic!("No handler registered for IRQ {}", irq_number), Some(descriptor) => { // Call the IRQ handler. Panics on failure. - descriptor.handler.handle().expect("Error handling IRQ"); + descriptor.handler().handle().expect("Error handling IRQ"); } } } @@ -164,7 +164,7 @@ impl exception::asynchronous::interface::IRQManager for PeripheralIC { self.handler_table.read(|table| { for (i, opt) in table.iter().enumerate() { if let Some(handler) = opt { - info!(" {: >3}. {}", i, handler.name); + info!(" {: >3}. {}", i, handler.name()); } } }); diff --git a/18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs b/18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs index f67d70df..0ee7feb7 100644 --- a/18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs +++ b/18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs @@ -10,9 +10,9 @@ //! - use crate::{ - bsp, bsp::device_driver::common::MMIODerefWrapper, - console, cpu, driver, exception, + console, cpu, driver, + exception::{self, asynchronous::IRQNumber}, memory::{Address, Virtual}, synchronization, synchronization::IRQSafeNullLock, @@ -233,8 +233,6 @@ struct PL011UartInner { /// Representation of the UART. pub struct PL011Uart { inner: IRQSafeNullLock, - irq_number: bsp::device_driver::IRQNumber, - post_init_callback: fn(), } //-------------------------------------------------------------------------------------------------- @@ -398,16 +396,9 @@ impl PL011Uart { /// # Safety /// /// - The user must ensure to provide a correct MMIO start address. - /// - The user must ensure to provide correct IRQ numbers. - pub const unsafe fn new( - mmio_start_addr: Address, - irq_number: bsp::device_driver::IRQNumber, - post_init_callback: fn(), - ) -> Self { + pub const unsafe fn new(mmio_start_addr: Address) -> Self { Self { inner: IRQSafeNullLock::new(PL011UartInner::new(mmio_start_addr)), - irq_number, - post_init_callback, } } } @@ -418,27 +409,28 @@ impl PL011Uart { use synchronization::interface::Mutex; impl driver::interface::DeviceDriver for PL011Uart { + type IRQNumberType = IRQNumber; + fn compatible(&self) -> &'static str { Self::COMPATIBLE } unsafe fn init(&self) -> Result<(), &'static str> { self.inner.lock(|inner| inner.init()); - (self.post_init_callback)(); Ok(()) } - fn register_and_enable_irq_handler(&'static self) -> Result<(), &'static str> { - use exception::asynchronous::{irq_manager, IRQDescriptor}; + fn register_and_enable_irq_handler( + &'static self, + irq_number: &Self::IRQNumberType, + ) -> Result<(), &'static str> { + use exception::asynchronous::{irq_manager, IRQHandlerDescriptor}; - let descriptor = IRQDescriptor { - name: Self::COMPATIBLE, - handler: self, - }; + let descriptor = IRQHandlerDescriptor::new(*irq_number, Self::COMPATIBLE, self); - irq_manager().register_handler(self.irq_number, descriptor)?; - irq_manager().enable(self.irq_number); + irq_manager().register_handler(descriptor)?; + irq_manager().enable(irq_number); Ok(()) } diff --git a/18_backtrace/kernel/src/bsp/device_driver/common.rs b/18_backtrace/kernel/src/bsp/device_driver/common.rs index 69f038d4..ca7aeb76 100644 --- a/18_backtrace/kernel/src/bsp/device_driver/common.rs +++ b/18_backtrace/kernel/src/bsp/device_driver/common.rs @@ -5,7 +5,7 @@ //! Common device driver code. use crate::memory::{Address, Virtual}; -use core::{marker::PhantomData, ops}; +use core::{fmt, marker::PhantomData, ops}; //-------------------------------------------------------------------------------------------------- // Public Definitions @@ -16,6 +16,10 @@ pub struct MMIODerefWrapper { phantom: PhantomData T>, } +/// A wrapper type for usize with integrated range bound check. +#[derive(Copy, Clone)] +pub struct BoundedUsize(usize); + //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- @@ -37,3 +41,25 @@ impl ops::Deref for MMIODerefWrapper { unsafe { &*(self.start_addr.as_usize() as *const _) } } } + +impl BoundedUsize<{ MAX_INCLUSIVE }> { + pub const MAX_INCLUSIVE: usize = MAX_INCLUSIVE; + + /// Creates a new instance if number <= MAX_INCLUSIVE. + pub const fn new(number: usize) -> Self { + assert!(number <= MAX_INCLUSIVE); + + Self(number) + } + + /// Return the wrapped number. + pub const fn get(self) -> usize { + self.0 + } +} + +impl fmt::Display for BoundedUsize<{ MAX_INCLUSIVE }> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.0) + } +} diff --git a/18_backtrace/kernel/src/bsp/raspberrypi/driver.rs b/18_backtrace/kernel/src/bsp/raspberrypi/driver.rs index e1db4a00..ca3435aa 100644 --- a/18_backtrace/kernel/src/bsp/raspberrypi/driver.rs +++ b/18_backtrace/kernel/src/bsp/raspberrypi/driver.rs @@ -7,34 +7,16 @@ use super::{exception, memory::map::mmio}; use crate::{ bsp::device_driver, - console, driver, exception as generic_exception, memory, + console, driver as generic_driver, + exception::{self as generic_exception}, + memory, memory::mmu::MMIODescriptor, - synchronization::{interface::ReadWriteEx, InitStateLock}, }; use core::{ mem::MaybeUninit, sync::atomic::{AtomicBool, Ordering}, }; -pub use device_driver::IRQNumber; - -//-------------------------------------------------------------------------------------------------- -// Private Definitions -//-------------------------------------------------------------------------------------------------- - -/// Device Driver Manager type. -struct BSPDriverManager { - device_drivers: InitStateLock<[Option<&'static (dyn DeviceDriver + Sync)>; NUM_DRIVERS]>, - init_done: AtomicBool, -} - -//-------------------------------------------------------------------------------------------------- -// Public Definitions -//-------------------------------------------------------------------------------------------------- - -/// The number of active drivers provided by this BSP. -pub const NUM_DRIVERS: usize = 3; - //-------------------------------------------------------------------------------------------------- // Global instances //-------------------------------------------------------------------------------------------------- @@ -49,150 +31,154 @@ static mut INTERRUPT_CONTROLLER: MaybeUninit #[cfg(feature = "bsp_rpi4")] static mut INTERRUPT_CONTROLLER: MaybeUninit = MaybeUninit::uninit(); -static BSP_DRIVER_MANAGER: BSPDriverManager = BSPDriverManager { - device_drivers: InitStateLock::new([None; NUM_DRIVERS]), - init_done: AtomicBool::new(false), -}; - //-------------------------------------------------------------------------------------------------- // Private Code //-------------------------------------------------------------------------------------------------- -impl BSPDriverManager { - unsafe fn instantiate_uart(&self) -> Result<(), &'static str> { - let mmio_descriptor = MMIODescriptor::new(mmio::PL011_UART_START, mmio::PL011_UART_SIZE); - let virt_addr = - memory::mmu::kernel_map_mmio(device_driver::PL011Uart::COMPATIBLE, &mmio_descriptor)?; +/// This must be called only after successful init of the memory subsystem. +unsafe fn instantiate_uart() -> Result<(), &'static str> { + let mmio_descriptor = MMIODescriptor::new(mmio::PL011_UART_START, mmio::PL011_UART_SIZE); + let virt_addr = + memory::mmu::kernel_map_mmio(device_driver::PL011Uart::COMPATIBLE, &mmio_descriptor)?; - // This is safe to do, because it is only called from the init'ed instance itself. - fn uart_post_init() { - console::register_console(unsafe { PL011_UART.assume_init_ref() }); - } + PL011_UART.write(device_driver::PL011Uart::new(virt_addr)); - PL011_UART.write(device_driver::PL011Uart::new( - virt_addr, - exception::asynchronous::irq_map::PL011_UART, - uart_post_init, - )); + Ok(()) +} - Ok(()) - } +/// This must be called only after successful init of the UART driver. +unsafe fn post_init_uart() -> Result<(), &'static str> { + console::register_console(PL011_UART.assume_init_ref()); - unsafe fn instantiate_gpio(&self) -> Result<(), &'static str> { - let mmio_descriptor = MMIODescriptor::new(mmio::GPIO_START, mmio::GPIO_SIZE); - let virt_addr = - memory::mmu::kernel_map_mmio(device_driver::GPIO::COMPATIBLE, &mmio_descriptor)?; + Ok(()) +} - // This is safe to do, because it is only called from the init'ed instance itself. - fn gpio_post_init() { - unsafe { GPIO.assume_init_ref().map_pl011_uart() }; - } +/// This must be called only after successful init of the memory subsystem. +unsafe fn instantiate_gpio() -> Result<(), &'static str> { + let mmio_descriptor = MMIODescriptor::new(mmio::GPIO_START, mmio::GPIO_SIZE); + let virt_addr = + memory::mmu::kernel_map_mmio(device_driver::GPIO::COMPATIBLE, &mmio_descriptor)?; - GPIO.write(device_driver::GPIO::new(virt_addr, gpio_post_init)); + GPIO.write(device_driver::GPIO::new(virt_addr)); - Ok(()) - } + Ok(()) +} - #[cfg(feature = "bsp_rpi3")] - unsafe fn instantiate_interrupt_controller(&self) -> Result<(), &'static str> { - let periph_mmio_descriptor = - MMIODescriptor::new(mmio::PERIPHERAL_IC_START, mmio::PERIPHERAL_IC_SIZE); - let periph_virt_addr = memory::mmu::kernel_map_mmio( - device_driver::InterruptController::COMPATIBLE, - &periph_mmio_descriptor, - )?; - - // This is safe to do, because it is only called from the init'ed instance itself. - fn interrupt_controller_post_init() { - generic_exception::asynchronous::register_irq_manager(unsafe { - INTERRUPT_CONTROLLER.assume_init_ref() - }); - } - - INTERRUPT_CONTROLLER.write(device_driver::InterruptController::new( - periph_virt_addr, - interrupt_controller_post_init, - )); - - Ok(()) - } +/// This must be called only after successful init of the GPIO driver. +unsafe fn post_init_gpio() -> Result<(), &'static str> { + GPIO.assume_init_ref().map_pl011_uart(); + Ok(()) +} + +/// This must be called only after successful init of the memory subsystem. +#[cfg(feature = "bsp_rpi3")] +unsafe fn instantiate_interrupt_controller() -> Result<(), &'static str> { + let periph_mmio_descriptor = + MMIODescriptor::new(mmio::PERIPHERAL_IC_START, mmio::PERIPHERAL_IC_SIZE); + let periph_virt_addr = memory::mmu::kernel_map_mmio( + device_driver::InterruptController::COMPATIBLE, + &periph_mmio_descriptor, + )?; + + INTERRUPT_CONTROLLER.write(device_driver::InterruptController::new(periph_virt_addr)); - #[cfg(feature = "bsp_rpi4")] - unsafe fn instantiate_interrupt_controller(&self) -> Result<(), &'static str> { - let gicd_mmio_descriptor = MMIODescriptor::new(mmio::GICD_START, mmio::GICD_SIZE); - let gicd_virt_addr = memory::mmu::kernel_map_mmio("GICv2 GICD", &gicd_mmio_descriptor)?; + Ok(()) +} - let gicc_mmio_descriptor = MMIODescriptor::new(mmio::GICC_START, mmio::GICC_SIZE); - let gicc_virt_addr = memory::mmu::kernel_map_mmio("GICV2 GICC", &gicc_mmio_descriptor)?; +/// This must be called only after successful init of the memory subsystem. +#[cfg(feature = "bsp_rpi4")] +unsafe fn instantiate_interrupt_controller() -> Result<(), &'static str> { + let gicd_mmio_descriptor = MMIODescriptor::new(mmio::GICD_START, mmio::GICD_SIZE); + let gicd_virt_addr = memory::mmu::kernel_map_mmio("GICv2 GICD", &gicd_mmio_descriptor)?; - // This is safe to do, because it is only called from the init'ed instance itself. - fn interrupt_controller_post_init() { - generic_exception::asynchronous::register_irq_manager(unsafe { - INTERRUPT_CONTROLLER.assume_init_ref() - }); - } + let gicc_mmio_descriptor = MMIODescriptor::new(mmio::GICC_START, mmio::GICC_SIZE); + let gicc_virt_addr = memory::mmu::kernel_map_mmio("GICV2 GICC", &gicc_mmio_descriptor)?; - INTERRUPT_CONTROLLER.write(device_driver::GICv2::new( - gicd_virt_addr, - gicc_virt_addr, - interrupt_controller_post_init, - )); + INTERRUPT_CONTROLLER.write(device_driver::GICv2::new(gicd_virt_addr, gicc_virt_addr)); - Ok(()) - } + Ok(()) +} - unsafe fn register_drivers(&self) { - self.device_drivers.write(|drivers| { - drivers[0] = Some(PL011_UART.assume_init_ref()); - drivers[1] = Some(GPIO.assume_init_ref()); - drivers[2] = Some(INTERRUPT_CONTROLLER.assume_init_ref()); - }); - } +/// This must be called only after successful init of the interrupt controller driver. +unsafe fn post_init_interrupt_controller() -> Result<(), &'static str> { + generic_exception::asynchronous::register_irq_manager(INTERRUPT_CONTROLLER.assume_init_ref()); + + Ok(()) } -//-------------------------------------------------------------------------------------------------- -// Public Code -//-------------------------------------------------------------------------------------------------- +/// Function needs to ensure that driver registration happens only after correct instantiation. +unsafe fn driver_uart() -> Result<(), &'static str> { + instantiate_uart()?; + + let uart_descriptor = generic_driver::DeviceDriverDescriptor::new( + PL011_UART.assume_init_ref(), + Some(post_init_uart), + Some(exception::asynchronous::irq_map::PL011_UART), + ); + generic_driver::driver_manager().register_driver(uart_descriptor); + + Ok(()) +} + +/// Function needs to ensure that driver registration happens only after correct instantiation. +unsafe fn driver_gpio() -> Result<(), &'static str> { + instantiate_gpio()?; + + let gpio_descriptor = generic_driver::DeviceDriverDescriptor::new( + GPIO.assume_init_ref(), + Some(post_init_gpio), + None, + ); + generic_driver::driver_manager().register_driver(gpio_descriptor); -/// Return a reference to the driver manager. -pub fn driver_manager() -> &'static impl driver::interface::DriverManager { - &BSP_DRIVER_MANAGER + Ok(()) } -//------------------------------------------------------------------------------ -// OS Interface Code -//------------------------------------------------------------------------------ -use driver::interface::DeviceDriver; +/// Function needs to ensure that driver registration happens only after correct instantiation. +unsafe fn driver_interrupt_controller() -> Result<(), &'static str> { + instantiate_interrupt_controller()?; -impl driver::interface::DriverManager for BSPDriverManager { - unsafe fn instantiate_drivers(&self) -> Result<(), &'static str> { - if self.init_done.load(Ordering::Relaxed) { - return Err("Drivers already instantiated"); - } + let interrupt_controller_descriptor = generic_driver::DeviceDriverDescriptor::new( + INTERRUPT_CONTROLLER.assume_init_ref(), + Some(post_init_interrupt_controller), + None, + ); + generic_driver::driver_manager().register_driver(interrupt_controller_descriptor); - self.instantiate_uart()?; - self.instantiate_gpio()?; - self.instantiate_interrupt_controller()?; + Ok(()) +} - self.register_drivers(); +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- - self.init_done.store(true, Ordering::Relaxed); - Ok(()) +/// Initialize the driver subsystem. +/// +/// # Safety +/// +/// See child function calls. +pub unsafe fn init() -> Result<(), &'static str> { + static INIT_DONE: AtomicBool = AtomicBool::new(false); + if INIT_DONE.load(Ordering::Relaxed) { + return Err("Init already done"); } - fn all_device_drivers(&self) -> [&(dyn DeviceDriver + Sync); NUM_DRIVERS] { - self.device_drivers - .read(|drivers| drivers.map(|drivers| drivers.unwrap())) - } + driver_uart()?; + driver_gpio()?; + driver_interrupt_controller()?; - #[cfg(feature = "test_build")] - fn qemu_bring_up_console(&self) { - use crate::cpu; + INIT_DONE.store(true, Ordering::Relaxed); + Ok(()) +} - unsafe { - self.instantiate_uart() - .unwrap_or_else(|_| cpu::qemu_exit_failure()); - console::register_console(PL011_UART.assume_init_ref()); - }; - } +/// Minimal code needed to bring up the console in QEMU (for testing only). This is often less steps +/// than on real hardware due to QEMU's abstractions. +#[cfg(feature = "test_build")] +pub fn qemu_bring_up_console() { + use crate::cpu; + + unsafe { + instantiate_uart().unwrap_or_else(|_| cpu::qemu_exit_failure()); + console::register_console(PL011_UART.assume_init_ref()); + }; } diff --git a/18_backtrace/kernel/src/bsp/raspberrypi/exception/asynchronous.rs b/18_backtrace/kernel/src/bsp/raspberrypi/exception/asynchronous.rs index ab20d86d..06a67558 100644 --- a/18_backtrace/kernel/src/bsp/raspberrypi/exception/asynchronous.rs +++ b/18_backtrace/kernel/src/bsp/raspberrypi/exception/asynchronous.rs @@ -10,6 +10,9 @@ use crate::bsp; // Public Definitions //-------------------------------------------------------------------------------------------------- +/// Export for reuse in generic asynchronous.rs. +pub use bsp::device_driver::IRQNumber; + #[cfg(feature = "bsp_rpi3")] pub(in crate::bsp) mod irq_map { use super::bsp::device_driver::{IRQNumber, PeripheralIRQ}; diff --git a/18_backtrace/kernel/src/driver.rs b/18_backtrace/kernel/src/driver.rs index 98197fef..18066c31 100644 --- a/18_backtrace/kernel/src/driver.rs +++ b/18_backtrace/kernel/src/driver.rs @@ -4,16 +4,37 @@ //! Driver support. +use crate::{ + exception, info, + synchronization::{interface::ReadWriteEx, InitStateLock}, +}; +use core::fmt; + +//-------------------------------------------------------------------------------------------------- +// Private Definitions +//-------------------------------------------------------------------------------------------------- + +const NUM_DRIVERS: usize = 5; + +struct DriverManagerInner +where + T: 'static, +{ + next_index: usize, + descriptors: [Option>; NUM_DRIVERS], +} + //-------------------------------------------------------------------------------------------------- // Public Definitions //-------------------------------------------------------------------------------------------------- /// Driver interfaces. pub mod interface { - use crate::bsp; - /// Device Driver functions. pub trait DeviceDriver { + /// Different interrupt controllers might use different types for IRQ number. + type IRQNumberType: super::fmt::Display; + /// Return a compatibility string for identifying the driver. fn compatible(&self) -> &'static str; @@ -26,32 +47,175 @@ pub mod interface { Ok(()) } - /// Called by the kernel to register and enable the device's IRQ handlers, if any. + /// Called by the kernel to register and enable the device's IRQ handler. /// /// Rust's type system will prevent a call to this function unless the calling instance /// itself has static lifetime. - fn register_and_enable_irq_handler(&'static self) -> Result<(), &'static str> { - Ok(()) + fn register_and_enable_irq_handler( + &'static self, + irq_number: &Self::IRQNumberType, + ) -> Result<(), &'static str> { + panic!( + "Attempt to enable IRQ {} for device {}, but driver does not support this", + irq_number, + self.compatible() + ) + } + } +} + +/// Tpye to be used as an optional callback after a driver's init() has run. +pub type DeviceDriverPostInitCallback = unsafe fn() -> Result<(), &'static str>; + +/// A descriptor for device drivers. +#[derive(Copy, Clone)] +pub struct DeviceDriverDescriptor +where + T: 'static, +{ + device_driver: &'static (dyn interface::DeviceDriver + Sync), + post_init_callback: Option, + irq_number: Option, +} + +/// Provides device driver management functions. +pub struct DriverManager +where + T: 'static, +{ + inner: InitStateLock>, +} + +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +static DRIVER_MANAGER: DriverManager = DriverManager::new(); + +//-------------------------------------------------------------------------------------------------- +// Private Code +//-------------------------------------------------------------------------------------------------- + +impl DriverManagerInner +where + T: 'static + Copy, +{ + /// Create an instance. + pub const fn new() -> Self { + Self { + next_index: 0, + descriptors: [None; NUM_DRIVERS], } } +} - /// Device driver management functions. +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +impl DeviceDriverDescriptor { + /// Create an instance. + pub fn new( + device_driver: &'static (dyn interface::DeviceDriver + Sync), + post_init_callback: Option, + irq_number: Option, + ) -> Self { + Self { + device_driver, + post_init_callback, + irq_number, + } + } +} + +/// Return a reference to the global DriverManager. +pub fn driver_manager() -> &'static DriverManager { + &DRIVER_MANAGER +} + +impl DriverManager +where + T: fmt::Display + Copy, +{ + /// Create an instance. + pub const fn new() -> Self { + Self { + inner: InitStateLock::new(DriverManagerInner::new()), + } + } + + /// Register a device driver with the kernel. + pub fn register_driver(&self, descriptor: DeviceDriverDescriptor) { + self.inner.write(|inner| { + inner.descriptors[inner.next_index] = Some(descriptor); + inner.next_index += 1; + }) + } + + /// Helper for iterating over registered drivers. + fn for_each_descriptor<'a>(&'a self, f: impl FnMut(&'a DeviceDriverDescriptor)) { + self.inner.read(|inner| { + inner + .descriptors + .iter() + .filter_map(|x| x.as_ref()) + .for_each(f) + }) + } + + /// Fully initialize all drivers and their interrupts handlers. /// - /// The `BSP` is supposed to supply one global instance. - pub trait DriverManager { - /// Instantiate all drivers. - /// - /// # Safety - /// - /// Must be called before `all_device_drivers`. - unsafe fn instantiate_drivers(&self) -> Result<(), &'static str>; + /// # Safety + /// + /// - During init, drivers might do stuff with system-wide impact. + pub unsafe fn init_drivers_and_irqs(&self) { + self.for_each_descriptor(|descriptor| { + // 1. Initialize driver. + if let Err(x) = descriptor.device_driver.init() { + panic!( + "Error initializing driver: {}: {}", + descriptor.device_driver.compatible(), + x + ); + } + + // 2. Call corresponding post init callback. + if let Some(callback) = &descriptor.post_init_callback { + if let Err(x) = callback() { + panic!( + "Error during driver post-init callback: {}: {}", + descriptor.device_driver.compatible(), + x + ); + } + } + }); + + // 3. After all post-init callbacks were done, the interrupt controller should be + // registered and functional. So let drivers register with it now. + self.for_each_descriptor(|descriptor| { + if let Some(irq_number) = &descriptor.irq_number { + if let Err(x) = descriptor + .device_driver + .register_and_enable_irq_handler(irq_number) + { + panic!( + "Error during driver interrupt handler registration: {}: {}", + descriptor.device_driver.compatible(), + x + ); + } + } + }); + } - /// Return a slice of references to all `BSP`-instantiated drivers. - fn all_device_drivers(&self) -> [&(dyn DeviceDriver + Sync); bsp::driver::NUM_DRIVERS]; + /// Enumerate all registered device drivers. + pub fn enumerate(&self) { + let mut i: usize = 1; + self.for_each_descriptor(|descriptor| { + info!(" {}. {}", i, descriptor.device_driver.compatible()); - /// Minimal code needed to bring up the console in QEMU (for testing only). This is often - /// less steps than on real hardware due to QEMU's abstractions. - #[cfg(feature = "test_build")] - fn qemu_bring_up_console(&self); + i += 1; + }); } } diff --git a/18_backtrace/kernel/src/exception/asynchronous.rs b/18_backtrace/kernel/src/exception/asynchronous.rs index 83ca1aa6..c1f2a27b 100644 --- a/18_backtrace/kernel/src/exception/asynchronous.rs +++ b/18_backtrace/kernel/src/exception/asynchronous.rs @@ -10,7 +10,7 @@ mod arch_asynchronous; mod null_irq_manager; use crate::{bsp, synchronization}; -use core::{fmt, marker::PhantomData}; +use core::marker::PhantomData; //-------------------------------------------------------------------------------------------------- // Architectural Public Reexports @@ -24,14 +24,23 @@ pub use arch_asynchronous::{ // Public Definitions //-------------------------------------------------------------------------------------------------- +/// Interrupt number as defined by the BSP. +pub type IRQNumber = bsp::exception::asynchronous::IRQNumber; + /// Interrupt descriptor. #[derive(Copy, Clone)] -pub struct IRQDescriptor { +pub struct IRQHandlerDescriptor +where + T: Copy, +{ + /// The IRQ number. + number: T, + /// Descriptive name. - pub name: &'static str, + name: &'static str, /// Reference to handler trait object. - pub handler: &'static (dyn interface::IRQHandler + Sync), + handler: &'static (dyn interface::IRQHandler + Sync), } /// IRQContext token. @@ -61,17 +70,16 @@ pub mod interface { /// platform's interrupt controller. pub trait IRQManager { /// The IRQ number type depends on the implementation. - type IRQNumberType; + type IRQNumberType: Copy; /// Register a handler. fn register_handler( &self, - irq_number: Self::IRQNumberType, - descriptor: super::IRQDescriptor, + irq_handler_descriptor: super::IRQHandlerDescriptor, ) -> Result<(), &'static str>; /// Enable an interrupt in the controller. - fn enable(&self, irq_number: Self::IRQNumberType); + fn enable(&self, irq_number: &Self::IRQNumberType); /// Handle pending interrupts. /// @@ -91,16 +99,12 @@ pub mod interface { } } -/// A wrapper type for IRQ numbers with integrated range sanity check. -#[derive(Copy, Clone)] -pub struct IRQNumber(usize); - //-------------------------------------------------------------------------------------------------- // Global instances //-------------------------------------------------------------------------------------------------- static CUR_IRQ_MANAGER: InitStateLock< - &'static (dyn interface::IRQManager + Sync), + &'static (dyn interface::IRQManager + Sync), > = InitStateLock::new(&null_irq_manager::NULL_IRQ_MANAGER); //-------------------------------------------------------------------------------------------------- @@ -108,6 +112,39 @@ static CUR_IRQ_MANAGER: InitStateLock< //-------------------------------------------------------------------------------------------------- use synchronization::{interface::ReadWriteEx, InitStateLock}; +impl IRQHandlerDescriptor +where + T: Copy, +{ + /// Create an instance. + pub const fn new( + number: T, + name: &'static str, + handler: &'static (dyn interface::IRQHandler + Sync), + ) -> Self { + Self { + number, + name, + handler, + } + } + + /// Return the number. + pub const fn number(&self) -> T { + self.number + } + + /// Return the name. + pub const fn name(&self) -> &'static str { + self.name + } + + /// Return the handler. + pub const fn handler(&self) -> &'static (dyn interface::IRQHandler + Sync) { + self.handler + } +} + impl<'irq_context> IRQContext<'irq_context> { /// Creates an IRQContext token. /// @@ -125,29 +162,6 @@ impl<'irq_context> IRQContext<'irq_context> { } } -impl IRQNumber<{ MAX_INCLUSIVE }> { - /// The total number of IRQs this type supports. - pub const NUM_TOTAL: usize = MAX_INCLUSIVE + 1; - - /// Creates a new instance if number <= MAX_INCLUSIVE. - pub const fn new(number: usize) -> Self { - assert!(number <= MAX_INCLUSIVE); - - Self(number) - } - - /// Return the wrapped number. - pub const fn get(self) -> usize { - self.0 - } -} - -impl fmt::Display for IRQNumber<{ MAX_INCLUSIVE }> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}", self.0) - } -} - /// Executes the provided closure while IRQs are masked on the executing core. /// /// While the function temporarily changes the HW state of the executing core, it restores it to the @@ -163,8 +177,7 @@ pub fn exec_with_irq_masked(f: impl FnOnce() -> T) -> T { /// Register a new IRQ manager. pub fn register_irq_manager( - new_manager: &'static (dyn interface::IRQManager - + Sync), + new_manager: &'static (dyn interface::IRQManager + Sync), ) { CUR_IRQ_MANAGER.write(|manager| *manager = new_manager); } @@ -172,6 +185,6 @@ pub fn register_irq_manager( /// Return a reference to the currently registered IRQ manager. /// /// This is the IRQ manager used by the architectural interrupt handling code. -pub fn irq_manager() -> &'static dyn interface::IRQManager { +pub fn irq_manager() -> &'static dyn interface::IRQManager { CUR_IRQ_MANAGER.read(|manager| *manager) } diff --git a/18_backtrace/kernel/src/exception/asynchronous/null_irq_manager.rs b/18_backtrace/kernel/src/exception/asynchronous/null_irq_manager.rs index 560e3ce4..438f9649 100644 --- a/18_backtrace/kernel/src/exception/asynchronous/null_irq_manager.rs +++ b/18_backtrace/kernel/src/exception/asynchronous/null_irq_manager.rs @@ -4,8 +4,7 @@ //! Null IRQ Manager. -use super::{interface, IRQContext, IRQDescriptor}; -use crate::bsp; +use super::{interface, IRQContext, IRQHandlerDescriptor}; //-------------------------------------------------------------------------------------------------- // Public Definitions @@ -24,17 +23,16 @@ pub static NULL_IRQ_MANAGER: NullIRQManager = NullIRQManager {}; //-------------------------------------------------------------------------------------------------- impl interface::IRQManager for NullIRQManager { - type IRQNumberType = bsp::driver::IRQNumber; + type IRQNumberType = super::IRQNumber; fn register_handler( &self, - _irq_number: Self::IRQNumberType, - _descriptor: IRQDescriptor, + _descriptor: IRQHandlerDescriptor, ) -> Result<(), &'static str> { panic!("No IRQ Manager registered yet"); } - fn enable(&self, _irq_number: Self::IRQNumberType) { + fn enable(&self, _irq_number: &Self::IRQNumberType) { panic!("No IRQ Manager registered yet"); } diff --git a/18_backtrace/kernel/src/lib.rs b/18_backtrace/kernel/src/lib.rs index 2545b20b..5b79ebfe 100644 --- a/18_backtrace/kernel/src/lib.rs +++ b/18_backtrace/kernel/src/lib.rs @@ -183,11 +183,9 @@ pub fn test_runner(tests: &[&test_types::UnitTest]) { #[cfg(test)] #[no_mangle] unsafe fn kernel_init() -> ! { - use driver::interface::DriverManager; - exception::handling_init(); memory::init(); - bsp::driver::driver_manager().qemu_bring_up_console(); + bsp::driver::qemu_bring_up_console(); test_main(); diff --git a/18_backtrace/kernel/src/main.rs b/18_backtrace/kernel/src/main.rs index 9aeb4438..65905258 100644 --- a/18_backtrace/kernel/src/main.rs +++ b/18_backtrace/kernel/src/main.rs @@ -13,7 +13,7 @@ #![no_main] #![no_std] -use libkernel::{bsp, cpu, driver, exception, info, memory, state, time, warn}; +use libkernel::{bsp, cpu, driver, exception, info, memory, state, time}; /// Early init code. /// @@ -25,27 +25,16 @@ use libkernel::{bsp, cpu, driver, exception, info, memory, state, time, warn}; /// - Printing will not work until the respective driver's MMIO is remapped. #[no_mangle] unsafe fn kernel_init() -> ! { - use driver::interface::DriverManager; - exception::handling_init(); memory::init(); - // Instantiate and init all device drivers. - if let Err(x) = bsp::driver::driver_manager().instantiate_drivers() { - panic!("Error instantiating drivers: {}", x); - } - for i in bsp::driver::driver_manager().all_device_drivers().iter() { - if let Err(x) = i.init() { - panic!("Error loading driver: {}: {}", i.compatible(), x); - } + // Initialize the BSP driver subsystem. + if let Err(x) = bsp::driver::init() { + panic!("Error initializing BSP driver subsystem: {}", x); } - // Let device drivers register and enable their handlers with the interrupt controller. - for i in bsp::driver::driver_manager().all_device_drivers() { - if let Err(msg) = i.register_and_enable_irq_handler() { - warn!("Error registering IRQ handler: {}", msg); - } - } + // Initialize all device drivers. + driver::driver_manager().init_drivers_and_irqs(); bsp::memory::mmu::kernel_add_mapping_records_for_precomputed(); @@ -61,8 +50,6 @@ unsafe fn kernel_init() -> ! { /// The main function running after the early init. fn kernel_main() -> ! { - use driver::interface::DriverManager; - info!("{}", libkernel::version()); info!("Booting on: {}", bsp::board_name()); @@ -81,13 +68,7 @@ fn kernel_main() -> ! { ); info!("Drivers loaded:"); - for (i, driver) in bsp::driver::driver_manager() - .all_device_drivers() - .iter() - .enumerate() - { - info!(" {}. {}", i + 1, driver.compatible()); - } + driver::driver_manager().enumerate(); info!("Registered IRQ handlers:"); exception::asynchronous::irq_manager().print_handler(); diff --git a/18_backtrace/kernel/src/state.rs b/18_backtrace/kernel/src/state.rs index 0af3688c..6a261b34 100644 --- a/18_backtrace/kernel/src/state.rs +++ b/18_backtrace/kernel/src/state.rs @@ -52,7 +52,7 @@ impl StateManager { const SINGLE_CORE_MAIN: u8 = 1; const MULTI_CORE_MAIN: u8 = 2; - /// Create a new instance. + /// Create an instance. pub const fn new() -> Self { Self(AtomicU8::new(Self::INIT)) } diff --git a/18_backtrace/kernel/tests/00_console_sanity.rs b/18_backtrace/kernel/tests/00_console_sanity.rs index 305510ce..2c0225b7 100644 --- a/18_backtrace/kernel/tests/00_console_sanity.rs +++ b/18_backtrace/kernel/tests/00_console_sanity.rs @@ -11,16 +11,15 @@ /// Console tests should time out on the I/O harness in case of panic. mod panic_wait_forever; -use libkernel::{bsp, console, cpu, driver, exception, memory, print}; +use libkernel::{bsp, console, cpu, exception, memory, print}; #[no_mangle] unsafe fn kernel_init() -> ! { use console::console; - use driver::interface::DriverManager; exception::handling_init(); memory::init(); - bsp::driver::driver_manager().qemu_bring_up_console(); + bsp::driver::qemu_bring_up_console(); // Handshake assert_eq!(console().read_char(), 'A'); diff --git a/18_backtrace/kernel/tests/01_timer_sanity.rs b/18_backtrace/kernel/tests/01_timer_sanity.rs index 39899332..8188b942 100644 --- a/18_backtrace/kernel/tests/01_timer_sanity.rs +++ b/18_backtrace/kernel/tests/01_timer_sanity.rs @@ -11,16 +11,14 @@ #![test_runner(libkernel::test_runner)] use core::time::Duration; -use libkernel::{bsp, cpu, driver, exception, memory, time}; +use libkernel::{bsp, cpu, exception, memory, time}; use test_macros::kernel_test; #[no_mangle] unsafe fn kernel_init() -> ! { - use driver::interface::DriverManager; - exception::handling_init(); memory::init(); - bsp::driver::driver_manager().qemu_bring_up_console(); + bsp::driver::qemu_bring_up_console(); // Depending on CPU arch, some timer bring-up code could go here. Not needed for the RPi. diff --git a/18_backtrace/kernel/tests/02_exception_sync_page_fault.rs b/18_backtrace/kernel/tests/02_exception_sync_page_fault.rs index a6d15b69..fab44c8f 100644 --- a/18_backtrace/kernel/tests/02_exception_sync_page_fault.rs +++ b/18_backtrace/kernel/tests/02_exception_sync_page_fault.rs @@ -17,15 +17,13 @@ /// or indirectly. mod panic_exit_success; -use libkernel::{bsp, cpu, driver, exception, info, memory, println}; +use libkernel::{bsp, cpu, exception, info, memory, println}; #[no_mangle] unsafe fn kernel_init() -> ! { - use driver::interface::DriverManager; - exception::handling_init(); memory::init(); - bsp::driver::driver_manager().qemu_bring_up_console(); + bsp::driver::qemu_bring_up_console(); // This line will be printed as the test header. println!("Testing synchronous exception handling by causing a page fault"); diff --git a/18_backtrace/kernel/tests/03_exception_restore_sanity.rs b/18_backtrace/kernel/tests/03_exception_restore_sanity.rs index 47dd2714..f176c6a6 100644 --- a/18_backtrace/kernel/tests/03_exception_restore_sanity.rs +++ b/18_backtrace/kernel/tests/03_exception_restore_sanity.rs @@ -12,7 +12,7 @@ mod panic_wait_forever; use core::arch::asm; -use libkernel::{bsp, cpu, driver, exception, info, memory, println}; +use libkernel::{bsp, cpu, exception, info, memory, println}; #[inline(never)] fn nested_system_call() { @@ -30,11 +30,9 @@ fn nested_system_call() { #[no_mangle] unsafe fn kernel_init() -> ! { - use driver::interface::DriverManager; - exception::handling_init(); memory::init(); - bsp::driver::driver_manager().qemu_bring_up_console(); + bsp::driver::qemu_bring_up_console(); // This line will be printed as the test header. println!("Testing exception restore"); diff --git a/18_backtrace/kernel/tests/04_exception_irq_sanity.rs b/18_backtrace/kernel/tests/04_exception_irq_sanity.rs index e93a4caf..e6f94c91 100644 --- a/18_backtrace/kernel/tests/04_exception_irq_sanity.rs +++ b/18_backtrace/kernel/tests/04_exception_irq_sanity.rs @@ -10,15 +10,13 @@ #![reexport_test_harness_main = "test_main"] #![test_runner(libkernel::test_runner)] -use libkernel::{bsp, cpu, driver, exception, memory}; +use libkernel::{bsp, cpu, exception, memory}; use test_macros::kernel_test; #[no_mangle] unsafe fn kernel_init() -> ! { - use driver::interface::DriverManager; - memory::init(); - bsp::driver::driver_manager().qemu_bring_up_console(); + bsp::driver::qemu_bring_up_console(); exception::handling_init(); exception::asynchronous::local_irq_unmask(); diff --git a/18_backtrace/kernel/tests/05_backtrace_sanity.rs b/18_backtrace/kernel/tests/05_backtrace_sanity.rs index ea425f68..f75c0ea3 100644 --- a/18_backtrace/kernel/tests/05_backtrace_sanity.rs +++ b/18_backtrace/kernel/tests/05_backtrace_sanity.rs @@ -11,7 +11,7 @@ /// Console tests should time out on the I/O harness in case of panic. mod panic_wait_forever; -use libkernel::{bsp, cpu, driver, exception, memory}; +use libkernel::{bsp, cpu, exception, memory}; #[inline(never)] fn nested() { @@ -20,11 +20,9 @@ fn nested() { #[no_mangle] unsafe fn kernel_init() -> ! { - use driver::interface::DriverManager; - exception::handling_init(); memory::init(); - bsp::driver::driver_manager().qemu_bring_up_console(); + bsp::driver::qemu_bring_up_console(); nested(); diff --git a/18_backtrace/kernel/tests/06_backtrace_invalid_frame.rs b/18_backtrace/kernel/tests/06_backtrace_invalid_frame.rs index 8769c7b6..33d3c02d 100644 --- a/18_backtrace/kernel/tests/06_backtrace_invalid_frame.rs +++ b/18_backtrace/kernel/tests/06_backtrace_invalid_frame.rs @@ -11,7 +11,7 @@ /// Console tests should time out on the I/O harness in case of panic. mod panic_wait_forever; -use libkernel::{backtrace, bsp, cpu, driver, exception, memory}; +use libkernel::{backtrace, bsp, cpu, exception, memory}; #[inline(never)] fn nested() { @@ -22,11 +22,9 @@ fn nested() { #[no_mangle] unsafe fn kernel_init() -> ! { - use driver::interface::DriverManager; - exception::handling_init(); memory::init(); - bsp::driver::driver_manager().qemu_bring_up_console(); + bsp::driver::qemu_bring_up_console(); nested(); diff --git a/18_backtrace/kernel/tests/07_backtrace_invalid_link.rs b/18_backtrace/kernel/tests/07_backtrace_invalid_link.rs index 28f3cdda..bcb0538a 100644 --- a/18_backtrace/kernel/tests/07_backtrace_invalid_link.rs +++ b/18_backtrace/kernel/tests/07_backtrace_invalid_link.rs @@ -11,7 +11,7 @@ /// Console tests should time out on the I/O harness in case of panic. mod panic_wait_forever; -use libkernel::{backtrace, bsp, cpu, driver, exception, memory}; +use libkernel::{backtrace, bsp, cpu, exception, memory}; #[inline(never)] fn nested_2() -> &'static str { @@ -27,11 +27,9 @@ fn nested_1() { #[no_mangle] unsafe fn kernel_init() -> ! { - use driver::interface::DriverManager; - exception::handling_init(); memory::init(); - bsp::driver::driver_manager().qemu_bring_up_console(); + bsp::driver::qemu_bring_up_console(); nested_1(); diff --git a/19_kernel_heap/Makefile b/19_kernel_heap/Makefile index 7b1673f3..be41c136 100644 --- a/19_kernel_heap/Makefile +++ b/19_kernel_heap/Makefile @@ -341,7 +341,7 @@ test_boot: $(KERNEL_BIN) ## Helpers for unit and integration test targets ##------------------------------------------------------------------------------ define KERNEL_TEST_RUNNER - #!/usr/bin/env bash +#!/usr/bin/env bash # The cargo test runner seems to change into the crate under test's directory. Therefore, ensure # this script executes from the root. diff --git a/19_kernel_heap/README.md b/19_kernel_heap/README.md index 4eafd344..a40d203d 100644 --- a/19_kernel_heap/README.md +++ b/19_kernel_heap/README.md @@ -131,11 +131,19 @@ wrapped allocator to the heap that we defined earlier: ```rust /// Query the BSP for the heap region and initialize the kernel's heap allocator with it. pub fn kernel_init_heap_allocator() { + static INIT_DONE: AtomicBool = AtomicBool::new(false); + if INIT_DONE.load(Ordering::Relaxed) { + warn!("Already initialized"); + return; + } + let region = bsp::memory::mmu::virt_heap_region(); - KERNEL_HEAP_ALLOCATOR - .inner - .lock(|inner| unsafe { inner.init(region.start_addr().as_usize(), region.size()) }); + KERNEL_HEAP_ALLOCATOR.inner.lock(|inner| unsafe { + inner.init(region.start_addr().as_usize() as *mut u8, region.size()) + }); + + INIT_DONE.store(true, Ordering::Relaxed); } ``` @@ -288,7 +296,7 @@ diff -uNr 18_backtrace/kernel/Cargo.toml 19_kernel_heap/kernel/Cargo.toml diff -uNr 18_backtrace/kernel/src/bsp/device_driver/arm/gicv2.rs 19_kernel_heap/kernel/src/bsp/device_driver/arm/gicv2.rs --- 18_backtrace/kernel/src/bsp/device_driver/arm/gicv2.rs +++ 19_kernel_heap/kernel/src/bsp/device_driver/arm/gicv2.rs -@@ -85,12 +85,13 @@ +@@ -86,13 +86,13 @@ synchronization, synchronization::InitStateLock, }; @@ -298,12 +306,13 @@ diff -uNr 18_backtrace/kernel/src/bsp/device_driver/arm/gicv2.rs 19_kernel_heap/ // Private Definitions //-------------------------------------------------------------------------------------------------- --type HandlerTable = [Option; IRQNumber::NUM_TOTAL]; -+type HandlerTable = Vec>; +-type HandlerTable = [Option>; +- IRQNumber::MAX_INCLUSIVE + 1]; ++type HandlerTable = Vec>>; //-------------------------------------------------------------------------------------------------- // Public Definitions -@@ -119,7 +120,7 @@ +@@ -118,7 +118,7 @@ //-------------------------------------------------------------------------------------------------- impl GICv2 { @@ -312,21 +321,21 @@ diff -uNr 18_backtrace/kernel/src/bsp/device_driver/arm/gicv2.rs 19_kernel_heap/ pub const COMPATIBLE: &'static str = "GICv2 (ARM Generic Interrupt Controller v2)"; -@@ -136,7 +137,7 @@ +@@ -134,7 +134,7 @@ Self { gicd: gicd::GICD::new(gicd_mmio_start_addr), gicc: gicc::GICC::new(gicc_mmio_start_addr), -- handler_table: InitStateLock::new([None; IRQNumber::NUM_TOTAL]), +- handler_table: InitStateLock::new([None; IRQNumber::MAX_INCLUSIVE + 1]), + handler_table: InitStateLock::new(Vec::new()), - post_init_callback, } } -@@ -153,6 +154,9 @@ + } +@@ -152,6 +152,9 @@ } unsafe fn init(&self) -> Result<(), &'static str> { + self.handler_table -+ .write(|table| table.resize(IRQNumber::NUM_TOTAL, None)); ++ .write(|table| table.resize(IRQNumber::MAX_INCLUSIVE + 1, None)); + if bsp::cpu::BOOT_CORE_ID == cpu::smp::core_id() { self.gicd.boot_core_init(); @@ -343,20 +352,21 @@ diff -uNr 18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_contro use tock_registers::{ interfaces::{Readable, Writeable}, register_structs, -@@ -52,7 +53,7 @@ +@@ -52,8 +53,7 @@ /// Abstraction for the ReadOnly parts of the associated MMIO registers. type ReadOnlyRegisters = MMIODerefWrapper; --type HandlerTable = [Option; PeripheralIRQ::NUM_TOTAL]; -+type HandlerTable = Vec>; +-type HandlerTable = [Option>; +- PeripheralIRQ::MAX_INCLUSIVE + 1]; ++type HandlerTable = Vec>>; //-------------------------------------------------------------------------------------------------- // Public Definitions -@@ -84,10 +85,16 @@ +@@ -85,10 +85,16 @@ Self { wo_registers: IRQSafeNullLock::new(WriteOnlyRegisters::new(mmio_start_addr)), ro_registers: ReadOnlyRegisters::new(mmio_start_addr), -- handler_table: InitStateLock::new([None; PeripheralIRQ::NUM_TOTAL]), +- handler_table: InitStateLock::new([None; PeripheralIRQ::MAX_INCLUSIVE + 1]), + handler_table: InitStateLock::new(Vec::new()), } } @@ -364,7 +374,7 @@ diff -uNr 18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_contro + /// Called by the kernel to bring up the device. + pub fn init(&self) { + self.handler_table -+ .write(|table| table.resize(PeripheralIRQ::NUM_TOTAL, None)); ++ .write(|table| table.resize(PeripheralIRQ::MAX_INCLUSIVE + 1, None)); + } + /// Query the list of pending IRQs. @@ -374,20 +384,24 @@ diff -uNr 18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_contro diff -uNr 18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs 19_kernel_heap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs --- 18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs +++ 19_kernel_heap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs -@@ -104,6 +104,8 @@ +@@ -109,6 +109,12 @@ + fn compatible(&self) -> &'static str { + Self::COMPATIBLE } - - unsafe fn init(&self) -> Result<(), &'static str> { ++ ++ unsafe fn init(&self) -> Result<(), &'static str> { + self.periph.init(); + - (self.post_init_callback)(); ++ Ok(()) ++ } + } - Ok(()) + impl exception::asynchronous::interface::IRQManager for InterruptController { diff -uNr 18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs 19_kernel_heap/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs --- 18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs +++ 19_kernel_heap/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs -@@ -329,6 +329,13 @@ +@@ -327,6 +327,13 @@ self.chars_written += 1; } @@ -401,7 +415,7 @@ diff -uNr 18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs 19 /// Block execution until the last buffered character has been physically put on the TX wire. fn flush(&self) { // Spin until the busy bit is cleared. -@@ -451,6 +458,10 @@ +@@ -443,6 +450,10 @@ self.inner.lock(|inner| inner.write_char(c)); } @@ -413,72 +427,6 @@ diff -uNr 18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs 19 // Fully qualified syntax for the call to `core::fmt::Write::write_fmt()` to increase // readability. -diff -uNr 18_backtrace/kernel/src/bsp/raspberrypi/driver.rs 19_kernel_heap/kernel/src/bsp/raspberrypi/driver.rs ---- 18_backtrace/kernel/src/bsp/raspberrypi/driver.rs -+++ 19_kernel_heap/kernel/src/bsp/raspberrypi/driver.rs -@@ -11,6 +11,7 @@ - memory::mmu::MMIODescriptor, - synchronization::{interface::ReadWriteEx, InitStateLock}, - }; -+use alloc::vec::Vec; - use core::{ - mem::MaybeUninit, - sync::atomic::{AtomicBool, Ordering}, -@@ -24,18 +25,11 @@ - - /// Device Driver Manager type. - struct BSPDriverManager { -- device_drivers: InitStateLock<[Option<&'static (dyn DeviceDriver + Sync)>; NUM_DRIVERS]>, -+ device_drivers: InitStateLock>, - init_done: AtomicBool, - } - - //-------------------------------------------------------------------------------------------------- --// Public Definitions --//-------------------------------------------------------------------------------------------------- -- --/// The number of active drivers provided by this BSP. --pub const NUM_DRIVERS: usize = 3; -- --//-------------------------------------------------------------------------------------------------- - // Global instances - //-------------------------------------------------------------------------------------------------- - -@@ -50,7 +44,7 @@ - static mut INTERRUPT_CONTROLLER: MaybeUninit = MaybeUninit::uninit(); - - static BSP_DRIVER_MANAGER: BSPDriverManager = BSPDriverManager { -- device_drivers: InitStateLock::new([None; NUM_DRIVERS]), -+ device_drivers: InitStateLock::new(Vec::new()), - init_done: AtomicBool::new(false), - }; - -@@ -143,9 +137,9 @@ - - unsafe fn register_drivers(&self) { - self.device_drivers.write(|drivers| { -- drivers[0] = Some(PL011_UART.assume_init_ref()); -- drivers[1] = Some(GPIO.assume_init_ref()); -- drivers[2] = Some(INTERRUPT_CONTROLLER.assume_init_ref()); -+ drivers.push(PL011_UART.assume_init_ref()); -+ drivers.push(GPIO.assume_init_ref()); -+ drivers.push(INTERRUPT_CONTROLLER.assume_init_ref()); - }); - } - } -@@ -180,9 +174,8 @@ - Ok(()) - } - -- fn all_device_drivers(&self) -> [&(dyn DeviceDriver + Sync); NUM_DRIVERS] { -- self.device_drivers -- .read(|drivers| drivers.map(|drivers| drivers.unwrap())) -+ fn all_device_drivers(&self) -> &Vec<&(dyn DeviceDriver + Sync)> { -+ self.device_drivers.read(|drivers| drivers) - } - - #[cfg(feature = "test_build")] - diff -uNr 18_backtrace/kernel/src/bsp/raspberrypi/kernel.ld 19_kernel_heap/kernel/src/bsp/raspberrypi/kernel.ld --- 18_backtrace/kernel/src/bsp/raspberrypi/kernel.ld +++ 19_kernel_heap/kernel/src/bsp/raspberrypi/kernel.ld @@ -819,26 +767,198 @@ diff -uNr 18_backtrace/kernel/src/console.rs 19_kernel_heap/kernel/src/console.r diff -uNr 18_backtrace/kernel/src/driver.rs 19_kernel_heap/kernel/src/driver.rs --- 18_backtrace/kernel/src/driver.rs +++ 19_kernel_heap/kernel/src/driver.rs -@@ -10,7 +10,7 @@ +@@ -8,23 +8,10 @@ + exception, info, + synchronization::{interface::ReadWriteEx, InitStateLock}, + }; ++use alloc::vec::Vec; + use core::fmt; - /// Driver interfaces. - pub mod interface { -- use crate::bsp; -+ use alloc::vec::Vec; + //-------------------------------------------------------------------------------------------------- +-// Private Definitions +-//-------------------------------------------------------------------------------------------------- +- +-const NUM_DRIVERS: usize = 5; +- +-struct DriverManagerInner +-where +- T: 'static, +-{ +- next_index: usize, +- descriptors: [Option>; NUM_DRIVERS], +-} +- +-//-------------------------------------------------------------------------------------------------- + // Public Definitions + //-------------------------------------------------------------------------------------------------- + +@@ -68,7 +55,6 @@ + pub type DeviceDriverPostInitCallback = unsafe fn() -> Result<(), &'static str>; + + /// A descriptor for device drivers. +-#[derive(Copy, Clone)] + pub struct DeviceDriverDescriptor + where + T: 'static, +@@ -83,7 +69,7 @@ + where + T: 'static, + { +- inner: InitStateLock>, ++ descriptors: InitStateLock>>, + } + + //-------------------------------------------------------------------------------------------------- +@@ -93,23 +79,6 @@ + static DRIVER_MANAGER: DriverManager = DriverManager::new(); + + //-------------------------------------------------------------------------------------------------- +-// Private Code +-//-------------------------------------------------------------------------------------------------- +- +-impl DriverManagerInner +-where +- T: 'static + Copy, +-{ +- /// Create an instance. +- pub const fn new() -> Self { +- Self { +- next_index: 0, +- descriptors: [None; NUM_DRIVERS], +- } +- } +-} +- +-//-------------------------------------------------------------------------------------------------- + // Public Code + //-------------------------------------------------------------------------------------------------- + +@@ -135,32 +104,19 @@ + + impl DriverManager + where +- T: fmt::Display + Copy, ++ T: fmt::Display, + { + /// Create an instance. + pub const fn new() -> Self { + Self { +- inner: InitStateLock::new(DriverManagerInner::new()), ++ descriptors: InitStateLock::new(Vec::new()), + } + } - /// Device Driver functions. - pub trait DeviceDriver { -@@ -46,8 +46,8 @@ - /// Must be called before `all_device_drivers`. - unsafe fn instantiate_drivers(&self) -> Result<(), &'static str>; + /// Register a device driver with the kernel. + pub fn register_driver(&self, descriptor: DeviceDriverDescriptor) { +- self.inner.write(|inner| { +- inner.descriptors[inner.next_index] = Some(descriptor); +- inner.next_index += 1; +- }) +- } +- +- /// Helper for iterating over registered drivers. +- fn for_each_descriptor<'a>(&'a self, f: impl FnMut(&'a DeviceDriverDescriptor)) { +- self.inner.read(|inner| { +- inner +- .descriptors +- .iter() +- .filter_map(|x| x.as_ref()) +- .for_each(f) +- }) ++ self.descriptors ++ .write(|descriptors| descriptors.push(descriptor)); + } -- /// Return a slice of references to all `BSP`-instantiated drivers. -- fn all_device_drivers(&self) -> [&(dyn DeviceDriver + Sync); bsp::driver::NUM_DRIVERS]; -+ /// Return a vector of references to all `BSP`-instantiated drivers. -+ fn all_device_drivers(&self) -> &Vec<&(dyn DeviceDriver + Sync)>; + /// Fully initialize all drivers and their interrupts handlers. +@@ -169,53 +125,54 @@ + /// + /// - During init, drivers might do stuff with system-wide impact. + pub unsafe fn init_drivers_and_irqs(&self) { +- self.for_each_descriptor(|descriptor| { +- // 1. Initialize driver. +- if let Err(x) = descriptor.device_driver.init() { +- panic!( +- "Error initializing driver: {}: {}", +- descriptor.device_driver.compatible(), +- x +- ); +- } +- +- // 2. Call corresponding post init callback. +- if let Some(callback) = &descriptor.post_init_callback { +- if let Err(x) = callback() { ++ self.descriptors.read(|descriptors| { ++ for descriptor in descriptors { ++ // 1. Initialize driver. ++ if let Err(x) = descriptor.device_driver.init() { + panic!( +- "Error during driver post-init callback: {}: {}", ++ "Error initializing driver: {}: {}", + descriptor.device_driver.compatible(), + x + ); + } ++ ++ // 2. Call corresponding post init callback. ++ if let Some(callback) = &descriptor.post_init_callback { ++ if let Err(x) = callback() { ++ panic!( ++ "Error during driver post-init callback: {}: {}", ++ descriptor.device_driver.compatible(), ++ x ++ ); ++ } ++ } + } +- }); + +- // 3. After all post-init callbacks were done, the interrupt controller should be +- // registered and functional. So let drivers register with it now. +- self.for_each_descriptor(|descriptor| { +- if let Some(irq_number) = &descriptor.irq_number { +- if let Err(x) = descriptor +- .device_driver +- .register_and_enable_irq_handler(irq_number) +- { +- panic!( +- "Error during driver interrupt handler registration: {}: {}", +- descriptor.device_driver.compatible(), +- x +- ); ++ // 3. After all post-init callbacks were done, the interrupt controller should be ++ // registered and functional. So let drivers register with it now. ++ for descriptor in descriptors { ++ if let Some(irq_number) = &descriptor.irq_number { ++ if let Err(x) = descriptor ++ .device_driver ++ .register_and_enable_irq_handler(irq_number) ++ { ++ panic!( ++ "Error during driver interrupt handler registration: {}: {}", ++ descriptor.device_driver.compatible(), ++ x ++ ); ++ } + } + } +- }); ++ }) + } - /// Minimal code needed to bring up the console in QEMU (for testing only). This is often - /// less steps than on real hardware due to QEMU's abstractions. + /// Enumerate all registered device drivers. + pub fn enumerate(&self) { +- let mut i: usize = 1; +- self.for_each_descriptor(|descriptor| { +- info!(" {}. {}", i, descriptor.device_driver.compatible()); +- +- i += 1; ++ self.descriptors.read(|descriptors| { ++ for (i, desc) in descriptors.iter().enumerate() { ++ info!(" {}. {}", i + 1, desc.device_driver.compatible()); ++ } + }); + } + } diff -uNr 18_backtrace/kernel/src/lib.rs 19_kernel_heap/kernel/src/lib.rs --- 18_backtrace/kernel/src/lib.rs @@ -870,10 +990,10 @@ diff -uNr 18_backtrace/kernel/src/main.rs 19_kernel_heap/kernel/src/main.rs +extern crate alloc; + - use libkernel::{bsp, cpu, driver, exception, info, memory, state, time, warn}; + use libkernel::{bsp, cpu, driver, exception, info, memory, state, time}; /// Early init code. -@@ -92,6 +94,9 @@ +@@ -73,6 +75,9 @@ info!("Registered IRQ handlers:"); exception::asynchronous::irq_manager().print_handler(); @@ -887,7 +1007,7 @@ diff -uNr 18_backtrace/kernel/src/main.rs 19_kernel_heap/kernel/src/main.rs diff -uNr 18_backtrace/kernel/src/memory/heap_alloc.rs 19_kernel_heap/kernel/src/memory/heap_alloc.rs --- 18_backtrace/kernel/src/memory/heap_alloc.rs +++ 19_kernel_heap/kernel/src/memory/heap_alloc.rs -@@ -0,0 +1,137 @@ +@@ -0,0 +1,147 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2022 Andre Richter @@ -899,8 +1019,10 @@ diff -uNr 18_backtrace/kernel/src/memory/heap_alloc.rs 19_kernel_heap/kernel/src + memory::{Address, Virtual}, + synchronization, + synchronization::IRQSafeNullLock, ++ warn, +}; +use alloc::alloc::{GlobalAlloc, Layout}; ++use core::sync::atomic::{AtomicBool, Ordering}; +use linked_list_allocator::Heap as LinkedListHeap; + +//-------------------------------------------------------------------------------------------------- @@ -1019,11 +1141,19 @@ diff -uNr 18_backtrace/kernel/src/memory/heap_alloc.rs 19_kernel_heap/kernel/src + +/// Query the BSP for the heap region and initialize the kernel's heap allocator with it. +pub fn kernel_init_heap_allocator() { ++ static INIT_DONE: AtomicBool = AtomicBool::new(false); ++ if INIT_DONE.load(Ordering::Relaxed) { ++ warn!("Already initialized"); ++ return; ++ } ++ + let region = bsp::memory::mmu::virt_heap_region(); + + KERNEL_HEAP_ALLOCATOR.inner.lock(|inner| unsafe { + inner.init(region.start_addr().as_usize() as *mut u8, region.size()) + }); ++ ++ INIT_DONE.store(true, Ordering::Relaxed); +} diff -uNr 18_backtrace/kernel/src/memory/mmu/mapping_record.rs 19_kernel_heap/kernel/src/memory/mmu/mapping_record.rs @@ -1280,6 +1410,19 @@ diff -uNr 18_backtrace/kernel/src/print.rs 19_kernel_heap/kernel/src/print.rs + }) +} +diff -uNr 18_backtrace/kernel/src/state.rs 19_kernel_heap/kernel/src/state.rs +--- 18_backtrace/kernel/src/state.rs ++++ 19_kernel_heap/kernel/src/state.rs +@@ -52,7 +52,7 @@ + const SINGLE_CORE_MAIN: u8 = 1; + const MULTI_CORE_MAIN: u8 = 2; + +- /// Create an instance. ++ /// Create a new instance. + pub const fn new() -> Self { + Self(AtomicU8::new(Self::INIT)) + } + diff -uNr 18_backtrace/Makefile 19_kernel_heap/Makefile --- 18_backtrace/Makefile +++ 19_kernel_heap/Makefile diff --git a/19_kernel_heap/kernel/src/bsp/device_driver/arm/gicv2.rs b/19_kernel_heap/kernel/src/bsp/device_driver/arm/gicv2.rs index 69ba8513..fee8bb4c 100644 --- a/19_kernel_heap/kernel/src/bsp/device_driver/arm/gicv2.rs +++ b/19_kernel_heap/kernel/src/bsp/device_driver/arm/gicv2.rs @@ -80,7 +80,8 @@ mod gicc; mod gicd; use crate::{ - bsp, cpu, driver, exception, + bsp::{self, device_driver::common::BoundedUsize}, + cpu, driver, exception, memory::{Address, Virtual}, synchronization, synchronization::InitStateLock, @@ -91,14 +92,14 @@ use alloc::vec::Vec; // Private Definitions //-------------------------------------------------------------------------------------------------- -type HandlerTable = Vec>; +type HandlerTable = Vec>>; //-------------------------------------------------------------------------------------------------- // Public Definitions //-------------------------------------------------------------------------------------------------- /// Used for the associated type of trait [`exception::asynchronous::interface::IRQManager`]. -pub type IRQNumber = exception::asynchronous::IRQNumber<{ GICv2::MAX_IRQ_NUMBER }>; +pub type IRQNumber = BoundedUsize<{ GICv2::MAX_IRQ_NUMBER }>; /// Representation of the GIC. pub struct GICv2 { @@ -110,9 +111,6 @@ pub struct GICv2 { /// Stores registered IRQ handlers. Writable only during kernel init. RO afterwards. handler_table: InitStateLock, - - /// Callback to be invoked after successful init. - post_init_callback: fn(), } //-------------------------------------------------------------------------------------------------- @@ -132,13 +130,11 @@ impl GICv2 { pub const unsafe fn new( gicd_mmio_start_addr: Address, gicc_mmio_start_addr: Address, - post_init_callback: fn(), ) -> Self { Self { gicd: gicd::GICD::new(gicd_mmio_start_addr), gicc: gicc::GICC::new(gicc_mmio_start_addr), handler_table: InitStateLock::new(Vec::new()), - post_init_callback, } } } @@ -149,13 +145,15 @@ impl GICv2 { use synchronization::interface::ReadWriteEx; impl driver::interface::DeviceDriver for GICv2 { + type IRQNumberType = IRQNumber; + fn compatible(&self) -> &'static str { Self::COMPATIBLE } unsafe fn init(&self) -> Result<(), &'static str> { self.handler_table - .write(|table| table.resize(IRQNumber::NUM_TOTAL, None)); + .write(|table| table.resize(IRQNumber::MAX_INCLUSIVE + 1, None)); if bsp::cpu::BOOT_CORE_ID == cpu::smp::core_id() { self.gicd.boot_core_init(); @@ -164,8 +162,6 @@ impl driver::interface::DeviceDriver for GICv2 { self.gicc.priority_accept_all(); self.gicc.enable(); - (self.post_init_callback)(); - Ok(()) } } @@ -175,23 +171,22 @@ impl exception::asynchronous::interface::IRQManager for GICv2 { fn register_handler( &self, - irq_number: Self::IRQNumberType, - descriptor: exception::asynchronous::IRQDescriptor, + irq_handler_descriptor: exception::asynchronous::IRQHandlerDescriptor, ) -> Result<(), &'static str> { self.handler_table.write(|table| { - let irq_number = irq_number.get(); + let irq_number = irq_handler_descriptor.number().get(); if table[irq_number].is_some() { return Err("IRQ handler already registered"); } - table[irq_number] = Some(descriptor); + table[irq_number] = Some(irq_handler_descriptor); Ok(()) }) } - fn enable(&self, irq_number: Self::IRQNumberType) { + fn enable(&self, irq_number: &Self::IRQNumberType) { self.gicd.enable(irq_number); } @@ -214,7 +209,7 @@ impl exception::asynchronous::interface::IRQManager for GICv2 { None => panic!("No handler registered for IRQ {}", irq_number), Some(descriptor) => { // Call the IRQ handler. Panics on failure. - descriptor.handler.handle().expect("Error handling IRQ"); + descriptor.handler().handle().expect("Error handling IRQ"); } } }); @@ -231,7 +226,7 @@ impl exception::asynchronous::interface::IRQManager for GICv2 { self.handler_table.read(|table| { for (i, opt) in table.iter().skip(32).enumerate() { if let Some(handler) = opt { - info!(" {: >3}. {}", i + 32, handler.name); + info!(" {: >3}. {}", i + 32, handler.name()); } } }); diff --git a/19_kernel_heap/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs b/19_kernel_heap/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs index a9c97a8e..8aebcf2b 100644 --- a/19_kernel_heap/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs +++ b/19_kernel_heap/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs @@ -172,7 +172,7 @@ impl GICD { } /// Enable an interrupt. - pub fn enable(&self, irq_num: super::IRQNumber) { + pub fn enable(&self, irq_num: &super::IRQNumber) { let irq_num = irq_num.get(); // Each bit in the u32 enable register corresponds to one IRQ number. Shift right by 5 diff --git a/19_kernel_heap/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs b/19_kernel_heap/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs index 2281e66a..fb61a651 100644 --- a/19_kernel_heap/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs +++ b/19_kernel_heap/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs @@ -7,6 +7,7 @@ use crate::{ bsp::device_driver::common::MMIODerefWrapper, driver, + exception::asynchronous::IRQNumber, memory::{Address, Virtual}, synchronization, synchronization::IRQSafeNullLock, @@ -122,7 +123,6 @@ struct GPIOInner { /// Representation of the GPIO HW. pub struct GPIO { inner: IRQSafeNullLock, - post_init_callback: fn(), } //-------------------------------------------------------------------------------------------------- @@ -202,10 +202,9 @@ impl GPIO { /// # Safety /// /// - The user must ensure to provide a correct MMIO start address. - pub const unsafe fn new(mmio_start_addr: Address, post_init_callback: fn()) -> Self { + pub const unsafe fn new(mmio_start_addr: Address) -> Self { Self { inner: IRQSafeNullLock::new(GPIOInner::new(mmio_start_addr)), - post_init_callback, } } @@ -221,13 +220,9 @@ impl GPIO { use synchronization::interface::Mutex; impl driver::interface::DeviceDriver for GPIO { + type IRQNumberType = IRQNumber; + fn compatible(&self) -> &'static str { Self::COMPATIBLE } - - unsafe fn init(&self) -> Result<(), &'static str> { - (self.post_init_callback)(); - - Ok(()) - } } diff --git a/19_kernel_heap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs b/19_kernel_heap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs index 658d3705..a03b472a 100644 --- a/19_kernel_heap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs +++ b/19_kernel_heap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs @@ -7,9 +7,12 @@ mod peripheral_ic; use crate::{ - driver, exception, + bsp::device_driver::common::BoundedUsize, + driver, + exception::{self, asynchronous::IRQHandlerDescriptor}, memory::{Address, Virtual}, }; +use core::fmt; //-------------------------------------------------------------------------------------------------- // Private Definitions @@ -24,10 +27,8 @@ struct PendingIRQs { // Public Definitions //-------------------------------------------------------------------------------------------------- -pub type LocalIRQ = - exception::asynchronous::IRQNumber<{ InterruptController::MAX_LOCAL_IRQ_NUMBER }>; -pub type PeripheralIRQ = - exception::asynchronous::IRQNumber<{ InterruptController::MAX_PERIPHERAL_IRQ_NUMBER }>; +pub type LocalIRQ = BoundedUsize<{ InterruptController::MAX_LOCAL_IRQ_NUMBER }>; +pub type PeripheralIRQ = BoundedUsize<{ InterruptController::MAX_PERIPHERAL_IRQ_NUMBER }>; /// Used for the associated type of trait [`exception::asynchronous::interface::IRQManager`]. #[derive(Copy, Clone)] @@ -40,7 +41,6 @@ pub enum IRQNumber { /// Representation of the Interrupt Controller. pub struct InterruptController { periph: peripheral_ic::PeripheralIC, - post_init_callback: fn(), } //-------------------------------------------------------------------------------------------------- @@ -71,6 +71,15 @@ impl Iterator for PendingIRQs { // Public Code //-------------------------------------------------------------------------------------------------- +impl fmt::Display for IRQNumber { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Self::Local(number) => write!(f, "Local({})", number), + Self::Peripheral(number) => write!(f, "Peripheral({})", number), + } + } +} + impl InterruptController { // Restrict to 3 for now. This makes future code for local_ic.rs more straight forward. const MAX_LOCAL_IRQ_NUMBER: usize = 3; @@ -83,13 +92,9 @@ impl InterruptController { /// # Safety /// /// - The user must ensure to provide a correct MMIO start address. - pub const unsafe fn new( - periph_mmio_start_addr: Address, - post_init_callback: fn(), - ) -> Self { + pub const unsafe fn new(periph_mmio_start_addr: Address) -> Self { Self { periph: peripheral_ic::PeripheralIC::new(periph_mmio_start_addr), - post_init_callback, } } } @@ -99,6 +104,8 @@ impl InterruptController { //------------------------------------------------------------------------------ impl driver::interface::DeviceDriver for InterruptController { + type IRQNumberType = IRQNumber; + fn compatible(&self) -> &'static str { Self::COMPATIBLE } @@ -106,8 +113,6 @@ impl driver::interface::DeviceDriver for InterruptController { unsafe fn init(&self) -> Result<(), &'static str> { self.periph.init(); - (self.post_init_callback)(); - Ok(()) } } @@ -117,16 +122,23 @@ impl exception::asynchronous::interface::IRQManager for InterruptController { fn register_handler( &self, - irq: Self::IRQNumberType, - descriptor: exception::asynchronous::IRQDescriptor, + irq_handler_descriptor: exception::asynchronous::IRQHandlerDescriptor, ) -> Result<(), &'static str> { - match irq { + match irq_handler_descriptor.number() { IRQNumber::Local(_) => unimplemented!("Local IRQ controller not implemented."), - IRQNumber::Peripheral(pirq) => self.periph.register_handler(pirq, descriptor), + IRQNumber::Peripheral(pirq) => { + let periph_descriptor = IRQHandlerDescriptor::new( + pirq, + irq_handler_descriptor.name(), + irq_handler_descriptor.handler(), + ); + + self.periph.register_handler(periph_descriptor) + } } } - fn enable(&self, irq: Self::IRQNumberType) { + fn enable(&self, irq: &Self::IRQNumberType) { match irq { IRQNumber::Local(_) => unimplemented!("Local IRQ controller not implemented."), IRQNumber::Peripheral(pirq) => self.periph.enable(pirq), diff --git a/19_kernel_heap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs b/19_kernel_heap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs index 90b56378..238088a8 100644 --- a/19_kernel_heap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs +++ b/19_kernel_heap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs @@ -53,7 +53,7 @@ type WriteOnlyRegisters = MMIODerefWrapper; /// Abstraction for the ReadOnly parts of the associated MMIO registers. type ReadOnlyRegisters = MMIODerefWrapper; -type HandlerTable = Vec>; +type HandlerTable = Vec>>; //-------------------------------------------------------------------------------------------------- // Public Definitions @@ -92,7 +92,7 @@ impl PeripheralIC { /// Called by the kernel to bring up the device. pub fn init(&self) { self.handler_table - .write(|table| table.resize(PeripheralIRQ::NUM_TOTAL, None)); + .write(|table| table.resize(PeripheralIRQ::MAX_INCLUSIVE + 1, None)); } /// Query the list of pending IRQs. @@ -114,23 +114,22 @@ impl exception::asynchronous::interface::IRQManager for PeripheralIC { fn register_handler( &self, - irq: Self::IRQNumberType, - descriptor: exception::asynchronous::IRQDescriptor, + irq_handler_descriptor: exception::asynchronous::IRQHandlerDescriptor, ) -> Result<(), &'static str> { self.handler_table.write(|table| { - let irq_number = irq.get(); + let irq_number = irq_handler_descriptor.number().get(); if table[irq_number].is_some() { return Err("IRQ handler already registered"); } - table[irq_number] = Some(descriptor); + table[irq_number] = Some(irq_handler_descriptor); Ok(()) }) } - fn enable(&self, irq: Self::IRQNumberType) { + fn enable(&self, irq: &Self::IRQNumberType) { self.wo_registers.lock(|regs| { let enable_reg = if irq.get() <= 31 { ®s.ENABLE_1 @@ -156,7 +155,7 @@ impl exception::asynchronous::interface::IRQManager for PeripheralIC { None => panic!("No handler registered for IRQ {}", irq_number), Some(descriptor) => { // Call the IRQ handler. Panics on failure. - descriptor.handler.handle().expect("Error handling IRQ"); + descriptor.handler().handle().expect("Error handling IRQ"); } } } @@ -171,7 +170,7 @@ impl exception::asynchronous::interface::IRQManager for PeripheralIC { self.handler_table.read(|table| { for (i, opt) in table.iter().enumerate() { if let Some(handler) = opt { - info!(" {: >3}. {}", i, handler.name); + info!(" {: >3}. {}", i, handler.name()); } } }); diff --git a/19_kernel_heap/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs b/19_kernel_heap/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs index 26593039..3e7e1812 100644 --- a/19_kernel_heap/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs +++ b/19_kernel_heap/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs @@ -10,9 +10,9 @@ //! - use crate::{ - bsp, bsp::device_driver::common::MMIODerefWrapper, - console, cpu, driver, exception, + console, cpu, driver, + exception::{self, asynchronous::IRQNumber}, memory::{Address, Virtual}, synchronization, synchronization::IRQSafeNullLock, @@ -233,8 +233,6 @@ struct PL011UartInner { /// Representation of the UART. pub struct PL011Uart { inner: IRQSafeNullLock, - irq_number: bsp::device_driver::IRQNumber, - post_init_callback: fn(), } //-------------------------------------------------------------------------------------------------- @@ -405,16 +403,9 @@ impl PL011Uart { /// # Safety /// /// - The user must ensure to provide a correct MMIO start address. - /// - The user must ensure to provide correct IRQ numbers. - pub const unsafe fn new( - mmio_start_addr: Address, - irq_number: bsp::device_driver::IRQNumber, - post_init_callback: fn(), - ) -> Self { + pub const unsafe fn new(mmio_start_addr: Address) -> Self { Self { inner: IRQSafeNullLock::new(PL011UartInner::new(mmio_start_addr)), - irq_number, - post_init_callback, } } } @@ -425,27 +416,28 @@ impl PL011Uart { use synchronization::interface::Mutex; impl driver::interface::DeviceDriver for PL011Uart { + type IRQNumberType = IRQNumber; + fn compatible(&self) -> &'static str { Self::COMPATIBLE } unsafe fn init(&self) -> Result<(), &'static str> { self.inner.lock(|inner| inner.init()); - (self.post_init_callback)(); Ok(()) } - fn register_and_enable_irq_handler(&'static self) -> Result<(), &'static str> { - use exception::asynchronous::{irq_manager, IRQDescriptor}; + fn register_and_enable_irq_handler( + &'static self, + irq_number: &Self::IRQNumberType, + ) -> Result<(), &'static str> { + use exception::asynchronous::{irq_manager, IRQHandlerDescriptor}; - let descriptor = IRQDescriptor { - name: Self::COMPATIBLE, - handler: self, - }; + let descriptor = IRQHandlerDescriptor::new(*irq_number, Self::COMPATIBLE, self); - irq_manager().register_handler(self.irq_number, descriptor)?; - irq_manager().enable(self.irq_number); + irq_manager().register_handler(descriptor)?; + irq_manager().enable(irq_number); Ok(()) } diff --git a/19_kernel_heap/kernel/src/bsp/device_driver/common.rs b/19_kernel_heap/kernel/src/bsp/device_driver/common.rs index 69f038d4..ca7aeb76 100644 --- a/19_kernel_heap/kernel/src/bsp/device_driver/common.rs +++ b/19_kernel_heap/kernel/src/bsp/device_driver/common.rs @@ -5,7 +5,7 @@ //! Common device driver code. use crate::memory::{Address, Virtual}; -use core::{marker::PhantomData, ops}; +use core::{fmt, marker::PhantomData, ops}; //-------------------------------------------------------------------------------------------------- // Public Definitions @@ -16,6 +16,10 @@ pub struct MMIODerefWrapper { phantom: PhantomData T>, } +/// A wrapper type for usize with integrated range bound check. +#[derive(Copy, Clone)] +pub struct BoundedUsize(usize); + //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- @@ -37,3 +41,25 @@ impl ops::Deref for MMIODerefWrapper { unsafe { &*(self.start_addr.as_usize() as *const _) } } } + +impl BoundedUsize<{ MAX_INCLUSIVE }> { + pub const MAX_INCLUSIVE: usize = MAX_INCLUSIVE; + + /// Creates a new instance if number <= MAX_INCLUSIVE. + pub const fn new(number: usize) -> Self { + assert!(number <= MAX_INCLUSIVE); + + Self(number) + } + + /// Return the wrapped number. + pub const fn get(self) -> usize { + self.0 + } +} + +impl fmt::Display for BoundedUsize<{ MAX_INCLUSIVE }> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.0) + } +} diff --git a/19_kernel_heap/kernel/src/bsp/raspberrypi/driver.rs b/19_kernel_heap/kernel/src/bsp/raspberrypi/driver.rs index 5571c392..ca3435aa 100644 --- a/19_kernel_heap/kernel/src/bsp/raspberrypi/driver.rs +++ b/19_kernel_heap/kernel/src/bsp/raspberrypi/driver.rs @@ -7,28 +7,16 @@ use super::{exception, memory::map::mmio}; use crate::{ bsp::device_driver, - console, driver, exception as generic_exception, memory, + console, driver as generic_driver, + exception::{self as generic_exception}, + memory, memory::mmu::MMIODescriptor, - synchronization::{interface::ReadWriteEx, InitStateLock}, }; -use alloc::vec::Vec; use core::{ mem::MaybeUninit, sync::atomic::{AtomicBool, Ordering}, }; -pub use device_driver::IRQNumber; - -//-------------------------------------------------------------------------------------------------- -// Private Definitions -//-------------------------------------------------------------------------------------------------- - -/// Device Driver Manager type. -struct BSPDriverManager { - device_drivers: InitStateLock>, - init_done: AtomicBool, -} - //-------------------------------------------------------------------------------------------------- // Global instances //-------------------------------------------------------------------------------------------------- @@ -43,149 +31,154 @@ static mut INTERRUPT_CONTROLLER: MaybeUninit #[cfg(feature = "bsp_rpi4")] static mut INTERRUPT_CONTROLLER: MaybeUninit = MaybeUninit::uninit(); -static BSP_DRIVER_MANAGER: BSPDriverManager = BSPDriverManager { - device_drivers: InitStateLock::new(Vec::new()), - init_done: AtomicBool::new(false), -}; - //-------------------------------------------------------------------------------------------------- // Private Code //-------------------------------------------------------------------------------------------------- -impl BSPDriverManager { - unsafe fn instantiate_uart(&self) -> Result<(), &'static str> { - let mmio_descriptor = MMIODescriptor::new(mmio::PL011_UART_START, mmio::PL011_UART_SIZE); - let virt_addr = - memory::mmu::kernel_map_mmio(device_driver::PL011Uart::COMPATIBLE, &mmio_descriptor)?; +/// This must be called only after successful init of the memory subsystem. +unsafe fn instantiate_uart() -> Result<(), &'static str> { + let mmio_descriptor = MMIODescriptor::new(mmio::PL011_UART_START, mmio::PL011_UART_SIZE); + let virt_addr = + memory::mmu::kernel_map_mmio(device_driver::PL011Uart::COMPATIBLE, &mmio_descriptor)?; - // This is safe to do, because it is only called from the init'ed instance itself. - fn uart_post_init() { - console::register_console(unsafe { PL011_UART.assume_init_ref() }); - } + PL011_UART.write(device_driver::PL011Uart::new(virt_addr)); - PL011_UART.write(device_driver::PL011Uart::new( - virt_addr, - exception::asynchronous::irq_map::PL011_UART, - uart_post_init, - )); + Ok(()) +} - Ok(()) - } +/// This must be called only after successful init of the UART driver. +unsafe fn post_init_uart() -> Result<(), &'static str> { + console::register_console(PL011_UART.assume_init_ref()); - unsafe fn instantiate_gpio(&self) -> Result<(), &'static str> { - let mmio_descriptor = MMIODescriptor::new(mmio::GPIO_START, mmio::GPIO_SIZE); - let virt_addr = - memory::mmu::kernel_map_mmio(device_driver::GPIO::COMPATIBLE, &mmio_descriptor)?; + Ok(()) +} - // This is safe to do, because it is only called from the init'ed instance itself. - fn gpio_post_init() { - unsafe { GPIO.assume_init_ref().map_pl011_uart() }; - } +/// This must be called only after successful init of the memory subsystem. +unsafe fn instantiate_gpio() -> Result<(), &'static str> { + let mmio_descriptor = MMIODescriptor::new(mmio::GPIO_START, mmio::GPIO_SIZE); + let virt_addr = + memory::mmu::kernel_map_mmio(device_driver::GPIO::COMPATIBLE, &mmio_descriptor)?; - GPIO.write(device_driver::GPIO::new(virt_addr, gpio_post_init)); + GPIO.write(device_driver::GPIO::new(virt_addr)); - Ok(()) - } + Ok(()) +} - #[cfg(feature = "bsp_rpi3")] - unsafe fn instantiate_interrupt_controller(&self) -> Result<(), &'static str> { - let periph_mmio_descriptor = - MMIODescriptor::new(mmio::PERIPHERAL_IC_START, mmio::PERIPHERAL_IC_SIZE); - let periph_virt_addr = memory::mmu::kernel_map_mmio( - device_driver::InterruptController::COMPATIBLE, - &periph_mmio_descriptor, - )?; - - // This is safe to do, because it is only called from the init'ed instance itself. - fn interrupt_controller_post_init() { - generic_exception::asynchronous::register_irq_manager(unsafe { - INTERRUPT_CONTROLLER.assume_init_ref() - }); - } - - INTERRUPT_CONTROLLER.write(device_driver::InterruptController::new( - periph_virt_addr, - interrupt_controller_post_init, - )); - - Ok(()) - } +/// This must be called only after successful init of the GPIO driver. +unsafe fn post_init_gpio() -> Result<(), &'static str> { + GPIO.assume_init_ref().map_pl011_uart(); + Ok(()) +} - #[cfg(feature = "bsp_rpi4")] - unsafe fn instantiate_interrupt_controller(&self) -> Result<(), &'static str> { - let gicd_mmio_descriptor = MMIODescriptor::new(mmio::GICD_START, mmio::GICD_SIZE); - let gicd_virt_addr = memory::mmu::kernel_map_mmio("GICv2 GICD", &gicd_mmio_descriptor)?; +/// This must be called only after successful init of the memory subsystem. +#[cfg(feature = "bsp_rpi3")] +unsafe fn instantiate_interrupt_controller() -> Result<(), &'static str> { + let periph_mmio_descriptor = + MMIODescriptor::new(mmio::PERIPHERAL_IC_START, mmio::PERIPHERAL_IC_SIZE); + let periph_virt_addr = memory::mmu::kernel_map_mmio( + device_driver::InterruptController::COMPATIBLE, + &periph_mmio_descriptor, + )?; - let gicc_mmio_descriptor = MMIODescriptor::new(mmio::GICC_START, mmio::GICC_SIZE); - let gicc_virt_addr = memory::mmu::kernel_map_mmio("GICV2 GICC", &gicc_mmio_descriptor)?; + INTERRUPT_CONTROLLER.write(device_driver::InterruptController::new(periph_virt_addr)); - // This is safe to do, because it is only called from the init'ed instance itself. - fn interrupt_controller_post_init() { - generic_exception::asynchronous::register_irq_manager(unsafe { - INTERRUPT_CONTROLLER.assume_init_ref() - }); - } + Ok(()) +} - INTERRUPT_CONTROLLER.write(device_driver::GICv2::new( - gicd_virt_addr, - gicc_virt_addr, - interrupt_controller_post_init, - )); +/// This must be called only after successful init of the memory subsystem. +#[cfg(feature = "bsp_rpi4")] +unsafe fn instantiate_interrupt_controller() -> Result<(), &'static str> { + let gicd_mmio_descriptor = MMIODescriptor::new(mmio::GICD_START, mmio::GICD_SIZE); + let gicd_virt_addr = memory::mmu::kernel_map_mmio("GICv2 GICD", &gicd_mmio_descriptor)?; - Ok(()) - } + let gicc_mmio_descriptor = MMIODescriptor::new(mmio::GICC_START, mmio::GICC_SIZE); + let gicc_virt_addr = memory::mmu::kernel_map_mmio("GICV2 GICC", &gicc_mmio_descriptor)?; - unsafe fn register_drivers(&self) { - self.device_drivers.write(|drivers| { - drivers.push(PL011_UART.assume_init_ref()); - drivers.push(GPIO.assume_init_ref()); - drivers.push(INTERRUPT_CONTROLLER.assume_init_ref()); - }); - } + INTERRUPT_CONTROLLER.write(device_driver::GICv2::new(gicd_virt_addr, gicc_virt_addr)); + + Ok(()) } -//-------------------------------------------------------------------------------------------------- -// Public Code -//-------------------------------------------------------------------------------------------------- +/// This must be called only after successful init of the interrupt controller driver. +unsafe fn post_init_interrupt_controller() -> Result<(), &'static str> { + generic_exception::asynchronous::register_irq_manager(INTERRUPT_CONTROLLER.assume_init_ref()); -/// Return a reference to the driver manager. -pub fn driver_manager() -> &'static impl driver::interface::DriverManager { - &BSP_DRIVER_MANAGER + Ok(()) } -//------------------------------------------------------------------------------ -// OS Interface Code -//------------------------------------------------------------------------------ -use driver::interface::DeviceDriver; +/// Function needs to ensure that driver registration happens only after correct instantiation. +unsafe fn driver_uart() -> Result<(), &'static str> { + instantiate_uart()?; + + let uart_descriptor = generic_driver::DeviceDriverDescriptor::new( + PL011_UART.assume_init_ref(), + Some(post_init_uart), + Some(exception::asynchronous::irq_map::PL011_UART), + ); + generic_driver::driver_manager().register_driver(uart_descriptor); -impl driver::interface::DriverManager for BSPDriverManager { - unsafe fn instantiate_drivers(&self) -> Result<(), &'static str> { - if self.init_done.load(Ordering::Relaxed) { - return Err("Drivers already instantiated"); - } + Ok(()) +} - self.instantiate_uart()?; - self.instantiate_gpio()?; - self.instantiate_interrupt_controller()?; +/// Function needs to ensure that driver registration happens only after correct instantiation. +unsafe fn driver_gpio() -> Result<(), &'static str> { + instantiate_gpio()?; - self.register_drivers(); + let gpio_descriptor = generic_driver::DeviceDriverDescriptor::new( + GPIO.assume_init_ref(), + Some(post_init_gpio), + None, + ); + generic_driver::driver_manager().register_driver(gpio_descriptor); - self.init_done.store(true, Ordering::Relaxed); - Ok(()) - } + Ok(()) +} - fn all_device_drivers(&self) -> &Vec<&(dyn DeviceDriver + Sync)> { - self.device_drivers.read(|drivers| drivers) - } +/// Function needs to ensure that driver registration happens only after correct instantiation. +unsafe fn driver_interrupt_controller() -> Result<(), &'static str> { + instantiate_interrupt_controller()?; + + let interrupt_controller_descriptor = generic_driver::DeviceDriverDescriptor::new( + INTERRUPT_CONTROLLER.assume_init_ref(), + Some(post_init_interrupt_controller), + None, + ); + generic_driver::driver_manager().register_driver(interrupt_controller_descriptor); - #[cfg(feature = "test_build")] - fn qemu_bring_up_console(&self) { - use crate::cpu; + Ok(()) +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- - unsafe { - self.instantiate_uart() - .unwrap_or_else(|_| cpu::qemu_exit_failure()); - console::register_console(PL011_UART.assume_init_ref()); - }; +/// Initialize the driver subsystem. +/// +/// # Safety +/// +/// See child function calls. +pub unsafe fn init() -> Result<(), &'static str> { + static INIT_DONE: AtomicBool = AtomicBool::new(false); + if INIT_DONE.load(Ordering::Relaxed) { + return Err("Init already done"); } + + driver_uart()?; + driver_gpio()?; + driver_interrupt_controller()?; + + INIT_DONE.store(true, Ordering::Relaxed); + Ok(()) +} + +/// Minimal code needed to bring up the console in QEMU (for testing only). This is often less steps +/// than on real hardware due to QEMU's abstractions. +#[cfg(feature = "test_build")] +pub fn qemu_bring_up_console() { + use crate::cpu; + + unsafe { + instantiate_uart().unwrap_or_else(|_| cpu::qemu_exit_failure()); + console::register_console(PL011_UART.assume_init_ref()); + }; } diff --git a/19_kernel_heap/kernel/src/bsp/raspberrypi/exception/asynchronous.rs b/19_kernel_heap/kernel/src/bsp/raspberrypi/exception/asynchronous.rs index ab20d86d..06a67558 100644 --- a/19_kernel_heap/kernel/src/bsp/raspberrypi/exception/asynchronous.rs +++ b/19_kernel_heap/kernel/src/bsp/raspberrypi/exception/asynchronous.rs @@ -10,6 +10,9 @@ use crate::bsp; // Public Definitions //-------------------------------------------------------------------------------------------------- +/// Export for reuse in generic asynchronous.rs. +pub use bsp::device_driver::IRQNumber; + #[cfg(feature = "bsp_rpi3")] pub(in crate::bsp) mod irq_map { use super::bsp::device_driver::{IRQNumber, PeripheralIRQ}; diff --git a/19_kernel_heap/kernel/src/driver.rs b/19_kernel_heap/kernel/src/driver.rs index d884d471..2f22fd20 100644 --- a/19_kernel_heap/kernel/src/driver.rs +++ b/19_kernel_heap/kernel/src/driver.rs @@ -4,16 +4,24 @@ //! Driver support. +use crate::{ + exception, info, + synchronization::{interface::ReadWriteEx, InitStateLock}, +}; +use alloc::vec::Vec; +use core::fmt; + //-------------------------------------------------------------------------------------------------- // Public Definitions //-------------------------------------------------------------------------------------------------- /// Driver interfaces. pub mod interface { - use alloc::vec::Vec; - /// Device Driver functions. pub trait DeviceDriver { + /// Different interrupt controllers might use different types for IRQ number. + type IRQNumberType: super::fmt::Display; + /// Return a compatibility string for identifying the driver. fn compatible(&self) -> &'static str; @@ -26,32 +34,145 @@ pub mod interface { Ok(()) } - /// Called by the kernel to register and enable the device's IRQ handlers, if any. + /// Called by the kernel to register and enable the device's IRQ handler. /// /// Rust's type system will prevent a call to this function unless the calling instance /// itself has static lifetime. - fn register_and_enable_irq_handler(&'static self) -> Result<(), &'static str> { - Ok(()) + fn register_and_enable_irq_handler( + &'static self, + irq_number: &Self::IRQNumberType, + ) -> Result<(), &'static str> { + panic!( + "Attempt to enable IRQ {} for device {}, but driver does not support this", + irq_number, + self.compatible() + ) + } + } +} + +/// Tpye to be used as an optional callback after a driver's init() has run. +pub type DeviceDriverPostInitCallback = unsafe fn() -> Result<(), &'static str>; + +/// A descriptor for device drivers. +pub struct DeviceDriverDescriptor +where + T: 'static, +{ + device_driver: &'static (dyn interface::DeviceDriver + Sync), + post_init_callback: Option, + irq_number: Option, +} + +/// Provides device driver management functions. +pub struct DriverManager +where + T: 'static, +{ + descriptors: InitStateLock>>, +} + +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +static DRIVER_MANAGER: DriverManager = DriverManager::new(); + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +impl DeviceDriverDescriptor { + /// Create an instance. + pub fn new( + device_driver: &'static (dyn interface::DeviceDriver + Sync), + post_init_callback: Option, + irq_number: Option, + ) -> Self { + Self { + device_driver, + post_init_callback, + irq_number, + } + } +} + +/// Return a reference to the global DriverManager. +pub fn driver_manager() -> &'static DriverManager { + &DRIVER_MANAGER +} + +impl DriverManager +where + T: fmt::Display, +{ + /// Create an instance. + pub const fn new() -> Self { + Self { + descriptors: InitStateLock::new(Vec::new()), } } - /// Device driver management functions. + /// Register a device driver with the kernel. + pub fn register_driver(&self, descriptor: DeviceDriverDescriptor) { + self.descriptors + .write(|descriptors| descriptors.push(descriptor)); + } + + /// Fully initialize all drivers and their interrupts handlers. /// - /// The `BSP` is supposed to supply one global instance. - pub trait DriverManager { - /// Instantiate all drivers. - /// - /// # Safety - /// - /// Must be called before `all_device_drivers`. - unsafe fn instantiate_drivers(&self) -> Result<(), &'static str>; + /// # Safety + /// + /// - During init, drivers might do stuff with system-wide impact. + pub unsafe fn init_drivers_and_irqs(&self) { + self.descriptors.read(|descriptors| { + for descriptor in descriptors { + // 1. Initialize driver. + if let Err(x) = descriptor.device_driver.init() { + panic!( + "Error initializing driver: {}: {}", + descriptor.device_driver.compatible(), + x + ); + } - /// Return a vector of references to all `BSP`-instantiated drivers. - fn all_device_drivers(&self) -> &Vec<&(dyn DeviceDriver + Sync)>; + // 2. Call corresponding post init callback. + if let Some(callback) = &descriptor.post_init_callback { + if let Err(x) = callback() { + panic!( + "Error during driver post-init callback: {}: {}", + descriptor.device_driver.compatible(), + x + ); + } + } + } + + // 3. After all post-init callbacks were done, the interrupt controller should be + // registered and functional. So let drivers register with it now. + for descriptor in descriptors { + if let Some(irq_number) = &descriptor.irq_number { + if let Err(x) = descriptor + .device_driver + .register_and_enable_irq_handler(irq_number) + { + panic!( + "Error during driver interrupt handler registration: {}: {}", + descriptor.device_driver.compatible(), + x + ); + } + } + } + }) + } - /// Minimal code needed to bring up the console in QEMU (for testing only). This is often - /// less steps than on real hardware due to QEMU's abstractions. - #[cfg(feature = "test_build")] - fn qemu_bring_up_console(&self); + /// Enumerate all registered device drivers. + pub fn enumerate(&self) { + self.descriptors.read(|descriptors| { + for (i, desc) in descriptors.iter().enumerate() { + info!(" {}. {}", i + 1, desc.device_driver.compatible()); + } + }); } } diff --git a/19_kernel_heap/kernel/src/exception/asynchronous.rs b/19_kernel_heap/kernel/src/exception/asynchronous.rs index 83ca1aa6..c1f2a27b 100644 --- a/19_kernel_heap/kernel/src/exception/asynchronous.rs +++ b/19_kernel_heap/kernel/src/exception/asynchronous.rs @@ -10,7 +10,7 @@ mod arch_asynchronous; mod null_irq_manager; use crate::{bsp, synchronization}; -use core::{fmt, marker::PhantomData}; +use core::marker::PhantomData; //-------------------------------------------------------------------------------------------------- // Architectural Public Reexports @@ -24,14 +24,23 @@ pub use arch_asynchronous::{ // Public Definitions //-------------------------------------------------------------------------------------------------- +/// Interrupt number as defined by the BSP. +pub type IRQNumber = bsp::exception::asynchronous::IRQNumber; + /// Interrupt descriptor. #[derive(Copy, Clone)] -pub struct IRQDescriptor { +pub struct IRQHandlerDescriptor +where + T: Copy, +{ + /// The IRQ number. + number: T, + /// Descriptive name. - pub name: &'static str, + name: &'static str, /// Reference to handler trait object. - pub handler: &'static (dyn interface::IRQHandler + Sync), + handler: &'static (dyn interface::IRQHandler + Sync), } /// IRQContext token. @@ -61,17 +70,16 @@ pub mod interface { /// platform's interrupt controller. pub trait IRQManager { /// The IRQ number type depends on the implementation. - type IRQNumberType; + type IRQNumberType: Copy; /// Register a handler. fn register_handler( &self, - irq_number: Self::IRQNumberType, - descriptor: super::IRQDescriptor, + irq_handler_descriptor: super::IRQHandlerDescriptor, ) -> Result<(), &'static str>; /// Enable an interrupt in the controller. - fn enable(&self, irq_number: Self::IRQNumberType); + fn enable(&self, irq_number: &Self::IRQNumberType); /// Handle pending interrupts. /// @@ -91,16 +99,12 @@ pub mod interface { } } -/// A wrapper type for IRQ numbers with integrated range sanity check. -#[derive(Copy, Clone)] -pub struct IRQNumber(usize); - //-------------------------------------------------------------------------------------------------- // Global instances //-------------------------------------------------------------------------------------------------- static CUR_IRQ_MANAGER: InitStateLock< - &'static (dyn interface::IRQManager + Sync), + &'static (dyn interface::IRQManager + Sync), > = InitStateLock::new(&null_irq_manager::NULL_IRQ_MANAGER); //-------------------------------------------------------------------------------------------------- @@ -108,6 +112,39 @@ static CUR_IRQ_MANAGER: InitStateLock< //-------------------------------------------------------------------------------------------------- use synchronization::{interface::ReadWriteEx, InitStateLock}; +impl IRQHandlerDescriptor +where + T: Copy, +{ + /// Create an instance. + pub const fn new( + number: T, + name: &'static str, + handler: &'static (dyn interface::IRQHandler + Sync), + ) -> Self { + Self { + number, + name, + handler, + } + } + + /// Return the number. + pub const fn number(&self) -> T { + self.number + } + + /// Return the name. + pub const fn name(&self) -> &'static str { + self.name + } + + /// Return the handler. + pub const fn handler(&self) -> &'static (dyn interface::IRQHandler + Sync) { + self.handler + } +} + impl<'irq_context> IRQContext<'irq_context> { /// Creates an IRQContext token. /// @@ -125,29 +162,6 @@ impl<'irq_context> IRQContext<'irq_context> { } } -impl IRQNumber<{ MAX_INCLUSIVE }> { - /// The total number of IRQs this type supports. - pub const NUM_TOTAL: usize = MAX_INCLUSIVE + 1; - - /// Creates a new instance if number <= MAX_INCLUSIVE. - pub const fn new(number: usize) -> Self { - assert!(number <= MAX_INCLUSIVE); - - Self(number) - } - - /// Return the wrapped number. - pub const fn get(self) -> usize { - self.0 - } -} - -impl fmt::Display for IRQNumber<{ MAX_INCLUSIVE }> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}", self.0) - } -} - /// Executes the provided closure while IRQs are masked on the executing core. /// /// While the function temporarily changes the HW state of the executing core, it restores it to the @@ -163,8 +177,7 @@ pub fn exec_with_irq_masked(f: impl FnOnce() -> T) -> T { /// Register a new IRQ manager. pub fn register_irq_manager( - new_manager: &'static (dyn interface::IRQManager - + Sync), + new_manager: &'static (dyn interface::IRQManager + Sync), ) { CUR_IRQ_MANAGER.write(|manager| *manager = new_manager); } @@ -172,6 +185,6 @@ pub fn register_irq_manager( /// Return a reference to the currently registered IRQ manager. /// /// This is the IRQ manager used by the architectural interrupt handling code. -pub fn irq_manager() -> &'static dyn interface::IRQManager { +pub fn irq_manager() -> &'static dyn interface::IRQManager { CUR_IRQ_MANAGER.read(|manager| *manager) } diff --git a/19_kernel_heap/kernel/src/exception/asynchronous/null_irq_manager.rs b/19_kernel_heap/kernel/src/exception/asynchronous/null_irq_manager.rs index 560e3ce4..438f9649 100644 --- a/19_kernel_heap/kernel/src/exception/asynchronous/null_irq_manager.rs +++ b/19_kernel_heap/kernel/src/exception/asynchronous/null_irq_manager.rs @@ -4,8 +4,7 @@ //! Null IRQ Manager. -use super::{interface, IRQContext, IRQDescriptor}; -use crate::bsp; +use super::{interface, IRQContext, IRQHandlerDescriptor}; //-------------------------------------------------------------------------------------------------- // Public Definitions @@ -24,17 +23,16 @@ pub static NULL_IRQ_MANAGER: NullIRQManager = NullIRQManager {}; //-------------------------------------------------------------------------------------------------- impl interface::IRQManager for NullIRQManager { - type IRQNumberType = bsp::driver::IRQNumber; + type IRQNumberType = super::IRQNumber; fn register_handler( &self, - _irq_number: Self::IRQNumberType, - _descriptor: IRQDescriptor, + _descriptor: IRQHandlerDescriptor, ) -> Result<(), &'static str> { panic!("No IRQ Manager registered yet"); } - fn enable(&self, _irq_number: Self::IRQNumberType) { + fn enable(&self, _irq_number: &Self::IRQNumberType) { panic!("No IRQ Manager registered yet"); } diff --git a/19_kernel_heap/kernel/src/lib.rs b/19_kernel_heap/kernel/src/lib.rs index 8e4195e0..bba0fcc7 100644 --- a/19_kernel_heap/kernel/src/lib.rs +++ b/19_kernel_heap/kernel/src/lib.rs @@ -186,11 +186,9 @@ pub fn test_runner(tests: &[&test_types::UnitTest]) { #[cfg(test)] #[no_mangle] unsafe fn kernel_init() -> ! { - use driver::interface::DriverManager; - exception::handling_init(); memory::init(); - bsp::driver::driver_manager().qemu_bring_up_console(); + bsp::driver::qemu_bring_up_console(); test_main(); diff --git a/19_kernel_heap/kernel/src/main.rs b/19_kernel_heap/kernel/src/main.rs index d2044c29..9a5fd58a 100644 --- a/19_kernel_heap/kernel/src/main.rs +++ b/19_kernel_heap/kernel/src/main.rs @@ -15,7 +15,7 @@ extern crate alloc; -use libkernel::{bsp, cpu, driver, exception, info, memory, state, time, warn}; +use libkernel::{bsp, cpu, driver, exception, info, memory, state, time}; /// Early init code. /// @@ -27,27 +27,16 @@ use libkernel::{bsp, cpu, driver, exception, info, memory, state, time, warn}; /// - Printing will not work until the respective driver's MMIO is remapped. #[no_mangle] unsafe fn kernel_init() -> ! { - use driver::interface::DriverManager; - exception::handling_init(); memory::init(); - // Instantiate and init all device drivers. - if let Err(x) = bsp::driver::driver_manager().instantiate_drivers() { - panic!("Error instantiating drivers: {}", x); - } - for i in bsp::driver::driver_manager().all_device_drivers().iter() { - if let Err(x) = i.init() { - panic!("Error loading driver: {}: {}", i.compatible(), x); - } + // Initialize the BSP driver subsystem. + if let Err(x) = bsp::driver::init() { + panic!("Error initializing BSP driver subsystem: {}", x); } - // Let device drivers register and enable their handlers with the interrupt controller. - for i in bsp::driver::driver_manager().all_device_drivers() { - if let Err(msg) = i.register_and_enable_irq_handler() { - warn!("Error registering IRQ handler: {}", msg); - } - } + // Initialize all device drivers. + driver::driver_manager().init_drivers_and_irqs(); bsp::memory::mmu::kernel_add_mapping_records_for_precomputed(); @@ -63,8 +52,6 @@ unsafe fn kernel_init() -> ! { /// The main function running after the early init. fn kernel_main() -> ! { - use driver::interface::DriverManager; - info!("{}", libkernel::version()); info!("Booting on: {}", bsp::board_name()); @@ -83,13 +70,7 @@ fn kernel_main() -> ! { ); info!("Drivers loaded:"); - for (i, driver) in bsp::driver::driver_manager() - .all_device_drivers() - .iter() - .enumerate() - { - info!(" {}. {}", i + 1, driver.compatible()); - } + driver::driver_manager().enumerate(); info!("Registered IRQ handlers:"); exception::asynchronous::irq_manager().print_handler(); diff --git a/19_kernel_heap/kernel/src/memory/heap_alloc.rs b/19_kernel_heap/kernel/src/memory/heap_alloc.rs index c290be4d..c0f56d8d 100644 --- a/19_kernel_heap/kernel/src/memory/heap_alloc.rs +++ b/19_kernel_heap/kernel/src/memory/heap_alloc.rs @@ -9,8 +9,10 @@ use crate::{ memory::{Address, Virtual}, synchronization, synchronization::IRQSafeNullLock, + warn, }; use alloc::alloc::{GlobalAlloc, Layout}; +use core::sync::atomic::{AtomicBool, Ordering}; use linked_list_allocator::Heap as LinkedListHeap; //-------------------------------------------------------------------------------------------------- @@ -129,9 +131,17 @@ unsafe impl GlobalAlloc for HeapAllocator { /// Query the BSP for the heap region and initialize the kernel's heap allocator with it. pub fn kernel_init_heap_allocator() { + static INIT_DONE: AtomicBool = AtomicBool::new(false); + if INIT_DONE.load(Ordering::Relaxed) { + warn!("Already initialized"); + return; + } + let region = bsp::memory::mmu::virt_heap_region(); KERNEL_HEAP_ALLOCATOR.inner.lock(|inner| unsafe { inner.init(region.start_addr().as_usize() as *mut u8, region.size()) }); + + INIT_DONE.store(true, Ordering::Relaxed); } diff --git a/19_kernel_heap/kernel/tests/00_console_sanity.rs b/19_kernel_heap/kernel/tests/00_console_sanity.rs index 305510ce..2c0225b7 100644 --- a/19_kernel_heap/kernel/tests/00_console_sanity.rs +++ b/19_kernel_heap/kernel/tests/00_console_sanity.rs @@ -11,16 +11,15 @@ /// Console tests should time out on the I/O harness in case of panic. mod panic_wait_forever; -use libkernel::{bsp, console, cpu, driver, exception, memory, print}; +use libkernel::{bsp, console, cpu, exception, memory, print}; #[no_mangle] unsafe fn kernel_init() -> ! { use console::console; - use driver::interface::DriverManager; exception::handling_init(); memory::init(); - bsp::driver::driver_manager().qemu_bring_up_console(); + bsp::driver::qemu_bring_up_console(); // Handshake assert_eq!(console().read_char(), 'A'); diff --git a/19_kernel_heap/kernel/tests/01_timer_sanity.rs b/19_kernel_heap/kernel/tests/01_timer_sanity.rs index 39899332..8188b942 100644 --- a/19_kernel_heap/kernel/tests/01_timer_sanity.rs +++ b/19_kernel_heap/kernel/tests/01_timer_sanity.rs @@ -11,16 +11,14 @@ #![test_runner(libkernel::test_runner)] use core::time::Duration; -use libkernel::{bsp, cpu, driver, exception, memory, time}; +use libkernel::{bsp, cpu, exception, memory, time}; use test_macros::kernel_test; #[no_mangle] unsafe fn kernel_init() -> ! { - use driver::interface::DriverManager; - exception::handling_init(); memory::init(); - bsp::driver::driver_manager().qemu_bring_up_console(); + bsp::driver::qemu_bring_up_console(); // Depending on CPU arch, some timer bring-up code could go here. Not needed for the RPi. diff --git a/19_kernel_heap/kernel/tests/02_exception_sync_page_fault.rs b/19_kernel_heap/kernel/tests/02_exception_sync_page_fault.rs index a6d15b69..fab44c8f 100644 --- a/19_kernel_heap/kernel/tests/02_exception_sync_page_fault.rs +++ b/19_kernel_heap/kernel/tests/02_exception_sync_page_fault.rs @@ -17,15 +17,13 @@ /// or indirectly. mod panic_exit_success; -use libkernel::{bsp, cpu, driver, exception, info, memory, println}; +use libkernel::{bsp, cpu, exception, info, memory, println}; #[no_mangle] unsafe fn kernel_init() -> ! { - use driver::interface::DriverManager; - exception::handling_init(); memory::init(); - bsp::driver::driver_manager().qemu_bring_up_console(); + bsp::driver::qemu_bring_up_console(); // This line will be printed as the test header. println!("Testing synchronous exception handling by causing a page fault"); diff --git a/19_kernel_heap/kernel/tests/03_exception_restore_sanity.rs b/19_kernel_heap/kernel/tests/03_exception_restore_sanity.rs index 47dd2714..f176c6a6 100644 --- a/19_kernel_heap/kernel/tests/03_exception_restore_sanity.rs +++ b/19_kernel_heap/kernel/tests/03_exception_restore_sanity.rs @@ -12,7 +12,7 @@ mod panic_wait_forever; use core::arch::asm; -use libkernel::{bsp, cpu, driver, exception, info, memory, println}; +use libkernel::{bsp, cpu, exception, info, memory, println}; #[inline(never)] fn nested_system_call() { @@ -30,11 +30,9 @@ fn nested_system_call() { #[no_mangle] unsafe fn kernel_init() -> ! { - use driver::interface::DriverManager; - exception::handling_init(); memory::init(); - bsp::driver::driver_manager().qemu_bring_up_console(); + bsp::driver::qemu_bring_up_console(); // This line will be printed as the test header. println!("Testing exception restore"); diff --git a/19_kernel_heap/kernel/tests/04_exception_irq_sanity.rs b/19_kernel_heap/kernel/tests/04_exception_irq_sanity.rs index e93a4caf..e6f94c91 100644 --- a/19_kernel_heap/kernel/tests/04_exception_irq_sanity.rs +++ b/19_kernel_heap/kernel/tests/04_exception_irq_sanity.rs @@ -10,15 +10,13 @@ #![reexport_test_harness_main = "test_main"] #![test_runner(libkernel::test_runner)] -use libkernel::{bsp, cpu, driver, exception, memory}; +use libkernel::{bsp, cpu, exception, memory}; use test_macros::kernel_test; #[no_mangle] unsafe fn kernel_init() -> ! { - use driver::interface::DriverManager; - memory::init(); - bsp::driver::driver_manager().qemu_bring_up_console(); + bsp::driver::qemu_bring_up_console(); exception::handling_init(); exception::asynchronous::local_irq_unmask(); diff --git a/19_kernel_heap/kernel/tests/05_backtrace_sanity.rs b/19_kernel_heap/kernel/tests/05_backtrace_sanity.rs index ea425f68..f75c0ea3 100644 --- a/19_kernel_heap/kernel/tests/05_backtrace_sanity.rs +++ b/19_kernel_heap/kernel/tests/05_backtrace_sanity.rs @@ -11,7 +11,7 @@ /// Console tests should time out on the I/O harness in case of panic. mod panic_wait_forever; -use libkernel::{bsp, cpu, driver, exception, memory}; +use libkernel::{bsp, cpu, exception, memory}; #[inline(never)] fn nested() { @@ -20,11 +20,9 @@ fn nested() { #[no_mangle] unsafe fn kernel_init() -> ! { - use driver::interface::DriverManager; - exception::handling_init(); memory::init(); - bsp::driver::driver_manager().qemu_bring_up_console(); + bsp::driver::qemu_bring_up_console(); nested(); diff --git a/19_kernel_heap/kernel/tests/06_backtrace_invalid_frame.rs b/19_kernel_heap/kernel/tests/06_backtrace_invalid_frame.rs index 8769c7b6..33d3c02d 100644 --- a/19_kernel_heap/kernel/tests/06_backtrace_invalid_frame.rs +++ b/19_kernel_heap/kernel/tests/06_backtrace_invalid_frame.rs @@ -11,7 +11,7 @@ /// Console tests should time out on the I/O harness in case of panic. mod panic_wait_forever; -use libkernel::{backtrace, bsp, cpu, driver, exception, memory}; +use libkernel::{backtrace, bsp, cpu, exception, memory}; #[inline(never)] fn nested() { @@ -22,11 +22,9 @@ fn nested() { #[no_mangle] unsafe fn kernel_init() -> ! { - use driver::interface::DriverManager; - exception::handling_init(); memory::init(); - bsp::driver::driver_manager().qemu_bring_up_console(); + bsp::driver::qemu_bring_up_console(); nested(); diff --git a/19_kernel_heap/kernel/tests/07_backtrace_invalid_link.rs b/19_kernel_heap/kernel/tests/07_backtrace_invalid_link.rs index 28f3cdda..bcb0538a 100644 --- a/19_kernel_heap/kernel/tests/07_backtrace_invalid_link.rs +++ b/19_kernel_heap/kernel/tests/07_backtrace_invalid_link.rs @@ -11,7 +11,7 @@ /// Console tests should time out on the I/O harness in case of panic. mod panic_wait_forever; -use libkernel::{backtrace, bsp, cpu, driver, exception, memory}; +use libkernel::{backtrace, bsp, cpu, exception, memory}; #[inline(never)] fn nested_2() -> &'static str { @@ -27,11 +27,9 @@ fn nested_1() { #[no_mangle] unsafe fn kernel_init() -> ! { - use driver::interface::DriverManager; - exception::handling_init(); memory::init(); - bsp::driver::driver_manager().qemu_bring_up_console(); + bsp::driver::qemu_bring_up_console(); nested_1(); diff --git a/X1_JTAG_boot/src/bsp/raspberrypi.rs b/X1_JTAG_boot/src/bsp/raspberrypi.rs index eb6be81a..7bda8a4d 100644 --- a/X1_JTAG_boot/src/bsp/raspberrypi.rs +++ b/X1_JTAG_boot/src/bsp/raspberrypi.rs @@ -4,7 +4,6 @@ //! Top-level BSP file for the Raspberry Pi 3 and 4. -pub mod console; pub mod cpu; pub mod driver; pub mod memory; diff --git a/X1_JTAG_boot/src/bsp/raspberrypi/console.rs b/X1_JTAG_boot/src/bsp/raspberrypi/console.rs deleted file mode 100644 index 0a630eef..00000000 --- a/X1_JTAG_boot/src/bsp/raspberrypi/console.rs +++ /dev/null @@ -1,16 +0,0 @@ -// SPDX-License-Identifier: MIT OR Apache-2.0 -// -// Copyright (c) 2018-2022 Andre Richter - -//! BSP console facilities. - -use crate::console; - -//-------------------------------------------------------------------------------------------------- -// Public Code -//-------------------------------------------------------------------------------------------------- - -/// Return a reference to the console. -pub fn console() -> &'static dyn console::interface::All { - &super::driver::PL011_UART -} diff --git a/X1_JTAG_boot/src/bsp/raspberrypi/driver.rs b/X1_JTAG_boot/src/bsp/raspberrypi/driver.rs index 8b683ed8..ea843066 100644 --- a/X1_JTAG_boot/src/bsp/raspberrypi/driver.rs +++ b/X1_JTAG_boot/src/bsp/raspberrypi/driver.rs @@ -5,51 +5,67 @@ //! BSP driver support. use super::memory::map::mmio; -use crate::{bsp::device_driver, driver}; +use crate::{bsp::device_driver, console, driver as generic_driver}; +use core::sync::atomic::{AtomicBool, Ordering}; //-------------------------------------------------------------------------------------------------- -// Private Definitions +// Global instances //-------------------------------------------------------------------------------------------------- -/// Device Driver Manager type. -struct BSPDriverManager { - device_drivers: [&'static (dyn DeviceDriver + Sync); 2], -} +static PL011_UART: device_driver::PL011Uart = + unsafe { device_driver::PL011Uart::new(mmio::PL011_UART_START) }; +static GPIO: device_driver::GPIO = unsafe { device_driver::GPIO::new(mmio::GPIO_START) }; //-------------------------------------------------------------------------------------------------- -// Global instances +// Private Code //-------------------------------------------------------------------------------------------------- -pub(super) static PL011_UART: device_driver::PL011Uart = - unsafe { device_driver::PL011Uart::new(mmio::PL011_UART_START) }; +/// This must be called only after successful init of the UART driver. +fn post_init_uart() -> Result<(), &'static str> { + console::register_console(&PL011_UART); -static GPIO: device_driver::GPIO = unsafe { device_driver::GPIO::new(mmio::GPIO_START) }; + Ok(()) +} -static BSP_DRIVER_MANAGER: BSPDriverManager = BSPDriverManager { - device_drivers: [&PL011_UART, &GPIO], -}; +/// This must be called only after successful init of the GPIO driver. +fn post_init_gpio() -> Result<(), &'static str> { + GPIO.map_pl011_uart(); + Ok(()) +} -//-------------------------------------------------------------------------------------------------- -// Public Code -//-------------------------------------------------------------------------------------------------- +fn driver_uart() -> Result<(), &'static str> { + let uart_descriptor = + generic_driver::DeviceDriverDescriptor::new(&PL011_UART, Some(post_init_uart)); + generic_driver::driver_manager().register_driver(uart_descriptor); -/// Return a reference to the driver manager. -pub fn driver_manager() -> &'static impl driver::interface::DriverManager { - &BSP_DRIVER_MANAGER + Ok(()) } -//------------------------------------------------------------------------------ -// OS Interface Code -//------------------------------------------------------------------------------ -use driver::interface::DeviceDriver; +fn driver_gpio() -> Result<(), &'static str> { + let gpio_descriptor = generic_driver::DeviceDriverDescriptor::new(&GPIO, Some(post_init_gpio)); + generic_driver::driver_manager().register_driver(gpio_descriptor); -impl driver::interface::DriverManager for BSPDriverManager { - fn all_device_drivers(&self) -> &[&'static (dyn DeviceDriver + Sync)] { - &self.device_drivers[..] - } + Ok(()) +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- - fn post_device_driver_init(&self) { - // Configure PL011Uart's output pins. - GPIO.map_pl011_uart(); +/// Initialize the driver subsystem. +/// +/// # Safety +/// +/// See child function calls. +pub unsafe fn init() -> Result<(), &'static str> { + static INIT_DONE: AtomicBool = AtomicBool::new(false); + if INIT_DONE.load(Ordering::Relaxed) { + return Err("Init already done"); } + + driver_uart()?; + driver_gpio()?; + + INIT_DONE.store(true, Ordering::Relaxed); + Ok(()) } diff --git a/X1_JTAG_boot/src/console.rs b/X1_JTAG_boot/src/console.rs index c1fb0e53..02b43df9 100644 --- a/X1_JTAG_boot/src/console.rs +++ b/X1_JTAG_boot/src/console.rs @@ -4,7 +4,9 @@ //! System console. -use crate::bsp; +mod null_console; + +use crate::synchronization::{self, NullLock}; //-------------------------------------------------------------------------------------------------- // Public Definitions @@ -54,13 +56,26 @@ pub mod interface { pub trait All: Write + Read + Statistics {} } +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +static CUR_CONSOLE: NullLock<&'static (dyn interface::All + Sync)> = + NullLock::new(&null_console::NULL_CONSOLE); + //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- +use synchronization::interface::Mutex; + +/// Register a new console. +pub fn register_console(new_console: &'static (dyn interface::All + Sync)) { + CUR_CONSOLE.lock(|con| *con = new_console); +} -/// Return a reference to the console. +/// Return a reference to the currently registered console. /// /// This is the global console used by all printing macros. pub fn console() -> &'static dyn interface::All { - bsp::console::console() + CUR_CONSOLE.lock(|con| *con) } diff --git a/X1_JTAG_boot/src/console/null_console.rs b/X1_JTAG_boot/src/console/null_console.rs new file mode 100644 index 00000000..2c64d499 --- /dev/null +++ b/X1_JTAG_boot/src/console/null_console.rs @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2022 Andre Richter + +//! Null console. + +use super::interface; +use core::fmt; + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +pub struct NullConsole; + +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +pub static NULL_CONSOLE: NullConsole = NullConsole {}; + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +impl interface::Write for NullConsole { + fn write_char(&self, _c: char) {} + + fn write_fmt(&self, _args: fmt::Arguments) -> fmt::Result { + fmt::Result::Ok(()) + } + + fn flush(&self) {} +} + +impl interface::Read for NullConsole { + fn clear_rx(&self) {} +} + +impl interface::Statistics for NullConsole {} +impl interface::All for NullConsole {} diff --git a/X1_JTAG_boot/src/driver.rs b/X1_JTAG_boot/src/driver.rs index 2fcc7562..fb44bbd9 100644 --- a/X1_JTAG_boot/src/driver.rs +++ b/X1_JTAG_boot/src/driver.rs @@ -4,6 +4,19 @@ //! Driver support. +use crate::synchronization::{interface::Mutex, NullLock}; + +//-------------------------------------------------------------------------------------------------- +// Private Definitions +//-------------------------------------------------------------------------------------------------- + +const NUM_DRIVERS: usize = 5; + +struct DriverManagerInner { + next_index: usize, + descriptors: [Option; NUM_DRIVERS], +} + //-------------------------------------------------------------------------------------------------- // Public Definitions //-------------------------------------------------------------------------------------------------- @@ -24,21 +37,118 @@ pub mod interface { Ok(()) } } +} + +/// Tpye to be used as an optional callback after a driver's init() has run. +pub type DeviceDriverPostInitCallback = unsafe fn() -> Result<(), &'static str>; - /// Device driver management functions. +/// A descriptor for device drivers. +#[derive(Copy, Clone)] +pub struct DeviceDriverDescriptor { + device_driver: &'static (dyn interface::DeviceDriver + Sync), + post_init_callback: Option, +} + +/// Provides device driver management functions. +pub struct DriverManager { + inner: NullLock, +} + +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +static DRIVER_MANAGER: DriverManager = DriverManager::new(); + +//-------------------------------------------------------------------------------------------------- +// Private Code +//-------------------------------------------------------------------------------------------------- + +impl DriverManagerInner { + /// Create an instance. + pub const fn new() -> Self { + Self { + next_index: 0, + descriptors: [None; NUM_DRIVERS], + } + } +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +impl DeviceDriverDescriptor { + /// Create an instance. + pub fn new( + device_driver: &'static (dyn interface::DeviceDriver + Sync), + post_init_callback: Option, + ) -> Self { + Self { + device_driver, + post_init_callback, + } + } +} + +/// Return a reference to the global DriverManager. +pub fn driver_manager() -> &'static DriverManager { + &DRIVER_MANAGER +} + +impl DriverManager { + /// Create an instance. + pub const fn new() -> Self { + Self { + inner: NullLock::new(DriverManagerInner::new()), + } + } + + /// Register a device driver with the kernel. + pub fn register_driver(&self, descriptor: DeviceDriverDescriptor) { + self.inner.lock(|inner| { + inner.descriptors[inner.next_index] = Some(descriptor); + inner.next_index += 1; + }) + } + + /// Helper for iterating over registered drivers. + fn for_each_descriptor<'a>(&'a self, f: impl FnMut(&'a DeviceDriverDescriptor)) { + self.inner.lock(|inner| { + inner + .descriptors + .iter() + .filter_map(|x| x.as_ref()) + .for_each(f) + }) + } + + /// Fully initialize all drivers. /// - /// The `BSP` is supposed to supply one global instance. - pub trait DriverManager { - /// Return a slice of references to all `BSP`-instantiated drivers. - /// - /// # Safety - /// - /// - The order of devices is the order in which `DeviceDriver::init()` is called. - fn all_device_drivers(&self) -> &[&'static (dyn DeviceDriver + Sync)]; + /// # Safety + /// + /// - During init, drivers might do stuff with system-wide impact. + pub unsafe fn init_drivers(&self) { + self.for_each_descriptor(|descriptor| { + // 1. Initialize driver. + if let Err(x) = descriptor.device_driver.init() { + panic!( + "Error initializing driver: {}: {}", + descriptor.device_driver.compatible(), + x + ); + } - /// Initialization code that runs after driver init. - /// - /// For example, device driver code that depends on other drivers already being online. - fn post_device_driver_init(&self); + // 2. Call corresponding post init callback. + if let Some(callback) = &descriptor.post_init_callback { + if let Err(x) = callback() { + panic!( + "Error during driver post-init callback: {}: {}", + descriptor.device_driver.compatible(), + x + ); + } + } + }); } } diff --git a/X1_JTAG_boot/src/main.rs b/X1_JTAG_boot/src/main.rs index a38b1ef5..8d244c77 100644 --- a/X1_JTAG_boot/src/main.rs +++ b/X1_JTAG_boot/src/main.rs @@ -133,14 +133,13 @@ mod time; /// - Only a single core must be active and running this function. /// - The init calls in this function must appear in the correct order. unsafe fn kernel_init() -> ! { - use driver::interface::DriverManager; - - for i in bsp::driver::driver_manager().all_device_drivers().iter() { - if let Err(x) = i.init() { - panic!("Error loading driver: {}: {}", i.compatible(), x); - } + // Initialize the BSP driver subsystem. + if let Err(x) = bsp::driver::init() { + panic!("Error initializing BSP driver subsystem: {}", x); } - bsp::driver::driver_manager().post_device_driver_init(); + + // Initialize all device drivers. + driver::driver_manager().init_drivers(); // println! is usable from here on. // Transition from unsafe to safe. diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 0a525545..a554c0a9 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,4 +1,4 @@ [toolchain] -channel = "nightly-2022-08-01" +channel = "nightly-2022-10-13" components = ["rust-src", "llvm-tools-preview", "rustfmt"] targets = ["aarch64-unknown-none-softfloat"] From ec842133d9f61e2be2f9a7c2ef8a1e8fba6931f5 Mon Sep 17 00:00:00 2001 From: Andre Richter Date: Mon, 24 Oct 2022 22:15:48 +0200 Subject: [PATCH 58/75] Improve macOS support macOS support is still not great, but this patch at least fixes some import Makefile subtargets. --- .ruby-version | 2 +- 01_wait_forever/Makefile | 5 +-- 02_runtime_init/Makefile | 5 +-- 02_runtime_init/README.md | 2 +- 03_hacky_hello_world/Makefile | 5 +-- 03_hacky_hello_world/README.md | 8 ++--- 04_safe_globals/Makefile | 5 +-- 05_drivers_gpio_uart/Makefile | 5 +-- 05_drivers_gpio_uart/README.md | 8 ++--- 06_uart_chainloader/Makefile | 5 +-- 06_uart_chainloader/README.md | 14 ++++----- 07_timestamps/Makefile | 5 +-- 07_timestamps/README.md | 10 +++--- 08_hw_debug_JTAG/Makefile | 5 +-- 08_hw_debug_JTAG/README.md | 8 ++--- 09_privilege_level/Makefile | 5 +-- .../Makefile | 5 +-- 11_exceptions_part1_groundwork/Makefile | 5 +-- 12_integrated_testing/Makefile | 5 +-- 13_exceptions_part2_peripheral_IRQs/Makefile | 5 +-- 14_virtual_mem_part2_mmio_remap/Makefile | 5 +-- .../Makefile | 5 +-- .../README.md | 8 ++--- .../Makefile | 5 +-- 17_kernel_symbols/Makefile | 8 ++--- 17_kernel_symbols/README.md | 31 +++++++++++++------ 17_kernel_symbols/kernel_symbols.mk | 18 +++++++++-- 18_backtrace/Makefile | 8 ++--- 18_backtrace/README.md | 6 ++-- 18_backtrace/kernel_symbols.mk | 18 +++++++++-- 19_kernel_heap/Makefile | 8 ++--- 19_kernel_heap/README.md | 6 ++-- 19_kernel_heap/kernel_symbols.mk | 18 +++++++++-- README.md | 8 ++++- X1_JTAG_boot/Makefile | 5 +-- common/operating_system.mk | 9 ++++++ 36 files changed, 185 insertions(+), 98 deletions(-) create mode 100644 common/operating_system.mk diff --git a/.ruby-version b/.ruby-version index 1effb003..b5021469 100644 --- a/.ruby-version +++ b/.ruby-version @@ -1 +1 @@ -2.7 +3.0.2 diff --git a/01_wait_forever/Makefile b/01_wait_forever/Makefile index 679b23b4..c87546fd 100644 --- a/01_wait_forever/Makefile +++ b/01_wait_forever/Makefile @@ -2,8 +2,9 @@ ## ## Copyright (c) 2018-2022 Andre Richter -include ../common/format.mk include ../common/docker.mk +include ../common/format.mk +include ../common/operating_system.mk ##-------------------------------------------------------------------------------------------------- ## Optional, user-provided configuration values @@ -130,7 +131,7 @@ $(KERNEL_BIN): $(KERNEL_ELF) $(call color_progress_prefix, "Name") @echo $(KERNEL_BIN) $(call color_progress_prefix, "Size") - @printf '%s KiB\n' `du -k $(KERNEL_BIN) | cut -f1` + $(call disk_usage_KiB, $(KERNEL_BIN)) ##------------------------------------------------------------------------------ ## Generate the documentation diff --git a/02_runtime_init/Makefile b/02_runtime_init/Makefile index 0abb67cc..807a935e 100644 --- a/02_runtime_init/Makefile +++ b/02_runtime_init/Makefile @@ -2,8 +2,9 @@ ## ## Copyright (c) 2018-2022 Andre Richter -include ../common/format.mk include ../common/docker.mk +include ../common/format.mk +include ../common/operating_system.mk ##-------------------------------------------------------------------------------------------------- ## Optional, user-provided configuration values @@ -130,7 +131,7 @@ $(KERNEL_BIN): $(KERNEL_ELF) $(call color_progress_prefix, "Name") @echo $(KERNEL_BIN) $(call color_progress_prefix, "Size") - @printf '%s KiB\n' `du -k $(KERNEL_BIN) | cut -f1` + $(call disk_usage_KiB, $(KERNEL_BIN)) ##------------------------------------------------------------------------------ ## Generate the documentation diff --git a/02_runtime_init/README.md b/02_runtime_init/README.md index 80fd77a4..7b3fcd82 100644 --- a/02_runtime_init/README.md +++ b/02_runtime_init/README.md @@ -52,7 +52,7 @@ diff -uNr 01_wait_forever/Cargo.toml 02_runtime_init/Cargo.toml diff -uNr 01_wait_forever/Makefile 02_runtime_init/Makefile --- 01_wait_forever/Makefile +++ 02_runtime_init/Makefile -@@ -180,6 +180,7 @@ +@@ -181,6 +181,7 @@ $(call color_header, "Launching objdump") @$(DOCKER_TOOLS) $(OBJDUMP_BINARY) --disassemble --demangle \ --section .text \ diff --git a/03_hacky_hello_world/Makefile b/03_hacky_hello_world/Makefile index cfd5dc6e..13dba46c 100644 --- a/03_hacky_hello_world/Makefile +++ b/03_hacky_hello_world/Makefile @@ -2,8 +2,9 @@ ## ## Copyright (c) 2018-2022 Andre Richter -include ../common/format.mk include ../common/docker.mk +include ../common/format.mk +include ../common/operating_system.mk ##-------------------------------------------------------------------------------------------------- ## Optional, user-provided configuration values @@ -133,7 +134,7 @@ $(KERNEL_BIN): $(KERNEL_ELF) $(call color_progress_prefix, "Name") @echo $(KERNEL_BIN) $(call color_progress_prefix, "Size") - @printf '%s KiB\n' `du -k $(KERNEL_BIN) | cut -f1` + $(call disk_usage_KiB, $(KERNEL_BIN)) ##------------------------------------------------------------------------------ ## Generate the documentation diff --git a/03_hacky_hello_world/README.md b/03_hacky_hello_world/README.md index 416cab02..b0ad3ff2 100644 --- a/03_hacky_hello_world/README.md +++ b/03_hacky_hello_world/README.md @@ -53,7 +53,7 @@ diff -uNr 02_runtime_init/Cargo.toml 03_hacky_hello_world/Cargo.toml diff -uNr 02_runtime_init/Makefile 03_hacky_hello_world/Makefile --- 02_runtime_init/Makefile +++ 03_hacky_hello_world/Makefile -@@ -24,7 +24,7 @@ +@@ -25,7 +25,7 @@ KERNEL_BIN = kernel8.img QEMU_BINARY = qemu-system-aarch64 QEMU_MACHINE_TYPE = raspi3 @@ -62,7 +62,7 @@ diff -uNr 02_runtime_init/Makefile 03_hacky_hello_world/Makefile OBJDUMP_BINARY = aarch64-none-elf-objdump NM_BINARY = aarch64-none-elf-nm READELF_BINARY = aarch64-none-elf-readelf -@@ -35,7 +35,7 @@ +@@ -36,7 +36,7 @@ KERNEL_BIN = kernel8.img QEMU_BINARY = qemu-system-aarch64 QEMU_MACHINE_TYPE = @@ -71,7 +71,7 @@ diff -uNr 02_runtime_init/Makefile 03_hacky_hello_world/Makefile OBJDUMP_BINARY = aarch64-none-elf-objdump NM_BINARY = aarch64-none-elf-nm READELF_BINARY = aarch64-none-elf-readelf -@@ -85,17 +85,20 @@ +@@ -86,17 +86,20 @@ --strip-all \ -O binary @@ -95,7 +95,7 @@ diff -uNr 02_runtime_init/Makefile 03_hacky_hello_world/Makefile -@@ -190,3 +193,27 @@ +@@ -191,3 +194,27 @@ $(call color_header, "Launching nm") @$(DOCKER_TOOLS) $(NM_BINARY) --demangle --print-size $(KERNEL_ELF) | sort | rustfilt diff --git a/04_safe_globals/Makefile b/04_safe_globals/Makefile index cfd5dc6e..13dba46c 100644 --- a/04_safe_globals/Makefile +++ b/04_safe_globals/Makefile @@ -2,8 +2,9 @@ ## ## Copyright (c) 2018-2022 Andre Richter -include ../common/format.mk include ../common/docker.mk +include ../common/format.mk +include ../common/operating_system.mk ##-------------------------------------------------------------------------------------------------- ## Optional, user-provided configuration values @@ -133,7 +134,7 @@ $(KERNEL_BIN): $(KERNEL_ELF) $(call color_progress_prefix, "Name") @echo $(KERNEL_BIN) $(call color_progress_prefix, "Size") - @printf '%s KiB\n' `du -k $(KERNEL_BIN) | cut -f1` + $(call disk_usage_KiB, $(KERNEL_BIN)) ##------------------------------------------------------------------------------ ## Generate the documentation diff --git a/05_drivers_gpio_uart/Makefile b/05_drivers_gpio_uart/Makefile index 29d6729f..a8c4821a 100644 --- a/05_drivers_gpio_uart/Makefile +++ b/05_drivers_gpio_uart/Makefile @@ -2,8 +2,9 @@ ## ## Copyright (c) 2018-2022 Andre Richter -include ../common/format.mk include ../common/docker.mk +include ../common/format.mk +include ../common/operating_system.mk ##-------------------------------------------------------------------------------------------------- ## Optional, user-provided configuration values @@ -145,7 +146,7 @@ $(KERNEL_BIN): $(KERNEL_ELF) $(call color_progress_prefix, "Name") @echo $(KERNEL_BIN) $(call color_progress_prefix, "Size") - @printf '%s KiB\n' `du -k $(KERNEL_BIN) | cut -f1` + $(call disk_usage_KiB, $(KERNEL_BIN)) ##------------------------------------------------------------------------------ ## Generate the documentation diff --git a/05_drivers_gpio_uart/README.md b/05_drivers_gpio_uart/README.md index 3fe5e7b2..f53a330b 100644 --- a/05_drivers_gpio_uart/README.md +++ b/05_drivers_gpio_uart/README.md @@ -186,7 +186,7 @@ diff -uNr 04_safe_globals/Cargo.toml 05_drivers_gpio_uart/Cargo.toml diff -uNr 04_safe_globals/Makefile 05_drivers_gpio_uart/Makefile --- 04_safe_globals/Makefile +++ 05_drivers_gpio_uart/Makefile -@@ -12,6 +12,9 @@ +@@ -13,6 +13,9 @@ # Default to the RPi3. BSP ?= rpi3 @@ -196,7 +196,7 @@ diff -uNr 04_safe_globals/Makefile 05_drivers_gpio_uart/Makefile ##-------------------------------------------------------------------------------------------------- -@@ -87,6 +90,7 @@ +@@ -88,6 +91,7 @@ EXEC_QEMU = $(QEMU_BINARY) -M $(QEMU_MACHINE_TYPE) EXEC_TEST_DISPATCH = ruby ../common/tests/dispatch.rb @@ -204,7 +204,7 @@ diff -uNr 04_safe_globals/Makefile 05_drivers_gpio_uart/Makefile ##------------------------------------------------------------------------------ ## Dockerization -@@ -94,18 +98,26 @@ +@@ -95,18 +99,26 @@ DOCKER_CMD = docker run -t --rm -v $(shell pwd):/work/tutorial -w /work/tutorial DOCKER_CMD_INTERACT = $(DOCKER_CMD) -i DOCKER_ARG_DIR_COMMON = -v $(shell pwd)/../common:/work/common @@ -232,7 +232,7 @@ diff -uNr 04_safe_globals/Makefile 05_drivers_gpio_uart/Makefile all: $(KERNEL_BIN) -@@ -155,9 +167,16 @@ +@@ -156,9 +168,16 @@ qemu: $(KERNEL_BIN) $(call color_header, "Launching QEMU") @$(DOCKER_QEMU) $(EXEC_QEMU) $(QEMU_RELEASE_ARGS) -kernel $(KERNEL_BIN) diff --git a/06_uart_chainloader/Makefile b/06_uart_chainloader/Makefile index d7b102ae..b619b4ca 100644 --- a/06_uart_chainloader/Makefile +++ b/06_uart_chainloader/Makefile @@ -2,8 +2,9 @@ ## ## Copyright (c) 2018-2022 Andre Richter -include ../common/format.mk include ../common/docker.mk +include ../common/format.mk +include ../common/operating_system.mk ##-------------------------------------------------------------------------------------------------- ## Optional, user-provided configuration values @@ -147,7 +148,7 @@ $(KERNEL_BIN): $(KERNEL_ELF) $(call color_progress_prefix, "Name") @echo $(KERNEL_BIN) $(call color_progress_prefix, "Size") - @printf '%s KiB\n' `du -k $(KERNEL_BIN) | cut -f1` + $(call disk_usage_KiB, $(KERNEL_BIN)) ##------------------------------------------------------------------------------ ## Generate the documentation diff --git a/06_uart_chainloader/README.md b/06_uart_chainloader/README.md index e321e603..95b95149 100644 --- a/06_uart_chainloader/README.md +++ b/06_uart_chainloader/README.md @@ -140,7 +140,7 @@ Binary files 05_drivers_gpio_uart/demo_payload_rpi4.img and 06_uart_chainloader/ diff -uNr 05_drivers_gpio_uart/Makefile 06_uart_chainloader/Makefile --- 05_drivers_gpio_uart/Makefile +++ 06_uart_chainloader/Makefile -@@ -23,27 +23,29 @@ +@@ -24,27 +24,29 @@ QEMU_MISSING_STRING = "This board is not yet supported for QEMU." ifeq ($(BSP),rpi3) @@ -190,7 +190,7 @@ diff -uNr 05_drivers_gpio_uart/Makefile 06_uart_chainloader/Makefile endif # Export for build.rs. -@@ -89,8 +91,8 @@ +@@ -90,8 +92,8 @@ -O binary EXEC_QEMU = $(QEMU_BINARY) -M $(QEMU_MACHINE_TYPE) @@ -201,7 +201,7 @@ diff -uNr 05_drivers_gpio_uart/Makefile 06_uart_chainloader/Makefile ##------------------------------------------------------------------------------ ## Dockerization -@@ -109,7 +111,7 @@ +@@ -110,7 +112,7 @@ ifeq ($(shell uname -s),Linux) DOCKER_CMD_DEV = $(DOCKER_CMD_INTERACT) $(DOCKER_ARG_DEV) @@ -210,7 +210,7 @@ diff -uNr 05_drivers_gpio_uart/Makefile 06_uart_chainloader/Makefile endif -@@ -117,7 +119,7 @@ +@@ -118,7 +120,7 @@ ##-------------------------------------------------------------------------------------------------- ## Targets ##-------------------------------------------------------------------------------------------------- @@ -219,7 +219,7 @@ diff -uNr 05_drivers_gpio_uart/Makefile 06_uart_chainloader/Makefile all: $(KERNEL_BIN) -@@ -159,7 +161,7 @@ +@@ -160,7 +162,7 @@ ##------------------------------------------------------------------------------ ifeq ($(QEMU_MACHINE_TYPE),) # QEMU is not supported for the board. @@ -228,7 +228,7 @@ diff -uNr 05_drivers_gpio_uart/Makefile 06_uart_chainloader/Makefile $(call color_header, "$(QEMU_MISSING_STRING)") else # QEMU is supported. -@@ -168,13 +170,17 @@ +@@ -169,13 +171,17 @@ $(call color_header, "Launching QEMU") @$(DOCKER_QEMU) $(EXEC_QEMU) $(QEMU_RELEASE_ARGS) -kernel $(KERNEL_BIN) @@ -249,7 +249,7 @@ diff -uNr 05_drivers_gpio_uart/Makefile 06_uart_chainloader/Makefile ##------------------------------------------------------------------------------ ## Run clippy -@@ -231,7 +237,8 @@ +@@ -232,7 +238,8 @@ ##------------------------------------------------------------------------------ test_boot: $(KERNEL_BIN) $(call color_header, "Boot test - $(BSP)") diff --git a/07_timestamps/Makefile b/07_timestamps/Makefile index 76ddb186..23de6557 100644 --- a/07_timestamps/Makefile +++ b/07_timestamps/Makefile @@ -2,8 +2,9 @@ ## ## Copyright (c) 2018-2022 Andre Richter -include ../common/format.mk include ../common/docker.mk +include ../common/format.mk +include ../common/operating_system.mk ##-------------------------------------------------------------------------------------------------- ## Optional, user-provided configuration values @@ -145,7 +146,7 @@ $(KERNEL_BIN): $(KERNEL_ELF) $(call color_progress_prefix, "Name") @echo $(KERNEL_BIN) $(call color_progress_prefix, "Size") - @printf '%s KiB\n' `du -k $(KERNEL_BIN) | cut -f1` + $(call disk_usage_KiB, $(KERNEL_BIN)) ##------------------------------------------------------------------------------ ## Generate the documentation diff --git a/07_timestamps/README.md b/07_timestamps/README.md index 4a5905b4..236def5b 100644 --- a/07_timestamps/README.md +++ b/07_timestamps/README.md @@ -63,7 +63,7 @@ Binary files 06_uart_chainloader/demo_payload_rpi4.img and 07_timestamps/demo_pa diff -uNr 06_uart_chainloader/Makefile 07_timestamps/Makefile --- 06_uart_chainloader/Makefile +++ 07_timestamps/Makefile -@@ -23,29 +23,27 @@ +@@ -24,29 +24,27 @@ QEMU_MISSING_STRING = "This board is not yet supported for QEMU." ifeq ($(BSP),rpi3) @@ -113,7 +113,7 @@ diff -uNr 06_uart_chainloader/Makefile 07_timestamps/Makefile endif # Export for build.rs. -@@ -91,7 +89,7 @@ +@@ -92,7 +90,7 @@ -O binary EXEC_QEMU = $(QEMU_BINARY) -M $(QEMU_MACHINE_TYPE) @@ -122,7 +122,7 @@ diff -uNr 06_uart_chainloader/Makefile 07_timestamps/Makefile EXEC_MINIPUSH = ruby ../common/serial/minipush.rb ##------------------------------------------------------------------------------ -@@ -161,7 +159,7 @@ +@@ -162,7 +160,7 @@ ##------------------------------------------------------------------------------ ifeq ($(QEMU_MACHINE_TYPE),) # QEMU is not supported for the board. @@ -131,7 +131,7 @@ diff -uNr 06_uart_chainloader/Makefile 07_timestamps/Makefile $(call color_header, "$(QEMU_MISSING_STRING)") else # QEMU is supported. -@@ -170,17 +168,13 @@ +@@ -171,17 +169,13 @@ $(call color_header, "Launching QEMU") @$(DOCKER_QEMU) $(EXEC_QEMU) $(QEMU_RELEASE_ARGS) -kernel $(KERNEL_BIN) @@ -150,7 +150,7 @@ diff -uNr 06_uart_chainloader/Makefile 07_timestamps/Makefile ##------------------------------------------------------------------------------ ## Run clippy -@@ -237,8 +231,7 @@ +@@ -238,8 +232,7 @@ ##------------------------------------------------------------------------------ test_boot: $(KERNEL_BIN) $(call color_header, "Boot test - $(BSP)") diff --git a/08_hw_debug_JTAG/Makefile b/08_hw_debug_JTAG/Makefile index ce0ebc31..125f75cb 100644 --- a/08_hw_debug_JTAG/Makefile +++ b/08_hw_debug_JTAG/Makefile @@ -2,8 +2,9 @@ ## ## Copyright (c) 2018-2022 Andre Richter -include ../common/format.mk include ../common/docker.mk +include ../common/format.mk +include ../common/operating_system.mk ##-------------------------------------------------------------------------------------------------- ## Optional, user-provided configuration values @@ -156,7 +157,7 @@ $(KERNEL_BIN): $(KERNEL_ELF) $(call color_progress_prefix, "Name") @echo $(KERNEL_BIN) $(call color_progress_prefix, "Size") - @printf '%s KiB\n' `du -k $(KERNEL_BIN) | cut -f1` + $(call disk_usage_KiB, $(KERNEL_BIN)) ##------------------------------------------------------------------------------ ## Generate the documentation diff --git a/08_hw_debug_JTAG/README.md b/08_hw_debug_JTAG/README.md index 69b6b82e..14928253 100644 --- a/08_hw_debug_JTAG/README.md +++ b/08_hw_debug_JTAG/README.md @@ -320,7 +320,7 @@ diff -uNr 07_timestamps/Cargo.toml 08_hw_debug_JTAG/Cargo.toml diff -uNr 07_timestamps/Makefile 08_hw_debug_JTAG/Makefile --- 07_timestamps/Makefile +++ 08_hw_debug_JTAG/Makefile -@@ -31,6 +31,8 @@ +@@ -32,6 +32,8 @@ OBJDUMP_BINARY = aarch64-none-elf-objdump NM_BINARY = aarch64-none-elf-nm READELF_BINARY = aarch64-none-elf-readelf @@ -329,7 +329,7 @@ diff -uNr 07_timestamps/Makefile 08_hw_debug_JTAG/Makefile LD_SCRIPT_PATH = $(shell pwd)/src/bsp/raspberrypi RUSTC_MISC_ARGS = -C target-cpu=cortex-a53 else ifeq ($(BSP),rpi4) -@@ -42,6 +44,8 @@ +@@ -43,6 +45,8 @@ OBJDUMP_BINARY = aarch64-none-elf-objdump NM_BINARY = aarch64-none-elf-nm READELF_BINARY = aarch64-none-elf-readelf @@ -338,7 +338,7 @@ diff -uNr 07_timestamps/Makefile 08_hw_debug_JTAG/Makefile LD_SCRIPT_PATH = $(shell pwd)/src/bsp/raspberrypi RUSTC_MISC_ARGS = -C target-cpu=cortex-a72 endif -@@ -98,18 +102,25 @@ +@@ -99,18 +103,25 @@ DOCKER_CMD = docker run -t --rm -v $(shell pwd):/work/tutorial -w /work/tutorial DOCKER_CMD_INTERACT = $(DOCKER_CMD) -i DOCKER_ARG_DIR_COMMON = -v $(shell pwd)/../common:/work/common @@ -364,7 +364,7 @@ diff -uNr 07_timestamps/Makefile 08_hw_debug_JTAG/Makefile endif -@@ -214,6 +225,35 @@ +@@ -215,6 +226,35 @@ diff --git a/09_privilege_level/Makefile b/09_privilege_level/Makefile index ce0ebc31..125f75cb 100644 --- a/09_privilege_level/Makefile +++ b/09_privilege_level/Makefile @@ -2,8 +2,9 @@ ## ## Copyright (c) 2018-2022 Andre Richter -include ../common/format.mk include ../common/docker.mk +include ../common/format.mk +include ../common/operating_system.mk ##-------------------------------------------------------------------------------------------------- ## Optional, user-provided configuration values @@ -156,7 +157,7 @@ $(KERNEL_BIN): $(KERNEL_ELF) $(call color_progress_prefix, "Name") @echo $(KERNEL_BIN) $(call color_progress_prefix, "Size") - @printf '%s KiB\n' `du -k $(KERNEL_BIN) | cut -f1` + $(call disk_usage_KiB, $(KERNEL_BIN)) ##------------------------------------------------------------------------------ ## Generate the documentation diff --git a/10_virtual_mem_part1_identity_mapping/Makefile b/10_virtual_mem_part1_identity_mapping/Makefile index ce0ebc31..125f75cb 100644 --- a/10_virtual_mem_part1_identity_mapping/Makefile +++ b/10_virtual_mem_part1_identity_mapping/Makefile @@ -2,8 +2,9 @@ ## ## Copyright (c) 2018-2022 Andre Richter -include ../common/format.mk include ../common/docker.mk +include ../common/format.mk +include ../common/operating_system.mk ##-------------------------------------------------------------------------------------------------- ## Optional, user-provided configuration values @@ -156,7 +157,7 @@ $(KERNEL_BIN): $(KERNEL_ELF) $(call color_progress_prefix, "Name") @echo $(KERNEL_BIN) $(call color_progress_prefix, "Size") - @printf '%s KiB\n' `du -k $(KERNEL_BIN) | cut -f1` + $(call disk_usage_KiB, $(KERNEL_BIN)) ##------------------------------------------------------------------------------ ## Generate the documentation diff --git a/11_exceptions_part1_groundwork/Makefile b/11_exceptions_part1_groundwork/Makefile index ce0ebc31..125f75cb 100644 --- a/11_exceptions_part1_groundwork/Makefile +++ b/11_exceptions_part1_groundwork/Makefile @@ -2,8 +2,9 @@ ## ## Copyright (c) 2018-2022 Andre Richter -include ../common/format.mk include ../common/docker.mk +include ../common/format.mk +include ../common/operating_system.mk ##-------------------------------------------------------------------------------------------------- ## Optional, user-provided configuration values @@ -156,7 +157,7 @@ $(KERNEL_BIN): $(KERNEL_ELF) $(call color_progress_prefix, "Name") @echo $(KERNEL_BIN) $(call color_progress_prefix, "Size") - @printf '%s KiB\n' `du -k $(KERNEL_BIN) | cut -f1` + $(call disk_usage_KiB, $(KERNEL_BIN)) ##------------------------------------------------------------------------------ ## Generate the documentation diff --git a/12_integrated_testing/Makefile b/12_integrated_testing/Makefile index 2d480119..88d106f8 100644 --- a/12_integrated_testing/Makefile +++ b/12_integrated_testing/Makefile @@ -2,8 +2,9 @@ ## ## Copyright (c) 2018-2022 Andre Richter -include ../common/format.mk include ../common/docker.mk +include ../common/format.mk +include ../common/operating_system.mk ##-------------------------------------------------------------------------------------------------- ## Optional, user-provided configuration values @@ -166,7 +167,7 @@ $(KERNEL_BIN): $(KERNEL_ELF) $(call color_progress_prefix, "Name") @echo $(KERNEL_BIN) $(call color_progress_prefix, "Size") - @printf '%s KiB\n' `du -k $(KERNEL_BIN) | cut -f1` + $(call disk_usage_KiB, $(KERNEL_BIN)) ##------------------------------------------------------------------------------ ## Generate the documentation diff --git a/13_exceptions_part2_peripheral_IRQs/Makefile b/13_exceptions_part2_peripheral_IRQs/Makefile index 2d480119..88d106f8 100644 --- a/13_exceptions_part2_peripheral_IRQs/Makefile +++ b/13_exceptions_part2_peripheral_IRQs/Makefile @@ -2,8 +2,9 @@ ## ## Copyright (c) 2018-2022 Andre Richter -include ../common/format.mk include ../common/docker.mk +include ../common/format.mk +include ../common/operating_system.mk ##-------------------------------------------------------------------------------------------------- ## Optional, user-provided configuration values @@ -166,7 +167,7 @@ $(KERNEL_BIN): $(KERNEL_ELF) $(call color_progress_prefix, "Name") @echo $(KERNEL_BIN) $(call color_progress_prefix, "Size") - @printf '%s KiB\n' `du -k $(KERNEL_BIN) | cut -f1` + $(call disk_usage_KiB, $(KERNEL_BIN)) ##------------------------------------------------------------------------------ ## Generate the documentation diff --git a/14_virtual_mem_part2_mmio_remap/Makefile b/14_virtual_mem_part2_mmio_remap/Makefile index 2d480119..88d106f8 100644 --- a/14_virtual_mem_part2_mmio_remap/Makefile +++ b/14_virtual_mem_part2_mmio_remap/Makefile @@ -2,8 +2,9 @@ ## ## Copyright (c) 2018-2022 Andre Richter -include ../common/format.mk include ../common/docker.mk +include ../common/format.mk +include ../common/operating_system.mk ##-------------------------------------------------------------------------------------------------- ## Optional, user-provided configuration values @@ -166,7 +167,7 @@ $(KERNEL_BIN): $(KERNEL_ELF) $(call color_progress_prefix, "Name") @echo $(KERNEL_BIN) $(call color_progress_prefix, "Size") - @printf '%s KiB\n' `du -k $(KERNEL_BIN) | cut -f1` + $(call disk_usage_KiB, $(KERNEL_BIN)) ##------------------------------------------------------------------------------ ## Generate the documentation diff --git a/15_virtual_mem_part3_precomputed_tables/Makefile b/15_virtual_mem_part3_precomputed_tables/Makefile index 4092ec8f..0f5c4870 100644 --- a/15_virtual_mem_part3_precomputed_tables/Makefile +++ b/15_virtual_mem_part3_precomputed_tables/Makefile @@ -2,8 +2,9 @@ ## ## Copyright (c) 2018-2022 Andre Richter -include ../common/format.mk include ../common/docker.mk +include ../common/format.mk +include ../common/operating_system.mk ##-------------------------------------------------------------------------------------------------- ## Optional, user-provided configuration values @@ -185,7 +186,7 @@ $(KERNEL_BIN): $(KERNEL_ELF_TTABLES) $(call color_progress_prefix, "Name") @echo $(KERNEL_BIN) $(call color_progress_prefix, "Size") - @printf '%s KiB\n' `du -k $(KERNEL_BIN) | cut -f1` + $(call disk_usage_KiB, $(KERNEL_BIN)) ##------------------------------------------------------------------------------ ## Generate the documentation diff --git a/15_virtual_mem_part3_precomputed_tables/README.md b/15_virtual_mem_part3_precomputed_tables/README.md index 00586235..c850992e 100644 --- a/15_virtual_mem_part3_precomputed_tables/README.md +++ b/15_virtual_mem_part3_precomputed_tables/README.md @@ -1848,7 +1848,7 @@ diff -uNr 14_virtual_mem_part2_mmio_remap/kernel/tests/04_exception_irq_sanity.r diff -uNr 14_virtual_mem_part2_mmio_remap/Makefile 15_virtual_mem_part3_precomputed_tables/Makefile --- 14_virtual_mem_part2_mmio_remap/Makefile +++ 15_virtual_mem_part3_precomputed_tables/Makefile -@@ -71,10 +71,20 @@ +@@ -72,10 +72,20 @@ KERNEL_LINKER_SCRIPT = kernel.ld LAST_BUILD_CONFIG = target/$(BSP).build_config @@ -1871,7 +1871,7 @@ diff -uNr 14_virtual_mem_part2_mmio_remap/Makefile 15_virtual_mem_part3_precompu -@@ -103,6 +113,7 @@ +@@ -104,6 +114,7 @@ -O binary EXEC_QEMU = $(QEMU_BINARY) -M $(QEMU_MACHINE_TYPE) @@ -1879,7 +1879,7 @@ diff -uNr 14_virtual_mem_part2_mmio_remap/Makefile 15_virtual_mem_part3_precompu EXEC_TEST_DISPATCH = ruby ../common/tests/dispatch.rb EXEC_MINIPUSH = ruby ../common/serial/minipush.rb -@@ -153,16 +164,24 @@ +@@ -154,16 +165,24 @@ ##------------------------------------------------------------------------------ ## Compile the kernel ELF ##------------------------------------------------------------------------------ @@ -1907,7 +1907,7 @@ diff -uNr 14_virtual_mem_part2_mmio_remap/Makefile 15_virtual_mem_part3_precompu $(call color_progress_prefix, "Name") @echo $(KERNEL_BIN) $(call color_progress_prefix, "Size") -@@ -300,6 +319,7 @@ +@@ -301,6 +320,7 @@ TEST_ELF=$$(echo $$1 | sed -e 's/.*target/target/g') TEST_BINARY=$$(echo $$1.img | sed -e 's/.*target/target/g') diff --git a/16_virtual_mem_part4_higher_half_kernel/Makefile b/16_virtual_mem_part4_higher_half_kernel/Makefile index 4092ec8f..0f5c4870 100644 --- a/16_virtual_mem_part4_higher_half_kernel/Makefile +++ b/16_virtual_mem_part4_higher_half_kernel/Makefile @@ -2,8 +2,9 @@ ## ## Copyright (c) 2018-2022 Andre Richter -include ../common/format.mk include ../common/docker.mk +include ../common/format.mk +include ../common/operating_system.mk ##-------------------------------------------------------------------------------------------------- ## Optional, user-provided configuration values @@ -185,7 +186,7 @@ $(KERNEL_BIN): $(KERNEL_ELF_TTABLES) $(call color_progress_prefix, "Name") @echo $(KERNEL_BIN) $(call color_progress_prefix, "Size") - @printf '%s KiB\n' `du -k $(KERNEL_BIN) | cut -f1` + $(call disk_usage_KiB, $(KERNEL_BIN)) ##------------------------------------------------------------------------------ ## Generate the documentation diff --git a/17_kernel_symbols/Makefile b/17_kernel_symbols/Makefile index 7bed51da..ce1d165b 100644 --- a/17_kernel_symbols/Makefile +++ b/17_kernel_symbols/Makefile @@ -2,8 +2,9 @@ ## ## Copyright (c) 2018-2022 Andre Richter -include ../common/format.mk include ../common/docker.mk +include ../common/format.mk +include ../common/operating_system.mk ##-------------------------------------------------------------------------------------------------- ## Optional, user-provided configuration values @@ -198,8 +199,7 @@ $(KERNEL_ELF_TTABLES): $(KERNEL_ELF_TTABLES_DEPS) ##------------------------------------------------------------------------------ $(KERNEL_ELF_TTABLES_SYMS): $(KERNEL_ELF_TTABLES_SYMS_DEPS) $(call color_header, "Generating kernel symbols and patching kernel ELF") - @time -f "in %es" \ - $(MAKE) --no-print-directory -f kernel_symbols.mk + @$(MAKE) --no-print-directory -f kernel_symbols.mk ##------------------------------------------------------------------------------ ## Generate the stripped kernel binary @@ -210,7 +210,7 @@ $(KERNEL_BIN): $(KERNEL_ELF_TTABLES_SYMS) $(call color_progress_prefix, "Name") @echo $(KERNEL_BIN) $(call color_progress_prefix, "Size") - @printf '%s KiB\n' `du -k $(KERNEL_BIN) | cut -f1` + $(call disk_usage_KiB, $(KERNEL_BIN)) ##------------------------------------------------------------------------------ ## Generate the documentation diff --git a/17_kernel_symbols/README.md b/17_kernel_symbols/README.md index 87264162..925ed689 100644 --- a/17_kernel_symbols/README.md +++ b/17_kernel_symbols/README.md @@ -516,7 +516,7 @@ diff -uNr 16_virtual_mem_part4_higher_half_kernel/kernel_symbols/src/main.rs 17_ diff -uNr 16_virtual_mem_part4_higher_half_kernel/kernel_symbols.mk 17_kernel_symbols/kernel_symbols.mk --- 16_virtual_mem_part4_higher_half_kernel/kernel_symbols.mk +++ 17_kernel_symbols/kernel_symbols.mk -@@ -0,0 +1,103 @@ +@@ -0,0 +1,117 @@ +## SPDX-License-Identifier: MIT OR Apache-2.0 +## +## Copyright (c) 2018-2022 Andre Richter @@ -598,9 +598,11 @@ diff -uNr 16_virtual_mem_part4_higher_half_kernel/kernel_symbols.mk 17_kernel_sy +##-------------------------------------------------------------------------------------------------- +## Targets +##-------------------------------------------------------------------------------------------------- -+.PHONY: all ++.PHONY: all symbols measure_time_start measure_time_finish + -+all: ++all: measure_time_start symbols measure_time_finish ++ ++symbols: + @cp $(KERNEL_SYMBOLS_INPUT_ELF) $(KERNEL_SYMBOLS_OUTPUT_ELF) + + @$(DOCKER_TOOLS) $(EXEC_SYMBOLS_TOOL) --gen_symbols $(KERNEL_SYMBOLS_OUTPUT_ELF) \ @@ -619,7 +621,19 @@ diff -uNr 16_virtual_mem_part4_higher_half_kernel/kernel_symbols.mk 17_kernel_sy + @$(DOCKER_TOOLS) $(EXEC_SYMBOLS_TOOL) --patch_data $(KERNEL_SYMBOLS_OUTPUT_ELF) \ + $(KERNEL_SYMBOLS_STRIPPED) + ++# Note: The following is the only _trivial_ way I could think of that works out of the box on both ++# Linux and macOS. Since macOS does not have the moduloN nanosecond format string option, the ++# resolution is restricted to whole seconds. ++measure_time_start: ++ @date +modulos > /tmp/kernel_symbols_start.date ++ ++measure_time_finish: ++ @date +modulos > /tmp/kernel_symbols_end.date ++ + $(call color_progress_prefix, "Finished") ++ @echo "in $$((`cat /tmp/kernel_symbols_end.date` - `cat /tmp/kernel_symbols_start.date`)).0s" ++ ++ @rm /tmp/kernel_symbols_end.date /tmp/kernel_symbols_start.date diff -uNr 16_virtual_mem_part4_higher_half_kernel/libraries/debug-symbol-types/Cargo.toml 17_kernel_symbols/libraries/debug-symbol-types/Cargo.toml --- 16_virtual_mem_part4_higher_half_kernel/libraries/debug-symbol-types/Cargo.toml @@ -683,7 +697,7 @@ diff -uNr 16_virtual_mem_part4_higher_half_kernel/libraries/debug-symbol-types/s diff -uNr 16_virtual_mem_part4_higher_half_kernel/Makefile 17_kernel_symbols/Makefile --- 16_virtual_mem_part4_higher_half_kernel/Makefile +++ 17_kernel_symbols/Makefile -@@ -84,7 +84,24 @@ +@@ -85,7 +85,24 @@ KERNEL_ELF_TTABLES = target/$(TARGET)/release/kernel+ttables KERNEL_ELF_TTABLES_DEPS = $(KERNEL_ELF_RAW) $(wildcard $(TT_TOOL_PATH)/*) @@ -709,7 +723,7 @@ diff -uNr 16_virtual_mem_part4_higher_half_kernel/Makefile 17_kernel_symbols/Mak -@@ -177,11 +194,19 @@ +@@ -178,11 +195,18 @@ @$(DOCKER_TOOLS) $(EXEC_TT_TOOL) $(BSP) $(KERNEL_ELF_TTABLES) ##------------------------------------------------------------------------------ @@ -717,8 +731,7 @@ diff -uNr 16_virtual_mem_part4_higher_half_kernel/Makefile 17_kernel_symbols/Mak +##------------------------------------------------------------------------------ +$(KERNEL_ELF_TTABLES_SYMS): $(KERNEL_ELF_TTABLES_SYMS_DEPS) + $(call color_header, "Generating kernel symbols and patching kernel ELF") -+ @time -f "in moduloes" \ -+ $(MAKE) --no-print-directory -f kernel_symbols.mk ++ @$(MAKE) --no-print-directory -f kernel_symbols.mk + +##------------------------------------------------------------------------------ ## Generate the stripped kernel binary @@ -731,7 +744,7 @@ diff -uNr 16_virtual_mem_part4_higher_half_kernel/Makefile 17_kernel_symbols/Mak $(call color_progress_prefix, "Name") @echo $(KERNEL_BIN) $(call color_progress_prefix, "Size") -@@ -190,7 +215,7 @@ +@@ -191,7 +215,7 @@ ##------------------------------------------------------------------------------ ## Generate the documentation ##------------------------------------------------------------------------------ @@ -740,7 +753,7 @@ diff -uNr 16_virtual_mem_part4_higher_half_kernel/Makefile 17_kernel_symbols/Mak $(call color_header, "Generating docs") @$(DOC_CMD) --document-private-items --open -@@ -317,10 +342,19 @@ +@@ -318,10 +342,19 @@ cd $(shell pwd) TEST_ELF=$$(echo $$1 | sed -e 's/.*target/target/g') diff --git a/17_kernel_symbols/kernel_symbols.mk b/17_kernel_symbols/kernel_symbols.mk index 5b51ccfe..d496ea8a 100644 --- a/17_kernel_symbols/kernel_symbols.mk +++ b/17_kernel_symbols/kernel_symbols.mk @@ -79,9 +79,11 @@ DOCKER_TOOLS = $(DOCKER_CMD) $(DOCKER_IMAGE) ##-------------------------------------------------------------------------------------------------- ## Targets ##-------------------------------------------------------------------------------------------------- -.PHONY: all +.PHONY: all symbols measure_time_start measure_time_finish -all: +all: measure_time_start symbols measure_time_finish + +symbols: @cp $(KERNEL_SYMBOLS_INPUT_ELF) $(KERNEL_SYMBOLS_OUTPUT_ELF) @$(DOCKER_TOOLS) $(EXEC_SYMBOLS_TOOL) --gen_symbols $(KERNEL_SYMBOLS_OUTPUT_ELF) \ @@ -100,4 +102,16 @@ all: @$(DOCKER_TOOLS) $(EXEC_SYMBOLS_TOOL) --patch_data $(KERNEL_SYMBOLS_OUTPUT_ELF) \ $(KERNEL_SYMBOLS_STRIPPED) +# Note: The following is the only _trivial_ way I could think of that works out of the box on both +# Linux and macOS. Since macOS does not have the %N nanosecond format string option, the +# resolution is restricted to whole seconds. +measure_time_start: + @date +%s > /tmp/kernel_symbols_start.date + +measure_time_finish: + @date +%s > /tmp/kernel_symbols_end.date + $(call color_progress_prefix, "Finished") + @echo "in $$((`cat /tmp/kernel_symbols_end.date` - `cat /tmp/kernel_symbols_start.date`)).0s" + + @rm /tmp/kernel_symbols_end.date /tmp/kernel_symbols_start.date diff --git a/18_backtrace/Makefile b/18_backtrace/Makefile index 789ed5cd..fbd96e64 100644 --- a/18_backtrace/Makefile +++ b/18_backtrace/Makefile @@ -2,8 +2,9 @@ ## ## Copyright (c) 2018-2022 Andre Richter -include ../common/format.mk include ../common/docker.mk +include ../common/format.mk +include ../common/operating_system.mk ##-------------------------------------------------------------------------------------------------- ## Optional, user-provided configuration values @@ -200,8 +201,7 @@ $(KERNEL_ELF_TTABLES): $(KERNEL_ELF_TTABLES_DEPS) ##------------------------------------------------------------------------------ $(KERNEL_ELF_TTABLES_SYMS): $(KERNEL_ELF_TTABLES_SYMS_DEPS) $(call color_header, "Generating kernel symbols and patching kernel ELF") - @time -f "in %es" \ - $(MAKE) --no-print-directory -f kernel_symbols.mk + @$(MAKE) --no-print-directory -f kernel_symbols.mk ##------------------------------------------------------------------------------ ## Generate the stripped kernel binary @@ -212,7 +212,7 @@ $(KERNEL_BIN): $(KERNEL_ELF_TTABLES_SYMS) $(call color_progress_prefix, "Name") @echo $(KERNEL_BIN) $(call color_progress_prefix, "Size") - @printf '%s KiB\n' `du -k $(KERNEL_BIN) | cut -f1` + $(call disk_usage_KiB, $(KERNEL_BIN)) ##------------------------------------------------------------------------------ ## Generate the documentation diff --git a/18_backtrace/README.md b/18_backtrace/README.md index 021b8435..837d0161 100644 --- a/18_backtrace/README.md +++ b/18_backtrace/README.md @@ -1227,7 +1227,7 @@ diff -uNr 17_kernel_symbols/kernel/tests/07_backtrace_invalid_link.rs 18_backtra diff -uNr 17_kernel_symbols/Makefile 18_backtrace/Makefile --- 17_kernel_symbols/Makefile +++ 18_backtrace/Makefile -@@ -42,7 +42,7 @@ +@@ -43,7 +43,7 @@ OPENOCD_ARG = -f /openocd/tcl/interface/ftdi/olimex-arm-usb-tiny-h.cfg -f /openocd/rpi3.cfg JTAG_BOOT_IMAGE = ../X1_JTAG_boot/jtag_boot_rpi3.img LD_SCRIPT_PATH = $(shell pwd)/kernel/src/bsp/raspberrypi @@ -1236,7 +1236,7 @@ diff -uNr 17_kernel_symbols/Makefile 18_backtrace/Makefile else ifeq ($(BSP),rpi4) TARGET = aarch64-unknown-none-softfloat KERNEL_BIN = kernel8.img -@@ -56,7 +56,7 @@ +@@ -57,7 +57,7 @@ OPENOCD_ARG = -f /openocd/tcl/interface/ftdi/olimex-arm-usb-tiny-h.cfg -f /openocd/rpi4.cfg JTAG_BOOT_IMAGE = ../X1_JTAG_boot/jtag_boot_rpi4.img LD_SCRIPT_PATH = $(shell pwd)/kernel/src/bsp/raspberrypi @@ -1245,7 +1245,7 @@ diff -uNr 17_kernel_symbols/Makefile 18_backtrace/Makefile endif # Export for build.rs. -@@ -121,10 +121,12 @@ +@@ -122,10 +122,12 @@ $(FEATURES) \ --release diff --git a/18_backtrace/kernel_symbols.mk b/18_backtrace/kernel_symbols.mk index 5b51ccfe..d496ea8a 100644 --- a/18_backtrace/kernel_symbols.mk +++ b/18_backtrace/kernel_symbols.mk @@ -79,9 +79,11 @@ DOCKER_TOOLS = $(DOCKER_CMD) $(DOCKER_IMAGE) ##-------------------------------------------------------------------------------------------------- ## Targets ##-------------------------------------------------------------------------------------------------- -.PHONY: all +.PHONY: all symbols measure_time_start measure_time_finish -all: +all: measure_time_start symbols measure_time_finish + +symbols: @cp $(KERNEL_SYMBOLS_INPUT_ELF) $(KERNEL_SYMBOLS_OUTPUT_ELF) @$(DOCKER_TOOLS) $(EXEC_SYMBOLS_TOOL) --gen_symbols $(KERNEL_SYMBOLS_OUTPUT_ELF) \ @@ -100,4 +102,16 @@ all: @$(DOCKER_TOOLS) $(EXEC_SYMBOLS_TOOL) --patch_data $(KERNEL_SYMBOLS_OUTPUT_ELF) \ $(KERNEL_SYMBOLS_STRIPPED) +# Note: The following is the only _trivial_ way I could think of that works out of the box on both +# Linux and macOS. Since macOS does not have the %N nanosecond format string option, the +# resolution is restricted to whole seconds. +measure_time_start: + @date +%s > /tmp/kernel_symbols_start.date + +measure_time_finish: + @date +%s > /tmp/kernel_symbols_end.date + $(call color_progress_prefix, "Finished") + @echo "in $$((`cat /tmp/kernel_symbols_end.date` - `cat /tmp/kernel_symbols_start.date`)).0s" + + @rm /tmp/kernel_symbols_end.date /tmp/kernel_symbols_start.date diff --git a/19_kernel_heap/Makefile b/19_kernel_heap/Makefile index be41c136..43f5ad1f 100644 --- a/19_kernel_heap/Makefile +++ b/19_kernel_heap/Makefile @@ -2,8 +2,9 @@ ## ## Copyright (c) 2018-2022 Andre Richter -include ../common/format.mk include ../common/docker.mk +include ../common/format.mk +include ../common/operating_system.mk ##-------------------------------------------------------------------------------------------------- ## Optional, user-provided configuration values @@ -205,8 +206,7 @@ $(KERNEL_ELF_TTABLES): $(KERNEL_ELF_TTABLES_DEPS) ##------------------------------------------------------------------------------ $(KERNEL_ELF_TTABLES_SYMS): $(KERNEL_ELF_TTABLES_SYMS_DEPS) $(call color_header, "Generating kernel symbols and patching kernel ELF") - @time -f "in %es" \ - $(MAKE) --no-print-directory -f kernel_symbols.mk + @$(MAKE) --no-print-directory -f kernel_symbols.mk ##------------------------------------------------------------------------------ ## Generate the stripped kernel binary @@ -217,7 +217,7 @@ $(KERNEL_BIN): $(KERNEL_ELF_TTABLES_SYMS) $(call color_progress_prefix, "Name") @echo $(KERNEL_BIN) $(call color_progress_prefix, "Size") - @printf '%s KiB\n' `du -k $(KERNEL_BIN) | cut -f1` + $(call disk_usage_KiB, $(KERNEL_BIN)) ##------------------------------------------------------------------------------ ## Generate the documentation diff --git a/19_kernel_heap/README.md b/19_kernel_heap/README.md index a40d203d..54bca4ef 100644 --- a/19_kernel_heap/README.md +++ b/19_kernel_heap/README.md @@ -1426,7 +1426,7 @@ diff -uNr 18_backtrace/kernel/src/state.rs 19_kernel_heap/kernel/src/state.rs diff -uNr 18_backtrace/Makefile 19_kernel_heap/Makefile --- 18_backtrace/Makefile +++ 19_kernel_heap/Makefile -@@ -15,6 +15,11 @@ +@@ -16,6 +16,11 @@ # Default to a serial device name that is common in Linux. DEV_SERIAL ?= /dev/ttyUSB0 @@ -1438,7 +1438,7 @@ diff -uNr 18_backtrace/Makefile 19_kernel_heap/Makefile # Optional integration test name. ifdef TEST TEST_ARG = --test $(TEST) -@@ -69,7 +74,7 @@ +@@ -70,7 +75,7 @@ ##-------------------------------------------------------------------------------------------------- KERNEL_MANIFEST = kernel/Cargo.toml KERNEL_LINKER_SCRIPT = kernel.ld @@ -1447,7 +1447,7 @@ diff -uNr 18_backtrace/Makefile 19_kernel_heap/Makefile KERNEL_ELF_RAW = target/$(TARGET)/release/kernel # This parses cargo's dep-info file. -@@ -116,17 +121,17 @@ +@@ -117,17 +122,17 @@ -D warnings \ -D missing_docs diff --git a/19_kernel_heap/kernel_symbols.mk b/19_kernel_heap/kernel_symbols.mk index 5b51ccfe..d496ea8a 100644 --- a/19_kernel_heap/kernel_symbols.mk +++ b/19_kernel_heap/kernel_symbols.mk @@ -79,9 +79,11 @@ DOCKER_TOOLS = $(DOCKER_CMD) $(DOCKER_IMAGE) ##-------------------------------------------------------------------------------------------------- ## Targets ##-------------------------------------------------------------------------------------------------- -.PHONY: all +.PHONY: all symbols measure_time_start measure_time_finish -all: +all: measure_time_start symbols measure_time_finish + +symbols: @cp $(KERNEL_SYMBOLS_INPUT_ELF) $(KERNEL_SYMBOLS_OUTPUT_ELF) @$(DOCKER_TOOLS) $(EXEC_SYMBOLS_TOOL) --gen_symbols $(KERNEL_SYMBOLS_OUTPUT_ELF) \ @@ -100,4 +102,16 @@ all: @$(DOCKER_TOOLS) $(EXEC_SYMBOLS_TOOL) --patch_data $(KERNEL_SYMBOLS_OUTPUT_ELF) \ $(KERNEL_SYMBOLS_STRIPPED) +# Note: The following is the only _trivial_ way I could think of that works out of the box on both +# Linux and macOS. Since macOS does not have the %N nanosecond format string option, the +# resolution is restricted to whole seconds. +measure_time_start: + @date +%s > /tmp/kernel_symbols_start.date + +measure_time_finish: + @date +%s > /tmp/kernel_symbols_end.date + $(call color_progress_prefix, "Finished") + @echo "in $$((`cat /tmp/kernel_symbols_end.date` - `cat /tmp/kernel_symbols_start.date`)).0s" + + @rm /tmp/kernel_symbols_end.date /tmp/kernel_symbols_start.date diff --git a/README.md b/README.md index 745dd3c5..7267f440 100644 --- a/README.md +++ b/README.md @@ -81,10 +81,16 @@ The tutorials are primarily targeted at **Linux**-based distributions. Most stuf 1. In case you use `Visual Studio Code`, I strongly recommend installing the [Rust Analyzer extension]. 1. (**macOS only**) Install a few `Ruby` gems. + This was last tested by the author with Ruby version `3.0.2` on `macOS Monterey`. If you are using + `rbenv`, the respective `.ruby-version` file is already in place. If you never heard of `rbenv`, + try using [this little guide](https://stackoverflow.com/a/68118750). + Run this in the repository root folder: ```bash - bundle install --path .vendor/bundle --without development + bundle config set --local path '.vendor/bundle' + bundle config set --local without 'development' + bundle install ``` [docker group]: https://docs.docker.com/engine/install/linux-postinstall/ diff --git a/X1_JTAG_boot/Makefile b/X1_JTAG_boot/Makefile index 76ddb186..23de6557 100644 --- a/X1_JTAG_boot/Makefile +++ b/X1_JTAG_boot/Makefile @@ -2,8 +2,9 @@ ## ## Copyright (c) 2018-2022 Andre Richter -include ../common/format.mk include ../common/docker.mk +include ../common/format.mk +include ../common/operating_system.mk ##-------------------------------------------------------------------------------------------------- ## Optional, user-provided configuration values @@ -145,7 +146,7 @@ $(KERNEL_BIN): $(KERNEL_ELF) $(call color_progress_prefix, "Name") @echo $(KERNEL_BIN) $(call color_progress_prefix, "Size") - @printf '%s KiB\n' `du -k $(KERNEL_BIN) | cut -f1` + $(call disk_usage_KiB, $(KERNEL_BIN)) ##------------------------------------------------------------------------------ ## Generate the documentation diff --git a/common/operating_system.mk b/common/operating_system.mk new file mode 100644 index 00000000..90172f77 --- /dev/null +++ b/common/operating_system.mk @@ -0,0 +1,9 @@ +ifeq ($(shell uname -s),Linux) + DU_ARGUMENTS = --block-size=1024 --apparent-size +else ifeq ($(shell uname -s),Darwin) + DU_ARGUMENTS = -k -A +endif + +define disk_usage_KiB + @printf '%s KiB\n' `du $(DU_ARGUMENTS) $(1) | cut -f1` +endef From 203fe318d4985ef139900175b5ff2ddffa6a6387 Mon Sep 17 00:00:00 2001 From: Andre Richter Date: Tue, 25 Oct 2022 08:37:35 +0200 Subject: [PATCH 59/75] Fix rubocop complaint; Bump actions Ubuntu version --- .github/workflows/build_rpi3.yml | 6 +++--- .github/workflows/build_rpi4.yml | 6 +++--- .github/workflows/sanity.yml | 6 +++--- .github/workflows/test_integration.yml | 6 +++--- .github/workflows/test_unit.yml | 6 +++--- .github/workflows/test_xtra.yml | 6 +++--- Gemfile | 2 +- contributor_setup.sh | 2 +- utils/devtool.rb | 2 +- 9 files changed, 21 insertions(+), 21 deletions(-) diff --git a/.github/workflows/build_rpi3.yml b/.github/workflows/build_rpi3.yml index d974eebf..acdea068 100644 --- a/.github/workflows/build_rpi3.yml +++ b/.github/workflows/build_rpi3.yml @@ -21,11 +21,11 @@ on: jobs: build: name: Build kernels - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v2 - - name: Set up Ruby 2.x + - uses: actions/checkout@v3 + - name: Set up Ruby uses: ruby/setup-ruby@v1 - name: Set up Rust nightly run: | diff --git a/.github/workflows/build_rpi4.yml b/.github/workflows/build_rpi4.yml index 68de1dc1..c511f7bc 100644 --- a/.github/workflows/build_rpi4.yml +++ b/.github/workflows/build_rpi4.yml @@ -21,11 +21,11 @@ on: jobs: build: name: Build kernels - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v2 - - name: Set up Ruby 2.x + - uses: actions/checkout@v3 + - name: Set up Ruby uses: ruby/setup-ruby@v1 - name: Set up Rust nightly run: | diff --git a/.github/workflows/sanity.yml b/.github/workflows/sanity.yml index a42198d7..9441e3c9 100644 --- a/.github/workflows/sanity.yml +++ b/.github/workflows/sanity.yml @@ -11,15 +11,15 @@ on: jobs: build: name: Various Sanity Checks - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Set up Node uses: actions/setup-node@v1 with: node-version: "12" - - name: Set up Ruby 2.x + - name: Set up Ruby uses: ruby/setup-ruby@v1 - name: Set up Rust nightly run: | diff --git a/.github/workflows/test_integration.yml b/.github/workflows/test_integration.yml index 954d6432..f2980039 100644 --- a/.github/workflows/test_integration.yml +++ b/.github/workflows/test_integration.yml @@ -21,11 +21,11 @@ on: jobs: build: name: Run integration tests - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v2 - - name: Set up Ruby 2.x + - uses: actions/checkout@v3 + - name: Set up Ruby uses: ruby/setup-ruby@v1 - name: Set up Rust nightly run: | diff --git a/.github/workflows/test_unit.yml b/.github/workflows/test_unit.yml index 02de1b84..909bde35 100644 --- a/.github/workflows/test_unit.yml +++ b/.github/workflows/test_unit.yml @@ -21,11 +21,11 @@ on: jobs: build: name: Run boot and unit tests - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v2 - - name: Set up Ruby 2.x + - uses: actions/checkout@v3 + - name: Set up Ruby uses: ruby/setup-ruby@v1 - name: Set up Rust nightly run: | diff --git a/.github/workflows/test_xtra.yml b/.github/workflows/test_xtra.yml index a330ef74..f77c8da1 100644 --- a/.github/workflows/test_xtra.yml +++ b/.github/workflows/test_xtra.yml @@ -21,11 +21,11 @@ on: jobs: build: name: Run xtra tests - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v2 - - name: Set up Ruby 2.x + - uses: actions/checkout@v3 + - name: Set up Ruby uses: ruby/setup-ruby@v1 - name: Set up Rust nightly run: | diff --git a/Gemfile b/Gemfile index 7ac3b89e..48256484 100644 --- a/Gemfile +++ b/Gemfile @@ -11,5 +11,5 @@ group :uart do end group :development do - gem 'rubocop', '>= 1.4.1', require: false + gem 'rubocop', '>= 1.37.1', require: false end diff --git a/contributor_setup.sh b/contributor_setup.sh index 8348b4d7..26a4059e 100755 --- a/contributor_setup.sh +++ b/contributor_setup.sh @@ -10,7 +10,7 @@ then echo "'bundle' could not be found. Please install Ruby and Bundler." exit fi -bundle config set path '.vendor/bundle' +bundle config set --local path '.vendor/bundle' bundle install # diff --git a/utils/devtool.rb b/utils/devtool.rb index 47141c1d..fdbcf3a5 100755 --- a/utils/devtool.rb +++ b/utils/devtool.rb @@ -108,7 +108,7 @@ class DevTool @user_has_supplied_crates = false @bsp = bsp_from_env || SUPPORTED_BSPS.first - cl = user_supplied_crate_list || Dir['*/Cargo.toml'].sort + cl = user_supplied_crate_list || Dir['*/Cargo.toml'] @crates = cl.map { |c| TutorialCrate.new(c.delete_suffix('/Cargo.toml')) } end From e04022a9eff2d49912c186aacde5ba1a7524a9fd Mon Sep 17 00:00:00 2001 From: Andre Richter Date: Tue, 25 Oct 2022 08:46:05 +0200 Subject: [PATCH 60/75] actions: Bump node to 16 --- .github/workflows/build_rpi3.yml | 2 +- .github/workflows/build_rpi4.yml | 2 +- .github/workflows/sanity.yml | 2 +- .github/workflows/test_integration.yml | 2 +- .github/workflows/test_unit.yml | 2 +- .github/workflows/test_xtra.yml | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/build_rpi3.yml b/.github/workflows/build_rpi3.yml index acdea068..179752b7 100644 --- a/.github/workflows/build_rpi3.yml +++ b/.github/workflows/build_rpi3.yml @@ -35,6 +35,6 @@ jobs: gem install bundler bundle config set without 'uart' bundle install --retry 3 - - name: Make + - name: Run run: | BSP=rpi3 bundle exec ruby utils/devtool.rb make diff --git a/.github/workflows/build_rpi4.yml b/.github/workflows/build_rpi4.yml index c511f7bc..88d69885 100644 --- a/.github/workflows/build_rpi4.yml +++ b/.github/workflows/build_rpi4.yml @@ -35,6 +35,6 @@ jobs: gem install bundler bundle config set without 'uart' bundle install --retry 3 - - name: Make + - name: Run run: | BSP=rpi4 bundle exec ruby utils/devtool.rb make diff --git a/.github/workflows/sanity.yml b/.github/workflows/sanity.yml index 9441e3c9..fc14b242 100644 --- a/.github/workflows/sanity.yml +++ b/.github/workflows/sanity.yml @@ -18,7 +18,7 @@ jobs: - name: Set up Node uses: actions/setup-node@v1 with: - node-version: "12" + node-version: "16" - name: Set up Ruby uses: ruby/setup-ruby@v1 - name: Set up Rust nightly diff --git a/.github/workflows/test_integration.yml b/.github/workflows/test_integration.yml index f2980039..affc9793 100644 --- a/.github/workflows/test_integration.yml +++ b/.github/workflows/test_integration.yml @@ -35,6 +35,6 @@ jobs: gem install bundler bundle config set without 'uart' bundle install --retry 3 - - name: Make all + - name: Run run: | bundle exec ruby utils/devtool.rb test_integration diff --git a/.github/workflows/test_unit.yml b/.github/workflows/test_unit.yml index 909bde35..7518b08c 100644 --- a/.github/workflows/test_unit.yml +++ b/.github/workflows/test_unit.yml @@ -35,7 +35,7 @@ jobs: gem install bundler bundle config set without 'uart' bundle install --retry 3 - - name: Make all + - name: Run run: | bundle exec ruby utils/devtool.rb test_boot bundle exec ruby utils/devtool.rb test_unit diff --git a/.github/workflows/test_xtra.yml b/.github/workflows/test_xtra.yml index f77c8da1..a2a6c1e0 100644 --- a/.github/workflows/test_xtra.yml +++ b/.github/workflows/test_xtra.yml @@ -35,6 +35,6 @@ jobs: gem install bundler bundle config set without 'uart' bundle install --retry 3 - - name: Make all + - name: Run run: | bundle exec ruby utils/devtool.rb make_xtra From c0fb7f536a44a9e8e4f1060b719f66c76fef87bd Mon Sep 17 00:00:00 2001 From: Andre Richter Date: Wed, 26 Oct 2022 21:48:14 +0200 Subject: [PATCH 61/75] Bump dependencies --- 12_integrated_testing/Cargo.lock | 12 ++++++------ 13_exceptions_part2_peripheral_IRQs/Cargo.lock | 12 ++++++------ 14_virtual_mem_part2_mmio_remap/Cargo.lock | 12 ++++++------ .../Cargo.lock | 12 ++++++------ .../Cargo.lock | 12 ++++++------ 17_kernel_symbols/Cargo.lock | 12 ++++++------ 18_backtrace/Cargo.lock | 12 ++++++------ 19_kernel_heap/Cargo.lock | 16 ++++++++-------- 8 files changed, 50 insertions(+), 50 deletions(-) diff --git a/12_integrated_testing/Cargo.lock b/12_integrated_testing/Cargo.lock index 7af740b1..abe5ab82 100644 --- a/12_integrated_testing/Cargo.lock +++ b/12_integrated_testing/Cargo.lock @@ -24,9 +24,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.44" +version = "1.0.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7bd7356a8122b6c4a24a82b278680c73357984ca2fc79a0f9fa6dea7dced7c58" +checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725" dependencies = [ "unicode-ident", ] @@ -48,9 +48,9 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.101" +version = "1.0.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e90cde112c4b9690b8cbe810cba9ddd8bc1d7472e2cae317b69e9438c1cba7d2" +checksum = "a864042229133ada95abf3b54fdc62ef5ccabe9515b64717bcb9a1919e59445d" dependencies = [ "proc-macro2", "quote", @@ -79,6 +79,6 @@ checksum = "696941a0aee7e276a165a978b37918fd5d22c55c3d6bda197813070ca9c0f21c" [[package]] name = "unicode-ident" -version = "1.0.4" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcc811dc4066ac62f84f11307873c4850cb653bfa9b1719cee2bd2204a4bc5dd" +checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3" diff --git a/13_exceptions_part2_peripheral_IRQs/Cargo.lock b/13_exceptions_part2_peripheral_IRQs/Cargo.lock index 59d40ee6..d893a0af 100644 --- a/13_exceptions_part2_peripheral_IRQs/Cargo.lock +++ b/13_exceptions_part2_peripheral_IRQs/Cargo.lock @@ -24,9 +24,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.44" +version = "1.0.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7bd7356a8122b6c4a24a82b278680c73357984ca2fc79a0f9fa6dea7dced7c58" +checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725" dependencies = [ "unicode-ident", ] @@ -48,9 +48,9 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.101" +version = "1.0.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e90cde112c4b9690b8cbe810cba9ddd8bc1d7472e2cae317b69e9438c1cba7d2" +checksum = "a864042229133ada95abf3b54fdc62ef5ccabe9515b64717bcb9a1919e59445d" dependencies = [ "proc-macro2", "quote", @@ -79,6 +79,6 @@ checksum = "696941a0aee7e276a165a978b37918fd5d22c55c3d6bda197813070ca9c0f21c" [[package]] name = "unicode-ident" -version = "1.0.4" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcc811dc4066ac62f84f11307873c4850cb653bfa9b1719cee2bd2204a4bc5dd" +checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3" diff --git a/14_virtual_mem_part2_mmio_remap/Cargo.lock b/14_virtual_mem_part2_mmio_remap/Cargo.lock index a66dec99..dd14a9d7 100644 --- a/14_virtual_mem_part2_mmio_remap/Cargo.lock +++ b/14_virtual_mem_part2_mmio_remap/Cargo.lock @@ -24,9 +24,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.44" +version = "1.0.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7bd7356a8122b6c4a24a82b278680c73357984ca2fc79a0f9fa6dea7dced7c58" +checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725" dependencies = [ "unicode-ident", ] @@ -48,9 +48,9 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.101" +version = "1.0.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e90cde112c4b9690b8cbe810cba9ddd8bc1d7472e2cae317b69e9438c1cba7d2" +checksum = "a864042229133ada95abf3b54fdc62ef5ccabe9515b64717bcb9a1919e59445d" dependencies = [ "proc-macro2", "quote", @@ -79,6 +79,6 @@ checksum = "696941a0aee7e276a165a978b37918fd5d22c55c3d6bda197813070ca9c0f21c" [[package]] name = "unicode-ident" -version = "1.0.4" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcc811dc4066ac62f84f11307873c4850cb653bfa9b1719cee2bd2204a4bc5dd" +checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3" diff --git a/15_virtual_mem_part3_precomputed_tables/Cargo.lock b/15_virtual_mem_part3_precomputed_tables/Cargo.lock index e0c25535..6863764a 100644 --- a/15_virtual_mem_part3_precomputed_tables/Cargo.lock +++ b/15_virtual_mem_part3_precomputed_tables/Cargo.lock @@ -24,9 +24,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.44" +version = "1.0.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7bd7356a8122b6c4a24a82b278680c73357984ca2fc79a0f9fa6dea7dced7c58" +checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725" dependencies = [ "unicode-ident", ] @@ -48,9 +48,9 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.101" +version = "1.0.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e90cde112c4b9690b8cbe810cba9ddd8bc1d7472e2cae317b69e9438c1cba7d2" +checksum = "a864042229133ada95abf3b54fdc62ef5ccabe9515b64717bcb9a1919e59445d" dependencies = [ "proc-macro2", "quote", @@ -79,6 +79,6 @@ checksum = "696941a0aee7e276a165a978b37918fd5d22c55c3d6bda197813070ca9c0f21c" [[package]] name = "unicode-ident" -version = "1.0.4" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcc811dc4066ac62f84f11307873c4850cb653bfa9b1719cee2bd2204a4bc5dd" +checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3" diff --git a/16_virtual_mem_part4_higher_half_kernel/Cargo.lock b/16_virtual_mem_part4_higher_half_kernel/Cargo.lock index 95941be4..1cd1bc74 100644 --- a/16_virtual_mem_part4_higher_half_kernel/Cargo.lock +++ b/16_virtual_mem_part4_higher_half_kernel/Cargo.lock @@ -24,9 +24,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.44" +version = "1.0.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7bd7356a8122b6c4a24a82b278680c73357984ca2fc79a0f9fa6dea7dced7c58" +checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725" dependencies = [ "unicode-ident", ] @@ -48,9 +48,9 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.101" +version = "1.0.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e90cde112c4b9690b8cbe810cba9ddd8bc1d7472e2cae317b69e9438c1cba7d2" +checksum = "a864042229133ada95abf3b54fdc62ef5ccabe9515b64717bcb9a1919e59445d" dependencies = [ "proc-macro2", "quote", @@ -79,6 +79,6 @@ checksum = "696941a0aee7e276a165a978b37918fd5d22c55c3d6bda197813070ca9c0f21c" [[package]] name = "unicode-ident" -version = "1.0.4" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcc811dc4066ac62f84f11307873c4850cb653bfa9b1719cee2bd2204a4bc5dd" +checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3" diff --git a/17_kernel_symbols/Cargo.lock b/17_kernel_symbols/Cargo.lock index 8c84705d..af229efe 100644 --- a/17_kernel_symbols/Cargo.lock +++ b/17_kernel_symbols/Cargo.lock @@ -36,9 +36,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.44" +version = "1.0.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7bd7356a8122b6c4a24a82b278680c73357984ca2fc79a0f9fa6dea7dced7c58" +checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725" dependencies = [ "unicode-ident", ] @@ -60,9 +60,9 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.101" +version = "1.0.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e90cde112c4b9690b8cbe810cba9ddd8bc1d7472e2cae317b69e9438c1cba7d2" +checksum = "a864042229133ada95abf3b54fdc62ef5ccabe9515b64717bcb9a1919e59445d" dependencies = [ "proc-macro2", "quote", @@ -91,6 +91,6 @@ checksum = "696941a0aee7e276a165a978b37918fd5d22c55c3d6bda197813070ca9c0f21c" [[package]] name = "unicode-ident" -version = "1.0.4" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcc811dc4066ac62f84f11307873c4850cb653bfa9b1719cee2bd2204a4bc5dd" +checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3" diff --git a/18_backtrace/Cargo.lock b/18_backtrace/Cargo.lock index f662e8a6..2b51ab72 100644 --- a/18_backtrace/Cargo.lock +++ b/18_backtrace/Cargo.lock @@ -36,9 +36,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.44" +version = "1.0.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7bd7356a8122b6c4a24a82b278680c73357984ca2fc79a0f9fa6dea7dced7c58" +checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725" dependencies = [ "unicode-ident", ] @@ -60,9 +60,9 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.101" +version = "1.0.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e90cde112c4b9690b8cbe810cba9ddd8bc1d7472e2cae317b69e9438c1cba7d2" +checksum = "a864042229133ada95abf3b54fdc62ef5ccabe9515b64717bcb9a1919e59445d" dependencies = [ "proc-macro2", "quote", @@ -91,6 +91,6 @@ checksum = "696941a0aee7e276a165a978b37918fd5d22c55c3d6bda197813070ca9c0f21c" [[package]] name = "unicode-ident" -version = "1.0.4" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcc811dc4066ac62f84f11307873c4850cb653bfa9b1719cee2bd2204a4bc5dd" +checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3" diff --git a/19_kernel_heap/Cargo.lock b/19_kernel_heap/Cargo.lock index f8d4b6f8..eb80ffea 100644 --- a/19_kernel_heap/Cargo.lock +++ b/19_kernel_heap/Cargo.lock @@ -24,9 +24,9 @@ dependencies = [ [[package]] name = "linked_list_allocator" -version = "0.10.3" +version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e8da0e6283aace40e4e0395fe5ad7a147fac6ff47bda1f038b5044fb11683c2" +checksum = "e322f259d225fbae43a1b053b2dc6a5968a6bdf8b205f5de684dab485b95030e" [[package]] name = "mingo" @@ -43,9 +43,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.44" +version = "1.0.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7bd7356a8122b6c4a24a82b278680c73357984ca2fc79a0f9fa6dea7dced7c58" +checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725" dependencies = [ "unicode-ident", ] @@ -67,9 +67,9 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.101" +version = "1.0.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e90cde112c4b9690b8cbe810cba9ddd8bc1d7472e2cae317b69e9438c1cba7d2" +checksum = "a864042229133ada95abf3b54fdc62ef5ccabe9515b64717bcb9a1919e59445d" dependencies = [ "proc-macro2", "quote", @@ -98,6 +98,6 @@ checksum = "696941a0aee7e276a165a978b37918fd5d22c55c3d6bda197813070ca9c0f21c" [[package]] name = "unicode-ident" -version = "1.0.4" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcc811dc4066ac62f84f11307873c4850cb653bfa9b1719cee2bd2204a4bc5dd" +checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3" From 2035ae1a51b7ce1ad48aa001acff9923013154b0 Mon Sep 17 00:00:00 2001 From: Andre Richter Date: Wed, 26 Oct 2022 22:02:12 +0200 Subject: [PATCH 62/75] Add tutorial 20 --- 20_timer_callbacks/.cargo/config.toml | 2 + 20_timer_callbacks/.vscode/settings.json | 10 + 20_timer_callbacks/Cargo.lock | 103 +++ 20_timer_callbacks/Cargo.toml | 11 + 20_timer_callbacks/Makefile | 393 ++++++++++ 20_timer_callbacks/README.md | 735 ++++++++++++++++++ 20_timer_callbacks/kernel/Cargo.lock | 96 +++ 20_timer_callbacks/kernel/Cargo.toml | 72 ++ 20_timer_callbacks/kernel/build.rs | 20 + .../kernel/src/_arch/aarch64/backtrace.rs | 136 ++++ .../kernel/src/_arch/aarch64/cpu.rs | 49 ++ .../kernel/src/_arch/aarch64/cpu/boot.rs | 117 +++ .../kernel/src/_arch/aarch64/cpu/boot.s | 105 +++ .../kernel/src/_arch/aarch64/cpu/smp.rs | 30 + .../kernel/src/_arch/aarch64/exception.rs | 325 ++++++++ .../kernel/src/_arch/aarch64/exception.s | 190 +++++ .../_arch/aarch64/exception/asynchronous.rs | 141 ++++ .../kernel/src/_arch/aarch64/memory/mmu.rs | 158 ++++ .../aarch64/memory/mmu/translation_table.rs | 521 +++++++++++++ .../kernel/src/_arch/aarch64/time.rs | 193 +++++ 20_timer_callbacks/kernel/src/backtrace.rs | 114 +++ 20_timer_callbacks/kernel/src/bsp.rs | 13 + .../kernel/src/bsp/device_driver.rs | 16 + .../kernel/src/bsp/device_driver/arm.rs | 9 + .../kernel/src/bsp/device_driver/arm/gicv2.rs | 234 ++++++ .../src/bsp/device_driver/arm/gicv2/gicc.rs | 145 ++++ .../src/bsp/device_driver/arm/gicv2/gicd.rs | 201 +++++ .../kernel/src/bsp/device_driver/bcm.rs | 15 + .../src/bsp/device_driver/bcm/bcm2xxx_gpio.rs | 228 ++++++ .../bcm/bcm2xxx_interrupt_controller.rs | 175 +++++ .../bcm2xxx_interrupt_controller/local_ic.rs | 173 +++++ .../peripheral_ic.rs | 178 +++++ .../device_driver/bcm/bcm2xxx_pl011_uart.rs | 516 ++++++++++++ .../kernel/src/bsp/device_driver/common.rs | 65 ++ .../kernel/src/bsp/raspberrypi.rs | 27 + .../kernel/src/bsp/raspberrypi/cpu.rs | 14 + .../kernel/src/bsp/raspberrypi/driver.rs | 193 +++++ .../kernel/src/bsp/raspberrypi/exception.rs | 7 + .../bsp/raspberrypi/exception/asynchronous.rs | 36 + .../kernel/src/bsp/raspberrypi/kernel.ld | 134 ++++ .../kernel_virt_addr_space_size.ld | 1 + .../kernel/src/bsp/raspberrypi/memory.rs | 254 ++++++ .../kernel/src/bsp/raspberrypi/memory/mmu.rs | 197 +++++ 20_timer_callbacks/kernel/src/common.rs | 46 ++ 20_timer_callbacks/kernel/src/console.rs | 93 +++ .../kernel/src/console/buffer_console.rs | 108 +++ 20_timer_callbacks/kernel/src/cpu.rs | 21 + 20_timer_callbacks/kernel/src/cpu/boot.rs | 9 + 20_timer_callbacks/kernel/src/cpu/smp.rs | 14 + 20_timer_callbacks/kernel/src/driver.rs | 178 +++++ 20_timer_callbacks/kernel/src/exception.rs | 48 ++ .../kernel/src/exception/asynchronous.rs | 190 +++++ .../asynchronous/null_irq_manager.rs | 42 + 20_timer_callbacks/kernel/src/lib.rs | 196 +++++ 20_timer_callbacks/kernel/src/main.rs | 96 +++ 20_timer_callbacks/kernel/src/memory.rs | 198 +++++ .../kernel/src/memory/heap_alloc.rs | 147 ++++ 20_timer_callbacks/kernel/src/memory/mmu.rs | 262 +++++++ .../kernel/src/memory/mmu/mapping_record.rs | 204 +++++ .../kernel/src/memory/mmu/page_alloc.rs | 70 ++ .../src/memory/mmu/translation_table.rs | 137 ++++ .../kernel/src/memory/mmu/types.rs | 378 +++++++++ 20_timer_callbacks/kernel/src/panic_wait.rs | 88 +++ 20_timer_callbacks/kernel/src/print.rs | 112 +++ 20_timer_callbacks/kernel/src/state.rs | 92 +++ 20_timer_callbacks/kernel/src/symbols.rs | 88 +++ .../kernel/src/synchronization.rs | 159 ++++ 20_timer_callbacks/kernel/src/time.rs | 263 +++++++ .../kernel/tests/00_console_sanity.rb | 48 ++ .../kernel/tests/00_console_sanity.rs | 38 + .../kernel/tests/01_timer_sanity.rs | 51 ++ .../tests/02_exception_sync_page_fault.rs | 37 + .../tests/03_exception_restore_sanity.rb | 25 + .../tests/03_exception_restore_sanity.rs | 49 ++ .../kernel/tests/04_exception_irq_sanity.rs | 67 ++ .../kernel/tests/05_backtrace_sanity.rb | 39 + .../kernel/tests/05_backtrace_sanity.rs | 31 + .../tests/06_backtrace_invalid_frame.rb | 26 + .../tests/06_backtrace_invalid_frame.rs | 33 + .../kernel/tests/07_backtrace_invalid_link.rb | 25 + .../kernel/tests/07_backtrace_invalid_link.rs | 38 + .../kernel/tests/boot_test_string.rb | 3 + .../kernel/tests/panic_exit_success/mod.rs | 9 + .../kernel/tests/panic_wait_forever/mod.rs | 9 + 20_timer_callbacks/kernel_symbols.mk | 117 +++ 20_timer_callbacks/kernel_symbols/Cargo.lock | 14 + 20_timer_callbacks/kernel_symbols/Cargo.toml | 15 + 20_timer_callbacks/kernel_symbols/build.rs | 14 + .../kernel_symbols/kernel_symbols.ld | 15 + 20_timer_callbacks/kernel_symbols/src/main.rs | 16 + .../libraries/debug-symbol-types/Cargo.toml | 4 + .../libraries/debug-symbol-types/src/lib.rs | 45 ++ .../libraries/test-macros/Cargo.toml | 14 + .../libraries/test-macros/src/lib.rs | 29 + .../libraries/test-types/Cargo.toml | 5 + .../libraries/test-types/src/lib.rs | 16 + .../tools/kernel_symbols_tool/cmds.rb | 45 ++ .../tools/kernel_symbols_tool/kernel_elf.rb | 74 ++ .../tools/kernel_symbols_tool/main.rb | 47 ++ .../tools/translation_table_tool/arch.rb | 314 ++++++++ .../tools/translation_table_tool/bsp.rb | 54 ++ .../tools/translation_table_tool/generic.rb | 189 +++++ .../translation_table_tool/kernel_elf.rb | 96 +++ .../tools/translation_table_tool/main.rb | 46 ++ 104 files changed, 11288 insertions(+) create mode 100644 20_timer_callbacks/.cargo/config.toml create mode 100644 20_timer_callbacks/.vscode/settings.json create mode 100644 20_timer_callbacks/Cargo.lock create mode 100644 20_timer_callbacks/Cargo.toml create mode 100644 20_timer_callbacks/Makefile create mode 100644 20_timer_callbacks/README.md create mode 100644 20_timer_callbacks/kernel/Cargo.lock create mode 100644 20_timer_callbacks/kernel/Cargo.toml create mode 100644 20_timer_callbacks/kernel/build.rs create mode 100644 20_timer_callbacks/kernel/src/_arch/aarch64/backtrace.rs create mode 100644 20_timer_callbacks/kernel/src/_arch/aarch64/cpu.rs create mode 100644 20_timer_callbacks/kernel/src/_arch/aarch64/cpu/boot.rs create mode 100644 20_timer_callbacks/kernel/src/_arch/aarch64/cpu/boot.s create mode 100644 20_timer_callbacks/kernel/src/_arch/aarch64/cpu/smp.rs create mode 100644 20_timer_callbacks/kernel/src/_arch/aarch64/exception.rs create mode 100644 20_timer_callbacks/kernel/src/_arch/aarch64/exception.s create mode 100644 20_timer_callbacks/kernel/src/_arch/aarch64/exception/asynchronous.rs create mode 100644 20_timer_callbacks/kernel/src/_arch/aarch64/memory/mmu.rs create mode 100644 20_timer_callbacks/kernel/src/_arch/aarch64/memory/mmu/translation_table.rs create mode 100644 20_timer_callbacks/kernel/src/_arch/aarch64/time.rs create mode 100644 20_timer_callbacks/kernel/src/backtrace.rs create mode 100644 20_timer_callbacks/kernel/src/bsp.rs create mode 100644 20_timer_callbacks/kernel/src/bsp/device_driver.rs create mode 100644 20_timer_callbacks/kernel/src/bsp/device_driver/arm.rs create mode 100644 20_timer_callbacks/kernel/src/bsp/device_driver/arm/gicv2.rs create mode 100644 20_timer_callbacks/kernel/src/bsp/device_driver/arm/gicv2/gicc.rs create mode 100644 20_timer_callbacks/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs create mode 100644 20_timer_callbacks/kernel/src/bsp/device_driver/bcm.rs create mode 100644 20_timer_callbacks/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs create mode 100644 20_timer_callbacks/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs create mode 100644 20_timer_callbacks/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/local_ic.rs create mode 100644 20_timer_callbacks/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs create mode 100644 20_timer_callbacks/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs create mode 100644 20_timer_callbacks/kernel/src/bsp/device_driver/common.rs create mode 100644 20_timer_callbacks/kernel/src/bsp/raspberrypi.rs create mode 100644 20_timer_callbacks/kernel/src/bsp/raspberrypi/cpu.rs create mode 100644 20_timer_callbacks/kernel/src/bsp/raspberrypi/driver.rs create mode 100644 20_timer_callbacks/kernel/src/bsp/raspberrypi/exception.rs create mode 100644 20_timer_callbacks/kernel/src/bsp/raspberrypi/exception/asynchronous.rs create mode 100644 20_timer_callbacks/kernel/src/bsp/raspberrypi/kernel.ld create mode 100644 20_timer_callbacks/kernel/src/bsp/raspberrypi/kernel_virt_addr_space_size.ld create mode 100644 20_timer_callbacks/kernel/src/bsp/raspberrypi/memory.rs create mode 100644 20_timer_callbacks/kernel/src/bsp/raspberrypi/memory/mmu.rs create mode 100644 20_timer_callbacks/kernel/src/common.rs create mode 100644 20_timer_callbacks/kernel/src/console.rs create mode 100644 20_timer_callbacks/kernel/src/console/buffer_console.rs create mode 100644 20_timer_callbacks/kernel/src/cpu.rs create mode 100644 20_timer_callbacks/kernel/src/cpu/boot.rs create mode 100644 20_timer_callbacks/kernel/src/cpu/smp.rs create mode 100644 20_timer_callbacks/kernel/src/driver.rs create mode 100644 20_timer_callbacks/kernel/src/exception.rs create mode 100644 20_timer_callbacks/kernel/src/exception/asynchronous.rs create mode 100644 20_timer_callbacks/kernel/src/exception/asynchronous/null_irq_manager.rs create mode 100644 20_timer_callbacks/kernel/src/lib.rs create mode 100644 20_timer_callbacks/kernel/src/main.rs create mode 100644 20_timer_callbacks/kernel/src/memory.rs create mode 100644 20_timer_callbacks/kernel/src/memory/heap_alloc.rs create mode 100644 20_timer_callbacks/kernel/src/memory/mmu.rs create mode 100644 20_timer_callbacks/kernel/src/memory/mmu/mapping_record.rs create mode 100644 20_timer_callbacks/kernel/src/memory/mmu/page_alloc.rs create mode 100644 20_timer_callbacks/kernel/src/memory/mmu/translation_table.rs create mode 100644 20_timer_callbacks/kernel/src/memory/mmu/types.rs create mode 100644 20_timer_callbacks/kernel/src/panic_wait.rs create mode 100644 20_timer_callbacks/kernel/src/print.rs create mode 100644 20_timer_callbacks/kernel/src/state.rs create mode 100644 20_timer_callbacks/kernel/src/symbols.rs create mode 100644 20_timer_callbacks/kernel/src/synchronization.rs create mode 100644 20_timer_callbacks/kernel/src/time.rs create mode 100644 20_timer_callbacks/kernel/tests/00_console_sanity.rb create mode 100644 20_timer_callbacks/kernel/tests/00_console_sanity.rs create mode 100644 20_timer_callbacks/kernel/tests/01_timer_sanity.rs create mode 100644 20_timer_callbacks/kernel/tests/02_exception_sync_page_fault.rs create mode 100644 20_timer_callbacks/kernel/tests/03_exception_restore_sanity.rb create mode 100644 20_timer_callbacks/kernel/tests/03_exception_restore_sanity.rs create mode 100644 20_timer_callbacks/kernel/tests/04_exception_irq_sanity.rs create mode 100644 20_timer_callbacks/kernel/tests/05_backtrace_sanity.rb create mode 100644 20_timer_callbacks/kernel/tests/05_backtrace_sanity.rs create mode 100644 20_timer_callbacks/kernel/tests/06_backtrace_invalid_frame.rb create mode 100644 20_timer_callbacks/kernel/tests/06_backtrace_invalid_frame.rs create mode 100644 20_timer_callbacks/kernel/tests/07_backtrace_invalid_link.rb create mode 100644 20_timer_callbacks/kernel/tests/07_backtrace_invalid_link.rs create mode 100644 20_timer_callbacks/kernel/tests/boot_test_string.rb create mode 100644 20_timer_callbacks/kernel/tests/panic_exit_success/mod.rs create mode 100644 20_timer_callbacks/kernel/tests/panic_wait_forever/mod.rs create mode 100644 20_timer_callbacks/kernel_symbols.mk create mode 100644 20_timer_callbacks/kernel_symbols/Cargo.lock create mode 100644 20_timer_callbacks/kernel_symbols/Cargo.toml create mode 100644 20_timer_callbacks/kernel_symbols/build.rs create mode 100644 20_timer_callbacks/kernel_symbols/kernel_symbols.ld create mode 100644 20_timer_callbacks/kernel_symbols/src/main.rs create mode 100644 20_timer_callbacks/libraries/debug-symbol-types/Cargo.toml create mode 100644 20_timer_callbacks/libraries/debug-symbol-types/src/lib.rs create mode 100644 20_timer_callbacks/libraries/test-macros/Cargo.toml create mode 100644 20_timer_callbacks/libraries/test-macros/src/lib.rs create mode 100644 20_timer_callbacks/libraries/test-types/Cargo.toml create mode 100644 20_timer_callbacks/libraries/test-types/src/lib.rs create mode 100644 20_timer_callbacks/tools/kernel_symbols_tool/cmds.rb create mode 100644 20_timer_callbacks/tools/kernel_symbols_tool/kernel_elf.rb create mode 100755 20_timer_callbacks/tools/kernel_symbols_tool/main.rb create mode 100644 20_timer_callbacks/tools/translation_table_tool/arch.rb create mode 100644 20_timer_callbacks/tools/translation_table_tool/bsp.rb create mode 100644 20_timer_callbacks/tools/translation_table_tool/generic.rb create mode 100644 20_timer_callbacks/tools/translation_table_tool/kernel_elf.rb create mode 100755 20_timer_callbacks/tools/translation_table_tool/main.rb diff --git a/20_timer_callbacks/.cargo/config.toml b/20_timer_callbacks/.cargo/config.toml new file mode 100644 index 00000000..e3476485 --- /dev/null +++ b/20_timer_callbacks/.cargo/config.toml @@ -0,0 +1,2 @@ +[target.'cfg(target_os = "none")'] +runner = "target/kernel_test_runner.sh" diff --git a/20_timer_callbacks/.vscode/settings.json b/20_timer_callbacks/.vscode/settings.json new file mode 100644 index 00000000..292bf2a9 --- /dev/null +++ b/20_timer_callbacks/.vscode/settings.json @@ -0,0 +1,10 @@ +{ + "editor.formatOnSave": true, + "editor.rulers": [100], + "rust-analyzer.cargo.target": "aarch64-unknown-none-softfloat", + "rust-analyzer.cargo.features": ["bsp_rpi3"], + "rust-analyzer.checkOnSave.allTargets": false, + "rust-analyzer.checkOnSave.extraArgs": ["--lib", "--bins"], + "rust-analyzer.lens.debug": false, + "rust-analyzer.lens.run": false +} diff --git a/20_timer_callbacks/Cargo.lock b/20_timer_callbacks/Cargo.lock new file mode 100644 index 00000000..8f9eae58 --- /dev/null +++ b/20_timer_callbacks/Cargo.lock @@ -0,0 +1,103 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "cortex-a" +version = "8.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cd4524931a4e0ec50ae91f0d55f571f31ffe11dd9ce2f9905b8343c018c25bb" +dependencies = [ + "tock-registers", +] + +[[package]] +name = "debug-symbol-types" +version = "0.1.0" + +[[package]] +name = "kernel_symbols" +version = "0.1.0" +dependencies = [ + "debug-symbol-types", +] + +[[package]] +name = "linked_list_allocator" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e322f259d225fbae43a1b053b2dc6a5968a6bdf8b205f5de684dab485b95030e" + +[[package]] +name = "mingo" +version = "0.20.0" +dependencies = [ + "cortex-a", + "debug-symbol-types", + "linked_list_allocator", + "qemu-exit", + "test-macros", + "test-types", + "tock-registers", +] + +[[package]] +name = "proc-macro2" +version = "1.0.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "qemu-exit" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ff023245bfcc73fb890e1f8d5383825b3131cc920020a5c487d6f113dfc428a" + +[[package]] +name = "quote" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "syn" +version = "1.0.103" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a864042229133ada95abf3b54fdc62ef5ccabe9515b64717bcb9a1919e59445d" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "test-macros" +version = "0.1.0" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "test-types", +] + +[[package]] +name = "test-types" +version = "0.1.0" + +[[package]] +name = "tock-registers" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "696941a0aee7e276a165a978b37918fd5d22c55c3d6bda197813070ca9c0f21c" + +[[package]] +name = "unicode-ident" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3" diff --git a/20_timer_callbacks/Cargo.toml b/20_timer_callbacks/Cargo.toml new file mode 100644 index 00000000..38eeb116 --- /dev/null +++ b/20_timer_callbacks/Cargo.toml @@ -0,0 +1,11 @@ +[workspace] + +members = [ + "libraries/*", + "kernel", + "kernel_symbols" +] + +[profile.release] +lto = true +debug = true diff --git a/20_timer_callbacks/Makefile b/20_timer_callbacks/Makefile new file mode 100644 index 00000000..43f5ad1f --- /dev/null +++ b/20_timer_callbacks/Makefile @@ -0,0 +1,393 @@ +## SPDX-License-Identifier: MIT OR Apache-2.0 +## +## Copyright (c) 2018-2022 Andre Richter + +include ../common/docker.mk +include ../common/format.mk +include ../common/operating_system.mk + +##-------------------------------------------------------------------------------------------------- +## Optional, user-provided configuration values +##-------------------------------------------------------------------------------------------------- + +# Default to the RPi3. +BSP ?= rpi3 + +# Default to a serial device name that is common in Linux. +DEV_SERIAL ?= /dev/ttyUSB0 + +# Optional debug prints. +ifdef DEBUG_PRINTS + FEATURES = --features debug_prints +endif + +# Optional integration test name. +ifdef TEST + TEST_ARG = --test $(TEST) +else + TEST_ARG = --test '*' +endif + + + +##-------------------------------------------------------------------------------------------------- +## BSP-specific configuration values +##-------------------------------------------------------------------------------------------------- +QEMU_MISSING_STRING = "This board is not yet supported for QEMU." + +ifeq ($(BSP),rpi3) + TARGET = aarch64-unknown-none-softfloat + KERNEL_BIN = kernel8.img + QEMU_BINARY = qemu-system-aarch64 + QEMU_MACHINE_TYPE = raspi3 + QEMU_RELEASE_ARGS = -serial stdio -display none + QEMU_TEST_ARGS = $(QEMU_RELEASE_ARGS) -semihosting + OBJDUMP_BINARY = aarch64-none-elf-objdump + NM_BINARY = aarch64-none-elf-nm + READELF_BINARY = aarch64-none-elf-readelf + OPENOCD_ARG = -f /openocd/tcl/interface/ftdi/olimex-arm-usb-tiny-h.cfg -f /openocd/rpi3.cfg + JTAG_BOOT_IMAGE = ../X1_JTAG_boot/jtag_boot_rpi3.img + LD_SCRIPT_PATH = $(shell pwd)/kernel/src/bsp/raspberrypi + RUSTC_MISC_ARGS = -C target-cpu=cortex-a53 -C force-frame-pointers +else ifeq ($(BSP),rpi4) + TARGET = aarch64-unknown-none-softfloat + KERNEL_BIN = kernel8.img + QEMU_BINARY = qemu-system-aarch64 + QEMU_MACHINE_TYPE = + QEMU_RELEASE_ARGS = -serial stdio -display none + QEMU_TEST_ARGS = $(QEMU_RELEASE_ARGS) -semihosting + OBJDUMP_BINARY = aarch64-none-elf-objdump + NM_BINARY = aarch64-none-elf-nm + READELF_BINARY = aarch64-none-elf-readelf + OPENOCD_ARG = -f /openocd/tcl/interface/ftdi/olimex-arm-usb-tiny-h.cfg -f /openocd/rpi4.cfg + JTAG_BOOT_IMAGE = ../X1_JTAG_boot/jtag_boot_rpi4.img + LD_SCRIPT_PATH = $(shell pwd)/kernel/src/bsp/raspberrypi + RUSTC_MISC_ARGS = -C target-cpu=cortex-a72 -C force-frame-pointers +endif + +# Export for build.rs. +export LD_SCRIPT_PATH + + + +##-------------------------------------------------------------------------------------------------- +## Targets and Prerequisites +##-------------------------------------------------------------------------------------------------- +KERNEL_MANIFEST = kernel/Cargo.toml +KERNEL_LINKER_SCRIPT = kernel.ld +LAST_BUILD_CONFIG = target/$(BSP)_$(DEBUG_PRINTS).build_config + +KERNEL_ELF_RAW = target/$(TARGET)/release/kernel +# This parses cargo's dep-info file. +# https://doc.rust-lang.org/cargo/guide/build-cache.html#dep-info-files +KERNEL_ELF_RAW_DEPS = $(filter-out %: ,$(file < $(KERNEL_ELF_RAW).d)) $(KERNEL_MANIFEST) $(LAST_BUILD_CONFIG) + +##------------------------------------------------------------------------------ +## Translation tables +##------------------------------------------------------------------------------ +TT_TOOL_PATH = tools/translation_table_tool + +KERNEL_ELF_TTABLES = target/$(TARGET)/release/kernel+ttables +KERNEL_ELF_TTABLES_DEPS = $(KERNEL_ELF_RAW) $(wildcard $(TT_TOOL_PATH)/*) + +##------------------------------------------------------------------------------ +## Kernel symbols +##------------------------------------------------------------------------------ +export KERNEL_SYMBOLS_TOOL_PATH = tools/kernel_symbols_tool + +KERNEL_ELF_TTABLES_SYMS = target/$(TARGET)/release/kernel+ttables+symbols + +# Unlike with KERNEL_ELF_RAW, we are not relying on dep-info here. One of the reasons being that the +# name of the generated symbols file varies between runs, which can cause confusion. +KERNEL_ELF_TTABLES_SYMS_DEPS = $(KERNEL_ELF_TTABLES) \ + $(wildcard kernel_symbols/*) \ + $(wildcard $(KERNEL_SYMBOLS_TOOL_PATH)/*) + +export TARGET +export KERNEL_SYMBOLS_INPUT_ELF = $(KERNEL_ELF_TTABLES) +export KERNEL_SYMBOLS_OUTPUT_ELF = $(KERNEL_ELF_TTABLES_SYMS) + +KERNEL_ELF = $(KERNEL_ELF_TTABLES_SYMS) + + + +##-------------------------------------------------------------------------------------------------- +## Command building blocks +##-------------------------------------------------------------------------------------------------- +RUSTFLAGS = $(RUSTC_MISC_ARGS) \ + -C link-arg=--library-path=$(LD_SCRIPT_PATH) \ + -C link-arg=--script=$(KERNEL_LINKER_SCRIPT) + +RUSTFLAGS_PEDANTIC = $(RUSTFLAGS) \ + -D warnings \ + -D missing_docs + +FEATURES += --features bsp_$(BSP) +COMPILER_ARGS = --target=$(TARGET) \ + $(FEATURES) \ + --release + +# build-std can be skipped for helper commands that do not rely on correct stack frames and other +# custom compiler options. This results in a huge speedup. +RUSTC_CMD = cargo rustc $(COMPILER_ARGS) -Z build-std=core,alloc --manifest-path $(KERNEL_MANIFEST) +DOC_CMD = cargo doc $(COMPILER_ARGS) +CLIPPY_CMD = cargo clippy $(COMPILER_ARGS) +TEST_CMD = cargo test $(COMPILER_ARGS) -Z build-std=core,alloc --manifest-path $(KERNEL_MANIFEST) +OBJCOPY_CMD = rust-objcopy \ + --strip-all \ + -O binary + +EXEC_QEMU = $(QEMU_BINARY) -M $(QEMU_MACHINE_TYPE) +EXEC_TT_TOOL = ruby $(TT_TOOL_PATH)/main.rb +EXEC_TEST_DISPATCH = ruby ../common/tests/dispatch.rb +EXEC_MINIPUSH = ruby ../common/serial/minipush.rb + +##------------------------------------------------------------------------------ +## Dockerization +##------------------------------------------------------------------------------ +DOCKER_CMD = docker run -t --rm -v $(shell pwd):/work/tutorial -w /work/tutorial +DOCKER_CMD_INTERACT = $(DOCKER_CMD) -i +DOCKER_ARG_DIR_COMMON = -v $(shell pwd)/../common:/work/common +DOCKER_ARG_DIR_JTAG = -v $(shell pwd)/../X1_JTAG_boot:/work/X1_JTAG_boot +DOCKER_ARG_DEV = --privileged -v /dev:/dev +DOCKER_ARG_NET = --network host + +# DOCKER_IMAGE defined in include file (see top of this file). +DOCKER_QEMU = $(DOCKER_CMD_INTERACT) $(DOCKER_IMAGE) +DOCKER_TOOLS = $(DOCKER_CMD) $(DOCKER_IMAGE) +DOCKER_TEST = $(DOCKER_CMD) $(DOCKER_ARG_DIR_COMMON) $(DOCKER_IMAGE) +DOCKER_GDB = $(DOCKER_CMD_INTERACT) $(DOCKER_ARG_NET) $(DOCKER_IMAGE) + +# Dockerize commands, which require USB device passthrough, only on Linux. +ifeq ($(shell uname -s),Linux) + DOCKER_CMD_DEV = $(DOCKER_CMD_INTERACT) $(DOCKER_ARG_DEV) + + DOCKER_CHAINBOOT = $(DOCKER_CMD_DEV) $(DOCKER_ARG_DIR_COMMON) $(DOCKER_IMAGE) + DOCKER_JTAGBOOT = $(DOCKER_CMD_DEV) $(DOCKER_ARG_DIR_COMMON) $(DOCKER_ARG_DIR_JTAG) $(DOCKER_IMAGE) + DOCKER_OPENOCD = $(DOCKER_CMD_DEV) $(DOCKER_ARG_NET) $(DOCKER_IMAGE) +else + DOCKER_OPENOCD = echo "Not yet supported on non-Linux systems."; \# +endif + + + +##-------------------------------------------------------------------------------------------------- +## Targets +##-------------------------------------------------------------------------------------------------- +.PHONY: all doc qemu chainboot clippy clean readelf objdump nm check + +all: $(KERNEL_BIN) + +##------------------------------------------------------------------------------ +## Save the configuration as a file, so make understands if it changed. +##------------------------------------------------------------------------------ +$(LAST_BUILD_CONFIG): + @rm -f target/*.build_config + @mkdir -p target + @touch $(LAST_BUILD_CONFIG) + +##------------------------------------------------------------------------------ +## Compile the kernel ELF +##------------------------------------------------------------------------------ +$(KERNEL_ELF_RAW): $(KERNEL_ELF_RAW_DEPS) + $(call color_header, "Compiling kernel ELF - $(BSP)") + @RUSTFLAGS="$(RUSTFLAGS_PEDANTIC)" $(RUSTC_CMD) + +##------------------------------------------------------------------------------ +## Precompute the kernel translation tables and patch them into the kernel ELF +##------------------------------------------------------------------------------ +$(KERNEL_ELF_TTABLES): $(KERNEL_ELF_TTABLES_DEPS) + $(call color_header, "Precomputing kernel translation tables and patching kernel ELF") + @cp $(KERNEL_ELF_RAW) $(KERNEL_ELF_TTABLES) + @$(DOCKER_TOOLS) $(EXEC_TT_TOOL) $(BSP) $(KERNEL_ELF_TTABLES) + +##------------------------------------------------------------------------------ +## Generate kernel symbols and patch them into the kernel ELF +##------------------------------------------------------------------------------ +$(KERNEL_ELF_TTABLES_SYMS): $(KERNEL_ELF_TTABLES_SYMS_DEPS) + $(call color_header, "Generating kernel symbols and patching kernel ELF") + @$(MAKE) --no-print-directory -f kernel_symbols.mk + +##------------------------------------------------------------------------------ +## Generate the stripped kernel binary +##------------------------------------------------------------------------------ +$(KERNEL_BIN): $(KERNEL_ELF_TTABLES_SYMS) + $(call color_header, "Generating stripped binary") + @$(OBJCOPY_CMD) $(KERNEL_ELF_TTABLES_SYMS) $(KERNEL_BIN) + $(call color_progress_prefix, "Name") + @echo $(KERNEL_BIN) + $(call color_progress_prefix, "Size") + $(call disk_usage_KiB, $(KERNEL_BIN)) + +##------------------------------------------------------------------------------ +## Generate the documentation +##------------------------------------------------------------------------------ +doc: clean + $(call color_header, "Generating docs") + @$(DOC_CMD) --document-private-items --open + +##------------------------------------------------------------------------------ +## Run the kernel in QEMU +##------------------------------------------------------------------------------ +ifeq ($(QEMU_MACHINE_TYPE),) # QEMU is not supported for the board. + +qemu: + $(call color_header, "$(QEMU_MISSING_STRING)") + +else # QEMU is supported. + +qemu: $(KERNEL_BIN) + $(call color_header, "Launching QEMU") + @$(DOCKER_QEMU) $(EXEC_QEMU) $(QEMU_RELEASE_ARGS) -kernel $(KERNEL_BIN) + +endif + +##------------------------------------------------------------------------------ +## Push the kernel to the real HW target +##------------------------------------------------------------------------------ +chainboot: $(KERNEL_BIN) + @$(DOCKER_CHAINBOOT) $(EXEC_MINIPUSH) $(DEV_SERIAL) $(KERNEL_BIN) + +##------------------------------------------------------------------------------ +## Run clippy +##------------------------------------------------------------------------------ +clippy: + @RUSTFLAGS="$(RUSTFLAGS_PEDANTIC)" $(CLIPPY_CMD) + @RUSTFLAGS="$(RUSTFLAGS_PEDANTIC)" $(CLIPPY_CMD) --features test_build --tests \ + --manifest-path $(KERNEL_MANIFEST) + +##------------------------------------------------------------------------------ +## Clean +##------------------------------------------------------------------------------ +clean: + rm -rf target $(KERNEL_BIN) + +##------------------------------------------------------------------------------ +## Run readelf +##------------------------------------------------------------------------------ +readelf: $(KERNEL_ELF) + $(call color_header, "Launching readelf") + @$(DOCKER_TOOLS) $(READELF_BINARY) --headers $(KERNEL_ELF) + +##------------------------------------------------------------------------------ +## Run objdump +##------------------------------------------------------------------------------ +objdump: $(KERNEL_ELF) + $(call color_header, "Launching objdump") + @$(DOCKER_TOOLS) $(OBJDUMP_BINARY) --disassemble --demangle \ + --section .text \ + --section .rodata \ + $(KERNEL_ELF) | rustfilt + +##------------------------------------------------------------------------------ +## Run nm +##------------------------------------------------------------------------------ +nm: $(KERNEL_ELF) + $(call color_header, "Launching nm") + @$(DOCKER_TOOLS) $(NM_BINARY) --demangle --print-size $(KERNEL_ELF) | sort | rustfilt + + + +##-------------------------------------------------------------------------------------------------- +## Debugging targets +##-------------------------------------------------------------------------------------------------- +.PHONY: jtagboot openocd gdb gdb-opt0 + +##------------------------------------------------------------------------------ +## Push the JTAG boot image to the real HW target +##------------------------------------------------------------------------------ +jtagboot: + @$(DOCKER_JTAGBOOT) $(EXEC_MINIPUSH) $(DEV_SERIAL) $(JTAG_BOOT_IMAGE) + +##------------------------------------------------------------------------------ +## Start OpenOCD session +##------------------------------------------------------------------------------ +openocd: + $(call color_header, "Launching OpenOCD") + @$(DOCKER_OPENOCD) openocd $(OPENOCD_ARG) + +##------------------------------------------------------------------------------ +## Start GDB session +##------------------------------------------------------------------------------ +gdb-opt0: RUSTC_MISC_ARGS += -C opt-level=0 +gdb gdb-opt0: $(KERNEL_ELF) + $(call color_header, "Launching GDB") + @$(DOCKER_GDB) gdb-multiarch -q $(KERNEL_ELF) + + + +##-------------------------------------------------------------------------------------------------- +## Testing targets +##-------------------------------------------------------------------------------------------------- +.PHONY: test test_boot test_unit test_integration + +test_unit test_integration: FEATURES += --features test_build + +ifeq ($(QEMU_MACHINE_TYPE),) # QEMU is not supported for the board. + +test_boot test_unit test_integration test: + $(call color_header, "$(QEMU_MISSING_STRING)") + +else # QEMU is supported. + +##------------------------------------------------------------------------------ +## Run boot test +##------------------------------------------------------------------------------ +test_boot: $(KERNEL_BIN) + $(call color_header, "Boot test - $(BSP)") + @$(DOCKER_TEST) $(EXEC_TEST_DISPATCH) $(EXEC_QEMU) $(QEMU_RELEASE_ARGS) -kernel $(KERNEL_BIN) + +##------------------------------------------------------------------------------ +## Helpers for unit and integration test targets +##------------------------------------------------------------------------------ +define KERNEL_TEST_RUNNER +#!/usr/bin/env bash + + # The cargo test runner seems to change into the crate under test's directory. Therefore, ensure + # this script executes from the root. + cd $(shell pwd) + + TEST_ELF=$$(echo $$1 | sed -e 's/.*target/target/g') + TEST_ELF_SYMS="$${TEST_ELF}_syms" + TEST_BINARY=$$(echo $$1.img | sed -e 's/.*target/target/g') + + $(DOCKER_TOOLS) $(EXEC_TT_TOOL) $(BSP) $$TEST_ELF > /dev/null + + # This overrides the two ENV variables. The other ENV variables that are required as input for + # the .mk file are set already because they are exported by this Makefile and this script is + # started by the same. + KERNEL_SYMBOLS_INPUT_ELF=$$TEST_ELF \ + KERNEL_SYMBOLS_OUTPUT_ELF=$$TEST_ELF_SYMS \ + $(MAKE) --no-print-directory -f kernel_symbols.mk > /dev/null 2>&1 + + $(OBJCOPY_CMD) $$TEST_ELF_SYMS $$TEST_BINARY + $(DOCKER_TEST) $(EXEC_TEST_DISPATCH) $(EXEC_QEMU) $(QEMU_TEST_ARGS) -kernel $$TEST_BINARY +endef + +export KERNEL_TEST_RUNNER + +define test_prepare + @mkdir -p target + @echo "$$KERNEL_TEST_RUNNER" > target/kernel_test_runner.sh + @chmod +x target/kernel_test_runner.sh +endef + +##------------------------------------------------------------------------------ +## Run unit test(s) +##------------------------------------------------------------------------------ +test_unit: + $(call color_header, "Compiling unit test(s) - $(BSP)") + $(call test_prepare) + @RUSTFLAGS="$(RUSTFLAGS_PEDANTIC)" $(TEST_CMD) --lib + +##------------------------------------------------------------------------------ +## Run integration test(s) +##------------------------------------------------------------------------------ +test_integration: + $(call color_header, "Compiling integration test(s) - $(BSP)") + $(call test_prepare) + @RUSTFLAGS="$(RUSTFLAGS_PEDANTIC)" $(TEST_CMD) $(TEST_ARG) + +test: test_boot test_unit test_integration + +endif diff --git a/20_timer_callbacks/README.md b/20_timer_callbacks/README.md new file mode 100644 index 00000000..3647fb38 --- /dev/null +++ b/20_timer_callbacks/README.md @@ -0,0 +1,735 @@ +# Tutorial 20 - Timer Callbacks + +## tl;dr + +- The timer subsystem is extended so that it can be used to execute timeout callbacks in IRQ + context. + +## Note + +This chapter's code will be tightly coupled to follow-up tutorials which are yet to be developed. It +is therefore expected that this chapter's code is subject to change depending upon findings that are +yet to be made. + +Therefore, content for this README will be provided sometime later when all the pieces fit together. + +## Diff to previous +```diff + +diff -uNr 19_kernel_heap/kernel/Cargo.toml 20_timer_callbacks/kernel/Cargo.toml +--- 19_kernel_heap/kernel/Cargo.toml ++++ 20_timer_callbacks/kernel/Cargo.toml +@@ -1,6 +1,6 @@ + [package] + name = "mingo" +-version = "0.19.0" ++version = "0.20.0" + authors = ["Andre Richter "] + edition = "2021" + + +diff -uNr 19_kernel_heap/kernel/src/_arch/aarch64/time.rs 20_timer_callbacks/kernel/src/_arch/aarch64/time.rs +--- 19_kernel_heap/kernel/src/_arch/aarch64/time.rs ++++ 20_timer_callbacks/kernel/src/_arch/aarch64/time.rs +@@ -11,14 +11,17 @@ + //! + //! crate::time::arch_time + +-use crate::warn; ++use crate::{ ++ bsp::{self, exception}, ++ warn, ++}; + use core::{ + num::{NonZeroU128, NonZeroU32, NonZeroU64}, + ops::{Add, Div}, + time::Duration, + }; + use cortex_a::{asm::barrier, registers::*}; +-use tock_registers::interfaces::Readable; ++use tock_registers::interfaces::{ReadWriteable, Readable, Writeable}; + + //-------------------------------------------------------------------------------------------------- + // Private Definitions +@@ -160,3 +163,31 @@ + // Read CNTPCT_EL0 directly to avoid the ISB that is part of [`read_cntpct`]. + while GenericTimerCounterValue(CNTPCT_EL0.get()) < counter_value_target {} + } ++ ++/// The associated IRQ number. ++pub const fn timeout_irq() -> exception::asynchronous::IRQNumber { ++ bsp::exception::asynchronous::irq_map::ARM_NS_PHYISCAL_TIMER ++} ++ ++/// Program a timer IRQ to be fired after `delay` has passed. ++pub fn set_timeout_irq(due_time: Duration) { ++ let counter_value_target: GenericTimerCounterValue = match due_time.try_into() { ++ Err(msg) => { ++ warn!("set_timeout: {}. Skipping", msg); ++ return; ++ } ++ Ok(val) => val, ++ }; ++ ++ // Set the compare value register. ++ CNTP_CVAL_EL0.set(counter_value_target.0); ++ ++ // Kick off the timer. ++ CNTP_CTL_EL0.modify(CNTP_CTL_EL0::ENABLE::SET + CNTP_CTL_EL0::IMASK::CLEAR); ++} ++ ++/// Conclude a pending timeout IRQ. ++pub fn conclude_timeout_irq() { ++ // Disable counting. De-asserts the IRQ. ++ CNTP_CTL_EL0.modify(CNTP_CTL_EL0::ENABLE::CLEAR); ++} + +diff -uNr 19_kernel_heap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/local_ic.rs 20_timer_callbacks/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/local_ic.rs +--- 19_kernel_heap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/local_ic.rs ++++ 20_timer_callbacks/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/local_ic.rs +@@ -0,0 +1,173 @@ ++// SPDX-License-Identifier: MIT OR Apache-2.0 ++// ++// Copyright (c) 2022 Andre Richter ++ ++//! Local Interrupt Controller Driver. ++//! ++//! # Resources ++//! ++//! - ++ ++use super::{LocalIRQ, PendingIRQs}; ++use crate::{ ++ bsp::device_driver::common::MMIODerefWrapper, ++ exception, ++ memory::{Address, Virtual}, ++ synchronization, ++ synchronization::{IRQSafeNullLock, InitStateLock}, ++}; ++use alloc::vec::Vec; ++use tock_registers::{ ++ interfaces::{Readable, Writeable}, ++ register_structs, ++ registers::{ReadOnly, WriteOnly}, ++}; ++ ++//-------------------------------------------------------------------------------------------------- ++// Private Definitions ++//-------------------------------------------------------------------------------------------------- ++ ++register_structs! { ++ #[allow(non_snake_case)] ++ WORegisterBlock { ++ (0x00 => _reserved1), ++ (0x40 => CORE0_TIMER_INTERRUPT_CONTROL: WriteOnly), ++ (0x44 => @END), ++ } ++} ++ ++register_structs! { ++ #[allow(non_snake_case)] ++ RORegisterBlock { ++ (0x00 => _reserved1), ++ (0x60 => CORE0_INTERRUPT_SOURCE: ReadOnly), ++ (0x64 => @END), ++ } ++} ++ ++/// Abstraction for the WriteOnly parts of the associated MMIO registers. ++type WriteOnlyRegisters = MMIODerefWrapper; ++ ++/// Abstraction for the ReadOnly parts of the associated MMIO registers. ++type ReadOnlyRegisters = MMIODerefWrapper; ++ ++type HandlerTable = Vec>>; ++ ++//-------------------------------------------------------------------------------------------------- ++// Public Definitions ++//-------------------------------------------------------------------------------------------------- ++ ++/// Representation of the peripheral interrupt controller. ++pub struct LocalIC { ++ /// Access to write registers is guarded with a lock. ++ wo_registers: IRQSafeNullLock, ++ ++ /// Register read access is unguarded. ++ ro_registers: ReadOnlyRegisters, ++ ++ /// Stores registered IRQ handlers. Writable only during kernel init. RO afterwards. ++ handler_table: InitStateLock, ++} ++ ++//-------------------------------------------------------------------------------------------------- ++// Public Code ++//-------------------------------------------------------------------------------------------------- ++ ++impl LocalIC { ++ // See datasheet. ++ const PERIPH_IRQ_MASK: u32 = (1 << 8); ++ ++ /// Create an instance. ++ /// ++ /// # Safety ++ /// ++ /// - The user must ensure to provide a correct MMIO start address. ++ pub const unsafe fn new(mmio_start_addr: Address) -> Self { ++ Self { ++ wo_registers: IRQSafeNullLock::new(WriteOnlyRegisters::new(mmio_start_addr)), ++ ro_registers: ReadOnlyRegisters::new(mmio_start_addr), ++ handler_table: InitStateLock::new(Vec::new()), ++ } ++ } ++ ++ /// Called by the kernel to bring up the device. ++ pub fn init(&self) { ++ self.handler_table ++ .write(|table| table.resize(LocalIRQ::MAX_INCLUSIVE + 1, None)); ++ } ++ ++ /// Query the list of pending IRQs. ++ fn pending_irqs(&self) -> PendingIRQs { ++ // Ignore the indicator bit for a peripheral IRQ. ++ PendingIRQs::new( ++ (self.ro_registers.CORE0_INTERRUPT_SOURCE.get() & !Self::PERIPH_IRQ_MASK).into(), ++ ) ++ } ++} ++ ++//------------------------------------------------------------------------------ ++// OS Interface Code ++//------------------------------------------------------------------------------ ++use synchronization::interface::{Mutex, ReadWriteEx}; ++ ++impl exception::asynchronous::interface::IRQManager for LocalIC { ++ type IRQNumberType = LocalIRQ; ++ ++ fn register_handler( ++ &self, ++ irq_handler_descriptor: exception::asynchronous::IRQHandlerDescriptor, ++ ) -> Result<(), &'static str> { ++ self.handler_table.write(|table| { ++ let irq_number = irq_handler_descriptor.number().get(); ++ ++ if table[irq_number].is_some() { ++ return Err("IRQ handler already registered"); ++ } ++ ++ table[irq_number] = Some(irq_handler_descriptor); ++ ++ Ok(()) ++ }) ++ } ++ ++ fn enable(&self, irq: &Self::IRQNumberType) { ++ self.wo_registers.lock(|regs| { ++ let enable_bit: u32 = 1 << (irq.get()); ++ ++ // Writing a 1 to a bit will set the corresponding IRQ enable bit. All other IRQ enable ++ // bits are unaffected. So we don't need read and OR'ing here. ++ regs.CORE0_TIMER_INTERRUPT_CONTROL.set(enable_bit); ++ }); ++ } ++ ++ fn handle_pending_irqs<'irq_context>( ++ &'irq_context self, ++ _ic: &exception::asynchronous::IRQContext<'irq_context>, ++ ) { ++ self.handler_table.read(|table| { ++ for irq_number in self.pending_irqs() { ++ match table[irq_number] { ++ None => panic!("No handler registered for IRQ {}", irq_number), ++ Some(descriptor) => { ++ // Call the IRQ handler. Panics on failure. ++ descriptor.handler().handle().expect("Error handling IRQ"); ++ } ++ } ++ } ++ }) ++ } ++ ++ fn print_handler(&self) { ++ use crate::info; ++ ++ info!(" Local handler:"); ++ ++ self.handler_table.read(|table| { ++ for (i, opt) in table.iter().enumerate() { ++ if let Some(handler) = opt { ++ info!(" {: >3}. {}", i, handler.name()); ++ } ++ } ++ }); ++ } ++} + +diff -uNr 19_kernel_heap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs 20_timer_callbacks/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs +--- 19_kernel_heap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs ++++ 20_timer_callbacks/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs +@@ -4,6 +4,7 @@ + + //! Interrupt Controller Driver. + ++mod local_ic; + mod peripheral_ic; + + use crate::{ +@@ -40,6 +41,7 @@ + + /// Representation of the Interrupt Controller. + pub struct InterruptController { ++ local: local_ic::LocalIC, + periph: peripheral_ic::PeripheralIC, + } + +@@ -81,7 +83,7 @@ + } + + impl InterruptController { +- // Restrict to 3 for now. This makes future code for local_ic.rs more straight forward. ++ // Restrict to 3 for now. This makes the code for local_ic.rs more straight forward. + const MAX_LOCAL_IRQ_NUMBER: usize = 3; + const MAX_PERIPHERAL_IRQ_NUMBER: usize = 63; + +@@ -92,8 +94,12 @@ + /// # Safety + /// + /// - The user must ensure to provide a correct MMIO start address. +- pub const unsafe fn new(periph_mmio_start_addr: Address) -> Self { ++ pub const unsafe fn new( ++ local_mmio_start_addr: Address, ++ periph_mmio_start_addr: Address, ++ ) -> Self { + Self { ++ local: local_ic::LocalIC::new(local_mmio_start_addr), + periph: peripheral_ic::PeripheralIC::new(periph_mmio_start_addr), + } + } +@@ -111,6 +117,7 @@ + } + + unsafe fn init(&self) -> Result<(), &'static str> { ++ self.local.init(); + self.periph.init(); + + Ok(()) +@@ -125,7 +132,15 @@ + irq_handler_descriptor: exception::asynchronous::IRQHandlerDescriptor, + ) -> Result<(), &'static str> { + match irq_handler_descriptor.number() { +- IRQNumber::Local(_) => unimplemented!("Local IRQ controller not implemented."), ++ IRQNumber::Local(lirq) => { ++ let local_descriptor = IRQHandlerDescriptor::new( ++ lirq, ++ irq_handler_descriptor.name(), ++ irq_handler_descriptor.handler(), ++ ); ++ ++ self.local.register_handler(local_descriptor) ++ } + IRQNumber::Peripheral(pirq) => { + let periph_descriptor = IRQHandlerDescriptor::new( + pirq, +@@ -140,7 +155,7 @@ + + fn enable(&self, irq: &Self::IRQNumberType) { + match irq { +- IRQNumber::Local(_) => unimplemented!("Local IRQ controller not implemented."), ++ IRQNumber::Local(lirq) => self.local.enable(lirq), + IRQNumber::Peripheral(pirq) => self.periph.enable(pirq), + } + } +@@ -149,11 +164,12 @@ + &'irq_context self, + ic: &exception::asynchronous::IRQContext<'irq_context>, + ) { +- // It can only be a peripheral IRQ pending because enable() does not support local IRQs yet. ++ self.local.handle_pending_irqs(ic); + self.periph.handle_pending_irqs(ic) + } + + fn print_handler(&self) { ++ self.local.print_handler(); + self.periph.print_handler(); + } + } + +diff -uNr 19_kernel_heap/kernel/src/bsp/raspberrypi/driver.rs 20_timer_callbacks/kernel/src/bsp/raspberrypi/driver.rs +--- 19_kernel_heap/kernel/src/bsp/raspberrypi/driver.rs ++++ 20_timer_callbacks/kernel/src/bsp/raspberrypi/driver.rs +@@ -73,6 +73,12 @@ + /// This must be called only after successful init of the memory subsystem. + #[cfg(feature = "bsp_rpi3")] + unsafe fn instantiate_interrupt_controller() -> Result<(), &'static str> { ++ let local_mmio_descriptor = MMIODescriptor::new(mmio::LOCAL_IC_START, mmio::LOCAL_IC_SIZE); ++ let local_virt_addr = memory::mmu::kernel_map_mmio( ++ device_driver::InterruptController::COMPATIBLE, ++ &local_mmio_descriptor, ++ )?; ++ + let periph_mmio_descriptor = + MMIODescriptor::new(mmio::PERIPHERAL_IC_START, mmio::PERIPHERAL_IC_SIZE); + let periph_virt_addr = memory::mmu::kernel_map_mmio( +@@ -80,7 +86,10 @@ + &periph_mmio_descriptor, + )?; + +- INTERRUPT_CONTROLLER.write(device_driver::InterruptController::new(periph_virt_addr)); ++ INTERRUPT_CONTROLLER.write(device_driver::InterruptController::new( ++ local_virt_addr, ++ periph_virt_addr, ++ )); + + Ok(()) + } + +diff -uNr 19_kernel_heap/kernel/src/bsp/raspberrypi/exception/asynchronous.rs 20_timer_callbacks/kernel/src/bsp/raspberrypi/exception/asynchronous.rs +--- 19_kernel_heap/kernel/src/bsp/raspberrypi/exception/asynchronous.rs ++++ 20_timer_callbacks/kernel/src/bsp/raspberrypi/exception/asynchronous.rs +@@ -13,16 +13,24 @@ + /// Export for reuse in generic asynchronous.rs. + pub use bsp::device_driver::IRQNumber; + ++/// The IRQ map. + #[cfg(feature = "bsp_rpi3")] +-pub(in crate::bsp) mod irq_map { +- use super::bsp::device_driver::{IRQNumber, PeripheralIRQ}; ++pub mod irq_map { ++ use super::bsp::device_driver::{IRQNumber, LocalIRQ, PeripheralIRQ}; + +- pub const PL011_UART: IRQNumber = IRQNumber::Peripheral(PeripheralIRQ::new(57)); ++ /// The non-secure physical timer IRQ number. ++ pub const ARM_NS_PHYISCAL_TIMER: IRQNumber = IRQNumber::Local(LocalIRQ::new(1)); ++ ++ pub(in crate::bsp) const PL011_UART: IRQNumber = IRQNumber::Peripheral(PeripheralIRQ::new(57)); + } + ++/// The IRQ map. + #[cfg(feature = "bsp_rpi4")] +-pub(in crate::bsp) mod irq_map { ++pub mod irq_map { + use super::bsp::device_driver::IRQNumber; + +- pub const PL011_UART: IRQNumber = IRQNumber::new(153); ++ /// The non-secure physical timer IRQ number. ++ pub const ARM_NS_PHYISCAL_TIMER: IRQNumber = IRQNumber::new(30); ++ ++ pub(in crate::bsp) const PL011_UART: IRQNumber = IRQNumber::new(153); + } + +diff -uNr 19_kernel_heap/kernel/src/bsp/raspberrypi/memory.rs 20_timer_callbacks/kernel/src/bsp/raspberrypi/memory.rs +--- 19_kernel_heap/kernel/src/bsp/raspberrypi/memory.rs ++++ 20_timer_callbacks/kernel/src/bsp/raspberrypi/memory.rs +@@ -124,6 +124,9 @@ + pub const PL011_UART_START: Address = Address::new(0x3F20_1000); + pub const PL011_UART_SIZE: usize = 0x48; + ++ pub const LOCAL_IC_START: Address = Address::new(0x4000_0000); ++ pub const LOCAL_IC_SIZE: usize = 0x100; ++ + pub const END: Address = Address::new(0x4001_0000); + } + + +diff -uNr 19_kernel_heap/kernel/src/main.rs 20_timer_callbacks/kernel/src/main.rs +--- 19_kernel_heap/kernel/src/main.rs ++++ 20_timer_callbacks/kernel/src/main.rs +@@ -30,6 +30,11 @@ + exception::handling_init(); + memory::init(); + ++ // Initialize the timer subsystem. ++ if let Err(x) = time::init() { ++ panic!("Error initializing timer subsystem: {}", x); ++ } ++ + // Initialize the BSP driver subsystem. + if let Err(x) = bsp::driver::init() { + panic!("Error initializing BSP driver subsystem: {}", x); +@@ -52,6 +57,9 @@ + + /// The main function running after the early init. + fn kernel_main() -> ! { ++ use alloc::boxed::Box; ++ use core::time::Duration; ++ + info!("{}", libkernel::version()); + info!("Booting on: {}", bsp::board_name()); + +@@ -78,6 +86,11 @@ + info!("Kernel heap:"); + memory::heap_alloc::kernel_heap_allocator().print_usage(); + ++ time::time_manager().set_timeout_once(Duration::from_secs(5), Box::new(|| info!("Once 5"))); ++ time::time_manager().set_timeout_once(Duration::from_secs(3), Box::new(|| info!("Once 2"))); ++ time::time_manager() ++ .set_timeout_periodic(Duration::from_secs(1), Box::new(|| info!("Periodic 1 sec"))); ++ + info!("Echoing input now"); + cpu::wait_forever(); + } + +diff -uNr 19_kernel_heap/kernel/src/time.rs 20_timer_callbacks/kernel/src/time.rs +--- 19_kernel_heap/kernel/src/time.rs ++++ 20_timer_callbacks/kernel/src/time.rs +@@ -3,19 +3,54 @@ + // Copyright (c) 2020-2022 Andre Richter + + //! Timer primitives. ++//! ++//! # Resources ++//! ++//! - ++//! - + + #[cfg(target_arch = "aarch64")] + #[path = "_arch/aarch64/time.rs"] + mod arch_time; + +-use core::time::Duration; ++use crate::{ ++ driver, exception, ++ exception::asynchronous::IRQNumber, ++ synchronization::{interface::Mutex, IRQSafeNullLock}, ++ warn, ++}; ++use alloc::{boxed::Box, vec::Vec}; ++use core::{ ++ sync::atomic::{AtomicBool, Ordering}, ++ time::Duration, ++}; ++ ++//-------------------------------------------------------------------------------------------------- ++// Private Definitions ++//-------------------------------------------------------------------------------------------------- ++ ++struct Timeout { ++ due_time: Duration, ++ period: Option, ++ callback: TimeoutCallback, ++} ++ ++struct OrderedTimeoutQueue { ++ // Can be replaced with a BinaryHeap once it's new() becomes const. ++ inner: Vec, ++} + + //-------------------------------------------------------------------------------------------------- + // Public Definitions + //-------------------------------------------------------------------------------------------------- + ++/// The callback type used by timer IRQs. ++pub type TimeoutCallback = Box; ++ + /// Provides time management functions. +-pub struct TimeManager; ++pub struct TimeManager { ++ queue: IRQSafeNullLock, ++} + + //-------------------------------------------------------------------------------------------------- + // Global instances +@@ -24,6 +59,46 @@ + static TIME_MANAGER: TimeManager = TimeManager::new(); + + //-------------------------------------------------------------------------------------------------- ++// Private Code ++//-------------------------------------------------------------------------------------------------- ++ ++impl Timeout { ++ pub fn is_periodic(&self) -> bool { ++ self.period.is_some() ++ } ++ ++ pub fn refresh(&mut self) { ++ if let Some(delay) = self.period { ++ self.due_time += delay; ++ } ++ } ++} ++ ++impl OrderedTimeoutQueue { ++ pub const fn new() -> Self { ++ Self { inner: Vec::new() } ++ } ++ ++ pub fn push(&mut self, timeout: Timeout) { ++ self.inner.push(timeout); ++ ++ // Note reverse compare order so that earliest expiring item is at end of vec. We do this so ++ // that we can use Vec::pop below to retrieve the item that is next due. ++ self.inner.sort_by(|a, b| b.due_time.cmp(&a.due_time)); ++ } ++ ++ pub fn peek_next_due_time(&self) -> Option { ++ let timeout = self.inner.last()?; ++ ++ Some(timeout.due_time) ++ } ++ ++ pub fn pop(&mut self) -> Option { ++ self.inner.pop() ++ } ++} ++ ++//-------------------------------------------------------------------------------------------------- + // Public Code + //-------------------------------------------------------------------------------------------------- + +@@ -33,9 +108,14 @@ + } + + impl TimeManager { ++ /// Compatibility string. ++ pub const COMPATIBLE: &'static str = "ARM Architectural Timer"; ++ + /// Create an instance. + pub const fn new() -> Self { +- Self ++ Self { ++ queue: IRQSafeNullLock::new(OrderedTimeoutQueue::new()), ++ } + } + + /// The timer's resolution. +@@ -54,4 +134,130 @@ + pub fn spin_for(&self, duration: Duration) { + arch_time::spin_for(duration) + } ++ ++ /// Set a timeout. ++ fn set_timeout(&self, timeout: Timeout) { ++ self.queue.lock(|queue| { ++ queue.push(timeout); ++ ++ arch_time::set_timeout_irq(queue.peek_next_due_time().unwrap()); ++ }); ++ } ++ ++ /// Set a one-shot timeout. ++ pub fn set_timeout_once(&self, delay: Duration, callback: TimeoutCallback) { ++ let timeout = Timeout { ++ due_time: self.uptime() + delay, ++ period: None, ++ callback, ++ }; ++ ++ self.set_timeout(timeout); ++ } ++ ++ /// Set a periodic timeout. ++ pub fn set_timeout_periodic(&self, delay: Duration, callback: TimeoutCallback) { ++ let timeout = Timeout { ++ due_time: self.uptime() + delay, ++ period: Some(delay), ++ callback, ++ }; ++ ++ self.set_timeout(timeout); ++ } ++} ++ ++/// Initialize the timer subsystem. ++pub fn init() -> Result<(), &'static str> { ++ static INIT_DONE: AtomicBool = AtomicBool::new(false); ++ if INIT_DONE.load(Ordering::Relaxed) { ++ return Err("Init already done"); ++ } ++ ++ let timer_descriptor = ++ driver::DeviceDriverDescriptor::new(time_manager(), None, Some(arch_time::timeout_irq())); ++ driver::driver_manager().register_driver(timer_descriptor); ++ ++ INIT_DONE.store(true, Ordering::Relaxed); ++ Ok(()) ++} ++ ++//------------------------------------------------------------------------------ ++// OS Interface Code ++//------------------------------------------------------------------------------ ++ ++impl driver::interface::DeviceDriver for TimeManager { ++ type IRQNumberType = IRQNumber; ++ ++ fn compatible(&self) -> &'static str { ++ Self::COMPATIBLE ++ } ++ ++ fn register_and_enable_irq_handler( ++ &'static self, ++ irq_number: &Self::IRQNumberType, ++ ) -> Result<(), &'static str> { ++ use exception::asynchronous::{irq_manager, IRQHandlerDescriptor}; ++ ++ let descriptor = IRQHandlerDescriptor::new(*irq_number, Self::COMPATIBLE, self); ++ ++ irq_manager().register_handler(descriptor)?; ++ irq_manager().enable(irq_number); ++ ++ Ok(()) ++ } ++} ++ ++impl exception::asynchronous::interface::IRQHandler for TimeManager { ++ fn handle(&self) -> Result<(), &'static str> { ++ arch_time::conclude_timeout_irq(); ++ ++ let maybe_timeout: Option = self.queue.lock(|queue| { ++ let next_due_time = queue.peek_next_due_time()?; ++ if next_due_time > self.uptime() { ++ return None; ++ } ++ ++ let mut timeout = queue.pop().unwrap(); ++ ++ // Refresh as early as possible to prevent drift. ++ if timeout.is_periodic() { ++ timeout.refresh(); ++ } ++ ++ Some(timeout) ++ }); ++ ++ let timeout = match maybe_timeout { ++ None => { ++ warn!("Spurious timeout IRQ"); ++ return Ok(()); ++ } ++ Some(t) => t, ++ }; ++ ++ // Important: Call the callback while not holding any lock, because the callback might ++ // attempt to modify data that is protected by a lock (in particular, the timeout queue ++ // itself). ++ (timeout.callback)(); ++ ++ self.queue.lock(|queue| { ++ if timeout.is_periodic() { ++ // There might be some overhead involved in the periodic path, because the timeout ++ // item is first popped from the underlying Vec and then pushed back again. It could ++ // be faster to keep the item in the queue and find a way to work with a reference ++ // to it. ++ // ++ // We are not going this route on purpose, though. It allows to keep the code simple ++ // and the focus on the high-level concepts. ++ queue.push(timeout); ++ }; ++ ++ if let Some(due_time) = queue.peek_next_due_time() { ++ arch_time::set_timeout_irq(due_time); ++ } ++ }); ++ ++ Ok(()) ++ } + } + +diff -uNr 19_kernel_heap/kernel/tests/boot_test_string.rb 20_timer_callbacks/kernel/tests/boot_test_string.rb +--- 19_kernel_heap/kernel/tests/boot_test_string.rb ++++ 20_timer_callbacks/kernel/tests/boot_test_string.rb +@@ -1,3 +1,3 @@ + # frozen_string_literal: true + +-EXPECTED_PRINT = 'Echoing input now' ++EXPECTED_PRINT = 'Once 5' + +``` diff --git a/20_timer_callbacks/kernel/Cargo.lock b/20_timer_callbacks/kernel/Cargo.lock new file mode 100644 index 00000000..740209d0 --- /dev/null +++ b/20_timer_callbacks/kernel/Cargo.lock @@ -0,0 +1,96 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "cortex-a" +version = "8.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cd4524931a4e0ec50ae91f0d55f571f31ffe11dd9ce2f9905b8343c018c25bb" +dependencies = [ + "tock-registers", +] + +[[package]] +name = "debug-symbol-types" +version = "0.1.0" + +[[package]] +name = "linked_list_allocator" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e322f259d225fbae43a1b053b2dc6a5968a6bdf8b205f5de684dab485b95030e" + +[[package]] +name = "mingo" +version = "0.20.0" +dependencies = [ + "cortex-a", + "debug-symbol-types", + "linked_list_allocator", + "qemu-exit", + "test-macros", + "test-types", + "tock-registers", +] + +[[package]] +name = "proc-macro2" +version = "1.0.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9027b48e9d4c9175fa2218adf3557f91c1137021739951d4932f5f8268ac48aa" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "qemu-exit" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ff023245bfcc73fb890e1f8d5383825b3131cc920020a5c487d6f113dfc428a" + +[[package]] +name = "quote" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "syn" +version = "1.0.94" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a07e33e919ebcd69113d5be0e4d70c5707004ff45188910106854f38b960df4a" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "test-macros" +version = "0.1.0" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "test-types", +] + +[[package]] +name = "test-types" +version = "0.1.0" + +[[package]] +name = "tock-registers" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "696941a0aee7e276a165a978b37918fd5d22c55c3d6bda197813070ca9c0f21c" + +[[package]] +name = "unicode-xid" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "957e51f3646910546462e67d5f7599b9e4fb8acdd304b087a6494730f9eebf04" diff --git a/20_timer_callbacks/kernel/Cargo.toml b/20_timer_callbacks/kernel/Cargo.toml new file mode 100644 index 00000000..e127a857 --- /dev/null +++ b/20_timer_callbacks/kernel/Cargo.toml @@ -0,0 +1,72 @@ +[package] +name = "mingo" +version = "0.20.0" +authors = ["Andre Richter "] +edition = "2021" + +[features] +default = [] +debug_prints = [] +bsp_rpi3 = ["tock-registers"] +bsp_rpi4 = ["tock-registers"] +test_build = ["qemu-exit"] + +##-------------------------------------------------------------------------------------------------- +## Dependencies +##-------------------------------------------------------------------------------------------------- + +[dependencies] +test-types = { path = "../libraries/test-types" } +debug-symbol-types = { path = "../libraries/debug-symbol-types" } +linked_list_allocator = { version = "0.10.x", default-features = false, features = ["const_mut_refs"] } + +# Optional dependencies +tock-registers = { version = "0.8.x", default-features = false, features = ["register_types"], optional = true } +qemu-exit = { version = "3.x.x", optional = true } + +# Platform specific dependencies +[target.'cfg(target_arch = "aarch64")'.dependencies] +cortex-a = { version = "8.x.x" } + +##-------------------------------------------------------------------------------------------------- +## Testing +##-------------------------------------------------------------------------------------------------- + +[dev-dependencies] +test-macros = { path = "../libraries/test-macros" } + +# Unit tests are done in the library part of the kernel. +[lib] +name = "libkernel" +test = true + +# Disable unit tests for the kernel binary. +[[bin]] +name = "kernel" +path = "src/main.rs" +test = false + +# List of tests without harness. +[[test]] +name = "00_console_sanity" +harness = false + +[[test]] +name = "02_exception_sync_page_fault" +harness = false + +[[test]] +name = "03_exception_restore_sanity" +harness = false + +[[test]] +name = "05_backtrace_sanity" +harness = false + +[[test]] +name = "06_backtrace_invalid_frame" +harness = false + +[[test]] +name = "07_backtrace_invalid_link" +harness = false diff --git a/20_timer_callbacks/kernel/build.rs b/20_timer_callbacks/kernel/build.rs new file mode 100644 index 00000000..cab00bb3 --- /dev/null +++ b/20_timer_callbacks/kernel/build.rs @@ -0,0 +1,20 @@ +use std::{env, fs, process}; + +fn main() { + let ld_script_path = match env::var("LD_SCRIPT_PATH") { + Ok(var) => var, + _ => process::exit(0), + }; + + let files = fs::read_dir(ld_script_path).unwrap(); + files + .filter_map(Result::ok) + .filter(|d| { + if let Some(e) = d.path().extension() { + e == "ld" + } else { + false + } + }) + .for_each(|f| println!("cargo:rerun-if-changed={}", f.path().display())); +} diff --git a/20_timer_callbacks/kernel/src/_arch/aarch64/backtrace.rs b/20_timer_callbacks/kernel/src/_arch/aarch64/backtrace.rs new file mode 100644 index 00000000..e8860984 --- /dev/null +++ b/20_timer_callbacks/kernel/src/_arch/aarch64/backtrace.rs @@ -0,0 +1,136 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2022 Andre Richter + +//! Architectural backtracing support. +//! +//! # Orientation +//! +//! Since arch modules are imported into generic modules using the path attribute, the path of this +//! file is: +//! +//! crate::backtrace::arch_backtrace + +use crate::{ + backtrace::BacktraceItem, + memory::{Address, Virtual}, +}; +use cortex_a::registers::*; +use tock_registers::interfaces::Readable; + +//-------------------------------------------------------------------------------------------------- +// Private Definitions +//-------------------------------------------------------------------------------------------------- + +/// A Stack frame record. +/// +/// # Note +/// +/// The convention is that `previous_record` is valid as long as it contains a non-null value. +/// Therefore, it is possible to type the member as `Option<&StackFrameRecord>` because of Rust's +/// `null-pointer optimization`. +#[repr(C)] +struct StackFrameRecord<'a> { + previous_record: Option<&'a StackFrameRecord<'a>>, + link: Address, +} + +struct StackFrameRecordIterator<'a> { + cur: &'a StackFrameRecord<'a>, +} + +//-------------------------------------------------------------------------------------------------- +// Private Code +//-------------------------------------------------------------------------------------------------- + +impl<'a> Iterator for StackFrameRecordIterator<'a> { + type Item = BacktraceItem; + + fn next(&mut self) -> Option { + static ABORT_FRAME: StackFrameRecord = StackFrameRecord { + previous_record: None, + link: Address::new(0), + }; + + // If previous is None, this is the root frame, so iteration will stop here. + let previous = self.cur.previous_record?; + + // Need to abort if the pointer to the previous frame record is invalid. + let prev_addr = Address::::new(previous as *const _ as usize); + if !prev_addr.is_valid_stack_addr() { + // This allows to return the error and then stop on the next iteration. + self.cur = &ABORT_FRAME; + return Some(BacktraceItem::InvalidFramePointer(prev_addr)); + } + + let ret = if !self.cur.link.is_valid_code_addr() { + Some(BacktraceItem::InvalidLink(self.cur.link)) + } else { + // The link points to the instruction to be executed _after_ returning from a branch. + // However, we want to show the instruction that caused the branch, so subtract by one + // instruction. + // + // This might be called from panic!, so it must not panic itself on the subtraction. + let link = if self.cur.link >= Address::new(4) { + self.cur.link - 4 + } else { + self.cur.link + }; + + Some(BacktraceItem::Link(link)) + }; + + // Advance the iterator. + self.cur = previous; + + ret + } +} + +fn stack_frame_record_iterator<'a>() -> Option> { + let fp = Address::::new(FP.get() as usize); + if !fp.is_valid_stack_addr() { + return None; + } + + Some(StackFrameRecordIterator { + cur: unsafe { &*(fp.as_usize() as *const _) }, + }) +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +/// Architectural implementation of the backtrace. +pub fn backtrace(f: impl FnOnce(Option<&mut dyn Iterator>)) { + f(stack_frame_record_iterator().as_mut().map(|s| s as _)) +} + +//-------------------------------------------------------------------------------------------------- +// Testing +//-------------------------------------------------------------------------------------------------- + +#[cfg(feature = "test_build")] +#[inline(always)] +/// Hack for corrupting the previous frame address in the current stack frame. +/// +/// # Safety +/// +/// - To be used only by testing code. +pub unsafe fn corrupt_previous_frame_addr() { + let sf = FP.get() as *mut usize; + *sf = 0x123; +} + +#[cfg(feature = "test_build")] +#[inline(always)] +/// Hack for corrupting the link in the current stack frame. +/// +/// # Safety +/// +/// - To be used only by testing code. +pub unsafe fn corrupt_link() { + let sf = FP.get() as *mut StackFrameRecord; + (*sf).link = Address::new(0x456); +} diff --git a/20_timer_callbacks/kernel/src/_arch/aarch64/cpu.rs b/20_timer_callbacks/kernel/src/_arch/aarch64/cpu.rs new file mode 100644 index 00000000..66da661c --- /dev/null +++ b/20_timer_callbacks/kernel/src/_arch/aarch64/cpu.rs @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2018-2022 Andre Richter + +//! Architectural processor code. +//! +//! # Orientation +//! +//! Since arch modules are imported into generic modules using the path attribute, the path of this +//! file is: +//! +//! crate::cpu::arch_cpu + +use cortex_a::asm; + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +pub use asm::nop; + +/// Pause execution on the core. +#[inline(always)] +pub fn wait_forever() -> ! { + loop { + asm::wfe() + } +} + +//-------------------------------------------------------------------------------------------------- +// Testing +//-------------------------------------------------------------------------------------------------- +#[cfg(feature = "test_build")] +use qemu_exit::QEMUExit; + +#[cfg(feature = "test_build")] +const QEMU_EXIT_HANDLE: qemu_exit::AArch64 = qemu_exit::AArch64::new(); + +/// Make the host QEMU binary execute `exit(1)`. +#[cfg(feature = "test_build")] +pub fn qemu_exit_failure() -> ! { + QEMU_EXIT_HANDLE.exit_failure() +} + +/// Make the host QEMU binary execute `exit(0)`. +#[cfg(feature = "test_build")] +pub fn qemu_exit_success() -> ! { + QEMU_EXIT_HANDLE.exit_success() +} diff --git a/20_timer_callbacks/kernel/src/_arch/aarch64/cpu/boot.rs b/20_timer_callbacks/kernel/src/_arch/aarch64/cpu/boot.rs new file mode 100644 index 00000000..15ab92b6 --- /dev/null +++ b/20_timer_callbacks/kernel/src/_arch/aarch64/cpu/boot.rs @@ -0,0 +1,117 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2021-2022 Andre Richter + +//! Architectural boot code. +//! +//! # Orientation +//! +//! Since arch modules are imported into generic modules using the path attribute, the path of this +//! file is: +//! +//! crate::cpu::boot::arch_boot + +use crate::{memory, memory::Address}; +use core::{ + arch::global_asm, + sync::atomic::{compiler_fence, Ordering}, +}; +use cortex_a::{asm, registers::*}; +use tock_registers::interfaces::Writeable; + +// Assembly counterpart to this file. +global_asm!( + include_str!("boot.s"), + CONST_CURRENTEL_EL2 = const 0x8, + CONST_CORE_ID_MASK = const 0b11 +); + +//-------------------------------------------------------------------------------------------------- +// Private Code +//-------------------------------------------------------------------------------------------------- + +/// Prepares the transition from EL2 to EL1. +/// +/// # Safety +/// +/// - The `bss` section is not initialized yet. The code must not use or reference it in any way. +/// - The HW state of EL1 must be prepared in a sound way. +#[inline(always)] +unsafe fn prepare_el2_to_el1_transition( + virt_boot_core_stack_end_exclusive_addr: u64, + virt_kernel_init_addr: u64, +) { + // Enable timer counter registers for EL1. + CNTHCTL_EL2.write(CNTHCTL_EL2::EL1PCEN::SET + CNTHCTL_EL2::EL1PCTEN::SET); + + // No offset for reading the counters. + CNTVOFF_EL2.set(0); + + // Set EL1 execution state to AArch64. + HCR_EL2.write(HCR_EL2::RW::EL1IsAarch64); + + // Set up a simulated exception return. + // + // First, fake a saved program status where all interrupts were masked and SP_EL1 was used as a + // stack pointer. + SPSR_EL2.write( + SPSR_EL2::D::Masked + + SPSR_EL2::A::Masked + + SPSR_EL2::I::Masked + + SPSR_EL2::F::Masked + + SPSR_EL2::M::EL1h, + ); + + // Second, let the link register point to kernel_init(). + ELR_EL2.set(virt_kernel_init_addr); + + // Set up SP_EL1 (stack pointer), which will be used by EL1 once we "return" to it. Since there + // are no plans to ever return to EL2, just re-use the same stack. + SP_EL1.set(virt_boot_core_stack_end_exclusive_addr); +} + +/// Reset the backtrace by setting link register and frame pointer to zero. +/// +/// # Safety +/// +/// - This function must only be used immediately before entering EL1. +#[inline(always)] +unsafe fn prepare_backtrace_reset() { + compiler_fence(Ordering::SeqCst); + FP.set(0); + LR.set(0); +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +/// The Rust entry of the `kernel` binary. +/// +/// The function is called from the assembly `_start` function. +/// +/// # Safety +/// +/// - Exception return from EL2 must must continue execution in EL1 with `kernel_init()`. +#[no_mangle] +pub unsafe extern "C" fn _start_rust( + phys_kernel_tables_base_addr: u64, + virt_boot_core_stack_end_exclusive_addr: u64, + virt_kernel_init_addr: u64, +) -> ! { + prepare_el2_to_el1_transition( + virt_boot_core_stack_end_exclusive_addr, + virt_kernel_init_addr, + ); + + // Turn on the MMU for EL1. + let addr = Address::new(phys_kernel_tables_base_addr as usize); + memory::mmu::enable_mmu_and_caching(addr).unwrap(); + + // Make the function we return to the root of a backtrace. + prepare_backtrace_reset(); + + // Use `eret` to "return" to EL1. Since virtual memory will already be enabled, this results in + // execution of kernel_init() in EL1 from its _virtual address_. + asm::eret() +} diff --git a/20_timer_callbacks/kernel/src/_arch/aarch64/cpu/boot.s b/20_timer_callbacks/kernel/src/_arch/aarch64/cpu/boot.s new file mode 100644 index 00000000..1a8c8801 --- /dev/null +++ b/20_timer_callbacks/kernel/src/_arch/aarch64/cpu/boot.s @@ -0,0 +1,105 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2021-2022 Andre Richter + +//-------------------------------------------------------------------------------------------------- +// Definitions +//-------------------------------------------------------------------------------------------------- + +// Load the address of a symbol into a register, PC-relative. +// +// The symbol must lie within +/- 4 GiB of the Program Counter. +// +// # Resources +// +// - https://sourceware.org/binutils/docs-2.36/as/AArch64_002dRelocations.html +.macro ADR_REL register, symbol + adrp \register, \symbol + add \register, \register, #:lo12:\symbol +.endm + +// Load the address of a symbol into a register, absolute. +// +// # Resources +// +// - https://sourceware.org/binutils/docs-2.36/as/AArch64_002dRelocations.html +.macro ADR_ABS register, symbol + movz \register, #:abs_g3:\symbol + movk \register, #:abs_g2_nc:\symbol + movk \register, #:abs_g1_nc:\symbol + movk \register, #:abs_g0_nc:\symbol +.endm + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- +.section .text._start + +//------------------------------------------------------------------------------ +// fn _start() +//------------------------------------------------------------------------------ +_start: + // Only proceed if the core executes in EL2. Park it otherwise. + mrs x0, CurrentEL + cmp x0, {CONST_CURRENTEL_EL2} + b.ne .L_parking_loop + + // Only proceed on the boot core. Park it otherwise. + mrs x1, MPIDR_EL1 + and x1, x1, {CONST_CORE_ID_MASK} + ldr x2, BOOT_CORE_ID // provided by bsp/__board_name__/cpu.rs + cmp x1, x2 + b.ne .L_parking_loop + + // If execution reaches here, it is the boot core. + + // Initialize DRAM. + ADR_REL x0, __bss_start + ADR_REL x1, __bss_end_exclusive + +.L_bss_init_loop: + cmp x0, x1 + b.eq .L_prepare_rust + stp xzr, xzr, [x0], #16 + b .L_bss_init_loop + + // Prepare the jump to Rust code. +.L_prepare_rust: + // Load the base address of the kernel's translation tables. + ldr x0, PHYS_KERNEL_TABLES_BASE_ADDR // provided by bsp/__board_name__/memory/mmu.rs + + // Load the _absolute_ addresses of the following symbols. Since the kernel is linked at + // the top of the 64 bit address space, these are effectively virtual addresses. + ADR_ABS x1, __boot_core_stack_end_exclusive + ADR_ABS x2, kernel_init + + // Load the PC-relative address of the stack and set the stack pointer. + // + // Since _start() is the first function that runs after the firmware has loaded the kernel + // into memory, retrieving this symbol PC-relative returns the "physical" address. + // + // Setting the stack pointer to this value ensures that anything that still runs in EL2, + // until the kernel returns to EL1 with the MMU enabled, works as well. After the return to + // EL1, the virtual address of the stack retrieved above will be used. + ADR_REL x3, __boot_core_stack_end_exclusive + mov sp, x3 + + // Read the CPU's timer counter frequency and store it in ARCH_TIMER_COUNTER_FREQUENCY. + // Abort if the frequency read back as 0. + ADR_REL x4, ARCH_TIMER_COUNTER_FREQUENCY // provided by aarch64/time.rs + mrs x5, CNTFRQ_EL0 + cmp x5, xzr + b.eq .L_parking_loop + str w5, [x4] + + // Jump to Rust code. x0, x1 and x2 hold the function arguments provided to _start_rust(). + b _start_rust + + // Infinitely wait for events (aka "park the core"). +.L_parking_loop: + wfe + b .L_parking_loop + +.size _start, . - _start +.type _start, function +.global _start diff --git a/20_timer_callbacks/kernel/src/_arch/aarch64/cpu/smp.rs b/20_timer_callbacks/kernel/src/_arch/aarch64/cpu/smp.rs new file mode 100644 index 00000000..351fde62 --- /dev/null +++ b/20_timer_callbacks/kernel/src/_arch/aarch64/cpu/smp.rs @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2018-2022 Andre Richter + +//! Architectural symmetric multiprocessing. +//! +//! # Orientation +//! +//! Since arch modules are imported into generic modules using the path attribute, the path of this +//! file is: +//! +//! crate::cpu::smp::arch_smp + +use cortex_a::registers::*; +use tock_registers::interfaces::Readable; + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +/// Return the executing core's id. +#[inline(always)] +pub fn core_id() -> T +where + T: From, +{ + const CORE_MASK: u64 = 0b11; + + T::from((MPIDR_EL1.get() & CORE_MASK) as u8) +} diff --git a/20_timer_callbacks/kernel/src/_arch/aarch64/exception.rs b/20_timer_callbacks/kernel/src/_arch/aarch64/exception.rs new file mode 100644 index 00000000..e03e382f --- /dev/null +++ b/20_timer_callbacks/kernel/src/_arch/aarch64/exception.rs @@ -0,0 +1,325 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2018-2022 Andre Richter + +//! Architectural synchronous and asynchronous exception handling. +//! +//! # Orientation +//! +//! Since arch modules are imported into generic modules using the path attribute, the path of this +//! file is: +//! +//! crate::exception::arch_exception + +use crate::{exception, memory, symbols}; +use core::{arch::global_asm, cell::UnsafeCell, fmt}; +use cortex_a::{asm::barrier, registers::*}; +use tock_registers::{ + interfaces::{Readable, Writeable}, + registers::InMemoryRegister, +}; + +// Assembly counterpart to this file. +global_asm!( + include_str!("exception.s"), + CONST_ESR_EL1_EC_SHIFT = const 26, + CONST_ESR_EL1_EC_VALUE_SVC64 = const 0x15 +); + +//-------------------------------------------------------------------------------------------------- +// Private Definitions +//-------------------------------------------------------------------------------------------------- + +/// Wrapper structs for memory copies of registers. +#[repr(transparent)] +struct SpsrEL1(InMemoryRegister); +struct EsrEL1(InMemoryRegister); + +/// The exception context as it is stored on the stack on exception entry. +#[repr(C)] +struct ExceptionContext { + /// General Purpose Registers. + gpr: [u64; 30], + + /// The link register, aka x30. + lr: u64, + + /// Exception link register. The program counter at the time the exception happened. + elr_el1: u64, + + /// Saved program status. + spsr_el1: SpsrEL1, + + /// Exception syndrome register. + esr_el1: EsrEL1, +} + +//-------------------------------------------------------------------------------------------------- +// Private Code +//-------------------------------------------------------------------------------------------------- + +/// Prints verbose information about the exception and then panics. +fn default_exception_handler(exc: &ExceptionContext) { + panic!( + "CPU Exception!\n\n\ + {}", + exc + ); +} + +//------------------------------------------------------------------------------ +// Current, EL0 +//------------------------------------------------------------------------------ + +#[no_mangle] +extern "C" fn current_el0_synchronous(_e: &mut ExceptionContext) { + panic!("Should not be here. Use of SP_EL0 in EL1 is not supported.") +} + +#[no_mangle] +extern "C" fn current_el0_irq(_e: &mut ExceptionContext) { + panic!("Should not be here. Use of SP_EL0 in EL1 is not supported.") +} + +#[no_mangle] +extern "C" fn current_el0_serror(_e: &mut ExceptionContext) { + panic!("Should not be here. Use of SP_EL0 in EL1 is not supported.") +} + +//------------------------------------------------------------------------------ +// Current, ELx +//------------------------------------------------------------------------------ + +#[no_mangle] +extern "C" fn current_elx_synchronous(e: &mut ExceptionContext) { + #[cfg(feature = "test_build")] + { + const TEST_SVC_ID: u64 = 0x1337; + + if let Some(ESR_EL1::EC::Value::SVC64) = e.esr_el1.exception_class() { + if e.esr_el1.iss() == TEST_SVC_ID { + return; + } + } + } + + default_exception_handler(e); +} + +#[no_mangle] +extern "C" fn current_elx_irq(_e: &mut ExceptionContext) { + let token = unsafe { &exception::asynchronous::IRQContext::new() }; + exception::asynchronous::irq_manager().handle_pending_irqs(token); +} + +#[no_mangle] +extern "C" fn current_elx_serror(e: &mut ExceptionContext) { + default_exception_handler(e); +} + +//------------------------------------------------------------------------------ +// Lower, AArch64 +//------------------------------------------------------------------------------ + +#[no_mangle] +extern "C" fn lower_aarch64_synchronous(e: &mut ExceptionContext) { + default_exception_handler(e); +} + +#[no_mangle] +extern "C" fn lower_aarch64_irq(e: &mut ExceptionContext) { + default_exception_handler(e); +} + +#[no_mangle] +extern "C" fn lower_aarch64_serror(e: &mut ExceptionContext) { + default_exception_handler(e); +} + +//------------------------------------------------------------------------------ +// Lower, AArch32 +//------------------------------------------------------------------------------ + +#[no_mangle] +extern "C" fn lower_aarch32_synchronous(e: &mut ExceptionContext) { + default_exception_handler(e); +} + +#[no_mangle] +extern "C" fn lower_aarch32_irq(e: &mut ExceptionContext) { + default_exception_handler(e); +} + +#[no_mangle] +extern "C" fn lower_aarch32_serror(e: &mut ExceptionContext) { + default_exception_handler(e); +} + +//------------------------------------------------------------------------------ +// Misc +//------------------------------------------------------------------------------ + +/// Human readable SPSR_EL1. +#[rustfmt::skip] +impl fmt::Display for SpsrEL1 { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + // Raw value. + writeln!(f, "SPSR_EL1: {:#010x}", self.0.get())?; + + let to_flag_str = |x| -> _ { + if x { "Set" } else { "Not set" } + }; + + writeln!(f, " Flags:")?; + writeln!(f, " Negative (N): {}", to_flag_str(self.0.is_set(SPSR_EL1::N)))?; + writeln!(f, " Zero (Z): {}", to_flag_str(self.0.is_set(SPSR_EL1::Z)))?; + writeln!(f, " Carry (C): {}", to_flag_str(self.0.is_set(SPSR_EL1::C)))?; + writeln!(f, " Overflow (V): {}", to_flag_str(self.0.is_set(SPSR_EL1::V)))?; + + let to_mask_str = |x| -> _ { + if x { "Masked" } else { "Unmasked" } + }; + + writeln!(f, " Exception handling state:")?; + writeln!(f, " Debug (D): {}", to_mask_str(self.0.is_set(SPSR_EL1::D)))?; + writeln!(f, " SError (A): {}", to_mask_str(self.0.is_set(SPSR_EL1::A)))?; + writeln!(f, " IRQ (I): {}", to_mask_str(self.0.is_set(SPSR_EL1::I)))?; + writeln!(f, " FIQ (F): {}", to_mask_str(self.0.is_set(SPSR_EL1::F)))?; + + write!(f, " Illegal Execution State (IL): {}", + to_flag_str(self.0.is_set(SPSR_EL1::IL)) + ) + } +} + +impl EsrEL1 { + #[inline(always)] + fn exception_class(&self) -> Option { + self.0.read_as_enum(ESR_EL1::EC) + } + + #[cfg(feature = "test_build")] + #[inline(always)] + fn iss(&self) -> u64 { + self.0.read(ESR_EL1::ISS) + } +} + +/// Human readable ESR_EL1. +#[rustfmt::skip] +impl fmt::Display for EsrEL1 { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + // Raw print of whole register. + writeln!(f, "ESR_EL1: {:#010x}", self.0.get())?; + + // Raw print of exception class. + write!(f, " Exception Class (EC) : {:#x}", self.0.read(ESR_EL1::EC))?; + + // Exception class. + let ec_translation = match self.exception_class() { + Some(ESR_EL1::EC::Value::DataAbortCurrentEL) => "Data Abort, current EL", + _ => "N/A", + }; + writeln!(f, " - {}", ec_translation)?; + + // Raw print of instruction specific syndrome. + write!(f, " Instr Specific Syndrome (ISS): {:#x}", self.0.read(ESR_EL1::ISS)) + } +} + +impl ExceptionContext { + #[inline(always)] + fn exception_class(&self) -> Option { + self.esr_el1.exception_class() + } + + #[inline(always)] + fn fault_address_valid(&self) -> bool { + use ESR_EL1::EC::Value::*; + + match self.exception_class() { + None => false, + Some(ec) => matches!( + ec, + InstrAbortLowerEL + | InstrAbortCurrentEL + | PCAlignmentFault + | DataAbortLowerEL + | DataAbortCurrentEL + | WatchpointLowerEL + | WatchpointCurrentEL + ), + } + } +} + +/// Human readable print of the exception context. +impl fmt::Display for ExceptionContext { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + writeln!(f, "{}", self.esr_el1)?; + + if self.fault_address_valid() { + writeln!(f, "FAR_EL1: {:#018x}", FAR_EL1.get() as usize)?; + } + + writeln!(f, "{}", self.spsr_el1)?; + writeln!(f, "ELR_EL1: {:#018x}", self.elr_el1)?; + writeln!( + f, + " Symbol: {}", + match symbols::lookup_symbol(memory::Address::new(self.elr_el1 as usize)) { + Some(sym) => sym.name(), + _ => "Symbol not found", + } + )?; + writeln!(f)?; + writeln!(f, "General purpose register:")?; + + #[rustfmt::skip] + let alternating = |x| -> _ { + if x % 2 == 0 { " " } else { "\n" } + }; + + // Print two registers per line. + for (i, reg) in self.gpr.iter().enumerate() { + write!(f, " x{: <2}: {: >#018x}{}", i, reg, alternating(i))?; + } + write!(f, " lr : {:#018x}", self.lr) + } +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- +use crate::exception::PrivilegeLevel; + +/// The processing element's current privilege level. +pub fn current_privilege_level() -> (PrivilegeLevel, &'static str) { + let el = CurrentEL.read_as_enum(CurrentEL::EL); + match el { + Some(CurrentEL::EL::Value::EL2) => (PrivilegeLevel::Hypervisor, "EL2"), + Some(CurrentEL::EL::Value::EL1) => (PrivilegeLevel::Kernel, "EL1"), + Some(CurrentEL::EL::Value::EL0) => (PrivilegeLevel::User, "EL0"), + _ => (PrivilegeLevel::Unknown, "Unknown"), + } +} + +/// Init exception handling by setting the exception vector base address register. +/// +/// # Safety +/// +/// - Changes the HW state of the executing core. +/// - The vector table and the symbol `__exception_vector_table_start` from the linker script must +/// adhere to the alignment and size constraints demanded by the ARMv8-A Architecture Reference +/// Manual. +pub unsafe fn handling_init() { + // Provided by exception.S. + extern "Rust" { + static __exception_vector_start: UnsafeCell<()>; + } + + VBAR_EL1.set(__exception_vector_start.get() as u64); + + // Force VBAR update to complete before next instruction. + barrier::isb(barrier::SY); +} diff --git a/20_timer_callbacks/kernel/src/_arch/aarch64/exception.s b/20_timer_callbacks/kernel/src/_arch/aarch64/exception.s new file mode 100644 index 00000000..cdef8c58 --- /dev/null +++ b/20_timer_callbacks/kernel/src/_arch/aarch64/exception.s @@ -0,0 +1,190 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2018-2022 Andre Richter + +//-------------------------------------------------------------------------------------------------- +// Definitions +//-------------------------------------------------------------------------------------------------- + +/// Call the function provided by parameter `\handler` after saving the exception context. Provide +/// the context as the first parameter to '\handler'. +.macro CALL_WITH_CONTEXT handler is_lower_el is_sync +__vector_\handler: + // Make room on the stack for the exception context. + sub sp, sp, #16 * 18 + + // Store all general purpose registers on the stack. + stp x0, x1, [sp, #16 * 0] + stp x2, x3, [sp, #16 * 1] + stp x4, x5, [sp, #16 * 2] + stp x6, x7, [sp, #16 * 3] + stp x8, x9, [sp, #16 * 4] + stp x10, x11, [sp, #16 * 5] + stp x12, x13, [sp, #16 * 6] + stp x14, x15, [sp, #16 * 7] + stp x16, x17, [sp, #16 * 8] + stp x18, x19, [sp, #16 * 9] + stp x20, x21, [sp, #16 * 10] + stp x22, x23, [sp, #16 * 11] + stp x24, x25, [sp, #16 * 12] + stp x26, x27, [sp, #16 * 13] + stp x28, x29, [sp, #16 * 14] + + // Add the exception link register (ELR_EL1), saved program status (SPSR_EL1) and exception + // syndrome register (ESR_EL1). + mrs x1, ELR_EL1 + mrs x2, SPSR_EL1 + mrs x3, ESR_EL1 + + stp lr, x1, [sp, #16 * 15] + stp x2, x3, [sp, #16 * 16] + + // Build a stack frame for backtracing. +.if \is_lower_el == 1 + // If we came from a lower EL, make it a root frame (by storing zero) so that the kernel + // does not attempt to trace into userspace. + stp xzr, xzr, [sp, #16 * 17] +.else + // For normal branches, the link address points to the instruction to be executed _after_ + // returning from a branch. In a backtrace, we want to show the instruction that caused the + // branch, though. That is why code in backtrace.rs subtracts 4 (length of one instruction) + // from the link address. + // + // Here we have a special case, though, because ELR_EL1 is used instead of LR to build the + // stack frame, so that it becomes possible to trace beyond an exception. Hence, it must be + // considered that semantics for ELR_EL1 differ from case to case. + // + // Unless an "exception generating instruction" was executed, ELR_EL1 already points to the + // the correct instruction, and hence the subtraction by 4 in backtrace.rs would yield wrong + // results. To cover for this, 4 is added to ELR_EL1 below unless the cause of exception was + // an SVC instruction. BRK and HLT are "exception generating instructions" as well, but they + // are not expected and therefore left out for now. + // + // For reference: Search for "preferred exception return address" in the Architecture + // Reference Manual for ARMv8-A. +.if \is_sync == 1 + lsr w3, w3, {CONST_ESR_EL1_EC_SHIFT} // w3 = ESR_EL1.EC + cmp w3, {CONST_ESR_EL1_EC_VALUE_SVC64} // w3 == SVC64 ? + b.eq 1f +.endif + add x1, x1, #4 +1: + stp x29, x1, [sp, #16 * 17] +.endif + + // Set the frame pointer to the stack frame record. + add x29, sp, #16 * 17 + + // x0 is the first argument for the function called through `\handler`. + mov x0, sp + + // Call `\handler`. + bl \handler + + // After returning from exception handling code, replay the saved context and return via + // `eret`. + b __exception_restore_context + +.size __vector_\handler, . - __vector_\handler +.type __vector_\handler, function +.endm + +.macro FIQ_SUSPEND +1: wfe + b 1b +.endm + +//-------------------------------------------------------------------------------------------------- +// Private Code +//-------------------------------------------------------------------------------------------------- +.section .text + +//------------------------------------------------------------------------------ +// The exception vector table. +//------------------------------------------------------------------------------ + +// Align by 2^11 bytes, as demanded by ARMv8-A. Same as ALIGN(2048) in an ld script. +.align 11 + +// Export a symbol for the Rust code to use. +__exception_vector_start: + +// Current exception level with SP_EL0. +// +// .org sets the offset relative to section start. +// +// # Safety +// +// - It must be ensured that `CALL_WITH_CONTEXT` <= 0x80 bytes. +.org 0x000 + CALL_WITH_CONTEXT current_el0_synchronous, 0, 1 +.org 0x080 + CALL_WITH_CONTEXT current_el0_irq, 0, 0 +.org 0x100 + FIQ_SUSPEND +.org 0x180 + CALL_WITH_CONTEXT current_el0_serror, 0, 0 + +// Current exception level with SP_ELx, x > 0. +.org 0x200 + CALL_WITH_CONTEXT current_elx_synchronous, 0, 1 +.org 0x280 + CALL_WITH_CONTEXT current_elx_irq, 0, 0 +.org 0x300 + FIQ_SUSPEND +.org 0x380 + CALL_WITH_CONTEXT current_elx_serror, 0, 0 + +// Lower exception level, AArch64 +.org 0x400 + CALL_WITH_CONTEXT lower_aarch64_synchronous, 1, 1 +.org 0x480 + CALL_WITH_CONTEXT lower_aarch64_irq, 1, 0 +.org 0x500 + FIQ_SUSPEND +.org 0x580 + CALL_WITH_CONTEXT lower_aarch64_serror, 1, 0 + +// Lower exception level, AArch32 +.org 0x600 + CALL_WITH_CONTEXT lower_aarch32_synchronous, 1, 0 +.org 0x680 + CALL_WITH_CONTEXT lower_aarch32_irq, 1, 0 +.org 0x700 + FIQ_SUSPEND +.org 0x780 + CALL_WITH_CONTEXT lower_aarch32_serror, 1, 0 +.org 0x800 + +//------------------------------------------------------------------------------ +// fn __exception_restore_context() +//------------------------------------------------------------------------------ +__exception_restore_context: + ldr w19, [sp, #16 * 16] + ldp lr, x20, [sp, #16 * 15] + + msr SPSR_EL1, x19 + msr ELR_EL1, x20 + + ldp x0, x1, [sp, #16 * 0] + ldp x2, x3, [sp, #16 * 1] + ldp x4, x5, [sp, #16 * 2] + ldp x6, x7, [sp, #16 * 3] + ldp x8, x9, [sp, #16 * 4] + ldp x10, x11, [sp, #16 * 5] + ldp x12, x13, [sp, #16 * 6] + ldp x14, x15, [sp, #16 * 7] + ldp x16, x17, [sp, #16 * 8] + ldp x18, x19, [sp, #16 * 9] + ldp x20, x21, [sp, #16 * 10] + ldp x22, x23, [sp, #16 * 11] + ldp x24, x25, [sp, #16 * 12] + ldp x26, x27, [sp, #16 * 13] + ldp x28, x29, [sp, #16 * 14] + + add sp, sp, #16 * 18 + + eret + +.size __exception_restore_context, . - __exception_restore_context +.type __exception_restore_context, function diff --git a/20_timer_callbacks/kernel/src/_arch/aarch64/exception/asynchronous.rs b/20_timer_callbacks/kernel/src/_arch/aarch64/exception/asynchronous.rs new file mode 100644 index 00000000..cf6f97ac --- /dev/null +++ b/20_timer_callbacks/kernel/src/_arch/aarch64/exception/asynchronous.rs @@ -0,0 +1,141 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2018-2022 Andre Richter + +//! Architectural asynchronous exception handling. +//! +//! # Orientation +//! +//! Since arch modules are imported into generic modules using the path attribute, the path of this +//! file is: +//! +//! crate::exception::asynchronous::arch_asynchronous + +use core::arch::asm; +use cortex_a::registers::*; +use tock_registers::interfaces::{Readable, Writeable}; + +//-------------------------------------------------------------------------------------------------- +// Private Definitions +//-------------------------------------------------------------------------------------------------- + +mod daif_bits { + pub const IRQ: u8 = 0b0010; +} + +trait DaifField { + fn daif_field() -> tock_registers::fields::Field; +} + +struct Debug; +struct SError; +struct IRQ; +struct FIQ; + +//-------------------------------------------------------------------------------------------------- +// Private Code +//-------------------------------------------------------------------------------------------------- + +impl DaifField for Debug { + fn daif_field() -> tock_registers::fields::Field { + DAIF::D + } +} + +impl DaifField for SError { + fn daif_field() -> tock_registers::fields::Field { + DAIF::A + } +} + +impl DaifField for IRQ { + fn daif_field() -> tock_registers::fields::Field { + DAIF::I + } +} + +impl DaifField for FIQ { + fn daif_field() -> tock_registers::fields::Field { + DAIF::F + } +} + +fn is_masked() -> bool +where + T: DaifField, +{ + DAIF.is_set(T::daif_field()) +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +/// Returns whether IRQs are masked on the executing core. +pub fn is_local_irq_masked() -> bool { + !is_masked::() +} + +/// Unmask IRQs on the executing core. +/// +/// It is not needed to place an explicit instruction synchronization barrier after the `msr`. +/// Quoting the Architecture Reference Manual for ARMv8-A, section C5.1.3: +/// +/// "Writes to PSTATE.{PAN, D, A, I, F} occur in program order without the need for additional +/// synchronization." +#[inline(always)] +pub fn local_irq_unmask() { + unsafe { + asm!( + "msr DAIFClr, {arg}", + arg = const daif_bits::IRQ, + options(nomem, nostack, preserves_flags) + ); + } +} + +/// Mask IRQs on the executing core. +#[inline(always)] +pub fn local_irq_mask() { + unsafe { + asm!( + "msr DAIFSet, {arg}", + arg = const daif_bits::IRQ, + options(nomem, nostack, preserves_flags) + ); + } +} + +/// Mask IRQs on the executing core and return the previously saved interrupt mask bits (DAIF). +#[inline(always)] +pub fn local_irq_mask_save() -> u64 { + let saved = DAIF.get(); + local_irq_mask(); + + saved +} + +/// Restore the interrupt mask bits (DAIF) using the callee's argument. +/// +/// # Invariant +/// +/// - No sanity checks on the input. +#[inline(always)] +pub fn local_irq_restore(saved: u64) { + DAIF.set(saved); +} + +/// Print the AArch64 exceptions status. +#[rustfmt::skip] +pub fn print_state() { + use crate::info; + + let to_mask_str = |x| -> _ { + if x { "Masked" } else { "Unmasked" } + }; + + info!(" Debug: {}", to_mask_str(is_masked::())); + info!(" SError: {}", to_mask_str(is_masked::())); + info!(" IRQ: {}", to_mask_str(is_masked::())); + info!(" FIQ: {}", to_mask_str(is_masked::())); +} diff --git a/20_timer_callbacks/kernel/src/_arch/aarch64/memory/mmu.rs b/20_timer_callbacks/kernel/src/_arch/aarch64/memory/mmu.rs new file mode 100644 index 00000000..3d6c18b7 --- /dev/null +++ b/20_timer_callbacks/kernel/src/_arch/aarch64/memory/mmu.rs @@ -0,0 +1,158 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2018-2022 Andre Richter + +//! Memory Management Unit Driver. +//! +//! Only 64 KiB granule is supported. +//! +//! # Orientation +//! +//! Since arch modules are imported into generic modules using the path attribute, the path of this +//! file is: +//! +//! crate::memory::mmu::arch_mmu + +use crate::{ + bsp, memory, + memory::{mmu::TranslationGranule, Address, Physical}, +}; +use core::intrinsics::unlikely; +use cortex_a::{asm::barrier, registers::*}; +use tock_registers::interfaces::{ReadWriteable, Readable, Writeable}; + +//-------------------------------------------------------------------------------------------------- +// Private Definitions +//-------------------------------------------------------------------------------------------------- + +/// Memory Management Unit type. +struct MemoryManagementUnit; + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +pub type Granule512MiB = TranslationGranule<{ 512 * 1024 * 1024 }>; +pub type Granule64KiB = TranslationGranule<{ 64 * 1024 }>; + +/// Constants for indexing the MAIR_EL1. +#[allow(dead_code)] +pub mod mair { + pub const DEVICE: u64 = 0; + pub const NORMAL: u64 = 1; +} + +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +static MMU: MemoryManagementUnit = MemoryManagementUnit; + +//-------------------------------------------------------------------------------------------------- +// Private Code +//-------------------------------------------------------------------------------------------------- + +impl memory::mmu::AddressSpace { + /// Checks for architectural restrictions. + pub const fn arch_address_space_size_sanity_checks() { + // Size must be at least one full 512 MiB table. + assert!((AS_SIZE % Granule512MiB::SIZE) == 0); + + // Check for 48 bit virtual address size as maximum, which is supported by any ARMv8 + // version. + assert!(AS_SIZE <= (1 << 48)); + } +} + +impl MemoryManagementUnit { + /// Setup function for the MAIR_EL1 register. + #[inline(always)] + fn set_up_mair(&self) { + // Define the memory types being mapped. + MAIR_EL1.write( + // Attribute 1 - Cacheable normal DRAM. + MAIR_EL1::Attr1_Normal_Outer::WriteBack_NonTransient_ReadWriteAlloc + + MAIR_EL1::Attr1_Normal_Inner::WriteBack_NonTransient_ReadWriteAlloc + + + // Attribute 0 - Device. + MAIR_EL1::Attr0_Device::nonGathering_nonReordering_EarlyWriteAck, + ); + } + + /// Configure various settings of stage 1 of the EL1 translation regime. + #[inline(always)] + fn configure_translation_control(&self) { + let t1sz = (64 - bsp::memory::mmu::KernelVirtAddrSpace::SIZE_SHIFT) as u64; + + TCR_EL1.write( + TCR_EL1::TBI1::Used + + TCR_EL1::IPS::Bits_40 + + TCR_EL1::TG1::KiB_64 + + TCR_EL1::SH1::Inner + + TCR_EL1::ORGN1::WriteBack_ReadAlloc_WriteAlloc_Cacheable + + TCR_EL1::IRGN1::WriteBack_ReadAlloc_WriteAlloc_Cacheable + + TCR_EL1::EPD1::EnableTTBR1Walks + + TCR_EL1::A1::TTBR1 + + TCR_EL1::T1SZ.val(t1sz) + + TCR_EL1::EPD0::DisableTTBR0Walks, + ); + } +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +/// Return a reference to the MMU instance. +pub fn mmu() -> &'static impl memory::mmu::interface::MMU { + &MMU +} + +//------------------------------------------------------------------------------ +// OS Interface Code +//------------------------------------------------------------------------------ +use memory::mmu::MMUEnableError; + +impl memory::mmu::interface::MMU for MemoryManagementUnit { + unsafe fn enable_mmu_and_caching( + &self, + phys_tables_base_addr: Address, + ) -> Result<(), MMUEnableError> { + if unlikely(self.is_enabled()) { + return Err(MMUEnableError::AlreadyEnabled); + } + + // Fail early if translation granule is not supported. + if unlikely(!ID_AA64MMFR0_EL1.matches_all(ID_AA64MMFR0_EL1::TGran64::Supported)) { + return Err(MMUEnableError::Other( + "Translation granule not supported in HW", + )); + } + + // Prepare the memory attribute indirection register. + self.set_up_mair(); + + // Set the "Translation Table Base Register". + TTBR1_EL1.set_baddr(phys_tables_base_addr.as_usize() as u64); + + self.configure_translation_control(); + + // Switch the MMU on. + // + // First, force all previous changes to be seen before the MMU is enabled. + barrier::isb(barrier::SY); + + // Enable the MMU and turn on data and instruction caching. + SCTLR_EL1.modify(SCTLR_EL1::M::Enable + SCTLR_EL1::C::Cacheable + SCTLR_EL1::I::Cacheable); + + // Force MMU init to complete before next instruction. + barrier::isb(barrier::SY); + + Ok(()) + } + + #[inline(always)] + fn is_enabled(&self) -> bool { + SCTLR_EL1.matches_all(SCTLR_EL1::M::Enable) + } +} diff --git a/20_timer_callbacks/kernel/src/_arch/aarch64/memory/mmu/translation_table.rs b/20_timer_callbacks/kernel/src/_arch/aarch64/memory/mmu/translation_table.rs new file mode 100644 index 00000000..f0b4ac85 --- /dev/null +++ b/20_timer_callbacks/kernel/src/_arch/aarch64/memory/mmu/translation_table.rs @@ -0,0 +1,521 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2021-2022 Andre Richter + +//! Architectural translation table. +//! +//! Only 64 KiB granule is supported. +//! +//! # Orientation +//! +//! Since arch modules are imported into generic modules using the path attribute, the path of this +//! file is: +//! +//! crate::memory::mmu::translation_table::arch_translation_table + +use crate::{ + bsp, + memory::{ + self, + mmu::{ + arch_mmu::{Granule512MiB, Granule64KiB}, + AccessPermissions, AttributeFields, MemAttributes, MemoryRegion, PageAddress, + }, + Address, Physical, Virtual, + }, +}; +use core::convert; +use tock_registers::{ + interfaces::{Readable, Writeable}, + register_bitfields, + registers::InMemoryRegister, +}; + +//-------------------------------------------------------------------------------------------------- +// Private Definitions +//-------------------------------------------------------------------------------------------------- + +// A table descriptor, as per ARMv8-A Architecture Reference Manual Figure D5-15. +register_bitfields! {u64, + STAGE1_TABLE_DESCRIPTOR [ + /// Physical address of the next descriptor. + NEXT_LEVEL_TABLE_ADDR_64KiB OFFSET(16) NUMBITS(32) [], // [47:16] + + TYPE OFFSET(1) NUMBITS(1) [ + Block = 0, + Table = 1 + ], + + VALID OFFSET(0) NUMBITS(1) [ + False = 0, + True = 1 + ] + ] +} + +// A level 3 page descriptor, as per ARMv8-A Architecture Reference Manual Figure D5-17. +register_bitfields! {u64, + STAGE1_PAGE_DESCRIPTOR [ + /// Unprivileged execute-never. + UXN OFFSET(54) NUMBITS(1) [ + False = 0, + True = 1 + ], + + /// Privileged execute-never. + PXN OFFSET(53) NUMBITS(1) [ + False = 0, + True = 1 + ], + + /// Physical address of the next table descriptor (lvl2) or the page descriptor (lvl3). + OUTPUT_ADDR_64KiB OFFSET(16) NUMBITS(32) [], // [47:16] + + /// Access flag. + AF OFFSET(10) NUMBITS(1) [ + False = 0, + True = 1 + ], + + /// Shareability field. + SH OFFSET(8) NUMBITS(2) [ + OuterShareable = 0b10, + InnerShareable = 0b11 + ], + + /// Access Permissions. + AP OFFSET(6) NUMBITS(2) [ + RW_EL1 = 0b00, + RW_EL1_EL0 = 0b01, + RO_EL1 = 0b10, + RO_EL1_EL0 = 0b11 + ], + + /// Memory attributes index into the MAIR_EL1 register. + AttrIndx OFFSET(2) NUMBITS(3) [], + + TYPE OFFSET(1) NUMBITS(1) [ + Reserved_Invalid = 0, + Page = 1 + ], + + VALID OFFSET(0) NUMBITS(1) [ + False = 0, + True = 1 + ] + ] +} + +/// A table descriptor for 64 KiB aperture. +/// +/// The output points to the next table. +#[derive(Copy, Clone)] +#[repr(C)] +struct TableDescriptor { + value: u64, +} + +/// A page descriptor with 64 KiB aperture. +/// +/// The output points to physical memory. +#[derive(Copy, Clone)] +#[repr(C)] +struct PageDescriptor { + value: u64, +} + +trait StartAddr { + fn virt_start_addr(&self) -> Address; +} + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +/// Big monolithic struct for storing the translation tables. Individual levels must be 64 KiB +/// aligned, so the lvl3 is put first. +#[repr(C)] +#[repr(align(65536))] +pub struct FixedSizeTranslationTable { + /// Page descriptors, covering 64 KiB windows per entry. + lvl3: [[PageDescriptor; 8192]; NUM_TABLES], + + /// Table descriptors, covering 512 MiB windows. + lvl2: [TableDescriptor; NUM_TABLES], + + /// Have the tables been initialized? + initialized: bool, +} + +//-------------------------------------------------------------------------------------------------- +// Private Code +//-------------------------------------------------------------------------------------------------- + +impl StartAddr for [T; N] { + fn virt_start_addr(&self) -> Address { + Address::new(self as *const _ as usize) + } +} + +impl TableDescriptor { + /// Create an instance. + /// + /// Descriptor is invalid by default. + pub const fn new_zeroed() -> Self { + Self { value: 0 } + } + + /// Create an instance pointing to the supplied address. + pub fn from_next_lvl_table_addr(phys_next_lvl_table_addr: Address) -> Self { + let val = InMemoryRegister::::new(0); + + let shifted = phys_next_lvl_table_addr.as_usize() >> Granule64KiB::SHIFT; + val.write( + STAGE1_TABLE_DESCRIPTOR::NEXT_LEVEL_TABLE_ADDR_64KiB.val(shifted as u64) + + STAGE1_TABLE_DESCRIPTOR::TYPE::Table + + STAGE1_TABLE_DESCRIPTOR::VALID::True, + ); + + TableDescriptor { value: val.get() } + } +} + +/// Convert the kernel's generic memory attributes to HW-specific attributes of the MMU. +impl convert::From + for tock_registers::fields::FieldValue +{ + fn from(attribute_fields: AttributeFields) -> Self { + // Memory attributes. + let mut desc = match attribute_fields.mem_attributes { + MemAttributes::CacheableDRAM => { + STAGE1_PAGE_DESCRIPTOR::SH::InnerShareable + + STAGE1_PAGE_DESCRIPTOR::AttrIndx.val(memory::mmu::arch_mmu::mair::NORMAL) + } + MemAttributes::Device => { + STAGE1_PAGE_DESCRIPTOR::SH::OuterShareable + + STAGE1_PAGE_DESCRIPTOR::AttrIndx.val(memory::mmu::arch_mmu::mair::DEVICE) + } + }; + + // Access Permissions. + desc += match attribute_fields.acc_perms { + AccessPermissions::ReadOnly => STAGE1_PAGE_DESCRIPTOR::AP::RO_EL1, + AccessPermissions::ReadWrite => STAGE1_PAGE_DESCRIPTOR::AP::RW_EL1, + }; + + // The execute-never attribute is mapped to PXN in AArch64. + desc += if attribute_fields.execute_never { + STAGE1_PAGE_DESCRIPTOR::PXN::True + } else { + STAGE1_PAGE_DESCRIPTOR::PXN::False + }; + + // Always set unprivileged exectue-never as long as userspace is not implemented yet. + desc += STAGE1_PAGE_DESCRIPTOR::UXN::True; + + desc + } +} + +/// Convert the HW-specific attributes of the MMU to kernel's generic memory attributes. +impl convert::TryFrom> for AttributeFields { + type Error = &'static str; + + fn try_from( + desc: InMemoryRegister, + ) -> Result { + let mem_attributes = match desc.read(STAGE1_PAGE_DESCRIPTOR::AttrIndx) { + memory::mmu::arch_mmu::mair::NORMAL => MemAttributes::CacheableDRAM, + memory::mmu::arch_mmu::mair::DEVICE => MemAttributes::Device, + _ => return Err("Unexpected memory attribute"), + }; + + let acc_perms = match desc.read_as_enum(STAGE1_PAGE_DESCRIPTOR::AP) { + Some(STAGE1_PAGE_DESCRIPTOR::AP::Value::RO_EL1) => AccessPermissions::ReadOnly, + Some(STAGE1_PAGE_DESCRIPTOR::AP::Value::RW_EL1) => AccessPermissions::ReadWrite, + _ => return Err("Unexpected access permission"), + }; + + let execute_never = desc.read(STAGE1_PAGE_DESCRIPTOR::PXN) > 0; + + Ok(AttributeFields { + mem_attributes, + acc_perms, + execute_never, + }) + } +} + +impl PageDescriptor { + /// Create an instance. + /// + /// Descriptor is invalid by default. + pub const fn new_zeroed() -> Self { + Self { value: 0 } + } + + /// Create an instance. + pub fn from_output_page_addr( + phys_output_page_addr: PageAddress, + attribute_fields: &AttributeFields, + ) -> Self { + let val = InMemoryRegister::::new(0); + + let shifted = phys_output_page_addr.into_inner().as_usize() >> Granule64KiB::SHIFT; + val.write( + STAGE1_PAGE_DESCRIPTOR::OUTPUT_ADDR_64KiB.val(shifted as u64) + + STAGE1_PAGE_DESCRIPTOR::AF::True + + STAGE1_PAGE_DESCRIPTOR::TYPE::Page + + STAGE1_PAGE_DESCRIPTOR::VALID::True + + (*attribute_fields).into(), + ); + + Self { value: val.get() } + } + + /// Returns the valid bit. + fn is_valid(&self) -> bool { + InMemoryRegister::::new(self.value) + .is_set(STAGE1_PAGE_DESCRIPTOR::VALID) + } + + /// Returns the output page. + fn output_page_addr(&self) -> PageAddress { + let shifted = InMemoryRegister::::new(self.value) + .read(STAGE1_PAGE_DESCRIPTOR::OUTPUT_ADDR_64KiB) as usize; + + PageAddress::from(shifted << Granule64KiB::SHIFT) + } + + /// Returns the attributes. + fn try_attributes(&self) -> Result { + InMemoryRegister::::new(self.value).try_into() + } +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +impl memory::mmu::AssociatedTranslationTable + for memory::mmu::AddressSpace +where + [u8; Self::SIZE >> Granule512MiB::SHIFT]: Sized, +{ + type TableStartFromTop = + FixedSizeTranslationTable<{ Self::SIZE >> Granule512MiB::SHIFT }, true>; + + type TableStartFromBottom = + FixedSizeTranslationTable<{ Self::SIZE >> Granule512MiB::SHIFT }, false>; +} + +impl + FixedSizeTranslationTable +{ + const START_FROM_TOP_OFFSET: Address = + Address::new((usize::MAX - (Granule512MiB::SIZE * NUM_TABLES)) + 1); + + /// Create an instance. + #[allow(clippy::assertions_on_constants)] + const fn _new(for_precompute: bool) -> Self { + assert!(bsp::memory::mmu::KernelGranule::SIZE == Granule64KiB::SIZE); + + // Can't have a zero-sized address space. + assert!(NUM_TABLES > 0); + + Self { + lvl3: [[PageDescriptor::new_zeroed(); 8192]; NUM_TABLES], + lvl2: [TableDescriptor::new_zeroed(); NUM_TABLES], + initialized: for_precompute, + } + } + + pub const fn new_for_precompute() -> Self { + Self::_new(true) + } + + #[cfg(test)] + pub fn new_for_runtime() -> Self { + Self::_new(false) + } + + /// Helper to calculate the lvl2 and lvl3 indices from an address. + #[inline(always)] + fn lvl2_lvl3_index_from_page_addr( + &self, + virt_page_addr: PageAddress, + ) -> Result<(usize, usize), &'static str> { + let mut addr = virt_page_addr.into_inner(); + + if START_FROM_TOP { + addr = addr - Self::START_FROM_TOP_OFFSET; + } + + let lvl2_index = addr.as_usize() >> Granule512MiB::SHIFT; + let lvl3_index = (addr.as_usize() & Granule512MiB::MASK) >> Granule64KiB::SHIFT; + + if lvl2_index > (NUM_TABLES - 1) { + return Err("Virtual page is out of bounds of translation table"); + } + + Ok((lvl2_index, lvl3_index)) + } + + /// Returns the PageDescriptor corresponding to the supplied page address. + #[inline(always)] + fn page_descriptor_from_page_addr( + &self, + virt_page_addr: PageAddress, + ) -> Result<&PageDescriptor, &'static str> { + let (lvl2_index, lvl3_index) = self.lvl2_lvl3_index_from_page_addr(virt_page_addr)?; + let desc = &self.lvl3[lvl2_index][lvl3_index]; + + Ok(desc) + } + + /// Sets the PageDescriptor corresponding to the supplied page address. + /// + /// Doesn't allow overriding an already valid page. + #[inline(always)] + fn set_page_descriptor_from_page_addr( + &mut self, + virt_page_addr: PageAddress, + new_desc: &PageDescriptor, + ) -> Result<(), &'static str> { + let (lvl2_index, lvl3_index) = self.lvl2_lvl3_index_from_page_addr(virt_page_addr)?; + let desc = &mut self.lvl3[lvl2_index][lvl3_index]; + + if desc.is_valid() { + return Err("Virtual page is already mapped"); + } + + *desc = *new_desc; + Ok(()) + } +} + +//------------------------------------------------------------------------------ +// OS Interface Code +//------------------------------------------------------------------------------ + +impl + memory::mmu::translation_table::interface::TranslationTable + for FixedSizeTranslationTable +{ + fn init(&mut self) -> Result<(), &'static str> { + if self.initialized { + return Ok(()); + } + + // Populate the l2 entries. + for (lvl2_nr, lvl2_entry) in self.lvl2.iter_mut().enumerate() { + let virt_table_addr = self.lvl3[lvl2_nr].virt_start_addr(); + let phys_table_addr = memory::mmu::try_kernel_virt_addr_to_phys_addr(virt_table_addr)?; + + let new_desc = TableDescriptor::from_next_lvl_table_addr(phys_table_addr); + *lvl2_entry = new_desc; + } + + self.initialized = true; + + Ok(()) + } + + unsafe fn map_at( + &mut self, + virt_region: &MemoryRegion, + phys_region: &MemoryRegion, + attr: &AttributeFields, + ) -> Result<(), &'static str> { + assert!(self.initialized, "Translation tables not initialized"); + + if virt_region.size() != phys_region.size() { + return Err("Tried to map memory regions with unequal sizes"); + } + + if phys_region.end_exclusive_page_addr() > bsp::memory::phys_addr_space_end_exclusive_addr() + { + return Err("Tried to map outside of physical address space"); + } + + let iter = phys_region.into_iter().zip(virt_region.into_iter()); + for (phys_page_addr, virt_page_addr) in iter { + let new_desc = PageDescriptor::from_output_page_addr(phys_page_addr, attr); + let virt_page = virt_page_addr; + + self.set_page_descriptor_from_page_addr(virt_page, &new_desc)?; + } + + Ok(()) + } + + fn try_virt_page_addr_to_phys_page_addr( + &self, + virt_page_addr: PageAddress, + ) -> Result, &'static str> { + let page_desc = self.page_descriptor_from_page_addr(virt_page_addr)?; + + if !page_desc.is_valid() { + return Err("Page marked invalid"); + } + + Ok(page_desc.output_page_addr()) + } + + fn try_page_attributes( + &self, + virt_page_addr: PageAddress, + ) -> Result { + let page_desc = self.page_descriptor_from_page_addr(virt_page_addr)?; + + if !page_desc.is_valid() { + return Err("Page marked invalid"); + } + + page_desc.try_attributes() + } + + /// Try to translate a virtual address to a physical address. + /// + /// Will only succeed if there exists a valid mapping for the input address. + fn try_virt_addr_to_phys_addr( + &self, + virt_addr: Address, + ) -> Result, &'static str> { + let virt_page = PageAddress::from(virt_addr.align_down_page()); + let phys_page = self.try_virt_page_addr_to_phys_page_addr(virt_page)?; + + Ok(phys_page.into_inner() + virt_addr.offset_into_page()) + } +} + +//-------------------------------------------------------------------------------------------------- +// Testing +//-------------------------------------------------------------------------------------------------- + +#[cfg(test)] +pub type MinSizeTranslationTable = FixedSizeTranslationTable<1, true>; + +#[cfg(test)] +mod tests { + use super::*; + use test_macros::kernel_test; + + /// Check if the size of `struct TableDescriptor` is as expected. + #[kernel_test] + fn size_of_tabledescriptor_equals_64_bit() { + assert_eq!( + core::mem::size_of::(), + core::mem::size_of::() + ); + } + + /// Check if the size of `struct PageDescriptor` is as expected. + #[kernel_test] + fn size_of_pagedescriptor_equals_64_bit() { + assert_eq!( + core::mem::size_of::(), + core::mem::size_of::() + ); + } +} diff --git a/20_timer_callbacks/kernel/src/_arch/aarch64/time.rs b/20_timer_callbacks/kernel/src/_arch/aarch64/time.rs new file mode 100644 index 00000000..568363fc --- /dev/null +++ b/20_timer_callbacks/kernel/src/_arch/aarch64/time.rs @@ -0,0 +1,193 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2018-2022 Andre Richter + +//! Architectural timer primitives. +//! +//! # Orientation +//! +//! Since arch modules are imported into generic modules using the path attribute, the path of this +//! file is: +//! +//! crate::time::arch_time + +use crate::{ + bsp::{self, exception}, + warn, +}; +use core::{ + num::{NonZeroU128, NonZeroU32, NonZeroU64}, + ops::{Add, Div}, + time::Duration, +}; +use cortex_a::{asm::barrier, registers::*}; +use tock_registers::interfaces::{ReadWriteable, Readable, Writeable}; + +//-------------------------------------------------------------------------------------------------- +// Private Definitions +//-------------------------------------------------------------------------------------------------- + +const NANOSEC_PER_SEC: NonZeroU64 = NonZeroU64::new(1_000_000_000).unwrap(); + +#[derive(Copy, Clone, PartialOrd, PartialEq)] +struct GenericTimerCounterValue(u64); + +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +/// Boot assembly code overwrites this value with the value of CNTFRQ_EL0 before any Rust code is +/// executed. This given value here is just a (safe) dummy. +#[no_mangle] +static ARCH_TIMER_COUNTER_FREQUENCY: NonZeroU32 = NonZeroU32::MIN; + +//-------------------------------------------------------------------------------------------------- +// Private Code +//-------------------------------------------------------------------------------------------------- + +fn arch_timer_counter_frequency() -> NonZeroU32 { + // Read volatile is needed here to prevent the compiler from optimizing + // ARCH_TIMER_COUNTER_FREQUENCY away. + // + // This is safe, because all the safety requirements as stated in read_volatile()'s + // documentation are fulfilled. + unsafe { core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY) } +} + +impl GenericTimerCounterValue { + pub const MAX: Self = GenericTimerCounterValue(u64::MAX); +} + +impl Add for GenericTimerCounterValue { + type Output = Self; + + fn add(self, other: Self) -> Self { + GenericTimerCounterValue(self.0.wrapping_add(other.0)) + } +} + +impl From for Duration { + fn from(counter_value: GenericTimerCounterValue) -> Self { + if counter_value.0 == 0 { + return Duration::ZERO; + } + + let frequency: NonZeroU64 = arch_timer_counter_frequency().into(); + + // Div implementation for u64 cannot panic. + let secs = counter_value.0.div(frequency); + + // This is safe, because frequency can never be greater than u32::MAX, which means the + // largest theoretical value for sub_second_counter_value is (u32::MAX - 1). Therefore, + // (sub_second_counter_value * NANOSEC_PER_SEC) cannot overflow an u64. + // + // The subsequent division ensures the result fits into u32, since the max result is smaller + // than NANOSEC_PER_SEC. Therefore, just cast it to u32 using `as`. + let sub_second_counter_value = counter_value.0 % frequency; + let nanos = unsafe { sub_second_counter_value.unchecked_mul(u64::from(NANOSEC_PER_SEC)) } + .div(frequency) as u32; + + Duration::new(secs, nanos) + } +} + +fn max_duration() -> Duration { + Duration::from(GenericTimerCounterValue::MAX) +} + +impl TryFrom for GenericTimerCounterValue { + type Error = &'static str; + + fn try_from(duration: Duration) -> Result { + if duration < resolution() { + return Ok(GenericTimerCounterValue(0)); + } + + if duration > max_duration() { + return Err("Conversion error. Duration too big"); + } + + let frequency: u128 = u32::from(arch_timer_counter_frequency()) as u128; + let duration: u128 = duration.as_nanos(); + + // This is safe, because frequency can never be greater than u32::MAX, and + // (Duration::MAX.as_nanos() * u32::MAX) < u128::MAX. + let counter_value = + unsafe { duration.unchecked_mul(frequency) }.div(NonZeroU128::from(NANOSEC_PER_SEC)); + + // Since we checked above that we are <= max_duration(), just cast to u64. + Ok(GenericTimerCounterValue(counter_value as u64)) + } +} + +#[inline(always)] +fn read_cntpct() -> GenericTimerCounterValue { + // Prevent that the counter is read ahead of time due to out-of-order execution. + barrier::isb(barrier::SY); + let cnt = CNTPCT_EL0.get(); + + GenericTimerCounterValue(cnt) +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +/// The timer's resolution. +pub fn resolution() -> Duration { + Duration::from(GenericTimerCounterValue(1)) +} + +/// The uptime since power-on of the device. +/// +/// This includes time consumed by firmware and bootloaders. +pub fn uptime() -> Duration { + read_cntpct().into() +} + +/// Spin for a given duration. +pub fn spin_for(duration: Duration) { + let curr_counter_value = read_cntpct(); + + let counter_value_delta: GenericTimerCounterValue = match duration.try_into() { + Err(msg) => { + warn!("spin_for: {}. Skipping", msg); + return; + } + Ok(val) => val, + }; + let counter_value_target = curr_counter_value + counter_value_delta; + + // Busy wait. + // + // Read CNTPCT_EL0 directly to avoid the ISB that is part of [`read_cntpct`]. + while GenericTimerCounterValue(CNTPCT_EL0.get()) < counter_value_target {} +} + +/// The associated IRQ number. +pub const fn timeout_irq() -> exception::asynchronous::IRQNumber { + bsp::exception::asynchronous::irq_map::ARM_NS_PHYISCAL_TIMER +} + +/// Program a timer IRQ to be fired after `delay` has passed. +pub fn set_timeout_irq(due_time: Duration) { + let counter_value_target: GenericTimerCounterValue = match due_time.try_into() { + Err(msg) => { + warn!("set_timeout: {}. Skipping", msg); + return; + } + Ok(val) => val, + }; + + // Set the compare value register. + CNTP_CVAL_EL0.set(counter_value_target.0); + + // Kick off the timer. + CNTP_CTL_EL0.modify(CNTP_CTL_EL0::ENABLE::SET + CNTP_CTL_EL0::IMASK::CLEAR); +} + +/// Conclude a pending timeout IRQ. +pub fn conclude_timeout_irq() { + // Disable counting. De-asserts the IRQ. + CNTP_CTL_EL0.modify(CNTP_CTL_EL0::ENABLE::CLEAR); +} diff --git a/20_timer_callbacks/kernel/src/backtrace.rs b/20_timer_callbacks/kernel/src/backtrace.rs new file mode 100644 index 00000000..22de6c48 --- /dev/null +++ b/20_timer_callbacks/kernel/src/backtrace.rs @@ -0,0 +1,114 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2022 Andre Richter + +//! Backtracing support. + +#[cfg(target_arch = "aarch64")] +#[path = "_arch/aarch64/backtrace.rs"] +mod arch_backtrace; + +use crate::{ + memory::{Address, Virtual}, + symbols, +}; +use core::fmt; + +//-------------------------------------------------------------------------------------------------- +// Architectural Public Reexports +//-------------------------------------------------------------------------------------------------- +#[cfg(feature = "test_build")] +pub use arch_backtrace::{corrupt_link, corrupt_previous_frame_addr}; + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +/// A backtrace item. +#[allow(missing_docs)] +pub enum BacktraceItem { + InvalidFramePointer(Address), + InvalidLink(Address), + Link(Address), +} + +/// Pseudo-struct for printing a backtrace using its fmt::Display implementation. +pub struct Backtrace; + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +impl fmt::Display for Backtrace { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + writeln!(f, "Backtrace:")?; + writeln!( + f, + " ----------------------------------------------------------------------------------------------" + )?; + writeln!( + f, + " Address Function containing address" + )?; + writeln!( + f, + " ----------------------------------------------------------------------------------------------" + )?; + + let mut fmt_res: fmt::Result = Ok(()); + let trace_formatter = + |maybe_iter: Option<&mut dyn Iterator>| match maybe_iter { + None => fmt_res = writeln!(f, "ERROR! No valid stack frame found"), + Some(iter) => { + // Since the backtrace is printed, the first function is always + // core::fmt::write. Skip 1 so it is excluded and doesn't bloat the output. + for (i, backtrace_res) in iter.skip(1).enumerate() { + match backtrace_res { + BacktraceItem::InvalidFramePointer(addr) => { + fmt_res = writeln!( + f, + " {:>2}. ERROR! \ + Encountered invalid frame pointer ({}) during backtrace", + i + 1, + addr + ); + } + BacktraceItem::InvalidLink(addr) => { + fmt_res = writeln!( + f, + " {:>2}. ERROR! \ + Link address ({}) is not contained in kernel .text section", + i + 1, + addr + ); + } + BacktraceItem::Link(addr) => { + fmt_res = writeln!( + f, + " {:>2}. {:016x} | {:<50}", + i + 1, + addr.as_usize(), + match symbols::lookup_symbol(addr) { + Some(sym) => sym.name(), + _ => "Symbol not found", + } + ) + } + }; + + if fmt_res.is_err() { + break; + } + } + } + }; + + arch_backtrace::backtrace(trace_formatter); + fmt_res?; + + writeln!( + f, + " ----------------------------------------------------------------------------------------------" + ) + } +} diff --git a/20_timer_callbacks/kernel/src/bsp.rs b/20_timer_callbacks/kernel/src/bsp.rs new file mode 100644 index 00000000..824787f6 --- /dev/null +++ b/20_timer_callbacks/kernel/src/bsp.rs @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2018-2022 Andre Richter + +//! Conditional reexporting of Board Support Packages. + +mod device_driver; + +#[cfg(any(feature = "bsp_rpi3", feature = "bsp_rpi4"))] +mod raspberrypi; + +#[cfg(any(feature = "bsp_rpi3", feature = "bsp_rpi4"))] +pub use raspberrypi::*; diff --git a/20_timer_callbacks/kernel/src/bsp/device_driver.rs b/20_timer_callbacks/kernel/src/bsp/device_driver.rs new file mode 100644 index 00000000..eafaf775 --- /dev/null +++ b/20_timer_callbacks/kernel/src/bsp/device_driver.rs @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2018-2022 Andre Richter + +//! Device driver. + +#[cfg(feature = "bsp_rpi4")] +mod arm; +#[cfg(any(feature = "bsp_rpi3", feature = "bsp_rpi4"))] +mod bcm; +mod common; + +#[cfg(feature = "bsp_rpi4")] +pub use arm::*; +#[cfg(any(feature = "bsp_rpi3", feature = "bsp_rpi4"))] +pub use bcm::*; diff --git a/20_timer_callbacks/kernel/src/bsp/device_driver/arm.rs b/20_timer_callbacks/kernel/src/bsp/device_driver/arm.rs new file mode 100644 index 00000000..e83e24c9 --- /dev/null +++ b/20_timer_callbacks/kernel/src/bsp/device_driver/arm.rs @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2020-2022 Andre Richter + +//! ARM driver top level. + +pub mod gicv2; + +pub use gicv2::*; diff --git a/20_timer_callbacks/kernel/src/bsp/device_driver/arm/gicv2.rs b/20_timer_callbacks/kernel/src/bsp/device_driver/arm/gicv2.rs new file mode 100644 index 00000000..fee8bb4c --- /dev/null +++ b/20_timer_callbacks/kernel/src/bsp/device_driver/arm/gicv2.rs @@ -0,0 +1,234 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2020-2022 Andre Richter + +//! GICv2 Driver - ARM Generic Interrupt Controller v2. +//! +//! The following is a collection of excerpts with useful information from +//! - `Programmer's Guide for ARMv8-A` +//! - `ARM Generic Interrupt Controller Architecture Specification` +//! +//! # Programmer's Guide - 10.6.1 Configuration +//! +//! The GIC is accessed as a memory-mapped peripheral. +//! +//! All cores can access the common Distributor, but the CPU interface is banked, that is, each core +//! uses the same address to access its own private CPU interface. +//! +//! It is not possible for a core to access the CPU interface of another core. +//! +//! # Architecture Specification - 10.6.2 Initialization +//! +//! Both the Distributor and the CPU interfaces are disabled at reset. The GIC must be initialized +//! after reset before it can deliver interrupts to the core. +//! +//! In the Distributor, software must configure the priority, target, security and enable individual +//! interrupts. The Distributor must subsequently be enabled through its control register +//! (GICD_CTLR). For each CPU interface, software must program the priority mask and preemption +//! settings. +//! +//! Each CPU interface block itself must be enabled through its control register (GICD_CTLR). This +//! prepares the GIC to deliver interrupts to the core. +//! +//! Before interrupts are expected in the core, software prepares the core to take interrupts by +//! setting a valid interrupt vector in the vector table, and clearing interrupt mask bits in +//! PSTATE, and setting the routing controls. +//! +//! The entire interrupt mechanism in the system can be disabled by disabling the Distributor. +//! Interrupt delivery to an individual core can be disabled by disabling its CPU interface. +//! Individual interrupts can also be disabled (or enabled) in the distributor. +//! +//! For an interrupt to reach the core, the individual interrupt, Distributor and CPU interface must +//! all be enabled. The interrupt also needs to be of sufficient priority, that is, higher than the +//! core's priority mask. +//! +//! # Architecture Specification - 1.4.2 Interrupt types +//! +//! - Peripheral interrupt +//! - Private Peripheral Interrupt (PPI) +//! - This is a peripheral interrupt that is specific to a single processor. +//! - Shared Peripheral Interrupt (SPI) +//! - This is a peripheral interrupt that the Distributor can route to any of a specified +//! combination of processors. +//! +//! - Software-generated interrupt (SGI) +//! - This is an interrupt generated by software writing to a GICD_SGIR register in the GIC. The +//! system uses SGIs for interprocessor communication. +//! - An SGI has edge-triggered properties. The software triggering of the interrupt is +//! equivalent to the edge transition of the interrupt request signal. +//! - When an SGI occurs in a multiprocessor implementation, the CPUID field in the Interrupt +//! Acknowledge Register, GICC_IAR, or the Aliased Interrupt Acknowledge Register, GICC_AIAR, +//! identifies the processor that requested the interrupt. +//! +//! # Architecture Specification - 2.2.1 Interrupt IDs +//! +//! Interrupts from sources are identified using ID numbers. Each CPU interface can see up to 1020 +//! interrupts. The banking of SPIs and PPIs increases the total number of interrupts supported by +//! the Distributor. +//! +//! The GIC assigns interrupt ID numbers ID0-ID1019 as follows: +//! - Interrupt numbers 32..1019 are used for SPIs. +//! - Interrupt numbers 0..31 are used for interrupts that are private to a CPU interface. These +//! interrupts are banked in the Distributor. +//! - A banked interrupt is one where the Distributor can have multiple interrupts with the +//! same ID. A banked interrupt is identified uniquely by its ID number and its associated +//! CPU interface number. Of the banked interrupt IDs: +//! - 00..15 SGIs +//! - 16..31 PPIs + +mod gicc; +mod gicd; + +use crate::{ + bsp::{self, device_driver::common::BoundedUsize}, + cpu, driver, exception, + memory::{Address, Virtual}, + synchronization, + synchronization::InitStateLock, +}; +use alloc::vec::Vec; + +//-------------------------------------------------------------------------------------------------- +// Private Definitions +//-------------------------------------------------------------------------------------------------- + +type HandlerTable = Vec>>; + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +/// Used for the associated type of trait [`exception::asynchronous::interface::IRQManager`]. +pub type IRQNumber = BoundedUsize<{ GICv2::MAX_IRQ_NUMBER }>; + +/// Representation of the GIC. +pub struct GICv2 { + /// The Distributor. + gicd: gicd::GICD, + + /// The CPU Interface. + gicc: gicc::GICC, + + /// Stores registered IRQ handlers. Writable only during kernel init. RO afterwards. + handler_table: InitStateLock, +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +impl GICv2 { + const MAX_IRQ_NUMBER: usize = 1019; + + pub const COMPATIBLE: &'static str = "GICv2 (ARM Generic Interrupt Controller v2)"; + + /// Create an instance. + /// + /// # Safety + /// + /// - The user must ensure to provide a correct MMIO start address. + pub const unsafe fn new( + gicd_mmio_start_addr: Address, + gicc_mmio_start_addr: Address, + ) -> Self { + Self { + gicd: gicd::GICD::new(gicd_mmio_start_addr), + gicc: gicc::GICC::new(gicc_mmio_start_addr), + handler_table: InitStateLock::new(Vec::new()), + } + } +} + +//------------------------------------------------------------------------------ +// OS Interface Code +//------------------------------------------------------------------------------ +use synchronization::interface::ReadWriteEx; + +impl driver::interface::DeviceDriver for GICv2 { + type IRQNumberType = IRQNumber; + + fn compatible(&self) -> &'static str { + Self::COMPATIBLE + } + + unsafe fn init(&self) -> Result<(), &'static str> { + self.handler_table + .write(|table| table.resize(IRQNumber::MAX_INCLUSIVE + 1, None)); + + if bsp::cpu::BOOT_CORE_ID == cpu::smp::core_id() { + self.gicd.boot_core_init(); + } + + self.gicc.priority_accept_all(); + self.gicc.enable(); + + Ok(()) + } +} + +impl exception::asynchronous::interface::IRQManager for GICv2 { + type IRQNumberType = IRQNumber; + + fn register_handler( + &self, + irq_handler_descriptor: exception::asynchronous::IRQHandlerDescriptor, + ) -> Result<(), &'static str> { + self.handler_table.write(|table| { + let irq_number = irq_handler_descriptor.number().get(); + + if table[irq_number].is_some() { + return Err("IRQ handler already registered"); + } + + table[irq_number] = Some(irq_handler_descriptor); + + Ok(()) + }) + } + + fn enable(&self, irq_number: &Self::IRQNumberType) { + self.gicd.enable(irq_number); + } + + fn handle_pending_irqs<'irq_context>( + &'irq_context self, + ic: &exception::asynchronous::IRQContext<'irq_context>, + ) { + // Extract the highest priority pending IRQ number from the Interrupt Acknowledge Register + // (IAR). + let irq_number = self.gicc.pending_irq_number(ic); + + // Guard against spurious interrupts. + if irq_number > GICv2::MAX_IRQ_NUMBER { + return; + } + + // Call the IRQ handler. Panic if there is none. + self.handler_table.read(|table| { + match table[irq_number] { + None => panic!("No handler registered for IRQ {}", irq_number), + Some(descriptor) => { + // Call the IRQ handler. Panics on failure. + descriptor.handler().handle().expect("Error handling IRQ"); + } + } + }); + + // Signal completion of handling. + self.gicc.mark_comleted(irq_number as u32, ic); + } + + fn print_handler(&self) { + use crate::info; + + info!(" Peripheral handler:"); + + self.handler_table.read(|table| { + for (i, opt) in table.iter().skip(32).enumerate() { + if let Some(handler) = opt { + info!(" {: >3}. {}", i + 32, handler.name()); + } + } + }); + } +} diff --git a/20_timer_callbacks/kernel/src/bsp/device_driver/arm/gicv2/gicc.rs b/20_timer_callbacks/kernel/src/bsp/device_driver/arm/gicv2/gicc.rs new file mode 100644 index 00000000..1a02fc65 --- /dev/null +++ b/20_timer_callbacks/kernel/src/bsp/device_driver/arm/gicv2/gicc.rs @@ -0,0 +1,145 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2020-2022 Andre Richter + +//! GICC Driver - GIC CPU interface. + +use crate::{ + bsp::device_driver::common::MMIODerefWrapper, + exception, + memory::{Address, Virtual}, +}; +use tock_registers::{ + interfaces::{Readable, Writeable}, + register_bitfields, register_structs, + registers::ReadWrite, +}; + +//-------------------------------------------------------------------------------------------------- +// Private Definitions +//-------------------------------------------------------------------------------------------------- + +register_bitfields! { + u32, + + /// CPU Interface Control Register + CTLR [ + Enable OFFSET(0) NUMBITS(1) [] + ], + + /// Interrupt Priority Mask Register + PMR [ + Priority OFFSET(0) NUMBITS(8) [] + ], + + /// Interrupt Acknowledge Register + IAR [ + InterruptID OFFSET(0) NUMBITS(10) [] + ], + + /// End of Interrupt Register + EOIR [ + EOIINTID OFFSET(0) NUMBITS(10) [] + ] +} + +register_structs! { + #[allow(non_snake_case)] + pub RegisterBlock { + (0x000 => CTLR: ReadWrite), + (0x004 => PMR: ReadWrite), + (0x008 => _reserved1), + (0x00C => IAR: ReadWrite), + (0x010 => EOIR: ReadWrite), + (0x014 => @END), + } +} + +/// Abstraction for the associated MMIO registers. +type Registers = MMIODerefWrapper; + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +/// Representation of the GIC CPU interface. +pub struct GICC { + registers: Registers, +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +impl GICC { + /// Create an instance. + /// + /// # Safety + /// + /// - The user must ensure to provide a correct MMIO start address. + pub const unsafe fn new(mmio_start_addr: Address) -> Self { + Self { + registers: Registers::new(mmio_start_addr), + } + } + + /// Accept interrupts of any priority. + /// + /// Quoting the GICv2 Architecture Specification: + /// + /// "Writing 255 to the GICC_PMR always sets it to the largest supported priority field + /// value." + /// + /// # Safety + /// + /// - GICC MMIO registers are banked per CPU core. It is therefore safe to have `&self` instead + /// of `&mut self`. + pub fn priority_accept_all(&self) { + self.registers.PMR.write(PMR::Priority.val(255)); // Comment in arch spec. + } + + /// Enable the interface - start accepting IRQs. + /// + /// # Safety + /// + /// - GICC MMIO registers are banked per CPU core. It is therefore safe to have `&self` instead + /// of `&mut self`. + pub fn enable(&self) { + self.registers.CTLR.write(CTLR::Enable::SET); + } + + /// Extract the number of the highest-priority pending IRQ. + /// + /// Can only be called from IRQ context, which is ensured by taking an `IRQContext` token. + /// + /// # Safety + /// + /// - GICC MMIO registers are banked per CPU core. It is therefore safe to have `&self` instead + /// of `&mut self`. + #[allow(clippy::trivially_copy_pass_by_ref)] + pub fn pending_irq_number<'irq_context>( + &self, + _ic: &exception::asynchronous::IRQContext<'irq_context>, + ) -> usize { + self.registers.IAR.read(IAR::InterruptID) as usize + } + + /// Complete handling of the currently active IRQ. + /// + /// Can only be called from IRQ context, which is ensured by taking an `IRQContext` token. + /// + /// To be called after `pending_irq_number()`. + /// + /// # Safety + /// + /// - GICC MMIO registers are banked per CPU core. It is therefore safe to have `&self` instead + /// of `&mut self`. + #[allow(clippy::trivially_copy_pass_by_ref)] + pub fn mark_comleted<'irq_context>( + &self, + irq_number: u32, + _ic: &exception::asynchronous::IRQContext<'irq_context>, + ) { + self.registers.EOIR.write(EOIR::EOIINTID.val(irq_number)); + } +} diff --git a/20_timer_callbacks/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs b/20_timer_callbacks/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs new file mode 100644 index 00000000..8aebcf2b --- /dev/null +++ b/20_timer_callbacks/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs @@ -0,0 +1,201 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2020-2022 Andre Richter + +//! GICD Driver - GIC Distributor. +//! +//! # Glossary +//! - SPI - Shared Peripheral Interrupt. + +use crate::{ + bsp::device_driver::common::MMIODerefWrapper, + memory::{Address, Virtual}, + state, synchronization, + synchronization::IRQSafeNullLock, +}; +use tock_registers::{ + interfaces::{Readable, Writeable}, + register_bitfields, register_structs, + registers::{ReadOnly, ReadWrite}, +}; + +//-------------------------------------------------------------------------------------------------- +// Private Definitions +//-------------------------------------------------------------------------------------------------- + +register_bitfields! { + u32, + + /// Distributor Control Register + CTLR [ + Enable OFFSET(0) NUMBITS(1) [] + ], + + /// Interrupt Controller Type Register + TYPER [ + ITLinesNumber OFFSET(0) NUMBITS(5) [] + ], + + /// Interrupt Processor Targets Registers + ITARGETSR [ + Offset3 OFFSET(24) NUMBITS(8) [], + Offset2 OFFSET(16) NUMBITS(8) [], + Offset1 OFFSET(8) NUMBITS(8) [], + Offset0 OFFSET(0) NUMBITS(8) [] + ] +} + +register_structs! { + #[allow(non_snake_case)] + SharedRegisterBlock { + (0x000 => CTLR: ReadWrite), + (0x004 => TYPER: ReadOnly), + (0x008 => _reserved1), + (0x104 => ISENABLER: [ReadWrite; 31]), + (0x180 => _reserved2), + (0x820 => ITARGETSR: [ReadWrite; 248]), + (0xC00 => @END), + } +} + +register_structs! { + #[allow(non_snake_case)] + BankedRegisterBlock { + (0x000 => _reserved1), + (0x100 => ISENABLER: ReadWrite), + (0x104 => _reserved2), + (0x800 => ITARGETSR: [ReadOnly; 8]), + (0x820 => @END), + } +} + +/// Abstraction for the non-banked parts of the associated MMIO registers. +type SharedRegisters = MMIODerefWrapper; + +/// Abstraction for the banked parts of the associated MMIO registers. +type BankedRegisters = MMIODerefWrapper; + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +/// Representation of the GIC Distributor. +pub struct GICD { + /// Access to shared registers is guarded with a lock. + shared_registers: IRQSafeNullLock, + + /// Access to banked registers is unguarded. + banked_registers: BankedRegisters, +} + +//-------------------------------------------------------------------------------------------------- +// Private Code +//-------------------------------------------------------------------------------------------------- + +impl SharedRegisters { + /// Return the number of IRQs that this HW implements. + #[inline(always)] + fn num_irqs(&mut self) -> usize { + // Query number of implemented IRQs. + // + // Refer to GICv2 Architecture Specification, Section 4.3.2. + ((self.TYPER.read(TYPER::ITLinesNumber) as usize) + 1) * 32 + } + + /// Return a slice of the implemented ITARGETSR. + #[inline(always)] + fn implemented_itargets_slice(&mut self) -> &[ReadWrite] { + assert!(self.num_irqs() >= 36); + + // Calculate the max index of the shared ITARGETSR array. + // + // The first 32 IRQs are private, so not included in `shared_registers`. Each ITARGETS + // register has four entries, so shift right by two. Subtract one because we start + // counting at zero. + let spi_itargetsr_max_index = ((self.num_irqs() - 32) >> 2) - 1; + + // Rust automatically inserts slice range sanity check, i.e. max >= min. + &self.ITARGETSR[0..spi_itargetsr_max_index] + } +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- +use synchronization::interface::Mutex; + +impl GICD { + /// Create an instance. + /// + /// # Safety + /// + /// - The user must ensure to provide a correct MMIO start address. + pub const unsafe fn new(mmio_start_addr: Address) -> Self { + Self { + shared_registers: IRQSafeNullLock::new(SharedRegisters::new(mmio_start_addr)), + banked_registers: BankedRegisters::new(mmio_start_addr), + } + } + + /// Use a banked ITARGETSR to retrieve the executing core's GIC target mask. + /// + /// Quoting the GICv2 Architecture Specification: + /// + /// "GICD_ITARGETSR0 to GICD_ITARGETSR7 are read-only, and each field returns a value that + /// corresponds only to the processor reading the register." + fn local_gic_target_mask(&self) -> u32 { + self.banked_registers.ITARGETSR[0].read(ITARGETSR::Offset0) + } + + /// Route all SPIs to the boot core and enable the distributor. + pub fn boot_core_init(&self) { + assert!( + state::state_manager().is_init(), + "Only allowed during kernel init phase" + ); + + // Target all SPIs to the boot core only. + let mask = self.local_gic_target_mask(); + + self.shared_registers.lock(|regs| { + for i in regs.implemented_itargets_slice().iter() { + i.write( + ITARGETSR::Offset3.val(mask) + + ITARGETSR::Offset2.val(mask) + + ITARGETSR::Offset1.val(mask) + + ITARGETSR::Offset0.val(mask), + ); + } + + regs.CTLR.write(CTLR::Enable::SET); + }); + } + + /// Enable an interrupt. + pub fn enable(&self, irq_num: &super::IRQNumber) { + let irq_num = irq_num.get(); + + // Each bit in the u32 enable register corresponds to one IRQ number. Shift right by 5 + // (division by 32) and arrive at the index for the respective ISENABLER[i]. + let enable_reg_index = irq_num >> 5; + let enable_bit: u32 = 1u32 << (irq_num % 32); + + // Check if we are handling a private or shared IRQ. + match irq_num { + // Private. + 0..=31 => { + let enable_reg = &self.banked_registers.ISENABLER; + enable_reg.set(enable_reg.get() | enable_bit); + } + // Shared. + _ => { + let enable_reg_index_shared = enable_reg_index - 1; + + self.shared_registers.lock(|regs| { + let enable_reg = ®s.ISENABLER[enable_reg_index_shared]; + enable_reg.set(enable_reg.get() | enable_bit); + }); + } + } + } +} diff --git a/20_timer_callbacks/kernel/src/bsp/device_driver/bcm.rs b/20_timer_callbacks/kernel/src/bsp/device_driver/bcm.rs new file mode 100644 index 00000000..5a7cc23b --- /dev/null +++ b/20_timer_callbacks/kernel/src/bsp/device_driver/bcm.rs @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2018-2022 Andre Richter + +//! BCM driver top level. + +mod bcm2xxx_gpio; +#[cfg(feature = "bsp_rpi3")] +mod bcm2xxx_interrupt_controller; +mod bcm2xxx_pl011_uart; + +pub use bcm2xxx_gpio::*; +#[cfg(feature = "bsp_rpi3")] +pub use bcm2xxx_interrupt_controller::*; +pub use bcm2xxx_pl011_uart::*; diff --git a/20_timer_callbacks/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs b/20_timer_callbacks/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs new file mode 100644 index 00000000..fb61a651 --- /dev/null +++ b/20_timer_callbacks/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs @@ -0,0 +1,228 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2018-2022 Andre Richter + +//! GPIO Driver. + +use crate::{ + bsp::device_driver::common::MMIODerefWrapper, + driver, + exception::asynchronous::IRQNumber, + memory::{Address, Virtual}, + synchronization, + synchronization::IRQSafeNullLock, +}; +use tock_registers::{ + interfaces::{ReadWriteable, Writeable}, + register_bitfields, register_structs, + registers::ReadWrite, +}; + +//-------------------------------------------------------------------------------------------------- +// Private Definitions +//-------------------------------------------------------------------------------------------------- + +// GPIO registers. +// +// Descriptions taken from +// - https://github.com/raspberrypi/documentation/files/1888662/BCM2837-ARM-Peripherals.-.Revised.-.V2-1.pdf +// - https://datasheets.raspberrypi.org/bcm2711/bcm2711-peripherals.pdf +register_bitfields! { + u32, + + /// GPIO Function Select 1 + GPFSEL1 [ + /// Pin 15 + FSEL15 OFFSET(15) NUMBITS(3) [ + Input = 0b000, + Output = 0b001, + AltFunc0 = 0b100 // PL011 UART RX + + ], + + /// Pin 14 + FSEL14 OFFSET(12) NUMBITS(3) [ + Input = 0b000, + Output = 0b001, + AltFunc0 = 0b100 // PL011 UART TX + ] + ], + + /// GPIO Pull-up/down Register + /// + /// BCM2837 only. + GPPUD [ + /// Controls the actuation of the internal pull-up/down control line to ALL the GPIO pins. + PUD OFFSET(0) NUMBITS(2) [ + Off = 0b00, + PullDown = 0b01, + PullUp = 0b10 + ] + ], + + /// GPIO Pull-up/down Clock Register 0 + /// + /// BCM2837 only. + GPPUDCLK0 [ + /// Pin 15 + PUDCLK15 OFFSET(15) NUMBITS(1) [ + NoEffect = 0, + AssertClock = 1 + ], + + /// Pin 14 + PUDCLK14 OFFSET(14) NUMBITS(1) [ + NoEffect = 0, + AssertClock = 1 + ] + ], + + /// GPIO Pull-up / Pull-down Register 0 + /// + /// BCM2711 only. + GPIO_PUP_PDN_CNTRL_REG0 [ + /// Pin 15 + GPIO_PUP_PDN_CNTRL15 OFFSET(30) NUMBITS(2) [ + NoResistor = 0b00, + PullUp = 0b01 + ], + + /// Pin 14 + GPIO_PUP_PDN_CNTRL14 OFFSET(28) NUMBITS(2) [ + NoResistor = 0b00, + PullUp = 0b01 + ] + ] +} + +register_structs! { + #[allow(non_snake_case)] + RegisterBlock { + (0x00 => _reserved1), + (0x04 => GPFSEL1: ReadWrite), + (0x08 => _reserved2), + (0x94 => GPPUD: ReadWrite), + (0x98 => GPPUDCLK0: ReadWrite), + (0x9C => _reserved3), + (0xE4 => GPIO_PUP_PDN_CNTRL_REG0: ReadWrite), + (0xE8 => @END), + } +} + +/// Abstraction for the associated MMIO registers. +type Registers = MMIODerefWrapper; + +struct GPIOInner { + registers: Registers, +} + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +/// Representation of the GPIO HW. +pub struct GPIO { + inner: IRQSafeNullLock, +} + +//-------------------------------------------------------------------------------------------------- +// Private Code +//-------------------------------------------------------------------------------------------------- + +impl GPIOInner { + /// Create an instance. + /// + /// # Safety + /// + /// - The user must ensure to provide a correct MMIO start address. + pub const unsafe fn new(mmio_start_addr: Address) -> Self { + Self { + registers: Registers::new(mmio_start_addr), + } + } + + /// Disable pull-up/down on pins 14 and 15. + #[cfg(feature = "bsp_rpi3")] + fn disable_pud_14_15_bcm2837(&mut self) { + use crate::time; + use core::time::Duration; + + // The Linux 2837 GPIO driver waits 1 µs between the steps. + const DELAY: Duration = Duration::from_micros(1); + + self.registers.GPPUD.write(GPPUD::PUD::Off); + time::time_manager().spin_for(DELAY); + + self.registers + .GPPUDCLK0 + .write(GPPUDCLK0::PUDCLK15::AssertClock + GPPUDCLK0::PUDCLK14::AssertClock); + time::time_manager().spin_for(DELAY); + + self.registers.GPPUD.write(GPPUD::PUD::Off); + self.registers.GPPUDCLK0.set(0); + } + + /// Disable pull-up/down on pins 14 and 15. + #[cfg(feature = "bsp_rpi4")] + fn disable_pud_14_15_bcm2711(&mut self) { + self.registers.GPIO_PUP_PDN_CNTRL_REG0.write( + GPIO_PUP_PDN_CNTRL_REG0::GPIO_PUP_PDN_CNTRL15::PullUp + + GPIO_PUP_PDN_CNTRL_REG0::GPIO_PUP_PDN_CNTRL14::PullUp, + ); + } + + /// Map PL011 UART as standard output. + /// + /// TX to pin 14 + /// RX to pin 15 + pub fn map_pl011_uart(&mut self) { + // Select the UART on pins 14 and 15. + self.registers + .GPFSEL1 + .modify(GPFSEL1::FSEL15::AltFunc0 + GPFSEL1::FSEL14::AltFunc0); + + // Disable pull-up/down on pins 14 and 15. + #[cfg(feature = "bsp_rpi3")] + self.disable_pud_14_15_bcm2837(); + + #[cfg(feature = "bsp_rpi4")] + self.disable_pud_14_15_bcm2711(); + } +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +impl GPIO { + pub const COMPATIBLE: &'static str = "BCM GPIO"; + + /// Create an instance. + /// + /// # Safety + /// + /// - The user must ensure to provide a correct MMIO start address. + pub const unsafe fn new(mmio_start_addr: Address) -> Self { + Self { + inner: IRQSafeNullLock::new(GPIOInner::new(mmio_start_addr)), + } + } + + /// Concurrency safe version of `GPIOInner.map_pl011_uart()` + pub fn map_pl011_uart(&self) { + self.inner.lock(|inner| inner.map_pl011_uart()) + } +} + +//------------------------------------------------------------------------------ +// OS Interface Code +//------------------------------------------------------------------------------ +use synchronization::interface::Mutex; + +impl driver::interface::DeviceDriver for GPIO { + type IRQNumberType = IRQNumber; + + fn compatible(&self) -> &'static str { + Self::COMPATIBLE + } +} diff --git a/20_timer_callbacks/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs b/20_timer_callbacks/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs new file mode 100644 index 00000000..6c2cd451 --- /dev/null +++ b/20_timer_callbacks/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs @@ -0,0 +1,175 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2020-2022 Andre Richter + +//! Interrupt Controller Driver. + +mod local_ic; +mod peripheral_ic; + +use crate::{ + bsp::device_driver::common::BoundedUsize, + driver, + exception::{self, asynchronous::IRQHandlerDescriptor}, + memory::{Address, Virtual}, +}; +use core::fmt; + +//-------------------------------------------------------------------------------------------------- +// Private Definitions +//-------------------------------------------------------------------------------------------------- + +/// Wrapper struct for a bitmask indicating pending IRQ numbers. +struct PendingIRQs { + bitmask: u64, +} + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +pub type LocalIRQ = BoundedUsize<{ InterruptController::MAX_LOCAL_IRQ_NUMBER }>; +pub type PeripheralIRQ = BoundedUsize<{ InterruptController::MAX_PERIPHERAL_IRQ_NUMBER }>; + +/// Used for the associated type of trait [`exception::asynchronous::interface::IRQManager`]. +#[derive(Copy, Clone)] +#[allow(missing_docs)] +pub enum IRQNumber { + Local(LocalIRQ), + Peripheral(PeripheralIRQ), +} + +/// Representation of the Interrupt Controller. +pub struct InterruptController { + local: local_ic::LocalIC, + periph: peripheral_ic::PeripheralIC, +} + +//-------------------------------------------------------------------------------------------------- +// Private Code +//-------------------------------------------------------------------------------------------------- + +impl PendingIRQs { + pub fn new(bitmask: u64) -> Self { + Self { bitmask } + } +} + +impl Iterator for PendingIRQs { + type Item = usize; + + fn next(&mut self) -> Option { + if self.bitmask == 0 { + return None; + } + + let next = self.bitmask.trailing_zeros() as usize; + self.bitmask &= self.bitmask.wrapping_sub(1); + Some(next) + } +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +impl fmt::Display for IRQNumber { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Self::Local(number) => write!(f, "Local({})", number), + Self::Peripheral(number) => write!(f, "Peripheral({})", number), + } + } +} + +impl InterruptController { + // Restrict to 3 for now. This makes the code for local_ic.rs more straight forward. + const MAX_LOCAL_IRQ_NUMBER: usize = 3; + const MAX_PERIPHERAL_IRQ_NUMBER: usize = 63; + + pub const COMPATIBLE: &'static str = "BCM Interrupt Controller"; + + /// Create an instance. + /// + /// # Safety + /// + /// - The user must ensure to provide a correct MMIO start address. + pub const unsafe fn new( + local_mmio_start_addr: Address, + periph_mmio_start_addr: Address, + ) -> Self { + Self { + local: local_ic::LocalIC::new(local_mmio_start_addr), + periph: peripheral_ic::PeripheralIC::new(periph_mmio_start_addr), + } + } +} + +//------------------------------------------------------------------------------ +// OS Interface Code +//------------------------------------------------------------------------------ + +impl driver::interface::DeviceDriver for InterruptController { + type IRQNumberType = IRQNumber; + + fn compatible(&self) -> &'static str { + Self::COMPATIBLE + } + + unsafe fn init(&self) -> Result<(), &'static str> { + self.local.init(); + self.periph.init(); + + Ok(()) + } +} + +impl exception::asynchronous::interface::IRQManager for InterruptController { + type IRQNumberType = IRQNumber; + + fn register_handler( + &self, + irq_handler_descriptor: exception::asynchronous::IRQHandlerDescriptor, + ) -> Result<(), &'static str> { + match irq_handler_descriptor.number() { + IRQNumber::Local(lirq) => { + let local_descriptor = IRQHandlerDescriptor::new( + lirq, + irq_handler_descriptor.name(), + irq_handler_descriptor.handler(), + ); + + self.local.register_handler(local_descriptor) + } + IRQNumber::Peripheral(pirq) => { + let periph_descriptor = IRQHandlerDescriptor::new( + pirq, + irq_handler_descriptor.name(), + irq_handler_descriptor.handler(), + ); + + self.periph.register_handler(periph_descriptor) + } + } + } + + fn enable(&self, irq: &Self::IRQNumberType) { + match irq { + IRQNumber::Local(lirq) => self.local.enable(lirq), + IRQNumber::Peripheral(pirq) => self.periph.enable(pirq), + } + } + + fn handle_pending_irqs<'irq_context>( + &'irq_context self, + ic: &exception::asynchronous::IRQContext<'irq_context>, + ) { + self.local.handle_pending_irqs(ic); + self.periph.handle_pending_irqs(ic) + } + + fn print_handler(&self) { + self.local.print_handler(); + self.periph.print_handler(); + } +} diff --git a/20_timer_callbacks/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/local_ic.rs b/20_timer_callbacks/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/local_ic.rs new file mode 100644 index 00000000..ac382e95 --- /dev/null +++ b/20_timer_callbacks/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/local_ic.rs @@ -0,0 +1,173 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2022 Andre Richter + +//! Local Interrupt Controller Driver. +//! +//! # Resources +//! +//! - + +use super::{LocalIRQ, PendingIRQs}; +use crate::{ + bsp::device_driver::common::MMIODerefWrapper, + exception, + memory::{Address, Virtual}, + synchronization, + synchronization::{IRQSafeNullLock, InitStateLock}, +}; +use alloc::vec::Vec; +use tock_registers::{ + interfaces::{Readable, Writeable}, + register_structs, + registers::{ReadOnly, WriteOnly}, +}; + +//-------------------------------------------------------------------------------------------------- +// Private Definitions +//-------------------------------------------------------------------------------------------------- + +register_structs! { + #[allow(non_snake_case)] + WORegisterBlock { + (0x00 => _reserved1), + (0x40 => CORE0_TIMER_INTERRUPT_CONTROL: WriteOnly), + (0x44 => @END), + } +} + +register_structs! { + #[allow(non_snake_case)] + RORegisterBlock { + (0x00 => _reserved1), + (0x60 => CORE0_INTERRUPT_SOURCE: ReadOnly), + (0x64 => @END), + } +} + +/// Abstraction for the WriteOnly parts of the associated MMIO registers. +type WriteOnlyRegisters = MMIODerefWrapper; + +/// Abstraction for the ReadOnly parts of the associated MMIO registers. +type ReadOnlyRegisters = MMIODerefWrapper; + +type HandlerTable = Vec>>; + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +/// Representation of the peripheral interrupt controller. +pub struct LocalIC { + /// Access to write registers is guarded with a lock. + wo_registers: IRQSafeNullLock, + + /// Register read access is unguarded. + ro_registers: ReadOnlyRegisters, + + /// Stores registered IRQ handlers. Writable only during kernel init. RO afterwards. + handler_table: InitStateLock, +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +impl LocalIC { + // See datasheet. + const PERIPH_IRQ_MASK: u32 = (1 << 8); + + /// Create an instance. + /// + /// # Safety + /// + /// - The user must ensure to provide a correct MMIO start address. + pub const unsafe fn new(mmio_start_addr: Address) -> Self { + Self { + wo_registers: IRQSafeNullLock::new(WriteOnlyRegisters::new(mmio_start_addr)), + ro_registers: ReadOnlyRegisters::new(mmio_start_addr), + handler_table: InitStateLock::new(Vec::new()), + } + } + + /// Called by the kernel to bring up the device. + pub fn init(&self) { + self.handler_table + .write(|table| table.resize(LocalIRQ::MAX_INCLUSIVE + 1, None)); + } + + /// Query the list of pending IRQs. + fn pending_irqs(&self) -> PendingIRQs { + // Ignore the indicator bit for a peripheral IRQ. + PendingIRQs::new( + (self.ro_registers.CORE0_INTERRUPT_SOURCE.get() & !Self::PERIPH_IRQ_MASK).into(), + ) + } +} + +//------------------------------------------------------------------------------ +// OS Interface Code +//------------------------------------------------------------------------------ +use synchronization::interface::{Mutex, ReadWriteEx}; + +impl exception::asynchronous::interface::IRQManager for LocalIC { + type IRQNumberType = LocalIRQ; + + fn register_handler( + &self, + irq_handler_descriptor: exception::asynchronous::IRQHandlerDescriptor, + ) -> Result<(), &'static str> { + self.handler_table.write(|table| { + let irq_number = irq_handler_descriptor.number().get(); + + if table[irq_number].is_some() { + return Err("IRQ handler already registered"); + } + + table[irq_number] = Some(irq_handler_descriptor); + + Ok(()) + }) + } + + fn enable(&self, irq: &Self::IRQNumberType) { + self.wo_registers.lock(|regs| { + let enable_bit: u32 = 1 << (irq.get()); + + // Writing a 1 to a bit will set the corresponding IRQ enable bit. All other IRQ enable + // bits are unaffected. So we don't need read and OR'ing here. + regs.CORE0_TIMER_INTERRUPT_CONTROL.set(enable_bit); + }); + } + + fn handle_pending_irqs<'irq_context>( + &'irq_context self, + _ic: &exception::asynchronous::IRQContext<'irq_context>, + ) { + self.handler_table.read(|table| { + for irq_number in self.pending_irqs() { + match table[irq_number] { + None => panic!("No handler registered for IRQ {}", irq_number), + Some(descriptor) => { + // Call the IRQ handler. Panics on failure. + descriptor.handler().handle().expect("Error handling IRQ"); + } + } + } + }) + } + + fn print_handler(&self) { + use crate::info; + + info!(" Local handler:"); + + self.handler_table.read(|table| { + for (i, opt) in table.iter().enumerate() { + if let Some(handler) = opt { + info!(" {: >3}. {}", i, handler.name()); + } + } + }); + } +} diff --git a/20_timer_callbacks/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs b/20_timer_callbacks/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs new file mode 100644 index 00000000..238088a8 --- /dev/null +++ b/20_timer_callbacks/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs @@ -0,0 +1,178 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2020-2022 Andre Richter + +//! Peripheral Interrupt Controller Driver. +//! +//! # Resources +//! +//! - + +use super::{PendingIRQs, PeripheralIRQ}; +use crate::{ + bsp::device_driver::common::MMIODerefWrapper, + exception, + memory::{Address, Virtual}, + synchronization, + synchronization::{IRQSafeNullLock, InitStateLock}, +}; +use alloc::vec::Vec; +use tock_registers::{ + interfaces::{Readable, Writeable}, + register_structs, + registers::{ReadOnly, WriteOnly}, +}; + +//-------------------------------------------------------------------------------------------------- +// Private Definitions +//-------------------------------------------------------------------------------------------------- + +register_structs! { + #[allow(non_snake_case)] + WORegisterBlock { + (0x00 => _reserved1), + (0x10 => ENABLE_1: WriteOnly), + (0x14 => ENABLE_2: WriteOnly), + (0x18 => @END), + } +} + +register_structs! { + #[allow(non_snake_case)] + RORegisterBlock { + (0x00 => _reserved1), + (0x04 => PENDING_1: ReadOnly), + (0x08 => PENDING_2: ReadOnly), + (0x0c => @END), + } +} + +/// Abstraction for the WriteOnly parts of the associated MMIO registers. +type WriteOnlyRegisters = MMIODerefWrapper; + +/// Abstraction for the ReadOnly parts of the associated MMIO registers. +type ReadOnlyRegisters = MMIODerefWrapper; + +type HandlerTable = Vec>>; + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +/// Representation of the peripheral interrupt controller. +pub struct PeripheralIC { + /// Access to write registers is guarded with a lock. + wo_registers: IRQSafeNullLock, + + /// Register read access is unguarded. + ro_registers: ReadOnlyRegisters, + + /// Stores registered IRQ handlers. Writable only during kernel init. RO afterwards. + handler_table: InitStateLock, +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +impl PeripheralIC { + /// Create an instance. + /// + /// # Safety + /// + /// - The user must ensure to provide a correct MMIO start address. + pub const unsafe fn new(mmio_start_addr: Address) -> Self { + Self { + wo_registers: IRQSafeNullLock::new(WriteOnlyRegisters::new(mmio_start_addr)), + ro_registers: ReadOnlyRegisters::new(mmio_start_addr), + handler_table: InitStateLock::new(Vec::new()), + } + } + + /// Called by the kernel to bring up the device. + pub fn init(&self) { + self.handler_table + .write(|table| table.resize(PeripheralIRQ::MAX_INCLUSIVE + 1, None)); + } + + /// Query the list of pending IRQs. + fn pending_irqs(&self) -> PendingIRQs { + let pending_mask: u64 = (u64::from(self.ro_registers.PENDING_2.get()) << 32) + | u64::from(self.ro_registers.PENDING_1.get()); + + PendingIRQs::new(pending_mask) + } +} + +//------------------------------------------------------------------------------ +// OS Interface Code +//------------------------------------------------------------------------------ +use synchronization::interface::{Mutex, ReadWriteEx}; + +impl exception::asynchronous::interface::IRQManager for PeripheralIC { + type IRQNumberType = PeripheralIRQ; + + fn register_handler( + &self, + irq_handler_descriptor: exception::asynchronous::IRQHandlerDescriptor, + ) -> Result<(), &'static str> { + self.handler_table.write(|table| { + let irq_number = irq_handler_descriptor.number().get(); + + if table[irq_number].is_some() { + return Err("IRQ handler already registered"); + } + + table[irq_number] = Some(irq_handler_descriptor); + + Ok(()) + }) + } + + fn enable(&self, irq: &Self::IRQNumberType) { + self.wo_registers.lock(|regs| { + let enable_reg = if irq.get() <= 31 { + ®s.ENABLE_1 + } else { + ®s.ENABLE_2 + }; + + let enable_bit: u32 = 1 << (irq.get() % 32); + + // Writing a 1 to a bit will set the corresponding IRQ enable bit. All other IRQ enable + // bits are unaffected. So we don't need read and OR'ing here. + enable_reg.set(enable_bit); + }); + } + + fn handle_pending_irqs<'irq_context>( + &'irq_context self, + _ic: &exception::asynchronous::IRQContext<'irq_context>, + ) { + self.handler_table.read(|table| { + for irq_number in self.pending_irqs() { + match table[irq_number] { + None => panic!("No handler registered for IRQ {}", irq_number), + Some(descriptor) => { + // Call the IRQ handler. Panics on failure. + descriptor.handler().handle().expect("Error handling IRQ"); + } + } + } + }) + } + + fn print_handler(&self) { + use crate::info; + + info!(" Peripheral handler:"); + + self.handler_table.read(|table| { + for (i, opt) in table.iter().enumerate() { + if let Some(handler) = opt { + info!(" {: >3}. {}", i, handler.name()); + } + } + }); + } +} diff --git a/20_timer_callbacks/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs b/20_timer_callbacks/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs new file mode 100644 index 00000000..3e7e1812 --- /dev/null +++ b/20_timer_callbacks/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs @@ -0,0 +1,516 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2018-2022 Andre Richter + +//! PL011 UART driver. +//! +//! # Resources +//! +//! - +//! - + +use crate::{ + bsp::device_driver::common::MMIODerefWrapper, + console, cpu, driver, + exception::{self, asynchronous::IRQNumber}, + memory::{Address, Virtual}, + synchronization, + synchronization::IRQSafeNullLock, +}; +use core::fmt; +use tock_registers::{ + interfaces::{Readable, Writeable}, + register_bitfields, register_structs, + registers::{ReadOnly, ReadWrite, WriteOnly}, +}; + +//-------------------------------------------------------------------------------------------------- +// Private Definitions +//-------------------------------------------------------------------------------------------------- + +// PL011 UART registers. +// +// Descriptions taken from "PrimeCell UART (PL011) Technical Reference Manual" r1p5. +register_bitfields! { + u32, + + /// Flag Register. + FR [ + /// Transmit FIFO empty. The meaning of this bit depends on the state of the FEN bit in the + /// Line Control Register, LCR_H. + /// + /// - If the FIFO is disabled, this bit is set when the transmit holding register is empty. + /// - If the FIFO is enabled, the TXFE bit is set when the transmit FIFO is empty. + /// - This bit does not indicate if there is data in the transmit shift register. + TXFE OFFSET(7) NUMBITS(1) [], + + /// Transmit FIFO full. The meaning of this bit depends on the state of the FEN bit in the + /// LCR_H Register. + /// + /// - If the FIFO is disabled, this bit is set when the transmit holding register is full. + /// - If the FIFO is enabled, the TXFF bit is set when the transmit FIFO is full. + TXFF OFFSET(5) NUMBITS(1) [], + + /// Receive FIFO empty. The meaning of this bit depends on the state of the FEN bit in the + /// LCR_H Register. + /// + /// - If the FIFO is disabled, this bit is set when the receive holding register is empty. + /// - If the FIFO is enabled, the RXFE bit is set when the receive FIFO is empty. + RXFE OFFSET(4) NUMBITS(1) [], + + /// UART busy. If this bit is set to 1, the UART is busy transmitting data. This bit remains + /// set until the complete byte, including all the stop bits, has been sent from the shift + /// register. + /// + /// This bit is set as soon as the transmit FIFO becomes non-empty, regardless of whether + /// the UART is enabled or not. + BUSY OFFSET(3) NUMBITS(1) [] + ], + + /// Integer Baud Rate Divisor. + IBRD [ + /// The integer baud rate divisor. + BAUD_DIVINT OFFSET(0) NUMBITS(16) [] + ], + + /// Fractional Baud Rate Divisor. + FBRD [ + /// The fractional baud rate divisor. + BAUD_DIVFRAC OFFSET(0) NUMBITS(6) [] + ], + + /// Line Control Register. + LCR_H [ + /// Word length. These bits indicate the number of data bits transmitted or received in a + /// frame. + #[allow(clippy::enum_variant_names)] + WLEN OFFSET(5) NUMBITS(2) [ + FiveBit = 0b00, + SixBit = 0b01, + SevenBit = 0b10, + EightBit = 0b11 + ], + + /// Enable FIFOs: + /// + /// 0 = FIFOs are disabled (character mode) that is, the FIFOs become 1-byte-deep holding + /// registers. + /// + /// 1 = Transmit and receive FIFO buffers are enabled (FIFO mode). + FEN OFFSET(4) NUMBITS(1) [ + FifosDisabled = 0, + FifosEnabled = 1 + ] + ], + + /// Control Register. + CR [ + /// Receive enable. If this bit is set to 1, the receive section of the UART is enabled. + /// Data reception occurs for either UART signals or SIR signals depending on the setting of + /// the SIREN bit. When the UART is disabled in the middle of reception, it completes the + /// current character before stopping. + RXE OFFSET(9) NUMBITS(1) [ + Disabled = 0, + Enabled = 1 + ], + + /// Transmit enable. If this bit is set to 1, the transmit section of the UART is enabled. + /// Data transmission occurs for either UART signals, or SIR signals depending on the + /// setting of the SIREN bit. When the UART is disabled in the middle of transmission, it + /// completes the current character before stopping. + TXE OFFSET(8) NUMBITS(1) [ + Disabled = 0, + Enabled = 1 + ], + + /// UART enable: + /// + /// 0 = UART is disabled. If the UART is disabled in the middle of transmission or + /// reception, it completes the current character before stopping. + /// + /// 1 = The UART is enabled. Data transmission and reception occurs for either UART signals + /// or SIR signals depending on the setting of the SIREN bit + UARTEN OFFSET(0) NUMBITS(1) [ + /// If the UART is disabled in the middle of transmission or reception, it completes the + /// current character before stopping. + Disabled = 0, + Enabled = 1 + ] + ], + + /// Interrupt FIFO Level Select Register. + IFLS [ + /// Receive interrupt FIFO level select. The trigger points for the receive interrupt are as + /// follows. + RXIFLSEL OFFSET(3) NUMBITS(5) [ + OneEigth = 0b000, + OneQuarter = 0b001, + OneHalf = 0b010, + ThreeQuarters = 0b011, + SevenEights = 0b100 + ] + ], + + /// Interrupt Mask Set/Clear Register. + IMSC [ + /// Receive timeout interrupt mask. A read returns the current mask for the UARTRTINTR + /// interrupt. + /// + /// - On a write of 1, the mask of the UARTRTINTR interrupt is set. + /// - A write of 0 clears the mask. + RTIM OFFSET(6) NUMBITS(1) [ + Disabled = 0, + Enabled = 1 + ], + + /// Receive interrupt mask. A read returns the current mask for the UARTRXINTR interrupt. + /// + /// - On a write of 1, the mask of the UARTRXINTR interrupt is set. + /// - A write of 0 clears the mask. + RXIM OFFSET(4) NUMBITS(1) [ + Disabled = 0, + Enabled = 1 + ] + ], + + /// Masked Interrupt Status Register. + MIS [ + /// Receive timeout masked interrupt status. Returns the masked interrupt state of the + /// UARTRTINTR interrupt. + RTMIS OFFSET(6) NUMBITS(1) [], + + /// Receive masked interrupt status. Returns the masked interrupt state of the UARTRXINTR + /// interrupt. + RXMIS OFFSET(4) NUMBITS(1) [] + ], + + /// Interrupt Clear Register. + ICR [ + /// Meta field for all pending interrupts. + ALL OFFSET(0) NUMBITS(11) [] + ] +} + +register_structs! { + #[allow(non_snake_case)] + pub RegisterBlock { + (0x00 => DR: ReadWrite), + (0x04 => _reserved1), + (0x18 => FR: ReadOnly), + (0x1c => _reserved2), + (0x24 => IBRD: WriteOnly), + (0x28 => FBRD: WriteOnly), + (0x2c => LCR_H: WriteOnly), + (0x30 => CR: WriteOnly), + (0x34 => IFLS: ReadWrite), + (0x38 => IMSC: ReadWrite), + (0x3C => _reserved3), + (0x40 => MIS: ReadOnly), + (0x44 => ICR: WriteOnly), + (0x48 => @END), + } +} + +/// Abstraction for the associated MMIO registers. +type Registers = MMIODerefWrapper; + +#[derive(PartialEq)] +enum BlockingMode { + Blocking, + NonBlocking, +} + +struct PL011UartInner { + registers: Registers, + chars_written: usize, + chars_read: usize, +} + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +/// Representation of the UART. +pub struct PL011Uart { + inner: IRQSafeNullLock, +} + +//-------------------------------------------------------------------------------------------------- +// Private Code +//-------------------------------------------------------------------------------------------------- + +impl PL011UartInner { + /// Create an instance. + /// + /// # Safety + /// + /// - The user must ensure to provide a correct MMIO start address. + pub const unsafe fn new(mmio_start_addr: Address) -> Self { + Self { + registers: Registers::new(mmio_start_addr), + chars_written: 0, + chars_read: 0, + } + } + + /// Set up baud rate and characteristics. + /// + /// This results in 8N1 and 921_600 baud. + /// + /// The calculation for the BRD is (we set the clock to 48 MHz in config.txt): + /// `(48_000_000 / 16) / 921_600 = 3.2552083`. + /// + /// This means the integer part is `3` and goes into the `IBRD`. + /// The fractional part is `0.2552083`. + /// + /// `FBRD` calculation according to the PL011 Technical Reference Manual: + /// `INTEGER((0.2552083 * 64) + 0.5) = 16`. + /// + /// Therefore, the generated baud rate divider is: `3 + 16/64 = 3.25`. Which results in a + /// genrated baud rate of `48_000_000 / (16 * 3.25) = 923_077`. + /// + /// Error = `((923_077 - 921_600) / 921_600) * 100 = 0.16%`. + pub fn init(&mut self) { + // Execution can arrive here while there are still characters queued in the TX FIFO and + // actively being sent out by the UART hardware. If the UART is turned off in this case, + // those queued characters would be lost. + // + // For example, this can happen during runtime on a call to panic!(), because panic!() + // initializes its own UART instance and calls init(). + // + // Hence, flush first to ensure all pending characters are transmitted. + self.flush(); + + // Turn the UART off temporarily. + self.registers.CR.set(0); + + // Clear all pending interrupts. + self.registers.ICR.write(ICR::ALL::CLEAR); + + // From the PL011 Technical Reference Manual: + // + // The LCR_H, IBRD, and FBRD registers form the single 30-bit wide LCR Register that is + // updated on a single write strobe generated by a LCR_H write. So, to internally update the + // contents of IBRD or FBRD, a LCR_H write must always be performed at the end. + // + // Set the baud rate, 8N1 and FIFO enabled. + self.registers.IBRD.write(IBRD::BAUD_DIVINT.val(3)); + self.registers.FBRD.write(FBRD::BAUD_DIVFRAC.val(16)); + self.registers + .LCR_H + .write(LCR_H::WLEN::EightBit + LCR_H::FEN::FifosEnabled); + + // Set RX FIFO fill level at 1/8. + self.registers.IFLS.write(IFLS::RXIFLSEL::OneEigth); + + // Enable RX IRQ + RX timeout IRQ. + self.registers + .IMSC + .write(IMSC::RXIM::Enabled + IMSC::RTIM::Enabled); + + // Turn the UART on. + self.registers + .CR + .write(CR::UARTEN::Enabled + CR::TXE::Enabled + CR::RXE::Enabled); + } + + /// Send a character. + fn write_char(&mut self, c: char) { + // Spin while TX FIFO full is set, waiting for an empty slot. + while self.registers.FR.matches_all(FR::TXFF::SET) { + cpu::nop(); + } + + // Write the character to the buffer. + self.registers.DR.set(c as u32); + + self.chars_written += 1; + } + + /// Send a slice of characters. + fn write_array(&mut self, a: &[char]) { + for c in a { + self.write_char(*c); + } + } + + /// Block execution until the last buffered character has been physically put on the TX wire. + fn flush(&self) { + // Spin until the busy bit is cleared. + while self.registers.FR.matches_all(FR::BUSY::SET) { + cpu::nop(); + } + } + + /// Retrieve a character. + fn read_char_converting(&mut self, blocking_mode: BlockingMode) -> Option { + // If RX FIFO is empty, + if self.registers.FR.matches_all(FR::RXFE::SET) { + // immediately return in non-blocking mode. + if blocking_mode == BlockingMode::NonBlocking { + return None; + } + + // Otherwise, wait until a char was received. + while self.registers.FR.matches_all(FR::RXFE::SET) { + cpu::nop(); + } + } + + // Read one character. + let mut ret = self.registers.DR.get() as u8 as char; + + // Convert carrige return to newline. + if ret == '\r' { + ret = '\n' + } + + // Update statistics. + self.chars_read += 1; + + Some(ret) + } +} + +/// Implementing `core::fmt::Write` enables usage of the `format_args!` macros, which in turn are +/// used to implement the `kernel`'s `print!` and `println!` macros. By implementing `write_str()`, +/// we get `write_fmt()` automatically. +/// +/// The function takes an `&mut self`, so it must be implemented for the inner struct. +/// +/// See [`src/print.rs`]. +/// +/// [`src/print.rs`]: ../../print/index.html +impl fmt::Write for PL011UartInner { + fn write_str(&mut self, s: &str) -> fmt::Result { + for c in s.chars() { + self.write_char(c); + } + + Ok(()) + } +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +impl PL011Uart { + pub const COMPATIBLE: &'static str = "BCM PL011 UART"; + + /// Create an instance. + /// + /// # Safety + /// + /// - The user must ensure to provide a correct MMIO start address. + pub const unsafe fn new(mmio_start_addr: Address) -> Self { + Self { + inner: IRQSafeNullLock::new(PL011UartInner::new(mmio_start_addr)), + } + } +} + +//------------------------------------------------------------------------------ +// OS Interface Code +//------------------------------------------------------------------------------ +use synchronization::interface::Mutex; + +impl driver::interface::DeviceDriver for PL011Uart { + type IRQNumberType = IRQNumber; + + fn compatible(&self) -> &'static str { + Self::COMPATIBLE + } + + unsafe fn init(&self) -> Result<(), &'static str> { + self.inner.lock(|inner| inner.init()); + + Ok(()) + } + + fn register_and_enable_irq_handler( + &'static self, + irq_number: &Self::IRQNumberType, + ) -> Result<(), &'static str> { + use exception::asynchronous::{irq_manager, IRQHandlerDescriptor}; + + let descriptor = IRQHandlerDescriptor::new(*irq_number, Self::COMPATIBLE, self); + + irq_manager().register_handler(descriptor)?; + irq_manager().enable(irq_number); + + Ok(()) + } +} + +impl console::interface::Write for PL011Uart { + /// Passthrough of `args` to the `core::fmt::Write` implementation, but guarded by a Mutex to + /// serialize access. + fn write_char(&self, c: char) { + self.inner.lock(|inner| inner.write_char(c)); + } + + fn write_array(&self, a: &[char]) { + self.inner.lock(|inner| inner.write_array(a)); + } + + fn write_fmt(&self, args: core::fmt::Arguments) -> fmt::Result { + // Fully qualified syntax for the call to `core::fmt::Write::write_fmt()` to increase + // readability. + self.inner.lock(|inner| fmt::Write::write_fmt(inner, args)) + } + + fn flush(&self) { + // Spin until TX FIFO empty is set. + self.inner.lock(|inner| inner.flush()); + } +} + +impl console::interface::Read for PL011Uart { + fn read_char(&self) -> char { + self.inner + .lock(|inner| inner.read_char_converting(BlockingMode::Blocking).unwrap()) + } + + fn clear_rx(&self) { + // Read from the RX FIFO until it is indicating empty. + while self + .inner + .lock(|inner| inner.read_char_converting(BlockingMode::NonBlocking)) + .is_some() + {} + } +} + +impl console::interface::Statistics for PL011Uart { + fn chars_written(&self) -> usize { + self.inner.lock(|inner| inner.chars_written) + } + + fn chars_read(&self) -> usize { + self.inner.lock(|inner| inner.chars_read) + } +} + +impl console::interface::All for PL011Uart {} + +impl exception::asynchronous::interface::IRQHandler for PL011Uart { + fn handle(&self) -> Result<(), &'static str> { + self.inner.lock(|inner| { + let pending = inner.registers.MIS.extract(); + + // Clear all pending IRQs. + inner.registers.ICR.write(ICR::ALL::CLEAR); + + // Check for any kind of RX interrupt. + if pending.matches_any(MIS::RXMIS::SET + MIS::RTMIS::SET) { + // Echo any received characters. + while let Some(c) = inner.read_char_converting(BlockingMode::NonBlocking) { + inner.write_char(c) + } + } + }); + + Ok(()) + } +} diff --git a/20_timer_callbacks/kernel/src/bsp/device_driver/common.rs b/20_timer_callbacks/kernel/src/bsp/device_driver/common.rs new file mode 100644 index 00000000..ca7aeb76 --- /dev/null +++ b/20_timer_callbacks/kernel/src/bsp/device_driver/common.rs @@ -0,0 +1,65 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2020-2022 Andre Richter + +//! Common device driver code. + +use crate::memory::{Address, Virtual}; +use core::{fmt, marker::PhantomData, ops}; + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +pub struct MMIODerefWrapper { + start_addr: Address, + phantom: PhantomData T>, +} + +/// A wrapper type for usize with integrated range bound check. +#[derive(Copy, Clone)] +pub struct BoundedUsize(usize); + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +impl MMIODerefWrapper { + /// Create an instance. + pub const unsafe fn new(start_addr: Address) -> Self { + Self { + start_addr, + phantom: PhantomData, + } + } +} + +impl ops::Deref for MMIODerefWrapper { + type Target = T; + + fn deref(&self) -> &Self::Target { + unsafe { &*(self.start_addr.as_usize() as *const _) } + } +} + +impl BoundedUsize<{ MAX_INCLUSIVE }> { + pub const MAX_INCLUSIVE: usize = MAX_INCLUSIVE; + + /// Creates a new instance if number <= MAX_INCLUSIVE. + pub const fn new(number: usize) -> Self { + assert!(number <= MAX_INCLUSIVE); + + Self(number) + } + + /// Return the wrapped number. + pub const fn get(self) -> usize { + self.0 + } +} + +impl fmt::Display for BoundedUsize<{ MAX_INCLUSIVE }> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.0) + } +} diff --git a/20_timer_callbacks/kernel/src/bsp/raspberrypi.rs b/20_timer_callbacks/kernel/src/bsp/raspberrypi.rs new file mode 100644 index 00000000..474419f4 --- /dev/null +++ b/20_timer_callbacks/kernel/src/bsp/raspberrypi.rs @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2018-2022 Andre Richter + +//! Top-level BSP file for the Raspberry Pi 3 and 4. + +pub mod cpu; +pub mod driver; +pub mod exception; +pub mod memory; + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +/// Board identification. +pub fn board_name() -> &'static str { + #[cfg(feature = "bsp_rpi3")] + { + "Raspberry Pi 3" + } + + #[cfg(feature = "bsp_rpi4")] + { + "Raspberry Pi 4" + } +} diff --git a/20_timer_callbacks/kernel/src/bsp/raspberrypi/cpu.rs b/20_timer_callbacks/kernel/src/bsp/raspberrypi/cpu.rs new file mode 100644 index 00000000..85fb89e4 --- /dev/null +++ b/20_timer_callbacks/kernel/src/bsp/raspberrypi/cpu.rs @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2018-2022 Andre Richter + +//! BSP Processor code. + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +/// Used by `arch` code to find the early boot core. +#[no_mangle] +#[link_section = ".text._start_arguments"] +pub static BOOT_CORE_ID: u64 = 0; diff --git a/20_timer_callbacks/kernel/src/bsp/raspberrypi/driver.rs b/20_timer_callbacks/kernel/src/bsp/raspberrypi/driver.rs new file mode 100644 index 00000000..a23b08c0 --- /dev/null +++ b/20_timer_callbacks/kernel/src/bsp/raspberrypi/driver.rs @@ -0,0 +1,193 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2018-2022 Andre Richter + +//! BSP driver support. + +use super::{exception, memory::map::mmio}; +use crate::{ + bsp::device_driver, + console, driver as generic_driver, + exception::{self as generic_exception}, + memory, + memory::mmu::MMIODescriptor, +}; +use core::{ + mem::MaybeUninit, + sync::atomic::{AtomicBool, Ordering}, +}; + +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +static mut PL011_UART: MaybeUninit = MaybeUninit::uninit(); +static mut GPIO: MaybeUninit = MaybeUninit::uninit(); + +#[cfg(feature = "bsp_rpi3")] +static mut INTERRUPT_CONTROLLER: MaybeUninit = + MaybeUninit::uninit(); + +#[cfg(feature = "bsp_rpi4")] +static mut INTERRUPT_CONTROLLER: MaybeUninit = MaybeUninit::uninit(); + +//-------------------------------------------------------------------------------------------------- +// Private Code +//-------------------------------------------------------------------------------------------------- + +/// This must be called only after successful init of the memory subsystem. +unsafe fn instantiate_uart() -> Result<(), &'static str> { + let mmio_descriptor = MMIODescriptor::new(mmio::PL011_UART_START, mmio::PL011_UART_SIZE); + let virt_addr = + memory::mmu::kernel_map_mmio(device_driver::PL011Uart::COMPATIBLE, &mmio_descriptor)?; + + PL011_UART.write(device_driver::PL011Uart::new(virt_addr)); + + Ok(()) +} + +/// This must be called only after successful init of the UART driver. +unsafe fn post_init_uart() -> Result<(), &'static str> { + console::register_console(PL011_UART.assume_init_ref()); + + Ok(()) +} + +/// This must be called only after successful init of the memory subsystem. +unsafe fn instantiate_gpio() -> Result<(), &'static str> { + let mmio_descriptor = MMIODescriptor::new(mmio::GPIO_START, mmio::GPIO_SIZE); + let virt_addr = + memory::mmu::kernel_map_mmio(device_driver::GPIO::COMPATIBLE, &mmio_descriptor)?; + + GPIO.write(device_driver::GPIO::new(virt_addr)); + + Ok(()) +} + +/// This must be called only after successful init of the GPIO driver. +unsafe fn post_init_gpio() -> Result<(), &'static str> { + GPIO.assume_init_ref().map_pl011_uart(); + Ok(()) +} + +/// This must be called only after successful init of the memory subsystem. +#[cfg(feature = "bsp_rpi3")] +unsafe fn instantiate_interrupt_controller() -> Result<(), &'static str> { + let local_mmio_descriptor = MMIODescriptor::new(mmio::LOCAL_IC_START, mmio::LOCAL_IC_SIZE); + let local_virt_addr = memory::mmu::kernel_map_mmio( + device_driver::InterruptController::COMPATIBLE, + &local_mmio_descriptor, + )?; + + let periph_mmio_descriptor = + MMIODescriptor::new(mmio::PERIPHERAL_IC_START, mmio::PERIPHERAL_IC_SIZE); + let periph_virt_addr = memory::mmu::kernel_map_mmio( + device_driver::InterruptController::COMPATIBLE, + &periph_mmio_descriptor, + )?; + + INTERRUPT_CONTROLLER.write(device_driver::InterruptController::new( + local_virt_addr, + periph_virt_addr, + )); + + Ok(()) +} + +/// This must be called only after successful init of the memory subsystem. +#[cfg(feature = "bsp_rpi4")] +unsafe fn instantiate_interrupt_controller() -> Result<(), &'static str> { + let gicd_mmio_descriptor = MMIODescriptor::new(mmio::GICD_START, mmio::GICD_SIZE); + let gicd_virt_addr = memory::mmu::kernel_map_mmio("GICv2 GICD", &gicd_mmio_descriptor)?; + + let gicc_mmio_descriptor = MMIODescriptor::new(mmio::GICC_START, mmio::GICC_SIZE); + let gicc_virt_addr = memory::mmu::kernel_map_mmio("GICV2 GICC", &gicc_mmio_descriptor)?; + + INTERRUPT_CONTROLLER.write(device_driver::GICv2::new(gicd_virt_addr, gicc_virt_addr)); + + Ok(()) +} + +/// This must be called only after successful init of the interrupt controller driver. +unsafe fn post_init_interrupt_controller() -> Result<(), &'static str> { + generic_exception::asynchronous::register_irq_manager(INTERRUPT_CONTROLLER.assume_init_ref()); + + Ok(()) +} + +/// Function needs to ensure that driver registration happens only after correct instantiation. +unsafe fn driver_uart() -> Result<(), &'static str> { + instantiate_uart()?; + + let uart_descriptor = generic_driver::DeviceDriverDescriptor::new( + PL011_UART.assume_init_ref(), + Some(post_init_uart), + Some(exception::asynchronous::irq_map::PL011_UART), + ); + generic_driver::driver_manager().register_driver(uart_descriptor); + + Ok(()) +} + +/// Function needs to ensure that driver registration happens only after correct instantiation. +unsafe fn driver_gpio() -> Result<(), &'static str> { + instantiate_gpio()?; + + let gpio_descriptor = generic_driver::DeviceDriverDescriptor::new( + GPIO.assume_init_ref(), + Some(post_init_gpio), + None, + ); + generic_driver::driver_manager().register_driver(gpio_descriptor); + + Ok(()) +} + +/// Function needs to ensure that driver registration happens only after correct instantiation. +unsafe fn driver_interrupt_controller() -> Result<(), &'static str> { + instantiate_interrupt_controller()?; + + let interrupt_controller_descriptor = generic_driver::DeviceDriverDescriptor::new( + INTERRUPT_CONTROLLER.assume_init_ref(), + Some(post_init_interrupt_controller), + None, + ); + generic_driver::driver_manager().register_driver(interrupt_controller_descriptor); + + Ok(()) +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +/// Initialize the driver subsystem. +/// +/// # Safety +/// +/// See child function calls. +pub unsafe fn init() -> Result<(), &'static str> { + static INIT_DONE: AtomicBool = AtomicBool::new(false); + if INIT_DONE.load(Ordering::Relaxed) { + return Err("Init already done"); + } + + driver_uart()?; + driver_gpio()?; + driver_interrupt_controller()?; + + INIT_DONE.store(true, Ordering::Relaxed); + Ok(()) +} + +/// Minimal code needed to bring up the console in QEMU (for testing only). This is often less steps +/// than on real hardware due to QEMU's abstractions. +#[cfg(feature = "test_build")] +pub fn qemu_bring_up_console() { + use crate::cpu; + + unsafe { + instantiate_uart().unwrap_or_else(|_| cpu::qemu_exit_failure()); + console::register_console(PL011_UART.assume_init_ref()); + }; +} diff --git a/20_timer_callbacks/kernel/src/bsp/raspberrypi/exception.rs b/20_timer_callbacks/kernel/src/bsp/raspberrypi/exception.rs new file mode 100644 index 00000000..aa6c5a63 --- /dev/null +++ b/20_timer_callbacks/kernel/src/bsp/raspberrypi/exception.rs @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2020-2022 Andre Richter + +//! BSP synchronous and asynchronous exception handling. + +pub mod asynchronous; diff --git a/20_timer_callbacks/kernel/src/bsp/raspberrypi/exception/asynchronous.rs b/20_timer_callbacks/kernel/src/bsp/raspberrypi/exception/asynchronous.rs new file mode 100644 index 00000000..a6fd27fb --- /dev/null +++ b/20_timer_callbacks/kernel/src/bsp/raspberrypi/exception/asynchronous.rs @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2020-2022 Andre Richter + +//! BSP asynchronous exception handling. + +use crate::bsp; + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +/// Export for reuse in generic asynchronous.rs. +pub use bsp::device_driver::IRQNumber; + +/// The IRQ map. +#[cfg(feature = "bsp_rpi3")] +pub mod irq_map { + use super::bsp::device_driver::{IRQNumber, LocalIRQ, PeripheralIRQ}; + + /// The non-secure physical timer IRQ number. + pub const ARM_NS_PHYISCAL_TIMER: IRQNumber = IRQNumber::Local(LocalIRQ::new(1)); + + pub(in crate::bsp) const PL011_UART: IRQNumber = IRQNumber::Peripheral(PeripheralIRQ::new(57)); +} + +/// The IRQ map. +#[cfg(feature = "bsp_rpi4")] +pub mod irq_map { + use super::bsp::device_driver::IRQNumber; + + /// The non-secure physical timer IRQ number. + pub const ARM_NS_PHYISCAL_TIMER: IRQNumber = IRQNumber::new(30); + + pub(in crate::bsp) const PL011_UART: IRQNumber = IRQNumber::new(153); +} diff --git a/20_timer_callbacks/kernel/src/bsp/raspberrypi/kernel.ld b/20_timer_callbacks/kernel/src/bsp/raspberrypi/kernel.ld new file mode 100644 index 00000000..2408b63c --- /dev/null +++ b/20_timer_callbacks/kernel/src/bsp/raspberrypi/kernel.ld @@ -0,0 +1,134 @@ +/* SPDX-License-Identifier: MIT OR Apache-2.0 + * + * Copyright (c) 2018-2022 Andre Richter + */ + +INCLUDE kernel_virt_addr_space_size.ld; + +PAGE_SIZE = 64K; +PAGE_MASK = PAGE_SIZE - 1; + +/* The kernel's virtual address range will be: + * + * [END_ADDRESS_INCLUSIVE, START_ADDRESS] + * [u64::MAX , (u64::MAX - __kernel_virt_addr_space_size) + 1] + */ +__kernel_virt_start_addr = ((0xffffffffffffffff - __kernel_virt_addr_space_size) + 1); + +__rpi_phys_dram_start_addr = 0; + +/* The physical address at which the the kernel binary will be loaded by the Raspberry's firmware */ +__rpi_phys_binary_load_addr = 0x80000; + + +ENTRY(__rpi_phys_binary_load_addr) + +/* Flags: + * 4 == R + * 5 == RX + * 6 == RW + * + * Segments are marked PT_LOAD below so that the ELF file provides virtual and physical addresses. + * It doesn't mean all of them need actually be loaded. + */ +PHDRS +{ + segment_code PT_LOAD FLAGS(5); + segment_data PT_LOAD FLAGS(6); + segment_heap PT_LOAD FLAGS(6); + segment_boot_core_stack PT_LOAD FLAGS(6); +} + +SECTIONS +{ + . = __kernel_virt_start_addr; + + ASSERT((. & PAGE_MASK) == 0, "Start of address space is not page aligned") + + /*********************************************************************************************** + * Code + RO Data + Global Offset Table + ***********************************************************************************************/ + __code_start = .; + .text : AT(__rpi_phys_binary_load_addr) + { + KEEP(*(.text._start)) + *(.text._start_arguments) /* Constants (or statics in Rust speak) read by _start(). */ + *(.text._start_rust) /* The Rust entry point */ + *(.text*) /* Everything else */ + } :segment_code + + .rodata : ALIGN(8) { *(.rodata*) } :segment_code + .kernel_symbols : ALIGN(8) { + __kernel_symbols_start = .; + . += 32 * 1024; + } :segment_code + + . = ALIGN(PAGE_SIZE); + __code_end_exclusive = .; + + /*********************************************************************************************** + * Data + BSS + ***********************************************************************************************/ + __data_start = .; + .data : { *(.data*) } :segment_data + + /* Section is zeroed in pairs of u64. Align start and end to 16 bytes */ + .bss (NOLOAD) : ALIGN(16) + { + __bss_start = .; + *(.bss*); + . = ALIGN(16); + __bss_end_exclusive = .; + } :segment_data + + . = ALIGN(PAGE_SIZE); + __data_end_exclusive = .; + + /*********************************************************************************************** + * Heap + ***********************************************************************************************/ + __heap_start = .; + .heap (NOLOAD) : + { + . += 16 * 1024 * 1024; + } :segment_heap + __heap_end_exclusive = .; + + ASSERT((. & PAGE_MASK) == 0, "Heap is not page aligned") + + /*********************************************************************************************** + * MMIO Remap Reserved + ***********************************************************************************************/ + __mmio_remap_start = .; + . += 8 * 1024 * 1024; + __mmio_remap_end_exclusive = .; + + ASSERT((. & PAGE_MASK) == 0, "MMIO remap reservation is not page aligned") + + /*********************************************************************************************** + * Guard Page + ***********************************************************************************************/ + . += PAGE_SIZE; + + /*********************************************************************************************** + * Boot Core Stack + ***********************************************************************************************/ + .boot_core_stack (NOLOAD) : AT(__rpi_phys_dram_start_addr) + { + __boot_core_stack_start = .; /* ^ */ + /* | stack */ + . += __rpi_phys_binary_load_addr; /* | growth */ + /* | direction */ + __boot_core_stack_end_exclusive = .; /* | */ + } :segment_boot_core_stack + + ASSERT((. & PAGE_MASK) == 0, "End of boot core stack is not page aligned") + + /*********************************************************************************************** + * Misc + ***********************************************************************************************/ + .got : { *(.got*) } + ASSERT(SIZEOF(.got) == 0, "Relocation support not expected") + + /DISCARD/ : { *(.comment*) } +} diff --git a/20_timer_callbacks/kernel/src/bsp/raspberrypi/kernel_virt_addr_space_size.ld b/20_timer_callbacks/kernel/src/bsp/raspberrypi/kernel_virt_addr_space_size.ld new file mode 100644 index 00000000..c5d58c30 --- /dev/null +++ b/20_timer_callbacks/kernel/src/bsp/raspberrypi/kernel_virt_addr_space_size.ld @@ -0,0 +1 @@ +__kernel_virt_addr_space_size = 1024 * 1024 * 1024 diff --git a/20_timer_callbacks/kernel/src/bsp/raspberrypi/memory.rs b/20_timer_callbacks/kernel/src/bsp/raspberrypi/memory.rs new file mode 100644 index 00000000..d07c9695 --- /dev/null +++ b/20_timer_callbacks/kernel/src/bsp/raspberrypi/memory.rs @@ -0,0 +1,254 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2018-2022 Andre Richter + +//! BSP Memory Management. +//! +//! The physical memory layout. +//! +//! The Raspberry's firmware copies the kernel binary to 0x8_0000. The preceding region will be used +//! as the boot core's stack. +//! +//! +---------------------------------------+ +//! | | boot_core_stack_start @ 0x0 +//! | | ^ +//! | Boot-core Stack | | stack +//! | | | growth +//! | | | direction +//! +---------------------------------------+ +//! | | code_start @ 0x8_0000 == boot_core_stack_end_exclusive +//! | .text | +//! | .rodata | +//! | .got | +//! | .kernel_symbols | +//! | | +//! +---------------------------------------+ +//! | | data_start == code_end_exclusive +//! | .data | +//! | .bss | +//! | | +//! +---------------------------------------+ +//! | | heap_start == data_end_exclusive +//! | .heap | +//! | | +//! +---------------------------------------+ +//! | | heap_end_exclusive +//! | | +//! +//! +//! +//! +//! +//! The virtual memory layout is as follows: +//! +//! +---------------------------------------+ +//! | | code_start @ __kernel_virt_start_addr +//! | .text | +//! | .rodata | +//! | .got | +//! | .kernel_symbols | +//! | | +//! +---------------------------------------+ +//! | | data_start == code_end_exclusive +//! | .data | +//! | .bss | +//! | | +//! +---------------------------------------+ +//! | | heap_start == data_end_exclusive +//! | .heap | +//! | | +//! +---------------------------------------+ +//! | | mmio_remap_start == heap_end_exclusive +//! | VA region for MMIO remapping | +//! | | +//! +---------------------------------------+ +//! | | mmio_remap_end_exclusive +//! | Unmapped guard page | +//! | | +//! +---------------------------------------+ +//! | | boot_core_stack_start +//! | | ^ +//! | Boot-core Stack | | stack +//! | | | growth +//! | | | direction +//! +---------------------------------------+ +//! | | boot_core_stack_end_exclusive +//! | | +pub mod mmu; + +use crate::memory::{mmu::PageAddress, Address, Physical, Virtual}; +use core::cell::UnsafeCell; + +//-------------------------------------------------------------------------------------------------- +// Private Definitions +//-------------------------------------------------------------------------------------------------- + +// Symbols from the linker script. +extern "Rust" { + static __code_start: UnsafeCell<()>; + static __code_end_exclusive: UnsafeCell<()>; + + static __data_start: UnsafeCell<()>; + static __data_end_exclusive: UnsafeCell<()>; + + static __heap_start: UnsafeCell<()>; + static __heap_end_exclusive: UnsafeCell<()>; + + static __mmio_remap_start: UnsafeCell<()>; + static __mmio_remap_end_exclusive: UnsafeCell<()>; + + static __boot_core_stack_start: UnsafeCell<()>; + static __boot_core_stack_end_exclusive: UnsafeCell<()>; +} + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +/// The board's physical memory map. +#[rustfmt::skip] +pub(super) mod map { + use super::*; + + /// Physical devices. + #[cfg(feature = "bsp_rpi3")] + pub mod mmio { + use super::*; + + pub const PERIPHERAL_IC_START: Address = Address::new(0x3F00_B200); + pub const PERIPHERAL_IC_SIZE: usize = 0x24; + + pub const GPIO_START: Address = Address::new(0x3F20_0000); + pub const GPIO_SIZE: usize = 0xA0; + + pub const PL011_UART_START: Address = Address::new(0x3F20_1000); + pub const PL011_UART_SIZE: usize = 0x48; + + pub const LOCAL_IC_START: Address = Address::new(0x4000_0000); + pub const LOCAL_IC_SIZE: usize = 0x100; + + pub const END: Address = Address::new(0x4001_0000); + } + + /// Physical devices. + #[cfg(feature = "bsp_rpi4")] + pub mod mmio { + use super::*; + + pub const GPIO_START: Address = Address::new(0xFE20_0000); + pub const GPIO_SIZE: usize = 0xA0; + + pub const PL011_UART_START: Address = Address::new(0xFE20_1000); + pub const PL011_UART_SIZE: usize = 0x48; + + pub const GICD_START: Address = Address::new(0xFF84_1000); + pub const GICD_SIZE: usize = 0x824; + + pub const GICC_START: Address = Address::new(0xFF84_2000); + pub const GICC_SIZE: usize = 0x14; + + pub const END: Address = Address::new(0xFF85_0000); + } + + pub const END: Address = mmio::END; +} + +//-------------------------------------------------------------------------------------------------- +// Private Code +//-------------------------------------------------------------------------------------------------- + +/// Start page address of the code segment. +/// +/// # Safety +/// +/// - Value is provided by the linker script and must be trusted as-is. +#[inline(always)] +fn virt_code_start() -> PageAddress { + PageAddress::from(unsafe { __code_start.get() as usize }) +} + +/// Size of the code segment. +/// +/// # Safety +/// +/// - Value is provided by the linker script and must be trusted as-is. +#[inline(always)] +fn code_size() -> usize { + unsafe { (__code_end_exclusive.get() as usize) - (__code_start.get() as usize) } +} + +/// Start page address of the data segment. +#[inline(always)] +fn virt_data_start() -> PageAddress { + PageAddress::from(unsafe { __data_start.get() as usize }) +} + +/// Size of the data segment. +/// +/// # Safety +/// +/// - Value is provided by the linker script and must be trusted as-is. +#[inline(always)] +fn data_size() -> usize { + unsafe { (__data_end_exclusive.get() as usize) - (__data_start.get() as usize) } +} + +/// Start page address of the heap segment. +#[inline(always)] +fn virt_heap_start() -> PageAddress { + PageAddress::from(unsafe { __heap_start.get() as usize }) +} + +/// Size of the heap segment. +/// +/// # Safety +/// +/// - Value is provided by the linker script and must be trusted as-is. +#[inline(always)] +fn heap_size() -> usize { + unsafe { (__heap_end_exclusive.get() as usize) - (__heap_start.get() as usize) } +} + +/// Start page address of the MMIO remap reservation. +/// +/// # Safety +/// +/// - Value is provided by the linker script and must be trusted as-is. +#[inline(always)] +fn virt_mmio_remap_start() -> PageAddress { + PageAddress::from(unsafe { __mmio_remap_start.get() as usize }) +} + +/// Size of the MMIO remap reservation. +/// +/// # Safety +/// +/// - Value is provided by the linker script and must be trusted as-is. +#[inline(always)] +fn mmio_remap_size() -> usize { + unsafe { (__mmio_remap_end_exclusive.get() as usize) - (__mmio_remap_start.get() as usize) } +} + +/// Start page address of the boot core's stack. +#[inline(always)] +fn virt_boot_core_stack_start() -> PageAddress { + PageAddress::from(unsafe { __boot_core_stack_start.get() as usize }) +} + +/// Size of the boot core's stack. +#[inline(always)] +fn boot_core_stack_size() -> usize { + unsafe { + (__boot_core_stack_end_exclusive.get() as usize) - (__boot_core_stack_start.get() as usize) + } +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +/// Exclusive end address of the physical address space. +#[inline(always)] +pub fn phys_addr_space_end_exclusive_addr() -> PageAddress { + PageAddress::from(map::END) +} diff --git a/20_timer_callbacks/kernel/src/bsp/raspberrypi/memory/mmu.rs b/20_timer_callbacks/kernel/src/bsp/raspberrypi/memory/mmu.rs new file mode 100644 index 00000000..bb2f8208 --- /dev/null +++ b/20_timer_callbacks/kernel/src/bsp/raspberrypi/memory/mmu.rs @@ -0,0 +1,197 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2018-2022 Andre Richter + +//! BSP Memory Management Unit. + +use crate::{ + memory::{ + mmu::{ + self as generic_mmu, AddressSpace, AssociatedTranslationTable, AttributeFields, + MemoryRegion, PageAddress, TranslationGranule, + }, + Physical, Virtual, + }, + synchronization::InitStateLock, +}; + +//-------------------------------------------------------------------------------------------------- +// Private Definitions +//-------------------------------------------------------------------------------------------------- + +type KernelTranslationTable = + ::TableStartFromTop; + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +/// The translation granule chosen by this BSP. This will be used everywhere else in the kernel to +/// derive respective data structures and their sizes. For example, the `crate::memory::mmu::Page`. +pub type KernelGranule = TranslationGranule<{ 64 * 1024 }>; + +/// The kernel's virtual address space defined by this BSP. +pub type KernelVirtAddrSpace = AddressSpace<{ kernel_virt_addr_space_size() }>; + +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +/// The kernel translation tables. +/// +/// It is mandatory that InitStateLock is transparent. +/// +/// That is, `size_of(InitStateLock) == size_of(KernelTranslationTable)`. +/// There is a unit tests that checks this porperty. +#[link_section = ".data"] +#[no_mangle] +static KERNEL_TABLES: InitStateLock = + InitStateLock::new(KernelTranslationTable::new_for_precompute()); + +/// This value is needed during early boot for MMU setup. +/// +/// This will be patched to the correct value by the "translation table tool" after linking. This +/// given value here is just a dummy. +#[link_section = ".text._start_arguments"] +#[no_mangle] +static PHYS_KERNEL_TABLES_BASE_ADDR: u64 = 0xCCCCAAAAFFFFEEEE; + +//-------------------------------------------------------------------------------------------------- +// Private Code +//-------------------------------------------------------------------------------------------------- + +/// This is a hack for retrieving the value for the kernel's virtual address space size as a +/// constant from a common place, since it is needed as a compile-time/link-time constant in both, +/// the linker script and the Rust sources. +#[allow(clippy::needless_late_init)] +const fn kernel_virt_addr_space_size() -> usize { + let __kernel_virt_addr_space_size; + + include!("../kernel_virt_addr_space_size.ld"); + + __kernel_virt_addr_space_size +} + +/// Helper function for calculating the number of pages the given parameter spans. +const fn size_to_num_pages(size: usize) -> usize { + assert!(size > 0); + assert!(size % KernelGranule::SIZE == 0); + + size >> KernelGranule::SHIFT +} + +/// The data pages of the kernel binary. +fn virt_data_region() -> MemoryRegion { + let num_pages = size_to_num_pages(super::data_size()); + + let start_page_addr = super::virt_data_start(); + let end_exclusive_page_addr = start_page_addr.checked_offset(num_pages as isize).unwrap(); + + MemoryRegion::new(start_page_addr, end_exclusive_page_addr) +} + +// There is no reason to expect the following conversions to fail, since they were generated offline +// by the `translation table tool`. If it doesn't work, a panic due to the unwraps is justified. +fn kernel_virt_to_phys_region(virt_region: MemoryRegion) -> MemoryRegion { + let phys_start_page_addr = + generic_mmu::try_kernel_virt_page_addr_to_phys_page_addr(virt_region.start_page_addr()) + .unwrap(); + + let phys_end_exclusive_page_addr = phys_start_page_addr + .checked_offset(virt_region.num_pages() as isize) + .unwrap(); + + MemoryRegion::new(phys_start_page_addr, phys_end_exclusive_page_addr) +} + +fn kernel_page_attributes(virt_page_addr: PageAddress) -> AttributeFields { + generic_mmu::try_kernel_page_attributes(virt_page_addr).unwrap() +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +/// The code pages of the kernel binary. +pub fn virt_code_region() -> MemoryRegion { + let num_pages = size_to_num_pages(super::code_size()); + + let start_page_addr = super::virt_code_start(); + let end_exclusive_page_addr = start_page_addr.checked_offset(num_pages as isize).unwrap(); + + MemoryRegion::new(start_page_addr, end_exclusive_page_addr) +} + +/// The heap pages. +pub fn virt_heap_region() -> MemoryRegion { + let num_pages = size_to_num_pages(super::heap_size()); + + let start_page_addr = super::virt_heap_start(); + let end_exclusive_page_addr = start_page_addr.checked_offset(num_pages as isize).unwrap(); + + MemoryRegion::new(start_page_addr, end_exclusive_page_addr) +} + +/// The boot core stack pages. +pub fn virt_boot_core_stack_region() -> MemoryRegion { + let num_pages = size_to_num_pages(super::boot_core_stack_size()); + + let start_page_addr = super::virt_boot_core_stack_start(); + let end_exclusive_page_addr = start_page_addr.checked_offset(num_pages as isize).unwrap(); + + MemoryRegion::new(start_page_addr, end_exclusive_page_addr) +} + +/// Return a reference to the kernel's translation tables. +pub fn kernel_translation_tables() -> &'static InitStateLock { + &KERNEL_TABLES +} + +/// The MMIO remap pages. +pub fn virt_mmio_remap_region() -> MemoryRegion { + let num_pages = size_to_num_pages(super::mmio_remap_size()); + + let start_page_addr = super::virt_mmio_remap_start(); + let end_exclusive_page_addr = start_page_addr.checked_offset(num_pages as isize).unwrap(); + + MemoryRegion::new(start_page_addr, end_exclusive_page_addr) +} + +/// Add mapping records for the kernel binary. +/// +/// The actual translation table entries for the kernel binary are generated using the offline +/// `translation table tool` and patched into the kernel binary. This function just adds the mapping +/// record entries. +pub fn kernel_add_mapping_records_for_precomputed() { + let virt_code_region = virt_code_region(); + generic_mmu::kernel_add_mapping_record( + "Kernel code and RO data", + &virt_code_region, + &kernel_virt_to_phys_region(virt_code_region), + &kernel_page_attributes(virt_code_region.start_page_addr()), + ); + + let virt_data_region = virt_data_region(); + generic_mmu::kernel_add_mapping_record( + "Kernel data and bss", + &virt_data_region, + &kernel_virt_to_phys_region(virt_data_region), + &kernel_page_attributes(virt_data_region.start_page_addr()), + ); + + let virt_heap_region = virt_heap_region(); + generic_mmu::kernel_add_mapping_record( + "Kernel heap", + &virt_heap_region, + &kernel_virt_to_phys_region(virt_heap_region), + &kernel_page_attributes(virt_heap_region.start_page_addr()), + ); + + let virt_boot_core_stack_region = virt_boot_core_stack_region(); + generic_mmu::kernel_add_mapping_record( + "Kernel boot-core stack", + &virt_boot_core_stack_region, + &kernel_virt_to_phys_region(virt_boot_core_stack_region), + &kernel_page_attributes(virt_boot_core_stack_region.start_page_addr()), + ); +} diff --git a/20_timer_callbacks/kernel/src/common.rs b/20_timer_callbacks/kernel/src/common.rs new file mode 100644 index 00000000..f32f650f --- /dev/null +++ b/20_timer_callbacks/kernel/src/common.rs @@ -0,0 +1,46 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2020-2022 Andre Richter + +//! General purpose code. + +/// Check if a value is aligned to a given size. +#[inline(always)] +pub const fn is_aligned(value: usize, alignment: usize) -> bool { + assert!(alignment.is_power_of_two()); + + (value & (alignment - 1)) == 0 +} + +/// Align down. +#[inline(always)] +pub const fn align_down(value: usize, alignment: usize) -> usize { + assert!(alignment.is_power_of_two()); + + value & !(alignment - 1) +} + +/// Align up. +#[inline(always)] +pub const fn align_up(value: usize, alignment: usize) -> usize { + assert!(alignment.is_power_of_two()); + + (value + alignment - 1) & !(alignment - 1) +} + +/// Convert a size into human readable format. +pub const fn size_human_readable_ceil(size: usize) -> (usize, &'static str) { + const KIB: usize = 1024; + const MIB: usize = 1024 * 1024; + const GIB: usize = 1024 * 1024 * 1024; + + if (size / GIB) > 0 { + (size.div_ceil(GIB), "GiB") + } else if (size / MIB) > 0 { + (size.div_ceil(MIB), "MiB") + } else if (size / KIB) > 0 { + (size.div_ceil(KIB), "KiB") + } else { + (size, "Byte") + } +} diff --git a/20_timer_callbacks/kernel/src/console.rs b/20_timer_callbacks/kernel/src/console.rs new file mode 100644 index 00000000..ff1d8ddc --- /dev/null +++ b/20_timer_callbacks/kernel/src/console.rs @@ -0,0 +1,93 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2018-2022 Andre Richter + +//! System console. + +mod buffer_console; + +use crate::synchronization; + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +/// Console interfaces. +pub mod interface { + use core::fmt; + + /// Console write functions. + pub trait Write { + /// Write a single character. + fn write_char(&self, c: char); + + /// Write a slice of characters. + fn write_array(&self, a: &[char]); + + /// Write a Rust format string. + fn write_fmt(&self, args: fmt::Arguments) -> fmt::Result; + + /// Block until the last buffered character has been physically put on the TX wire. + fn flush(&self); + } + + /// Console read functions. + pub trait Read { + /// Read a single character. + fn read_char(&self) -> char { + ' ' + } + + /// Clear RX buffers, if any. + fn clear_rx(&self); + } + + /// Console statistics. + pub trait Statistics { + /// Return the number of characters written. + fn chars_written(&self) -> usize { + 0 + } + + /// Return the number of characters read. + fn chars_read(&self) -> usize { + 0 + } + } + + /// Trait alias for a full-fledged console. + pub trait All: Write + Read + Statistics {} +} + +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +static CUR_CONSOLE: InitStateLock<&'static (dyn interface::All + Sync)> = + InitStateLock::new(&buffer_console::BUFFER_CONSOLE); + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- +use synchronization::{interface::ReadWriteEx, InitStateLock}; + +/// Register a new console. +pub fn register_console(new_console: &'static (dyn interface::All + Sync)) { + CUR_CONSOLE.write(|con| *con = new_console); + + static FIRST_SWITCH: InitStateLock = InitStateLock::new(true); + FIRST_SWITCH.write(|first| { + if *first { + *first = false; + + buffer_console::BUFFER_CONSOLE.dump(); + } + }); +} + +/// Return a reference to the currently registered console. +/// +/// This is the global console used by all printing macros. +pub fn console() -> &'static dyn interface::All { + CUR_CONSOLE.read(|con| *con) +} diff --git a/20_timer_callbacks/kernel/src/console/buffer_console.rs b/20_timer_callbacks/kernel/src/console/buffer_console.rs new file mode 100644 index 00000000..c3259f89 --- /dev/null +++ b/20_timer_callbacks/kernel/src/console/buffer_console.rs @@ -0,0 +1,108 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2022 Andre Richter + +//! A console that buffers input during the init phase. + +use super::interface; +use crate::{console, info, synchronization, synchronization::InitStateLock}; +use core::fmt; + +//-------------------------------------------------------------------------------------------------- +// Private Definitions +//-------------------------------------------------------------------------------------------------- + +const BUF_SIZE: usize = 1024 * 64; + +pub struct BufferConsoleInner { + buf: [char; BUF_SIZE], + write_ptr: usize, +} + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +pub struct BufferConsole { + inner: InitStateLock, +} + +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +pub static BUFFER_CONSOLE: BufferConsole = BufferConsole { + inner: InitStateLock::new(BufferConsoleInner { + // Use the null character, so this lands in .bss and does not waste space in the binary. + buf: ['\0'; BUF_SIZE], + write_ptr: 0, + }), +}; + +//-------------------------------------------------------------------------------------------------- +// Private Code +//-------------------------------------------------------------------------------------------------- + +impl BufferConsoleInner { + fn write_char(&mut self, c: char) { + if self.write_ptr < (BUF_SIZE - 1) { + self.buf[self.write_ptr] = c; + self.write_ptr += 1; + } + } +} + +impl fmt::Write for BufferConsoleInner { + fn write_str(&mut self, s: &str) -> fmt::Result { + for c in s.chars() { + self.write_char(c); + } + + Ok(()) + } +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- +use synchronization::interface::ReadWriteEx; + +impl BufferConsole { + /// Dump the buffer. + /// + /// # Invariant + /// + /// It is expected that this is only called when self != crate::console::console(). + pub fn dump(&self) { + self.inner.read(|inner| { + console::console().write_array(&inner.buf[0..inner.write_ptr]); + + if inner.write_ptr == (BUF_SIZE - 1) { + info!("Pre-UART buffer overflowed"); + } else if inner.write_ptr > 0 { + info!("End of pre-UART buffer") + } + }); + } +} + +impl interface::Write for BufferConsole { + fn write_char(&self, c: char) { + self.inner.write(|inner| inner.write_char(c)); + } + + fn write_array(&self, _a: &[char]) {} + + fn write_fmt(&self, args: fmt::Arguments) -> fmt::Result { + self.inner.write(|inner| fmt::Write::write_fmt(inner, args)) + } + + fn flush(&self) {} +} + +impl interface::Read for BufferConsole { + fn clear_rx(&self) {} +} + +impl interface::Statistics for BufferConsole {} +impl interface::All for BufferConsole {} diff --git a/20_timer_callbacks/kernel/src/cpu.rs b/20_timer_callbacks/kernel/src/cpu.rs new file mode 100644 index 00000000..e1493d1d --- /dev/null +++ b/20_timer_callbacks/kernel/src/cpu.rs @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2020-2022 Andre Richter + +//! Processor code. + +#[cfg(target_arch = "aarch64")] +#[path = "_arch/aarch64/cpu.rs"] +mod arch_cpu; + +mod boot; + +pub mod smp; + +//-------------------------------------------------------------------------------------------------- +// Architectural Public Reexports +//-------------------------------------------------------------------------------------------------- +pub use arch_cpu::{nop, wait_forever}; + +#[cfg(feature = "test_build")] +pub use arch_cpu::{qemu_exit_failure, qemu_exit_success}; diff --git a/20_timer_callbacks/kernel/src/cpu/boot.rs b/20_timer_callbacks/kernel/src/cpu/boot.rs new file mode 100644 index 00000000..8091dac3 --- /dev/null +++ b/20_timer_callbacks/kernel/src/cpu/boot.rs @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2021-2022 Andre Richter + +//! Boot code. + +#[cfg(target_arch = "aarch64")] +#[path = "../_arch/aarch64/cpu/boot.rs"] +mod arch_boot; diff --git a/20_timer_callbacks/kernel/src/cpu/smp.rs b/20_timer_callbacks/kernel/src/cpu/smp.rs new file mode 100644 index 00000000..57386f79 --- /dev/null +++ b/20_timer_callbacks/kernel/src/cpu/smp.rs @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2018-2022 Andre Richter + +//! Symmetric multiprocessing. + +#[cfg(target_arch = "aarch64")] +#[path = "../_arch/aarch64/cpu/smp.rs"] +mod arch_smp; + +//-------------------------------------------------------------------------------------------------- +// Architectural Public Reexports +//-------------------------------------------------------------------------------------------------- +pub use arch_smp::core_id; diff --git a/20_timer_callbacks/kernel/src/driver.rs b/20_timer_callbacks/kernel/src/driver.rs new file mode 100644 index 00000000..2f22fd20 --- /dev/null +++ b/20_timer_callbacks/kernel/src/driver.rs @@ -0,0 +1,178 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2018-2022 Andre Richter + +//! Driver support. + +use crate::{ + exception, info, + synchronization::{interface::ReadWriteEx, InitStateLock}, +}; +use alloc::vec::Vec; +use core::fmt; + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +/// Driver interfaces. +pub mod interface { + /// Device Driver functions. + pub trait DeviceDriver { + /// Different interrupt controllers might use different types for IRQ number. + type IRQNumberType: super::fmt::Display; + + /// Return a compatibility string for identifying the driver. + fn compatible(&self) -> &'static str; + + /// Called by the kernel to bring up the device. + /// + /// # Safety + /// + /// - During init, drivers might do stuff with system-wide impact. + unsafe fn init(&self) -> Result<(), &'static str> { + Ok(()) + } + + /// Called by the kernel to register and enable the device's IRQ handler. + /// + /// Rust's type system will prevent a call to this function unless the calling instance + /// itself has static lifetime. + fn register_and_enable_irq_handler( + &'static self, + irq_number: &Self::IRQNumberType, + ) -> Result<(), &'static str> { + panic!( + "Attempt to enable IRQ {} for device {}, but driver does not support this", + irq_number, + self.compatible() + ) + } + } +} + +/// Tpye to be used as an optional callback after a driver's init() has run. +pub type DeviceDriverPostInitCallback = unsafe fn() -> Result<(), &'static str>; + +/// A descriptor for device drivers. +pub struct DeviceDriverDescriptor +where + T: 'static, +{ + device_driver: &'static (dyn interface::DeviceDriver + Sync), + post_init_callback: Option, + irq_number: Option, +} + +/// Provides device driver management functions. +pub struct DriverManager +where + T: 'static, +{ + descriptors: InitStateLock>>, +} + +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +static DRIVER_MANAGER: DriverManager = DriverManager::new(); + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +impl DeviceDriverDescriptor { + /// Create an instance. + pub fn new( + device_driver: &'static (dyn interface::DeviceDriver + Sync), + post_init_callback: Option, + irq_number: Option, + ) -> Self { + Self { + device_driver, + post_init_callback, + irq_number, + } + } +} + +/// Return a reference to the global DriverManager. +pub fn driver_manager() -> &'static DriverManager { + &DRIVER_MANAGER +} + +impl DriverManager +where + T: fmt::Display, +{ + /// Create an instance. + pub const fn new() -> Self { + Self { + descriptors: InitStateLock::new(Vec::new()), + } + } + + /// Register a device driver with the kernel. + pub fn register_driver(&self, descriptor: DeviceDriverDescriptor) { + self.descriptors + .write(|descriptors| descriptors.push(descriptor)); + } + + /// Fully initialize all drivers and their interrupts handlers. + /// + /// # Safety + /// + /// - During init, drivers might do stuff with system-wide impact. + pub unsafe fn init_drivers_and_irqs(&self) { + self.descriptors.read(|descriptors| { + for descriptor in descriptors { + // 1. Initialize driver. + if let Err(x) = descriptor.device_driver.init() { + panic!( + "Error initializing driver: {}: {}", + descriptor.device_driver.compatible(), + x + ); + } + + // 2. Call corresponding post init callback. + if let Some(callback) = &descriptor.post_init_callback { + if let Err(x) = callback() { + panic!( + "Error during driver post-init callback: {}: {}", + descriptor.device_driver.compatible(), + x + ); + } + } + } + + // 3. After all post-init callbacks were done, the interrupt controller should be + // registered and functional. So let drivers register with it now. + for descriptor in descriptors { + if let Some(irq_number) = &descriptor.irq_number { + if let Err(x) = descriptor + .device_driver + .register_and_enable_irq_handler(irq_number) + { + panic!( + "Error during driver interrupt handler registration: {}: {}", + descriptor.device_driver.compatible(), + x + ); + } + } + } + }) + } + + /// Enumerate all registered device drivers. + pub fn enumerate(&self) { + self.descriptors.read(|descriptors| { + for (i, desc) in descriptors.iter().enumerate() { + info!(" {}. {}", i + 1, desc.device_driver.compatible()); + } + }); + } +} diff --git a/20_timer_callbacks/kernel/src/exception.rs b/20_timer_callbacks/kernel/src/exception.rs new file mode 100644 index 00000000..7ea7cd80 --- /dev/null +++ b/20_timer_callbacks/kernel/src/exception.rs @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2020-2022 Andre Richter + +//! Synchronous and asynchronous exception handling. + +#[cfg(target_arch = "aarch64")] +#[path = "_arch/aarch64/exception.rs"] +mod arch_exception; + +pub mod asynchronous; + +//-------------------------------------------------------------------------------------------------- +// Architectural Public Reexports +//-------------------------------------------------------------------------------------------------- +pub use arch_exception::{current_privilege_level, handling_init}; + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +/// Kernel privilege levels. +#[allow(missing_docs)] +#[derive(Eq, PartialEq)] +pub enum PrivilegeLevel { + User, + Kernel, + Hypervisor, + Unknown, +} + +//-------------------------------------------------------------------------------------------------- +// Testing +//-------------------------------------------------------------------------------------------------- + +#[cfg(test)] +mod tests { + use super::*; + use test_macros::kernel_test; + + /// Libkernel unit tests must execute in kernel mode. + #[kernel_test] + fn test_runner_executes_in_kernel_mode() { + let (level, _) = current_privilege_level(); + + assert!(level == PrivilegeLevel::Kernel) + } +} diff --git a/20_timer_callbacks/kernel/src/exception/asynchronous.rs b/20_timer_callbacks/kernel/src/exception/asynchronous.rs new file mode 100644 index 00000000..c1f2a27b --- /dev/null +++ b/20_timer_callbacks/kernel/src/exception/asynchronous.rs @@ -0,0 +1,190 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2020-2022 Andre Richter + +//! Asynchronous exception handling. + +#[cfg(target_arch = "aarch64")] +#[path = "../_arch/aarch64/exception/asynchronous.rs"] +mod arch_asynchronous; +mod null_irq_manager; + +use crate::{bsp, synchronization}; +use core::marker::PhantomData; + +//-------------------------------------------------------------------------------------------------- +// Architectural Public Reexports +//-------------------------------------------------------------------------------------------------- +pub use arch_asynchronous::{ + is_local_irq_masked, local_irq_mask, local_irq_mask_save, local_irq_restore, local_irq_unmask, + print_state, +}; + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +/// Interrupt number as defined by the BSP. +pub type IRQNumber = bsp::exception::asynchronous::IRQNumber; + +/// Interrupt descriptor. +#[derive(Copy, Clone)] +pub struct IRQHandlerDescriptor +where + T: Copy, +{ + /// The IRQ number. + number: T, + + /// Descriptive name. + name: &'static str, + + /// Reference to handler trait object. + handler: &'static (dyn interface::IRQHandler + Sync), +} + +/// IRQContext token. +/// +/// An instance of this type indicates that the local core is currently executing in IRQ +/// context, aka executing an interrupt vector or subcalls of it. +/// +/// Concept and implementation derived from the `CriticalSection` introduced in +/// +#[derive(Clone, Copy)] +pub struct IRQContext<'irq_context> { + _0: PhantomData<&'irq_context ()>, +} + +/// Asynchronous exception handling interfaces. +pub mod interface { + + /// Implemented by types that handle IRQs. + pub trait IRQHandler { + /// Called when the corresponding interrupt is asserted. + fn handle(&self) -> Result<(), &'static str>; + } + + /// IRQ management functions. + /// + /// The `BSP` is supposed to supply one global instance. Typically implemented by the + /// platform's interrupt controller. + pub trait IRQManager { + /// The IRQ number type depends on the implementation. + type IRQNumberType: Copy; + + /// Register a handler. + fn register_handler( + &self, + irq_handler_descriptor: super::IRQHandlerDescriptor, + ) -> Result<(), &'static str>; + + /// Enable an interrupt in the controller. + fn enable(&self, irq_number: &Self::IRQNumberType); + + /// Handle pending interrupts. + /// + /// This function is called directly from the CPU's IRQ exception vector. On AArch64, + /// this means that the respective CPU core has disabled exception handling. + /// This function can therefore not be preempted and runs start to finish. + /// + /// Takes an IRQContext token to ensure it can only be called from IRQ context. + #[allow(clippy::trivially_copy_pass_by_ref)] + fn handle_pending_irqs<'irq_context>( + &'irq_context self, + ic: &super::IRQContext<'irq_context>, + ); + + /// Print list of registered handlers. + fn print_handler(&self) {} + } +} + +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +static CUR_IRQ_MANAGER: InitStateLock< + &'static (dyn interface::IRQManager + Sync), +> = InitStateLock::new(&null_irq_manager::NULL_IRQ_MANAGER); + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- +use synchronization::{interface::ReadWriteEx, InitStateLock}; + +impl IRQHandlerDescriptor +where + T: Copy, +{ + /// Create an instance. + pub const fn new( + number: T, + name: &'static str, + handler: &'static (dyn interface::IRQHandler + Sync), + ) -> Self { + Self { + number, + name, + handler, + } + } + + /// Return the number. + pub const fn number(&self) -> T { + self.number + } + + /// Return the name. + pub const fn name(&self) -> &'static str { + self.name + } + + /// Return the handler. + pub const fn handler(&self) -> &'static (dyn interface::IRQHandler + Sync) { + self.handler + } +} + +impl<'irq_context> IRQContext<'irq_context> { + /// Creates an IRQContext token. + /// + /// # Safety + /// + /// - This must only be called when the current core is in an interrupt context and will not + /// live beyond the end of it. That is, creation is allowed in interrupt vector functions. For + /// example, in the ARMv8-A case, in `extern "C" fn current_elx_irq()`. + /// - Note that the lifetime `'irq_context` of the returned instance is unconstrained. User code + /// must not be able to influence the lifetime picked for this type, since that might cause it + /// to be inferred to `'static`. + #[inline(always)] + pub unsafe fn new() -> Self { + IRQContext { _0: PhantomData } + } +} + +/// Executes the provided closure while IRQs are masked on the executing core. +/// +/// While the function temporarily changes the HW state of the executing core, it restores it to the +/// previous state before returning, so this is deemed safe. +#[inline(always)] +pub fn exec_with_irq_masked(f: impl FnOnce() -> T) -> T { + let saved = local_irq_mask_save(); + let ret = f(); + local_irq_restore(saved); + + ret +} + +/// Register a new IRQ manager. +pub fn register_irq_manager( + new_manager: &'static (dyn interface::IRQManager + Sync), +) { + CUR_IRQ_MANAGER.write(|manager| *manager = new_manager); +} + +/// Return a reference to the currently registered IRQ manager. +/// +/// This is the IRQ manager used by the architectural interrupt handling code. +pub fn irq_manager() -> &'static dyn interface::IRQManager { + CUR_IRQ_MANAGER.read(|manager| *manager) +} diff --git a/20_timer_callbacks/kernel/src/exception/asynchronous/null_irq_manager.rs b/20_timer_callbacks/kernel/src/exception/asynchronous/null_irq_manager.rs new file mode 100644 index 00000000..438f9649 --- /dev/null +++ b/20_timer_callbacks/kernel/src/exception/asynchronous/null_irq_manager.rs @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2022 Andre Richter + +//! Null IRQ Manager. + +use super::{interface, IRQContext, IRQHandlerDescriptor}; + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +pub struct NullIRQManager; + +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +pub static NULL_IRQ_MANAGER: NullIRQManager = NullIRQManager {}; + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +impl interface::IRQManager for NullIRQManager { + type IRQNumberType = super::IRQNumber; + + fn register_handler( + &self, + _descriptor: IRQHandlerDescriptor, + ) -> Result<(), &'static str> { + panic!("No IRQ Manager registered yet"); + } + + fn enable(&self, _irq_number: &Self::IRQNumberType) { + panic!("No IRQ Manager registered yet"); + } + + fn handle_pending_irqs<'irq_context>(&'irq_context self, _ic: &IRQContext<'irq_context>) { + panic!("No IRQ Manager registered yet"); + } +} diff --git a/20_timer_callbacks/kernel/src/lib.rs b/20_timer_callbacks/kernel/src/lib.rs new file mode 100644 index 00000000..bba0fcc7 --- /dev/null +++ b/20_timer_callbacks/kernel/src/lib.rs @@ -0,0 +1,196 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2018-2022 Andre Richter + +// Rust embedded logo for `make doc`. +#![doc( + html_logo_url = "https://raw.githubusercontent.com/rust-embedded/wg/master/assets/logo/ewg-logo-blue-white-on-transparent.png" +)] + +//! The `kernel` library. +//! +//! Used to compose the final kernel binary. +//! +//! # Code organization and architecture +//! +//! The code is divided into different *modules*, each representing a typical **subsystem** of the +//! `kernel`. Top-level module files of subsystems reside directly in the `src` folder. For example, +//! `src/memory.rs` contains code that is concerned with all things memory management. +//! +//! ## Visibility of processor architecture code +//! +//! Some of the `kernel`'s subsystems depend on low-level code that is specific to the target +//! processor architecture. For each supported processor architecture, there exists a subfolder in +//! `src/_arch`, for example, `src/_arch/aarch64`. +//! +//! The architecture folders mirror the subsystem modules laid out in `src`. For example, +//! architectural code that belongs to the `kernel`'s MMU subsystem (`src/memory/mmu.rs`) would go +//! into `src/_arch/aarch64/memory/mmu.rs`. The latter file is loaded as a module in +//! `src/memory/mmu.rs` using the `path attribute`. Usually, the chosen module name is the generic +//! module's name prefixed with `arch_`. +//! +//! For example, this is the top of `src/memory/mmu.rs`: +//! +//! ``` +//! #[cfg(target_arch = "aarch64")] +//! #[path = "../_arch/aarch64/memory/mmu.rs"] +//! mod arch_mmu; +//! ``` +//! +//! Often times, items from the `arch_ module` will be publicly reexported by the parent module. +//! This way, each architecture specific module can provide its implementation of an item, while the +//! caller must not be concerned which architecture has been conditionally compiled. +//! +//! ## BSP code +//! +//! `BSP` stands for Board Support Package. `BSP` code is organized under `src/bsp.rs` and contains +//! target board specific definitions and functions. These are things such as the board's memory map +//! or instances of drivers for devices that are featured on the respective board. +//! +//! Just like processor architecture code, the `BSP` code's module structure tries to mirror the +//! `kernel`'s subsystem modules, but there is no reexporting this time. That means whatever is +//! provided must be called starting from the `bsp` namespace, e.g. `bsp::driver::driver_manager()`. +//! +//! ## Kernel interfaces +//! +//! Both `arch` and `bsp` contain code that is conditionally compiled depending on the actual target +//! and board for which the kernel is compiled. For example, the `interrupt controller` hardware of +//! the `Raspberry Pi 3` and the `Raspberry Pi 4` is different, but we want the rest of the `kernel` +//! code to play nicely with any of the two without much hassle. +//! +//! In order to provide a clean abstraction between `arch`, `bsp` and `generic kernel code`, +//! `interface` traits are provided *whenever possible* and *where it makes sense*. They are defined +//! in the respective subsystem module and help to enforce the idiom of *program to an interface, +//! not an implementation*. For example, there will be a common IRQ handling interface which the two +//! different interrupt controller `drivers` of both Raspberrys will implement, and only export the +//! interface to the rest of the `kernel`. +//! +//! ``` +//! +-------------------+ +//! | Interface (Trait) | +//! | | +//! +--+-------------+--+ +//! ^ ^ +//! | | +//! | | +//! +----------+--+ +--+----------+ +//! | kernel code | | bsp code | +//! | | | arch code | +//! +-------------+ +-------------+ +//! ``` +//! +//! # Summary +//! +//! For a logical `kernel` subsystem, corresponding code can be distributed over several physical +//! locations. Here is an example for the **memory** subsystem: +//! +//! - `src/memory.rs` and `src/memory/**/*` +//! - Common code that is agnostic of target processor architecture and `BSP` characteristics. +//! - Example: A function to zero a chunk of memory. +//! - Interfaces for the memory subsystem that are implemented by `arch` or `BSP` code. +//! - Example: An `MMU` interface that defines `MMU` function prototypes. +//! - `src/bsp/__board_name__/memory.rs` and `src/bsp/__board_name__/memory/**/*` +//! - `BSP` specific code. +//! - Example: The board's memory map (physical addresses of DRAM and MMIO devices). +//! - `src/_arch/__arch_name__/memory.rs` and `src/_arch/__arch_name__/memory/**/*` +//! - Processor architecture specific code. +//! - Example: Implementation of the `MMU` interface for the `__arch_name__` processor +//! architecture. +//! +//! From a namespace perspective, **memory** subsystem code lives in: +//! +//! - `crate::memory::*` +//! - `crate::bsp::memory::*` +//! +//! # Boot flow +//! +//! 1. The kernel's entry point is the function `cpu::boot::arch_boot::_start()`. +//! - It is implemented in `src/_arch/__arch_name__/cpu/boot.s`. +//! 2. Once finished with architectural setup, the arch code calls `kernel_init()`. + +#![allow(clippy::upper_case_acronyms)] +#![allow(incomplete_features)] +#![feature(alloc_error_handler)] +#![feature(asm_const)] +#![feature(const_option)] +#![feature(core_intrinsics)] +#![feature(format_args_nl)] +#![feature(generic_const_exprs)] +#![feature(int_roundings)] +#![feature(is_sorted)] +#![feature(linkage)] +#![feature(nonzero_min_max)] +#![feature(panic_info_message)] +#![feature(step_trait)] +#![feature(trait_alias)] +#![feature(unchecked_math)] +#![no_std] +// Testing +#![cfg_attr(test, no_main)] +#![feature(custom_test_frameworks)] +#![reexport_test_harness_main = "test_main"] +#![test_runner(crate::test_runner)] + +extern crate alloc; + +mod panic_wait; +mod synchronization; + +pub mod backtrace; +pub mod bsp; +pub mod common; +pub mod console; +pub mod cpu; +pub mod driver; +pub mod exception; +pub mod memory; +pub mod print; +pub mod state; +pub mod symbols; +pub mod time; + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +/// Version string. +pub fn version() -> &'static str { + concat!( + env!("CARGO_PKG_NAME"), + " version ", + env!("CARGO_PKG_VERSION") + ) +} + +//-------------------------------------------------------------------------------------------------- +// Testing +//-------------------------------------------------------------------------------------------------- + +/// The default runner for unit tests. +pub fn test_runner(tests: &[&test_types::UnitTest]) { + // This line will be printed as the test header. + println!("Running {} tests", tests.len()); + + for (i, test) in tests.iter().enumerate() { + print!("{:>3}. {:.<58}", i + 1, test.name); + + // Run the actual test. + (test.test_func)(); + + // Failed tests call panic!(). Execution reaches here only if the test has passed. + println!("[ok]") + } +} + +/// The `kernel_init()` for unit tests. +#[cfg(test)] +#[no_mangle] +unsafe fn kernel_init() -> ! { + exception::handling_init(); + memory::init(); + bsp::driver::qemu_bring_up_console(); + + test_main(); + + cpu::qemu_exit_success() +} diff --git a/20_timer_callbacks/kernel/src/main.rs b/20_timer_callbacks/kernel/src/main.rs new file mode 100644 index 00000000..28b75340 --- /dev/null +++ b/20_timer_callbacks/kernel/src/main.rs @@ -0,0 +1,96 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2018-2022 Andre Richter + +// Rust embedded logo for `make doc`. +#![doc( + html_logo_url = "https://raw.githubusercontent.com/rust-embedded/wg/master/assets/logo/ewg-logo-blue-white-on-transparent.png" +)] + +//! The `kernel` binary. + +#![feature(format_args_nl)] +#![no_main] +#![no_std] + +extern crate alloc; + +use libkernel::{bsp, cpu, driver, exception, info, memory, state, time}; + +/// Early init code. +/// +/// When this code runs, virtual memory is already enabled. +/// +/// # Safety +/// +/// - Only a single core must be active and running this function. +/// - Printing will not work until the respective driver's MMIO is remapped. +#[no_mangle] +unsafe fn kernel_init() -> ! { + exception::handling_init(); + memory::init(); + + // Initialize the timer subsystem. + if let Err(x) = time::init() { + panic!("Error initializing timer subsystem: {}", x); + } + + // Initialize the BSP driver subsystem. + if let Err(x) = bsp::driver::init() { + panic!("Error initializing BSP driver subsystem: {}", x); + } + + // Initialize all device drivers. + driver::driver_manager().init_drivers_and_irqs(); + + bsp::memory::mmu::kernel_add_mapping_records_for_precomputed(); + + // Unmask interrupts on the boot CPU core. + exception::asynchronous::local_irq_unmask(); + + // Announce conclusion of the kernel_init() phase. + state::state_manager().transition_to_single_core_main(); + + // Transition from unsafe to safe. + kernel_main() +} + +/// The main function running after the early init. +fn kernel_main() -> ! { + use alloc::boxed::Box; + use core::time::Duration; + + info!("{}", libkernel::version()); + info!("Booting on: {}", bsp::board_name()); + + info!("MMU online:"); + memory::mmu::kernel_print_mappings(); + + let (_, privilege_level) = exception::current_privilege_level(); + info!("Current privilege level: {}", privilege_level); + + info!("Exception handling state:"); + exception::asynchronous::print_state(); + + info!( + "Architectural timer resolution: {} ns", + time::time_manager().resolution().as_nanos() + ); + + info!("Drivers loaded:"); + driver::driver_manager().enumerate(); + + info!("Registered IRQ handlers:"); + exception::asynchronous::irq_manager().print_handler(); + + info!("Kernel heap:"); + memory::heap_alloc::kernel_heap_allocator().print_usage(); + + time::time_manager().set_timeout_once(Duration::from_secs(5), Box::new(|| info!("Once 5"))); + time::time_manager().set_timeout_once(Duration::from_secs(3), Box::new(|| info!("Once 2"))); + time::time_manager() + .set_timeout_periodic(Duration::from_secs(1), Box::new(|| info!("Periodic 1 sec"))); + + info!("Echoing input now"); + cpu::wait_forever(); +} diff --git a/20_timer_callbacks/kernel/src/memory.rs b/20_timer_callbacks/kernel/src/memory.rs new file mode 100644 index 00000000..a64bfbae --- /dev/null +++ b/20_timer_callbacks/kernel/src/memory.rs @@ -0,0 +1,198 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2018-2022 Andre Richter + +//! Memory Management. + +pub mod heap_alloc; +pub mod mmu; + +use crate::{bsp, common}; +use core::{ + fmt, + marker::PhantomData, + ops::{Add, Sub}, +}; + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +/// Metadata trait for marking the type of an address. +pub trait AddressType: Copy + Clone + PartialOrd + PartialEq + Ord + Eq {} + +/// Zero-sized type to mark a physical address. +#[derive(Copy, Clone, Debug, PartialOrd, PartialEq, Ord, Eq)] +pub enum Physical {} + +/// Zero-sized type to mark a virtual address. +#[derive(Copy, Clone, Debug, PartialOrd, PartialEq, Ord, Eq)] +pub enum Virtual {} + +/// Generic address type. +#[derive(Copy, Clone, Debug, PartialOrd, PartialEq, Ord, Eq)] +pub struct Address { + value: usize, + _address_type: PhantomData ATYPE>, +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +impl AddressType for Physical {} +impl AddressType for Virtual {} + +impl Address { + /// Create an instance. + pub const fn new(value: usize) -> Self { + Self { + value, + _address_type: PhantomData, + } + } + + /// Convert to usize. + pub const fn as_usize(self) -> usize { + self.value + } + + /// Align down to page size. + #[must_use] + pub const fn align_down_page(self) -> Self { + let aligned = common::align_down(self.value, bsp::memory::mmu::KernelGranule::SIZE); + + Self::new(aligned) + } + + /// Align up to page size. + #[must_use] + pub const fn align_up_page(self) -> Self { + let aligned = common::align_up(self.value, bsp::memory::mmu::KernelGranule::SIZE); + + Self::new(aligned) + } + + /// Checks if the address is page aligned. + pub const fn is_page_aligned(&self) -> bool { + common::is_aligned(self.value, bsp::memory::mmu::KernelGranule::SIZE) + } + + /// Return the address' offset into the corresponding page. + pub const fn offset_into_page(&self) -> usize { + self.value & bsp::memory::mmu::KernelGranule::MASK + } +} + +impl Add for Address { + type Output = Self; + + #[inline(always)] + fn add(self, rhs: usize) -> Self::Output { + match self.value.checked_add(rhs) { + None => panic!("Overflow on Address::add"), + Some(x) => Self::new(x), + } + } +} + +impl Sub for Address { + type Output = Self; + + #[inline(always)] + fn sub(self, rhs: usize) -> Self::Output { + match self.value.checked_sub(rhs) { + None => panic!("Overflow on Address::sub"), + Some(x) => Self::new(x), + } + } +} + +impl Sub> for Address { + type Output = Self; + + #[inline(always)] + fn sub(self, rhs: Address) -> Self::Output { + match self.value.checked_sub(rhs.value) { + None => panic!("Overflow on Address::sub"), + Some(x) => Self::new(x), + } + } +} + +impl Address { + /// Checks if the address is part of the boot core stack region. + pub fn is_valid_stack_addr(&self) -> bool { + bsp::memory::mmu::virt_boot_core_stack_region().contains(*self) + } + + /// Checks if the address is part of the kernel code region. + pub fn is_valid_code_addr(&self) -> bool { + bsp::memory::mmu::virt_code_region().contains(*self) + } +} + +impl fmt::Display for Address { + // Don't expect to see physical addresses greater than 40 bit. + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let q3: u8 = ((self.value >> 32) & 0xff) as u8; + let q2: u16 = ((self.value >> 16) & 0xffff) as u16; + let q1: u16 = (self.value & 0xffff) as u16; + + write!(f, "0x")?; + write!(f, "{:02x}_", q3)?; + write!(f, "{:04x}_", q2)?; + write!(f, "{:04x}", q1) + } +} + +impl fmt::Display for Address { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let q4: u16 = ((self.value >> 48) & 0xffff) as u16; + let q3: u16 = ((self.value >> 32) & 0xffff) as u16; + let q2: u16 = ((self.value >> 16) & 0xffff) as u16; + let q1: u16 = (self.value & 0xffff) as u16; + + write!(f, "0x")?; + write!(f, "{:04x}_", q4)?; + write!(f, "{:04x}_", q3)?; + write!(f, "{:04x}_", q2)?; + write!(f, "{:04x}", q1) + } +} + +/// Initialize the memory subsystem. +pub fn init() { + mmu::kernel_init_mmio_va_allocator(); + heap_alloc::kernel_init_heap_allocator(); +} + +//-------------------------------------------------------------------------------------------------- +// Testing +//-------------------------------------------------------------------------------------------------- + +#[cfg(test)] +mod tests { + use super::*; + use test_macros::kernel_test; + + /// Sanity of [Address] methods. + #[kernel_test] + fn address_type_method_sanity() { + let addr = Address::::new(bsp::memory::mmu::KernelGranule::SIZE + 100); + + assert_eq!( + addr.align_down_page().as_usize(), + bsp::memory::mmu::KernelGranule::SIZE + ); + + assert_eq!( + addr.align_up_page().as_usize(), + bsp::memory::mmu::KernelGranule::SIZE * 2 + ); + + assert!(!addr.is_page_aligned()); + + assert_eq!(addr.offset_into_page(), 100); + } +} diff --git a/20_timer_callbacks/kernel/src/memory/heap_alloc.rs b/20_timer_callbacks/kernel/src/memory/heap_alloc.rs new file mode 100644 index 00000000..c0f56d8d --- /dev/null +++ b/20_timer_callbacks/kernel/src/memory/heap_alloc.rs @@ -0,0 +1,147 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2022 Andre Richter + +//! Heap allocation. + +use crate::{ + backtrace, bsp, common, debug, info, + memory::{Address, Virtual}, + synchronization, + synchronization::IRQSafeNullLock, + warn, +}; +use alloc::alloc::{GlobalAlloc, Layout}; +use core::sync::atomic::{AtomicBool, Ordering}; +use linked_list_allocator::Heap as LinkedListHeap; + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +/// A heap allocator that can be lazyily initialized. +pub struct HeapAllocator { + inner: IRQSafeNullLock, +} + +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +#[global_allocator] +static KERNEL_HEAP_ALLOCATOR: HeapAllocator = HeapAllocator::new(); + +//-------------------------------------------------------------------------------------------------- +// Private Code +//-------------------------------------------------------------------------------------------------- + +#[inline(always)] +fn debug_print_alloc_dealloc(operation: &'static str, ptr: *mut u8, layout: Layout) { + let size = layout.size(); + let (size_h, size_unit) = common::size_human_readable_ceil(size); + let addr = Address::::new(ptr as usize); + + debug!( + "Kernel Heap: {}\n \ + Size: {:#x} ({} {})\n \ + Start: {}\n \ + End excl: {}\n\n \ + {}", + operation, + size, + size_h, + size_unit, + addr, + addr + size, + backtrace::Backtrace + ); +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- +use synchronization::interface::Mutex; + +#[alloc_error_handler] +fn alloc_error_handler(layout: Layout) -> ! { + panic!("Allocation error: {:?}", layout) +} + +/// Return a reference to the kernel's heap allocator. +pub fn kernel_heap_allocator() -> &'static HeapAllocator { + &KERNEL_HEAP_ALLOCATOR +} + +impl HeapAllocator { + /// Create an instance. + pub const fn new() -> Self { + Self { + inner: IRQSafeNullLock::new(LinkedListHeap::empty()), + } + } + + /// Print the current heap usage. + pub fn print_usage(&self) { + let (used, free) = KERNEL_HEAP_ALLOCATOR + .inner + .lock(|inner| (inner.used(), inner.free())); + + if used >= 1024 { + let (used_h, used_unit) = common::size_human_readable_ceil(used); + info!(" Used: {} Byte ({} {})", used, used_h, used_unit); + } else { + info!(" Used: {} Byte", used); + } + + if free >= 1024 { + let (free_h, free_unit) = common::size_human_readable_ceil(free); + info!(" Free: {} Byte ({} {})", free, free_h, free_unit); + } else { + info!(" Free: {} Byte", free); + } + } +} + +unsafe impl GlobalAlloc for HeapAllocator { + unsafe fn alloc(&self, layout: Layout) -> *mut u8 { + let result = KERNEL_HEAP_ALLOCATOR + .inner + .lock(|inner| inner.allocate_first_fit(layout).ok()); + + match result { + None => core::ptr::null_mut(), + Some(allocation) => { + let ptr = allocation.as_ptr(); + + debug_print_alloc_dealloc("Allocation", ptr, layout); + + ptr + } + } + } + + unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) { + KERNEL_HEAP_ALLOCATOR + .inner + .lock(|inner| inner.deallocate(core::ptr::NonNull::new_unchecked(ptr), layout)); + + debug_print_alloc_dealloc("Free", ptr, layout); + } +} + +/// Query the BSP for the heap region and initialize the kernel's heap allocator with it. +pub fn kernel_init_heap_allocator() { + static INIT_DONE: AtomicBool = AtomicBool::new(false); + if INIT_DONE.load(Ordering::Relaxed) { + warn!("Already initialized"); + return; + } + + let region = bsp::memory::mmu::virt_heap_region(); + + KERNEL_HEAP_ALLOCATOR.inner.lock(|inner| unsafe { + inner.init(region.start_addr().as_usize() as *mut u8, region.size()) + }); + + INIT_DONE.store(true, Ordering::Relaxed); +} diff --git a/20_timer_callbacks/kernel/src/memory/mmu.rs b/20_timer_callbacks/kernel/src/memory/mmu.rs new file mode 100644 index 00000000..8d204a4e --- /dev/null +++ b/20_timer_callbacks/kernel/src/memory/mmu.rs @@ -0,0 +1,262 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2020-2022 Andre Richter + +//! Memory Management Unit. + +#[cfg(target_arch = "aarch64")] +#[path = "../_arch/aarch64/memory/mmu.rs"] +mod arch_mmu; + +mod mapping_record; +mod page_alloc; +mod translation_table; +mod types; + +use crate::{ + bsp, + memory::{Address, Physical, Virtual}, + synchronization::{self, interface::Mutex}, +}; +use core::{fmt, num::NonZeroUsize}; + +pub use types::*; + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +/// MMU enable errors variants. +#[allow(missing_docs)] +#[derive(Debug)] +pub enum MMUEnableError { + AlreadyEnabled, + Other(&'static str), +} + +/// Memory Management interfaces. +pub mod interface { + use super::*; + + /// MMU functions. + pub trait MMU { + /// Turns on the MMU for the first time and enables data and instruction caching. + /// + /// # Safety + /// + /// - Changes the HW's global state. + unsafe fn enable_mmu_and_caching( + &self, + phys_tables_base_addr: Address, + ) -> Result<(), MMUEnableError>; + + /// Returns true if the MMU is enabled, false otherwise. + fn is_enabled(&self) -> bool; + } +} + +/// Describes the characteristics of a translation granule. +pub struct TranslationGranule; + +/// Describes properties of an address space. +pub struct AddressSpace; + +/// Intended to be implemented for [`AddressSpace`]. +pub trait AssociatedTranslationTable { + /// A translation table whose address range is: + /// + /// [u64::MAX, (u64::MAX - AS_SIZE) + 1] + type TableStartFromTop; + + /// A translation table whose address range is: + /// + /// [AS_SIZE - 1, 0] + type TableStartFromBottom; +} + +//-------------------------------------------------------------------------------------------------- +// Private Code +//-------------------------------------------------------------------------------------------------- +use interface::MMU; +use synchronization::interface::ReadWriteEx; +use translation_table::interface::TranslationTable; + +/// Map a region in the kernel's translation tables. +/// +/// No input checks done, input is passed through to the architectural implementation. +/// +/// # Safety +/// +/// - See `map_at()`. +/// - Does not prevent aliasing. +unsafe fn kernel_map_at_unchecked( + name: &'static str, + virt_region: &MemoryRegion, + phys_region: &MemoryRegion, + attr: &AttributeFields, +) -> Result<(), &'static str> { + bsp::memory::mmu::kernel_translation_tables() + .write(|tables| tables.map_at(virt_region, phys_region, attr))?; + + kernel_add_mapping_record(name, virt_region, phys_region, attr); + + Ok(()) +} + +/// Try to translate a kernel virtual address to a physical address. +/// +/// Will only succeed if there exists a valid mapping for the input address. +fn try_kernel_virt_addr_to_phys_addr( + virt_addr: Address, +) -> Result, &'static str> { + bsp::memory::mmu::kernel_translation_tables() + .read(|tables| tables.try_virt_addr_to_phys_addr(virt_addr)) +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +impl fmt::Display for MMUEnableError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + MMUEnableError::AlreadyEnabled => write!(f, "MMU is already enabled"), + MMUEnableError::Other(x) => write!(f, "{}", x), + } + } +} + +impl TranslationGranule { + /// The granule's size. + pub const SIZE: usize = Self::size_checked(); + + /// The granule's mask. + pub const MASK: usize = Self::SIZE - 1; + + /// The granule's shift, aka log2(size). + pub const SHIFT: usize = Self::SIZE.trailing_zeros() as usize; + + const fn size_checked() -> usize { + assert!(GRANULE_SIZE.is_power_of_two()); + + GRANULE_SIZE + } +} + +impl AddressSpace { + /// The address space size. + pub const SIZE: usize = Self::size_checked(); + + /// The address space shift, aka log2(size). + pub const SIZE_SHIFT: usize = Self::SIZE.trailing_zeros() as usize; + + const fn size_checked() -> usize { + assert!(AS_SIZE.is_power_of_two()); + + // Check for architectural restrictions as well. + Self::arch_address_space_size_sanity_checks(); + + AS_SIZE + } +} + +/// Query the BSP for the reserved virtual addresses for MMIO remapping and initialize the kernel's +/// MMIO VA allocator with it. +pub fn kernel_init_mmio_va_allocator() { + let region = bsp::memory::mmu::virt_mmio_remap_region(); + + page_alloc::kernel_mmio_va_allocator().lock(|allocator| allocator.init(region)); +} + +/// Add an entry to the mapping info record. +pub fn kernel_add_mapping_record( + name: &'static str, + virt_region: &MemoryRegion, + phys_region: &MemoryRegion, + attr: &AttributeFields, +) { + mapping_record::kernel_add(name, virt_region, phys_region, attr); +} + +/// MMIO remapping in the kernel translation tables. +/// +/// Typically used by device drivers. +/// +/// # Safety +/// +/// - Same as `kernel_map_at_unchecked()`, minus the aliasing part. +pub unsafe fn kernel_map_mmio( + name: &'static str, + mmio_descriptor: &MMIODescriptor, +) -> Result, &'static str> { + let phys_region = MemoryRegion::from(*mmio_descriptor); + let offset_into_start_page = mmio_descriptor.start_addr().offset_into_page(); + + // Check if an identical region has been mapped for another driver. If so, reuse it. + let virt_addr = if let Some(addr) = + mapping_record::kernel_find_and_insert_mmio_duplicate(mmio_descriptor, name) + { + addr + // Otherwise, allocate a new region and map it. + } else { + let num_pages = match NonZeroUsize::new(phys_region.num_pages()) { + None => return Err("Requested 0 pages"), + Some(x) => x, + }; + + let virt_region = + page_alloc::kernel_mmio_va_allocator().lock(|allocator| allocator.alloc(num_pages))?; + + kernel_map_at_unchecked( + name, + &virt_region, + &phys_region, + &AttributeFields { + mem_attributes: MemAttributes::Device, + acc_perms: AccessPermissions::ReadWrite, + execute_never: true, + }, + )?; + + virt_region.start_addr() + }; + + Ok(virt_addr + offset_into_start_page) +} + +/// Try to translate a kernel virtual page address to a physical page address. +/// +/// Will only succeed if there exists a valid mapping for the input page. +pub fn try_kernel_virt_page_addr_to_phys_page_addr( + virt_page_addr: PageAddress, +) -> Result, &'static str> { + bsp::memory::mmu::kernel_translation_tables() + .read(|tables| tables.try_virt_page_addr_to_phys_page_addr(virt_page_addr)) +} + +/// Try to get the attributes of a kernel page. +/// +/// Will only succeed if there exists a valid mapping for the input page. +pub fn try_kernel_page_attributes( + virt_page_addr: PageAddress, +) -> Result { + bsp::memory::mmu::kernel_translation_tables() + .read(|tables| tables.try_page_attributes(virt_page_addr)) +} + +/// Human-readable print of all recorded kernel mappings. +pub fn kernel_print_mappings() { + mapping_record::kernel_print() +} + +/// Enable the MMU and data + instruction caching. +/// +/// # Safety +/// +/// - Crucial function during kernel init. Changes the the complete memory view of the processor. +#[inline(always)] +pub unsafe fn enable_mmu_and_caching( + phys_tables_base_addr: Address, +) -> Result<(), MMUEnableError> { + arch_mmu::mmu().enable_mmu_and_caching(phys_tables_base_addr) +} diff --git a/20_timer_callbacks/kernel/src/memory/mmu/mapping_record.rs b/20_timer_callbacks/kernel/src/memory/mmu/mapping_record.rs new file mode 100644 index 00000000..4e9395da --- /dev/null +++ b/20_timer_callbacks/kernel/src/memory/mmu/mapping_record.rs @@ -0,0 +1,204 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2020-2022 Andre Richter + +//! A record of mapped pages. + +use super::{ + AccessPermissions, Address, AttributeFields, MMIODescriptor, MemAttributes, MemoryRegion, + Physical, Virtual, +}; +use crate::{bsp, common, info, synchronization, synchronization::InitStateLock}; +use alloc::{vec, vec::Vec}; + +//-------------------------------------------------------------------------------------------------- +// Private Definitions +//-------------------------------------------------------------------------------------------------- + +/// Type describing a virtual memory mapping. +#[allow(missing_docs)] +struct MappingRecordEntry { + pub users: Vec<&'static str>, + pub phys_start_addr: Address, + pub virt_start_addr: Address, + pub num_pages: usize, + pub attribute_fields: AttributeFields, +} + +struct MappingRecord { + inner: Vec, +} + +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +static KERNEL_MAPPING_RECORD: InitStateLock = + InitStateLock::new(MappingRecord::new()); + +//-------------------------------------------------------------------------------------------------- +// Private Code +//-------------------------------------------------------------------------------------------------- + +impl MappingRecordEntry { + pub fn new( + name: &'static str, + virt_region: &MemoryRegion, + phys_region: &MemoryRegion, + attr: &AttributeFields, + ) -> Self { + Self { + users: vec![name], + phys_start_addr: phys_region.start_addr(), + virt_start_addr: virt_region.start_addr(), + num_pages: phys_region.num_pages(), + attribute_fields: *attr, + } + } + + pub fn add_user(&mut self, user: &'static str) { + self.users.push(user); + } +} + +impl MappingRecord { + pub const fn new() -> Self { + Self { inner: Vec::new() } + } + + fn sort(&mut self) { + if !self.inner.is_sorted_by_key(|item| item.virt_start_addr) { + self.inner.sort_unstable_by_key(|item| item.virt_start_addr) + } + } + + fn find_duplicate( + &mut self, + phys_region: &MemoryRegion, + ) -> Option<&mut MappingRecordEntry> { + self.inner + .iter_mut() + .filter(|x| x.attribute_fields.mem_attributes == MemAttributes::Device) + .find(|x| { + if x.phys_start_addr != phys_region.start_addr() { + return false; + } + + if x.num_pages != phys_region.num_pages() { + return false; + } + + true + }) + } + + pub fn add( + &mut self, + name: &'static str, + virt_region: &MemoryRegion, + phys_region: &MemoryRegion, + attr: &AttributeFields, + ) { + self.inner.push(MappingRecordEntry::new( + name, + virt_region, + phys_region, + attr, + )); + + self.sort(); + } + + pub fn print(&self) { + info!(" -------------------------------------------------------------------------------------------------------------------------------------------"); + info!( + " {:^44} {:^30} {:^7} {:^9} {:^35}", + "Virtual", "Physical", "Size", "Attr", "Entity" + ); + info!(" -------------------------------------------------------------------------------------------------------------------------------------------"); + + for i in self.inner.iter() { + let size = i.num_pages * bsp::memory::mmu::KernelGranule::SIZE; + let virt_start = i.virt_start_addr; + let virt_end_inclusive = virt_start + (size - 1); + let phys_start = i.phys_start_addr; + let phys_end_inclusive = phys_start + (size - 1); + + let (size, unit) = common::size_human_readable_ceil(size); + + let attr = match i.attribute_fields.mem_attributes { + MemAttributes::CacheableDRAM => "C", + MemAttributes::Device => "Dev", + }; + + let acc_p = match i.attribute_fields.acc_perms { + AccessPermissions::ReadOnly => "RO", + AccessPermissions::ReadWrite => "RW", + }; + + let xn = if i.attribute_fields.execute_never { + "XN" + } else { + "X" + }; + + info!( + " {}..{} --> {}..{} | {:>3} {} | {:<3} {} {:<2} | {}", + virt_start, + virt_end_inclusive, + phys_start, + phys_end_inclusive, + size, + unit, + attr, + acc_p, + xn, + i.users[0] + ); + + for k in &i.users[1..] { + info!( + " | {}", + k + ); + } + } + + info!(" -------------------------------------------------------------------------------------------------------------------------------------------"); + } +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- +use synchronization::interface::ReadWriteEx; + +/// Add an entry to the mapping info record. +pub fn kernel_add( + name: &'static str, + virt_region: &MemoryRegion, + phys_region: &MemoryRegion, + attr: &AttributeFields, +) { + KERNEL_MAPPING_RECORD.write(|mr| mr.add(name, virt_region, phys_region, attr)) +} + +pub fn kernel_find_and_insert_mmio_duplicate( + mmio_descriptor: &MMIODescriptor, + new_user: &'static str, +) -> Option> { + let phys_region: MemoryRegion = (*mmio_descriptor).into(); + + KERNEL_MAPPING_RECORD.write(|mr| { + let dup = mr.find_duplicate(&phys_region)?; + + dup.add_user(new_user); + + Some(dup.virt_start_addr) + }) +} + +/// Human-readable print of all recorded kernel mappings. +pub fn kernel_print() { + KERNEL_MAPPING_RECORD.read(|mr| mr.print()); +} diff --git a/20_timer_callbacks/kernel/src/memory/mmu/page_alloc.rs b/20_timer_callbacks/kernel/src/memory/mmu/page_alloc.rs new file mode 100644 index 00000000..347fcd34 --- /dev/null +++ b/20_timer_callbacks/kernel/src/memory/mmu/page_alloc.rs @@ -0,0 +1,70 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2021-2022 Andre Richter + +//! Page allocation. + +use super::MemoryRegion; +use crate::{ + memory::{AddressType, Virtual}, + synchronization::IRQSafeNullLock, + warn, +}; +use core::num::NonZeroUsize; + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +/// A page allocator that can be lazyily initialized. +pub struct PageAllocator { + pool: Option>, +} + +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +static KERNEL_MMIO_VA_ALLOCATOR: IRQSafeNullLock> = + IRQSafeNullLock::new(PageAllocator::new()); + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +/// Return a reference to the kernel's MMIO virtual address allocator. +pub fn kernel_mmio_va_allocator() -> &'static IRQSafeNullLock> { + &KERNEL_MMIO_VA_ALLOCATOR +} + +impl PageAllocator { + /// Create an instance. + pub const fn new() -> Self { + Self { pool: None } + } + + /// Initialize the allocator. + pub fn init(&mut self, pool: MemoryRegion) { + if self.pool.is_some() { + warn!("Already initialized"); + return; + } + + self.pool = Some(pool); + } + + /// Allocate a number of pages. + pub fn alloc( + &mut self, + num_requested_pages: NonZeroUsize, + ) -> Result, &'static str> { + if self.pool.is_none() { + return Err("Allocator not initialized"); + } + + self.pool + .as_mut() + .unwrap() + .take_first_n_pages(num_requested_pages) + } +} diff --git a/20_timer_callbacks/kernel/src/memory/mmu/translation_table.rs b/20_timer_callbacks/kernel/src/memory/mmu/translation_table.rs new file mode 100644 index 00000000..9301bb0c --- /dev/null +++ b/20_timer_callbacks/kernel/src/memory/mmu/translation_table.rs @@ -0,0 +1,137 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2021-2022 Andre Richter + +//! Translation table. + +#[cfg(target_arch = "aarch64")] +#[path = "../../_arch/aarch64/memory/mmu/translation_table.rs"] +mod arch_translation_table; + +use super::{AttributeFields, MemoryRegion}; +use crate::memory::{Address, Physical, Virtual}; + +//-------------------------------------------------------------------------------------------------- +// Architectural Public Reexports +//-------------------------------------------------------------------------------------------------- +#[cfg(target_arch = "aarch64")] +pub use arch_translation_table::FixedSizeTranslationTable; + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +/// Translation table interfaces. +pub mod interface { + use crate::memory::mmu::PageAddress; + + use super::*; + + /// Translation table operations. + pub trait TranslationTable { + /// Anything that needs to run before any of the other provided functions can be used. + /// + /// # Safety + /// + /// - Implementor must ensure that this function can run only once or is harmless if invoked + /// multiple times. + fn init(&mut self) -> Result<(), &'static str>; + + /// Map the given virtual memory region to the given physical memory region. + /// + /// # Safety + /// + /// - Using wrong attributes can cause multiple issues of different nature in the system. + /// - It is not required that the architectural implementation prevents aliasing. That is, + /// mapping to the same physical memory using multiple virtual addresses, which would + /// break Rust's ownership assumptions. This should be protected against in the kernel's + /// generic MMU code. + unsafe fn map_at( + &mut self, + virt_region: &MemoryRegion, + phys_region: &MemoryRegion, + attr: &AttributeFields, + ) -> Result<(), &'static str>; + + /// Try to translate a virtual page address to a physical page address. + /// + /// Will only succeed if there exists a valid mapping for the input page. + fn try_virt_page_addr_to_phys_page_addr( + &self, + virt_page_addr: PageAddress, + ) -> Result, &'static str>; + + /// Try to get the attributes of a page. + /// + /// Will only succeed if there exists a valid mapping for the input page. + fn try_page_attributes( + &self, + virt_page_addr: PageAddress, + ) -> Result; + + /// Try to translate a virtual address to a physical address. + /// + /// Will only succeed if there exists a valid mapping for the input address. + fn try_virt_addr_to_phys_addr( + &self, + virt_addr: Address, + ) -> Result, &'static str>; + } +} + +//-------------------------------------------------------------------------------------------------- +// Testing +//-------------------------------------------------------------------------------------------------- + +#[cfg(test)] +mod tests { + use super::*; + use crate::memory::mmu::{AccessPermissions, MemAttributes, PageAddress}; + use arch_translation_table::MinSizeTranslationTable; + use interface::TranslationTable; + use test_macros::kernel_test; + + /// Sanity checks for the TranslationTable implementation. + #[kernel_test] + fn translationtable_implementation_sanity() { + // This will occupy a lot of space on the stack. + let mut tables = MinSizeTranslationTable::new_for_runtime(); + + assert_eq!(tables.init(), Ok(())); + + let virt_end_exclusive_page_addr: PageAddress = PageAddress::MAX; + let virt_start_page_addr: PageAddress = + virt_end_exclusive_page_addr.checked_offset(-5).unwrap(); + + let phys_start_page_addr: PageAddress = PageAddress::from(0); + let phys_end_exclusive_page_addr: PageAddress = + phys_start_page_addr.checked_offset(5).unwrap(); + + let virt_region = MemoryRegion::new(virt_start_page_addr, virt_end_exclusive_page_addr); + let phys_region = MemoryRegion::new(phys_start_page_addr, phys_end_exclusive_page_addr); + + let attr = AttributeFields { + mem_attributes: MemAttributes::CacheableDRAM, + acc_perms: AccessPermissions::ReadWrite, + execute_never: true, + }; + + unsafe { assert_eq!(tables.map_at(&virt_region, &phys_region, &attr), Ok(())) }; + + assert_eq!( + tables.try_virt_page_addr_to_phys_page_addr(virt_start_page_addr), + Ok(phys_start_page_addr) + ); + + assert_eq!( + tables.try_page_attributes(virt_start_page_addr.checked_offset(-1).unwrap()), + Err("Page marked invalid") + ); + + assert_eq!(tables.try_page_attributes(virt_start_page_addr), Ok(attr)); + + let virt_addr = virt_start_page_addr.into_inner() + 0x100; + let phys_addr = phys_start_page_addr.into_inner() + 0x100; + assert_eq!(tables.try_virt_addr_to_phys_addr(virt_addr), Ok(phys_addr)); + } +} diff --git a/20_timer_callbacks/kernel/src/memory/mmu/types.rs b/20_timer_callbacks/kernel/src/memory/mmu/types.rs new file mode 100644 index 00000000..62f3926e --- /dev/null +++ b/20_timer_callbacks/kernel/src/memory/mmu/types.rs @@ -0,0 +1,378 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2020-2022 Andre Richter + +//! Memory Management Unit types. + +use crate::{ + bsp, common, + memory::{Address, AddressType, Physical}, +}; +use core::{convert::From, iter::Step, num::NonZeroUsize, ops::Range}; + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +/// A wrapper type around [Address] that ensures page alignment. +#[derive(Copy, Clone, Debug, Eq, PartialOrd, PartialEq)] +pub struct PageAddress { + inner: Address, +} + +/// A type that describes a region of memory in quantities of pages. +#[derive(Copy, Clone, Debug, Eq, PartialOrd, PartialEq)] +pub struct MemoryRegion { + start: PageAddress, + end_exclusive: PageAddress, +} + +/// Architecture agnostic memory attributes. +#[allow(missing_docs)] +#[derive(Copy, Clone, Debug, Eq, PartialOrd, PartialEq)] +pub enum MemAttributes { + CacheableDRAM, + Device, +} + +/// Architecture agnostic access permissions. +#[allow(missing_docs)] +#[derive(Copy, Clone, Debug, Eq, PartialOrd, PartialEq)] +pub enum AccessPermissions { + ReadOnly, + ReadWrite, +} + +/// Collection of memory attributes. +#[allow(missing_docs)] +#[derive(Copy, Clone, Debug, Eq, PartialOrd, PartialEq)] +pub struct AttributeFields { + pub mem_attributes: MemAttributes, + pub acc_perms: AccessPermissions, + pub execute_never: bool, +} + +/// An MMIO descriptor for use in device drivers. +#[derive(Copy, Clone)] +pub struct MMIODescriptor { + start_addr: Address, + end_addr_exclusive: Address, +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +//------------------------------------------------------------------------------ +// PageAddress +//------------------------------------------------------------------------------ +impl PageAddress { + /// The largest value that can be represented by this type. + pub const MAX: Self = PageAddress { + inner: Address::new(usize::MAX).align_down_page(), + }; + + /// Unwraps the value. + pub fn into_inner(self) -> Address { + self.inner + } + + /// Calculates the offset from the page address. + /// + /// `count` is in units of [PageAddress]. For example, a count of 2 means `result = self + 2 * + /// page_size`. + pub fn checked_offset(self, count: isize) -> Option { + if count == 0 { + return Some(self); + } + + let delta = count + .unsigned_abs() + .checked_mul(bsp::memory::mmu::KernelGranule::SIZE)?; + let result = if count.is_positive() { + self.inner.as_usize().checked_add(delta)? + } else { + self.inner.as_usize().checked_sub(delta)? + }; + + Some(Self { + inner: Address::new(result), + }) + } +} + +impl From for PageAddress { + fn from(addr: usize) -> Self { + assert!( + common::is_aligned(addr, bsp::memory::mmu::KernelGranule::SIZE), + "Input usize not page aligned" + ); + + Self { + inner: Address::new(addr), + } + } +} + +impl From> for PageAddress { + fn from(addr: Address) -> Self { + assert!(addr.is_page_aligned(), "Input Address not page aligned"); + + Self { inner: addr } + } +} + +impl Step for PageAddress { + fn steps_between(start: &Self, end: &Self) -> Option { + if start > end { + return None; + } + + // Since start <= end, do unchecked arithmetic. + Some( + (end.inner.as_usize() - start.inner.as_usize()) + >> bsp::memory::mmu::KernelGranule::SHIFT, + ) + } + + fn forward_checked(start: Self, count: usize) -> Option { + start.checked_offset(count as isize) + } + + fn backward_checked(start: Self, count: usize) -> Option { + start.checked_offset(-(count as isize)) + } +} + +//------------------------------------------------------------------------------ +// MemoryRegion +//------------------------------------------------------------------------------ +impl MemoryRegion { + /// Create an instance. + pub fn new(start: PageAddress, end_exclusive: PageAddress) -> Self { + assert!(start <= end_exclusive); + + Self { + start, + end_exclusive, + } + } + + fn as_range(&self) -> Range> { + self.into_iter() + } + + /// Returns the start page address. + pub fn start_page_addr(&self) -> PageAddress { + self.start + } + + /// Returns the start address. + pub fn start_addr(&self) -> Address { + self.start.into_inner() + } + + /// Returns the exclusive end page address. + pub fn end_exclusive_page_addr(&self) -> PageAddress { + self.end_exclusive + } + + /// Returns the exclusive end page address. + pub fn end_inclusive_page_addr(&self) -> PageAddress { + self.end_exclusive.checked_offset(-1).unwrap() + } + + /// Checks if self contains an address. + pub fn contains(&self, addr: Address) -> bool { + let page_addr = PageAddress::from(addr.align_down_page()); + self.as_range().contains(&page_addr) + } + + /// Checks if there is an overlap with another memory region. + pub fn overlaps(&self, other_region: &Self) -> bool { + let self_range = self.as_range(); + + self_range.contains(&other_region.start_page_addr()) + || self_range.contains(&other_region.end_inclusive_page_addr()) + } + + /// Returns the number of pages contained in this region. + pub fn num_pages(&self) -> usize { + PageAddress::steps_between(&self.start, &self.end_exclusive).unwrap() + } + + /// Returns the size in bytes of this region. + pub fn size(&self) -> usize { + // Invariant: start <= end_exclusive, so do unchecked arithmetic. + let end_exclusive = self.end_exclusive.into_inner().as_usize(); + let start = self.start.into_inner().as_usize(); + + end_exclusive - start + } + + /// Splits the MemoryRegion like: + /// + /// -------------------------------------------------------------------------------- + /// | | | | | | | | | | | | | | | | | | | + /// -------------------------------------------------------------------------------- + /// ^ ^ ^ + /// | | | + /// left_start left_end_exclusive | + /// | + /// ^ | + /// | | + /// right_start right_end_exclusive + /// + /// Left region is returned to the caller. Right region is the new region for this struct. + pub fn take_first_n_pages(&mut self, num_pages: NonZeroUsize) -> Result { + let count: usize = num_pages.into(); + + let left_end_exclusive = self.start.checked_offset(count as isize); + let left_end_exclusive = match left_end_exclusive { + None => return Err("Overflow while calculating left_end_exclusive"), + Some(x) => x, + }; + + if left_end_exclusive > self.end_exclusive { + return Err("Not enough free pages"); + } + + let allocation = Self { + start: self.start, + end_exclusive: left_end_exclusive, + }; + self.start = left_end_exclusive; + + Ok(allocation) + } +} + +impl IntoIterator for MemoryRegion { + type Item = PageAddress; + type IntoIter = Range; + + fn into_iter(self) -> Self::IntoIter { + Range { + start: self.start, + end: self.end_exclusive, + } + } +} + +impl From for MemoryRegion { + fn from(desc: MMIODescriptor) -> Self { + let start = PageAddress::from(desc.start_addr.align_down_page()); + let end_exclusive = PageAddress::from(desc.end_addr_exclusive().align_up_page()); + + Self { + start, + end_exclusive, + } + } +} + +//------------------------------------------------------------------------------ +// MMIODescriptor +//------------------------------------------------------------------------------ + +impl MMIODescriptor { + /// Create an instance. + pub const fn new(start_addr: Address, size: usize) -> Self { + assert!(size > 0); + let end_addr_exclusive = Address::new(start_addr.as_usize() + size); + + Self { + start_addr, + end_addr_exclusive, + } + } + + /// Return the start address. + pub const fn start_addr(&self) -> Address { + self.start_addr + } + + /// Return the exclusive end address. + pub fn end_addr_exclusive(&self) -> Address { + self.end_addr_exclusive + } +} + +//-------------------------------------------------------------------------------------------------- +// Testing +//-------------------------------------------------------------------------------------------------- + +#[cfg(test)] +mod tests { + use super::*; + use crate::memory::Virtual; + use test_macros::kernel_test; + + /// Sanity of [PageAddress] methods. + #[kernel_test] + fn pageaddress_type_method_sanity() { + let page_addr: PageAddress = + PageAddress::from(bsp::memory::mmu::KernelGranule::SIZE * 2); + + assert_eq!( + page_addr.checked_offset(-2), + Some(PageAddress::::from(0)) + ); + + assert_eq!( + page_addr.checked_offset(2), + Some(PageAddress::::from( + bsp::memory::mmu::KernelGranule::SIZE * 4 + )) + ); + + assert_eq!( + PageAddress::::from(0).checked_offset(0), + Some(PageAddress::::from(0)) + ); + assert_eq!(PageAddress::::from(0).checked_offset(-1), None); + + let max_page_addr = Address::::new(usize::MAX).align_down_page(); + assert_eq!( + PageAddress::::from(max_page_addr).checked_offset(1), + None + ); + + let zero = PageAddress::::from(0); + let three = PageAddress::::from(bsp::memory::mmu::KernelGranule::SIZE * 3); + assert_eq!(PageAddress::steps_between(&zero, &three), Some(3)); + } + + /// Sanity of [MemoryRegion] methods. + #[kernel_test] + fn memoryregion_type_method_sanity() { + let zero = PageAddress::::from(0); + let zero_region = MemoryRegion::new(zero, zero); + assert_eq!(zero_region.num_pages(), 0); + assert_eq!(zero_region.size(), 0); + + let one = PageAddress::::from(bsp::memory::mmu::KernelGranule::SIZE); + let one_region = MemoryRegion::new(zero, one); + assert_eq!(one_region.num_pages(), 1); + assert_eq!(one_region.size(), bsp::memory::mmu::KernelGranule::SIZE); + + let three = PageAddress::::from(bsp::memory::mmu::KernelGranule::SIZE * 3); + let mut three_region = MemoryRegion::new(zero, three); + assert!(three_region.contains(zero.into_inner())); + assert!(!three_region.contains(three.into_inner())); + assert!(three_region.overlaps(&one_region)); + + let allocation = three_region + .take_first_n_pages(NonZeroUsize::new(2).unwrap()) + .unwrap(); + assert_eq!(allocation.num_pages(), 2); + assert_eq!(three_region.num_pages(), 1); + + for (i, alloc) in allocation.into_iter().enumerate() { + assert_eq!( + alloc.into_inner().as_usize(), + i * bsp::memory::mmu::KernelGranule::SIZE + ); + } + } +} diff --git a/20_timer_callbacks/kernel/src/panic_wait.rs b/20_timer_callbacks/kernel/src/panic_wait.rs new file mode 100644 index 00000000..bc95f77c --- /dev/null +++ b/20_timer_callbacks/kernel/src/panic_wait.rs @@ -0,0 +1,88 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2018-2022 Andre Richter + +//! A panic handler that infinitely waits. + +use crate::{backtrace, cpu, exception, println}; +use core::panic::PanicInfo; + +//-------------------------------------------------------------------------------------------------- +// Private Code +//-------------------------------------------------------------------------------------------------- + +/// The point of exit for `libkernel`. +/// +/// It is linked weakly, so that the integration tests can overload its standard behavior. +#[linkage = "weak"] +#[no_mangle] +fn _panic_exit() -> ! { + #[cfg(not(feature = "test_build"))] + { + cpu::wait_forever() + } + + #[cfg(feature = "test_build")] + { + cpu::qemu_exit_failure() + } +} + +/// Stop immediately if called a second time. +/// +/// # Note +/// +/// Using atomics here relieves us from needing to use `unsafe` for the static variable. +/// +/// On `AArch64`, which is the only implemented architecture at the time of writing this, +/// [`AtomicBool::load`] and [`AtomicBool::store`] are lowered to ordinary load and store +/// instructions. They are therefore safe to use even with MMU + caching deactivated. +/// +/// [`AtomicBool::load`]: core::sync::atomic::AtomicBool::load +/// [`AtomicBool::store`]: core::sync::atomic::AtomicBool::store +fn panic_prevent_reenter() { + use core::sync::atomic::{AtomicBool, Ordering}; + + #[cfg(not(target_arch = "aarch64"))] + compile_error!("Add the target_arch to above's check if the following code is safe to use"); + + static PANIC_IN_PROGRESS: AtomicBool = AtomicBool::new(false); + + if !PANIC_IN_PROGRESS.load(Ordering::Relaxed) { + PANIC_IN_PROGRESS.store(true, Ordering::Relaxed); + + return; + } + + _panic_exit() +} + +#[panic_handler] +fn panic(info: &PanicInfo) -> ! { + exception::asynchronous::local_irq_mask(); + + // Protect against panic infinite loops if any of the following code panics itself. + panic_prevent_reenter(); + + let timestamp = crate::time::time_manager().uptime(); + let (location, line, column) = match info.location() { + Some(loc) => (loc.file(), loc.line(), loc.column()), + _ => ("???", 0, 0), + }; + + println!( + "[ {:>3}.{:06}] Kernel panic!\n\n\ + Panic location:\n File '{}', line {}, column {}\n\n\ + {}\n\n\ + {}", + timestamp.as_secs(), + timestamp.subsec_micros(), + location, + line, + column, + info.message().unwrap_or(&format_args!("")), + backtrace::Backtrace + ); + + _panic_exit() +} diff --git a/20_timer_callbacks/kernel/src/print.rs b/20_timer_callbacks/kernel/src/print.rs new file mode 100644 index 00000000..8d56d2e4 --- /dev/null +++ b/20_timer_callbacks/kernel/src/print.rs @@ -0,0 +1,112 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2018-2022 Andre Richter + +//! Printing. + +use crate::console; +use core::fmt; + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +#[doc(hidden)] +pub fn _print(args: fmt::Arguments) { + console::console().write_fmt(args).unwrap(); +} + +/// Prints without a newline. +/// +/// Carbon copy from +#[macro_export] +macro_rules! print { + ($($arg:tt)*) => ($crate::print::_print(format_args!($($arg)*))); +} + +/// Prints with a newline. +/// +/// Carbon copy from +#[macro_export] +macro_rules! println { + () => ($crate::print!("\n")); + ($($arg:tt)*) => ({ + $crate::print::_print(format_args_nl!($($arg)*)); + }) +} + +/// Prints an info, with a newline. +#[macro_export] +macro_rules! info { + ($string:expr) => ({ + let timestamp = $crate::time::time_manager().uptime(); + + $crate::print::_print(format_args_nl!( + concat!("[ {:>3}.{:06}] ", $string), + timestamp.as_secs(), + timestamp.subsec_micros(), + )); + }); + ($format_string:expr, $($arg:tt)*) => ({ + let timestamp = $crate::time::time_manager().uptime(); + + $crate::print::_print(format_args_nl!( + concat!("[ {:>3}.{:06}] ", $format_string), + timestamp.as_secs(), + timestamp.subsec_micros(), + $($arg)* + )); + }) +} + +/// Prints a warning, with a newline. +#[macro_export] +macro_rules! warn { + ($string:expr) => ({ + let timestamp = $crate::time::time_manager().uptime(); + + $crate::print::_print(format_args_nl!( + concat!("[W {:>3}.{:06}] ", $string), + timestamp.as_secs(), + timestamp.subsec_micros(), + )); + }); + ($format_string:expr, $($arg:tt)*) => ({ + let timestamp = $crate::time::time_manager().uptime(); + + $crate::print::_print(format_args_nl!( + concat!("[W {:>3}.{:06}] ", $format_string), + timestamp.as_secs(), + timestamp.subsec_micros(), + $($arg)* + )); + }) +} + +/// Debug print, with a newline. +#[macro_export] +macro_rules! debug { + ($string:expr) => ({ + if cfg!(feature = "debug_prints") { + let timestamp = $crate::time::time_manager().uptime(); + + $crate::print::_print(format_args_nl!( + concat!("<[>D {:>3}.{:06}> ", $string), + timestamp.as_secs(), + timestamp.subsec_micros(), + )); + } + }); + ($format_string:expr, $($arg:tt)*) => ({ + if cfg!(feature = "debug_prints") { + let timestamp = $crate::time::time_manager().uptime(); + + $crate::print::_print(format_args_nl!( + concat!("3}.{:06}> ", $format_string), + timestamp.as_secs(), + timestamp.subsec_micros(), + $($arg)* + )); + } + }) +} diff --git a/20_timer_callbacks/kernel/src/state.rs b/20_timer_callbacks/kernel/src/state.rs new file mode 100644 index 00000000..0af3688c --- /dev/null +++ b/20_timer_callbacks/kernel/src/state.rs @@ -0,0 +1,92 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2020-2022 Andre Richter + +//! State information about the kernel itself. + +use core::sync::atomic::{AtomicU8, Ordering}; + +//-------------------------------------------------------------------------------------------------- +// Private Definitions +//-------------------------------------------------------------------------------------------------- + +/// Different stages in the kernel execution. +#[derive(Copy, Clone, Eq, PartialEq)] +enum State { + /// The kernel starts booting in this state. + Init, + + /// The kernel transitions to this state when jumping to `kernel_main()` (at the end of + /// `kernel_init()`, after all init calls are done). + SingleCoreMain, + + /// The kernel transitions to this state when it boots the secondary cores, aka switches + /// exectution mode to symmetric multiprocessing (SMP). + MultiCoreMain, +} + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +/// Maintains the kernel state and state transitions. +pub struct StateManager(AtomicU8); + +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +static STATE_MANAGER: StateManager = StateManager::new(); + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +/// Return a reference to the global StateManager. +pub fn state_manager() -> &'static StateManager { + &STATE_MANAGER +} + +impl StateManager { + const INIT: u8 = 0; + const SINGLE_CORE_MAIN: u8 = 1; + const MULTI_CORE_MAIN: u8 = 2; + + /// Create a new instance. + pub const fn new() -> Self { + Self(AtomicU8::new(Self::INIT)) + } + + /// Return the current state. + fn state(&self) -> State { + let state = self.0.load(Ordering::Acquire); + + match state { + Self::INIT => State::Init, + Self::SINGLE_CORE_MAIN => State::SingleCoreMain, + Self::MULTI_CORE_MAIN => State::MultiCoreMain, + _ => panic!("Invalid KERNEL_STATE"), + } + } + + /// Return if the kernel is init state. + pub fn is_init(&self) -> bool { + self.state() == State::Init + } + + /// Transition from Init to SingleCoreMain. + pub fn transition_to_single_core_main(&self) { + if self + .0 + .compare_exchange( + Self::INIT, + Self::SINGLE_CORE_MAIN, + Ordering::Acquire, + Ordering::Relaxed, + ) + .is_err() + { + panic!("transition_to_single_core_main() called while state != Init"); + } + } +} diff --git a/20_timer_callbacks/kernel/src/symbols.rs b/20_timer_callbacks/kernel/src/symbols.rs new file mode 100644 index 00000000..680b8eaf --- /dev/null +++ b/20_timer_callbacks/kernel/src/symbols.rs @@ -0,0 +1,88 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2022 Andre Richter + +//! Debug symbol support. + +use crate::memory::{Address, Virtual}; +use core::{cell::UnsafeCell, slice}; +use debug_symbol_types::Symbol; + +//-------------------------------------------------------------------------------------------------- +// Private Definitions +//-------------------------------------------------------------------------------------------------- + +// Symbol from the linker script. +extern "Rust" { + static __kernel_symbols_start: UnsafeCell<()>; +} + +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +/// This will be patched to the correct value by the "kernel symbols tool" after linking. This given +/// value here is just a (safe) dummy. +#[no_mangle] +static NUM_KERNEL_SYMBOLS: u64 = 0; + +//-------------------------------------------------------------------------------------------------- +// Private Code +//-------------------------------------------------------------------------------------------------- + +fn kernel_symbol_section_virt_start_addr() -> Address { + Address::new(unsafe { __kernel_symbols_start.get() as usize }) +} + +fn num_kernel_symbols() -> usize { + unsafe { + // Read volatile is needed here to prevent the compiler from optimizing NUM_KERNEL_SYMBOLS + // away. + core::ptr::read_volatile(&NUM_KERNEL_SYMBOLS as *const u64) as usize + } +} + +fn kernel_symbols_slice() -> &'static [Symbol] { + let ptr = kernel_symbol_section_virt_start_addr().as_usize() as *const Symbol; + + unsafe { slice::from_raw_parts(ptr, num_kernel_symbols()) } +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +/// Retrieve the symbol corresponding to a virtual address, if any. +pub fn lookup_symbol(addr: Address) -> Option<&'static Symbol> { + kernel_symbols_slice() + .iter() + .find(|&i| i.contains(addr.as_usize())) +} + +//-------------------------------------------------------------------------------------------------- +// Testing +//-------------------------------------------------------------------------------------------------- + +#[cfg(test)] +mod tests { + use super::*; + use test_macros::kernel_test; + + /// Sanity of symbols module. + #[kernel_test] + fn symbols_sanity() { + let first_sym = lookup_symbol(Address::new( + crate::common::is_aligned as *const usize as usize, + )) + .unwrap() + .name(); + + assert_eq!(first_sym, "libkernel::common::is_aligned"); + + let second_sym = lookup_symbol(Address::new(crate::version as *const usize as usize)) + .unwrap() + .name(); + + assert_eq!(second_sym, "libkernel::version"); + } +} diff --git a/20_timer_callbacks/kernel/src/synchronization.rs b/20_timer_callbacks/kernel/src/synchronization.rs new file mode 100644 index 00000000..ab2b86e6 --- /dev/null +++ b/20_timer_callbacks/kernel/src/synchronization.rs @@ -0,0 +1,159 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2020-2022 Andre Richter + +//! Synchronization primitives. +//! +//! # Resources +//! +//! - +//! - +//! - + +use core::cell::UnsafeCell; + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +/// Synchronization interfaces. +pub mod interface { + + /// Any object implementing this trait guarantees exclusive access to the data wrapped within + /// the Mutex for the duration of the provided closure. + pub trait Mutex { + /// The type of the data that is wrapped by this mutex. + type Data; + + /// Locks the mutex and grants the closure temporary mutable access to the wrapped data. + fn lock<'a, R>(&'a self, f: impl FnOnce(&'a mut Self::Data) -> R) -> R; + } + + /// A reader-writer exclusion type. + /// + /// The implementing object allows either a number of readers or at most one writer at any point + /// in time. + pub trait ReadWriteEx { + /// The type of encapsulated data. + type Data; + + /// Grants temporary mutable access to the encapsulated data. + fn write<'a, R>(&'a self, f: impl FnOnce(&'a mut Self::Data) -> R) -> R; + + /// Grants temporary immutable access to the encapsulated data. + fn read<'a, R>(&'a self, f: impl FnOnce(&'a Self::Data) -> R) -> R; + } +} + +/// A pseudo-lock for teaching purposes. +/// +/// In contrast to a real Mutex implementation, does not protect against concurrent access from +/// other cores to the contained data. This part is preserved for later lessons. +/// +/// The lock will only be used as long as it is safe to do so, i.e. as long as the kernel is +/// executing on a single core. +pub struct IRQSafeNullLock +where + T: ?Sized, +{ + data: UnsafeCell, +} + +/// A pseudo-lock that is RW during the single-core kernel init phase and RO afterwards. +/// +/// Intended to encapsulate data that is populated during kernel init when no concurrency exists. +pub struct InitStateLock +where + T: ?Sized, +{ + data: UnsafeCell, +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +unsafe impl Send for IRQSafeNullLock where T: ?Sized + Send {} +unsafe impl Sync for IRQSafeNullLock where T: ?Sized + Send {} + +impl IRQSafeNullLock { + /// Create an instance. + pub const fn new(data: T) -> Self { + Self { + data: UnsafeCell::new(data), + } + } +} + +unsafe impl Send for InitStateLock where T: ?Sized + Send {} +unsafe impl Sync for InitStateLock where T: ?Sized + Send {} + +impl InitStateLock { + /// Create an instance. + pub const fn new(data: T) -> Self { + Self { + data: UnsafeCell::new(data), + } + } +} + +//------------------------------------------------------------------------------ +// OS Interface Code +//------------------------------------------------------------------------------ +use crate::{exception, state}; + +impl interface::Mutex for IRQSafeNullLock { + type Data = T; + + fn lock<'a, R>(&'a self, f: impl FnOnce(&'a mut Self::Data) -> R) -> R { + // In a real lock, there would be code encapsulating this line that ensures that this + // mutable reference will ever only be given out once at a time. + let data = unsafe { &mut *self.data.get() }; + + // Execute the closure while IRQs are masked. + exception::asynchronous::exec_with_irq_masked(|| f(data)) + } +} + +impl interface::ReadWriteEx for InitStateLock { + type Data = T; + + fn write<'a, R>(&'a self, f: impl FnOnce(&'a mut Self::Data) -> R) -> R { + assert!( + state::state_manager().is_init(), + "InitStateLock::write called after kernel init phase" + ); + assert!( + !exception::asynchronous::is_local_irq_masked(), + "InitStateLock::write called with IRQs unmasked" + ); + + let data = unsafe { &mut *self.data.get() }; + + f(data) + } + + fn read<'a, R>(&'a self, f: impl FnOnce(&'a Self::Data) -> R) -> R { + let data = unsafe { &*self.data.get() }; + + f(data) + } +} + +//-------------------------------------------------------------------------------------------------- +// Testing +//-------------------------------------------------------------------------------------------------- + +#[cfg(test)] +mod tests { + use super::*; + use test_macros::kernel_test; + + /// InitStateLock must be transparent. + #[kernel_test] + fn init_state_lock_is_transparent() { + use core::mem::size_of; + + assert_eq!(size_of::>(), size_of::()); + } +} diff --git a/20_timer_callbacks/kernel/src/time.rs b/20_timer_callbacks/kernel/src/time.rs new file mode 100644 index 00000000..80194182 --- /dev/null +++ b/20_timer_callbacks/kernel/src/time.rs @@ -0,0 +1,263 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2020-2022 Andre Richter + +//! Timer primitives. +//! +//! # Resources +//! +//! - +//! - + +#[cfg(target_arch = "aarch64")] +#[path = "_arch/aarch64/time.rs"] +mod arch_time; + +use crate::{ + driver, exception, + exception::asynchronous::IRQNumber, + synchronization::{interface::Mutex, IRQSafeNullLock}, + warn, +}; +use alloc::{boxed::Box, vec::Vec}; +use core::{ + sync::atomic::{AtomicBool, Ordering}, + time::Duration, +}; + +//-------------------------------------------------------------------------------------------------- +// Private Definitions +//-------------------------------------------------------------------------------------------------- + +struct Timeout { + due_time: Duration, + period: Option, + callback: TimeoutCallback, +} + +struct OrderedTimeoutQueue { + // Can be replaced with a BinaryHeap once it's new() becomes const. + inner: Vec, +} + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +/// The callback type used by timer IRQs. +pub type TimeoutCallback = Box; + +/// Provides time management functions. +pub struct TimeManager { + queue: IRQSafeNullLock, +} + +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +static TIME_MANAGER: TimeManager = TimeManager::new(); + +//-------------------------------------------------------------------------------------------------- +// Private Code +//-------------------------------------------------------------------------------------------------- + +impl Timeout { + pub fn is_periodic(&self) -> bool { + self.period.is_some() + } + + pub fn refresh(&mut self) { + if let Some(delay) = self.period { + self.due_time += delay; + } + } +} + +impl OrderedTimeoutQueue { + pub const fn new() -> Self { + Self { inner: Vec::new() } + } + + pub fn push(&mut self, timeout: Timeout) { + self.inner.push(timeout); + + // Note reverse compare order so that earliest expiring item is at end of vec. We do this so + // that we can use Vec::pop below to retrieve the item that is next due. + self.inner.sort_by(|a, b| b.due_time.cmp(&a.due_time)); + } + + pub fn peek_next_due_time(&self) -> Option { + let timeout = self.inner.last()?; + + Some(timeout.due_time) + } + + pub fn pop(&mut self) -> Option { + self.inner.pop() + } +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +/// Return a reference to the global TimeManager. +pub fn time_manager() -> &'static TimeManager { + &TIME_MANAGER +} + +impl TimeManager { + /// Compatibility string. + pub const COMPATIBLE: &'static str = "ARM Architectural Timer"; + + /// Create an instance. + pub const fn new() -> Self { + Self { + queue: IRQSafeNullLock::new(OrderedTimeoutQueue::new()), + } + } + + /// The timer's resolution. + pub fn resolution(&self) -> Duration { + arch_time::resolution() + } + + /// The uptime since power-on of the device. + /// + /// This includes time consumed by firmware and bootloaders. + pub fn uptime(&self) -> Duration { + arch_time::uptime() + } + + /// Spin for a given duration. + pub fn spin_for(&self, duration: Duration) { + arch_time::spin_for(duration) + } + + /// Set a timeout. + fn set_timeout(&self, timeout: Timeout) { + self.queue.lock(|queue| { + queue.push(timeout); + + arch_time::set_timeout_irq(queue.peek_next_due_time().unwrap()); + }); + } + + /// Set a one-shot timeout. + pub fn set_timeout_once(&self, delay: Duration, callback: TimeoutCallback) { + let timeout = Timeout { + due_time: self.uptime() + delay, + period: None, + callback, + }; + + self.set_timeout(timeout); + } + + /// Set a periodic timeout. + pub fn set_timeout_periodic(&self, delay: Duration, callback: TimeoutCallback) { + let timeout = Timeout { + due_time: self.uptime() + delay, + period: Some(delay), + callback, + }; + + self.set_timeout(timeout); + } +} + +/// Initialize the timer subsystem. +pub fn init() -> Result<(), &'static str> { + static INIT_DONE: AtomicBool = AtomicBool::new(false); + if INIT_DONE.load(Ordering::Relaxed) { + return Err("Init already done"); + } + + let timer_descriptor = + driver::DeviceDriverDescriptor::new(time_manager(), None, Some(arch_time::timeout_irq())); + driver::driver_manager().register_driver(timer_descriptor); + + INIT_DONE.store(true, Ordering::Relaxed); + Ok(()) +} + +//------------------------------------------------------------------------------ +// OS Interface Code +//------------------------------------------------------------------------------ + +impl driver::interface::DeviceDriver for TimeManager { + type IRQNumberType = IRQNumber; + + fn compatible(&self) -> &'static str { + Self::COMPATIBLE + } + + fn register_and_enable_irq_handler( + &'static self, + irq_number: &Self::IRQNumberType, + ) -> Result<(), &'static str> { + use exception::asynchronous::{irq_manager, IRQHandlerDescriptor}; + + let descriptor = IRQHandlerDescriptor::new(*irq_number, Self::COMPATIBLE, self); + + irq_manager().register_handler(descriptor)?; + irq_manager().enable(irq_number); + + Ok(()) + } +} + +impl exception::asynchronous::interface::IRQHandler for TimeManager { + fn handle(&self) -> Result<(), &'static str> { + arch_time::conclude_timeout_irq(); + + let maybe_timeout: Option = self.queue.lock(|queue| { + let next_due_time = queue.peek_next_due_time()?; + if next_due_time > self.uptime() { + return None; + } + + let mut timeout = queue.pop().unwrap(); + + // Refresh as early as possible to prevent drift. + if timeout.is_periodic() { + timeout.refresh(); + } + + Some(timeout) + }); + + let timeout = match maybe_timeout { + None => { + warn!("Spurious timeout IRQ"); + return Ok(()); + } + Some(t) => t, + }; + + // Important: Call the callback while not holding any lock, because the callback might + // attempt to modify data that is protected by a lock (in particular, the timeout queue + // itself). + (timeout.callback)(); + + self.queue.lock(|queue| { + if timeout.is_periodic() { + // There might be some overhead involved in the periodic path, because the timeout + // item is first popped from the underlying Vec and then pushed back again. It could + // be faster to keep the item in the queue and find a way to work with a reference + // to it. + // + // We are not going this route on purpose, though. It allows to keep the code simple + // and the focus on the high-level concepts. + queue.push(timeout); + }; + + if let Some(due_time) = queue.peek_next_due_time() { + arch_time::set_timeout_irq(due_time); + } + }); + + Ok(()) + } +} diff --git a/20_timer_callbacks/kernel/tests/00_console_sanity.rb b/20_timer_callbacks/kernel/tests/00_console_sanity.rb new file mode 100644 index 00000000..4dde5576 --- /dev/null +++ b/20_timer_callbacks/kernel/tests/00_console_sanity.rb @@ -0,0 +1,48 @@ +# frozen_string_literal: true + +# SPDX-License-Identifier: MIT OR Apache-2.0 +# +# Copyright (c) 2019-2022 Andre Richter + +require 'console_io_test' + +# Verify sending and receiving works as expected. +class TxRxHandshakeTest < SubtestBase + def name + 'Transmit and Receive handshake' + end + + def run(qemu_out, qemu_in) + qemu_in.write_nonblock('ABC') + expect_or_raise(qemu_out, 'OK1234') + end +end + +# Check for correct TX statistics implementation. Depends on test 1 being run first. +class TxStatisticsTest < SubtestBase + def name + 'Transmit statistics' + end + + def run(qemu_out, _qemu_in) + expect_or_raise(qemu_out, '6') + end +end + +# Check for correct RX statistics implementation. Depends on test 1 being run first. +class RxStatisticsTest < SubtestBase + def name + 'Receive statistics' + end + + def run(qemu_out, _qemu_in) + expect_or_raise(qemu_out, '3') + end +end + +##-------------------------------------------------------------------------------------------------- +## Test registration +##-------------------------------------------------------------------------------------------------- +def subtest_collection + [TxRxHandshakeTest.new, TxStatisticsTest.new, RxStatisticsTest.new] +end diff --git a/20_timer_callbacks/kernel/tests/00_console_sanity.rs b/20_timer_callbacks/kernel/tests/00_console_sanity.rs new file mode 100644 index 00000000..2c0225b7 --- /dev/null +++ b/20_timer_callbacks/kernel/tests/00_console_sanity.rs @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2019-2022 Andre Richter + +//! Console sanity tests - RX, TX and statistics. + +#![feature(format_args_nl)] +#![no_main] +#![no_std] + +/// Console tests should time out on the I/O harness in case of panic. +mod panic_wait_forever; + +use libkernel::{bsp, console, cpu, exception, memory, print}; + +#[no_mangle] +unsafe fn kernel_init() -> ! { + use console::console; + + exception::handling_init(); + memory::init(); + bsp::driver::qemu_bring_up_console(); + + // Handshake + assert_eq!(console().read_char(), 'A'); + assert_eq!(console().read_char(), 'B'); + assert_eq!(console().read_char(), 'C'); + print!("OK1234"); + + // 6 + print!("{}", console().chars_written()); + + // 3 + print!("{}", console().chars_read()); + + // The QEMU process running this test will be closed by the I/O test harness. + cpu::wait_forever(); +} diff --git a/20_timer_callbacks/kernel/tests/01_timer_sanity.rs b/20_timer_callbacks/kernel/tests/01_timer_sanity.rs new file mode 100644 index 00000000..8188b942 --- /dev/null +++ b/20_timer_callbacks/kernel/tests/01_timer_sanity.rs @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2019-2022 Andre Richter + +//! Timer sanity tests. + +#![feature(custom_test_frameworks)] +#![no_main] +#![no_std] +#![reexport_test_harness_main = "test_main"] +#![test_runner(libkernel::test_runner)] + +use core::time::Duration; +use libkernel::{bsp, cpu, exception, memory, time}; +use test_macros::kernel_test; + +#[no_mangle] +unsafe fn kernel_init() -> ! { + exception::handling_init(); + memory::init(); + bsp::driver::qemu_bring_up_console(); + + // Depending on CPU arch, some timer bring-up code could go here. Not needed for the RPi. + + test_main(); + + cpu::qemu_exit_success() +} + +/// Simple check that the timer is running. +#[kernel_test] +fn timer_is_counting() { + assert!(time::time_manager().uptime().as_nanos() > 0) +} + +/// Timer resolution must be sufficient. +#[kernel_test] +fn timer_resolution_is_sufficient() { + assert!(time::time_manager().resolution().as_nanos() > 0); + assert!(time::time_manager().resolution().as_nanos() < 100) +} + +/// Sanity check spin_for() implementation. +#[kernel_test] +fn spin_accuracy_check_1_second() { + let t1 = time::time_manager().uptime(); + time::time_manager().spin_for(Duration::from_secs(1)); + let t2 = time::time_manager().uptime(); + + assert_eq!((t2 - t1).as_secs(), 1) +} diff --git a/20_timer_callbacks/kernel/tests/02_exception_sync_page_fault.rs b/20_timer_callbacks/kernel/tests/02_exception_sync_page_fault.rs new file mode 100644 index 00000000..fab44c8f --- /dev/null +++ b/20_timer_callbacks/kernel/tests/02_exception_sync_page_fault.rs @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2019-2022 Andre Richter + +//! Page faults must result in synchronous exceptions. + +#![feature(format_args_nl)] +#![no_main] +#![no_std] + +/// Overwrites libkernel's `panic_wait::_panic_exit()` so that it returns a "success" code. +/// +/// In this test, reaching the panic is a success, because it is called from the synchronous +/// exception handler, which is what this test wants to achieve. +/// +/// It also means that this integration test can not use any other code that calls panic!() directly +/// or indirectly. +mod panic_exit_success; + +use libkernel::{bsp, cpu, exception, info, memory, println}; + +#[no_mangle] +unsafe fn kernel_init() -> ! { + exception::handling_init(); + memory::init(); + bsp::driver::qemu_bring_up_console(); + + // This line will be printed as the test header. + println!("Testing synchronous exception handling by causing a page fault"); + + info!("Writing to bottom of address space to address 1 GiB..."); + let big_addr: u64 = 1024 * 1024 * 1024; + core::ptr::read_volatile(big_addr as *mut u64); + + // If execution reaches here, the memory access above did not cause a page fault exception. + cpu::qemu_exit_failure() +} diff --git a/20_timer_callbacks/kernel/tests/03_exception_restore_sanity.rb b/20_timer_callbacks/kernel/tests/03_exception_restore_sanity.rb new file mode 100644 index 00000000..5f52e0c7 --- /dev/null +++ b/20_timer_callbacks/kernel/tests/03_exception_restore_sanity.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +# SPDX-License-Identifier: MIT OR Apache-2.0 +# +# Copyright (c) 2022 Andre Richter + +require 'console_io_test' + +# Verify that exception restore works. +class ExceptionRestoreTest < SubtestBase + def name + 'Exception restore' + end + + def run(qemu_out, _qemu_in) + expect_or_raise(qemu_out, 'Back from system call!') + end +end + +##-------------------------------------------------------------------------------------------------- +## Test registration +##-------------------------------------------------------------------------------------------------- +def subtest_collection + [ExceptionRestoreTest.new] +end diff --git a/20_timer_callbacks/kernel/tests/03_exception_restore_sanity.rs b/20_timer_callbacks/kernel/tests/03_exception_restore_sanity.rs new file mode 100644 index 00000000..f176c6a6 --- /dev/null +++ b/20_timer_callbacks/kernel/tests/03_exception_restore_sanity.rs @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2022 Andre Richter + +//! A simple sanity test to see if exception restore code works. + +#![feature(format_args_nl)] +#![no_main] +#![no_std] + +/// Console tests should time out on the I/O harness in case of panic. +mod panic_wait_forever; + +use core::arch::asm; +use libkernel::{bsp, cpu, exception, info, memory, println}; + +#[inline(never)] +fn nested_system_call() { + #[cfg(target_arch = "aarch64")] + unsafe { + asm!("svc #0x1337", options(nomem, nostack, preserves_flags)); + } + + #[cfg(not(target_arch = "aarch64"))] + { + info!("Not supported yet"); + cpu::wait_forever(); + } +} + +#[no_mangle] +unsafe fn kernel_init() -> ! { + exception::handling_init(); + memory::init(); + bsp::driver::qemu_bring_up_console(); + + // This line will be printed as the test header. + println!("Testing exception restore"); + + info!("Making a dummy system call"); + + // Calling this inside a function indirectly tests if the link register is restored properly. + nested_system_call(); + + info!("Back from system call!"); + + // The QEMU process running this test will be closed by the I/O test harness. + cpu::wait_forever(); +} diff --git a/20_timer_callbacks/kernel/tests/04_exception_irq_sanity.rs b/20_timer_callbacks/kernel/tests/04_exception_irq_sanity.rs new file mode 100644 index 00000000..e6f94c91 --- /dev/null +++ b/20_timer_callbacks/kernel/tests/04_exception_irq_sanity.rs @@ -0,0 +1,67 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2020-2022 Andre Richter + +//! IRQ handling sanity tests. + +#![feature(custom_test_frameworks)] +#![no_main] +#![no_std] +#![reexport_test_harness_main = "test_main"] +#![test_runner(libkernel::test_runner)] + +use libkernel::{bsp, cpu, exception, memory}; +use test_macros::kernel_test; + +#[no_mangle] +unsafe fn kernel_init() -> ! { + memory::init(); + bsp::driver::qemu_bring_up_console(); + + exception::handling_init(); + exception::asynchronous::local_irq_unmask(); + + test_main(); + + cpu::qemu_exit_success() +} + +/// Check that IRQ masking works. +#[kernel_test] +fn local_irq_mask_works() { + // Precondition: IRQs are unmasked. + assert!(exception::asynchronous::is_local_irq_masked()); + + exception::asynchronous::local_irq_mask(); + assert!(!exception::asynchronous::is_local_irq_masked()); + + // Restore earlier state. + exception::asynchronous::local_irq_unmask(); +} + +/// Check that IRQ unmasking works. +#[kernel_test] +fn local_irq_unmask_works() { + // Precondition: IRQs are masked. + exception::asynchronous::local_irq_mask(); + assert!(!exception::asynchronous::is_local_irq_masked()); + + exception::asynchronous::local_irq_unmask(); + assert!(exception::asynchronous::is_local_irq_masked()); +} + +/// Check that IRQ mask save is saving "something". +#[kernel_test] +fn local_irq_mask_save_works() { + // Precondition: IRQs are unmasked. + assert!(exception::asynchronous::is_local_irq_masked()); + + let first = exception::asynchronous::local_irq_mask_save(); + assert!(!exception::asynchronous::is_local_irq_masked()); + + let second = exception::asynchronous::local_irq_mask_save(); + assert_ne!(first, second); + + exception::asynchronous::local_irq_restore(first); + assert!(exception::asynchronous::is_local_irq_masked()); +} diff --git a/20_timer_callbacks/kernel/tests/05_backtrace_sanity.rb b/20_timer_callbacks/kernel/tests/05_backtrace_sanity.rb new file mode 100644 index 00000000..5650f97c --- /dev/null +++ b/20_timer_callbacks/kernel/tests/05_backtrace_sanity.rb @@ -0,0 +1,39 @@ +# frozen_string_literal: true + +# SPDX-License-Identifier: MIT OR Apache-2.0 +# +# Copyright (c) 2022 Andre Richter + +require 'console_io_test' + +# Verify that panic produces a backtrace. +class PanicBacktraceTest < SubtestBase + def name + 'Panic produces backtrace' + end + + def run(qemu_out, _qemu_in) + expect_or_raise(qemu_out, 'Kernel panic!') + expect_or_raise(qemu_out, 'Backtrace:') + end +end + +# Verify backtrace correctness. +class BacktraceCorrectnessTest < SubtestBase + def name + 'Backtrace is correct' + end + + def run(qemu_out, _qemu_in) + expect_or_raise(qemu_out, '| core::panicking::panic') + expect_or_raise(qemu_out, '| _05_backtrace_sanity::nested') + expect_or_raise(qemu_out, '| kernel_init') + end +end + +##-------------------------------------------------------------------------------------------------- +## Test registration +##-------------------------------------------------------------------------------------------------- +def subtest_collection + [PanicBacktraceTest.new, BacktraceCorrectnessTest.new] +end diff --git a/20_timer_callbacks/kernel/tests/05_backtrace_sanity.rs b/20_timer_callbacks/kernel/tests/05_backtrace_sanity.rs new file mode 100644 index 00000000..f75c0ea3 --- /dev/null +++ b/20_timer_callbacks/kernel/tests/05_backtrace_sanity.rs @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2022 Andre Richter + +//! Test if backtracing code detects an invalid frame pointer. + +#![feature(format_args_nl)] +#![no_main] +#![no_std] + +/// Console tests should time out on the I/O harness in case of panic. +mod panic_wait_forever; + +use libkernel::{bsp, cpu, exception, memory}; + +#[inline(never)] +fn nested() { + panic!() +} + +#[no_mangle] +unsafe fn kernel_init() -> ! { + exception::handling_init(); + memory::init(); + bsp::driver::qemu_bring_up_console(); + + nested(); + + // The QEMU process running this test will be closed by the I/O test harness. + cpu::wait_forever() +} diff --git a/20_timer_callbacks/kernel/tests/06_backtrace_invalid_frame.rb b/20_timer_callbacks/kernel/tests/06_backtrace_invalid_frame.rb new file mode 100644 index 00000000..7601cf97 --- /dev/null +++ b/20_timer_callbacks/kernel/tests/06_backtrace_invalid_frame.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +# SPDX-License-Identifier: MIT OR Apache-2.0 +# +# Copyright (c) 2022 Andre Richter + +require 'console_io_test' + +# Test detection of invalid frame pointers. +class InvalidFramePointerTest < SubtestBase + def name + 'Detect invalid frame pointer' + end + + def run(qemu_out, _qemu_in) + expect_or_raise(qemu_out, + /Encountered invalid frame pointer \(.*\) during backtrace/) + end +end + +##-------------------------------------------------------------------------------------------------- +## Test registration +##-------------------------------------------------------------------------------------------------- +def subtest_collection + [InvalidFramePointerTest.new] +end diff --git a/20_timer_callbacks/kernel/tests/06_backtrace_invalid_frame.rs b/20_timer_callbacks/kernel/tests/06_backtrace_invalid_frame.rs new file mode 100644 index 00000000..33d3c02d --- /dev/null +++ b/20_timer_callbacks/kernel/tests/06_backtrace_invalid_frame.rs @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2022 Andre Richter + +//! Test if backtracing code detects an invalid frame pointer. + +#![feature(format_args_nl)] +#![no_main] +#![no_std] + +/// Console tests should time out on the I/O harness in case of panic. +mod panic_wait_forever; + +use libkernel::{backtrace, bsp, cpu, exception, memory}; + +#[inline(never)] +fn nested() { + unsafe { backtrace::corrupt_previous_frame_addr() }; + + panic!() +} + +#[no_mangle] +unsafe fn kernel_init() -> ! { + exception::handling_init(); + memory::init(); + bsp::driver::qemu_bring_up_console(); + + nested(); + + // The QEMU process running this test will be closed by the I/O test harness. + cpu::wait_forever() +} diff --git a/20_timer_callbacks/kernel/tests/07_backtrace_invalid_link.rb b/20_timer_callbacks/kernel/tests/07_backtrace_invalid_link.rb new file mode 100644 index 00000000..0fabcf4c --- /dev/null +++ b/20_timer_callbacks/kernel/tests/07_backtrace_invalid_link.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +# SPDX-License-Identifier: MIT OR Apache-2.0 +# +# Copyright (c) 2022 Andre Richter + +require 'console_io_test' + +# Test detection of invalid link. +class InvalidLinkTest < SubtestBase + def name + 'Detect invalid link' + end + + def run(qemu_out, _qemu_in) + expect_or_raise(qemu_out, /Link address \(.*\) is not contained in kernel .text section/) + end +end + +##-------------------------------------------------------------------------------------------------- +## Test registration +##-------------------------------------------------------------------------------------------------- +def subtest_collection + [InvalidLinkTest.new] +end diff --git a/20_timer_callbacks/kernel/tests/07_backtrace_invalid_link.rs b/20_timer_callbacks/kernel/tests/07_backtrace_invalid_link.rs new file mode 100644 index 00000000..bcb0538a --- /dev/null +++ b/20_timer_callbacks/kernel/tests/07_backtrace_invalid_link.rs @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2022 Andre Richter + +//! Test if backtracing code detects an invalid link. + +#![feature(format_args_nl)] +#![no_main] +#![no_std] + +/// Console tests should time out on the I/O harness in case of panic. +mod panic_wait_forever; + +use libkernel::{backtrace, bsp, cpu, exception, memory}; + +#[inline(never)] +fn nested_2() -> &'static str { + unsafe { backtrace::corrupt_link() }; + libkernel::println!("{}", libkernel::backtrace::Backtrace); + "foo" +} + +#[inline(never)] +fn nested_1() { + libkernel::println!("{}", nested_2()) +} + +#[no_mangle] +unsafe fn kernel_init() -> ! { + exception::handling_init(); + memory::init(); + bsp::driver::qemu_bring_up_console(); + + nested_1(); + + // The QEMU process running this test will be closed by the I/O test harness. + cpu::wait_forever() +} diff --git a/20_timer_callbacks/kernel/tests/boot_test_string.rb b/20_timer_callbacks/kernel/tests/boot_test_string.rb new file mode 100644 index 00000000..d65f1a92 --- /dev/null +++ b/20_timer_callbacks/kernel/tests/boot_test_string.rb @@ -0,0 +1,3 @@ +# frozen_string_literal: true + +EXPECTED_PRINT = 'Once 5' diff --git a/20_timer_callbacks/kernel/tests/panic_exit_success/mod.rs b/20_timer_callbacks/kernel/tests/panic_exit_success/mod.rs new file mode 100644 index 00000000..908fac51 --- /dev/null +++ b/20_timer_callbacks/kernel/tests/panic_exit_success/mod.rs @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2019-2022 Andre Richter + +/// Overwrites libkernel's `panic_wait::_panic_exit()` with the QEMU-exit version. +#[no_mangle] +fn _panic_exit() -> ! { + libkernel::cpu::qemu_exit_success() +} diff --git a/20_timer_callbacks/kernel/tests/panic_wait_forever/mod.rs b/20_timer_callbacks/kernel/tests/panic_wait_forever/mod.rs new file mode 100644 index 00000000..7a4effa5 --- /dev/null +++ b/20_timer_callbacks/kernel/tests/panic_wait_forever/mod.rs @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2022 Andre Richter + +/// Overwrites libkernel's `panic_wait::_panic_exit()` with wait_forever. +#[no_mangle] +fn _panic_exit() -> ! { + libkernel::cpu::wait_forever() +} diff --git a/20_timer_callbacks/kernel_symbols.mk b/20_timer_callbacks/kernel_symbols.mk new file mode 100644 index 00000000..d496ea8a --- /dev/null +++ b/20_timer_callbacks/kernel_symbols.mk @@ -0,0 +1,117 @@ +## SPDX-License-Identifier: MIT OR Apache-2.0 +## +## Copyright (c) 2018-2022 Andre Richter + +include ../common/format.mk +include ../common/docker.mk + +##-------------------------------------------------------------------------------------------------- +## Check for input variables that need be exported by the calling Makefile +##-------------------------------------------------------------------------------------------------- +ifndef KERNEL_SYMBOLS_TOOL_PATH +$(error KERNEL_SYMBOLS_TOOL_PATH is not set) +endif + +ifndef TARGET +$(error TARGET is not set) +endif + +ifndef KERNEL_SYMBOLS_INPUT_ELF +$(error KERNEL_SYMBOLS_INPUT_ELF is not set) +endif + +ifndef KERNEL_SYMBOLS_OUTPUT_ELF +$(error KERNEL_SYMBOLS_OUTPUT_ELF is not set) +endif + + + +##-------------------------------------------------------------------------------------------------- +## Targets and Prerequisites +##-------------------------------------------------------------------------------------------------- +KERNEL_SYMBOLS_MANIFEST = kernel_symbols/Cargo.toml +KERNEL_SYMBOLS_LINKER_SCRIPT = kernel_symbols/kernel_symbols.ld + +KERNEL_SYMBOLS_RS = $(KERNEL_SYMBOLS_INPUT_ELF)_symbols.rs +KERNEL_SYMBOLS_DEMANGLED_RS = $(shell pwd)/$(KERNEL_SYMBOLS_INPUT_ELF)_symbols_demangled.rs + +KERNEL_SYMBOLS_ELF = target/$(TARGET)/release/kernel_symbols +KERNEL_SYMBOLS_STRIPPED = target/$(TARGET)/release/kernel_symbols_stripped + +# Export for build.rs of kernel_symbols crate. +export KERNEL_SYMBOLS_DEMANGLED_RS + + + +##-------------------------------------------------------------------------------------------------- +## Command building blocks +##-------------------------------------------------------------------------------------------------- +GET_SYMBOLS_SECTION_VIRT_ADDR = $(DOCKER_TOOLS) $(EXEC_SYMBOLS_TOOL) \ + --get_symbols_section_virt_addr $(KERNEL_SYMBOLS_OUTPUT_ELF) + +RUSTFLAGS = -C link-arg=--script=$(KERNEL_SYMBOLS_LINKER_SCRIPT) \ + -C link-arg=--section-start=.rodata=$$($(GET_SYMBOLS_SECTION_VIRT_ADDR)) + +RUSTFLAGS_PEDANTIC = $(RUSTFLAGS) \ + -D warnings \ + -D missing_docs + +COMPILER_ARGS = --target=$(TARGET) \ + --release + +RUSTC_CMD = cargo rustc $(COMPILER_ARGS) --manifest-path $(KERNEL_SYMBOLS_MANIFEST) +OBJCOPY_CMD = rust-objcopy \ + --strip-all \ + -O binary + +EXEC_SYMBOLS_TOOL = ruby $(KERNEL_SYMBOLS_TOOL_PATH)/main.rb + +##------------------------------------------------------------------------------ +## Dockerization +##------------------------------------------------------------------------------ +DOCKER_CMD = docker run -t --rm -v $(shell pwd):/work/tutorial -w /work/tutorial + +# DOCKER_IMAGE defined in include file (see top of this file). +DOCKER_TOOLS = $(DOCKER_CMD) $(DOCKER_IMAGE) + + + +##-------------------------------------------------------------------------------------------------- +## Targets +##-------------------------------------------------------------------------------------------------- +.PHONY: all symbols measure_time_start measure_time_finish + +all: measure_time_start symbols measure_time_finish + +symbols: + @cp $(KERNEL_SYMBOLS_INPUT_ELF) $(KERNEL_SYMBOLS_OUTPUT_ELF) + + @$(DOCKER_TOOLS) $(EXEC_SYMBOLS_TOOL) --gen_symbols $(KERNEL_SYMBOLS_OUTPUT_ELF) \ + $(KERNEL_SYMBOLS_RS) + + $(call color_progress_prefix, "Demangling") + @echo Symbol names + @cat $(KERNEL_SYMBOLS_RS) | rustfilt > $(KERNEL_SYMBOLS_DEMANGLED_RS) + + @RUSTFLAGS="$(RUSTFLAGS_PEDANTIC)" $(RUSTC_CMD) + + $(call color_progress_prefix, "Stripping") + @echo Symbols ELF file + @$(OBJCOPY_CMD) $(KERNEL_SYMBOLS_ELF) $(KERNEL_SYMBOLS_STRIPPED) + + @$(DOCKER_TOOLS) $(EXEC_SYMBOLS_TOOL) --patch_data $(KERNEL_SYMBOLS_OUTPUT_ELF) \ + $(KERNEL_SYMBOLS_STRIPPED) + +# Note: The following is the only _trivial_ way I could think of that works out of the box on both +# Linux and macOS. Since macOS does not have the %N nanosecond format string option, the +# resolution is restricted to whole seconds. +measure_time_start: + @date +%s > /tmp/kernel_symbols_start.date + +measure_time_finish: + @date +%s > /tmp/kernel_symbols_end.date + + $(call color_progress_prefix, "Finished") + @echo "in $$((`cat /tmp/kernel_symbols_end.date` - `cat /tmp/kernel_symbols_start.date`)).0s" + + @rm /tmp/kernel_symbols_end.date /tmp/kernel_symbols_start.date diff --git a/20_timer_callbacks/kernel_symbols/Cargo.lock b/20_timer_callbacks/kernel_symbols/Cargo.lock new file mode 100644 index 00000000..70b7fa66 --- /dev/null +++ b/20_timer_callbacks/kernel_symbols/Cargo.lock @@ -0,0 +1,14 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "debug-symbol-types" +version = "0.1.0" + +[[package]] +name = "kernel_symbols" +version = "0.1.0" +dependencies = [ + "debug-symbol-types", +] diff --git a/20_timer_callbacks/kernel_symbols/Cargo.toml b/20_timer_callbacks/kernel_symbols/Cargo.toml new file mode 100644 index 00000000..3407aa7e --- /dev/null +++ b/20_timer_callbacks/kernel_symbols/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "kernel_symbols" +version = "0.1.0" +edition = "2021" + +[features] +default = [] +generated_symbols_available = [] + +##-------------------------------------------------------------------------------------------------- +## Dependencies +##-------------------------------------------------------------------------------------------------- + +[dependencies] +debug-symbol-types = { path = "../libraries/debug-symbol-types" } diff --git a/20_timer_callbacks/kernel_symbols/build.rs b/20_timer_callbacks/kernel_symbols/build.rs new file mode 100644 index 00000000..5062df44 --- /dev/null +++ b/20_timer_callbacks/kernel_symbols/build.rs @@ -0,0 +1,14 @@ +use std::{env, path::Path}; + +fn main() { + if let Ok(path) = env::var("KERNEL_SYMBOLS_DEMANGLED_RS") { + if Path::new(&path).exists() { + println!("cargo:rustc-cfg=feature=\"generated_symbols_available\"") + } + } + + println!( + "cargo:rerun-if-changed={}", + Path::new("kernel_symbols.ld").display() + ); +} diff --git a/20_timer_callbacks/kernel_symbols/kernel_symbols.ld b/20_timer_callbacks/kernel_symbols/kernel_symbols.ld new file mode 100644 index 00000000..0625f008 --- /dev/null +++ b/20_timer_callbacks/kernel_symbols/kernel_symbols.ld @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: MIT OR Apache-2.0 + * + * Copyright (c) 2022 Andre Richter + */ + +SECTIONS +{ + .rodata : { + ASSERT(. > 0xffffffff00000000, "Expected higher half address") + + KEEP(*(.rodata.symbol_desc*)) + . = ALIGN(8); + *(.rodata*) + } +} diff --git a/20_timer_callbacks/kernel_symbols/src/main.rs b/20_timer_callbacks/kernel_symbols/src/main.rs new file mode 100644 index 00000000..bd90b535 --- /dev/null +++ b/20_timer_callbacks/kernel_symbols/src/main.rs @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2022 Andre Richter + +//! Generation of kernel symbols. + +#![no_std] +#![no_main] + +#[cfg(feature = "generated_symbols_available")] +include!(env!("KERNEL_SYMBOLS_DEMANGLED_RS")); + +#[panic_handler] +fn panic(_info: &core::panic::PanicInfo) -> ! { + unimplemented!() +} diff --git a/20_timer_callbacks/libraries/debug-symbol-types/Cargo.toml b/20_timer_callbacks/libraries/debug-symbol-types/Cargo.toml new file mode 100644 index 00000000..e5b1fd1f --- /dev/null +++ b/20_timer_callbacks/libraries/debug-symbol-types/Cargo.toml @@ -0,0 +1,4 @@ +[package] +name = "debug-symbol-types" +version = "0.1.0" +edition = "2021" diff --git a/20_timer_callbacks/libraries/debug-symbol-types/src/lib.rs b/20_timer_callbacks/libraries/debug-symbol-types/src/lib.rs new file mode 100644 index 00000000..b6dff082 --- /dev/null +++ b/20_timer_callbacks/libraries/debug-symbol-types/src/lib.rs @@ -0,0 +1,45 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2022 Andre Richter + +//! Types for implementing debug symbol support. + +#![no_std] + +use core::ops::Range; + +/// A symbol containing a size. +#[repr(C)] +#[derive(Clone)] +pub struct Symbol { + addr_range: Range, + name: &'static str, +} + +impl Symbol { + /// Create an instance. + pub const fn new(start: usize, size: usize, name: &'static str) -> Symbol { + Symbol { + addr_range: Range { + start, + end: start + size, + }, + name, + } + } + + /// Returns true if addr is contained in the range. + pub fn contains(&self, addr: usize) -> bool { + self.addr_range.contains(&addr) + } + + /// Returns the symbol's name. + pub fn name(&self) -> &'static str { + self.name + } + + /// Returns the symbol's size. + pub fn size(&self) -> usize { + self.addr_range.end - self.addr_range.start + } +} diff --git a/20_timer_callbacks/libraries/test-macros/Cargo.toml b/20_timer_callbacks/libraries/test-macros/Cargo.toml new file mode 100644 index 00000000..fff98a1f --- /dev/null +++ b/20_timer_callbacks/libraries/test-macros/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "test-macros" +version = "0.1.0" +authors = ["Andre Richter "] +edition = "2021" + +[lib] +proc-macro = true + +[dependencies] +proc-macro2 = "1.x" +quote = "1.x" +syn = { version = "1.x", features = ["full"] } +test-types = { path = "../test-types" } diff --git a/20_timer_callbacks/libraries/test-macros/src/lib.rs b/20_timer_callbacks/libraries/test-macros/src/lib.rs new file mode 100644 index 00000000..9879677c --- /dev/null +++ b/20_timer_callbacks/libraries/test-macros/src/lib.rs @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2019-2022 Andre Richter + +use proc_macro::TokenStream; +use proc_macro2::Span; +use quote::quote; +use syn::{parse_macro_input, Ident, ItemFn}; + +#[proc_macro_attribute] +pub fn kernel_test(_attr: TokenStream, input: TokenStream) -> TokenStream { + let f = parse_macro_input!(input as ItemFn); + + let test_name = &format!("{}", f.sig.ident); + let test_ident = Ident::new( + &format!("{}_TEST_CONTAINER", f.sig.ident.to_string().to_uppercase()), + Span::call_site(), + ); + let test_code_block = f.block; + + quote!( + #[test_case] + const #test_ident: test_types::UnitTest = test_types::UnitTest { + name: #test_name, + test_func: || #test_code_block, + }; + ) + .into() +} diff --git a/20_timer_callbacks/libraries/test-types/Cargo.toml b/20_timer_callbacks/libraries/test-types/Cargo.toml new file mode 100644 index 00000000..2f20f060 --- /dev/null +++ b/20_timer_callbacks/libraries/test-types/Cargo.toml @@ -0,0 +1,5 @@ +[package] +name = "test-types" +version = "0.1.0" +authors = ["Andre Richter "] +edition = "2021" diff --git a/20_timer_callbacks/libraries/test-types/src/lib.rs b/20_timer_callbacks/libraries/test-types/src/lib.rs new file mode 100644 index 00000000..922c2a1c --- /dev/null +++ b/20_timer_callbacks/libraries/test-types/src/lib.rs @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2019-2022 Andre Richter + +//! Types for the `custom_test_frameworks` implementation. + +#![no_std] + +/// Unit test container. +pub struct UnitTest { + /// Name of the test. + pub name: &'static str, + + /// Function pointer to the test. + pub test_func: fn(), +} diff --git a/20_timer_callbacks/tools/kernel_symbols_tool/cmds.rb b/20_timer_callbacks/tools/kernel_symbols_tool/cmds.rb new file mode 100644 index 00000000..fe66ea71 --- /dev/null +++ b/20_timer_callbacks/tools/kernel_symbols_tool/cmds.rb @@ -0,0 +1,45 @@ +# frozen_string_literal: true + +# SPDX-License-Identifier: MIT OR Apache-2.0 +# +# Copyright (c) 2022 Andre Richter + +def generate_symbols(kernel_elf, output_file) + File.open(output_file, 'w') do |file| + header = <<~HEREDOC + use debug_symbol_types::Symbol; + + # [no_mangle] + # [link_section = ".rodata.symbol_desc"] + static KERNEL_SYMBOLS: [Symbol; #{kernel_elf.num_symbols}] = [ + HEREDOC + + file.write(header) + kernel_elf.symbols.each do |sym| + value = sym.header.st_value + size = sym.header.st_size + name = sym.name + + file.write(" Symbol::new(#{value}, #{size}, \"#{name}\"),\n") + end + file.write("];\n") + end +end + +def get_symbols_section_virt_addr(kernel_elf) + kernel_elf.kernel_symbols_section_virt_addr +end + +def patch_symbol_data(kernel_elf, symbols_blob_path) + symbols_blob = File.binread(symbols_blob_path) + + raise if symbols_blob.size > kernel_elf.kernel_symbols_section_size + + File.binwrite(kernel_elf.path, File.binread(symbols_blob_path), + kernel_elf.kernel_symbols_section_offset_in_file) +end + +def patch_num_symbols(kernel_elf) + num_packed = [kernel_elf.num_symbols].pack('Q<*') # "Q" == uint64_t, "<" == little endian + File.binwrite(kernel_elf.path, num_packed, kernel_elf.num_kernel_symbols_offset_in_file) +end diff --git a/20_timer_callbacks/tools/kernel_symbols_tool/kernel_elf.rb b/20_timer_callbacks/tools/kernel_symbols_tool/kernel_elf.rb new file mode 100644 index 00000000..b1649767 --- /dev/null +++ b/20_timer_callbacks/tools/kernel_symbols_tool/kernel_elf.rb @@ -0,0 +1,74 @@ +# frozen_string_literal: true + +# SPDX-License-Identifier: MIT OR Apache-2.0 +# +# Copyright (c) 2021-2022 Andre Richter + +# KernelELF +class KernelELF + attr_reader :path + + def initialize(kernel_elf_path, kernel_symbols_section, num_kernel_symbols) + @elf = ELFTools::ELFFile.new(File.open(kernel_elf_path)) + @symtab_section = @elf.section_by_name('.symtab') + + @path = kernel_elf_path + fetch_values(kernel_symbols_section, num_kernel_symbols) + end + + private + + def fetch_values(kernel_symbols_section, num_kernel_symbols) + sym = @symtab_section.symbol_by_name(num_kernel_symbols) + raise "Symbol \"#{num_kernel_symbols}\" not found" if sym.nil? + + @num_kernel_symbols = sym + + section = @elf.section_by_name(kernel_symbols_section) + raise "Section \"#{kernel_symbols_section}\" not found" if section.nil? + + @kernel_symbols_section = section + end + + def num_kernel_symbols_virt_addr + @num_kernel_symbols.header.st_value + end + + def segment_containing_virt_addr(virt_addr) + @elf.each_segments do |segment| + return segment if segment.vma_in?(virt_addr) + end + end + + def virt_addr_to_file_offset(virt_addr) + segment = segment_containing_virt_addr(virt_addr) + segment.vma_to_offset(virt_addr) + end + + public + + def symbols + non_zero_symbols = @symtab_section.symbols.reject { |sym| sym.header.st_size.zero? } + non_zero_symbols.sort_by { |sym| sym.header.st_value } + end + + def num_symbols + symbols.size + end + + def kernel_symbols_section_virt_addr + @kernel_symbols_section.header.sh_addr.to_i + end + + def kernel_symbols_section_size + @kernel_symbols_section.header.sh_size.to_i + end + + def kernel_symbols_section_offset_in_file + virt_addr_to_file_offset(kernel_symbols_section_virt_addr) + end + + def num_kernel_symbols_offset_in_file + virt_addr_to_file_offset(num_kernel_symbols_virt_addr) + end +end diff --git a/20_timer_callbacks/tools/kernel_symbols_tool/main.rb b/20_timer_callbacks/tools/kernel_symbols_tool/main.rb new file mode 100755 index 00000000..30a8be6f --- /dev/null +++ b/20_timer_callbacks/tools/kernel_symbols_tool/main.rb @@ -0,0 +1,47 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +# SPDX-License-Identifier: MIT OR Apache-2.0 +# +# Copyright (c) 2022 Andre Richter + +require 'rubygems' +require 'bundler/setup' +require 'colorize' +require 'elftools' + +require_relative 'kernel_elf' +require_relative 'cmds' + +KERNEL_SYMBOLS_SECTION = '.kernel_symbols' +NUM_KERNEL_SYMBOLS = 'NUM_KERNEL_SYMBOLS' + +cmd = ARGV[0] + +kernel_elf_path = ARGV[1] +kernel_elf = KernelELF.new(kernel_elf_path, KERNEL_SYMBOLS_SECTION, NUM_KERNEL_SYMBOLS) + +case cmd +when '--gen_symbols' + output_file = ARGV[2] + + print 'Generating'.rjust(12).green.bold + puts ' Symbols source file' + + generate_symbols(kernel_elf, output_file) +when '--get_symbols_section_virt_addr' + addr = get_symbols_section_virt_addr(kernel_elf) + + puts "0x#{addr.to_s(16)}" +when '--patch_data' + symbols_blob_path = ARGV[2] + num_symbols = kernel_elf.num_symbols + + print 'Patching'.rjust(12).green.bold + puts " Symbols blob and number of symbols (#{num_symbols}) into ELF" + + patch_symbol_data(kernel_elf, symbols_blob_path) + patch_num_symbols(kernel_elf) +else + raise +end diff --git a/20_timer_callbacks/tools/translation_table_tool/arch.rb b/20_timer_callbacks/tools/translation_table_tool/arch.rb new file mode 100644 index 00000000..deceb6d0 --- /dev/null +++ b/20_timer_callbacks/tools/translation_table_tool/arch.rb @@ -0,0 +1,314 @@ +# frozen_string_literal: true + +# SPDX-License-Identifier: MIT OR Apache-2.0 +# +# Copyright (c) 2021-2022 Andre Richter + +# Bitfield manipulation. +class BitField + def initialize + @value = 0 + end + + def self.attr_bitfield(name, offset, num_bits) + define_method("#{name}=") do |bits| + mask = (2**num_bits) - 1 + + raise "Input out of range: #{name} = 0x#{bits.to_s(16)}" if (bits & ~mask).positive? + + # Clear bitfield + @value &= ~(mask << offset) + + # Set it + @value |= (bits << offset) + end + end + + def to_i + @value + end + + def size_in_byte + 8 + end +end + +# An array class that knows its memory location. +class CArray < Array + attr_reader :phys_start_addr + + def initialize(phys_start_addr, size, &block) + @phys_start_addr = phys_start_addr + + super(size, &block) + end + + def size_in_byte + inject(0) { |sum, n| sum + n.size_in_byte } + end +end + +#--------------------------------------------------------------------------------------------------- +# Arch:: +#--------------------------------------------------------------------------------------------------- +module Arch +#--------------------------------------------------------------------------------------------------- +# Arch::ARMv8 +#--------------------------------------------------------------------------------------------------- +module ARMv8 +# ARMv8 Table Descriptor. +class Stage1TableDescriptor < BitField + module NextLevelTableAddr + OFFSET = 16 + NUMBITS = 32 + end + + module Type + OFFSET = 1 + NUMBITS = 1 + + BLOCK = 0 + TABLE = 1 + end + + module Valid + OFFSET = 0 + NUMBITS = 1 + + FALSE = 0 + TRUE = 1 + end + + attr_bitfield(:__next_level_table_addr, NextLevelTableAddr::OFFSET, NextLevelTableAddr::NUMBITS) + attr_bitfield(:type, Type::OFFSET, Type::NUMBITS) + attr_bitfield(:valid, Valid::OFFSET, Valid::NUMBITS) + + def next_level_table_addr=(addr) + addr = addr >> Granule64KiB::SHIFT + + self.__next_level_table_addr = addr + end + + private :__next_level_table_addr= +end + +# ARMv8 level 3 page descriptor. +class Stage1PageDescriptor < BitField + module UXN + OFFSET = 54 + NUMBITS = 1 + + FALSE = 0 + TRUE = 1 + end + + module PXN + OFFSET = 53 + NUMBITS = 1 + + FALSE = 0 + TRUE = 1 + end + + module OutputAddr + OFFSET = 16 + NUMBITS = 32 + end + + module AF + OFFSET = 10 + NUMBITS = 1 + + FALSE = 0 + TRUE = 1 + end + + module SH + OFFSET = 8 + NUMBITS = 2 + + INNER_SHAREABLE = 0b11 + end + + module AP + OFFSET = 6 + NUMBITS = 2 + + RW_EL1 = 0b00 + RO_EL1 = 0b10 + end + + module AttrIndx + OFFSET = 2 + NUMBITS = 3 + end + + module Type + OFFSET = 1 + NUMBITS = 1 + + RESERVED_INVALID = 0 + PAGE = 1 + end + + module Valid + OFFSET = 0 + NUMBITS = 1 + + FALSE = 0 + TRUE = 1 + end + + attr_bitfield(:uxn, UXN::OFFSET, UXN::NUMBITS) + attr_bitfield(:pxn, PXN::OFFSET, PXN::NUMBITS) + attr_bitfield(:__output_addr, OutputAddr::OFFSET, OutputAddr::NUMBITS) + attr_bitfield(:af, AF::OFFSET, AF::NUMBITS) + attr_bitfield(:sh, SH::OFFSET, SH::NUMBITS) + attr_bitfield(:ap, AP::OFFSET, AP::NUMBITS) + attr_bitfield(:attr_indx, AttrIndx::OFFSET, AttrIndx::NUMBITS) + attr_bitfield(:type, Type::OFFSET, Type::NUMBITS) + attr_bitfield(:valid, Valid::OFFSET, Valid::NUMBITS) + + def output_addr=(addr) + addr = addr >> Granule64KiB::SHIFT + + self.__output_addr = addr + end + + private :__output_addr= +end + +# Translation table representing the structure defined in translation_table.rs. +class TranslationTable + module MAIR + NORMAL = 1 + end + + def initialize + do_sanity_checks + + num_lvl2_tables = BSP.kernel_virt_addr_space_size >> Granule512MiB::SHIFT + + @lvl3 = new_lvl3(num_lvl2_tables, BSP.phys_addr_of_kernel_tables) + + @lvl2_phys_start_addr = @lvl3.phys_start_addr + @lvl3.size_in_byte + @lvl2 = new_lvl2(num_lvl2_tables, @lvl2_phys_start_addr) + + populate_lvl2_entries + end + + def map_at(virt_region, phys_region, attributes) + return if virt_region.empty? + + raise if virt_region.size != phys_region.size + raise if phys_region.last > BSP.phys_addr_space_end_page + + virt_region.zip(phys_region).each do |virt_page, phys_page| + desc = page_descriptor_from(virt_page) + set_lvl3_entry(desc, phys_page, attributes) + end + end + + def to_binary + data = @lvl3.flatten.map(&:to_i) + @lvl2.map(&:to_i) + data.pack('Q<*') # "Q" == uint64_t, "<" == little endian + end + + def phys_tables_base_addr_binary + [@lvl2_phys_start_addr].pack('Q<*') # "Q" == uint64_t, "<" == little endian + end + + def phys_tables_base_addr + @lvl2_phys_start_addr + end + + private + + def do_sanity_checks + raise unless BSP.kernel_granule::SIZE == Granule64KiB::SIZE + raise unless (BSP.kernel_virt_addr_space_size % Granule512MiB::SIZE).zero? + end + + def new_lvl3(num_lvl2_tables, start_addr) + CArray.new(start_addr, num_lvl2_tables) do + temp = CArray.new(start_addr, 8192) do + Stage1PageDescriptor.new + end + start_addr += temp.size_in_byte + + temp + end + end + + def new_lvl2(num_lvl2_tables, start_addr) + CArray.new(start_addr, num_lvl2_tables) do + Stage1TableDescriptor.new + end + end + + def populate_lvl2_entries + @lvl2.each_with_index do |descriptor, i| + descriptor.next_level_table_addr = @lvl3[i].phys_start_addr + descriptor.type = Stage1TableDescriptor::Type::TABLE + descriptor.valid = Stage1TableDescriptor::Valid::TRUE + end + end + + def lvl2_lvl3_index_from(addr) + addr -= BSP.kernel_virt_start_addr + + lvl2_index = addr >> Granule512MiB::SHIFT + lvl3_index = (addr & Granule512MiB::MASK) >> Granule64KiB::SHIFT + + raise unless lvl2_index < @lvl2.size + + [lvl2_index, lvl3_index] + end + + def page_descriptor_from(virt_addr) + lvl2_index, lvl3_index = lvl2_lvl3_index_from(virt_addr) + + @lvl3[lvl2_index][lvl3_index] + end + + # rubocop:disable Metrics/MethodLength + def set_attributes(desc, attributes) + case attributes.mem_attributes + when :CacheableDRAM + desc.sh = Stage1PageDescriptor::SH::INNER_SHAREABLE + desc.attr_indx = MAIR::NORMAL + else + raise 'Invalid input' + end + + desc.ap = case attributes.acc_perms + when :ReadOnly + Stage1PageDescriptor::AP::RO_EL1 + when :ReadWrite + Stage1PageDescriptor::AP::RW_EL1 + else + raise 'Invalid input' + + end + + desc.pxn = if attributes.execute_never + Stage1PageDescriptor::PXN::TRUE + else + Stage1PageDescriptor::PXN::FALSE + end + + desc.uxn = Stage1PageDescriptor::UXN::TRUE + end + # rubocop:enable Metrics/MethodLength + + def set_lvl3_entry(desc, output_addr, attributes) + desc.output_addr = output_addr + desc.af = Stage1PageDescriptor::AF::TRUE + desc.type = Stage1PageDescriptor::Type::PAGE + desc.valid = Stage1PageDescriptor::Valid::TRUE + + set_attributes(desc, attributes) + end +end +end +end diff --git a/20_timer_callbacks/tools/translation_table_tool/bsp.rb b/20_timer_callbacks/tools/translation_table_tool/bsp.rb new file mode 100644 index 00000000..dbab5ab6 --- /dev/null +++ b/20_timer_callbacks/tools/translation_table_tool/bsp.rb @@ -0,0 +1,54 @@ +# frozen_string_literal: true + +# SPDX-License-Identifier: MIT OR Apache-2.0 +# +# Copyright (c) 2021-2022 Andre Richter + +# Raspberry Pi 3 + 4 +class RaspberryPi + attr_reader :kernel_granule, :kernel_virt_addr_space_size, :kernel_virt_start_addr + + MEMORY_SRC = File.read('kernel/src/bsp/raspberrypi/memory.rs').split("\n") + + def initialize + @kernel_granule = Granule64KiB + + @kernel_virt_addr_space_size = KERNEL_ELF.symbol_value('__kernel_virt_addr_space_size') + @kernel_virt_start_addr = KERNEL_ELF.symbol_value('__kernel_virt_start_addr') + + @virt_addr_of_kernel_tables = KERNEL_ELF.symbol_value('KERNEL_TABLES') + @virt_addr_of_phys_kernel_tables_base_addr = KERNEL_ELF.symbol_value( + 'PHYS_KERNEL_TABLES_BASE_ADDR' + ) + end + + def phys_addr_of_kernel_tables + KERNEL_ELF.virt_to_phys(@virt_addr_of_kernel_tables) + end + + def kernel_tables_offset_in_file + KERNEL_ELF.virt_addr_to_file_offset(@virt_addr_of_kernel_tables) + end + + def phys_kernel_tables_base_addr_offset_in_file + KERNEL_ELF.virt_addr_to_file_offset(@virt_addr_of_phys_kernel_tables_base_addr) + end + + def phys_addr_space_end_page + x = MEMORY_SRC.grep(/pub const END/) + x = case BSP_TYPE + when :rpi3 + x[0] + when :rpi4 + x[1] + else + raise + end + + # Extract the hex literal with underscores like 0x0123_abcd. + x = x.scan(/0x[\h_]*/)[0] + + # Further remove x and _ and convert to int. + x.scan(/\h+/).join.to_i(16) + end +end diff --git a/20_timer_callbacks/tools/translation_table_tool/generic.rb b/20_timer_callbacks/tools/translation_table_tool/generic.rb new file mode 100644 index 00000000..eee8ccda --- /dev/null +++ b/20_timer_callbacks/tools/translation_table_tool/generic.rb @@ -0,0 +1,189 @@ +# frozen_string_literal: true + +# SPDX-License-Identifier: MIT OR Apache-2.0 +# +# Copyright (c) 2021-2022 Andre Richter + +module Granule64KiB + SIZE = 64 * 1024 + SHIFT = Math.log2(SIZE).to_i +end + +module Granule512MiB + SIZE = 512 * 1024 * 1024 + SHIFT = Math.log2(SIZE).to_i + MASK = SIZE - 1 +end + +# Monkey-patch Integer with some helper functions. +class Integer + def power_of_two? + self[0].zero? + end + + def aligned?(alignment) + raise unless alignment.power_of_two? + + (self & (alignment - 1)).zero? + end + + def align_up(alignment) + raise unless alignment.power_of_two? + + (self + alignment - 1) & ~(alignment - 1) + end + + def to_hex_underscore(with_leading_zeros: false) + fmt = with_leading_zeros ? '%016x' : '%x' + value = format(fmt, self).to_s.reverse.scan(/.{4}|.+/).join('_').reverse + + format('0x%s', value) + end +end + +# An array where each value is the start address of a Page. +class MemoryRegion < Array + def initialize(start_addr, size, granule_size) + raise unless start_addr.aligned?(granule_size) + raise unless size.positive? + raise unless (size % granule_size).zero? + + num_pages = size / granule_size + super(num_pages) do |i| + (i * granule_size) + start_addr + end + end +end + +# Collection of memory attributes. +class AttributeFields + attr_reader :mem_attributes, :acc_perms, :execute_never + + def initialize(mem_attributes, acc_perms, execute_never) + @mem_attributes = mem_attributes + @acc_perms = acc_perms + @execute_never = execute_never + end + + def to_s + x = case @mem_attributes + when :CacheableDRAM + 'C' + else + '?' + end + + y = case @acc_perms + when :ReadWrite + 'RW' + when :ReadOnly + 'RO' + else + '??' + end + + z = @execute_never ? 'XN' : 'X ' + + "#{x} #{y} #{z}" + end +end + +# A container that describes a virt-to-phys region mapping. +class MappingDescriptor + @max_section_name_length = 'Sections'.length + + class << self + attr_accessor :max_section_name_length + + def update_max_section_name_length(length) + @max_section_name_length = [@max_section_name_length, length].max + end + end + + attr_reader :name, :virt_region, :phys_region, :attributes + + def initialize(name, virt_region, phys_region, attributes) + @name = name + @virt_region = virt_region + @phys_region = phys_region + @attributes = attributes + end + + def size_human_readable(size) + if size >= (1024 * 1024) + "#{(size / (1024 * 1024)).to_s.rjust(3)} MiB" + elsif size >= 1024 + "#{(size / 1024).to_s.rjust(3)} KiB" + else + raise + end + end + + def to_s + name = @name.ljust(self.class.max_section_name_length) + virt_start = @virt_region.first.to_hex_underscore(with_leading_zeros: true) + phys_start = @phys_region.first.to_hex_underscore(with_leading_zeros: true) + size = size_human_readable(@virt_region.size * 65_536) + + "#{name} | #{virt_start} | #{phys_start} | #{size} | #{@attributes}" + end + + def self.print_divider + print ' ' + print '-' * max_section_name_length + puts '--------------------------------------------------------------------' + end + + def self.print_header + print_divider + print ' ' + print 'Sections'.center(max_section_name_length) + print ' ' + print 'Virt Start Addr'.center(21) + print ' ' + print 'Phys Start Addr'.center(21) + print ' ' + print 'Size'.center(7) + print ' ' + print 'Attr'.center(7) + puts + print_divider + end +end + +def kernel_map_binary + mapping_descriptors = KERNEL_ELF.generate_mapping_descriptors + + # Generate_mapping_descriptors updates the header being printed with this call. So it must come + # afterwards. + MappingDescriptor.print_header + + mapping_descriptors.each do |i| + print 'Generating'.rjust(12).green.bold + print ' ' + puts i.to_s + + TRANSLATION_TABLES.map_at(i.virt_region, i.phys_region, i.attributes) + end + + MappingDescriptor.print_divider +end + +def kernel_patch_tables(kernel_elf_path) + print 'Patching'.rjust(12).green.bold + print ' Kernel table struct at ELF file offset ' + puts BSP.kernel_tables_offset_in_file.to_hex_underscore + + File.binwrite(kernel_elf_path, TRANSLATION_TABLES.to_binary, BSP.kernel_tables_offset_in_file) +end + +def kernel_patch_base_addr(kernel_elf_path) + print 'Patching'.rjust(12).green.bold + print ' Kernel tables physical base address start argument to value ' + print TRANSLATION_TABLES.phys_tables_base_addr.to_hex_underscore + print ' at ELF file offset ' + puts BSP.phys_kernel_tables_base_addr_offset_in_file.to_hex_underscore + + File.binwrite(kernel_elf_path, TRANSLATION_TABLES.phys_tables_base_addr_binary, + BSP.phys_kernel_tables_base_addr_offset_in_file) +end diff --git a/20_timer_callbacks/tools/translation_table_tool/kernel_elf.rb b/20_timer_callbacks/tools/translation_table_tool/kernel_elf.rb new file mode 100644 index 00000000..f2d5b0b7 --- /dev/null +++ b/20_timer_callbacks/tools/translation_table_tool/kernel_elf.rb @@ -0,0 +1,96 @@ +# frozen_string_literal: true + +# SPDX-License-Identifier: MIT OR Apache-2.0 +# +# Copyright (c) 2021-2022 Andre Richter + +# KernelELF +class KernelELF + SECTION_FLAG_ALLOC = 2 + + def initialize(kernel_elf_path) + @elf = ELFTools::ELFFile.new(File.open(kernel_elf_path)) + @symtab_section = @elf.section_by_name('.symtab') + end + + def machine + @elf.machine.to_sym + end + + def symbol_value(symbol_name) + @symtab_section.symbol_by_name(symbol_name).header.st_value + end + + def segment_containing_virt_addr(virt_addr) + @elf.each_segments do |segment| + return segment if segment.vma_in?(virt_addr) + end + end + + def virt_to_phys(virt_addr) + segment = segment_containing_virt_addr(virt_addr) + translation_offset = segment.header.p_vaddr - segment.header.p_paddr + + virt_addr - translation_offset + end + + def virt_addr_to_file_offset(virt_addr) + segment = segment_containing_virt_addr(virt_addr) + segment.vma_to_offset(virt_addr) + end + + def sections_in_segment(segment) + head = segment.mem_head + tail = segment.mem_tail + + sections = @elf.each_sections.select do |section| + file_offset = section.header.sh_addr + flags = section.header.sh_flags + + file_offset >= head && file_offset < tail && (flags & SECTION_FLAG_ALLOC != 0) + end + + sections.map(&:name).join(' ') + end + + def select_load_segments + @elf.each_segments.select do |segment| + segment.instance_of?(ELFTools::Segments::LoadSegment) + end + end + + def segment_get_acc_perms(segment) + if segment.readable? && segment.writable? + :ReadWrite + elsif segment.readable? + :ReadOnly + else + :Invalid + end + end + + def update_max_section_name_length(descriptors) + MappingDescriptor.update_max_section_name_length(descriptors.map { |i| i.name.size }.max) + end + + def generate_mapping_descriptors + descriptors = select_load_segments.map do |segment| + # Assume each segment is page aligned. + size = segment.mem_size.align_up(BSP.kernel_granule::SIZE) + virt_start_addr = segment.header.p_vaddr + phys_start_addr = segment.header.p_paddr + acc_perms = segment_get_acc_perms(segment) + execute_never = !segment.executable? + section_names = sections_in_segment(segment) + + virt_region = MemoryRegion.new(virt_start_addr, size, BSP.kernel_granule::SIZE) + phys_region = MemoryRegion.new(phys_start_addr, size, BSP.kernel_granule::SIZE) + attributes = AttributeFields.new(:CacheableDRAM, acc_perms, execute_never) + + MappingDescriptor.new(section_names, virt_region, phys_region, attributes) + end + + update_max_section_name_length(descriptors) + descriptors + end +end diff --git a/20_timer_callbacks/tools/translation_table_tool/main.rb b/20_timer_callbacks/tools/translation_table_tool/main.rb new file mode 100755 index 00000000..6419e364 --- /dev/null +++ b/20_timer_callbacks/tools/translation_table_tool/main.rb @@ -0,0 +1,46 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +# SPDX-License-Identifier: MIT OR Apache-2.0 +# +# Copyright (c) 2021-2022 Andre Richter + +require 'rubygems' +require 'bundler/setup' +require 'colorize' +require 'elftools' + +require_relative 'generic' +require_relative 'kernel_elf' +require_relative 'bsp' +require_relative 'arch' + +BSP_TYPE = ARGV[0].to_sym +kernel_elf_path = ARGV[1] + +start = Time.now + +KERNEL_ELF = KernelELF.new(kernel_elf_path) + +BSP = case BSP_TYPE + when :rpi3, :rpi4 + RaspberryPi.new + else + raise + end + +TRANSLATION_TABLES = case KERNEL_ELF.machine + when :AArch64 + Arch::ARMv8::TranslationTable.new + else + raise + end + +kernel_map_binary +kernel_patch_tables(kernel_elf_path) +kernel_patch_base_addr(kernel_elf_path) + +elapsed = Time.now - start + +print 'Finished'.rjust(12).green.bold +puts " in #{elapsed.round(2)}s" From 60ae47032ba1253265f5eabf2bb1520d1200e4df Mon Sep 17 00:00:00 2001 From: Andre Richter Date: Wed, 26 Oct 2022 22:36:35 +0200 Subject: [PATCH 63/75] typo --- 20_timer_callbacks/README.md | 6 +++--- 20_timer_callbacks/kernel/src/_arch/aarch64/time.rs | 2 +- .../kernel/src/bsp/raspberrypi/exception/asynchronous.rs | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/20_timer_callbacks/README.md b/20_timer_callbacks/README.md index 3647fb38..7d944b99 100644 --- a/20_timer_callbacks/README.md +++ b/20_timer_callbacks/README.md @@ -58,7 +58,7 @@ diff -uNr 19_kernel_heap/kernel/src/_arch/aarch64/time.rs 20_timer_callbacks/ker + +/// The associated IRQ number. +pub const fn timeout_irq() -> exception::asynchronous::IRQNumber { -+ bsp::exception::asynchronous::irq_map::ARM_NS_PHYISCAL_TIMER ++ bsp::exception::asynchronous::irq_map::ARM_NS_PHYSICAL_TIMER +} + +/// Program a timer IRQ to be fired after `delay` has passed. @@ -398,7 +398,7 @@ diff -uNr 19_kernel_heap/kernel/src/bsp/raspberrypi/exception/asynchronous.rs 20 - pub const PL011_UART: IRQNumber = IRQNumber::Peripheral(PeripheralIRQ::new(57)); + /// The non-secure physical timer IRQ number. -+ pub const ARM_NS_PHYISCAL_TIMER: IRQNumber = IRQNumber::Local(LocalIRQ::new(1)); ++ pub const ARM_NS_PHYSICAL_TIMER: IRQNumber = IRQNumber::Local(LocalIRQ::new(1)); + + pub(in crate::bsp) const PL011_UART: IRQNumber = IRQNumber::Peripheral(PeripheralIRQ::new(57)); } @@ -411,7 +411,7 @@ diff -uNr 19_kernel_heap/kernel/src/bsp/raspberrypi/exception/asynchronous.rs 20 - pub const PL011_UART: IRQNumber = IRQNumber::new(153); + /// The non-secure physical timer IRQ number. -+ pub const ARM_NS_PHYISCAL_TIMER: IRQNumber = IRQNumber::new(30); ++ pub const ARM_NS_PHYSICAL_TIMER: IRQNumber = IRQNumber::new(30); + + pub(in crate::bsp) const PL011_UART: IRQNumber = IRQNumber::new(153); } diff --git a/20_timer_callbacks/kernel/src/_arch/aarch64/time.rs b/20_timer_callbacks/kernel/src/_arch/aarch64/time.rs index 568363fc..5479deb4 100644 --- a/20_timer_callbacks/kernel/src/_arch/aarch64/time.rs +++ b/20_timer_callbacks/kernel/src/_arch/aarch64/time.rs @@ -166,7 +166,7 @@ pub fn spin_for(duration: Duration) { /// The associated IRQ number. pub const fn timeout_irq() -> exception::asynchronous::IRQNumber { - bsp::exception::asynchronous::irq_map::ARM_NS_PHYISCAL_TIMER + bsp::exception::asynchronous::irq_map::ARM_NS_PHYSICAL_TIMER } /// Program a timer IRQ to be fired after `delay` has passed. diff --git a/20_timer_callbacks/kernel/src/bsp/raspberrypi/exception/asynchronous.rs b/20_timer_callbacks/kernel/src/bsp/raspberrypi/exception/asynchronous.rs index a6fd27fb..b2cb955e 100644 --- a/20_timer_callbacks/kernel/src/bsp/raspberrypi/exception/asynchronous.rs +++ b/20_timer_callbacks/kernel/src/bsp/raspberrypi/exception/asynchronous.rs @@ -19,7 +19,7 @@ pub mod irq_map { use super::bsp::device_driver::{IRQNumber, LocalIRQ, PeripheralIRQ}; /// The non-secure physical timer IRQ number. - pub const ARM_NS_PHYISCAL_TIMER: IRQNumber = IRQNumber::Local(LocalIRQ::new(1)); + pub const ARM_NS_PHYSICAL_TIMER: IRQNumber = IRQNumber::Local(LocalIRQ::new(1)); pub(in crate::bsp) const PL011_UART: IRQNumber = IRQNumber::Peripheral(PeripheralIRQ::new(57)); } @@ -30,7 +30,7 @@ pub mod irq_map { use super::bsp::device_driver::IRQNumber; /// The non-secure physical timer IRQ number. - pub const ARM_NS_PHYISCAL_TIMER: IRQNumber = IRQNumber::new(30); + pub const ARM_NS_PHYSICAL_TIMER: IRQNumber = IRQNumber::new(30); pub(in crate::bsp) const PL011_UART: IRQNumber = IRQNumber::new(153); } From 5e3af39bdc58da3e9b31995b7b30d6fd6392801a Mon Sep 17 00:00:00 2001 From: Andre Richter Date: Sun, 6 Nov 2022 22:02:03 +0100 Subject: [PATCH 64/75] Change to aarch64-cpu crate --- 02_runtime_init/Cargo.lock | 8 +- 02_runtime_init/Cargo.toml | 2 +- 02_runtime_init/README.ES.md | 2 +- 02_runtime_init/README.md | 8 +- 02_runtime_init/src/_arch/aarch64/cpu.rs | 2 +- 03_hacky_hello_world/Cargo.lock | 8 +- 03_hacky_hello_world/Cargo.toml | 2 +- 03_hacky_hello_world/src/_arch/aarch64/cpu.rs | 2 +- 04_safe_globals/Cargo.lock | 8 +- 04_safe_globals/Cargo.toml | 2 +- 04_safe_globals/src/_arch/aarch64/cpu.rs | 2 +- 05_drivers_gpio_uart/Cargo.lock | 8 +- 05_drivers_gpio_uart/Cargo.toml | 2 +- 05_drivers_gpio_uart/README.md | 2 +- 05_drivers_gpio_uart/src/_arch/aarch64/cpu.rs | 2 +- 06_uart_chainloader/Cargo.lock | 8 +- 06_uart_chainloader/Cargo.toml | 2 +- 06_uart_chainloader/demo_payload_rpi3.img | Bin 7648 -> 9496 bytes 06_uart_chainloader/demo_payload_rpi4.img | Bin 7584 -> 9472 bytes 06_uart_chainloader/src/_arch/aarch64/cpu.rs | 2 +- 07_timestamps/Cargo.lock | 8 +- 07_timestamps/Cargo.toml | 2 +- 07_timestamps/README.md | 2 +- 07_timestamps/src/_arch/aarch64/cpu.rs | 2 +- 07_timestamps/src/_arch/aarch64/time.rs | 2 +- 08_hw_debug_JTAG/Cargo.lock | 8 +- 08_hw_debug_JTAG/Cargo.toml | 2 +- 08_hw_debug_JTAG/src/_arch/aarch64/cpu.rs | 2 +- 08_hw_debug_JTAG/src/_arch/aarch64/time.rs | 2 +- 09_privilege_level/Cargo.lock | 8 +- 09_privilege_level/Cargo.toml | 2 +- 09_privilege_level/README.md | 19 ++-- 09_privilege_level/src/_arch/aarch64/cpu.rs | 2 +- .../src/_arch/aarch64/cpu/boot.rs | 2 +- .../src/_arch/aarch64/exception.rs | 2 +- .../_arch/aarch64/exception/asynchronous.rs | 2 +- 09_privilege_level/src/_arch/aarch64/time.rs | 2 +- .../Cargo.lock | 8 +- .../Cargo.toml | 2 +- .../README.md | 12 +-- .../src/_arch/aarch64/cpu.rs | 2 +- .../src/_arch/aarch64/cpu/boot.rs | 2 +- .../src/_arch/aarch64/exception.rs | 2 +- .../_arch/aarch64/exception/asynchronous.rs | 2 +- .../src/_arch/aarch64/memory/mmu.rs | 2 +- .../src/_arch/aarch64/time.rs | 2 +- 11_exceptions_part1_groundwork/Cargo.lock | 8 +- 11_exceptions_part1_groundwork/Cargo.toml | 2 +- 11_exceptions_part1_groundwork/README.md | 4 +- .../src/_arch/aarch64/cpu.rs | 2 +- .../src/_arch/aarch64/cpu/boot.rs | 2 +- .../src/_arch/aarch64/exception.rs | 2 +- .../_arch/aarch64/exception/asynchronous.rs | 2 +- .../src/_arch/aarch64/memory/mmu.rs | 2 +- .../src/_arch/aarch64/time.rs | 2 +- 12_integrated_testing/Cargo.lock | 8 +- 12_integrated_testing/kernel/Cargo.toml | 2 +- .../kernel/src/_arch/aarch64/cpu.rs | 2 +- .../kernel/src/_arch/aarch64/cpu/boot.rs | 2 +- .../kernel/src/_arch/aarch64/exception.rs | 2 +- .../_arch/aarch64/exception/asynchronous.rs | 2 +- .../kernel/src/_arch/aarch64/memory/mmu.rs | 2 +- .../kernel/src/_arch/aarch64/time.rs | 2 +- .../Cargo.lock | 8 +- 13_exceptions_part2_peripheral_IRQs/README.md | 11 +- .../kernel/Cargo.toml | 2 +- .../kernel/src/_arch/aarch64/cpu.rs | 2 +- .../kernel/src/_arch/aarch64/cpu/boot.rs | 2 +- .../kernel/src/_arch/aarch64/cpu/smp.rs | 2 +- .../kernel/src/_arch/aarch64/exception.rs | 2 +- .../_arch/aarch64/exception/asynchronous.rs | 2 +- .../kernel/src/_arch/aarch64/memory/mmu.rs | 2 +- .../kernel/src/_arch/aarch64/time.rs | 2 +- 14_virtual_mem_part2_mmio_remap/Cargo.lock | 8 +- 14_virtual_mem_part2_mmio_remap/README.md | 2 +- .../kernel/Cargo.toml | 2 +- .../kernel/src/_arch/aarch64/cpu.rs | 2 +- .../kernel/src/_arch/aarch64/cpu/boot.rs | 2 +- .../kernel/src/_arch/aarch64/cpu/smp.rs | 2 +- .../kernel/src/_arch/aarch64/exception.rs | 2 +- .../_arch/aarch64/exception/asynchronous.rs | 2 +- .../kernel/src/_arch/aarch64/memory/mmu.rs | 2 +- .../kernel/src/_arch/aarch64/time.rs | 2 +- .../Cargo.lock | 8 +- .../README.md | 2 +- .../kernel/Cargo.toml | 2 +- .../kernel/src/_arch/aarch64/cpu.rs | 2 +- .../kernel/src/_arch/aarch64/cpu/boot.rs | 2 +- .../kernel/src/_arch/aarch64/cpu/smp.rs | 2 +- .../kernel/src/_arch/aarch64/exception.rs | 2 +- .../_arch/aarch64/exception/asynchronous.rs | 2 +- .../kernel/src/_arch/aarch64/memory/mmu.rs | 2 +- .../kernel/src/_arch/aarch64/time.rs | 2 +- .../Cargo.lock | 8 +- .../kernel/Cargo.toml | 2 +- .../kernel/src/_arch/aarch64/cpu.rs | 2 +- .../kernel/src/_arch/aarch64/cpu/boot.rs | 2 +- .../kernel/src/_arch/aarch64/cpu/smp.rs | 2 +- .../kernel/src/_arch/aarch64/exception.rs | 2 +- .../_arch/aarch64/exception/asynchronous.rs | 2 +- .../kernel/src/_arch/aarch64/memory/mmu.rs | 2 +- .../kernel/src/_arch/aarch64/time.rs | 2 +- 17_kernel_symbols/Cargo.lock | 8 +- 17_kernel_symbols/README.md | 2 +- 17_kernel_symbols/kernel/Cargo.toml | 2 +- .../kernel/src/_arch/aarch64/cpu.rs | 2 +- .../kernel/src/_arch/aarch64/cpu/boot.rs | 2 +- .../kernel/src/_arch/aarch64/cpu/smp.rs | 2 +- .../kernel/src/_arch/aarch64/exception.rs | 2 +- .../_arch/aarch64/exception/asynchronous.rs | 2 +- .../kernel/src/_arch/aarch64/memory/mmu.rs | 2 +- .../kernel/src/_arch/aarch64/time.rs | 2 +- 18_backtrace/Cargo.lock | 8 +- 18_backtrace/README.md | 8 +- 18_backtrace/kernel/Cargo.toml | 2 +- .../kernel/src/_arch/aarch64/backtrace.rs | 2 +- 18_backtrace/kernel/src/_arch/aarch64/cpu.rs | 2 +- .../kernel/src/_arch/aarch64/cpu/boot.rs | 2 +- .../kernel/src/_arch/aarch64/cpu/smp.rs | 2 +- .../kernel/src/_arch/aarch64/exception.rs | 2 +- .../_arch/aarch64/exception/asynchronous.rs | 2 +- .../kernel/src/_arch/aarch64/memory/mmu.rs | 2 +- 18_backtrace/kernel/src/_arch/aarch64/time.rs | 2 +- 19_kernel_heap/Cargo.lock | 8 +- 19_kernel_heap/kernel/Cargo.lock | 96 ------------------ 19_kernel_heap/kernel/Cargo.toml | 2 +- .../kernel/src/_arch/aarch64/backtrace.rs | 2 +- .../kernel/src/_arch/aarch64/cpu.rs | 2 +- .../kernel/src/_arch/aarch64/cpu/boot.rs | 2 +- .../kernel/src/_arch/aarch64/cpu/smp.rs | 2 +- .../kernel/src/_arch/aarch64/exception.rs | 2 +- .../_arch/aarch64/exception/asynchronous.rs | 2 +- .../kernel/src/_arch/aarch64/memory/mmu.rs | 2 +- .../kernel/src/_arch/aarch64/time.rs | 2 +- 20_timer_callbacks/Cargo.lock | 8 +- 20_timer_callbacks/README.md | 2 +- 20_timer_callbacks/kernel/Cargo.lock | 96 ------------------ 20_timer_callbacks/kernel/Cargo.toml | 2 +- .../kernel/src/_arch/aarch64/backtrace.rs | 2 +- .../kernel/src/_arch/aarch64/cpu.rs | 2 +- .../kernel/src/_arch/aarch64/cpu/boot.rs | 2 +- .../kernel/src/_arch/aarch64/cpu/smp.rs | 2 +- .../kernel/src/_arch/aarch64/exception.rs | 2 +- .../_arch/aarch64/exception/asynchronous.rs | 2 +- .../kernel/src/_arch/aarch64/memory/mmu.rs | 2 +- .../kernel/src/_arch/aarch64/time.rs | 2 +- X1_JTAG_boot/Cargo.lock | 8 +- X1_JTAG_boot/Cargo.toml | 2 +- X1_JTAG_boot/jtag_boot_rpi3.img | Bin 8648 -> 10216 bytes X1_JTAG_boot/jtag_boot_rpi4.img | Bin 7744 -> 9368 bytes X1_JTAG_boot/src/_arch/aarch64/cpu.rs | 2 +- X1_JTAG_boot/src/_arch/aarch64/time.rs | 2 +- 152 files changed, 231 insertions(+), 423 deletions(-) delete mode 100644 19_kernel_heap/kernel/Cargo.lock delete mode 100644 20_timer_callbacks/kernel/Cargo.lock diff --git a/02_runtime_init/Cargo.lock b/02_runtime_init/Cargo.lock index 17e64197..e52e7fdf 100644 --- a/02_runtime_init/Cargo.lock +++ b/02_runtime_init/Cargo.lock @@ -3,10 +3,10 @@ version = 3 [[package]] -name = "cortex-a" -version = "8.0.0" +name = "aarch64-cpu" +version = "9.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cd4524931a4e0ec50ae91f0d55f571f31ffe11dd9ce2f9905b8343c018c25bb" +checksum = "3aceb88e55ba626a5479279268d009a92d9d00eacce0de1b8c236c7ad31b7225" dependencies = [ "tock-registers", ] @@ -15,7 +15,7 @@ dependencies = [ name = "mingo" version = "0.2.0" dependencies = [ - "cortex-a", + "aarch64-cpu", ] [[package]] diff --git a/02_runtime_init/Cargo.toml b/02_runtime_init/Cargo.toml index 59566db0..5946f43c 100644 --- a/02_runtime_init/Cargo.toml +++ b/02_runtime_init/Cargo.toml @@ -24,4 +24,4 @@ path = "src/main.rs" # Platform specific dependencies [target.'cfg(target_arch = "aarch64")'.dependencies] -cortex-a = { version = "8.x.x" } +aarch64-cpu = { version = "9.x.x" } diff --git a/02_runtime_init/README.ES.md b/02_runtime_init/README.ES.md index e1210e9b..2f93586f 100644 --- a/02_runtime_init/README.ES.md +++ b/02_runtime_init/README.ES.md @@ -28,7 +28,7 @@ * Llama a `kernel_init()`, que llama a `panic!()`, que al final también pone al núcleo 0 en pausa. -* La librería ahora usa el crate [cortex-a](https://github.com/rust-embedded/cortex-a), que nos da abstracciones sin coste y envuelve las partes que hacen uso de un `unsafe` (partes con código que no es seguro y podría causar errores) cuando se trabaja directamente con los recursos del procesador. +* La librería ahora usa el crate [aarch64-cpu](https://github.com/rust-embedded/aarch64-cpu), que nos da abstracciones sin coste y envuelve las partes que hacen uso de un `unsafe` (partes con código que no es seguro y podría causar errores) cuando se trabaja directamente con los recursos del procesador. * Lo puedes ver en acción en `_arch/__arch_name__/cpu.rs`. diff --git a/02_runtime_init/README.md b/02_runtime_init/README.md index 7b3fcd82..76fc07dd 100644 --- a/02_runtime_init/README.md +++ b/02_runtime_init/README.md @@ -19,12 +19,12 @@ 1. Jumps to the `_start_rust()` function, defined in `arch/__arch_name__/cpu/boot.rs`. - `_start_rust()`: - Calls `kernel_init()`, which calls `panic!()`, which eventually halts core0 as well. -- The library now uses the [cortex-a] crate, which provides zero-overhead abstractions and wraps +- The library now uses the [aarch64-cpu] crate, which provides zero-overhead abstractions and wraps `unsafe` parts when dealing with the CPU's resources. - See it in action in `_arch/__arch_name__/cpu.rs`. [bss]: https://en.wikipedia.org/wiki/.bss -[cortex-a]: https://github.com/rust-embedded/cortex-a +[aarch64-cpu]: https://github.com/rust-embedded/aarch64-cpu ## Diff to previous ```diff @@ -47,7 +47,7 @@ diff -uNr 01_wait_forever/Cargo.toml 02_runtime_init/Cargo.toml + +# Platform specific dependencies +[target.'cfg(target_arch = "aarch64")'.dependencies] -+cortex-a = { version = "8.x.x" } ++aarch64-cpu = { version = "9.x.x" } diff -uNr 01_wait_forever/Makefile 02_runtime_init/Makefile --- 01_wait_forever/Makefile @@ -165,7 +165,7 @@ diff -uNr 01_wait_forever/src/_arch/aarch64/cpu.rs 02_runtime_init/src/_arch/aar +//! +//! crate::cpu::arch_cpu + -+use cortex_a::asm; ++use aarch64_cpu::asm; + +//-------------------------------------------------------------------------------------------------- +// Public Code diff --git a/02_runtime_init/src/_arch/aarch64/cpu.rs b/02_runtime_init/src/_arch/aarch64/cpu.rs index 3b52e3a3..7872f85f 100644 --- a/02_runtime_init/src/_arch/aarch64/cpu.rs +++ b/02_runtime_init/src/_arch/aarch64/cpu.rs @@ -11,7 +11,7 @@ //! //! crate::cpu::arch_cpu -use cortex_a::asm; +use aarch64_cpu::asm; //-------------------------------------------------------------------------------------------------- // Public Code diff --git a/03_hacky_hello_world/Cargo.lock b/03_hacky_hello_world/Cargo.lock index 6b68a92e..6e5873df 100644 --- a/03_hacky_hello_world/Cargo.lock +++ b/03_hacky_hello_world/Cargo.lock @@ -3,10 +3,10 @@ version = 3 [[package]] -name = "cortex-a" -version = "8.0.0" +name = "aarch64-cpu" +version = "9.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cd4524931a4e0ec50ae91f0d55f571f31ffe11dd9ce2f9905b8343c018c25bb" +checksum = "3aceb88e55ba626a5479279268d009a92d9d00eacce0de1b8c236c7ad31b7225" dependencies = [ "tock-registers", ] @@ -15,7 +15,7 @@ dependencies = [ name = "mingo" version = "0.3.0" dependencies = [ - "cortex-a", + "aarch64-cpu", ] [[package]] diff --git a/03_hacky_hello_world/Cargo.toml b/03_hacky_hello_world/Cargo.toml index e3e95003..a6d527c1 100644 --- a/03_hacky_hello_world/Cargo.toml +++ b/03_hacky_hello_world/Cargo.toml @@ -24,4 +24,4 @@ path = "src/main.rs" # Platform specific dependencies [target.'cfg(target_arch = "aarch64")'.dependencies] -cortex-a = { version = "8.x.x" } +aarch64-cpu = { version = "9.x.x" } diff --git a/03_hacky_hello_world/src/_arch/aarch64/cpu.rs b/03_hacky_hello_world/src/_arch/aarch64/cpu.rs index 3b52e3a3..7872f85f 100644 --- a/03_hacky_hello_world/src/_arch/aarch64/cpu.rs +++ b/03_hacky_hello_world/src/_arch/aarch64/cpu.rs @@ -11,7 +11,7 @@ //! //! crate::cpu::arch_cpu -use cortex_a::asm; +use aarch64_cpu::asm; //-------------------------------------------------------------------------------------------------- // Public Code diff --git a/04_safe_globals/Cargo.lock b/04_safe_globals/Cargo.lock index 21c1ad6f..3d196407 100644 --- a/04_safe_globals/Cargo.lock +++ b/04_safe_globals/Cargo.lock @@ -3,10 +3,10 @@ version = 3 [[package]] -name = "cortex-a" -version = "8.0.0" +name = "aarch64-cpu" +version = "9.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cd4524931a4e0ec50ae91f0d55f571f31ffe11dd9ce2f9905b8343c018c25bb" +checksum = "3aceb88e55ba626a5479279268d009a92d9d00eacce0de1b8c236c7ad31b7225" dependencies = [ "tock-registers", ] @@ -15,7 +15,7 @@ dependencies = [ name = "mingo" version = "0.4.0" dependencies = [ - "cortex-a", + "aarch64-cpu", ] [[package]] diff --git a/04_safe_globals/Cargo.toml b/04_safe_globals/Cargo.toml index 51ddd52b..1d8ee6a7 100644 --- a/04_safe_globals/Cargo.toml +++ b/04_safe_globals/Cargo.toml @@ -24,4 +24,4 @@ path = "src/main.rs" # Platform specific dependencies [target.'cfg(target_arch = "aarch64")'.dependencies] -cortex-a = { version = "8.x.x" } +aarch64-cpu = { version = "9.x.x" } diff --git a/04_safe_globals/src/_arch/aarch64/cpu.rs b/04_safe_globals/src/_arch/aarch64/cpu.rs index 3b52e3a3..7872f85f 100644 --- a/04_safe_globals/src/_arch/aarch64/cpu.rs +++ b/04_safe_globals/src/_arch/aarch64/cpu.rs @@ -11,7 +11,7 @@ //! //! crate::cpu::arch_cpu -use cortex_a::asm; +use aarch64_cpu::asm; //-------------------------------------------------------------------------------------------------- // Public Code diff --git a/05_drivers_gpio_uart/Cargo.lock b/05_drivers_gpio_uart/Cargo.lock index 93873c45..4514e882 100644 --- a/05_drivers_gpio_uart/Cargo.lock +++ b/05_drivers_gpio_uart/Cargo.lock @@ -3,10 +3,10 @@ version = 3 [[package]] -name = "cortex-a" -version = "8.0.0" +name = "aarch64-cpu" +version = "9.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cd4524931a4e0ec50ae91f0d55f571f31ffe11dd9ce2f9905b8343c018c25bb" +checksum = "3aceb88e55ba626a5479279268d009a92d9d00eacce0de1b8c236c7ad31b7225" dependencies = [ "tock-registers", ] @@ -15,7 +15,7 @@ dependencies = [ name = "mingo" version = "0.5.0" dependencies = [ - "cortex-a", + "aarch64-cpu", "tock-registers", ] diff --git a/05_drivers_gpio_uart/Cargo.toml b/05_drivers_gpio_uart/Cargo.toml index 1f6db5de..c431e438 100644 --- a/05_drivers_gpio_uart/Cargo.toml +++ b/05_drivers_gpio_uart/Cargo.toml @@ -27,4 +27,4 @@ tock-registers = { version = "0.8.x", default-features = false, features = ["reg # Platform specific dependencies [target.'cfg(target_arch = "aarch64")'.dependencies] -cortex-a = { version = "8.x.x" } +aarch64-cpu = { version = "9.x.x" } diff --git a/05_drivers_gpio_uart/README.md b/05_drivers_gpio_uart/README.md index f53a330b..563af1a7 100644 --- a/05_drivers_gpio_uart/README.md +++ b/05_drivers_gpio_uart/README.md @@ -181,7 +181,7 @@ diff -uNr 04_safe_globals/Cargo.toml 05_drivers_gpio_uart/Cargo.toml + # Platform specific dependencies [target.'cfg(target_arch = "aarch64")'.dependencies] - cortex-a = { version = "8.x.x" } + aarch64-cpu = { version = "9.x.x" } diff -uNr 04_safe_globals/Makefile 05_drivers_gpio_uart/Makefile --- 04_safe_globals/Makefile diff --git a/05_drivers_gpio_uart/src/_arch/aarch64/cpu.rs b/05_drivers_gpio_uart/src/_arch/aarch64/cpu.rs index 2ef860d2..2431d2d2 100644 --- a/05_drivers_gpio_uart/src/_arch/aarch64/cpu.rs +++ b/05_drivers_gpio_uart/src/_arch/aarch64/cpu.rs @@ -11,7 +11,7 @@ //! //! crate::cpu::arch_cpu -use cortex_a::asm; +use aarch64_cpu::asm; //-------------------------------------------------------------------------------------------------- // Public Code diff --git a/06_uart_chainloader/Cargo.lock b/06_uart_chainloader/Cargo.lock index c26c68d1..047875fe 100644 --- a/06_uart_chainloader/Cargo.lock +++ b/06_uart_chainloader/Cargo.lock @@ -3,10 +3,10 @@ version = 3 [[package]] -name = "cortex-a" -version = "8.0.0" +name = "aarch64-cpu" +version = "9.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cd4524931a4e0ec50ae91f0d55f571f31ffe11dd9ce2f9905b8343c018c25bb" +checksum = "3aceb88e55ba626a5479279268d009a92d9d00eacce0de1b8c236c7ad31b7225" dependencies = [ "tock-registers", ] @@ -15,7 +15,7 @@ dependencies = [ name = "mingo" version = "0.6.0" dependencies = [ - "cortex-a", + "aarch64-cpu", "tock-registers", ] diff --git a/06_uart_chainloader/Cargo.toml b/06_uart_chainloader/Cargo.toml index 8770d7a0..27b413a2 100644 --- a/06_uart_chainloader/Cargo.toml +++ b/06_uart_chainloader/Cargo.toml @@ -27,4 +27,4 @@ tock-registers = { version = "0.8.x", default-features = false, features = ["reg # Platform specific dependencies [target.'cfg(target_arch = "aarch64")'.dependencies] -cortex-a = { version = "8.x.x" } +aarch64-cpu = { version = "9.x.x" } diff --git a/06_uart_chainloader/demo_payload_rpi3.img b/06_uart_chainloader/demo_payload_rpi3.img index 20f13981c87fa20c518e3039149ff063beb0eb3d..8109de38e1ee46ee668b5b5fcaa068e973753192 100755 GIT binary patch literal 9496 zcmeHMdsI~So&Vms49pAt;EQ3Hm)(}jU>XID7TLDvWV3)u;{bwy_OXox zO&^Iv8ZYbiq1#oHbnBhemb7|K=xG};ZBJ918tZDhr+YSoIqd?YZN|{bxRKe<_ue~- zR8M=(_RqcN!0+Dg@ArNDzVF{}j+6fqrO89JCi?J^BSf zjh2xz@eNYTX`pf9ISN#z>v*GL^JVFg&;D}s`4_Gabf3R|{713t3`;&CTsVoflfYwo z6(-W<{cq4KBXvR~WpYKD%5#%%16Bw6E6nP8;7o~vlFX;XWSO8&m5J)FlgTf$j7d?r zFuRx%Hpn_53Xu)B)?KXmu{F*#tk=o@RvI;RIK#hu+wm`r=j`9O9v2;vbKm>b^{gdF z8((<(x7T+)bD*&+Yas9UkZJgb$9toqEmFVl+))SFWA(QhE;b5Ti)%k%+FJT}_TtjV zbGI&CpR>61!P4+`F*o9RU}^Y@kQXjXlLMtB2bQJFfx1H!C^N}{59QH?+Cd7e`w9i> z4pU(Ltz=Wf7fES;T8N*7T?(MrSlU1%e>+XowDJ9>t(q)Wx-hsed+{#FG`KH!>p^Gs z;%kuYl#m&Yi8+yq2P(pw&2nIiAP1(ztjM?H4*&4D!{6+r_!ZD)-PVs$?n$#|CiKG!7o?R>_pksyYck9#N zQ{U|t)SHi))R|^c{o_Z{)alJ;)lw;sw3`PSSDKDDvfeY_CHp&~DPk4mp=sEpMxdTQ zh!pvfaInN7Ea_!i-4Me^rUW`2NtY8&AwT?xV2y>~$0yT@d?&BS0Y^6VSPGAoILy>L znhrlUQ_mR2o3NiB`+4cZLG_Bbu;MLoQ6wrBMaIR#$PUOW3*_~~UjVC^-uxhBTnAa} zAafA1*Q&QZ{gactm*;ZigpOAbxgzFA?zgsu9G6GhgQ_KcppogOcz)k2k3_}d$PXav zxL6W7>7|jEuE5riL3%gC_wfu;E~ismg3RmlnOAW{01XmqF3ZUb?;D7{o8n^DaX|=c zcP48uuDw-z@qeKAmp&F$KMmL!@W2?4!mi~S4Q-zlDH=ZkjhBP#dIn~aP5NGnu@_w@ zrI2IvMux9^!QK00Tmt+Z=&@PMkF~(}=F;v*uc%t!XPO^c!Gxc27wGHR;9`?!^wY*}(*5_H3+{P0FIDN~Rs1AD$E z+AExb?c5Y%&MD-CU#?x((_*2fLEsT`O0$p|i)K*M?~pHED;)I?zlZX6%_hB@5L*lK zD9`a3vFB7F<-Ll%K5T_QpA~y9;QPhG6895;ZOWDdJilsniTj#0$F0#fV{I-eSD?Fx zt)yJbEpfkz_jqoB`{8VSi@6oZdyAMi%g`W<23DA6ydB`(zhCTm1$6tz#2%)<5jnvRUSGf6vXz6)N~cJy})h1 z*+0a5V)z?`pI(FRzZieh{|xjn2z|Y2@JnLsxD-Be%1Utod_%}-&Dh^)J~f3+ws5=2 zcJ5yCeF;4JfpY*dFi+k`K44vm{vrPUJ^l`XZyY|6cl}MjU>XhBZOG~Af@|>7;E|d% z!S(w~&m3{tbiP-GtZ=`O6XW;|n{vWk&=YA&p z=oYg)^s{VR*g5v0@at)G<^>C#?ia*3$3?qq@W|Vs(}6hJT=<#mG@ER?ki7u4Gbi$$ zTglV4Hd(F9t5q8hkn$U`G}3I!jeY&yhc5nBTpBr1R2%t?SQhySzDq}Gh~a08f{{wH zhsVWbk>`r)B0<1Q0p9{xY00&JI~L_@3-@@E(7yt-dsDmb|g*tG1kjm z+Vg7%>t+J=*&!^7MNtz{`^xkfIa~k)CsPm+_ zx3GRJ5ff@@XBr*80$3C|hh;aT=1p&2r)oV*o!+w~Mbm}ZGD^%eo1x2e)P)Syk~aEF zt_va5o1{pIWF{rXpEIfJQ70zfqCgaV=1KT*2(?Ddq|@ytIgyny(6|Eq)S^~WI^yz> zXJ6LQJ<#)qOZ8s%rGHD>&tlzKLd_}*s$&P5XDrwU*UEuR@=fH)BNILvnb;-=CctAS z>fhu-d1TT}BUA5{)t?~;HzVFpz#i6IYq$db*en#qI5ye8lFLb*dT+mK6X*>4i4%Uz ze-+rnlrh(S9~vzN4emAW#uK1R^xOyjVa5WU^nk2NkeAZQcR7gu;|j%ZTp^`4k!<=K z;O<-~Cw_`p3Spm_&_z4;&~Z&3Vm&On_V`5)biw*~c8(rS%+Uk#mT&agevK#VWz&k}@K<6J`Mzj)k<^Mj`6Z|Y~lsZ(U1EF00zgbaW6zmoRo3Y`7w^muFi7S4xH z;C#5;teqFvW1iQA_LDt{^Waojx_)j%9+)gM;mnw(J`5QooEh1+@O$JF6Z&OKr1w^G zkt78*Iww9)_Gb}OBK)ZZIf(FRa`KDuEX_dggWl3frZD%4h`W&*vc_zPS@b%J%}fcz zP*V(i+EMd2qCcCW86VDT72{%NBolGlSuBrqrj`5Rs81C*KZbKD@7O-EryhM8p9fc2 z#{JBu>`%lm;wUE+|{xJp5 z0{k-IyUTs8dX^$4osXw)tuU8VW!eWCH(-860lBBJCg!8SVqPc9JqNUPSz9Zti?wxG zSi5p%x|`Q>KIZjTu|D=b3giICx@4fyhBZu+*E+Z4xhvLXxl=gEpMj?s4>(tW6RV*B zXeb-d^YJ|g?<)-ZG@}M*!ag0a4|11gpR4Fm!m!US*e3@2#Gn&CQ)j_GPeT{G4Er>o zkNzg?^D^wyVc3Uz`j=s!U*NmTuulVeZJs{|`-EYie#1WX=;>25Uo-4ekA5`_`=sF6 zhJC&W`_!Y?$63GP_MBlKmg%)Q_JLiroW^;J?Zfqv>*6f#N4{>N!vfK8^es|Kqc~Gw z?)|g#Vld^2PC z9o^<<1ufQ<1N5xOZ%)RykfzH}a=AC955j(LzcZm!F1$@tPK+TZr9LgoWSo5k_PRjsl$b zaPGB;1C8h*hn-^u3eE<@mSvWsnHX_jaHw7=P&!((mBIZ^#deC+tZYh@Bc=%YV0`qA zi6G9pjAsR%`V$2T<29gn7!)cL%PQ+prp@%6C-RjJAxFt7h8|a$R44pzJ>r=CWj*2; zeRW`uK!=fEv^z_d(+U5yoXAmte`pFm)G@X|(PE*F>jkMydumOZc5mq%Ga(lWN~tW~ zb-(z^O}$oJG)C5A>PbFf<-q-Be;Rrky>DzO(e?f+eADtD zg2KHXub+Oyr1HHh?p&1?^o|oRm{q3B_oVeF%!(8EOltzPxSx}X$bU$7H08#&wF-SLh&vPHQ1pVjj|3B` zUKeqtM89BCS+06R-icpB)-v>XEE8m9xmm_`%=6x-3^}8Dg z*zUG{%y;u)U$Q))`zqTsx`+~N_mrQe?4I&Zrm6X8X@A#s0~D#{O6@ zSTx_9@0X*3zSi;{oiFEGO^#yydnfp#x2tfXf8%_~^k=xAc}`FsyQRl8;&@o#dM8^_ zXM(%)U!8bic5{{%*Vg?_fe=x3Gx+fDB`n`Ns2$e*1%VHN9_MD;%Ak|apqyK#)|i|d z7!DrzttD>RZ&4|A4Uza?hPhz zP9144EO1wtQU7luPXXrmXY>Q$gZdZeyF(j&rIF`sU)AAr=d}KT*JCbKgOYW~uh{$a zW{YNneB_&d!r7MjvYrc01QSoKfh}FCB z5U(jb8RvbC-=#ZvQ4^h+-n?F&eIL%Xup#U1N&Y<}gU~bOM_31_afc@0cTV^i*T85- zy5>LQxi}x?!>^X7>E|Qk{N%KgJrDizUqVL!ZKhE=;72{3M<E0dxs_Pcfcw#7 zSYM9cuUc^b*$>~!#2xrG^y|M9vm-AS%7O2oCqKVQ_P>rk{1{r~J9Ecl(+hy`hh{^{(#i|Bx4T!`v9~wW^_Zk1NV~iH_N)qZh4x6>TRS_qwQlcNEB(sAFE{XIhfWW7 zC)zWg{$W7TpO8+UiG^A_L;rY(%UVgp^DoiqpqJ8~KS%cTq}084kJSA!X`{2mn1`;)YAF;t*oqcRaRBHE2}F#mEKBUrN1)Z zs&u(rRW7%y+U0S1T|SrJ6{xDLa#dATxvQ$HJXPK*UzNWq;I4GL+*NM3yV~t>d)+>_ z-yNu~taepbRlBRJt3B1;YG1X#I^e1FxI9%Jx2M|U@pwHxkKYsUR(f6DDzDpH?e%!Q zUZ2ozm{suF&>Un{5k^5O90z9w>6HO%K-(hC16MU~KR1+`Fqwve|66 z<6(tCx5$VOU3)|g#&=5JO~&{A;ydMUMFzbT9XVfrJ7kRaTQ_RVzy4>|4IBO%HAcx; zKcCM@L*DsxUpL_QlVgiPx5XG!>r(qkjdHR6w#67XaN2I|>}_k^@hNFXcUPOChZMf? zNvZrK7wGtv#(2MVTa5YCc)xXaW1TdQ?tDI@Wrp1I=uQ}Lt~_l!q?X3EzP+7$)~?;# z^@-lr-Q~^}M2XbeCAAaNU9wPyaF4Otr4nTW2-t<_N UY8a5p({^JW*>$+Kc+S871rEAvc>n+a literal 7648 zcmeHLeQ;D&mOrmwC+Y5_LlP1UiJBJzLI;HOcQ-nlmjn<32ph8N?mC*pNSQAZlA!L^ ziU~57109r3v7;N@4a!!@YsJwKwv4m21f6wdfMGEUPSsA0olvWtGyywANekrd@4W7o zi1^3+zptwMzIQ*)$M2kb&OP@4dCrku?k&^NUlouLeodh20!ch4U!n|dcW{gTT0;Lb zI}Y7Y)jPEDX%+qCHxOmlV4jM8y3KP+Px~a2{yQ-=DAt@$ymPBo&{+e?(Nfa2tFvfe z1bi%aQr2SXt{StGf31+}vm|?5PVgxusr_}xXL%-hQ*lzBEiI$FYAxn1$tL@nyC@6u zy%*i&O{{Cwdt3{7oh-NObi6KYQ?W5$TW7}FdzU2JXRd7qt#Pcsc;8JLYjhsh9MCY{ z-CbqE8s^DsEgQ4!#VgY62^yo|?PHm-ejMvBmfoasf;{fZB=V;Ta&*sJd0>xzk^3Id zT%RO+mt;~_>2|UG?HtOoK*se(*;{&CY(I?e(>Zzedi1R^%U%n6)Cj3zW0D-TKxShSMY~~>HG=FNjh4EGVCSG%Pz<~I*_Ns(X!e6VeqC~R)pU`l zJe5TI1fq9>7sy}OJ>Nfqu~d=vP3Ox|%-7Z>d|+M*9bx-hNass|j7{KQO2)7W{24P7 z_){`fheaXKlr!jA$9ASE_n4SgJS?ULQh{j;WN!hc5y)1om%Tn<+7C=CJX$>$PM1NrhWR2521>F7snuP}PHv!i~e;WGFqkjwVEKDQ+ z81VdV?Av7;o-ETT;CU*J*9^aZ=eW>aMe+g-2iDz)xw|M=TgUGw)B<-Se95Hiu1ZaZ zf7f4y)=-9KBiv)TEI11{fPGzy<^1B@S4MK*|ESM zd_hoxMdS~?LCPY~4jm-#>GXMFem^lj{IjgL_IxqX`qFb%ZE4+E zUxDwt|9+rjLNo;`x1ZXt)1~^FGwE#QjkQBHy3DY=#+)zQuiI4kOnQFdGntztnw4L; zvd||jkbFh3XCcX6J=%)BnpLo1#98M-ZAvE9Ay}L zOfa4diiUumzP|^iXXQ;@ZxfVnpU^2&HKOv(LwaR$Ly}@Bkq4TRV0+kaiS9sEGi-Q8 z)CG)!+&c+7lnT`TwMcUbkhNU7-d3her>vS{A2~3uTp1R#10&+>!0qOVW;x1pYpLM80r4S5^CqtkT=KxL zA>Sbv4ZJ@>-j(28dp*VduaA~1o)q%urcgwNoS`f^8WiUQ1kfO%^t`O5xPFhlbxoWb zh(d=X=&(pF8?s={eK*R6qQLw8rgG(ed=G%ftDqBvEmzNGI=RqwZgGOn$DmVMv7-H& zxWBJZMCQ*e`*!#qsxHNQnUShf)8y!G-E7||=&#k&k&EyJj^lff zgDgVY$!5&62xi|!(Hy8n&gvIT;qDZw9_M|Acz$VGb)7~`Kej_`ub)<{k0DNf1l?Xl z9()OVYAPtt9t7KBFC8fr zW{3HFvb$;2QzHo0-{PJ19>WiNJDbOMsA}~X_}2&&>D2A&+o#*z*KikdoL-K0Jx7tp zz?au_=F^ce*d>g)Ex@5aNw8YZ?dn6$i!hBL(A#x4FpO;PT`Xju+@ebjAH>?OLW(q? zJ%+Xj?QXuF z=c}S^KIiK@Y@~<){*8!RHPAjNe}Hiiqif ztclM(f^N{8VM2^f7OXwzdiqNBg7xybm-?)x7_W;$ny*Vp5A*)?>C%0zz=P%Dxm~a$ za`Hx}F_-Flj?2CLJI+HZ$Wjzj`+tXJHJ!I}P&ge5!Y7(+={?P%J7Yd3j)8%T@k29e>wWMqOUx6Wnd@1wRf~UPe301 z6niHXv1+$D)7KV}CkXrJ7-YApJb`;*ASs$dQe z0{3-hvrhz$OrPVC`dN}mC_a1H1hgE(6w4~~kv*k?L|=tJ8s!2XEAfh_Pe%%7RhDi90H z70%sLHDyW>=dve$bEuXI&QGB)gf*OZjL0_zV3UhBBpL%bKP^}0;(Lxm9`GXXbc0VU zf5q}1$7{}Cv3MQh!StCn=hV;3SF}%wuk;PW-+pXPESE67oB0U)=SOLBo+?0|l5UaZ z);z^N9YTIA5OTvoz-6zS44%o=RMXeCd@|kgRgI)1ZF<13|<-mL2%*o7}KM(Q1Q=SZ$z+y0gU%$>6Hdy=nMED%*f4ecR=YtE&6~QPgixSx5>>2a> z2VnnIIFqbYri-|C)M+(S?A&tuF|J4BHOqijvuxLDmi7YFEXvCNuUY=on&q?W>dW7& z+p*s`MiI_^+@coR+kjfda(uC$G2Xq3GDeFAlu=dv3j5!0IqUHU7YoW*1!?2L1C$Zm zi8^#)lEU*B{So&_XivB)L+uikv7%&UHTK46kxm&!JQyv~E9)SGggYd*Cwv|;MThgO zAy9ooy+e}VJCNaZtSLNT@$>n%7IBE;59;8(KGb2x;Z@P%B-B+o+4kZj)X(2`R~gV( z@DHe`!5?=Wk>kiCCVHic$4vkD{eEp8`ZV1W#I;tAe#9{_!Ee5-j6hD#8N>=Shr{K4gnQ?c4Se%lq*`n|#unp`K zTBz4-Fc!Db=yJ9V>`^2rqqx5r#U0O=kc)Y%72?@x$a}rbfZEWAy=uaqO-0O3L;XN| zb2NEM{71{pe&&lfu-8(z%+EFpJw!1d0N>7eZvQush3|`k2l?zE_(Kl~N(1bAA*kRc}9H}I3ErXj;@ax$M2z|?TurTJLhJm_&DM&p~$bV>+un0<=*t3yeOrO@gR zse0`m3<={ zCt5?w6fn3F78Uh!k|w7YJi1fK{VHNE+dW&RjE6OT*@0`|*TDV(J}m#w=aHZDC2Gc) z{I}5k8s8z%9$iS${w`7`+me++rf(p31MU%+zR^V)Osg^>+rhYPfE(-iHDqM_i~&!^ zma)tL4csxf8O!f*th+sij2~ksV$GnQoQ)_sC>~d23TEUl>iu=Q6o2>L;eM>TFcY{5G{q_K>zQ7t-N*5LckqJX{}}RV{=O6bzQL^dwsFVP-bNxv4RGT7 zZwv5%Zv>1x+}`&w-+)+PT2gM&eBlk81(u1Hceo$8s4C7hxYr4($x28yD7AbBu~U@y zaOfa>AMcD`s0c9>`;=|5_=Kw2Vyr%9&(K2nb|=mNI|YBRUgsa#sq=$}5?ZE@?W_M$ z5sPu31UgJBtI+K~1Q{(moc@V7jLI&&hg6di+6fv@;7oNeRe9|OY)9lw=oAFa7vj3Z zmf1D;Q^bgx8?k+@!6;7{$>2jg!g+^KV+yEcWzV`CLVauuA4EK@B*V!in6nmjTR-M6 z!r8nQby*kUZ7S*uz6ZF3y5Zd%+50Qh<7d{(p8w*SAMeZV&b7ab`aB)&JLo&}lMH*- z-GBSu+t16MrDz}gv#sx4+FtwK(&uTaR4{};LJfmEGn`*3@El@h2Kxp0oP>PZeFJKU z#9Wqb2V^Nn?ab#tqoDH@XUiTFWG{%z&M|o_0X;mi|C?>MF4of>ACcqVZMGZgp6lR+rUn^;o^O5}Va#v)OG9o73j9xosYs*Ir_`+HH2b-C=jyU3RzKWA{2r z99DXZl~MjcDp@pucyRg_1HXikHh2ixIAu;$K&-vL@(HTLE4LDUUaSO=xFPJ zMhQG|CfA;X_FKi+TX(!o%u9?X+O4zW^WyC%as0OC#rg;1-><~K*&YvUT(e=}5~-!J zb+c4o*V3~2ajCXybLW#S+mWwNhKFRM#riLeN_2sk)XYH*4}GX&WpXl&iKw4;;f$Z`AOzE6ALgM{-tY5GeoZFP?~wmu;}-qHBf=8omk za;YIcA2~;RZnZzt-%{7u8YfQ&;`8C>+VgY#oAG3oZ5T1!8Pkhp=BH$-b7=`$>6ZS7t&d3MZEf3Fo3_^Fk|#dS`toxt z{fBLjNGmk0J2ezGKfWASB}5JJb=mxZN7A09(%yJ~a;%$v5&ur?iyzRpKO$8$)OB=9 zPj@tK+qM}ZX)8a8ufw@Rdw#Ia@rbmtzM+lvXl&j3qIL<#5_sbZ{M4RG# n5_b7%{QJlBtg7qW`q<`JvaO5l0%F(Pv20P{9Mj_?XzSLZm6U>ePWP+>9z97$S_fmvuqJmuzkBb5 zF@@7TXZ>^UIpKHj_xJn0AHVPKHyk4GSxS+Is!a5kR^p_Rlq4E5al&uoeDTzNFj1ly5vIZTb7(j6U<+rGc(@FCF@M^b&)q4{>9|SUUkc zMz737n!G1J0=*Ja#(4@&tVmJVob409szHB6s!{`-NuCR-xfGu$;grb|UiqD>{(#A- z^4!?$Vv3s~>p0Ja*UhXwQ~3)q#%QdIk>!IFYG|_sfAfj;hxMl{&t8i0*6^vH{l}%u zB~R5q_vlBLIv(Fs-E!(qv!t6XYu~$-Zyo&{)+V`PM#3 zzUuwttC>+7>K>y|oLCp_-u~JQ^kqFt(wn5qbNd89RUpnj$4P(8EzsVijplsAP%P9B#^C zGn$4tPNnXX7_Y#8Ug-1EH~q>5eqq@M{GxD#F9@IK^TXRAugsC#i+BO7Y-;0ekZ~mKW8KlqCJ>O2J(77~kLbD%+774OG&DWS5;Wcfjo18Zy9cJ#23?mz=%U-C z7;=nWPWP1F@I^ftE&={2?AXZXMw<|O$+UaZD8$xCs#>uljm9z|UyVki5H{9r#pWYZ z>7HrcTJ|#Zeg%3z16jsl2P;<;onC&h=n%eV?|K#S!6~2eeE2iO!4zVkQC`~(A2kf; zFuC$T)1>Khh{!F$zEc~kl-avp*L;+V_|Vrd|5U->)-dxMn{OiPxd`|tub;i=W%!zd z&rRUVD+1z7i$g(YNI4y|s(S-+>xLZ4 zu|B|eAI+znx1j4CBI5aVzIzPc&*v989|CMcmh5Bmt5z2|FNzDC8vRtP&8E-=*zOLI zLKm}(obTg3mYwIkBMaYrb{Xp4BF3A^P{)n>R+y&UZQ$MiAm9B4==PuFyBYoU;K^jE z1)o9iVZ4rR$lLrV_;1K3XNSRa6l-m;b0wD>eI0SOuXV!P$Z?K+c%Ot_c-Z2ks^UE_ z+{jU^*R=P*e$&1KzbvBTLW&&k-$Svjpuuc-rhtx5BA23A+YXx?OywN5vwIKJ!e$SG z#;c&UcL{}7#&!<{xx7;yri|z|CUY^xN-@5M@dGA zscXsieemc9&K}6Xcrrb50qczS53%n*;O`0WjUgs-F1_#NOrt)F88tnPa}1sxJW!d! zIsS0=@dFOC&i7+3GuY29h_d_*nid2*VG|}JTief>qs%7H%~YRJQt0?m*yIi_EBFp{ zc@1kWzIU*Q#b^ZjznePhV>%r@`{;p6$R{(Hm;}qB*dgTcyID!FY{V&pWhcS%Db@r# zznh-~E2P*cw&{cu_nFRy&7ayV*%z$Oj)||2Y3k^B&XE#}b*$-qr zwJB8|`c;-WXgm3h;OP`P@ti=%`#CJUDav znSF(|VeFMd671BTD#xwx+eLn5_$cOnQn)@mh`D{7IVizqZ6d>4q2UD!>%wiAYsDP1 z70Z*lnVK`TKcb;F{4sbGHmlv8@s#akZBW48whlDJi0rGxzBa+{Wxnl+0EV&qJjTnQ zkquhHGQX0jvr`+ZQOo=a+l!|gtCW%~)V_OuuGPNF`u?0JV$Tpzw-#X>=f!Y-lV2&s z_reN!#Aoasg0^?$qt-5*+dEiK@ILkq7Mp@r-`RXpeV?nxx(tjzp_@kkBWY7VFtKLDqD9Vix_VBr7K9DWkrt)p~C?wK0YDhS=vR z+& z->`ilfc-}0DXwNv{QMDzpE&`&LDrchf< z9&+u@e5wz2{${b>%f9rls^xX8d!4XnmH3sDdm5(&=)v~NfeiAD=g1@D9vT_nD*ML4 zV+Z!XiG}jWgp)=lZ?7Sc+%1WtW zYeN60_Yt?l-(N>RaGNq)!g^Sf*2C&O!?ov<&JrWqSz>p}W}GFut>|ed9{c~Z#Q)_i z5&K;ILGoFGkZY`#5c)4R?!fs$v-5NMnXv3AStd$Gv@;=tzx7|LC9(o%ziK_-4r4y@ z5YC6oQ?>JA4d&T8Wq>Ry&V!RBY5KVlbzq{zgfnA`atCCPaAst_MckvFn9wf^;hq_F zktF#wI_DoI%hSjy9`V$K8bo+BIoXTxEKNu6gWl3crXcGTk#{3z%?p4dF45O!FnXJEoC(@1)@C|w3=cRHSYHNSla=J#3%p4u zh1Q|xWA_|PuOR%B0spkYKd4)%tGa(aMvoGNe>&iwDEt$JP1u<_6aIM=w&*bY^Aq@| z4!v|6{PUXOAJ)_V8sDAp&ufN%>d| zPc8cV$KW5F^~>hw4F52h-bwNg{G!z~R=1dcW^pgV_DHrj9x~B>ru*S8pq}}h(GtN+p#m)~*gX4wOSO8e4jQrEMkCBW;!QLnnlRchF2J~o zMr=(Ou?F!IPQ=eudZqK|-QwZk8+MLhJ&ce-S}oA(Fn?8-4nvo!z*Sw$*U^Qkbd}$q z%Ac%XfRj7|Cyxm5ztu(E>!5!r_ehb5+GK+~qCj!mt-Vm?YrW){UukwXLs{?jcJZ`UGK>sNsvK*&3Zb zvWTlpS{)9o#CsvdYmm1rHfoT!rHHv2j(j^g+K+mo-%)~|06ZJwa2$OQqa*xLwM-!1 zCs6Yl4ujdYu>FKnCg$!Dd2MYo;Ow69->>LrYhtNYdrlX$_&_9YA-tgb( zGM~7l?>iIt9)FLNiT5}K{mQZ4t+}D5rLwkm?_ZIn6>`+!Z>j`$4E?w_`zh|tve5%t z(R+TN-?_+($;D(H-%Oj{LM*bo)v5PPN`lT?e@&LjBf!6f^uEtY@mkPK&|!2Fv?2xM zO2%V-;>2^h&cD4Id*pJ8PpP^L2^@J5xtP7ic|8`GEDP^cE%Yej0PlCnWRcMSX>k(r z#}oZ+UNyf3?}Pk=sb}m>p(8K#(CY(3EuS2 z{`efPAANbeBnx`+`MiFd#7p_|c#URWgV*y(yiR<1yqd&o@OmYQ*U2xB7kZm7*pT^J zxJf_jL>5t8ivh$!BL2i0#4Tdse-pRx`CQyGyhPkyD_%!AeXVe#&YQ(3`_tqp)M4oJ z%Cv9ed=O{7%@HoNeMZlBmg8zQKQ_BD6ZeI5OynBSdr(Cq=&;{MK1H8sL)?m7p6^cJ zh&Z1jt`$-8+t63q*x7Rf;Eb)2LtD(6=H-+3z1(zBT8Ds93Kjq969$277Ly_&&%s z*+}uQky{gW=zUdDIbUtk?s1!lTnSwwfZd#=ccQ)}=!;dlOy;$yy*9%BqwnFGT>}0% z&ZHwj>?N)FdCsy_8W8{!DO@jp_{IGmbdS-X5aNt}B0(p?Ppw8hg^i{*3Yu=Ys4xGB zvn%71hr05Jb~l_GW@kiMpc9&W|KyMFz}Z@ZnRQq$YQ!8KYD6;LK$?Mf_$uCjK`R&e zK8J^VPsSU?9hS!L=vBN?gH|qbcMcD^n~X=ifj4p$5Br}+D;Ie*9o<`68YrNmGq`>(+dh`Vtj{)}Xtrlm_lJCCwZx74f)fn&i z+Rhh$zq{$h)eqBjC5L+j{2rG986jI3XOa^ZyfZ$hARprcyy?VRCfkFM#g98_cE2NX zreIl~>@`Dnt06n{QE$(-TekNEzTMKZx~CVx{^X7DES@awU!rc~{kEQ-t{!RouAV^W zJ(7+f?dGT<~Ky!QG z@2+xLBWZZj5}giuDDC-kbn#mN;m(O9?O82-*T7HH(dhx>J0aKCmg@8o1KJbl+}`qC zscToC)b%ZCYuB#M?Y(QHz8x)6drPMj=#`|cm}1}hLO^u9V+LL0lTI7oIr=mmLZ_en zB=|jJzzub28i(QJXTH96yWL?gw>#|>c9-34_t?F5pTq8OILaMPM}@=Xa63E>uftbv zFL#uempjWV%3bB|a!4A9nNy6(^=tkIo(c=)9dtA*ee_rgW??e@66ZlA~Qad^r-PEUo$<#BsF z9vhr-gGRrL+^&AmIfw)FJeD{Tr$71xL*|K?4JsO{agwfElMzLpNn)a{Z^ z&t@2#hB?(#68|dnk@O|1?hxgr>O(bc&|l8t%P0PUGie@pq@(poLA zd!_cS=It%p*Wd^QI~#cTEnj=KIPaFKcQp6(O5f=T^!2rXv<83DSch|g_WTL`io2!T zw(aO*@&r0}A{jcnz5@=Y4ZMX0UR_I1XG^=Zv$->{t=Med#6}3Tt+@||TVvMK^Xq~3 z7HK(i>Ft}=ZCt)mY7ca_NGqjnUG2L%IwiB&JeLnE47w|fd`-lO)A&x<`>V$H_3}Fr zZv_Uu1RXh7e|y3hueWa0m_Pkz)*UnAHDZjCv3@?ECk%P#(|yT+Ur&xr2HhrOOsq@j zlNb*b>2Jr3aUCn$&Fwuc&D-ylws&>57D|@dw`R?*&hPXz?<}=7Axos@PN@mSph^06 zbNen`!|Tb@VAL6w|2whC^%(_Vc$v;0|EEBg7ys(HD$O!LqE1g6^5C?o!L`Ln|NIY5 Ctze}9 literal 7584 zcmeHLdvH``mOr;|9^IV>oseKil-v+B>G10J1D(xH0tx|y4Vl#~A4$ZN=_Dj1L7l0E zNszTh=%93pTCFfUplp@iR-ADRTgKU1g3ipY3k-u9aH?i%?1UZdq=axuqiH1*Y0S zP2RP$*7;IAt}Stq*>{7+1<;6Ktw!T+^0v*Qu}0@{ z%>xa?g1)-1*Kf?VPhd?ZXf0luXz_sA1M;|QQz?)s$g#ci<>9?4 z6u1}S{Z{|~OnuOWbYAtpUN+^R~{F;HluG%mh3g7Pgz=M-)+dY zS5~d;3W-!-oAV9Li$b|O2Q+I96nH+T&^{q%S0wpmVa&*5SrpitlZUaaugCUMxr^<| za-C9_yLSsTY)F-3X2@$urC5WI5$S_X)(En9B39`dg`GoUaRuxaU|Xu9pxJMxR8$~S zK$q56*PKfGnP$llnL_6&FpmBVk@n9N!Oo(ftxNjA!gLy9`)u) zm1Kxe8r4TcA=sKf;#tQwr)l@3m{~CO&> zbUiRV2uy2$X+>syP7s*30@DUyI)eTZ6J$-$JPF+X1ezs!3bX>#WPc|5&vAby1-1as zN#ObQ*wy74o-ETz;CV8ESJLkpm(UwzIxh6paUbh$z}($bpsnNoAE?FdVk-?7ucBce z{K#-8Y@$PJMw<;^Z^ZwlzzK6;i{Kburd14Dz%@^OpZ65~+<;dvEDxA>E((NxEGVH; z3WQ%Jr5rTFhspbE*o5~cua%A-_%QTeN3MiY{(MFH)3qzy$F`j*qL>kM!@z&djg_O7 zzcxf!hcybB-cOb@cxgS9(O9?kL|&6sB;2FhRI)w0sAPN2CW+=0m8>f9 zOLt2CQrNPDWN!-EntkLY{IBXK@5-0REAJ<7%MG=@?O!R-uvdt_20xt({Ua%Tb^L9B zJ=c9tw`mLHXfx26{vBCGTOd#Wj+{+<%vnVjA=eSamx?g|Wv3 z!-J0)uSEagq(DQ#H0&i|uKyneL&S$z*^*M=er;U# z7H3hHKL220aVm8;Vn3nn+KKiWZ03SKAu%6*G_PV@ye;@R zJTTZet=7-Rq6G4ce3kBAJtw&?t}Cx4^nVWCz2e+RBYbT(?VdCW@El219W7~eCKK|7 zv*S7>@#68&RJwZ_@$_Bj|4ZoqZ;&M{76priqR4dF!NNoMo|&^?dTN89un$bZ?v?V& zE(x~n1NQnH?0L{RMC6iSuc-}en`+HAbKws>XAHI(hnzeXw@0;R502xr=g&OxAF#0i zTkGJ5qQbFB^EJAkx;l0j)mP$wm4WIrGUeDF-CX|!=&wzop$qT@j^lfg zhs;9ei8jnL3t9dPVpgybIqRTcjP#{b{YBnqi07APRM#oQ^kX}b>t@vYV~Ef1L$~LV z2VcOR+K1ftTg39q{I1X2bQ&>y&OEaJ3^7|p%$8EAelPOiUx3qIKqa3my&N!L%E|V;9=j!Q&0^I07DRpx@6gc(jAZ8~J2k2ObB(gJ4_irJ+h; zZiLS#ds-(v4T50(AN*&%C-Gu$=kfSXRjr={{|14gJ-Xe4`*nK;Tkb%POOa!}&rtL+ z@Z~ibfIiYZs`u-R{#Kpw#I591z=Qb}pzVnD4)FiWc=v%b&H@+sN~Y)|LU>YGo|5y?MfN3$RD4_4&bzILrKf z{*MOQ1mg+Yl^vs>f$oPl)S&?(*FT26vM^It7UfkbC4Ch5L|hnb&T)%JhQ?WGo zUO{#66LC@SQ+!vC&;a+JFQ^G_B$Iz!yfgT#f|bF|=&wfqR`gXDtP1YJxAq?`&l8YG zKg8b2K&;x6mE-S>%2x>c=NM$nfo^YE1A~`wCbM?mvFT#8cfdODpWt)wDIv#yiQ5vk zcUExV*xHS0N8~2T#n!i4H4 zSdDY7J~-V_rId0md*WBGHB#}pY4nA$hVzaA`9=?H3ebi{Loom0YGppY=Q-qIFY-%#mH0A zO|smar`V^%$dAQBK_rCyGqvHb<>RxUpqDjVdS+1fNwT5?HZpKgYvO0dsSPPg7`cjT z0{ceBR3GHp;87jz=XxN7*vGO1zx`7iRw`O;P!q2WR8e?(Wi`j z$hnBm!>ULzHG^Vfhjq$onq!?YfHuze_#+_2ej*iFOX$7F99JX&xD znV2UJqxKt~yh~R2yw!l%^D^vY%rW?DQMWVzH;xmW6DG?@nY^o4sSxNWpG(abw~rcp zzG*Y+iwfwG9N+UDbQ%+M*vI~QtpH3ZF!9Wz(|YixJ7q;;ze*$bxoQd=9jEA5;}j5L zYW?k4-!e~*=@CESr)PZ7xfQzTFUkXXz{3eVzJe_nmse)t@$xJ@`b2V%ywa=j)bPRg zS7{VI3SP{w3VWD+X9{|^02_Typ8ufE5Ybx?4vO$O*8f&xT+fHfsujT?E9FV-arTV+ z{e7_iy*QJsQf5lIcGPLLWBlB5>#a*M?(97lT2!_s7#ioDXXzJCQ5b61meL&X^OHAGDxUX*`Dxu#1tLQv-)8D z4fQrjg6}|vSFon!PkNOP zVNIXJe07(2W@bYc&c0Z;^C_>7$k71#_V&d0=x089?noEo`~}pD+A`6 zb%F6+x_~mHz6e>INu5IIdjT>tz6l8S(UQdhA#p!3`+kAPwb*<&@jb&nl3an`T~l8q z#5dOE5NtaIS|OsNub}1HiRtp#e_P1Jy0h&1s)~RCu_lyG3LzGj<4wk0)-{x#rul|4 zpY_%9h^A{RbY=b7KPF2BMeT);i0mVxHh&D`p&HyvL8hcWY7OiOd9QcsQM(!tON@vq z8OSM_+M3mO$L~46KM%AYAg!+jec=ZL1u<)1&q7z=^V{M$mV3zL18)f4Mx4lO|JdT$ZW=GF^jwsN0Zhkom`PnV#ONnx-2_xe6Vw0t2T1Ll@-yR8(4c9m{z+ZUf{- zO_s5|Z{*AYkG>3YA3#oc81t`#57YQPunQr_w6K4Gm&OD1;s1efl6D!zdV5JhjT@Ni ziR&TclIe@{kPk0o8oL4ddUChmp5qJ1nY7JrJDF-(zE=@LZh__TIp7bSm_`^ha0i0g zJuX`d)-sk~+ckk!hx=g1;~W_nU1tS?S06_B7J&F8c+^-G=pTs8N@kx;MsSOF%0V zbk@zp?-Thy-zQ!|9OAph{+TlEzL4+ZL+6FSPubV7*PvezwWfA98{)GWYWM?)lZcUd z4fjwKce?e6%WL%p`HF$`e(Y78RS5N=fI3w6tjj0VwuZ=IoT+O`e_{#dtVPXr5cA7% zu5Lt4)r&Jv25JMY;V2{RL|2)9Yo=@3>ya|K$q`>~EpA&PMxl^qu~m$)3C5 z2XDXmtn68a_Wr-y`u3$Ajc+e|mZmEOedK-AAGq(r*^`3LAfA{QGw?Y9`Lw$Nod1(^ zS+<>!r5bfFpWO_C&R>xydyJ61I3as7rf(%g96a&gZ`wXxyr(ZQA}7A9Yt~B}*IBGq z>HAf6^+YKt$(0%zgu3{nPxOxzeS7>|;u~in?Xg%aR*TJIw>T_Li_7A+cr0Ek$Xjhz zyVYTJT3uGR)noPAEH;dDA(PPfzJ^tvoAtIOuHyBsd3%jI&rJT9->;n-zp~XOti^)$?;@s;tYUCO0>`25&yOn#@oKc_k)S=wawif&F#|GrViic5~Fb= zw^DoO=B91F&W;sENqg?~wKq#;Y`Xh4uGvtwL~8eSG)qgQ&7JK}Zt0MWD9R5d=q=W` z6OAUmlXCqr@r^yLJ^!2dPTFzl?eUpO``0z~Y<;Y`yZeXIMxW%^+|=IQ{J7Lu*WB}D z`?eJ;p6qzKyJ>5=xl!uukeWKAM!?r7J=N6yWOIUk5}(B9*M2pU8|Ty0y?Oc8ZePc? zW!*hI=cR;S;T}|K&(#8Y)s5!nfb9S zb1t)>{lQKB4_P0PsyjQku{JQUv@bEv`tox#{fBIiNGmn1do&c9A723}iAECZ^7sQ! z+)gaqLl0BGMm$VBco6!iE5^aKBviUzY{f%Y- diff --git a/06_uart_chainloader/src/_arch/aarch64/cpu.rs b/06_uart_chainloader/src/_arch/aarch64/cpu.rs index 2ef860d2..2431d2d2 100644 --- a/06_uart_chainloader/src/_arch/aarch64/cpu.rs +++ b/06_uart_chainloader/src/_arch/aarch64/cpu.rs @@ -11,7 +11,7 @@ //! //! crate::cpu::arch_cpu -use cortex_a::asm; +use aarch64_cpu::asm; //-------------------------------------------------------------------------------------------------- // Public Code diff --git a/07_timestamps/Cargo.lock b/07_timestamps/Cargo.lock index 5155fff2..be8e7c13 100644 --- a/07_timestamps/Cargo.lock +++ b/07_timestamps/Cargo.lock @@ -3,10 +3,10 @@ version = 3 [[package]] -name = "cortex-a" -version = "8.0.0" +name = "aarch64-cpu" +version = "9.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cd4524931a4e0ec50ae91f0d55f571f31ffe11dd9ce2f9905b8343c018c25bb" +checksum = "3aceb88e55ba626a5479279268d009a92d9d00eacce0de1b8c236c7ad31b7225" dependencies = [ "tock-registers", ] @@ -15,7 +15,7 @@ dependencies = [ name = "mingo" version = "0.7.0" dependencies = [ - "cortex-a", + "aarch64-cpu", "tock-registers", ] diff --git a/07_timestamps/Cargo.toml b/07_timestamps/Cargo.toml index 5997997a..f4e4bcf6 100644 --- a/07_timestamps/Cargo.toml +++ b/07_timestamps/Cargo.toml @@ -27,4 +27,4 @@ tock-registers = { version = "0.8.x", default-features = false, features = ["reg # Platform specific dependencies [target.'cfg(target_arch = "aarch64")'.dependencies] -cortex-a = { version = "8.x.x" } +aarch64-cpu = { version = "9.x.x" } diff --git a/07_timestamps/README.md b/07_timestamps/README.md index 236def5b..afa75ad9 100644 --- a/07_timestamps/README.md +++ b/07_timestamps/README.md @@ -272,12 +272,12 @@ diff -uNr 06_uart_chainloader/src/_arch/aarch64/time.rs 07_timestamps/src/_arch/ +//! crate::time::arch_time + +use crate::warn; ++use aarch64_cpu::{asm::barrier, registers::*}; +use core::{ + num::{NonZeroU128, NonZeroU32, NonZeroU64}, + ops::{Add, Div}, + time::Duration, +}; -+use cortex_a::{asm::barrier, registers::*}; +use tock_registers::interfaces::Readable; + +//-------------------------------------------------------------------------------------------------- diff --git a/07_timestamps/src/_arch/aarch64/cpu.rs b/07_timestamps/src/_arch/aarch64/cpu.rs index 4414ac6a..bbe7687a 100644 --- a/07_timestamps/src/_arch/aarch64/cpu.rs +++ b/07_timestamps/src/_arch/aarch64/cpu.rs @@ -11,7 +11,7 @@ //! //! crate::cpu::arch_cpu -use cortex_a::asm; +use aarch64_cpu::asm; //-------------------------------------------------------------------------------------------------- // Public Code diff --git a/07_timestamps/src/_arch/aarch64/time.rs b/07_timestamps/src/_arch/aarch64/time.rs index 1e2efbec..94d02379 100644 --- a/07_timestamps/src/_arch/aarch64/time.rs +++ b/07_timestamps/src/_arch/aarch64/time.rs @@ -12,12 +12,12 @@ //! crate::time::arch_time use crate::warn; +use aarch64_cpu::{asm::barrier, registers::*}; use core::{ num::{NonZeroU128, NonZeroU32, NonZeroU64}, ops::{Add, Div}, time::Duration, }; -use cortex_a::{asm::barrier, registers::*}; use tock_registers::interfaces::Readable; //-------------------------------------------------------------------------------------------------- diff --git a/08_hw_debug_JTAG/Cargo.lock b/08_hw_debug_JTAG/Cargo.lock index bcfb442a..9020b4f9 100644 --- a/08_hw_debug_JTAG/Cargo.lock +++ b/08_hw_debug_JTAG/Cargo.lock @@ -3,10 +3,10 @@ version = 3 [[package]] -name = "cortex-a" -version = "8.0.0" +name = "aarch64-cpu" +version = "9.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cd4524931a4e0ec50ae91f0d55f571f31ffe11dd9ce2f9905b8343c018c25bb" +checksum = "3aceb88e55ba626a5479279268d009a92d9d00eacce0de1b8c236c7ad31b7225" dependencies = [ "tock-registers", ] @@ -15,7 +15,7 @@ dependencies = [ name = "mingo" version = "0.8.0" dependencies = [ - "cortex-a", + "aarch64-cpu", "tock-registers", ] diff --git a/08_hw_debug_JTAG/Cargo.toml b/08_hw_debug_JTAG/Cargo.toml index 55963c38..e310c371 100644 --- a/08_hw_debug_JTAG/Cargo.toml +++ b/08_hw_debug_JTAG/Cargo.toml @@ -27,4 +27,4 @@ tock-registers = { version = "0.8.x", default-features = false, features = ["reg # Platform specific dependencies [target.'cfg(target_arch = "aarch64")'.dependencies] -cortex-a = { version = "8.x.x" } +aarch64-cpu = { version = "9.x.x" } diff --git a/08_hw_debug_JTAG/src/_arch/aarch64/cpu.rs b/08_hw_debug_JTAG/src/_arch/aarch64/cpu.rs index 4414ac6a..bbe7687a 100644 --- a/08_hw_debug_JTAG/src/_arch/aarch64/cpu.rs +++ b/08_hw_debug_JTAG/src/_arch/aarch64/cpu.rs @@ -11,7 +11,7 @@ //! //! crate::cpu::arch_cpu -use cortex_a::asm; +use aarch64_cpu::asm; //-------------------------------------------------------------------------------------------------- // Public Code diff --git a/08_hw_debug_JTAG/src/_arch/aarch64/time.rs b/08_hw_debug_JTAG/src/_arch/aarch64/time.rs index 1e2efbec..94d02379 100644 --- a/08_hw_debug_JTAG/src/_arch/aarch64/time.rs +++ b/08_hw_debug_JTAG/src/_arch/aarch64/time.rs @@ -12,12 +12,12 @@ //! crate::time::arch_time use crate::warn; +use aarch64_cpu::{asm::barrier, registers::*}; use core::{ num::{NonZeroU128, NonZeroU32, NonZeroU64}, ops::{Add, Div}, time::Duration, }; -use cortex_a::{asm::barrier, registers::*}; use tock_registers::interfaces::Readable; //-------------------------------------------------------------------------------------------------- diff --git a/09_privilege_level/Cargo.lock b/09_privilege_level/Cargo.lock index 29c6ef54..12b21042 100644 --- a/09_privilege_level/Cargo.lock +++ b/09_privilege_level/Cargo.lock @@ -3,10 +3,10 @@ version = 3 [[package]] -name = "cortex-a" -version = "8.0.0" +name = "aarch64-cpu" +version = "9.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cd4524931a4e0ec50ae91f0d55f571f31ffe11dd9ce2f9905b8343c018c25bb" +checksum = "3aceb88e55ba626a5479279268d009a92d9d00eacce0de1b8c236c7ad31b7225" dependencies = [ "tock-registers", ] @@ -15,7 +15,7 @@ dependencies = [ name = "mingo" version = "0.9.0" dependencies = [ - "cortex-a", + "aarch64-cpu", "tock-registers", ] diff --git a/09_privilege_level/Cargo.toml b/09_privilege_level/Cargo.toml index a89435bc..480508b5 100644 --- a/09_privilege_level/Cargo.toml +++ b/09_privilege_level/Cargo.toml @@ -27,4 +27,4 @@ tock-registers = { version = "0.8.x", default-features = false, features = ["reg # Platform specific dependencies [target.'cfg(target_arch = "aarch64")'.dependencies] -cortex-a = { version = "8.x.x" } +aarch64-cpu = { version = "9.x.x" } diff --git a/09_privilege_level/README.md b/09_privilege_level/README.md index 5710fdb8..e0f73b63 100644 --- a/09_privilege_level/README.md +++ b/09_privilege_level/README.md @@ -75,7 +75,7 @@ We are already using them since [tutorial 07](../07_timestamps/), so of course w Therefore we set the respective flags in the [Counter-timer Hypervisor Control register] and additionally set the virtual offset to zero so that we get the real physical value everytime: -[Counter-timer Hypervisor Control register]: https://docs.rs/cortex-a/5.1.2/src/cortex_a/regs/cnthctl_el2.rs.html +[Counter-timer Hypervisor Control register]: https://docs.rs/aarch64-cpu/9.0.0/src/aarch64_cpu/registers/cnthctl_el2.rs.html ```rust // Enable timer counter registers for EL1. @@ -88,7 +88,7 @@ CNTVOFF_EL2.set(0); Next, we configure the [Hypervisor Configuration Register] such that `EL1` runs in `AArch64` mode, and not in `AArch32`, which would also be possible. -[Hypervisor Configuration Register]: https://docs.rs/cortex-a/5.1.2/src/cortex_a/regs/hcr_el2.rs.html +[Hypervisor Configuration Register]: https://docs.rs/aarch64-cpu/9.0.0/src/aarch64_cpu/registers/hcr_el2.rs.html ```rust // Set EL1 execution state to AArch64. @@ -100,7 +100,7 @@ HCR_EL2.write(HCR_EL2::RW::EL1IsAarch64); There is actually only one way to transition from a higher EL to a lower EL, which is by way of executing the [ERET] instruction. -[ERET]: https://docs.rs/cortex-a/5.1.2/src/cortex_a/asm.rs.html#87-96 +[ERET]: https://docs.rs/aarch64-cpu/9.0.0/src/aarch64_cpu/asm.rs.html#92-101 This instruction will copy the contents of the [Saved Program Status Register - EL2] to `Current Program Status Register - EL1` and jump to the instruction address that is stored in the [Exception @@ -109,8 +109,8 @@ Link Register - EL2]. This is basically the reverse of what is happening when an exception is taken. You'll learn about that in an upcoming tutorial. -[Saved Program Status Register - EL2]: https://docs.rs/cortex-a/5.1.2/src/cortex_a/regs/spsr_el2.rs.html -[Exception Link Register - EL2]: https://docs.rs/cortex-a/5.1.2/src/cortex_a/regs/elr_el2.rs.html +[Saved Program Status Register - EL2]: https://docs.rs/aarch64-cpu/9.0.0/src/aarch64_cpu/registers/spsr_el2.rs.html +[Exception Link Register - EL2]: https://docs.rs/aarch64-cpu/9.0.0/src/aarch64_cpu/registers/elr_el2.rs.html ```rust // Set up a simulated exception return. @@ -212,11 +212,12 @@ diff -uNr 08_hw_debug_JTAG/Cargo.toml 09_privilege_level/Cargo.toml diff -uNr 08_hw_debug_JTAG/src/_arch/aarch64/cpu/boot.rs 09_privilege_level/src/_arch/aarch64/cpu/boot.rs --- 08_hw_debug_JTAG/src/_arch/aarch64/cpu/boot.rs +++ 09_privilege_level/src/_arch/aarch64/cpu/boot.rs -@@ -12,21 +12,72 @@ +@@ -11,22 +11,73 @@ + //! //! crate::cpu::boot::arch_boot ++use aarch64_cpu::{asm, registers::*}; use core::arch::global_asm; -+use cortex_a::{asm, registers::*}; +use tock_registers::interfaces::Writeable; // Assembly counterpart to this file. @@ -348,7 +349,7 @@ diff -uNr 08_hw_debug_JTAG/src/_arch/aarch64/exception/asynchronous.rs 09_privil +//! +//! crate::exception::asynchronous::arch_asynchronous + -+use cortex_a::registers::*; ++use aarch64_cpu::registers::*; +use tock_registers::interfaces::Readable; + +//-------------------------------------------------------------------------------------------------- @@ -435,7 +436,7 @@ diff -uNr 08_hw_debug_JTAG/src/_arch/aarch64/exception.rs 09_privilege_level/src +//! +//! crate::exception::arch_exception + -+use cortex_a::registers::*; ++use aarch64_cpu::registers::*; +use tock_registers::interfaces::Readable; + +//-------------------------------------------------------------------------------------------------- diff --git a/09_privilege_level/src/_arch/aarch64/cpu.rs b/09_privilege_level/src/_arch/aarch64/cpu.rs index 4414ac6a..bbe7687a 100644 --- a/09_privilege_level/src/_arch/aarch64/cpu.rs +++ b/09_privilege_level/src/_arch/aarch64/cpu.rs @@ -11,7 +11,7 @@ //! //! crate::cpu::arch_cpu -use cortex_a::asm; +use aarch64_cpu::asm; //-------------------------------------------------------------------------------------------------- // Public Code diff --git a/09_privilege_level/src/_arch/aarch64/cpu/boot.rs b/09_privilege_level/src/_arch/aarch64/cpu/boot.rs index 0bf45b83..b458f0db 100644 --- a/09_privilege_level/src/_arch/aarch64/cpu/boot.rs +++ b/09_privilege_level/src/_arch/aarch64/cpu/boot.rs @@ -11,8 +11,8 @@ //! //! crate::cpu::boot::arch_boot +use aarch64_cpu::{asm, registers::*}; use core::arch::global_asm; -use cortex_a::{asm, registers::*}; use tock_registers::interfaces::Writeable; // Assembly counterpart to this file. diff --git a/09_privilege_level/src/_arch/aarch64/exception.rs b/09_privilege_level/src/_arch/aarch64/exception.rs index c8eac4f0..c2b7cea8 100644 --- a/09_privilege_level/src/_arch/aarch64/exception.rs +++ b/09_privilege_level/src/_arch/aarch64/exception.rs @@ -11,7 +11,7 @@ //! //! crate::exception::arch_exception -use cortex_a::registers::*; +use aarch64_cpu::registers::*; use tock_registers::interfaces::Readable; //-------------------------------------------------------------------------------------------------- diff --git a/09_privilege_level/src/_arch/aarch64/exception/asynchronous.rs b/09_privilege_level/src/_arch/aarch64/exception/asynchronous.rs index e3e3672e..0347dc3f 100644 --- a/09_privilege_level/src/_arch/aarch64/exception/asynchronous.rs +++ b/09_privilege_level/src/_arch/aarch64/exception/asynchronous.rs @@ -11,7 +11,7 @@ //! //! crate::exception::asynchronous::arch_asynchronous -use cortex_a::registers::*; +use aarch64_cpu::registers::*; use tock_registers::interfaces::Readable; //-------------------------------------------------------------------------------------------------- diff --git a/09_privilege_level/src/_arch/aarch64/time.rs b/09_privilege_level/src/_arch/aarch64/time.rs index 1e2efbec..94d02379 100644 --- a/09_privilege_level/src/_arch/aarch64/time.rs +++ b/09_privilege_level/src/_arch/aarch64/time.rs @@ -12,12 +12,12 @@ //! crate::time::arch_time use crate::warn; +use aarch64_cpu::{asm::barrier, registers::*}; use core::{ num::{NonZeroU128, NonZeroU32, NonZeroU64}, ops::{Add, Div}, time::Duration, }; -use cortex_a::{asm::barrier, registers::*}; use tock_registers::interfaces::Readable; //-------------------------------------------------------------------------------------------------- diff --git a/10_virtual_mem_part1_identity_mapping/Cargo.lock b/10_virtual_mem_part1_identity_mapping/Cargo.lock index 4bfff935..af2a0a5d 100644 --- a/10_virtual_mem_part1_identity_mapping/Cargo.lock +++ b/10_virtual_mem_part1_identity_mapping/Cargo.lock @@ -3,10 +3,10 @@ version = 3 [[package]] -name = "cortex-a" -version = "8.0.0" +name = "aarch64-cpu" +version = "9.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cd4524931a4e0ec50ae91f0d55f571f31ffe11dd9ce2f9905b8343c018c25bb" +checksum = "3aceb88e55ba626a5479279268d009a92d9d00eacce0de1b8c236c7ad31b7225" dependencies = [ "tock-registers", ] @@ -15,7 +15,7 @@ dependencies = [ name = "mingo" version = "0.10.0" dependencies = [ - "cortex-a", + "aarch64-cpu", "tock-registers", ] diff --git a/10_virtual_mem_part1_identity_mapping/Cargo.toml b/10_virtual_mem_part1_identity_mapping/Cargo.toml index d3e2582d..6f12f98e 100644 --- a/10_virtual_mem_part1_identity_mapping/Cargo.toml +++ b/10_virtual_mem_part1_identity_mapping/Cargo.toml @@ -27,4 +27,4 @@ tock-registers = { version = "0.8.x", default-features = false, features = ["reg # Platform specific dependencies [target.'cfg(target_arch = "aarch64")'.dependencies] -cortex-a = { version = "8.x.x" } +aarch64-cpu = { version = "9.x.x" } diff --git a/10_virtual_mem_part1_identity_mapping/README.md b/10_virtual_mem_part1_identity_mapping/README.md index 946500dc..36c37c79 100644 --- a/10_virtual_mem_part1_identity_mapping/README.md +++ b/10_virtual_mem_part1_identity_mapping/README.md @@ -218,9 +218,9 @@ self.configure_translation_control(); Finally, the `MMU` is turned on through the [System Control Register - EL1]. The last step also enables caching for data and instructions. -[Translation Table Base Register 0 - EL1]: https://docs.rs/crate/cortex-a/5.1.2/source/src/regs/ttbr0_el1.rs -[Translation Control Register - EL1]: https://docs.rs/crate/cortex-a/5.1.2/source/src/regs/tcr_el1.rs -[System Control Register - EL1]: https://docs.rs/crate/cortex-a/5.1.2/source/src/regs/sctlr_el1.rs +[Translation Table Base Register 0 - EL1]: https://docs.rs/aarch64-cpu/9.0.0/src/aarch64_cpu/registers/ttbr0_el1.rs.html +[Translation Control Register - EL1]: https://docs.rs/aarch64-cpu/9.0.0/src/aarch64_cpu/registers/tcr_el1.rs.html +[System Control Register - EL1]: https://docs.rs/aarch64-cpu/9.0.0/src/aarch64_cpu/registers/sctlr_el1.rs.html ### `kernel.ld` @@ -257,11 +257,11 @@ The MMU init code is again a good example to see the great potential of Rust's z abstractions[[1]][[2]] for embedded programming. Let's take a look again at the piece of code for setting up the `MAIR_EL1` register using the -[cortex-a] crate: +[aarch64-cpu] crate: [1]: https://blog.rust-lang.org/2015/05/11/traits.html [2]: https://ruudvanasseldonk.com/2016/11/30/zero-cost-abstractions -[cortex-a]: https://crates.io/crates/cortex-a +[aarch64-cpu]: https://crates.io/crates/aarch64-cpu ```rust /// Setup function for the MAIR_EL1 register. @@ -681,8 +681,8 @@ diff -uNr 09_privilege_level/src/_arch/aarch64/memory/mmu.rs 10_virtual_mem_part + bsp, memory, + memory::mmu::{translation_table::KernelTranslationTable, TranslationGranule}, +}; ++use aarch64_cpu::{asm::barrier, registers::*}; +use core::intrinsics::unlikely; -+use cortex_a::{asm::barrier, registers::*}; +use tock_registers::interfaces::{ReadWriteable, Readable, Writeable}; + +//-------------------------------------------------------------------------------------------------- diff --git a/10_virtual_mem_part1_identity_mapping/src/_arch/aarch64/cpu.rs b/10_virtual_mem_part1_identity_mapping/src/_arch/aarch64/cpu.rs index 4414ac6a..bbe7687a 100644 --- a/10_virtual_mem_part1_identity_mapping/src/_arch/aarch64/cpu.rs +++ b/10_virtual_mem_part1_identity_mapping/src/_arch/aarch64/cpu.rs @@ -11,7 +11,7 @@ //! //! crate::cpu::arch_cpu -use cortex_a::asm; +use aarch64_cpu::asm; //-------------------------------------------------------------------------------------------------- // Public Code diff --git a/10_virtual_mem_part1_identity_mapping/src/_arch/aarch64/cpu/boot.rs b/10_virtual_mem_part1_identity_mapping/src/_arch/aarch64/cpu/boot.rs index 0bf45b83..b458f0db 100644 --- a/10_virtual_mem_part1_identity_mapping/src/_arch/aarch64/cpu/boot.rs +++ b/10_virtual_mem_part1_identity_mapping/src/_arch/aarch64/cpu/boot.rs @@ -11,8 +11,8 @@ //! //! crate::cpu::boot::arch_boot +use aarch64_cpu::{asm, registers::*}; use core::arch::global_asm; -use cortex_a::{asm, registers::*}; use tock_registers::interfaces::Writeable; // Assembly counterpart to this file. diff --git a/10_virtual_mem_part1_identity_mapping/src/_arch/aarch64/exception.rs b/10_virtual_mem_part1_identity_mapping/src/_arch/aarch64/exception.rs index c8eac4f0..c2b7cea8 100644 --- a/10_virtual_mem_part1_identity_mapping/src/_arch/aarch64/exception.rs +++ b/10_virtual_mem_part1_identity_mapping/src/_arch/aarch64/exception.rs @@ -11,7 +11,7 @@ //! //! crate::exception::arch_exception -use cortex_a::registers::*; +use aarch64_cpu::registers::*; use tock_registers::interfaces::Readable; //-------------------------------------------------------------------------------------------------- diff --git a/10_virtual_mem_part1_identity_mapping/src/_arch/aarch64/exception/asynchronous.rs b/10_virtual_mem_part1_identity_mapping/src/_arch/aarch64/exception/asynchronous.rs index e3e3672e..0347dc3f 100644 --- a/10_virtual_mem_part1_identity_mapping/src/_arch/aarch64/exception/asynchronous.rs +++ b/10_virtual_mem_part1_identity_mapping/src/_arch/aarch64/exception/asynchronous.rs @@ -11,7 +11,7 @@ //! //! crate::exception::asynchronous::arch_asynchronous -use cortex_a::registers::*; +use aarch64_cpu::registers::*; use tock_registers::interfaces::Readable; //-------------------------------------------------------------------------------------------------- diff --git a/10_virtual_mem_part1_identity_mapping/src/_arch/aarch64/memory/mmu.rs b/10_virtual_mem_part1_identity_mapping/src/_arch/aarch64/memory/mmu.rs index 3a965f71..e5e2653a 100644 --- a/10_virtual_mem_part1_identity_mapping/src/_arch/aarch64/memory/mmu.rs +++ b/10_virtual_mem_part1_identity_mapping/src/_arch/aarch64/memory/mmu.rs @@ -17,8 +17,8 @@ use crate::{ bsp, memory, memory::mmu::{translation_table::KernelTranslationTable, TranslationGranule}, }; +use aarch64_cpu::{asm::barrier, registers::*}; use core::intrinsics::unlikely; -use cortex_a::{asm::barrier, registers::*}; use tock_registers::interfaces::{ReadWriteable, Readable, Writeable}; //-------------------------------------------------------------------------------------------------- diff --git a/10_virtual_mem_part1_identity_mapping/src/_arch/aarch64/time.rs b/10_virtual_mem_part1_identity_mapping/src/_arch/aarch64/time.rs index 1e2efbec..94d02379 100644 --- a/10_virtual_mem_part1_identity_mapping/src/_arch/aarch64/time.rs +++ b/10_virtual_mem_part1_identity_mapping/src/_arch/aarch64/time.rs @@ -12,12 +12,12 @@ //! crate::time::arch_time use crate::warn; +use aarch64_cpu::{asm::barrier, registers::*}; use core::{ num::{NonZeroU128, NonZeroU32, NonZeroU64}, ops::{Add, Div}, time::Duration, }; -use cortex_a::{asm::barrier, registers::*}; use tock_registers::interfaces::Readable; //-------------------------------------------------------------------------------------------------- diff --git a/11_exceptions_part1_groundwork/Cargo.lock b/11_exceptions_part1_groundwork/Cargo.lock index c7bfdadd..dd741b8d 100644 --- a/11_exceptions_part1_groundwork/Cargo.lock +++ b/11_exceptions_part1_groundwork/Cargo.lock @@ -3,10 +3,10 @@ version = 3 [[package]] -name = "cortex-a" -version = "8.0.0" +name = "aarch64-cpu" +version = "9.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cd4524931a4e0ec50ae91f0d55f571f31ffe11dd9ce2f9905b8343c018c25bb" +checksum = "3aceb88e55ba626a5479279268d009a92d9d00eacce0de1b8c236c7ad31b7225" dependencies = [ "tock-registers", ] @@ -15,7 +15,7 @@ dependencies = [ name = "mingo" version = "0.11.0" dependencies = [ - "cortex-a", + "aarch64-cpu", "tock-registers", ] diff --git a/11_exceptions_part1_groundwork/Cargo.toml b/11_exceptions_part1_groundwork/Cargo.toml index c8d3613f..22343d4c 100644 --- a/11_exceptions_part1_groundwork/Cargo.toml +++ b/11_exceptions_part1_groundwork/Cargo.toml @@ -27,4 +27,4 @@ tock-registers = { version = "0.8.x", default-features = false, features = ["reg # Platform specific dependencies [target.'cfg(target_arch = "aarch64")'.dependencies] -cortex-a = { version = "8.x.x" } +aarch64-cpu = { version = "9.x.x" } diff --git a/11_exceptions_part1_groundwork/README.md b/11_exceptions_part1_groundwork/README.md index 12812acb..0a9cc9fc 100644 --- a/11_exceptions_part1_groundwork/README.md +++ b/11_exceptions_part1_groundwork/README.md @@ -507,10 +507,10 @@ diff -uNr 10_virtual_mem_part1_identity_mapping/src/_arch/aarch64/exception.rs 1 //! //! crate::exception::arch_exception --use cortex_a::registers::*; +-use aarch64_cpu::registers::*; -use tock_registers::interfaces::Readable; ++use aarch64_cpu::{asm::barrier, registers::*}; +use core::{arch::global_asm, cell::UnsafeCell, fmt}; -+use cortex_a::{asm::barrier, registers::*}; +use tock_registers::{ + interfaces::{Readable, Writeable}, + registers::InMemoryRegister, diff --git a/11_exceptions_part1_groundwork/src/_arch/aarch64/cpu.rs b/11_exceptions_part1_groundwork/src/_arch/aarch64/cpu.rs index 4414ac6a..bbe7687a 100644 --- a/11_exceptions_part1_groundwork/src/_arch/aarch64/cpu.rs +++ b/11_exceptions_part1_groundwork/src/_arch/aarch64/cpu.rs @@ -11,7 +11,7 @@ //! //! crate::cpu::arch_cpu -use cortex_a::asm; +use aarch64_cpu::asm; //-------------------------------------------------------------------------------------------------- // Public Code diff --git a/11_exceptions_part1_groundwork/src/_arch/aarch64/cpu/boot.rs b/11_exceptions_part1_groundwork/src/_arch/aarch64/cpu/boot.rs index 0bf45b83..b458f0db 100644 --- a/11_exceptions_part1_groundwork/src/_arch/aarch64/cpu/boot.rs +++ b/11_exceptions_part1_groundwork/src/_arch/aarch64/cpu/boot.rs @@ -11,8 +11,8 @@ //! //! crate::cpu::boot::arch_boot +use aarch64_cpu::{asm, registers::*}; use core::arch::global_asm; -use cortex_a::{asm, registers::*}; use tock_registers::interfaces::Writeable; // Assembly counterpart to this file. diff --git a/11_exceptions_part1_groundwork/src/_arch/aarch64/exception.rs b/11_exceptions_part1_groundwork/src/_arch/aarch64/exception.rs index c72fb885..165e0730 100644 --- a/11_exceptions_part1_groundwork/src/_arch/aarch64/exception.rs +++ b/11_exceptions_part1_groundwork/src/_arch/aarch64/exception.rs @@ -11,8 +11,8 @@ //! //! crate::exception::arch_exception +use aarch64_cpu::{asm::barrier, registers::*}; use core::{arch::global_asm, cell::UnsafeCell, fmt}; -use cortex_a::{asm::barrier, registers::*}; use tock_registers::{ interfaces::{Readable, Writeable}, registers::InMemoryRegister, diff --git a/11_exceptions_part1_groundwork/src/_arch/aarch64/exception/asynchronous.rs b/11_exceptions_part1_groundwork/src/_arch/aarch64/exception/asynchronous.rs index e3e3672e..0347dc3f 100644 --- a/11_exceptions_part1_groundwork/src/_arch/aarch64/exception/asynchronous.rs +++ b/11_exceptions_part1_groundwork/src/_arch/aarch64/exception/asynchronous.rs @@ -11,7 +11,7 @@ //! //! crate::exception::asynchronous::arch_asynchronous -use cortex_a::registers::*; +use aarch64_cpu::registers::*; use tock_registers::interfaces::Readable; //-------------------------------------------------------------------------------------------------- diff --git a/11_exceptions_part1_groundwork/src/_arch/aarch64/memory/mmu.rs b/11_exceptions_part1_groundwork/src/_arch/aarch64/memory/mmu.rs index 3a965f71..e5e2653a 100644 --- a/11_exceptions_part1_groundwork/src/_arch/aarch64/memory/mmu.rs +++ b/11_exceptions_part1_groundwork/src/_arch/aarch64/memory/mmu.rs @@ -17,8 +17,8 @@ use crate::{ bsp, memory, memory::mmu::{translation_table::KernelTranslationTable, TranslationGranule}, }; +use aarch64_cpu::{asm::barrier, registers::*}; use core::intrinsics::unlikely; -use cortex_a::{asm::barrier, registers::*}; use tock_registers::interfaces::{ReadWriteable, Readable, Writeable}; //-------------------------------------------------------------------------------------------------- diff --git a/11_exceptions_part1_groundwork/src/_arch/aarch64/time.rs b/11_exceptions_part1_groundwork/src/_arch/aarch64/time.rs index 1e2efbec..94d02379 100644 --- a/11_exceptions_part1_groundwork/src/_arch/aarch64/time.rs +++ b/11_exceptions_part1_groundwork/src/_arch/aarch64/time.rs @@ -12,12 +12,12 @@ //! crate::time::arch_time use crate::warn; +use aarch64_cpu::{asm::barrier, registers::*}; use core::{ num::{NonZeroU128, NonZeroU32, NonZeroU64}, ops::{Add, Div}, time::Duration, }; -use cortex_a::{asm::barrier, registers::*}; use tock_registers::interfaces::Readable; //-------------------------------------------------------------------------------------------------- diff --git a/12_integrated_testing/Cargo.lock b/12_integrated_testing/Cargo.lock index abe5ab82..8db3db87 100644 --- a/12_integrated_testing/Cargo.lock +++ b/12_integrated_testing/Cargo.lock @@ -3,10 +3,10 @@ version = 3 [[package]] -name = "cortex-a" -version = "8.0.0" +name = "aarch64-cpu" +version = "9.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cd4524931a4e0ec50ae91f0d55f571f31ffe11dd9ce2f9905b8343c018c25bb" +checksum = "3aceb88e55ba626a5479279268d009a92d9d00eacce0de1b8c236c7ad31b7225" dependencies = [ "tock-registers", ] @@ -15,7 +15,7 @@ dependencies = [ name = "mingo" version = "0.12.0" dependencies = [ - "cortex-a", + "aarch64-cpu", "qemu-exit", "test-macros", "test-types", diff --git a/12_integrated_testing/kernel/Cargo.toml b/12_integrated_testing/kernel/Cargo.toml index 7bbca0b4..97dd972e 100644 --- a/12_integrated_testing/kernel/Cargo.toml +++ b/12_integrated_testing/kernel/Cargo.toml @@ -23,7 +23,7 @@ qemu-exit = { version = "3.x.x", optional = true } # Platform specific dependencies [target.'cfg(target_arch = "aarch64")'.dependencies] -cortex-a = { version = "8.x.x" } +aarch64-cpu = { version = "9.x.x" } ##-------------------------------------------------------------------------------------------------- ## Testing diff --git a/12_integrated_testing/kernel/src/_arch/aarch64/cpu.rs b/12_integrated_testing/kernel/src/_arch/aarch64/cpu.rs index 66da661c..7eb7f010 100644 --- a/12_integrated_testing/kernel/src/_arch/aarch64/cpu.rs +++ b/12_integrated_testing/kernel/src/_arch/aarch64/cpu.rs @@ -11,7 +11,7 @@ //! //! crate::cpu::arch_cpu -use cortex_a::asm; +use aarch64_cpu::asm; //-------------------------------------------------------------------------------------------------- // Public Code diff --git a/12_integrated_testing/kernel/src/_arch/aarch64/cpu/boot.rs b/12_integrated_testing/kernel/src/_arch/aarch64/cpu/boot.rs index 0bf45b83..b458f0db 100644 --- a/12_integrated_testing/kernel/src/_arch/aarch64/cpu/boot.rs +++ b/12_integrated_testing/kernel/src/_arch/aarch64/cpu/boot.rs @@ -11,8 +11,8 @@ //! //! crate::cpu::boot::arch_boot +use aarch64_cpu::{asm, registers::*}; use core::arch::global_asm; -use cortex_a::{asm, registers::*}; use tock_registers::interfaces::Writeable; // Assembly counterpart to this file. diff --git a/12_integrated_testing/kernel/src/_arch/aarch64/exception.rs b/12_integrated_testing/kernel/src/_arch/aarch64/exception.rs index 5664605e..84681bc7 100644 --- a/12_integrated_testing/kernel/src/_arch/aarch64/exception.rs +++ b/12_integrated_testing/kernel/src/_arch/aarch64/exception.rs @@ -11,8 +11,8 @@ //! //! crate::exception::arch_exception +use aarch64_cpu::{asm::barrier, registers::*}; use core::{arch::global_asm, cell::UnsafeCell, fmt}; -use cortex_a::{asm::barrier, registers::*}; use tock_registers::{ interfaces::{Readable, Writeable}, registers::InMemoryRegister, diff --git a/12_integrated_testing/kernel/src/_arch/aarch64/exception/asynchronous.rs b/12_integrated_testing/kernel/src/_arch/aarch64/exception/asynchronous.rs index e3e3672e..0347dc3f 100644 --- a/12_integrated_testing/kernel/src/_arch/aarch64/exception/asynchronous.rs +++ b/12_integrated_testing/kernel/src/_arch/aarch64/exception/asynchronous.rs @@ -11,7 +11,7 @@ //! //! crate::exception::asynchronous::arch_asynchronous -use cortex_a::registers::*; +use aarch64_cpu::registers::*; use tock_registers::interfaces::Readable; //-------------------------------------------------------------------------------------------------- diff --git a/12_integrated_testing/kernel/src/_arch/aarch64/memory/mmu.rs b/12_integrated_testing/kernel/src/_arch/aarch64/memory/mmu.rs index 15a7faeb..fbd4992f 100644 --- a/12_integrated_testing/kernel/src/_arch/aarch64/memory/mmu.rs +++ b/12_integrated_testing/kernel/src/_arch/aarch64/memory/mmu.rs @@ -17,8 +17,8 @@ use crate::{ bsp, memory, memory::mmu::{translation_table::KernelTranslationTable, TranslationGranule}, }; +use aarch64_cpu::{asm::barrier, registers::*}; use core::intrinsics::unlikely; -use cortex_a::{asm::barrier, registers::*}; use tock_registers::interfaces::{ReadWriteable, Readable, Writeable}; //-------------------------------------------------------------------------------------------------- diff --git a/12_integrated_testing/kernel/src/_arch/aarch64/time.rs b/12_integrated_testing/kernel/src/_arch/aarch64/time.rs index 1e2efbec..94d02379 100644 --- a/12_integrated_testing/kernel/src/_arch/aarch64/time.rs +++ b/12_integrated_testing/kernel/src/_arch/aarch64/time.rs @@ -12,12 +12,12 @@ //! crate::time::arch_time use crate::warn; +use aarch64_cpu::{asm::barrier, registers::*}; use core::{ num::{NonZeroU128, NonZeroU32, NonZeroU64}, ops::{Add, Div}, time::Duration, }; -use cortex_a::{asm::barrier, registers::*}; use tock_registers::interfaces::Readable; //-------------------------------------------------------------------------------------------------- diff --git a/13_exceptions_part2_peripheral_IRQs/Cargo.lock b/13_exceptions_part2_peripheral_IRQs/Cargo.lock index d893a0af..ad1e8660 100644 --- a/13_exceptions_part2_peripheral_IRQs/Cargo.lock +++ b/13_exceptions_part2_peripheral_IRQs/Cargo.lock @@ -3,10 +3,10 @@ version = 3 [[package]] -name = "cortex-a" -version = "8.0.0" +name = "aarch64-cpu" +version = "9.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cd4524931a4e0ec50ae91f0d55f571f31ffe11dd9ce2f9905b8343c018c25bb" +checksum = "3aceb88e55ba626a5479279268d009a92d9d00eacce0de1b8c236c7ad31b7225" dependencies = [ "tock-registers", ] @@ -15,7 +15,7 @@ dependencies = [ name = "mingo" version = "0.13.0" dependencies = [ - "cortex-a", + "aarch64-cpu", "qemu-exit", "test-macros", "test-types", diff --git a/13_exceptions_part2_peripheral_IRQs/README.md b/13_exceptions_part2_peripheral_IRQs/README.md index a8c503d5..944001e7 100644 --- a/13_exceptions_part2_peripheral_IRQs/README.md +++ b/13_exceptions_part2_peripheral_IRQs/README.md @@ -802,7 +802,7 @@ diff -uNr 12_integrated_testing/kernel/src/_arch/aarch64/cpu/smp.rs 13_exception +//! +//! crate::cpu::smp::arch_smp + -+use cortex_a::registers::*; ++use aarch64_cpu::registers::*; +use tock_registers::interfaces::Readable; + +//-------------------------------------------------------------------------------------------------- @@ -823,13 +823,12 @@ diff -uNr 12_integrated_testing/kernel/src/_arch/aarch64/cpu/smp.rs 13_exception diff -uNr 12_integrated_testing/kernel/src/_arch/aarch64/exception/asynchronous.rs 13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/exception/asynchronous.rs --- 12_integrated_testing/kernel/src/_arch/aarch64/exception/asynchronous.rs +++ 13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/exception/asynchronous.rs -@@ -11,13 +11,18 @@ - //! +@@ -12,12 +12,17 @@ //! crate::exception::asynchronous::arch_asynchronous -+use core::arch::asm; - use cortex_a::registers::*; + use aarch64_cpu::registers::*; -use tock_registers::interfaces::Readable; ++use core::arch::asm; +use tock_registers::interfaces::{Readable, Writeable}; //-------------------------------------------------------------------------------------------------- @@ -913,8 +912,8 @@ diff -uNr 12_integrated_testing/kernel/src/_arch/aarch64/exception.rs 13_excepti //! crate::exception::arch_exception +use crate::exception; + use aarch64_cpu::{asm::barrier, registers::*}; use core::{arch::global_asm, cell::UnsafeCell, fmt}; - use cortex_a::{asm::barrier, registers::*}; use tock_registers::{ @@ -102,8 +103,9 @@ } diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/Cargo.toml b/13_exceptions_part2_peripheral_IRQs/kernel/Cargo.toml index 5f371dda..3b04b97b 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/Cargo.toml +++ b/13_exceptions_part2_peripheral_IRQs/kernel/Cargo.toml @@ -23,7 +23,7 @@ qemu-exit = { version = "3.x.x", optional = true } # Platform specific dependencies [target.'cfg(target_arch = "aarch64")'.dependencies] -cortex-a = { version = "8.x.x" } +aarch64-cpu = { version = "9.x.x" } ##-------------------------------------------------------------------------------------------------- ## Testing diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/cpu.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/cpu.rs index 66da661c..7eb7f010 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/cpu.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/cpu.rs @@ -11,7 +11,7 @@ //! //! crate::cpu::arch_cpu -use cortex_a::asm; +use aarch64_cpu::asm; //-------------------------------------------------------------------------------------------------- // Public Code diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/cpu/boot.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/cpu/boot.rs index 0bf45b83..b458f0db 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/cpu/boot.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/cpu/boot.rs @@ -11,8 +11,8 @@ //! //! crate::cpu::boot::arch_boot +use aarch64_cpu::{asm, registers::*}; use core::arch::global_asm; -use cortex_a::{asm, registers::*}; use tock_registers::interfaces::Writeable; // Assembly counterpart to this file. diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/cpu/smp.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/cpu/smp.rs index 351fde62..9d304d65 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/cpu/smp.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/cpu/smp.rs @@ -11,7 +11,7 @@ //! //! crate::cpu::smp::arch_smp -use cortex_a::registers::*; +use aarch64_cpu::registers::*; use tock_registers::interfaces::Readable; //-------------------------------------------------------------------------------------------------- diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/exception.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/exception.rs index 3aa6fb24..71831178 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/exception.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/exception.rs @@ -12,8 +12,8 @@ //! crate::exception::arch_exception use crate::exception; +use aarch64_cpu::{asm::barrier, registers::*}; use core::{arch::global_asm, cell::UnsafeCell, fmt}; -use cortex_a::{asm::barrier, registers::*}; use tock_registers::{ interfaces::{Readable, Writeable}, registers::InMemoryRegister, diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/exception/asynchronous.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/exception/asynchronous.rs index cf6f97ac..f545a3e1 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/exception/asynchronous.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/exception/asynchronous.rs @@ -11,8 +11,8 @@ //! //! crate::exception::asynchronous::arch_asynchronous +use aarch64_cpu::registers::*; use core::arch::asm; -use cortex_a::registers::*; use tock_registers::interfaces::{Readable, Writeable}; //-------------------------------------------------------------------------------------------------- diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/memory/mmu.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/memory/mmu.rs index 15a7faeb..fbd4992f 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/memory/mmu.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/memory/mmu.rs @@ -17,8 +17,8 @@ use crate::{ bsp, memory, memory::mmu::{translation_table::KernelTranslationTable, TranslationGranule}, }; +use aarch64_cpu::{asm::barrier, registers::*}; use core::intrinsics::unlikely; -use cortex_a::{asm::barrier, registers::*}; use tock_registers::interfaces::{ReadWriteable, Readable, Writeable}; //-------------------------------------------------------------------------------------------------- diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/time.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/time.rs index 1e2efbec..94d02379 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/time.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/time.rs @@ -12,12 +12,12 @@ //! crate::time::arch_time use crate::warn; +use aarch64_cpu::{asm::barrier, registers::*}; use core::{ num::{NonZeroU128, NonZeroU32, NonZeroU64}, ops::{Add, Div}, time::Duration, }; -use cortex_a::{asm::barrier, registers::*}; use tock_registers::interfaces::Readable; //-------------------------------------------------------------------------------------------------- diff --git a/14_virtual_mem_part2_mmio_remap/Cargo.lock b/14_virtual_mem_part2_mmio_remap/Cargo.lock index dd14a9d7..eea03734 100644 --- a/14_virtual_mem_part2_mmio_remap/Cargo.lock +++ b/14_virtual_mem_part2_mmio_remap/Cargo.lock @@ -3,10 +3,10 @@ version = 3 [[package]] -name = "cortex-a" -version = "8.0.0" +name = "aarch64-cpu" +version = "9.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cd4524931a4e0ec50ae91f0d55f571f31ffe11dd9ce2f9905b8343c018c25bb" +checksum = "3aceb88e55ba626a5479279268d009a92d9d00eacce0de1b8c236c7ad31b7225" dependencies = [ "tock-registers", ] @@ -15,7 +15,7 @@ dependencies = [ name = "mingo" version = "0.14.0" dependencies = [ - "cortex-a", + "aarch64-cpu", "qemu-exit", "test-macros", "test-types", diff --git a/14_virtual_mem_part2_mmio_remap/README.md b/14_virtual_mem_part2_mmio_remap/README.md index 61117358..7d16e69c 100644 --- a/14_virtual_mem_part2_mmio_remap/README.md +++ b/14_virtual_mem_part2_mmio_remap/README.md @@ -751,8 +751,8 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/memory/mm - memory::mmu::{translation_table::KernelTranslationTable, TranslationGranule}, + memory::{mmu::TranslationGranule, Address, Physical}, }; + use aarch64_cpu::{asm::barrier, registers::*}; use core::intrinsics::unlikely; - use cortex_a::{asm::barrier, registers::*}; @@ -46,13 +46,6 @@ // Global instances //-------------------------------------------------------------------------------------------------- diff --git a/14_virtual_mem_part2_mmio_remap/kernel/Cargo.toml b/14_virtual_mem_part2_mmio_remap/kernel/Cargo.toml index fe4e48e7..b85ecbed 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/Cargo.toml +++ b/14_virtual_mem_part2_mmio_remap/kernel/Cargo.toml @@ -23,7 +23,7 @@ qemu-exit = { version = "3.x.x", optional = true } # Platform specific dependencies [target.'cfg(target_arch = "aarch64")'.dependencies] -cortex-a = { version = "8.x.x" } +aarch64-cpu = { version = "9.x.x" } ##-------------------------------------------------------------------------------------------------- ## Testing diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/cpu.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/cpu.rs index 66da661c..7eb7f010 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/cpu.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/cpu.rs @@ -11,7 +11,7 @@ //! //! crate::cpu::arch_cpu -use cortex_a::asm; +use aarch64_cpu::asm; //-------------------------------------------------------------------------------------------------- // Public Code diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/cpu/boot.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/cpu/boot.rs index 0bf45b83..b458f0db 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/cpu/boot.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/cpu/boot.rs @@ -11,8 +11,8 @@ //! //! crate::cpu::boot::arch_boot +use aarch64_cpu::{asm, registers::*}; use core::arch::global_asm; -use cortex_a::{asm, registers::*}; use tock_registers::interfaces::Writeable; // Assembly counterpart to this file. diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/cpu/smp.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/cpu/smp.rs index 351fde62..9d304d65 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/cpu/smp.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/cpu/smp.rs @@ -11,7 +11,7 @@ //! //! crate::cpu::smp::arch_smp -use cortex_a::registers::*; +use aarch64_cpu::registers::*; use tock_registers::interfaces::Readable; //-------------------------------------------------------------------------------------------------- diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/exception.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/exception.rs index 3aa6fb24..71831178 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/exception.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/exception.rs @@ -12,8 +12,8 @@ //! crate::exception::arch_exception use crate::exception; +use aarch64_cpu::{asm::barrier, registers::*}; use core::{arch::global_asm, cell::UnsafeCell, fmt}; -use cortex_a::{asm::barrier, registers::*}; use tock_registers::{ interfaces::{Readable, Writeable}, registers::InMemoryRegister, diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/exception/asynchronous.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/exception/asynchronous.rs index cf6f97ac..f545a3e1 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/exception/asynchronous.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/exception/asynchronous.rs @@ -11,8 +11,8 @@ //! //! crate::exception::asynchronous::arch_asynchronous +use aarch64_cpu::registers::*; use core::arch::asm; -use cortex_a::registers::*; use tock_registers::interfaces::{Readable, Writeable}; //-------------------------------------------------------------------------------------------------- diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/memory/mmu.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/memory/mmu.rs index e2db2d23..aaec1925 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/memory/mmu.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/memory/mmu.rs @@ -17,8 +17,8 @@ use crate::{ bsp, memory, memory::{mmu::TranslationGranule, Address, Physical}, }; +use aarch64_cpu::{asm::barrier, registers::*}; use core::intrinsics::unlikely; -use cortex_a::{asm::barrier, registers::*}; use tock_registers::interfaces::{ReadWriteable, Readable, Writeable}; //-------------------------------------------------------------------------------------------------- diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/time.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/time.rs index 1e2efbec..94d02379 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/time.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/time.rs @@ -12,12 +12,12 @@ //! crate::time::arch_time use crate::warn; +use aarch64_cpu::{asm::barrier, registers::*}; use core::{ num::{NonZeroU128, NonZeroU32, NonZeroU64}, ops::{Add, Div}, time::Duration, }; -use cortex_a::{asm::barrier, registers::*}; use tock_registers::interfaces::Readable; //-------------------------------------------------------------------------------------------------- diff --git a/15_virtual_mem_part3_precomputed_tables/Cargo.lock b/15_virtual_mem_part3_precomputed_tables/Cargo.lock index 6863764a..1bef088b 100644 --- a/15_virtual_mem_part3_precomputed_tables/Cargo.lock +++ b/15_virtual_mem_part3_precomputed_tables/Cargo.lock @@ -3,10 +3,10 @@ version = 3 [[package]] -name = "cortex-a" -version = "8.0.0" +name = "aarch64-cpu" +version = "9.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cd4524931a4e0ec50ae91f0d55f571f31ffe11dd9ce2f9905b8343c018c25bb" +checksum = "3aceb88e55ba626a5479279268d009a92d9d00eacce0de1b8c236c7ad31b7225" dependencies = [ "tock-registers", ] @@ -15,7 +15,7 @@ dependencies = [ name = "mingo" version = "0.15.0" dependencies = [ - "cortex-a", + "aarch64-cpu", "qemu-exit", "test-macros", "test-types", diff --git a/15_virtual_mem_part3_precomputed_tables/README.md b/15_virtual_mem_part3_precomputed_tables/README.md index c850992e..23210265 100644 --- a/15_virtual_mem_part3_precomputed_tables/README.md +++ b/15_virtual_mem_part3_precomputed_tables/README.md @@ -816,8 +816,8 @@ diff -uNr 14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/cpu/boot.rs 1 //! crate::cpu::boot::arch_boot +use crate::{memory, memory::Address}; + use aarch64_cpu::{asm, registers::*}; use core::arch::global_asm; - use cortex_a::{asm, registers::*}; use tock_registers::interfaces::Writeable; @@ -75,9 +76,16 @@ /// diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/Cargo.toml b/15_virtual_mem_part3_precomputed_tables/kernel/Cargo.toml index 9a0408ad..73b6feef 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/Cargo.toml +++ b/15_virtual_mem_part3_precomputed_tables/kernel/Cargo.toml @@ -23,7 +23,7 @@ qemu-exit = { version = "3.x.x", optional = true } # Platform specific dependencies [target.'cfg(target_arch = "aarch64")'.dependencies] -cortex-a = { version = "8.x.x" } +aarch64-cpu = { version = "9.x.x" } ##-------------------------------------------------------------------------------------------------- ## Testing diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/cpu.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/cpu.rs index 66da661c..7eb7f010 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/cpu.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/cpu.rs @@ -11,7 +11,7 @@ //! //! crate::cpu::arch_cpu -use cortex_a::asm; +use aarch64_cpu::asm; //-------------------------------------------------------------------------------------------------- // Public Code diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/cpu/boot.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/cpu/boot.rs index a66c0cb3..fc70fe7f 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/cpu/boot.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/cpu/boot.rs @@ -12,8 +12,8 @@ //! crate::cpu::boot::arch_boot use crate::{memory, memory::Address}; +use aarch64_cpu::{asm, registers::*}; use core::arch::global_asm; -use cortex_a::{asm, registers::*}; use tock_registers::interfaces::Writeable; // Assembly counterpart to this file. diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/cpu/smp.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/cpu/smp.rs index 351fde62..9d304d65 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/cpu/smp.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/cpu/smp.rs @@ -11,7 +11,7 @@ //! //! crate::cpu::smp::arch_smp -use cortex_a::registers::*; +use aarch64_cpu::registers::*; use tock_registers::interfaces::Readable; //-------------------------------------------------------------------------------------------------- diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/exception.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/exception.rs index 3aa6fb24..71831178 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/exception.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/exception.rs @@ -12,8 +12,8 @@ //! crate::exception::arch_exception use crate::exception; +use aarch64_cpu::{asm::barrier, registers::*}; use core::{arch::global_asm, cell::UnsafeCell, fmt}; -use cortex_a::{asm::barrier, registers::*}; use tock_registers::{ interfaces::{Readable, Writeable}, registers::InMemoryRegister, diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/exception/asynchronous.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/exception/asynchronous.rs index cf6f97ac..f545a3e1 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/exception/asynchronous.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/exception/asynchronous.rs @@ -11,8 +11,8 @@ //! //! crate::exception::asynchronous::arch_asynchronous +use aarch64_cpu::registers::*; use core::arch::asm; -use cortex_a::registers::*; use tock_registers::interfaces::{Readable, Writeable}; //-------------------------------------------------------------------------------------------------- diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/memory/mmu.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/memory/mmu.rs index e2db2d23..aaec1925 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/memory/mmu.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/memory/mmu.rs @@ -17,8 +17,8 @@ use crate::{ bsp, memory, memory::{mmu::TranslationGranule, Address, Physical}, }; +use aarch64_cpu::{asm::barrier, registers::*}; use core::intrinsics::unlikely; -use cortex_a::{asm::barrier, registers::*}; use tock_registers::interfaces::{ReadWriteable, Readable, Writeable}; //-------------------------------------------------------------------------------------------------- diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/time.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/time.rs index 1e2efbec..94d02379 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/time.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/time.rs @@ -12,12 +12,12 @@ //! crate::time::arch_time use crate::warn; +use aarch64_cpu::{asm::barrier, registers::*}; use core::{ num::{NonZeroU128, NonZeroU32, NonZeroU64}, ops::{Add, Div}, time::Duration, }; -use cortex_a::{asm::barrier, registers::*}; use tock_registers::interfaces::Readable; //-------------------------------------------------------------------------------------------------- diff --git a/16_virtual_mem_part4_higher_half_kernel/Cargo.lock b/16_virtual_mem_part4_higher_half_kernel/Cargo.lock index 1cd1bc74..52d5b3fb 100644 --- a/16_virtual_mem_part4_higher_half_kernel/Cargo.lock +++ b/16_virtual_mem_part4_higher_half_kernel/Cargo.lock @@ -3,10 +3,10 @@ version = 3 [[package]] -name = "cortex-a" -version = "8.0.0" +name = "aarch64-cpu" +version = "9.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cd4524931a4e0ec50ae91f0d55f571f31ffe11dd9ce2f9905b8343c018c25bb" +checksum = "3aceb88e55ba626a5479279268d009a92d9d00eacce0de1b8c236c7ad31b7225" dependencies = [ "tock-registers", ] @@ -15,7 +15,7 @@ dependencies = [ name = "mingo" version = "0.16.0" dependencies = [ - "cortex-a", + "aarch64-cpu", "qemu-exit", "test-macros", "test-types", diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/Cargo.toml b/16_virtual_mem_part4_higher_half_kernel/kernel/Cargo.toml index 06b2573c..857256cb 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/Cargo.toml +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/Cargo.toml @@ -23,7 +23,7 @@ qemu-exit = { version = "3.x.x", optional = true } # Platform specific dependencies [target.'cfg(target_arch = "aarch64")'.dependencies] -cortex-a = { version = "8.x.x" } +aarch64-cpu = { version = "9.x.x" } ##-------------------------------------------------------------------------------------------------- ## Testing diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/cpu.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/cpu.rs index 66da661c..7eb7f010 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/cpu.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/cpu.rs @@ -11,7 +11,7 @@ //! //! crate::cpu::arch_cpu -use cortex_a::asm; +use aarch64_cpu::asm; //-------------------------------------------------------------------------------------------------- // Public Code diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/cpu/boot.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/cpu/boot.rs index 293d4608..2cad1ab6 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/cpu/boot.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/cpu/boot.rs @@ -12,8 +12,8 @@ //! crate::cpu::boot::arch_boot use crate::{memory, memory::Address}; +use aarch64_cpu::{asm, registers::*}; use core::arch::global_asm; -use cortex_a::{asm, registers::*}; use tock_registers::interfaces::Writeable; // Assembly counterpart to this file. diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/cpu/smp.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/cpu/smp.rs index 351fde62..9d304d65 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/cpu/smp.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/cpu/smp.rs @@ -11,7 +11,7 @@ //! //! crate::cpu::smp::arch_smp -use cortex_a::registers::*; +use aarch64_cpu::registers::*; use tock_registers::interfaces::Readable; //-------------------------------------------------------------------------------------------------- diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/exception.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/exception.rs index 3aa6fb24..71831178 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/exception.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/exception.rs @@ -12,8 +12,8 @@ //! crate::exception::arch_exception use crate::exception; +use aarch64_cpu::{asm::barrier, registers::*}; use core::{arch::global_asm, cell::UnsafeCell, fmt}; -use cortex_a::{asm::barrier, registers::*}; use tock_registers::{ interfaces::{Readable, Writeable}, registers::InMemoryRegister, diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/exception/asynchronous.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/exception/asynchronous.rs index cf6f97ac..f545a3e1 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/exception/asynchronous.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/exception/asynchronous.rs @@ -11,8 +11,8 @@ //! //! crate::exception::asynchronous::arch_asynchronous +use aarch64_cpu::registers::*; use core::arch::asm; -use cortex_a::registers::*; use tock_registers::interfaces::{Readable, Writeable}; //-------------------------------------------------------------------------------------------------- diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/memory/mmu.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/memory/mmu.rs index 3d6c18b7..74a71d11 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/memory/mmu.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/memory/mmu.rs @@ -17,8 +17,8 @@ use crate::{ bsp, memory, memory::{mmu::TranslationGranule, Address, Physical}, }; +use aarch64_cpu::{asm::barrier, registers::*}; use core::intrinsics::unlikely; -use cortex_a::{asm::barrier, registers::*}; use tock_registers::interfaces::{ReadWriteable, Readable, Writeable}; //-------------------------------------------------------------------------------------------------- diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/time.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/time.rs index 1e2efbec..94d02379 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/time.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/time.rs @@ -12,12 +12,12 @@ //! crate::time::arch_time use crate::warn; +use aarch64_cpu::{asm::barrier, registers::*}; use core::{ num::{NonZeroU128, NonZeroU32, NonZeroU64}, ops::{Add, Div}, time::Duration, }; -use cortex_a::{asm::barrier, registers::*}; use tock_registers::interfaces::Readable; //-------------------------------------------------------------------------------------------------- diff --git a/17_kernel_symbols/Cargo.lock b/17_kernel_symbols/Cargo.lock index af229efe..382a3bda 100644 --- a/17_kernel_symbols/Cargo.lock +++ b/17_kernel_symbols/Cargo.lock @@ -3,10 +3,10 @@ version = 3 [[package]] -name = "cortex-a" -version = "8.0.0" +name = "aarch64-cpu" +version = "9.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cd4524931a4e0ec50ae91f0d55f571f31ffe11dd9ce2f9905b8343c018c25bb" +checksum = "3aceb88e55ba626a5479279268d009a92d9d00eacce0de1b8c236c7ad31b7225" dependencies = [ "tock-registers", ] @@ -26,7 +26,7 @@ dependencies = [ name = "mingo" version = "0.17.0" dependencies = [ - "cortex-a", + "aarch64-cpu", "debug-symbol-types", "qemu-exit", "test-macros", diff --git a/17_kernel_symbols/README.md b/17_kernel_symbols/README.md index 925ed689..aec53437 100644 --- a/17_kernel_symbols/README.md +++ b/17_kernel_symbols/README.md @@ -272,8 +272,8 @@ diff -uNr 16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/excep -use crate::exception; +use crate::{exception, memory, symbols}; + use aarch64_cpu::{asm::barrier, registers::*}; use core::{arch::global_asm, cell::UnsafeCell, fmt}; - use cortex_a::{asm::barrier, registers::*}; use tock_registers::{ @@ -260,6 +260,14 @@ diff --git a/17_kernel_symbols/kernel/Cargo.toml b/17_kernel_symbols/kernel/Cargo.toml index a2a83aad..58bf54d2 100644 --- a/17_kernel_symbols/kernel/Cargo.toml +++ b/17_kernel_symbols/kernel/Cargo.toml @@ -24,7 +24,7 @@ qemu-exit = { version = "3.x.x", optional = true } # Platform specific dependencies [target.'cfg(target_arch = "aarch64")'.dependencies] -cortex-a = { version = "8.x.x" } +aarch64-cpu = { version = "9.x.x" } ##-------------------------------------------------------------------------------------------------- ## Testing diff --git a/17_kernel_symbols/kernel/src/_arch/aarch64/cpu.rs b/17_kernel_symbols/kernel/src/_arch/aarch64/cpu.rs index 66da661c..7eb7f010 100644 --- a/17_kernel_symbols/kernel/src/_arch/aarch64/cpu.rs +++ b/17_kernel_symbols/kernel/src/_arch/aarch64/cpu.rs @@ -11,7 +11,7 @@ //! //! crate::cpu::arch_cpu -use cortex_a::asm; +use aarch64_cpu::asm; //-------------------------------------------------------------------------------------------------- // Public Code diff --git a/17_kernel_symbols/kernel/src/_arch/aarch64/cpu/boot.rs b/17_kernel_symbols/kernel/src/_arch/aarch64/cpu/boot.rs index 293d4608..2cad1ab6 100644 --- a/17_kernel_symbols/kernel/src/_arch/aarch64/cpu/boot.rs +++ b/17_kernel_symbols/kernel/src/_arch/aarch64/cpu/boot.rs @@ -12,8 +12,8 @@ //! crate::cpu::boot::arch_boot use crate::{memory, memory::Address}; +use aarch64_cpu::{asm, registers::*}; use core::arch::global_asm; -use cortex_a::{asm, registers::*}; use tock_registers::interfaces::Writeable; // Assembly counterpart to this file. diff --git a/17_kernel_symbols/kernel/src/_arch/aarch64/cpu/smp.rs b/17_kernel_symbols/kernel/src/_arch/aarch64/cpu/smp.rs index 351fde62..9d304d65 100644 --- a/17_kernel_symbols/kernel/src/_arch/aarch64/cpu/smp.rs +++ b/17_kernel_symbols/kernel/src/_arch/aarch64/cpu/smp.rs @@ -11,7 +11,7 @@ //! //! crate::cpu::smp::arch_smp -use cortex_a::registers::*; +use aarch64_cpu::registers::*; use tock_registers::interfaces::Readable; //-------------------------------------------------------------------------------------------------- diff --git a/17_kernel_symbols/kernel/src/_arch/aarch64/exception.rs b/17_kernel_symbols/kernel/src/_arch/aarch64/exception.rs index 1d720f3e..926d6d38 100644 --- a/17_kernel_symbols/kernel/src/_arch/aarch64/exception.rs +++ b/17_kernel_symbols/kernel/src/_arch/aarch64/exception.rs @@ -12,8 +12,8 @@ //! crate::exception::arch_exception use crate::{exception, memory, symbols}; +use aarch64_cpu::{asm::barrier, registers::*}; use core::{arch::global_asm, cell::UnsafeCell, fmt}; -use cortex_a::{asm::barrier, registers::*}; use tock_registers::{ interfaces::{Readable, Writeable}, registers::InMemoryRegister, diff --git a/17_kernel_symbols/kernel/src/_arch/aarch64/exception/asynchronous.rs b/17_kernel_symbols/kernel/src/_arch/aarch64/exception/asynchronous.rs index cf6f97ac..f545a3e1 100644 --- a/17_kernel_symbols/kernel/src/_arch/aarch64/exception/asynchronous.rs +++ b/17_kernel_symbols/kernel/src/_arch/aarch64/exception/asynchronous.rs @@ -11,8 +11,8 @@ //! //! crate::exception::asynchronous::arch_asynchronous +use aarch64_cpu::registers::*; use core::arch::asm; -use cortex_a::registers::*; use tock_registers::interfaces::{Readable, Writeable}; //-------------------------------------------------------------------------------------------------- diff --git a/17_kernel_symbols/kernel/src/_arch/aarch64/memory/mmu.rs b/17_kernel_symbols/kernel/src/_arch/aarch64/memory/mmu.rs index 3d6c18b7..74a71d11 100644 --- a/17_kernel_symbols/kernel/src/_arch/aarch64/memory/mmu.rs +++ b/17_kernel_symbols/kernel/src/_arch/aarch64/memory/mmu.rs @@ -17,8 +17,8 @@ use crate::{ bsp, memory, memory::{mmu::TranslationGranule, Address, Physical}, }; +use aarch64_cpu::{asm::barrier, registers::*}; use core::intrinsics::unlikely; -use cortex_a::{asm::barrier, registers::*}; use tock_registers::interfaces::{ReadWriteable, Readable, Writeable}; //-------------------------------------------------------------------------------------------------- diff --git a/17_kernel_symbols/kernel/src/_arch/aarch64/time.rs b/17_kernel_symbols/kernel/src/_arch/aarch64/time.rs index 1e2efbec..94d02379 100644 --- a/17_kernel_symbols/kernel/src/_arch/aarch64/time.rs +++ b/17_kernel_symbols/kernel/src/_arch/aarch64/time.rs @@ -12,12 +12,12 @@ //! crate::time::arch_time use crate::warn; +use aarch64_cpu::{asm::barrier, registers::*}; use core::{ num::{NonZeroU128, NonZeroU32, NonZeroU64}, ops::{Add, Div}, time::Duration, }; -use cortex_a::{asm::barrier, registers::*}; use tock_registers::interfaces::Readable; //-------------------------------------------------------------------------------------------------- diff --git a/18_backtrace/Cargo.lock b/18_backtrace/Cargo.lock index 2b51ab72..701f10f1 100644 --- a/18_backtrace/Cargo.lock +++ b/18_backtrace/Cargo.lock @@ -3,10 +3,10 @@ version = 3 [[package]] -name = "cortex-a" -version = "8.0.0" +name = "aarch64-cpu" +version = "9.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cd4524931a4e0ec50ae91f0d55f571f31ffe11dd9ce2f9905b8343c018c25bb" +checksum = "3aceb88e55ba626a5479279268d009a92d9d00eacce0de1b8c236c7ad31b7225" dependencies = [ "tock-registers", ] @@ -26,7 +26,7 @@ dependencies = [ name = "mingo" version = "0.18.0" dependencies = [ - "cortex-a", + "aarch64-cpu", "debug-symbol-types", "qemu-exit", "test-macros", diff --git a/18_backtrace/README.md b/18_backtrace/README.md index 837d0161..542fdfbb 100644 --- a/18_backtrace/README.md +++ b/18_backtrace/README.md @@ -415,7 +415,7 @@ diff -uNr 17_kernel_symbols/kernel/src/_arch/aarch64/backtrace.rs 18_backtrace/k + backtrace::BacktraceItem, + memory::{Address, Virtual}, +}; -+use cortex_a::registers::*; ++use aarch64_cpu::registers::*; +use tock_registers::interfaces::Readable; + +//-------------------------------------------------------------------------------------------------- @@ -538,18 +538,18 @@ diff -uNr 17_kernel_symbols/kernel/src/_arch/aarch64/backtrace.rs 18_backtrace/k diff -uNr 17_kernel_symbols/kernel/src/_arch/aarch64/cpu/boot.rs 18_backtrace/kernel/src/_arch/aarch64/cpu/boot.rs --- 17_kernel_symbols/kernel/src/_arch/aarch64/cpu/boot.rs +++ 18_backtrace/kernel/src/_arch/aarch64/cpu/boot.rs -@@ -12,7 +12,10 @@ - //! crate::cpu::boot::arch_boot +@@ -13,7 +13,10 @@ use crate::{memory, memory::Address}; + use aarch64_cpu::{asm, registers::*}; -use core::arch::global_asm; +use core::{ + arch::global_asm, + sync::atomic::{compiler_fence, Ordering}, +}; - use cortex_a::{asm, registers::*}; use tock_registers::interfaces::Writeable; + // Assembly counterpart to this file. @@ -67,6 +70,18 @@ SP_EL1.set(virt_boot_core_stack_end_exclusive_addr); } diff --git a/18_backtrace/kernel/Cargo.toml b/18_backtrace/kernel/Cargo.toml index 5a443538..bba97b8d 100644 --- a/18_backtrace/kernel/Cargo.toml +++ b/18_backtrace/kernel/Cargo.toml @@ -24,7 +24,7 @@ qemu-exit = { version = "3.x.x", optional = true } # Platform specific dependencies [target.'cfg(target_arch = "aarch64")'.dependencies] -cortex-a = { version = "8.x.x" } +aarch64-cpu = { version = "9.x.x" } ##-------------------------------------------------------------------------------------------------- ## Testing diff --git a/18_backtrace/kernel/src/_arch/aarch64/backtrace.rs b/18_backtrace/kernel/src/_arch/aarch64/backtrace.rs index e8860984..3511c918 100644 --- a/18_backtrace/kernel/src/_arch/aarch64/backtrace.rs +++ b/18_backtrace/kernel/src/_arch/aarch64/backtrace.rs @@ -15,7 +15,7 @@ use crate::{ backtrace::BacktraceItem, memory::{Address, Virtual}, }; -use cortex_a::registers::*; +use aarch64_cpu::registers::*; use tock_registers::interfaces::Readable; //-------------------------------------------------------------------------------------------------- diff --git a/18_backtrace/kernel/src/_arch/aarch64/cpu.rs b/18_backtrace/kernel/src/_arch/aarch64/cpu.rs index 66da661c..7eb7f010 100644 --- a/18_backtrace/kernel/src/_arch/aarch64/cpu.rs +++ b/18_backtrace/kernel/src/_arch/aarch64/cpu.rs @@ -11,7 +11,7 @@ //! //! crate::cpu::arch_cpu -use cortex_a::asm; +use aarch64_cpu::asm; //-------------------------------------------------------------------------------------------------- // Public Code diff --git a/18_backtrace/kernel/src/_arch/aarch64/cpu/boot.rs b/18_backtrace/kernel/src/_arch/aarch64/cpu/boot.rs index 15ab92b6..d9662d3a 100644 --- a/18_backtrace/kernel/src/_arch/aarch64/cpu/boot.rs +++ b/18_backtrace/kernel/src/_arch/aarch64/cpu/boot.rs @@ -12,11 +12,11 @@ //! crate::cpu::boot::arch_boot use crate::{memory, memory::Address}; +use aarch64_cpu::{asm, registers::*}; use core::{ arch::global_asm, sync::atomic::{compiler_fence, Ordering}, }; -use cortex_a::{asm, registers::*}; use tock_registers::interfaces::Writeable; // Assembly counterpart to this file. diff --git a/18_backtrace/kernel/src/_arch/aarch64/cpu/smp.rs b/18_backtrace/kernel/src/_arch/aarch64/cpu/smp.rs index 351fde62..9d304d65 100644 --- a/18_backtrace/kernel/src/_arch/aarch64/cpu/smp.rs +++ b/18_backtrace/kernel/src/_arch/aarch64/cpu/smp.rs @@ -11,7 +11,7 @@ //! //! crate::cpu::smp::arch_smp -use cortex_a::registers::*; +use aarch64_cpu::registers::*; use tock_registers::interfaces::Readable; //-------------------------------------------------------------------------------------------------- diff --git a/18_backtrace/kernel/src/_arch/aarch64/exception.rs b/18_backtrace/kernel/src/_arch/aarch64/exception.rs index e03e382f..a8bc0d2f 100644 --- a/18_backtrace/kernel/src/_arch/aarch64/exception.rs +++ b/18_backtrace/kernel/src/_arch/aarch64/exception.rs @@ -12,8 +12,8 @@ //! crate::exception::arch_exception use crate::{exception, memory, symbols}; +use aarch64_cpu::{asm::barrier, registers::*}; use core::{arch::global_asm, cell::UnsafeCell, fmt}; -use cortex_a::{asm::barrier, registers::*}; use tock_registers::{ interfaces::{Readable, Writeable}, registers::InMemoryRegister, diff --git a/18_backtrace/kernel/src/_arch/aarch64/exception/asynchronous.rs b/18_backtrace/kernel/src/_arch/aarch64/exception/asynchronous.rs index cf6f97ac..f545a3e1 100644 --- a/18_backtrace/kernel/src/_arch/aarch64/exception/asynchronous.rs +++ b/18_backtrace/kernel/src/_arch/aarch64/exception/asynchronous.rs @@ -11,8 +11,8 @@ //! //! crate::exception::asynchronous::arch_asynchronous +use aarch64_cpu::registers::*; use core::arch::asm; -use cortex_a::registers::*; use tock_registers::interfaces::{Readable, Writeable}; //-------------------------------------------------------------------------------------------------- diff --git a/18_backtrace/kernel/src/_arch/aarch64/memory/mmu.rs b/18_backtrace/kernel/src/_arch/aarch64/memory/mmu.rs index 3d6c18b7..74a71d11 100644 --- a/18_backtrace/kernel/src/_arch/aarch64/memory/mmu.rs +++ b/18_backtrace/kernel/src/_arch/aarch64/memory/mmu.rs @@ -17,8 +17,8 @@ use crate::{ bsp, memory, memory::{mmu::TranslationGranule, Address, Physical}, }; +use aarch64_cpu::{asm::barrier, registers::*}; use core::intrinsics::unlikely; -use cortex_a::{asm::barrier, registers::*}; use tock_registers::interfaces::{ReadWriteable, Readable, Writeable}; //-------------------------------------------------------------------------------------------------- diff --git a/18_backtrace/kernel/src/_arch/aarch64/time.rs b/18_backtrace/kernel/src/_arch/aarch64/time.rs index 1e2efbec..94d02379 100644 --- a/18_backtrace/kernel/src/_arch/aarch64/time.rs +++ b/18_backtrace/kernel/src/_arch/aarch64/time.rs @@ -12,12 +12,12 @@ //! crate::time::arch_time use crate::warn; +use aarch64_cpu::{asm::barrier, registers::*}; use core::{ num::{NonZeroU128, NonZeroU32, NonZeroU64}, ops::{Add, Div}, time::Duration, }; -use cortex_a::{asm::barrier, registers::*}; use tock_registers::interfaces::Readable; //-------------------------------------------------------------------------------------------------- diff --git a/19_kernel_heap/Cargo.lock b/19_kernel_heap/Cargo.lock index eb80ffea..0f642903 100644 --- a/19_kernel_heap/Cargo.lock +++ b/19_kernel_heap/Cargo.lock @@ -3,10 +3,10 @@ version = 3 [[package]] -name = "cortex-a" -version = "8.0.0" +name = "aarch64-cpu" +version = "9.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cd4524931a4e0ec50ae91f0d55f571f31ffe11dd9ce2f9905b8343c018c25bb" +checksum = "3aceb88e55ba626a5479279268d009a92d9d00eacce0de1b8c236c7ad31b7225" dependencies = [ "tock-registers", ] @@ -32,7 +32,7 @@ checksum = "e322f259d225fbae43a1b053b2dc6a5968a6bdf8b205f5de684dab485b95030e" name = "mingo" version = "0.19.0" dependencies = [ - "cortex-a", + "aarch64-cpu", "debug-symbol-types", "linked_list_allocator", "qemu-exit", diff --git a/19_kernel_heap/kernel/Cargo.lock b/19_kernel_heap/kernel/Cargo.lock deleted file mode 100644 index 9149faf0..00000000 --- a/19_kernel_heap/kernel/Cargo.lock +++ /dev/null @@ -1,96 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "cortex-a" -version = "7.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27bd91f65ccd348bb2d043d98c5b34af141ecef7f102147f59bf5898f6e734ad" -dependencies = [ - "tock-registers", -] - -[[package]] -name = "debug-symbol-types" -version = "0.1.0" - -[[package]] -name = "linked_list_allocator" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "549ce1740e46b291953c4340adcd74c59bcf4308f4cac050fd33ba91b7168f4a" - -[[package]] -name = "mingo" -version = "0.19.0" -dependencies = [ - "cortex-a", - "debug-symbol-types", - "linked_list_allocator", - "qemu-exit", - "test-macros", - "test-types", - "tock-registers", -] - -[[package]] -name = "proc-macro2" -version = "1.0.38" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9027b48e9d4c9175fa2218adf3557f91c1137021739951d4932f5f8268ac48aa" -dependencies = [ - "unicode-xid", -] - -[[package]] -name = "qemu-exit" -version = "3.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ff023245bfcc73fb890e1f8d5383825b3131cc920020a5c487d6f113dfc428a" - -[[package]] -name = "quote" -version = "1.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "syn" -version = "1.0.94" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a07e33e919ebcd69113d5be0e4d70c5707004ff45188910106854f38b960df4a" -dependencies = [ - "proc-macro2", - "quote", - "unicode-xid", -] - -[[package]] -name = "test-macros" -version = "0.1.0" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "test-types", -] - -[[package]] -name = "test-types" -version = "0.1.0" - -[[package]] -name = "tock-registers" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ee8fba06c1f4d0b396ef61a54530bb6b28f0dc61c38bc8bc5a5a48161e6282e" - -[[package]] -name = "unicode-xid" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "957e51f3646910546462e67d5f7599b9e4fb8acdd304b087a6494730f9eebf04" diff --git a/19_kernel_heap/kernel/Cargo.toml b/19_kernel_heap/kernel/Cargo.toml index bccd0882..03ebfc02 100644 --- a/19_kernel_heap/kernel/Cargo.toml +++ b/19_kernel_heap/kernel/Cargo.toml @@ -26,7 +26,7 @@ qemu-exit = { version = "3.x.x", optional = true } # Platform specific dependencies [target.'cfg(target_arch = "aarch64")'.dependencies] -cortex-a = { version = "8.x.x" } +aarch64-cpu = { version = "9.x.x" } ##-------------------------------------------------------------------------------------------------- ## Testing diff --git a/19_kernel_heap/kernel/src/_arch/aarch64/backtrace.rs b/19_kernel_heap/kernel/src/_arch/aarch64/backtrace.rs index e8860984..3511c918 100644 --- a/19_kernel_heap/kernel/src/_arch/aarch64/backtrace.rs +++ b/19_kernel_heap/kernel/src/_arch/aarch64/backtrace.rs @@ -15,7 +15,7 @@ use crate::{ backtrace::BacktraceItem, memory::{Address, Virtual}, }; -use cortex_a::registers::*; +use aarch64_cpu::registers::*; use tock_registers::interfaces::Readable; //-------------------------------------------------------------------------------------------------- diff --git a/19_kernel_heap/kernel/src/_arch/aarch64/cpu.rs b/19_kernel_heap/kernel/src/_arch/aarch64/cpu.rs index 66da661c..7eb7f010 100644 --- a/19_kernel_heap/kernel/src/_arch/aarch64/cpu.rs +++ b/19_kernel_heap/kernel/src/_arch/aarch64/cpu.rs @@ -11,7 +11,7 @@ //! //! crate::cpu::arch_cpu -use cortex_a::asm; +use aarch64_cpu::asm; //-------------------------------------------------------------------------------------------------- // Public Code diff --git a/19_kernel_heap/kernel/src/_arch/aarch64/cpu/boot.rs b/19_kernel_heap/kernel/src/_arch/aarch64/cpu/boot.rs index 15ab92b6..d9662d3a 100644 --- a/19_kernel_heap/kernel/src/_arch/aarch64/cpu/boot.rs +++ b/19_kernel_heap/kernel/src/_arch/aarch64/cpu/boot.rs @@ -12,11 +12,11 @@ //! crate::cpu::boot::arch_boot use crate::{memory, memory::Address}; +use aarch64_cpu::{asm, registers::*}; use core::{ arch::global_asm, sync::atomic::{compiler_fence, Ordering}, }; -use cortex_a::{asm, registers::*}; use tock_registers::interfaces::Writeable; // Assembly counterpart to this file. diff --git a/19_kernel_heap/kernel/src/_arch/aarch64/cpu/smp.rs b/19_kernel_heap/kernel/src/_arch/aarch64/cpu/smp.rs index 351fde62..9d304d65 100644 --- a/19_kernel_heap/kernel/src/_arch/aarch64/cpu/smp.rs +++ b/19_kernel_heap/kernel/src/_arch/aarch64/cpu/smp.rs @@ -11,7 +11,7 @@ //! //! crate::cpu::smp::arch_smp -use cortex_a::registers::*; +use aarch64_cpu::registers::*; use tock_registers::interfaces::Readable; //-------------------------------------------------------------------------------------------------- diff --git a/19_kernel_heap/kernel/src/_arch/aarch64/exception.rs b/19_kernel_heap/kernel/src/_arch/aarch64/exception.rs index e03e382f..a8bc0d2f 100644 --- a/19_kernel_heap/kernel/src/_arch/aarch64/exception.rs +++ b/19_kernel_heap/kernel/src/_arch/aarch64/exception.rs @@ -12,8 +12,8 @@ //! crate::exception::arch_exception use crate::{exception, memory, symbols}; +use aarch64_cpu::{asm::barrier, registers::*}; use core::{arch::global_asm, cell::UnsafeCell, fmt}; -use cortex_a::{asm::barrier, registers::*}; use tock_registers::{ interfaces::{Readable, Writeable}, registers::InMemoryRegister, diff --git a/19_kernel_heap/kernel/src/_arch/aarch64/exception/asynchronous.rs b/19_kernel_heap/kernel/src/_arch/aarch64/exception/asynchronous.rs index cf6f97ac..f545a3e1 100644 --- a/19_kernel_heap/kernel/src/_arch/aarch64/exception/asynchronous.rs +++ b/19_kernel_heap/kernel/src/_arch/aarch64/exception/asynchronous.rs @@ -11,8 +11,8 @@ //! //! crate::exception::asynchronous::arch_asynchronous +use aarch64_cpu::registers::*; use core::arch::asm; -use cortex_a::registers::*; use tock_registers::interfaces::{Readable, Writeable}; //-------------------------------------------------------------------------------------------------- diff --git a/19_kernel_heap/kernel/src/_arch/aarch64/memory/mmu.rs b/19_kernel_heap/kernel/src/_arch/aarch64/memory/mmu.rs index 3d6c18b7..74a71d11 100644 --- a/19_kernel_heap/kernel/src/_arch/aarch64/memory/mmu.rs +++ b/19_kernel_heap/kernel/src/_arch/aarch64/memory/mmu.rs @@ -17,8 +17,8 @@ use crate::{ bsp, memory, memory::{mmu::TranslationGranule, Address, Physical}, }; +use aarch64_cpu::{asm::barrier, registers::*}; use core::intrinsics::unlikely; -use cortex_a::{asm::barrier, registers::*}; use tock_registers::interfaces::{ReadWriteable, Readable, Writeable}; //-------------------------------------------------------------------------------------------------- diff --git a/19_kernel_heap/kernel/src/_arch/aarch64/time.rs b/19_kernel_heap/kernel/src/_arch/aarch64/time.rs index 1e2efbec..94d02379 100644 --- a/19_kernel_heap/kernel/src/_arch/aarch64/time.rs +++ b/19_kernel_heap/kernel/src/_arch/aarch64/time.rs @@ -12,12 +12,12 @@ //! crate::time::arch_time use crate::warn; +use aarch64_cpu::{asm::barrier, registers::*}; use core::{ num::{NonZeroU128, NonZeroU32, NonZeroU64}, ops::{Add, Div}, time::Duration, }; -use cortex_a::{asm::barrier, registers::*}; use tock_registers::interfaces::Readable; //-------------------------------------------------------------------------------------------------- diff --git a/20_timer_callbacks/Cargo.lock b/20_timer_callbacks/Cargo.lock index 8f9eae58..754ed74d 100644 --- a/20_timer_callbacks/Cargo.lock +++ b/20_timer_callbacks/Cargo.lock @@ -3,10 +3,10 @@ version = 3 [[package]] -name = "cortex-a" -version = "8.0.0" +name = "aarch64-cpu" +version = "9.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cd4524931a4e0ec50ae91f0d55f571f31ffe11dd9ce2f9905b8343c018c25bb" +checksum = "3aceb88e55ba626a5479279268d009a92d9d00eacce0de1b8c236c7ad31b7225" dependencies = [ "tock-registers", ] @@ -32,7 +32,7 @@ checksum = "e322f259d225fbae43a1b053b2dc6a5968a6bdf8b205f5de684dab485b95030e" name = "mingo" version = "0.20.0" dependencies = [ - "cortex-a", + "aarch64-cpu", "debug-symbol-types", "linked_list_allocator", "qemu-exit", diff --git a/20_timer_callbacks/README.md b/20_timer_callbacks/README.md index 7d944b99..da5a5510 100644 --- a/20_timer_callbacks/README.md +++ b/20_timer_callbacks/README.md @@ -40,12 +40,12 @@ diff -uNr 19_kernel_heap/kernel/src/_arch/aarch64/time.rs 20_timer_callbacks/ker + bsp::{self, exception}, + warn, +}; + use aarch64_cpu::{asm::barrier, registers::*}; use core::{ num::{NonZeroU128, NonZeroU32, NonZeroU64}, ops::{Add, Div}, time::Duration, }; - use cortex_a::{asm::barrier, registers::*}; -use tock_registers::interfaces::Readable; +use tock_registers::interfaces::{ReadWriteable, Readable, Writeable}; diff --git a/20_timer_callbacks/kernel/Cargo.lock b/20_timer_callbacks/kernel/Cargo.lock deleted file mode 100644 index 740209d0..00000000 --- a/20_timer_callbacks/kernel/Cargo.lock +++ /dev/null @@ -1,96 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "cortex-a" -version = "8.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cd4524931a4e0ec50ae91f0d55f571f31ffe11dd9ce2f9905b8343c018c25bb" -dependencies = [ - "tock-registers", -] - -[[package]] -name = "debug-symbol-types" -version = "0.1.0" - -[[package]] -name = "linked_list_allocator" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e322f259d225fbae43a1b053b2dc6a5968a6bdf8b205f5de684dab485b95030e" - -[[package]] -name = "mingo" -version = "0.20.0" -dependencies = [ - "cortex-a", - "debug-symbol-types", - "linked_list_allocator", - "qemu-exit", - "test-macros", - "test-types", - "tock-registers", -] - -[[package]] -name = "proc-macro2" -version = "1.0.38" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9027b48e9d4c9175fa2218adf3557f91c1137021739951d4932f5f8268ac48aa" -dependencies = [ - "unicode-xid", -] - -[[package]] -name = "qemu-exit" -version = "3.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ff023245bfcc73fb890e1f8d5383825b3131cc920020a5c487d6f113dfc428a" - -[[package]] -name = "quote" -version = "1.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "syn" -version = "1.0.94" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a07e33e919ebcd69113d5be0e4d70c5707004ff45188910106854f38b960df4a" -dependencies = [ - "proc-macro2", - "quote", - "unicode-xid", -] - -[[package]] -name = "test-macros" -version = "0.1.0" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "test-types", -] - -[[package]] -name = "test-types" -version = "0.1.0" - -[[package]] -name = "tock-registers" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "696941a0aee7e276a165a978b37918fd5d22c55c3d6bda197813070ca9c0f21c" - -[[package]] -name = "unicode-xid" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "957e51f3646910546462e67d5f7599b9e4fb8acdd304b087a6494730f9eebf04" diff --git a/20_timer_callbacks/kernel/Cargo.toml b/20_timer_callbacks/kernel/Cargo.toml index e127a857..87c9cbb6 100644 --- a/20_timer_callbacks/kernel/Cargo.toml +++ b/20_timer_callbacks/kernel/Cargo.toml @@ -26,7 +26,7 @@ qemu-exit = { version = "3.x.x", optional = true } # Platform specific dependencies [target.'cfg(target_arch = "aarch64")'.dependencies] -cortex-a = { version = "8.x.x" } +aarch64-cpu = { version = "9.x.x" } ##-------------------------------------------------------------------------------------------------- ## Testing diff --git a/20_timer_callbacks/kernel/src/_arch/aarch64/backtrace.rs b/20_timer_callbacks/kernel/src/_arch/aarch64/backtrace.rs index e8860984..3511c918 100644 --- a/20_timer_callbacks/kernel/src/_arch/aarch64/backtrace.rs +++ b/20_timer_callbacks/kernel/src/_arch/aarch64/backtrace.rs @@ -15,7 +15,7 @@ use crate::{ backtrace::BacktraceItem, memory::{Address, Virtual}, }; -use cortex_a::registers::*; +use aarch64_cpu::registers::*; use tock_registers::interfaces::Readable; //-------------------------------------------------------------------------------------------------- diff --git a/20_timer_callbacks/kernel/src/_arch/aarch64/cpu.rs b/20_timer_callbacks/kernel/src/_arch/aarch64/cpu.rs index 66da661c..7eb7f010 100644 --- a/20_timer_callbacks/kernel/src/_arch/aarch64/cpu.rs +++ b/20_timer_callbacks/kernel/src/_arch/aarch64/cpu.rs @@ -11,7 +11,7 @@ //! //! crate::cpu::arch_cpu -use cortex_a::asm; +use aarch64_cpu::asm; //-------------------------------------------------------------------------------------------------- // Public Code diff --git a/20_timer_callbacks/kernel/src/_arch/aarch64/cpu/boot.rs b/20_timer_callbacks/kernel/src/_arch/aarch64/cpu/boot.rs index 15ab92b6..d9662d3a 100644 --- a/20_timer_callbacks/kernel/src/_arch/aarch64/cpu/boot.rs +++ b/20_timer_callbacks/kernel/src/_arch/aarch64/cpu/boot.rs @@ -12,11 +12,11 @@ //! crate::cpu::boot::arch_boot use crate::{memory, memory::Address}; +use aarch64_cpu::{asm, registers::*}; use core::{ arch::global_asm, sync::atomic::{compiler_fence, Ordering}, }; -use cortex_a::{asm, registers::*}; use tock_registers::interfaces::Writeable; // Assembly counterpart to this file. diff --git a/20_timer_callbacks/kernel/src/_arch/aarch64/cpu/smp.rs b/20_timer_callbacks/kernel/src/_arch/aarch64/cpu/smp.rs index 351fde62..9d304d65 100644 --- a/20_timer_callbacks/kernel/src/_arch/aarch64/cpu/smp.rs +++ b/20_timer_callbacks/kernel/src/_arch/aarch64/cpu/smp.rs @@ -11,7 +11,7 @@ //! //! crate::cpu::smp::arch_smp -use cortex_a::registers::*; +use aarch64_cpu::registers::*; use tock_registers::interfaces::Readable; //-------------------------------------------------------------------------------------------------- diff --git a/20_timer_callbacks/kernel/src/_arch/aarch64/exception.rs b/20_timer_callbacks/kernel/src/_arch/aarch64/exception.rs index e03e382f..a8bc0d2f 100644 --- a/20_timer_callbacks/kernel/src/_arch/aarch64/exception.rs +++ b/20_timer_callbacks/kernel/src/_arch/aarch64/exception.rs @@ -12,8 +12,8 @@ //! crate::exception::arch_exception use crate::{exception, memory, symbols}; +use aarch64_cpu::{asm::barrier, registers::*}; use core::{arch::global_asm, cell::UnsafeCell, fmt}; -use cortex_a::{asm::barrier, registers::*}; use tock_registers::{ interfaces::{Readable, Writeable}, registers::InMemoryRegister, diff --git a/20_timer_callbacks/kernel/src/_arch/aarch64/exception/asynchronous.rs b/20_timer_callbacks/kernel/src/_arch/aarch64/exception/asynchronous.rs index cf6f97ac..f545a3e1 100644 --- a/20_timer_callbacks/kernel/src/_arch/aarch64/exception/asynchronous.rs +++ b/20_timer_callbacks/kernel/src/_arch/aarch64/exception/asynchronous.rs @@ -11,8 +11,8 @@ //! //! crate::exception::asynchronous::arch_asynchronous +use aarch64_cpu::registers::*; use core::arch::asm; -use cortex_a::registers::*; use tock_registers::interfaces::{Readable, Writeable}; //-------------------------------------------------------------------------------------------------- diff --git a/20_timer_callbacks/kernel/src/_arch/aarch64/memory/mmu.rs b/20_timer_callbacks/kernel/src/_arch/aarch64/memory/mmu.rs index 3d6c18b7..74a71d11 100644 --- a/20_timer_callbacks/kernel/src/_arch/aarch64/memory/mmu.rs +++ b/20_timer_callbacks/kernel/src/_arch/aarch64/memory/mmu.rs @@ -17,8 +17,8 @@ use crate::{ bsp, memory, memory::{mmu::TranslationGranule, Address, Physical}, }; +use aarch64_cpu::{asm::barrier, registers::*}; use core::intrinsics::unlikely; -use cortex_a::{asm::barrier, registers::*}; use tock_registers::interfaces::{ReadWriteable, Readable, Writeable}; //-------------------------------------------------------------------------------------------------- diff --git a/20_timer_callbacks/kernel/src/_arch/aarch64/time.rs b/20_timer_callbacks/kernel/src/_arch/aarch64/time.rs index 5479deb4..2807bc32 100644 --- a/20_timer_callbacks/kernel/src/_arch/aarch64/time.rs +++ b/20_timer_callbacks/kernel/src/_arch/aarch64/time.rs @@ -15,12 +15,12 @@ use crate::{ bsp::{self, exception}, warn, }; +use aarch64_cpu::{asm::barrier, registers::*}; use core::{ num::{NonZeroU128, NonZeroU32, NonZeroU64}, ops::{Add, Div}, time::Duration, }; -use cortex_a::{asm::barrier, registers::*}; use tock_registers::interfaces::{ReadWriteable, Readable, Writeable}; //-------------------------------------------------------------------------------------------------- diff --git a/X1_JTAG_boot/Cargo.lock b/X1_JTAG_boot/Cargo.lock index bcfb442a..9020b4f9 100644 --- a/X1_JTAG_boot/Cargo.lock +++ b/X1_JTAG_boot/Cargo.lock @@ -3,10 +3,10 @@ version = 3 [[package]] -name = "cortex-a" -version = "8.0.0" +name = "aarch64-cpu" +version = "9.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cd4524931a4e0ec50ae91f0d55f571f31ffe11dd9ce2f9905b8343c018c25bb" +checksum = "3aceb88e55ba626a5479279268d009a92d9d00eacce0de1b8c236c7ad31b7225" dependencies = [ "tock-registers", ] @@ -15,7 +15,7 @@ dependencies = [ name = "mingo" version = "0.8.0" dependencies = [ - "cortex-a", + "aarch64-cpu", "tock-registers", ] diff --git a/X1_JTAG_boot/Cargo.toml b/X1_JTAG_boot/Cargo.toml index 55963c38..e310c371 100644 --- a/X1_JTAG_boot/Cargo.toml +++ b/X1_JTAG_boot/Cargo.toml @@ -27,4 +27,4 @@ tock-registers = { version = "0.8.x", default-features = false, features = ["reg # Platform specific dependencies [target.'cfg(target_arch = "aarch64")'.dependencies] -cortex-a = { version = "8.x.x" } +aarch64-cpu = { version = "9.x.x" } diff --git a/X1_JTAG_boot/jtag_boot_rpi3.img b/X1_JTAG_boot/jtag_boot_rpi3.img index 8c67b2dd87ca95ac69ab1567d94595d9cb5bc53f..f472e76666034632af74963b83585ad4e6ebcece 100755 GIT binary patch literal 10216 zcmeHNeNV4LZZFH7owG~Z2VvJ2J)po7Uj1RM#1w2WDF%zE+y!q|> zp-AJjYt8&QXDvAQ?6dbi`|Q2X-uoOl%siKEaq@l>&%RK?Op!(ttFub{<)KG73-w$% zdd5W>7~s$CJUSJN%_F!x9Rr*N>AUeZvzWpUU#@3X6>lM9g9(gf)MG9Nd^V$HC9szy zCjHs~4e|9?jBn~=#H4cGVfyWEMZdDLJqL!5;o+==M*Mc z`f68WerX1Cjsqv+X5RUPC(B*CRJ`O3`Qm&PFB!PYmL)g|*9RKHzYhG!!^}GeG~$B3 zS~GBnC*j&_(wzAf$xef24EVc=4m8(66DeU{@CdHv#DD;L(nWw{gY}#kNs5=FZSgFa z6wjh8fz@5-&7nZ%kZ0?IEG@!rxg&f^{y3i;O6KI~-fVerYh0dt61rLwFMGe2%F@pC z@Lg@0EX@vktQTePnX`P?FEQ@O%yE_jwkAdP()@+xInIDM$Jtw2(KQ5kRVoV_JTG#2 z?tcf*Dv<>PsX0yqo&xw4z`vfF;jBtw!3aMm|IXa)l`h%`$#gNc()}jz!n`#fb_tTL zVmznXC(N^;DWR`+I+s_D!=@Z#C&KTrpl!$-w@;U?ZL9o4USi0t>c6Uj{r`*Vk6) z%a+W7hzsoOg7QdBl4!RZM3UMrI*l(KW z6~lgye2VSfHGR76$cA^<`(ycuzli;f@+_2(Jymg%+s;vsJ&CY6Y*|vwx@2y5jt?@4 zq9zmJzA?Q-m7n5^;VU!O6TypgWd%P`0575!n5s)(Y>CUz2g82ve5(w!u@!P*m=Sx8 zT_Qd&q-ya^e3MziU*nW;E(?x+mnnI$!RQg@eIibaQ^ZSp>TiBE^qpfj`a0jbapEYE0v%b$C-$wv*=hZ zr;OwL{4N&zCdEWLThsGd)U4`|3$3227%uslI7vLtzs@Z0#Id?Id*D|eSpT8+g5|q6 zCgC3!Uj6NjbWprWtK?Q)SBU1E_r_G zBc=_u=Thd|o=e@ZuyW3P+oQI?4L&vGSiCTBjY|vU;yl@y>|K-~d&~DRZ>~x9KAy%d zmG(1l#kZKZ{3YhCoQl=0`8o^M@8u?sB0gt8uaUUES{hTlTKiek22~c3UFz>inZFe> z_4lN1*kezbKLOc}b4dZjoKXJa{6ID0T@5FDDHi_gq}6j`#OkTHv&n1VOS-K(%TkvC zAO3P_59URzWsf%p#%T`lWuRXUdLPzWi}`h+r#X_R6mfYYCte8iLMV>i>(f)uzN&oE z$tkzDn3P-fyz*a9#wjcuVk6x3#))dwyWFE}1#xwsAasm3T zv*>Tbeje=S^b=*uHGXdXJN&#*n9mB0@R^}akXPoI%L9J_EdOTpqmZ!zvX(>UGRR)4 zOg;PaqvVT6=EzZvE+ce}PY>M>w}Dx&47Qdj0^&CDHP-x*OCAjK*`Xgp))77@bkxNL zPhW$rA%pZuqWg=9EO;e>O-hitGM(1S4sqbYxRNV!EYbBFoY~v_eA01-54bI{(&1H8 zrNe)K-cN5XQ=SFv6xKjL8HQc+R37R+^9>$92ahvl6)(VJg3?y9sZ%=kbO#FZ)=F`M)M8KdWCZAO#JCBKZ30}*xZD5d4=Mx z>W7GZEJw${H(*K+tVMhrhfI`XCwNP~oikq;$Cbx%3Cft`qOBL4X$2zpu@pTy+_G0~YnasIW zUvmh!cIdf;OOKp`pY3TK^VD;kV-LQ^p%)&yI2()MJ0n!jvB_@J?gKBG_8fRU2Q>-u zM(-{*xe+`_hr?Oy<@4m7q*&` zB26T-jZNmEKZE`qlEIV|P(*qEK`tY*lcze+8ghZQ^>*)mS|@^^e)#DGbpQ3qtDYC3 zhkoems=i(fecR>0f#V{Zfua7UW*wqJ%MxdU+zCp6302-zx?6>hgno}_ z{02;O0v*r^$w;`poH;@|IW|>3ti-XC$Dxz;TuR^~_HqU|6Tdl_Lq3X{qwcNvAusLe z_~pF^N+6$1FmVPfg-ss9Iesf;1}qhRO0d)!uuL}D06o8zIRlo>CWj#3`RpNYiN1yj zd!E2v7092Q)mJ<5Jo}*;u+-_wVaq?U{SN#Tm@I+RucQpr#LN5NNHGWOXCDu|9mh@` z6WGaKj-RA+(dy_w@B#R=;T%uX{PUweIv6H1{St(B|Rcd#!;O}`` zsNR$s`R7j_8-ABx7&@F)8u~q-8~QoMwjs8k;ODZ+LIunc7~vO%j%1aG$^f?kUIUmd zt0J@!WAz)oiuXyZZW!lf4$n?rz`9n%<5twI*ZKTV|I}l{d$OxS$d&sg=&2pGv=w%n z;FpDtWA1y|YeW5*+ryay5_HyvTI@Q%RHX}KuL-qbt`&2nD>^4@rYeW4{*mo(!w(0>dbso*6nDpQO&d$YP6v8)Vr zrx3bTU#jG$AogwfsT%t}*79?Ph@3&S>OAzLyco)CC{waAo?9djdiC5PsJSB(v3BmA z+(9+LRpbuxO+k(CG(RK0--*YX475J2O}UeDN6eHSA-&AxJv(=hZbp%xt=zmw7&*b% z&rDvUh|8QHt9#rxjXGA66%+O;BfiJVwc74xbsW`($nz}dtRejfA-YHXCGJafZwe#k zknHiuc{i&o6!i{OuHB(xyy?<(E{oo(kB2T3kQWjaA#Uhblo#mk5aU@imc*hXM@&j3 z^2FFX%o|3Xc@%!^L#|Ph*vVFt98FHdeHr!Cyhavmo0Rt#_aqN&hn}CXX|?R>e~DSn z0q-0`&dM!Q&hDzeC14+vEBlg|do)cR9Cfq7(T%cq6l=5~|BcO+2XQ|h9Dhhw-arhl z$9X>tdx)uGARqo%&t*mEY?6P)mM~@fp>(E*sm$AuG#0T=3 zo7is)>cWF2A@Ukzrx`OKdp{<4EFvU>VZd< z>0G)~o7B6cRx^D1+>E=#Ao=C$p12LTOLSRL)A~05|6SsLbC;O>B=*gF-ZpU7D3&nP zU(~nY{-El4n|3D*bur6W?x1=nB>4INj9J1rQ8^|BE1PsQd*Qklx9@o8px8E1-z zKQ$l*F}2Cj|Df2UH(`;CT9gC506t>qI&zFLM}4duF{hkGlNj4~wFLKEyz`0jw`*5- zf7jmuKIeUI&as84c~|o6)Wu?9{u%H+huoI}IjeB@JO211!HHu`F=Vd7 zS#JaHb>f8sAth;`3cRZDy#~A#F6r1g+-+Ly!u-}(ch^=Wzw8%!LIc9o=3#mlq<#9{ z9;o#-9R*wj+&?TJFRC_zK1w*8ZPY&tfs1|QQ(ZUuBI08#_QBW^^`0LT9CL%?PE#<_ z#DeXx$q3o<2&dZV=(QO919w(uqB4%yO?)dqj9K;oZ|n%Kj$hcP`I7iJvoM>ijNvVT z@OIZSi;#-=>r7B64k7;+PnRP`lxr~p?~*4_@0_6bIl=Z|&<>tehd&dv^(_d7Aw$f` zqU3kuy@|@;A2gpLc(wi}q5AaOi5H>M|<%NeUV>`FG*I;<6D*E2|WBPnS;C{N5_|>sQ%HwSh1nw zFxJ03t=as4^b?W?acFc2Voz_JvQqaG-7QXV^uAdn7&+-4dmDU(5%?Q)E28G8I-C&{ z?MxxRn65sfASa&K1HWl`w>&Dw%Y&;kGn`^P8>F%I@7ds0$f(Y-Z`F$5W`n=e$Hb53 zt$)}U7C=N1Nq z<>CPGCVqAsc%7XaOwPtT<#LlkK3$1gh-%zQymO-jiSm5A$RoT(Phe2nyvgfn#vXKMB0q&u*2dj#3emO zzRV5bN!q*O#<*OLSbiyACFbrxObUAn#moi6(>ouu^}0&;*}HUM z6FYUYx>A{b_-@X5f!-q%8SX*pA<_YScHijpoEqQAr^AU_EVGrNzDd{Oocb=V*FQd) zS<>J;e-0ly8^ptQC>7@;POFm)J`XbsosTj7ot@s`nQmXuWz_!#VmEwvlxJ%MQNAHE zArMyY7Yy$u9Nv9o&)Q6eHzYA~1o^#+2^W?DXARyr4gx<9@6Qc*zv#tXCkby@6L`aZ zk538xAXE1K5N}p*t&=@(UWjAtgAO3lGM3l zyVSW^+Ss|HV^jAkX?shv)ZW}7`MM=(Bc^DqAp){ufyP%-S7mIyK8AhOCdC_)Xk*w# zZHshx-jaLgUu|;hK1qF_R!UAVOQ9*HmtH530DeyWVuA|W5bQC#?9WIC4;c<8i z3kn^Dg@w+-qQc@rSE0MmQ|NUTI33PHr_)*FEOxq_Zl}lTEh;E-6crXZi;9Yhi(EzS zB2SUGxS-fkTv+TZE-EfAb``seJ;h#Efy?14bU9r`u40$V<#u^oUUz}p;VyJL-9_$V zx6AEzd)!`6fydz~^f*05o??&7wW%zS!*V z_H}kh%>-T{RqXILZm03~&Q58gZ_86pN>5AO+k74Mn>+ohq!rSJHs3Z3x0wIUs_6&y zjM_Flq>T-|4(jvBS!(;4K8CN|(+vII1H{1KE9nykU!%Vt9sVCcZ4!QyL4um>ztOfbq#(-AJ*YbjqUBt zo1})?=I$Ns+gGjH(eaGGaa*3fL4s8qJER6UK!fzf#`Yb}>Xz;&&#%+9b-MjcE4TT5 z9otvc*j!P zY`ody*>q%EYP0cXk0llB?s+4>+2r>jzG#l~L9S*Q+?&g;I#6h)V9s4-02 zy<=ndm%Fz&Z#C>Wrpsm5^+$fQwb9q1hZ~ls#{na6>;WE~>8B)V#nVzvqrZ(zSzhyb zgb;u83aO^Oxv{$$gN}~oCX^3wK&h&(^f9TU^O+S0E`KVn)amOL>hc)fY=1Z4#`%(T zfDsRj{(f}#iwh+1=Jw8KP}$tc#;aC!G(V&BH|msZeZ11YqkDVP%BBLZ$Jyv@Y-~c_ z-{f$)3kw?^g|33a#wM5BgSw*GRoLX*ym4i_Z==7_|K*jWt(Bzg?Y^zeQ1%z}`lnLo a`v!VCH%6Ql^mxmdRHC9-^j^m|y8i|t>7AJX delta 5231 zcmd5=eQ;CPl|N5UvLs8gC4V7ogCxwC#D{GRwpHl(*@gxT)I_MwhNiW_gjzNUu}Jr0 zHuQCV~?ZMt1THsFTs?CvzOnN4L22Sn+{T7uvH zt|T{McQgCv?wfhOy7%1kaewFBbIx%aDN14&!p924lhRJ4TMdGLxq}KC4)8s%6;pv%CsJ^$S@1WE@I7a+aJjg&rURC5vI%}K=E{oFn#1P2 znuf;pJu#kwEsoEGPH{`?91!}fqqL^QOwt6O=bKe%11%S{UPn<)i;dB2f28%&(pu&V zX4vJ0T4mi~jt1K}OTugrQeIeXHc%=8w`}4B|3s>xc2xH0DvIAR&@qnaZ0tHoo?)*v z&XZ($^I@HXEAUCfeA_h>2`MvV9wuk49O2#EnEWH&watZPf+^ZXx?&=F-wYY15t6(k zJ}LHnPKi~J6n}-3rNA=&GWj3W(=j)>f6YX?&!4y&`{kM2G5v3EyZ`m>ZMG&KHI$2+ z&XfJ3o`QS5(W^<<4+HPoU%8#&UFy3ResgcYoz4>NcF>iUdz(kwbdH3u$yUa#({1-Wl~?9@%CX%|`DLCBo~V0~J6fR^ z{2mhgdW_9|z^mTaE$z&_q1U5k4S3k<&vj>Ss_lE&_@DnZiXYbd|9{s zF&NS0~n=v(BAeibp$3S=jFtNNOO{I7H5Z}U>}ZE%MSFl&Sy37Fg!^40^ZBA+2Q z8Zy%rw${y=qg%k=0{*?=?EJ-0+g5QP6oPxvb@k(wf14o zoCx6_b?TjUr^W@p%SJt>;(=0^fx_)M6vWtb5aV4SSPPXgzE~aOOMK(}9QirpBI}It zE7J`6lM9*@`CVhV$lHVzTWlxSHB(L`P!HdIj!C^xD-8Y&icZzi;9KM5-#~P%{ZnJz z-+Ze{sW+13G*VK4!gzs@it!~X2N}dQToW{7?Qb+~&Ru@4nu0L~7_(Gs9QA@{?Y+j) z6mL@B>S}6H)?r}~N`44IF#xx*kO^|a>bbsILGM6NL-YEcyZnjc?bBND^9Fig(C{b5 zx{dM~Q<*68g^6}J>+@3f=a9rCxixKdXAWJl!jyPk#@sQ!NFC=3RYs59G1g7Gx_tU@3eBt?|GeihbOf`Sl{D@KO(@>M8rtJDHfN-!}TA}XtkG- zWQPv&JsmSza0n^tB8+|(>FNiF!9Jv@_mHA)vUh9I_J2g`67x%_=5^#N4f)D#pkOcZ z)xQCOUgV(b7^h&w5EKcxyDB&A_vxl}jG?cswC1;?d8w!rH7fSX* z$*aXwvjsW^po8EwME1D`t}ua0GCz2vYofl5MF#tMu_kUem-vCSa#AF<^|y(59>Ej^v@wm>|`CvPBebyYume2TZI4;Fv7znjaw zwCeVO(OZyw^`3UFpDT!t!D|bwg0irvQSn4b`iNhkw&}RUJD)x<`a8ZtecRb2svq$S z)!$*EX_)#M;kvU~-A4B4IKN2!xpTeRf%PV=KY_I-=LYo<=IP%U***@*?kc=!!F@Pl zb42$gh1&#A4#7wV4);d2bo?d?NOgGL_Nk=UUtRK-z{sT@Rd`5Z6wr@RqA!#qcX)EcmvLWy3^UH2HvKA4-{_(*efY7x)U*Y3C)4V*%HHW!WNq? z$^%KJfFaakvqyWsCrqu@>AJs#y_`j^ z$Xj9N5JR}ZYJvQ4-ZF6-DJG5?OFd?!923st#2DwzYVjjY%3RD#RttlEWS$7j$fU4L zzMRcGnQPpv{QE;q%5)p9^S6I~isjD_o7VSC^Uoh2LvVh<9{yT9PrjPBD%XXa#BxNu zK+el|8=OcePPrz35w~A{IKNUiq?3>2@AzumMCU@tN)rf`E}f9F8Y6*aC?ZaxzV4*Z zzvh7T#FMc2>i~YvPMl@RWvChPq$5*kj$CoWR+Lh7l@O%PHhP47hz z!Tu*2>qcWsPzC!OJH+*)4Zkq=xX?-|t^Wt@$hyz^k^g7y2=`C&nnIVzI=xNE1kH}LzYG_Yfcqn@K&Z|Q)6s!yTDfo}+WX&K;yyq+`Mv!z4m#W>Ux8|-dDBYDPADNQXS<--R417B?I2VJN+-H>^+ zXs);b<+{^rD(kv%IM8B!DQr5Ro-p0pGn$X+WjQQ|U73;1gQ53N1VSCBKsSRP9yM_& zGLY54nGzR~6&Ggq`&cQAx6)u74w|T-)CA8-rZ?=;WDO@V9PzyrV6A_wLI?1QqQElX;9*bfOw@* z>6+1=lix2cTIU79)X1e78XrMeK)5D?DH|H`hsYimjf#3V<9QIT7+a*twREour#^NJ) zd6PGW_UldqrQ$5LRqDKd_&yC<7#+vb#9W1a&csEt5*IB>JIky%8Y@llW}U>2nGX2t zoa6{)!d}px@yb|Az&o}^|IIUMM z;W+WrnOkz|dIoD>J+OW`=YFhLGpube492Iiwkq)shIO8D=brW)j9oJeQH&X}6ec(JAldJTfHy{T{&6(w9=yydM%=iC><&iW@LR6 zDo@Nv3adcuDtmFw-6&{jNDl#aKsw2j6f@?e4Sx|)8Ea;FMxV|nli8pOAu=@)xut?r z5YjBc@XFo)$VSzzxgM4S3QN7*)AE-~mx`4%n09O-uswuq#xBa6s8w*}W?-GZC@*u+ zLK(P5GJf*bk$wCk;jVD^`3nC>u*d5t)d}9oNu@}5&_q4%3!hg041yyr8kE~gD|+MxTpr7{)24p`fD28 z5BX^tJs&W?K!f|Tb4GK$K<2@j){%5uBTtv#k#Eg&?&#COEqMAUGj7Yyo0_+}w{5Aa zu6BQ|F%X3J^ci}3GyVXw^yAE~SGn(}=egee>HPVe|D&?ZIszd5e8ZKQ&+<=X>G)Pl zKYz&1E%F*bhdTj)=+Twf$5UY?P@=4dL*80TgMREEE^|H+QZJ^qeeJ8Ns|R@d&X+Oua* zeRb`sHC4M-?b=zltFEec*P7j{cX#Zms;a8o8`>4#8UBmPj(y=rEBA*xDxVBJ_UOv+ z{`RbUHfH7iEyiNJk*wR%e6mN*Uu3pM_{UPm3yn^WEO<%c-E7d4`+p*%Fg5R kPEYHK_X{#qru~U<=!#E%QbTqYX=P!aP|9YvgSfX%^E&Pm&3;Y-2?hAt_Czu`KXtwMKRb z1x2z64fcq@s5D9Kwl+8|dgHidu~WoJK!!92aENgfJ3VPm8JR;m(nJYkM9>(d>F>V9 z9xM1Hr~S8cj(p$!?zi1E92zQ%>?)X}I}j@T?)Re+5S^)(11TThmJ&(^wPC!_C%0 za!$L+y9s#98J;Bd?*|@RGvRObgW21=gyoLPH5twrXl8(`(A-L1KWK76Biy9oW-)$E z`A(hp>W$e>E29I=H1I1SYo><02S7LDq|hc#2pU1pY!T#WJS$yFbfr@$E1eRpoDic7 zYWWRs3I~fOJUySL{20xuEPB*@N5() z6wE7i>hK)EFEDrxg}#|r=#25Xl~>j-uXnM1FrD5^u6O?gcoE)G3BQDxuaZ2c_-C=4 zmm@rd3>m}CD>LW`B@WJzIr0vLE&_fhPfsi^haY)Pq0@c5B9l%s|60iq%!JK4VJ{Qx z)d+i;V6Pfd?G@v>a3}1w1@@YOyy^d)1s?1h#!mw8-?A5B-tIP~PX*_?T*{jS*p-$LKhi7Z{D$Ax&59~Dq-(6YL z?8S8YNs7JnxMp@a`Xe%*=7yUYjO|?ju1v*>o!L5@zn-+XEp{5W+(zRp9)+7}Trgm? zV$8+3md34Z7=Z(SgmwN``Bg08x8BXcw#GCmVT5gsX_V0Yx5!`h-6`ZF(}8>Gs_%Yn z_+;NPA6}LBhx(`P&(Dc&BPWd;;Xg|?^>4!dE4W8W1tWY9eFP&VBD}GZ(J1yWdyLsqzHyV|rS^GnEIU^(R-kbbAo?d*xeUpw2C@JEn!nSLqz%^V;u8sc)~ph<$&9 zlOyF6iat$p1#BNZM&9ouep#Jjyu`b|{CwW;d{MWd}^URdR(`u#oMet>|Z9GkRYk==hr*j9fE+hGy9eJT^ZUFZEO6539DGv4QU3=#g}=oeEVXbq1(>fs!EWUbgz{c9{BMXi^XHPQbMIG z3}566!q>xXBg=*H&N|tMn$7s?GJoKb#v^=5_=nJSiZ2b1xoG@_i|{pc5I@dzelet`%lvX?<3c}hcO`2lH!RdnegwO}a8I550AQye z17kb_zg8$blzmp}JbnxwFV}7CAD&OPsCy~FUR0ZuL63+AN~MwFozgul{WUnM=fLdOs_)lG${KyO5_q@-??qI^5R{u zC_XAce5g3gKeh0;CCvQB*4xN(f%Vu_{Kb2J0AF+PxdC!{nbln-4pBc@93qC|D@$rG zPpzbu8hlR))MCn(64T%tG!z84pvKNXC)Q(Ud2^+eGo6`1&RMzK;LGTJZANMt0Ue>H zv~pRoNG7%X7WLvy^xS7qvwIekuC2(e8}d=VzsC2oe)>B0%FZH|SNQ&Om_LjD`Ve4S zaTa0gYuA-JXVF^~{^`KQS>z&YcL&ZNv*@R9<2#Q2c?ZrNvwU79>fSOYo9VEboA9nS z%)7cEduSiu|0?(np?5R>TOgC^(g-;tki%r1*jl*#QOMs~M9v;f<^*u9uyYMp5PJo2 zcCd5W)5>x7gZQ3-U3l2ybTWzW!f-1`@d3kuLr)kE9(t`5XA<;{q5Tx!0UpeTlf`s$ z2DuaiZZ~XlB%QNc&mTC1b4q+4c)SE&2X3O!n)u*okSjdXW5|lNGo8yQUV-stjPEcV z3|T>0kVcPig|U4+I|o|AF3@&f9vWqGV)z?DoX*1b-;BTQc?@0I=S~&?uY#4u6kBZX7X@ zf9Y)xXPEGsO{nP^oPFf{$f24v&i=dej~%j`RJp(5vV%ihZj9w`(2yJKg-w`_40nh# z#h6WwFVs)UX>{@gY;p&e6MPeUc^Npfzc^CLVif1amb2*-Ubd$b=N~;(1N|fh6H;I~ z6hDeQKAV#Q%R`(pSY8UOh~jOq^Vy;lSP8`^px^5y6W$t4h5>t?#a?CTpItoMJo^wm zX96s5v0>8uk2Gq>pUq$n=6x;aa8tT8`bLf^Xg&S;;9F^Q>bQ|k4sm>(%ulN2dDUz;bX=1;X1&}0B-`UtaxL12ju>nV@W{gLlLt#0!|0WxBJ9+S^Rxwio8{MpPhjnPC0oKHSUbp> zf+B3zB`~_x3SF>dbGQp@omgYGVtKN8p<%M|A851-e+(Xj%^C-@4qHz*294-#o4`Ye zNZuOswQ2qU^KBpk7{>l7j30tW9(Wm7*2#LEo!eHAT2_ZUgE2hcS}T|5p!VJSBc=9z zsP^YV0X>7ARhMCm@*Uk>Tj!0~ z2kVu?S>%r9OXE>DjYoG#-Y8`3LjRk-Q5wg6d3@#;Nqz%0xE1;SB>W-d3BgLlV=Gr2 zW4X!VE4hl~nOlZr6Gx|5oLCXZ?5`4gn9!zE9n_wUo+masEWyK#UFdKdmlWlpcVGzd*80%&sX4m&xm|Mt$oJo+c<6#UO&|E zq;NP(`n%@M15XEx=nqD~guzXdUAqr72kB_QI(YoBb>ZI07EU;BVCU0`zitkXyb!1; zGcEVOc%XSx_EVsf4;L-mGs(_oAFwkp@`csF6Sxx#sGrlvNEXC8>vTD9ovWwB2amD$ zkAm{bCJ`ijjMA|CwS#9g8Egh+c*N)UhVGB^sE>lGqZVgl|hx$ulhea zq`o6e?NQ_8>_@8anLi2l0zd0D+V3Lb0cTmI2i*@pDsibVVq`TV6_)y~pyA$}3QK)! zV(U!LG3X_rcd+k+e}Qi+L7w_1rNq-`>Jq5=<3aH1EGl$XrsEw7FoD9&!n@bLU$J+T z#nqHxbjBx}y}Qz>ntjuk>JpYhoX2r5QDW|Ne#pqS3}yVV@q@=?-k zIze)F4kaqkO9*uwJze2Zhr5UXT895d51BWkt{c}1hZVk4dCES5e~x{uRqZ~VNScKb zN;IHvvGYg+-X$yGmj;f!yU~~NzO1|rF@8qSS@BL6Mc-29b1c@-hmfO;hQX$RGmW>N z=_~I(yn-Pya)-I_nUuJNnl4NATW`#34_NjaE>eA|T_G$98Yl^ir3767Y24t633 z4r2xzkZ&}NTQgDb>o@2z@V zs@7!xzkoB;t(2JCW>jil!I$e2e}l6Ii@8EyUE&etE?*F4JzX-=DJ3pD>Jqzf7E)j) z6;|L+q3gMpZa71u>%U4jtnn(?n?iU0wR97>b13o#uhQYYNP!jXOQC!CS~}u2x&v3~ z5dSLOqbYQuYw0AMzZ7|YdzB97np1Pz8sx=Wan3*;WwqcD_P&(Ka$L1bBvY-6W4}Ty zJj8lZ8e*Hpyy}}VH<>pnzT?pI)VEIEkEgL#ggCn%Pvb8?nP-FJ`aFGDV|jGovKl`e z__zKU#RbHBl&8%`LAoT6F&I(Kj)c1~hdaIG*-}J!9}r^bB`u9)JhKKkn{jtN0{jZR zEwq_2?-6IWN}jjy9`RFrufM6-`7GWiaxp#w*xApR zo%uI?_4$8!Sn{mHc*kdVKmXgow&&M9O!GAy&VhJ8&4P~5EsX!8I%UQ;lXC|8F*%@{ z*KwI{`=Co5-VoS%T;L4B%0kIwg6AEH=06tNED>e9A<=3u9MRkrEr2K3)o89KHIc-(8YMaaEws~w`JJhv1 z>`r@?z1r@wyX_vk*I{$m9S(=nQRS$1xEyYW$KiF_oOY+f>2y{(tDP>V+v#z7t87*F zDo2&Gs;a8G%2nmA@>F@NZPoT_N42xMs=B(`Rqd|!RC`@Em)+%XIbBt*YM0C9c6nT0 zx6N&LJKRopmAl&Qa=YCgx7TCy*gX!9(^KWC_P9K5kH_QnLPamcd%@ZZGA}^41pQy0=*sG;%;BBzrD<4YGR|<-Pi8h>iSx3{g5`-t^JfXNAFX9$F;d`_Y>M& z=cl3J`Q?*;x*npotkdb^_2}^b!^%&@zf3oskB+a83KITVIv2GColYN@;w_yorNcc^ z`7Om;I$uhM`}zNhPR~<~99KN`XTDMMkTzZqPt?}+@p^cXB9-5J+DIDRQaQUVDxS_y zAHSo)+kM^L9XrLg=8l2A-Fr4{*xP$wz_+`?+9vk(ioRa44FTRJe#O_lw?o;;_4N69 zfhuPp(7t|mz~8%PU0{F_?AG!gZ}Z9zwGgd~h~e!F_`lK-P!YeQ;pM1k)QgdQEBPhv z+zXcXiYkG)yKi96T7R#9kI1y&;cM^OAZ`#H}g*v6Bb!VxZ5b)5iG&zi^-`DN` ztElkA)yC`Ly``;3{s`U#ukw3O z8*Li?AIQ=6v6Sza2EU#jZ5rR*+Nk5HQt8UR-YQlh5pCSW+~n&Hboh4OFYfH??NA+h zjiKwdH|ee&*t=uk{((ImJ-R*%-2?;!qVweN0GT=!+M z$rtEiuB>mm6IC|Qu}*C2?(hwCVA9*$(T;YA02CWrYHt^N`|ex!C)D4MHF*wI+?9Wq z))Rd}uUn!9(CdLdUXSj2^^+-lPj}ya=+xrIy#ckqZ0PN{Pvfum-4boSKCpLSPy70I zo7dy?d40Zi^s$|Gm)qg+*&QyM!`JR|d(bC4T#k0wTx8R2Mk4`JhG?6WwL@sTtA$afa zNOIslI`_}pomm~7@0{=T`_B2Dv(I%*Y#1)dNsztL#lL$fL9)lq_qf$hFw;o#R?ZUfW;OfP5f!$OYv4r=;|H>KR+~y2I+jvC=J<2$;XrjEHO@4V zf9rjEA!D;|71I;N0fT{pY@P+L_keZh8lkLV^_r~4qp)!cHsa8Q4XJTvJ^B0ZGtyyb z_7%g3P!SG%YG6lx<2014Ft&Q5wQ&s$F$1@tn+l|b{E_=?yhY7TohFj4oR}Oc5yyv& zRZS~lbB%-Yx0^)&_lqdMV(K=Lz=(#B~%w|dc`4P!ZM%trE%qYz`ZPsfI+%EyYq z0()n$;i5qyWoD$>~$Vd{u9CcQ_!_(0EQgjYs)P?FL>pu@Vyr zA?k0^RWs2K1-#}%4YIe@El0n_sZkHfv9qLB0oT|W@{jX$!bPs%FkRP$Q`e&Zets@$ z{KK5<_jl%)OgU~UmpWb~`Qc_gbWSiPb;@*vj5LqL3nw`$)vk^cuA`MbQ7cmvuY6T-Sg zjyOW@3wfJ?RbjO$ClV6qDwFkdLS!5CJE8w5bo-#IxC#oDSeD(mkXJgde3DgewE*EY zhS5MjP*#>_*R6k;6XGH4uU@0G>D-j)ue8yCx#)ChrHKZ+vnYsm;1Jq7K+p%5QN9S} zE3Tg6mnhF>udps;|KmJ^eso!zs$9t~mw20)WWsK$yl&142bxj4`;@fTeB$`)aCFW` z<3E`q|0bdn-JfJP{rI2T)aGoGo!OKS;V_mjCZl|@#=!=0E!Rao+xI(NUvh^p(UJ(p zgkY-l)=4jP*57TNO!8*!Cw*<5>IMkL;pBN3iUPPT1xWk`1 z**&iZ?+?(8fF?f9ZrY-pHiR~DaNb-HvE{e`@W`P&b1>YsUocAF=yMcg>x zLOsI3)9es8C7Gd7BA*L5-hQZ6UC3@r0ban-7@Kqh&Zd9|8%tx~mckzUta@?2azdz) zR#LFVM2S{`f)=ZoJZ30}Oha$0k;ZNz=xii01RC*j*312v=jCjXTf9x{2IZXQa^m4^ z3eK{1Sv1l7!Gi942PAs&5U6TF4_*Xiy@{Zo0gZhJYj7CU^(#=i*O`j?`qtHzuGYG>x7doIAO-S;N%F}m*M0U zI5`g|{cv!cy>RjiF?nNn)0*ffcWM=JnN;^4??uJH0>221=5rbuo| z^rF3p)`RvK7(^AskvLCd5@5Um_-?^W9N9gfJY{J&xQdn6EER$ZgKWU5%vy9Q*BK6c zc!d6y5qAE(5f4wE=?%$5`JUJ67$GSY>93(RwT;ueUjul|{n zv%E$7Y|+yr{anuFhPi{2AHnjqyZYD&mmj%-sx7mM>hi)?)g31JJ${+iW#Hn!_+<0s z`@Bbc!`UWj@A1pE_aSJTpb<83)7h@=AbVtrU!ncnxl!8reR zggzSc9VB&%<*o#0cSw#akgrKH)zBS$6EpR1C$%-!5X}b zOM}kY;u9#sHk&QN14-t9A=GKJM~1#B&a-v=0bis2>h9*rcS^Qv=P%L7%g}S@>w2*7 z?v_c=^++dsIg8@Str0k^A?#o+UwJrpwKNZkiJ`}+M*!uRk&hE?j2E<`FSe;A=ohaQ z$NgZQFv3VvSeh>vnJ2xC+tt5*u1%fq!gl`h&(AUb{A1h3fqDM9lQ*z9|Hd5tdMsDD zmfMh12~J`h5zAL{^IRq;2*s&1=B?oND-Y+@ax0aid0%)iW~Q+aNNE}?rOzNHt=YJ@ z;0$pR4fiL+k#z^Hr=CQ>{{-BZ^dOP_dGZ^WhqGoZ>S7+&r2I8TmDTLsKixC-SGc#8`*I0I`VgR8{vMdtShLL zaCsT-HQ`qNf=^~Bz5NBUPkYAIX%Cw|$~N>%wI*#&bCPNsHoyox%7RC%2;kAB2>_3qaxx$rr=dix=VireY1zS=OCC}MSDP2nd2hE+@-N?F*Wd!} zjIKYM%4Rd!W0IiiQjQvvEGqWFSadTb8HL5#4RQ?sV>h`J65hkQJ$9B;V+Dp(zvF$@ zH>6O(UBo^E^k&ZRY7EH5&KlL&PLieAS(6&`q!r#WksYVZaOVrnn2?oLTn$BulGDg0 zw#u54Z2`1zrTR8Cwwpnpo07LKWp{rb+|0|z7xZTl?7BrnqL2+DDF!=BthbfyKu8L( zh?yYPf_mu&HKy~azPla9VEpYnX{AN@Sv!Tg;V@RCsM%KmH}2QTt_9YnADuT`U06@- z17es)o8|Ap27!5)pV2L3e-ih&DA9$lkVGfgrEW1QGn_JLSxwD7K3M=gM6*dH&{P%P zMb?WQ;UG^Vq}~C{s{kjTUXWTHN`}SA7Tt`8L+P;ac((8|iPa;qc9Ku9#CX7=JinyO zm|7OEFRAAaE3-?gqyivbOXDe|_UZQNBLsa?W3Q%tgx=NfRccilz+cv&QcaW$r7Dy5 zbqW|Ilc(OqH{E})6lBte5Pk{@0!FD&{L_~_{?Dr~Ga(YP5hfwX||Co+wvzS(|L zdb@^cgqaSW^zXfP*pQYCXGV4?iL#=#sGo6hW=ajEPe0C#e6;+(jz3-Y>ap^bTbachFX}&1k{(Y5g&8B6{-U*$nLf68>N%6?j^#nz~KJW zjM2)TVeckkZjdSAo3x?K&sdYX1M)%kX<+p~7h?!9$&bxQ5>lBK`SK)oen Date: Sun, 6 Nov 2022 22:21:05 +0100 Subject: [PATCH 65/75] Fix newest rubocop complaint --- Gemfile | 2 +- common/tests/console_io_test.rb | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Gemfile b/Gemfile index 48256484..7460e048 100644 --- a/Gemfile +++ b/Gemfile @@ -11,5 +11,5 @@ group :uart do end group :development do - gem 'rubocop', '>= 1.37.1', require: false + gem 'rubocop', '>= 1.38.0', require: false end diff --git a/common/tests/console_io_test.rb b/common/tests/console_io_test.rb index cfb45a2b..002fb895 100644 --- a/common/tests/console_io_test.rb +++ b/common/tests/console_io_test.rb @@ -27,9 +27,9 @@ end # Monkey-patch IO so that we get access to the buffer of a previously unsuccessful expect(). class IO - # rubocop:disable Naming:MethodName - attr_reader :unusedBuf - # rubocop:enable Naming:MethodName + def unused_buf + @unusedBuf + end end # A wrapper class that records characters that have been received from a PTY. @@ -43,7 +43,7 @@ class PTYLoggerWrapper def expect(pattern, timeout) result = @pty.expect(pattern, timeout) @log << if result.nil? - @pty.unusedBuf + @pty.unused_buf else result end From a952d6d9ee62622af5cdf72fa0450dcbff51414d Mon Sep 17 00:00:00 2001 From: Andre Richter Date: Sat, 19 Nov 2022 23:47:11 +0100 Subject: [PATCH 66/75] Update README.md --- 09_privilege_level/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/09_privilege_level/README.md b/09_privilege_level/README.md index e0f73b63..bb704700 100644 --- a/09_privilege_level/README.md +++ b/09_privilege_level/README.md @@ -34,7 +34,7 @@ architectures, please have a look at the following links: At this point, I strongly recommend that you glimpse over `Chapter 3` of the [Programmer’s Guide for ARMv8-A] before you continue. It gives a concise overview about the topic. -[Programmer’s Guide forARMv8-A]: http://infocenter.arm.com/help/topic/com.arm.doc.den0024a/DEN0024A_v8_architecture_PG.pdf +[Programmer’s Guide for ARMv8-A]: http://infocenter.arm.com/help/topic/com.arm.doc.den0024a/DEN0024A_v8_architecture_PG.pdf ## Scope of this tutorial From ac3ea0e616ccf1da6ac83206490e50034ee35072 Mon Sep 17 00:00:00 2001 From: fei long Date: Sat, 31 Dec 2022 04:30:34 +0800 Subject: [PATCH 67/75] Tutorial 02: update chinese translate. (#175) --- 02_runtime_init/README.CN.md | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/02_runtime_init/README.CN.md b/02_runtime_init/README.CN.md index f8d64f6f..0272e057 100644 --- a/02_runtime_init/README.CN.md +++ b/02_runtime_init/README.CN.md @@ -2,21 +2,28 @@ ## tl;dr -我们拓展了`boot.S`,在第一次启动的时候调用Rust代码。在Rust的代码中先清零了[bss] section,然后通过调用`panic()`挂起CPU。再次运行`make qemu`看看新增加的代码是怎么运行的。 +- 我们拓展了`boot.S`,在第一次启动的时候调用Rust代码。 + 在跳转到rust代码前,对运行时进行了一些初始化工作。 +- Rust通过调用`panic()`挂起CPU。 +- 再次运行`make qemu`看看新增加的代码是怎么运行的。 ## 值得注意的变化 -- 链接脚本(linker script)中有了更多的section。 - - `.rodata`, `.data` - - `.bss` -- `_start()`: - - 当核心不是`core0`第0号核心的时候,挂起该CPU核心。 - - `core0`会调用Rust的函数`runtime_init()`。 -- `runtime_init.rs`内的`runtime_init()` - - 清零了`.bss` section. - - 它调用了`kernel_init()`, 这个函数又调用了`panic!()`, panic函数最终把`core0`和其他核心一样挂起了。 +- 链接脚本(linker script)中的变化: + - 新程序段(sections): `.rodata`, `.got`, `.data`, `.bss`. + - 使用一个独立的位置(`.text._start_arguments`)来保存`_start()`引导函数所使用的参数。 +- `_start()` in `_arch/__arch_name__/cpu/boot.s`: + 1. 当核心不是`core0`第0号核心的时候,挂起该CPU核心。 + 1. 通过清零`.bss`程序段来初始化`DRAM`. + 1. 初始化堆栈指针(`stack pointer`). + 1. 跳转到`arch/__arch_name__/cpu/boot.rs`文件中定义的`_start_rust()`函数 +- `_start_rust()`: + 1. 它调用了`kernel_init()`, 这个函数又调用了`panic!()`, panic函数最终把`core0`和其他核心一样挂起了。 +- 目前依赖 [aarch64-cpu] 程序库, 这个库零成本的包装了处理 CPU 资源时的“不安全”部分。 + - 详细请参考 `_arch/__arch_name__/cpu.rs`. [bss]: https://en.wikipedia.org/wiki/.bss +[aarch64-cpu]: https://github.com/rust-embedded/aarch64-cpu ## 相比之前的变化(diff) 请检查[英文版本](README.md#diff-to-previous),这是最新的。 From 49a25275e66ab0dcacfcbbbb666311df7a9650c9 Mon Sep 17 00:00:00 2001 From: James Zow Date: Thu, 9 Mar 2023 19:19:03 +0800 Subject: [PATCH 68/75] Translation Chapter 4 (#171) * Translation Chapter 4 * Update README.CN.md --- 04_safe_globals/README.CN.md | 50 ++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 04_safe_globals/README.CN.md diff --git a/04_safe_globals/README.CN.md b/04_safe_globals/README.CN.md new file mode 100644 index 00000000..eb35c006 --- /dev/null +++ b/04_safe_globals/README.CN.md @@ -0,0 +1,50 @@ +# 教程 04 - 全局安全 + +## tl;dr + +- 引入了假的锁。 +- 这是第一次展示原始操作系统同步,并支持安全访问全局数据结构。 + +## Rust中的全局可变 + +当我们引入全局可用的`print!`宏在 [教程03],我门有一点作弊。 调用 +`core::fmt`的`write_fmt()`函数,接受`&mut self`的方法之所以有效, +是因为在每次调用时都会创建一个新的`QEMUOutput`实例。 + +如果我们想保留一些状态,例如关于写入字符数的统计数据, +我们需要创建`QEMUOutput`的一个全局实例 (在Rust中,使用`static`关键字). + +然而`static QEMU_OUTPUT`不允许调用具有`&mut self`的函数。 +为此,我们需要`static mut`,但是调用改变`static mut`状态的函数是不安全的。 +这个是Rust编译器对此的推理,它无法再阻止核心/线程同时改变数据(它是全局的,所以每个人都可以从任何地方引用它,检查程序借用在这里帮不上忙)。 + + +这个问题的解决方案是将全局封装到原始同步中。在我们的例子中,是一个*MUTual EXclusion*原语的变体。 +`Mutex`是`synchronization.rs`中引入的一个特性,并由同一文件中的`NullLock`实现。 +为了使代码更易于教学,它省略了用于防止并发访问的实际体系结构特定逻辑,因为只要内核仅在单个内核上执行并禁用中断,我们就不需要它。 + +`NullLock`侧重于展示Rust内部可变性的核心概念。请务必阅读它。 +我们还建议您阅读这篇关于[Rust的引用类型的精确心智模型]文章 + +如果要将`NullLock`与一些真实的互斥实现进行比较,可以查看 +[spin crate]或者[parking lot crate]。 + +[教程03]: ../03_hacky_hello_world +[内部可变性]: https://doc.rust-lang.org/std/cell/index.html +[Rust的引用类型的精确心智模型]: https://docs.rs/dtolnay/0.0.6/dtolnay/macro._02__reference_types.html +[spin crate]: https://github.com/mvdnes/spin-rs +[parking lot crate]: https://github.com/Amanieu/parking_lot + +## 测试 + +```console +$ make qemu +[...] + +[0] Hello from Rust! +[1] Chars written: 22 +[2] Stopping here. +``` + +## 相比之前的变化(diff) +请检查[英文版本](README.md#diff-to-previous),这是最新的。 From 52b7ac9b2f1a980ed408e06f57a44f1562433986 Mon Sep 17 00:00:00 2001 From: James Zow Date: Fri, 15 Sep 2023 20:22:15 +0800 Subject: [PATCH 69/75] fix ci/cd error (#195) * fix ci/cd error * update copyright year * Modify remaining years * solve ci report settings.json code style * update .prettierrc.json * prettierrc fix code style * fix rb file i.to_s and code style * fix error Line is too long. [101/100] * Modify the Ruby file format and restore other file formats * update makefile and readme file space --- .githooks/pre-commit | 6 +- .github/workflows/build_rpi3.yml | 68 ++++++++-------- .github/workflows/build_rpi4.yml | 68 ++++++++-------- .github/workflows/sanity.yml | 80 +++++++++---------- .github/workflows/test_integration.yml | 68 ++++++++-------- .github/workflows/test_unit.yml | 70 ++++++++-------- .github/workflows/test_xtra.yml | 68 ++++++++-------- .prettierrc.json | 36 ++++++++- .rubocop.yml | 16 ++-- .vscode/settings.json | 16 ++-- 01_wait_forever/.vscode/settings.json | 16 ++-- 01_wait_forever/Cargo.toml | 2 +- 01_wait_forever/Makefile | 2 +- 01_wait_forever/src/_arch/aarch64/cpu/boot.rs | 2 +- 01_wait_forever/src/_arch/aarch64/cpu/boot.s | 2 +- 01_wait_forever/src/bsp.rs | 2 +- 01_wait_forever/src/bsp/raspberrypi.rs | 2 +- 01_wait_forever/src/cpu.rs | 2 +- 01_wait_forever/src/cpu/boot.rs | 2 +- 01_wait_forever/src/main.rs | 2 +- 01_wait_forever/src/panic_wait.rs | 2 +- 02_runtime_init/.vscode/settings.json | 16 ++-- 02_runtime_init/Makefile | 2 +- 02_runtime_init/README.md | 9 +-- 02_runtime_init/src/_arch/aarch64/cpu.rs | 2 +- 02_runtime_init/src/_arch/aarch64/cpu/boot.rs | 2 +- 02_runtime_init/src/bsp.rs | 2 +- 02_runtime_init/src/bsp/raspberrypi.rs | 2 +- 02_runtime_init/src/bsp/raspberrypi/cpu.rs | 2 +- 02_runtime_init/src/cpu.rs | 2 +- 02_runtime_init/src/cpu/boot.rs | 2 +- 02_runtime_init/src/main.rs | 2 +- 02_runtime_init/src/panic_wait.rs | 2 +- 03_hacky_hello_world/.vscode/settings.json | 16 ++-- 03_hacky_hello_world/Makefile | 2 +- 03_hacky_hello_world/README.md | 6 +- 03_hacky_hello_world/src/_arch/aarch64/cpu.rs | 2 +- .../src/_arch/aarch64/cpu/boot.rs | 2 +- 03_hacky_hello_world/src/bsp.rs | 2 +- 03_hacky_hello_world/src/bsp/raspberrypi.rs | 2 +- .../src/bsp/raspberrypi/console.rs | 2 +- .../src/bsp/raspberrypi/cpu.rs | 2 +- 03_hacky_hello_world/src/console.rs | 2 +- 03_hacky_hello_world/src/cpu.rs | 2 +- 03_hacky_hello_world/src/cpu/boot.rs | 2 +- 03_hacky_hello_world/src/main.rs | 2 +- 03_hacky_hello_world/src/panic_wait.rs | 2 +- 03_hacky_hello_world/src/print.rs | 2 +- 04_safe_globals/.vscode/settings.json | 16 ++-- 04_safe_globals/Makefile | 2 +- 04_safe_globals/README.md | 2 +- 04_safe_globals/src/_arch/aarch64/cpu.rs | 2 +- 04_safe_globals/src/_arch/aarch64/cpu/boot.rs | 2 +- 04_safe_globals/src/bsp.rs | 2 +- 04_safe_globals/src/bsp/raspberrypi.rs | 2 +- .../src/bsp/raspberrypi/console.rs | 2 +- 04_safe_globals/src/bsp/raspberrypi/cpu.rs | 2 +- 04_safe_globals/src/console.rs | 2 +- 04_safe_globals/src/cpu.rs | 2 +- 04_safe_globals/src/cpu/boot.rs | 2 +- 04_safe_globals/src/main.rs | 2 +- 04_safe_globals/src/panic_wait.rs | 2 +- 04_safe_globals/src/print.rs | 2 +- 04_safe_globals/src/synchronization.rs | 2 +- 05_drivers_gpio_uart/.vscode/settings.json | 16 ++-- 05_drivers_gpio_uart/Makefile | 4 +- 05_drivers_gpio_uart/README.md | 18 ++--- 05_drivers_gpio_uart/src/_arch/aarch64/cpu.rs | 2 +- .../src/_arch/aarch64/cpu/boot.rs | 2 +- 05_drivers_gpio_uart/src/bsp.rs | 2 +- 05_drivers_gpio_uart/src/bsp/device_driver.rs | 2 +- .../src/bsp/device_driver/bcm.rs | 2 +- .../src/bsp/device_driver/bcm/bcm2xxx_gpio.rs | 2 +- .../device_driver/bcm/bcm2xxx_pl011_uart.rs | 2 +- .../src/bsp/device_driver/common.rs | 2 +- 05_drivers_gpio_uart/src/bsp/raspberrypi.rs | 2 +- .../src/bsp/raspberrypi/console.rs | 2 +- .../src/bsp/raspberrypi/cpu.rs | 2 +- .../src/bsp/raspberrypi/driver.rs | 2 +- .../src/bsp/raspberrypi/memory.rs | 2 +- 05_drivers_gpio_uart/src/console.rs | 2 +- .../src/console/null_console.rs | 2 +- 05_drivers_gpio_uart/src/cpu.rs | 2 +- 05_drivers_gpio_uart/src/cpu/boot.rs | 2 +- 05_drivers_gpio_uart/src/driver.rs | 2 +- 05_drivers_gpio_uart/src/main.rs | 2 +- 05_drivers_gpio_uart/src/panic_wait.rs | 2 +- 05_drivers_gpio_uart/src/print.rs | 2 +- 05_drivers_gpio_uart/src/synchronization.rs | 2 +- 06_uart_chainloader/.vscode/settings.json | 16 ++-- 06_uart_chainloader/Makefile | 2 +- 06_uart_chainloader/README.md | 7 +- 06_uart_chainloader/src/_arch/aarch64/cpu.rs | 2 +- .../src/_arch/aarch64/cpu/boot.rs | 2 +- 06_uart_chainloader/src/bsp.rs | 2 +- 06_uart_chainloader/src/bsp/device_driver.rs | 2 +- .../src/bsp/device_driver/bcm.rs | 2 +- .../src/bsp/device_driver/bcm/bcm2xxx_gpio.rs | 2 +- .../device_driver/bcm/bcm2xxx_pl011_uart.rs | 2 +- .../src/bsp/device_driver/common.rs | 2 +- 06_uart_chainloader/src/bsp/raspberrypi.rs | 2 +- .../src/bsp/raspberrypi/cpu.rs | 2 +- .../src/bsp/raspberrypi/driver.rs | 2 +- .../src/bsp/raspberrypi/memory.rs | 2 +- 06_uart_chainloader/src/console.rs | 2 +- .../src/console/null_console.rs | 2 +- 06_uart_chainloader/src/cpu.rs | 2 +- 06_uart_chainloader/src/cpu/boot.rs | 2 +- 06_uart_chainloader/src/driver.rs | 2 +- 06_uart_chainloader/src/main.rs | 2 +- 06_uart_chainloader/src/panic_wait.rs | 2 +- 06_uart_chainloader/src/print.rs | 2 +- 06_uart_chainloader/src/synchronization.rs | 2 +- 06_uart_chainloader/tests/chainboot_test.rb | 6 +- 07_timestamps/.vscode/settings.json | 16 ++-- 07_timestamps/Makefile | 2 +- 07_timestamps/README.md | 8 +- 07_timestamps/src/_arch/aarch64/cpu.rs | 2 +- 07_timestamps/src/_arch/aarch64/cpu/boot.rs | 2 +- 07_timestamps/src/_arch/aarch64/time.rs | 2 +- 07_timestamps/src/bsp.rs | 2 +- 07_timestamps/src/bsp/device_driver.rs | 2 +- 07_timestamps/src/bsp/device_driver/bcm.rs | 2 +- .../src/bsp/device_driver/bcm/bcm2xxx_gpio.rs | 2 +- .../device_driver/bcm/bcm2xxx_pl011_uart.rs | 2 +- 07_timestamps/src/bsp/device_driver/common.rs | 2 +- 07_timestamps/src/bsp/raspberrypi.rs | 2 +- 07_timestamps/src/bsp/raspberrypi/cpu.rs | 2 +- 07_timestamps/src/bsp/raspberrypi/driver.rs | 2 +- 07_timestamps/src/bsp/raspberrypi/memory.rs | 2 +- 07_timestamps/src/console.rs | 2 +- 07_timestamps/src/console/null_console.rs | 2 +- 07_timestamps/src/cpu.rs | 2 +- 07_timestamps/src/cpu/boot.rs | 2 +- 07_timestamps/src/driver.rs | 2 +- 07_timestamps/src/main.rs | 2 +- 07_timestamps/src/panic_wait.rs | 2 +- 07_timestamps/src/print.rs | 2 +- 07_timestamps/src/synchronization.rs | 2 +- 07_timestamps/src/time.rs | 2 +- 08_hw_debug_JTAG/.vscode/settings.json | 16 ++-- 08_hw_debug_JTAG/Makefile | 2 +- 08_hw_debug_JTAG/src/_arch/aarch64/cpu.rs | 2 +- .../src/_arch/aarch64/cpu/boot.rs | 2 +- 08_hw_debug_JTAG/src/_arch/aarch64/time.rs | 2 +- 08_hw_debug_JTAG/src/bsp.rs | 2 +- 08_hw_debug_JTAG/src/bsp/device_driver.rs | 2 +- 08_hw_debug_JTAG/src/bsp/device_driver/bcm.rs | 2 +- .../src/bsp/device_driver/bcm/bcm2xxx_gpio.rs | 2 +- .../device_driver/bcm/bcm2xxx_pl011_uart.rs | 2 +- .../src/bsp/device_driver/common.rs | 2 +- 08_hw_debug_JTAG/src/bsp/raspberrypi.rs | 2 +- 08_hw_debug_JTAG/src/bsp/raspberrypi/cpu.rs | 2 +- .../src/bsp/raspberrypi/driver.rs | 2 +- .../src/bsp/raspberrypi/memory.rs | 2 +- 08_hw_debug_JTAG/src/console.rs | 2 +- 08_hw_debug_JTAG/src/console/null_console.rs | 2 +- 08_hw_debug_JTAG/src/cpu.rs | 2 +- 08_hw_debug_JTAG/src/cpu/boot.rs | 2 +- 08_hw_debug_JTAG/src/driver.rs | 2 +- 08_hw_debug_JTAG/src/main.rs | 2 +- 08_hw_debug_JTAG/src/panic_wait.rs | 2 +- 08_hw_debug_JTAG/src/print.rs | 2 +- 08_hw_debug_JTAG/src/synchronization.rs | 2 +- 08_hw_debug_JTAG/src/time.rs | 2 +- 09_privilege_level/.vscode/settings.json | 16 ++-- 09_privilege_level/Makefile | 2 +- 09_privilege_level/README.md | 8 +- 09_privilege_level/src/_arch/aarch64/cpu.rs | 2 +- .../src/_arch/aarch64/cpu/boot.rs | 2 +- .../src/_arch/aarch64/exception.rs | 2 +- .../_arch/aarch64/exception/asynchronous.rs | 2 +- 09_privilege_level/src/_arch/aarch64/time.rs | 2 +- 09_privilege_level/src/bsp.rs | 2 +- 09_privilege_level/src/bsp/device_driver.rs | 2 +- .../src/bsp/device_driver/bcm.rs | 2 +- .../src/bsp/device_driver/bcm/bcm2xxx_gpio.rs | 2 +- .../device_driver/bcm/bcm2xxx_pl011_uart.rs | 2 +- .../src/bsp/device_driver/common.rs | 2 +- 09_privilege_level/src/bsp/raspberrypi.rs | 2 +- 09_privilege_level/src/bsp/raspberrypi/cpu.rs | 2 +- .../src/bsp/raspberrypi/driver.rs | 2 +- .../src/bsp/raspberrypi/memory.rs | 2 +- 09_privilege_level/src/console.rs | 2 +- .../src/console/null_console.rs | 2 +- 09_privilege_level/src/cpu.rs | 2 +- 09_privilege_level/src/cpu/boot.rs | 2 +- 09_privilege_level/src/driver.rs | 2 +- 09_privilege_level/src/exception.rs | 2 +- .../src/exception/asynchronous.rs | 2 +- 09_privilege_level/src/main.rs | 2 +- 09_privilege_level/src/panic_wait.rs | 2 +- 09_privilege_level/src/print.rs | 2 +- 09_privilege_level/src/synchronization.rs | 2 +- 09_privilege_level/src/time.rs | 2 +- .../.vscode/settings.json | 16 ++-- .../Makefile | 2 +- .../README.md | 18 ++--- .../src/_arch/aarch64/cpu.rs | 2 +- .../src/_arch/aarch64/cpu/boot.rs | 2 +- .../src/_arch/aarch64/exception.rs | 2 +- .../_arch/aarch64/exception/asynchronous.rs | 2 +- .../src/_arch/aarch64/memory/mmu.rs | 2 +- .../aarch64/memory/mmu/translation_table.rs | 2 +- .../src/_arch/aarch64/time.rs | 2 +- .../src/bsp.rs | 2 +- .../src/bsp/device_driver.rs | 2 +- .../src/bsp/device_driver/bcm.rs | 2 +- .../src/bsp/device_driver/bcm/bcm2xxx_gpio.rs | 2 +- .../device_driver/bcm/bcm2xxx_pl011_uart.rs | 2 +- .../src/bsp/device_driver/common.rs | 2 +- .../src/bsp/raspberrypi.rs | 2 +- .../src/bsp/raspberrypi/cpu.rs | 2 +- .../src/bsp/raspberrypi/driver.rs | 2 +- .../src/bsp/raspberrypi/kernel.ld | 2 +- .../src/bsp/raspberrypi/memory.rs | 2 +- .../src/bsp/raspberrypi/memory/mmu.rs | 2 +- .../src/common.rs | 2 +- .../src/console.rs | 2 +- .../src/console/null_console.rs | 2 +- .../src/cpu.rs | 2 +- .../src/cpu/boot.rs | 2 +- .../src/driver.rs | 2 +- .../src/exception.rs | 2 +- .../src/exception/asynchronous.rs | 2 +- .../src/main.rs | 2 +- .../src/memory.rs | 2 +- .../src/memory/mmu.rs | 2 +- .../src/memory/mmu/translation_table.rs | 2 +- .../src/panic_wait.rs | 2 +- .../src/print.rs | 2 +- .../src/synchronization.rs | 2 +- .../src/time.rs | 2 +- .../.vscode/settings.json | 16 ++-- 11_exceptions_part1_groundwork/Makefile | 2 +- 11_exceptions_part1_groundwork/README.md | 2 +- .../src/_arch/aarch64/cpu.rs | 2 +- .../src/_arch/aarch64/cpu/boot.rs | 2 +- .../src/_arch/aarch64/exception.rs | 2 +- .../_arch/aarch64/exception/asynchronous.rs | 2 +- .../src/_arch/aarch64/memory/mmu.rs | 2 +- .../aarch64/memory/mmu/translation_table.rs | 2 +- .../src/_arch/aarch64/time.rs | 2 +- 11_exceptions_part1_groundwork/src/bsp.rs | 2 +- .../src/bsp/device_driver.rs | 2 +- .../src/bsp/device_driver/bcm.rs | 2 +- .../src/bsp/device_driver/bcm/bcm2xxx_gpio.rs | 2 +- .../device_driver/bcm/bcm2xxx_pl011_uart.rs | 2 +- .../src/bsp/device_driver/common.rs | 2 +- .../src/bsp/raspberrypi.rs | 2 +- .../src/bsp/raspberrypi/cpu.rs | 2 +- .../src/bsp/raspberrypi/driver.rs | 2 +- .../src/bsp/raspberrypi/memory.rs | 2 +- .../src/bsp/raspberrypi/memory/mmu.rs | 2 +- 11_exceptions_part1_groundwork/src/common.rs | 2 +- 11_exceptions_part1_groundwork/src/console.rs | 2 +- .../src/console/null_console.rs | 2 +- 11_exceptions_part1_groundwork/src/cpu.rs | 2 +- .../src/cpu/boot.rs | 2 +- 11_exceptions_part1_groundwork/src/driver.rs | 2 +- .../src/exception.rs | 2 +- .../src/exception/asynchronous.rs | 2 +- 11_exceptions_part1_groundwork/src/main.rs | 2 +- 11_exceptions_part1_groundwork/src/memory.rs | 2 +- .../src/memory/mmu.rs | 2 +- .../src/memory/mmu/translation_table.rs | 2 +- .../src/panic_wait.rs | 2 +- 11_exceptions_part1_groundwork/src/print.rs | 2 +- .../src/synchronization.rs | 2 +- 11_exceptions_part1_groundwork/src/time.rs | 2 +- 12_integrated_testing/.vscode/settings.json | 16 ++-- 12_integrated_testing/Makefile | 2 +- .../kernel/src/_arch/aarch64/cpu.rs | 2 +- .../kernel/src/_arch/aarch64/cpu/boot.rs | 2 +- .../kernel/src/_arch/aarch64/exception.rs | 2 +- .../_arch/aarch64/exception/asynchronous.rs | 2 +- .../kernel/src/_arch/aarch64/memory/mmu.rs | 2 +- .../aarch64/memory/mmu/translation_table.rs | 2 +- .../kernel/src/_arch/aarch64/time.rs | 2 +- 12_integrated_testing/kernel/src/bsp.rs | 2 +- .../kernel/src/bsp/device_driver.rs | 2 +- .../kernel/src/bsp/device_driver/bcm.rs | 2 +- .../src/bsp/device_driver/bcm/bcm2xxx_gpio.rs | 2 +- .../device_driver/bcm/bcm2xxx_pl011_uart.rs | 2 +- .../kernel/src/bsp/device_driver/common.rs | 2 +- .../kernel/src/bsp/raspberrypi.rs | 2 +- .../kernel/src/bsp/raspberrypi/cpu.rs | 2 +- .../kernel/src/bsp/raspberrypi/driver.rs | 2 +- .../kernel/src/bsp/raspberrypi/memory.rs | 2 +- .../kernel/src/bsp/raspberrypi/memory/mmu.rs | 2 +- 12_integrated_testing/kernel/src/common.rs | 2 +- 12_integrated_testing/kernel/src/console.rs | 2 +- .../kernel/src/console/null_console.rs | 2 +- 12_integrated_testing/kernel/src/cpu.rs | 2 +- 12_integrated_testing/kernel/src/cpu/boot.rs | 2 +- 12_integrated_testing/kernel/src/driver.rs | 2 +- 12_integrated_testing/kernel/src/exception.rs | 2 +- .../kernel/src/exception/asynchronous.rs | 2 +- 12_integrated_testing/kernel/src/lib.rs | 2 +- 12_integrated_testing/kernel/src/main.rs | 2 +- 12_integrated_testing/kernel/src/memory.rs | 2 +- .../kernel/src/memory/mmu.rs | 2 +- .../src/memory/mmu/translation_table.rs | 2 +- .../kernel/src/panic_wait.rs | 2 +- 12_integrated_testing/kernel/src/print.rs | 2 +- .../kernel/src/synchronization.rs | 2 +- 12_integrated_testing/kernel/src/time.rs | 2 +- .../kernel/tests/00_console_sanity.rb | 6 +- .../kernel/tests/00_console_sanity.rs | 2 +- .../kernel/tests/01_timer_sanity.rs | 2 +- .../tests/02_exception_sync_page_fault.rs | 2 +- .../tests/03_exception_restore_sanity.rb | 6 +- .../tests/03_exception_restore_sanity.rs | 2 +- .../kernel/tests/panic_exit_success/mod.rs | 2 +- .../kernel/tests/panic_wait_forever/mod.rs | 2 +- .../libraries/test-macros/src/lib.rs | 2 +- .../libraries/test-types/src/lib.rs | 2 +- .../.vscode/settings.json | 16 ++-- 13_exceptions_part2_peripheral_IRQs/Makefile | 2 +- 13_exceptions_part2_peripheral_IRQs/README.md | 26 +++--- .../kernel/src/_arch/aarch64/cpu.rs | 2 +- .../kernel/src/_arch/aarch64/cpu/boot.rs | 2 +- .../kernel/src/_arch/aarch64/cpu/smp.rs | 2 +- .../kernel/src/_arch/aarch64/exception.rs | 2 +- .../_arch/aarch64/exception/asynchronous.rs | 2 +- .../kernel/src/_arch/aarch64/memory/mmu.rs | 2 +- .../aarch64/memory/mmu/translation_table.rs | 2 +- .../kernel/src/_arch/aarch64/time.rs | 2 +- .../kernel/src/bsp.rs | 2 +- .../kernel/src/bsp/device_driver.rs | 2 +- .../kernel/src/bsp/device_driver/arm.rs | 2 +- .../kernel/src/bsp/device_driver/arm/gicv2.rs | 2 +- .../src/bsp/device_driver/arm/gicv2/gicc.rs | 2 +- .../src/bsp/device_driver/arm/gicv2/gicd.rs | 2 +- .../kernel/src/bsp/device_driver/bcm.rs | 2 +- .../src/bsp/device_driver/bcm/bcm2xxx_gpio.rs | 2 +- .../bcm/bcm2xxx_interrupt_controller.rs | 2 +- .../peripheral_ic.rs | 2 +- .../device_driver/bcm/bcm2xxx_pl011_uart.rs | 2 +- .../kernel/src/bsp/device_driver/common.rs | 2 +- .../kernel/src/bsp/raspberrypi.rs | 2 +- .../kernel/src/bsp/raspberrypi/cpu.rs | 2 +- .../kernel/src/bsp/raspberrypi/driver.rs | 2 +- .../kernel/src/bsp/raspberrypi/exception.rs | 2 +- .../bsp/raspberrypi/exception/asynchronous.rs | 2 +- .../kernel/src/bsp/raspberrypi/memory.rs | 2 +- .../kernel/src/bsp/raspberrypi/memory/mmu.rs | 2 +- .../kernel/src/common.rs | 2 +- .../kernel/src/console.rs | 2 +- .../kernel/src/console/null_console.rs | 2 +- .../kernel/src/cpu.rs | 2 +- .../kernel/src/cpu/boot.rs | 2 +- .../kernel/src/cpu/smp.rs | 2 +- .../kernel/src/driver.rs | 2 +- .../kernel/src/exception.rs | 2 +- .../kernel/src/exception/asynchronous.rs | 2 +- .../asynchronous/null_irq_manager.rs | 2 +- .../kernel/src/lib.rs | 2 +- .../kernel/src/main.rs | 2 +- .../kernel/src/memory.rs | 2 +- .../kernel/src/memory/mmu.rs | 2 +- .../src/memory/mmu/translation_table.rs | 2 +- .../kernel/src/panic_wait.rs | 2 +- .../kernel/src/print.rs | 2 +- .../kernel/src/state.rs | 2 +- .../kernel/src/synchronization.rs | 2 +- .../kernel/src/time.rs | 2 +- .../kernel/tests/00_console_sanity.rb | 6 +- .../kernel/tests/00_console_sanity.rs | 2 +- .../kernel/tests/01_timer_sanity.rs | 2 +- .../tests/02_exception_sync_page_fault.rs | 2 +- .../tests/03_exception_restore_sanity.rb | 6 +- .../tests/03_exception_restore_sanity.rs | 2 +- .../kernel/tests/04_exception_irq_sanity.rs | 2 +- .../kernel/tests/panic_exit_success/mod.rs | 2 +- .../kernel/tests/panic_wait_forever/mod.rs | 2 +- .../libraries/test-macros/src/lib.rs | 2 +- .../libraries/test-types/src/lib.rs | 2 +- .../.vscode/settings.json | 16 ++-- 14_virtual_mem_part2_mmio_remap/Makefile | 2 +- 14_virtual_mem_part2_mmio_remap/README.md | 8 +- .../kernel/src/_arch/aarch64/cpu.rs | 2 +- .../kernel/src/_arch/aarch64/cpu/boot.rs | 2 +- .../kernel/src/_arch/aarch64/cpu/smp.rs | 2 +- .../kernel/src/_arch/aarch64/exception.rs | 2 +- .../_arch/aarch64/exception/asynchronous.rs | 2 +- .../kernel/src/_arch/aarch64/memory/mmu.rs | 2 +- .../aarch64/memory/mmu/translation_table.rs | 2 +- .../kernel/src/_arch/aarch64/time.rs | 2 +- .../kernel/src/bsp.rs | 2 +- .../kernel/src/bsp/device_driver.rs | 2 +- .../kernel/src/bsp/device_driver/arm.rs | 2 +- .../kernel/src/bsp/device_driver/arm/gicv2.rs | 2 +- .../src/bsp/device_driver/arm/gicv2/gicc.rs | 2 +- .../src/bsp/device_driver/arm/gicv2/gicd.rs | 2 +- .../kernel/src/bsp/device_driver/bcm.rs | 2 +- .../src/bsp/device_driver/bcm/bcm2xxx_gpio.rs | 2 +- .../bcm/bcm2xxx_interrupt_controller.rs | 2 +- .../peripheral_ic.rs | 2 +- .../device_driver/bcm/bcm2xxx_pl011_uart.rs | 2 +- .../kernel/src/bsp/device_driver/common.rs | 2 +- .../kernel/src/bsp/raspberrypi.rs | 2 +- .../kernel/src/bsp/raspberrypi/cpu.rs | 2 +- .../kernel/src/bsp/raspberrypi/driver.rs | 2 +- .../kernel/src/bsp/raspberrypi/exception.rs | 2 +- .../bsp/raspberrypi/exception/asynchronous.rs | 2 +- .../kernel/src/bsp/raspberrypi/memory.rs | 2 +- .../kernel/src/bsp/raspberrypi/memory/mmu.rs | 2 +- .../kernel/src/common.rs | 2 +- .../kernel/src/console.rs | 2 +- .../kernel/src/console/null_console.rs | 2 +- .../kernel/src/cpu.rs | 2 +- .../kernel/src/cpu/boot.rs | 2 +- .../kernel/src/cpu/smp.rs | 2 +- .../kernel/src/driver.rs | 2 +- .../kernel/src/exception.rs | 2 +- .../kernel/src/exception/asynchronous.rs | 2 +- .../asynchronous/null_irq_manager.rs | 2 +- .../kernel/src/lib.rs | 2 +- .../kernel/src/main.rs | 2 +- .../kernel/src/memory.rs | 2 +- .../kernel/src/memory/mmu.rs | 2 +- .../kernel/src/memory/mmu/mapping_record.rs | 2 +- .../kernel/src/memory/mmu/page_alloc.rs | 2 +- .../src/memory/mmu/translation_table.rs | 2 +- .../kernel/src/memory/mmu/types.rs | 2 +- .../kernel/src/panic_wait.rs | 2 +- .../kernel/src/print.rs | 2 +- .../kernel/src/state.rs | 2 +- .../kernel/src/synchronization.rs | 2 +- .../kernel/src/time.rs | 2 +- .../kernel/tests/00_console_sanity.rb | 6 +- .../kernel/tests/00_console_sanity.rs | 2 +- .../kernel/tests/01_timer_sanity.rs | 2 +- .../tests/02_exception_sync_page_fault.rs | 2 +- .../tests/03_exception_restore_sanity.rb | 6 +- .../tests/03_exception_restore_sanity.rs | 2 +- .../kernel/tests/04_exception_irq_sanity.rs | 2 +- .../kernel/tests/panic_exit_success/mod.rs | 2 +- .../kernel/tests/panic_wait_forever/mod.rs | 2 +- .../libraries/test-macros/src/lib.rs | 2 +- .../libraries/test-types/src/lib.rs | 2 +- .../.vscode/settings.json | 16 ++-- .../Makefile | 2 +- .../README.md | 16 ++-- .../kernel/Cargo.toml | 8 +- .../kernel/src/_arch/aarch64/cpu.rs | 2 +- .../kernel/src/_arch/aarch64/cpu/boot.rs | 2 +- .../kernel/src/_arch/aarch64/cpu/smp.rs | 2 +- .../kernel/src/_arch/aarch64/exception.rs | 2 +- .../_arch/aarch64/exception/asynchronous.rs | 2 +- .../kernel/src/_arch/aarch64/memory/mmu.rs | 2 +- .../aarch64/memory/mmu/translation_table.rs | 2 +- .../kernel/src/_arch/aarch64/time.rs | 2 +- .../kernel/src/bsp.rs | 2 +- .../kernel/src/bsp/device_driver.rs | 2 +- .../kernel/src/bsp/device_driver/arm.rs | 2 +- .../kernel/src/bsp/device_driver/arm/gicv2.rs | 2 +- .../src/bsp/device_driver/arm/gicv2/gicc.rs | 2 +- .../src/bsp/device_driver/arm/gicv2/gicd.rs | 2 +- .../kernel/src/bsp/device_driver/bcm.rs | 2 +- .../src/bsp/device_driver/bcm/bcm2xxx_gpio.rs | 2 +- .../bcm/bcm2xxx_interrupt_controller.rs | 2 +- .../peripheral_ic.rs | 2 +- .../device_driver/bcm/bcm2xxx_pl011_uart.rs | 2 +- .../kernel/src/bsp/device_driver/common.rs | 2 +- .../kernel/src/bsp/raspberrypi.rs | 2 +- .../kernel/src/bsp/raspberrypi/cpu.rs | 2 +- .../kernel/src/bsp/raspberrypi/driver.rs | 2 +- .../kernel/src/bsp/raspberrypi/exception.rs | 2 +- .../bsp/raspberrypi/exception/asynchronous.rs | 2 +- .../kernel/src/bsp/raspberrypi/memory.rs | 2 +- .../kernel/src/bsp/raspberrypi/memory/mmu.rs | 2 +- .../kernel/src/common.rs | 2 +- .../kernel/src/console.rs | 2 +- .../kernel/src/console/null_console.rs | 2 +- .../kernel/src/cpu.rs | 2 +- .../kernel/src/cpu/boot.rs | 2 +- .../kernel/src/cpu/smp.rs | 2 +- .../kernel/src/driver.rs | 2 +- .../kernel/src/exception.rs | 2 +- .../kernel/src/exception/asynchronous.rs | 2 +- .../asynchronous/null_irq_manager.rs | 2 +- .../kernel/src/lib.rs | 2 +- .../kernel/src/main.rs | 2 +- .../kernel/src/memory.rs | 2 +- .../kernel/src/memory/mmu.rs | 2 +- .../kernel/src/memory/mmu/mapping_record.rs | 2 +- .../kernel/src/memory/mmu/page_alloc.rs | 2 +- .../src/memory/mmu/translation_table.rs | 2 +- .../kernel/src/memory/mmu/types.rs | 2 +- .../kernel/src/panic_wait.rs | 2 +- .../kernel/src/print.rs | 2 +- .../kernel/src/state.rs | 2 +- .../kernel/src/synchronization.rs | 2 +- .../kernel/src/time.rs | 2 +- .../kernel/tests/00_console_sanity.rb | 6 +- .../kernel/tests/00_console_sanity.rs | 2 +- .../kernel/tests/01_timer_sanity.rs | 2 +- .../tests/02_exception_sync_page_fault.rs | 2 +- .../tests/03_exception_restore_sanity.rb | 6 +- .../tests/03_exception_restore_sanity.rs | 2 +- .../kernel/tests/04_exception_irq_sanity.rs | 2 +- .../kernel/tests/panic_exit_success/mod.rs | 2 +- .../kernel/tests/panic_wait_forever/mod.rs | 2 +- .../libraries/test-macros/src/lib.rs | 2 +- .../libraries/test-types/src/lib.rs | 2 +- .../tools/translation_table_tool/arch.rb | 2 +- .../tools/translation_table_tool/bsp.rb | 2 +- .../tools/translation_table_tool/generic.rb | 4 +- .../translation_table_tool/kernel_elf.rb | 2 +- .../tools/translation_table_tool/main.rb | 2 +- .../.vscode/settings.json | 16 ++-- .../Makefile | 2 +- .../kernel/src/_arch/aarch64/cpu.rs | 2 +- .../kernel/src/_arch/aarch64/cpu/boot.rs | 2 +- .../kernel/src/_arch/aarch64/cpu/smp.rs | 2 +- .../kernel/src/_arch/aarch64/exception.rs | 2 +- .../_arch/aarch64/exception/asynchronous.rs | 2 +- .../kernel/src/_arch/aarch64/memory/mmu.rs | 2 +- .../aarch64/memory/mmu/translation_table.rs | 2 +- .../kernel/src/_arch/aarch64/time.rs | 2 +- .../kernel/src/bsp.rs | 2 +- .../kernel/src/bsp/device_driver.rs | 2 +- .../kernel/src/bsp/device_driver/arm.rs | 2 +- .../kernel/src/bsp/device_driver/arm/gicv2.rs | 2 +- .../src/bsp/device_driver/arm/gicv2/gicc.rs | 2 +- .../src/bsp/device_driver/arm/gicv2/gicd.rs | 2 +- .../kernel/src/bsp/device_driver/bcm.rs | 2 +- .../src/bsp/device_driver/bcm/bcm2xxx_gpio.rs | 2 +- .../bcm/bcm2xxx_interrupt_controller.rs | 2 +- .../peripheral_ic.rs | 2 +- .../device_driver/bcm/bcm2xxx_pl011_uart.rs | 2 +- .../kernel/src/bsp/device_driver/common.rs | 2 +- .../kernel/src/bsp/raspberrypi.rs | 2 +- .../kernel/src/bsp/raspberrypi/cpu.rs | 2 +- .../kernel/src/bsp/raspberrypi/driver.rs | 2 +- .../kernel/src/bsp/raspberrypi/exception.rs | 2 +- .../bsp/raspberrypi/exception/asynchronous.rs | 2 +- .../kernel/src/bsp/raspberrypi/memory.rs | 2 +- .../kernel/src/bsp/raspberrypi/memory/mmu.rs | 2 +- .../kernel/src/common.rs | 2 +- .../kernel/src/console.rs | 2 +- .../kernel/src/console/null_console.rs | 2 +- .../kernel/src/cpu.rs | 2 +- .../kernel/src/cpu/boot.rs | 2 +- .../kernel/src/cpu/smp.rs | 2 +- .../kernel/src/driver.rs | 2 +- .../kernel/src/exception.rs | 2 +- .../kernel/src/exception/asynchronous.rs | 2 +- .../asynchronous/null_irq_manager.rs | 2 +- .../kernel/src/lib.rs | 2 +- .../kernel/src/main.rs | 2 +- .../kernel/src/memory.rs | 2 +- .../kernel/src/memory/mmu.rs | 2 +- .../kernel/src/memory/mmu/mapping_record.rs | 2 +- .../kernel/src/memory/mmu/page_alloc.rs | 2 +- .../src/memory/mmu/translation_table.rs | 2 +- .../kernel/src/memory/mmu/types.rs | 2 +- .../kernel/src/panic_wait.rs | 2 +- .../kernel/src/print.rs | 2 +- .../kernel/src/state.rs | 2 +- .../kernel/src/synchronization.rs | 2 +- .../kernel/src/time.rs | 2 +- .../kernel/tests/00_console_sanity.rb | 6 +- .../kernel/tests/00_console_sanity.rs | 2 +- .../kernel/tests/01_timer_sanity.rs | 2 +- .../tests/02_exception_sync_page_fault.rs | 2 +- .../tests/03_exception_restore_sanity.rb | 6 +- .../tests/03_exception_restore_sanity.rs | 2 +- .../kernel/tests/04_exception_irq_sanity.rs | 2 +- .../kernel/tests/panic_exit_success/mod.rs | 2 +- .../kernel/tests/panic_wait_forever/mod.rs | 2 +- .../libraries/test-macros/src/lib.rs | 2 +- .../libraries/test-types/src/lib.rs | 2 +- .../tools/translation_table_tool/arch.rb | 2 +- .../tools/translation_table_tool/bsp.rb | 2 +- .../tools/translation_table_tool/generic.rb | 4 +- .../translation_table_tool/kernel_elf.rb | 2 +- .../tools/translation_table_tool/main.rb | 2 +- 17_kernel_symbols/.vscode/settings.json | 16 ++-- 17_kernel_symbols/Makefile | 2 +- 17_kernel_symbols/README.md | 16 ++-- .../kernel/src/_arch/aarch64/cpu.rs | 2 +- .../kernel/src/_arch/aarch64/cpu/boot.rs | 2 +- .../kernel/src/_arch/aarch64/cpu/smp.rs | 2 +- .../kernel/src/_arch/aarch64/exception.rs | 2 +- .../_arch/aarch64/exception/asynchronous.rs | 2 +- .../kernel/src/_arch/aarch64/memory/mmu.rs | 2 +- .../aarch64/memory/mmu/translation_table.rs | 2 +- .../kernel/src/_arch/aarch64/time.rs | 2 +- 17_kernel_symbols/kernel/src/bsp.rs | 2 +- .../kernel/src/bsp/device_driver.rs | 2 +- .../kernel/src/bsp/device_driver/arm.rs | 2 +- .../kernel/src/bsp/device_driver/arm/gicv2.rs | 2 +- .../src/bsp/device_driver/arm/gicv2/gicc.rs | 2 +- .../src/bsp/device_driver/arm/gicv2/gicd.rs | 2 +- .../kernel/src/bsp/device_driver/bcm.rs | 2 +- .../src/bsp/device_driver/bcm/bcm2xxx_gpio.rs | 2 +- .../bcm/bcm2xxx_interrupt_controller.rs | 2 +- .../peripheral_ic.rs | 2 +- .../device_driver/bcm/bcm2xxx_pl011_uart.rs | 2 +- .../kernel/src/bsp/device_driver/common.rs | 2 +- .../kernel/src/bsp/raspberrypi.rs | 2 +- .../kernel/src/bsp/raspberrypi/cpu.rs | 2 +- .../kernel/src/bsp/raspberrypi/driver.rs | 2 +- .../kernel/src/bsp/raspberrypi/exception.rs | 2 +- .../bsp/raspberrypi/exception/asynchronous.rs | 2 +- .../kernel/src/bsp/raspberrypi/memory.rs | 2 +- .../kernel/src/bsp/raspberrypi/memory/mmu.rs | 2 +- 17_kernel_symbols/kernel/src/common.rs | 2 +- 17_kernel_symbols/kernel/src/console.rs | 2 +- .../kernel/src/console/null_console.rs | 2 +- 17_kernel_symbols/kernel/src/cpu.rs | 2 +- 17_kernel_symbols/kernel/src/cpu/boot.rs | 2 +- 17_kernel_symbols/kernel/src/cpu/smp.rs | 2 +- 17_kernel_symbols/kernel/src/driver.rs | 2 +- 17_kernel_symbols/kernel/src/exception.rs | 2 +- .../kernel/src/exception/asynchronous.rs | 2 +- .../asynchronous/null_irq_manager.rs | 2 +- 17_kernel_symbols/kernel/src/lib.rs | 2 +- 17_kernel_symbols/kernel/src/main.rs | 2 +- 17_kernel_symbols/kernel/src/memory.rs | 2 +- 17_kernel_symbols/kernel/src/memory/mmu.rs | 2 +- .../kernel/src/memory/mmu/mapping_record.rs | 2 +- .../kernel/src/memory/mmu/page_alloc.rs | 2 +- .../src/memory/mmu/translation_table.rs | 2 +- .../kernel/src/memory/mmu/types.rs | 2 +- 17_kernel_symbols/kernel/src/panic_wait.rs | 2 +- 17_kernel_symbols/kernel/src/print.rs | 2 +- 17_kernel_symbols/kernel/src/state.rs | 2 +- 17_kernel_symbols/kernel/src/symbols.rs | 2 +- .../kernel/src/synchronization.rs | 2 +- 17_kernel_symbols/kernel/src/time.rs | 2 +- .../kernel/tests/00_console_sanity.rb | 6 +- .../kernel/tests/00_console_sanity.rs | 2 +- .../kernel/tests/01_timer_sanity.rs | 2 +- .../tests/02_exception_sync_page_fault.rs | 2 +- .../tests/03_exception_restore_sanity.rb | 6 +- .../tests/03_exception_restore_sanity.rs | 2 +- .../kernel/tests/04_exception_irq_sanity.rs | 2 +- .../kernel/tests/panic_exit_success/mod.rs | 2 +- .../kernel/tests/panic_wait_forever/mod.rs | 2 +- 17_kernel_symbols/kernel_symbols.mk | 2 +- 17_kernel_symbols/kernel_symbols/src/main.rs | 2 +- .../libraries/debug-symbol-types/src/lib.rs | 2 +- .../libraries/test-macros/src/lib.rs | 2 +- .../libraries/test-types/src/lib.rs | 2 +- .../tools/kernel_symbols_tool/cmds.rb | 2 +- .../tools/kernel_symbols_tool/kernel_elf.rb | 2 +- .../tools/kernel_symbols_tool/main.rb | 2 +- .../tools/translation_table_tool/arch.rb | 2 +- .../tools/translation_table_tool/bsp.rb | 2 +- .../tools/translation_table_tool/generic.rb | 4 +- .../translation_table_tool/kernel_elf.rb | 2 +- .../tools/translation_table_tool/main.rb | 2 +- 18_backtrace/.vscode/settings.json | 16 ++-- 18_backtrace/Makefile | 2 +- 18_backtrace/README.md | 16 ++-- .../kernel/src/_arch/aarch64/backtrace.rs | 2 +- 18_backtrace/kernel/src/_arch/aarch64/cpu.rs | 2 +- .../kernel/src/_arch/aarch64/cpu/boot.rs | 2 +- .../kernel/src/_arch/aarch64/cpu/boot.s | 2 +- .../kernel/src/_arch/aarch64/cpu/smp.rs | 2 +- .../kernel/src/_arch/aarch64/exception.rs | 2 +- .../_arch/aarch64/exception/asynchronous.rs | 2 +- .../kernel/src/_arch/aarch64/memory/mmu.rs | 2 +- .../aarch64/memory/mmu/translation_table.rs | 2 +- 18_backtrace/kernel/src/_arch/aarch64/time.rs | 2 +- 18_backtrace/kernel/src/backtrace.rs | 2 +- 18_backtrace/kernel/src/bsp.rs | 2 +- 18_backtrace/kernel/src/bsp/device_driver.rs | 2 +- .../kernel/src/bsp/device_driver/arm.rs | 2 +- .../kernel/src/bsp/device_driver/arm/gicv2.rs | 2 +- .../src/bsp/device_driver/arm/gicv2/gicc.rs | 2 +- .../src/bsp/device_driver/arm/gicv2/gicd.rs | 2 +- .../kernel/src/bsp/device_driver/bcm.rs | 2 +- .../src/bsp/device_driver/bcm/bcm2xxx_gpio.rs | 2 +- .../bcm/bcm2xxx_interrupt_controller.rs | 2 +- .../peripheral_ic.rs | 2 +- .../device_driver/bcm/bcm2xxx_pl011_uart.rs | 2 +- .../kernel/src/bsp/device_driver/common.rs | 2 +- 18_backtrace/kernel/src/bsp/raspberrypi.rs | 2 +- .../kernel/src/bsp/raspberrypi/cpu.rs | 2 +- .../kernel/src/bsp/raspberrypi/driver.rs | 2 +- .../kernel/src/bsp/raspberrypi/exception.rs | 2 +- .../bsp/raspberrypi/exception/asynchronous.rs | 2 +- .../kernel/src/bsp/raspberrypi/memory.rs | 2 +- .../kernel/src/bsp/raspberrypi/memory/mmu.rs | 2 +- 18_backtrace/kernel/src/common.rs | 2 +- 18_backtrace/kernel/src/console.rs | 2 +- .../kernel/src/console/null_console.rs | 2 +- 18_backtrace/kernel/src/cpu.rs | 2 +- 18_backtrace/kernel/src/cpu/boot.rs | 2 +- 18_backtrace/kernel/src/cpu/smp.rs | 2 +- 18_backtrace/kernel/src/driver.rs | 2 +- 18_backtrace/kernel/src/exception.rs | 2 +- .../kernel/src/exception/asynchronous.rs | 2 +- .../asynchronous/null_irq_manager.rs | 2 +- 18_backtrace/kernel/src/lib.rs | 2 +- 18_backtrace/kernel/src/main.rs | 2 +- 18_backtrace/kernel/src/memory.rs | 2 +- 18_backtrace/kernel/src/memory/mmu.rs | 2 +- .../kernel/src/memory/mmu/mapping_record.rs | 2 +- .../kernel/src/memory/mmu/page_alloc.rs | 2 +- .../src/memory/mmu/translation_table.rs | 2 +- 18_backtrace/kernel/src/memory/mmu/types.rs | 2 +- 18_backtrace/kernel/src/panic_wait.rs | 2 +- 18_backtrace/kernel/src/print.rs | 2 +- 18_backtrace/kernel/src/state.rs | 2 +- 18_backtrace/kernel/src/symbols.rs | 2 +- 18_backtrace/kernel/src/synchronization.rs | 2 +- 18_backtrace/kernel/src/time.rs | 2 +- .../kernel/tests/00_console_sanity.rb | 6 +- .../kernel/tests/00_console_sanity.rs | 2 +- 18_backtrace/kernel/tests/01_timer_sanity.rs | 2 +- .../tests/02_exception_sync_page_fault.rs | 2 +- .../tests/03_exception_restore_sanity.rb | 6 +- .../tests/03_exception_restore_sanity.rs | 2 +- .../kernel/tests/04_exception_irq_sanity.rs | 2 +- .../kernel/tests/05_backtrace_sanity.rb | 6 +- .../kernel/tests/05_backtrace_sanity.rs | 2 +- .../tests/06_backtrace_invalid_frame.rb | 6 +- .../tests/06_backtrace_invalid_frame.rs | 2 +- .../kernel/tests/07_backtrace_invalid_link.rb | 6 +- .../kernel/tests/07_backtrace_invalid_link.rs | 2 +- .../kernel/tests/panic_exit_success/mod.rs | 2 +- .../kernel/tests/panic_wait_forever/mod.rs | 2 +- 18_backtrace/kernel_symbols.mk | 2 +- 18_backtrace/kernel_symbols/src/main.rs | 2 +- .../libraries/debug-symbol-types/src/lib.rs | 2 +- 18_backtrace/libraries/test-macros/src/lib.rs | 2 +- 18_backtrace/libraries/test-types/src/lib.rs | 2 +- .../tools/kernel_symbols_tool/cmds.rb | 2 +- .../tools/kernel_symbols_tool/kernel_elf.rb | 2 +- .../tools/kernel_symbols_tool/main.rb | 2 +- .../tools/translation_table_tool/arch.rb | 2 +- .../tools/translation_table_tool/bsp.rb | 2 +- .../tools/translation_table_tool/generic.rb | 4 +- .../translation_table_tool/kernel_elf.rb | 2 +- .../tools/translation_table_tool/main.rb | 2 +- 19_kernel_heap/.vscode/settings.json | 16 ++-- 19_kernel_heap/Makefile | 2 +- 19_kernel_heap/README.md | 6 +- .../kernel/src/_arch/aarch64/backtrace.rs | 2 +- .../kernel/src/_arch/aarch64/cpu.rs | 2 +- .../kernel/src/_arch/aarch64/cpu/boot.rs | 2 +- .../kernel/src/_arch/aarch64/cpu/smp.rs | 2 +- .../kernel/src/_arch/aarch64/exception.rs | 2 +- .../_arch/aarch64/exception/asynchronous.rs | 2 +- .../kernel/src/_arch/aarch64/memory/mmu.rs | 2 +- .../aarch64/memory/mmu/translation_table.rs | 2 +- .../kernel/src/_arch/aarch64/time.rs | 2 +- 19_kernel_heap/kernel/src/backtrace.rs | 2 +- 19_kernel_heap/kernel/src/bsp.rs | 2 +- .../kernel/src/bsp/device_driver.rs | 2 +- .../kernel/src/bsp/device_driver/arm.rs | 2 +- .../kernel/src/bsp/device_driver/arm/gicv2.rs | 2 +- .../src/bsp/device_driver/arm/gicv2/gicc.rs | 2 +- .../src/bsp/device_driver/arm/gicv2/gicd.rs | 2 +- .../kernel/src/bsp/device_driver/bcm.rs | 2 +- .../src/bsp/device_driver/bcm/bcm2xxx_gpio.rs | 2 +- .../bcm/bcm2xxx_interrupt_controller.rs | 2 +- .../peripheral_ic.rs | 2 +- .../device_driver/bcm/bcm2xxx_pl011_uart.rs | 2 +- .../kernel/src/bsp/device_driver/common.rs | 2 +- 19_kernel_heap/kernel/src/bsp/raspberrypi.rs | 2 +- .../kernel/src/bsp/raspberrypi/cpu.rs | 2 +- .../kernel/src/bsp/raspberrypi/driver.rs | 2 +- .../kernel/src/bsp/raspberrypi/exception.rs | 2 +- .../bsp/raspberrypi/exception/asynchronous.rs | 2 +- .../kernel/src/bsp/raspberrypi/memory.rs | 2 +- .../kernel/src/bsp/raspberrypi/memory/mmu.rs | 2 +- 19_kernel_heap/kernel/src/common.rs | 2 +- 19_kernel_heap/kernel/src/console.rs | 2 +- .../kernel/src/console/buffer_console.rs | 2 +- 19_kernel_heap/kernel/src/cpu.rs | 2 +- 19_kernel_heap/kernel/src/cpu/boot.rs | 2 +- 19_kernel_heap/kernel/src/cpu/smp.rs | 2 +- 19_kernel_heap/kernel/src/driver.rs | 2 +- 19_kernel_heap/kernel/src/exception.rs | 2 +- .../kernel/src/exception/asynchronous.rs | 2 +- .../asynchronous/null_irq_manager.rs | 2 +- 19_kernel_heap/kernel/src/lib.rs | 2 +- 19_kernel_heap/kernel/src/main.rs | 2 +- 19_kernel_heap/kernel/src/memory.rs | 2 +- .../kernel/src/memory/heap_alloc.rs | 2 +- 19_kernel_heap/kernel/src/memory/mmu.rs | 2 +- .../kernel/src/memory/mmu/mapping_record.rs | 2 +- .../kernel/src/memory/mmu/page_alloc.rs | 2 +- .../src/memory/mmu/translation_table.rs | 2 +- 19_kernel_heap/kernel/src/memory/mmu/types.rs | 2 +- 19_kernel_heap/kernel/src/panic_wait.rs | 2 +- 19_kernel_heap/kernel/src/print.rs | 2 +- 19_kernel_heap/kernel/src/state.rs | 2 +- 19_kernel_heap/kernel/src/symbols.rs | 2 +- 19_kernel_heap/kernel/src/synchronization.rs | 2 +- 19_kernel_heap/kernel/src/time.rs | 2 +- .../kernel/tests/00_console_sanity.rb | 6 +- .../kernel/tests/00_console_sanity.rs | 2 +- .../kernel/tests/01_timer_sanity.rs | 2 +- .../tests/02_exception_sync_page_fault.rs | 2 +- .../tests/03_exception_restore_sanity.rb | 6 +- .../tests/03_exception_restore_sanity.rs | 2 +- .../kernel/tests/04_exception_irq_sanity.rs | 2 +- .../kernel/tests/05_backtrace_sanity.rb | 6 +- .../kernel/tests/05_backtrace_sanity.rs | 2 +- .../tests/06_backtrace_invalid_frame.rb | 6 +- .../tests/06_backtrace_invalid_frame.rs | 2 +- .../kernel/tests/07_backtrace_invalid_link.rb | 6 +- .../kernel/tests/07_backtrace_invalid_link.rs | 2 +- .../kernel/tests/panic_exit_success/mod.rs | 2 +- .../kernel/tests/panic_wait_forever/mod.rs | 2 +- 19_kernel_heap/kernel_symbols.mk | 2 +- 19_kernel_heap/kernel_symbols/src/main.rs | 2 +- .../libraries/debug-symbol-types/src/lib.rs | 2 +- .../libraries/test-macros/src/lib.rs | 2 +- .../libraries/test-types/src/lib.rs | 2 +- .../tools/kernel_symbols_tool/cmds.rb | 2 +- .../tools/kernel_symbols_tool/kernel_elf.rb | 2 +- .../tools/kernel_symbols_tool/main.rb | 2 +- .../tools/translation_table_tool/arch.rb | 2 +- .../tools/translation_table_tool/bsp.rb | 2 +- .../tools/translation_table_tool/generic.rb | 4 +- .../translation_table_tool/kernel_elf.rb | 2 +- .../tools/translation_table_tool/main.rb | 2 +- 20_timer_callbacks/.vscode/settings.json | 16 ++-- 20_timer_callbacks/Makefile | 2 +- 20_timer_callbacks/README.md | 4 +- 20_timer_callbacks/kernel/Cargo.toml | 8 +- .../kernel/src/_arch/aarch64/backtrace.rs | 2 +- .../kernel/src/_arch/aarch64/cpu.rs | 2 +- .../kernel/src/_arch/aarch64/cpu/boot.rs | 2 +- .../kernel/src/_arch/aarch64/cpu/boot.s | 2 +- .../kernel/src/_arch/aarch64/cpu/smp.rs | 2 +- .../kernel/src/_arch/aarch64/exception.rs | 2 +- .../kernel/src/_arch/aarch64/exception.s | 2 +- .../_arch/aarch64/exception/asynchronous.rs | 2 +- .../kernel/src/_arch/aarch64/memory/mmu.rs | 2 +- .../aarch64/memory/mmu/translation_table.rs | 2 +- .../kernel/src/_arch/aarch64/time.rs | 2 +- 20_timer_callbacks/kernel/src/backtrace.rs | 2 +- 20_timer_callbacks/kernel/src/bsp.rs | 2 +- .../kernel/src/bsp/device_driver.rs | 2 +- .../kernel/src/bsp/device_driver/arm.rs | 2 +- .../kernel/src/bsp/device_driver/arm/gicv2.rs | 2 +- .../src/bsp/device_driver/arm/gicv2/gicc.rs | 2 +- .../src/bsp/device_driver/arm/gicv2/gicd.rs | 2 +- .../kernel/src/bsp/device_driver/bcm.rs | 2 +- .../src/bsp/device_driver/bcm/bcm2xxx_gpio.rs | 2 +- .../bcm/bcm2xxx_interrupt_controller.rs | 2 +- .../bcm2xxx_interrupt_controller/local_ic.rs | 2 +- .../peripheral_ic.rs | 2 +- .../device_driver/bcm/bcm2xxx_pl011_uart.rs | 2 +- .../kernel/src/bsp/device_driver/common.rs | 2 +- .../kernel/src/bsp/raspberrypi.rs | 2 +- .../kernel/src/bsp/raspberrypi/cpu.rs | 2 +- .../kernel/src/bsp/raspberrypi/driver.rs | 2 +- .../kernel/src/bsp/raspberrypi/exception.rs | 2 +- .../bsp/raspberrypi/exception/asynchronous.rs | 2 +- .../kernel/src/bsp/raspberrypi/memory.rs | 2 +- .../kernel/src/bsp/raspberrypi/memory/mmu.rs | 2 +- 20_timer_callbacks/kernel/src/common.rs | 2 +- 20_timer_callbacks/kernel/src/console.rs | 2 +- .../kernel/src/console/buffer_console.rs | 2 +- 20_timer_callbacks/kernel/src/cpu.rs | 2 +- 20_timer_callbacks/kernel/src/cpu/boot.rs | 2 +- 20_timer_callbacks/kernel/src/cpu/smp.rs | 2 +- 20_timer_callbacks/kernel/src/driver.rs | 2 +- 20_timer_callbacks/kernel/src/exception.rs | 2 +- .../kernel/src/exception/asynchronous.rs | 2 +- .../asynchronous/null_irq_manager.rs | 2 +- 20_timer_callbacks/kernel/src/lib.rs | 2 +- 20_timer_callbacks/kernel/src/main.rs | 2 +- 20_timer_callbacks/kernel/src/memory.rs | 2 +- .../kernel/src/memory/heap_alloc.rs | 2 +- 20_timer_callbacks/kernel/src/memory/mmu.rs | 2 +- .../kernel/src/memory/mmu/mapping_record.rs | 2 +- .../kernel/src/memory/mmu/page_alloc.rs | 2 +- .../src/memory/mmu/translation_table.rs | 2 +- .../kernel/src/memory/mmu/types.rs | 2 +- 20_timer_callbacks/kernel/src/panic_wait.rs | 2 +- 20_timer_callbacks/kernel/src/print.rs | 2 +- 20_timer_callbacks/kernel/src/state.rs | 2 +- 20_timer_callbacks/kernel/src/symbols.rs | 2 +- .../kernel/src/synchronization.rs | 2 +- 20_timer_callbacks/kernel/src/time.rs | 2 +- .../kernel/tests/00_console_sanity.rb | 6 +- .../kernel/tests/00_console_sanity.rs | 2 +- .../kernel/tests/01_timer_sanity.rs | 2 +- .../tests/02_exception_sync_page_fault.rs | 2 +- .../tests/03_exception_restore_sanity.rb | 6 +- .../tests/03_exception_restore_sanity.rs | 2 +- .../kernel/tests/04_exception_irq_sanity.rs | 2 +- .../kernel/tests/05_backtrace_sanity.rb | 6 +- .../kernel/tests/05_backtrace_sanity.rs | 2 +- .../tests/06_backtrace_invalid_frame.rb | 6 +- .../tests/06_backtrace_invalid_frame.rs | 2 +- .../kernel/tests/07_backtrace_invalid_link.rb | 6 +- .../kernel/tests/07_backtrace_invalid_link.rs | 2 +- .../kernel/tests/panic_exit_success/mod.rs | 2 +- .../kernel/tests/panic_wait_forever/mod.rs | 2 +- 20_timer_callbacks/kernel_symbols.mk | 2 +- .../kernel_symbols/kernel_symbols.ld | 2 +- 20_timer_callbacks/kernel_symbols/src/main.rs | 2 +- .../libraries/debug-symbol-types/src/lib.rs | 2 +- .../libraries/test-macros/src/lib.rs | 2 +- .../libraries/test-types/src/lib.rs | 2 +- .../tools/kernel_symbols_tool/cmds.rb | 2 +- .../tools/kernel_symbols_tool/kernel_elf.rb | 2 +- .../tools/kernel_symbols_tool/main.rb | 2 +- .../tools/translation_table_tool/arch.rb | 2 +- .../tools/translation_table_tool/bsp.rb | 2 +- .../tools/translation_table_tool/generic.rb | 4 +- .../translation_table_tool/kernel_elf.rb | 2 +- .../tools/translation_table_tool/main.rb | 2 +- LICENSE-MIT | 2 +- X1_JTAG_boot/.vscode/settings.json | 16 ++-- X1_JTAG_boot/Makefile | 2 +- X1_JTAG_boot/src/_arch/aarch64/cpu.rs | 2 +- X1_JTAG_boot/src/_arch/aarch64/cpu/boot.rs | 2 +- X1_JTAG_boot/src/_arch/aarch64/cpu/boot.s | 2 +- X1_JTAG_boot/src/_arch/aarch64/time.rs | 2 +- X1_JTAG_boot/src/bsp.rs | 2 +- X1_JTAG_boot/src/bsp/device_driver.rs | 2 +- X1_JTAG_boot/src/bsp/device_driver/bcm.rs | 2 +- .../src/bsp/device_driver/bcm/bcm2xxx_gpio.rs | 2 +- .../device_driver/bcm/bcm2xxx_pl011_uart.rs | 2 +- X1_JTAG_boot/src/bsp/device_driver/common.rs | 2 +- X1_JTAG_boot/src/bsp/raspberrypi.rs | 2 +- X1_JTAG_boot/src/bsp/raspberrypi/cpu.rs | 2 +- X1_JTAG_boot/src/bsp/raspberrypi/driver.rs | 2 +- X1_JTAG_boot/src/bsp/raspberrypi/kernel.ld | 2 +- X1_JTAG_boot/src/bsp/raspberrypi/memory.rs | 2 +- X1_JTAG_boot/src/console.rs | 2 +- X1_JTAG_boot/src/console/null_console.rs | 2 +- X1_JTAG_boot/src/cpu.rs | 2 +- X1_JTAG_boot/src/cpu/boot.rs | 2 +- X1_JTAG_boot/src/driver.rs | 2 +- X1_JTAG_boot/src/main.rs | 2 +- X1_JTAG_boot/src/panic_wait.rs | 2 +- X1_JTAG_boot/src/print.rs | 2 +- X1_JTAG_boot/src/synchronization.rs | 2 +- X1_JTAG_boot/src/time.rs | 2 +- common/serial/minipush.rb | 6 +- common/serial/minipush/progressbar_patch.rb | 2 +- common/serial/miniterm.rb | 6 +- common/tests/boot_test.rb | 2 +- common/tests/console_io_test.rb | 2 +- common/tests/dispatch.rb | 2 +- common/tests/exit_code_test.rb | 2 +- common/tests/test.rb | 2 +- docker/rustembedded-osdev-utils/Dockerfile | 4 +- docker/rustembedded-osdev-utils/Makefile | 2 +- utils/devtool.rb | 6 +- utils/devtool/copyright.rb | 2 +- utils/diff_tut_folders.bash | 2 +- utils/update_copyright.rb | 2 +- 958 files changed, 1504 insertions(+), 1472 deletions(-) diff --git a/.githooks/pre-commit b/.githooks/pre-commit index e9570651..71381892 100755 --- a/.githooks/pre-commit +++ b/.githooks/pre-commit @@ -3,7 +3,7 @@ # SPDX-License-Identifier: MIT OR Apache-2.0 # -# Copyright (c) 2018-2022 Andre Richter +# Copyright (c) 2018-2023 Andre Richter require_relative '../utils/devtool/copyright' @@ -23,9 +23,9 @@ def copyright_check(staged_files) copyright_check_files(staged_files) end -##-------------------------------------------------------------------------------------------------- +## ------------------------------------------------------------------------------------------------- ## Execution starts here -##-------------------------------------------------------------------------------------------------- +## ------------------------------------------------------------------------------------------------- staged_files = `git --no-pager diff --name-only --cached --diff-filter=d`.split(/\n/) root_dir = `git rev-parse --show-toplevel`.strip diff --git a/.github/workflows/build_rpi3.yml b/.github/workflows/build_rpi3.yml index 179752b7..b3b997b3 100644 --- a/.github/workflows/build_rpi3.yml +++ b/.github/workflows/build_rpi3.yml @@ -1,40 +1,40 @@ name: BSP-RPi3 on: - push: - branches: - - master - paths-ignore: - - "utils/**" - - "doc/**" - - "docker/**" - pull_request: - branches: - - master - paths-ignore: - - "utils/**" - - "doc/**" - - "docker/**" - schedule: - - cron: "0 5 * * *" + push: + branches: + - master + paths-ignore: + - "utils/**" + - "doc/**" + - "docker/**" + pull_request: + branches: + - master + paths-ignore: + - "utils/**" + - "doc/**" + - "docker/**" + schedule: + - cron: "0 5 * * *" jobs: - build: - name: Build kernels - runs-on: ubuntu-22.04 + build: + name: Build kernels + runs-on: ubuntu-22.04 - steps: - - uses: actions/checkout@v3 - - name: Set up Ruby - uses: ruby/setup-ruby@v1 - - name: Set up Rust nightly - run: | - cargo install cargo-binutils rustfilt - - name: Set up Ruby - run: | - gem install bundler - bundle config set without 'uart' - bundle install --retry 3 - - name: Run - run: | - BSP=rpi3 bundle exec ruby utils/devtool.rb make + steps: + - uses: actions/checkout@v3 + - name: Set up Ruby + uses: ruby/setup-ruby@v1 + - name: Set up Rust nightly + run: | + cargo install cargo-binutils rustfilt + - name: Set up Ruby + run: | + gem install bundler + bundle config set without 'uart' + bundle install --retry 3 + - name: Run + run: | + BSP=rpi3 bundle exec ruby utils/devtool.rb make diff --git a/.github/workflows/build_rpi4.yml b/.github/workflows/build_rpi4.yml index 88d69885..ca15786e 100644 --- a/.github/workflows/build_rpi4.yml +++ b/.github/workflows/build_rpi4.yml @@ -1,40 +1,40 @@ name: BSP-RPi4 on: - push: - branches: - - master - paths-ignore: - - "utils/**" - - "doc/**" - - "docker/**" - pull_request: - branches: - - master - paths-ignore: - - "utils/**" - - "doc/**" - - "docker/**" - schedule: - - cron: "0 5 * * *" + push: + branches: + - master + paths-ignore: + - "utils/**" + - "doc/**" + - "docker/**" + pull_request: + branches: + - master + paths-ignore: + - "utils/**" + - "doc/**" + - "docker/**" + schedule: + - cron: "0 5 * * *" jobs: - build: - name: Build kernels - runs-on: ubuntu-22.04 + build: + name: Build kernels + runs-on: ubuntu-22.04 - steps: - - uses: actions/checkout@v3 - - name: Set up Ruby - uses: ruby/setup-ruby@v1 - - name: Set up Rust nightly - run: | - cargo install cargo-binutils rustfilt - - name: Set up Ruby - run: | - gem install bundler - bundle config set without 'uart' - bundle install --retry 3 - - name: Run - run: | - BSP=rpi4 bundle exec ruby utils/devtool.rb make + steps: + - uses: actions/checkout@v3 + - name: Set up Ruby + uses: ruby/setup-ruby@v1 + - name: Set up Rust nightly + run: | + cargo install cargo-binutils rustfilt + - name: Set up Ruby + run: | + gem install bundler + bundle config set without 'uart' + bundle install --retry 3 + - name: Run + run: | + BSP=rpi4 bundle exec ruby utils/devtool.rb make diff --git a/.github/workflows/sanity.yml b/.github/workflows/sanity.yml index fc14b242..3eb0f088 100644 --- a/.github/workflows/sanity.yml +++ b/.github/workflows/sanity.yml @@ -1,46 +1,46 @@ name: Various Sanity Checks on: - push: - branches: - - master - pull_request: - branches: - - master + push: + branches: + - master + pull_request: + branches: + - master jobs: - build: - name: Various Sanity Checks - runs-on: ubuntu-22.04 + build: + name: Various Sanity Checks + runs-on: ubuntu-22.04 - steps: - - uses: actions/checkout@v3 - - name: Set up Node - uses: actions/setup-node@v1 - with: - node-version: "16" - - name: Set up Ruby - uses: ruby/setup-ruby@v1 - - name: Set up Rust nightly - run: | - rustup component add clippy - - name: Set up Bundler - run: | - gem install bundler - bundle config set without 'uart' - bundle install --retry 3 - - name: Set up Prettier - run: | - npm install prettier - - name: Setup misspell - run: | - curl -L -o ./install-misspell.sh https://raw.githubusercontent.com/client9/misspell/master/install-misspell.sh - sh ./install-misspell.sh -b .vendor - - name: Run checks - run: | - BSP=rpi3 bundle exec ruby utils/devtool.rb clippy - BSP=rpi4 bundle exec ruby utils/devtool.rb clippy - bundle exec ruby utils/devtool.rb copyright - bundle exec ruby utils/devtool.rb fmt_check - bundle exec ruby utils/devtool.rb misspell - bundle exec ruby utils/devtool.rb rubocop + steps: + - uses: actions/checkout@v3 + - name: Set up Node + uses: actions/setup-node@v1 + with: + node-version: "16" + - name: Set up Ruby + uses: ruby/setup-ruby@v1 + - name: Set up Rust nightly + run: | + rustup component add clippy + - name: Set up Bundler + run: | + gem install bundler + bundle config set without 'uart' + bundle install --retry 3 + - name: Set up Prettier + run: | + npm install prettier + - name: Setup misspell + run: | + curl -L -o ./install-misspell.sh https://raw.githubusercontent.com/client9/misspell/master/install-misspell.sh + sh ./install-misspell.sh -b .vendor + - name: Run checks + run: | + BSP=rpi3 bundle exec ruby utils/devtool.rb clippy + BSP=rpi4 bundle exec ruby utils/devtool.rb clippy + bundle exec ruby utils/devtool.rb copyright + bundle exec ruby utils/devtool.rb fmt_check + bundle exec ruby utils/devtool.rb misspell + bundle exec ruby utils/devtool.rb rubocop diff --git a/.github/workflows/test_integration.yml b/.github/workflows/test_integration.yml index affc9793..7e3ab076 100644 --- a/.github/workflows/test_integration.yml +++ b/.github/workflows/test_integration.yml @@ -1,40 +1,40 @@ name: Integration-Tests on: - push: - branches: - - master - paths-ignore: - - "utils/**" - - "doc/**" - - "docker/**" - pull_request: - branches: - - master - paths-ignore: - - "utils/**" - - "doc/**" - - "docker/**" - schedule: - - cron: "0 5 * * *" + push: + branches: + - master + paths-ignore: + - "utils/**" + - "doc/**" + - "docker/**" + pull_request: + branches: + - master + paths-ignore: + - "utils/**" + - "doc/**" + - "docker/**" + schedule: + - cron: "0 5 * * *" jobs: - build: - name: Run integration tests - runs-on: ubuntu-22.04 + build: + name: Run integration tests + runs-on: ubuntu-22.04 - steps: - - uses: actions/checkout@v3 - - name: Set up Ruby - uses: ruby/setup-ruby@v1 - - name: Set up Rust nightly - run: | - cargo install cargo-binutils rustfilt - - name: Set up Ruby - run: | - gem install bundler - bundle config set without 'uart' - bundle install --retry 3 - - name: Run - run: | - bundle exec ruby utils/devtool.rb test_integration + steps: + - uses: actions/checkout@v3 + - name: Set up Ruby + uses: ruby/setup-ruby@v1 + - name: Set up Rust nightly + run: | + cargo install cargo-binutils rustfilt + - name: Set up Ruby + run: | + gem install bundler + bundle config set without 'uart' + bundle install --retry 3 + - name: Run + run: | + bundle exec ruby utils/devtool.rb test_integration diff --git a/.github/workflows/test_unit.yml b/.github/workflows/test_unit.yml index 7518b08c..9ac56432 100644 --- a/.github/workflows/test_unit.yml +++ b/.github/workflows/test_unit.yml @@ -1,41 +1,41 @@ name: Boot-and-Unit-Tests on: - push: - branches: - - master - paths-ignore: - - "utils/**" - - "doc/**" - - "docker/**" - pull_request: - branches: - - master - paths-ignore: - - "utils/**" - - "doc/**" - - "docker/**" - schedule: - - cron: "0 5 * * *" + push: + branches: + - master + paths-ignore: + - "utils/**" + - "doc/**" + - "docker/**" + pull_request: + branches: + - master + paths-ignore: + - "utils/**" + - "doc/**" + - "docker/**" + schedule: + - cron: "0 5 * * *" jobs: - build: - name: Run boot and unit tests - runs-on: ubuntu-22.04 + build: + name: Run boot and unit tests + runs-on: ubuntu-22.04 - steps: - - uses: actions/checkout@v3 - - name: Set up Ruby - uses: ruby/setup-ruby@v1 - - name: Set up Rust nightly - run: | - cargo install cargo-binutils rustfilt - - name: Set up Ruby - run: | - gem install bundler - bundle config set without 'uart' - bundle install --retry 3 - - name: Run - run: | - bundle exec ruby utils/devtool.rb test_boot - bundle exec ruby utils/devtool.rb test_unit + steps: + - uses: actions/checkout@v3 + - name: Set up Ruby + uses: ruby/setup-ruby@v1 + - name: Set up Rust nightly + run: | + cargo install cargo-binutils rustfilt + - name: Set up Ruby + run: | + gem install bundler + bundle config set without 'uart' + bundle install --retry 3 + - name: Run + run: | + bundle exec ruby utils/devtool.rb test_boot + bundle exec ruby utils/devtool.rb test_unit diff --git a/.github/workflows/test_xtra.yml b/.github/workflows/test_xtra.yml index a2a6c1e0..cdc705f9 100644 --- a/.github/workflows/test_xtra.yml +++ b/.github/workflows/test_xtra.yml @@ -1,40 +1,40 @@ name: Xtra-Tests on: - push: - branches: - - master - paths-ignore: - - "utils/**" - - "doc/**" - - "docker/**" - pull_request: - branches: - - master - paths-ignore: - - "utils/**" - - "doc/**" - - "docker/**" - schedule: - - cron: "0 5 * * *" + push: + branches: + - master + paths-ignore: + - "utils/**" + - "doc/**" + - "docker/**" + pull_request: + branches: + - master + paths-ignore: + - "utils/**" + - "doc/**" + - "docker/**" + schedule: + - cron: "0 5 * * *" jobs: - build: - name: Run xtra tests - runs-on: ubuntu-22.04 + build: + name: Run xtra tests + runs-on: ubuntu-22.04 - steps: - - uses: actions/checkout@v3 - - name: Set up Ruby - uses: ruby/setup-ruby@v1 - - name: Set up Rust nightly - run: | - cargo install cargo-binutils - - name: Set up Ruby - run: | - gem install bundler - bundle config set without 'uart' - bundle install --retry 3 - - name: Run - run: | - bundle exec ruby utils/devtool.rb make_xtra + steps: + - uses: actions/checkout@v3 + - name: Set up Ruby + uses: ruby/setup-ruby@v1 + - name: Set up Rust nightly + run: | + cargo install cargo-binutils + - name: Set up Ruby + run: | + gem install bundler + bundle config set without 'uart' + bundle install --retry 3 + - name: Run + run: | + bundle exec ruby utils/devtool.rb make_xtra diff --git a/.prettierrc.json b/.prettierrc.json index 0967ef42..864ccc36 100644 --- a/.prettierrc.json +++ b/.prettierrc.json @@ -1 +1,35 @@ -{} +{ + "printWidth": 100, + "tabWidth": 4, + "useTabs": false, + "semi": true, + "singleQuote": false, + "trailingComma": "es5", + "bracketSpacing": true, + "jsxBracketSameLine": false, + "arrowParens": "always", + "requirePragma": false, + "insertPragma": false, + "proseWrap": "preserve", + "endOfLine": "auto", + "overrides": [ + { + "files": "*.rs", + "options": { + "printWidth": 100, + "tabWidth": 4, + "useTabs": false, + "semi": true, + "singleQuote": false, + "trailingComma": "es5", + "bracketSpacing": true, + "jsxBracketSameLine": false, + "arrowParens": "always", + "requirePragma": false, + "insertPragma": false, + "proseWrap": "preserve", + "endOfLine": "auto" + } + } + ] +} diff --git a/.rubocop.yml b/.rubocop.yml index 1de61528..059ba16e 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -10,23 +10,23 @@ # See https://github.com/rubocop-hq/rubocop/blob/master/manual/configuration.md Layout/IndentationWidth: - Width: 4 - AllowedPatterns: ['^\s*module'] + Width: 4 + AllowedPatterns: ['^\s*module'] Layout/LineLength: - Max: 100 + Max: 100 Lint/UnusedMethodArgument: - AutoCorrect: False + AutoCorrect: False Metrics/AbcSize: - Max: 25 + Max: 25 Metrics/ClassLength: - Enabled: false + Enabled: false Metrics/MethodLength: - Max: 20 + Max: 20 AllCops: - NewCops: enable + NewCops: enable diff --git a/.vscode/settings.json b/.vscode/settings.json index 292bf2a9..9ef30cd0 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,10 +1,10 @@ { - "editor.formatOnSave": true, - "editor.rulers": [100], - "rust-analyzer.cargo.target": "aarch64-unknown-none-softfloat", - "rust-analyzer.cargo.features": ["bsp_rpi3"], - "rust-analyzer.checkOnSave.allTargets": false, - "rust-analyzer.checkOnSave.extraArgs": ["--lib", "--bins"], - "rust-analyzer.lens.debug": false, - "rust-analyzer.lens.run": false + "editor.formatOnSave": true, + "editor.rulers": [100], + "rust-analyzer.cargo.target": "aarch64-unknown-none-softfloat", + "rust-analyzer.cargo.features": ["bsp_rpi3"], + "rust-analyzer.checkOnSave.allTargets": false, + "rust-analyzer.checkOnSave.extraArgs": ["--lib", "--bins"], + "rust-analyzer.lens.debug": false, + "rust-analyzer.lens.run": false } diff --git a/01_wait_forever/.vscode/settings.json b/01_wait_forever/.vscode/settings.json index d1916456..bfa278e9 100644 --- a/01_wait_forever/.vscode/settings.json +++ b/01_wait_forever/.vscode/settings.json @@ -1,10 +1,10 @@ { - "editor.formatOnSave": true, - "editor.rulers": [100], - "rust-analyzer.cargo.target": "aarch64-unknown-none-softfloat", - "rust-analyzer.cargo.features": ["bsp_rpi3"], - "rust-analyzer.checkOnSave.allTargets": false, - "rust-analyzer.checkOnSave.extraArgs": ["--bins"], - "rust-analyzer.lens.debug": false, - "rust-analyzer.lens.run": false + "editor.formatOnSave": true, + "editor.rulers": [100], + "rust-analyzer.cargo.target": "aarch64-unknown-none-softfloat", + "rust-analyzer.cargo.features": ["bsp_rpi3"], + "rust-analyzer.checkOnSave.allTargets": false, + "rust-analyzer.checkOnSave.extraArgs": ["--bins"], + "rust-analyzer.lens.debug": false, + "rust-analyzer.lens.run": false } diff --git a/01_wait_forever/Cargo.toml b/01_wait_forever/Cargo.toml index 459866f8..c2815c32 100644 --- a/01_wait_forever/Cargo.toml +++ b/01_wait_forever/Cargo.toml @@ -20,4 +20,4 @@ path = "src/main.rs" ## Dependencies ##-------------------------------------------------------------------------------------------------- -[dependencies] +[dependencies] \ No newline at end of file diff --git a/01_wait_forever/Makefile b/01_wait_forever/Makefile index c87546fd..51c128f7 100644 --- a/01_wait_forever/Makefile +++ b/01_wait_forever/Makefile @@ -1,6 +1,6 @@ ## SPDX-License-Identifier: MIT OR Apache-2.0 ## -## Copyright (c) 2018-2022 Andre Richter +## Copyright (c) 2018-2023 Andre Richter include ../common/docker.mk include ../common/format.mk diff --git a/01_wait_forever/src/_arch/aarch64/cpu/boot.rs b/01_wait_forever/src/_arch/aarch64/cpu/boot.rs index 77d3d99f..3cf9b08f 100644 --- a/01_wait_forever/src/_arch/aarch64/cpu/boot.rs +++ b/01_wait_forever/src/_arch/aarch64/cpu/boot.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2021-2022 Andre Richter +// Copyright (c) 2021-2023 Andre Richter //! Architectural boot code. //! diff --git a/01_wait_forever/src/_arch/aarch64/cpu/boot.s b/01_wait_forever/src/_arch/aarch64/cpu/boot.s index d5b5bc9c..8f33b483 100644 --- a/01_wait_forever/src/_arch/aarch64/cpu/boot.s +++ b/01_wait_forever/src/_arch/aarch64/cpu/boot.s @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2021-2022 Andre Richter +// Copyright (c) 2021-2023 Andre Richter //-------------------------------------------------------------------------------------------------- // Public Code diff --git a/01_wait_forever/src/bsp.rs b/01_wait_forever/src/bsp.rs index a09ba8a4..b128add9 100644 --- a/01_wait_forever/src/bsp.rs +++ b/01_wait_forever/src/bsp.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Conditional reexporting of Board Support Packages. diff --git a/01_wait_forever/src/bsp/raspberrypi.rs b/01_wait_forever/src/bsp/raspberrypi.rs index 26b678a0..3253ee5e 100644 --- a/01_wait_forever/src/bsp/raspberrypi.rs +++ b/01_wait_forever/src/bsp/raspberrypi.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Top-level BSP file for the Raspberry Pi 3 and 4. diff --git a/01_wait_forever/src/cpu.rs b/01_wait_forever/src/cpu.rs index 8f50133f..9f399de2 100644 --- a/01_wait_forever/src/cpu.rs +++ b/01_wait_forever/src/cpu.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Processor code. diff --git a/01_wait_forever/src/cpu/boot.rs b/01_wait_forever/src/cpu/boot.rs index 8091dac3..b1e98328 100644 --- a/01_wait_forever/src/cpu/boot.rs +++ b/01_wait_forever/src/cpu/boot.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2021-2022 Andre Richter +// Copyright (c) 2021-2023 Andre Richter //! Boot code. diff --git a/01_wait_forever/src/main.rs b/01_wait_forever/src/main.rs index f7e08a59..10fdb3f4 100644 --- a/01_wait_forever/src/main.rs +++ b/01_wait_forever/src/main.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter // Rust embedded logo for `make doc`. #![doc( diff --git a/01_wait_forever/src/panic_wait.rs b/01_wait_forever/src/panic_wait.rs index c9a8f5e4..714bf296 100644 --- a/01_wait_forever/src/panic_wait.rs +++ b/01_wait_forever/src/panic_wait.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! A panic handler that infinitely waits. diff --git a/02_runtime_init/.vscode/settings.json b/02_runtime_init/.vscode/settings.json index d1916456..bfa278e9 100644 --- a/02_runtime_init/.vscode/settings.json +++ b/02_runtime_init/.vscode/settings.json @@ -1,10 +1,10 @@ { - "editor.formatOnSave": true, - "editor.rulers": [100], - "rust-analyzer.cargo.target": "aarch64-unknown-none-softfloat", - "rust-analyzer.cargo.features": ["bsp_rpi3"], - "rust-analyzer.checkOnSave.allTargets": false, - "rust-analyzer.checkOnSave.extraArgs": ["--bins"], - "rust-analyzer.lens.debug": false, - "rust-analyzer.lens.run": false + "editor.formatOnSave": true, + "editor.rulers": [100], + "rust-analyzer.cargo.target": "aarch64-unknown-none-softfloat", + "rust-analyzer.cargo.features": ["bsp_rpi3"], + "rust-analyzer.checkOnSave.allTargets": false, + "rust-analyzer.checkOnSave.extraArgs": ["--bins"], + "rust-analyzer.lens.debug": false, + "rust-analyzer.lens.run": false } diff --git a/02_runtime_init/Makefile b/02_runtime_init/Makefile index 807a935e..893564e2 100644 --- a/02_runtime_init/Makefile +++ b/02_runtime_init/Makefile @@ -1,6 +1,6 @@ ## SPDX-License-Identifier: MIT OR Apache-2.0 ## -## Copyright (c) 2018-2022 Andre Richter +## Copyright (c) 2018-2023 Andre Richter include ../common/docker.mk include ../common/format.mk diff --git a/02_runtime_init/README.md b/02_runtime_init/README.md index 76fc07dd..1082f18c 100644 --- a/02_runtime_init/README.md +++ b/02_runtime_init/README.md @@ -58,7 +58,6 @@ diff -uNr 01_wait_forever/Makefile 02_runtime_init/Makefile --section .text \ + --section .rodata \ $(KERNEL_ELF) | rustfilt - ##------------------------------------------------------------------------------ diff -uNr 01_wait_forever/src/_arch/aarch64/cpu/boot.rs 02_runtime_init/src/_arch/aarch64/cpu/boot.rs @@ -90,7 +89,7 @@ diff -uNr 01_wait_forever/src/_arch/aarch64/cpu/boot.s 02_runtime_init/src/_arch --- 01_wait_forever/src/_arch/aarch64/cpu/boot.s +++ 02_runtime_init/src/_arch/aarch64/cpu/boot.s @@ -3,6 +3,22 @@ - // Copyright (c) 2021-2022 Andre Richter + // Copyright (c) 2021-2023 Andre Richter //-------------------------------------------------------------------------------------------------- +// Definitions @@ -154,7 +153,7 @@ diff -uNr 01_wait_forever/src/_arch/aarch64/cpu.rs 02_runtime_init/src/_arch/aar @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// -+// Copyright (c) 2018-2022 Andre Richter ++// Copyright (c) 2018-2023 Andre Richter + +//! Architectural processor code. +//! @@ -185,7 +184,7 @@ diff -uNr 01_wait_forever/src/bsp/raspberrypi/cpu.rs 02_runtime_init/src/bsp/ras @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// -+// Copyright (c) 2018-2022 Andre Richter ++// Copyright (c) 2018-2023 Andre Richter + +//! BSP Processor code. + @@ -202,7 +201,7 @@ diff -uNr 01_wait_forever/src/bsp/raspberrypi/kernel.ld 02_runtime_init/src/bsp/ --- 01_wait_forever/src/bsp/raspberrypi/kernel.ld +++ 02_runtime_init/src/bsp/raspberrypi/kernel.ld @@ -3,6 +3,8 @@ - * Copyright (c) 2018-2022 Andre Richter + * Copyright (c) 2018-2023 Andre Richter */ +__rpi_phys_dram_start_addr = 0; diff --git a/02_runtime_init/src/_arch/aarch64/cpu.rs b/02_runtime_init/src/_arch/aarch64/cpu.rs index 7872f85f..11d5024e 100644 --- a/02_runtime_init/src/_arch/aarch64/cpu.rs +++ b/02_runtime_init/src/_arch/aarch64/cpu.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Architectural processor code. //! diff --git a/02_runtime_init/src/_arch/aarch64/cpu/boot.rs b/02_runtime_init/src/_arch/aarch64/cpu/boot.rs index 8390c013..2a6c4649 100644 --- a/02_runtime_init/src/_arch/aarch64/cpu/boot.rs +++ b/02_runtime_init/src/_arch/aarch64/cpu/boot.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2021-2022 Andre Richter +// Copyright (c) 2021-2023 Andre Richter //! Architectural boot code. //! diff --git a/02_runtime_init/src/bsp.rs b/02_runtime_init/src/bsp.rs index a09ba8a4..b128add9 100644 --- a/02_runtime_init/src/bsp.rs +++ b/02_runtime_init/src/bsp.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Conditional reexporting of Board Support Packages. diff --git a/02_runtime_init/src/bsp/raspberrypi.rs b/02_runtime_init/src/bsp/raspberrypi.rs index 5ab6cb34..c3abe0a6 100644 --- a/02_runtime_init/src/bsp/raspberrypi.rs +++ b/02_runtime_init/src/bsp/raspberrypi.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Top-level BSP file for the Raspberry Pi 3 and 4. diff --git a/02_runtime_init/src/bsp/raspberrypi/cpu.rs b/02_runtime_init/src/bsp/raspberrypi/cpu.rs index 85fb89e4..65cf5abb 100644 --- a/02_runtime_init/src/bsp/raspberrypi/cpu.rs +++ b/02_runtime_init/src/bsp/raspberrypi/cpu.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! BSP Processor code. diff --git a/02_runtime_init/src/cpu.rs b/02_runtime_init/src/cpu.rs index b2a96010..13b89581 100644 --- a/02_runtime_init/src/cpu.rs +++ b/02_runtime_init/src/cpu.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Processor code. diff --git a/02_runtime_init/src/cpu/boot.rs b/02_runtime_init/src/cpu/boot.rs index 8091dac3..b1e98328 100644 --- a/02_runtime_init/src/cpu/boot.rs +++ b/02_runtime_init/src/cpu/boot.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2021-2022 Andre Richter +// Copyright (c) 2021-2023 Andre Richter //! Boot code. diff --git a/02_runtime_init/src/main.rs b/02_runtime_init/src/main.rs index e16354ed..152d7544 100644 --- a/02_runtime_init/src/main.rs +++ b/02_runtime_init/src/main.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter // Rust embedded logo for `make doc`. #![doc( diff --git a/02_runtime_init/src/panic_wait.rs b/02_runtime_init/src/panic_wait.rs index 7e9adfce..34a98173 100644 --- a/02_runtime_init/src/panic_wait.rs +++ b/02_runtime_init/src/panic_wait.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! A panic handler that infinitely waits. diff --git a/03_hacky_hello_world/.vscode/settings.json b/03_hacky_hello_world/.vscode/settings.json index d1916456..bfa278e9 100644 --- a/03_hacky_hello_world/.vscode/settings.json +++ b/03_hacky_hello_world/.vscode/settings.json @@ -1,10 +1,10 @@ { - "editor.formatOnSave": true, - "editor.rulers": [100], - "rust-analyzer.cargo.target": "aarch64-unknown-none-softfloat", - "rust-analyzer.cargo.features": ["bsp_rpi3"], - "rust-analyzer.checkOnSave.allTargets": false, - "rust-analyzer.checkOnSave.extraArgs": ["--bins"], - "rust-analyzer.lens.debug": false, - "rust-analyzer.lens.run": false + "editor.formatOnSave": true, + "editor.rulers": [100], + "rust-analyzer.cargo.target": "aarch64-unknown-none-softfloat", + "rust-analyzer.cargo.features": ["bsp_rpi3"], + "rust-analyzer.checkOnSave.allTargets": false, + "rust-analyzer.checkOnSave.extraArgs": ["--bins"], + "rust-analyzer.lens.debug": false, + "rust-analyzer.lens.run": false } diff --git a/03_hacky_hello_world/Makefile b/03_hacky_hello_world/Makefile index 13dba46c..ce5aff09 100644 --- a/03_hacky_hello_world/Makefile +++ b/03_hacky_hello_world/Makefile @@ -1,6 +1,6 @@ ## SPDX-License-Identifier: MIT OR Apache-2.0 ## -## Copyright (c) 2018-2022 Andre Richter +## Copyright (c) 2018-2023 Andre Richter include ../common/docker.mk include ../common/format.mk diff --git a/03_hacky_hello_world/README.md b/03_hacky_hello_world/README.md index b0ad3ff2..07bf4503 100644 --- a/03_hacky_hello_world/README.md +++ b/03_hacky_hello_world/README.md @@ -130,7 +130,7 @@ diff -uNr 02_runtime_init/src/bsp/raspberrypi/console.rs 03_hacky_hello_world/sr @@ -0,0 +1,47 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// -+// Copyright (c) 2018-2022 Andre Richter ++// Copyright (c) 2018-2023 Andre Richter + +//! BSP console facilities. + @@ -192,7 +192,7 @@ diff -uNr 02_runtime_init/src/console.rs 03_hacky_hello_world/src/console.rs @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// -+// Copyright (c) 2018-2022 Andre Richter ++// Copyright (c) 2018-2023 Andre Richter + +//! System console. + @@ -327,7 +327,7 @@ diff -uNr 02_runtime_init/src/print.rs 03_hacky_hello_world/src/print.rs @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// -+// Copyright (c) 2018-2022 Andre Richter ++// Copyright (c) 2018-2023 Andre Richter + +//! Printing. + diff --git a/03_hacky_hello_world/src/_arch/aarch64/cpu.rs b/03_hacky_hello_world/src/_arch/aarch64/cpu.rs index 7872f85f..11d5024e 100644 --- a/03_hacky_hello_world/src/_arch/aarch64/cpu.rs +++ b/03_hacky_hello_world/src/_arch/aarch64/cpu.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Architectural processor code. //! diff --git a/03_hacky_hello_world/src/_arch/aarch64/cpu/boot.rs b/03_hacky_hello_world/src/_arch/aarch64/cpu/boot.rs index 8390c013..2a6c4649 100644 --- a/03_hacky_hello_world/src/_arch/aarch64/cpu/boot.rs +++ b/03_hacky_hello_world/src/_arch/aarch64/cpu/boot.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2021-2022 Andre Richter +// Copyright (c) 2021-2023 Andre Richter //! Architectural boot code. //! diff --git a/03_hacky_hello_world/src/bsp.rs b/03_hacky_hello_world/src/bsp.rs index a09ba8a4..b128add9 100644 --- a/03_hacky_hello_world/src/bsp.rs +++ b/03_hacky_hello_world/src/bsp.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Conditional reexporting of Board Support Packages. diff --git a/03_hacky_hello_world/src/bsp/raspberrypi.rs b/03_hacky_hello_world/src/bsp/raspberrypi.rs index 6688a514..919d7e79 100644 --- a/03_hacky_hello_world/src/bsp/raspberrypi.rs +++ b/03_hacky_hello_world/src/bsp/raspberrypi.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Top-level BSP file for the Raspberry Pi 3 and 4. diff --git a/03_hacky_hello_world/src/bsp/raspberrypi/console.rs b/03_hacky_hello_world/src/bsp/raspberrypi/console.rs index 4cdf53ee..49d29370 100644 --- a/03_hacky_hello_world/src/bsp/raspberrypi/console.rs +++ b/03_hacky_hello_world/src/bsp/raspberrypi/console.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! BSP console facilities. diff --git a/03_hacky_hello_world/src/bsp/raspberrypi/cpu.rs b/03_hacky_hello_world/src/bsp/raspberrypi/cpu.rs index 85fb89e4..65cf5abb 100644 --- a/03_hacky_hello_world/src/bsp/raspberrypi/cpu.rs +++ b/03_hacky_hello_world/src/bsp/raspberrypi/cpu.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! BSP Processor code. diff --git a/03_hacky_hello_world/src/console.rs b/03_hacky_hello_world/src/console.rs index 7d940f29..8b094dda 100644 --- a/03_hacky_hello_world/src/console.rs +++ b/03_hacky_hello_world/src/console.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! System console. diff --git a/03_hacky_hello_world/src/cpu.rs b/03_hacky_hello_world/src/cpu.rs index b2a96010..13b89581 100644 --- a/03_hacky_hello_world/src/cpu.rs +++ b/03_hacky_hello_world/src/cpu.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Processor code. diff --git a/03_hacky_hello_world/src/cpu/boot.rs b/03_hacky_hello_world/src/cpu/boot.rs index 8091dac3..b1e98328 100644 --- a/03_hacky_hello_world/src/cpu/boot.rs +++ b/03_hacky_hello_world/src/cpu/boot.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2021-2022 Andre Richter +// Copyright (c) 2021-2023 Andre Richter //! Boot code. diff --git a/03_hacky_hello_world/src/main.rs b/03_hacky_hello_world/src/main.rs index 74b621de..a38495a2 100644 --- a/03_hacky_hello_world/src/main.rs +++ b/03_hacky_hello_world/src/main.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter // Rust embedded logo for `make doc`. #![doc( diff --git a/03_hacky_hello_world/src/panic_wait.rs b/03_hacky_hello_world/src/panic_wait.rs index fb30e8d4..5bb0896e 100644 --- a/03_hacky_hello_world/src/panic_wait.rs +++ b/03_hacky_hello_world/src/panic_wait.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! A panic handler that infinitely waits. diff --git a/03_hacky_hello_world/src/print.rs b/03_hacky_hello_world/src/print.rs index 05ef2aea..4e8c9b37 100644 --- a/03_hacky_hello_world/src/print.rs +++ b/03_hacky_hello_world/src/print.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Printing. diff --git a/04_safe_globals/.vscode/settings.json b/04_safe_globals/.vscode/settings.json index d1916456..bfa278e9 100644 --- a/04_safe_globals/.vscode/settings.json +++ b/04_safe_globals/.vscode/settings.json @@ -1,10 +1,10 @@ { - "editor.formatOnSave": true, - "editor.rulers": [100], - "rust-analyzer.cargo.target": "aarch64-unknown-none-softfloat", - "rust-analyzer.cargo.features": ["bsp_rpi3"], - "rust-analyzer.checkOnSave.allTargets": false, - "rust-analyzer.checkOnSave.extraArgs": ["--bins"], - "rust-analyzer.lens.debug": false, - "rust-analyzer.lens.run": false + "editor.formatOnSave": true, + "editor.rulers": [100], + "rust-analyzer.cargo.target": "aarch64-unknown-none-softfloat", + "rust-analyzer.cargo.features": ["bsp_rpi3"], + "rust-analyzer.checkOnSave.allTargets": false, + "rust-analyzer.checkOnSave.extraArgs": ["--bins"], + "rust-analyzer.lens.debug": false, + "rust-analyzer.lens.run": false } diff --git a/04_safe_globals/Makefile b/04_safe_globals/Makefile index 13dba46c..ce5aff09 100644 --- a/04_safe_globals/Makefile +++ b/04_safe_globals/Makefile @@ -1,6 +1,6 @@ ## SPDX-License-Identifier: MIT OR Apache-2.0 ## -## Copyright (c) 2018-2022 Andre Richter +## Copyright (c) 2018-2023 Andre Richter include ../common/docker.mk include ../common/format.mk diff --git a/04_safe_globals/README.md b/04_safe_globals/README.md index b34c04f9..6418ef5b 100644 --- a/04_safe_globals/README.md +++ b/04_safe_globals/README.md @@ -287,7 +287,7 @@ diff -uNr 03_hacky_hello_world/src/synchronization.rs 04_safe_globals/src/synchr @@ -0,0 +1,77 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// -+// Copyright (c) 2020-2022 Andre Richter ++// Copyright (c) 2020-2023 Andre Richter + +//! Synchronization primitives. +//! diff --git a/04_safe_globals/src/_arch/aarch64/cpu.rs b/04_safe_globals/src/_arch/aarch64/cpu.rs index 7872f85f..11d5024e 100644 --- a/04_safe_globals/src/_arch/aarch64/cpu.rs +++ b/04_safe_globals/src/_arch/aarch64/cpu.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Architectural processor code. //! diff --git a/04_safe_globals/src/_arch/aarch64/cpu/boot.rs b/04_safe_globals/src/_arch/aarch64/cpu/boot.rs index 8390c013..2a6c4649 100644 --- a/04_safe_globals/src/_arch/aarch64/cpu/boot.rs +++ b/04_safe_globals/src/_arch/aarch64/cpu/boot.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2021-2022 Andre Richter +// Copyright (c) 2021-2023 Andre Richter //! Architectural boot code. //! diff --git a/04_safe_globals/src/bsp.rs b/04_safe_globals/src/bsp.rs index a09ba8a4..b128add9 100644 --- a/04_safe_globals/src/bsp.rs +++ b/04_safe_globals/src/bsp.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Conditional reexporting of Board Support Packages. diff --git a/04_safe_globals/src/bsp/raspberrypi.rs b/04_safe_globals/src/bsp/raspberrypi.rs index 6688a514..919d7e79 100644 --- a/04_safe_globals/src/bsp/raspberrypi.rs +++ b/04_safe_globals/src/bsp/raspberrypi.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Top-level BSP file for the Raspberry Pi 3 and 4. diff --git a/04_safe_globals/src/bsp/raspberrypi/console.rs b/04_safe_globals/src/bsp/raspberrypi/console.rs index 6427e099..753cbcb6 100644 --- a/04_safe_globals/src/bsp/raspberrypi/console.rs +++ b/04_safe_globals/src/bsp/raspberrypi/console.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! BSP console facilities. diff --git a/04_safe_globals/src/bsp/raspberrypi/cpu.rs b/04_safe_globals/src/bsp/raspberrypi/cpu.rs index 85fb89e4..65cf5abb 100644 --- a/04_safe_globals/src/bsp/raspberrypi/cpu.rs +++ b/04_safe_globals/src/bsp/raspberrypi/cpu.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! BSP Processor code. diff --git a/04_safe_globals/src/console.rs b/04_safe_globals/src/console.rs index 94e00f84..d41c95a1 100644 --- a/04_safe_globals/src/console.rs +++ b/04_safe_globals/src/console.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! System console. diff --git a/04_safe_globals/src/cpu.rs b/04_safe_globals/src/cpu.rs index b2a96010..13b89581 100644 --- a/04_safe_globals/src/cpu.rs +++ b/04_safe_globals/src/cpu.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Processor code. diff --git a/04_safe_globals/src/cpu/boot.rs b/04_safe_globals/src/cpu/boot.rs index 8091dac3..b1e98328 100644 --- a/04_safe_globals/src/cpu/boot.rs +++ b/04_safe_globals/src/cpu/boot.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2021-2022 Andre Richter +// Copyright (c) 2021-2023 Andre Richter //! Boot code. diff --git a/04_safe_globals/src/main.rs b/04_safe_globals/src/main.rs index 4726477d..4c5a7e0d 100644 --- a/04_safe_globals/src/main.rs +++ b/04_safe_globals/src/main.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter // Rust embedded logo for `make doc`. #![doc( diff --git a/04_safe_globals/src/panic_wait.rs b/04_safe_globals/src/panic_wait.rs index fb30e8d4..5bb0896e 100644 --- a/04_safe_globals/src/panic_wait.rs +++ b/04_safe_globals/src/panic_wait.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! A panic handler that infinitely waits. diff --git a/04_safe_globals/src/print.rs b/04_safe_globals/src/print.rs index f69bad44..6de99572 100644 --- a/04_safe_globals/src/print.rs +++ b/04_safe_globals/src/print.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Printing. diff --git a/04_safe_globals/src/synchronization.rs b/04_safe_globals/src/synchronization.rs index d3937b0d..94c83de1 100644 --- a/04_safe_globals/src/synchronization.rs +++ b/04_safe_globals/src/synchronization.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Synchronization primitives. //! diff --git a/05_drivers_gpio_uart/.vscode/settings.json b/05_drivers_gpio_uart/.vscode/settings.json index d1916456..bfa278e9 100644 --- a/05_drivers_gpio_uart/.vscode/settings.json +++ b/05_drivers_gpio_uart/.vscode/settings.json @@ -1,10 +1,10 @@ { - "editor.formatOnSave": true, - "editor.rulers": [100], - "rust-analyzer.cargo.target": "aarch64-unknown-none-softfloat", - "rust-analyzer.cargo.features": ["bsp_rpi3"], - "rust-analyzer.checkOnSave.allTargets": false, - "rust-analyzer.checkOnSave.extraArgs": ["--bins"], - "rust-analyzer.lens.debug": false, - "rust-analyzer.lens.run": false + "editor.formatOnSave": true, + "editor.rulers": [100], + "rust-analyzer.cargo.target": "aarch64-unknown-none-softfloat", + "rust-analyzer.cargo.features": ["bsp_rpi3"], + "rust-analyzer.checkOnSave.allTargets": false, + "rust-analyzer.checkOnSave.extraArgs": ["--bins"], + "rust-analyzer.lens.debug": false, + "rust-analyzer.lens.run": false } diff --git a/05_drivers_gpio_uart/Makefile b/05_drivers_gpio_uart/Makefile index a8c4821a..f5135d1e 100644 --- a/05_drivers_gpio_uart/Makefile +++ b/05_drivers_gpio_uart/Makefile @@ -1,6 +1,6 @@ ## SPDX-License-Identifier: MIT OR Apache-2.0 ## -## Copyright (c) 2018-2022 Andre Richter +## Copyright (c) 2018-2023 Andre Richter include ../common/docker.mk include ../common/format.mk @@ -150,7 +150,7 @@ $(KERNEL_BIN): $(KERNEL_ELF) ##------------------------------------------------------------------------------ ## Generate the documentation -##------------------------------------------------------------------------------ +##----------------------------------------------------------------------------- doc: $(call color_header, "Generating docs") @$(DOC_CMD) --document-private-items --open diff --git a/05_drivers_gpio_uart/README.md b/05_drivers_gpio_uart/README.md index 563af1a7..e6e5dd64 100644 --- a/05_drivers_gpio_uart/README.md +++ b/05_drivers_gpio_uart/README.md @@ -278,7 +278,7 @@ diff -uNr 04_safe_globals/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs 05_drivers_g @@ -0,0 +1,228 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// -+// Copyright (c) 2018-2022 Andre Richter ++// Copyright (c) 2018-2023 Andre Richter + +//! GPIO Driver. + @@ -511,7 +511,7 @@ diff -uNr 04_safe_globals/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs 05_dri @@ -0,0 +1,407 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// -+// Copyright (c) 2018-2022 Andre Richter ++// Copyright (c) 2018-2023 Andre Richter + +//! PL011 UART driver. +//! @@ -923,7 +923,7 @@ diff -uNr 04_safe_globals/src/bsp/device_driver/bcm.rs 05_drivers_gpio_uart/src/ @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// -+// Copyright (c) 2018-2022 Andre Richter ++// Copyright (c) 2018-2023 Andre Richter + +//! BCM driver top level. + @@ -939,7 +939,7 @@ diff -uNr 04_safe_globals/src/bsp/device_driver/common.rs 05_drivers_gpio_uart/s @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// -+// Copyright (c) 2020-2022 Andre Richter ++// Copyright (c) 2020-2023 Andre Richter + +//! Common device driver code. + @@ -982,7 +982,7 @@ diff -uNr 04_safe_globals/src/bsp/device_driver.rs 05_drivers_gpio_uart/src/bsp/ @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// -+// Copyright (c) 2018-2022 Andre Richter ++// Copyright (c) 2018-2023 Andre Richter + +//! Device driver. + @@ -1121,7 +1121,7 @@ diff -uNr 04_safe_globals/src/bsp/raspberrypi/driver.rs 05_drivers_gpio_uart/src @@ -0,0 +1,71 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// -+// Copyright (c) 2018-2022 Andre Richter ++// Copyright (c) 2018-2023 Andre Richter + +//! BSP driver support. + @@ -1197,7 +1197,7 @@ diff -uNr 04_safe_globals/src/bsp/raspberrypi/memory.rs 05_drivers_gpio_uart/src @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// -+// Copyright (c) 2018-2022 Andre Richter ++// Copyright (c) 2018-2023 Andre Richter + +//! BSP Memory Management. + @@ -1281,7 +1281,7 @@ diff -uNr 04_safe_globals/src/console/null_console.rs 05_drivers_gpio_uart/src/c @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// -+// Copyright (c) 2022 Andre Richter ++// Copyright (c) 2022-2023 Andre Richter + +//! Null console. + @@ -1422,7 +1422,7 @@ diff -uNr 04_safe_globals/src/driver.rs 05_drivers_gpio_uart/src/driver.rs @@ -0,0 +1,167 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// -+// Copyright (c) 2018-2022 Andre Richter ++// Copyright (c) 2018-2023 Andre Richter + +//! Driver support. + diff --git a/05_drivers_gpio_uart/src/_arch/aarch64/cpu.rs b/05_drivers_gpio_uart/src/_arch/aarch64/cpu.rs index 2431d2d2..f1f1e9af 100644 --- a/05_drivers_gpio_uart/src/_arch/aarch64/cpu.rs +++ b/05_drivers_gpio_uart/src/_arch/aarch64/cpu.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Architectural processor code. //! diff --git a/05_drivers_gpio_uart/src/_arch/aarch64/cpu/boot.rs b/05_drivers_gpio_uart/src/_arch/aarch64/cpu/boot.rs index 8390c013..2a6c4649 100644 --- a/05_drivers_gpio_uart/src/_arch/aarch64/cpu/boot.rs +++ b/05_drivers_gpio_uart/src/_arch/aarch64/cpu/boot.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2021-2022 Andre Richter +// Copyright (c) 2021-2023 Andre Richter //! Architectural boot code. //! diff --git a/05_drivers_gpio_uart/src/bsp.rs b/05_drivers_gpio_uart/src/bsp.rs index 824787f6..246973bc 100644 --- a/05_drivers_gpio_uart/src/bsp.rs +++ b/05_drivers_gpio_uart/src/bsp.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Conditional reexporting of Board Support Packages. diff --git a/05_drivers_gpio_uart/src/bsp/device_driver.rs b/05_drivers_gpio_uart/src/bsp/device_driver.rs index 6e9bf8f3..64049a4c 100644 --- a/05_drivers_gpio_uart/src/bsp/device_driver.rs +++ b/05_drivers_gpio_uart/src/bsp/device_driver.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Device driver. diff --git a/05_drivers_gpio_uart/src/bsp/device_driver/bcm.rs b/05_drivers_gpio_uart/src/bsp/device_driver/bcm.rs index b4b7906e..1c343d1d 100644 --- a/05_drivers_gpio_uart/src/bsp/device_driver/bcm.rs +++ b/05_drivers_gpio_uart/src/bsp/device_driver/bcm.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! BCM driver top level. diff --git a/05_drivers_gpio_uart/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs b/05_drivers_gpio_uart/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs index 0601d58e..920b4c00 100644 --- a/05_drivers_gpio_uart/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs +++ b/05_drivers_gpio_uart/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! GPIO Driver. diff --git a/05_drivers_gpio_uart/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs b/05_drivers_gpio_uart/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs index b034e92e..d92612ea 100644 --- a/05_drivers_gpio_uart/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs +++ b/05_drivers_gpio_uart/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! PL011 UART driver. //! diff --git a/05_drivers_gpio_uart/src/bsp/device_driver/common.rs b/05_drivers_gpio_uart/src/bsp/device_driver/common.rs index fd9e988e..dfe7d8ef 100644 --- a/05_drivers_gpio_uart/src/bsp/device_driver/common.rs +++ b/05_drivers_gpio_uart/src/bsp/device_driver/common.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Common device driver code. diff --git a/05_drivers_gpio_uart/src/bsp/raspberrypi.rs b/05_drivers_gpio_uart/src/bsp/raspberrypi.rs index fe940677..3ea864dc 100644 --- a/05_drivers_gpio_uart/src/bsp/raspberrypi.rs +++ b/05_drivers_gpio_uart/src/bsp/raspberrypi.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Top-level BSP file for the Raspberry Pi 3 and 4. diff --git a/05_drivers_gpio_uart/src/bsp/raspberrypi/console.rs b/05_drivers_gpio_uart/src/bsp/raspberrypi/console.rs index 0a630eef..0d585229 100644 --- a/05_drivers_gpio_uart/src/bsp/raspberrypi/console.rs +++ b/05_drivers_gpio_uart/src/bsp/raspberrypi/console.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! BSP console facilities. diff --git a/05_drivers_gpio_uart/src/bsp/raspberrypi/cpu.rs b/05_drivers_gpio_uart/src/bsp/raspberrypi/cpu.rs index 85fb89e4..65cf5abb 100644 --- a/05_drivers_gpio_uart/src/bsp/raspberrypi/cpu.rs +++ b/05_drivers_gpio_uart/src/bsp/raspberrypi/cpu.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! BSP Processor code. diff --git a/05_drivers_gpio_uart/src/bsp/raspberrypi/driver.rs b/05_drivers_gpio_uart/src/bsp/raspberrypi/driver.rs index ea843066..2a80ee2c 100644 --- a/05_drivers_gpio_uart/src/bsp/raspberrypi/driver.rs +++ b/05_drivers_gpio_uart/src/bsp/raspberrypi/driver.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! BSP driver support. diff --git a/05_drivers_gpio_uart/src/bsp/raspberrypi/memory.rs b/05_drivers_gpio_uart/src/bsp/raspberrypi/memory.rs index 27be8590..cdca14b8 100644 --- a/05_drivers_gpio_uart/src/bsp/raspberrypi/memory.rs +++ b/05_drivers_gpio_uart/src/bsp/raspberrypi/memory.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! BSP Memory Management. diff --git a/05_drivers_gpio_uart/src/console.rs b/05_drivers_gpio_uart/src/console.rs index 02b43df9..a83f86fe 100644 --- a/05_drivers_gpio_uart/src/console.rs +++ b/05_drivers_gpio_uart/src/console.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! System console. diff --git a/05_drivers_gpio_uart/src/console/null_console.rs b/05_drivers_gpio_uart/src/console/null_console.rs index 2c64d499..e92a022b 100644 --- a/05_drivers_gpio_uart/src/console/null_console.rs +++ b/05_drivers_gpio_uart/src/console/null_console.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2022 Andre Richter +// Copyright (c) 2022-2023 Andre Richter //! Null console. diff --git a/05_drivers_gpio_uart/src/cpu.rs b/05_drivers_gpio_uart/src/cpu.rs index 6ccee456..eacb8924 100644 --- a/05_drivers_gpio_uart/src/cpu.rs +++ b/05_drivers_gpio_uart/src/cpu.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Processor code. diff --git a/05_drivers_gpio_uart/src/cpu/boot.rs b/05_drivers_gpio_uart/src/cpu/boot.rs index 8091dac3..b1e98328 100644 --- a/05_drivers_gpio_uart/src/cpu/boot.rs +++ b/05_drivers_gpio_uart/src/cpu/boot.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2021-2022 Andre Richter +// Copyright (c) 2021-2023 Andre Richter //! Boot code. diff --git a/05_drivers_gpio_uart/src/driver.rs b/05_drivers_gpio_uart/src/driver.rs index e324ecf8..feef34e2 100644 --- a/05_drivers_gpio_uart/src/driver.rs +++ b/05_drivers_gpio_uart/src/driver.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Driver support. diff --git a/05_drivers_gpio_uart/src/main.rs b/05_drivers_gpio_uart/src/main.rs index 9d158238..11d342ce 100644 --- a/05_drivers_gpio_uart/src/main.rs +++ b/05_drivers_gpio_uart/src/main.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter // Rust embedded logo for `make doc`. #![doc( diff --git a/05_drivers_gpio_uart/src/panic_wait.rs b/05_drivers_gpio_uart/src/panic_wait.rs index fb30e8d4..5bb0896e 100644 --- a/05_drivers_gpio_uart/src/panic_wait.rs +++ b/05_drivers_gpio_uart/src/panic_wait.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! A panic handler that infinitely waits. diff --git a/05_drivers_gpio_uart/src/print.rs b/05_drivers_gpio_uart/src/print.rs index f69bad44..6de99572 100644 --- a/05_drivers_gpio_uart/src/print.rs +++ b/05_drivers_gpio_uart/src/print.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Printing. diff --git a/05_drivers_gpio_uart/src/synchronization.rs b/05_drivers_gpio_uart/src/synchronization.rs index d3937b0d..94c83de1 100644 --- a/05_drivers_gpio_uart/src/synchronization.rs +++ b/05_drivers_gpio_uart/src/synchronization.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Synchronization primitives. //! diff --git a/06_uart_chainloader/.vscode/settings.json b/06_uart_chainloader/.vscode/settings.json index d1916456..bfa278e9 100644 --- a/06_uart_chainloader/.vscode/settings.json +++ b/06_uart_chainloader/.vscode/settings.json @@ -1,10 +1,10 @@ { - "editor.formatOnSave": true, - "editor.rulers": [100], - "rust-analyzer.cargo.target": "aarch64-unknown-none-softfloat", - "rust-analyzer.cargo.features": ["bsp_rpi3"], - "rust-analyzer.checkOnSave.allTargets": false, - "rust-analyzer.checkOnSave.extraArgs": ["--bins"], - "rust-analyzer.lens.debug": false, - "rust-analyzer.lens.run": false + "editor.formatOnSave": true, + "editor.rulers": [100], + "rust-analyzer.cargo.target": "aarch64-unknown-none-softfloat", + "rust-analyzer.cargo.features": ["bsp_rpi3"], + "rust-analyzer.checkOnSave.allTargets": false, + "rust-analyzer.checkOnSave.extraArgs": ["--bins"], + "rust-analyzer.lens.debug": false, + "rust-analyzer.lens.run": false } diff --git a/06_uart_chainloader/Makefile b/06_uart_chainloader/Makefile index b619b4ca..3366de31 100644 --- a/06_uart_chainloader/Makefile +++ b/06_uart_chainloader/Makefile @@ -1,6 +1,6 @@ ## SPDX-License-Identifier: MIT OR Apache-2.0 ## -## Copyright (c) 2018-2022 Andre Richter +## Copyright (c) 2018-2023 Andre Richter include ../common/docker.mk include ../common/format.mk diff --git a/06_uart_chainloader/README.md b/06_uart_chainloader/README.md index 95b95149..5e4efe25 100644 --- a/06_uart_chainloader/README.md +++ b/06_uart_chainloader/README.md @@ -237,7 +237,6 @@ diff -uNr 05_drivers_gpio_uart/Makefile 06_uart_chainloader/Makefile + @$(DOCKER_QEMU) $(EXEC_QEMU) $(QEMU_RELEASE_ARGS) -kernel $(KERNEL_BIN) -d in_asm + endif - ##------------------------------------------------------------------------------ -## Connect to the target's serial +## Push the kernel to the real HW target @@ -375,7 +374,7 @@ diff -uNr 05_drivers_gpio_uart/src/bsp/raspberrypi/console.rs 06_uart_chainloade @@ -1,16 +0,0 @@ -// SPDX-License-Identifier: MIT OR Apache-2.0 -// --// Copyright (c) 2018-2022 Andre Richter +-// Copyright (c) 2018-2023 Andre Richter - -//! BSP console facilities. - @@ -394,7 +393,7 @@ diff -uNr 05_drivers_gpio_uart/src/bsp/raspberrypi/kernel.ld 06_uart_chainloader --- 05_drivers_gpio_uart/src/bsp/raspberrypi/kernel.ld +++ 06_uart_chainloader/src/bsp/raspberrypi/kernel.ld @@ -3,8 +3,6 @@ - * Copyright (c) 2018-2022 Andre Richter + * Copyright (c) 2018-2023 Andre Richter */ -__rpi_phys_dram_start_addr = 0; @@ -580,7 +579,7 @@ diff -uNr 05_drivers_gpio_uart/tests/chainboot_test.rb 06_uart_chainloader/tests + +# SPDX-License-Identifier: MIT OR Apache-2.0 +# -+# Copyright (c) 2020-2022 Andre Richter ++# Copyright (c) 2020-2023 Andre Richter + +require_relative '../../common/serial/minipush' +require_relative '../../common/tests/boot_test' diff --git a/06_uart_chainloader/src/_arch/aarch64/cpu.rs b/06_uart_chainloader/src/_arch/aarch64/cpu.rs index 2431d2d2..f1f1e9af 100644 --- a/06_uart_chainloader/src/_arch/aarch64/cpu.rs +++ b/06_uart_chainloader/src/_arch/aarch64/cpu.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Architectural processor code. //! diff --git a/06_uart_chainloader/src/_arch/aarch64/cpu/boot.rs b/06_uart_chainloader/src/_arch/aarch64/cpu/boot.rs index 8390c013..2a6c4649 100644 --- a/06_uart_chainloader/src/_arch/aarch64/cpu/boot.rs +++ b/06_uart_chainloader/src/_arch/aarch64/cpu/boot.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2021-2022 Andre Richter +// Copyright (c) 2021-2023 Andre Richter //! Architectural boot code. //! diff --git a/06_uart_chainloader/src/bsp.rs b/06_uart_chainloader/src/bsp.rs index 824787f6..246973bc 100644 --- a/06_uart_chainloader/src/bsp.rs +++ b/06_uart_chainloader/src/bsp.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Conditional reexporting of Board Support Packages. diff --git a/06_uart_chainloader/src/bsp/device_driver.rs b/06_uart_chainloader/src/bsp/device_driver.rs index 6e9bf8f3..64049a4c 100644 --- a/06_uart_chainloader/src/bsp/device_driver.rs +++ b/06_uart_chainloader/src/bsp/device_driver.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Device driver. diff --git a/06_uart_chainloader/src/bsp/device_driver/bcm.rs b/06_uart_chainloader/src/bsp/device_driver/bcm.rs index b4b7906e..1c343d1d 100644 --- a/06_uart_chainloader/src/bsp/device_driver/bcm.rs +++ b/06_uart_chainloader/src/bsp/device_driver/bcm.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! BCM driver top level. diff --git a/06_uart_chainloader/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs b/06_uart_chainloader/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs index 0601d58e..920b4c00 100644 --- a/06_uart_chainloader/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs +++ b/06_uart_chainloader/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! GPIO Driver. diff --git a/06_uart_chainloader/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs b/06_uart_chainloader/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs index df56d7c4..50a069ea 100644 --- a/06_uart_chainloader/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs +++ b/06_uart_chainloader/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! PL011 UART driver. //! diff --git a/06_uart_chainloader/src/bsp/device_driver/common.rs b/06_uart_chainloader/src/bsp/device_driver/common.rs index fd9e988e..dfe7d8ef 100644 --- a/06_uart_chainloader/src/bsp/device_driver/common.rs +++ b/06_uart_chainloader/src/bsp/device_driver/common.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Common device driver code. diff --git a/06_uart_chainloader/src/bsp/raspberrypi.rs b/06_uart_chainloader/src/bsp/raspberrypi.rs index fe940677..3ea864dc 100644 --- a/06_uart_chainloader/src/bsp/raspberrypi.rs +++ b/06_uart_chainloader/src/bsp/raspberrypi.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Top-level BSP file for the Raspberry Pi 3 and 4. diff --git a/06_uart_chainloader/src/bsp/raspberrypi/cpu.rs b/06_uart_chainloader/src/bsp/raspberrypi/cpu.rs index 85fb89e4..65cf5abb 100644 --- a/06_uart_chainloader/src/bsp/raspberrypi/cpu.rs +++ b/06_uart_chainloader/src/bsp/raspberrypi/cpu.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! BSP Processor code. diff --git a/06_uart_chainloader/src/bsp/raspberrypi/driver.rs b/06_uart_chainloader/src/bsp/raspberrypi/driver.rs index ea843066..2a80ee2c 100644 --- a/06_uart_chainloader/src/bsp/raspberrypi/driver.rs +++ b/06_uart_chainloader/src/bsp/raspberrypi/driver.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! BSP driver support. diff --git a/06_uart_chainloader/src/bsp/raspberrypi/memory.rs b/06_uart_chainloader/src/bsp/raspberrypi/memory.rs index 6ef46c35..ee72b27a 100644 --- a/06_uart_chainloader/src/bsp/raspberrypi/memory.rs +++ b/06_uart_chainloader/src/bsp/raspberrypi/memory.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! BSP Memory Management. diff --git a/06_uart_chainloader/src/console.rs b/06_uart_chainloader/src/console.rs index 02b43df9..a83f86fe 100644 --- a/06_uart_chainloader/src/console.rs +++ b/06_uart_chainloader/src/console.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! System console. diff --git a/06_uart_chainloader/src/console/null_console.rs b/06_uart_chainloader/src/console/null_console.rs index 2c64d499..e92a022b 100644 --- a/06_uart_chainloader/src/console/null_console.rs +++ b/06_uart_chainloader/src/console/null_console.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2022 Andre Richter +// Copyright (c) 2022-2023 Andre Richter //! Null console. diff --git a/06_uart_chainloader/src/cpu.rs b/06_uart_chainloader/src/cpu.rs index 6ccee456..eacb8924 100644 --- a/06_uart_chainloader/src/cpu.rs +++ b/06_uart_chainloader/src/cpu.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Processor code. diff --git a/06_uart_chainloader/src/cpu/boot.rs b/06_uart_chainloader/src/cpu/boot.rs index 8091dac3..b1e98328 100644 --- a/06_uart_chainloader/src/cpu/boot.rs +++ b/06_uart_chainloader/src/cpu/boot.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2021-2022 Andre Richter +// Copyright (c) 2021-2023 Andre Richter //! Boot code. diff --git a/06_uart_chainloader/src/driver.rs b/06_uart_chainloader/src/driver.rs index fb44bbd9..53592c66 100644 --- a/06_uart_chainloader/src/driver.rs +++ b/06_uart_chainloader/src/driver.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Driver support. diff --git a/06_uart_chainloader/src/main.rs b/06_uart_chainloader/src/main.rs index bef62822..dd82ec3f 100644 --- a/06_uart_chainloader/src/main.rs +++ b/06_uart_chainloader/src/main.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter // Rust embedded logo for `make doc`. #![doc( diff --git a/06_uart_chainloader/src/panic_wait.rs b/06_uart_chainloader/src/panic_wait.rs index fb30e8d4..5bb0896e 100644 --- a/06_uart_chainloader/src/panic_wait.rs +++ b/06_uart_chainloader/src/panic_wait.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! A panic handler that infinitely waits. diff --git a/06_uart_chainloader/src/print.rs b/06_uart_chainloader/src/print.rs index f69bad44..6de99572 100644 --- a/06_uart_chainloader/src/print.rs +++ b/06_uart_chainloader/src/print.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Printing. diff --git a/06_uart_chainloader/src/synchronization.rs b/06_uart_chainloader/src/synchronization.rs index d3937b0d..94c83de1 100644 --- a/06_uart_chainloader/src/synchronization.rs +++ b/06_uart_chainloader/src/synchronization.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Synchronization primitives. //! diff --git a/06_uart_chainloader/tests/chainboot_test.rb b/06_uart_chainloader/tests/chainboot_test.rb index 56099740..00de42a3 100644 --- a/06_uart_chainloader/tests/chainboot_test.rb +++ b/06_uart_chainloader/tests/chainboot_test.rb @@ -2,7 +2,7 @@ # SPDX-License-Identifier: MIT OR Apache-2.0 # -# Copyright (c) 2020-2022 Andre Richter +# Copyright (c) 2020-2023 Andre Richter require_relative '../../common/serial/minipush' require_relative '../../common/tests/boot_test' @@ -69,9 +69,9 @@ class ChainbootTest < BootTest end end -##-------------------------------------------------------------------------------------------------- +## ------------------------------------------------------------------------------------------------- ## Execution starts here -##-------------------------------------------------------------------------------------------------- +## ------------------------------------------------------------------------------------------------- payload_path = ARGV.pop qemu_cmd = ARGV.join(' ') diff --git a/07_timestamps/.vscode/settings.json b/07_timestamps/.vscode/settings.json index d1916456..bfa278e9 100644 --- a/07_timestamps/.vscode/settings.json +++ b/07_timestamps/.vscode/settings.json @@ -1,10 +1,10 @@ { - "editor.formatOnSave": true, - "editor.rulers": [100], - "rust-analyzer.cargo.target": "aarch64-unknown-none-softfloat", - "rust-analyzer.cargo.features": ["bsp_rpi3"], - "rust-analyzer.checkOnSave.allTargets": false, - "rust-analyzer.checkOnSave.extraArgs": ["--bins"], - "rust-analyzer.lens.debug": false, - "rust-analyzer.lens.run": false + "editor.formatOnSave": true, + "editor.rulers": [100], + "rust-analyzer.cargo.target": "aarch64-unknown-none-softfloat", + "rust-analyzer.cargo.features": ["bsp_rpi3"], + "rust-analyzer.checkOnSave.allTargets": false, + "rust-analyzer.checkOnSave.extraArgs": ["--bins"], + "rust-analyzer.lens.debug": false, + "rust-analyzer.lens.run": false } diff --git a/07_timestamps/Makefile b/07_timestamps/Makefile index 23de6557..b13f0dfb 100644 --- a/07_timestamps/Makefile +++ b/07_timestamps/Makefile @@ -1,6 +1,6 @@ ## SPDX-License-Identifier: MIT OR Apache-2.0 ## -## Copyright (c) 2018-2022 Andre Richter +## Copyright (c) 2018-2023 Andre Richter include ../common/docker.mk include ../common/format.mk diff --git a/07_timestamps/README.md b/07_timestamps/README.md index afa75ad9..af44e8cc 100644 --- a/07_timestamps/README.md +++ b/07_timestamps/README.md @@ -260,7 +260,7 @@ diff -uNr 06_uart_chainloader/src/_arch/aarch64/time.rs 07_timestamps/src/_arch/ @@ -0,0 +1,162 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// -+// Copyright (c) 2018-2022 Andre Richter ++// Copyright (c) 2018-2023 Andre Richter + +//! Architectural timer primitives. +//! @@ -527,7 +527,7 @@ diff -uNr 06_uart_chainloader/src/bsp/raspberrypi/kernel.ld 07_timestamps/src/bs --- 06_uart_chainloader/src/bsp/raspberrypi/kernel.ld +++ 07_timestamps/src/bsp/raspberrypi/kernel.ld @@ -3,6 +3,8 @@ - * Copyright (c) 2018-2022 Andre Richter + * Copyright (c) 2018-2023 Andre Richter */ +__rpi_phys_dram_start_addr = 0; @@ -822,7 +822,7 @@ diff -uNr 06_uart_chainloader/src/time.rs 07_timestamps/src/time.rs @@ -0,0 +1,57 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// -+// Copyright (c) 2020-2022 Andre Richter ++// Copyright (c) 2020-2023 Andre Richter + +//! Timer primitives. + @@ -894,7 +894,7 @@ diff -uNr 06_uart_chainloader/tests/chainboot_test.rb 07_timestamps/tests/chainb - -# SPDX-License-Identifier: MIT OR Apache-2.0 -# --# Copyright (c) 2020-2022 Andre Richter +-# Copyright (c) 2020-2023 Andre Richter - -require_relative '../../common/serial/minipush' -require_relative '../../common/tests/boot_test' diff --git a/07_timestamps/src/_arch/aarch64/cpu.rs b/07_timestamps/src/_arch/aarch64/cpu.rs index bbe7687a..602c9789 100644 --- a/07_timestamps/src/_arch/aarch64/cpu.rs +++ b/07_timestamps/src/_arch/aarch64/cpu.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Architectural processor code. //! diff --git a/07_timestamps/src/_arch/aarch64/cpu/boot.rs b/07_timestamps/src/_arch/aarch64/cpu/boot.rs index 8390c013..2a6c4649 100644 --- a/07_timestamps/src/_arch/aarch64/cpu/boot.rs +++ b/07_timestamps/src/_arch/aarch64/cpu/boot.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2021-2022 Andre Richter +// Copyright (c) 2021-2023 Andre Richter //! Architectural boot code. //! diff --git a/07_timestamps/src/_arch/aarch64/time.rs b/07_timestamps/src/_arch/aarch64/time.rs index 94d02379..ee1c3ef7 100644 --- a/07_timestamps/src/_arch/aarch64/time.rs +++ b/07_timestamps/src/_arch/aarch64/time.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Architectural timer primitives. //! diff --git a/07_timestamps/src/bsp.rs b/07_timestamps/src/bsp.rs index 824787f6..246973bc 100644 --- a/07_timestamps/src/bsp.rs +++ b/07_timestamps/src/bsp.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Conditional reexporting of Board Support Packages. diff --git a/07_timestamps/src/bsp/device_driver.rs b/07_timestamps/src/bsp/device_driver.rs index 6e9bf8f3..64049a4c 100644 --- a/07_timestamps/src/bsp/device_driver.rs +++ b/07_timestamps/src/bsp/device_driver.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Device driver. diff --git a/07_timestamps/src/bsp/device_driver/bcm.rs b/07_timestamps/src/bsp/device_driver/bcm.rs index b4b7906e..1c343d1d 100644 --- a/07_timestamps/src/bsp/device_driver/bcm.rs +++ b/07_timestamps/src/bsp/device_driver/bcm.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! BCM driver top level. diff --git a/07_timestamps/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs b/07_timestamps/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs index 24e537cf..8e57dfed 100644 --- a/07_timestamps/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs +++ b/07_timestamps/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! GPIO Driver. diff --git a/07_timestamps/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs b/07_timestamps/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs index b034e92e..d92612ea 100644 --- a/07_timestamps/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs +++ b/07_timestamps/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! PL011 UART driver. //! diff --git a/07_timestamps/src/bsp/device_driver/common.rs b/07_timestamps/src/bsp/device_driver/common.rs index fd9e988e..dfe7d8ef 100644 --- a/07_timestamps/src/bsp/device_driver/common.rs +++ b/07_timestamps/src/bsp/device_driver/common.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Common device driver code. diff --git a/07_timestamps/src/bsp/raspberrypi.rs b/07_timestamps/src/bsp/raspberrypi.rs index fe940677..3ea864dc 100644 --- a/07_timestamps/src/bsp/raspberrypi.rs +++ b/07_timestamps/src/bsp/raspberrypi.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Top-level BSP file for the Raspberry Pi 3 and 4. diff --git a/07_timestamps/src/bsp/raspberrypi/cpu.rs b/07_timestamps/src/bsp/raspberrypi/cpu.rs index 85fb89e4..65cf5abb 100644 --- a/07_timestamps/src/bsp/raspberrypi/cpu.rs +++ b/07_timestamps/src/bsp/raspberrypi/cpu.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! BSP Processor code. diff --git a/07_timestamps/src/bsp/raspberrypi/driver.rs b/07_timestamps/src/bsp/raspberrypi/driver.rs index 4a42b84f..7716fe3f 100644 --- a/07_timestamps/src/bsp/raspberrypi/driver.rs +++ b/07_timestamps/src/bsp/raspberrypi/driver.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! BSP driver support. diff --git a/07_timestamps/src/bsp/raspberrypi/memory.rs b/07_timestamps/src/bsp/raspberrypi/memory.rs index 27be8590..cdca14b8 100644 --- a/07_timestamps/src/bsp/raspberrypi/memory.rs +++ b/07_timestamps/src/bsp/raspberrypi/memory.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! BSP Memory Management. diff --git a/07_timestamps/src/console.rs b/07_timestamps/src/console.rs index 02b43df9..a83f86fe 100644 --- a/07_timestamps/src/console.rs +++ b/07_timestamps/src/console.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! System console. diff --git a/07_timestamps/src/console/null_console.rs b/07_timestamps/src/console/null_console.rs index 2c64d499..e92a022b 100644 --- a/07_timestamps/src/console/null_console.rs +++ b/07_timestamps/src/console/null_console.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2022 Andre Richter +// Copyright (c) 2022-2023 Andre Richter //! Null console. diff --git a/07_timestamps/src/cpu.rs b/07_timestamps/src/cpu.rs index 62503fb4..67ab79c0 100644 --- a/07_timestamps/src/cpu.rs +++ b/07_timestamps/src/cpu.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Processor code. diff --git a/07_timestamps/src/cpu/boot.rs b/07_timestamps/src/cpu/boot.rs index 8091dac3..b1e98328 100644 --- a/07_timestamps/src/cpu/boot.rs +++ b/07_timestamps/src/cpu/boot.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2021-2022 Andre Richter +// Copyright (c) 2021-2023 Andre Richter //! Boot code. diff --git a/07_timestamps/src/driver.rs b/07_timestamps/src/driver.rs index a798c86d..050e7022 100644 --- a/07_timestamps/src/driver.rs +++ b/07_timestamps/src/driver.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Driver support. diff --git a/07_timestamps/src/main.rs b/07_timestamps/src/main.rs index df863f32..b094dacc 100644 --- a/07_timestamps/src/main.rs +++ b/07_timestamps/src/main.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter // Rust embedded logo for `make doc`. #![doc( diff --git a/07_timestamps/src/panic_wait.rs b/07_timestamps/src/panic_wait.rs index ccf54f61..5776aca8 100644 --- a/07_timestamps/src/panic_wait.rs +++ b/07_timestamps/src/panic_wait.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! A panic handler that infinitely waits. diff --git a/07_timestamps/src/print.rs b/07_timestamps/src/print.rs index fe13b334..8e303046 100644 --- a/07_timestamps/src/print.rs +++ b/07_timestamps/src/print.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Printing. diff --git a/07_timestamps/src/synchronization.rs b/07_timestamps/src/synchronization.rs index d3937b0d..94c83de1 100644 --- a/07_timestamps/src/synchronization.rs +++ b/07_timestamps/src/synchronization.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Synchronization primitives. //! diff --git a/07_timestamps/src/time.rs b/07_timestamps/src/time.rs index a6c0c5b6..a9d50120 100644 --- a/07_timestamps/src/time.rs +++ b/07_timestamps/src/time.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Timer primitives. diff --git a/08_hw_debug_JTAG/.vscode/settings.json b/08_hw_debug_JTAG/.vscode/settings.json index d1916456..bfa278e9 100644 --- a/08_hw_debug_JTAG/.vscode/settings.json +++ b/08_hw_debug_JTAG/.vscode/settings.json @@ -1,10 +1,10 @@ { - "editor.formatOnSave": true, - "editor.rulers": [100], - "rust-analyzer.cargo.target": "aarch64-unknown-none-softfloat", - "rust-analyzer.cargo.features": ["bsp_rpi3"], - "rust-analyzer.checkOnSave.allTargets": false, - "rust-analyzer.checkOnSave.extraArgs": ["--bins"], - "rust-analyzer.lens.debug": false, - "rust-analyzer.lens.run": false + "editor.formatOnSave": true, + "editor.rulers": [100], + "rust-analyzer.cargo.target": "aarch64-unknown-none-softfloat", + "rust-analyzer.cargo.features": ["bsp_rpi3"], + "rust-analyzer.checkOnSave.allTargets": false, + "rust-analyzer.checkOnSave.extraArgs": ["--bins"], + "rust-analyzer.lens.debug": false, + "rust-analyzer.lens.run": false } diff --git a/08_hw_debug_JTAG/Makefile b/08_hw_debug_JTAG/Makefile index 125f75cb..9549f092 100644 --- a/08_hw_debug_JTAG/Makefile +++ b/08_hw_debug_JTAG/Makefile @@ -1,6 +1,6 @@ ## SPDX-License-Identifier: MIT OR Apache-2.0 ## -## Copyright (c) 2018-2022 Andre Richter +## Copyright (c) 2018-2023 Andre Richter include ../common/docker.mk include ../common/format.mk diff --git a/08_hw_debug_JTAG/src/_arch/aarch64/cpu.rs b/08_hw_debug_JTAG/src/_arch/aarch64/cpu.rs index bbe7687a..602c9789 100644 --- a/08_hw_debug_JTAG/src/_arch/aarch64/cpu.rs +++ b/08_hw_debug_JTAG/src/_arch/aarch64/cpu.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Architectural processor code. //! diff --git a/08_hw_debug_JTAG/src/_arch/aarch64/cpu/boot.rs b/08_hw_debug_JTAG/src/_arch/aarch64/cpu/boot.rs index 8390c013..2a6c4649 100644 --- a/08_hw_debug_JTAG/src/_arch/aarch64/cpu/boot.rs +++ b/08_hw_debug_JTAG/src/_arch/aarch64/cpu/boot.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2021-2022 Andre Richter +// Copyright (c) 2021-2023 Andre Richter //! Architectural boot code. //! diff --git a/08_hw_debug_JTAG/src/_arch/aarch64/time.rs b/08_hw_debug_JTAG/src/_arch/aarch64/time.rs index 94d02379..ee1c3ef7 100644 --- a/08_hw_debug_JTAG/src/_arch/aarch64/time.rs +++ b/08_hw_debug_JTAG/src/_arch/aarch64/time.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Architectural timer primitives. //! diff --git a/08_hw_debug_JTAG/src/bsp.rs b/08_hw_debug_JTAG/src/bsp.rs index 824787f6..246973bc 100644 --- a/08_hw_debug_JTAG/src/bsp.rs +++ b/08_hw_debug_JTAG/src/bsp.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Conditional reexporting of Board Support Packages. diff --git a/08_hw_debug_JTAG/src/bsp/device_driver.rs b/08_hw_debug_JTAG/src/bsp/device_driver.rs index 6e9bf8f3..64049a4c 100644 --- a/08_hw_debug_JTAG/src/bsp/device_driver.rs +++ b/08_hw_debug_JTAG/src/bsp/device_driver.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Device driver. diff --git a/08_hw_debug_JTAG/src/bsp/device_driver/bcm.rs b/08_hw_debug_JTAG/src/bsp/device_driver/bcm.rs index b4b7906e..1c343d1d 100644 --- a/08_hw_debug_JTAG/src/bsp/device_driver/bcm.rs +++ b/08_hw_debug_JTAG/src/bsp/device_driver/bcm.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! BCM driver top level. diff --git a/08_hw_debug_JTAG/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs b/08_hw_debug_JTAG/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs index 24e537cf..8e57dfed 100644 --- a/08_hw_debug_JTAG/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs +++ b/08_hw_debug_JTAG/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! GPIO Driver. diff --git a/08_hw_debug_JTAG/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs b/08_hw_debug_JTAG/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs index b034e92e..d92612ea 100644 --- a/08_hw_debug_JTAG/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs +++ b/08_hw_debug_JTAG/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! PL011 UART driver. //! diff --git a/08_hw_debug_JTAG/src/bsp/device_driver/common.rs b/08_hw_debug_JTAG/src/bsp/device_driver/common.rs index fd9e988e..dfe7d8ef 100644 --- a/08_hw_debug_JTAG/src/bsp/device_driver/common.rs +++ b/08_hw_debug_JTAG/src/bsp/device_driver/common.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Common device driver code. diff --git a/08_hw_debug_JTAG/src/bsp/raspberrypi.rs b/08_hw_debug_JTAG/src/bsp/raspberrypi.rs index fe940677..3ea864dc 100644 --- a/08_hw_debug_JTAG/src/bsp/raspberrypi.rs +++ b/08_hw_debug_JTAG/src/bsp/raspberrypi.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Top-level BSP file for the Raspberry Pi 3 and 4. diff --git a/08_hw_debug_JTAG/src/bsp/raspberrypi/cpu.rs b/08_hw_debug_JTAG/src/bsp/raspberrypi/cpu.rs index 85fb89e4..65cf5abb 100644 --- a/08_hw_debug_JTAG/src/bsp/raspberrypi/cpu.rs +++ b/08_hw_debug_JTAG/src/bsp/raspberrypi/cpu.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! BSP Processor code. diff --git a/08_hw_debug_JTAG/src/bsp/raspberrypi/driver.rs b/08_hw_debug_JTAG/src/bsp/raspberrypi/driver.rs index ea843066..2a80ee2c 100644 --- a/08_hw_debug_JTAG/src/bsp/raspberrypi/driver.rs +++ b/08_hw_debug_JTAG/src/bsp/raspberrypi/driver.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! BSP driver support. diff --git a/08_hw_debug_JTAG/src/bsp/raspberrypi/memory.rs b/08_hw_debug_JTAG/src/bsp/raspberrypi/memory.rs index 27be8590..cdca14b8 100644 --- a/08_hw_debug_JTAG/src/bsp/raspberrypi/memory.rs +++ b/08_hw_debug_JTAG/src/bsp/raspberrypi/memory.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! BSP Memory Management. diff --git a/08_hw_debug_JTAG/src/console.rs b/08_hw_debug_JTAG/src/console.rs index 02b43df9..a83f86fe 100644 --- a/08_hw_debug_JTAG/src/console.rs +++ b/08_hw_debug_JTAG/src/console.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! System console. diff --git a/08_hw_debug_JTAG/src/console/null_console.rs b/08_hw_debug_JTAG/src/console/null_console.rs index 2c64d499..e92a022b 100644 --- a/08_hw_debug_JTAG/src/console/null_console.rs +++ b/08_hw_debug_JTAG/src/console/null_console.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2022 Andre Richter +// Copyright (c) 2022-2023 Andre Richter //! Null console. diff --git a/08_hw_debug_JTAG/src/cpu.rs b/08_hw_debug_JTAG/src/cpu.rs index 62503fb4..67ab79c0 100644 --- a/08_hw_debug_JTAG/src/cpu.rs +++ b/08_hw_debug_JTAG/src/cpu.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Processor code. diff --git a/08_hw_debug_JTAG/src/cpu/boot.rs b/08_hw_debug_JTAG/src/cpu/boot.rs index 8091dac3..b1e98328 100644 --- a/08_hw_debug_JTAG/src/cpu/boot.rs +++ b/08_hw_debug_JTAG/src/cpu/boot.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2021-2022 Andre Richter +// Copyright (c) 2021-2023 Andre Richter //! Boot code. diff --git a/08_hw_debug_JTAG/src/driver.rs b/08_hw_debug_JTAG/src/driver.rs index a798c86d..050e7022 100644 --- a/08_hw_debug_JTAG/src/driver.rs +++ b/08_hw_debug_JTAG/src/driver.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Driver support. diff --git a/08_hw_debug_JTAG/src/main.rs b/08_hw_debug_JTAG/src/main.rs index df863f32..b094dacc 100644 --- a/08_hw_debug_JTAG/src/main.rs +++ b/08_hw_debug_JTAG/src/main.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter // Rust embedded logo for `make doc`. #![doc( diff --git a/08_hw_debug_JTAG/src/panic_wait.rs b/08_hw_debug_JTAG/src/panic_wait.rs index ccf54f61..5776aca8 100644 --- a/08_hw_debug_JTAG/src/panic_wait.rs +++ b/08_hw_debug_JTAG/src/panic_wait.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! A panic handler that infinitely waits. diff --git a/08_hw_debug_JTAG/src/print.rs b/08_hw_debug_JTAG/src/print.rs index fe13b334..8e303046 100644 --- a/08_hw_debug_JTAG/src/print.rs +++ b/08_hw_debug_JTAG/src/print.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Printing. diff --git a/08_hw_debug_JTAG/src/synchronization.rs b/08_hw_debug_JTAG/src/synchronization.rs index d3937b0d..94c83de1 100644 --- a/08_hw_debug_JTAG/src/synchronization.rs +++ b/08_hw_debug_JTAG/src/synchronization.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Synchronization primitives. //! diff --git a/08_hw_debug_JTAG/src/time.rs b/08_hw_debug_JTAG/src/time.rs index a6c0c5b6..a9d50120 100644 --- a/08_hw_debug_JTAG/src/time.rs +++ b/08_hw_debug_JTAG/src/time.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Timer primitives. diff --git a/09_privilege_level/.vscode/settings.json b/09_privilege_level/.vscode/settings.json index d1916456..bfa278e9 100644 --- a/09_privilege_level/.vscode/settings.json +++ b/09_privilege_level/.vscode/settings.json @@ -1,10 +1,10 @@ { - "editor.formatOnSave": true, - "editor.rulers": [100], - "rust-analyzer.cargo.target": "aarch64-unknown-none-softfloat", - "rust-analyzer.cargo.features": ["bsp_rpi3"], - "rust-analyzer.checkOnSave.allTargets": false, - "rust-analyzer.checkOnSave.extraArgs": ["--bins"], - "rust-analyzer.lens.debug": false, - "rust-analyzer.lens.run": false + "editor.formatOnSave": true, + "editor.rulers": [100], + "rust-analyzer.cargo.target": "aarch64-unknown-none-softfloat", + "rust-analyzer.cargo.features": ["bsp_rpi3"], + "rust-analyzer.checkOnSave.allTargets": false, + "rust-analyzer.checkOnSave.extraArgs": ["--bins"], + "rust-analyzer.lens.debug": false, + "rust-analyzer.lens.run": false } diff --git a/09_privilege_level/Makefile b/09_privilege_level/Makefile index 125f75cb..9549f092 100644 --- a/09_privilege_level/Makefile +++ b/09_privilege_level/Makefile @@ -1,6 +1,6 @@ ## SPDX-License-Identifier: MIT OR Apache-2.0 ## -## Copyright (c) 2018-2022 Andre Richter +## Copyright (c) 2018-2023 Andre Richter include ../common/docker.mk include ../common/format.mk diff --git a/09_privilege_level/README.md b/09_privilege_level/README.md index bb704700..ca2b920f 100644 --- a/09_privilege_level/README.md +++ b/09_privilege_level/README.md @@ -338,7 +338,7 @@ diff -uNr 08_hw_debug_JTAG/src/_arch/aarch64/exception/asynchronous.rs 09_privil @@ -0,0 +1,82 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// -+// Copyright (c) 2018-2022 Andre Richter ++// Copyright (c) 2018-2023 Andre Richter + +//! Architectural asynchronous exception handling. +//! @@ -425,7 +425,7 @@ diff -uNr 08_hw_debug_JTAG/src/_arch/aarch64/exception.rs 09_privilege_level/src @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// -+// Copyright (c) 2018-2022 Andre Richter ++// Copyright (c) 2018-2023 Andre Richter + +//! Architectural synchronous and asynchronous exception handling. +//! @@ -461,7 +461,7 @@ diff -uNr 08_hw_debug_JTAG/src/exception/asynchronous.rs 09_privilege_level/src/ @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// -+// Copyright (c) 2020-2022 Andre Richter ++// Copyright (c) 2020-2023 Andre Richter + +//! Asynchronous exception handling. + @@ -480,7 +480,7 @@ diff -uNr 08_hw_debug_JTAG/src/exception.rs 09_privilege_level/src/exception.rs @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// -+// Copyright (c) 2020-2022 Andre Richter ++// Copyright (c) 2020-2023 Andre Richter + +//! Synchronous and asynchronous exception handling. + diff --git a/09_privilege_level/src/_arch/aarch64/cpu.rs b/09_privilege_level/src/_arch/aarch64/cpu.rs index bbe7687a..602c9789 100644 --- a/09_privilege_level/src/_arch/aarch64/cpu.rs +++ b/09_privilege_level/src/_arch/aarch64/cpu.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Architectural processor code. //! diff --git a/09_privilege_level/src/_arch/aarch64/cpu/boot.rs b/09_privilege_level/src/_arch/aarch64/cpu/boot.rs index b458f0db..c80f3ebb 100644 --- a/09_privilege_level/src/_arch/aarch64/cpu/boot.rs +++ b/09_privilege_level/src/_arch/aarch64/cpu/boot.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2021-2022 Andre Richter +// Copyright (c) 2021-2023 Andre Richter //! Architectural boot code. //! diff --git a/09_privilege_level/src/_arch/aarch64/exception.rs b/09_privilege_level/src/_arch/aarch64/exception.rs index c2b7cea8..1051af6a 100644 --- a/09_privilege_level/src/_arch/aarch64/exception.rs +++ b/09_privilege_level/src/_arch/aarch64/exception.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Architectural synchronous and asynchronous exception handling. //! diff --git a/09_privilege_level/src/_arch/aarch64/exception/asynchronous.rs b/09_privilege_level/src/_arch/aarch64/exception/asynchronous.rs index 0347dc3f..65fcad25 100644 --- a/09_privilege_level/src/_arch/aarch64/exception/asynchronous.rs +++ b/09_privilege_level/src/_arch/aarch64/exception/asynchronous.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Architectural asynchronous exception handling. //! diff --git a/09_privilege_level/src/_arch/aarch64/time.rs b/09_privilege_level/src/_arch/aarch64/time.rs index 94d02379..ee1c3ef7 100644 --- a/09_privilege_level/src/_arch/aarch64/time.rs +++ b/09_privilege_level/src/_arch/aarch64/time.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Architectural timer primitives. //! diff --git a/09_privilege_level/src/bsp.rs b/09_privilege_level/src/bsp.rs index 824787f6..246973bc 100644 --- a/09_privilege_level/src/bsp.rs +++ b/09_privilege_level/src/bsp.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Conditional reexporting of Board Support Packages. diff --git a/09_privilege_level/src/bsp/device_driver.rs b/09_privilege_level/src/bsp/device_driver.rs index 6e9bf8f3..64049a4c 100644 --- a/09_privilege_level/src/bsp/device_driver.rs +++ b/09_privilege_level/src/bsp/device_driver.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Device driver. diff --git a/09_privilege_level/src/bsp/device_driver/bcm.rs b/09_privilege_level/src/bsp/device_driver/bcm.rs index b4b7906e..1c343d1d 100644 --- a/09_privilege_level/src/bsp/device_driver/bcm.rs +++ b/09_privilege_level/src/bsp/device_driver/bcm.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! BCM driver top level. diff --git a/09_privilege_level/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs b/09_privilege_level/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs index 24e537cf..8e57dfed 100644 --- a/09_privilege_level/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs +++ b/09_privilege_level/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! GPIO Driver. diff --git a/09_privilege_level/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs b/09_privilege_level/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs index b034e92e..d92612ea 100644 --- a/09_privilege_level/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs +++ b/09_privilege_level/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! PL011 UART driver. //! diff --git a/09_privilege_level/src/bsp/device_driver/common.rs b/09_privilege_level/src/bsp/device_driver/common.rs index fd9e988e..dfe7d8ef 100644 --- a/09_privilege_level/src/bsp/device_driver/common.rs +++ b/09_privilege_level/src/bsp/device_driver/common.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Common device driver code. diff --git a/09_privilege_level/src/bsp/raspberrypi.rs b/09_privilege_level/src/bsp/raspberrypi.rs index fe940677..3ea864dc 100644 --- a/09_privilege_level/src/bsp/raspberrypi.rs +++ b/09_privilege_level/src/bsp/raspberrypi.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Top-level BSP file for the Raspberry Pi 3 and 4. diff --git a/09_privilege_level/src/bsp/raspberrypi/cpu.rs b/09_privilege_level/src/bsp/raspberrypi/cpu.rs index 85fb89e4..65cf5abb 100644 --- a/09_privilege_level/src/bsp/raspberrypi/cpu.rs +++ b/09_privilege_level/src/bsp/raspberrypi/cpu.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! BSP Processor code. diff --git a/09_privilege_level/src/bsp/raspberrypi/driver.rs b/09_privilege_level/src/bsp/raspberrypi/driver.rs index ea843066..2a80ee2c 100644 --- a/09_privilege_level/src/bsp/raspberrypi/driver.rs +++ b/09_privilege_level/src/bsp/raspberrypi/driver.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! BSP driver support. diff --git a/09_privilege_level/src/bsp/raspberrypi/memory.rs b/09_privilege_level/src/bsp/raspberrypi/memory.rs index 27be8590..cdca14b8 100644 --- a/09_privilege_level/src/bsp/raspberrypi/memory.rs +++ b/09_privilege_level/src/bsp/raspberrypi/memory.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! BSP Memory Management. diff --git a/09_privilege_level/src/console.rs b/09_privilege_level/src/console.rs index 02b43df9..a83f86fe 100644 --- a/09_privilege_level/src/console.rs +++ b/09_privilege_level/src/console.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! System console. diff --git a/09_privilege_level/src/console/null_console.rs b/09_privilege_level/src/console/null_console.rs index 2c64d499..e92a022b 100644 --- a/09_privilege_level/src/console/null_console.rs +++ b/09_privilege_level/src/console/null_console.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2022 Andre Richter +// Copyright (c) 2022-2023 Andre Richter //! Null console. diff --git a/09_privilege_level/src/cpu.rs b/09_privilege_level/src/cpu.rs index 62503fb4..67ab79c0 100644 --- a/09_privilege_level/src/cpu.rs +++ b/09_privilege_level/src/cpu.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Processor code. diff --git a/09_privilege_level/src/cpu/boot.rs b/09_privilege_level/src/cpu/boot.rs index 8091dac3..b1e98328 100644 --- a/09_privilege_level/src/cpu/boot.rs +++ b/09_privilege_level/src/cpu/boot.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2021-2022 Andre Richter +// Copyright (c) 2021-2023 Andre Richter //! Boot code. diff --git a/09_privilege_level/src/driver.rs b/09_privilege_level/src/driver.rs index a798c86d..050e7022 100644 --- a/09_privilege_level/src/driver.rs +++ b/09_privilege_level/src/driver.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Driver support. diff --git a/09_privilege_level/src/exception.rs b/09_privilege_level/src/exception.rs index d5f2e68e..45760391 100644 --- a/09_privilege_level/src/exception.rs +++ b/09_privilege_level/src/exception.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Synchronous and asynchronous exception handling. diff --git a/09_privilege_level/src/exception/asynchronous.rs b/09_privilege_level/src/exception/asynchronous.rs index bad85779..fd059326 100644 --- a/09_privilege_level/src/exception/asynchronous.rs +++ b/09_privilege_level/src/exception/asynchronous.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Asynchronous exception handling. diff --git a/09_privilege_level/src/main.rs b/09_privilege_level/src/main.rs index c60aee8e..cc0e1dfd 100644 --- a/09_privilege_level/src/main.rs +++ b/09_privilege_level/src/main.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter // Rust embedded logo for `make doc`. #![doc( diff --git a/09_privilege_level/src/panic_wait.rs b/09_privilege_level/src/panic_wait.rs index ccf54f61..5776aca8 100644 --- a/09_privilege_level/src/panic_wait.rs +++ b/09_privilege_level/src/panic_wait.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! A panic handler that infinitely waits. diff --git a/09_privilege_level/src/print.rs b/09_privilege_level/src/print.rs index fe13b334..8e303046 100644 --- a/09_privilege_level/src/print.rs +++ b/09_privilege_level/src/print.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Printing. diff --git a/09_privilege_level/src/synchronization.rs b/09_privilege_level/src/synchronization.rs index d3937b0d..94c83de1 100644 --- a/09_privilege_level/src/synchronization.rs +++ b/09_privilege_level/src/synchronization.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Synchronization primitives. //! diff --git a/09_privilege_level/src/time.rs b/09_privilege_level/src/time.rs index a6c0c5b6..a9d50120 100644 --- a/09_privilege_level/src/time.rs +++ b/09_privilege_level/src/time.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Timer primitives. diff --git a/10_virtual_mem_part1_identity_mapping/.vscode/settings.json b/10_virtual_mem_part1_identity_mapping/.vscode/settings.json index d1916456..bfa278e9 100644 --- a/10_virtual_mem_part1_identity_mapping/.vscode/settings.json +++ b/10_virtual_mem_part1_identity_mapping/.vscode/settings.json @@ -1,10 +1,10 @@ { - "editor.formatOnSave": true, - "editor.rulers": [100], - "rust-analyzer.cargo.target": "aarch64-unknown-none-softfloat", - "rust-analyzer.cargo.features": ["bsp_rpi3"], - "rust-analyzer.checkOnSave.allTargets": false, - "rust-analyzer.checkOnSave.extraArgs": ["--bins"], - "rust-analyzer.lens.debug": false, - "rust-analyzer.lens.run": false + "editor.formatOnSave": true, + "editor.rulers": [100], + "rust-analyzer.cargo.target": "aarch64-unknown-none-softfloat", + "rust-analyzer.cargo.features": ["bsp_rpi3"], + "rust-analyzer.checkOnSave.allTargets": false, + "rust-analyzer.checkOnSave.extraArgs": ["--bins"], + "rust-analyzer.lens.debug": false, + "rust-analyzer.lens.run": false } diff --git a/10_virtual_mem_part1_identity_mapping/Makefile b/10_virtual_mem_part1_identity_mapping/Makefile index 125f75cb..9549f092 100644 --- a/10_virtual_mem_part1_identity_mapping/Makefile +++ b/10_virtual_mem_part1_identity_mapping/Makefile @@ -1,6 +1,6 @@ ## SPDX-License-Identifier: MIT OR Apache-2.0 ## -## Copyright (c) 2018-2022 Andre Richter +## Copyright (c) 2018-2023 Andre Richter include ../common/docker.mk include ../common/format.mk diff --git a/10_virtual_mem_part1_identity_mapping/README.md b/10_virtual_mem_part1_identity_mapping/README.md index 36c37c79..498ef111 100644 --- a/10_virtual_mem_part1_identity_mapping/README.md +++ b/10_virtual_mem_part1_identity_mapping/README.md @@ -367,7 +367,7 @@ diff -uNr 09_privilege_level/src/_arch/aarch64/memory/mmu/translation_table.rs 1 @@ -0,0 +1,292 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// -+// Copyright (c) 2021-2022 Andre Richter ++// Copyright (c) 2021-2023 Andre Richter + +//! Architectural translation table. +//! @@ -664,7 +664,7 @@ diff -uNr 09_privilege_level/src/_arch/aarch64/memory/mmu.rs 10_virtual_mem_part @@ -0,0 +1,165 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// -+// Copyright (c) 2018-2022 Andre Richter ++// Copyright (c) 2018-2023 Andre Richter + +//! Memory Management Unit Driver. +//! @@ -832,7 +832,7 @@ diff -uNr 09_privilege_level/src/bsp/raspberrypi/kernel.ld 10_virtual_mem_part1_ --- 09_privilege_level/src/bsp/raspberrypi/kernel.ld +++ 10_virtual_mem_part1_identity_mapping/src/bsp/raspberrypi/kernel.ld @@ -3,6 +3,9 @@ - * Copyright (c) 2018-2022 Andre Richter + * Copyright (c) 2018-2023 Andre Richter */ +PAGE_SIZE = 64K; @@ -871,7 +871,7 @@ diff -uNr 09_privilege_level/src/bsp/raspberrypi/memory/mmu.rs 10_virtual_mem_pa @@ -0,0 +1,86 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// -+// Copyright (c) 2018-2022 Andre Richter ++// Copyright (c) 2018-2023 Andre Richter + +//! BSP Memory Management Unit. + @@ -960,7 +960,7 @@ diff -uNr 09_privilege_level/src/bsp/raspberrypi/memory.rs 10_virtual_mem_part1_ --- 09_privilege_level/src/bsp/raspberrypi/memory.rs +++ 10_virtual_mem_part1_identity_mapping/src/bsp/raspberrypi/memory.rs @@ -3,6 +3,45 @@ - // Copyright (c) 2018-2022 Andre Richter + // Copyright (c) 2018-2023 Andre Richter //! BSP Memory Management. +//! @@ -1084,7 +1084,7 @@ diff -uNr 09_privilege_level/src/common.rs 10_virtual_mem_part1_identity_mapping @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// -+// Copyright (c) 2020-2022 Andre Richter ++// Copyright (c) 2020-2023 Andre Richter + +//! General purpose code. + @@ -1193,7 +1193,7 @@ diff -uNr 09_privilege_level/src/memory/mmu/translation_table.rs 10_virtual_mem_ @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// -+// Copyright (c) 2021-2022 Andre Richter ++// Copyright (c) 2021-2023 Andre Richter + +//! Translation table. + @@ -1212,7 +1212,7 @@ diff -uNr 09_privilege_level/src/memory/mmu.rs 10_virtual_mem_part1_identity_map @@ -0,0 +1,253 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// -+// Copyright (c) 2020-2022 Andre Richter ++// Copyright (c) 2020-2023 Andre Richter + +//! Memory Management Unit. +//! @@ -1470,7 +1470,7 @@ diff -uNr 09_privilege_level/src/memory.rs 10_virtual_mem_part1_identity_mapping @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// -+// Copyright (c) 2018-2022 Andre Richter ++// Copyright (c) 2018-2023 Andre Richter + +//! Memory Management. + diff --git a/10_virtual_mem_part1_identity_mapping/src/_arch/aarch64/cpu.rs b/10_virtual_mem_part1_identity_mapping/src/_arch/aarch64/cpu.rs index bbe7687a..602c9789 100644 --- a/10_virtual_mem_part1_identity_mapping/src/_arch/aarch64/cpu.rs +++ b/10_virtual_mem_part1_identity_mapping/src/_arch/aarch64/cpu.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Architectural processor code. //! diff --git a/10_virtual_mem_part1_identity_mapping/src/_arch/aarch64/cpu/boot.rs b/10_virtual_mem_part1_identity_mapping/src/_arch/aarch64/cpu/boot.rs index b458f0db..c80f3ebb 100644 --- a/10_virtual_mem_part1_identity_mapping/src/_arch/aarch64/cpu/boot.rs +++ b/10_virtual_mem_part1_identity_mapping/src/_arch/aarch64/cpu/boot.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2021-2022 Andre Richter +// Copyright (c) 2021-2023 Andre Richter //! Architectural boot code. //! diff --git a/10_virtual_mem_part1_identity_mapping/src/_arch/aarch64/exception.rs b/10_virtual_mem_part1_identity_mapping/src/_arch/aarch64/exception.rs index c2b7cea8..1051af6a 100644 --- a/10_virtual_mem_part1_identity_mapping/src/_arch/aarch64/exception.rs +++ b/10_virtual_mem_part1_identity_mapping/src/_arch/aarch64/exception.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Architectural synchronous and asynchronous exception handling. //! diff --git a/10_virtual_mem_part1_identity_mapping/src/_arch/aarch64/exception/asynchronous.rs b/10_virtual_mem_part1_identity_mapping/src/_arch/aarch64/exception/asynchronous.rs index 0347dc3f..65fcad25 100644 --- a/10_virtual_mem_part1_identity_mapping/src/_arch/aarch64/exception/asynchronous.rs +++ b/10_virtual_mem_part1_identity_mapping/src/_arch/aarch64/exception/asynchronous.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Architectural asynchronous exception handling. //! diff --git a/10_virtual_mem_part1_identity_mapping/src/_arch/aarch64/memory/mmu.rs b/10_virtual_mem_part1_identity_mapping/src/_arch/aarch64/memory/mmu.rs index e5e2653a..eea4465c 100644 --- a/10_virtual_mem_part1_identity_mapping/src/_arch/aarch64/memory/mmu.rs +++ b/10_virtual_mem_part1_identity_mapping/src/_arch/aarch64/memory/mmu.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Memory Management Unit Driver. //! diff --git a/10_virtual_mem_part1_identity_mapping/src/_arch/aarch64/memory/mmu/translation_table.rs b/10_virtual_mem_part1_identity_mapping/src/_arch/aarch64/memory/mmu/translation_table.rs index 057335c4..f3d8f619 100644 --- a/10_virtual_mem_part1_identity_mapping/src/_arch/aarch64/memory/mmu/translation_table.rs +++ b/10_virtual_mem_part1_identity_mapping/src/_arch/aarch64/memory/mmu/translation_table.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2021-2022 Andre Richter +// Copyright (c) 2021-2023 Andre Richter //! Architectural translation table. //! diff --git a/10_virtual_mem_part1_identity_mapping/src/_arch/aarch64/time.rs b/10_virtual_mem_part1_identity_mapping/src/_arch/aarch64/time.rs index 94d02379..ee1c3ef7 100644 --- a/10_virtual_mem_part1_identity_mapping/src/_arch/aarch64/time.rs +++ b/10_virtual_mem_part1_identity_mapping/src/_arch/aarch64/time.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Architectural timer primitives. //! diff --git a/10_virtual_mem_part1_identity_mapping/src/bsp.rs b/10_virtual_mem_part1_identity_mapping/src/bsp.rs index 2e860ecb..7a3c804b 100644 --- a/10_virtual_mem_part1_identity_mapping/src/bsp.rs +++ b/10_virtual_mem_part1_identity_mapping/src/bsp.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Conditional reexporting of Board Support Packages. diff --git a/10_virtual_mem_part1_identity_mapping/src/bsp/device_driver.rs b/10_virtual_mem_part1_identity_mapping/src/bsp/device_driver.rs index 6e9bf8f3..64049a4c 100644 --- a/10_virtual_mem_part1_identity_mapping/src/bsp/device_driver.rs +++ b/10_virtual_mem_part1_identity_mapping/src/bsp/device_driver.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Device driver. diff --git a/10_virtual_mem_part1_identity_mapping/src/bsp/device_driver/bcm.rs b/10_virtual_mem_part1_identity_mapping/src/bsp/device_driver/bcm.rs index b4b7906e..1c343d1d 100644 --- a/10_virtual_mem_part1_identity_mapping/src/bsp/device_driver/bcm.rs +++ b/10_virtual_mem_part1_identity_mapping/src/bsp/device_driver/bcm.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! BCM driver top level. diff --git a/10_virtual_mem_part1_identity_mapping/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs b/10_virtual_mem_part1_identity_mapping/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs index 24e537cf..8e57dfed 100644 --- a/10_virtual_mem_part1_identity_mapping/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs +++ b/10_virtual_mem_part1_identity_mapping/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! GPIO Driver. diff --git a/10_virtual_mem_part1_identity_mapping/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs b/10_virtual_mem_part1_identity_mapping/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs index b034e92e..d92612ea 100644 --- a/10_virtual_mem_part1_identity_mapping/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs +++ b/10_virtual_mem_part1_identity_mapping/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! PL011 UART driver. //! diff --git a/10_virtual_mem_part1_identity_mapping/src/bsp/device_driver/common.rs b/10_virtual_mem_part1_identity_mapping/src/bsp/device_driver/common.rs index fd9e988e..dfe7d8ef 100644 --- a/10_virtual_mem_part1_identity_mapping/src/bsp/device_driver/common.rs +++ b/10_virtual_mem_part1_identity_mapping/src/bsp/device_driver/common.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Common device driver code. diff --git a/10_virtual_mem_part1_identity_mapping/src/bsp/raspberrypi.rs b/10_virtual_mem_part1_identity_mapping/src/bsp/raspberrypi.rs index fe940677..3ea864dc 100644 --- a/10_virtual_mem_part1_identity_mapping/src/bsp/raspberrypi.rs +++ b/10_virtual_mem_part1_identity_mapping/src/bsp/raspberrypi.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Top-level BSP file for the Raspberry Pi 3 and 4. diff --git a/10_virtual_mem_part1_identity_mapping/src/bsp/raspberrypi/cpu.rs b/10_virtual_mem_part1_identity_mapping/src/bsp/raspberrypi/cpu.rs index 85fb89e4..65cf5abb 100644 --- a/10_virtual_mem_part1_identity_mapping/src/bsp/raspberrypi/cpu.rs +++ b/10_virtual_mem_part1_identity_mapping/src/bsp/raspberrypi/cpu.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! BSP Processor code. diff --git a/10_virtual_mem_part1_identity_mapping/src/bsp/raspberrypi/driver.rs b/10_virtual_mem_part1_identity_mapping/src/bsp/raspberrypi/driver.rs index ea843066..2a80ee2c 100644 --- a/10_virtual_mem_part1_identity_mapping/src/bsp/raspberrypi/driver.rs +++ b/10_virtual_mem_part1_identity_mapping/src/bsp/raspberrypi/driver.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! BSP driver support. diff --git a/10_virtual_mem_part1_identity_mapping/src/bsp/raspberrypi/kernel.ld b/10_virtual_mem_part1_identity_mapping/src/bsp/raspberrypi/kernel.ld index 6d939889..3ce16cce 100644 --- a/10_virtual_mem_part1_identity_mapping/src/bsp/raspberrypi/kernel.ld +++ b/10_virtual_mem_part1_identity_mapping/src/bsp/raspberrypi/kernel.ld @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: MIT OR Apache-2.0 * - * Copyright (c) 2018-2022 Andre Richter + * Copyright (c) 2018-2023 Andre Richter */ PAGE_SIZE = 64K; diff --git a/10_virtual_mem_part1_identity_mapping/src/bsp/raspberrypi/memory.rs b/10_virtual_mem_part1_identity_mapping/src/bsp/raspberrypi/memory.rs index 7a57b618..661476f4 100644 --- a/10_virtual_mem_part1_identity_mapping/src/bsp/raspberrypi/memory.rs +++ b/10_virtual_mem_part1_identity_mapping/src/bsp/raspberrypi/memory.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! BSP Memory Management. //! diff --git a/10_virtual_mem_part1_identity_mapping/src/bsp/raspberrypi/memory/mmu.rs b/10_virtual_mem_part1_identity_mapping/src/bsp/raspberrypi/memory/mmu.rs index ea43f899..6c2414f7 100644 --- a/10_virtual_mem_part1_identity_mapping/src/bsp/raspberrypi/memory/mmu.rs +++ b/10_virtual_mem_part1_identity_mapping/src/bsp/raspberrypi/memory/mmu.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! BSP Memory Management Unit. diff --git a/10_virtual_mem_part1_identity_mapping/src/common.rs b/10_virtual_mem_part1_identity_mapping/src/common.rs index 27679aea..782a5da1 100644 --- a/10_virtual_mem_part1_identity_mapping/src/common.rs +++ b/10_virtual_mem_part1_identity_mapping/src/common.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! General purpose code. diff --git a/10_virtual_mem_part1_identity_mapping/src/console.rs b/10_virtual_mem_part1_identity_mapping/src/console.rs index 02b43df9..a83f86fe 100644 --- a/10_virtual_mem_part1_identity_mapping/src/console.rs +++ b/10_virtual_mem_part1_identity_mapping/src/console.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! System console. diff --git a/10_virtual_mem_part1_identity_mapping/src/console/null_console.rs b/10_virtual_mem_part1_identity_mapping/src/console/null_console.rs index 2c64d499..e92a022b 100644 --- a/10_virtual_mem_part1_identity_mapping/src/console/null_console.rs +++ b/10_virtual_mem_part1_identity_mapping/src/console/null_console.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2022 Andre Richter +// Copyright (c) 2022-2023 Andre Richter //! Null console. diff --git a/10_virtual_mem_part1_identity_mapping/src/cpu.rs b/10_virtual_mem_part1_identity_mapping/src/cpu.rs index 62503fb4..67ab79c0 100644 --- a/10_virtual_mem_part1_identity_mapping/src/cpu.rs +++ b/10_virtual_mem_part1_identity_mapping/src/cpu.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Processor code. diff --git a/10_virtual_mem_part1_identity_mapping/src/cpu/boot.rs b/10_virtual_mem_part1_identity_mapping/src/cpu/boot.rs index 8091dac3..b1e98328 100644 --- a/10_virtual_mem_part1_identity_mapping/src/cpu/boot.rs +++ b/10_virtual_mem_part1_identity_mapping/src/cpu/boot.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2021-2022 Andre Richter +// Copyright (c) 2021-2023 Andre Richter //! Boot code. diff --git a/10_virtual_mem_part1_identity_mapping/src/driver.rs b/10_virtual_mem_part1_identity_mapping/src/driver.rs index a798c86d..050e7022 100644 --- a/10_virtual_mem_part1_identity_mapping/src/driver.rs +++ b/10_virtual_mem_part1_identity_mapping/src/driver.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Driver support. diff --git a/10_virtual_mem_part1_identity_mapping/src/exception.rs b/10_virtual_mem_part1_identity_mapping/src/exception.rs index d5f2e68e..45760391 100644 --- a/10_virtual_mem_part1_identity_mapping/src/exception.rs +++ b/10_virtual_mem_part1_identity_mapping/src/exception.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Synchronous and asynchronous exception handling. diff --git a/10_virtual_mem_part1_identity_mapping/src/exception/asynchronous.rs b/10_virtual_mem_part1_identity_mapping/src/exception/asynchronous.rs index bad85779..fd059326 100644 --- a/10_virtual_mem_part1_identity_mapping/src/exception/asynchronous.rs +++ b/10_virtual_mem_part1_identity_mapping/src/exception/asynchronous.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Asynchronous exception handling. diff --git a/10_virtual_mem_part1_identity_mapping/src/main.rs b/10_virtual_mem_part1_identity_mapping/src/main.rs index b40a37bf..52ce7d98 100644 --- a/10_virtual_mem_part1_identity_mapping/src/main.rs +++ b/10_virtual_mem_part1_identity_mapping/src/main.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter // Rust embedded logo for `make doc`. #![doc( diff --git a/10_virtual_mem_part1_identity_mapping/src/memory.rs b/10_virtual_mem_part1_identity_mapping/src/memory.rs index ac6663b3..6dd8f186 100644 --- a/10_virtual_mem_part1_identity_mapping/src/memory.rs +++ b/10_virtual_mem_part1_identity_mapping/src/memory.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Memory Management. diff --git a/10_virtual_mem_part1_identity_mapping/src/memory/mmu.rs b/10_virtual_mem_part1_identity_mapping/src/memory/mmu.rs index bef4c1d1..87ed1efb 100644 --- a/10_virtual_mem_part1_identity_mapping/src/memory/mmu.rs +++ b/10_virtual_mem_part1_identity_mapping/src/memory/mmu.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Memory Management Unit. //! diff --git a/10_virtual_mem_part1_identity_mapping/src/memory/mmu/translation_table.rs b/10_virtual_mem_part1_identity_mapping/src/memory/mmu/translation_table.rs index 88e3fe48..1a2581aa 100644 --- a/10_virtual_mem_part1_identity_mapping/src/memory/mmu/translation_table.rs +++ b/10_virtual_mem_part1_identity_mapping/src/memory/mmu/translation_table.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2021-2022 Andre Richter +// Copyright (c) 2021-2023 Andre Richter //! Translation table. diff --git a/10_virtual_mem_part1_identity_mapping/src/panic_wait.rs b/10_virtual_mem_part1_identity_mapping/src/panic_wait.rs index ccf54f61..5776aca8 100644 --- a/10_virtual_mem_part1_identity_mapping/src/panic_wait.rs +++ b/10_virtual_mem_part1_identity_mapping/src/panic_wait.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! A panic handler that infinitely waits. diff --git a/10_virtual_mem_part1_identity_mapping/src/print.rs b/10_virtual_mem_part1_identity_mapping/src/print.rs index fe13b334..8e303046 100644 --- a/10_virtual_mem_part1_identity_mapping/src/print.rs +++ b/10_virtual_mem_part1_identity_mapping/src/print.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Printing. diff --git a/10_virtual_mem_part1_identity_mapping/src/synchronization.rs b/10_virtual_mem_part1_identity_mapping/src/synchronization.rs index d3937b0d..94c83de1 100644 --- a/10_virtual_mem_part1_identity_mapping/src/synchronization.rs +++ b/10_virtual_mem_part1_identity_mapping/src/synchronization.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Synchronization primitives. //! diff --git a/10_virtual_mem_part1_identity_mapping/src/time.rs b/10_virtual_mem_part1_identity_mapping/src/time.rs index a6c0c5b6..a9d50120 100644 --- a/10_virtual_mem_part1_identity_mapping/src/time.rs +++ b/10_virtual_mem_part1_identity_mapping/src/time.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Timer primitives. diff --git a/11_exceptions_part1_groundwork/.vscode/settings.json b/11_exceptions_part1_groundwork/.vscode/settings.json index d1916456..bfa278e9 100644 --- a/11_exceptions_part1_groundwork/.vscode/settings.json +++ b/11_exceptions_part1_groundwork/.vscode/settings.json @@ -1,10 +1,10 @@ { - "editor.formatOnSave": true, - "editor.rulers": [100], - "rust-analyzer.cargo.target": "aarch64-unknown-none-softfloat", - "rust-analyzer.cargo.features": ["bsp_rpi3"], - "rust-analyzer.checkOnSave.allTargets": false, - "rust-analyzer.checkOnSave.extraArgs": ["--bins"], - "rust-analyzer.lens.debug": false, - "rust-analyzer.lens.run": false + "editor.formatOnSave": true, + "editor.rulers": [100], + "rust-analyzer.cargo.target": "aarch64-unknown-none-softfloat", + "rust-analyzer.cargo.features": ["bsp_rpi3"], + "rust-analyzer.checkOnSave.allTargets": false, + "rust-analyzer.checkOnSave.extraArgs": ["--bins"], + "rust-analyzer.lens.debug": false, + "rust-analyzer.lens.run": false } diff --git a/11_exceptions_part1_groundwork/Makefile b/11_exceptions_part1_groundwork/Makefile index 125f75cb..9549f092 100644 --- a/11_exceptions_part1_groundwork/Makefile +++ b/11_exceptions_part1_groundwork/Makefile @@ -1,6 +1,6 @@ ## SPDX-License-Identifier: MIT OR Apache-2.0 ## -## Copyright (c) 2018-2022 Andre Richter +## Copyright (c) 2018-2023 Andre Richter include ../common/docker.mk include ../common/format.mk diff --git a/11_exceptions_part1_groundwork/README.md b/11_exceptions_part1_groundwork/README.md index 0a9cc9fc..7de4e306 100644 --- a/11_exceptions_part1_groundwork/README.md +++ b/11_exceptions_part1_groundwork/README.md @@ -800,7 +800,7 @@ diff -uNr 10_virtual_mem_part1_identity_mapping/src/_arch/aarch64/exception.s 11 @@ -0,0 +1,154 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// -+// Copyright (c) 2018-2022 Andre Richter ++// Copyright (c) 2018-2023 Andre Richter + +//-------------------------------------------------------------------------------------------------- +// Definitions diff --git a/11_exceptions_part1_groundwork/src/_arch/aarch64/cpu.rs b/11_exceptions_part1_groundwork/src/_arch/aarch64/cpu.rs index bbe7687a..602c9789 100644 --- a/11_exceptions_part1_groundwork/src/_arch/aarch64/cpu.rs +++ b/11_exceptions_part1_groundwork/src/_arch/aarch64/cpu.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Architectural processor code. //! diff --git a/11_exceptions_part1_groundwork/src/_arch/aarch64/cpu/boot.rs b/11_exceptions_part1_groundwork/src/_arch/aarch64/cpu/boot.rs index b458f0db..c80f3ebb 100644 --- a/11_exceptions_part1_groundwork/src/_arch/aarch64/cpu/boot.rs +++ b/11_exceptions_part1_groundwork/src/_arch/aarch64/cpu/boot.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2021-2022 Andre Richter +// Copyright (c) 2021-2023 Andre Richter //! Architectural boot code. //! diff --git a/11_exceptions_part1_groundwork/src/_arch/aarch64/exception.rs b/11_exceptions_part1_groundwork/src/_arch/aarch64/exception.rs index 165e0730..9d2ed5b7 100644 --- a/11_exceptions_part1_groundwork/src/_arch/aarch64/exception.rs +++ b/11_exceptions_part1_groundwork/src/_arch/aarch64/exception.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Architectural synchronous and asynchronous exception handling. //! diff --git a/11_exceptions_part1_groundwork/src/_arch/aarch64/exception/asynchronous.rs b/11_exceptions_part1_groundwork/src/_arch/aarch64/exception/asynchronous.rs index 0347dc3f..65fcad25 100644 --- a/11_exceptions_part1_groundwork/src/_arch/aarch64/exception/asynchronous.rs +++ b/11_exceptions_part1_groundwork/src/_arch/aarch64/exception/asynchronous.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Architectural asynchronous exception handling. //! diff --git a/11_exceptions_part1_groundwork/src/_arch/aarch64/memory/mmu.rs b/11_exceptions_part1_groundwork/src/_arch/aarch64/memory/mmu.rs index e5e2653a..eea4465c 100644 --- a/11_exceptions_part1_groundwork/src/_arch/aarch64/memory/mmu.rs +++ b/11_exceptions_part1_groundwork/src/_arch/aarch64/memory/mmu.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Memory Management Unit Driver. //! diff --git a/11_exceptions_part1_groundwork/src/_arch/aarch64/memory/mmu/translation_table.rs b/11_exceptions_part1_groundwork/src/_arch/aarch64/memory/mmu/translation_table.rs index 057335c4..f3d8f619 100644 --- a/11_exceptions_part1_groundwork/src/_arch/aarch64/memory/mmu/translation_table.rs +++ b/11_exceptions_part1_groundwork/src/_arch/aarch64/memory/mmu/translation_table.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2021-2022 Andre Richter +// Copyright (c) 2021-2023 Andre Richter //! Architectural translation table. //! diff --git a/11_exceptions_part1_groundwork/src/_arch/aarch64/time.rs b/11_exceptions_part1_groundwork/src/_arch/aarch64/time.rs index 94d02379..ee1c3ef7 100644 --- a/11_exceptions_part1_groundwork/src/_arch/aarch64/time.rs +++ b/11_exceptions_part1_groundwork/src/_arch/aarch64/time.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Architectural timer primitives. //! diff --git a/11_exceptions_part1_groundwork/src/bsp.rs b/11_exceptions_part1_groundwork/src/bsp.rs index 824787f6..246973bc 100644 --- a/11_exceptions_part1_groundwork/src/bsp.rs +++ b/11_exceptions_part1_groundwork/src/bsp.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Conditional reexporting of Board Support Packages. diff --git a/11_exceptions_part1_groundwork/src/bsp/device_driver.rs b/11_exceptions_part1_groundwork/src/bsp/device_driver.rs index 6e9bf8f3..64049a4c 100644 --- a/11_exceptions_part1_groundwork/src/bsp/device_driver.rs +++ b/11_exceptions_part1_groundwork/src/bsp/device_driver.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Device driver. diff --git a/11_exceptions_part1_groundwork/src/bsp/device_driver/bcm.rs b/11_exceptions_part1_groundwork/src/bsp/device_driver/bcm.rs index b4b7906e..1c343d1d 100644 --- a/11_exceptions_part1_groundwork/src/bsp/device_driver/bcm.rs +++ b/11_exceptions_part1_groundwork/src/bsp/device_driver/bcm.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! BCM driver top level. diff --git a/11_exceptions_part1_groundwork/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs b/11_exceptions_part1_groundwork/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs index 24e537cf..8e57dfed 100644 --- a/11_exceptions_part1_groundwork/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs +++ b/11_exceptions_part1_groundwork/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! GPIO Driver. diff --git a/11_exceptions_part1_groundwork/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs b/11_exceptions_part1_groundwork/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs index b034e92e..d92612ea 100644 --- a/11_exceptions_part1_groundwork/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs +++ b/11_exceptions_part1_groundwork/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! PL011 UART driver. //! diff --git a/11_exceptions_part1_groundwork/src/bsp/device_driver/common.rs b/11_exceptions_part1_groundwork/src/bsp/device_driver/common.rs index fd9e988e..dfe7d8ef 100644 --- a/11_exceptions_part1_groundwork/src/bsp/device_driver/common.rs +++ b/11_exceptions_part1_groundwork/src/bsp/device_driver/common.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Common device driver code. diff --git a/11_exceptions_part1_groundwork/src/bsp/raspberrypi.rs b/11_exceptions_part1_groundwork/src/bsp/raspberrypi.rs index fe940677..3ea864dc 100644 --- a/11_exceptions_part1_groundwork/src/bsp/raspberrypi.rs +++ b/11_exceptions_part1_groundwork/src/bsp/raspberrypi.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Top-level BSP file for the Raspberry Pi 3 and 4. diff --git a/11_exceptions_part1_groundwork/src/bsp/raspberrypi/cpu.rs b/11_exceptions_part1_groundwork/src/bsp/raspberrypi/cpu.rs index 85fb89e4..65cf5abb 100644 --- a/11_exceptions_part1_groundwork/src/bsp/raspberrypi/cpu.rs +++ b/11_exceptions_part1_groundwork/src/bsp/raspberrypi/cpu.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! BSP Processor code. diff --git a/11_exceptions_part1_groundwork/src/bsp/raspberrypi/driver.rs b/11_exceptions_part1_groundwork/src/bsp/raspberrypi/driver.rs index ea843066..2a80ee2c 100644 --- a/11_exceptions_part1_groundwork/src/bsp/raspberrypi/driver.rs +++ b/11_exceptions_part1_groundwork/src/bsp/raspberrypi/driver.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! BSP driver support. diff --git a/11_exceptions_part1_groundwork/src/bsp/raspberrypi/memory.rs b/11_exceptions_part1_groundwork/src/bsp/raspberrypi/memory.rs index 7a57b618..661476f4 100644 --- a/11_exceptions_part1_groundwork/src/bsp/raspberrypi/memory.rs +++ b/11_exceptions_part1_groundwork/src/bsp/raspberrypi/memory.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! BSP Memory Management. //! diff --git a/11_exceptions_part1_groundwork/src/bsp/raspberrypi/memory/mmu.rs b/11_exceptions_part1_groundwork/src/bsp/raspberrypi/memory/mmu.rs index 2b3a609b..6009ace4 100644 --- a/11_exceptions_part1_groundwork/src/bsp/raspberrypi/memory/mmu.rs +++ b/11_exceptions_part1_groundwork/src/bsp/raspberrypi/memory/mmu.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! BSP Memory Management Unit. diff --git a/11_exceptions_part1_groundwork/src/common.rs b/11_exceptions_part1_groundwork/src/common.rs index 27679aea..782a5da1 100644 --- a/11_exceptions_part1_groundwork/src/common.rs +++ b/11_exceptions_part1_groundwork/src/common.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! General purpose code. diff --git a/11_exceptions_part1_groundwork/src/console.rs b/11_exceptions_part1_groundwork/src/console.rs index 02b43df9..a83f86fe 100644 --- a/11_exceptions_part1_groundwork/src/console.rs +++ b/11_exceptions_part1_groundwork/src/console.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! System console. diff --git a/11_exceptions_part1_groundwork/src/console/null_console.rs b/11_exceptions_part1_groundwork/src/console/null_console.rs index 2c64d499..e92a022b 100644 --- a/11_exceptions_part1_groundwork/src/console/null_console.rs +++ b/11_exceptions_part1_groundwork/src/console/null_console.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2022 Andre Richter +// Copyright (c) 2022-2023 Andre Richter //! Null console. diff --git a/11_exceptions_part1_groundwork/src/cpu.rs b/11_exceptions_part1_groundwork/src/cpu.rs index 62503fb4..67ab79c0 100644 --- a/11_exceptions_part1_groundwork/src/cpu.rs +++ b/11_exceptions_part1_groundwork/src/cpu.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Processor code. diff --git a/11_exceptions_part1_groundwork/src/cpu/boot.rs b/11_exceptions_part1_groundwork/src/cpu/boot.rs index 8091dac3..b1e98328 100644 --- a/11_exceptions_part1_groundwork/src/cpu/boot.rs +++ b/11_exceptions_part1_groundwork/src/cpu/boot.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2021-2022 Andre Richter +// Copyright (c) 2021-2023 Andre Richter //! Boot code. diff --git a/11_exceptions_part1_groundwork/src/driver.rs b/11_exceptions_part1_groundwork/src/driver.rs index a798c86d..050e7022 100644 --- a/11_exceptions_part1_groundwork/src/driver.rs +++ b/11_exceptions_part1_groundwork/src/driver.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Driver support. diff --git a/11_exceptions_part1_groundwork/src/exception.rs b/11_exceptions_part1_groundwork/src/exception.rs index 97fbad6c..77b58248 100644 --- a/11_exceptions_part1_groundwork/src/exception.rs +++ b/11_exceptions_part1_groundwork/src/exception.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Synchronous and asynchronous exception handling. diff --git a/11_exceptions_part1_groundwork/src/exception/asynchronous.rs b/11_exceptions_part1_groundwork/src/exception/asynchronous.rs index bad85779..fd059326 100644 --- a/11_exceptions_part1_groundwork/src/exception/asynchronous.rs +++ b/11_exceptions_part1_groundwork/src/exception/asynchronous.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Asynchronous exception handling. diff --git a/11_exceptions_part1_groundwork/src/main.rs b/11_exceptions_part1_groundwork/src/main.rs index 9d300bf0..fc01bb3b 100644 --- a/11_exceptions_part1_groundwork/src/main.rs +++ b/11_exceptions_part1_groundwork/src/main.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter // Rust embedded logo for `make doc`. #![doc( diff --git a/11_exceptions_part1_groundwork/src/memory.rs b/11_exceptions_part1_groundwork/src/memory.rs index ac6663b3..6dd8f186 100644 --- a/11_exceptions_part1_groundwork/src/memory.rs +++ b/11_exceptions_part1_groundwork/src/memory.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Memory Management. diff --git a/11_exceptions_part1_groundwork/src/memory/mmu.rs b/11_exceptions_part1_groundwork/src/memory/mmu.rs index bef4c1d1..87ed1efb 100644 --- a/11_exceptions_part1_groundwork/src/memory/mmu.rs +++ b/11_exceptions_part1_groundwork/src/memory/mmu.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Memory Management Unit. //! diff --git a/11_exceptions_part1_groundwork/src/memory/mmu/translation_table.rs b/11_exceptions_part1_groundwork/src/memory/mmu/translation_table.rs index 88e3fe48..1a2581aa 100644 --- a/11_exceptions_part1_groundwork/src/memory/mmu/translation_table.rs +++ b/11_exceptions_part1_groundwork/src/memory/mmu/translation_table.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2021-2022 Andre Richter +// Copyright (c) 2021-2023 Andre Richter //! Translation table. diff --git a/11_exceptions_part1_groundwork/src/panic_wait.rs b/11_exceptions_part1_groundwork/src/panic_wait.rs index ccf54f61..5776aca8 100644 --- a/11_exceptions_part1_groundwork/src/panic_wait.rs +++ b/11_exceptions_part1_groundwork/src/panic_wait.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! A panic handler that infinitely waits. diff --git a/11_exceptions_part1_groundwork/src/print.rs b/11_exceptions_part1_groundwork/src/print.rs index fe13b334..8e303046 100644 --- a/11_exceptions_part1_groundwork/src/print.rs +++ b/11_exceptions_part1_groundwork/src/print.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Printing. diff --git a/11_exceptions_part1_groundwork/src/synchronization.rs b/11_exceptions_part1_groundwork/src/synchronization.rs index d3937b0d..94c83de1 100644 --- a/11_exceptions_part1_groundwork/src/synchronization.rs +++ b/11_exceptions_part1_groundwork/src/synchronization.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Synchronization primitives. //! diff --git a/11_exceptions_part1_groundwork/src/time.rs b/11_exceptions_part1_groundwork/src/time.rs index a6c0c5b6..a9d50120 100644 --- a/11_exceptions_part1_groundwork/src/time.rs +++ b/11_exceptions_part1_groundwork/src/time.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Timer primitives. diff --git a/12_integrated_testing/.vscode/settings.json b/12_integrated_testing/.vscode/settings.json index 292bf2a9..9ef30cd0 100644 --- a/12_integrated_testing/.vscode/settings.json +++ b/12_integrated_testing/.vscode/settings.json @@ -1,10 +1,10 @@ { - "editor.formatOnSave": true, - "editor.rulers": [100], - "rust-analyzer.cargo.target": "aarch64-unknown-none-softfloat", - "rust-analyzer.cargo.features": ["bsp_rpi3"], - "rust-analyzer.checkOnSave.allTargets": false, - "rust-analyzer.checkOnSave.extraArgs": ["--lib", "--bins"], - "rust-analyzer.lens.debug": false, - "rust-analyzer.lens.run": false + "editor.formatOnSave": true, + "editor.rulers": [100], + "rust-analyzer.cargo.target": "aarch64-unknown-none-softfloat", + "rust-analyzer.cargo.features": ["bsp_rpi3"], + "rust-analyzer.checkOnSave.allTargets": false, + "rust-analyzer.checkOnSave.extraArgs": ["--lib", "--bins"], + "rust-analyzer.lens.debug": false, + "rust-analyzer.lens.run": false } diff --git a/12_integrated_testing/Makefile b/12_integrated_testing/Makefile index 88d106f8..4e2efeff 100644 --- a/12_integrated_testing/Makefile +++ b/12_integrated_testing/Makefile @@ -1,6 +1,6 @@ ## SPDX-License-Identifier: MIT OR Apache-2.0 ## -## Copyright (c) 2018-2022 Andre Richter +## Copyright (c) 2018-2023 Andre Richter include ../common/docker.mk include ../common/format.mk diff --git a/12_integrated_testing/kernel/src/_arch/aarch64/cpu.rs b/12_integrated_testing/kernel/src/_arch/aarch64/cpu.rs index 7eb7f010..2d010473 100644 --- a/12_integrated_testing/kernel/src/_arch/aarch64/cpu.rs +++ b/12_integrated_testing/kernel/src/_arch/aarch64/cpu.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Architectural processor code. //! diff --git a/12_integrated_testing/kernel/src/_arch/aarch64/cpu/boot.rs b/12_integrated_testing/kernel/src/_arch/aarch64/cpu/boot.rs index b458f0db..c80f3ebb 100644 --- a/12_integrated_testing/kernel/src/_arch/aarch64/cpu/boot.rs +++ b/12_integrated_testing/kernel/src/_arch/aarch64/cpu/boot.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2021-2022 Andre Richter +// Copyright (c) 2021-2023 Andre Richter //! Architectural boot code. //! diff --git a/12_integrated_testing/kernel/src/_arch/aarch64/exception.rs b/12_integrated_testing/kernel/src/_arch/aarch64/exception.rs index 84681bc7..4df4adab 100644 --- a/12_integrated_testing/kernel/src/_arch/aarch64/exception.rs +++ b/12_integrated_testing/kernel/src/_arch/aarch64/exception.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Architectural synchronous and asynchronous exception handling. //! diff --git a/12_integrated_testing/kernel/src/_arch/aarch64/exception/asynchronous.rs b/12_integrated_testing/kernel/src/_arch/aarch64/exception/asynchronous.rs index 0347dc3f..65fcad25 100644 --- a/12_integrated_testing/kernel/src/_arch/aarch64/exception/asynchronous.rs +++ b/12_integrated_testing/kernel/src/_arch/aarch64/exception/asynchronous.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Architectural asynchronous exception handling. //! diff --git a/12_integrated_testing/kernel/src/_arch/aarch64/memory/mmu.rs b/12_integrated_testing/kernel/src/_arch/aarch64/memory/mmu.rs index fbd4992f..99ecaa2b 100644 --- a/12_integrated_testing/kernel/src/_arch/aarch64/memory/mmu.rs +++ b/12_integrated_testing/kernel/src/_arch/aarch64/memory/mmu.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Memory Management Unit Driver. //! diff --git a/12_integrated_testing/kernel/src/_arch/aarch64/memory/mmu/translation_table.rs b/12_integrated_testing/kernel/src/_arch/aarch64/memory/mmu/translation_table.rs index 78776126..5e45a5fd 100644 --- a/12_integrated_testing/kernel/src/_arch/aarch64/memory/mmu/translation_table.rs +++ b/12_integrated_testing/kernel/src/_arch/aarch64/memory/mmu/translation_table.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2021-2022 Andre Richter +// Copyright (c) 2021-2023 Andre Richter //! Architectural translation table. //! diff --git a/12_integrated_testing/kernel/src/_arch/aarch64/time.rs b/12_integrated_testing/kernel/src/_arch/aarch64/time.rs index 94d02379..ee1c3ef7 100644 --- a/12_integrated_testing/kernel/src/_arch/aarch64/time.rs +++ b/12_integrated_testing/kernel/src/_arch/aarch64/time.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Architectural timer primitives. //! diff --git a/12_integrated_testing/kernel/src/bsp.rs b/12_integrated_testing/kernel/src/bsp.rs index 824787f6..246973bc 100644 --- a/12_integrated_testing/kernel/src/bsp.rs +++ b/12_integrated_testing/kernel/src/bsp.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Conditional reexporting of Board Support Packages. diff --git a/12_integrated_testing/kernel/src/bsp/device_driver.rs b/12_integrated_testing/kernel/src/bsp/device_driver.rs index 6e9bf8f3..64049a4c 100644 --- a/12_integrated_testing/kernel/src/bsp/device_driver.rs +++ b/12_integrated_testing/kernel/src/bsp/device_driver.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Device driver. diff --git a/12_integrated_testing/kernel/src/bsp/device_driver/bcm.rs b/12_integrated_testing/kernel/src/bsp/device_driver/bcm.rs index b4b7906e..1c343d1d 100644 --- a/12_integrated_testing/kernel/src/bsp/device_driver/bcm.rs +++ b/12_integrated_testing/kernel/src/bsp/device_driver/bcm.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! BCM driver top level. diff --git a/12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs b/12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs index 24e537cf..8e57dfed 100644 --- a/12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs +++ b/12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! GPIO Driver. diff --git a/12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs b/12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs index b034e92e..d92612ea 100644 --- a/12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs +++ b/12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! PL011 UART driver. //! diff --git a/12_integrated_testing/kernel/src/bsp/device_driver/common.rs b/12_integrated_testing/kernel/src/bsp/device_driver/common.rs index fd9e988e..dfe7d8ef 100644 --- a/12_integrated_testing/kernel/src/bsp/device_driver/common.rs +++ b/12_integrated_testing/kernel/src/bsp/device_driver/common.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Common device driver code. diff --git a/12_integrated_testing/kernel/src/bsp/raspberrypi.rs b/12_integrated_testing/kernel/src/bsp/raspberrypi.rs index fe940677..3ea864dc 100644 --- a/12_integrated_testing/kernel/src/bsp/raspberrypi.rs +++ b/12_integrated_testing/kernel/src/bsp/raspberrypi.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Top-level BSP file for the Raspberry Pi 3 and 4. diff --git a/12_integrated_testing/kernel/src/bsp/raspberrypi/cpu.rs b/12_integrated_testing/kernel/src/bsp/raspberrypi/cpu.rs index 85fb89e4..65cf5abb 100644 --- a/12_integrated_testing/kernel/src/bsp/raspberrypi/cpu.rs +++ b/12_integrated_testing/kernel/src/bsp/raspberrypi/cpu.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! BSP Processor code. diff --git a/12_integrated_testing/kernel/src/bsp/raspberrypi/driver.rs b/12_integrated_testing/kernel/src/bsp/raspberrypi/driver.rs index beaee16b..7ecb48c8 100644 --- a/12_integrated_testing/kernel/src/bsp/raspberrypi/driver.rs +++ b/12_integrated_testing/kernel/src/bsp/raspberrypi/driver.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! BSP driver support. diff --git a/12_integrated_testing/kernel/src/bsp/raspberrypi/memory.rs b/12_integrated_testing/kernel/src/bsp/raspberrypi/memory.rs index 7a57b618..661476f4 100644 --- a/12_integrated_testing/kernel/src/bsp/raspberrypi/memory.rs +++ b/12_integrated_testing/kernel/src/bsp/raspberrypi/memory.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! BSP Memory Management. //! diff --git a/12_integrated_testing/kernel/src/bsp/raspberrypi/memory/mmu.rs b/12_integrated_testing/kernel/src/bsp/raspberrypi/memory/mmu.rs index f8cdc82f..563c8ba9 100644 --- a/12_integrated_testing/kernel/src/bsp/raspberrypi/memory/mmu.rs +++ b/12_integrated_testing/kernel/src/bsp/raspberrypi/memory/mmu.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! BSP Memory Management Unit. diff --git a/12_integrated_testing/kernel/src/common.rs b/12_integrated_testing/kernel/src/common.rs index 27679aea..782a5da1 100644 --- a/12_integrated_testing/kernel/src/common.rs +++ b/12_integrated_testing/kernel/src/common.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! General purpose code. diff --git a/12_integrated_testing/kernel/src/console.rs b/12_integrated_testing/kernel/src/console.rs index 02b43df9..a83f86fe 100644 --- a/12_integrated_testing/kernel/src/console.rs +++ b/12_integrated_testing/kernel/src/console.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! System console. diff --git a/12_integrated_testing/kernel/src/console/null_console.rs b/12_integrated_testing/kernel/src/console/null_console.rs index 2c64d499..cbb7ec7d 100644 --- a/12_integrated_testing/kernel/src/console/null_console.rs +++ b/12_integrated_testing/kernel/src/console/null_console.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2022 Andre Richter +// Copyright (c) 2023 Andre Richter //! Null console. diff --git a/12_integrated_testing/kernel/src/cpu.rs b/12_integrated_testing/kernel/src/cpu.rs index 6d3e9f08..1f6b57f3 100644 --- a/12_integrated_testing/kernel/src/cpu.rs +++ b/12_integrated_testing/kernel/src/cpu.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Processor code. diff --git a/12_integrated_testing/kernel/src/cpu/boot.rs b/12_integrated_testing/kernel/src/cpu/boot.rs index 8091dac3..b1e98328 100644 --- a/12_integrated_testing/kernel/src/cpu/boot.rs +++ b/12_integrated_testing/kernel/src/cpu/boot.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2021-2022 Andre Richter +// Copyright (c) 2021-2023 Andre Richter //! Boot code. diff --git a/12_integrated_testing/kernel/src/driver.rs b/12_integrated_testing/kernel/src/driver.rs index a798c86d..050e7022 100644 --- a/12_integrated_testing/kernel/src/driver.rs +++ b/12_integrated_testing/kernel/src/driver.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Driver support. diff --git a/12_integrated_testing/kernel/src/exception.rs b/12_integrated_testing/kernel/src/exception.rs index 7ea7cd80..3d5f219f 100644 --- a/12_integrated_testing/kernel/src/exception.rs +++ b/12_integrated_testing/kernel/src/exception.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Synchronous and asynchronous exception handling. diff --git a/12_integrated_testing/kernel/src/exception/asynchronous.rs b/12_integrated_testing/kernel/src/exception/asynchronous.rs index bad85779..fd059326 100644 --- a/12_integrated_testing/kernel/src/exception/asynchronous.rs +++ b/12_integrated_testing/kernel/src/exception/asynchronous.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Asynchronous exception handling. diff --git a/12_integrated_testing/kernel/src/lib.rs b/12_integrated_testing/kernel/src/lib.rs index 3f5a846f..16e0b1d0 100644 --- a/12_integrated_testing/kernel/src/lib.rs +++ b/12_integrated_testing/kernel/src/lib.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter // Rust embedded logo for `make doc`. #![doc( diff --git a/12_integrated_testing/kernel/src/main.rs b/12_integrated_testing/kernel/src/main.rs index 9cfcf315..9a8df1d7 100644 --- a/12_integrated_testing/kernel/src/main.rs +++ b/12_integrated_testing/kernel/src/main.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter // Rust embedded logo for `make doc`. #![doc( diff --git a/12_integrated_testing/kernel/src/memory.rs b/12_integrated_testing/kernel/src/memory.rs index ac6663b3..6dd8f186 100644 --- a/12_integrated_testing/kernel/src/memory.rs +++ b/12_integrated_testing/kernel/src/memory.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Memory Management. diff --git a/12_integrated_testing/kernel/src/memory/mmu.rs b/12_integrated_testing/kernel/src/memory/mmu.rs index b313d7d4..7c7fc397 100644 --- a/12_integrated_testing/kernel/src/memory/mmu.rs +++ b/12_integrated_testing/kernel/src/memory/mmu.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Memory Management Unit. //! diff --git a/12_integrated_testing/kernel/src/memory/mmu/translation_table.rs b/12_integrated_testing/kernel/src/memory/mmu/translation_table.rs index 88e3fe48..1a2581aa 100644 --- a/12_integrated_testing/kernel/src/memory/mmu/translation_table.rs +++ b/12_integrated_testing/kernel/src/memory/mmu/translation_table.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2021-2022 Andre Richter +// Copyright (c) 2021-2023 Andre Richter //! Translation table. diff --git a/12_integrated_testing/kernel/src/panic_wait.rs b/12_integrated_testing/kernel/src/panic_wait.rs index da779008..a896ad5e 100644 --- a/12_integrated_testing/kernel/src/panic_wait.rs +++ b/12_integrated_testing/kernel/src/panic_wait.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! A panic handler that infinitely waits. diff --git a/12_integrated_testing/kernel/src/print.rs b/12_integrated_testing/kernel/src/print.rs index fe13b334..8e303046 100644 --- a/12_integrated_testing/kernel/src/print.rs +++ b/12_integrated_testing/kernel/src/print.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Printing. diff --git a/12_integrated_testing/kernel/src/synchronization.rs b/12_integrated_testing/kernel/src/synchronization.rs index d3937b0d..94c83de1 100644 --- a/12_integrated_testing/kernel/src/synchronization.rs +++ b/12_integrated_testing/kernel/src/synchronization.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Synchronization primitives. //! diff --git a/12_integrated_testing/kernel/src/time.rs b/12_integrated_testing/kernel/src/time.rs index a6c0c5b6..a9d50120 100644 --- a/12_integrated_testing/kernel/src/time.rs +++ b/12_integrated_testing/kernel/src/time.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Timer primitives. diff --git a/12_integrated_testing/kernel/tests/00_console_sanity.rb b/12_integrated_testing/kernel/tests/00_console_sanity.rb index 4dde5576..8be7a2f1 100644 --- a/12_integrated_testing/kernel/tests/00_console_sanity.rb +++ b/12_integrated_testing/kernel/tests/00_console_sanity.rb @@ -2,7 +2,7 @@ # SPDX-License-Identifier: MIT OR Apache-2.0 # -# Copyright (c) 2019-2022 Andre Richter +# Copyright (c) 2019-2023 Andre Richter require 'console_io_test' @@ -40,9 +40,9 @@ class RxStatisticsTest < SubtestBase end end -##-------------------------------------------------------------------------------------------------- +## ------------------------------------------------------------------------------------------------- ## Test registration -##-------------------------------------------------------------------------------------------------- +## ------------------------------------------------------------------------------------------------- def subtest_collection [TxRxHandshakeTest.new, TxStatisticsTest.new, RxStatisticsTest.new] end diff --git a/12_integrated_testing/kernel/tests/00_console_sanity.rs b/12_integrated_testing/kernel/tests/00_console_sanity.rs index 69313428..982c6170 100644 --- a/12_integrated_testing/kernel/tests/00_console_sanity.rs +++ b/12_integrated_testing/kernel/tests/00_console_sanity.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2019-2022 Andre Richter +// Copyright (c) 2019-2023 Andre Richter //! Console sanity tests - RX, TX and statistics. diff --git a/12_integrated_testing/kernel/tests/01_timer_sanity.rs b/12_integrated_testing/kernel/tests/01_timer_sanity.rs index b86016b6..3b065f13 100644 --- a/12_integrated_testing/kernel/tests/01_timer_sanity.rs +++ b/12_integrated_testing/kernel/tests/01_timer_sanity.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2019-2022 Andre Richter +// Copyright (c) 2019-2023 Andre Richter //! Timer sanity tests. diff --git a/12_integrated_testing/kernel/tests/02_exception_sync_page_fault.rs b/12_integrated_testing/kernel/tests/02_exception_sync_page_fault.rs index 46501960..bf5b7d71 100644 --- a/12_integrated_testing/kernel/tests/02_exception_sync_page_fault.rs +++ b/12_integrated_testing/kernel/tests/02_exception_sync_page_fault.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2019-2022 Andre Richter +// Copyright (c) 2019-2023 Andre Richter //! Page faults must result in synchronous exceptions. diff --git a/12_integrated_testing/kernel/tests/03_exception_restore_sanity.rb b/12_integrated_testing/kernel/tests/03_exception_restore_sanity.rb index 5f52e0c7..02f51f74 100644 --- a/12_integrated_testing/kernel/tests/03_exception_restore_sanity.rb +++ b/12_integrated_testing/kernel/tests/03_exception_restore_sanity.rb @@ -2,7 +2,7 @@ # SPDX-License-Identifier: MIT OR Apache-2.0 # -# Copyright (c) 2022 Andre Richter +# Copyright (c) 2022-2023 Andre Richter require 'console_io_test' @@ -17,9 +17,9 @@ class ExceptionRestoreTest < SubtestBase end end -##-------------------------------------------------------------------------------------------------- +## ------------------------------------------------------------------------------------------------- ## Test registration -##-------------------------------------------------------------------------------------------------- +## ------------------------------------------------------------------------------------------------- def subtest_collection [ExceptionRestoreTest.new] end diff --git a/12_integrated_testing/kernel/tests/03_exception_restore_sanity.rs b/12_integrated_testing/kernel/tests/03_exception_restore_sanity.rs index cba9285f..e22f4977 100644 --- a/12_integrated_testing/kernel/tests/03_exception_restore_sanity.rs +++ b/12_integrated_testing/kernel/tests/03_exception_restore_sanity.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2022 Andre Richter +// Copyright (c) 2022-2023 Andre Richter //! A simple sanity test to see if exception restore code works. diff --git a/12_integrated_testing/kernel/tests/panic_exit_success/mod.rs b/12_integrated_testing/kernel/tests/panic_exit_success/mod.rs index 908fac51..449ad6f9 100644 --- a/12_integrated_testing/kernel/tests/panic_exit_success/mod.rs +++ b/12_integrated_testing/kernel/tests/panic_exit_success/mod.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2019-2022 Andre Richter +// Copyright (c) 2019-2023 Andre Richter /// Overwrites libkernel's `panic_wait::_panic_exit()` with the QEMU-exit version. #[no_mangle] diff --git a/12_integrated_testing/kernel/tests/panic_wait_forever/mod.rs b/12_integrated_testing/kernel/tests/panic_wait_forever/mod.rs index 7a4effa5..9ac19144 100644 --- a/12_integrated_testing/kernel/tests/panic_wait_forever/mod.rs +++ b/12_integrated_testing/kernel/tests/panic_wait_forever/mod.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2022 Andre Richter +// Copyright (c) 2022-2023 Andre Richter /// Overwrites libkernel's `panic_wait::_panic_exit()` with wait_forever. #[no_mangle] diff --git a/12_integrated_testing/libraries/test-macros/src/lib.rs b/12_integrated_testing/libraries/test-macros/src/lib.rs index 9879677c..52cf893d 100644 --- a/12_integrated_testing/libraries/test-macros/src/lib.rs +++ b/12_integrated_testing/libraries/test-macros/src/lib.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2019-2022 Andre Richter +// Copyright (c) 2019-2023 Andre Richter use proc_macro::TokenStream; use proc_macro2::Span; diff --git a/12_integrated_testing/libraries/test-types/src/lib.rs b/12_integrated_testing/libraries/test-types/src/lib.rs index 922c2a1c..38961a9c 100644 --- a/12_integrated_testing/libraries/test-types/src/lib.rs +++ b/12_integrated_testing/libraries/test-types/src/lib.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2019-2022 Andre Richter +// Copyright (c) 2019-2023 Andre Richter //! Types for the `custom_test_frameworks` implementation. diff --git a/13_exceptions_part2_peripheral_IRQs/.vscode/settings.json b/13_exceptions_part2_peripheral_IRQs/.vscode/settings.json index 292bf2a9..9ef30cd0 100644 --- a/13_exceptions_part2_peripheral_IRQs/.vscode/settings.json +++ b/13_exceptions_part2_peripheral_IRQs/.vscode/settings.json @@ -1,10 +1,10 @@ { - "editor.formatOnSave": true, - "editor.rulers": [100], - "rust-analyzer.cargo.target": "aarch64-unknown-none-softfloat", - "rust-analyzer.cargo.features": ["bsp_rpi3"], - "rust-analyzer.checkOnSave.allTargets": false, - "rust-analyzer.checkOnSave.extraArgs": ["--lib", "--bins"], - "rust-analyzer.lens.debug": false, - "rust-analyzer.lens.run": false + "editor.formatOnSave": true, + "editor.rulers": [100], + "rust-analyzer.cargo.target": "aarch64-unknown-none-softfloat", + "rust-analyzer.cargo.features": ["bsp_rpi3"], + "rust-analyzer.checkOnSave.allTargets": false, + "rust-analyzer.checkOnSave.extraArgs": ["--lib", "--bins"], + "rust-analyzer.lens.debug": false, + "rust-analyzer.lens.run": false } diff --git a/13_exceptions_part2_peripheral_IRQs/Makefile b/13_exceptions_part2_peripheral_IRQs/Makefile index 88d106f8..4e2efeff 100644 --- a/13_exceptions_part2_peripheral_IRQs/Makefile +++ b/13_exceptions_part2_peripheral_IRQs/Makefile @@ -1,6 +1,6 @@ ## SPDX-License-Identifier: MIT OR Apache-2.0 ## -## Copyright (c) 2018-2022 Andre Richter +## Copyright (c) 2018-2023 Andre Richter include ../common/docker.mk include ../common/format.mk diff --git a/13_exceptions_part2_peripheral_IRQs/README.md b/13_exceptions_part2_peripheral_IRQs/README.md index 944001e7..5be65914 100644 --- a/13_exceptions_part2_peripheral_IRQs/README.md +++ b/13_exceptions_part2_peripheral_IRQs/README.md @@ -791,7 +791,7 @@ diff -uNr 12_integrated_testing/kernel/src/_arch/aarch64/cpu/smp.rs 13_exception @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// -+// Copyright (c) 2018-2022 Andre Richter ++// Copyright (c) 2018-2023 Andre Richter + +//! Architectural symmetric multiprocessing. +//! @@ -934,7 +934,7 @@ diff -uNr 12_integrated_testing/kernel/src/bsp/device_driver/arm/gicv2/gicc.rs 1 @@ -0,0 +1,141 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// -+// Copyright (c) 2020-2022 Andre Richter ++// Copyright (c) 2020-2023 Andre Richter + +//! GICC Driver - GIC CPU interface. + @@ -1080,7 +1080,7 @@ diff -uNr 12_integrated_testing/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs 1 @@ -0,0 +1,199 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// -+// Copyright (c) 2020-2022 Andre Richter ++// Copyright (c) 2020-2023 Andre Richter + +//! GICD Driver - GIC Distributor. +//! @@ -1284,7 +1284,7 @@ diff -uNr 12_integrated_testing/kernel/src/bsp/device_driver/arm/gicv2.rs 13_exc @@ -0,0 +1,226 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// -+// Copyright (c) 2020-2022 Andre Richter ++// Copyright (c) 2020-2023 Andre Richter + +//! GICv2 Driver - ARM Generic Interrupt Controller v2. +//! @@ -1515,7 +1515,7 @@ diff -uNr 12_integrated_testing/kernel/src/bsp/device_driver/arm.rs 13_exception @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// -+// Copyright (c) 2020-2022 Andre Richter ++// Copyright (c) 2020-2023 Andre Richter + +//! ARM driver top level. + @@ -1571,7 +1571,7 @@ diff -uNr 12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_interru @@ -0,0 +1,170 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// -+// Copyright (c) 2020-2022 Andre Richter ++// Copyright (c) 2020-2023 Andre Richter + +//! Peripheral Interrupt Controller Driver. +//! @@ -1746,7 +1746,7 @@ diff -uNr 12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_interru @@ -0,0 +1,152 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// -+// Copyright (c) 2020-2022 Andre Richter ++// Copyright (c) 2020-2023 Andre Richter + +//! Interrupt Controller Driver. + @@ -2247,7 +2247,7 @@ diff -uNr 12_integrated_testing/kernel/src/bsp/raspberrypi/exception/asynchronou @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// -+// Copyright (c) 2020-2022 Andre Richter ++// Copyright (c) 2020-2023 Andre Richter + +//! BSP asynchronous exception handling. + @@ -2280,7 +2280,7 @@ diff -uNr 12_integrated_testing/kernel/src/bsp/raspberrypi/exception.rs 13_excep @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// -+// Copyright (c) 2020-2022 Andre Richter ++// Copyright (c) 2020-2023 Andre Richter + +//! BSP synchronous and asynchronous exception handling. + @@ -2374,7 +2374,7 @@ diff -uNr 12_integrated_testing/kernel/src/cpu/smp.rs 13_exceptions_part2_periph @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// -+// Copyright (c) 2018-2022 Andre Richter ++// Copyright (c) 2018-2023 Andre Richter + +//! Symmetric multiprocessing. + @@ -2611,7 +2611,7 @@ diff -uNr 12_integrated_testing/kernel/src/exception/asynchronous/null_irq_manag @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// -+// Copyright (c) 2022 Andre Richter ++// Copyright (c) 2022-2023 Andre Richter + +//! Null IRQ Manager. + @@ -2946,7 +2946,7 @@ diff -uNr 12_integrated_testing/kernel/src/state.rs 13_exceptions_part2_peripher @@ -0,0 +1,92 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// -+// Copyright (c) 2020-2022 Andre Richter ++// Copyright (c) 2020-2023 Andre Richter + +//! State information about the kernel itself. + @@ -3178,7 +3178,7 @@ diff -uNr 12_integrated_testing/kernel/tests/04_exception_irq_sanity.rs 13_excep @@ -0,0 +1,66 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// -+// Copyright (c) 2020-2022 Andre Richter ++// Copyright (c) 2020-2023 Andre Richter + +//! IRQ handling sanity tests. + diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/cpu.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/cpu.rs index 7eb7f010..2d010473 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/cpu.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/cpu.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Architectural processor code. //! diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/cpu/boot.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/cpu/boot.rs index b458f0db..c80f3ebb 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/cpu/boot.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/cpu/boot.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2021-2022 Andre Richter +// Copyright (c) 2021-2023 Andre Richter //! Architectural boot code. //! diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/cpu/smp.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/cpu/smp.rs index 9d304d65..49192038 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/cpu/smp.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/cpu/smp.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Architectural symmetric multiprocessing. //! diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/exception.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/exception.rs index 71831178..73019800 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/exception.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/exception.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Architectural synchronous and asynchronous exception handling. //! diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/exception/asynchronous.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/exception/asynchronous.rs index f545a3e1..811ef138 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/exception/asynchronous.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/exception/asynchronous.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Architectural asynchronous exception handling. //! diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/memory/mmu.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/memory/mmu.rs index fbd4992f..99ecaa2b 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/memory/mmu.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/memory/mmu.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Memory Management Unit Driver. //! diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/memory/mmu/translation_table.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/memory/mmu/translation_table.rs index 78776126..5e45a5fd 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/memory/mmu/translation_table.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/memory/mmu/translation_table.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2021-2022 Andre Richter +// Copyright (c) 2021-2023 Andre Richter //! Architectural translation table. //! diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/time.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/time.rs index 94d02379..ee1c3ef7 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/time.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/time.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Architectural timer primitives. //! diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp.rs index 824787f6..246973bc 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Conditional reexporting of Board Support Packages. diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver.rs index eafaf775..2dfaec8d 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Device driver. diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/arm.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/arm.rs index e83e24c9..8d1cbfbd 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/arm.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/arm.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! ARM driver top level. diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/arm/gicv2.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/arm/gicv2.rs index 2623c305..d8744fec 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/arm/gicv2.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/arm/gicv2.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! GICv2 Driver - ARM Generic Interrupt Controller v2. //! diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/arm/gicv2/gicc.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/arm/gicv2/gicc.rs index 2d2eebc6..ce8ffa72 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/arm/gicv2/gicc.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/arm/gicv2/gicc.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! GICC Driver - GIC CPU interface. diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs index 2d18be9c..1d528ca5 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! GICD Driver - GIC Distributor. //! diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm.rs index 5a7cc23b..7b7c288b 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! BCM driver top level. diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs index 336cc8f7..353bcc8c 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! GPIO Driver. diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs index 22298f1c..dfcbbaa7 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Interrupt Controller Driver. diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs index 1af6f22f..b4c56f44 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Peripheral Interrupt Controller Driver. //! diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs index 71b3e254..fbbbee56 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! PL011 UART driver. //! diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/common.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/common.rs index c368534a..90027e47 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/common.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/common.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Common device driver code. diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi.rs index 474419f4..30421dfa 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Top-level BSP file for the Raspberry Pi 3 and 4. diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/cpu.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/cpu.rs index 85fb89e4..65cf5abb 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/cpu.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/cpu.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! BSP Processor code. diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/driver.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/driver.rs index 91dd6133..d17272dd 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/driver.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/driver.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! BSP driver support. diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/exception.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/exception.rs index aa6c5a63..a9eaa6ac 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/exception.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/exception.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! BSP synchronous and asynchronous exception handling. diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/exception/asynchronous.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/exception/asynchronous.rs index 06a67558..776182fd 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/exception/asynchronous.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/exception/asynchronous.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! BSP asynchronous exception handling. diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/memory.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/memory.rs index be13bb7a..44cefe33 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/memory.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/memory.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! BSP Memory Management. //! diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/memory/mmu.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/memory/mmu.rs index f8cdc82f..563c8ba9 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/memory/mmu.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/memory/mmu.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! BSP Memory Management Unit. diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/common.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/common.rs index 27679aea..782a5da1 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/common.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/common.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! General purpose code. diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/console.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/console.rs index a85bcffe..f0363464 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/console.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/console.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! System console. diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/console/null_console.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/console/null_console.rs index 2c64d499..e92a022b 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/console/null_console.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/console/null_console.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2022 Andre Richter +// Copyright (c) 2022-2023 Andre Richter //! Null console. diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/cpu.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/cpu.rs index e1493d1d..8716a918 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/cpu.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/cpu.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Processor code. diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/cpu/boot.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/cpu/boot.rs index 8091dac3..b1e98328 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/cpu/boot.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/cpu/boot.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2021-2022 Andre Richter +// Copyright (c) 2021-2023 Andre Richter //! Boot code. diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/cpu/smp.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/cpu/smp.rs index 57386f79..de612d58 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/cpu/smp.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/cpu/smp.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Symmetric multiprocessing. diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/driver.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/driver.rs index 18066c31..2edf8b85 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/driver.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/driver.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Driver support. diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/exception.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/exception.rs index 7ea7cd80..3d5f219f 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/exception.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/exception.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Synchronous and asynchronous exception handling. diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/exception/asynchronous.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/exception/asynchronous.rs index c1f2a27b..2c874dd6 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/exception/asynchronous.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/exception/asynchronous.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Asynchronous exception handling. diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/exception/asynchronous/null_irq_manager.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/exception/asynchronous/null_irq_manager.rs index 438f9649..38919ffe 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/exception/asynchronous/null_irq_manager.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/exception/asynchronous/null_irq_manager.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2022 Andre Richter +// Copyright (c) 2022-2023 Andre Richter //! Null IRQ Manager. diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/lib.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/lib.rs index 93b863d7..a8783f6c 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/lib.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/lib.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter // Rust embedded logo for `make doc`. #![doc( diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/main.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/main.rs index d3bdf394..e524322d 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/main.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/main.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter // Rust embedded logo for `make doc`. #![doc( diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/memory.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/memory.rs index ac6663b3..6dd8f186 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/memory.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/memory.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Memory Management. diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/memory/mmu.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/memory/mmu.rs index b313d7d4..7c7fc397 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/memory/mmu.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/memory/mmu.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Memory Management Unit. //! diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/memory/mmu/translation_table.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/memory/mmu/translation_table.rs index 88e3fe48..1a2581aa 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/memory/mmu/translation_table.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/memory/mmu/translation_table.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2021-2022 Andre Richter +// Copyright (c) 2021-2023 Andre Richter //! Translation table. diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/panic_wait.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/panic_wait.rs index ae4651e7..c6f3a9c7 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/panic_wait.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/panic_wait.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! A panic handler that infinitely waits. diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/print.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/print.rs index fe13b334..8e303046 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/print.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/print.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Printing. diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/state.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/state.rs index 0af3688c..6d99beed 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/state.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/state.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! State information about the kernel itself. diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/synchronization.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/synchronization.rs index ab2b86e6..5740b63e 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/synchronization.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/synchronization.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Synchronization primitives. //! diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/time.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/time.rs index a6c0c5b6..a9d50120 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/time.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/time.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Timer primitives. diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/tests/00_console_sanity.rb b/13_exceptions_part2_peripheral_IRQs/kernel/tests/00_console_sanity.rb index 4dde5576..8be7a2f1 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/tests/00_console_sanity.rb +++ b/13_exceptions_part2_peripheral_IRQs/kernel/tests/00_console_sanity.rb @@ -2,7 +2,7 @@ # SPDX-License-Identifier: MIT OR Apache-2.0 # -# Copyright (c) 2019-2022 Andre Richter +# Copyright (c) 2019-2023 Andre Richter require 'console_io_test' @@ -40,9 +40,9 @@ class RxStatisticsTest < SubtestBase end end -##-------------------------------------------------------------------------------------------------- +## ------------------------------------------------------------------------------------------------- ## Test registration -##-------------------------------------------------------------------------------------------------- +## ------------------------------------------------------------------------------------------------- def subtest_collection [TxRxHandshakeTest.new, TxStatisticsTest.new, RxStatisticsTest.new] end diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/tests/00_console_sanity.rs b/13_exceptions_part2_peripheral_IRQs/kernel/tests/00_console_sanity.rs index 69313428..982c6170 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/tests/00_console_sanity.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/tests/00_console_sanity.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2019-2022 Andre Richter +// Copyright (c) 2019-2023 Andre Richter //! Console sanity tests - RX, TX and statistics. diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/tests/01_timer_sanity.rs b/13_exceptions_part2_peripheral_IRQs/kernel/tests/01_timer_sanity.rs index b86016b6..3b065f13 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/tests/01_timer_sanity.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/tests/01_timer_sanity.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2019-2022 Andre Richter +// Copyright (c) 2019-2023 Andre Richter //! Timer sanity tests. diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/tests/02_exception_sync_page_fault.rs b/13_exceptions_part2_peripheral_IRQs/kernel/tests/02_exception_sync_page_fault.rs index 46501960..bf5b7d71 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/tests/02_exception_sync_page_fault.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/tests/02_exception_sync_page_fault.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2019-2022 Andre Richter +// Copyright (c) 2019-2023 Andre Richter //! Page faults must result in synchronous exceptions. diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/tests/03_exception_restore_sanity.rb b/13_exceptions_part2_peripheral_IRQs/kernel/tests/03_exception_restore_sanity.rb index 5f52e0c7..02f51f74 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/tests/03_exception_restore_sanity.rb +++ b/13_exceptions_part2_peripheral_IRQs/kernel/tests/03_exception_restore_sanity.rb @@ -2,7 +2,7 @@ # SPDX-License-Identifier: MIT OR Apache-2.0 # -# Copyright (c) 2022 Andre Richter +# Copyright (c) 2022-2023 Andre Richter require 'console_io_test' @@ -17,9 +17,9 @@ class ExceptionRestoreTest < SubtestBase end end -##-------------------------------------------------------------------------------------------------- +## ------------------------------------------------------------------------------------------------- ## Test registration -##-------------------------------------------------------------------------------------------------- +## ------------------------------------------------------------------------------------------------- def subtest_collection [ExceptionRestoreTest.new] end diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/tests/03_exception_restore_sanity.rs b/13_exceptions_part2_peripheral_IRQs/kernel/tests/03_exception_restore_sanity.rs index cba9285f..e22f4977 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/tests/03_exception_restore_sanity.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/tests/03_exception_restore_sanity.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2022 Andre Richter +// Copyright (c) 2022-2023 Andre Richter //! A simple sanity test to see if exception restore code works. diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/tests/04_exception_irq_sanity.rs b/13_exceptions_part2_peripheral_IRQs/kernel/tests/04_exception_irq_sanity.rs index 8f2b924e..e37896b8 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/tests/04_exception_irq_sanity.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/tests/04_exception_irq_sanity.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! IRQ handling sanity tests. diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/tests/panic_exit_success/mod.rs b/13_exceptions_part2_peripheral_IRQs/kernel/tests/panic_exit_success/mod.rs index 908fac51..449ad6f9 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/tests/panic_exit_success/mod.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/tests/panic_exit_success/mod.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2019-2022 Andre Richter +// Copyright (c) 2019-2023 Andre Richter /// Overwrites libkernel's `panic_wait::_panic_exit()` with the QEMU-exit version. #[no_mangle] diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/tests/panic_wait_forever/mod.rs b/13_exceptions_part2_peripheral_IRQs/kernel/tests/panic_wait_forever/mod.rs index 7a4effa5..9ac19144 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/tests/panic_wait_forever/mod.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/tests/panic_wait_forever/mod.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2022 Andre Richter +// Copyright (c) 2022-2023 Andre Richter /// Overwrites libkernel's `panic_wait::_panic_exit()` with wait_forever. #[no_mangle] diff --git a/13_exceptions_part2_peripheral_IRQs/libraries/test-macros/src/lib.rs b/13_exceptions_part2_peripheral_IRQs/libraries/test-macros/src/lib.rs index 9879677c..52cf893d 100644 --- a/13_exceptions_part2_peripheral_IRQs/libraries/test-macros/src/lib.rs +++ b/13_exceptions_part2_peripheral_IRQs/libraries/test-macros/src/lib.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2019-2022 Andre Richter +// Copyright (c) 2019-2023 Andre Richter use proc_macro::TokenStream; use proc_macro2::Span; diff --git a/13_exceptions_part2_peripheral_IRQs/libraries/test-types/src/lib.rs b/13_exceptions_part2_peripheral_IRQs/libraries/test-types/src/lib.rs index 922c2a1c..38961a9c 100644 --- a/13_exceptions_part2_peripheral_IRQs/libraries/test-types/src/lib.rs +++ b/13_exceptions_part2_peripheral_IRQs/libraries/test-types/src/lib.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2019-2022 Andre Richter +// Copyright (c) 2019-2023 Andre Richter //! Types for the `custom_test_frameworks` implementation. diff --git a/14_virtual_mem_part2_mmio_remap/.vscode/settings.json b/14_virtual_mem_part2_mmio_remap/.vscode/settings.json index 292bf2a9..9ef30cd0 100644 --- a/14_virtual_mem_part2_mmio_remap/.vscode/settings.json +++ b/14_virtual_mem_part2_mmio_remap/.vscode/settings.json @@ -1,10 +1,10 @@ { - "editor.formatOnSave": true, - "editor.rulers": [100], - "rust-analyzer.cargo.target": "aarch64-unknown-none-softfloat", - "rust-analyzer.cargo.features": ["bsp_rpi3"], - "rust-analyzer.checkOnSave.allTargets": false, - "rust-analyzer.checkOnSave.extraArgs": ["--lib", "--bins"], - "rust-analyzer.lens.debug": false, - "rust-analyzer.lens.run": false + "editor.formatOnSave": true, + "editor.rulers": [100], + "rust-analyzer.cargo.target": "aarch64-unknown-none-softfloat", + "rust-analyzer.cargo.features": ["bsp_rpi3"], + "rust-analyzer.checkOnSave.allTargets": false, + "rust-analyzer.checkOnSave.extraArgs": ["--lib", "--bins"], + "rust-analyzer.lens.debug": false, + "rust-analyzer.lens.run": false } diff --git a/14_virtual_mem_part2_mmio_remap/Makefile b/14_virtual_mem_part2_mmio_remap/Makefile index 88d106f8..4e2efeff 100644 --- a/14_virtual_mem_part2_mmio_remap/Makefile +++ b/14_virtual_mem_part2_mmio_remap/Makefile @@ -1,6 +1,6 @@ ## SPDX-License-Identifier: MIT OR Apache-2.0 ## -## Copyright (c) 2018-2022 Andre Richter +## Copyright (c) 2018-2023 Andre Richter include ../common/docker.mk include ../common/format.mk diff --git a/14_virtual_mem_part2_mmio_remap/README.md b/14_virtual_mem_part2_mmio_remap/README.md index 7d16e69c..e21ad501 100644 --- a/14_virtual_mem_part2_mmio_remap/README.md +++ b/14_virtual_mem_part2_mmio_remap/README.md @@ -1928,7 +1928,7 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/memory/mmu/mapping_reco @@ -0,0 +1,238 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// -+// Copyright (c) 2020-2022 Andre Richter ++// Copyright (c) 2020-2023 Andre Richter + +//! A record of mapped pages. + @@ -2171,7 +2171,7 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/memory/mmu/page_alloc.r @@ -0,0 +1,70 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// -+// Copyright (c) 2021-2022 Andre Richter ++// Copyright (c) 2021-2023 Andre Richter + +//! Page allocation. + @@ -2343,7 +2343,7 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/memory/mmu/types.rs 14_ @@ -0,0 +1,373 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// -+// Copyright (c) 2020-2022 Andre Richter ++// Copyright (c) 2020-2023 Andre Richter + +//! Memory Management Unit types. + @@ -2719,7 +2719,7 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/memory/mmu.rs 14_virtua --- 13_exceptions_part2_peripheral_IRQs/kernel/src/memory/mmu.rs +++ 14_virtual_mem_part2_mmio_remap/kernel/src/memory/mmu.rs @@ -3,30 +3,24 @@ - // Copyright (c) 2020-2022 Andre Richter + // Copyright (c) 2020-2023 Andre Richter //! Memory Management Unit. -//! diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/cpu.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/cpu.rs index 7eb7f010..2d010473 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/cpu.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/cpu.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Architectural processor code. //! diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/cpu/boot.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/cpu/boot.rs index b458f0db..c80f3ebb 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/cpu/boot.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/cpu/boot.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2021-2022 Andre Richter +// Copyright (c) 2021-2023 Andre Richter //! Architectural boot code. //! diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/cpu/smp.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/cpu/smp.rs index 9d304d65..49192038 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/cpu/smp.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/cpu/smp.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Architectural symmetric multiprocessing. //! diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/exception.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/exception.rs index 71831178..73019800 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/exception.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/exception.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Architectural synchronous and asynchronous exception handling. //! diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/exception/asynchronous.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/exception/asynchronous.rs index f545a3e1..811ef138 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/exception/asynchronous.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/exception/asynchronous.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Architectural asynchronous exception handling. //! diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/memory/mmu.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/memory/mmu.rs index aaec1925..e0717a7f 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/memory/mmu.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/memory/mmu.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Memory Management Unit Driver. //! diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/memory/mmu/translation_table.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/memory/mmu/translation_table.rs index cc31b302..2d87543c 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/memory/mmu/translation_table.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/memory/mmu/translation_table.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2021-2022 Andre Richter +// Copyright (c) 2021-2023 Andre Richter //! Architectural translation table. //! diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/time.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/time.rs index 94d02379..ee1c3ef7 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/time.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/time.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Architectural timer primitives. //! diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp.rs index 824787f6..246973bc 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Conditional reexporting of Board Support Packages. diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver.rs index eafaf775..2dfaec8d 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Device driver. diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/arm.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/arm.rs index e83e24c9..8d1cbfbd 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/arm.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/arm.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! ARM driver top level. diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/arm/gicv2.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/arm/gicv2.rs index 3cc35b5e..256de704 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/arm/gicv2.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/arm/gicv2.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! GICv2 Driver - ARM Generic Interrupt Controller v2. //! diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/arm/gicv2/gicc.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/arm/gicv2/gicc.rs index 1a02fc65..0fd16bb3 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/arm/gicv2/gicc.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/arm/gicv2/gicc.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! GICC Driver - GIC CPU interface. diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs index 8aebcf2b..1fc9d70e 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! GICD Driver - GIC Distributor. //! diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm.rs index 5a7cc23b..7b7c288b 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! BCM driver top level. diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs index fb61a651..812156f4 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! GPIO Driver. diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs index c93a9fa1..62f07800 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Interrupt Controller Driver. diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs index 0a20bd87..a26bff8d 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Peripheral Interrupt Controller Driver. //! diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs index 0ee7feb7..b424d4be 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! PL011 UART driver. //! diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/common.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/common.rs index ca7aeb76..3ce1d8d8 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/common.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/common.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Common device driver code. diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi.rs index 474419f4..30421dfa 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Top-level BSP file for the Raspberry Pi 3 and 4. diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/cpu.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/cpu.rs index 85fb89e4..65cf5abb 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/cpu.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/cpu.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! BSP Processor code. diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/driver.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/driver.rs index ca3435aa..a1f55b17 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/driver.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/driver.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! BSP driver support. diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/exception.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/exception.rs index aa6c5a63..a9eaa6ac 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/exception.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/exception.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! BSP synchronous and asynchronous exception handling. diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/exception/asynchronous.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/exception/asynchronous.rs index 06a67558..776182fd 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/exception/asynchronous.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/exception/asynchronous.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! BSP asynchronous exception handling. diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/memory.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/memory.rs index 7d6e7911..0d963aa3 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/memory.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/memory.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! BSP Memory Management. //! diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/memory/mmu.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/memory/mmu.rs index 8d395a58..86a118c3 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/memory/mmu.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/memory/mmu.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! BSP Memory Management Unit. diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/common.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/common.rs index f32f650f..2ad7e4c1 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/common.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/common.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! General purpose code. diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/console.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/console.rs index a85bcffe..f0363464 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/console.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/console.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! System console. diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/console/null_console.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/console/null_console.rs index 2c64d499..e92a022b 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/console/null_console.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/console/null_console.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2022 Andre Richter +// Copyright (c) 2022-2023 Andre Richter //! Null console. diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/cpu.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/cpu.rs index e1493d1d..8716a918 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/cpu.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/cpu.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Processor code. diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/cpu/boot.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/cpu/boot.rs index 8091dac3..b1e98328 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/cpu/boot.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/cpu/boot.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2021-2022 Andre Richter +// Copyright (c) 2021-2023 Andre Richter //! Boot code. diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/cpu/smp.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/cpu/smp.rs index 57386f79..de612d58 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/cpu/smp.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/cpu/smp.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Symmetric multiprocessing. diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/driver.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/driver.rs index 18066c31..2edf8b85 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/driver.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/driver.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Driver support. diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/exception.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/exception.rs index 7ea7cd80..3d5f219f 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/exception.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/exception.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Synchronous and asynchronous exception handling. diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/exception/asynchronous.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/exception/asynchronous.rs index c1f2a27b..2c874dd6 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/exception/asynchronous.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/exception/asynchronous.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Asynchronous exception handling. diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/exception/asynchronous/null_irq_manager.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/exception/asynchronous/null_irq_manager.rs index 438f9649..38919ffe 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/exception/asynchronous/null_irq_manager.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/exception/asynchronous/null_irq_manager.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2022 Andre Richter +// Copyright (c) 2022-2023 Andre Richter //! Null IRQ Manager. diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/lib.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/lib.rs index 25f66be3..fef85dfb 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/lib.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/lib.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter // Rust embedded logo for `make doc`. #![doc( diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/main.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/main.rs index 045d1200..b76b003c 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/main.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/main.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter // Rust embedded logo for `make doc`. #![doc( diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/memory.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/memory.rs index 64d8cf64..b2638470 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/memory.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/memory.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Memory Management. diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/memory/mmu.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/memory/mmu.rs index bd1f56ff..20e35def 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/memory/mmu.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/memory/mmu.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Memory Management Unit. diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/memory/mmu/mapping_record.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/memory/mmu/mapping_record.rs index b893fee3..0e079220 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/memory/mmu/mapping_record.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/memory/mmu/mapping_record.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! A record of mapped pages. diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/memory/mmu/page_alloc.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/memory/mmu/page_alloc.rs index 347fcd34..344afd20 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/memory/mmu/page_alloc.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/memory/mmu/page_alloc.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2021-2022 Andre Richter +// Copyright (c) 2021-2023 Andre Richter //! Page allocation. diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/memory/mmu/translation_table.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/memory/mmu/translation_table.rs index 7eb46ebf..0445ab29 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/memory/mmu/translation_table.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/memory/mmu/translation_table.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2021-2022 Andre Richter +// Copyright (c) 2021-2023 Andre Richter //! Translation table. diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/memory/mmu/types.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/memory/mmu/types.rs index 362438fd..8feee064 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/memory/mmu/types.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/memory/mmu/types.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Memory Management Unit types. diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/panic_wait.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/panic_wait.rs index ae4651e7..c6f3a9c7 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/panic_wait.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/panic_wait.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! A panic handler that infinitely waits. diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/print.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/print.rs index fe13b334..8e303046 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/print.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/print.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Printing. diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/state.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/state.rs index 0af3688c..6d99beed 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/state.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/state.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! State information about the kernel itself. diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/synchronization.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/synchronization.rs index ab2b86e6..5740b63e 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/synchronization.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/synchronization.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Synchronization primitives. //! diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/time.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/time.rs index a6c0c5b6..a9d50120 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/time.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/time.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Timer primitives. diff --git a/14_virtual_mem_part2_mmio_remap/kernel/tests/00_console_sanity.rb b/14_virtual_mem_part2_mmio_remap/kernel/tests/00_console_sanity.rb index 4dde5576..8be7a2f1 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/tests/00_console_sanity.rb +++ b/14_virtual_mem_part2_mmio_remap/kernel/tests/00_console_sanity.rb @@ -2,7 +2,7 @@ # SPDX-License-Identifier: MIT OR Apache-2.0 # -# Copyright (c) 2019-2022 Andre Richter +# Copyright (c) 2019-2023 Andre Richter require 'console_io_test' @@ -40,9 +40,9 @@ class RxStatisticsTest < SubtestBase end end -##-------------------------------------------------------------------------------------------------- +## ------------------------------------------------------------------------------------------------- ## Test registration -##-------------------------------------------------------------------------------------------------- +## ------------------------------------------------------------------------------------------------- def subtest_collection [TxRxHandshakeTest.new, TxStatisticsTest.new, RxStatisticsTest.new] end diff --git a/14_virtual_mem_part2_mmio_remap/kernel/tests/00_console_sanity.rs b/14_virtual_mem_part2_mmio_remap/kernel/tests/00_console_sanity.rs index b27822d5..d7409173 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/tests/00_console_sanity.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/tests/00_console_sanity.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2019-2022 Andre Richter +// Copyright (c) 2019-2023 Andre Richter //! Console sanity tests - RX, TX and statistics. diff --git a/14_virtual_mem_part2_mmio_remap/kernel/tests/01_timer_sanity.rs b/14_virtual_mem_part2_mmio_remap/kernel/tests/01_timer_sanity.rs index 691b511d..c0a570e4 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/tests/01_timer_sanity.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/tests/01_timer_sanity.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2019-2022 Andre Richter +// Copyright (c) 2019-2023 Andre Richter //! Timer sanity tests. diff --git a/14_virtual_mem_part2_mmio_remap/kernel/tests/02_exception_sync_page_fault.rs b/14_virtual_mem_part2_mmio_remap/kernel/tests/02_exception_sync_page_fault.rs index c3053961..3abe91fc 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/tests/02_exception_sync_page_fault.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/tests/02_exception_sync_page_fault.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2019-2022 Andre Richter +// Copyright (c) 2019-2023 Andre Richter //! Page faults must result in synchronous exceptions. diff --git a/14_virtual_mem_part2_mmio_remap/kernel/tests/03_exception_restore_sanity.rb b/14_virtual_mem_part2_mmio_remap/kernel/tests/03_exception_restore_sanity.rb index 5f52e0c7..02f51f74 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/tests/03_exception_restore_sanity.rb +++ b/14_virtual_mem_part2_mmio_remap/kernel/tests/03_exception_restore_sanity.rb @@ -2,7 +2,7 @@ # SPDX-License-Identifier: MIT OR Apache-2.0 # -# Copyright (c) 2022 Andre Richter +# Copyright (c) 2022-2023 Andre Richter require 'console_io_test' @@ -17,9 +17,9 @@ class ExceptionRestoreTest < SubtestBase end end -##-------------------------------------------------------------------------------------------------- +## ------------------------------------------------------------------------------------------------- ## Test registration -##-------------------------------------------------------------------------------------------------- +## ------------------------------------------------------------------------------------------------- def subtest_collection [ExceptionRestoreTest.new] end diff --git a/14_virtual_mem_part2_mmio_remap/kernel/tests/03_exception_restore_sanity.rs b/14_virtual_mem_part2_mmio_remap/kernel/tests/03_exception_restore_sanity.rs index 6351e80c..77ec2d41 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/tests/03_exception_restore_sanity.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/tests/03_exception_restore_sanity.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2022 Andre Richter +// Copyright (c) 2022-2023 Andre Richter //! A simple sanity test to see if exception restore code works. diff --git a/14_virtual_mem_part2_mmio_remap/kernel/tests/04_exception_irq_sanity.rs b/14_virtual_mem_part2_mmio_remap/kernel/tests/04_exception_irq_sanity.rs index 35bf51b6..ac7c8ae4 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/tests/04_exception_irq_sanity.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/tests/04_exception_irq_sanity.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! IRQ handling sanity tests. diff --git a/14_virtual_mem_part2_mmio_remap/kernel/tests/panic_exit_success/mod.rs b/14_virtual_mem_part2_mmio_remap/kernel/tests/panic_exit_success/mod.rs index 908fac51..449ad6f9 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/tests/panic_exit_success/mod.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/tests/panic_exit_success/mod.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2019-2022 Andre Richter +// Copyright (c) 2019-2023 Andre Richter /// Overwrites libkernel's `panic_wait::_panic_exit()` with the QEMU-exit version. #[no_mangle] diff --git a/14_virtual_mem_part2_mmio_remap/kernel/tests/panic_wait_forever/mod.rs b/14_virtual_mem_part2_mmio_remap/kernel/tests/panic_wait_forever/mod.rs index 7a4effa5..9ac19144 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/tests/panic_wait_forever/mod.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/tests/panic_wait_forever/mod.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2022 Andre Richter +// Copyright (c) 2022-2023 Andre Richter /// Overwrites libkernel's `panic_wait::_panic_exit()` with wait_forever. #[no_mangle] diff --git a/14_virtual_mem_part2_mmio_remap/libraries/test-macros/src/lib.rs b/14_virtual_mem_part2_mmio_remap/libraries/test-macros/src/lib.rs index 9879677c..52cf893d 100644 --- a/14_virtual_mem_part2_mmio_remap/libraries/test-macros/src/lib.rs +++ b/14_virtual_mem_part2_mmio_remap/libraries/test-macros/src/lib.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2019-2022 Andre Richter +// Copyright (c) 2019-2023 Andre Richter use proc_macro::TokenStream; use proc_macro2::Span; diff --git a/14_virtual_mem_part2_mmio_remap/libraries/test-types/src/lib.rs b/14_virtual_mem_part2_mmio_remap/libraries/test-types/src/lib.rs index 922c2a1c..38961a9c 100644 --- a/14_virtual_mem_part2_mmio_remap/libraries/test-types/src/lib.rs +++ b/14_virtual_mem_part2_mmio_remap/libraries/test-types/src/lib.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2019-2022 Andre Richter +// Copyright (c) 2019-2023 Andre Richter //! Types for the `custom_test_frameworks` implementation. diff --git a/15_virtual_mem_part3_precomputed_tables/.vscode/settings.json b/15_virtual_mem_part3_precomputed_tables/.vscode/settings.json index 292bf2a9..9ef30cd0 100644 --- a/15_virtual_mem_part3_precomputed_tables/.vscode/settings.json +++ b/15_virtual_mem_part3_precomputed_tables/.vscode/settings.json @@ -1,10 +1,10 @@ { - "editor.formatOnSave": true, - "editor.rulers": [100], - "rust-analyzer.cargo.target": "aarch64-unknown-none-softfloat", - "rust-analyzer.cargo.features": ["bsp_rpi3"], - "rust-analyzer.checkOnSave.allTargets": false, - "rust-analyzer.checkOnSave.extraArgs": ["--lib", "--bins"], - "rust-analyzer.lens.debug": false, - "rust-analyzer.lens.run": false + "editor.formatOnSave": true, + "editor.rulers": [100], + "rust-analyzer.cargo.target": "aarch64-unknown-none-softfloat", + "rust-analyzer.cargo.features": ["bsp_rpi3"], + "rust-analyzer.checkOnSave.allTargets": false, + "rust-analyzer.checkOnSave.extraArgs": ["--lib", "--bins"], + "rust-analyzer.lens.debug": false, + "rust-analyzer.lens.run": false } diff --git a/15_virtual_mem_part3_precomputed_tables/Makefile b/15_virtual_mem_part3_precomputed_tables/Makefile index 0f5c4870..bc23270d 100644 --- a/15_virtual_mem_part3_precomputed_tables/Makefile +++ b/15_virtual_mem_part3_precomputed_tables/Makefile @@ -1,6 +1,6 @@ ## SPDX-License-Identifier: MIT OR Apache-2.0 ## -## Copyright (c) 2018-2022 Andre Richter +## Copyright (c) 2018-2023 Andre Richter include ../common/docker.mk include ../common/format.mk diff --git a/15_virtual_mem_part3_precomputed_tables/README.md b/15_virtual_mem_part3_precomputed_tables/README.md index 23210265..3fdc2385 100644 --- a/15_virtual_mem_part3_precomputed_tables/README.md +++ b/15_virtual_mem_part3_precomputed_tables/README.md @@ -637,7 +637,7 @@ def kernel_map_binary mapping_descriptors.each do |i| print 'Generating'.rjust(12).green.bold print ' ' - puts i.to_s + puts i TRANSLATION_TABLES.map_at(i.virt_region, i.phys_region, i.attributes) end @@ -1081,7 +1081,7 @@ diff -uNr 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/kernel.ld 1 --- 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/kernel.ld +++ 15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/kernel.ld @@ -3,6 +3,8 @@ - * Copyright (c) 2018-2022 Andre Richter + * Copyright (c) 2018-2023 Andre Richter */ +INCLUDE kernel_virt_addr_space_size.ld; @@ -1924,7 +1924,7 @@ diff -uNr 14_virtual_mem_part2_mmio_remap/tools/translation_table_tool/arch.rb 1 + +# SPDX-License-Identifier: MIT OR Apache-2.0 +# -+# Copyright (c) 2021-2022 Andre Richter ++# Copyright (c) 2021-2023 Andre Richter + +# Bitfield manipulation. +class BitField @@ -2241,7 +2241,7 @@ diff -uNr 14_virtual_mem_part2_mmio_remap/tools/translation_table_tool/bsp.rb 15 + +# SPDX-License-Identifier: MIT OR Apache-2.0 +# -+# Copyright (c) 2021-2022 Andre Richter ++# Copyright (c) 2021-2023 Andre Richter + +# Raspberry Pi 3 + 4 +class RaspberryPi @@ -2295,7 +2295,7 @@ diff -uNr 14_virtual_mem_part2_mmio_remap/tools/translation_table_tool/generic.r + +# SPDX-License-Identifier: MIT OR Apache-2.0 +# -+# Copyright (c) 2021-2022 Andre Richter ++# Copyright (c) 2021-2023 Andre Richter + +module Granule64KiB + SIZE = 64 * 1024 @@ -2444,7 +2444,7 @@ diff -uNr 14_virtual_mem_part2_mmio_remap/tools/translation_table_tool/generic.r + mapping_descriptors.each do |i| + print 'Generating'.rjust(12).green.bold + print ' ' -+ puts i.to_s ++ puts i + + TRANSLATION_TABLES.map_at(i.virt_region, i.phys_region, i.attributes) + end @@ -2479,7 +2479,7 @@ diff -uNr 14_virtual_mem_part2_mmio_remap/tools/translation_table_tool/kernel_el + +# SPDX-License-Identifier: MIT OR Apache-2.0 +# -+# Copyright (c) 2021-2022 Andre Richter ++# Copyright (c) 2021-2023 Andre Richter + +# KernelELF +class KernelELF @@ -2581,7 +2581,7 @@ diff -uNr 14_virtual_mem_part2_mmio_remap/tools/translation_table_tool/main.rb 1 + +# SPDX-License-Identifier: MIT OR Apache-2.0 +# -+# Copyright (c) 2021-2022 Andre Richter ++# Copyright (c) 2021-2023 Andre Richter + +require 'rubygems' +require 'bundler/setup' diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/Cargo.toml b/15_virtual_mem_part3_precomputed_tables/kernel/Cargo.toml index 73b6feef..a0652b4f 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/Cargo.toml +++ b/15_virtual_mem_part3_precomputed_tables/kernel/Cargo.toml @@ -10,9 +10,9 @@ bsp_rpi3 = ["tock-registers"] bsp_rpi4 = ["tock-registers"] test_build = ["qemu-exit"] -##-------------------------------------------------------------------------------------------------- +##------------------------------------------------------------------------------------------------- ## Dependencies -##-------------------------------------------------------------------------------------------------- +##------------------------------------------------------------------------------------------------- [dependencies] test-types = { path = "../libraries/test-types" } @@ -25,9 +25,9 @@ qemu-exit = { version = "3.x.x", optional = true } [target.'cfg(target_arch = "aarch64")'.dependencies] aarch64-cpu = { version = "9.x.x" } -##-------------------------------------------------------------------------------------------------- +##------------------------------------------------------------------------------------------------- ## Testing -##-------------------------------------------------------------------------------------------------- +##------------------------------------------------------------------------------------------------- [dev-dependencies] test-macros = { path = "../libraries/test-macros" } diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/cpu.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/cpu.rs index 7eb7f010..2d010473 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/cpu.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/cpu.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Architectural processor code. //! diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/cpu/boot.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/cpu/boot.rs index fc70fe7f..b76176df 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/cpu/boot.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/cpu/boot.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2021-2022 Andre Richter +// Copyright (c) 2021-2023 Andre Richter //! Architectural boot code. //! diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/cpu/smp.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/cpu/smp.rs index 9d304d65..49192038 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/cpu/smp.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/cpu/smp.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Architectural symmetric multiprocessing. //! diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/exception.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/exception.rs index 71831178..73019800 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/exception.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/exception.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Architectural synchronous and asynchronous exception handling. //! diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/exception/asynchronous.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/exception/asynchronous.rs index f545a3e1..811ef138 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/exception/asynchronous.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/exception/asynchronous.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Architectural asynchronous exception handling. //! diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/memory/mmu.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/memory/mmu.rs index aaec1925..e0717a7f 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/memory/mmu.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/memory/mmu.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Memory Management Unit Driver. //! diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/memory/mmu/translation_table.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/memory/mmu/translation_table.rs index 53f59216..8cba4cd7 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/memory/mmu/translation_table.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/memory/mmu/translation_table.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2021-2022 Andre Richter +// Copyright (c) 2021-2023 Andre Richter //! Architectural translation table. //! diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/time.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/time.rs index 94d02379..ee1c3ef7 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/time.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/time.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Architectural timer primitives. //! diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp.rs index 824787f6..246973bc 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Conditional reexporting of Board Support Packages. diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver.rs index eafaf775..2dfaec8d 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Device driver. diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/arm.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/arm.rs index e83e24c9..8d1cbfbd 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/arm.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/arm.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! ARM driver top level. diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/arm/gicv2.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/arm/gicv2.rs index 3cc35b5e..256de704 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/arm/gicv2.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/arm/gicv2.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! GICv2 Driver - ARM Generic Interrupt Controller v2. //! diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/arm/gicv2/gicc.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/arm/gicv2/gicc.rs index 1a02fc65..0fd16bb3 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/arm/gicv2/gicc.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/arm/gicv2/gicc.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! GICC Driver - GIC CPU interface. diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs index 8aebcf2b..1fc9d70e 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! GICD Driver - GIC Distributor. //! diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/bcm.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/bcm.rs index 5a7cc23b..7b7c288b 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/bcm.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/bcm.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! BCM driver top level. diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs index fb61a651..812156f4 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! GPIO Driver. diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs index c93a9fa1..62f07800 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Interrupt Controller Driver. diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs index 0a20bd87..a26bff8d 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Peripheral Interrupt Controller Driver. //! diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs index 0ee7feb7..b424d4be 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! PL011 UART driver. //! diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/common.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/common.rs index ca7aeb76..3ce1d8d8 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/common.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/common.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Common device driver code. diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi.rs index 474419f4..30421dfa 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Top-level BSP file for the Raspberry Pi 3 and 4. diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/cpu.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/cpu.rs index 85fb89e4..65cf5abb 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/cpu.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/cpu.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! BSP Processor code. diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/driver.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/driver.rs index ca3435aa..a1f55b17 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/driver.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/driver.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! BSP driver support. diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/exception.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/exception.rs index aa6c5a63..a9eaa6ac 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/exception.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/exception.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! BSP synchronous and asynchronous exception handling. diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/exception/asynchronous.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/exception/asynchronous.rs index 06a67558..776182fd 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/exception/asynchronous.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/exception/asynchronous.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! BSP asynchronous exception handling. diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/memory.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/memory.rs index 7d6e7911..0d963aa3 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/memory.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/memory.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! BSP Memory Management. //! diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/memory/mmu.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/memory/mmu.rs index f78b57d1..ce3d6750 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/memory/mmu.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/memory/mmu.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! BSP Memory Management Unit. diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/common.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/common.rs index f32f650f..2ad7e4c1 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/common.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/common.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! General purpose code. diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/console.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/console.rs index a85bcffe..f0363464 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/console.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/console.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! System console. diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/console/null_console.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/console/null_console.rs index 2c64d499..e92a022b 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/console/null_console.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/console/null_console.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2022 Andre Richter +// Copyright (c) 2022-2023 Andre Richter //! Null console. diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/cpu.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/cpu.rs index e1493d1d..8716a918 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/cpu.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/cpu.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Processor code. diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/cpu/boot.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/cpu/boot.rs index 8091dac3..b1e98328 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/cpu/boot.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/cpu/boot.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2021-2022 Andre Richter +// Copyright (c) 2021-2023 Andre Richter //! Boot code. diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/cpu/smp.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/cpu/smp.rs index 57386f79..de612d58 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/cpu/smp.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/cpu/smp.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Symmetric multiprocessing. diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/driver.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/driver.rs index 18066c31..2edf8b85 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/driver.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/driver.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Driver support. diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/exception.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/exception.rs index 7ea7cd80..3d5f219f 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/exception.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/exception.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Synchronous and asynchronous exception handling. diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/exception/asynchronous.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/exception/asynchronous.rs index c1f2a27b..2c874dd6 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/exception/asynchronous.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/exception/asynchronous.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Asynchronous exception handling. diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/exception/asynchronous/null_irq_manager.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/exception/asynchronous/null_irq_manager.rs index 438f9649..38919ffe 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/exception/asynchronous/null_irq_manager.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/exception/asynchronous/null_irq_manager.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2022 Andre Richter +// Copyright (c) 2022-2023 Andre Richter //! Null IRQ Manager. diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/lib.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/lib.rs index 197b1f41..71350bd0 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/lib.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/lib.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter // Rust embedded logo for `make doc`. #![doc( diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/main.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/main.rs index 65905258..e41cfaa0 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/main.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/main.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter // Rust embedded logo for `make doc`. #![doc( diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/memory.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/memory.rs index 3b6868e7..6131bdb6 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/memory.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/memory.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Memory Management. diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/memory/mmu.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/memory/mmu.rs index 698f2095..f19758c1 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/memory/mmu.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/memory/mmu.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Memory Management Unit. diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/memory/mmu/mapping_record.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/memory/mmu/mapping_record.rs index b893fee3..0e079220 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/memory/mmu/mapping_record.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/memory/mmu/mapping_record.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! A record of mapped pages. diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/memory/mmu/page_alloc.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/memory/mmu/page_alloc.rs index 347fcd34..344afd20 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/memory/mmu/page_alloc.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/memory/mmu/page_alloc.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2021-2022 Andre Richter +// Copyright (c) 2021-2023 Andre Richter //! Page allocation. diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/memory/mmu/translation_table.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/memory/mmu/translation_table.rs index c36fb3d6..41368dae 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/memory/mmu/translation_table.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/memory/mmu/translation_table.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2021-2022 Andre Richter +// Copyright (c) 2021-2023 Andre Richter //! Translation table. diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/memory/mmu/types.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/memory/mmu/types.rs index 362438fd..8feee064 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/memory/mmu/types.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/memory/mmu/types.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Memory Management Unit types. diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/panic_wait.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/panic_wait.rs index ae4651e7..c6f3a9c7 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/panic_wait.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/panic_wait.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! A panic handler that infinitely waits. diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/print.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/print.rs index fe13b334..8e303046 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/print.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/print.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Printing. diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/state.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/state.rs index 0af3688c..6d99beed 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/state.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/state.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! State information about the kernel itself. diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/synchronization.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/synchronization.rs index ab2b86e6..5740b63e 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/synchronization.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/synchronization.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Synchronization primitives. //! diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/time.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/time.rs index a6c0c5b6..a9d50120 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/time.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/time.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Timer primitives. diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/tests/00_console_sanity.rb b/15_virtual_mem_part3_precomputed_tables/kernel/tests/00_console_sanity.rb index 4dde5576..8be7a2f1 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/tests/00_console_sanity.rb +++ b/15_virtual_mem_part3_precomputed_tables/kernel/tests/00_console_sanity.rb @@ -2,7 +2,7 @@ # SPDX-License-Identifier: MIT OR Apache-2.0 # -# Copyright (c) 2019-2022 Andre Richter +# Copyright (c) 2019-2023 Andre Richter require 'console_io_test' @@ -40,9 +40,9 @@ class RxStatisticsTest < SubtestBase end end -##-------------------------------------------------------------------------------------------------- +## ------------------------------------------------------------------------------------------------- ## Test registration -##-------------------------------------------------------------------------------------------------- +## ------------------------------------------------------------------------------------------------- def subtest_collection [TxRxHandshakeTest.new, TxStatisticsTest.new, RxStatisticsTest.new] end diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/tests/00_console_sanity.rs b/15_virtual_mem_part3_precomputed_tables/kernel/tests/00_console_sanity.rs index 2c0225b7..682ea9b8 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/tests/00_console_sanity.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/tests/00_console_sanity.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2019-2022 Andre Richter +// Copyright (c) 2019-2023 Andre Richter //! Console sanity tests - RX, TX and statistics. diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/tests/01_timer_sanity.rs b/15_virtual_mem_part3_precomputed_tables/kernel/tests/01_timer_sanity.rs index 8188b942..1581a02e 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/tests/01_timer_sanity.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/tests/01_timer_sanity.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2019-2022 Andre Richter +// Copyright (c) 2019-2023 Andre Richter //! Timer sanity tests. diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/tests/02_exception_sync_page_fault.rs b/15_virtual_mem_part3_precomputed_tables/kernel/tests/02_exception_sync_page_fault.rs index c4b801ce..da64739c 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/tests/02_exception_sync_page_fault.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/tests/02_exception_sync_page_fault.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2019-2022 Andre Richter +// Copyright (c) 2019-2023 Andre Richter //! Page faults must result in synchronous exceptions. diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/tests/03_exception_restore_sanity.rb b/15_virtual_mem_part3_precomputed_tables/kernel/tests/03_exception_restore_sanity.rb index 5f52e0c7..02f51f74 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/tests/03_exception_restore_sanity.rb +++ b/15_virtual_mem_part3_precomputed_tables/kernel/tests/03_exception_restore_sanity.rb @@ -2,7 +2,7 @@ # SPDX-License-Identifier: MIT OR Apache-2.0 # -# Copyright (c) 2022 Andre Richter +# Copyright (c) 2022-2023 Andre Richter require 'console_io_test' @@ -17,9 +17,9 @@ class ExceptionRestoreTest < SubtestBase end end -##-------------------------------------------------------------------------------------------------- +## ------------------------------------------------------------------------------------------------- ## Test registration -##-------------------------------------------------------------------------------------------------- +## ------------------------------------------------------------------------------------------------- def subtest_collection [ExceptionRestoreTest.new] end diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/tests/03_exception_restore_sanity.rs b/15_virtual_mem_part3_precomputed_tables/kernel/tests/03_exception_restore_sanity.rs index f176c6a6..1a302911 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/tests/03_exception_restore_sanity.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/tests/03_exception_restore_sanity.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2022 Andre Richter +// Copyright (c) 2022-2023 Andre Richter //! A simple sanity test to see if exception restore code works. diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/tests/04_exception_irq_sanity.rs b/15_virtual_mem_part3_precomputed_tables/kernel/tests/04_exception_irq_sanity.rs index e6f94c91..fcace897 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/tests/04_exception_irq_sanity.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/tests/04_exception_irq_sanity.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! IRQ handling sanity tests. diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/tests/panic_exit_success/mod.rs b/15_virtual_mem_part3_precomputed_tables/kernel/tests/panic_exit_success/mod.rs index 908fac51..449ad6f9 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/tests/panic_exit_success/mod.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/tests/panic_exit_success/mod.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2019-2022 Andre Richter +// Copyright (c) 2019-2023 Andre Richter /// Overwrites libkernel's `panic_wait::_panic_exit()` with the QEMU-exit version. #[no_mangle] diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/tests/panic_wait_forever/mod.rs b/15_virtual_mem_part3_precomputed_tables/kernel/tests/panic_wait_forever/mod.rs index 7a4effa5..9ac19144 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/tests/panic_wait_forever/mod.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/tests/panic_wait_forever/mod.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2022 Andre Richter +// Copyright (c) 2022-2023 Andre Richter /// Overwrites libkernel's `panic_wait::_panic_exit()` with wait_forever. #[no_mangle] diff --git a/15_virtual_mem_part3_precomputed_tables/libraries/test-macros/src/lib.rs b/15_virtual_mem_part3_precomputed_tables/libraries/test-macros/src/lib.rs index 9879677c..52cf893d 100644 --- a/15_virtual_mem_part3_precomputed_tables/libraries/test-macros/src/lib.rs +++ b/15_virtual_mem_part3_precomputed_tables/libraries/test-macros/src/lib.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2019-2022 Andre Richter +// Copyright (c) 2019-2023 Andre Richter use proc_macro::TokenStream; use proc_macro2::Span; diff --git a/15_virtual_mem_part3_precomputed_tables/libraries/test-types/src/lib.rs b/15_virtual_mem_part3_precomputed_tables/libraries/test-types/src/lib.rs index 922c2a1c..38961a9c 100644 --- a/15_virtual_mem_part3_precomputed_tables/libraries/test-types/src/lib.rs +++ b/15_virtual_mem_part3_precomputed_tables/libraries/test-types/src/lib.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2019-2022 Andre Richter +// Copyright (c) 2019-2023 Andre Richter //! Types for the `custom_test_frameworks` implementation. diff --git a/15_virtual_mem_part3_precomputed_tables/tools/translation_table_tool/arch.rb b/15_virtual_mem_part3_precomputed_tables/tools/translation_table_tool/arch.rb index 07b06f13..44b8531e 100644 --- a/15_virtual_mem_part3_precomputed_tables/tools/translation_table_tool/arch.rb +++ b/15_virtual_mem_part3_precomputed_tables/tools/translation_table_tool/arch.rb @@ -2,7 +2,7 @@ # SPDX-License-Identifier: MIT OR Apache-2.0 # -# Copyright (c) 2021-2022 Andre Richter +# Copyright (c) 2021-2023 Andre Richter # Bitfield manipulation. class BitField diff --git a/15_virtual_mem_part3_precomputed_tables/tools/translation_table_tool/bsp.rb b/15_virtual_mem_part3_precomputed_tables/tools/translation_table_tool/bsp.rb index 0b76b403..49e6fae9 100644 --- a/15_virtual_mem_part3_precomputed_tables/tools/translation_table_tool/bsp.rb +++ b/15_virtual_mem_part3_precomputed_tables/tools/translation_table_tool/bsp.rb @@ -2,7 +2,7 @@ # SPDX-License-Identifier: MIT OR Apache-2.0 # -# Copyright (c) 2021-2022 Andre Richter +# Copyright (c) 2021-2023 Andre Richter # Raspberry Pi 3 + 4 class RaspberryPi diff --git a/15_virtual_mem_part3_precomputed_tables/tools/translation_table_tool/generic.rb b/15_virtual_mem_part3_precomputed_tables/tools/translation_table_tool/generic.rb index 13df0658..743840e0 100644 --- a/15_virtual_mem_part3_precomputed_tables/tools/translation_table_tool/generic.rb +++ b/15_virtual_mem_part3_precomputed_tables/tools/translation_table_tool/generic.rb @@ -2,7 +2,7 @@ # SPDX-License-Identifier: MIT OR Apache-2.0 # -# Copyright (c) 2021-2022 Andre Richter +# Copyright (c) 2021-2023 Andre Richter module Granule64KiB SIZE = 64 * 1024 @@ -151,7 +151,7 @@ def kernel_map_binary mapping_descriptors.each do |i| print 'Generating'.rjust(12).green.bold print ' ' - puts i.to_s + puts i TRANSLATION_TABLES.map_at(i.virt_region, i.phys_region, i.attributes) end diff --git a/15_virtual_mem_part3_precomputed_tables/tools/translation_table_tool/kernel_elf.rb b/15_virtual_mem_part3_precomputed_tables/tools/translation_table_tool/kernel_elf.rb index f2d5b0b7..5ba78d9d 100644 --- a/15_virtual_mem_part3_precomputed_tables/tools/translation_table_tool/kernel_elf.rb +++ b/15_virtual_mem_part3_precomputed_tables/tools/translation_table_tool/kernel_elf.rb @@ -2,7 +2,7 @@ # SPDX-License-Identifier: MIT OR Apache-2.0 # -# Copyright (c) 2021-2022 Andre Richter +# Copyright (c) 2021-2023 Andre Richter # KernelELF class KernelELF diff --git a/15_virtual_mem_part3_precomputed_tables/tools/translation_table_tool/main.rb b/15_virtual_mem_part3_precomputed_tables/tools/translation_table_tool/main.rb index 6419e364..22ab24fd 100755 --- a/15_virtual_mem_part3_precomputed_tables/tools/translation_table_tool/main.rb +++ b/15_virtual_mem_part3_precomputed_tables/tools/translation_table_tool/main.rb @@ -3,7 +3,7 @@ # SPDX-License-Identifier: MIT OR Apache-2.0 # -# Copyright (c) 2021-2022 Andre Richter +# Copyright (c) 2021-2023 Andre Richter require 'rubygems' require 'bundler/setup' diff --git a/16_virtual_mem_part4_higher_half_kernel/.vscode/settings.json b/16_virtual_mem_part4_higher_half_kernel/.vscode/settings.json index 292bf2a9..9ef30cd0 100644 --- a/16_virtual_mem_part4_higher_half_kernel/.vscode/settings.json +++ b/16_virtual_mem_part4_higher_half_kernel/.vscode/settings.json @@ -1,10 +1,10 @@ { - "editor.formatOnSave": true, - "editor.rulers": [100], - "rust-analyzer.cargo.target": "aarch64-unknown-none-softfloat", - "rust-analyzer.cargo.features": ["bsp_rpi3"], - "rust-analyzer.checkOnSave.allTargets": false, - "rust-analyzer.checkOnSave.extraArgs": ["--lib", "--bins"], - "rust-analyzer.lens.debug": false, - "rust-analyzer.lens.run": false + "editor.formatOnSave": true, + "editor.rulers": [100], + "rust-analyzer.cargo.target": "aarch64-unknown-none-softfloat", + "rust-analyzer.cargo.features": ["bsp_rpi3"], + "rust-analyzer.checkOnSave.allTargets": false, + "rust-analyzer.checkOnSave.extraArgs": ["--lib", "--bins"], + "rust-analyzer.lens.debug": false, + "rust-analyzer.lens.run": false } diff --git a/16_virtual_mem_part4_higher_half_kernel/Makefile b/16_virtual_mem_part4_higher_half_kernel/Makefile index 0f5c4870..bc23270d 100644 --- a/16_virtual_mem_part4_higher_half_kernel/Makefile +++ b/16_virtual_mem_part4_higher_half_kernel/Makefile @@ -1,6 +1,6 @@ ## SPDX-License-Identifier: MIT OR Apache-2.0 ## -## Copyright (c) 2018-2022 Andre Richter +## Copyright (c) 2018-2023 Andre Richter include ../common/docker.mk include ../common/format.mk diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/cpu.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/cpu.rs index 7eb7f010..2d010473 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/cpu.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/cpu.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Architectural processor code. //! diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/cpu/boot.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/cpu/boot.rs index 2cad1ab6..4d7b7735 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/cpu/boot.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/cpu/boot.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2021-2022 Andre Richter +// Copyright (c) 2021-2023 Andre Richter //! Architectural boot code. //! diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/cpu/smp.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/cpu/smp.rs index 9d304d65..49192038 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/cpu/smp.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/cpu/smp.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Architectural symmetric multiprocessing. //! diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/exception.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/exception.rs index 71831178..73019800 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/exception.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/exception.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Architectural synchronous and asynchronous exception handling. //! diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/exception/asynchronous.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/exception/asynchronous.rs index f545a3e1..811ef138 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/exception/asynchronous.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/exception/asynchronous.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Architectural asynchronous exception handling. //! diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/memory/mmu.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/memory/mmu.rs index 74a71d11..984b2e04 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/memory/mmu.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/memory/mmu.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Memory Management Unit Driver. //! diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/memory/mmu/translation_table.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/memory/mmu/translation_table.rs index f0b4ac85..21fae3b8 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/memory/mmu/translation_table.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/memory/mmu/translation_table.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2021-2022 Andre Richter +// Copyright (c) 2021-2023 Andre Richter //! Architectural translation table. //! diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/time.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/time.rs index 94d02379..ee1c3ef7 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/time.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/time.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Architectural timer primitives. //! diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp.rs index 824787f6..246973bc 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Conditional reexporting of Board Support Packages. diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver.rs index eafaf775..2dfaec8d 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Device driver. diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/arm.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/arm.rs index e83e24c9..8d1cbfbd 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/arm.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/arm.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! ARM driver top level. diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/arm/gicv2.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/arm/gicv2.rs index 3cc35b5e..256de704 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/arm/gicv2.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/arm/gicv2.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! GICv2 Driver - ARM Generic Interrupt Controller v2. //! diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/arm/gicv2/gicc.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/arm/gicv2/gicc.rs index 1a02fc65..0fd16bb3 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/arm/gicv2/gicc.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/arm/gicv2/gicc.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! GICC Driver - GIC CPU interface. diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs index 8aebcf2b..1fc9d70e 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! GICD Driver - GIC Distributor. //! diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/bcm.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/bcm.rs index 5a7cc23b..7b7c288b 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/bcm.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/bcm.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! BCM driver top level. diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs index fb61a651..812156f4 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! GPIO Driver. diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs index c93a9fa1..62f07800 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Interrupt Controller Driver. diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs index 0a20bd87..a26bff8d 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Peripheral Interrupt Controller Driver. //! diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs index 0ee7feb7..b424d4be 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! PL011 UART driver. //! diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/common.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/common.rs index ca7aeb76..3ce1d8d8 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/common.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/common.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Common device driver code. diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi.rs index 474419f4..30421dfa 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Top-level BSP file for the Raspberry Pi 3 and 4. diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi/cpu.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi/cpu.rs index 85fb89e4..65cf5abb 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi/cpu.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi/cpu.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! BSP Processor code. diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi/driver.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi/driver.rs index ca3435aa..a1f55b17 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi/driver.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi/driver.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! BSP driver support. diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi/exception.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi/exception.rs index aa6c5a63..a9eaa6ac 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi/exception.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi/exception.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! BSP synchronous and asynchronous exception handling. diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi/exception/asynchronous.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi/exception/asynchronous.rs index 06a67558..776182fd 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi/exception/asynchronous.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi/exception/asynchronous.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! BSP asynchronous exception handling. diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi/memory.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi/memory.rs index f34009de..3a33126c 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi/memory.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi/memory.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! BSP Memory Management. //! diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi/memory/mmu.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi/memory/mmu.rs index bfebd8b2..3c0368b9 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi/memory/mmu.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi/memory/mmu.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! BSP Memory Management Unit. diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/common.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/common.rs index f32f650f..2ad7e4c1 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/common.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/common.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! General purpose code. diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/console.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/console.rs index a85bcffe..f0363464 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/console.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/console.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! System console. diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/console/null_console.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/console/null_console.rs index 2c64d499..e92a022b 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/console/null_console.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/console/null_console.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2022 Andre Richter +// Copyright (c) 2022-2023 Andre Richter //! Null console. diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/cpu.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/cpu.rs index e1493d1d..8716a918 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/cpu.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/cpu.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Processor code. diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/cpu/boot.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/cpu/boot.rs index 8091dac3..b1e98328 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/cpu/boot.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/cpu/boot.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2021-2022 Andre Richter +// Copyright (c) 2021-2023 Andre Richter //! Boot code. diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/cpu/smp.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/cpu/smp.rs index 57386f79..de612d58 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/cpu/smp.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/cpu/smp.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Symmetric multiprocessing. diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/driver.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/driver.rs index 18066c31..2edf8b85 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/driver.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/driver.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Driver support. diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/exception.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/exception.rs index 7ea7cd80..3d5f219f 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/exception.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/exception.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Synchronous and asynchronous exception handling. diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/exception/asynchronous.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/exception/asynchronous.rs index c1f2a27b..2c874dd6 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/exception/asynchronous.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/exception/asynchronous.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Asynchronous exception handling. diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/exception/asynchronous/null_irq_manager.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/exception/asynchronous/null_irq_manager.rs index 438f9649..38919ffe 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/exception/asynchronous/null_irq_manager.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/exception/asynchronous/null_irq_manager.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2022 Andre Richter +// Copyright (c) 2022-2023 Andre Richter //! Null IRQ Manager. diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/lib.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/lib.rs index f595b587..d883d354 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/lib.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/lib.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter // Rust embedded logo for `make doc`. #![doc( diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/main.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/main.rs index 65905258..e41cfaa0 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/main.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/main.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter // Rust embedded logo for `make doc`. #![doc( diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/memory.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/memory.rs index 3b6868e7..6131bdb6 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/memory.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/memory.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Memory Management. diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/memory/mmu.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/memory/mmu.rs index 7f02dad9..404e2a8a 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/memory/mmu.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/memory/mmu.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Memory Management Unit. diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/memory/mmu/mapping_record.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/memory/mmu/mapping_record.rs index b893fee3..0e079220 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/memory/mmu/mapping_record.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/memory/mmu/mapping_record.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! A record of mapped pages. diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/memory/mmu/page_alloc.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/memory/mmu/page_alloc.rs index 347fcd34..344afd20 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/memory/mmu/page_alloc.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/memory/mmu/page_alloc.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2021-2022 Andre Richter +// Copyright (c) 2021-2023 Andre Richter //! Page allocation. diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/memory/mmu/translation_table.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/memory/mmu/translation_table.rs index 9301bb0c..341ffc5c 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/memory/mmu/translation_table.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/memory/mmu/translation_table.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2021-2022 Andre Richter +// Copyright (c) 2021-2023 Andre Richter //! Translation table. diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/memory/mmu/types.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/memory/mmu/types.rs index 62f3926e..f6ac8d59 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/memory/mmu/types.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/memory/mmu/types.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Memory Management Unit types. diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/panic_wait.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/panic_wait.rs index ae4651e7..c6f3a9c7 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/panic_wait.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/panic_wait.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! A panic handler that infinitely waits. diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/print.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/print.rs index fe13b334..8e303046 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/print.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/print.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Printing. diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/state.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/state.rs index 0af3688c..6d99beed 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/state.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/state.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! State information about the kernel itself. diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/synchronization.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/synchronization.rs index ab2b86e6..5740b63e 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/synchronization.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/synchronization.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Synchronization primitives. //! diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/time.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/time.rs index a6c0c5b6..a9d50120 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/time.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/time.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Timer primitives. diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/tests/00_console_sanity.rb b/16_virtual_mem_part4_higher_half_kernel/kernel/tests/00_console_sanity.rb index 4dde5576..8be7a2f1 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/tests/00_console_sanity.rb +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/tests/00_console_sanity.rb @@ -2,7 +2,7 @@ # SPDX-License-Identifier: MIT OR Apache-2.0 # -# Copyright (c) 2019-2022 Andre Richter +# Copyright (c) 2019-2023 Andre Richter require 'console_io_test' @@ -40,9 +40,9 @@ class RxStatisticsTest < SubtestBase end end -##-------------------------------------------------------------------------------------------------- +## ------------------------------------------------------------------------------------------------- ## Test registration -##-------------------------------------------------------------------------------------------------- +## ------------------------------------------------------------------------------------------------- def subtest_collection [TxRxHandshakeTest.new, TxStatisticsTest.new, RxStatisticsTest.new] end diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/tests/00_console_sanity.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/tests/00_console_sanity.rs index 2c0225b7..682ea9b8 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/tests/00_console_sanity.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/tests/00_console_sanity.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2019-2022 Andre Richter +// Copyright (c) 2019-2023 Andre Richter //! Console sanity tests - RX, TX and statistics. diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/tests/01_timer_sanity.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/tests/01_timer_sanity.rs index 8188b942..1581a02e 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/tests/01_timer_sanity.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/tests/01_timer_sanity.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2019-2022 Andre Richter +// Copyright (c) 2019-2023 Andre Richter //! Timer sanity tests. diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/tests/02_exception_sync_page_fault.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/tests/02_exception_sync_page_fault.rs index fab44c8f..09d17798 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/tests/02_exception_sync_page_fault.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/tests/02_exception_sync_page_fault.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2019-2022 Andre Richter +// Copyright (c) 2019-2023 Andre Richter //! Page faults must result in synchronous exceptions. diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/tests/03_exception_restore_sanity.rb b/16_virtual_mem_part4_higher_half_kernel/kernel/tests/03_exception_restore_sanity.rb index 5f52e0c7..02f51f74 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/tests/03_exception_restore_sanity.rb +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/tests/03_exception_restore_sanity.rb @@ -2,7 +2,7 @@ # SPDX-License-Identifier: MIT OR Apache-2.0 # -# Copyright (c) 2022 Andre Richter +# Copyright (c) 2022-2023 Andre Richter require 'console_io_test' @@ -17,9 +17,9 @@ class ExceptionRestoreTest < SubtestBase end end -##-------------------------------------------------------------------------------------------------- +## ------------------------------------------------------------------------------------------------- ## Test registration -##-------------------------------------------------------------------------------------------------- +## ------------------------------------------------------------------------------------------------- def subtest_collection [ExceptionRestoreTest.new] end diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/tests/03_exception_restore_sanity.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/tests/03_exception_restore_sanity.rs index f176c6a6..1a302911 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/tests/03_exception_restore_sanity.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/tests/03_exception_restore_sanity.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2022 Andre Richter +// Copyright (c) 2022-2023 Andre Richter //! A simple sanity test to see if exception restore code works. diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/tests/04_exception_irq_sanity.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/tests/04_exception_irq_sanity.rs index e6f94c91..fcace897 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/tests/04_exception_irq_sanity.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/tests/04_exception_irq_sanity.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! IRQ handling sanity tests. diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/tests/panic_exit_success/mod.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/tests/panic_exit_success/mod.rs index 908fac51..449ad6f9 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/tests/panic_exit_success/mod.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/tests/panic_exit_success/mod.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2019-2022 Andre Richter +// Copyright (c) 2019-2023 Andre Richter /// Overwrites libkernel's `panic_wait::_panic_exit()` with the QEMU-exit version. #[no_mangle] diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/tests/panic_wait_forever/mod.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/tests/panic_wait_forever/mod.rs index 7a4effa5..9ac19144 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/tests/panic_wait_forever/mod.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/tests/panic_wait_forever/mod.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2022 Andre Richter +// Copyright (c) 2022-2023 Andre Richter /// Overwrites libkernel's `panic_wait::_panic_exit()` with wait_forever. #[no_mangle] diff --git a/16_virtual_mem_part4_higher_half_kernel/libraries/test-macros/src/lib.rs b/16_virtual_mem_part4_higher_half_kernel/libraries/test-macros/src/lib.rs index 9879677c..52cf893d 100644 --- a/16_virtual_mem_part4_higher_half_kernel/libraries/test-macros/src/lib.rs +++ b/16_virtual_mem_part4_higher_half_kernel/libraries/test-macros/src/lib.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2019-2022 Andre Richter +// Copyright (c) 2019-2023 Andre Richter use proc_macro::TokenStream; use proc_macro2::Span; diff --git a/16_virtual_mem_part4_higher_half_kernel/libraries/test-types/src/lib.rs b/16_virtual_mem_part4_higher_half_kernel/libraries/test-types/src/lib.rs index 922c2a1c..38961a9c 100644 --- a/16_virtual_mem_part4_higher_half_kernel/libraries/test-types/src/lib.rs +++ b/16_virtual_mem_part4_higher_half_kernel/libraries/test-types/src/lib.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2019-2022 Andre Richter +// Copyright (c) 2019-2023 Andre Richter //! Types for the `custom_test_frameworks` implementation. diff --git a/16_virtual_mem_part4_higher_half_kernel/tools/translation_table_tool/arch.rb b/16_virtual_mem_part4_higher_half_kernel/tools/translation_table_tool/arch.rb index deceb6d0..61a6d6ca 100644 --- a/16_virtual_mem_part4_higher_half_kernel/tools/translation_table_tool/arch.rb +++ b/16_virtual_mem_part4_higher_half_kernel/tools/translation_table_tool/arch.rb @@ -2,7 +2,7 @@ # SPDX-License-Identifier: MIT OR Apache-2.0 # -# Copyright (c) 2021-2022 Andre Richter +# Copyright (c) 2021-2023 Andre Richter # Bitfield manipulation. class BitField diff --git a/16_virtual_mem_part4_higher_half_kernel/tools/translation_table_tool/bsp.rb b/16_virtual_mem_part4_higher_half_kernel/tools/translation_table_tool/bsp.rb index 536a2f21..93bcedd9 100644 --- a/16_virtual_mem_part4_higher_half_kernel/tools/translation_table_tool/bsp.rb +++ b/16_virtual_mem_part4_higher_half_kernel/tools/translation_table_tool/bsp.rb @@ -2,7 +2,7 @@ # SPDX-License-Identifier: MIT OR Apache-2.0 # -# Copyright (c) 2021-2022 Andre Richter +# Copyright (c) 2021-2023 Andre Richter # Raspberry Pi 3 + 4 class RaspberryPi diff --git a/16_virtual_mem_part4_higher_half_kernel/tools/translation_table_tool/generic.rb b/16_virtual_mem_part4_higher_half_kernel/tools/translation_table_tool/generic.rb index 13df0658..743840e0 100644 --- a/16_virtual_mem_part4_higher_half_kernel/tools/translation_table_tool/generic.rb +++ b/16_virtual_mem_part4_higher_half_kernel/tools/translation_table_tool/generic.rb @@ -2,7 +2,7 @@ # SPDX-License-Identifier: MIT OR Apache-2.0 # -# Copyright (c) 2021-2022 Andre Richter +# Copyright (c) 2021-2023 Andre Richter module Granule64KiB SIZE = 64 * 1024 @@ -151,7 +151,7 @@ def kernel_map_binary mapping_descriptors.each do |i| print 'Generating'.rjust(12).green.bold print ' ' - puts i.to_s + puts i TRANSLATION_TABLES.map_at(i.virt_region, i.phys_region, i.attributes) end diff --git a/16_virtual_mem_part4_higher_half_kernel/tools/translation_table_tool/kernel_elf.rb b/16_virtual_mem_part4_higher_half_kernel/tools/translation_table_tool/kernel_elf.rb index f2d5b0b7..5ba78d9d 100644 --- a/16_virtual_mem_part4_higher_half_kernel/tools/translation_table_tool/kernel_elf.rb +++ b/16_virtual_mem_part4_higher_half_kernel/tools/translation_table_tool/kernel_elf.rb @@ -2,7 +2,7 @@ # SPDX-License-Identifier: MIT OR Apache-2.0 # -# Copyright (c) 2021-2022 Andre Richter +# Copyright (c) 2021-2023 Andre Richter # KernelELF class KernelELF diff --git a/16_virtual_mem_part4_higher_half_kernel/tools/translation_table_tool/main.rb b/16_virtual_mem_part4_higher_half_kernel/tools/translation_table_tool/main.rb index 6419e364..22ab24fd 100755 --- a/16_virtual_mem_part4_higher_half_kernel/tools/translation_table_tool/main.rb +++ b/16_virtual_mem_part4_higher_half_kernel/tools/translation_table_tool/main.rb @@ -3,7 +3,7 @@ # SPDX-License-Identifier: MIT OR Apache-2.0 # -# Copyright (c) 2021-2022 Andre Richter +# Copyright (c) 2021-2023 Andre Richter require 'rubygems' require 'bundler/setup' diff --git a/17_kernel_symbols/.vscode/settings.json b/17_kernel_symbols/.vscode/settings.json index 292bf2a9..9ef30cd0 100644 --- a/17_kernel_symbols/.vscode/settings.json +++ b/17_kernel_symbols/.vscode/settings.json @@ -1,10 +1,10 @@ { - "editor.formatOnSave": true, - "editor.rulers": [100], - "rust-analyzer.cargo.target": "aarch64-unknown-none-softfloat", - "rust-analyzer.cargo.features": ["bsp_rpi3"], - "rust-analyzer.checkOnSave.allTargets": false, - "rust-analyzer.checkOnSave.extraArgs": ["--lib", "--bins"], - "rust-analyzer.lens.debug": false, - "rust-analyzer.lens.run": false + "editor.formatOnSave": true, + "editor.rulers": [100], + "rust-analyzer.cargo.target": "aarch64-unknown-none-softfloat", + "rust-analyzer.cargo.features": ["bsp_rpi3"], + "rust-analyzer.checkOnSave.allTargets": false, + "rust-analyzer.checkOnSave.extraArgs": ["--lib", "--bins"], + "rust-analyzer.lens.debug": false, + "rust-analyzer.lens.run": false } diff --git a/17_kernel_symbols/Makefile b/17_kernel_symbols/Makefile index ce1d165b..3c33cd66 100644 --- a/17_kernel_symbols/Makefile +++ b/17_kernel_symbols/Makefile @@ -1,6 +1,6 @@ ## SPDX-License-Identifier: MIT OR Apache-2.0 ## -## Copyright (c) 2018-2022 Andre Richter +## Copyright (c) 2018-2023 Andre Richter include ../common/docker.mk include ../common/format.mk diff --git a/17_kernel_symbols/README.md b/17_kernel_symbols/README.md index aec53437..78962bd8 100644 --- a/17_kernel_symbols/README.md +++ b/17_kernel_symbols/README.md @@ -346,7 +346,7 @@ diff -uNr 16_virtual_mem_part4_higher_half_kernel/kernel/src/symbols.rs 17_kerne @@ -0,0 +1,88 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// -+// Copyright (c) 2022 Andre Richter ++// Copyright (c) 2022-2023 Andre Richter + +//! Debug symbol support. + @@ -478,7 +478,7 @@ diff -uNr 16_virtual_mem_part4_higher_half_kernel/kernel_symbols/kernel_symbols. @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: MIT OR Apache-2.0 + * -+ * Copyright (c) 2022 Andre Richter ++ * Copyright (c) 2022-2023 Andre Richter + */ + +SECTIONS @@ -498,7 +498,7 @@ diff -uNr 16_virtual_mem_part4_higher_half_kernel/kernel_symbols/src/main.rs 17_ @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// -+// Copyright (c) 2022 Andre Richter ++// Copyright (c) 2022-2023 Andre Richter + +//! Generation of kernel symbols. + @@ -519,7 +519,7 @@ diff -uNr 16_virtual_mem_part4_higher_half_kernel/kernel_symbols.mk 17_kernel_sy @@ -0,0 +1,117 @@ +## SPDX-License-Identifier: MIT OR Apache-2.0 +## -+## Copyright (c) 2018-2022 Andre Richter ++## Copyright (c) 2018-2023 Andre Richter + +include ../common/format.mk +include ../common/docker.mk @@ -650,7 +650,7 @@ diff -uNr 16_virtual_mem_part4_higher_half_kernel/libraries/debug-symbol-types/s @@ -0,0 +1,45 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// -+// Copyright (c) 2022 Andre Richter ++// Copyright (c) 2022-2023 Andre Richter + +//! Types for implementing debug symbol support. + @@ -783,7 +783,7 @@ diff -uNr 16_virtual_mem_part4_higher_half_kernel/tools/kernel_symbols_tool/cmds + +# SPDX-License-Identifier: MIT OR Apache-2.0 +# -+# Copyright (c) 2022 Andre Richter ++# Copyright (c) 2022-2023 Andre Richter + +def generate_symbols(kernel_elf, output_file) + File.open(output_file, 'w') do |file| @@ -833,7 +833,7 @@ diff -uNr 16_virtual_mem_part4_higher_half_kernel/tools/kernel_symbols_tool/kern + +# SPDX-License-Identifier: MIT OR Apache-2.0 +# -+# Copyright (c) 2021-2022 Andre Richter ++# Copyright (c) 2021-2023 Andre Richter + +# KernelELF +class KernelELF @@ -913,7 +913,7 @@ diff -uNr 16_virtual_mem_part4_higher_half_kernel/tools/kernel_symbols_tool/main + +# SPDX-License-Identifier: MIT OR Apache-2.0 +# -+# Copyright (c) 2022 Andre Richter ++# Copyright (c) 2022-2023 Andre Richter + +require 'rubygems' +require 'bundler/setup' diff --git a/17_kernel_symbols/kernel/src/_arch/aarch64/cpu.rs b/17_kernel_symbols/kernel/src/_arch/aarch64/cpu.rs index 7eb7f010..2d010473 100644 --- a/17_kernel_symbols/kernel/src/_arch/aarch64/cpu.rs +++ b/17_kernel_symbols/kernel/src/_arch/aarch64/cpu.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Architectural processor code. //! diff --git a/17_kernel_symbols/kernel/src/_arch/aarch64/cpu/boot.rs b/17_kernel_symbols/kernel/src/_arch/aarch64/cpu/boot.rs index 2cad1ab6..4d7b7735 100644 --- a/17_kernel_symbols/kernel/src/_arch/aarch64/cpu/boot.rs +++ b/17_kernel_symbols/kernel/src/_arch/aarch64/cpu/boot.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2021-2022 Andre Richter +// Copyright (c) 2021-2023 Andre Richter //! Architectural boot code. //! diff --git a/17_kernel_symbols/kernel/src/_arch/aarch64/cpu/smp.rs b/17_kernel_symbols/kernel/src/_arch/aarch64/cpu/smp.rs index 9d304d65..49192038 100644 --- a/17_kernel_symbols/kernel/src/_arch/aarch64/cpu/smp.rs +++ b/17_kernel_symbols/kernel/src/_arch/aarch64/cpu/smp.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Architectural symmetric multiprocessing. //! diff --git a/17_kernel_symbols/kernel/src/_arch/aarch64/exception.rs b/17_kernel_symbols/kernel/src/_arch/aarch64/exception.rs index 926d6d38..d7863a1e 100644 --- a/17_kernel_symbols/kernel/src/_arch/aarch64/exception.rs +++ b/17_kernel_symbols/kernel/src/_arch/aarch64/exception.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Architectural synchronous and asynchronous exception handling. //! diff --git a/17_kernel_symbols/kernel/src/_arch/aarch64/exception/asynchronous.rs b/17_kernel_symbols/kernel/src/_arch/aarch64/exception/asynchronous.rs index f545a3e1..811ef138 100644 --- a/17_kernel_symbols/kernel/src/_arch/aarch64/exception/asynchronous.rs +++ b/17_kernel_symbols/kernel/src/_arch/aarch64/exception/asynchronous.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Architectural asynchronous exception handling. //! diff --git a/17_kernel_symbols/kernel/src/_arch/aarch64/memory/mmu.rs b/17_kernel_symbols/kernel/src/_arch/aarch64/memory/mmu.rs index 74a71d11..984b2e04 100644 --- a/17_kernel_symbols/kernel/src/_arch/aarch64/memory/mmu.rs +++ b/17_kernel_symbols/kernel/src/_arch/aarch64/memory/mmu.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Memory Management Unit Driver. //! diff --git a/17_kernel_symbols/kernel/src/_arch/aarch64/memory/mmu/translation_table.rs b/17_kernel_symbols/kernel/src/_arch/aarch64/memory/mmu/translation_table.rs index f0b4ac85..21fae3b8 100644 --- a/17_kernel_symbols/kernel/src/_arch/aarch64/memory/mmu/translation_table.rs +++ b/17_kernel_symbols/kernel/src/_arch/aarch64/memory/mmu/translation_table.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2021-2022 Andre Richter +// Copyright (c) 2021-2023 Andre Richter //! Architectural translation table. //! diff --git a/17_kernel_symbols/kernel/src/_arch/aarch64/time.rs b/17_kernel_symbols/kernel/src/_arch/aarch64/time.rs index 94d02379..ee1c3ef7 100644 --- a/17_kernel_symbols/kernel/src/_arch/aarch64/time.rs +++ b/17_kernel_symbols/kernel/src/_arch/aarch64/time.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Architectural timer primitives. //! diff --git a/17_kernel_symbols/kernel/src/bsp.rs b/17_kernel_symbols/kernel/src/bsp.rs index 824787f6..246973bc 100644 --- a/17_kernel_symbols/kernel/src/bsp.rs +++ b/17_kernel_symbols/kernel/src/bsp.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Conditional reexporting of Board Support Packages. diff --git a/17_kernel_symbols/kernel/src/bsp/device_driver.rs b/17_kernel_symbols/kernel/src/bsp/device_driver.rs index eafaf775..2dfaec8d 100644 --- a/17_kernel_symbols/kernel/src/bsp/device_driver.rs +++ b/17_kernel_symbols/kernel/src/bsp/device_driver.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Device driver. diff --git a/17_kernel_symbols/kernel/src/bsp/device_driver/arm.rs b/17_kernel_symbols/kernel/src/bsp/device_driver/arm.rs index e83e24c9..8d1cbfbd 100644 --- a/17_kernel_symbols/kernel/src/bsp/device_driver/arm.rs +++ b/17_kernel_symbols/kernel/src/bsp/device_driver/arm.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! ARM driver top level. diff --git a/17_kernel_symbols/kernel/src/bsp/device_driver/arm/gicv2.rs b/17_kernel_symbols/kernel/src/bsp/device_driver/arm/gicv2.rs index 3cc35b5e..256de704 100644 --- a/17_kernel_symbols/kernel/src/bsp/device_driver/arm/gicv2.rs +++ b/17_kernel_symbols/kernel/src/bsp/device_driver/arm/gicv2.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! GICv2 Driver - ARM Generic Interrupt Controller v2. //! diff --git a/17_kernel_symbols/kernel/src/bsp/device_driver/arm/gicv2/gicc.rs b/17_kernel_symbols/kernel/src/bsp/device_driver/arm/gicv2/gicc.rs index 1a02fc65..0fd16bb3 100644 --- a/17_kernel_symbols/kernel/src/bsp/device_driver/arm/gicv2/gicc.rs +++ b/17_kernel_symbols/kernel/src/bsp/device_driver/arm/gicv2/gicc.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! GICC Driver - GIC CPU interface. diff --git a/17_kernel_symbols/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs b/17_kernel_symbols/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs index 8aebcf2b..1fc9d70e 100644 --- a/17_kernel_symbols/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs +++ b/17_kernel_symbols/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! GICD Driver - GIC Distributor. //! diff --git a/17_kernel_symbols/kernel/src/bsp/device_driver/bcm.rs b/17_kernel_symbols/kernel/src/bsp/device_driver/bcm.rs index 5a7cc23b..7b7c288b 100644 --- a/17_kernel_symbols/kernel/src/bsp/device_driver/bcm.rs +++ b/17_kernel_symbols/kernel/src/bsp/device_driver/bcm.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! BCM driver top level. diff --git a/17_kernel_symbols/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs b/17_kernel_symbols/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs index fb61a651..812156f4 100644 --- a/17_kernel_symbols/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs +++ b/17_kernel_symbols/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! GPIO Driver. diff --git a/17_kernel_symbols/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs b/17_kernel_symbols/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs index c93a9fa1..62f07800 100644 --- a/17_kernel_symbols/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs +++ b/17_kernel_symbols/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Interrupt Controller Driver. diff --git a/17_kernel_symbols/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs b/17_kernel_symbols/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs index 0a20bd87..a26bff8d 100644 --- a/17_kernel_symbols/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs +++ b/17_kernel_symbols/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Peripheral Interrupt Controller Driver. //! diff --git a/17_kernel_symbols/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs b/17_kernel_symbols/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs index 0ee7feb7..b424d4be 100644 --- a/17_kernel_symbols/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs +++ b/17_kernel_symbols/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! PL011 UART driver. //! diff --git a/17_kernel_symbols/kernel/src/bsp/device_driver/common.rs b/17_kernel_symbols/kernel/src/bsp/device_driver/common.rs index ca7aeb76..3ce1d8d8 100644 --- a/17_kernel_symbols/kernel/src/bsp/device_driver/common.rs +++ b/17_kernel_symbols/kernel/src/bsp/device_driver/common.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Common device driver code. diff --git a/17_kernel_symbols/kernel/src/bsp/raspberrypi.rs b/17_kernel_symbols/kernel/src/bsp/raspberrypi.rs index 474419f4..30421dfa 100644 --- a/17_kernel_symbols/kernel/src/bsp/raspberrypi.rs +++ b/17_kernel_symbols/kernel/src/bsp/raspberrypi.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Top-level BSP file for the Raspberry Pi 3 and 4. diff --git a/17_kernel_symbols/kernel/src/bsp/raspberrypi/cpu.rs b/17_kernel_symbols/kernel/src/bsp/raspberrypi/cpu.rs index 85fb89e4..65cf5abb 100644 --- a/17_kernel_symbols/kernel/src/bsp/raspberrypi/cpu.rs +++ b/17_kernel_symbols/kernel/src/bsp/raspberrypi/cpu.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! BSP Processor code. diff --git a/17_kernel_symbols/kernel/src/bsp/raspberrypi/driver.rs b/17_kernel_symbols/kernel/src/bsp/raspberrypi/driver.rs index ca3435aa..a1f55b17 100644 --- a/17_kernel_symbols/kernel/src/bsp/raspberrypi/driver.rs +++ b/17_kernel_symbols/kernel/src/bsp/raspberrypi/driver.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! BSP driver support. diff --git a/17_kernel_symbols/kernel/src/bsp/raspberrypi/exception.rs b/17_kernel_symbols/kernel/src/bsp/raspberrypi/exception.rs index aa6c5a63..a9eaa6ac 100644 --- a/17_kernel_symbols/kernel/src/bsp/raspberrypi/exception.rs +++ b/17_kernel_symbols/kernel/src/bsp/raspberrypi/exception.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! BSP synchronous and asynchronous exception handling. diff --git a/17_kernel_symbols/kernel/src/bsp/raspberrypi/exception/asynchronous.rs b/17_kernel_symbols/kernel/src/bsp/raspberrypi/exception/asynchronous.rs index 06a67558..776182fd 100644 --- a/17_kernel_symbols/kernel/src/bsp/raspberrypi/exception/asynchronous.rs +++ b/17_kernel_symbols/kernel/src/bsp/raspberrypi/exception/asynchronous.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! BSP asynchronous exception handling. diff --git a/17_kernel_symbols/kernel/src/bsp/raspberrypi/memory.rs b/17_kernel_symbols/kernel/src/bsp/raspberrypi/memory.rs index 32416e6c..96a4d8c1 100644 --- a/17_kernel_symbols/kernel/src/bsp/raspberrypi/memory.rs +++ b/17_kernel_symbols/kernel/src/bsp/raspberrypi/memory.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! BSP Memory Management. //! diff --git a/17_kernel_symbols/kernel/src/bsp/raspberrypi/memory/mmu.rs b/17_kernel_symbols/kernel/src/bsp/raspberrypi/memory/mmu.rs index bfebd8b2..3c0368b9 100644 --- a/17_kernel_symbols/kernel/src/bsp/raspberrypi/memory/mmu.rs +++ b/17_kernel_symbols/kernel/src/bsp/raspberrypi/memory/mmu.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! BSP Memory Management Unit. diff --git a/17_kernel_symbols/kernel/src/common.rs b/17_kernel_symbols/kernel/src/common.rs index f32f650f..2ad7e4c1 100644 --- a/17_kernel_symbols/kernel/src/common.rs +++ b/17_kernel_symbols/kernel/src/common.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! General purpose code. diff --git a/17_kernel_symbols/kernel/src/console.rs b/17_kernel_symbols/kernel/src/console.rs index a85bcffe..f0363464 100644 --- a/17_kernel_symbols/kernel/src/console.rs +++ b/17_kernel_symbols/kernel/src/console.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! System console. diff --git a/17_kernel_symbols/kernel/src/console/null_console.rs b/17_kernel_symbols/kernel/src/console/null_console.rs index 2c64d499..e92a022b 100644 --- a/17_kernel_symbols/kernel/src/console/null_console.rs +++ b/17_kernel_symbols/kernel/src/console/null_console.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2022 Andre Richter +// Copyright (c) 2022-2023 Andre Richter //! Null console. diff --git a/17_kernel_symbols/kernel/src/cpu.rs b/17_kernel_symbols/kernel/src/cpu.rs index e1493d1d..8716a918 100644 --- a/17_kernel_symbols/kernel/src/cpu.rs +++ b/17_kernel_symbols/kernel/src/cpu.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Processor code. diff --git a/17_kernel_symbols/kernel/src/cpu/boot.rs b/17_kernel_symbols/kernel/src/cpu/boot.rs index 8091dac3..b1e98328 100644 --- a/17_kernel_symbols/kernel/src/cpu/boot.rs +++ b/17_kernel_symbols/kernel/src/cpu/boot.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2021-2022 Andre Richter +// Copyright (c) 2021-2023 Andre Richter //! Boot code. diff --git a/17_kernel_symbols/kernel/src/cpu/smp.rs b/17_kernel_symbols/kernel/src/cpu/smp.rs index 57386f79..de612d58 100644 --- a/17_kernel_symbols/kernel/src/cpu/smp.rs +++ b/17_kernel_symbols/kernel/src/cpu/smp.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Symmetric multiprocessing. diff --git a/17_kernel_symbols/kernel/src/driver.rs b/17_kernel_symbols/kernel/src/driver.rs index 18066c31..2edf8b85 100644 --- a/17_kernel_symbols/kernel/src/driver.rs +++ b/17_kernel_symbols/kernel/src/driver.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Driver support. diff --git a/17_kernel_symbols/kernel/src/exception.rs b/17_kernel_symbols/kernel/src/exception.rs index 7ea7cd80..3d5f219f 100644 --- a/17_kernel_symbols/kernel/src/exception.rs +++ b/17_kernel_symbols/kernel/src/exception.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Synchronous and asynchronous exception handling. diff --git a/17_kernel_symbols/kernel/src/exception/asynchronous.rs b/17_kernel_symbols/kernel/src/exception/asynchronous.rs index c1f2a27b..2c874dd6 100644 --- a/17_kernel_symbols/kernel/src/exception/asynchronous.rs +++ b/17_kernel_symbols/kernel/src/exception/asynchronous.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Asynchronous exception handling. diff --git a/17_kernel_symbols/kernel/src/exception/asynchronous/null_irq_manager.rs b/17_kernel_symbols/kernel/src/exception/asynchronous/null_irq_manager.rs index 438f9649..38919ffe 100644 --- a/17_kernel_symbols/kernel/src/exception/asynchronous/null_irq_manager.rs +++ b/17_kernel_symbols/kernel/src/exception/asynchronous/null_irq_manager.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2022 Andre Richter +// Copyright (c) 2022-2023 Andre Richter //! Null IRQ Manager. diff --git a/17_kernel_symbols/kernel/src/lib.rs b/17_kernel_symbols/kernel/src/lib.rs index 22572709..54e581a2 100644 --- a/17_kernel_symbols/kernel/src/lib.rs +++ b/17_kernel_symbols/kernel/src/lib.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter // Rust embedded logo for `make doc`. #![doc( diff --git a/17_kernel_symbols/kernel/src/main.rs b/17_kernel_symbols/kernel/src/main.rs index 65905258..e41cfaa0 100644 --- a/17_kernel_symbols/kernel/src/main.rs +++ b/17_kernel_symbols/kernel/src/main.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter // Rust embedded logo for `make doc`. #![doc( diff --git a/17_kernel_symbols/kernel/src/memory.rs b/17_kernel_symbols/kernel/src/memory.rs index 3b6868e7..6131bdb6 100644 --- a/17_kernel_symbols/kernel/src/memory.rs +++ b/17_kernel_symbols/kernel/src/memory.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Memory Management. diff --git a/17_kernel_symbols/kernel/src/memory/mmu.rs b/17_kernel_symbols/kernel/src/memory/mmu.rs index 7f02dad9..404e2a8a 100644 --- a/17_kernel_symbols/kernel/src/memory/mmu.rs +++ b/17_kernel_symbols/kernel/src/memory/mmu.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Memory Management Unit. diff --git a/17_kernel_symbols/kernel/src/memory/mmu/mapping_record.rs b/17_kernel_symbols/kernel/src/memory/mmu/mapping_record.rs index b893fee3..0e079220 100644 --- a/17_kernel_symbols/kernel/src/memory/mmu/mapping_record.rs +++ b/17_kernel_symbols/kernel/src/memory/mmu/mapping_record.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! A record of mapped pages. diff --git a/17_kernel_symbols/kernel/src/memory/mmu/page_alloc.rs b/17_kernel_symbols/kernel/src/memory/mmu/page_alloc.rs index 347fcd34..344afd20 100644 --- a/17_kernel_symbols/kernel/src/memory/mmu/page_alloc.rs +++ b/17_kernel_symbols/kernel/src/memory/mmu/page_alloc.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2021-2022 Andre Richter +// Copyright (c) 2021-2023 Andre Richter //! Page allocation. diff --git a/17_kernel_symbols/kernel/src/memory/mmu/translation_table.rs b/17_kernel_symbols/kernel/src/memory/mmu/translation_table.rs index 9301bb0c..341ffc5c 100644 --- a/17_kernel_symbols/kernel/src/memory/mmu/translation_table.rs +++ b/17_kernel_symbols/kernel/src/memory/mmu/translation_table.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2021-2022 Andre Richter +// Copyright (c) 2021-2023 Andre Richter //! Translation table. diff --git a/17_kernel_symbols/kernel/src/memory/mmu/types.rs b/17_kernel_symbols/kernel/src/memory/mmu/types.rs index 62f3926e..f6ac8d59 100644 --- a/17_kernel_symbols/kernel/src/memory/mmu/types.rs +++ b/17_kernel_symbols/kernel/src/memory/mmu/types.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Memory Management Unit types. diff --git a/17_kernel_symbols/kernel/src/panic_wait.rs b/17_kernel_symbols/kernel/src/panic_wait.rs index ae4651e7..c6f3a9c7 100644 --- a/17_kernel_symbols/kernel/src/panic_wait.rs +++ b/17_kernel_symbols/kernel/src/panic_wait.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! A panic handler that infinitely waits. diff --git a/17_kernel_symbols/kernel/src/print.rs b/17_kernel_symbols/kernel/src/print.rs index fe13b334..8e303046 100644 --- a/17_kernel_symbols/kernel/src/print.rs +++ b/17_kernel_symbols/kernel/src/print.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Printing. diff --git a/17_kernel_symbols/kernel/src/state.rs b/17_kernel_symbols/kernel/src/state.rs index 0af3688c..6d99beed 100644 --- a/17_kernel_symbols/kernel/src/state.rs +++ b/17_kernel_symbols/kernel/src/state.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! State information about the kernel itself. diff --git a/17_kernel_symbols/kernel/src/symbols.rs b/17_kernel_symbols/kernel/src/symbols.rs index 680b8eaf..fdc1d084 100644 --- a/17_kernel_symbols/kernel/src/symbols.rs +++ b/17_kernel_symbols/kernel/src/symbols.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2022 Andre Richter +// Copyright (c) 2022-2023 Andre Richter //! Debug symbol support. diff --git a/17_kernel_symbols/kernel/src/synchronization.rs b/17_kernel_symbols/kernel/src/synchronization.rs index ab2b86e6..5740b63e 100644 --- a/17_kernel_symbols/kernel/src/synchronization.rs +++ b/17_kernel_symbols/kernel/src/synchronization.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Synchronization primitives. //! diff --git a/17_kernel_symbols/kernel/src/time.rs b/17_kernel_symbols/kernel/src/time.rs index a6c0c5b6..a9d50120 100644 --- a/17_kernel_symbols/kernel/src/time.rs +++ b/17_kernel_symbols/kernel/src/time.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Timer primitives. diff --git a/17_kernel_symbols/kernel/tests/00_console_sanity.rb b/17_kernel_symbols/kernel/tests/00_console_sanity.rb index 4dde5576..8be7a2f1 100644 --- a/17_kernel_symbols/kernel/tests/00_console_sanity.rb +++ b/17_kernel_symbols/kernel/tests/00_console_sanity.rb @@ -2,7 +2,7 @@ # SPDX-License-Identifier: MIT OR Apache-2.0 # -# Copyright (c) 2019-2022 Andre Richter +# Copyright (c) 2019-2023 Andre Richter require 'console_io_test' @@ -40,9 +40,9 @@ class RxStatisticsTest < SubtestBase end end -##-------------------------------------------------------------------------------------------------- +## ------------------------------------------------------------------------------------------------- ## Test registration -##-------------------------------------------------------------------------------------------------- +## ------------------------------------------------------------------------------------------------- def subtest_collection [TxRxHandshakeTest.new, TxStatisticsTest.new, RxStatisticsTest.new] end diff --git a/17_kernel_symbols/kernel/tests/00_console_sanity.rs b/17_kernel_symbols/kernel/tests/00_console_sanity.rs index 2c0225b7..682ea9b8 100644 --- a/17_kernel_symbols/kernel/tests/00_console_sanity.rs +++ b/17_kernel_symbols/kernel/tests/00_console_sanity.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2019-2022 Andre Richter +// Copyright (c) 2019-2023 Andre Richter //! Console sanity tests - RX, TX and statistics. diff --git a/17_kernel_symbols/kernel/tests/01_timer_sanity.rs b/17_kernel_symbols/kernel/tests/01_timer_sanity.rs index 8188b942..1581a02e 100644 --- a/17_kernel_symbols/kernel/tests/01_timer_sanity.rs +++ b/17_kernel_symbols/kernel/tests/01_timer_sanity.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2019-2022 Andre Richter +// Copyright (c) 2019-2023 Andre Richter //! Timer sanity tests. diff --git a/17_kernel_symbols/kernel/tests/02_exception_sync_page_fault.rs b/17_kernel_symbols/kernel/tests/02_exception_sync_page_fault.rs index fab44c8f..09d17798 100644 --- a/17_kernel_symbols/kernel/tests/02_exception_sync_page_fault.rs +++ b/17_kernel_symbols/kernel/tests/02_exception_sync_page_fault.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2019-2022 Andre Richter +// Copyright (c) 2019-2023 Andre Richter //! Page faults must result in synchronous exceptions. diff --git a/17_kernel_symbols/kernel/tests/03_exception_restore_sanity.rb b/17_kernel_symbols/kernel/tests/03_exception_restore_sanity.rb index 5f52e0c7..02f51f74 100644 --- a/17_kernel_symbols/kernel/tests/03_exception_restore_sanity.rb +++ b/17_kernel_symbols/kernel/tests/03_exception_restore_sanity.rb @@ -2,7 +2,7 @@ # SPDX-License-Identifier: MIT OR Apache-2.0 # -# Copyright (c) 2022 Andre Richter +# Copyright (c) 2022-2023 Andre Richter require 'console_io_test' @@ -17,9 +17,9 @@ class ExceptionRestoreTest < SubtestBase end end -##-------------------------------------------------------------------------------------------------- +## ------------------------------------------------------------------------------------------------- ## Test registration -##-------------------------------------------------------------------------------------------------- +## ------------------------------------------------------------------------------------------------- def subtest_collection [ExceptionRestoreTest.new] end diff --git a/17_kernel_symbols/kernel/tests/03_exception_restore_sanity.rs b/17_kernel_symbols/kernel/tests/03_exception_restore_sanity.rs index f176c6a6..1a302911 100644 --- a/17_kernel_symbols/kernel/tests/03_exception_restore_sanity.rs +++ b/17_kernel_symbols/kernel/tests/03_exception_restore_sanity.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2022 Andre Richter +// Copyright (c) 2022-2023 Andre Richter //! A simple sanity test to see if exception restore code works. diff --git a/17_kernel_symbols/kernel/tests/04_exception_irq_sanity.rs b/17_kernel_symbols/kernel/tests/04_exception_irq_sanity.rs index e6f94c91..fcace897 100644 --- a/17_kernel_symbols/kernel/tests/04_exception_irq_sanity.rs +++ b/17_kernel_symbols/kernel/tests/04_exception_irq_sanity.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! IRQ handling sanity tests. diff --git a/17_kernel_symbols/kernel/tests/panic_exit_success/mod.rs b/17_kernel_symbols/kernel/tests/panic_exit_success/mod.rs index 908fac51..449ad6f9 100644 --- a/17_kernel_symbols/kernel/tests/panic_exit_success/mod.rs +++ b/17_kernel_symbols/kernel/tests/panic_exit_success/mod.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2019-2022 Andre Richter +// Copyright (c) 2019-2023 Andre Richter /// Overwrites libkernel's `panic_wait::_panic_exit()` with the QEMU-exit version. #[no_mangle] diff --git a/17_kernel_symbols/kernel/tests/panic_wait_forever/mod.rs b/17_kernel_symbols/kernel/tests/panic_wait_forever/mod.rs index 7a4effa5..9ac19144 100644 --- a/17_kernel_symbols/kernel/tests/panic_wait_forever/mod.rs +++ b/17_kernel_symbols/kernel/tests/panic_wait_forever/mod.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2022 Andre Richter +// Copyright (c) 2022-2023 Andre Richter /// Overwrites libkernel's `panic_wait::_panic_exit()` with wait_forever. #[no_mangle] diff --git a/17_kernel_symbols/kernel_symbols.mk b/17_kernel_symbols/kernel_symbols.mk index d496ea8a..d38b7785 100644 --- a/17_kernel_symbols/kernel_symbols.mk +++ b/17_kernel_symbols/kernel_symbols.mk @@ -1,6 +1,6 @@ ## SPDX-License-Identifier: MIT OR Apache-2.0 ## -## Copyright (c) 2018-2022 Andre Richter +## Copyright (c) 2018-2023 Andre Richter include ../common/format.mk include ../common/docker.mk diff --git a/17_kernel_symbols/kernel_symbols/src/main.rs b/17_kernel_symbols/kernel_symbols/src/main.rs index bd90b535..38ce18f8 100644 --- a/17_kernel_symbols/kernel_symbols/src/main.rs +++ b/17_kernel_symbols/kernel_symbols/src/main.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2022 Andre Richter +// Copyright (c) 2022-2023 Andre Richter //! Generation of kernel symbols. diff --git a/17_kernel_symbols/libraries/debug-symbol-types/src/lib.rs b/17_kernel_symbols/libraries/debug-symbol-types/src/lib.rs index b6dff082..81c897bf 100644 --- a/17_kernel_symbols/libraries/debug-symbol-types/src/lib.rs +++ b/17_kernel_symbols/libraries/debug-symbol-types/src/lib.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2022 Andre Richter +// Copyright (c) 2022-2023 Andre Richter //! Types for implementing debug symbol support. diff --git a/17_kernel_symbols/libraries/test-macros/src/lib.rs b/17_kernel_symbols/libraries/test-macros/src/lib.rs index 9879677c..52cf893d 100644 --- a/17_kernel_symbols/libraries/test-macros/src/lib.rs +++ b/17_kernel_symbols/libraries/test-macros/src/lib.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2019-2022 Andre Richter +// Copyright (c) 2019-2023 Andre Richter use proc_macro::TokenStream; use proc_macro2::Span; diff --git a/17_kernel_symbols/libraries/test-types/src/lib.rs b/17_kernel_symbols/libraries/test-types/src/lib.rs index 922c2a1c..38961a9c 100644 --- a/17_kernel_symbols/libraries/test-types/src/lib.rs +++ b/17_kernel_symbols/libraries/test-types/src/lib.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2019-2022 Andre Richter +// Copyright (c) 2019-2023 Andre Richter //! Types for the `custom_test_frameworks` implementation. diff --git a/17_kernel_symbols/tools/kernel_symbols_tool/cmds.rb b/17_kernel_symbols/tools/kernel_symbols_tool/cmds.rb index fe66ea71..c43acb24 100644 --- a/17_kernel_symbols/tools/kernel_symbols_tool/cmds.rb +++ b/17_kernel_symbols/tools/kernel_symbols_tool/cmds.rb @@ -2,7 +2,7 @@ # SPDX-License-Identifier: MIT OR Apache-2.0 # -# Copyright (c) 2022 Andre Richter +# Copyright (c) 2022-2023 Andre Richter def generate_symbols(kernel_elf, output_file) File.open(output_file, 'w') do |file| diff --git a/17_kernel_symbols/tools/kernel_symbols_tool/kernel_elf.rb b/17_kernel_symbols/tools/kernel_symbols_tool/kernel_elf.rb index b1649767..32b5460a 100644 --- a/17_kernel_symbols/tools/kernel_symbols_tool/kernel_elf.rb +++ b/17_kernel_symbols/tools/kernel_symbols_tool/kernel_elf.rb @@ -2,7 +2,7 @@ # SPDX-License-Identifier: MIT OR Apache-2.0 # -# Copyright (c) 2021-2022 Andre Richter +# Copyright (c) 2021-2023 Andre Richter # KernelELF class KernelELF diff --git a/17_kernel_symbols/tools/kernel_symbols_tool/main.rb b/17_kernel_symbols/tools/kernel_symbols_tool/main.rb index 30a8be6f..899f9646 100755 --- a/17_kernel_symbols/tools/kernel_symbols_tool/main.rb +++ b/17_kernel_symbols/tools/kernel_symbols_tool/main.rb @@ -3,7 +3,7 @@ # SPDX-License-Identifier: MIT OR Apache-2.0 # -# Copyright (c) 2022 Andre Richter +# Copyright (c) 2022-2023 Andre Richter require 'rubygems' require 'bundler/setup' diff --git a/17_kernel_symbols/tools/translation_table_tool/arch.rb b/17_kernel_symbols/tools/translation_table_tool/arch.rb index deceb6d0..61a6d6ca 100644 --- a/17_kernel_symbols/tools/translation_table_tool/arch.rb +++ b/17_kernel_symbols/tools/translation_table_tool/arch.rb @@ -2,7 +2,7 @@ # SPDX-License-Identifier: MIT OR Apache-2.0 # -# Copyright (c) 2021-2022 Andre Richter +# Copyright (c) 2021-2023 Andre Richter # Bitfield manipulation. class BitField diff --git a/17_kernel_symbols/tools/translation_table_tool/bsp.rb b/17_kernel_symbols/tools/translation_table_tool/bsp.rb index 536a2f21..93bcedd9 100644 --- a/17_kernel_symbols/tools/translation_table_tool/bsp.rb +++ b/17_kernel_symbols/tools/translation_table_tool/bsp.rb @@ -2,7 +2,7 @@ # SPDX-License-Identifier: MIT OR Apache-2.0 # -# Copyright (c) 2021-2022 Andre Richter +# Copyright (c) 2021-2023 Andre Richter # Raspberry Pi 3 + 4 class RaspberryPi diff --git a/17_kernel_symbols/tools/translation_table_tool/generic.rb b/17_kernel_symbols/tools/translation_table_tool/generic.rb index 13df0658..743840e0 100644 --- a/17_kernel_symbols/tools/translation_table_tool/generic.rb +++ b/17_kernel_symbols/tools/translation_table_tool/generic.rb @@ -2,7 +2,7 @@ # SPDX-License-Identifier: MIT OR Apache-2.0 # -# Copyright (c) 2021-2022 Andre Richter +# Copyright (c) 2021-2023 Andre Richter module Granule64KiB SIZE = 64 * 1024 @@ -151,7 +151,7 @@ def kernel_map_binary mapping_descriptors.each do |i| print 'Generating'.rjust(12).green.bold print ' ' - puts i.to_s + puts i TRANSLATION_TABLES.map_at(i.virt_region, i.phys_region, i.attributes) end diff --git a/17_kernel_symbols/tools/translation_table_tool/kernel_elf.rb b/17_kernel_symbols/tools/translation_table_tool/kernel_elf.rb index f2d5b0b7..5ba78d9d 100644 --- a/17_kernel_symbols/tools/translation_table_tool/kernel_elf.rb +++ b/17_kernel_symbols/tools/translation_table_tool/kernel_elf.rb @@ -2,7 +2,7 @@ # SPDX-License-Identifier: MIT OR Apache-2.0 # -# Copyright (c) 2021-2022 Andre Richter +# Copyright (c) 2021-2023 Andre Richter # KernelELF class KernelELF diff --git a/17_kernel_symbols/tools/translation_table_tool/main.rb b/17_kernel_symbols/tools/translation_table_tool/main.rb index 6419e364..22ab24fd 100755 --- a/17_kernel_symbols/tools/translation_table_tool/main.rb +++ b/17_kernel_symbols/tools/translation_table_tool/main.rb @@ -3,7 +3,7 @@ # SPDX-License-Identifier: MIT OR Apache-2.0 # -# Copyright (c) 2021-2022 Andre Richter +# Copyright (c) 2021-2023 Andre Richter require 'rubygems' require 'bundler/setup' diff --git a/18_backtrace/.vscode/settings.json b/18_backtrace/.vscode/settings.json index 292bf2a9..9ef30cd0 100644 --- a/18_backtrace/.vscode/settings.json +++ b/18_backtrace/.vscode/settings.json @@ -1,10 +1,10 @@ { - "editor.formatOnSave": true, - "editor.rulers": [100], - "rust-analyzer.cargo.target": "aarch64-unknown-none-softfloat", - "rust-analyzer.cargo.features": ["bsp_rpi3"], - "rust-analyzer.checkOnSave.allTargets": false, - "rust-analyzer.checkOnSave.extraArgs": ["--lib", "--bins"], - "rust-analyzer.lens.debug": false, - "rust-analyzer.lens.run": false + "editor.formatOnSave": true, + "editor.rulers": [100], + "rust-analyzer.cargo.target": "aarch64-unknown-none-softfloat", + "rust-analyzer.cargo.features": ["bsp_rpi3"], + "rust-analyzer.checkOnSave.allTargets": false, + "rust-analyzer.checkOnSave.extraArgs": ["--lib", "--bins"], + "rust-analyzer.lens.debug": false, + "rust-analyzer.lens.run": false } diff --git a/18_backtrace/Makefile b/18_backtrace/Makefile index fbd96e64..7edf4edf 100644 --- a/18_backtrace/Makefile +++ b/18_backtrace/Makefile @@ -1,6 +1,6 @@ ## SPDX-License-Identifier: MIT OR Apache-2.0 ## -## Copyright (c) 2018-2022 Andre Richter +## Copyright (c) 2018-2023 Andre Richter include ../common/docker.mk include ../common/format.mk diff --git a/18_backtrace/README.md b/18_backtrace/README.md index 542fdfbb..00a156d7 100644 --- a/18_backtrace/README.md +++ b/18_backtrace/README.md @@ -400,7 +400,7 @@ diff -uNr 17_kernel_symbols/kernel/src/_arch/aarch64/backtrace.rs 18_backtrace/k @@ -0,0 +1,136 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// -+// Copyright (c) 2022 Andre Richter ++// Copyright (c) 2022-2023 Andre Richter + +//! Architectural backtracing support. +//! @@ -728,7 +728,7 @@ diff -uNr 17_kernel_symbols/kernel/src/backtrace.rs 18_backtrace/kernel/src/back @@ -0,0 +1,114 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// -+// Copyright (c) 2022 Andre Richter ++// Copyright (c) 2022-2023 Andre Richter + +//! Backtracing support. + @@ -1010,7 +1010,7 @@ diff -uNr 17_kernel_symbols/kernel/tests/05_backtrace_sanity.rb 18_backtrace/ker + +# SPDX-License-Identifier: MIT OR Apache-2.0 +# -+# Copyright (c) 2022 Andre Richter ++# Copyright (c) 2022-2023 Andre Richter + +require 'console_io_test' + @@ -1052,7 +1052,7 @@ diff -uNr 17_kernel_symbols/kernel/tests/05_backtrace_sanity.rs 18_backtrace/ker @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// -+// Copyright (c) 2022 Andre Richter ++// Copyright (c) 2022-2023 Andre Richter + +//! Test if backtracing code detects an invalid frame pointer. + @@ -1090,7 +1090,7 @@ diff -uNr 17_kernel_symbols/kernel/tests/06_backtrace_invalid_frame.rb 18_backtr + +# SPDX-License-Identifier: MIT OR Apache-2.0 +# -+# Copyright (c) 2022 Andre Richter ++# Copyright (c) 2022-2023 Andre Richter + +require 'console_io_test' + @@ -1119,7 +1119,7 @@ diff -uNr 17_kernel_symbols/kernel/tests/06_backtrace_invalid_frame.rs 18_backtr @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// -+// Copyright (c) 2022 Andre Richter ++// Copyright (c) 2022-2023 Andre Richter + +//! Test if backtracing code detects an invalid frame pointer. + @@ -1159,7 +1159,7 @@ diff -uNr 17_kernel_symbols/kernel/tests/07_backtrace_invalid_link.rb 18_backtra + +# SPDX-License-Identifier: MIT OR Apache-2.0 +# -+# Copyright (c) 2022 Andre Richter ++# Copyright (c) 2022-2023 Andre Richter + +require 'console_io_test' + @@ -1187,7 +1187,7 @@ diff -uNr 17_kernel_symbols/kernel/tests/07_backtrace_invalid_link.rs 18_backtra @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// -+// Copyright (c) 2022 Andre Richter ++// Copyright (c) 2022-2023 Andre Richter + +//! Test if backtracing code detects an invalid link. + diff --git a/18_backtrace/kernel/src/_arch/aarch64/backtrace.rs b/18_backtrace/kernel/src/_arch/aarch64/backtrace.rs index 3511c918..c2fb8dcb 100644 --- a/18_backtrace/kernel/src/_arch/aarch64/backtrace.rs +++ b/18_backtrace/kernel/src/_arch/aarch64/backtrace.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2022 Andre Richter +// Copyright (c) 2022-2023 Andre Richter //! Architectural backtracing support. //! diff --git a/18_backtrace/kernel/src/_arch/aarch64/cpu.rs b/18_backtrace/kernel/src/_arch/aarch64/cpu.rs index 7eb7f010..2d010473 100644 --- a/18_backtrace/kernel/src/_arch/aarch64/cpu.rs +++ b/18_backtrace/kernel/src/_arch/aarch64/cpu.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Architectural processor code. //! diff --git a/18_backtrace/kernel/src/_arch/aarch64/cpu/boot.rs b/18_backtrace/kernel/src/_arch/aarch64/cpu/boot.rs index d9662d3a..b8033fbe 100644 --- a/18_backtrace/kernel/src/_arch/aarch64/cpu/boot.rs +++ b/18_backtrace/kernel/src/_arch/aarch64/cpu/boot.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2021-2022 Andre Richter +// Copyright (c) 2021-2023 Andre Richter //! Architectural boot code. //! diff --git a/18_backtrace/kernel/src/_arch/aarch64/cpu/boot.s b/18_backtrace/kernel/src/_arch/aarch64/cpu/boot.s index 1a8c8801..65d71b1a 100644 --- a/18_backtrace/kernel/src/_arch/aarch64/cpu/boot.s +++ b/18_backtrace/kernel/src/_arch/aarch64/cpu/boot.s @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2021-2022 Andre Richter +// Copyright (c) 2021-2023 Andre Richter //-------------------------------------------------------------------------------------------------- // Definitions diff --git a/18_backtrace/kernel/src/_arch/aarch64/cpu/smp.rs b/18_backtrace/kernel/src/_arch/aarch64/cpu/smp.rs index 9d304d65..49192038 100644 --- a/18_backtrace/kernel/src/_arch/aarch64/cpu/smp.rs +++ b/18_backtrace/kernel/src/_arch/aarch64/cpu/smp.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Architectural symmetric multiprocessing. //! diff --git a/18_backtrace/kernel/src/_arch/aarch64/exception.rs b/18_backtrace/kernel/src/_arch/aarch64/exception.rs index a8bc0d2f..ab464081 100644 --- a/18_backtrace/kernel/src/_arch/aarch64/exception.rs +++ b/18_backtrace/kernel/src/_arch/aarch64/exception.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Architectural synchronous and asynchronous exception handling. //! diff --git a/18_backtrace/kernel/src/_arch/aarch64/exception/asynchronous.rs b/18_backtrace/kernel/src/_arch/aarch64/exception/asynchronous.rs index f545a3e1..811ef138 100644 --- a/18_backtrace/kernel/src/_arch/aarch64/exception/asynchronous.rs +++ b/18_backtrace/kernel/src/_arch/aarch64/exception/asynchronous.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Architectural asynchronous exception handling. //! diff --git a/18_backtrace/kernel/src/_arch/aarch64/memory/mmu.rs b/18_backtrace/kernel/src/_arch/aarch64/memory/mmu.rs index 74a71d11..984b2e04 100644 --- a/18_backtrace/kernel/src/_arch/aarch64/memory/mmu.rs +++ b/18_backtrace/kernel/src/_arch/aarch64/memory/mmu.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Memory Management Unit Driver. //! diff --git a/18_backtrace/kernel/src/_arch/aarch64/memory/mmu/translation_table.rs b/18_backtrace/kernel/src/_arch/aarch64/memory/mmu/translation_table.rs index f0b4ac85..21fae3b8 100644 --- a/18_backtrace/kernel/src/_arch/aarch64/memory/mmu/translation_table.rs +++ b/18_backtrace/kernel/src/_arch/aarch64/memory/mmu/translation_table.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2021-2022 Andre Richter +// Copyright (c) 2021-2023 Andre Richter //! Architectural translation table. //! diff --git a/18_backtrace/kernel/src/_arch/aarch64/time.rs b/18_backtrace/kernel/src/_arch/aarch64/time.rs index 94d02379..ee1c3ef7 100644 --- a/18_backtrace/kernel/src/_arch/aarch64/time.rs +++ b/18_backtrace/kernel/src/_arch/aarch64/time.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Architectural timer primitives. //! diff --git a/18_backtrace/kernel/src/backtrace.rs b/18_backtrace/kernel/src/backtrace.rs index 22de6c48..a6af2fcc 100644 --- a/18_backtrace/kernel/src/backtrace.rs +++ b/18_backtrace/kernel/src/backtrace.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2022 Andre Richter +// Copyright (c) 2022-2023 Andre Richter //! Backtracing support. diff --git a/18_backtrace/kernel/src/bsp.rs b/18_backtrace/kernel/src/bsp.rs index 824787f6..246973bc 100644 --- a/18_backtrace/kernel/src/bsp.rs +++ b/18_backtrace/kernel/src/bsp.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Conditional reexporting of Board Support Packages. diff --git a/18_backtrace/kernel/src/bsp/device_driver.rs b/18_backtrace/kernel/src/bsp/device_driver.rs index eafaf775..2dfaec8d 100644 --- a/18_backtrace/kernel/src/bsp/device_driver.rs +++ b/18_backtrace/kernel/src/bsp/device_driver.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Device driver. diff --git a/18_backtrace/kernel/src/bsp/device_driver/arm.rs b/18_backtrace/kernel/src/bsp/device_driver/arm.rs index e83e24c9..8d1cbfbd 100644 --- a/18_backtrace/kernel/src/bsp/device_driver/arm.rs +++ b/18_backtrace/kernel/src/bsp/device_driver/arm.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! ARM driver top level. diff --git a/18_backtrace/kernel/src/bsp/device_driver/arm/gicv2.rs b/18_backtrace/kernel/src/bsp/device_driver/arm/gicv2.rs index 3cc35b5e..256de704 100644 --- a/18_backtrace/kernel/src/bsp/device_driver/arm/gicv2.rs +++ b/18_backtrace/kernel/src/bsp/device_driver/arm/gicv2.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! GICv2 Driver - ARM Generic Interrupt Controller v2. //! diff --git a/18_backtrace/kernel/src/bsp/device_driver/arm/gicv2/gicc.rs b/18_backtrace/kernel/src/bsp/device_driver/arm/gicv2/gicc.rs index 1a02fc65..0fd16bb3 100644 --- a/18_backtrace/kernel/src/bsp/device_driver/arm/gicv2/gicc.rs +++ b/18_backtrace/kernel/src/bsp/device_driver/arm/gicv2/gicc.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! GICC Driver - GIC CPU interface. diff --git a/18_backtrace/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs b/18_backtrace/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs index 8aebcf2b..1fc9d70e 100644 --- a/18_backtrace/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs +++ b/18_backtrace/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! GICD Driver - GIC Distributor. //! diff --git a/18_backtrace/kernel/src/bsp/device_driver/bcm.rs b/18_backtrace/kernel/src/bsp/device_driver/bcm.rs index 5a7cc23b..7b7c288b 100644 --- a/18_backtrace/kernel/src/bsp/device_driver/bcm.rs +++ b/18_backtrace/kernel/src/bsp/device_driver/bcm.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! BCM driver top level. diff --git a/18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs b/18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs index fb61a651..812156f4 100644 --- a/18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs +++ b/18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! GPIO Driver. diff --git a/18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs b/18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs index c93a9fa1..62f07800 100644 --- a/18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs +++ b/18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Interrupt Controller Driver. diff --git a/18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs b/18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs index 0a20bd87..a26bff8d 100644 --- a/18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs +++ b/18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Peripheral Interrupt Controller Driver. //! diff --git a/18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs b/18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs index 0ee7feb7..b424d4be 100644 --- a/18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs +++ b/18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! PL011 UART driver. //! diff --git a/18_backtrace/kernel/src/bsp/device_driver/common.rs b/18_backtrace/kernel/src/bsp/device_driver/common.rs index ca7aeb76..3ce1d8d8 100644 --- a/18_backtrace/kernel/src/bsp/device_driver/common.rs +++ b/18_backtrace/kernel/src/bsp/device_driver/common.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Common device driver code. diff --git a/18_backtrace/kernel/src/bsp/raspberrypi.rs b/18_backtrace/kernel/src/bsp/raspberrypi.rs index 474419f4..30421dfa 100644 --- a/18_backtrace/kernel/src/bsp/raspberrypi.rs +++ b/18_backtrace/kernel/src/bsp/raspberrypi.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Top-level BSP file for the Raspberry Pi 3 and 4. diff --git a/18_backtrace/kernel/src/bsp/raspberrypi/cpu.rs b/18_backtrace/kernel/src/bsp/raspberrypi/cpu.rs index 85fb89e4..65cf5abb 100644 --- a/18_backtrace/kernel/src/bsp/raspberrypi/cpu.rs +++ b/18_backtrace/kernel/src/bsp/raspberrypi/cpu.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! BSP Processor code. diff --git a/18_backtrace/kernel/src/bsp/raspberrypi/driver.rs b/18_backtrace/kernel/src/bsp/raspberrypi/driver.rs index ca3435aa..a1f55b17 100644 --- a/18_backtrace/kernel/src/bsp/raspberrypi/driver.rs +++ b/18_backtrace/kernel/src/bsp/raspberrypi/driver.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! BSP driver support. diff --git a/18_backtrace/kernel/src/bsp/raspberrypi/exception.rs b/18_backtrace/kernel/src/bsp/raspberrypi/exception.rs index aa6c5a63..a9eaa6ac 100644 --- a/18_backtrace/kernel/src/bsp/raspberrypi/exception.rs +++ b/18_backtrace/kernel/src/bsp/raspberrypi/exception.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! BSP synchronous and asynchronous exception handling. diff --git a/18_backtrace/kernel/src/bsp/raspberrypi/exception/asynchronous.rs b/18_backtrace/kernel/src/bsp/raspberrypi/exception/asynchronous.rs index 06a67558..776182fd 100644 --- a/18_backtrace/kernel/src/bsp/raspberrypi/exception/asynchronous.rs +++ b/18_backtrace/kernel/src/bsp/raspberrypi/exception/asynchronous.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! BSP asynchronous exception handling. diff --git a/18_backtrace/kernel/src/bsp/raspberrypi/memory.rs b/18_backtrace/kernel/src/bsp/raspberrypi/memory.rs index 32416e6c..96a4d8c1 100644 --- a/18_backtrace/kernel/src/bsp/raspberrypi/memory.rs +++ b/18_backtrace/kernel/src/bsp/raspberrypi/memory.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! BSP Memory Management. //! diff --git a/18_backtrace/kernel/src/bsp/raspberrypi/memory/mmu.rs b/18_backtrace/kernel/src/bsp/raspberrypi/memory/mmu.rs index 160c188f..c6263245 100644 --- a/18_backtrace/kernel/src/bsp/raspberrypi/memory/mmu.rs +++ b/18_backtrace/kernel/src/bsp/raspberrypi/memory/mmu.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! BSP Memory Management Unit. diff --git a/18_backtrace/kernel/src/common.rs b/18_backtrace/kernel/src/common.rs index f32f650f..2ad7e4c1 100644 --- a/18_backtrace/kernel/src/common.rs +++ b/18_backtrace/kernel/src/common.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! General purpose code. diff --git a/18_backtrace/kernel/src/console.rs b/18_backtrace/kernel/src/console.rs index a85bcffe..f0363464 100644 --- a/18_backtrace/kernel/src/console.rs +++ b/18_backtrace/kernel/src/console.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! System console. diff --git a/18_backtrace/kernel/src/console/null_console.rs b/18_backtrace/kernel/src/console/null_console.rs index 2c64d499..e92a022b 100644 --- a/18_backtrace/kernel/src/console/null_console.rs +++ b/18_backtrace/kernel/src/console/null_console.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2022 Andre Richter +// Copyright (c) 2022-2023 Andre Richter //! Null console. diff --git a/18_backtrace/kernel/src/cpu.rs b/18_backtrace/kernel/src/cpu.rs index e1493d1d..8716a918 100644 --- a/18_backtrace/kernel/src/cpu.rs +++ b/18_backtrace/kernel/src/cpu.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Processor code. diff --git a/18_backtrace/kernel/src/cpu/boot.rs b/18_backtrace/kernel/src/cpu/boot.rs index 8091dac3..b1e98328 100644 --- a/18_backtrace/kernel/src/cpu/boot.rs +++ b/18_backtrace/kernel/src/cpu/boot.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2021-2022 Andre Richter +// Copyright (c) 2021-2023 Andre Richter //! Boot code. diff --git a/18_backtrace/kernel/src/cpu/smp.rs b/18_backtrace/kernel/src/cpu/smp.rs index 57386f79..de612d58 100644 --- a/18_backtrace/kernel/src/cpu/smp.rs +++ b/18_backtrace/kernel/src/cpu/smp.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Symmetric multiprocessing. diff --git a/18_backtrace/kernel/src/driver.rs b/18_backtrace/kernel/src/driver.rs index 18066c31..2edf8b85 100644 --- a/18_backtrace/kernel/src/driver.rs +++ b/18_backtrace/kernel/src/driver.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Driver support. diff --git a/18_backtrace/kernel/src/exception.rs b/18_backtrace/kernel/src/exception.rs index 7ea7cd80..3d5f219f 100644 --- a/18_backtrace/kernel/src/exception.rs +++ b/18_backtrace/kernel/src/exception.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Synchronous and asynchronous exception handling. diff --git a/18_backtrace/kernel/src/exception/asynchronous.rs b/18_backtrace/kernel/src/exception/asynchronous.rs index c1f2a27b..2c874dd6 100644 --- a/18_backtrace/kernel/src/exception/asynchronous.rs +++ b/18_backtrace/kernel/src/exception/asynchronous.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Asynchronous exception handling. diff --git a/18_backtrace/kernel/src/exception/asynchronous/null_irq_manager.rs b/18_backtrace/kernel/src/exception/asynchronous/null_irq_manager.rs index 438f9649..38919ffe 100644 --- a/18_backtrace/kernel/src/exception/asynchronous/null_irq_manager.rs +++ b/18_backtrace/kernel/src/exception/asynchronous/null_irq_manager.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2022 Andre Richter +// Copyright (c) 2022-2023 Andre Richter //! Null IRQ Manager. diff --git a/18_backtrace/kernel/src/lib.rs b/18_backtrace/kernel/src/lib.rs index 5b79ebfe..512894f7 100644 --- a/18_backtrace/kernel/src/lib.rs +++ b/18_backtrace/kernel/src/lib.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter // Rust embedded logo for `make doc`. #![doc( diff --git a/18_backtrace/kernel/src/main.rs b/18_backtrace/kernel/src/main.rs index 65905258..e41cfaa0 100644 --- a/18_backtrace/kernel/src/main.rs +++ b/18_backtrace/kernel/src/main.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter // Rust embedded logo for `make doc`. #![doc( diff --git a/18_backtrace/kernel/src/memory.rs b/18_backtrace/kernel/src/memory.rs index 840db396..0434b13c 100644 --- a/18_backtrace/kernel/src/memory.rs +++ b/18_backtrace/kernel/src/memory.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Memory Management. diff --git a/18_backtrace/kernel/src/memory/mmu.rs b/18_backtrace/kernel/src/memory/mmu.rs index 7f02dad9..404e2a8a 100644 --- a/18_backtrace/kernel/src/memory/mmu.rs +++ b/18_backtrace/kernel/src/memory/mmu.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Memory Management Unit. diff --git a/18_backtrace/kernel/src/memory/mmu/mapping_record.rs b/18_backtrace/kernel/src/memory/mmu/mapping_record.rs index b893fee3..0e079220 100644 --- a/18_backtrace/kernel/src/memory/mmu/mapping_record.rs +++ b/18_backtrace/kernel/src/memory/mmu/mapping_record.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! A record of mapped pages. diff --git a/18_backtrace/kernel/src/memory/mmu/page_alloc.rs b/18_backtrace/kernel/src/memory/mmu/page_alloc.rs index 347fcd34..344afd20 100644 --- a/18_backtrace/kernel/src/memory/mmu/page_alloc.rs +++ b/18_backtrace/kernel/src/memory/mmu/page_alloc.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2021-2022 Andre Richter +// Copyright (c) 2021-2023 Andre Richter //! Page allocation. diff --git a/18_backtrace/kernel/src/memory/mmu/translation_table.rs b/18_backtrace/kernel/src/memory/mmu/translation_table.rs index 9301bb0c..341ffc5c 100644 --- a/18_backtrace/kernel/src/memory/mmu/translation_table.rs +++ b/18_backtrace/kernel/src/memory/mmu/translation_table.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2021-2022 Andre Richter +// Copyright (c) 2021-2023 Andre Richter //! Translation table. diff --git a/18_backtrace/kernel/src/memory/mmu/types.rs b/18_backtrace/kernel/src/memory/mmu/types.rs index 62f3926e..f6ac8d59 100644 --- a/18_backtrace/kernel/src/memory/mmu/types.rs +++ b/18_backtrace/kernel/src/memory/mmu/types.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Memory Management Unit types. diff --git a/18_backtrace/kernel/src/panic_wait.rs b/18_backtrace/kernel/src/panic_wait.rs index bc95f77c..389eb2c8 100644 --- a/18_backtrace/kernel/src/panic_wait.rs +++ b/18_backtrace/kernel/src/panic_wait.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! A panic handler that infinitely waits. diff --git a/18_backtrace/kernel/src/print.rs b/18_backtrace/kernel/src/print.rs index fe13b334..8e303046 100644 --- a/18_backtrace/kernel/src/print.rs +++ b/18_backtrace/kernel/src/print.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Printing. diff --git a/18_backtrace/kernel/src/state.rs b/18_backtrace/kernel/src/state.rs index 6a261b34..becdd1b6 100644 --- a/18_backtrace/kernel/src/state.rs +++ b/18_backtrace/kernel/src/state.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! State information about the kernel itself. diff --git a/18_backtrace/kernel/src/symbols.rs b/18_backtrace/kernel/src/symbols.rs index 680b8eaf..fdc1d084 100644 --- a/18_backtrace/kernel/src/symbols.rs +++ b/18_backtrace/kernel/src/symbols.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2022 Andre Richter +// Copyright (c) 2022-2023 Andre Richter //! Debug symbol support. diff --git a/18_backtrace/kernel/src/synchronization.rs b/18_backtrace/kernel/src/synchronization.rs index ab2b86e6..5740b63e 100644 --- a/18_backtrace/kernel/src/synchronization.rs +++ b/18_backtrace/kernel/src/synchronization.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Synchronization primitives. //! diff --git a/18_backtrace/kernel/src/time.rs b/18_backtrace/kernel/src/time.rs index a6c0c5b6..a9d50120 100644 --- a/18_backtrace/kernel/src/time.rs +++ b/18_backtrace/kernel/src/time.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Timer primitives. diff --git a/18_backtrace/kernel/tests/00_console_sanity.rb b/18_backtrace/kernel/tests/00_console_sanity.rb index 4dde5576..8be7a2f1 100644 --- a/18_backtrace/kernel/tests/00_console_sanity.rb +++ b/18_backtrace/kernel/tests/00_console_sanity.rb @@ -2,7 +2,7 @@ # SPDX-License-Identifier: MIT OR Apache-2.0 # -# Copyright (c) 2019-2022 Andre Richter +# Copyright (c) 2019-2023 Andre Richter require 'console_io_test' @@ -40,9 +40,9 @@ class RxStatisticsTest < SubtestBase end end -##-------------------------------------------------------------------------------------------------- +## ------------------------------------------------------------------------------------------------- ## Test registration -##-------------------------------------------------------------------------------------------------- +## ------------------------------------------------------------------------------------------------- def subtest_collection [TxRxHandshakeTest.new, TxStatisticsTest.new, RxStatisticsTest.new] end diff --git a/18_backtrace/kernel/tests/00_console_sanity.rs b/18_backtrace/kernel/tests/00_console_sanity.rs index 2c0225b7..682ea9b8 100644 --- a/18_backtrace/kernel/tests/00_console_sanity.rs +++ b/18_backtrace/kernel/tests/00_console_sanity.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2019-2022 Andre Richter +// Copyright (c) 2019-2023 Andre Richter //! Console sanity tests - RX, TX and statistics. diff --git a/18_backtrace/kernel/tests/01_timer_sanity.rs b/18_backtrace/kernel/tests/01_timer_sanity.rs index 8188b942..1581a02e 100644 --- a/18_backtrace/kernel/tests/01_timer_sanity.rs +++ b/18_backtrace/kernel/tests/01_timer_sanity.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2019-2022 Andre Richter +// Copyright (c) 2019-2023 Andre Richter //! Timer sanity tests. diff --git a/18_backtrace/kernel/tests/02_exception_sync_page_fault.rs b/18_backtrace/kernel/tests/02_exception_sync_page_fault.rs index fab44c8f..09d17798 100644 --- a/18_backtrace/kernel/tests/02_exception_sync_page_fault.rs +++ b/18_backtrace/kernel/tests/02_exception_sync_page_fault.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2019-2022 Andre Richter +// Copyright (c) 2019-2023 Andre Richter //! Page faults must result in synchronous exceptions. diff --git a/18_backtrace/kernel/tests/03_exception_restore_sanity.rb b/18_backtrace/kernel/tests/03_exception_restore_sanity.rb index 5f52e0c7..02f51f74 100644 --- a/18_backtrace/kernel/tests/03_exception_restore_sanity.rb +++ b/18_backtrace/kernel/tests/03_exception_restore_sanity.rb @@ -2,7 +2,7 @@ # SPDX-License-Identifier: MIT OR Apache-2.0 # -# Copyright (c) 2022 Andre Richter +# Copyright (c) 2022-2023 Andre Richter require 'console_io_test' @@ -17,9 +17,9 @@ class ExceptionRestoreTest < SubtestBase end end -##-------------------------------------------------------------------------------------------------- +## ------------------------------------------------------------------------------------------------- ## Test registration -##-------------------------------------------------------------------------------------------------- +## ------------------------------------------------------------------------------------------------- def subtest_collection [ExceptionRestoreTest.new] end diff --git a/18_backtrace/kernel/tests/03_exception_restore_sanity.rs b/18_backtrace/kernel/tests/03_exception_restore_sanity.rs index f176c6a6..1a302911 100644 --- a/18_backtrace/kernel/tests/03_exception_restore_sanity.rs +++ b/18_backtrace/kernel/tests/03_exception_restore_sanity.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2022 Andre Richter +// Copyright (c) 2022-2023 Andre Richter //! A simple sanity test to see if exception restore code works. diff --git a/18_backtrace/kernel/tests/04_exception_irq_sanity.rs b/18_backtrace/kernel/tests/04_exception_irq_sanity.rs index e6f94c91..fcace897 100644 --- a/18_backtrace/kernel/tests/04_exception_irq_sanity.rs +++ b/18_backtrace/kernel/tests/04_exception_irq_sanity.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! IRQ handling sanity tests. diff --git a/18_backtrace/kernel/tests/05_backtrace_sanity.rb b/18_backtrace/kernel/tests/05_backtrace_sanity.rb index 5650f97c..243e2fc8 100644 --- a/18_backtrace/kernel/tests/05_backtrace_sanity.rb +++ b/18_backtrace/kernel/tests/05_backtrace_sanity.rb @@ -2,7 +2,7 @@ # SPDX-License-Identifier: MIT OR Apache-2.0 # -# Copyright (c) 2022 Andre Richter +# Copyright (c) 2022-2023 Andre Richter require 'console_io_test' @@ -31,9 +31,9 @@ class BacktraceCorrectnessTest < SubtestBase end end -##-------------------------------------------------------------------------------------------------- +## ------------------------------------------------------------------------------------------------- ## Test registration -##-------------------------------------------------------------------------------------------------- +## ------------------------------------------------------------------------------------------------- def subtest_collection [PanicBacktraceTest.new, BacktraceCorrectnessTest.new] end diff --git a/18_backtrace/kernel/tests/05_backtrace_sanity.rs b/18_backtrace/kernel/tests/05_backtrace_sanity.rs index f75c0ea3..66fd0a3e 100644 --- a/18_backtrace/kernel/tests/05_backtrace_sanity.rs +++ b/18_backtrace/kernel/tests/05_backtrace_sanity.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2022 Andre Richter +// Copyright (c) 2022-2023 Andre Richter //! Test if backtracing code detects an invalid frame pointer. diff --git a/18_backtrace/kernel/tests/06_backtrace_invalid_frame.rb b/18_backtrace/kernel/tests/06_backtrace_invalid_frame.rb index 7601cf97..80695468 100644 --- a/18_backtrace/kernel/tests/06_backtrace_invalid_frame.rb +++ b/18_backtrace/kernel/tests/06_backtrace_invalid_frame.rb @@ -2,7 +2,7 @@ # SPDX-License-Identifier: MIT OR Apache-2.0 # -# Copyright (c) 2022 Andre Richter +# Copyright (c) 2022-2023 Andre Richter require 'console_io_test' @@ -18,9 +18,9 @@ class InvalidFramePointerTest < SubtestBase end end -##-------------------------------------------------------------------------------------------------- +## ------------------------------------------------------------------------------------------------- ## Test registration -##-------------------------------------------------------------------------------------------------- +## ------------------------------------------------------------------------------------------------- def subtest_collection [InvalidFramePointerTest.new] end diff --git a/18_backtrace/kernel/tests/06_backtrace_invalid_frame.rs b/18_backtrace/kernel/tests/06_backtrace_invalid_frame.rs index 33d3c02d..38411af6 100644 --- a/18_backtrace/kernel/tests/06_backtrace_invalid_frame.rs +++ b/18_backtrace/kernel/tests/06_backtrace_invalid_frame.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2022 Andre Richter +// Copyright (c) 2022-2023 Andre Richter //! Test if backtracing code detects an invalid frame pointer. diff --git a/18_backtrace/kernel/tests/07_backtrace_invalid_link.rb b/18_backtrace/kernel/tests/07_backtrace_invalid_link.rb index 0fabcf4c..6b6f0413 100644 --- a/18_backtrace/kernel/tests/07_backtrace_invalid_link.rb +++ b/18_backtrace/kernel/tests/07_backtrace_invalid_link.rb @@ -2,7 +2,7 @@ # SPDX-License-Identifier: MIT OR Apache-2.0 # -# Copyright (c) 2022 Andre Richter +# Copyright (c) 2022-2023 Andre Richter require 'console_io_test' @@ -17,9 +17,9 @@ class InvalidLinkTest < SubtestBase end end -##-------------------------------------------------------------------------------------------------- +## ------------------------------------------------------------------------------------------------- ## Test registration -##-------------------------------------------------------------------------------------------------- +## ------------------------------------------------------------------------------------------------- def subtest_collection [InvalidLinkTest.new] end diff --git a/18_backtrace/kernel/tests/07_backtrace_invalid_link.rs b/18_backtrace/kernel/tests/07_backtrace_invalid_link.rs index bcb0538a..6e0873dd 100644 --- a/18_backtrace/kernel/tests/07_backtrace_invalid_link.rs +++ b/18_backtrace/kernel/tests/07_backtrace_invalid_link.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2022 Andre Richter +// Copyright (c) 2022-2023 Andre Richter //! Test if backtracing code detects an invalid link. diff --git a/18_backtrace/kernel/tests/panic_exit_success/mod.rs b/18_backtrace/kernel/tests/panic_exit_success/mod.rs index 908fac51..449ad6f9 100644 --- a/18_backtrace/kernel/tests/panic_exit_success/mod.rs +++ b/18_backtrace/kernel/tests/panic_exit_success/mod.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2019-2022 Andre Richter +// Copyright (c) 2019-2023 Andre Richter /// Overwrites libkernel's `panic_wait::_panic_exit()` with the QEMU-exit version. #[no_mangle] diff --git a/18_backtrace/kernel/tests/panic_wait_forever/mod.rs b/18_backtrace/kernel/tests/panic_wait_forever/mod.rs index 7a4effa5..9ac19144 100644 --- a/18_backtrace/kernel/tests/panic_wait_forever/mod.rs +++ b/18_backtrace/kernel/tests/panic_wait_forever/mod.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2022 Andre Richter +// Copyright (c) 2022-2023 Andre Richter /// Overwrites libkernel's `panic_wait::_panic_exit()` with wait_forever. #[no_mangle] diff --git a/18_backtrace/kernel_symbols.mk b/18_backtrace/kernel_symbols.mk index d496ea8a..d38b7785 100644 --- a/18_backtrace/kernel_symbols.mk +++ b/18_backtrace/kernel_symbols.mk @@ -1,6 +1,6 @@ ## SPDX-License-Identifier: MIT OR Apache-2.0 ## -## Copyright (c) 2018-2022 Andre Richter +## Copyright (c) 2018-2023 Andre Richter include ../common/format.mk include ../common/docker.mk diff --git a/18_backtrace/kernel_symbols/src/main.rs b/18_backtrace/kernel_symbols/src/main.rs index bd90b535..38ce18f8 100644 --- a/18_backtrace/kernel_symbols/src/main.rs +++ b/18_backtrace/kernel_symbols/src/main.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2022 Andre Richter +// Copyright (c) 2022-2023 Andre Richter //! Generation of kernel symbols. diff --git a/18_backtrace/libraries/debug-symbol-types/src/lib.rs b/18_backtrace/libraries/debug-symbol-types/src/lib.rs index b6dff082..81c897bf 100644 --- a/18_backtrace/libraries/debug-symbol-types/src/lib.rs +++ b/18_backtrace/libraries/debug-symbol-types/src/lib.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2022 Andre Richter +// Copyright (c) 2022-2023 Andre Richter //! Types for implementing debug symbol support. diff --git a/18_backtrace/libraries/test-macros/src/lib.rs b/18_backtrace/libraries/test-macros/src/lib.rs index 9879677c..52cf893d 100644 --- a/18_backtrace/libraries/test-macros/src/lib.rs +++ b/18_backtrace/libraries/test-macros/src/lib.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2019-2022 Andre Richter +// Copyright (c) 2019-2023 Andre Richter use proc_macro::TokenStream; use proc_macro2::Span; diff --git a/18_backtrace/libraries/test-types/src/lib.rs b/18_backtrace/libraries/test-types/src/lib.rs index 922c2a1c..38961a9c 100644 --- a/18_backtrace/libraries/test-types/src/lib.rs +++ b/18_backtrace/libraries/test-types/src/lib.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2019-2022 Andre Richter +// Copyright (c) 2019-2023 Andre Richter //! Types for the `custom_test_frameworks` implementation. diff --git a/18_backtrace/tools/kernel_symbols_tool/cmds.rb b/18_backtrace/tools/kernel_symbols_tool/cmds.rb index fe66ea71..c43acb24 100644 --- a/18_backtrace/tools/kernel_symbols_tool/cmds.rb +++ b/18_backtrace/tools/kernel_symbols_tool/cmds.rb @@ -2,7 +2,7 @@ # SPDX-License-Identifier: MIT OR Apache-2.0 # -# Copyright (c) 2022 Andre Richter +# Copyright (c) 2022-2023 Andre Richter def generate_symbols(kernel_elf, output_file) File.open(output_file, 'w') do |file| diff --git a/18_backtrace/tools/kernel_symbols_tool/kernel_elf.rb b/18_backtrace/tools/kernel_symbols_tool/kernel_elf.rb index b1649767..32b5460a 100644 --- a/18_backtrace/tools/kernel_symbols_tool/kernel_elf.rb +++ b/18_backtrace/tools/kernel_symbols_tool/kernel_elf.rb @@ -2,7 +2,7 @@ # SPDX-License-Identifier: MIT OR Apache-2.0 # -# Copyright (c) 2021-2022 Andre Richter +# Copyright (c) 2021-2023 Andre Richter # KernelELF class KernelELF diff --git a/18_backtrace/tools/kernel_symbols_tool/main.rb b/18_backtrace/tools/kernel_symbols_tool/main.rb index 30a8be6f..899f9646 100755 --- a/18_backtrace/tools/kernel_symbols_tool/main.rb +++ b/18_backtrace/tools/kernel_symbols_tool/main.rb @@ -3,7 +3,7 @@ # SPDX-License-Identifier: MIT OR Apache-2.0 # -# Copyright (c) 2022 Andre Richter +# Copyright (c) 2022-2023 Andre Richter require 'rubygems' require 'bundler/setup' diff --git a/18_backtrace/tools/translation_table_tool/arch.rb b/18_backtrace/tools/translation_table_tool/arch.rb index deceb6d0..61a6d6ca 100644 --- a/18_backtrace/tools/translation_table_tool/arch.rb +++ b/18_backtrace/tools/translation_table_tool/arch.rb @@ -2,7 +2,7 @@ # SPDX-License-Identifier: MIT OR Apache-2.0 # -# Copyright (c) 2021-2022 Andre Richter +# Copyright (c) 2021-2023 Andre Richter # Bitfield manipulation. class BitField diff --git a/18_backtrace/tools/translation_table_tool/bsp.rb b/18_backtrace/tools/translation_table_tool/bsp.rb index dbab5ab6..5887d774 100644 --- a/18_backtrace/tools/translation_table_tool/bsp.rb +++ b/18_backtrace/tools/translation_table_tool/bsp.rb @@ -2,7 +2,7 @@ # SPDX-License-Identifier: MIT OR Apache-2.0 # -# Copyright (c) 2021-2022 Andre Richter +# Copyright (c) 2021-2023 Andre Richter # Raspberry Pi 3 + 4 class RaspberryPi diff --git a/18_backtrace/tools/translation_table_tool/generic.rb b/18_backtrace/tools/translation_table_tool/generic.rb index eee8ccda..941e2226 100644 --- a/18_backtrace/tools/translation_table_tool/generic.rb +++ b/18_backtrace/tools/translation_table_tool/generic.rb @@ -2,7 +2,7 @@ # SPDX-License-Identifier: MIT OR Apache-2.0 # -# Copyright (c) 2021-2022 Andre Richter +# Copyright (c) 2021-2023 Andre Richter module Granule64KiB SIZE = 64 * 1024 @@ -161,7 +161,7 @@ def kernel_map_binary mapping_descriptors.each do |i| print 'Generating'.rjust(12).green.bold print ' ' - puts i.to_s + puts i TRANSLATION_TABLES.map_at(i.virt_region, i.phys_region, i.attributes) end diff --git a/18_backtrace/tools/translation_table_tool/kernel_elf.rb b/18_backtrace/tools/translation_table_tool/kernel_elf.rb index f2d5b0b7..5ba78d9d 100644 --- a/18_backtrace/tools/translation_table_tool/kernel_elf.rb +++ b/18_backtrace/tools/translation_table_tool/kernel_elf.rb @@ -2,7 +2,7 @@ # SPDX-License-Identifier: MIT OR Apache-2.0 # -# Copyright (c) 2021-2022 Andre Richter +# Copyright (c) 2021-2023 Andre Richter # KernelELF class KernelELF diff --git a/18_backtrace/tools/translation_table_tool/main.rb b/18_backtrace/tools/translation_table_tool/main.rb index 6419e364..22ab24fd 100755 --- a/18_backtrace/tools/translation_table_tool/main.rb +++ b/18_backtrace/tools/translation_table_tool/main.rb @@ -3,7 +3,7 @@ # SPDX-License-Identifier: MIT OR Apache-2.0 # -# Copyright (c) 2021-2022 Andre Richter +# Copyright (c) 2021-2023 Andre Richter require 'rubygems' require 'bundler/setup' diff --git a/19_kernel_heap/.vscode/settings.json b/19_kernel_heap/.vscode/settings.json index 292bf2a9..9ef30cd0 100644 --- a/19_kernel_heap/.vscode/settings.json +++ b/19_kernel_heap/.vscode/settings.json @@ -1,10 +1,10 @@ { - "editor.formatOnSave": true, - "editor.rulers": [100], - "rust-analyzer.cargo.target": "aarch64-unknown-none-softfloat", - "rust-analyzer.cargo.features": ["bsp_rpi3"], - "rust-analyzer.checkOnSave.allTargets": false, - "rust-analyzer.checkOnSave.extraArgs": ["--lib", "--bins"], - "rust-analyzer.lens.debug": false, - "rust-analyzer.lens.run": false + "editor.formatOnSave": true, + "editor.rulers": [100], + "rust-analyzer.cargo.target": "aarch64-unknown-none-softfloat", + "rust-analyzer.cargo.features": ["bsp_rpi3"], + "rust-analyzer.checkOnSave.allTargets": false, + "rust-analyzer.checkOnSave.extraArgs": ["--lib", "--bins"], + "rust-analyzer.lens.debug": false, + "rust-analyzer.lens.run": false } diff --git a/19_kernel_heap/Makefile b/19_kernel_heap/Makefile index 43f5ad1f..f9704a44 100644 --- a/19_kernel_heap/Makefile +++ b/19_kernel_heap/Makefile @@ -1,6 +1,6 @@ ## SPDX-License-Identifier: MIT OR Apache-2.0 ## -## Copyright (c) 2018-2022 Andre Richter +## Copyright (c) 2018-2023 Andre Richter include ../common/docker.mk include ../common/format.mk diff --git a/19_kernel_heap/README.md b/19_kernel_heap/README.md index 54bca4ef..eedf82c7 100644 --- a/19_kernel_heap/README.md +++ b/19_kernel_heap/README.md @@ -563,7 +563,7 @@ diff -uNr 18_backtrace/kernel/src/console/buffer_console.rs 19_kernel_heap/kerne @@ -0,0 +1,108 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// -+// Copyright (c) 2022 Andre Richter ++// Copyright (c) 2022-2023 Andre Richter + +//! A console that buffers input during the init phase. + @@ -676,7 +676,7 @@ diff -uNr 18_backtrace/kernel/src/console/null_console.rs 19_kernel_heap/kernel/ @@ -1,41 +0,0 @@ -// SPDX-License-Identifier: MIT OR Apache-2.0 -// --// Copyright (c) 2022 Andre Richter +-// Copyright (c) 2022-2023 Andre Richter - -//! Null console. - @@ -1010,7 +1010,7 @@ diff -uNr 18_backtrace/kernel/src/memory/heap_alloc.rs 19_kernel_heap/kernel/src @@ -0,0 +1,147 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// -+// Copyright (c) 2022 Andre Richter ++// Copyright (c) 2022-2023 Andre Richter + +//! Heap allocation. + diff --git a/19_kernel_heap/kernel/src/_arch/aarch64/backtrace.rs b/19_kernel_heap/kernel/src/_arch/aarch64/backtrace.rs index 3511c918..c2fb8dcb 100644 --- a/19_kernel_heap/kernel/src/_arch/aarch64/backtrace.rs +++ b/19_kernel_heap/kernel/src/_arch/aarch64/backtrace.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2022 Andre Richter +// Copyright (c) 2022-2023 Andre Richter //! Architectural backtracing support. //! diff --git a/19_kernel_heap/kernel/src/_arch/aarch64/cpu.rs b/19_kernel_heap/kernel/src/_arch/aarch64/cpu.rs index 7eb7f010..2d010473 100644 --- a/19_kernel_heap/kernel/src/_arch/aarch64/cpu.rs +++ b/19_kernel_heap/kernel/src/_arch/aarch64/cpu.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Architectural processor code. //! diff --git a/19_kernel_heap/kernel/src/_arch/aarch64/cpu/boot.rs b/19_kernel_heap/kernel/src/_arch/aarch64/cpu/boot.rs index d9662d3a..b8033fbe 100644 --- a/19_kernel_heap/kernel/src/_arch/aarch64/cpu/boot.rs +++ b/19_kernel_heap/kernel/src/_arch/aarch64/cpu/boot.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2021-2022 Andre Richter +// Copyright (c) 2021-2023 Andre Richter //! Architectural boot code. //! diff --git a/19_kernel_heap/kernel/src/_arch/aarch64/cpu/smp.rs b/19_kernel_heap/kernel/src/_arch/aarch64/cpu/smp.rs index 9d304d65..49192038 100644 --- a/19_kernel_heap/kernel/src/_arch/aarch64/cpu/smp.rs +++ b/19_kernel_heap/kernel/src/_arch/aarch64/cpu/smp.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Architectural symmetric multiprocessing. //! diff --git a/19_kernel_heap/kernel/src/_arch/aarch64/exception.rs b/19_kernel_heap/kernel/src/_arch/aarch64/exception.rs index a8bc0d2f..ab464081 100644 --- a/19_kernel_heap/kernel/src/_arch/aarch64/exception.rs +++ b/19_kernel_heap/kernel/src/_arch/aarch64/exception.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Architectural synchronous and asynchronous exception handling. //! diff --git a/19_kernel_heap/kernel/src/_arch/aarch64/exception/asynchronous.rs b/19_kernel_heap/kernel/src/_arch/aarch64/exception/asynchronous.rs index f545a3e1..811ef138 100644 --- a/19_kernel_heap/kernel/src/_arch/aarch64/exception/asynchronous.rs +++ b/19_kernel_heap/kernel/src/_arch/aarch64/exception/asynchronous.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Architectural asynchronous exception handling. //! diff --git a/19_kernel_heap/kernel/src/_arch/aarch64/memory/mmu.rs b/19_kernel_heap/kernel/src/_arch/aarch64/memory/mmu.rs index 74a71d11..984b2e04 100644 --- a/19_kernel_heap/kernel/src/_arch/aarch64/memory/mmu.rs +++ b/19_kernel_heap/kernel/src/_arch/aarch64/memory/mmu.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Memory Management Unit Driver. //! diff --git a/19_kernel_heap/kernel/src/_arch/aarch64/memory/mmu/translation_table.rs b/19_kernel_heap/kernel/src/_arch/aarch64/memory/mmu/translation_table.rs index f0b4ac85..21fae3b8 100644 --- a/19_kernel_heap/kernel/src/_arch/aarch64/memory/mmu/translation_table.rs +++ b/19_kernel_heap/kernel/src/_arch/aarch64/memory/mmu/translation_table.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2021-2022 Andre Richter +// Copyright (c) 2021-2023 Andre Richter //! Architectural translation table. //! diff --git a/19_kernel_heap/kernel/src/_arch/aarch64/time.rs b/19_kernel_heap/kernel/src/_arch/aarch64/time.rs index 94d02379..ee1c3ef7 100644 --- a/19_kernel_heap/kernel/src/_arch/aarch64/time.rs +++ b/19_kernel_heap/kernel/src/_arch/aarch64/time.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Architectural timer primitives. //! diff --git a/19_kernel_heap/kernel/src/backtrace.rs b/19_kernel_heap/kernel/src/backtrace.rs index 22de6c48..a6af2fcc 100644 --- a/19_kernel_heap/kernel/src/backtrace.rs +++ b/19_kernel_heap/kernel/src/backtrace.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2022 Andre Richter +// Copyright (c) 2022-2023 Andre Richter //! Backtracing support. diff --git a/19_kernel_heap/kernel/src/bsp.rs b/19_kernel_heap/kernel/src/bsp.rs index 824787f6..246973bc 100644 --- a/19_kernel_heap/kernel/src/bsp.rs +++ b/19_kernel_heap/kernel/src/bsp.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Conditional reexporting of Board Support Packages. diff --git a/19_kernel_heap/kernel/src/bsp/device_driver.rs b/19_kernel_heap/kernel/src/bsp/device_driver.rs index eafaf775..2dfaec8d 100644 --- a/19_kernel_heap/kernel/src/bsp/device_driver.rs +++ b/19_kernel_heap/kernel/src/bsp/device_driver.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Device driver. diff --git a/19_kernel_heap/kernel/src/bsp/device_driver/arm.rs b/19_kernel_heap/kernel/src/bsp/device_driver/arm.rs index e83e24c9..8d1cbfbd 100644 --- a/19_kernel_heap/kernel/src/bsp/device_driver/arm.rs +++ b/19_kernel_heap/kernel/src/bsp/device_driver/arm.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! ARM driver top level. diff --git a/19_kernel_heap/kernel/src/bsp/device_driver/arm/gicv2.rs b/19_kernel_heap/kernel/src/bsp/device_driver/arm/gicv2.rs index fee8bb4c..7dabf793 100644 --- a/19_kernel_heap/kernel/src/bsp/device_driver/arm/gicv2.rs +++ b/19_kernel_heap/kernel/src/bsp/device_driver/arm/gicv2.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! GICv2 Driver - ARM Generic Interrupt Controller v2. //! diff --git a/19_kernel_heap/kernel/src/bsp/device_driver/arm/gicv2/gicc.rs b/19_kernel_heap/kernel/src/bsp/device_driver/arm/gicv2/gicc.rs index 1a02fc65..0fd16bb3 100644 --- a/19_kernel_heap/kernel/src/bsp/device_driver/arm/gicv2/gicc.rs +++ b/19_kernel_heap/kernel/src/bsp/device_driver/arm/gicv2/gicc.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! GICC Driver - GIC CPU interface. diff --git a/19_kernel_heap/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs b/19_kernel_heap/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs index 8aebcf2b..1fc9d70e 100644 --- a/19_kernel_heap/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs +++ b/19_kernel_heap/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! GICD Driver - GIC Distributor. //! diff --git a/19_kernel_heap/kernel/src/bsp/device_driver/bcm.rs b/19_kernel_heap/kernel/src/bsp/device_driver/bcm.rs index 5a7cc23b..7b7c288b 100644 --- a/19_kernel_heap/kernel/src/bsp/device_driver/bcm.rs +++ b/19_kernel_heap/kernel/src/bsp/device_driver/bcm.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! BCM driver top level. diff --git a/19_kernel_heap/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs b/19_kernel_heap/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs index fb61a651..812156f4 100644 --- a/19_kernel_heap/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs +++ b/19_kernel_heap/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! GPIO Driver. diff --git a/19_kernel_heap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs b/19_kernel_heap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs index a03b472a..66c39597 100644 --- a/19_kernel_heap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs +++ b/19_kernel_heap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Interrupt Controller Driver. diff --git a/19_kernel_heap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs b/19_kernel_heap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs index 238088a8..029c1e74 100644 --- a/19_kernel_heap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs +++ b/19_kernel_heap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Peripheral Interrupt Controller Driver. //! diff --git a/19_kernel_heap/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs b/19_kernel_heap/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs index 3e7e1812..3d580975 100644 --- a/19_kernel_heap/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs +++ b/19_kernel_heap/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! PL011 UART driver. //! diff --git a/19_kernel_heap/kernel/src/bsp/device_driver/common.rs b/19_kernel_heap/kernel/src/bsp/device_driver/common.rs index ca7aeb76..3ce1d8d8 100644 --- a/19_kernel_heap/kernel/src/bsp/device_driver/common.rs +++ b/19_kernel_heap/kernel/src/bsp/device_driver/common.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Common device driver code. diff --git a/19_kernel_heap/kernel/src/bsp/raspberrypi.rs b/19_kernel_heap/kernel/src/bsp/raspberrypi.rs index 474419f4..30421dfa 100644 --- a/19_kernel_heap/kernel/src/bsp/raspberrypi.rs +++ b/19_kernel_heap/kernel/src/bsp/raspberrypi.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Top-level BSP file for the Raspberry Pi 3 and 4. diff --git a/19_kernel_heap/kernel/src/bsp/raspberrypi/cpu.rs b/19_kernel_heap/kernel/src/bsp/raspberrypi/cpu.rs index 85fb89e4..65cf5abb 100644 --- a/19_kernel_heap/kernel/src/bsp/raspberrypi/cpu.rs +++ b/19_kernel_heap/kernel/src/bsp/raspberrypi/cpu.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! BSP Processor code. diff --git a/19_kernel_heap/kernel/src/bsp/raspberrypi/driver.rs b/19_kernel_heap/kernel/src/bsp/raspberrypi/driver.rs index ca3435aa..a1f55b17 100644 --- a/19_kernel_heap/kernel/src/bsp/raspberrypi/driver.rs +++ b/19_kernel_heap/kernel/src/bsp/raspberrypi/driver.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! BSP driver support. diff --git a/19_kernel_heap/kernel/src/bsp/raspberrypi/exception.rs b/19_kernel_heap/kernel/src/bsp/raspberrypi/exception.rs index aa6c5a63..a9eaa6ac 100644 --- a/19_kernel_heap/kernel/src/bsp/raspberrypi/exception.rs +++ b/19_kernel_heap/kernel/src/bsp/raspberrypi/exception.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! BSP synchronous and asynchronous exception handling. diff --git a/19_kernel_heap/kernel/src/bsp/raspberrypi/exception/asynchronous.rs b/19_kernel_heap/kernel/src/bsp/raspberrypi/exception/asynchronous.rs index 06a67558..776182fd 100644 --- a/19_kernel_heap/kernel/src/bsp/raspberrypi/exception/asynchronous.rs +++ b/19_kernel_heap/kernel/src/bsp/raspberrypi/exception/asynchronous.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! BSP asynchronous exception handling. diff --git a/19_kernel_heap/kernel/src/bsp/raspberrypi/memory.rs b/19_kernel_heap/kernel/src/bsp/raspberrypi/memory.rs index 760128d3..8507dfc7 100644 --- a/19_kernel_heap/kernel/src/bsp/raspberrypi/memory.rs +++ b/19_kernel_heap/kernel/src/bsp/raspberrypi/memory.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! BSP Memory Management. //! diff --git a/19_kernel_heap/kernel/src/bsp/raspberrypi/memory/mmu.rs b/19_kernel_heap/kernel/src/bsp/raspberrypi/memory/mmu.rs index bb2f8208..ef52e368 100644 --- a/19_kernel_heap/kernel/src/bsp/raspberrypi/memory/mmu.rs +++ b/19_kernel_heap/kernel/src/bsp/raspberrypi/memory/mmu.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! BSP Memory Management Unit. diff --git a/19_kernel_heap/kernel/src/common.rs b/19_kernel_heap/kernel/src/common.rs index f32f650f..2ad7e4c1 100644 --- a/19_kernel_heap/kernel/src/common.rs +++ b/19_kernel_heap/kernel/src/common.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! General purpose code. diff --git a/19_kernel_heap/kernel/src/console.rs b/19_kernel_heap/kernel/src/console.rs index ff1d8ddc..5efa9395 100644 --- a/19_kernel_heap/kernel/src/console.rs +++ b/19_kernel_heap/kernel/src/console.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! System console. diff --git a/19_kernel_heap/kernel/src/console/buffer_console.rs b/19_kernel_heap/kernel/src/console/buffer_console.rs index c3259f89..05903e7c 100644 --- a/19_kernel_heap/kernel/src/console/buffer_console.rs +++ b/19_kernel_heap/kernel/src/console/buffer_console.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2022 Andre Richter +// Copyright (c) 2022-2023 Andre Richter //! A console that buffers input during the init phase. diff --git a/19_kernel_heap/kernel/src/cpu.rs b/19_kernel_heap/kernel/src/cpu.rs index e1493d1d..8716a918 100644 --- a/19_kernel_heap/kernel/src/cpu.rs +++ b/19_kernel_heap/kernel/src/cpu.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Processor code. diff --git a/19_kernel_heap/kernel/src/cpu/boot.rs b/19_kernel_heap/kernel/src/cpu/boot.rs index 8091dac3..b1e98328 100644 --- a/19_kernel_heap/kernel/src/cpu/boot.rs +++ b/19_kernel_heap/kernel/src/cpu/boot.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2021-2022 Andre Richter +// Copyright (c) 2021-2023 Andre Richter //! Boot code. diff --git a/19_kernel_heap/kernel/src/cpu/smp.rs b/19_kernel_heap/kernel/src/cpu/smp.rs index 57386f79..de612d58 100644 --- a/19_kernel_heap/kernel/src/cpu/smp.rs +++ b/19_kernel_heap/kernel/src/cpu/smp.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Symmetric multiprocessing. diff --git a/19_kernel_heap/kernel/src/driver.rs b/19_kernel_heap/kernel/src/driver.rs index 2f22fd20..88b41b81 100644 --- a/19_kernel_heap/kernel/src/driver.rs +++ b/19_kernel_heap/kernel/src/driver.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Driver support. diff --git a/19_kernel_heap/kernel/src/exception.rs b/19_kernel_heap/kernel/src/exception.rs index 7ea7cd80..3d5f219f 100644 --- a/19_kernel_heap/kernel/src/exception.rs +++ b/19_kernel_heap/kernel/src/exception.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Synchronous and asynchronous exception handling. diff --git a/19_kernel_heap/kernel/src/exception/asynchronous.rs b/19_kernel_heap/kernel/src/exception/asynchronous.rs index c1f2a27b..2c874dd6 100644 --- a/19_kernel_heap/kernel/src/exception/asynchronous.rs +++ b/19_kernel_heap/kernel/src/exception/asynchronous.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Asynchronous exception handling. diff --git a/19_kernel_heap/kernel/src/exception/asynchronous/null_irq_manager.rs b/19_kernel_heap/kernel/src/exception/asynchronous/null_irq_manager.rs index 438f9649..38919ffe 100644 --- a/19_kernel_heap/kernel/src/exception/asynchronous/null_irq_manager.rs +++ b/19_kernel_heap/kernel/src/exception/asynchronous/null_irq_manager.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2022 Andre Richter +// Copyright (c) 2022-2023 Andre Richter //! Null IRQ Manager. diff --git a/19_kernel_heap/kernel/src/lib.rs b/19_kernel_heap/kernel/src/lib.rs index bba0fcc7..317bcc72 100644 --- a/19_kernel_heap/kernel/src/lib.rs +++ b/19_kernel_heap/kernel/src/lib.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter // Rust embedded logo for `make doc`. #![doc( diff --git a/19_kernel_heap/kernel/src/main.rs b/19_kernel_heap/kernel/src/main.rs index 9a5fd58a..ae2ea8a7 100644 --- a/19_kernel_heap/kernel/src/main.rs +++ b/19_kernel_heap/kernel/src/main.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter // Rust embedded logo for `make doc`. #![doc( diff --git a/19_kernel_heap/kernel/src/memory.rs b/19_kernel_heap/kernel/src/memory.rs index a64bfbae..bc611336 100644 --- a/19_kernel_heap/kernel/src/memory.rs +++ b/19_kernel_heap/kernel/src/memory.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Memory Management. diff --git a/19_kernel_heap/kernel/src/memory/heap_alloc.rs b/19_kernel_heap/kernel/src/memory/heap_alloc.rs index c0f56d8d..cf4298fa 100644 --- a/19_kernel_heap/kernel/src/memory/heap_alloc.rs +++ b/19_kernel_heap/kernel/src/memory/heap_alloc.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2022 Andre Richter +// Copyright (c) 2022-2023 Andre Richter //! Heap allocation. diff --git a/19_kernel_heap/kernel/src/memory/mmu.rs b/19_kernel_heap/kernel/src/memory/mmu.rs index 8d204a4e..abe3b181 100644 --- a/19_kernel_heap/kernel/src/memory/mmu.rs +++ b/19_kernel_heap/kernel/src/memory/mmu.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Memory Management Unit. diff --git a/19_kernel_heap/kernel/src/memory/mmu/mapping_record.rs b/19_kernel_heap/kernel/src/memory/mmu/mapping_record.rs index 4e9395da..9c17258d 100644 --- a/19_kernel_heap/kernel/src/memory/mmu/mapping_record.rs +++ b/19_kernel_heap/kernel/src/memory/mmu/mapping_record.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! A record of mapped pages. diff --git a/19_kernel_heap/kernel/src/memory/mmu/page_alloc.rs b/19_kernel_heap/kernel/src/memory/mmu/page_alloc.rs index 347fcd34..344afd20 100644 --- a/19_kernel_heap/kernel/src/memory/mmu/page_alloc.rs +++ b/19_kernel_heap/kernel/src/memory/mmu/page_alloc.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2021-2022 Andre Richter +// Copyright (c) 2021-2023 Andre Richter //! Page allocation. diff --git a/19_kernel_heap/kernel/src/memory/mmu/translation_table.rs b/19_kernel_heap/kernel/src/memory/mmu/translation_table.rs index 9301bb0c..341ffc5c 100644 --- a/19_kernel_heap/kernel/src/memory/mmu/translation_table.rs +++ b/19_kernel_heap/kernel/src/memory/mmu/translation_table.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2021-2022 Andre Richter +// Copyright (c) 2021-2023 Andre Richter //! Translation table. diff --git a/19_kernel_heap/kernel/src/memory/mmu/types.rs b/19_kernel_heap/kernel/src/memory/mmu/types.rs index 62f3926e..f6ac8d59 100644 --- a/19_kernel_heap/kernel/src/memory/mmu/types.rs +++ b/19_kernel_heap/kernel/src/memory/mmu/types.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Memory Management Unit types. diff --git a/19_kernel_heap/kernel/src/panic_wait.rs b/19_kernel_heap/kernel/src/panic_wait.rs index bc95f77c..389eb2c8 100644 --- a/19_kernel_heap/kernel/src/panic_wait.rs +++ b/19_kernel_heap/kernel/src/panic_wait.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! A panic handler that infinitely waits. diff --git a/19_kernel_heap/kernel/src/print.rs b/19_kernel_heap/kernel/src/print.rs index 8d56d2e4..a89f8201 100644 --- a/19_kernel_heap/kernel/src/print.rs +++ b/19_kernel_heap/kernel/src/print.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Printing. diff --git a/19_kernel_heap/kernel/src/state.rs b/19_kernel_heap/kernel/src/state.rs index 0af3688c..6d99beed 100644 --- a/19_kernel_heap/kernel/src/state.rs +++ b/19_kernel_heap/kernel/src/state.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! State information about the kernel itself. diff --git a/19_kernel_heap/kernel/src/symbols.rs b/19_kernel_heap/kernel/src/symbols.rs index 680b8eaf..fdc1d084 100644 --- a/19_kernel_heap/kernel/src/symbols.rs +++ b/19_kernel_heap/kernel/src/symbols.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2022 Andre Richter +// Copyright (c) 2022-2023 Andre Richter //! Debug symbol support. diff --git a/19_kernel_heap/kernel/src/synchronization.rs b/19_kernel_heap/kernel/src/synchronization.rs index ab2b86e6..5740b63e 100644 --- a/19_kernel_heap/kernel/src/synchronization.rs +++ b/19_kernel_heap/kernel/src/synchronization.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Synchronization primitives. //! diff --git a/19_kernel_heap/kernel/src/time.rs b/19_kernel_heap/kernel/src/time.rs index a6c0c5b6..a9d50120 100644 --- a/19_kernel_heap/kernel/src/time.rs +++ b/19_kernel_heap/kernel/src/time.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Timer primitives. diff --git a/19_kernel_heap/kernel/tests/00_console_sanity.rb b/19_kernel_heap/kernel/tests/00_console_sanity.rb index 4dde5576..8be7a2f1 100644 --- a/19_kernel_heap/kernel/tests/00_console_sanity.rb +++ b/19_kernel_heap/kernel/tests/00_console_sanity.rb @@ -2,7 +2,7 @@ # SPDX-License-Identifier: MIT OR Apache-2.0 # -# Copyright (c) 2019-2022 Andre Richter +# Copyright (c) 2019-2023 Andre Richter require 'console_io_test' @@ -40,9 +40,9 @@ class RxStatisticsTest < SubtestBase end end -##-------------------------------------------------------------------------------------------------- +## ------------------------------------------------------------------------------------------------- ## Test registration -##-------------------------------------------------------------------------------------------------- +## ------------------------------------------------------------------------------------------------- def subtest_collection [TxRxHandshakeTest.new, TxStatisticsTest.new, RxStatisticsTest.new] end diff --git a/19_kernel_heap/kernel/tests/00_console_sanity.rs b/19_kernel_heap/kernel/tests/00_console_sanity.rs index 2c0225b7..682ea9b8 100644 --- a/19_kernel_heap/kernel/tests/00_console_sanity.rs +++ b/19_kernel_heap/kernel/tests/00_console_sanity.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2019-2022 Andre Richter +// Copyright (c) 2019-2023 Andre Richter //! Console sanity tests - RX, TX and statistics. diff --git a/19_kernel_heap/kernel/tests/01_timer_sanity.rs b/19_kernel_heap/kernel/tests/01_timer_sanity.rs index 8188b942..1581a02e 100644 --- a/19_kernel_heap/kernel/tests/01_timer_sanity.rs +++ b/19_kernel_heap/kernel/tests/01_timer_sanity.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2019-2022 Andre Richter +// Copyright (c) 2019-2023 Andre Richter //! Timer sanity tests. diff --git a/19_kernel_heap/kernel/tests/02_exception_sync_page_fault.rs b/19_kernel_heap/kernel/tests/02_exception_sync_page_fault.rs index fab44c8f..09d17798 100644 --- a/19_kernel_heap/kernel/tests/02_exception_sync_page_fault.rs +++ b/19_kernel_heap/kernel/tests/02_exception_sync_page_fault.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2019-2022 Andre Richter +// Copyright (c) 2019-2023 Andre Richter //! Page faults must result in synchronous exceptions. diff --git a/19_kernel_heap/kernel/tests/03_exception_restore_sanity.rb b/19_kernel_heap/kernel/tests/03_exception_restore_sanity.rb index 5f52e0c7..02f51f74 100644 --- a/19_kernel_heap/kernel/tests/03_exception_restore_sanity.rb +++ b/19_kernel_heap/kernel/tests/03_exception_restore_sanity.rb @@ -2,7 +2,7 @@ # SPDX-License-Identifier: MIT OR Apache-2.0 # -# Copyright (c) 2022 Andre Richter +# Copyright (c) 2022-2023 Andre Richter require 'console_io_test' @@ -17,9 +17,9 @@ class ExceptionRestoreTest < SubtestBase end end -##-------------------------------------------------------------------------------------------------- +## ------------------------------------------------------------------------------------------------- ## Test registration -##-------------------------------------------------------------------------------------------------- +## ------------------------------------------------------------------------------------------------- def subtest_collection [ExceptionRestoreTest.new] end diff --git a/19_kernel_heap/kernel/tests/03_exception_restore_sanity.rs b/19_kernel_heap/kernel/tests/03_exception_restore_sanity.rs index f176c6a6..1a302911 100644 --- a/19_kernel_heap/kernel/tests/03_exception_restore_sanity.rs +++ b/19_kernel_heap/kernel/tests/03_exception_restore_sanity.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2022 Andre Richter +// Copyright (c) 2022-2023 Andre Richter //! A simple sanity test to see if exception restore code works. diff --git a/19_kernel_heap/kernel/tests/04_exception_irq_sanity.rs b/19_kernel_heap/kernel/tests/04_exception_irq_sanity.rs index e6f94c91..fcace897 100644 --- a/19_kernel_heap/kernel/tests/04_exception_irq_sanity.rs +++ b/19_kernel_heap/kernel/tests/04_exception_irq_sanity.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! IRQ handling sanity tests. diff --git a/19_kernel_heap/kernel/tests/05_backtrace_sanity.rb b/19_kernel_heap/kernel/tests/05_backtrace_sanity.rb index 5650f97c..243e2fc8 100644 --- a/19_kernel_heap/kernel/tests/05_backtrace_sanity.rb +++ b/19_kernel_heap/kernel/tests/05_backtrace_sanity.rb @@ -2,7 +2,7 @@ # SPDX-License-Identifier: MIT OR Apache-2.0 # -# Copyright (c) 2022 Andre Richter +# Copyright (c) 2022-2023 Andre Richter require 'console_io_test' @@ -31,9 +31,9 @@ class BacktraceCorrectnessTest < SubtestBase end end -##-------------------------------------------------------------------------------------------------- +## ------------------------------------------------------------------------------------------------- ## Test registration -##-------------------------------------------------------------------------------------------------- +## ------------------------------------------------------------------------------------------------- def subtest_collection [PanicBacktraceTest.new, BacktraceCorrectnessTest.new] end diff --git a/19_kernel_heap/kernel/tests/05_backtrace_sanity.rs b/19_kernel_heap/kernel/tests/05_backtrace_sanity.rs index f75c0ea3..66fd0a3e 100644 --- a/19_kernel_heap/kernel/tests/05_backtrace_sanity.rs +++ b/19_kernel_heap/kernel/tests/05_backtrace_sanity.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2022 Andre Richter +// Copyright (c) 2022-2023 Andre Richter //! Test if backtracing code detects an invalid frame pointer. diff --git a/19_kernel_heap/kernel/tests/06_backtrace_invalid_frame.rb b/19_kernel_heap/kernel/tests/06_backtrace_invalid_frame.rb index 7601cf97..80695468 100644 --- a/19_kernel_heap/kernel/tests/06_backtrace_invalid_frame.rb +++ b/19_kernel_heap/kernel/tests/06_backtrace_invalid_frame.rb @@ -2,7 +2,7 @@ # SPDX-License-Identifier: MIT OR Apache-2.0 # -# Copyright (c) 2022 Andre Richter +# Copyright (c) 2022-2023 Andre Richter require 'console_io_test' @@ -18,9 +18,9 @@ class InvalidFramePointerTest < SubtestBase end end -##-------------------------------------------------------------------------------------------------- +## ------------------------------------------------------------------------------------------------- ## Test registration -##-------------------------------------------------------------------------------------------------- +## ------------------------------------------------------------------------------------------------- def subtest_collection [InvalidFramePointerTest.new] end diff --git a/19_kernel_heap/kernel/tests/06_backtrace_invalid_frame.rs b/19_kernel_heap/kernel/tests/06_backtrace_invalid_frame.rs index 33d3c02d..38411af6 100644 --- a/19_kernel_heap/kernel/tests/06_backtrace_invalid_frame.rs +++ b/19_kernel_heap/kernel/tests/06_backtrace_invalid_frame.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2022 Andre Richter +// Copyright (c) 2022-2023 Andre Richter //! Test if backtracing code detects an invalid frame pointer. diff --git a/19_kernel_heap/kernel/tests/07_backtrace_invalid_link.rb b/19_kernel_heap/kernel/tests/07_backtrace_invalid_link.rb index 0fabcf4c..6b6f0413 100644 --- a/19_kernel_heap/kernel/tests/07_backtrace_invalid_link.rb +++ b/19_kernel_heap/kernel/tests/07_backtrace_invalid_link.rb @@ -2,7 +2,7 @@ # SPDX-License-Identifier: MIT OR Apache-2.0 # -# Copyright (c) 2022 Andre Richter +# Copyright (c) 2022-2023 Andre Richter require 'console_io_test' @@ -17,9 +17,9 @@ class InvalidLinkTest < SubtestBase end end -##-------------------------------------------------------------------------------------------------- +## ------------------------------------------------------------------------------------------------- ## Test registration -##-------------------------------------------------------------------------------------------------- +## ------------------------------------------------------------------------------------------------- def subtest_collection [InvalidLinkTest.new] end diff --git a/19_kernel_heap/kernel/tests/07_backtrace_invalid_link.rs b/19_kernel_heap/kernel/tests/07_backtrace_invalid_link.rs index bcb0538a..6e0873dd 100644 --- a/19_kernel_heap/kernel/tests/07_backtrace_invalid_link.rs +++ b/19_kernel_heap/kernel/tests/07_backtrace_invalid_link.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2022 Andre Richter +// Copyright (c) 2022-2023 Andre Richter //! Test if backtracing code detects an invalid link. diff --git a/19_kernel_heap/kernel/tests/panic_exit_success/mod.rs b/19_kernel_heap/kernel/tests/panic_exit_success/mod.rs index 908fac51..449ad6f9 100644 --- a/19_kernel_heap/kernel/tests/panic_exit_success/mod.rs +++ b/19_kernel_heap/kernel/tests/panic_exit_success/mod.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2019-2022 Andre Richter +// Copyright (c) 2019-2023 Andre Richter /// Overwrites libkernel's `panic_wait::_panic_exit()` with the QEMU-exit version. #[no_mangle] diff --git a/19_kernel_heap/kernel/tests/panic_wait_forever/mod.rs b/19_kernel_heap/kernel/tests/panic_wait_forever/mod.rs index 7a4effa5..9ac19144 100644 --- a/19_kernel_heap/kernel/tests/panic_wait_forever/mod.rs +++ b/19_kernel_heap/kernel/tests/panic_wait_forever/mod.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2022 Andre Richter +// Copyright (c) 2022-2023 Andre Richter /// Overwrites libkernel's `panic_wait::_panic_exit()` with wait_forever. #[no_mangle] diff --git a/19_kernel_heap/kernel_symbols.mk b/19_kernel_heap/kernel_symbols.mk index d496ea8a..d38b7785 100644 --- a/19_kernel_heap/kernel_symbols.mk +++ b/19_kernel_heap/kernel_symbols.mk @@ -1,6 +1,6 @@ ## SPDX-License-Identifier: MIT OR Apache-2.0 ## -## Copyright (c) 2018-2022 Andre Richter +## Copyright (c) 2018-2023 Andre Richter include ../common/format.mk include ../common/docker.mk diff --git a/19_kernel_heap/kernel_symbols/src/main.rs b/19_kernel_heap/kernel_symbols/src/main.rs index bd90b535..38ce18f8 100644 --- a/19_kernel_heap/kernel_symbols/src/main.rs +++ b/19_kernel_heap/kernel_symbols/src/main.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2022 Andre Richter +// Copyright (c) 2022-2023 Andre Richter //! Generation of kernel symbols. diff --git a/19_kernel_heap/libraries/debug-symbol-types/src/lib.rs b/19_kernel_heap/libraries/debug-symbol-types/src/lib.rs index b6dff082..81c897bf 100644 --- a/19_kernel_heap/libraries/debug-symbol-types/src/lib.rs +++ b/19_kernel_heap/libraries/debug-symbol-types/src/lib.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2022 Andre Richter +// Copyright (c) 2022-2023 Andre Richter //! Types for implementing debug symbol support. diff --git a/19_kernel_heap/libraries/test-macros/src/lib.rs b/19_kernel_heap/libraries/test-macros/src/lib.rs index 9879677c..52cf893d 100644 --- a/19_kernel_heap/libraries/test-macros/src/lib.rs +++ b/19_kernel_heap/libraries/test-macros/src/lib.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2019-2022 Andre Richter +// Copyright (c) 2019-2023 Andre Richter use proc_macro::TokenStream; use proc_macro2::Span; diff --git a/19_kernel_heap/libraries/test-types/src/lib.rs b/19_kernel_heap/libraries/test-types/src/lib.rs index 922c2a1c..38961a9c 100644 --- a/19_kernel_heap/libraries/test-types/src/lib.rs +++ b/19_kernel_heap/libraries/test-types/src/lib.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2019-2022 Andre Richter +// Copyright (c) 2019-2023 Andre Richter //! Types for the `custom_test_frameworks` implementation. diff --git a/19_kernel_heap/tools/kernel_symbols_tool/cmds.rb b/19_kernel_heap/tools/kernel_symbols_tool/cmds.rb index fe66ea71..c43acb24 100644 --- a/19_kernel_heap/tools/kernel_symbols_tool/cmds.rb +++ b/19_kernel_heap/tools/kernel_symbols_tool/cmds.rb @@ -2,7 +2,7 @@ # SPDX-License-Identifier: MIT OR Apache-2.0 # -# Copyright (c) 2022 Andre Richter +# Copyright (c) 2022-2023 Andre Richter def generate_symbols(kernel_elf, output_file) File.open(output_file, 'w') do |file| diff --git a/19_kernel_heap/tools/kernel_symbols_tool/kernel_elf.rb b/19_kernel_heap/tools/kernel_symbols_tool/kernel_elf.rb index b1649767..32b5460a 100644 --- a/19_kernel_heap/tools/kernel_symbols_tool/kernel_elf.rb +++ b/19_kernel_heap/tools/kernel_symbols_tool/kernel_elf.rb @@ -2,7 +2,7 @@ # SPDX-License-Identifier: MIT OR Apache-2.0 # -# Copyright (c) 2021-2022 Andre Richter +# Copyright (c) 2021-2023 Andre Richter # KernelELF class KernelELF diff --git a/19_kernel_heap/tools/kernel_symbols_tool/main.rb b/19_kernel_heap/tools/kernel_symbols_tool/main.rb index 30a8be6f..899f9646 100755 --- a/19_kernel_heap/tools/kernel_symbols_tool/main.rb +++ b/19_kernel_heap/tools/kernel_symbols_tool/main.rb @@ -3,7 +3,7 @@ # SPDX-License-Identifier: MIT OR Apache-2.0 # -# Copyright (c) 2022 Andre Richter +# Copyright (c) 2022-2023 Andre Richter require 'rubygems' require 'bundler/setup' diff --git a/19_kernel_heap/tools/translation_table_tool/arch.rb b/19_kernel_heap/tools/translation_table_tool/arch.rb index deceb6d0..61a6d6ca 100644 --- a/19_kernel_heap/tools/translation_table_tool/arch.rb +++ b/19_kernel_heap/tools/translation_table_tool/arch.rb @@ -2,7 +2,7 @@ # SPDX-License-Identifier: MIT OR Apache-2.0 # -# Copyright (c) 2021-2022 Andre Richter +# Copyright (c) 2021-2023 Andre Richter # Bitfield manipulation. class BitField diff --git a/19_kernel_heap/tools/translation_table_tool/bsp.rb b/19_kernel_heap/tools/translation_table_tool/bsp.rb index dbab5ab6..5887d774 100644 --- a/19_kernel_heap/tools/translation_table_tool/bsp.rb +++ b/19_kernel_heap/tools/translation_table_tool/bsp.rb @@ -2,7 +2,7 @@ # SPDX-License-Identifier: MIT OR Apache-2.0 # -# Copyright (c) 2021-2022 Andre Richter +# Copyright (c) 2021-2023 Andre Richter # Raspberry Pi 3 + 4 class RaspberryPi diff --git a/19_kernel_heap/tools/translation_table_tool/generic.rb b/19_kernel_heap/tools/translation_table_tool/generic.rb index eee8ccda..941e2226 100644 --- a/19_kernel_heap/tools/translation_table_tool/generic.rb +++ b/19_kernel_heap/tools/translation_table_tool/generic.rb @@ -2,7 +2,7 @@ # SPDX-License-Identifier: MIT OR Apache-2.0 # -# Copyright (c) 2021-2022 Andre Richter +# Copyright (c) 2021-2023 Andre Richter module Granule64KiB SIZE = 64 * 1024 @@ -161,7 +161,7 @@ def kernel_map_binary mapping_descriptors.each do |i| print 'Generating'.rjust(12).green.bold print ' ' - puts i.to_s + puts i TRANSLATION_TABLES.map_at(i.virt_region, i.phys_region, i.attributes) end diff --git a/19_kernel_heap/tools/translation_table_tool/kernel_elf.rb b/19_kernel_heap/tools/translation_table_tool/kernel_elf.rb index f2d5b0b7..5ba78d9d 100644 --- a/19_kernel_heap/tools/translation_table_tool/kernel_elf.rb +++ b/19_kernel_heap/tools/translation_table_tool/kernel_elf.rb @@ -2,7 +2,7 @@ # SPDX-License-Identifier: MIT OR Apache-2.0 # -# Copyright (c) 2021-2022 Andre Richter +# Copyright (c) 2021-2023 Andre Richter # KernelELF class KernelELF diff --git a/19_kernel_heap/tools/translation_table_tool/main.rb b/19_kernel_heap/tools/translation_table_tool/main.rb index 6419e364..22ab24fd 100755 --- a/19_kernel_heap/tools/translation_table_tool/main.rb +++ b/19_kernel_heap/tools/translation_table_tool/main.rb @@ -3,7 +3,7 @@ # SPDX-License-Identifier: MIT OR Apache-2.0 # -# Copyright (c) 2021-2022 Andre Richter +# Copyright (c) 2021-2023 Andre Richter require 'rubygems' require 'bundler/setup' diff --git a/20_timer_callbacks/.vscode/settings.json b/20_timer_callbacks/.vscode/settings.json index 292bf2a9..9ef30cd0 100644 --- a/20_timer_callbacks/.vscode/settings.json +++ b/20_timer_callbacks/.vscode/settings.json @@ -1,10 +1,10 @@ { - "editor.formatOnSave": true, - "editor.rulers": [100], - "rust-analyzer.cargo.target": "aarch64-unknown-none-softfloat", - "rust-analyzer.cargo.features": ["bsp_rpi3"], - "rust-analyzer.checkOnSave.allTargets": false, - "rust-analyzer.checkOnSave.extraArgs": ["--lib", "--bins"], - "rust-analyzer.lens.debug": false, - "rust-analyzer.lens.run": false + "editor.formatOnSave": true, + "editor.rulers": [100], + "rust-analyzer.cargo.target": "aarch64-unknown-none-softfloat", + "rust-analyzer.cargo.features": ["bsp_rpi3"], + "rust-analyzer.checkOnSave.allTargets": false, + "rust-analyzer.checkOnSave.extraArgs": ["--lib", "--bins"], + "rust-analyzer.lens.debug": false, + "rust-analyzer.lens.run": false } diff --git a/20_timer_callbacks/Makefile b/20_timer_callbacks/Makefile index 43f5ad1f..f9704a44 100644 --- a/20_timer_callbacks/Makefile +++ b/20_timer_callbacks/Makefile @@ -1,6 +1,6 @@ ## SPDX-License-Identifier: MIT OR Apache-2.0 ## -## Copyright (c) 2018-2022 Andre Richter +## Copyright (c) 2018-2023 Andre Richter include ../common/docker.mk include ../common/format.mk diff --git a/20_timer_callbacks/README.md b/20_timer_callbacks/README.md index da5a5510..062d5912 100644 --- a/20_timer_callbacks/README.md +++ b/20_timer_callbacks/README.md @@ -90,7 +90,7 @@ diff -uNr 19_kernel_heap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_cont @@ -0,0 +1,173 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// -+// Copyright (c) 2022 Andre Richter ++// Copyright (c) 2022-2023 Andre Richter + +//! Local Interrupt Controller Driver. +//! @@ -472,7 +472,7 @@ diff -uNr 19_kernel_heap/kernel/src/time.rs 20_timer_callbacks/kernel/src/time.r --- 19_kernel_heap/kernel/src/time.rs +++ 20_timer_callbacks/kernel/src/time.rs @@ -3,19 +3,54 @@ - // Copyright (c) 2020-2022 Andre Richter + // Copyright (c) 2020-2023 Andre Richter //! Timer primitives. +//! diff --git a/20_timer_callbacks/kernel/Cargo.toml b/20_timer_callbacks/kernel/Cargo.toml index 87c9cbb6..4a3b76d3 100644 --- a/20_timer_callbacks/kernel/Cargo.toml +++ b/20_timer_callbacks/kernel/Cargo.toml @@ -11,9 +11,9 @@ bsp_rpi3 = ["tock-registers"] bsp_rpi4 = ["tock-registers"] test_build = ["qemu-exit"] -##-------------------------------------------------------------------------------------------------- +##------------------------------------------------------------------------------------------------- ## Dependencies -##-------------------------------------------------------------------------------------------------- +##------------------------------------------------------------------------------------------------- [dependencies] test-types = { path = "../libraries/test-types" } @@ -28,9 +28,9 @@ qemu-exit = { version = "3.x.x", optional = true } [target.'cfg(target_arch = "aarch64")'.dependencies] aarch64-cpu = { version = "9.x.x" } -##-------------------------------------------------------------------------------------------------- +##------------------------------------------------------------------------------------------------- ## Testing -##-------------------------------------------------------------------------------------------------- +##------------------------------------------------------------------------------------------------- [dev-dependencies] test-macros = { path = "../libraries/test-macros" } diff --git a/20_timer_callbacks/kernel/src/_arch/aarch64/backtrace.rs b/20_timer_callbacks/kernel/src/_arch/aarch64/backtrace.rs index 3511c918..c2fb8dcb 100644 --- a/20_timer_callbacks/kernel/src/_arch/aarch64/backtrace.rs +++ b/20_timer_callbacks/kernel/src/_arch/aarch64/backtrace.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2022 Andre Richter +// Copyright (c) 2022-2023 Andre Richter //! Architectural backtracing support. //! diff --git a/20_timer_callbacks/kernel/src/_arch/aarch64/cpu.rs b/20_timer_callbacks/kernel/src/_arch/aarch64/cpu.rs index 7eb7f010..2d010473 100644 --- a/20_timer_callbacks/kernel/src/_arch/aarch64/cpu.rs +++ b/20_timer_callbacks/kernel/src/_arch/aarch64/cpu.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Architectural processor code. //! diff --git a/20_timer_callbacks/kernel/src/_arch/aarch64/cpu/boot.rs b/20_timer_callbacks/kernel/src/_arch/aarch64/cpu/boot.rs index d9662d3a..b8033fbe 100644 --- a/20_timer_callbacks/kernel/src/_arch/aarch64/cpu/boot.rs +++ b/20_timer_callbacks/kernel/src/_arch/aarch64/cpu/boot.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2021-2022 Andre Richter +// Copyright (c) 2021-2023 Andre Richter //! Architectural boot code. //! diff --git a/20_timer_callbacks/kernel/src/_arch/aarch64/cpu/boot.s b/20_timer_callbacks/kernel/src/_arch/aarch64/cpu/boot.s index 1a8c8801..65d71b1a 100644 --- a/20_timer_callbacks/kernel/src/_arch/aarch64/cpu/boot.s +++ b/20_timer_callbacks/kernel/src/_arch/aarch64/cpu/boot.s @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2021-2022 Andre Richter +// Copyright (c) 2021-2023 Andre Richter //-------------------------------------------------------------------------------------------------- // Definitions diff --git a/20_timer_callbacks/kernel/src/_arch/aarch64/cpu/smp.rs b/20_timer_callbacks/kernel/src/_arch/aarch64/cpu/smp.rs index 9d304d65..49192038 100644 --- a/20_timer_callbacks/kernel/src/_arch/aarch64/cpu/smp.rs +++ b/20_timer_callbacks/kernel/src/_arch/aarch64/cpu/smp.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Architectural symmetric multiprocessing. //! diff --git a/20_timer_callbacks/kernel/src/_arch/aarch64/exception.rs b/20_timer_callbacks/kernel/src/_arch/aarch64/exception.rs index a8bc0d2f..ab464081 100644 --- a/20_timer_callbacks/kernel/src/_arch/aarch64/exception.rs +++ b/20_timer_callbacks/kernel/src/_arch/aarch64/exception.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Architectural synchronous and asynchronous exception handling. //! diff --git a/20_timer_callbacks/kernel/src/_arch/aarch64/exception.s b/20_timer_callbacks/kernel/src/_arch/aarch64/exception.s index cdef8c58..a806a276 100644 --- a/20_timer_callbacks/kernel/src/_arch/aarch64/exception.s +++ b/20_timer_callbacks/kernel/src/_arch/aarch64/exception.s @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //-------------------------------------------------------------------------------------------------- // Definitions diff --git a/20_timer_callbacks/kernel/src/_arch/aarch64/exception/asynchronous.rs b/20_timer_callbacks/kernel/src/_arch/aarch64/exception/asynchronous.rs index f545a3e1..811ef138 100644 --- a/20_timer_callbacks/kernel/src/_arch/aarch64/exception/asynchronous.rs +++ b/20_timer_callbacks/kernel/src/_arch/aarch64/exception/asynchronous.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Architectural asynchronous exception handling. //! diff --git a/20_timer_callbacks/kernel/src/_arch/aarch64/memory/mmu.rs b/20_timer_callbacks/kernel/src/_arch/aarch64/memory/mmu.rs index 74a71d11..984b2e04 100644 --- a/20_timer_callbacks/kernel/src/_arch/aarch64/memory/mmu.rs +++ b/20_timer_callbacks/kernel/src/_arch/aarch64/memory/mmu.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Memory Management Unit Driver. //! diff --git a/20_timer_callbacks/kernel/src/_arch/aarch64/memory/mmu/translation_table.rs b/20_timer_callbacks/kernel/src/_arch/aarch64/memory/mmu/translation_table.rs index f0b4ac85..21fae3b8 100644 --- a/20_timer_callbacks/kernel/src/_arch/aarch64/memory/mmu/translation_table.rs +++ b/20_timer_callbacks/kernel/src/_arch/aarch64/memory/mmu/translation_table.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2021-2022 Andre Richter +// Copyright (c) 2021-2023 Andre Richter //! Architectural translation table. //! diff --git a/20_timer_callbacks/kernel/src/_arch/aarch64/time.rs b/20_timer_callbacks/kernel/src/_arch/aarch64/time.rs index 2807bc32..37ebf44b 100644 --- a/20_timer_callbacks/kernel/src/_arch/aarch64/time.rs +++ b/20_timer_callbacks/kernel/src/_arch/aarch64/time.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Architectural timer primitives. //! diff --git a/20_timer_callbacks/kernel/src/backtrace.rs b/20_timer_callbacks/kernel/src/backtrace.rs index 22de6c48..a6af2fcc 100644 --- a/20_timer_callbacks/kernel/src/backtrace.rs +++ b/20_timer_callbacks/kernel/src/backtrace.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2022 Andre Richter +// Copyright (c) 2022-2023 Andre Richter //! Backtracing support. diff --git a/20_timer_callbacks/kernel/src/bsp.rs b/20_timer_callbacks/kernel/src/bsp.rs index 824787f6..246973bc 100644 --- a/20_timer_callbacks/kernel/src/bsp.rs +++ b/20_timer_callbacks/kernel/src/bsp.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Conditional reexporting of Board Support Packages. diff --git a/20_timer_callbacks/kernel/src/bsp/device_driver.rs b/20_timer_callbacks/kernel/src/bsp/device_driver.rs index eafaf775..2dfaec8d 100644 --- a/20_timer_callbacks/kernel/src/bsp/device_driver.rs +++ b/20_timer_callbacks/kernel/src/bsp/device_driver.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Device driver. diff --git a/20_timer_callbacks/kernel/src/bsp/device_driver/arm.rs b/20_timer_callbacks/kernel/src/bsp/device_driver/arm.rs index e83e24c9..8d1cbfbd 100644 --- a/20_timer_callbacks/kernel/src/bsp/device_driver/arm.rs +++ b/20_timer_callbacks/kernel/src/bsp/device_driver/arm.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! ARM driver top level. diff --git a/20_timer_callbacks/kernel/src/bsp/device_driver/arm/gicv2.rs b/20_timer_callbacks/kernel/src/bsp/device_driver/arm/gicv2.rs index fee8bb4c..7dabf793 100644 --- a/20_timer_callbacks/kernel/src/bsp/device_driver/arm/gicv2.rs +++ b/20_timer_callbacks/kernel/src/bsp/device_driver/arm/gicv2.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! GICv2 Driver - ARM Generic Interrupt Controller v2. //! diff --git a/20_timer_callbacks/kernel/src/bsp/device_driver/arm/gicv2/gicc.rs b/20_timer_callbacks/kernel/src/bsp/device_driver/arm/gicv2/gicc.rs index 1a02fc65..0fd16bb3 100644 --- a/20_timer_callbacks/kernel/src/bsp/device_driver/arm/gicv2/gicc.rs +++ b/20_timer_callbacks/kernel/src/bsp/device_driver/arm/gicv2/gicc.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! GICC Driver - GIC CPU interface. diff --git a/20_timer_callbacks/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs b/20_timer_callbacks/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs index 8aebcf2b..1fc9d70e 100644 --- a/20_timer_callbacks/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs +++ b/20_timer_callbacks/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! GICD Driver - GIC Distributor. //! diff --git a/20_timer_callbacks/kernel/src/bsp/device_driver/bcm.rs b/20_timer_callbacks/kernel/src/bsp/device_driver/bcm.rs index 5a7cc23b..7b7c288b 100644 --- a/20_timer_callbacks/kernel/src/bsp/device_driver/bcm.rs +++ b/20_timer_callbacks/kernel/src/bsp/device_driver/bcm.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! BCM driver top level. diff --git a/20_timer_callbacks/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs b/20_timer_callbacks/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs index fb61a651..812156f4 100644 --- a/20_timer_callbacks/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs +++ b/20_timer_callbacks/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! GPIO Driver. diff --git a/20_timer_callbacks/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs b/20_timer_callbacks/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs index 6c2cd451..d32bd8db 100644 --- a/20_timer_callbacks/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs +++ b/20_timer_callbacks/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Interrupt Controller Driver. diff --git a/20_timer_callbacks/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/local_ic.rs b/20_timer_callbacks/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/local_ic.rs index ac382e95..b5e4974b 100644 --- a/20_timer_callbacks/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/local_ic.rs +++ b/20_timer_callbacks/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/local_ic.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2022 Andre Richter +// Copyright (c) 2022-2023 Andre Richter //! Local Interrupt Controller Driver. //! diff --git a/20_timer_callbacks/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs b/20_timer_callbacks/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs index 238088a8..029c1e74 100644 --- a/20_timer_callbacks/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs +++ b/20_timer_callbacks/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Peripheral Interrupt Controller Driver. //! diff --git a/20_timer_callbacks/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs b/20_timer_callbacks/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs index 3e7e1812..3d580975 100644 --- a/20_timer_callbacks/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs +++ b/20_timer_callbacks/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! PL011 UART driver. //! diff --git a/20_timer_callbacks/kernel/src/bsp/device_driver/common.rs b/20_timer_callbacks/kernel/src/bsp/device_driver/common.rs index ca7aeb76..3ce1d8d8 100644 --- a/20_timer_callbacks/kernel/src/bsp/device_driver/common.rs +++ b/20_timer_callbacks/kernel/src/bsp/device_driver/common.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Common device driver code. diff --git a/20_timer_callbacks/kernel/src/bsp/raspberrypi.rs b/20_timer_callbacks/kernel/src/bsp/raspberrypi.rs index 474419f4..30421dfa 100644 --- a/20_timer_callbacks/kernel/src/bsp/raspberrypi.rs +++ b/20_timer_callbacks/kernel/src/bsp/raspberrypi.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Top-level BSP file for the Raspberry Pi 3 and 4. diff --git a/20_timer_callbacks/kernel/src/bsp/raspberrypi/cpu.rs b/20_timer_callbacks/kernel/src/bsp/raspberrypi/cpu.rs index 85fb89e4..65cf5abb 100644 --- a/20_timer_callbacks/kernel/src/bsp/raspberrypi/cpu.rs +++ b/20_timer_callbacks/kernel/src/bsp/raspberrypi/cpu.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! BSP Processor code. diff --git a/20_timer_callbacks/kernel/src/bsp/raspberrypi/driver.rs b/20_timer_callbacks/kernel/src/bsp/raspberrypi/driver.rs index a23b08c0..d02909e3 100644 --- a/20_timer_callbacks/kernel/src/bsp/raspberrypi/driver.rs +++ b/20_timer_callbacks/kernel/src/bsp/raspberrypi/driver.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! BSP driver support. diff --git a/20_timer_callbacks/kernel/src/bsp/raspberrypi/exception.rs b/20_timer_callbacks/kernel/src/bsp/raspberrypi/exception.rs index aa6c5a63..a9eaa6ac 100644 --- a/20_timer_callbacks/kernel/src/bsp/raspberrypi/exception.rs +++ b/20_timer_callbacks/kernel/src/bsp/raspberrypi/exception.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! BSP synchronous and asynchronous exception handling. diff --git a/20_timer_callbacks/kernel/src/bsp/raspberrypi/exception/asynchronous.rs b/20_timer_callbacks/kernel/src/bsp/raspberrypi/exception/asynchronous.rs index b2cb955e..82935adb 100644 --- a/20_timer_callbacks/kernel/src/bsp/raspberrypi/exception/asynchronous.rs +++ b/20_timer_callbacks/kernel/src/bsp/raspberrypi/exception/asynchronous.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! BSP asynchronous exception handling. diff --git a/20_timer_callbacks/kernel/src/bsp/raspberrypi/memory.rs b/20_timer_callbacks/kernel/src/bsp/raspberrypi/memory.rs index d07c9695..f8c9b6a1 100644 --- a/20_timer_callbacks/kernel/src/bsp/raspberrypi/memory.rs +++ b/20_timer_callbacks/kernel/src/bsp/raspberrypi/memory.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! BSP Memory Management. //! diff --git a/20_timer_callbacks/kernel/src/bsp/raspberrypi/memory/mmu.rs b/20_timer_callbacks/kernel/src/bsp/raspberrypi/memory/mmu.rs index bb2f8208..ef52e368 100644 --- a/20_timer_callbacks/kernel/src/bsp/raspberrypi/memory/mmu.rs +++ b/20_timer_callbacks/kernel/src/bsp/raspberrypi/memory/mmu.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! BSP Memory Management Unit. diff --git a/20_timer_callbacks/kernel/src/common.rs b/20_timer_callbacks/kernel/src/common.rs index f32f650f..2ad7e4c1 100644 --- a/20_timer_callbacks/kernel/src/common.rs +++ b/20_timer_callbacks/kernel/src/common.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! General purpose code. diff --git a/20_timer_callbacks/kernel/src/console.rs b/20_timer_callbacks/kernel/src/console.rs index ff1d8ddc..5efa9395 100644 --- a/20_timer_callbacks/kernel/src/console.rs +++ b/20_timer_callbacks/kernel/src/console.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! System console. diff --git a/20_timer_callbacks/kernel/src/console/buffer_console.rs b/20_timer_callbacks/kernel/src/console/buffer_console.rs index c3259f89..05903e7c 100644 --- a/20_timer_callbacks/kernel/src/console/buffer_console.rs +++ b/20_timer_callbacks/kernel/src/console/buffer_console.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2022 Andre Richter +// Copyright (c) 2022-2023 Andre Richter //! A console that buffers input during the init phase. diff --git a/20_timer_callbacks/kernel/src/cpu.rs b/20_timer_callbacks/kernel/src/cpu.rs index e1493d1d..8716a918 100644 --- a/20_timer_callbacks/kernel/src/cpu.rs +++ b/20_timer_callbacks/kernel/src/cpu.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Processor code. diff --git a/20_timer_callbacks/kernel/src/cpu/boot.rs b/20_timer_callbacks/kernel/src/cpu/boot.rs index 8091dac3..b1e98328 100644 --- a/20_timer_callbacks/kernel/src/cpu/boot.rs +++ b/20_timer_callbacks/kernel/src/cpu/boot.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2021-2022 Andre Richter +// Copyright (c) 2021-2023 Andre Richter //! Boot code. diff --git a/20_timer_callbacks/kernel/src/cpu/smp.rs b/20_timer_callbacks/kernel/src/cpu/smp.rs index 57386f79..de612d58 100644 --- a/20_timer_callbacks/kernel/src/cpu/smp.rs +++ b/20_timer_callbacks/kernel/src/cpu/smp.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Symmetric multiprocessing. diff --git a/20_timer_callbacks/kernel/src/driver.rs b/20_timer_callbacks/kernel/src/driver.rs index 2f22fd20..88b41b81 100644 --- a/20_timer_callbacks/kernel/src/driver.rs +++ b/20_timer_callbacks/kernel/src/driver.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Driver support. diff --git a/20_timer_callbacks/kernel/src/exception.rs b/20_timer_callbacks/kernel/src/exception.rs index 7ea7cd80..3d5f219f 100644 --- a/20_timer_callbacks/kernel/src/exception.rs +++ b/20_timer_callbacks/kernel/src/exception.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Synchronous and asynchronous exception handling. diff --git a/20_timer_callbacks/kernel/src/exception/asynchronous.rs b/20_timer_callbacks/kernel/src/exception/asynchronous.rs index c1f2a27b..2c874dd6 100644 --- a/20_timer_callbacks/kernel/src/exception/asynchronous.rs +++ b/20_timer_callbacks/kernel/src/exception/asynchronous.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Asynchronous exception handling. diff --git a/20_timer_callbacks/kernel/src/exception/asynchronous/null_irq_manager.rs b/20_timer_callbacks/kernel/src/exception/asynchronous/null_irq_manager.rs index 438f9649..38919ffe 100644 --- a/20_timer_callbacks/kernel/src/exception/asynchronous/null_irq_manager.rs +++ b/20_timer_callbacks/kernel/src/exception/asynchronous/null_irq_manager.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2022 Andre Richter +// Copyright (c) 2022-2023 Andre Richter //! Null IRQ Manager. diff --git a/20_timer_callbacks/kernel/src/lib.rs b/20_timer_callbacks/kernel/src/lib.rs index bba0fcc7..317bcc72 100644 --- a/20_timer_callbacks/kernel/src/lib.rs +++ b/20_timer_callbacks/kernel/src/lib.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter // Rust embedded logo for `make doc`. #![doc( diff --git a/20_timer_callbacks/kernel/src/main.rs b/20_timer_callbacks/kernel/src/main.rs index 28b75340..249b2718 100644 --- a/20_timer_callbacks/kernel/src/main.rs +++ b/20_timer_callbacks/kernel/src/main.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter // Rust embedded logo for `make doc`. #![doc( diff --git a/20_timer_callbacks/kernel/src/memory.rs b/20_timer_callbacks/kernel/src/memory.rs index a64bfbae..bc611336 100644 --- a/20_timer_callbacks/kernel/src/memory.rs +++ b/20_timer_callbacks/kernel/src/memory.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Memory Management. diff --git a/20_timer_callbacks/kernel/src/memory/heap_alloc.rs b/20_timer_callbacks/kernel/src/memory/heap_alloc.rs index c0f56d8d..cf4298fa 100644 --- a/20_timer_callbacks/kernel/src/memory/heap_alloc.rs +++ b/20_timer_callbacks/kernel/src/memory/heap_alloc.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2022 Andre Richter +// Copyright (c) 2022-2023 Andre Richter //! Heap allocation. diff --git a/20_timer_callbacks/kernel/src/memory/mmu.rs b/20_timer_callbacks/kernel/src/memory/mmu.rs index 8d204a4e..abe3b181 100644 --- a/20_timer_callbacks/kernel/src/memory/mmu.rs +++ b/20_timer_callbacks/kernel/src/memory/mmu.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Memory Management Unit. diff --git a/20_timer_callbacks/kernel/src/memory/mmu/mapping_record.rs b/20_timer_callbacks/kernel/src/memory/mmu/mapping_record.rs index 4e9395da..9c17258d 100644 --- a/20_timer_callbacks/kernel/src/memory/mmu/mapping_record.rs +++ b/20_timer_callbacks/kernel/src/memory/mmu/mapping_record.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! A record of mapped pages. diff --git a/20_timer_callbacks/kernel/src/memory/mmu/page_alloc.rs b/20_timer_callbacks/kernel/src/memory/mmu/page_alloc.rs index 347fcd34..344afd20 100644 --- a/20_timer_callbacks/kernel/src/memory/mmu/page_alloc.rs +++ b/20_timer_callbacks/kernel/src/memory/mmu/page_alloc.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2021-2022 Andre Richter +// Copyright (c) 2021-2023 Andre Richter //! Page allocation. diff --git a/20_timer_callbacks/kernel/src/memory/mmu/translation_table.rs b/20_timer_callbacks/kernel/src/memory/mmu/translation_table.rs index 9301bb0c..341ffc5c 100644 --- a/20_timer_callbacks/kernel/src/memory/mmu/translation_table.rs +++ b/20_timer_callbacks/kernel/src/memory/mmu/translation_table.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2021-2022 Andre Richter +// Copyright (c) 2021-2023 Andre Richter //! Translation table. diff --git a/20_timer_callbacks/kernel/src/memory/mmu/types.rs b/20_timer_callbacks/kernel/src/memory/mmu/types.rs index 62f3926e..f6ac8d59 100644 --- a/20_timer_callbacks/kernel/src/memory/mmu/types.rs +++ b/20_timer_callbacks/kernel/src/memory/mmu/types.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Memory Management Unit types. diff --git a/20_timer_callbacks/kernel/src/panic_wait.rs b/20_timer_callbacks/kernel/src/panic_wait.rs index bc95f77c..389eb2c8 100644 --- a/20_timer_callbacks/kernel/src/panic_wait.rs +++ b/20_timer_callbacks/kernel/src/panic_wait.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! A panic handler that infinitely waits. diff --git a/20_timer_callbacks/kernel/src/print.rs b/20_timer_callbacks/kernel/src/print.rs index 8d56d2e4..a89f8201 100644 --- a/20_timer_callbacks/kernel/src/print.rs +++ b/20_timer_callbacks/kernel/src/print.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Printing. diff --git a/20_timer_callbacks/kernel/src/state.rs b/20_timer_callbacks/kernel/src/state.rs index 0af3688c..6d99beed 100644 --- a/20_timer_callbacks/kernel/src/state.rs +++ b/20_timer_callbacks/kernel/src/state.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! State information about the kernel itself. diff --git a/20_timer_callbacks/kernel/src/symbols.rs b/20_timer_callbacks/kernel/src/symbols.rs index 680b8eaf..fdc1d084 100644 --- a/20_timer_callbacks/kernel/src/symbols.rs +++ b/20_timer_callbacks/kernel/src/symbols.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2022 Andre Richter +// Copyright (c) 2022-2023 Andre Richter //! Debug symbol support. diff --git a/20_timer_callbacks/kernel/src/synchronization.rs b/20_timer_callbacks/kernel/src/synchronization.rs index ab2b86e6..5740b63e 100644 --- a/20_timer_callbacks/kernel/src/synchronization.rs +++ b/20_timer_callbacks/kernel/src/synchronization.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Synchronization primitives. //! diff --git a/20_timer_callbacks/kernel/src/time.rs b/20_timer_callbacks/kernel/src/time.rs index 80194182..5767a3e6 100644 --- a/20_timer_callbacks/kernel/src/time.rs +++ b/20_timer_callbacks/kernel/src/time.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Timer primitives. //! diff --git a/20_timer_callbacks/kernel/tests/00_console_sanity.rb b/20_timer_callbacks/kernel/tests/00_console_sanity.rb index 4dde5576..8be7a2f1 100644 --- a/20_timer_callbacks/kernel/tests/00_console_sanity.rb +++ b/20_timer_callbacks/kernel/tests/00_console_sanity.rb @@ -2,7 +2,7 @@ # SPDX-License-Identifier: MIT OR Apache-2.0 # -# Copyright (c) 2019-2022 Andre Richter +# Copyright (c) 2019-2023 Andre Richter require 'console_io_test' @@ -40,9 +40,9 @@ class RxStatisticsTest < SubtestBase end end -##-------------------------------------------------------------------------------------------------- +## ------------------------------------------------------------------------------------------------- ## Test registration -##-------------------------------------------------------------------------------------------------- +## ------------------------------------------------------------------------------------------------- def subtest_collection [TxRxHandshakeTest.new, TxStatisticsTest.new, RxStatisticsTest.new] end diff --git a/20_timer_callbacks/kernel/tests/00_console_sanity.rs b/20_timer_callbacks/kernel/tests/00_console_sanity.rs index 2c0225b7..682ea9b8 100644 --- a/20_timer_callbacks/kernel/tests/00_console_sanity.rs +++ b/20_timer_callbacks/kernel/tests/00_console_sanity.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2019-2022 Andre Richter +// Copyright (c) 2019-2023 Andre Richter //! Console sanity tests - RX, TX and statistics. diff --git a/20_timer_callbacks/kernel/tests/01_timer_sanity.rs b/20_timer_callbacks/kernel/tests/01_timer_sanity.rs index 8188b942..1581a02e 100644 --- a/20_timer_callbacks/kernel/tests/01_timer_sanity.rs +++ b/20_timer_callbacks/kernel/tests/01_timer_sanity.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2019-2022 Andre Richter +// Copyright (c) 2019-2023 Andre Richter //! Timer sanity tests. diff --git a/20_timer_callbacks/kernel/tests/02_exception_sync_page_fault.rs b/20_timer_callbacks/kernel/tests/02_exception_sync_page_fault.rs index fab44c8f..09d17798 100644 --- a/20_timer_callbacks/kernel/tests/02_exception_sync_page_fault.rs +++ b/20_timer_callbacks/kernel/tests/02_exception_sync_page_fault.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2019-2022 Andre Richter +// Copyright (c) 2019-2023 Andre Richter //! Page faults must result in synchronous exceptions. diff --git a/20_timer_callbacks/kernel/tests/03_exception_restore_sanity.rb b/20_timer_callbacks/kernel/tests/03_exception_restore_sanity.rb index 5f52e0c7..02f51f74 100644 --- a/20_timer_callbacks/kernel/tests/03_exception_restore_sanity.rb +++ b/20_timer_callbacks/kernel/tests/03_exception_restore_sanity.rb @@ -2,7 +2,7 @@ # SPDX-License-Identifier: MIT OR Apache-2.0 # -# Copyright (c) 2022 Andre Richter +# Copyright (c) 2022-2023 Andre Richter require 'console_io_test' @@ -17,9 +17,9 @@ class ExceptionRestoreTest < SubtestBase end end -##-------------------------------------------------------------------------------------------------- +## ------------------------------------------------------------------------------------------------- ## Test registration -##-------------------------------------------------------------------------------------------------- +## ------------------------------------------------------------------------------------------------- def subtest_collection [ExceptionRestoreTest.new] end diff --git a/20_timer_callbacks/kernel/tests/03_exception_restore_sanity.rs b/20_timer_callbacks/kernel/tests/03_exception_restore_sanity.rs index f176c6a6..1a302911 100644 --- a/20_timer_callbacks/kernel/tests/03_exception_restore_sanity.rs +++ b/20_timer_callbacks/kernel/tests/03_exception_restore_sanity.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2022 Andre Richter +// Copyright (c) 2022-2023 Andre Richter //! A simple sanity test to see if exception restore code works. diff --git a/20_timer_callbacks/kernel/tests/04_exception_irq_sanity.rs b/20_timer_callbacks/kernel/tests/04_exception_irq_sanity.rs index e6f94c91..fcace897 100644 --- a/20_timer_callbacks/kernel/tests/04_exception_irq_sanity.rs +++ b/20_timer_callbacks/kernel/tests/04_exception_irq_sanity.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! IRQ handling sanity tests. diff --git a/20_timer_callbacks/kernel/tests/05_backtrace_sanity.rb b/20_timer_callbacks/kernel/tests/05_backtrace_sanity.rb index 5650f97c..243e2fc8 100644 --- a/20_timer_callbacks/kernel/tests/05_backtrace_sanity.rb +++ b/20_timer_callbacks/kernel/tests/05_backtrace_sanity.rb @@ -2,7 +2,7 @@ # SPDX-License-Identifier: MIT OR Apache-2.0 # -# Copyright (c) 2022 Andre Richter +# Copyright (c) 2022-2023 Andre Richter require 'console_io_test' @@ -31,9 +31,9 @@ class BacktraceCorrectnessTest < SubtestBase end end -##-------------------------------------------------------------------------------------------------- +## ------------------------------------------------------------------------------------------------- ## Test registration -##-------------------------------------------------------------------------------------------------- +## ------------------------------------------------------------------------------------------------- def subtest_collection [PanicBacktraceTest.new, BacktraceCorrectnessTest.new] end diff --git a/20_timer_callbacks/kernel/tests/05_backtrace_sanity.rs b/20_timer_callbacks/kernel/tests/05_backtrace_sanity.rs index f75c0ea3..66fd0a3e 100644 --- a/20_timer_callbacks/kernel/tests/05_backtrace_sanity.rs +++ b/20_timer_callbacks/kernel/tests/05_backtrace_sanity.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2022 Andre Richter +// Copyright (c) 2022-2023 Andre Richter //! Test if backtracing code detects an invalid frame pointer. diff --git a/20_timer_callbacks/kernel/tests/06_backtrace_invalid_frame.rb b/20_timer_callbacks/kernel/tests/06_backtrace_invalid_frame.rb index 7601cf97..80695468 100644 --- a/20_timer_callbacks/kernel/tests/06_backtrace_invalid_frame.rb +++ b/20_timer_callbacks/kernel/tests/06_backtrace_invalid_frame.rb @@ -2,7 +2,7 @@ # SPDX-License-Identifier: MIT OR Apache-2.0 # -# Copyright (c) 2022 Andre Richter +# Copyright (c) 2022-2023 Andre Richter require 'console_io_test' @@ -18,9 +18,9 @@ class InvalidFramePointerTest < SubtestBase end end -##-------------------------------------------------------------------------------------------------- +## ------------------------------------------------------------------------------------------------- ## Test registration -##-------------------------------------------------------------------------------------------------- +## ------------------------------------------------------------------------------------------------- def subtest_collection [InvalidFramePointerTest.new] end diff --git a/20_timer_callbacks/kernel/tests/06_backtrace_invalid_frame.rs b/20_timer_callbacks/kernel/tests/06_backtrace_invalid_frame.rs index 33d3c02d..38411af6 100644 --- a/20_timer_callbacks/kernel/tests/06_backtrace_invalid_frame.rs +++ b/20_timer_callbacks/kernel/tests/06_backtrace_invalid_frame.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2022 Andre Richter +// Copyright (c) 2022-2023 Andre Richter //! Test if backtracing code detects an invalid frame pointer. diff --git a/20_timer_callbacks/kernel/tests/07_backtrace_invalid_link.rb b/20_timer_callbacks/kernel/tests/07_backtrace_invalid_link.rb index 0fabcf4c..6b6f0413 100644 --- a/20_timer_callbacks/kernel/tests/07_backtrace_invalid_link.rb +++ b/20_timer_callbacks/kernel/tests/07_backtrace_invalid_link.rb @@ -2,7 +2,7 @@ # SPDX-License-Identifier: MIT OR Apache-2.0 # -# Copyright (c) 2022 Andre Richter +# Copyright (c) 2022-2023 Andre Richter require 'console_io_test' @@ -17,9 +17,9 @@ class InvalidLinkTest < SubtestBase end end -##-------------------------------------------------------------------------------------------------- +## ------------------------------------------------------------------------------------------------- ## Test registration -##-------------------------------------------------------------------------------------------------- +## ------------------------------------------------------------------------------------------------- def subtest_collection [InvalidLinkTest.new] end diff --git a/20_timer_callbacks/kernel/tests/07_backtrace_invalid_link.rs b/20_timer_callbacks/kernel/tests/07_backtrace_invalid_link.rs index bcb0538a..6e0873dd 100644 --- a/20_timer_callbacks/kernel/tests/07_backtrace_invalid_link.rs +++ b/20_timer_callbacks/kernel/tests/07_backtrace_invalid_link.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2022 Andre Richter +// Copyright (c) 2022-2023 Andre Richter //! Test if backtracing code detects an invalid link. diff --git a/20_timer_callbacks/kernel/tests/panic_exit_success/mod.rs b/20_timer_callbacks/kernel/tests/panic_exit_success/mod.rs index 908fac51..449ad6f9 100644 --- a/20_timer_callbacks/kernel/tests/panic_exit_success/mod.rs +++ b/20_timer_callbacks/kernel/tests/panic_exit_success/mod.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2019-2022 Andre Richter +// Copyright (c) 2019-2023 Andre Richter /// Overwrites libkernel's `panic_wait::_panic_exit()` with the QEMU-exit version. #[no_mangle] diff --git a/20_timer_callbacks/kernel/tests/panic_wait_forever/mod.rs b/20_timer_callbacks/kernel/tests/panic_wait_forever/mod.rs index 7a4effa5..9ac19144 100644 --- a/20_timer_callbacks/kernel/tests/panic_wait_forever/mod.rs +++ b/20_timer_callbacks/kernel/tests/panic_wait_forever/mod.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2022 Andre Richter +// Copyright (c) 2022-2023 Andre Richter /// Overwrites libkernel's `panic_wait::_panic_exit()` with wait_forever. #[no_mangle] diff --git a/20_timer_callbacks/kernel_symbols.mk b/20_timer_callbacks/kernel_symbols.mk index d496ea8a..d38b7785 100644 --- a/20_timer_callbacks/kernel_symbols.mk +++ b/20_timer_callbacks/kernel_symbols.mk @@ -1,6 +1,6 @@ ## SPDX-License-Identifier: MIT OR Apache-2.0 ## -## Copyright (c) 2018-2022 Andre Richter +## Copyright (c) 2018-2023 Andre Richter include ../common/format.mk include ../common/docker.mk diff --git a/20_timer_callbacks/kernel_symbols/kernel_symbols.ld b/20_timer_callbacks/kernel_symbols/kernel_symbols.ld index 0625f008..16724a07 100644 --- a/20_timer_callbacks/kernel_symbols/kernel_symbols.ld +++ b/20_timer_callbacks/kernel_symbols/kernel_symbols.ld @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: MIT OR Apache-2.0 * - * Copyright (c) 2022 Andre Richter + * Copyright (c) 2022-2023 Andre Richter */ SECTIONS diff --git a/20_timer_callbacks/kernel_symbols/src/main.rs b/20_timer_callbacks/kernel_symbols/src/main.rs index bd90b535..38ce18f8 100644 --- a/20_timer_callbacks/kernel_symbols/src/main.rs +++ b/20_timer_callbacks/kernel_symbols/src/main.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2022 Andre Richter +// Copyright (c) 2022-2023 Andre Richter //! Generation of kernel symbols. diff --git a/20_timer_callbacks/libraries/debug-symbol-types/src/lib.rs b/20_timer_callbacks/libraries/debug-symbol-types/src/lib.rs index b6dff082..81c897bf 100644 --- a/20_timer_callbacks/libraries/debug-symbol-types/src/lib.rs +++ b/20_timer_callbacks/libraries/debug-symbol-types/src/lib.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2022 Andre Richter +// Copyright (c) 2022-2023 Andre Richter //! Types for implementing debug symbol support. diff --git a/20_timer_callbacks/libraries/test-macros/src/lib.rs b/20_timer_callbacks/libraries/test-macros/src/lib.rs index 9879677c..52cf893d 100644 --- a/20_timer_callbacks/libraries/test-macros/src/lib.rs +++ b/20_timer_callbacks/libraries/test-macros/src/lib.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2019-2022 Andre Richter +// Copyright (c) 2019-2023 Andre Richter use proc_macro::TokenStream; use proc_macro2::Span; diff --git a/20_timer_callbacks/libraries/test-types/src/lib.rs b/20_timer_callbacks/libraries/test-types/src/lib.rs index 922c2a1c..38961a9c 100644 --- a/20_timer_callbacks/libraries/test-types/src/lib.rs +++ b/20_timer_callbacks/libraries/test-types/src/lib.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2019-2022 Andre Richter +// Copyright (c) 2019-2023 Andre Richter //! Types for the `custom_test_frameworks` implementation. diff --git a/20_timer_callbacks/tools/kernel_symbols_tool/cmds.rb b/20_timer_callbacks/tools/kernel_symbols_tool/cmds.rb index fe66ea71..c43acb24 100644 --- a/20_timer_callbacks/tools/kernel_symbols_tool/cmds.rb +++ b/20_timer_callbacks/tools/kernel_symbols_tool/cmds.rb @@ -2,7 +2,7 @@ # SPDX-License-Identifier: MIT OR Apache-2.0 # -# Copyright (c) 2022 Andre Richter +# Copyright (c) 2022-2023 Andre Richter def generate_symbols(kernel_elf, output_file) File.open(output_file, 'w') do |file| diff --git a/20_timer_callbacks/tools/kernel_symbols_tool/kernel_elf.rb b/20_timer_callbacks/tools/kernel_symbols_tool/kernel_elf.rb index b1649767..32b5460a 100644 --- a/20_timer_callbacks/tools/kernel_symbols_tool/kernel_elf.rb +++ b/20_timer_callbacks/tools/kernel_symbols_tool/kernel_elf.rb @@ -2,7 +2,7 @@ # SPDX-License-Identifier: MIT OR Apache-2.0 # -# Copyright (c) 2021-2022 Andre Richter +# Copyright (c) 2021-2023 Andre Richter # KernelELF class KernelELF diff --git a/20_timer_callbacks/tools/kernel_symbols_tool/main.rb b/20_timer_callbacks/tools/kernel_symbols_tool/main.rb index 30a8be6f..899f9646 100755 --- a/20_timer_callbacks/tools/kernel_symbols_tool/main.rb +++ b/20_timer_callbacks/tools/kernel_symbols_tool/main.rb @@ -3,7 +3,7 @@ # SPDX-License-Identifier: MIT OR Apache-2.0 # -# Copyright (c) 2022 Andre Richter +# Copyright (c) 2022-2023 Andre Richter require 'rubygems' require 'bundler/setup' diff --git a/20_timer_callbacks/tools/translation_table_tool/arch.rb b/20_timer_callbacks/tools/translation_table_tool/arch.rb index deceb6d0..61a6d6ca 100644 --- a/20_timer_callbacks/tools/translation_table_tool/arch.rb +++ b/20_timer_callbacks/tools/translation_table_tool/arch.rb @@ -2,7 +2,7 @@ # SPDX-License-Identifier: MIT OR Apache-2.0 # -# Copyright (c) 2021-2022 Andre Richter +# Copyright (c) 2021-2023 Andre Richter # Bitfield manipulation. class BitField diff --git a/20_timer_callbacks/tools/translation_table_tool/bsp.rb b/20_timer_callbacks/tools/translation_table_tool/bsp.rb index dbab5ab6..5887d774 100644 --- a/20_timer_callbacks/tools/translation_table_tool/bsp.rb +++ b/20_timer_callbacks/tools/translation_table_tool/bsp.rb @@ -2,7 +2,7 @@ # SPDX-License-Identifier: MIT OR Apache-2.0 # -# Copyright (c) 2021-2022 Andre Richter +# Copyright (c) 2021-2023 Andre Richter # Raspberry Pi 3 + 4 class RaspberryPi diff --git a/20_timer_callbacks/tools/translation_table_tool/generic.rb b/20_timer_callbacks/tools/translation_table_tool/generic.rb index eee8ccda..941e2226 100644 --- a/20_timer_callbacks/tools/translation_table_tool/generic.rb +++ b/20_timer_callbacks/tools/translation_table_tool/generic.rb @@ -2,7 +2,7 @@ # SPDX-License-Identifier: MIT OR Apache-2.0 # -# Copyright (c) 2021-2022 Andre Richter +# Copyright (c) 2021-2023 Andre Richter module Granule64KiB SIZE = 64 * 1024 @@ -161,7 +161,7 @@ def kernel_map_binary mapping_descriptors.each do |i| print 'Generating'.rjust(12).green.bold print ' ' - puts i.to_s + puts i TRANSLATION_TABLES.map_at(i.virt_region, i.phys_region, i.attributes) end diff --git a/20_timer_callbacks/tools/translation_table_tool/kernel_elf.rb b/20_timer_callbacks/tools/translation_table_tool/kernel_elf.rb index f2d5b0b7..5ba78d9d 100644 --- a/20_timer_callbacks/tools/translation_table_tool/kernel_elf.rb +++ b/20_timer_callbacks/tools/translation_table_tool/kernel_elf.rb @@ -2,7 +2,7 @@ # SPDX-License-Identifier: MIT OR Apache-2.0 # -# Copyright (c) 2021-2022 Andre Richter +# Copyright (c) 2021-2023 Andre Richter # KernelELF class KernelELF diff --git a/20_timer_callbacks/tools/translation_table_tool/main.rb b/20_timer_callbacks/tools/translation_table_tool/main.rb index 6419e364..22ab24fd 100755 --- a/20_timer_callbacks/tools/translation_table_tool/main.rb +++ b/20_timer_callbacks/tools/translation_table_tool/main.rb @@ -3,7 +3,7 @@ # SPDX-License-Identifier: MIT OR Apache-2.0 # -# Copyright (c) 2021-2022 Andre Richter +# Copyright (c) 2021-2023 Andre Richter require 'rubygems' require 'bundler/setup' diff --git a/LICENSE-MIT b/LICENSE-MIT index d36a7e18..af7f918f 100644 --- a/LICENSE-MIT +++ b/LICENSE-MIT @@ -1,6 +1,6 @@ MIT License -Copyright (C) 2018-2022 by the respective authors +Copyright (C) 2018-2023 by the respective authors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/X1_JTAG_boot/.vscode/settings.json b/X1_JTAG_boot/.vscode/settings.json index d1916456..bfa278e9 100644 --- a/X1_JTAG_boot/.vscode/settings.json +++ b/X1_JTAG_boot/.vscode/settings.json @@ -1,10 +1,10 @@ { - "editor.formatOnSave": true, - "editor.rulers": [100], - "rust-analyzer.cargo.target": "aarch64-unknown-none-softfloat", - "rust-analyzer.cargo.features": ["bsp_rpi3"], - "rust-analyzer.checkOnSave.allTargets": false, - "rust-analyzer.checkOnSave.extraArgs": ["--bins"], - "rust-analyzer.lens.debug": false, - "rust-analyzer.lens.run": false + "editor.formatOnSave": true, + "editor.rulers": [100], + "rust-analyzer.cargo.target": "aarch64-unknown-none-softfloat", + "rust-analyzer.cargo.features": ["bsp_rpi3"], + "rust-analyzer.checkOnSave.allTargets": false, + "rust-analyzer.checkOnSave.extraArgs": ["--bins"], + "rust-analyzer.lens.debug": false, + "rust-analyzer.lens.run": false } diff --git a/X1_JTAG_boot/Makefile b/X1_JTAG_boot/Makefile index 23de6557..b13f0dfb 100644 --- a/X1_JTAG_boot/Makefile +++ b/X1_JTAG_boot/Makefile @@ -1,6 +1,6 @@ ## SPDX-License-Identifier: MIT OR Apache-2.0 ## -## Copyright (c) 2018-2022 Andre Richter +## Copyright (c) 2018-2023 Andre Richter include ../common/docker.mk include ../common/format.mk diff --git a/X1_JTAG_boot/src/_arch/aarch64/cpu.rs b/X1_JTAG_boot/src/_arch/aarch64/cpu.rs index bbe7687a..602c9789 100644 --- a/X1_JTAG_boot/src/_arch/aarch64/cpu.rs +++ b/X1_JTAG_boot/src/_arch/aarch64/cpu.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Architectural processor code. //! diff --git a/X1_JTAG_boot/src/_arch/aarch64/cpu/boot.rs b/X1_JTAG_boot/src/_arch/aarch64/cpu/boot.rs index 8390c013..2a6c4649 100644 --- a/X1_JTAG_boot/src/_arch/aarch64/cpu/boot.rs +++ b/X1_JTAG_boot/src/_arch/aarch64/cpu/boot.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2021-2022 Andre Richter +// Copyright (c) 2021-2023 Andre Richter //! Architectural boot code. //! diff --git a/X1_JTAG_boot/src/_arch/aarch64/cpu/boot.s b/X1_JTAG_boot/src/_arch/aarch64/cpu/boot.s index aa701fd1..78f8c321 100644 --- a/X1_JTAG_boot/src/_arch/aarch64/cpu/boot.s +++ b/X1_JTAG_boot/src/_arch/aarch64/cpu/boot.s @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2021-2022 Andre Richter +// Copyright (c) 2021-2023 Andre Richter //-------------------------------------------------------------------------------------------------- // Definitions diff --git a/X1_JTAG_boot/src/_arch/aarch64/time.rs b/X1_JTAG_boot/src/_arch/aarch64/time.rs index 400b3dcc..eb97b8be 100644 --- a/X1_JTAG_boot/src/_arch/aarch64/time.rs +++ b/X1_JTAG_boot/src/_arch/aarch64/time.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Architectural timer primitives. //! diff --git a/X1_JTAG_boot/src/bsp.rs b/X1_JTAG_boot/src/bsp.rs index 824787f6..246973bc 100644 --- a/X1_JTAG_boot/src/bsp.rs +++ b/X1_JTAG_boot/src/bsp.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Conditional reexporting of Board Support Packages. diff --git a/X1_JTAG_boot/src/bsp/device_driver.rs b/X1_JTAG_boot/src/bsp/device_driver.rs index 6e9bf8f3..64049a4c 100644 --- a/X1_JTAG_boot/src/bsp/device_driver.rs +++ b/X1_JTAG_boot/src/bsp/device_driver.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Device driver. diff --git a/X1_JTAG_boot/src/bsp/device_driver/bcm.rs b/X1_JTAG_boot/src/bsp/device_driver/bcm.rs index b4b7906e..1c343d1d 100644 --- a/X1_JTAG_boot/src/bsp/device_driver/bcm.rs +++ b/X1_JTAG_boot/src/bsp/device_driver/bcm.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! BCM driver top level. diff --git a/X1_JTAG_boot/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs b/X1_JTAG_boot/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs index 24e537cf..8e57dfed 100644 --- a/X1_JTAG_boot/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs +++ b/X1_JTAG_boot/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! GPIO Driver. diff --git a/X1_JTAG_boot/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs b/X1_JTAG_boot/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs index b034e92e..d92612ea 100644 --- a/X1_JTAG_boot/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs +++ b/X1_JTAG_boot/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! PL011 UART driver. //! diff --git a/X1_JTAG_boot/src/bsp/device_driver/common.rs b/X1_JTAG_boot/src/bsp/device_driver/common.rs index fd9e988e..dfe7d8ef 100644 --- a/X1_JTAG_boot/src/bsp/device_driver/common.rs +++ b/X1_JTAG_boot/src/bsp/device_driver/common.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Common device driver code. diff --git a/X1_JTAG_boot/src/bsp/raspberrypi.rs b/X1_JTAG_boot/src/bsp/raspberrypi.rs index 7bda8a4d..b6d48fdd 100644 --- a/X1_JTAG_boot/src/bsp/raspberrypi.rs +++ b/X1_JTAG_boot/src/bsp/raspberrypi.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Top-level BSP file for the Raspberry Pi 3 and 4. diff --git a/X1_JTAG_boot/src/bsp/raspberrypi/cpu.rs b/X1_JTAG_boot/src/bsp/raspberrypi/cpu.rs index 85fb89e4..65cf5abb 100644 --- a/X1_JTAG_boot/src/bsp/raspberrypi/cpu.rs +++ b/X1_JTAG_boot/src/bsp/raspberrypi/cpu.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! BSP Processor code. diff --git a/X1_JTAG_boot/src/bsp/raspberrypi/driver.rs b/X1_JTAG_boot/src/bsp/raspberrypi/driver.rs index ea843066..2a80ee2c 100644 --- a/X1_JTAG_boot/src/bsp/raspberrypi/driver.rs +++ b/X1_JTAG_boot/src/bsp/raspberrypi/driver.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! BSP driver support. diff --git a/X1_JTAG_boot/src/bsp/raspberrypi/kernel.ld b/X1_JTAG_boot/src/bsp/raspberrypi/kernel.ld index f6c18843..32f6defa 100644 --- a/X1_JTAG_boot/src/bsp/raspberrypi/kernel.ld +++ b/X1_JTAG_boot/src/bsp/raspberrypi/kernel.ld @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: MIT OR Apache-2.0 * - * Copyright (c) 2018-2022 Andre Richter + * Copyright (c) 2018-2023 Andre Richter */ __rpi_phys_dram_start_addr = 0; diff --git a/X1_JTAG_boot/src/bsp/raspberrypi/memory.rs b/X1_JTAG_boot/src/bsp/raspberrypi/memory.rs index 27be8590..cdca14b8 100644 --- a/X1_JTAG_boot/src/bsp/raspberrypi/memory.rs +++ b/X1_JTAG_boot/src/bsp/raspberrypi/memory.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! BSP Memory Management. diff --git a/X1_JTAG_boot/src/console.rs b/X1_JTAG_boot/src/console.rs index 02b43df9..a83f86fe 100644 --- a/X1_JTAG_boot/src/console.rs +++ b/X1_JTAG_boot/src/console.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! System console. diff --git a/X1_JTAG_boot/src/console/null_console.rs b/X1_JTAG_boot/src/console/null_console.rs index 2c64d499..e92a022b 100644 --- a/X1_JTAG_boot/src/console/null_console.rs +++ b/X1_JTAG_boot/src/console/null_console.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2022 Andre Richter +// Copyright (c) 2022-2023 Andre Richter //! Null console. diff --git a/X1_JTAG_boot/src/cpu.rs b/X1_JTAG_boot/src/cpu.rs index 62503fb4..67ab79c0 100644 --- a/X1_JTAG_boot/src/cpu.rs +++ b/X1_JTAG_boot/src/cpu.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Processor code. diff --git a/X1_JTAG_boot/src/cpu/boot.rs b/X1_JTAG_boot/src/cpu/boot.rs index 8091dac3..b1e98328 100644 --- a/X1_JTAG_boot/src/cpu/boot.rs +++ b/X1_JTAG_boot/src/cpu/boot.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2021-2022 Andre Richter +// Copyright (c) 2021-2023 Andre Richter //! Boot code. diff --git a/X1_JTAG_boot/src/driver.rs b/X1_JTAG_boot/src/driver.rs index fb44bbd9..53592c66 100644 --- a/X1_JTAG_boot/src/driver.rs +++ b/X1_JTAG_boot/src/driver.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Driver support. diff --git a/X1_JTAG_boot/src/main.rs b/X1_JTAG_boot/src/main.rs index 8d244c77..7ab191f5 100644 --- a/X1_JTAG_boot/src/main.rs +++ b/X1_JTAG_boot/src/main.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter // Rust embedded logo for `make doc`. #![doc( diff --git a/X1_JTAG_boot/src/panic_wait.rs b/X1_JTAG_boot/src/panic_wait.rs index ccf54f61..5776aca8 100644 --- a/X1_JTAG_boot/src/panic_wait.rs +++ b/X1_JTAG_boot/src/panic_wait.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! A panic handler that infinitely waits. diff --git a/X1_JTAG_boot/src/print.rs b/X1_JTAG_boot/src/print.rs index fe13b334..8e303046 100644 --- a/X1_JTAG_boot/src/print.rs +++ b/X1_JTAG_boot/src/print.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2018-2022 Andre Richter +// Copyright (c) 2018-2023 Andre Richter //! Printing. diff --git a/X1_JTAG_boot/src/synchronization.rs b/X1_JTAG_boot/src/synchronization.rs index d3937b0d..94c83de1 100644 --- a/X1_JTAG_boot/src/synchronization.rs +++ b/X1_JTAG_boot/src/synchronization.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Synchronization primitives. //! diff --git a/X1_JTAG_boot/src/time.rs b/X1_JTAG_boot/src/time.rs index c6b40068..19a48a88 100644 --- a/X1_JTAG_boot/src/time.rs +++ b/X1_JTAG_boot/src/time.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // -// Copyright (c) 2020-2022 Andre Richter +// Copyright (c) 2020-2023 Andre Richter //! Timer primitives. diff --git a/common/serial/minipush.rb b/common/serial/minipush.rb index 262ce20a..2b90dd71 100755 --- a/common/serial/minipush.rb +++ b/common/serial/minipush.rb @@ -3,7 +3,7 @@ # SPDX-License-Identifier: MIT OR Apache-2.0 # -# Copyright (c) 2020-2022 Andre Richter +# Copyright (c) 2020-2023 Andre Richter require_relative 'miniterm' require 'ruby-progressbar' @@ -113,9 +113,9 @@ class MiniPush < MiniTerm end end -##-------------------------------------------------------------------------------------------------- +## ------------------------------------------------------------------------------------------------- ## Execution starts here -##-------------------------------------------------------------------------------------------------- +## ------------------------------------------------------------------------------------------------- if __FILE__ == $PROGRAM_NAME puts puts 'Minipush 1.0'.cyan diff --git a/common/serial/minipush/progressbar_patch.rb b/common/serial/minipush/progressbar_patch.rb index 1862a234..e90b9bd1 100644 --- a/common/serial/minipush/progressbar_patch.rb +++ b/common/serial/minipush/progressbar_patch.rb @@ -2,7 +2,7 @@ # SPDX-License-Identifier: MIT OR Apache-2.0 # -# Copyright (c) 2020-2022 Andre Richter +# Copyright (c) 2020-2023 Andre Richter # Monkey-patch ruby-progressbar so that it supports reporting the progress in KiB instead of Byte. diff --git a/common/serial/miniterm.rb b/common/serial/miniterm.rb index 038ed978..db2ddac5 100755 --- a/common/serial/miniterm.rb +++ b/common/serial/miniterm.rb @@ -3,7 +3,7 @@ # SPDX-License-Identifier: MIT OR Apache-2.0 # -# Copyright (c) 2020-2022 Andre Richter +# Copyright (c) 2020-2023 Andre Richter require 'rubygems' require 'bundler/setup' @@ -126,9 +126,9 @@ class MiniTerm end end -##-------------------------------------------------------------------------------------------------- +## ------------------------------------------------------------------------------------------------- ## Execution starts here -##-------------------------------------------------------------------------------------------------- +## ------------------------------------------------------------------------------------------------- if __FILE__ == $PROGRAM_NAME puts puts 'Miniterm 1.0'.cyan diff --git a/common/tests/boot_test.rb b/common/tests/boot_test.rb index 0dbef3df..5885c727 100644 --- a/common/tests/boot_test.rb +++ b/common/tests/boot_test.rb @@ -2,7 +2,7 @@ # SPDX-License-Identifier: MIT OR Apache-2.0 # -# Copyright (c) 2021-2022 Andre Richter +# Copyright (c) 2021-2023 Andre Richter require_relative 'console_io_test' diff --git a/common/tests/console_io_test.rb b/common/tests/console_io_test.rb index 002fb895..ea9d93e2 100644 --- a/common/tests/console_io_test.rb +++ b/common/tests/console_io_test.rb @@ -2,7 +2,7 @@ # SPDX-License-Identifier: MIT OR Apache-2.0 # -# Copyright (c) 2019-2022 Andre Richter +# Copyright (c) 2019-2023 Andre Richter require 'expect' require 'pty' diff --git a/common/tests/dispatch.rb b/common/tests/dispatch.rb index b6223418..96793710 100755 --- a/common/tests/dispatch.rb +++ b/common/tests/dispatch.rb @@ -3,7 +3,7 @@ # SPDX-License-Identifier: MIT OR Apache-2.0 # -# Copyright (c) 2019-2022 Andre Richter +# Copyright (c) 2019-2023 Andre Richter file_dir = File.dirname(__FILE__) $LOAD_PATH.unshift(file_dir) unless $LOAD_PATH.include?(file_dir) diff --git a/common/tests/exit_code_test.rb b/common/tests/exit_code_test.rb index 4bcdc7af..900510d4 100644 --- a/common/tests/exit_code_test.rb +++ b/common/tests/exit_code_test.rb @@ -2,7 +2,7 @@ # SPDX-License-Identifier: MIT OR Apache-2.0 # -# Copyright (c) 2019-2022 Andre Richter +# Copyright (c) 2019-2023 Andre Richter require 'English' require_relative 'test' diff --git a/common/tests/test.rb b/common/tests/test.rb index d102ecd9..65afad0b 100644 --- a/common/tests/test.rb +++ b/common/tests/test.rb @@ -2,7 +2,7 @@ # SPDX-License-Identifier: MIT OR Apache-2.0 # -# Copyright (c) 2019-2022 Andre Richter +# Copyright (c) 2019-2023 Andre Richter # Test base class. class Test diff --git a/docker/rustembedded-osdev-utils/Dockerfile b/docker/rustembedded-osdev-utils/Dockerfile index 7aa705df..e8cb2cb5 100644 --- a/docker/rustembedded-osdev-utils/Dockerfile +++ b/docker/rustembedded-osdev-utils/Dockerfile @@ -1,7 +1,7 @@ ## SPDX-License-Identifier: MIT OR Apache-2.0 ## -## Copyright (c) 2017-2022 Andre Richter -## Copyright (c) 2019-2022 Nao Taco +## Copyright (c) 2017-2023 Andre Richter +## Copyright (c) 2019-2023 Nao Taco FROM ubuntu:20.04 ARG VCS_REF diff --git a/docker/rustembedded-osdev-utils/Makefile b/docker/rustembedded-osdev-utils/Makefile index 8127375d..57acd995 100644 --- a/docker/rustembedded-osdev-utils/Makefile +++ b/docker/rustembedded-osdev-utils/Makefile @@ -1,6 +1,6 @@ ## SPDX-License-Identifier: MIT OR Apache-2.0 ## -## Copyright (c) 2019-2022 Andre Richter +## Copyright (c) 2019-2023 Andre Richter # Reference followed: https://www.docker.com/blog/getting-started-with-docker-for-arm-on-linux diff --git a/utils/devtool.rb b/utils/devtool.rb index fdbcf3a5..2b120d6b 100755 --- a/utils/devtool.rb +++ b/utils/devtool.rb @@ -3,7 +3,7 @@ # SPDX-License-Identifier: MIT OR Apache-2.0 # -# Copyright (c) 2020-2022 Andre Richter +# Copyright (c) 2020-2023 Andre Richter require 'rubygems' require 'bundler/setup' @@ -329,9 +329,9 @@ class DevTool end end -##-------------------------------------------------------------------------------------------------- +## ------------------------------------------------------------------------------------------------- ## Execution starts here -##-------------------------------------------------------------------------------------------------- +## ------------------------------------------------------------------------------------------------- tool = DevTool.new cmd = ARGV[0] commands = tool.public_methods(false).sort diff --git a/utils/devtool/copyright.rb b/utils/devtool/copyright.rb index e1741554..d1aed851 100644 --- a/utils/devtool/copyright.rb +++ b/utils/devtool/copyright.rb @@ -2,7 +2,7 @@ # SPDX-License-Identifier: MIT OR Apache-2.0 # -# Copyright (c) 2018-2022 Andre Richter +# Copyright (c) 2018-2023 Andre Richter require 'rubygems' require 'bundler/setup' diff --git a/utils/diff_tut_folders.bash b/utils/diff_tut_folders.bash index d93ca57d..cdd9880e 100755 --- a/utils/diff_tut_folders.bash +++ b/utils/diff_tut_folders.bash @@ -2,7 +2,7 @@ # SPDX-License-Identifier: MIT OR Apache-2.0 # -# Copyright (c) 2018-2022 Andre Richter +# Copyright (c) 2018-2023 Andre Richter DIFF=$( diff -uNr \ diff --git a/utils/update_copyright.rb b/utils/update_copyright.rb index 2bfd2895..dc1abbf4 100755 --- a/utils/update_copyright.rb +++ b/utils/update_copyright.rb @@ -3,7 +3,7 @@ # SPDX-License-Identifier: MIT OR Apache-2.0 # -# Copyright (c) 2021-2022 Andre Richter +# Copyright (c) 2021-2023 Andre Richter require 'date' From daee880368ef7d3b3a18e611c6b75c4beb00b5b0 Mon Sep 17 00:00:00 2001 From: James Zow Date: Mon, 25 Sep 2023 20:22:34 +0800 Subject: [PATCH 70/75] Translate Chapter 5 and modify the source file format (#187) * Translation Chapter 05 * Modify RPi3 and RPi4 unified formats --- 05_drivers_gpio_uart/README.CN.md | 138 ++++++++++++++++++++++++++++++ 05_drivers_gpio_uart/README.md | 18 ++-- 2 files changed, 147 insertions(+), 9 deletions(-) create mode 100644 05_drivers_gpio_uart/README.CN.md diff --git a/05_drivers_gpio_uart/README.CN.md b/05_drivers_gpio_uart/README.CN.md new file mode 100644 index 00000000..7999da7b --- /dev/null +++ b/05_drivers_gpio_uart/README.CN.md @@ -0,0 +1,138 @@ +# 教程 05 - 驱动程序: GPIO和UART + +## tl;dr + +- 添加了用于真实`UART`和`GPIO`控制器的驱动程序。 +- **我们将首次能够在真实硬件上运行代码** (请向下滚动查看说明)。 + +## 简介 + +在上一篇教程中,我们启用了全局安全变量,为添加第一个真实设备驱动程序奠定了基础。 +我们放弃了神奇的QEMU控制台,并引入了一个`驱动程序管理器`,允许`BSP`将设备驱动程序注册到`内核`中。 + +## 驱动程序管理器 + +第一步是向内核添加一个`driver subsystem`。相应的代码将位于`src/driver.rs`中。 +该子系统引入了`interface::DeviceDriver`,这是每个设备驱动程序都需要实现的通用特征,并为内核所知。 +在同一文件中实例化的全局`DRIVER_MANAGER`实例(类型为`DriverManager`)作为一个中央实体,可以被调用来管理内核中的所有设备驱动程序。 +例如,通过使用全局可访问的`crate::driver::driver_manager().register_driver(...)`,任何代码都可以注册一个实现了`interface::DeviceDriver`特征的具有静态生命周期的对象。 + +在内核初始化期间,调用`crate::driver::driver_manager().init_drivers(...)`将使驱动程序管理器遍历所有已注册的驱动程序, +并启动它们的初始化,并执行可选的`post-init callback`,该回调可以与驱动程序一起注册。 +例如,此机制用于在`UART`驱动程序初始化后将其切换为主系统控制台的驱动程序。 + +## BSP驱动程序实现 + +在`src/bsp/raspberrypi/driver.rs`中,函数`init()`负责注册`UART`和`GPIO`驱动程序。 +因此,在内核初始化期间,按照以下来自`main.rs`的代码,正确的顺序是: +(i)首先初始化BSP驱动程序子系统,然后(ii)调用`driver_manager()`。 + +```rust +unsafe fn kernel_init() -> ! { + // Initialize the BSP driver subsystem. + if let Err(x) = bsp::driver::init() { + panic!("Error initializing BSP driver subsystem: {}", x); + } + + // Initialize all device drivers. + driver::driver_manager().init_drivers(); + // println! is usable from here on. +``` + + + +驱动程序本身存储在`src/bsp/device_driver`中,并且可以在不同的`BSP`之间重复使用 +在这些教程中添加的第一个驱动程序是`PL011Uart`驱动程序:它实现了`console::interface::*`特征,并且从现在开始用作主系统控制台。 +第二个驱动程序是`GPIO`驱动程序,它根据需要将`RPii's`的`UART`映射(即将来自`SoC`内部的信号路由到实际的硬件引脚)。 +请注意,`GPIO`驱动程序区分**RPi 3**和**RPi 4**。它们的硬件不同,因此我们必须在软件中进行适配。 + +现在,`BSP`还包含了一个内存映射表,位于`src/bsp/raspberrypi/memory.rs`中。它提供了树莓派的`MMIO`地址, +`BSP`使用这些地址来实例化相应的设备驱动程序,以便驱动程序代码知道在内存中找到设备的寄存器的位置。 + +## SD卡启动 + +由于我们现在有了真实的`UART`输出,我们可以在真实的硬件上运行代码。 +由于前面提到的`GPIO`驱动程序的差异,构建过程在**RPi 3**和**RPi 4**之间有所区别。 +默认情况下,所有的`Makefile`目标都将为**RPi 3**构建。 +为了**RPi 4**构建,需要在每个目标前加上`BSP=rpi4`。例如: + +```console +$ BSP=rpi4 make +$ BSP=rpi4 make doc +``` + +不幸的是,QEMU目前还不支持**RPi 4**,因此`BSP=rpi4 make qemu`无法工作。 + +**准备SD卡的一些步骤在RPi3和RPi4之间有所不同,请在以下操作中小心。** + +### 通用步骤 + +1. 创建一个名为`boot`的`FAT32`分区。 +2. 在SD卡上生成一个名为`config.txt`的文件,并将以下内容写入其中: + +```txt +arm_64bit=1 +init_uart_clock=48000000 +``` +### RPi 3 + +3. 从[Raspberry Pi firmware repo](https://github.com/raspberrypi/firmware/tree/master/boot)中将以下文件复制到SD卡上: + - [bootcode.bin](https://github.com/raspberrypi/firmware/raw/master/boot/bootcode.bin) + - [fixup.dat](https://github.com/raspberrypi/firmware/raw/master/boot/fixup.dat) + - [start.elf](https://github.com/raspberrypi/firmware/raw/master/boot/start.elf) +4. 运行`make`命令。 + +### RPi 4 + +3. 从[Raspberry Pi firmware repo](https://github.com/raspberrypi/firmware/tree/master/boot)中将以下文件复制到SD卡上: + - [fixup4.dat](https://github.com/raspberrypi/firmware/raw/master/boot/fixup4.dat) + - [start4.elf](https://github.com/raspberrypi/firmware/raw/master/boot/start4.elf) + - [bcm2711-rpi-4-b.dtb](https://github.com/raspberrypi/firmware/raw/master/boot/bcm2711-rpi-4-b.dtb) +4. 运行`BSP=rpi4 make`命令。 + + +_**注意**: 如果在您的RPi4上无法正常工作,请尝试将`start4.elf`重命名为`start.elf` (不带4) +并复制到SD卡上。_ + +### 再次通用步骤 + +5. 将`kernel8.img`复制到SD卡上,并将SD卡插入RPi。 +6. 运行`miniterm` target,在主机上打开UART设备: + +```console +$ make miniterm +``` + +> ❗ **注意**: `Miniterm`假设默认的串行设备名称为`/dev/ttyUSB0`。Depending on your +> 根据您的主机操作系统,设备名称可能会有所不同。例如,在`macOS`上,它可能是 +> `/dev/tty.usbserial-0001`之类的。在这种情况下,请明确提供设备名称: + + +```console +$ DEV_SERIAL=/dev/tty.usbserial-0001 make miniterm +``` + +7. 将USB串口连接到主机PC。 + - 请参考[top-level README](../README.md#-usb-serial-output)中的接线图。 + - **注意**: TX(发送)线连接到RX(接收)引脚。 + - 确保您**没有**连接USB串口的电源引脚,只连接RX/TX和GND引脚。 +8. 将RPi连接到(USB)电源线,并观察输出。 + +```console +Miniterm 1.0 + +[MT] ⏳ Waiting for /dev/ttyUSB0 +[MT] ✅ Serial connected +[0] mingo version 0.5.0 +[1] Booting on: Raspberry Pi 3 +[2] Drivers loaded: + 1. BCM PL011 UART + 2. BCM GPIO +[3] Chars written: 117 +[4] Echoing input now +``` + +8. 通过按下ctrl-c退出。 + +## 相比之前的变化(diff) +请检查[英文版本](README.md#diff-to-previous),这是最新的。 diff --git a/05_drivers_gpio_uart/README.md b/05_drivers_gpio_uart/README.md index e6e5dd64..5e96d40a 100644 --- a/05_drivers_gpio_uart/README.md +++ b/05_drivers_gpio_uart/README.md @@ -54,8 +54,8 @@ The drivers themselves are stored in `src/bsp/device_driver`, and can be reused first driver added in these tutorials is the `PL011Uart` driver: It implements the `console::interface::*` traits and is from now on used as the main system console. The second driver is the `GPIO` driver, which pinmuxes (that is, routing signals from inside the `SoC` to actual HW -pins) the RPi's PL011 UART accordingly. Note how the `GPIO` driver differentiates between **RPi3** -and **RPi4**. Their HW is different, so we have to account for it in SW. +pins) the RPi's PL011 UART accordingly. Note how the `GPIO` driver differentiates between **RPi 3** +and **RPi 4**. Their HW is different, so we have to account for it in SW. The `BSP`s now also contain a memory map in `src/bsp/raspberrypi/memory.rs`. It provides the Raspberry's `MMIO` addresses which are used by the `BSP` to instantiate the respective device @@ -64,18 +64,18 @@ drivers, so that the driver code knows where to find the device's registers in m ## Boot it from SD card Since we have real `UART` output now, we can run the code on the real hardware. Building is -differentiated between the **RPi 3** and the **RPi4** due to before mentioned differences in the +differentiated between the **RPi 3** and the **RPi 4** due to before mentioned differences in the `GPIO` driver. By default, all `Makefile` targets will build for the **RPi 3**. In order to build -for the the **RPi4**, prepend `BSP=rpi4` to each target. For example: +for the the **RPi 4**, prepend `BSP=rpi4` to each target. For example: ```console $ BSP=rpi4 make $ BSP=rpi4 make doc ``` -Unfortunately, QEMU does not yet support the **RPi4**, so `BSP=rpi4 make qemu` won't work. +Unfortunately, QEMU does not yet support the **RPi 4**, so `BSP=rpi4 make qemu` won't work. -**Some steps for preparing the SD card differ between RPi3 and RPi4, so be careful in the +**Some steps for preparing the SD card differ between RPi 3 and RPi 4, so be careful in the following.** ### Common for both @@ -87,7 +87,7 @@ following.** arm_64bit=1 init_uart_clock=48000000 ``` -### Pi 3 +### RPi 3 3. Copy the following files from the [Raspberry Pi firmware repo](https://github.com/raspberrypi/firmware/tree/master/boot) onto the SD card: - [bootcode.bin](https://github.com/raspberrypi/firmware/raw/master/boot/bootcode.bin) @@ -95,7 +95,7 @@ init_uart_clock=48000000 - [start.elf](https://github.com/raspberrypi/firmware/raw/master/boot/start.elf) 4. Run `make`. -### Pi 4 +### RPi 4 3. Copy the following files from the [Raspberry Pi firmware repo](https://github.com/raspberrypi/firmware/tree/master/boot) onto the SD card: - [fixup4.dat](https://github.com/raspberrypi/firmware/raw/master/boot/fixup4.dat) @@ -104,7 +104,7 @@ init_uart_clock=48000000 4. Run `BSP=rpi4 make`. -_**Note**: Should it not work on your RPi4, try renaming `start4.elf` to `start.elf` (without the 4) +_**Note**: Should it not work on your RPi 4, try renaming `start4.elf` to `start.elf` (without the 4) on the SD card._ ### Common again From 9fd529ff808f489a1b7d41c4a06885dabe6f2489 Mon Sep 17 00:00:00 2001 From: James Zow Date: Mon, 25 Sep 2023 20:23:11 +0800 Subject: [PATCH 71/75] Translation Chapter 6 (#186) --- 06_uart_chainloader/README.CN.md | 116 +++++++++++++++++++++++++++++++ 1 file changed, 116 insertions(+) create mode 100644 06_uart_chainloader/README.CN.md diff --git a/06_uart_chainloader/README.CN.md b/06_uart_chainloader/README.CN.md new file mode 100644 index 00000000..de7f5111 --- /dev/null +++ b/06_uart_chainloader/README.CN.md @@ -0,0 +1,116 @@ +# 教程06 - UART链加载器 + +## tl;dr + +- 从SD卡上运行是一次不错的体验,但是每次都为每个新的二进制文件这样做将非常繁琐。 + 因此,让我们编写一个[chainloader]。 +- 这将是您需要放在SD卡上的最后一个二进制文件。 + 每个后续的教程都将在`Makefile`中提供一个`chainboot`,让您方便地通过`UART`加载内核。 + +[chainloader]: https://en.wikipedia.org/wiki/Chain_loading + + +## 注意 + +请注意,这个教程中有一些内容仅通过查看源代码很难理解。 + +大致的意思是,在`boot.s`中,我们编写了一段[position independent code]代码, +它会自动确定固件加载二进制文件的位置(`0x8_0000`),以及链接到的位置(`0x200_0000`,参见 `kernel.ld`)。 +然后,二进制文件将自身从加载地址复制到链接地址(也就是"重定位"自身),然后跳转到`_start_rust()`的重定位版本。 + +由于链加载程序现在已经"脱离了路径",它现在可以从`UART`接收另一个内核二进制文件,并将其复制到RPi固件的标准加载地址`0x8_0000`。 +最后,它跳转到`0x8_0000`,新加载的二进制文件会透明地执行,就好像它一直从SD卡加载一样。 + +在我有时间详细写下这些内容之前,请耐心等待。目前,请将这个教程视为一种便利功能的启用程序,它允许快速启动以下教程。 +_对于那些渴望深入了解的人,可以直接跳到第[15章](../15_virtual_mem_part3_precomputed_tables),阅读README的前半部分, +其中讨论了`Load Address != Link Address`的问题_。 + +[position independent code]: https://en.wikipedia.org/wiki/Position-independent_code + +## 安装并测试它 + +我们的链加载程序称为`MiniLoad`,受到了[raspbootin]的启发。 + +您可以按照以下教程尝试它: +1. 根据您的目标硬件运行命令:`make`或`BSP=rpi4 make`。 +1. 将`kernel8.img`复制到SD卡中,并将SD卡重新插入您的RPi。 +1. 运行命令`make chainboot`或`BSP=rpi4 make chainboot`。 +1. 将USB串口连接到您的主机PC上。 + - 请参考[top-level README](../README.md#-usb-serial-output)中的接线图。 + - 确保您**没有**连接USB串口的电源引脚,只连接RX/TX和GND。 +1. 将RPi连接到(USB)电源线。 +1. 观察加载程序通过`UART`获取内核: + +> ❗ **注意**: `make chainboot`假设默认的串行设备名称为`/dev/ttyUSB0`。根据您的主机操作系统,设备名称可能会有所不同。 +> 例如,在`macOS`上,它可能是类似于`/dev/tty.usbserial-0001`的名称。 +> 在这种情况下,请明确给出设备名称: + + +```console +$ DEV_SERIAL=/dev/tty.usbserial-0001 make chainboot +``` + +[raspbootin]: https://github.com/mrvn/raspbootin + +```console +$ make chainboot +[...] +Minipush 1.0 + +[MP] ⏳ Waiting for /dev/ttyUSB0 +[MP] ✅ Serial connected +[MP] 🔌 Please power the target now + + __ __ _ _ _ _ +| \/ (_)_ _ (_) | ___ __ _ __| | +| |\/| | | ' \| | |__/ _ \/ _` / _` | +|_| |_|_|_||_|_|____\___/\__,_\__,_| + + Raspberry Pi 3 + +[ML] Requesting binary +[MP] ⏩ Pushing 7 KiB ==========================================🦀 100% 0 KiB/s Time: 00:00:00 +[ML] Loaded! Executing the payload now + +[0] mingo version 0.5.0 +[1] Booting on: Raspberry Pi 3 +[2] Drivers loaded: + 1. BCM PL011 UART + 2. BCM GPIO +[3] Chars written: 117 +[4] Echoing input now +``` + +在这个教程中,为了演示目的,加载了上一个教程中的内核版本。在后续的教程中,将使用工作目录的内核。 + +## 测试它 + +这个教程中的`Makefile`有一个额外的目标`qemuasm`,它可以让你很好地观察到内核在重新定位后如何从加载地址区域(`0x80_XXX`) +跳转到重新定位的代码(`0x0200_0XXX`): + +```console +$ make qemuasm +[...] +N: +0x00080030: 58000140 ldr x0, #0x80058 +0x00080034: 9100001f mov sp, x0 +0x00080038: 58000141 ldr x1, #0x80060 +0x0008003c: d61f0020 br x1 + +---------------- +IN: +0x02000070: 9400044c bl #0x20011a0 + +---------------- +IN: +0x020011a0: 90000008 adrp x8, #0x2001000 +0x020011a4: 90000009 adrp x9, #0x2001000 +0x020011a8: f9446508 ldr x8, [x8, #0x8c8] +0x020011ac: f9446929 ldr x9, [x9, #0x8d0] +0x020011b0: eb08013f cmp x9, x8 +0x020011b4: 54000109 b.ls #0x20011d4 +[...] +``` + +## 相比之前的变化(diff) +请检查[英文版本](README.md#diff-to-previous),这是最新的。 \ No newline at end of file From 2dfb9e788772945e6bdfb0d41ce5dfecd6bd6c2e Mon Sep 17 00:00:00 2001 From: James Zow Date: Mon, 25 Sep 2023 20:23:39 +0800 Subject: [PATCH 72/75] Translation Chapter 7 (#189) --- 07_timestamps/README.CN.md | 45 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 07_timestamps/README.CN.md diff --git a/07_timestamps/README.CN.md b/07_timestamps/README.CN.md new file mode 100644 index 00000000..1192996d --- /dev/null +++ b/07_timestamps/README.CN.md @@ -0,0 +1,45 @@ +# 教程 07 - 时间戳 + +## tl;dr + +- 我们为计时器硬件添加了抽象,并在`_arch/aarch64`中实现了ARM架构计时器。 +- 新的计时器函数用于给UART打印添加时间戳,并且用于消除`GPIO`设备驱动中基于周期的延迟,从而提高准确性。 +- 添加了`warn!()`宏。 + +## 测试它 + +请通过 chainboot 进行检查(在上一个教程中添加)。 +```console +$ make chainboot +[...] +Minipush 1.0 + +[MP] ⏳ Waiting for /dev/ttyUSB0 +[MP] ✅ Serial connected +[MP] 🔌 Please power the target now + + __ __ _ _ _ _ +| \/ (_)_ _ (_) | ___ __ _ __| | +| |\/| | | ' \| | |__/ _ \/ _` / _` | +|_| |_|_|_||_|_|____\___/\__,_\__,_| + + Raspberry Pi 3 + +[ML] Requesting binary +[MP] ⏩ Pushing 12 KiB =========================================🦀 100% 0 KiB/s Time: 00:00:00 +[ML] Loaded! Executing the payload now + +[ 0.143123] mingo version 0.7.0 +[ 0.143323] Booting on: Raspberry Pi 3 +[ 0.143778] Architectural timer resolution: 52 ns +[ 0.144352] Drivers loaded: +[ 0.144688] 1. BCM PL011 UART +[ 0.145110] 2. BCM GPIO +[W 0.145469] Spin duration smaller than architecturally supported, skipping +[ 0.146313] Spinning for 1 second +[ 1.146715] Spinning for 1 second +[ 2.146938] Spinning for 1 second +``` + +## 相比之前的变化(diff) +请检查[英文版本](README.md#diff-to-previous),这是最新的。 From aa7413fe797e9623a35684561cb3616b50d47ecb Mon Sep 17 00:00:00 2001 From: James Zow Date: Mon, 25 Sep 2023 20:25:30 +0800 Subject: [PATCH 73/75] Translation Chapter 09 (#191) --- 09_privilege_level/README.CN.md | 182 ++++++++++++++++++++++++++++++++ 1 file changed, 182 insertions(+) create mode 100644 09_privilege_level/README.CN.md diff --git a/09_privilege_level/README.CN.md b/09_privilege_level/README.CN.md new file mode 100644 index 00000000..80773a69 --- /dev/null +++ b/09_privilege_level/README.CN.md @@ -0,0 +1,182 @@ +# 教程 09 - 特权级别 + +## tl;dr + +- 在早期引导代码中,我们从`Hypervisor`特权级别(AArch64中的`EL2`)过渡到`Kernel` (`EL1`)特权级别。 + +## 目录 + +- [介绍](#介绍) +- [本教程的范围](#本教程的范围) +- [在入口点检查EL2](#在入口点检查EL2) +- [过渡准备](#过渡准备) +- [从未发生的异常中返回](#从未发生的异常中返回) +- [测试](#测试) +- [相比之前的变化(diff)](#相比之前的变化(diff)) + +## 介绍 + +应用级别的CPU具有所谓的`privilege levels`,它们具有不同的目的: + +| Typically used for | AArch64 | RISC-V | x86 | +| ------------- | ------------- | ------------- | ------------- | +| Userspace applications | EL0 | U/VU | Ring 3 | +| OS Kernel | EL1 | S/VS | Ring 0 | +| Hypervisor | EL2 | HS | Ring -1 | +| Low-Level Firmware | EL3 | M | | + +在AArch64中,`EL`代表`Exception Level`(异常级别)。如果您想获取有关其他体系结构的更多信息,请查看以下链接: +- [x86 privilege rings](https://en.wikipedia.org/wiki/Protection_ring). +- [RISC-V privilege modes](https://content.riscv.org/wp-content/uploads/2017/12/Tue0942-riscv-hypervisor-waterman.pdf). + +在继续之前,我强烈建议您先浏览一下[Programmer’s Guide for ARMv8-A]`的第3章`。它提供了关于该主题的简明概述。 + +[Programmer’s Guide for ARMv8-A]: http://infocenter.arm.com/help/topic/com.arm.doc.den0024a/DEN0024A_v8_architecture_PG.pdf + +## 本教程的范围 + +默认情况下,树莓派将始终在`EL2`中开始执行。由于我们正在编写一个传统的`Kernel`,我们需要过渡到更合适的`EL1`。 + +## 在入口点检查EL2 + +首先,我们需要确保我们实际上是在`EL2`中执行,然后才能调用相应的代码过渡到`EL1`。 +因此,我们在`boot.s`的顶部添加了一个新的检查,如果CPU核心不在`EL2`中,则将其停止。 + +``` +// Only proceed if the core executes in EL2. Park it otherwise. +mrs x0, CurrentEL +cmp x0, {CONST_CURRENTEL_EL2} +b.ne .L_parking_loop +``` + +接下来,在`boot.rs`中继续准备从`EL2`到`EL1`的过渡,通过调用`prepare_el2_to_el1_transition()`函数。 + +```rust +#[no_mangle] +pub unsafe extern "C" fn _start_rust(phys_boot_core_stack_end_exclusive_addr: u64) -> ! { + prepare_el2_to_el1_transition(phys_boot_core_stack_end_exclusive_addr); + + // Use `eret` to "return" to EL1. This results in execution of kernel_init() in EL1. + asm::eret() +} +``` + +## 过渡准备 + +由于`EL2`比`EL1`更具特权,它可以控制各种处理器功能,并允许或禁止`EL1`代码使用它们。 +其中一个例子是访问计时器和计数器寄存器。我们已经在[tutorial 07](../07_timestamps/)中使用了它们,所以当然我们希望保留它们。 +因此,我们在[Counter-timer Hypervisor Control register]中设置相应的标志,并将虚拟偏移量设置为零,以获取真实的物理值。 + +[Counter-timer Hypervisor Control register]: https://docs.rs/aarch64-cpu/9.0.0/src/aarch64_cpu/registers/cnthctl_el2.rs.html + +```rust +// Enable timer counter registers for EL1. +CNTHCTL_EL2.write(CNTHCTL_EL2::EL1PCEN::SET + CNTHCTL_EL2::EL1PCTEN::SET); + +// No offset for reading the counters. +CNTVOFF_EL2.set(0); +``` + +接下来,我们配置[Hypervisor Configuration Register],使`EL1`在`AArch64`模式下运行,而不是在`AArch32`模式下运行,这也是可能的。 + +[Hypervisor Configuration Register]: https://docs.rs/aarch64-cpu/9.0.0/src/aarch64_cpu/registers/hcr_el2.rs.html + +```rust +// Set EL1 execution state to AArch64. +HCR_EL2.write(HCR_EL2::RW::EL1IsAarch64); +``` + +## 从未发生的异常中返回 + +实际上,从较高的EL过渡到较低的EL只有一种方式,即通过执行[ERET]指令。 + +[ERET]: https://docs.rs/aarch64-cpu/9.0.0/src/aarch64_cpu/asm.rs.html#92-101 + +在这个指令中,它将会将[Saved Program Status Register - EL2]的内容复制到`Current Program Status Register - EL1`,并跳转到存储在[Exception Link Register - EL2]。 + +这基本上是在发生异常时所发生的相反过程。您将在即将发布的教程中了解更多相关内容。 + +[Saved Program Status Register - EL2]: https://docs.rs/aarch64-cpu/9.0.0/src/aarch64_cpu/registers/spsr_el2.rs.html +[Exception Link Register - EL2]: https://docs.rs/aarch64-cpu/9.0.0/src/aarch64_cpu/registers/elr_el2.rs.html + +```rust +// Set up a simulated exception return. +// +// First, fake a saved program status where all interrupts were masked and SP_EL1 was used as a +// stack pointer. +SPSR_EL2.write( + SPSR_EL2::D::Masked + + SPSR_EL2::A::Masked + + SPSR_EL2::I::Masked + + SPSR_EL2::F::Masked + + SPSR_EL2::M::EL1h, +); + +// Second, let the link register point to kernel_init(). +ELR_EL2.set(crate::kernel_init as *const () as u64); + +// Set up SP_EL1 (stack pointer), which will be used by EL1 once we "return" to it. Since there +// are no plans to ever return to EL2, just re-use the same stack. +SP_EL1.set(phys_boot_core_stack_end_exclusive_addr); +``` + +正如您所看到的,我们将`ELR_EL2`的值设置为之前直接从入口点调用的`kernel_init()`函数的地址。最后,我们设置了`SP_EL1`的堆栈指针。 + +您可能已经注意到,堆栈的地址作为函数参数进行了传递。正如您可能记得的,在`boot.s`的`_start()`函数中, +我们已经为`EL2`设置了堆栈。由于没有计划返回到`EL2`,我们可以直接重用相同的堆栈作为`EL1`的堆栈, +因此使用函数参数将其地址传递。 + +最后,在`_start_rust()`函数中调用了`ERET`指令。 + +```rust +#[no_mangle] +pub unsafe extern "C" fn _start_rust(phys_boot_core_stack_end_exclusive_addr: u64) -> ! { + prepare_el2_to_el1_transition(phys_boot_core_stack_end_exclusive_addr); + + // Use `eret` to "return" to EL1. This results in execution of kernel_init() in EL1. + asm::eret() +} +``` + +## 测试 + +在`main.rs`中,我们打印`current privilege level`,并额外检查`SPSR_EL2`中的掩码位是否传递到了`EL1`: + +```console +$ make chainboot +[...] +Minipush 1.0 + +[MP] ⏳ Waiting for /dev/ttyUSB0 +[MP] ✅ Serial connected +[MP] 🔌 Please power the target now + + __ __ _ _ _ _ +| \/ (_)_ _ (_) | ___ __ _ __| | +| |\/| | | ' \| | |__/ _ \/ _` / _` | +|_| |_|_|_||_|_|____\___/\__,_\__,_| + + Raspberry Pi 3 + +[ML] Requesting binary +[MP] ⏩ Pushing 14 KiB =========================================🦀 100% 0 KiB/s Time: 00:00:00 +[ML] Loaded! Executing the payload now + +[ 0.162546] mingo version 0.9.0 +[ 0.162745] Booting on: Raspberry Pi 3 +[ 0.163201] Current privilege level: EL1 +[ 0.163677] Exception handling state: +[ 0.164122] Debug: Masked +[ 0.164511] SError: Masked +[ 0.164901] IRQ: Masked +[ 0.165291] FIQ: Masked +[ 0.165681] Architectural timer resolution: 52 ns +[ 0.166255] Drivers loaded: +[ 0.166592] 1. BCM PL011 UART +[ 0.167014] 2. BCM GPIO +[ 0.167371] Timer test, spinning for 1 second +[ 1.167904] Echoing input now +``` + +## 相比之前的变化(diff) +请检查[英文版本](README.md#diff-to-previous),这是最新的。 From 502935c6768dea726aad15d1e5a9dd4c7360e92c Mon Sep 17 00:00:00 2001 From: James Zow Date: Mon, 25 Sep 2023 20:25:58 +0800 Subject: [PATCH 74/75] Translation Chapter 10 (#192) --- .../README.CN.md | 319 ++++++++++++++++++ 1 file changed, 319 insertions(+) create mode 100644 10_virtual_mem_part1_identity_mapping/README.CN.md diff --git a/10_virtual_mem_part1_identity_mapping/README.CN.md b/10_virtual_mem_part1_identity_mapping/README.CN.md new file mode 100644 index 00000000..2b840e28 --- /dev/null +++ b/10_virtual_mem_part1_identity_mapping/README.CN.md @@ -0,0 +1,319 @@ +# 教程10 - 虚拟内存第一部分:将所有内容进行身份映射! + +## tl;dr + +- 打开`MMU`。 +- 使用简单的方案:静态的`64 KiB`转换表。 +- 为了教学目的,我们将数据写入重新映射的`UART`,并对其他所有内容进行`identity map`。 + +## 目录 + +- [介绍](#introduction) +- [MMU和分页理论](#MMU和分页理论) +- [方法](#方法) + * [通用内核代码:`memory/mmu.rs`](#通用内核代码:`memory/mmu.rs`) + * [BSP:`bsp/raspberrypi/memory/mmu.rs`](#bsp-bspraspberrypimemorymmurs) + * [AArch64:`_arch/aarch64/memory/*`](#aarch64-_archaarch64memory) + * [`kernel.ld`](#kernelld) +- [地址转换示例](#地址转换示例) + * [使用64 KiB页描述符进行地址转换](#使用64KiB页描述符进行地址转换) +- [零成本抽象](#零成本抽象) +- [测试](#测试) +- [相比之前的变化(diff)](#相比之前的变化(diff)) + +## 介绍 + +虚拟内存是一个非常复杂但重要且强大的主题。在本教程中,我们从简单易懂的方式开始, +通过打开`MMU`,使用静态转换表和一次性进行`identity-map` +(除了为教育目的而重新映射的`UART`之外;在下一个教程中,这将被取消)。 + +## MMU和分页理论 + +在这一点上,我们不会重新发明轮子并详细描述现代应用级处理器中分页的工作原理。 +互联网上有很多关于这个主题的优秀资源,我们鼓励您阅读其中一些以获得对该主题的高层理解。 + +继续阅读本`AArch64`特定的教程,我强烈建议您在此处停下来,首先阅读[ARM Cortex-A Series Programmer's Guide for ARMv8-A]的`第12章`, +以便在继续之前获得所有所需的`AArch64`特定知识。 + +已经阅读完`第12章`了吗?做得好 :+1:! + +[ARM Cortex-A Series Programmer's Guide for ARMv8-A]: http://infocenter.arm.com/help/topic/com.arm.doc.den0024a/DEN0024A_v8_architecture_PG.pdf + +## 方法 + +1. 通用的`kernel`部分:`src/memory/mmu.rs`及其子模块提供了与体系结构无关的描述符类型, + 用于组合一个高级数据结构,描述内核的虚拟内存布局:`memory::mmu::KernelVirtualLayout`。 +2. `BSP`部分:`src/bsp/raspberrypi/memory/mmu.rs`包含一个`KernelVirtualLayout`的静态实例,并通过函数 + `bsp::memory::mmu::virt_mem_layout()`使其可访问。 +3. `aarch64`部分:`src/_arch/aarch64/memory/mmu.rs`及其子模块包含实际的`MMU`驱动程序。它使用`64 KiB`粒度获取 + `BSP`的高级`KernelVirtualLayout`并进行映射。 + +### 通用内核代码:`memory/mmu.rs` + +在这个文件中提供的描述符类型是构建块,用于描述不同内存区域的属性。 +例如,`R/W`(读/写)、`no-execute`(不执行)、`cached/uncached`(缓存/非缓存)等等。 + +这些描述符与硬件`MMU`的实际描述符无关。不同的`BSP`可以使用这些类型来生成内核虚拟内存布局的高级描述。 +真实硬件的实际`MMU`驱动程序将使用这些类型作为输入。 + +通过这种方式,我们在`BSP`和`_arch`代码之间实现了清晰的抽象,这样可以在不需要调整另一个的情况下进行交换。 + +### BSP: `bsp/raspberrypi/memory/mmu.rs` + +这个文件包含了一个`KernelVirtualLayout`的实例,用于存储先前提到的描述符。 +将其放在`BSP`中是正确的位置,因为它具有目标板的内存映射知识。 + +策略是只描述**不是**普通的、可缓存的DRAM的区域。然而,如果您希望,也可以定义这些区域。 +这里是一个设备MMIO区域的示例: + +```rust +TranslationDescriptor { + name: "Device MMIO", + virtual_range: mmio_range_inclusive, + physical_range_translation: Translation::Identity, + attribute_fields: AttributeFields { + mem_attributes: MemAttributes::Device, + acc_perms: AccessPermissions::ReadWrite, + execute_never: true, + }, +}, +``` + +`KernelVirtualLayout`本身实现了以下方法: + +```rust +pub fn virt_addr_properties( + &self, + virt_addr: usize, +) -> Result<(usize, AttributeFields), &'static str> +``` + +它将被`_arch/aarch64`的`MMU`代码使用,用于请求虚拟地址和转换的属性,该转换提供物理输出地址 +(返回元组中的`usize`)。该函数扫描包含查询地址的描述符,并返回第一个匹配的条目的相应结果。 +如果找不到条目,则返回普通可缓存DRAM的默认属性和输入地址,从而告诉`MMU`代码请求的地址应该是`identity mapped`。 + +由于这种默认行为,不需要定义普通可缓存DRAM区域。 + +### AArch64: `_arch/aarch64/memory/*` + +这些模块包含了`AArch64`的`MMU`驱动程序。粒度在这里被硬编码为(`64 KiB`页描述符)。 + +在`translation_table.rs`中,有一个实际的转换表结构的定义,它对`LVL2`表的数量进行了泛化。 +后者取决于目标板的内存大小。自然地,`BSP`了解目标板的这些细节,并通过常量 +`bsp::memory::mmu::KernelAddrSpace::SIZE`提供大小信息。 + +`translation_table.rs`使用这些信息来计算所需的`LVL2`表的数量。由于在`64 KiB`配置中, +一个`LVL2`表可以覆盖`512 MiB`,所以只需要将`KernelAddrSpace::SIZE`除以`512 MiB` +(有几个编译时检查确保`KernelAddrSpace::SIZE`是`512 MiB`的倍数)。 + +最终的表类型被导出为`KernelTranslationTable`。以下是来自`translation_table.rs`的相关代码: + +```rust +/// A table descriptor for 64 KiB aperture. +/// +/// The output points to the next table. +#[derive(Copy, Clone)] +#[repr(C)] +struct TableDescriptor { + value: u64, +} + +/// A page descriptor with 64 KiB aperture. +/// +/// The output points to physical memory. +#[derive(Copy, Clone)] +#[repr(C)] +struct PageDescriptor { + value: u64, +} + +const NUM_LVL2_TABLES: usize = bsp::memory::mmu::KernelAddrSpace::SIZE >> Granule512MiB::SHIFT; + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +/// Big monolithic struct for storing the translation tables. Individual levels must be 64 KiB +/// aligned, hence the "reverse" order of appearance. +#[repr(C)] +#[repr(align(65536))] +pub struct FixedSizeTranslationTable { + /// Page descriptors, covering 64 KiB windows per entry. + lvl3: [[PageDescriptor; 8192]; NUM_TABLES], + + /// Table descriptors, covering 512 MiB windows. + lvl2: [TableDescriptor; NUM_TABLES], +} + +/// A translation table type for the kernel space. +pub type KernelTranslationTable = FixedSizeTranslationTable; +``` + +在`mmu.rs`中,`KernelTranslationTable`用于创建内核表的最终实例: + +```rust +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +/// The kernel translation tables. +static mut KERNEL_TABLES: KernelTranslationTable = KernelTranslationTable::new(); +``` + +它们在`MMU::init()`期间通过调用`KERNEL_TABLES.populate_tt_entries()`进行填充, +该函数利用`bsp::memory::mmu::virt_mem_layout().virt_addr_properties()`和一系列实用函数,将内核通用描述符转换为 +`AArch64 MMU`硬件所需的实际`64 bit`整数条目,用于填充转换表数组。 + +一个值得注意的事情是,每个页描述符都有一个索引(`AttrIndex`),它索引到[MAIR_EL1]寄存器, +该寄存器保存了有关相应页面的缓存属性的信息。我们目前定义了普通可缓存内存和设备内存(不被缓存)。 + +[MAIR_EL1]: http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0500d/CIHDHJBB.html + +```rust +impl MemoryManagementUnit { + /// Setup function for the MAIR_EL1 register. + fn set_up_mair(&self) { + // Define the memory types being mapped. + MAIR_EL1.write( + // Attribute 1 - Cacheable normal DRAM. + MAIR_EL1::Attr1_Normal_Outer::WriteBack_NonTransient_ReadWriteAlloc + + MAIR_EL1::Attr1_Normal_Inner::WriteBack_NonTransient_ReadWriteAlloc + + + // Attribute 0 - Device. + MAIR_EL1::Attr0_Device::nonGathering_nonReordering_EarlyWriteAck, + ); + } +``` + +然后,[Translation Table Base Register 0 - EL1]使用`lvl2`表的基地址进行设置,同时配置[Translation Control Register - EL1]: + +```rust +// Set the "Translation Table Base Register". +TTBR0_EL1.set_baddr(KERNEL_TABLES.phys_base_address()); + +self.configure_translation_control(); +``` + +最后,通过[System Control Register - EL1]打开`MMU`。最后一步还启用了数据和指令的缓存。 + +[Translation Table Base Register 0 - EL1]: https://docs.rs/aarch64-cpu/9.0.0/src/aarch64_cpu/registers/ttbr0_el1.rs.html +[Translation Control Register - EL1]: https://docs.rs/aarch64-cpu/9.0.0/src/aarch64_cpu/registers/tcr_el1.rs.html +[System Control Register - EL1]: https://docs.rs/aarch64-cpu/9.0.0/src/aarch64_cpu/registers/sctlr_el1.rs.html + +### `kernel.ld` + +我们需要将`code`段对齐到`64 KiB`,这样它就不会与下一个需要读/写属性而不是读/执行属性的部分重叠。 + +```ld.s +. = ALIGN(PAGE_SIZE); +__code_end_exclusive = .; +``` + +这会增加二进制文件的大小,但考虑到与传统的`4 KiB`粒度相比,它显著减少了静态分页条目的数量,这是一个小小的代价。 + +## 地址转换示例 + +出于教育目的,定义了一个布局,允许通过两个不同的虚拟地址访问`UART` +- 由于我们对整个`Device MMIO`区域进行了身份映射,所以在`MMU`打开后,可以通过断言其物理基地址 + (`0x3F20_1000`或`0xFA20_1000`,取决于使用的是哪个RPi版本)来访问它。 +- 此外,它还映射到第一个`512 MiB`中的最后一个`64 KiB`槽位,使其可以通过基地址`0x1FFF_1000`访问。 + +以下块图可视化了第二个映射的底层转换。 + +### 使用64KiB页描述符进行地址转换 + +Page Tables 64KiB + +## 零成本抽象 + +初始化代码再次是展示Rust零成本抽象在嵌入式编程中巨大潜力的一个很好的例子[[1]][[2]]。 + +让我们再次看一下使用[aarch64-cpu]crate设置`MAIR_EL1`寄存器的代码片段: + +[1]: https://blog.rust-lang.org/2015/05/11/traits.html +[2]: https://ruudvanasseldonk.com/2016/11/30/zero-cost-abstractions +[aarch64-cpu]: https://crates.io/crates/aarch64-cpu + +```rust +/// Setup function for the MAIR_EL1 register. +fn set_up_mair(&self) { + // Define the memory types being mapped. + MAIR_EL1.write( + // Attribute 1 - Cacheable normal DRAM. + MAIR_EL1::Attr1_Normal_Outer::WriteBack_NonTransient_ReadWriteAlloc + + MAIR_EL1::Attr1_Normal_Inner::WriteBack_NonTransient_ReadWriteAlloc + + + // Attribute 0 - Device. + MAIR_EL1::Attr0_Device::nonGathering_nonReordering_EarlyWriteAck, + ); +} +``` + +这段代码具有超强的表达能力,它利用`traits`,不同的`types`和`constants`来提供类型安全的寄存器操作。 + +最后,此代码根据数据表将寄存器的前四个字节设置为特定值。查看生成的代码, +我们可以看到,尽管有所有的类型安全和抽象,但它可以归结为两条汇编指令: + +```text + 800a8: 529fe089 mov w9, #0xff04 // #65284 + 800ac: d518a209 msr mair_el1, x9 +``` + +## 测试 + +打开虚拟内存现在是我们在内核初始化过程中要做的第一件事: + +```rust +unsafe fn kernel_init() -> ! { + use memory::mmu::interface::MMU; + + if let Err(string) = memory::mmu::mmu().enable_mmu_and_caching() { + panic!("MMU: {}", string); + } +``` + +稍后在引导过程中,可以观察到有关映射的打印: + +```console +$ make chainboot +[...] +Minipush 1.0 + +[MP] ⏳ Waiting for /dev/ttyUSB0 +[MP] ✅ Serial connected +[MP] 🔌 Please power the target now + + __ __ _ _ _ _ +| \/ (_)_ _ (_) | ___ __ _ __| | +| |\/| | | ' \| | |__/ _ \/ _` / _` | +|_| |_|_|_||_|_|____\___/\__,_\__,_| + + Raspberry Pi 3 + +[ML] Requesting binary +[MP] ⏩ Pushing 64 KiB =========================================🦀 100% 0 KiB/s Time: 00:00:00 +[ML] Loaded! Executing the payload now + +[ 0.811167] mingo version 0.10.0 +[ 0.811374] Booting on: Raspberry Pi 3 +[ 0.811829] MMU online. Special regions: +[ 0.812306] 0x00080000 - 0x0008ffff | 64 KiB | C RO PX | Kernel code and RO data +[ 0.813324] 0x1fff0000 - 0x1fffffff | 64 KiB | Dev RW PXN | Remapped Device MMIO +[ 0.814310] 0x3f000000 - 0x4000ffff | 17 MiB | Dev RW PXN | Device MMIO +[ 0.815198] Current privilege level: EL1 +[ 0.815675] Exception handling state: +[ 0.816119] Debug: Masked +[ 0.816509] SError: Masked +[ 0.816899] IRQ: Masked +[ 0.817289] FIQ: Masked +[ 0.817679] Architectural timer resolution: 52 ns +[ 0.818253] Drivers loaded: +[ 0.818589] 1. BCM PL011 UART +[ 0.819011] 2. BCM GPIO +[ 0.819369] Timer test, spinning for 1 second +[ !!! ] Writing through the remapped UART at 0x1FFF_1000 +[ 1.820409] Echoing input now +``` + +## 相比之前的变化(diff) +请检查[英文版本](README.md#diff-to-previous),这是最新的。 From 93e108f1b4eba360032411f2dc91aade3a94721b Mon Sep 17 00:00:00 2001 From: James Zow Date: Mon, 25 Sep 2023 21:35:15 +0800 Subject: [PATCH 75/75] Translation Chapter 08 (#190) * Translation Chapter 08 * error correction symbol * Update 08_hw_debug_JTAG/README.md --------- Co-authored-by: Diego Barrios Romero --- 08_hw_debug_JTAG/README.CN.md | 288 ++++++++++++++++++++++++++++++++++ 1 file changed, 288 insertions(+) create mode 100644 08_hw_debug_JTAG/README.CN.md diff --git a/08_hw_debug_JTAG/README.CN.md b/08_hw_debug_JTAG/README.CN.md new file mode 100644 index 00000000..b7703210 --- /dev/null +++ b/08_hw_debug_JTAG/README.CN.md @@ -0,0 +1,288 @@ +# 教程 08 - 使用JTAG进行硬件调试 + +## tl;dr + +按照以下顺序进行操作: + +1. 运行`make jtagboot`并保持终端打开。 +2. 连接USB串行设备。 +3. 连接`JTAG`调试器的USB设备。 +4. 在新的终端中,运行`make openocd`并保持终端打开。 +5. 在新的终端中,运行`make gdb`或者运行`make gdb-opt0`。 + +![Demo](../doc/09_demo.gif) + +## 目录 + +- [简介](#简介) +- [大纲](#大纲) +- [软件设置](#软件设置) +- [硬件设置](#硬件设置) + * [线路](#线路) +- [准备连接](#准备连接) +- [OpenOCD](#openocd) +- [GDB](#gdb) + * [备注](#备注) + + [优化](#优化) + + [GDB控制](#GDB控制) +- [关于USB连接限制的注意事项](#关于USB连接限制的注意事项) +- [额外资料](#额外资料) +- [致谢](#致谢) +- [相比之前的变化(diff)](#相比之前的变化(diff)) + +## 简介 + +在即将到来的教程中,我们将涉及RPi的SoC(系统芯片)的敏感区域,这可能会让我们的调试工作变得非常困难。 +例如,改变处理器的`Privilege Level`或引入`Virtual Memory`。 + +硬件调试器有时可以成为寻找棘手错误的最后手段。特别是对于调试复杂的、与体系结构相关的硬件问题,它将非常有用, +因为在这个领域,`QEMU`有时无法提供帮助,因为它对硬件的某些特性进行了抽象,并没有模拟到最后一位。 + +那么,让我们介绍一下`JTAG`调试。一旦设置好,它将允许我们在真实的硬件上逐步执行我们的内核。这是多么酷啊! + +## 大纲 + +从内核的角度来看,这个教程与之前的教程相同。我们只是在其周围添加了用于JTAG调试的基础设施。 + +## 软件设置 + +我们需要在SD卡的`config.txt`文件中添加另一行: + +```toml +arm_64bit=1 +init_uart_clock=48000000 +enable_jtag_gpio=1 +``` + +## 硬件设置 + +与我们WG的[Embedded Rust Book]书籍中使用的`STM32F3DISCOVERY`等微控制器板不同,RPi没有在其板上内置调试器。 +因此,您需要购买一个。 + +在本教程中,我们将使用OLIMEX的[ARM-USB-TINY-H]。它具有标准的[ARM JTAG 20 connector]。 +不幸的是,RPi没有这个连接器,所以我们必须通过跳线连接它。 + +[Embedded Rust Book]: https://rust-embedded.github.io/book/start/hardware.html +[ARM-USB-TINY-H]: https://www.olimex.com/Products/ARM/JTAG/ARM-USB-TINY-H +[ARM JTAG 20 connector]: http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0499dj/BEHEIHCE.html + +### 线路 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
GPIO #NameJTAG #NoteDiagram
VTREF1to 3.3V
GND4to GND
22TRST3
26TDI5
27TMS7
25TCK9
23RTCK11
24TDO13
+ +

+ +## 准备连接 + +在启动时,由于我们对`config.txt`进行的更改,RPi的固件将配置相应的GPIO引脚以实现`JTAG`功能。 + +现在剩下的要做的就是暂停RPi的执行,然后通过`JTAG`进行连接。因此,我们添加了一个新的`Makefile` target, +`make jtagboot`,它使用`chainboot`方法将一个小型辅助二进制文件加载到RPi上, +该文件只是将执行核心置于等待状态。 + +文件夹中单独[X1_JTAG_boot]文件夹中单独维护,并且是我们迄今为止在教程中使用的内核的修改版本。 + +[X1_JTAG_boot]: ../X1_JTAG_boot + +```console +$ make jtagboot +Minipush 1.0 + +[MP] ⏳ Waiting for /dev/ttyUSB0 +[MP] ✅ Serial connected +[MP] 🔌 Please power the target now + __ __ _ _ _ _ +| \/ (_)_ _ (_) | ___ __ _ __| | +| |\/| | | ' \| | |__/ _ \/ _` / _` | +|_| |_|_|_||_|_|____\___/\__,_\__,_| + + Raspberry Pi 3 + +[ML] Requesting binary +[MP] ⏩ Pushing 7 KiB ==========================================🦀 100% 0 KiB/s Time: 00:00:00 +[ML] Loaded! Executing the payload now + +[ 0.394532] Parking CPU core. Please connect over JTAG now. +``` + +保持USB串口连接和打开运行`jtagboot`的终端非常重要。当我们稍后加载实际的内核时,`UART`输出将显示在这里。 + +## OpenOCD + +接下来,我们需要启动开放式片上调试器 [Open On-Chip Debugger],也称为`OpenOCD`,以实际连接`JTAG`。 + +[Open On-Chip Debugger]: http://openocd.org + +一如既往,我们的教程力求使开发工具的使用尽可能简单, +这就是为什么我们将所有内容打包到了[dedicated Docker container]中,该容器已经用于链式引导和`QEMU`。 + +[dedicated Docker container]: ../docker/rustembedded-osdev-utils + +连接Olimex USB JTAG调试器,在同一个文件夹中打开一个新的终端窗口,然后按顺序输入 +`make openocd`命令。你将会看到一些初始输出: + +```console +$ make openocd +[...] +Open On-Chip Debugger 0.10.0 +[...] +Info : Listening on port 6666 for tcl connections +Info : Listening on port 4444 for telnet connections +Info : clock speed 1000 kHz +Info : JTAG tap: rpi3.tap tap/device found: 0x4ba00477 (mfg: 0x23b (ARM Ltd.), part: 0xba00, ver: 0x4) +Info : rpi3.core0: hardware has 6 breakpoints, 4 watchpoints +Info : rpi3.core1: hardware has 6 breakpoints, 4 watchpoints +Info : rpi3.core2: hardware has 6 breakpoints, 4 watchpoints +Info : rpi3.core3: hardware has 6 breakpoints, 4 watchpoints +Info : Listening on port 3333 for gdb connections +Info : Listening on port 3334 for gdb connections +Info : Listening on port 3335 for gdb connections +Info : Listening on port 3336 for gdb connections +``` + +`OpenOCD`已检测到RPi的四个核心,并打开了四个网络端口,`gdb`现在可以连接到这些端口来调试各自的核心。 + +## GDB + +最后,我们需要一个支持`AArch64`的`gdb`版本。你猜对了,它已经打包在osdev容器中。 +可以通过`make gdb`命令启动它。 + +实际上,这个Makefile target做了更多的事情。它构建了一个包含调试信息的特殊版本的内核。 +这使得`gdb`能够显示我们当前正在调试的`Rust`源代码行。 +它还启动了`gdb`,以便它已经加载了这个调试构建(`kernel_for_jtag`)。 + +现在我们可以使用`gdb`命令行来进行以下操作: + 1. 在我们的内核中设置断点。 + 2. 通过JTAG将内核加载到内存中(请记住,当前RPi仍在执行最小的JTAG引导二进制文件)。 + 3. 操纵RPi的程序计数器,使其从我们内核的入口点开始执行。 + 4. 逐步执行内核的执行过程。 + +```console +$ make gdb +[...] +>>> target remote :3333 # Connect to OpenOCD, core0 +>>> load # Load the kernel into the RPi's DRAM over JTAG. +Loading section .text, size 0x2454 lma 0x80000 +Loading section .rodata, size 0xa1d lma 0x82460 +Loading section .got, size 0x10 lma 0x82e80 +Loading section .data, size 0x20 lma 0x82e90 +Start address 0x0000000000080000, load size 11937 +Transfer rate: 63 KB/sec, 2984 bytes/write. +>>> set $pc = 0x80000 # Set RPI's program counter to the start of the + # kernel binary. +>>> break main.rs:158 +Breakpoint 1 at 0x8025c: file src/main.rs, line 158. +>>> cont +>>> step # Single-step through the kernel +>>> step +>>> ... +``` + +### 备注 + +#### 优化 + +在调试操作系统二进制文件时,您需要在可以逐步执行源代码粒度和生成的二进制文件的优化级别之间进行权衡。 +`make`和`make gdb`targets生成一个`--release`二进制文件,其中包含优化级别为3(`-opt-level=3`)。 +然而,在这种情况下,编译器会非常积极地进行内联,并尽可能地将读取和写入操作打包在一起。 +因此,不总是能够在源代码文件的特定行上准确命中断点。 + +因此,Makefile还提供了`make gdb-opt0` target,它使用了`-opt-level=0`。 +因此,它将允许您拥有更精细的调试粒度。然而,请记住,当调试与硬件密切相关的代码时, +编译器对易失性寄存器的读取或写入进行压缩的优化可能会对执行产生重大影响。 +请注意,上面的演示GIF是使用`gdb-opt0`录制的。 + +#### GDB控制 + +在某些情况下,您可能会遇到延迟循环或等待串行输入的代码。在这种情况下, +逐步执行可能不可行或无法正常工作。您可以通过在这些区域之外设置其他断点,从而跳过这些障碍。 +并使用`cont`命令到达它们。 + +在`gdb`中按下`ctrl+c`将再次停止RPi的执行,以防止您在没有进一步断点的情况下继续执行。 + +## 关于USB连接限制的注意事项 + +如果您按照教程从头到尾进行操作,关于USB连接的一切应该都没问题。 + +但是,请注意,根据当前的形式,我们的`Makefile`对连接的USB设备的命名做出了隐含的假设。 +它期望`/dev/ttyUSB0`是`UART`设备。 + +因此,请确保按照以下顺序将设备连接到您的计算机: + 1. 首先连接USB串行设备。 + 2. 然后连接Olimex调试器。 + +这样,主机操作系统会相应地枚举这些设备。这只需要做一次即可。 +可以多次断开和连接串行设备,例如在保持调试器连接的情况下启动不同的`make jtagboot`运行。 + +## 额外资料 + +- https://metebalci.com/blog/bare-metal-raspberry-pi-3b-jtag +- https://www.suse.com/c/debugging-raspberry-pi-3-with-jtag + +## 致谢 + +感谢[@naotaco](https://github.com/naotaco)为本教程奠定了基础。 + +## 相比之前的变化(diff) +请检查[英文版本](README.md#diff-to-previous),这是最新的。