diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 806b6d6..db0e144 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -3,7 +3,7 @@ name: Rust on: push: pull_request: - branches: [ "master" ] + branches: ["master"] env: CARGO_TERM_COLOR: always @@ -15,7 +15,7 @@ jobs: steps: - uses: actions/checkout@v4 - name: Install rustfmt for nightly - run: rustup component add --toolchain nightly-x86_64-unknown-linux-gnu rustfmt + run: rustup component add --toolchain nightly-x86_64-unknown-linux-gnu rustfmt clippy - name: Run format check run: cargo fmt --check - name: Run lint @@ -27,6 +27,6 @@ jobs: steps: - uses: actions/checkout@v4 - name: Install rustfmt for nightly - run: rustup component add --toolchain nightly-x86_64-unknown-linux-gnu rustfmt + run: rustup component add --toolchain nightly-x86_64-unknown-linux-gnu rustfmt clippy - name: Build run: cargo build --verbose diff --git a/.gitignore b/.gitignore index a5adda7..a6534a8 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ kernel8.img .env sd.img +settings.json diff --git a/.vscode/launch.json b/.vscode/launch.json index 941b38e..bffd237 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -1,5 +1,12 @@ { "version": "0.2.0", + "compounds": [ + { + "name": "Run QEMU + Attach LLDB", + "configurations": ["Attach LLDB"], + "preLaunchTask": "Run QEMU" + } + ], "configurations": [ { "name": "Attach to QEMU (AArch64)", @@ -12,19 +19,29 @@ "stopAtEntry": true, "externalConsole": false, "MIMode": "gdb", -"setupCommands": [ - { - "description": "Enable pretty-printing for gdb", - "text": "-enable-pretty-printing", - "ignoreFailures": true - }, - { - "description": "Show assembly on stop", - "text": "layout asm", - "ignoreFailures": true - } -], + "setupCommands": [ + { + "description": "Enable pretty-printing for gdb", + "text": "-enable-pretty-printing", + "ignoreFailures": true + }, + { + "description": "Show assembly on stop", + "text": "set disassemble-next-line on", + "ignoreFailures": true + } + ], "preLaunchTask": "Run QEMU" + }, + + { + "name": "Attach LLDB", + "type": "lldb", + "request": "attach", + "debugServer": 1234, + "program": "${workspaceFolder}/target/aarch64-unknown-none/debug/nova", + "stopOnEntry": true, + "processCreateCommands": ["gdb-remote localhost:1234"] } ] } diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 9445da3..18998f4 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -14,7 +14,7 @@ { "label": "Run QEMU", "type": "shell", - "command": "qemu-system-aarch64 -M raspi3b -cpu cortex-a53 -serial stdio -sd sd.img -display none -kernel ${workspaceFolder}/target/aarch64-unknown-none/debug/kernel8.img -S -s", + "command": "qemu-system-aarch64 -M raspi3b -cpu cortex-a53 -serial stdio -sd sd.img -display none -kernel ${workspaceFolder}/target/aarch64-unknown-none/debug/kernel8.img -S -s -m 1024", "isBackground": true, "dependsOn": ["Build"] } diff --git a/Cargo.toml b/Cargo.toml index 45aea39..c8de713 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,6 +6,8 @@ edition = "2021" [profile.dev] panic = "abort" +debug = true +opt-level = 0 [profile.release] panic = "abort" diff --git a/firmware_files/fixup.dat b/firmware_files/fixup.dat new file mode 100755 index 0000000..f830300 Binary files /dev/null and b/firmware_files/fixup.dat differ diff --git a/link.ld b/link.ld index 34c2072..f4ef72e 100644 --- a/link.ld +++ b/link.ld @@ -27,10 +27,9 @@ SECTIONS { KEEP(*(.vector_table)) } - .stack 0x8008000 : ALIGN(16) + .stack 0x8018000 : ALIGN(16) { __stack_start = .; - .+=0x10000; __stack_end = .; } diff --git a/src/configuration.rs b/src/configuration.rs new file mode 100644 index 0000000..59deccd --- /dev/null +++ b/src/configuration.rs @@ -0,0 +1,15 @@ +static SCTLR_EL1_MMU_DISABLED: u64 = 0 << 0; //M +static SCTLR_EL1_DATA_CACHE_DISABLED: u64 = 0 << 2; //C +static SCTLR_EL1_INSTRUCTION_CACHE_DISABLED: u64 = 0 << 12; //I +static SCTLR_EL1_LITTLE_ENDIAN_EL0: u64 = 0 << 24; //E0E +static SCTLR_EL1_LITTLE_ENDIAN_EL1: u64 = 0 << 25; //EE + +static SCTLR_EL1_RES: u64 = (0 << 6) | (1 << 11) | (0 << 17) | (1 << 20) | (1 << 22); //Res0 & Res1 + +#[no_mangle] +pub static SCTLR_EL1_CONF: u64 = SCTLR_EL1_MMU_DISABLED + | SCTLR_EL1_DATA_CACHE_DISABLED + | SCTLR_EL1_INSTRUCTION_CACHE_DISABLED + | SCTLR_EL1_LITTLE_ENDIAN_EL0 + | SCTLR_EL1_LITTLE_ENDIAN_EL1 + | SCTLR_EL1_RES; diff --git a/src/irq_interrupt.rs b/src/irq_interrupt.rs index 27b2af8..8e03285 100644 --- a/src/irq_interrupt.rs +++ b/src/irq_interrupt.rs @@ -3,7 +3,14 @@ use core::{ sync::atomic::{compiler_fence, Ordering}, }; -use crate::{mmio_read, mmio_write, peripherals::uart::print}; +use crate::{ + mmio_read, mmio_write, + peripherals::{ + gpio::{blink_gpio, SpecificGpio}, + uart::print, + }, + timer::{sleep_ms, sleep_s}, +}; const INTERRUPT_BASE: u32 = 0x3F00_B000; const IRQ_PENDING_BASE: u32 = INTERRUPT_BASE + 0x204; @@ -35,7 +42,42 @@ unsafe extern "C" fn irq_handler() { handle_gpio_interrupt(); } +#[no_mangle] +unsafe extern "C" fn synchronous_interrupt() { + loop { + print("Sync Exception \r\n"); + blink_gpio(SpecificGpio::OnboardLed as u8, 100); + esr_uart_dump(); + sleep_s(200); + } +} + +fn esr_uart_dump() { + let esr: u32; + unsafe { + asm!( + "mrs {esr}, ESR_EL1", + esr = out(reg) esr + ); + } + for i in (0..32).rev() { + if ((esr >> i) & 1) == 0 { + print("0"); + } else { + print("1"); + } + if i % 4 == 0 && i > 0 { + print("_"); + } + + if i == 26 || i == 25 || i == 0 { + print("\n\r"); + } + } +} + fn handle_gpio_interrupt() { + print("Interrupt\r\n"); for i in 0..=53u32 { let val = read_gpio_event_detect_status(i); diff --git a/src/lib.rs b/src/lib.rs index 8d909e0..61a00be 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,6 +4,7 @@ use core::ptr::{read_volatile, write_volatile}; pub mod peripherals; +pub mod configuration; pub mod irq_interrupt; pub mod mailbox; pub mod timer; diff --git a/src/mailbox.rs b/src/mailbox.rs new file mode 100644 index 0000000..3f94599 --- /dev/null +++ b/src/mailbox.rs @@ -0,0 +1,58 @@ +use crate::{mmio_read, mmio_write, peripherals::uart::print}; + +const MBOX_BASE: u32 = 0x3F00_0000 + 0xB880; + +// MB0 +const MBOX_READ: u32 = MBOX_BASE + 0x00; +const MBOX_STATUS: u32 = MBOX_BASE + 0x18; + +// MB1 +const MBOX_WRITE: u32 = MBOX_BASE + 0x20; + +// Status +const MAIL_FULL: u32 = 0x80000000; +const MAIL_EMPTY: u32 = 0x40000000; + +pub fn read_mailbox(channel: u32) -> u32 { + // Wait until mailbox is not empty + loop { + while mmio_read(MBOX_STATUS) & MAIL_EMPTY != 0 {} + let mut data = mmio_read(MBOX_READ); + let read_channel = data & 0xF; + + data >>= 4; + + if channel == read_channel { + return data; + } + } +} + +pub fn write_mailbox(channel: u32, data: u32) { + while mmio_read(MBOX_STATUS) & MAIL_FULL != 0 {} + mmio_write(MBOX_WRITE, (data & !0xF) | (channel & 0xF)); +} + +pub fn read_soc_temp() -> u32 { + let mut mailbox = [0; 36]; + mailbox[0] = 8 * 4; // Total size in bytes + mailbox[1] = 0; // Request + mailbox[2] = 0x00030006; // Tag + mailbox[3] = 8; // Maximum buffer len + mailbox[4] = 4; // Request length + mailbox[5] = 0; // Value Buffer + mailbox[6] = 0; // Value Buffer + mailbox[7] = 0; // End + + let addr = core::ptr::addr_of!(mailbox[0]) as u32; + + write_mailbox(8, addr); + + let _ = read_mailbox(8); + + if mailbox[1] == 0 { + print("Failed\r\n"); + } + let raw_temp = mailbox[6] / 1000; + raw_temp +} diff --git a/src/main.rs b/src/main.rs index 479f264..81c3b16 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,24 +5,28 @@ use core::{ arch::{asm, global_asm}, panic::PanicInfo, + ptr::write_volatile, }; use nova::{ irq_interrupt::enable_irq_source, + mailbox::read_soc_temp, peripherals::{ gpio::{ - gpio_get_state, gpio_high, gpio_low, gpio_pull_up, set_falling_edge_detect, - set_gpio_function, GPIOFunction, + blink_gpio, gpio_pull_up, set_falling_edge_detect, set_gpio_function, GPIOFunction, + SpecificGpio, }, - uart::{print, uart_init}, + uart::{print, print_u32, uart_init}, }, - timer::{delay_nops, sleep_ms, sleep_us}, + timer::{delay_nops, sleep_us}, }; global_asm!(include_str!("vector.S")); extern "C" { fn el2_to_el1(); + static mut __bss_start: u32; + static mut __bss_end: u32; } #[panic_handler] @@ -46,6 +50,9 @@ pub unsafe extern "C" fn _start() { #[no_mangle] pub extern "C" fn main() -> ! { + unsafe { + zero_bss(); + } enable_uart(); // Set ACT Led to Outout @@ -58,12 +65,21 @@ pub extern "C" fn main() -> ! { print("Hello World!\r\n"); unsafe { + asm!("mrs x0, SCTLR_EL1"); el2_to_el1(); } loop {} } +unsafe fn zero_bss() { + let mut bss: *mut u32 = &raw mut __bss_start as *mut u32; + while bss < &raw mut __bss_end as *mut u32 { + write_volatile(bss, 0); + bss = bss.add(1); + } +} + #[no_mangle] pub extern "C" fn kernel_main() -> ! { print_current_el_str(); @@ -77,26 +93,13 @@ pub extern "C" fn kernel_main() -> ! { set_falling_edge_detect(26, true); loop { - let _ = gpio_high(29); + let temp = read_soc_temp(); + print_u32(temp); - sleep_ms(500); // 0.5s - let _ = gpio_low(29); - sleep_ms(500); // 0.5s - print_gpio_state(); + blink_gpio(SpecificGpio::OnboardLed as u8, 500); } } -fn print_gpio_state() { - let state = gpio_get_state(26); - - let ascii_byte = b'0' + state; - let data = [ascii_byte]; - - let s = str::from_utf8(&data).unwrap(); - print(s); - print("\r\n"); -} - pub fn get_current_el() -> u64 { let el: u64; unsafe { diff --git a/src/peripherals/gpio.rs b/src/peripherals/gpio.rs index 709277f..dfe804b 100644 --- a/src/peripherals/gpio.rs +++ b/src/peripherals/gpio.rs @@ -1,7 +1,7 @@ use core::result::Result; use core::result::Result::Ok; -use crate::timer::delay_nops; +use crate::timer::{delay_nops, sleep_ms}; use crate::{mmio_read, mmio_write}; const GPFSEL_BASE: u32 = 0x3F20_0000; @@ -13,6 +13,11 @@ const GPPUDCLK_BASE: u32 = 0x3F20_0098; const GPREN_BASE: u32 = 0x3F20_004C; const GPFEN_BASE: u32 = 0x3F20_0058; +#[repr(u8)] +pub enum SpecificGpio { + OnboardLed = 29, +} + #[repr(u32)] pub enum GPIOFunction { Input = 0b000, @@ -90,30 +95,28 @@ pub fn gpio_pull_down(gpio: u8) { } fn gpio_pull_up_down(gpio: u8, val: u32) { - unsafe { - // Determine GPPUDCLK Register - let register_addr = GPPUDCLK_BASE + 4 * (gpio as u32 / 32); - let register_offset = gpio % 32; + // Determine GPPUDCLK Register + let register_addr = GPPUDCLK_BASE + 4 * (gpio as u32 / 32); + let register_offset = gpio % 32; - // 1. Write Pull up - mmio_write(GPPUD, val); + // 1. Write Pull up + mmio_write(GPPUD, val); - // 2. Delay 150 cycles - delay_nops(150); + // 2. Delay 150 cycles + delay_nops(150); - // 3. Write to clock - let new_val = 0b1 << register_offset; - mmio_write(register_addr, new_val); + // 3. Write to clock + let new_val = 0b1 << register_offset; + mmio_write(register_addr, new_val); - // 4. Delay 150 cycles - delay_nops(150); + // 4. Delay 150 cycles + delay_nops(150); - // 5. reset GPPUD - mmio_write(GPPUD, 0); + // 5. reset GPPUD + mmio_write(GPPUD, 0); - // 6. reset clock - mmio_write(register_addr, 0); - } + // 6. reset clock + mmio_write(register_addr, 0); } /// Get the current status if falling edge detection is set @@ -166,3 +169,11 @@ pub fn set_rising_edge_detect(gpio: u8, enable: bool) { mmio_write(register_addr, new_val); } + +pub fn blink_gpio(gpio: u8, duration_ms: u32) { + let _ = gpio_high(gpio); + + sleep_ms(duration_ms); + let _ = gpio_low(gpio); + sleep_ms(duration_ms); +} diff --git a/src/peripherals/uart.rs b/src/peripherals/uart.rs index 1ad0fd2..30bd345 100644 --- a/src/peripherals/uart.rs +++ b/src/peripherals/uart.rs @@ -1,3 +1,5 @@ +use core::arch::asm; + use crate::{mmio_read, mmio_write}; const BAUD: u32 = 115200; @@ -21,11 +23,41 @@ const UART0_LCRH_FEN: u32 = 1 << 4; /// Print `s` over UART pub fn print(s: &str) { for byte in s.bytes() { - while mmio_read(UART0_FR) & UART0_FR_TXFF != 0 {} + while (mmio_read(UART0_FR) & UART0_FR_TXFF) != 0 { + unsafe { asm!("nop") } + } mmio_write(UART0_DR, byte as u32); } // wait till uart is not busy anymore - while (mmio_read(UART0_FR) >> 3) & 0b1 != 0 {} + while ((mmio_read(UART0_FR) >> 3) & 0b1) != 0 {} +} + +pub fn print_u32(mut val: u32) { + let mut last_valid = 0; + let mut values = [0u32; 10]; + for (i, c) in (&mut values).iter_mut().enumerate() { + if val == 0 { + break; + } + + *c = val % 10; + val /= 10; + if *c != 0 { + last_valid = i; + } + } + + for (i, c) in values.iter().enumerate().rev() { + if i > last_valid { + continue; + } + let ascii_byte = b'0' + *c as u8; + let data = [ascii_byte]; + + let s = str::from_utf8(&data).unwrap(); + print(s); + } + print("\r\n"); } /// Initialize UART peripheral diff --git a/src/vector.S b/src/vector.S index 1e125a6..63d0b6a 100644 --- a/src/vector.S +++ b/src/vector.S @@ -14,14 +14,13 @@ vector_table: ventry . ventry . - ventry . - ventry irq_handler // IRQ(Interrupt Request) 0x280 + ventry synchronous_interrupt // Synchronous Exception 0x200 + ventry irq_handler // IRQ(Interrupt Request) 0x280 ventry . ventry . .align 4 -.extern main .global el2_to_el1 el2_to_el1: @@ -44,6 +43,16 @@ el2_to_el1: adr x0, vector_table msr VBAR_EL1, x0 + // Disable MMU + ldr x0, =SCTLR_EL1_CONF + msr sctlr_el1, x0 + + // SIMD should not be trapped + mrs x0, CPACR_EL1 + mov x1, #(0b11<<20) + orr x0,x0, x1 + msr CPACR_EL1,x0 + isb // Return to EL1 diff --git a/tools/start_simulator_debug.sh b/tools/start_simulator_debug.sh index 5c75ea3..17e9660 100755 --- a/tools/start_simulator_debug.sh +++ b/tools/start_simulator_debug.sh @@ -10,4 +10,5 @@ qemu-system-aarch64 \ -serial stdio \ -sd ../sd.img \ -display none \ - -kernel ../target/aarch64-unknown-none/debug/kernel8.img + -kernel ../target/aarch64-unknown-none/debug/kernel8.img \ + -s -S