diff --git a/Cargo.lock b/Cargo.lock index f0aae7d..db6846e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -57,6 +57,12 @@ version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" +[[package]] +name = "cc" +version = "1.0.97" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "099a5357d84c4c61eb35fc8eafa9a79a902c2f76911e5747ced4e032edd8d9b4" + [[package]] name = "cfg-if" version = "1.0.0" @@ -75,6 +81,22 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "361a90feb7004eca4019fb28352a9465666b24f840f5c3cddf0ff13920590b89" +[[package]] +name = "errno" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +dependencies = [ + "libc", + "windows-sys", +] + +[[package]] +name = "fastrand" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" + [[package]] name = "fdt" version = "0.1.5" @@ -89,6 +111,18 @@ dependencies = [ "spin", ] +[[package]] +name = "libc" +version = "0.2.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae743338b92ff9146ce83992f766a31066a91a8c84a45e0e9f21e7cf6de6d346" + +[[package]] +name = "linux-raw-sys" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" + [[package]] name = "lock_api" version = "0.4.11" @@ -115,6 +149,15 @@ dependencies = [ "bitflags 1.3.2", ] +[[package]] +name = "memoffset" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" +dependencies = [ + "autocfg", +] + [[package]] name = "multiboot" version = "0.8.0" @@ -124,6 +167,19 @@ dependencies = [ "paste", ] +[[package]] +name = "nix" +version = "0.23.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f3790c00a0150112de0f4cd161e3d7fc4b2d8a5542ffc35f099a2562aecb35c" +dependencies = [ + "bitflags 1.3.2", + "cc", + "cfg-if", + "libc", + "memoffset", +] + [[package]] name = "paste" version = "1.0.14" @@ -165,12 +221,14 @@ dependencies = [ "log", "loongArch64", "multiboot", + "nix", "percpu", "polyhal-macro", "raw-cpuid 11.0.1", "riscv", "sbi-rt", "spin", + "tempfile", "tock-registers", "x2apic", "x86", @@ -232,6 +290,19 @@ dependencies = [ "embedded-hal", ] +[[package]] +name = "rustix" +version = "0.38.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" +dependencies = [ + "bitflags 2.5.0", + "errno", + "libc", + "linux-raw-sys", + "windows-sys", +] + [[package]] name = "rustversion" version = "1.0.15" @@ -288,6 +359,18 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "tempfile" +version = "3.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" +dependencies = [ + "cfg-if", + "fastrand", + "rustix", + "windows-sys", +] + [[package]] name = "tock-registers" version = "0.8.1" @@ -306,6 +389,79 @@ version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "442887c63f2c839b346c192d047a7c87e73d0689c9157b00b53dcc27dd5ea793" +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" + [[package]] name = "x2apic" version = "0.4.3" diff --git a/Cargo.toml b/Cargo.toml index 4d50f5c..0bdb26a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,16 +12,23 @@ repository = "https://github.com/Byte-OS/polyhal" [features] kcontext = [] multicore = [] +libos = [ + "nix", + "tempfile" +] default = ["multicore"] [dependencies] log = "0.4" +nix = { version = "0.23", optional = true} +tempfile = { version = "3", optional = true} fdt = "0.1.5" -bitflags = "2.0.2" +bitflags = "2.0.1" cfg-if = "1.0.0" percpu = { git = "https://github.com/Byte-OS/percpu.git" } polyhal-macro = { path = "polyhal-macro" } +spin = { version = "0.9.8", features = ["mutex"] } [target.'cfg(target_arch = "riscv64")'.dependencies] riscv = "0.11.0" @@ -30,7 +37,6 @@ sbi-rt = { version = "0.0.2", features = ["legacy"] } [target.'cfg(target_arch = "x86_64")'.dependencies] x86 = "0.52" x86_64 = "0.14" -spin = { version = "0.9.8", features = ["mutex"] } irq_safety = { git = "https://github.com/theseus-os/irq_safety.git" } multiboot = "0.8.0" x2apic = "0.4" @@ -46,3 +52,6 @@ arm_gic = { git = "https://github.com/Byte-OS/arm_gic" } [target.'cfg(target_arch = "loongarch64")'.dependencies] spin = { version = "0.9.8", features = ["mutex"] } loongArch64 = "0.2.2" + +[profile.release] +debug = true \ No newline at end of file diff --git a/src/aarch64/gic.rs b/src/aarch64/gic.rs deleted file mode 100644 index d6c4cd9..0000000 --- a/src/aarch64/gic.rs +++ /dev/null @@ -1,46 +0,0 @@ -use arm_gic::gic_v2::{GicCpuInterface, GicDistributor}; -use arm_gic::{translate_irq, InterruptType}; -use irq_safety::MutexIrqSafe; - -use crate::addr::PhysAddr; - -/// The maximum number of IRQs. -#[allow(dead_code)] -pub const MAX_IRQ_COUNT: usize = 1024; - -/// The timer IRQ number. -pub const TIMER_IRQ_NUM: usize = translate_irq(14, InterruptType::PPI).unwrap(); - -/// The UART IRQ number. -#[allow(dead_code)] -pub const UART_IRQ_NUM: usize = translate_irq(1, InterruptType::SPI).unwrap(); - -const GICD_BASE: PhysAddr = PhysAddr::new(0x0800_0000); -const GICC_BASE: PhysAddr = PhysAddr::new(0x0801_0000); - -static GICD: MutexIrqSafe = - MutexIrqSafe::new(GicDistributor::new(GICD_BASE.get_mut_ptr())); - -// per-CPU, no lock -static GICC: GicCpuInterface = GicCpuInterface::new(GICC_BASE.get_mut_ptr()); - -/// 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); -} - -/// Initializes GICD, GICC on the primary CPU. -pub(crate) fn init() { - info!("Initialize GICv2..."); - GICD.lock().init(); - GICC.init(); -} - -#[inline] -pub fn handle_irq(f: F) -where - F: FnOnce(u32), -{ - GICC.handle_irq(f) -} diff --git a/src/bare/addr.rs b/src/bare/addr.rs new file mode 100644 index 0000000..332d64d --- /dev/null +++ b/src/bare/addr.rs @@ -0,0 +1,95 @@ +use core::{ + ffi::CStr, + mem::size_of, +}; + +use crate::common::addr::{PhysAddr, PhysPage, VirtAddr}; + +use crate::{PageTable, VIRT_ADDR_START}; + +impl PhysAddr { + #[inline] + pub fn get_ptr(&self) -> *const T { + (self.0 | VIRT_ADDR_START) as *const T + } + + #[inline] + pub const fn get_mut_ptr(&self) -> *mut T { + (self.0 | VIRT_ADDR_START) as *mut T + } + + #[inline] + pub fn slice_with_len(&self, len: usize) -> &'static [T] { + unsafe { core::slice::from_raw_parts(self.get_ptr(), len) } + } + + #[inline] + pub fn slice_mut_with_len(&self, len: usize) -> &'static mut [T] { + unsafe { core::slice::from_raw_parts_mut(self.get_mut_ptr(), len) } + } + + #[inline] + pub fn get_cstr(&self) -> &CStr { + unsafe { CStr::from_ptr(self.get_ptr::()) } + } +} + +impl VirtAddr { + #[inline] + pub fn floor(&self) -> Self { + Self(self.0 / PageTable::PAGE_SIZE * PageTable::PAGE_SIZE) + } + + #[inline] + pub fn ceil(&self) -> Self { + Self((self.0 + PageTable::PAGE_SIZE - 1) / PageTable::PAGE_SIZE * PageTable::PAGE_SIZE) + } +} + + +impl PhysPage { + #[inline] + pub const fn get_buffer(&self) -> &'static mut [u8] { + unsafe { + core::slice::from_raw_parts_mut( + (self.0 << 12 | VIRT_ADDR_START) as *mut u8, + PageTable::PAGE_SIZE, + ) + } + } + + #[inline] + pub fn copy_value_from_another(&self, ppn: PhysPage) { + self.get_buffer().copy_from_slice(&ppn.get_buffer()); + #[cfg(c906)] + unsafe { + asm!(".long 0x0010000b"); // dcache.all + asm!(".long 0x01b0000b"); // sync.is + } + #[cfg(board = "2k1000")] + unsafe { + core::arch::asm!("dbar 0;ibar 0;") + } + } + + #[inline] + pub fn drop_clear(&self) { + // self.get_buffer().fill(0); + unsafe { + core::slice::from_raw_parts_mut( + (self.0 << 12 | VIRT_ADDR_START) as *mut usize, + PageTable::PAGE_SIZE / size_of::(), + ) + .fill(0); + } + #[cfg(board = "2k1000")] + unsafe { + core::arch::asm!("dbar 0;ibar 0;") + } + #[cfg(c906)] + unsafe { + asm!(".long 0x0010000b"); // dcache.all + asm!(".long 0x01b0000b"); // sync.is + } + } +} \ No newline at end of file diff --git a/src/api.rs b/src/bare/api.rs similarity index 92% rename from src/api.rs rename to src/bare/api.rs index 043be68..7d51a49 100644 --- a/src/api.rs +++ b/src/bare/api.rs @@ -1,4 +1,4 @@ -use crate::addr::PhysPage; +use crate::common::addr::PhysPage; use crate::{TrapFrame, TrapType, PAGE_ALLOC}; extern "Rust" { diff --git a/src/aarch64/barrier.rs b/src/bare/arch/aarch64/barrier.rs similarity index 100% rename from src/aarch64/barrier.rs rename to src/bare/arch/aarch64/barrier.rs diff --git a/src/aarch64/boot.rs b/src/bare/arch/aarch64/boot.rs similarity index 99% rename from src/aarch64/boot.rs rename to src/bare/arch/aarch64/boot.rs index 36c71ff..3a93dd1 100644 --- a/src/aarch64/boot.rs +++ b/src/bare/arch/aarch64/boot.rs @@ -1,4 +1,4 @@ -use crate::{pagetable::TLB, PTEFlags}; +use crate::{TLB, PTEFlags}; use aarch64_cpu::{asm, asm::barrier, registers::*}; // use page_table_entry::aarch64::{MemAttr, A64PTE}; diff --git a/src/aarch64/consts.rs b/src/bare/arch/aarch64/consts.rs similarity index 100% rename from src/aarch64/consts.rs rename to src/bare/arch/aarch64/consts.rs diff --git a/src/aarch64/context.rs b/src/bare/arch/aarch64/context.rs similarity index 93% rename from src/aarch64/context.rs rename to src/bare/arch/aarch64/context.rs index 94b89cc..80d3385 100644 --- a/src/aarch64/context.rs +++ b/src/bare/arch/aarch64/context.rs @@ -34,6 +34,12 @@ impl TrapFrame { ] } + /// Check if the trapframe was from user. + #[inline] + pub fn from_user(&self) -> bool { + (self.spsr >> 2) & 0x3 == 0 + } + #[inline] pub fn syscall_ok(&mut self) {} } @@ -70,4 +76,4 @@ impl IndexMut for TrapFrame { TrapFrameArgs::SYSCALL => &mut self.regs[8], } } -} +} \ No newline at end of file diff --git a/src/bare/arch/aarch64/gic.rs b/src/bare/arch/aarch64/gic.rs new file mode 100644 index 0000000..b1fa018 --- /dev/null +++ b/src/bare/arch/aarch64/gic.rs @@ -0,0 +1,89 @@ +use aarch64_cpu::registers::{Readable, DAIF}; +use tock_registers::interfaces::ReadWriteable; +use crate::addr::PhysAddr; +use crate::irq::{IRQVector, IRQ}; +use arm_gic::gic_v2::{GicCpuInterface, GicDistributor}; +use arm_gic::{translate_irq, InterruptType}; +use irq_safety::MutexIrqSafe; + +/// The maximum number of IRQs. +#[allow(dead_code)] +pub const MAX_IRQ_COUNT: usize = 1024; + +/// The timer IRQ number. +pub const TIMER_IRQ_NUM: usize = translate_irq(14, InterruptType::PPI).unwrap(); + +/// The UART IRQ number. +#[allow(dead_code)] +pub const UART_IRQ_NUM: usize = translate_irq(1, InterruptType::SPI).unwrap(); + +const GICD_BASE: PhysAddr = PhysAddr::new(0x0800_0000); +const GICC_BASE: PhysAddr = PhysAddr::new(0x0801_0000); + +static GICD: MutexIrqSafe = + MutexIrqSafe::new(GicDistributor::new(GICD_BASE.get_mut_ptr())); + +// per-CPU, no lock +static GICC: GicCpuInterface = GicCpuInterface::new(GICC_BASE.get_mut_ptr()); + +/// Initializes GICD, GICC on the primary CPU. +pub(crate) fn init() { + info!("Initialize GICv2..."); + GICD.lock().init(); + GICC.init(); +} + +/// Implmente the irq vector methods +impl IRQVector { + /// Get the irq number in this vector + #[inline] + pub const fn irq_num(&self) -> usize { + self.0 & 0x3ff + } + + /// Acknowledge the irq + pub fn ack(&self) { + GICC.eoi(self.0 as u32); + } +} + +/// Get the irq Vector that was +#[inline] +pub fn get_irq() -> IRQVector { + IRQVector(GICC.iar() as _) +} + +impl IRQ { + /// Enable irq for the given IRQ number. + #[inline] + pub fn irq_enable(irq_num: usize) { + GICD.lock().set_enable(irq_num, true); + // GICD.lock().configure_interrupt(irq_num, arm_gic::TriggerMode::Level); + } + + /// Disable irq for the given IRQ number. + #[inline] + pub fn irq_disable(irq_num: usize) { + GICD.lock().set_enable(irq_num, false); + } + + /// Enable interrupt. + #[inline] + pub fn int_enable() { + unsafe { core::arch::asm!("msr daifclr, #2") }; + // DAIF.modify(DAIF::I::Unmasked); + } + + /// Disable interrupt. + #[inline] + pub fn int_disable() { + unsafe { core::arch::asm!("msr daifset, #2") }; + // DAIF.modify(DAIF::I::Masked); + } + + /// Check if the interrupt was enabled. + #[inline] + pub fn int_enabled() -> bool { + DAIF.read(DAIF::I) == 0 + } +} \ No newline at end of file diff --git a/src/aarch64/kcontext.rs b/src/bare/arch/aarch64/kcontext.rs similarity index 100% rename from src/aarch64/kcontext.rs rename to src/bare/arch/aarch64/kcontext.rs diff --git a/src/aarch64/mod.rs b/src/bare/arch/aarch64/mod.rs similarity index 70% rename from src/aarch64/mod.rs rename to src/bare/arch/aarch64/mod.rs index ec33f2c..31f1f3e 100644 --- a/src/aarch64/mod.rs +++ b/src/bare/arch/aarch64/mod.rs @@ -14,6 +14,7 @@ mod trap; use core::slice; +use crate::debug::{display_info, println}; use aarch64_cpu::registers::CPACR_EL1; use aarch64_cpu::registers::{Readable, Writeable, MPIDR_EL1, TTBR0_EL1}; use alloc::vec::Vec; @@ -26,12 +27,12 @@ pub use kcontext::{context_switch, context_switch_pt, read_current_tp, KContext} pub use page_table::*; pub use psci::system_off as shutdown; -pub use trap::{disable_irq, enable_external_irq, enable_irq, run_user_task}; +pub use trap::run_user_task; -use crate::multicore::MultiCore; -use crate::once::LazyInit; -use crate::pagetable::PageTable; -use crate::{clear_bss, CPU_NUM, DTB_BIN, MEM_AREA}; +use super::{clear_bss, CPU_NUM, DTB_BIN, MEM_AREA}; +use crate::utils::once::LazyInit; +use crate::MultiCore; +use crate::PageTable; static DTB_PTR: LazyInit = LazyInit::new(); @@ -55,8 +56,28 @@ pub fn rust_tmp_main(hart_id: usize, device_tree: usize) { CPACR_EL1.write(CPACR_EL1::FPEN::TrapNothing); aarch64_cpu::asm::barrier::isb(aarch64_cpu::asm::barrier::SY); + // Display Polyhal and Platform Information + display_info!(); + println!(include_str!("../../../common/banner.txt")); + display_info!("Platform Name", "aarch64"); + if let Ok(fdt) = unsafe { Fdt::from_ptr(device_tree as *const u8) } { + display_info!("Platform HART Count", "{}", fdt.cpus().count()); + fdt.memory().regions().for_each(|x| { + display_info!( + "Platform Memory Region", + "{:#p} - {:#018x}", + x.starting_address, + x.starting_address as usize + x.size.unwrap() + ); + }); + } + display_info!("Platform Virt Mem Offset", "{:#x}", VIRT_ADDR_START); + display_info!(); + display_info!("Boot HART ID", "{}", hart_id); + display_info!(); + // Enter to kernel entry point(`main` function). - unsafe { crate::api::_main_for_arch(hart_id) }; + unsafe { crate::_main_for_arch(hart_id) }; shutdown(); } diff --git a/src/aarch64/page_table.rs b/src/bare/arch/aarch64/page_table.rs similarity index 99% rename from src/aarch64/page_table.rs rename to src/bare/arch/aarch64/page_table.rs index 015ea58..dabb89b 100644 --- a/src/aarch64/page_table.rs +++ b/src/bare/arch/aarch64/page_table.rs @@ -1,7 +1,8 @@ use aarch64_cpu::registers::{Writeable, TTBR0_EL1}; use crate::addr::{PhysAddr, PhysPage, VirtAddr, VirtPage}; -use crate::pagetable::{MappingFlags, PageTable, PTE, TLB}; +use crate::{MappingFlags, PageTable, PTE, TLB}; +use crate::bit; impl PTE { #[inline] diff --git a/src/aarch64/pl011.rs b/src/bare/arch/aarch64/pl011.rs similarity index 92% rename from src/aarch64/pl011.rs rename to src/bare/arch/aarch64/pl011.rs index be2c7a3..d527dab 100644 --- a/src/aarch64/pl011.rs +++ b/src/bare/arch/aarch64/pl011.rs @@ -3,7 +3,8 @@ use arm_pl011::pl011::Pl011Uart; use irq_safety::MutexIrqSafe; -use crate::{addr::PhysAddr, debug::DebugConsole}; +use crate::addr::PhysAddr; +use crate::debug::DebugConsole; const UART_BASE: PhysAddr = PhysAddr(0x0900_0000); diff --git a/src/aarch64/psci.rs b/src/bare/arch/aarch64/psci.rs similarity index 100% rename from src/aarch64/psci.rs rename to src/bare/arch/aarch64/psci.rs diff --git a/src/aarch64/timer.rs b/src/bare/arch/aarch64/timer.rs similarity index 85% rename from src/aarch64/timer.rs rename to src/bare/arch/aarch64/timer.rs index 6cc1837..5bad27a 100644 --- a/src/aarch64/timer.rs +++ b/src/bare/arch/aarch64/timer.rs @@ -3,7 +3,7 @@ use aarch64_cpu::registers::{CNTFRQ_EL0, CNTPCT_EL0, CNTP_CTL_EL0, CNTP_TVAL_EL0}; use tock_registers::interfaces::{Readable, Writeable}; -use crate::time::Time; +use crate::{irq::IRQ, time::Time}; impl Time { #[inline] @@ -27,6 +27,7 @@ pub fn init() { debug!("freq: {}", freq); CNTP_CTL_EL0.write(CNTP_CTL_EL0::ENABLE::SET); CNTP_TVAL_EL0.set(0); - super::gic::set_enable(super::gic::TIMER_IRQ_NUM, true); + // Enable the timer irq. + IRQ::irq_enable(super::gic::TIMER_IRQ_NUM); set_next_timer(); } diff --git a/src/aarch64/trap.S b/src/bare/arch/aarch64/trap.S similarity index 99% rename from src/aarch64/trap.S rename to src/bare/arch/aarch64/trap.S index 82b66df..0dec969 100644 --- a/src/aarch64/trap.S +++ b/src/bare/arch/aarch64/trap.S @@ -35,7 +35,7 @@ .macro USER_TRAP, kind .p2align 7 - msr daifset, #2 + msr daifset, #2 str x1, [sp, 17 * 8] ldr x1, [sp, 16 * 8] diff --git a/src/aarch64/trap.rs b/src/bare/arch/aarch64/trap.rs similarity index 88% rename from src/aarch64/trap.rs rename to src/bare/arch/aarch64/trap.rs index 4a114a5..2769b1e 100644 --- a/src/aarch64/trap.rs +++ b/src/bare/arch/aarch64/trap.rs @@ -1,15 +1,16 @@ use core::arch::{asm, global_asm}; -use aarch64_cpu::registers::{Writeable, ESR_EL1, FAR_EL1, VBAR_EL1}; +use aarch64_cpu::registers::{Writeable, ESR_EL1, FAR_EL1, SCTLR_EL2::I, VBAR_EL1}; use tock_registers::interfaces::Readable; use crate::{ - currrent_arch::{gic::handle_irq, timer::set_next_timer}, + current_arch::{gic::TIMER_IRQ_NUM, timer::set_next_timer}, instruction::Instruction, + irq::IRQVector, TrapType, }; -use super::TrapFrame; +use super::{gic::get_irq, TrapFrame}; global_asm!(include_str!("trap.S")); @@ -36,9 +37,17 @@ enum TrapSource { #[no_mangle] fn handle_exception(tf: &mut TrapFrame, kind: TrapKind, source: TrapSource) -> TrapType { if kind == TrapKind::Irq { - set_next_timer(); - handle_irq(|_irq| {}); - return TrapType::Time; + let irq = get_irq(); + let trap_type = match irq.irq_num() { + TIMER_IRQ_NUM => { + irq.ack(); + set_next_timer(); + TrapType::Time + } + _ => TrapType::Irq(irq), + }; + unsafe { crate::api::_interrupt_for_arch(tf, trap_type) }; + return trap_type; } if kind != TrapKind::Synchronous { panic!( @@ -88,7 +97,7 @@ fn handle_exception(tf: &mut TrapFrame, kind: TrapKind, source: TrapSource) -> T ); } }; - unsafe { crate::api::_interrupt_for_arch(tf, trap_type) }; + unsafe { crate::_interrupt_for_arch(tf, trap_type) }; trap_type } diff --git a/src/loongarch64/barrier.rs b/src/bare/arch/loongarch64/barrier.rs similarity index 100% rename from src/loongarch64/barrier.rs rename to src/bare/arch/loongarch64/barrier.rs diff --git a/src/loongarch64/boot.rs b/src/bare/arch/loongarch64/boot.rs similarity index 100% rename from src/loongarch64/boot.rs rename to src/bare/arch/loongarch64/boot.rs diff --git a/src/loongarch64/console.rs b/src/bare/arch/loongarch64/console.rs similarity index 100% rename from src/loongarch64/console.rs rename to src/bare/arch/loongarch64/console.rs diff --git a/src/loongarch64/consts.rs b/src/bare/arch/loongarch64/consts.rs similarity index 100% rename from src/loongarch64/consts.rs rename to src/bare/arch/loongarch64/consts.rs diff --git a/src/loongarch64/context.rs b/src/bare/arch/loongarch64/context.rs similarity index 100% rename from src/loongarch64/context.rs rename to src/bare/arch/loongarch64/context.rs diff --git a/src/loongarch64/kcontext.rs b/src/bare/arch/loongarch64/kcontext.rs similarity index 100% rename from src/loongarch64/kcontext.rs rename to src/bare/arch/loongarch64/kcontext.rs diff --git a/src/loongarch64/mod.rs b/src/bare/arch/loongarch64/mod.rs similarity index 87% rename from src/loongarch64/mod.rs rename to src/bare/arch/loongarch64/mod.rs index d79cb2d..203c880 100644 --- a/src/loongarch64/mod.rs +++ b/src/bare/arch/loongarch64/mod.rs @@ -11,7 +11,8 @@ mod timer; mod trap; mod unaligned; -use crate::{clear_bss, multicore::MultiCore, CPU_NUM, DTB_BIN, MEM_AREA}; +use crate::MultiCore; +use super::{clear_bss, CPU_NUM, DTB_BIN, MEM_AREA}; use alloc::vec::Vec; pub use consts::*; pub use context::TrapFrame; @@ -19,7 +20,7 @@ pub use context::TrapFrame; pub use kcontext::{context_switch, context_switch_pt, read_current_tp, KContext}; use loongArch64::register::euen; pub use page_table::kernel_page_table; -pub use trap::{disable_irq, enable_external_irq, enable_irq, run_user_task}; +pub use trap::run_user_task; pub fn rust_tmp_main(hart_id: usize) { clear_bss(); @@ -33,7 +34,7 @@ pub fn rust_tmp_main(hart_id: usize) { CPU_NUM.init_by(2); - unsafe { crate::api::_main_for_arch(hart_id) }; + unsafe { crate::_main_for_arch(hart_id) }; shutdown(); } diff --git a/src/loongarch64/page_table.rs b/src/bare/arch/loongarch64/page_table.rs similarity index 97% rename from src/loongarch64/page_table.rs rename to src/bare/arch/loongarch64/page_table.rs index a555522..9f8984f 100644 --- a/src/loongarch64/page_table.rs +++ b/src/bare/arch/loongarch64/page_table.rs @@ -1,11 +1,9 @@ use loongArch64::register::pgdl; -use crate::{ - addr::{PhysAddr, PhysPage, VirtAddr, VirtPage}, - pagetable::{MappingFlags, PageTable, PTE, TLB}, -}; +use crate::{addr::{PhysAddr, PhysPage, VirtAddr, VirtPage}, MappingFlags, PageTable, PTE, TLB}; use super::sigtrx::get_trx_mapping; +use crate::bit; impl PTE { #[inline] diff --git a/src/loongarch64/sigtrx.rs b/src/bare/arch/loongarch64/sigtrx.rs similarity index 95% rename from src/loongarch64/sigtrx.rs rename to src/bare/arch/loongarch64/sigtrx.rs index b03fa18..2f90b22 100644 --- a/src/loongarch64/sigtrx.rs +++ b/src/bare/arch/loongarch64/sigtrx.rs @@ -1,5 +1,5 @@ use crate::{ - pagetable::{MappingFlags, PageTable, PTE}, + {MappingFlags, PageTable, PTE}, PAGE_SIZE, VIRT_ADDR_START, }; diff --git a/src/bare/arch/loongarch64/timer.rs b/src/bare/arch/loongarch64/timer.rs new file mode 100644 index 0000000..fec861f --- /dev/null +++ b/src/bare/arch/loongarch64/timer.rs @@ -0,0 +1,69 @@ +use loongArch64::register::ecfg::{self, LineBasedInterrupt}; +use loongArch64::register::tcfg; +/// Returns the current clock time in hardware ticks. +use loongArch64::time::{get_timer_freq, Time}; +use spin::Lazy; +use crate::irq::IRQ; + +// static mut FREQ: usize = 0; +static FREQ: Lazy = Lazy::new(|| get_timer_freq()); + +impl crate::time::Time { + #[inline] + pub fn get_freq() -> usize { + *FREQ + } + + /// Returns the current clock time in hardware ticks. + #[inline] + pub fn now() -> Self { + Self(Time::read()) + } +} + +pub fn init_timer() { + let ticks = ((*FREQ / 1000) + 3) & !3; + tcfg::set_periodic(true); // set timer to one-shot mode + tcfg::set_init_val(ticks); // set timer initial value + tcfg::set_en(true); // enable timer + + let inter = LineBasedInterrupt::TIMER + | LineBasedInterrupt::SWI0 + | LineBasedInterrupt::SWI1 + | LineBasedInterrupt::HWI0; + ecfg::set_lie(inter); +} + +/// Implement IRQ operations for the IRQ interface. +impl IRQ { + /// Enable irq for the given IRQ number. + #[inline] + pub fn irq_enable(_irq_num: usize) { + log::warn!("irq not implemented in loongarch64 platform yet"); + } + + /// Disable irq for the given IRQ number. + #[inline] + pub fn irq_disable(_irq_num: usize) { + log::warn!("irq not implemented in loongarch64 platform yet"); + } + + /// Enable interrupt + #[inline] + pub fn int_enable() { + log::warn!("int_enable not implemented in loongarch64 platform yet"); + } + + /// Disable interrupt + #[inline] + pub fn int_disable() { + log::warn!("int_disable not implemented in loongarch64 platform yet"); + } + + /// Check if the interrupt was enabled. + #[inline] + pub fn int_enabled() -> bool { + log::warn!("int_enabled not implemented in loongarch64 platform yet"); + false + } +} \ No newline at end of file diff --git a/src/loongarch64/trap.rs b/src/bare/arch/loongarch64/trap.rs similarity index 97% rename from src/loongarch64/trap.rs rename to src/bare/arch/loongarch64/trap.rs index 9c6bf53..fdf9772 100644 --- a/src/loongarch64/trap.rs +++ b/src/bare/arch/loongarch64/trap.rs @@ -227,7 +227,7 @@ pub unsafe extern "C" fn trap_vector_base() { LOAD_REGS ertn ", - trapframe_size = const crate::consts::TRAPFRAME_SIZE, + trapframe_size = const crate::TRAPFRAME_SIZE, user_vec = sym user_vec, trap_handler = sym loongarch64_trap_handler, options(noreturn) @@ -349,7 +349,9 @@ fn loongarch64_trap_handler(tf: &mut TrapFrame) -> TrapType { // TrapType::Un TrapType::StorePageFault(badv::read().vaddr()) } - Trap::Exception(Exception::LoadPageFault) => TrapType::LoadPageFault(badv::read().vaddr()), + Trap::Exception(Exception::FetchPageFault) | Trap::Exception(Exception::LoadPageFault) => { + TrapType::LoadPageFault(badv::read().vaddr()) + } _ => { panic!( "Unhandled trap {:?} @ {:#x} BADV: {:#x}:\n{:#x?}", @@ -361,6 +363,6 @@ fn loongarch64_trap_handler(tf: &mut TrapFrame) -> TrapType { } }; // info!("return to addr: {:#x}", tf.era); - unsafe { crate::api::_interrupt_for_arch(tf, trap_type) }; + unsafe { crate::_interrupt_for_arch(tf, trap_type) }; trap_type } diff --git a/src/loongarch64/unaligned.rs b/src/bare/arch/loongarch64/unaligned.rs similarity index 100% rename from src/loongarch64/unaligned.rs rename to src/bare/arch/loongarch64/unaligned.rs diff --git a/src/x86_64/barrier.rs b/src/bare/arch/riscv64/barrier.rs similarity index 81% rename from src/x86_64/barrier.rs rename to src/bare/arch/riscv64/barrier.rs index 6a42705..bcc15ba 100644 --- a/src/x86_64/barrier.rs +++ b/src/bare/arch/riscv64/barrier.rs @@ -1,4 +1,4 @@ -use crate::mem::Barrier; +use crate::Barrier; impl Barrier { #[inline] diff --git a/src/riscv64/boards/cv1811h-fdt.dtb b/src/bare/arch/riscv64/boards/cv1811h-fdt.dtb similarity index 100% rename from src/riscv64/boards/cv1811h-fdt.dtb rename to src/bare/arch/riscv64/boards/cv1811h-fdt.dtb diff --git a/src/riscv64/boards/cv1811h-fdt.dts b/src/bare/arch/riscv64/boards/cv1811h-fdt.dts similarity index 100% rename from src/riscv64/boards/cv1811h-fdt.dts rename to src/bare/arch/riscv64/boards/cv1811h-fdt.dts diff --git a/src/riscv64/boards/cv1811h.rs b/src/bare/arch/riscv64/boards/cv1811h.rs similarity index 100% rename from src/riscv64/boards/cv1811h.rs rename to src/bare/arch/riscv64/boards/cv1811h.rs diff --git a/src/riscv64/boards/jh7110-visionfive-v2.dtb b/src/bare/arch/riscv64/boards/jh7110-visionfive-v2.dtb similarity index 100% rename from src/riscv64/boards/jh7110-visionfive-v2.dtb rename to src/bare/arch/riscv64/boards/jh7110-visionfive-v2.dtb diff --git a/src/riscv64/boards/jh7110-visionfive-v2.dts b/src/bare/arch/riscv64/boards/jh7110-visionfive-v2.dts similarity index 100% rename from src/riscv64/boards/jh7110-visionfive-v2.dts rename to src/bare/arch/riscv64/boards/jh7110-visionfive-v2.dts diff --git a/src/riscv64/boards/k210.rs b/src/bare/arch/riscv64/boards/k210.rs similarity index 100% rename from src/riscv64/boards/k210.rs rename to src/bare/arch/riscv64/boards/k210.rs diff --git a/src/riscv64/boards/mod.rs b/src/bare/arch/riscv64/boards/mod.rs similarity index 100% rename from src/riscv64/boards/mod.rs rename to src/bare/arch/riscv64/boards/mod.rs diff --git a/src/riscv64/boards/qemu.rs b/src/bare/arch/riscv64/boards/qemu.rs similarity index 100% rename from src/riscv64/boards/qemu.rs rename to src/bare/arch/riscv64/boards/qemu.rs diff --git a/src/riscv64/consts.rs b/src/bare/arch/riscv64/consts.rs similarity index 100% rename from src/riscv64/consts.rs rename to src/bare/arch/riscv64/consts.rs diff --git a/src/riscv64/context.rs b/src/bare/arch/riscv64/context.rs similarity index 94% rename from src/riscv64/context.rs rename to src/bare/arch/riscv64/context.rs index 1474f9e..69ab738 100644 --- a/src/riscv64/context.rs +++ b/src/bare/arch/riscv64/context.rs @@ -3,7 +3,7 @@ use core::{ ops::{Index, IndexMut}, }; -use riscv::register::sstatus::{self, Sstatus}; +use riscv::register::sstatus::{self, Sstatus, SPP}; use crate::TrapFrameArgs; @@ -75,6 +75,12 @@ impl TrapFrame { self.x[10..16].try_into().expect("args slice force convert") } + /// Check if the trapframe was from user. + #[inline] + pub fn from_user(&self) -> bool { + self.sstatus.spp() == SPP::User + } + #[inline] pub fn syscall_ok(&mut self) { self.sepc += 4; diff --git a/src/riscv64/entry.rs b/src/bare/arch/riscv64/entry.rs similarity index 98% rename from src/riscv64/entry.rs rename to src/bare/arch/riscv64/entry.rs index 1bf79ce..91e6e37 100644 --- a/src/riscv64/entry.rs +++ b/src/bare/arch/riscv64/entry.rs @@ -1,9 +1,9 @@ use core::arch::riscv64::sfence_vma_all; -use crate::pagetable::{PageTable, PTE}; -use crate::VIRT_ADDR_START; - use super::page_table::PTEFlags; +use crate::addr::PhysAddr; +use crate::VIRT_ADDR_START; +use crate::{PageTable, PTE}; #[link_section = ".data.prepage.entry"] pub(crate) static mut PAGE_TABLE: [PTE; PageTable::PTE_NUM_IN_PAGE] = { @@ -144,7 +144,7 @@ pub fn switch_to_kernel_page_table() { } pub fn kernel_page_table() -> PageTable { - PageTable(crate::addr::PhysAddr(unsafe { + PageTable(PhysAddr(unsafe { PAGE_TABLE.as_ptr() as usize & !VIRT_ADDR_START })) } diff --git a/src/riscv64/interrupt.rs b/src/bare/arch/riscv64/interrupt.rs similarity index 97% rename from src/riscv64/interrupt.rs rename to src/bare/arch/riscv64/interrupt.rs index 2ecee7a..7183692 100644 --- a/src/riscv64/interrupt.rs +++ b/src/bare/arch/riscv64/interrupt.rs @@ -83,7 +83,7 @@ static USER_RSP: usize = 0; // 设置中断 pub(crate) fn init_interrupt() { - crate::currrent_arch::page_table::sigtrx::init(); + crate::current_arch::page_table::sigtrx::init(); // 输出内核信息 unsafe { @@ -141,7 +141,7 @@ fn kernel_callback(context: &mut TrapFrame) -> TrapType { panic!("未知中断: {:#x?}", context); } }; - unsafe { crate::api::_interrupt_for_arch(context, trap_type) }; + unsafe { crate::_interrupt_for_arch(context, trap_type) }; trap_type } @@ -169,7 +169,7 @@ pub unsafe extern "C" fn kernelvec() { LOAD_GENERAL_REGS sret ", - cx_size = const crate::consts::TRAPFRAME_SIZE, + cx_size = const crate::TRAPFRAME_SIZE, options(noreturn) ) } diff --git a/src/bare/arch/riscv64/irq.rs b/src/bare/arch/riscv64/irq.rs new file mode 100644 index 0000000..95254e9 --- /dev/null +++ b/src/bare/arch/riscv64/irq.rs @@ -0,0 +1,50 @@ +use crate::irq::{IRQVector, IRQ}; +use riscv::register::sstatus::{self, clear_sie, set_sie}; + +/// Implement IRQ operations for the IRQ interface. +impl IRQ { + /// Enable irq for the given IRQ number. + #[inline] + pub fn irq_enable(_irq_num: usize) { + log::warn!("irq not implemented in riscv platform yet"); + } + + /// Disable irq for the given IRQ number. + #[inline] + pub fn irq_disable(_irq_num: usize) { + log::warn!("irq not implemented in riscv platform yet"); + } + + /// Enable interrupts. + #[inline] + pub fn int_enable() { + unsafe { set_sie() } + } + + /// Disable interrupts. + #[inline] + pub fn int_disable() { + unsafe { clear_sie() } + } + + /// Check if the interrupts was enabled. + #[inline] + pub fn int_enabled() -> bool { + sstatus::read().sie() + } +} + +/// Implmente the irq vector methods +impl IRQVector { + /// Get the irq number in this vector + #[inline] + pub fn irq_num(&self) -> usize { + log::warn!("ack not implemented in riscv platform yet"); + self.0 + } + + /// Acknowledge the irq + pub fn ack(&self) { + log::warn!("ack not implemented in riscv platform yet"); + } +} diff --git a/src/riscv64/kcontext.rs b/src/bare/arch/riscv64/kcontext.rs similarity index 100% rename from src/riscv64/kcontext.rs rename to src/bare/arch/riscv64/kcontext.rs diff --git a/src/riscv64/mod.rs b/src/bare/arch/riscv64/mod.rs similarity index 76% rename from src/riscv64/mod.rs rename to src/bare/arch/riscv64/mod.rs index 93b7d48..38f55f7 100644 --- a/src/riscv64/mod.rs +++ b/src/bare/arch/riscv64/mod.rs @@ -4,6 +4,7 @@ mod consts; mod context; mod entry; mod interrupt; +mod irq; #[cfg(feature = "kcontext")] mod kcontext; mod page_table; @@ -13,13 +14,12 @@ mod timer; use core::slice; use alloc::vec::Vec; +pub use boards::*; pub use consts::*; pub use context::TrapFrame; -pub use entry::{kernel_page_table, switch_to_kernel_page_table}; +pub use entry::kernel_page_table; use fdt::Fdt; -pub use interrupt::{ - disable_irq, enable_external_irq, enable_irq, run_user_task, run_user_task_forever, -}; +pub use interrupt::run_user_task; use sbi::*; pub use sbi::shutdown; @@ -27,9 +27,11 @@ pub use sbi::shutdown; #[cfg(feature = "kcontext")] pub use kcontext::{context_switch, context_switch_pt, read_current_tp, KContext}; -use riscv::register::sstatus; +use riscv::register::{sie, sstatus}; -use crate::{api::frame_alloc, multicore::MultiCore, once::LazyInit, CPU_NUM, DTB_BIN, MEM_AREA}; +use super::{CPU_NUM, DTB_BIN, MEM_AREA}; +use crate::debug::{display_info, println}; +use crate::{frame_alloc, utils::once::LazyInit, MultiCore}; #[percpu::def_percpu] static CPU_ID: usize = 0; @@ -37,7 +39,7 @@ static CPU_ID: usize = 0; static DTB_PTR: LazyInit = LazyInit::new(); pub(crate) fn rust_main(hartid: usize, device_tree: usize) { - crate::clear_bss(); + super::clear_bss(); // Init allocator percpu::init(4); percpu::set_local_thread_pointer(hartid); @@ -51,6 +53,8 @@ pub(crate) fn rust_main(hartid: usize, device_tree: usize) { unsafe { // 开启浮点运算 sstatus::set_fs(sstatus::FS::Dirty); + sie::set_sext(); + sie::set_ssoft(); } CPU_NUM.init_by(match unsafe { Fdt::from_ptr(device_tree as *const u8) } { @@ -60,7 +64,26 @@ pub(crate) fn rust_main(hartid: usize, device_tree: usize) { DTB_PTR.init_by(device_tree); - unsafe { crate::api::_main_for_arch(hartid) }; + display_info!(); + println!(include_str!("../../../common/banner.txt")); + display_info!("Platform Name", "riscv64"); + if let Ok(fdt) = unsafe { Fdt::from_ptr(device_tree as *const u8) } { + display_info!("Platform HART Count", "{}", fdt.cpus().count()); + fdt.memory().regions().for_each(|x| { + display_info!( + "Platform Memory Region", + "{:#p} - {:#018x}", + x.starting_address, + x.starting_address as usize + x.size.unwrap() + ); + }); + } + display_info!("Platform Virt Mem Offset", "{:#x}", VIRT_ADDR_START); + display_info!(); + display_info!("Boot HART ID", "{}", hartid); + display_info!(); + + unsafe { crate::_main_for_arch(hartid) }; shutdown(); } @@ -75,10 +98,12 @@ pub(crate) extern "C" fn rust_secondary_main(hartid: usize) { unsafe { // 开启浮点运算 sstatus::set_fs(sstatus::FS::Dirty); + sie::set_sext(); + sie::set_ssoft(); } info!("secondary hart {} started", hartid); - unsafe { crate::api::_main_for_arch(hartid) }; + unsafe { crate::_main_for_arch(hartid) }; shutdown(); } @@ -132,10 +157,7 @@ impl MultiCore { /// Boot all application cores. pub fn boot_all() { use self::entry::secondary_start; - use crate::{ - addr::VirtPage, - pagetable::{MappingFlags, MappingSize, PageTable}, - }; + use crate::{addr::VirtPage, MappingFlags, MappingSize, PageTable}; let page_table = PageTable::current(); diff --git a/src/riscv64/page_table/mod.rs b/src/bare/arch/riscv64/page_table/mod.rs similarity index 94% rename from src/riscv64/page_table/mod.rs rename to src/bare/arch/riscv64/page_table/mod.rs index 9f07067..61d7238 100644 --- a/src/riscv64/page_table/mod.rs +++ b/src/bare/arch/riscv64/page_table/mod.rs @@ -1,12 +1,12 @@ pub mod sigtrx; -mod sv39; +pub mod sv39; use core::arch::riscv64::sfence_vma; pub use sv39::*; use crate::addr::VirtAddr; -use crate::pagetable::TLB; +use crate::TLB; /// TLB operations impl TLB { diff --git a/src/riscv64/page_table/sigtrx.rs b/src/bare/arch/riscv64/page_table/sigtrx.rs similarity index 93% rename from src/riscv64/page_table/sigtrx.rs rename to src/bare/arch/riscv64/page_table/sigtrx.rs index acd352e..42bce9b 100644 --- a/src/riscv64/page_table/sigtrx.rs +++ b/src/bare/arch/riscv64/page_table/sigtrx.rs @@ -1,7 +1,4 @@ -use crate::{ - pagetable::{PageTable, PTE}, - VIRT_ADDR_START, -}; +use crate::{PageTable, PTE, VIRT_ADDR_START}; use super::PTEFlags; diff --git a/src/riscv64/page_table/sv39.rs b/src/bare/arch/riscv64/page_table/sv39.rs similarity index 97% rename from src/riscv64/page_table/sv39.rs rename to src/bare/arch/riscv64/page_table/sv39.rs index e8ab7a6..c666b9b 100644 --- a/src/riscv64/page_table/sv39.rs +++ b/src/bare/arch/riscv64/page_table/sv39.rs @@ -3,8 +3,9 @@ use riscv::register::satp; use crate::addr::{PhysAddr, PhysPage, VirtAddr, VirtPage}; use crate::kernel_page_table; -use crate::pagetable::MappingFlags; -use crate::pagetable::{PageTable, PTE, TLB}; +use crate::MappingFlags; +use crate::{PageTable, PTE, TLB}; +use crate::bit; use super::sigtrx::get_trx_mapping; @@ -198,9 +199,9 @@ impl PageTable { self.release(); let kernel_arr = Self::get_pte_list(kernel_page_table().0); let arr = Self::get_pte_list(self.0); - arr[0x100..].copy_from_slice(&kernel_arr[0x100..]); + arr[0x100..].copy_from_slice(&kernel_arr[0x100..]); // 0xffff ffc000000000 // TODO: using map kernel in the boot instead of map here manually - arr[0x104] = PTE::from_addr(get_trx_mapping(), PTEFlags::V); + arr[0x104] = PTE::from_addr(get_trx_mapping(), PTEFlags::V); // 0xffff ffc100000000 arr[0..0x100].fill(PTE(0)); } diff --git a/src/riscv64/sbi.rs b/src/bare/arch/riscv64/sbi.rs similarity index 100% rename from src/riscv64/sbi.rs rename to src/bare/arch/riscv64/sbi.rs diff --git a/src/riscv64/timer.rs b/src/bare/arch/riscv64/timer.rs similarity index 92% rename from src/riscv64/timer.rs rename to src/bare/arch/riscv64/timer.rs index 89aa91b..42dda20 100644 --- a/src/riscv64/timer.rs +++ b/src/bare/arch/riscv64/timer.rs @@ -1,4 +1,4 @@ -use crate::currrent_arch::boards::CLOCK_FREQ; +use crate::CLOCK_FREQ; use crate::time::Time; use riscv::register::{sie, time}; diff --git a/src/x86_64/apic.rs b/src/bare/arch/x86_64/apic.rs similarity index 79% rename from src/x86_64/apic.rs rename to src/bare/arch/x86_64/apic.rs index 04cb4a4..f228d36 100644 --- a/src/x86_64/apic.rs +++ b/src/bare/arch/x86_64/apic.rs @@ -5,9 +5,10 @@ use spin::Once; use x2apic::ioapic::IoApic; use x2apic::lapic::{xapic_base, LocalApic, LocalApicBuilder}; use x86_64::instructions::port::Port; +use crate::irq::IRQ; use self::vectors::*; -use crate::VIRT_ADDR_START; +use crate::imp::current_arch::VIRT_ADDR_START; pub(super) mod vectors { pub const APIC_TIMER_VECTOR: u8 = 0xf0; @@ -27,20 +28,6 @@ static mut LOCAL_APIC: Option = None; static mut IS_X2APIC: bool = false; static IO_APIC: Once> = Once::new(); -/// Enables or disables the given IRQ. -pub fn set_enable(vector: usize, enabled: bool) { - // should not affect LAPIC interrupts - if vector < APIC_TIMER_VECTOR as _ { - unsafe { - if enabled { - IO_APIC.get_unchecked().lock().enable_irq(vector as u8); - } else { - IO_APIC.get_unchecked().lock().disable_irq(vector as u8); - } - } - } -} - /// Registers an IRQ handler for the given IRQ. /// /// It also enables the IRQ if the registration succeeds. It returns `false` if @@ -112,3 +99,28 @@ pub(super) fn init() { let io_apic = unsafe { IoApic::new(IO_APIC_BASE) }; IO_APIC.call_once(|| MutexIrqSafe::new(io_apic)); } + +/// Implement IRQ operations for the IRQ interface. +impl IRQ { + /// Enable irq for the given IRQ number. + #[inline] + pub fn enable(irq_num: usize) { + // should not affect LAPIC interrupts + if irq_num < APIC_TIMER_VECTOR as _ { + unsafe { + IO_APIC.get_unchecked().lock().enable_irq(irq_num as _); + } + } + } + + /// Disable irq for the given IRQ number. + #[inline] + pub fn disable(irq_num: usize) { + // should not affect LAPIC interrupts + if irq_num < APIC_TIMER_VECTOR as _ { + unsafe { + IO_APIC.get_unchecked().lock().disable_irq(irq_num as _); + } + } + } +} \ No newline at end of file diff --git a/src/riscv64/barrier.rs b/src/bare/arch/x86_64/barrier.rs similarity index 100% rename from src/riscv64/barrier.rs rename to src/bare/arch/x86_64/barrier.rs diff --git a/src/x86_64/consts.rs b/src/bare/arch/x86_64/consts.rs similarity index 100% rename from src/x86_64/consts.rs rename to src/bare/arch/x86_64/consts.rs diff --git a/src/x86_64/context.rs b/src/bare/arch/x86_64/context.rs similarity index 98% rename from src/x86_64/context.rs rename to src/bare/arch/x86_64/context.rs index 050f39f..cc4fd1a 100644 --- a/src/x86_64/context.rs +++ b/src/bare/arch/x86_64/context.rs @@ -122,8 +122,9 @@ impl TrapFrame { // self.sepc += 4; } + /// Check if the trapframe was from user. #[inline] - pub fn is_user(&self) -> bool { + pub fn from_user(&self) -> bool { self.cs == GdtStruct::UCODE64_SELECTOR.0 as _ } } diff --git a/src/x86_64/gdt.rs b/src/bare/arch/x86_64/gdt.rs similarity index 100% rename from src/x86_64/gdt.rs rename to src/bare/arch/x86_64/gdt.rs diff --git a/src/x86_64/idt.rs b/src/bare/arch/x86_64/idt.rs similarity index 100% rename from src/x86_64/idt.rs rename to src/bare/arch/x86_64/idt.rs diff --git a/src/x86_64/interrupt.rs b/src/bare/arch/x86_64/interrupt.rs similarity index 95% rename from src/x86_64/interrupt.rs rename to src/bare/arch/x86_64/interrupt.rs index 74dd4f7..e9a0a61 100644 --- a/src/x86_64/interrupt.rs +++ b/src/bare/arch/x86_64/interrupt.rs @@ -8,10 +8,11 @@ use x86_64::VirtAddr; use x86::{controlregs::cr2, irq::*}; -use crate::consts::TRAPFRAME_SIZE; -use crate::currrent_arch::gdt::set_tss_kernel_sp; -use crate::SYSCALL_VECTOR; -use crate::{currrent_arch::gdt::GdtStruct, TrapFrame, TrapType}; +use crate::imp::current_arch::gdt::set_tss_kernel_sp; +use crate::imp::current_arch::gdt::GdtStruct; +use crate::imp::current_arch::SYSCALL_VECTOR; +use crate::TRAPFRAME_SIZE; +use crate::{imp::current_arch::TrapFrame, TrapType}; use super::apic::vectors::APIC_TIMER_VECTOR; use super::context::FxsaveArea; @@ -98,7 +99,10 @@ fn kernel_callback(context: &mut TrapFrame) { context ); } - APIC_TIMER_VECTOR => TrapType::Time, + APIC_TIMER_VECTOR => { + unsafe { super::apic::local_apic().end_of_interrupt() }; + TrapType::Time + } // IRQ_VECTOR_START..=IRQ_VECTOR_END => crate::trap::handle_irq_extern(tf.vector as _), _ => { panic!( @@ -107,8 +111,7 @@ fn kernel_callback(context: &mut TrapFrame) { ); } }; - unsafe { crate::api::_interrupt_for_arch(context, trap_type) }; - unsafe { super::apic::local_apic().end_of_interrupt() }; + unsafe { crate::_interrupt_for_arch(context, trap_type) }; } #[naked] @@ -389,7 +392,7 @@ pub fn run_user_task(context: &mut TrapFrame) -> Option<()> { match context.vector { SYSCALL_VECTOR => { - unsafe { crate::api::_interrupt_for_arch(context, TrapType::UserEnvCall) }; + unsafe { crate::_interrupt_for_arch(context, TrapType::UserEnvCall) }; Some(()) } _ => { diff --git a/src/bare/arch/x86_64/irq.rs b/src/bare/arch/x86_64/irq.rs new file mode 100644 index 0000000..16b8d58 --- /dev/null +++ b/src/bare/arch/x86_64/irq.rs @@ -0,0 +1,49 @@ +use crate::irq::{IRQVector, IRQ}; + +/// Implement IRQ operations for the IRQ interface. +impl IRQ { + /// Enable irq for the given IRQ number. + #[inline] + pub fn irq_enable(_irq_num: usize) { + log::warn!("irq not implemented in riscv platform yet"); + } + + /// Disable irq for the given IRQ number. + #[inline] + pub fn irq_disable(_irq_num: usize) { + log::warn!("irq not implemented in riscv platform yet"); + } + + /// Enable interrupts. + #[inline] + pub fn int_enable() { + x86_64::instructions::interrupts::enable(); + } + + /// Disable interrupts. + #[inline] + pub fn int_disable() { + x86_64::instructions::interrupts::disable(); + } + + /// Check if the interrupts was enabled. + #[inline] + pub fn int_enabled() -> bool { + x86_64::instructions::interrupts::are_enabled() + } +} + +/// Implmente the irq vector methods +impl IRQVector { + /// Get the irq number in this vector + #[inline] + pub fn irq_num(&self) -> usize { + log::warn!("ack not implemented in x86_64 platform yet"); + self.0 + } + + /// Acknowledge the irq + pub fn ack(&self) { + log::warn!("ack not implemented in x86_64 platform yet"); + } +} diff --git a/src/x86_64/kcontext.rs b/src/bare/arch/x86_64/kcontext.rs similarity index 81% rename from src/x86_64/kcontext.rs rename to src/bare/arch/x86_64/kcontext.rs index c3f0afc..3121a38 100644 --- a/src/x86_64/kcontext.rs +++ b/src/bare/arch/x86_64/kcontext.rs @@ -107,11 +107,36 @@ pub unsafe extern "C" fn context_switch(from: *mut KContext, to: *const KContext core::arch::asm!( // Save Kernel Context. " - + pop r8 + mov [rdi + 0 * 8], rsp + mov [rdi + 2 * 8], rbx + mov [rdi + 3 * 8], rbp + mov [rdi + 4 * 8], r12 + mov [rdi + 5 * 8], r13 + mov [rdi + 6 * 8], r14 + mov [rdi + 7 * 8], r15 + mov [rdi + 8 * 8], r8 # save old rip to stack + + mov ecx, 0xC0000100 + rdmsr + mov [rdi + 1*8], eax # push fabase + mov [rdi + 1*8+4], edx ", // Restore Kernel Context. " - + mov ecx, 0xC0000100 + mov eax, [rsi + 1*8] + mov edx, [rsi + 1*8+4] + wrmsr # pop fsbase + mov rsp, [rsi + 0 * 8] + mov rbx, [rsi + 2 * 8] + mov rbp, [rsi + 3 * 8] + mov r12, [rsi + 4 * 8] + mov r13, [rsi + 5 * 8] + mov r14, [rsi + 6 * 8] + mov r15, [rsi + 7 * 8] + mov r8, [rsi + 8 * 8] + push r8 ret ", options(noreturn) diff --git a/src/x86_64/mod.rs b/src/bare/arch/x86_64/mod.rs similarity index 64% rename from src/x86_64/mod.rs rename to src/bare/arch/x86_64/mod.rs index 5350177..b4ee204 100644 --- a/src/x86_64/mod.rs +++ b/src/bare/arch/x86_64/mod.rs @@ -5,6 +5,7 @@ mod context; mod gdt; mod idt; mod interrupt; +mod irq; #[cfg(feature = "kcontext")] mod kcontext; mod multiboot; @@ -17,12 +18,12 @@ use ::multiboot::information::MemoryType; use alloc::vec::Vec; pub use consts::*; pub use context::TrapFrame; +use core::cmp; pub use interrupt::*; #[cfg(feature = "kcontext")] pub use kcontext::{context_switch, context_switch_pt, read_current_tp, KContext}; pub use multiboot::kernel_page_table; use raw_cpuid::CpuId; -pub use uart::*; use x86_64::{ instructions::port::PortWriteOnly, @@ -32,10 +33,10 @@ use x86_64::{ }, }; -use crate::{ - currrent_arch::multiboot::use_multiboot, multicore::MultiCore, once::LazyInit, CPU_NUM, - DTB_BIN, MEM_AREA, -}; +use crate::debug::{display_info, println}; +use crate::imp::{current_arch::multiboot::use_multiboot, CPU_NUM, DTB_BIN, MEM_AREA}; +use crate::utils::once::LazyInit; +use crate::MultiCore; #[percpu::def_percpu] static CPU_ID: usize = 1; @@ -66,6 +67,12 @@ fn rust_tmp_main(magic: usize, mboot_ptr: usize) { CpuId::new().get_feature_info().map(|features| { info!("is there a avx feature: {}", features.has_avx()); info!("is there a xsave feature: {}", features.has_xsave()); + // Add OSXSave flag to cr4 register if supported + if features.has_xsave() { + unsafe { + Cr4::write(Cr4::read() | Cr4Flags::OSXSAVE); + } + } info!("cr4 has OSXSAVE feature: {:?}", Cr4::read()); if features.has_avx() && features.has_xsave() && Cr4::read().contains(Cr4Flags::OSXSAVE) { unsafe { @@ -77,23 +84,48 @@ fn rust_tmp_main(magic: usize, mboot_ptr: usize) { // TODO: This is will be fixed with ACPI support CPU_NUM.init_by(1); - info!( - "TEST CPU ID: {} ptr: {:#x}", - CPU_ID.read_current(), - unsafe { CPU_ID.current_ptr() } as usize - ); - CPU_ID.write_current(345); - info!( - "TEST CPU ID: {} ptr: {:#x}", - CPU_ID.read_current(), - unsafe { CPU_ID.current_ptr() } as usize - ); - info!("magic: {:#x}, mboot_ptr: {:#x}", magic, mboot_ptr); MBOOT_PTR.init_by(mboot_ptr); - unsafe { crate::api::_main_for_arch(0) }; + display_info!(); + println!(include_str!("../../../common/banner.txt")); + display_info!("Platform Arch", "x86_64"); + if let Some(features) = CpuId::new().get_feature_info() { + display_info!( + "Platform Hart Count", + "{}", + cmp::max(1, features.max_logical_processor_ids()) + ); + display_info!("Platform FPU Support", "{}", features.has_fpu()); + } + display_info!("Platform Virt Mem Offset", "{:#x}", VIRT_ADDR_START); + if let Some(mboot) = use_multiboot(mboot_ptr as _) { + mboot + .command_line() + .inspect(|cl| display_info!("Platform Command Line", "{}", cl)); + if let Some(mr) = mboot.memory_regions() { + mr.for_each(|mm| { + display_info!( + "Platform Memory Region", + "{:#018x} - {:#018x} {:?}", + mm.base_address(), + mm.base_address() + mm.length(), + mm.memory_type() + ) + }); + } + display_info!(); + display_info!( + "Boot Image Highest Addr", + "{:#018x}", + mboot.find_highest_address() + ); + } + display_info!("Boot HART ID", "{}", CPU_ID.read_current()); + display_info!(); + + unsafe { crate::_main_for_arch(0) }; shutdown() } @@ -101,12 +133,6 @@ fn rust_tmp_main(magic: usize, mboot_ptr: usize) { pub fn arch_init() { DTB_BIN.init_by(Vec::new()); if let Some(mboot) = use_multiboot(*MBOOT_PTR as _) { - mboot - .boot_loader_name() - .inspect(|x| info!("bootloader: {}", x)); - mboot - .command_line() - .inspect(|x| info!("command_line: {}", x)); let mut mem_area = Vec::new(); if mboot.has_memory_map() { mboot diff --git a/src/x86_64/multiboot.S b/src/bare/arch/x86_64/multiboot.S similarity index 100% rename from src/x86_64/multiboot.S rename to src/bare/arch/x86_64/multiboot.S diff --git a/src/x86_64/multiboot.rs b/src/bare/arch/x86_64/multiboot.rs similarity index 77% rename from src/x86_64/multiboot.rs rename to src/bare/arch/x86_64/multiboot.rs index 2f3bd8e..edb548a 100644 --- a/src/x86_64/multiboot.rs +++ b/src/bare/arch/x86_64/multiboot.rs @@ -1,5 +1,5 @@ -use crate::currrent_arch::rust_tmp_main; -use crate::pagetable::PageTable; +use crate::imp::current_arch::rust_tmp_main; +use crate::PageTable; use crate::{BOOT_STACK, STACK_SIZE}; use core::arch::global_asm; use core::{mem, slice}; @@ -7,7 +7,7 @@ use multiboot::information::{MemoryManagement, Multiboot, PAddr}; use x86_64::registers::control::{Cr0Flags, Cr4Flags}; use x86_64::registers::model_specific::EferFlags; -use crate::VIRT_ADDR_START; +use crate::imp::current_arch::VIRT_ADDR_START; /// Flags set in the 'flags' member of the multiboot header. /// @@ -17,17 +17,27 @@ const MULTIBOOT_HEADER_FLAGS: usize = 0x0001_0002; /// The magic field should contain this. const MULTIBOOT_HEADER_MAGIC: usize = 0x1BADB002; +/// CR0 Registers introduction: https://wiki.osdev.org/CPU_Registers_x86-64#CR0 const CR0: u64 = Cr0Flags::PROTECTED_MODE_ENABLE.bits() | Cr0Flags::MONITOR_COPROCESSOR.bits() | Cr0Flags::NUMERIC_ERROR.bits() | Cr0Flags::WRITE_PROTECT.bits() | Cr0Flags::PAGING.bits(); +/// CR4 registers introduction: https://wiki.osdev.org/CPU_Registers_x86-64#CR4 +/// Physical Address Extension const CR4: u64 = Cr4Flags::PHYSICAL_ADDRESS_EXTENSION.bits() + // Page Global Enable | Cr4Flags::PAGE_GLOBAL.bits() + // OS support for fxsave and fxrstor instructions | Cr4Flags::OSFXSR.bits() - | Cr4Flags::OSXSAVE.bits() + // XSAVE And Processor Extended States Enable + // This bit should open if the processor was supported. + // | Cr4Flags::OSXSAVE.bits() + // OS Support for unmasked simd floating point exceptions | Cr4Flags::OSXMMEXCPT_ENABLE.bits(); + +/// EFER registers introduction: https://wiki.osdev.org/CPU_Registers_x86-64#IA32_EFER const EFER: u64 = EferFlags::LONG_MODE_ENABLE.bits() | EferFlags::NO_EXECUTE_ENABLE.bits(); static mut MEM: Mem = Mem; diff --git a/src/x86_64/page_table.rs b/src/bare/arch/x86_64/page_table.rs similarity index 97% rename from src/x86_64/page_table.rs rename to src/bare/arch/x86_64/page_table.rs index 340ab48..4f1f825 100644 --- a/src/x86_64/page_table.rs +++ b/src/bare/arch/x86_64/page_table.rs @@ -4,10 +4,10 @@ use x86::tlb; use x86_64::registers::control::Cr3; use crate::addr::{PhysAddr, PhysPage, VirtAddr, VirtPage}; -use crate::{ - pagetable::{MappingFlags, PageTable, PTE, TLB}, - VIRT_ADDR_START, -}; +use crate::imp::current_arch::VIRT_ADDR_START; +use crate::{MappingFlags, PageTable, PTE, TLB}; +use crate::bit; + bitflags! { pub struct PTEFlags: u64 { diff --git a/src/x86_64/sigtrx.rs b/src/bare/arch/x86_64/sigtrx.rs similarity index 95% rename from src/x86_64/sigtrx.rs rename to src/bare/arch/x86_64/sigtrx.rs index 2a432b3..77d82fd 100644 --- a/src/x86_64/sigtrx.rs +++ b/src/bare/arch/x86_64/sigtrx.rs @@ -1,6 +1,6 @@ use x86::bits64::paging::{PDEntry, PDFlags, PTEntry, PTFlags, PAGE_SIZE_ENTRIES, PD, PT}; -use crate::VIRT_ADDR_START; +use crate::imp::current_arch::VIRT_ADDR_START; /// 汇编入口函数 /// diff --git a/src/bare/arch/x86_64/time.rs b/src/bare/arch/x86_64/time.rs new file mode 100644 index 0000000..efe9892 --- /dev/null +++ b/src/bare/arch/x86_64/time.rs @@ -0,0 +1,110 @@ +use raw_cpuid::CpuId; +use x86_64::structures::port::{self, PortRead}; +use crate::time::Time; + +static mut CPU_FREQ_MHZ: usize = 4000_000_000; + +impl Time { + #[inline] + pub fn get_freq() -> usize { + unsafe { CPU_FREQ_MHZ } + } + + #[inline] + pub fn now() -> Self { + Self(unsafe { core::arch::x86_64::_rdtsc() as _ }) + } +} + +pub(super) fn init_early() { + info!("freq1: {:#x?}", CpuId::new().get_tsc_info()); + debug!("cpuid: {:#x?}", CpuId::new().get_vendor_info()); + if let Some(freq) = CpuId::new() + .get_processor_frequency_info() + .map(|info| info.processor_base_frequency()) + { + debug!("freq: {}", freq); + if freq > 0 { + info!("Got TSC frequency by CPUID: {} MHz", freq); + unsafe { CPU_FREQ_MHZ = freq as _ } + } + } + + unsafe { + use x2apic::lapic::{TimerDivide, TimerMode}; + let lapic = super::apic::local_apic(); + lapic.set_timer_mode(TimerMode::Periodic); + lapic.set_timer_divide(TimerDivide::Div2); // indeed it is Div1, the name is confusing. + lapic.enable_timer(); + + // PIT(Programmable Interval Timer) + // https://wiki.osdev.org/Pit + // Bits Usage + // 6 and 7 Select channel : + // 0 0 = Channel 0 + // 0 1 = Channel 1 + // 1 0 = Channel 2 + // 1 1 = Read-back command (8254 only) + // 4 and 5 Access mode : + // 0 0 = Latch count value command + // 0 1 = Access mode: lobyte only + // 1 0 = Access mode: hibyte only + // 1 1 = Access mode: lobyte/hibyte + // 1 to 3 Operating mode : + // 0 0 0 = Mode 0 (interrupt on terminal count) + // 0 0 1 = Mode 1 (hardware re-triggerable one-shot) + // 0 1 0 = Mode 2 (rate generator) + // 0 1 1 = Mode 3 (square wave generator) + // 1 0 0 = Mode 4 (software triggered strobe) + // 1 0 1 = Mode 5 (hardware triggered strobe) + // 1 1 0 = Mode 2 (rate generator, same as 010b) + // 1 1 1 = Mode 3 (square wave generator, same as 011b) + // 0 BCD/Binary mode: 0 = 16-bit binary, 1 = four-digit BCD + // open PIT2 + let pcspeaker = u8::read_from_port(0x61); + u8::write_to_port(0x61, pcspeaker | 1); + + const PIT_FREQ: u16 = 11931; + use port::PortWrite; + // Set PIT2 one-shott mode + u8::write_to_port(0x43, 0b10110010); + + // Write frequency to port + u16::write_to_port(0x42, PIT_FREQ & 0xff); + u16::write_to_port(0x42, (PIT_FREQ >> 8) & 0xff); + + // Reset PIT2 counter + let pcspeaker = u8::read_from_port(0x61); + u8::write_to_port(0x61, pcspeaker & 0xfd); + u8::write_to_port(0x61, pcspeaker | 1); + + // Reset loapic counter + lapic.set_timer_initial(0xFFFF_FFFF); + + // Read count + loop { + let mut count = u16::read_from_port(0x42); + count |= u16::read_from_port(0x42) << 8; + if count == 0 || count >= 60000 { + break; + } + } + let end = lapic.timer_current(); + log::info!( + "end {:#x} start: {:#x}, interval: {:#x}", + end, + 0xFFFF_FFFFu32, + 0xFFFF_FFFF - end + ); + + let ticks10ms = 0xFFFF_FFFF - end; + // lapic.set_timer_initial(0x20_000); + // Set ticks 1s + log::info!("ticks 50us: {}", ticks10ms / 10 / 20); + // lapic.set_timer_initial(ticks10ms * 0x100); + // Set 500us ticks + lapic.set_timer_initial(ticks10ms / 20); + debug!("count: {}", lapic.timer_current()); + // set_oneshot_timer(2000); + } +} diff --git a/src/x86_64/trap.S b/src/bare/arch/x86_64/trap.S similarity index 100% rename from src/x86_64/trap.S rename to src/bare/arch/x86_64/trap.S diff --git a/src/x86_64/uart.rs b/src/bare/arch/x86_64/uart.rs similarity index 100% rename from src/x86_64/uart.rs rename to src/bare/arch/x86_64/uart.rs diff --git a/src/bare/consts.rs b/src/bare/consts.rs new file mode 100644 index 0000000..6ca9a59 --- /dev/null +++ b/src/bare/consts.rs @@ -0,0 +1,10 @@ +use core::mem::size_of; + +use crate::imp::current_arch::TrapFrame; + +/// Boot Stack Size. +/// TODO: reduce the boot stack size. Map stack in boot step. +pub const STACK_SIZE: usize = 0x8_0000; + +/// The size of the trap frame(diffent in each architecture.). +pub const TRAPFRAME_SIZE: usize = size_of::(); \ No newline at end of file diff --git a/src/instruction.rs b/src/bare/instruction.rs similarity index 100% rename from src/instruction.rs rename to src/bare/instruction.rs diff --git a/src/bare/irq.rs b/src/bare/irq.rs new file mode 100644 index 0000000..d78c7d0 --- /dev/null +++ b/src/bare/irq.rs @@ -0,0 +1,40 @@ +/// IRQ interface for exposing. +/// +/// TODO: Implement this interface. +/// +/// How to use this interface. +/// ```rust +/// // Init irq +/// IRQ::init(); +/// +/// [IRQ::irq_enable] +/// // Enable irq 3 +/// IRQ::irq_enable(3); +/// +/// [IRQ::irq_disable] +/// // Disable irq 3 +/// IRQ::irq_disable(3); +/// +/// [IRQ::irq_enabled] +/// // Check if irq is enabled +/// // Return true if the irq is enabled. +/// IRQ::irq_enabled(3); +/// +/// [IRQ::int_enable] +/// // Enable interrupt +/// IRQ::int_enable(); +/// +/// [IRQ::int_disable] +/// // Disable interrupt +/// IRQ::int_disable(); +/// +/// [IRQ::int_enabled] +/// // Check if interrupt is enabled +/// let enabled = IRQ::int_enabled(); +/// ``` +pub struct IRQ; + +impl IRQ {} + +#[derive(Debug, Clone, Copy)] +pub struct IRQVector(pub(crate) usize); \ No newline at end of file diff --git a/src/mem.rs b/src/bare/mem.rs similarity index 100% rename from src/mem.rs rename to src/bare/mem.rs diff --git a/src/bare/mod.rs b/src/bare/mod.rs new file mode 100644 index 0000000..9577128 --- /dev/null +++ b/src/bare/mod.rs @@ -0,0 +1,265 @@ +//! This is a crate to help you supporting multiple platforms. +//! +//! If you want to use this crate, you should implement the following trait in your code. +//! +//! ```rust +//! /// impl +//! pub struct PageAllocImpl; +//! +//! impl PageAlloc for PageAllocImpl { +//! fn alloc(&self) -> PhysPage { +//! frame_alloc() +//! } +//! +//! fn dealloc(&self, ppn: PhysPage) { +//! frame::frame_dealloc(ppn) +//! } +//! } +//! +//! /// kernel interrupt +//! #[polyhal::arch_interrupt] +//! fn kernel_interrupt(ctx: &mut TrapFrame, trap_type: TrapType) { +//! // println!("trap_type @ {:x?} {:#x?}", trap_type, ctx); +//! match trap_type { +//! Breakpoint => return, +//! UserEnvCall => { +//! // jump to next instruction anyway +//! ctx.syscall_ok(); +//! log::info!("Handle a syscall"); +//! } +//! StorePageFault(_paddr) | LoadPageFault(_paddr) | InstructionPageFault(_paddr) => { +//! log::info!("page fault"); +//! } +//! IllegalInstruction(_) => { +//! log::info!("illegal instruction"); +//! } +//! Time => { +//! log::info!("Timer"); +//! } +//! _ => { +//! log::warn!("unsuspended trap type: {:?}", trap_type); +//! } +//! } +//! } +//! +//! #[polyhal::arch_entry] +//! /// kernel main function, entry point. +//! fn main(hartid: usize) { +//! if hartid != 0 { +//! return; +//! } +//! +//! println!("[kernel] Hello, world!"); +//! allocator::init_allocator(); +//! logging::init(Some("trace")); +//! println!("init logging"); +//! +//! // Init page alloc for polyhal +//! polyhal::init(&PageAllocImpl); +//! +//! polyhal::init_interrupt(); +//! +//! get_mem_areas().into_iter().for_each(|(start, size)| { +//! println!("init memory region {:#x} - {:#x}", start, start + size); +//! frame::add_frame_range(start, start + size); +//! }); +//! panic!("end of rust_main!"); +//! } +//! +//! ``` +//! +//! The main(hardid: usize) is the entry point. +//! +//! You can find details in the example. +//! +//! In this crate you can find some interfaces to use. +//! These interfaces are classified into some structures. +//! +//! [PhysPage]: PhysicalPage And its associated functions. +//! +//! [PhysAddr](addr::PhysAddr): PhysicalAddr And its associated functions. +//! +//! [VirtPage](addr::VirtPage): VirtualPage And its associated functions. +//! +//! [VirtAddr](addr::VirtAddr): VirtualAddr And its associated functions. +//! +//! [IRQ](irq::IRQ): Interrupt ReQuest management, includes enable and disable. +//! +//! [Barrier](mem::Barrier): Memory barrier operations. +//! +//! [MultiCore](multicore::MultiCore): MultiCore operations. Now only [multicore::MultiCore::boot_all] is available. +//! +//! [PageTable]: PageTable and its associated functions. +//! +//! [MappingFlags](pagetable::MappingFlags): MappingFlags, This is an abstraction of pagetable flags. +//! +//! [TLB](pagetable::TLB): TLB operations. +//! +//! [PageTableWrapper](pagetable::PageTableWrapper): PageTableWrapper. It will dealloc all pagetable leaf when it was dropping. +//! +//! [Time](time::Time): Time and its associated functions. +//! +//! [Instruction](instruction::Instruction): Some platform instruction. +//! +//! There also provides a debugging console(recommanded only for debugging). +//! +//! [DebugConsole](debug::DebugConsole): A console for debugging. +//! +//! This crate provides a [TrapFrame], you can operate it through index with [TrapFrameArgs]. +//! +//! If you are using kernel task. You should to enable feature `kcontext`. +//! Then you can use kernel task context structure [KContext], and manipulate it with [KContextArgs]. +//! +//! You can switch kcontext through [context_switch_pt] or [context_switch] +//! +//! There are also some consts. +//! +//! [VIRT_ADDR_START]: This is a higher half kernel offset address. +//! [USER_VADDR_END]: End of the user address range. +//! [PAGE_SIZE]: The size of the page. +//! +//! You can get some device information using the functions below. +//! [get_mem_areas]: Get the avaliable memorys. +//! [get_fdt]: Get the Fdt structure(fdt is a rust dtb operation crate). +//! [get_cpu_num]: Get the number of cpus. +//! +//! TIPS: You should have finished [init] before using [get_mem_areas] and [get_fdt]. + +cfg_if! { + if #[cfg(target_arch = "x86_64")] { + #[path = "arch/x86_64/mod.rs"] + pub mod current_arch; + } else if #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] { + #[path = "arch/riscv64/mod.rs"] + pub mod current_arch; + } else if #[cfg(target_arch = "aarch64")] { + #[path = "arch/aarch64/mod.rs"] + pub mod current_arch; + } else if #[cfg(target_arch = "loongarch64")] { + #[path = "arch/loongarch64/mod.rs"] + pub mod current_arch; + } else { + compile_error!("Unsupported target_arch"); + } +} + +mod addr; +pub mod api; +pub mod consts; +pub mod instruction; +pub mod irq; +pub mod mem; +pub mod multicore; +pub mod pagetable; +pub mod time; + +use crate::irq::IRQVector; +use crate::utils::once::LazyInit; +use alloc::vec::Vec; +use cfg_if::cfg_if; +use core::mem::size_of; +use fdt::Fdt; +pub use mem::Barrier; + +use crate::common::page::PageAlloc; +/// Trap Frame +use crate::STACK_SIZE; + +pub const PAGE_SIZE: usize = crate::PageTable::PAGE_SIZE; +pub const USER_VADDR_END: usize = crate::PageTable::USER_VADDR_END; + +/// Kernel Context Arg Type. +/// +/// Using this by Index and IndexMut trait bound on KContext. +#[derive(Debug)] +#[cfg(feature = "kcontext")] +pub enum KContextArgs { + /// Kernel Stack Pointer + KSP, + /// Kernel Thread Pointer + KTP, + /// Kernel Program Counter + KPC, +} + +/// Trap Frame Arg Type +/// +/// Using this by Index and IndexMut trait bound on TrapFrame +#[derive(Debug)] +pub enum TrapFrameArgs { + SEPC, + RA, + SP, + RET, + ARG0, + ARG1, + ARG2, + TLS, + SYSCALL, +} + +#[derive(Debug, Clone, Copy)] +pub enum TrapType { + Breakpoint, + UserEnvCall, + Time, + Unknown, + SupervisorExternal, + StorePageFault(usize), + LoadPageFault(usize), + InstructionPageFault(usize), + IllegalInstruction(usize), + Irq(IRQVector), +} + +#[link_section = ".bss.stack"] +pub static mut BOOT_STACK: [u8; STACK_SIZE] = [0; STACK_SIZE]; + +pub(crate) fn clear_bss() { + extern "C" { + fn _sbss(); + fn _ebss(); + } + unsafe { + core::slice::from_raw_parts_mut( + _sbss as usize as *mut u128, + (_ebss as usize - _sbss as usize) / size_of::(), + ) + .fill(0); + } +} + +pub(crate) static PAGE_ALLOC: LazyInit<&dyn PageAlloc> = LazyInit::new(); + +/// Init arch with page allocator, like log crate +/// Please initialize the allocator before calling this function. +pub fn init(page_alloc: &'static dyn PageAlloc) { + PAGE_ALLOC.init_by(page_alloc); + + // Init current architecture + current_arch::arch_init(); +} + +/// Store the number of cpu, this will fill up by startup function. +pub(crate) static CPU_NUM: LazyInit = LazyInit::new(); + +/// Store the memory area, this will fill up by the arch_init() function in each architecture. +pub(crate) static MEM_AREA: LazyInit> = LazyInit::new(); + +/// Store the DTB_area, this will fill up by the arch_init() function in each architecture +static DTB_BIN: LazyInit> = LazyInit::new(); + +/// Get the memory area, this function should be called after initialization +pub fn get_mem_areas() -> Vec<(usize, usize)> { + MEM_AREA.clone() +} + +/// Get the fdt +pub fn get_fdt() -> Option> { + Fdt::new(&DTB_BIN).ok() +} + +/// Get the number of cpus +pub fn get_cpu_num() -> usize { + *CPU_NUM +} diff --git a/src/multicore.rs b/src/bare/multicore.rs similarity index 100% rename from src/multicore.rs rename to src/bare/multicore.rs diff --git a/src/pagetable.rs b/src/bare/pagetable.rs similarity index 98% rename from src/pagetable.rs rename to src/bare/pagetable.rs index 1170b53..73a0485 100644 --- a/src/pagetable.rs +++ b/src/bare/pagetable.rs @@ -1,9 +1,11 @@ use core::ops::Deref; -use crate::addr::{PhysAddr, PhysPage, VirtAddr, VirtPage}; -use crate::api::{frame_alloc, frame_dealloc}; +use crate::common::addr::{VirtAddr, VirtPage, PhysAddr, PhysPage}; +use crate::{frame_alloc, frame_dealloc}; +use bitflags::bitflags; +use crate::bit; -bitflags::bitflags! { +bitflags! { /// Mapping flags for page table. #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct MappingFlags: u64 { diff --git a/src/time.rs b/src/bare/time.rs similarity index 100% rename from src/time.rs rename to src/bare/time.rs diff --git a/src/addr.rs b/src/common/addr.rs similarity index 70% rename from src/addr.rs rename to src/common/addr.rs index fffe527..45075ab 100644 --- a/src/addr.rs +++ b/src/common/addr.rs @@ -1,12 +1,9 @@ use core::{ ffi::CStr, fmt::{Debug, Display}, - mem::size_of, ops::Add, }; -use crate::{pagetable::PageTable, VIRT_ADDR_START}; - #[repr(C)] #[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq)] pub struct PhysAddr(pub(crate) usize); @@ -21,31 +18,6 @@ impl PhysAddr { pub fn addr(&self) -> usize { self.0 } - - #[inline] - pub fn get_ptr(&self) -> *const T { - (self.0 | VIRT_ADDR_START) as *const T - } - - #[inline] - pub const fn get_mut_ptr(&self) -> *mut T { - (self.0 | VIRT_ADDR_START) as *mut T - } - - #[inline] - pub fn slice_with_len(&self, len: usize) -> &'static [T] { - unsafe { core::slice::from_raw_parts(self.get_ptr(), len) } - } - - #[inline] - pub fn slice_mut_with_len(&self, len: usize) -> &'static mut [T] { - unsafe { core::slice::from_raw_parts_mut(self.get_mut_ptr(), len) } - } - - #[inline] - pub fn get_cstr(&self) -> &CStr { - unsafe { CStr::from_ptr(self.get_ptr::()) } - } } #[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq)] @@ -120,16 +92,6 @@ impl VirtAddr { pub fn get_cstr(&self) -> &CStr { unsafe { CStr::from_ptr(self.get_ptr::()) } } - - #[inline] - pub fn floor(&self) -> Self { - Self(self.0 / PageTable::PAGE_SIZE * PageTable::PAGE_SIZE) - } - - #[inline] - pub fn ceil(&self) -> Self { - Self((self.0 + PageTable::PAGE_SIZE - 1) / PageTable::PAGE_SIZE * PageTable::PAGE_SIZE) - } } #[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq)] @@ -198,51 +160,6 @@ impl PhysPage { self.0 << 12 } - #[inline] - pub const fn get_buffer(&self) -> &'static mut [u8] { - unsafe { - core::slice::from_raw_parts_mut( - (self.0 << 12 | VIRT_ADDR_START) as *mut u8, - PageTable::PAGE_SIZE, - ) - } - } - - #[inline] - pub fn copy_value_from_another(&self, ppn: PhysPage) { - self.get_buffer().copy_from_slice(&ppn.get_buffer()); - #[cfg(c906)] - unsafe { - asm!(".long 0x0010000b"); // dcache.all - asm!(".long 0x01b0000b"); // sync.is - } - #[cfg(board = "2k1000")] - unsafe { - core::arch::asm!("dbar 0;ibar 0;") - } - } - - #[inline] - pub fn drop_clear(&self) { - // self.get_buffer().fill(0); - unsafe { - core::slice::from_raw_parts_mut( - (self.0 << 12 | VIRT_ADDR_START) as *mut usize, - PageTable::PAGE_SIZE / size_of::(), - ) - .fill(0); - } - #[cfg(board = "2k1000")] - unsafe { - core::arch::asm!("dbar 0;ibar 0;") - } - #[cfg(c906)] - unsafe { - asm!(".long 0x0010000b"); // dcache.all - asm!(".long 0x01b0000b"); // sync.is - } - } - #[inline] pub fn as_num(&self) -> usize { self.0 diff --git a/src/common/banner.txt b/src/common/banner.txt new file mode 100644 index 0000000..4f05405 --- /dev/null +++ b/src/common/banner.txt @@ -0,0 +1,8 @@ + _____ _ _ _ _ + | __ \ | | | | | | /\ | | + | |__) |__ | |_ _| |__| | / \ | | + | ___/ _ \| | | | | __ | / /\ \ | | + | | | (_) | | |_| | | | |/ ____ \| |____ + |_| \___/|_|\__, |_| |_/_/ \_\______| + __/ | + |___/ \ No newline at end of file diff --git a/src/common/debug.rs b/src/common/debug.rs new file mode 100644 index 0000000..24c97e2 --- /dev/null +++ b/src/common/debug.rs @@ -0,0 +1,54 @@ +use core::fmt::Write; + +/// This is a console for debugging, +/// If you want to use this logging +/// You need to use like this: +/// +/// #### Put a char to output device(always uart) +/// ```rust +/// DebugConsole::putchar(b'3'); +/// ``` +/// +/// ### Get a char from input device(always uart) +/// ```rust +/// DebugConsole::getchar(); +/// ``` +/// +/// Print macro to print polyhal information with newline +pub(crate) macro println { + () => { + $crate::debug::print(format_args!("\n")) + }, + ($fmt: expr $(, $($arg: tt)+)?) => { + $crate::debug::print(format_args!(concat!($fmt, "\n") $(, $($arg)+)?)) + }, +} + +/// Display Platform Information with specified format +/// display_info!("item name", "{}", "format"); +/// The output format like below: +/// item name : format +pub(crate) macro display_info{ + () => { + $crate::debug::print(format_args!("\n")) + }, + ($item:literal,$fmt: expr $(, $($arg: tt)+)?) => { + $crate::debug::print(format_args!(concat!("{:<26}: ", $fmt, "\n"),$item $(, $($arg)+)?)) + } +} + +/// Print the given arguments +#[inline] +pub(crate) fn print(args: core::fmt::Arguments) { + DebugConsole.write_fmt(args).expect("can't print arguments"); +} + +pub struct DebugConsole; + +// Write string through DebugConsole +impl Write for DebugConsole { + fn write_str(&mut self, s: &str) -> core::fmt::Result { + s.as_bytes().into_iter().for_each(|x| Self::putchar(*x)); + Ok(()) + } +} diff --git a/src/common/mod.rs b/src/common/mod.rs new file mode 100644 index 0000000..1286eac --- /dev/null +++ b/src/common/mod.rs @@ -0,0 +1,3 @@ +pub mod addr; +pub mod page; +pub mod debug; \ No newline at end of file diff --git a/src/common/page.rs b/src/common/page.rs new file mode 100644 index 0000000..7a480d1 --- /dev/null +++ b/src/common/page.rs @@ -0,0 +1,6 @@ +use crate::common::addr::PhysPage; + +pub trait PageAlloc: Sync { + fn alloc(&self) -> PhysPage; + fn dealloc(&self, ppn: PhysPage); +} \ No newline at end of file diff --git a/src/consts.rs b/src/consts.rs deleted file mode 100644 index 9b6940e..0000000 --- a/src/consts.rs +++ /dev/null @@ -1,21 +0,0 @@ -use core::mem::size_of; - -use crate::TrapFrame; - -/// Boot Stack Size. -/// TODO: reduce the boot stack size. Map stack in boot step. -pub const STACK_SIZE: usize = 0x8_0000; - -/// The size of the trap frame(diffent in each architecture.). -pub const TRAPFRAME_SIZE: usize = size_of::(); - -/// bit macro will generate the number through a shift value. -/// -/// Here is an example. -/// You can use bit!(0) instead of 1 << 0. -/// bit!(39) instead of 1 << 39. -macro_rules! bit { - ($x:expr) => { - 1 << $x - }; -} diff --git a/src/debug.rs b/src/debug.rs deleted file mode 100644 index 94f4723..0000000 --- a/src/debug.rs +++ /dev/null @@ -1,24 +0,0 @@ -use core::fmt::Write; - -/// This is a console for debugging, -/// If you want to use this logging -/// You need to use like this: -/// -/// #### Put a char to output device(always uart) -/// ```rust -/// DebugConsole::putchar(b'3'); -/// ``` -/// -/// ### Get a char from input device(always uart) -/// ```rust -/// DebugConsole::getchar(); -/// ``` -pub struct DebugConsole; - -// Write string through DebugConsole -impl Write for DebugConsole { - fn write_str(&mut self, s: &str) -> core::fmt::Result { - s.as_bytes().into_iter().for_each(|x| Self::putchar(*x)); - Ok(()) - } -} diff --git a/src/irq.rs b/src/irq.rs deleted file mode 100644 index 4d9e0db..0000000 --- a/src/irq.rs +++ /dev/null @@ -1,23 +0,0 @@ -/// IRQ interface for exposing. -/// -/// TODO: Implement this interface. -/// -/// How to use this interface. -/// ```rust -/// // Init irq -/// IRQ::init(); -/// -/// // Enable irq 3 -/// IRQ::enable(3); -/// -/// // Disable irq 3 -/// IRQ::disable(3); -/// -/// // Check if irq is enabled -/// // Return true if the irq is enabled. -/// IRQ::enabled(3); -/// -/// ``` -pub struct IRQ; - -impl IRQ {} diff --git a/src/lib.rs b/src/lib.rs index bf6ab72..b2f388e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,5 @@ -#![no_std] +#![cfg_attr(not(feature = "libos"), no_std)] +#![feature(decl_macro)] #![no_main] #![feature(naked_functions)] #![feature(asm_const)] @@ -8,274 +9,55 @@ #![cfg_attr(target_arch = "riscv64", feature(riscv_ext_intrinsics))] #![cfg_attr(target_arch = "aarch64", feature(const_option))] -//! This is a crate to help you supporting multiple platforms. -//! -//! If you want to use this crate, you should implement the following trait in your code. -//! -//! ```rust -//! /// impl -//! pub struct PageAllocImpl; -//! -//! impl PageAlloc for PageAllocImpl { -//! fn alloc(&self) -> PhysPage { -//! frame_alloc() -//! } -//! -//! fn dealloc(&self, ppn: PhysPage) { -//! frame::frame_dealloc(ppn) -//! } -//! } -//! -//! /// kernel interrupt -//! #[polyhal::arch_interrupt] -//! fn kernel_interrupt(ctx: &mut TrapFrame, trap_type: TrapType) { -//! // println!("trap_type @ {:x?} {:#x?}", trap_type, ctx); -//! match trap_type { -//! Breakpoint => return, -//! UserEnvCall => { -//! // jump to next instruction anyway -//! ctx.syscall_ok(); -//! log::info!("Handle a syscall"); -//! } -//! StorePageFault(_paddr) | LoadPageFault(_paddr) | InstructionPageFault(_paddr) => { -//! log::info!("page fault"); -//! } -//! IllegalInstruction(_) => { -//! log::info!("illegal instruction"); -//! } -//! Time => { -//! log::info!("Timer"); -//! } -//! _ => { -//! log::warn!("unsuspended trap type: {:?}", trap_type); -//! } -//! } -//! } -//! -//! #[polyhal::arch_entry] -//! /// kernel main function, entry point. -//! fn main(hartid: usize) { -//! if hartid != 0 { -//! return; -//! } -//! -//! println!("[kernel] Hello, world!"); -//! allocator::init_allocator(); -//! logging::init(Some("trace")); -//! println!("init logging"); -//! -//! // Init page alloc for polyhal -//! polyhal::init(&PageAllocImpl); -//! -//! polyhal::init_interrupt(); -//! -//! get_mem_areas().into_iter().for_each(|(start, size)| { -//! println!("init memory region {:#x} - {:#x}", start, start + size); -//! frame::add_frame_range(start, start + size); -//! }); -//! panic!("end of rust_main!"); -//! } -//! -//! ``` -//! -//! The main(hardid: usize) is the entry point. -//! -//! You can find details in the example. -//! -//! In this crate you can find some interfaces to use. -//! These interfaces are classified into some structures. -//! -//! [PhysPage]: PhysicalPage And its associated functions. -//! -//! [PhysAddr](addr::PhysAddr): PhysicalAddr And its associated functions. -//! -//! [VirtPage](addr::VirtPage): VirtualPage And its associated functions. -//! -//! [VirtAddr](addr::VirtAddr): VirtualAddr And its associated functions. -//! -//! [IRQ](irq::IRQ): Interrupt ReQuest management, includes enable and disable. -//! -//! [Barrier](mem::Barrier): Memory barrier operations. -//! -//! [MultiCore](multicore::MultiCore): MultiCore operations. Now only [multicore::MultiCore::boot_all] is available. -//! -//! [PageTable]: PageTable and its associated functions. -//! -//! [MappingFlags](pagetable::MappingFlags): MappingFlags, This is an abstraction of pagetable flags. -//! -//! [TLB](pagetable::TLB): TLB operations. -//! -//! [PageTableWrapper](pagetable::PageTableWrapper): PageTableWrapper. It will dealloc all pagetable leaf when it was dropping. -//! -//! [Time](time::Time): Time and its associated functions. -//! -//! [Instruction](instruction::Instruction): Some platform instruction. -//! -//! There also provides a debugging console(recommanded only for debugging). -//! -//! [DebugConsole](debug::DebugConsole): A console for debugging. -//! -//! This crate provides a [TrapFrame], you can operate it through index with [TrapFrameArgs]. -//! -//! If you are using kernel task. You should to enable feature `kcontext`. -//! Then you can use kernel task context structure [KContext], and manipulate it with [KContextArgs]. -//! -//! You can switch kcontext through [context_switch_pt] or [context_switch] -//! -//! There are also some consts. -//! -//! [VIRT_ADDR_START]: This is a higher half kernel offset address. -//! [USER_VADDR_END]: End of the user address range. -//! [PAGE_SIZE]: The size of the page. -//! -//! You can get some device information using the functions below. -//! [get_mem_areas]: Get the avaliable memorys. -//! [get_fdt]: Get the Fdt structure(fdt is a rust dtb operation crate). -//! [get_cpu_num]: Get the number of cpus. -//! -//! TIPS: You should have finished [init] before using [get_mem_areas] and [get_fdt]. - extern crate alloc; #[macro_use] extern crate log; - -pub mod addr; -pub mod api; #[macro_use] -pub mod consts; -pub mod debug; -pub mod instruction; -pub mod irq; -pub mod mem; -#[cfg(feature = "multicore")] -pub mod multicore; -pub mod once; -pub mod pagetable; -pub mod time; -use core::mem::size_of; - -use addr::PhysPage; -use alloc::vec::Vec; - -use consts::STACK_SIZE; -use fdt::Fdt; -use once::LazyInit; -use pagetable::PageTable; -pub use percpu; - -#[cfg_attr(target_arch = "riscv64", path = "riscv64/mod.rs")] -#[cfg_attr(target_arch = "aarch64", path = "aarch64/mod.rs")] -#[cfg_attr(target_arch = "x86_64", path = "x86_64/mod.rs")] -#[cfg_attr(target_arch = "loongarch64", path = "loongarch64/mod.rs")] -mod currrent_arch; - -/// Trap Frame -pub use currrent_arch::TrapFrame; - -pub use currrent_arch::*; - -pub use polyhal_macro::{arch_entry, arch_interrupt}; - -pub const PAGE_SIZE: usize = PageTable::PAGE_SIZE; -pub const USER_VADDR_END: usize = PageTable::USER_VADDR_END; - -/// Kernel Context Arg Type. -/// -/// Using this by Index and IndexMut trait bound on KContext. -#[derive(Debug)] -#[cfg(feature = "kcontext")] -pub enum KContextArgs { - /// Kernel Stack Pointer - KSP, - /// Kernel Thread Pointer - KTP, - /// Kernel Program Counter - KPC, -} - -/// Trap Frame Arg Type -/// -/// Using this by Index and IndexMut trait bound on TrapFrame -#[derive(Debug)] -pub enum TrapFrameArgs { - SEPC, - RA, - SP, - RET, - ARG0, - ARG1, - ARG2, - TLS, - SYSCALL, -} - -#[derive(Debug, Clone, Copy)] -pub enum TrapType { - Breakpoint, - UserEnvCall, - Time, - Unknown, - SupervisorExternal, - StorePageFault(usize), - LoadPageFault(usize), - InstructionPageFault(usize), - IllegalInstruction(usize), -} - -#[link_section = ".bss.stack"] -static mut BOOT_STACK: [u8; STACK_SIZE] = [0; STACK_SIZE]; - -pub(crate) fn clear_bss() { - extern "C" { - fn _sbss(); - fn _ebss(); - } - unsafe { - core::slice::from_raw_parts_mut( - _sbss as usize as *mut u128, - (_ebss as usize - _sbss as usize) / size_of::(), - ) - .fill(0); +extern crate cfg_if; +#[macro_use] +mod utils; +#[macro_use] +mod common; +pub use common::{page::PageAlloc, *}; + +cfg_if! { + if #[cfg(feature = "libos")] { + #[path = "libos/mod.rs"] + mod imp; + + pub use polyhal_macro::{arch_entry, arch_interrupt}; + pub use imp::context::*; + pub use imp::addr::*; + pub use imp::init; + pub use imp::mem::get_mem_areas; + pub use imp::vm::{Page, PageTable}; + pub use imp::addr::MMUFlags; + pub use imp::mem::{pmem_read, pmem_copy, pmem_write, pmem_zero}; + pub use imp::shutdown; + } else { + #[path = "bare/mod.rs"] + mod imp; + use imp::api::*; + use imp::pagetable::*; + use imp::consts::*; + use imp::multicore::MultiCore; + use imp::current_arch::*; + use irq::IRQVector; + + pub use imp::{ + *, + get_mem_areas, init, + TrapFrameArgs, TrapType, PAGE_SIZE, + time::*, + current_arch::{ + run_user_task, shutdown, kernel_page_table, + TrapFrame, VIRT_ADDR_START, + }, + }; + pub use polyhal_macro::{arch_entry, arch_interrupt}; + + #[cfg(feature = "kcontext")] + pub use imp::{KContextArgs, current_arch::{KContext, read_current_tp, context_switch_pt, context_switch}}; } } - -pub trait PageAlloc: Sync { - fn alloc(&self) -> PhysPage; - fn dealloc(&self, ppn: PhysPage); -} - -static PAGE_ALLOC: LazyInit<&dyn PageAlloc> = LazyInit::new(); - -/// Init arch with page allocator, like log crate -/// Please initialize the allocator before calling this function. -pub fn init(page_alloc: &'static dyn PageAlloc) { - PAGE_ALLOC.init_by(page_alloc); - - // Init current architecture - currrent_arch::arch_init(); -} - -/// Store the number of cpu, this will fill up by startup function. -pub(crate) static CPU_NUM: LazyInit = LazyInit::new(); - -/// Store the memory area, this will fill up by the arch_init() function in each architecture. -pub(crate) static MEM_AREA: LazyInit> = LazyInit::new(); - -/// Store the DTB_area, this will fill up by the arch_init() function in each architecture -static DTB_BIN: LazyInit> = LazyInit::new(); - -/// Get the memory area, this function should be called after initialization -pub fn get_mem_areas() -> Vec<(usize, usize)> { - MEM_AREA.clone() -} - -/// Get the fdt -pub fn get_fdt() -> Option> { - Fdt::new(&DTB_BIN).ok() -} - -/// Get the number of cpus -pub fn get_cpu_num() -> usize { - *CPU_NUM -} diff --git a/src/libos/addr.rs b/src/libos/addr.rs new file mode 100644 index 0000000..e36b49f --- /dev/null +++ b/src/libos/addr.rs @@ -0,0 +1,57 @@ +use bitflags::bitflags; +use crate::addr::{PhysAddr, VirtAddr}; +use crate::bit; +use crate::common::addr::PhysPage; + +pub const PAGE_SIZE: usize = 0x1000; +pub const PAGE_BITS: usize = 12; + +impl PhysPage { + pub fn addr(&self) -> PhysAddr { + PhysAddr::new(self.0 << PAGE_BITS) + } +} + +impl VirtAddr { + pub fn add_offset(&mut self, s: usize) { + self.0 += s; + } +} + +impl PhysAddr { + pub fn add_offset(&mut self, s: usize) { + self.0 += s; + } +} + +pub const fn align_down(addr: usize) -> usize { + addr & !(PAGE_SIZE - 1) +} + +pub const fn align_up(addr: usize) -> usize { + (addr + PAGE_SIZE - 1) & !(PAGE_SIZE - 1) +} + +pub const fn is_aligned(addr: usize) -> bool { + page_offset(addr) == 0 +} + +pub const fn page_count(size: usize) -> usize { + align_up(size) / PAGE_SIZE +} + +pub const fn page_offset(addr: usize) -> usize { + addr & (PAGE_SIZE - 1) +} + +bitflags! { + /// Generic memory flags. + #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] + pub struct MMUFlags: u64 { + #[allow(clippy::identity_op)] + const READ = bit!(2); + const WRITE = bit!(3); + const EXECUTE = bit!(4); + const USER = bit!(5); + } +} \ No newline at end of file diff --git a/src/libos/context.rs b/src/libos/context.rs new file mode 100644 index 0000000..a0628aa --- /dev/null +++ b/src/libos/context.rs @@ -0,0 +1,3 @@ +pub struct TrapFrame {} + +pub enum TrapType {} \ No newline at end of file diff --git a/src/libos/debug.rs b/src/libos/debug.rs new file mode 100644 index 0000000..1317615 --- /dev/null +++ b/src/libos/debug.rs @@ -0,0 +1,7 @@ +use crate::debug::DebugConsole; + +impl DebugConsole { + pub fn putchar(c: u8) { + print!("{}", c as char); + } +} diff --git a/src/libos/mem.rs b/src/libos/mem.rs new file mode 100644 index 0000000..62ca6cf --- /dev/null +++ b/src/libos/mem.rs @@ -0,0 +1,51 @@ +//! Physical memory operations. + +use alloc::vec::Vec; +use core::ops::Range; +use crate::utils::once::LazyInit; + +use super::mock_mem::MockMemory; +use crate::{addr::{PhysAddr, VirtAddr}, PAGE_SIZE}; + +/// Map physical memory from here. +pub(super) const PMEM_MAP_VADDR: VirtAddr = VirtAddr::new(0x8_0000_0000); +/// Physical memory size = 1GiB +pub(super) const PMEM_SIZE: usize = 0x4000_0000; + +pub(super) static MOCK_PHYS_MEM: LazyInit = LazyInit::new(); + +pub fn init_mock_mem() { + MOCK_PHYS_MEM.init_by(MockMemory::new(PMEM_SIZE)); +} + +pub fn get_mem_areas() -> Vec> { + vec![PAGE_SIZE..PMEM_SIZE] +} + +pub fn pmem_read(paddr: PhysAddr, buf: &mut [u8]) { + trace!("pmem read: paddr={:#x}, len={:#x}", paddr.addr(), buf.len()); + assert!(paddr.addr() + buf.len() <= PMEM_SIZE); + let src = MOCK_PHYS_MEM.as_ptr(paddr); + unsafe { buf.as_mut_ptr().copy_from_nonoverlapping(src, buf.len()) }; +} + +pub fn pmem_write(paddr: PhysAddr, buf: &[u8]) { + trace!("pmem write: paddr={:#x}, len={:#x}", paddr.addr(), buf.len()); + assert!(paddr.addr() + buf.len() <= PMEM_SIZE); + let dst = MOCK_PHYS_MEM.as_mut_ptr::(paddr); + unsafe { dst.copy_from_nonoverlapping(buf.as_ptr(), buf.len()) }; +} + +pub fn pmem_zero(paddr: PhysAddr, len: usize) { + trace!("pmem_zero: addr={:#x}, len={:#x}", paddr.addr(), len); + assert!(paddr.addr() + len <= PMEM_SIZE); + unsafe { core::ptr::write_bytes(MOCK_PHYS_MEM.as_mut_ptr::(paddr), 0, len) }; +} + +pub fn pmem_copy(dst: PhysAddr, src: PhysAddr, len: usize) { + trace!("pmem_copy: {:#x} <- {:#x}, len={:#x}", dst.addr(), src.addr(), len); + assert!(src.addr() + len <= PMEM_SIZE && dst.addr() + len <= PMEM_SIZE); + let dst = MOCK_PHYS_MEM.as_mut_ptr::(dst); + let src = MOCK_PHYS_MEM.as_ptr::(src); + unsafe { dst.copy_from_nonoverlapping(src, len) }; +} \ No newline at end of file diff --git a/src/libos/mock_mem.rs b/src/libos/mock_mem.rs new file mode 100644 index 0000000..7a1311d --- /dev/null +++ b/src/libos/mock_mem.rs @@ -0,0 +1,113 @@ +use std::os::unix::io::RawFd; + +use nix::fcntl::{self, OFlag}; +use nix::sys::mman::{self, MapFlags, ProtFlags}; +use nix::{sys::stat::Mode, unistd}; + +use super::mem::PMEM_MAP_VADDR; +use crate::{MMUFlags, addr::{PhysAddr, VirtAddr}}; + +pub struct MockMemory { + size: usize, + fd: RawFd, +} + +impl MockMemory { + pub fn new(size: usize) -> Self { + let dir = tempfile::tempdir().expect("failed to create pmem directory"); + let path = dir.path().join("rcore-libos-pmem"); + + let fd = fcntl::open( + &path, + OFlag::O_CREAT | OFlag::O_EXCL | OFlag::O_RDWR, + Mode::S_IRWXU, + ) + .expect("faild to open"); + unistd::ftruncate(fd, size as _).expect("failed to set size of shared memory!"); + + let mem = Self { size, fd }; + mem.mmap(PMEM_MAP_VADDR, size, PhysAddr::new(0), MMUFlags::READ | MMUFlags::WRITE); + mem + } + + /// Mmap `paddr` to `vaddr` in frame file. + pub fn mmap(&self, vaddr: VirtAddr, len: usize, paddr: PhysAddr, prot: MMUFlags) { + assert!(paddr.addr() < self.size); + assert!(paddr.addr() + len <= self.size); + + let prot_noexec = ProtFlags::from(prot) - ProtFlags::PROT_EXEC; + let flags = MapFlags::MAP_SHARED | MapFlags::MAP_FIXED; + let fd = self.fd; + let offset = paddr.addr() as _; + trace!( + "mmap file: fd={}, offset={:#x}, len={:#x}, vaddr={:#x}, prot={:?}", + fd, + offset, + len, + vaddr.addr(), + prot, + ); + + unsafe { mman::mmap(vaddr.addr() as _, len, prot_noexec, flags, fd, offset) }.unwrap_or_else( + |err| { + panic!( + "failed to mmap: fd={}, offset={:#x}, len={:#x}, vaddr={:#x}, prot={:?}: {:?}", + fd, offset, len, vaddr.addr(), prot, err + ) + }, + ); + if prot.contains(MMUFlags::EXECUTE) { + self.mprotect(vaddr, len, prot); + } + } + + pub fn munmap(&self, vaddr: VirtAddr, len: usize) { + unsafe { mman::munmap(vaddr.addr() as _, len) } + .unwrap_or_else(|err| panic!("failed to munmap: vaddr={:#x}: {:?}", vaddr.addr(), err)); + } + + pub fn mprotect(&self, vaddr: VirtAddr, len: usize, prot: MMUFlags) { + unsafe { mman::mprotect(vaddr.addr() as _, len, prot.into()) }.unwrap_or_else(|err| { + panic!( + "failed to mprotect: vaddr={:#x}, prot={:?}: {:?}", + vaddr.addr(), prot, err + ) + }); + } + + pub fn phys_to_virt(&self, paddr: PhysAddr) -> usize { + assert!(paddr.addr() < self.size); + PMEM_MAP_VADDR.addr() + paddr.addr() + } + + pub fn as_ptr(&self, paddr: PhysAddr) -> *const T { + self.phys_to_virt(paddr) as _ + } + + pub fn as_mut_ptr(&self, paddr: PhysAddr) -> *mut T { + self.phys_to_virt(paddr) as _ + } +} + +impl Drop for MockMemory { + fn drop(&mut self) { + trace!("Drop MockMemory: fd={:?}", self.fd); + unistd::close(self.fd).expect("failed to close shared memory file!"); + } +} + +impl From for ProtFlags { + fn from(f: MMUFlags) -> Self { + let mut flags = Self::empty(); + if f.contains(MMUFlags::READ) { + flags |= ProtFlags::PROT_READ; + } + if f.contains(MMUFlags::WRITE) { + flags |= ProtFlags::PROT_WRITE; + } + if f.contains(MMUFlags::EXECUTE) { + flags |= ProtFlags::PROT_EXEC; + } + flags + } +} diff --git a/src/libos/mod.rs b/src/libos/mod.rs new file mode 100644 index 0000000..6c2bf0e --- /dev/null +++ b/src/libos/mod.rs @@ -0,0 +1,37 @@ +pub mod addr; +pub mod context; +pub mod debug; +pub mod mem; +pub mod mock_mem; +pub mod vm; +use crate::debug::display_info; +use crate::utils::once::LazyInit; +use crate::PageAlloc; + +extern "Rust" { + pub(crate) fn _main_for_arch(hartid: usize); +} + +#[no_mangle] +fn main() { + display_info!(); + println!(include_str!("../common/banner.txt")); + display_info!("Platform Name", "libos"); + display_info!("Boot HART ID", "{}", 0); + display_info!(); + unsafe { _main_for_arch(0) }; +} + +pub(crate) static PAGE_ALLOC: LazyInit<&dyn PageAlloc> = LazyInit::new(); + +/// Init arch with page allocator, like log crate +/// Please initialize the allocator before calling this function. +pub fn init(page_alloc: &'static dyn PageAlloc) { + PAGE_ALLOC.init_by(page_alloc); + + self::mem::init_mock_mem(); +} + +pub fn shutdown() { + std::process::exit(0); +} diff --git a/src/libos/vm.rs b/src/libos/vm.rs new file mode 100644 index 0000000..44e74e2 --- /dev/null +++ b/src/libos/vm.rs @@ -0,0 +1,37 @@ +use super::mem::{MOCK_PHYS_MEM, PMEM_SIZE}; +use crate::{is_aligned, MMUFlags, addr::{PhysAddr, VirtAddr}, PAGE_SIZE}; + +#[derive(Debug, Copy, Clone)] +pub struct Page { + pub vaddr: VirtAddr, +} + +impl Page { + pub fn new(vaddr: VirtAddr) -> Self { + Self { vaddr } + } +} + +/// Dummy page table implemented by `mmap`, `munmap`, and `mprotect`. +pub struct PageTable; + +impl PageTable { + pub fn new() -> Self { + Self + } +} + +impl PageTable { + pub fn map(&mut self, page: Page, paddr: PhysAddr, flags: MMUFlags) { + debug_assert!(is_aligned(paddr.addr())); + if paddr.addr() < PMEM_SIZE { + MOCK_PHYS_MEM.mmap(page.vaddr, PAGE_SIZE, paddr, flags); + } else { + error!("failed to map(no memory): paddr={:#x}, flags={:?}", paddr.addr(), flags); + } + } + + pub fn unmap(&mut self, vaddr: VirtAddr) { + MOCK_PHYS_MEM.munmap(vaddr as _, PAGE_SIZE); + } +} diff --git a/src/loongarch64/timer.rs b/src/loongarch64/timer.rs deleted file mode 100644 index 536f34c..0000000 --- a/src/loongarch64/timer.rs +++ /dev/null @@ -1,34 +0,0 @@ -use loongArch64::register::ecfg::{self, LineBasedInterrupt}; -use loongArch64::register::tcfg; -/// Returns the current clock time in hardware ticks. -use loongArch64::time::{get_timer_freq, Time}; -use spin::Lazy; - -// static mut FREQ: usize = 0; -static FREQ: Lazy = Lazy::new(|| get_timer_freq()); - -impl crate::time::Time { - #[inline] - pub fn get_freq() -> usize { - *FREQ - } - - /// Returns the current clock time in hardware ticks. - #[inline] - pub fn now() -> Self { - Self(Time::read()) - } -} - -pub fn init_timer() { - let ticks = ((*FREQ / 1000) + 3) & !3; - tcfg::set_periodic(true); // set timer to one-shot mode - tcfg::set_init_val(ticks); // set timer initial value - tcfg::set_en(true); // enable timer - - let inter = LineBasedInterrupt::TIMER - | LineBasedInterrupt::SWI0 - | LineBasedInterrupt::SWI1 - | LineBasedInterrupt::HWI0; - ecfg::set_lie(inter); -} diff --git a/src/utils/macros.rs b/src/utils/macros.rs new file mode 100644 index 0000000..fcd0b00 --- /dev/null +++ b/src/utils/macros.rs @@ -0,0 +1,11 @@ +/// bit macro will generate the number through a shift value. +/// +/// Here is an example. +/// You can use bit!(0) instead of 1 << 0. +/// bit!(39) instead of 1 << 39. +#[macro_export] +macro_rules! bit { + ($x:expr) => { + 1 << $x + }; +} \ No newline at end of file diff --git a/src/utils/mod.rs b/src/utils/mod.rs new file mode 100644 index 0000000..a1dca5e --- /dev/null +++ b/src/utils/mod.rs @@ -0,0 +1,2 @@ +pub(crate) mod macros; +pub(crate) mod once; \ No newline at end of file diff --git a/src/once/mod.rs b/src/utils/once.rs similarity index 100% rename from src/once/mod.rs rename to src/utils/once.rs diff --git a/src/x86_64/time.rs b/src/x86_64/time.rs deleted file mode 100644 index 2a00445..0000000 --- a/src/x86_64/time.rs +++ /dev/null @@ -1,48 +0,0 @@ -use raw_cpuid::CpuId; - -use crate::time::Time; - -static mut INIT_TICK: usize = 0; -static mut CPU_FREQ_MHZ: usize = 4000_000_000; - -impl Time { - #[inline] - pub fn get_freq() -> usize { - unsafe { CPU_FREQ_MHZ } - } - - #[inline] - pub fn now() -> Self { - Self(unsafe { core::arch::x86_64::_rdtsc() as _ }) - } -} - -pub(super) fn init_early() { - info!("freq1: {:#x?}", CpuId::new().get_tsc_info()); - debug!("cpuid: {:#x?}", CpuId::new().get_vendor_info()); - if let Some(freq) = CpuId::new() - .get_processor_frequency_info() - .map(|info| info.processor_base_frequency()) - { - debug!("freq: {}", freq); - if freq > 0 { - info!("Got TSC frequency by CPUID: {} MHz", freq); - unsafe { CPU_FREQ_MHZ = freq as _ } - } - } - - unsafe { INIT_TICK = core::arch::x86_64::_rdtsc() as _ }; - debug!("INIT_TICK: {}", unsafe { INIT_TICK }); - - unsafe { - use x2apic::lapic::{TimerDivide, TimerMode}; - let lapic = super::apic::local_apic(); - lapic.set_timer_mode(TimerMode::Periodic); - lapic.set_timer_divide(TimerDivide::Div256); // indeed it is Div1, the name is confusing. - lapic.enable_timer(); - - lapic.set_timer_initial(0x20_0000); - debug!("count: {}", lapic.timer_current()); - // set_oneshot_timer(2000); - } -}