diff --git a/01_bareminimum/Makefile b/01_bareminimum/Makefile index 9283b7c3..dbf18840 100644 --- a/01_bareminimum/Makefile +++ b/01_bareminimum/Makefile @@ -24,6 +24,8 @@ TARGET = aarch64-unknown-none +SOURCES = $(wildcard **/*.rs) $(wildcard **/*.S) link.ld + OBJCOPY = cargo objcopy -- OBJCOPY_PARAMS = --strip-all -O binary @@ -31,26 +33,18 @@ UTILS_CONTAINER = andrerichter/raspi3-utils DOCKER_CMD = docker run -it --rm -v $(shell pwd):/work -w /work QEMU_CMD = qemu-system-aarch64 -M raspi3 -kernel kernel8.img -all: clean kernel8.img +.PHONY: all qemu clippy clean objdump nm -target/$(TARGET)/debug/kernel8: src/main.rs - cargo xbuild --target=$(TARGET) - cp $@ . +all: clean kernel8.img -target/$(TARGET)/release/kernel8: src/main.rs +target/$(TARGET)/release/kernel8: $(SOURCES) cargo xbuild --target=$(TARGET) --release - cp $@ . - -ifeq ($(DEBUG),1) -kernel8: target/$(TARGET)/debug/kernel8 -else -kernel8: target/$(TARGET)/release/kernel8 -endif -kernel8.img: kernel8 +kernel8.img: target/$(TARGET)/release/kernel8 + cp $< . $(OBJCOPY) $(OBJCOPY_PARAMS) $< kernel8.img -qemu: +qemu: all $(DOCKER_CMD) $(UTILS_CONTAINER) $(QEMU_CMD) -d in_asm clean: diff --git a/02_multicore_rust/Makefile b/02_multicore_rust/Makefile index 3552607b..6cfaf5cb 100644 --- a/02_multicore_rust/Makefile +++ b/02_multicore_rust/Makefile @@ -24,6 +24,8 @@ TARGET = aarch64-unknown-none +SOURCES = $(wildcard **/*.rs) $(wildcard **/*.S) link.ld + OBJCOPY = cargo objcopy -- OBJCOPY_PARAMS = --strip-all -O binary @@ -31,26 +33,18 @@ UTILS_CONTAINER = andrerichter/raspi3-utils DOCKER_CMD = docker run -it --rm -v $(shell pwd):/work -w /work QEMU_CMD = qemu-system-aarch64 -M raspi3 -kernel kernel8.img -all: clean kernel8.img +.PHONY: all qemu clippy clean objdump nm -target/$(TARGET)/debug/kernel8: src/main.rs - cargo xbuild --target=$(TARGET) - cp $@ . +all: clean kernel8.img -target/$(TARGET)/release/kernel8: src/main.rs +target/$(TARGET)/release/kernel8: $(SOURCES) cargo xbuild --target=$(TARGET) --release - cp $@ . - -ifeq ($(DEBUG),1) -kernel8: target/$(TARGET)/debug/kernel8 -else -kernel8: target/$(TARGET)/release/kernel8 -endif -kernel8.img: kernel8 +kernel8.img: target/$(TARGET)/release/kernel8 + cp $< . $(OBJCOPY) $(OBJCOPY_PARAMS) $< kernel8.img -qemu: +qemu: all $(DOCKER_CMD) $(UTILS_CONTAINER) $(QEMU_CMD) -d in_asm clippy: diff --git a/02_multicore_rust/src/main.rs b/02_multicore_rust/src/main.rs index a35bd169..08a6b7e4 100644 --- a/02_multicore_rust/src/main.rs +++ b/02_multicore_rust/src/main.rs @@ -25,8 +25,8 @@ #![no_std] #![no_main] -raspi3_boot::entry!(kernel_entry); - fn kernel_entry() -> ! { loop {} } + +raspi3_boot::entry!(kernel_entry); diff --git a/03_uart1/Makefile b/03_uart1/Makefile index d957691c..cfe6c745 100644 --- a/03_uart1/Makefile +++ b/03_uart1/Makefile @@ -24,6 +24,8 @@ TARGET = aarch64-unknown-none +SOURCES = $(wildcard **/*.rs) $(wildcard **/*.S) link.ld + OBJCOPY = cargo objcopy -- OBJCOPY_PARAMS = --strip-all -O binary @@ -31,26 +33,18 @@ UTILS_CONTAINER = andrerichter/raspi3-utils DOCKER_CMD = docker run -it --rm -v $(shell pwd):/work -w /work QEMU_CMD = qemu-system-aarch64 -M raspi3 -kernel kernel8.img -all: clean kernel8.img +.PHONY: all qemu clippy clean objdump nm -target/$(TARGET)/debug/kernel8: src/main.rs - cargo xbuild --target=$(TARGET) - cp $@ . +all: clean kernel8.img -target/$(TARGET)/release/kernel8: src/main.rs +target/$(TARGET)/release/kernel8: $(SOURCES) cargo xbuild --target=$(TARGET) --release - cp $@ . - -ifeq ($(DEBUG),1) -kernel8: target/$(TARGET)/debug/kernel8 -else -kernel8: target/$(TARGET)/release/kernel8 -endif -kernel8.img: kernel8 +kernel8.img: target/$(TARGET)/release/kernel8 + cp $< . $(OBJCOPY) $(OBJCOPY_PARAMS) $< kernel8.img -qemu: +qemu: all $(DOCKER_CMD) $(UTILS_CONTAINER) $(QEMU_CMD) -serial null -serial stdio clippy: diff --git a/03_uart1/README.md b/03_uart1/README.md index 5978705c..979892cc 100644 --- a/03_uart1/README.md +++ b/03_uart1/README.md @@ -43,8 +43,8 @@ the host PC. ```console ferris@box:~$ make qemu - -Hello Rustacean! +[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 diff --git a/03_uart1/kernel8 b/03_uart1/kernel8 index 92f12ee2..8b7e9a3c 100755 Binary files a/03_uart1/kernel8 and b/03_uart1/kernel8 differ diff --git a/03_uart1/kernel8.img b/03_uart1/kernel8.img index 3acb27e5..94807c19 100755 Binary files a/03_uart1/kernel8.img and b/03_uart1/kernel8.img differ diff --git a/03_uart1/src/main.rs b/03_uart1/src/main.rs index 7e31dedf..6feec605 100644 --- a/03_uart1/src/main.rs +++ b/03_uart1/src/main.rs @@ -31,19 +31,21 @@ const MMIO_BASE: u32 = 0x3F00_0000; mod gpio; mod uart; -raspi3_boot::entry!(kernel_entry); - fn kernel_entry() -> ! { let uart = uart::MiniUart::new(); // set up serial console uart.init(); + uart.puts("\n[0] UART is live!\n"); - uart.getc(); // Press a key first before being greeted - uart.puts("Hello Rustacean!\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/04_mailboxes/Makefile b/04_mailboxes/Makefile index d957691c..4797e77b 100644 --- a/04_mailboxes/Makefile +++ b/04_mailboxes/Makefile @@ -24,6 +24,8 @@ TARGET = aarch64-unknown-none +SOURCES = $(wildcard **/*.rs) $(wildcard **/*.S) link.ld + OBJCOPY = cargo objcopy -- OBJCOPY_PARAMS = --strip-all -O binary @@ -31,27 +33,19 @@ UTILS_CONTAINER = andrerichter/raspi3-utils DOCKER_CMD = docker run -it --rm -v $(shell pwd):/work -w /work QEMU_CMD = qemu-system-aarch64 -M raspi3 -kernel kernel8.img -all: clean kernel8.img +.PHONY: all qemu clippy clean objdump nm -target/$(TARGET)/debug/kernel8: src/main.rs - cargo xbuild --target=$(TARGET) - cp $@ . +all: clean kernel8.img -target/$(TARGET)/release/kernel8: src/main.rs +target/$(TARGET)/release/kernel8: $(SOURCES) cargo xbuild --target=$(TARGET) --release - cp $@ . - -ifeq ($(DEBUG),1) -kernel8: target/$(TARGET)/debug/kernel8 -else -kernel8: target/$(TARGET)/release/kernel8 -endif -kernel8.img: kernel8 +kernel8.img: target/$(TARGET)/release/kernel8 + cp $< . $(OBJCOPY) $(OBJCOPY_PARAMS) $< kernel8.img -qemu: - $(DOCKER_CMD) $(UTILS_CONTAINER) $(QEMU_CMD) -serial null -serial stdio +qemu: all + $(DOCKER_CMD) $(UTILS_CONTAINER) $(QEMU_CMD) -serial stdio clippy: cargo xclippy --target=$(TARGET) diff --git a/04_mailboxes/kernel8 b/04_mailboxes/kernel8 index 822794ab..32219e4e 100755 Binary files a/04_mailboxes/kernel8 and b/04_mailboxes/kernel8 differ diff --git a/04_mailboxes/kernel8.img b/04_mailboxes/kernel8.img index 9a7cef7a..3ce695a4 100755 Binary files a/04_mailboxes/kernel8.img and b/04_mailboxes/kernel8.img differ diff --git a/04_mailboxes/src/main.rs b/04_mailboxes/src/main.rs index f3bfe851..1f8d42d0 100644 --- a/04_mailboxes/src/main.rs +++ b/04_mailboxes/src/main.rs @@ -34,14 +34,17 @@ mod uart; use core::sync::atomic::{compiler_fence, Ordering}; -raspi3_boot::entry!(kernel_entry); - 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 @@ -64,16 +67,13 @@ fn kernel_entry() -> ! { Ok(()) => true, }; - uart.getc(); // Press a key first before being greeted - uart.puts("Hello Rustacean!\n"); - if serial_avail { - uart.puts("My serial number is: "); + uart.puts("[i] My serial number is: 0x"); uart.hex(mbox.buffer[6]); uart.hex(mbox.buffer[5]); uart.puts("\n"); } else { - uart.puts("Unable to query serial!\n"); + uart.puts("[i] Unable to query serial!\n"); } // echo everything back @@ -81,3 +81,5 @@ fn kernel_entry() -> ! { uart.send(uart.getc()); } } + +raspi3_boot::entry!(kernel_entry); diff --git a/05_uart0/Makefile b/05_uart0/Makefile index ee81d528..4797e77b 100644 --- a/05_uart0/Makefile +++ b/05_uart0/Makefile @@ -24,6 +24,8 @@ TARGET = aarch64-unknown-none +SOURCES = $(wildcard **/*.rs) $(wildcard **/*.S) link.ld + OBJCOPY = cargo objcopy -- OBJCOPY_PARAMS = --strip-all -O binary @@ -31,26 +33,18 @@ UTILS_CONTAINER = andrerichter/raspi3-utils DOCKER_CMD = docker run -it --rm -v $(shell pwd):/work -w /work QEMU_CMD = qemu-system-aarch64 -M raspi3 -kernel kernel8.img -all: clean kernel8.img +.PHONY: all qemu clippy clean objdump nm -target/$(TARGET)/debug/kernel8: src/main.rs - cargo xbuild --target=$(TARGET) - cp $@ . +all: clean kernel8.img -target/$(TARGET)/release/kernel8: src/main.rs +target/$(TARGET)/release/kernel8: $(SOURCES) cargo xbuild --target=$(TARGET) --release - cp $@ . - -ifeq ($(DEBUG),1) -kernel8: target/$(TARGET)/debug/kernel8 -else -kernel8: target/$(TARGET)/release/kernel8 -endif -kernel8.img: kernel8 +kernel8.img: target/$(TARGET)/release/kernel8 + cp $< . $(OBJCOPY) $(OBJCOPY_PARAMS) $< kernel8.img -qemu: +qemu: all $(DOCKER_CMD) $(UTILS_CONTAINER) $(QEMU_CMD) -serial stdio clippy: diff --git a/05_uart0/kernel8 b/05_uart0/kernel8 index 9f71b984..c647911a 100755 Binary files a/05_uart0/kernel8 and b/05_uart0/kernel8 differ diff --git a/05_uart0/kernel8.img b/05_uart0/kernel8.img index 9180dac2..246f1439 100755 Binary files a/05_uart0/kernel8.img and b/05_uart0/kernel8.img differ diff --git a/05_uart0/src/main.rs b/05_uart0/src/main.rs index b1493f97..7ccca746 100644 --- a/05_uart0/src/main.rs +++ b/05_uart0/src/main.rs @@ -34,17 +34,22 @@ mod uart; use core::sync::atomic::{compiler_fence, Ordering}; -raspi3_boot::entry!(kernel_entry); - 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 + 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 @@ -66,16 +71,13 @@ fn kernel_entry() -> ! { Ok(()) => true, }; - uart.getc(); // Press a key first before being greeted - uart.puts("Hello Rustacean!\n"); - if serial_avail { - uart.puts("My serial number is: "); + uart.puts("[i] My serial number is: 0x"); uart.hex(mbox.buffer[6]); uart.hex(mbox.buffer[5]); uart.puts("\n"); } else { - uart.puts("Unable to query serial!\n"); + uart.puts("[i] Unable to query serial!\n"); } // echo everything back @@ -83,3 +85,5 @@ fn kernel_entry() -> ! { uart.send(uart.getc()); } } + +raspi3_boot::entry!(kernel_entry); diff --git a/06_raspbootin64/Makefile b/06_raspbootin64/Makefile index ee81d528..4797e77b 100644 --- a/06_raspbootin64/Makefile +++ b/06_raspbootin64/Makefile @@ -24,6 +24,8 @@ TARGET = aarch64-unknown-none +SOURCES = $(wildcard **/*.rs) $(wildcard **/*.S) link.ld + OBJCOPY = cargo objcopy -- OBJCOPY_PARAMS = --strip-all -O binary @@ -31,26 +33,18 @@ UTILS_CONTAINER = andrerichter/raspi3-utils DOCKER_CMD = docker run -it --rm -v $(shell pwd):/work -w /work QEMU_CMD = qemu-system-aarch64 -M raspi3 -kernel kernel8.img -all: clean kernel8.img +.PHONY: all qemu clippy clean objdump nm -target/$(TARGET)/debug/kernel8: src/main.rs - cargo xbuild --target=$(TARGET) - cp $@ . +all: clean kernel8.img -target/$(TARGET)/release/kernel8: src/main.rs +target/$(TARGET)/release/kernel8: $(SOURCES) cargo xbuild --target=$(TARGET) --release - cp $@ . - -ifeq ($(DEBUG),1) -kernel8: target/$(TARGET)/debug/kernel8 -else -kernel8: target/$(TARGET)/release/kernel8 -endif -kernel8.img: kernel8 +kernel8.img: target/$(TARGET)/release/kernel8 + cp $< . $(OBJCOPY) $(OBJCOPY_PARAMS) $< kernel8.img -qemu: +qemu: all $(DOCKER_CMD) $(UTILS_CONTAINER) $(QEMU_CMD) -serial stdio clippy: diff --git a/06_raspbootin64/src/main.rs b/06_raspbootin64/src/main.rs index 2396cb9a..ff0bb94e 100644 --- a/06_raspbootin64/src/main.rs +++ b/06_raspbootin64/src/main.rs @@ -32,8 +32,6 @@ mod gpio; mod mbox; mod uart; -raspi3_boot::entry!(kernel_entry); - fn kernel_entry() -> ! { let mut mbox = mbox::Mbox::new(); let uart = uart::Uart::new(); @@ -77,3 +75,5 @@ fn kernel_entry() -> ! { // Jump to loaded kernel and never return! kernel() } + +raspi3_boot::entry!(kernel_entry); diff --git a/07_abstraction/Makefile b/07_abstraction/Makefile index ac35bea6..b3e446c7 100644 --- a/07_abstraction/Makefile +++ b/07_abstraction/Makefile @@ -24,6 +24,8 @@ TARGET = aarch64-unknown-none +SOURCES = $(wildcard **/*.rs) $(wildcard **/*.S) link.ld + OBJCOPY = cargo objcopy -- OBJCOPY_PARAMS = --strip-all -O binary @@ -33,29 +35,21 @@ DOCKER_TTY = --privileged -v /dev:/dev QEMU_CMD = qemu-system-aarch64 -M raspi3 -kernel kernel8.img RASPBOOT_CMD = raspbootcom /dev/ttyUSB0 kernel8.img -all: clean kernel8.img +.PHONY: all qemu raspboot clippy clean objdump nm -target/$(TARGET)/debug/kernel8: src/main.rs - cargo xbuild --target=$(TARGET) - cp $@ . +all: clean kernel8.img -target/$(TARGET)/release/kernel8: src/main.rs +target/$(TARGET)/release/kernel8: $(SOURCES) cargo xbuild --target=$(TARGET) --release - cp $@ . - -ifeq ($(DEBUG),1) -kernel8: target/$(TARGET)/debug/kernel8 -else -kernel8: target/$(TARGET)/release/kernel8 -endif -kernel8.img: kernel8 +kernel8.img: target/$(TARGET)/release/kernel8 + cp $< . $(OBJCOPY) $(OBJCOPY_PARAMS) $< kernel8.img -qemu: +qemu: all $(DOCKER_CMD) $(UTILS_CONTAINER) $(QEMU_CMD) -serial stdio -raspboot: +raspboot: all $(DOCKER_CMD) $(DOCKER_TTY) $(UTILS_CONTAINER) $(RASPBOOT_CMD) clippy: diff --git a/07_abstraction/README.md b/07_abstraction/README.md index 29889b9d..0b223a77 100644 --- a/07_abstraction/README.md +++ b/07_abstraction/README.md @@ -64,20 +64,20 @@ replaced it with a Rust function. Why? Because we can, for the fun of it. #[link_section = ".text.boot"] #[no_mangle] pub unsafe extern "C" fn _boot_cores() -> ! { - use cortex_a::{asm, regs::mpidr_el1::*, regs::sp::*}; + use cortex_a::{asm, regs::*}; + const CORE_0: u64 = 0; const CORE_MASK: u64 = 0x3; const STACK_START: u64 = 0x80_000; - match MPIDR_EL1.get() & CORE_MASK { - 0 => { - SP.set(STACK_START); - reset() - } - _ => loop { - // if not core0, infinitely wait for events + if CORE_0 == MPIDR_EL1.get() & CORE_MASK { + SP.set(STACK_START); + reset() + } else { + // if not core0, infinitely wait for events + loop { asm::wfe(); - }, + } } } ``` @@ -93,7 +93,7 @@ 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-raspi3-none-elf.json -- -disassemble -print-imm-hex kernel8 +ferris@box:~$ cargo objdump --target aarch64-unknown-none -- -disassemble -print-imm-hex kernel8 [...] (Some output omitted) @@ -103,9 +103,9 @@ _boot_cores: 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 09 32 orr w8, wzr, #0x800000 + 80014: e8 03 0d 32 orr w8, wzr, #0x80000 80018: 1f 01 00 91 mov sp, x8 - 8001c: 35 02 00 94 bl #0x8d4 + 8001c: e0 01 00 94 bl #0x780 ``` It is important to always manually check this, and not blindly rely on the diff --git a/07_abstraction/kernel8 b/07_abstraction/kernel8 index 3f058c28..24771fac 100755 Binary files a/07_abstraction/kernel8 and b/07_abstraction/kernel8 differ diff --git a/07_abstraction/kernel8.img b/07_abstraction/kernel8.img index 63c5a4b0..038d6139 100755 Binary files a/07_abstraction/kernel8.img and b/07_abstraction/kernel8.img differ diff --git a/07_abstraction/raspi3_boot/src/lib.rs b/07_abstraction/raspi3_boot/src/lib.rs index 38e1c8f7..62654e41 100644 --- a/07_abstraction/raspi3_boot/src/lib.rs +++ b/07_abstraction/raspi3_boot/src/lib.rs @@ -73,17 +73,17 @@ unsafe fn reset() -> ! { 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; - match MPIDR_EL1.get() & CORE_MASK { - 0 => { - SP.set(STACK_START); - reset() - } - _ => loop { - // if not core0, infinitely wait for events + 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/main.rs b/07_abstraction/src/main.rs index 82237308..937b662d 100644 --- a/07_abstraction/src/main.rs +++ b/07_abstraction/src/main.rs @@ -33,19 +33,22 @@ mod uart; use core::sync::atomic::{compiler_fence, Ordering}; -raspi3_boot::entry!(kernel_entry); - 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() { - loop { - cortex_a::asm::wfe() - } // If UART fails, abort early + 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 @@ -67,16 +70,13 @@ fn kernel_entry() -> ! { Ok(()) => true, }; - uart.getc(); // Press a key first before being greeted - uart.puts("Hello Rustacean!\n"); - if serial_avail { - uart.puts("My serial number is: "); + uart.puts("[i] My serial number is: 0x"); uart.hex(mbox.buffer[6]); uart.hex(mbox.buffer[5]); uart.puts("\n"); } else { - uart.puts("Unable to query serial!\n"); + uart.puts("[i] Unable to query serial!\n"); } // echo everything back @@ -84,3 +84,5 @@ fn kernel_entry() -> ! { uart.send(uart.getc()); } } + +raspi3_boot::entry!(kernel_entry); diff --git a/08_random/Makefile b/08_random/Makefile index ac35bea6..b3e446c7 100644 --- a/08_random/Makefile +++ b/08_random/Makefile @@ -24,6 +24,8 @@ TARGET = aarch64-unknown-none +SOURCES = $(wildcard **/*.rs) $(wildcard **/*.S) link.ld + OBJCOPY = cargo objcopy -- OBJCOPY_PARAMS = --strip-all -O binary @@ -33,29 +35,21 @@ DOCKER_TTY = --privileged -v /dev:/dev QEMU_CMD = qemu-system-aarch64 -M raspi3 -kernel kernel8.img RASPBOOT_CMD = raspbootcom /dev/ttyUSB0 kernel8.img -all: clean kernel8.img +.PHONY: all qemu raspboot clippy clean objdump nm -target/$(TARGET)/debug/kernel8: src/main.rs - cargo xbuild --target=$(TARGET) - cp $@ . +all: clean kernel8.img -target/$(TARGET)/release/kernel8: src/main.rs +target/$(TARGET)/release/kernel8: $(SOURCES) cargo xbuild --target=$(TARGET) --release - cp $@ . - -ifeq ($(DEBUG),1) -kernel8: target/$(TARGET)/debug/kernel8 -else -kernel8: target/$(TARGET)/release/kernel8 -endif -kernel8.img: kernel8 +kernel8.img: target/$(TARGET)/release/kernel8 + cp $< . $(OBJCOPY) $(OBJCOPY_PARAMS) $< kernel8.img -qemu: +qemu: all $(DOCKER_CMD) $(UTILS_CONTAINER) $(QEMU_CMD) -serial stdio -raspboot: +raspboot: all $(DOCKER_CMD) $(DOCKER_TTY) $(UTILS_CONTAINER) $(RASPBOOT_CMD) clippy: diff --git a/08_random/kernel8 b/08_random/kernel8 index f8cdc847..f511cb96 100755 Binary files a/08_random/kernel8 and b/08_random/kernel8 differ diff --git a/08_random/kernel8.img b/08_random/kernel8.img index 1ca65a6b..43c230a6 100755 Binary files a/08_random/kernel8.img and b/08_random/kernel8.img differ diff --git a/08_random/raspi3_boot/src/lib.rs b/08_random/raspi3_boot/src/lib.rs index 38e1c8f7..62654e41 100644 --- a/08_random/raspi3_boot/src/lib.rs +++ b/08_random/raspi3_boot/src/lib.rs @@ -73,17 +73,17 @@ unsafe fn reset() -> ! { 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; - match MPIDR_EL1.get() & CORE_MASK { - 0 => { - SP.set(STACK_START); - reset() - } - _ => loop { - // if not core0, infinitely wait for events + 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/main.rs b/08_random/src/main.rs index 31d7c371..be364ab9 100644 --- a/08_random/src/main.rs +++ b/08_random/src/main.rs @@ -32,26 +32,28 @@ mod mbox; mod rand; mod uart; -raspi3_boot::entry!(kernel_entry); - 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() { - loop { - cortex_a::asm::wfe() - } // If UART fails, abort early + 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.getc(); // Press a key first before being greeted - uart.puts("Hello Rustacean!\n"); + 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 @@ -63,3 +65,5 @@ fn kernel_entry() -> ! { uart.puts("\n"); } } + +raspi3_boot::entry!(kernel_entry); diff --git a/09_delays/Makefile b/09_delays/Makefile index ac35bea6..b3e446c7 100644 --- a/09_delays/Makefile +++ b/09_delays/Makefile @@ -24,6 +24,8 @@ TARGET = aarch64-unknown-none +SOURCES = $(wildcard **/*.rs) $(wildcard **/*.S) link.ld + OBJCOPY = cargo objcopy -- OBJCOPY_PARAMS = --strip-all -O binary @@ -33,29 +35,21 @@ DOCKER_TTY = --privileged -v /dev:/dev QEMU_CMD = qemu-system-aarch64 -M raspi3 -kernel kernel8.img RASPBOOT_CMD = raspbootcom /dev/ttyUSB0 kernel8.img -all: clean kernel8.img +.PHONY: all qemu raspboot clippy clean objdump nm -target/$(TARGET)/debug/kernel8: src/main.rs - cargo xbuild --target=$(TARGET) - cp $@ . +all: clean kernel8.img -target/$(TARGET)/release/kernel8: src/main.rs +target/$(TARGET)/release/kernel8: $(SOURCES) cargo xbuild --target=$(TARGET) --release - cp $@ . - -ifeq ($(DEBUG),1) -kernel8: target/$(TARGET)/debug/kernel8 -else -kernel8: target/$(TARGET)/release/kernel8 -endif -kernel8.img: kernel8 +kernel8.img: target/$(TARGET)/release/kernel8 + cp $< . $(OBJCOPY) $(OBJCOPY_PARAMS) $< kernel8.img -qemu: +qemu: all $(DOCKER_CMD) $(UTILS_CONTAINER) $(QEMU_CMD) -serial stdio -raspboot: +raspboot: all $(DOCKER_CMD) $(DOCKER_TTY) $(UTILS_CONTAINER) $(RASPBOOT_CMD) clippy: diff --git a/09_delays/kernel8 b/09_delays/kernel8 index 23cce42c..12051a78 100755 Binary files a/09_delays/kernel8 and b/09_delays/kernel8 differ diff --git a/09_delays/kernel8.img b/09_delays/kernel8.img index 2e2db8f0..9d9e3d6e 100755 Binary files a/09_delays/kernel8.img and b/09_delays/kernel8.img differ diff --git a/09_delays/raspi3_boot/src/lib.rs b/09_delays/raspi3_boot/src/lib.rs index 38e1c8f7..62654e41 100644 --- a/09_delays/raspi3_boot/src/lib.rs +++ b/09_delays/raspi3_boot/src/lib.rs @@ -73,17 +73,17 @@ unsafe fn reset() -> ! { 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; - match MPIDR_EL1.get() & CORE_MASK { - 0 => { - SP.set(STACK_START); - reset() - } - _ => loop { - // if not core0, infinitely wait for events + 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/main.rs b/09_delays/src/main.rs index d9ce934e..23deae75 100644 --- a/09_delays/src/main.rs +++ b/09_delays/src/main.rs @@ -32,40 +32,42 @@ mod gpio; mod mbox; mod uart; -raspi3_boot::entry!(kernel_entry); - 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() { - loop { - cortex_a::asm::wfe() - } // If UART fails, abort early + 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.getc(); // Press a key first before being greeted - uart.puts("Hello Rustacean!\n"); + uart.puts("[1] Press a key to continue booting... "); + uart.getc(); + uart.puts("Greetings fellow Rustacean!\n"); - uart.puts("Waiting 1_000_000 CPU cycles (ARM CPU): "); + uart.puts("[i] Waiting 1_000_000 CPU cycles (ARM CPU): "); delays::wait_cycles(1_000_000); uart.puts("OK\n"); - uart.puts("Waiting 1 second (ARM CPU): "); + uart.puts("[i] Waiting 1 second (ARM CPU): "); delays::wait_msec(1_000_000); uart.puts("OK\n"); let t = delays::SysTmr::new(); if t.get_system_timer() != 0 { - uart.puts("Waiting 1 second (BCM System Timer): "); + uart.puts("[i] Waiting 1 second (BCM System Timer): "); t.wait_msec_st(1_000_000); uart.puts("OK\n"); } - uart.puts("Looping forever now!\n"); + uart.puts("[i] Looping forever now!\n"); loop { delays::wait_msec(1_000_000); uart.puts("Tick: 1s\n"); } } + +raspi3_boot::entry!(kernel_entry); diff --git a/0A_power/Makefile b/0A_power/Makefile index ac35bea6..b3e446c7 100644 --- a/0A_power/Makefile +++ b/0A_power/Makefile @@ -24,6 +24,8 @@ TARGET = aarch64-unknown-none +SOURCES = $(wildcard **/*.rs) $(wildcard **/*.S) link.ld + OBJCOPY = cargo objcopy -- OBJCOPY_PARAMS = --strip-all -O binary @@ -33,29 +35,21 @@ DOCKER_TTY = --privileged -v /dev:/dev QEMU_CMD = qemu-system-aarch64 -M raspi3 -kernel kernel8.img RASPBOOT_CMD = raspbootcom /dev/ttyUSB0 kernel8.img -all: clean kernel8.img +.PHONY: all qemu raspboot clippy clean objdump nm -target/$(TARGET)/debug/kernel8: src/main.rs - cargo xbuild --target=$(TARGET) - cp $@ . +all: clean kernel8.img -target/$(TARGET)/release/kernel8: src/main.rs +target/$(TARGET)/release/kernel8: $(SOURCES) cargo xbuild --target=$(TARGET) --release - cp $@ . - -ifeq ($(DEBUG),1) -kernel8: target/$(TARGET)/debug/kernel8 -else -kernel8: target/$(TARGET)/release/kernel8 -endif -kernel8.img: kernel8 +kernel8.img: target/$(TARGET)/release/kernel8 + cp $< . $(OBJCOPY) $(OBJCOPY_PARAMS) $< kernel8.img -qemu: +qemu: all $(DOCKER_CMD) $(UTILS_CONTAINER) $(QEMU_CMD) -serial stdio -raspboot: +raspboot: all $(DOCKER_CMD) $(DOCKER_TTY) $(UTILS_CONTAINER) $(RASPBOOT_CMD) clippy: diff --git a/0A_power/kernel8 b/0A_power/kernel8 index 03daaaf5..5d16cb6f 100755 Binary files a/0A_power/kernel8 and b/0A_power/kernel8 differ diff --git a/0A_power/kernel8.img b/0A_power/kernel8.img index d82db789..580552a1 100755 Binary files a/0A_power/kernel8.img and b/0A_power/kernel8.img differ diff --git a/0A_power/raspi3_boot/src/lib.rs b/0A_power/raspi3_boot/src/lib.rs index 38e1c8f7..62654e41 100644 --- a/0A_power/raspi3_boot/src/lib.rs +++ b/0A_power/raspi3_boot/src/lib.rs @@ -73,17 +73,17 @@ unsafe fn reset() -> ! { 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; - match MPIDR_EL1.get() & CORE_MASK { - 0 => { - SP.set(STACK_START); - reset() - } - _ => loop { - // if not core0, infinitely wait for events + 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/main.rs b/0A_power/src/main.rs index 015ef27d..b928ee51 100644 --- a/0A_power/src/main.rs +++ b/0A_power/src/main.rs @@ -33,8 +33,6 @@ mod mbox; mod power; mod uart; -raspi3_boot::entry!(kernel_entry); - fn kernel_entry() -> ! { let gpio = gpio::GPIO::new(); let mut mbox = mbox::Mbox::new(); @@ -42,14 +40,16 @@ fn kernel_entry() -> ! { let power = power::Power::new(); // set up serial console - if uart.init(&mut mbox, &gpio).is_err() { - loop { - cortex_a::asm::wfe() - } // If UART fails, abort early + 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.getc(); // Press a key first before being greeted - uart.puts("Hello Rustacean!\n\n"); + 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: "); @@ -67,3 +67,5 @@ fn kernel_entry() -> ! { } } } + +raspi3_boot::entry!(kernel_entry); diff --git a/0B_exception_levels/Makefile b/0B_exception_levels/Makefile index 98c6812a..b3e446c7 100644 --- a/0B_exception_levels/Makefile +++ b/0B_exception_levels/Makefile @@ -24,6 +24,8 @@ TARGET = aarch64-unknown-none +SOURCES = $(wildcard **/*.rs) $(wildcard **/*.S) link.ld + OBJCOPY = cargo objcopy -- OBJCOPY_PARAMS = --strip-all -O binary @@ -33,23 +35,15 @@ DOCKER_TTY = --privileged -v /dev:/dev QEMU_CMD = qemu-system-aarch64 -M raspi3 -kernel kernel8.img RASPBOOT_CMD = raspbootcom /dev/ttyUSB0 kernel8.img -all: clean kernel8.img +.PHONY: all qemu raspboot clippy clean objdump nm -target/$(TARGET)/debug/kernel8: src/main.rs - cargo xbuild --target=$(TARGET) - cp $@ . +all: clean kernel8.img -target/$(TARGET)/release/kernel8: src/main.rs +target/$(TARGET)/release/kernel8: $(SOURCES) cargo xbuild --target=$(TARGET) --release - cp $@ . - -ifeq ($(DEBUG),1) -kernel8: target/$(TARGET)/debug/kernel8 -else -kernel8: target/$(TARGET)/release/kernel8 -endif -kernel8.img: kernel8 +kernel8.img: target/$(TARGET)/release/kernel8 + cp $< . $(OBJCOPY) $(OBJCOPY_PARAMS) $< kernel8.img qemu: all diff --git a/0B_exception_levels/README.md b/0B_exception_levels/README.md index 29517ea9..5c78df4e 100644 --- a/0B_exception_levels/README.md +++ b/0B_exception_levels/README.md @@ -8,20 +8,20 @@ Cortex-A53 processor: `Exception levels`. TODO: Write rest of tutorial. ```text -raspi3_boot::setup_and_enter_el1_from_el2::hb2c2ac4f6a7ddb7e: - 80954: e8 03 1f aa mov x8, xzr - 80958: e9 07 00 32 orr w9, wzr, #0x3 - 8095c: 4a 00 80 52 mov w10, #0x2 - 80960: 0a 00 b0 72 movk w10, #0x8000, lsl #16 - 80964: 09 e1 1c d5 msr CNTHCTL_EL2, x9 - 80968: 68 e0 1c d5 msr CNTVOFF_EL2, x8 - 8096c: 08 00 00 90 adrp x8, #0x0 - 80970: ab 78 80 52 mov w11, #0x3c5 - 80974: 0a 11 1c d5 msr HCR_EL2, x10 - 80978: ec 03 0d 32 orr w12, wzr, #0x80000 - 8097c: 08 81 24 91 add x8, x8, #0x920 - 80980: 0b 40 1c d5 msr SPSR_EL2, x11 - 80984: 28 40 1c d5 msr ELR_EL2, x8 - 80988: 0c 41 1c d5 msr SP_EL1, x12 - 8098c: e0 03 9f d6 eret +raspi3_boot::setup_and_enter_el1_from_el2::h568f1410ae7cc9b8: + 808c0: e8 03 1f aa mov x8, xzr + 808c4: e9 07 00 32 orr w9, wzr, #0x3 + 808c8: 09 e1 1c d5 msr CNTHCTL_EL2, x9 + 808cc: 4a 00 80 52 mov w10, #0x2 + 808d0: 68 e0 1c d5 msr CNTVOFF_EL2, x8 + 808d4: 08 00 00 90 adrp x8, #0x0 + 808d8: 0a 00 b0 72 movk w10, #0x8000, lsl #16 + 808dc: 0a 11 1c d5 msr HCR_EL2, x10 + 808e0: ab 78 80 52 mov w11, #0x3c5 + 808e4: 0b 40 1c d5 msr SPSR_EL2, x11 + 808e8: ec 03 0d 32 orr w12, wzr, #0x80000 + 808ec: 08 31 22 91 add x8, x8, #0x88c + 808f0: 28 40 1c d5 msr ELR_EL2, x8 + 808f4: 0c 41 1c d5 msr SP_EL1, x12 + 808f8: e0 03 9f d6 eret ``` diff --git a/0B_exception_levels/kernel8 b/0B_exception_levels/kernel8 index dfedbd82..123d60ff 100755 Binary files a/0B_exception_levels/kernel8 and b/0B_exception_levels/kernel8 differ diff --git a/0B_exception_levels/kernel8.img b/0B_exception_levels/kernel8.img index 7d47414a..0e521fda 100755 Binary files a/0B_exception_levels/kernel8.img and b/0B_exception_levels/kernel8.img differ diff --git a/0B_exception_levels/raspi3_boot/src/lib.rs b/0B_exception_levels/raspi3_boot/src/lib.rs index d5ce1ae8..4c2de2a7 100644 --- a/0B_exception_levels/raspi3_boot/src/lib.rs +++ b/0B_exception_levels/raspi3_boot/src/lib.rs @@ -69,6 +69,8 @@ unsafe fn reset() -> ! { 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); @@ -96,7 +98,7 @@ fn setup_and_enter_el1_from_el2() -> ! { // Set up SP_EL1 (stack pointer), which will be used by EL1 once // we "return" to it. - SP_EL1.set(0x80_000); + SP_EL1.set(STACK_START); // Use `eret` to "return" to EL1. This will result in execution of // `reset()` in EL1. @@ -116,10 +118,8 @@ pub unsafe extern "C" fn _boot_cores() -> ! { const CORE_MASK: u64 = 0x3; const EL2: u32 = CurrentEL::EL::EL2.value; - if let CORE_0 = MPIDR_EL1.get() & CORE_MASK { - if let EL2 = CurrentEL.get() { - setup_and_enter_el1_from_el2() - } + 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 diff --git a/0B_exception_levels/src/delays.rs b/0B_exception_levels/src/delays.rs index 693f21d9..130b8ae5 100644 --- a/0B_exception_levels/src/delays.rs +++ b/0B_exception_levels/src/delays.rs @@ -22,6 +22,7 @@ * SOFTWARE. */ +use cortex_a::asm; use cortex_a::regs::*; /* @@ -53,3 +54,15 @@ pub fn wait_msec(n: u32) { // 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/0B_exception_levels/src/gpio.rs b/0B_exception_levels/src/gpio.rs index da6a5be4..608ba532 100644 --- a/0B_exception_levels/src/gpio.rs +++ b/0B_exception_levels/src/gpio.rs @@ -23,6 +23,7 @@ */ use super::MMIO_BASE; +use core::ops; use register::{mmio::ReadWrite, register_bitfields}; // Descriptions taken from @@ -66,10 +67,55 @@ register_bitfields! { ] } -pub const GPFSEL1: *const ReadWrite = - (MMIO_BASE + 0x0020_0004) as *const ReadWrite; +const GPIO_BASE: u32 = MMIO_BASE + 0x200_000; -pub const GPPUD: *const ReadWrite = (MMIO_BASE + 0x0020_0094) as *const ReadWrite; +#[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; -pub const GPPUDCLK0: *const ReadWrite = - (MMIO_BASE + 0x0020_0098) as *const ReadWrite; +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_exception_levels/src/main.rs b/0B_exception_levels/src/main.rs index 6e501672..810e2d90 100644 --- a/0B_exception_levels/src/main.rs +++ b/0B_exception_levels/src/main.rs @@ -36,17 +36,17 @@ 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", + "Testing EL1 access to timer registers:\ + \n Delaying for 3 seconds now.\n", ); - delays::wait_msec(1000); - uart.puts("1.."); - delays::wait_msec(1000); + delays::wait_msec(1_000_000); + uart.puts(" 1.."); + delays::wait_msec(1_000_000); uart.puts("2.."); - delays::wait_msec(1000); + delays::wait_msec(1_000_000); uart.puts( - "3\n\ - Works!\n\n", + "3\ + \n Works!\n\n", ); } @@ -55,10 +55,10 @@ fn check_daif(uart: &uart::Uart) { let daif = DAIF.extract(); for x in &[ - ("D: ", DAIF::D), - ("A: ", DAIF::A), - ("I: ", DAIF::I), - ("F: ", DAIF::F), + (" D: ", DAIF::D), + (" A: ", DAIF::A), + (" I: ", DAIF::I), + (" F: ", DAIF::F), ] { uart.puts(x.0); if daif.is_set(x.1) { @@ -69,24 +69,25 @@ fn check_daif(uart: &uart::Uart) { } } -raspi3_boot::entry!(kernel_entry); - fn kernel_entry() -> ! { + let gpio = gpio::GPIO::new(); let mut mbox = mbox::Mbox::new(); let uart = uart::Uart::new(); // set up serial console - if uart.init(&mut mbox).is_err() { - loop { + 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.getc(); // Press a key first before being greeted - uart.puts("Hello Rustacean!\n\n"); + uart.puts("[1] Press a key to continue booting... "); + uart.getc(); + uart.puts("Greetings fellow Rustacean!\n"); - uart.puts("Executing in EL: "); - uart.hex(CurrentEL.read(CurrentEL::EL)); + uart.puts("[i] Executing in EL: "); + uart.dec(CurrentEL.read(CurrentEL::EL)); uart.puts("\n\n"); check_timer(&uart); @@ -97,3 +98,5 @@ fn kernel_entry() -> ! { uart.send(uart.getc()); } } + +raspi3_boot::entry!(kernel_entry); diff --git a/0B_exception_levels/src/uart.rs b/0B_exception_levels/src/uart.rs index db4c639a..4172e059 100644 --- a/0B_exception_levels/src/uart.rs +++ b/0B_exception_levels/src/uart.rs @@ -23,6 +23,7 @@ */ use super::MMIO_BASE; +use crate::delays; use crate::gpio; use crate::mbox; use core::{ @@ -162,7 +163,7 @@ impl Uart { } ///Set baud rate and characteristics (115200 8N1) and map to GPIO - pub fn init(&self, mbox: &mut mbox::Mbox) -> Result<()> { + pub fn init(&self, mbox: &mut mbox::Mbox, gpio: &gpio::GPIO) -> Result<()> { // turn off UART0 self.CR.set(0); @@ -187,23 +188,18 @@ impl Uart { }; // map UART0 to GPIO pins - unsafe { - (*gpio::GPFSEL1).modify(gpio::GPFSEL1::FSEL14::TXD0 + gpio::GPFSEL1::FSEL15::RXD0); + 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.GPPUD.set(0); // enable pins 14 and 15 + delays::wait_cycles(150); - (*gpio::GPPUDCLK0).modify( - gpio::GPPUDCLK0::PUDCLK14::AssertClock + gpio::GPPUDCLK0::PUDCLK15::AssertClock, - ); - for _ in 0..150 { - asm::nop(); - } + gpio.GPPUDCLK0.modify( + gpio::GPPUDCLK0::PUDCLK14::AssertClock + gpio::GPPUDCLK0::PUDCLK15::AssertClock, + ); + delays::wait_cycles(150); - (*gpio::GPPUDCLK0).set(0); - } + gpio.GPPUDCLK0.set(0); self.ICR.write(ICR::ALL::CLEAR); self.IBRD.write(IBRD::IBRD.val(2)); // Results in 115200 baud @@ -264,23 +260,23 @@ impl Uart { } } - /// Display a binary value in hexadecimal - pub fn hex(&self, d: u32) { - let mut n; + /// 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 0..8 { - // get highest tetrad - n = d.wrapping_shr(28 - i * 4) & 0xF; + for i in digits.iter_mut() { + *i = ((d % 10) + 0x30) as u8 as char; - // 0-9 => '0'-'9', 10-15 => 'A'-'F' - // Add proper offset for ASCII table - if n > 9 { - n += 0x37; - } else { - n += 0x30; + d /= 10; + + if d == 0 { + break; } + } - self.send(n as u8 as char); + for c in digits.iter().rev() { + self.send(*c); } } } diff --git a/0C_virtual_memory/Makefile b/0C_virtual_memory/Makefile index 98c6812a..b3e446c7 100644 --- a/0C_virtual_memory/Makefile +++ b/0C_virtual_memory/Makefile @@ -24,6 +24,8 @@ TARGET = aarch64-unknown-none +SOURCES = $(wildcard **/*.rs) $(wildcard **/*.S) link.ld + OBJCOPY = cargo objcopy -- OBJCOPY_PARAMS = --strip-all -O binary @@ -33,23 +35,15 @@ DOCKER_TTY = --privileged -v /dev:/dev QEMU_CMD = qemu-system-aarch64 -M raspi3 -kernel kernel8.img RASPBOOT_CMD = raspbootcom /dev/ttyUSB0 kernel8.img -all: clean kernel8.img +.PHONY: all qemu raspboot clippy clean objdump nm -target/$(TARGET)/debug/kernel8: src/main.rs - cargo xbuild --target=$(TARGET) - cp $@ . +all: clean kernel8.img -target/$(TARGET)/release/kernel8: src/main.rs +target/$(TARGET)/release/kernel8: $(SOURCES) cargo xbuild --target=$(TARGET) --release - cp $@ . - -ifeq ($(DEBUG),1) -kernel8: target/$(TARGET)/debug/kernel8 -else -kernel8: target/$(TARGET)/release/kernel8 -endif -kernel8.img: kernel8 +kernel8.img: target/$(TARGET)/release/kernel8 + cp $< . $(OBJCOPY) $(OBJCOPY_PARAMS) $< kernel8.img qemu: all diff --git a/0C_virtual_memory/kernel8 b/0C_virtual_memory/kernel8 index b4644b05..68126393 100755 Binary files a/0C_virtual_memory/kernel8 and b/0C_virtual_memory/kernel8 differ diff --git a/0C_virtual_memory/kernel8.img b/0C_virtual_memory/kernel8.img index c0cfc9e8..657c1789 100755 Binary files a/0C_virtual_memory/kernel8.img and b/0C_virtual_memory/kernel8.img differ diff --git a/0C_virtual_memory/raspi3_boot/src/lib.rs b/0C_virtual_memory/raspi3_boot/src/lib.rs index d5ce1ae8..4c2de2a7 100644 --- a/0C_virtual_memory/raspi3_boot/src/lib.rs +++ b/0C_virtual_memory/raspi3_boot/src/lib.rs @@ -69,6 +69,8 @@ unsafe fn reset() -> ! { 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); @@ -96,7 +98,7 @@ fn setup_and_enter_el1_from_el2() -> ! { // Set up SP_EL1 (stack pointer), which will be used by EL1 once // we "return" to it. - SP_EL1.set(0x80_000); + SP_EL1.set(STACK_START); // Use `eret` to "return" to EL1. This will result in execution of // `reset()` in EL1. @@ -116,10 +118,8 @@ pub unsafe extern "C" fn _boot_cores() -> ! { const CORE_MASK: u64 = 0x3; const EL2: u32 = CurrentEL::EL::EL2.value; - if let CORE_0 = MPIDR_EL1.get() & CORE_MASK { - if let EL2 = CurrentEL.get() { - setup_and_enter_el1_from_el2() - } + 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 diff --git a/0C_virtual_memory/src/delays.rs b/0C_virtual_memory/src/delays.rs new file mode 100644 index 00000000..63414e4f --- /dev/null +++ b/0C_virtual_memory/src/delays.rs @@ -0,0 +1,37 @@ +/* + * 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/0C_virtual_memory/src/gpio.rs b/0C_virtual_memory/src/gpio.rs index da6a5be4..608ba532 100644 --- a/0C_virtual_memory/src/gpio.rs +++ b/0C_virtual_memory/src/gpio.rs @@ -23,6 +23,7 @@ */ use super::MMIO_BASE; +use core::ops; use register::{mmio::ReadWrite, register_bitfields}; // Descriptions taken from @@ -66,10 +67,55 @@ register_bitfields! { ] } -pub const GPFSEL1: *const ReadWrite = - (MMIO_BASE + 0x0020_0004) as *const ReadWrite; +const GPIO_BASE: u32 = MMIO_BASE + 0x200_000; -pub const GPPUD: *const ReadWrite = (MMIO_BASE + 0x0020_0094) as *const ReadWrite; +#[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; -pub const GPPUDCLK0: *const ReadWrite = - (MMIO_BASE + 0x0020_0098) as *const ReadWrite; +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_virtual_memory/src/main.rs b/0C_virtual_memory/src/main.rs index 741cf4b2..caf70bab 100644 --- a/0C_virtual_memory/src/main.rs +++ b/0C_virtual_memory/src/main.rs @@ -29,14 +29,14 @@ const MMIO_BASE: u32 = 0x3F00_0000; +mod delays; mod gpio; mod mbox; mod mmu; mod uart; -raspi3_boot::entry!(kernel_entry); - fn kernel_entry() -> ! { + let gpio = gpio::GPIO::new(); let mut mbox = mbox::Mbox::new(); { @@ -44,18 +44,20 @@ fn kernel_entry() -> ! { let uart = uart::Uart::new(uart::UART_PHYS_BASE); // set up serial console - if uart.init(&mut mbox).is_err() { - loop { + 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.getc(); // Press a key first before being greeted - uart.puts("Hello Rustacean!\n\n"); + uart.puts("[1] Press a key to continue booting... "); + uart.getc(); + uart.puts("Greetings fellow Rustacean!\n"); mmu::print_features(&uart); - uart.puts("\nSwitching MMU on now..."); + uart.puts("[2] Switching MMU on now... "); } // After this closure, the UART instance is not valid anymore. unsafe { mmu::init() }; @@ -66,7 +68,7 @@ fn kernel_entry() -> ! { let uart = uart::Uart::new(UART_VIRT_BASE); uart.puts("MMU is live \\o/\n\nWriting through the virtual mapping at 0x"); - uart.hex(UART_VIRT_BASE); + uart.hex(UART_VIRT_BASE as u64); uart.puts(".\n"); // echo everything back @@ -74,3 +76,5 @@ fn kernel_entry() -> ! { uart.send(uart.getc()); } } + +raspi3_boot::entry!(kernel_entry); diff --git a/0C_virtual_memory/src/mmu.rs b/0C_virtual_memory/src/mmu.rs index 8eebdaea..98f76816 100644 --- a/0C_virtual_memory/src/mmu.rs +++ b/0C_virtual_memory/src/mmu.rs @@ -34,13 +34,13 @@ pub fn print_features(uart: &uart::Uart) { if let Some(ID_AA64MMFR0_EL1::TGran4::Value::Supported) = mmfr.read_as_enum(ID_AA64MMFR0_EL1::TGran4) { - uart.puts("MMU: 4 KiB granule supported!\n"); + 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("MMU: Up to 40 Bit physical address range supported!\n"); + uart.puts("[i] MMU: Up to 40 Bit physical address range supported!\n"); } } diff --git a/0C_virtual_memory/src/uart.rs b/0C_virtual_memory/src/uart.rs index 492b3b78..2c0e8a03 100644 --- a/0C_virtual_memory/src/uart.rs +++ b/0C_virtual_memory/src/uart.rs @@ -23,6 +23,7 @@ */ use super::MMIO_BASE; +use crate::delays; use crate::gpio; use crate::mbox; use core::{ @@ -164,7 +165,7 @@ impl Uart { } ///Set baud rate and characteristics (115200 8N1) and map to GPIO - pub fn init(&self, mbox: &mut mbox::Mbox) -> Result<()> { + pub fn init(&self, mbox: &mut mbox::Mbox, gpio: &gpio::GPIO) -> Result<()> { // turn off UART0 self.CR.set(0); @@ -189,23 +190,18 @@ impl Uart { }; // map UART0 to GPIO pins - unsafe { - (*gpio::GPFSEL1).modify(gpio::GPFSEL1::FSEL14::TXD0 + gpio::GPFSEL1::FSEL15::RXD0); + 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.GPPUD.set(0); // enable pins 14 and 15 + delays::wait_cycles(150); - (*gpio::GPPUDCLK0).modify( - gpio::GPPUDCLK0::PUDCLK14::AssertClock + gpio::GPPUDCLK0::PUDCLK15::AssertClock, - ); - for _ in 0..150 { - asm::nop(); - } + gpio.GPPUDCLK0.modify( + gpio::GPPUDCLK0::PUDCLK14::AssertClock + gpio::GPPUDCLK0::PUDCLK15::AssertClock, + ); + delays::wait_cycles(150); - (*gpio::GPPUDCLK0).set(0); - } + gpio.GPPUDCLK0.set(0); self.ICR.write(ICR::ALL::CLEAR); self.IBRD.write(IBRD::IBRD.val(2)); // Results in 115200 baud @@ -267,12 +263,12 @@ impl Uart { } /// Display a binary value in hexadecimal - pub fn hex(&self, d: u32) { + pub fn hex(&self, d: u64) { let mut n; - for i in 0..8 { + for i in 0..16 { // get highest tetrad - n = d.wrapping_shr(28 - i * 4) & 0xF; + n = d.wrapping_shr(60 - i * 4) & 0xF; // 0-9 => '0'-'9', 10-15 => 'A'-'F' // Add proper offset for ASCII table diff --git a/0D_cache_performance/Makefile b/0D_cache_performance/Makefile index 98c6812a..b3e446c7 100644 --- a/0D_cache_performance/Makefile +++ b/0D_cache_performance/Makefile @@ -24,6 +24,8 @@ TARGET = aarch64-unknown-none +SOURCES = $(wildcard **/*.rs) $(wildcard **/*.S) link.ld + OBJCOPY = cargo objcopy -- OBJCOPY_PARAMS = --strip-all -O binary @@ -33,23 +35,15 @@ DOCKER_TTY = --privileged -v /dev:/dev QEMU_CMD = qemu-system-aarch64 -M raspi3 -kernel kernel8.img RASPBOOT_CMD = raspbootcom /dev/ttyUSB0 kernel8.img -all: clean kernel8.img +.PHONY: all qemu raspboot clippy clean objdump nm -target/$(TARGET)/debug/kernel8: src/main.rs - cargo xbuild --target=$(TARGET) - cp $@ . +all: clean kernel8.img -target/$(TARGET)/release/kernel8: src/main.rs +target/$(TARGET)/release/kernel8: $(SOURCES) cargo xbuild --target=$(TARGET) --release - cp $@ . - -ifeq ($(DEBUG),1) -kernel8: target/$(TARGET)/debug/kernel8 -else -kernel8: target/$(TARGET)/release/kernel8 -endif -kernel8.img: kernel8 +kernel8.img: target/$(TARGET)/release/kernel8 + cp $< . $(OBJCOPY) $(OBJCOPY_PARAMS) $< kernel8.img qemu: all diff --git a/0D_cache_performance/README.md b/0D_cache_performance/README.md index 89577d03..6248a0a7 100644 --- a/0D_cache_performance/README.md +++ b/0D_cache_performance/README.md @@ -43,13 +43,13 @@ showcase how much faster it is to operate on DRAM with caching enabled. On my Raspberry, I get the following results: ```text -Benchmarking non-cacheable DRAM modifications at virtual 0x00200000, physical 0x00400000: +Benchmarking non-cacheable DRAM modifications at virtual 0x0000000000200000, physical 0x0000000000400000: 1040 miliseconds. -Benchmarking cacheable DRAM modifications at virtual 0x00400000, physical 0x00400000: +Benchmarking cacheable DRAM modifications at virtual 0x0000000000400000, physical 0x0000000000400000: 53 miliseconds. -With caching, the function is 1862% faster! +With caching, the function is 1800% faster! ``` Impressive, isn't it? diff --git a/0D_cache_performance/kernel8 b/0D_cache_performance/kernel8 index 3f0fed00..3b29dd03 100755 Binary files a/0D_cache_performance/kernel8 and b/0D_cache_performance/kernel8 differ diff --git a/0D_cache_performance/kernel8.img b/0D_cache_performance/kernel8.img index 05fdca45..f630951a 100755 Binary files a/0D_cache_performance/kernel8.img and b/0D_cache_performance/kernel8.img differ diff --git a/0D_cache_performance/raspi3_boot/src/lib.rs b/0D_cache_performance/raspi3_boot/src/lib.rs index d5ce1ae8..4c2de2a7 100644 --- a/0D_cache_performance/raspi3_boot/src/lib.rs +++ b/0D_cache_performance/raspi3_boot/src/lib.rs @@ -69,6 +69,8 @@ unsafe fn reset() -> ! { 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); @@ -96,7 +98,7 @@ fn setup_and_enter_el1_from_el2() -> ! { // Set up SP_EL1 (stack pointer), which will be used by EL1 once // we "return" to it. - SP_EL1.set(0x80_000); + SP_EL1.set(STACK_START); // Use `eret` to "return" to EL1. This will result in execution of // `reset()` in EL1. @@ -116,10 +118,8 @@ pub unsafe extern "C" fn _boot_cores() -> ! { const CORE_MASK: u64 = 0x3; const EL2: u32 = CurrentEL::EL::EL2.value; - if let CORE_0 = MPIDR_EL1.get() & CORE_MASK { - if let EL2 = CurrentEL.get() { - setup_and_enter_el1_from_el2() - } + 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 diff --git a/0D_cache_performance/src/benchmark.rs b/0D_cache_performance/src/benchmark.rs index c63b343b..419684dd 100644 --- a/0D_cache_performance/src/benchmark.rs +++ b/0D_cache_performance/src/benchmark.rs @@ -53,9 +53,9 @@ pub fn run(uart: &uart::Uart) { let cacheable_addr: u64 = 2 * SIZE_2MIB; uart.puts("Benchmarking non-cacheable DRAM modifications at virtual 0x"); - uart.hex(non_cacheable_addr as u32); + uart.hex(non_cacheable_addr); uart.puts(", physical 0x"); - uart.hex(2 * SIZE_2MIB as u32); + uart.hex(2 * SIZE_2MIB); uart.puts(":\n"); let result_nc = match batch_modify_time(non_cacheable_addr) { @@ -71,9 +71,9 @@ pub fn run(uart: &uart::Uart) { }; uart.puts("Benchmarking cacheable DRAM modifications at virtual 0x"); - uart.hex(cacheable_addr as u32); + uart.hex(cacheable_addr); uart.puts(", physical 0x"); - uart.hex(2 * SIZE_2MIB as u32); + uart.hex(2 * SIZE_2MIB); uart.puts(":\n"); let result_c = match batch_modify_time(cacheable_addr) { diff --git a/0D_cache_performance/src/delays.rs b/0D_cache_performance/src/delays.rs new file mode 100644 index 00000000..63414e4f --- /dev/null +++ b/0D_cache_performance/src/delays.rs @@ -0,0 +1,37 @@ +/* + * 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/0D_cache_performance/src/gpio.rs b/0D_cache_performance/src/gpio.rs index da6a5be4..608ba532 100644 --- a/0D_cache_performance/src/gpio.rs +++ b/0D_cache_performance/src/gpio.rs @@ -23,6 +23,7 @@ */ use super::MMIO_BASE; +use core::ops; use register::{mmio::ReadWrite, register_bitfields}; // Descriptions taken from @@ -66,10 +67,55 @@ register_bitfields! { ] } -pub const GPFSEL1: *const ReadWrite = - (MMIO_BASE + 0x0020_0004) as *const ReadWrite; +const GPIO_BASE: u32 = MMIO_BASE + 0x200_000; -pub const GPPUD: *const ReadWrite = (MMIO_BASE + 0x0020_0094) as *const ReadWrite; +#[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; -pub const GPPUDCLK0: *const ReadWrite = - (MMIO_BASE + 0x0020_0098) as *const ReadWrite; +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/0D_cache_performance/src/main.rs b/0D_cache_performance/src/main.rs index 112e1b69..47a823a7 100644 --- a/0D_cache_performance/src/main.rs +++ b/0D_cache_performance/src/main.rs @@ -30,28 +30,30 @@ const MMIO_BASE: u32 = 0x3F00_0000; mod benchmark; +mod delays; mod gpio; mod mbox; mod mmu; mod uart; -raspi3_boot::entry!(kernel_entry); - fn kernel_entry() -> ! { + let gpio = gpio::GPIO::new(); let mut mbox = mbox::Mbox::new(); let uart = uart::Uart::new(uart::UART_PHYS_BASE); // set up serial console - if uart.init(&mut mbox).is_err() { - loop { + 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.getc(); // Press a key first before being greeted - uart.puts("Hello Rustacean!\n\n"); + uart.puts("[1] Press a key to continue booting... "); + uart.getc(); + uart.puts("Greetings fellow Rustacean!\n"); - uart.puts("\nSwitching MMU on now..."); + uart.puts("[2] Switching MMU on now... "); unsafe { mmu::init() }; @@ -64,3 +66,5 @@ fn kernel_entry() -> ! { uart.send(uart.getc()); } } + +raspi3_boot::entry!(kernel_entry); diff --git a/0D_cache_performance/src/uart.rs b/0D_cache_performance/src/uart.rs index b8e160e7..7287ec75 100644 --- a/0D_cache_performance/src/uart.rs +++ b/0D_cache_performance/src/uart.rs @@ -23,6 +23,7 @@ */ use super::MMIO_BASE; +use crate::delays; use crate::gpio; use crate::mbox; use core::{ @@ -164,7 +165,7 @@ impl Uart { } ///Set baud rate and characteristics (115200 8N1) and map to GPIO - pub fn init(&self, mbox: &mut mbox::Mbox) -> Result<()> { + pub fn init(&self, mbox: &mut mbox::Mbox, gpio: &gpio::GPIO) -> Result<()> { // turn off UART0 self.CR.set(0); @@ -189,23 +190,18 @@ impl Uart { }; // map UART0 to GPIO pins - unsafe { - (*gpio::GPFSEL1).modify(gpio::GPFSEL1::FSEL14::TXD0 + gpio::GPFSEL1::FSEL15::RXD0); + 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.GPPUD.set(0); // enable pins 14 and 15 + delays::wait_cycles(150); - (*gpio::GPPUDCLK0).modify( - gpio::GPPUDCLK0::PUDCLK14::AssertClock + gpio::GPPUDCLK0::PUDCLK15::AssertClock, - ); - for _ in 0..150 { - asm::nop(); - } + gpio.GPPUDCLK0.modify( + gpio::GPPUDCLK0::PUDCLK14::AssertClock + gpio::GPPUDCLK0::PUDCLK15::AssertClock, + ); + delays::wait_cycles(150); - (*gpio::GPPUDCLK0).set(0); - } + gpio.GPPUDCLK0.set(0); self.ICR.write(ICR::ALL::CLEAR); self.IBRD.write(IBRD::IBRD.val(2)); // Results in 115200 baud @@ -267,12 +263,12 @@ impl Uart { } /// Display a binary value in hexadecimal - pub fn hex(&self, d: u32) { + pub fn hex(&self, d: u64) { let mut n; - for i in 0..8 { + for i in 0..16 { // get highest tetrad - n = d.wrapping_shr(28 - i * 4) & 0xF; + n = d.wrapping_shr(60 - i * 4) & 0xF; // 0-9 => '0'-'9', 10-15 => 'A'-'F' // Add proper offset for ASCII table