diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 4472f73221..70f3747579 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -132,6 +132,9 @@ jobs: - name: Build fs/shell for aarch64-raspi4 run: make PLATFORM=aarch64-raspi4 A=apps/fs/shell FEATURES=driver-bcm2835-sdhci + - name: Build helloworld for aarch64-bsta1000b + run: make PLATFORM=aarch64-bsta1000b A=apps/helloworld + build-apps-for-std: runs-on: ${{ matrix.os }} strategy: diff --git a/.gitignore b/.gitignore index 1ae218476f..9d91ac5720 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ *.img actual.out qemu.log +rusty-tags.vi diff --git a/Cargo.lock b/Cargo.lock index 6219f64a46..c1929b9403 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -367,6 +367,7 @@ dependencies = [ "bitflags 2.3.3", "cfg-if", "crate_interface", + "dw_apb_uart", "handler_table", "kernel_guard", "lazy_init", @@ -959,6 +960,13 @@ dependencies = [ "virtio-drivers", ] +[[package]] +name = "dw_apb_uart" +version = "0.1.0" +dependencies = [ + "tock-registers", +] + [[package]] name = "either" version = "1.9.0" diff --git a/Cargo.toml b/Cargo.toml index e1491ef042..7b77147621 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,6 +5,7 @@ members = [ "crates/allocator", "crates/arm_gic", "crates/arm_pl011", + "crates/dw_apb_uart", "crates/axerrno", "crates/axfs_devfs", "crates/axfs_ramfs", diff --git a/Makefile b/Makefile index ba7a60ef18..b351596584 100644 --- a/Makefile +++ b/Makefile @@ -143,6 +143,8 @@ include scripts/make/qemu.mk include scripts/make/test.mk ifeq ($(PLATFORM_NAME), aarch64-raspi4) include scripts/make/raspi4.mk +else ifeq ($(PLATFORM_NAME), aarch64-bsta1000b) + include scripts/make/bsta1000b-fada.mk endif build: $(OUT_DIR) $(OUT_BIN) diff --git a/crates/arm_gic/src/lib.rs b/crates/arm_gic/src/lib.rs index 6e8ac25ff0..56e3578732 100644 --- a/crates/arm_gic/src/lib.rs +++ b/crates/arm_gic/src/lib.rs @@ -45,3 +45,47 @@ pub enum TriggerMode { /// level is active, and deasserted whenever the level is not active. Level = 1, } + +/// Different types of interrupt that the GIC handles. +pub enum InterruptType { + /// Software-generated interrupt. + /// + /// SGIs are typically used for inter-processor communication and are + /// generated by a write to an SGI register in the GIC. + SGI, + /// Private Peripheral Interrupt. + /// + /// Peripheral interrupts that are private to one core. + PPI, + /// Shared Peripheral Interrupt. + /// + /// Peripheral interrupts that can delivered to any connected core. + SPI, +} + +/// Translate an interrupt of a given type to a GIC INTID. +pub const fn translate_irq(id: usize, int_type: InterruptType) -> Option { + match int_type { + InterruptType::SGI => { + if id < SGI_RANGE.end { + Some(id) + } else { + None + } + } + InterruptType::PPI => { + if id < PPI_RANGE.end - PPI_RANGE.start { + Some(id + PPI_RANGE.start) + } else { + None + } + } + InterruptType::SPI => { + if id < SPI_RANGE.end - SPI_RANGE.start { + Some(id + SPI_RANGE.start) + } else { + None + } + } + } +} diff --git a/crates/dw_apb_uart/Cargo.toml b/crates/dw_apb_uart/Cargo.toml new file mode 100644 index 0000000000..503e44baa5 --- /dev/null +++ b/crates/dw_apb_uart/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "dw_apb_uart" +authors = ["Luoyuan Xiao "] +version = "0.1.0" +edition = "2021" +license = "GPL-2.0" +repository = "https://github.com/elliott10/arceos/tree/main/crates/dw_apb_uart" +description = "Uart snps,dw-apb-uart driver in Rust for BST A1000b FADA board." + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +tock-registers = "0.8" diff --git a/crates/dw_apb_uart/src/lib.rs b/crates/dw_apb_uart/src/lib.rs new file mode 100644 index 0000000000..069f079617 --- /dev/null +++ b/crates/dw_apb_uart/src/lib.rs @@ -0,0 +1,118 @@ +//! Definitions for snps,dw-apb-uart serial driver. +//! Uart snps,dw-apb-uart driver in Rust for BST A1000b FADA board. +#![no_std] + +use tock_registers::{ + interfaces::{Readable, Writeable}, + register_structs, + registers::{ReadOnly, ReadWrite}, +}; + +register_structs! { + DW8250Regs { + /// Get or Put Register. + (0x00 => rbr: ReadWrite), + (0x04 => ier: ReadWrite), + (0x08 => fcr: ReadWrite), + (0x0c => lcr: ReadWrite), + (0x10 => mcr: ReadWrite), + (0x14 => lsr: ReadOnly), + (0x18 => msr: ReadOnly), + (0x1c => scr: ReadWrite), + (0x20 => lpdll: ReadWrite), + (0x24 => _reserved0), + /// Uart Status Register. + (0x7c => usr: ReadOnly), + (0x80 => _reserved1), + (0xc0 => dlf: ReadWrite), + (0xc4 => @END), + } +} + +/// dw-apb-uart serial driver: DW8250 +pub struct DW8250 { + base_vaddr: usize, +} + +impl DW8250 { + /// New a DW8250 + pub const fn new(base_vaddr: usize) -> Self { + Self { base_vaddr } + } + + const fn regs(&self) -> &DW8250Regs { + unsafe { &*(self.base_vaddr as *const _) } + } + + /// DW8250 initialize + pub fn init(&mut self) { + const UART_SRC_CLK: u32 = 25000000; + const BST_UART_DLF_LEN: u32 = 6; + const BAUDRATE: u32 = 115200; + //const BAUDRATE: u32 = 38400; + + let get_baud_divider = |baudrate| (UART_SRC_CLK << (BST_UART_DLF_LEN - 4)) / baudrate; + let divider = get_baud_divider(BAUDRATE); + + // Waiting to be no USR_BUSY. + while self.regs().usr.get() & 0b1 != 0 {} + + // bst_serial_hw_init_clk_rst + + /* Disable interrupts and Enable FIFOs */ + self.regs().ier.set(0); + self.regs().fcr.set(1); + + /* Disable flow ctrl */ + self.regs().mcr.set(0); + + /* Clear MCR_RTS */ + self.regs().mcr.set(self.regs().mcr.get() | (1 << 1)); + + /* Enable access DLL & DLH. Set LCR_DLAB */ + self.regs().lcr.set(self.regs().lcr.get() | (1 << 7)); + + /* Set baud rate. Set DLL, DLH, DLF */ + self.regs().rbr.set((divider >> BST_UART_DLF_LEN) & 0xff); + self.regs() + .ier + .set((divider >> (BST_UART_DLF_LEN + 8)) & 0xff); + self.regs().dlf.set(divider & ((1 << BST_UART_DLF_LEN) - 1)); + + /* Clear DLAB bit */ + self.regs().lcr.set(self.regs().lcr.get() & !(1 << 7)); + + /* Set data length to 8 bit, 1 stop bit, no parity. Set LCR_WLS1 | LCR_WLS0 */ + self.regs().lcr.set(self.regs().lcr.get() | 0b11); + } + + /// DW8250 serial output + pub fn putchar(&mut self, c: u8) { + // Check LSR_TEMT + // Wait for last character to go. + while self.regs().lsr.get() & (1 << 6) == 0 {} + self.regs().rbr.set(c as u32); + } + + /// DW8250 serial input + pub fn getchar(&mut self) -> Option { + // Check LSR_DR + // Wait for a character to arrive. + if self.regs().lsr.get() & 0b1 != 0 { + Some((self.regs().rbr.get() & 0xff) as u8) + } else { + None + } + } + + /// DW8250 serial interrupt enable or disable + pub fn set_ier(&mut self, enable: bool) { + if enable { + // Enable interrupts + self.regs().ier.set(1); + } else { + // Disable interrupts + self.regs().ier.set(0); + } + } +} diff --git a/modules/axhal/Cargo.toml b/modules/axhal/Cargo.toml index 6b797f0237..f29ecde07d 100644 --- a/modules/axhal/Cargo.toml +++ b/modules/axhal/Cargo.toml @@ -52,6 +52,7 @@ aarch64-cpu = "9.3" tock-registers = "0.8" arm_gic = { path = "../../crates/arm_gic" } arm_pl011 = { path = "../../crates/arm_pl011" } +dw_apb_uart = { path = "../../crates/dw_apb_uart" } [build-dependencies] axconfig = { path = "../axconfig" } diff --git a/modules/axhal/src/lib.rs b/modules/axhal/src/lib.rs index 20636d2995..9fd27a1b1f 100644 --- a/modules/axhal/src/lib.rs +++ b/modules/axhal/src/lib.rs @@ -28,6 +28,7 @@ #![feature(asm_const)] #![feature(naked_functions)] #![feature(const_maybe_uninit_zeroed)] +#![feature(const_option)] #![feature(doc_auto_cfg)] #[allow(unused_imports)] diff --git a/modules/axhal/src/platform/aarch64_bsta1000b/dw_apb_uart.rs b/modules/axhal/src/platform/aarch64_bsta1000b/dw_apb_uart.rs new file mode 100644 index 0000000000..844a3cbb3c --- /dev/null +++ b/modules/axhal/src/platform/aarch64_bsta1000b/dw_apb_uart.rs @@ -0,0 +1,44 @@ +//! snps,dw-apb-uart serial driver + +use crate::mem::phys_to_virt; +use dw_apb_uart::DW8250; +use memory_addr::PhysAddr; +use spinlock::SpinNoIrq; + +const UART_BASE: PhysAddr = PhysAddr::from(axconfig::UART_PADDR); + +static UART: SpinNoIrq = SpinNoIrq::new(DW8250::new(phys_to_virt(UART_BASE).as_usize())); + +/// Writes a byte to the console. +pub fn putchar(c: u8) { + let mut uart = UART.lock(); + match c { + b'\r' | b'\n' => { + uart.putchar(b'\r'); + uart.putchar(b'\n'); + } + c => uart.putchar(c), + } +} + +/// Reads a byte from the console, or returns [`None`] if no input is available. +pub fn getchar() -> Option { + UART.lock().getchar() +} + +/// UART simply initialize +pub fn init_early() { + UART.lock().init(); +} + +/// Set UART IRQ Enable +#[cfg(feature = "irq")] +pub fn init_irq() { + UART.lock().set_ier(true); + crate::irq::register_handler(crate::platform::irq::UART_IRQ_NUM, handle); +} + +/// UART IRQ Handler +pub fn handle() { + trace!("Uart IRQ Handler"); +} diff --git a/modules/axhal/src/platform/aarch64_bsta1000b/mem.rs b/modules/axhal/src/platform/aarch64_bsta1000b/mem.rs new file mode 100644 index 0000000000..e6faa5ef4e --- /dev/null +++ b/modules/axhal/src/platform/aarch64_bsta1000b/mem.rs @@ -0,0 +1,33 @@ +use crate::mem::{MemRegion, PhysAddr}; +use page_table_entry::{aarch64::A64PTE, GenericPTE, MappingFlags}; + +/// Returns platform-specific memory regions. +pub(crate) fn platform_regions() -> impl Iterator { + crate::mem::default_free_regions().chain(crate::mem::default_mmio_regions()) +} + +pub(crate) unsafe fn init_boot_page_table( + boot_pt_l0: &mut [A64PTE; 512], + boot_pt_l1: &mut [A64PTE; 512], +) { + // 0x0000_0000_0000 ~ 0x0080_0000_0000, table + boot_pt_l0[0] = A64PTE::new_table(PhysAddr::from(boot_pt_l1.as_ptr() as usize)); + // 0x0000_0000_0000..0x0000_4000_0000, 1G block, device memory + boot_pt_l1[0] = A64PTE::new_page( + PhysAddr::from(0), + MappingFlags::READ | MappingFlags::WRITE | MappingFlags::DEVICE, + true, + ); + // 1G block, device memory + boot_pt_l1[1] = A64PTE::new_page( + PhysAddr::from(0x40000000), + MappingFlags::READ | MappingFlags::WRITE | MappingFlags::DEVICE, + true, + ); + // 1G block, normal memory + boot_pt_l1[2] = A64PTE::new_page( + PhysAddr::from(0x80000000), + MappingFlags::READ | MappingFlags::WRITE | MappingFlags::EXECUTE, + true, + ); +} diff --git a/modules/axhal/src/platform/aarch64_bsta1000b/misc.rs b/modules/axhal/src/platform/aarch64_bsta1000b/misc.rs new file mode 100644 index 0000000000..8954132e19 --- /dev/null +++ b/modules/axhal/src/platform/aarch64_bsta1000b/misc.rs @@ -0,0 +1,60 @@ +pub use crate::platform::aarch64_common::psci::system_off as terminate; + +use crate::mem::phys_to_virt; +use crate::time::{busy_wait, Duration}; +use core::ptr::{read_volatile, write_volatile}; + +/// Do QSPI reset +pub fn reset_qspi() { + // qspi exit 4-byte mode + // exit_4byte_qspi(); + + let ptr = phys_to_virt((axconfig::A1000BASE_SAFETYCRM + 0x8).into()).as_mut_ptr() as *mut u32; + unsafe { + let value = read_volatile(ptr); + trace!("SAFETY CRM RESET CTRL = {:#x}", value); + write_volatile(ptr, value & !(0b11 << 15)); + busy_wait(Duration::from_millis(100)); + + write_volatile(ptr, value | (0b11 << 15)); + busy_wait(Duration::from_millis(100)); + } +} + +/// Do CPU reset +pub fn reset_cpu() { + reset_qspi(); + + //Data Width = 32 + let ptr = phys_to_virt((axconfig::A1000BASE_SAFETYCRM + 0x8).into()).as_mut_ptr() as *mut u32; + unsafe { + write_volatile(ptr, read_volatile(ptr) & !0b1); + } + + loop {} +} + +/// reboot system +#[allow(dead_code)] +pub fn do_reset() { + axlog::ax_println!("resetting ...\n"); + + // wait 50 ms + busy_wait(Duration::from_millis(50)); + + // disable_interrupts(); + + reset_cpu(); + + // NOT REACHED + warn!("NOT REACHED Resetting"); +} + +/// bootmode define bit [27:26], from strap pin +#[allow(dead_code)] +pub fn get_bootmode() -> u32 { + unsafe { + let ptr = phys_to_virt((axconfig::A1000BASE_TOPCRM).into()).as_mut_ptr() as *mut u32; + (ptr.read_volatile() >> 26) & 0x7 + } +} diff --git a/modules/axhal/src/platform/aarch64_bsta1000b/mod.rs b/modules/axhal/src/platform/aarch64_bsta1000b/mod.rs new file mode 100644 index 0000000000..8c7634bcf7 --- /dev/null +++ b/modules/axhal/src/platform/aarch64_bsta1000b/mod.rs @@ -0,0 +1,62 @@ +mod dw_apb_uart; + +pub mod mem; +pub mod misc; + +#[cfg(feature = "smp")] +pub mod mp; + +#[cfg(feature = "irq")] +pub mod irq { + pub use crate::platform::aarch64_common::gic::*; +} + +pub mod console { + pub use super::dw_apb_uart::*; +} + +pub mod time { + pub use crate::platform::aarch64_common::generic_timer::*; +} + +extern "C" { + fn exception_vector_base(); + fn rust_main(cpu_id: usize, dtb: usize); + #[cfg(feature = "smp")] + fn rust_main_secondary(cpu_id: usize); +} + +pub(crate) unsafe extern "C" fn rust_entry(cpu_id: usize, dtb: usize) { + crate::mem::clear_bss(); + crate::arch::set_exception_vector_base(exception_vector_base as usize); + crate::cpu::init_primary(cpu_id); + dw_apb_uart::init_early(); + super::aarch64_common::generic_timer::init_early(); + rust_main(cpu_id, dtb); +} + +#[cfg(feature = "smp")] +pub(crate) unsafe extern "C" fn rust_entry_secondary(cpu_id: usize) { + crate::arch::set_exception_vector_base(exception_vector_base as usize); + crate::cpu::init_secondary(cpu_id); + rust_main_secondary(cpu_id); +} + +/// Initializes the platform devices for the primary CPU. +/// +/// For example, the interrupt controller and the timer. +pub fn platform_init() { + #[cfg(feature = "irq")] + super::aarch64_common::gic::init_primary(); + super::aarch64_common::generic_timer::init_percpu(); + #[cfg(feature = "irq")] + dw_apb_uart::init_irq(); +} + +/// Initializes the platform devices for secondary CPUs. +#[cfg(feature = "smp")] +pub fn platform_init_secondary() { + #[cfg(feature = "irq")] + super::aarch64_common::gic::init_secondary(); + super::aarch64_common::generic_timer::init_percpu(); +} diff --git a/modules/axhal/src/platform/aarch64_bsta1000b/mp.rs b/modules/axhal/src/platform/aarch64_bsta1000b/mp.rs new file mode 100644 index 0000000000..489f342fa3 --- /dev/null +++ b/modules/axhal/src/platform/aarch64_bsta1000b/mp.rs @@ -0,0 +1,23 @@ +use crate::mem::{virt_to_phys, PhysAddr, VirtAddr}; + +/// Hart number of bsta1000b board +pub const MAX_HARTS: usize = 8; +/// CPU HWID from cpu device tree nodes with "reg" property +pub const CPU_HWID: [usize; MAX_HARTS] = [0x00, 0x100, 0x200, 0x300, 0x400, 0x500, 0x600, 0x700]; + +/// Starts the given secondary CPU with its boot stack. +pub fn start_secondary_cpu(cpu_id: usize, stack_top: PhysAddr) { + if cpu_id >= MAX_HARTS { + error!("No support for bsta1000b core {}", cpu_id); + return; + } + extern "C" { + fn _start_secondary(); + } + let entry = virt_to_phys(VirtAddr::from(_start_secondary as usize)); + crate::platform::aarch64_common::psci::cpu_on( + CPU_HWID[cpu_id], + entry.as_usize(), + stack_top.as_usize(), + ); +} diff --git a/modules/axhal/src/platform/aarch64_common/gic.rs b/modules/axhal/src/platform/aarch64_common/gic.rs index 0d0aaa0a89..362a73ec78 100644 --- a/modules/axhal/src/platform/aarch64_common/gic.rs +++ b/modules/axhal/src/platform/aarch64_common/gic.rs @@ -1,5 +1,6 @@ use crate::{irq::IrqHandler, mem::phys_to_virt}; use arm_gic::gic_v2::{GicCpuInterface, GicDistributor}; +use arm_gic::{translate_irq, InterruptType}; use memory_addr::PhysAddr; use spinlock::SpinNoIrq; @@ -7,7 +8,10 @@ use spinlock::SpinNoIrq; pub const MAX_IRQ_COUNT: usize = 1024; /// The timer IRQ number. -pub const TIMER_IRQ_NUM: usize = 30; // physical timer, type=PPI, id=14 +pub const TIMER_IRQ_NUM: usize = translate_irq(14, InterruptType::PPI).unwrap(); + +/// The UART IRQ number. +pub const UART_IRQ_NUM: usize = translate_irq(axconfig::UART_IRQ, InterruptType::SPI).unwrap(); const GICD_BASE: PhysAddr = PhysAddr::from(axconfig::GICD_PADDR); const GICC_BASE: PhysAddr = PhysAddr::from(axconfig::GICC_PADDR); @@ -20,6 +24,7 @@ static GICC: GicCpuInterface = GicCpuInterface::new(phys_to_virt(GICC_BASE).as_m /// Enables or disables the given IRQ. pub fn set_enable(irq_num: usize, enabled: bool) { + trace!("GICD set enable: {} {}", irq_num, enabled); GICD.lock().set_enable(irq_num as _, enabled); } @@ -28,6 +33,7 @@ pub fn set_enable(irq_num: usize, enabled: bool) { /// It also enables the IRQ if the registration succeeds. It returns `false` if /// the registration failed. pub fn register_handler(irq_num: usize, handler: IrqHandler) -> bool { + trace!("register handler irq {}", irq_num); crate::irq::register_handler_common(irq_num, handler) } diff --git a/modules/axhal/src/platform/aarch64_common/mod.rs b/modules/axhal/src/platform/aarch64_common/mod.rs index d6630b122b..c585541fe8 100644 --- a/modules/axhal/src/platform/aarch64_common/mod.rs +++ b/modules/axhal/src/platform/aarch64_common/mod.rs @@ -1,8 +1,11 @@ mod boot; pub mod generic_timer; -pub mod pl011; +#[cfg(not(platform_family = "aarch64-raspi"))] pub mod psci; #[cfg(feature = "irq")] pub mod gic; + +#[cfg(not(platform_family = "aarch64-bsta1000b"))] +pub mod pl011; diff --git a/modules/axhal/src/platform/aarch64_common/pl011.rs b/modules/axhal/src/platform/aarch64_common/pl011.rs index d162ce5c22..e1c9083e79 100644 --- a/modules/axhal/src/platform/aarch64_common/pl011.rs +++ b/modules/axhal/src/platform/aarch64_common/pl011.rs @@ -36,7 +36,7 @@ pub fn init_early() { /// Set UART IRQ Enable pub fn init() { #[cfg(feature = "irq")] - crate::platform::irq::set_enable(axconfig::UART_IRQ_NUM, true); + crate::irq::set_enable(crate::platform::irq::UART_IRQ_NUM, true); } /// UART IRQ Handler diff --git a/modules/axhal/src/platform/aarch64_common/psci.rs b/modules/axhal/src/platform/aarch64_common/psci.rs index 09369357a3..feca7ba6db 100644 --- a/modules/axhal/src/platform/aarch64_common/psci.rs +++ b/modules/axhal/src/platform/aarch64_common/psci.rs @@ -1,16 +1,73 @@ +//! ARM Power State Coordination Interface. + #![allow(dead_code)] -//! ARM Power State Coordination Interface. +pub const PSCI_0_2_FN_BASE: u32 = 0x84000000; +pub const PSCI_0_2_64BIT: u32 = 0x40000000; +pub const PSCI_0_2_FN_CPU_SUSPEND: u32 = PSCI_0_2_FN_BASE + 1; +pub const PSCI_0_2_FN_CPU_OFF: u32 = PSCI_0_2_FN_BASE + 2; +pub const PSCI_0_2_FN_CPU_ON: u32 = PSCI_0_2_FN_BASE + 3; +pub const PSCI_0_2_FN_MIGRATE: u32 = PSCI_0_2_FN_BASE + 5; +pub const PSCI_0_2_FN_SYSTEM_OFF: u32 = PSCI_0_2_FN_BASE + 8; +pub const PSCI_0_2_FN_SYSTEM_RESET: u32 = PSCI_0_2_FN_BASE + 9; +pub const PSCI_0_2_FN64_CPU_SUSPEND: u32 = PSCI_0_2_FN_BASE + PSCI_0_2_64BIT + 1; +pub const PSCI_0_2_FN64_CPU_ON: u32 = PSCI_0_2_FN_BASE + PSCI_0_2_64BIT + 3; +pub const PSCI_0_2_FN64_MIGRATE: u32 = PSCI_0_2_FN_BASE + PSCI_0_2_64BIT + 5; -use core::arch::asm; +/// PSCI return values, inclusive of all PSCI versions. +#[derive(PartialEq, Debug)] +#[repr(i32)] +pub enum PsciError { + NotSupported = -1, + InvalidParams = -2, + Denied = -3, + AlreadyOn = -4, + OnPending = -5, + InternalFailure = -6, + NotPresent = -7, + Disabled = -8, + InvalidAddress = -9, +} -const PSCI_CPU_ON: u32 = 0x8400_0003; -const PSCI_SYSTEM_OFF: u32 = 0x8400_0008; +impl From for PsciError { + fn from(code: i32) -> PsciError { + use PsciError::*; + match code { + -1 => NotSupported, + -2 => InvalidParams, + -3 => Denied, + -4 => AlreadyOn, + -5 => OnPending, + -6 => InternalFailure, + -7 => NotPresent, + -8 => Disabled, + -9 => InvalidAddress, + _ => panic!("Unknown PSCI error code: {}", code), + } + } +} +/// arm,psci method: smc +/// when SMCCC_CONDUIT_SMC = 1 +fn arm_smccc_smc(func: u32, arg0: usize, arg1: usize, arg2: usize) -> usize { + let mut ret; + unsafe { + core::arch::asm!( + "smc #0", + inlateout("x0") func as usize => ret, + in("x1") arg0, + in("x2") arg1, + in("x3") arg2, + ) + } + ret +} + +/// psci "hvc" method call fn psci_hvc_call(func: u32, arg0: usize, arg1: usize, arg2: usize) -> usize { let ret; unsafe { - asm!( + core::arch::asm!( "hvc #0", inlateout("x0") func as usize => ret, in("x1") arg0, @@ -21,22 +78,52 @@ fn psci_hvc_call(func: u32, arg0: usize, arg1: usize, arg2: usize) -> usize { ret } +fn psci_call(func: u32, arg0: usize, arg1: usize, arg2: usize) -> Result<(), PsciError> { + let ret = match axconfig::PSCI_METHOD { + "smc" => arm_smccc_smc(func, arg0, arg1, arg2), + "hvc" => psci_hvc_call(func, arg0, arg1, arg2), + _ => panic!("Unknown PSCI method: {}", axconfig::PSCI_METHOD), + }; + if ret == 0 { + Ok(()) + } else { + Err(PsciError::from(ret as i32)) + } +} + /// Shutdown the whole system, including all CPUs. pub fn system_off() -> ! { info!("Shutting down..."); - psci_hvc_call(PSCI_SYSTEM_OFF, 0, 0, 0); + psci_call(PSCI_0_2_FN_SYSTEM_OFF, 0, 0, 0).ok(); warn!("It should shutdown!"); loop { crate::arch::halt(); } } -/// Starts a secondary CPU with the given ID. +/// Power up a core. This call is used to power up cores that either: +/// +/// * Have not yet been booted into the calling supervisory software. +/// * Have been previously powered down with a `cpu_off` call. /// -/// When the CPU is started, it will jump to the given entry and set the -/// corresponding register to the given argument. -pub fn cpu_on(id: usize, entry: usize, arg: usize) { - debug!("Starting core {}...", id); - assert_eq!(psci_hvc_call(PSCI_CPU_ON, id, entry, arg), 0); - debug!("Started core {}!", id); +/// `target_cpu` contains a copy of the affinity fields of the MPIDR register. +/// `entry_point` is the physical address of the secondary CPU's entry point. +/// `arg` will be passed to the `X0` register of the secondary CPU. +pub fn cpu_on(target_cpu: usize, entry_point: usize, arg: usize) { + info!("Starting CPU {:x} ON ...", target_cpu); + let res = psci_call(PSCI_0_2_FN64_CPU_ON, target_cpu, entry_point, arg); + if let Err(e) = res { + error!("failed to boot CPU {:x} ({:?})", target_cpu, e); + } +} + +/// Power down the calling core. This call is intended for use in hotplug. A +/// core that is powered down by `cpu_off` can only be powered up again in +/// response to a `cpu_on`. +pub fn cpu_off() { + const PSCI_POWER_STATE_TYPE_STANDBY: u32 = 0; + const PSCI_POWER_STATE_TYPE_POWER_DOWN: u32 = 1; + const PSCI_0_2_POWER_STATE_TYPE_SHIFT: u32 = 16; + let state: u32 = PSCI_POWER_STATE_TYPE_POWER_DOWN << PSCI_0_2_POWER_STATE_TYPE_SHIFT; + psci_call(PSCI_0_2_FN_CPU_OFF, state as usize, 0, 0).ok(); } diff --git a/modules/axhal/src/platform/aarch64_raspi/mod.rs b/modules/axhal/src/platform/aarch64_raspi/mod.rs index 2a452fa08e..c7c7264d4c 100644 --- a/modules/axhal/src/platform/aarch64_raspi/mod.rs +++ b/modules/axhal/src/platform/aarch64_raspi/mod.rs @@ -17,7 +17,12 @@ pub mod time { } pub mod misc { - pub use crate::platform::aarch64_common::psci::system_off as terminate; + pub fn terminate() -> ! { + info!("Shutting down..."); + loop { + crate::arch::halt(); + } + } } extern "C" { diff --git a/modules/axhal/src/platform/mod.rs b/modules/axhal/src/platform/mod.rs index 66f251a995..a39151c47f 100644 --- a/modules/axhal/src/platform/mod.rs +++ b/modules/axhal/src/platform/mod.rs @@ -19,6 +19,9 @@ cfg_if::cfg_if! { } else if #[cfg(all(target_arch = "aarch64", platform_family = "aarch64-raspi"))] { mod aarch64_raspi; pub use self::aarch64_raspi::*; + } else if #[cfg(all(target_arch = "aarch64", platform_family = "aarch64-bsta1000b"))] { + mod aarch64_bsta1000b; + pub use self::aarch64_bsta1000b::*; } else { mod dummy; pub use self::dummy::*; diff --git a/modules/axruntime/src/mp.rs b/modules/axruntime/src/mp.rs index 2797471683..768ef5188a 100644 --- a/modules/axruntime/src/mp.rs +++ b/modules/axruntime/src/mp.rs @@ -32,7 +32,7 @@ pub fn start_secondary_cpus(primary_cpu_id: usize) { #[no_mangle] pub extern "C" fn rust_main_secondary(cpu_id: usize) -> ! { ENTERED_CPUS.fetch_add(1, Ordering::Relaxed); - info!("Secondary CPU {} started.", cpu_id); + info!("Secondary CPU {:x} started.", cpu_id); #[cfg(feature = "paging")] super::remap_kernel_memory().unwrap(); @@ -42,7 +42,7 @@ pub extern "C" fn rust_main_secondary(cpu_id: usize) -> ! { #[cfg(feature = "multitask")] axtask::init_scheduler_secondary(); - info!("Secondary CPU {} init OK.", cpu_id); + info!("Secondary CPU {:x} init OK.", cpu_id); super::INITED_CPUS.fetch_add(1, Ordering::Relaxed); while !super::is_init_ok() { diff --git a/platforms/aarch64-bsta1000b.toml b/platforms/aarch64-bsta1000b.toml new file mode 100644 index 0000000000..097556a9f3 --- /dev/null +++ b/platforms/aarch64-bsta1000b.toml @@ -0,0 +1,54 @@ +# Architecture identifier. +arch = "aarch64" +# Platform identifier. +platform = "aarch64-bsta1000b" +# Platform family. +family = "aarch64-bsta1000b" + +# Base address of the whole physical memory. +phys-memory-base = "0x80000000" +# Size of the whole physical memory. +phys-memory-size = "0x70000000" +# Base physical address of the kernel image. +kernel-base-paddr = "0x81000000" +# Base virtual address of the kernel image. +kernel-base-vaddr = "0xffff_0000_8100_0000" +# Linear mapping offset, for quick conversions between physical and virtual +# addresses. +phys-virt-offset = "0xffff_0000_0000_0000" +# MMIO regions with format (`base_paddr`, `size`). +mmio-regions = [ + ["0x20008000", "0x1000"], # uart8250 UART0 + ["0x32000000", "0x8000"], # arm,gic-400 + ["0x32011000", "0x1000"], # CPU CSR + ["0x33002000", "0x1000"], # Top CRM + ["0x70035000", "0x1000"], # CRM reg + ["0x70038000", "0x1000"], # aon pinmux +] + +virtio-mmio-regions = [] + +# Base physical address of the PCIe ECAM space. +# pci-ecam-base = "0x40_1000_0000" +# End PCI bus number (`bus-range` property in device tree). +# pci-bus-end = "0xff" +# PCI device memory ranges (`ranges` property in device tree). +# pci-ranges = [] + +# UART Address +uart-paddr = "0x20008000" +# UART irq from device tree +uart-irq = "0xd5" +# GICD Address +gicd-paddr = "0x32001000" +# GICC Address +gicc-paddr = "0x32002000" + +# BST A1000B board registers +CPU_CSR_BASE = "0x32011000" +A1000BASE_TOPCRM = "0x33002000" +A1000BASE_SAFETYCRM = "0x70035000" +A1000BASE_AONCFG = "0x70038000" + +# PSCI +psci-method = "smc" diff --git a/platforms/aarch64-qemu-virt.toml b/platforms/aarch64-qemu-virt.toml index b01d9f5bf7..723bba7eb1 100644 --- a/platforms/aarch64-qemu-virt.toml +++ b/platforms/aarch64-qemu-virt.toml @@ -71,8 +71,11 @@ pci-ranges = [ ] # UART Address uart-paddr = "0x0900_0000" -uart-irq-num = "33" +uart-irq = "1" # GICC Address gicc-paddr = "0x0801_0000" gicd-paddr = "0x0800_0000" + +# PSCI +psci-method = "hvc" diff --git a/platforms/aarch64-raspi4.toml b/platforms/aarch64-raspi4.toml index cfe9d1bb9d..f204d1d1a0 100644 --- a/platforms/aarch64-raspi4.toml +++ b/platforms/aarch64-raspi4.toml @@ -24,7 +24,7 @@ mmio-regions = [ virtio-mmio-regions = [] # UART Address uart-paddr = "0xFE20_1000" -uart-irq-num = "153" +uart-irq = "0x79" # GIC Address gicc-paddr = "0xFF84_2000" diff --git a/scripts/make/bsta1000b-fada.mk b/scripts/make/bsta1000b-fada.mk new file mode 100644 index 0000000000..7a9efe4005 --- /dev/null +++ b/scripts/make/bsta1000b-fada.mk @@ -0,0 +1,4 @@ +fada: build + gzip -9 -cvf $(OUT_BIN) > arceos-fada.bin.gz + mkimage -f tools/bsta1000b/bsta1000b-fada-arceos.its arceos-fada.itb + @echo 'Built the FIT-uImage arceos-fada.itb' diff --git a/scripts/make/raspi4.mk b/scripts/make/raspi4.mk index 7b0b932fb2..66eea697b5 100644 --- a/scripts/make/raspi4.mk +++ b/scripts/make/raspi4.mk @@ -28,9 +28,6 @@ ifeq ($(BSP),rpi4) RUSTC_MISC_ARGS = -C target-cpu=cortex-a72 endif -# Export for build.rs. -export LD_SCRIPT_PATH - EXEC_MINIPUSH = ruby tools/raspi4/common/serial/minipush.rb ##------------------------------------------------------------------------------ @@ -94,4 +91,4 @@ openocd: gdb: RUSTC_MISC_ARGS += -C debuginfo=2 gdb: $(KERNEL_ELF) $(call color_header, "Launching GDB") - @$(DOCKER_GDB) gdb-multiarch -q $(KERNEL_ELF) \ No newline at end of file + @$(DOCKER_GDB) gdb-multiarch -q $(KERNEL_ELF) diff --git a/tools/bsta1000b/bsta1000b-fada-arceos.its b/tools/bsta1000b/bsta1000b-fada-arceos.its new file mode 100755 index 0000000000..8062b6354a --- /dev/null +++ b/tools/bsta1000b/bsta1000b-fada-arceos.its @@ -0,0 +1,50 @@ +/* + * U-Boot uImage source file with multiple kernels, ramdisks and FDT blobs + */ + +/dts-v1/; + +/ { + description = "Various kernels, ramdisks and FDT blobs"; + #address-cells = <1>; + + images { + kernel { + description = "ArceOS for BST A1000B"; + data = /incbin/("../../arceos-fada.bin.gz"); + type = "kernel"; + arch = "arm64"; + os = "linux"; + compression = "gzip"; + load = <0x81000000>; + entry = <0x81000000>; + hash-1 { + algo = "md5"; + }; + hash-2 { + algo = "sha1"; + }; + }; + + fdt-fada { + description = "bsta1000b-fada fdt"; + data = /incbin/("./bsta1000b-fada.dtb"); + type = "flat_dt"; + arch = "arm64"; + compression = "none"; + hash-1 { + algo = "crc32"; + }; + }; + }; + + configurations { + default = "config-fada"; + + config-fada { + description = "bsta1000b fada configuration"; + kernel = "kernel"; + fdt = "fdt-fada"; + }; + }; +}; diff --git a/tools/bsta1000b/bsta1000b-fada.dtb b/tools/bsta1000b/bsta1000b-fada.dtb new file mode 100644 index 0000000000..ff0ea9a42d Binary files /dev/null and b/tools/bsta1000b/bsta1000b-fada.dtb differ