forked from rcore-os/zCore
kernel-hal: refactor for x86_64 bare-metal
This commit is contained in:
parent
3b0e3296e8
commit
ceacbc9d9c
|
@ -13,5 +13,4 @@ exclude = [
|
|||
"zCore",
|
||||
"rboot",
|
||||
"linux-syscall",
|
||||
"kernel-hal-bare",
|
||||
]
|
||||
|
|
|
@ -1,45 +0,0 @@
|
|||
[package]
|
||||
name = "kernel-hal-bare"
|
||||
version = "0.1.0"
|
||||
authors = ["Runji Wang <wangrunji0408@163.com>"]
|
||||
edition = "2018"
|
||||
description = "Kernel HAL implementation for bare metal environment."
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[features]
|
||||
board_qemu = []
|
||||
board_d1 = []
|
||||
|
||||
[dependencies]
|
||||
log = "0.4"
|
||||
spin = "0.7"
|
||||
git-version = "0.3"
|
||||
executor = { git = "https://github.com/rcore-os/executor.git", rev = "a2d02ee9" }
|
||||
trapframe = "0.8.0"
|
||||
kernel-hal = { path = "../kernel-hal" }
|
||||
naive-timer = "0.1.0"
|
||||
lazy_static = { version = "1.4", features = ["spin_no_std"] }
|
||||
rcore-fs = { git = "https://github.com/rcore-os/rcore-fs", rev = "6df6cd2" }
|
||||
device_tree = { git = "https://github.com/rcore-os/device_tree-rs" }
|
||||
virtio-drivers = { git = "https://github.com/rcore-os/virtio-drivers", rev = "568276" }
|
||||
|
||||
[target.'cfg(target_arch = "x86_64")'.dependencies]
|
||||
x86_64 = "0.14"
|
||||
uart_16550 = "=0.2.15"
|
||||
raw-cpuid = "9.0"
|
||||
pc-keyboard = "0.5"
|
||||
apic = { git = "https://github.com/rcore-os/apic-rs", rev = "fb86bd7" }
|
||||
x86-smpboot = { git = "https://github.com/rcore-os/x86-smpboot", rev = "43ffedf" }
|
||||
rcore-console = { git = "https://github.com/rcore-os/rcore-console", default-features = false, rev = "a980897b" }
|
||||
acpi = "1.1"
|
||||
ps2-mouse = { git = "https://github.com/YXL76/ps2-mouse", branch = "feat" }
|
||||
|
||||
[target.'cfg(any(target_arch = "riscv32", target_arch = "riscv64"))'.dependencies]
|
||||
riscv = { git = "https://github.com/rcore-os/riscv", features = [
|
||||
"inline-asm",
|
||||
], rev = "0074cbc" }
|
||||
# 注意rev版本号必须与其他组件的完全一致,不可多字符
|
||||
|
||||
bitflags = "1.0"
|
||||
volatile = "0.2"
|
|
@ -1,9 +0,0 @@
|
|||
#[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))]
|
||||
mod riscv;
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
mod x86_64;
|
||||
|
||||
#[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))]
|
||||
pub use self::riscv::*;
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
pub use self::x86_64::*;
|
|
@ -1,413 +0,0 @@
|
|||
#![allow(dead_code)]
|
||||
#![allow(non_upper_case_globals)]
|
||||
|
||||
use super::{acpi_table::*, phys_to_virt};
|
||||
use alloc::boxed::Box;
|
||||
use alloc::vec::Vec;
|
||||
use apic::IoApic;
|
||||
use ps2_mouse::{Mouse, MouseState};
|
||||
use spin::Mutex;
|
||||
use trapframe::TrapFrame;
|
||||
|
||||
const IO_APIC_NUM_REDIRECTIONS: u8 = 120;
|
||||
const TABLE_SIZE: usize = 256;
|
||||
pub type InterruptHandle = Box<dyn Fn() + Send + Sync>;
|
||||
lazy_static! {
|
||||
static ref IRQ_TABLE: Mutex<Vec<Option<InterruptHandle>>> = Default::default();
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
static ref MOUSE: Mutex<Mouse> = Mutex::new(Mouse::new());
|
||||
static ref MOUSE_CALLBACK: Mutex<Vec<Box<dyn Fn([u8; 3]) + Send + Sync>>> =
|
||||
Mutex::new(Vec::new());
|
||||
}
|
||||
|
||||
#[export_name = "hal_mouse_set_callback"]
|
||||
pub fn mouse_set_callback(callback: Box<dyn Fn([u8; 3]) + Send + Sync>) {
|
||||
MOUSE_CALLBACK.lock().push(callback);
|
||||
}
|
||||
|
||||
fn mouse_on_complete(mouse_state: MouseState) {
|
||||
debug!("mouse state: {:?}", mouse_state);
|
||||
MOUSE_CALLBACK.lock().iter().for_each(|callback| {
|
||||
callback([
|
||||
mouse_state.get_flags().bits(),
|
||||
mouse_state.get_x() as u8,
|
||||
mouse_state.get_y() as u8,
|
||||
]);
|
||||
});
|
||||
}
|
||||
|
||||
fn mouse() {
|
||||
use x86_64::instructions::port::PortReadOnly;
|
||||
let mut port = PortReadOnly::new(0x60);
|
||||
let packet = unsafe { port.read() };
|
||||
MOUSE.lock().process_packet(packet);
|
||||
}
|
||||
|
||||
pub fn init() {
|
||||
MOUSE.lock().init().unwrap();
|
||||
MOUSE.lock().set_on_complete(mouse_on_complete);
|
||||
unsafe {
|
||||
init_ioapic();
|
||||
}
|
||||
init_irq_table();
|
||||
irq_add_handle(Timer + IRQ0, Box::new(timer));
|
||||
irq_add_handle(Keyboard + IRQ0, Box::new(keyboard));
|
||||
irq_add_handle(Mouse + IRQ0, Box::new(mouse));
|
||||
irq_add_handle(COM1 + IRQ0, Box::new(com1));
|
||||
irq_enable_raw(Keyboard, Keyboard + IRQ0);
|
||||
irq_enable_raw(Mouse, Mouse + IRQ0);
|
||||
irq_enable_raw(COM1, COM1 + IRQ0);
|
||||
}
|
||||
|
||||
fn init_irq_table() {
|
||||
let mut table = IRQ_TABLE.lock();
|
||||
for _ in 0..TABLE_SIZE {
|
||||
table.push(None);
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn init_ioapic() {
|
||||
for ioapic in AcpiTable::get_ioapic() {
|
||||
info!("Ioapic found: {:#x?}", ioapic);
|
||||
let mut ip = IoApic::new(phys_to_virt(ioapic.address as usize));
|
||||
ip.disable_all();
|
||||
}
|
||||
let mut ip = IoApic::new(phys_to_virt(super::IOAPIC_ADDR));
|
||||
ip.disable_all();
|
||||
}
|
||||
|
||||
fn get_ioapic(irq: u32) -> Option<acpi::interrupt::IoApic> {
|
||||
for i in AcpiTable::get_ioapic() {
|
||||
let num_instr = core::cmp::min(
|
||||
ioapic_maxinstr(i.address).unwrap(),
|
||||
IO_APIC_NUM_REDIRECTIONS - 1,
|
||||
);
|
||||
if i.global_system_interrupt_base <= irq
|
||||
&& irq <= i.global_system_interrupt_base + num_instr as u32
|
||||
{
|
||||
return Some(i);
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn ioapic_controller(i: &acpi::interrupt::IoApic) -> IoApic {
|
||||
unsafe { IoApic::new(phys_to_virt(i.address as usize)) }
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn trap_handler(tf: &mut TrapFrame) {
|
||||
trace!("Interrupt: {:#x} @ CPU{}", tf.trap_num, 0); // TODO 0 should replace in multi-core case
|
||||
match tf.trap_num as u8 {
|
||||
Breakpoint => breakpoint(),
|
||||
DoubleFault => double_fault(tf),
|
||||
PageFault => page_fault(tf),
|
||||
IRQ0..=63 => irq_handle(tf.trap_num as u8),
|
||||
_ => panic!("Unhandled interrupt {:x} {:#x?}", tf.trap_num, tf),
|
||||
}
|
||||
}
|
||||
|
||||
#[export_name = "hal_irq_handle"]
|
||||
pub fn irq_handle(irq: u8) {
|
||||
use super::{LocalApic, XApic, LAPIC_ADDR};
|
||||
let mut lapic = unsafe { XApic::new(phys_to_virt(LAPIC_ADDR)) };
|
||||
lapic.eoi();
|
||||
let table = IRQ_TABLE.lock();
|
||||
match &table[irq as usize] {
|
||||
Some(f) => f(),
|
||||
None => panic!("unhandled external IRQ number: {}", irq),
|
||||
}
|
||||
}
|
||||
|
||||
#[export_name = "hal_irq_register_handler"]
|
||||
pub fn register_irq_handler(global_irq: u32, handle: InterruptHandle) -> Option<u32> {
|
||||
info!("set_handle irq={:#x?}", global_irq);
|
||||
// if global_irq == 1 {
|
||||
// irq_add_handle(global_irq as u8 + IRQ0, handle);
|
||||
// return Some(global_irq as u8 + IRQ0);
|
||||
// }
|
||||
let ioapic_info = get_ioapic(global_irq)?;
|
||||
let mut ioapic = ioapic_controller(&ioapic_info);
|
||||
let offset = (global_irq - ioapic_info.global_system_interrupt_base) as u8;
|
||||
let irq = ioapic.irq_vector(offset);
|
||||
let new_handle = if global_irq == 0x1 {
|
||||
Box::new(move || {
|
||||
handle();
|
||||
keyboard();
|
||||
mouse();
|
||||
})
|
||||
} else {
|
||||
handle
|
||||
};
|
||||
irq_add_handle(irq, new_handle).map(|x| {
|
||||
info!(
|
||||
"irq_set_handle: mapping from {:#x?} to {:#x?}",
|
||||
global_irq, x
|
||||
);
|
||||
ioapic.set_irq_vector(offset, x);
|
||||
x as u32
|
||||
})
|
||||
}
|
||||
|
||||
#[export_name = "hal_irq_unregister_handler"]
|
||||
pub fn unregister_irq_handler(global_irq: u32) -> bool {
|
||||
info!("reset_handle");
|
||||
let ioapic_info = if let Some(x) = get_ioapic(global_irq) {
|
||||
x
|
||||
} else {
|
||||
return false;
|
||||
};
|
||||
let mut ioapic = ioapic_controller(&ioapic_info);
|
||||
let offset = (global_irq - ioapic_info.global_system_interrupt_base) as u8;
|
||||
let irq = ioapic.irq_vector(offset);
|
||||
if !irq_remove_handle(irq) {
|
||||
ioapic.set_irq_vector(offset, 0);
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/// Add a handle to IRQ table. Return the specified irq or an allocated irq on success
|
||||
fn irq_add_handle(irq: u8, handle: InterruptHandle) -> Option<u8> {
|
||||
info!("IRQ add handle {:#x?}", irq);
|
||||
let mut table = IRQ_TABLE.lock();
|
||||
// allocate a valid irq number
|
||||
if irq == 0 {
|
||||
let mut id = 0x20;
|
||||
while id < table.len() {
|
||||
if table[id].is_none() {
|
||||
table[id] = Some(handle);
|
||||
return Some(id as u8);
|
||||
}
|
||||
id += 1;
|
||||
}
|
||||
return None;
|
||||
}
|
||||
match table[irq as usize] {
|
||||
Some(_) => None,
|
||||
None => {
|
||||
table[irq as usize] = Some(handle);
|
||||
Some(irq)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn irq_remove_handle(irq: u8) -> bool {
|
||||
// TODO: ioapic redirection entries associated with this should be reset.
|
||||
info!("IRQ remove handle {:#x?}", irq);
|
||||
let irq = irq as usize;
|
||||
let mut table = IRQ_TABLE.lock();
|
||||
match table[irq] {
|
||||
Some(_) => {
|
||||
table[irq] = None;
|
||||
false
|
||||
}
|
||||
None => true,
|
||||
}
|
||||
}
|
||||
|
||||
fn irq_overwrite_handler(irq: u8, handle: Box<dyn Fn() + Send + Sync>) -> bool {
|
||||
info!("IRQ overwrite handle {:#x?}", irq);
|
||||
let mut table = IRQ_TABLE.lock();
|
||||
let set = table[irq as usize].is_none();
|
||||
table[irq as usize] = Some(handle);
|
||||
set
|
||||
}
|
||||
|
||||
#[export_name = "hal_msi_allocate_block"]
|
||||
pub fn msi_allocate_block(irq_num: u32) -> Option<(usize, usize)> {
|
||||
info!("hal_irq_allocate_block: count={:#x?}", irq_num);
|
||||
let irq_num = u32::next_power_of_two(irq_num) as usize;
|
||||
let mut irq_start = 0x20;
|
||||
let mut irq_cur = irq_start;
|
||||
let mut table = IRQ_TABLE.lock();
|
||||
while irq_cur < TABLE_SIZE && irq_cur < irq_start + irq_num {
|
||||
if table[irq_cur].is_none() {
|
||||
irq_cur += 1;
|
||||
} else {
|
||||
irq_start = (irq_cur - irq_cur % irq_num) + irq_num;
|
||||
irq_cur = irq_start;
|
||||
}
|
||||
}
|
||||
for i in irq_start..irq_start + irq_num {
|
||||
table[i] = Some(Box::new(|| {}));
|
||||
}
|
||||
info!(
|
||||
"hal_irq_allocate_block: start={:#x?} num={:#x?}",
|
||||
irq_start, irq_num
|
||||
);
|
||||
Some((irq_start, irq_num))
|
||||
}
|
||||
|
||||
#[export_name = "hal_msi_free_block"]
|
||||
pub fn msi_free_block(irq_start: u32, irq_num: u32) {
|
||||
let mut table = IRQ_TABLE.lock();
|
||||
for i in irq_start..irq_start + irq_num {
|
||||
table[i as usize] = None;
|
||||
}
|
||||
}
|
||||
|
||||
#[export_name = "hal_msi_register_handler"]
|
||||
pub fn msi_register_handler(
|
||||
irq_start: u32,
|
||||
_irq_num: u32,
|
||||
msi_id: u32,
|
||||
handle: Box<dyn Fn() + Send + Sync>,
|
||||
) {
|
||||
irq_overwrite_handler((irq_start + msi_id) as u8, handle);
|
||||
}
|
||||
|
||||
#[export_name = "hal_irq_enable"]
|
||||
pub fn irq_enable(irq: u32) {
|
||||
info!("irq_enable irq={:#x?}", irq);
|
||||
// if irq == 1 {
|
||||
// irq_enable_raw(irq as u8, irq as u8 + IRQ0);
|
||||
// return;
|
||||
// }
|
||||
if let Some(x) = get_ioapic(irq) {
|
||||
let mut ioapic = ioapic_controller(&x);
|
||||
ioapic.enable((irq - x.global_system_interrupt_base) as u8, 0);
|
||||
}
|
||||
}
|
||||
|
||||
fn irq_enable_raw(irq: u8, vector: u8) {
|
||||
info!("irq_enable_raw: irq={:#x?}, vector={:#x?}", irq, vector);
|
||||
let mut ioapic = unsafe { IoApic::new(phys_to_virt(super::IOAPIC_ADDR)) };
|
||||
ioapic.set_irq_vector(irq, vector);
|
||||
ioapic.enable(irq, 0)
|
||||
}
|
||||
|
||||
#[export_name = "hal_irq_disable"]
|
||||
pub fn irq_disable(irq: u32) {
|
||||
info!("irq_disable");
|
||||
if let Some(x) = get_ioapic(irq) {
|
||||
let mut ioapic = ioapic_controller(&x);
|
||||
ioapic.disable((irq - x.global_system_interrupt_base) as u8);
|
||||
}
|
||||
}
|
||||
|
||||
#[export_name = "hal_irq_configure"]
|
||||
pub fn irq_configure(vector: u32, trig_mode: bool, polarity: bool) -> bool {
|
||||
info!(
|
||||
"irq_configure: vector={:#x?}, trig_mode={:#x?}, polarity={:#x?}",
|
||||
vector, trig_mode, polarity
|
||||
);
|
||||
let dest = super::apic_local_id();
|
||||
get_ioapic(vector)
|
||||
.map(|x| {
|
||||
let mut ioapic = ioapic_controller(&x);
|
||||
ioapic.config(
|
||||
(vector - x.global_system_interrupt_base) as u8,
|
||||
0,
|
||||
dest,
|
||||
trig_mode,
|
||||
polarity,
|
||||
false, /* physical */
|
||||
true, /* mask */
|
||||
);
|
||||
})
|
||||
.is_some()
|
||||
}
|
||||
|
||||
fn ioapic_maxinstr(ioapic_addr: u32) -> Option<u8> {
|
||||
let mut table = MAX_INSTR_TABLE.lock();
|
||||
for (addr, v) in table.iter() {
|
||||
if *addr == ioapic_addr as usize {
|
||||
return Some(*v);
|
||||
}
|
||||
}
|
||||
let mut ioapic = unsafe { IoApic::new(phys_to_virt(ioapic_addr as usize)) };
|
||||
let v = ioapic.maxintr();
|
||||
table.push((ioapic_addr as usize, v));
|
||||
Some(v)
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
static ref MAX_INSTR_TABLE: Mutex<Vec<(usize, u8)>> = Mutex::default();
|
||||
}
|
||||
|
||||
#[export_name = "hal_irq_isvalid"]
|
||||
pub fn is_valid_irq(irq: u32) -> bool {
|
||||
trace!("irq_is_valid: irq={:#x?}", irq);
|
||||
get_ioapic(irq).is_some()
|
||||
}
|
||||
|
||||
fn breakpoint() {
|
||||
panic!("\nEXCEPTION: Breakpoint");
|
||||
}
|
||||
|
||||
fn double_fault(tf: &TrapFrame) {
|
||||
panic!("\nEXCEPTION: Double Fault\n{:#x?}", tf);
|
||||
}
|
||||
|
||||
fn page_fault(tf: &mut TrapFrame) {
|
||||
panic!("\nEXCEPTION: Page Fault\n{:#x?}", tf);
|
||||
}
|
||||
|
||||
fn timer() {
|
||||
super::timer_tick();
|
||||
}
|
||||
|
||||
fn com1() {
|
||||
let c = super::COM1.lock().receive();
|
||||
super::serial_put(c);
|
||||
}
|
||||
|
||||
fn keyboard() {
|
||||
use pc_keyboard::{DecodedKey, KeyCode};
|
||||
if let Some(key) = super::keyboard::receive() {
|
||||
match key {
|
||||
DecodedKey::Unicode(c) => super::serial_put(c as u8),
|
||||
DecodedKey::RawKey(code) => {
|
||||
let s = match code {
|
||||
KeyCode::ArrowUp => "\u{1b}[A",
|
||||
KeyCode::ArrowDown => "\u{1b}[B",
|
||||
KeyCode::ArrowRight => "\u{1b}[C",
|
||||
KeyCode::ArrowLeft => "\u{1b}[D",
|
||||
_ => "",
|
||||
};
|
||||
for c in s.bytes() {
|
||||
super::serial_put(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Reference: https://wiki.osdev.org/Exceptions
|
||||
const DivideError: u8 = 0;
|
||||
const Debug: u8 = 1;
|
||||
const NonMaskableInterrupt: u8 = 2;
|
||||
const Breakpoint: u8 = 3;
|
||||
const Overflow: u8 = 4;
|
||||
const BoundRangeExceeded: u8 = 5;
|
||||
const InvalidOpcode: u8 = 6;
|
||||
const DeviceNotAvailable: u8 = 7;
|
||||
const DoubleFault: u8 = 8;
|
||||
const CoprocessorSegmentOverrun: u8 = 9;
|
||||
const InvalidTSS: u8 = 10;
|
||||
const SegmentNotPresent: u8 = 11;
|
||||
const StackSegmentFault: u8 = 12;
|
||||
const GeneralProtectionFault: u8 = 13;
|
||||
const PageFault: u8 = 14;
|
||||
const FloatingPointException: u8 = 16;
|
||||
const AlignmentCheck: u8 = 17;
|
||||
const MachineCheck: u8 = 18;
|
||||
const SIMDFloatingPointException: u8 = 19;
|
||||
const VirtualizationException: u8 = 20;
|
||||
const SecurityException: u8 = 30;
|
||||
|
||||
const IRQ0: u8 = 32;
|
||||
|
||||
// IRQ
|
||||
const Timer: u8 = 0;
|
||||
const Keyboard: u8 = 1;
|
||||
const COM2: u8 = 3;
|
||||
const COM1: u8 = 4;
|
||||
const Mouse: u8 = 12;
|
||||
const IDE: u8 = 14;
|
||||
const Error: u8 = 19;
|
||||
const Spurious: u8 = 31;
|
|
@ -1,524 +0,0 @@
|
|||
use {
|
||||
super::super::*,
|
||||
acpi::{parse_rsdp, Acpi, AcpiHandler, PhysicalMapping},
|
||||
alloc::{collections::VecDeque, vec::Vec},
|
||||
apic::{LocalApic, XApic},
|
||||
core::arch::x86_64::{__cpuid, _mm_clflush, _mm_mfence},
|
||||
core::convert::TryFrom,
|
||||
core::fmt::{Arguments, Write},
|
||||
core::ptr::NonNull,
|
||||
core::time::Duration,
|
||||
git_version::git_version,
|
||||
kernel_hal::dev::fb::{ColorDepth, ColorFormat, FramebufferInfo, FRAME_BUFFER},
|
||||
kernel_hal::{HalError, paging::PageTableTrait, HalResult as Result},
|
||||
rcore_console::{Console, ConsoleOnGraphic, DrawTarget, Pixel, Rgb888, Size},
|
||||
spin::Mutex,
|
||||
uart_16550::SerialPort,
|
||||
x86_64::{
|
||||
instructions::port::Port,
|
||||
registers::control::{Cr2, Cr3, Cr3Flags, Cr4, Cr4Flags},
|
||||
structures::paging::{PageTableFlags as PTF, *},
|
||||
},
|
||||
};
|
||||
|
||||
mod acpi_table;
|
||||
mod interrupt;
|
||||
mod keyboard;
|
||||
|
||||
/// Page Table
|
||||
#[repr(C)]
|
||||
pub struct PageTableImpl {
|
||||
root_paddr: PhysAddr,
|
||||
}
|
||||
|
||||
impl PageTableImpl {
|
||||
#[export_name = "hal_pt_current"]
|
||||
pub fn current() -> Self {
|
||||
PageTableImpl {
|
||||
root_paddr: Cr3::read().0.start_address().as_u64() as _,
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a new `PageTable`.
|
||||
#[allow(clippy::new_without_default)]
|
||||
#[export_name = "hal_pt_new"]
|
||||
pub fn new() -> Self {
|
||||
let root_frame = Frame::alloc().expect("failed to alloc frame");
|
||||
let root_vaddr = phys_to_virt(root_frame.paddr);
|
||||
let root = unsafe { &mut *(root_vaddr as *mut PageTable) };
|
||||
root.zero();
|
||||
map_kernel(root_vaddr as _, frame_to_page_table(Cr3::read().0) as _);
|
||||
trace!("create page table @ {:#x}", root_frame.paddr);
|
||||
PageTableImpl {
|
||||
root_paddr: root_frame.paddr,
|
||||
}
|
||||
}
|
||||
|
||||
fn get(&mut self) -> OffsetPageTable<'_> {
|
||||
let root_vaddr = phys_to_virt(self.root_paddr);
|
||||
let root = unsafe { &mut *(root_vaddr as *mut PageTable) };
|
||||
let offset = x86_64::VirtAddr::new(phys_to_virt(0) as u64);
|
||||
unsafe { OffsetPageTable::new(root, offset) }
|
||||
}
|
||||
}
|
||||
|
||||
impl PageTableTrait for PageTableImpl {
|
||||
/// Map the page of `vaddr` to the frame of `paddr` with `flags`.
|
||||
#[export_name = "hal_pt_map"]
|
||||
fn map(&mut self, vaddr: VirtAddr, paddr: PhysAddr, flags: MMUFlags) -> Result<()> {
|
||||
let mut pt = self.get();
|
||||
unsafe {
|
||||
pt.map_to_with_table_flags(
|
||||
Page::<Size4KiB>::from_start_address(x86_64::VirtAddr::new(vaddr as u64)).unwrap(),
|
||||
PhysFrame::from_start_address(x86_64::PhysAddr::new(paddr as u64)).unwrap(),
|
||||
flags.to_ptf(),
|
||||
PTF::PRESENT | PTF::WRITABLE | PTF::USER_ACCESSIBLE,
|
||||
&mut FrameAllocatorImpl,
|
||||
)
|
||||
.unwrap()
|
||||
.flush();
|
||||
};
|
||||
debug!(
|
||||
"map: {:x?} -> {:x?}, flags={:?} in {:#x?}",
|
||||
vaddr, paddr, flags, self.root_paddr
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Unmap the page of `vaddr`.
|
||||
#[export_name = "hal_pt_unmap"]
|
||||
fn unmap(&mut self, vaddr: VirtAddr) -> Result<()> {
|
||||
let mut pt = self.get();
|
||||
let page =
|
||||
Page::<Size4KiB>::from_start_address(x86_64::VirtAddr::new(vaddr as u64)).unwrap();
|
||||
// This is a workaround to an issue in the x86-64 crate
|
||||
// A page without PRESENT bit is not unmappable AND mapable
|
||||
// So we add PRESENT bit here
|
||||
unsafe {
|
||||
pt.update_flags(page, PTF::PRESENT | PTF::NO_EXECUTE).ok();
|
||||
}
|
||||
match pt.unmap(page) {
|
||||
Ok((_, flush)) => {
|
||||
flush.flush();
|
||||
trace!("unmap: {:x?} in {:#x?}", vaddr, self.root_paddr);
|
||||
}
|
||||
Err(mapper::UnmapError::PageNotMapped) => {
|
||||
trace!(
|
||||
"unmap not mapped, skip: {:x?} in {:#x?}",
|
||||
vaddr,
|
||||
self.root_paddr
|
||||
);
|
||||
return Ok(());
|
||||
}
|
||||
Err(err) => {
|
||||
debug!(
|
||||
"unmap failed: {:x?} err={:x?} in {:#x?}",
|
||||
vaddr, err, self.root_paddr
|
||||
);
|
||||
return Err(HalError);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Change the `flags` of the page of `vaddr`.
|
||||
#[export_name = "hal_pt_protect"]
|
||||
fn protect(&mut self, vaddr: VirtAddr, flags: MMUFlags) -> Result<()> {
|
||||
let mut pt = self.get();
|
||||
let page =
|
||||
Page::<Size4KiB>::from_start_address(x86_64::VirtAddr::new(vaddr as u64)).unwrap();
|
||||
if let Ok(flush) = unsafe { pt.update_flags(page, flags.to_ptf()) } {
|
||||
flush.flush();
|
||||
}
|
||||
trace!("protect: {:x?}, flags={:?}", vaddr, flags);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Query the physical address which the page of `vaddr` maps to.
|
||||
#[export_name = "hal_pt_query"]
|
||||
fn query(&mut self, vaddr: VirtAddr) -> Result<PhysAddr> {
|
||||
let pt = self.get();
|
||||
let ret = pt
|
||||
.translate_addr(x86_64::VirtAddr::new(vaddr as u64))
|
||||
.map(|addr| addr.as_u64() as PhysAddr)
|
||||
.ok_or(HalError);
|
||||
trace!("query: {:x?} => {:x?}", vaddr, ret);
|
||||
ret
|
||||
}
|
||||
|
||||
/// Get the physical address of root page table.
|
||||
#[export_name = "hal_pt_table_phys"]
|
||||
fn table_phys(&self) -> PhysAddr {
|
||||
self.root_paddr
|
||||
}
|
||||
|
||||
// /// Activate this page table
|
||||
// #[export_name = "hal_pt_activate"]
|
||||
// fn activate(&self) {
|
||||
// unimplemented!()
|
||||
// }
|
||||
}
|
||||
|
||||
/// Set page table.
|
||||
///
|
||||
/// # Safety
|
||||
/// This function will set CR3 to `vmtoken`.
|
||||
pub unsafe fn set_page_table(vmtoken: usize) {
|
||||
let frame = PhysFrame::containing_address(x86_64::PhysAddr::new(vmtoken as _));
|
||||
if Cr3::read().0 == frame {
|
||||
return;
|
||||
}
|
||||
Cr3::write(frame, Cr3Flags::empty());
|
||||
debug!("set page_table @ {:#x}", vmtoken);
|
||||
}
|
||||
|
||||
fn frame_to_page_table(frame: PhysFrame) -> *mut PageTable {
|
||||
let vaddr = phys_to_virt(frame.start_address().as_u64() as usize);
|
||||
vaddr as *mut PageTable
|
||||
}
|
||||
|
||||
trait FlagsExt {
|
||||
fn to_ptf(self) -> PTF;
|
||||
}
|
||||
|
||||
impl FlagsExt for MMUFlags {
|
||||
fn to_ptf(self) -> PTF {
|
||||
let mut flags = PTF::empty();
|
||||
if self.contains(MMUFlags::READ) {
|
||||
flags |= PTF::PRESENT;
|
||||
}
|
||||
if self.contains(MMUFlags::WRITE) {
|
||||
flags |= PTF::WRITABLE;
|
||||
}
|
||||
if !self.contains(MMUFlags::EXECUTE) {
|
||||
flags |= PTF::NO_EXECUTE;
|
||||
}
|
||||
if self.contains(MMUFlags::USER) {
|
||||
flags |= PTF::USER_ACCESSIBLE;
|
||||
}
|
||||
let cache_policy = (self.bits() & 3) as u32; // 最低三位用于储存缓存策略
|
||||
match CachePolicy::try_from(cache_policy) {
|
||||
Ok(CachePolicy::Cached) => {
|
||||
flags.remove(PTF::WRITE_THROUGH);
|
||||
}
|
||||
Ok(CachePolicy::Uncached) | Ok(CachePolicy::UncachedDevice) => {
|
||||
flags |= PTF::NO_CACHE | PTF::WRITE_THROUGH;
|
||||
}
|
||||
Ok(CachePolicy::WriteCombining) => {
|
||||
flags |= PTF::NO_CACHE | PTF::WRITE_THROUGH;
|
||||
// 当位于level=1时,页面更大,在1<<12位上(0x100)为1
|
||||
// 但是bitflags里面没有这一位。由页表自行管理标记位去吧
|
||||
}
|
||||
Err(_) => unreachable!("invalid cache policy"),
|
||||
}
|
||||
flags
|
||||
}
|
||||
}
|
||||
|
||||
struct FrameAllocatorImpl;
|
||||
|
||||
unsafe impl FrameAllocator<Size4KiB> for FrameAllocatorImpl {
|
||||
fn allocate_frame(&mut self) -> Option<PhysFrame> {
|
||||
Frame::alloc().map(|f| {
|
||||
let paddr = x86_64::PhysAddr::new(f.paddr as u64);
|
||||
PhysFrame::from_start_address(paddr).unwrap()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl FrameDeallocator<Size4KiB> for FrameAllocatorImpl {
|
||||
unsafe fn deallocate_frame(&mut self, frame: PhysFrame) {
|
||||
Frame {
|
||||
paddr: frame.start_address().as_u64() as usize,
|
||||
}
|
||||
.dealloc()
|
||||
}
|
||||
}
|
||||
|
||||
static CONSOLE: Mutex<Option<ConsoleOnGraphic<Framebuffer>>> = Mutex::new(None);
|
||||
|
||||
struct Framebuffer {
|
||||
width: u32,
|
||||
height: u32,
|
||||
buf: &'static mut [u32],
|
||||
}
|
||||
|
||||
impl DrawTarget<Rgb888> for Framebuffer {
|
||||
type Error = core::convert::Infallible;
|
||||
|
||||
fn draw_pixel(&mut self, item: Pixel<Rgb888>) -> core::result::Result<(), Self::Error> {
|
||||
let idx = (item.0.x as u32 + item.0.y as u32 * self.width) as usize;
|
||||
self.buf[idx] = unsafe { core::mem::transmute(item.1) };
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn size(&self) -> Size {
|
||||
Size::new(self.width, self.height)
|
||||
}
|
||||
}
|
||||
|
||||
/// Initialize console on framebuffer.
|
||||
pub fn init_framebuffer(width: u32, height: u32, addr: usize, size: usize) {
|
||||
let vaddr = phys_to_virt(addr);
|
||||
let fb_info = FramebufferInfo {
|
||||
xres: width,
|
||||
yres: height,
|
||||
xres_virtual: width,
|
||||
yres_virtual: height,
|
||||
xoffset: 0,
|
||||
yoffset: 0,
|
||||
depth: ColorDepth::ColorDepth32,
|
||||
format: ColorFormat::RGBA8888,
|
||||
paddr: addr,
|
||||
vaddr,
|
||||
screen_size: size,
|
||||
};
|
||||
*FRAME_BUFFER.write() = Some(fb_info);
|
||||
let console = Console::on_frame_buffer(Framebuffer {
|
||||
width,
|
||||
height,
|
||||
buf: unsafe {
|
||||
core::slice::from_raw_parts_mut(vaddr as *mut u32, (width * height) as usize)
|
||||
},
|
||||
});
|
||||
*CONSOLE.lock() = Some(console);
|
||||
}
|
||||
|
||||
static COM1: Mutex<SerialPort> = Mutex::new(unsafe { SerialPort::new(0x3F8) });
|
||||
|
||||
pub fn putfmt(fmt: Arguments) {
|
||||
COM1.lock().write_fmt(fmt).unwrap();
|
||||
if let Some(console) = CONSOLE.lock().as_mut() {
|
||||
console.write_fmt(fmt).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
static ref STDIN: Mutex<VecDeque<u8>> = Mutex::new(VecDeque::new());
|
||||
static ref STDIN_CALLBACK: Mutex<Vec<Box<dyn Fn() -> bool + Send + Sync>>> =
|
||||
Mutex::new(Vec::new());
|
||||
}
|
||||
|
||||
/// Put a char by serial interrupt handler.
|
||||
fn serial_put(mut x: u8) {
|
||||
if x == b'\r' {
|
||||
x = b'\n';
|
||||
}
|
||||
STDIN.lock().push_back(x);
|
||||
STDIN_CALLBACK.lock().retain(|f| !f());
|
||||
}
|
||||
|
||||
#[export_name = "hal_serial_set_callback"]
|
||||
pub fn serial_set_callback(callback: Box<dyn Fn() -> bool + Send + Sync>) {
|
||||
STDIN_CALLBACK.lock().push(callback);
|
||||
}
|
||||
|
||||
#[export_name = "hal_serial_read"]
|
||||
pub fn serial_read(buf: &mut [u8]) -> usize {
|
||||
let mut stdin = STDIN.lock();
|
||||
let len = stdin.len().min(buf.len());
|
||||
for c in &mut buf[..len] {
|
||||
*c = stdin.pop_front().unwrap();
|
||||
}
|
||||
len
|
||||
}
|
||||
|
||||
#[export_name = "hal_serial_write"]
|
||||
pub fn print_str(s: &str) {
|
||||
putfmt(format_args!("{}", s));
|
||||
}
|
||||
|
||||
/// Get TSC frequency.
|
||||
///
|
||||
/// WARN: This will be very slow on virtual machine since it uses CPUID instruction.
|
||||
fn tsc_frequency() -> u16 {
|
||||
const DEFAULT: u16 = 2600;
|
||||
if let Some(info) = raw_cpuid::CpuId::new().get_processor_frequency_info() {
|
||||
let f = info.processor_base_frequency();
|
||||
return if f == 0 { DEFAULT } else { f };
|
||||
}
|
||||
// FIXME: QEMU, AMD, VirtualBox
|
||||
DEFAULT
|
||||
}
|
||||
|
||||
#[export_name = "hal_timer_now"]
|
||||
pub fn timer_now() -> Duration {
|
||||
let tsc = unsafe { core::arch::x86_64::_rdtsc() };
|
||||
Duration::from_nanos(tsc * 1000 / unsafe { TSC_FREQUENCY } as u64)
|
||||
}
|
||||
|
||||
fn timer_init() {
|
||||
let mut lapic = unsafe { XApic::new(phys_to_virt(LAPIC_ADDR)) };
|
||||
lapic.cpu_init();
|
||||
}
|
||||
|
||||
#[export_name = "hal_apic_local_id"]
|
||||
pub fn apic_local_id() -> u8 {
|
||||
let lapic = unsafe { XApic::new(phys_to_virt(LAPIC_ADDR)) };
|
||||
lapic.id() as u8
|
||||
}
|
||||
|
||||
const LAPIC_ADDR: usize = 0xfee0_0000;
|
||||
const IOAPIC_ADDR: usize = 0xfec0_0000;
|
||||
|
||||
#[export_name = "hal_vdso_constants"]
|
||||
fn vdso_constants() -> VdsoConstants {
|
||||
let tsc_frequency = unsafe { TSC_FREQUENCY };
|
||||
let mut constants = VdsoConstants {
|
||||
max_num_cpus: 1,
|
||||
features: Features {
|
||||
cpu: 0,
|
||||
hw_breakpoint_count: 0,
|
||||
hw_watchpoint_count: 0,
|
||||
},
|
||||
dcache_line_size: 0,
|
||||
icache_line_size: 0,
|
||||
ticks_per_second: tsc_frequency as u64 * 1_000_000,
|
||||
ticks_to_mono_numerator: 1000,
|
||||
ticks_to_mono_denominator: tsc_frequency as u32,
|
||||
physmem: 0,
|
||||
version_string_len: 0,
|
||||
version_string: Default::default(),
|
||||
};
|
||||
constants.set_version_string(git_version!(
|
||||
prefix = "git-",
|
||||
args = ["--always", "--abbrev=40", "--dirty=-dirty"]
|
||||
));
|
||||
constants
|
||||
}
|
||||
|
||||
/// Initialize the HAL.
|
||||
pub fn init(config: Config) {
|
||||
timer_init();
|
||||
interrupt::init();
|
||||
COM1.lock().init();
|
||||
unsafe {
|
||||
// enable global page
|
||||
Cr4::update(|f| f.insert(Cr4Flags::PAGE_GLOBAL));
|
||||
// store config
|
||||
CONFIG = config;
|
||||
// get tsc frequency
|
||||
TSC_FREQUENCY = tsc_frequency();
|
||||
|
||||
// start multi-processors
|
||||
fn ap_main() {
|
||||
info!("processor {} started", apic_local_id());
|
||||
unsafe {
|
||||
trapframe::init();
|
||||
}
|
||||
timer_init();
|
||||
let ap_fn = unsafe { CONFIG.ap_fn };
|
||||
ap_fn()
|
||||
}
|
||||
fn stack_fn(pid: usize) -> usize {
|
||||
// split and reuse the current stack
|
||||
unsafe {
|
||||
let mut stack: usize;
|
||||
asm!("mov {}, rsp", out(reg) stack);
|
||||
stack -= 0x4000 * pid;
|
||||
stack
|
||||
}
|
||||
}
|
||||
x86_smpboot::start_application_processors(ap_main, stack_fn, phys_to_virt);
|
||||
}
|
||||
}
|
||||
|
||||
/// Configuration of HAL.
|
||||
pub struct Config {
|
||||
pub acpi_rsdp: u64,
|
||||
pub smbios: u64,
|
||||
pub ap_fn: fn() -> !,
|
||||
}
|
||||
|
||||
#[export_name = "fetch_fault_vaddr"]
|
||||
pub fn fetch_fault_vaddr() -> VirtAddr {
|
||||
Cr2::read().as_u64() as _
|
||||
}
|
||||
|
||||
/// Get physical address of `acpi_rsdp` and `smbios` on x86_64.
|
||||
#[export_name = "hal_pc_firmware_tables"]
|
||||
pub fn pc_firmware_tables() -> (u64, u64) {
|
||||
unsafe { (CONFIG.acpi_rsdp, CONFIG.smbios) }
|
||||
}
|
||||
|
||||
static mut CONFIG: Config = Config {
|
||||
acpi_rsdp: 0,
|
||||
smbios: 0,
|
||||
ap_fn: || unreachable!(),
|
||||
};
|
||||
|
||||
static mut TSC_FREQUENCY: u16 = 2600;
|
||||
|
||||
/// Build ACPI Table
|
||||
struct AcpiHelper {}
|
||||
impl AcpiHandler for AcpiHelper {
|
||||
unsafe fn map_physical_region<T>(
|
||||
&mut self,
|
||||
physical_address: usize,
|
||||
size: usize,
|
||||
) -> PhysicalMapping<T> {
|
||||
#[allow(non_snake_case)]
|
||||
let OFFSET = 0;
|
||||
let page_start = physical_address / PAGE_SIZE;
|
||||
let page_end = (physical_address + size + PAGE_SIZE - 1) / PAGE_SIZE;
|
||||
PhysicalMapping::<T> {
|
||||
physical_start: physical_address,
|
||||
virtual_start: NonNull::new_unchecked(phys_to_virt(physical_address + OFFSET) as *mut T),
|
||||
mapped_length: size,
|
||||
region_length: PAGE_SIZE * (page_end - page_start),
|
||||
}
|
||||
}
|
||||
fn unmap_physical_region<T>(&mut self, _region: PhysicalMapping<T>) {}
|
||||
}
|
||||
|
||||
#[export_name = "hal_acpi_table"]
|
||||
pub fn get_acpi_table() -> Option<Acpi> {
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
{
|
||||
let mut handler = AcpiHelper {};
|
||||
match unsafe { parse_rsdp(&mut handler, pc_firmware_tables().0 as usize) } {
|
||||
Ok(table) => Some(table),
|
||||
Err(info) => {
|
||||
warn!("get_acpi_table error: {:#x?}", info);
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(not(target_arch = "x86_64"))]
|
||||
None
|
||||
}
|
||||
|
||||
/// IO Port in/out instruction
|
||||
#[export_name = "hal_outpd"]
|
||||
pub fn outpd(port: u16, value: u32) {
|
||||
unsafe {
|
||||
Port::new(port).write(value);
|
||||
}
|
||||
}
|
||||
|
||||
#[export_name = "hal_inpd"]
|
||||
pub fn inpd(port: u16) -> u32 {
|
||||
unsafe { Port::new(port).read() }
|
||||
}
|
||||
|
||||
/// Flush the physical frame.
|
||||
#[export_name = "hal_frame_flush"]
|
||||
pub fn frame_flush(target: PhysAddr) {
|
||||
unsafe {
|
||||
for paddr in (target..target + PAGE_SIZE).step_by(cacheline_size()) {
|
||||
_mm_clflush(phys_to_virt(paddr) as *const u8);
|
||||
}
|
||||
_mm_mfence();
|
||||
}
|
||||
}
|
||||
|
||||
/// Get cache line size in bytes.
|
||||
fn cacheline_size() -> usize {
|
||||
let leaf = unsafe { __cpuid(1).ebx };
|
||||
(((leaf >> 8) & 0xff) << 3) as usize
|
||||
}
|
||||
|
||||
#[export_name = "hal_current_pgtable"]
|
||||
pub fn current_page_table() -> usize {
|
||||
PageTableImpl::current().root_paddr
|
||||
}
|
|
@ -1,252 +0,0 @@
|
|||
//! Zircon HAL implementation for bare metal environment.
|
||||
//!
|
||||
//! This crate implements the following interfaces:
|
||||
//! - `hal_pt_new`
|
||||
//! - `hal_pt_map`
|
||||
//! - `hal_pt_unmap`
|
||||
//! - `hal_pt_protect`
|
||||
//! - `hal_pt_query`
|
||||
//! - `hal_pmem_read`
|
||||
//! - `hal_pmem_write`
|
||||
//!
|
||||
//! And you have to implement these interfaces in addition:
|
||||
//! - `hal_pt_map_kernel`
|
||||
//! - `hal_pmem_base`
|
||||
|
||||
#![no_std]
|
||||
#![feature(asm)]
|
||||
#![feature(llvm_asm)]
|
||||
#![feature(global_asm)]
|
||||
#![feature(linkage)]
|
||||
//#![deny(warnings)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate log;
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
#[macro_use]
|
||||
extern crate lazy_static;
|
||||
|
||||
use alloc::boxed::Box;
|
||||
use core::time::Duration;
|
||||
use core::{
|
||||
future::Future,
|
||||
pin::Pin,
|
||||
task::{Context, Poll},
|
||||
};
|
||||
use kernel_hal::{VirtAddr, PhysAddr, PAGE_SIZE, CachePolicy, MMUFlags};
|
||||
use kernel_hal::vdso::*;
|
||||
use kernel_hal::context::UserContext;
|
||||
use naive_timer::Timer;
|
||||
use spin::Mutex;
|
||||
|
||||
pub mod arch;
|
||||
pub mod drivers;
|
||||
|
||||
pub use self::arch::*;
|
||||
|
||||
#[allow(improper_ctypes)]
|
||||
extern "C" {
|
||||
fn hal_pt_map_kernel(pt: *mut u8, current: *const u8);
|
||||
fn frame_alloc() -> Option<usize>;
|
||||
fn hal_frame_alloc_contiguous(page_num: usize, align_log2: usize) -> Option<usize>;
|
||||
fn frame_dealloc(paddr: &usize);
|
||||
#[link_name = "hal_pmem_base"]
|
||||
static PMEM_BASE: usize;
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct Thread {
|
||||
thread: usize,
|
||||
}
|
||||
|
||||
impl Thread {
|
||||
#[export_name = "hal_thread_spawn"]
|
||||
pub fn spawn(
|
||||
future: Pin<Box<dyn Future<Output = ()> + Send + 'static>>,
|
||||
vmtoken: usize,
|
||||
) -> Self {
|
||||
struct PageTableSwitchWrapper {
|
||||
inner: Mutex<Pin<Box<dyn Future<Output = ()> + Send>>>,
|
||||
vmtoken: usize,
|
||||
}
|
||||
impl Future for PageTableSwitchWrapper {
|
||||
type Output = ();
|
||||
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
unsafe {
|
||||
arch::set_page_table(self.vmtoken);
|
||||
}
|
||||
self.inner.lock().as_mut().poll(cx)
|
||||
}
|
||||
}
|
||||
|
||||
executor::spawn(PageTableSwitchWrapper {
|
||||
inner: Mutex::new(future),
|
||||
vmtoken,
|
||||
});
|
||||
|
||||
Thread { thread: 0 }
|
||||
}
|
||||
|
||||
#[export_name = "hal_thread_set_tid"]
|
||||
pub fn set_tid(_tid: u64, _pid: u64) {}
|
||||
|
||||
#[export_name = "hal_thread_get_tid"]
|
||||
pub fn get_tid() -> (u64, u64) {
|
||||
(0, 0)
|
||||
}
|
||||
}
|
||||
|
||||
#[export_name = "hal_context_run"]
|
||||
pub fn context_run(context: &mut UserContext) {
|
||||
context.run();
|
||||
}
|
||||
|
||||
/// Map kernel for the new page table.
|
||||
///
|
||||
/// `pt` is a page-aligned pointer to the root page table.
|
||||
#[allow(clippy::not_unsafe_ptr_arg_deref)]
|
||||
pub fn map_kernel(pt: *mut u8, current: *const u8) {
|
||||
unsafe {
|
||||
hal_pt_map_kernel(pt, current);
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct Frame {
|
||||
paddr: PhysAddr,
|
||||
}
|
||||
|
||||
impl Frame {
|
||||
#[export_name = "hal_frame_alloc"]
|
||||
pub fn alloc() -> Option<Self> {
|
||||
unsafe { frame_alloc().map(|paddr| Frame { paddr }) }
|
||||
}
|
||||
|
||||
#[export_name = "hal_frame_dealloc"]
|
||||
pub fn dealloc(&mut self) {
|
||||
unsafe {
|
||||
frame_dealloc(&self.paddr);
|
||||
}
|
||||
}
|
||||
|
||||
#[export_name = "hal_zero_frame_paddr"]
|
||||
pub fn zero_frame_addr() -> PhysAddr {
|
||||
#[repr(align(0x1000))]
|
||||
struct Page([u8; PAGE_SIZE]);
|
||||
static ZERO_PAGE: Page = Page([0u8; PAGE_SIZE]);
|
||||
unsafe { ZERO_PAGE.0.as_ptr() as usize - PMEM_BASE }
|
||||
}
|
||||
}
|
||||
|
||||
pub fn phys_to_virt(paddr: PhysAddr) -> VirtAddr {
|
||||
unsafe { PMEM_BASE + paddr }
|
||||
}
|
||||
|
||||
pub fn virt_to_phys(vaddr: VirtAddr) -> PhysAddr {
|
||||
unsafe { vaddr - PMEM_BASE }
|
||||
}
|
||||
|
||||
/// Read physical memory from `paddr` to `buf`.
|
||||
#[export_name = "hal_pmem_read"]
|
||||
pub fn pmem_read(paddr: PhysAddr, buf: &mut [u8]) {
|
||||
trace!("pmem_read: addr={:#x}, len={:#x}", paddr, buf.len());
|
||||
unsafe {
|
||||
(phys_to_virt(paddr) as *const u8).copy_to_nonoverlapping(buf.as_mut_ptr(), buf.len());
|
||||
}
|
||||
}
|
||||
|
||||
/// Write physical memory to `paddr` from `buf`.
|
||||
#[export_name = "hal_pmem_write"]
|
||||
pub fn pmem_write(paddr: PhysAddr, buf: &[u8]) {
|
||||
trace!(
|
||||
"pmem_write: addr={:#x}, len={:#x}, vaddr = {:#x}",
|
||||
paddr,
|
||||
buf.len(),
|
||||
phys_to_virt(paddr)
|
||||
);
|
||||
unsafe {
|
||||
buf.as_ptr()
|
||||
.copy_to_nonoverlapping(phys_to_virt(paddr) as _, buf.len());
|
||||
}
|
||||
}
|
||||
|
||||
/// Zero physical memory at `[paddr, paddr + len)`
|
||||
#[export_name = "hal_pmem_zero"]
|
||||
pub fn pmem_zero(paddr: PhysAddr, len: usize) {
|
||||
trace!("pmem_zero: addr={:#x}, len={:#x}", paddr, len);
|
||||
unsafe {
|
||||
core::ptr::write_bytes(phys_to_virt(paddr) as *mut u8, 0, len);
|
||||
}
|
||||
}
|
||||
|
||||
/// Copy content of `src` frame to `target` frame
|
||||
#[export_name = "hal_frame_copy"]
|
||||
pub fn frame_copy(src: PhysAddr, target: PhysAddr) {
|
||||
trace!("frame_copy: {:#x} <- {:#x}", target, src);
|
||||
unsafe {
|
||||
let buf = phys_to_virt(src) as *const u8;
|
||||
buf.copy_to_nonoverlapping(phys_to_virt(target) as _, PAGE_SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
/// Zero `target` frame.
|
||||
#[export_name = "hal_frame_zero"]
|
||||
pub fn frame_zero_in_range(target: PhysAddr, start: usize, end: usize) {
|
||||
assert!(start < PAGE_SIZE && end <= PAGE_SIZE);
|
||||
trace!("frame_zero: {:#x?}", target);
|
||||
unsafe {
|
||||
core::ptr::write_bytes(phys_to_virt(target + start) as *mut u8, 0, end - start);
|
||||
}
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
pub static ref NAIVE_TIMER: Mutex<Timer> = Mutex::new(Timer::default());
|
||||
}
|
||||
|
||||
#[export_name = "hal_timer_set"]
|
||||
pub fn timer_set(deadline: Duration, callback: Box<dyn FnOnce(Duration) + Send + Sync>) {
|
||||
NAIVE_TIMER.lock().add(deadline, callback);
|
||||
}
|
||||
|
||||
#[export_name = "hal_timer_tick"]
|
||||
pub fn timer_tick() {
|
||||
let now = arch::timer_now();
|
||||
NAIVE_TIMER.lock().expire(now);
|
||||
}
|
||||
|
||||
/// Initialize the HAL.
|
||||
pub fn init(config: Config) {
|
||||
unsafe {
|
||||
trapframe::init();
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "riscv64")]
|
||||
trace!("hal dtb: {:#x}", config.dtb);
|
||||
|
||||
arch::init(config);
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" fn hal_pt_map_kernel(_pt: *mut u8, _current: *const u8) {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" fn hal_frame_alloc() -> Option<PhysAddr> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" fn hal_frame_dealloc(_paddr: &PhysAddr) {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
#[export_name = "hal_pmem_base"]
|
||||
static PMEM_BASE: usize = 0;
|
||||
}
|
|
@ -30,21 +30,21 @@ async-std = { version = "1.9", optional = true }
|
|||
|
||||
# Bare-metal mode
|
||||
[target.'cfg(target_os = "none")'.dependencies]
|
||||
# executor = { git = "https://github.com/rcore-os/executor.git", rev = "a2d02ee9" }
|
||||
# naive-timer = "0.1.0"
|
||||
# lazy_static = { version = "1.4", features = ["spin_no_std"] }
|
||||
executor = { git = "https://github.com/rcore-os/executor.git", rev = "a2d02ee9" }
|
||||
naive-timer = "0.1.0"
|
||||
lazy_static = { version = "1.4", features = ["spin_no_std"] }
|
||||
# rcore-fs = { git = "https://github.com/rcore-os/rcore-fs", rev = "6df6cd2" }
|
||||
# device_tree = { git = "https://github.com/rcore-os/device_tree-rs" }
|
||||
# virtio-drivers = { git = "https://github.com/rcore-os/virtio-drivers", rev = "568276" }
|
||||
|
||||
# Bare-metal mode on x86_64
|
||||
[target.'cfg(all(target_os = "none", target_arch = "x86_64"))'.dependencies]
|
||||
# x86_64 = "0.14"
|
||||
# uart_16550 = "=0.2.15"
|
||||
# raw-cpuid = "9.0"
|
||||
x86_64 = "0.14"
|
||||
uart_16550 = "=0.2.15"
|
||||
raw-cpuid = "9.0"
|
||||
apic = { git = "https://github.com/rcore-os/apic-rs", rev = "fb86bd7" }
|
||||
x86-smpboot = { git = "https://github.com/rcore-os/x86-smpboot", rev = "43ffedf" }
|
||||
# pc-keyboard = "0.5"
|
||||
# apic = { git = "https://github.com/rcore-os/apic-rs", rev = "fb86bd7" }
|
||||
# x86-smpboot = { git = "https://github.com/rcore-os/x86-smpboot", rev = "43ffedf" }
|
||||
# rcore-console = { git = "https://github.com/rcore-os/rcore-console", default-features = false, rev = "a980897b" }
|
||||
# ps2-mouse = { git = "https://github.com/YXL76/ps2-mouse", branch = "feat" }
|
||||
|
||||
|
|
|
@ -1,20 +1,62 @@
|
|||
#![allow(dead_code)]
|
||||
use crate::get_acpi_table;
|
||||
pub use acpi::{
|
||||
interrupt::{InterruptModel, InterruptSourceOverride, IoApic, Polarity, TriggerMode},
|
||||
Acpi,
|
||||
};
|
||||
|
||||
use alloc::vec::Vec;
|
||||
use lazy_static::*;
|
||||
use core::ptr::NonNull;
|
||||
|
||||
use acpi::interrupt::{InterruptModel, InterruptSourceOverride, IoApic, Polarity, TriggerMode};
|
||||
use acpi::{parse_rsdp, Acpi, AcpiHandler, PhysicalMapping};
|
||||
use spin::Mutex;
|
||||
|
||||
use super::super::mem::phys_to_virt;
|
||||
use crate::PAGE_SIZE;
|
||||
|
||||
pub struct AcpiTable {
|
||||
inner: Acpi,
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
lazy_static::lazy_static! {
|
||||
static ref ACPI_TABLE: Mutex<Option<AcpiTable>> = Mutex::default();
|
||||
}
|
||||
|
||||
/// Build ACPI Table
|
||||
struct AcpiHelper;
|
||||
|
||||
impl AcpiHandler for AcpiHelper {
|
||||
unsafe fn map_physical_region<T>(
|
||||
&mut self,
|
||||
physical_address: usize,
|
||||
size: usize,
|
||||
) -> PhysicalMapping<T> {
|
||||
#[allow(non_snake_case)]
|
||||
let OFFSET = 0;
|
||||
let page_start = physical_address / PAGE_SIZE;
|
||||
let page_end = (physical_address + size + PAGE_SIZE - 1) / PAGE_SIZE;
|
||||
PhysicalMapping::<T> {
|
||||
physical_start: physical_address,
|
||||
virtual_start: NonNull::new_unchecked(phys_to_virt(physical_address + OFFSET) as *mut T),
|
||||
mapped_length: size,
|
||||
region_length: PAGE_SIZE * (page_end - page_start),
|
||||
}
|
||||
}
|
||||
fn unmap_physical_region<T>(&mut self, _region: PhysicalMapping<T>) {}
|
||||
}
|
||||
|
||||
fn get_acpi_table() -> Option<Acpi> {
|
||||
let mut handler = AcpiHelper;
|
||||
match unsafe {
|
||||
parse_rsdp(
|
||||
&mut handler,
|
||||
super::special::pc_firmware_tables().0 as usize,
|
||||
)
|
||||
} {
|
||||
Ok(table) => Some(table),
|
||||
Err(info) => {
|
||||
warn!("get_acpi_table error: {:#x?}", info);
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AcpiTable {
|
||||
fn initialize_check() {
|
||||
#[cfg(target_arch = "x86_64")]
|
|
@ -0,0 +1,22 @@
|
|||
use apic::{IoApic, LocalApic, XApic};
|
||||
|
||||
use super::super::mem::phys_to_virt;
|
||||
|
||||
const LAPIC_ADDR: usize = 0xfee0_0000;
|
||||
const IOAPIC_ADDR: usize = 0xfec0_0000;
|
||||
|
||||
pub fn get_lapic() -> XApic {
|
||||
unsafe { XApic::new(phys_to_virt(LAPIC_ADDR)) }
|
||||
}
|
||||
|
||||
pub fn get_ioapic() -> IoApic {
|
||||
unsafe { IoApic::new(phys_to_virt(IOAPIC_ADDR)) }
|
||||
}
|
||||
|
||||
pub fn lapic_id() -> u8 {
|
||||
get_lapic().id() as u8
|
||||
}
|
||||
|
||||
pub fn init() {
|
||||
get_lapic().cpu_init();
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
use x86_64::registers::control::Cr2;
|
||||
|
||||
use crate::VirtAddr;
|
||||
|
||||
hal_fn_impl! {
|
||||
impl mod crate::defs::context {
|
||||
fn context_run(context: &mut UserContext) {
|
||||
context.run();
|
||||
}
|
||||
|
||||
fn fetch_fault_vaddr() -> VirtAddr {
|
||||
Cr2::read().as_u64() as _
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
lazy_static::lazy_static! {
|
||||
static ref TSC_FREQUENCY: u16 = {
|
||||
const DEFAULT: u16 = 2600;
|
||||
if let Some(info) = raw_cpuid::CpuId::new().get_processor_frequency_info() {
|
||||
let f = info.processor_base_frequency();
|
||||
return if f == 0 { DEFAULT } else { f };
|
||||
}
|
||||
// FIXME: QEMU, AMD, VirtualBox
|
||||
DEFAULT
|
||||
};
|
||||
}
|
||||
|
||||
hal_fn_impl! {
|
||||
impl mod crate::defs::cpu {
|
||||
fn cpu_id() -> u8 {
|
||||
super::apic::lapic_id()
|
||||
}
|
||||
|
||||
fn cpu_frequency() -> u16 {
|
||||
*TSC_FREQUENCY
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,369 @@
|
|||
#![allow(dead_code)]
|
||||
#![allow(non_upper_case_globals)]
|
||||
|
||||
use alloc::{boxed::Box, vec::Vec};
|
||||
|
||||
use apic::IoApic;
|
||||
use spin::Mutex;
|
||||
|
||||
use super::super::mem::phys_to_virt;
|
||||
use super::acpi_table::AcpiTable;
|
||||
|
||||
const IRQ0: u8 = 32;
|
||||
|
||||
// IRQ
|
||||
const Timer: u8 = 0;
|
||||
const Keyboard: u8 = 1;
|
||||
const COM2: u8 = 3;
|
||||
const COM1: u8 = 4;
|
||||
const Mouse: u8 = 12;
|
||||
const IDE: u8 = 14;
|
||||
const Error: u8 = 19;
|
||||
const Spurious: u8 = 31;
|
||||
|
||||
const IO_APIC_NUM_REDIRECTIONS: u8 = 120;
|
||||
const TABLE_SIZE: usize = 256;
|
||||
|
||||
type InterruptHandler = Box<dyn Fn() + Send + Sync>;
|
||||
|
||||
lazy_static::lazy_static! {
|
||||
static ref IRQ_TABLE: Mutex<Vec<Option<InterruptHandler>>> = Default::default();
|
||||
static ref MAX_INSTR_TABLE: Mutex<Vec<(usize, u8)>> = Mutex::default();
|
||||
}
|
||||
|
||||
/*
|
||||
lazy_static! {
|
||||
static ref MOUSE: Mutex<Mouse> = Mutex::new(Mouse::new());
|
||||
static ref MOUSE_CALLBACK: Mutex<Vec<Box<dyn Fn([u8; 3]) + Send + Sync>>> =
|
||||
Mutex::new(Vec::new());
|
||||
}
|
||||
|
||||
#[export_name = "hal_mouse_set_callback"]
|
||||
pub fn mouse_set_callback(callback: Box<dyn Fn([u8; 3]) + Send + Sync>) {
|
||||
MOUSE_CALLBACK.lock().push(callback);
|
||||
}
|
||||
|
||||
fn mouse_on_complete(mouse_state: MouseState) {
|
||||
debug!("mouse state: {:?}", mouse_state);
|
||||
MOUSE_CALLBACK.lock().iter().for_each(|callback| {
|
||||
callback([
|
||||
mouse_state.get_flags().bits(),
|
||||
mouse_state.get_x() as u8,
|
||||
mouse_state.get_y() as u8,
|
||||
]);
|
||||
});
|
||||
}
|
||||
|
||||
fn mouse() {
|
||||
use x86_64::instructions::port::PortReadOnly;
|
||||
let mut port = PortReadOnly::new(0x60);
|
||||
let packet = unsafe { port.read() };
|
||||
MOUSE.lock().process_packet(packet);
|
||||
}
|
||||
*/
|
||||
|
||||
fn ioapic_maxinstr(ioapic_addr: u32) -> Option<u8> {
|
||||
let mut table = MAX_INSTR_TABLE.lock();
|
||||
for (addr, v) in table.iter() {
|
||||
if *addr == ioapic_addr as usize {
|
||||
return Some(*v);
|
||||
}
|
||||
}
|
||||
let mut ioapic = unsafe { IoApic::new(phys_to_virt(ioapic_addr as usize)) };
|
||||
let v = ioapic.maxintr();
|
||||
table.push((ioapic_addr as usize, v));
|
||||
Some(v)
|
||||
}
|
||||
|
||||
unsafe fn init_ioapic() {
|
||||
for ioapic in AcpiTable::get_ioapic() {
|
||||
info!("Ioapic found: {:#x?}", ioapic);
|
||||
let mut ip = IoApic::new(phys_to_virt(ioapic.address as usize));
|
||||
ip.disable_all();
|
||||
}
|
||||
let mut ip = super::apic::get_ioapic();
|
||||
ip.disable_all();
|
||||
}
|
||||
|
||||
fn get_ioapic(irq: u32) -> Option<acpi::interrupt::IoApic> {
|
||||
for i in AcpiTable::get_ioapic() {
|
||||
let num_instr = core::cmp::min(
|
||||
ioapic_maxinstr(i.address).unwrap(),
|
||||
IO_APIC_NUM_REDIRECTIONS - 1,
|
||||
);
|
||||
if i.global_system_interrupt_base <= irq
|
||||
&& irq <= i.global_system_interrupt_base + num_instr as u32
|
||||
{
|
||||
return Some(i);
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn ioapic_controller(i: &acpi::interrupt::IoApic) -> IoApic {
|
||||
unsafe { IoApic::new(phys_to_virt(i.address as usize)) }
|
||||
}
|
||||
|
||||
/// Add a handler to IRQ table. Return the specified irq or an allocated irq on success
|
||||
fn irq_add_handler(irq: u8, handler: InterruptHandler) -> Option<u8> {
|
||||
info!("IRQ add handler {:#x?}", irq);
|
||||
let mut table = IRQ_TABLE.lock();
|
||||
// allocate a valid irq number
|
||||
if irq == 0 {
|
||||
let mut id = 0x20;
|
||||
while id < table.len() {
|
||||
if table[id].is_none() {
|
||||
table[id] = Some(handler);
|
||||
return Some(id as u8);
|
||||
}
|
||||
id += 1;
|
||||
}
|
||||
return None;
|
||||
}
|
||||
match table[irq as usize] {
|
||||
Some(_) => None,
|
||||
None => {
|
||||
table[irq as usize] = Some(handler);
|
||||
Some(irq)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn irq_remove_handler(irq: u8) -> bool {
|
||||
// TODO: ioapic redirection entries associated with this should be reset.
|
||||
info!("IRQ remove handler {:#x?}", irq);
|
||||
let irq = irq as usize;
|
||||
let mut table = IRQ_TABLE.lock();
|
||||
match table[irq] {
|
||||
Some(_) => {
|
||||
table[irq] = None;
|
||||
false
|
||||
}
|
||||
None => true,
|
||||
}
|
||||
}
|
||||
|
||||
fn irq_overwrite_handler(irq: u8, handler: Box<dyn Fn() + Send + Sync>) -> bool {
|
||||
info!("IRQ overwrite handle {:#x?}", irq);
|
||||
let mut table = IRQ_TABLE.lock();
|
||||
let set = table[irq as usize].is_none();
|
||||
table[irq as usize] = Some(handler);
|
||||
set
|
||||
}
|
||||
|
||||
hal_fn_impl! {
|
||||
impl mod crate::defs::interrupt {
|
||||
fn enable_irq(irq: u32) {
|
||||
info!("enable_irq irq={:#x?}", irq);
|
||||
// if irq == 1 {
|
||||
// irq_enable_raw(irq as u8, irq as u8 + IRQ0);
|
||||
// return;
|
||||
// }
|
||||
if let Some(x) = get_ioapic(irq) {
|
||||
let mut ioapic = ioapic_controller(&x);
|
||||
ioapic.enable((irq - x.global_system_interrupt_base) as u8, 0);
|
||||
}
|
||||
}
|
||||
|
||||
fn disable_irq(irq: u32) {
|
||||
info!("disable_irq");
|
||||
if let Some(x) = get_ioapic(irq) {
|
||||
let mut ioapic = ioapic_controller(&x);
|
||||
ioapic.disable((irq - x.global_system_interrupt_base) as u8);
|
||||
}
|
||||
}
|
||||
|
||||
fn is_valid_irq(irq: u32) -> bool {
|
||||
trace!("is_valid_irq: irq={:#x?}", irq);
|
||||
get_ioapic(irq).is_some()
|
||||
}
|
||||
|
||||
fn configure_irq(vector: u32, trig_mode: bool, polarity: bool) -> bool {
|
||||
info!(
|
||||
"configure_irq: vector={:#x?}, trig_mode={:#x?}, polarity={:#x?}",
|
||||
vector, trig_mode, polarity
|
||||
);
|
||||
let dest = super::apic::lapic_id();
|
||||
get_ioapic(vector)
|
||||
.map(|x| {
|
||||
let mut ioapic = ioapic_controller(&x);
|
||||
ioapic.config(
|
||||
(vector - x.global_system_interrupt_base) as u8,
|
||||
0,
|
||||
dest,
|
||||
trig_mode,
|
||||
polarity,
|
||||
false, /* physical */
|
||||
true, /* mask */
|
||||
);
|
||||
})
|
||||
.is_some()
|
||||
}
|
||||
|
||||
fn register_irq_handler(global_irq: u32, handler: InterruptHandler) -> Option<u32> {
|
||||
info!("set_handle irq={:#x?}", global_irq);
|
||||
// if global_irq == 1 {
|
||||
// irq_add_handler(global_irq as u8 + IRQ0, handler);
|
||||
// return Some(global_irq as u8 + IRQ0);
|
||||
// }
|
||||
let ioapic_info = get_ioapic(global_irq)?;
|
||||
let mut ioapic = ioapic_controller(&ioapic_info);
|
||||
let offset = (global_irq - ioapic_info.global_system_interrupt_base) as u8;
|
||||
let irq = ioapic.irq_vector(offset);
|
||||
let new_handler = if global_irq == 0x1 {
|
||||
Box::new(move || {
|
||||
handler();
|
||||
// keyboard();
|
||||
// mouse();
|
||||
})
|
||||
} else {
|
||||
handler
|
||||
};
|
||||
irq_add_handler(irq, new_handler).map(|x| {
|
||||
info!(
|
||||
"irq_set_handle: mapping from {:#x?} to {:#x?}",
|
||||
global_irq, x
|
||||
);
|
||||
ioapic.set_irq_vector(offset, x);
|
||||
x as u32
|
||||
})
|
||||
}
|
||||
|
||||
fn unregister_irq_handler(global_irq: u32) -> bool {
|
||||
info!("reset_handle");
|
||||
let ioapic_info = if let Some(x) = get_ioapic(global_irq) {
|
||||
x
|
||||
} else {
|
||||
return false;
|
||||
};
|
||||
let mut ioapic = ioapic_controller(&ioapic_info);
|
||||
let offset = (global_irq - ioapic_info.global_system_interrupt_base) as u8;
|
||||
let irq = ioapic.irq_vector(offset);
|
||||
if !irq_remove_handler(irq) {
|
||||
ioapic.set_irq_vector(offset, 0);
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_irq(irq: u32) {
|
||||
use apic::LocalApic;
|
||||
let mut lapic = super::apic::get_lapic();
|
||||
lapic.eoi();
|
||||
let table = IRQ_TABLE.lock();
|
||||
match &table[irq as usize] {
|
||||
Some(f) => f(),
|
||||
None => panic!("unhandled external IRQ number: {}", irq),
|
||||
}
|
||||
}
|
||||
|
||||
fn msi_allocate_block(irq_num: u32) -> Option<(usize, usize)> {
|
||||
info!("hal_irq_allocate_block: count={:#x?}", irq_num);
|
||||
let irq_num = u32::next_power_of_two(irq_num) as usize;
|
||||
let mut irq_start = 0x20;
|
||||
let mut irq_cur = irq_start;
|
||||
let mut table = IRQ_TABLE.lock();
|
||||
while irq_cur < TABLE_SIZE && irq_cur < irq_start + irq_num {
|
||||
if table[irq_cur].is_none() {
|
||||
irq_cur += 1;
|
||||
} else {
|
||||
irq_start = (irq_cur - irq_cur % irq_num) + irq_num;
|
||||
irq_cur = irq_start;
|
||||
}
|
||||
}
|
||||
for i in irq_start..irq_start + irq_num {
|
||||
table[i] = Some(Box::new(|| {}));
|
||||
}
|
||||
info!(
|
||||
"hal_irq_allocate_block: start={:#x?} num={:#x?}",
|
||||
irq_start, irq_num
|
||||
);
|
||||
Some((irq_start, irq_num))
|
||||
}
|
||||
|
||||
fn msi_free_block(irq_start: u32, irq_num: u32) {
|
||||
let mut table = IRQ_TABLE.lock();
|
||||
for i in irq_start..irq_start + irq_num {
|
||||
table[i as usize] = None;
|
||||
}
|
||||
}
|
||||
|
||||
fn msi_register_handler(
|
||||
irq_start: u32,
|
||||
_irq_num: u32,
|
||||
msi_id: u32,
|
||||
handler: Box<dyn Fn() + Send + Sync>,
|
||||
) {
|
||||
irq_overwrite_handler((irq_start + msi_id) as u8, handler);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn irq57test() {
|
||||
warn!("irq 57");
|
||||
// poll_ifaces();
|
||||
}
|
||||
|
||||
fn timer() {
|
||||
crate::timer::timer_tick();
|
||||
}
|
||||
|
||||
fn com1() {
|
||||
let c = super::serial::COM1.lock().receive();
|
||||
super::serial::serial_put(c);
|
||||
}
|
||||
|
||||
/*
|
||||
fn keyboard() {
|
||||
use pc_keyboard::{DecodedKey, KeyCode};
|
||||
if let Some(key) = super::keyboard::receive() {
|
||||
match key {
|
||||
DecodedKey::Unicode(c) => super::serial_put(c as u8),
|
||||
DecodedKey::RawKey(code) => {
|
||||
let s = match code {
|
||||
KeyCode::ArrowUp => "\u{1b}[A",
|
||||
KeyCode::ArrowDown => "\u{1b}[B",
|
||||
KeyCode::ArrowRight => "\u{1b}[C",
|
||||
KeyCode::ArrowLeft => "\u{1b}[D",
|
||||
_ => "",
|
||||
};
|
||||
for c in s.bytes() {
|
||||
super::serial_put(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
fn init_irq_table() {
|
||||
let mut table = IRQ_TABLE.lock();
|
||||
for _ in 0..TABLE_SIZE {
|
||||
table.push(None);
|
||||
}
|
||||
}
|
||||
|
||||
fn irq_enable_raw(irq: u8, vector: u8) {
|
||||
info!("irq_enable_raw: irq={:#x?}, vector={:#x?}", irq, vector);
|
||||
let mut ioapic = super::apic::get_ioapic();
|
||||
ioapic.set_irq_vector(irq, vector);
|
||||
ioapic.enable(irq, 0)
|
||||
}
|
||||
|
||||
pub fn init() {
|
||||
// MOUSE.lock().init().unwrap();
|
||||
// MOUSE.lock().set_on_complete(mouse_on_complete);
|
||||
unsafe {
|
||||
init_ioapic();
|
||||
}
|
||||
init_irq_table();
|
||||
irq_add_handler(Timer + IRQ0, Box::new(timer));
|
||||
// irq_add_handler(Keyboard + IRQ0, Box::new(keyboard));
|
||||
// irq_add_handler(Mouse + IRQ0, Box::new(mouse));
|
||||
irq_add_handler(COM1 + IRQ0, Box::new(com1));
|
||||
irq_add_handler(57u8, Box::new(irq57test));
|
||||
// irq_enable_raw(Keyboard, Keyboard + IRQ0);
|
||||
// irq_enable_raw(Mouse, Mouse + IRQ0);
|
||||
irq_enable_raw(COM1, COM1 + IRQ0);
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
use core::arch::x86_64::{__cpuid, _mm_clflush, _mm_mfence};
|
||||
|
||||
use super::super::mem::phys_to_virt;
|
||||
use crate::{PhysAddr, PAGE_SIZE};
|
||||
|
||||
// Get cache line size in bytes.
|
||||
fn cacheline_size() -> usize {
|
||||
let leaf = unsafe { __cpuid(1).ebx };
|
||||
(((leaf >> 8) & 0xff) << 3) as usize
|
||||
}
|
||||
|
||||
/// Flush the physical frame.
|
||||
pub fn frame_flush(target: PhysAddr) {
|
||||
unsafe {
|
||||
for paddr in (target..target + PAGE_SIZE).step_by(cacheline_size()) {
|
||||
_mm_clflush(phys_to_virt(paddr) as *const u8);
|
||||
}
|
||||
_mm_mfence();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
mod acpi_table;
|
||||
mod apic;
|
||||
mod trap;
|
||||
|
||||
pub mod context;
|
||||
pub mod cpu;
|
||||
pub mod interrupt;
|
||||
pub mod mem;
|
||||
pub mod serial;
|
||||
pub mod special;
|
||||
pub mod timer;
|
||||
pub mod vm;
|
||||
|
||||
use x86_64::registers::control::{Cr4, Cr4Flags};
|
||||
|
||||
/// Configuration of HAL.
|
||||
pub struct HalConfig {
|
||||
pub acpi_rsdp: u64,
|
||||
pub smbios: u64,
|
||||
pub ap_fn: fn() -> !,
|
||||
}
|
||||
|
||||
pub(super) static mut CONFIG: HalConfig = HalConfig {
|
||||
acpi_rsdp: 0,
|
||||
smbios: 0,
|
||||
ap_fn: || unreachable!(),
|
||||
};
|
||||
|
||||
pub fn init(config: HalConfig) {
|
||||
apic::init();
|
||||
interrupt::init();
|
||||
serial::init();
|
||||
unsafe {
|
||||
// enable global page
|
||||
Cr4::update(|f| f.insert(Cr4Flags::PAGE_GLOBAL));
|
||||
// store config
|
||||
CONFIG = config;
|
||||
|
||||
// start multi-processors
|
||||
fn ap_main() {
|
||||
info!("processor {} started", cpu::cpu_id());
|
||||
unsafe {
|
||||
trapframe::init();
|
||||
}
|
||||
apic::init();
|
||||
let ap_fn = unsafe { CONFIG.ap_fn };
|
||||
ap_fn()
|
||||
}
|
||||
fn stack_fn(pid: usize) -> usize {
|
||||
// split and reuse the current stack
|
||||
unsafe {
|
||||
let mut stack: usize;
|
||||
asm!("mov {}, rsp", out(reg) stack);
|
||||
stack -= 0x4000 * pid;
|
||||
stack
|
||||
}
|
||||
}
|
||||
x86_smpboot::start_application_processors(
|
||||
ap_main,
|
||||
stack_fn,
|
||||
super::super::mem::phys_to_virt,
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
use alloc::{boxed::Box, collections::VecDeque, vec::Vec};
|
||||
use core::fmt::{Arguments, Write};
|
||||
|
||||
use spin::Mutex;
|
||||
use uart_16550::SerialPort;
|
||||
|
||||
lazy_static::lazy_static! {
|
||||
static ref STDIN: Mutex<VecDeque<u8>> = Mutex::new(VecDeque::new());
|
||||
static ref STDIN_CALLBACK: Mutex<Vec<Box<dyn Fn() -> bool + Send + Sync>>> =
|
||||
Mutex::new(Vec::new());
|
||||
}
|
||||
|
||||
pub(super) static COM1: Mutex<SerialPort> = Mutex::new(unsafe { SerialPort::new(0x3F8) });
|
||||
|
||||
pub(super) fn init() {
|
||||
COM1.lock().init();
|
||||
}
|
||||
|
||||
hal_fn_impl! {
|
||||
impl mod crate::defs::serial {
|
||||
fn serial_put(x: u8) {
|
||||
let x = if x == b'\r' { b'\n' } else { x };
|
||||
STDIN.lock().push_back(x);
|
||||
STDIN_CALLBACK.lock().retain(|f| !f());
|
||||
}
|
||||
|
||||
fn serial_set_callback(callback: Box<dyn Fn() -> bool + Send + Sync>) {
|
||||
STDIN_CALLBACK.lock().push(callback);
|
||||
}
|
||||
|
||||
fn serial_read(buf: &mut [u8]) -> usize {
|
||||
let mut stdin = STDIN.lock();
|
||||
let len = stdin.len().min(buf.len());
|
||||
for c in &mut buf[..len] {
|
||||
*c = stdin.pop_front().unwrap();
|
||||
}
|
||||
len
|
||||
}
|
||||
|
||||
fn print_fmt(fmt: Arguments) {
|
||||
COM1.lock().write_fmt(fmt).unwrap();
|
||||
// if let Some(console) = CONSOLE.lock().as_mut() {
|
||||
// console.write_fmt(fmt).unwrap();
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
use x86_64::instructions::port::Port;
|
||||
|
||||
/// IO Port in instruction
|
||||
pub fn pio_read(port: u16) -> u32 {
|
||||
unsafe { Port::new(port).read() }
|
||||
}
|
||||
|
||||
/// IO Port out instruction
|
||||
pub fn pio_write(port: u16, value: u32) {
|
||||
unsafe { Port::new(port).write(value) }
|
||||
}
|
||||
|
||||
/// Get physical address of `acpi_rsdp` and `smbios` on x86_64.
|
||||
pub fn pc_firmware_tables() -> (u64, u64) {
|
||||
unsafe { (super::CONFIG.acpi_rsdp, super::CONFIG.smbios) }
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
use core::time::Duration;
|
||||
|
||||
pub fn timer_now() -> Duration {
|
||||
let tsc = unsafe { core::arch::x86_64::_rdtsc() };
|
||||
Duration::from_nanos(tsc * 1000 / super::cpu::cpu_frequency() as u64)
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
#![allow(dead_code)]
|
||||
#![allow(non_upper_case_globals)]
|
||||
|
||||
use trapframe::TrapFrame;
|
||||
|
||||
// Reference: https://wiki.osdev.org/Exceptions
|
||||
const DivideError: u8 = 0;
|
||||
const Debug: u8 = 1;
|
||||
const NonMaskableInterrupt: u8 = 2;
|
||||
const Breakpoint: u8 = 3;
|
||||
const Overflow: u8 = 4;
|
||||
const BoundRangeExceeded: u8 = 5;
|
||||
const InvalidOpcode: u8 = 6;
|
||||
const DeviceNotAvailable: u8 = 7;
|
||||
const DoubleFault: u8 = 8;
|
||||
const CoprocessorSegmentOverrun: u8 = 9;
|
||||
const InvalidTSS: u8 = 10;
|
||||
const SegmentNotPresent: u8 = 11;
|
||||
const StackSegmentFault: u8 = 12;
|
||||
const GeneralProtectionFault: u8 = 13;
|
||||
const PageFault: u8 = 14;
|
||||
const FloatingPointException: u8 = 16;
|
||||
const AlignmentCheck: u8 = 17;
|
||||
const MachineCheck: u8 = 18;
|
||||
const SIMDFloatingPointException: u8 = 19;
|
||||
const VirtualizationException: u8 = 20;
|
||||
const SecurityException: u8 = 30;
|
||||
|
||||
const IRQ0: u8 = 32;
|
||||
|
||||
fn breakpoint() {
|
||||
panic!("\nEXCEPTION: Breakpoint");
|
||||
}
|
||||
|
||||
fn double_fault(tf: &TrapFrame) {
|
||||
panic!("\nEXCEPTION: Double Fault\n{:#x?}", tf);
|
||||
}
|
||||
|
||||
fn page_fault(tf: &mut TrapFrame) {
|
||||
panic!(
|
||||
"\nEXCEPTION: Page Fault @ {:#x?}\n{:#x?}",
|
||||
crate::context::fetch_fault_vaddr(),
|
||||
tf
|
||||
);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn trap_handler(tf: &mut TrapFrame) {
|
||||
trace!("Interrupt: {:#x} @ CPU{}", tf.trap_num, 0); // TODO 0 should replace in multi-core case
|
||||
match tf.trap_num as u8 {
|
||||
Breakpoint => breakpoint(),
|
||||
DoubleFault => double_fault(tf),
|
||||
PageFault => page_fault(tf),
|
||||
IRQ0..=63 => crate::interrupt::handle_irq(tf.trap_num as u32),
|
||||
_ => panic!("Unhandled interrupt {:x} {:#x?}", tf.trap_num, tf),
|
||||
}
|
||||
}
|
|
@ -0,0 +1,203 @@
|
|||
use core::convert::TryFrom;
|
||||
|
||||
use x86_64::{
|
||||
registers::control::{Cr3, Cr3Flags},
|
||||
structures::paging::{mapper, FrameAllocator, FrameDeallocator, Mapper, Translate},
|
||||
structures::paging::{OffsetPageTable, PageTable as X86PageTable, PageTableFlags as PTF},
|
||||
structures::paging::{Page, PhysFrame, Size4KiB},
|
||||
};
|
||||
|
||||
use super::super::{ffi, mem::phys_to_virt};
|
||||
use crate::{CachePolicy, HalError, HalResult, MMUFlags, PhysAddr, VirtAddr};
|
||||
|
||||
pub use crate::common::vm::*;
|
||||
|
||||
/// Set page table.
|
||||
///
|
||||
/// # Safety
|
||||
/// This function will set CR3 to `vmtoken`.
|
||||
pub(crate) unsafe fn set_page_table(vmtoken: usize) {
|
||||
let frame = PhysFrame::containing_address(x86_64::PhysAddr::new(vmtoken as _));
|
||||
if Cr3::read().0 == frame {
|
||||
return;
|
||||
}
|
||||
Cr3::write(frame, Cr3Flags::empty());
|
||||
debug!("set page_table @ {:#x}", vmtoken);
|
||||
}
|
||||
|
||||
fn frame_to_page_table(frame: PhysFrame) -> *mut X86PageTable {
|
||||
let vaddr = phys_to_virt(frame.start_address().as_u64() as usize);
|
||||
vaddr as *mut X86PageTable
|
||||
}
|
||||
|
||||
/// Page Table
|
||||
pub struct PageTable {
|
||||
root_paddr: PhysAddr,
|
||||
}
|
||||
|
||||
impl PageTable {
|
||||
pub fn current() -> Self {
|
||||
PageTable {
|
||||
root_paddr: Cr3::read().0.start_address().as_u64() as _,
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a new `PageTable`.
|
||||
pub fn new() -> Self {
|
||||
let root_paddr = crate::mem::frame_alloc().expect("failed to alloc frame");
|
||||
let root_vaddr = phys_to_virt(root_paddr);
|
||||
let root = unsafe { &mut *(root_vaddr as *mut X86PageTable) };
|
||||
root.zero();
|
||||
unsafe { ffi::hal_pt_map_kernel(root_vaddr as _, frame_to_page_table(Cr3::read().0) as _) };
|
||||
trace!("create page table @ {:#x}", root_paddr);
|
||||
PageTable { root_paddr }
|
||||
}
|
||||
|
||||
fn get(&mut self) -> OffsetPageTable<'_> {
|
||||
let root_vaddr = phys_to_virt(self.root_paddr);
|
||||
let root = unsafe { &mut *(root_vaddr as *mut X86PageTable) };
|
||||
let offset = x86_64::VirtAddr::new(phys_to_virt(0) as u64);
|
||||
unsafe { OffsetPageTable::new(root, offset) }
|
||||
}
|
||||
}
|
||||
|
||||
impl PageTableTrait for PageTable {
|
||||
/// Map the page of `vaddr` to the frame of `paddr` with `flags`.
|
||||
fn map(&mut self, vaddr: VirtAddr, paddr: PhysAddr, flags: MMUFlags) -> HalResult<()> {
|
||||
let mut pt = self.get();
|
||||
unsafe {
|
||||
pt.map_to_with_table_flags(
|
||||
Page::<Size4KiB>::from_start_address(x86_64::VirtAddr::new(vaddr as u64)).unwrap(),
|
||||
PhysFrame::from_start_address(x86_64::PhysAddr::new(paddr as u64)).unwrap(),
|
||||
flags.to_ptf(),
|
||||
PTF::PRESENT | PTF::WRITABLE | PTF::USER_ACCESSIBLE,
|
||||
&mut FrameAllocatorImpl,
|
||||
)
|
||||
.unwrap()
|
||||
.flush();
|
||||
};
|
||||
debug!(
|
||||
"map: {:x?} -> {:x?}, flags={:?} in {:#x?}",
|
||||
vaddr, paddr, flags, self.root_paddr
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Unmap the page of `vaddr`.
|
||||
fn unmap(&mut self, vaddr: VirtAddr) -> HalResult<()> {
|
||||
let mut pt = self.get();
|
||||
let page =
|
||||
Page::<Size4KiB>::from_start_address(x86_64::VirtAddr::new(vaddr as u64)).unwrap();
|
||||
// This is a workaround to an issue in the x86-64 crate
|
||||
// A page without PRESENT bit is not unmappable AND mapable
|
||||
// So we add PRESENT bit here
|
||||
unsafe {
|
||||
pt.update_flags(page, PTF::PRESENT | PTF::NO_EXECUTE).ok();
|
||||
}
|
||||
match pt.unmap(page) {
|
||||
Ok((_, flush)) => {
|
||||
flush.flush();
|
||||
trace!("unmap: {:x?} in {:#x?}", vaddr, self.root_paddr);
|
||||
}
|
||||
Err(mapper::UnmapError::PageNotMapped) => {
|
||||
trace!(
|
||||
"unmap not mapped, skip: {:x?} in {:#x?}",
|
||||
vaddr,
|
||||
self.root_paddr
|
||||
);
|
||||
return Ok(());
|
||||
}
|
||||
Err(err) => {
|
||||
debug!(
|
||||
"unmap failed: {:x?} err={:x?} in {:#x?}",
|
||||
vaddr, err, self.root_paddr
|
||||
);
|
||||
return Err(HalError);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Change the `flags` of the page of `vaddr`.
|
||||
fn protect(&mut self, vaddr: VirtAddr, flags: MMUFlags) -> HalResult<()> {
|
||||
let mut pt = self.get();
|
||||
let page =
|
||||
Page::<Size4KiB>::from_start_address(x86_64::VirtAddr::new(vaddr as u64)).unwrap();
|
||||
if let Ok(flush) = unsafe { pt.update_flags(page, flags.to_ptf()) } {
|
||||
flush.flush();
|
||||
}
|
||||
trace!("protect: {:x?}, flags={:?}", vaddr, flags);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Query the physical address which the page of `vaddr` maps to.
|
||||
fn query(&mut self, vaddr: VirtAddr) -> HalResult<PhysAddr> {
|
||||
let pt = self.get();
|
||||
let ret = pt
|
||||
.translate_addr(x86_64::VirtAddr::new(vaddr as u64))
|
||||
.map(|addr| addr.as_u64() as PhysAddr)
|
||||
.ok_or(HalError);
|
||||
trace!("query: {:x?} => {:x?}", vaddr, ret);
|
||||
ret
|
||||
}
|
||||
|
||||
/// Get the physical address of root page table.
|
||||
fn table_phys(&self) -> PhysAddr {
|
||||
self.root_paddr
|
||||
}
|
||||
}
|
||||
|
||||
trait FlagsExt {
|
||||
fn to_ptf(self) -> PTF;
|
||||
}
|
||||
|
||||
impl FlagsExt for MMUFlags {
|
||||
fn to_ptf(self) -> PTF {
|
||||
let mut flags = PTF::empty();
|
||||
if self.contains(MMUFlags::READ) {
|
||||
flags |= PTF::PRESENT;
|
||||
}
|
||||
if self.contains(MMUFlags::WRITE) {
|
||||
flags |= PTF::WRITABLE;
|
||||
}
|
||||
if !self.contains(MMUFlags::EXECUTE) {
|
||||
flags |= PTF::NO_EXECUTE;
|
||||
}
|
||||
if self.contains(MMUFlags::USER) {
|
||||
flags |= PTF::USER_ACCESSIBLE;
|
||||
}
|
||||
let cache_policy = (self.bits() & 3) as u32; // 最低三位用于储存缓存策略
|
||||
match CachePolicy::try_from(cache_policy) {
|
||||
Ok(CachePolicy::Cached) => {
|
||||
flags.remove(PTF::WRITE_THROUGH);
|
||||
}
|
||||
Ok(CachePolicy::Uncached) | Ok(CachePolicy::UncachedDevice) => {
|
||||
flags |= PTF::NO_CACHE | PTF::WRITE_THROUGH;
|
||||
}
|
||||
Ok(CachePolicy::WriteCombining) => {
|
||||
flags |= PTF::NO_CACHE | PTF::WRITE_THROUGH;
|
||||
// 当位于level=1时,页面更大,在1<<12位上(0x100)为1
|
||||
// 但是bitflags里面没有这一位。由页表自行管理标记位去吧
|
||||
}
|
||||
Err(_) => unreachable!("invalid cache policy"),
|
||||
}
|
||||
flags
|
||||
}
|
||||
}
|
||||
|
||||
struct FrameAllocatorImpl;
|
||||
|
||||
unsafe impl FrameAllocator<Size4KiB> for FrameAllocatorImpl {
|
||||
fn allocate_frame(&mut self) -> Option<PhysFrame> {
|
||||
crate::mem::frame_alloc().map(|f| {
|
||||
let paddr = x86_64::PhysAddr::new(f as u64);
|
||||
PhysFrame::from_start_address(paddr).unwrap()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl FrameDeallocator<Size4KiB> for FrameAllocatorImpl {
|
||||
unsafe fn deallocate_frame(&mut self, frame: PhysFrame) {
|
||||
crate::mem::frame_dealloc(frame.start_address().as_u64() as PhysAddr);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
#[allow(improper_ctypes)]
|
||||
extern "C" {
|
||||
pub fn hal_pt_map_kernel(pt: *mut u8, current: *const u8);
|
||||
pub fn hal_frame_alloc() -> Option<usize>;
|
||||
pub fn hal_frame_alloc_contiguous(frame_count: usize, align_log2: usize) -> Option<usize>;
|
||||
pub fn hal_frame_dealloc(paddr: usize);
|
||||
#[link_name = "hal_pmem_base"]
|
||||
pub static PMEM_BASE: usize;
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
use super::ffi;
|
||||
use crate::{PhysAddr, VirtAddr, PAGE_SIZE};
|
||||
|
||||
pub(super) fn phys_to_virt(paddr: PhysAddr) -> VirtAddr {
|
||||
unsafe { ffi::PMEM_BASE + paddr }
|
||||
}
|
||||
|
||||
pub(super) fn virt_to_phys(vaddr: VirtAddr) -> PhysAddr {
|
||||
unsafe { vaddr - ffi::PMEM_BASE }
|
||||
}
|
||||
|
||||
hal_fn_impl! {
|
||||
impl mod crate::defs::mem {
|
||||
fn pmem_read(paddr: PhysAddr, buf: &mut [u8]) {
|
||||
trace!("pmem_read: addr={:#x}, len={:#x}", paddr, buf.len());
|
||||
unsafe {
|
||||
(phys_to_virt(paddr) as *const u8).copy_to_nonoverlapping(buf.as_mut_ptr(), buf.len());
|
||||
}
|
||||
}
|
||||
|
||||
fn pmem_write(paddr: PhysAddr, buf: &[u8]) {
|
||||
trace!(
|
||||
"pmem_write: addr={:#x}, len={:#x}, vaddr = {:#x}",
|
||||
paddr,
|
||||
buf.len(),
|
||||
phys_to_virt(paddr)
|
||||
);
|
||||
unsafe {
|
||||
buf.as_ptr()
|
||||
.copy_to_nonoverlapping(phys_to_virt(paddr) as _, buf.len());
|
||||
}
|
||||
}
|
||||
|
||||
fn pmem_zero(paddr: PhysAddr, len: usize) {
|
||||
trace!("pmem_zero: addr={:#x}, len={:#x}", paddr, len);
|
||||
unsafe {
|
||||
core::ptr::write_bytes(phys_to_virt(paddr) as *mut u8, 0, len);
|
||||
}
|
||||
}
|
||||
|
||||
fn frame_copy(src: PhysAddr, target: PhysAddr) {
|
||||
trace!("frame_copy: {:#x} <- {:#x}", target, src);
|
||||
unsafe {
|
||||
let buf = phys_to_virt(src) as *const u8;
|
||||
buf.copy_to_nonoverlapping(phys_to_virt(target) as _, PAGE_SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
fn frame_flush(target: PhysAddr) {
|
||||
super::arch::mem::frame_flush(target)
|
||||
}
|
||||
|
||||
fn frame_alloc() -> Option<PhysAddr> {
|
||||
unsafe { ffi::hal_frame_alloc() }
|
||||
}
|
||||
|
||||
fn frame_alloc_contiguous(frame_count: usize, align_log2: usize) -> Option<PhysAddr> {
|
||||
unsafe { ffi::hal_frame_alloc_contiguous(frame_count, align_log2) }
|
||||
}
|
||||
|
||||
fn frame_dealloc(paddr: PhysAddr) {
|
||||
unsafe { ffi::hal_frame_dealloc(paddr) }
|
||||
}
|
||||
|
||||
fn zero_frame_addr() -> PhysAddr {
|
||||
#[repr(align(0x1000))]
|
||||
struct AlignedPage([u8; PAGE_SIZE]);
|
||||
static ZERO_PAGE: AlignedPage = AlignedPage([0u8; PAGE_SIZE]);
|
||||
virt_to_phys(ZERO_PAGE.0.as_ptr() as VirtAddr)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
mod ffi;
|
||||
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(target_arch = "x86_64")] {
|
||||
#[path = "arch/x86_64/mod.rs"]
|
||||
mod arch;
|
||||
pub use self::arch::special as x86_64;
|
||||
} else if #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] {
|
||||
#[path = "arch/x86_64/mod.rs"]
|
||||
mod arch;
|
||||
pub use self::arch::special as riscv;
|
||||
}
|
||||
}
|
||||
|
||||
pub mod mem;
|
||||
pub mod thread;
|
||||
pub mod timer;
|
||||
|
||||
pub use super::defs::{dev, rand, vdso};
|
||||
|
||||
hal_fn_impl_default!(rand, vdso, dev::fb, dev::input);
|
||||
|
||||
pub use self::arch::{context, cpu, interrupt, serial, vm, HalConfig};
|
||||
|
||||
/// Initialize the HAL.
|
||||
///
|
||||
/// This function must be called at the beginning.
|
||||
pub fn init(config: HalConfig) {
|
||||
unsafe {
|
||||
trapframe::init();
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "riscv64")]
|
||||
trace!("hal dtb: {:#x}", config.dtb);
|
||||
|
||||
self::arch::init(config);
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
use alloc::boxed::Box;
|
||||
use core::task::{Context, Poll};
|
||||
use core::{future::Future, pin::Pin};
|
||||
|
||||
use spin::Mutex;
|
||||
|
||||
hal_fn_impl! {
|
||||
impl mod crate::defs::thread {
|
||||
fn spawn(future: Pin<Box<dyn Future<Output = ()> + Send + 'static>>, vmtoken: usize) {
|
||||
struct PageTableSwitchWrapper {
|
||||
inner: Mutex<Pin<Box<dyn Future<Output = ()> + Send>>>,
|
||||
vmtoken: usize,
|
||||
}
|
||||
impl Future for PageTableSwitchWrapper {
|
||||
type Output = ();
|
||||
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
unsafe {
|
||||
super::arch::vm::set_page_table(self.vmtoken);
|
||||
}
|
||||
self.inner.lock().as_mut().poll(cx)
|
||||
}
|
||||
}
|
||||
|
||||
executor::spawn(PageTableSwitchWrapper {
|
||||
inner: Mutex::new(future),
|
||||
vmtoken,
|
||||
});
|
||||
}
|
||||
|
||||
fn set_tid(_tid: u64, _pid: u64) {}
|
||||
|
||||
fn get_tid() -> (u64, u64) {
|
||||
(0, 0)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
use alloc::boxed::Box;
|
||||
use core::time::Duration;
|
||||
|
||||
use naive_timer::Timer;
|
||||
use spin::Mutex;
|
||||
|
||||
lazy_static::lazy_static! {
|
||||
pub static ref NAIVE_TIMER: Mutex<Timer> = Mutex::new(Timer::default());
|
||||
}
|
||||
|
||||
hal_fn_impl! {
|
||||
impl mod crate::defs::timer {
|
||||
fn timer_now() -> Duration {
|
||||
super::arch::timer::timer_now()
|
||||
}
|
||||
|
||||
fn timer_set(deadline: Duration, callback: Box<dyn FnOnce(Duration) + Send + Sync>) {
|
||||
NAIVE_TIMER.lock().add(deadline, callback);
|
||||
}
|
||||
|
||||
fn timer_tick() {
|
||||
let now = timer_now();
|
||||
NAIVE_TIMER.lock().expire(now);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -9,18 +9,27 @@ pub struct PhysFrame {
|
|||
}
|
||||
|
||||
impl PhysFrame {
|
||||
pub fn alloc() -> Option<Self> {
|
||||
crate::memory::frame_alloc().map(|paddr| Self { paddr })
|
||||
/// # Safety
|
||||
///
|
||||
/// This function is unsafe because the user must ensure that this is an available physical
|
||||
/// frame.
|
||||
pub unsafe fn from_paddr(paddr: PhysAddr) -> Self {
|
||||
assert!(crate::addr::is_aligned(paddr));
|
||||
Self { paddr }
|
||||
}
|
||||
|
||||
pub fn alloc_contiguous_base(size: usize, align_log2: usize) -> Option<PhysAddr> {
|
||||
crate::memory::frame_alloc_contiguous(size, align_log2)
|
||||
pub fn alloc() -> Option<Self> {
|
||||
crate::mem::frame_alloc().map(|paddr| Self { paddr })
|
||||
}
|
||||
|
||||
fn alloc_contiguous_base(size: usize, align_log2: usize) -> Option<PhysAddr> {
|
||||
crate::mem::frame_alloc_contiguous(size, align_log2)
|
||||
}
|
||||
|
||||
pub fn alloc_contiguous(size: usize, align_log2: usize) -> Vec<Self> {
|
||||
Self::alloc_contiguous_base(size, align_log2).map_or(Vec::new(), |base| {
|
||||
(0..size)
|
||||
.map(|i| PhysFrame {
|
||||
.map(|i| Self {
|
||||
paddr: base + i * PAGE_SIZE,
|
||||
})
|
||||
.collect()
|
||||
|
@ -32,12 +41,12 @@ impl PhysFrame {
|
|||
}
|
||||
|
||||
pub fn zero_frame_addr() -> PhysAddr {
|
||||
crate::memory::zero_frame_addr()
|
||||
crate::mem::zero_frame_addr()
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for PhysFrame {
|
||||
fn drop(&mut self) {
|
||||
crate::memory::frame_dealloc(self.paddr)
|
||||
crate::mem::frame_dealloc(self.paddr)
|
||||
}
|
||||
}
|
|
@ -4,7 +4,7 @@ pub(super) mod fb;
|
|||
pub mod addr;
|
||||
pub mod context;
|
||||
pub mod future;
|
||||
pub mod memory;
|
||||
pub mod paging;
|
||||
pub mod mem;
|
||||
pub mod user;
|
||||
pub mod vdso;
|
||||
pub mod vm;
|
||||
|
|
|
@ -12,7 +12,7 @@ hal_fn_def! {
|
|||
fn cpu_frequency() -> u16 { 3000 }
|
||||
}
|
||||
|
||||
pub mod memory: common::memory {
|
||||
pub mod mem: common::mem {
|
||||
/// Read physical memory from `paddr` to `buf`.
|
||||
fn pmem_read(paddr: PhysAddr, buf: &mut [u8]);
|
||||
|
||||
|
@ -31,8 +31,8 @@ hal_fn_def! {
|
|||
/// Allocate one physical frame.
|
||||
fn frame_alloc() -> Option<PhysAddr>;
|
||||
|
||||
/// Allocate contiguous physical frames of totally `size` bytes.
|
||||
fn frame_alloc_contiguous(size: usize, align_log2: usize) -> Option<PhysAddr>;
|
||||
/// Allocate contiguous `frame_count` physical frames.
|
||||
fn frame_alloc_contiguous(frame_count: usize, align_log2: usize) -> Option<PhysAddr>;
|
||||
|
||||
/// Deallocate a physical frame.
|
||||
fn frame_dealloc(paddr: PhysAddr);
|
||||
|
@ -153,13 +153,17 @@ hal_fn_def! {
|
|||
|
||||
pub mod vdso: common::vdso {
|
||||
/// Get platform specific information.
|
||||
fn vdso_constants() -> VdsoConstants;
|
||||
fn vdso_constants() -> VdsoConstants {
|
||||
vdso_constants_template()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub mod dev {
|
||||
use super::*;
|
||||
|
||||
hal_fn_def! {
|
||||
pub mod fb: crate::common::fb {
|
||||
pub mod fb: common::fb {
|
||||
/// Initialize framebuffer.
|
||||
fn init();
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ cfg_if::cfg_if! {
|
|||
mod libos;
|
||||
pub use self::libos::*;
|
||||
} else {
|
||||
mod libos;
|
||||
pub use self::libos::*;
|
||||
mod bare;
|
||||
pub use self::bare::*;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,11 +1,26 @@
|
|||
use lazy_static::lazy_static;
|
||||
use std::os::unix::io::AsRawFd;
|
||||
use std::sync::Mutex;
|
||||
|
||||
type MouseCallbackFn = dyn Fn([u8; 3]) + Send + Sync;
|
||||
type KBDCallbackFn = dyn Fn(u16, i32) + Send + Sync;
|
||||
|
||||
lazy_static! {
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone, Default)]
|
||||
struct TimeVal {
|
||||
pub sec: usize,
|
||||
pub usec: usize,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone, Default)]
|
||||
struct InputEvent {
|
||||
time: TimeVal,
|
||||
type_: u16,
|
||||
code: u16,
|
||||
value: i32,
|
||||
}
|
||||
|
||||
lazy_static::lazy_static! {
|
||||
static ref MOUSE_CALLBACK: Mutex<Vec<Box<MouseCallbackFn>>> = Mutex::new(Vec::new());
|
||||
static ref KBD_CALLBACK: Mutex<Vec<Box<KBDCallbackFn>>> = Mutex::new(Vec::new());
|
||||
}
|
||||
|
@ -23,21 +38,6 @@ fn init_kbd() {
|
|||
return;
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone, Default)]
|
||||
pub struct TimeVal {
|
||||
pub sec: usize,
|
||||
pub usec: usize,
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone, Default)]
|
||||
struct InputEvent {
|
||||
time: TimeVal,
|
||||
type_: u16,
|
||||
code: u16,
|
||||
value: i32,
|
||||
}
|
||||
|
||||
std::thread::spawn(move || {
|
||||
use core::mem::{size_of, transmute, transmute_copy};
|
||||
let ev = InputEvent::default();
|
||||
|
|
|
@ -2,8 +2,7 @@ use super::mem_common::{ensure_mmap_pmem, phys_to_virt, AVAILABLE_FRAMES, PMEM_S
|
|||
use crate::{PhysAddr, PAGE_SIZE};
|
||||
|
||||
hal_fn_impl! {
|
||||
impl mod crate::defs::memory {
|
||||
/// Read physical memory from `paddr` to `buf`.
|
||||
impl mod crate::defs::mem {
|
||||
fn pmem_read(paddr: PhysAddr, buf: &mut [u8]) {
|
||||
trace!("pmem read: paddr={:#x}, len={:#x}", paddr, buf.len());
|
||||
assert!(paddr + buf.len() <= PMEM_SIZE);
|
||||
|
@ -13,7 +12,6 @@ hal_fn_impl! {
|
|||
}
|
||||
}
|
||||
|
||||
/// Write physical memory to `paddr` from `buf`.
|
||||
fn pmem_write(paddr: PhysAddr, buf: &[u8]) {
|
||||
trace!("pmem write: paddr={:#x}, len={:#x}", paddr, buf.len());
|
||||
assert!(paddr + buf.len() <= PMEM_SIZE);
|
||||
|
@ -24,7 +22,6 @@ hal_fn_impl! {
|
|||
}
|
||||
}
|
||||
|
||||
/// Zero physical memory at `[paddr, paddr + len)`
|
||||
fn pmem_zero(paddr: PhysAddr, len: usize) {
|
||||
trace!("pmem_zero: addr={:#x}, len={:#x}", paddr, len);
|
||||
assert!(paddr + len <= PMEM_SIZE);
|
||||
|
@ -34,7 +31,6 @@ hal_fn_impl! {
|
|||
}
|
||||
}
|
||||
|
||||
/// Copy content of `src` frame to `target` frame
|
||||
fn frame_copy(src: PhysAddr, target: PhysAddr) {
|
||||
trace!("frame_copy: {:#x} <- {:#x}", target, src);
|
||||
assert!(src + PAGE_SIZE <= PMEM_SIZE && target + PAGE_SIZE <= PMEM_SIZE);
|
||||
|
@ -55,7 +51,7 @@ hal_fn_impl! {
|
|||
ret
|
||||
}
|
||||
|
||||
fn frame_alloc_contiguous(_size: usize, _align_log2: usize) -> Option<PhysAddr> {
|
||||
fn frame_alloc_contiguous(_frame_count: usize, _align_log2: usize) -> Option<PhysAddr> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
|
@ -1,5 +1,4 @@
|
|||
use alloc::collections::VecDeque;
|
||||
use lazy_static::lazy_static;
|
||||
use std::fs::{File, OpenOptions};
|
||||
use std::io::Error;
|
||||
use std::os::unix::io::AsRawFd;
|
||||
|
@ -10,7 +9,7 @@ use crate::{PhysAddr, VirtAddr, PAGE_SIZE};
|
|||
/// Map physical memory from here.
|
||||
pub(super) const PMEM_SIZE: usize = 0x4000_0000; // 1GiB
|
||||
|
||||
lazy_static! {
|
||||
lazy_static::lazy_static! {
|
||||
pub(super) static ref FRAME_FILE: File = create_pmem_file();
|
||||
pub(super) static ref AVAILABLE_FRAMES: Mutex<VecDeque<usize>> =
|
||||
Mutex::new((PAGE_SIZE..PMEM_SIZE).step_by(PAGE_SIZE).collect());
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
mod mem_common;
|
||||
|
||||
pub mod context;
|
||||
pub mod memory;
|
||||
pub mod paging;
|
||||
pub mod mem;
|
||||
pub mod serial;
|
||||
pub mod thread;
|
||||
pub mod timer;
|
||||
pub mod vdso;
|
||||
pub mod vm;
|
||||
|
||||
pub use super::defs::{cpu, interrupt, rand};
|
||||
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
use lazy_static::lazy_static;
|
||||
use std::collections::VecDeque;
|
||||
use std::sync::Mutex;
|
||||
|
||||
lazy_static! {
|
||||
lazy_static::lazy_static! {
|
||||
static ref STDIN: Mutex<VecDeque<u8>> = Mutex::new(VecDeque::new());
|
||||
static ref STDIN_CALLBACK: Mutex<Vec<Box<dyn Fn() -> bool + Send + Sync>>> =
|
||||
Mutex::new(Vec::new());
|
||||
|
|
|
@ -2,16 +2,12 @@ use std::time::{Duration, SystemTime};
|
|||
|
||||
hal_fn_impl! {
|
||||
impl mod crate::defs::timer {
|
||||
/// Get current time.
|
||||
fn timer_now() -> Duration {
|
||||
SystemTime::now()
|
||||
.duration_since(SystemTime::UNIX_EPOCH)
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
/// Set a new timer.
|
||||
///
|
||||
/// After `deadline`, the `callback` will be called.
|
||||
fn timer_set(deadline: Duration, callback: Box<dyn FnOnce(Duration) + Send + Sync>) {
|
||||
std::thread::spawn(move || {
|
||||
let now = timer_now();
|
||||
|
|
|
@ -4,7 +4,7 @@ use std::os::unix::io::AsRawFd;
|
|||
use super::mem_common::{mmap, FRAME_FILE};
|
||||
use crate::{addr::is_aligned, HalResult, MMUFlags, PhysAddr, VirtAddr, PAGE_SIZE};
|
||||
|
||||
pub use crate::common::paging::*;
|
||||
pub use crate::common::vm::*;
|
||||
|
||||
pub struct PageTable;
|
||||
|
|
@ -57,8 +57,8 @@ pub fn run(args: Vec<String>, envs: Vec<String>, rootfs: Arc<dyn FileSystem>) ->
|
|||
let path = args[0].clone();
|
||||
debug!("Linux process: {:?}", path);
|
||||
|
||||
use kernel_hal::paging::PageTableTrait;
|
||||
let pg_token = kernel_hal::paging::PageTable::current().table_phys();
|
||||
use kernel_hal::vm::PageTableTrait;
|
||||
let pg_token = kernel_hal::vm::PageTable::current().table_phys();
|
||||
debug!("current pgt = {:#x}", pg_token);
|
||||
//调用zircon-object/src/task/thread.start设置好要执行的thread
|
||||
let (entry, sp) = loader.load(&proc.vmar(), &data, args, envs, path).unwrap();
|
||||
|
|
|
@ -8,8 +8,8 @@ edition = "2018"
|
|||
|
||||
[features]
|
||||
graphic = []
|
||||
board_qemu = ["kernel-hal-bare/board_qemu"]
|
||||
board_d1 = ["link_user_img", "kernel-hal-bare/board_d1"]
|
||||
board_qemu = [] # "kernel-hal-bare/board_qemu"]
|
||||
board_d1 = ["link_user_img"] #, "kernel-hal-bare/board_d1"]
|
||||
link_user_img = []
|
||||
zircon = ["zircon-loader"]
|
||||
linux = ["linux-loader", "linux-object", "rcore-fs-sfs"]
|
||||
|
@ -23,7 +23,6 @@ log = "0.4"
|
|||
spin = "0.7"
|
||||
buddy_system_allocator = "0.7"
|
||||
kernel-hal = { path = "../kernel-hal" }
|
||||
kernel-hal-bare = { path = "../kernel-hal-bare" }
|
||||
lazy_static = { version = "1.4", features = ["spin_no_std" ] }
|
||||
bitmap-allocator = { git = "https://github.com/rcore-os/bitmap-allocator", rev = "03bd9909" }
|
||||
trapframe = "0.8.0"
|
||||
|
|
|
@ -18,7 +18,7 @@ kernel_bin := $(build_path)/zcore.bin
|
|||
ESP := $(build_path)/esp
|
||||
OVMF := ../rboot/OVMF.fd
|
||||
qemu := qemu-system-$(arch)
|
||||
OBJDUMP := rust-objdump -print-imm-hex -x86-asm-syntax=intel
|
||||
OBJDUMP := rust-objdump --print-imm-hex --x86-asm-syntax=intel
|
||||
OBJCOPY := rust-objcopy --binary-architecture=$(arch)
|
||||
VMDISK := $(build_path)/boot.vdi
|
||||
QEMU_DISK := $(build_path)/disk.qcow2
|
||||
|
@ -185,7 +185,7 @@ image:
|
|||
header:
|
||||
$(OBJDUMP) -x $(kernel) | less
|
||||
|
||||
asm:
|
||||
disasm:
|
||||
$(OBJDUMP) -d $(kernel) | less
|
||||
|
||||
vbox: build
|
||||
|
@ -224,4 +224,3 @@ baremetal-test:
|
|||
|
||||
baremetal-test-rv64: build $(QEMU_DISK)
|
||||
timeout --foreground 8s $(qemu) $(qemu_opts) -append ROOTPROC=$(ROOTPROC)
|
||||
|
||||
|
|
|
@ -7,4 +7,3 @@ pub use self::x86_64::*;
|
|||
pub mod riscv;
|
||||
#[cfg(target_arch = "riscv64")]
|
||||
pub use self::riscv::*;
|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
use alloc::sync::Arc;
|
||||
use rcore_fs::vfs::FileSystem;
|
||||
use linux_object::fs::MemBuf;
|
||||
use kernel_hal_bare::drivers::virtio::{BlockDriverWrapper, BLK_DRIVERS};
|
||||
use rcore_fs::vfs::FileSystem;
|
||||
|
||||
pub fn init_filesystem(ramfs_data: &'static mut [u8]) -> Arc<dyn FileSystem> {
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
|
@ -9,7 +8,7 @@ pub fn init_filesystem(ramfs_data: &'static mut [u8]) -> Arc<dyn FileSystem> {
|
|||
|
||||
#[cfg(feature = "link_user_img")]
|
||||
let ramfs_data = unsafe {
|
||||
extern {
|
||||
extern "C" {
|
||||
fn _user_img_start();
|
||||
fn _user_img_end();
|
||||
}
|
||||
|
@ -23,8 +22,9 @@ pub fn init_filesystem(ramfs_data: &'static mut [u8]) -> Arc<dyn FileSystem> {
|
|||
#[cfg(feature = "link_user_img")]
|
||||
let device = Arc::new(MemBuf::new(ramfs_data));
|
||||
|
||||
#[cfg(all(target_arch="riscv64", not(feature="link_user_img")))]
|
||||
#[cfg(all(target_arch = "riscv64", not(feature = "link_user_img")))]
|
||||
let device = {
|
||||
use kernel_hal::drivers::virtio::{BlockDriverWrapper, BLK_DRIVERS};
|
||||
let driver = BlockDriverWrapper(
|
||||
BLK_DRIVERS
|
||||
.read()
|
||||
|
|
|
@ -37,12 +37,12 @@ macro_rules! with_color {
|
|||
}
|
||||
|
||||
fn print_in_color(args: fmt::Arguments, color_code: u8) {
|
||||
kernel_hal_bare::arch::putfmt(with_color!(args, color_code));
|
||||
kernel_hal::serial::print_fmt(with_color!(args, color_code));
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn print(args: fmt::Arguments) {
|
||||
kernel_hal_bare::arch::putfmt(args);
|
||||
kernel_hal::serial::print_fmt(args);
|
||||
}
|
||||
|
||||
struct SimpleLogger;
|
||||
|
@ -56,11 +56,11 @@ impl Log for SimpleLogger {
|
|||
return;
|
||||
}
|
||||
|
||||
let (tid, pid) = kernel_hal_bare::Thread::get_tid();
|
||||
let (tid, pid) = kernel_hal::thread::get_tid();
|
||||
print_in_color(
|
||||
format_args!(
|
||||
"[{:?} {:>5} {} {}:{}] {}\n",
|
||||
kernel_hal_bare::timer_now(),
|
||||
kernel_hal::timer::timer_now(),
|
||||
record.level(),
|
||||
kernel_hal::cpu::cpu_id(),
|
||||
pid,
|
||||
|
|
|
@ -21,8 +21,8 @@ extern crate rlibc_opt; //Only for x86_64
|
|||
|
||||
#[macro_use]
|
||||
mod logging;
|
||||
mod lang;
|
||||
mod arch;
|
||||
mod lang;
|
||||
mod memory;
|
||||
|
||||
#[cfg(feature = "linux")]
|
||||
|
@ -33,16 +33,16 @@ use rboot::BootInfo;
|
|||
|
||||
#[cfg(target_arch = "riscv64")]
|
||||
use kernel_hal_bare::{
|
||||
phys_to_virt, remap_the_kernel,
|
||||
drivers::virtio::{GPU_DRIVERS, CMDLINE},
|
||||
BootInfo, GraphicInfo,
|
||||
drivers::virtio::{CMDLINE, GPU_DRIVERS},
|
||||
phys_to_virt, remap_the_kernel, BootInfo, GraphicInfo,
|
||||
};
|
||||
|
||||
use alloc::{
|
||||
format,vec,
|
||||
vec::Vec,
|
||||
boxed::Box,
|
||||
format,
|
||||
string::{String, ToString},
|
||||
vec,
|
||||
vec::Vec,
|
||||
};
|
||||
|
||||
#[cfg(feature = "board_qemu")]
|
||||
|
@ -61,7 +61,7 @@ pub extern "C" fn _start(boot_info: &BootInfo) -> ! {
|
|||
|
||||
trace!("{:#x?}", boot_info);
|
||||
|
||||
kernel_hal_bare::init(kernel_hal_bare::Config {
|
||||
kernel_hal::init(kernel_hal::HalConfig {
|
||||
acpi_rsdp: boot_info.acpi2_rsdp_addr,
|
||||
smbios: boot_info.smbios_addr,
|
||||
ap_fn: run,
|
||||
|
@ -72,7 +72,7 @@ pub extern "C" fn _start(boot_info: &BootInfo) -> ! {
|
|||
let (width, height) = boot_info.graphic_info.mode.resolution();
|
||||
let fb_addr = boot_info.graphic_info.fb_addr as usize;
|
||||
let fb_size = boot_info.graphic_info.fb_size as usize;
|
||||
kernel_hal_bare::init_framebuffer(width as u32, height as u32, fb_addr, fb_size);
|
||||
kernel_hal::dev::fb::init(width as u32, height as u32, fb_addr, fb_size);
|
||||
}
|
||||
|
||||
let ramfs_data = unsafe {
|
||||
|
@ -99,7 +99,10 @@ fn main(ramfs_data: &[u8], cmdline: &str) -> ! {
|
|||
#[cfg(target_arch = "riscv64")]
|
||||
#[no_mangle]
|
||||
pub extern "C" fn rust_main(hartid: usize, device_tree_paddr: usize) -> ! {
|
||||
println!("zCore rust_main( hartid: {}, device_tree_paddr: {:#x} )", hartid, device_tree_paddr);
|
||||
println!(
|
||||
"zCore rust_main( hartid: {}, device_tree_paddr: {:#x} )",
|
||||
hartid, device_tree_paddr
|
||||
);
|
||||
let device_tree_vaddr = phys_to_virt(device_tree_paddr);
|
||||
|
||||
let boot_info = BootInfo {
|
||||
|
@ -124,7 +127,7 @@ pub extern "C" fn rust_main(hartid: usize, device_tree_paddr: usize) -> ! {
|
|||
|
||||
info!("{:#x?}", boot_info);
|
||||
|
||||
kernel_hal_bare::init(kernel_hal_bare::Config {
|
||||
kernel_hal::init(kernel_hal::HalConfig {
|
||||
mconfig: 0,
|
||||
dtb: device_tree_vaddr,
|
||||
});
|
||||
|
@ -180,10 +183,10 @@ fn get_rootproc(cmdline: &str) -> Vec<String> {
|
|||
fn main(ramfs_data: &'static mut [u8], cmdline: &str) -> ! {
|
||||
use linux_object::fs::STDIN;
|
||||
|
||||
kernel_hal_bare::serial_set_callback(Box::new({
|
||||
kernel_hal::serial::serial_set_callback(Box::new({
|
||||
move || {
|
||||
let mut buffer = [0; 255];
|
||||
let len = kernel_hal_bare::serial_read(&mut buffer);
|
||||
let len = kernel_hal::serial::serial_read(&mut buffer);
|
||||
for c in &buffer[..len] {
|
||||
STDIN.push((*c).into());
|
||||
// kernel_hal_bare::print_str(alloc::format!("{}", *c as char).as_str());
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
//! Define the FrameAllocator for physical memory
|
||||
//! x86_64 -- 64GB
|
||||
|
||||
use {bitmap_allocator::BitAlloc, buddy_system_allocator::LockedHeap, spin::Mutex};
|
||||
use crate::arch::consts::*;
|
||||
use {bitmap_allocator::BitAlloc, buddy_system_allocator::LockedHeap, spin::Mutex};
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
use {
|
||||
|
@ -24,10 +24,6 @@ type FrameAlloc = bitmap_allocator::BitAlloc1M;
|
|||
|
||||
static FRAME_ALLOCATOR: Mutex<FrameAlloc> = Mutex::new(FrameAlloc::DEFAULT);
|
||||
|
||||
#[used]
|
||||
#[export_name = "hal_pmem_base"]
|
||||
static PMEM_BASE: usize = PHYSICAL_MEMORY_OFFSET;
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
pub fn init_frame_allocator(boot_info: &BootInfo) {
|
||||
let mut ba = FRAME_ALLOCATOR.lock();
|
||||
|
@ -78,67 +74,78 @@ pub fn init_heap() {
|
|||
info!("heap init end");
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[allow(improper_ctypes_definitions)]
|
||||
pub extern "C" fn frame_alloc() -> Option<usize> {
|
||||
// get the real address of the alloc frame
|
||||
let ret = FRAME_ALLOCATOR
|
||||
.lock()
|
||||
.alloc()
|
||||
.map(|id| id * PAGE_SIZE + MEMORY_OFFSET);
|
||||
trace!("Allocate frame: {:x?}", ret);
|
||||
ret
|
||||
}
|
||||
mod hal_extern_fn {
|
||||
use super::*;
|
||||
|
||||
#[no_mangle]
|
||||
#[allow(improper_ctypes_definitions)]
|
||||
pub extern "C" fn hal_frame_alloc_contiguous(page_num: usize, align_log2: usize) -> Option<usize> {
|
||||
let ret = FRAME_ALLOCATOR
|
||||
.lock()
|
||||
.alloc_contiguous(page_num, align_log2)
|
||||
.map(|id| id * PAGE_SIZE + MEMORY_OFFSET);
|
||||
trace!(
|
||||
"Allocate contiguous frames: {:x?} ~ {:x?}",
|
||||
ret,
|
||||
ret.map(|x| x + page_num)
|
||||
);
|
||||
ret
|
||||
}
|
||||
#[used]
|
||||
#[export_name = "hal_pmem_base"]
|
||||
static PMEM_BASE: usize = PHYSICAL_MEMORY_OFFSET;
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn frame_dealloc(target: &usize) {
|
||||
trace!("Deallocate frame: {:x}", *target);
|
||||
FRAME_ALLOCATOR
|
||||
.lock()
|
||||
.dealloc((*target - MEMORY_OFFSET) / PAGE_SIZE);
|
||||
}
|
||||
#[no_mangle]
|
||||
#[allow(improper_ctypes_definitions)]
|
||||
pub extern "C" fn hal_frame_alloc() -> Option<usize> {
|
||||
// get the real address of the alloc frame
|
||||
let ret = FRAME_ALLOCATOR
|
||||
.lock()
|
||||
.alloc()
|
||||
.map(|id| id * PAGE_SIZE + MEMORY_OFFSET);
|
||||
trace!("Allocate frame: {:x?}", ret);
|
||||
ret
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
pub extern "C" fn hal_pt_map_kernel(pt: &mut PageTable, current: &PageTable) {
|
||||
//复制旧的Kernel起始虚拟地址和物理内存起始虚拟地址的, Level3及以下级的页表,
|
||||
//分别可覆盖500G虚拟空间
|
||||
let ekernel = current[KERNEL_PM4].clone();
|
||||
let ephysical = current[PHYSICAL_MEMORY_PM4].clone();
|
||||
pt[KERNEL_PM4].set_addr(ekernel.addr(), ekernel.flags() | EF::GLOBAL);
|
||||
pt[PHYSICAL_MEMORY_PM4].set_addr(ephysical.addr(), ephysical.flags() | EF::GLOBAL);
|
||||
}
|
||||
#[no_mangle]
|
||||
#[allow(improper_ctypes_definitions)]
|
||||
pub extern "C" fn hal_frame_alloc_contiguous(
|
||||
page_num: usize,
|
||||
align_log2: usize,
|
||||
) -> Option<usize> {
|
||||
let ret = FRAME_ALLOCATOR
|
||||
.lock()
|
||||
.alloc_contiguous(page_num, align_log2)
|
||||
.map(|id| id * PAGE_SIZE + MEMORY_OFFSET);
|
||||
trace!(
|
||||
"Allocate contiguous frames: {:x?} ~ {:x?}",
|
||||
ret,
|
||||
ret.map(|x| x + page_num)
|
||||
);
|
||||
ret
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[cfg(target_arch = "riscv64")]
|
||||
pub extern "C" fn hal_pt_map_kernel(pt: &mut PageTable, current: &PageTable) {
|
||||
let ekernel = current[KERNEL_L2].clone(); //Kernel
|
||||
let ephysical = current[PHYSICAL_MEMORY_L2].clone(); //0xffffffff_00000000 --> 0x00000000
|
||||
pt[KERNEL_L2].set(Frame::of_addr(ekernel.addr()), ekernel.flags() | EF::GLOBAL);
|
||||
pt[PHYSICAL_MEMORY_L2].set(
|
||||
Frame::of_addr(ephysical.addr()),
|
||||
ephysical.flags() | EF::GLOBAL,
|
||||
);
|
||||
debug!(
|
||||
"KERNEL_L2:{:x?}, PHYSICAL_MEMORY_L2:{:x?}",
|
||||
ekernel.addr(),
|
||||
ephysical.addr()
|
||||
);
|
||||
#[no_mangle]
|
||||
pub extern "C" fn hal_frame_dealloc(target: usize) {
|
||||
trace!("Deallocate frame: {:x}", target);
|
||||
FRAME_ALLOCATOR
|
||||
.lock()
|
||||
.dealloc((target - MEMORY_OFFSET) / PAGE_SIZE);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
pub extern "C" fn hal_pt_map_kernel(pt: &mut PageTable, current: &PageTable) {
|
||||
//复制旧的Kernel起始虚拟地址和物理内存起始虚拟地址的, Level3及以下级的页表,
|
||||
//分别可覆盖500G虚拟空间
|
||||
let ekernel = current[KERNEL_PM4].clone();
|
||||
let ephysical = current[PHYSICAL_MEMORY_PM4].clone();
|
||||
pt[KERNEL_PM4].set_addr(ekernel.addr(), ekernel.flags() | EF::GLOBAL);
|
||||
pt[PHYSICAL_MEMORY_PM4].set_addr(ephysical.addr(), ephysical.flags() | EF::GLOBAL);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[cfg(target_arch = "riscv64")]
|
||||
pub extern "C" fn hal_pt_map_kernel(pt: &mut PageTable, current: &PageTable) {
|
||||
let ekernel = current[KERNEL_L2].clone(); //Kernel
|
||||
let ephysical = current[PHYSICAL_MEMORY_L2].clone(); //0xffffffff_00000000 --> 0x00000000
|
||||
pt[KERNEL_L2].set(Frame::of_addr(ekernel.addr()), ekernel.flags() | EF::GLOBAL);
|
||||
pt[PHYSICAL_MEMORY_L2].set(
|
||||
Frame::of_addr(ephysical.addr()),
|
||||
ephysical.flags() | EF::GLOBAL,
|
||||
);
|
||||
debug!(
|
||||
"KERNEL_L2:{:x?}, PHYSICAL_MEMORY_L2:{:x?}",
|
||||
ekernel.addr(),
|
||||
ephysical.addr()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// First core stores its SATP here.
|
||||
|
|
|
@ -34,7 +34,7 @@ pub fn create_kcounter_vmo() -> (Arc<VmObject>, Arc<VmObject>) {
|
|||
fn kcounters_arena_start();
|
||||
fn kcounters_arena_end();
|
||||
}
|
||||
use kernel_hal::paging::{PageTable, PageTableTrait};
|
||||
use kernel_hal::vm::{PageTable, PageTableTrait};
|
||||
let mut pgtable = PageTable::current();
|
||||
let paddr = pgtable.query(kcounters_arena_start as usize).unwrap();
|
||||
assert_eq!(
|
||||
|
|
|
@ -12,7 +12,7 @@ pub fn pci_bdf_raw_addr(bus: u8, dev: u8, func: u8, offset: u8) -> u32 {
|
|||
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(all(target_arch = "x86_64", target_os = "none"))] {
|
||||
use kernel_hal::{inpd, outpd};
|
||||
use kernel_hal::x86_64::{pio_read, pio_write};
|
||||
use spin::Mutex;
|
||||
|
||||
static PIO_LOCK: Mutex<()> = Mutex::new(());
|
||||
|
@ -26,8 +26,8 @@ if #[cfg(all(target_arch = "x86_64", target_os = "none"))] {
|
|||
if shift + width > 32 {
|
||||
return Err(ZxError::INVALID_ARGS);
|
||||
}
|
||||
outpd(PCI_CONFIG_ADDR, (addr & !0x3) | PCI_CONFIG_ENABLE);
|
||||
let tmp_val = u32::from_le(inpd(PCI_CONFIG_DATA));
|
||||
pio_write(PCI_CONFIG_ADDR, (addr & !0x3) | PCI_CONFIG_ENABLE);
|
||||
let tmp_val = u32::from_le(pio_read(PCI_CONFIG_DATA));
|
||||
Ok((tmp_val >> shift) & (((1u64 << width) - 1) as u32))
|
||||
}
|
||||
pub fn pio_config_write_addr(addr: u32, val: u32, width: usize) -> ZxResult {
|
||||
|
@ -36,15 +36,15 @@ if #[cfg(all(target_arch = "x86_64", target_os = "none"))] {
|
|||
if shift + width > 32 {
|
||||
return Err(ZxError::INVALID_ARGS);
|
||||
}
|
||||
outpd(PCI_CONFIG_ADDR, (addr & !0x3) | PCI_CONFIG_ENABLE);
|
||||
pio_write(PCI_CONFIG_ADDR, (addr & !0x3) | PCI_CONFIG_ENABLE);
|
||||
let width_mask = ((1u64 << width) - 1) as u32;
|
||||
let val = val & width_mask;
|
||||
let tmp_val = if width < 32 {
|
||||
(u32::from_le(inpd(PCI_CONFIG_DATA)) & !(width_mask << shift)) | (val << shift)
|
||||
(u32::from_le(pio_read(PCI_CONFIG_DATA)) & !(width_mask << shift)) | (val << shift)
|
||||
} else {
|
||||
val
|
||||
};
|
||||
outpd(PCI_CONFIG_DATA, u32::to_le(tmp_val));
|
||||
pio_write(PCI_CONFIG_DATA, u32::to_le(tmp_val));
|
||||
Ok(())
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use {
|
||||
super::*, crate::object::*, alloc::sync::Arc, alloc::vec, alloc::vec::Vec, bitflags::bitflags,
|
||||
kernel_hal::paging::PageTableTrait, spin::Mutex,
|
||||
kernel_hal::vm::PageTableTrait, spin::Mutex,
|
||||
};
|
||||
|
||||
bitflags! {
|
||||
|
@ -78,7 +78,7 @@ impl VmAddressRegion {
|
|||
addr,
|
||||
size,
|
||||
parent: None,
|
||||
page_table: Arc::new(Mutex::new(kernel_hal::paging::PageTable::new())), //hal PageTable
|
||||
page_table: Arc::new(Mutex::new(kernel_hal::vm::PageTable::new())), //hal PageTable
|
||||
inner: Mutex::new(Some(VmarInner::default())),
|
||||
})
|
||||
}
|
||||
|
@ -94,7 +94,7 @@ impl VmAddressRegion {
|
|||
addr: kernel_vmar_base,
|
||||
size: kernel_vmar_size,
|
||||
parent: None,
|
||||
page_table: Arc::new(Mutex::new(kernel_hal::paging::PageTable::new())),
|
||||
page_table: Arc::new(Mutex::new(kernel_hal::vm::PageTable::new())),
|
||||
inner: Mutex::new(Some(VmarInner::default())),
|
||||
})
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ use {
|
|||
core::ops::Range,
|
||||
core::sync::atomic::*,
|
||||
hashbrown::HashMap,
|
||||
kernel_hal::{memory::PhysFrame, PAGE_SIZE},
|
||||
kernel_hal::{mem::PhysFrame, PAGE_SIZE},
|
||||
spin::{Mutex, MutexGuard},
|
||||
};
|
||||
|
||||
|
@ -188,7 +188,7 @@ impl VMObjectPaged {
|
|||
let (_guard, mut inner) = vmo.get_inner_mut();
|
||||
inner.contiguous = true;
|
||||
for (i, f) in frames.drain(0..).enumerate() {
|
||||
kernel_hal::memory::pmem_zero(f.addr(), PAGE_SIZE);
|
||||
kernel_hal::mem::pmem_zero(f.addr(), PAGE_SIZE);
|
||||
let mut state = PageState::new(f);
|
||||
state.pin_count += 1;
|
||||
inner.frames.insert(i, state);
|
||||
|
@ -225,7 +225,7 @@ impl VMObjectTrait for VMObjectPaged {
|
|||
return Err(ZxError::BAD_STATE);
|
||||
}
|
||||
inner.for_each_page(offset, buf.len(), MMUFlags::READ, |paddr, buf_range| {
|
||||
kernel_hal::memory::pmem_read(paddr, &mut buf[buf_range]);
|
||||
kernel_hal::mem::pmem_read(paddr, &mut buf[buf_range]);
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -235,7 +235,7 @@ impl VMObjectTrait for VMObjectPaged {
|
|||
return Err(ZxError::BAD_STATE);
|
||||
}
|
||||
inner.for_each_page(offset, buf.len(), MMUFlags::WRITE, |paddr, buf_range| {
|
||||
kernel_hal::memory::pmem_write(paddr, &buf[buf_range]);
|
||||
kernel_hal::mem::pmem_write(paddr, &buf[buf_range]);
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -259,7 +259,7 @@ impl VMObjectTrait for VMObjectPaged {
|
|||
} else if inner.committed_pages_in_range(block.block, block.block + 1) != 0 {
|
||||
// check whether this page is initialized, otherwise nothing should be done
|
||||
let paddr = inner.commit_page(block.block, MMUFlags::WRITE)?;
|
||||
kernel_hal::memory::pmem_zero(paddr + block.begin, block.len());
|
||||
kernel_hal::mem::pmem_zero(paddr + block.begin, block.len());
|
||||
}
|
||||
}
|
||||
inner.release_unwanted_pages_in_parent(unwanted);
|
||||
|
@ -371,7 +371,7 @@ impl VMObjectTrait for VMObjectPaged {
|
|||
}
|
||||
if inner.cache_policy == CachePolicy::Cached && policy != CachePolicy::Cached {
|
||||
for (_, value) in inner.frames.iter() {
|
||||
kernel_hal::memory::frame_flush(value.frame.addr());
|
||||
kernel_hal::mem::frame_flush(value.frame.addr());
|
||||
}
|
||||
}
|
||||
inner.cache_policy = policy;
|
||||
|
@ -528,7 +528,7 @@ impl VMObjectPagedInner {
|
|||
// lazy allocate zero frame
|
||||
// 这里会调用HAL层的hal_frame_alloc, 请注意实现该函数时参数要一样
|
||||
let target_frame = PhysFrame::alloc().ok_or(ZxError::NO_MEMORY)?;
|
||||
kernel_hal::memory::pmem_zero(target_frame.addr(), PAGE_SIZE);
|
||||
kernel_hal::mem::pmem_zero(target_frame.addr(), PAGE_SIZE);
|
||||
if out_of_range {
|
||||
// can never be a hidden vmo
|
||||
assert!(!self.type_.is_hidden());
|
||||
|
@ -607,7 +607,7 @@ impl VMObjectPagedInner {
|
|||
} else if flags.contains(MMUFlags::WRITE) && child_tag.is_split() {
|
||||
// copy-on-write
|
||||
let target_frame = PhysFrame::alloc().ok_or(ZxError::NO_MEMORY)?;
|
||||
kernel_hal::memory::frame_copy(frame.frame.addr(), target_frame.addr());
|
||||
kernel_hal::mem::frame_copy(frame.frame.addr(), target_frame.addr());
|
||||
frame.tag = child_tag;
|
||||
return Ok(CommitResult::CopyOnWrite(target_frame, true));
|
||||
}
|
||||
|
|
|
@ -39,21 +39,21 @@ impl VMObjectTrait for VMObjectPhysical {
|
|||
fn read(&self, offset: usize, buf: &mut [u8]) -> ZxResult {
|
||||
let _ = self.data_lock.lock();
|
||||
assert!(offset + buf.len() <= self.len());
|
||||
kernel_hal::memory::pmem_read(self.paddr + offset, buf);
|
||||
kernel_hal::mem::pmem_read(self.paddr + offset, buf);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write(&self, offset: usize, buf: &[u8]) -> ZxResult {
|
||||
let _ = self.data_lock.lock();
|
||||
assert!(offset + buf.len() <= self.len());
|
||||
kernel_hal::memory::pmem_write(self.paddr + offset, buf);
|
||||
kernel_hal::mem::pmem_write(self.paddr + offset, buf);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn zero(&self, offset: usize, len: usize) -> ZxResult {
|
||||
let _ = self.data_lock.lock();
|
||||
assert!(offset + len <= self.len());
|
||||
kernel_hal::memory::pmem_zero(self.paddr + offset, len);
|
||||
kernel_hal::mem::pmem_zero(self.paddr + offset, len);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
|
@ -38,11 +38,11 @@ impl Syscall<'_> {
|
|||
out.write(handle)?;
|
||||
Ok(())
|
||||
}
|
||||
/// Creates a new bus transaction initiator.
|
||||
/// Creates a new bus transaction initiator.
|
||||
///
|
||||
/// `iommu: HandleValue`, a handle to an IOMMU.
|
||||
/// `options: u32`, must be 0 (reserved for future definition of creation flags).
|
||||
/// `bti_id: u64`, a hardware transaction identifier for a device downstream of that IOMMU.
|
||||
/// `iommu: HandleValue`, a handle to an IOMMU.
|
||||
/// `options: u32`, must be 0 (reserved for future definition of creation flags).
|
||||
/// `bti_id: u64`, a hardware transaction identifier for a device downstream of that IOMMU.
|
||||
pub fn sys_bti_create(
|
||||
&self,
|
||||
iommu: HandleValue,
|
||||
|
@ -69,7 +69,7 @@ impl Syscall<'_> {
|
|||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
/// Pin pages and grant devices access to them.
|
||||
/// Pin pages and grant devices access to them.
|
||||
pub fn sys_bti_pin(
|
||||
&self,
|
||||
bti: HandleValue,
|
||||
|
@ -113,7 +113,7 @@ impl Syscall<'_> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// Unpins pages that were previously pinned by `zx_bti_pin()`.
|
||||
/// Unpins pages that were previously pinned by `zx_bti_pin()`.
|
||||
pub fn sys_pmt_unpin(&self, pmt: HandleValue) -> ZxResult {
|
||||
info!("pmt.unpin: pmt={:#x}", pmt);
|
||||
let proc = self.thread.proc();
|
||||
|
@ -131,7 +131,7 @@ impl Syscall<'_> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
///
|
||||
///
|
||||
#[allow(unused_variables, unused_mut)]
|
||||
pub fn sys_pc_firmware_tables(
|
||||
&self,
|
||||
|
@ -145,7 +145,7 @@ impl Syscall<'_> {
|
|||
.validate(ResourceKind::ROOT)?;
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(all(target_arch = "x86_64", target_os = "none"))] {
|
||||
let (acpi_rsdp, smbios) = kernel_hal::pc_firmware_tables();
|
||||
let (acpi_rsdp, smbios) = kernel_hal::x86_64::pc_firmware_tables();
|
||||
acpi_rsdp_ptr.write(acpi_rsdp)?;
|
||||
smbios_ptr.write(smbios)?;
|
||||
Ok(())
|
||||
|
@ -155,7 +155,7 @@ impl Syscall<'_> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Creates an interrupt object which represents a physical or virtual interrupt.
|
||||
/// Creates an interrupt object which represents a physical or virtual interrupt.
|
||||
pub fn sys_interrupt_create(
|
||||
&self,
|
||||
resource: HandleValue,
|
||||
|
@ -184,7 +184,7 @@ impl Syscall<'_> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// Binds or unbinds an interrupt object to a port.
|
||||
/// Binds or unbinds an interrupt object to a port.
|
||||
///
|
||||
/// The key used when binding the interrupt will be present in the key field of the `zx_port_packet_t`.
|
||||
pub fn sys_interrupt_bind(
|
||||
|
@ -213,7 +213,7 @@ impl Syscall<'_> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Triggers a virtual interrupt object.
|
||||
/// Triggers a virtual interrupt object.
|
||||
pub fn sys_interrupt_trigger(
|
||||
&self,
|
||||
interrupt: HandleValue,
|
||||
|
@ -231,7 +231,7 @@ impl Syscall<'_> {
|
|||
interrupt.trigger(timestamp)
|
||||
}
|
||||
|
||||
/// Acknowledge an interrupt and re-arm it.
|
||||
/// Acknowledge an interrupt and re-arm it.
|
||||
///
|
||||
/// This system call acknowledges an interrupt object, causing it to be eligible to trigger again (and delivering a packet to the port it is bound to).
|
||||
pub fn sys_interrupt_ack(&self, interrupt: HandleValue) -> ZxResult {
|
||||
|
@ -243,14 +243,14 @@ impl Syscall<'_> {
|
|||
interrupt.ack()
|
||||
}
|
||||
|
||||
/// Destroys an interrupt object.
|
||||
/// Destroys an interrupt object.
|
||||
pub fn sys_interrupt_destroy(&self, interrupt: HandleValue) -> ZxResult {
|
||||
info!("interupt.destory: interrupt={:?}", interrupt);
|
||||
let interrupt = self.thread.proc().get_object::<Interrupt>(interrupt)?;
|
||||
interrupt.destroy()
|
||||
}
|
||||
|
||||
/// A blocking syscall which causes the caller to wait until an interrupt is triggered.
|
||||
/// A blocking syscall which causes the caller to wait until an interrupt is triggered.
|
||||
pub async fn sys_interrupt_wait(
|
||||
&self,
|
||||
interrupt: HandleValue,
|
||||
|
|
Loading…
Reference in New Issue