mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-09 05:16:47 +00:00
Remove x86_64_util
This commit is contained in:
parent
02731914dc
commit
840fe53845
@ -1,55 +1,60 @@
|
||||
use crate::{prelude::*, x86_64_util};
|
||||
use spin::Mutex;
|
||||
use x86_64::{
|
||||
instructions::port::Port,
|
||||
structures::port::{PortRead, PortWrite},
|
||||
};
|
||||
|
||||
/// An I/O port, representing a specific address in the I/O address of x86.
|
||||
pub struct IoPort {
|
||||
///
|
||||
/// The following code shows and example to read and write u32 value to an I/O port:
|
||||
///
|
||||
/// ```rust
|
||||
/// static PORT: IoPort<u32> = IoPort::new(0x12);
|
||||
///
|
||||
/// fn port_value_increase(){
|
||||
/// PORT.write(PORT.read() + 1)
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
pub struct IoPort<T> {
|
||||
addr: u16,
|
||||
port: Mutex<Port<T>>,
|
||||
}
|
||||
|
||||
impl IoPort {
|
||||
impl<T> IoPort<T> {
|
||||
/// Create an I/O port.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This function is marked unsafe as creating an I/O port is considered
|
||||
/// a privileged operation.
|
||||
pub unsafe fn new(addr: u16) -> Result<Self> {
|
||||
Ok(Self { addr: addr })
|
||||
pub const unsafe fn new(addr: u16) -> Self {
|
||||
Self {
|
||||
addr,
|
||||
port: Mutex::new(Port::new(addr)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IoPort {
|
||||
impl<T> IoPort<T> {
|
||||
/// Get the address of this I/O port.
|
||||
pub fn addr(&self) -> u16 {
|
||||
self.addr
|
||||
}
|
||||
}
|
||||
|
||||
/// Read a value of `u32`.
|
||||
pub fn read_u32(&self) -> u32 {
|
||||
x86_64_util::in32(self.addr)
|
||||
}
|
||||
|
||||
/// Write a value of `u32`.
|
||||
pub fn write_u32(&self, val: u32) {
|
||||
x86_64_util::out32(self.addr, val)
|
||||
}
|
||||
|
||||
/// Read a value of `u16`.
|
||||
pub fn read_u16(&self) -> u16 {
|
||||
x86_64_util::in16(self.addr)
|
||||
}
|
||||
|
||||
/// Write a value of `u16`.
|
||||
pub fn write_u16(&self, val: u16) {
|
||||
x86_64_util::out16(self.addr, val)
|
||||
}
|
||||
|
||||
/// Read a value of `u8`.
|
||||
pub fn read_u8(&self) -> u8 {
|
||||
x86_64_util::in8(self.addr)
|
||||
}
|
||||
|
||||
/// Write a value of `u8`.
|
||||
pub fn write_u8(&self, val: u8) {
|
||||
x86_64_util::out8(self.addr, val)
|
||||
impl<T: PortRead> IoPort<T> {
|
||||
/// Reads from the port.
|
||||
pub fn read(&self) -> T {
|
||||
unsafe { (*self.port.lock()).read() }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: PortWrite> IoPort<T> {
|
||||
/// Writes to the port.
|
||||
pub fn write(&self, val: T) {
|
||||
unsafe {
|
||||
self.port.lock().write(val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,12 +1,6 @@
|
||||
//! PCI bus io port
|
||||
|
||||
use super::io_port::IoPort;
|
||||
use lazy_static::lazy_static;
|
||||
|
||||
const CONFIG_ADDRESS: u16 = 0x0CF8;
|
||||
const CONFIG_DATA: u16 = 0x0CFC;
|
||||
|
||||
lazy_static! {
|
||||
pub static ref PCI_ADDRESS_PORT: IoPort = unsafe { IoPort::new(CONFIG_ADDRESS).unwrap() };
|
||||
pub static ref PCI_DATA_PORT: IoPort = unsafe { IoPort::new(CONFIG_DATA).unwrap() };
|
||||
}
|
||||
pub static PCI_ADDRESS_PORT: IoPort<u32> = unsafe { IoPort::new(0x0CF8) };
|
||||
pub static PCI_DATA_PORT: IoPort<u32> = unsafe { IoPort::new(0x0CFC) };
|
||||
|
@ -1,9 +1,11 @@
|
||||
//! A port-mapped UART. Copied from uart_16550.
|
||||
use alloc::{sync::Arc, vec::Vec};
|
||||
use log::debug;
|
||||
use spin::{Mutex, Once};
|
||||
use trapframe::TrapFrame;
|
||||
use x86_64::instructions::port::{Port, PortWriteOnly};
|
||||
|
||||
use crate::{driver::pic_allocate_irq, trap::IrqAllocateHandle, x86_64_util::*};
|
||||
use crate::{driver::pic_allocate_irq, trap::IrqAllocateHandle};
|
||||
use core::fmt::{self, Write};
|
||||
|
||||
bitflags::bitflags! {
|
||||
@ -13,13 +15,18 @@ bitflags::bitflags! {
|
||||
}
|
||||
}
|
||||
|
||||
/// 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;
|
||||
const SERIAL_DATA_PORT: u16 = 0x3F8;
|
||||
|
||||
static SERIAL_DATA: Mutex<Port<u8>> = Mutex::new(Port::new(SERIAL_DATA_PORT));
|
||||
static SERIAL_INT_EN: Mutex<PortWriteOnly<u8>> =
|
||||
Mutex::new(PortWriteOnly::new(SERIAL_DATA_PORT + 1));
|
||||
static SERIAL_FIFO_CTRL: Mutex<PortWriteOnly<u8>> =
|
||||
Mutex::new(PortWriteOnly::new(SERIAL_DATA_PORT + 2));
|
||||
static SERIAL_LINE_CTRL: Mutex<PortWriteOnly<u8>> =
|
||||
Mutex::new(PortWriteOnly::new(SERIAL_DATA_PORT + 3));
|
||||
static SERIAL_MODEM_CTRL: Mutex<PortWriteOnly<u8>> =
|
||||
Mutex::new(PortWriteOnly::new(SERIAL_DATA_PORT + 4));
|
||||
static SERIAL_LINE_STS: Mutex<Port<u8>> = Mutex::new(Port::new(SERIAL_DATA_PORT + 5));
|
||||
|
||||
static CONSOLE_IRQ_CALLBACK: Once<Mutex<IrqAllocateHandle>> = Once::new();
|
||||
static SERIAL_INPUT_CALLBACKS: Mutex<Vec<Arc<dyn Fn(u8) + Send + Sync + 'static>>> =
|
||||
@ -27,23 +34,30 @@ static SERIAL_INPUT_CALLBACKS: Mutex<Vec<Arc<dyn Fn(u8) + Send + Sync + 'static>
|
||||
|
||||
/// Initializes the serial port.
|
||||
pub(crate) fn init() {
|
||||
let mut serial_line_ctrl_lock = SERIAL_LINE_CTRL.lock();
|
||||
let mut serial_int_en_lock = SERIAL_INT_EN.lock();
|
||||
let mut serial_data_lock = SERIAL_DATA.lock();
|
||||
let mut serial_fifo_ctrl_lock = SERIAL_FIFO_CTRL.lock();
|
||||
let mut serial_modem_ctrl_lock = SERIAL_MODEM_CTRL.lock();
|
||||
unsafe {
|
||||
// Disable interrupts
|
||||
out8(SERIAL_INT_EN, 0x00);
|
||||
serial_int_en_lock.write(0x00);
|
||||
// Enable DLAB
|
||||
out8(SERIAL_LINE_CTRL, 0x80);
|
||||
serial_line_ctrl_lock.write(0x80);
|
||||
// Set maximum speed to 38400 bps by configuring DLL and DLM
|
||||
out8(SERIAL_DATA, 0x03);
|
||||
out8(SERIAL_INT_EN, 0x00);
|
||||
serial_data_lock.write(0x03);
|
||||
serial_int_en_lock.write(0x00);
|
||||
// Disable DLAB and set data word length to 8 bits
|
||||
out8(SERIAL_LINE_CTRL, 0x03);
|
||||
serial_line_ctrl_lock.write(0x03);
|
||||
// Enable FIFO, clear TX/RX queues and
|
||||
// set interrupt watermark at 14 bytes
|
||||
out8(SERIAL_FIFO_CTRL, 0xC7);
|
||||
serial_fifo_ctrl_lock.write(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);
|
||||
serial_modem_ctrl_lock.write(0x0B);
|
||||
// Enable interrupts
|
||||
out8(SERIAL_INT_EN, 0x01);
|
||||
serial_int_en_lock.write(0x01);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn register_serial_input_callback(f: impl Fn(u8) + Send + Sync + 'static) {
|
||||
@ -81,23 +95,26 @@ fn handle_serial_input(trap_frame: &TrapFrame) {
|
||||
}
|
||||
|
||||
fn line_sts() -> LineSts {
|
||||
LineSts::from_bits_truncate(in8(SERIAL_LINE_STS))
|
||||
LineSts::from_bits_truncate(unsafe { SERIAL_LINE_STS.lock().read() })
|
||||
}
|
||||
|
||||
/// Sends a byte on the serial port.
|
||||
pub fn send(data: u8) {
|
||||
let mut lock = SERIAL_DATA.lock();
|
||||
unsafe {
|
||||
match data {
|
||||
8 | 0x7F => {
|
||||
while !line_sts().contains(LineSts::OUTPUT_EMPTY) {}
|
||||
out8(SERIAL_DATA, 8);
|
||||
lock.write(8);
|
||||
while !line_sts().contains(LineSts::OUTPUT_EMPTY) {}
|
||||
out8(SERIAL_DATA, b' ');
|
||||
lock.write(b' ');
|
||||
while !line_sts().contains(LineSts::OUTPUT_EMPTY) {}
|
||||
out8(SERIAL_DATA, 8)
|
||||
lock.write(8);
|
||||
}
|
||||
_ => {
|
||||
while !line_sts().contains(LineSts::OUTPUT_EMPTY) {}
|
||||
out8(SERIAL_DATA, data);
|
||||
lock.write(data);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -105,7 +122,7 @@ pub fn send(data: u8) {
|
||||
/// 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))
|
||||
unsafe { Some(SERIAL_DATA.lock().read()) }
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
@ -1,12 +1,13 @@
|
||||
use crate::trap::allocate_target_irq;
|
||||
use crate::trap::IrqAllocateHandle;
|
||||
use crate::{trap::allocate_target_irq, x86_64_util::out8};
|
||||
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;
|
||||
static MASTER_CMD: Mutex<PortWriteOnly<u8>> = Mutex::new(PortWriteOnly::new(0x20));
|
||||
static MASTER_DATA: Mutex<PortWriteOnly<u8>> = Mutex::new(PortWriteOnly::new(0x21));
|
||||
static SLAVE_CMD: Mutex<PortWriteOnly<u8>> = Mutex::new(PortWriteOnly::new(0xA0));
|
||||
static SLAVE_DATA: Mutex<PortWriteOnly<u8>> = Mutex::new(PortWriteOnly::new(0xA1));
|
||||
|
||||
const IRQ_OFFSET: u8 = 0x20;
|
||||
|
||||
const TIMER_IRQ_NUM: u8 = 32;
|
||||
@ -15,6 +16,7 @@ use alloc::vec::Vec;
|
||||
use lazy_static::lazy_static;
|
||||
use log::info;
|
||||
use spin::Mutex;
|
||||
use x86_64::instructions::port::PortWriteOnly;
|
||||
|
||||
lazy_static! {
|
||||
/// store the irq, although we have APIC for manage interrupts
|
||||
@ -96,30 +98,36 @@ pub(crate) fn disable_temp() {
|
||||
|
||||
#[inline(always)]
|
||||
pub(crate) unsafe fn set_mask(master_mask: u8, slave_mask: u8) {
|
||||
let mut master_data_lock = MASTER_DATA.lock();
|
||||
let mut slave_data_lock = SLAVE_DATA.lock();
|
||||
unsafe {
|
||||
// Start initialization
|
||||
out8(MASTER_CMD, 0x11);
|
||||
out8(SLAVE_CMD, 0x11);
|
||||
MASTER_CMD.lock().write(0x11);
|
||||
SLAVE_CMD.lock().write(0x11);
|
||||
|
||||
// Set offsets
|
||||
// map master PIC vector 0x00~0x07 to 0x20~0x27 IRQ number
|
||||
out8(MASTER_DATA, IRQ_OFFSET);
|
||||
master_data_lock.write(IRQ_OFFSET);
|
||||
// map slave PIC vector 0x00~0x07 to 0x28~0x2f IRQ number
|
||||
out8(SLAVE_DATA, IRQ_OFFSET + 0x08);
|
||||
slave_data_lock.write(IRQ_OFFSET + 0x08);
|
||||
|
||||
// Set up cascade, there is slave at IRQ2
|
||||
out8(MASTER_DATA, 4);
|
||||
out8(SLAVE_DATA, 2);
|
||||
master_data_lock.write(4);
|
||||
slave_data_lock.write(2);
|
||||
|
||||
// Set up interrupt mode (1 is 8086/88 mode, 2 is auto EOI)
|
||||
out8(MASTER_DATA, 1);
|
||||
out8(SLAVE_DATA, 1);
|
||||
master_data_lock.write(1);
|
||||
slave_data_lock.write(1);
|
||||
|
||||
// mask interrupts
|
||||
out8(MASTER_DATA, master_mask);
|
||||
out8(SLAVE_DATA, slave_mask);
|
||||
master_data_lock.write(master_mask);
|
||||
slave_data_lock.write(slave_mask);
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub(crate) fn ack() {
|
||||
out8(MASTER_CMD, 0x20);
|
||||
unsafe {
|
||||
MASTER_CMD.lock().write(0x20);
|
||||
}
|
||||
}
|
||||
|
@ -4,16 +4,15 @@ use core::sync::atomic::Ordering::Relaxed;
|
||||
use acpi::{fadt::Fadt, sdt::Signature};
|
||||
use lazy_static::lazy_static;
|
||||
use spin::Mutex;
|
||||
use x86_64::instructions::port::{PortReadOnly, PortWriteOnly};
|
||||
|
||||
use crate::{
|
||||
time::Time,
|
||||
x86_64_util::{in8, out8},
|
||||
};
|
||||
use crate::time::Time;
|
||||
|
||||
use super::acpi::ACPI_TABLES;
|
||||
|
||||
const CMOS_ADDRESS: u16 = 0x70;
|
||||
const CMOS_DATA: u16 = 0x71;
|
||||
static CMOS_ADDRESS: Mutex<PortWriteOnly<u8>> = Mutex::new(PortWriteOnly::new(0x70));
|
||||
static CMOS_DATA: Mutex<PortReadOnly<u8>> = Mutex::new(PortReadOnly::new(0x71));
|
||||
|
||||
pub(crate) static CENTURY_REGISTER: AtomicU8 = AtomicU8::new(0);
|
||||
|
||||
lazy_static! {
|
||||
@ -33,13 +32,17 @@ pub fn init() {
|
||||
}
|
||||
|
||||
pub fn get_cmos(reg: u8) -> u8 {
|
||||
out8(CMOS_ADDRESS, reg as u8);
|
||||
in8(CMOS_DATA)
|
||||
unsafe {
|
||||
CMOS_ADDRESS.lock().write(reg);
|
||||
CMOS_DATA.lock().read()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_updating() -> bool {
|
||||
out8(CMOS_ADDRESS, 0x0A);
|
||||
in8(CMOS_DATA) & 0x80 != 0
|
||||
unsafe {
|
||||
CMOS_ADDRESS.lock().write(0x0A);
|
||||
CMOS_DATA.lock().read() & 0x80 != 0
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read() -> Time {
|
||||
|
@ -4,7 +4,6 @@ use trapframe::TrapFrame;
|
||||
use crate::{
|
||||
config,
|
||||
driver::{pic, timer, xapic::XAPIC_INSTANCE},
|
||||
x86_64_util,
|
||||
};
|
||||
use x86::apic::xapic;
|
||||
|
||||
@ -24,13 +23,13 @@ pub fn init() {
|
||||
|
||||
static mut IS_FINISH: bool = false;
|
||||
// wait until it is finish
|
||||
x86_64_util::enable_interrupts();
|
||||
x86_64::instructions::interrupts::enable();
|
||||
unsafe {
|
||||
while !IS_FINISH {
|
||||
x86_64_util::hlt();
|
||||
x86_64::instructions::hlt();
|
||||
}
|
||||
}
|
||||
x86_64_util::disable_interrupts();
|
||||
x86_64::instructions::interrupts::disable();
|
||||
drop(a);
|
||||
drop(handle);
|
||||
|
||||
|
@ -1,17 +1,22 @@
|
||||
//! used for PIT Timer
|
||||
|
||||
use crate::{config::TIMER_FREQ, x86_64_util::out8};
|
||||
use spin::Mutex;
|
||||
use x86_64::instructions::port::PortWriteOnly;
|
||||
|
||||
use crate::config::TIMER_FREQ;
|
||||
|
||||
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;
|
||||
static TIMER_PERIOD: Mutex<PortWriteOnly<u8>> = Mutex::new(PortWriteOnly::new(0x40));
|
||||
static TIMER_MOD: Mutex<PortWriteOnly<u8>> = Mutex::new(PortWriteOnly::new(0x43));
|
||||
static 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 _);
|
||||
unsafe {
|
||||
TIMER_MOD.lock().write(TIMER_SQUARE_WAVE);
|
||||
TIMER_PERIOD.lock().write((cycle & 0xFF) as _);
|
||||
TIMER_PERIOD.lock().write((cycle >> 8) as _);
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,11 @@
|
||||
use crate::{mm, x86_64_util};
|
||||
use crate::mm;
|
||||
use log::debug;
|
||||
use spin::{Mutex, Once};
|
||||
use x86::apic::xapic;
|
||||
|
||||
pub(crate) const IA32_APIC_BASE_MSR: u32 = 0x1B;
|
||||
pub(crate) const IA32_APIC_BASE_MSR_BSP: u32 = 0x100; // Processor is a BSP
|
||||
pub(crate) const IA32_APIC_BASE_MSR_ENABLE: u32 = 0x800;
|
||||
pub(crate) const IA32_APIC_BASE_MSR_ENABLE: u64 = 0x800;
|
||||
|
||||
const APIC_LVT_MASK_BITS: u32 = 1 << 16;
|
||||
|
||||
@ -40,7 +40,7 @@ impl XAPIC {
|
||||
}
|
||||
|
||||
pub(crate) fn has_apic() -> bool {
|
||||
let value = unsafe { x86_64_util::cpuid(1) };
|
||||
let value = unsafe { core::arch::x86_64::__cpuid(1) };
|
||||
value.edx & 0x100 != 0
|
||||
}
|
||||
|
||||
@ -79,13 +79,16 @@ pub fn ack() {
|
||||
|
||||
/// 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,
|
||||
)
|
||||
unsafe {
|
||||
x86_64::registers::model_specific::Msr::new(IA32_APIC_BASE_MSR)
|
||||
.write(address as u64 | IA32_APIC_BASE_MSR_ENABLE);
|
||||
}
|
||||
}
|
||||
|
||||
/// get APIC base address
|
||||
fn get_apic_base_address() -> usize {
|
||||
x86_64_util::get_msr(IA32_APIC_BASE_MSR) & 0xf_ffff_f000
|
||||
unsafe {
|
||||
(x86_64::registers::model_specific::Msr::new(IA32_APIC_BASE_MSR).read() & 0xf_ffff_f000)
|
||||
as usize
|
||||
}
|
||||
}
|
||||
|
@ -32,7 +32,6 @@ pub mod trap;
|
||||
pub mod user;
|
||||
mod util;
|
||||
pub mod vm;
|
||||
pub(crate) mod x86_64_util;
|
||||
|
||||
pub use self::error::Error;
|
||||
pub use self::prelude::Result;
|
||||
@ -42,7 +41,6 @@ pub use limine::LimineModuleRequest;
|
||||
use trap::{IrqCallbackHandle, IrqLine};
|
||||
use trapframe::TrapFrame;
|
||||
pub use util::AlignExt;
|
||||
use x86_64_util::enable_common_cpu_features;
|
||||
|
||||
static mut IRQ_CALLBACK_LIST: Vec<IrqCallbackHandle> = Vec::new();
|
||||
|
||||
@ -74,7 +72,6 @@ fn register_irq_common_callback() {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -93,6 +90,27 @@ fn invoke_c_init_funcs() {
|
||||
}
|
||||
}
|
||||
|
||||
fn enable_common_cpu_features() {
|
||||
use x86_64::registers::{control::Cr4Flags, model_specific::EferFlags, xcontrol::XCr0Flags};
|
||||
let mut cr4 = x86_64::registers::control::Cr4::read();
|
||||
cr4 |= Cr4Flags::FSGSBASE | Cr4Flags::OSXSAVE | Cr4Flags::OSFXSR | Cr4Flags::OSXMMEXCPT_ENABLE;
|
||||
unsafe {
|
||||
x86_64::registers::control::Cr4::write(cr4);
|
||||
}
|
||||
|
||||
let mut xcr0 = x86_64::registers::xcontrol::XCr0::read();
|
||||
xcr0 |= XCr0Flags::AVX | XCr0Flags::SSE;
|
||||
unsafe {
|
||||
x86_64::registers::xcontrol::XCr0::write(xcr0);
|
||||
}
|
||||
|
||||
unsafe {
|
||||
// enable non-executable page protection
|
||||
x86_64::registers::model_specific::Efer::update(|efer| {
|
||||
*efer |= EferFlags::NO_EXECUTE_ENABLE;
|
||||
});
|
||||
}
|
||||
}
|
||||
fn general_handler(trap_frame: &TrapFrame) {
|
||||
// info!("general handler");
|
||||
// println!("{:#x?}", trap_frame);
|
||||
@ -138,7 +156,6 @@ pub fn test_panic_handler(info: &PanicInfo) -> ! {
|
||||
}
|
||||
|
||||
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()
|
||||
|
@ -7,9 +7,7 @@ use crate::{
|
||||
config::{ENTRY_COUNT, PAGE_SIZE, PHYS_OFFSET},
|
||||
println,
|
||||
vm::VmFrame,
|
||||
x86_64_util,
|
||||
};
|
||||
use ::log::info;
|
||||
use alloc::{collections::BTreeMap, vec, vec::Vec};
|
||||
use core::{fmt, panic};
|
||||
use lazy_static::lazy_static;
|
||||
@ -213,56 +211,30 @@ 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();
|
||||
pub fn translate_not_offset_virtual_address(address: usize) -> usize {
|
||||
let (cr3, _) = x86_64::registers::control::Cr3::read();
|
||||
let cr3 = cr3.start_address().as_u64() as usize;
|
||||
|
||||
let p4 = table_of(PhysAddr(cr3));
|
||||
|
||||
let a = VirtAddr(va);
|
||||
let virtual_address = VirtAddr(address);
|
||||
|
||||
let pte = p4[p4_index(a)];
|
||||
let pte = p4[p4_index(virtual_address)];
|
||||
let p3 = table_of(pte.pa());
|
||||
|
||||
let pte = p3[p3_index(a)];
|
||||
let pte = p3[p3_index(virtual_address)];
|
||||
let p2 = table_of(pte.pa());
|
||||
|
||||
let pte = p2[p2_index(a)];
|
||||
let pte = p2[p2_index(virtual_address)];
|
||||
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);
|
||||
let pte = p1[p1_index(virtual_address)];
|
||||
(pte.pa().0 & ((1 << 48) - 1)) + (address & ((1 << 12) - 1))
|
||||
}
|
||||
|
||||
pub(crate) fn init() {
|
||||
let cr3 = x86_64_util::get_cr3();
|
||||
let (cr3, _) = x86_64::registers::control::Cr3::read();
|
||||
let cr3 = cr3.start_address().as_u64() as usize;
|
||||
|
||||
let p4 = table_of(PhysAddr(cr3));
|
||||
// Cancel mapping in lowest addresses.
|
||||
|
@ -1,10 +1,11 @@
|
||||
//! User space.
|
||||
|
||||
use crate::trap::call_irq_callback_functions;
|
||||
use crate::x86_64_util::{self, rdfsbase, wrfsbase};
|
||||
use log::debug;
|
||||
use trapframe::{TrapFrame, UserContext};
|
||||
use x86_64::registers::rflags::RFlags;
|
||||
use x86_64::registers::segmentation::Segment64;
|
||||
use x86_64::registers::segmentation::FS;
|
||||
|
||||
use crate::cpu::CpuContext;
|
||||
use crate::prelude::*;
|
||||
@ -115,7 +116,9 @@ impl<'a> UserMode<'a> {
|
||||
self.context.gp_regs.rflag = (RFlags::INTERRUPT_FLAG | RFlags::ID).bits() | 0x2;
|
||||
}
|
||||
// write fsbase
|
||||
wrfsbase(self.user_space.cpu_ctx.fs_base);
|
||||
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();
|
||||
@ -123,9 +126,11 @@ impl<'a> UserMode<'a> {
|
||||
self.executed = true;
|
||||
} else {
|
||||
// write fsbase
|
||||
if rdfsbase() != self.context.fs_base {
|
||||
if FS::read_base().as_u64() != self.context.fs_base {
|
||||
debug!("write fsbase: 0x{:x}", self.context.fs_base);
|
||||
wrfsbase(self.context.fs_base);
|
||||
unsafe {
|
||||
FS::write_base(x86_64::VirtAddr::new(self.context.fs_base));
|
||||
}
|
||||
}
|
||||
|
||||
// write fp_regs
|
||||
@ -167,12 +172,11 @@ impl<'a> UserMode<'a> {
|
||||
}
|
||||
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.fs_base = rdfsbase();
|
||||
// self.context.fp_regs.save();
|
||||
UserEvent::Exception
|
||||
} else {
|
||||
self.context.fs_base = rdfsbase();
|
||||
// self.context.fp_regs.save();
|
||||
// debug!("[kernel] syscall id:{}", self.context.gp_regs.rax);
|
||||
// debug!("[kernel] rsp: 0x{:x}", self.context.gp_regs.rsp);
|
||||
|
@ -1,8 +1,8 @@
|
||||
use crate::config::PAGE_SIZE;
|
||||
use crate::x86_64_util;
|
||||
use bitflags::bitflags;
|
||||
use core::ops::Range;
|
||||
use spin::Mutex;
|
||||
use x86_64::structures::paging::PhysFrame;
|
||||
|
||||
use crate::mm::address::{is_aligned, VirtAddr};
|
||||
use crate::mm::{MapArea, MemorySet, PTFlags};
|
||||
@ -37,7 +37,13 @@ impl VmSpace {
|
||||
}
|
||||
/// Activate the page table, load root physical address to cr3
|
||||
pub unsafe fn activate(&self) {
|
||||
x86_64_util::set_cr3(self.memory_set.lock().pt.root_pa.0);
|
||||
x86_64::registers::control::Cr3::write(
|
||||
PhysFrame::from_start_address(x86_64::PhysAddr::new(
|
||||
self.memory_set.lock().pt.root_pa.0 as u64,
|
||||
))
|
||||
.unwrap(),
|
||||
x86_64::registers::control::Cr3Flags::PAGE_LEVEL_CACHE_DISABLE,
|
||||
);
|
||||
}
|
||||
|
||||
/// Maps some physical memory pages into the VM space according to the given
|
||||
@ -87,7 +93,7 @@ impl VmSpace {
|
||||
/// clear all mappings
|
||||
pub fn clear(&self) {
|
||||
self.memory_set.lock().clear();
|
||||
crate::x86_64_util::flush_tlb();
|
||||
x86_64::instructions::tlb::flush_all();
|
||||
}
|
||||
|
||||
/// Update the VM protection permissions within the VM address range.
|
||||
|
@ -1,253 +0,0 @@
|
||||
//! util for x86_64, it will rename to x86_64 when depend x86_64 isn't necessary
|
||||
use core::arch::{asm, x86_64::CpuidResult};
|
||||
|
||||
use x86_64::registers::{
|
||||
control::Cr4Flags, model_specific::EferFlags, segmentation::Segment64, xcontrol::XCr0Flags,
|
||||
};
|
||||
|
||||
#[inline(always)]
|
||||
pub fn read_rsp() -> usize {
|
||||
let val: usize;
|
||||
unsafe {
|
||||
asm!("mov {}, rsp", out(reg) val);
|
||||
}
|
||||
val
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn in8(port: u16) -> u8 {
|
||||
// ::x86_64::instructions::port::Port::read()
|
||||
let val: u8;
|
||||
unsafe {
|
||||
asm!("in al, dx", out("al") val, in("dx") port, options(nomem, nostack, preserves_flags));
|
||||
}
|
||||
val
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn in16(port: u16) -> u16 {
|
||||
let val: u16;
|
||||
unsafe {
|
||||
asm!("in ax, dx", out("ax") val, in("dx") port, options(nomem, nostack, preserves_flags));
|
||||
}
|
||||
val
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn in32(port: u16) -> u32 {
|
||||
let val: u32;
|
||||
unsafe {
|
||||
asm!("in eax, dx", out("eax") val, in("dx") port, options(nomem, nostack, preserves_flags));
|
||||
}
|
||||
val
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn out8(port: u16, val: u8) {
|
||||
unsafe {
|
||||
asm!("out dx, al", in("dx") port, in("al") val, options(nomem, nostack, preserves_flags));
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn out16(port: u16, val: u16) {
|
||||
unsafe {
|
||||
asm!("out dx, ax", in("dx") port, in("ax") val, options(nomem, nostack, preserves_flags));
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn out32(port: u16, val: u32) {
|
||||
unsafe {
|
||||
asm!("out dx, eax", in("dx") port, in("eax") val, options(nomem, nostack, preserves_flags));
|
||||
}
|
||||
}
|
||||
|
||||
#[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 {
|
||||
asm!("cli", options(nomem, nostack));
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn enable_interrupts_and_hlt() {
|
||||
unsafe {
|
||||
asm!("sti; hlt", options(nomem, nostack));
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn enable_interrupts() {
|
||||
unsafe {
|
||||
asm!("sti", options(nomem, nostack));
|
||||
}
|
||||
}
|
||||
|
||||
pub const RING0: u16 = 0;
|
||||
pub const RING3: u16 = 3;
|
||||
|
||||
pub const RFLAGS_IF: usize = 1 << 9;
|
||||
|
||||
#[inline(always)]
|
||||
pub fn get_msr(id: u32) -> usize {
|
||||
let (high, low): (u32, u32);
|
||||
unsafe {
|
||||
asm!("rdmsr", in("ecx") id, out("eax") low, out("edx") high, options(nomem, nostack, preserves_flags));
|
||||
}
|
||||
((high as usize) << 32) | (low as usize)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn set_msr(id: u32, val: usize) {
|
||||
let low = val as u32;
|
||||
let high = (val >> 32) as u32;
|
||||
unsafe {
|
||||
asm!("wrmsr", in("ecx") id, in("eax") low, in("edx") high, options(nostack, preserves_flags));
|
||||
}
|
||||
}
|
||||
|
||||
pub const EFER_MSR: u32 = 0xC000_0080;
|
||||
pub const STAR_MSR: u32 = 0xC000_0081;
|
||||
pub const LSTAR_MSR: u32 = 0xC000_0082;
|
||||
pub const SFMASK_MSR: u32 = 0xC000_0084;
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
#[repr(C, packed)]
|
||||
pub struct DescriptorTablePointer {
|
||||
/// Size of the DT.
|
||||
pub limit: u16,
|
||||
/// Pointer to the memory region containing the DT.
|
||||
pub base: usize,
|
||||
}
|
||||
|
||||
/// Load a GDT.
|
||||
#[inline(always)]
|
||||
pub fn lgdt(gdt: &DescriptorTablePointer) {
|
||||
unsafe {
|
||||
asm!("lgdt [{}]", in(reg) gdt, options(readonly, nostack, preserves_flags));
|
||||
}
|
||||
}
|
||||
|
||||
/// Load an IDT.
|
||||
#[inline(always)]
|
||||
pub fn lidt(idt: &DescriptorTablePointer) {
|
||||
unsafe {
|
||||
asm!("lidt [{}]", in(reg) idt, options(readonly, nostack, preserves_flags));
|
||||
}
|
||||
}
|
||||
|
||||
/// Load the task state register using the `ltr` instruction.
|
||||
#[inline(always)]
|
||||
pub fn load_tss(sel: u16) {
|
||||
unsafe {
|
||||
asm!("ltr {0:x}", in(reg) sel, options(nomem, nostack, preserves_flags));
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn set_cs(sel: u16) {
|
||||
unsafe {
|
||||
asm!(
|
||||
"push {sel}",
|
||||
"lea {tmp}, [1f + rip]",
|
||||
"push {tmp}",
|
||||
"retfq",
|
||||
"1:",
|
||||
sel = in(reg) sel as usize,
|
||||
tmp = lateout(reg) _,
|
||||
options(preserves_flags),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn set_ss(sel: u16) {
|
||||
unsafe {
|
||||
asm!("mov ss, {0:x}", in(reg) sel, options(nostack, preserves_flags));
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn get_cr3() -> usize {
|
||||
let val: usize;
|
||||
unsafe {
|
||||
asm!("mov {}, cr3", out(reg) val, options(nomem, nostack, preserves_flags));
|
||||
}
|
||||
// Mask top bits and flags.
|
||||
val & 0x_000f_ffff_ffff_f000
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn get_cr3_raw() -> usize {
|
||||
let val: usize;
|
||||
unsafe {
|
||||
asm!("mov {}, cr3", out(reg) val, options(nomem, nostack, preserves_flags));
|
||||
}
|
||||
// Mask top bits and flags.
|
||||
val
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn get_return_address() -> usize {
|
||||
let val: usize;
|
||||
unsafe {
|
||||
asm!("mov {}, [rsp]", out(reg) val);
|
||||
}
|
||||
val
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn set_cr3(pa: usize) {
|
||||
unsafe {
|
||||
asm!("mov cr3, {}", in(reg) pa, options(nostack, preserves_flags));
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn wrfsbase(base: u64) {
|
||||
unsafe { asm!("wrfsbase {0}", in(reg) base, options(att_syntax)) }
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn rdfsbase() -> u64 {
|
||||
let fs_base = x86_64::registers::segmentation::FS::read_base();
|
||||
fs_base.as_u64()
|
||||
}
|
||||
|
||||
pub fn enable_common_cpu_features() {
|
||||
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;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
pub fn flush_tlb() {
|
||||
x86_64::instructions::tlb::flush_all();
|
||||
}
|
@ -66,8 +66,8 @@ impl CSpaceAccessMethod {
|
||||
match self {
|
||||
CSpaceAccessMethod::IO => {
|
||||
jinux_frame::device::pci::PCI_ADDRESS_PORT
|
||||
.write_u32(loc.encode() | ((offset as u32) & 0b11111100));
|
||||
jinux_frame::device::pci::PCI_DATA_PORT.read_u32().to_le()
|
||||
.write(loc.encode() | ((offset as u32) & 0b11111100));
|
||||
jinux_frame::device::pci::PCI_DATA_PORT.read().to_le()
|
||||
} //MemoryMapped(ptr) => {
|
||||
// // FIXME: Clarify whether the rules for GEP/GEPi forbid using regular .offset() here.
|
||||
// ::core::intrinsics::volatile_load(::core::intrinsics::arith_offset(ptr, offset as usize))
|
||||
@ -108,8 +108,8 @@ impl CSpaceAccessMethod {
|
||||
match self {
|
||||
CSpaceAccessMethod::IO => {
|
||||
jinux_frame::device::pci::PCI_ADDRESS_PORT
|
||||
.write_u32(loc.encode() | (offset as u32 & 0b11111100));
|
||||
jinux_frame::device::pci::PCI_DATA_PORT.write_u32(val.to_le())
|
||||
.write(loc.encode() | (offset as u32 & 0b11111100));
|
||||
jinux_frame::device::pci::PCI_DATA_PORT.write(val.to_le())
|
||||
} //MemoryMapped(ptr) => {
|
||||
// // FIXME: Clarify whether the rules for GEP/GEPi forbid using regular .offset() here.
|
||||
// ::core::intrinsics::volatile_load(::core::intrinsics::arith_offset(ptr, offset as usize))
|
||||
|
Loading…
x
Reference in New Issue
Block a user