Compare commits

..

8 Commits

Author SHA1 Message Date
d948ad81aa Update Pipeline 2025-07-18 15:04:02 +02:00
Alexander Neuhäuser
ebed65e0b2 Merge pull request #1 from iceHtwoO/read_SoC_temp
read SoC Temperature
2025-07-18 15:00:57 +02:00
863f6000b0 Remove unused import 2025-07-18 14:54:22 +02:00
Alexander Neuhäuser
5a4a8e5aac Update rust.yml 2025-07-18 14:53:32 +02:00
Alexander Neuhäuser
a02c38a8e4 Create rust.yml 2025-07-18 14:51:58 +02:00
fbc2fcff72 Read SoC temp via mailboxes 2025-07-18 14:41:25 +02:00
fe8e5e000a Trying to fix exception in el1 2025-06-25 11:44:40 +02:00
1ff752e3dd mailbox 2025-06-08 21:49:36 +02:00
16 changed files with 288 additions and 61 deletions

36
.github/workflows/rust.yml vendored Normal file
View File

@@ -0,0 +1,36 @@
name: Rust
on:
push:
pull_request:
branches: ["master"]
env:
CARGO_TERM_COLOR: always
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install rustfmt for nightly
run: rustup component add --toolchain nightly-x86_64-unknown-linux-gnu rustfmt clippy
- name: Add AArch64 Target
run: rustup target add aarch64-unknown-none
- name: Run format check
run: cargo fmt --check
- name: Run lint
run: cargo clippy
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install rustfmt for nightly
run: rustup component add --toolchain nightly-x86_64-unknown-linux-gnu rustfmt clippy
- name: Add AArch64 Target
run: rustup target add aarch64-unknown-none
- name: Build
run: cargo build --verbose

1
.gitignore vendored
View File

@@ -2,3 +2,4 @@
kernel8.img kernel8.img
.env .env
sd.img sd.img
settings.json

23
.vscode/launch.json vendored
View File

@@ -1,5 +1,12 @@
{ {
"version": "0.2.0", "version": "0.2.0",
"compounds": [
{
"name": "Run QEMU + Attach LLDB",
"configurations": ["Attach LLDB"],
"preLaunchTask": "Run QEMU"
}
],
"configurations": [ "configurations": [
{ {
"name": "Attach to QEMU (AArch64)", "name": "Attach to QEMU (AArch64)",
@@ -12,7 +19,7 @@
"stopAtEntry": true, "stopAtEntry": true,
"externalConsole": false, "externalConsole": false,
"MIMode": "gdb", "MIMode": "gdb",
"setupCommands": [ "setupCommands": [
{ {
"description": "Enable pretty-printing for gdb", "description": "Enable pretty-printing for gdb",
"text": "-enable-pretty-printing", "text": "-enable-pretty-printing",
@@ -20,11 +27,21 @@
}, },
{ {
"description": "Show assembly on stop", "description": "Show assembly on stop",
"text": "layout asm", "text": "set disassemble-next-line on",
"ignoreFailures": true "ignoreFailures": true
} }
], ],
"preLaunchTask": "Run QEMU" "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"]
} }
] ]
} }

2
.vscode/tasks.json vendored
View File

@@ -14,7 +14,7 @@
{ {
"label": "Run QEMU", "label": "Run QEMU",
"type": "shell", "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, "isBackground": true,
"dependsOn": ["Build"] "dependsOn": ["Build"]
} }

View File

@@ -6,6 +6,8 @@ edition = "2021"
[profile.dev] [profile.dev]
panic = "abort" panic = "abort"
debug = true
opt-level = 0
[profile.release] [profile.release]
panic = "abort" panic = "abort"

BIN
firmware_files/fixup.dat Executable file

Binary file not shown.

View File

@@ -27,10 +27,9 @@ SECTIONS {
KEEP(*(.vector_table)) KEEP(*(.vector_table))
} }
.stack 0x8008000 : ALIGN(16) .stack 0x8018000 : ALIGN(16)
{ {
__stack_start = .; __stack_start = .;
.+=0x10000;
__stack_end = .; __stack_end = .;
} }

15
src/configuration.rs Normal file
View File

@@ -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;

View File

@@ -3,7 +3,14 @@ use core::{
sync::atomic::{compiler_fence, Ordering}, 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 INTERRUPT_BASE: u32 = 0x3F00_B000;
const IRQ_PENDING_BASE: u32 = INTERRUPT_BASE + 0x204; const IRQ_PENDING_BASE: u32 = INTERRUPT_BASE + 0x204;
@@ -35,7 +42,42 @@ unsafe extern "C" fn irq_handler() {
handle_gpio_interrupt(); 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() { fn handle_gpio_interrupt() {
print("Interrupt\r\n");
for i in 0..=53u32 { for i in 0..=53u32 {
let val = read_gpio_event_detect_status(i); let val = read_gpio_event_detect_status(i);

View File

@@ -4,6 +4,7 @@ use core::ptr::{read_volatile, write_volatile};
pub mod peripherals; pub mod peripherals;
pub mod configuration;
pub mod irq_interrupt; pub mod irq_interrupt;
pub mod mailbox; pub mod mailbox;
pub mod timer; pub mod timer;

58
src/mailbox.rs Normal file
View File

@@ -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
}

View File

@@ -5,24 +5,28 @@
use core::{ use core::{
arch::{asm, global_asm}, arch::{asm, global_asm},
panic::PanicInfo, panic::PanicInfo,
ptr::write_volatile,
}; };
use nova::{ use nova::{
irq_interrupt::enable_irq_source, irq_interrupt::enable_irq_source,
mailbox::read_soc_temp,
peripherals::{ peripherals::{
gpio::{ gpio::{
gpio_get_state, gpio_high, gpio_low, gpio_pull_up, set_falling_edge_detect, blink_gpio, gpio_pull_up, set_falling_edge_detect, set_gpio_function, GPIOFunction,
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")); global_asm!(include_str!("vector.S"));
extern "C" { extern "C" {
fn el2_to_el1(); fn el2_to_el1();
static mut __bss_start: u32;
static mut __bss_end: u32;
} }
#[panic_handler] #[panic_handler]
@@ -46,6 +50,9 @@ pub unsafe extern "C" fn _start() {
#[no_mangle] #[no_mangle]
pub extern "C" fn main() -> ! { pub extern "C" fn main() -> ! {
unsafe {
zero_bss();
}
enable_uart(); enable_uart();
// Set ACT Led to Outout // Set ACT Led to Outout
@@ -58,12 +65,21 @@ pub extern "C" fn main() -> ! {
print("Hello World!\r\n"); print("Hello World!\r\n");
unsafe { unsafe {
asm!("mrs x0, SCTLR_EL1");
el2_to_el1(); el2_to_el1();
} }
loop {} 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] #[no_mangle]
pub extern "C" fn kernel_main() -> ! { pub extern "C" fn kernel_main() -> ! {
print_current_el_str(); print_current_el_str();
@@ -77,26 +93,13 @@ pub extern "C" fn kernel_main() -> ! {
set_falling_edge_detect(26, true); set_falling_edge_detect(26, true);
loop { loop {
let _ = gpio_high(29); let temp = read_soc_temp();
print_u32(temp);
sleep_ms(500); // 0.5s blink_gpio(SpecificGpio::OnboardLed as u8, 500);
let _ = gpio_low(29);
sleep_ms(500); // 0.5s
print_gpio_state();
} }
} }
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 { pub fn get_current_el() -> u64 {
let el: u64; let el: u64;
unsafe { unsafe {

View File

@@ -1,7 +1,7 @@
use core::result::Result; use core::result::Result;
use core::result::Result::Ok; use core::result::Result::Ok;
use crate::timer::delay_nops; use crate::timer::{delay_nops, sleep_ms};
use crate::{mmio_read, mmio_write}; use crate::{mmio_read, mmio_write};
const GPFSEL_BASE: u32 = 0x3F20_0000; const GPFSEL_BASE: u32 = 0x3F20_0000;
@@ -13,6 +13,11 @@ const GPPUDCLK_BASE: u32 = 0x3F20_0098;
const GPREN_BASE: u32 = 0x3F20_004C; const GPREN_BASE: u32 = 0x3F20_004C;
const GPFEN_BASE: u32 = 0x3F20_0058; const GPFEN_BASE: u32 = 0x3F20_0058;
#[repr(u8)]
pub enum SpecificGpio {
OnboardLed = 29,
}
#[repr(u32)] #[repr(u32)]
pub enum GPIOFunction { pub enum GPIOFunction {
Input = 0b000, Input = 0b000,
@@ -90,7 +95,6 @@ pub fn gpio_pull_down(gpio: u8) {
} }
fn gpio_pull_up_down(gpio: u8, val: u32) { fn gpio_pull_up_down(gpio: u8, val: u32) {
unsafe {
// Determine GPPUDCLK Register // Determine GPPUDCLK Register
let register_addr = GPPUDCLK_BASE + 4 * (gpio as u32 / 32); let register_addr = GPPUDCLK_BASE + 4 * (gpio as u32 / 32);
let register_offset = gpio % 32; let register_offset = gpio % 32;
@@ -113,7 +117,6 @@ fn gpio_pull_up_down(gpio: u8, val: u32) {
// 6. reset clock // 6. reset clock
mmio_write(register_addr, 0); mmio_write(register_addr, 0);
}
} }
/// Get the current status if falling edge detection is set /// 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); 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);
}

View File

@@ -1,3 +1,5 @@
use core::arch::asm;
use crate::{mmio_read, mmio_write}; use crate::{mmio_read, mmio_write};
const BAUD: u32 = 115200; const BAUD: u32 = 115200;
@@ -21,11 +23,41 @@ const UART0_LCRH_FEN: u32 = 1 << 4;
/// Print `s` over UART /// Print `s` over UART
pub fn print(s: &str) { pub fn print(s: &str) {
for byte in s.bytes() { 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); mmio_write(UART0_DR, byte as u32);
} }
// wait till uart is not busy anymore // 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 /// Initialize UART peripheral

View File

@@ -14,14 +14,13 @@ vector_table:
ventry . ventry .
ventry . ventry .
ventry . ventry synchronous_interrupt // Synchronous Exception 0x200
ventry irq_handler // IRQ(Interrupt Request) 0x280 ventry irq_handler // IRQ(Interrupt Request) 0x280
ventry . ventry .
ventry . ventry .
.align 4 .align 4
.extern main
.global el2_to_el1 .global el2_to_el1
el2_to_el1: el2_to_el1:
@@ -44,6 +43,16 @@ el2_to_el1:
adr x0, vector_table adr x0, vector_table
msr VBAR_EL1, x0 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 isb
// Return to EL1 // Return to EL1

View File

@@ -10,4 +10,5 @@ qemu-system-aarch64 \
-serial stdio \ -serial stdio \
-sd ../sd.img \ -sd ../sd.img \
-display none \ -display none \
-kernel ../target/aarch64-unknown-none/debug/kernel8.img -kernel ../target/aarch64-unknown-none/debug/kernel8.img \
-s -S