From 2886342e279108c3c5ff5245e3b83de792d3624f Mon Sep 17 00:00:00 2001 From: TKF <60510632+tkf2019@users.noreply.github.com> Date: Mon, 21 Oct 2024 16:57:13 +0800 Subject: [PATCH] Boot ArceOS on Phytium Pi (#190) * Boot ArceOS on Phytium Pi --- doc/platform_phytium_pi.md | 15 +++ modules/axhal/build.rs | 2 + .../axhal/src/platform/aarch64_common/mod.rs | 5 +- .../src/platform/aarch64_phytium_pi/mem.rs | 63 +++++++++++ .../src/platform/aarch64_phytium_pi/mod.rs | 100 ++++++++++++++++++ .../src/platform/aarch64_phytium_pi/mp.rs | 49 +++++++++ modules/axhal/src/platform/mod.rs | 3 + platforms/aarch64-phytium-pi.toml | 81 ++++++++++++++ 8 files changed, 317 insertions(+), 1 deletion(-) create mode 100644 doc/platform_phytium_pi.md create mode 100644 modules/axhal/src/platform/aarch64_phytium_pi/mem.rs create mode 100644 modules/axhal/src/platform/aarch64_phytium_pi/mod.rs create mode 100644 modules/axhal/src/platform/aarch64_phytium_pi/mp.rs create mode 100644 platforms/aarch64-phytium-pi.toml diff --git a/doc/platform_phytium_pi.md b/doc/platform_phytium_pi.md new file mode 100644 index 0000000000..5372a05059 --- /dev/null +++ b/doc/platform_phytium_pi.md @@ -0,0 +1,15 @@ +# How to run ArceOS on Phytium Pi + +See more details in [this doc](https://chenlongos.com/Phytium-Car/ch1-1.html). + +Build ArceOS: `make A=examples/helloworld PLATFORM=aarch64-phytium-pi LOG=trace`. + +Prepare a USB flash disk and copy `examples/helloworld/helloworld_aarch64-phytium-pi.bin` to it. + +Stop autoboot in U-Boot and execute following commands: + +``` +Phytium-Pi# usb start +Phytium-Pi# fatload usb 0:2 0x90100000 helloworld_aarch64-phytium-pi.bin +Phytium-Pi# go 0x90100000 +``` diff --git a/modules/axhal/build.rs b/modules/axhal/build.rs index c40f60359c..d496e62611 100644 --- a/modules/axhal/build.rs +++ b/modules/axhal/build.rs @@ -3,6 +3,7 @@ use std::path::Path; const BUILTIN_PLATFORMS: &[&str] = &[ "aarch64-bsta1000b", + "aarch64-phytium-pi", "aarch64-qemu-virt", "aarch64-raspi4", "riscv64-qemu-virt", @@ -12,6 +13,7 @@ const BUILTIN_PLATFORMS: &[&str] = &[ const BUILTIN_PLATFORM_FAMILIES: &[&str] = &[ "aarch64-bsta1000b", + "aarch64-phytium-pi", "aarch64-qemu-virt", "aarch64-raspi", "riscv64-qemu-virt", diff --git a/modules/axhal/src/platform/aarch64_common/mod.rs b/modules/axhal/src/platform/aarch64_common/mod.rs index c585541fe8..8dfcf412e3 100644 --- a/modules/axhal/src/platform/aarch64_common/mod.rs +++ b/modules/axhal/src/platform/aarch64_common/mod.rs @@ -1,7 +1,10 @@ mod boot; pub mod generic_timer; -#[cfg(not(platform_family = "aarch64-raspi"))] +#[cfg(not(any( + platform_family = "aarch64-raspi", + platform_family = "aarch64-phytium-pi" +)))] pub mod psci; #[cfg(feature = "irq")] diff --git a/modules/axhal/src/platform/aarch64_phytium_pi/mem.rs b/modules/axhal/src/platform/aarch64_phytium_pi/mem.rs new file mode 100644 index 0000000000..ee0df5ffbf --- /dev/null +++ b/modules/axhal/src/platform/aarch64_phytium_pi/mem.rs @@ -0,0 +1,63 @@ +use crate::mem::*; +use page_table_entry::{aarch64::A64PTE, GenericPTE, MappingFlags}; + +/// Returns the default free memory regions (kernel image end to physical memory end). +fn __free_regions() -> impl Iterator { + let start = virt_to_phys( + VirtAddr::from(_ekernel as usize + axconfig::NOCACHE_MEMORY_SIZE).align_up_4k(), + ); + let end = PhysAddr::from(axconfig::PHYS_MEMORY_END); + core::iter::once(MemRegion { + paddr: start, + size: end.as_usize() - start.as_usize(), + flags: MemRegionFlags::FREE | MemRegionFlags::READ | MemRegionFlags::WRITE, + name: "free memory", + }) +} + +/// Returns the default free memory regions (kernel image end to physical memory end). +fn __nocache_regions() -> impl Iterator { + let start = VirtAddr::from(_ekernel as usize).align_up_4k(); + let start = virt_to_phys(start); + + core::iter::once(MemRegion { + paddr: start, + size: axconfig::NOCACHE_MEMORY_SIZE, + flags: MemRegionFlags::DEVICE | MemRegionFlags::READ | MemRegionFlags::WRITE, + name: "nocache memory", + }) +} + +/// Returns platform-specific memory regions. +pub(crate) fn platform_regions() -> impl Iterator { + core::iter::once(MemRegion { + paddr: 0x0.into(), + size: 0x1000, + flags: MemRegionFlags::RESERVED | MemRegionFlags::READ | MemRegionFlags::WRITE, + name: "spintable", + }) + .chain(crate::mem::__nocache_regions()) + .chain(crate::mem::__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], +) { + let boot_pt_l0 = &mut *boot_pt_l0; + let boot_pt_l1 = &mut *boot_pt_l1; + // 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_8000_0000, 1G block, device memory + boot_pt_l1[0] = A64PTE::new_page( + PhysAddr::from(0), + MappingFlags::READ | MappingFlags::WRITE | MappingFlags::DEVICE, + true, + ); + boot_pt_l1[2] = A64PTE::new_page( + PhysAddr::from(0x8000_0000), + MappingFlags::READ | MappingFlags::WRITE | MappingFlags::EXECUTE, + true, + ); +} diff --git a/modules/axhal/src/platform/aarch64_phytium_pi/mod.rs b/modules/axhal/src/platform/aarch64_phytium_pi/mod.rs new file mode 100644 index 0000000000..1bf18c4b8f --- /dev/null +++ b/modules/axhal/src/platform/aarch64_phytium_pi/mod.rs @@ -0,0 +1,100 @@ +pub mod mem; +use core::ptr; + +#[cfg(feature = "smp")] +pub mod mp; + +#[cfg(feature = "irq")] +pub mod irq { + pub use crate::platform::aarch64_common::gic::*; +} + +pub mod console { + pub use crate::platform::aarch64_common::pl011::*; +} + +pub mod time { + pub use crate::platform::aarch64_common::generic_timer::*; +} + +pub mod misc { + pub fn terminate() -> ! { + info!("Shutting down..."); + loop { + crate::arch::halt(); + } + } +} + +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(); + put_debug2(); + crate::arch::set_exception_vector_base(exception_vector_base as usize); + put_debug2(); + crate::arch::write_page_table_root0(0.into()); // disable low address access + put_debug_paged2(); + crate::cpu::init_primary(cpu_id); + put_debug_paged2(); + super::aarch64_common::pl011::init_early(); + put_debug_paged2(); + super::aarch64_common::generic_timer::init_early(); + put_debug_paged2(); + rust_main(cpu_id, dtb); +} + +#[cfg(all(target_arch = "aarch64"))] +#[no_mangle] +unsafe extern "C" fn put_debug2() { + #[cfg(platform_family = "aarch64-phytium-pi")] + { + let state = (0x2800D018 as usize) as *mut u8; + let put = (0x2800D000 as usize) as *mut u8; + while (ptr::read_volatile(state) & (0x20 as u8)) != 0 {} + *put = b'a'; + } +} + +#[cfg(all(target_arch = "aarch64"))] +#[no_mangle] +unsafe extern "C" fn put_debug_paged2() { + #[cfg(platform_family = "aarch64-phytium-pi")] + { + let state = (0xFFFF00002800D018 as usize) as *mut u8; + let put = (0xFFFF00002800D000 as usize) as *mut u8; + while (ptr::read_volatile(state) & (0x20 as u8)) != 0 {} + *put = b'a'; + } +} + +#[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::arch::write_page_table_root0(0.into()); // disable low address access + 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(); + super::aarch64_common::pl011::init(); +} + +/// 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_phytium_pi/mp.rs b/modules/axhal/src/platform/aarch64_phytium_pi/mp.rs new file mode 100644 index 0000000000..23549c01f1 --- /dev/null +++ b/modules/axhal/src/platform/aarch64_phytium_pi/mp.rs @@ -0,0 +1,49 @@ +use crate::mem::{phys_to_virt, virt_to_phys, PhysAddr, VirtAddr}; + +static mut SECONDARY_STACK_TOP: usize = 0; + +extern "C" { + fn _start_secondary(); +} + +#[naked] +#[link_section = ".text.boot"] +unsafe extern "C" fn modify_stack_and_start() { + core::arch::asm!(" + ldr x21, ={secondary_boot_stack} // the secondary CPU hasn't set the TTBR1 + mov x8, {phys_virt_offset} // minus the offset to get the phys addr of the boot stack + sub x21, x21, x8 + ldr x21, [x21] + mov x0, x21 // x0 will be set to SP in the beginning of _start_secondary + b _start_secondary", + secondary_boot_stack = sym SECONDARY_STACK_TOP, + phys_virt_offset = const axconfig::PHYS_VIRT_OFFSET, + options(noreturn) + ); +} + +pub static CPU_SPIN_TABLE: [PhysAddr; 4] = [ + PhysAddr::from(0xd8), + PhysAddr::from(0xe0), + PhysAddr::from(0xe8), + PhysAddr::from(0xf0), +]; + +/// Starts the given secondary CPU with its boot stack. +pub fn start_secondary_cpu(cpu_id: usize, stack_top: PhysAddr) { + let entry_paddr = virt_to_phys(VirtAddr::from(modify_stack_and_start as usize)).as_usize(); + unsafe { + // set the boot code address of the given secondary CPU + let spintable_vaddr = phys_to_virt(CPU_SPIN_TABLE[cpu_id]); + let release_ptr = spintable_vaddr.as_mut_ptr() as *mut usize; + release_ptr.write_volatile(entry_paddr); + crate::arch::flush_dcache_line(spintable_vaddr); + + // set the boot stack of the given secondary CPU + SECONDARY_STACK_TOP = stack_top.as_usize(); + crate::arch::flush_dcache_line(VirtAddr::from( + (&SECONDARY_STACK_TOP as *const usize) as usize, + )); + } + aarch64_cpu::asm::sev(); +} diff --git a/modules/axhal/src/platform/mod.rs b/modules/axhal/src/platform/mod.rs index a39151c47f..349aac9ae0 100644 --- a/modules/axhal/src/platform/mod.rs +++ b/modules/axhal/src/platform/mod.rs @@ -22,6 +22,9 @@ cfg_if::cfg_if! { } else if #[cfg(all(target_arch = "aarch64", platform_family = "aarch64-bsta1000b"))] { mod aarch64_bsta1000b; pub use self::aarch64_bsta1000b::*; + } else if #[cfg(all(target_arch = "aarch64", platform_family = "aarch64-phytium-pi"))] { + mod aarch64_phytium_pi; + pub use self::aarch64_phytium_pi::*; } else { mod dummy; pub use self::dummy::*; diff --git a/platforms/aarch64-phytium-pi.toml b/platforms/aarch64-phytium-pi.toml new file mode 100644 index 0000000000..6ce4a223a6 --- /dev/null +++ b/platforms/aarch64-phytium-pi.toml @@ -0,0 +1,81 @@ +# Architecture identifier. +arch = "aarch64" +# Platform identifier. +platform = "aarch64-phytium-pi" +# Platform family. +family = "aarch64-phytium-pi" + +# Base address of the whole physical memory. +phys-memory-base = "0x8000_0000" +# Size of the whole physical memory. +phys-memory-size = "0x8000_0000" # 2G +# Base physical address of the kernel image. +kernel-base-paddr = "0x9010_0000" +# Base virtual address of the kernel image. +kernel-base-vaddr = "0xffff_0000_9010_0000" +# Linear mapping offset, for quick conversions between physical and virtual +# addresses. +phys-virt-offset = "0xffff_0000_0000_0000" +# Kernel address space base. +kernel-aspace-base = "0xffff_0000_0000_0000" +# Kernel address space size. +kernel-aspace-size = "0x0000_ffff_ffff_f000" +# MMIO regions with format (`base_paddr`, `size`). +mmio-regions = [ + # ["0xFE00_B000", "0x1000"], # mailbox + # ["0xFE20_1000", "0x1000"], # PL011 UART + # ["0xFF84_1000", "0x8000"], # GICv2 + #["0x40000000", "0xfff_ffff"], # pcie ecam + + + # ["0x6_0000_0000", "0x4000_0000"] # pcie control + + + ["0x2800_C000", "0x1000"], # UART 0 + ["0x2800_D000", "0x1000"], # UART 1 + ["0x2800_E000", "0x1000"], # UART 2 + ["0x2800_F000", "0x1000"], # UART 3 + # ["0x32a0_0000", "0x2_0000"], # usb0 + # ["0x32a2_0000", "0x2_0000"], # usb0 + # ["0x3200_C000", "0x2000"], #Ethernet1 + # ["0x3200_E000", "0x2000"], #Ethernet2 + # ["0x3080_0000", "0x8000"], # GICv2 + ["0x3000_0000","0x800_0000"], #other devices + ["0x4000_0000", "0x1000_0000"], # pcie ecam + + ["0x2801_4000", "0x2000"], # MIO0 - I2C + ["0x2801_6000", "0x2000"], # MIO1 - I2C + ["0x2801_8000", "0x2000"], # MIO2 - I2C + ["0x2801_A000", "0x2000"], # MIO3 - I2C + ["0x2801_C000", "0x2000"], # MIO4 - I2C + + ["0x000_2803_4000", "0x1000"], # GPIO0 + ["0x000_2803_5000", "0x1000"], # GPIO1 + ["0x000_2803_6000", "0x1000"], # GPIO2 + ["0x000_2803_7000", "0x1000"], # GPIO3 + ["0x000_2803_8000", "0x1000"], # GPIO4 + ["0x000_2803_9000", "0x1000"], # GPIO5 + + # ["0x6_0000_0000", "0x4000_0000"] # pcie control +] +virtio-mmio-regions = [] +# UART Address +uart-paddr = "0x2800_D000" +uart-irq = "24" + +# MIO0 I2C +MIO0 = "0x2801_4000" + +# GIC Address +gicc-paddr = "0xFF84_2000" +gicd-paddr = "0xFF84_1000" + +# Base physical address of the PCIe ECAM space. +pci-ecam-base = "0x40000000" +# End PCI bus number. +pci-bus-end = "0x2" +# PCI device memory ranges. +pci-ranges = [["0x58000000", "0x7fffffff"], ["0x6_0000_0000", "0x6_3fff_ffff"]] + +# Size of the nocache memory region +nocache-memory-size = "0x60_0000"