mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-09 13:26: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]
|
[dependencies]
|
||||||
bitflags = "1.3"
|
bitflags = "1.3"
|
||||||
x86_64 = "0.14.2"
|
cfg-if = "1.0"
|
||||||
x86 = "0.52.0"
|
|
||||||
spin = "0.9.4"
|
spin = "0.9.4"
|
||||||
volatile = { version = "0.4.5", features = ["unstable"] }
|
volatile = { version = "0.4.5", features = ["unstable"] }
|
||||||
buddy_system_allocator = "0.9.0"
|
buddy_system_allocator = "0.9.0"
|
||||||
pod = { path = "../pod" }
|
pod = { path = "../pod" }
|
||||||
acpi = "4.1.1"
|
|
||||||
intrusive-collections = "0.9.5"
|
intrusive-collections = "0.9.5"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
limine = { version = "0.1.10", features = ["into-uuid"] }
|
|
||||||
lazy_static = { version = "1.0", features = ["spin_no_std"] }
|
lazy_static = { version = "1.0", features = ["spin_no_std"] }
|
||||||
trapframe = { git = "https://github.com/sdww0/trapframe-rs", rev = "13e1065" }
|
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]
|
[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 limine::{LimineBootInfoRequest, LimineHhdmRequest, LimineStackSizeRequest};
|
||||||
use log::info;
|
use log::info;
|
||||||
|
|
||||||
pub(crate) fn init() {
|
pub fn init() {
|
||||||
if let Some(bootinfo) = BOOTLOADER_INFO_REQUEST.get_response().get() {
|
if let Some(bootinfo) = BOOTLOADER_INFO_REQUEST.get_response().get() {
|
||||||
info!(
|
info!(
|
||||||
"booted by {} v{}",
|
"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 acpi::{fadt::Fadt, sdt::Signature};
|
||||||
use x86_64::instructions::port::{ReadOnlyAccess, WriteOnlyAccess};
|
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;
|
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.
|
//! 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 alloc::{sync::Arc, vec::Vec};
|
||||||
use core::fmt::{self, Write};
|
|
||||||
use log::debug;
|
use log::debug;
|
||||||
use spin::{Mutex, Once};
|
use spin::{Mutex, Once};
|
||||||
|
|
||||||
use crate::{driver::pic_allocate_irq, trap::IrqAllocateHandle};
|
|
||||||
use trapframe::TrapFrame;
|
use trapframe::TrapFrame;
|
||||||
|
|
||||||
bitflags::bitflags! {
|
bitflags::bitflags! {
|
||||||
@ -56,7 +54,7 @@ pub fn register_serial_input_callback(f: impl Fn(u8) + Send + Sync + 'static) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn callback_init() {
|
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);
|
irq.on_active(handle_serial_input);
|
||||||
CONSOLE_IRQ_CALLBACK.call_once(|| Mutex::new(irq));
|
CONSOLE_IRQ_CALLBACK.call_once(|| Mutex::new(irq));
|
||||||
}
|
}
|
||||||
@ -115,32 +113,3 @@ pub fn receive_char() -> Option<u8> {
|
|||||||
None
|
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;
|
use super::acpi::ACPI_TABLES;
|
||||||
|
|
||||||
pub(crate) struct IoApicWrapper {
|
pub struct IoApicWrapper {
|
||||||
io_apic: IoApic,
|
io_apic: IoApic,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -14,23 +14,23 @@ impl IoApicWrapper {
|
|||||||
Self { io_apic }
|
Self { io_apic }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn disable_all(&mut self) {
|
pub fn disable_all(&mut self) {
|
||||||
self.io_apic.disable_all()
|
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);
|
self.io_apic.enable(irq, cpunum);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn id(&mut self) -> u8 {
|
pub fn id(&mut self) -> u8 {
|
||||||
self.io_apic.id()
|
self.io_apic.id()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn version(&mut self) -> u8 {
|
pub fn version(&mut self) -> u8 {
|
||||||
self.io_apic.version()
|
self.io_apic.version()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn supported_interrupts(&mut self) -> u8 {
|
pub fn supported_interrupts(&mut self) -> u8 {
|
||||||
self.io_apic.supported_interrupts()
|
self.io_apic.supported_interrupts()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -40,7 +40,7 @@ unsafe impl Send for IoApicWrapper {}
|
|||||||
/// # Safety: The pointer inside the IoApic will not change
|
/// # Safety: The pointer inside the IoApic will not change
|
||||||
unsafe impl Sync for IoApicWrapper {}
|
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() {
|
pub fn init() {
|
||||||
let c = ACPI_TABLES.get().unwrap().lock();
|
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::allocate_target_irq;
|
||||||
use crate::trap::IrqAllocateHandle;
|
use crate::trap::IrqAllocateHandle;
|
||||||
|
|
||||||
@ -32,7 +32,7 @@ static MASK_SLAVE: AtomicU8 = AtomicU8::new(0x00);
|
|||||||
static CHANGE_LOCK: AtomicBool = AtomicBool::new(false);
|
static CHANGE_LOCK: AtomicBool = AtomicBool::new(false);
|
||||||
|
|
||||||
/// init the PIC device
|
/// init the PIC device
|
||||||
pub(crate) fn init() {
|
pub fn init() {
|
||||||
if CHANGE_LOCK.load(Relaxed) {
|
if CHANGE_LOCK.load(Relaxed) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -42,13 +42,11 @@ pub(crate) fn init() {
|
|||||||
"PIC init, master mask:{:x} slave_mask:{:x}",
|
"PIC init, master mask:{:x} slave_mask:{:x}",
|
||||||
master_mask, slave_mask
|
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
|
/// 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 {
|
if index >= 16 {
|
||||||
return None;
|
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
|
/// enable the PIC device, this function will permanent enable all the interrupts
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) unsafe fn enable() {
|
pub fn enable() {
|
||||||
CHANGE_LOCK.store(true, Relaxed);
|
CHANGE_LOCK.store(true, Relaxed);
|
||||||
set_mask(0, 0);
|
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
|
/// disable the PIC device, this function will permanent disable all the interrupts
|
||||||
/// the interrupts mask may not exists after calling init function
|
/// the interrupts mask may not exists after calling init function
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) unsafe fn disable() {
|
pub fn disable() {
|
||||||
CHANGE_LOCK.store(true, Relaxed);
|
CHANGE_LOCK.store(true, Relaxed);
|
||||||
set_mask(0xFF, 0xFF);
|
set_mask(0xFF, 0xFF);
|
||||||
}
|
}
|
||||||
@ -82,23 +80,19 @@ pub(crate) unsafe fn disable() {
|
|||||||
/// enable the PIC device, this function will allow all the interrupts
|
/// enable the PIC device, this function will allow all the interrupts
|
||||||
/// the interrupts mask may not exists after calling init function
|
/// the interrupts mask may not exists after calling init function
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn enable_temp() {
|
pub fn enable_temp() {
|
||||||
unsafe {
|
|
||||||
set_mask(0, 0);
|
set_mask(0, 0);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// disable the PIC device, this function will disable all the interrupts
|
/// disable the PIC device, this function will disable all the interrupts
|
||||||
/// the interrupts mask may not exists after calling init function
|
/// the interrupts mask may not exists after calling init function
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn disable_temp() {
|
pub fn disable_temp() {
|
||||||
unsafe {
|
|
||||||
set_mask(0xFF, 0xFF);
|
set_mask(0xFF, 0xFF);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[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
|
// Start initialization
|
||||||
MASTER_CMD.write(0x11);
|
MASTER_CMD.write(0x11);
|
||||||
SLAVE_CMD.write(0x11);
|
SLAVE_CMD.write(0x11);
|
@ -3,13 +3,13 @@ use log::debug;
|
|||||||
use spin::{Mutex, Once};
|
use spin::{Mutex, Once};
|
||||||
use x86::apic::xapic;
|
use x86::apic::xapic;
|
||||||
|
|
||||||
pub(crate) const IA32_APIC_BASE_MSR: u32 = 0x1B;
|
const IA32_APIC_BASE_MSR: u32 = 0x1B;
|
||||||
pub(crate) const IA32_APIC_BASE_MSR_BSP: u32 = 0x100; // Processor is a BSP
|
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_ENABLE: u64 = 0x800;
|
||||||
|
|
||||||
const APIC_LVT_MASK_BITS: u32 = 1 << 16;
|
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)]
|
#[derive(Debug)]
|
||||||
pub struct Xapic {
|
pub struct Xapic {
|
||||||
@ -25,26 +25,26 @@ impl Xapic {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Read a register from the MMIO region.
|
/// 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);
|
assert!(offset as usize % 4 == 0);
|
||||||
let index = offset as usize / 4;
|
let index = offset as usize / 4;
|
||||||
unsafe { core::ptr::read_volatile(&self.mmio_region[index]) }
|
unsafe { core::ptr::read_volatile(&self.mmio_region[index]) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// write a register in the MMIO region.
|
/// 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);
|
assert!(offset as usize % 4 == 0);
|
||||||
let index = offset as usize / 4;
|
let index = offset as usize / 4;
|
||||||
unsafe { core::ptr::write_volatile(&mut self.mmio_region[index], val) }
|
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) };
|
let value = unsafe { core::arch::x86_64::__cpuid(1) };
|
||||||
value.edx & 0x100 != 0
|
value.edx & 0x100 != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn init() {
|
pub fn init() {
|
||||||
super::pic::disable_temp();
|
super::pic::disable_temp();
|
||||||
|
|
||||||
let mut apic = Xapic::new(vm::paddr_to_vaddr(get_apic_base_address()));
|
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 log::info;
|
||||||
use trapframe::TrapFrame;
|
use trapframe::TrapFrame;
|
||||||
|
|
||||||
use crate::{
|
use crate::arch::x86::kernel::{pic, xapic::XAPIC_INSTANCE};
|
||||||
config,
|
use crate::config;
|
||||||
driver::{pic, timer, xapic::XAPIC_INSTANCE},
|
|
||||||
};
|
|
||||||
use x86::apic::xapic;
|
use x86::apic::xapic;
|
||||||
|
|
||||||
pub fn init() {
|
pub fn init() {
|
||||||
let mut apic_lock = XAPIC_INSTANCE.get().unwrap().lock();
|
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);
|
let a = handle.on_active(init_function);
|
||||||
// divide by 64
|
// divide by 64
|
||||||
apic_lock.write(xapic::XAPIC_TIMER_DIV_CONF, 0b1001);
|
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
|
// init pic for now, disable it after the APIC Timer init is done
|
||||||
pic::enable_temp();
|
pic::enable_temp();
|
||||||
timer::pit::init();
|
super::pit::init();
|
||||||
|
|
||||||
static mut IS_FINISH: bool = false;
|
static mut IS_FINISH: bool = false;
|
||||||
// wait until it is finish
|
// 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_TIMER_INIT_COUNT, ticks as u32);
|
||||||
apic_lock.write(
|
apic_lock.write(
|
||||||
xapic::XAPIC_LVT_TIMER,
|
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);
|
apic_lock.write(xapic::XAPIC_TIMER_DIV_CONF, 0b1001);
|
||||||
|
|
@ -7,7 +7,7 @@ use volatile::{
|
|||||||
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();
|
static HPET_INSTANCE: Once<Hpet> = Once::new();
|
||||||
|
|
||||||
const OFFSET_ID_REGISTER: usize = 0x000;
|
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 spin::{Mutex, Once};
|
||||||
use trapframe::TrapFrame;
|
use trapframe::TrapFrame;
|
||||||
|
|
||||||
|
use crate::arch::x86::kernel;
|
||||||
use crate::trap::IrqAllocateHandle;
|
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;
|
pub static mut TICK: u64 = 0;
|
||||||
|
|
||||||
static TIMER_IRQ: Once<IrqAllocateHandle> = Once::new();
|
static TIMER_IRQ: Once<IrqAllocateHandle> = Once::new();
|
||||||
|
|
||||||
pub fn init() {
|
pub fn init() {
|
||||||
TIMEOUT_LIST.call_once(|| Mutex::new(BinaryHeap::new()));
|
TIMEOUT_LIST.call_once(|| Mutex::new(BinaryHeap::new()));
|
||||||
if super::xapic::has_apic() {
|
if kernel::xapic::has_apic() {
|
||||||
apic::init();
|
apic::init();
|
||||||
} else {
|
} else {
|
||||||
pit::init();
|
pit::init();
|
||||||
@ -47,7 +48,6 @@ fn timer_callback(trap_frame: &TrapFrame) {
|
|||||||
for callback in callbacks {
|
for callback in callbacks {
|
||||||
callback.callback.call((&callback,));
|
callback.callback.call((&callback,));
|
||||||
}
|
}
|
||||||
// crate::interrupt_ack();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static TIMEOUT_LIST: Once<Mutex<BinaryHeap<Arc<TimerCallback>>>> = Once::new();
|
static TIMEOUT_LIST: Once<Mutex<BinaryHeap<Arc<TimerCallback>>>> = Once::new();
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
use crate::config::TIMER_FREQ;
|
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;
|
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.
|
//! CPU.
|
||||||
|
|
||||||
use core::arch::x86_64::{_fxrstor, _fxsave};
|
cfg_if::cfg_if! {
|
||||||
use core::fmt::Debug;
|
if #[cfg(feature="x86_64")]{
|
||||||
use core::mem::MaybeUninit;
|
|
||||||
|
|
||||||
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;
|
/// Returns the number of CPUs.
|
||||||
use pod::Pod;
|
pub fn num_cpus() -> u32 {
|
||||||
|
crate::arch::x86::cpu::num_cpus()
|
||||||
/// 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) {
|
/// Returns the ID of this CPU.
|
||||||
self.gp_regs.rsp = rsp;
|
pub fn this_cpu() -> u32 {
|
||||||
|
crate::arch::x86::cpu::this_cpu()
|
||||||
}
|
}
|
||||||
|
|
||||||
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,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;
|
extern crate alloc;
|
||||||
|
|
||||||
mod boot;
|
pub mod arch;
|
||||||
pub mod config;
|
pub mod config;
|
||||||
pub mod cpu;
|
pub mod cpu;
|
||||||
pub mod device;
|
|
||||||
pub mod driver;
|
|
||||||
mod error;
|
mod error;
|
||||||
pub mod logger;
|
pub mod logger;
|
||||||
pub mod prelude;
|
pub mod prelude;
|
||||||
@ -35,6 +33,7 @@ pub use self::error::Error;
|
|||||||
pub use self::prelude::Result;
|
pub use self::prelude::Result;
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
use core::{mem, panic::PanicInfo};
|
use core::{mem, panic::PanicInfo};
|
||||||
|
#[cfg(feature = "x86_64")]
|
||||||
pub use limine::{LimineFramebufferRequest, LimineModuleRequest};
|
pub use limine::{LimineFramebufferRequest, LimineModuleRequest};
|
||||||
use trap::{IrqCallbackHandle, IrqLine};
|
use trap::{IrqCallbackHandle, IrqLine};
|
||||||
use trapframe::TrapFrame;
|
use trapframe::TrapFrame;
|
||||||
@ -42,18 +41,12 @@ pub use util::AlignExt;
|
|||||||
|
|
||||||
static mut IRQ_CALLBACK_LIST: Vec<IrqCallbackHandle> = Vec::new();
|
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() {
|
pub fn init() {
|
||||||
device::serial::init();
|
arch::before_all_init();
|
||||||
logger::init();
|
logger::init();
|
||||||
boot::init();
|
|
||||||
vm::init();
|
vm::init();
|
||||||
trap::init();
|
trap::init();
|
||||||
device::init();
|
arch::after_all_init();
|
||||||
driver::init();
|
|
||||||
enable_common_cpu_features();
|
|
||||||
register_irq_common_callback();
|
register_irq_common_callback();
|
||||||
invoke_c_init_funcs();
|
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) {
|
fn general_handler(trap_frame: &TrapFrame) {
|
||||||
// info!("general handler");
|
// info!("general handler");
|
||||||
// println!("{:#x?}", trap_frame);
|
// println!("{:#x?}", trap_frame);
|
||||||
@ -126,14 +98,14 @@ where
|
|||||||
T: Fn(),
|
T: Fn(),
|
||||||
{
|
{
|
||||||
fn run(&self) {
|
fn run(&self) {
|
||||||
console_print!("{}...\n", core::any::type_name::<T>());
|
print!("{}...\n", core::any::type_name::<T>());
|
||||||
self();
|
self();
|
||||||
console_println!("[ok]");
|
println!("[ok]");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn test_runner(tests: &[&dyn Testable]) {
|
pub fn test_runner(tests: &[&dyn Testable]) {
|
||||||
console_println!("Running {} tests", tests.len());
|
println!("Running {} tests", tests.len());
|
||||||
for test in tests {
|
for test in tests {
|
||||||
test.run();
|
test.run();
|
||||||
}
|
}
|
||||||
@ -141,8 +113,8 @@ pub fn test_runner(tests: &[&dyn Testable]) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn test_panic_handler(info: &PanicInfo) -> ! {
|
pub fn test_panic_handler(info: &PanicInfo) -> ! {
|
||||||
console_println!("[failed]");
|
println!("[failed]");
|
||||||
console_println!("Error: {}", info);
|
println!("Error: {}", info);
|
||||||
exit_qemu(QemuExitCode::Failed);
|
exit_qemu(QemuExitCode::Failed);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,7 +4,8 @@ use core::sync::atomic::{
|
|||||||
Ordering::{Acquire, Relaxed, Release},
|
Ordering::{Acquire, Relaxed, Release},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::cpu;
|
#[cfg(feature = "x86_64")]
|
||||||
|
use crate::arch::x86::cpu;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use crate::sync::AtomicBits;
|
use crate::sync::AtomicBits;
|
||||||
use crate::sync::SpinLock;
|
use crate::sync::SpinLock;
|
||||||
|
@ -1,10 +1,8 @@
|
|||||||
//! Timer.
|
//! Timer.
|
||||||
|
|
||||||
use crate::{
|
#[cfg(feature = "x86_64")]
|
||||||
config::TIMER_FREQ,
|
use crate::arch::x86::timer::{add_timeout_list, TimerCallback, TICK};
|
||||||
driver::{TimerCallback, TICK},
|
use crate::{config::TIMER_FREQ, prelude::*};
|
||||||
prelude::*,
|
|
||||||
};
|
|
||||||
use core::time::Duration;
|
use core::time::Duration;
|
||||||
use spin::Mutex;
|
use spin::Mutex;
|
||||||
|
|
||||||
@ -69,11 +67,7 @@ impl Timer {
|
|||||||
lock.start_tick = TICK;
|
lock.start_tick = TICK;
|
||||||
lock.timeout_tick = TICK + tick_count;
|
lock.timeout_tick = TICK + tick_count;
|
||||||
}
|
}
|
||||||
lock.timer_callback = Some(crate::driver::add_timeout_list(
|
lock.timer_callback = Some(add_timeout_list(tick_count, self.clone(), timer_callback));
|
||||||
tick_count,
|
|
||||||
self.clone(),
|
|
||||||
timer_callback,
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the remaining timeout value.
|
/// Returns the remaining timeout value.
|
||||||
|
@ -17,8 +17,7 @@ pub(crate) fn call_irq_callback_functions(f: &mut TrapFrame) {
|
|||||||
callback_function.call(f);
|
callback_function.call(f);
|
||||||
}
|
}
|
||||||
if f.trap_num >= 0x20 {
|
if f.trap_num >= 0x20 {
|
||||||
crate::driver::xapic_ack();
|
crate::arch::interrupts_ack();
|
||||||
crate::driver::pic_ack();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
//! User space.
|
//! User space.
|
||||||
|
|
||||||
use crate::trap::call_irq_callback_functions;
|
use trapframe::UserContext;
|
||||||
use log::debug;
|
|
||||||
use trapframe::{TrapFrame, UserContext};
|
cfg_if::cfg_if! {
|
||||||
use x86_64::registers::rflags::RFlags;
|
if #[cfg(feature="x86_64")]{
|
||||||
use x86_64::registers::segmentation::Segment64;
|
use crate::arch::x86::cpu::CpuContext;
|
||||||
use x86_64::registers::segmentation::FS;
|
}
|
||||||
|
}
|
||||||
|
|
||||||
use crate::cpu::CpuContext;
|
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use crate::task::Task;
|
use crate::task::Task;
|
||||||
use crate::vm::VmSpace;
|
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.
|
/// Code execution in the user mode.
|
||||||
///
|
///
|
||||||
/// This type enables executing the code in user space from a task in the kernel
|
/// 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> {
|
pub struct UserMode<'a> {
|
||||||
current: Arc<Task>,
|
current: Arc<Task>,
|
||||||
user_space: &'a Arc<UserSpace>,
|
pub(crate) user_space: &'a Arc<UserSpace>,
|
||||||
context: CpuContext,
|
pub(crate) context: CpuContext,
|
||||||
user_context: UserContext,
|
pub(crate) user_context: UserContext,
|
||||||
executed: bool,
|
pub(crate) executed: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
// An instance of `UserMode` is bound to the current task. So it cannot be
|
// 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.
|
/// Returns an immutable reference the user-mode CPU context.
|
||||||
pub fn context(&self) -> &CpuContext {
|
pub fn context(&self) -> &CpuContext {
|
||||||
&self.context
|
&self.context
|
||||||
|
@ -2,13 +2,12 @@ use core::ops::Range;
|
|||||||
|
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
use buddy_system_allocator::FrameAllocator;
|
use buddy_system_allocator::FrameAllocator;
|
||||||
use limine::{LimineMemmapEntry, LimineMemoryMapEntryType};
|
|
||||||
use log::{debug, info};
|
use log::{debug, info};
|
||||||
use spin::{Mutex, Once};
|
use spin::{Mutex, Once};
|
||||||
|
|
||||||
use crate::{config::PAGE_SIZE, vm::Paddr, AlignExt};
|
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();
|
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
|
/// Check if the physical address in range is valid
|
||||||
fn is_paddr_valid(range: Range<usize>) -> bool {
|
fn is_paddr_valid(range: Range<usize>) -> bool {
|
||||||
// special area in x86
|
// special area in x86
|
||||||
|
#[cfg(feature = "x86_64")]
|
||||||
if range.start >= 0xFE00_0000 && range.end <= 0xFFFF_FFFF {
|
if range.start >= 0xFE00_0000 && range.end <= 0xFFFF_FFFF {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
for i in super::MEMORY_REGIONS.get().unwrap().iter() {
|
for i in super::MEMORY_REGIONS.get().unwrap().iter() {
|
||||||
match i.typ {
|
match i.typ {
|
||||||
LimineMemoryMapEntryType::Usable => {}
|
MemoryRegionsType::Usable => {}
|
||||||
LimineMemoryMapEntryType::Reserved => {}
|
MemoryRegionsType::Reserved => {}
|
||||||
LimineMemoryMapEntryType::Framebuffer => {}
|
MemoryRegionsType::Framebuffer => {}
|
||||||
_ => {
|
_ => {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -93,10 +93,10 @@ pub(crate) unsafe fn dealloc(index: usize) {
|
|||||||
FRAME_ALLOCATOR.get().unwrap().lock().dealloc(index, 1);
|
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();
|
let mut allocator = FrameAllocator::<32>::new();
|
||||||
for region in regions.iter() {
|
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.base % PAGE_SIZE as u64, 0);
|
||||||
assert_eq!(region.len % PAGE_SIZE as u64, 0);
|
assert_eq!(region.len % PAGE_SIZE as u64, 0);
|
||||||
let start = region.base as usize / PAGE_SIZE;
|
let start = region.base as usize / PAGE_SIZE;
|
||||||
|
@ -27,10 +27,36 @@ pub use self::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
use limine::{LimineMemmapRequest, LimineMemoryMapEntryType};
|
|
||||||
use log::debug;
|
|
||||||
use spin::Once;
|
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
|
/// Convert physical address to virtual address using offset, only available inside jinux-frame
|
||||||
pub(crate) fn paddr_to_vaddr(pa: usize) -> usize {
|
pub(crate) fn paddr_to_vaddr(pa: usize) -> usize {
|
||||||
pa + PHYS_OFFSET
|
pa + PHYS_OFFSET
|
||||||
@ -50,28 +76,23 @@ pub const fn is_page_aligned(p: usize) -> bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Only available inside jinux-frame
|
/// Only available inside jinux-frame
|
||||||
pub(crate) static MEMORY_REGIONS: Once<Vec<&limine::LimineMemmapEntry>> = Once::new();
|
pub(crate) static MEMORY_REGIONS: Once<&Vec<MemoryRegions>> = Once::new();
|
||||||
static MEMMAP_REQUEST: LimineMemmapRequest = LimineMemmapRequest::new(0);
|
|
||||||
|
|
||||||
pub static FRAMEBUFFER_REGIONS: Once<Vec<&limine::LimineMemmapEntry>> = Once::new();
|
pub static FRAMEBUFFER_REGIONS: Once<Vec<MemoryRegions>> = Once::new();
|
||||||
|
|
||||||
pub(crate) fn init() {
|
pub(crate) fn init() {
|
||||||
heap_allocator::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 mut framebuffer_regions = Vec::new();
|
||||||
let response = MEMMAP_REQUEST
|
for i in memory_regions.iter() {
|
||||||
.get_response()
|
if i.typ == MemoryRegionsType::Framebuffer {
|
||||||
.get()
|
framebuffer_regions.push(i.clone());
|
||||||
.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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
frame_allocator::init(&memory_regions);
|
frame_allocator::init(memory_regions);
|
||||||
page_table::init();
|
page_table::init();
|
||||||
|
|
||||||
MEMORY_REGIONS.call_once(|| memory_regions);
|
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
|
/// 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> {
|
pub fn vaddr_to_paddr(virtual_address: Vaddr) -> Option<Paddr> {
|
||||||
let (cr3, _) = x86_64::registers::control::Cr3::read();
|
#[cfg(feature = "x86_64")]
|
||||||
let cr3 = cr3.start_address().as_u64() as usize;
|
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 pte = p4[p4_index(virtual_address)];
|
||||||
let p3 = table_of(pte.paddr())?;
|
let p3 = table_of(pte.paddr())?;
|
||||||
@ -238,10 +239,11 @@ pub fn vaddr_to_paddr(virtual_address: Vaddr) -> Option<Paddr> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn init() {
|
pub(crate) fn init() {
|
||||||
let (cr3, _) = x86_64::registers::control::Cr3::read();
|
#[cfg(feature = "x86_64")]
|
||||||
let cr3 = cr3.start_address().as_u64() as usize;
|
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.
|
// Cancel mapping in lowest addresses.
|
||||||
p4[0].0 = 0;
|
p4[0].0 = 0;
|
||||||
let mut map_pte = ALL_MAPPED_PTE.lock();
|
let mut map_pte = ALL_MAPPED_PTE.lock();
|
||||||
|
@ -3,7 +3,6 @@ use crate::vm::page_table::PageTableFlags;
|
|||||||
use bitflags::bitflags;
|
use bitflags::bitflags;
|
||||||
use core::ops::Range;
|
use core::ops::Range;
|
||||||
use spin::Mutex;
|
use spin::Mutex;
|
||||||
use x86_64::structures::paging::PhysFrame;
|
|
||||||
|
|
||||||
use super::VmFrameVec;
|
use super::VmFrameVec;
|
||||||
use super::{is_page_aligned, Vaddr};
|
use super::{is_page_aligned, Vaddr};
|
||||||
@ -38,11 +37,9 @@ impl VmSpace {
|
|||||||
}
|
}
|
||||||
/// Activate the page table, load root physical address to cr3
|
/// Activate the page table, load root physical address to cr3
|
||||||
pub unsafe fn activate(&self) {
|
pub unsafe fn activate(&self) {
|
||||||
x86_64::registers::control::Cr3::write(
|
#[cfg(feature = "x86_64")]
|
||||||
PhysFrame::from_start_address(x86_64::PhysAddr::new(
|
crate::arch::x86::mm::activate_page_table(
|
||||||
self.memory_set.lock().pt.root_pa as u64,
|
self.memory_set.lock().pt.root_pa,
|
||||||
))
|
|
||||||
.unwrap(),
|
|
||||||
x86_64::registers::control::Cr3Flags::PAGE_LEVEL_CACHE_DISABLE,
|
x86_64::registers::control::Cr3Flags::PAGE_LEVEL_CACHE_DISABLE,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -94,6 +91,7 @@ impl VmSpace {
|
|||||||
/// clear all mappings
|
/// clear all mappings
|
||||||
pub fn clear(&self) {
|
pub fn clear(&self) {
|
||||||
self.memory_set.lock().clear();
|
self.memory_set.lock().clear();
|
||||||
|
#[cfg(feature = "x86_64")]
|
||||||
x86_64::instructions::tlb::flush_all();
|
x86_64::instructions::tlb::flush_all();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,9 +65,11 @@ impl CSpaceAccessMethod {
|
|||||||
);
|
);
|
||||||
match self {
|
match self {
|
||||||
CSpaceAccessMethod::IO => {
|
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));
|
.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) => {
|
} //MemoryMapped(ptr) => {
|
||||||
// // FIXME: Clarify whether the rules for GEP/GEPi forbid using regular .offset() here.
|
// // 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))
|
// ::core::intrinsics::volatile_load(::core::intrinsics::arith_offset(ptr, offset as usize))
|
||||||
@ -107,9 +109,9 @@ impl CSpaceAccessMethod {
|
|||||||
);
|
);
|
||||||
match self {
|
match self {
|
||||||
CSpaceAccessMethod::IO => {
|
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));
|
.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) => {
|
} //MemoryMapped(ptr) => {
|
||||||
// // FIXME: Clarify whether the rules for GEP/GEPi forbid using regular .offset() here.
|
// // 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))
|
// ::core::intrinsics::volatile_load(::core::intrinsics::arith_offset(ptr, offset as usize))
|
||||||
|
@ -5,7 +5,7 @@ use spin::Mutex;
|
|||||||
|
|
||||||
use crate::SystemTime;
|
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);
|
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::{
|
use crate::{
|
||||||
prelude::*,
|
prelude::*,
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use jinux_frame::{
|
use jinux_frame::{
|
||||||
cpu::CpuContext,
|
cpu::CpuContext,
|
||||||
task::Task,
|
task::Task,
|
||||||
user::{UserEvent, UserMode, UserSpace},
|
user::{UserEvent, UserMode, UserModeExecute, UserSpace},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
Loading…
x
Reference in New Issue
Block a user