kernel-hal: refactor for x86_64 bare-metal

This commit is contained in:
Yuekai Jia 2021-09-02 23:03:52 +08:00
parent 3b0e3296e8
commit ceacbc9d9c
61 changed files with 1265 additions and 1435 deletions

View File

@ -13,5 +13,4 @@ exclude = [
"zCore",
"rboot",
"linux-syscall",
"kernel-hal-bare",
]

View File

@ -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"

View File

@ -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::*;

View File

@ -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;

View File

@ -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
}

View File

@ -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;
}

View File

@ -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" }

View File

@ -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")]

View File

@ -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();
}

View File

@ -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 _
}
}
}

View File

@ -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
}
}
}

View File

@ -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);
}

View File

@ -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();
}
}

View File

@ -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,
);
}
}

View File

@ -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();
// }
}
}
}

View File

@ -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) }
}

View File

@ -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)
}

View File

@ -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),
}
}

View File

@ -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);
}
}

View File

@ -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;
}

View File

@ -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)
}
}
}

View File

@ -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);
}

View File

@ -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)
}
}
}

View File

@ -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);
}
}
}

View File

@ -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)
}
}

View File

@ -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;

View File

@ -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();
}

View File

@ -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::*;
}
}

View File

@ -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();

View File

@ -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!()
}

View File

@ -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());

View File

@ -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};

View File

@ -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());

View File

@ -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();

View File

@ -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;

View File

@ -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();

View File

@ -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"

View File

@ -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)

View File

@ -7,4 +7,3 @@ pub use self::x86_64::*;
pub mod riscv;
#[cfg(target_arch = "riscv64")]
pub use self::riscv::*;

View File

@ -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()

View File

@ -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,

View File

@ -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());

View File

@ -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.

View File

@ -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!(

View File

@ -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 {

View File

@ -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())),
})
}

View File

@ -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));
}

View File

@ -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(())
}

View File

@ -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,