From 67ee3a9fa9f17c0b022219a33f4330abc9c0c1b4 Mon Sep 17 00:00:00 2001 From: Andre Richter Date: Tue, 24 Sep 2019 23:00:36 +0200 Subject: [PATCH] delete v1 tutorials --- .03_uart1/.cargo/config | 5 - .03_uart1/Cargo.lock | 46 -- .03_uart1/Cargo.toml | 12 - .03_uart1/Makefile | 68 --- .03_uart1/README.md | 51 -- .03_uart1/kernel8 | Bin 68176 -> 0 bytes .03_uart1/kernel8.img | Bin 982 -> 0 bytes .03_uart1/link.ld | 55 --- .03_uart1/raspi3_boot/Cargo.toml | 9 - .03_uart1/raspi3_boot/src/boot_cores.S | 48 -- .03_uart1/raspi3_boot/src/lib.rs | 79 --- .03_uart1/src/gpio.rs | 73 --- .03_uart1/src/main.rs | 51 -- .03_uart1/src/uart.rs | 235 --------- .04_mailboxes/.cargo/config | 5 - .04_mailboxes/Cargo.lock | 46 -- .04_mailboxes/Cargo.toml | 12 - .04_mailboxes/Makefile | 68 --- .04_mailboxes/README.md | 80 --- .04_mailboxes/kernel8 | Bin 69544 -> 0 bytes .04_mailboxes/kernel8.img | Bin 1998 -> 0 bytes .04_mailboxes/link.ld | 55 --- .04_mailboxes/raspi3_boot/Cargo.toml | 9 - .04_mailboxes/raspi3_boot/src/boot_cores.S | 48 -- .04_mailboxes/raspi3_boot/src/lib.rs | 79 --- .04_mailboxes/src/gpio.rs | 73 --- .04_mailboxes/src/main.rs | 81 ---- .04_mailboxes/src/mbox.rs | 156 ------ .04_mailboxes/src/uart.rs | 255 ---------- .05_uart0/.cargo/config | 5 - .05_uart0/Cargo.lock | 46 -- .05_uart0/Cargo.toml | 12 - .05_uart0/Makefile | 68 --- .05_uart0/README.md | 48 -- .05_uart0/kernel8 | Bin 69856 -> 0 bytes .05_uart0/kernel8.img | Bin 2230 -> 0 bytes .05_uart0/link.ld | 55 --- .05_uart0/raspi3_boot/Cargo.toml | 9 - .05_uart0/raspi3_boot/src/boot_cores.S | 48 -- .05_uart0/raspi3_boot/src/lib.rs | 79 --- .05_uart0/src/gpio.rs | 75 --- .05_uart0/src/main.rs | 89 ---- .05_uart0/src/mbox.rs | 162 ------- .05_uart0/src/uart.rs | 285 ----------- .06_raspbootin64/.cargo/config | 6 - .06_raspbootin64/Cargo.lock | 46 -- .06_raspbootin64/Cargo.toml | 12 - .06_raspbootin64/Makefile | 68 --- .06_raspbootin64/README.md | 126 ----- .06_raspbootin64/kernel8 | Bin 66560 -> 0 bytes .06_raspbootin64/kernel8.img | Bin 1364 -> 0 bytes .06_raspbootin64/link.ld | 51 -- .06_raspbootin64/raspi3_boot/Cargo.toml | 9 - .06_raspbootin64/raspi3_boot/src/boot_cores.S | 57 --- .06_raspbootin64/raspi3_boot/src/lib.rs | 70 --- .06_raspbootin64/src/gpio.rs | 75 --- .06_raspbootin64/src/main.rs | 79 --- .06_raspbootin64/src/mbox.rs | 161 ------- .06_raspbootin64/src/uart.rs | 246 ---------- .07_abstraction/.cargo/config | 5 - .07_abstraction/Cargo.lock | 57 --- .07_abstraction/Cargo.toml | 13 - .07_abstraction/Makefile | 77 --- .07_abstraction/README.md | 121 ----- .07_abstraction/kernel8 | Bin 69864 -> 0 bytes .07_abstraction/kernel8.img | Bin 2222 -> 0 bytes .07_abstraction/link.ld | 55 --- .07_abstraction/raspi3_boot/Cargo.toml | 10 - .07_abstraction/raspi3_boot/src/lib.rs | 102 ---- .07_abstraction/src/gpio.rs | 75 --- .07_abstraction/src/main.rs | 88 ---- .07_abstraction/src/mbox.rs | 163 ------- .07_abstraction/src/uart.rs | 286 ----------- .08_random/.cargo/config | 5 - .08_random/Cargo.lock | 57 --- .08_random/Cargo.toml | 13 - .08_random/Makefile | 77 --- .08_random/README.md | 19 - .08_random/kernel8 | Bin 70720 -> 0 bytes .08_random/kernel8.img | Bin 2099 -> 0 bytes .08_random/link.ld | 55 --- .08_random/raspi3_boot/Cargo.toml | 10 - .08_random/raspi3_boot/src/lib.rs | 102 ---- .08_random/src/gpio.rs | 75 --- .08_random/src/main.rs | 69 --- .08_random/src/mbox.rs | 162 ------- .08_random/src/rand.rs | 107 ---- .08_random/src/uart.rs | 286 ----------- .09_delays/.cargo/config | 5 - .09_delays/Cargo.lock | 57 --- .09_delays/Cargo.toml | 13 - .09_delays/Makefile | 77 --- .09_delays/README.md | 25 - .09_delays/kernel8 | Bin 69488 -> 0 bytes .09_delays/kernel8.img | Bin 1804 -> 0 bytes .09_delays/link.ld | 55 --- .09_delays/raspi3_boot/Cargo.toml | 10 - .09_delays/raspi3_boot/src/lib.rs | 102 ---- .09_delays/src/delays.rs | 140 ------ .09_delays/src/gpio.rs | 75 --- .09_delays/src/main.rs | 73 --- .09_delays/src/mbox.rs | 162 ------- .09_delays/src/uart.rs | 263 ---------- .0A_power/.cargo/config | 5 - .0A_power/Cargo.lock | 57 --- .0A_power/Cargo.toml | 13 - .0A_power/Makefile | 76 --- .0A_power/README.md | 40 -- .0A_power/kernel8 | Bin 69680 -> 0 bytes .0A_power/kernel8.img | Bin 1922 -> 0 bytes .0A_power/link.ld | 55 --- .0A_power/raspi3_boot/Cargo.toml | 10 - .0A_power/raspi3_boot/src/lib.rs | 102 ---- .0A_power/src/delays.rs | 37 -- .0A_power/src/gpio.rs | 121 ----- .0A_power/src/main.rs | 71 --- .0A_power/src/mbox.rs | 163 ------- .0A_power/src/power.rs | 143 ------ .0A_power/src/uart.rs | 262 ---------- .0B_hw_debug_JTAG/.cargo/config | 5 - .0B_hw_debug_JTAG/Cargo.lock | 57 --- .0B_hw_debug_JTAG/Cargo.toml | 13 - .0B_hw_debug_JTAG/Makefile | 101 ---- .0B_hw_debug_JTAG/README.md | 265 ---------- .0B_hw_debug_JTAG/kernel8 | Bin 69680 -> 0 bytes .0B_hw_debug_JTAG/kernel8.img | Bin 1922 -> 0 bytes .0B_hw_debug_JTAG/link.ld | 55 --- .0B_hw_debug_JTAG/raspi3_boot/Cargo.toml | 10 - .0B_hw_debug_JTAG/raspi3_boot/src/lib.rs | 102 ---- .0B_hw_debug_JTAG/src/delays.rs | 37 -- .0B_hw_debug_JTAG/src/gpio.rs | 121 ----- .0B_hw_debug_JTAG/src/main.rs | 71 --- .0B_hw_debug_JTAG/src/mbox.rs | 163 ------- .0B_hw_debug_JTAG/src/power.rs | 143 ------ .0B_hw_debug_JTAG/src/uart.rs | 262 ---------- .0C_exception_levels/.cargo/config | 5 - .0C_exception_levels/Cargo.lock | 57 --- .0C_exception_levels/Cargo.toml | 13 - .0C_exception_levels/Makefile | 105 ---- .0C_exception_levels/README.md | 170 ------- .0C_exception_levels/kernel8 | Bin 70904 -> 0 bytes .0C_exception_levels/kernel8.img | Bin 2660 -> 0 bytes .0C_exception_levels/link.ld | 55 --- .0C_exception_levels/raspi3_boot/Cargo.toml | 10 - .0C_exception_levels/raspi3_boot/src/lib.rs | 141 ------ .0C_exception_levels/src/delays.rs | 68 --- .0C_exception_levels/src/gpio.rs | 121 ----- .0C_exception_levels/src/main.rs | 102 ---- .0C_exception_levels/src/mbox.rs | 162 ------- .0C_exception_levels/src/uart.rs | 282 ----------- .0D_virtual_memory/.cargo/config | 5 - .0D_virtual_memory/Cargo.lock | 57 --- .0D_virtual_memory/Cargo.toml | 13 - .0D_virtual_memory/Makefile | 104 ---- .0D_virtual_memory/README.md | 206 -------- .0D_virtual_memory/kernel8 | Bin 74112 -> 0 bytes .0D_virtual_memory/kernel8.img | Bin 3600 -> 0 bytes .0D_virtual_memory/link.ld | 57 --- .0D_virtual_memory/raspi3_boot/Cargo.toml | 10 - .0D_virtual_memory/raspi3_boot/src/lib.rs | 141 ------ .0D_virtual_memory/src/delays.rs | 37 -- .0D_virtual_memory/src/gpio.rs | 120 ----- .0D_virtual_memory/src/main.rs | 82 ---- .0D_virtual_memory/src/mbox.rs | 163 ------- .0D_virtual_memory/src/memory.rs | 221 --------- .0D_virtual_memory/src/memory/mmu.rs | 359 -------------- .0D_virtual_memory/src/uart.rs | 281 ----------- .0E_cache_performance/.cargo/config | 5 - .0E_cache_performance/Cargo.lock | 57 --- .0E_cache_performance/Cargo.toml | 13 - .0E_cache_performance/Makefile | 103 ---- .0E_cache_performance/README.md | 59 --- .0E_cache_performance/kernel8 | Bin 77856 -> 0 bytes .0E_cache_performance/kernel8.img | Bin 4861 -> 0 bytes .0E_cache_performance/link.ld | 57 --- .0E_cache_performance/raspi3_boot/Cargo.toml | 10 - .0E_cache_performance/raspi3_boot/src/lib.rs | 141 ------ .0E_cache_performance/src/benchmark.rs | 113 ----- .0E_cache_performance/src/delays.rs | 37 -- .0E_cache_performance/src/gpio.rs | 120 ----- .0E_cache_performance/src/main.rs | 69 --- .0E_cache_performance/src/mbox.rs | 163 ------- .0E_cache_performance/src/memory.rs | 225 --------- .0E_cache_performance/src/memory/mmu.rs | 349 -------------- .0E_cache_performance/src/uart.rs | 301 ------------ .../.cargo/config | 5 - .../Cargo.lock | 57 --- .../Cargo.toml | 13 - .0F_globals_synchronization_println/Makefile | 103 ---- .0F_globals_synchronization_println/README.md | 455 ------------------ .0F_globals_synchronization_println/kernel8 | Bin 91032 -> 0 bytes .../kernel8.img | Bin 11637 -> 0 bytes .0F_globals_synchronization_println/link.ld | 57 --- .../raspi3_boot/Cargo.toml | 10 - .../raspi3_boot/src/lib.rs | 141 ------ .../src/delays.rs | 37 -- .../src/devices.rs | 26 - .../src/devices/hw.rs | 31 -- .../src/devices/hw/gpio.rs | 120 ----- .../src/devices/hw/uart.rs | 276 ----------- .../src/devices/hw/videocore_mbox.rs | 164 ------- .../src/devices/virt.rs | 27 -- .../src/devices/virt/console.rs | 136 ------ .../src/macros.rs | 49 -- .../src/main.rs | 107 ---- .../src/memory.rs | 268 ----------- .../src/memory/mmu.rs | 349 -------------- .../src/sync.rs | 51 -- .10_DMA_memory/.cargo/config | 5 - .10_DMA_memory/Cargo.lock | 57 --- .10_DMA_memory/Cargo.toml | 13 - .10_DMA_memory/Makefile | 104 ---- .10_DMA_memory/README.md | 264 ---------- .10_DMA_memory/kernel8 | Bin 97680 -> 0 bytes .10_DMA_memory/kernel8.img | Bin 16416 -> 0 bytes .10_DMA_memory/link.ld | 57 --- .10_DMA_memory/raspi3_boot/Cargo.lock | 46 -- .10_DMA_memory/raspi3_boot/Cargo.toml | 10 - .10_DMA_memory/raspi3_boot/src/lib.rs | 141 ------ .10_DMA_memory/src/delays.rs | 37 -- .10_DMA_memory/src/devices.rs | 26 - .10_DMA_memory/src/devices/hw.rs | 33 -- .10_DMA_memory/src/devices/hw/gpio.rs | 120 ----- .10_DMA_memory/src/devices/hw/mini_uart.rs | 266 ---------- .10_DMA_memory/src/devices/hw/pl011_uart.rs | 276 ----------- .../src/devices/hw/videocore_mbox.rs | 170 ------- .10_DMA_memory/src/devices/virt.rs | 27 -- .10_DMA_memory/src/devices/virt/console.rs | 144 ------ .10_DMA_memory/src/macros.rs | 49 -- .10_DMA_memory/src/main.rs | 163 ------- .10_DMA_memory/src/memory.rs | 292 ----------- .10_DMA_memory/src/memory/bump_allocator.rs | 100 ---- .10_DMA_memory/src/memory/mmu.rs | 349 -------------- .10_DMA_memory/src/sync.rs | 51 -- .11_exceptions_groundwork/.cargo/config | 5 - .11_exceptions_groundwork/Cargo.lock | 57 --- .11_exceptions_groundwork/Cargo.toml | 13 - .11_exceptions_groundwork/Makefile | 104 ---- .11_exceptions_groundwork/README.md | 292 ----------- .11_exceptions_groundwork/kernel8 | Bin 103224 -> 0 bytes .11_exceptions_groundwork/kernel8.img | Bin 20512 -> 0 bytes .11_exceptions_groundwork/link.ld | 78 --- .../raspi3_boot/Cargo.lock | 46 -- .../raspi3_boot/Cargo.toml | 10 - .../raspi3_boot/src/lib.rs | 141 ------ .11_exceptions_groundwork/src/delays.rs | 37 -- .11_exceptions_groundwork/src/devices.rs | 26 - .11_exceptions_groundwork/src/devices/hw.rs | 33 -- .../src/devices/hw/gpio.rs | 120 ----- .../src/devices/hw/mini_uart.rs | 266 ---------- .../src/devices/hw/pl011_uart.rs | 276 ----------- .../src/devices/hw/videocore_mbox.rs | 170 ------- .11_exceptions_groundwork/src/devices/virt.rs | 27 -- .../src/devices/virt/console.rs | 144 ------ .11_exceptions_groundwork/src/exception.rs | 104 ---- .11_exceptions_groundwork/src/macros.rs | 49 -- .11_exceptions_groundwork/src/main.rs | 185 ------- .11_exceptions_groundwork/src/memory.rs | 292 ----------- .../src/memory/bump_allocator.rs | 100 ---- .11_exceptions_groundwork/src/memory/mmu.rs | 349 -------------- .11_exceptions_groundwork/src/sync.rs | 51 -- .11_exceptions_groundwork/src/vectors.S | 113 ----- .X1_JTAG_boot/.cargo/config | 5 - .X1_JTAG_boot/Cargo.lock | 57 --- .X1_JTAG_boot/Cargo.toml | 13 - .X1_JTAG_boot/Makefile | 69 --- .X1_JTAG_boot/README.md | 4 - .X1_JTAG_boot/jtag_boot | Bin 67992 -> 0 bytes .X1_JTAG_boot/jtag_boot.img | Bin 775 -> 0 bytes .X1_JTAG_boot/link.ld | 55 --- .X1_JTAG_boot/raspi3_boot/Cargo.toml | 10 - .X1_JTAG_boot/raspi3_boot/src/lib.rs | 102 ---- .X1_JTAG_boot/src/gpio.rs | 166 ------- .X1_JTAG_boot/src/main.rs | 65 --- .X1_JTAG_boot/src/mini_uart.rs | 218 --------- 275 files changed, 23495 deletions(-) delete mode 100644 .03_uart1/.cargo/config delete mode 100644 .03_uart1/Cargo.lock delete mode 100644 .03_uart1/Cargo.toml delete mode 100644 .03_uart1/Makefile delete mode 100644 .03_uart1/README.md delete mode 100755 .03_uart1/kernel8 delete mode 100755 .03_uart1/kernel8.img delete mode 100644 .03_uart1/link.ld delete mode 100644 .03_uart1/raspi3_boot/Cargo.toml delete mode 100644 .03_uart1/raspi3_boot/src/boot_cores.S delete mode 100644 .03_uart1/raspi3_boot/src/lib.rs delete mode 100644 .03_uart1/src/gpio.rs delete mode 100644 .03_uart1/src/main.rs delete mode 100644 .03_uart1/src/uart.rs delete mode 100644 .04_mailboxes/.cargo/config delete mode 100644 .04_mailboxes/Cargo.lock delete mode 100644 .04_mailboxes/Cargo.toml delete mode 100644 .04_mailboxes/Makefile delete mode 100644 .04_mailboxes/README.md delete mode 100755 .04_mailboxes/kernel8 delete mode 100755 .04_mailboxes/kernel8.img delete mode 100644 .04_mailboxes/link.ld delete mode 100644 .04_mailboxes/raspi3_boot/Cargo.toml delete mode 100644 .04_mailboxes/raspi3_boot/src/boot_cores.S delete mode 100644 .04_mailboxes/raspi3_boot/src/lib.rs delete mode 100644 .04_mailboxes/src/gpio.rs delete mode 100644 .04_mailboxes/src/main.rs delete mode 100644 .04_mailboxes/src/mbox.rs delete mode 100644 .04_mailboxes/src/uart.rs delete mode 100644 .05_uart0/.cargo/config delete mode 100644 .05_uart0/Cargo.lock delete mode 100644 .05_uart0/Cargo.toml delete mode 100644 .05_uart0/Makefile delete mode 100644 .05_uart0/README.md delete mode 100755 .05_uart0/kernel8 delete mode 100755 .05_uart0/kernel8.img delete mode 100644 .05_uart0/link.ld delete mode 100644 .05_uart0/raspi3_boot/Cargo.toml delete mode 100644 .05_uart0/raspi3_boot/src/boot_cores.S delete mode 100644 .05_uart0/raspi3_boot/src/lib.rs delete mode 100644 .05_uart0/src/gpio.rs delete mode 100644 .05_uart0/src/main.rs delete mode 100644 .05_uart0/src/mbox.rs delete mode 100644 .05_uart0/src/uart.rs delete mode 100644 .06_raspbootin64/.cargo/config delete mode 100644 .06_raspbootin64/Cargo.lock delete mode 100644 .06_raspbootin64/Cargo.toml delete mode 100644 .06_raspbootin64/Makefile delete mode 100644 .06_raspbootin64/README.md delete mode 100755 .06_raspbootin64/kernel8 delete mode 100755 .06_raspbootin64/kernel8.img delete mode 100644 .06_raspbootin64/link.ld delete mode 100644 .06_raspbootin64/raspi3_boot/Cargo.toml delete mode 100644 .06_raspbootin64/raspi3_boot/src/boot_cores.S delete mode 100644 .06_raspbootin64/raspi3_boot/src/lib.rs delete mode 100644 .06_raspbootin64/src/gpio.rs delete mode 100644 .06_raspbootin64/src/main.rs delete mode 100644 .06_raspbootin64/src/mbox.rs delete mode 100644 .06_raspbootin64/src/uart.rs delete mode 100644 .07_abstraction/.cargo/config delete mode 100644 .07_abstraction/Cargo.lock delete mode 100644 .07_abstraction/Cargo.toml delete mode 100644 .07_abstraction/Makefile delete mode 100644 .07_abstraction/README.md delete mode 100755 .07_abstraction/kernel8 delete mode 100755 .07_abstraction/kernel8.img delete mode 100644 .07_abstraction/link.ld delete mode 100644 .07_abstraction/raspi3_boot/Cargo.toml delete mode 100644 .07_abstraction/raspi3_boot/src/lib.rs delete mode 100644 .07_abstraction/src/gpio.rs delete mode 100644 .07_abstraction/src/main.rs delete mode 100644 .07_abstraction/src/mbox.rs delete mode 100644 .07_abstraction/src/uart.rs delete mode 100644 .08_random/.cargo/config delete mode 100644 .08_random/Cargo.lock delete mode 100644 .08_random/Cargo.toml delete mode 100644 .08_random/Makefile delete mode 100644 .08_random/README.md delete mode 100755 .08_random/kernel8 delete mode 100755 .08_random/kernel8.img delete mode 100644 .08_random/link.ld delete mode 100644 .08_random/raspi3_boot/Cargo.toml delete mode 100644 .08_random/raspi3_boot/src/lib.rs delete mode 100644 .08_random/src/gpio.rs delete mode 100644 .08_random/src/main.rs delete mode 100644 .08_random/src/mbox.rs delete mode 100644 .08_random/src/rand.rs delete mode 100644 .08_random/src/uart.rs delete mode 100644 .09_delays/.cargo/config delete mode 100644 .09_delays/Cargo.lock delete mode 100644 .09_delays/Cargo.toml delete mode 100644 .09_delays/Makefile delete mode 100644 .09_delays/README.md delete mode 100755 .09_delays/kernel8 delete mode 100755 .09_delays/kernel8.img delete mode 100644 .09_delays/link.ld delete mode 100644 .09_delays/raspi3_boot/Cargo.toml delete mode 100644 .09_delays/raspi3_boot/src/lib.rs delete mode 100644 .09_delays/src/delays.rs delete mode 100644 .09_delays/src/gpio.rs delete mode 100644 .09_delays/src/main.rs delete mode 100644 .09_delays/src/mbox.rs delete mode 100644 .09_delays/src/uart.rs delete mode 100644 .0A_power/.cargo/config delete mode 100644 .0A_power/Cargo.lock delete mode 100644 .0A_power/Cargo.toml delete mode 100644 .0A_power/Makefile delete mode 100644 .0A_power/README.md delete mode 100755 .0A_power/kernel8 delete mode 100755 .0A_power/kernel8.img delete mode 100644 .0A_power/link.ld delete mode 100644 .0A_power/raspi3_boot/Cargo.toml delete mode 100644 .0A_power/raspi3_boot/src/lib.rs delete mode 100644 .0A_power/src/delays.rs delete mode 100644 .0A_power/src/gpio.rs delete mode 100644 .0A_power/src/main.rs delete mode 100644 .0A_power/src/mbox.rs delete mode 100644 .0A_power/src/power.rs delete mode 100644 .0A_power/src/uart.rs delete mode 100644 .0B_hw_debug_JTAG/.cargo/config delete mode 100644 .0B_hw_debug_JTAG/Cargo.lock delete mode 100644 .0B_hw_debug_JTAG/Cargo.toml delete mode 100644 .0B_hw_debug_JTAG/Makefile delete mode 100644 .0B_hw_debug_JTAG/README.md delete mode 100755 .0B_hw_debug_JTAG/kernel8 delete mode 100755 .0B_hw_debug_JTAG/kernel8.img delete mode 100644 .0B_hw_debug_JTAG/link.ld delete mode 100644 .0B_hw_debug_JTAG/raspi3_boot/Cargo.toml delete mode 100644 .0B_hw_debug_JTAG/raspi3_boot/src/lib.rs delete mode 100644 .0B_hw_debug_JTAG/src/delays.rs delete mode 100644 .0B_hw_debug_JTAG/src/gpio.rs delete mode 100644 .0B_hw_debug_JTAG/src/main.rs delete mode 100644 .0B_hw_debug_JTAG/src/mbox.rs delete mode 100644 .0B_hw_debug_JTAG/src/power.rs delete mode 100644 .0B_hw_debug_JTAG/src/uart.rs delete mode 100644 .0C_exception_levels/.cargo/config delete mode 100644 .0C_exception_levels/Cargo.lock delete mode 100644 .0C_exception_levels/Cargo.toml delete mode 100644 .0C_exception_levels/Makefile delete mode 100644 .0C_exception_levels/README.md delete mode 100755 .0C_exception_levels/kernel8 delete mode 100755 .0C_exception_levels/kernel8.img delete mode 100644 .0C_exception_levels/link.ld delete mode 100644 .0C_exception_levels/raspi3_boot/Cargo.toml delete mode 100644 .0C_exception_levels/raspi3_boot/src/lib.rs delete mode 100644 .0C_exception_levels/src/delays.rs delete mode 100644 .0C_exception_levels/src/gpio.rs delete mode 100644 .0C_exception_levels/src/main.rs delete mode 100644 .0C_exception_levels/src/mbox.rs delete mode 100644 .0C_exception_levels/src/uart.rs delete mode 100644 .0D_virtual_memory/.cargo/config delete mode 100644 .0D_virtual_memory/Cargo.lock delete mode 100644 .0D_virtual_memory/Cargo.toml delete mode 100644 .0D_virtual_memory/Makefile delete mode 100644 .0D_virtual_memory/README.md delete mode 100755 .0D_virtual_memory/kernel8 delete mode 100755 .0D_virtual_memory/kernel8.img delete mode 100644 .0D_virtual_memory/link.ld delete mode 100644 .0D_virtual_memory/raspi3_boot/Cargo.toml delete mode 100644 .0D_virtual_memory/raspi3_boot/src/lib.rs delete mode 100644 .0D_virtual_memory/src/delays.rs delete mode 100644 .0D_virtual_memory/src/gpio.rs delete mode 100644 .0D_virtual_memory/src/main.rs delete mode 100644 .0D_virtual_memory/src/mbox.rs delete mode 100644 .0D_virtual_memory/src/memory.rs delete mode 100644 .0D_virtual_memory/src/memory/mmu.rs delete mode 100644 .0D_virtual_memory/src/uart.rs delete mode 100644 .0E_cache_performance/.cargo/config delete mode 100644 .0E_cache_performance/Cargo.lock delete mode 100644 .0E_cache_performance/Cargo.toml delete mode 100644 .0E_cache_performance/Makefile delete mode 100644 .0E_cache_performance/README.md delete mode 100755 .0E_cache_performance/kernel8 delete mode 100755 .0E_cache_performance/kernel8.img delete mode 100644 .0E_cache_performance/link.ld delete mode 100644 .0E_cache_performance/raspi3_boot/Cargo.toml delete mode 100644 .0E_cache_performance/raspi3_boot/src/lib.rs delete mode 100644 .0E_cache_performance/src/benchmark.rs delete mode 100644 .0E_cache_performance/src/delays.rs delete mode 100644 .0E_cache_performance/src/gpio.rs delete mode 100644 .0E_cache_performance/src/main.rs delete mode 100644 .0E_cache_performance/src/mbox.rs delete mode 100644 .0E_cache_performance/src/memory.rs delete mode 100644 .0E_cache_performance/src/memory/mmu.rs delete mode 100644 .0E_cache_performance/src/uart.rs delete mode 100644 .0F_globals_synchronization_println/.cargo/config delete mode 100644 .0F_globals_synchronization_println/Cargo.lock delete mode 100644 .0F_globals_synchronization_println/Cargo.toml delete mode 100644 .0F_globals_synchronization_println/Makefile delete mode 100644 .0F_globals_synchronization_println/README.md delete mode 100755 .0F_globals_synchronization_println/kernel8 delete mode 100755 .0F_globals_synchronization_println/kernel8.img delete mode 100644 .0F_globals_synchronization_println/link.ld delete mode 100644 .0F_globals_synchronization_println/raspi3_boot/Cargo.toml delete mode 100644 .0F_globals_synchronization_println/raspi3_boot/src/lib.rs delete mode 100644 .0F_globals_synchronization_println/src/delays.rs delete mode 100644 .0F_globals_synchronization_println/src/devices.rs delete mode 100644 .0F_globals_synchronization_println/src/devices/hw.rs delete mode 100644 .0F_globals_synchronization_println/src/devices/hw/gpio.rs delete mode 100644 .0F_globals_synchronization_println/src/devices/hw/uart.rs delete mode 100644 .0F_globals_synchronization_println/src/devices/hw/videocore_mbox.rs delete mode 100644 .0F_globals_synchronization_println/src/devices/virt.rs delete mode 100644 .0F_globals_synchronization_println/src/devices/virt/console.rs delete mode 100644 .0F_globals_synchronization_println/src/macros.rs delete mode 100644 .0F_globals_synchronization_println/src/main.rs delete mode 100644 .0F_globals_synchronization_println/src/memory.rs delete mode 100644 .0F_globals_synchronization_println/src/memory/mmu.rs delete mode 100644 .0F_globals_synchronization_println/src/sync.rs delete mode 100644 .10_DMA_memory/.cargo/config delete mode 100644 .10_DMA_memory/Cargo.lock delete mode 100644 .10_DMA_memory/Cargo.toml delete mode 100644 .10_DMA_memory/Makefile delete mode 100644 .10_DMA_memory/README.md delete mode 100755 .10_DMA_memory/kernel8 delete mode 100755 .10_DMA_memory/kernel8.img delete mode 100644 .10_DMA_memory/link.ld delete mode 100644 .10_DMA_memory/raspi3_boot/Cargo.lock delete mode 100644 .10_DMA_memory/raspi3_boot/Cargo.toml delete mode 100644 .10_DMA_memory/raspi3_boot/src/lib.rs delete mode 100644 .10_DMA_memory/src/delays.rs delete mode 100644 .10_DMA_memory/src/devices.rs delete mode 100644 .10_DMA_memory/src/devices/hw.rs delete mode 100644 .10_DMA_memory/src/devices/hw/gpio.rs delete mode 100644 .10_DMA_memory/src/devices/hw/mini_uart.rs delete mode 100644 .10_DMA_memory/src/devices/hw/pl011_uart.rs delete mode 100644 .10_DMA_memory/src/devices/hw/videocore_mbox.rs delete mode 100644 .10_DMA_memory/src/devices/virt.rs delete mode 100644 .10_DMA_memory/src/devices/virt/console.rs delete mode 100644 .10_DMA_memory/src/macros.rs delete mode 100644 .10_DMA_memory/src/main.rs delete mode 100644 .10_DMA_memory/src/memory.rs delete mode 100644 .10_DMA_memory/src/memory/bump_allocator.rs delete mode 100644 .10_DMA_memory/src/memory/mmu.rs delete mode 100644 .10_DMA_memory/src/sync.rs delete mode 100644 .11_exceptions_groundwork/.cargo/config delete mode 100644 .11_exceptions_groundwork/Cargo.lock delete mode 100644 .11_exceptions_groundwork/Cargo.toml delete mode 100644 .11_exceptions_groundwork/Makefile delete mode 100644 .11_exceptions_groundwork/README.md delete mode 100755 .11_exceptions_groundwork/kernel8 delete mode 100755 .11_exceptions_groundwork/kernel8.img delete mode 100644 .11_exceptions_groundwork/link.ld delete mode 100644 .11_exceptions_groundwork/raspi3_boot/Cargo.lock delete mode 100644 .11_exceptions_groundwork/raspi3_boot/Cargo.toml delete mode 100644 .11_exceptions_groundwork/raspi3_boot/src/lib.rs delete mode 100644 .11_exceptions_groundwork/src/delays.rs delete mode 100644 .11_exceptions_groundwork/src/devices.rs delete mode 100644 .11_exceptions_groundwork/src/devices/hw.rs delete mode 100644 .11_exceptions_groundwork/src/devices/hw/gpio.rs delete mode 100644 .11_exceptions_groundwork/src/devices/hw/mini_uart.rs delete mode 100644 .11_exceptions_groundwork/src/devices/hw/pl011_uart.rs delete mode 100644 .11_exceptions_groundwork/src/devices/hw/videocore_mbox.rs delete mode 100644 .11_exceptions_groundwork/src/devices/virt.rs delete mode 100644 .11_exceptions_groundwork/src/devices/virt/console.rs delete mode 100644 .11_exceptions_groundwork/src/exception.rs delete mode 100644 .11_exceptions_groundwork/src/macros.rs delete mode 100644 .11_exceptions_groundwork/src/main.rs delete mode 100644 .11_exceptions_groundwork/src/memory.rs delete mode 100644 .11_exceptions_groundwork/src/memory/bump_allocator.rs delete mode 100644 .11_exceptions_groundwork/src/memory/mmu.rs delete mode 100644 .11_exceptions_groundwork/src/sync.rs delete mode 100644 .11_exceptions_groundwork/src/vectors.S delete mode 100644 .X1_JTAG_boot/.cargo/config delete mode 100644 .X1_JTAG_boot/Cargo.lock delete mode 100644 .X1_JTAG_boot/Cargo.toml delete mode 100644 .X1_JTAG_boot/Makefile delete mode 100644 .X1_JTAG_boot/README.md delete mode 100755 .X1_JTAG_boot/jtag_boot delete mode 100755 .X1_JTAG_boot/jtag_boot.img delete mode 100644 .X1_JTAG_boot/link.ld delete mode 100644 .X1_JTAG_boot/raspi3_boot/Cargo.toml delete mode 100644 .X1_JTAG_boot/raspi3_boot/src/lib.rs delete mode 100644 .X1_JTAG_boot/src/gpio.rs delete mode 100644 .X1_JTAG_boot/src/main.rs delete mode 100644 .X1_JTAG_boot/src/mini_uart.rs diff --git a/.03_uart1/.cargo/config b/.03_uart1/.cargo/config deleted file mode 100644 index de3f84c9..00000000 --- a/.03_uart1/.cargo/config +++ /dev/null @@ -1,5 +0,0 @@ -[target.aarch64-unknown-none-softfloat] -rustflags = [ - "-C", "link-arg=-Tlink.ld", - "-C", "target-cpu=cortex-a53", -] diff --git a/.03_uart1/Cargo.lock b/.03_uart1/Cargo.lock deleted file mode 100644 index 82ecd2c6..00000000 --- a/.03_uart1/Cargo.lock +++ /dev/null @@ -1,46 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -[[package]] -name = "kernel8" -version = "0.1.0" -dependencies = [ - "raspi3_boot 0.1.0", - "register 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "panic-abort" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "r0" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "raspi3_boot" -version = "0.1.0" -dependencies = [ - "panic-abort 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "r0 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "register" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "tock-registers 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tock-registers" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[metadata] -"checksum panic-abort 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2c14a66511ed17b6a8b4256b868d7fd207836d891db15eea5195dbcaf87e630f" -"checksum r0 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e2a38df5b15c8d5c7e8654189744d8e396bddc18ad48041a500ce52d6948941f" -"checksum register 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "469bb5ddde81d67fb8bba4e14d77689b8166cfd077abe7530591cefe29d05823" -"checksum tock-registers 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c758f5195a2e0df9d9fecf6f506506b2766ff74cf64db1e995c87e2761a5c3e2" diff --git a/.03_uart1/Cargo.toml b/.03_uart1/Cargo.toml deleted file mode 100644 index a14dbb2d..00000000 --- a/.03_uart1/Cargo.toml +++ /dev/null @@ -1,12 +0,0 @@ -[package] -name = "kernel8" -version = "0.1.0" -authors = ["Andre Richter "] -edition = "2018" - -[dependencies] -raspi3_boot = { path = "raspi3_boot" } -register = "0.3.3" - -[package.metadata.cargo-xbuild] -sysroot_path = "../xbuild_sysroot" diff --git a/.03_uart1/Makefile b/.03_uart1/Makefile deleted file mode 100644 index 56649ff8..00000000 --- a/.03_uart1/Makefile +++ /dev/null @@ -1,68 +0,0 @@ -# -# MIT License -# -# Copyright (c) 2018-2019 Andre Richter -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# - -TARGET = aarch64-unknown-none-softfloat - -SOURCES = $(wildcard **/*.rs) $(wildcard **/*.S) link.ld - - -XRUSTC_CMD = cargo xrustc --target=$(TARGET) --release -CARGO_OUTPUT = target/$(TARGET)/release/kernel8 - -OBJCOPY = cargo objcopy -- -OBJCOPY_PARAMS = --strip-all -O binary - -CONTAINER_UTILS = andrerichter/raspi3-utils - -DOCKER_CMD = docker run -it --rm -DOCKER_ARG_CURDIR = -v $(shell pwd):/work -w /work - -DOCKER_EXEC_QEMU = qemu-system-aarch64 -M raspi3 -kernel kernel8.img - -.PHONY: all qemu clippy clean objdump nm - -all: clean kernel8.img - -$(CARGO_OUTPUT): $(SOURCES) - $(XRUSTC_CMD) - -kernel8.img: $(CARGO_OUTPUT) - cp $< . - $(OBJCOPY) $(OBJCOPY_PARAMS) $< kernel8.img - -qemu: all - $(DOCKER_CMD) $(DOCKER_ARG_CURDIR) $(CONTAINER_UTILS) \ - $(DOCKER_EXEC_QEMU) -serial null -serial stdio - -clippy: - cargo xclippy --target=$(TARGET) - -clean: - cargo clean - -objdump: - cargo objdump --target $(TARGET) -- -disassemble -print-imm-hex kernel8 - -nm: - cargo nm --target $(TARGET) -- kernel8 | sort diff --git a/.03_uart1/README.md b/.03_uart1/README.md deleted file mode 100644 index 979892cc..00000000 --- a/.03_uart1/README.md +++ /dev/null @@ -1,51 +0,0 @@ -# Tutorial 03 - UART1, Auxilary mini UART - -It is time for the famous Hello World example. We're going to write on the UART1 -first, as it is easier to program, since it has a fixed clocked frequency. - -## gpio.rs - -We have a new file that defines the GPIO controller addresses. It is going to be -very popular, as many device will need it in the future. - -We are using the [register][register] crate to modify MMIO addresses, because it -allows easy wrapping of addresses to volatile types. It will also be used for -UART registers. - -[register]: https://crates.io/crates/register - -## uart.rs - -A very minimal implementation. - -`MiniUart::init(&self)` initializes the device and maps it to the GPIO ports. - -`MiniUart::send(&self, c: char)` sends a character over the serial line. - -`MiniUart::getc(&self)` receives a character. The carrige return character (13) -will be converted into a newline character (10). - -`MiniUart::puts(&self, string: &str)` prints out a string. On newline, a carrige -return character will also be sent (13 + 10). - -## main.rs - -First, we have to call the uart initialization code. Then we wait for the first -keypress from the user before we say "Hello Rustacean!". If you've purchased an -USB serial cable, you should see it on `screen`'s screen. After that, every -character typed in `screen` will be echoed back. If you haven't turned off local -echo, that means you'll see every pressed key twice. - -## Simulation - -We can also use `QEMU` to simulate the UART output of our bare-metal binary on -the host PC. - -```console -ferris@box:~$ make qemu -[0] UART is live! -[1] Press a key to continue booting... Greetings fellow Rustacean! -``` - -However, let it be said that it is more thrilling to see your first output from -the real hardware target, so don't be shy and grab a USB-serial. diff --git a/.03_uart1/kernel8 b/.03_uart1/kernel8 deleted file mode 100755 index dd158f90ab8ec2b762deec236a196f2894c3e7da..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 68176 zcmeI!Uu;uV90%~|Jo#B4$7Vcv5kIiQlTX#r zbcZ|^bxUp2O|><_*=o_IY0m^rH&)P)Sof*iEEG1 zgokrdyq?Oni~e6$a9^j@*T}Jcxox^eqUzJ!epjXe-giu_bC>ri@<(T0&iigy`6raI z=);^Blg6SlQH{tG<7;{RD;)ol$M5I*`gu%>cS?C{JZ`8i&Ds!({_OWq&uBtD<~t6Q49)g@2PA6F(%tfup4*m_=(ra~mY z-ol<2xSkjJyrHa{s;s>jiSW9O(n7eFYaEqp=JGt}MK{Hk_s>cTt@Da&%JU=*?O(-v z-nnZ??7h?8*Ez23L9T5#*S1Zu_Vv4X_EOER!}Sk8->UlHg5qux zwQavwh^^zin|7Wv-}`?TVwF`joL6b)Nq70)p3haerfbud`rro1n!|Ue5ObcF*w+T$ z*LvQU$KKZk_Hp)G#qkAYeUsR;?{>lbE;wV{%f^VDN%ojOzLTHL4t_@4C+{S_K6g=x zU%AG$imQviKU~weOIth9$mcf6H8;b?B4*y7qy-VX#LxXz`+2*&oA-J5Y>&pgshoE( zby)YgyZ!sT&t>&o&Z~I`^rK!Q<4t7JMk+n5dwVh&ZuF_D>U}z^>!O|W_UeO!nIqol zaL&*Yx|a5F;pGngj?)VIvryc>!3@YWrtmJ79UJZV>7w|fcKp+#_!DMaqGtPj;Y_vJ zj-Qh5pWn}MnU?bRiURqF^I59S!)4-cl!<>>CjMEO`1fVvH#tsR=Xg>5C%Il(UW%W$ z>;I$7Jgd!qiFOsaRdKx3ey!&s(WW9#$Ju!=o8|F`v#s_Rf52+Q z^|X;a>Tm7u4KxQsTf@QDNHUTP1VinmXZM#52TF&7rNg1p;g-_juqZx6MkX;3&+2`t zoS|oPYWPrksP{;?&)M?`?>VdG4yA%|@j6ib;iM7qM{;&QZ@ncFZ|ICQ3S%OsiEqzJ|lj+RJmD@%&qB9%6s|d%E~mu-+3y{Qt`0+Ge8tF|yKHiT^LU Y?yi)9>uF@JfMrG1so8qzqfS>HhJlL-}n9geDC+>A+RRZ1s_KM z76%BoW}0TpJixV1fb2(rC%bqS5eMLbep`)g<ij7Fz;Z% zK8yS3ER3LUh1S_YpH!bNTsNeRs(y;g$cIsld9p<0uZYpv3kC&m{%O3Qn-| z&FC}DC3+F3^yFD!EdpVzTh z`seZeU{5oAq%rHk)yeS10^TvjD(44Krq~M3{k}DCA$+o*Tp?DlOH+?=IxiGG(be|+Q)X~xSZ6Z%3Q<10|8Iy#6 D1HnEv diff --git a/.03_uart1/link.ld b/.03_uart1/link.ld deleted file mode 100644 index 5c499f89..00000000 --- a/.03_uart1/link.ld +++ /dev/null @@ -1,55 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2018 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -ENTRY(_boot_cores); - -SECTIONS -{ - . = 0x80000; - - .text : - { - KEEP(*(.text.boot)) *(.text .text.*) - } - - .rodata : - { - *(.rodata .rodata.*) - } - - .data : - { - *(.data .data.*) - } - - .bss ALIGN(8): - { - __bss_start = .; - *(.bss .bss.*) - *(COMMON) - __bss_end = .; - } - - /DISCARD/ : { *(.comment) *(.gnu*) *(.note*) *(.eh_frame*) } -} diff --git a/.03_uart1/raspi3_boot/Cargo.toml b/.03_uart1/raspi3_boot/Cargo.toml deleted file mode 100644 index 1c3c1c69..00000000 --- a/.03_uart1/raspi3_boot/Cargo.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "raspi3_boot" -version = "0.1.0" -authors = ["Andre Richter "] -edition = "2018" - -[dependencies] -panic-abort = "0.3.1" -r0 = "0.2.2" diff --git a/.03_uart1/raspi3_boot/src/boot_cores.S b/.03_uart1/raspi3_boot/src/boot_cores.S deleted file mode 100644 index f6f28af6..00000000 --- a/.03_uart1/raspi3_boot/src/boot_cores.S +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (C) 2018 bzt (bztsrc@github) - * Copyright (c) 2018 Andre Richter - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - * - */ - -.section ".text.boot" - -.global _boot_cores - -_boot_cores: - // read cpu id, stop slave cores - mrs x1, mpidr_el1 - and x1, x1, #3 - cbz x1, 2f - // cpu id > 0, stop -1: wfe - b 1b -2: // cpu id == 0 - - // set stack before our code - ldr x1, =_boot_cores - mov sp, x1 - - // jump to Rust code, should not return - bl reset - // for failsafe, halt this core too - b 1b diff --git a/.03_uart1/raspi3_boot/src/lib.rs b/.03_uart1/raspi3_boot/src/lib.rs deleted file mode 100644 index a185d0a9..00000000 --- a/.03_uart1/raspi3_boot/src/lib.rs +++ /dev/null @@ -1,79 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2018 Jorge Aparicio - * Copyright (c) 2018-2019 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#![deny(missing_docs)] -#![deny(warnings)] -#![no_std] -#![feature(global_asm)] - -//! Low-level boot of the Raspberry's processor - -extern crate panic_abort; - -/// Type check the user-supplied entry function. -#[macro_export] -macro_rules! entry { - ($path:path) => { - /// # Safety - /// - /// - User must ensure to provide a suitable main function for the - /// platform. - #[export_name = "main"] - pub unsafe fn __main() -> ! { - // type check the given path - let f: fn() -> ! = $path; - - f() - } - }; -} - -/// Reset function. -/// -/// Initializes the bss section before calling into the user's `main()`. -/// -/// # Safety -/// -/// - Only a single core must be active and running this function. -#[no_mangle] -pub unsafe extern "C" fn reset() -> ! { - extern "C" { - // Boundaries of the .bss section, provided by the linker script - static mut __bss_start: u64; - static mut __bss_end: u64; - } - - // Zeroes the .bss section - r0::zero_bss(&mut __bss_start, &mut __bss_end); - - extern "Rust" { - fn main() -> !; - } - - main(); -} - -// Disable all cores except core 0, and then jump to reset() -global_asm!(include_str!("boot_cores.S")); diff --git a/.03_uart1/src/gpio.rs b/.03_uart1/src/gpio.rs deleted file mode 100644 index 408af5ab..00000000 --- a/.03_uart1/src/gpio.rs +++ /dev/null @@ -1,73 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2018 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -use super::MMIO_BASE; -use register::{mmio::ReadWrite, register_bitfields}; - -// Descriptions taken from -// https://github.com/raspberrypi/documentation/files/1888662/BCM2837-ARM-Peripherals.-.Revised.-.V2-1.pdf -register_bitfields! { - u32, - - /// GPIO Function Select 1 - GPFSEL1 [ - /// Pin 15 - FSEL15 OFFSET(15) NUMBITS(3) [ - Input = 0b000, - Output = 0b001, - RXD1 = 0b010 // Mini UART - Alternate function 5 - - ], - - /// Pin 14 - FSEL14 OFFSET(12) NUMBITS(3) [ - Input = 0b000, - Output = 0b001, - TXD1 = 0b010 // Mini UART - Alternate function 5 - ] - ], - - /// GPIO Pull-up/down Clock Register 0 - GPPUDCLK0 [ - /// Pin 15 - PUDCLK15 OFFSET(15) NUMBITS(1) [ - NoEffect = 0, - AssertClock = 1 - ], - - /// Pin 14 - PUDCLK14 OFFSET(14) NUMBITS(1) [ - NoEffect = 0, - AssertClock = 1 - ] - ] -} - -pub const GPFSEL1: *const ReadWrite = - (MMIO_BASE + 0x0020_0004) as *const ReadWrite; - -pub const GPPUD: *const ReadWrite = (MMIO_BASE + 0x0020_0094) as *const ReadWrite; - -pub const GPPUDCLK0: *const ReadWrite = - (MMIO_BASE + 0x0020_0098) as *const ReadWrite; diff --git a/.03_uart1/src/main.rs b/.03_uart1/src/main.rs deleted file mode 100644 index 6feec605..00000000 --- a/.03_uart1/src/main.rs +++ /dev/null @@ -1,51 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2018 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#![no_std] -#![no_main] -#![feature(asm)] - -const MMIO_BASE: u32 = 0x3F00_0000; - -mod gpio; -mod uart; - -fn kernel_entry() -> ! { - let uart = uart::MiniUart::new(); - - // set up serial console - uart.init(); - uart.puts("\n[0] UART is live!\n"); - - uart.puts("[1] Press a key to continue booting... "); - uart.getc(); - uart.puts("Greetings fellow Rustacean!\n"); - - // echo everything back - loop { - uart.send(uart.getc()); - } -} - -raspi3_boot::entry!(kernel_entry); diff --git a/.03_uart1/src/uart.rs b/.03_uart1/src/uart.rs deleted file mode 100644 index bca57093..00000000 --- a/.03_uart1/src/uart.rs +++ /dev/null @@ -1,235 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2018-2019 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -use super::MMIO_BASE; -use crate::gpio; -use core::ops; -use register::{mmio::*, register_bitfields}; - -// Auxilary mini UART registers -// -// Descriptions taken from -// https://github.com/raspberrypi/documentation/files/1888662/BCM2837-ARM-Peripherals.-.Revised.-.V2-1.pdf -register_bitfields! { - u32, - - /// Auxiliary enables - AUX_ENABLES [ - /// If set the mini UART is enabled. The UART will immediately - /// start receiving data, especially if the UART1_RX line is - /// low. - /// If clear the mini UART is disabled. That also disables any - /// mini UART register access - MINI_UART_ENABLE OFFSET(0) NUMBITS(1) [] - ], - - /// Mini Uart Interrupt Identify - AUX_MU_IIR [ - /// Writing with bit 1 set will clear the receive FIFO - /// Writing with bit 2 set will clear the transmit FIFO - FIFO_CLEAR OFFSET(1) NUMBITS(2) [ - Rx = 0b01, - Tx = 0b10, - All = 0b11 - ] - ], - - /// Mini Uart Line Control - AUX_MU_LCR [ - /// Mode the UART works in - DATA_SIZE OFFSET(0) NUMBITS(2) [ - SevenBit = 0b00, - EightBit = 0b11 - ] - ], - - /// Mini Uart Line Status - AUX_MU_LSR [ - /// This bit is set if the transmit FIFO can accept at least - /// one byte. - TX_EMPTY OFFSET(5) NUMBITS(1) [], - - /// This bit is set if the receive FIFO holds at least 1 - /// symbol. - DATA_READY OFFSET(0) NUMBITS(1) [] - ], - - /// Mini Uart Extra Control - AUX_MU_CNTL [ - /// If this bit is set the mini UART transmitter is enabled. - /// If this bit is clear the mini UART transmitter is disabled. - TX_EN OFFSET(1) NUMBITS(1) [ - Disabled = 0, - Enabled = 1 - ], - - /// If this bit is set the mini UART receiver is enabled. - /// If this bit is clear the mini UART receiver is disabled. - RX_EN OFFSET(0) NUMBITS(1) [ - Disabled = 0, - Enabled = 1 - ] - ], - - /// Mini Uart Baudrate - AUX_MU_BAUD [ - /// Mini UART baudrate counter - RATE OFFSET(0) NUMBITS(16) [] - ] -} - -const MINI_UART_BASE: u32 = MMIO_BASE + 0x21_5000; - -#[allow(non_snake_case)] -#[repr(C)] -pub struct RegisterBlock { - __reserved_0: u32, // 0x00 - AUX_ENABLES: ReadWrite, // 0x04 - __reserved_1: [u32; 14], // 0x08 - AUX_MU_IO: ReadWrite, // 0x40 - Mini Uart I/O Data - AUX_MU_IER: WriteOnly, // 0x44 - Mini Uart Interrupt Enable - AUX_MU_IIR: WriteOnly, // 0x48 - AUX_MU_LCR: WriteOnly, // 0x4C - AUX_MU_MCR: WriteOnly, // 0x50 - AUX_MU_LSR: ReadOnly, // 0x54 - __reserved_2: [u32; 2], // 0x58 - AUX_MU_CNTL: WriteOnly, // 0x60 - __reserved_3: u32, // 0x64 - AUX_MU_BAUD: WriteOnly, // 0x68 -} - -pub struct MiniUart; - -/// Deref to RegisterBlock -/// -/// Allows writing -/// ``` -/// self.MU_IER.read() -/// ``` -/// instead of something along the lines of -/// ``` -/// unsafe { (*MiniUart::ptr()).MU_IER.read() } -/// ``` -impl ops::Deref for MiniUart { - type Target = RegisterBlock; - - fn deref(&self) -> &Self::Target { - unsafe { &*Self::ptr() } - } -} - -impl MiniUart { - pub fn new() -> MiniUart { - MiniUart - } - - /// Returns a pointer to the register block - fn ptr() -> *const RegisterBlock { - MINI_UART_BASE as *const _ - } - - ///Set baud rate and characteristics (115200 8N1) and map to GPIO - pub fn init(&self) { - // initialize UART - self.AUX_ENABLES.modify(AUX_ENABLES::MINI_UART_ENABLE::SET); - self.AUX_MU_IER.set(0); - self.AUX_MU_CNTL.set(0); - self.AUX_MU_LCR.write(AUX_MU_LCR::DATA_SIZE::EightBit); - self.AUX_MU_MCR.set(0); - self.AUX_MU_IER.set(0); - self.AUX_MU_IIR.write(AUX_MU_IIR::FIFO_CLEAR::All); - self.AUX_MU_BAUD.write(AUX_MU_BAUD::RATE.val(270)); // 115200 baud - - // map UART1 to GPIO pins - unsafe { - (*gpio::GPFSEL1).modify(gpio::GPFSEL1::FSEL14::TXD1 + gpio::GPFSEL1::FSEL15::RXD1); - - (*gpio::GPPUD).set(0); // enable pins 14 and 15 - for _ in 0..150 { - asm!("nop" :::: "volatile"); - } - - (*gpio::GPPUDCLK0).write( - gpio::GPPUDCLK0::PUDCLK14::AssertClock + gpio::GPPUDCLK0::PUDCLK15::AssertClock, - ); - for _ in 0..150 { - asm!("nop" :::: "volatile"); - } - - (*gpio::GPPUDCLK0).set(0); - } - - self.AUX_MU_CNTL - .write(AUX_MU_CNTL::RX_EN::Enabled + AUX_MU_CNTL::TX_EN::Enabled); - } - - /// Send a character - pub fn send(&self, c: char) { - // wait until we can send - loop { - if self.AUX_MU_LSR.is_set(AUX_MU_LSR::TX_EMPTY) { - break; - } - - unsafe { asm!("nop" :::: "volatile") }; - } - - // write the character to the buffer - self.AUX_MU_IO.set(c as u32); - } - - /// Receive a character - pub fn getc(&self) -> char { - // wait until something is in the buffer - loop { - if self.AUX_MU_LSR.is_set(AUX_MU_LSR::DATA_READY) { - break; - } - - unsafe { asm!("nop" :::: "volatile") }; - } - - // read it and return - let mut ret = self.AUX_MU_IO.get() as u8 as char; - - // convert carrige return to newline - if ret == '\r' { - ret = '\n' - } - - ret - } - - /// Display a string - pub fn puts(&self, string: &str) { - for c in string.chars() { - // convert newline to carrige return + newline - if c == '\n' { - self.send('\r') - } - - self.send(c); - } - } -} diff --git a/.04_mailboxes/.cargo/config b/.04_mailboxes/.cargo/config deleted file mode 100644 index de3f84c9..00000000 --- a/.04_mailboxes/.cargo/config +++ /dev/null @@ -1,5 +0,0 @@ -[target.aarch64-unknown-none-softfloat] -rustflags = [ - "-C", "link-arg=-Tlink.ld", - "-C", "target-cpu=cortex-a53", -] diff --git a/.04_mailboxes/Cargo.lock b/.04_mailboxes/Cargo.lock deleted file mode 100644 index 82ecd2c6..00000000 --- a/.04_mailboxes/Cargo.lock +++ /dev/null @@ -1,46 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -[[package]] -name = "kernel8" -version = "0.1.0" -dependencies = [ - "raspi3_boot 0.1.0", - "register 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "panic-abort" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "r0" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "raspi3_boot" -version = "0.1.0" -dependencies = [ - "panic-abort 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "r0 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "register" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "tock-registers 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tock-registers" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[metadata] -"checksum panic-abort 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2c14a66511ed17b6a8b4256b868d7fd207836d891db15eea5195dbcaf87e630f" -"checksum r0 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e2a38df5b15c8d5c7e8654189744d8e396bddc18ad48041a500ce52d6948941f" -"checksum register 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "469bb5ddde81d67fb8bba4e14d77689b8166cfd077abe7530591cefe29d05823" -"checksum tock-registers 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c758f5195a2e0df9d9fecf6f506506b2766ff74cf64db1e995c87e2761a5c3e2" diff --git a/.04_mailboxes/Cargo.toml b/.04_mailboxes/Cargo.toml deleted file mode 100644 index a14dbb2d..00000000 --- a/.04_mailboxes/Cargo.toml +++ /dev/null @@ -1,12 +0,0 @@ -[package] -name = "kernel8" -version = "0.1.0" -authors = ["Andre Richter "] -edition = "2018" - -[dependencies] -raspi3_boot = { path = "raspi3_boot" } -register = "0.3.3" - -[package.metadata.cargo-xbuild] -sysroot_path = "../xbuild_sysroot" diff --git a/.04_mailboxes/Makefile b/.04_mailboxes/Makefile deleted file mode 100644 index 56649ff8..00000000 --- a/.04_mailboxes/Makefile +++ /dev/null @@ -1,68 +0,0 @@ -# -# MIT License -# -# Copyright (c) 2018-2019 Andre Richter -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# - -TARGET = aarch64-unknown-none-softfloat - -SOURCES = $(wildcard **/*.rs) $(wildcard **/*.S) link.ld - - -XRUSTC_CMD = cargo xrustc --target=$(TARGET) --release -CARGO_OUTPUT = target/$(TARGET)/release/kernel8 - -OBJCOPY = cargo objcopy -- -OBJCOPY_PARAMS = --strip-all -O binary - -CONTAINER_UTILS = andrerichter/raspi3-utils - -DOCKER_CMD = docker run -it --rm -DOCKER_ARG_CURDIR = -v $(shell pwd):/work -w /work - -DOCKER_EXEC_QEMU = qemu-system-aarch64 -M raspi3 -kernel kernel8.img - -.PHONY: all qemu clippy clean objdump nm - -all: clean kernel8.img - -$(CARGO_OUTPUT): $(SOURCES) - $(XRUSTC_CMD) - -kernel8.img: $(CARGO_OUTPUT) - cp $< . - $(OBJCOPY) $(OBJCOPY_PARAMS) $< kernel8.img - -qemu: all - $(DOCKER_CMD) $(DOCKER_ARG_CURDIR) $(CONTAINER_UTILS) \ - $(DOCKER_EXEC_QEMU) -serial null -serial stdio - -clippy: - cargo xclippy --target=$(TARGET) - -clean: - cargo clean - -objdump: - cargo objdump --target $(TARGET) -- -disassemble -print-imm-hex kernel8 - -nm: - cargo nm --target $(TARGET) -- kernel8 | sort diff --git a/.04_mailboxes/README.md b/.04_mailboxes/README.md deleted file mode 100644 index 4be7859a..00000000 --- a/.04_mailboxes/README.md +++ /dev/null @@ -1,80 +0,0 @@ -# Tutorial 04 - Mailboxes - -The Raspberry Pi 3 also has a more powerful UART, `UART0`, that among other -features, supports programmable clock rates. Before we can go on with setting -up `UART0`, we need mailboxes. Mailboxes are an interface between the Pi's ARM -CPU cores and the GPU. They will be used as a means to request work from the -GPU, for example, requesting to program a certain clock for `UART0`. - -In this tutorial, we'll start slowly and use it to query the Raspberry's serial -number and print that out on the already functional `UART1`. - -## uart.rs - -`MiniUart::hex(&self, d: u32)` prints out a binary value in hexadecimal format. - -## mbox.rs - -The mailbox interface. First we fill up the message in the `mbox.buffer` array, -then we call `Mbox::call(&mut self, channel: u32)` to pass it to the GPU, -specifying the mailbox channel. In this example we have used the [property -channel], which requires the message to be formatted as: - -[property channel]: (https://github.com/raspberrypi/firmware/wiki/Mailbox-property-interface) - -``` - 0. size of the message in bytes, (x+1)*4 - 1. mbox::REQUEST magic value, indicates request message - 2-x. tags - x+1. mbox::tag::LAST magic value, indicates no more tags -``` - -Where each tag looks like: - -``` - n+0. tag identifier - n+1. value buffer size in bytes - n+2. must be zero - n+3. optional value buffer -``` - -### Synchronization - -When signaling the GPU about a new mailbox message, we need to take care that -mailbox buffer setup has really finished. Both setting up mailbox contents and -signaling the GPU is done with store operations to independent memory locations -(RAM and MMIO). Since compilers are free to reorder instructions without -control-flow or data-dependencies for optimization purposes, we need to take -care that signaling the GPU really takes place _after_ all of the contents have -been written to the mailbox buffer. - -One way to do this would be to define the whole mailbox buffer as `volatile`, as -well as the location that we write to to signal the GPU. The compiler is not -allowed to reorder memory operations tagged with the `volatile` keyword with -each other. But this is not needed here. We don't care if the compiler optimizes -the buffer setup code as long as signaling the GPU takes place afterwards. - -Therefore, we prevent premature signaling by inserting an explicit [compiler -fence] after the buffer preparation code. Since we signal the CPU by calling -another function, the fence would only be effective if that function was a) -inlined and b) the inlined instructions then reordered with buffer setup -code. Otherwise the compiler has to assume that the called function has -dependencies on previous memory operations and not reorder here. Although there -is little chance that the reordering scenario happens, I'll leave the fence -there nonetheless for academic purposes :-) - -Please note that such reordering might also be done by CPUs that feature -[out-of-order execution]. Lucky us, although the Rasperry Pi 3 features -`ARMv8.0-A` CPU cores, the `Cortex-A53` variant is used, [which does not support -this feature]. Otherwise, a [fence] that additionally [emits corresponding CPU -instructions] to prevent this behavior would be needed. - -[compiler fence]: https://doc.rust-lang.org/beta/core/sync/atomic/fn.compiler_fence.html -[out-of-order execution]: https://en.wikipedia.org/wiki/Out-of-order_execution -[which does not support this feature]: https://en.wikipedia.org/wiki/Comparison_of_ARMv8-A_cores -[fence]: https://doc.rust-lang.org/std/sync/atomic/fn.fence.html -[emits corresponding CPU instructions]: https://developer.arm.com/products/architecture/a-profile/docs/100941/latest/barriers - -## main.rs - -We query the board's serial number and then we display it on the UART. diff --git a/.04_mailboxes/kernel8 b/.04_mailboxes/kernel8 deleted file mode 100755 index 043ce120f715836e69ac914c95133b918751aad8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 69544 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 diff --git a/.04_mailboxes/kernel8.img b/.04_mailboxes/kernel8.img deleted file mode 100755 index cf8c62b3fdfd6e9fb729f6134c01e0f9889816c9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1998 zcmZ{lT})GF7{{M;4(RETF@Y8kq34_}CV(4p6t!D2`C2w{&XBe^6CzT`nJvYVwsaeV zq(EYVazpu0?~pBvl*t|NFep z^Lswt(RlRS*&r&!FUqdS)P-mRTF zM>OIY<1}AVIV4epC(^UHL$Jy3FRXIfH8ozbgk(EBf9db2^vGlZ`RAfm2;D#`Av*oXbaRBCHm-*t#IG9>bd1GF`2b zgKwa2nP5n3myAJ{Z!zp_$SuXk>SaK^jNp3&zEwL2A(_lLSwiV=CEhO^#m(4$?Uu#8O9S3UO^+^&O}vUOnZ9QN`NYZdn^t9==><-zVr z(k|ui>;EwKIeOUX;&$8%b`KK%L|wME^z9;3A(!x>ZpCb=ezCj?k=GB%OHStX0QE`b z`yKR6p`e`QtUkkBVFpuYzTI|)*@RG!Xm34wQ->bahPK*&o}Lx1{PDc`M`&DV9DS-n zf1*#u_mx=Loet!X2YoCzKrinrHsuf8EIJLgVZ@1HmQr&v1lt1W z*ONM%lUrbRx(lsruN*$BkCDgkE;Ka_Ocb%1`UKMH zIAr)?JgyeK>Egg}oagF3JeZd_XPW22;hj7e4ySq8`(ZDh#@#$;vi9aVla=PF--qY@ z-8>cIPM!)e%~QD#4|_i_&UAf@8GG{>GtxZrK0HTu^JG)*j(%m6$%=j%(3fo3KHAkU zri)3P@r*~5}R*#W+3ch5HUt{m#1`>Y}NgOWAq;<|fX7+!={2}fL?$d}^D+kN)t>(nFIoLBT z{(PM_nKlpm#aD@UmDGIVveHy*u_;cU(&_wMQ>Es2E-Q^*&F53>ic9NJy1SJ2E_b)n z?bnpHt}ZODR#a3dA9*#6t$oU8T4!h17mCI2>$bORb~ju&;nZz!>(tn3k6-ilC_c^W Zw09= - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -ENTRY(_boot_cores); - -SECTIONS -{ - . = 0x80000; - - .text : - { - KEEP(*(.text.boot)) *(.text .text.*) - } - - .rodata : - { - *(.rodata .rodata.*) - } - - .data : - { - *(.data .data.*) - } - - .bss ALIGN(8): - { - __bss_start = .; - *(.bss .bss.*) - *(COMMON) - __bss_end = .; - } - - /DISCARD/ : { *(.comment) *(.gnu*) *(.note*) *(.eh_frame*) } -} diff --git a/.04_mailboxes/raspi3_boot/Cargo.toml b/.04_mailboxes/raspi3_boot/Cargo.toml deleted file mode 100644 index 1c3c1c69..00000000 --- a/.04_mailboxes/raspi3_boot/Cargo.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "raspi3_boot" -version = "0.1.0" -authors = ["Andre Richter "] -edition = "2018" - -[dependencies] -panic-abort = "0.3.1" -r0 = "0.2.2" diff --git a/.04_mailboxes/raspi3_boot/src/boot_cores.S b/.04_mailboxes/raspi3_boot/src/boot_cores.S deleted file mode 100644 index f6f28af6..00000000 --- a/.04_mailboxes/raspi3_boot/src/boot_cores.S +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (C) 2018 bzt (bztsrc@github) - * Copyright (c) 2018 Andre Richter - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - * - */ - -.section ".text.boot" - -.global _boot_cores - -_boot_cores: - // read cpu id, stop slave cores - mrs x1, mpidr_el1 - and x1, x1, #3 - cbz x1, 2f - // cpu id > 0, stop -1: wfe - b 1b -2: // cpu id == 0 - - // set stack before our code - ldr x1, =_boot_cores - mov sp, x1 - - // jump to Rust code, should not return - bl reset - // for failsafe, halt this core too - b 1b diff --git a/.04_mailboxes/raspi3_boot/src/lib.rs b/.04_mailboxes/raspi3_boot/src/lib.rs deleted file mode 100644 index a185d0a9..00000000 --- a/.04_mailboxes/raspi3_boot/src/lib.rs +++ /dev/null @@ -1,79 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2018 Jorge Aparicio - * Copyright (c) 2018-2019 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#![deny(missing_docs)] -#![deny(warnings)] -#![no_std] -#![feature(global_asm)] - -//! Low-level boot of the Raspberry's processor - -extern crate panic_abort; - -/// Type check the user-supplied entry function. -#[macro_export] -macro_rules! entry { - ($path:path) => { - /// # Safety - /// - /// - User must ensure to provide a suitable main function for the - /// platform. - #[export_name = "main"] - pub unsafe fn __main() -> ! { - // type check the given path - let f: fn() -> ! = $path; - - f() - } - }; -} - -/// Reset function. -/// -/// Initializes the bss section before calling into the user's `main()`. -/// -/// # Safety -/// -/// - Only a single core must be active and running this function. -#[no_mangle] -pub unsafe extern "C" fn reset() -> ! { - extern "C" { - // Boundaries of the .bss section, provided by the linker script - static mut __bss_start: u64; - static mut __bss_end: u64; - } - - // Zeroes the .bss section - r0::zero_bss(&mut __bss_start, &mut __bss_end); - - extern "Rust" { - fn main() -> !; - } - - main(); -} - -// Disable all cores except core 0, and then jump to reset() -global_asm!(include_str!("boot_cores.S")); diff --git a/.04_mailboxes/src/gpio.rs b/.04_mailboxes/src/gpio.rs deleted file mode 100644 index 408af5ab..00000000 --- a/.04_mailboxes/src/gpio.rs +++ /dev/null @@ -1,73 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2018 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -use super::MMIO_BASE; -use register::{mmio::ReadWrite, register_bitfields}; - -// Descriptions taken from -// https://github.com/raspberrypi/documentation/files/1888662/BCM2837-ARM-Peripherals.-.Revised.-.V2-1.pdf -register_bitfields! { - u32, - - /// GPIO Function Select 1 - GPFSEL1 [ - /// Pin 15 - FSEL15 OFFSET(15) NUMBITS(3) [ - Input = 0b000, - Output = 0b001, - RXD1 = 0b010 // Mini UART - Alternate function 5 - - ], - - /// Pin 14 - FSEL14 OFFSET(12) NUMBITS(3) [ - Input = 0b000, - Output = 0b001, - TXD1 = 0b010 // Mini UART - Alternate function 5 - ] - ], - - /// GPIO Pull-up/down Clock Register 0 - GPPUDCLK0 [ - /// Pin 15 - PUDCLK15 OFFSET(15) NUMBITS(1) [ - NoEffect = 0, - AssertClock = 1 - ], - - /// Pin 14 - PUDCLK14 OFFSET(14) NUMBITS(1) [ - NoEffect = 0, - AssertClock = 1 - ] - ] -} - -pub const GPFSEL1: *const ReadWrite = - (MMIO_BASE + 0x0020_0004) as *const ReadWrite; - -pub const GPPUD: *const ReadWrite = (MMIO_BASE + 0x0020_0094) as *const ReadWrite; - -pub const GPPUDCLK0: *const ReadWrite = - (MMIO_BASE + 0x0020_0098) as *const ReadWrite; diff --git a/.04_mailboxes/src/main.rs b/.04_mailboxes/src/main.rs deleted file mode 100644 index 0c44920b..00000000 --- a/.04_mailboxes/src/main.rs +++ /dev/null @@ -1,81 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2018-2019 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#![no_std] -#![no_main] -#![feature(asm)] - -const MMIO_BASE: u32 = 0x3F00_0000; - -mod gpio; -mod mbox; -mod uart; - -use core::sync::atomic::{compiler_fence, Ordering}; - -fn kernel_entry() -> ! { - let mut mbox = mbox::Mbox::new(); - let uart = uart::MiniUart::new(); - - // set up serial console - uart.init(); - uart.puts("\n[0] UART is live!\n"); - - uart.puts("[1] Press a key to continue booting... "); - uart.getc(); - uart.puts("Greetings fellow Rustacean!\n"); - - // get the board's unique serial number with a mailbox call - mbox.buffer[0] = 8 * 4; // length of the message - mbox.buffer[1] = mbox::REQUEST; // this is a request message - mbox.buffer[2] = mbox::tag::GETSERIAL; // get serial number command - mbox.buffer[3] = 8; // buffer size - mbox.buffer[4] = 8; - mbox.buffer[5] = 0; // clear output buffer - mbox.buffer[6] = 0; - mbox.buffer[7] = mbox::tag::LAST; - - // Insert a compiler fence that ensures that all stores to the - // mbox buffer are finished before the GPU is signaled (which is - // done by a store operation as well). - compiler_fence(Ordering::Release); - - // send the message to the GPU and receive answer - match mbox.call(mbox::channel::PROP) { - Err(_) => uart.puts("[i] Unable to query serial!\n"), - Ok(()) => { - uart.puts("[i] My serial number is: 0x"); - uart.hex(mbox.buffer[6]); - uart.hex(mbox.buffer[5]); - uart.puts("\n"); - } - }; - - // echo everything back - loop { - uart.send(uart.getc()); - } -} - -raspi3_boot::entry!(kernel_entry); diff --git a/.04_mailboxes/src/mbox.rs b/.04_mailboxes/src/mbox.rs deleted file mode 100644 index 88f8fadd..00000000 --- a/.04_mailboxes/src/mbox.rs +++ /dev/null @@ -1,156 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2018 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -use super::MMIO_BASE; -use core::ops; -use register::{ - mmio::{ReadOnly, WriteOnly}, - register_bitfields, -}; - -register_bitfields! { - u32, - - STATUS [ - FULL OFFSET(31) NUMBITS(1) [], - EMPTY OFFSET(30) NUMBITS(1) [] - ] -} - -const VIDEOCORE_MBOX: u32 = MMIO_BASE + 0xB880; - -#[allow(non_snake_case)] -#[repr(C)] -pub struct RegisterBlock { - READ: ReadOnly, // 0x00 - __reserved_0: [u32; 5], // 0x04 - STATUS: ReadOnly, // 0x18 - __reserved_1: u32, // 0x1C - WRITE: WriteOnly, // 0x20 -} - -// Custom errors -pub enum MboxError { - ResponseError, - UnknownError, -} -pub type Result = ::core::result::Result; - -// Channels -pub mod channel { - pub const PROP: u32 = 8; -} - -// Tags -pub mod tag { - pub const GETSERIAL: u32 = 0x10004; - pub const LAST: u32 = 0; -} - -// Responses -mod response { - pub const SUCCESS: u32 = 0x8000_0000; - pub const ERROR: u32 = 0x8000_0001; // error parsing request buffer (partial response) -} - -pub const REQUEST: u32 = 0; - -// Public interface to the mailbox -#[repr(C)] -#[repr(align(16))] -pub struct Mbox { - // The address for buffer needs to be 16-byte aligned so that the - // Videcore can handle it properly. - pub buffer: [u32; 36], -} - -/// Deref to RegisterBlock -/// -/// Allows writing -/// ``` -/// self.STATUS.read() -/// ``` -/// instead of something along the lines of -/// ``` -/// unsafe { (*Mbox::ptr()).STATUS.read() } -/// ``` -impl ops::Deref for Mbox { - type Target = RegisterBlock; - - fn deref(&self) -> &Self::Target { - unsafe { &*Self::ptr() } - } -} - -impl Mbox { - pub fn new() -> Mbox { - Mbox { buffer: [0; 36] } - } - - /// Returns a pointer to the register block - fn ptr() -> *const RegisterBlock { - VIDEOCORE_MBOX as *const _ - } - - /// Make a mailbox call. Returns Err(MboxError) on failure, Ok(()) success - pub fn call(&self, channel: u32) -> Result<()> { - // wait until we can write to the mailbox - loop { - if !self.STATUS.is_set(STATUS::FULL) { - break; - } - - unsafe { asm!("nop" :::: "volatile") }; - } - - let buf_ptr = self.buffer.as_ptr() as u32; - - // write the address of our message to the mailbox with channel identifier - self.WRITE.set((buf_ptr & !0xF) | (channel & 0xF)); - - // now wait for the response - loop { - // is there a response? - loop { - if !self.STATUS.is_set(STATUS::EMPTY) { - break; - } - - unsafe { asm!("nop" :::: "volatile") }; - } - - let resp: u32 = self.READ.get(); - - // is it a response to our message? - if ((resp & 0xF) == channel) && ((resp & !0xF) == buf_ptr) { - // is it a valid successful response? - return match self.buffer[1] { - response::SUCCESS => Ok(()), - response::ERROR => Err(MboxError::ResponseError), - _ => Err(MboxError::UnknownError), - }; - } - } - } -} diff --git a/.04_mailboxes/src/uart.rs b/.04_mailboxes/src/uart.rs deleted file mode 100644 index 42ff4e43..00000000 --- a/.04_mailboxes/src/uart.rs +++ /dev/null @@ -1,255 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2018-2019 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -use super::MMIO_BASE; -use crate::gpio; -use core::ops; -use register::{mmio::*, register_bitfields}; - -// Auxilary mini UART registers -// -// Descriptions taken from -// https://github.com/raspberrypi/documentation/files/1888662/BCM2837-ARM-Peripherals.-.Revised.-.V2-1.pdf -register_bitfields! { - u32, - - /// Auxiliary enables - AUX_ENABLES [ - /// If set the mini UART is enabled. The UART will immediately - /// start receiving data, especially if the UART1_RX line is - /// low. - /// If clear the mini UART is disabled. That also disables any - /// mini UART register access - MINI_UART_ENABLE OFFSET(0) NUMBITS(1) [] - ], - - /// Mini Uart Interrupt Identify - AUX_MU_IIR [ - /// Writing with bit 1 set will clear the receive FIFO - /// Writing with bit 2 set will clear the transmit FIFO - FIFO_CLEAR OFFSET(1) NUMBITS(2) [ - Rx = 0b01, - Tx = 0b10, - All = 0b11 - ] - ], - - /// Mini Uart Line Control - AUX_MU_LCR [ - /// Mode the UART works in - DATA_SIZE OFFSET(0) NUMBITS(2) [ - SevenBit = 0b00, - EightBit = 0b11 - ] - ], - - /// Mini Uart Line Status - AUX_MU_LSR [ - /// This bit is set if the transmit FIFO can accept at least - /// one byte. - TX_EMPTY OFFSET(5) NUMBITS(1) [], - - /// This bit is set if the receive FIFO holds at least 1 - /// symbol. - DATA_READY OFFSET(0) NUMBITS(1) [] - ], - - /// Mini Uart Extra Control - AUX_MU_CNTL [ - /// If this bit is set the mini UART transmitter is enabled. - /// If this bit is clear the mini UART transmitter is disabled. - TX_EN OFFSET(1) NUMBITS(1) [ - Disabled = 0, - Enabled = 1 - ], - - /// If this bit is set the mini UART receiver is enabled. - /// If this bit is clear the mini UART receiver is disabled. - RX_EN OFFSET(0) NUMBITS(1) [ - Disabled = 0, - Enabled = 1 - ] - ], - - /// Mini Uart Baudrate - AUX_MU_BAUD [ - /// Mini UART baudrate counter - RATE OFFSET(0) NUMBITS(16) [] - ] -} - -const MINI_UART_BASE: u32 = MMIO_BASE + 0x21_5000; - -#[allow(non_snake_case)] -#[repr(C)] -pub struct RegisterBlock { - __reserved_0: u32, // 0x00 - AUX_ENABLES: ReadWrite, // 0x04 - __reserved_1: [u32; 14], // 0x08 - AUX_MU_IO: ReadWrite, // 0x40 - Mini Uart I/O Data - AUX_MU_IER: WriteOnly, // 0x44 - Mini Uart Interrupt Enable - AUX_MU_IIR: WriteOnly, // 0x48 - AUX_MU_LCR: WriteOnly, // 0x4C - AUX_MU_MCR: WriteOnly, // 0x50 - AUX_MU_LSR: ReadOnly, // 0x54 - __reserved_2: [u32; 2], // 0x58 - AUX_MU_CNTL: WriteOnly, // 0x60 - __reserved_3: u32, // 0x64 - AUX_MU_BAUD: WriteOnly, // 0x68 -} - -pub struct MiniUart; - -/// Deref to RegisterBlock -/// -/// Allows writing -/// ``` -/// self.MU_IER.read() -/// ``` -/// instead of something along the lines of -/// ``` -/// unsafe { (*MiniUart::ptr()).MU_IER.read() } -/// ``` -impl ops::Deref for MiniUart { - type Target = RegisterBlock; - - fn deref(&self) -> &Self::Target { - unsafe { &*Self::ptr() } - } -} - -impl MiniUart { - pub fn new() -> MiniUart { - MiniUart - } - - /// Returns a pointer to the register block - fn ptr() -> *const RegisterBlock { - MINI_UART_BASE as *const _ - } - - ///Set baud rate and characteristics (115200 8N1) and map to GPIO - pub fn init(&self) { - // initialize UART - self.AUX_ENABLES.modify(AUX_ENABLES::MINI_UART_ENABLE::SET); - self.AUX_MU_IER.set(0); - self.AUX_MU_CNTL.set(0); - self.AUX_MU_LCR.write(AUX_MU_LCR::DATA_SIZE::EightBit); - self.AUX_MU_MCR.set(0); - self.AUX_MU_IER.set(0); - self.AUX_MU_IIR.write(AUX_MU_IIR::FIFO_CLEAR::All); - self.AUX_MU_BAUD.write(AUX_MU_BAUD::RATE.val(270)); // 115200 baud - - // map UART1 to GPIO pins - unsafe { - (*gpio::GPFSEL1).modify(gpio::GPFSEL1::FSEL14::TXD1 + gpio::GPFSEL1::FSEL15::RXD1); - - (*gpio::GPPUD).set(0); // enable pins 14 and 15 - for _ in 0..150 { - asm!("nop" :::: "volatile"); - } - - (*gpio::GPPUDCLK0).write( - gpio::GPPUDCLK0::PUDCLK14::AssertClock + gpio::GPPUDCLK0::PUDCLK15::AssertClock, - ); - for _ in 0..150 { - asm!("nop" :::: "volatile"); - } - - (*gpio::GPPUDCLK0).set(0); - } - - self.AUX_MU_CNTL - .write(AUX_MU_CNTL::RX_EN::Enabled + AUX_MU_CNTL::TX_EN::Enabled); - } - - /// Send a character - pub fn send(&self, c: char) { - // wait until we can send - loop { - if self.AUX_MU_LSR.is_set(AUX_MU_LSR::TX_EMPTY) { - break; - } - - unsafe { asm!("nop" :::: "volatile") }; - } - - // write the character to the buffer - self.AUX_MU_IO.set(c as u32); - } - - /// Receive a character - pub fn getc(&self) -> char { - // wait until something is in the buffer - loop { - if self.AUX_MU_LSR.is_set(AUX_MU_LSR::DATA_READY) { - break; - } - - unsafe { asm!("nop" :::: "volatile") }; - } - - // read it and return - let mut ret = self.AUX_MU_IO.get() as u8 as char; - - // convert carrige return to newline - if ret == '\r' { - ret = '\n' - } - - ret - } - - /// Display a string - pub fn puts(&self, string: &str) { - for c in string.chars() { - // convert newline to carrige return + newline - if c == '\n' { - self.send('\r') - } - - self.send(c); - } - } - - /// Display a binary value in hexadecimal - pub fn hex(&self, d: u32) { - let mut n; - - for i in 0..8 { - // get highest tetrad - n = d.wrapping_shr(28 - i * 4) & 0xF; - - // 0-9 => '0'-'9', 10-15 => 'A'-'F' - // Add proper offset for ASCII table - if n > 9 { - n += 0x37; - } else { - n += 0x30; - } - - self.send(n as u8 as char); - } - } -} diff --git a/.05_uart0/.cargo/config b/.05_uart0/.cargo/config deleted file mode 100644 index de3f84c9..00000000 --- a/.05_uart0/.cargo/config +++ /dev/null @@ -1,5 +0,0 @@ -[target.aarch64-unknown-none-softfloat] -rustflags = [ - "-C", "link-arg=-Tlink.ld", - "-C", "target-cpu=cortex-a53", -] diff --git a/.05_uart0/Cargo.lock b/.05_uart0/Cargo.lock deleted file mode 100644 index 82ecd2c6..00000000 --- a/.05_uart0/Cargo.lock +++ /dev/null @@ -1,46 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -[[package]] -name = "kernel8" -version = "0.1.0" -dependencies = [ - "raspi3_boot 0.1.0", - "register 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "panic-abort" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "r0" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "raspi3_boot" -version = "0.1.0" -dependencies = [ - "panic-abort 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "r0 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "register" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "tock-registers 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tock-registers" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[metadata] -"checksum panic-abort 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2c14a66511ed17b6a8b4256b868d7fd207836d891db15eea5195dbcaf87e630f" -"checksum r0 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e2a38df5b15c8d5c7e8654189744d8e396bddc18ad48041a500ce52d6948941f" -"checksum register 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "469bb5ddde81d67fb8bba4e14d77689b8166cfd077abe7530591cefe29d05823" -"checksum tock-registers 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c758f5195a2e0df9d9fecf6f506506b2766ff74cf64db1e995c87e2761a5c3e2" diff --git a/.05_uart0/Cargo.toml b/.05_uart0/Cargo.toml deleted file mode 100644 index a14dbb2d..00000000 --- a/.05_uart0/Cargo.toml +++ /dev/null @@ -1,12 +0,0 @@ -[package] -name = "kernel8" -version = "0.1.0" -authors = ["Andre Richter "] -edition = "2018" - -[dependencies] -raspi3_boot = { path = "raspi3_boot" } -register = "0.3.3" - -[package.metadata.cargo-xbuild] -sysroot_path = "../xbuild_sysroot" diff --git a/.05_uart0/Makefile b/.05_uart0/Makefile deleted file mode 100644 index d1723093..00000000 --- a/.05_uart0/Makefile +++ /dev/null @@ -1,68 +0,0 @@ -# -# MIT License -# -# Copyright (c) 2018-2019 Andre Richter -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# - -TARGET = aarch64-unknown-none-softfloat - -SOURCES = $(wildcard **/*.rs) $(wildcard **/*.S) link.ld - - -XRUSTC_CMD = cargo xrustc --target=$(TARGET) --release -CARGO_OUTPUT = target/$(TARGET)/release/kernel8 - -OBJCOPY = cargo objcopy -- -OBJCOPY_PARAMS = --strip-all -O binary - -CONTAINER_UTILS = andrerichter/raspi3-utils - -DOCKER_CMD = docker run -it --rm -DOCKER_ARG_CURDIR = -v $(shell pwd):/work -w /work - -DOCKER_EXEC_QEMU = qemu-system-aarch64 -M raspi3 -kernel kernel8.img - -.PHONY: all qemu clippy clean objdump nm - -all: clean kernel8.img - -$(CARGO_OUTPUT): $(SOURCES) - $(XRUSTC_CMD) - -kernel8.img: $(CARGO_OUTPUT) - cp $< . - $(OBJCOPY) $(OBJCOPY_PARAMS) $< kernel8.img - -qemu: all - $(DOCKER_CMD) $(DOCKER_ARG_CURDIR) $(CONTAINER_UTILS) \ - $(DOCKER_EXEC_QEMU) -serial stdio - -clippy: - cargo xclippy --target=$(TARGET) - -clean: - cargo clean - -objdump: - cargo objdump --target $(TARGET) -- -disassemble -print-imm-hex kernel8 - -nm: - cargo nm --target $(TARGET) -- kernel8 | sort diff --git a/.05_uart0/README.md b/.05_uart0/README.md deleted file mode 100644 index 07062ea7..00000000 --- a/.05_uart0/README.md +++ /dev/null @@ -1,48 +0,0 @@ -# Tutorial 05 - UART0, PL011 - -Finally, we can set up `UART0` thanks to the mailbox interface. This tutorial -produces the same output as tutorial 04, but it prints the serial number on -`UART0`. - -## uart.rs - -In the init function, we use the mailbox to set a base clock for the UART: - -```rust -mbox.buffer[0] = 9 * 4; -mbox.buffer[1] = mbox::REQUEST; -mbox.buffer[2] = mbox::tag::SETCLKRATE; -mbox.buffer[3] = 12; -mbox.buffer[4] = 8; -mbox.buffer[5] = mbox::clock::UART; // UART clock -mbox.buffer[6] = 4_000_000; // 4Mhz -mbox.buffer[7] = 0; // skip turbo setting -mbox.buffer[8] = mbox::tag::LAST; - -// Insert a compiler fence that ensures that all stores to the -// mbox buffer are finished before the GPU is signaled (which -// is done by a store operation as well). -compiler_fence(Ordering::Release); - -if mbox.call(mbox::channel::PROP).is_err() { - return Err(UartError::MailboxError); // Abort if UART clocks couldn't be set -}; - -``` - -Afterwards, we can program the rate divisors: - -```rust -self.IBRD.write(IBRD::IBRD.val(2)); // Results in 115200 baud -self.FBRD.write(FBRD::FBRD.val(0xB)); -``` - -Baud rate calculation won't be covered in detail here. Please see [this -reference from ARM](http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0183g/I49493.html) -for details. - -The API for using the UART is identical to the `UART1` API. - -## main.rs - -We query the board's serial number and display it on the serial console. diff --git a/.05_uart0/kernel8 b/.05_uart0/kernel8 deleted file mode 100755 index c801eef137a5bc47a53b05c6315c3693ee227da8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 69856 zcmeI!TWlOx83*uhX6<;r4Y}C6PGXYmY;eJG=;FQD-n39V32EaJqO#t!h$wOPGPXCi z*V$WZHx|B#BDayMIMgkdN=<;OS;GT@DA))Tx8Wg$Cn8#&P!j}F8iPb)k~*#E@}1ck zUq-v)fd^jxEA7tgH{YD|o!>cUc1QLfd`y-kGF~$Mk_z9fTBuFGpsZicX`=wi)J7Fl zuH}|%ImY$EeME)hCH<>$B)#>o{Vfw)qqmI%1Rwwb2tWV=5P$##AOHafKmY;|fB*y_ z009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz z00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_< z0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb z2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$## zAOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;| zfB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U< z00Izz00bZa0SNs61FXfTW;ah1G)D&|9VvBI8A1VUOrCbH`QXw ze7JW`Z&SqH&|_oyeCRIMe?i{nov_iYOk@}RPH;}m(DsfWaNhe|Pnh#2xQ5D4QI)lS zYgMa@k~codhn$k5_dFkOR*Xdd;)I7#@-uQIetgx6D=bH-W zH~C!TinuGbV{!+L2FtmIrC867Nip6e=Y@D|Mt#D|!Cq;u@3LNB57!sxxOE#?rS;k|%0U=wrC9k6+wd!`EUf#+Du5J~PkO-^%A-RY>{chev*sJ3wcy-R+Qa_BG?d z9=5HNMz7hFv7nvjaf-bs*twnN?o3ylOV#jvES!>a3l?db=Wn)#=cY-a+|GI_*Q(I$ zpSaHh+@Ev!>7{uPv3+_>%tH^)!POOWaFwrb;yHMjbMpEauNIwyYHbdB)-2C~R7N3Q z7r}RU?OM5Bo5bs&#_qF8H0zwC*`4K-6!ZKR_iLl?YI(M))$w+|-^sBacDJn^4emNF z_JOnE^%|OeVXt#$V%$0N;@i%d(>&gVQ+soFJND#0JaXm2oTc+Uh3_@T?ni&k*Cozl zr&E^P_*%N?;C&&?{3M@taGjU9uc!Ha(^5TM>6i-ycrJHJi_H#R6C<*Heun31&PJh? z*WZyATNW(VY3D9V9RqSb1OAHrDzUEw%uQ!-k!B`T}S;x zwZ6?#p$*sle8|`XVqBYfTtDY=IrVW}Vjp9?KjrwMWmAI~vvQC3D$loZ&l@Z55ji>b zSU9zh=VmX@(VpD>=x?=o6#GEi13XV+-HSC|KfJZWwuaZ$pK0T+;cXo+a2+EXDarHL z;NW<}@K#^V*o(C-T-#~xN330A?@fp`&GF~;xOlF-!ZpVen>)m{25z(UK}u#5n|+7J zrfS7LeU5YAH?<++;+ZSrqKzqTqvx1itHs7`Jiv80xgAkY?=idYsj<^qJ>4bh;q|h# z$FzD5ZCG8;p$$v*JXNBeC(ZRdy0&;dkFH&+XJ3hWzGSY)ZCzcD+qzVbw?sXkH`lYh ztav@!%a-bKmZ)coxt?`YwQ9cBk*|a2%fa)qj&m=Y=1at_dR)xccX+Wi)w<_xTf*blY{?8E`#Ff%Dv!QoImelIeSBxV_fy7ajnYPv6x$nc3q;^DpvRV#s8B3V^e-q@7IX)vru~-E74A2eRBP#^@#V7R70 zXWhY2UDoHV%X%B@!fEYb>e#(pgS$PEIT-I%>mCo)`JYo$1H!neB^GV;c_U#@^X_ny zcmK*6@n^%SjQ=oy_-UW;r^HOxN#^% zjc-Kj`Bb!N(L=_*ozd@K&Mcgn@3(W<=zC?ZasLIqVKF`zzm56}&oiQ}95eb}dH?aX ag`V6igM4o8|Fb3Te@Vaptf@Hj{r>^*i3dUe diff --git a/.05_uart0/kernel8.img b/.05_uart0/kernel8.img deleted file mode 100755 index 38baf14bb62f25170c6bd664f2d827da13a71097..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2230 zcmZ`)UrbYX6h8Ofs<&50g#H1Ua&K8oplrlh|8yo3kR=nh8FO272~jE7*$S4lg>4QJ zN;8uxFVx9gvIk*{(cA4|S&X5}7Et$q+0)E)Pm8eZ0cCr@1}&P|eZO+sK_g9?-us>N zJLfy+JLlIia^AHW8qRx&t{qc^yO~U;Y>eprdZPGajxIdIy9}I2B=*S&!moU3M4c8W zJ|oEX$M4YMf=kj;ee1P*@SpDBfm6JP=t3LO_FPPkXt_pOFVTVmYeZ-3O>w#AbND%7PDnzMTLlJHeFQB(^o>@ z;B1T{cZ`TvO{0$_E~1LulVO*2Y%r5?FM$75e)G1N zL`j~=%<{(IV?ABz`VxNk!N&u?7&sVTqEhkHrqX&F1!taT+%jkB9K-MIx`w2YzEfq+ z*lFX*ovj}{ZRsV>gWx&yazm2!VvaqREj`cTnfWr@cDyQHMG>3oMv7dRek8Kk&E1sltI-D9Y@gb82a2ylaCVXMnhKUk?P~M zl)xpRU(yO~b||FPRC8LrLdoBeb06}_{fF~9Fsw<(m<~Q@FttpBDcH-P!EX3u^ctsL zsDUY~fp6{q8gK@3V=mO&m|YQkB@T07H9I7Zl5(7qHESrybiRSS5`B^NlSWqJ%{VUu z^P%rjQADk6V|yUmFIg#hcCS1hi^}8YZp!0Bs5jNOS6gs3YEN2kU7Zw;-BWP35L@i{ z5q1uK=u@AdMT_W~1$)7Iww?GP3wT~fuEY4w3Z{h7GU;?e%Nj1d(}I~8;LUU6&}mX4 z_j3DfF1;%yhzYrtf^F-tH%)H^J<$4HeU`7Hj~k))EM}-)SeoU3*q(Fdxi-uy`u0Xx zqPS$iY@0AU146JFILkMRU%$1%Sp!?MrNSZK5`tgrHWJ8v61M%YS&{1@dXo~&iChd3 zdm)unIMRY-XWSZ}W!xtCJ<$Df@xJ;u<2II<;b+YHaZmBC#}kdkuIkq+9Oc|n4BKMH zo!bFcS2^nX9(BojUDwf{T)p1{PYY#sRh z-%)dxi-Z{K!9zwI#;5bB*>PxaD9h)>Dts_6`5nvhIj~_Rp9356d=9O`=U^e9Jw-3( zv!^J}r)d>FZx-^Y6Ib%76Z3qwt-|NkLOzv-7xSq!}@Yz_%r|831A{vwh%gu88?vyk%!Y%Ct~4r8B&#hI#j4Zii9ICm5N49mWs zp)|v8!9VhR>He2mw;oYi8dbOA4=Y{%54|?2_4Oml!H_o`Ry<0l_q5W}t#ot;di;T2 zuhQP#jfWF;b#= - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -ENTRY(_boot_cores); - -SECTIONS -{ - . = 0x80000; - - .text : - { - KEEP(*(.text.boot)) *(.text .text.*) - } - - .rodata : - { - *(.rodata .rodata.*) - } - - .data : - { - *(.data .data.*) - } - - .bss ALIGN(8): - { - __bss_start = .; - *(.bss .bss.*) - *(COMMON) - __bss_end = .; - } - - /DISCARD/ : { *(.comment) *(.gnu*) *(.note*) *(.eh_frame*) } -} diff --git a/.05_uart0/raspi3_boot/Cargo.toml b/.05_uart0/raspi3_boot/Cargo.toml deleted file mode 100644 index 1c3c1c69..00000000 --- a/.05_uart0/raspi3_boot/Cargo.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "raspi3_boot" -version = "0.1.0" -authors = ["Andre Richter "] -edition = "2018" - -[dependencies] -panic-abort = "0.3.1" -r0 = "0.2.2" diff --git a/.05_uart0/raspi3_boot/src/boot_cores.S b/.05_uart0/raspi3_boot/src/boot_cores.S deleted file mode 100644 index f6f28af6..00000000 --- a/.05_uart0/raspi3_boot/src/boot_cores.S +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (C) 2018 bzt (bztsrc@github) - * Copyright (c) 2018 Andre Richter - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - * - */ - -.section ".text.boot" - -.global _boot_cores - -_boot_cores: - // read cpu id, stop slave cores - mrs x1, mpidr_el1 - and x1, x1, #3 - cbz x1, 2f - // cpu id > 0, stop -1: wfe - b 1b -2: // cpu id == 0 - - // set stack before our code - ldr x1, =_boot_cores - mov sp, x1 - - // jump to Rust code, should not return - bl reset - // for failsafe, halt this core too - b 1b diff --git a/.05_uart0/raspi3_boot/src/lib.rs b/.05_uart0/raspi3_boot/src/lib.rs deleted file mode 100644 index a185d0a9..00000000 --- a/.05_uart0/raspi3_boot/src/lib.rs +++ /dev/null @@ -1,79 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2018 Jorge Aparicio - * Copyright (c) 2018-2019 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#![deny(missing_docs)] -#![deny(warnings)] -#![no_std] -#![feature(global_asm)] - -//! Low-level boot of the Raspberry's processor - -extern crate panic_abort; - -/// Type check the user-supplied entry function. -#[macro_export] -macro_rules! entry { - ($path:path) => { - /// # Safety - /// - /// - User must ensure to provide a suitable main function for the - /// platform. - #[export_name = "main"] - pub unsafe fn __main() -> ! { - // type check the given path - let f: fn() -> ! = $path; - - f() - } - }; -} - -/// Reset function. -/// -/// Initializes the bss section before calling into the user's `main()`. -/// -/// # Safety -/// -/// - Only a single core must be active and running this function. -#[no_mangle] -pub unsafe extern "C" fn reset() -> ! { - extern "C" { - // Boundaries of the .bss section, provided by the linker script - static mut __bss_start: u64; - static mut __bss_end: u64; - } - - // Zeroes the .bss section - r0::zero_bss(&mut __bss_start, &mut __bss_end); - - extern "Rust" { - fn main() -> !; - } - - main(); -} - -// Disable all cores except core 0, and then jump to reset() -global_asm!(include_str!("boot_cores.S")); diff --git a/.05_uart0/src/gpio.rs b/.05_uart0/src/gpio.rs deleted file mode 100644 index da6a5be4..00000000 --- a/.05_uart0/src/gpio.rs +++ /dev/null @@ -1,75 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2018 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -use super::MMIO_BASE; -use register::{mmio::ReadWrite, register_bitfields}; - -// Descriptions taken from -// https://github.com/raspberrypi/documentation/files/1888662/BCM2837-ARM-Peripherals.-.Revised.-.V2-1.pdf -register_bitfields! { - u32, - - /// GPIO Function Select 1 - GPFSEL1 [ - /// Pin 15 - FSEL15 OFFSET(15) NUMBITS(3) [ - Input = 0b000, - Output = 0b001, - RXD0 = 0b100, // UART0 - Alternate function 0 - RXD1 = 0b010 // Mini UART - Alternate function 5 - - ], - - /// Pin 14 - FSEL14 OFFSET(12) NUMBITS(3) [ - Input = 0b000, - Output = 0b001, - TXD0 = 0b100, // UART0 - Alternate function 0 - TXD1 = 0b010 // Mini UART - Alternate function 5 - ] - ], - - /// GPIO Pull-up/down Clock Register 0 - GPPUDCLK0 [ - /// Pin 15 - PUDCLK15 OFFSET(15) NUMBITS(1) [ - NoEffect = 0, - AssertClock = 1 - ], - - /// Pin 14 - PUDCLK14 OFFSET(14) NUMBITS(1) [ - NoEffect = 0, - AssertClock = 1 - ] - ] -} - -pub const GPFSEL1: *const ReadWrite = - (MMIO_BASE + 0x0020_0004) as *const ReadWrite; - -pub const GPPUD: *const ReadWrite = (MMIO_BASE + 0x0020_0094) as *const ReadWrite; - -pub const GPPUDCLK0: *const ReadWrite = - (MMIO_BASE + 0x0020_0098) as *const ReadWrite; diff --git a/.05_uart0/src/main.rs b/.05_uart0/src/main.rs deleted file mode 100644 index 7ccca746..00000000 --- a/.05_uart0/src/main.rs +++ /dev/null @@ -1,89 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2018 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#![no_std] -#![no_main] -#![feature(asm)] - -const MMIO_BASE: u32 = 0x3F00_0000; - -mod gpio; -mod mbox; -mod uart; - -use core::sync::atomic::{compiler_fence, Ordering}; - -fn kernel_entry() -> ! { - let mut mbox = mbox::Mbox::new(); - let uart = uart::Uart::new(); - - // set up serial console - match uart.init(&mut mbox) { - Ok(_) => uart.puts("\n[0] UART is live!\n"), - Err(_) => loop { - unsafe { asm!("wfe" :::: "volatile") }; // If UART fails, abort early - }, - } - - uart.puts("[1] Press a key to continue booting... "); - uart.getc(); - uart.puts("Greetings fellow Rustacean!\n"); - - // get the board's unique serial number with a mailbox call - mbox.buffer[0] = 8 * 4; // length of the message - mbox.buffer[1] = mbox::REQUEST; // this is a request message - mbox.buffer[2] = mbox::tag::GETSERIAL; // get serial number command - mbox.buffer[3] = 8; // buffer size - mbox.buffer[4] = 8; - mbox.buffer[5] = 0; // clear output buffer - mbox.buffer[6] = 0; - mbox.buffer[7] = mbox::tag::LAST; - - // Insert a compiler fence that ensures that all stores to the - // mbox buffer are finished before the GPU is signaled (which is - // done by a store operation as well). - compiler_fence(Ordering::Release); - - // send the message to the GPU and receive answer - let serial_avail = match mbox.call(mbox::channel::PROP) { - Err(_) => false, - Ok(()) => true, - }; - - if serial_avail { - uart.puts("[i] My serial number is: 0x"); - uart.hex(mbox.buffer[6]); - uart.hex(mbox.buffer[5]); - uart.puts("\n"); - } else { - uart.puts("[i] Unable to query serial!\n"); - } - - // echo everything back - loop { - uart.send(uart.getc()); - } -} - -raspi3_boot::entry!(kernel_entry); diff --git a/.05_uart0/src/mbox.rs b/.05_uart0/src/mbox.rs deleted file mode 100644 index daff3771..00000000 --- a/.05_uart0/src/mbox.rs +++ /dev/null @@ -1,162 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2018 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -use super::MMIO_BASE; -use core::ops; -use register::{ - mmio::{ReadOnly, WriteOnly}, - register_bitfields, -}; - -register_bitfields! { - u32, - - STATUS [ - FULL OFFSET(31) NUMBITS(1) [], - EMPTY OFFSET(30) NUMBITS(1) [] - ] -} - -const VIDEOCORE_MBOX: u32 = MMIO_BASE + 0xB880; - -#[allow(non_snake_case)] -#[repr(C)] -pub struct RegisterBlock { - READ: ReadOnly, // 0x00 - __reserved_0: [u32; 5], // 0x04 - STATUS: ReadOnly, // 0x18 - __reserved_1: u32, // 0x1C - WRITE: WriteOnly, // 0x20 -} - -// Custom errors -pub enum MboxError { - ResponseError, - UnknownError, -} -pub type Result = ::core::result::Result; - -// Channels -pub mod channel { - pub const PROP: u32 = 8; -} - -// Tags -pub mod tag { - pub const GETSERIAL: u32 = 0x10004; - pub const SETCLKRATE: u32 = 0x38002; - pub const LAST: u32 = 0; -} - -// Clocks -pub mod clock { - pub const UART: u32 = 0x0_0000_0002; -} - -// Responses -mod response { - pub const SUCCESS: u32 = 0x8000_0000; - pub const ERROR: u32 = 0x8000_0001; // error parsing request buffer (partial response) -} - -pub const REQUEST: u32 = 0; - -// Public interface to the mailbox -#[repr(C)] -#[repr(align(16))] -pub struct Mbox { - // The address for buffer needs to be 16-byte aligned so that the - // Videcore can handle it properly. - pub buffer: [u32; 36], -} - -/// Deref to RegisterBlock -/// -/// Allows writing -/// ``` -/// self.STATUS.read() -/// ``` -/// instead of something along the lines of -/// ``` -/// unsafe { (*Mbox::ptr()).STATUS.read() } -/// ``` -impl ops::Deref for Mbox { - type Target = RegisterBlock; - - fn deref(&self) -> &Self::Target { - unsafe { &*Self::ptr() } - } -} - -impl Mbox { - pub fn new() -> Mbox { - Mbox { buffer: [0; 36] } - } - - /// Returns a pointer to the register block - fn ptr() -> *const RegisterBlock { - VIDEOCORE_MBOX as *const _ - } - - /// Make a mailbox call. Returns Err(MboxError) on failure, Ok(()) success - pub fn call(&self, channel: u32) -> Result<()> { - // wait until we can write to the mailbox - loop { - if !self.STATUS.is_set(STATUS::FULL) { - break; - } - - unsafe { asm!("nop" :::: "volatile") }; - } - - let buf_ptr = self.buffer.as_ptr() as u32; - - // write the address of our message to the mailbox with channel identifier - self.WRITE.set((buf_ptr & !0xF) | (channel & 0xF)); - - // now wait for the response - loop { - // is there a response? - loop { - if !self.STATUS.is_set(STATUS::EMPTY) { - break; - } - - unsafe { asm!("nop" :::: "volatile") }; - } - - let resp: u32 = self.READ.get(); - - // is it a response to our message? - if ((resp & 0xF) == channel) && ((resp & !0xF) == buf_ptr) { - // is it a valid successful response? - return match self.buffer[1] { - response::SUCCESS => Ok(()), - response::ERROR => Err(MboxError::ResponseError), - _ => Err(MboxError::UnknownError), - }; - } - } - } -} diff --git a/.05_uart0/src/uart.rs b/.05_uart0/src/uart.rs deleted file mode 100644 index 722cb034..00000000 --- a/.05_uart0/src/uart.rs +++ /dev/null @@ -1,285 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2018 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -use super::MMIO_BASE; -use crate::gpio; -use crate::mbox; -use core::{ - ops, - sync::atomic::{compiler_fence, Ordering}, -}; -use register::{mmio::*, register_bitfields}; - -// PL011 UART registers. -// -// Descriptions taken from -// https://github.com/raspberrypi/documentation/files/1888662/BCM2837-ARM-Peripherals.-.Revised.-.V2-1.pdf -register_bitfields! { - u32, - - /// Flag Register - FR [ - /// Transmit FIFO full. The meaning of this bit depends on the - /// state of the FEN bit in the UARTLCR_ LCRH 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 UARTLCR_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) [] - ], - - /// Integer Baud rate divisor - IBRD [ - /// Integer Baud rate divisor - IBRD OFFSET(0) NUMBITS(16) [] - ], - - /// Fractional Baud rate divisor - FBRD [ - /// Fractional Baud rate divisor - FBRD OFFSET(0) NUMBITS(6) [] - ], - - /// Line Control register - LCRH [ - /// Word length. These bits indicate the number of data bits - /// transmitted or received in a frame. - WLEN OFFSET(5) NUMBITS(2) [ - FiveBit = 0b00, - SixBit = 0b01, - SevenBit = 0b10, - EightBit = 0b11 - ] - ], - - /// Control Register - CR [ - /// Receive enable. If this bit is set to 1, the receive - /// section of the UART is enabled. Data reception occurs for - /// UART signals. 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 UART signals. 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 - 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 - ] - ], - - /// Interupt Clear Register - ICR [ - /// Meta field for all pending interrupts - ALL OFFSET(0) NUMBITS(11) [] - ] -} - -const UART_BASE: u32 = MMIO_BASE + 0x20_1000; - -#[allow(non_snake_case)] -#[repr(C)] -pub struct RegisterBlock { - DR: ReadWrite, // 0x00 - __reserved_0: [u32; 5], // 0x04 - FR: ReadOnly, // 0x18 - __reserved_1: [u32; 2], // 0x1c - IBRD: WriteOnly, // 0x24 - FBRD: WriteOnly, // 0x28 - LCRH: WriteOnly, // 0x2C - CR: WriteOnly, // 0x30 - __reserved_2: [u32; 4], // 0x34 - ICR: WriteOnly, // 0x44 -} - -pub enum UartError { - MailboxError, -} -pub type Result = ::core::result::Result; - -pub struct Uart; - -impl ops::Deref for Uart { - type Target = RegisterBlock; - - fn deref(&self) -> &Self::Target { - unsafe { &*Self::ptr() } - } -} - -impl Uart { - pub fn new() -> Uart { - Uart - } - - /// Returns a pointer to the register block - fn ptr() -> *const RegisterBlock { - UART_BASE as *const _ - } - - ///Set baud rate and characteristics (115200 8N1) and map to GPIO - pub fn init(&self, mbox: &mut mbox::Mbox) -> Result<()> { - // turn off UART0 - self.CR.set(0); - - // set up clock for consistent divisor values - mbox.buffer[0] = 9 * 4; - mbox.buffer[1] = mbox::REQUEST; - mbox.buffer[2] = mbox::tag::SETCLKRATE; - mbox.buffer[3] = 12; - mbox.buffer[4] = 8; - mbox.buffer[5] = mbox::clock::UART; // UART clock - mbox.buffer[6] = 4_000_000; // 4Mhz - mbox.buffer[7] = 0; // skip turbo setting - mbox.buffer[8] = mbox::tag::LAST; - - // Insert a compiler fence that ensures that all stores to the - // mbox buffer are finished before the GPU is signaled (which - // is done by a store operation as well). - compiler_fence(Ordering::Release); - - if mbox.call(mbox::channel::PROP).is_err() { - return Err(UartError::MailboxError); // Abort if UART clocks couldn't be set - }; - - // map UART0 to GPIO pins - unsafe { - (*gpio::GPFSEL1).modify(gpio::GPFSEL1::FSEL14::TXD0 + gpio::GPFSEL1::FSEL15::RXD0); - - (*gpio::GPPUD).set(0); // enable pins 14 and 15 - for _ in 0..150 { - asm!("nop" :::: "volatile"); - } - - (*gpio::GPPUDCLK0).write( - gpio::GPPUDCLK0::PUDCLK14::AssertClock + gpio::GPPUDCLK0::PUDCLK15::AssertClock, - ); - for _ in 0..150 { - asm!("nop" :::: "volatile"); - } - - (*gpio::GPPUDCLK0).set(0); - } - - self.ICR.write(ICR::ALL::CLEAR); - self.IBRD.write(IBRD::IBRD.val(2)); // Results in 115200 baud - self.FBRD.write(FBRD::FBRD.val(0xB)); - self.LCRH.write(LCRH::WLEN::EightBit); // 8N1 - self.CR - .write(CR::UARTEN::Enabled + CR::TXE::Enabled + CR::RXE::Enabled); - - Ok(()) - } - - /// Send a character - pub fn send(&self, c: char) { - // wait until we can send - loop { - if !self.FR.is_set(FR::TXFF) { - break; - } - - unsafe { asm!("nop" :::: "volatile") }; - } - - // write the character to the buffer - self.DR.set(c as u32); - } - - /// Receive a character - pub fn getc(&self) -> char { - // wait until something is in the buffer - loop { - if !self.FR.is_set(FR::RXFE) { - break; - } - - unsafe { asm!("nop" :::: "volatile") }; - } - - // read it and return - let mut ret = self.DR.get() as u8 as char; - - // convert carrige return to newline - if ret == '\r' { - ret = '\n' - } - - ret - } - - /// Display a string - pub fn puts(&self, string: &str) { - for c in string.chars() { - // convert newline to carrige return + newline - if c == '\n' { - self.send('\r') - } - - self.send(c); - } - } - - /// Display a binary value in hexadecimal - pub fn hex(&self, d: u32) { - let mut n; - - for i in 0..8 { - // get highest tetrad - n = d.wrapping_shr(28 - i * 4) & 0xF; - - // 0-9 => '0'-'9', 10-15 => 'A'-'F' - // Add proper offset for ASCII table - if n > 9 { - n += 0x37; - } else { - n += 0x30; - } - - self.send(n as u8 as char); - } - } -} diff --git a/.06_raspbootin64/.cargo/config b/.06_raspbootin64/.cargo/config deleted file mode 100644 index c8c5ae10..00000000 --- a/.06_raspbootin64/.cargo/config +++ /dev/null @@ -1,6 +0,0 @@ -[target.aarch64-unknown-none-softfloat] -rustflags = [ - "-C", "link-arg=-Tlink.ld", - "-C", "target-cpu=cortex-a53", - "-C", "relocation-model=pic", -] diff --git a/.06_raspbootin64/Cargo.lock b/.06_raspbootin64/Cargo.lock deleted file mode 100644 index 82ecd2c6..00000000 --- a/.06_raspbootin64/Cargo.lock +++ /dev/null @@ -1,46 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -[[package]] -name = "kernel8" -version = "0.1.0" -dependencies = [ - "raspi3_boot 0.1.0", - "register 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "panic-abort" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "r0" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "raspi3_boot" -version = "0.1.0" -dependencies = [ - "panic-abort 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "r0 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "register" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "tock-registers 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tock-registers" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[metadata] -"checksum panic-abort 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2c14a66511ed17b6a8b4256b868d7fd207836d891db15eea5195dbcaf87e630f" -"checksum r0 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e2a38df5b15c8d5c7e8654189744d8e396bddc18ad48041a500ce52d6948941f" -"checksum register 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "469bb5ddde81d67fb8bba4e14d77689b8166cfd077abe7530591cefe29d05823" -"checksum tock-registers 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c758f5195a2e0df9d9fecf6f506506b2766ff74cf64db1e995c87e2761a5c3e2" diff --git a/.06_raspbootin64/Cargo.toml b/.06_raspbootin64/Cargo.toml deleted file mode 100644 index 38cac1c9..00000000 --- a/.06_raspbootin64/Cargo.toml +++ /dev/null @@ -1,12 +0,0 @@ -[package] -name = "kernel8" -version = "0.1.0" -authors = ["Andre Richter "] -edition = "2018" - -[dependencies] -raspi3_boot = { path = "raspi3_boot" } -register = "0.3.3" - -[package.metadata.cargo-xbuild] -sysroot_path = "../xbuild_sysroot/pic" diff --git a/.06_raspbootin64/Makefile b/.06_raspbootin64/Makefile deleted file mode 100644 index d1723093..00000000 --- a/.06_raspbootin64/Makefile +++ /dev/null @@ -1,68 +0,0 @@ -# -# MIT License -# -# Copyright (c) 2018-2019 Andre Richter -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# - -TARGET = aarch64-unknown-none-softfloat - -SOURCES = $(wildcard **/*.rs) $(wildcard **/*.S) link.ld - - -XRUSTC_CMD = cargo xrustc --target=$(TARGET) --release -CARGO_OUTPUT = target/$(TARGET)/release/kernel8 - -OBJCOPY = cargo objcopy -- -OBJCOPY_PARAMS = --strip-all -O binary - -CONTAINER_UTILS = andrerichter/raspi3-utils - -DOCKER_CMD = docker run -it --rm -DOCKER_ARG_CURDIR = -v $(shell pwd):/work -w /work - -DOCKER_EXEC_QEMU = qemu-system-aarch64 -M raspi3 -kernel kernel8.img - -.PHONY: all qemu clippy clean objdump nm - -all: clean kernel8.img - -$(CARGO_OUTPUT): $(SOURCES) - $(XRUSTC_CMD) - -kernel8.img: $(CARGO_OUTPUT) - cp $< . - $(OBJCOPY) $(OBJCOPY_PARAMS) $< kernel8.img - -qemu: all - $(DOCKER_CMD) $(DOCKER_ARG_CURDIR) $(CONTAINER_UTILS) \ - $(DOCKER_EXEC_QEMU) -serial stdio - -clippy: - cargo xclippy --target=$(TARGET) - -clean: - cargo clean - -objdump: - cargo objdump --target $(TARGET) -- -disassemble -print-imm-hex kernel8 - -nm: - cargo nm --target $(TARGET) -- kernel8 | sort diff --git a/.06_raspbootin64/README.md b/.06_raspbootin64/README.md deleted file mode 100644 index f7fd6034..00000000 --- a/.06_raspbootin64/README.md +++ /dev/null @@ -1,126 +0,0 @@ -# Tutorial 06 - Raspbootin64 - -We are now at a point where we have a running serial connection, but for each -new feature we want to try, we still have to write and exchange the SD card -every time. - -As this tends to get very annoying and also to avoid potential SD card damage, -we create a kernel8.img that will load the real kernel8.img over serial. - -This tutorial is a rewrite of the well known serial boot loader -[raspbootin][bootin] in 64-bit. We only provide one part of the loader, the -kernel receiver, which runs on the RPi. For the other part, the sender, which -runs on your PC, we will rely on the original [raspbootcom][bootcom] utility. - -[bootin]:(https://github.com/mrvn/raspbootin) -[bootcom]:(https://github.com/mrvn/raspbootin/blob/master/raspbootcom/raspbootcom.cc) - -For convenience, it is already packaged in our `raspi3-utils` docker -container. So if you are running a Linux host, it will be as easy as calling -another Makefile target. It will be included starting with the next tutorial, -`07_abstraction`. You can invoke it with: - -```sh -make raspboot -``` - -If you want to use it with earlier versions of this tutorial, here is a bash -command to invoke it: - -```sh -docker run -it --rm \ - --privileged -v /dev/:/dev/ \ - -v $PWD:/work -w /work \ - raspi3-utils \ - raspbootcom /dev/ttyUSB0 kernel8.img -``` - -In any case, if your USB device is enumerated differently, adapt accordingly. - -If you want to send kernels from a Windows machine, I suggest to take a look at -John Cronin's rewrite, [raspbootin-server][w32] which can be compiled for the -Win32 API. Even more, [@milanvidakovic](https://github.com/milanvidakovic) was -so kind to share a [Java version][java] of the kernel sender with you. - -[w32]:(https://github.com/jncronin/rpi-boot/blob/master/raspbootin-server.c) -[java]:(https://github.com/milanvidakovic/Raspbootin64Client) - -## Chain Loading - -In order to load the new kernel to the same address, we have to move ourself out -of the way. It's called `chain loading`: One code loads the next code to the -same position in memory, therefore the latter thinks it was loaded by the -firmware. To implement that, we use a different linking address this time (we -subtract `2048` from the original address). You can check that with: - -```console -ferris@box:~$ cargo nm -- kernel8 | grep _boot_cores -000000000007f800 T _boot_cores -``` - -However, since the GPU loads us to `0x80_000` regardless, as a first action in -our binary, we have to copy our code to that link address. This is added to -`boot_cores.S`: - -```asm - // relocate our code from load address to link address - ldr x1, =0x80000 - ldr x2, =_boot_cores //<- actual link addr (0x80000 - 2048) from link.ld - ldr w3, =__loader_size -3: ldr x4, [x1], #8 - str x4, [x2], #8 - sub w3, w3, #1 - cbnz w3, 3b -``` - -When we're done, the memory at `0x80_000` is free to use. - -We also should minimize the size of the loader, since it will be overwritten by -the newly loaded code anyway. By removing `Uart::puts()` and other functions, -we've managed to shrink the loader's size by some bytes. - -## Position Independent Code (PIC) - -For reasons stated above, our code will initially execute from address -`0x80_000` despite the binary being actually linked to `0x7f_800`. In order to -ensure that our binary will not reference hardcoded addresses that actually -contain no or wrong data, we need to make this binary `position -independent`. This means that all addresses will always be runtime-computable as -an offset to the current `Program Counter`, and not hardcoded. - -To enable PIC for our loader, we add the following line to the compiler flags in -the`.cargo/config`: - -```toml -[target.aarch64-unknown-none-softfloat] -rustflags = [ - "-C", "link-arg=-Tlink.ld", - "-C", "target-cpu=cortex-a53", - "-C", "relocation-model=pic", # <-- New -] -``` - -## boot_cores.S - -In addition to the relocation copying, we also need to adjust the branch -instruction that jumps to the reset handler, because we want to jump to _the -relocated reset handler_, not the original one. - -Since rustc now generates jumps relative to the current instruction due to the -`position independence`, we can leverage this feature and add the same offset -to the reset address that we implicitly used for the relocation copying (`2048`). -This ensures that we jump to the reset handler _in the relocated loader code_. - -## Linker and Boot Code - -We use a different linking address this time. We calculate our code's size to -know how many bytes we have to copy. - -Additionally, we can remove the `bss section` entirely, since our loader does -not use any static variables. - -## main.rs - -We print 'RBIN64', receive the new kernel over serial and save it at the memory -address where the start.elf would have been loaded it. When finished, we restore -the arguments and jump to the new kernel using an absolute address. diff --git a/.06_raspbootin64/kernel8 b/.06_raspbootin64/kernel8 deleted file mode 100755 index 23dda14c86c54226e5b82c2f7e1fdaa626187131..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 66560 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 S&7bP^SaVZD;e(A0YlOcY1IfVv diff --git a/.06_raspbootin64/link.ld b/.06_raspbootin64/link.ld deleted file mode 100644 index 90ad85e4..00000000 --- a/.06_raspbootin64/link.ld +++ /dev/null @@ -1,51 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2018 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -ENTRY(_boot_cores); - -SECTIONS -{ - . = 0x80000 - 2048; - - _code = .; - .text : - { - KEEP(*(.text.boot)) *(.text .text.*) - } - - .rodata : - { - *(.rodata .rodata.*) - } - - .data : - { - *(.data .data.*) - } - _end = .; - - /DISCARD/ : { *(.comment) *(.gnu*) *(.note*) *(.eh_frame*) } -} - -__loader_size = (_end - _code) >> 3; diff --git a/.06_raspbootin64/raspi3_boot/Cargo.toml b/.06_raspbootin64/raspi3_boot/Cargo.toml deleted file mode 100644 index 1c3c1c69..00000000 --- a/.06_raspbootin64/raspi3_boot/Cargo.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "raspi3_boot" -version = "0.1.0" -authors = ["Andre Richter "] -edition = "2018" - -[dependencies] -panic-abort = "0.3.1" -r0 = "0.2.2" diff --git a/.06_raspbootin64/raspi3_boot/src/boot_cores.S b/.06_raspbootin64/raspi3_boot/src/boot_cores.S deleted file mode 100644 index e1a7fa55..00000000 --- a/.06_raspbootin64/raspi3_boot/src/boot_cores.S +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (C) 2018 bzt (bztsrc@github) - * Copyright (c) 2018 Andre Richter - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - * - */ - -.section ".text.boot" - -.global _boot_cores - -_boot_cores: - // read cpu id, stop slave cores - mrs x1, mpidr_el1 - and x1, x1, #3 - cbz x1, 2f - // cpu id > 0, stop -1: wfe - b 1b -2: // cpu id == 0 - - // relocate our code from load address to link address - ldr x1, =0x80000 - ldr x2, =_boot_cores - ldr w3, =__loader_size -3: ldr x4, [x1], #8 - str x4, [x2], #8 - sub w3, w3, #1 - cbnz w3, 3b - - // set stack before our code - ldr x1, =_boot_cores - mov sp, x1 - - // jump to relocated Rust code, should not return - bl reset-2048 - // for failsafe, halt this core too - b 1b diff --git a/.06_raspbootin64/raspi3_boot/src/lib.rs b/.06_raspbootin64/raspi3_boot/src/lib.rs deleted file mode 100644 index 2e29dceb..00000000 --- a/.06_raspbootin64/raspi3_boot/src/lib.rs +++ /dev/null @@ -1,70 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2018 Jorge Aparicio - * Copyright (c) 2018-2019 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#![deny(missing_docs)] -#![deny(warnings)] -#![no_std] -#![feature(global_asm)] - -//! Low-level boot of the Raspberry's processor - -extern crate panic_abort; - -/// Type check the user-supplied entry function. -#[macro_export] -macro_rules! entry { - ($path:path) => { - /// # Safety - /// - /// - User must ensure to provide a suitable main function for the - /// platform. - #[export_name = "main"] - pub unsafe fn __main() -> ! { - // type check the given path - let f: fn() -> ! = $path; - - f() - } - }; -} - -/// Reset function. -/// -/// Trampolines into the user's `main()`. -/// -/// # Safety -/// -/// - Only a single core must be active and running this function. -#[no_mangle] -pub unsafe extern "C" fn reset() -> ! { - extern "Rust" { - fn main() -> !; - } - - main(); -} - -// Disable all cores except core 0, and then jump to reset() -global_asm!(include_str!("boot_cores.S")); diff --git a/.06_raspbootin64/src/gpio.rs b/.06_raspbootin64/src/gpio.rs deleted file mode 100644 index da6a5be4..00000000 --- a/.06_raspbootin64/src/gpio.rs +++ /dev/null @@ -1,75 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2018 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -use super::MMIO_BASE; -use register::{mmio::ReadWrite, register_bitfields}; - -// Descriptions taken from -// https://github.com/raspberrypi/documentation/files/1888662/BCM2837-ARM-Peripherals.-.Revised.-.V2-1.pdf -register_bitfields! { - u32, - - /// GPIO Function Select 1 - GPFSEL1 [ - /// Pin 15 - FSEL15 OFFSET(15) NUMBITS(3) [ - Input = 0b000, - Output = 0b001, - RXD0 = 0b100, // UART0 - Alternate function 0 - RXD1 = 0b010 // Mini UART - Alternate function 5 - - ], - - /// Pin 14 - FSEL14 OFFSET(12) NUMBITS(3) [ - Input = 0b000, - Output = 0b001, - TXD0 = 0b100, // UART0 - Alternate function 0 - TXD1 = 0b010 // Mini UART - Alternate function 5 - ] - ], - - /// GPIO Pull-up/down Clock Register 0 - GPPUDCLK0 [ - /// Pin 15 - PUDCLK15 OFFSET(15) NUMBITS(1) [ - NoEffect = 0, - AssertClock = 1 - ], - - /// Pin 14 - PUDCLK14 OFFSET(14) NUMBITS(1) [ - NoEffect = 0, - AssertClock = 1 - ] - ] -} - -pub const GPFSEL1: *const ReadWrite = - (MMIO_BASE + 0x0020_0004) as *const ReadWrite; - -pub const GPPUD: *const ReadWrite = (MMIO_BASE + 0x0020_0094) as *const ReadWrite; - -pub const GPPUDCLK0: *const ReadWrite = - (MMIO_BASE + 0x0020_0098) as *const ReadWrite; diff --git a/.06_raspbootin64/src/main.rs b/.06_raspbootin64/src/main.rs deleted file mode 100644 index ff0bb94e..00000000 --- a/.06_raspbootin64/src/main.rs +++ /dev/null @@ -1,79 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2018 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#![no_std] -#![no_main] -#![feature(asm)] - -const MMIO_BASE: u32 = 0x3F00_0000; - -mod gpio; -mod mbox; -mod uart; - -fn kernel_entry() -> ! { - let mut mbox = mbox::Mbox::new(); - let uart = uart::Uart::new(); - - // set up serial console - if uart.init(&mut mbox).is_err() { - unsafe { asm!("wfe" :::: "volatile") }; // If UART fails, abort early - } - - // Say hello - for c in "RBIN64\r\n".chars() { - uart.send(c); - } - - // Notify raspbootcom to send the kernel - uart.send(3 as char); - uart.send(3 as char); - uart.send(3 as char); - - // Read the kernel's size - let mut size: u32 = u32::from(uart.getc()); - size |= u32::from(uart.getc()) << 8; - size |= u32::from(uart.getc()) << 16; - size |= u32::from(uart.getc()) << 24; - - // For now, blindly trust it's not too big - uart.send('O'); - uart.send('K'); - - let kernel_addr: *mut u8 = 0x80_000 as *mut u8; - unsafe { - // Read the kernel byte by byte - for i in 0..size { - *kernel_addr.offset(i as isize) = uart.getc(); - } - } - - // Use black magic to get a function pointer to 0x80_000 - let kernel: extern "C" fn() -> ! = unsafe { core::mem::transmute(kernel_addr as *const ()) }; - - // Jump to loaded kernel and never return! - kernel() -} - -raspi3_boot::entry!(kernel_entry); diff --git a/.06_raspbootin64/src/mbox.rs b/.06_raspbootin64/src/mbox.rs deleted file mode 100644 index d6343bee..00000000 --- a/.06_raspbootin64/src/mbox.rs +++ /dev/null @@ -1,161 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2018 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -use super::MMIO_BASE; -use core::ops; -use register::{ - mmio::{ReadOnly, WriteOnly}, - register_bitfields, -}; - -register_bitfields! { - u32, - - STATUS [ - FULL OFFSET(31) NUMBITS(1) [], - EMPTY OFFSET(30) NUMBITS(1) [] - ] -} - -const VIDEOCORE_MBOX: u32 = MMIO_BASE + 0xB880; - -#[allow(non_snake_case)] -#[repr(C)] -pub struct RegisterBlock { - READ: ReadOnly, // 0x00 - __reserved_0: [u32; 5], // 0x04 - STATUS: ReadOnly, // 0x18 - __reserved_1: u32, // 0x1C - WRITE: WriteOnly, // 0x20 -} - -// Custom errors -pub enum MboxError { - ResponseError, - UnknownError, -} -pub type Result = ::core::result::Result; - -// Channels -pub mod channel { - pub const PROP: u32 = 8; -} - -// Tags -pub mod tag { - pub const SETCLKRATE: u32 = 0x38002; - pub const LAST: u32 = 0; -} - -// Clocks -pub mod clock { - pub const UART: u32 = 0x0_0000_0002; -} - -// Responses -mod response { - pub const SUCCESS: u32 = 0x8000_0000; - pub const ERROR: u32 = 0x8000_0001; // error parsing request buffer (partial response) -} - -pub const REQUEST: u32 = 0; - -// Public interface to the mailbox -#[repr(C)] -#[repr(align(16))] -pub struct Mbox { - // The address for buffer needs to be 16-byte aligned so that the - // Videcore can handle it properly. - pub buffer: [u32; 36], -} - -/// Deref to RegisterBlock -/// -/// Allows writing -/// ``` -/// self.STATUS.read() -/// ``` -/// instead of something along the lines of -/// ``` -/// unsafe { (*Mbox::ptr()).STATUS.read() } -/// ``` -impl ops::Deref for Mbox { - type Target = RegisterBlock; - - fn deref(&self) -> &Self::Target { - unsafe { &*Self::ptr() } - } -} - -impl Mbox { - pub fn new() -> Mbox { - Mbox { buffer: [0; 36] } - } - - /// Returns a pointer to the register block - fn ptr() -> *const RegisterBlock { - VIDEOCORE_MBOX as *const _ - } - - /// Make a mailbox call. Returns Err(MboxError) on failure, Ok(()) success - pub fn call(&self, channel: u32) -> Result<()> { - // wait until we can write to the mailbox - loop { - if !self.STATUS.is_set(STATUS::FULL) { - break; - } - - unsafe { asm!("nop" :::: "volatile") }; - } - - let buf_ptr = self.buffer.as_ptr() as u32; - - // write the address of our message to the mailbox with channel identifier - self.WRITE.set((buf_ptr & !0xF) | (channel & 0xF)); - - // now wait for the response - loop { - // is there a response? - loop { - if !self.STATUS.is_set(STATUS::EMPTY) { - break; - } - - unsafe { asm!("nop" :::: "volatile") }; - } - - let resp: u32 = self.READ.get(); - - // is it a response to our message? - if ((resp & 0xF) == channel) && ((resp & !0xF) == buf_ptr) { - // is it a valid successful response? - return match self.buffer[1] { - response::SUCCESS => Ok(()), - response::ERROR => Err(MboxError::ResponseError), - _ => Err(MboxError::UnknownError), - }; - } - } - } -} diff --git a/.06_raspbootin64/src/uart.rs b/.06_raspbootin64/src/uart.rs deleted file mode 100644 index 26b7a0b7..00000000 --- a/.06_raspbootin64/src/uart.rs +++ /dev/null @@ -1,246 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2018 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -use super::MMIO_BASE; -use crate::gpio; -use crate::mbox; -use core::{ - ops, - sync::atomic::{compiler_fence, Ordering}, -}; -use register::{mmio::*, register_bitfields}; - -// PL011 UART registers. -// -// Descriptions taken from -// https://github.com/raspberrypi/documentation/files/1888662/BCM2837-ARM-Peripherals.-.Revised.-.V2-1.pdf -register_bitfields! { - u32, - - /// Flag Register - FR [ - /// Transmit FIFO full. The meaning of this bit depends on the - /// state of the FEN bit in the UARTLCR_ LCRH 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 UARTLCR_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) [] - ], - - /// Integer Baud rate divisor - IBRD [ - /// Integer Baud rate divisor - IBRD OFFSET(0) NUMBITS(16) [] - ], - - /// Fractional Baud rate divisor - FBRD [ - /// Fractional Baud rate divisor - FBRD OFFSET(0) NUMBITS(6) [] - ], - - /// Line Control register - LCRH [ - /// Word length. These bits indicate the number of data bits - /// transmitted or received in a frame. - WLEN OFFSET(5) NUMBITS(2) [ - FiveBit = 0b00, - SixBit = 0b01, - SevenBit = 0b10, - EightBit = 0b11 - ] - ], - - /// Control Register - CR [ - /// Receive enable. If this bit is set to 1, the receive - /// section of the UART is enabled. Data reception occurs for - /// UART signals. 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 UART signals. 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 - 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 - ] - ], - - /// Interupt Clear Register - ICR [ - /// Meta field for all pending interrupts - ALL OFFSET(0) NUMBITS(11) [] - ] -} - -const UART_BASE: u32 = MMIO_BASE + 0x20_1000; - -#[allow(non_snake_case)] -#[repr(C)] -pub struct RegisterBlock { - DR: ReadWrite, // 0x00 - __reserved_0: [u32; 5], // 0x04 - FR: ReadOnly, // 0x18 - __reserved_1: [u32; 2], // 0x1c - IBRD: WriteOnly, // 0x24 - FBRD: WriteOnly, // 0x28 - LCRH: WriteOnly, // 0x2C - CR: WriteOnly, // 0x30 - __reserved_2: [u32; 4], // 0x34 - ICR: WriteOnly, // 0x44 -} - -pub enum UartError { - MailboxError, -} -pub type Result = ::core::result::Result; - -pub struct Uart; - -impl ops::Deref for Uart { - type Target = RegisterBlock; - - fn deref(&self) -> &Self::Target { - unsafe { &*Self::ptr() } - } -} - -impl Uart { - pub fn new() -> Uart { - Uart - } - - /// Returns a pointer to the register block - fn ptr() -> *const RegisterBlock { - UART_BASE as *const _ - } - - ///Set baud rate and characteristics (115200 8N1) and map to GPIO - pub fn init(&self, mbox: &mut mbox::Mbox) -> Result<()> { - // turn off UART0 - self.CR.set(0); - - // set up clock for consistent divisor values - mbox.buffer[0] = 9 * 4; - mbox.buffer[1] = mbox::REQUEST; - mbox.buffer[2] = mbox::tag::SETCLKRATE; - mbox.buffer[3] = 12; - mbox.buffer[4] = 8; - mbox.buffer[5] = mbox::clock::UART; // UART clock - mbox.buffer[6] = 4_000_000; // 4Mhz - mbox.buffer[7] = 0; // skip turbo setting - mbox.buffer[8] = mbox::tag::LAST; - - // Insert a compiler fence that ensures that all stores to the - // mbox buffer are finished before the GPU is signaled (which - // is done by a store operation as well). - compiler_fence(Ordering::Release); - - if mbox.call(mbox::channel::PROP).is_err() { - return Err(UartError::MailboxError); // Abort if UART clocks couldn't be set - }; - - // map UART0 to GPIO pins - unsafe { - (*gpio::GPFSEL1).modify(gpio::GPFSEL1::FSEL14::TXD0 + gpio::GPFSEL1::FSEL15::RXD0); - - (*gpio::GPPUD).set(0); // enable pins 14 and 15 - for _ in 0..150 { - asm!("nop" :::: "volatile"); - } - - (*gpio::GPPUDCLK0).modify( - gpio::GPPUDCLK0::PUDCLK14::AssertClock + gpio::GPPUDCLK0::PUDCLK15::AssertClock, - ); - for _ in 0..150 { - asm!("nop" :::: "volatile"); - } - - (*gpio::GPPUDCLK0).set(0); - } - - self.ICR.write(ICR::ALL::CLEAR); - self.IBRD.write(IBRD::IBRD.val(2)); // Results in 115200 baud - self.FBRD.write(FBRD::FBRD.val(0xB)); - self.LCRH.write(LCRH::WLEN::EightBit); // 8N1 - self.CR - .write(CR::UARTEN::Enabled + CR::TXE::Enabled + CR::RXE::Enabled); - - Ok(()) - } - - /// Send a character - pub fn send(&self, c: char) { - // wait until we can send - loop { - if !self.FR.is_set(FR::TXFF) { - break; - } - - unsafe { asm!("nop" :::: "volatile") }; - } - - // write the character to the buffer - self.DR.set(c as u32); - } - - /// Receive a character - pub fn getc(&self) -> u8 { - // wait until something is in the buffer - loop { - if !self.FR.is_set(FR::RXFE) { - break; - } - - unsafe { asm!("nop" :::: "volatile") }; - } - - // read it and return - self.DR.get() as u8 - } -} diff --git a/.07_abstraction/.cargo/config b/.07_abstraction/.cargo/config deleted file mode 100644 index de3f84c9..00000000 --- a/.07_abstraction/.cargo/config +++ /dev/null @@ -1,5 +0,0 @@ -[target.aarch64-unknown-none-softfloat] -rustflags = [ - "-C", "link-arg=-Tlink.ld", - "-C", "target-cpu=cortex-a53", -] diff --git a/.07_abstraction/Cargo.lock b/.07_abstraction/Cargo.lock deleted file mode 100644 index d218ad56..00000000 --- a/.07_abstraction/Cargo.lock +++ /dev/null @@ -1,57 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -[[package]] -name = "cortex-a" -version = "2.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "register 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "kernel8" -version = "0.1.0" -dependencies = [ - "cortex-a 2.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "raspi3_boot 0.1.0", - "register 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "panic-abort" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "r0" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "raspi3_boot" -version = "0.1.0" -dependencies = [ - "cortex-a 2.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "panic-abort 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "r0 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "register" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "tock-registers 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tock-registers" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[metadata] -"checksum cortex-a 2.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cbb16c411ab74044f174746a6cbae67bcdebea126e376b5441e5986e6a6aa950" -"checksum panic-abort 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2c14a66511ed17b6a8b4256b868d7fd207836d891db15eea5195dbcaf87e630f" -"checksum r0 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e2a38df5b15c8d5c7e8654189744d8e396bddc18ad48041a500ce52d6948941f" -"checksum register 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "469bb5ddde81d67fb8bba4e14d77689b8166cfd077abe7530591cefe29d05823" -"checksum tock-registers 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c758f5195a2e0df9d9fecf6f506506b2766ff74cf64db1e995c87e2761a5c3e2" diff --git a/.07_abstraction/Cargo.toml b/.07_abstraction/Cargo.toml deleted file mode 100644 index 43d1e22e..00000000 --- a/.07_abstraction/Cargo.toml +++ /dev/null @@ -1,13 +0,0 @@ -[package] -name = "kernel8" -version = "0.1.0" -authors = ["Andre Richter "] -edition = "2018" - -[dependencies] -raspi3_boot = { path = "raspi3_boot" } -cortex-a = "2.7.0" -register = "0.3.3" - -[package.metadata.cargo-xbuild] -sysroot_path = "../xbuild_sysroot" diff --git a/.07_abstraction/Makefile b/.07_abstraction/Makefile deleted file mode 100644 index 411b9bc3..00000000 --- a/.07_abstraction/Makefile +++ /dev/null @@ -1,77 +0,0 @@ -# -# MIT License -# -# Copyright (c) 2018-2019 Andre Richter -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# - -TARGET = aarch64-unknown-none-softfloat - -SOURCES = $(wildcard **/*.rs) $(wildcard **/*.S) link.ld - - -XRUSTC_CMD = cargo xrustc --target=$(TARGET) --release -CARGO_OUTPUT = target/$(TARGET)/release/kernel8 - -OBJCOPY = cargo objcopy -- -OBJCOPY_PARAMS = --strip-all -O binary - -CONTAINER_UTILS = andrerichter/raspi3-utils - -DOCKER_CMD = docker run -it --rm -DOCKER_ARG_CURDIR = -v $(shell pwd):/work -w /work -DOCKER_ARG_TTY = --privileged -v /dev:/dev - -DOCKER_EXEC_QEMU = qemu-system-aarch64 -M raspi3 -kernel kernel8.img -DOCKER_EXEC_RASPBOOT = raspbootcom -DOCKER_EXEC_RASPBOOT_DEV = /dev/ttyUSB0 -# DOCKER_EXEC_RASPBOOT_DEV = /dev/ttyACM0 - -.PHONY: all qemu raspboot clippy clean objdump nm - -all: clean kernel8.img - -$(CARGO_OUTPUT): $(SOURCES) - $(XRUSTC_CMD) - -kernel8.img: $(CARGO_OUTPUT) - cp $< . - $(OBJCOPY) $(OBJCOPY_PARAMS) $< kernel8.img - -qemu: all - $(DOCKER_CMD) $(DOCKER_ARG_CURDIR) $(CONTAINER_UTILS) \ - $(DOCKER_EXEC_QEMU) -serial stdio - -raspboot: all - $(DOCKER_CMD) $(DOCKER_ARG_CURDIR) $(DOCKER_ARG_TTY) \ - $(CONTAINER_UTILS) $(DOCKER_EXEC_RASPBOOT) $(DOCKER_EXEC_RASPBOOT_DEV) \ - kernel8.img - -clippy: - cargo xclippy --target=$(TARGET) - -clean: - cargo clean - -objdump: - cargo objdump --target $(TARGET) -- -disassemble -print-imm-hex kernel8 - -nm: - cargo nm --target $(TARGET) -- kernel8 | sort diff --git a/.07_abstraction/README.md b/.07_abstraction/README.md deleted file mode 100644 index 1b0517b4..00000000 --- a/.07_abstraction/README.md +++ /dev/null @@ -1,121 +0,0 @@ -# Tutorial 07 - Abstraction - -This is a short one regarding code changes, but has lots of text because two -important Rust principles are introduced: Abstraction and modularity. - -From a functional perspective, this tutorial is the same as `05_uart0`, but with -the key difference that we threw out all manually crafted assembler. Both the -main and the boot crate do not use `#![feature(global_asm)]` or -`#![feature(asm)]` anymore. Instead, we pulled in the [cortex-a][crate] crate, -which now provides `cortex-a` specific features like register access or safe -wrappers around assembly instructions. - -[crate]: https://github.com/andre-richter/cortex-a - -For single assembler instructions, we now have the `cortex-a::asm` namespace, -e.g. providing `asm::nop()`. - -For registers, there is `cortex-a::regs`. The interface is the same as we have -it for MMIO accesses, aka provided by [register-rs][register-rs] and therefore -based on [tock-regs][tock-regs]. For registers like the stack pointer, which are -generally read and written as a whole, there's the common [get()][get] and -[set()][set] functions which take and return primitive integer types. - -[register-rs]: https://github.com/rust-osdev/register-rs -[tock-regs]: https://github.com/tock/tock/tree/master/libraries/tock-register-interface -[get]: https://docs.rs/cortex-a/1.0.0/cortex_a/regs/sp/trait.RegisterReadWrite.html#tymethod.get -[set]: https://docs.rs/cortex-a/1.0.0/cortex_a/regs/sp/trait.RegisterReadWrite.html#tymethod.set - -Registers that are divided into multiple fields, like `CNTP_CTL_EL0`, on the -other hand, are backed by a respective [type][cntp_type] definition that allow -for fine-grained reading and modifications. - -[cntp_type]: https://docs.rs/cortex-a/1.0.0/cortex_a/regs/cntp_ctl_el0/CNTP_CTL_EL0/index.html - -The register API is based on the [tock project's][tock] register -interface. Please see [their homepage][tock_registers] for all the details. - -[tock]: https://github.com/tock/tock -[tock_registers]: https://github.com/tock/tock/tree/master/libraries/tock-register-interface - -To some extent, this namespacing also makes our code more portable. For example, -if we want to reuse parts of it on another processor architecture, we could pull -in the respective crate and change our use-clause from `use cortex-a::asm` to -`use new_architecture::asm`. Of course this also demands that both crates adhere -to a common set of wrappers that provide the same functionality. Assembler and -register instructions like we use them here are actually a weak example. Where -this modular approach can really pay off is for common peripherals like timers -or memory management units, where implementations differ between processors, but -usage is often the same (e.g. setting a timer for x amount of microseconds). - -In Rust, we have the [Embedded Devices Working -Group](https://github.com/rust-lang-nursery/embedded-wg), which among other -goals, tries to establish a common set of wrapper- and interface-crates that -introduce abstraction on different levels of the system. Check out the [Awesome -Embedded Rust](https://github.com/rust-embedded/awesome-embedded-rust) list for -an overview. - -## Boot Code - -Like mentioned above, we threw out the `boot_cores.S` assembler file and -replaced it with a Rust function. Why? Because we can, for the fun of it. - -```rust -#[link_section = ".text.boot"] -#[no_mangle] -pub unsafe extern "C" fn _boot_cores() -> ! { - use cortex_a::{asm, regs::*}; - - const CORE_0: u64 = 0; - const CORE_MASK: u64 = 0x3; - const STACK_START: u64 = 0x80_000; - - if CORE_0 == MPIDR_EL1.get() & CORE_MASK { - SP.set(STACK_START); - reset() - } else { - // if not core0, infinitely wait for events - loop { - asm::wfe(); - } - } -} -``` - -Since this is the first code that the RPi3 will execute, the stack has not been -set up yet. Actually it is this function that will do it for the first -time. Therefore, it is important to check that code generated from this function -does not call any subroutines that need a working stack themselves. - -The `get()` and `asm` wrappers that we use from the `cortex-a` crate are all -inlined, so we fulfill this requirement. The compilation result of this function -should yield something like the following, where you can see that the stack -pointer is not used apart from ourselves setting it. - -```console -ferris@box:~$ cargo objdump --target aarch64-unknown-none-softfloat -- -disassemble -print-imm-hex kernel8 - -[...] (Some output omitted) - -_boot_cores: - 80000: a8 00 38 d5 mrs x8, MPIDR_EL1 - 80004: 1f 05 40 f2 tst x8, #0x3 - 80008: 60 00 00 54 b.eq #0xc <_boot_cores+0x14> - 8000c: 5f 20 03 d5 wfe - 80010: ff ff ff 17 b #-0x4 <_boot_cores+0xc> - 80014: e8 03 0d 32 orr w8, wzr, #0x80000 - 80018: 1f 01 00 91 mov sp, x8 - 8001c: e0 01 00 94 bl #0x780 -``` - -It is important to always manually check this, and not blindly rely on the -compiler. - -## Test it - -Since this is the first tutorial after we've written our own bootloader over -serial, you can now for the first time test this convenient interface: - -```sh -make raspboot -``` diff --git a/.07_abstraction/kernel8 b/.07_abstraction/kernel8 deleted file mode 100755 index ea343760b6e6aa9d6a336e074176bce9bdfdc134..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 69864 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

n9_CB&2(uQ__xC03{s)Fqh+ z{eIs$-#NcdlJk~a)-vBka;+KyMk*k}XEvh6K#w5g4)1Mc^8Q@s%4+C;P zE$6;P%*VH+&6NgM2At=43NTGFG(CbQh98a{P1$_5JXcJJs%FzU)jWMM{1x7fQ}m`0 zd<`@)FL6;-vZ3D5o)GT`aK`wWW`Tnr; zd##PeZZ5bu&AcY2`p{b=7riMdBdQrbj-%gk^tqif^U1XnVJrN|4)R)7;F9n!ZG|^G z6w(?SIIUTs^lhBkj`QT9!$luhY@Z%uKKS6l^%WjmN4^>!yaG&4ukrd*Juu}x@U26xhkhdQFC^1kG9}y)gE?Uo6HEuepT>pX>6(I zJLEaw(5pc~iv23U#f;obTNi^1$ym^m(2{FE_yR8O%|$usqLy!*7{0&vs#6(Yu!- z5+x)H=G%n%85TnAh_mx1@a?y@I2(~`x70f1YeMKVJx2n$-$rgfa#oymAHB&6=463G z#BNBHwT?wWvNLV1|K{8#;O^39~%g`p*Y3LZPq!4_xTM)MoZFE>i&eZOLwo#nJ z=C`naaW>b8pVH&(ZuuCR{lOX+%h|!%yqQ7+!5T-$$apQ=)%StDQ^LXG?A~Q@#xV{K z-%)d3iv*5!&>@3|=?NS)I}VME=Jgz3MGxksxMz7i2i8BS=fL`+o@F|r*}ICKS4;IYiBIZj5{r7at)l1oQayEsr|YRR6!plf=-E)Jr-G`U@T-CxF8F1E zFBQOEDe;TNMLo{^`UrlN-Vf|_Xe(@P|eNCGKO-_Zw-> zHYYo6o5^_rTr$Vcvj4Ys5`Pp)9K{_r$63fZg&gC$Is(TGnoC(d34p2hON zPthWaT?2mj@$!Fw)VcMD($T8A6@NtO^}pk_Nu4hqQ4WT^k%;0^0^XBKf1lFR7wq>3 z2fRvmUmqThH#IdWuZ6u{_8d{(^7i)jy{o7Lk$z8)*AoPV|A_MDNhRV9`#rr%aNtC@ cH;e;bR<^#E&vgVn-MwDM92)S33qYInKTX=@KmY&$ diff --git a/.07_abstraction/link.ld b/.07_abstraction/link.ld deleted file mode 100644 index 5c499f89..00000000 --- a/.07_abstraction/link.ld +++ /dev/null @@ -1,55 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2018 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -ENTRY(_boot_cores); - -SECTIONS -{ - . = 0x80000; - - .text : - { - KEEP(*(.text.boot)) *(.text .text.*) - } - - .rodata : - { - *(.rodata .rodata.*) - } - - .data : - { - *(.data .data.*) - } - - .bss ALIGN(8): - { - __bss_start = .; - *(.bss .bss.*) - *(COMMON) - __bss_end = .; - } - - /DISCARD/ : { *(.comment) *(.gnu*) *(.note*) *(.eh_frame*) } -} diff --git a/.07_abstraction/raspi3_boot/Cargo.toml b/.07_abstraction/raspi3_boot/Cargo.toml deleted file mode 100644 index 024fd184..00000000 --- a/.07_abstraction/raspi3_boot/Cargo.toml +++ /dev/null @@ -1,10 +0,0 @@ -[package] -name = "raspi3_boot" -version = "0.1.0" -authors = ["Andre Richter "] -edition = "2018" - -[dependencies] -cortex-a = "2.7.0" -panic-abort = "0.3.1" -r0 = "0.2.2" diff --git a/.07_abstraction/raspi3_boot/src/lib.rs b/.07_abstraction/raspi3_boot/src/lib.rs deleted file mode 100644 index a6b59ef1..00000000 --- a/.07_abstraction/raspi3_boot/src/lib.rs +++ /dev/null @@ -1,102 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2018 Jorge Aparicio - * Copyright (c) 2018-2019 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#![deny(missing_docs)] -#![deny(warnings)] -#![no_std] - -//! Low-level boot of the Raspberry's processor - -extern crate panic_abort; - -/// Type check the user-supplied entry function. -#[macro_export] -macro_rules! entry { - ($path:path) => { - /// # Safety - /// - /// - User must ensure to provide a suitable main function for the - /// platform. - #[export_name = "main"] - pub unsafe fn __main() -> ! { - // type check the given path - let f: fn() -> ! = $path; - - f() - } - }; -} - -/// Reset function. -/// -/// Initializes the bss section before calling into the user's `main()`. -/// -/// # Safety -/// -/// - Only a single core must be active and running this function. -unsafe fn reset() -> ! { - extern "C" { - // Boundaries of the .bss section, provided by the linker script - static mut __bss_start: u64; - static mut __bss_end: u64; - } - - // Zeroes the .bss section - r0::zero_bss(&mut __bss_start, &mut __bss_end); - - extern "Rust" { - fn main() -> !; - } - - main(); -} - -/// Entrypoint of the processor. -/// -/// Parks all cores except core0, and then jumps to the internal -/// `reset()` function. -/// -/// # Safety -/// -/// - Linker script must ensure to place this function at `0x80_000`. -#[link_section = ".text.boot"] -#[no_mangle] -pub unsafe extern "C" fn _boot_cores() -> ! { - use cortex_a::{asm, regs::*}; - - const CORE_0: u64 = 0; - const CORE_MASK: u64 = 0x3; - const STACK_START: u64 = 0x80_000; - - if CORE_0 == MPIDR_EL1.get() & CORE_MASK { - SP.set(STACK_START); - reset() - } else { - // if not core0, infinitely wait for events - loop { - asm::wfe(); - } - } -} diff --git a/.07_abstraction/src/gpio.rs b/.07_abstraction/src/gpio.rs deleted file mode 100644 index da6a5be4..00000000 --- a/.07_abstraction/src/gpio.rs +++ /dev/null @@ -1,75 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2018 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -use super::MMIO_BASE; -use register::{mmio::ReadWrite, register_bitfields}; - -// Descriptions taken from -// https://github.com/raspberrypi/documentation/files/1888662/BCM2837-ARM-Peripherals.-.Revised.-.V2-1.pdf -register_bitfields! { - u32, - - /// GPIO Function Select 1 - GPFSEL1 [ - /// Pin 15 - FSEL15 OFFSET(15) NUMBITS(3) [ - Input = 0b000, - Output = 0b001, - RXD0 = 0b100, // UART0 - Alternate function 0 - RXD1 = 0b010 // Mini UART - Alternate function 5 - - ], - - /// Pin 14 - FSEL14 OFFSET(12) NUMBITS(3) [ - Input = 0b000, - Output = 0b001, - TXD0 = 0b100, // UART0 - Alternate function 0 - TXD1 = 0b010 // Mini UART - Alternate function 5 - ] - ], - - /// GPIO Pull-up/down Clock Register 0 - GPPUDCLK0 [ - /// Pin 15 - PUDCLK15 OFFSET(15) NUMBITS(1) [ - NoEffect = 0, - AssertClock = 1 - ], - - /// Pin 14 - PUDCLK14 OFFSET(14) NUMBITS(1) [ - NoEffect = 0, - AssertClock = 1 - ] - ] -} - -pub const GPFSEL1: *const ReadWrite = - (MMIO_BASE + 0x0020_0004) as *const ReadWrite; - -pub const GPPUD: *const ReadWrite = (MMIO_BASE + 0x0020_0094) as *const ReadWrite; - -pub const GPPUDCLK0: *const ReadWrite = - (MMIO_BASE + 0x0020_0098) as *const ReadWrite; diff --git a/.07_abstraction/src/main.rs b/.07_abstraction/src/main.rs deleted file mode 100644 index 937b662d..00000000 --- a/.07_abstraction/src/main.rs +++ /dev/null @@ -1,88 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2018 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#![no_std] -#![no_main] - -const MMIO_BASE: u32 = 0x3F00_0000; - -mod gpio; -mod mbox; -mod uart; - -use core::sync::atomic::{compiler_fence, Ordering}; - -fn kernel_entry() -> ! { - let mut mbox = mbox::Mbox::new(); - let uart = uart::Uart::new(); - - // set up serial console - match uart.init(&mut mbox) { - Ok(_) => uart.puts("\n[0] UART is live!\n"), - Err(_) => loop { - cortex_a::asm::wfe() // If UART fails, abort early - }, - } - - uart.puts("[1] Press a key to continue booting... "); - uart.getc(); - uart.puts("Greetings fellow Rustacean!\n"); - - // get the board's unique serial number with a mailbox call - mbox.buffer[0] = 8 * 4; // length of the message - mbox.buffer[1] = mbox::REQUEST; // this is a request message - mbox.buffer[2] = mbox::tag::GETSERIAL; // get serial number command - mbox.buffer[3] = 8; // buffer size - mbox.buffer[4] = 8; - mbox.buffer[5] = 0; // clear output buffer - mbox.buffer[6] = 0; - mbox.buffer[7] = mbox::tag::LAST; - - // Insert a compiler fence that ensures that all stores to the - // mbox buffer are finished before the GPU is signaled (which is - // done by a store operation as well). - compiler_fence(Ordering::Release); - - // send the message to the GPU and receive answer - let serial_avail = match mbox.call(mbox::channel::PROP) { - Err(_) => false, - Ok(()) => true, - }; - - if serial_avail { - uart.puts("[i] My serial number is: 0x"); - uart.hex(mbox.buffer[6]); - uart.hex(mbox.buffer[5]); - uart.puts("\n"); - } else { - uart.puts("[i] Unable to query serial!\n"); - } - - // echo everything back - loop { - uart.send(uart.getc()); - } -} - -raspi3_boot::entry!(kernel_entry); diff --git a/.07_abstraction/src/mbox.rs b/.07_abstraction/src/mbox.rs deleted file mode 100644 index 5b7e3589..00000000 --- a/.07_abstraction/src/mbox.rs +++ /dev/null @@ -1,163 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2018 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -use super::MMIO_BASE; -use core::ops; -use cortex_a::asm; -use register::{ - mmio::{ReadOnly, WriteOnly}, - register_bitfields, -}; - -register_bitfields! { - u32, - - STATUS [ - FULL OFFSET(31) NUMBITS(1) [], - EMPTY OFFSET(30) NUMBITS(1) [] - ] -} - -const VIDEOCORE_MBOX: u32 = MMIO_BASE + 0xB880; - -#[allow(non_snake_case)] -#[repr(C)] -pub struct RegisterBlock { - READ: ReadOnly, // 0x00 - __reserved_0: [u32; 5], // 0x04 - STATUS: ReadOnly, // 0x18 - __reserved_1: u32, // 0x1C - WRITE: WriteOnly, // 0x20 -} - -// Custom errors -pub enum MboxError { - ResponseError, - UnknownError, -} -pub type Result = ::core::result::Result; - -// Channels -pub mod channel { - pub const PROP: u32 = 8; -} - -// Tags -pub mod tag { - pub const GETSERIAL: u32 = 0x10004; - pub const SETCLKRATE: u32 = 0x38002; - pub const LAST: u32 = 0; -} - -// Clocks -pub mod clock { - pub const UART: u32 = 0x0_0000_0002; -} - -// Responses -mod response { - pub const SUCCESS: u32 = 0x8000_0000; - pub const ERROR: u32 = 0x8000_0001; // error parsing request buffer (partial response) -} - -pub const REQUEST: u32 = 0; - -// Public interface to the mailbox -#[repr(C)] -#[repr(align(16))] -pub struct Mbox { - // The address for buffer needs to be 16-byte aligned so that the - // Videcore can handle it properly. - pub buffer: [u32; 36], -} - -/// Deref to RegisterBlock -/// -/// Allows writing -/// ``` -/// self.STATUS.read() -/// ``` -/// instead of something along the lines of -/// ``` -/// unsafe { (*Mbox::ptr()).STATUS.read() } -/// ``` -impl ops::Deref for Mbox { - type Target = RegisterBlock; - - fn deref(&self) -> &Self::Target { - unsafe { &*Self::ptr() } - } -} - -impl Mbox { - pub fn new() -> Mbox { - Mbox { buffer: [0; 36] } - } - - /// Returns a pointer to the register block - fn ptr() -> *const RegisterBlock { - VIDEOCORE_MBOX as *const _ - } - - /// Make a mailbox call. Returns Err(MboxError) on failure, Ok(()) success - pub fn call(&self, channel: u32) -> Result<()> { - // wait until we can write to the mailbox - loop { - if !self.STATUS.is_set(STATUS::FULL) { - break; - } - - asm::nop(); - } - - let buf_ptr = self.buffer.as_ptr() as u32; - - // write the address of our message to the mailbox with channel identifier - self.WRITE.set((buf_ptr & !0xF) | (channel & 0xF)); - - // now wait for the response - loop { - // is there a response? - loop { - if !self.STATUS.is_set(STATUS::EMPTY) { - break; - } - - asm::nop(); - } - - let resp: u32 = self.READ.get(); - - // is it a response to our message? - if ((resp & 0xF) == channel) && ((resp & !0xF) == buf_ptr) { - // is it a valid successful response? - return match self.buffer[1] { - response::SUCCESS => Ok(()), - response::ERROR => Err(MboxError::ResponseError), - _ => Err(MboxError::UnknownError), - }; - } - } - } -} diff --git a/.07_abstraction/src/uart.rs b/.07_abstraction/src/uart.rs deleted file mode 100644 index db4c639a..00000000 --- a/.07_abstraction/src/uart.rs +++ /dev/null @@ -1,286 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2018 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -use super::MMIO_BASE; -use crate::gpio; -use crate::mbox; -use core::{ - ops, - sync::atomic::{compiler_fence, Ordering}, -}; -use cortex_a::asm; -use register::{mmio::*, register_bitfields}; - -// PL011 UART registers. -// -// Descriptions taken from -// https://github.com/raspberrypi/documentation/files/1888662/BCM2837-ARM-Peripherals.-.Revised.-.V2-1.pdf -register_bitfields! { - u32, - - /// Flag Register - FR [ - /// Transmit FIFO full. The meaning of this bit depends on the - /// state of the FEN bit in the UARTLCR_ LCRH 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 UARTLCR_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) [] - ], - - /// Integer Baud rate divisor - IBRD [ - /// Integer Baud rate divisor - IBRD OFFSET(0) NUMBITS(16) [] - ], - - /// Fractional Baud rate divisor - FBRD [ - /// Fractional Baud rate divisor - FBRD OFFSET(0) NUMBITS(6) [] - ], - - /// Line Control register - LCRH [ - /// Word length. These bits indicate the number of data bits - /// transmitted or received in a frame. - WLEN OFFSET(5) NUMBITS(2) [ - FiveBit = 0b00, - SixBit = 0b01, - SevenBit = 0b10, - EightBit = 0b11 - ] - ], - - /// Control Register - CR [ - /// Receive enable. If this bit is set to 1, the receive - /// section of the UART is enabled. Data reception occurs for - /// UART signals. 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 UART signals. 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 - 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 - ] - ], - - /// Interupt Clear Register - ICR [ - /// Meta field for all pending interrupts - ALL OFFSET(0) NUMBITS(11) [] - ] -} - -const UART_BASE: u32 = MMIO_BASE + 0x20_1000; - -#[allow(non_snake_case)] -#[repr(C)] -pub struct RegisterBlock { - DR: ReadWrite, // 0x00 - __reserved_0: [u32; 5], // 0x04 - FR: ReadOnly, // 0x18 - __reserved_1: [u32; 2], // 0x1c - IBRD: WriteOnly, // 0x24 - FBRD: WriteOnly, // 0x28 - LCRH: WriteOnly, // 0x2C - CR: WriteOnly, // 0x30 - __reserved_2: [u32; 4], // 0x34 - ICR: WriteOnly, // 0x44 -} - -pub enum UartError { - MailboxError, -} -pub type Result = ::core::result::Result; - -pub struct Uart; - -impl ops::Deref for Uart { - type Target = RegisterBlock; - - fn deref(&self) -> &Self::Target { - unsafe { &*Self::ptr() } - } -} - -impl Uart { - pub fn new() -> Uart { - Uart - } - - /// Returns a pointer to the register block - fn ptr() -> *const RegisterBlock { - UART_BASE as *const _ - } - - ///Set baud rate and characteristics (115200 8N1) and map to GPIO - pub fn init(&self, mbox: &mut mbox::Mbox) -> Result<()> { - // turn off UART0 - self.CR.set(0); - - // set up clock for consistent divisor values - mbox.buffer[0] = 9 * 4; - mbox.buffer[1] = mbox::REQUEST; - mbox.buffer[2] = mbox::tag::SETCLKRATE; - mbox.buffer[3] = 12; - mbox.buffer[4] = 8; - mbox.buffer[5] = mbox::clock::UART; // UART clock - mbox.buffer[6] = 4_000_000; // 4Mhz - mbox.buffer[7] = 0; // skip turbo setting - mbox.buffer[8] = mbox::tag::LAST; - - // Insert a compiler fence that ensures that all stores to the - // mbox buffer are finished before the GPU is signaled (which - // is done by a store operation as well). - compiler_fence(Ordering::Release); - - if mbox.call(mbox::channel::PROP).is_err() { - return Err(UartError::MailboxError); // Abort if UART clocks couldn't be set - }; - - // map UART0 to GPIO pins - unsafe { - (*gpio::GPFSEL1).modify(gpio::GPFSEL1::FSEL14::TXD0 + gpio::GPFSEL1::FSEL15::RXD0); - - (*gpio::GPPUD).set(0); // enable pins 14 and 15 - for _ in 0..150 { - asm::nop(); - } - - (*gpio::GPPUDCLK0).modify( - gpio::GPPUDCLK0::PUDCLK14::AssertClock + gpio::GPPUDCLK0::PUDCLK15::AssertClock, - ); - for _ in 0..150 { - asm::nop(); - } - - (*gpio::GPPUDCLK0).set(0); - } - - self.ICR.write(ICR::ALL::CLEAR); - self.IBRD.write(IBRD::IBRD.val(2)); // Results in 115200 baud - self.FBRD.write(FBRD::FBRD.val(0xB)); - self.LCRH.write(LCRH::WLEN::EightBit); // 8N1 - self.CR - .write(CR::UARTEN::Enabled + CR::TXE::Enabled + CR::RXE::Enabled); - - Ok(()) - } - - /// Send a character - pub fn send(&self, c: char) { - // wait until we can send - loop { - if !self.FR.is_set(FR::TXFF) { - break; - } - - asm::nop(); - } - - // write the character to the buffer - self.DR.set(c as u32); - } - - /// Receive a character - pub fn getc(&self) -> char { - // wait until something is in the buffer - loop { - if !self.FR.is_set(FR::RXFE) { - break; - } - - asm::nop(); - } - - // read it and return - let mut ret = self.DR.get() as u8 as char; - - // convert carrige return to newline - if ret == '\r' { - ret = '\n' - } - - ret - } - - /// Display a string - pub fn puts(&self, string: &str) { - for c in string.chars() { - // convert newline to carrige return + newline - if c == '\n' { - self.send('\r') - } - - self.send(c); - } - } - - /// Display a binary value in hexadecimal - pub fn hex(&self, d: u32) { - let mut n; - - for i in 0..8 { - // get highest tetrad - n = d.wrapping_shr(28 - i * 4) & 0xF; - - // 0-9 => '0'-'9', 10-15 => 'A'-'F' - // Add proper offset for ASCII table - if n > 9 { - n += 0x37; - } else { - n += 0x30; - } - - self.send(n as u8 as char); - } - } -} diff --git a/.08_random/.cargo/config b/.08_random/.cargo/config deleted file mode 100644 index de3f84c9..00000000 --- a/.08_random/.cargo/config +++ /dev/null @@ -1,5 +0,0 @@ -[target.aarch64-unknown-none-softfloat] -rustflags = [ - "-C", "link-arg=-Tlink.ld", - "-C", "target-cpu=cortex-a53", -] diff --git a/.08_random/Cargo.lock b/.08_random/Cargo.lock deleted file mode 100644 index d218ad56..00000000 --- a/.08_random/Cargo.lock +++ /dev/null @@ -1,57 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -[[package]] -name = "cortex-a" -version = "2.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "register 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "kernel8" -version = "0.1.0" -dependencies = [ - "cortex-a 2.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "raspi3_boot 0.1.0", - "register 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "panic-abort" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "r0" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "raspi3_boot" -version = "0.1.0" -dependencies = [ - "cortex-a 2.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "panic-abort 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "r0 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "register" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "tock-registers 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tock-registers" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[metadata] -"checksum cortex-a 2.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cbb16c411ab74044f174746a6cbae67bcdebea126e376b5441e5986e6a6aa950" -"checksum panic-abort 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2c14a66511ed17b6a8b4256b868d7fd207836d891db15eea5195dbcaf87e630f" -"checksum r0 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e2a38df5b15c8d5c7e8654189744d8e396bddc18ad48041a500ce52d6948941f" -"checksum register 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "469bb5ddde81d67fb8bba4e14d77689b8166cfd077abe7530591cefe29d05823" -"checksum tock-registers 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c758f5195a2e0df9d9fecf6f506506b2766ff74cf64db1e995c87e2761a5c3e2" diff --git a/.08_random/Cargo.toml b/.08_random/Cargo.toml deleted file mode 100644 index 43d1e22e..00000000 --- a/.08_random/Cargo.toml +++ /dev/null @@ -1,13 +0,0 @@ -[package] -name = "kernel8" -version = "0.1.0" -authors = ["Andre Richter "] -edition = "2018" - -[dependencies] -raspi3_boot = { path = "raspi3_boot" } -cortex-a = "2.7.0" -register = "0.3.3" - -[package.metadata.cargo-xbuild] -sysroot_path = "../xbuild_sysroot" diff --git a/.08_random/Makefile b/.08_random/Makefile deleted file mode 100644 index 12815149..00000000 --- a/.08_random/Makefile +++ /dev/null @@ -1,77 +0,0 @@ -# -# MIT License -# -# Copyright (c) 2018-2019 Andre Richter -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# - -TARGET = aarch64-unknown-none-softfloat - -SOURCES = $(wildcard **/*.rs) $(wildcard **/*.S) link.ld - - -XRUSTC_CMD = cargo xrustc --target=$(TARGET) --release -CARGO_OUTPUT = target/$(TARGET)/release/kernel8 - -OBJCOPY = cargo objcopy -- -OBJCOPY_PARAMS = --strip-all -O binary - -CONTAINER_UTILS = andrerichter/raspi3-utils - -DOCKER_CMD = docker run -it --rm -DOCKER_ARG_CURDIR = -v $(shell pwd):/work -w /work -DOCKER_ARG_TTY = --privileged -v /dev:/dev - -DOCKER_EXEC_QEMU = qemu-system-aarch64 -M raspi3 -kernel kernel8.img -DOCKER_EXEC_RASPBOOT = raspbootcom -DOCKER_EXEC_RASPBOOT_DEV = /dev/ttyUSB0 -# DOCKER_EXEC_RASPBOOT_DEV = /dev/ttyACM0 - -.PHONY: all qemu raspboot clippy clean objdump nm - -all: clean kernel8.img - -$(CARGO_OUTPUT): $(SOURCES) - $(XRUSTC_CMD) - -kernel8.img: $(CARGO_OUTPUT) - cp $< . - $(OBJCOPY) $(OBJCOPY_PARAMS) $< kernel8.img - -qemu: all - $(DOCKER_CMD) $(DOCKER_ARG_CURDIR) $(CONTAINER_UTILS) \ - $(DOCKER_EXEC_QEMU) -serial stdio - -raspboot: all - $(DOCKER_CMD) $(DOCKER_ARG_CURDIR) $(DOCKER_ARG_TTY) \ - $(CONTAINER_UTILS) $(DOCKER_EXEC_RASPBOOT) $(DOCKER_EXEC_RASPBOOT_DEV) \ - kernel8.img - -clippy: - cargo xclippy --target=$(TARGET) - -clean: - cargo clean - -objdump: - cargo objdump --target $(TARGET) -- -disassemble -print-imm-hex kernel8 - -nm: - cargo nm --target $(TARGET) -- kernel8 | sort diff --git a/.08_random/README.md b/.08_random/README.md deleted file mode 100644 index 5e7c98ba..00000000 --- a/.08_random/README.md +++ /dev/null @@ -1,19 +0,0 @@ -# Tutorial 08 - Hardware Random Number Generator - -This going to be an easy tutorial. We query a number from the (undocumented) -hardware random number generator. You can use this to implement a simple, but -accurate dice throw in any game. It is important as without hardware support you -can only generate pseudo-random numbers. - -## rand.s - -Due to lack of documentation, we [mimic the respective Linux driver](https://github.com/torvalds/linux/blob/master/drivers/char/hw_random/bcm2835-rng.c). - -`Rng::init(&self)` initializes the hardware. - -`Rng::rand(&self, min: u32, max: u32)` returns a random number between min and -max. - -## main.rs - -Press a key to query a random value and then display it on the serial console. diff --git a/.08_random/kernel8 b/.08_random/kernel8 deleted file mode 100755 index 9097108f63a5062a1f85cb0175a15d971b35a7e1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 70720 zcmeI$Z)_9i9S88=*$Fr0Q;o8tK*_Y3!y`Zn(eOJ#nw)iHX@mOD5jqHaAiZ&S|Wb=oI%8H2RTy9 zb2L`{mvh;1ZYTDAT*mu;UE243&dxiUrmL2hwTyG0!w%{aHOXAl=UkI$|NiLSsk%EkpW6Ya#g>V7YeIr!Wzi2_%a()3jaO<%bbpDKR8 zBu@?NHEb^D8fukdp9eXs;^RI1m%F5lo%)qB<{z5C|+%==yitKqkJIZ6~bgT|s zanrOhZc+b=p*1bf&Kvg?9(To)RO#wjRk^W_`fq+wXqBa^uCx5!$z!abpYr;t=&CED zR#(+X>?*Gv7uV~)xNB;%#-q9~)=bG4<*9Y$)Gv%K@_8$yrs;`2Jf|mk%(I6!^V-}raew#a^E1x)M+zTn z&K{@ivEl7?NVvWAb=X#m{ZaJ$aE2?Lr(bZJBPI?fo=Jhb_ z@Z6pnT{AV~rq=oUuSyRhvrgBfyq@~^E#|em<@x>uJ8z%2hMuY}Z@IaeGU?KjX5`sxvSZ>iYnz{XMZ#2;(X)$o~~(%uH${p)hku`va|n3`aW_}>wez% zBJZo=bA7@#vrf;X(T9uY#l3u``oQUK5VdXkccGQnx##bCJEOlJ{)gvbxrf_T6x&Ik z^LM>JSH;qnwHsEdwNj~%x`%~UV~w2WHB!stdWXj)>*IQteMBzC`!?qfoGTi{n3d0X zt?1X2IOZqwjuCAp*kkt47M`2UJV%=*9;SX-oJVmj6t4rGC$aX$I$wKuRf~HOudP4P z^7V&Tw;bp54KJsDp2vo2&KnM|QfrRBzB0n+Il<=<*X<2`-5(R{n)BE6TwKp@a?R;X zZHw5~zxuTUgJIWpnlHvZ?1Kb3M;3v99O2C3E#`v8m@9=6bxY zh4pw{bM*vl>iN34o;79G^{gqIt4Fq}=P7eNOQ~|fd@Uulh3Bi9=Vd9kecv=+B6sPz zn6Ec@zRdRrac>d#j--Pw#LMW8xQ1^zZ7o|Nat_70gX)i-Cj27qh~=ZMB~N%#=T^ z=YKTiU(@r?OgXPH-W;^ZwXlD`p8HIBSkD8d{MlkIQ9Ui}r%BIGNelC>oIB`I`#u4{ zTaN#%9A3A{&)VcuHhB~0#OM8ish;2H`M(?s>%6At=gSu6A33>xheSr+%{O(im6erp zqyKN~<5Kn9=>LMA|3MsMG4G$+{;5q~#`9oRf2~cv!6x5ilkc?2(>D1Ln_N5~Th;lFO>WHBD${&*=)EQFh)r%>@7<<)nu=%V$uZprV&Zz?>&|E&EVd&$!g(d<#yT{v zvLug7r&$TNCw^k1*{bCC08{6H5q-Iu;&lan{E4d%(4?QKis6XZ?ia^%eo_2d&t ze(%iXv!zd^ck0rz8Ld0&)v{q!bQMZ$P}L;w30vLgFPXULxWpO7(-H z-JsV`@mF?4^nUz-(ucT~$!CZBkqzJF;wLcNm+5bRHQZs)4KiJ-H>-Igjmd-k18Tmw z!ymE=EnBKqE&Udu&m!~ts4tO8r{alZZ#M4@Ci(_6ZD>d@?#p#qRbW{_(BfoPnbkPM z7RN>`vPRB&`qJH6Hl7?vck|Oq&KnA3(;W$aYHkFNZQvKpQd z-daDP2I>a_zWPM2_-0yQ-bZWA+nmX7Pj_kc+gj^`2eoW3cibL|w55D%Aer!o8xtYE z#O7U)!GT0JAKb|=YNs~Ht)r<>s=X~5NVP|`NF?mDX&p>w(xU31PxD9H6M>*VluU5x zcFp?+@;PpvRKsdA+!#_5$*AA2g||{qBAuZgt%nh)2o@J>Fh}t?-1exWkH+_<3_~NAUySMi*>iw`f_Zr^fT?xOhO}?F~IQ-b$(Qjp!@< zQJj%)|HaL?Z%6q*nyfZ+>fuKGQ}(6JIR039X_pwEcxE+5S9+c%TE&@h?o!Lr>&%m- aGkNES{Mmf|uX1K}{6F>MPny8Y$Nv`z!MObZ diff --git a/.08_random/kernel8.img b/.08_random/kernel8.img deleted file mode 100755 index f991fad03af61ec278a99f034876464b3ed399bb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2099 zcmZ{lUu;u#6vxlKw}acuTv-2YEU^2l2?;COzzR}hWdBHD#1L{@AaQ}M8z~> zobx-s&pGG&`*n=Gch!>mxi%tyE0gZ(x?Uj*DNPk9c}JkLjMyE$N%~2&#I}?~QbM!;aV3&M9QWNf z!S~~W?^D>u#QL1I+~i9kXH2AS&ZL6rDVTWt^~8~^vr{ePN=R|-JPm7(`&S|#VeM2| zeeN`+G#am#nTKzeI>G;QMzW6kgj8t`vq*x;8zC^ zb&ngp<+fdhZ3s1WiW_RD6v{2u&G{?(t9@@Qt9uG{n_nV}d~&^|&Pm~W&vd^kSi3Lb z-H95_^cD1D?sl5UFI(fbmHl-04O&JDgCnXE4(d)SMq^gf<(}k6UhxjZ3XR zGpsGPJ?Z!segSdl)qs>vl+snMP2RU{B#v;6Uc+98@H~*L8MA%d>)k+>8e#r5JM<6} zZ8OcAIvE1L*Tx%QUpkUgCRzIoC-G8u}aaRt4Kk zn@GHOuSXS1Dt7eNN)|OHg_~jL`=#*ia@2ck;A^&5dDI(H_%p*t68VqAw--JK_Iilk zh$ySp{wVM&+9aH~3CtzgRhiF-MmjcGuu~ zk7MXe)eh`4f_?b8oi=no%ykX>DZ|ds^La3Lg(`jA=R(f9jTG(+ReBB#ovU&nmfsJ* z7v^ z&&{ihJU-0Jj=7W}_IlC0xLr2vd|sbmUd8tVzgzg-(Js=}Ruj$gGyFhOGYZbap843v zW)meJ;+*d_)2wq=^*T3__Y!icf;hwP)n<}!$s~{94x1J1 - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -ENTRY(_boot_cores); - -SECTIONS -{ - . = 0x80000; - - .text : - { - KEEP(*(.text.boot)) *(.text .text.*) - } - - .rodata : - { - *(.rodata .rodata.*) - } - - .data : - { - *(.data .data.*) - } - - .bss ALIGN(8): - { - __bss_start = .; - *(.bss .bss.*) - *(COMMON) - __bss_end = .; - } - - /DISCARD/ : { *(.comment) *(.gnu*) *(.note*) *(.eh_frame*) } -} diff --git a/.08_random/raspi3_boot/Cargo.toml b/.08_random/raspi3_boot/Cargo.toml deleted file mode 100644 index 024fd184..00000000 --- a/.08_random/raspi3_boot/Cargo.toml +++ /dev/null @@ -1,10 +0,0 @@ -[package] -name = "raspi3_boot" -version = "0.1.0" -authors = ["Andre Richter "] -edition = "2018" - -[dependencies] -cortex-a = "2.7.0" -panic-abort = "0.3.1" -r0 = "0.2.2" diff --git a/.08_random/raspi3_boot/src/lib.rs b/.08_random/raspi3_boot/src/lib.rs deleted file mode 100644 index a6b59ef1..00000000 --- a/.08_random/raspi3_boot/src/lib.rs +++ /dev/null @@ -1,102 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2018 Jorge Aparicio - * Copyright (c) 2018-2019 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#![deny(missing_docs)] -#![deny(warnings)] -#![no_std] - -//! Low-level boot of the Raspberry's processor - -extern crate panic_abort; - -/// Type check the user-supplied entry function. -#[macro_export] -macro_rules! entry { - ($path:path) => { - /// # Safety - /// - /// - User must ensure to provide a suitable main function for the - /// platform. - #[export_name = "main"] - pub unsafe fn __main() -> ! { - // type check the given path - let f: fn() -> ! = $path; - - f() - } - }; -} - -/// Reset function. -/// -/// Initializes the bss section before calling into the user's `main()`. -/// -/// # Safety -/// -/// - Only a single core must be active and running this function. -unsafe fn reset() -> ! { - extern "C" { - // Boundaries of the .bss section, provided by the linker script - static mut __bss_start: u64; - static mut __bss_end: u64; - } - - // Zeroes the .bss section - r0::zero_bss(&mut __bss_start, &mut __bss_end); - - extern "Rust" { - fn main() -> !; - } - - main(); -} - -/// Entrypoint of the processor. -/// -/// Parks all cores except core0, and then jumps to the internal -/// `reset()` function. -/// -/// # Safety -/// -/// - Linker script must ensure to place this function at `0x80_000`. -#[link_section = ".text.boot"] -#[no_mangle] -pub unsafe extern "C" fn _boot_cores() -> ! { - use cortex_a::{asm, regs::*}; - - const CORE_0: u64 = 0; - const CORE_MASK: u64 = 0x3; - const STACK_START: u64 = 0x80_000; - - if CORE_0 == MPIDR_EL1.get() & CORE_MASK { - SP.set(STACK_START); - reset() - } else { - // if not core0, infinitely wait for events - loop { - asm::wfe(); - } - } -} diff --git a/.08_random/src/gpio.rs b/.08_random/src/gpio.rs deleted file mode 100644 index da6a5be4..00000000 --- a/.08_random/src/gpio.rs +++ /dev/null @@ -1,75 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2018 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -use super::MMIO_BASE; -use register::{mmio::ReadWrite, register_bitfields}; - -// Descriptions taken from -// https://github.com/raspberrypi/documentation/files/1888662/BCM2837-ARM-Peripherals.-.Revised.-.V2-1.pdf -register_bitfields! { - u32, - - /// GPIO Function Select 1 - GPFSEL1 [ - /// Pin 15 - FSEL15 OFFSET(15) NUMBITS(3) [ - Input = 0b000, - Output = 0b001, - RXD0 = 0b100, // UART0 - Alternate function 0 - RXD1 = 0b010 // Mini UART - Alternate function 5 - - ], - - /// Pin 14 - FSEL14 OFFSET(12) NUMBITS(3) [ - Input = 0b000, - Output = 0b001, - TXD0 = 0b100, // UART0 - Alternate function 0 - TXD1 = 0b010 // Mini UART - Alternate function 5 - ] - ], - - /// GPIO Pull-up/down Clock Register 0 - GPPUDCLK0 [ - /// Pin 15 - PUDCLK15 OFFSET(15) NUMBITS(1) [ - NoEffect = 0, - AssertClock = 1 - ], - - /// Pin 14 - PUDCLK14 OFFSET(14) NUMBITS(1) [ - NoEffect = 0, - AssertClock = 1 - ] - ] -} - -pub const GPFSEL1: *const ReadWrite = - (MMIO_BASE + 0x0020_0004) as *const ReadWrite; - -pub const GPPUD: *const ReadWrite = (MMIO_BASE + 0x0020_0094) as *const ReadWrite; - -pub const GPPUDCLK0: *const ReadWrite = - (MMIO_BASE + 0x0020_0098) as *const ReadWrite; diff --git a/.08_random/src/main.rs b/.08_random/src/main.rs deleted file mode 100644 index be364ab9..00000000 --- a/.08_random/src/main.rs +++ /dev/null @@ -1,69 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2018 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#![no_std] -#![no_main] - -const MMIO_BASE: u32 = 0x3F00_0000; - -mod gpio; -mod mbox; -mod rand; -mod uart; - -fn kernel_entry() -> ! { - let mut mbox = mbox::Mbox::new(); - let uart = uart::Uart::new(); - - // set up serial console - match uart.init(&mut mbox) { - Ok(_) => uart.puts("\n[0] UART is live!\n"), - Err(_) => loop { - cortex_a::asm::wfe() // If UART fails, abort early - }, - } - - uart.puts("[1] Press a key to continue booting... "); - uart.getc(); - uart.puts("Greetings fellow Rustacean!\n"); - - // set up random number generator - let rng = rand::Rng::new(); - rng.init(); - - uart.puts("[2] RNG ready.\n\n"); - - uart.puts("Press any key to generate random numbers.\n"); - - // echo everything back - loop { - uart.getc(); - - uart.puts("0x"); - uart.hex(rng.rand(0, 4_294_967_295)); - uart.puts("\n"); - } -} - -raspi3_boot::entry!(kernel_entry); diff --git a/.08_random/src/mbox.rs b/.08_random/src/mbox.rs deleted file mode 100644 index aeae88bb..00000000 --- a/.08_random/src/mbox.rs +++ /dev/null @@ -1,162 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2018 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -use super::MMIO_BASE; -use core::ops; -use cortex_a::asm; -use register::{ - mmio::{ReadOnly, WriteOnly}, - register_bitfields, -}; - -register_bitfields! { - u32, - - STATUS [ - FULL OFFSET(31) NUMBITS(1) [], - EMPTY OFFSET(30) NUMBITS(1) [] - ] -} - -const VIDEOCORE_MBOX: u32 = MMIO_BASE + 0xB880; - -#[allow(non_snake_case)] -#[repr(C)] -pub struct RegisterBlock { - READ: ReadOnly, // 0x00 - __reserved_0: [u32; 5], // 0x04 - STATUS: ReadOnly, // 0x18 - __reserved_1: u32, // 0x1C - WRITE: WriteOnly, // 0x20 -} - -// Custom errors -pub enum MboxError { - ResponseError, - UnknownError, -} -pub type Result = ::core::result::Result; - -// Channels -pub mod channel { - pub const PROP: u32 = 8; -} - -// Tags -pub mod tag { - pub const SETCLKRATE: u32 = 0x38002; - pub const LAST: u32 = 0; -} - -// Clocks -pub mod clock { - pub const UART: u32 = 0x0_0000_0002; -} - -// Responses -mod response { - pub const SUCCESS: u32 = 0x8000_0000; - pub const ERROR: u32 = 0x8000_0001; // error parsing request buffer (partial response) -} - -pub const REQUEST: u32 = 0; - -// Public interface to the mailbox -#[repr(C)] -#[repr(align(16))] -pub struct Mbox { - // The address for buffer needs to be 16-byte aligned so that the - // Videcore can handle it properly. - pub buffer: [u32; 36], -} - -/// Deref to RegisterBlock -/// -/// Allows writing -/// ``` -/// self.STATUS.read() -/// ``` -/// instead of something along the lines of -/// ``` -/// unsafe { (*Mbox::ptr()).STATUS.read() } -/// ``` -impl ops::Deref for Mbox { - type Target = RegisterBlock; - - fn deref(&self) -> &Self::Target { - unsafe { &*Self::ptr() } - } -} - -impl Mbox { - pub fn new() -> Mbox { - Mbox { buffer: [0; 36] } - } - - /// Returns a pointer to the register block - fn ptr() -> *const RegisterBlock { - VIDEOCORE_MBOX as *const _ - } - - /// Make a mailbox call. Returns Err(MboxError) on failure, Ok(()) success - pub fn call(&self, channel: u32) -> Result<()> { - // wait until we can write to the mailbox - loop { - if !self.STATUS.is_set(STATUS::FULL) { - break; - } - - asm::nop(); - } - - let buf_ptr = self.buffer.as_ptr() as u32; - - // write the address of our message to the mailbox with channel identifier - self.WRITE.set((buf_ptr & !0xF) | (channel & 0xF)); - - // now wait for the response - loop { - // is there a response? - loop { - if !self.STATUS.is_set(STATUS::EMPTY) { - break; - } - - asm::nop(); - } - - let resp: u32 = self.READ.get(); - - // is it a response to our message? - if ((resp & 0xF) == channel) && ((resp & !0xF) == buf_ptr) { - // is it a valid successful response? - return match self.buffer[1] { - response::SUCCESS => Ok(()), - response::ERROR => Err(MboxError::ResponseError), - _ => Err(MboxError::UnknownError), - }; - } - } - } -} diff --git a/.08_random/src/rand.rs b/.08_random/src/rand.rs deleted file mode 100644 index 140e03d1..00000000 --- a/.08_random/src/rand.rs +++ /dev/null @@ -1,107 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2018 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -use super::MMIO_BASE; -use core::ops; -use cortex_a::asm; -use register::{mmio::*, register_bitfields}; - -register_bitfields! { - u32, - - CTRL [ - ENABLE OFFSET(0) NUMBITS(1) [ - True = 1, - False = 0 - ] - ], - - INT_MASK [ - INT_OFF OFFSET(0) NUMBITS(1) [ - True = 1, - False = 0 - ] - ] -} - -const RNG_BASE: u32 = MMIO_BASE + 0x104_000; -const RNG_WARMUP_COUNT: u32 = 0x40_000; - -#[allow(non_snake_case)] -#[repr(C)] -pub struct RegisterBlock { - CTRL: ReadWrite, // 0x00 - STATUS: ReadWrite, // 0x04 - DATA: ReadOnly, // 0x08 - __reserved_0: u32, // 0x0c - INT_MASK: ReadWrite, // 0x10 -} - -/// Public interface to the RNG -pub struct Rng; - -impl ops::Deref for Rng { - type Target = RegisterBlock; - - fn deref(&self) -> &Self::Target { - unsafe { &*Self::ptr() } - } -} - -impl Rng { - pub fn new() -> Rng { - Rng - } - - /// Returns a pointer to the register block - fn ptr() -> *const RegisterBlock { - RNG_BASE as *const _ - } - - /// Initialize the RNG - pub fn init(&self) { - // Disable interrupts - self.INT_MASK.modify(INT_MASK::INT_OFF::True); - - // Set warm-up count and enable - self.STATUS.set(RNG_WARMUP_COUNT); - self.CTRL.modify(CTRL::ENABLE::True); - } - - /// Return a random number between [min..max] - pub fn rand(&self, min: u32, max: u32) -> u32 { - // wait for gaining some entropy - loop { - if (self.STATUS.get() >> 24) != 0 { - break; - } - - asm::nop(); - } - - let r = self.DATA.get(); - - r % (max - min) + min - } -} diff --git a/.08_random/src/uart.rs b/.08_random/src/uart.rs deleted file mode 100644 index db4c639a..00000000 --- a/.08_random/src/uart.rs +++ /dev/null @@ -1,286 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2018 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -use super::MMIO_BASE; -use crate::gpio; -use crate::mbox; -use core::{ - ops, - sync::atomic::{compiler_fence, Ordering}, -}; -use cortex_a::asm; -use register::{mmio::*, register_bitfields}; - -// PL011 UART registers. -// -// Descriptions taken from -// https://github.com/raspberrypi/documentation/files/1888662/BCM2837-ARM-Peripherals.-.Revised.-.V2-1.pdf -register_bitfields! { - u32, - - /// Flag Register - FR [ - /// Transmit FIFO full. The meaning of this bit depends on the - /// state of the FEN bit in the UARTLCR_ LCRH 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 UARTLCR_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) [] - ], - - /// Integer Baud rate divisor - IBRD [ - /// Integer Baud rate divisor - IBRD OFFSET(0) NUMBITS(16) [] - ], - - /// Fractional Baud rate divisor - FBRD [ - /// Fractional Baud rate divisor - FBRD OFFSET(0) NUMBITS(6) [] - ], - - /// Line Control register - LCRH [ - /// Word length. These bits indicate the number of data bits - /// transmitted or received in a frame. - WLEN OFFSET(5) NUMBITS(2) [ - FiveBit = 0b00, - SixBit = 0b01, - SevenBit = 0b10, - EightBit = 0b11 - ] - ], - - /// Control Register - CR [ - /// Receive enable. If this bit is set to 1, the receive - /// section of the UART is enabled. Data reception occurs for - /// UART signals. 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 UART signals. 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 - 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 - ] - ], - - /// Interupt Clear Register - ICR [ - /// Meta field for all pending interrupts - ALL OFFSET(0) NUMBITS(11) [] - ] -} - -const UART_BASE: u32 = MMIO_BASE + 0x20_1000; - -#[allow(non_snake_case)] -#[repr(C)] -pub struct RegisterBlock { - DR: ReadWrite, // 0x00 - __reserved_0: [u32; 5], // 0x04 - FR: ReadOnly, // 0x18 - __reserved_1: [u32; 2], // 0x1c - IBRD: WriteOnly, // 0x24 - FBRD: WriteOnly, // 0x28 - LCRH: WriteOnly, // 0x2C - CR: WriteOnly, // 0x30 - __reserved_2: [u32; 4], // 0x34 - ICR: WriteOnly, // 0x44 -} - -pub enum UartError { - MailboxError, -} -pub type Result = ::core::result::Result; - -pub struct Uart; - -impl ops::Deref for Uart { - type Target = RegisterBlock; - - fn deref(&self) -> &Self::Target { - unsafe { &*Self::ptr() } - } -} - -impl Uart { - pub fn new() -> Uart { - Uart - } - - /// Returns a pointer to the register block - fn ptr() -> *const RegisterBlock { - UART_BASE as *const _ - } - - ///Set baud rate and characteristics (115200 8N1) and map to GPIO - pub fn init(&self, mbox: &mut mbox::Mbox) -> Result<()> { - // turn off UART0 - self.CR.set(0); - - // set up clock for consistent divisor values - mbox.buffer[0] = 9 * 4; - mbox.buffer[1] = mbox::REQUEST; - mbox.buffer[2] = mbox::tag::SETCLKRATE; - mbox.buffer[3] = 12; - mbox.buffer[4] = 8; - mbox.buffer[5] = mbox::clock::UART; // UART clock - mbox.buffer[6] = 4_000_000; // 4Mhz - mbox.buffer[7] = 0; // skip turbo setting - mbox.buffer[8] = mbox::tag::LAST; - - // Insert a compiler fence that ensures that all stores to the - // mbox buffer are finished before the GPU is signaled (which - // is done by a store operation as well). - compiler_fence(Ordering::Release); - - if mbox.call(mbox::channel::PROP).is_err() { - return Err(UartError::MailboxError); // Abort if UART clocks couldn't be set - }; - - // map UART0 to GPIO pins - unsafe { - (*gpio::GPFSEL1).modify(gpio::GPFSEL1::FSEL14::TXD0 + gpio::GPFSEL1::FSEL15::RXD0); - - (*gpio::GPPUD).set(0); // enable pins 14 and 15 - for _ in 0..150 { - asm::nop(); - } - - (*gpio::GPPUDCLK0).modify( - gpio::GPPUDCLK0::PUDCLK14::AssertClock + gpio::GPPUDCLK0::PUDCLK15::AssertClock, - ); - for _ in 0..150 { - asm::nop(); - } - - (*gpio::GPPUDCLK0).set(0); - } - - self.ICR.write(ICR::ALL::CLEAR); - self.IBRD.write(IBRD::IBRD.val(2)); // Results in 115200 baud - self.FBRD.write(FBRD::FBRD.val(0xB)); - self.LCRH.write(LCRH::WLEN::EightBit); // 8N1 - self.CR - .write(CR::UARTEN::Enabled + CR::TXE::Enabled + CR::RXE::Enabled); - - Ok(()) - } - - /// Send a character - pub fn send(&self, c: char) { - // wait until we can send - loop { - if !self.FR.is_set(FR::TXFF) { - break; - } - - asm::nop(); - } - - // write the character to the buffer - self.DR.set(c as u32); - } - - /// Receive a character - pub fn getc(&self) -> char { - // wait until something is in the buffer - loop { - if !self.FR.is_set(FR::RXFE) { - break; - } - - asm::nop(); - } - - // read it and return - let mut ret = self.DR.get() as u8 as char; - - // convert carrige return to newline - if ret == '\r' { - ret = '\n' - } - - ret - } - - /// Display a string - pub fn puts(&self, string: &str) { - for c in string.chars() { - // convert newline to carrige return + newline - if c == '\n' { - self.send('\r') - } - - self.send(c); - } - } - - /// Display a binary value in hexadecimal - pub fn hex(&self, d: u32) { - let mut n; - - for i in 0..8 { - // get highest tetrad - n = d.wrapping_shr(28 - i * 4) & 0xF; - - // 0-9 => '0'-'9', 10-15 => 'A'-'F' - // Add proper offset for ASCII table - if n > 9 { - n += 0x37; - } else { - n += 0x30; - } - - self.send(n as u8 as char); - } - } -} diff --git a/.09_delays/.cargo/config b/.09_delays/.cargo/config deleted file mode 100644 index de3f84c9..00000000 --- a/.09_delays/.cargo/config +++ /dev/null @@ -1,5 +0,0 @@ -[target.aarch64-unknown-none-softfloat] -rustflags = [ - "-C", "link-arg=-Tlink.ld", - "-C", "target-cpu=cortex-a53", -] diff --git a/.09_delays/Cargo.lock b/.09_delays/Cargo.lock deleted file mode 100644 index d218ad56..00000000 --- a/.09_delays/Cargo.lock +++ /dev/null @@ -1,57 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -[[package]] -name = "cortex-a" -version = "2.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "register 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "kernel8" -version = "0.1.0" -dependencies = [ - "cortex-a 2.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "raspi3_boot 0.1.0", - "register 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "panic-abort" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "r0" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "raspi3_boot" -version = "0.1.0" -dependencies = [ - "cortex-a 2.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "panic-abort 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "r0 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "register" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "tock-registers 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tock-registers" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[metadata] -"checksum cortex-a 2.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cbb16c411ab74044f174746a6cbae67bcdebea126e376b5441e5986e6a6aa950" -"checksum panic-abort 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2c14a66511ed17b6a8b4256b868d7fd207836d891db15eea5195dbcaf87e630f" -"checksum r0 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e2a38df5b15c8d5c7e8654189744d8e396bddc18ad48041a500ce52d6948941f" -"checksum register 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "469bb5ddde81d67fb8bba4e14d77689b8166cfd077abe7530591cefe29d05823" -"checksum tock-registers 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c758f5195a2e0df9d9fecf6f506506b2766ff74cf64db1e995c87e2761a5c3e2" diff --git a/.09_delays/Cargo.toml b/.09_delays/Cargo.toml deleted file mode 100644 index 43d1e22e..00000000 --- a/.09_delays/Cargo.toml +++ /dev/null @@ -1,13 +0,0 @@ -[package] -name = "kernel8" -version = "0.1.0" -authors = ["Andre Richter "] -edition = "2018" - -[dependencies] -raspi3_boot = { path = "raspi3_boot" } -cortex-a = "2.7.0" -register = "0.3.3" - -[package.metadata.cargo-xbuild] -sysroot_path = "../xbuild_sysroot" diff --git a/.09_delays/Makefile b/.09_delays/Makefile deleted file mode 100644 index 411b9bc3..00000000 --- a/.09_delays/Makefile +++ /dev/null @@ -1,77 +0,0 @@ -# -# MIT License -# -# Copyright (c) 2018-2019 Andre Richter -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# - -TARGET = aarch64-unknown-none-softfloat - -SOURCES = $(wildcard **/*.rs) $(wildcard **/*.S) link.ld - - -XRUSTC_CMD = cargo xrustc --target=$(TARGET) --release -CARGO_OUTPUT = target/$(TARGET)/release/kernel8 - -OBJCOPY = cargo objcopy -- -OBJCOPY_PARAMS = --strip-all -O binary - -CONTAINER_UTILS = andrerichter/raspi3-utils - -DOCKER_CMD = docker run -it --rm -DOCKER_ARG_CURDIR = -v $(shell pwd):/work -w /work -DOCKER_ARG_TTY = --privileged -v /dev:/dev - -DOCKER_EXEC_QEMU = qemu-system-aarch64 -M raspi3 -kernel kernel8.img -DOCKER_EXEC_RASPBOOT = raspbootcom -DOCKER_EXEC_RASPBOOT_DEV = /dev/ttyUSB0 -# DOCKER_EXEC_RASPBOOT_DEV = /dev/ttyACM0 - -.PHONY: all qemu raspboot clippy clean objdump nm - -all: clean kernel8.img - -$(CARGO_OUTPUT): $(SOURCES) - $(XRUSTC_CMD) - -kernel8.img: $(CARGO_OUTPUT) - cp $< . - $(OBJCOPY) $(OBJCOPY_PARAMS) $< kernel8.img - -qemu: all - $(DOCKER_CMD) $(DOCKER_ARG_CURDIR) $(CONTAINER_UTILS) \ - $(DOCKER_EXEC_QEMU) -serial stdio - -raspboot: all - $(DOCKER_CMD) $(DOCKER_ARG_CURDIR) $(DOCKER_ARG_TTY) \ - $(CONTAINER_UTILS) $(DOCKER_EXEC_RASPBOOT) $(DOCKER_EXEC_RASPBOOT_DEV) \ - kernel8.img - -clippy: - cargo xclippy --target=$(TARGET) - -clean: - cargo clean - -objdump: - cargo objdump --target $(TARGET) -- -disassemble -print-imm-hex kernel8 - -nm: - cargo nm --target $(TARGET) -- kernel8 | sort diff --git a/.09_delays/README.md b/.09_delays/README.md deleted file mode 100644 index 185bd36b..00000000 --- a/.09_delays/README.md +++ /dev/null @@ -1,25 +0,0 @@ -# Tutorial 09 - Delays - -It is very important to wait precise amounts of time while you are interfacing -with low level hardware. In this tutorial, we'll cover thee ways. One is CPU -frequency dependent (and useful if wait time is given in CPU clock cycles), the -other two are µs based. - -## delays.rs - -`delays::wait_cycles(cyc: u32)` this is very straightforward, we execute the -`nop` instruction n times. - -`delays::wait_usec(n: u32)` this implementation uses ARM system registers -(available on all AArch64 CPUs). - -`delays::SysTmr::wait_usec_st(&self, n: u64)` is a BCM specific implementation, -which uses the System Timer peripheral (not available on qemu). - -## uart.rs - -We can now conveniently use `delays::wait_cycles()` in `Uart::init()`. - -## main.rs - -We test our different wait implementations. diff --git a/.09_delays/kernel8 b/.09_delays/kernel8 deleted file mode 100755 index 5b299d271f5a851cb085646dcb0a1498e2da6f2b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 69488 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 - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -ENTRY(_boot_cores); - -SECTIONS -{ - . = 0x80000; - - .text : - { - KEEP(*(.text.boot)) *(.text .text.*) - } - - .rodata : - { - *(.rodata .rodata.*) - } - - .data : - { - *(.data .data.*) - } - - .bss ALIGN(8): - { - __bss_start = .; - *(.bss .bss.*) - *(COMMON) - __bss_end = .; - } - - /DISCARD/ : { *(.comment) *(.gnu*) *(.note*) *(.eh_frame*) } -} diff --git a/.09_delays/raspi3_boot/Cargo.toml b/.09_delays/raspi3_boot/Cargo.toml deleted file mode 100644 index 024fd184..00000000 --- a/.09_delays/raspi3_boot/Cargo.toml +++ /dev/null @@ -1,10 +0,0 @@ -[package] -name = "raspi3_boot" -version = "0.1.0" -authors = ["Andre Richter "] -edition = "2018" - -[dependencies] -cortex-a = "2.7.0" -panic-abort = "0.3.1" -r0 = "0.2.2" diff --git a/.09_delays/raspi3_boot/src/lib.rs b/.09_delays/raspi3_boot/src/lib.rs deleted file mode 100644 index a6b59ef1..00000000 --- a/.09_delays/raspi3_boot/src/lib.rs +++ /dev/null @@ -1,102 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2018 Jorge Aparicio - * Copyright (c) 2018-2019 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#![deny(missing_docs)] -#![deny(warnings)] -#![no_std] - -//! Low-level boot of the Raspberry's processor - -extern crate panic_abort; - -/// Type check the user-supplied entry function. -#[macro_export] -macro_rules! entry { - ($path:path) => { - /// # Safety - /// - /// - User must ensure to provide a suitable main function for the - /// platform. - #[export_name = "main"] - pub unsafe fn __main() -> ! { - // type check the given path - let f: fn() -> ! = $path; - - f() - } - }; -} - -/// Reset function. -/// -/// Initializes the bss section before calling into the user's `main()`. -/// -/// # Safety -/// -/// - Only a single core must be active and running this function. -unsafe fn reset() -> ! { - extern "C" { - // Boundaries of the .bss section, provided by the linker script - static mut __bss_start: u64; - static mut __bss_end: u64; - } - - // Zeroes the .bss section - r0::zero_bss(&mut __bss_start, &mut __bss_end); - - extern "Rust" { - fn main() -> !; - } - - main(); -} - -/// Entrypoint of the processor. -/// -/// Parks all cores except core0, and then jumps to the internal -/// `reset()` function. -/// -/// # Safety -/// -/// - Linker script must ensure to place this function at `0x80_000`. -#[link_section = ".text.boot"] -#[no_mangle] -pub unsafe extern "C" fn _boot_cores() -> ! { - use cortex_a::{asm, regs::*}; - - const CORE_0: u64 = 0; - const CORE_MASK: u64 = 0x3; - const STACK_START: u64 = 0x80_000; - - if CORE_0 == MPIDR_EL1.get() & CORE_MASK { - SP.set(STACK_START); - reset() - } else { - // if not core0, infinitely wait for events - loop { - asm::wfe(); - } - } -} diff --git a/.09_delays/src/delays.rs b/.09_delays/src/delays.rs deleted file mode 100644 index 53af476c..00000000 --- a/.09_delays/src/delays.rs +++ /dev/null @@ -1,140 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2018-2019 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -use super::MMIO_BASE; -use core::ops; -use cortex_a::{asm, regs::*}; -use register::mmio::*; - -const DELAY_BASE: u32 = MMIO_BASE + 0x3004; - -/* - * - * Using the RPi3 SoC's system timer peripheral - * - */ -#[allow(non_snake_case)] -#[repr(C)] -pub struct RegisterBlock { - SYSTMR_LO: ReadOnly, // 0x00 - SYSTMR_HI: ReadOnly, // 0x04 -} - -/// Public interface to the BCM System Timer -pub struct SysTmr; - -impl ops::Deref for SysTmr { - type Target = RegisterBlock; - - fn deref(&self) -> &Self::Target { - unsafe { &*Self::ptr() } - } -} - -impl SysTmr { - pub fn new() -> SysTmr { - SysTmr - } - - /// Returns a pointer to the register block - fn ptr() -> *const RegisterBlock { - DELAY_BASE as *const _ - } - - /// Get System Timer's counter - pub fn get_system_timer(&self) -> u64 { - // Since it is MMIO, we must emit two separate 32 bit reads - let mut hi = self.SYSTMR_HI.get(); - let mut lo = self.SYSTMR_LO.get(); - - // We have to repeat if high word changed during read. This - // will emit a clippy warning that needs be ignored, or you - // lose an MMIO read. - if hi != self.SYSTMR_HI.get() { - hi = self.SYSTMR_HI.get(); - lo = self.SYSTMR_LO.get(); - } - - // Compose long int value - (u64::from(hi) << 32) | u64::from(lo) - } - - /// Wait N microsec (with BCM System Timer) - pub fn wait_usec_st(&self, n: u64) { - let t = self.get_system_timer(); - - // We must check if it's non-zero, because qemu does not - // emulate system timer, and returning constant zero would - // mean infinite loop - if t > 0 { - loop { - if self.get_system_timer() > (t + n) { - break; - } - } - } - } -} - -/* - * - * Using the CPU's counter registers - * - */ -/// Wait N microsec (ARM CPU only) -pub fn wait_usec(n: u32) { - // Get the counter frequency - let frq = CNTFRQ_EL0.get(); - - // Calculate number of ticks - let tval = (u64::from(frq) * u64::from(n) / 1_000_000) as u32; - - // 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); - - loop { - // ISTATUS will be one when cval ticks have passed. Continuously check it. - if CNTP_CTL_EL0.is_set(CNTP_CTL_EL0::ISTATUS) { - break; - } - } - - // Disable counting again - CNTP_CTL_EL0.modify(CNTP_CTL_EL0::ENABLE::CLEAR); -} - -/* - * - * Using the CPU's cycles - * - */ -/// Wait N CPU cycles (ARM CPU only) -pub fn wait_cycles(cyc: u32) { - for _ in 0..cyc { - asm::nop(); - } -} diff --git a/.09_delays/src/gpio.rs b/.09_delays/src/gpio.rs deleted file mode 100644 index da6a5be4..00000000 --- a/.09_delays/src/gpio.rs +++ /dev/null @@ -1,75 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2018 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -use super::MMIO_BASE; -use register::{mmio::ReadWrite, register_bitfields}; - -// Descriptions taken from -// https://github.com/raspberrypi/documentation/files/1888662/BCM2837-ARM-Peripherals.-.Revised.-.V2-1.pdf -register_bitfields! { - u32, - - /// GPIO Function Select 1 - GPFSEL1 [ - /// Pin 15 - FSEL15 OFFSET(15) NUMBITS(3) [ - Input = 0b000, - Output = 0b001, - RXD0 = 0b100, // UART0 - Alternate function 0 - RXD1 = 0b010 // Mini UART - Alternate function 5 - - ], - - /// Pin 14 - FSEL14 OFFSET(12) NUMBITS(3) [ - Input = 0b000, - Output = 0b001, - TXD0 = 0b100, // UART0 - Alternate function 0 - TXD1 = 0b010 // Mini UART - Alternate function 5 - ] - ], - - /// GPIO Pull-up/down Clock Register 0 - GPPUDCLK0 [ - /// Pin 15 - PUDCLK15 OFFSET(15) NUMBITS(1) [ - NoEffect = 0, - AssertClock = 1 - ], - - /// Pin 14 - PUDCLK14 OFFSET(14) NUMBITS(1) [ - NoEffect = 0, - AssertClock = 1 - ] - ] -} - -pub const GPFSEL1: *const ReadWrite = - (MMIO_BASE + 0x0020_0004) as *const ReadWrite; - -pub const GPPUD: *const ReadWrite = (MMIO_BASE + 0x0020_0094) as *const ReadWrite; - -pub const GPPUDCLK0: *const ReadWrite = - (MMIO_BASE + 0x0020_0098) as *const ReadWrite; diff --git a/.09_delays/src/main.rs b/.09_delays/src/main.rs deleted file mode 100644 index 8c92ba69..00000000 --- a/.09_delays/src/main.rs +++ /dev/null @@ -1,73 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2018-2019 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#![no_std] -#![no_main] - -const MMIO_BASE: u32 = 0x3F00_0000; - -mod delays; -mod gpio; -mod mbox; -mod uart; - -fn kernel_entry() -> ! { - let mut mbox = mbox::Mbox::new(); - let uart = uart::Uart::new(); - - // set up serial console - match uart.init(&mut mbox) { - Ok(_) => uart.puts("\n[0] UART is live!\n"), - Err(_) => loop { - cortex_a::asm::wfe() // If UART fails, abort early - }, - } - - uart.puts("[1] Press a key to continue booting... "); - uart.getc(); - uart.puts("Greetings fellow Rustacean!\n"); - - uart.puts("[i] Waiting 1_000_000 CPU cycles (ARM CPU): "); - delays::wait_cycles(1_000_000); - uart.puts("OK\n"); - - uart.puts("[i] Waiting 1 second (ARM CPU): "); - delays::wait_usec(1_000_000); - uart.puts("OK\n"); - - let t = delays::SysTmr::new(); - if t.get_system_timer() != 0 { - uart.puts("[i] Waiting 1 second (BCM System Timer): "); - t.wait_usec_st(1_000_000); - uart.puts("OK\n"); - } - - uart.puts("[i] Looping forever now!\n"); - loop { - delays::wait_usec(1_000_000); - uart.puts("Tick: 1s\n"); - } -} - -raspi3_boot::entry!(kernel_entry); diff --git a/.09_delays/src/mbox.rs b/.09_delays/src/mbox.rs deleted file mode 100644 index aeae88bb..00000000 --- a/.09_delays/src/mbox.rs +++ /dev/null @@ -1,162 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2018 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -use super::MMIO_BASE; -use core::ops; -use cortex_a::asm; -use register::{ - mmio::{ReadOnly, WriteOnly}, - register_bitfields, -}; - -register_bitfields! { - u32, - - STATUS [ - FULL OFFSET(31) NUMBITS(1) [], - EMPTY OFFSET(30) NUMBITS(1) [] - ] -} - -const VIDEOCORE_MBOX: u32 = MMIO_BASE + 0xB880; - -#[allow(non_snake_case)] -#[repr(C)] -pub struct RegisterBlock { - READ: ReadOnly, // 0x00 - __reserved_0: [u32; 5], // 0x04 - STATUS: ReadOnly, // 0x18 - __reserved_1: u32, // 0x1C - WRITE: WriteOnly, // 0x20 -} - -// Custom errors -pub enum MboxError { - ResponseError, - UnknownError, -} -pub type Result = ::core::result::Result; - -// Channels -pub mod channel { - pub const PROP: u32 = 8; -} - -// Tags -pub mod tag { - pub const SETCLKRATE: u32 = 0x38002; - pub const LAST: u32 = 0; -} - -// Clocks -pub mod clock { - pub const UART: u32 = 0x0_0000_0002; -} - -// Responses -mod response { - pub const SUCCESS: u32 = 0x8000_0000; - pub const ERROR: u32 = 0x8000_0001; // error parsing request buffer (partial response) -} - -pub const REQUEST: u32 = 0; - -// Public interface to the mailbox -#[repr(C)] -#[repr(align(16))] -pub struct Mbox { - // The address for buffer needs to be 16-byte aligned so that the - // Videcore can handle it properly. - pub buffer: [u32; 36], -} - -/// Deref to RegisterBlock -/// -/// Allows writing -/// ``` -/// self.STATUS.read() -/// ``` -/// instead of something along the lines of -/// ``` -/// unsafe { (*Mbox::ptr()).STATUS.read() } -/// ``` -impl ops::Deref for Mbox { - type Target = RegisterBlock; - - fn deref(&self) -> &Self::Target { - unsafe { &*Self::ptr() } - } -} - -impl Mbox { - pub fn new() -> Mbox { - Mbox { buffer: [0; 36] } - } - - /// Returns a pointer to the register block - fn ptr() -> *const RegisterBlock { - VIDEOCORE_MBOX as *const _ - } - - /// Make a mailbox call. Returns Err(MboxError) on failure, Ok(()) success - pub fn call(&self, channel: u32) -> Result<()> { - // wait until we can write to the mailbox - loop { - if !self.STATUS.is_set(STATUS::FULL) { - break; - } - - asm::nop(); - } - - let buf_ptr = self.buffer.as_ptr() as u32; - - // write the address of our message to the mailbox with channel identifier - self.WRITE.set((buf_ptr & !0xF) | (channel & 0xF)); - - // now wait for the response - loop { - // is there a response? - loop { - if !self.STATUS.is_set(STATUS::EMPTY) { - break; - } - - asm::nop(); - } - - let resp: u32 = self.READ.get(); - - // is it a response to our message? - if ((resp & 0xF) == channel) && ((resp & !0xF) == buf_ptr) { - // is it a valid successful response? - return match self.buffer[1] { - response::SUCCESS => Ok(()), - response::ERROR => Err(MboxError::ResponseError), - _ => Err(MboxError::UnknownError), - }; - } - } - } -} diff --git a/.09_delays/src/uart.rs b/.09_delays/src/uart.rs deleted file mode 100644 index 75310d17..00000000 --- a/.09_delays/src/uart.rs +++ /dev/null @@ -1,263 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2018 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -use super::MMIO_BASE; -use crate::delays; -use crate::gpio; -use crate::mbox; -use core::{ - ops, - sync::atomic::{compiler_fence, Ordering}, -}; -use cortex_a::asm; -use register::{mmio::*, register_bitfields}; - -// PL011 UART registers. -// -// Descriptions taken from -// https://github.com/raspberrypi/documentation/files/1888662/BCM2837-ARM-Peripherals.-.Revised.-.V2-1.pdf -register_bitfields! { - u32, - - /// Flag Register - FR [ - /// Transmit FIFO full. The meaning of this bit depends on the - /// state of the FEN bit in the UARTLCR_ LCRH 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 UARTLCR_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) [] - ], - - /// Integer Baud rate divisor - IBRD [ - /// Integer Baud rate divisor - IBRD OFFSET(0) NUMBITS(16) [] - ], - - /// Fractional Baud rate divisor - FBRD [ - /// Fractional Baud rate divisor - FBRD OFFSET(0) NUMBITS(6) [] - ], - - /// Line Control register - LCRH [ - /// Word length. These bits indicate the number of data bits - /// transmitted or received in a frame. - WLEN OFFSET(5) NUMBITS(2) [ - FiveBit = 0b00, - SixBit = 0b01, - SevenBit = 0b10, - EightBit = 0b11 - ] - ], - - /// Control Register - CR [ - /// Receive enable. If this bit is set to 1, the receive - /// section of the UART is enabled. Data reception occurs for - /// UART signals. 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 UART signals. 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 - 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 - ] - ], - - /// Interupt Clear Register - ICR [ - /// Meta field for all pending interrupts - ALL OFFSET(0) NUMBITS(11) [] - ] -} - -const UART_BASE: u32 = MMIO_BASE + 0x20_1000; - -#[allow(non_snake_case)] -#[repr(C)] -pub struct RegisterBlock { - DR: ReadWrite, // 0x00 - __reserved_0: [u32; 5], // 0x04 - FR: ReadOnly, // 0x18 - __reserved_1: [u32; 2], // 0x1c - IBRD: WriteOnly, // 0x24 - FBRD: WriteOnly, // 0x28 - LCRH: WriteOnly, // 0x2C - CR: WriteOnly, // 0x30 - __reserved_2: [u32; 4], // 0x34 - ICR: WriteOnly, // 0x44 -} - -pub enum UartError { - MailboxError, -} -pub type Result = ::core::result::Result; - -pub struct Uart; - -impl ops::Deref for Uart { - type Target = RegisterBlock; - - fn deref(&self) -> &Self::Target { - unsafe { &*Self::ptr() } - } -} - -impl Uart { - pub fn new() -> Uart { - Uart - } - - /// Returns a pointer to the register block - fn ptr() -> *const RegisterBlock { - UART_BASE as *const _ - } - - ///Set baud rate and characteristics (115200 8N1) and map to GPIO - pub fn init(&self, mbox: &mut mbox::Mbox) -> Result<()> { - // turn off UART0 - self.CR.set(0); - - // set up clock for consistent divisor values - mbox.buffer[0] = 9 * 4; - mbox.buffer[1] = mbox::REQUEST; - mbox.buffer[2] = mbox::tag::SETCLKRATE; - mbox.buffer[3] = 12; - mbox.buffer[4] = 8; - mbox.buffer[5] = mbox::clock::UART; // UART clock - mbox.buffer[6] = 4_000_000; // 4Mhz - mbox.buffer[7] = 0; // skip turbo setting - mbox.buffer[8] = mbox::tag::LAST; - - // Insert a compiler fence that ensures that all stores to the - // mbox buffer are finished before the GPU is signaled (which - // is done by a store operation as well). - compiler_fence(Ordering::Release); - - if mbox.call(mbox::channel::PROP).is_err() { - return Err(UartError::MailboxError); // Abort if UART clocks couldn't be set - }; - - // map UART0 to GPIO pins - unsafe { - (*gpio::GPFSEL1).modify(gpio::GPFSEL1::FSEL14::TXD0 + gpio::GPFSEL1::FSEL15::RXD0); - - (*gpio::GPPUD).set(0); // enable pins 14 and 15 - delays::wait_cycles(150); - - (*gpio::GPPUDCLK0).modify( - gpio::GPPUDCLK0::PUDCLK14::AssertClock + gpio::GPPUDCLK0::PUDCLK15::AssertClock, - ); - delays::wait_cycles(150); - - (*gpio::GPPUDCLK0).set(0); - } - - self.ICR.write(ICR::ALL::CLEAR); - self.IBRD.write(IBRD::IBRD.val(2)); // Results in 115200 baud - self.FBRD.write(FBRD::FBRD.val(0xB)); - self.LCRH.write(LCRH::WLEN::EightBit); // 8N1 - self.CR - .write(CR::UARTEN::Enabled + CR::TXE::Enabled + CR::RXE::Enabled); - - Ok(()) - } - - /// Send a character - pub fn send(&self, c: char) { - // wait until we can send - loop { - if !self.FR.is_set(FR::TXFF) { - break; - } - - asm::nop(); - } - - // write the character to the buffer - self.DR.set(c as u32); - } - - /// Receive a character - pub fn getc(&self) -> char { - // wait until something is in the buffer - loop { - if !self.FR.is_set(FR::RXFE) { - break; - } - - asm::nop(); - } - - // read it and return - let mut ret = self.DR.get() as u8 as char; - - // convert carrige return to newline - if ret == '\r' { - ret = '\n' - } - - ret - } - - /// Display a string - pub fn puts(&self, string: &str) { - for c in string.chars() { - // convert newline to carrige return + newline - if c == '\n' { - self.send('\r') - } - - self.send(c); - } - } -} diff --git a/.0A_power/.cargo/config b/.0A_power/.cargo/config deleted file mode 100644 index de3f84c9..00000000 --- a/.0A_power/.cargo/config +++ /dev/null @@ -1,5 +0,0 @@ -[target.aarch64-unknown-none-softfloat] -rustflags = [ - "-C", "link-arg=-Tlink.ld", - "-C", "target-cpu=cortex-a53", -] diff --git a/.0A_power/Cargo.lock b/.0A_power/Cargo.lock deleted file mode 100644 index d218ad56..00000000 --- a/.0A_power/Cargo.lock +++ /dev/null @@ -1,57 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -[[package]] -name = "cortex-a" -version = "2.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "register 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "kernel8" -version = "0.1.0" -dependencies = [ - "cortex-a 2.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "raspi3_boot 0.1.0", - "register 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "panic-abort" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "r0" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "raspi3_boot" -version = "0.1.0" -dependencies = [ - "cortex-a 2.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "panic-abort 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "r0 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "register" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "tock-registers 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tock-registers" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[metadata] -"checksum cortex-a 2.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cbb16c411ab74044f174746a6cbae67bcdebea126e376b5441e5986e6a6aa950" -"checksum panic-abort 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2c14a66511ed17b6a8b4256b868d7fd207836d891db15eea5195dbcaf87e630f" -"checksum r0 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e2a38df5b15c8d5c7e8654189744d8e396bddc18ad48041a500ce52d6948941f" -"checksum register 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "469bb5ddde81d67fb8bba4e14d77689b8166cfd077abe7530591cefe29d05823" -"checksum tock-registers 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c758f5195a2e0df9d9fecf6f506506b2766ff74cf64db1e995c87e2761a5c3e2" diff --git a/.0A_power/Cargo.toml b/.0A_power/Cargo.toml deleted file mode 100644 index 43d1e22e..00000000 --- a/.0A_power/Cargo.toml +++ /dev/null @@ -1,13 +0,0 @@ -[package] -name = "kernel8" -version = "0.1.0" -authors = ["Andre Richter "] -edition = "2018" - -[dependencies] -raspi3_boot = { path = "raspi3_boot" } -cortex-a = "2.7.0" -register = "0.3.3" - -[package.metadata.cargo-xbuild] -sysroot_path = "../xbuild_sysroot" diff --git a/.0A_power/Makefile b/.0A_power/Makefile deleted file mode 100644 index 16e51f6c..00000000 --- a/.0A_power/Makefile +++ /dev/null @@ -1,76 +0,0 @@ -# -# MIT License -# -# Copyright (c) 2018-2019 Andre Richter -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# - -TARGET = aarch64-unknown-none-softfloat - -SOURCES = $(wildcard **/*.rs) $(wildcard **/*.S) link.ld - - -XRUSTC_CMD = cargo xrustc --target=$(TARGET) --release -CARGO_OUTPUT = target/$(TARGET)/release/kernel8 - -OBJCOPY = cargo objcopy -- -OBJCOPY_PARAMS = --strip-all -O binary - -CONTAINER_UTILS = andrerichter/raspi3-utils - -DOCKER_CMD = docker run -it --rm -DOCKER_ARG_CURDIR = -v $(shell pwd):/work -w /work -DOCKER_ARG_TTY = --privileged -v /dev:/dev - -DOCKER_EXEC_QEMU = qemu-system-aarch64 -M raspi3 -kernel kernel8.img -DOCKER_EXEC_RASPBOOT = raspbootcom -DOCKER_EXEC_RASPBOOT_DEV = /dev/ttyUSB0 -# DOCKER_EXEC_RASPBOOT_DEV = /dev/ttyACM0 - -.PHONY: all qemu raspboot clippy clean objdump nm - -all: clean kernel8.img - -$(CARGO_OUTPUT): $(SOURCES) - $(XRUSTC_CMD) - -kernel8.img: $(CARGO_OUTPUT) - cp $< . - $(OBJCOPY) $(OBJCOPY_PARAMS) $< kernel8.img - -qemu: all - $(DOCKER_CMD) $(DOCKER_ARG_CURDIR) $(CONTAINER_UTILS) \ - $(DOCKER_EXEC_QEMU) -serial stdio - -raspboot: all - $(DOCKER_CMD) $(DOCKER_ARG_CURDIR) $(DOCKER_ARG_TTY) \ - $(CONTAINER_UTILS) $(DOCKER_EXEC_RASPBOOT) $(DOCKER_EXEC_RASPBOOT_DEV) kernel8.img - -clippy: - cargo xclippy --target=$(TARGET) - -clean: - cargo clean - -objdump: - cargo objdump --target $(TARGET) -- -disassemble -print-imm-hex kernel8 - -nm: - cargo nm --target $(TARGET) -- kernel8 | sort diff --git a/.0A_power/README.md b/.0A_power/README.md deleted file mode 100644 index fcf4f2f9..00000000 --- a/.0A_power/README.md +++ /dev/null @@ -1,40 +0,0 @@ -# Tutorial 0A - Power management - -For embedded systems, power consumption is critical. The Raspberry Pi 3 has a -very sophisticated PM interface. You can turn each device on and off -independently. There's a catch though. The GPIO VCC pins are hardwired, there's -no way to turn them off programmatically. This means if you connect some devices -to them, you'll have to implement a way to turn those devices off (with a -transistor connected to a data GPIO pin for example). - -## power.rs - -Unfortunately, the documentation about the PM interface is very very rare. We -will therefore more or less implement a carbon copy of respective functions of -Linux' -[bcm2835_wdt.c](https://github.com/torvalds/linux/blob/master/drivers/watchdog/bcm2835_wdt.c) -driver. - -The power management controller is one of the peripherals that are not emulated -properly by QEMU. Our implementation therefore works on real hardware only. - -`Power::off(&self, mbox: &mut mbox::Mbox, gpio: &gpio::GPIO)` shuts down the -board to an almost zero power consumption state. - -`Power::reset(&self)` reboots the machine. Also handled by the PMC, and since -the Raspberry Pi does not have a hardware reset button, it's very useful. - -When using `make raspboot` and choosing `reset()`, you can see your code in -action nicely as you generate a boot-loop. - - -## gpio.rs - -We introduce a lot of new GPIO pins. It's a good time to refactor the GPIO MMIO -interface into its own type with the common `RegisterBlock` implementation that -you already know from the other components. - -## main.rs - -We display a simple menu, and wait for user input. Depending on the input, we -reboot the system or power it off. diff --git a/.0A_power/kernel8 b/.0A_power/kernel8 deleted file mode 100755 index 3e949a47eefa50afb79f13f6cb80da2824f389c0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 69680 zcmeI#TW}j^6$kLMk}uLa4Ye)XNt#saVyNvBjU`#K9GKe9rH#|Tq_RUwL!-#j+E#p# zwUQHubjFSurY?DjnU*l+At|>+W*B&Ii_K+l8ldTv2Pm`*Gi7ixWyY!DAu*wLQYy~3 z+NHKerVl*u^4E;C()rGQm*1XmcQm?Z|05PjBJ*XTA5-?1O%Jsi4MQ70%xR?nS*VqY zsZh@?)N{=C?0H1l<9Knl1M^5m?~ngA6)iIQ#sLBlfB*y_009U<00Izz00bZa0SG_< z0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb z2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$## zAOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;| zfB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U< z00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa z0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z z1Rwwb2tWV=5P$##{{I4(DDbAUu=UnaqRx7m=R%iX4$7p3GBB$RwT#~-su_3*5>Yns7oI4+}a63(2=i?Eg=eW;CvrmcW zY?oy$SbgEXNs(7&9S>H$b5Wb(JkfT&fZP6-ZTl|A7A&o^<)sB3aqf52LVaR>PM+T# zo}b9ij31e)p4h7QHEtaXeuK}c;CLm!m$(=tAXN++-^SF=mxGmPT<1X-+H+WvQZB*v;QDR3$VaI0c z#Fj@mH^jO0uZ%uNG50Op)@sDVnM~(3p7&~>Kk-<~`~@-!rPkSfQi1w3%Bgj*c-BPI_O~U=h_mSqR{Lgc`X}x9nPl@_01XAK*V@lJ$9Pc)@#}3xhm7Fh36rz(N%7* zI(dHwaZZM>oml@>wzJWi8c|xb^{CN#%Vn^0Bvw`=cLm&Dr~^`I^|u$AYhM zz1eua^5xIZOjSC(^5x1I=Vj+iT_GjJ7?-(EJ6qHjmU%?3%nqyD=DAMWX-w4dY%g2N z8^(eU9UTjvucX;$cRFV##+@@?eZ@I*hS$7wYA4rm8`txdOLNxHTMD0-8(WF|jN2v7 zW2;lv^!NsvuHYILZjEF)Q^9k6na4TA?**_-&W9**w3usr*X~4^o%b7-m)LSM*U}HTHbgxN%fEAtI3>s8Q40yX=A=xM zas}I#b6t*F6YU%q<6YomtgSjNA5c8}Av%yX>{ZHE8x> zfk)Po+sVm-$s8n`^Jvi?OVK?q--D6 zE16ESM#Q={@w!g%x}3(kUS=P2y$OylTdV5Dnw5WM_mz3hu~p}YoHTnZo!Z6MW+z{x zw)9Hmm-=>6JNv4 zT#un$l$hswJbr}IBgZUtPZm?@=tf%kCeOWH%;D+7|Jf5Fw%dq_J@Ndi{V>68_wj!C z47ZOOYn}Lr{os@~_tE>A&ZSek)1n@4ckJS|?BunzrSJCrN?)J-or^)SSHwPP;W`)l zz$x~LR5jyla^GkmIsVl1prSPpakf#XU*vL9w5@EHoV|pqrwu7p%@HncMa* zkABTwK$Gus?eDYG&FY)ZK=mgm@FLqeCCj3?*R+%EbsO2v@V>q&RZu|edC{MZ@9|t? zXKmH@PuB6fMY1iv!ucYm|NaUsi`W&;|H%j0`=Wff;VI={Td-4!C6)fzakW}L?0!l) zpsC5E5?1=ulS(SCMB;;~*x<0Lbj9QRrN`xRDUWKZD!wO`ZneKZenJTjCsW~w8Xl~c zWyP&*SBByzR85I@cgu>0e{z> zC90vd{rHXeRcUSf(;T<(gTT!Hj#v=CV*JjxuCaCE{Cv-w|HF0Szg{Q)=XK)d{C}G> z|9@~k@%(G8YuDAxH!_PwA~XL9V_m&Q+{~Xg;w$TndoQ==b9iu_xH-?a3)ar(oH4E$ zA2Y^%c%6O@t`kq{=SlR%ocbC0i2P_y{%?%=nDGO;Bhd@%^kdf5bWT6!dMT&gUgCa4 zU77ifM*s61FXOm5e^cpIo{xx|^=Za`Z^X_1Ym9#W!ts0gAvuv#|2Ni&lPjf;q{yYk zqv2GTTwTc|xsoRbQsFK>_9jzW_FMKyeX2I7_6J<5=5I*E8jfv`^bETis3z+2h!3y$ zXcQkl@!_YM5z#v0a#QHZ&ovomyFJ-2A$2gNopd+#Mk0Q{R}FZY+>uCkv)i*L|2Xb- z!VUT3p8R2N{%~XdFt1~TSCn_%{`}#l{NX_Ua5JUik-m_o_QaAYRZF`3LxYL#6aF5P zc7$mo@qwXOzp910hGYGFQ%|~l9xc`rc1QFqw}-TFawz5viTl5+*?0W-v3OK9dSH3C zdsVwnztJst z=BPeryL4-jH3yq%c;DzH;mQkC-7+A6P$qPHIdD^?x8fZv{F$VXp-b86Uy zH&LqN#x?LwLBHC>YnimeRk&6c;?s z_5e$5McmlX5jV~|D0{M5&mFKxq;Z6+hQr%`aJ{~DX$ zo|BcdzJa10%fa!M9nntU{8ACii@>r5T>1js5PTF^{t1rg%r?^@k-+ZR0gY0c9oSZb zm&0<@54)&0g5O?;ufYSK-(FjEX&JBl`;iL*=ekc4jy^za<~!^K&X|Dy+;)r9Gh70eCoFa;m) z2U;*oGiGZtABKM{%%|QNHH21#PQ2i`(19*=!kihs3FkP@gg8&?Mx%IDNi$mcle#&H z-6J%kV)y9qwF>QE2f53A*%vq3D-~8zSK3Ez`0KEf+|VKHn!>aS1v|-&`(h^v4GKMV zNi^18Mzey~)3Tn{;M+Mr{JvU7se9mlt4g!3S-rva6g6A`b~=-0#IEs^a$O<}%`it?>OW%?sNV#DD#GaW86ZPw(NcHW@+QJHY#T z4~1M>+vYudS1dFzz&m+3bd(Q9cz2|Ku($tUh<8OI__Kf0rcL~XSSTd^5Ac1VzP`v| zZX6sK?CcJ8_PaEVZ{{2M+mXYe7?14Rr|~WLM9R>h*3uJ+41{>3Kh(%y?(FUBiX7pg TSS%9bz5RTbxY5{%D{jv}RE?E8 diff --git a/.0A_power/link.ld b/.0A_power/link.ld deleted file mode 100644 index 5c499f89..00000000 --- a/.0A_power/link.ld +++ /dev/null @@ -1,55 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2018 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -ENTRY(_boot_cores); - -SECTIONS -{ - . = 0x80000; - - .text : - { - KEEP(*(.text.boot)) *(.text .text.*) - } - - .rodata : - { - *(.rodata .rodata.*) - } - - .data : - { - *(.data .data.*) - } - - .bss ALIGN(8): - { - __bss_start = .; - *(.bss .bss.*) - *(COMMON) - __bss_end = .; - } - - /DISCARD/ : { *(.comment) *(.gnu*) *(.note*) *(.eh_frame*) } -} diff --git a/.0A_power/raspi3_boot/Cargo.toml b/.0A_power/raspi3_boot/Cargo.toml deleted file mode 100644 index 024fd184..00000000 --- a/.0A_power/raspi3_boot/Cargo.toml +++ /dev/null @@ -1,10 +0,0 @@ -[package] -name = "raspi3_boot" -version = "0.1.0" -authors = ["Andre Richter "] -edition = "2018" - -[dependencies] -cortex-a = "2.7.0" -panic-abort = "0.3.1" -r0 = "0.2.2" diff --git a/.0A_power/raspi3_boot/src/lib.rs b/.0A_power/raspi3_boot/src/lib.rs deleted file mode 100644 index a6b59ef1..00000000 --- a/.0A_power/raspi3_boot/src/lib.rs +++ /dev/null @@ -1,102 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2018 Jorge Aparicio - * Copyright (c) 2018-2019 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#![deny(missing_docs)] -#![deny(warnings)] -#![no_std] - -//! Low-level boot of the Raspberry's processor - -extern crate panic_abort; - -/// Type check the user-supplied entry function. -#[macro_export] -macro_rules! entry { - ($path:path) => { - /// # Safety - /// - /// - User must ensure to provide a suitable main function for the - /// platform. - #[export_name = "main"] - pub unsafe fn __main() -> ! { - // type check the given path - let f: fn() -> ! = $path; - - f() - } - }; -} - -/// Reset function. -/// -/// Initializes the bss section before calling into the user's `main()`. -/// -/// # Safety -/// -/// - Only a single core must be active and running this function. -unsafe fn reset() -> ! { - extern "C" { - // Boundaries of the .bss section, provided by the linker script - static mut __bss_start: u64; - static mut __bss_end: u64; - } - - // Zeroes the .bss section - r0::zero_bss(&mut __bss_start, &mut __bss_end); - - extern "Rust" { - fn main() -> !; - } - - main(); -} - -/// Entrypoint of the processor. -/// -/// Parks all cores except core0, and then jumps to the internal -/// `reset()` function. -/// -/// # Safety -/// -/// - Linker script must ensure to place this function at `0x80_000`. -#[link_section = ".text.boot"] -#[no_mangle] -pub unsafe extern "C" fn _boot_cores() -> ! { - use cortex_a::{asm, regs::*}; - - const CORE_0: u64 = 0; - const CORE_MASK: u64 = 0x3; - const STACK_START: u64 = 0x80_000; - - if CORE_0 == MPIDR_EL1.get() & CORE_MASK { - SP.set(STACK_START); - reset() - } else { - // if not core0, infinitely wait for events - loop { - asm::wfe(); - } - } -} diff --git a/.0A_power/src/delays.rs b/.0A_power/src/delays.rs deleted file mode 100644 index 63414e4f..00000000 --- a/.0A_power/src/delays.rs +++ /dev/null @@ -1,37 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2018 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -use cortex_a::asm; - -/* - * - * Using the CPU's cycles - * - */ -/// Wait N CPU cycles (ARM CPU only) -pub fn wait_cycles(cyc: u32) { - for _ in 0..cyc { - asm::nop(); - } -} diff --git a/.0A_power/src/gpio.rs b/.0A_power/src/gpio.rs deleted file mode 100644 index 608ba532..00000000 --- a/.0A_power/src/gpio.rs +++ /dev/null @@ -1,121 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2018 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -use super::MMIO_BASE; -use core::ops; -use register::{mmio::ReadWrite, register_bitfields}; - -// Descriptions taken from -// https://github.com/raspberrypi/documentation/files/1888662/BCM2837-ARM-Peripherals.-.Revised.-.V2-1.pdf -register_bitfields! { - u32, - - /// GPIO Function Select 1 - GPFSEL1 [ - /// Pin 15 - FSEL15 OFFSET(15) NUMBITS(3) [ - Input = 0b000, - Output = 0b001, - RXD0 = 0b100, // UART0 - Alternate function 0 - RXD1 = 0b010 // Mini UART - Alternate function 5 - - ], - - /// Pin 14 - FSEL14 OFFSET(12) NUMBITS(3) [ - Input = 0b000, - Output = 0b001, - TXD0 = 0b100, // UART0 - Alternate function 0 - TXD1 = 0b010 // Mini UART - Alternate function 5 - ] - ], - - /// GPIO Pull-up/down Clock Register 0 - GPPUDCLK0 [ - /// Pin 15 - PUDCLK15 OFFSET(15) NUMBITS(1) [ - NoEffect = 0, - AssertClock = 1 - ], - - /// Pin 14 - PUDCLK14 OFFSET(14) NUMBITS(1) [ - NoEffect = 0, - AssertClock = 1 - ] - ] -} - -const GPIO_BASE: u32 = MMIO_BASE + 0x200_000; - -#[allow(non_snake_case)] -#[repr(C)] -pub struct RegisterBlock { - pub GPFSEL0: ReadWrite, // 0x00 - pub GPFSEL1: ReadWrite, // 0x04 - pub GPFSEL2: ReadWrite, // 0x08 - pub GPFSEL3: ReadWrite, // 0x0C - pub GPFSEL4: ReadWrite, // 0x10 - pub GPFSEL5: ReadWrite, // 0x14 - __reserved_0: u32, // 0x18 - GPSET0: ReadWrite, // 0x1C - GPSET1: ReadWrite, // 0x20 - __reserved_1: u32, // - GPCLR0: ReadWrite, // 0x28 - __reserved_2: [u32; 2], // - GPLEV0: ReadWrite, // 0x34 - GPLEV1: ReadWrite, // 0x38 - __reserved_3: u32, // - GPEDS0: ReadWrite, // 0x40 - GPEDS1: ReadWrite, // 0x44 - __reserved_4: [u32; 7], // - GPHEN0: ReadWrite, // 0x64 - GPHEN1: ReadWrite, // 0x68 - __reserved_5: [u32; 10], // - pub GPPUD: ReadWrite, // 0x94 - pub GPPUDCLK0: ReadWrite, // 0x98 - pub GPPUDCLK1: ReadWrite, // 0x9C -} - -/// Public interface to the GPIO MMIO area -pub struct GPIO; - -impl ops::Deref for GPIO { - type Target = RegisterBlock; - - fn deref(&self) -> &Self::Target { - unsafe { &*Self::ptr() } - } -} - -impl GPIO { - pub fn new() -> GPIO { - GPIO - } - - /// Returns a pointer to the register block - fn ptr() -> *const RegisterBlock { - GPIO_BASE as *const _ - } -} diff --git a/.0A_power/src/main.rs b/.0A_power/src/main.rs deleted file mode 100644 index b928ee51..00000000 --- a/.0A_power/src/main.rs +++ /dev/null @@ -1,71 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2018 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#![no_std] -#![no_main] - -const MMIO_BASE: u32 = 0x3F00_0000; - -mod delays; -mod gpio; -mod mbox; -mod power; -mod uart; - -fn kernel_entry() -> ! { - let gpio = gpio::GPIO::new(); - let mut mbox = mbox::Mbox::new(); - let uart = uart::Uart::new(); - let power = power::Power::new(); - - // set up serial console - match uart.init(&mut mbox, &gpio) { - Ok(_) => uart.puts("\n[0] UART is live!\n"), - Err(_) => loop { - cortex_a::asm::wfe() // If UART fails, abort early - }, - } - - uart.puts("[1] Press a key to continue booting... "); - uart.getc(); - uart.puts("Greetings fellow Rustacean!\n"); - - loop { - uart.puts("\n 1 - power off\n 2 - reset\nChoose one: "); - let c = uart.getc(); - uart.send(c); - - match c { - '1' => { - if power.off(&mut mbox, &gpio).is_err() { - uart.puts("Mailbox error in Power::off()"); - } - } - '2' => power.reset(), - _ => {} - } - } -} - -raspi3_boot::entry!(kernel_entry); diff --git a/.0A_power/src/mbox.rs b/.0A_power/src/mbox.rs deleted file mode 100644 index f5a420a5..00000000 --- a/.0A_power/src/mbox.rs +++ /dev/null @@ -1,163 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2018 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -use super::MMIO_BASE; -use core::ops; -use cortex_a::asm; -use register::{ - mmio::{ReadOnly, WriteOnly}, - register_bitfields, -}; - -register_bitfields! { - u32, - - STATUS [ - FULL OFFSET(31) NUMBITS(1) [], - EMPTY OFFSET(30) NUMBITS(1) [] - ] -} - -const VIDEOCORE_MBOX: u32 = MMIO_BASE + 0xB880; - -#[allow(non_snake_case)] -#[repr(C)] -pub struct RegisterBlock { - READ: ReadOnly, // 0x00 - __reserved_0: [u32; 5], // 0x04 - STATUS: ReadOnly, // 0x18 - __reserved_1: u32, // 0x1C - WRITE: WriteOnly, // 0x20 -} - -// Custom errors -pub enum MboxError { - ResponseError, - UnknownError, -} -pub type Result = ::core::result::Result; - -// Channels -pub mod channel { - pub const PROP: u32 = 8; -} - -// Tags -pub mod tag { - pub const SETPOWER: u32 = 0x28001; - pub const SETCLKRATE: u32 = 0x38002; - pub const LAST: u32 = 0; -} - -// Clocks -pub mod clock { - pub const UART: u32 = 0x0_0000_0002; -} - -// Responses -mod response { - pub const SUCCESS: u32 = 0x8000_0000; - pub const ERROR: u32 = 0x8000_0001; // error parsing request buffer (partial response) -} - -pub const REQUEST: u32 = 0; - -// Public interface to the mailbox -#[repr(C)] -#[repr(align(16))] -pub struct Mbox { - // The address for buffer needs to be 16-byte aligned so that the - // Videcore can handle it properly. - pub buffer: [u32; 36], -} - -/// Deref to RegisterBlock -/// -/// Allows writing -/// ``` -/// self.STATUS.read() -/// ``` -/// instead of something along the lines of -/// ``` -/// unsafe { (*Mbox::ptr()).STATUS.read() } -/// ``` -impl ops::Deref for Mbox { - type Target = RegisterBlock; - - fn deref(&self) -> &Self::Target { - unsafe { &*Self::ptr() } - } -} - -impl Mbox { - pub fn new() -> Mbox { - Mbox { buffer: [0; 36] } - } - - /// Returns a pointer to the register block - fn ptr() -> *const RegisterBlock { - VIDEOCORE_MBOX as *const _ - } - - /// Make a mailbox call. Returns Err(MboxError) on failure, Ok(()) success - pub fn call(&self, channel: u32) -> Result<()> { - // wait until we can write to the mailbox - loop { - if !self.STATUS.is_set(STATUS::FULL) { - break; - } - - asm::nop(); - } - - let buf_ptr = self.buffer.as_ptr() as u32; - - // write the address of our message to the mailbox with channel identifier - self.WRITE.set((buf_ptr & !0xF) | (channel & 0xF)); - - // now wait for the response - loop { - // is there a response? - loop { - if !self.STATUS.is_set(STATUS::EMPTY) { - break; - } - - asm::nop(); - } - - let resp: u32 = self.READ.get(); - - // is it a response to our message? - if ((resp & 0xF) == channel) && ((resp & !0xF) == buf_ptr) { - // is it a valid successful response? - return match self.buffer[1] { - response::SUCCESS => Ok(()), - response::ERROR => Err(MboxError::ResponseError), - _ => Err(MboxError::UnknownError), - }; - } - } - } -} diff --git a/.0A_power/src/power.rs b/.0A_power/src/power.rs deleted file mode 100644 index 4b555a05..00000000 --- a/.0A_power/src/power.rs +++ /dev/null @@ -1,143 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2018-2019 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -use super::MMIO_BASE; -use crate::delays; -use crate::gpio; -use crate::mbox; -use core::ops; -use core::sync::atomic::{compiler_fence, Ordering}; -use register::mmio::*; - -const POWER_BASE: u32 = MMIO_BASE + 0x100_01C; - -#[allow(non_snake_case)] -#[repr(C)] -pub struct RegisterBlock { - PM_RSTC: ReadWrite, // 0x1C - PM_RSTS: ReadWrite, // 0x20 - PM_WDOG: ReadWrite, // 0x24 -} - -const PM_PASSWORD: u32 = 0x5a_000_000; -const PM_RSTC_WRCFG_CLR: u32 = 0xffff_ffcf; -const PM_RSTC_WRCFG_FULL_RESET: u32 = 0x0000_0020; - -// The Raspberry Pi firmware uses the RSTS register to know which -// partition to boot from. The partition value is spread into bits 0, 2, -// 4, 6, 8, 10. Partition 63 is a special partition used by the -// firmware to indicate halt. -const PM_RSTS_RASPBERRYPI_HALT: u32 = 0x555; - -pub enum PowerError { - MailboxError, -} -pub type Result = ::core::result::Result; - -/// Public interface to the Power subsystem -pub struct Power; - -impl ops::Deref for Power { - type Target = RegisterBlock; - - fn deref(&self) -> &Self::Target { - unsafe { &*Self::ptr() } - } -} - -impl Power { - pub fn new() -> Power { - Power - } - - /// Returns a pointer to the register block - fn ptr() -> *const RegisterBlock { - POWER_BASE as *const _ - } - - /// Shutdown the board - pub fn off(&self, mbox: &mut mbox::Mbox, gpio: &gpio::GPIO) -> Result<()> { - // power off devices one by one - for dev_id in 0..16 { - mbox.buffer[0] = 8 * 4; - mbox.buffer[1] = mbox::REQUEST; - mbox.buffer[2] = mbox::tag::SETPOWER; - mbox.buffer[3] = 8; - mbox.buffer[4] = 8; - mbox.buffer[5] = dev_id; // device id - mbox.buffer[6] = 0; // bit 0: off, bit 1: no wait - mbox.buffer[7] = mbox::tag::LAST; - - // Insert a compiler fence that ensures that all stores to the - // mbox buffer are finished before the GPU is signaled (which - // is done by a store operation as well). - compiler_fence(Ordering::Release); - - if mbox.call(mbox::channel::PROP).is_err() { - return Err(PowerError::MailboxError); - }; - } - - // power off gpio pins (but not VCC pins) - gpio.GPFSEL0.set(0); - gpio.GPFSEL1.set(0); - gpio.GPFSEL2.set(0); - gpio.GPFSEL3.set(0); - gpio.GPFSEL4.set(0); - gpio.GPFSEL5.set(0); - - gpio.GPPUD.set(0); - delays::wait_cycles(150); - - gpio.GPPUDCLK0.set(0xffff_ffff); - gpio.GPPUDCLK1.set(0xffff_ffff); - delays::wait_cycles(150); - - // flush GPIO setup - gpio.GPPUDCLK0.set(0); - gpio.GPPUDCLK1.set(0); - - // We set the watchdog hard reset bit here to distinguish this - // reset from the normal (full) reset. bootcode.bin will not - // reboot after a hard reset. - let mut val = self.PM_RSTS.get(); - val |= PM_PASSWORD | PM_RSTS_RASPBERRYPI_HALT; - self.PM_RSTS.set(val); - - // Continue with normal reset mechanism - self.reset(); - } - - /// Reboot - pub fn reset(&self) -> ! { - // use a timeout of 10 ticks (~150us) - self.PM_WDOG.set(PM_PASSWORD | 10); - let mut val = self.PM_RSTC.get(); - val &= PM_RSTC_WRCFG_CLR; - val |= PM_PASSWORD | PM_RSTC_WRCFG_FULL_RESET; - self.PM_RSTC.set(val); - - loop {} - } -} diff --git a/.0A_power/src/uart.rs b/.0A_power/src/uart.rs deleted file mode 100644 index 8950fea6..00000000 --- a/.0A_power/src/uart.rs +++ /dev/null @@ -1,262 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2018 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -use super::MMIO_BASE; -use crate::delays; -use crate::gpio; -use crate::mbox; -use core::{ - ops, - sync::atomic::{compiler_fence, Ordering}, -}; -use cortex_a::asm; -use register::{mmio::*, register_bitfields}; - -// PL011 UART registers. -// -// Descriptions taken from -// https://github.com/raspberrypi/documentation/files/1888662/BCM2837-ARM-Peripherals.-.Revised.-.V2-1.pdf -register_bitfields! { - u32, - - /// Flag Register - FR [ - /// Transmit FIFO full. The meaning of this bit depends on the - /// state of the FEN bit in the UARTLCR_ LCRH 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 UARTLCR_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) [] - ], - - /// Integer Baud rate divisor - IBRD [ - /// Integer Baud rate divisor - IBRD OFFSET(0) NUMBITS(16) [] - ], - - /// Fractional Baud rate divisor - FBRD [ - /// Fractional Baud rate divisor - FBRD OFFSET(0) NUMBITS(6) [] - ], - - /// Line Control register - LCRH [ - /// Word length. These bits indicate the number of data bits - /// transmitted or received in a frame. - WLEN OFFSET(5) NUMBITS(2) [ - FiveBit = 0b00, - SixBit = 0b01, - SevenBit = 0b10, - EightBit = 0b11 - ] - ], - - /// Control Register - CR [ - /// Receive enable. If this bit is set to 1, the receive - /// section of the UART is enabled. Data reception occurs for - /// UART signals. 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 UART signals. 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 - 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 - ] - ], - - /// Interupt Clear Register - ICR [ - /// Meta field for all pending interrupts - ALL OFFSET(0) NUMBITS(11) [] - ] -} - -const UART_BASE: u32 = MMIO_BASE + 0x20_1000; - -#[allow(non_snake_case)] -#[repr(C)] -pub struct RegisterBlock { - DR: ReadWrite, // 0x00 - __reserved_0: [u32; 5], // 0x04 - FR: ReadOnly, // 0x18 - __reserved_1: [u32; 2], // 0x1c - IBRD: WriteOnly, // 0x24 - FBRD: WriteOnly, // 0x28 - LCRH: WriteOnly, // 0x2C - CR: WriteOnly, // 0x30 - __reserved_2: [u32; 4], // 0x34 - ICR: WriteOnly, // 0x44 -} - -pub enum UartError { - MailboxError, -} -pub type Result = ::core::result::Result; - -pub struct Uart; - -impl ops::Deref for Uart { - type Target = RegisterBlock; - - fn deref(&self) -> &Self::Target { - unsafe { &*Self::ptr() } - } -} - -impl Uart { - pub fn new() -> Uart { - Uart - } - - /// Returns a pointer to the register block - fn ptr() -> *const RegisterBlock { - UART_BASE as *const _ - } - - ///Set baud rate and characteristics (115200 8N1) and map to GPIO - pub fn init(&self, mbox: &mut mbox::Mbox, gpio: &gpio::GPIO) -> Result<()> { - // turn off UART0 - self.CR.set(0); - - // set up clock for consistent divisor values - mbox.buffer[0] = 9 * 4; - mbox.buffer[1] = mbox::REQUEST; - mbox.buffer[2] = mbox::tag::SETCLKRATE; - mbox.buffer[3] = 12; - mbox.buffer[4] = 8; - mbox.buffer[5] = mbox::clock::UART; // UART clock - mbox.buffer[6] = 4_000_000; // 4Mhz - mbox.buffer[7] = 0; // skip turbo setting - mbox.buffer[8] = mbox::tag::LAST; - - // Insert a compiler fence that ensures that all stores to the - // mbox buffer are finished before the GPU is signaled (which - // is done by a store operation as well). - compiler_fence(Ordering::Release); - - if mbox.call(mbox::channel::PROP).is_err() { - return Err(UartError::MailboxError); // Abort if UART clocks couldn't be set - }; - - // map UART0 to GPIO pins - gpio.GPFSEL1 - .modify(gpio::GPFSEL1::FSEL14::TXD0 + gpio::GPFSEL1::FSEL15::RXD0); - - gpio.GPPUD.set(0); // enable pins 14 and 15 - delays::wait_cycles(150); - - gpio.GPPUDCLK0.modify( - gpio::GPPUDCLK0::PUDCLK14::AssertClock + gpio::GPPUDCLK0::PUDCLK15::AssertClock, - ); - delays::wait_cycles(150); - - gpio.GPPUDCLK0.set(0); - - self.ICR.write(ICR::ALL::CLEAR); - self.IBRD.write(IBRD::IBRD.val(2)); // Results in 115200 baud - self.FBRD.write(FBRD::FBRD.val(0xB)); - self.LCRH.write(LCRH::WLEN::EightBit); // 8N1 - self.CR - .write(CR::UARTEN::Enabled + CR::TXE::Enabled + CR::RXE::Enabled); - - Ok(()) - } - - /// Send a character - pub fn send(&self, c: char) { - // wait until we can send - loop { - if !self.FR.is_set(FR::TXFF) { - break; - } - - asm::nop(); - } - - // write the character to the buffer - self.DR.set(c as u32); - } - - /// Receive a character - pub fn getc(&self) -> char { - // wait until something is in the buffer - loop { - if !self.FR.is_set(FR::RXFE) { - break; - } - - asm::nop(); - } - - // read it and return - let mut ret = self.DR.get() as u8 as char; - - // convert carrige return to newline - if ret == '\r' { - ret = '\n' - } - - ret - } - - /// Display a string - pub fn puts(&self, string: &str) { - for c in string.chars() { - // convert newline to carrige return + newline - if c == '\n' { - self.send('\r') - } - - self.send(c); - } - } -} diff --git a/.0B_hw_debug_JTAG/.cargo/config b/.0B_hw_debug_JTAG/.cargo/config deleted file mode 100644 index de3f84c9..00000000 --- a/.0B_hw_debug_JTAG/.cargo/config +++ /dev/null @@ -1,5 +0,0 @@ -[target.aarch64-unknown-none-softfloat] -rustflags = [ - "-C", "link-arg=-Tlink.ld", - "-C", "target-cpu=cortex-a53", -] diff --git a/.0B_hw_debug_JTAG/Cargo.lock b/.0B_hw_debug_JTAG/Cargo.lock deleted file mode 100644 index d218ad56..00000000 --- a/.0B_hw_debug_JTAG/Cargo.lock +++ /dev/null @@ -1,57 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -[[package]] -name = "cortex-a" -version = "2.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "register 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "kernel8" -version = "0.1.0" -dependencies = [ - "cortex-a 2.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "raspi3_boot 0.1.0", - "register 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "panic-abort" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "r0" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "raspi3_boot" -version = "0.1.0" -dependencies = [ - "cortex-a 2.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "panic-abort 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "r0 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "register" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "tock-registers 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tock-registers" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[metadata] -"checksum cortex-a 2.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cbb16c411ab74044f174746a6cbae67bcdebea126e376b5441e5986e6a6aa950" -"checksum panic-abort 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2c14a66511ed17b6a8b4256b868d7fd207836d891db15eea5195dbcaf87e630f" -"checksum r0 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e2a38df5b15c8d5c7e8654189744d8e396bddc18ad48041a500ce52d6948941f" -"checksum register 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "469bb5ddde81d67fb8bba4e14d77689b8166cfd077abe7530591cefe29d05823" -"checksum tock-registers 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c758f5195a2e0df9d9fecf6f506506b2766ff74cf64db1e995c87e2761a5c3e2" diff --git a/.0B_hw_debug_JTAG/Cargo.toml b/.0B_hw_debug_JTAG/Cargo.toml deleted file mode 100644 index 43d1e22e..00000000 --- a/.0B_hw_debug_JTAG/Cargo.toml +++ /dev/null @@ -1,13 +0,0 @@ -[package] -name = "kernel8" -version = "0.1.0" -authors = ["Andre Richter "] -edition = "2018" - -[dependencies] -raspi3_boot = { path = "raspi3_boot" } -cortex-a = "2.7.0" -register = "0.3.3" - -[package.metadata.cargo-xbuild] -sysroot_path = "../xbuild_sysroot" diff --git a/.0B_hw_debug_JTAG/Makefile b/.0B_hw_debug_JTAG/Makefile deleted file mode 100644 index 913fc341..00000000 --- a/.0B_hw_debug_JTAG/Makefile +++ /dev/null @@ -1,101 +0,0 @@ -# -# MIT License -# -# Copyright (c) 2018-2019 Andre Richter -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# - -TARGET = aarch64-unknown-none-softfloat - -SOURCES = $(wildcard **/*.rs) $(wildcard **/*.S) link.ld - - -XRUSTC_CMD = cargo xrustc --target=$(TARGET) --release -CARGO_OUTPUT = target/$(TARGET)/release/kernel8 - -OBJCOPY = cargo objcopy -- -OBJCOPY_PARAMS = --strip-all -O binary - -CONTAINER_UTILS = andrerichter/raspi3-utils -CONTAINER_OPENOCD = andrerichter/raspi3-openocd -# CONTAINER_OPENOCD_ARG = -f openocd/tcl/interface/ftdi/olimex-jtag-tiny.cfg -f /openocd/rpi3.cfg -CONTAINER_GDB = andrerichter/raspi3-gdb - -DOCKER_CMD = docker run -it --rm -DOCKER_ARG_CURDIR = -v $(shell pwd):/work -w /work -DOCKER_ARG_TTY = --privileged -v /dev:/dev -DOCKER_ARG_JTAG = -v $(shell pwd)/../X1_JTAG_boot:/jtag -DOCKER_ARG_NET = --network host - -DOCKER_EXEC_QEMU = qemu-system-aarch64 -M raspi3 -kernel kernel8.img -DOCKER_EXEC_RASPBOOT = raspbootcom -DOCKER_EXEC_RASPBOOT_DEV = /dev/ttyUSB0 -# DOCKER_EXEC_RASPBOOT_DEV = /dev/ttyACM0 - -.PHONY: all qemu raspboot clippy clean objdump nm jtagboot openocd gdb gdb-opt0 - -all: clean kernel8.img - -$(CARGO_OUTPUT): $(SOURCES) - $(XRUSTC_CMD) - -kernel8.img: $(CARGO_OUTPUT) - cp $< . - $(OBJCOPY) $(OBJCOPY_PARAMS) $< kernel8.img - -qemu: all - $(DOCKER_CMD) $(DOCKER_ARG_CURDIR) $(CONTAINER_UTILS) \ - $(DOCKER_EXEC_QEMU) -serial stdio - -raspboot: all - $(DOCKER_CMD) $(DOCKER_ARG_CURDIR) $(DOCKER_ARG_TTY) \ - $(CONTAINER_UTILS) $(DOCKER_EXEC_RASPBOOT) $(DOCKER_EXEC_RASPBOOT_DEV) kernel8.img - -clippy: - cargo xclippy --target=$(TARGET) - -clean: - cargo clean - -objdump: - cargo objdump --target $(TARGET) -- -disassemble -print-imm-hex kernel8 - -nm: - cargo nm --target $(TARGET) -- kernel8 | sort - -jtagboot: - $(DOCKER_CMD) $(DOCKER_ARG_TTY) $(DOCKER_ARG_JTAG) $(CONTAINER_UTILS) \ - $(DOCKER_EXEC_RASPBOOT) $(DOCKER_EXEC_RASPBOOT_DEV) /jtag/jtag_boot.img - -openocd: - $(DOCKER_CMD) $(DOCKER_ARG_TTY) $(DOCKER_ARG_NET) $(CONTAINER_OPENOCD) $(CONTAINER_OPENOCD_ARG) - -define gen_gdb - $(XRUSTC_CMD) -- $1 - cp $(CARGO_OUTPUT) kernel8_for_jtag - $(DOCKER_CMD) $(DOCKER_ARG_CURDIR) $(DOCKER_ARG_NET) $(CONTAINER_GDB) \ - gdb-multiarch -q kernel8_for_jtag -endef - -gdb: clean $(SOURCES) - $(call gen_gdb,-C debuginfo=2) - -gdb-opt0: clean $(SOURCES) - $(call gen_gdb,-C debuginfo=2 -C opt-level=0) diff --git a/.0B_hw_debug_JTAG/README.md b/.0B_hw_debug_JTAG/README.md deleted file mode 100644 index 5812d673..00000000 --- a/.0B_hw_debug_JTAG/README.md +++ /dev/null @@ -1,265 +0,0 @@ -# Tutorial 0B - Hardware Debugging using JTAG - -In the upcoming tutorials, we are going to touch sensitive areas of the RPi's -SoC that can make our debugging life very hard. For example, changing the -processor's `Exception Level` or introducing `virtual memory`. - -A hardware based debugger can sometimes be the last resort when searching for a -tricky bug. Especially for debugging intricate, architecture-specific HW issues, -it will be handy, because in this area `QEMU` sometimes can not help, since it -abstracts certain features of our RPi's HW and doesn't simulate down to the very -last bit. - -So lets introduce `JTAG` debugging. Once set up, it will allow us to single-step -through our kernel on the real HW. How cool is that?! - -![JTAG live demo](../doc/jtag_demo.gif) - -## Outline - -Functionally, this tutorial is the same as the previous one, where we reset or -power down the RPi. Around that, we add infrastructure for JTAG debugging. - -## Hardware - -Unlike microcontroller boards like the `STM32F3DISCOVERY`, which is used in our -WG's [Embedded Rust Book](https://rust-embedded.github.io/book/start/hardware.html), -the RPi does not have an embedded debugger on it's board. Hence, you need to buy one. - -For this tutorial, we will use the -[ARM-USB-TINY-H](https://www.olimex.com/Products/ARM/JTAG/ARM-USB-TINY-H/) by -OLIMEX. It has a standard -[ARM JTAG 20 connector](http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0499dj/BEHEIHCE.html). -Unfortunately, the RPi does not, so we have to connect it via jumper wires. - -### Wiring - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
GPIO #NameJTAG #NoteDiagram
VTREF1to 3.3V
GND4to GND
22TRST3
26TDI5
27TMS7
25TCK9
23RTCK11
24TDO13
- -

- -## Configuring GPIO for JTAG - -Before it is possible to connect, we additionally have to configure the -respective GPIO pins for `JTAG` functionality from software. Our approach is as -allows: - -Via `raspboot`, we load a tiny helper binary onto the RPi which configures the -pins respectively and then parks the executing core in an endless loop, waiting -for the `JTAG` debugger to connect. The helper binary is maintained separately -in this repository's [X1_JTAG_boot](../X1_JTAG_boot) folder, and is a -stripped-down version of the code we use in our tutorials. - -This functionality is provided by the new `Makefile` target `make jtagboot`. - -```console -ferris@box:~$ make jtagboot -Raspbootcom V1.0 -### Listening on /dev/ttyUSB0 -RBIN64 -### sending kernel /jtag/jtag_boot.img [759 byte] -### finished sending - - -[i] JTAG is live. Please connect. -``` - -It is important to keep the USB serial connected and the terminal open with -`raspboot` running. When we load the actual kernel later, `UART` output will -appear here. - -## OpenOCD - -Next, we need to launch the [Open On-Chip Debugger](http://openocd.org/), aka -`OpenOCD` to actually connect the `JTAG`. - -As always, our tutorials try to be as painless as possible regarding dev-tools, -which is why we have packaged everything into a [dedicated Docker container](../docker/raspi3-openocd) that will be provisioned automagically on the first run. - - - -Now connect the Olimex USB JTAG debugger, open a new terminal and in the same -folder, type `make openocd` (in that order!). You will see some initial output: - -```console -ferris@box:~$ make openocd -Open On-Chip Debugger 0.10.0+dev-ge243075 (2019-03-07-19:07) -Licensed under GNU GPL v2 -For bug reports, read - http://openocd.org/doc/doxygen/bugs.html -trst_and_srst separate srst_gates_jtag trst_push_pull srst_open_drain connect_deassert_srst -adapter speed: 1000 kHz -jtag_ntrst_delay: 500 -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` has detected the four cores of the RPi, and opened four network ports -to which `gdb` can now connect to debug the respective core. - -## GDB - -Finally, we need an `AArch64`-capable version of `gdb`. You guessed right, we -packaged [another container for you](../docker/raspi3-gdb). It can be launched -via `make gdb`. - -This Makefile target actually does a little more. It builds a special version of -our kernel with debug information included. This enables `gdb` to show the `Rust` -source code line we are currently debugging. It also launches `gdb` such -that it already loads this debug build (`kernel8_for_jtag`). - -We can now use the `gdb` commandline to - 1. Set breakpoints in our kernel - 2. Load the kernel via JTAG in memory (remember that currently, the RPi is still executing -the minimal JTAG pin enablement binary). - 3. Manipulate the program counter of the RPi to start execution at our kernel's entry point. - 4. Single-step through its execution. - -```shell ->>> break _boot_cores -Breakpoint 1 at 0x80000 ->>> target remote :3333 # Connect to OpenOCD, raspi3.core0 ->>> load # Load the kernel into the Raspi's DRAM over JTAG. -Loading section .text, size 0x6cc lma 0x80000 -Loading section .rodata, size 0x9a lma 0x806cc -Start address 0x80000, load size 1894 -Transfer rate: 66 KB/sec, 947 bytes/write. ->>> set $pc = 0x80000 # Set RPI's program counter to the start of the kernel binary. ->>> cont -Breakpoint 1, 0x0000000000080000 in _boot_cores () ->>> step ->>> step # Single-step through the kernel ->>> ... -``` - -### Remarks - -#### Optimization - -When debugging an OS binary, you have to make a trade-off between the -granularity at which you can step through your Rust source-code and the -optimization level of the generated binary. The `make` and `make gdb` targets -produce a `--release` binary, which includes an optimization level of three -(`-opt-level=3`). However, in this case, the compiler will inline very -aggressively and pack together reads and writes where possible. As a result, it -will not always be possible to hit breakpoints exactly where you want to -regarding the line of source code file. - -For this reason, the Makefile also provides the `make gdb-opt0` target, which -uses `-opt-level=0`. Hence, it will allow you to have finer debugging -granularity. However, please keep in mind that when debugging code that closely -deals with HW, a compiler optimization that squashes reads or writes to volatile -registers can make all the difference in execution. FYI, the demo gif above has -been recorded with `gdb-opt0`. - -#### GDB control - -At some point, you may reach delay loops or code that waits on user input from -the serial. Here, single stepping might not be feasible or work anymore. You can -jump over these roadblocks by setting other breakpoints beyond these areas, and -reach them using the `cont` command. - -Pressing `ctrl+c` in `gdb` will stop execution of the RPi again in case you -continued it without further breakpoints. - -## Notes on USB connection constraints - -If you followed the tutorial from top to bottom, everything should be fine -regarding USB connections. - -Still, please note that in its current form, our `Makefile` makes implicit -assumptions about the naming of the connected USB devices. It expects -`/dev/ttyUSB0` to be the `UART` device. - -Hence, please ensure the following order of connecting the devices to your box: - 1. Connect the USB serial. - 2. Afterwards, the Olimex debugger. - -This way, Linux enumerates the devices accordingly. This has to be done only -once. It is fine to disconnect and connect the serial multiple times, e.g. for -kicking off different `make jtagboot` runs, while keeping the debugger -connected. - -## In summary - -1. `make jtagboot` and keep terminal open. -2. Connect USB serial device. -3. Connect `JTAG` debugger USB device. -4. In new terminal, `make openocd`. -5. In new terminal, `make gdb` or make `make gdb-opt0`. - -## Acknowledgments - -Thanks to [@naotaco](https://github.com/naotaco) for laying the groundwork for -this tutorial. diff --git a/.0B_hw_debug_JTAG/kernel8 b/.0B_hw_debug_JTAG/kernel8 deleted file mode 100755 index 3e949a47eefa50afb79f13f6cb80da2824f389c0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 69680 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 TSS%9bz5RTbxY5{%D{jv}RE?E8 diff --git a/.0B_hw_debug_JTAG/link.ld b/.0B_hw_debug_JTAG/link.ld deleted file mode 100644 index 5c499f89..00000000 --- a/.0B_hw_debug_JTAG/link.ld +++ /dev/null @@ -1,55 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2018 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -ENTRY(_boot_cores); - -SECTIONS -{ - . = 0x80000; - - .text : - { - KEEP(*(.text.boot)) *(.text .text.*) - } - - .rodata : - { - *(.rodata .rodata.*) - } - - .data : - { - *(.data .data.*) - } - - .bss ALIGN(8): - { - __bss_start = .; - *(.bss .bss.*) - *(COMMON) - __bss_end = .; - } - - /DISCARD/ : { *(.comment) *(.gnu*) *(.note*) *(.eh_frame*) } -} diff --git a/.0B_hw_debug_JTAG/raspi3_boot/Cargo.toml b/.0B_hw_debug_JTAG/raspi3_boot/Cargo.toml deleted file mode 100644 index 024fd184..00000000 --- a/.0B_hw_debug_JTAG/raspi3_boot/Cargo.toml +++ /dev/null @@ -1,10 +0,0 @@ -[package] -name = "raspi3_boot" -version = "0.1.0" -authors = ["Andre Richter "] -edition = "2018" - -[dependencies] -cortex-a = "2.7.0" -panic-abort = "0.3.1" -r0 = "0.2.2" diff --git a/.0B_hw_debug_JTAG/raspi3_boot/src/lib.rs b/.0B_hw_debug_JTAG/raspi3_boot/src/lib.rs deleted file mode 100644 index a6b59ef1..00000000 --- a/.0B_hw_debug_JTAG/raspi3_boot/src/lib.rs +++ /dev/null @@ -1,102 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2018 Jorge Aparicio - * Copyright (c) 2018-2019 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#![deny(missing_docs)] -#![deny(warnings)] -#![no_std] - -//! Low-level boot of the Raspberry's processor - -extern crate panic_abort; - -/// Type check the user-supplied entry function. -#[macro_export] -macro_rules! entry { - ($path:path) => { - /// # Safety - /// - /// - User must ensure to provide a suitable main function for the - /// platform. - #[export_name = "main"] - pub unsafe fn __main() -> ! { - // type check the given path - let f: fn() -> ! = $path; - - f() - } - }; -} - -/// Reset function. -/// -/// Initializes the bss section before calling into the user's `main()`. -/// -/// # Safety -/// -/// - Only a single core must be active and running this function. -unsafe fn reset() -> ! { - extern "C" { - // Boundaries of the .bss section, provided by the linker script - static mut __bss_start: u64; - static mut __bss_end: u64; - } - - // Zeroes the .bss section - r0::zero_bss(&mut __bss_start, &mut __bss_end); - - extern "Rust" { - fn main() -> !; - } - - main(); -} - -/// Entrypoint of the processor. -/// -/// Parks all cores except core0, and then jumps to the internal -/// `reset()` function. -/// -/// # Safety -/// -/// - Linker script must ensure to place this function at `0x80_000`. -#[link_section = ".text.boot"] -#[no_mangle] -pub unsafe extern "C" fn _boot_cores() -> ! { - use cortex_a::{asm, regs::*}; - - const CORE_0: u64 = 0; - const CORE_MASK: u64 = 0x3; - const STACK_START: u64 = 0x80_000; - - if CORE_0 == MPIDR_EL1.get() & CORE_MASK { - SP.set(STACK_START); - reset() - } else { - // if not core0, infinitely wait for events - loop { - asm::wfe(); - } - } -} diff --git a/.0B_hw_debug_JTAG/src/delays.rs b/.0B_hw_debug_JTAG/src/delays.rs deleted file mode 100644 index b1c1fa0f..00000000 --- a/.0B_hw_debug_JTAG/src/delays.rs +++ /dev/null @@ -1,37 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2018-2019 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -use cortex_a::asm; - -/* - * - * Using the CPU's cycles - * - */ -/// Wait N CPU cycles (ARM CPU only) -pub fn wait_cycles(cyc: u32) { - for _ in 0..cyc { - asm::nop(); - } -} diff --git a/.0B_hw_debug_JTAG/src/gpio.rs b/.0B_hw_debug_JTAG/src/gpio.rs deleted file mode 100644 index ad104078..00000000 --- a/.0B_hw_debug_JTAG/src/gpio.rs +++ /dev/null @@ -1,121 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2018-2019 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -use super::MMIO_BASE; -use core::ops; -use register::{mmio::ReadWrite, register_bitfields}; - -// Descriptions taken from -// https://github.com/raspberrypi/documentation/files/1888662/BCM2837-ARM-Peripherals.-.Revised.-.V2-1.pdf -register_bitfields! { - u32, - - /// GPIO Function Select 1 - GPFSEL1 [ - /// Pin 15 - FSEL15 OFFSET(15) NUMBITS(3) [ - Input = 0b000, - Output = 0b001, - RXD0 = 0b100, // UART0 - Alternate function 0 - RXD1 = 0b010 // Mini UART - Alternate function 5 - - ], - - /// Pin 14 - FSEL14 OFFSET(12) NUMBITS(3) [ - Input = 0b000, - Output = 0b001, - TXD0 = 0b100, // UART0 - Alternate function 0 - TXD1 = 0b010 // Mini UART - Alternate function 5 - ] - ], - - /// GPIO Pull-up/down Clock Register 0 - GPPUDCLK0 [ - /// Pin 15 - PUDCLK15 OFFSET(15) NUMBITS(1) [ - NoEffect = 0, - AssertClock = 1 - ], - - /// Pin 14 - PUDCLK14 OFFSET(14) NUMBITS(1) [ - NoEffect = 0, - AssertClock = 1 - ] - ] -} - -const GPIO_BASE: u32 = MMIO_BASE + 0x200_000; - -#[allow(non_snake_case)] -#[repr(C)] -pub struct RegisterBlock { - pub GPFSEL0: ReadWrite, // 0x00 - pub GPFSEL1: ReadWrite, // 0x04 - pub GPFSEL2: ReadWrite, // 0x08 - pub GPFSEL3: ReadWrite, // 0x0C - pub GPFSEL4: ReadWrite, // 0x10 - pub GPFSEL5: ReadWrite, // 0x14 - __reserved_0: u32, // 0x18 - GPSET0: ReadWrite, // 0x1C - GPSET1: ReadWrite, // 0x20 - __reserved_1: u32, // - GPCLR0: ReadWrite, // 0x28 - __reserved_2: [u32; 2], // - GPLEV0: ReadWrite, // 0x34 - GPLEV1: ReadWrite, // 0x38 - __reserved_3: u32, // - GPEDS0: ReadWrite, // 0x40 - GPEDS1: ReadWrite, // 0x44 - __reserved_4: [u32; 7], // - GPHEN0: ReadWrite, // 0x64 - GPHEN1: ReadWrite, // 0x68 - __reserved_5: [u32; 10], // - pub GPPUD: ReadWrite, // 0x94 - pub GPPUDCLK0: ReadWrite, // 0x98 - pub GPPUDCLK1: ReadWrite, // 0x9C -} - -/// Public interface to the GPIO MMIO area -pub struct GPIO; - -impl ops::Deref for GPIO { - type Target = RegisterBlock; - - fn deref(&self) -> &Self::Target { - unsafe { &*Self::ptr() } - } -} - -impl GPIO { - pub fn new() -> GPIO { - GPIO - } - - /// Returns a pointer to the register block - fn ptr() -> *const RegisterBlock { - GPIO_BASE as *const _ - } -} diff --git a/.0B_hw_debug_JTAG/src/main.rs b/.0B_hw_debug_JTAG/src/main.rs deleted file mode 100644 index 281cc66f..00000000 --- a/.0B_hw_debug_JTAG/src/main.rs +++ /dev/null @@ -1,71 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2018-2019 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#![no_std] -#![no_main] - -const MMIO_BASE: u32 = 0x3F00_0000; - -mod delays; -mod gpio; -mod mbox; -mod power; -mod uart; - -fn kernel_entry() -> ! { - let gpio = gpio::GPIO::new(); - let mut mbox = mbox::Mbox::new(); - let uart = uart::Uart::new(); - let power = power::Power::new(); - - // set up serial console - match uart.init(&mut mbox, &gpio) { - Ok(_) => uart.puts("\n[0] UART is live!\n"), - Err(_) => loop { - cortex_a::asm::wfe() // If UART fails, abort early - }, - } - - uart.puts("[1] Press a key to continue booting... "); - uart.getc(); - uart.puts("Greetings fellow Rustacean!\n"); - - loop { - uart.puts("\n 1 - power off\n 2 - reset\nChoose one: "); - let c = uart.getc(); - uart.send(c); - - match c { - '1' => { - if power.off(&mut mbox, &gpio).is_err() { - uart.puts("Mailbox error in Power::off()"); - } - } - '2' => power.reset(), - _ => {} - } - } -} - -raspi3_boot::entry!(kernel_entry); diff --git a/.0B_hw_debug_JTAG/src/mbox.rs b/.0B_hw_debug_JTAG/src/mbox.rs deleted file mode 100644 index 484c494e..00000000 --- a/.0B_hw_debug_JTAG/src/mbox.rs +++ /dev/null @@ -1,163 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2018-2019 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -use super::MMIO_BASE; -use core::ops; -use cortex_a::asm; -use register::{ - mmio::{ReadOnly, WriteOnly}, - register_bitfields, -}; - -register_bitfields! { - u32, - - STATUS [ - FULL OFFSET(31) NUMBITS(1) [], - EMPTY OFFSET(30) NUMBITS(1) [] - ] -} - -const VIDEOCORE_MBOX: u32 = MMIO_BASE + 0xB880; - -#[allow(non_snake_case)] -#[repr(C)] -pub struct RegisterBlock { - READ: ReadOnly, // 0x00 - __reserved_0: [u32; 5], // 0x04 - STATUS: ReadOnly, // 0x18 - __reserved_1: u32, // 0x1C - WRITE: WriteOnly, // 0x20 -} - -// Custom errors -pub enum MboxError { - ResponseError, - UnknownError, -} -pub type Result = ::core::result::Result; - -// Channels -pub mod channel { - pub const PROP: u32 = 8; -} - -// Tags -pub mod tag { - pub const SETPOWER: u32 = 0x28001; - pub const SETCLKRATE: u32 = 0x38002; - pub const LAST: u32 = 0; -} - -// Clocks -pub mod clock { - pub const UART: u32 = 0x0_0000_0002; -} - -// Responses -mod response { - pub const SUCCESS: u32 = 0x8000_0000; - pub const ERROR: u32 = 0x8000_0001; // error parsing request buffer (partial response) -} - -pub const REQUEST: u32 = 0; - -// Public interface to the mailbox -#[repr(C)] -#[repr(align(16))] -pub struct Mbox { - // The address for buffer needs to be 16-byte aligned so that the - // Videcore can handle it properly. - pub buffer: [u32; 36], -} - -/// Deref to RegisterBlock -/// -/// Allows writing -/// ``` -/// self.STATUS.read() -/// ``` -/// instead of something along the lines of -/// ``` -/// unsafe { (*Mbox::ptr()).STATUS.read() } -/// ``` -impl ops::Deref for Mbox { - type Target = RegisterBlock; - - fn deref(&self) -> &Self::Target { - unsafe { &*Self::ptr() } - } -} - -impl Mbox { - pub fn new() -> Mbox { - Mbox { buffer: [0; 36] } - } - - /// Returns a pointer to the register block - fn ptr() -> *const RegisterBlock { - VIDEOCORE_MBOX as *const _ - } - - /// Make a mailbox call. Returns Err(MboxError) on failure, Ok(()) success - pub fn call(&self, channel: u32) -> Result<()> { - // wait until we can write to the mailbox - loop { - if !self.STATUS.is_set(STATUS::FULL) { - break; - } - - asm::nop(); - } - - let buf_ptr = self.buffer.as_ptr() as u32; - - // write the address of our message to the mailbox with channel identifier - self.WRITE.set((buf_ptr & !0xF) | (channel & 0xF)); - - // now wait for the response - loop { - // is there a response? - loop { - if !self.STATUS.is_set(STATUS::EMPTY) { - break; - } - - asm::nop(); - } - - let resp: u32 = self.READ.get(); - - // is it a response to our message? - if ((resp & 0xF) == channel) && ((resp & !0xF) == buf_ptr) { - // is it a valid successful response? - return match self.buffer[1] { - response::SUCCESS => Ok(()), - response::ERROR => Err(MboxError::ResponseError), - _ => Err(MboxError::UnknownError), - }; - } - } - } -} diff --git a/.0B_hw_debug_JTAG/src/power.rs b/.0B_hw_debug_JTAG/src/power.rs deleted file mode 100644 index 4b555a05..00000000 --- a/.0B_hw_debug_JTAG/src/power.rs +++ /dev/null @@ -1,143 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2018-2019 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -use super::MMIO_BASE; -use crate::delays; -use crate::gpio; -use crate::mbox; -use core::ops; -use core::sync::atomic::{compiler_fence, Ordering}; -use register::mmio::*; - -const POWER_BASE: u32 = MMIO_BASE + 0x100_01C; - -#[allow(non_snake_case)] -#[repr(C)] -pub struct RegisterBlock { - PM_RSTC: ReadWrite, // 0x1C - PM_RSTS: ReadWrite, // 0x20 - PM_WDOG: ReadWrite, // 0x24 -} - -const PM_PASSWORD: u32 = 0x5a_000_000; -const PM_RSTC_WRCFG_CLR: u32 = 0xffff_ffcf; -const PM_RSTC_WRCFG_FULL_RESET: u32 = 0x0000_0020; - -// The Raspberry Pi firmware uses the RSTS register to know which -// partition to boot from. The partition value is spread into bits 0, 2, -// 4, 6, 8, 10. Partition 63 is a special partition used by the -// firmware to indicate halt. -const PM_RSTS_RASPBERRYPI_HALT: u32 = 0x555; - -pub enum PowerError { - MailboxError, -} -pub type Result = ::core::result::Result; - -/// Public interface to the Power subsystem -pub struct Power; - -impl ops::Deref for Power { - type Target = RegisterBlock; - - fn deref(&self) -> &Self::Target { - unsafe { &*Self::ptr() } - } -} - -impl Power { - pub fn new() -> Power { - Power - } - - /// Returns a pointer to the register block - fn ptr() -> *const RegisterBlock { - POWER_BASE as *const _ - } - - /// Shutdown the board - pub fn off(&self, mbox: &mut mbox::Mbox, gpio: &gpio::GPIO) -> Result<()> { - // power off devices one by one - for dev_id in 0..16 { - mbox.buffer[0] = 8 * 4; - mbox.buffer[1] = mbox::REQUEST; - mbox.buffer[2] = mbox::tag::SETPOWER; - mbox.buffer[3] = 8; - mbox.buffer[4] = 8; - mbox.buffer[5] = dev_id; // device id - mbox.buffer[6] = 0; // bit 0: off, bit 1: no wait - mbox.buffer[7] = mbox::tag::LAST; - - // Insert a compiler fence that ensures that all stores to the - // mbox buffer are finished before the GPU is signaled (which - // is done by a store operation as well). - compiler_fence(Ordering::Release); - - if mbox.call(mbox::channel::PROP).is_err() { - return Err(PowerError::MailboxError); - }; - } - - // power off gpio pins (but not VCC pins) - gpio.GPFSEL0.set(0); - gpio.GPFSEL1.set(0); - gpio.GPFSEL2.set(0); - gpio.GPFSEL3.set(0); - gpio.GPFSEL4.set(0); - gpio.GPFSEL5.set(0); - - gpio.GPPUD.set(0); - delays::wait_cycles(150); - - gpio.GPPUDCLK0.set(0xffff_ffff); - gpio.GPPUDCLK1.set(0xffff_ffff); - delays::wait_cycles(150); - - // flush GPIO setup - gpio.GPPUDCLK0.set(0); - gpio.GPPUDCLK1.set(0); - - // We set the watchdog hard reset bit here to distinguish this - // reset from the normal (full) reset. bootcode.bin will not - // reboot after a hard reset. - let mut val = self.PM_RSTS.get(); - val |= PM_PASSWORD | PM_RSTS_RASPBERRYPI_HALT; - self.PM_RSTS.set(val); - - // Continue with normal reset mechanism - self.reset(); - } - - /// Reboot - pub fn reset(&self) -> ! { - // use a timeout of 10 ticks (~150us) - self.PM_WDOG.set(PM_PASSWORD | 10); - let mut val = self.PM_RSTC.get(); - val &= PM_RSTC_WRCFG_CLR; - val |= PM_PASSWORD | PM_RSTC_WRCFG_FULL_RESET; - self.PM_RSTC.set(val); - - loop {} - } -} diff --git a/.0B_hw_debug_JTAG/src/uart.rs b/.0B_hw_debug_JTAG/src/uart.rs deleted file mode 100644 index 28fdb206..00000000 --- a/.0B_hw_debug_JTAG/src/uart.rs +++ /dev/null @@ -1,262 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2018-2019 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -use super::MMIO_BASE; -use crate::delays; -use crate::gpio; -use crate::mbox; -use core::{ - ops, - sync::atomic::{compiler_fence, Ordering}, -}; -use cortex_a::asm; -use register::{mmio::*, register_bitfields}; - -// PL011 UART registers. -// -// Descriptions taken from -// https://github.com/raspberrypi/documentation/files/1888662/BCM2837-ARM-Peripherals.-.Revised.-.V2-1.pdf -register_bitfields! { - u32, - - /// Flag Register - FR [ - /// Transmit FIFO full. The meaning of this bit depends on the - /// state of the FEN bit in the UARTLCR_ LCRH 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 UARTLCR_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) [] - ], - - /// Integer Baud rate divisor - IBRD [ - /// Integer Baud rate divisor - IBRD OFFSET(0) NUMBITS(16) [] - ], - - /// Fractional Baud rate divisor - FBRD [ - /// Fractional Baud rate divisor - FBRD OFFSET(0) NUMBITS(6) [] - ], - - /// Line Control register - LCRH [ - /// Word length. These bits indicate the number of data bits - /// transmitted or received in a frame. - WLEN OFFSET(5) NUMBITS(2) [ - FiveBit = 0b00, - SixBit = 0b01, - SevenBit = 0b10, - EightBit = 0b11 - ] - ], - - /// Control Register - CR [ - /// Receive enable. If this bit is set to 1, the receive - /// section of the UART is enabled. Data reception occurs for - /// UART signals. 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 UART signals. 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 - 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 - ] - ], - - /// Interupt Clear Register - ICR [ - /// Meta field for all pending interrupts - ALL OFFSET(0) NUMBITS(11) [] - ] -} - -const UART_BASE: u32 = MMIO_BASE + 0x20_1000; - -#[allow(non_snake_case)] -#[repr(C)] -pub struct RegisterBlock { - DR: ReadWrite, // 0x00 - __reserved_0: [u32; 5], // 0x04 - FR: ReadOnly, // 0x18 - __reserved_1: [u32; 2], // 0x1c - IBRD: WriteOnly, // 0x24 - FBRD: WriteOnly, // 0x28 - LCRH: WriteOnly, // 0x2C - CR: WriteOnly, // 0x30 - __reserved_2: [u32; 4], // 0x34 - ICR: WriteOnly, // 0x44 -} - -pub enum UartError { - MailboxError, -} -pub type Result = ::core::result::Result; - -pub struct Uart; - -impl ops::Deref for Uart { - type Target = RegisterBlock; - - fn deref(&self) -> &Self::Target { - unsafe { &*Self::ptr() } - } -} - -impl Uart { - pub fn new() -> Uart { - Uart - } - - /// Returns a pointer to the register block - fn ptr() -> *const RegisterBlock { - UART_BASE as *const _ - } - - ///Set baud rate and characteristics (115200 8N1) and map to GPIO - pub fn init(&self, mbox: &mut mbox::Mbox, gpio: &gpio::GPIO) -> Result<()> { - // turn off UART0 - self.CR.set(0); - - // set up clock for consistent divisor values - mbox.buffer[0] = 9 * 4; - mbox.buffer[1] = mbox::REQUEST; - mbox.buffer[2] = mbox::tag::SETCLKRATE; - mbox.buffer[3] = 12; - mbox.buffer[4] = 8; - mbox.buffer[5] = mbox::clock::UART; // UART clock - mbox.buffer[6] = 4_000_000; // 4Mhz - mbox.buffer[7] = 0; // skip turbo setting - mbox.buffer[8] = mbox::tag::LAST; - - // Insert a compiler fence that ensures that all stores to the - // mbox buffer are finished before the GPU is signaled (which - // is done by a store operation as well). - compiler_fence(Ordering::Release); - - if mbox.call(mbox::channel::PROP).is_err() { - return Err(UartError::MailboxError); // Abort if UART clocks couldn't be set - }; - - // map UART0 to GPIO pins - gpio.GPFSEL1 - .modify(gpio::GPFSEL1::FSEL14::TXD0 + gpio::GPFSEL1::FSEL15::RXD0); - - gpio.GPPUD.set(0); // enable pins 14 and 15 - delays::wait_cycles(150); - - gpio.GPPUDCLK0.modify( - gpio::GPPUDCLK0::PUDCLK14::AssertClock + gpio::GPPUDCLK0::PUDCLK15::AssertClock, - ); - delays::wait_cycles(150); - - gpio.GPPUDCLK0.set(0); - - self.ICR.write(ICR::ALL::CLEAR); - self.IBRD.write(IBRD::IBRD.val(2)); // Results in 115200 baud - self.FBRD.write(FBRD::FBRD.val(0xB)); - self.LCRH.write(LCRH::WLEN::EightBit); // 8N1 - self.CR - .write(CR::UARTEN::Enabled + CR::TXE::Enabled + CR::RXE::Enabled); - - Ok(()) - } - - /// Send a character - pub fn send(&self, c: char) { - // wait until we can send - loop { - if !self.FR.is_set(FR::TXFF) { - break; - } - - asm::nop(); - } - - // write the character to the buffer - self.DR.set(c as u32); - } - - /// Receive a character - pub fn getc(&self) -> char { - // wait until something is in the buffer - loop { - if !self.FR.is_set(FR::RXFE) { - break; - } - - asm::nop(); - } - - // read it and return - let mut ret = self.DR.get() as u8 as char; - - // convert carrige return to newline - if ret == '\r' { - ret = '\n' - } - - ret - } - - /// Display a string - pub fn puts(&self, string: &str) { - for c in string.chars() { - // convert newline to carrige return + newline - if c == '\n' { - self.send('\r') - } - - self.send(c); - } - } -} diff --git a/.0C_exception_levels/.cargo/config b/.0C_exception_levels/.cargo/config deleted file mode 100644 index de3f84c9..00000000 --- a/.0C_exception_levels/.cargo/config +++ /dev/null @@ -1,5 +0,0 @@ -[target.aarch64-unknown-none-softfloat] -rustflags = [ - "-C", "link-arg=-Tlink.ld", - "-C", "target-cpu=cortex-a53", -] diff --git a/.0C_exception_levels/Cargo.lock b/.0C_exception_levels/Cargo.lock deleted file mode 100644 index d218ad56..00000000 --- a/.0C_exception_levels/Cargo.lock +++ /dev/null @@ -1,57 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -[[package]] -name = "cortex-a" -version = "2.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "register 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "kernel8" -version = "0.1.0" -dependencies = [ - "cortex-a 2.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "raspi3_boot 0.1.0", - "register 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "panic-abort" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "r0" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "raspi3_boot" -version = "0.1.0" -dependencies = [ - "cortex-a 2.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "panic-abort 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "r0 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "register" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "tock-registers 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tock-registers" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[metadata] -"checksum cortex-a 2.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cbb16c411ab74044f174746a6cbae67bcdebea126e376b5441e5986e6a6aa950" -"checksum panic-abort 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2c14a66511ed17b6a8b4256b868d7fd207836d891db15eea5195dbcaf87e630f" -"checksum r0 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e2a38df5b15c8d5c7e8654189744d8e396bddc18ad48041a500ce52d6948941f" -"checksum register 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "469bb5ddde81d67fb8bba4e14d77689b8166cfd077abe7530591cefe29d05823" -"checksum tock-registers 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c758f5195a2e0df9d9fecf6f506506b2766ff74cf64db1e995c87e2761a5c3e2" diff --git a/.0C_exception_levels/Cargo.toml b/.0C_exception_levels/Cargo.toml deleted file mode 100644 index 43d1e22e..00000000 --- a/.0C_exception_levels/Cargo.toml +++ /dev/null @@ -1,13 +0,0 @@ -[package] -name = "kernel8" -version = "0.1.0" -authors = ["Andre Richter "] -edition = "2018" - -[dependencies] -raspi3_boot = { path = "raspi3_boot" } -cortex-a = "2.7.0" -register = "0.3.3" - -[package.metadata.cargo-xbuild] -sysroot_path = "../xbuild_sysroot" diff --git a/.0C_exception_levels/Makefile b/.0C_exception_levels/Makefile deleted file mode 100644 index e5d41e64..00000000 --- a/.0C_exception_levels/Makefile +++ /dev/null @@ -1,105 +0,0 @@ -# -# MIT License -# -# Copyright (c) 2018-2019 Andre Richter -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# - -TARGET = aarch64-unknown-none-softfloat - -SOURCES = $(wildcard **/*.rs) $(wildcard **/*.S) link.ld - - -XRUSTC_CMD = cargo xrustc --target=$(TARGET) --release -CARGO_OUTPUT = target/$(TARGET)/release/kernel8 - -OBJCOPY = cargo objcopy -- -OBJCOPY_PARAMS = --strip-all -O binary - -CONTAINER_UTILS = andrerichter/raspi3-utils -CONTAINER_OPENOCD = andrerichter/raspi3-openocd -# CONTAINER_OPENOCD_ARG = -f openocd/tcl/interface/ftdi/olimex-jtag-tiny.cfg -f /openocd/rpi3.cfg - -CONTAINER_GDB = andrerichter/raspi3-gdb - -DOCKER_CMD = docker run -it --rm -DOCKER_ARG_CURDIR = -v $(shell pwd):/work -w /work -DOCKER_ARG_TTY = --privileged -v /dev:/dev -DOCKER_ARG_JTAG = -v $(shell pwd)/../X1_JTAG_boot:/jtag -DOCKER_ARG_NET = --network host - -DOCKER_EXEC_QEMU = qemu-system-aarch64 -M raspi3 -kernel kernel8.img -DOCKER_EXEC_RASPBOOT = raspbootcom -DOCKER_EXEC_RASPBOOT_DEV = /dev/ttyUSB0 -# DOCKER_EXEC_RASPBOOT_DEV = /dev/ttyACM0 - - -.PHONY: all qemu raspboot clippy clean objdump nm jtagboot openocd gdb gdb-opt0 - -all: clean kernel8.img - -$(CARGO_OUTPUT): $(SOURCES) - $(XRUSTC_CMD) - -kernel8.img: $(CARGO_OUTPUT) - cp $< . - $(OBJCOPY) $(OBJCOPY_PARAMS) $< kernel8.img - -qemu: all - $(DOCKER_CMD) $(DOCKER_ARG_CURDIR) $(CONTAINER_UTILS) \ - $(DOCKER_EXEC_QEMU) -serial stdio - -raspboot: all - $(DOCKER_CMD) $(DOCKER_ARG_CURDIR) $(DOCKER_ARG_TTY) \ - $(CONTAINER_UTILS) $(DOCKER_EXEC_RASPBOOT) $(DOCKER_EXEC_RASPBOOT_DEV) \ - kernel8.img - -clippy: - cargo xclippy --target=$(TARGET) - -clean: - cargo clean - -objdump: - cargo objdump --target $(TARGET) -- -disassemble -print-imm-hex kernel8 - -nm: - cargo nm --target $(TARGET) -- kernel8 | sort - -jtagboot: - $(DOCKER_CMD) $(DOCKER_ARG_TTY) $(DOCKER_ARG_JTAG) $(CONTAINER_UTILS) \ - $(DOCKER_EXEC_RASPBOOT) $(DOCKER_EXEC_RASPBOOT_DEV) /jtag/jtag_boot.img - -openocd: - $(DOCKER_CMD) $(DOCKER_ARG_TTY) $(DOCKER_ARG_NET) $(CONTAINER_OPENOCD) \ - $(CONTAINER_OPENOCD_ARG) - -define gen_gdb - $(XRUSTC_CMD) -- $1 - cp $(CARGO_OUTPUT) kernel8_for_jtag - $(DOCKER_CMD) $(DOCKER_ARG_CURDIR) $(DOCKER_ARG_NET) $(CONTAINER_GDB) \ - gdb-multiarch -q kernel8_for_jtag -endef - -gdb: clean $(SOURCES) - $(call gen_gdb,-C debuginfo=2) - -gdb-opt0: clean $(SOURCES) - $(call gen_gdb,-C debuginfo=2 -C opt-level=0) diff --git a/.0C_exception_levels/README.md b/.0C_exception_levels/README.md deleted file mode 100644 index 738e8665..00000000 --- a/.0C_exception_levels/README.md +++ /dev/null @@ -1,170 +0,0 @@ -# Tutorial 0C - Exception Levels - -In `AArch64`, there are four so-called exception levels: - -| Exception Level | Typically used for | -| ------------- | ------------- | -| EL0 | Userspace applications | -| EL1 | OS Kernel | -| EL2 | Hypervisor | -| EL3 | Low-Level Firmware | - -If you are familiar with the `x86` architecture, `ELs` are the counterpart to [privilege rings](https://en.wikipedia.org/wiki/Protection_ring). - -At this point, I strongly recommend that you glimpse over `Chapter 3` of the [Programmer’s Guide for ARMv8-A](http://infocenter.arm.com/help/topic/com.arm.doc.den0024a/DEN0024A_v8_architecture_PG.pdf) before you continue. -It gives a concise overview about the topic. - -## Scope of this tutorial - -If you set up your SD Card exactly like mentioned in the repository's [top-level README](../README.md#prerequisites), -our binary will start executing in `EL2`. Since we have an OS-focus, we will now write code that will cause a transition -into the more appropriate `EL1`. - -## Checking for EL2 in the entrypoint - -First of all, we need to ensure that we actually run in `EL2` before we can call respective code to transition to EL1: - -```rust -/// Entrypoint of the processor. -/// -/// Parks all cores except core0 and checks if we started in EL2. If -/// so, proceeds with setting up EL1. -#[link_section = ".text.boot"] -#[no_mangle] -pub unsafe extern "C" fn _boot_cores() -> ! { - use cortex_a::{asm, regs::*}; - - const CORE_0: u64 = 0; - const CORE_MASK: u64 = 0x3; - const EL2: u32 = CurrentEL::EL::EL2.value; - - if (CORE_0 == MPIDR_EL1.get() & CORE_MASK) && (EL2 == CurrentEL.get()) { - setup_and_enter_el1_from_el2() - } - - // if not core0 or EL != 2, infinitely wait for events - loop { - asm::wfe(); - } -} -``` - -If this is the case, we continue with preparing the `EL2` -> `EL1` transition in `setup_and_enter_el1_from_el2()`. - -## Transition preparation - -Since `EL2` is more privileged than `EL1`, it has control over various processor features and can allow or disallow -`EL1` code to use them. One such example is access to timer and counter registers. We are already using them since -[tutorial 09_delays](../09_delays/), so we want to keep them. Therefore we set the respective flags in the -[Counter-timer Hypervisor Control register](https://docs.rs/cortex-a/2.4.0/src/cortex_a/regs/cnthctl_el2.rs.html) -and additionally set the virtual offset to zero so that we get the real physical value everytime: - -```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); -``` - -Next, we configure the [Hypervisor Configuration Register](https://docs.rs/cortex-a/2.4.0/src/cortex_a/regs/hcr_el2.rs.html) such that `EL1` should actually run in `AArch64` mode, and not in `AArch32`, which would also be possible. - -```rust -// Set EL1 execution state to AArch64 -HCR_EL2.write(HCR_EL2::RW::EL1IsAarch64; -``` - -## Returning from an exception that never happened - -There is actually only one way to transition from a higher EL to a lower EL, which is by way of executing -the [ERET](https://docs.rs/cortex-a/2.4.0/src/cortex_a/asm.rs.html#49-62) instruction. - -This instruction will copy the contents of the [Saved Program Status Register - EL2](https://docs.rs/cortex-a/2.4.0/src/cortex_a/regs/spsr_el2.rs.html) -to `Current Program Status Register - EL1` and jump to the instruction address that is stored in the [Exception Link Register - EL2](https://docs.rs/cortex-a/2.4.0/src/cortex_a/regs/elr_el2.rs.html). - -This is basically the reverse of what is happening when an exception is taken. You'll learn about it in tutorial [10_exception_groundwork](../10_exceptions_groundwork). - -```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 reset(). -ELR_EL2.set(reset as *const () as u64); -``` - -As you can see, we are populating `ELR_EL2` with the address of the [reset()](raspi3_boot/src/lib.rs#L51) function that we earlier used to call directly from the entrypoint. - -Finally, we set the stack pointer for `SP_EL1` and call `ERET`: - -```rust -// Set up SP_EL1 (stack pointer), which will be used by EL1 once -// we "return" to it. -SP_EL1.set(STACK_START); - -// Use `eret` to "return" to EL1. This will result in execution of -// `reset()` in EL1. -asm::eret() -``` - -## Are we stackless? - -We just wrote a big rust function, `setup_and_enter_el1_from_el2()`, that is executed in a context where we -do not have a stack yet. We should double-check the generated machine code: - -```console -ferris@box:~$ make objdump -cargo objdump --target aarch64-unknown-none-softfloat -- -disassemble -print-imm-hex kernel8 - -kernel8: file format ELF64-aarch64-little - -Disassembly of section .text: -raspi3_boot::setup_and_enter_el1_from_el2::hf5d23e5bead7ee4e: - 808bc: e8 03 1f aa mov x8, xzr - 808c0: e9 07 00 32 orr w9, wzr, #0x3 - 808c4: 09 e1 1c d5 msr CNTHCTL_EL2, x9 - 808c8: 68 e0 1c d5 msr CNTVOFF_EL2, x8 - 808cc: 08 00 00 90 adrp x8, #0x0 - 808d0: ea 03 01 32 orr w10, wzr, #0x80000000 - 808d4: 0a 11 1c d5 msr HCR_EL2, x10 - 808d8: ab 78 80 52 mov w11, #0x3c5 - 808dc: 0b 40 1c d5 msr SPSR_EL2, x11 - 808e0: ec 03 0d 32 orr w12, wzr, #0x80000 - 808e4: 08 21 22 91 add x8, x8, #0x888 - 808e8: 28 40 1c d5 msr ELR_EL2, x8 - 808ec: 0c 41 1c d5 msr SP_EL1, x12 - 808f0: e0 03 9f d6 eret -``` - -Looks good! Thanks zero-overhead abstractions in the [cortex-a](https://github.com/rust-embedded/cortex-a) crate! :heart_eyes: - -## Testing - -In `main.rs`, we added some tests to see if access to the counter timer registers is actually working, and if the mask bits in `SPSR_EL2` made it to `EL1` as well: - -```console -ferris@box:~$ make raspboot - -[0] UART is live! -[1] Press a key to continue booting... Greetings fellow Rustacean! -[i] Executing in EL: 1 - -Testing EL1 access to timer registers: - Delaying for 3 seconds now. - 1..2..3 - Works! - -Checking interrupt mask bits: - D: Masked. - A: Masked. - I: Masked. - F: Masked. -``` diff --git a/.0C_exception_levels/kernel8 b/.0C_exception_levels/kernel8 deleted file mode 100755 index ffe4d6b3e88981e8fa8f084913ecfa369f9fd36d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 70904 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

%NB`?zke8+vipMay;G>jrqM@F0Z$S zyE~am@=*`Saj)0c<@WgpcqIjoYr~4oRoUBUHKVpnGj4U zByKooVi$}dUI=c99_Er|F{WL%48$dvUFode?4poeOvx?)nV`|``T8TwK#WbA@9X)&Jida!b?*QE{05%q{$7C| zc^h6V%P)+@P+q+~{1fD73v|}=;Qke{jv)Wcwi=wKtMMA95@LAH*H;+ep}Vq}&l2am z#JJuNt-Y_v)xVhQqc~R|<64(yZF@zo&lhvG$GN&8>&sbTZAj#Ae2Ey_ff1L8(*rpV zIqS(}ukK6m*wGhG^yePr!-YN;*OE+m3u)bAOtsp$-ket-?VYfHx@ z5=zE727PwNI%^g%QS=1!a}06nR*_7xDKE1UJ7fG=)FyL!_aIK^3QI^weo$mi=QgDf zo2d6IH?ccJ_$!Tk7#zwnlu095L3uNrcNBsH^?VI_`)7V9F|IklJ% z_!)8{zf!ti*;wyaE@Y9=$!a;++am|Rye{pSnLH}Aev{Aci{ZG(_?_Srb*rsKZ{?J&;o=;o z`KT?~BP^~pi0d@sk`r-VLw=I+egXNMkX^!JrvIW>Q1hgXe~}HtXvoJ*XANpojT%*H z^Nt&_I!0@_TUviV>LCxE><@X^oK3DLfmy478m4H`E*@V_i>8rzd5}zDu551}*Unew zlh&`EI{r9)LdqQ%(o4Qi%`0tk6$Ql%5*R~X9=>e}CI6S4h=a{!9eiT@uRbv&?Ei<& z=EIGaP!gjohbdgZ)GmivzksnUhmjXBTbIM+E?~^dVX_x68D%<+?Kht(4CcaeyvurH=KBdK7!gz<^^-$L)65eJI{#rRfo;^cMUnJo7E z1es&9QQ*IQ7T>q*T^II+ZagpSjO2wGhlE}BUAtdN=LQrhBQLzt0(tBDKoQRLs=RPS zxPTo)@7PqY&((aC?%cbX+8qwn>!rRH>T@-z9_mq#y1YKs;zw=#*tLy*0GN8%EbVV*2J9x)Z8}KzS1C5?^3q1vXR1l6+kBAj^Dw9F)U9?f z*WnZbYEx-LOACw4Y&O&PJ*vv?UV21rY-~A3l{T->?ojQ`pl}_eJKI%9TPzK(W@KU; Hm8Aawe0zV> diff --git a/.0C_exception_levels/link.ld b/.0C_exception_levels/link.ld deleted file mode 100644 index 5c499f89..00000000 --- a/.0C_exception_levels/link.ld +++ /dev/null @@ -1,55 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2018 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -ENTRY(_boot_cores); - -SECTIONS -{ - . = 0x80000; - - .text : - { - KEEP(*(.text.boot)) *(.text .text.*) - } - - .rodata : - { - *(.rodata .rodata.*) - } - - .data : - { - *(.data .data.*) - } - - .bss ALIGN(8): - { - __bss_start = .; - *(.bss .bss.*) - *(COMMON) - __bss_end = .; - } - - /DISCARD/ : { *(.comment) *(.gnu*) *(.note*) *(.eh_frame*) } -} diff --git a/.0C_exception_levels/raspi3_boot/Cargo.toml b/.0C_exception_levels/raspi3_boot/Cargo.toml deleted file mode 100644 index 024fd184..00000000 --- a/.0C_exception_levels/raspi3_boot/Cargo.toml +++ /dev/null @@ -1,10 +0,0 @@ -[package] -name = "raspi3_boot" -version = "0.1.0" -authors = ["Andre Richter "] -edition = "2018" - -[dependencies] -cortex-a = "2.7.0" -panic-abort = "0.3.1" -r0 = "0.2.2" diff --git a/.0C_exception_levels/raspi3_boot/src/lib.rs b/.0C_exception_levels/raspi3_boot/src/lib.rs deleted file mode 100644 index 01ccd956..00000000 --- a/.0C_exception_levels/raspi3_boot/src/lib.rs +++ /dev/null @@ -1,141 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2018 Jorge Aparicio - * Copyright (c) 2018-2019 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#![deny(missing_docs)] -#![deny(warnings)] -#![no_std] - -//! Low-level boot of the Raspberry's processor - -extern crate panic_abort; - -/// Type check the user-supplied entry function. -#[macro_export] -macro_rules! entry { - ($path:path) => { - /// # Safety - /// - /// - User must ensure to provide a suitable main function for the - /// platform. - #[export_name = "main"] - pub unsafe fn __main() -> ! { - // type check the given path - let f: fn() -> ! = $path; - - f() - } - }; -} - -/// Reset function. -/// -/// Initializes the bss section before calling into the user's `main()`. -/// -/// # Safety -/// -/// - Only a single core must be active and running this function. -unsafe fn reset() -> ! { - extern "C" { - // Boundaries of the .bss section, provided by the linker script - static mut __bss_start: u64; - static mut __bss_end: u64; - } - - // Zeroes the .bss section - r0::zero_bss(&mut __bss_start, &mut __bss_end); - - extern "Rust" { - fn main() -> !; - } - - main() -} - -/// Prepare and execute transition from EL2 to EL1. -#[inline] -fn setup_and_enter_el1_from_el2() -> ! { - use cortex_a::{asm, regs::*}; - - const STACK_START: u64 = 0x80_000; - - // 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 reset(). - ELR_EL2.set(reset as *const () as u64); - - // Set up SP_EL1 (stack pointer), which will be used by EL1 once - // we "return" to it. - SP_EL1.set(STACK_START); - - // Use `eret` to "return" to EL1. This will result in execution of - // `reset()` in EL1. - asm::eret() -} - -/// Entrypoint of the processor. -/// -/// Parks all cores except core0 and checks if we started in EL2. If -/// so, proceeds with setting up EL1. -/// -/// # Safety -/// -/// - Linker script must ensure to place this function at `0x80_000`. -#[link_section = ".text.boot"] -#[no_mangle] -pub unsafe extern "C" fn _boot_cores() -> ! { - use cortex_a::{asm, regs::*}; - - const CORE_0: u64 = 0; - const CORE_MASK: u64 = 0x3; - const EL2: u32 = CurrentEL::EL::EL2.value; - - if (CORE_0 == MPIDR_EL1.get() & CORE_MASK) && (EL2 == CurrentEL.get()) { - setup_and_enter_el1_from_el2() - } - - // if not core0 or EL != 2, infinitely wait for events - loop { - asm::wfe(); - } -} diff --git a/.0C_exception_levels/src/delays.rs b/.0C_exception_levels/src/delays.rs deleted file mode 100644 index 585584f2..00000000 --- a/.0C_exception_levels/src/delays.rs +++ /dev/null @@ -1,68 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2018-2019 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -use cortex_a::asm; -use cortex_a::regs::*; - -/* - * - * Using the CPU's counter registers - * - */ -/// Wait N microsec (ARM CPU only) -pub fn wait_usec(n: u32) { - // Get the counter frequency - let frq = CNTFRQ_EL0.get(); - - // Calculate number of ticks - let tval = (u64::from(frq) * u64::from(n) / 1_000_000) as u32; - - // 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); - - loop { - // ISTATUS will be one when cval ticks have passed. Continuously check it. - if CNTP_CTL_EL0.is_set(CNTP_CTL_EL0::ISTATUS) { - break; - } - } - - // Disable counting again - CNTP_CTL_EL0.modify(CNTP_CTL_EL0::ENABLE::CLEAR); -} - -/* - * - * Using the CPU's cycles - * - */ -/// Wait N CPU cycles (ARM CPU only) -pub fn wait_cycles(cyc: u32) { - for _ in 0..cyc { - asm::nop(); - } -} diff --git a/.0C_exception_levels/src/gpio.rs b/.0C_exception_levels/src/gpio.rs deleted file mode 100644 index ad104078..00000000 --- a/.0C_exception_levels/src/gpio.rs +++ /dev/null @@ -1,121 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2018-2019 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -use super::MMIO_BASE; -use core::ops; -use register::{mmio::ReadWrite, register_bitfields}; - -// Descriptions taken from -// https://github.com/raspberrypi/documentation/files/1888662/BCM2837-ARM-Peripherals.-.Revised.-.V2-1.pdf -register_bitfields! { - u32, - - /// GPIO Function Select 1 - GPFSEL1 [ - /// Pin 15 - FSEL15 OFFSET(15) NUMBITS(3) [ - Input = 0b000, - Output = 0b001, - RXD0 = 0b100, // UART0 - Alternate function 0 - RXD1 = 0b010 // Mini UART - Alternate function 5 - - ], - - /// Pin 14 - FSEL14 OFFSET(12) NUMBITS(3) [ - Input = 0b000, - Output = 0b001, - TXD0 = 0b100, // UART0 - Alternate function 0 - TXD1 = 0b010 // Mini UART - Alternate function 5 - ] - ], - - /// GPIO Pull-up/down Clock Register 0 - GPPUDCLK0 [ - /// Pin 15 - PUDCLK15 OFFSET(15) NUMBITS(1) [ - NoEffect = 0, - AssertClock = 1 - ], - - /// Pin 14 - PUDCLK14 OFFSET(14) NUMBITS(1) [ - NoEffect = 0, - AssertClock = 1 - ] - ] -} - -const GPIO_BASE: u32 = MMIO_BASE + 0x200_000; - -#[allow(non_snake_case)] -#[repr(C)] -pub struct RegisterBlock { - pub GPFSEL0: ReadWrite, // 0x00 - pub GPFSEL1: ReadWrite, // 0x04 - pub GPFSEL2: ReadWrite, // 0x08 - pub GPFSEL3: ReadWrite, // 0x0C - pub GPFSEL4: ReadWrite, // 0x10 - pub GPFSEL5: ReadWrite, // 0x14 - __reserved_0: u32, // 0x18 - GPSET0: ReadWrite, // 0x1C - GPSET1: ReadWrite, // 0x20 - __reserved_1: u32, // - GPCLR0: ReadWrite, // 0x28 - __reserved_2: [u32; 2], // - GPLEV0: ReadWrite, // 0x34 - GPLEV1: ReadWrite, // 0x38 - __reserved_3: u32, // - GPEDS0: ReadWrite, // 0x40 - GPEDS1: ReadWrite, // 0x44 - __reserved_4: [u32; 7], // - GPHEN0: ReadWrite, // 0x64 - GPHEN1: ReadWrite, // 0x68 - __reserved_5: [u32; 10], // - pub GPPUD: ReadWrite, // 0x94 - pub GPPUDCLK0: ReadWrite, // 0x98 - pub GPPUDCLK1: ReadWrite, // 0x9C -} - -/// Public interface to the GPIO MMIO area -pub struct GPIO; - -impl ops::Deref for GPIO { - type Target = RegisterBlock; - - fn deref(&self) -> &Self::Target { - unsafe { &*Self::ptr() } - } -} - -impl GPIO { - pub fn new() -> GPIO { - GPIO - } - - /// Returns a pointer to the register block - fn ptr() -> *const RegisterBlock { - GPIO_BASE as *const _ - } -} diff --git a/.0C_exception_levels/src/main.rs b/.0C_exception_levels/src/main.rs deleted file mode 100644 index 1dc8a905..00000000 --- a/.0C_exception_levels/src/main.rs +++ /dev/null @@ -1,102 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2018-2019 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#![no_std] -#![no_main] - -const MMIO_BASE: u32 = 0x3F00_0000; - -mod delays; -mod gpio; -mod mbox; -mod uart; - -use cortex_a::regs::*; - -fn check_timer(uart: &uart::Uart) { - uart.puts( - "Testing EL1 access to timer registers:\ - \n Delaying for 3 seconds now.\n", - ); - delays::wait_usec(1_000_000); - uart.puts(" 1.."); - delays::wait_usec(1_000_000); - uart.puts("2.."); - delays::wait_usec(1_000_000); - uart.puts( - "3\ - \n Works!\n\n", - ); -} - -fn check_daif(uart: &uart::Uart) { - uart.puts("Checking interrupt mask bits:\n"); - - let daif = DAIF.extract(); - for x in &[ - (" D: ", DAIF::D), - (" A: ", DAIF::A), - (" I: ", DAIF::I), - (" F: ", DAIF::F), - ] { - uart.puts(x.0); - if daif.is_set(x.1) { - uart.puts("Masked.\n"); - } else { - uart.puts("Unmasked.\n"); - } - } -} - -fn kernel_entry() -> ! { - let gpio = gpio::GPIO::new(); - let mut mbox = mbox::Mbox::new(); - let uart = uart::Uart::new(); - - // set up serial console - match uart.init(&mut mbox, &gpio) { - Ok(_) => uart.puts("\n[0] UART is live!\n"), - Err(_) => loop { - cortex_a::asm::wfe() // If UART fails, abort early - }, - } - - uart.puts("[1] Press a key to continue booting... "); - uart.getc(); - uart.puts("Greetings fellow Rustacean!\n"); - - uart.puts("[i] Executing in EL: "); - uart.dec(CurrentEL.read(CurrentEL::EL)); - uart.puts("\n\n"); - - check_timer(&uart); - check_daif(&uart); - - // echo everything back - loop { - uart.send(uart.getc()); - } -} - -raspi3_boot::entry!(kernel_entry); diff --git a/.0C_exception_levels/src/mbox.rs b/.0C_exception_levels/src/mbox.rs deleted file mode 100644 index a9791c80..00000000 --- a/.0C_exception_levels/src/mbox.rs +++ /dev/null @@ -1,162 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2018-2019 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -use super::MMIO_BASE; -use core::ops; -use cortex_a::asm; -use register::{ - mmio::{ReadOnly, WriteOnly}, - register_bitfields, -}; - -register_bitfields! { - u32, - - STATUS [ - FULL OFFSET(31) NUMBITS(1) [], - EMPTY OFFSET(30) NUMBITS(1) [] - ] -} - -const VIDEOCORE_MBOX: u32 = MMIO_BASE + 0xB880; - -#[allow(non_snake_case)] -#[repr(C)] -pub struct RegisterBlock { - READ: ReadOnly, // 0x00 - __reserved_0: [u32; 5], // 0x04 - STATUS: ReadOnly, // 0x18 - __reserved_1: u32, // 0x1C - WRITE: WriteOnly, // 0x20 -} - -// Custom errors -pub enum MboxError { - ResponseError, - UnknownError, -} -pub type Result = ::core::result::Result; - -// Channels -pub mod channel { - pub const PROP: u32 = 8; -} - -// Tags -pub mod tag { - pub const SETCLKRATE: u32 = 0x38002; - pub const LAST: u32 = 0; -} - -// Clocks -pub mod clock { - pub const UART: u32 = 0x0_0000_0002; -} - -// Responses -mod response { - pub const SUCCESS: u32 = 0x8000_0000; - pub const ERROR: u32 = 0x8000_0001; // error parsing request buffer (partial response) -} - -pub const REQUEST: u32 = 0; - -// Public interface to the mailbox -#[repr(C)] -#[repr(align(16))] -pub struct Mbox { - // The address for buffer needs to be 16-byte aligned so that the - // Videcore can handle it properly. - pub buffer: [u32; 36], -} - -/// Deref to RegisterBlock -/// -/// Allows writing -/// ``` -/// self.STATUS.read() -/// ``` -/// instead of something along the lines of -/// ``` -/// unsafe { (*Mbox::ptr()).STATUS.read() } -/// ``` -impl ops::Deref for Mbox { - type Target = RegisterBlock; - - fn deref(&self) -> &Self::Target { - unsafe { &*Self::ptr() } - } -} - -impl Mbox { - pub fn new() -> Mbox { - Mbox { buffer: [0; 36] } - } - - /// Returns a pointer to the register block - fn ptr() -> *const RegisterBlock { - VIDEOCORE_MBOX as *const _ - } - - /// Make a mailbox call. Returns Err(MboxError) on failure, Ok(()) success - pub fn call(&self, channel: u32) -> Result<()> { - // wait until we can write to the mailbox - loop { - if !self.STATUS.is_set(STATUS::FULL) { - break; - } - - asm::nop(); - } - - let buf_ptr = self.buffer.as_ptr() as u32; - - // write the address of our message to the mailbox with channel identifier - self.WRITE.set((buf_ptr & !0xF) | (channel & 0xF)); - - // now wait for the response - loop { - // is there a response? - loop { - if !self.STATUS.is_set(STATUS::EMPTY) { - break; - } - - asm::nop(); - } - - let resp: u32 = self.READ.get(); - - // is it a response to our message? - if ((resp & 0xF) == channel) && ((resp & !0xF) == buf_ptr) { - // is it a valid successful response? - return match self.buffer[1] { - response::SUCCESS => Ok(()), - response::ERROR => Err(MboxError::ResponseError), - _ => Err(MboxError::UnknownError), - }; - } - } - } -} diff --git a/.0C_exception_levels/src/uart.rs b/.0C_exception_levels/src/uart.rs deleted file mode 100644 index d3f5796c..00000000 --- a/.0C_exception_levels/src/uart.rs +++ /dev/null @@ -1,282 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2018-2019 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -use super::MMIO_BASE; -use crate::delays; -use crate::gpio; -use crate::mbox; -use core::{ - ops, - sync::atomic::{compiler_fence, Ordering}, -}; -use cortex_a::asm; -use register::{mmio::*, register_bitfields}; - -// PL011 UART registers. -// -// Descriptions taken from -// https://github.com/raspberrypi/documentation/files/1888662/BCM2837-ARM-Peripherals.-.Revised.-.V2-1.pdf -register_bitfields! { - u32, - - /// Flag Register - FR [ - /// Transmit FIFO full. The meaning of this bit depends on the - /// state of the FEN bit in the UARTLCR_ LCRH 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 UARTLCR_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) [] - ], - - /// Integer Baud rate divisor - IBRD [ - /// Integer Baud rate divisor - IBRD OFFSET(0) NUMBITS(16) [] - ], - - /// Fractional Baud rate divisor - FBRD [ - /// Fractional Baud rate divisor - FBRD OFFSET(0) NUMBITS(6) [] - ], - - /// Line Control register - LCRH [ - /// Word length. These bits indicate the number of data bits - /// transmitted or received in a frame. - WLEN OFFSET(5) NUMBITS(2) [ - FiveBit = 0b00, - SixBit = 0b01, - SevenBit = 0b10, - EightBit = 0b11 - ] - ], - - /// Control Register - CR [ - /// Receive enable. If this bit is set to 1, the receive - /// section of the UART is enabled. Data reception occurs for - /// UART signals. 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 UART signals. 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 - 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 - ] - ], - - /// Interupt Clear Register - ICR [ - /// Meta field for all pending interrupts - ALL OFFSET(0) NUMBITS(11) [] - ] -} - -const UART_BASE: u32 = MMIO_BASE + 0x20_1000; - -#[allow(non_snake_case)] -#[repr(C)] -pub struct RegisterBlock { - DR: ReadWrite, // 0x00 - __reserved_0: [u32; 5], // 0x04 - FR: ReadOnly, // 0x18 - __reserved_1: [u32; 2], // 0x1c - IBRD: WriteOnly, // 0x24 - FBRD: WriteOnly, // 0x28 - LCRH: WriteOnly, // 0x2C - CR: WriteOnly, // 0x30 - __reserved_2: [u32; 4], // 0x34 - ICR: WriteOnly, // 0x44 -} - -pub enum UartError { - MailboxError, -} -pub type Result = ::core::result::Result; - -pub struct Uart; - -impl ops::Deref for Uart { - type Target = RegisterBlock; - - fn deref(&self) -> &Self::Target { - unsafe { &*Self::ptr() } - } -} - -impl Uart { - pub fn new() -> Uart { - Uart - } - - /// Returns a pointer to the register block - fn ptr() -> *const RegisterBlock { - UART_BASE as *const _ - } - - ///Set baud rate and characteristics (115200 8N1) and map to GPIO - pub fn init(&self, mbox: &mut mbox::Mbox, gpio: &gpio::GPIO) -> Result<()> { - // turn off UART0 - self.CR.set(0); - - // set up clock for consistent divisor values - mbox.buffer[0] = 9 * 4; - mbox.buffer[1] = mbox::REQUEST; - mbox.buffer[2] = mbox::tag::SETCLKRATE; - mbox.buffer[3] = 12; - mbox.buffer[4] = 8; - mbox.buffer[5] = mbox::clock::UART; // UART clock - mbox.buffer[6] = 4_000_000; // 4Mhz - mbox.buffer[7] = 0; // skip turbo setting - mbox.buffer[8] = mbox::tag::LAST; - - // Insert a compiler fence that ensures that all stores to the - // mbox buffer are finished before the GPU is signaled (which - // is done by a store operation as well). - compiler_fence(Ordering::Release); - - if mbox.call(mbox::channel::PROP).is_err() { - return Err(UartError::MailboxError); // Abort if UART clocks couldn't be set - }; - - // map UART0 to GPIO pins - gpio.GPFSEL1 - .modify(gpio::GPFSEL1::FSEL14::TXD0 + gpio::GPFSEL1::FSEL15::RXD0); - - gpio.GPPUD.set(0); // enable pins 14 and 15 - delays::wait_cycles(150); - - gpio.GPPUDCLK0.modify( - gpio::GPPUDCLK0::PUDCLK14::AssertClock + gpio::GPPUDCLK0::PUDCLK15::AssertClock, - ); - delays::wait_cycles(150); - - gpio.GPPUDCLK0.set(0); - - self.ICR.write(ICR::ALL::CLEAR); - self.IBRD.write(IBRD::IBRD.val(2)); // Results in 115200 baud - self.FBRD.write(FBRD::FBRD.val(0xB)); - self.LCRH.write(LCRH::WLEN::EightBit); // 8N1 - self.CR - .write(CR::UARTEN::Enabled + CR::TXE::Enabled + CR::RXE::Enabled); - - Ok(()) - } - - /// Send a character - pub fn send(&self, c: char) { - // wait until we can send - loop { - if !self.FR.is_set(FR::TXFF) { - break; - } - - asm::nop(); - } - - // write the character to the buffer - self.DR.set(c as u32); - } - - /// Receive a character - pub fn getc(&self) -> char { - // wait until something is in the buffer - loop { - if !self.FR.is_set(FR::RXFE) { - break; - } - - asm::nop(); - } - - // read it and return - let mut ret = self.DR.get() as u8 as char; - - // convert carrige return to newline - if ret == '\r' { - ret = '\n' - } - - ret - } - - /// Display a string - pub fn puts(&self, string: &str) { - for c in string.chars() { - // convert newline to carrige return + newline - if c == '\n' { - self.send('\r') - } - - self.send(c); - } - } - - /// Display a binary value in decimal - pub fn dec(&self, d: u32) { - let mut digits: [char; 10] = ['\0'; 10]; - let mut d = d; - - for i in digits.iter_mut() { - *i = ((d % 10) + 0x30) as u8 as char; - - d /= 10; - - if d == 0 { - break; - } - } - - for c in digits.iter().rev() { - self.send(*c); - } - } -} diff --git a/.0D_virtual_memory/.cargo/config b/.0D_virtual_memory/.cargo/config deleted file mode 100644 index de3f84c9..00000000 --- a/.0D_virtual_memory/.cargo/config +++ /dev/null @@ -1,5 +0,0 @@ -[target.aarch64-unknown-none-softfloat] -rustflags = [ - "-C", "link-arg=-Tlink.ld", - "-C", "target-cpu=cortex-a53", -] diff --git a/.0D_virtual_memory/Cargo.lock b/.0D_virtual_memory/Cargo.lock deleted file mode 100644 index d218ad56..00000000 --- a/.0D_virtual_memory/Cargo.lock +++ /dev/null @@ -1,57 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -[[package]] -name = "cortex-a" -version = "2.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "register 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "kernel8" -version = "0.1.0" -dependencies = [ - "cortex-a 2.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "raspi3_boot 0.1.0", - "register 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "panic-abort" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "r0" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "raspi3_boot" -version = "0.1.0" -dependencies = [ - "cortex-a 2.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "panic-abort 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "r0 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "register" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "tock-registers 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tock-registers" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[metadata] -"checksum cortex-a 2.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cbb16c411ab74044f174746a6cbae67bcdebea126e376b5441e5986e6a6aa950" -"checksum panic-abort 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2c14a66511ed17b6a8b4256b868d7fd207836d891db15eea5195dbcaf87e630f" -"checksum r0 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e2a38df5b15c8d5c7e8654189744d8e396bddc18ad48041a500ce52d6948941f" -"checksum register 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "469bb5ddde81d67fb8bba4e14d77689b8166cfd077abe7530591cefe29d05823" -"checksum tock-registers 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c758f5195a2e0df9d9fecf6f506506b2766ff74cf64db1e995c87e2761a5c3e2" diff --git a/.0D_virtual_memory/Cargo.toml b/.0D_virtual_memory/Cargo.toml deleted file mode 100644 index 43d1e22e..00000000 --- a/.0D_virtual_memory/Cargo.toml +++ /dev/null @@ -1,13 +0,0 @@ -[package] -name = "kernel8" -version = "0.1.0" -authors = ["Andre Richter "] -edition = "2018" - -[dependencies] -raspi3_boot = { path = "raspi3_boot" } -cortex-a = "2.7.0" -register = "0.3.3" - -[package.metadata.cargo-xbuild] -sysroot_path = "../xbuild_sysroot" diff --git a/.0D_virtual_memory/Makefile b/.0D_virtual_memory/Makefile deleted file mode 100644 index 78b808e6..00000000 --- a/.0D_virtual_memory/Makefile +++ /dev/null @@ -1,104 +0,0 @@ -# -# MIT License -# -# Copyright (c) 2018-2019 Andre Richter -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# - -TARGET = aarch64-unknown-none-softfloat - -SOURCES = $(wildcard **/*.rs) $(wildcard **/*.S) link.ld - - -XRUSTC_CMD = cargo xrustc --target=$(TARGET) --release -CARGO_OUTPUT = target/$(TARGET)/release/kernel8 - -OBJCOPY = cargo objcopy -- -OBJCOPY_PARAMS = --strip-all -O binary - -CONTAINER_UTILS = andrerichter/raspi3-utils -CONTAINER_OPENOCD = andrerichter/raspi3-openocd -# CONTAINER_OPENOCD_ARG = -f openocd/tcl/interface/ftdi/olimex-jtag-tiny.cfg -f /openocd/rpi3.cfg -CONTAINER_GDB = andrerichter/raspi3-gdb - -DOCKER_CMD = docker run -it --rm -DOCKER_ARG_CURDIR = -v $(shell pwd):/work -w /work -DOCKER_ARG_TTY = --privileged -v /dev:/dev -DOCKER_ARG_JTAG = -v $(shell pwd)/../X1_JTAG_boot:/jtag -DOCKER_ARG_NET = --network host - -DOCKER_EXEC_QEMU = qemu-system-aarch64 -M raspi3 -kernel kernel8.img -DOCKER_EXEC_RASPBOOT = raspbootcom -DOCKER_EXEC_RASPBOOT_DEV = /dev/ttyUSB0 -# DOCKER_EXEC_RASPBOOT_DEV = /dev/ttyACM0 - - -.PHONY: all qemu raspboot clippy clean objdump nm jtagboot openocd gdb gdb-opt0 - -all: clean kernel8.img - -$(CARGO_OUTPUT): $(SOURCES) - $(XRUSTC_CMD) - -kernel8.img: $(CARGO_OUTPUT) - cp $< . - $(OBJCOPY) $(OBJCOPY_PARAMS) $< kernel8.img - -qemu: all - $(DOCKER_CMD) $(DOCKER_ARG_CURDIR) $(CONTAINER_UTILS) \ - $(DOCKER_EXEC_QEMU) -serial stdio - -raspboot: all - $(DOCKER_CMD) $(DOCKER_ARG_CURDIR) $(DOCKER_ARG_TTY) \ - $(CONTAINER_UTILS) $(DOCKER_EXEC_RASPBOOT) \ - $(DOCKER_EXEC_RASPBOOT_DEV) kernel8.img - -clippy: - cargo xclippy --target=$(TARGET) - -clean: - cargo clean - -objdump: - cargo objdump --target $(TARGET) -- -disassemble -print-imm-hex kernel8 - -nm: - cargo nm --target $(TARGET) -- kernel8 | sort - -jtagboot: - $(DOCKER_CMD) $(DOCKER_ARG_TTY) $(DOCKER_ARG_JTAG) $(CONTAINER_UTILS) \ - $(DOCKER_EXEC_RASPBOOT) $(DOCKER_EXEC_RASPBOOT_DEV) /jtag/jtag_boot.img - -openocd: - $(DOCKER_CMD) $(DOCKER_ARG_TTY) $(DOCKER_ARG_NET) $(CONTAINER_OPENOCD) \ - $(CONTAINER_OPENOCD_ARG) - -define gen_gdb - $(XRUSTC_CMD) -- $1 - cp $(CARGO_OUTPUT) kernel8_for_jtag - $(DOCKER_CMD) $(DOCKER_ARG_CURDIR) $(DOCKER_ARG_NET) $(CONTAINER_GDB) \ - gdb-multiarch -q kernel8_for_jtag -endef - -gdb: clean $(SOURCES) - $(call gen_gdb,-C debuginfo=2) - -gdb-opt0: clean $(SOURCES) - $(call gen_gdb,-C debuginfo=2 -C opt-level=0) diff --git a/.0D_virtual_memory/README.md b/.0D_virtual_memory/README.md deleted file mode 100644 index b8fbbde2..00000000 --- a/.0D_virtual_memory/README.md +++ /dev/null @@ -1,206 +0,0 @@ -# Tutorial 0D - Virtual Memory - -Virtual memory is an immensely complex, but exciting topic. In this first -lesson, we start slow and switch on the MMU and use static page tables. We will -only be concerned about the first `1 GiB` of address space. That is the amount -of `DRAM` the usual Raspberry Pi 3 has. As we already know, the upper `16 MiB` -of this gigabyte-window are occupied by the Raspberry's peripherals such as the -UART. - -## MMU and paging theory - -At this point, we will not reinvent the wheel again and go into detailed -descriptions of how paging in modern application processors works. The internet -is full of great resources regarding this topic, and we encourage you to read -some of it to get a high-level understanding of the topic. - -To follow the rest of this `AArch64` specific tutorial, we strongly recommend -that you stop right here and first read `Chapter 12` of the [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) -before you continue. This will set you up with all the `AArch64`-specific -knowledge needed to follow along. - -Back from reading `Chapter 12` already? Good job :+1:! - -## Approach - -The following partitioning will be used for the static page tables: -- The first `2 MiB` will be mapped using a Level 3 table with `4 KiB` granule. - - This aperture includes, among others, the kernel's code, read-only data, and - mutable data. All of which will be `identity mapped` to make our life easy - for now. - - In the past, we already made sure that the linker script aligns the - respective regions to `4 KiB` boundaries. - - This way, we can conveniently flag corresponding regions in distinct page - table entries. E.g. marking the code regions executable, while the mutable - data regions are not. -- All the rest will be mapped using `2 MiB` granule. - -The actual code is divided into two files: `memory.rs` and `memory/mmu.rs`. - -### memory.rs - -This file is used to describe our kernel's memory layout in a high-level -abstraction using our own descriptor format. We can define ranges of arbitrary -length and set respective attributes, for example if the bits and bytes in this -range should be executable or not. - -The descriptors we use here are agnostic of the hardware `MMU`'s actual -descriptors, and we are also agnostic of the paging granule the `MMU` will use. -Having this distinction is less of a technical need and more a convenience -feature for us in order to easily describe the kernels memory layout, and -hopefully it makes the whole concept a bit more graspable for the reader. - -The file contains a global `static KERNEL_VIRTUAL_LAYOUT` array which -stores these descriptors. The policy is to only store regions that are **not** -ordinary, normal chacheable DRAM. However, nothing prevents you from defining -those too if you wish to. Here is an example for the device MMIO region: - -```rust -// Device MMIO -Descriptor { - virtual_range: || RangeInclusive::new(map::physical::MMIO_BASE, map::physical::MMIO_END), - translation: Translation::Identity, - attribute_fields: AttributeFields { - mem_attributes: MemAttributes::Device, - acc_perms: AccessPermissions::ReadWrite, - execute_never: true, - }, -}, -``` - -Finally, the file contains the following function: - -```rust -fn get_virt_addr_properties(virt_addr: usize) -> Result<(usize, AttributeFields), &'static str> -``` - -It will be used by code in `mmu.rs` to request attributes for a virtual address -and the translation of the address. The function scans `KERNEL_VIRTUAL_LAYOUT` -for a descriptor that contains the queried address, and returns the respective -findings for the first entry that is a hit. If no entry is found, it returns -default attributes for normal chacheable DRAM and the input address, hence -telling the `MMU` code that the requested address should be `identity mapped`. - -Due to this default return, it is not needed to define normal cacheable DRAM -regions in `KERNEL_VIRTUAL_LAYOUT`. - -### mmu.rs - -This file contains the `AArch64` specific code. It is a driver, if you like, and -the split in paging granule mentioned before is hardcoded here (`4 KiB` page -descriptors for the first `2 MiB` and `2 MiB` block descriptors for everything -else). - -Two static page table arrays are instantiated, `LVL2_TABLE` and `LVL3_TABLE`, -and they are populated using `get_virt_addr_properties()` and a bunch of utility -functions that convert our own descriptors to the actual `64 bit` descriptor -entries needed by the MMU hardware for the page table arrays. - -Each page table has an entry (`AttrIndex`) that indexes into the -[MAIR_EL1](http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0500d/CIHDHJBB.html) -register, which holds information about the cacheability of the respective -page. We currently define normal cacheable memory and device memory (which is -not cached). - -```rust -/// Setup function for the MAIR_EL1 register. -fn set_up_mair() { - // Define the memory types that we will map. Cacheable normal DRAM and - // device. - MAIR_EL1.write( - // Attribute 1 - MAIR_EL1::Attr1_HIGH::Memory_OuterWriteBack_NonTransient_ReadAlloc_WriteAlloc - + MAIR_EL1::Attr1_LOW_MEMORY::InnerWriteBack_NonTransient_ReadAlloc_WriteAlloc - - // Attribute 0 - + MAIR_EL1::Attr0_HIGH::Device - + MAIR_EL1::Attr0_LOW_DEVICE::Device_nGnRE, - ); -} -``` - -Afterwards, the [Translation Table Base Register 0 - EL1](https://docs.rs/crate/cortex-a/2.4.0/source/src/regs/ttbr0_el1.rs) is set up with the base address of the `LVL3_TABLE` and -the [Translation Control Register - EL1](https://docs.rs/crate/cortex-a/2.4.0/source/src/regs/tcr_el1.rs) is -configured. - -Finally, the MMU is turned on through the [System Control Register - EL1](https://docs.rs/crate/cortex-a/2.4.0/source/src/regs/sctlr_el1.rs). The last step also enables caching for data and instructions. - -## Address translation examples - -For educational purposes, in `memory.rs`, a layout is defined which allows to -access the `UART` via two different virtual addresses: -- Since we identity map the whole `Device MMIO` region, it is accessible by -asserting its physical base address (`0x3F20_1000`) after the `MMU` is turned -on. -- Additionally, it is also mapped into the last `4 KiB` entry of the `LVL3` -table, making it accessible through base address `0x001F_F000`. - -The following two block diagrams visualize the underlying translations for the -two mappings, accessing the UART's Control Register (`CR`, offset `0x30`). - -### Adress translation using a 2 MiB block descriptor - -![2 MiB translation block diagram](../doc/page_tables_2MiB.png) - -### Adress translation using a 4 KiB page descriptor - -![4 KiB translation block diagram](../doc/page_tables_4KiB.png) - - -## Zero-cost abstraction - -The MMU init code is also a good example to see the great potential of Rust's -zero-cost abstractions[[1]](https://blog.rust-lang.org/2015/05/11/traits.html)[[2]](https://ruudvanasseldonk.com/2016/11/30/zero-cost-abstractions) for embedded programming. - -Take this piece of code for setting up the `MAIR_EL1` register using the -[cortex-a](https://crates.io/crates/cortex-a) crate: - - - -```rust -/// Setup function for the MAIR_EL1 register. -fn set_up_mair() { - // Define the memory types that we will map. Cacheable normal DRAM and - // device. - MAIR_EL1.write( - // Attribute 1 - MAIR_EL1::Attr1_HIGH::Memory_OuterWriteBack_NonTransient_ReadAlloc_WriteAlloc - + MAIR_EL1::Attr1_LOW_MEMORY::InnerWriteBack_NonTransient_ReadAlloc_WriteAlloc - - // Attribute 0 - + MAIR_EL1::Attr0_HIGH::Device - + MAIR_EL1::Attr0_LOW_DEVICE::Device_nGnRE, - ); -} -``` - -This piece of code is super expressive, and it makes use of `traits`, different -`types` and `constants` to provide type-safe register manipulation. - -In the end, this code sets the first four bytes of the register to certain -values according to the data sheet. Looking at the generated code, we can see -that despite all the type-safety and abstractions, we get super lean code: - -```text -00000000000803ac kernel8::memory::mmu::init::h7ef502c5548c1a62: - ... - 803cc: 88 e0 9f 52 mov w8, #0xff04 - ... - 803d8: 08 a2 18 d5 msr MAIR_EL1, x8 -``` - -## Output - -```console -ferris@box:~$ make raspboot - -[0] UART is live! -[1] Press a key to continue booting... Greetings fellow Rustacean! -[i] MMU: 4 KiB granule supported! -[i] MMU: Up to 40 Bit physical address range supported! -[2] MMU online. - -Writing through the virtual mapping at base address 0x00000000001FF000. -``` diff --git a/.0D_virtual_memory/kernel8 b/.0D_virtual_memory/kernel8 deleted file mode 100755 index e37ffda1e4654f1b4183afd3cdfe5b95049f262c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 74112 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 VZgzeLx - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -ENTRY(_boot_cores); - -SECTIONS -{ - . = 0x80000; /* This is already 4KiB aligned */ - __ro_start = .; - .text : - { - KEEP(*(.text.boot)) *(.text .text.*) - } - - .rodata : - { - *(.rodata .rodata.*) - } - . = ALIGN(4096); /* Fill up to 4KiB */ - __ro_end = .; - - .data : - { - *(.data .data.*) - } - - .bss ALIGN(8): - { - __bss_start = .; - *(.bss .bss.*) - *(COMMON) - __bss_end = .; - } - - /DISCARD/ : { *(.comment) *(.gnu*) *(.note*) *(.eh_frame*) } -} diff --git a/.0D_virtual_memory/raspi3_boot/Cargo.toml b/.0D_virtual_memory/raspi3_boot/Cargo.toml deleted file mode 100644 index 024fd184..00000000 --- a/.0D_virtual_memory/raspi3_boot/Cargo.toml +++ /dev/null @@ -1,10 +0,0 @@ -[package] -name = "raspi3_boot" -version = "0.1.0" -authors = ["Andre Richter "] -edition = "2018" - -[dependencies] -cortex-a = "2.7.0" -panic-abort = "0.3.1" -r0 = "0.2.2" diff --git a/.0D_virtual_memory/raspi3_boot/src/lib.rs b/.0D_virtual_memory/raspi3_boot/src/lib.rs deleted file mode 100644 index 01ccd956..00000000 --- a/.0D_virtual_memory/raspi3_boot/src/lib.rs +++ /dev/null @@ -1,141 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2018 Jorge Aparicio - * Copyright (c) 2018-2019 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#![deny(missing_docs)] -#![deny(warnings)] -#![no_std] - -//! Low-level boot of the Raspberry's processor - -extern crate panic_abort; - -/// Type check the user-supplied entry function. -#[macro_export] -macro_rules! entry { - ($path:path) => { - /// # Safety - /// - /// - User must ensure to provide a suitable main function for the - /// platform. - #[export_name = "main"] - pub unsafe fn __main() -> ! { - // type check the given path - let f: fn() -> ! = $path; - - f() - } - }; -} - -/// Reset function. -/// -/// Initializes the bss section before calling into the user's `main()`. -/// -/// # Safety -/// -/// - Only a single core must be active and running this function. -unsafe fn reset() -> ! { - extern "C" { - // Boundaries of the .bss section, provided by the linker script - static mut __bss_start: u64; - static mut __bss_end: u64; - } - - // Zeroes the .bss section - r0::zero_bss(&mut __bss_start, &mut __bss_end); - - extern "Rust" { - fn main() -> !; - } - - main() -} - -/// Prepare and execute transition from EL2 to EL1. -#[inline] -fn setup_and_enter_el1_from_el2() -> ! { - use cortex_a::{asm, regs::*}; - - const STACK_START: u64 = 0x80_000; - - // 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 reset(). - ELR_EL2.set(reset as *const () as u64); - - // Set up SP_EL1 (stack pointer), which will be used by EL1 once - // we "return" to it. - SP_EL1.set(STACK_START); - - // Use `eret` to "return" to EL1. This will result in execution of - // `reset()` in EL1. - asm::eret() -} - -/// Entrypoint of the processor. -/// -/// Parks all cores except core0 and checks if we started in EL2. If -/// so, proceeds with setting up EL1. -/// -/// # Safety -/// -/// - Linker script must ensure to place this function at `0x80_000`. -#[link_section = ".text.boot"] -#[no_mangle] -pub unsafe extern "C" fn _boot_cores() -> ! { - use cortex_a::{asm, regs::*}; - - const CORE_0: u64 = 0; - const CORE_MASK: u64 = 0x3; - const EL2: u32 = CurrentEL::EL::EL2.value; - - if (CORE_0 == MPIDR_EL1.get() & CORE_MASK) && (EL2 == CurrentEL.get()) { - setup_and_enter_el1_from_el2() - } - - // if not core0 or EL != 2, infinitely wait for events - loop { - asm::wfe(); - } -} diff --git a/.0D_virtual_memory/src/delays.rs b/.0D_virtual_memory/src/delays.rs deleted file mode 100644 index b1c1fa0f..00000000 --- a/.0D_virtual_memory/src/delays.rs +++ /dev/null @@ -1,37 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2018-2019 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -use cortex_a::asm; - -/* - * - * Using the CPU's cycles - * - */ -/// Wait N CPU cycles (ARM CPU only) -pub fn wait_cycles(cyc: u32) { - for _ in 0..cyc { - asm::nop(); - } -} diff --git a/.0D_virtual_memory/src/gpio.rs b/.0D_virtual_memory/src/gpio.rs deleted file mode 100644 index 7affea08..00000000 --- a/.0D_virtual_memory/src/gpio.rs +++ /dev/null @@ -1,120 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2018-2019 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -use core::ops; -use register::{mmio::ReadWrite, register_bitfields}; - -// Descriptions taken from -// https://github.com/raspberrypi/documentation/files/1888662/BCM2837-ARM-Peripherals.-.Revised.-.V2-1.pdf -register_bitfields! { - u32, - - /// GPIO Function Select 1 - GPFSEL1 [ - /// Pin 15 - FSEL15 OFFSET(15) NUMBITS(3) [ - Input = 0b000, - Output = 0b001, - RXD0 = 0b100, // UART0 - Alternate function 0 - RXD1 = 0b010 // Mini UART - Alternate function 5 - - ], - - /// Pin 14 - FSEL14 OFFSET(12) NUMBITS(3) [ - Input = 0b000, - Output = 0b001, - TXD0 = 0b100, // UART0 - Alternate function 0 - TXD1 = 0b010 // Mini UART - Alternate function 5 - ] - ], - - /// GPIO Pull-up/down Clock Register 0 - GPPUDCLK0 [ - /// Pin 15 - PUDCLK15 OFFSET(15) NUMBITS(1) [ - NoEffect = 0, - AssertClock = 1 - ], - - /// Pin 14 - PUDCLK14 OFFSET(14) NUMBITS(1) [ - NoEffect = 0, - AssertClock = 1 - ] - ] -} - -#[allow(non_snake_case)] -#[repr(C)] -pub struct RegisterBlock { - pub GPFSEL0: ReadWrite, // 0x00 - pub GPFSEL1: ReadWrite, // 0x04 - pub GPFSEL2: ReadWrite, // 0x08 - pub GPFSEL3: ReadWrite, // 0x0C - pub GPFSEL4: ReadWrite, // 0x10 - pub GPFSEL5: ReadWrite, // 0x14 - __reserved_0: u32, // 0x18 - GPSET0: ReadWrite, // 0x1C - GPSET1: ReadWrite, // 0x20 - __reserved_1: u32, // - GPCLR0: ReadWrite, // 0x28 - __reserved_2: [u32; 2], // - GPLEV0: ReadWrite, // 0x34 - GPLEV1: ReadWrite, // 0x38 - __reserved_3: u32, // - GPEDS0: ReadWrite, // 0x40 - GPEDS1: ReadWrite, // 0x44 - __reserved_4: [u32; 7], // - GPHEN0: ReadWrite, // 0x64 - GPHEN1: ReadWrite, // 0x68 - __reserved_5: [u32; 10], // - pub GPPUD: ReadWrite, // 0x94 - pub GPPUDCLK0: ReadWrite, // 0x98 - pub GPPUDCLK1: ReadWrite, // 0x9C -} - -/// Public interface to the GPIO MMIO area -pub struct GPIO { - base_addr: usize, -} - -impl ops::Deref for GPIO { - type Target = RegisterBlock; - - fn deref(&self) -> &Self::Target { - unsafe { &*self.ptr() } - } -} - -impl GPIO { - pub fn new(base_addr: usize) -> GPIO { - GPIO { base_addr } - } - - /// Returns a pointer to the register block - fn ptr(&self) -> *const RegisterBlock { - self.base_addr as *const _ - } -} diff --git a/.0D_virtual_memory/src/main.rs b/.0D_virtual_memory/src/main.rs deleted file mode 100644 index 266eba10..00000000 --- a/.0D_virtual_memory/src/main.rs +++ /dev/null @@ -1,82 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2018-2019 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#![no_std] -#![no_main] - -mod delays; -mod gpio; -mod mbox; -mod memory; -mod uart; - -fn kernel_entry() -> ! { - let gpio = gpio::GPIO::new(memory::map::physical::GPIO_BASE); - let mut mbox = mbox::Mbox::new(memory::map::physical::VIDEOCORE_MBOX_BASE); - - { - // Before the MMU is live, instantiate a UART driver with the physical address - let uart = uart::Uart::new(memory::map::physical::UART_BASE); - - // set up serial console - match uart.init(&mut mbox, &gpio) { - Ok(_) => uart.puts("\n[0] UART is live!\n"), - Err(_) => loop { - cortex_a::asm::wfe() // If UART fails, abort early - }, - } - - uart.puts("[1] Press a key to continue booting... "); - uart.getc(); - uart.puts("Greetings fellow Rustacean!\n"); - - memory::mmu::print_features(&uart); - - match unsafe { memory::mmu::init() } { - Err(s) => { - uart.puts("[2][Error] MMU: "); - uart.puts(s); - uart.puts("\n"); - } - // The following write is already using the identity mapped - // translation in the LVL2 table. - Ok(()) => uart.puts("[2] MMU online.\n"), - } - } // After this closure, the UART instance is not valid anymore. - - // Instantiate a new UART using the remapped address. No need to init() - // again, though. - let uart = uart::Uart::new(memory::map::virt::REMAPPED_UART_BASE); - - uart.puts("\nWriting through the virtual mapping at base address 0x"); - uart.hex(memory::map::virt::REMAPPED_UART_BASE as u64); - uart.puts(".\n"); - - // echo everything back - loop { - uart.send(uart.getc()); - } -} - -raspi3_boot::entry!(kernel_entry); diff --git a/.0D_virtual_memory/src/mbox.rs b/.0D_virtual_memory/src/mbox.rs deleted file mode 100644 index 2e4bf0ad..00000000 --- a/.0D_virtual_memory/src/mbox.rs +++ /dev/null @@ -1,163 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2018-2019 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -use core::ops; -use cortex_a::asm; -use register::{ - mmio::{ReadOnly, WriteOnly}, - register_bitfields, -}; - -register_bitfields! { - u32, - - STATUS [ - FULL OFFSET(31) NUMBITS(1) [], - EMPTY OFFSET(30) NUMBITS(1) [] - ] -} - -#[allow(non_snake_case)] -#[repr(C)] -pub struct RegisterBlock { - READ: ReadOnly, // 0x00 - __reserved_0: [u32; 5], // 0x04 - STATUS: ReadOnly, // 0x18 - __reserved_1: u32, // 0x1C - WRITE: WriteOnly, // 0x20 -} - -// Custom errors -pub enum MboxError { - ResponseError, - UnknownError, -} -pub type Result = ::core::result::Result; - -// Channels -pub mod channel { - pub const PROP: u32 = 8; -} - -// Tags -pub mod tag { - pub const SETCLKRATE: u32 = 0x38002; - pub const LAST: u32 = 0; -} - -// Clocks -pub mod clock { - pub const UART: u32 = 0x0_0000_0002; -} - -// Responses -mod response { - pub const SUCCESS: u32 = 0x8000_0000; - pub const ERROR: u32 = 0x8000_0001; // error parsing request buffer (partial response) -} - -pub const REQUEST: u32 = 0; - -// Public interface to the mailbox -#[repr(C)] -#[repr(align(16))] -pub struct Mbox { - // The address for buffer needs to be 16-byte aligned so that the - // Videcore can handle it properly. - pub buffer: [u32; 36], - base_addr: usize, -} - -/// Deref to RegisterBlock -/// -/// Allows writing -/// ``` -/// self.STATUS.read() -/// ``` -/// instead of something along the lines of -/// ``` -/// unsafe { (*Mbox::ptr()).STATUS.read() } -/// ``` -impl ops::Deref for Mbox { - type Target = RegisterBlock; - - fn deref(&self) -> &Self::Target { - unsafe { &*self.ptr() } - } -} - -impl Mbox { - pub fn new(base_addr: usize) -> Mbox { - Mbox { - buffer: [0; 36], - base_addr, - } - } - - /// Returns a pointer to the register block - fn ptr(&self) -> *const RegisterBlock { - self.base_addr as *const _ - } - - /// Make a mailbox call. Returns Err(MboxError) on failure, Ok(()) success - pub fn call(&self, channel: u32) -> Result<()> { - // wait until we can write to the mailbox - loop { - if !self.STATUS.is_set(STATUS::FULL) { - break; - } - - asm::nop(); - } - - let buf_ptr = self.buffer.as_ptr() as u32; - - // write the address of our message to the mailbox with channel identifier - self.WRITE.set((buf_ptr & !0xF) | (channel & 0xF)); - - // now wait for the response - loop { - // is there a response? - loop { - if !self.STATUS.is_set(STATUS::EMPTY) { - break; - } - - asm::nop(); - } - - let resp: u32 = self.READ.get(); - - // is it a response to our message? - if ((resp & 0xF) == channel) && ((resp & !0xF) == buf_ptr) { - // is it a valid successful response? - return match self.buffer[1] { - response::SUCCESS => Ok(()), - response::ERROR => Err(MboxError::ResponseError), - _ => Err(MboxError::UnknownError), - }; - } - } - } -} diff --git a/.0D_virtual_memory/src/memory.rs b/.0D_virtual_memory/src/memory.rs deleted file mode 100644 index c2135539..00000000 --- a/.0D_virtual_memory/src/memory.rs +++ /dev/null @@ -1,221 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2019 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -use core::ops::RangeInclusive; - -pub mod mmu; - -/// System memory map. -#[rustfmt::skip] -pub mod map { - pub const START: usize = 0x0000_0000; - pub const END: usize = 0x3FFF_FFFF; - - pub mod physical { - pub const MMIO_BASE: usize = 0x3F00_0000; - pub const VIDEOCORE_MBOX_BASE: usize = MMIO_BASE + 0x0000_B880; - pub const GPIO_BASE: usize = MMIO_BASE + 0x0020_0000; - pub const UART_BASE: usize = MMIO_BASE + 0x0020_1000; - pub const MMIO_END: usize = super::END; - } - - pub mod virt { - pub const KERN_STACK_START: usize = super::START; - pub const KERN_STACK_END: usize = 0x0007_FFFF; - - // The last 4 KiB slot in the first 2 MiB - pub const REMAPPED_UART_BASE: usize = 0x001F_F000; - pub const REMAPPED_UART_END: usize = 0x001F_FFFF; - } -} - -/// Types used for compiling the virtual memory layout of the kernel using -/// address ranges. -pub mod kernel_mem_range { - use core::ops::RangeInclusive; - - #[derive(Copy, Clone)] - pub enum MemAttributes { - CacheableDRAM, - Device, - } - - #[derive(Copy, Clone)] - pub enum AccessPermissions { - ReadOnly, - ReadWrite, - } - - #[derive(Copy, Clone)] - pub enum Translation { - Identity, - Offset(usize), - } - - #[derive(Copy, Clone)] - pub struct AttributeFields { - pub mem_attributes: MemAttributes, - pub acc_perms: AccessPermissions, - pub execute_never: bool, - } - - impl Default for AttributeFields { - fn default() -> AttributeFields { - AttributeFields { - mem_attributes: MemAttributes::CacheableDRAM, - acc_perms: AccessPermissions::ReadWrite, - execute_never: true, - } - } - } - - pub struct Descriptor { - pub virtual_range: fn() -> RangeInclusive, - pub translation: Translation, - pub attribute_fields: AttributeFields, - } -} - -use kernel_mem_range::*; - -/// A virtual memory layout that is agnostic of the paging granularity that the -/// hardware MMU will use. -/// -/// Contains only special ranges, aka anything that is _not_ normal cacheable -/// DRAM. -static KERNEL_VIRTUAL_LAYOUT: [Descriptor; 5] = [ - // Kernel stack - Descriptor { - virtual_range: || { - RangeInclusive::new(map::virt::KERN_STACK_START, map::virt::KERN_STACK_END) - }, - translation: Translation::Identity, - attribute_fields: AttributeFields { - mem_attributes: MemAttributes::CacheableDRAM, - acc_perms: AccessPermissions::ReadWrite, - execute_never: true, - }, - }, - // Kernel code and RO data - Descriptor { - virtual_range: || { - // Using the linker script, we ensure that the RO area is consecutive and 4 - // KiB aligned, and we export the boundaries via symbols: - // - // [__ro_start, __ro_end) - extern "C" { - // The inclusive start of the read-only area, aka the address of the - // first byte of the area. - static __ro_start: u64; - - // The exclusive end of the read-only area, aka the address of - // the first byte _after_ the RO area. - static __ro_end: u64; - } - - unsafe { - // Notice the subtraction to turn the exclusive end into an - // inclusive end - RangeInclusive::new( - &__ro_start as *const _ as usize, - &__ro_end as *const _ as usize - 1, - ) - } - }, - translation: Translation::Identity, - attribute_fields: AttributeFields { - mem_attributes: MemAttributes::CacheableDRAM, - acc_perms: AccessPermissions::ReadOnly, - execute_never: false, - }, - }, - // Kernel data and BSS - Descriptor { - virtual_range: || { - extern "C" { - static __ro_end: u64; - static __bss_end: u64; - } - - unsafe { - RangeInclusive::new( - &__ro_end as *const _ as usize, - &__bss_end as *const _ as usize - 1, - ) - } - }, - translation: Translation::Identity, - attribute_fields: AttributeFields { - mem_attributes: MemAttributes::CacheableDRAM, - acc_perms: AccessPermissions::ReadWrite, - execute_never: true, - }, - }, - // Remapped UART - Descriptor { - virtual_range: || { - RangeInclusive::new(map::virt::REMAPPED_UART_BASE, map::virt::REMAPPED_UART_END) - }, - translation: Translation::Offset(map::physical::UART_BASE), - attribute_fields: AttributeFields { - mem_attributes: MemAttributes::Device, - acc_perms: AccessPermissions::ReadWrite, - execute_never: true, - }, - }, - // Device MMIO - Descriptor { - virtual_range: || RangeInclusive::new(map::physical::MMIO_BASE, map::physical::MMIO_END), - translation: Translation::Identity, - attribute_fields: AttributeFields { - mem_attributes: MemAttributes::Device, - acc_perms: AccessPermissions::ReadWrite, - execute_never: true, - }, - }, -]; - -/// For a given virtual address, find and return the output address and -/// according attributes. -/// -/// If the address is not covered in VIRTUAL_LAYOUT, return a default for normal -/// cacheable DRAM. -fn get_virt_addr_properties(virt_addr: usize) -> Result<(usize, AttributeFields), &'static str> { - if virt_addr > map::END { - return Err("Address out of range."); - } - - for i in KERNEL_VIRTUAL_LAYOUT.iter() { - if (i.virtual_range)().contains(&virt_addr) { - let output_addr = match i.translation { - Translation::Identity => virt_addr, - Translation::Offset(a) => a + (virt_addr - (i.virtual_range)().start()), - }; - - return Ok((output_addr, i.attribute_fields)); - } - } - - Ok((virt_addr, AttributeFields::default())) -} diff --git a/.0D_virtual_memory/src/memory/mmu.rs b/.0D_virtual_memory/src/memory/mmu.rs deleted file mode 100644 index 9dae90f3..00000000 --- a/.0D_virtual_memory/src/memory/mmu.rs +++ /dev/null @@ -1,359 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2018-2019 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -use crate::memory::{get_virt_addr_properties, AttributeFields}; -use crate::uart; -use cortex_a::{barrier, regs::*}; -use register::register_bitfields; - -/// Parse the ID_AA64MMFR0_EL1 register for runtime information about supported -/// MMU features. -pub fn print_features(uart: &uart::Uart) { - let mmfr = ID_AA64MMFR0_EL1.extract(); - - if let Some(ID_AA64MMFR0_EL1::TGran4::Value::Supported) = - mmfr.read_as_enum(ID_AA64MMFR0_EL1::TGran4) - { - uart.puts("[i] MMU: 4 KiB granule supported!\n"); - } - - if let Some(ID_AA64MMFR0_EL1::PARange::Value::Bits_40) = - mmfr.read_as_enum(ID_AA64MMFR0_EL1::PARange) - { - uart.puts("[i] MMU: Up to 40 Bit physical address range supported!\n"); - } -} - -register_bitfields! {u64, - // AArch64 Reference Manual page 2150 - STAGE1_DESCRIPTOR [ - /// Privileged execute-never - PXN OFFSET(53) NUMBITS(1) [ - False = 0, - True = 1 - ], - - /// Various address fields, depending on use case - LVL2_OUTPUT_ADDR_4KiB OFFSET(21) NUMBITS(27) [], // [47:21] - NEXT_LVL_TABLE_ADDR_4KiB OFFSET(12) NUMBITS(36) [], // [47:12] - - /// 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) [ - Block = 0, - Table = 1 - ], - - VALID OFFSET(0) NUMBITS(1) [ - False = 0, - True = 1 - ] - ] -} - -const FOUR_KIB: usize = 4 * 1024; -const FOUR_KIB_SHIFT: usize = 12; // log2(4 * 1024) - -const TWO_MIB: usize = 2 * 1024 * 1024; -const TWO_MIB_SHIFT: usize = 21; // log2(2 * 1024 * 1024) - -/// A descriptor pointing to the next page table. -struct TableDescriptor(register::FieldValue); - -impl TableDescriptor { - fn new(next_lvl_table_addr: usize) -> Result { - if next_lvl_table_addr % FOUR_KIB != 0 { - return Err("TableDescriptor: Address is not 4 KiB aligned."); - } - - let shifted = next_lvl_table_addr >> FOUR_KIB_SHIFT; - - Ok(TableDescriptor( - STAGE1_DESCRIPTOR::VALID::True - + STAGE1_DESCRIPTOR::TYPE::Table - + STAGE1_DESCRIPTOR::NEXT_LVL_TABLE_ADDR_4KiB.val(shifted as u64), - )) - } - - fn value(&self) -> u64 { - self.0.value - } -} - -/// A function that maps the generic memory range attributes to HW-specific -/// attributes of the MMU. -fn into_mmu_attributes( - attribute_fields: AttributeFields, -) -> register::FieldValue { - use crate::memory::{AccessPermissions, MemAttributes}; - - // Memory attributes - let mut desc = match attribute_fields.mem_attributes { - MemAttributes::CacheableDRAM => { - STAGE1_DESCRIPTOR::SH::InnerShareable + STAGE1_DESCRIPTOR::AttrIndx.val(mair::NORMAL) - } - MemAttributes::Device => { - STAGE1_DESCRIPTOR::SH::OuterShareable + STAGE1_DESCRIPTOR::AttrIndx.val(mair::DEVICE) - } - }; - - // Access Permissions - desc += match attribute_fields.acc_perms { - AccessPermissions::ReadOnly => STAGE1_DESCRIPTOR::AP::RO_EL1, - AccessPermissions::ReadWrite => STAGE1_DESCRIPTOR::AP::RW_EL1, - }; - - // Execute Never - desc += if attribute_fields.execute_never { - STAGE1_DESCRIPTOR::PXN::True - } else { - STAGE1_DESCRIPTOR::PXN::False - }; - - desc -} - -/// A Level2 block descriptor with 2 MiB aperture. -/// -/// The output points to physical memory. -struct Lvl2BlockDescriptor(register::FieldValue); - -impl Lvl2BlockDescriptor { - fn new( - output_addr: usize, - attribute_fields: AttributeFields, - ) -> Result { - if output_addr % TWO_MIB != 0 { - return Err("BlockDescriptor: Address is not 2 MiB aligned."); - } - - let shifted = output_addr >> TWO_MIB_SHIFT; - - Ok(Lvl2BlockDescriptor( - STAGE1_DESCRIPTOR::VALID::True - + STAGE1_DESCRIPTOR::AF::True - + into_mmu_attributes(attribute_fields) - + STAGE1_DESCRIPTOR::TYPE::Block - + STAGE1_DESCRIPTOR::LVL2_OUTPUT_ADDR_4KiB.val(shifted as u64), - )) - } - - fn value(&self) -> u64 { - self.0.value - } -} - -/// A page descriptor with 4 KiB aperture. -/// -/// The output points to physical memory. -struct PageDescriptor(register::FieldValue); - -impl PageDescriptor { - fn new( - output_addr: usize, - attribute_fields: AttributeFields, - ) -> Result { - if output_addr % FOUR_KIB != 0 { - return Err("PageDescriptor: Address is not 4 KiB aligned."); - } - - let shifted = output_addr >> FOUR_KIB_SHIFT; - - Ok(PageDescriptor( - STAGE1_DESCRIPTOR::VALID::True - + STAGE1_DESCRIPTOR::AF::True - + into_mmu_attributes(attribute_fields) - + STAGE1_DESCRIPTOR::TYPE::Table - + STAGE1_DESCRIPTOR::NEXT_LVL_TABLE_ADDR_4KiB.val(shifted as u64), - )) - } - - fn value(&self) -> u64 { - self.0.value - } -} - -/// Constants for indexing the MAIR_EL1. -#[allow(dead_code)] -mod mair { - pub const DEVICE: u64 = 0; - pub const NORMAL: u64 = 1; -} - -/// Setup function for the MAIR_EL1 register. -fn set_up_mair() { - // Define the memory types that we will map. Cacheable normal DRAM and - // device. - MAIR_EL1.write( - // Attribute 1 - MAIR_EL1::Attr1_HIGH::Memory_OuterWriteBack_NonTransient_ReadAlloc_WriteAlloc - + MAIR_EL1::Attr1_LOW_MEMORY::InnerWriteBack_NonTransient_ReadAlloc_WriteAlloc - - // Attribute 0 - + MAIR_EL1::Attr0_HIGH::Device - + MAIR_EL1::Attr0_LOW_DEVICE::Device_nGnRE, - ); -} - -trait BaseAddr { - fn base_addr_u64(&self) -> u64; - fn base_addr_usize(&self) -> usize; -} - -impl BaseAddr for [u64; 512] { - fn base_addr_u64(&self) -> u64 { - self as *const u64 as u64 - } - - fn base_addr_usize(&self) -> usize { - self as *const u64 as usize - } -} - -const NUM_ENTRIES_4KIB: usize = 512; - -// A wrapper struct is needed here so that the align attribute can be used. -#[repr(C)] -#[repr(align(4096))] -struct PageTable { - entries: [u64; NUM_ENTRIES_4KIB], -} - -/// The LVL2 page table containng the 2 MiB entries. -static mut LVL2_TABLE: PageTable = PageTable { - entries: [0; NUM_ENTRIES_4KIB], -}; - -/// The LVL3 page table containing the 4 KiB entries. -/// -/// The first entry of the LVL2_TABLE will forward to this table. -static mut LVL3_TABLE: PageTable = PageTable { - entries: [0; NUM_ENTRIES_4KIB], -}; - -/// Set up identity mapped page tables for the first 1 GiB of address space. -/// -/// The first 2 MiB are 4 KiB granule, the rest 2 MiB. -/// -/// # Safety -/// -/// - User must ensure that the hardware supports the paremeters being set here. -pub unsafe fn init() -> Result<(), &'static str> { - // Prepare the memory attribute indirection register. - set_up_mair(); - - // Point the first 2 MiB of virtual addresses to the follow-up LVL3 - // page-table. - LVL2_TABLE.entries[0] = match TableDescriptor::new(LVL3_TABLE.entries.base_addr_usize()) { - Err(s) => return Err(s), - Ok(d) => d.value(), - }; - - // Fill the rest of the LVL2 (2 MiB) entries as block descriptors. - // - // Notice the skip(1) which makes the iteration start at the second 2 MiB - // block (0x20_0000). - for (block_descriptor_nr, entry) in LVL2_TABLE.entries.iter_mut().enumerate().skip(1) { - let virt_addr = block_descriptor_nr << TWO_MIB_SHIFT; - - let (output_addr, attribute_fields) = match get_virt_addr_properties(virt_addr) { - Err(s) => return Err(s), - Ok((a, b)) => (a, b), - }; - - let block_desc = match Lvl2BlockDescriptor::new(output_addr, attribute_fields) { - Err(s) => return Err(s), - Ok(desc) => desc, - }; - - *entry = block_desc.value(); - } - - // Finally, fill the single LVL3 table (4 KiB granule). - for (page_descriptor_nr, entry) in LVL3_TABLE.entries.iter_mut().enumerate() { - let virt_addr = page_descriptor_nr << FOUR_KIB_SHIFT; - - let (output_addr, attribute_fields) = match get_virt_addr_properties(virt_addr) { - Err(s) => return Err(s), - Ok((a, b)) => (a, b), - }; - - let page_desc = match PageDescriptor::new(output_addr, attribute_fields) { - Err(s) => return Err(s), - Ok(desc) => desc, - }; - - *entry = page_desc.value(); - } - - // Point to the LVL2 table base address in TTBR0. - TTBR0_EL1.set_baddr(LVL2_TABLE.entries.base_addr_u64()); - - // Configure various settings of stage 1 of the EL1 translation regime. - let ips = ID_AA64MMFR0_EL1.read(ID_AA64MMFR0_EL1::PARange); - TCR_EL1.write( - TCR_EL1::TBI0::Ignored - + TCR_EL1::IPS.val(ips) - + TCR_EL1::TG0::KiB_4 // 4 KiB granule - + TCR_EL1::SH0::Inner - + TCR_EL1::ORGN0::WriteBack_ReadAlloc_WriteAlloc_Cacheable - + TCR_EL1::IRGN0::WriteBack_ReadAlloc_WriteAlloc_Cacheable - + TCR_EL1::EPD0::EnableTTBR0Walks - + TCR_EL1::T0SZ.val(34), // Start walks at level 2 - ); - - // 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(()) -} diff --git a/.0D_virtual_memory/src/uart.rs b/.0D_virtual_memory/src/uart.rs deleted file mode 100644 index 9505be3a..00000000 --- a/.0D_virtual_memory/src/uart.rs +++ /dev/null @@ -1,281 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2018-2019 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -use crate::delays; -use crate::gpio; -use crate::mbox; -use core::{ - ops, - sync::atomic::{compiler_fence, Ordering}, -}; -use cortex_a::asm; -use register::{mmio::*, register_bitfields}; - -// PL011 UART registers. -// -// Descriptions taken from -// https://github.com/raspberrypi/documentation/files/1888662/BCM2837-ARM-Peripherals.-.Revised.-.V2-1.pdf -register_bitfields! { - u32, - - /// Flag Register - FR [ - /// Transmit FIFO full. The meaning of this bit depends on the - /// state of the FEN bit in the UARTLCR_ LCRH 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 UARTLCR_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) [] - ], - - /// Integer Baud rate divisor - IBRD [ - /// Integer Baud rate divisor - IBRD OFFSET(0) NUMBITS(16) [] - ], - - /// Fractional Baud rate divisor - FBRD [ - /// Fractional Baud rate divisor - FBRD OFFSET(0) NUMBITS(6) [] - ], - - /// Line Control register - LCRH [ - /// Word length. These bits indicate the number of data bits - /// transmitted or received in a frame. - WLEN OFFSET(5) NUMBITS(2) [ - FiveBit = 0b00, - SixBit = 0b01, - SevenBit = 0b10, - EightBit = 0b11 - ] - ], - - /// Control Register - CR [ - /// Receive enable. If this bit is set to 1, the receive - /// section of the UART is enabled. Data reception occurs for - /// UART signals. 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 UART signals. 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 - 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 - ] - ], - - /// Interupt Clear Register - ICR [ - /// Meta field for all pending interrupts - ALL OFFSET(0) NUMBITS(11) [] - ] -} - -#[allow(non_snake_case)] -#[repr(C)] -pub struct RegisterBlock { - DR: ReadWrite, // 0x00 - __reserved_0: [u32; 5], // 0x04 - FR: ReadOnly, // 0x18 - __reserved_1: [u32; 2], // 0x1c - IBRD: WriteOnly, // 0x24 - FBRD: WriteOnly, // 0x28 - LCRH: WriteOnly, // 0x2C - CR: WriteOnly, // 0x30 - __reserved_2: [u32; 4], // 0x34 - ICR: WriteOnly, // 0x44 -} - -pub enum UartError { - MailboxError, -} -pub type Result = ::core::result::Result; - -pub struct Uart { - base_addr: usize, -} - -impl ops::Deref for Uart { - type Target = RegisterBlock; - - fn deref(&self) -> &Self::Target { - unsafe { &*self.ptr() } - } -} - -impl Uart { - pub fn new(base_addr: usize) -> Uart { - Uart { base_addr } - } - - /// Returns a pointer to the register block - fn ptr(&self) -> *const RegisterBlock { - self.base_addr as *const _ - } - - ///Set baud rate and characteristics (115200 8N1) and map to GPIO - pub fn init(&self, mbox: &mut mbox::Mbox, gpio: &gpio::GPIO) -> Result<()> { - // turn off UART0 - self.CR.set(0); - - // set up clock for consistent divisor values - mbox.buffer[0] = 9 * 4; - mbox.buffer[1] = mbox::REQUEST; - mbox.buffer[2] = mbox::tag::SETCLKRATE; - mbox.buffer[3] = 12; - mbox.buffer[4] = 8; - mbox.buffer[5] = mbox::clock::UART; // UART clock - mbox.buffer[6] = 4_000_000; // 4Mhz - mbox.buffer[7] = 0; // skip turbo setting - mbox.buffer[8] = mbox::tag::LAST; - - // Insert a compiler fence that ensures that all stores to the - // mbox buffer are finished before the GPU is signaled (which - // is done by a store operation as well). - compiler_fence(Ordering::Release); - - if mbox.call(mbox::channel::PROP).is_err() { - return Err(UartError::MailboxError); // Abort if UART clocks couldn't be set - }; - - // map UART0 to GPIO pins - gpio.GPFSEL1 - .modify(gpio::GPFSEL1::FSEL14::TXD0 + gpio::GPFSEL1::FSEL15::RXD0); - - gpio.GPPUD.set(0); // enable pins 14 and 15 - delays::wait_cycles(150); - - gpio.GPPUDCLK0.modify( - gpio::GPPUDCLK0::PUDCLK14::AssertClock + gpio::GPPUDCLK0::PUDCLK15::AssertClock, - ); - delays::wait_cycles(150); - - gpio.GPPUDCLK0.set(0); - - self.ICR.write(ICR::ALL::CLEAR); - self.IBRD.write(IBRD::IBRD.val(2)); // Results in 115200 baud - self.FBRD.write(FBRD::FBRD.val(0xB)); - self.LCRH.write(LCRH::WLEN::EightBit); // 8N1 - self.CR - .write(CR::UARTEN::Enabled + CR::TXE::Enabled + CR::RXE::Enabled); - - Ok(()) - } - - /// Send a character - pub fn send(&self, c: char) { - // wait until we can send - loop { - if !self.FR.is_set(FR::TXFF) { - break; - } - - asm::nop(); - } - - // write the character to the buffer - self.DR.set(c as u32); - } - - /// Receive a character - pub fn getc(&self) -> char { - // wait until something is in the buffer - loop { - if !self.FR.is_set(FR::RXFE) { - break; - } - - asm::nop(); - } - - // read it and return - let mut ret = self.DR.get() as u8 as char; - - // convert carrige return to newline - if ret == '\r' { - ret = '\n' - } - - ret - } - - /// Display a string - pub fn puts(&self, string: &str) { - for c in string.chars() { - // convert newline to carrige return + newline - if c == '\n' { - self.send('\r') - } - - self.send(c); - } - } - - /// Display a binary value in hexadecimal - pub fn hex(&self, d: u64) { - let mut n; - - for i in 0..16 { - // get highest tetrad - n = d.wrapping_shr(60 - i * 4) & 0xF; - - // 0-9 => '0'-'9', 10-15 => 'A'-'F' - // Add proper offset for ASCII table - if n > 9 { - n += 0x37; - } else { - n += 0x30; - } - - self.send(n as u8 as char); - } - } -} diff --git a/.0E_cache_performance/.cargo/config b/.0E_cache_performance/.cargo/config deleted file mode 100644 index de3f84c9..00000000 --- a/.0E_cache_performance/.cargo/config +++ /dev/null @@ -1,5 +0,0 @@ -[target.aarch64-unknown-none-softfloat] -rustflags = [ - "-C", "link-arg=-Tlink.ld", - "-C", "target-cpu=cortex-a53", -] diff --git a/.0E_cache_performance/Cargo.lock b/.0E_cache_performance/Cargo.lock deleted file mode 100644 index d218ad56..00000000 --- a/.0E_cache_performance/Cargo.lock +++ /dev/null @@ -1,57 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -[[package]] -name = "cortex-a" -version = "2.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "register 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "kernel8" -version = "0.1.0" -dependencies = [ - "cortex-a 2.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "raspi3_boot 0.1.0", - "register 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "panic-abort" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "r0" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "raspi3_boot" -version = "0.1.0" -dependencies = [ - "cortex-a 2.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "panic-abort 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "r0 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "register" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "tock-registers 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tock-registers" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[metadata] -"checksum cortex-a 2.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cbb16c411ab74044f174746a6cbae67bcdebea126e376b5441e5986e6a6aa950" -"checksum panic-abort 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2c14a66511ed17b6a8b4256b868d7fd207836d891db15eea5195dbcaf87e630f" -"checksum r0 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e2a38df5b15c8d5c7e8654189744d8e396bddc18ad48041a500ce52d6948941f" -"checksum register 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "469bb5ddde81d67fb8bba4e14d77689b8166cfd077abe7530591cefe29d05823" -"checksum tock-registers 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c758f5195a2e0df9d9fecf6f506506b2766ff74cf64db1e995c87e2761a5c3e2" diff --git a/.0E_cache_performance/Cargo.toml b/.0E_cache_performance/Cargo.toml deleted file mode 100644 index 43d1e22e..00000000 --- a/.0E_cache_performance/Cargo.toml +++ /dev/null @@ -1,13 +0,0 @@ -[package] -name = "kernel8" -version = "0.1.0" -authors = ["Andre Richter "] -edition = "2018" - -[dependencies] -raspi3_boot = { path = "raspi3_boot" } -cortex-a = "2.7.0" -register = "0.3.3" - -[package.metadata.cargo-xbuild] -sysroot_path = "../xbuild_sysroot" diff --git a/.0E_cache_performance/Makefile b/.0E_cache_performance/Makefile deleted file mode 100644 index f5c8310d..00000000 --- a/.0E_cache_performance/Makefile +++ /dev/null @@ -1,103 +0,0 @@ -# -# MIT License -# -# Copyright (c) 2018-2019 Andre Richter -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# - -TARGET = aarch64-unknown-none-softfloat - -SOURCES = $(wildcard **/*.rs) $(wildcard **/*.S) link.ld - - -XRUSTC_CMD = cargo xrustc --target=$(TARGET) --release -CARGO_OUTPUT = target/$(TARGET)/release/kernel8 - -OBJCOPY = cargo objcopy -- -OBJCOPY_PARAMS = --strip-all -O binary - -CONTAINER_UTILS = andrerichter/raspi3-utils -CONTAINER_OPENOCD = andrerichter/raspi3-openocd -# CONTAINER_OPENOCD_ARG = -f openocd/tcl/interface/ftdi/olimex-jtag-tiny.cfg -f /openocd/rpi3.cfg -CONTAINER_GDB = andrerichter/raspi3-gdb - -DOCKER_CMD = docker run -it --rm -DOCKER_ARG_CURDIR = -v $(shell pwd):/work -w /work -DOCKER_ARG_TTY = --privileged -v /dev:/dev -DOCKER_ARG_JTAG = -v $(shell pwd)/../X1_JTAG_boot:/jtag -DOCKER_ARG_NET = --network host - -DOCKER_EXEC_QEMU = qemu-system-aarch64 -M raspi3 -kernel kernel8.img -DOCKER_EXEC_RASPBOOT = raspbootcom -DOCKER_EXEC_RASPBOOT_DEV = /dev/ttyUSB0 -# DOCKER_EXEC_RASPBOOT_DEV = /dev/ttyACM0 - -.PHONY: all qemu raspboot clippy clean objdump nm jtagboot openocd gdb gdb-opt0 - -all: clean kernel8.img - -$(CARGO_OUTPUT): $(SOURCES) - $(XRUSTC_CMD) - -kernel8.img: $(CARGO_OUTPUT) - cp $< . - $(OBJCOPY) $(OBJCOPY_PARAMS) $< kernel8.img - -qemu: all - $(DOCKER_CMD) $(DOCKER_ARG_CURDIR) $(CONTAINER_UTILS) \ - $(DOCKER_EXEC_QEMU) -serial stdio - -raspboot: all - $(DOCKER_CMD) $(DOCKER_ARG_CURDIR) $(DOCKER_ARG_TTY) \ - $(CONTAINER_UTILS) $(DOCKER_EXEC_RASPBOOT) \ - $(DOCKER_EXEC_RASPBOOT_DEV) kernel8.img - -clippy: - cargo xclippy --target=$(TARGET) - -clean: - cargo clean - -objdump: - cargo objdump --target $(TARGET) -- -disassemble -print-imm-hex kernel8 - -nm: - cargo nm --target $(TARGET) -- kernel8 | sort - -jtagboot: - $(DOCKER_CMD) $(DOCKER_ARG_TTY) $(DOCKER_ARG_JTAG) $(CONTAINER_UTILS) \ - $(DOCKER_EXEC_RASPBOOT) $(DOCKER_EXEC_RASPBOOT_DEV) /jtag/jtag_boot.img - -openocd: - $(DOCKER_CMD) $(DOCKER_ARG_TTY) $(DOCKER_ARG_NET) $(CONTAINER_OPENOCD) \ - $(CONTAINER_OPENOCD_ARG) - -define gen_gdb - $(XRUSTC_CMD) -- $1 - cp $(CARGO_OUTPUT) kernel8_for_jtag - $(DOCKER_CMD) $(DOCKER_ARG_CURDIR) $(DOCKER_ARG_NET) $(CONTAINER_GDB) \ - gdb-multiarch -q kernel8_for_jtag -endef - -gdb: clean $(SOURCES) - $(call gen_gdb,-C debuginfo=2) - -gdb-opt0: clean $(SOURCES) - $(call gen_gdb,-C debuginfo=2 -C opt-level=0) diff --git a/.0E_cache_performance/README.md b/.0E_cache_performance/README.md deleted file mode 100644 index 6db274a6..00000000 --- a/.0E_cache_performance/README.md +++ /dev/null @@ -1,59 +0,0 @@ -# Tutorial 0E - Cache Performance - -Now that we finally have virtual memory capabilities available, we also have -fine grained control over `cacheability`. You've caught a glimpse already in the -last tutorial, where we used page table entries to reference the `MAIR_EL1` -register to indicate the cacheability of a page or block. - -Unfortunately, for the user it is often hard to grasp the advantage of caching -in early stages of OS or bare-metal software development. This tutorial is a -short interlude that tries to give you a feeling of what caching can do for -performance. - -## Benchmark - -Let's write a tiny, arbitrary micro-benchmark to showcase the performance of -operating with data on the same DRAM with caching enabled and disabled. - -### mmu.rs - -Therefore, we will map the same physical memory via two different virtual -addresses. We set up our pagetables such that the virtual address `0x400000` -points to the physical DRAM at `0x200000`, and we configure it as -`non-cacheable` in the page tables. - -There is also an identity mapped block, which starts at virtual `0x200000` and -points at physical `0x200000`. This time, the block is configured as cacheable. - -### benchmark.rs - -We write a little function that iteratively reads memory of five times the size -of a `cacheline`, in steps of 8 bytes, aka one processor register at a time. We -read the value, add 1, and write it back. This whole process is repeated -`20_000` times. - -The benchmark function is called twice. Once for the cacheable and once for the -non-cacheable virtual addresses. Remember that both virtual addresses point to -the _same_ physical DRAM, so the difference in time that we will see will -showcase how much faster it is to operate on DRAM with caching enabled. - -## Output - -On my Raspberry, I get the following results: - -```console -ferris@box:~$ make raspboot - -[0] UART is live! -[1] Press a key to continue booting... Greetings fellow Rustacean! -[2] MMU online. -Benchmarking non-cacheable DRAM modifications at virtual 0x0000000000400000, physical 0x0000000000200000: -1040 miliseconds. - -Benchmarking cacheable DRAM modifications at virtual 0x0000000000200000, physical 0x0000000000200000: -53 miliseconds. - -With caching, the function is 1800% faster! -``` - -Impressive, isn't it? diff --git a/.0E_cache_performance/kernel8 b/.0E_cache_performance/kernel8 deleted file mode 100755 index 8044ad1ec2781c5c05a75a03c1d17c4b4971c952..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 77856 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 - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -ENTRY(_boot_cores); - -SECTIONS -{ - . = 0x80000; /* This is already 4KiB aligned */ - __ro_start = .; - .text : - { - KEEP(*(.text.boot)) *(.text .text.*) - } - - .rodata : - { - *(.rodata .rodata.*) - } - . = ALIGN(4096); /* Fill up to 4KiB */ - __ro_end = .; - - .data : - { - *(.data .data.*) - } - - .bss ALIGN(8): - { - __bss_start = .; - *(.bss .bss.*) - *(COMMON) - __bss_end = .; - } - - /DISCARD/ : { *(.comment) *(.gnu*) *(.note*) *(.eh_frame*) } -} diff --git a/.0E_cache_performance/raspi3_boot/Cargo.toml b/.0E_cache_performance/raspi3_boot/Cargo.toml deleted file mode 100644 index 024fd184..00000000 --- a/.0E_cache_performance/raspi3_boot/Cargo.toml +++ /dev/null @@ -1,10 +0,0 @@ -[package] -name = "raspi3_boot" -version = "0.1.0" -authors = ["Andre Richter "] -edition = "2018" - -[dependencies] -cortex-a = "2.7.0" -panic-abort = "0.3.1" -r0 = "0.2.2" diff --git a/.0E_cache_performance/raspi3_boot/src/lib.rs b/.0E_cache_performance/raspi3_boot/src/lib.rs deleted file mode 100644 index 01ccd956..00000000 --- a/.0E_cache_performance/raspi3_boot/src/lib.rs +++ /dev/null @@ -1,141 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2018 Jorge Aparicio - * Copyright (c) 2018-2019 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#![deny(missing_docs)] -#![deny(warnings)] -#![no_std] - -//! Low-level boot of the Raspberry's processor - -extern crate panic_abort; - -/// Type check the user-supplied entry function. -#[macro_export] -macro_rules! entry { - ($path:path) => { - /// # Safety - /// - /// - User must ensure to provide a suitable main function for the - /// platform. - #[export_name = "main"] - pub unsafe fn __main() -> ! { - // type check the given path - let f: fn() -> ! = $path; - - f() - } - }; -} - -/// Reset function. -/// -/// Initializes the bss section before calling into the user's `main()`. -/// -/// # Safety -/// -/// - Only a single core must be active and running this function. -unsafe fn reset() -> ! { - extern "C" { - // Boundaries of the .bss section, provided by the linker script - static mut __bss_start: u64; - static mut __bss_end: u64; - } - - // Zeroes the .bss section - r0::zero_bss(&mut __bss_start, &mut __bss_end); - - extern "Rust" { - fn main() -> !; - } - - main() -} - -/// Prepare and execute transition from EL2 to EL1. -#[inline] -fn setup_and_enter_el1_from_el2() -> ! { - use cortex_a::{asm, regs::*}; - - const STACK_START: u64 = 0x80_000; - - // 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 reset(). - ELR_EL2.set(reset as *const () as u64); - - // Set up SP_EL1 (stack pointer), which will be used by EL1 once - // we "return" to it. - SP_EL1.set(STACK_START); - - // Use `eret` to "return" to EL1. This will result in execution of - // `reset()` in EL1. - asm::eret() -} - -/// Entrypoint of the processor. -/// -/// Parks all cores except core0 and checks if we started in EL2. If -/// so, proceeds with setting up EL1. -/// -/// # Safety -/// -/// - Linker script must ensure to place this function at `0x80_000`. -#[link_section = ".text.boot"] -#[no_mangle] -pub unsafe extern "C" fn _boot_cores() -> ! { - use cortex_a::{asm, regs::*}; - - const CORE_0: u64 = 0; - const CORE_MASK: u64 = 0x3; - const EL2: u32 = CurrentEL::EL::EL2.value; - - if (CORE_0 == MPIDR_EL1.get() & CORE_MASK) && (EL2 == CurrentEL.get()) { - setup_and_enter_el1_from_el2() - } - - // if not core0 or EL != 2, infinitely wait for events - loop { - asm::wfe(); - } -} diff --git a/.0E_cache_performance/src/benchmark.rs b/.0E_cache_performance/src/benchmark.rs deleted file mode 100644 index 346399f5..00000000 --- a/.0E_cache_performance/src/benchmark.rs +++ /dev/null @@ -1,113 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2018-2019 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -use crate::uart; -use core::sync::atomic::{compiler_fence, Ordering}; -use cortex_a::{barrier, regs::*}; - -/// We assume that addr is cacheline aligned -fn batch_modify_time(addr: usize) -> Option { - const CACHELINE_SIZE_BYTES: usize = 64; // TODO: retrieve this from a system register - const NUM_CACHELINES_TOUCHED: usize = 5; - const NUM_BENCH_ITERATIONS: usize = 20_000; - - const NUM_BYTES_TOUCHED: usize = CACHELINE_SIZE_BYTES * NUM_CACHELINES_TOUCHED; - - let mem = unsafe { core::slice::from_raw_parts_mut(addr as *mut usize, NUM_BYTES_TOUCHED) }; - - // Benchmark starts here - let t1 = CNTPCT_EL0.get(); - - compiler_fence(Ordering::SeqCst); - - let mut temp: usize; - for _ in 0..NUM_BENCH_ITERATIONS { - for qword in mem.iter_mut() { - unsafe { - temp = core::ptr::read_volatile(qword); - core::ptr::write_volatile(qword, temp + 1); - } - } - } - - // Insert a barrier to ensure that the last memory operation has finished - // before we retrieve the elapsed time with the subsequent counter read. Not - // needed at all given the sample size, but let's be a bit pedantic here for - // education purposes. For measuring single-instructions, this would be - // needed. - unsafe { barrier::dsb(barrier::SY) }; - - let t2 = CNTPCT_EL0.get(); - let frq = u64::from(CNTFRQ_EL0.get()); - - ((t2 - t1) * 1000).checked_div(frq) -} - -pub fn run(uart: &uart::Uart) { - use crate::memory::map; - - const ERROR_STRING: &str = "Something went wrong!"; - - uart.puts("Benchmarking non-cacheable DRAM modifications at virtual 0x"); - uart.hex(map::virt::NON_CACHEABLE_START as u64); - uart.puts(", physical 0x"); - uart.hex(map::virt::CACHEABLE_START as u64); - uart.puts(":\n"); - - let result_nc = match batch_modify_time(map::virt::NON_CACHEABLE_START) { - Some(t) => { - uart.dec(t as u32); - uart.puts(" miliseconds.\n\n"); - t - } - None => { - uart.puts(ERROR_STRING); - return; - } - }; - - uart.puts("Benchmarking cacheable DRAM modifications at virtual 0x"); - uart.hex(map::virt::CACHEABLE_START as u64); - uart.puts(", physical 0x"); - uart.hex(map::virt::CACHEABLE_START as u64); - uart.puts(":\n"); - - let result_c = match batch_modify_time(map::virt::CACHEABLE_START) { - Some(t) => { - uart.dec(t as u32); - uart.puts(" miliseconds.\n\n"); - t - } - None => { - uart.puts(ERROR_STRING); - return; - } - }; - - if let Some(t) = (result_nc - result_c).checked_div(result_c) { - uart.puts("With caching, the function is "); - uart.dec((t * 100) as u32); - uart.puts("% faster!\n"); - } -} diff --git a/.0E_cache_performance/src/delays.rs b/.0E_cache_performance/src/delays.rs deleted file mode 100644 index b1c1fa0f..00000000 --- a/.0E_cache_performance/src/delays.rs +++ /dev/null @@ -1,37 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2018-2019 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -use cortex_a::asm; - -/* - * - * Using the CPU's cycles - * - */ -/// Wait N CPU cycles (ARM CPU only) -pub fn wait_cycles(cyc: u32) { - for _ in 0..cyc { - asm::nop(); - } -} diff --git a/.0E_cache_performance/src/gpio.rs b/.0E_cache_performance/src/gpio.rs deleted file mode 100644 index 7affea08..00000000 --- a/.0E_cache_performance/src/gpio.rs +++ /dev/null @@ -1,120 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2018-2019 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -use core::ops; -use register::{mmio::ReadWrite, register_bitfields}; - -// Descriptions taken from -// https://github.com/raspberrypi/documentation/files/1888662/BCM2837-ARM-Peripherals.-.Revised.-.V2-1.pdf -register_bitfields! { - u32, - - /// GPIO Function Select 1 - GPFSEL1 [ - /// Pin 15 - FSEL15 OFFSET(15) NUMBITS(3) [ - Input = 0b000, - Output = 0b001, - RXD0 = 0b100, // UART0 - Alternate function 0 - RXD1 = 0b010 // Mini UART - Alternate function 5 - - ], - - /// Pin 14 - FSEL14 OFFSET(12) NUMBITS(3) [ - Input = 0b000, - Output = 0b001, - TXD0 = 0b100, // UART0 - Alternate function 0 - TXD1 = 0b010 // Mini UART - Alternate function 5 - ] - ], - - /// GPIO Pull-up/down Clock Register 0 - GPPUDCLK0 [ - /// Pin 15 - PUDCLK15 OFFSET(15) NUMBITS(1) [ - NoEffect = 0, - AssertClock = 1 - ], - - /// Pin 14 - PUDCLK14 OFFSET(14) NUMBITS(1) [ - NoEffect = 0, - AssertClock = 1 - ] - ] -} - -#[allow(non_snake_case)] -#[repr(C)] -pub struct RegisterBlock { - pub GPFSEL0: ReadWrite, // 0x00 - pub GPFSEL1: ReadWrite, // 0x04 - pub GPFSEL2: ReadWrite, // 0x08 - pub GPFSEL3: ReadWrite, // 0x0C - pub GPFSEL4: ReadWrite, // 0x10 - pub GPFSEL5: ReadWrite, // 0x14 - __reserved_0: u32, // 0x18 - GPSET0: ReadWrite, // 0x1C - GPSET1: ReadWrite, // 0x20 - __reserved_1: u32, // - GPCLR0: ReadWrite, // 0x28 - __reserved_2: [u32; 2], // - GPLEV0: ReadWrite, // 0x34 - GPLEV1: ReadWrite, // 0x38 - __reserved_3: u32, // - GPEDS0: ReadWrite, // 0x40 - GPEDS1: ReadWrite, // 0x44 - __reserved_4: [u32; 7], // - GPHEN0: ReadWrite, // 0x64 - GPHEN1: ReadWrite, // 0x68 - __reserved_5: [u32; 10], // - pub GPPUD: ReadWrite, // 0x94 - pub GPPUDCLK0: ReadWrite, // 0x98 - pub GPPUDCLK1: ReadWrite, // 0x9C -} - -/// Public interface to the GPIO MMIO area -pub struct GPIO { - base_addr: usize, -} - -impl ops::Deref for GPIO { - type Target = RegisterBlock; - - fn deref(&self) -> &Self::Target { - unsafe { &*self.ptr() } - } -} - -impl GPIO { - pub fn new(base_addr: usize) -> GPIO { - GPIO { base_addr } - } - - /// Returns a pointer to the register block - fn ptr(&self) -> *const RegisterBlock { - self.base_addr as *const _ - } -} diff --git a/.0E_cache_performance/src/main.rs b/.0E_cache_performance/src/main.rs deleted file mode 100644 index 9d2e8c64..00000000 --- a/.0E_cache_performance/src/main.rs +++ /dev/null @@ -1,69 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2018-2019 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#![no_std] -#![no_main] - -mod benchmark; -mod delays; -mod gpio; -mod mbox; -mod memory; -mod uart; - -fn kernel_entry() -> ! { - let gpio = gpio::GPIO::new(memory::map::physical::GPIO_BASE); - let mut mbox = mbox::Mbox::new(memory::map::physical::VIDEOCORE_MBOX_BASE); - let uart = uart::Uart::new(memory::map::physical::UART_BASE); - - // set up serial console - match uart.init(&mut mbox, &gpio) { - Ok(_) => uart.puts("\n[0] UART is live!\n"), - Err(_) => loop { - cortex_a::asm::wfe() // If UART fails, abort early - }, - } - - uart.puts("[1] Press a key to continue booting... "); - uart.getc(); - uart.puts("Greetings fellow Rustacean!\n"); - - match unsafe { memory::mmu::init() } { - Err(s) => { - uart.puts("[2][Error] MMU: "); - uart.puts(s); - uart.puts("\n"); - } - Ok(()) => uart.puts("[2] MMU online.\n"), - } - - benchmark::run(&uart); - - // echo everything back - loop { - uart.send(uart.getc()); - } -} - -raspi3_boot::entry!(kernel_entry); diff --git a/.0E_cache_performance/src/mbox.rs b/.0E_cache_performance/src/mbox.rs deleted file mode 100644 index 2e4bf0ad..00000000 --- a/.0E_cache_performance/src/mbox.rs +++ /dev/null @@ -1,163 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2018-2019 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -use core::ops; -use cortex_a::asm; -use register::{ - mmio::{ReadOnly, WriteOnly}, - register_bitfields, -}; - -register_bitfields! { - u32, - - STATUS [ - FULL OFFSET(31) NUMBITS(1) [], - EMPTY OFFSET(30) NUMBITS(1) [] - ] -} - -#[allow(non_snake_case)] -#[repr(C)] -pub struct RegisterBlock { - READ: ReadOnly, // 0x00 - __reserved_0: [u32; 5], // 0x04 - STATUS: ReadOnly, // 0x18 - __reserved_1: u32, // 0x1C - WRITE: WriteOnly, // 0x20 -} - -// Custom errors -pub enum MboxError { - ResponseError, - UnknownError, -} -pub type Result = ::core::result::Result; - -// Channels -pub mod channel { - pub const PROP: u32 = 8; -} - -// Tags -pub mod tag { - pub const SETCLKRATE: u32 = 0x38002; - pub const LAST: u32 = 0; -} - -// Clocks -pub mod clock { - pub const UART: u32 = 0x0_0000_0002; -} - -// Responses -mod response { - pub const SUCCESS: u32 = 0x8000_0000; - pub const ERROR: u32 = 0x8000_0001; // error parsing request buffer (partial response) -} - -pub const REQUEST: u32 = 0; - -// Public interface to the mailbox -#[repr(C)] -#[repr(align(16))] -pub struct Mbox { - // The address for buffer needs to be 16-byte aligned so that the - // Videcore can handle it properly. - pub buffer: [u32; 36], - base_addr: usize, -} - -/// Deref to RegisterBlock -/// -/// Allows writing -/// ``` -/// self.STATUS.read() -/// ``` -/// instead of something along the lines of -/// ``` -/// unsafe { (*Mbox::ptr()).STATUS.read() } -/// ``` -impl ops::Deref for Mbox { - type Target = RegisterBlock; - - fn deref(&self) -> &Self::Target { - unsafe { &*self.ptr() } - } -} - -impl Mbox { - pub fn new(base_addr: usize) -> Mbox { - Mbox { - buffer: [0; 36], - base_addr, - } - } - - /// Returns a pointer to the register block - fn ptr(&self) -> *const RegisterBlock { - self.base_addr as *const _ - } - - /// Make a mailbox call. Returns Err(MboxError) on failure, Ok(()) success - pub fn call(&self, channel: u32) -> Result<()> { - // wait until we can write to the mailbox - loop { - if !self.STATUS.is_set(STATUS::FULL) { - break; - } - - asm::nop(); - } - - let buf_ptr = self.buffer.as_ptr() as u32; - - // write the address of our message to the mailbox with channel identifier - self.WRITE.set((buf_ptr & !0xF) | (channel & 0xF)); - - // now wait for the response - loop { - // is there a response? - loop { - if !self.STATUS.is_set(STATUS::EMPTY) { - break; - } - - asm::nop(); - } - - let resp: u32 = self.READ.get(); - - // is it a response to our message? - if ((resp & 0xF) == channel) && ((resp & !0xF) == buf_ptr) { - // is it a valid successful response? - return match self.buffer[1] { - response::SUCCESS => Ok(()), - response::ERROR => Err(MboxError::ResponseError), - _ => Err(MboxError::UnknownError), - }; - } - } - } -} diff --git a/.0E_cache_performance/src/memory.rs b/.0E_cache_performance/src/memory.rs deleted file mode 100644 index 72db92dd..00000000 --- a/.0E_cache_performance/src/memory.rs +++ /dev/null @@ -1,225 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2019 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -use core::ops::RangeInclusive; - -pub mod mmu; - -/// System memory map. -#[rustfmt::skip] -pub mod map { - pub const START: usize = 0x0000_0000; - pub const END: usize = 0x3FFF_FFFF; - - pub mod physical { - pub const MMIO_BASE: usize = 0x3F00_0000; - pub const VIDEOCORE_MBOX_BASE: usize = MMIO_BASE + 0x0000_B880; - pub const GPIO_BASE: usize = MMIO_BASE + 0x0020_0000; - pub const UART_BASE: usize = MMIO_BASE + 0x0020_1000; - pub const MMIO_END: usize = super::END; - } - - pub mod virt { - pub const KERN_STACK_START: usize = super::START; - pub const KERN_STACK_END: usize = 0x0007_FFFF; - - // The second 2 MiB block - pub const CACHEABLE_START: usize = 0x0020_0000; - - // The third 2 MiB block - pub const NON_CACHEABLE_START: usize = 0x0040_0000; - pub const NON_CACHEABLE_END: usize = 0x005F_FFFF; - } -} - -/// Types used for compiling the virtual memory layout of the kernel using -/// address ranges. -pub mod kernel_mem_range { - use core::ops::RangeInclusive; - - #[derive(Copy, Clone)] - pub enum MemAttributes { - CacheableDRAM, - NonCacheableDRAM, - Device, - } - - #[derive(Copy, Clone)] - pub enum AccessPermissions { - ReadOnly, - ReadWrite, - } - - #[derive(Copy, Clone)] - pub enum Translation { - Identity, - Offset(usize), - } - - #[derive(Copy, Clone)] - pub struct AttributeFields { - pub mem_attributes: MemAttributes, - pub acc_perms: AccessPermissions, - pub execute_never: bool, - } - - impl Default for AttributeFields { - fn default() -> AttributeFields { - AttributeFields { - mem_attributes: MemAttributes::CacheableDRAM, - acc_perms: AccessPermissions::ReadWrite, - execute_never: true, - } - } - } - - pub struct Descriptor { - pub virtual_range: fn() -> RangeInclusive, - pub translation: Translation, - pub attribute_fields: AttributeFields, - } -} - -use kernel_mem_range::*; - -/// A virtual memory layout that is agnostic of the paging granularity that the -/// hardware MMU will use. -/// -/// Contains only special ranges, aka anything that is _not_ normal cacheable -/// DRAM. -static KERNEL_VIRTUAL_LAYOUT: [Descriptor; 5] = [ - // Kernel stack - Descriptor { - virtual_range: || { - RangeInclusive::new(map::virt::KERN_STACK_START, map::virt::KERN_STACK_END) - }, - translation: Translation::Identity, - attribute_fields: AttributeFields { - mem_attributes: MemAttributes::CacheableDRAM, - acc_perms: AccessPermissions::ReadWrite, - execute_never: true, - }, - }, - // Kernel code and RO data - Descriptor { - virtual_range: || { - // Using the linker script, we ensure that the RO area is consecutive and 4 - // KiB aligned, and we export the boundaries via symbols: - // - // [__ro_start, __ro_end) - extern "C" { - // The inclusive start of the read-only area, aka the address of the - // first byte of the area. - static __ro_start: u64; - - // The exclusive end of the read-only area, aka the address of - // the first byte _after_ the RO area. - static __ro_end: u64; - } - - unsafe { - // Notice the subtraction to turn the exclusive end into an - // inclusive end - RangeInclusive::new( - &__ro_start as *const _ as usize, - &__ro_end as *const _ as usize - 1, - ) - } - }, - translation: Translation::Identity, - attribute_fields: AttributeFields { - mem_attributes: MemAttributes::CacheableDRAM, - acc_perms: AccessPermissions::ReadOnly, - execute_never: false, - }, - }, - // Kernel data and BSS - Descriptor { - virtual_range: || { - extern "C" { - static __ro_end: u64; - static __bss_end: u64; - } - - unsafe { - RangeInclusive::new( - &__ro_end as *const _ as usize, - &__bss_end as *const _ as usize - 1, - ) - } - }, - translation: Translation::Identity, - attribute_fields: AttributeFields { - mem_attributes: MemAttributes::CacheableDRAM, - acc_perms: AccessPermissions::ReadWrite, - execute_never: true, - }, - }, - // Non-cacheable DRAM - Descriptor { - virtual_range: || { - RangeInclusive::new(map::virt::NON_CACHEABLE_START, map::virt::NON_CACHEABLE_END) - }, - translation: Translation::Offset(map::virt::CACHEABLE_START), - attribute_fields: AttributeFields { - mem_attributes: MemAttributes::NonCacheableDRAM, - acc_perms: AccessPermissions::ReadWrite, - execute_never: true, - }, - }, - // Device MMIO - Descriptor { - virtual_range: || RangeInclusive::new(map::physical::MMIO_BASE, map::physical::MMIO_END), - translation: Translation::Identity, - attribute_fields: AttributeFields { - mem_attributes: MemAttributes::Device, - acc_perms: AccessPermissions::ReadWrite, - execute_never: true, - }, - }, -]; - -/// For a given virtual address, find and return the output address and -/// according attributes. -/// -/// If the address is not covered in VIRTUAL_LAYOUT, return a default for normal -/// cacheable DRAM. -fn get_virt_addr_properties(virt_addr: usize) -> Result<(usize, AttributeFields), &'static str> { - if virt_addr > map::END { - return Err("Address out of range."); - } - - for i in KERNEL_VIRTUAL_LAYOUT.iter() { - if (i.virtual_range)().contains(&virt_addr) { - let output_addr = match i.translation { - Translation::Identity => virt_addr, - Translation::Offset(a) => a + (virt_addr - (i.virtual_range)().start()), - }; - - return Ok((output_addr, i.attribute_fields)); - } - } - - Ok((virt_addr, AttributeFields::default())) -} diff --git a/.0E_cache_performance/src/memory/mmu.rs b/.0E_cache_performance/src/memory/mmu.rs deleted file mode 100644 index aa4e43c6..00000000 --- a/.0E_cache_performance/src/memory/mmu.rs +++ /dev/null @@ -1,349 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2018-2019 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -use crate::memory::{get_virt_addr_properties, AttributeFields}; -use cortex_a::{barrier, regs::*}; -use register::register_bitfields; - -register_bitfields! {u64, - // AArch64 Reference Manual page 2150 - STAGE1_DESCRIPTOR [ - /// Privileged execute-never - PXN OFFSET(53) NUMBITS(1) [ - False = 0, - True = 1 - ], - - /// Various address fields, depending on use case - LVL2_OUTPUT_ADDR_4KiB OFFSET(21) NUMBITS(27) [], // [47:21] - NEXT_LVL_TABLE_ADDR_4KiB OFFSET(12) NUMBITS(36) [], // [47:12] - - /// 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) [ - Block = 0, - Table = 1 - ], - - VALID OFFSET(0) NUMBITS(1) [ - False = 0, - True = 1 - ] - ] -} - -const FOUR_KIB: usize = 4 * 1024; -const FOUR_KIB_SHIFT: usize = 12; // log2(4 * 1024) - -const TWO_MIB: usize = 2 * 1024 * 1024; -const TWO_MIB_SHIFT: usize = 21; // log2(2 * 1024 * 1024) - -/// A descriptor pointing to the next page table. -struct TableDescriptor(register::FieldValue); - -impl TableDescriptor { - fn new(next_lvl_table_addr: usize) -> Result { - if next_lvl_table_addr % FOUR_KIB != 0 { - return Err("TableDescriptor: Address is not 4 KiB aligned."); - } - - let shifted = next_lvl_table_addr >> FOUR_KIB_SHIFT; - - Ok(TableDescriptor( - STAGE1_DESCRIPTOR::VALID::True - + STAGE1_DESCRIPTOR::TYPE::Table - + STAGE1_DESCRIPTOR::NEXT_LVL_TABLE_ADDR_4KiB.val(shifted as u64), - )) - } - - fn value(&self) -> u64 { - self.0.value - } -} - -/// A function that maps the generic memory range attributes to HW-specific -/// attributes of the MMU. -fn into_mmu_attributes( - attribute_fields: AttributeFields, -) -> register::FieldValue { - use crate::memory::{AccessPermissions, MemAttributes}; - - // Memory attributes - let mut desc = match attribute_fields.mem_attributes { - MemAttributes::CacheableDRAM => { - STAGE1_DESCRIPTOR::SH::InnerShareable + STAGE1_DESCRIPTOR::AttrIndx.val(mair::NORMAL) - } - MemAttributes::NonCacheableDRAM => { - STAGE1_DESCRIPTOR::SH::InnerShareable - + STAGE1_DESCRIPTOR::AttrIndx.val(mair::NORMAL_NON_CACHEABLE) - } - MemAttributes::Device => { - STAGE1_DESCRIPTOR::SH::OuterShareable + STAGE1_DESCRIPTOR::AttrIndx.val(mair::DEVICE) - } - }; - - // Access Permissions - desc += match attribute_fields.acc_perms { - AccessPermissions::ReadOnly => STAGE1_DESCRIPTOR::AP::RO_EL1, - AccessPermissions::ReadWrite => STAGE1_DESCRIPTOR::AP::RW_EL1, - }; - - // Execute Never - desc += if attribute_fields.execute_never { - STAGE1_DESCRIPTOR::PXN::True - } else { - STAGE1_DESCRIPTOR::PXN::False - }; - - desc -} - -/// A Level2 block descriptor with 2 MiB aperture. -/// -/// The output points to physical memory. -struct Lvl2BlockDescriptor(register::FieldValue); - -impl Lvl2BlockDescriptor { - fn new( - output_addr: usize, - attribute_fields: AttributeFields, - ) -> Result { - if output_addr % TWO_MIB != 0 { - return Err("BlockDescriptor: Address is not 2 MiB aligned."); - } - - let shifted = output_addr >> TWO_MIB_SHIFT; - - Ok(Lvl2BlockDescriptor( - STAGE1_DESCRIPTOR::VALID::True - + STAGE1_DESCRIPTOR::AF::True - + into_mmu_attributes(attribute_fields) - + STAGE1_DESCRIPTOR::TYPE::Block - + STAGE1_DESCRIPTOR::LVL2_OUTPUT_ADDR_4KiB.val(shifted as u64), - )) - } - - fn value(&self) -> u64 { - self.0.value - } -} - -/// A page descriptor with 4 KiB aperture. -/// -/// The output points to physical memory. -struct PageDescriptor(register::FieldValue); - -impl PageDescriptor { - fn new( - output_addr: usize, - attribute_fields: AttributeFields, - ) -> Result { - if output_addr % FOUR_KIB != 0 { - return Err("PageDescriptor: Address is not 4 KiB aligned."); - } - - let shifted = output_addr >> FOUR_KIB_SHIFT; - - Ok(PageDescriptor( - STAGE1_DESCRIPTOR::VALID::True - + STAGE1_DESCRIPTOR::AF::True - + into_mmu_attributes(attribute_fields) - + STAGE1_DESCRIPTOR::TYPE::Table - + STAGE1_DESCRIPTOR::NEXT_LVL_TABLE_ADDR_4KiB.val(shifted as u64), - )) - } - - fn value(&self) -> u64 { - self.0.value - } -} - -/// Constants for indexing the MAIR_EL1. -#[allow(dead_code)] -mod mair { - pub const DEVICE: u64 = 0; - pub const NORMAL: u64 = 1; - pub const NORMAL_NON_CACHEABLE: u64 = 2; -} - -/// Setup function for the MAIR_EL1 register. -fn set_up_mair() { - // Define the three memory types that we will map. Cacheable and - // non-cacheable normal DRAM, and device. - MAIR_EL1.write( - // Attribute 2 - MAIR_EL1::Attr2_HIGH::Memory_OuterNonCacheable - + MAIR_EL1::Attr2_LOW_MEMORY::InnerNonCacheable - - // Attribute 1 - + MAIR_EL1::Attr1_HIGH::Memory_OuterWriteBack_NonTransient_ReadAlloc_WriteAlloc - + MAIR_EL1::Attr1_LOW_MEMORY::InnerWriteBack_NonTransient_ReadAlloc_WriteAlloc - - // Attribute 0 - + MAIR_EL1::Attr0_HIGH::Device - + MAIR_EL1::Attr0_LOW_DEVICE::Device_nGnRE, - ); -} - -trait BaseAddr { - fn base_addr_u64(&self) -> u64; - fn base_addr_usize(&self) -> usize; -} - -impl BaseAddr for [u64; 512] { - fn base_addr_u64(&self) -> u64 { - self as *const u64 as u64 - } - - fn base_addr_usize(&self) -> usize { - self as *const u64 as usize - } -} - -const NUM_ENTRIES_4KIB: usize = 512; - -// A wrapper struct is needed here so that the align attribute can be used. -#[repr(C)] -#[repr(align(4096))] -struct PageTable { - entries: [u64; NUM_ENTRIES_4KIB], -} - -/// The LVL2 page table containng the 2 MiB entries. -static mut LVL2_TABLE: PageTable = PageTable { - entries: [0; NUM_ENTRIES_4KIB], -}; - -/// The LVL3 page table containing the 4 KiB entries. -/// -/// The first entry of the LVL2_TABLE will forward to this table. -static mut LVL3_TABLE: PageTable = PageTable { - entries: [0; NUM_ENTRIES_4KIB], -}; - -/// Set up identity mapped page tables for the first 1 GiB of address space. -/// -/// The first 2 MiB are 4 KiB granule, the rest 2 MiB. -/// -/// # Safety -/// -/// - User must ensure that the hardware supports the paremeters being set here. -pub unsafe fn init() -> Result<(), &'static str> { - // Prepare the memory attribute indirection register. - set_up_mair(); - - // Point the first 2 MiB of virtual addresses to the follow-up LVL3 - // page-table. - LVL2_TABLE.entries[0] = match TableDescriptor::new(LVL3_TABLE.entries.base_addr_usize()) { - Err(s) => return Err(s), - Ok(d) => d.value(), - }; - - // Fill the rest of the LVL2 (2 MiB) entries as block descriptors. - // - // Notice the skip(1) which makes the iteration start at the second 2 MiB - // block (0x20_0000). - for (block_descriptor_nr, entry) in LVL2_TABLE.entries.iter_mut().enumerate().skip(1) { - let virt_addr = block_descriptor_nr << TWO_MIB_SHIFT; - - let (output_addr, attribute_fields) = match get_virt_addr_properties(virt_addr) { - Err(s) => return Err(s), - Ok((a, b)) => (a, b), - }; - - let block_desc = match Lvl2BlockDescriptor::new(output_addr, attribute_fields) { - Err(s) => return Err(s), - Ok(desc) => desc, - }; - - *entry = block_desc.value(); - } - - // Finally, fill the single LVL3 table (4 KiB granule). - for (page_descriptor_nr, entry) in LVL3_TABLE.entries.iter_mut().enumerate() { - let virt_addr = page_descriptor_nr << FOUR_KIB_SHIFT; - - let (output_addr, attribute_fields) = match get_virt_addr_properties(virt_addr) { - Err(s) => return Err(s), - Ok((a, b)) => (a, b), - }; - - let page_desc = match PageDescriptor::new(output_addr, attribute_fields) { - Err(s) => return Err(s), - Ok(desc) => desc, - }; - - *entry = page_desc.value(); - } - - // Point to the LVL2 table base address in TTBR0. - TTBR0_EL1.set_baddr(LVL2_TABLE.entries.base_addr_u64()); - - // Configure various settings of stage 1 of the EL1 translation regime. - let ips = ID_AA64MMFR0_EL1.read(ID_AA64MMFR0_EL1::PARange); - TCR_EL1.write( - TCR_EL1::TBI0::Ignored - + TCR_EL1::IPS.val(ips) - + TCR_EL1::TG0::KiB_4 // 4 KiB granule - + TCR_EL1::SH0::Inner - + TCR_EL1::ORGN0::WriteBack_ReadAlloc_WriteAlloc_Cacheable - + TCR_EL1::IRGN0::WriteBack_ReadAlloc_WriteAlloc_Cacheable - + TCR_EL1::EPD0::EnableTTBR0Walks - + TCR_EL1::T0SZ.val(34), // Start walks at level 2 - ); - - // 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(()) -} diff --git a/.0E_cache_performance/src/uart.rs b/.0E_cache_performance/src/uart.rs deleted file mode 100644 index 093ef6a7..00000000 --- a/.0E_cache_performance/src/uart.rs +++ /dev/null @@ -1,301 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2018-2019 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -use crate::delays; -use crate::gpio; -use crate::mbox; -use core::{ - ops, - sync::atomic::{compiler_fence, Ordering}, -}; -use cortex_a::asm; -use register::{mmio::*, register_bitfields}; - -// PL011 UART registers. -// -// Descriptions taken from -// https://github.com/raspberrypi/documentation/files/1888662/BCM2837-ARM-Peripherals.-.Revised.-.V2-1.pdf -register_bitfields! { - u32, - - /// Flag Register - FR [ - /// Transmit FIFO full. The meaning of this bit depends on the - /// state of the FEN bit in the UARTLCR_ LCRH 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 UARTLCR_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) [] - ], - - /// Integer Baud rate divisor - IBRD [ - /// Integer Baud rate divisor - IBRD OFFSET(0) NUMBITS(16) [] - ], - - /// Fractional Baud rate divisor - FBRD [ - /// Fractional Baud rate divisor - FBRD OFFSET(0) NUMBITS(6) [] - ], - - /// Line Control register - LCRH [ - /// Word length. These bits indicate the number of data bits - /// transmitted or received in a frame. - WLEN OFFSET(5) NUMBITS(2) [ - FiveBit = 0b00, - SixBit = 0b01, - SevenBit = 0b10, - EightBit = 0b11 - ] - ], - - /// Control Register - CR [ - /// Receive enable. If this bit is set to 1, the receive - /// section of the UART is enabled. Data reception occurs for - /// UART signals. 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 UART signals. 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 - 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 - ] - ], - - /// Interupt Clear Register - ICR [ - /// Meta field for all pending interrupts - ALL OFFSET(0) NUMBITS(11) [] - ] -} - -#[allow(non_snake_case)] -#[repr(C)] -pub struct RegisterBlock { - DR: ReadWrite, // 0x00 - __reserved_0: [u32; 5], // 0x04 - FR: ReadOnly, // 0x18 - __reserved_1: [u32; 2], // 0x1c - IBRD: WriteOnly, // 0x24 - FBRD: WriteOnly, // 0x28 - LCRH: WriteOnly, // 0x2C - CR: WriteOnly, // 0x30 - __reserved_2: [u32; 4], // 0x34 - ICR: WriteOnly, // 0x44 -} - -pub enum UartError { - MailboxError, -} -pub type Result = ::core::result::Result; - -pub struct Uart { - base_addr: usize, -} - -impl ops::Deref for Uart { - type Target = RegisterBlock; - - fn deref(&self) -> &Self::Target { - unsafe { &*self.ptr() } - } -} - -impl Uart { - pub fn new(base_addr: usize) -> Uart { - Uart { base_addr } - } - - /// Returns a pointer to the register block - fn ptr(&self) -> *const RegisterBlock { - self.base_addr as *const _ - } - - ///Set baud rate and characteristics (115200 8N1) and map to GPIO - pub fn init(&self, mbox: &mut mbox::Mbox, gpio: &gpio::GPIO) -> Result<()> { - // turn off UART0 - self.CR.set(0); - - // set up clock for consistent divisor values - mbox.buffer[0] = 9 * 4; - mbox.buffer[1] = mbox::REQUEST; - mbox.buffer[2] = mbox::tag::SETCLKRATE; - mbox.buffer[3] = 12; - mbox.buffer[4] = 8; - mbox.buffer[5] = mbox::clock::UART; // UART clock - mbox.buffer[6] = 4_000_000; // 4Mhz - mbox.buffer[7] = 0; // skip turbo setting - mbox.buffer[8] = mbox::tag::LAST; - - // Insert a compiler fence that ensures that all stores to the - // mbox buffer are finished before the GPU is signaled (which - // is done by a store operation as well). - compiler_fence(Ordering::Release); - - if mbox.call(mbox::channel::PROP).is_err() { - return Err(UartError::MailboxError); // Abort if UART clocks couldn't be set - }; - - // map UART0 to GPIO pins - gpio.GPFSEL1 - .modify(gpio::GPFSEL1::FSEL14::TXD0 + gpio::GPFSEL1::FSEL15::RXD0); - - gpio.GPPUD.set(0); // enable pins 14 and 15 - delays::wait_cycles(150); - - gpio.GPPUDCLK0.modify( - gpio::GPPUDCLK0::PUDCLK14::AssertClock + gpio::GPPUDCLK0::PUDCLK15::AssertClock, - ); - delays::wait_cycles(150); - - gpio.GPPUDCLK0.set(0); - - self.ICR.write(ICR::ALL::CLEAR); - self.IBRD.write(IBRD::IBRD.val(2)); // Results in 115200 baud - self.FBRD.write(FBRD::FBRD.val(0xB)); - self.LCRH.write(LCRH::WLEN::EightBit); // 8N1 - self.CR - .write(CR::UARTEN::Enabled + CR::TXE::Enabled + CR::RXE::Enabled); - - Ok(()) - } - - /// Send a character - pub fn send(&self, c: char) { - // wait until we can send - loop { - if !self.FR.is_set(FR::TXFF) { - break; - } - - asm::nop(); - } - - // write the character to the buffer - self.DR.set(c as u32); - } - - /// Receive a character - pub fn getc(&self) -> char { - // wait until something is in the buffer - loop { - if !self.FR.is_set(FR::RXFE) { - break; - } - - asm::nop(); - } - - // read it and return - let mut ret = self.DR.get() as u8 as char; - - // convert carrige return to newline - if ret == '\r' { - ret = '\n' - } - - ret - } - - /// Display a string - pub fn puts(&self, string: &str) { - for c in string.chars() { - // convert newline to carrige return + newline - if c == '\n' { - self.send('\r') - } - - self.send(c); - } - } - - /// Display a binary value in hexadecimal - pub fn hex(&self, d: u64) { - let mut n; - - for i in 0..16 { - // get highest tetrad - n = d.wrapping_shr(60 - i * 4) & 0xF; - - // 0-9 => '0'-'9', 10-15 => 'A'-'F' - // Add proper offset for ASCII table - if n > 9 { - n += 0x37; - } else { - n += 0x30; - } - - self.send(n as u8 as char); - } - } - - /// Display a binary value in decimal - pub fn dec(&self, d: u32) { - let mut digits: [char; 10] = ['\0'; 10]; - let mut d = d; - - for i in digits.iter_mut() { - *i = ((d % 10) + 0x30) as u8 as char; - - d /= 10; - - if d == 0 { - break; - } - } - - for c in digits.iter().rev() { - self.send(*c); - } - } -} diff --git a/.0F_globals_synchronization_println/.cargo/config b/.0F_globals_synchronization_println/.cargo/config deleted file mode 100644 index de3f84c9..00000000 --- a/.0F_globals_synchronization_println/.cargo/config +++ /dev/null @@ -1,5 +0,0 @@ -[target.aarch64-unknown-none-softfloat] -rustflags = [ - "-C", "link-arg=-Tlink.ld", - "-C", "target-cpu=cortex-a53", -] diff --git a/.0F_globals_synchronization_println/Cargo.lock b/.0F_globals_synchronization_println/Cargo.lock deleted file mode 100644 index d218ad56..00000000 --- a/.0F_globals_synchronization_println/Cargo.lock +++ /dev/null @@ -1,57 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -[[package]] -name = "cortex-a" -version = "2.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "register 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "kernel8" -version = "0.1.0" -dependencies = [ - "cortex-a 2.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "raspi3_boot 0.1.0", - "register 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "panic-abort" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "r0" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "raspi3_boot" -version = "0.1.0" -dependencies = [ - "cortex-a 2.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "panic-abort 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "r0 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "register" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "tock-registers 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tock-registers" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[metadata] -"checksum cortex-a 2.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cbb16c411ab74044f174746a6cbae67bcdebea126e376b5441e5986e6a6aa950" -"checksum panic-abort 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2c14a66511ed17b6a8b4256b868d7fd207836d891db15eea5195dbcaf87e630f" -"checksum r0 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e2a38df5b15c8d5c7e8654189744d8e396bddc18ad48041a500ce52d6948941f" -"checksum register 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "469bb5ddde81d67fb8bba4e14d77689b8166cfd077abe7530591cefe29d05823" -"checksum tock-registers 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c758f5195a2e0df9d9fecf6f506506b2766ff74cf64db1e995c87e2761a5c3e2" diff --git a/.0F_globals_synchronization_println/Cargo.toml b/.0F_globals_synchronization_println/Cargo.toml deleted file mode 100644 index 43d1e22e..00000000 --- a/.0F_globals_synchronization_println/Cargo.toml +++ /dev/null @@ -1,13 +0,0 @@ -[package] -name = "kernel8" -version = "0.1.0" -authors = ["Andre Richter "] -edition = "2018" - -[dependencies] -raspi3_boot = { path = "raspi3_boot" } -cortex-a = "2.7.0" -register = "0.3.3" - -[package.metadata.cargo-xbuild] -sysroot_path = "../xbuild_sysroot" diff --git a/.0F_globals_synchronization_println/Makefile b/.0F_globals_synchronization_println/Makefile deleted file mode 100644 index 4e02fa9d..00000000 --- a/.0F_globals_synchronization_println/Makefile +++ /dev/null @@ -1,103 +0,0 @@ -# -# MIT License -# -# Copyright (c) 2018-2019 Andre Richter -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# - -TARGET = aarch64-unknown-none-softfloat - -SOURCES = $(wildcard **/*.rs) $(wildcard **/*.S) link.ld - - -XRUSTC_CMD = cargo xrustc --target=$(TARGET) --release -CARGO_OUTPUT = target/$(TARGET)/release/kernel8 - -OBJCOPY = cargo objcopy -- -OBJCOPY_PARAMS = --strip-all -O binary - -CONTAINER_UTILS = andrerichter/raspi3-utils -CONTAINER_OPENOCD = andrerichter/raspi3-openocd -# CONTAINER_OPENOCD_ARG = -f openocd/tcl/interface/ftdi/olimex-jtag-tiny.cfg -f /openocd/rpi3.cfg -CONTAINER_GDB = andrerichter/raspi3-gdb - -DOCKER_CMD = docker run -it --rm -DOCKER_ARG_CURDIR = -v $(shell pwd):/work -w /work -DOCKER_ARG_TTY = --privileged -v /dev:/dev -DOCKER_ARG_JTAG = -v $(shell pwd)/../X1_JTAG_boot:/jtag -DOCKER_ARG_NET = --network host - -DOCKER_EXEC_QEMU = qemu-system-aarch64 -M raspi3 -kernel kernel8.img -DOCKER_EXEC_RASPBOOT = raspbootcom -DOCKER_EXEC_RASPBOOT_DEV = /dev/ttyUSB0 -# DOCKER_EXEC_RASPBOOT_DEV = /dev/ttyACM0 - -.PHONY: all qemu raspboot clippy clean objdump nm jtagboot openocd gdb gdb-opt0 - -all: clean kernel8.img - -$(CARGO_OUTPUT): $(SOURCES) - $(XRUSTC_CMD) - -kernel8.img: $(CARGO_OUTPUT) - cp $< . - $(OBJCOPY) $(OBJCOPY_PARAMS) $< kernel8.img - -qemu: all - $(DOCKER_CMD) $(DOCKER_ARG_CURDIR) $(CONTAINER_UTILS) \ - $(DOCKER_EXEC_QEMU) -serial stdio - -raspboot: all - $(DOCKER_CMD) $(DOCKER_ARG_CURDIR) $(DOCKER_ARG_TTY) \ - $(CONTAINER_UTILS) $(DOCKER_EXEC_RASPBOOT) $(DOCKER_EXEC_RASPBOOT_DEV) \ - kernel8.img - -clippy: - cargo xclippy --target=$(TARGET) - -clean: - cargo clean - -objdump: - cargo objdump --target $(TARGET) -- -disassemble -print-imm-hex kernel8 - -nm: - cargo nm --target $(TARGET) -- kernel8 | sort - -jtagboot: - $(DOCKER_CMD) $(DOCKER_ARG_TTY) $(DOCKER_ARG_JTAG) $(CONTAINER_UTILS) \ - $(DOCKER_EXEC_RASPBOOT) $(DOCKER_EXEC_RASPBOOT_DEV) /jtag/jtag_boot.img - -openocd: - $(DOCKER_CMD) $(DOCKER_ARG_TTY) $(DOCKER_ARG_NET) $(CONTAINER_OPENOCD) \ - $(CONTAINER_OPENOCD_ARG) - -define gen_gdb - $(XRUSTC_CMD) -- $1 - cp $(CARGO_OUTPUT) kernel8_for_jtag - $(DOCKER_CMD) $(DOCKER_ARG_CURDIR) $(DOCKER_ARG_NET) $(CONTAINER_GDB) \ - gdb-multiarch -q kernel8_for_jtag -endef - -gdb: clean $(SOURCES) - $(call gen_gdb,-C debuginfo=2) - -gdb-opt0: clean $(SOURCES) - $(call gen_gdb,-C debuginfo=2 -C opt-level=0) diff --git a/.0F_globals_synchronization_println/README.md b/.0F_globals_synchronization_println/README.md deleted file mode 100644 index bd0f34c8..00000000 --- a/.0F_globals_synchronization_println/README.md +++ /dev/null @@ -1,455 +0,0 @@ -# Tutorial 0F - Globals, Synchronization and `println!` - -Until now, we use a rather inelegant way of printing messages: We are directly -calling the `UART` device driver's functions for putting and receiving -characters on the serial line, e.g. `uart.puts()`. Also, we have only very -bare-bones implementations for printing hex or decimal integers. This both looks -ugly in the code, and is not very flexible. For example, if at some point we -decide to replace the `UART` as the output device, we have to manually find and -replace all the respective calls, and need to take care that we do not use the -device before it was probed or after it was shut down. - -Hence, it is time to get some elegant format-string-based printing going, like -we know it from other languages, e.g. `C`'s `printf()`, and introduce an -abstraction layer that allows us to decouple printing functions from the actual -output device. - -On this occasion, we will also learn important lessons about about **mutable -global variables**, which are called **static variables** in Rust, get to know -**trait objects** and hear about Rust's concept of **interior mutability**. - -## The Virtual Console - -First, we introduce a `Console` type in `src/devics/virt/console.rs`: - -```rust -pub struct Console { - output: Output, -} -``` - -When everything is finished, this type will be used as a `virtual device` that -forwards calls to printing functions to the currently active output device. - -### Code Restructuring - -In case you wonder about the path: The introduction of the first `virtual -device` in our code was a good opportunity to introduce a better structure for -our modules. Basically, we differentiate between real (HW) and virtual devices -now: - -```console -src -├── devices -│   ├── hw -│   │   ├── gpio.rs -│   │   ├── uart.rs -│   │   └── videocore_mbox.rs -│   ├── hw.rs -│   ├── virt -│   │   └── console.rs -│   └── virt.rs -├── devices.rs -``` - -### Console Implementation - -The `Console` type has a single field of type `Output`: - -```rust -/// Possible outputs which the console can store. -pub enum Output { - None(NullConsole), - Uart(hw::Uart), -} -``` - -How will it be used? Let us have a look: - -```rust -impl Console { - pub const fn new() -> Console { - Console { - output: Output::None(NullConsole {}), - } - } - - #[inline(always)] - fn current_ptr(&self) -> &dyn ConsoleOps { - match &self.output { - Output::None(i) => i, - Output::Uart(i) => i, - } - } - - /// Overwrite the current output. The old output will go out of scope and - /// it's Drop function will be called. - pub fn replace_with(&mut self, x: Output) { - self.current_ptr().flush(); - - self.output = x; - } -``` - -Basically two things can be done. - -1. `output` can be replaced during runtime. -2. Using `current_ptr()`, a reference to the current `output` is returned as a - [trait object](https://doc.rust-lang.org/edition-guide/rust-2018/trait-system/dyn-trait-for-trait-objects.html) - that implements the `ConsoleOps` trait. Hence, for the first time in the - tutorials, Rust's [dynamic dispatch](https://doc.rust-lang.org/book/ch17-02-trait-objects.html#trait-objects-perform-dynamic-dispatch) - is used. - -So what does the `ConsoleOps` trait define? - -```rust -pub trait ConsoleOps: Drop { - fn putc(&self, c: char) {} - fn puts(&self, string: &str) {} - fn getc(&self) -> char { - ' ' - } - fn flush(&self) {} -} -``` - -All in all, it is basically the same that is already present in the `UART` -driver: Reading and writing a single character, and writing a whole string. What -is new is the `flush` function, which is meant for devices that implement output -FIFOs. - -So any device that can be stored into `output` must implement this trait, -otherwise a compile-time error would occur. - -### Dispatching to the Current Output - -In order to use the `Console` as a HW-agnostic device for printing, some -dispatching code is needed. Therefore, it implements the `ConsoleOps` trait -itself, and forwards the trait calls during run-time to whatever is stored in -`output`. - -```rust -/// Dispatch the respective function to the currently stored output device. -impl ConsoleOps for Console { - fn putc(&self, c: char) { - self.current_ptr().putc(c); - } - - fn puts(&self, string: &str) { - self.current_ptr().puts(string); - } - - fn getc(&self) -> char { - self.current_ptr().getc() - } - - fn flush(&self) { - self.current_ptr().flush() - } -} -``` - -Congratulations :tada:. - -This is not much code, but enough so that you've implemented your first, very -basic kind of [Hardware Abstraction Layer (HAL)](https://en.wikipedia.org/wiki/Hardware_abstraction). - -## Making it Static (and Mutable) - -Now we need an instance of the virtual console in form of a _static variable_ -(remember, this is Rust speak for global) to make our life easier and our code -less bloated. Doing so enables calls to printing functions from every place in -the code, without dragging along references to the console everywhere. - -At times, we also want to replace the `output` field of our console variable, so we -need a `mutable` static. - -In system programming languages like `C` or `C++`, this would be quite easy. For -example, the declaration below is enough to allow mutation of `console`, since -the language does not have a built-in concept of mutable and immutable types: - -```C++ -Console console = Console::Console(); - -int kernel_entry() { - console.replace_with(...) -} -``` - -However, in Rust, if you do - -```rust -static mut CONSOLE: devices::virt::Console = - devices::virt::Console::new(); - -fn kernel_entry() -> ! { - CONSOLE.replace_with(...) // <-- Compiler: "Where's my unsafe{}?!!" -} -``` - -the compiler will shout angrily at you whenever you try to use `CONSOLE` that -this is unsafe code, and frankly, that is a good thing. - -In contrast to the C-family of languages, Rust is from the ground up designed -with multi-core and multi-threading in mind. Thanks to the **borrow-checker**, -Rust ensures that in safe code, there can ever only exist a single mutable -reference to a variable. - -This way, it is ensured at compile time that no situations are created where -code that might execute concurrently (that is, for example, code running at the -same time on different physical processor cores) fiddles with the same data -or resources in an unsychronized way. - -By instantiating a **mutable** static variable, we allow all code from every -source-code file to easily operate on this mutable reference. Since the variable -is not instantiated at runtime and explicitly passed on in function calls, it is -not possible for the borrow-checker to draw any conclusions about the number of -mutable references in use. As a result, access to mutable statics needs to be -marked with `unsafe{}` in any case in Rust. - -So how can we make this safe again? What we need in this case is a -**synchronization primitive**. You've probably heard of them -before. **Spinlocks** and **mutexes** are two examples. What they do is to -ensure _at runtime_ that there is no concurrent access to the data they protect. - -### How to Build a Synchronization Primitive in Rust - -In contrast to mutable statics, **immutable statics** are considered safe by -Rust as long as they are marked -[Sync](https://doc.rust-lang.org/std/marker/trait.Sync.html). It is perfectly -fine to share an infinite number of references to them. So here is the strategy: - -1. Build a wrapper type that can be instantiated as an **immutable static** and - that encapsulates the actual mutable data. -2. Provide a function that returns a mutable reference to the wrapped type. -3. This function will need to be marked `unsafe`. In order to consider it safe - nonetheless, it must feature code that ensures at runtime that only a - single reference is given out at times. - -This is the basic concept of all synchronization primitives in Rust. For -educational purposes, in the tutorials, we will roll our own, and not reuse -stuff from the core library or popular crates like [spin](https://crates.io/crates/spin). - -### The `NullLock` - -The first implementation will actually be very easy. We do not yet have to worry -that a situation arises where (i) code tries to take the lock while it is -already locked or (ii) where there is contention for the lock. This is because -the kernel is still in a state where everything is executed linearly from start -to finish: - -1. Asynchronous exceptions like Interrupts are not enabled yet, so there never is - any interruption in the program flow. -2. We know that we currently do not have any code yet that raises synchronous exceptions. -2. Only a single core is active, all others are parked. Therefore, no concurrent - execution of code is happening. - -> Hint: You will learn about asynchronous and synchronous exceptions in the -> tutorial after the next. - -So all that needs be done is wrapping the data and giving back the mutable -reference. Introducing the `NullLock` in `sync.rs`: - -```rust -use core::cell::UnsafeCell; - -pub struct NullLock { - data: UnsafeCell, -} - -unsafe impl Sync for NullLock {} - -impl NullLock { - pub const fn new(data: T) -> NullLock { - NullLock { - data: UnsafeCell::new(data), - } - } -} - -impl NullLock { - pub fn lock(&self, f: F) -> R - where - F: FnOnce(&mut T) -> R, - { - // In a real lock, there would be code around this line that ensures - // that this mutable reference will ever only be given out one at a - // time. - f(unsafe { &mut *self.data.get() }) - } -} -``` - -First, the lock type is marked with the `Sync` [marker trait](https://doc.rust-lang.org/std/marker/trait.Sync.html) to tell the -compiler that it is safe to share references to it between threads. More -literature on this topic in [[1]](https://doc.rust-lang.org/beta/nomicon/send-and-sync.html)[[2]](https://doc.rust-lang.org/book/ch16-04-extensible-concurrency-sync-and-send.html). - -Second, a `lock()` function is provided which returns mutable references to the -wrapped data in the -[UnsafeCell](https://doc.rust-lang.org/std/cell/struct.UnsafeCell.html). Quoting -from the UnsafeCell documentation: - - -> The core primitive for interior mutability in Rust. -> -> UnsafeCell is a type that wraps some T and indicates unsafe interior operations on the wrapped type. Types with an UnsafeCell field are considered to have an 'unsafe interior'. The UnsafeCell type is the only legal way to obtain aliasable data that is considered mutable. In general, transmuting an &T type into an &mut T is considered undefined behavior. -> -> [...] -> -> The UnsafeCell API itself is technically very simple: it gives you a raw pointer *mut T to its contents. It is up to you as the abstraction designer to use that raw pointer correctly. - -In upcoming tutorials, when the need arises, the `NullLock` will be gradually -extended to provide proper locking using architectural features the RPi3 -provides for this case. - -### Closures - -The Rust standard library and some popular crates for synchronization primitives -use the concept of returning -[RAII](https://en.wikipedia.org/wiki/Resource_acquisition_is_initialization) -type [guards](https://doc.rust-lang.org/std/sync/struct.Mutex.html#method.lock) -that allow usage of the locked data until the guard goes out of scope. - -In the author's opinion, RAII guards have the disadvantage that the user must -explicitly scope their lifetime with braces `{}`, which is prone to being -forgotten. This in turn would lead to the lock being held much longer than -needed. For educational purposes, the `lock()` functions in the tutorials will -therefore take [closures](https://doc.rust-lang.org/book/ch13-01-closures.html) -as arguments. They give better visual cues about the parts of the code during -which the lock is held. - -Example: - -```rust -static CONSOLE: sync::NullLock = - sync::NullLock::new(devices::virt::Console::new()); - -fn kernel_entry() -> ! { - - ... - - CONSOLE.lock(|c| { // - c.getc(); // Unlocked only inside here - }); // - - ... -} -``` - -> Disclaimer: No investigations have been made if using closures results in -> poorer performance. If so, the hit is taken willingly for said educational -> purposes. - -## `print!` and `println!` - -In `macros.rs`, printing macros from the Rust core library are reused to empower -the kernel with [all the format-string beauty Rust provides](https://doc.rust-lang.org/std/fmt/). The macros eventually call the -function `_print()`, which redirects to the global `CONSOLE` of the kernel (will -be introduced in a minute): - -```rust -pub fn _print(args: fmt::Arguments) { - use core::fmt::Write; - - crate::CONSOLE.lock(|c| { - c.write_fmt(args).unwrap(); - }) -} -``` - -To make this work, the virtual console needs to provide an implementation of -`core::fmt::Write`. In this case, it is as easy as forwarding the -macro-formatted string via `self.current_ptr().puts(s)`. - -## Stitching it All Together - -In `main.rs`, a static `CONSOLE` is defined: - -```rust -/// The global console. Output of the print! and println! macros. -static CONSOLE: sync::NullLock = - sync::NullLock::new(devices::virt::Console::new()); -``` - -By default, it encapsulates a `NullConsole` output, which, well, does -nothing. This is just a safety measure to ensure that the print macros can be -called any time, even before a real physical output is available. In `main.rs`, -a respective call is made that will never appear as an output anywhere: - -```rust -// This will be invisible, because CONSOLE is dispatching to the NullConsole -// at this point in time. -println!("Is there anybody out there?"); -``` - -After initializing the `GPIO` and `VidecoreMbox` drivers, the `UART` is -initialized and replaces the `NullConsole` as the static output: - -```rust -match uart.init(&mut v_mbox, &gpio) { - Ok(_) => { - CONSOLE.lock(|c| { - // Moves uart into the global CONSOLE. It is not accessible - // anymore for the remaining parts of kernel_entry(). - c.replace_with(uart.into()); - }); - println!("\n[0] UART is live!"); - } -``` - -Here it becomes clear why the virtual console is designed such that it stores an -output _by value_. It is not possible to safely store a reference to something -that is generated at runtime in a static data structure. This is because the -static has `static` lifetime, aka lives forever. Whereas a reference to -something generated during runtime might become invalid at some point in the -future. - -Hence, `move semantics` are used to achieve our goal. Once `uart` has moved into -`CONSOLE`, it will live there until it is replaces again. That is also why the -`ConsoleOps` trait demands that its implementors also implement the `Drop` -trait. When calling `CONSOLE.replace()`, the old output will go out of scope, -and hence its drop function will be called. The drop function can then take care -of gracefully shutting down or disabling the device it belongs to. - -While the print macros implicitly call the lock function, there are some places -where it is done explicitly. For example, when querying a keystroke from the -user: - -```rust - print!("[1] Press a key to continue booting... "); - CONSOLE.lock(|c| { - c.getc(); - }); - println!("Greetings fellow Rustacean!"); - -``` - -## Summary - -Lots of things happened in this tutorial: -1. The kernel's code was restructured. -2. The virtual console was introduced as a **Hardware Abstraction Layer**. - 1. **Trait objects** and **dynamic dispatch** were used for the first time. -3. The peculiarities of **mutable static variables** were discussed and what role the **Sync marker trait** plays for them. -4. **Synchronization primitives** were introduced and (a special) one was built. - 1. You learned about **UnsafeCell** and its role in providing **interior mutability**. - 2. You read about **Closures** vs. **RAII guards**. -5. And finally, the `print!` and `println!` macros from the core library are now - usable in the kernel! - -## Output - -```console -ferris@box:~$ make raspboot - -[0] UART is live! -[1] Press a key to continue booting... Greetings fellow Rustacean! -[2] MMU online. -[i] Kernel memory layout: - 0x00000000 - 0x0007FFFF | 512 KiB | C RW PXN | Kernel stack - 0x00080000 - 0x00082FFF | 12 KiB | C RO PX | Kernel code and RO data - 0x00083000 - 0x0008500F | 8 KiB | C RW PXN | Kernel data and BSS - 0x3F000000 - 0x3FFFFFFF | 16 MiB | Dev RW PXN | Device MMIO - -$> -``` diff --git a/.0F_globals_synchronization_println/kernel8 b/.0F_globals_synchronization_println/kernel8 deleted file mode 100755 index cc1c2b2cbf2066445249c248b7c221811ab998fe..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 91032 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 diff --git a/.0F_globals_synchronization_println/link.ld b/.0F_globals_synchronization_println/link.ld deleted file mode 100644 index cb6f21a6..00000000 --- a/.0F_globals_synchronization_println/link.ld +++ /dev/null @@ -1,57 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2018 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -ENTRY(_boot_cores); - -SECTIONS -{ - . = 0x80000; /* This is already 4KiB aligned */ - __ro_start = .; - .text : - { - KEEP(*(.text.boot)) *(.text .text.*) - } - - .rodata : - { - *(.rodata .rodata.*) - } - . = ALIGN(4096); /* Fill up to 4KiB */ - __ro_end = .; - - .data : - { - *(.data .data.*) - } - - .bss ALIGN(8): - { - __bss_start = .; - *(.bss .bss.*) - *(COMMON) - __bss_end = .; - } - - /DISCARD/ : { *(.comment) *(.gnu*) *(.note*) *(.eh_frame*) } -} diff --git a/.0F_globals_synchronization_println/raspi3_boot/Cargo.toml b/.0F_globals_synchronization_println/raspi3_boot/Cargo.toml deleted file mode 100644 index 024fd184..00000000 --- a/.0F_globals_synchronization_println/raspi3_boot/Cargo.toml +++ /dev/null @@ -1,10 +0,0 @@ -[package] -name = "raspi3_boot" -version = "0.1.0" -authors = ["Andre Richter "] -edition = "2018" - -[dependencies] -cortex-a = "2.7.0" -panic-abort = "0.3.1" -r0 = "0.2.2" diff --git a/.0F_globals_synchronization_println/raspi3_boot/src/lib.rs b/.0F_globals_synchronization_println/raspi3_boot/src/lib.rs deleted file mode 100644 index 01ccd956..00000000 --- a/.0F_globals_synchronization_println/raspi3_boot/src/lib.rs +++ /dev/null @@ -1,141 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2018 Jorge Aparicio - * Copyright (c) 2018-2019 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#![deny(missing_docs)] -#![deny(warnings)] -#![no_std] - -//! Low-level boot of the Raspberry's processor - -extern crate panic_abort; - -/// Type check the user-supplied entry function. -#[macro_export] -macro_rules! entry { - ($path:path) => { - /// # Safety - /// - /// - User must ensure to provide a suitable main function for the - /// platform. - #[export_name = "main"] - pub unsafe fn __main() -> ! { - // type check the given path - let f: fn() -> ! = $path; - - f() - } - }; -} - -/// Reset function. -/// -/// Initializes the bss section before calling into the user's `main()`. -/// -/// # Safety -/// -/// - Only a single core must be active and running this function. -unsafe fn reset() -> ! { - extern "C" { - // Boundaries of the .bss section, provided by the linker script - static mut __bss_start: u64; - static mut __bss_end: u64; - } - - // Zeroes the .bss section - r0::zero_bss(&mut __bss_start, &mut __bss_end); - - extern "Rust" { - fn main() -> !; - } - - main() -} - -/// Prepare and execute transition from EL2 to EL1. -#[inline] -fn setup_and_enter_el1_from_el2() -> ! { - use cortex_a::{asm, regs::*}; - - const STACK_START: u64 = 0x80_000; - - // 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 reset(). - ELR_EL2.set(reset as *const () as u64); - - // Set up SP_EL1 (stack pointer), which will be used by EL1 once - // we "return" to it. - SP_EL1.set(STACK_START); - - // Use `eret` to "return" to EL1. This will result in execution of - // `reset()` in EL1. - asm::eret() -} - -/// Entrypoint of the processor. -/// -/// Parks all cores except core0 and checks if we started in EL2. If -/// so, proceeds with setting up EL1. -/// -/// # Safety -/// -/// - Linker script must ensure to place this function at `0x80_000`. -#[link_section = ".text.boot"] -#[no_mangle] -pub unsafe extern "C" fn _boot_cores() -> ! { - use cortex_a::{asm, regs::*}; - - const CORE_0: u64 = 0; - const CORE_MASK: u64 = 0x3; - const EL2: u32 = CurrentEL::EL::EL2.value; - - if (CORE_0 == MPIDR_EL1.get() & CORE_MASK) && (EL2 == CurrentEL.get()) { - setup_and_enter_el1_from_el2() - } - - // if not core0 or EL != 2, infinitely wait for events - loop { - asm::wfe(); - } -} diff --git a/.0F_globals_synchronization_println/src/delays.rs b/.0F_globals_synchronization_println/src/delays.rs deleted file mode 100644 index b1c1fa0f..00000000 --- a/.0F_globals_synchronization_println/src/delays.rs +++ /dev/null @@ -1,37 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2018-2019 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -use cortex_a::asm; - -/* - * - * Using the CPU's cycles - * - */ -/// Wait N CPU cycles (ARM CPU only) -pub fn wait_cycles(cyc: u32) { - for _ in 0..cyc { - asm::nop(); - } -} diff --git a/.0F_globals_synchronization_println/src/devices.rs b/.0F_globals_synchronization_println/src/devices.rs deleted file mode 100644 index 227b92c2..00000000 --- a/.0F_globals_synchronization_println/src/devices.rs +++ /dev/null @@ -1,26 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2019 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -pub mod hw; -pub mod virt; diff --git a/.0F_globals_synchronization_println/src/devices/hw.rs b/.0F_globals_synchronization_println/src/devices/hw.rs deleted file mode 100644 index d9684419..00000000 --- a/.0F_globals_synchronization_println/src/devices/hw.rs +++ /dev/null @@ -1,31 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2019 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -mod gpio; -mod uart; -mod videocore_mbox; - -pub use gpio::GPIO; -pub use uart::Uart; -pub use videocore_mbox::VideocoreMbox; diff --git a/.0F_globals_synchronization_println/src/devices/hw/gpio.rs b/.0F_globals_synchronization_println/src/devices/hw/gpio.rs deleted file mode 100644 index 7affea08..00000000 --- a/.0F_globals_synchronization_println/src/devices/hw/gpio.rs +++ /dev/null @@ -1,120 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2018-2019 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -use core::ops; -use register::{mmio::ReadWrite, register_bitfields}; - -// Descriptions taken from -// https://github.com/raspberrypi/documentation/files/1888662/BCM2837-ARM-Peripherals.-.Revised.-.V2-1.pdf -register_bitfields! { - u32, - - /// GPIO Function Select 1 - GPFSEL1 [ - /// Pin 15 - FSEL15 OFFSET(15) NUMBITS(3) [ - Input = 0b000, - Output = 0b001, - RXD0 = 0b100, // UART0 - Alternate function 0 - RXD1 = 0b010 // Mini UART - Alternate function 5 - - ], - - /// Pin 14 - FSEL14 OFFSET(12) NUMBITS(3) [ - Input = 0b000, - Output = 0b001, - TXD0 = 0b100, // UART0 - Alternate function 0 - TXD1 = 0b010 // Mini UART - Alternate function 5 - ] - ], - - /// GPIO Pull-up/down Clock Register 0 - GPPUDCLK0 [ - /// Pin 15 - PUDCLK15 OFFSET(15) NUMBITS(1) [ - NoEffect = 0, - AssertClock = 1 - ], - - /// Pin 14 - PUDCLK14 OFFSET(14) NUMBITS(1) [ - NoEffect = 0, - AssertClock = 1 - ] - ] -} - -#[allow(non_snake_case)] -#[repr(C)] -pub struct RegisterBlock { - pub GPFSEL0: ReadWrite, // 0x00 - pub GPFSEL1: ReadWrite, // 0x04 - pub GPFSEL2: ReadWrite, // 0x08 - pub GPFSEL3: ReadWrite, // 0x0C - pub GPFSEL4: ReadWrite, // 0x10 - pub GPFSEL5: ReadWrite, // 0x14 - __reserved_0: u32, // 0x18 - GPSET0: ReadWrite, // 0x1C - GPSET1: ReadWrite, // 0x20 - __reserved_1: u32, // - GPCLR0: ReadWrite, // 0x28 - __reserved_2: [u32; 2], // - GPLEV0: ReadWrite, // 0x34 - GPLEV1: ReadWrite, // 0x38 - __reserved_3: u32, // - GPEDS0: ReadWrite, // 0x40 - GPEDS1: ReadWrite, // 0x44 - __reserved_4: [u32; 7], // - GPHEN0: ReadWrite, // 0x64 - GPHEN1: ReadWrite, // 0x68 - __reserved_5: [u32; 10], // - pub GPPUD: ReadWrite, // 0x94 - pub GPPUDCLK0: ReadWrite, // 0x98 - pub GPPUDCLK1: ReadWrite, // 0x9C -} - -/// Public interface to the GPIO MMIO area -pub struct GPIO { - base_addr: usize, -} - -impl ops::Deref for GPIO { - type Target = RegisterBlock; - - fn deref(&self) -> &Self::Target { - unsafe { &*self.ptr() } - } -} - -impl GPIO { - pub fn new(base_addr: usize) -> GPIO { - GPIO { base_addr } - } - - /// Returns a pointer to the register block - fn ptr(&self) -> *const RegisterBlock { - self.base_addr as *const _ - } -} diff --git a/.0F_globals_synchronization_println/src/devices/hw/uart.rs b/.0F_globals_synchronization_println/src/devices/hw/uart.rs deleted file mode 100644 index c27b62d6..00000000 --- a/.0F_globals_synchronization_println/src/devices/hw/uart.rs +++ /dev/null @@ -1,276 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2018-2019 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -use super::gpio; -use super::videocore_mbox; -use crate::delays; -use crate::devices::virt::ConsoleOps; -use core::{ - ops, - sync::atomic::{compiler_fence, Ordering}, -}; -use cortex_a::asm; -use register::{mmio::*, register_bitfields}; - -// PL011 UART registers. -// -// Descriptions taken from -// https://github.com/raspberrypi/documentation/files/1888662/BCM2837-ARM-Peripherals.-.Revised.-.V2-1.pdf -register_bitfields! { - u32, - - /// Flag Register - FR [ - /// Transmit FIFO full. The meaning of this bit depends on the - /// state of the FEN bit in the UARTLCR_ LCRH 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 UARTLCR_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) [] - ], - - /// Integer Baud rate divisor - IBRD [ - /// Integer Baud rate divisor - IBRD OFFSET(0) NUMBITS(16) [] - ], - - /// Fractional Baud rate divisor - FBRD [ - /// Fractional Baud rate divisor - FBRD OFFSET(0) NUMBITS(6) [] - ], - - /// Line Control register - LCRH [ - /// Word length. These bits indicate the number of data bits - /// transmitted or received in a frame. - WLEN OFFSET(5) NUMBITS(2) [ - FiveBit = 0b00, - SixBit = 0b01, - SevenBit = 0b10, - EightBit = 0b11 - ] - ], - - /// Control Register - CR [ - /// Receive enable. If this bit is set to 1, the receive - /// section of the UART is enabled. Data reception occurs for - /// UART signals. 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 UART signals. 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 - 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 - ] - ], - - /// Interupt Clear Register - ICR [ - /// Meta field for all pending interrupts - ALL OFFSET(0) NUMBITS(11) [] - ] -} - -#[allow(non_snake_case)] -#[repr(C)] -pub struct RegisterBlock { - DR: ReadWrite, // 0x00 - __reserved_0: [u32; 5], // 0x04 - FR: ReadOnly, // 0x18 - __reserved_1: [u32; 2], // 0x1c - IBRD: WriteOnly, // 0x24 - FBRD: WriteOnly, // 0x28 - LCRH: WriteOnly, // 0x2C - CR: WriteOnly, // 0x30 - __reserved_2: [u32; 4], // 0x34 - ICR: WriteOnly, // 0x44 -} - -pub enum UartError { - MailboxError, -} -pub type Result = ::core::result::Result; - -pub struct Uart { - base_addr: usize, -} - -impl ops::Deref for Uart { - type Target = RegisterBlock; - - fn deref(&self) -> &Self::Target { - unsafe { &*self.ptr() } - } -} - -impl Uart { - pub fn new(base_addr: usize) -> Uart { - Uart { base_addr } - } - - /// Returns a pointer to the register block - fn ptr(&self) -> *const RegisterBlock { - self.base_addr as *const _ - } - - ///Set baud rate and characteristics (115200 8N1) and map to GPIO - pub fn init( - &self, - v_mbox: &mut videocore_mbox::VideocoreMbox, - gpio: &gpio::GPIO, - ) -> Result<()> { - // turn off UART0 - self.CR.set(0); - - // set up clock for consistent divisor values - v_mbox.buffer[0] = 9 * 4; - v_mbox.buffer[1] = videocore_mbox::REQUEST; - v_mbox.buffer[2] = videocore_mbox::tag::SETCLKRATE; - v_mbox.buffer[3] = 12; - v_mbox.buffer[4] = 8; - v_mbox.buffer[5] = videocore_mbox::clock::UART; // UART clock - v_mbox.buffer[6] = 4_000_000; // 4Mhz - v_mbox.buffer[7] = 0; // skip turbo setting - v_mbox.buffer[8] = videocore_mbox::tag::LAST; - - // Insert a compiler fence that ensures that all stores to the - // mbox buffer are finished before the GPU is signaled (which - // is done by a store operation as well). - compiler_fence(Ordering::Release); - - if v_mbox.call(videocore_mbox::channel::PROP).is_err() { - return Err(UartError::MailboxError); // Abort if UART clocks couldn't be set - }; - - // map UART0 to GPIO pins - gpio.GPFSEL1 - .modify(gpio::GPFSEL1::FSEL14::TXD0 + gpio::GPFSEL1::FSEL15::RXD0); - - gpio.GPPUD.set(0); // enable pins 14 and 15 - delays::wait_cycles(150); - - gpio.GPPUDCLK0.modify( - gpio::GPPUDCLK0::PUDCLK14::AssertClock + gpio::GPPUDCLK0::PUDCLK15::AssertClock, - ); - delays::wait_cycles(150); - - gpio.GPPUDCLK0.set(0); - - self.ICR.write(ICR::ALL::CLEAR); - self.IBRD.write(IBRD::IBRD.val(2)); // Results in 115200 baud - self.FBRD.write(FBRD::FBRD.val(0xB)); - self.LCRH.write(LCRH::WLEN::EightBit); // 8N1 - - self.CR - .write(CR::UARTEN::Enabled + CR::TXE::Enabled + CR::RXE::Enabled); - - Ok(()) - } -} - -impl Drop for Uart { - fn drop(&mut self) { - self.CR - .write(CR::UARTEN::Disabled + CR::TXE::Disabled + CR::RXE::Disabled); - } -} - -impl ConsoleOps for Uart { - /// Send a character - fn putc(&self, c: char) { - // wait until we can send - loop { - if !self.FR.is_set(FR::TXFF) { - break; - } - - asm::nop(); - } - - // write the character to the buffer - self.DR.set(c as u32); - } - - /// Display a string - fn puts(&self, string: &str) { - for c in string.chars() { - // convert newline to carrige return + newline - if c == '\n' { - self.putc('\r') - } - - self.putc(c); - } - } - - /// Receive a character - fn getc(&self) -> char { - // wait until something is in the buffer - loop { - if !self.FR.is_set(FR::RXFE) { - break; - } - - asm::nop(); - } - - // read it and return - let mut ret = self.DR.get() as u8 as char; - - // convert carrige return to newline - if ret == '\r' { - ret = '\n' - } - - ret - } -} diff --git a/.0F_globals_synchronization_println/src/devices/hw/videocore_mbox.rs b/.0F_globals_synchronization_println/src/devices/hw/videocore_mbox.rs deleted file mode 100644 index 0f6e294b..00000000 --- a/.0F_globals_synchronization_println/src/devices/hw/videocore_mbox.rs +++ /dev/null @@ -1,164 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2018-2019 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -use core::ops; -use cortex_a::asm; -use register::{ - mmio::{ReadOnly, WriteOnly}, - register_bitfields, -}; - -register_bitfields! { - u32, - - STATUS [ - FULL OFFSET(31) NUMBITS(1) [], - EMPTY OFFSET(30) NUMBITS(1) [] - ] -} - -#[allow(non_snake_case)] -#[repr(C)] -pub struct RegisterBlock { - READ: ReadOnly, // 0x00 - __reserved_0: [u32; 5], // 0x04 - STATUS: ReadOnly, // 0x18 - __reserved_1: u32, // 0x1C - WRITE: WriteOnly, // 0x20 -} - -// Custom errors -pub enum VideocoreMboxError { - ResponseError, - UnknownError, -} -pub type Result = ::core::result::Result; - -// Channels -pub mod channel { - pub const PROP: u32 = 8; -} - -// Tags -pub mod tag { - pub const SETCLKRATE: u32 = 0x38002; - pub const LAST: u32 = 0; -} - -// Clocks -pub mod clock { - pub const UART: u32 = 0x0_0000_0002; -} - -// Responses -mod response { - pub const SUCCESS: u32 = 0x8000_0000; - pub const ERROR: u32 = 0x8000_0001; // error parsing request buffer (partial response) -} - -pub const REQUEST: u32 = 0; - -// Public interface to the mailbox -#[repr(C)] -#[repr(align(16))] -pub struct VideocoreMbox { - // The address for buffer needs to be 16-byte aligned so that the Videcore - // can handle it properly. Hence, put it at the start of the struct so that - // the align attribute is effective. - pub buffer: [u32; 36], - base_addr: usize, -} - -/// Deref to RegisterBlock -/// -/// Allows writing -/// ``` -/// self.STATUS.read() -/// ``` -/// instead of something along the lines of -/// ``` -/// unsafe { (*Mbox::ptr()).STATUS.read() } -/// ``` -impl ops::Deref for VideocoreMbox { - type Target = RegisterBlock; - - fn deref(&self) -> &Self::Target { - unsafe { &*self.ptr() } - } -} - -impl VideocoreMbox { - pub fn new(base_addr: usize) -> VideocoreMbox { - VideocoreMbox { - buffer: [0; 36], - base_addr, - } - } - - /// Returns a pointer to the register block - fn ptr(&self) -> *const RegisterBlock { - self.base_addr as *const _ - } - - /// Make a mailbox call. Returns Err(MboxError) on failure, Ok(()) success - pub fn call(&self, channel: u32) -> Result<()> { - // wait until we can write to the mailbox - loop { - if !self.STATUS.is_set(STATUS::FULL) { - break; - } - - asm::nop(); - } - - let buf_ptr = self.buffer.as_ptr() as u32; - - // write the address of our message to the mailbox with channel identifier - self.WRITE.set((buf_ptr & !0xF) | (channel & 0xF)); - - // now wait for the response - loop { - // is there a response? - loop { - if !self.STATUS.is_set(STATUS::EMPTY) { - break; - } - - asm::nop(); - } - - let resp: u32 = self.READ.get(); - - // is it a response to our message? - if ((resp & 0xF) == channel) && ((resp & !0xF) == buf_ptr) { - // is it a valid successful response? - return match self.buffer[1] { - response::SUCCESS => Ok(()), - response::ERROR => Err(VideocoreMboxError::ResponseError), - _ => Err(VideocoreMboxError::UnknownError), - }; - } - } - } -} diff --git a/.0F_globals_synchronization_println/src/devices/virt.rs b/.0F_globals_synchronization_println/src/devices/virt.rs deleted file mode 100644 index 30ed5469..00000000 --- a/.0F_globals_synchronization_println/src/devices/virt.rs +++ /dev/null @@ -1,27 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2019 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -mod console; - -pub use console::{Console, ConsoleOps}; diff --git a/.0F_globals_synchronization_println/src/devices/virt/console.rs b/.0F_globals_synchronization_println/src/devices/virt/console.rs deleted file mode 100644 index 84244da8..00000000 --- a/.0F_globals_synchronization_println/src/devices/virt/console.rs +++ /dev/null @@ -1,136 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2019 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -use crate::devices::hw; -use core::fmt; - -/// A trait that must be implemented by devices that are candidates for the -/// global console. -#[allow(unused_variables)] -pub trait ConsoleOps: Drop { - fn putc(&self, c: char) {} - fn puts(&self, string: &str) {} - fn getc(&self) -> char { - ' ' - } - fn flush(&self) {} -} - -/// A dummy console that just ignores its inputs. -pub struct NullConsole; -impl Drop for NullConsole { - fn drop(&mut self) {} -} -impl ConsoleOps for NullConsole {} - -/// Possible outputs which the console can store. -pub enum Output { - None(NullConsole), - Uart(hw::Uart), -} - -impl From for Output { - fn from(instance: hw::Uart) -> Self { - Output::Uart(instance) - } -} - -pub struct Console { - output: Output, -} - -impl Console { - pub const fn new() -> Console { - Console { - output: Output::None(NullConsole {}), - } - } - - #[inline(always)] - fn current_ptr(&self) -> &dyn ConsoleOps { - match &self.output { - Output::None(i) => i, - Output::Uart(i) => i, - } - } - - /// Overwrite the current output. The old output will go out of scope and - /// it's Drop function will be called. - pub fn replace_with(&mut self, x: Output) { - self.current_ptr().flush(); - - self.output = x; - } - - /// A command prompt. Currently does nothing. - pub fn command_prompt(&self) -> ! { - self.puts("\n$> "); - - let mut input; - loop { - input = self.getc(); - - if input == '\n' { - self.puts("\n$> ") - } else { - self.putc(input); - } - } - } -} - -impl Drop for Console { - fn drop(&mut self) {} -} - -/// Dispatch the respective function to the currently stored output device. -impl ConsoleOps for Console { - fn putc(&self, c: char) { - self.current_ptr().putc(c); - } - - fn puts(&self, string: &str) { - self.current_ptr().puts(string); - } - - fn getc(&self) -> char { - self.current_ptr().getc() - } - - fn flush(&self) { - self.current_ptr().flush() - } -} - -/// Implementing this trait enables usage of the format_args! macros, which in -/// turn are used to implement the kernel's print! and println! macros. -/// -/// See src/macros.rs. -impl fmt::Write for Console { - fn write_str(&mut self, s: &str) -> fmt::Result { - self.current_ptr().puts(s); - - Ok(()) - } -} diff --git a/.0F_globals_synchronization_println/src/macros.rs b/.0F_globals_synchronization_println/src/macros.rs deleted file mode 100644 index 28280be9..00000000 --- a/.0F_globals_synchronization_println/src/macros.rs +++ /dev/null @@ -1,49 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2019 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -use core::fmt; - -// https://doc.rust-lang.org/src/std/macros.rs.html -#[macro_export] -macro_rules! print { - ($($arg:tt)*) => ($crate::macros::_print(format_args!($($arg)*))); -} - -// https://doc.rust-lang.org/src/std/macros.rs.html -#[macro_export] -macro_rules! println { - () => (print!("\n")); - ($($arg:tt)*) => ({ - $crate::macros::_print(format_args_nl!($($arg)*)); - }) -} - -#[doc(hidden)] -pub fn _print(args: fmt::Arguments) { - use core::fmt::Write; - - crate::CONSOLE.lock(|c| { - c.write_fmt(args).unwrap(); - }) -} diff --git a/.0F_globals_synchronization_println/src/main.rs b/.0F_globals_synchronization_println/src/main.rs deleted file mode 100644 index 7e4b15b2..00000000 --- a/.0F_globals_synchronization_println/src/main.rs +++ /dev/null @@ -1,107 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2018-2019 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#![no_std] -#![no_main] -#![feature(const_fn)] -#![feature(custom_attribute)] -#![feature(format_args_nl)] - -mod delays; -mod devices; -mod macros; -mod memory; -mod sync; - -/// The global console. Output of the print! and println! macros. -static CONSOLE: sync::NullLock = - sync::NullLock::new(devices::virt::Console::new()); - -fn kernel_entry() -> ! { - use devices::hw; - use devices::virt::ConsoleOps; - - // This will be invisible, because CONSOLE is dispatching to the NullConsole - // at this point in time. - println!("Is there anybody out there?"); - - //------------------------------------------------------------ - // Instantiate GPIO device - //------------------------------------------------------------ - let gpio = hw::GPIO::new(memory::map::physical::GPIO_BASE); - - //------------------------------------------------------------ - // Instantiate Videocore Mailbox - //------------------------------------------------------------ - let mut v_mbox = hw::VideocoreMbox::new(memory::map::physical::VIDEOCORE_MBOX_BASE); - - //------------------------------------------------------------ - // Instantiate PL011 UART and put it in CONSOLE - //------------------------------------------------------------ - let uart = hw::Uart::new(memory::map::physical::UART_BASE); - - match uart.init(&mut v_mbox, &gpio) { - Ok(_) => { - CONSOLE.lock(|c| { - // Moves uart into the global CONSOLE. It is not accessible - // anymore for the remaining parts of kernel_entry(). - c.replace_with(uart.into()); - }); - - println!("\n[0] UART is live!"); - } - Err(_) => loop { - cortex_a::asm::wfe() // If UART fails, abort early - }, - } - - //------------------------------------------------------------ - // Greet the user - //------------------------------------------------------------ - print!("[1] Press a key to continue booting... "); - CONSOLE.lock(|c| { - c.getc(); - }); - println!("Greetings fellow Rustacean!"); - - //------------------------------------------------------------ - // Bring up memory subsystem - //------------------------------------------------------------ - if unsafe { memory::mmu::init() }.is_err() { - println!("[2][Error] Could not set up MMU. Aborting."); - } else { - println!("[2] MMU online."); - } - - memory::print_layout(); - - //------------------------------------------------------------ - // Start a command prompt - //------------------------------------------------------------ - CONSOLE.lock(|c| { - c.command_prompt(); - }) -} - -raspi3_boot::entry!(kernel_entry); diff --git a/.0F_globals_synchronization_println/src/memory.rs b/.0F_globals_synchronization_println/src/memory.rs deleted file mode 100644 index dd00a8f4..00000000 --- a/.0F_globals_synchronization_println/src/memory.rs +++ /dev/null @@ -1,268 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2019 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -use crate::println; -use core::fmt; -use core::ops::RangeInclusive; - -pub mod mmu; - -/// System memory map. -#[rustfmt::skip] -pub mod map { - pub const START: usize = 0x0000_0000; - pub const END: usize = 0x3FFF_FFFF; - - pub mod physical { - pub const MMIO_BASE: usize = 0x3F00_0000; - pub const VIDEOCORE_MBOX_BASE: usize = MMIO_BASE + 0x0000_B880; - pub const GPIO_BASE: usize = MMIO_BASE + 0x0020_0000; - pub const UART_BASE: usize = MMIO_BASE + 0x0020_1000; - pub const MMIO_END: usize = super::END; - } - - pub mod virt { - pub const KERN_STACK_START: usize = super::START; - pub const KERN_STACK_END: usize = 0x0007_FFFF; - } -} - -/// Types used for compiling the virtual memory layout of the kernel using -/// address ranges. -pub mod kernel_mem_range { - use core::ops::RangeInclusive; - - #[allow(dead_code)] - #[derive(Copy, Clone)] - pub enum MemAttributes { - CacheableDRAM, - NonCacheableDRAM, - Device, - } - - #[derive(Copy, Clone)] - pub enum AccessPermissions { - ReadOnly, - ReadWrite, - } - - #[allow(dead_code)] - #[derive(Copy, Clone)] - pub enum Translation { - Identity, - Offset(usize), - } - - #[derive(Copy, Clone)] - pub struct AttributeFields { - pub mem_attributes: MemAttributes, - pub acc_perms: AccessPermissions, - pub execute_never: bool, - } - - impl Default for AttributeFields { - fn default() -> AttributeFields { - AttributeFields { - mem_attributes: MemAttributes::CacheableDRAM, - acc_perms: AccessPermissions::ReadWrite, - execute_never: true, - } - } - } - - pub struct Descriptor { - pub name: &'static str, - pub virtual_range: fn() -> RangeInclusive, - pub translation: Translation, - pub attribute_fields: AttributeFields, - } -} - -use kernel_mem_range::*; - -/// A virtual memory layout that is agnostic of the paging granularity that the -/// hardware MMU will use. -/// -/// Contains only special ranges, aka anything that is _not_ normal cacheable -/// DRAM. -static KERNEL_VIRTUAL_LAYOUT: [Descriptor; 4] = [ - Descriptor { - name: "Kernel stack", - virtual_range: || { - RangeInclusive::new(map::virt::KERN_STACK_START, map::virt::KERN_STACK_END) - }, - translation: Translation::Identity, - attribute_fields: AttributeFields { - mem_attributes: MemAttributes::CacheableDRAM, - acc_perms: AccessPermissions::ReadWrite, - execute_never: true, - }, - }, - Descriptor { - name: "Kernel code and RO data", - virtual_range: || { - // Using the linker script, we ensure that the RO area is consecutive and 4 - // KiB aligned, and we export the boundaries via symbols: - // - // [__ro_start, __ro_end) - extern "C" { - // The inclusive start of the read-only area, aka the address of the - // first byte of the area. - static __ro_start: u64; - - // The exclusive end of the read-only area, aka the address of - // the first byte _after_ the RO area. - static __ro_end: u64; - } - - unsafe { - // Notice the subtraction to turn the exclusive end into an - // inclusive end - RangeInclusive::new( - &__ro_start as *const _ as usize, - &__ro_end as *const _ as usize - 1, - ) - } - }, - translation: Translation::Identity, - attribute_fields: AttributeFields { - mem_attributes: MemAttributes::CacheableDRAM, - acc_perms: AccessPermissions::ReadOnly, - execute_never: false, - }, - }, - Descriptor { - name: "Kernel data and BSS", - virtual_range: || { - extern "C" { - static __ro_end: u64; - static __bss_end: u64; - } - - unsafe { - RangeInclusive::new( - &__ro_end as *const _ as usize, - &__bss_end as *const _ as usize - 1, - ) - } - }, - translation: Translation::Identity, - attribute_fields: AttributeFields { - mem_attributes: MemAttributes::CacheableDRAM, - acc_perms: AccessPermissions::ReadWrite, - execute_never: true, - }, - }, - Descriptor { - name: "Device MMIO", - virtual_range: || RangeInclusive::new(map::physical::MMIO_BASE, map::physical::MMIO_END), - translation: Translation::Identity, - attribute_fields: AttributeFields { - mem_attributes: MemAttributes::Device, - acc_perms: AccessPermissions::ReadWrite, - execute_never: true, - }, - }, -]; - -/// For a given virtual address, find and return the output address and -/// according attributes. -/// -/// If the address is not covered in VIRTUAL_LAYOUT, return a default for normal -/// cacheable DRAM. -fn get_virt_addr_properties(virt_addr: usize) -> Result<(usize, AttributeFields), &'static str> { - if virt_addr > map::END { - return Err("Address out of range."); - } - - for i in KERNEL_VIRTUAL_LAYOUT.iter() { - if (i.virtual_range)().contains(&virt_addr) { - let output_addr = match i.translation { - Translation::Identity => virt_addr, - Translation::Offset(a) => a + (virt_addr - (i.virtual_range)().start()), - }; - - return Ok((output_addr, i.attribute_fields)); - } - } - - Ok((virt_addr, AttributeFields::default())) -} - -/// Human-readable output of a Descriptor. -impl fmt::Display for Descriptor { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - // Call the function to which self.range points, and dereference the - // result, which causes Rust to copy the value. - let start = *(self.virtual_range)().start(); - 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 attr = match self.attribute_fields.mem_attributes { - MemAttributes::CacheableDRAM => "C", - MemAttributes::NonCacheableDRAM => "NC", - MemAttributes::Device => "Dev", - }; - - let acc_p = match self.attribute_fields.acc_perms { - AccessPermissions::ReadOnly => "RO", - AccessPermissions::ReadWrite => "RW", - }; - - 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 - ) - } -} - -/// Print the kernel memory layout. -pub fn print_layout() { - println!("[i] Kernel memory layout:"); - - for i in KERNEL_VIRTUAL_LAYOUT.iter() { - println!("{}", i); - } -} diff --git a/.0F_globals_synchronization_println/src/memory/mmu.rs b/.0F_globals_synchronization_println/src/memory/mmu.rs deleted file mode 100644 index aa4e43c6..00000000 --- a/.0F_globals_synchronization_println/src/memory/mmu.rs +++ /dev/null @@ -1,349 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2018-2019 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -use crate::memory::{get_virt_addr_properties, AttributeFields}; -use cortex_a::{barrier, regs::*}; -use register::register_bitfields; - -register_bitfields! {u64, - // AArch64 Reference Manual page 2150 - STAGE1_DESCRIPTOR [ - /// Privileged execute-never - PXN OFFSET(53) NUMBITS(1) [ - False = 0, - True = 1 - ], - - /// Various address fields, depending on use case - LVL2_OUTPUT_ADDR_4KiB OFFSET(21) NUMBITS(27) [], // [47:21] - NEXT_LVL_TABLE_ADDR_4KiB OFFSET(12) NUMBITS(36) [], // [47:12] - - /// 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) [ - Block = 0, - Table = 1 - ], - - VALID OFFSET(0) NUMBITS(1) [ - False = 0, - True = 1 - ] - ] -} - -const FOUR_KIB: usize = 4 * 1024; -const FOUR_KIB_SHIFT: usize = 12; // log2(4 * 1024) - -const TWO_MIB: usize = 2 * 1024 * 1024; -const TWO_MIB_SHIFT: usize = 21; // log2(2 * 1024 * 1024) - -/// A descriptor pointing to the next page table. -struct TableDescriptor(register::FieldValue); - -impl TableDescriptor { - fn new(next_lvl_table_addr: usize) -> Result { - if next_lvl_table_addr % FOUR_KIB != 0 { - return Err("TableDescriptor: Address is not 4 KiB aligned."); - } - - let shifted = next_lvl_table_addr >> FOUR_KIB_SHIFT; - - Ok(TableDescriptor( - STAGE1_DESCRIPTOR::VALID::True - + STAGE1_DESCRIPTOR::TYPE::Table - + STAGE1_DESCRIPTOR::NEXT_LVL_TABLE_ADDR_4KiB.val(shifted as u64), - )) - } - - fn value(&self) -> u64 { - self.0.value - } -} - -/// A function that maps the generic memory range attributes to HW-specific -/// attributes of the MMU. -fn into_mmu_attributes( - attribute_fields: AttributeFields, -) -> register::FieldValue { - use crate::memory::{AccessPermissions, MemAttributes}; - - // Memory attributes - let mut desc = match attribute_fields.mem_attributes { - MemAttributes::CacheableDRAM => { - STAGE1_DESCRIPTOR::SH::InnerShareable + STAGE1_DESCRIPTOR::AttrIndx.val(mair::NORMAL) - } - MemAttributes::NonCacheableDRAM => { - STAGE1_DESCRIPTOR::SH::InnerShareable - + STAGE1_DESCRIPTOR::AttrIndx.val(mair::NORMAL_NON_CACHEABLE) - } - MemAttributes::Device => { - STAGE1_DESCRIPTOR::SH::OuterShareable + STAGE1_DESCRIPTOR::AttrIndx.val(mair::DEVICE) - } - }; - - // Access Permissions - desc += match attribute_fields.acc_perms { - AccessPermissions::ReadOnly => STAGE1_DESCRIPTOR::AP::RO_EL1, - AccessPermissions::ReadWrite => STAGE1_DESCRIPTOR::AP::RW_EL1, - }; - - // Execute Never - desc += if attribute_fields.execute_never { - STAGE1_DESCRIPTOR::PXN::True - } else { - STAGE1_DESCRIPTOR::PXN::False - }; - - desc -} - -/// A Level2 block descriptor with 2 MiB aperture. -/// -/// The output points to physical memory. -struct Lvl2BlockDescriptor(register::FieldValue); - -impl Lvl2BlockDescriptor { - fn new( - output_addr: usize, - attribute_fields: AttributeFields, - ) -> Result { - if output_addr % TWO_MIB != 0 { - return Err("BlockDescriptor: Address is not 2 MiB aligned."); - } - - let shifted = output_addr >> TWO_MIB_SHIFT; - - Ok(Lvl2BlockDescriptor( - STAGE1_DESCRIPTOR::VALID::True - + STAGE1_DESCRIPTOR::AF::True - + into_mmu_attributes(attribute_fields) - + STAGE1_DESCRIPTOR::TYPE::Block - + STAGE1_DESCRIPTOR::LVL2_OUTPUT_ADDR_4KiB.val(shifted as u64), - )) - } - - fn value(&self) -> u64 { - self.0.value - } -} - -/// A page descriptor with 4 KiB aperture. -/// -/// The output points to physical memory. -struct PageDescriptor(register::FieldValue); - -impl PageDescriptor { - fn new( - output_addr: usize, - attribute_fields: AttributeFields, - ) -> Result { - if output_addr % FOUR_KIB != 0 { - return Err("PageDescriptor: Address is not 4 KiB aligned."); - } - - let shifted = output_addr >> FOUR_KIB_SHIFT; - - Ok(PageDescriptor( - STAGE1_DESCRIPTOR::VALID::True - + STAGE1_DESCRIPTOR::AF::True - + into_mmu_attributes(attribute_fields) - + STAGE1_DESCRIPTOR::TYPE::Table - + STAGE1_DESCRIPTOR::NEXT_LVL_TABLE_ADDR_4KiB.val(shifted as u64), - )) - } - - fn value(&self) -> u64 { - self.0.value - } -} - -/// Constants for indexing the MAIR_EL1. -#[allow(dead_code)] -mod mair { - pub const DEVICE: u64 = 0; - pub const NORMAL: u64 = 1; - pub const NORMAL_NON_CACHEABLE: u64 = 2; -} - -/// Setup function for the MAIR_EL1 register. -fn set_up_mair() { - // Define the three memory types that we will map. Cacheable and - // non-cacheable normal DRAM, and device. - MAIR_EL1.write( - // Attribute 2 - MAIR_EL1::Attr2_HIGH::Memory_OuterNonCacheable - + MAIR_EL1::Attr2_LOW_MEMORY::InnerNonCacheable - - // Attribute 1 - + MAIR_EL1::Attr1_HIGH::Memory_OuterWriteBack_NonTransient_ReadAlloc_WriteAlloc - + MAIR_EL1::Attr1_LOW_MEMORY::InnerWriteBack_NonTransient_ReadAlloc_WriteAlloc - - // Attribute 0 - + MAIR_EL1::Attr0_HIGH::Device - + MAIR_EL1::Attr0_LOW_DEVICE::Device_nGnRE, - ); -} - -trait BaseAddr { - fn base_addr_u64(&self) -> u64; - fn base_addr_usize(&self) -> usize; -} - -impl BaseAddr for [u64; 512] { - fn base_addr_u64(&self) -> u64 { - self as *const u64 as u64 - } - - fn base_addr_usize(&self) -> usize { - self as *const u64 as usize - } -} - -const NUM_ENTRIES_4KIB: usize = 512; - -// A wrapper struct is needed here so that the align attribute can be used. -#[repr(C)] -#[repr(align(4096))] -struct PageTable { - entries: [u64; NUM_ENTRIES_4KIB], -} - -/// The LVL2 page table containng the 2 MiB entries. -static mut LVL2_TABLE: PageTable = PageTable { - entries: [0; NUM_ENTRIES_4KIB], -}; - -/// The LVL3 page table containing the 4 KiB entries. -/// -/// The first entry of the LVL2_TABLE will forward to this table. -static mut LVL3_TABLE: PageTable = PageTable { - entries: [0; NUM_ENTRIES_4KIB], -}; - -/// Set up identity mapped page tables for the first 1 GiB of address space. -/// -/// The first 2 MiB are 4 KiB granule, the rest 2 MiB. -/// -/// # Safety -/// -/// - User must ensure that the hardware supports the paremeters being set here. -pub unsafe fn init() -> Result<(), &'static str> { - // Prepare the memory attribute indirection register. - set_up_mair(); - - // Point the first 2 MiB of virtual addresses to the follow-up LVL3 - // page-table. - LVL2_TABLE.entries[0] = match TableDescriptor::new(LVL3_TABLE.entries.base_addr_usize()) { - Err(s) => return Err(s), - Ok(d) => d.value(), - }; - - // Fill the rest of the LVL2 (2 MiB) entries as block descriptors. - // - // Notice the skip(1) which makes the iteration start at the second 2 MiB - // block (0x20_0000). - for (block_descriptor_nr, entry) in LVL2_TABLE.entries.iter_mut().enumerate().skip(1) { - let virt_addr = block_descriptor_nr << TWO_MIB_SHIFT; - - let (output_addr, attribute_fields) = match get_virt_addr_properties(virt_addr) { - Err(s) => return Err(s), - Ok((a, b)) => (a, b), - }; - - let block_desc = match Lvl2BlockDescriptor::new(output_addr, attribute_fields) { - Err(s) => return Err(s), - Ok(desc) => desc, - }; - - *entry = block_desc.value(); - } - - // Finally, fill the single LVL3 table (4 KiB granule). - for (page_descriptor_nr, entry) in LVL3_TABLE.entries.iter_mut().enumerate() { - let virt_addr = page_descriptor_nr << FOUR_KIB_SHIFT; - - let (output_addr, attribute_fields) = match get_virt_addr_properties(virt_addr) { - Err(s) => return Err(s), - Ok((a, b)) => (a, b), - }; - - let page_desc = match PageDescriptor::new(output_addr, attribute_fields) { - Err(s) => return Err(s), - Ok(desc) => desc, - }; - - *entry = page_desc.value(); - } - - // Point to the LVL2 table base address in TTBR0. - TTBR0_EL1.set_baddr(LVL2_TABLE.entries.base_addr_u64()); - - // Configure various settings of stage 1 of the EL1 translation regime. - let ips = ID_AA64MMFR0_EL1.read(ID_AA64MMFR0_EL1::PARange); - TCR_EL1.write( - TCR_EL1::TBI0::Ignored - + TCR_EL1::IPS.val(ips) - + TCR_EL1::TG0::KiB_4 // 4 KiB granule - + TCR_EL1::SH0::Inner - + TCR_EL1::ORGN0::WriteBack_ReadAlloc_WriteAlloc_Cacheable - + TCR_EL1::IRGN0::WriteBack_ReadAlloc_WriteAlloc_Cacheable - + TCR_EL1::EPD0::EnableTTBR0Walks - + TCR_EL1::T0SZ.val(34), // Start walks at level 2 - ); - - // 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(()) -} diff --git a/.0F_globals_synchronization_println/src/sync.rs b/.0F_globals_synchronization_println/src/sync.rs deleted file mode 100644 index 3cbc1714..00000000 --- a/.0F_globals_synchronization_println/src/sync.rs +++ /dev/null @@ -1,51 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2019 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -use core::cell::UnsafeCell; - -pub struct NullLock { - data: UnsafeCell, -} - -unsafe impl Sync for NullLock {} - -impl NullLock { - pub const fn new(data: T) -> NullLock { - NullLock { - data: UnsafeCell::new(data), - } - } -} - -impl NullLock { - pub fn lock(&self, f: F) -> R - where - F: FnOnce(&mut T) -> R, - { - // In a real lock, there would be code around this line that ensures - // that this mutable reference will ever only be given out one at a - // time. - f(unsafe { &mut *self.data.get() }) - } -} diff --git a/.10_DMA_memory/.cargo/config b/.10_DMA_memory/.cargo/config deleted file mode 100644 index de3f84c9..00000000 --- a/.10_DMA_memory/.cargo/config +++ /dev/null @@ -1,5 +0,0 @@ -[target.aarch64-unknown-none-softfloat] -rustflags = [ - "-C", "link-arg=-Tlink.ld", - "-C", "target-cpu=cortex-a53", -] diff --git a/.10_DMA_memory/Cargo.lock b/.10_DMA_memory/Cargo.lock deleted file mode 100644 index d218ad56..00000000 --- a/.10_DMA_memory/Cargo.lock +++ /dev/null @@ -1,57 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -[[package]] -name = "cortex-a" -version = "2.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "register 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "kernel8" -version = "0.1.0" -dependencies = [ - "cortex-a 2.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "raspi3_boot 0.1.0", - "register 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "panic-abort" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "r0" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "raspi3_boot" -version = "0.1.0" -dependencies = [ - "cortex-a 2.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "panic-abort 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "r0 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "register" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "tock-registers 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tock-registers" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[metadata] -"checksum cortex-a 2.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cbb16c411ab74044f174746a6cbae67bcdebea126e376b5441e5986e6a6aa950" -"checksum panic-abort 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2c14a66511ed17b6a8b4256b868d7fd207836d891db15eea5195dbcaf87e630f" -"checksum r0 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e2a38df5b15c8d5c7e8654189744d8e396bddc18ad48041a500ce52d6948941f" -"checksum register 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "469bb5ddde81d67fb8bba4e14d77689b8166cfd077abe7530591cefe29d05823" -"checksum tock-registers 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c758f5195a2e0df9d9fecf6f506506b2766ff74cf64db1e995c87e2761a5c3e2" diff --git a/.10_DMA_memory/Cargo.toml b/.10_DMA_memory/Cargo.toml deleted file mode 100644 index 43d1e22e..00000000 --- a/.10_DMA_memory/Cargo.toml +++ /dev/null @@ -1,13 +0,0 @@ -[package] -name = "kernel8" -version = "0.1.0" -authors = ["Andre Richter "] -edition = "2018" - -[dependencies] -raspi3_boot = { path = "raspi3_boot" } -cortex-a = "2.7.0" -register = "0.3.3" - -[package.metadata.cargo-xbuild] -sysroot_path = "../xbuild_sysroot" diff --git a/.10_DMA_memory/Makefile b/.10_DMA_memory/Makefile deleted file mode 100644 index 7a8d3e52..00000000 --- a/.10_DMA_memory/Makefile +++ /dev/null @@ -1,104 +0,0 @@ -# -# MIT License -# -# Copyright (c) 2018-2019 Andre Richter -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# - -TARGET = aarch64-unknown-none-softfloat - -SOURCES = $(wildcard **/*.rs) $(wildcard **/*.S) link.ld - - -XRUSTC_CMD = cargo xrustc --target=$(TARGET) --release -CARGO_OUTPUT = target/$(TARGET)/release/kernel8 - -OBJCOPY = cargo objcopy -- -OBJCOPY_PARAMS = --strip-all -O binary - -CONTAINER_UTILS = andrerichter/raspi3-utils -CONTAINER_OPENOCD = andrerichter/raspi3-openocd -# CONTAINER_OPENOCD_ARG = -f openocd/tcl/interface/ftdi/olimex-jtag-tiny.cfg -f /openocd/rpi3.cfg -CONTAINER_GDB = andrerichter/raspi3-gdb - -DOCKER_CMD = docker run -it --rm -DOCKER_ARG_CURDIR = -v $(shell pwd):/work -w /work -DOCKER_ARG_TTY = --privileged -v /dev:/dev -DOCKER_ARG_JTAG = -v $(shell pwd)/../X1_JTAG_boot:/jtag -DOCKER_ARG_NET = --network host -DOCKER_ARG_EMU = -v $(shell pwd)/../emulation:/emulation - -DOCKER_EXEC_QEMU = bash /emulation/qemu_multi_uart.sh -DOCKER_EXEC_RASPBOOT = raspbootcom -DOCKER_EXEC_RASPBOOT_DEV = /dev/ttyUSB0 -# DOCKER_EXEC_RASPBOOT_DEV = /dev/ttyACM0 - -.PHONY: all qemu raspboot clippy clean objdump nm jtagboot openocd gdb gdb-opt0 - -all: clean kernel8.img - -$(CARGO_OUTPUT): $(SOURCES) - $(XRUSTC_CMD) - -kernel8.img: $(CARGO_OUTPUT) - cp $< . - $(OBJCOPY) $(OBJCOPY_PARAMS) $< kernel8.img - -qemu: all - $(DOCKER_CMD) $(DOCKER_ARG_CURDIR) $(DOCKER_ARG_EMU) \ - $(CONTAINER_UTILS) $(DOCKER_EXEC_QEMU) - -raspboot: all - $(DOCKER_CMD) $(DOCKER_ARG_CURDIR) $(DOCKER_ARG_TTY) \ - $(CONTAINER_UTILS) $(DOCKER_EXEC_RASPBOOT) $(DOCKER_EXEC_RASPBOOT_DEV) \ - kernel8.img - -clippy: - cargo xclippy --target=$(TARGET) - -clean: - cargo clean - -objdump: - cargo objdump --target $(TARGET) -- -disassemble -print-imm-hex kernel8 - -nm: - cargo nm --target $(TARGET) -- kernel8 | sort - -jtagboot: - $(DOCKER_CMD) $(DOCKER_ARG_TTY) $(DOCKER_ARG_JTAG) $(CONTAINER_UTILS) \ - $(DOCKER_EXEC_RASPBOOT) $(DOCKER_EXEC_RASPBOOT_DEV) /jtag/jtag_boot.img - -openocd: - $(DOCKER_CMD) $(DOCKER_ARG_TTY) $(DOCKER_ARG_NET) $(CONTAINER_OPENOCD) \ - $(CONTAINER_OPENOCD_ARG) - -define gen_gdb - $(XRUSTC_CMD) -- $1 - cp $(CARGO_OUTPUT) kernel8_for_jtag - $(DOCKER_CMD) $(DOCKER_ARG_CURDIR) $(DOCKER_ARG_NET) $(CONTAINER_GDB) \ - gdb-multiarch -q kernel8_for_jtag -endef - -gdb: clean $(SOURCES) - $(call gen_gdb,-C debuginfo=2) - -gdb-opt0: clean $(SOURCES) - $(call gen_gdb,-C debuginfo=2 -C opt-level=0) diff --git a/.10_DMA_memory/README.md b/.10_DMA_memory/README.md deleted file mode 100644 index 57a4481b..00000000 --- a/.10_DMA_memory/README.md +++ /dev/null @@ -1,264 +0,0 @@ -# Tutorial 10 - DMA Memory - -There's a secret I haven't told you! A certain part of our code doesn't work -anymore since the [virtual memory](../0D_virtual_memory) tutorial. There is a -regression that manifests in the `Videocore Mailbox` driver. It will only work -until **paging and caching** is switched on. Afterwards, the `call()` method -will fail. Why is that? - -The reason is that in our code, the RPi's processor is sharing a `DRAM buffer` -with the `Videocore` device. In other words, the concept of **shared memory** is -used. Let's recall a simplified version of the protocol: - -1. RPi `CPU` checks the `STATUS` MMIO register of the `Videcore` if a message can - be written. -2. If so, `CPU` writes the address of the `DRAM buffer` in which the actual - message is stored into the `Videocore`'s `WRITE` MMIO register. -3. `CPU` checks the `STATUS` and `READ` MMIO registers if the Videocore has - answered. -4. If so, `CPU` checks the first `u32` word of the earlier provided `DRAM buffer` - if the response is valid (the `Videocore` puts its answer into the same buffer - in which the original request was stored. This is what is commonly called - a `DMA` transaction). - -At step **4**, things break. The reason is that code and **page tables** were -set up in a way that the `DRAM buffer` used for message exchange between `CPU` -and Videcore is attributed as _cacheable_. - -So when the `CPU` is writing to the buffer, the contents might not get written -back to `DRAM` in time before the notification of a new message is signaled to -the Videocore via the `WRITE` MMIO register (which is correctly attributed as -device memory in the page tables and hence not cached). - -Even if the contents would land in `DRAM` in time, the `Videocore`'s answer -which overwrites the same buffer would not be reflected in the `CPU`'s cache, -since there is no coherency mechanism in place between the two. The RPi `CPU` -would read back the same values it put into the buffer itself when setting up -the message, and not the `DRAM` content that contains the answer. - -![DMA block diagram](../doc/dma_0.png) - -The regression did not manifest yet because the Mailbox is only used before -paging and caching is switched on, and never afterwards. However, now is a good time -to fix this. - -## An Allocator for DMA Memory - -The first step is to introduce a region of _non-cacheable DRAM_ in the -`KERNEL_VIRTUAL_LAYOUT` in `memory.rs`: - -```rust -Descriptor { - name: "DMA heap pool", - virtual_range: || RangeInclusive::new(map::virt::DMA_HEAP_START, map::virt::DMA_HEAP_END), - translation: Translation::Identity, - attribute_fields: AttributeFields { - mem_attributes: MemAttributes::NonCacheableDRAM, - acc_perms: AccessPermissions::ReadWrite, - execute_never: true, - }, -}, -``` - -When you saw the inferior performance of non-cacheable mapped DRAM compared to -cacheable DRAM in the [cache performance tutorial](../0E_cache_performance) -earlier and asked yourself why anybody would ever want this: Exactly for the -use-case at hand! - -Theoretically, some linker hacks could be used to ensure that the `Videcore` is -using a buffer that is statically linked to the DMA heap pool once paging and -caching is turned on. However, in real-world kernels, it is common to frequently -map/allocate and unmap/free chunks of `DMA` memory at runtime, for example in -device drivers for DMA-capable devices. - -Hence, let's introduce an `allocator`. - -### Bump Allocation - -As always in the tutorials, a simple implementation is used for getting started -with basic concepts of a topic, and upgrades are introduced when they are -needed. - -In a `bump allocator`, when a requests comes in, it always returns the next -possible aligned region of its heap until it runs out of memory. What makes it -really simple is that it doesn't provide means for freeing memory again. When no -more memory is left, game is over. - -Conveniently enough, [Rust already provides memory allocation APIs](https://doc.rust-lang.org/alloc/alloc/index.html). There is an -[Alloc](https://doc.rust-lang.org/alloc/alloc/trait.Alloc.html) and a -[GlobalAlloc](https://doc.rust-lang.org/alloc/alloc/trait.GlobalAlloc.html) -trait. The latter is intended for realizing a _default allocator_, meaning it -would be the allocator used for any standard language construtcs that -automatically allocate something on the heap, for example a -[Box](https://doc.rust-lang.org/alloc/boxed/index.html). There can only be one -global allocator, so the tutorials will make use of it for cacheable DRAM later. - -Hence, for the DMA bump allocator, -[Alloc](https://doc.rust-lang.org/alloc/alloc/trait.Alloc.html) will be -used. What is also really nice is that for both traits, only the `alloc()` -method needs to be implemented. If this is done, you automatically get a bunch -of additional default methods for free, e.g. `alloc_zeroed()`. - -Here is the implementation in `memory/bump_allocator.rs`: - -```rust -pub struct BumpAllocator { - next: usize, - pool_end: usize, - name: &'static str, -} - -unsafe impl Alloc for BumpAllocator { - unsafe fn alloc(&mut self, layout: Layout) -> Result, AllocErr> { - let start = crate::memory::aligned_addr_unchecked(self.next, layout.align()); - let end = start + layout.size(); - - if end <= self.pool_end { - self.next = end; - - println!( - "[i] {}:\n Allocated Addr {:#010X} Size {:#X}", - self.name, - start, - layout.size() - ); - - Ok(NonNull::new_unchecked(start as *mut u8)) - } else { - Err(AllocErr) - } - } - - // A bump allocator doesn't care - unsafe fn dealloc(&mut self, _ptr: NonNull, _layout: Layout) {} -} -``` - -The `alloc()` method returns a pointer to memory. However, it is safer to -operate with [slices](https://doc.rust-lang.org/alloc/slice/index.html), since -they are intrinsically bounds-checked. Therefore, the `BumpAllocator` gets an -additional method called `alloc_slice_zeroed()`, which wraps around -`alloc_zeroed()` provided by the `Alloc` trait and on success returns a `&'a mut -[T]`. - -### Global Instance - -A global instance of the allocator is needed, and since its methods demand -_mutable references_ to `self`, it is wrapped into a `NullLock`, which was -introduced in the [last tutorial](../0F_globals_synchronization_println): - -```rust -/// The global allocator for DMA-able memory. That is, memory which is tagged -/// non-cacheable in the page tables. -static DMA_ALLOCATOR: sync::NullLock = - sync::NullLock::new(memory::BumpAllocator::new( - memory::map::virt::DMA_HEAP_START as usize, - memory::map::virt::DMA_HEAP_END as usize, - "Global DMA Allocator", - )); - -``` - -## Videocore Driver - -The `Videocore` driver has to be changed to use the allocator during -instantiation, and in contrast to earlier, this could fail now: - -```rust -let ret = crate::DMA_ALLOCATOR.lock(|d| d.alloc_slice_zeroed(MBOX_SIZE, MBOX_ALIGNMENT)); - -if ret.is_err() { - return Err(()); -} -``` - -## Reorg of the Kernel Init - -Since the `Videcore` now depends on the `DMA Allocator`, its initialization must -now happen _after_ the `MMU init`, which turns on **paging and caching**. This, -in turn, means that the `PL011 UART`, which is used for printing and needs the -`Videcore` for its setup, has to shift its init as well. So there is a lot of -shuffling happening. - -In summary, the new init procedure would be: - -1. GPIO -2. MMU -3. Videcore -4. PL011 UART - -That is a bit unfortunate, because if anything goes wrong at `MMU` or -`Videocore` init, we can not print any fault info on the console. For this -reason, the `MiniUart` from the earlier tutorials is revived, because it only -needs the `GPIO` driver to set itself up. So here is the revamped init: - -1. GPIO -2. MiniUart -3. MMU -4. Videcore -5. PL011 UART - -Using this procedure, the `MiniUart` can report faults for any of the subsequent -stages like`MMU` or `Videocore` init. If all is successful and the more capable -`PL011 UART` comes online, we can let it conveniently replace the `MiniUart` -through the `CONSOLE.replace_with()` scheme introduced in the [last tutorial](../0F_globals_synchronization_println). - -### Make it Fault - -If you feel curious and want to put all the theory to action, take a look at the -code in `main.rs` for the DMA allocator instantiation and try the changes in the -comments: - -```rust -/// The global allocator for DMA-able memory. That is, memory which is tagged -/// non-cacheable in the page tables. -static DMA_ALLOCATOR: sync::NullLock = - sync::NullLock::new(memory::BumpAllocator::new( - memory::map::virt::DMA_HEAP_START as usize, - memory::map::virt::DMA_HEAP_END as usize, - "Global DMA Allocator", - // Try the following arguments instead to see the PL011 UART init - // fail. It will cause the allocator to use memory that is marked - // cacheable and therefore not DMA-safe. The communication with the - // Videocore will therefore fail. - - // 0x00600000 as usize, - // 0x007FFFFF as usize, - // "Global Non-DMA Allocator", - )); -``` - -This might only work on the real HW and not in QEMU. - -## QEMU - -On the actual HW it is possible to reprogram the same `GPIO` pins at runtime to -either use the `MiniUart` or the `PL011`, and as a result the console output of -both is sent through the same USB-serial dongle. This is transparent to the -user. - -On QEMU, unfortunately, two different virtual terminals must be used and this -multiplexing is not possible. As a result, you'll see that the QEMU output has -changed in optics a bit and now provides separate views for the two `UARTs`. - -## Output - -```console -ferris@box:~$ make raspboot - -[0] MiniUart online. -[1] Press a key to continue booting... Greetings fellow Rustacean! -[2] MMU online. -[i] Kernel memory layout: - 0x00000000 - 0x0007FFFF | 512 KiB | C RW PXN | Kernel stack - 0x00080000 - 0x00083FFF | 16 KiB | C RO PX | Kernel code and RO data - 0x00084000 - 0x0008700F | 12 KiB | C RW PXN | Kernel data and BSS - 0x00200000 - 0x005FFFFF | 4 MiB | NC RW PXN | DMA heap pool - 0x3F000000 - 0x3FFFFFFF | 16 MiB | Dev RW PXN | Device MMIO -[i] Global DMA Allocator: - Allocated Addr 0x00200000 Size 0x90 -[3] Videocore Mailbox set up (DMA mem heap allocation successful). -[4] PL011 UART online. Output switched to it. - -$> -``` diff --git a/.10_DMA_memory/kernel8 b/.10_DMA_memory/kernel8 deleted file mode 100755 index d1061bd0e29eb595b4f825709e1e380c144d3a38..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 97680 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

    Q}H2}i@Ra6A%-=#gN=h=d~HNF)-C#3J!%AgV`$ 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 BG4=oe diff --git a/.10_DMA_memory/kernel8.img b/.10_DMA_memory/kernel8.img deleted file mode 100755 index a38b0f622bd0988ab46949689990c13ee832d885..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 16416 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 diff --git a/.10_DMA_memory/link.ld b/.10_DMA_memory/link.ld deleted file mode 100644 index cb6f21a6..00000000 --- a/.10_DMA_memory/link.ld +++ /dev/null @@ -1,57 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2018 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -ENTRY(_boot_cores); - -SECTIONS -{ - . = 0x80000; /* This is already 4KiB aligned */ - __ro_start = .; - .text : - { - KEEP(*(.text.boot)) *(.text .text.*) - } - - .rodata : - { - *(.rodata .rodata.*) - } - . = ALIGN(4096); /* Fill up to 4KiB */ - __ro_end = .; - - .data : - { - *(.data .data.*) - } - - .bss ALIGN(8): - { - __bss_start = .; - *(.bss .bss.*) - *(COMMON) - __bss_end = .; - } - - /DISCARD/ : { *(.comment) *(.gnu*) *(.note*) *(.eh_frame*) } -} diff --git a/.10_DMA_memory/raspi3_boot/Cargo.lock b/.10_DMA_memory/raspi3_boot/Cargo.lock deleted file mode 100644 index 7428c6de..00000000 --- a/.10_DMA_memory/raspi3_boot/Cargo.lock +++ /dev/null @@ -1,46 +0,0 @@ -[[package]] -name = "cortex-a" -version = "2.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "register 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "panic-abort" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "r0" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "raspi3_boot" -version = "0.1.0" -dependencies = [ - "cortex-a 2.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "panic-abort 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "r0 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "register" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "tock-registers 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tock-registers" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[metadata] -"checksum cortex-a 2.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "97867bac786c0a2912f7df981bdb8b6ea109a2422c22b37faf651d558a054453" -"checksum panic-abort 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2c14a66511ed17b6a8b4256b868d7fd207836d891db15eea5195dbcaf87e630f" -"checksum r0 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e2a38df5b15c8d5c7e8654189744d8e396bddc18ad48041a500ce52d6948941f" -"checksum register 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a0f44a6dc9a98359515541a0c46ef4e3630a30879c1d7a4038f31dd533570bfb" -"checksum tock-registers 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c758f5195a2e0df9d9fecf6f506506b2766ff74cf64db1e995c87e2761a5c3e2" diff --git a/.10_DMA_memory/raspi3_boot/Cargo.toml b/.10_DMA_memory/raspi3_boot/Cargo.toml deleted file mode 100644 index 024fd184..00000000 --- a/.10_DMA_memory/raspi3_boot/Cargo.toml +++ /dev/null @@ -1,10 +0,0 @@ -[package] -name = "raspi3_boot" -version = "0.1.0" -authors = ["Andre Richter "] -edition = "2018" - -[dependencies] -cortex-a = "2.7.0" -panic-abort = "0.3.1" -r0 = "0.2.2" diff --git a/.10_DMA_memory/raspi3_boot/src/lib.rs b/.10_DMA_memory/raspi3_boot/src/lib.rs deleted file mode 100644 index 01ccd956..00000000 --- a/.10_DMA_memory/raspi3_boot/src/lib.rs +++ /dev/null @@ -1,141 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2018 Jorge Aparicio - * Copyright (c) 2018-2019 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#![deny(missing_docs)] -#![deny(warnings)] -#![no_std] - -//! Low-level boot of the Raspberry's processor - -extern crate panic_abort; - -/// Type check the user-supplied entry function. -#[macro_export] -macro_rules! entry { - ($path:path) => { - /// # Safety - /// - /// - User must ensure to provide a suitable main function for the - /// platform. - #[export_name = "main"] - pub unsafe fn __main() -> ! { - // type check the given path - let f: fn() -> ! = $path; - - f() - } - }; -} - -/// Reset function. -/// -/// Initializes the bss section before calling into the user's `main()`. -/// -/// # Safety -/// -/// - Only a single core must be active and running this function. -unsafe fn reset() -> ! { - extern "C" { - // Boundaries of the .bss section, provided by the linker script - static mut __bss_start: u64; - static mut __bss_end: u64; - } - - // Zeroes the .bss section - r0::zero_bss(&mut __bss_start, &mut __bss_end); - - extern "Rust" { - fn main() -> !; - } - - main() -} - -/// Prepare and execute transition from EL2 to EL1. -#[inline] -fn setup_and_enter_el1_from_el2() -> ! { - use cortex_a::{asm, regs::*}; - - const STACK_START: u64 = 0x80_000; - - // 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 reset(). - ELR_EL2.set(reset as *const () as u64); - - // Set up SP_EL1 (stack pointer), which will be used by EL1 once - // we "return" to it. - SP_EL1.set(STACK_START); - - // Use `eret` to "return" to EL1. This will result in execution of - // `reset()` in EL1. - asm::eret() -} - -/// Entrypoint of the processor. -/// -/// Parks all cores except core0 and checks if we started in EL2. If -/// so, proceeds with setting up EL1. -/// -/// # Safety -/// -/// - Linker script must ensure to place this function at `0x80_000`. -#[link_section = ".text.boot"] -#[no_mangle] -pub unsafe extern "C" fn _boot_cores() -> ! { - use cortex_a::{asm, regs::*}; - - const CORE_0: u64 = 0; - const CORE_MASK: u64 = 0x3; - const EL2: u32 = CurrentEL::EL::EL2.value; - - if (CORE_0 == MPIDR_EL1.get() & CORE_MASK) && (EL2 == CurrentEL.get()) { - setup_and_enter_el1_from_el2() - } - - // if not core0 or EL != 2, infinitely wait for events - loop { - asm::wfe(); - } -} diff --git a/.10_DMA_memory/src/delays.rs b/.10_DMA_memory/src/delays.rs deleted file mode 100644 index b1c1fa0f..00000000 --- a/.10_DMA_memory/src/delays.rs +++ /dev/null @@ -1,37 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2018-2019 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -use cortex_a::asm; - -/* - * - * Using the CPU's cycles - * - */ -/// Wait N CPU cycles (ARM CPU only) -pub fn wait_cycles(cyc: u32) { - for _ in 0..cyc { - asm::nop(); - } -} diff --git a/.10_DMA_memory/src/devices.rs b/.10_DMA_memory/src/devices.rs deleted file mode 100644 index 227b92c2..00000000 --- a/.10_DMA_memory/src/devices.rs +++ /dev/null @@ -1,26 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2019 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -pub mod hw; -pub mod virt; diff --git a/.10_DMA_memory/src/devices/hw.rs b/.10_DMA_memory/src/devices/hw.rs deleted file mode 100644 index 08a6c06c..00000000 --- a/.10_DMA_memory/src/devices/hw.rs +++ /dev/null @@ -1,33 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2019 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -mod gpio; -mod mini_uart; -mod pl011_uart; -mod videocore_mbox; - -pub use gpio::GPIO; -pub use mini_uart::MiniUart; -pub use pl011_uart::PL011Uart; -pub use videocore_mbox::VideocoreMbox; diff --git a/.10_DMA_memory/src/devices/hw/gpio.rs b/.10_DMA_memory/src/devices/hw/gpio.rs deleted file mode 100644 index 7affea08..00000000 --- a/.10_DMA_memory/src/devices/hw/gpio.rs +++ /dev/null @@ -1,120 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2018-2019 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -use core::ops; -use register::{mmio::ReadWrite, register_bitfields}; - -// Descriptions taken from -// https://github.com/raspberrypi/documentation/files/1888662/BCM2837-ARM-Peripherals.-.Revised.-.V2-1.pdf -register_bitfields! { - u32, - - /// GPIO Function Select 1 - GPFSEL1 [ - /// Pin 15 - FSEL15 OFFSET(15) NUMBITS(3) [ - Input = 0b000, - Output = 0b001, - RXD0 = 0b100, // UART0 - Alternate function 0 - RXD1 = 0b010 // Mini UART - Alternate function 5 - - ], - - /// Pin 14 - FSEL14 OFFSET(12) NUMBITS(3) [ - Input = 0b000, - Output = 0b001, - TXD0 = 0b100, // UART0 - Alternate function 0 - TXD1 = 0b010 // Mini UART - Alternate function 5 - ] - ], - - /// GPIO Pull-up/down Clock Register 0 - GPPUDCLK0 [ - /// Pin 15 - PUDCLK15 OFFSET(15) NUMBITS(1) [ - NoEffect = 0, - AssertClock = 1 - ], - - /// Pin 14 - PUDCLK14 OFFSET(14) NUMBITS(1) [ - NoEffect = 0, - AssertClock = 1 - ] - ] -} - -#[allow(non_snake_case)] -#[repr(C)] -pub struct RegisterBlock { - pub GPFSEL0: ReadWrite, // 0x00 - pub GPFSEL1: ReadWrite, // 0x04 - pub GPFSEL2: ReadWrite, // 0x08 - pub GPFSEL3: ReadWrite, // 0x0C - pub GPFSEL4: ReadWrite, // 0x10 - pub GPFSEL5: ReadWrite, // 0x14 - __reserved_0: u32, // 0x18 - GPSET0: ReadWrite, // 0x1C - GPSET1: ReadWrite, // 0x20 - __reserved_1: u32, // - GPCLR0: ReadWrite, // 0x28 - __reserved_2: [u32; 2], // - GPLEV0: ReadWrite, // 0x34 - GPLEV1: ReadWrite, // 0x38 - __reserved_3: u32, // - GPEDS0: ReadWrite, // 0x40 - GPEDS1: ReadWrite, // 0x44 - __reserved_4: [u32; 7], // - GPHEN0: ReadWrite, // 0x64 - GPHEN1: ReadWrite, // 0x68 - __reserved_5: [u32; 10], // - pub GPPUD: ReadWrite, // 0x94 - pub GPPUDCLK0: ReadWrite, // 0x98 - pub GPPUDCLK1: ReadWrite, // 0x9C -} - -/// Public interface to the GPIO MMIO area -pub struct GPIO { - base_addr: usize, -} - -impl ops::Deref for GPIO { - type Target = RegisterBlock; - - fn deref(&self) -> &Self::Target { - unsafe { &*self.ptr() } - } -} - -impl GPIO { - pub fn new(base_addr: usize) -> GPIO { - GPIO { base_addr } - } - - /// Returns a pointer to the register block - fn ptr(&self) -> *const RegisterBlock { - self.base_addr as *const _ - } -} diff --git a/.10_DMA_memory/src/devices/hw/mini_uart.rs b/.10_DMA_memory/src/devices/hw/mini_uart.rs deleted file mode 100644 index f98b06bf..00000000 --- a/.10_DMA_memory/src/devices/hw/mini_uart.rs +++ /dev/null @@ -1,266 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2018-2019 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -use super::gpio; -use crate::devices::virt::ConsoleOps; -use core::ops; -use cortex_a::asm; -use register::{mmio::*, register_bitfields}; - -// Auxilary mini UART registers -// -// Descriptions taken from -// https://github.com/raspberrypi/documentation/files/1888662/BCM2837-ARM-Peripherals.-.Revised.-.V2-1.pdf -register_bitfields! { - u32, - - /// Auxiliary enables - AUX_ENABLES [ - /// If set the mini UART is enabled. The UART will immediately - /// start receiving data, especially if the UART1_RX line is - /// low. - /// If clear the mini UART is disabled. That also disables any - /// mini UART register access - MINI_UART_ENABLE OFFSET(0) NUMBITS(1) [] - ], - - /// Mini Uart Interrupt Identify - AUX_MU_IIR [ - /// Writing with bit 1 set will clear the receive FIFO - /// Writing with bit 2 set will clear the transmit FIFO - FIFO_CLEAR OFFSET(1) NUMBITS(2) [ - Rx = 0b01, - Tx = 0b10, - All = 0b11 - ] - ], - - /// Mini Uart Line Control - AUX_MU_LCR [ - /// Mode the UART works in - DATA_SIZE OFFSET(0) NUMBITS(2) [ - SevenBit = 0b00, - EightBit = 0b11 - ] - ], - - /// Mini Uart Line Status - AUX_MU_LSR [ - /// This bit is set if the transmit FIFO is empty and the transmitter is - /// idle. (Finished shifting out the last bit). - TX_IDLE OFFSET(6) NUMBITS(1) [], - - /// This bit is set if the transmit FIFO can accept at least - /// one byte. - TX_EMPTY OFFSET(5) NUMBITS(1) [], - - /// This bit is set if the receive FIFO holds at least 1 - /// symbol. - DATA_READY OFFSET(0) NUMBITS(1) [] - ], - - /// Mini Uart Extra Control - AUX_MU_CNTL [ - /// If this bit is set the mini UART transmitter is enabled. - /// If this bit is clear the mini UART transmitter is disabled. - TX_EN OFFSET(1) NUMBITS(1) [ - Disabled = 0, - Enabled = 1 - ], - - /// If this bit is set the mini UART receiver is enabled. - /// If this bit is clear the mini UART receiver is disabled. - RX_EN OFFSET(0) NUMBITS(1) [ - Disabled = 0, - Enabled = 1 - ] - ], - - /// Mini Uart Baudrate - AUX_MU_BAUD [ - /// Mini UART baudrate counter - RATE OFFSET(0) NUMBITS(16) [] - ] -} - -#[allow(non_snake_case)] -#[repr(C)] -pub struct RegisterBlock { - __reserved_0: u32, // 0x00 - AUX_ENABLES: ReadWrite, // 0x04 - __reserved_1: [u32; 14], // 0x08 - AUX_MU_IO: ReadWrite, // 0x40 - Mini Uart I/O Data - AUX_MU_IER: WriteOnly, // 0x44 - Mini Uart Interrupt Enable - AUX_MU_IIR: WriteOnly, // 0x48 - AUX_MU_LCR: WriteOnly, // 0x4C - AUX_MU_MCR: WriteOnly, // 0x50 - AUX_MU_LSR: ReadOnly, // 0x54 - __reserved_2: [u32; 2], // 0x58 - AUX_MU_CNTL: WriteOnly, // 0x60 - __reserved_3: u32, // 0x64 - AUX_MU_BAUD: WriteOnly, // 0x68 -} - -pub struct MiniUart { - base_addr: usize, -} - -/// Deref to RegisterBlock -/// -/// Allows writing -/// ``` -/// self.MU_IER.read() -/// ``` -/// instead of something along the lines of -/// ``` -/// unsafe { (*MiniUart::ptr()).MU_IER.read() } -/// ``` -impl ops::Deref for MiniUart { - type Target = RegisterBlock; - - fn deref(&self) -> &Self::Target { - unsafe { &*self.ptr() } - } -} - -impl MiniUart { - pub fn new(base_addr: usize) -> MiniUart { - MiniUart { base_addr } - } - - /// Returns a pointer to the register block - fn ptr(&self) -> *const RegisterBlock { - self.base_addr as *const _ - } - - ///Set baud rate and characteristics (115200 8N1) and map to GPIO - pub fn init(&self, gpio: &gpio::GPIO) { - // initialize UART - self.AUX_ENABLES.modify(AUX_ENABLES::MINI_UART_ENABLE::SET); - self.AUX_MU_IER.set(0); - self.AUX_MU_CNTL.set(0); - self.AUX_MU_LCR.write(AUX_MU_LCR::DATA_SIZE::EightBit); - self.AUX_MU_MCR.set(0); - self.AUX_MU_IER.set(0); - self.AUX_MU_IIR.write(AUX_MU_IIR::FIFO_CLEAR::All); - self.AUX_MU_BAUD.write(AUX_MU_BAUD::RATE.val(270)); // 115200 baud - - // map UART1 to GPIO pins - gpio.GPFSEL1 - .modify(gpio::GPFSEL1::FSEL14::TXD1 + gpio::GPFSEL1::FSEL15::RXD1); - - gpio.GPPUD.set(0); // enable pins 14 and 15 - for _ in 0..150 { - asm::nop(); - } - - gpio.GPPUDCLK0 - .write(gpio::GPPUDCLK0::PUDCLK14::AssertClock + gpio::GPPUDCLK0::PUDCLK15::AssertClock); - for _ in 0..150 { - asm::nop(); - } - - gpio.GPPUDCLK0.set(0); - - self.AUX_MU_CNTL - .write(AUX_MU_CNTL::RX_EN::Enabled + AUX_MU_CNTL::TX_EN::Enabled); - - // Clear FIFOs before using the device - self.AUX_MU_IIR.write(AUX_MU_IIR::FIFO_CLEAR::All); - } - - pub fn wait_tx_fifo_empty(&self) { - loop { - if self.AUX_MU_LSR.is_set(AUX_MU_LSR::TX_IDLE) { - break; - } - - asm::nop(); - } - } -} - -impl Drop for MiniUart { - fn drop(&mut self) { - self.AUX_ENABLES - .modify(AUX_ENABLES::MINI_UART_ENABLE::CLEAR); - } -} - -impl ConsoleOps for MiniUart { - /// Send a character - fn putc(&self, c: char) { - // wait until we can send - loop { - if self.AUX_MU_LSR.is_set(AUX_MU_LSR::TX_EMPTY) { - break; - } - - asm::nop(); - } - - // write the character to the buffer - self.AUX_MU_IO.set(c as u32); - } - - /// Display a string - fn puts(&self, string: &str) { - for c in string.chars() { - // convert newline to carrige return + newline - if c == '\n' { - self.putc('\r') - } - - self.putc(c); - } - } - - /// Receive a character - fn getc(&self) -> char { - // wait until something is in the buffer - loop { - if self.AUX_MU_LSR.is_set(AUX_MU_LSR::DATA_READY) { - break; - } - - asm::nop(); - } - - // read it and return - let mut ret = self.AUX_MU_IO.get() as u8 as char; - - // convert carrige return to newline - if ret == '\r' { - ret = '\n' - } - - ret - } - - /// Wait until the TX FIFO is empty, aka all characters have been put on the - /// line. - fn flush(&self) { - self.wait_tx_fifo_empty(); - } -} diff --git a/.10_DMA_memory/src/devices/hw/pl011_uart.rs b/.10_DMA_memory/src/devices/hw/pl011_uart.rs deleted file mode 100644 index 44580d35..00000000 --- a/.10_DMA_memory/src/devices/hw/pl011_uart.rs +++ /dev/null @@ -1,276 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2018-2019 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -use super::gpio; -use super::videocore_mbox; -use crate::delays; -use crate::devices::virt::ConsoleOps; -use core::{ - ops, - sync::atomic::{compiler_fence, Ordering}, -}; -use cortex_a::asm; -use register::{mmio::*, register_bitfields}; - -// PL011 UART registers. -// -// Descriptions taken from -// https://github.com/raspberrypi/documentation/files/1888662/BCM2837-ARM-Peripherals.-.Revised.-.V2-1.pdf -register_bitfields! { - u32, - - /// Flag Register - FR [ - /// Transmit FIFO full. The meaning of this bit depends on the - /// state of the FEN bit in the UARTLCR_ LCRH 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 UARTLCR_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) [] - ], - - /// Integer Baud rate divisor - IBRD [ - /// Integer Baud rate divisor - IBRD OFFSET(0) NUMBITS(16) [] - ], - - /// Fractional Baud rate divisor - FBRD [ - /// Fractional Baud rate divisor - FBRD OFFSET(0) NUMBITS(6) [] - ], - - /// Line Control register - LCRH [ - /// Word length. These bits indicate the number of data bits - /// transmitted or received in a frame. - WLEN OFFSET(5) NUMBITS(2) [ - FiveBit = 0b00, - SixBit = 0b01, - SevenBit = 0b10, - EightBit = 0b11 - ] - ], - - /// Control Register - CR [ - /// Receive enable. If this bit is set to 1, the receive - /// section of the UART is enabled. Data reception occurs for - /// UART signals. 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 UART signals. 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 - 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 - ] - ], - - /// Interupt Clear Register - ICR [ - /// Meta field for all pending interrupts - ALL OFFSET(0) NUMBITS(11) [] - ] -} - -#[allow(non_snake_case)] -#[repr(C)] -pub struct RegisterBlock { - DR: ReadWrite, // 0x00 - __reserved_0: [u32; 5], // 0x04 - FR: ReadOnly, // 0x18 - __reserved_1: [u32; 2], // 0x1c - IBRD: WriteOnly, // 0x24 - FBRD: WriteOnly, // 0x28 - LCRH: WriteOnly, // 0x2C - CR: WriteOnly, // 0x30 - __reserved_2: [u32; 4], // 0x34 - ICR: WriteOnly, // 0x44 -} - -pub enum PL011UartError { - MailboxError, -} -pub type Result = ::core::result::Result; - -pub struct PL011Uart { - base_addr: usize, -} - -impl ops::Deref for PL011Uart { - type Target = RegisterBlock; - - fn deref(&self) -> &Self::Target { - unsafe { &*self.ptr() } - } -} - -impl PL011Uart { - pub fn new(base_addr: usize) -> PL011Uart { - PL011Uart { base_addr } - } - - /// Returns a pointer to the register block - fn ptr(&self) -> *const RegisterBlock { - self.base_addr as *const _ - } - - ///Set baud rate and characteristics (115200 8N1) and map to GPIO - pub fn init( - &self, - v_mbox: &mut videocore_mbox::VideocoreMbox, - gpio: &gpio::GPIO, - ) -> Result<()> { - // turn off UART0 - self.CR.set(0); - - // set up clock for consistent divisor values - v_mbox.buffer[0] = 9 * 4; - v_mbox.buffer[1] = videocore_mbox::REQUEST; - v_mbox.buffer[2] = videocore_mbox::tag::SETCLKRATE; - v_mbox.buffer[3] = 12; - v_mbox.buffer[4] = 8; - v_mbox.buffer[5] = videocore_mbox::clock::UART; // UART clock - v_mbox.buffer[6] = 4_000_000; // 4Mhz - v_mbox.buffer[7] = 0; // skip turbo setting - v_mbox.buffer[8] = videocore_mbox::tag::LAST; - - // Insert a compiler fence that ensures that all stores to the - // mbox buffer are finished before the GPU is signaled (which - // is done by a store operation as well). - compiler_fence(Ordering::Release); - - if v_mbox.call(videocore_mbox::channel::PROP).is_err() { - return Err(PL011UartError::MailboxError); // Abort if UART clocks couldn't be set - }; - - // map UART0 to GPIO pins - gpio.GPFSEL1 - .modify(gpio::GPFSEL1::FSEL14::TXD0 + gpio::GPFSEL1::FSEL15::RXD0); - - gpio.GPPUD.set(0); // enable pins 14 and 15 - delays::wait_cycles(150); - - gpio.GPPUDCLK0.modify( - gpio::GPPUDCLK0::PUDCLK14::AssertClock + gpio::GPPUDCLK0::PUDCLK15::AssertClock, - ); - delays::wait_cycles(150); - - gpio.GPPUDCLK0.set(0); - - self.ICR.write(ICR::ALL::CLEAR); - self.IBRD.write(IBRD::IBRD.val(2)); // Results in 115200 baud - self.FBRD.write(FBRD::FBRD.val(0xB)); - self.LCRH.write(LCRH::WLEN::EightBit); // 8N1 - - self.CR - .write(CR::UARTEN::Enabled + CR::TXE::Enabled + CR::RXE::Enabled); - - Ok(()) - } -} - -impl Drop for PL011Uart { - fn drop(&mut self) { - self.CR - .write(CR::UARTEN::Disabled + CR::TXE::Disabled + CR::RXE::Disabled); - } -} - -impl ConsoleOps for PL011Uart { - /// Send a character - fn putc(&self, c: char) { - // wait until we can send - loop { - if !self.FR.is_set(FR::TXFF) { - break; - } - - asm::nop(); - } - - // write the character to the buffer - self.DR.set(c as u32); - } - - /// Display a string - fn puts(&self, string: &str) { - for c in string.chars() { - // convert newline to carrige return + newline - if c == '\n' { - self.putc('\r') - } - - self.putc(c); - } - } - - /// Receive a character - fn getc(&self) -> char { - // wait until something is in the buffer - loop { - if !self.FR.is_set(FR::RXFE) { - break; - } - - asm::nop(); - } - - // read it and return - let mut ret = self.DR.get() as u8 as char; - - // convert carrige return to newline - if ret == '\r' { - ret = '\n' - } - - ret - } -} diff --git a/.10_DMA_memory/src/devices/hw/videocore_mbox.rs b/.10_DMA_memory/src/devices/hw/videocore_mbox.rs deleted file mode 100644 index 729777aa..00000000 --- a/.10_DMA_memory/src/devices/hw/videocore_mbox.rs +++ /dev/null @@ -1,170 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2018-2019 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -use core::ops; -use cortex_a::asm; -use register::{ - mmio::{ReadOnly, WriteOnly}, - register_bitfields, -}; - -register_bitfields! { - u32, - - STATUS [ - FULL OFFSET(31) NUMBITS(1) [], - EMPTY OFFSET(30) NUMBITS(1) [] - ] -} - -#[allow(non_snake_case)] -#[repr(C)] -pub struct RegisterBlock { - READ: ReadOnly, // 0x00 - __reserved_0: [u32; 5], // 0x04 - STATUS: ReadOnly, // 0x18 - __reserved_1: u32, // 0x1C - WRITE: WriteOnly, // 0x20 -} - -// Custom errors -pub enum VideocoreMboxError { - ResponseError, - UnknownError, -} -pub type Result = ::core::result::Result; - -// Channels -pub mod channel { - pub const PROP: u32 = 8; -} - -// Tags -pub mod tag { - pub const SETCLKRATE: u32 = 0x38002; - pub const LAST: u32 = 0; -} - -// Clocks -pub mod clock { - pub const UART: u32 = 0x0_0000_0002; -} - -// Responses -mod response { - pub const SUCCESS: u32 = 0x8000_0000; - pub const ERROR: u32 = 0x8000_0001; // error parsing request buffer (partial response) -} - -pub const REQUEST: u32 = 0; - -// The address for buffer needs to be 16-byte aligned so that the Videcore can -// handle it properly. -const MBOX_ALIGNMENT: usize = 16; -const MBOX_SIZE: usize = 36; - -// Public interface to the mailbox -pub struct VideocoreMbox<'a> { - pub buffer: &'a mut [u32], - base_addr: usize, -} - -/// Deref to RegisterBlock -/// -/// Allows writing -/// ``` -/// self.STATUS.read() -/// ``` -/// instead of something along the lines of -/// ``` -/// unsafe { (*Mbox::ptr()).STATUS.read() } -/// ``` -impl<'a> ops::Deref for VideocoreMbox<'a> { - type Target = RegisterBlock; - - fn deref(&self) -> &Self::Target { - unsafe { &*self.ptr() } - } -} - -impl<'a> VideocoreMbox<'a> { - pub fn new(base_addr: usize) -> ::core::result::Result, ()> { - let ret = crate::DMA_ALLOCATOR.lock(|d| d.alloc_slice_zeroed(MBOX_SIZE, MBOX_ALIGNMENT)); - - if ret.is_err() { - return Err(()); - } - - Ok(VideocoreMbox { - base_addr, - buffer: ret.unwrap(), - }) - } - - /// Returns a pointer to the register block - fn ptr(&self) -> *const RegisterBlock { - self.base_addr as *const _ - } - - /// Make a mailbox call. Returns Err(MboxError) on failure, Ok(()) success - pub fn call(&self, channel: u32) -> Result<()> { - // wait until we can write to the mailbox - loop { - if !self.STATUS.is_set(STATUS::FULL) { - break; - } - - asm::nop(); - } - - let buf_ptr = self.buffer.as_ptr() as u32; - - // write the address of our message to the mailbox with channel identifier - self.WRITE.set((buf_ptr & !0xF) | (channel & 0xF)); - - // now wait for the response - loop { - // is there a response? - loop { - if !self.STATUS.is_set(STATUS::EMPTY) { - break; - } - - asm::nop(); - } - - let resp: u32 = self.READ.get(); - - // is it a response to our message? - if ((resp & 0xF) == channel) && ((resp & !0xF) == buf_ptr) { - // is it a valid successful response? - return match self.buffer[1] { - response::SUCCESS => Ok(()), - response::ERROR => Err(VideocoreMboxError::ResponseError), - _ => Err(VideocoreMboxError::UnknownError), - }; - } - } - } -} diff --git a/.10_DMA_memory/src/devices/virt.rs b/.10_DMA_memory/src/devices/virt.rs deleted file mode 100644 index 30ed5469..00000000 --- a/.10_DMA_memory/src/devices/virt.rs +++ /dev/null @@ -1,27 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2019 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -mod console; - -pub use console::{Console, ConsoleOps}; diff --git a/.10_DMA_memory/src/devices/virt/console.rs b/.10_DMA_memory/src/devices/virt/console.rs deleted file mode 100644 index 6972325a..00000000 --- a/.10_DMA_memory/src/devices/virt/console.rs +++ /dev/null @@ -1,144 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2019 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -use crate::devices::hw; -use core::fmt; - -/// A trait that must be implemented by devices that are candidates for the -/// global console. -#[allow(unused_variables)] -pub trait ConsoleOps: Drop { - fn putc(&self, c: char) {} - fn puts(&self, string: &str) {} - fn getc(&self) -> char { - ' ' - } - fn flush(&self) {} -} - -/// A dummy console that just ignores its inputs. -pub struct NullConsole; -impl Drop for NullConsole { - fn drop(&mut self) {} -} -impl ConsoleOps for NullConsole {} - -/// Possible outputs which the console can store. -pub enum Output { - None(NullConsole), - MiniUart(hw::MiniUart), - PL011Uart(hw::PL011Uart), -} - -impl From for Output { - fn from(instance: hw::MiniUart) -> Self { - Output::MiniUart(instance) - } -} - -impl From for Output { - fn from(instance: hw::PL011Uart) -> Self { - Output::PL011Uart(instance) - } -} - -pub struct Console { - output: Output, -} - -impl Console { - pub const fn new() -> Console { - Console { - output: Output::None(NullConsole {}), - } - } - - #[inline(always)] - fn current_ptr(&self) -> &dyn ConsoleOps { - match &self.output { - Output::None(i) => i, - Output::MiniUart(i) => i, - Output::PL011Uart(i) => i, - } - } - - /// Overwrite the current output. The old output will go out of scope and - /// it's Drop function will be called. - pub fn replace_with(&mut self, x: Output) { - self.current_ptr().flush(); - - self.output = x; - } - - /// A command prompt. Currently does nothing. - pub fn command_prompt(&self) -> ! { - self.puts("\n$> "); - - let mut input; - loop { - input = self.getc(); - - if input == '\n' { - self.puts("\n$> ") - } else { - self.putc(input); - } - } - } -} - -impl Drop for Console { - fn drop(&mut self) {} -} - -/// Dispatch the respective function to the currently stored output device. -impl ConsoleOps for Console { - fn putc(&self, c: char) { - self.current_ptr().putc(c); - } - - fn puts(&self, string: &str) { - self.current_ptr().puts(string); - } - - fn getc(&self) -> char { - self.current_ptr().getc() - } - - fn flush(&self) { - self.current_ptr().flush() - } -} - -/// Implementing this trait enables usage of the format_args! macros, which in -/// turn are used to implement the kernel's print! and println! macros. -/// -/// See src/macros.rs. -impl fmt::Write for Console { - fn write_str(&mut self, s: &str) -> fmt::Result { - self.current_ptr().puts(s); - - Ok(()) - } -} diff --git a/.10_DMA_memory/src/macros.rs b/.10_DMA_memory/src/macros.rs deleted file mode 100644 index 28280be9..00000000 --- a/.10_DMA_memory/src/macros.rs +++ /dev/null @@ -1,49 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2019 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -use core::fmt; - -// https://doc.rust-lang.org/src/std/macros.rs.html -#[macro_export] -macro_rules! print { - ($($arg:tt)*) => ($crate::macros::_print(format_args!($($arg)*))); -} - -// https://doc.rust-lang.org/src/std/macros.rs.html -#[macro_export] -macro_rules! println { - () => (print!("\n")); - ($($arg:tt)*) => ({ - $crate::macros::_print(format_args_nl!($($arg)*)); - }) -} - -#[doc(hidden)] -pub fn _print(args: fmt::Arguments) { - use core::fmt::Write; - - crate::CONSOLE.lock(|c| { - c.write_fmt(args).unwrap(); - }) -} diff --git a/.10_DMA_memory/src/main.rs b/.10_DMA_memory/src/main.rs deleted file mode 100644 index 06fdd57a..00000000 --- a/.10_DMA_memory/src/main.rs +++ /dev/null @@ -1,163 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2018-2019 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#![no_std] -#![no_main] -#![feature(allocator_api)] -#![feature(const_fn)] -#![feature(custom_attribute)] -#![feature(format_args_nl)] -#![feature(label_break_value)] - -mod delays; -mod devices; -mod macros; -mod memory; -mod sync; - -/// The global console. Output of the print! and println! macros. -static CONSOLE: sync::NullLock = - sync::NullLock::new(devices::virt::Console::new()); - -/// The global allocator for DMA-able memory. That is, memory which is tagged -/// non-cacheable in the page tables. -static DMA_ALLOCATOR: sync::NullLock = - sync::NullLock::new(memory::BumpAllocator::new( - memory::map::virt::DMA_HEAP_START as usize, - memory::map::virt::DMA_HEAP_END as usize, - "Global DMA Allocator", - // Try the following arguments instead to see the PL011 UART init - // fail. It will cause the allocator to use memory that is marked - // cacheable and therefore not DMA-safe. The communication with the - // Videocore will therefore fail. - - // 0x00600000 as usize, - // 0x007FFFFF as usize, - // "Global Non-DMA Allocator", - )); - -fn kernel_entry() -> ! { - use devices::hw; - use devices::virt::ConsoleOps; - - //------------------------------------------------------------ - // Instantiate GPIO device - //------------------------------------------------------------ - let gpio = hw::GPIO::new(memory::map::physical::GPIO_BASE); - - //------------------------------------------------------------ - // Instantiate MiniUart - //------------------------------------------------------------ - let mini_uart = hw::MiniUart::new(memory::map::physical::MINI_UART_BASE); - mini_uart.init(&gpio); - - CONSOLE.lock(|c| { - // Moves mini_uart into the global CONSOLE. It is not accessible anymore - // for the remaining parts of kernel_entry(). - c.replace_with(mini_uart.into()); - }); - println!("\n[0] MiniUart online."); - - //------------------------------------------------------------ - // Greet the user - //------------------------------------------------------------ - print!("[1] Press a key to continue booting... "); - CONSOLE.lock(|c| { - c.getc(); - }); - println!("Greetings fellow Rustacean!"); - - // We are now in a state where every next step can fail, but we can handle - // the error with feedback for the user and fall through to our UART - // loopback. - 'init: { - //------------------------------------------------------------ - // Bring up memory subsystem - //------------------------------------------------------------ - if unsafe { memory::mmu::init() }.is_err() { - println!("[2][Error] Could not set up MMU. Aborting."); - break 'init; - }; - println!("[2] MMU online."); - - memory::print_layout(); - - //------------------------------------------------------------ - // Instantiate Videocore Mailbox - //------------------------------------------------------------ - let mut v_mbox; - match hw::VideocoreMbox::new(memory::map::physical::VIDEOCORE_MBOX_BASE) { - Ok(i) => { - println!("[3] Videocore Mailbox set up (DMA mem heap allocation successful)."); - v_mbox = i; - } - - Err(_) => { - println!("[3][Error] Could not set up Videocore Mailbox. Aborting."); - break 'init; - } - } - - //------------------------------------------------------------ - // Instantiate PL011 UART and replace MiniUart with it in CONSOLE - //------------------------------------------------------------ - let pl011_uart = hw::PL011Uart::new(memory::map::physical::PL011_UART_BASE); - - // uart.init() will reconfigure the GPIO, which causes a race against - // the MiniUart that is still putting out characters on the physical - // line that are already buffered in its TX FIFO. - // - // To ensure the CPU doesn't rewire the GPIO before the MiniUart has put - // its last character, explicitly flush it before rewiring. - // - // If you switch to an output that happens to not use the same pair of - // physical wires (e.g. the Framebuffer), you don't need to do this, - // because flush() is anyways called implicitly by replace_with(). This - // is just a special case. - CONSOLE.lock(|c| c.flush()); - match pl011_uart.init(&mut v_mbox, &gpio) { - Ok(_) => { - CONSOLE.lock(|c| { - c.replace_with(pl011_uart.into()); - }); - - println!("[4] PL011 UART online. Output switched to it."); - } - - Err(_) => println!( - "[4][Error] PL011 UART init failed. \ - Trying to continue with MiniUart." - ), - } - } - - //------------------------------------------------------------ - // Start a command prompt - //------------------------------------------------------------ - CONSOLE.lock(|c| { - c.command_prompt(); - }) -} - -raspi3_boot::entry!(kernel_entry); diff --git a/.10_DMA_memory/src/memory.rs b/.10_DMA_memory/src/memory.rs deleted file mode 100644 index f1da0c87..00000000 --- a/.10_DMA_memory/src/memory.rs +++ /dev/null @@ -1,292 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2019 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -use crate::println; -use core::fmt; -use core::ops::RangeInclusive; - -mod bump_allocator; -pub use bump_allocator::BumpAllocator; - -pub mod mmu; - -/// System memory map. -#[rustfmt::skip] -pub mod map { - pub const START: usize = 0x0000_0000; - pub const END: usize = 0x3FFF_FFFF; - - pub mod physical { - pub const MMIO_BASE: usize = 0x3F00_0000; - pub const VIDEOCORE_MBOX_BASE: usize = MMIO_BASE + 0x0000_B880; - pub const GPIO_BASE: usize = MMIO_BASE + 0x0020_0000; - pub const PL011_UART_BASE: usize = MMIO_BASE + 0x0020_1000; - pub const MINI_UART_BASE: usize = MMIO_BASE + 0x0021_5000; - pub const MMIO_END: usize = super::END; - } - - pub mod virt { - pub const KERN_STACK_START: usize = super::START; - pub const KERN_STACK_END: usize = 0x0007_FFFF; - - // The second 2 MiB block. - pub const DMA_HEAP_START: usize = 0x0020_0000; - pub const DMA_HEAP_END: usize = 0x005F_FFFF; - } -} - -/// Types used for compiling the virtual memory layout of the kernel using -/// address ranges. -pub mod kernel_mem_range { - use core::ops::RangeInclusive; - - #[derive(Copy, Clone)] - pub enum MemAttributes { - CacheableDRAM, - NonCacheableDRAM, - Device, - } - - #[derive(Copy, Clone)] - pub enum AccessPermissions { - ReadOnly, - ReadWrite, - } - - #[allow(dead_code)] - #[derive(Copy, Clone)] - pub enum Translation { - Identity, - Offset(usize), - } - - #[derive(Copy, Clone)] - pub struct AttributeFields { - pub mem_attributes: MemAttributes, - pub acc_perms: AccessPermissions, - pub execute_never: bool, - } - - impl Default for AttributeFields { - fn default() -> AttributeFields { - AttributeFields { - mem_attributes: MemAttributes::CacheableDRAM, - acc_perms: AccessPermissions::ReadWrite, - execute_never: true, - } - } - } - - pub struct Descriptor { - pub name: &'static str, - pub virtual_range: fn() -> RangeInclusive, - pub translation: Translation, - pub attribute_fields: AttributeFields, - } -} - -use kernel_mem_range::*; - -/// A virtual memory layout that is agnostic of the paging granularity that the -/// hardware MMU will use. -/// -/// Contains only special ranges, aka anything that is _not_ normal cacheable -/// DRAM. -static KERNEL_VIRTUAL_LAYOUT: [Descriptor; 5] = [ - Descriptor { - name: "Kernel stack", - virtual_range: || { - RangeInclusive::new(map::virt::KERN_STACK_START, map::virt::KERN_STACK_END) - }, - translation: Translation::Identity, - attribute_fields: AttributeFields { - mem_attributes: MemAttributes::CacheableDRAM, - acc_perms: AccessPermissions::ReadWrite, - execute_never: true, - }, - }, - Descriptor { - name: "Kernel code and RO data", - virtual_range: || { - // Using the linker script, we ensure that the RO area is consecutive and 4 - // KiB aligned, and we export the boundaries via symbols: - // - // [__ro_start, __ro_end) - extern "C" { - // The inclusive start of the read-only area, aka the address of the - // first byte of the area. - static __ro_start: u64; - - // The exclusive end of the read-only area, aka the address of - // the first byte _after_ the RO area. - static __ro_end: u64; - } - - unsafe { - // Notice the subtraction to turn the exclusive end into an - // inclusive end - RangeInclusive::new( - &__ro_start as *const _ as usize, - &__ro_end as *const _ as usize - 1, - ) - } - }, - translation: Translation::Identity, - attribute_fields: AttributeFields { - mem_attributes: MemAttributes::CacheableDRAM, - acc_perms: AccessPermissions::ReadOnly, - execute_never: false, - }, - }, - Descriptor { - name: "Kernel data and BSS", - virtual_range: || { - extern "C" { - static __ro_end: u64; - static __bss_end: u64; - } - - unsafe { - RangeInclusive::new( - &__ro_end as *const _ as usize, - &__bss_end as *const _ as usize - 1, - ) - } - }, - translation: Translation::Identity, - attribute_fields: AttributeFields { - mem_attributes: MemAttributes::CacheableDRAM, - acc_perms: AccessPermissions::ReadWrite, - execute_never: true, - }, - }, - Descriptor { - name: "DMA heap pool", - virtual_range: || RangeInclusive::new(map::virt::DMA_HEAP_START, map::virt::DMA_HEAP_END), - translation: Translation::Identity, - attribute_fields: AttributeFields { - mem_attributes: MemAttributes::NonCacheableDRAM, - acc_perms: AccessPermissions::ReadWrite, - execute_never: true, - }, - }, - Descriptor { - name: "Device MMIO", - virtual_range: || RangeInclusive::new(map::physical::MMIO_BASE, map::physical::MMIO_END), - translation: Translation::Identity, - attribute_fields: AttributeFields { - mem_attributes: MemAttributes::Device, - acc_perms: AccessPermissions::ReadWrite, - execute_never: true, - }, - }, -]; - -/// For a given virtual address, find and return the output address and -/// according attributes. -/// -/// If the address is not covered in VIRTUAL_LAYOUT, return a default for normal -/// cacheable DRAM. -fn get_virt_addr_properties(virt_addr: usize) -> Result<(usize, AttributeFields), &'static str> { - if virt_addr > map::END { - return Err("Address out of range."); - } - - for i in KERNEL_VIRTUAL_LAYOUT.iter() { - if (i.virtual_range)().contains(&virt_addr) { - let output_addr = match i.translation { - Translation::Identity => virt_addr, - Translation::Offset(a) => a + (virt_addr - (i.virtual_range)().start()), - }; - - return Ok((output_addr, i.attribute_fields)); - } - } - - Ok((virt_addr, AttributeFields::default())) -} - -/// Human-readable output of a Descriptor. -impl fmt::Display for Descriptor { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - // Call the function to which self.range points, and dereference the - // result, which causes Rust to copy the value. - let start = *(self.virtual_range)().start(); - 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 attr = match self.attribute_fields.mem_attributes { - MemAttributes::CacheableDRAM => "C", - MemAttributes::NonCacheableDRAM => "NC", - MemAttributes::Device => "Dev", - }; - - let acc_p = match self.attribute_fields.acc_perms { - AccessPermissions::ReadOnly => "RO", - AccessPermissions::ReadWrite => "RW", - }; - - 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 - ) - } -} - -/// Print the kernel memory layout. -pub fn print_layout() { - println!("[i] Kernel memory layout:"); - - for i in KERNEL_VIRTUAL_LAYOUT.iter() { - println!("{}", i); - } -} - -/// Calculate the next possible aligned address without sanity checking the -/// input parameters. -#[inline] -fn aligned_addr_unchecked(addr: usize, alignment: usize) -> usize { - (addr + (alignment - 1)) & !(alignment - 1) -} diff --git a/.10_DMA_memory/src/memory/bump_allocator.rs b/.10_DMA_memory/src/memory/bump_allocator.rs deleted file mode 100644 index 0bab4129..00000000 --- a/.10_DMA_memory/src/memory/bump_allocator.rs +++ /dev/null @@ -1,100 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2019 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -use crate::println; -use core::alloc::{Alloc, AllocErr, Layout}; -use core::mem; -use core::ptr::NonNull; -use core::slice; - -pub struct BumpAllocator { - next: usize, - pool_end: usize, - name: &'static str, -} - -unsafe impl Alloc for BumpAllocator { - unsafe fn alloc(&mut self, layout: Layout) -> Result, AllocErr> { - let start = crate::memory::aligned_addr_unchecked(self.next, layout.align()); - let end = start + layout.size(); - - if end <= self.pool_end { - self.next = end; - - println!( - "[i] {}:\n Allocated Addr {:#010X} Size {:#X}", - self.name, - start, - layout.size() - ); - - Ok(NonNull::new_unchecked(start as *mut u8)) - } else { - Err(AllocErr) - } - } - - // A bump allocator doesn't care - unsafe fn dealloc(&mut self, _ptr: NonNull, _layout: Layout) {} -} - -impl BumpAllocator { - pub const fn new(pool_start: usize, pool_end: usize, name: &'static str) -> Self { - Self { - next: pool_start, - pool_end, - name, - } - } - - /// Allocate a zeroed slice - pub fn alloc_slice_zeroed<'a, T>( - &mut self, - count_of_items: usize, - alignment: usize, - ) -> Result<&'a mut [T], ()> { - let l; - let size_in_byte = count_of_items * mem::size_of::(); - match Layout::from_size_align(size_in_byte, alignment) { - Ok(layout) => l = layout, - - Err(_) => { - println!("[e] Layout Error!"); - return Err(()); - } - } - - let ptr; - match unsafe { self.alloc_zeroed(l) } { - Ok(i) => ptr = i.as_ptr(), - - Err(_) => { - println!("[e] Layout Error!"); - return Err(()); - } - } - - Ok(unsafe { slice::from_raw_parts_mut(ptr as *mut T, count_of_items) }) - } -} diff --git a/.10_DMA_memory/src/memory/mmu.rs b/.10_DMA_memory/src/memory/mmu.rs deleted file mode 100644 index aa4e43c6..00000000 --- a/.10_DMA_memory/src/memory/mmu.rs +++ /dev/null @@ -1,349 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2018-2019 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -use crate::memory::{get_virt_addr_properties, AttributeFields}; -use cortex_a::{barrier, regs::*}; -use register::register_bitfields; - -register_bitfields! {u64, - // AArch64 Reference Manual page 2150 - STAGE1_DESCRIPTOR [ - /// Privileged execute-never - PXN OFFSET(53) NUMBITS(1) [ - False = 0, - True = 1 - ], - - /// Various address fields, depending on use case - LVL2_OUTPUT_ADDR_4KiB OFFSET(21) NUMBITS(27) [], // [47:21] - NEXT_LVL_TABLE_ADDR_4KiB OFFSET(12) NUMBITS(36) [], // [47:12] - - /// 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) [ - Block = 0, - Table = 1 - ], - - VALID OFFSET(0) NUMBITS(1) [ - False = 0, - True = 1 - ] - ] -} - -const FOUR_KIB: usize = 4 * 1024; -const FOUR_KIB_SHIFT: usize = 12; // log2(4 * 1024) - -const TWO_MIB: usize = 2 * 1024 * 1024; -const TWO_MIB_SHIFT: usize = 21; // log2(2 * 1024 * 1024) - -/// A descriptor pointing to the next page table. -struct TableDescriptor(register::FieldValue); - -impl TableDescriptor { - fn new(next_lvl_table_addr: usize) -> Result { - if next_lvl_table_addr % FOUR_KIB != 0 { - return Err("TableDescriptor: Address is not 4 KiB aligned."); - } - - let shifted = next_lvl_table_addr >> FOUR_KIB_SHIFT; - - Ok(TableDescriptor( - STAGE1_DESCRIPTOR::VALID::True - + STAGE1_DESCRIPTOR::TYPE::Table - + STAGE1_DESCRIPTOR::NEXT_LVL_TABLE_ADDR_4KiB.val(shifted as u64), - )) - } - - fn value(&self) -> u64 { - self.0.value - } -} - -/// A function that maps the generic memory range attributes to HW-specific -/// attributes of the MMU. -fn into_mmu_attributes( - attribute_fields: AttributeFields, -) -> register::FieldValue { - use crate::memory::{AccessPermissions, MemAttributes}; - - // Memory attributes - let mut desc = match attribute_fields.mem_attributes { - MemAttributes::CacheableDRAM => { - STAGE1_DESCRIPTOR::SH::InnerShareable + STAGE1_DESCRIPTOR::AttrIndx.val(mair::NORMAL) - } - MemAttributes::NonCacheableDRAM => { - STAGE1_DESCRIPTOR::SH::InnerShareable - + STAGE1_DESCRIPTOR::AttrIndx.val(mair::NORMAL_NON_CACHEABLE) - } - MemAttributes::Device => { - STAGE1_DESCRIPTOR::SH::OuterShareable + STAGE1_DESCRIPTOR::AttrIndx.val(mair::DEVICE) - } - }; - - // Access Permissions - desc += match attribute_fields.acc_perms { - AccessPermissions::ReadOnly => STAGE1_DESCRIPTOR::AP::RO_EL1, - AccessPermissions::ReadWrite => STAGE1_DESCRIPTOR::AP::RW_EL1, - }; - - // Execute Never - desc += if attribute_fields.execute_never { - STAGE1_DESCRIPTOR::PXN::True - } else { - STAGE1_DESCRIPTOR::PXN::False - }; - - desc -} - -/// A Level2 block descriptor with 2 MiB aperture. -/// -/// The output points to physical memory. -struct Lvl2BlockDescriptor(register::FieldValue); - -impl Lvl2BlockDescriptor { - fn new( - output_addr: usize, - attribute_fields: AttributeFields, - ) -> Result { - if output_addr % TWO_MIB != 0 { - return Err("BlockDescriptor: Address is not 2 MiB aligned."); - } - - let shifted = output_addr >> TWO_MIB_SHIFT; - - Ok(Lvl2BlockDescriptor( - STAGE1_DESCRIPTOR::VALID::True - + STAGE1_DESCRIPTOR::AF::True - + into_mmu_attributes(attribute_fields) - + STAGE1_DESCRIPTOR::TYPE::Block - + STAGE1_DESCRIPTOR::LVL2_OUTPUT_ADDR_4KiB.val(shifted as u64), - )) - } - - fn value(&self) -> u64 { - self.0.value - } -} - -/// A page descriptor with 4 KiB aperture. -/// -/// The output points to physical memory. -struct PageDescriptor(register::FieldValue); - -impl PageDescriptor { - fn new( - output_addr: usize, - attribute_fields: AttributeFields, - ) -> Result { - if output_addr % FOUR_KIB != 0 { - return Err("PageDescriptor: Address is not 4 KiB aligned."); - } - - let shifted = output_addr >> FOUR_KIB_SHIFT; - - Ok(PageDescriptor( - STAGE1_DESCRIPTOR::VALID::True - + STAGE1_DESCRIPTOR::AF::True - + into_mmu_attributes(attribute_fields) - + STAGE1_DESCRIPTOR::TYPE::Table - + STAGE1_DESCRIPTOR::NEXT_LVL_TABLE_ADDR_4KiB.val(shifted as u64), - )) - } - - fn value(&self) -> u64 { - self.0.value - } -} - -/// Constants for indexing the MAIR_EL1. -#[allow(dead_code)] -mod mair { - pub const DEVICE: u64 = 0; - pub const NORMAL: u64 = 1; - pub const NORMAL_NON_CACHEABLE: u64 = 2; -} - -/// Setup function for the MAIR_EL1 register. -fn set_up_mair() { - // Define the three memory types that we will map. Cacheable and - // non-cacheable normal DRAM, and device. - MAIR_EL1.write( - // Attribute 2 - MAIR_EL1::Attr2_HIGH::Memory_OuterNonCacheable - + MAIR_EL1::Attr2_LOW_MEMORY::InnerNonCacheable - - // Attribute 1 - + MAIR_EL1::Attr1_HIGH::Memory_OuterWriteBack_NonTransient_ReadAlloc_WriteAlloc - + MAIR_EL1::Attr1_LOW_MEMORY::InnerWriteBack_NonTransient_ReadAlloc_WriteAlloc - - // Attribute 0 - + MAIR_EL1::Attr0_HIGH::Device - + MAIR_EL1::Attr0_LOW_DEVICE::Device_nGnRE, - ); -} - -trait BaseAddr { - fn base_addr_u64(&self) -> u64; - fn base_addr_usize(&self) -> usize; -} - -impl BaseAddr for [u64; 512] { - fn base_addr_u64(&self) -> u64 { - self as *const u64 as u64 - } - - fn base_addr_usize(&self) -> usize { - self as *const u64 as usize - } -} - -const NUM_ENTRIES_4KIB: usize = 512; - -// A wrapper struct is needed here so that the align attribute can be used. -#[repr(C)] -#[repr(align(4096))] -struct PageTable { - entries: [u64; NUM_ENTRIES_4KIB], -} - -/// The LVL2 page table containng the 2 MiB entries. -static mut LVL2_TABLE: PageTable = PageTable { - entries: [0; NUM_ENTRIES_4KIB], -}; - -/// The LVL3 page table containing the 4 KiB entries. -/// -/// The first entry of the LVL2_TABLE will forward to this table. -static mut LVL3_TABLE: PageTable = PageTable { - entries: [0; NUM_ENTRIES_4KIB], -}; - -/// Set up identity mapped page tables for the first 1 GiB of address space. -/// -/// The first 2 MiB are 4 KiB granule, the rest 2 MiB. -/// -/// # Safety -/// -/// - User must ensure that the hardware supports the paremeters being set here. -pub unsafe fn init() -> Result<(), &'static str> { - // Prepare the memory attribute indirection register. - set_up_mair(); - - // Point the first 2 MiB of virtual addresses to the follow-up LVL3 - // page-table. - LVL2_TABLE.entries[0] = match TableDescriptor::new(LVL3_TABLE.entries.base_addr_usize()) { - Err(s) => return Err(s), - Ok(d) => d.value(), - }; - - // Fill the rest of the LVL2 (2 MiB) entries as block descriptors. - // - // Notice the skip(1) which makes the iteration start at the second 2 MiB - // block (0x20_0000). - for (block_descriptor_nr, entry) in LVL2_TABLE.entries.iter_mut().enumerate().skip(1) { - let virt_addr = block_descriptor_nr << TWO_MIB_SHIFT; - - let (output_addr, attribute_fields) = match get_virt_addr_properties(virt_addr) { - Err(s) => return Err(s), - Ok((a, b)) => (a, b), - }; - - let block_desc = match Lvl2BlockDescriptor::new(output_addr, attribute_fields) { - Err(s) => return Err(s), - Ok(desc) => desc, - }; - - *entry = block_desc.value(); - } - - // Finally, fill the single LVL3 table (4 KiB granule). - for (page_descriptor_nr, entry) in LVL3_TABLE.entries.iter_mut().enumerate() { - let virt_addr = page_descriptor_nr << FOUR_KIB_SHIFT; - - let (output_addr, attribute_fields) = match get_virt_addr_properties(virt_addr) { - Err(s) => return Err(s), - Ok((a, b)) => (a, b), - }; - - let page_desc = match PageDescriptor::new(output_addr, attribute_fields) { - Err(s) => return Err(s), - Ok(desc) => desc, - }; - - *entry = page_desc.value(); - } - - // Point to the LVL2 table base address in TTBR0. - TTBR0_EL1.set_baddr(LVL2_TABLE.entries.base_addr_u64()); - - // Configure various settings of stage 1 of the EL1 translation regime. - let ips = ID_AA64MMFR0_EL1.read(ID_AA64MMFR0_EL1::PARange); - TCR_EL1.write( - TCR_EL1::TBI0::Ignored - + TCR_EL1::IPS.val(ips) - + TCR_EL1::TG0::KiB_4 // 4 KiB granule - + TCR_EL1::SH0::Inner - + TCR_EL1::ORGN0::WriteBack_ReadAlloc_WriteAlloc_Cacheable - + TCR_EL1::IRGN0::WriteBack_ReadAlloc_WriteAlloc_Cacheable - + TCR_EL1::EPD0::EnableTTBR0Walks - + TCR_EL1::T0SZ.val(34), // Start walks at level 2 - ); - - // 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(()) -} diff --git a/.10_DMA_memory/src/sync.rs b/.10_DMA_memory/src/sync.rs deleted file mode 100644 index 3cbc1714..00000000 --- a/.10_DMA_memory/src/sync.rs +++ /dev/null @@ -1,51 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2019 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -use core::cell::UnsafeCell; - -pub struct NullLock { - data: UnsafeCell, -} - -unsafe impl Sync for NullLock {} - -impl NullLock { - pub const fn new(data: T) -> NullLock { - NullLock { - data: UnsafeCell::new(data), - } - } -} - -impl NullLock { - pub fn lock(&self, f: F) -> R - where - F: FnOnce(&mut T) -> R, - { - // In a real lock, there would be code around this line that ensures - // that this mutable reference will ever only be given out one at a - // time. - f(unsafe { &mut *self.data.get() }) - } -} diff --git a/.11_exceptions_groundwork/.cargo/config b/.11_exceptions_groundwork/.cargo/config deleted file mode 100644 index de3f84c9..00000000 --- a/.11_exceptions_groundwork/.cargo/config +++ /dev/null @@ -1,5 +0,0 @@ -[target.aarch64-unknown-none-softfloat] -rustflags = [ - "-C", "link-arg=-Tlink.ld", - "-C", "target-cpu=cortex-a53", -] diff --git a/.11_exceptions_groundwork/Cargo.lock b/.11_exceptions_groundwork/Cargo.lock deleted file mode 100644 index d218ad56..00000000 --- a/.11_exceptions_groundwork/Cargo.lock +++ /dev/null @@ -1,57 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -[[package]] -name = "cortex-a" -version = "2.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "register 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "kernel8" -version = "0.1.0" -dependencies = [ - "cortex-a 2.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "raspi3_boot 0.1.0", - "register 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "panic-abort" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "r0" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "raspi3_boot" -version = "0.1.0" -dependencies = [ - "cortex-a 2.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "panic-abort 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "r0 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "register" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "tock-registers 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tock-registers" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[metadata] -"checksum cortex-a 2.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cbb16c411ab74044f174746a6cbae67bcdebea126e376b5441e5986e6a6aa950" -"checksum panic-abort 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2c14a66511ed17b6a8b4256b868d7fd207836d891db15eea5195dbcaf87e630f" -"checksum r0 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e2a38df5b15c8d5c7e8654189744d8e396bddc18ad48041a500ce52d6948941f" -"checksum register 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "469bb5ddde81d67fb8bba4e14d77689b8166cfd077abe7530591cefe29d05823" -"checksum tock-registers 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c758f5195a2e0df9d9fecf6f506506b2766ff74cf64db1e995c87e2761a5c3e2" diff --git a/.11_exceptions_groundwork/Cargo.toml b/.11_exceptions_groundwork/Cargo.toml deleted file mode 100644 index 43d1e22e..00000000 --- a/.11_exceptions_groundwork/Cargo.toml +++ /dev/null @@ -1,13 +0,0 @@ -[package] -name = "kernel8" -version = "0.1.0" -authors = ["Andre Richter "] -edition = "2018" - -[dependencies] -raspi3_boot = { path = "raspi3_boot" } -cortex-a = "2.7.0" -register = "0.3.3" - -[package.metadata.cargo-xbuild] -sysroot_path = "../xbuild_sysroot" diff --git a/.11_exceptions_groundwork/Makefile b/.11_exceptions_groundwork/Makefile deleted file mode 100644 index 72d854de..00000000 --- a/.11_exceptions_groundwork/Makefile +++ /dev/null @@ -1,104 +0,0 @@ -# -# MIT License -# -# Copyright (c) 2018-2019 Andre Richter -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# - -TARGET = aarch64-unknown-none-softfloat - -SOURCES = $(wildcard **/*.rs) $(wildcard **/*.S) link.ld - - -XRUSTC_CMD = cargo xrustc --target=$(TARGET) --release -CARGO_OUTPUT = target/$(TARGET)/release/kernel8 - -OBJCOPY = cargo objcopy -- -OBJCOPY_PARAMS = --strip-all -O binary - -CONTAINER_UTILS = andrerichter/raspi3-utils -CONTAINER_OPENOCD = andrerichter/raspi3-openocd -# CONTAINER_OPENOCD_ARG = -f openocd/tcl/interface/ftdi/olimex-jtag-tiny.cfg -f /openocd/rpi3.cfg -CONTAINER_GDB = andrerichter/raspi3-gdb - -DOCKER_CMD = docker run -it --rm -DOCKER_ARG_CURDIR = -v $(shell pwd):/work -w /work -DOCKER_ARG_TTY = --privileged -v /dev:/dev -DOCKER_ARG_JTAG = -v $(shell pwd)/../X1_JTAG_boot:/jtag -DOCKER_ARG_NET = --network host -DOCKER_ARG_EMU = -v $(shell pwd)/../emulation:/emulation - -DOCKER_EXEC_QEMU = bash /emulation/qemu_multi_uart.sh -DOCKER_EXEC_RASPBOOT = raspbootcom -DOCKER_EXEC_RASPBOOT_DEV = /dev/ttyUSB0 -# DOCKER_EXEC_RASPBOOT_DEV = /dev/ttyACM0 - -.PHONY: all qemu raspboot clippy clean objdump nm jtagboot openocd gdb gdb-opt0 - -all: clean kernel8.img - -$(CARGO_OUTPUT): $(SOURCES) - $(XRUSTC_CMD) - -kernel8.img: $(CARGO_OUTPUT) - cp $< . - $(OBJCOPY) $(OBJCOPY_PARAMS) $< kernel8.img - -qemu: all - $(DOCKER_CMD) $(DOCKER_ARG_CURDIR) $(DOCKER_ARG_EMU) \ - $(CONTAINER_UTILS) $(DOCKER_EXEC_QEMU) - -raspboot: all - $(DOCKER_CMD) $(DOCKER_ARG_CURDIR) $(DOCKER_ARG_TTY) \ - $(CONTAINER_UTILS) $(DOCKER_EXEC_RASPBOOT) \ - $(DOCKER_EXEC_RASPBOOT_DEV) kernel8.img - -clippy: - cargo xclippy --target=$(TARGET) - -clean: - cargo clean - -objdump: - cargo objdump --target $(TARGET) -- -disassemble -print-imm-hex kernel8 - -nm: - cargo nm --target $(TARGET) -- kernel8 | sort - -jtagboot: - $(DOCKER_CMD) $(DOCKER_ARG_TTY) $(DOCKER_ARG_JTAG) $(CONTAINER_UTILS) \ - $(DOCKER_EXEC_RASPBOOT) $(DOCKER_EXEC_RASPBOOT_DEV) /jtag/jtag_boot.img - -openocd: - $(DOCKER_CMD) $(DOCKER_ARG_TTY) $(DOCKER_ARG_NET) $(CONTAINER_OPENOCD) \ - $(CONTAINER_OPENOCD_ARG) - -define gen_gdb - $(XRUSTC_CMD) -- $1 - cp $(CARGO_OUTPUT) kernel8_for_jtag - $(DOCKER_CMD) $(DOCKER_ARG_CURDIR) $(DOCKER_ARG_NET) $(CONTAINER_GDB) \ - gdb-multiarch -q kernel8_for_jtag -endef - -gdb: clean $(SOURCES) - $(call gen_gdb,-C debuginfo=2) - -gdb-opt0: clean $(SOURCES) - $(call gen_gdb,-C debuginfo=2 -C opt-level=0) diff --git a/.11_exceptions_groundwork/README.md b/.11_exceptions_groundwork/README.md deleted file mode 100644 index 1f25325d..00000000 --- a/.11_exceptions_groundwork/README.md +++ /dev/null @@ -1,292 +0,0 @@ -# Tutorial 11 - Exceptions: Groundwork - - -In this tutorial, we lay the groundwork for taking exceptions, and write a very bare-bones handler for a synchronous exception that happens in `EL1`. - -More tutorials on exceptions will follow, implementing and introducing various other aspects of this rather huge topic. - -## Exception Types - -In `AArch64`, it is differentiated between four types of exceptions. These are: -- Synchronous - - For example, a `data abort` or a `system call`. They happen in direct consequence of executing a certain instruction, hence _synchronously_. -- Interrupt Request (`IRQ`) - - For example, an external device, like a timer, is asserting a physical interrupt line. IRQs happen _asynchronously_. -- Fast Interrupt Request (`FIQ`) - - These are basically interrupts that take priority over normal IRQs and have some more traits that make them suitable to implement super-fast processing. However, this is out of scope for this tutorial. For the sake of keeping these tutorials compact and concise, we will more or less ignore FIQs and only implement a dummy handler that would halt the CPU core. -- System Error (`SError`) - - Like IRQs, SErrors happen asynchronously and are technically more or less the same. They are intended to signal rather fatal errors in the system, e.g. if a transaction times out on the `SoC` interconnect. They are highly implementation specific and it is up to the SoC designer to decide which events are delivered as SErrors instead of normal IRQs. - -## Exception entry - -We recommend to read pages 1874-1876 of the [ARMv8 Architecture Reference Manual][ARMv8_Manual] to understand the mechanisms of taking an exception. - -Here's an excerpt of important features for this tutorial: -- Exception entry moves the processor to the same or a higher `Exception Level`, but never to a lower `EL`. -- The program status is saved in the `SPSR_ELx` register at the target `EL`. -- The preferred return address is saved in the `ELR_ELx` register. - - "Preferred" here means that `ELR_ELx` may hold the instruction address of the instructions that caused the exception (`synchronous case`) or the first instruction that did not complete due to an `asynchronous` exception. Details in Chapter D1.10.1 of the [ARMv8 Architecture Reference Manual][ARMv8_Manual]. -- All kinds of exceptions are turned off upon taking an exception, so that by default exception handlers can not get interrupted themselves. -- Taking an exception will select the dedicated stack pointer of the target `EL`. - - For example, if an exception in `EL0` is taken, the Stack Pointer Select register `SPSel` will switch from `0` to `1`, meaning that `SP_EL1` will be used by the exception vector code unless you explicitly change it back to `SP_EL0`. - - -### Exception Vectors - -`AArch64` has a total of 16 exception vectors. There is one for each of the four kinds that were introduced already, and additionally, it is taken into account _where_ the exception was taken from and what the circumstances were. - -Here is a copy of the decision table as shown in Chapter D1.10.2 of the [ARMv8 Architecture Reference Manual][ARMv8_Manual]: - -[ARMv8_Manual]: https://developer.arm.com/docs/ddi0487/latest/arm-architecture-reference-manual-armv8-for-armv8-a-architecture-profile - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    Exception taken from Offset for exception type
    SynchronousIRQ or vIRQFIQ or vFIQSError or vSError
    Current Exception level with SP_EL0.0x0000x0800x1000x180
    Current Exception level with SP_ELx, x>0.0x2000x2800x3000x380
    Lower Exception level, where the implemented level immediately lower than the target level is using AArch64.0x4000x4800x5000x580
    Lower Exception level, where the implemented level immediately lower than the target level is using AArch32.0x6000x6800x7000x780
    - -Since our bare-metal Raspberry code operates in `EL1` using `SP_EL1`, if we'd cause a synchronous exception, the exception vector at offset `0x200` would be executed. But what does that even mean? - -## Handler Code and Offsets - -In many architectures, Operating Systems register their exception handlers (aka vectors) by compiling an architecturally defined data structure that stores function pointers to the different handlers. This can be as simple as an ordinary array of function pointers. The `base address` of this data structure is then stored into a special purpose register so that the CPU can branch to the respective handler function upon taking an exception. The famous `x86_64` architecture follows this principle, for example. - -In `AArch64`, it is a bit different. Here, we have the special purpose register as well, called `VBAR_EL1`: Vector Base Address Register. - -However, it does not store the base address of an array of function pointers, but the base address of a **memory location that contains code** for the 16 handlers, one handler back-to-back after the other. Each handler can take a maximum space of `0x80` bytes, aka 128 bytes. That's why the table above shows `offsets`: To indicate at which offset a certain handler starts. - -Of course, you are not obliged to cram all your handler code into only 128 bytes. You are free to branch off to any other functions at any time. Actually, that is needed in most cases anyways, because the context-saving code alone would take up most of the available space (You'll learn about what context saving is shortly). - -Additionally, there is a requirement that the `Vector Base Address` is aligned to `0x800` aka 2048 bytes. - -## Rust Implementation - -We start by adding a new section to the `link.ld` script, which will contain the exception vector code: - -```rust -SECTIONS -{ - .vectors ALIGN(2048): - { - *(.vectors) - } -``` - -### Context Save and Restore - -Exception vectors, just like any other code, use a bunch of commonly shared processor resources. Most of all, the set of `General Purpose Registers` (GPRs) that each core in `AArch64` provides (`X0`-`X30`). - -In order to not taint these registers when executing exception vector code, it is general practice to save these shared resources in memory (the stack, to be precise) as the very first action. This is commonly described as *saving the context*. Exception vector code can then use the shared resources in its own code without bothering, and as a last action before returning from exception handling code, restore the context, so that the processor can continue where it left off before taking the exception. - -Context save and restore is one of the few places in system software where it is strongly advised to to use some hand-crafted assembly. Introducing `vectors.S`: - -```asm -.macro SAVE_CONTEXT_CALL_HANDLER_AND_RESTORE handler -.balign 0x80 - - sub sp, sp, #16 * 17 - - 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] - - mrs x1, SPSR_EL1 - mrs x2, ELR_EL1 - - stp x30, x1, [sp, #16 * 15] - str x2, [sp, #16 * 16] - - mov x0, sp - bl \handler - b __restore_context -.endm -``` - -First, a macro for saving the context, branching to follow-up handler code, and finally restoring the context. In advance, we reserve space on the stack for the context. That is, the 30 `GPRs` as well as the `saved program status` and the `exception link register` (holding the preferred return address). Afterwards, we store those registers, save the current stack address in `X0` and branch off to follow-up handler-code, whose function name is supplied as an argument to the macro. - -The handler code will be written in Rust, but use the platform's `C` ABI. This way, we can define a function signature that has a pointer to the context-data on the stack as its first argument, and know that this argument is expected to be in the `X0` register. We need to use the `C` ABI here because `Rust` has no stable convention ([yet](https://github.com/rust-lang/rfcs/issues/600)). - -Also note the `.balign 0x80` which ensure that the code is aligned properly according to the table shown earlier. - -### Exception Vector Code - -Next, we populate the `.vectors` section of the linker script using our macro (except for the FIQ vectors, for which we insert code that halts the CPU (via another macro): - -```asm -.section .vectors, "ax" -.global __exception_vectors_start -__exception_vectors_start: - SAVE_CONTEXT_CALL_HANDLER_AND_RESTORE current_el0_synchronous // 0x000 - SAVE_CONTEXT_CALL_HANDLER_AND_RESTORE current_el0_irq // 0x080 - FIQ_DUMMY // 0x100 - SAVE_CONTEXT_CALL_HANDLER_AND_RESTORE current_el0_serror // 0x180 - - SAVE_CONTEXT_CALL_HANDLER_AND_RESTORE current_elx_synchronous // 0x200 - SAVE_CONTEXT_CALL_HANDLER_AND_RESTORE current_elx_irq // 0x280 - FIQ_DUMMY // 0x300 - SAVE_CONTEXT_CALL_HANDLER_AND_RESTORE current_elx_serror // 0x380 - - SAVE_CONTEXT_CALL_HANDLER_AND_RESTORE lower_aarch64_synchronous // 0x400 - SAVE_CONTEXT_CALL_HANDLER_AND_RESTORE lower_aarch64_irq // 0x480 - FIQ_DUMMY // 0x500 - SAVE_CONTEXT_CALL_HANDLER_AND_RESTORE lower_aarch64_serror // 0x580 - - SAVE_CONTEXT_CALL_HANDLER_AND_RESTORE lower_aarch32_synchronous // 0x600 - SAVE_CONTEXT_CALL_HANDLER_AND_RESTORE lower_aarch32_irq // 0x680 - FIQ_DUMMY // 0x700 - SAVE_CONTEXT_CALL_HANDLER_AND_RESTORE lower_aarch32_serror // 0x780 -``` - -This part introduces various handler function names, which we can now implement using `Rust`. - -### Implementing a handler - -In `exception.rs`, we implement a handler for a synchronous exception that that will happen in `EL1` using `SP_EL1`: - -```rust -#[no_mangle] -unsafe extern "C" fn current_elx_synchronous(e: &mut ExceptionContext) { - println!("[!] A synchronous exception happened."); - println!(" ELR_EL1: {:#010X}", e.elr_el1); - println!( - " Incrementing ELR_EL1 by 4 now to continue with the first \ - instruction after the exception!" - ); - - e.elr_el1 += 4; - - println!(" ELR_EL1 modified: {:#010X}", e.elr_el1); - println!(" Returning from exception...\n"); -} -``` - -The function takes a `struct ExceptionContext` argument, which resembles what we put on the stack before branching to the handler: - -```rust -#[repr(C)] -pub struct GPR { - x: [u64; 31], -} - -#[repr(C)] -pub struct ExceptionContext { - // General Purpose Registers - gpr: GPR, - spsr_el1: u64, - elr_el1: u64, -} -``` - -Inside the function, for demo purposes, we advance the copy of the `ELR` by 4, which makes it point to the next instruction after the instruction that caused the exception. -When the function returns, execution continues in the assembly macro we introduced before. The macro has only one more line left: `b __restore_context`, which jumps to an assembly function that plays back our saved context before finally executing `eret` to return from the exception. - -#### Default handler - -In order to spare the work of implementing each and every handler, we define an `extern "C" fn default_exception_handler()`. Using the linker script, we take a shortcut and make all the other handlers point to this function code if it is not implemented explicitly anywhere else: - -```rust -PROVIDE(current_el0_synchronous = default_exception_handler); -PROVIDE(current_el0_irq = default_exception_handler); -PROVIDE(current_el0_serror = default_exception_handler); - -...(Many more omitted) -``` - -## Causing an Exception - Testing the Code - -After pointing `VBAR_EL1` to our vector code, - -```rust -exception::set_vbar_el1_checked(exception_vectors_start) -``` -which enables exception handling, we cause a data abort exception by reading from memory address `3 GiB`: - -```rust -let big_addr: u64 = 3 * 1024 * 1024 * 1024; -unsafe { core::ptr::read_volatile(big_addr as *mut u64) }; -``` - -Finally, this triggers our exception code, because we try to read from a virtual address for which no address translations have been installed. Remember, we only installed identity-mapped page tables for the first 1 GiB of address space in lesson `0D`. -After the exception handler is finished, it returns to the first instruction -after the memory read that caused the exception. - -## Output - -```console -ferris@box:~$ make raspboot - -[0] MiniUart online. -[1] Press a key to continue booting... Greetings fellow Rustacean! -[2] MMU online. -[i] Kernel memory layout: - 0x00000000 - 0x0007FFFF | 512 KiB | C RW PXN | Kernel stack - 0x00080000 - 0x00084FFF | 20 KiB | C RO PX | Kernel code and RO data - 0x00085000 - 0x0008800F | 12 KiB | C RW PXN | Kernel data and BSS - 0x00200000 - 0x005FFFFF | 4 MiB | NC RW PXN | DMA heap pool - 0x3F000000 - 0x3FFFFFFF | 16 MiB | Dev RW PXN | Device MMIO -[i] Global DMA Allocator: - Allocated Addr 0x00200000 Size 0x90 -[3] Videocore Mailbox set up (DMA mem heap allocation successful). -[4] PL011 UART online. Output switched to it. -[5] Exception vectors are set up. -[!] A synchronous exception happened. - ELR_EL1: 0x00080C20 - Incrementing ELR_EL1 by 4 now to continue with the first instruction after the exception! - ELR_EL1 modified: 0x00080C24 - Returning from exception... - -[i] Whoa! We recovered from an exception. - -$> -``` diff --git a/.11_exceptions_groundwork/kernel8 b/.11_exceptions_groundwork/kernel8 deleted file mode 100755 index ef99bf7d71d78d0fb53931ba2b4cbf616cebef36..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 103224 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

    P=P8G~HygtvCZ-z_Swkrk=%B+*8kD05%M@@TB)) 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 diff --git a/.11_exceptions_groundwork/link.ld b/.11_exceptions_groundwork/link.ld deleted file mode 100644 index 00bb9b46..00000000 --- a/.11_exceptions_groundwork/link.ld +++ /dev/null @@ -1,78 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2018 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -ENTRY(_boot_cores); - -SECTIONS -{ - . = 0x80000; /* This is already 4KiB aligned */ - __ro_start = .; - .text : - { - KEEP(*(.text.boot)) *(.text .text.*) - } - - .vectors ALIGN(2048): - { - *(.vectors) - } - - .rodata : - { - *(.rodata .rodata.*) - } - . = ALIGN(4096); /* Fill up to 4KiB */ - __ro_end = .; - - .data : - { - *(.data .data.*) - } - - .bss ALIGN(8): - { - __bss_start = .; - *(.bss .bss.*) - *(COMMON) - __bss_end = .; - } - - /DISCARD/ : { *(.comment) *(.gnu*) *(.note*) *(.eh_frame*) } -} - -PROVIDE(current_el0_synchronous = default_exception_handler); -PROVIDE(current_el0_irq = default_exception_handler); -PROVIDE(current_el0_serror = default_exception_handler); - -PROVIDE(current_elx_synchronous = default_exception_handler); -PROVIDE(current_elx_irq = default_exception_handler); -PROVIDE(current_elx_serror = default_exception_handler); - -PROVIDE(lower_aarch64_synchronous = default_exception_handler); -PROVIDE(lower_aarch64_irq = default_exception_handler); -PROVIDE(lower_aarch64_serror = default_exception_handler); - -PROVIDE(lower_aarch32_synchronous = default_exception_handler); -PROVIDE(lower_aarch32_irq = default_exception_handler); -PROVIDE(lower_aarch32_serror = default_exception_handler); diff --git a/.11_exceptions_groundwork/raspi3_boot/Cargo.lock b/.11_exceptions_groundwork/raspi3_boot/Cargo.lock deleted file mode 100644 index 7428c6de..00000000 --- a/.11_exceptions_groundwork/raspi3_boot/Cargo.lock +++ /dev/null @@ -1,46 +0,0 @@ -[[package]] -name = "cortex-a" -version = "2.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "register 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "panic-abort" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "r0" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "raspi3_boot" -version = "0.1.0" -dependencies = [ - "cortex-a 2.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "panic-abort 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "r0 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "register" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "tock-registers 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tock-registers" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[metadata] -"checksum cortex-a 2.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "97867bac786c0a2912f7df981bdb8b6ea109a2422c22b37faf651d558a054453" -"checksum panic-abort 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2c14a66511ed17b6a8b4256b868d7fd207836d891db15eea5195dbcaf87e630f" -"checksum r0 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e2a38df5b15c8d5c7e8654189744d8e396bddc18ad48041a500ce52d6948941f" -"checksum register 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a0f44a6dc9a98359515541a0c46ef4e3630a30879c1d7a4038f31dd533570bfb" -"checksum tock-registers 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c758f5195a2e0df9d9fecf6f506506b2766ff74cf64db1e995c87e2761a5c3e2" diff --git a/.11_exceptions_groundwork/raspi3_boot/Cargo.toml b/.11_exceptions_groundwork/raspi3_boot/Cargo.toml deleted file mode 100644 index 024fd184..00000000 --- a/.11_exceptions_groundwork/raspi3_boot/Cargo.toml +++ /dev/null @@ -1,10 +0,0 @@ -[package] -name = "raspi3_boot" -version = "0.1.0" -authors = ["Andre Richter "] -edition = "2018" - -[dependencies] -cortex-a = "2.7.0" -panic-abort = "0.3.1" -r0 = "0.2.2" diff --git a/.11_exceptions_groundwork/raspi3_boot/src/lib.rs b/.11_exceptions_groundwork/raspi3_boot/src/lib.rs deleted file mode 100644 index 01ccd956..00000000 --- a/.11_exceptions_groundwork/raspi3_boot/src/lib.rs +++ /dev/null @@ -1,141 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2018 Jorge Aparicio - * Copyright (c) 2018-2019 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#![deny(missing_docs)] -#![deny(warnings)] -#![no_std] - -//! Low-level boot of the Raspberry's processor - -extern crate panic_abort; - -/// Type check the user-supplied entry function. -#[macro_export] -macro_rules! entry { - ($path:path) => { - /// # Safety - /// - /// - User must ensure to provide a suitable main function for the - /// platform. - #[export_name = "main"] - pub unsafe fn __main() -> ! { - // type check the given path - let f: fn() -> ! = $path; - - f() - } - }; -} - -/// Reset function. -/// -/// Initializes the bss section before calling into the user's `main()`. -/// -/// # Safety -/// -/// - Only a single core must be active and running this function. -unsafe fn reset() -> ! { - extern "C" { - // Boundaries of the .bss section, provided by the linker script - static mut __bss_start: u64; - static mut __bss_end: u64; - } - - // Zeroes the .bss section - r0::zero_bss(&mut __bss_start, &mut __bss_end); - - extern "Rust" { - fn main() -> !; - } - - main() -} - -/// Prepare and execute transition from EL2 to EL1. -#[inline] -fn setup_and_enter_el1_from_el2() -> ! { - use cortex_a::{asm, regs::*}; - - const STACK_START: u64 = 0x80_000; - - // 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 reset(). - ELR_EL2.set(reset as *const () as u64); - - // Set up SP_EL1 (stack pointer), which will be used by EL1 once - // we "return" to it. - SP_EL1.set(STACK_START); - - // Use `eret` to "return" to EL1. This will result in execution of - // `reset()` in EL1. - asm::eret() -} - -/// Entrypoint of the processor. -/// -/// Parks all cores except core0 and checks if we started in EL2. If -/// so, proceeds with setting up EL1. -/// -/// # Safety -/// -/// - Linker script must ensure to place this function at `0x80_000`. -#[link_section = ".text.boot"] -#[no_mangle] -pub unsafe extern "C" fn _boot_cores() -> ! { - use cortex_a::{asm, regs::*}; - - const CORE_0: u64 = 0; - const CORE_MASK: u64 = 0x3; - const EL2: u32 = CurrentEL::EL::EL2.value; - - if (CORE_0 == MPIDR_EL1.get() & CORE_MASK) && (EL2 == CurrentEL.get()) { - setup_and_enter_el1_from_el2() - } - - // if not core0 or EL != 2, infinitely wait for events - loop { - asm::wfe(); - } -} diff --git a/.11_exceptions_groundwork/src/delays.rs b/.11_exceptions_groundwork/src/delays.rs deleted file mode 100644 index b1c1fa0f..00000000 --- a/.11_exceptions_groundwork/src/delays.rs +++ /dev/null @@ -1,37 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2018-2019 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -use cortex_a::asm; - -/* - * - * Using the CPU's cycles - * - */ -/// Wait N CPU cycles (ARM CPU only) -pub fn wait_cycles(cyc: u32) { - for _ in 0..cyc { - asm::nop(); - } -} diff --git a/.11_exceptions_groundwork/src/devices.rs b/.11_exceptions_groundwork/src/devices.rs deleted file mode 100644 index 227b92c2..00000000 --- a/.11_exceptions_groundwork/src/devices.rs +++ /dev/null @@ -1,26 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2019 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -pub mod hw; -pub mod virt; diff --git a/.11_exceptions_groundwork/src/devices/hw.rs b/.11_exceptions_groundwork/src/devices/hw.rs deleted file mode 100644 index 08a6c06c..00000000 --- a/.11_exceptions_groundwork/src/devices/hw.rs +++ /dev/null @@ -1,33 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2019 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -mod gpio; -mod mini_uart; -mod pl011_uart; -mod videocore_mbox; - -pub use gpio::GPIO; -pub use mini_uart::MiniUart; -pub use pl011_uart::PL011Uart; -pub use videocore_mbox::VideocoreMbox; diff --git a/.11_exceptions_groundwork/src/devices/hw/gpio.rs b/.11_exceptions_groundwork/src/devices/hw/gpio.rs deleted file mode 100644 index 7affea08..00000000 --- a/.11_exceptions_groundwork/src/devices/hw/gpio.rs +++ /dev/null @@ -1,120 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2018-2019 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -use core::ops; -use register::{mmio::ReadWrite, register_bitfields}; - -// Descriptions taken from -// https://github.com/raspberrypi/documentation/files/1888662/BCM2837-ARM-Peripherals.-.Revised.-.V2-1.pdf -register_bitfields! { - u32, - - /// GPIO Function Select 1 - GPFSEL1 [ - /// Pin 15 - FSEL15 OFFSET(15) NUMBITS(3) [ - Input = 0b000, - Output = 0b001, - RXD0 = 0b100, // UART0 - Alternate function 0 - RXD1 = 0b010 // Mini UART - Alternate function 5 - - ], - - /// Pin 14 - FSEL14 OFFSET(12) NUMBITS(3) [ - Input = 0b000, - Output = 0b001, - TXD0 = 0b100, // UART0 - Alternate function 0 - TXD1 = 0b010 // Mini UART - Alternate function 5 - ] - ], - - /// GPIO Pull-up/down Clock Register 0 - GPPUDCLK0 [ - /// Pin 15 - PUDCLK15 OFFSET(15) NUMBITS(1) [ - NoEffect = 0, - AssertClock = 1 - ], - - /// Pin 14 - PUDCLK14 OFFSET(14) NUMBITS(1) [ - NoEffect = 0, - AssertClock = 1 - ] - ] -} - -#[allow(non_snake_case)] -#[repr(C)] -pub struct RegisterBlock { - pub GPFSEL0: ReadWrite, // 0x00 - pub GPFSEL1: ReadWrite, // 0x04 - pub GPFSEL2: ReadWrite, // 0x08 - pub GPFSEL3: ReadWrite, // 0x0C - pub GPFSEL4: ReadWrite, // 0x10 - pub GPFSEL5: ReadWrite, // 0x14 - __reserved_0: u32, // 0x18 - GPSET0: ReadWrite, // 0x1C - GPSET1: ReadWrite, // 0x20 - __reserved_1: u32, // - GPCLR0: ReadWrite, // 0x28 - __reserved_2: [u32; 2], // - GPLEV0: ReadWrite, // 0x34 - GPLEV1: ReadWrite, // 0x38 - __reserved_3: u32, // - GPEDS0: ReadWrite, // 0x40 - GPEDS1: ReadWrite, // 0x44 - __reserved_4: [u32; 7], // - GPHEN0: ReadWrite, // 0x64 - GPHEN1: ReadWrite, // 0x68 - __reserved_5: [u32; 10], // - pub GPPUD: ReadWrite, // 0x94 - pub GPPUDCLK0: ReadWrite, // 0x98 - pub GPPUDCLK1: ReadWrite, // 0x9C -} - -/// Public interface to the GPIO MMIO area -pub struct GPIO { - base_addr: usize, -} - -impl ops::Deref for GPIO { - type Target = RegisterBlock; - - fn deref(&self) -> &Self::Target { - unsafe { &*self.ptr() } - } -} - -impl GPIO { - pub fn new(base_addr: usize) -> GPIO { - GPIO { base_addr } - } - - /// Returns a pointer to the register block - fn ptr(&self) -> *const RegisterBlock { - self.base_addr as *const _ - } -} diff --git a/.11_exceptions_groundwork/src/devices/hw/mini_uart.rs b/.11_exceptions_groundwork/src/devices/hw/mini_uart.rs deleted file mode 100644 index f98b06bf..00000000 --- a/.11_exceptions_groundwork/src/devices/hw/mini_uart.rs +++ /dev/null @@ -1,266 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2018-2019 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -use super::gpio; -use crate::devices::virt::ConsoleOps; -use core::ops; -use cortex_a::asm; -use register::{mmio::*, register_bitfields}; - -// Auxilary mini UART registers -// -// Descriptions taken from -// https://github.com/raspberrypi/documentation/files/1888662/BCM2837-ARM-Peripherals.-.Revised.-.V2-1.pdf -register_bitfields! { - u32, - - /// Auxiliary enables - AUX_ENABLES [ - /// If set the mini UART is enabled. The UART will immediately - /// start receiving data, especially if the UART1_RX line is - /// low. - /// If clear the mini UART is disabled. That also disables any - /// mini UART register access - MINI_UART_ENABLE OFFSET(0) NUMBITS(1) [] - ], - - /// Mini Uart Interrupt Identify - AUX_MU_IIR [ - /// Writing with bit 1 set will clear the receive FIFO - /// Writing with bit 2 set will clear the transmit FIFO - FIFO_CLEAR OFFSET(1) NUMBITS(2) [ - Rx = 0b01, - Tx = 0b10, - All = 0b11 - ] - ], - - /// Mini Uart Line Control - AUX_MU_LCR [ - /// Mode the UART works in - DATA_SIZE OFFSET(0) NUMBITS(2) [ - SevenBit = 0b00, - EightBit = 0b11 - ] - ], - - /// Mini Uart Line Status - AUX_MU_LSR [ - /// This bit is set if the transmit FIFO is empty and the transmitter is - /// idle. (Finished shifting out the last bit). - TX_IDLE OFFSET(6) NUMBITS(1) [], - - /// This bit is set if the transmit FIFO can accept at least - /// one byte. - TX_EMPTY OFFSET(5) NUMBITS(1) [], - - /// This bit is set if the receive FIFO holds at least 1 - /// symbol. - DATA_READY OFFSET(0) NUMBITS(1) [] - ], - - /// Mini Uart Extra Control - AUX_MU_CNTL [ - /// If this bit is set the mini UART transmitter is enabled. - /// If this bit is clear the mini UART transmitter is disabled. - TX_EN OFFSET(1) NUMBITS(1) [ - Disabled = 0, - Enabled = 1 - ], - - /// If this bit is set the mini UART receiver is enabled. - /// If this bit is clear the mini UART receiver is disabled. - RX_EN OFFSET(0) NUMBITS(1) [ - Disabled = 0, - Enabled = 1 - ] - ], - - /// Mini Uart Baudrate - AUX_MU_BAUD [ - /// Mini UART baudrate counter - RATE OFFSET(0) NUMBITS(16) [] - ] -} - -#[allow(non_snake_case)] -#[repr(C)] -pub struct RegisterBlock { - __reserved_0: u32, // 0x00 - AUX_ENABLES: ReadWrite, // 0x04 - __reserved_1: [u32; 14], // 0x08 - AUX_MU_IO: ReadWrite, // 0x40 - Mini Uart I/O Data - AUX_MU_IER: WriteOnly, // 0x44 - Mini Uart Interrupt Enable - AUX_MU_IIR: WriteOnly, // 0x48 - AUX_MU_LCR: WriteOnly, // 0x4C - AUX_MU_MCR: WriteOnly, // 0x50 - AUX_MU_LSR: ReadOnly, // 0x54 - __reserved_2: [u32; 2], // 0x58 - AUX_MU_CNTL: WriteOnly, // 0x60 - __reserved_3: u32, // 0x64 - AUX_MU_BAUD: WriteOnly, // 0x68 -} - -pub struct MiniUart { - base_addr: usize, -} - -/// Deref to RegisterBlock -/// -/// Allows writing -/// ``` -/// self.MU_IER.read() -/// ``` -/// instead of something along the lines of -/// ``` -/// unsafe { (*MiniUart::ptr()).MU_IER.read() } -/// ``` -impl ops::Deref for MiniUart { - type Target = RegisterBlock; - - fn deref(&self) -> &Self::Target { - unsafe { &*self.ptr() } - } -} - -impl MiniUart { - pub fn new(base_addr: usize) -> MiniUart { - MiniUart { base_addr } - } - - /// Returns a pointer to the register block - fn ptr(&self) -> *const RegisterBlock { - self.base_addr as *const _ - } - - ///Set baud rate and characteristics (115200 8N1) and map to GPIO - pub fn init(&self, gpio: &gpio::GPIO) { - // initialize UART - self.AUX_ENABLES.modify(AUX_ENABLES::MINI_UART_ENABLE::SET); - self.AUX_MU_IER.set(0); - self.AUX_MU_CNTL.set(0); - self.AUX_MU_LCR.write(AUX_MU_LCR::DATA_SIZE::EightBit); - self.AUX_MU_MCR.set(0); - self.AUX_MU_IER.set(0); - self.AUX_MU_IIR.write(AUX_MU_IIR::FIFO_CLEAR::All); - self.AUX_MU_BAUD.write(AUX_MU_BAUD::RATE.val(270)); // 115200 baud - - // map UART1 to GPIO pins - gpio.GPFSEL1 - .modify(gpio::GPFSEL1::FSEL14::TXD1 + gpio::GPFSEL1::FSEL15::RXD1); - - gpio.GPPUD.set(0); // enable pins 14 and 15 - for _ in 0..150 { - asm::nop(); - } - - gpio.GPPUDCLK0 - .write(gpio::GPPUDCLK0::PUDCLK14::AssertClock + gpio::GPPUDCLK0::PUDCLK15::AssertClock); - for _ in 0..150 { - asm::nop(); - } - - gpio.GPPUDCLK0.set(0); - - self.AUX_MU_CNTL - .write(AUX_MU_CNTL::RX_EN::Enabled + AUX_MU_CNTL::TX_EN::Enabled); - - // Clear FIFOs before using the device - self.AUX_MU_IIR.write(AUX_MU_IIR::FIFO_CLEAR::All); - } - - pub fn wait_tx_fifo_empty(&self) { - loop { - if self.AUX_MU_LSR.is_set(AUX_MU_LSR::TX_IDLE) { - break; - } - - asm::nop(); - } - } -} - -impl Drop for MiniUart { - fn drop(&mut self) { - self.AUX_ENABLES - .modify(AUX_ENABLES::MINI_UART_ENABLE::CLEAR); - } -} - -impl ConsoleOps for MiniUart { - /// Send a character - fn putc(&self, c: char) { - // wait until we can send - loop { - if self.AUX_MU_LSR.is_set(AUX_MU_LSR::TX_EMPTY) { - break; - } - - asm::nop(); - } - - // write the character to the buffer - self.AUX_MU_IO.set(c as u32); - } - - /// Display a string - fn puts(&self, string: &str) { - for c in string.chars() { - // convert newline to carrige return + newline - if c == '\n' { - self.putc('\r') - } - - self.putc(c); - } - } - - /// Receive a character - fn getc(&self) -> char { - // wait until something is in the buffer - loop { - if self.AUX_MU_LSR.is_set(AUX_MU_LSR::DATA_READY) { - break; - } - - asm::nop(); - } - - // read it and return - let mut ret = self.AUX_MU_IO.get() as u8 as char; - - // convert carrige return to newline - if ret == '\r' { - ret = '\n' - } - - ret - } - - /// Wait until the TX FIFO is empty, aka all characters have been put on the - /// line. - fn flush(&self) { - self.wait_tx_fifo_empty(); - } -} diff --git a/.11_exceptions_groundwork/src/devices/hw/pl011_uart.rs b/.11_exceptions_groundwork/src/devices/hw/pl011_uart.rs deleted file mode 100644 index 44580d35..00000000 --- a/.11_exceptions_groundwork/src/devices/hw/pl011_uart.rs +++ /dev/null @@ -1,276 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2018-2019 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -use super::gpio; -use super::videocore_mbox; -use crate::delays; -use crate::devices::virt::ConsoleOps; -use core::{ - ops, - sync::atomic::{compiler_fence, Ordering}, -}; -use cortex_a::asm; -use register::{mmio::*, register_bitfields}; - -// PL011 UART registers. -// -// Descriptions taken from -// https://github.com/raspberrypi/documentation/files/1888662/BCM2837-ARM-Peripherals.-.Revised.-.V2-1.pdf -register_bitfields! { - u32, - - /// Flag Register - FR [ - /// Transmit FIFO full. The meaning of this bit depends on the - /// state of the FEN bit in the UARTLCR_ LCRH 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 UARTLCR_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) [] - ], - - /// Integer Baud rate divisor - IBRD [ - /// Integer Baud rate divisor - IBRD OFFSET(0) NUMBITS(16) [] - ], - - /// Fractional Baud rate divisor - FBRD [ - /// Fractional Baud rate divisor - FBRD OFFSET(0) NUMBITS(6) [] - ], - - /// Line Control register - LCRH [ - /// Word length. These bits indicate the number of data bits - /// transmitted or received in a frame. - WLEN OFFSET(5) NUMBITS(2) [ - FiveBit = 0b00, - SixBit = 0b01, - SevenBit = 0b10, - EightBit = 0b11 - ] - ], - - /// Control Register - CR [ - /// Receive enable. If this bit is set to 1, the receive - /// section of the UART is enabled. Data reception occurs for - /// UART signals. 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 UART signals. 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 - 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 - ] - ], - - /// Interupt Clear Register - ICR [ - /// Meta field for all pending interrupts - ALL OFFSET(0) NUMBITS(11) [] - ] -} - -#[allow(non_snake_case)] -#[repr(C)] -pub struct RegisterBlock { - DR: ReadWrite, // 0x00 - __reserved_0: [u32; 5], // 0x04 - FR: ReadOnly, // 0x18 - __reserved_1: [u32; 2], // 0x1c - IBRD: WriteOnly, // 0x24 - FBRD: WriteOnly, // 0x28 - LCRH: WriteOnly, // 0x2C - CR: WriteOnly, // 0x30 - __reserved_2: [u32; 4], // 0x34 - ICR: WriteOnly, // 0x44 -} - -pub enum PL011UartError { - MailboxError, -} -pub type Result = ::core::result::Result; - -pub struct PL011Uart { - base_addr: usize, -} - -impl ops::Deref for PL011Uart { - type Target = RegisterBlock; - - fn deref(&self) -> &Self::Target { - unsafe { &*self.ptr() } - } -} - -impl PL011Uart { - pub fn new(base_addr: usize) -> PL011Uart { - PL011Uart { base_addr } - } - - /// Returns a pointer to the register block - fn ptr(&self) -> *const RegisterBlock { - self.base_addr as *const _ - } - - ///Set baud rate and characteristics (115200 8N1) and map to GPIO - pub fn init( - &self, - v_mbox: &mut videocore_mbox::VideocoreMbox, - gpio: &gpio::GPIO, - ) -> Result<()> { - // turn off UART0 - self.CR.set(0); - - // set up clock for consistent divisor values - v_mbox.buffer[0] = 9 * 4; - v_mbox.buffer[1] = videocore_mbox::REQUEST; - v_mbox.buffer[2] = videocore_mbox::tag::SETCLKRATE; - v_mbox.buffer[3] = 12; - v_mbox.buffer[4] = 8; - v_mbox.buffer[5] = videocore_mbox::clock::UART; // UART clock - v_mbox.buffer[6] = 4_000_000; // 4Mhz - v_mbox.buffer[7] = 0; // skip turbo setting - v_mbox.buffer[8] = videocore_mbox::tag::LAST; - - // Insert a compiler fence that ensures that all stores to the - // mbox buffer are finished before the GPU is signaled (which - // is done by a store operation as well). - compiler_fence(Ordering::Release); - - if v_mbox.call(videocore_mbox::channel::PROP).is_err() { - return Err(PL011UartError::MailboxError); // Abort if UART clocks couldn't be set - }; - - // map UART0 to GPIO pins - gpio.GPFSEL1 - .modify(gpio::GPFSEL1::FSEL14::TXD0 + gpio::GPFSEL1::FSEL15::RXD0); - - gpio.GPPUD.set(0); // enable pins 14 and 15 - delays::wait_cycles(150); - - gpio.GPPUDCLK0.modify( - gpio::GPPUDCLK0::PUDCLK14::AssertClock + gpio::GPPUDCLK0::PUDCLK15::AssertClock, - ); - delays::wait_cycles(150); - - gpio.GPPUDCLK0.set(0); - - self.ICR.write(ICR::ALL::CLEAR); - self.IBRD.write(IBRD::IBRD.val(2)); // Results in 115200 baud - self.FBRD.write(FBRD::FBRD.val(0xB)); - self.LCRH.write(LCRH::WLEN::EightBit); // 8N1 - - self.CR - .write(CR::UARTEN::Enabled + CR::TXE::Enabled + CR::RXE::Enabled); - - Ok(()) - } -} - -impl Drop for PL011Uart { - fn drop(&mut self) { - self.CR - .write(CR::UARTEN::Disabled + CR::TXE::Disabled + CR::RXE::Disabled); - } -} - -impl ConsoleOps for PL011Uart { - /// Send a character - fn putc(&self, c: char) { - // wait until we can send - loop { - if !self.FR.is_set(FR::TXFF) { - break; - } - - asm::nop(); - } - - // write the character to the buffer - self.DR.set(c as u32); - } - - /// Display a string - fn puts(&self, string: &str) { - for c in string.chars() { - // convert newline to carrige return + newline - if c == '\n' { - self.putc('\r') - } - - self.putc(c); - } - } - - /// Receive a character - fn getc(&self) -> char { - // wait until something is in the buffer - loop { - if !self.FR.is_set(FR::RXFE) { - break; - } - - asm::nop(); - } - - // read it and return - let mut ret = self.DR.get() as u8 as char; - - // convert carrige return to newline - if ret == '\r' { - ret = '\n' - } - - ret - } -} diff --git a/.11_exceptions_groundwork/src/devices/hw/videocore_mbox.rs b/.11_exceptions_groundwork/src/devices/hw/videocore_mbox.rs deleted file mode 100644 index 729777aa..00000000 --- a/.11_exceptions_groundwork/src/devices/hw/videocore_mbox.rs +++ /dev/null @@ -1,170 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2018-2019 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -use core::ops; -use cortex_a::asm; -use register::{ - mmio::{ReadOnly, WriteOnly}, - register_bitfields, -}; - -register_bitfields! { - u32, - - STATUS [ - FULL OFFSET(31) NUMBITS(1) [], - EMPTY OFFSET(30) NUMBITS(1) [] - ] -} - -#[allow(non_snake_case)] -#[repr(C)] -pub struct RegisterBlock { - READ: ReadOnly, // 0x00 - __reserved_0: [u32; 5], // 0x04 - STATUS: ReadOnly, // 0x18 - __reserved_1: u32, // 0x1C - WRITE: WriteOnly, // 0x20 -} - -// Custom errors -pub enum VideocoreMboxError { - ResponseError, - UnknownError, -} -pub type Result = ::core::result::Result; - -// Channels -pub mod channel { - pub const PROP: u32 = 8; -} - -// Tags -pub mod tag { - pub const SETCLKRATE: u32 = 0x38002; - pub const LAST: u32 = 0; -} - -// Clocks -pub mod clock { - pub const UART: u32 = 0x0_0000_0002; -} - -// Responses -mod response { - pub const SUCCESS: u32 = 0x8000_0000; - pub const ERROR: u32 = 0x8000_0001; // error parsing request buffer (partial response) -} - -pub const REQUEST: u32 = 0; - -// The address for buffer needs to be 16-byte aligned so that the Videcore can -// handle it properly. -const MBOX_ALIGNMENT: usize = 16; -const MBOX_SIZE: usize = 36; - -// Public interface to the mailbox -pub struct VideocoreMbox<'a> { - pub buffer: &'a mut [u32], - base_addr: usize, -} - -/// Deref to RegisterBlock -/// -/// Allows writing -/// ``` -/// self.STATUS.read() -/// ``` -/// instead of something along the lines of -/// ``` -/// unsafe { (*Mbox::ptr()).STATUS.read() } -/// ``` -impl<'a> ops::Deref for VideocoreMbox<'a> { - type Target = RegisterBlock; - - fn deref(&self) -> &Self::Target { - unsafe { &*self.ptr() } - } -} - -impl<'a> VideocoreMbox<'a> { - pub fn new(base_addr: usize) -> ::core::result::Result, ()> { - let ret = crate::DMA_ALLOCATOR.lock(|d| d.alloc_slice_zeroed(MBOX_SIZE, MBOX_ALIGNMENT)); - - if ret.is_err() { - return Err(()); - } - - Ok(VideocoreMbox { - base_addr, - buffer: ret.unwrap(), - }) - } - - /// Returns a pointer to the register block - fn ptr(&self) -> *const RegisterBlock { - self.base_addr as *const _ - } - - /// Make a mailbox call. Returns Err(MboxError) on failure, Ok(()) success - pub fn call(&self, channel: u32) -> Result<()> { - // wait until we can write to the mailbox - loop { - if !self.STATUS.is_set(STATUS::FULL) { - break; - } - - asm::nop(); - } - - let buf_ptr = self.buffer.as_ptr() as u32; - - // write the address of our message to the mailbox with channel identifier - self.WRITE.set((buf_ptr & !0xF) | (channel & 0xF)); - - // now wait for the response - loop { - // is there a response? - loop { - if !self.STATUS.is_set(STATUS::EMPTY) { - break; - } - - asm::nop(); - } - - let resp: u32 = self.READ.get(); - - // is it a response to our message? - if ((resp & 0xF) == channel) && ((resp & !0xF) == buf_ptr) { - // is it a valid successful response? - return match self.buffer[1] { - response::SUCCESS => Ok(()), - response::ERROR => Err(VideocoreMboxError::ResponseError), - _ => Err(VideocoreMboxError::UnknownError), - }; - } - } - } -} diff --git a/.11_exceptions_groundwork/src/devices/virt.rs b/.11_exceptions_groundwork/src/devices/virt.rs deleted file mode 100644 index 30ed5469..00000000 --- a/.11_exceptions_groundwork/src/devices/virt.rs +++ /dev/null @@ -1,27 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2019 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -mod console; - -pub use console::{Console, ConsoleOps}; diff --git a/.11_exceptions_groundwork/src/devices/virt/console.rs b/.11_exceptions_groundwork/src/devices/virt/console.rs deleted file mode 100644 index 6972325a..00000000 --- a/.11_exceptions_groundwork/src/devices/virt/console.rs +++ /dev/null @@ -1,144 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2019 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -use crate::devices::hw; -use core::fmt; - -/// A trait that must be implemented by devices that are candidates for the -/// global console. -#[allow(unused_variables)] -pub trait ConsoleOps: Drop { - fn putc(&self, c: char) {} - fn puts(&self, string: &str) {} - fn getc(&self) -> char { - ' ' - } - fn flush(&self) {} -} - -/// A dummy console that just ignores its inputs. -pub struct NullConsole; -impl Drop for NullConsole { - fn drop(&mut self) {} -} -impl ConsoleOps for NullConsole {} - -/// Possible outputs which the console can store. -pub enum Output { - None(NullConsole), - MiniUart(hw::MiniUart), - PL011Uart(hw::PL011Uart), -} - -impl From for Output { - fn from(instance: hw::MiniUart) -> Self { - Output::MiniUart(instance) - } -} - -impl From for Output { - fn from(instance: hw::PL011Uart) -> Self { - Output::PL011Uart(instance) - } -} - -pub struct Console { - output: Output, -} - -impl Console { - pub const fn new() -> Console { - Console { - output: Output::None(NullConsole {}), - } - } - - #[inline(always)] - fn current_ptr(&self) -> &dyn ConsoleOps { - match &self.output { - Output::None(i) => i, - Output::MiniUart(i) => i, - Output::PL011Uart(i) => i, - } - } - - /// Overwrite the current output. The old output will go out of scope and - /// it's Drop function will be called. - pub fn replace_with(&mut self, x: Output) { - self.current_ptr().flush(); - - self.output = x; - } - - /// A command prompt. Currently does nothing. - pub fn command_prompt(&self) -> ! { - self.puts("\n$> "); - - let mut input; - loop { - input = self.getc(); - - if input == '\n' { - self.puts("\n$> ") - } else { - self.putc(input); - } - } - } -} - -impl Drop for Console { - fn drop(&mut self) {} -} - -/// Dispatch the respective function to the currently stored output device. -impl ConsoleOps for Console { - fn putc(&self, c: char) { - self.current_ptr().putc(c); - } - - fn puts(&self, string: &str) { - self.current_ptr().puts(string); - } - - fn getc(&self) -> char { - self.current_ptr().getc() - } - - fn flush(&self) { - self.current_ptr().flush() - } -} - -/// Implementing this trait enables usage of the format_args! macros, which in -/// turn are used to implement the kernel's print! and println! macros. -/// -/// See src/macros.rs. -impl fmt::Write for Console { - fn write_str(&mut self, s: &str) -> fmt::Result { - self.current_ptr().puts(s); - - Ok(()) - } -} diff --git a/.11_exceptions_groundwork/src/exception.rs b/.11_exceptions_groundwork/src/exception.rs deleted file mode 100644 index 189d4c36..00000000 --- a/.11_exceptions_groundwork/src/exception.rs +++ /dev/null @@ -1,104 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2018-2019 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -use crate::println; -use cortex_a::{barrier, regs::*}; - -global_asm!(include_str!("vectors.S")); - -/// # Safety -/// -/// - User must ensure to call this function at a suitable place, since it -/// changes the state of the hardware. -pub unsafe fn set_vbar_el1_checked(vec_base_addr: u64) -> bool { - if vec_base_addr.trailing_zeros() < 11 { - false - } else { - cortex_a::regs::VBAR_EL1.set(vec_base_addr); - - // Force VBAR update to complete before next instruction. - barrier::isb(barrier::SY); - - true - } -} - -#[repr(C)] -pub struct GPR { - x: [u64; 31], -} - -#[repr(C)] -pub struct ExceptionContext { - // General Purpose Registers - gpr: GPR, - spsr_el1: u64, - elr_el1: u64, -} - -/// The default exception, invoked for every exception type unless the handler -/// is overwritten. -#[no_mangle] -unsafe extern "C" fn default_exception_handler() { - println!("Unexpected exception. Halting CPU."); - - loop { - cortex_a::asm::wfe() - } -} - -// To implement an exception handler, overwrite it by defining the respective -// function below. -// Don't forget the #[no_mangle] attribute. -// -// unsafe extern "C" fn current_el0_synchronous(e: &mut ExceptionContext); -// unsafe extern "C" fn current_el0_irq(e: &mut ExceptionContext); -// unsafe extern "C" fn current_el0_serror(e: &mut ExceptionContext); - -// unsafe extern "C" fn current_elx_synchronous(e: &mut ExceptionContext); -// unsafe extern "C" fn current_elx_irq(e: &mut ExceptionContext); -// unsafe extern "C" fn current_elx_serror(e: &mut ExceptionContext); - -// unsafe extern "C" fn lower_aarch64_synchronous(e: &mut ExceptionContext); -// unsafe extern "C" fn lower_aarch64_irq(e: &mut ExceptionContext); -// unsafe extern "C" fn lower_aarch64_serror(e: &mut ExceptionContext); - -// unsafe extern "C" fn lower_aarch32_synchronous(e: &mut ExceptionContext); -// unsafe extern "C" fn lower_aarch32_irq(e: &mut ExceptionContext); -// unsafe extern "C" fn lower_aarch32_serror(e: &mut ExceptionContext); - -#[no_mangle] -unsafe extern "C" fn current_elx_synchronous(e: &mut ExceptionContext) { - println!("[!] A synchronous exception happened."); - println!(" ELR_EL1: {:#010X}", e.elr_el1); - println!( - " Incrementing ELR_EL1 by 4 now to continue with the first \ - instruction after the exception!" - ); - - e.elr_el1 += 4; - - println!(" ELR_EL1 modified: {:#010X}", e.elr_el1); - println!(" Returning from exception...\n"); -} diff --git a/.11_exceptions_groundwork/src/macros.rs b/.11_exceptions_groundwork/src/macros.rs deleted file mode 100644 index 28280be9..00000000 --- a/.11_exceptions_groundwork/src/macros.rs +++ /dev/null @@ -1,49 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2019 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -use core::fmt; - -// https://doc.rust-lang.org/src/std/macros.rs.html -#[macro_export] -macro_rules! print { - ($($arg:tt)*) => ($crate::macros::_print(format_args!($($arg)*))); -} - -// https://doc.rust-lang.org/src/std/macros.rs.html -#[macro_export] -macro_rules! println { - () => (print!("\n")); - ($($arg:tt)*) => ({ - $crate::macros::_print(format_args_nl!($($arg)*)); - }) -} - -#[doc(hidden)] -pub fn _print(args: fmt::Arguments) { - use core::fmt::Write; - - crate::CONSOLE.lock(|c| { - c.write_fmt(args).unwrap(); - }) -} diff --git a/.11_exceptions_groundwork/src/main.rs b/.11_exceptions_groundwork/src/main.rs deleted file mode 100644 index 2e8ae768..00000000 --- a/.11_exceptions_groundwork/src/main.rs +++ /dev/null @@ -1,185 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2018-2019 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#![no_std] -#![no_main] -#![feature(allocator_api)] -#![feature(const_fn)] -#![feature(custom_attribute)] -#![feature(format_args_nl)] -#![feature(global_asm)] -#![feature(label_break_value)] - -mod delays; -mod devices; -mod exception; -mod macros; -mod memory; -mod sync; - -/// The global console. Output of the print! and println! macros. -static CONSOLE: sync::NullLock = - sync::NullLock::new(devices::virt::Console::new()); - -/// The global allocator for DMA-able memory. That is, memory which is tagged -/// non-cacheable in the page tables. -static DMA_ALLOCATOR: sync::NullLock = - sync::NullLock::new(memory::BumpAllocator::new( - memory::map::virt::DMA_HEAP_START as usize, - memory::map::virt::DMA_HEAP_END as usize, - "Global DMA Allocator", - )); - -fn kernel_entry() -> ! { - use devices::hw; - use devices::virt::ConsoleOps; - - extern "C" { - static __exception_vectors_start: u64; - } - - //------------------------------------------------------------ - // Instantiate GPIO device - //------------------------------------------------------------ - let gpio = hw::GPIO::new(memory::map::physical::GPIO_BASE); - - //------------------------------------------------------------ - // Instantiate MiniUart - //------------------------------------------------------------ - let mini_uart = hw::MiniUart::new(memory::map::physical::MINI_UART_BASE); - mini_uart.init(&gpio); - - CONSOLE.lock(|c| { - // Moves mini_uart into the global CONSOLE. It is not accessible anymore - // for the remaining parts of kernel_entry(). - c.replace_with(mini_uart.into()); - }); - println!("\n[0] MiniUart online."); - - //------------------------------------------------------------ - // Greet the user - //------------------------------------------------------------ - print!("[1] Press a key to continue booting... "); - CONSOLE.lock(|c| { - c.getc(); - }); - println!("Greetings fellow Rustacean!"); - - // We are now in a state where every next step can fail, but we can handle - // the error with feedback for the user and fall through to our UART - // loopback. - 'init: { - //------------------------------------------------------------ - // Bring up memory subsystem - //------------------------------------------------------------ - if unsafe { memory::mmu::init() }.is_err() { - println!("[2][Error] Could not set up MMU. Aborting."); - break 'init; - }; - println!("[2] MMU online."); - - memory::print_layout(); - - //------------------------------------------------------------ - // Instantiate Videocore Mailbox - //------------------------------------------------------------ - let mut v_mbox; - match hw::VideocoreMbox::new(memory::map::physical::VIDEOCORE_MBOX_BASE) { - Ok(i) => { - println!("[3] Videocore Mailbox set up (DMA mem heap allocation successful)."); - v_mbox = i; - } - - Err(_) => { - println!("[3][Error] Could not set up Videocore Mailbox. Aborting."); - break 'init; - } - } - - //------------------------------------------------------------ - // Instantiate PL011 UART and replace MiniUart with it in CONSOLE - //------------------------------------------------------------ - let pl011_uart = hw::PL011Uart::new(memory::map::physical::PL011_UART_BASE); - - // uart.init() will reconfigure the GPIO, which causes a race against - // the MiniUart that is still putting out characters on the physical - // line that are already buffered in its TX FIFO. - // - // To ensure the CPU doesn't rewire the GPIO before the MiniUart has put - // its last character, explicitly flush it before rewiring. - // - // If you switch to an output that happens to not use the same pair of - // physical wires (e.g. the Framebuffer), you don't need to do this, - // because flush() is anyways called implicitly by replace_with(). This - // is just a special case. - CONSOLE.lock(|c| c.flush()); - match pl011_uart.init(&mut v_mbox, &gpio) { - Ok(_) => { - CONSOLE.lock(|c| { - c.replace_with(pl011_uart.into()); - }); - - println!("[4] PL011 UART online. Output switched to it."); - } - - Err(_) => println!( - "[4][Error] PL011 UART init failed. \ - Trying to continue with MiniUart." - ), - } - - //------------------------------------------------------------ - // Set up exception vectors and cause an exception - //------------------------------------------------------------ - if unsafe { - let exception_vectors_start: u64 = &__exception_vectors_start as *const _ as u64; - - exception::set_vbar_el1_checked(exception_vectors_start) - } { - println!("[5] Exception vectors are set up."); - } else { - println!("[5][Error] Error setting exception vectors. Aborting."); - break 'init; - } - - // Cause an exception by accessing a virtual address for which no - // address translations have been set up. - // - // This line of code accesses the address 3 GiB, but page tables are - // only set up for the range [0..1] GiB. - let big_addr: u64 = 3 * 1024 * 1024 * 1024; - unsafe { core::ptr::read_volatile(big_addr as *mut u64) }; - - println!("[i] Whoa! We recovered from an exception."); - } - - //------------------------------------------------------------ - // Start a command prompt - //------------------------------------------------------------ - CONSOLE.lock(|c| { - c.command_prompt(); - }) -} - -raspi3_boot::entry!(kernel_entry); diff --git a/.11_exceptions_groundwork/src/memory.rs b/.11_exceptions_groundwork/src/memory.rs deleted file mode 100644 index f1da0c87..00000000 --- a/.11_exceptions_groundwork/src/memory.rs +++ /dev/null @@ -1,292 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2019 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -use crate::println; -use core::fmt; -use core::ops::RangeInclusive; - -mod bump_allocator; -pub use bump_allocator::BumpAllocator; - -pub mod mmu; - -/// System memory map. -#[rustfmt::skip] -pub mod map { - pub const START: usize = 0x0000_0000; - pub const END: usize = 0x3FFF_FFFF; - - pub mod physical { - pub const MMIO_BASE: usize = 0x3F00_0000; - pub const VIDEOCORE_MBOX_BASE: usize = MMIO_BASE + 0x0000_B880; - pub const GPIO_BASE: usize = MMIO_BASE + 0x0020_0000; - pub const PL011_UART_BASE: usize = MMIO_BASE + 0x0020_1000; - pub const MINI_UART_BASE: usize = MMIO_BASE + 0x0021_5000; - pub const MMIO_END: usize = super::END; - } - - pub mod virt { - pub const KERN_STACK_START: usize = super::START; - pub const KERN_STACK_END: usize = 0x0007_FFFF; - - // The second 2 MiB block. - pub const DMA_HEAP_START: usize = 0x0020_0000; - pub const DMA_HEAP_END: usize = 0x005F_FFFF; - } -} - -/// Types used for compiling the virtual memory layout of the kernel using -/// address ranges. -pub mod kernel_mem_range { - use core::ops::RangeInclusive; - - #[derive(Copy, Clone)] - pub enum MemAttributes { - CacheableDRAM, - NonCacheableDRAM, - Device, - } - - #[derive(Copy, Clone)] - pub enum AccessPermissions { - ReadOnly, - ReadWrite, - } - - #[allow(dead_code)] - #[derive(Copy, Clone)] - pub enum Translation { - Identity, - Offset(usize), - } - - #[derive(Copy, Clone)] - pub struct AttributeFields { - pub mem_attributes: MemAttributes, - pub acc_perms: AccessPermissions, - pub execute_never: bool, - } - - impl Default for AttributeFields { - fn default() -> AttributeFields { - AttributeFields { - mem_attributes: MemAttributes::CacheableDRAM, - acc_perms: AccessPermissions::ReadWrite, - execute_never: true, - } - } - } - - pub struct Descriptor { - pub name: &'static str, - pub virtual_range: fn() -> RangeInclusive, - pub translation: Translation, - pub attribute_fields: AttributeFields, - } -} - -use kernel_mem_range::*; - -/// A virtual memory layout that is agnostic of the paging granularity that the -/// hardware MMU will use. -/// -/// Contains only special ranges, aka anything that is _not_ normal cacheable -/// DRAM. -static KERNEL_VIRTUAL_LAYOUT: [Descriptor; 5] = [ - Descriptor { - name: "Kernel stack", - virtual_range: || { - RangeInclusive::new(map::virt::KERN_STACK_START, map::virt::KERN_STACK_END) - }, - translation: Translation::Identity, - attribute_fields: AttributeFields { - mem_attributes: MemAttributes::CacheableDRAM, - acc_perms: AccessPermissions::ReadWrite, - execute_never: true, - }, - }, - Descriptor { - name: "Kernel code and RO data", - virtual_range: || { - // Using the linker script, we ensure that the RO area is consecutive and 4 - // KiB aligned, and we export the boundaries via symbols: - // - // [__ro_start, __ro_end) - extern "C" { - // The inclusive start of the read-only area, aka the address of the - // first byte of the area. - static __ro_start: u64; - - // The exclusive end of the read-only area, aka the address of - // the first byte _after_ the RO area. - static __ro_end: u64; - } - - unsafe { - // Notice the subtraction to turn the exclusive end into an - // inclusive end - RangeInclusive::new( - &__ro_start as *const _ as usize, - &__ro_end as *const _ as usize - 1, - ) - } - }, - translation: Translation::Identity, - attribute_fields: AttributeFields { - mem_attributes: MemAttributes::CacheableDRAM, - acc_perms: AccessPermissions::ReadOnly, - execute_never: false, - }, - }, - Descriptor { - name: "Kernel data and BSS", - virtual_range: || { - extern "C" { - static __ro_end: u64; - static __bss_end: u64; - } - - unsafe { - RangeInclusive::new( - &__ro_end as *const _ as usize, - &__bss_end as *const _ as usize - 1, - ) - } - }, - translation: Translation::Identity, - attribute_fields: AttributeFields { - mem_attributes: MemAttributes::CacheableDRAM, - acc_perms: AccessPermissions::ReadWrite, - execute_never: true, - }, - }, - Descriptor { - name: "DMA heap pool", - virtual_range: || RangeInclusive::new(map::virt::DMA_HEAP_START, map::virt::DMA_HEAP_END), - translation: Translation::Identity, - attribute_fields: AttributeFields { - mem_attributes: MemAttributes::NonCacheableDRAM, - acc_perms: AccessPermissions::ReadWrite, - execute_never: true, - }, - }, - Descriptor { - name: "Device MMIO", - virtual_range: || RangeInclusive::new(map::physical::MMIO_BASE, map::physical::MMIO_END), - translation: Translation::Identity, - attribute_fields: AttributeFields { - mem_attributes: MemAttributes::Device, - acc_perms: AccessPermissions::ReadWrite, - execute_never: true, - }, - }, -]; - -/// For a given virtual address, find and return the output address and -/// according attributes. -/// -/// If the address is not covered in VIRTUAL_LAYOUT, return a default for normal -/// cacheable DRAM. -fn get_virt_addr_properties(virt_addr: usize) -> Result<(usize, AttributeFields), &'static str> { - if virt_addr > map::END { - return Err("Address out of range."); - } - - for i in KERNEL_VIRTUAL_LAYOUT.iter() { - if (i.virtual_range)().contains(&virt_addr) { - let output_addr = match i.translation { - Translation::Identity => virt_addr, - Translation::Offset(a) => a + (virt_addr - (i.virtual_range)().start()), - }; - - return Ok((output_addr, i.attribute_fields)); - } - } - - Ok((virt_addr, AttributeFields::default())) -} - -/// Human-readable output of a Descriptor. -impl fmt::Display for Descriptor { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - // Call the function to which self.range points, and dereference the - // result, which causes Rust to copy the value. - let start = *(self.virtual_range)().start(); - 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 attr = match self.attribute_fields.mem_attributes { - MemAttributes::CacheableDRAM => "C", - MemAttributes::NonCacheableDRAM => "NC", - MemAttributes::Device => "Dev", - }; - - let acc_p = match self.attribute_fields.acc_perms { - AccessPermissions::ReadOnly => "RO", - AccessPermissions::ReadWrite => "RW", - }; - - 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 - ) - } -} - -/// Print the kernel memory layout. -pub fn print_layout() { - println!("[i] Kernel memory layout:"); - - for i in KERNEL_VIRTUAL_LAYOUT.iter() { - println!("{}", i); - } -} - -/// Calculate the next possible aligned address without sanity checking the -/// input parameters. -#[inline] -fn aligned_addr_unchecked(addr: usize, alignment: usize) -> usize { - (addr + (alignment - 1)) & !(alignment - 1) -} diff --git a/.11_exceptions_groundwork/src/memory/bump_allocator.rs b/.11_exceptions_groundwork/src/memory/bump_allocator.rs deleted file mode 100644 index 0bab4129..00000000 --- a/.11_exceptions_groundwork/src/memory/bump_allocator.rs +++ /dev/null @@ -1,100 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2019 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -use crate::println; -use core::alloc::{Alloc, AllocErr, Layout}; -use core::mem; -use core::ptr::NonNull; -use core::slice; - -pub struct BumpAllocator { - next: usize, - pool_end: usize, - name: &'static str, -} - -unsafe impl Alloc for BumpAllocator { - unsafe fn alloc(&mut self, layout: Layout) -> Result, AllocErr> { - let start = crate::memory::aligned_addr_unchecked(self.next, layout.align()); - let end = start + layout.size(); - - if end <= self.pool_end { - self.next = end; - - println!( - "[i] {}:\n Allocated Addr {:#010X} Size {:#X}", - self.name, - start, - layout.size() - ); - - Ok(NonNull::new_unchecked(start as *mut u8)) - } else { - Err(AllocErr) - } - } - - // A bump allocator doesn't care - unsafe fn dealloc(&mut self, _ptr: NonNull, _layout: Layout) {} -} - -impl BumpAllocator { - pub const fn new(pool_start: usize, pool_end: usize, name: &'static str) -> Self { - Self { - next: pool_start, - pool_end, - name, - } - } - - /// Allocate a zeroed slice - pub fn alloc_slice_zeroed<'a, T>( - &mut self, - count_of_items: usize, - alignment: usize, - ) -> Result<&'a mut [T], ()> { - let l; - let size_in_byte = count_of_items * mem::size_of::(); - match Layout::from_size_align(size_in_byte, alignment) { - Ok(layout) => l = layout, - - Err(_) => { - println!("[e] Layout Error!"); - return Err(()); - } - } - - let ptr; - match unsafe { self.alloc_zeroed(l) } { - Ok(i) => ptr = i.as_ptr(), - - Err(_) => { - println!("[e] Layout Error!"); - return Err(()); - } - } - - Ok(unsafe { slice::from_raw_parts_mut(ptr as *mut T, count_of_items) }) - } -} diff --git a/.11_exceptions_groundwork/src/memory/mmu.rs b/.11_exceptions_groundwork/src/memory/mmu.rs deleted file mode 100644 index aa4e43c6..00000000 --- a/.11_exceptions_groundwork/src/memory/mmu.rs +++ /dev/null @@ -1,349 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2018-2019 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -use crate::memory::{get_virt_addr_properties, AttributeFields}; -use cortex_a::{barrier, regs::*}; -use register::register_bitfields; - -register_bitfields! {u64, - // AArch64 Reference Manual page 2150 - STAGE1_DESCRIPTOR [ - /// Privileged execute-never - PXN OFFSET(53) NUMBITS(1) [ - False = 0, - True = 1 - ], - - /// Various address fields, depending on use case - LVL2_OUTPUT_ADDR_4KiB OFFSET(21) NUMBITS(27) [], // [47:21] - NEXT_LVL_TABLE_ADDR_4KiB OFFSET(12) NUMBITS(36) [], // [47:12] - - /// 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) [ - Block = 0, - Table = 1 - ], - - VALID OFFSET(0) NUMBITS(1) [ - False = 0, - True = 1 - ] - ] -} - -const FOUR_KIB: usize = 4 * 1024; -const FOUR_KIB_SHIFT: usize = 12; // log2(4 * 1024) - -const TWO_MIB: usize = 2 * 1024 * 1024; -const TWO_MIB_SHIFT: usize = 21; // log2(2 * 1024 * 1024) - -/// A descriptor pointing to the next page table. -struct TableDescriptor(register::FieldValue); - -impl TableDescriptor { - fn new(next_lvl_table_addr: usize) -> Result { - if next_lvl_table_addr % FOUR_KIB != 0 { - return Err("TableDescriptor: Address is not 4 KiB aligned."); - } - - let shifted = next_lvl_table_addr >> FOUR_KIB_SHIFT; - - Ok(TableDescriptor( - STAGE1_DESCRIPTOR::VALID::True - + STAGE1_DESCRIPTOR::TYPE::Table - + STAGE1_DESCRIPTOR::NEXT_LVL_TABLE_ADDR_4KiB.val(shifted as u64), - )) - } - - fn value(&self) -> u64 { - self.0.value - } -} - -/// A function that maps the generic memory range attributes to HW-specific -/// attributes of the MMU. -fn into_mmu_attributes( - attribute_fields: AttributeFields, -) -> register::FieldValue { - use crate::memory::{AccessPermissions, MemAttributes}; - - // Memory attributes - let mut desc = match attribute_fields.mem_attributes { - MemAttributes::CacheableDRAM => { - STAGE1_DESCRIPTOR::SH::InnerShareable + STAGE1_DESCRIPTOR::AttrIndx.val(mair::NORMAL) - } - MemAttributes::NonCacheableDRAM => { - STAGE1_DESCRIPTOR::SH::InnerShareable - + STAGE1_DESCRIPTOR::AttrIndx.val(mair::NORMAL_NON_CACHEABLE) - } - MemAttributes::Device => { - STAGE1_DESCRIPTOR::SH::OuterShareable + STAGE1_DESCRIPTOR::AttrIndx.val(mair::DEVICE) - } - }; - - // Access Permissions - desc += match attribute_fields.acc_perms { - AccessPermissions::ReadOnly => STAGE1_DESCRIPTOR::AP::RO_EL1, - AccessPermissions::ReadWrite => STAGE1_DESCRIPTOR::AP::RW_EL1, - }; - - // Execute Never - desc += if attribute_fields.execute_never { - STAGE1_DESCRIPTOR::PXN::True - } else { - STAGE1_DESCRIPTOR::PXN::False - }; - - desc -} - -/// A Level2 block descriptor with 2 MiB aperture. -/// -/// The output points to physical memory. -struct Lvl2BlockDescriptor(register::FieldValue); - -impl Lvl2BlockDescriptor { - fn new( - output_addr: usize, - attribute_fields: AttributeFields, - ) -> Result { - if output_addr % TWO_MIB != 0 { - return Err("BlockDescriptor: Address is not 2 MiB aligned."); - } - - let shifted = output_addr >> TWO_MIB_SHIFT; - - Ok(Lvl2BlockDescriptor( - STAGE1_DESCRIPTOR::VALID::True - + STAGE1_DESCRIPTOR::AF::True - + into_mmu_attributes(attribute_fields) - + STAGE1_DESCRIPTOR::TYPE::Block - + STAGE1_DESCRIPTOR::LVL2_OUTPUT_ADDR_4KiB.val(shifted as u64), - )) - } - - fn value(&self) -> u64 { - self.0.value - } -} - -/// A page descriptor with 4 KiB aperture. -/// -/// The output points to physical memory. -struct PageDescriptor(register::FieldValue); - -impl PageDescriptor { - fn new( - output_addr: usize, - attribute_fields: AttributeFields, - ) -> Result { - if output_addr % FOUR_KIB != 0 { - return Err("PageDescriptor: Address is not 4 KiB aligned."); - } - - let shifted = output_addr >> FOUR_KIB_SHIFT; - - Ok(PageDescriptor( - STAGE1_DESCRIPTOR::VALID::True - + STAGE1_DESCRIPTOR::AF::True - + into_mmu_attributes(attribute_fields) - + STAGE1_DESCRIPTOR::TYPE::Table - + STAGE1_DESCRIPTOR::NEXT_LVL_TABLE_ADDR_4KiB.val(shifted as u64), - )) - } - - fn value(&self) -> u64 { - self.0.value - } -} - -/// Constants for indexing the MAIR_EL1. -#[allow(dead_code)] -mod mair { - pub const DEVICE: u64 = 0; - pub const NORMAL: u64 = 1; - pub const NORMAL_NON_CACHEABLE: u64 = 2; -} - -/// Setup function for the MAIR_EL1 register. -fn set_up_mair() { - // Define the three memory types that we will map. Cacheable and - // non-cacheable normal DRAM, and device. - MAIR_EL1.write( - // Attribute 2 - MAIR_EL1::Attr2_HIGH::Memory_OuterNonCacheable - + MAIR_EL1::Attr2_LOW_MEMORY::InnerNonCacheable - - // Attribute 1 - + MAIR_EL1::Attr1_HIGH::Memory_OuterWriteBack_NonTransient_ReadAlloc_WriteAlloc - + MAIR_EL1::Attr1_LOW_MEMORY::InnerWriteBack_NonTransient_ReadAlloc_WriteAlloc - - // Attribute 0 - + MAIR_EL1::Attr0_HIGH::Device - + MAIR_EL1::Attr0_LOW_DEVICE::Device_nGnRE, - ); -} - -trait BaseAddr { - fn base_addr_u64(&self) -> u64; - fn base_addr_usize(&self) -> usize; -} - -impl BaseAddr for [u64; 512] { - fn base_addr_u64(&self) -> u64 { - self as *const u64 as u64 - } - - fn base_addr_usize(&self) -> usize { - self as *const u64 as usize - } -} - -const NUM_ENTRIES_4KIB: usize = 512; - -// A wrapper struct is needed here so that the align attribute can be used. -#[repr(C)] -#[repr(align(4096))] -struct PageTable { - entries: [u64; NUM_ENTRIES_4KIB], -} - -/// The LVL2 page table containng the 2 MiB entries. -static mut LVL2_TABLE: PageTable = PageTable { - entries: [0; NUM_ENTRIES_4KIB], -}; - -/// The LVL3 page table containing the 4 KiB entries. -/// -/// The first entry of the LVL2_TABLE will forward to this table. -static mut LVL3_TABLE: PageTable = PageTable { - entries: [0; NUM_ENTRIES_4KIB], -}; - -/// Set up identity mapped page tables for the first 1 GiB of address space. -/// -/// The first 2 MiB are 4 KiB granule, the rest 2 MiB. -/// -/// # Safety -/// -/// - User must ensure that the hardware supports the paremeters being set here. -pub unsafe fn init() -> Result<(), &'static str> { - // Prepare the memory attribute indirection register. - set_up_mair(); - - // Point the first 2 MiB of virtual addresses to the follow-up LVL3 - // page-table. - LVL2_TABLE.entries[0] = match TableDescriptor::new(LVL3_TABLE.entries.base_addr_usize()) { - Err(s) => return Err(s), - Ok(d) => d.value(), - }; - - // Fill the rest of the LVL2 (2 MiB) entries as block descriptors. - // - // Notice the skip(1) which makes the iteration start at the second 2 MiB - // block (0x20_0000). - for (block_descriptor_nr, entry) in LVL2_TABLE.entries.iter_mut().enumerate().skip(1) { - let virt_addr = block_descriptor_nr << TWO_MIB_SHIFT; - - let (output_addr, attribute_fields) = match get_virt_addr_properties(virt_addr) { - Err(s) => return Err(s), - Ok((a, b)) => (a, b), - }; - - let block_desc = match Lvl2BlockDescriptor::new(output_addr, attribute_fields) { - Err(s) => return Err(s), - Ok(desc) => desc, - }; - - *entry = block_desc.value(); - } - - // Finally, fill the single LVL3 table (4 KiB granule). - for (page_descriptor_nr, entry) in LVL3_TABLE.entries.iter_mut().enumerate() { - let virt_addr = page_descriptor_nr << FOUR_KIB_SHIFT; - - let (output_addr, attribute_fields) = match get_virt_addr_properties(virt_addr) { - Err(s) => return Err(s), - Ok((a, b)) => (a, b), - }; - - let page_desc = match PageDescriptor::new(output_addr, attribute_fields) { - Err(s) => return Err(s), - Ok(desc) => desc, - }; - - *entry = page_desc.value(); - } - - // Point to the LVL2 table base address in TTBR0. - TTBR0_EL1.set_baddr(LVL2_TABLE.entries.base_addr_u64()); - - // Configure various settings of stage 1 of the EL1 translation regime. - let ips = ID_AA64MMFR0_EL1.read(ID_AA64MMFR0_EL1::PARange); - TCR_EL1.write( - TCR_EL1::TBI0::Ignored - + TCR_EL1::IPS.val(ips) - + TCR_EL1::TG0::KiB_4 // 4 KiB granule - + TCR_EL1::SH0::Inner - + TCR_EL1::ORGN0::WriteBack_ReadAlloc_WriteAlloc_Cacheable - + TCR_EL1::IRGN0::WriteBack_ReadAlloc_WriteAlloc_Cacheable - + TCR_EL1::EPD0::EnableTTBR0Walks - + TCR_EL1::T0SZ.val(34), // Start walks at level 2 - ); - - // 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(()) -} diff --git a/.11_exceptions_groundwork/src/sync.rs b/.11_exceptions_groundwork/src/sync.rs deleted file mode 100644 index 3cbc1714..00000000 --- a/.11_exceptions_groundwork/src/sync.rs +++ /dev/null @@ -1,51 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2019 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -use core::cell::UnsafeCell; - -pub struct NullLock { - data: UnsafeCell, -} - -unsafe impl Sync for NullLock {} - -impl NullLock { - pub const fn new(data: T) -> NullLock { - NullLock { - data: UnsafeCell::new(data), - } - } -} - -impl NullLock { - pub fn lock(&self, f: F) -> R - where - F: FnOnce(&mut T) -> R, - { - // In a real lock, there would be code around this line that ensures - // that this mutable reference will ever only be given out one at a - // time. - f(unsafe { &mut *self.data.get() }) - } -} diff --git a/.11_exceptions_groundwork/src/vectors.S b/.11_exceptions_groundwork/src/vectors.S deleted file mode 100644 index b2f294c8..00000000 --- a/.11_exceptions_groundwork/src/vectors.S +++ /dev/null @@ -1,113 +0,0 @@ -// -// MIT License -// -// Copyright (c) 2018-2019 Andre Richter -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -.macro SAVE_CONTEXT_CALL_HANDLER_AND_RESTORE handler -.balign 0x80 - - sub sp, sp, #16 * 17 - - 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] - - mrs x1, SPSR_EL1 - mrs x2, ELR_EL1 - - stp x30, x1, [sp, #16 * 15] - str x2, [sp, #16 * 16] - - mov x0, sp - bl \handler - b __restore_context -.endm - -.macro FIQ_DUMMY -.balign 0x80 -1: wfe - b 1b -.endm - -// The vector definitions -.section .vectors, "ax" -.global __exception_vectors_start -__exception_vectors_start: - SAVE_CONTEXT_CALL_HANDLER_AND_RESTORE current_el0_synchronous // 0x000 - SAVE_CONTEXT_CALL_HANDLER_AND_RESTORE current_el0_irq // 0x080 - FIQ_DUMMY // 0x100 - SAVE_CONTEXT_CALL_HANDLER_AND_RESTORE current_el0_serror // 0x180 - - SAVE_CONTEXT_CALL_HANDLER_AND_RESTORE current_elx_synchronous // 0x200 - SAVE_CONTEXT_CALL_HANDLER_AND_RESTORE current_elx_irq // 0x280 - FIQ_DUMMY // 0x300 - SAVE_CONTEXT_CALL_HANDLER_AND_RESTORE current_elx_serror // 0x380 - - SAVE_CONTEXT_CALL_HANDLER_AND_RESTORE lower_aarch64_synchronous // 0x400 - SAVE_CONTEXT_CALL_HANDLER_AND_RESTORE lower_aarch64_irq // 0x480 - FIQ_DUMMY // 0x500 - SAVE_CONTEXT_CALL_HANDLER_AND_RESTORE lower_aarch64_serror // 0x580 - - SAVE_CONTEXT_CALL_HANDLER_AND_RESTORE lower_aarch32_synchronous // 0x600 - SAVE_CONTEXT_CALL_HANDLER_AND_RESTORE lower_aarch32_irq // 0x680 - FIQ_DUMMY // 0x700 - SAVE_CONTEXT_CALL_HANDLER_AND_RESTORE lower_aarch32_serror // 0x780 - -.global __restore_context -__restore_context: - ldr x19, [sp, #16 * 16] - ldp x30, x20, [sp, #16 * 15] - - msr ELR_EL1, x19 - msr SPSR_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 diff --git a/.X1_JTAG_boot/.cargo/config b/.X1_JTAG_boot/.cargo/config deleted file mode 100644 index de3f84c9..00000000 --- a/.X1_JTAG_boot/.cargo/config +++ /dev/null @@ -1,5 +0,0 @@ -[target.aarch64-unknown-none-softfloat] -rustflags = [ - "-C", "link-arg=-Tlink.ld", - "-C", "target-cpu=cortex-a53", -] diff --git a/.X1_JTAG_boot/Cargo.lock b/.X1_JTAG_boot/Cargo.lock deleted file mode 100644 index b1188c19..00000000 --- a/.X1_JTAG_boot/Cargo.lock +++ /dev/null @@ -1,57 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -[[package]] -name = "cortex-a" -version = "2.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "register 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "jtag_boot" -version = "0.1.0" -dependencies = [ - "cortex-a 2.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "raspi3_boot 0.1.0", - "register 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "panic-abort" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "r0" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "raspi3_boot" -version = "0.1.0" -dependencies = [ - "cortex-a 2.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "panic-abort 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "r0 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "register" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "tock-registers 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tock-registers" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[metadata] -"checksum cortex-a 2.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cbb16c411ab74044f174746a6cbae67bcdebea126e376b5441e5986e6a6aa950" -"checksum panic-abort 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2c14a66511ed17b6a8b4256b868d7fd207836d891db15eea5195dbcaf87e630f" -"checksum r0 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e2a38df5b15c8d5c7e8654189744d8e396bddc18ad48041a500ce52d6948941f" -"checksum register 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "469bb5ddde81d67fb8bba4e14d77689b8166cfd077abe7530591cefe29d05823" -"checksum tock-registers 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c758f5195a2e0df9d9fecf6f506506b2766ff74cf64db1e995c87e2761a5c3e2" diff --git a/.X1_JTAG_boot/Cargo.toml b/.X1_JTAG_boot/Cargo.toml deleted file mode 100644 index 3db9c194..00000000 --- a/.X1_JTAG_boot/Cargo.toml +++ /dev/null @@ -1,13 +0,0 @@ -[package] -name = "jtag_boot" -version = "0.1.0" -authors = ["Andre Richter "] -edition = "2018" - -[dependencies] -raspi3_boot = { path = "raspi3_boot" } -cortex-a = "2.3.1" -register = "0.3.3" - -[package.metadata.cargo-xbuild] -sysroot_path = "../xbuild_sysroot" diff --git a/.X1_JTAG_boot/Makefile b/.X1_JTAG_boot/Makefile deleted file mode 100644 index 6e5b8124..00000000 --- a/.X1_JTAG_boot/Makefile +++ /dev/null @@ -1,69 +0,0 @@ -# -# MIT License -# -# Copyright (c) 2018-2019 Andre Richter -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# - -TARGET = aarch64-unknown-none-softfloat - -SOURCES = $(wildcard **/*.rs) $(wildcard **/*.S) link.ld - -OBJCOPY = cargo objcopy -- -OBJCOPY_PARAMS = --strip-all -O binary - -UTILS_CONTAINER = andrerichter/raspi3-utils -DOCKER_CMD = docker run -it --rm -v $(shell pwd):/work -w /work -DOCKER_TTY = --privileged -v /dev:/dev -QEMU_CMD = qemu-system-aarch64 -M raspi3 -kernel jtag_boot.img -RASPBOOT_CMD = raspbootcom -RASPBOOT_DEV = /dev/ttyUSB0 -# RASPBOOT_DEV = /dev/ttyACM0 - - -.PHONY: all qemu raspboot clippy clean objdump nm - -all: clean jtag_boot.img - -target/$(TARGET)/release/jtag_boot: $(SOURCES) - cargo xbuild --target=$(TARGET) --release - -jtag_boot.img: target/$(TARGET)/release/jtag_boot - cp $< . - $(OBJCOPY) $(OBJCOPY_PARAMS) $< jtag_boot.img - -qemu: all - $(DOCKER_CMD) $(UTILS_CONTAINER) $(QEMU_CMD) -serial null -serial stdio - -raspboot: all - $(DOCKER_CMD) $(DOCKER_TTY) $(UTILS_CONTAINER) $(RASPBOOT_CMD) \ - $(RASPBOOT_DEV) jtag_boot.img - -clippy: - cargo xclippy --target=$(TARGET) - -clean: - cargo clean - -objdump: - cargo objdump --target $(TARGET) -- -disassemble -print-imm-hex jtag_boot - -nm: - cargo nm --target $(TARGET) -- jtag_boot | sort diff --git a/.X1_JTAG_boot/README.md b/.X1_JTAG_boot/README.md deleted file mode 100644 index d10287c4..00000000 --- a/.X1_JTAG_boot/README.md +++ /dev/null @@ -1,4 +0,0 @@ -# Xtra 1 - JTAG boot - -Not much is happening here. The binary configures the RPi's GPIO pins for `JTAG` -mode and waits for a debugger to connect. diff --git a/.X1_JTAG_boot/jtag_boot b/.X1_JTAG_boot/jtag_boot deleted file mode 100755 index 9bbaa70c0df5d67788db7bd77766858c0eb9fbeb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 67992 zcmeIzNo*Tc9LMp$J#k~ZKxv4f4Irn~ptKcMY{#*4ic1NQk|IcrkU+?F>}l#QNn=k+ z3lc;^NNo`kk=Smu2bP2j2L$o~smqP!fCLDMOAkdXJ+QPu5(MTy_Dqsm^@#(Q?@0C= z|K6MT{_itm`?;Z!`@9~HxQAChlEx>0J<2#8-?Xoc$w*qfl96`t)yMkkW8D76bs~+n z-DphUw&KkG$ahw8jWah50tg_000IagfB*srAb9of+Mx*F6~OOnlN|pG$RcR&$?Bg|&vWwOV$qyfIqud-dwv zuEAb^P;-yS%VTXbqnln{I~&yX_J8}@sJ+HkIaTiQWvUl8%j^R~U5Or_RNHhfs@?f{ zt@gUTr=@kbE-V&2bALYJo%?;aF?acywz)g5lMk*Kp83m$%qPYB;)kA@(Z}@lgV8x3 z2%Sl%ZRG~%bNbKzSzF%2kIouyE$9BK zWdrLwb&WuMjng{zd)=#Di$8F~?w-555*s|u`hV227qsv4GxzHK*rE63p1H-s_PM3@ zp@lO>?&}MBjote7o(J^h-*nyV7JUtR{FlzDqn*`1zaR^Cc3z*M7o2+?e4_MZ_s;D0 z`@2h(?t`TxX0-d^gJ!;Bb{8fmCd`5r4YvFu>N6&7@@uVmKv#=A(IOvdk(({@XEhh` z%0;j4c-8TI{oErFxjH}Ym-#BaDG8+o`zE>X)oYDu&_S7jk888`>p(VZftVWiuOG{zHhu7>$|%!J{|3C)e&pe5pUIzXw}gtkzzD1k)yhr zzQrW>_(KEB^~B-_%<_bJFlSC!>NUmd%Q3 zY0dq;sYEfA=r0z`0kfFUny=d9z@gGaDL0)jTj^bT_Nbop9iFx-dZn4p_s8?8L_U@7 zP44YAhvZPcG+|$!Oy?pa*~oMv9+{5!M)H+<(^PwOWgF4q32UTuz>M6Vjr2WjmM3-g zy~$Lu(3^;l@RO=;N9ncU~v zPDOv0mOJVv`u}>>(XOBDk?t_}ckH76CfLX3`uoaTBVGBtPEYL>4JUHHSAL^;WMe>c z+NrU-wlhV&aj!q@blUq1>C4^S24}GTzb&urMD^yVudz~eb*Sgf>))lBTl?yvZ#&m- KYbvh!`hNi)Ecn|1 diff --git a/.X1_JTAG_boot/jtag_boot.img b/.X1_JTAG_boot/jtag_boot.img deleted file mode 100755 index 85fa18341e26e07acdc4109d54c7a71202e00ff5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 775 zcmZ8fO-vI(6n?YQ%I-oW)GkQX?BY+-mdL?It*0)QMvEaa%Oo5KDcJM?5=_Au4F{VT z62J?a;LlAs7;VqSWN-Z3Fdj_Ai@9j&7?&@Ci z+c*GA8FZI(-X)VYODAAI2Us=0cz@8YyNj@FO+n5IetI$c2D8!u@Ag`tsu0r&5jdw1 zaF!6)`@vE0jy?vCngnO32eBb=1m2oJECbGQ6ghp$P_8o~HN{RKtah(=F< zFGSo6-B_n94$d=4E9F#RfAdMny;z}gLGOiZ&I?SB4`jy`VD}`m8XPg5faV<@LN6%_ zHz#oBqTd?MJld$Y{)@91*4K$v8kc}A9x^Yjs$i=c_~awt)9=%467jmW2iQ`l84V$q z)B+KGn`R#%Cb%NzW#k5tJA?JUQaxOuTA^7(KHyC42t-_}hK1M78fSOWql_NA(c@|K z82is-Cwgr1#~b|SKL69hUPGhlW$PzrN{1gcl)A<`-u;Zd3NNy9csO`A5IIU3`ad`; zB3GUtzO&FVh%DpI6%4tj%?@G2h+NvjISQ - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -ENTRY(_boot_cores); - -SECTIONS -{ - . = 0x80000; - - .text : - { - KEEP(*(.text.boot)) *(.text .text.*) - } - - .rodata : - { - *(.rodata .rodata.*) - } - - .data : - { - *(.data .data.*) - } - - .bss ALIGN(8): - { - __bss_start = .; - *(.bss .bss.*) - *(COMMON) - __bss_end = .; - } - - /DISCARD/ : { *(.comment) *(.gnu*) *(.note*) *(.eh_frame*) } -} diff --git a/.X1_JTAG_boot/raspi3_boot/Cargo.toml b/.X1_JTAG_boot/raspi3_boot/Cargo.toml deleted file mode 100644 index 024fd184..00000000 --- a/.X1_JTAG_boot/raspi3_boot/Cargo.toml +++ /dev/null @@ -1,10 +0,0 @@ -[package] -name = "raspi3_boot" -version = "0.1.0" -authors = ["Andre Richter "] -edition = "2018" - -[dependencies] -cortex-a = "2.7.0" -panic-abort = "0.3.1" -r0 = "0.2.2" diff --git a/.X1_JTAG_boot/raspi3_boot/src/lib.rs b/.X1_JTAG_boot/raspi3_boot/src/lib.rs deleted file mode 100644 index a6b59ef1..00000000 --- a/.X1_JTAG_boot/raspi3_boot/src/lib.rs +++ /dev/null @@ -1,102 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2018 Jorge Aparicio - * Copyright (c) 2018-2019 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#![deny(missing_docs)] -#![deny(warnings)] -#![no_std] - -//! Low-level boot of the Raspberry's processor - -extern crate panic_abort; - -/// Type check the user-supplied entry function. -#[macro_export] -macro_rules! entry { - ($path:path) => { - /// # Safety - /// - /// - User must ensure to provide a suitable main function for the - /// platform. - #[export_name = "main"] - pub unsafe fn __main() -> ! { - // type check the given path - let f: fn() -> ! = $path; - - f() - } - }; -} - -/// Reset function. -/// -/// Initializes the bss section before calling into the user's `main()`. -/// -/// # Safety -/// -/// - Only a single core must be active and running this function. -unsafe fn reset() -> ! { - extern "C" { - // Boundaries of the .bss section, provided by the linker script - static mut __bss_start: u64; - static mut __bss_end: u64; - } - - // Zeroes the .bss section - r0::zero_bss(&mut __bss_start, &mut __bss_end); - - extern "Rust" { - fn main() -> !; - } - - main(); -} - -/// Entrypoint of the processor. -/// -/// Parks all cores except core0, and then jumps to the internal -/// `reset()` function. -/// -/// # Safety -/// -/// - Linker script must ensure to place this function at `0x80_000`. -#[link_section = ".text.boot"] -#[no_mangle] -pub unsafe extern "C" fn _boot_cores() -> ! { - use cortex_a::{asm, regs::*}; - - const CORE_0: u64 = 0; - const CORE_MASK: u64 = 0x3; - const STACK_START: u64 = 0x80_000; - - if CORE_0 == MPIDR_EL1.get() & CORE_MASK { - SP.set(STACK_START); - reset() - } else { - // if not core0, infinitely wait for events - loop { - asm::wfe(); - } - } -} diff --git a/.X1_JTAG_boot/src/gpio.rs b/.X1_JTAG_boot/src/gpio.rs deleted file mode 100644 index ac23f945..00000000 --- a/.X1_JTAG_boot/src/gpio.rs +++ /dev/null @@ -1,166 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2018-2019 Andre Richter - * Copyright (c) 2019 Nao Taco - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -use core::ops; -use register::{mmio::ReadWrite, register_bitfields}; - -// Descriptions taken from -// https://github.com/raspberrypi/documentation/files/1888662/BCM2837-ARM-Peripherals.-.Revised.-.V2-1.pdf -register_bitfields! { - u32, - - /// GPIO Function Select 1 - GPFSEL1 [ - /// Pin 15 - FSEL15 OFFSET(15) NUMBITS(3) [ - Input = 0b000, - Output = 0b001, - RXD0 = 0b100, // UART0 - Alternate function 0 - RXD1 = 0b010 // Mini UART - Alternate function 5 - - ], - - /// Pin 14 - FSEL14 OFFSET(12) NUMBITS(3) [ - Input = 0b000, - Output = 0b001, - TXD0 = 0b100, // UART0 - Alternate function 0 - TXD1 = 0b010 // Mini UART - Alternate function 5 - ] - ], - - /// GPIO Function Select 2 - GPFSEL2 [ - /// Pin 27 - FSEL27 OFFSET(21) NUMBITS(3)[ - Input = 0b000, - Output = 0b001, - ARM_TMS = 0b011 // JTAG TMS - Alternate function 4 - ], - - /// Pin 26 - FSEL26 OFFSET(18) NUMBITS(3)[ - Input = 0b000, - Output = 0b001, - ARM_TDI = 0b011 // JTAG TDI - Alternate function 4 - ], - - /// Pin 25 - FSEL25 OFFSET(15) NUMBITS(3)[ - Input = 0b000, - Output = 0b001, - ARM_TCK = 0b011 // JTAG TCK - Alternate function 4 - ], - - /// Pin 24 - FSEL24 OFFSET(12) NUMBITS(3)[ // GPIO24 - Input = 0b000, - Output = 0b001, - ARM_TDO = 0b011 // JTAG TDO - Alternate function 4 - ], - - /// Pin 23 - FSEL23 OFFSET(9) NUMBITS(3)[ - Input = 0b000, - Output = 0b001, - ARM_RTCK = 0b011 // JTAG RTCK - Alternate function 4 - ], - - /// Pin 22 - FSEL22 OFFSET(6) NUMBITS(3)[ - Input = 0b000, - Output = 0b001, - ARM_TRST = 0b011 // JTAG TRST - Alternate function 4 - ] - ], - - /// GPIO Pull-up/down Clock Register 0 - GPPUDCLK0 [ - /// Pin 15 - PUDCLK15 OFFSET(15) NUMBITS(1) [ - NoEffect = 0, - AssertClock = 1 - ], - - /// Pin 14 - PUDCLK14 OFFSET(14) NUMBITS(1) [ - NoEffect = 0, - AssertClock = 1 - ] - ] -} - -#[allow(non_snake_case)] -#[repr(C)] -pub struct RegisterBlock { - pub GPFSEL0: ReadWrite, // 0x00 - pub GPFSEL1: ReadWrite, // 0x04 - pub GPFSEL2: ReadWrite, // 0x08 - pub GPFSEL3: ReadWrite, // 0x0C - pub GPFSEL4: ReadWrite, // 0x10 - pub GPFSEL5: ReadWrite, // 0x14 - __reserved_0: u32, // 0x18 - GPSET0: ReadWrite, // 0x1C - GPSET1: ReadWrite, // 0x20 - __reserved_1: u32, // - GPCLR0: ReadWrite, // 0x28 - __reserved_2: [u32; 2], // - GPLEV0: ReadWrite, // 0x34 - GPLEV1: ReadWrite, // 0x38 - __reserved_3: u32, // - GPEDS0: ReadWrite, // 0x40 - GPEDS1: ReadWrite, // 0x44 - __reserved_4: [u32; 7], // - GPHEN0: ReadWrite, // 0x64 - GPHEN1: ReadWrite, // 0x68 - __reserved_5: [u32; 10], // - pub GPPUD: ReadWrite, // 0x94 - pub GPPUDCLK0: ReadWrite, // 0x98 - pub GPPUDCLK1: ReadWrite, // 0x9C -} - -/// Public interface to the GPIO MMIO area -pub struct GPIO { - base_addr: usize, -} - -impl ops::Deref for GPIO { - type Target = RegisterBlock; - - fn deref(&self) -> &Self::Target { - unsafe { &*self.ptr() } - } -} - -impl GPIO { - pub fn new(base_addr: usize) -> GPIO { - GPIO { base_addr } - } - - /// Returns a pointer to the register block - fn ptr(&self) -> *const RegisterBlock { - self.base_addr as *const _ - } -} diff --git a/.X1_JTAG_boot/src/main.rs b/.X1_JTAG_boot/src/main.rs deleted file mode 100644 index 23cbd132..00000000 --- a/.X1_JTAG_boot/src/main.rs +++ /dev/null @@ -1,65 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2018-2019 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#![no_std] -#![no_main] - -const MMIO_BASE: usize = 0x3F00_0000; -const GPIO_BASE: usize = MMIO_BASE + 0x0020_0000; -const MINI_UART_BASE: usize = MMIO_BASE + 0x0021_5000; - -mod gpio; -mod mini_uart; - -pub fn setup_jtag(gpio: &gpio::GPIO) { - gpio.GPFSEL2.modify( - gpio::GPFSEL2::FSEL27::ARM_TMS - + gpio::GPFSEL2::FSEL26::ARM_TDI - + gpio::GPFSEL2::FSEL25::ARM_TCK - + gpio::GPFSEL2::FSEL24::ARM_TDO - + gpio::GPFSEL2::FSEL23::ARM_RTCK - + gpio::GPFSEL2::FSEL22::ARM_TRST, - ); -} - -fn kernel_entry() -> ! { - let gpio = gpio::GPIO::new(GPIO_BASE); - - //------------------------------------------------------------ - // Instantiate MiniUart - //------------------------------------------------------------ - let mini_uart = mini_uart::MiniUart::new(MINI_UART_BASE); - mini_uart.init(&gpio); - - //------------------------------------------------------------ - // Configure JTAG pins - //------------------------------------------------------------ - setup_jtag(&gpio); - - mini_uart.puts("\n[i] JTAG is live. Please connect.\n"); - - loop {} -} - -raspi3_boot::entry!(kernel_entry); diff --git a/.X1_JTAG_boot/src/mini_uart.rs b/.X1_JTAG_boot/src/mini_uart.rs deleted file mode 100644 index db21db49..00000000 --- a/.X1_JTAG_boot/src/mini_uart.rs +++ /dev/null @@ -1,218 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2018-2019 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -use super::gpio; -use core::ops; -use cortex_a::asm; -use register::{mmio::*, register_bitfields}; - -// Auxilary mini UART registers -// -// Descriptions taken from -// https://github.com/raspberrypi/documentation/files/1888662/BCM2837-ARM-Peripherals.-.Revised.-.V2-1.pdf -register_bitfields! { - u32, - - /// Auxiliary enables - AUX_ENABLES [ - /// If set the mini UART is enabled. The UART will immediately - /// start receiving data, especially if the UART1_RX line is - /// low. - /// If clear the mini UART is disabled. That also disables any - /// mini UART register access - MINI_UART_ENABLE OFFSET(0) NUMBITS(1) [] - ], - - /// Mini Uart Interrupt Identify - AUX_MU_IIR [ - /// Writing with bit 1 set will clear the receive FIFO - /// Writing with bit 2 set will clear the transmit FIFO - FIFO_CLEAR OFFSET(1) NUMBITS(2) [ - Rx = 0b01, - Tx = 0b10, - All = 0b11 - ] - ], - - /// Mini Uart Line Control - AUX_MU_LCR [ - /// Mode the UART works in - DATA_SIZE OFFSET(0) NUMBITS(2) [ - SevenBit = 0b00, - EightBit = 0b11 - ] - ], - - /// Mini Uart Line Status - AUX_MU_LSR [ - /// This bit is set if the transmit FIFO is empty and the transmitter is - /// idle. (Finished shifting out the last bit). - TX_IDLE OFFSET(6) NUMBITS(1) [], - - /// This bit is set if the transmit FIFO can accept at least - /// one byte. - TX_EMPTY OFFSET(5) NUMBITS(1) [], - - /// This bit is set if the receive FIFO holds at least 1 - /// symbol. - DATA_READY OFFSET(0) NUMBITS(1) [] - ], - - /// Mini Uart Extra Control - AUX_MU_CNTL [ - /// If this bit is set the mini UART transmitter is enabled. - /// If this bit is clear the mini UART transmitter is disabled. - TX_EN OFFSET(1) NUMBITS(1) [ - Disabled = 0, - Enabled = 1 - ], - - /// If this bit is set the mini UART receiver is enabled. - /// If this bit is clear the mini UART receiver is disabled. - RX_EN OFFSET(0) NUMBITS(1) [ - Disabled = 0, - Enabled = 1 - ] - ], - - /// Mini Uart Baudrate - AUX_MU_BAUD [ - /// Mini UART baudrate counter - RATE OFFSET(0) NUMBITS(16) [] - ] -} - -#[allow(non_snake_case)] -#[repr(C)] -pub struct RegisterBlock { - __reserved_0: u32, // 0x00 - AUX_ENABLES: ReadWrite, // 0x04 - __reserved_1: [u32; 14], // 0x08 - AUX_MU_IO: ReadWrite, // 0x40 - Mini Uart I/O Data - AUX_MU_IER: WriteOnly, // 0x44 - Mini Uart Interrupt Enable - AUX_MU_IIR: WriteOnly, // 0x48 - AUX_MU_LCR: WriteOnly, // 0x4C - AUX_MU_MCR: WriteOnly, // 0x50 - AUX_MU_LSR: ReadOnly, // 0x54 - __reserved_2: [u32; 2], // 0x58 - AUX_MU_CNTL: WriteOnly, // 0x60 - __reserved_3: u32, // 0x64 - AUX_MU_BAUD: WriteOnly, // 0x68 -} - -pub struct MiniUart { - base_addr: usize, -} - -/// Deref to RegisterBlock -/// -/// Allows writing -/// ``` -/// self.MU_IER.read() -/// ``` -/// instead of something along the lines of -/// ``` -/// unsafe { (*MiniUart::ptr()).MU_IER.read() } -/// ``` -impl ops::Deref for MiniUart { - type Target = RegisterBlock; - - fn deref(&self) -> &Self::Target { - unsafe { &*self.ptr() } - } -} - -impl MiniUart { - pub fn new(base_addr: usize) -> MiniUart { - MiniUart { base_addr } - } - - /// Returns a pointer to the register block - fn ptr(&self) -> *const RegisterBlock { - self.base_addr as *const _ - } - - ///Set baud rate and characteristics (115200 8N1) and map to GPIO - pub fn init(&self, gpio: &gpio::GPIO) { - // initialize UART - self.AUX_ENABLES.modify(AUX_ENABLES::MINI_UART_ENABLE::SET); - self.AUX_MU_IER.set(0); - self.AUX_MU_CNTL.set(0); - self.AUX_MU_LCR.write(AUX_MU_LCR::DATA_SIZE::EightBit); - self.AUX_MU_MCR.set(0); - self.AUX_MU_IER.set(0); - self.AUX_MU_IIR.write(AUX_MU_IIR::FIFO_CLEAR::All); - self.AUX_MU_BAUD.write(AUX_MU_BAUD::RATE.val(270)); // 115200 baud - - // map UART1 to GPIO pins - gpio.GPFSEL1 - .modify(gpio::GPFSEL1::FSEL14::TXD1 + gpio::GPFSEL1::FSEL15::RXD1); - - gpio.GPPUD.set(0); // enable pins 14 and 15 - for _ in 0..150 { - asm::nop(); - } - - gpio.GPPUDCLK0 - .write(gpio::GPPUDCLK0::PUDCLK14::AssertClock + gpio::GPPUDCLK0::PUDCLK15::AssertClock); - for _ in 0..150 { - asm::nop(); - } - - gpio.GPPUDCLK0.set(0); - - self.AUX_MU_CNTL - .write(AUX_MU_CNTL::RX_EN::Enabled + AUX_MU_CNTL::TX_EN::Enabled); - - // Clear FIFOs before using the device - self.AUX_MU_IIR.write(AUX_MU_IIR::FIFO_CLEAR::All); - } - - /// Send a character - fn putc(&self, c: char) { - // wait until we can send - loop { - if self.AUX_MU_LSR.is_set(AUX_MU_LSR::TX_EMPTY) { - break; - } - - asm::nop(); - } - - // write the character to the buffer - self.AUX_MU_IO.set(c as u32); - } - - /// Display a string - pub fn puts(&self, string: &str) { - for c in string.chars() { - // convert newline to carrige return + newline - if c == '\n' { - self.putc('\r') - } - - self.putc(c); - } - } -}