mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-13 23:36:48 +00:00
Merge pull request #40 from sdww0/main
Finish PIT Timer, vmo and vmar passed the compilation
This commit is contained in:
commit
f944a5ead1
5
src/Cargo.lock
generated
5
src/Cargo.lock
generated
@ -127,6 +127,7 @@ version = "0.1.0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"kxos-frame",
|
"kxos-frame",
|
||||||
|
"kxos-frame-pod-derive",
|
||||||
"kxos-util",
|
"kxos-util",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"spin 0.9.4",
|
"spin 0.9.4",
|
||||||
@ -149,6 +150,9 @@ dependencies = [
|
|||||||
"kxos-frame",
|
"kxos-frame",
|
||||||
"kxos-frame-pod-derive",
|
"kxos-frame-pod-derive",
|
||||||
"kxos-pci",
|
"kxos-pci",
|
||||||
|
"kxos-rights-proc",
|
||||||
|
"kxos-typeflags",
|
||||||
|
"kxos-typeflags-util",
|
||||||
"kxos-virtio",
|
"kxos-virtio",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"spin 0.9.4",
|
"spin 0.9.4",
|
||||||
@ -182,6 +186,7 @@ version = "0.1.0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"kxos-frame",
|
"kxos-frame",
|
||||||
|
"kxos-frame-pod-derive",
|
||||||
"kxos-pci",
|
"kxos-pci",
|
||||||
"kxos-util",
|
"kxos-util",
|
||||||
"spin 0.9.4",
|
"spin 0.9.4",
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
use proc_macro2::TokenStream;
|
use proc_macro2::TokenStream;
|
||||||
use quote::quote;
|
use quote::quote;
|
||||||
use syn::{parse_macro_input, Data, DataStruct, DeriveInput, Fields};
|
use syn::{
|
||||||
|
parse_macro_input, punctuated::Punctuated, token::Comma, Data, DataEnum, DataStruct,
|
||||||
|
DeriveInput, Field, Fields,
|
||||||
|
};
|
||||||
|
|
||||||
#[proc_macro_derive(Pod)]
|
#[proc_macro_derive(Pod)]
|
||||||
pub fn derive_pod(input_token: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
pub fn derive_pod(input_token: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
||||||
@ -14,11 +17,22 @@ fn expand_derive_pod(input: DeriveInput) -> TokenStream {
|
|||||||
Data::Struct(DataStruct { fields, .. }) => match fields {
|
Data::Struct(DataStruct { fields, .. }) => match fields {
|
||||||
Fields::Named(fields_named) => fields_named.named,
|
Fields::Named(fields_named) => fields_named.named,
|
||||||
Fields::Unnamed(fields_unnamed) => fields_unnamed.unnamed,
|
Fields::Unnamed(fields_unnamed) => fields_unnamed.unnamed,
|
||||||
Fields::Unit => panic!("derive pod does not work for struct with unit field"),
|
Fields::Unit => Punctuated::new(),
|
||||||
},
|
},
|
||||||
|
Data::Enum(DataEnum { variants, .. }) => {
|
||||||
|
let mut fields: Punctuated<Field, Comma> = Punctuated::new();
|
||||||
|
for var in variants {
|
||||||
|
fields.extend(match var.fields {
|
||||||
|
Fields::Named(fields_named) => fields_named.named,
|
||||||
|
Fields::Unnamed(fields_unnamed) => fields_unnamed.unnamed,
|
||||||
|
Fields::Unit => Punctuated::new(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
fields
|
||||||
|
}
|
||||||
// Panic on compilation time if one tries to derive pod for enum or union.
|
// Panic on compilation time if one tries to derive pod for enum or union.
|
||||||
// It may not be a good idea, but works now.
|
// It may not be a good idea, but works now.
|
||||||
_ => panic!("derive pod only works for struct now."),
|
_ => panic!("derive pod only works for struct and enum now."),
|
||||||
};
|
};
|
||||||
|
|
||||||
// deal with generics
|
// deal with generics
|
||||||
|
@ -3,10 +3,14 @@
|
|||||||
pub mod framebuffer;
|
pub mod framebuffer;
|
||||||
mod io_port;
|
mod io_port;
|
||||||
pub mod pci;
|
pub mod pci;
|
||||||
|
mod pic;
|
||||||
pub mod serial;
|
pub mod serial;
|
||||||
|
|
||||||
pub use self::io_port::IoPort;
|
pub use self::io_port::IoPort;
|
||||||
|
pub(crate) use pic::{add_timeout_list, TICK};
|
||||||
|
pub use pic::{TimerCallback, TIMER_FREQ};
|
||||||
|
|
||||||
pub(crate) fn init(framebuffer: &'static mut bootloader::boot_info::FrameBuffer) {
|
pub(crate) fn init(framebuffer: &'static mut bootloader::boot_info::FrameBuffer) {
|
||||||
framebuffer::init(framebuffer);
|
framebuffer::init(framebuffer);
|
||||||
|
pic::init();
|
||||||
}
|
}
|
||||||
|
176
src/kxos-frame/src/device/pic.rs
Normal file
176
src/kxos-frame/src/device/pic.rs
Normal file
@ -0,0 +1,176 @@
|
|||||||
|
use crate::cell::Cell;
|
||||||
|
use crate::x86_64_util::out8;
|
||||||
|
use crate::{IrqAllocateHandle, TrapFrame};
|
||||||
|
use alloc::sync::Arc;
|
||||||
|
use alloc::vec::Vec;
|
||||||
|
use alloc::{boxed::Box, collections::BinaryHeap};
|
||||||
|
use core::any::Any;
|
||||||
|
use lazy_static::lazy_static;
|
||||||
|
use spin::Mutex;
|
||||||
|
|
||||||
|
const MASTER_CMD: u16 = 0x20;
|
||||||
|
const MASTER_DATA: u16 = MASTER_CMD + 1;
|
||||||
|
const SLAVE_CMD: u16 = 0xA0;
|
||||||
|
const SLAVE_DATA: u16 = SLAVE_CMD + 1;
|
||||||
|
|
||||||
|
const TIMER_RATE: u32 = 1193182;
|
||||||
|
/// This value represent the base timer frequency in Hz
|
||||||
|
pub const TIMER_FREQ: u64 = 100;
|
||||||
|
const TIMER_PERIOD_IO_PORT: u16 = 0x40;
|
||||||
|
const TIMER_MODE_IO_PORT: u16 = 0x43;
|
||||||
|
const TIMER_SQUARE_WAVE: u8 = 0x36;
|
||||||
|
|
||||||
|
const TIMER_IRQ_NUM: u8 = 32;
|
||||||
|
|
||||||
|
pub static mut TICK: u64 = 0;
|
||||||
|
|
||||||
|
lazy_static! {
|
||||||
|
static ref TIMER_IRQ: Mutex<IrqAllocateHandle> = Mutex::new(
|
||||||
|
crate::trap::allocate_target_irq(TIMER_IRQ_NUM).expect("Timer irq Allocate error")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn init() {
|
||||||
|
// Start initialization
|
||||||
|
out8(MASTER_CMD, 0x11);
|
||||||
|
out8(SLAVE_CMD, 0x11);
|
||||||
|
|
||||||
|
// Set offsets
|
||||||
|
out8(MASTER_DATA, 0x20);
|
||||||
|
out8(SLAVE_DATA, 0x28);
|
||||||
|
|
||||||
|
// Set up cascade
|
||||||
|
out8(MASTER_DATA, 4);
|
||||||
|
out8(SLAVE_DATA, 2);
|
||||||
|
|
||||||
|
// Set up interrupt mode (1 is 8086/88 mode, 2 is auto EOI)
|
||||||
|
out8(MASTER_DATA, 1);
|
||||||
|
out8(SLAVE_DATA, 1);
|
||||||
|
|
||||||
|
// Unmask interrupts
|
||||||
|
out8(MASTER_DATA, 0);
|
||||||
|
out8(SLAVE_DATA, 0);
|
||||||
|
|
||||||
|
// Ack remaining interrupts
|
||||||
|
out8(MASTER_CMD, 0x20);
|
||||||
|
out8(SLAVE_CMD, 0x20);
|
||||||
|
|
||||||
|
// Initialize timer.
|
||||||
|
let cycle = TIMER_RATE / TIMER_FREQ as u32; // 1ms per interrupt.
|
||||||
|
out8(TIMER_MODE_IO_PORT, TIMER_SQUARE_WAVE);
|
||||||
|
out8(TIMER_PERIOD_IO_PORT, (cycle & 0xFF) as _);
|
||||||
|
out8(TIMER_PERIOD_IO_PORT, (cycle >> 8) as _);
|
||||||
|
TIMER_IRQ.lock().on_active(timer_callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn ack() {
|
||||||
|
out8(MASTER_CMD, 0x20);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn timer_callback(trap_frame: &TrapFrame) {
|
||||||
|
// FIXME: disable and enable interupt will cause infinity loop
|
||||||
|
// x86_64_util::disable_interrupts();
|
||||||
|
ack();
|
||||||
|
let current_ms;
|
||||||
|
unsafe {
|
||||||
|
current_ms = TICK;
|
||||||
|
TICK += 1;
|
||||||
|
}
|
||||||
|
let timeout_list = TIMEOUT_LIST.get();
|
||||||
|
let mut callbacks: Vec<Arc<TimerCallback>> = Vec::new();
|
||||||
|
while let Some(t) = timeout_list.peek() {
|
||||||
|
if t.expire_ms <= current_ms {
|
||||||
|
callbacks.push(timeout_list.pop().unwrap());
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for callback in callbacks {
|
||||||
|
if callback.is_enable() {
|
||||||
|
callback.callback.call((&callback,));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// x86_64_util::enable_interrupts();
|
||||||
|
}
|
||||||
|
|
||||||
|
lazy_static! {
|
||||||
|
static ref TIMEOUT_LIST: Cell<BinaryHeap<Arc<TimerCallback>>> = Cell::new(BinaryHeap::new());
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct TimerCallback {
|
||||||
|
expire_ms: u64,
|
||||||
|
data: Arc<dyn Any + Send + Sync>,
|
||||||
|
callback: Box<dyn Fn(&TimerCallback) + Send + Sync>,
|
||||||
|
enable: Cell<bool>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TimerCallback {
|
||||||
|
fn new(
|
||||||
|
timeout_ms: u64,
|
||||||
|
data: Arc<dyn Any + Send + Sync>,
|
||||||
|
callback: Box<dyn Fn(&TimerCallback) + Send + Sync>,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
expire_ms: timeout_ms,
|
||||||
|
data,
|
||||||
|
callback,
|
||||||
|
enable: Cell::new(true),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn data(&self) -> &Arc<dyn Any + Send + Sync> {
|
||||||
|
&self.data
|
||||||
|
}
|
||||||
|
|
||||||
|
/// disable this timeout
|
||||||
|
pub fn disable(&self) {
|
||||||
|
*self.enable.get() = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// enable this timeout
|
||||||
|
pub fn enable(&self) {
|
||||||
|
*self.enable.get() = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_enable(&self) -> bool {
|
||||||
|
*self.enable
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq for TimerCallback {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
self.expire_ms == other.expire_ms
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Eq for TimerCallback {}
|
||||||
|
|
||||||
|
impl PartialOrd for TimerCallback {
|
||||||
|
fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
|
||||||
|
Some(self.cmp(other))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Ord for TimerCallback {
|
||||||
|
fn cmp(&self, other: &Self) -> core::cmp::Ordering {
|
||||||
|
self.expire_ms.cmp(&other.expire_ms).reverse()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// add timeout task into timeout list, the frequency see const TIMER_FREQ
|
||||||
|
///
|
||||||
|
/// user should ensure that the callback function cannot take too much time
|
||||||
|
///
|
||||||
|
pub fn add_timeout_list<F, T>(timeout: u64, data: T, callback: F) -> Arc<TimerCallback>
|
||||||
|
where
|
||||||
|
F: Fn(&TimerCallback) + Send + Sync + 'static,
|
||||||
|
T: Any + Send + Sync,
|
||||||
|
{
|
||||||
|
unsafe {
|
||||||
|
let timer_callback = TimerCallback::new(TICK + timeout, Arc::new(data), Box::new(callback));
|
||||||
|
let arc = Arc::new(timer_callback);
|
||||||
|
TIMEOUT_LIST.get().push(arc.clone());
|
||||||
|
arc
|
||||||
|
}
|
||||||
|
}
|
@ -26,7 +26,6 @@ pub mod timer;
|
|||||||
pub mod trap;
|
pub mod trap;
|
||||||
pub mod user;
|
pub mod user;
|
||||||
mod util;
|
mod util;
|
||||||
#[macro_use]
|
|
||||||
pub mod vm;
|
pub mod vm;
|
||||||
pub(crate) mod x86_64_util;
|
pub(crate) mod x86_64_util;
|
||||||
|
|
||||||
@ -62,10 +61,6 @@ pub use crate::serial_println as println;
|
|||||||
|
|
||||||
pub fn init(boot_info: &'static mut BootInfo) {
|
pub fn init(boot_info: &'static mut BootInfo) {
|
||||||
let siz = boot_info.framebuffer.as_ref().unwrap() as *const FrameBuffer as usize;
|
let siz = boot_info.framebuffer.as_ref().unwrap() as *const FrameBuffer as usize;
|
||||||
device::init(boot_info.framebuffer.as_mut().unwrap());
|
|
||||||
device::framebuffer::WRITER.lock().as_mut().unwrap().clear();
|
|
||||||
trap::init();
|
|
||||||
enable_common_cpu_features();
|
|
||||||
let mut memory_init = false;
|
let mut memory_init = false;
|
||||||
// memory
|
// memory
|
||||||
for region in boot_info.memory_regions.iter() {
|
for region in boot_info.memory_regions.iter() {
|
||||||
@ -84,13 +79,19 @@ pub fn init(boot_info: &'static mut BootInfo) {
|
|||||||
if !memory_init {
|
if !memory_init {
|
||||||
panic!("memory init failed");
|
panic!("memory init failed");
|
||||||
}
|
}
|
||||||
|
device::init(boot_info.framebuffer.as_mut().unwrap());
|
||||||
|
device::framebuffer::WRITER.lock().as_mut().unwrap().clear();
|
||||||
|
trap::init();
|
||||||
|
enable_common_cpu_features();
|
||||||
unsafe {
|
unsafe {
|
||||||
for i in 0..256 {
|
for i in 0..256 {
|
||||||
IRQ_CALLBACK_LIST.push(IrqLine::acquire(i as u8).on_active(general_handler))
|
IRQ_CALLBACK_LIST.push(IrqLine::acquire(i as u8).on_active(general_handler))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// uncomment below code to enable timer interrupt
|
||||||
|
// x86_64_util::enable_interrupts_and_hlt();
|
||||||
}
|
}
|
||||||
fn general_handler(trap_frame: TrapFrame) {
|
fn general_handler(trap_frame: &TrapFrame) {
|
||||||
println!("{:#x?}", trap_frame);
|
println!("{:#x?}", trap_frame);
|
||||||
println!("rip = 0x{:x}", trap_frame.rip);
|
println!("rip = 0x{:x}", trap_frame.rip);
|
||||||
println!("rsp = 0x{:x}", trap_frame.rsp);
|
println!("rsp = 0x{:x}", trap_frame.rsp);
|
||||||
@ -113,7 +114,7 @@ where
|
|||||||
T: Fn(),
|
T: Fn(),
|
||||||
{
|
{
|
||||||
fn run(&self) {
|
fn run(&self) {
|
||||||
serial_print!("{}...\t", core::any::type_name::<T>());
|
serial_print!("{}...\n", core::any::type_name::<T>());
|
||||||
self();
|
self();
|
||||||
serial_println!("[ok]");
|
serial_println!("[ok]");
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,11 @@
|
|||||||
//! Timer.
|
//! Timer.
|
||||||
|
|
||||||
use crate::prelude::*;
|
use crate::{
|
||||||
|
device::{TimerCallback, TICK, TIMER_FREQ},
|
||||||
|
prelude::*,
|
||||||
|
};
|
||||||
use core::time::Duration;
|
use core::time::Duration;
|
||||||
|
use spin::Mutex;
|
||||||
|
|
||||||
/// A timer invokes a callback function after a specified span of time elapsed.
|
/// A timer invokes a callback function after a specified span of time elapsed.
|
||||||
///
|
///
|
||||||
@ -11,33 +15,96 @@ use core::time::Duration;
|
|||||||
///
|
///
|
||||||
/// Timers are one-shot. If the time is out, one has to set the timer again
|
/// Timers are one-shot. If the time is out, one has to set the timer again
|
||||||
/// in order to trigger the callback again.
|
/// in order to trigger the callback again.
|
||||||
pub struct Timer {}
|
pub struct Timer {
|
||||||
|
function: Arc<dyn Fn(Arc<Self>) + Send + Sync>,
|
||||||
|
inner: Mutex<TimerInner>,
|
||||||
|
}
|
||||||
|
#[derive(Default)]
|
||||||
|
struct TimerInner {
|
||||||
|
start_tick: u64,
|
||||||
|
timeout_tick: u64,
|
||||||
|
timer_callback: Option<Arc<TimerCallback>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn timer_callback(callback: &TimerCallback) {
|
||||||
|
let data = callback.data();
|
||||||
|
if data.is::<Arc<Timer>>() {
|
||||||
|
let timer = data.downcast_ref::<Arc<Timer>>().unwrap();
|
||||||
|
timer.function.call((timer.clone(),));
|
||||||
|
} else {
|
||||||
|
panic!("the timer callback is not Timer structure");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const NANOS_DIVIDE: u64 = 1_000_000_000 / TIMER_FREQ;
|
||||||
|
|
||||||
impl Timer {
|
impl Timer {
|
||||||
/// Creates a new instance, given a callback function.
|
/// Creates a new instance, given a callback function.
|
||||||
pub fn new<F>(f: F) -> Result<Self>
|
pub fn new<F>(f: F) -> Result<Arc<Self>>
|
||||||
where
|
where
|
||||||
F: FnMut(&Self),
|
F: Fn(Arc<Timer>) + Send + Sync + 'static,
|
||||||
{
|
{
|
||||||
todo!()
|
Ok(Arc::new(Self {
|
||||||
|
function: Arc::new(f),
|
||||||
|
inner: Mutex::new(TimerInner::default()),
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set a timeout value.
|
/// Set a timeout value.
|
||||||
///
|
///
|
||||||
/// If a timeout value is already set, the timeout value will be refreshed.
|
/// If a timeout value is already set, the timeout value will be refreshed.
|
||||||
pub fn set(&self, timeout: Duration) {
|
///
|
||||||
todo!()
|
pub fn set(self: Arc<Self>, timeout: Duration) {
|
||||||
|
let mut lock = self.inner.lock();
|
||||||
|
match &lock.timer_callback {
|
||||||
|
Some(callback) => {
|
||||||
|
callback.disable();
|
||||||
|
}
|
||||||
|
None => {}
|
||||||
|
}
|
||||||
|
let tick_count = timeout.as_secs() * TIMER_FREQ
|
||||||
|
+ if timeout.subsec_nanos() != 0 {
|
||||||
|
(timeout.subsec_nanos() as u64 - 1) / NANOS_DIVIDE + 1
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
};
|
||||||
|
unsafe {
|
||||||
|
lock.start_tick = TICK;
|
||||||
|
lock.timeout_tick = TICK + tick_count;
|
||||||
|
}
|
||||||
|
lock.timer_callback = Some(crate::device::add_timeout_list(
|
||||||
|
tick_count,
|
||||||
|
self.clone(),
|
||||||
|
timer_callback,
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the remaining timeout value.
|
/// Returns the remaining timeout value.
|
||||||
///
|
///
|
||||||
/// If the timer is not set, then the remaining timeout value is zero.
|
/// If the timer is not set, then the remaining timeout value is zero.
|
||||||
pub fn remain(&self) -> Duration {
|
pub fn remain(&self) -> Duration {
|
||||||
todo!()
|
let lock = self.inner.lock();
|
||||||
|
let tick_remain;
|
||||||
|
unsafe {
|
||||||
|
tick_remain = lock.timeout_tick as i64 - TICK as i64;
|
||||||
|
}
|
||||||
|
if tick_remain <= 0 {
|
||||||
|
Duration::new(0, 0)
|
||||||
|
} else {
|
||||||
|
let second_count = tick_remain as u64 / TIMER_FREQ;
|
||||||
|
let remain_count = tick_remain as u64 % TIMER_FREQ;
|
||||||
|
Duration::new(second_count, (remain_count * NANOS_DIVIDE) as u32)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Clear the timeout value.
|
/// Clear the timeout value.
|
||||||
pub fn clear(&self) {
|
pub fn clear(&self) {
|
||||||
todo!()
|
let mut lock = self.inner.lock();
|
||||||
|
if let Some(callback) = &lock.timer_callback {
|
||||||
|
callback.disable();
|
||||||
|
}
|
||||||
|
lock.timeout_tick = 0;
|
||||||
|
lock.start_tick = 0;
|
||||||
|
lock.timer_callback = None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,7 @@ use crate::task::{
|
|||||||
use super::{irq::IRQ_LIST, *};
|
use super::{irq::IRQ_LIST, *};
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub(crate) extern "C" fn syscall_handler(f: &'static mut SyscallFrame) -> isize {
|
pub(crate) extern "C" fn syscall_handler(f: &mut SyscallFrame) -> isize {
|
||||||
let r = &f.caller;
|
let r = &f.caller;
|
||||||
let current = Task::current();
|
let current = Task::current();
|
||||||
current.inner_exclusive_access().is_from_trap = false;
|
current.inner_exclusive_access().is_from_trap = false;
|
||||||
@ -20,7 +20,7 @@ pub(crate) extern "C" fn syscall_handler(f: &'static mut SyscallFrame) -> isize
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub(crate) extern "C" fn trap_handler(f: &'static mut TrapFrame) {
|
pub(crate) extern "C" fn trap_handler(f: &mut TrapFrame) {
|
||||||
if !is_from_kernel(f.cs) {
|
if !is_from_kernel(f.cs) {
|
||||||
let current = Task::current();
|
let current = Task::current();
|
||||||
current.inner_exclusive_access().is_from_trap = true;
|
current.inner_exclusive_access().is_from_trap = true;
|
||||||
@ -37,11 +37,18 @@ pub(crate) extern "C" fn trap_handler(f: &'static mut TrapFrame) {
|
|||||||
let irq_line = IRQ_LIST.get(f.id as usize).unwrap();
|
let irq_line = IRQ_LIST.get(f.id as usize).unwrap();
|
||||||
let callback_functions = irq_line.callback_list();
|
let callback_functions = irq_line.callback_list();
|
||||||
for callback_function in callback_functions.iter() {
|
for callback_function in callback_functions.iter() {
|
||||||
callback_function.call(f.clone());
|
callback_function.call(f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
panic!("cannot handle kernel exception now");
|
if is_cpu_fault(f) {
|
||||||
|
panic!("cannot handle kernel cpu fault now");
|
||||||
|
}
|
||||||
|
let irq_line = IRQ_LIST.get(f.id as usize).unwrap();
|
||||||
|
let callback_functions = irq_line.callback_list();
|
||||||
|
for callback_function in callback_functions.iter() {
|
||||||
|
callback_function.call(f);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,6 +20,14 @@ pub fn allocate_irq() -> Result<IrqAllocateHandle> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn allocate_target_irq(target_irq: u8) -> Result<IrqAllocateHandle> {
|
||||||
|
if NOT_USING_IRQ.lock().get_target(target_irq as usize) {
|
||||||
|
Ok(IrqAllocateHandle::new(target_irq))
|
||||||
|
} else {
|
||||||
|
Err(Error::NotEnoughResources)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// The handle to a allocate irq number between [32,256), used in std and other parts in kxos
|
/// The handle to a allocate irq number between [32,256), used in std and other parts in kxos
|
||||||
///
|
///
|
||||||
/// When the handle is dropped, all the callback in this will be unregistered automatically.
|
/// When the handle is dropped, all the callback in this will be unregistered automatically.
|
||||||
@ -50,7 +58,7 @@ impl IrqAllocateHandle {
|
|||||||
/// For each IRQ line, multiple callbacks may be registered.
|
/// For each IRQ line, multiple callbacks may be registered.
|
||||||
pub fn on_active<F>(&mut self, callback: F)
|
pub fn on_active<F>(&mut self, callback: F)
|
||||||
where
|
where
|
||||||
F: Fn(TrapFrame) + Sync + Send + 'static,
|
F: Fn(&TrapFrame) + Sync + Send + 'static,
|
||||||
{
|
{
|
||||||
self.callbacks.push(self.irq.on_active(callback))
|
self.callbacks.push(self.irq.on_active(callback))
|
||||||
}
|
}
|
||||||
@ -87,12 +95,12 @@ lazy_static! {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct CallbackElement {
|
pub struct CallbackElement {
|
||||||
function: Box<dyn Fn(TrapFrame) + Send + Sync + 'static>,
|
function: Box<dyn Fn(&TrapFrame) + Send + Sync + 'static>,
|
||||||
id: usize,
|
id: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CallbackElement {
|
impl CallbackElement {
|
||||||
pub fn call(&self, element: TrapFrame) {
|
pub fn call(&self, element: &TrapFrame) {
|
||||||
self.function.call((element,));
|
self.function.call((element,));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -140,7 +148,7 @@ impl IrqLine {
|
|||||||
/// For each IRQ line, multiple callbacks may be registered.
|
/// For each IRQ line, multiple callbacks may be registered.
|
||||||
pub fn on_active<F>(&self, callback: F) -> IrqCallbackHandle
|
pub fn on_active<F>(&self, callback: F) -> IrqCallbackHandle
|
||||||
where
|
where
|
||||||
F: Fn(TrapFrame) + Sync + Send + 'static,
|
F: Fn(&TrapFrame) + Sync + Send + 'static,
|
||||||
{
|
{
|
||||||
let allocate_id = ID_ALLOCATOR.lock().alloc();
|
let allocate_id = ID_ALLOCATOR.lock().alloc();
|
||||||
self.callback_list.lock().push(CallbackElement {
|
self.callback_list.lock().push(CallbackElement {
|
||||||
|
@ -2,7 +2,7 @@ mod handler;
|
|||||||
mod irq;
|
mod irq;
|
||||||
|
|
||||||
pub use self::irq::{allocate_irq, IrqAllocateHandle};
|
pub use self::irq::{allocate_irq, IrqAllocateHandle};
|
||||||
pub(crate) use self::irq::{IrqCallbackHandle, IrqLine};
|
pub(crate) use self::irq::{allocate_target_irq, IrqCallbackHandle, IrqLine};
|
||||||
use core::{fmt::Debug, mem::size_of_val};
|
use core::{fmt::Debug, mem::size_of_val};
|
||||||
|
|
||||||
use crate::{x86_64_util::*, *};
|
use crate::{x86_64_util::*, *};
|
||||||
|
@ -3,6 +3,7 @@ use alloc::vec::Vec;
|
|||||||
pub struct RecycleAllocator {
|
pub struct RecycleAllocator {
|
||||||
current: usize,
|
current: usize,
|
||||||
recycled: Vec<usize>,
|
recycled: Vec<usize>,
|
||||||
|
skip: Vec<usize>,
|
||||||
max: usize,
|
max: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -11,6 +12,7 @@ impl RecycleAllocator {
|
|||||||
RecycleAllocator {
|
RecycleAllocator {
|
||||||
current: 0,
|
current: 0,
|
||||||
recycled: Vec::new(),
|
recycled: Vec::new(),
|
||||||
|
skip: Vec::new(),
|
||||||
max: usize::MAX - 1,
|
max: usize::MAX - 1,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -19,30 +21,73 @@ impl RecycleAllocator {
|
|||||||
RecycleAllocator {
|
RecycleAllocator {
|
||||||
current: start,
|
current: start,
|
||||||
recycled: Vec::new(),
|
recycled: Vec::new(),
|
||||||
|
skip: Vec::new(),
|
||||||
max: max,
|
max: max,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
pub fn alloc(&mut self) -> usize {
|
pub fn alloc(&mut self) -> usize {
|
||||||
if self.current == self.max && self.recycled.is_empty() {
|
if let Some(id) = self.recycled.pop() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
// recycle list is empty, need to use current to allocate an id.
|
||||||
|
// it should skip the element in skip list
|
||||||
|
while self.skip.contains(&self.current) {
|
||||||
|
self.current += 1;
|
||||||
|
}
|
||||||
|
if self.current == self.max {
|
||||||
return usize::MAX;
|
return usize::MAX;
|
||||||
}
|
}
|
||||||
if let Some(id) = self.recycled.pop() {
|
|
||||||
id
|
|
||||||
} else {
|
|
||||||
self.current += 1;
|
self.current += 1;
|
||||||
self.current - 1
|
self.current - 1
|
||||||
}
|
}
|
||||||
}
|
/// deallocate a id, it should fit one of the following requirement, otherwise it will panic:
|
||||||
|
///
|
||||||
|
/// 1. It is in the skip list
|
||||||
|
///
|
||||||
|
/// 2. It smaller than current and not in recycled list
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
pub fn dealloc(&mut self, id: usize) {
|
pub fn dealloc(&mut self, id: usize) {
|
||||||
|
if !self.skip.contains(&id) {
|
||||||
assert!(id < self.current);
|
assert!(id < self.current);
|
||||||
assert!(
|
assert!(
|
||||||
!self.recycled.iter().any(|i| *i == id),
|
!self.recycled.iter().any(|i| *i == id),
|
||||||
"id {} has been deallocated!",
|
"id {} has been deallocated!",
|
||||||
id
|
id
|
||||||
);
|
);
|
||||||
|
} else {
|
||||||
|
// if the value is in skip list, then remove it from the skip list
|
||||||
|
self.skip.retain(|value| *value != id);
|
||||||
|
}
|
||||||
self.recycled.push(id);
|
self.recycled.push(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// get target id in the list, it will return true if the target can used, false if can not used.
|
||||||
|
/// the target need to meet one of the following requirement so that it can used:
|
||||||
|
///
|
||||||
|
/// 1. It is in the recycled list
|
||||||
|
///
|
||||||
|
/// 2. It is bigger than the current, smaller than max and not in the skip list
|
||||||
|
///
|
||||||
|
pub fn get_target(&mut self, target: usize) -> bool {
|
||||||
|
if target >= self.max {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if target >= self.current {
|
||||||
|
if self.skip.contains(&target) {
|
||||||
|
false
|
||||||
|
} else {
|
||||||
|
self.skip.push(target);
|
||||||
|
true
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if self.recycled.contains(&target) {
|
||||||
|
self.recycled.retain(|value| *value != target);
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,6 @@ pub type Paddr = usize;
|
|||||||
|
|
||||||
mod frame;
|
mod frame;
|
||||||
mod io;
|
mod io;
|
||||||
#[macro_use]
|
|
||||||
mod pod;
|
mod pod;
|
||||||
mod space;
|
mod space;
|
||||||
|
|
||||||
|
@ -52,8 +52,6 @@ pub unsafe trait Pod: Copy + Sized + Debug {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// FIXME: use derive instead
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! impl_pod_for {
|
macro_rules! impl_pod_for {
|
||||||
($($pod_ty:ty),*) => {
|
($($pod_ty:ty),*) => {
|
||||||
$(unsafe impl Pod for $pod_ty {})*
|
$(unsafe impl Pod for $pod_ty {})*
|
||||||
|
@ -77,6 +77,13 @@ pub fn enable_interrupts_and_hlt() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn enable_interrupts() {
|
||||||
|
unsafe {
|
||||||
|
asm!("sti", options(nomem, nostack));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub const RING0: u16 = 0;
|
pub const RING0: u16 = 0;
|
||||||
pub const RING3: u16 = 3;
|
pub const RING3: u16 = 3;
|
||||||
|
|
||||||
|
@ -10,6 +10,7 @@ bitflags = "1.3"
|
|||||||
spin = "0.9.4"
|
spin = "0.9.4"
|
||||||
kxos-frame = {path = "../kxos-frame"}
|
kxos-frame = {path = "../kxos-frame"}
|
||||||
kxos-util = {path="../kxos-util"}
|
kxos-util = {path="../kxos-util"}
|
||||||
|
kxos-frame-pod-derive= {path="../kxos-frame-pod-derive"}
|
||||||
|
|
||||||
[dependencies.lazy_static]
|
[dependencies.lazy_static]
|
||||||
version = "1.0"
|
version = "1.0"
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
|
|
||||||
use crate::util::{CSpaceAccessMethod, Location, BAR};
|
use crate::util::{CSpaceAccessMethod, Location, BAR};
|
||||||
|
use kxos_frame_pod_derive::Pod;
|
||||||
|
|
||||||
use super::capability::msix::CapabilityMSIXData;
|
use super::capability::msix::CapabilityMSIXData;
|
||||||
|
|
||||||
@ -21,7 +22,7 @@ pub struct MSIXEntry {
|
|||||||
pub irq_handle: IrqAllocateHandle,
|
pub irq_handle: IrqAllocateHandle,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default, Copy, Clone, PartialEq, Eq)]
|
#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, Pod)]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct MSIXTableEntry {
|
pub struct MSIXTableEntry {
|
||||||
pub msg_addr: u32,
|
pub msg_addr: u32,
|
||||||
@ -30,8 +31,6 @@ pub struct MSIXTableEntry {
|
|||||||
pub vector_control: u32,
|
pub vector_control: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
kxos_frame::impl_pod_for!(MSIXTableEntry);
|
|
||||||
|
|
||||||
impl MSIX {
|
impl MSIX {
|
||||||
/// create a MSIX instance, it allocate the irq number automatically.
|
/// create a MSIX instance, it allocate the irq number automatically.
|
||||||
pub fn new(
|
pub fn new(
|
||||||
|
@ -10,6 +10,9 @@ kxos-frame = {path = "../kxos-frame"}
|
|||||||
kxos-frame-pod-derive = {path = "../kxos-frame-pod-derive"}
|
kxos-frame-pod-derive = {path = "../kxos-frame-pod-derive"}
|
||||||
kxos-pci = {path="../kxos-pci"}
|
kxos-pci = {path="../kxos-pci"}
|
||||||
kxos-virtio = {path="../kxos-virtio"}
|
kxos-virtio = {path="../kxos-virtio"}
|
||||||
|
kxos-typeflags = {path="../kxos-typeflags"}
|
||||||
|
kxos-typeflags-util = {path="../kxos-typeflags-util"}
|
||||||
|
kxos-rights-proc = {path="../kxos-rights-proc"}
|
||||||
|
|
||||||
# parse elf file
|
# parse elf file
|
||||||
xmas-elf = "0.8.0"
|
xmas-elf = "0.8.0"
|
||||||
|
@ -3,7 +3,8 @@ use core::hint::spin_loop;
|
|||||||
use crate::process::Process;
|
use crate::process::Process;
|
||||||
use alloc::sync::Arc;
|
use alloc::sync::Arc;
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
use kxos_frame::{impl_pod_for, info};
|
use kxos_frame::info;
|
||||||
|
use kxos_frame_pod_derive::Pod;
|
||||||
use kxos_pci::PCIDevice;
|
use kxos_pci::PCIDevice;
|
||||||
use kxos_virtio::PCIVirtioDevice;
|
use kxos_virtio::PCIVirtioDevice;
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
@ -18,7 +19,7 @@ pub struct VirtioBlockDevice {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Debug, Copy, Clone)]
|
#[derive(Debug, Copy, Clone, Pod)]
|
||||||
pub struct BlkReq {
|
pub struct BlkReq {
|
||||||
pub type_: ReqType,
|
pub type_: ReqType,
|
||||||
pub reserved: u32,
|
pub reserved: u32,
|
||||||
@ -27,13 +28,13 @@ pub struct BlkReq {
|
|||||||
|
|
||||||
/// Response of a VirtIOBlk request.
|
/// Response of a VirtIOBlk request.
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Debug, Copy, Clone)]
|
#[derive(Debug, Copy, Clone, Pod)]
|
||||||
pub struct BlkResp {
|
pub struct BlkResp {
|
||||||
pub status: RespStatus,
|
pub status: RespStatus,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[repr(u32)]
|
#[repr(u32)]
|
||||||
#[derive(Debug, Copy, Clone)]
|
#[derive(Debug, Copy, Clone, Pod)]
|
||||||
pub enum ReqType {
|
pub enum ReqType {
|
||||||
In = 0,
|
In = 0,
|
||||||
Out = 1,
|
Out = 1,
|
||||||
@ -43,7 +44,7 @@ pub enum ReqType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
#[derive(Debug, Eq, PartialEq, Copy, Clone)]
|
#[derive(Debug, Eq, PartialEq, Copy, Clone, Pod)]
|
||||||
pub enum RespStatus {
|
pub enum RespStatus {
|
||||||
/// Ok.
|
/// Ok.
|
||||||
Ok = 0,
|
Ok = 0,
|
||||||
@ -63,8 +64,6 @@ impl Default for BlkResp {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl_pod_for!(BlkResp, RespStatus, ReqType, BlkReq);
|
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
// TODO: use dyn BlockDevice instead
|
// TODO: use dyn BlockDevice instead
|
||||||
pub static ref BLOCK_DEVICE: Arc<Mutex<Option<VirtioBlockDevice>>> = Arc::new(Mutex::new(None)) ;
|
pub static ref BLOCK_DEVICE: Arc<Mutex<Option<VirtioBlockDevice>>> = Arc::new(Mutex::new(None)) ;
|
||||||
@ -124,7 +123,7 @@ impl BlockDevice for VirtioBlockDevice {
|
|||||||
|
|
||||||
impl VirtioBlockDevice {
|
impl VirtioBlockDevice {
|
||||||
fn new(mut virtio_device: PCIVirtioDevice) -> Self {
|
fn new(mut virtio_device: PCIVirtioDevice) -> Self {
|
||||||
fn handle_block_device(frame: TrapFrame) {
|
fn handle_block_device(frame: &TrapFrame) {
|
||||||
info!("pci block device queue interrupt");
|
info!("pci block device queue interrupt");
|
||||||
BLOCK_DEVICE.lock().as_ref().unwrap().handle_irq()
|
BLOCK_DEVICE.lock().as_ref().unwrap().handle_irq()
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
#![feature(half_open_range_patterns)]
|
#![feature(half_open_range_patterns)]
|
||||||
#![feature(exclusive_range_pattern)]
|
#![feature(exclusive_range_pattern)]
|
||||||
#![feature(btree_drain_filter)]
|
#![feature(btree_drain_filter)]
|
||||||
|
#![feature(const_option)]
|
||||||
|
|
||||||
use kxos_frame::{debug, info, println};
|
use kxos_frame::{debug, info, println};
|
||||||
use process::Process;
|
use process::Process;
|
||||||
@ -22,9 +23,11 @@ pub mod fs;
|
|||||||
mod memory;
|
mod memory;
|
||||||
pub mod prelude;
|
pub mod prelude;
|
||||||
mod process;
|
mod process;
|
||||||
|
pub mod rights;
|
||||||
pub mod syscall;
|
pub mod syscall;
|
||||||
mod user_apps;
|
mod user_apps;
|
||||||
mod util;
|
mod util;
|
||||||
|
pub mod vm;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate kxos_frame_pod_derive;
|
extern crate kxos_frame_pod_derive;
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use typeflags::typeflags;
|
|
||||||
use bitflags::bitflags;
|
use bitflags::bitflags;
|
||||||
|
use kxos_typeflags::type_flags;
|
||||||
|
|
||||||
bitflags! {
|
bitflags! {
|
||||||
/// Value-based access rights.
|
/// Value-based access rights.
|
||||||
@ -10,46 +10,48 @@ bitflags! {
|
|||||||
/// Here, we give some sensible semantics for each access right.
|
/// Here, we give some sensible semantics for each access right.
|
||||||
pub struct Rights: u32 {
|
pub struct Rights: u32 {
|
||||||
/// Allows duplicating a capability.
|
/// Allows duplicating a capability.
|
||||||
const DUP: u32 = 1 << 0;
|
const DUP = 1 << 0;
|
||||||
/// Allows reading data from a data source (files, VM objects, etc.) or
|
/// Allows reading data from a data source (files, VM objects, etc.) or
|
||||||
/// creating readable memory mappings.
|
/// creating readable memory mappings.
|
||||||
const READ: u32 = 1 << 1;
|
const READ = 1 << 1;
|
||||||
/// Allows writing data to a data sink (files, VM objects, etc.) or
|
/// Allows writing data to a data sink (files, VM objects, etc.) or
|
||||||
/// creating writable memory mappings.
|
/// creating writable memory mappings.
|
||||||
const WRITE: u32 = 1 << 2;
|
const WRITE = 1 << 2;
|
||||||
/// Allows creating executable memory mappings.
|
/// Allows creating executable memory mappings.
|
||||||
const EXEC: u32 = 1 << 3;
|
const EXEC = 1 << 3;
|
||||||
/// Allows sending notifications or signals.
|
/// Allows sending notifications or signals.
|
||||||
const SIGNAL: u32 = 1 << 7;
|
const SIGNAL = 1 << 7;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
typeflags! {
|
|
||||||
/// Type-based access rights.
|
/// Type-based access rights.
|
||||||
///
|
///
|
||||||
/// Similar to value-based access rights (`Rights`), but represented in
|
/// Similar to value-based access rights (`Rights`), but represented in
|
||||||
/// types.
|
/// types.
|
||||||
|
///
|
||||||
|
/// pub trait TRights: u32 {
|
||||||
|
/// /// Allows duplicating a capability.
|
||||||
|
/// struct Dup: u32 = Rights::DUP;
|
||||||
|
/// /// Allows reading data from a data source (files, VM objects, etc.) or
|
||||||
|
/// /// creating readable memory mappings.
|
||||||
|
/// struct Read: u32 = Rights::READ;
|
||||||
|
/// /// Allows writing data to a data sink (files, VM objects, etc.) or
|
||||||
|
/// /// creating writable memory mappings.
|
||||||
|
/// struct Write: u32 = Rights::WRITE;
|
||||||
|
/// /// Allows creating executable memory mappings.
|
||||||
|
/// struct Exec: u32 = Rights::EXEC;
|
||||||
|
/// /// Allows sending notifications or signals.
|
||||||
|
/// struct Signal: u32 = Rights::SIGNAL;
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
type_flags! {
|
||||||
pub trait TRights: u32 {
|
pub trait TRights: u32 {
|
||||||
/// Allows duplicating a capability.
|
pub struct Dup = 1 <<0;
|
||||||
struct Dup: u32 = Rights::DUP;
|
pub struct Read = 1 <<1;
|
||||||
/// Allows reading data from a data source (files, VM objects, etc.) or
|
pub struct Write = 1 <<2;
|
||||||
/// creating readable memory mappings.
|
pub struct Exec = 1 <<3;
|
||||||
struct Read: u32 = Rights::READ;
|
pub struct Signal = 1 <<7;
|
||||||
/// Allows writing data to a data sink (files, VM objects, etc.) or
|
|
||||||
/// creating writable memory mappings.
|
|
||||||
struct Write: u32 = Rights::WRITE;
|
|
||||||
/// Allows creating executable memory mappings.
|
|
||||||
struct Exec: u32 = Rights::EXEC;
|
|
||||||
/// Allows sending notifications or signals.
|
|
||||||
struct Signal: u32 = Rights::SIGNAL;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The full set of access rights.
|
/// The full set of access rights.
|
||||||
pub type Full = TRights![
|
pub type Full = TRights![Dup, Read, Write, Exec, Signal];
|
||||||
Dup,
|
|
||||||
Read,
|
|
||||||
Write,
|
|
||||||
Exec,
|
|
||||||
Signal,
|
|
||||||
];
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
//!
|
//!
|
||||||
//! There are two primary VM abstractions:
|
//! There are two primary VM abstractions:
|
||||||
//! * Virtual Memory Address Regions (VMARs) a type of capability that manages
|
//! * Virtual Memory Address Regions (VMARs) a type of capability that manages
|
||||||
/// user address spaces.
|
//! user address spaces.
|
||||||
//! * Virtual Memory Objects (VMOs) are are a type of capability that
|
//! * Virtual Memory Objects (VMOs) are are a type of capability that
|
||||||
//! represents a set of memory pages.
|
//! represents a set of memory pages.
|
||||||
//!
|
//!
|
||||||
|
@ -1,7 +1,20 @@
|
|||||||
|
use core::ops::Range;
|
||||||
|
|
||||||
|
use alloc::sync::Arc;
|
||||||
|
use kxos_frame::prelude::Result;
|
||||||
|
use kxos_frame::{vm::VmIo, Error};
|
||||||
|
|
||||||
|
use crate::{rights::Rights, vm::vmo::Vmo};
|
||||||
|
|
||||||
|
use super::{
|
||||||
|
options::{VmarChildOptions, VmarMapOptions},
|
||||||
|
VmPerms, Vmar, Vmar_,
|
||||||
|
};
|
||||||
|
|
||||||
impl Vmar<Rights> {
|
impl Vmar<Rights> {
|
||||||
/// Creates a root VMAR.
|
/// Creates a root VMAR.
|
||||||
pub fn new() -> Result<Self> {
|
pub fn new() -> Result<Self> {
|
||||||
let inner = Arc::new(Vmar_::new());
|
let inner = Arc::new(Vmar_::new()?);
|
||||||
let rights = Rights::all();
|
let rights = Rights::all();
|
||||||
let new_self = Self(inner, rights);
|
let new_self = Self(inner, rights);
|
||||||
Ok(new_self)
|
Ok(new_self)
|
||||||
@ -42,9 +55,13 @@ impl Vmar<Rights> {
|
|||||||
/// Memory permissions may be changed through the `protect` method,
|
/// Memory permissions may be changed through the `protect` method,
|
||||||
/// which ensures that any updated memory permissions do not go beyond
|
/// which ensures that any updated memory permissions do not go beyond
|
||||||
/// the access rights of the underlying VMOs.
|
/// the access rights of the underlying VMOs.
|
||||||
pub fn new_map(&self, vmo: Vmo, perms: VmPerms) -> VmarMapOptions<'_, Rights> {
|
pub fn new_map(
|
||||||
|
&self,
|
||||||
|
vmo: Vmo<Rights>,
|
||||||
|
perms: VmPerms,
|
||||||
|
) -> Result<VmarMapOptions<Rights, Rights>> {
|
||||||
let dup_self = self.dup()?;
|
let dup_self = self.dup()?;
|
||||||
VmarMapOptions::new(dup_self, vmo, perms)
|
Ok(VmarMapOptions::new(dup_self, vmo, perms))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a new child VMAR through a set of VMAR child options.
|
/// Creates a new child VMAR through a set of VMAR child options.
|
||||||
@ -66,9 +83,9 @@ impl Vmar<Rights> {
|
|||||||
///
|
///
|
||||||
/// The new VMAR child will be of the same capability class and
|
/// The new VMAR child will be of the same capability class and
|
||||||
/// access rights as the parent.
|
/// access rights as the parent.
|
||||||
pub fn new_child(&self, size: usize) -> VmarChildOptions<'a, Rights> {
|
pub fn new_child(&self, size: usize) -> Result<VmarChildOptions<Rights>> {
|
||||||
let dup_self = self.dup()?;
|
let dup_self = self.dup()?;
|
||||||
VmarChildOptions::new(dup_self, size)
|
Ok(VmarChildOptions::new(dup_self, size))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Change the permissions of the memory mappings in the specified range.
|
/// Change the permissions of the memory mappings in the specified range.
|
||||||
@ -107,24 +124,42 @@ impl Vmar<Rights> {
|
|||||||
/// As for children VMARs, they must be fully within the range.
|
/// As for children VMARs, they must be fully within the range.
|
||||||
/// All children VMARs that fall within the range get their `destroy` methods
|
/// All children VMARs that fall within the range get their `destroy` methods
|
||||||
/// called.
|
/// called.
|
||||||
pub fn destroy(&self, range: &Range<usize>) -> Result<()> {
|
pub fn destroy(&self, range: Range<usize>) -> Result<()> {
|
||||||
self.0.destroy(range)
|
self.0.destroy(range)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Duplicates the capability.
|
||||||
|
///
|
||||||
|
/// # Access rights
|
||||||
|
///
|
||||||
|
/// The method requires the Dup right.
|
||||||
|
pub fn dup(&self) -> Result<Self> {
|
||||||
|
self.check_rights(Rights::DUP)?;
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns the access rights.
|
/// Returns the access rights.
|
||||||
pub fn rights(&self) -> Rights {
|
pub fn rights(&self) -> Rights {
|
||||||
self.1
|
self.1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn check_rights(&self, rights: Rights) -> Result<()> {
|
||||||
|
if self.1.contains(rights) {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(Error::AccessDenied)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<R> VmIo for Vmar<Rights> {
|
impl VmIo for Vmar<Rights> {
|
||||||
fn read_bytes(&self, offset: usize, buf: &mut [u8]) -> Result<()> {
|
fn read_bytes(&self, offset: usize, buf: &mut [u8]) -> Result<()> {
|
||||||
self.check_rights!(Rights::READ)?;
|
self.check_rights(Rights::READ)?;
|
||||||
self.0.read(offset, buf)
|
self.0.read(offset, buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_bytes(&self, offset: usize, buf: &[u8]) -> Result<()> {
|
fn write_bytes(&self, offset: usize, buf: &[u8]) -> Result<()> {
|
||||||
self.check_rights!(Rights::WRITE)?;
|
self.check_rights(Rights::WRITE)?;
|
||||||
self.0.write(offset, buf)
|
self.0.write(offset, buf)
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,8 +1,18 @@
|
|||||||
//! Virtual Memory Address Regions (VMARs).
|
//! Virtual Memory Address Regions (VMARs).
|
||||||
|
|
||||||
mod static_cap;
|
|
||||||
mod dyn_cap;
|
mod dyn_cap;
|
||||||
mod options;
|
mod options;
|
||||||
|
mod static_cap;
|
||||||
|
|
||||||
|
use crate::rights::Rights;
|
||||||
|
use alloc::sync::Arc;
|
||||||
|
use bitflags::bitflags;
|
||||||
|
use core::ops::Range;
|
||||||
|
use kxos_frame::prelude::Result;
|
||||||
|
use kxos_frame::vm::Vaddr;
|
||||||
|
use kxos_frame::vm::VmSpace;
|
||||||
|
use kxos_frame::Error;
|
||||||
|
use spin::Mutex;
|
||||||
|
|
||||||
/// Virtual Memory Address Regions (VMARs) are a type of capability that manages
|
/// Virtual Memory Address Regions (VMARs) are a type of capability that manages
|
||||||
/// user address spaces.
|
/// user address spaces.
|
||||||
@ -79,15 +89,7 @@ impl<R> Vmar<R> {
|
|||||||
///
|
///
|
||||||
/// The base address of a root VMAR is zero.
|
/// The base address of a root VMAR is zero.
|
||||||
pub fn base(&self) -> Vaddr {
|
pub fn base(&self) -> Vaddr {
|
||||||
self.base
|
self.0.base
|
||||||
}
|
|
||||||
|
|
||||||
fn check_rights(&self, rights: Rights) -> Result<()> {
|
|
||||||
if self.rights.contains(rights) {
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
Err(EACCESS)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -95,16 +97,22 @@ bitflags! {
|
|||||||
/// The memory access permissions of memory mappings.
|
/// The memory access permissions of memory mappings.
|
||||||
pub struct VmPerms: u32 {
|
pub struct VmPerms: u32 {
|
||||||
/// Readable.
|
/// Readable.
|
||||||
const READ: u32 = 1 << 0;
|
const READ = 1 << 0;
|
||||||
/// Writable.
|
/// Writable.
|
||||||
const WRITE: u32 = 1 << 1;
|
const WRITE = 1 << 1;
|
||||||
/// Executable.
|
/// Executable.
|
||||||
const EXEC: u32 = 1 << 2;
|
const EXEC = 1 << 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Rights> for VmPerms {
|
impl From<Rights> for VmPerms {
|
||||||
fn from(perms: VmPerms) -> Rights {
|
fn from(rights: Rights) -> VmPerms {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<VmPerms> for Rights {
|
||||||
|
fn from(vm_perms: VmPerms) -> Rights {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,5 +1,12 @@
|
|||||||
//! Options for allocating child VMARs and creating mappings.
|
//! Options for allocating child VMARs and creating mappings.
|
||||||
|
|
||||||
|
use kxos_frame::prelude::Result;
|
||||||
|
use kxos_frame::{config::PAGE_SIZE, vm::Vaddr};
|
||||||
|
|
||||||
|
use crate::vm::vmo::Vmo;
|
||||||
|
|
||||||
|
use super::{VmPerms, Vmar};
|
||||||
|
|
||||||
/// Options for allocating a child VMAR, which must not overlap with any
|
/// Options for allocating a child VMAR, which must not overlap with any
|
||||||
/// existing mappings or child VMARs.
|
/// existing mappings or child VMARs.
|
||||||
///
|
///
|
||||||
@ -39,6 +46,7 @@ pub struct VmarChildOptions<R> {
|
|||||||
parent: Vmar<R>,
|
parent: Vmar<R>,
|
||||||
size: usize,
|
size: usize,
|
||||||
offset: usize,
|
offset: usize,
|
||||||
|
align: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<R> VmarChildOptions<R> {
|
impl<R> VmarChildOptions<R> {
|
||||||
@ -94,9 +102,9 @@ impl<R> VmarChildOptions<R> {
|
|||||||
/// Options for creating a new mapping. The mapping is not allowed to overlap
|
/// Options for creating a new mapping. The mapping is not allowed to overlap
|
||||||
/// with any child VMARs. And unless specified otherwise, it is not allowed
|
/// with any child VMARs. And unless specified otherwise, it is not allowed
|
||||||
/// to overlap with any existing mapping, either.
|
/// to overlap with any existing mapping, either.
|
||||||
pub struct VmarMapOptions<R> {
|
pub struct VmarMapOptions<R1, R2> {
|
||||||
parent: Vmar<R>,
|
parent: Vmar<R1>,
|
||||||
vmo: Vmo,
|
vmo: Vmo<R2>,
|
||||||
perms: VmPerms,
|
perms: VmPerms,
|
||||||
vmo_offset: usize,
|
vmo_offset: usize,
|
||||||
size: usize,
|
size: usize,
|
||||||
@ -105,20 +113,21 @@ pub struct VmarMapOptions<R> {
|
|||||||
can_overwrite: bool,
|
can_overwrite: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<R> VmarMapOptions<'a, R> {
|
impl<R1, R2> VmarMapOptions<R1, R2> {
|
||||||
/// Creates a default set of options with the VMO and the memory access
|
/// Creates a default set of options with the VMO and the memory access
|
||||||
/// permissions.
|
/// permissions.
|
||||||
///
|
///
|
||||||
/// The VMO must have access rights that correspond to the memory
|
/// The VMO must have access rights that correspond to the memory
|
||||||
/// access permissions. For example, if `perms` contains `VmPerm::Write`,
|
/// access permissions. For example, if `perms` contains `VmPerm::Write`,
|
||||||
/// then `vmo.rights()` should contain `Rights::WRITE`.
|
/// then `vmo.rights()` should contain `Rights::WRITE`.
|
||||||
pub fn new(parent: Vmar<R>, vmo: Vmo, perms: VmPerms) -> Self {
|
pub fn new(parent: Vmar<R1>, vmo: Vmo<R2>, perms: VmPerms) -> Self {
|
||||||
|
let size = vmo.size();
|
||||||
Self {
|
Self {
|
||||||
parent,
|
parent,
|
||||||
vmo,
|
vmo,
|
||||||
perms,
|
perms,
|
||||||
vmo_offset: 0,
|
vmo_offset: 0,
|
||||||
size: vmo.size(),
|
size,
|
||||||
offset: None,
|
offset: None,
|
||||||
align: PAGE_SIZE,
|
align: PAGE_SIZE,
|
||||||
can_overwrite: false,
|
can_overwrite: false,
|
||||||
@ -176,7 +185,7 @@ impl<R> VmarMapOptions<'a, R> {
|
|||||||
///
|
///
|
||||||
/// If not set, the system will choose an offset automatically.
|
/// If not set, the system will choose an offset automatically.
|
||||||
pub fn offset(mut self, offset: usize) -> Self {
|
pub fn offset(mut self, offset: usize) -> Self {
|
||||||
self.offset = offset;
|
self.offset = Some(offset);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,3 +1,17 @@
|
|||||||
|
use core::ops::Range;
|
||||||
|
|
||||||
|
use alloc::sync::Arc;
|
||||||
|
use kxos_frame::prelude::Result;
|
||||||
|
use kxos_frame::{vm::VmIo, Error};
|
||||||
|
use kxos_rights_proc::require;
|
||||||
|
|
||||||
|
use crate::{rights::*, vm::vmo::Vmo};
|
||||||
|
|
||||||
|
use super::{
|
||||||
|
options::{VmarChildOptions, VmarMapOptions},
|
||||||
|
VmPerms, Vmar, Vmar_,
|
||||||
|
};
|
||||||
|
|
||||||
impl<R: TRights> Vmar<R> {
|
impl<R: TRights> Vmar<R> {
|
||||||
/// Creates a root VMAR.
|
/// Creates a root VMAR.
|
||||||
///
|
///
|
||||||
@ -5,7 +19,7 @@ impl<R: TRights> Vmar<R> {
|
|||||||
///
|
///
|
||||||
/// A root VMAR is initially given full access rights.
|
/// A root VMAR is initially given full access rights.
|
||||||
pub fn new() -> Result<Self> {
|
pub fn new() -> Result<Self> {
|
||||||
let inner = Arc::new(Vmar_::new());
|
let inner = Arc::new(Vmar_::new()?);
|
||||||
let rights = R::new();
|
let rights = R::new();
|
||||||
let new_self = Self(inner, rights);
|
let new_self = Self(inner, rights);
|
||||||
Ok(new_self)
|
Ok(new_self)
|
||||||
@ -46,9 +60,10 @@ impl<R: TRights> Vmar<R> {
|
|||||||
/// Memory permissions may be changed through the `protect` method,
|
/// Memory permissions may be changed through the `protect` method,
|
||||||
/// which ensures that any updated memory permissions do not go beyond
|
/// which ensures that any updated memory permissions do not go beyond
|
||||||
/// the access rights of the underlying VMOs.
|
/// the access rights of the underlying VMOs.
|
||||||
pub fn new_map(&self, vmo: Vmo, perms: VmPerms) -> VmarMapOptions<'_, Rights> {
|
#[require(R > Dup)]
|
||||||
let dup_self = self.dup();
|
pub fn new_map(&self, vmo: Vmo<Rights>, perms: VmPerms) -> Result<VmarMapOptions<R, Rights>> {
|
||||||
VmarMapOptions::new(dup_self, vmo_ref)
|
let dup_self = self.dup()?;
|
||||||
|
Ok(VmarMapOptions::new(dup_self, vmo, perms))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a new child VMAR through a set of VMAR child options.
|
/// Creates a new child VMAR through a set of VMAR child options.
|
||||||
@ -71,9 +86,9 @@ impl<R: TRights> Vmar<R> {
|
|||||||
/// The new VMAR child will be of the same capability class and
|
/// The new VMAR child will be of the same capability class and
|
||||||
/// access rights as the parent.
|
/// access rights as the parent.
|
||||||
#[require(R > Dup)]
|
#[require(R > Dup)]
|
||||||
pub fn new_child(&self, size: usize) -> VmarChildOptions<'a, R> {
|
pub fn new_child(&self, size: usize) -> Result<VmarChildOptions<R>> {
|
||||||
let dup_self = self.dup();
|
let dup_self = self.dup()?;
|
||||||
VmarChildOptions::new(dup_self, size)
|
Ok(VmarChildOptions::new(dup_self, size))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Change the permissions of the memory mappings in the specified range.
|
/// Change the permissions of the memory mappings in the specified range.
|
||||||
@ -112,24 +127,48 @@ impl<R: TRights> Vmar<R> {
|
|||||||
/// As for children VMARs, they must be fully within the range.
|
/// As for children VMARs, they must be fully within the range.
|
||||||
/// All children VMARs that fall within the range get their `destroy` methods
|
/// All children VMARs that fall within the range get their `destroy` methods
|
||||||
/// called.
|
/// called.
|
||||||
pub fn destroy(&self, range: &Range<usize>) -> Result<()> {
|
pub fn destroy(&self, range: Range<usize>) -> Result<()> {
|
||||||
self.0.destroy(range)
|
self.0.destroy(range)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Duplicate the capability.
|
||||||
|
///
|
||||||
|
/// # Access rights
|
||||||
|
///
|
||||||
|
/// The method requires the Dup right.
|
||||||
|
#[require(R > Dup)]
|
||||||
|
pub fn dup(&self) -> Result<Self> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Strict the access rights.
|
||||||
|
#[require(R > R1)]
|
||||||
|
pub fn restrict<R1>(mut self) -> Vmo<R1> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns the access rights.
|
/// Returns the access rights.
|
||||||
pub const fn rights(&self) -> Rights {
|
pub const fn rights(&self) -> Rights {
|
||||||
R::BITS
|
Rights::from_bits(R::BITS).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_rights(&self, rights: Rights) -> Result<()> {
|
||||||
|
if self.rights().contains(rights) {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(Error::AccessDenied)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<R> VmIo for Vmar<Rights> {
|
impl<R: TRights> VmIo for Vmar<R> {
|
||||||
fn read_bytes(&self, offset: usize, buf: &mut [u8]) -> Result<()> {
|
fn read_bytes(&self, offset: usize, buf: &mut [u8]) -> Result<()> {
|
||||||
self.check_rights!(Rights::READ)?;
|
// self.check_rights!(Rights::READ)?;
|
||||||
self.0.read(offset, buf)
|
self.0.read(offset, buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_bytes(&self, offset: usize, buf: &[u8]) -> Result<()> {
|
fn write_bytes(&self, offset: usize, buf: &[u8]) -> Result<()> {
|
||||||
self.check_rights!(Rights::WRITE)?;
|
// self.check_rights!(Rights::WRITE)?;
|
||||||
self.0.write(offset, buf)
|
self.0.write(offset, buf)
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,3 +1,15 @@
|
|||||||
|
use core::ops::Range;
|
||||||
|
|
||||||
|
use kxos_frame::prelude::Result;
|
||||||
|
use kxos_frame::{vm::VmIo, Error};
|
||||||
|
|
||||||
|
use crate::rights::{Rights, TRights};
|
||||||
|
|
||||||
|
use super::{
|
||||||
|
options::{VmoCowChild, VmoSliceChild},
|
||||||
|
Vmo, VmoChildOptions,
|
||||||
|
};
|
||||||
|
|
||||||
impl Vmo<Rights> {
|
impl Vmo<Rights> {
|
||||||
/// Creates a new slice VMO through a set of VMO child options.
|
/// Creates a new slice VMO through a set of VMO child options.
|
||||||
///
|
///
|
||||||
@ -18,9 +30,12 @@ impl Vmo<Rights> {
|
|||||||
///
|
///
|
||||||
/// The new VMO child will be of the same capability flavor as the parent;
|
/// The new VMO child will be of the same capability flavor as the parent;
|
||||||
/// so are the access rights.
|
/// so are the access rights.
|
||||||
pub fn new_slice_child(&self, range: Range<usize>) -> VmoChildOptions<'_, Rights, VmoSliceChild> {
|
pub fn new_slice_child(
|
||||||
|
&self,
|
||||||
|
range: Range<usize>,
|
||||||
|
) -> Result<VmoChildOptions<Rights, VmoSliceChild>> {
|
||||||
let dup_self = self.dup()?;
|
let dup_self = self.dup()?;
|
||||||
VmoChildOptions::new_slice(dup_self, range)
|
Ok(VmoChildOptions::new_slice_rights(dup_self, range))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a new COW VMO through a set of VMO child options.
|
/// Creates a new COW VMO through a set of VMO child options.
|
||||||
@ -43,9 +58,12 @@ impl Vmo<Rights> {
|
|||||||
/// The new VMO child will be of the same capability flavor as the parent.
|
/// The new VMO child will be of the same capability flavor as the parent.
|
||||||
/// The child will be given the access rights of the parent
|
/// The child will be given the access rights of the parent
|
||||||
/// plus the Write right.
|
/// plus the Write right.
|
||||||
pub fn new_cow_child(&self, range: Range<usize>) -> VmoChildOptions<'_, Rights, VmoCowChild> {
|
pub fn new_cow_child(
|
||||||
|
&self,
|
||||||
|
range: Range<usize>,
|
||||||
|
) -> Result<VmoChildOptions<Rights, VmoCowChild>> {
|
||||||
let dup_self = self.dup()?;
|
let dup_self = self.dup()?;
|
||||||
VmoChildOptions::new_cow(dup_self, range)
|
Ok(VmoChildOptions::new_cow(dup_self, range))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Commits the pages specified in the range (in bytes).
|
/// Commits the pages specified in the range (in bytes).
|
||||||
@ -117,7 +135,7 @@ impl Vmo<Rights> {
|
|||||||
|
|
||||||
/// Converts to a static capability.
|
/// Converts to a static capability.
|
||||||
pub fn to_static<R1: TRights>(self) -> Result<Vmo<R1>> {
|
pub fn to_static<R1: TRights>(self) -> Result<Vmo<R1>> {
|
||||||
self.check_rights(R1::BITS)?;
|
self.check_rights(Rights::from_bits(R1::BITS).ok_or(Error::InvalidArgs)?)?;
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -125,16 +143,24 @@ impl Vmo<Rights> {
|
|||||||
pub fn rights(&self) -> Rights {
|
pub fn rights(&self) -> Rights {
|
||||||
self.1
|
self.1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn check_rights(&self, rights: Rights) -> Result<()> {
|
||||||
|
if self.rights().contains(rights) {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(Error::AccessDenied)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl VmIo for Vmo<Rights> {
|
impl VmIo for Vmo<Rights> {
|
||||||
fn read_bytes(&self, offset: usize, buf: &mut [u8]) -> Result<()> {
|
fn read_bytes(&self, offset: usize, buf: &mut [u8]) -> Result<()> {
|
||||||
self.check_rights(Rights::READ)?;
|
self.check_rights(Rights::READ)?;
|
||||||
self.0.read(offset, buf)
|
self.0.read_bytes(offset, buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_bytes(&self, offset: usize, buf: &[u8]) -> Result<()> {
|
fn write_bytes(&self, offset: usize, buf: &[u8]) -> Result<()> {
|
||||||
self.check_rights(Rights::WRITE)?;
|
self.check_rights(Rights::WRITE)?;
|
||||||
self.0.write(offset, buf)
|
self.0.write_bytes(offset, buf)
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,16 +1,20 @@
|
|||||||
//! Virtual Memory Objects (VMOs).
|
//! Virtual Memory Objects (VMOs).
|
||||||
|
|
||||||
use kx_frame::vm::VmIo;
|
use core::ops::Range;
|
||||||
|
|
||||||
use crate::rights::{Rights, TRights};
|
use crate::rights::Rights;
|
||||||
|
use alloc::sync::Arc;
|
||||||
|
use bitflags::bitflags;
|
||||||
|
use kxos_frame::{prelude::Result, vm::Paddr, Error};
|
||||||
|
|
||||||
mod static_cap;
|
|
||||||
mod dyn_cap;
|
mod dyn_cap;
|
||||||
mod options;
|
mod options;
|
||||||
mod pager;
|
mod pager;
|
||||||
|
mod static_cap;
|
||||||
|
|
||||||
pub use options::{VmoOptions, VmoChildOptions};
|
pub use options::{VmoChildOptions, VmoOptions};
|
||||||
pub use pager::Pager;
|
pub use pager::Pager;
|
||||||
|
use spin::Mutex;
|
||||||
|
|
||||||
/// Virtual Memory Objects (VMOs) are a type of capability that represents a
|
/// Virtual Memory Objects (VMOs) are a type of capability that represents a
|
||||||
/// range of memory pages.
|
/// range of memory pages.
|
||||||
@ -73,16 +77,16 @@ bitflags! {
|
|||||||
/// VMO flags.
|
/// VMO flags.
|
||||||
pub struct VmoFlags: u32 {
|
pub struct VmoFlags: u32 {
|
||||||
/// Set this flag if a VMO is resizable.
|
/// Set this flag if a VMO is resizable.
|
||||||
const RESIZABLE: u32 = 1 << 0;
|
const RESIZABLE = 1 << 0;
|
||||||
/// Set this flags if a VMO is backed by physically contiguous memory
|
/// Set this flags if a VMO is backed by physically contiguous memory
|
||||||
/// pages.
|
/// pages.
|
||||||
///
|
///
|
||||||
/// To ensure the memory pages to be contiguous, these pages
|
/// To ensure the memory pages to be contiguous, these pages
|
||||||
/// are allocated upon the creation of the VMO, rather than on demands.
|
/// are allocated upon the creation of the VMO, rather than on demands.
|
||||||
const CONTIGUOUS: u32 = 1 << 1;
|
const CONTIGUOUS = 1 << 1;
|
||||||
/// Set this flag if a VMO is backed by memory pages that supports
|
/// Set this flag if a VMO is backed by memory pages that supports
|
||||||
/// Direct Memory Access (DMA) by devices.
|
/// Direct Memory Access (DMA) by devices.
|
||||||
const DMA: u32 = 1 << 2;
|
const DMA = 1 << 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -126,7 +130,7 @@ impl Vmo_ {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn size(&self) -> usize {
|
pub fn size(&self) -> usize {
|
||||||
self.0.size()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn resize(&self, new_size: usize) -> Result<()> {
|
pub fn resize(&self, new_size: usize) -> Result<()> {
|
||||||
@ -142,7 +146,6 @@ impl Vmo_ {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
impl<R> Vmo<R> {
|
impl<R> Vmo<R> {
|
||||||
/// Returns the size (in bytes) of a VMO.
|
/// Returns the size (in bytes) of a VMO.
|
||||||
pub fn size(&self) -> usize {
|
pub fn size(&self) -> usize {
|
||||||
@ -159,12 +162,4 @@ impl<R> Vmo<R> {
|
|||||||
pub fn flags(&self) -> VmoFlags {
|
pub fn flags(&self) -> VmoFlags {
|
||||||
self.0.flags()
|
self.0.flags()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_rights(&self, rights: Rights) -> Result<()> {
|
|
||||||
if self.rights().contains(rights) {
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
Err(Error::AccessDenied)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -1,5 +1,17 @@
|
|||||||
//! Options for allocating root and child VMOs.
|
//! Options for allocating root and child VMOs.
|
||||||
|
|
||||||
|
use core::marker::PhantomData;
|
||||||
|
use core::ops::Range;
|
||||||
|
|
||||||
|
use alloc::sync::Arc;
|
||||||
|
use kxos_frame::prelude::Result;
|
||||||
|
use kxos_frame::vm::Paddr;
|
||||||
|
use kxos_rights_proc::require;
|
||||||
|
|
||||||
|
use crate::rights::{Dup, Rights, TRights};
|
||||||
|
|
||||||
|
use super::{Pager, Vmo, VmoFlags};
|
||||||
|
|
||||||
/// Options for allocating a root VMO.
|
/// Options for allocating a root VMO.
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
@ -38,7 +50,8 @@ pub struct VmoOptions<R = Rights> {
|
|||||||
size: usize,
|
size: usize,
|
||||||
paddr: Option<Paddr>,
|
paddr: Option<Paddr>,
|
||||||
flags: VmoFlags,
|
flags: VmoFlags,
|
||||||
supplier: Option<Arc<dyn FrameSupplier>>,
|
rights: R,
|
||||||
|
// supplier: Option<Arc<dyn FrameSupplier>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<R> VmoOptions<R> {
|
impl<R> VmoOptions<R> {
|
||||||
@ -81,7 +94,7 @@ impl VmoOptions<Rights> {
|
|||||||
/// # Access rights
|
/// # Access rights
|
||||||
///
|
///
|
||||||
/// The VMO is initially assigned full access rights.
|
/// The VMO is initially assigned full access rights.
|
||||||
pub fn alloc(mut self) -> Result<Vmo<R>> {
|
pub fn alloc(mut self) -> Result<Vmo<Rights>> {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -185,10 +198,10 @@ pub struct VmoChildOptions<R, C> {
|
|||||||
range: Range<usize>,
|
range: Range<usize>,
|
||||||
flags: VmoFlags,
|
flags: VmoFlags,
|
||||||
// Specifies whether the child is a slice or a COW
|
// Specifies whether the child is a slice or a COW
|
||||||
child_marker: PhantomData<C>,
|
marker: PhantomData<C>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<R> VmoChildOptions<R, VmoSliceChild> {
|
impl<R: TRights> VmoChildOptions<R, VmoSliceChild> {
|
||||||
/// Creates a default set of options for creating a slice VMO child.
|
/// Creates a default set of options for creating a slice VMO child.
|
||||||
///
|
///
|
||||||
/// A slice child of a VMO, which has direct access to a range of memory
|
/// A slice child of a VMO, which has direct access to a range of memory
|
||||||
@ -199,9 +212,32 @@ impl<R> VmoChildOptions<R, VmoSliceChild> {
|
|||||||
#[require(R > Dup)]
|
#[require(R > Dup)]
|
||||||
pub fn new_slice(parent: Vmo<R>, range: Range<usize>) -> Self {
|
pub fn new_slice(parent: Vmo<R>, range: Range<usize>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
flags: parent.flags() & Self::PARENT_FLAGS_MASK,
|
||||||
|
parent,
|
||||||
|
range,
|
||||||
|
marker: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VmoChildOptions<Rights, VmoSliceChild> {
|
||||||
|
/// Creates a default set of options for creating a slice VMO child.
|
||||||
|
///
|
||||||
|
/// User should ensure parent have dup rights, otherwise this function will panic
|
||||||
|
///
|
||||||
|
/// A slice child of a VMO, which has direct access to a range of memory
|
||||||
|
/// pages in the parent VMO. In other words, any updates of the parent will
|
||||||
|
/// reflect on the child, and vice versa.
|
||||||
|
///
|
||||||
|
/// The range of a child must be within that of the parent.
|
||||||
|
pub fn new_slice_rights(parent: Vmo<Rights>, range: Range<usize>) -> Self {
|
||||||
|
parent
|
||||||
|
.check_rights(Rights::DUP)
|
||||||
|
.expect("function new_slice_rights should called with rights Dup");
|
||||||
|
Self {
|
||||||
|
flags: parent.flags() & Self::PARENT_FLAGS_MASK,
|
||||||
parent,
|
parent,
|
||||||
range,
|
range,
|
||||||
flags: parent.flags & Self::PARENT_FLAGS_MASK,
|
|
||||||
marker: PhantomData,
|
marker: PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -219,9 +255,9 @@ impl<R> VmoChildOptions<R, VmoCowChild> {
|
|||||||
/// Any pages that are beyond the parent's range are initially all zeros.
|
/// Any pages that are beyond the parent's range are initially all zeros.
|
||||||
pub fn new_cow(parent: Vmo<R>, range: Range<usize>) -> Self {
|
pub fn new_cow(parent: Vmo<R>, range: Range<usize>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
flags: parent.flags() & Self::PARENT_FLAGS_MASK,
|
||||||
parent,
|
parent,
|
||||||
range,
|
range,
|
||||||
flags: parent.flags & Self::PARENT_FLAGS_MASK,
|
|
||||||
marker: PhantomData,
|
marker: PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -229,10 +265,10 @@ impl<R> VmoChildOptions<R, VmoCowChild> {
|
|||||||
|
|
||||||
impl<R, C> VmoChildOptions<R, C> {
|
impl<R, C> VmoChildOptions<R, C> {
|
||||||
/// Flags that a VMO child inherits from its parent.
|
/// Flags that a VMO child inherits from its parent.
|
||||||
pub const PARENT_FLAGS_MASK: VmoFlags = VmoFlags::CONTIGUOUS.bits |
|
pub const PARENT_FLAGS_MASK: VmoFlags =
|
||||||
VmoFlags::DMA.bits;
|
VmoFlags::from_bits(VmoFlags::CONTIGUOUS.bits | VmoFlags::DMA.bits).unwrap();
|
||||||
/// Flags that a VMO child may differ from its parent.
|
/// Flags that a VMO child may differ from its parent.
|
||||||
pub const CHILD_FLAGS_MASK: VmoFlags = VmoFlags::RESIZABLE.bits;
|
pub const CHILD_FLAGS_MASK: VmoFlags = VmoFlags::RESIZABLE;
|
||||||
|
|
||||||
/// Sets the VMO flags.
|
/// Sets the VMO flags.
|
||||||
///
|
///
|
||||||
@ -248,7 +284,7 @@ impl<R, C> VmoChildOptions<R, C> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, C> VmoChildOptions<'a, Rights, C> {
|
impl<C> VmoChildOptions<Rights, C> {
|
||||||
/// Allocates the child VMO.
|
/// Allocates the child VMO.
|
||||||
///
|
///
|
||||||
/// # Access rights
|
/// # Access rights
|
||||||
@ -259,7 +295,7 @@ impl<'a, C> VmoChildOptions<'a, Rights, C> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, R: TRights> VmoChildOptions<'a, R, VmoSliceChild> {
|
impl<R: TRights> VmoChildOptions<R, VmoSliceChild> {
|
||||||
/// Allocates the child VMO.
|
/// Allocates the child VMO.
|
||||||
///
|
///
|
||||||
/// # Access rights
|
/// # Access rights
|
||||||
@ -270,23 +306,34 @@ impl<'a, R: TRights> VmoChildOptions<'a, R, VmoSliceChild> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, R: TRights> VmoChildOptions<'a, R, VmoCowChild> {
|
impl<R: TRights> VmoChildOptions<R, VmoCowChild> {
|
||||||
/// Allocates the child VMO.
|
/// Allocates the child VMO.
|
||||||
///
|
///
|
||||||
/// # Access rights
|
/// # Access rights
|
||||||
///
|
///
|
||||||
/// The child VMO is initially assigned all the parent's access rights
|
/// The child VMO is initially assigned all the parent's access rights
|
||||||
/// plus the Write right.
|
/// plus the Write right.
|
||||||
pub fn alloc<R1>(mut self) -> Result<Vmo<R1>>
|
pub fn alloc<TRights>(mut self) -> Result<Vmo<TRights>>
|
||||||
where
|
|
||||||
// TODO: R1 must contain the Write right. To do so at the type level,
|
// TODO: R1 must contain the Write right. To do so at the type level,
|
||||||
// we need to implement a type-level operator
|
// we need to implement a type-level operator
|
||||||
// (say, `TRightsExtend(L, F)`)
|
// (say, `TRightsExtend(L, F)`)
|
||||||
// that may extend a list (`L`) of type-level flags with an extra flag `F`.
|
// that may extend a list (`L`) of type-level flags with an extra flag `F`.
|
||||||
R1: R // TRightsExtend<R, Write>
|
// TRightsExtend<R, Write>
|
||||||
{
|
{
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// original:
|
||||||
|
// pub fn alloc<R1>(mut self) -> Result<Vmo<R1>>
|
||||||
|
// where
|
||||||
|
// // TODO: R1 must contain the Write right. To do so at the type level,
|
||||||
|
// // we need to implement a type-level operator
|
||||||
|
// // (say, `TRightsExtend(L, F)`)
|
||||||
|
// // that may extend a list (`L`) of type-level flags with an extra flag `F`.
|
||||||
|
// R1: R // TRightsExtend<R, Write>
|
||||||
|
// {
|
||||||
|
// todo!()
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A type to specify the "type" of a child, which is either a slice or a COW.
|
/// A type to specify the "type" of a child, which is either a slice or a COW.
|
||||||
@ -295,9 +342,9 @@ pub trait VmoChildType {}
|
|||||||
/// A type to mark a child is slice.
|
/// A type to mark a child is slice.
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
pub struct VmoSliceChild;
|
pub struct VmoSliceChild;
|
||||||
impl VmoChildType for VmoSliceChild {};
|
impl VmoChildType for VmoSliceChild {}
|
||||||
|
|
||||||
/// A type to mark a child is COW.
|
/// A type to mark a child is COW.
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
pub struct VmoCowChild;
|
pub struct VmoCowChild;
|
||||||
impl VmoChildType for VmoCowChild {};
|
impl VmoChildType for VmoCowChild {}
|
||||||
|
@ -1,3 +1,6 @@
|
|||||||
|
use kxos_frame::prelude::Result;
|
||||||
|
use kxos_frame::vm::VmFrame;
|
||||||
|
|
||||||
/// Pagers provide frame to a VMO.
|
/// Pagers provide frame to a VMO.
|
||||||
///
|
///
|
||||||
/// A `Pager` object can be attached to a VMO. Whenever the
|
/// A `Pager` object can be attached to a VMO. Whenever the
|
||||||
|
@ -1,3 +1,16 @@
|
|||||||
|
use core::ops::Range;
|
||||||
|
|
||||||
|
use kxos_frame::prelude::Result;
|
||||||
|
use kxos_frame::{vm::VmIo, Error};
|
||||||
|
use kxos_rights_proc::require;
|
||||||
|
|
||||||
|
use crate::rights::*;
|
||||||
|
|
||||||
|
use super::{
|
||||||
|
options::{VmoCowChild, VmoSliceChild},
|
||||||
|
Vmo, VmoChildOptions,
|
||||||
|
};
|
||||||
|
|
||||||
impl<R: TRights> Vmo<R> {
|
impl<R: TRights> Vmo<R> {
|
||||||
/// Creates a new slice VMO through a set of VMO child options.
|
/// Creates a new slice VMO through a set of VMO child options.
|
||||||
///
|
///
|
||||||
@ -19,9 +32,12 @@ impl<R: TRights> Vmo<R> {
|
|||||||
/// The new VMO child will be of the same capability flavor as the parent;
|
/// The new VMO child will be of the same capability flavor as the parent;
|
||||||
/// so are the access rights.
|
/// so are the access rights.
|
||||||
#[require(R > Dup)]
|
#[require(R > Dup)]
|
||||||
pub fn new_slice_child(&self, range: Range<usize>) -> VmoChildOptions<'_, R, VmoSliceChild> {
|
pub fn new_slice_child(
|
||||||
let dup_self = self.dup();
|
&self,
|
||||||
VmoChildOptions::new_slice(dup_self, range)
|
range: Range<usize>,
|
||||||
|
) -> Result<VmoChildOptions<R, VmoSliceChild>> {
|
||||||
|
let dup_self = self.dup()?;
|
||||||
|
Ok(VmoChildOptions::new_slice(dup_self, range))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a new COW VMO through a set of VMO child options.
|
/// Creates a new COW VMO through a set of VMO child options.
|
||||||
@ -45,9 +61,9 @@ impl<R: TRights> Vmo<R> {
|
|||||||
/// The child will be given the access rights of the parent
|
/// The child will be given the access rights of the parent
|
||||||
/// plus the Write right.
|
/// plus the Write right.
|
||||||
#[require(R > Dup)]
|
#[require(R > Dup)]
|
||||||
pub fn new_cow_child(&self, range: Range<usize>) -> VmoChildOptions<'_, R, VmoCowChild> {
|
pub fn new_cow_child(&self, range: Range<usize>) -> Result<VmoChildOptions<R, VmoCowChild>> {
|
||||||
let dup_self = self.dup();
|
let dup_self = self.dup()?;
|
||||||
VmoChildOptions::new_cow(dup_self, range)
|
Ok(VmoChildOptions::new_cow(dup_self, range))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Commit the pages specified in the range (in bytes).
|
/// Commit the pages specified in the range (in bytes).
|
||||||
@ -102,11 +118,6 @@ impl<R: TRights> Vmo<R> {
|
|||||||
self.0.clear(range)
|
self.0.clear(range)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the size of the VMO in bytes.
|
|
||||||
pub fn size(&self) -> usize {
|
|
||||||
self.0.size()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Duplicate the capability.
|
/// Duplicate the capability.
|
||||||
///
|
///
|
||||||
/// # Access rights
|
/// # Access rights
|
||||||
@ -124,13 +135,21 @@ impl<R: TRights> Vmo<R> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Converts to a dynamic capability.
|
/// Converts to a dynamic capability.
|
||||||
pub fn to_dyn(self) -> Vmo {
|
pub fn to_dyn(self) -> Vmo<Rights> {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the access rights.
|
/// Returns the access rights.
|
||||||
pub const fn rights(&self) -> Rights {
|
pub const fn rights(&self) -> Rights {
|
||||||
R::BITS
|
Rights::from_bits(R::BITS).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_rights(&self, rights: Rights) -> Result<()> {
|
||||||
|
if self.rights().contains(rights) {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(Error::AccessDenied)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
//! Type level bools
|
//! Type level bools
|
||||||
|
|
||||||
pub use std::ops::BitAnd as And;
|
pub use core::ops::BitAnd as And;
|
||||||
pub use std::ops::BitOr as Or;
|
pub use core::ops::BitOr as Or;
|
||||||
pub use std::ops::Not;
|
pub use core::ops::Not;
|
||||||
|
use core::unimplemented;
|
||||||
|
|
||||||
pub trait Bool {}
|
pub trait Bool {}
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
//! This crate defines common type level operations, like SameAsOp, and Bool type operations.
|
//! This crate defines common type level operations, like SameAsOp, and Bool type operations.
|
||||||
//! Besides, this crate defines operations to deal with type sets, like SetContain and SetInclude.
|
//! Besides, this crate defines operations to deal with type sets, like SetContain and SetInclude.
|
||||||
//! When use kxos-typeflags or kxos-rights-poc, this crate should also be added as a dependency.
|
//! When use kxos-typeflags or kxos-rights-poc, this crate should also be added as a dependency.
|
||||||
|
#![no_std]
|
||||||
pub mod assert;
|
pub mod assert;
|
||||||
pub mod bool;
|
pub mod bool;
|
||||||
pub mod if_;
|
pub mod if_;
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
//! Common types and traits to deal with type-level sets
|
//! Common types and traits to deal with type-level sets
|
||||||
|
|
||||||
use std::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
if_::{If, IfOp},
|
if_::{If, IfOp},
|
||||||
And, AndOp, False, OrOp, SameAs, SameAsOp, True,
|
And, AndOp, False, OrOp, SameAs, SameAsOp, True,
|
||||||
};
|
};
|
||||||
|
|
||||||
use std::ops::BitOr as Or;
|
use core::ops::BitOr as Or;
|
||||||
|
|
||||||
/// A marker trait for type-level sets.
|
/// A marker trait for type-level sets.
|
||||||
pub trait Set {}
|
pub trait Set {}
|
||||||
|
@ -65,11 +65,12 @@ impl TypeFlagDef {
|
|||||||
let ident = self.ident.clone();
|
let ident = self.ident.clone();
|
||||||
let type_ = self.type_.clone();
|
let type_ = self.type_.clone();
|
||||||
quote!(
|
quote!(
|
||||||
#vis trait #ident {
|
#vis trait #ident : Sync + Send{
|
||||||
const BITS: #type_;
|
const BITS: #type_;
|
||||||
|
|
||||||
fn new() -> Self;
|
fn new() -> Self;
|
||||||
}
|
}
|
||||||
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,6 +11,7 @@ spin = "0.9.4"
|
|||||||
kxos-frame = {path = "../kxos-frame"}
|
kxos-frame = {path = "../kxos-frame"}
|
||||||
kxos-pci = {path="../kxos-pci"}
|
kxos-pci = {path="../kxos-pci"}
|
||||||
kxos-util = {path="../kxos-util"}
|
kxos-util = {path="../kxos-util"}
|
||||||
|
kxos-frame-pod-derive= {path="../kxos-frame-pod-derive"}
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
|
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
use kxos_frame::Pod;
|
use kxos_frame::Pod;
|
||||||
|
use kxos_frame_pod_derive::Pod;
|
||||||
use kxos_pci::capability::vendor::virtio::CapabilityVirtioData;
|
use kxos_pci::capability::vendor::virtio::CapabilityVirtioData;
|
||||||
use kxos_pci::util::BAR;
|
use kxos_pci::util::BAR;
|
||||||
use kxos_util::frame_ptr::InFramePtr;
|
use kxos_util::frame_ptr::InFramePtr;
|
||||||
|
|
||||||
pub const BLK_SIZE: usize = 512;
|
pub const BLK_SIZE: usize = 512;
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone)]
|
#[derive(Debug, Copy, Clone, Pod)]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct VirtioBLKConfig {
|
pub struct VirtioBLKConfig {
|
||||||
capacity: u64,
|
capacity: u64,
|
||||||
@ -24,7 +25,7 @@ pub struct VirtioBLKConfig {
|
|||||||
unused1: [u8; 3],
|
unused1: [u8; 3],
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone)]
|
#[derive(Debug, Copy, Clone, Pod)]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct VirtioBLKGeometry {
|
pub struct VirtioBLKGeometry {
|
||||||
cylinders: u16,
|
cylinders: u16,
|
||||||
@ -32,7 +33,7 @@ pub struct VirtioBLKGeometry {
|
|||||||
sectors: u8,
|
sectors: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone)]
|
#[derive(Debug, Copy, Clone, Pod)]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct VirtioBLKTopology {
|
pub struct VirtioBLKTopology {
|
||||||
physical_block_exp: u8,
|
physical_block_exp: u8,
|
||||||
@ -41,8 +42,6 @@ pub struct VirtioBLKTopology {
|
|||||||
opt_io_size: u32,
|
opt_io_size: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
kxos_frame::impl_pod_for!(VirtioBLKTopology, VirtioBLKGeometry, VirtioBLKConfig);
|
|
||||||
|
|
||||||
impl VirtioBLKConfig {
|
impl VirtioBLKConfig {
|
||||||
pub(crate) fn new(cap: &CapabilityVirtioData, bars: [Option<BAR>; 6]) -> InFramePtr<Self> {
|
pub(crate) fn new(cap: &CapabilityVirtioData, bars: [Option<BAR>; 6]) -> InFramePtr<Self> {
|
||||||
let bar = cap.bar;
|
let bar = cap.bar;
|
||||||
|
@ -7,8 +7,10 @@ extern crate alloc;
|
|||||||
use alloc::{sync::Arc, vec::Vec};
|
use alloc::{sync::Arc, vec::Vec};
|
||||||
use bitflags::bitflags;
|
use bitflags::bitflags;
|
||||||
use kxos_frame::{info, offset_of, TrapFrame};
|
use kxos_frame::{info, offset_of, TrapFrame};
|
||||||
|
use kxos_frame_pod_derive::Pod;
|
||||||
use kxos_pci::util::{PCIDevice, BAR};
|
use kxos_pci::util::{PCIDevice, BAR};
|
||||||
use kxos_util::frame_ptr::InFramePtr;
|
use kxos_util::frame_ptr::InFramePtr;
|
||||||
|
|
||||||
use spin::{mutex::Mutex, MutexGuard};
|
use spin::{mutex::Mutex, MutexGuard};
|
||||||
|
|
||||||
use self::{block::VirtioBLKConfig, queue::VirtQueue};
|
use self::{block::VirtioBLKConfig, queue::VirtQueue};
|
||||||
@ -54,7 +56,7 @@ bitflags! {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default, Copy, Clone)]
|
#[derive(Debug, Default, Copy, Clone, Pod)]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct VitrioPciCommonCfg {
|
pub struct VitrioPciCommonCfg {
|
||||||
device_feature_select: u32,
|
device_feature_select: u32,
|
||||||
@ -76,8 +78,6 @@ pub struct VitrioPciCommonCfg {
|
|||||||
queue_device: u64,
|
queue_device: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
kxos_frame::impl_pod_for!(VitrioPciCommonCfg);
|
|
||||||
|
|
||||||
impl VitrioPciCommonCfg {
|
impl VitrioPciCommonCfg {
|
||||||
pub(crate) fn new(cap: &CapabilityVirtioData, bars: [Option<BAR>; 6]) -> InFramePtr<Self> {
|
pub(crate) fn new(cap: &CapabilityVirtioData, bars: [Option<BAR>; 6]) -> InFramePtr<Self> {
|
||||||
let bar = cap.bar;
|
let bar = cap.bar;
|
||||||
@ -272,7 +272,7 @@ impl PCIVirtioDevice {
|
|||||||
/// register the queue interrupt functions, this function should call only once
|
/// register the queue interrupt functions, this function should call only once
|
||||||
pub fn register_queue_interrupt_functions<F>(&mut self, functions: &mut Vec<F>)
|
pub fn register_queue_interrupt_functions<F>(&mut self, functions: &mut Vec<F>)
|
||||||
where
|
where
|
||||||
F: Fn(TrapFrame) + Send + Sync + 'static,
|
F: Fn(&TrapFrame) + Send + Sync + 'static,
|
||||||
{
|
{
|
||||||
let len = functions.len();
|
let len = functions.len();
|
||||||
if len
|
if len
|
||||||
|
@ -6,6 +6,7 @@ use bitflags::bitflags;
|
|||||||
use core::sync::atomic::{fence, Ordering};
|
use core::sync::atomic::{fence, Ordering};
|
||||||
use kxos_frame::offset_of;
|
use kxos_frame::offset_of;
|
||||||
use kxos_frame::Pod;
|
use kxos_frame::Pod;
|
||||||
|
use kxos_frame_pod_derive::Pod;
|
||||||
use kxos_util::frame_ptr::InFramePtr;
|
use kxos_util::frame_ptr::InFramePtr;
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum QueueError {
|
pub enum QueueError {
|
||||||
@ -230,7 +231,7 @@ impl VirtQueue {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[repr(C, align(16))]
|
#[repr(C, align(16))]
|
||||||
#[derive(Debug, Default, Copy, Clone)]
|
#[derive(Debug, Default, Copy, Clone, Pod)]
|
||||||
struct Descriptor {
|
struct Descriptor {
|
||||||
addr: u64,
|
addr: u64,
|
||||||
len: u32,
|
len: u32,
|
||||||
@ -252,9 +253,9 @@ fn set_buf(inframe_ptr: &InFramePtr<Descriptor>, buf: &[u8]) {
|
|||||||
);
|
);
|
||||||
inframe_ptr.write_at(offset_of!(Descriptor, len), buf.len() as u32);
|
inframe_ptr.write_at(offset_of!(Descriptor, len), buf.len() as u32);
|
||||||
}
|
}
|
||||||
|
|
||||||
bitflags! {
|
bitflags! {
|
||||||
/// Descriptor flags
|
/// Descriptor flags
|
||||||
|
#[derive(Pod)]
|
||||||
struct DescFlags: u16 {
|
struct DescFlags: u16 {
|
||||||
const NEXT = 1;
|
const NEXT = 1;
|
||||||
const WRITE = 2;
|
const WRITE = 2;
|
||||||
@ -273,7 +274,7 @@ impl Default for DescFlags {
|
|||||||
/// each ring entry refers to the head of a descriptor chain.
|
/// each ring entry refers to the head of a descriptor chain.
|
||||||
/// It is only written by the driver and read by the device.
|
/// It is only written by the driver and read by the device.
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Debug, Default, Copy, Clone)]
|
#[derive(Debug, Default, Copy, Clone, Pod)]
|
||||||
struct AvailRing {
|
struct AvailRing {
|
||||||
flags: u16,
|
flags: u16,
|
||||||
/// A driver MUST NOT decrement the idx.
|
/// A driver MUST NOT decrement the idx.
|
||||||
@ -285,7 +286,7 @@ struct AvailRing {
|
|||||||
/// The used ring is where the device returns buffers once it is done with them:
|
/// The used ring is where the device returns buffers once it is done with them:
|
||||||
/// it is only written to by the device, and read by the driver.
|
/// it is only written to by the device, and read by the driver.
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Debug, Default, Copy, Clone)]
|
#[derive(Debug, Default, Copy, Clone, Pod)]
|
||||||
struct UsedRing {
|
struct UsedRing {
|
||||||
flags: u16,
|
flags: u16,
|
||||||
idx: u16,
|
idx: u16,
|
||||||
@ -294,10 +295,8 @@ struct UsedRing {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Debug, Default, Copy, Clone)]
|
#[derive(Debug, Default, Copy, Clone, Pod)]
|
||||||
struct UsedElem {
|
struct UsedElem {
|
||||||
id: u32,
|
id: u32,
|
||||||
len: u32,
|
len: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
kxos_frame::impl_pod_for!(UsedElem, UsedRing, AvailRing, Descriptor, DescFlags);
|
|
||||||
|
48
src/tests/timer_test.rs
Normal file
48
src/tests/timer_test.rs
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
#![no_std]
|
||||||
|
#![no_main]
|
||||||
|
#![feature(custom_test_frameworks)]
|
||||||
|
#![test_runner(kxos_frame::test_runner)]
|
||||||
|
#![reexport_test_harness_main = "test_main"]
|
||||||
|
use bootloader::{entry_point, BootInfo};
|
||||||
|
use kxos_frame::timer::Timer;
|
||||||
|
extern crate alloc;
|
||||||
|
use alloc::sync::Arc;
|
||||||
|
use core::panic::PanicInfo;
|
||||||
|
use core::time::Duration;
|
||||||
|
use kxos_frame::println;
|
||||||
|
|
||||||
|
static mut TICK: usize = 0;
|
||||||
|
|
||||||
|
entry_point!(kernel_test_main);
|
||||||
|
|
||||||
|
fn kernel_test_main(boot_info: &'static mut BootInfo) -> ! {
|
||||||
|
kxos_frame::init(boot_info);
|
||||||
|
test_main();
|
||||||
|
loop {}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[panic_handler]
|
||||||
|
fn panic(info: &PanicInfo) -> ! {
|
||||||
|
kxos_frame::test_panic_handler(info)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test_case]
|
||||||
|
fn test_timer() {
|
||||||
|
println!(
|
||||||
|
"If you want to pass this test, you may need to enable the interrupt in kxos_frame/lib.rs"
|
||||||
|
);
|
||||||
|
println!("make sure the Timer irq number 32 handler won't panic");
|
||||||
|
unsafe {
|
||||||
|
let timer = Timer::new(timer_callback).unwrap();
|
||||||
|
timer.set(Duration::from_secs(1));
|
||||||
|
while TICK < 5 {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn timer_callback(timer: Arc<Timer>) {
|
||||||
|
unsafe {
|
||||||
|
TICK += 1;
|
||||||
|
println!("TICK:{}", TICK);
|
||||||
|
timer.set(Duration::from_secs(1));
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user