Skip to content

Commit

Permalink
[feat] add phytium pi support
Browse files Browse the repository at this point in the history
  • Loading branch information
ZR233 committed Nov 29, 2024
1 parent 82d9a05 commit 687dd36
Show file tree
Hide file tree
Showing 14 changed files with 285 additions and 14 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@
*.bin
qemu.log
rusty-tags.vi
/.project.toml
Binary file added doc/figures/phytium_select_app.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/figures/phytium_select_dtb.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/figures/phytium_select_platform.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
32 changes: 32 additions & 0 deletions doc/platform_phytium_pi.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# How to run ArceOS on phytium pi

First, we need `ostool` to build and upload the image to the board. It also supports windows.

```bash
cargo install ostool
```

We also need to connect the board to the computer with serial port, and connect netwire to the board. The host pc and the board should be in the same network.

Then, we can run it easily.

```bash
# cd arceos main dir.
ostool run uboot
```

![select](./figures/phytium_select_platform.png)

Then, press `1` and `enter` to select phytium pi.

![select](./figures/phytium_select_app.png)

Then, select app you want to run. Item without `arceos-*` are not app and can not run. Here we select `arceos-helloworld` for test.

![select](./figures/phytium_select_dtb.png)

We can ignore select dtb step by pressing `enter` directly. ArceOS dose not support dtb yet.

Then the cmdline will wait for you to put board power on or reset.

You can modify config in `.project.toml` to change the default behavior.
10 changes: 10 additions & 0 deletions modules/axconfig/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,16 @@ fn gen_config_rs(config_path: &Path) -> Result<Vec<u8>> {
}
}
Value::Array(regions) => {
if key == "cpu-id-list" {
writeln!(output, "{comments}")?;
writeln!(output, "pub const {var_name}: &[usize] = &[")?;
for r in regions.iter() {
let r = r.as_str().unwrap();
writeln!(output, "{},", r)?;
}
writeln!(output, "];")?;
}

if key != "mmio-regions" && key != "virtio-mmio-regions" && key != "pci-ranges"
{
continue;
Expand Down
2 changes: 2 additions & 0 deletions modules/axconfig/defconfig.toml
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,5 @@ ticks-per-sec = "100"

# Number of CPUs
smp = "1"

cpu-id-list = []
14 changes: 14 additions & 0 deletions modules/axhal/src/platform/aarch64_common/pl011.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,20 @@ use memory_addr::PhysAddr;

use crate::mem::phys_to_virt;

/// Prints a character to the UART before mmu.
#[allow(unused)]
pub(crate) fn put_char_early(c: u8) {
unsafe {
let reg = axconfig::UART_PADDR as *mut u8;
let state = reg.add(0x18);
let data = reg.add(0x00);

while (state.read_volatile() & 0x20_u8) != 0 {}

data.write_volatile(c);
}
}

const UART_BASE: PhysAddr = pa!(axconfig::UART_PADDR);

static UART: SpinNoIrq<Pl011Uart> =
Expand Down
37 changes: 37 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,37 @@
use crate::mem::*;
use page_table_entry::{aarch64::A64PTE, GenericPTE, MappingFlags};

/// 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::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],
) {
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(pa!(boot_pt_l1.as_ptr() as usize));
// 0x0000_0000_0000..0x0000_8000_0000, 1G block, device memory
boot_pt_l1[0] = A64PTE::new_page(
pa!(0),
MappingFlags::READ | MappingFlags::WRITE | MappingFlags::DEVICE,
true,
);
// 0x0000_8000_0000..0x0000_C000_0000, 2G block, normal memory
boot_pt_l1[2] = A64PTE::new_page(
pa!(0x8000_0000),
MappingFlags::READ | MappingFlags::WRITE | MappingFlags::EXECUTE,
true,
);
}
69 changes: 69 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,69 @@
pub mod mem;

#[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();
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_primary(cpu_id);
super::aarch64_common::pl011::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::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();
}
14 changes: 14 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,14 @@
use crate::mem::{virt_to_phys, PhysAddr};

extern "C" {
fn _start_secondary();
}

/// Starts the given secondary CPU with its boot stack.
pub fn start_secondary_cpu(cpu_id: usize, stack_top: PhysAddr) {
extern "C" {
fn _start_secondary();
}
let entry = virt_to_phys(va!(_start_secondary as usize));
crate::platform::aarch64_common::psci::cpu_on(cpu_id, entry.as_usize(), stack_top.as_usize());
}
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
41 changes: 27 additions & 14 deletions modules/axruntime/src/mp.rs
Original file line number Diff line number Diff line change
@@ -1,28 +1,41 @@
use core::sync::atomic::{AtomicUsize, Ordering};

use axconfig::{SMP, TASK_STACK_SIZE};
use axconfig::{CPU_ID_LIST, SMP, TASK_STACK_SIZE};
use axhal::mem::{virt_to_phys, VirtAddr};

#[link_section = ".bss.stack"]
static mut SECONDARY_BOOT_STACK: [[u8; TASK_STACK_SIZE]; SMP - 1] = [[0; TASK_STACK_SIZE]; SMP - 1];

static ENTERED_CPUS: AtomicUsize = AtomicUsize::new(1);

fn start_secondary_cpus_one(primary_cpu_id: usize, cpu_id: usize, cpu_i: &mut usize) {
if cpu_id != primary_cpu_id && *cpu_i < SMP {
let stack_top = virt_to_phys(VirtAddr::from(unsafe {
SECONDARY_BOOT_STACK[*cpu_i].as_ptr_range().end as usize
}));

debug!("starting CPU {}...", cpu_id);
axhal::mp::start_secondary_cpu(cpu_id, stack_top);
*cpu_i += 1;

while ENTERED_CPUS.load(Ordering::Acquire) <= *cpu_i {
core::hint::spin_loop();
}
}
}

pub fn start_secondary_cpus(primary_cpu_id: usize) {
let mut logic_cpu_id = 0;
for i in 0..SMP {
if i != primary_cpu_id {
let stack_top = virt_to_phys(VirtAddr::from(unsafe {
SECONDARY_BOOT_STACK[logic_cpu_id].as_ptr_range().end as usize
}));

debug!("starting CPU {}...", i);
axhal::mp::start_secondary_cpu(i, stack_top);
logic_cpu_id += 1;

while ENTERED_CPUS.load(Ordering::Acquire) <= logic_cpu_id {
core::hint::spin_loop();
let mut cpu_i = 0;
if CPU_ID_LIST.is_empty() {
for id in 0..SMP {
start_secondary_cpus_one(primary_cpu_id, id, &mut cpu_i);
}
} else {
for (i, id) in CPU_ID_LIST.iter().enumerate() {
if i >= SMP {
break;
}
start_secondary_cpus_one(primary_cpu_id, *id, &mut cpu_i);
}
}
}
Expand Down
76 changes: 76 additions & 0 deletions platforms/aarch64-phytium-pi.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
# 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 = "0x9000_0000"
# Base virtual address of the kernel image.
kernel-base-vaddr = "0xffff_0000_9000_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 = [
["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

["0x58000000", "0x7fffffff"], # 32-bit MMIO space

["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"

# PSCI
psci-method = "smc"

# 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 = [
["0x0", "0x50000000"], # PIO space
["0x58000000", "0x7fffffff"], # 32-bit MMIO space
["0x6_0000_0000", "0x6_3fff_ffff"], # 64-but MMIO space
]

cpu-id-list = ["0x0", "0x100", "0x200", "0x201"]

0 comments on commit 687dd36

Please sign in to comment.