mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-08 21:06:48 +00:00
Extract x86-specific code into arch/x86
This commit is contained in:
parent
b01987c721
commit
d0268309ff
@ -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"]
|
||||
|
20
src/framework/jinux-frame/src/arch/mod.rs
Normal file
20
src/framework/jinux-frame/src/arch/mod.rs
Normal 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();
|
||||
}
|
@ -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{}",
|
6
src/framework/jinux-frame/src/arch/x86/boot/mod.rs
Normal file
6
src/framework/jinux-frame/src/arch/x86/boot/mod.rs
Normal file
@ -0,0 +1,6 @@
|
||||
mod limine;
|
||||
|
||||
/// init bootloader
|
||||
pub fn init() {
|
||||
limine::init();
|
||||
}
|
254
src/framework/jinux-frame/src/arch/x86/cpu.rs
Normal file
254
src/framework/jinux-frame/src/arch/x86/cpu.rs
Normal 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
|
||||
}
|
@ -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;
|
||||
|
7
src/framework/jinux-frame/src/arch/x86/device/mod.rs
Normal file
7
src/framework/jinux-frame/src/arch/x86/device/mod.rs
Normal 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;
|
@ -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)+)?))
|
||||
}
|
||||
}
|
@ -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();
|
9
src/framework/jinux-frame/src/arch/x86/kernel/mod.rs
Normal file
9
src/framework/jinux-frame/src/arch/x86/kernel/mod.rs
Normal 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;
|
@ -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);
|
@ -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()));
|
57
src/framework/jinux-frame/src/arch/x86/mm/mod.rs
Normal file
57
src/framework/jinux-frame/src/arch/x86/mm/mod.rs
Normal 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()
|
||||
}
|
169
src/framework/jinux-frame/src/arch/x86/mod.rs
Normal file
169
src/framework/jinux-frame/src/arch/x86/mod.rs
Normal 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;
|
||||
});
|
||||
}
|
||||
}
|
@ -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);
|
||||
|
@ -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;
|
@ -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();
|
@ -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;
|
||||
|
@ -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();
|
||||
}
|
@ -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
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
@ -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();
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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.
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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))
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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::*,
|
||||
|
@ -1,7 +1,7 @@
|
||||
use jinux_frame::{
|
||||
cpu::CpuContext,
|
||||
task::Task,
|
||||
user::{UserEvent, UserMode, UserSpace},
|
||||
user::{UserEvent, UserMode, UserModeExecute, UserSpace},
|
||||
};
|
||||
|
||||
use crate::{
|
||||
|
Loading…
x
Reference in New Issue
Block a user