diff --git a/address/src/phys.rs b/address/src/phys.rs index b679e67..4baff2a 100644 --- a/address/src/phys.rs +++ b/address/src/phys.rs @@ -87,6 +87,13 @@ impl From for VirtualAddress< } } +impl From for usize { + #[inline(always)] + fn from(p: PhysicalAddress) -> Self { + p.0 as usize + } +} + #[cfg(target_pointer_width = "64")] impl From for u64 { #[inline(always)] diff --git a/address/src/virt.rs b/address/src/virt.rs index 6f11cb7..28185cd 100644 --- a/address/src/virt.rs +++ b/address/src/virt.rs @@ -121,6 +121,11 @@ impl VirtualAddress { pub unsafe fn as_mut(self) -> &'static mut U { &mut *(self.0 as *mut U) } + + #[inline(always)] + pub unsafe fn from_ref(r: &U) -> Self { + Self(r as *const U as usize, PhantomData) + } } // Step diff --git a/kernel/src/arch/cpu.rs b/kernel/src/arch/cpu.rs index 9f14e9d..afce2ba 100644 --- a/kernel/src/arch/cpu.rs +++ b/kernel/src/arch/cpu.rs @@ -1,4 +1,5 @@ use crate::{ + arch::intrin, entry_common, mem::phys::{self, PageUsage}, proc::Scheduler, @@ -23,19 +24,20 @@ static CPU_COUNT: AtomicUsize = AtomicUsize::new(1); #[inline(always)] pub fn get_cpu() -> &'static mut Cpu { - unsafe { - let mut out: usize; - llvm_asm!("mrs $0, tpidr_el1":"=r"(out)); - &mut *(out as *mut _) - } + unsafe { &mut *(intrin::read_tpidr_el1() as *mut _) } } fn set_cpu(cpu: *mut Cpu) { unsafe { - llvm_asm!("msr tpidr_el1, $0"::"r"(cpu)); + intrin::write_tpidr_el1(cpu as usize); } } +#[inline(always)] +pub fn get_phys_id() -> usize { + intrin::read_mpidr_el1() & 0x3 +} + #[no_mangle] extern "C" fn kernel_ap_main() -> ! { let cpu = get_cpu(); @@ -82,7 +84,7 @@ pub fn wakeup_single_ap() { // Wakeup a single AP for test core::ptr::write_volatile(&mut ap_init_value, cpu_addr_phys.into()); // Ensure all writes are complete before waking up an AP - llvm_asm!("dsb sy"); + intrin::dsb_sy(); core::ptr::write_volatile(&mut ap_wakeup_lock, 0); } diff --git a/kernel/src/arch/intrin.rs b/kernel/src/arch/intrin.rs new file mode 100644 index 0000000..d103c55 --- /dev/null +++ b/kernel/src/arch/intrin.rs @@ -0,0 +1,60 @@ +#[inline(always)] +pub unsafe fn disable_irq() { + llvm_asm!("msr daifset, #0xF"); +} + +#[inline(always)] +pub unsafe fn enable_irq() { + llvm_asm!("msr daifclr, #0xF"); +} + +// TPIDR +#[inline(always)] +pub fn read_tpidr_el1() -> usize { + let mut out: usize; + unsafe { + llvm_asm!("mrs $0, tpidr_el1":"=r"(out)); + } + out +} + +#[inline(always)] +pub unsafe fn write_tpidr_el1(value: usize) { + llvm_asm!("msr tpidr_el1, $0"::"r"(value)); +} + +// MPIDR +#[inline(always)] +pub fn read_mpidr_el1() -> usize { + let mut out: usize; + unsafe { + llvm_asm!("mrs $0, mpidr_el1":"=r"(out)); + } + out +} + +// CNTP_CTL +#[inline(always)] +pub unsafe fn write_cntp_ctl_el0(value: usize) { + llvm_asm!("msr cntp_ctl_el0, $0"::"r"(value)); +} + +// CNTP_CVAL +pub fn read_cntp_cval_el0() -> usize { + let mut out: usize; + unsafe { + llvm_asm!("mrs $0, cntp_cval_el0":"=r"(out)); + } + out +} + +pub unsafe fn write_cntp_cval_el0(value: usize) { + llvm_asm!("msr cntp_cval_el0, $0"::"r"(value)); +} + +#[inline(always)] +pub fn dsb_sy() { + unsafe { + llvm_asm!("dsb sy"); + } +} diff --git a/kernel/src/arch/mbox.rs b/kernel/src/arch/mbox.rs new file mode 100644 index 0000000..ef8952b --- /dev/null +++ b/kernel/src/arch/mbox.rs @@ -0,0 +1,81 @@ +use super::{intrin, mmio_read, mmio_write}; +use crate::KernelSpace; +use address::{PhysicalAddress, VirtualAddress}; + +const MBOX_BASE: usize = 0x3F00B880; +const MBOX_READ: usize = MBOX_BASE + 0x00; +const MBOX_POLL: usize = MBOX_BASE + 0x10; +const MBOX_STATUS: usize = MBOX_BASE + 0x18; +const MBOX_WRITE: usize = MBOX_BASE + 0x20; + +const MBOX_STATUS_FULL: u32 = 1 << 31; +const MBOX_STATUS_EMPTY: u32 = 1 << 30; + +const MBOX_RESPONSE: u32 = 1 << 31; +const MBOX_REQUEST: u32 = 0; + +const MBOX_CHAR_PROPERTY: u32 = 8; + +const MBOX_TAG_GET_SERIAL: u32 = 0x10004; +const MBOX_TAG_GET_REV: u32 = 0x10002; +const MBOX_TAG_GET_MODEL: u32 = 0x10001; +const MBOX_TAG_GET_ARM_MEMORY: u32 = 0x10005; +const MBOX_TAG_LAST: u32 = 0; + +#[repr(C, align(16))] +#[derive(Debug)] +struct Message { + data: [u32; 36], +} + +static mut MESSAGE: Message = Message { data: [0; 36] }; + +unsafe fn call(ch: u32) -> Result<(), ()> { + let value = (usize::from(PhysicalAddress::from( + VirtualAddress::::from_ref(&MESSAGE), + )) as u32) + | (ch & 0xF); + + while mmio_read(MBOX_STATUS) & MBOX_STATUS_FULL != 0 { + llvm_asm!("nop"); + } + + intrin::dsb_sy(); + mmio_write(MBOX_WRITE, value); + + loop { + while mmio_read(MBOX_STATUS) & MBOX_STATUS_EMPTY != 0 { + llvm_asm!("nop"); + } + + if mmio_read(MBOX_READ) == value { + if MESSAGE.data[1] == MBOX_RESPONSE { + return Ok(()); + } else { + return Err(()); + } + } + } +} + +pub fn get_arm_memory() -> Result { + unsafe { + MESSAGE.data[0] = 8 * 4; + MESSAGE.data[1] = MBOX_REQUEST; + + MESSAGE.data[2] = MBOX_TAG_GET_ARM_MEMORY; + MESSAGE.data[3] = 8; + MESSAGE.data[4] = 0; + MESSAGE.data[5] = 0; + MESSAGE.data[6] = 0; + + MESSAGE.data[7] = MBOX_TAG_LAST; + + call(MBOX_CHAR_PROPERTY)?; + + assert!(MESSAGE.data[4] == 0x80000008); // Response of 8 bytes + assert!(MESSAGE.data[5] == 0x00000000); // Base address of RAM is zero + + Ok(MESSAGE.data[6] as usize) + } +} diff --git a/kernel/src/arch/mod.rs b/kernel/src/arch/mod.rs index fa3caab..7a833f0 100644 --- a/kernel/src/arch/mod.rs +++ b/kernel/src/arch/mod.rs @@ -1,9 +1,11 @@ -use address::{PhysicalAddress, VirtualAddress}; use crate::KernelSpace; +use address::{PhysicalAddress, VirtualAddress}; -pub mod exception; -pub mod timer; pub mod cpu; +pub mod exception; +pub mod intrin; +pub mod mbox; +pub mod timer; pub unsafe fn mmio_write(addr: usize, value: u32) { core::ptr::write_volatile( diff --git a/kernel/src/arch/timer.rs b/kernel/src/arch/timer.rs index 2488ef3..d69977c 100644 --- a/kernel/src/arch/timer.rs +++ b/kernel/src/arch/timer.rs @@ -1,4 +1,4 @@ -use super::{cpu::get_cpu, mmio_read, mmio_write}; +use super::{cpu, intrin, mmio_read, mmio_write}; pub struct LocalTimer; @@ -10,15 +10,10 @@ impl LocalTimer { // as I didn't yet write a way to determine // "ARM" core number pub unsafe fn enable() { - let mut phys_core_id: usize; - llvm_asm!(r#" - mrs $0, mpidr_el1; - and $0, $0, #3 - "#:"=r"(phys_core_id)); - + let phys_core_id = cpu::get_phys_id(); debug!( "cpu{}: physical core id is {}\n", - get_cpu().cpu_id, + cpu::get_cpu().cpu_id, phys_core_id ); @@ -26,21 +21,13 @@ impl LocalTimer { let tmp = mmio_read(CORE_TIMER_INTC + 4 * phys_core_id); mmio_write(CORE_TIMER_INTC + 4 * phys_core_id, tmp | (1 << 1)); - llvm_asm!( - r#" - mov x0, #1 - msr cntp_ctl_el0, x0 - "# - ); + intrin::write_cntp_ctl_el0(1); } pub fn update(value: usize) { + let current = intrin::read_cntp_cval_el0(); unsafe { - llvm_asm!(r#" - mrs x0, cntpct_el0 - add x0, x0, $0 - msr cntp_cval_el0, x0 - "#::"r"(value):"x0"); + intrin::write_cntp_cval_el0(current + value); } } } diff --git a/kernel/src/main.rs b/kernel/src/main.rs index c69edfb..4298564 100644 --- a/kernel/src/main.rs +++ b/kernel/src/main.rs @@ -13,14 +13,14 @@ pub mod proc; pub use mem::KernelSpace; use address::PhysicalAddress; +use arch::{cpu, intrin, mbox, timer::LocalTimer}; use mem::phys::{SimpleMemoryIterator, UsableMemory}; -use arch::{cpu, timer::LocalTimer}; pub fn entry_common() -> ! { cpu::wakeup_single_ap(); unsafe { - llvm_asm!("msr daifset, #0xF"); + intrin::disable_irq(); LocalTimer::enable(); } proc::enter(); @@ -28,12 +28,13 @@ pub fn entry_common() -> ! { #[no_mangle] extern "C" fn kernel_bsp_main() -> ! { - // TODO determine VC/ARM split cpu::bsp_init(); + let arm_memory = mbox::get_arm_memory().expect("Failed to determine ARM memory"); + let iter = SimpleMemoryIterator::new(UsableMemory { start: PhysicalAddress::from(0usize), - end: PhysicalAddress::from(0x30000000usize), + end: PhysicalAddress::from(arm_memory), }); unsafe { mem::phys::initialize(iter); diff --git a/kernel/src/mem/phys/reserved.rs b/kernel/src/mem/phys/reserved.rs index 9db375d..ab1e7ea 100644 --- a/kernel/src/mem/phys/reserved.rs +++ b/kernel/src/mem/phys/reserved.rs @@ -32,7 +32,7 @@ impl ReservedRegion { ReservedRegion { start, end, - next: null_mut() + next: null_mut(), } } } @@ -55,10 +55,7 @@ pub(super) unsafe fn reserve_kernel() { } pub(super) unsafe fn reserve_pages(base: PhysicalAddress, count: usize) { - RESERVED_REGION_PAGES.write(ReservedRegion::new( - base, - base + count * PAGE_SIZE - )); + RESERVED_REGION_PAGES.write(ReservedRegion::new(base, base + count * PAGE_SIZE)); reserve(RESERVED_REGION_PAGES.as_mut_ptr()); } diff --git a/kernel/src/proc/context.rs b/kernel/src/proc/context.rs index a5b9dc9..9bcbd18 100644 --- a/kernel/src/proc/context.rs +++ b/kernel/src/proc/context.rs @@ -9,8 +9,8 @@ global_asm!(include_str!("context.S")); #[repr(C)] pub(super) struct Context { - pub kernel_sp: VirtualAddress, // 0x00 - cpu_id: u32, // 0x08 + pub kernel_sp: VirtualAddress, // 0x00 + cpu_id: u32, // 0x08 } struct StackBuilder { @@ -50,10 +50,7 @@ impl Context { impl StackBuilder { pub unsafe fn new(bp: VirtualAddress, size: usize) -> Self { - Self { - bp, - sp: bp + size, - } + Self { bp, sp: bp + size } } pub fn push>(&mut self, value: A) { @@ -73,4 +70,3 @@ extern "C" { fn context_enter_kernel(); } -