Skip to content

Commit

Permalink
Boot ArceOS on Phytium Pi (#190)
Browse files Browse the repository at this point in the history
* Boot ArceOS on Phytium Pi
  • Loading branch information
tkf2019 authored Oct 21, 2024
1 parent f03dcbb commit 2886342
Show file tree
Hide file tree
Showing 8 changed files with 317 additions and 1 deletion.
15 changes: 15 additions & 0 deletions doc/platform_phytium_pi.md
Original file line number Diff line number Diff line change
@@ -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
```
2 changes: 2 additions & 0 deletions modules/axhal/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -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",
Expand Down
5 changes: 4 additions & 1 deletion modules/axhal/src/platform/aarch64_common/mod.rs
Original file line number Diff line number Diff line change
@@ -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")]
Expand Down
63 changes: 63 additions & 0 deletions modules/axhal/src/platform/aarch64_phytium_pi/mem.rs
Original file line number Diff line number Diff line change
@@ -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<Item = MemRegion> {
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<Item = MemRegion> {
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<Item = MemRegion> {
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,
);
}
100 changes: 100 additions & 0 deletions modules/axhal/src/platform/aarch64_phytium_pi/mod.rs
Original file line number Diff line number Diff line change
@@ -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();
}
49 changes: 49 additions & 0 deletions modules/axhal/src/platform/aarch64_phytium_pi/mp.rs
Original file line number Diff line number Diff line change
@@ -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();
}
3 changes: 3 additions & 0 deletions modules/axhal/src/platform/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::*;
Expand Down
81 changes: 81 additions & 0 deletions platforms/aarch64-phytium-pi.toml
Original file line number Diff line number Diff line change
@@ -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"

0 comments on commit 2886342

Please sign in to comment.