From 384c54855734e1f5d10ac3120c8612b1ff329f0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Neuh=C3=A4user?= Date: Fri, 26 Dec 2025 13:48:22 +0100 Subject: [PATCH] Add power management watchdog, rework interrupts --- heap/src/lib.rs | 12 +-- link.ld | 9 +- src/irq_interrupt.rs | 191 +++++++++++++++++++++++++++------------- src/lib.rs | 16 ++++ src/mailbox.rs | 6 +- src/main.rs | 49 +++++------ src/peripherals/gpio.rs | 34 ++++++- src/power_management.rs | 27 ++++++ src/vector.S | 125 +++++++++++++++++++++++++- tools/deply_to_hw.sh | 2 +- 10 files changed, 361 insertions(+), 110 deletions(-) create mode 100644 src/power_management.rs diff --git a/heap/src/lib.rs b/heap/src/lib.rs index 44609fe..5c1d83f 100644 --- a/heap/src/lib.rs +++ b/heap/src/lib.rs @@ -15,7 +15,7 @@ extern crate alloc; #[repr(C, align(16))] #[derive(Clone, Copy)] -pub struct HeapHeader { +struct HeapHeader { next: Option<*mut HeapHeader>, before: Option<*mut HeapHeader>, size: usize, @@ -26,9 +26,9 @@ const HEAP_HEADER_SIZE: usize = size_of::(); const MIN_BLOCK_SIZE: usize = 16; pub struct Heap { - pub start_address: *mut HeapHeader, - pub end_address: *mut HeapHeader, - pub raw_size: usize, + start_address: *mut HeapHeader, + end_address: *mut HeapHeader, + raw_size: usize, } impl Heap { pub const fn empty() -> Self { @@ -72,7 +72,7 @@ impl Heap { Ok(current) } - pub fn malloc(&self, mut size: usize) -> Result<*mut u8, NovaError> { + fn malloc(&self, mut size: usize) -> Result<*mut u8, NovaError> { if size == 0 { return Err(NovaError::EmptyHeapSegmentNotAllowed); } @@ -130,7 +130,7 @@ impl Heap { } } - pub fn free(&self, pointer: *mut u8) -> Result<(), NovaError> { + fn free(&self, pointer: *mut u8) -> Result<(), NovaError> { let mut segment = Self::get_header_ref_from_data_pointer(pointer); unsafe { // IF prev is free: diff --git a/link.ld b/link.ld index 7ead11e..3a85ba0 100644 --- a/link.ld +++ b/link.ld @@ -27,7 +27,7 @@ SECTIONS { KEEP(*(.vector_table)) } - .heap 0x8000000 : ALIGN(16) + .heap : ALIGN(16) { __heap_start = .; . += 0x10000; #10kB @@ -41,6 +41,13 @@ SECTIONS { __stack_end = .; } + .stack_el0 : ALIGN(16) + { + __stack_start_el0 = .; + . += 0x10000; #10kB stack + __stack_end_el0 = .; + } + _end = .; } diff --git a/src/irq_interrupt.rs b/src/irq_interrupt.rs index afdcda2..2a85486 100644 --- a/src/irq_interrupt.rs +++ b/src/irq_interrupt.rs @@ -1,12 +1,10 @@ -use core::{ - arch::asm, - sync::atomic::{compiler_fence, Ordering}, -}; +use core::arch::asm; use crate::{ + get_current_el, + irq_interrupt::daif::unmask_irq, mmio_read, mmio_write, - peripherals::gpio::{blink_gpio, SpecificGpio}, - timer::sleep_s, + peripherals::gpio::{read_gpio_event_detect_status, reset_gpio_event_detect_status}, }; const INTERRUPT_BASE: u32 = 0x3F00_B000; @@ -14,9 +12,6 @@ const IRQ_PENDING_BASE: u32 = INTERRUPT_BASE + 0x204; const ENABLE_IRQ_BASE: u32 = INTERRUPT_BASE + 0x210; const DISABLE_IRQ_BASE: u32 = INTERRUPT_BASE + 0x21C; -// GPIO -const GPEDS_BASE: u32 = 0x3F20_0040; - #[repr(u32)] pub enum IRQState { AuxInt = 29, @@ -34,22 +29,97 @@ pub enum IRQState { UartInt = 57, } -#[no_mangle] -unsafe extern "C" fn irq_handler() { - handle_gpio_interrupt(); +/// Representation of the ESR_ELx registers +/// +/// Reference: D1.10.4 +#[derive(Debug, Clone, Copy)] +#[allow(dead_code)] +struct EsrElX { + ec: u32, + il: u32, + iss: u32, } -#[no_mangle] -unsafe extern "C" fn synchronous_interrupt() { - loop { - println!("Sync Exception"); - blink_gpio(SpecificGpio::OnboardLed as u8, 100); - esr_uart_dump(); - sleep_s(200); +impl From for EsrElX { + fn from(value: u32) -> Self { + Self { + ec: value >> 26, + il: (value >> 25) & 0b1, + iss: value & 0x1FFFFFF, + } } } -fn esr_uart_dump() { +#[no_mangle] +unsafe extern "C" fn rust_irq_handler() { + daif::mask_all(); + handle_gpio_interrupt(); + let source_el = get_exception_return_exception_level() >> 2; + println!("Source EL: {}", source_el); + println!("Current EL: {}", get_current_el()); + println!("Return register address: {:#x}", get_elr_el1()); +} + +#[no_mangle] +unsafe extern "C" fn rust_synchronous_interrupt_no_el_change() { + daif::mask_all(); + + let source_el = get_exception_return_exception_level() >> 2; + println!("--------Sync Exception in EL{}--------", source_el); + println!("No EL change"); + println!("Current EL: {}", get_current_el()); + println!("{:?}", EsrElX::from(get_esr_el1())); + println!("Return register address: {:#x}", get_elr_el1()); + println!("-------------------------------------"); +} + +/// Synchronous Exception Handler +/// +/// Lower Exception level, where the implemented level +/// immediately lower than the target level is using +/// AArch64. +#[no_mangle] +unsafe extern "C" fn rust_synchronous_interrupt_imm_lower_aarch64() { + daif::mask_all(); + + let source_el = get_exception_return_exception_level() >> 2; + println!("--------Sync Exception in EL{}--------", source_el); + println!("Exception escalated to EL {}", get_current_el()); + println!("Current EL: {}", get_current_el()); + let esr = EsrElX::from(get_esr_el1()); + println!("{:?}", EsrElX::from(esr)); + println!("Return register address: {:#x}", get_elr_el1()); + + match esr.ec { + 0b100100 => { + println!("Cause: Data Abort from a lower Exception level"); + } + _ => {} + } + println!("-------------------------------------"); + + set_return_to_kernel_main(); +} + +fn set_return_to_kernel_main() { + unsafe { + asm!("ldr x0, =kernel_main", "msr ELR_EL1, x0"); + asm!("mov x0, #(0b0101)", "msr SPSR_EL1, x0"); + } +} + +fn get_exception_return_exception_level() -> u32 { + let spsr: u32; + unsafe { + asm!("mrs {0:x}, SPSR_EL1", out(reg) spsr); + } + spsr & 0b1111 +} + +/// Read the syndrome information that caused an exception +/// +/// ESR = Exception Syndrome Register +fn get_esr_el1() -> u32 { let esr: u32; unsafe { asm!( @@ -57,20 +127,21 @@ fn esr_uart_dump() { 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!("_"); - } + esr +} - if i == 26 || i == 25 || i == 0 { - print!("\n\r"); - } +/// Read the return address +/// +/// ELR = Exception Link Registers +fn get_elr_el1() -> u32 { + let elr: u32; + unsafe { + asm!( + "mrs {esr:x}, ELR_EL1", + esr = out(reg) elr + ); } + elr } fn handle_gpio_interrupt() { @@ -81,32 +152,16 @@ fn handle_gpio_interrupt() { if val { #[allow(clippy::single_match)] match i { - 26 => print!("Button Pressed"), + 26 => { + println!("Button Pressed"); + } _ => {} } // Reset GPIO Interrupt handler by writing a 1 reset_gpio_event_detect_status(i); } } - enable_irq(); -} - -/// Get current interrupt status of a GPIO pin -pub fn read_gpio_event_detect_status(id: u32) -> bool { - let register = GPEDS_BASE + (id / 32) * 4; - let register_offset = id % 32; - - let val = mmio_read(register) >> register_offset; - (val & 0b1) != 0 -} - -/// Resets current interrupt status of a GPIO pin -pub fn reset_gpio_event_detect_status(id: u32) { - let register = GPEDS_BASE + (id / 32) * 4; - let register_offset = id % 32; - - mmio_write(register, 0b1 << register_offset); - compiler_fence(Ordering::SeqCst); + unmask_irq(); } /// Enables IRQ Source @@ -147,16 +202,26 @@ pub fn read_irq_pending(state: IRQState) -> bool { ((mmio_read(register) >> register_offset) & 0b1) != 0 } -/// Clears the IRQ DAIF Mask -/// -/// Enables IRQ interrupts -pub fn enable_irq() { - unsafe { asm!("msr DAIFClr, #0x2") } -} +pub mod daif { + use core::arch::asm; -/// Clears the IRQ DAIF Mask -/// -/// Disable IRQ interrupts -pub fn disable_irq() { - unsafe { asm!("msr DAIFSet, #0x2") } + #[inline(always)] + pub fn mask_all() { + unsafe { asm!("msr DAIFSet, #0xf", options(nomem, nostack)) } + } + + #[inline(always)] + pub fn unmask_all() { + unsafe { asm!("msr DAIFClr, #0xf", options(nomem, nostack)) } + } + + #[inline(always)] + pub fn mask_irq() { + unsafe { asm!("msr DAIFSet, #0x2", options(nomem, nostack)) } + } + + #[inline(always)] + pub fn unmask_irq() { + unsafe { asm!("msr DAIFClr, #0x2", options(nomem, nostack)) } + } } diff --git a/src/lib.rs b/src/lib.rs index 20b3758..7a0b173 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,12 +1,15 @@ #![no_std] #![allow(clippy::missing_safety_doc)] use core::{ + arch::asm, panic::PanicInfo, ptr::{read_volatile, write_volatile}, }; use heap::Heap; +pub static PERIPHERAL_BASE: u32 = 0x3F00_0000; + unsafe extern "C" { unsafe static mut __heap_start: u8; unsafe static mut __heap_end: u8; @@ -53,6 +56,7 @@ pub mod configuration; pub mod framebuffer; pub mod irq_interrupt; pub mod mailbox; +pub mod power_management; pub mod timer; pub fn mmio_read(address: u32) -> u32 { @@ -62,3 +66,15 @@ pub fn mmio_read(address: u32) -> u32 { pub fn mmio_write(address: u32, data: u32) { unsafe { write_volatile(address as *mut u32, data) } } + +pub fn get_current_el() -> u64 { + let el: u64; + unsafe { + asm!( + "mrs {el}, CurrentEL", + el = out(reg) el, + options(nomem, nostack, preserves_flags) + ); + } + el >> 2 +} diff --git a/src/mailbox.rs b/src/mailbox.rs index 847f50b..cdbdf7c 100644 --- a/src/mailbox.rs +++ b/src/mailbox.rs @@ -27,7 +27,7 @@ macro_rules! max { #[macro_export] macro_rules! mailbox_command { ($name:ident, $tag:expr, $request_len:expr,$response_len:expr) => { - /// More information at: https://github.com/raspberrypi/firmware/wiki/Mailbox-property-interface + /// More information at: pub fn $name( request_data: [u32; $request_len / 4], ) -> Result<[u32; $response_len / 4], NovaError> { @@ -59,10 +59,10 @@ macro_rules! mailbox_command { }; } -mailbox_command!(mb_read_soc_temp, 0x0003_0006, 4, 8); +mailbox_command!(read_soc_temp, 0x0003_0006, 4, 8); // Framebuffer -mailbox_command!(mb_get_display_resolution, 0x0004_0003, 0, 8); +mailbox_command!(get_display_resolution, 0x0004_0003, 0, 8); pub fn read_mailbox(channel: u32) -> u32 { // Wait until mailbox is not empty diff --git a/src/main.rs b/src/main.rs index 1d3f643..99e12e4 100644 --- a/src/main.rs +++ b/src/main.rs @@ -13,9 +13,9 @@ extern crate alloc; use alloc::boxed::Box; use nova::{ framebuffer::{FrameBuffer, BLUE, GREEN, RED}, - init_heap, - irq_interrupt::enable_irq_source, - mailbox::mb_read_soc_temp, + get_current_el, init_heap, + irq_interrupt::{daif, enable_irq_source}, + mailbox, peripherals::{ gpio::{ blink_gpio, gpio_pull_up, set_falling_edge_detect, set_gpio_function, GPIOFunction, @@ -24,13 +24,13 @@ use nova::{ uart::uart_init, }, print, println, - timer::{delay_nops, sleep_us}, }; global_asm!(include_str!("vector.S")); extern "C" { fn el2_to_el1(); + fn el1_to_el0(); static mut __bss_start: u32; static mut __bss_end: u32; } @@ -57,12 +57,11 @@ pub extern "C" fn main() -> ! { // Set ACT Led to Outout let _ = set_gpio_function(21, GPIOFunction::Output); - // Delay so clock speed can stabilize - delay_nops(50000); println!("Hello World!"); + println!("Exception level: {}", get_current_el()); unsafe { - asm!("mrs x0, SCTLR_EL1"); + asm!("mrs x0, SCTLR_EL1",); el2_to_el1(); } @@ -80,14 +79,22 @@ unsafe fn zero_bss() { #[no_mangle] pub extern "C" fn kernel_main() -> ! { - println!("EL: {}", get_current_el()); + println!("Kernel Main"); + println!("Exception Level: {}", get_current_el()); + daif::unmask_all(); unsafe { init_heap(); - heap_test(); + el1_to_el0(); }; - sleep_us(500_000); + #[allow(clippy::empty_loop)] + loop {} +} + +#[no_mangle] +pub extern "C" fn el0() -> ! { + println!("Jumped into EL0"); // Set GPIO 26 to Input enable_irq_source(nova::irq_interrupt::IRQState::GpioInt0); //26 is on the first GPIO bank @@ -106,34 +113,20 @@ pub extern "C" fn kernel_main() -> ! { fb.draw_function(cos, 100, 101, RED); loop { - let temp = mb_read_soc_temp([0]).unwrap(); + let temp = mailbox::read_soc_temp([0]).unwrap(); println!("{} °C", temp[1] / 1000); blink_gpio(SpecificGpio::OnboardLed as u8, 500); - } -} -unsafe fn heap_test() { - let b = Box::new([1, 2, 3, 4]); - println!("{:?}", b); + let b = Box::new([1, 2, 3, 4]); + println!("{:?}", b); + } } fn cos(x: u32) -> f64 { libm::cos(x as f64 * 0.1) * 20.0 } -fn get_current_el() -> u64 { - let el: u64; - unsafe { - asm!( - "mrs {el}, CurrentEL", - el = out(reg) el, - options(nomem, nostack, preserves_flags) - ); - } - el >> 2 -} - fn enable_uart() { uart_init(); // Set GPIO Pins to UART diff --git a/src/peripherals/gpio.rs b/src/peripherals/gpio.rs index a6e8bb0..3f4de8a 100644 --- a/src/peripherals/gpio.rs +++ b/src/peripherals/gpio.rs @@ -1,5 +1,6 @@ use core::result::Result; use core::result::Result::Ok; +use core::sync::atomic::{compiler_fence, Ordering}; use crate::timer::{delay_nops, sleep_ms}; use crate::{mmio_read, mmio_write}; @@ -8,10 +9,11 @@ const GPFSEL_BASE: u32 = 0x3F20_0000; const GPSET_BASE: u32 = 0x3F20_001C; const GPCLR_BASE: u32 = 0x3F20_0028; const GPLEV_BASE: u32 = 0x3F20_0034; +const GPEDS_BASE: u32 = 0x3F20_0040; +const GPFEN_BASE: u32 = 0x3F20_0058; const GPPUD: u32 = 0x3F20_0094; const GPPUDCLK_BASE: u32 = 0x3F20_0098; const GPREN_BASE: u32 = 0x3F20_004C; -const GPFEN_BASE: u32 = 0x3F20_0058; #[repr(u8)] pub enum SpecificGpio { @@ -48,7 +50,8 @@ pub fn set_gpio_function(gpio: u8, state: GPIOFunction) -> Result<(), &'static s /// Set the GPIO to high /// -/// Should be used when GPIO function is set to `OUTPUT` via `set_gpio_function` +/// Should be used when GPIO function is set to `OUTPUT` via `set_gpio_function`, +/// otherwise setting is ignored pub fn gpio_high(gpio: u8) -> Result<(), &'static str> { let register_index = gpio / 32; let register_offset = gpio % 32; @@ -119,7 +122,7 @@ fn gpio_pull_up_down(gpio: u8, val: u32) { mmio_write(register_addr, 0); } -/// Get the current status if falling edge detection is set +/// Get the current status of the falling edge detection pub fn read_falling_edge_detect(gpio: u8) -> bool { let register_addr = GPFEN_BASE + 4 * (gpio as u32 / 32); let register_offset = gpio % 32; @@ -128,7 +131,7 @@ pub fn read_falling_edge_detect(gpio: u8) -> bool { ((current >> register_offset) & 0b1) != 0 } -/// Get the current status if falling edge detection is set +/// Get the current status of the rising edge detection pub fn read_rising_edge_detect(gpio: u8) -> bool { let register_addr = GPREN_BASE + 4 * (gpio as u32 / 32); let register_offset = gpio % 32; @@ -170,6 +173,29 @@ pub fn set_rising_edge_detect(gpio: u8, enable: bool) { mmio_write(register_addr, new_val); } +/// Returns with the interrupt status of an GPIO. +/// +/// GPEDS register is used to record level and edge events on the GPIO pins. +/// When an event is triggered by the GPIO, the corresponding bit will be set to 1. +pub fn read_gpio_event_detect_status(id: u32) -> bool { + let register = GPEDS_BASE + (id / 32) * 4; + let register_offset = id % 32; + + let val = mmio_read(register) >> register_offset; + (val & 0b1) != 0 +} + +/// Resets current interrupt status of a GPIO pin. +pub fn reset_gpio_event_detect_status(id: u32) { + let register = GPEDS_BASE + (id / 32) * 4; + let register_offset = id % 32; + + mmio_write(register, 0b1 << register_offset); + compiler_fence(Ordering::SeqCst); +} + +// TODO: GPHEN,GPLEN,GPAREN,GPAFEN + pub fn blink_gpio(gpio: u8, duration_ms: u64) { let _ = gpio_high(gpio); diff --git a/src/power_management.rs b/src/power_management.rs new file mode 100644 index 0000000..93e92a9 --- /dev/null +++ b/src/power_management.rs @@ -0,0 +1,27 @@ +use core::ptr::{read_volatile, write_volatile}; + +use crate::PERIPHERAL_BASE; + +/// Power Management Base +static PM_BASE: u32 = PERIPHERAL_BASE + 0x10_0000; +static PM_RSTC: u32 = PM_BASE + 0x1c; +static PM_WDOG: u32 = PM_BASE + 0x24; + +static PM_PASSWORD: u32 = 0x5a000000; +static PM_WDOG_TIMER_MASK: u32 = 0x000fffff; +static PM_RSTC_WRCFG_CLR: u32 = 0xffffffcf; +static PM_RSTC_WRCFG_FULL_RESET: u32 = 0x00000020; + +pub fn reboot_system() { + unsafe { + let pm_rstc_val = read_volatile(PM_RSTC as *mut u32); + // (31:16) bits -> password + // (11:0) bits -> value + write_volatile(PM_WDOG as *mut u32, PM_PASSWORD | (1 & PM_WDOG_TIMER_MASK)); + write_volatile( + PM_RSTC as *mut u32, + PM_PASSWORD | (pm_rstc_val & PM_RSTC_WRCFG_CLR) | PM_RSTC_WRCFG_FULL_RESET, + ); + } + loop {} +} diff --git a/src/vector.S b/src/vector.S index 63d0b6a..a4a2d35 100644 --- a/src/vector.S +++ b/src/vector.S @@ -14,11 +14,14 @@ vector_table: ventry . ventry . - ventry synchronous_interrupt // Synchronous Exception 0x200 + ventry synchronous_interrupt_no_el_change // Synchronous Exception 0x200 ventry irq_handler // IRQ(Interrupt Request) 0x280 ventry . ventry . + ventry synchronous_interrupt_imm_lower_aarch64 + ventry irq_handler + .align 4 .global el2_to_el1 @@ -31,7 +34,7 @@ el2_to_el1: mov x0, #(0b0101) msr SPSR_EL2, x0 - // Set return address to ELR_EL2 + // Set return address to kernel_main ldr x0, =kernel_main msr ELR_EL2, x0 @@ -53,7 +56,121 @@ el2_to_el1: orr x0,x0, x1 msr CPACR_EL1,x0 - isb - // Return to EL1 eret + +.align 4 +.global el1_to_el0 +el1_to_el0: + + // Set SPSR_EL1: return to EL0t + mov x0, #(0b0000) + msr SPSR_EL1, x0 + + // Set return address to el0 + ldr x0, =el0 + msr ELR_EL1, x0 + + // Set SP_EL1 to stack base + ldr x0, =__stack_end_el0 + msr SP_EL0, x0 + + // Return to EL0 + eret + + +.align 4 +irq_handler: + sub sp, sp, #176 + stp x0, x1, [sp, #0] + stp x2, x3, [sp, #16] + stp x4, x5, [sp, #32] + stp x6, x7, [sp, #48] + stp x8, x9, [sp, #64] + stp x10, x11, [sp, #80] + stp x12, x13, [sp, #96] + stp x14, x15, [sp, #112] + stp x16, x17, [sp, #128] + stp x18, x29, [sp, #144] + stp x30, xzr, [sp, #160] + + bl rust_irq_handler + + ldp x0, x1, [sp, #0] + ldp x2, x3, [sp, #16] + ldp x4, x5, [sp, #32] + ldp x6, x7, [sp, #48] + ldp x8, x9, [sp, #64] + ldp x10, x11, [sp, #80] + ldp x12, x13, [sp, #96] + ldp x14, x15, [sp, #112] + ldp x16, x17, [sp, #128] + ldp x18, x29, [sp, #144] + ldp x30, xzr, [sp, #160] + add sp, sp, #176 + + eret + +.align 4 +synchronous_interrupt_imm_lower_aarch64: + sub sp, sp, #176 + stp x0, x1, [sp, #0] + stp x2, x3, [sp, #16] + stp x4, x5, [sp, #32] + stp x6, x7, [sp, #48] + stp x8, x9, [sp, #64] + stp x10, x11, [sp, #80] + stp x12, x13, [sp, #96] + stp x14, x15, [sp, #112] + stp x16, x17, [sp, #128] + stp x18, x29, [sp, #144] + stp x30, xzr, [sp, #160] + + bl rust_synchronous_interrupt_imm_lower_aarch64 + + ldp x0, x1, [sp, #0] + ldp x2, x3, [sp, #16] + ldp x4, x5, [sp, #32] + ldp x6, x7, [sp, #48] + ldp x8, x9, [sp, #64] + ldp x10, x11, [sp, #80] + ldp x12, x13, [sp, #96] + ldp x14, x15, [sp, #112] + ldp x16, x17, [sp, #128] + ldp x18, x29, [sp, #144] + ldp x30, xzr, [sp, #160] + add sp, sp, #176 + + eret + +.align 4 +synchronous_interrupt_no_el_change: + sub sp, sp, #176 + stp x0, x1, [sp, #0] + stp x2, x3, [sp, #16] + stp x4, x5, [sp, #32] + stp x6, x7, [sp, #48] + stp x8, x9, [sp, #64] + stp x10, x11, [sp, #80] + stp x12, x13, [sp, #96] + stp x14, x15, [sp, #112] + stp x16, x17, [sp, #128] + stp x18, x29, [sp, #144] + stp x30, xzr, [sp, #160] + + bl rust_synchronous_interrupt_no_el_change + + ldp x0, x1, [sp, #0] + ldp x2, x3, [sp, #16] + ldp x4, x5, [sp, #32] + ldp x6, x7, [sp, #48] + ldp x8, x9, [sp, #64] + ldp x10, x11, [sp, #80] + ldp x12, x13, [sp, #96] + ldp x14, x15, [sp, #112] + ldp x16, x17, [sp, #128] + ldp x18, x29, [sp, #144] + ldp x30, xzr, [sp, #160] + add sp, sp, #176 + + eret diff --git a/tools/deply_to_hw.sh b/tools/deply_to_hw.sh index 650ba9d..ca0844c 100755 --- a/tools/deply_to_hw.sh +++ b/tools/deply_to_hw.sh @@ -15,7 +15,7 @@ REMOTE_DIR="$TFTP_PATH" # BUILD echo "[*] Building kernel..." -cargo build --release +cargo build --release --target aarch64-unknown-none # CONVERT TO IMG echo "[*] Convert kernel elf to img..."