diff --git a/src/framework/jinux-frame/Cargo.toml b/src/framework/jinux-frame/Cargo.toml index e35a0ae1..1633196f 100644 --- a/src/framework/jinux-frame/Cargo.toml +++ b/src/framework/jinux-frame/Cargo.toml @@ -7,17 +7,21 @@ edition = "2021" [dependencies] bitflags = "1.3" -x86_64 = "0.14.2" -x86 = "0.52.0" +cfg-if = "1.0" spin = "0.9.4" volatile = { version = "0.4.5", features = ["unstable"] } buddy_system_allocator = "0.9.0" pod = { path = "../pod" } -acpi = "4.1.1" intrusive-collections = "0.9.5" log = "0.4" -limine = { version = "0.1.10", features = ["into-uuid"] } lazy_static = { version = "1.0", features = ["spin_no_std"] } trapframe = { git = "https://github.com/sdww0/trapframe-rs", rev = "13e1065" } +limine = { version = "0.1.10", features = ["into-uuid"], optional = true } +x86_64 = { version = "0.14.2", optional = true } +x86 = { version = "0.52.0", optional = true } +acpi = { version = "4.1.1", optional = true } + [features] +default = ["x86_64"] +x86_64 = ["dep:x86_64", "dep:x86", "dep:limine", "dep:acpi"] diff --git a/src/framework/jinux-frame/src/arch/mod.rs b/src/framework/jinux-frame/src/arch/mod.rs new file mode 100644 index 00000000..0abf5c1a --- /dev/null +++ b/src/framework/jinux-frame/src/arch/mod.rs @@ -0,0 +1,20 @@ +#[cfg(feature = "x86_64")] +pub mod x86; + +/// Call before all the resources have been initialized +pub(crate) fn before_all_init() { + #[cfg(feature = "x86_64")] + x86::before_all_init(); +} + +/// Call after all the resources have been initialized +pub(crate) fn after_all_init() { + #[cfg(feature = "x86_64")] + x86::after_all_init(); +} + +#[inline] +pub(crate) fn interrupts_ack() { + #[cfg(feature = "x86_64")] + x86::interrupts_ack(); +} diff --git a/src/framework/jinux-frame/src/boot/limine.rs b/src/framework/jinux-frame/src/arch/x86/boot/limine.rs similarity index 97% rename from src/framework/jinux-frame/src/boot/limine.rs rename to src/framework/jinux-frame/src/arch/x86/boot/limine.rs index 8aaaf7cc..2ad131f1 100644 --- a/src/framework/jinux-frame/src/boot/limine.rs +++ b/src/framework/jinux-frame/src/arch/x86/boot/limine.rs @@ -2,7 +2,7 @@ use crate::config::{self, PAGE_SIZE}; use limine::{LimineBootInfoRequest, LimineHhdmRequest, LimineStackSizeRequest}; use log::info; -pub(crate) fn init() { +pub fn init() { if let Some(bootinfo) = BOOTLOADER_INFO_REQUEST.get_response().get() { info!( "booted by {} v{}", diff --git a/src/framework/jinux-frame/src/arch/x86/boot/mod.rs b/src/framework/jinux-frame/src/arch/x86/boot/mod.rs new file mode 100644 index 00000000..79499777 --- /dev/null +++ b/src/framework/jinux-frame/src/arch/x86/boot/mod.rs @@ -0,0 +1,6 @@ +mod limine; + +/// init bootloader +pub fn init() { + limine::init(); +} diff --git a/src/framework/jinux-frame/src/arch/x86/cpu.rs b/src/framework/jinux-frame/src/arch/x86/cpu.rs new file mode 100644 index 00000000..bebfbe51 --- /dev/null +++ b/src/framework/jinux-frame/src/arch/x86/cpu.rs @@ -0,0 +1,254 @@ +//! CPU. + +use core::arch::x86_64::{_fxrstor, _fxsave}; +use core::fmt::Debug; +use core::mem::MaybeUninit; + +use trapframe::{GeneralRegs, UserContext}; + +use log::debug; +use pod::Pod; + +/// Defines a CPU-local variable. +#[macro_export] +macro_rules! cpu_local { + () => { + todo!() + }; +} + +/// Returns the number of CPUs. +pub fn num_cpus() -> u32 { + // FIXME: we only start one cpu now. + 1 +} + +/// Returns the ID of this CPU. +pub fn this_cpu() -> u32 { + todo!() +} + +/// Cpu context, including both general-purpose registers and floating-point registers. +#[derive(Clone, Default, Copy, Debug)] +#[repr(C)] +pub struct CpuContext { + pub fp_regs: FpRegs, + pub gp_regs: GpRegs, + pub fs_base: u64, + pub gs_base: u64, + /// trap information, this field is all zero when it is syscall + pub trap_information: TrapInformation, +} + +impl CpuContext { + pub fn set_rax(&mut self, rax: u64) { + self.gp_regs.rax = rax; + } + + pub fn set_rsp(&mut self, rsp: u64) { + self.gp_regs.rsp = rsp; + } + + pub fn set_rip(&mut self, rip: u64) { + self.gp_regs.rip = rip; + } + + pub fn set_fsbase(&mut self, fs_base: u64) { + self.fs_base = fs_base; + } +} + +#[derive(Clone, Default, Copy, Debug)] +#[repr(C)] +pub struct TrapInformation { + pub cr2: u64, + pub id: u64, + pub err: u64, +} + +/// The general-purpose registers of CPU. +#[derive(Clone, Copy, Debug, Default)] +#[repr(C)] +pub struct GpRegs { + pub r8: u64, + pub r9: u64, + pub r10: u64, + pub r11: u64, + pub r12: u64, + pub r13: u64, + pub r14: u64, + pub r15: u64, + pub rdi: u64, + pub rsi: u64, + pub rbp: u64, + pub rbx: u64, + pub rdx: u64, + pub rax: u64, + pub rcx: u64, + pub rsp: u64, + pub rip: u64, + pub rflag: u64, +} + +unsafe impl Pod for GpRegs {} +unsafe impl Pod for TrapInformation {} +unsafe impl Pod for CpuContext {} +unsafe impl Pod for FpRegs {} + +impl From for CpuContext { + fn from(value: UserContext) -> Self { + Self { + gp_regs: GpRegs { + r8: value.general.r8 as u64, + r9: value.general.r9 as u64, + r10: value.general.r10 as u64, + r11: value.general.r11 as u64, + r12: value.general.r12 as u64, + r13: value.general.r13 as u64, + r14: value.general.r14 as u64, + r15: value.general.r15 as u64, + rdi: value.general.rdi as u64, + rsi: value.general.rsi as u64, + rbp: value.general.rbp as u64, + rbx: value.general.rbx as u64, + rdx: value.general.rdx as u64, + rax: value.general.rax as u64, + rcx: value.general.rcx as u64, + rsp: value.general.rsp as u64, + rip: value.general.rip as u64, + rflag: value.general.rflags as u64, + }, + fs_base: value.general.fsbase as u64, + fp_regs: FpRegs::default(), + trap_information: TrapInformation { + cr2: x86_64::registers::control::Cr2::read_raw(), + id: value.trap_num as u64, + err: value.error_code as u64, + }, + gs_base: value.general.gsbase as u64, + } + } +} + +impl Into for CpuContext { + fn into(self) -> UserContext { + UserContext { + trap_num: self.trap_information.id as usize, + error_code: self.trap_information.err as usize, + general: GeneralRegs { + rax: self.gp_regs.rax as usize, + rbx: self.gp_regs.rbx as usize, + rcx: self.gp_regs.rcx as usize, + rdx: self.gp_regs.rdx as usize, + rsi: self.gp_regs.rsi as usize, + rdi: self.gp_regs.rdi as usize, + rbp: self.gp_regs.rbp as usize, + rsp: self.gp_regs.rsp as usize, + r8: self.gp_regs.r8 as usize, + r9: self.gp_regs.r9 as usize, + r10: self.gp_regs.r10 as usize, + r11: self.gp_regs.r11 as usize, + r12: self.gp_regs.r12 as usize, + r13: self.gp_regs.r13 as usize, + r14: self.gp_regs.r14 as usize, + r15: self.gp_regs.r15 as usize, + rip: self.gp_regs.rip as usize, + rflags: self.gp_regs.rflag as usize, + fsbase: self.fs_base as usize, + gsbase: self.gs_base as usize, + }, + } + } +} + +/// The floating-point state of CPU. +#[derive(Clone, Copy, Debug)] +#[repr(C)] +pub struct FpRegs { + buf: FxsaveArea, + is_valid: bool, +} + +impl FpRegs { + /// Create a new instance. + /// + /// Note that a newly-created instance's floating point state is not + /// initialized, thus considered invalid (i.e., `self.is_valid() == false`). + pub fn new() -> Self { + // The buffer address requires 16bytes alignment. + Self { + buf: unsafe { MaybeUninit::uninit().assume_init() }, + is_valid: false, + } + } + + /// Save CPU's current floating pointer states into this instance. + pub fn save(&mut self) { + debug!("save fpregs"); + debug!("write addr = 0x{:x}", (&mut self.buf) as *mut _ as usize); + let layout = alloc::alloc::Layout::for_value(&self.buf); + debug!("layout: {:?}", layout); + let ptr = unsafe { alloc::alloc::alloc(layout) } as usize; + debug!("ptr = 0x{:x}", ptr); + unsafe { + _fxsave((&mut self.buf.data).as_mut_ptr() as *mut u8); + } + debug!("save fpregs success"); + self.is_valid = true; + } + + /// Save the floating state given by a slice of u8. + /// + /// After calling this method, the state of the instance will be considered valid. + /// + /// # Safety + /// + /// It is the caller's responsibility to ensure that the source slice contains + /// data that is in xsave/xrstor format. The slice must have a length of 512 bytes. + pub unsafe fn save_from_slice(&mut self, src: &[u8]) { + (&mut self.buf.data).copy_from_slice(src); + self.is_valid = true; + } + + /// Returns whether the instance can contains data in valid xsave/xrstor format. + pub fn is_valid(&self) -> bool { + self.is_valid + } + + /// Clear the state of the instance. + /// + /// This method does not reset the underlying buffer that contains the floating + /// point state; it only marks the buffer __invalid__. + pub fn clear(&mut self) { + self.is_valid = false; + } + + /// Restore CPU's CPU floating pointer states from this instance. + /// + /// Panic. If the current state is invalid, the method will panic. + pub fn restore(&self) { + debug!("restore fpregs"); + assert!(self.is_valid); + unsafe { _fxrstor((&self.buf.data).as_ptr()) }; + debug!("restore fpregs success"); + } + + /// Returns the floating point state as a slice. + /// + /// Note that the slice may contain garbage if `self.is_valid() == false`. + pub fn as_slice(&self) -> &[u8] { + &self.buf.data + } +} + +impl Default for FpRegs { + fn default() -> Self { + Self::new() + } +} + +#[repr(C, align(16))] +#[derive(Debug, Clone, Copy)] +struct FxsaveArea { + data: [u8; 512], // 512 bytes +} diff --git a/src/framework/jinux-frame/src/device/cmos.rs b/src/framework/jinux-frame/src/arch/x86/device/cmos.rs similarity index 92% rename from src/framework/jinux-frame/src/device/cmos.rs rename to src/framework/jinux-frame/src/arch/x86/device/cmos.rs index 02ec84ce..ef8b1a83 100644 --- a/src/framework/jinux-frame/src/device/cmos.rs +++ b/src/framework/jinux-frame/src/arch/x86/device/cmos.rs @@ -1,7 +1,7 @@ use acpi::{fadt::Fadt, sdt::Signature}; use x86_64::instructions::port::{ReadOnlyAccess, WriteOnlyAccess}; -use crate::driver::ACPI_TABLES; +use crate::arch::x86::kernel::acpi::ACPI_TABLES; use super::io_port::IoPort; diff --git a/src/framework/jinux-frame/src/device/io_port.rs b/src/framework/jinux-frame/src/arch/x86/device/io_port.rs similarity index 100% rename from src/framework/jinux-frame/src/device/io_port.rs rename to src/framework/jinux-frame/src/arch/x86/device/io_port.rs diff --git a/src/framework/jinux-frame/src/arch/x86/device/mod.rs b/src/framework/jinux-frame/src/arch/x86/device/mod.rs new file mode 100644 index 00000000..33c4ca70 --- /dev/null +++ b/src/framework/jinux-frame/src/arch/x86/device/mod.rs @@ -0,0 +1,7 @@ +//! Device-related APIs. +//! This module mainly contains the APIs that should exposed to the device driver like PCI, RTC + +pub mod cmos; +pub mod io_port; +pub mod pci; +pub mod serial; diff --git a/src/framework/jinux-frame/src/device/pci.rs b/src/framework/jinux-frame/src/arch/x86/device/pci.rs similarity index 100% rename from src/framework/jinux-frame/src/device/pci.rs rename to src/framework/jinux-frame/src/arch/x86/device/pci.rs diff --git a/src/framework/jinux-frame/src/device/serial.rs b/src/framework/jinux-frame/src/arch/x86/device/serial.rs similarity index 81% rename from src/framework/jinux-frame/src/device/serial.rs rename to src/framework/jinux-frame/src/arch/x86/device/serial.rs index d2012ccc..b043be14 100644 --- a/src/framework/jinux-frame/src/device/serial.rs +++ b/src/framework/jinux-frame/src/arch/x86/device/serial.rs @@ -1,12 +1,10 @@ //! A port-mapped UART. Copied from uart_16550. -use super::io_port::{IoPort, ReadWriteAccess, WriteOnlyAccess}; +use crate::arch::x86::device::io_port::{IoPort, ReadWriteAccess, WriteOnlyAccess}; +use crate::trap::IrqAllocateHandle; use alloc::{sync::Arc, vec::Vec}; -use core::fmt::{self, Write}; use log::debug; use spin::{Mutex, Once}; - -use crate::{driver::pic_allocate_irq, trap::IrqAllocateHandle}; use trapframe::TrapFrame; bitflags::bitflags! { @@ -56,7 +54,7 @@ pub fn register_serial_input_callback(f: impl Fn(u8) + Send + Sync + 'static) { } pub(crate) fn callback_init() { - let mut irq = pic_allocate_irq(4).unwrap(); + let mut irq = crate::arch::x86::kernel::pic::allocate_irq(4).unwrap(); irq.on_active(handle_serial_input); CONSOLE_IRQ_CALLBACK.call_once(|| Mutex::new(irq)); } @@ -115,32 +113,3 @@ pub fn receive_char() -> Option { None } } - -struct Stdout; - -impl Write for Stdout { - fn write_str(&mut self, s: &str) -> fmt::Result { - for &c in s.as_bytes() { - send(c); - } - Ok(()) - } -} - -pub fn print(args: fmt::Arguments) { - Stdout.write_fmt(args).unwrap(); -} - -#[macro_export] -macro_rules! console_print { - ($fmt: literal $(, $($arg: tt)+)?) => { - $crate::device::serial::print(format_args!($fmt $(, $($arg)+)?)) - } -} - -#[macro_export] -macro_rules! console_println { - ($fmt: literal $(, $($arg: tt)+)?) => { - $crate::device::serial::print(format_args!(concat!($fmt, "\n") $(, $($arg)+)?)) - } -} diff --git a/src/framework/jinux-frame/src/driver/acpi.rs b/src/framework/jinux-frame/src/arch/x86/kernel/acpi.rs similarity index 100% rename from src/framework/jinux-frame/src/driver/acpi.rs rename to src/framework/jinux-frame/src/arch/x86/kernel/acpi.rs diff --git a/src/framework/jinux-frame/src/driver/ioapic.rs b/src/framework/jinux-frame/src/arch/x86/kernel/ioapic.rs similarity index 82% rename from src/framework/jinux-frame/src/driver/ioapic.rs rename to src/framework/jinux-frame/src/arch/x86/kernel/ioapic.rs index 052906d4..52ce67a4 100644 --- a/src/framework/jinux-frame/src/driver/ioapic.rs +++ b/src/framework/jinux-frame/src/arch/x86/kernel/ioapic.rs @@ -5,7 +5,7 @@ use x86::apic::ioapic::IoApic; use super::acpi::ACPI_TABLES; -pub(crate) struct IoApicWrapper { +pub struct IoApicWrapper { io_apic: IoApic, } @@ -14,23 +14,23 @@ impl IoApicWrapper { Self { io_apic } } - pub(crate) fn disable_all(&mut self) { + pub fn disable_all(&mut self) { self.io_apic.disable_all() } - pub(crate) fn enable(&mut self, irq: u8, cpunum: u8) { + pub fn enable(&mut self, irq: u8, cpunum: u8) { self.io_apic.enable(irq, cpunum); } - pub(crate) fn id(&mut self) -> u8 { + pub fn id(&mut self) -> u8 { self.io_apic.id() } - pub(crate) fn version(&mut self) -> u8 { + pub fn version(&mut self) -> u8 { self.io_apic.version() } - pub(crate) fn supported_interrupts(&mut self) -> u8 { + pub fn supported_interrupts(&mut self) -> u8 { self.io_apic.supported_interrupts() } } @@ -40,7 +40,7 @@ unsafe impl Send for IoApicWrapper {} /// # Safety: The pointer inside the IoApic will not change unsafe impl Sync for IoApicWrapper {} -pub(crate) static IO_APIC: Once> = Once::new(); +pub static IO_APIC: Once> = Once::new(); pub fn init() { let c = ACPI_TABLES.get().unwrap().lock(); diff --git a/src/framework/jinux-frame/src/arch/x86/kernel/mod.rs b/src/framework/jinux-frame/src/arch/x86/kernel/mod.rs new file mode 100644 index 00000000..23f3323a --- /dev/null +++ b/src/framework/jinux-frame/src/arch/x86/kernel/mod.rs @@ -0,0 +1,9 @@ +//! the kernel part of x86 +//! +//! The modules should only visiable inside x86 module +//! + +pub mod acpi; +pub mod ioapic; +pub mod pic; +pub mod xapic; diff --git a/src/framework/jinux-frame/src/driver/pic.rs b/src/framework/jinux-frame/src/arch/x86/kernel/pic.rs similarity index 86% rename from src/framework/jinux-frame/src/driver/pic.rs rename to src/framework/jinux-frame/src/arch/x86/kernel/pic.rs index cda3ebfd..dff5af7b 100644 --- a/src/framework/jinux-frame/src/driver/pic.rs +++ b/src/framework/jinux-frame/src/arch/x86/kernel/pic.rs @@ -1,4 +1,4 @@ -use crate::device::io_port::{IoPort, WriteOnlyAccess}; +use crate::arch::x86::device::io_port::{IoPort, WriteOnlyAccess}; use crate::trap::allocate_target_irq; use crate::trap::IrqAllocateHandle; @@ -32,7 +32,7 @@ static MASK_SLAVE: AtomicU8 = AtomicU8::new(0x00); static CHANGE_LOCK: AtomicBool = AtomicBool::new(false); /// init the PIC device -pub(crate) fn init() { +pub fn init() { if CHANGE_LOCK.load(Relaxed) { return; } @@ -42,13 +42,11 @@ pub(crate) fn init() { "PIC init, master mask:{:x} slave_mask:{:x}", master_mask, slave_mask ); - unsafe { - set_mask(master_mask, slave_mask); - } + set_mask(master_mask, slave_mask); } /// allocate irq, for example, if timer need IRQ0, it will return IrqAllocateHandle with irq num: IRQ_OFFSET+0 -pub(crate) fn allocate_irq(index: u8) -> Option { +pub fn allocate_irq(index: u8) -> Option { if index >= 16 { return None; } @@ -66,7 +64,7 @@ pub(crate) fn allocate_irq(index: u8) -> Option { /// enable the PIC device, this function will permanent enable all the interrupts #[inline] -pub(crate) unsafe fn enable() { +pub fn enable() { CHANGE_LOCK.store(true, Relaxed); set_mask(0, 0); } @@ -74,7 +72,7 @@ pub(crate) unsafe fn enable() { /// disable the PIC device, this function will permanent disable all the interrupts /// the interrupts mask may not exists after calling init function #[inline] -pub(crate) unsafe fn disable() { +pub fn disable() { CHANGE_LOCK.store(true, Relaxed); set_mask(0xFF, 0xFF); } @@ -82,23 +80,19 @@ pub(crate) unsafe fn disable() { /// enable the PIC device, this function will allow all the interrupts /// the interrupts mask may not exists after calling init function #[inline] -pub(crate) fn enable_temp() { - unsafe { - set_mask(0, 0); - } +pub fn enable_temp() { + set_mask(0, 0); } /// disable the PIC device, this function will disable all the interrupts /// the interrupts mask may not exists after calling init function #[inline] -pub(crate) fn disable_temp() { - unsafe { - set_mask(0xFF, 0xFF); - } +pub fn disable_temp() { + set_mask(0xFF, 0xFF); } #[inline(always)] -pub(crate) unsafe fn set_mask(master_mask: u8, slave_mask: u8) { +pub fn set_mask(master_mask: u8, slave_mask: u8) { // Start initialization MASTER_CMD.write(0x11); SLAVE_CMD.write(0x11); diff --git a/src/framework/jinux-frame/src/driver/xapic.rs b/src/framework/jinux-frame/src/arch/x86/kernel/xapic.rs similarity index 83% rename from src/framework/jinux-frame/src/driver/xapic.rs rename to src/framework/jinux-frame/src/arch/x86/kernel/xapic.rs index 7213eb78..cbd09859 100644 --- a/src/framework/jinux-frame/src/driver/xapic.rs +++ b/src/framework/jinux-frame/src/arch/x86/kernel/xapic.rs @@ -3,13 +3,13 @@ use log::debug; use spin::{Mutex, Once}; use x86::apic::xapic; -pub(crate) const IA32_APIC_BASE_MSR: u32 = 0x1B; -pub(crate) const IA32_APIC_BASE_MSR_BSP: u32 = 0x100; // Processor is a BSP -pub(crate) const IA32_APIC_BASE_MSR_ENABLE: u64 = 0x800; +const IA32_APIC_BASE_MSR: u32 = 0x1B; +const IA32_APIC_BASE_MSR_BSP: u32 = 0x100; // Processor is a BSP +const IA32_APIC_BASE_MSR_ENABLE: u64 = 0x800; const APIC_LVT_MASK_BITS: u32 = 1 << 16; -pub(crate) static XAPIC_INSTANCE: Once> = Once::new(); +pub static XAPIC_INSTANCE: Once> = Once::new(); #[derive(Debug)] pub struct Xapic { @@ -25,26 +25,26 @@ impl Xapic { } /// Read a register from the MMIO region. - pub(crate) fn read(&self, offset: u32) -> u32 { + pub fn read(&self, offset: u32) -> u32 { assert!(offset as usize % 4 == 0); let index = offset as usize / 4; unsafe { core::ptr::read_volatile(&self.mmio_region[index]) } } /// write a register in the MMIO region. - pub(crate) fn write(&mut self, offset: u32, val: u32) { + pub fn write(&mut self, offset: u32, val: u32) { assert!(offset as usize % 4 == 0); let index = offset as usize / 4; unsafe { core::ptr::write_volatile(&mut self.mmio_region[index], val) } } } -pub(crate) fn has_apic() -> bool { +pub fn has_apic() -> bool { let value = unsafe { core::arch::x86_64::__cpuid(1) }; value.edx & 0x100 != 0 } -pub(crate) fn init() { +pub fn init() { super::pic::disable_temp(); let mut apic = Xapic::new(vm::paddr_to_vaddr(get_apic_base_address())); diff --git a/src/framework/jinux-frame/src/arch/x86/mm/mod.rs b/src/framework/jinux-frame/src/arch/x86/mm/mod.rs new file mode 100644 index 00000000..f71680dc --- /dev/null +++ b/src/framework/jinux-frame/src/arch/x86/mm/mod.rs @@ -0,0 +1,57 @@ +use alloc::vec::Vec; +use limine::{LimineMemmapEntry, LimineMemmapRequest, LimineMemoryMapEntryType}; +use log::debug; +use spin::Once; +use x86_64::structures::paging::PhysFrame; + +use crate::vm::{MemoryRegions, MemoryRegionsType, Paddr}; + +pub unsafe fn activate_page_table(root_paddr: Paddr, flags: x86_64::registers::control::Cr3Flags) { + x86_64::registers::control::Cr3::write( + PhysFrame::from_start_address(x86_64::PhysAddr::new(root_paddr as u64)).unwrap(), + flags, + ); +} + +static MEMMAP_REQUEST: LimineMemmapRequest = LimineMemmapRequest::new(0); +static MEMORY_REGIONS: Once> = Once::new(); + +impl From<&LimineMemmapEntry> for MemoryRegions { + fn from(value: &LimineMemmapEntry) -> Self { + Self { + base: value.base, + len: value.len, + typ: MemoryRegionsType::from(value.typ), + } + } +} + +impl From for MemoryRegionsType { + fn from(value: LimineMemoryMapEntryType) -> Self { + match value { + LimineMemoryMapEntryType::Usable => Self::Usable, + LimineMemoryMapEntryType::Reserved => Self::Reserved, + LimineMemoryMapEntryType::AcpiReclaimable => Self::AcpiReclaimable, + LimineMemoryMapEntryType::AcpiNvs => Self::AcpiNvs, + LimineMemoryMapEntryType::BadMemory => Self::BadMemory, + LimineMemoryMapEntryType::BootloaderReclaimable => Self::BootloaderReclaimable, + LimineMemoryMapEntryType::KernelAndModules => Self::KernelAndModules, + LimineMemoryMapEntryType::Framebuffer => Self::Framebuffer, + } + } +} + +/// Get memory regions, this function should call after the heap was initialized +pub fn get_memory_regions() -> &'static Vec { + let mut memory_regions = Vec::new(); + let response = MEMMAP_REQUEST + .get_response() + .get() + .expect("Not found memory region information"); + for i in response.memmap() { + debug!("Found memory region:{:x?}", **i); + memory_regions.push(MemoryRegions::from(&**i)); + } + MEMORY_REGIONS.call_once(|| memory_regions); + MEMORY_REGIONS.get().unwrap() +} diff --git a/src/framework/jinux-frame/src/arch/x86/mod.rs b/src/framework/jinux-frame/src/arch/x86/mod.rs new file mode 100644 index 00000000..3172c42b --- /dev/null +++ b/src/framework/jinux-frame/src/arch/x86/mod.rs @@ -0,0 +1,169 @@ +mod boot; +pub(crate) mod cpu; +pub mod device; +mod kernel; +pub(crate) mod mm; +pub(crate) mod timer; + +use core::fmt::Write; +use alloc::fmt; +use log::{debug, info}; +use trapframe::TrapFrame; +use x86_64::registers::{ + rflags::RFlags, + segmentation::{Segment64, FS}, +}; + +use crate::{ + trap::call_irq_callback_functions, + user::{UserEvent, UserMode, UserModeExecute}, +}; + +use self::cpu::CpuContext; + +pub(crate) fn before_all_init() { + enable_common_cpu_features(); + device::serial::init(); + boot::init(); +} + +pub(crate) fn after_all_init() { + device::serial::callback_init(); + kernel::acpi::init(); + if kernel::xapic::has_apic() { + kernel::ioapic::init(); + kernel::xapic::init(); + } else { + info!("No apic exists, using pic instead"); + kernel::pic::enable(); + } + timer::init(); + // Some driver like serial may use PIC + kernel::pic::init(); +} + +pub(crate) fn interrupts_ack() { + kernel::pic::ack(); + kernel::xapic::ack(); +} + +impl<'a> UserModeExecute for UserMode<'a> { + fn execute(&mut self) -> crate::user::UserEvent { + unsafe { + self.user_space.vm_space().activate(); + } + if !self.executed { + self.context = self.user_space.cpu_ctx; + if self.context.gp_regs.rflag == 0 { + self.context.gp_regs.rflag = (RFlags::INTERRUPT_FLAG | RFlags::ID).bits() | 0x2; + } + // write fsbase + unsafe { + FS::write_base(x86_64::VirtAddr::new(self.user_space.cpu_ctx.fs_base)); + } + let fp_regs = self.user_space.cpu_ctx.fp_regs; + if fp_regs.is_valid() { + fp_regs.restore(); + } + self.executed = true; + } else { + // write fsbase + if FS::read_base().as_u64() != self.context.fs_base { + debug!("write fsbase: 0x{:x}", self.context.fs_base); + unsafe { + FS::write_base(x86_64::VirtAddr::new(self.context.fs_base)); + } + } + } + self.user_context = self.context.into(); + self.user_context.run(); + let mut trap_frame; + while self.user_context.trap_num >= 0x20 && self.user_context.trap_num < 0x100 { + trap_frame = TrapFrame { + rax: self.user_context.general.rax, + rbx: self.user_context.general.rbx, + rcx: self.user_context.general.rcx, + rdx: self.user_context.general.rdx, + rsi: self.user_context.general.rsi, + rdi: self.user_context.general.rdi, + rbp: self.user_context.general.rbp, + rsp: self.user_context.general.rsp, + r8: self.user_context.general.r8, + r9: self.user_context.general.r9, + r10: self.user_context.general.r10, + r11: self.user_context.general.r11, + r12: self.user_context.general.r12, + r13: self.user_context.general.r13, + r14: self.user_context.general.r14, + r15: self.user_context.general.r15, + _pad: 0, + trap_num: self.user_context.trap_num, + error_code: self.user_context.error_code, + rip: self.user_context.general.rip, + cs: 0, + rflags: self.user_context.general.rflags, + }; + call_irq_callback_functions(&mut trap_frame); + self.user_context.run(); + } + x86_64::instructions::interrupts::enable(); + self.context = CpuContext::from(self.user_context); + self.context.fs_base = FS::read_base().as_u64(); + if self.user_context.trap_num != 0x100 { + UserEvent::Exception + } else { + UserEvent::Syscall + } + } +} + +struct Stdout; + +impl Write for Stdout { + fn write_str(&mut self, s: &str) -> fmt::Result { + for &c in s.as_bytes() { + device::serial::send(c); + } + Ok(()) + } +} + +pub fn print(args: fmt::Arguments) { + Stdout.write_fmt(args).unwrap(); +} + +#[macro_export] +macro_rules! print { + ($fmt: literal $(, $($arg: tt)+)?) => { + $crate::arch::x86::print(format_args!($fmt $(, $($arg)+)?)) + } +} + +#[macro_export] +macro_rules! println { + ($fmt: literal $(, $($arg: tt)+)?) => { + $crate::arch::x86::print(format_args!(concat!($fmt, "\n") $(, $($arg)+)?)) + } +} + +fn enable_common_cpu_features() { + use x86_64::registers::{control::Cr4Flags, model_specific::EferFlags, xcontrol::XCr0Flags}; + let mut cr4 = x86_64::registers::control::Cr4::read(); + cr4 |= Cr4Flags::FSGSBASE | Cr4Flags::OSXSAVE | Cr4Flags::OSFXSR | Cr4Flags::OSXMMEXCPT_ENABLE; + unsafe { + x86_64::registers::control::Cr4::write(cr4); + } + + let mut xcr0 = x86_64::registers::xcontrol::XCr0::read(); + xcr0 |= XCr0Flags::AVX | XCr0Flags::SSE; + unsafe { + x86_64::registers::xcontrol::XCr0::write(xcr0); + } + + unsafe { + // enable non-executable page protection + x86_64::registers::model_specific::Efer::update(|efer| { + *efer |= EferFlags::NO_EXECUTE_ENABLE; + }); + } +} diff --git a/src/framework/jinux-frame/src/driver/timer/apic.rs b/src/framework/jinux-frame/src/arch/x86/timer/apic.rs similarity index 91% rename from src/framework/jinux-frame/src/driver/timer/apic.rs rename to src/framework/jinux-frame/src/arch/x86/timer/apic.rs index 6595b55a..f6302c67 100644 --- a/src/framework/jinux-frame/src/driver/timer/apic.rs +++ b/src/framework/jinux-frame/src/arch/x86/timer/apic.rs @@ -1,15 +1,14 @@ use log::info; use trapframe::TrapFrame; -use crate::{ - config, - driver::{pic, timer, xapic::XAPIC_INSTANCE}, -}; +use crate::arch::x86::kernel::{pic, xapic::XAPIC_INSTANCE}; +use crate::config; + use x86::apic::xapic; pub fn init() { let mut apic_lock = XAPIC_INSTANCE.get().unwrap().lock(); - let handle = unsafe { crate::trap::IrqLine::acquire(timer::TIMER_IRQ_NUM) }; + let handle = unsafe { crate::trap::IrqLine::acquire(super::TIMER_IRQ_NUM) }; let a = handle.on_active(init_function); // divide by 64 apic_lock.write(xapic::XAPIC_TIMER_DIV_CONF, 0b1001); @@ -19,7 +18,7 @@ pub fn init() { // init pic for now, disable it after the APIC Timer init is done pic::enable_temp(); - timer::pit::init(); + super::pit::init(); static mut IS_FINISH: bool = false; // wait until it is finish @@ -57,7 +56,7 @@ pub fn init() { apic_lock.write(xapic::XAPIC_TIMER_INIT_COUNT, ticks as u32); apic_lock.write( xapic::XAPIC_LVT_TIMER, - timer::TIMER_IRQ_NUM as u32 | (1 << 17), + super::TIMER_IRQ_NUM as u32 | (1 << 17), ); apic_lock.write(xapic::XAPIC_TIMER_DIV_CONF, 0b1001); diff --git a/src/framework/jinux-frame/src/driver/timer/hpet.rs b/src/framework/jinux-frame/src/arch/x86/timer/hpet.rs similarity index 98% rename from src/framework/jinux-frame/src/driver/timer/hpet.rs rename to src/framework/jinux-frame/src/arch/x86/timer/hpet.rs index 299e797a..60b184b0 100644 --- a/src/framework/jinux-frame/src/driver/timer/hpet.rs +++ b/src/framework/jinux-frame/src/arch/x86/timer/hpet.rs @@ -7,7 +7,7 @@ use volatile::{ Volatile, }; -use crate::driver::{acpi::ACPI_TABLES, ioapic}; +use crate::arch::x86::kernel::{acpi::ACPI_TABLES, ioapic}; static HPET_INSTANCE: Once = Once::new(); const OFFSET_ID_REGISTER: usize = 0x000; diff --git a/src/framework/jinux-frame/src/driver/timer/mod.rs b/src/framework/jinux-frame/src/arch/x86/timer/mod.rs similarity index 96% rename from src/framework/jinux-frame/src/driver/timer/mod.rs rename to src/framework/jinux-frame/src/arch/x86/timer/mod.rs index 1e943d1d..992c3263 100644 --- a/src/framework/jinux-frame/src/driver/timer/mod.rs +++ b/src/framework/jinux-frame/src/arch/x86/timer/mod.rs @@ -8,16 +8,17 @@ use alloc::{boxed::Box, collections::BinaryHeap, sync::Arc, vec::Vec}; use spin::{Mutex, Once}; use trapframe::TrapFrame; +use crate::arch::x86::kernel; use crate::trap::IrqAllocateHandle; -pub(crate) const TIMER_IRQ_NUM: u8 = 32; +pub const TIMER_IRQ_NUM: u8 = 32; pub static mut TICK: u64 = 0; static TIMER_IRQ: Once = Once::new(); pub fn init() { TIMEOUT_LIST.call_once(|| Mutex::new(BinaryHeap::new())); - if super::xapic::has_apic() { + if kernel::xapic::has_apic() { apic::init(); } else { pit::init(); @@ -47,7 +48,6 @@ fn timer_callback(trap_frame: &TrapFrame) { for callback in callbacks { callback.callback.call((&callback,)); } - // crate::interrupt_ack(); } static TIMEOUT_LIST: Once>>> = Once::new(); diff --git a/src/framework/jinux-frame/src/driver/timer/pit.rs b/src/framework/jinux-frame/src/arch/x86/timer/pit.rs similarity index 88% rename from src/framework/jinux-frame/src/driver/timer/pit.rs rename to src/framework/jinux-frame/src/arch/x86/timer/pit.rs index e2715393..bd0d57bd 100644 --- a/src/framework/jinux-frame/src/driver/timer/pit.rs +++ b/src/framework/jinux-frame/src/arch/x86/timer/pit.rs @@ -2,7 +2,7 @@ use crate::config::TIMER_FREQ; -use crate::device::io_port::{IoPort, WriteOnlyAccess}; +use crate::arch::x86::device::io_port::{IoPort, WriteOnlyAccess}; const TIMER_RATE: u32 = 1193182; diff --git a/src/framework/jinux-frame/src/boot/mod.rs b/src/framework/jinux-frame/src/boot/mod.rs deleted file mode 100644 index 44515ac0..00000000 --- a/src/framework/jinux-frame/src/boot/mod.rs +++ /dev/null @@ -1,9 +0,0 @@ -mod limine; - -pub(crate) const MEMORY_MAP_MAX_COUNT: usize = 30; -pub(crate) const MODULE_MAX_COUNT: usize = 10; - -/// init bootloader -pub(crate) fn init() { - limine::init(); -} diff --git a/src/framework/jinux-frame/src/cpu.rs b/src/framework/jinux-frame/src/cpu.rs index bebfbe51..34d80127 100644 --- a/src/framework/jinux-frame/src/cpu.rs +++ b/src/framework/jinux-frame/src/cpu.rs @@ -1,254 +1,22 @@ //! CPU. -use core::arch::x86_64::{_fxrstor, _fxsave}; -use core::fmt::Debug; -use core::mem::MaybeUninit; +cfg_if::cfg_if! { + if #[cfg(feature="x86_64")]{ -use trapframe::{GeneralRegs, UserContext}; + pub use crate::arch::x86::cpu::CpuContext; + pub use crate::arch::x86::cpu::TrapInformation; + pub use crate::arch::x86::cpu::GpRegs; + pub use crate::arch::x86::cpu::FpRegs; -use log::debug; -use pod::Pod; - -/// Defines a CPU-local variable. -#[macro_export] -macro_rules! cpu_local { - () => { - todo!() - }; -} - -/// Returns the number of CPUs. -pub fn num_cpus() -> u32 { - // FIXME: we only start one cpu now. - 1 -} - -/// Returns the ID of this CPU. -pub fn this_cpu() -> u32 { - todo!() -} - -/// Cpu context, including both general-purpose registers and floating-point registers. -#[derive(Clone, Default, Copy, Debug)] -#[repr(C)] -pub struct CpuContext { - pub fp_regs: FpRegs, - pub gp_regs: GpRegs, - pub fs_base: u64, - pub gs_base: u64, - /// trap information, this field is all zero when it is syscall - pub trap_information: TrapInformation, -} - -impl CpuContext { - pub fn set_rax(&mut self, rax: u64) { - self.gp_regs.rax = rax; - } - - pub fn set_rsp(&mut self, rsp: u64) { - self.gp_regs.rsp = rsp; - } - - pub fn set_rip(&mut self, rip: u64) { - self.gp_regs.rip = rip; - } - - pub fn set_fsbase(&mut self, fs_base: u64) { - self.fs_base = fs_base; - } -} - -#[derive(Clone, Default, Copy, Debug)] -#[repr(C)] -pub struct TrapInformation { - pub cr2: u64, - pub id: u64, - pub err: u64, -} - -/// The general-purpose registers of CPU. -#[derive(Clone, Copy, Debug, Default)] -#[repr(C)] -pub struct GpRegs { - pub r8: u64, - pub r9: u64, - pub r10: u64, - pub r11: u64, - pub r12: u64, - pub r13: u64, - pub r14: u64, - pub r15: u64, - pub rdi: u64, - pub rsi: u64, - pub rbp: u64, - pub rbx: u64, - pub rdx: u64, - pub rax: u64, - pub rcx: u64, - pub rsp: u64, - pub rip: u64, - pub rflag: u64, -} - -unsafe impl Pod for GpRegs {} -unsafe impl Pod for TrapInformation {} -unsafe impl Pod for CpuContext {} -unsafe impl Pod for FpRegs {} - -impl From for CpuContext { - fn from(value: UserContext) -> Self { - Self { - gp_regs: GpRegs { - r8: value.general.r8 as u64, - r9: value.general.r9 as u64, - r10: value.general.r10 as u64, - r11: value.general.r11 as u64, - r12: value.general.r12 as u64, - r13: value.general.r13 as u64, - r14: value.general.r14 as u64, - r15: value.general.r15 as u64, - rdi: value.general.rdi as u64, - rsi: value.general.rsi as u64, - rbp: value.general.rbp as u64, - rbx: value.general.rbx as u64, - rdx: value.general.rdx as u64, - rax: value.general.rax as u64, - rcx: value.general.rcx as u64, - rsp: value.general.rsp as u64, - rip: value.general.rip as u64, - rflag: value.general.rflags as u64, - }, - fs_base: value.general.fsbase as u64, - fp_regs: FpRegs::default(), - trap_information: TrapInformation { - cr2: x86_64::registers::control::Cr2::read_raw(), - id: value.trap_num as u64, - err: value.error_code as u64, - }, - gs_base: value.general.gsbase as u64, + /// Returns the number of CPUs. + pub fn num_cpus() -> u32 { + crate::arch::x86::cpu::num_cpus() } - } -} -impl Into for CpuContext { - fn into(self) -> UserContext { - UserContext { - trap_num: self.trap_information.id as usize, - error_code: self.trap_information.err as usize, - general: GeneralRegs { - rax: self.gp_regs.rax as usize, - rbx: self.gp_regs.rbx as usize, - rcx: self.gp_regs.rcx as usize, - rdx: self.gp_regs.rdx as usize, - rsi: self.gp_regs.rsi as usize, - rdi: self.gp_regs.rdi as usize, - rbp: self.gp_regs.rbp as usize, - rsp: self.gp_regs.rsp as usize, - r8: self.gp_regs.r8 as usize, - r9: self.gp_regs.r9 as usize, - r10: self.gp_regs.r10 as usize, - r11: self.gp_regs.r11 as usize, - r12: self.gp_regs.r12 as usize, - r13: self.gp_regs.r13 as usize, - r14: self.gp_regs.r14 as usize, - r15: self.gp_regs.r15 as usize, - rip: self.gp_regs.rip as usize, - rflags: self.gp_regs.rflag as usize, - fsbase: self.fs_base as usize, - gsbase: self.gs_base as usize, - }, + /// Returns the ID of this CPU. + pub fn this_cpu() -> u32 { + crate::arch::x86::cpu::this_cpu() } + } } - -/// The floating-point state of CPU. -#[derive(Clone, Copy, Debug)] -#[repr(C)] -pub struct FpRegs { - buf: FxsaveArea, - is_valid: bool, -} - -impl FpRegs { - /// Create a new instance. - /// - /// Note that a newly-created instance's floating point state is not - /// initialized, thus considered invalid (i.e., `self.is_valid() == false`). - pub fn new() -> Self { - // The buffer address requires 16bytes alignment. - Self { - buf: unsafe { MaybeUninit::uninit().assume_init() }, - is_valid: false, - } - } - - /// Save CPU's current floating pointer states into this instance. - pub fn save(&mut self) { - debug!("save fpregs"); - debug!("write addr = 0x{:x}", (&mut self.buf) as *mut _ as usize); - let layout = alloc::alloc::Layout::for_value(&self.buf); - debug!("layout: {:?}", layout); - let ptr = unsafe { alloc::alloc::alloc(layout) } as usize; - debug!("ptr = 0x{:x}", ptr); - unsafe { - _fxsave((&mut self.buf.data).as_mut_ptr() as *mut u8); - } - debug!("save fpregs success"); - self.is_valid = true; - } - - /// Save the floating state given by a slice of u8. - /// - /// After calling this method, the state of the instance will be considered valid. - /// - /// # Safety - /// - /// It is the caller's responsibility to ensure that the source slice contains - /// data that is in xsave/xrstor format. The slice must have a length of 512 bytes. - pub unsafe fn save_from_slice(&mut self, src: &[u8]) { - (&mut self.buf.data).copy_from_slice(src); - self.is_valid = true; - } - - /// Returns whether the instance can contains data in valid xsave/xrstor format. - pub fn is_valid(&self) -> bool { - self.is_valid - } - - /// Clear the state of the instance. - /// - /// This method does not reset the underlying buffer that contains the floating - /// point state; it only marks the buffer __invalid__. - pub fn clear(&mut self) { - self.is_valid = false; - } - - /// Restore CPU's CPU floating pointer states from this instance. - /// - /// Panic. If the current state is invalid, the method will panic. - pub fn restore(&self) { - debug!("restore fpregs"); - assert!(self.is_valid); - unsafe { _fxrstor((&self.buf.data).as_ptr()) }; - debug!("restore fpregs success"); - } - - /// Returns the floating point state as a slice. - /// - /// Note that the slice may contain garbage if `self.is_valid() == false`. - pub fn as_slice(&self) -> &[u8] { - &self.buf.data - } -} - -impl Default for FpRegs { - fn default() -> Self { - Self::new() - } -} - -#[repr(C, align(16))] -#[derive(Debug, Clone, Copy)] -struct FxsaveArea { - data: [u8; 512], // 512 bytes -} diff --git a/src/framework/jinux-frame/src/device/mod.rs b/src/framework/jinux-frame/src/device/mod.rs deleted file mode 100644 index 6f1be1fd..00000000 --- a/src/framework/jinux-frame/src/device/mod.rs +++ /dev/null @@ -1,11 +0,0 @@ -//! Device-related APIs. - -pub mod cmos; -pub mod io_port; -pub mod pci; -pub mod serial; - -/// Call after the memory allocator init -pub(crate) fn init() { - serial::callback_init(); -} diff --git a/src/framework/jinux-frame/src/driver/mod.rs b/src/framework/jinux-frame/src/driver/mod.rs deleted file mode 100644 index 3ed248c3..00000000 --- a/src/framework/jinux-frame/src/driver/mod.rs +++ /dev/null @@ -1,31 +0,0 @@ -//! Driver for APIC, PIC, PIT etc. -//! - -mod acpi; -mod ioapic; -mod pic; -mod timer; -mod xapic; - -pub(crate) use self::acpi::ACPI_TABLES; -pub(crate) use self::pic::ack as pic_ack; -pub(crate) use self::pic::allocate_irq as pic_allocate_irq; -pub(crate) use self::xapic::ack as xapic_ack; -pub(crate) use timer::{add_timeout_list, TimerCallback, TICK}; - -use log::info; - -pub(crate) fn init() { - acpi::init(); - if xapic::has_apic() { - ioapic::init(); - xapic::init(); - } else { - info!("No apic exists, using pic instead"); - unsafe { - pic::enable(); - } - } - timer::init(); - pic::init(); -} diff --git a/src/framework/jinux-frame/src/lib.rs b/src/framework/jinux-frame/src/lib.rs index 031ada1f..b6961b17 100644 --- a/src/framework/jinux-frame/src/lib.rs +++ b/src/framework/jinux-frame/src/lib.rs @@ -15,11 +15,9 @@ extern crate alloc; -mod boot; +pub mod arch; pub mod config; pub mod cpu; -pub mod device; -pub mod driver; mod error; pub mod logger; pub mod prelude; @@ -35,6 +33,7 @@ pub use self::error::Error; pub use self::prelude::Result; use alloc::vec::Vec; use core::{mem, panic::PanicInfo}; +#[cfg(feature = "x86_64")] pub use limine::{LimineFramebufferRequest, LimineModuleRequest}; use trap::{IrqCallbackHandle, IrqLine}; use trapframe::TrapFrame; @@ -42,18 +41,12 @@ pub use util::AlignExt; static mut IRQ_CALLBACK_LIST: Vec = Vec::new(); -pub use crate::console_print as print; -pub use crate::console_println as println; - pub fn init() { - device::serial::init(); + arch::before_all_init(); logger::init(); - boot::init(); vm::init(); trap::init(); - device::init(); - driver::init(); - enable_common_cpu_features(); + arch::after_all_init(); register_irq_common_callback(); invoke_c_init_funcs(); } @@ -81,27 +74,6 @@ fn invoke_c_init_funcs() { } } -fn enable_common_cpu_features() { - use x86_64::registers::{control::Cr4Flags, model_specific::EferFlags, xcontrol::XCr0Flags}; - let mut cr4 = x86_64::registers::control::Cr4::read(); - cr4 |= Cr4Flags::FSGSBASE | Cr4Flags::OSXSAVE | Cr4Flags::OSFXSR | Cr4Flags::OSXMMEXCPT_ENABLE; - unsafe { - x86_64::registers::control::Cr4::write(cr4); - } - - let mut xcr0 = x86_64::registers::xcontrol::XCr0::read(); - xcr0 |= XCr0Flags::AVX | XCr0Flags::SSE; - unsafe { - x86_64::registers::xcontrol::XCr0::write(xcr0); - } - - unsafe { - // enable non-executable page protection - x86_64::registers::model_specific::Efer::update(|efer| { - *efer |= EferFlags::NO_EXECUTE_ENABLE; - }); - } -} fn general_handler(trap_frame: &TrapFrame) { // info!("general handler"); // println!("{:#x?}", trap_frame); @@ -126,14 +98,14 @@ where T: Fn(), { fn run(&self) { - console_print!("{}...\n", core::any::type_name::()); + print!("{}...\n", core::any::type_name::()); self(); - console_println!("[ok]"); + println!("[ok]"); } } pub fn test_runner(tests: &[&dyn Testable]) { - console_println!("Running {} tests", tests.len()); + println!("Running {} tests", tests.len()); for test in tests { test.run(); } @@ -141,8 +113,8 @@ pub fn test_runner(tests: &[&dyn Testable]) { } pub fn test_panic_handler(info: &PanicInfo) -> ! { - console_println!("[failed]"); - console_println!("Error: {}", info); + println!("[failed]"); + println!("Error: {}", info); exit_qemu(QemuExitCode::Failed); } diff --git a/src/framework/jinux-frame/src/sync/rcu/monitor.rs b/src/framework/jinux-frame/src/sync/rcu/monitor.rs index db016d63..d0c38f04 100644 --- a/src/framework/jinux-frame/src/sync/rcu/monitor.rs +++ b/src/framework/jinux-frame/src/sync/rcu/monitor.rs @@ -4,7 +4,8 @@ use core::sync::atomic::{ Ordering::{Acquire, Relaxed, Release}, }; -use crate::cpu; +#[cfg(feature = "x86_64")] +use crate::arch::x86::cpu; use crate::prelude::*; use crate::sync::AtomicBits; use crate::sync::SpinLock; diff --git a/src/framework/jinux-frame/src/timer.rs b/src/framework/jinux-frame/src/timer.rs index 67b45709..f2b25e69 100644 --- a/src/framework/jinux-frame/src/timer.rs +++ b/src/framework/jinux-frame/src/timer.rs @@ -1,10 +1,8 @@ //! Timer. -use crate::{ - config::TIMER_FREQ, - driver::{TimerCallback, TICK}, - prelude::*, -}; +#[cfg(feature = "x86_64")] +use crate::arch::x86::timer::{add_timeout_list, TimerCallback, TICK}; +use crate::{config::TIMER_FREQ, prelude::*}; use core::time::Duration; use spin::Mutex; @@ -69,11 +67,7 @@ impl Timer { lock.start_tick = TICK; lock.timeout_tick = TICK + tick_count; } - lock.timer_callback = Some(crate::driver::add_timeout_list( - tick_count, - self.clone(), - timer_callback, - )); + lock.timer_callback = Some(add_timeout_list(tick_count, self.clone(), timer_callback)); } /// Returns the remaining timeout value. diff --git a/src/framework/jinux-frame/src/trap/handler.rs b/src/framework/jinux-frame/src/trap/handler.rs index 9342a44a..9c209fb5 100644 --- a/src/framework/jinux-frame/src/trap/handler.rs +++ b/src/framework/jinux-frame/src/trap/handler.rs @@ -17,8 +17,7 @@ pub(crate) fn call_irq_callback_functions(f: &mut TrapFrame) { callback_function.call(f); } if f.trap_num >= 0x20 { - crate::driver::xapic_ack(); - crate::driver::pic_ack(); + crate::arch::interrupts_ack(); } } diff --git a/src/framework/jinux-frame/src/user.rs b/src/framework/jinux-frame/src/user.rs index 81a163d0..dbfbcc7c 100644 --- a/src/framework/jinux-frame/src/user.rs +++ b/src/framework/jinux-frame/src/user.rs @@ -1,13 +1,13 @@ //! User space. -use crate::trap::call_irq_callback_functions; -use log::debug; -use trapframe::{TrapFrame, UserContext}; -use x86_64::registers::rflags::RFlags; -use x86_64::registers::segmentation::Segment64; -use x86_64::registers::segmentation::FS; +use trapframe::UserContext; + +cfg_if::cfg_if! { + if #[cfg(feature="x86_64")]{ + use crate::arch::x86::cpu::CpuContext; + } +} -use crate::cpu::CpuContext; use crate::prelude::*; use crate::task::Task; use crate::vm::VmSpace; @@ -55,6 +55,20 @@ impl UserSpace { } } +/// Specific architectures need to implement this trait so that UserMode tasks can be executed +pub trait UserModeExecute { + /// Starts executing in the user mode. Make sure current task is the task in `UserMode`. + /// + /// The method returns for one of three possible reasons indicated by `UserEvent`. + /// 1. The user invokes a system call; + /// 2. The user triggers an exception; + /// 3. The user triggers a fault. + /// + /// After handling the user event and updating the user-mode CPU context, + /// this method can be invoked again to go back to the user space. + fn execute(&mut self) -> UserEvent; +} + /// Code execution in the user mode. /// /// This type enables executing the code in user space from a task in the kernel @@ -77,10 +91,10 @@ impl UserSpace { /// ``` pub struct UserMode<'a> { current: Arc, - user_space: &'a Arc, - context: CpuContext, - user_context: UserContext, - executed: bool, + pub(crate) user_space: &'a Arc, + pub(crate) context: CpuContext, + pub(crate) user_context: UserContext, + pub(crate) executed: bool, } // An instance of `UserMode` is bound to the current task. So it cannot be @@ -97,95 +111,6 @@ impl<'a> UserMode<'a> { } } - /// Starts executing in the user mode. Make sure current task is the task in `UserMode`. - /// - /// The method returns for one of three possible reasons indicated by `UserEvent`. - /// 1. The user invokes a system call; - /// 2. The user triggers an exception; - /// 3. The user triggers a fault. - /// - /// After handling the user event and updating the user-mode CPU context, - /// this method can be invoked again to go back to the user space. - pub fn execute(&mut self) -> UserEvent { - unsafe { - self.user_space.vm_space().activate(); - } - if !self.executed { - self.context = self.user_space.cpu_ctx; - if self.context.gp_regs.rflag == 0 { - self.context.gp_regs.rflag = (RFlags::INTERRUPT_FLAG | RFlags::ID).bits() | 0x2; - } - // write fsbase - unsafe { - FS::write_base(x86_64::VirtAddr::new(self.user_space.cpu_ctx.fs_base)); - } - let fp_regs = self.user_space.cpu_ctx.fp_regs; - if fp_regs.is_valid() { - fp_regs.restore(); - } - self.executed = true; - } else { - // write fsbase - if FS::read_base().as_u64() != self.context.fs_base { - debug!("write fsbase: 0x{:x}", self.context.fs_base); - unsafe { - FS::write_base(x86_64::VirtAddr::new(self.context.fs_base)); - } - } - - // write fp_regs - // let fp_regs = self.context.fp_regs; - // if fp_regs.is_valid() { - // fp_regs.restore(); - // } - } - self.user_context = self.context.into(); - self.user_context.run(); - let mut trap_frame; - while self.user_context.trap_num >= 0x20 && self.user_context.trap_num < 0x100 { - trap_frame = TrapFrame { - rax: self.user_context.general.rax, - rbx: self.user_context.general.rbx, - rcx: self.user_context.general.rcx, - rdx: self.user_context.general.rdx, - rsi: self.user_context.general.rsi, - rdi: self.user_context.general.rdi, - rbp: self.user_context.general.rbp, - rsp: self.user_context.general.rsp, - r8: self.user_context.general.r8, - r9: self.user_context.general.r9, - r10: self.user_context.general.r10, - r11: self.user_context.general.r11, - r12: self.user_context.general.r12, - r13: self.user_context.general.r13, - r14: self.user_context.general.r14, - r15: self.user_context.general.r15, - _pad: 0, - trap_num: self.user_context.trap_num, - error_code: self.user_context.error_code, - rip: self.user_context.general.rip, - cs: 0, - rflags: self.user_context.general.rflags, - }; - call_irq_callback_functions(&mut trap_frame); - self.user_context.run(); - } - x86_64::instructions::interrupts::enable(); - self.context = CpuContext::from(self.user_context); - self.context.fs_base = FS::read_base().as_u64(); - if self.user_context.trap_num != 0x100 { - // self.context.fp_regs.save(); - UserEvent::Exception - } else { - // self.context.fp_regs.save(); - // debug!("[kernel] syscall id:{}", self.context.gp_regs.rax); - // debug!("[kernel] rsp: 0x{:x}", self.context.gp_regs.rsp); - // debug!("[kernel] rcx: 0x{:x}", self.context.gp_regs.rcx); - // debug!("[kernel] rip: 0x{:x}", self.context.gp_regs.rip); - UserEvent::Syscall - } - } - /// Returns an immutable reference the user-mode CPU context. pub fn context(&self) -> &CpuContext { &self.context diff --git a/src/framework/jinux-frame/src/vm/frame_allocator.rs b/src/framework/jinux-frame/src/vm/frame_allocator.rs index 37450c21..fdd6b319 100644 --- a/src/framework/jinux-frame/src/vm/frame_allocator.rs +++ b/src/framework/jinux-frame/src/vm/frame_allocator.rs @@ -2,13 +2,12 @@ use core::ops::Range; use alloc::vec::Vec; use buddy_system_allocator::FrameAllocator; -use limine::{LimineMemmapEntry, LimineMemoryMapEntryType}; use log::{debug, info}; use spin::{Mutex, Once}; use crate::{config::PAGE_SIZE, vm::Paddr, AlignExt}; -use super::{frame::VmFrameFlags, VmFrame}; +use super::{frame::VmFrameFlags, MemoryRegions, MemoryRegionsType, VmFrame}; static FRAME_ALLOCATOR: Once> = Once::new(); @@ -57,15 +56,16 @@ pub fn alloc_with_paddr(paddr: Paddr) -> Option { /// Check if the physical address in range is valid fn is_paddr_valid(range: Range) -> bool { // special area in x86 + #[cfg(feature = "x86_64")] if range.start >= 0xFE00_0000 && range.end <= 0xFFFF_FFFF { return true; } for i in super::MEMORY_REGIONS.get().unwrap().iter() { match i.typ { - LimineMemoryMapEntryType::Usable => {} - LimineMemoryMapEntryType::Reserved => {} - LimineMemoryMapEntryType::Framebuffer => {} + MemoryRegionsType::Usable => {} + MemoryRegionsType::Reserved => {} + MemoryRegionsType::Framebuffer => {} _ => { continue; } @@ -93,10 +93,10 @@ pub(crate) unsafe fn dealloc(index: usize) { FRAME_ALLOCATOR.get().unwrap().lock().dealloc(index, 1); } -pub(crate) fn init(regions: &Vec<&LimineMemmapEntry>) { +pub(crate) fn init(regions: &Vec) { let mut allocator = FrameAllocator::<32>::new(); for region in regions.iter() { - if region.typ == LimineMemoryMapEntryType::Usable { + if region.typ == MemoryRegionsType::Usable { assert_eq!(region.base % PAGE_SIZE as u64, 0); assert_eq!(region.len % PAGE_SIZE as u64, 0); let start = region.base as usize / PAGE_SIZE; diff --git a/src/framework/jinux-frame/src/vm/mod.rs b/src/framework/jinux-frame/src/vm/mod.rs index 02c1d19c..0d2c1efc 100644 --- a/src/framework/jinux-frame/src/vm/mod.rs +++ b/src/framework/jinux-frame/src/vm/mod.rs @@ -27,10 +27,36 @@ pub use self::{ }; use alloc::vec::Vec; -use limine::{LimineMemmapRequest, LimineMemoryMapEntryType}; -use log::debug; use spin::Once; +#[derive(Clone, Copy)] +pub struct MemoryRegions { + pub base: u64, + pub len: u64, + pub typ: MemoryRegionsType, +} + +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +/// Copy from limine boot protocol +pub enum MemoryRegionsType { + Usable = 0, + Reserved = 1, + AcpiReclaimable = 2, + AcpiNvs = 3, + BadMemory = 4, + BootloaderReclaimable = 5, + /// The kernel and modules loaded are not marked as usable memory. They are + /// marked as Kernel/Modules. The entries are guaranteed to be sorted by base + /// address, lowest to highest. Usable and bootloader reclaimable entries are + /// guaranteed to be 4096 byte aligned for both base and length. Usable and + /// bootloader reclaimable entries are guaranteed not to overlap with any + /// other entry. To the contrary, all non-usable entries (including kernel/modules) + /// are not guaranteed any alignment, nor is it guaranteed that they do not + /// overlap other entries. + KernelAndModules = 6, + Framebuffer = 7, +} + /// Convert physical address to virtual address using offset, only available inside jinux-frame pub(crate) fn paddr_to_vaddr(pa: usize) -> usize { pa + PHYS_OFFSET @@ -50,28 +76,23 @@ pub const fn is_page_aligned(p: usize) -> bool { } /// Only available inside jinux-frame -pub(crate) static MEMORY_REGIONS: Once> = Once::new(); -static MEMMAP_REQUEST: LimineMemmapRequest = LimineMemmapRequest::new(0); +pub(crate) static MEMORY_REGIONS: Once<&Vec> = Once::new(); -pub static FRAMEBUFFER_REGIONS: Once> = Once::new(); +pub static FRAMEBUFFER_REGIONS: Once> = Once::new(); pub(crate) fn init() { heap_allocator::init(); - let mut memory_regions = Vec::new(); + #[cfg(feature = "x86_64")] + let memory_regions = crate::arch::x86::mm::get_memory_regions(); + let mut framebuffer_regions = Vec::new(); - let response = MEMMAP_REQUEST - .get_response() - .get() - .expect("Not found memory region information"); - for i in response.memmap() { - debug!("Found memory region:{:x?}", **i); - memory_regions.push(&**i); - if i.typ == LimineMemoryMapEntryType::Framebuffer { - framebuffer_regions.push(&**i); + for i in memory_regions.iter() { + if i.typ == MemoryRegionsType::Framebuffer { + framebuffer_regions.push(i.clone()); } } - frame_allocator::init(&memory_regions); + frame_allocator::init(memory_regions); page_table::init(); MEMORY_REGIONS.call_once(|| memory_regions); diff --git a/src/framework/jinux-frame/src/vm/page_table.rs b/src/framework/jinux-frame/src/vm/page_table.rs index 5c918cd1..03652ccd 100644 --- a/src/framework/jinux-frame/src/vm/page_table.rs +++ b/src/framework/jinux-frame/src/vm/page_table.rs @@ -219,10 +219,11 @@ fn next_table_or_create<'a>( /// translate a virtual address to physical address which cannot use offset to get physical address pub fn vaddr_to_paddr(virtual_address: Vaddr) -> Option { - let (cr3, _) = x86_64::registers::control::Cr3::read(); - let cr3 = cr3.start_address().as_u64() as usize; + #[cfg(feature = "x86_64")] + let (page_directory_base, _) = x86_64::registers::control::Cr3::read(); - let p4 = table_of(cr3)?; + let page_directory_base = page_directory_base.start_address().as_u64() as usize; + let p4 = table_of(page_directory_base)?; let pte = p4[p4_index(virtual_address)]; let p3 = table_of(pte.paddr())?; @@ -238,10 +239,11 @@ pub fn vaddr_to_paddr(virtual_address: Vaddr) -> Option { } pub(crate) fn init() { - let (cr3, _) = x86_64::registers::control::Cr3::read(); - let cr3 = cr3.start_address().as_u64() as usize; + #[cfg(feature = "x86_64")] + let (page_directory_base, _) = x86_64::registers::control::Cr3::read(); + let page_directory_base = page_directory_base.start_address().as_u64() as usize; - let p4 = table_of(cr3).unwrap(); + let p4 = table_of(page_directory_base).unwrap(); // Cancel mapping in lowest addresses. p4[0].0 = 0; let mut map_pte = ALL_MAPPED_PTE.lock(); diff --git a/src/framework/jinux-frame/src/vm/space.rs b/src/framework/jinux-frame/src/vm/space.rs index f6889d0a..b7bbcc93 100644 --- a/src/framework/jinux-frame/src/vm/space.rs +++ b/src/framework/jinux-frame/src/vm/space.rs @@ -3,7 +3,6 @@ use crate::vm::page_table::PageTableFlags; use bitflags::bitflags; use core::ops::Range; use spin::Mutex; -use x86_64::structures::paging::PhysFrame; use super::VmFrameVec; use super::{is_page_aligned, Vaddr}; @@ -38,11 +37,9 @@ impl VmSpace { } /// Activate the page table, load root physical address to cr3 pub unsafe fn activate(&self) { - x86_64::registers::control::Cr3::write( - PhysFrame::from_start_address(x86_64::PhysAddr::new( - self.memory_set.lock().pt.root_pa as u64, - )) - .unwrap(), + #[cfg(feature = "x86_64")] + crate::arch::x86::mm::activate_page_table( + self.memory_set.lock().pt.root_pa, x86_64::registers::control::Cr3Flags::PAGE_LEVEL_CACHE_DISABLE, ); } @@ -94,6 +91,7 @@ impl VmSpace { /// clear all mappings pub fn clear(&self) { self.memory_set.lock().clear(); + #[cfg(feature = "x86_64")] x86_64::instructions::tlb::flush_all(); } diff --git a/src/services/comps/pci/src/util.rs b/src/services/comps/pci/src/util.rs index 104de554..9192d97d 100644 --- a/src/services/comps/pci/src/util.rs +++ b/src/services/comps/pci/src/util.rs @@ -65,9 +65,11 @@ impl CSpaceAccessMethod { ); match self { CSpaceAccessMethod::IO => { - jinux_frame::device::pci::PCI_ADDRESS_PORT + jinux_frame::arch::x86::device::pci::PCI_ADDRESS_PORT .write(loc.encode() | ((offset as u32) & 0b11111100)); - jinux_frame::device::pci::PCI_DATA_PORT.read().to_le() + jinux_frame::arch::x86::device::pci::PCI_DATA_PORT + .read() + .to_le() } //MemoryMapped(ptr) => { // // FIXME: Clarify whether the rules for GEP/GEPi forbid using regular .offset() here. // ::core::intrinsics::volatile_load(::core::intrinsics::arith_offset(ptr, offset as usize)) @@ -107,9 +109,9 @@ impl CSpaceAccessMethod { ); match self { CSpaceAccessMethod::IO => { - jinux_frame::device::pci::PCI_ADDRESS_PORT + jinux_frame::arch::x86::device::pci::PCI_ADDRESS_PORT .write(loc.encode() | (offset as u32 & 0b11111100)); - jinux_frame::device::pci::PCI_DATA_PORT.write(val.to_le()) + jinux_frame::arch::x86::device::pci::PCI_DATA_PORT.write(val.to_le()) } //MemoryMapped(ptr) => { // // FIXME: Clarify whether the rules for GEP/GEPi forbid using regular .offset() here. // ::core::intrinsics::volatile_load(::core::intrinsics::arith_offset(ptr, offset as usize)) diff --git a/src/services/comps/time/src/rtc.rs b/src/services/comps/time/src/rtc.rs index a9ddff3a..5e70e034 100644 --- a/src/services/comps/time/src/rtc.rs +++ b/src/services/comps/time/src/rtc.rs @@ -5,7 +5,7 @@ use spin::Mutex; use crate::SystemTime; -use jinux_frame::device::cmos::{get_century, CMOS_ADDRESS, CMOS_DATA}; +use jinux_frame::arch::x86::device::cmos::{get_century, CMOS_ADDRESS, CMOS_DATA}; pub(crate) static CENTURY_REGISTER: AtomicU8 = AtomicU8::new(0); diff --git a/src/services/libs/jinux-std/src/driver/tty.rs b/src/services/libs/jinux-std/src/driver/tty.rs index d339dfb6..1b177ab6 100644 --- a/src/services/libs/jinux-std/src/driver/tty.rs +++ b/src/services/libs/jinux-std/src/driver/tty.rs @@ -1,4 +1,4 @@ -pub use jinux_frame::device::serial::register_serial_input_callback; +pub use jinux_frame::arch::x86::device::serial::register_serial_input_callback; use crate::{ prelude::*, diff --git a/src/services/libs/jinux-std/src/thread/task.rs b/src/services/libs/jinux-std/src/thread/task.rs index 2bf34a38..3251ea36 100644 --- a/src/services/libs/jinux-std/src/thread/task.rs +++ b/src/services/libs/jinux-std/src/thread/task.rs @@ -1,7 +1,7 @@ use jinux_frame::{ cpu::CpuContext, task::Task, - user::{UserEvent, UserMode, UserSpace}, + user::{UserEvent, UserMode, UserModeExecute, UserSpace}, }; use crate::{