refactor virtio code; APIC , console interrupt support

This commit is contained in:
Yuke Peng
2022-12-26 04:33:27 -08:00
parent 1d401fd8fc
commit 46497554d2
48 changed files with 2365 additions and 548 deletions

View File

@ -17,6 +17,7 @@ font8x8 = { version = "0.2.5", default-features = false, features = ["unicode"]}
uart_16550 = "0.2.0"
pod = {path = "../pod"}
pod-derive = {path = "../pod-derive"}
acpi= "4.1.1"
[dependencies.lazy_static]
version = "1.0"

View File

@ -2,8 +2,8 @@
use crate::log::LogLevel;
pub const USER_STACK_SIZE: usize = PAGE_SIZE * 2;
pub const KERNEL_STACK_SIZE: usize = PAGE_SIZE * 16;
pub const USER_STACK_SIZE: usize = PAGE_SIZE * 4;
pub const KERNEL_STACK_SIZE: usize = PAGE_SIZE * 64;
pub const KERNEL_HEAP_SIZE: usize = 0x1_000_000;
pub const KERNEL_OFFSET: usize = 0xffffff00_00000000;
@ -16,3 +16,5 @@ pub const PAGE_SIZE_BITS: usize = 0xc;
pub const KVA_START: usize = (usize::MAX) << PAGE_SIZE_BITS;
pub const DEFAULT_LOG_LEVEL: LogLevel = LogLevel::Close;
/// This value represent the base timer frequency in Hz
pub const TIMER_FREQ: u64 = 100;

View File

@ -0,0 +1,111 @@
use lazy_static::lazy_static;
use crate::{cell::Cell, driver::pic, x86_64_util::*, IrqAllocateHandle, TrapFrame};
use core::fmt::{self, Write};
bitflags::bitflags! {
struct LineSts: u8 {
const INPUT_FULL = 1;
const OUTPUT_EMPTY = 1 << 5;
}
}
/// A port-mapped UART. Copied from uart_16550.
const SERIAL_DATA: u16 = 0x3F8;
const SERIAL_INT_EN: u16 = SERIAL_DATA + 1;
const SERIAL_FIFO_CTRL: u16 = SERIAL_DATA + 2;
const SERIAL_LINE_CTRL: u16 = SERIAL_DATA + 3;
const SERIAL_MODEM_CTRL: u16 = SERIAL_DATA + 4;
const SERIAL_LINE_STS: u16 = SERIAL_DATA + 5;
lazy_static! {
static ref CONSOLE_IRQ_CALLBACK: Cell<IrqAllocateHandle> =
Cell::new(pic::allocate_irq(4).unwrap());
}
/// Initializes the serial port.
pub(crate) fn init() {
// Disable interrupts
out8(SERIAL_INT_EN, 0x00);
// Enable DLAB
out8(SERIAL_LINE_CTRL, 0x80);
// Set maximum speed to 38400 bps by configuring DLL and DLM
out8(SERIAL_DATA, 0x03);
out8(SERIAL_INT_EN, 0x00);
// Disable DLAB and set data word length to 8 bits
out8(SERIAL_LINE_CTRL, 0x03);
// Enable FIFO, clear TX/RX queues and
// set interrupt watermark at 14 bytes
out8(SERIAL_FIFO_CTRL, 0xC7);
// Mark data terminal ready, signal request to send
// and enable auxilliary output #2 (used as interrupt line for CPU)
out8(SERIAL_MODEM_CTRL, 0x0B);
// Enable interrupts
out8(SERIAL_INT_EN, 0x01);
}
pub fn register_console_input_callback<F>(callback: F)
where
F: Fn(&TrapFrame) + Sync + Send + 'static,
{
CONSOLE_IRQ_CALLBACK.get().on_active(callback);
}
fn line_sts() -> LineSts {
LineSts::from_bits_truncate(in8(SERIAL_LINE_STS))
}
/// Sends a byte on the serial port.
pub fn send(data: u8) {
match data {
8 | 0x7F => {
while !line_sts().contains(LineSts::OUTPUT_EMPTY) {}
out8(SERIAL_DATA, 8);
while !line_sts().contains(LineSts::OUTPUT_EMPTY) {}
out8(SERIAL_DATA, b' ');
while !line_sts().contains(LineSts::OUTPUT_EMPTY) {}
out8(SERIAL_DATA, 8)
}
_ => {
while !line_sts().contains(LineSts::OUTPUT_EMPTY) {}
out8(SERIAL_DATA, data);
}
}
}
/// Receives a byte on the serial port. non-blocking
pub fn receive_char() -> Option<u8> {
if line_sts().contains(LineSts::INPUT_FULL) {
Some(in8(SERIAL_DATA))
} else {
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::console::print(format_args!($fmt $(, $($arg)+)?))
}
}
#[macro_export]
macro_rules! console_println {
($fmt: literal $(, $($arg: tt)+)?) => {
$crate::device::console::print(format_args!(concat!($fmt, "\n") $(, $($arg)+)?))
}
}

View File

@ -1,16 +1,19 @@
//! Device-related APIs.
pub mod framebuffer;
pub mod console;
mod io_port;
pub mod pci;
mod pic;
pub mod serial;
pub use self::io_port::IoPort;
pub(crate) use pic::{add_timeout_list, TICK};
pub use pic::{TimerCallback, TIMER_FREQ};
pub(crate) fn init(framebuffer: &'static mut bootloader::boot_info::FrameBuffer) {
/// first step to init device, call before the memory allocator init
pub(crate) fn first_init(framebuffer: &'static mut bootloader::boot_info::FrameBuffer) {
framebuffer::init(framebuffer);
pic::init();
console::init();
}
/// second step to init device, call after the memory allocator init
pub(crate) fn second_init() {
console::register_console_input_callback(|trap| {});
}

View File

@ -1,47 +0,0 @@
use lazy_static::lazy_static;
use spin::Mutex;
use uart_16550::SerialPort;
lazy_static! {
pub static ref SERIAL: Mutex<SerialPort> = {
let mut serial_port = unsafe { SerialPort::new(0x3F8) };
serial_port.init();
Mutex::new(serial_port)
};
}
/// read a char from the keyboard input.
/// FIXME: this function should **NOT** block. If no char receives, this function should return None immediately.
/// However, the receive function on SERIAL will block until a char is received, which will block the whole kernel.
/// A more correct implementation should be added once interrupt is ready. We should register the kerboard interrupt
/// handler to wake up foreground processes which wait on IOEVENTS.
pub fn receive_char() -> Option<u8> {
let byte = SERIAL.lock().receive();
Some(byte)
}
#[doc(hidden)]
pub fn _print(args: ::core::fmt::Arguments) {
use core::fmt::Write;
SERIAL
.lock()
.write_fmt(args)
.expect("Printing to serial failed");
}
/// Prints to the host through the serial interface.
#[macro_export]
macro_rules! serial_print {
($($arg:tt)*) => {
$crate::device::serial::_print(format_args!($($arg)*));
};
}
/// Prints to the host through the serial interface, appending a newline.
#[macro_export]
macro_rules! serial_println {
() => ($crate::serial_print!("\n"));
($fmt:expr) => ($crate::serial_print!(concat!($fmt, "\n")));
($fmt:expr, $($arg:tt)*) => ($crate::serial_print!(
concat!($fmt, "\n"), $($arg)*));
}

View File

@ -0,0 +1,45 @@
use core::ptr::NonNull;
use crate::{info, mm::address::phys_to_virt};
use acpi::{AcpiHandler, AcpiTables};
use lazy_static::lazy_static;
use spin::Mutex;
lazy_static! {
/// RSDP information, key is the signature, value is the virtual address of the signature
pub(crate) static ref ACPI_TABLES : Mutex<AcpiTables<AcpiMemoryHandler>> = unsafe{
Mutex::new(core::mem::MaybeUninit::zeroed().assume_init())
};
}
#[derive(Debug, Clone)]
pub struct AcpiMemoryHandler {}
impl AcpiHandler for AcpiMemoryHandler {
unsafe fn map_physical_region<T>(
&self,
physical_address: usize,
size: usize,
) -> acpi::PhysicalMapping<Self, T> {
acpi::PhysicalMapping::new(
physical_address,
NonNull::new(phys_to_virt(physical_address) as *mut T).unwrap(),
size,
size,
self.clone(),
)
}
fn unmap_physical_region<T>(region: &acpi::PhysicalMapping<Self, T>) {}
}
pub fn init(rsdp: u64) {
let a = unsafe { AcpiTables::from_rsdp(AcpiMemoryHandler {}, rsdp as usize).unwrap() };
*ACPI_TABLES.lock() = a;
let c = ACPI_TABLES.lock();
for (signature, sdt) in c.sdts.iter() {
info!("ACPI found signature:{:?}", signature);
}
info!("acpi init complete");
}

View File

@ -0,0 +1,210 @@
use crate::{cell::Cell, debug, x86_64_util};
use lazy_static::lazy_static;
use volatile::{
access::{ReadOnly, ReadWrite, WriteOnly},
Volatile,
};
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: u32 = 0x800;
const APIC_LVT_MASK_BITS: u32 = 1 << 16;
lazy_static! {
pub static ref APIC_INSTANCE: Cell<APIC> = Cell::new(APIC::new());
}
#[derive(Debug)]
pub struct APIC {
local_apic_id_register: Volatile<&'static mut u32, ReadWrite>,
local_apic_version_register: Volatile<&'static u32, ReadOnly>,
task_priority_register: Volatile<&'static mut u32, ReadWrite>,
arbitration_priority_register: Volatile<&'static u32, ReadOnly>,
processor_priority_register: Volatile<&'static u32, ReadOnly>,
pub eoi_register: Volatile<&'static mut u32, WriteOnly>,
remote_read_register: Volatile<&'static u32, ReadOnly>,
logical_destination_register: Volatile<&'static mut u32, ReadWrite>,
destination_format_register: Volatile<&'static mut u32, ReadWrite>,
spurious_interrupt_vector_register: Volatile<&'static mut u32, ReadWrite>,
/// total 256 bits, 32 bits per element
isr_per_32_bits: [Volatile<&'static u32, ReadOnly>; 8],
/// total 256 bits, 32 bits per element
tmr_per_32_bits: [Volatile<&'static u32, ReadOnly>; 8],
/// total 256 bits, 32 bits per element
irr_per_32_bits: [Volatile<&'static u32, ReadOnly>; 8],
pub error_status_register: Volatile<&'static u32, ReadOnly>,
lvt_cmci_register: Volatile<&'static mut u32, ReadWrite>,
icr_bits_31_0: Volatile<&'static mut u32, ReadWrite>,
icr_bits_63_32: Volatile<&'static mut u32, ReadWrite>,
pub lvt_timer_register: Volatile<&'static mut u32, ReadWrite>,
lvt_thermal_sensor_register: Volatile<&'static mut u32, ReadWrite>,
lvt_performance_monitoring_counters_register: Volatile<&'static mut u32, ReadWrite>,
lvt_lint0_register: Volatile<&'static mut u32, ReadWrite>,
lvt_lint1_register: Volatile<&'static mut u32, ReadWrite>,
lvt_error_register: Volatile<&'static mut u32, ReadWrite>,
pub initial_count_register: Volatile<&'static mut u32, ReadWrite>,
pub current_count_register: Volatile<&'static u32, ReadOnly>,
pub divide_configuration_register: Volatile<&'static mut u32, ReadWrite>,
}
impl APIC {
pub fn new() -> Self {
let base_address = get_apic_base_address();
let local_apic_id_register = Self::new_read_write_volatile(base_address + 0x0020);
let local_apic_version_register = Self::new_read_only_volatile(base_address + 0x0030);
let task_priority_register = Self::new_read_write_volatile(base_address + 0x0080);
let arbitration_priority_register = Self::new_read_only_volatile(base_address + 0x0090);
let processor_priority_register = Self::new_read_only_volatile(base_address + 0x00A0);
let eoi_register = Self::new_write_only_volatile(base_address + 0x00B0);
let remote_read_register = Self::new_read_only_volatile(base_address + 0x00C0);
let logical_destination_register = Self::new_read_write_volatile(base_address + 0x00D0);
let destination_format_register = Self::new_read_write_volatile(base_address + 0x00E0);
let spurious_interrupt_vector_register =
Self::new_read_write_volatile(base_address + 0x00F0);
let mut isr_per_32_bits: [Volatile<&'static u32, ReadOnly>; 8] =
unsafe { core::mem::MaybeUninit::uninit().assume_init() };
for i in 0..8 {
isr_per_32_bits[i] = Self::new_read_only_volatile(base_address + 0x0100 + i * 0x0010);
}
let mut tmr_per_32_bits: [Volatile<&'static u32, ReadOnly>; 8] =
unsafe { core::mem::MaybeUninit::uninit().assume_init() };
for i in 0..8 {
tmr_per_32_bits[i] = Self::new_read_only_volatile(base_address + 0x0180 + i * 0x0010);
}
let mut irr_per_32_bits: [Volatile<&'static u32, ReadOnly>; 8] =
unsafe { core::mem::MaybeUninit::uninit().assume_init() };
for i in 0..8 {
irr_per_32_bits[i] = Self::new_read_only_volatile(base_address + 0x0200 + i * 0x0010);
}
let error_status_register = Self::new_read_only_volatile(base_address + 0x0280);
let lvt_cmci_register = Self::new_read_write_volatile(base_address + 0x02F0);
let icr_bits_31_0 = Self::new_read_write_volatile(base_address + 0x0300);
let icr_bits_63_32 = Self::new_read_write_volatile(base_address + 0x0310);
let lvt_timer_register = Self::new_read_write_volatile(base_address + 0x0320);
let lvt_thermal_sensor_register = Self::new_read_write_volatile(base_address + 0x0330);
let lvt_performance_monitoring_counters_register =
Self::new_read_write_volatile(base_address + 0x0340);
let lvt_lint0_register = Self::new_read_write_volatile(base_address + 0x0350);
let lvt_lint1_register = Self::new_read_write_volatile(base_address + 0x0360);
let lvt_error_register = Self::new_read_write_volatile(base_address + 0x0370);
let initial_count_register = Self::new_read_write_volatile(base_address + 0x0380);
let current_count_register = Self::new_read_only_volatile(base_address + 0x0390);
let divide_configuration_register = Self::new_read_write_volatile(base_address + 0x03E0);
Self {
local_apic_id_register,
local_apic_version_register,
task_priority_register,
arbitration_priority_register,
processor_priority_register,
eoi_register,
remote_read_register,
logical_destination_register,
destination_format_register,
spurious_interrupt_vector_register,
isr_per_32_bits,
tmr_per_32_bits,
irr_per_32_bits,
error_status_register,
lvt_cmci_register,
icr_bits_31_0,
icr_bits_63_32,
lvt_timer_register,
lvt_thermal_sensor_register,
lvt_performance_monitoring_counters_register,
lvt_lint0_register,
lvt_lint1_register,
lvt_error_register,
initial_count_register,
current_count_register,
divide_configuration_register,
}
}
#[inline(always)]
fn new_read_only_volatile(pa: usize) -> Volatile<&'static u32, ReadOnly> {
Volatile::new_read_only(Self::convert_pa_to_u32_ref(pa))
}
#[inline(always)]
fn new_read_write_volatile(pa: usize) -> Volatile<&'static mut u32, ReadWrite> {
Volatile::new(Self::convert_pa_to_u32_ref(pa))
}
#[inline(always)]
fn new_write_only_volatile(pa: usize) -> Volatile<&'static mut u32, WriteOnly> {
Volatile::new_write_only(Self::convert_pa_to_u32_ref(pa))
}
#[inline(always)]
fn convert_pa_to_u32_ref(pa: usize) -> &'static mut u32 {
unsafe { &mut *(crate::mm::address::phys_to_virt(pa) as *mut usize as *mut u32) }
}
}
pub(crate) fn has_apic() -> bool {
let value = unsafe { x86_64_util::cpuid(1) };
value.edx & 0x100 != 0
}
pub(crate) fn init() {
super::pic::disable_temp();
let apic_lock = APIC_INSTANCE.get();
// enable apic
set_apic_base_address(get_apic_base_address());
let spurious = apic_lock.spurious_interrupt_vector_register.read();
apic_lock
.spurious_interrupt_vector_register
.write(spurious | (0x100));
let apic_id = apic_lock.local_apic_id_register.read() >> 24;
let apic_ver = apic_lock.local_apic_version_register.read();
debug!(
"APIC ID:{:x}, Version:{:x}, Max LVT:{:x}",
apic_id,
apic_ver & 0xff,
(apic_ver >> 16) & 0xff
);
debug!(
"LDR:{:x}, DFR:{:x}",
apic_lock.logical_destination_register.read(),
apic_lock.destination_format_register.read()
);
debug!("spurious:{:x}", spurious);
drop(apic_lock);
}
#[inline(always)]
pub fn ack() {
let lock = APIC_INSTANCE.get();
lock.eoi_register.write(0);
}
/// set APIC base address and enable it
fn set_apic_base_address(address: usize) {
x86_64_util::set_msr(
IA32_APIC_BASE_MSR,
address | IA32_APIC_BASE_MSR_ENABLE as usize,
)
}
/// get APIC base address
fn get_apic_base_address() -> usize {
x86_64_util::get_msr(IA32_APIC_BASE_MSR) & 0xf_ffff_f000
}

View File

@ -0,0 +1,153 @@
use acpi::PlatformInfo;
use super::acpi::ACPI_TABLES;
use crate::cell::Cell;
use crate::debug;
use crate::mm::address::phys_to_virt;
use crate::util::recycle_allocator::RecycleAllocator;
use lazy_static::lazy_static;
lazy_static! {
pub static ref IO_APIC: Cell<IoApic> =
unsafe { Cell::new(core::mem::MaybeUninit::zeroed().assume_init()) };
}
const IOAPICID: u32 = 0x00;
const IOAPICVER: u32 = 0x01;
const IOAPICARB: u32 = 0x02;
const fn IoApicRedtbl(index: u8) -> u32 {
0x10 + 2 * index as u32
}
#[derive(Debug)]
#[repr(C)]
struct IoApicRegister {
address: u32,
reserved: [u8; 0x10 - 0x04],
data: u32,
}
impl IoApicRegister {
pub fn read(self: &mut Self, reg: u32) -> u32 {
self.address = reg & 0xff;
self.data
}
pub fn write(self: &mut Self, reg: u32, value: u32) {
self.address = reg & 0xff;
self.data = value;
}
}
#[derive(Debug)]
pub struct IoApicEntryHandle {
index: u8,
}
impl IoApicEntryHandle {
pub fn read(&mut self) -> u64 {
let io_apic = IO_APIC.get();
io_apic.read_irq(self.index)
}
pub fn write(&mut self, value: u64) {
let io_apic = IO_APIC.get();
io_apic.write_irq(self.index, value);
}
pub fn get_index(&self) -> u8 {
self.index
}
}
impl Drop for IoApicEntryHandle {
fn drop(&mut self) {
let io_apic = IO_APIC.get();
// mask
io_apic.write_irq(self.index, 1 << 16);
io_apic.entry_allocator.dealloc(self.index as usize);
}
}
#[derive(Debug)]
pub struct IoApic {
id: u8,
version: u32,
max_redirection_entry: u32,
io_apic_register: &'static mut IoApicRegister,
entry_allocator: RecycleAllocator,
}
impl IoApic {
fn read_irq(&mut self, irq_index: u8) -> u64 {
let low = self.io_apic_register.read(IoApicRedtbl(irq_index)) as u64;
let high = self.io_apic_register.read(IoApicRedtbl(irq_index) + 1) as u64;
high << 32 | low
}
fn write_irq(&mut self, irq_index: u8, value: u64) {
let low = value as u32;
let high = (value >> 32) as u32;
self.io_apic_register.write(IoApicRedtbl(irq_index), low);
self.io_apic_register
.write(IoApicRedtbl(irq_index) + 1, high);
}
pub fn allocate_entry(&mut self) -> Option<IoApicEntryHandle> {
let id = self.entry_allocator.alloc();
if id == usize::MAX {
return None;
}
Some(IoApicEntryHandle { index: id as u8 })
}
}
pub fn init() {
let c = ACPI_TABLES.lock();
let platform_info = PlatformInfo::new(&*c).unwrap();
let mut ioapic_address = 0;
match platform_info.interrupt_model {
acpi::InterruptModel::Unknown => panic!("not found APIC in ACPI Table"),
acpi::InterruptModel::Apic(apic) => {
for io_apic in apic.io_apics.iter() {
ioapic_address = io_apic.address;
}
}
_ => todo!(),
}
if ioapic_address == 0 {
return;
}
let io_apic_register =
unsafe { &mut *(phys_to_virt(ioapic_address as usize) as *mut IoApicRegister) };
let id = (read_io_apic(io_apic_register, IOAPICID) & (0xF00_0000) >> 24) as u8;
let raw_version = read_io_apic(io_apic_register, IOAPICVER);
let version = raw_version & 0x1ff;
let max_redirection_entry = ((raw_version & (0xFF_0000)) >> 16) + 1;
debug!(
"IOAPIC id: {}, version:{}, max_redirection_entry:{}",
id, version, max_redirection_entry
);
let io_apic = IoApic {
id,
version,
max_redirection_entry,
io_apic_register,
entry_allocator: RecycleAllocator::with_start_max(0, max_redirection_entry as usize),
};
*IO_APIC.get() = io_apic;
}
fn read_io_apic(io_apic_register: &mut IoApicRegister, reg: u32) -> u32 {
io_apic_register.address = reg & 0xff;
io_apic_register.data
}
fn write_io_apic(io_apic_register: &mut IoApicRegister, reg: u32, value: u32) {
io_apic_register.address = reg & 0xff;
io_apic_register.data = value;
}

View File

@ -0,0 +1,30 @@
//! Driver for APIC, PIC, PIT etc.
//! This module should inaccessible by other crate such as std, virtio etc.
//!
pub mod acpi;
pub mod apic;
pub mod ioapic;
pub mod pic;
pub mod timer;
pub use apic::ack;
pub use timer::TimerCallback;
pub(crate) use timer::{add_timeout_list, TICK};
use crate::info;
pub(crate) fn init(rsdp: Option<u64>) {
acpi::init(rsdp.unwrap());
timer::init();
if apic::has_apic() {
ioapic::init();
apic::init();
} else {
info!("No apic exists, using pic instead");
unsafe {
pic::enable();
}
}
pic::init();
}

View File

@ -0,0 +1,123 @@
use crate::{info, trap::allocate_target_irq, x86_64_util::out8, IrqAllocateHandle};
use core::sync::atomic::Ordering::Relaxed;
use core::sync::atomic::{AtomicBool, AtomicU8};
const MASTER_CMD: u16 = 0x20;
const MASTER_DATA: u16 = MASTER_CMD + 1;
const SLAVE_CMD: u16 = 0xA0;
const SLAVE_DATA: u16 = SLAVE_CMD + 1;
const IRQ_OFFSET: u8 = 0x20;
const TIMER_IRQ_NUM: u8 = 32;
use alloc::vec::Vec;
use lazy_static::lazy_static;
use spin::Mutex;
lazy_static! {
/// store the irq, although we have APIC for manage interrupts
/// but something like serial still need pic for register interrupts
static ref IRQ_LOCK : Mutex<Vec<IrqAllocateHandle>> = Mutex::new(Vec::new());
}
static MASK_MASTER: AtomicU8 = AtomicU8::new(0x00);
static MASK_SLAVE: AtomicU8 = AtomicU8::new(0x00);
static CHANGE_LOCK: AtomicBool = AtomicBool::new(false);
/// init the PIC device
pub(crate) fn init() {
if CHANGE_LOCK.load(Relaxed) {
return;
}
let master_mask = !(MASK_MASTER.load(Relaxed));
let slave_mask = !(MASK_SLAVE.load(Relaxed));
info!(
"PIC init, master mask:{:x} slave_mask:{:x}",
master_mask, slave_mask
);
unsafe {
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> {
if index >= 16 {
return None;
}
if let Ok(irq) = allocate_target_irq(IRQ_OFFSET + index) {
if index >= 8 {
MASK_SLAVE.fetch_or(1 << (index - 8), Relaxed);
} else {
MASK_MASTER.fetch_or(1 << (index), Relaxed);
}
Some(irq)
} else {
None
}
}
/// enable the PIC device, this function will permanent enable all the interrupts
#[inline]
pub(crate) unsafe fn enable() {
CHANGE_LOCK.store(true, Relaxed);
set_mask(0, 0);
}
/// 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() {
CHANGE_LOCK.store(true, Relaxed);
set_mask(0xFF, 0xFF);
}
/// 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);
}
}
/// 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);
}
}
#[inline(always)]
pub(crate) unsafe fn set_mask(master_mask: u8, slave_mask: u8) {
// Start initialization
out8(MASTER_CMD, 0x11);
out8(SLAVE_CMD, 0x11);
// Set offsets
// map master PIC vector 0x00~0x07 to 0x20~0x27 IRQ number
out8(MASTER_DATA, IRQ_OFFSET);
// map slave PIC vector 0x00~0x07 to 0x28~0x2f IRQ number
out8(SLAVE_DATA, IRQ_OFFSET + 0x08);
// Set up cascade, there is slave at IRQ2
out8(MASTER_DATA, 4);
out8(SLAVE_DATA, 2);
// Set up interrupt mode (1 is 8086/88 mode, 2 is auto EOI)
out8(MASTER_DATA, 1);
out8(SLAVE_DATA, 1);
// mask interrupts
out8(MASTER_DATA, master_mask);
out8(SLAVE_DATA, slave_mask);
}
#[inline(always)]
pub(crate) fn ack() {
out8(MASTER_CMD, 0x20);
}

View File

@ -0,0 +1,70 @@
use crate::{
config,
driver::{apic::APIC_INSTANCE, pic, timer},
info, x86_64_util, TrapFrame,
};
pub fn init() {
let apic_lock = APIC_INSTANCE.get();
let handle = unsafe { crate::trap::IrqLine::acquire(timer::TIMER_IRQ_NUM) };
let a = handle.on_active(init_function);
// divide by 64
apic_lock.divide_configuration_register.write(0b1001);
apic_lock.initial_count_register.write(0xFFFF_FFFF);
// apic_lock.lvt_timer_register.write(timer::TIMER_IRQ_NUM as u32);
drop(apic_lock);
// init pic for now, disable it after the APIC Timer init is done
pic::enable_temp();
timer::pit::init();
static mut IS_FINISH: bool = false;
// wait until it is finish
x86_64_util::enable_interrupts();
unsafe {
while !IS_FINISH {
x86_64_util::hlt();
}
}
x86_64_util::disable_interrupts();
drop(a);
drop(handle);
fn init_function(trap_frame: &TrapFrame) {
static mut IN_TIME: u8 = 0;
static mut FIRST_TIME_COUNT: u32 = 0;
unsafe {
if IS_FINISH || IN_TIME == 0 {
// drop the first entry, since it may not be the time we want
IN_TIME += 1;
let apic_lock = APIC_INSTANCE.get();
let remain_ticks = apic_lock.current_count_register.read();
FIRST_TIME_COUNT = 0xFFFF_FFFF - remain_ticks;
pic::ack();
return;
}
}
pic::disable_temp();
// stop APIC Timer, get the number of tick we need
let apic_lock = APIC_INSTANCE.get();
let remain_ticks = apic_lock.current_count_register.read();
apic_lock.initial_count_register.write(0);
let ticks = unsafe { 0xFFFF_FFFF - remain_ticks - FIRST_TIME_COUNT };
// periodic mode, divide 64, freq: TIMER_FREQ Hz
apic_lock.initial_count_register.write(ticks as u32);
apic_lock
.lvt_timer_register
.write(timer::TIMER_IRQ_NUM as u32 | (1 << 17));
apic_lock.divide_configuration_register.write(0b1001);
info!(
"APIC Timer ticks count:{:x}, remain ticks: {:x},Timer Freq:{} Hz",
ticks,
remain_ticks,
config::TIMER_FREQ
);
unsafe {
IS_FINISH = true;
}
}
}

View File

@ -0,0 +1,126 @@
use acpi::{AcpiError, HpetInfo};
use alloc::vec::Vec;
use volatile::{
access::{ReadOnly, ReadWrite},
Volatile,
};
use crate::{
cell::Cell,
driver::{
acpi::ACPI_TABLES,
ioapic::{self, IoApicEntryHandle},
},
};
use lazy_static::lazy_static;
lazy_static! {
static ref HPET_INSTANCE: Cell<HPET> =
unsafe { Cell::new(core::mem::MaybeUninit::zeroed().assume_init()) };
}
const OFFSET_ID_REGISTER: usize = 0x000;
const OFFSET_CONFIGURATION_REGISTER: usize = 0x010;
const OFFSET_INTERRUPT_STATUS_REGISTER: usize = 0x020;
const OFFSET_MAIN_COUNTER_VALUE_REGISTER: usize = 0x0F0;
const HPET_FREQ: usize = 1_000_000_000_000_000;
#[derive(Debug)]
#[repr(C)]
struct HPETTimerRegister {
configuration_and_capabilities_register: u32,
timer_compartor_value_register: u32,
fsb_interrupt_route_register: u32,
}
struct HPET {
io_apic_entry: IoApicEntryHandle,
information_register: Volatile<&'static u32, ReadOnly>,
general_configuration_register: Volatile<&'static mut u32, ReadWrite>,
general_interrupt_status_register: Volatile<&'static mut u32, ReadWrite>,
timer_registers: Vec<Volatile<&'static mut HPETTimerRegister, ReadWrite>>,
}
impl HPET {
fn new(base_address: usize) -> HPET {
let information_register_ref = unsafe {
&*(crate::mm::address::phys_to_virt(base_address + OFFSET_ID_REGISTER) as *mut usize
as *mut u32)
};
let general_configuration_register_ref = unsafe {
&mut *(crate::mm::address::phys_to_virt(base_address + OFFSET_CONFIGURATION_REGISTER)
as *mut usize as *mut u32)
};
let general_interrupt_status_register_ref = unsafe {
&mut *(crate::mm::address::phys_to_virt(base_address + OFFSET_INTERRUPT_STATUS_REGISTER)
as *mut usize as *mut u32)
};
let information_register = Volatile::new_read_only(information_register_ref);
let general_configuration_register = Volatile::new(general_configuration_register_ref);
let general_interrupt_status_register =
Volatile::new(general_interrupt_status_register_ref);
let num_comparator = ((information_register.read() & 0x1F00) >> 8) as u8 + 1;
let mut comparators = Vec::with_capacity(num_comparator as usize);
for i in 0..num_comparator {
let comp = Volatile::new(unsafe {
&mut *(crate::mm::address::phys_to_virt(base_address + 0x100 + i as usize * 0x20)
as *mut usize as *mut HPETTimerRegister)
});
comparators.push(comp);
}
let mut io_apic_entry = ioapic::IO_APIC.get().allocate_entry().unwrap();
let vector = super::TIMER_IRQ_NUM;
// 0 for now
let destination_apic_id: u8 = 0;
let write_value = (destination_apic_id as u64) << 56 | vector as u64;
io_apic_entry.write(write_value);
HPET {
io_apic_entry,
information_register,
general_configuration_register,
general_interrupt_status_register,
timer_registers: comparators,
}
}
pub fn hardware_rev(&self) -> u8 {
(self.information_register.read() & 0xFF) as u8
}
pub fn num_comparators(&self) -> u8 {
((self.information_register.read() & 0x1F00) >> 8) as u8 + 1
}
pub fn main_counter_is_64bits(&self) -> bool {
(self.information_register.read() & 0x2000) != 0
}
pub fn legacy_irq_capable(&self) -> bool {
(self.information_register.read() & 0x8000) != 0
}
pub fn pci_vendor_id(&self) -> u16 {
((self.information_register.read() & 0xFFFF_0000) >> 16) as u16
}
}
/// HPET init, need to init IOAPIC before init this function
pub fn init() -> Result<(), AcpiError> {
let c = ACPI_TABLES.lock();
let hpet_info = HpetInfo::new(&*c)?;
// config IO APIC entry
let hpet = HPET::new(hpet_info.base_address);
*HPET_INSTANCE.get() = hpet;
Ok(())
}

View File

@ -1,27 +1,16 @@
use crate::cell::Cell;
use crate::x86_64_util::out8;
use crate::{IrqAllocateHandle, TrapFrame};
use alloc::sync::Arc;
use alloc::vec::Vec;
use alloc::{boxed::Box, collections::BinaryHeap};
pub mod apic;
pub mod hpet;
pub mod pit;
use core::any::Any;
use alloc::{boxed::Box, collections::BinaryHeap, sync::Arc, vec::Vec};
use lazy_static::lazy_static;
use spin::Mutex;
const MASTER_CMD: u16 = 0x20;
const MASTER_DATA: u16 = MASTER_CMD + 1;
const SLAVE_CMD: u16 = 0xA0;
const SLAVE_DATA: u16 = SLAVE_CMD + 1;
const TIMER_RATE: u32 = 1193182;
/// This value represent the base timer frequency in Hz
pub const TIMER_FREQ: u64 = 100;
const TIMER_PERIOD_IO_PORT: u16 = 0x40;
const TIMER_MODE_IO_PORT: u16 = 0x43;
const TIMER_SQUARE_WAVE: u8 = 0x36;
const TIMER_IRQ_NUM: u8 = 32;
use crate::{cell::Cell, IrqAllocateHandle, TrapFrame};
pub(crate) const TIMER_IRQ_NUM: u8 = 32;
pub static mut TICK: u64 = 0;
lazy_static! {
@ -31,49 +20,16 @@ lazy_static! {
}
pub fn init() {
// Start initialization
out8(MASTER_CMD, 0x11);
out8(SLAVE_CMD, 0x11);
if super::apic::has_apic() {
apic::init();
} else {
pit::init();
}
// Set offsets
// map master PIC vector 0x00~0x07 to 0x20~0x27 IRQ number
out8(MASTER_DATA, 0x20);
// map slave PIC vector 0x00~0x07 to 0x28~0x2f IRQ number
out8(SLAVE_DATA, 0x28);
// Set up cascade, there is slave at IRQ2
out8(MASTER_DATA, 4);
out8(SLAVE_DATA, 2);
// Set up interrupt mode (1 is 8086/88 mode, 2 is auto EOI)
out8(MASTER_DATA, 1);
out8(SLAVE_DATA, 1);
// Unmask timer interrupt
out8(MASTER_DATA, 0xFE);
out8(SLAVE_DATA, 0xFF);
// Ack remaining interrupts
out8(MASTER_CMD, 0x20);
out8(SLAVE_CMD, 0x20);
// Initialize timer.
let cycle = TIMER_RATE / TIMER_FREQ as u32; // 1ms per interrupt.
out8(TIMER_MODE_IO_PORT, TIMER_SQUARE_WAVE);
out8(TIMER_PERIOD_IO_PORT, (cycle & 0xFF) as _);
out8(TIMER_PERIOD_IO_PORT, (cycle >> 8) as _);
TIMER_IRQ.lock().on_active(timer_callback);
}
#[inline(always)]
fn ack() {
out8(MASTER_CMD, 0x20);
}
fn timer_callback(trap_frame: &TrapFrame) {
// FIXME: disable and enable interupt will cause infinity loop
// x86_64_util::disable_interrupts();
ack();
let current_ms;
unsafe {
current_ms = TICK;
@ -82,18 +38,16 @@ fn timer_callback(trap_frame: &TrapFrame) {
let timeout_list = TIMEOUT_LIST.get();
let mut callbacks: Vec<Arc<TimerCallback>> = Vec::new();
while let Some(t) = timeout_list.peek() {
if t.expire_ms <= current_ms {
if t.expire_ms <= current_ms && t.is_enable() {
callbacks.push(timeout_list.pop().unwrap());
} else {
break;
}
}
for callback in callbacks {
if callback.is_enable() {
callback.callback.call((&callback,));
}
callback.callback.call((&callback,));
}
// x86_64_util::enable_interrupts();
// crate::interrupt_ack();
}
lazy_static! {

View File

@ -0,0 +1,17 @@
//! used for PIT Timer
use crate::{config::TIMER_FREQ, x86_64_util::out8};
const TIMER_RATE: u32 = 1193182;
const TIMER_PERIOD_IO_PORT: u16 = 0x40;
const TIMER_MODE_IO_PORT: u16 = 0x43;
const TIMER_SQUARE_WAVE: u8 = 0x36;
pub(crate) fn init() {
// Initialize timer.
let cycle = TIMER_RATE / TIMER_FREQ as u32;
out8(TIMER_MODE_IO_PORT, TIMER_SQUARE_WAVE);
out8(TIMER_PERIOD_IO_PORT, (cycle & 0xFF) as _);
out8(TIMER_PERIOD_IO_PORT, (cycle >> 8) as _);
}

View File

@ -16,6 +16,7 @@ pub(crate) mod cell;
pub mod config;
pub mod cpu;
pub mod device;
mod driver;
mod error;
pub mod log;
pub(crate) mod mm;
@ -30,39 +31,48 @@ pub mod vm;
pub(crate) mod x86_64_util;
use core::{mem, panic::PanicInfo};
pub use driver::ack as apic_ack;
pub use self::error::Error;
pub use self::prelude::Result;
pub(crate) use self::sync::up::UPSafeCell;
pub use trap::interrupt_ack;
pub use x86_64_util::{disable_interrupts, enable_interrupts, hlt};
use alloc::vec::Vec;
use bootloader::{
boot_info::{FrameBuffer, MemoryRegionKind},
BootInfo,
};
pub use device::serial::receive_char;
pub use device::console::receive_char;
pub use mm::address::{align_down, align_up, is_aligned, virt_to_phys};
pub use mm::page_table::translate_not_offset_virtual_address;
pub use trap::{allocate_irq, IrqAllocateHandle, TrapFrame};
use trap::{IrqCallbackHandle, IrqLine};
pub use util::AlignExt;
pub use x86_64::registers::rflags::read as get_rflags;
pub use x86_64::registers::rflags::RFlags;
use x86_64_util::enable_common_cpu_features;
static mut IRQ_CALLBACK_LIST: Vec<IrqCallbackHandle> = Vec::new();
// TODO: serial中断
// 讨论syscall的中断启用
#[cfg(not(feature = "serial_print"))]
pub use crate::screen_print as print;
#[cfg(not(feature = "serial_print"))]
pub use crate::screen_println as println;
#[cfg(feature = "serial_print")]
pub use crate::serial_print as print;
pub use crate::console_print as print;
#[cfg(feature = "serial_print")]
pub use crate::serial_println as println;
pub use crate::console_println as println;
pub fn init(boot_info: &'static mut BootInfo) {
let siz = boot_info.framebuffer.as_ref().unwrap() as *const FrameBuffer as usize;
let mut memory_init = false;
// memory
device::first_init(boot_info.framebuffer.as_mut().unwrap());
device::framebuffer::WRITER.lock().as_mut().unwrap().clear();
for region in boot_info.memory_regions.iter() {
if region.kind == MemoryRegionKind::Usable {
let start: u64 = region.start;
@ -79,25 +89,25 @@ pub fn init(boot_info: &'static mut BootInfo) {
if !memory_init {
panic!("memory init failed");
}
device::init(boot_info.framebuffer.as_mut().unwrap());
device::framebuffer::WRITER.lock().as_mut().unwrap().clear();
trap::init();
device::second_init();
driver::init(boot_info.rsdp_addr.into_option());
enable_common_cpu_features();
unsafe {
for i in 0..256 {
IRQ_CALLBACK_LIST.push(IrqLine::acquire(i as u8).on_active(general_handler))
}
let value = x86_64_util::cpuid(1);
}
// uncomment below code to enable timer interrupt
// x86_64_util::enable_interrupts_and_hlt();
}
fn general_handler(trap_frame: &TrapFrame) {
println!("{:#x?}", trap_frame);
println!("rip = 0x{:x}", trap_frame.rip);
println!("rsp = 0x{:x}", trap_frame.rsp);
println!("cr2 = 0x{:x}", trap_frame.cr2);
// println!("rbx = 0x{:x}", trap_frame.)
panic!("couldn't handler trap right now");
// info!("general handler");
// println!("{:#x?}", trap_frame);
// println!("rip = 0x{:x}", trap_frame.rip);
// println!("rsp = 0x{:x}", trap_frame.rsp);
// println!("cr2 = 0x{:x}", trap_frame.cr2);
// // println!("rbx = 0x{:x}", trap_frame.)
// panic!("couldn't handler trap right now");
}
#[inline(always)]
@ -114,14 +124,14 @@ where
T: Fn(),
{
fn run(&self) {
serial_print!("{}...\n", core::any::type_name::<T>());
console_print!("{}...\n", core::any::type_name::<T>());
self();
serial_println!("[ok]");
console_println!("[ok]");
}
}
pub fn test_runner(tests: &[&dyn Testable]) {
serial_println!("Running {} tests", tests.len());
console_println!("Running {} tests", tests.len());
for test in tests {
test.run();
}
@ -129,11 +139,33 @@ pub fn test_runner(tests: &[&dyn Testable]) {
}
pub fn test_panic_handler(info: &PanicInfo) -> ! {
serial_println!("[failed]");
serial_println!("Error: {}", info);
console_println!("[failed]");
console_println!("Error: {}", info);
exit_qemu(QemuExitCode::Failed);
}
pub fn panic_handler() {
println!("[panic]: cr3:{:x}", x86_64_util::get_cr3());
// let mut fp: usize;
// let stop = unsafe{
// Task::current().kstack.get_top()
// };
// info!("stop:{:x}",stop);
// unsafe{
// asm!("mov rbp, {}", out(reg) fp);
// info!("fp:{:x}",fp);
// println!("---START BACKTRACE---");
// for i in 0..10 {
// if fp == stop {
// break;
// }
// println!("#{}:ra={:#x}", i, *((fp - 8) as *const usize));
// info!("fp target:{:x}",*((fp ) as *const usize));
// fp = *((fp - 16) as *const usize);
// }
// println!("---END BACKTRACE---");
// }
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u32)]
pub enum QemuExitCode {

View File

@ -23,15 +23,7 @@ pub fn log_print(args: Arguments) {
#[cfg(feature = "serial_print")]
#[doc(hidden)]
pub fn log_print(args: Arguments) {
use crate::device::serial::SERIAL;
use core::fmt::Write;
use x86_64::instructions::interrupts;
interrupts::without_interrupts(|| {
SERIAL
.lock()
.write_fmt(args)
.expect("Printing to serial failed");
});
crate::device::console::print(args);
}
/// This macro should not be directly called.

View File

@ -4,13 +4,19 @@ pub mod address;
mod frame_allocator;
mod heap_allocator;
mod memory_set;
mod page_table;
pub(crate) mod page_table;
use core::sync::atomic::AtomicUsize;
use address::PhysAddr;
use address::VirtAddr;
use crate::x86_64_util;
pub use self::{frame_allocator::*, memory_set::*, page_table::*};
pub(crate) static ORIGINAL_CR3: AtomicUsize = AtomicUsize::new(0);
bitflags::bitflags! {
/// Possible flags for a page table entry.
pub struct PTFlags: usize {
@ -35,4 +41,8 @@ pub(crate) fn init(start: u64, size: u64) {
heap_allocator::init();
frame_allocator::init(start as usize, size as usize);
page_table::init();
ORIGINAL_CR3.store(
x86_64_util::get_cr3_raw(),
core::sync::atomic::Ordering::Relaxed,
)
}

View File

@ -192,6 +192,56 @@ fn next_table_or_create<'a>(
}
}
/// translate a virtual address to physical address which cannot use offset to get physical address
/// Note: this may not useful for accessing usermode data, use offset first
pub fn translate_not_offset_virtual_address(va: usize) -> usize {
let cr3 = x86_64_util::get_cr3();
let p4 = table_of(PhysAddr(cr3));
let a = VirtAddr(va);
let pte = p4[p4_index(a)];
let p3 = table_of(pte.pa());
let pte = p3[p3_index(a)];
let p2 = table_of(pte.pa());
let pte = p2[p2_index(a)];
let p1 = table_of(pte.pa());
let pte = p1[p1_index(a)];
(pte.pa().0 & ((1 << 48) - 1)) + (va & ((1 << 12) - 1))
}
pub fn print_virtual_address_translate_information(va: usize) {
let cr3 = x86_64_util::get_cr3();
let p4 = table_of(PhysAddr(cr3));
let a = VirtAddr(va);
info!("p4 index:{:x}", p4_index(a));
let pte = p4[p4_index(a)];
info!("p4 pte:{:x}", pte.0);
let p3 = table_of(pte.pa());
info!("p3 index:{:x}", p3_index(a));
let pte = p3[p3_index(a)];
info!("p3 pte:{:x}", pte.0);
let p2 = table_of(pte.pa());
info!("p2 index:{:x}", p2_index(a));
let pte = p2[p2_index(a)];
info!("p2 pte:{:x}", pte.0);
let p1 = table_of(pte.pa());
info!("p1 index:{:x}", p1_index(a));
let pte = p1[p1_index(a)];
info!("p1 pte:{:x}", pte.0);
}
pub(crate) fn init() {
let cr3 = x86_64_util::get_cr3();
@ -201,7 +251,7 @@ pub(crate) fn init() {
// there is mapping where index is 1,2,3, so user may not use these value
let mut map_pte = ALL_MAPPED_PTE.exclusive_access();
for i in 0..512 {
if !p4[i].flags().is_empty() {
if p4[i].flags().contains(PTFlags::PRESENT) {
map_pte.insert(i, p4[i]);
}
}

View File

@ -1,7 +1,8 @@
//! Timer.
use crate::{
device::{TimerCallback, TICK, TIMER_FREQ},
config::TIMER_FREQ,
driver::{TimerCallback, TICK},
prelude::*,
};
use core::time::Duration;
@ -62,17 +63,13 @@ impl Timer {
}
None => {}
}
let tick_count = timeout.as_secs() * TIMER_FREQ
+ if timeout.subsec_nanos() != 0 {
(timeout.subsec_nanos() as u64 - 1) / NANOS_DIVIDE + 1
} else {
0
};
let tick_count =
timeout.as_secs() * TIMER_FREQ + timeout.subsec_nanos() as u64 / NANOS_DIVIDE;
unsafe {
lock.start_tick = TICK;
lock.timeout_tick = TICK + tick_count;
}
lock.timer_callback = Some(crate::device::add_timeout_list(
lock.timer_callback = Some(crate::driver::add_timeout_list(
tick_count,
self.clone(),
timer_callback,

View File

@ -33,23 +33,21 @@ pub(crate) extern "C" fn trap_handler(f: &mut TrapFrame) {
&Task::current().inner_ctx() as *const TaskContext,
)
}
} else {
let irq_line = IRQ_LIST.get(f.id as usize).unwrap();
let callback_functions = irq_line.callback_list();
for callback_function in callback_functions.iter() {
callback_function.call(f);
}
}
} else {
if is_cpu_fault(f) {
panic!("cannot handle kernel cpu fault now");
}
let irq_line = IRQ_LIST.get(f.id as usize).unwrap();
let callback_functions = irq_line.callback_list();
for callback_function in callback_functions.iter() {
callback_function.call(f);
panic!("cannot handle kernel cpu fault now, information:{:#x?}", f);
}
}
let irq_line = IRQ_LIST.get(f.id as usize).unwrap();
let callback_functions = irq_line.callback_list();
for callback_function in callback_functions.iter() {
callback_function.call(f);
}
if f.id >= 0x20 {
crate::driver::apic::ack();
crate::driver::pic::ack();
}
}
fn is_from_kernel(cs: u64) -> bool {

View File

@ -120,6 +120,15 @@ struct IDT {
entries: [[usize; 2]; 256],
}
#[inline]
pub fn interrupt_ack() {
if crate::driver::apic::has_apic() {
crate::driver::apic::ack();
} else {
crate::driver::pic::ack();
}
}
impl IDT {
const fn default() -> Self {
Self {

View File

@ -2,6 +2,7 @@
use crate::debug;
use crate::x86_64_util::{rdfsbase, wrfsbase};
use x86_64::registers::rflags::RFlags;
use crate::cpu::CpuContext;
use crate::prelude::*;
@ -116,6 +117,10 @@ impl<'a> UserMode<'a> {
}
if !self.executed {
*self.current.syscall_frame() = self.user_space.cpu_ctx.into();
if self.context.gp_regs.rflag == 0 {
self.context.gp_regs.rflag = (RFlags::INTERRUPT_FLAG | RFlags::ID).bits();
}
self.current.syscall_frame().caller.r11 = self.context.gp_regs.rflag;
self.current.syscall_frame().caller.rcx = self.user_space.cpu_ctx.gp_regs.rip;
// write fsbase
wrfsbase(self.user_space.cpu_ctx.fs_base);
@ -129,6 +134,8 @@ impl<'a> UserMode<'a> {
*self.current.trap_frame() = self.context.into();
} else {
*self.current.syscall_frame() = self.context.into();
self.context.gp_regs.rflag |= RFlags::INTERRUPT_FLAG.bits();
self.current.syscall_frame().caller.r11 = self.context.gp_regs.rflag;
self.current.syscall_frame().caller.rcx = self.context.gp_regs.rip;
}

View File

@ -1,5 +1,6 @@
use alloc::vec::Vec;
#[derive(Debug)]
pub struct RecycleAllocator {
current: usize,
recycled: Vec<usize>,

View File

@ -1,5 +1,5 @@
//! util for x86_64, it will rename to x86_64 when depend x86_64 isn't necessary
use core::arch::asm;
use core::arch::{asm, x86_64::CpuidResult};
use x86_64::registers::{control::Cr4Flags, segmentation::Segment64, xcontrol::XCr0Flags};
@ -61,6 +61,18 @@ pub fn out32(port: u16, val: u32) {
}
}
#[inline(always)]
pub unsafe fn cpuid(leaf: u32) -> CpuidResult {
core::arch::x86_64::__cpuid(leaf)
}
#[inline(always)]
pub fn hlt() {
unsafe {
asm!("hlt", options(nomem, nostack));
}
}
#[inline(always)]
pub fn disable_interrupts() {
unsafe {