Extract x86-specific code into arch/x86

This commit is contained in:
Yuke Peng 2023-03-25 02:27:09 -07:00 committed by Tate, Hongliang Tian
parent b01987c721
commit d0268309ff
38 changed files with 691 additions and 572 deletions

View File

@ -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"]

View File

@ -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();
}

View File

@ -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{}",

View File

@ -0,0 +1,6 @@
mod limine;
/// init bootloader
pub fn init() {
limine::init();
}

View File

@ -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<UserContext> 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<UserContext> 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
}

View File

@ -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;

View File

@ -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;

View File

@ -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<u8> {
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)+)?))
}
}

View File

@ -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<Mutex<IoApicWrapper>> = Once::new();
pub static IO_APIC: Once<Mutex<IoApicWrapper>> = Once::new();
pub fn init() {
let c = ACPI_TABLES.get().unwrap().lock();

View File

@ -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;

View File

@ -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<IrqAllocateHandle> {
pub fn allocate_irq(index: u8) -> Option<IrqAllocateHandle> {
if index >= 16 {
return None;
}
@ -66,7 +64,7 @@ pub(crate) fn allocate_irq(index: u8) -> Option<IrqAllocateHandle> {
/// 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);

View File

@ -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<Mutex<Xapic>> = Once::new();
pub static XAPIC_INSTANCE: Once<Mutex<Xapic>> = 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()));

View File

@ -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<Vec<MemoryRegions>> = 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<LimineMemoryMapEntryType> 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<MemoryRegions> {
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()
}

View File

@ -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;
});
}
}

View File

@ -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);

View File

@ -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<Hpet> = Once::new();
const OFFSET_ID_REGISTER: usize = 0x000;

View File

@ -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<IrqAllocateHandle> = 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<Mutex<BinaryHeap<Arc<TimerCallback>>>> = Once::new();

View File

@ -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;

View File

@ -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();
}

View File

@ -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<UserContext> 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<UserContext> 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
}

View File

@ -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();
}

View File

@ -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();
}

View File

@ -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<IrqCallbackHandle> = 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::<T>());
print!("{}...\n", core::any::type_name::<T>());
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);
}

View File

@ -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;

View File

@ -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.

View File

@ -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();
}
}

View File

@ -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<Task>,
user_space: &'a Arc<UserSpace>,
context: CpuContext,
user_context: UserContext,
executed: bool,
pub(crate) user_space: &'a Arc<UserSpace>,
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

View File

@ -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<Mutex<FrameAllocator>> = Once::new();
@ -57,15 +56,16 @@ pub fn alloc_with_paddr(paddr: Paddr) -> Option<VmFrame> {
/// Check if the physical address in range is valid
fn is_paddr_valid(range: Range<usize>) -> 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<MemoryRegions>) {
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;

View File

@ -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<Vec<&limine::LimineMemmapEntry>> = Once::new();
static MEMMAP_REQUEST: LimineMemmapRequest = LimineMemmapRequest::new(0);
pub(crate) static MEMORY_REGIONS: Once<&Vec<MemoryRegions>> = Once::new();
pub static FRAMEBUFFER_REGIONS: Once<Vec<&limine::LimineMemmapEntry>> = Once::new();
pub static FRAMEBUFFER_REGIONS: Once<Vec<MemoryRegions>> = 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);

View File

@ -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<Paddr> {
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<Paddr> {
}
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();

View File

@ -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();
}

View File

@ -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))

View File

@ -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);

View File

@ -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::*,

View File

@ -1,7 +1,7 @@
use jinux_frame::{
cpu::CpuContext,
task::Task,
user::{UserEvent, UserMode, UserSpace},
user::{UserEvent, UserMode, UserModeExecute, UserSpace},
};
use crate::{