From 280591db666eb980e93c67d43f8b248ec1f8b75e Mon Sep 17 00:00:00 2001 From: sdww0 <1315953661@qq.com> Date: Wed, 9 Nov 2022 20:33:41 +0800 Subject: [PATCH 1/4] finish PIT Timer and add testcase --- src/kxos-frame/src/device/mod.rs | 4 + src/kxos-frame/src/device/pic.rs | 182 +++++++++++++++++++ src/kxos-frame/src/lib.rs | 14 +- src/kxos-frame/src/timer.rs | 72 +++++++- src/kxos-frame/src/trap/handler.rs | 15 +- src/kxos-frame/src/trap/irq.rs | 16 +- src/kxos-frame/src/trap/mod.rs | 2 +- src/kxos-frame/src/util/recycle_allocator.rs | 71 ++++++-- src/kxos-frame/src/x86_64_util.rs | 7 + src/kxos-std/src/driver/pci/virtio/block.rs | 2 +- src/kxos-virtio/src/lib.rs | 2 +- src/tests/timer_test.rs | 46 +++++ 12 files changed, 394 insertions(+), 39 deletions(-) create mode 100644 src/kxos-frame/src/device/pic.rs create mode 100644 src/tests/timer_test.rs diff --git a/src/kxos-frame/src/device/mod.rs b/src/kxos-frame/src/device/mod.rs index eff48e93..e0337b7b 100644 --- a/src/kxos-frame/src/device/mod.rs +++ b/src/kxos-frame/src/device/mod.rs @@ -4,9 +4,13 @@ pub mod framebuffer; mod io_port; pub mod pci; pub mod serial; +mod pic; +pub use pic::{TimerCallback, TIMER_FREQ}; +pub(crate) use pic::{add_timeout_list,TICK}; pub use self::io_port::IoPort; pub(crate) fn init(framebuffer: &'static mut bootloader::boot_info::FrameBuffer) { framebuffer::init(framebuffer); + pic::init(); } diff --git a/src/kxos-frame/src/device/pic.rs b/src/kxos-frame/src/device/pic.rs new file mode 100644 index 00000000..c55282cb --- /dev/null +++ b/src/kxos-frame/src/device/pic.rs @@ -0,0 +1,182 @@ +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 = 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>= 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>> = Cell::new(BinaryHeap::new()) ; +} + +pub struct TimerCallback { + expire_ms: u64, + data: Arc, + callback: Box, + enable: Cell, +} + +impl TimerCallback { + fn new( + timeout_ms: u64, + data: Arc, + callback: Box, + ) -> Self { + Self { + expire_ms: timeout_ms, + data, + callback, + enable:Cell::new(true), + } + } + + pub fn data(&self) -> &Arc { + &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 { + 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(timeout: u64, data: T, callback: F) -> Arc +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 + } +} diff --git a/src/kxos-frame/src/lib.rs b/src/kxos-frame/src/lib.rs index be481f24..13c44156 100644 --- a/src/kxos-frame/src/lib.rs +++ b/src/kxos-frame/src/lib.rs @@ -62,10 +62,6 @@ pub use crate::serial_println as println; pub fn init(boot_info: &'static mut BootInfo) { 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; // memory for region in boot_info.memory_regions.iter() { @@ -84,13 +80,19 @@ pub fn init(boot_info: &'static mut BootInfo) { if !memory_init { panic!("memory init failed"); } + device::init(boot_info.framebuffer.as_mut().unwrap()); + device::framebuffer::WRITER.lock().as_mut().unwrap().clear(); + trap::init(); + enable_common_cpu_features(); unsafe { for i in 0..256 { 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!("rip = 0x{:x}", trap_frame.rip); println!("rsp = 0x{:x}", trap_frame.rsp); @@ -113,7 +115,7 @@ where T: Fn(), { fn run(&self) { - serial_print!("{}...\t", core::any::type_name::()); + serial_print!("{}...\n", core::any::type_name::()); self(); serial_println!("[ok]"); } diff --git a/src/kxos-frame/src/timer.rs b/src/kxos-frame/src/timer.rs index 9fa3d499..ba9a3820 100644 --- a/src/kxos-frame/src/timer.rs +++ b/src/kxos-frame/src/timer.rs @@ -1,6 +1,7 @@ //! Timer. -use crate::prelude::*; +use crate::{prelude::*, device::{TimerCallback, TICK,TIMER_FREQ}}; +use spin::Mutex; use core::time::Duration; /// A timer invokes a callback function after a specified span of time elapsed. @@ -11,33 +12,86 @@ use core::time::Duration; /// /// Timers are one-shot. If the time is out, one has to set the timer again /// in order to trigger the callback again. -pub struct Timer {} +pub struct Timer { + function: Arc)+Send+Sync>, + inner: Mutex, +} +#[derive(Default)] +struct TimerInner{ + start_tick: u64, + timeout_tick:u64, + timer_callback:Option>, +} + +fn timer_callback(callback:&TimerCallback){ + let data = callback.data(); + if data.is::>(){ + let timer = data.downcast_ref::>().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 { /// Creates a new instance, given a callback function. - pub fn new(f: F) -> Result + pub fn new(f: F) -> Result> where - F: FnMut(&Self), + F: Fn(Arc) +Send+Sync+'static, { - todo!() + Ok(Arc::new(Self { function: Arc::new(f),inner:Mutex::new(TimerInner::default()) })) } /// Set a timeout value. /// /// 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, 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. /// /// If the timer is not set, then the remaining timeout value is zero. 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. 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; } } diff --git a/src/kxos-frame/src/trap/handler.rs b/src/kxos-frame/src/trap/handler.rs index c6fbf5cb..b3d4cabf 100644 --- a/src/kxos-frame/src/trap/handler.rs +++ b/src/kxos-frame/src/trap/handler.rs @@ -5,7 +5,7 @@ use crate::task::{ use super::{irq::IRQ_LIST, *}; #[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 current = Task::current(); 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] -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) { let current = Task::current(); 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 callback_functions = irq_line.callback_list(); for callback_function in callback_functions.iter() { - callback_function.call(f.clone()); + callback_function.call(f); } } } 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); + } } } diff --git a/src/kxos-frame/src/trap/irq.rs b/src/kxos-frame/src/trap/irq.rs index 112f744f..9c9ca371 100644 --- a/src/kxos-frame/src/trap/irq.rs +++ b/src/kxos-frame/src/trap/irq.rs @@ -20,6 +20,14 @@ pub fn allocate_irq() -> Result { } } +pub(crate) fn allocate_target_irq(target_irq: u8) -> Result { + 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 /// /// 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. pub fn on_active(&mut self, callback: F) where - F: Fn(TrapFrame) + Sync + Send + 'static, + F: Fn(&TrapFrame) + Sync + Send + 'static, { self.callbacks.push(self.irq.on_active(callback)) } @@ -87,12 +95,12 @@ lazy_static! { } pub struct CallbackElement { - function: Box, + function: Box, id: usize, } impl CallbackElement { - pub fn call(&self, element: TrapFrame) { + pub fn call(&self, element: &TrapFrame) { self.function.call((element,)); } } @@ -140,7 +148,7 @@ impl IrqLine { /// For each IRQ line, multiple callbacks may be registered. pub fn on_active(&self, callback: F) -> IrqCallbackHandle where - F: Fn(TrapFrame) + Sync + Send + 'static, + F: Fn(&TrapFrame) + Sync + Send + 'static, { let allocate_id = ID_ALLOCATOR.lock().alloc(); self.callback_list.lock().push(CallbackElement { diff --git a/src/kxos-frame/src/trap/mod.rs b/src/kxos-frame/src/trap/mod.rs index 453cb151..5ae6dc5b 100644 --- a/src/kxos-frame/src/trap/mod.rs +++ b/src/kxos-frame/src/trap/mod.rs @@ -2,7 +2,7 @@ mod handler; mod irq; 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 crate::{x86_64_util::*, *}; diff --git a/src/kxos-frame/src/util/recycle_allocator.rs b/src/kxos-frame/src/util/recycle_allocator.rs index 04f1c8da..8d1932bd 100644 --- a/src/kxos-frame/src/util/recycle_allocator.rs +++ b/src/kxos-frame/src/util/recycle_allocator.rs @@ -3,6 +3,7 @@ use alloc::vec::Vec; pub struct RecycleAllocator { current: usize, recycled: Vec, + skip: Vec, max: usize, } @@ -11,6 +12,7 @@ impl RecycleAllocator { RecycleAllocator { current: 0, recycled: Vec::new(), + skip: Vec::new(), max: usize::MAX - 1, } } @@ -19,30 +21,73 @@ impl RecycleAllocator { RecycleAllocator { current: start, recycled: Vec::new(), + skip: Vec::new(), max: max, } } #[allow(unused)] 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; } - 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)] pub fn dealloc(&mut self, id: usize) { - assert!(id < self.current); - assert!( - !self.recycled.iter().any(|i| *i == id), - "id {} has been deallocated!", - id - ); + if !self.skip.contains(&id) { + assert!(id < self.current); + assert!( + !self.recycled.iter().any(|i| *i == id), + "id {} has been deallocated!", + 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); } + + /// 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 + } + } + } } diff --git a/src/kxos-frame/src/x86_64_util.rs b/src/kxos-frame/src/x86_64_util.rs index 10c8d05a..73233019 100644 --- a/src/kxos-frame/src/x86_64_util.rs +++ b/src/kxos-frame/src/x86_64_util.rs @@ -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 RING3: u16 = 3; diff --git a/src/kxos-std/src/driver/pci/virtio/block.rs b/src/kxos-std/src/driver/pci/virtio/block.rs index 62d6e342..785d9da7 100644 --- a/src/kxos-std/src/driver/pci/virtio/block.rs +++ b/src/kxos-std/src/driver/pci/virtio/block.rs @@ -124,7 +124,7 @@ impl BlockDevice for VirtioBlockDevice { impl VirtioBlockDevice { 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"); BLOCK_DEVICE.lock().as_ref().unwrap().handle_irq() } diff --git a/src/kxos-virtio/src/lib.rs b/src/kxos-virtio/src/lib.rs index 692fa662..03d48517 100644 --- a/src/kxos-virtio/src/lib.rs +++ b/src/kxos-virtio/src/lib.rs @@ -272,7 +272,7 @@ impl PCIVirtioDevice { /// register the queue interrupt functions, this function should call only once pub fn register_queue_interrupt_functions(&mut self, functions: &mut Vec) where - F: Fn(TrapFrame) + Send + Sync + 'static, + F: Fn(&TrapFrame) + Send + Sync + 'static, { let len = functions.len(); if len diff --git a/src/tests/timer_test.rs b/src/tests/timer_test.rs new file mode 100644 index 00000000..7d9cad0a --- /dev/null +++ b/src/tests/timer_test.rs @@ -0,0 +1,46 @@ +#![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::time::Duration; +use core::panic::PanicInfo; +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) { + unsafe { + TICK+=1; + println!("TICK:{}",TICK); + timer.set(Duration::from_secs(1)); + } +} From 9480890e3ccb3c2e4db8e4a4d3aa5b53c011a706 Mon Sep 17 00:00:00 2001 From: sdww0 <1315953661@qq.com> Date: Wed, 9 Nov 2022 21:20:44 +0800 Subject: [PATCH 2/4] use derive pod instead of impl_pod_for --- src/Cargo.lock | 2 ++ src/kxos-frame-pod-derive/src/lib.rs | 17 ++++++++++++++--- src/kxos-frame/src/lib.rs | 1 - src/kxos-frame/src/vm/mod.rs | 1 - src/kxos-frame/src/vm/pod.rs | 2 -- src/kxos-pci/Cargo.toml | 1 + src/kxos-pci/src/msix.rs | 5 ++--- src/kxos-std/src/driver/pci/virtio/block.rs | 13 ++++++------- src/kxos-virtio/Cargo.toml | 1 + src/kxos-virtio/src/block.rs | 9 ++++----- src/kxos-virtio/src/lib.rs | 7 ++++--- src/kxos-virtio/src/queue.rs | 13 ++++++------- 12 files changed, 40 insertions(+), 32 deletions(-) diff --git a/src/Cargo.lock b/src/Cargo.lock index 1f64b119..9c013331 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -127,6 +127,7 @@ version = "0.1.0" dependencies = [ "bitflags", "kxos-frame", + "kxos-frame-pod-derive", "kxos-util", "lazy_static", "spin 0.9.4", @@ -182,6 +183,7 @@ version = "0.1.0" dependencies = [ "bitflags", "kxos-frame", + "kxos-frame-pod-derive", "kxos-pci", "kxos-util", "spin 0.9.4", diff --git a/src/kxos-frame-pod-derive/src/lib.rs b/src/kxos-frame-pod-derive/src/lib.rs index bb0243c6..17769688 100644 --- a/src/kxos-frame-pod-derive/src/lib.rs +++ b/src/kxos-frame-pod-derive/src/lib.rs @@ -1,6 +1,6 @@ use proc_macro2::TokenStream; use quote::quote; -use syn::{parse_macro_input, Data, DataStruct, DeriveInput, Fields}; +use syn::{parse_macro_input, Data, DataStruct, DeriveInput, Fields, DataEnum, punctuated::Punctuated, token::Comma, Field}; #[proc_macro_derive(Pod)] pub fn derive_pod(input_token: proc_macro::TokenStream) -> proc_macro::TokenStream { @@ -14,11 +14,22 @@ fn expand_derive_pod(input: DeriveInput) -> TokenStream { Data::Struct(DataStruct { fields, .. }) => match fields { Fields::Named(fields_named) => fields_named.named, 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 = 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. // 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 diff --git a/src/kxos-frame/src/lib.rs b/src/kxos-frame/src/lib.rs index 13c44156..45aab530 100644 --- a/src/kxos-frame/src/lib.rs +++ b/src/kxos-frame/src/lib.rs @@ -26,7 +26,6 @@ pub mod timer; pub mod trap; pub mod user; mod util; -#[macro_use] pub mod vm; pub(crate) mod x86_64_util; diff --git a/src/kxos-frame/src/vm/mod.rs b/src/kxos-frame/src/vm/mod.rs index 2b59cb8f..34c00fad 100644 --- a/src/kxos-frame/src/vm/mod.rs +++ b/src/kxos-frame/src/vm/mod.rs @@ -8,7 +8,6 @@ pub type Paddr = usize; mod frame; mod io; -#[macro_use] mod pod; mod space; diff --git a/src/kxos-frame/src/vm/pod.rs b/src/kxos-frame/src/vm/pod.rs index f53aff2f..479dbce1 100644 --- a/src/kxos-frame/src/vm/pod.rs +++ b/src/kxos-frame/src/vm/pod.rs @@ -52,8 +52,6 @@ pub unsafe trait Pod: Copy + Sized + Debug { } } -/// FIXME: use derive instead -#[macro_export] macro_rules! impl_pod_for { ($($pod_ty:ty),*) => { $(unsafe impl Pod for $pod_ty {})* diff --git a/src/kxos-pci/Cargo.toml b/src/kxos-pci/Cargo.toml index be1797bf..610e79fd 100644 --- a/src/kxos-pci/Cargo.toml +++ b/src/kxos-pci/Cargo.toml @@ -10,6 +10,7 @@ bitflags = "1.3" spin = "0.9.4" kxos-frame = {path = "../kxos-frame"} kxos-util = {path="../kxos-util"} +kxos-frame-pod-derive= {path="../kxos-frame-pod-derive"} [dependencies.lazy_static] version = "1.0" diff --git a/src/kxos-pci/src/msix.rs b/src/kxos-pci/src/msix.rs index 2dd3640d..8fc03b60 100644 --- a/src/kxos-pci/src/msix.rs +++ b/src/kxos-pci/src/msix.rs @@ -1,6 +1,7 @@ use alloc::vec::Vec; use crate::util::{CSpaceAccessMethod, Location, BAR}; +use kxos_frame_pod_derive::Pod; use super::capability::msix::CapabilityMSIXData; @@ -21,7 +22,7 @@ pub struct MSIXEntry { pub irq_handle: IrqAllocateHandle, } -#[derive(Debug, Default, Copy, Clone, PartialEq, Eq)] +#[derive(Debug, Default, Copy, Clone, PartialEq, Eq,Pod)] #[repr(C)] pub struct MSIXTableEntry { pub msg_addr: u32, @@ -30,8 +31,6 @@ pub struct MSIXTableEntry { pub vector_control: u32, } -kxos_frame::impl_pod_for!(MSIXTableEntry); - impl MSIX { /// create a MSIX instance, it allocate the irq number automatically. pub fn new( diff --git a/src/kxos-std/src/driver/pci/virtio/block.rs b/src/kxos-std/src/driver/pci/virtio/block.rs index 785d9da7..bd2fe26c 100644 --- a/src/kxos-std/src/driver/pci/virtio/block.rs +++ b/src/kxos-std/src/driver/pci/virtio/block.rs @@ -3,9 +3,10 @@ use core::hint::spin_loop; use crate::process::Process; use alloc::sync::Arc; use alloc::vec::Vec; -use kxos_frame::{impl_pod_for, info}; +use kxos_frame::info; use kxos_pci::PCIDevice; use kxos_virtio::PCIVirtioDevice; +use kxos_frame_pod_derive::Pod; use lazy_static::lazy_static; use spin::mutex::Mutex; @@ -18,7 +19,7 @@ pub struct VirtioBlockDevice { } #[repr(C)] -#[derive(Debug, Copy, Clone)] +#[derive(Debug, Copy, Clone,Pod)] pub struct BlkReq { pub type_: ReqType, pub reserved: u32, @@ -27,13 +28,13 @@ pub struct BlkReq { /// Response of a VirtIOBlk request. #[repr(C)] -#[derive(Debug, Copy, Clone)] +#[derive(Debug, Copy, Clone,Pod)] pub struct BlkResp { pub status: RespStatus, } #[repr(u32)] -#[derive(Debug, Copy, Clone)] +#[derive(Debug, Copy, Clone,Pod)] pub enum ReqType { In = 0, Out = 1, @@ -43,7 +44,7 @@ pub enum ReqType { } #[repr(u8)] -#[derive(Debug, Eq, PartialEq, Copy, Clone)] +#[derive(Debug, Eq, PartialEq, Copy, Clone,Pod)] pub enum RespStatus { /// Ok. Ok = 0, @@ -63,8 +64,6 @@ impl Default for BlkResp { } } -impl_pod_for!(BlkResp, RespStatus, ReqType, BlkReq); - lazy_static! { // TODO: use dyn BlockDevice instead pub static ref BLOCK_DEVICE: Arc>> = Arc::new(Mutex::new(None)) ; diff --git a/src/kxos-virtio/Cargo.toml b/src/kxos-virtio/Cargo.toml index 25b0429a..f0835309 100644 --- a/src/kxos-virtio/Cargo.toml +++ b/src/kxos-virtio/Cargo.toml @@ -11,6 +11,7 @@ spin = "0.9.4" kxos-frame = {path = "../kxos-frame"} kxos-pci = {path="../kxos-pci"} kxos-util = {path="../kxos-util"} +kxos-frame-pod-derive= {path="../kxos-frame-pod-derive"} [features] diff --git a/src/kxos-virtio/src/block.rs b/src/kxos-virtio/src/block.rs index 81b680ca..d79e5f39 100644 --- a/src/kxos-virtio/src/block.rs +++ b/src/kxos-virtio/src/block.rs @@ -2,10 +2,11 @@ use kxos_frame::Pod; use kxos_pci::capability::vendor::virtio::CapabilityVirtioData; use kxos_pci::util::BAR; use kxos_util::frame_ptr::InFramePtr; +use kxos_frame_pod_derive::Pod; pub const BLK_SIZE: usize = 512; -#[derive(Debug, Copy, Clone)] +#[derive(Debug, Copy, Clone,Pod)] #[repr(C)] pub struct VirtioBLKConfig { capacity: u64, @@ -24,7 +25,7 @@ pub struct VirtioBLKConfig { unused1: [u8; 3], } -#[derive(Debug, Copy, Clone)] +#[derive(Debug, Copy, Clone,Pod)] #[repr(C)] pub struct VirtioBLKGeometry { cylinders: u16, @@ -32,7 +33,7 @@ pub struct VirtioBLKGeometry { sectors: u8, } -#[derive(Debug, Copy, Clone)] +#[derive(Debug, Copy, Clone,Pod)] #[repr(C)] pub struct VirtioBLKTopology { physical_block_exp: u8, @@ -41,8 +42,6 @@ pub struct VirtioBLKTopology { opt_io_size: u32, } -kxos_frame::impl_pod_for!(VirtioBLKTopology, VirtioBLKGeometry, VirtioBLKConfig); - impl VirtioBLKConfig { pub(crate) fn new(cap: &CapabilityVirtioData, bars: [Option; 6]) -> InFramePtr { let bar = cap.bar; diff --git a/src/kxos-virtio/src/lib.rs b/src/kxos-virtio/src/lib.rs index 03d48517..a6d1b737 100644 --- a/src/kxos-virtio/src/lib.rs +++ b/src/kxos-virtio/src/lib.rs @@ -9,8 +9,11 @@ use bitflags::bitflags; use kxos_frame::{info, offset_of, TrapFrame}; use kxos_pci::util::{PCIDevice, BAR}; use kxos_util::frame_ptr::InFramePtr; +use kxos_frame_pod_derive::Pod; + use spin::{mutex::Mutex, MutexGuard}; + use self::{block::VirtioBLKConfig, queue::VirtQueue}; use kxos_frame::Pod; @@ -54,7 +57,7 @@ bitflags! { } } -#[derive(Debug, Default, Copy, Clone)] +#[derive(Debug, Default, Copy, Clone,Pod)] #[repr(C)] pub struct VitrioPciCommonCfg { device_feature_select: u32, @@ -76,8 +79,6 @@ pub struct VitrioPciCommonCfg { queue_device: u64, } -kxos_frame::impl_pod_for!(VitrioPciCommonCfg); - impl VitrioPciCommonCfg { pub(crate) fn new(cap: &CapabilityVirtioData, bars: [Option; 6]) -> InFramePtr { let bar = cap.bar; diff --git a/src/kxos-virtio/src/queue.rs b/src/kxos-virtio/src/queue.rs index 684e7703..85a12249 100644 --- a/src/kxos-virtio/src/queue.rs +++ b/src/kxos-virtio/src/queue.rs @@ -7,6 +7,7 @@ use core::sync::atomic::{fence, Ordering}; use kxos_frame::offset_of; use kxos_frame::Pod; use kxos_util::frame_ptr::InFramePtr; +use kxos_frame_pod_derive::Pod; #[derive(Debug)] pub enum QueueError { InvalidArgs, @@ -230,7 +231,7 @@ impl VirtQueue { } #[repr(C, align(16))] -#[derive(Debug, Default, Copy, Clone)] +#[derive(Debug, Default, Copy, Clone,Pod)] struct Descriptor { addr: u64, len: u32, @@ -252,9 +253,9 @@ fn set_buf(inframe_ptr: &InFramePtr, buf: &[u8]) { ); inframe_ptr.write_at(offset_of!(Descriptor, len), buf.len() as u32); } - bitflags! { /// Descriptor flags + #[derive(Pod)] struct DescFlags: u16 { const NEXT = 1; const WRITE = 2; @@ -273,7 +274,7 @@ impl Default for DescFlags { /// each ring entry refers to the head of a descriptor chain. /// It is only written by the driver and read by the device. #[repr(C)] -#[derive(Debug, Default, Copy, Clone)] +#[derive(Debug, Default, Copy, Clone,Pod)] struct AvailRing { flags: u16, /// 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: /// it is only written to by the device, and read by the driver. #[repr(C)] -#[derive(Debug, Default, Copy, Clone)] +#[derive(Debug, Default, Copy, Clone,Pod)] struct UsedRing { flags: u16, idx: u16, @@ -294,10 +295,8 @@ struct UsedRing { } #[repr(C)] -#[derive(Debug, Default, Copy, Clone)] +#[derive(Debug, Default, Copy, Clone,Pod)] struct UsedElem { id: u32, len: u32, } - -kxos_frame::impl_pod_for!(UsedElem, UsedRing, AvailRing, Descriptor, DescFlags); From 7be7775f97263ae8d7bd2b96bc7182ac1b0216cf Mon Sep 17 00:00:00 2001 From: Yuke Peng Date: Thu, 10 Nov 2022 06:53:23 -0800 Subject: [PATCH 3/4] VMO and VMAR passed the compilation --- src/Cargo.lock | 3 + src/kxos-std/Cargo.toml | 3 + src/kxos-std/src/lib.rs | 3 + src/kxos-std/src/rights.rs | 58 ++++++++++--------- src/kxos-std/src/vm/mod.rs | 2 +- src/kxos-std/src/vm/vmar/dyn_cap.rs | 47 +++++++++++++--- src/kxos-std/src/vm/vmar/mod.rs | 36 +++++++----- src/kxos-std/src/vm/vmar/options.rs | 23 +++++--- src/kxos-std/src/vm/vmar/static_cap.rs | 61 ++++++++++++++++---- src/kxos-std/src/vm/vmo/dyn_cap.rs | 31 ++++++++--- src/kxos-std/src/vm/vmo/mod.rs | 25 ++++----- src/kxos-std/src/vm/vmo/options.rs | 77 ++++++++++++++++++++------ src/kxos-std/src/vm/vmo/pager.rs | 3 + src/kxos-std/src/vm/vmo/static_cap.rs | 39 ++++++++----- src/kxos-typeflags-util/src/bool.rs | 7 ++- src/kxos-typeflags-util/src/lib.rs | 2 +- src/kxos-typeflags-util/src/set.rs | 4 +- src/kxos-typeflags/src/type_flag.rs | 3 +- 18 files changed, 304 insertions(+), 123 deletions(-) diff --git a/src/Cargo.lock b/src/Cargo.lock index 9c013331..f3f809f1 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -150,6 +150,9 @@ dependencies = [ "kxos-frame", "kxos-frame-pod-derive", "kxos-pci", + "kxos-rights-proc", + "kxos-typeflags", + "kxos-typeflags-util", "kxos-virtio", "lazy_static", "spin 0.9.4", diff --git a/src/kxos-std/Cargo.toml b/src/kxos-std/Cargo.toml index 9df4831b..1fd63d9d 100644 --- a/src/kxos-std/Cargo.toml +++ b/src/kxos-std/Cargo.toml @@ -10,6 +10,9 @@ kxos-frame = {path = "../kxos-frame"} kxos-frame-pod-derive = {path = "../kxos-frame-pod-derive"} kxos-pci = {path="../kxos-pci"} 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 xmas-elf = "0.8.0" diff --git a/src/kxos-std/src/lib.rs b/src/kxos-std/src/lib.rs index a349363c..aa79ba43 100644 --- a/src/kxos-std/src/lib.rs +++ b/src/kxos-std/src/lib.rs @@ -8,6 +8,7 @@ #![feature(half_open_range_patterns)] #![feature(exclusive_range_pattern)] #![feature(btree_drain_filter)] +#![feature(const_option)] use kxos_frame::{debug, info, println}; use process::Process; @@ -25,6 +26,8 @@ mod process; pub mod syscall; mod user_apps; mod util; +pub mod vm; +pub mod rights; #[macro_use] extern crate kxos_frame_pod_derive; diff --git a/src/kxos-std/src/rights.rs b/src/kxos-std/src/rights.rs index 4882211c..cbb51f35 100644 --- a/src/kxos-std/src/rights.rs +++ b/src/kxos-std/src/rights.rs @@ -1,4 +1,4 @@ -use typeflags::typeflags; +use kxos_typeflags::type_flags; use bitflags::bitflags; bitflags! { @@ -10,38 +10,46 @@ bitflags! { /// Here, we give some sensible semantics for each access right. pub struct Rights: u32 { /// 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 /// 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 /// creating writable memory mappings. - const WRITE: u32 = 1 << 2; + const WRITE = 1 << 2; /// Allows creating executable memory mappings. - const EXEC: u32 = 1 << 3; + const EXEC = 1 << 3; /// Allows sending notifications or signals. - const SIGNAL: u32 = 1 << 7; + const SIGNAL = 1 << 7; } } - -typeflags! { - /// Type-based access rights. - /// - /// Similar to value-based access rights (`Rights`), but represented in - /// types. +/// Type-based access rights. +/// +/// Similar to value-based access rights (`Rights`), but represented in +/// 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 { - /// 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; + pub struct Dup = 1 <<0; + pub struct Read = 1 <<1; + pub struct Write = 1 <<2; + pub struct Exec = 1 <<3; + pub struct Signal = 1 <<7; } } @@ -51,5 +59,5 @@ pub type Full = TRights![ Read, Write, Exec, - Signal, + Signal ]; diff --git a/src/kxos-std/src/vm/mod.rs b/src/kxos-std/src/vm/mod.rs index e89392f4..7d6a2e57 100644 --- a/src/kxos-std/src/vm/mod.rs +++ b/src/kxos-std/src/vm/mod.rs @@ -2,7 +2,7 @@ //! //! There are two primary VM abstractions: //! * 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 //! represents a set of memory pages. //! diff --git a/src/kxos-std/src/vm/vmar/dyn_cap.rs b/src/kxos-std/src/vm/vmar/dyn_cap.rs index 4c31f91c..1d7d77e0 100644 --- a/src/kxos-std/src/vm/vmar/dyn_cap.rs +++ b/src/kxos-std/src/vm/vmar/dyn_cap.rs @@ -1,7 +1,17 @@ +use core::ops::Range; + +use alloc::sync::Arc; +use kxos_frame::{vm::VmIo, Error}; +use kxos_frame::prelude::Result; + +use crate::{rights::Rights, vm::vmo::Vmo}; + +use super::{Vmar, VmPerms, options::{VmarChildOptions, VmarMapOptions}, Vmar_}; + impl Vmar { /// Creates a root VMAR. pub fn new() -> Result { - let inner = Arc::new(Vmar_::new()); + let inner = Arc::new(Vmar_::new()?); let rights = Rights::all(); let new_self = Self(inner, rights); Ok(new_self) @@ -42,9 +52,9 @@ impl Vmar { /// Memory permissions may be changed through the `protect` method, /// which ensures that any updated memory permissions do not go beyond /// 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, perms: VmPerms) -> Result> { 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. @@ -66,9 +76,9 @@ impl Vmar { /// /// The new VMAR child will be of the same capability class and /// access rights as the parent. - pub fn new_child(&self, size: usize) -> VmarChildOptions<'a, Rights> { + pub fn new_child(&self, size: usize) -> Result> { 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. @@ -107,24 +117,43 @@ impl Vmar { /// As for children VMARs, they must be fully within the range. /// All children VMARs that fall within the range get their `destroy` methods /// called. - pub fn destroy(&self, range: &Range) -> Result<()> { + pub fn destroy(&self, range: Range) -> Result<()> { self.0.destroy(range) } + /// Duplicates the capability. + /// + /// # Access rights + /// + /// The method requires the Dup right. + pub fn dup(&self) -> Result { + self.check_rights(Rights::DUP)?; + todo!() + } + /// Returns the access rights. pub fn rights(&self) -> Rights { self.1 } + + fn check_rights(&self, rights: Rights) -> Result<()> { + if self.1.contains(rights) { + Ok(()) + } else { + Err(Error::AccessDenied) + } + } + } -impl VmIo for Vmar { +impl VmIo for Vmar { 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) } fn write_bytes(&self, offset: usize, buf: &[u8]) -> Result<()> { - self.check_rights!(Rights::WRITE)?; + self.check_rights(Rights::WRITE)?; self.0.write(offset, buf) } } \ No newline at end of file diff --git a/src/kxos-std/src/vm/vmar/mod.rs b/src/kxos-std/src/vm/vmar/mod.rs index 13d9b3c8..d5038dc5 100644 --- a/src/kxos-std/src/vm/vmar/mod.rs +++ b/src/kxos-std/src/vm/vmar/mod.rs @@ -4,6 +4,16 @@ mod static_cap; mod dyn_cap; mod options; +use core::ops::Range; +use kxos_frame::vm::VmSpace; +use kxos_frame::vm::Vaddr; +use spin::Mutex; +use alloc::sync::Arc; +use kxos_frame::prelude::Result; +use kxos_frame::Error; +use crate::rights::Rights; +use bitflags::bitflags; + /// Virtual Memory Address Regions (VMARs) are a type of capability that manages /// user address spaces. /// @@ -79,32 +89,32 @@ impl Vmar { /// /// The base address of a root VMAR is zero. 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) - } - } + } bitflags! { /// The memory access permissions of memory mappings. pub struct VmPerms: u32 { /// Readable. - const READ: u32 = 1 << 0; + const READ = 1 << 0; /// Writable. - const WRITE: u32 = 1 << 1; + const WRITE = 1 << 1; /// Executable. - const EXEC: u32 = 1 << 2; + const EXEC = 1 << 2; } } impl From for VmPerms { - fn from(perms: VmPerms) -> Rights { + fn from(rights: Rights) -> VmPerms { todo!() } -} \ No newline at end of file +} + +impl From for Rights { + fn from(vm_perms: VmPerms) -> Rights { + todo!() + } +} diff --git a/src/kxos-std/src/vm/vmar/options.rs b/src/kxos-std/src/vm/vmar/options.rs index 4c52e886..e48e2e5d 100644 --- a/src/kxos-std/src/vm/vmar/options.rs +++ b/src/kxos-std/src/vm/vmar/options.rs @@ -1,5 +1,12 @@ //! Options for allocating child VMARs and creating mappings. +use kxos_frame::{config::PAGE_SIZE, vm::Vaddr}; +use kxos_frame::prelude::Result; + +use crate::vm::vmo::Vmo; + +use super::{Vmar, VmPerms}; + /// Options for allocating a child VMAR, which must not overlap with any /// existing mappings or child VMARs. /// @@ -39,6 +46,7 @@ pub struct VmarChildOptions { parent: Vmar, size: usize, offset: usize, + align:usize, } impl VmarChildOptions { @@ -94,9 +102,9 @@ impl VmarChildOptions { /// 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 /// to overlap with any existing mapping, either. -pub struct VmarMapOptions { - parent: Vmar, - vmo: Vmo, +pub struct VmarMapOptions { + parent: Vmar, + vmo: Vmo, perms: VmPerms, vmo_offset: usize, size: usize, @@ -105,20 +113,21 @@ pub struct VmarMapOptions { can_overwrite: bool, } -impl VmarMapOptions<'a, R> { +impl VmarMapOptions { /// Creates a default set of options with the VMO and the memory access /// permissions. /// /// The VMO must have access rights that correspond to the memory /// access permissions. For example, if `perms` contains `VmPerm::Write`, /// then `vmo.rights()` should contain `Rights::WRITE`. - pub fn new(parent: Vmar, vmo: Vmo, perms: VmPerms) -> Self { + pub fn new(parent: Vmar, vmo: Vmo, perms: VmPerms) -> Self { + let size = vmo.size(); Self { parent, vmo, perms, vmo_offset: 0, - size: vmo.size(), + size, offset: None, align: PAGE_SIZE, can_overwrite: false, @@ -176,7 +185,7 @@ impl VmarMapOptions<'a, R> { /// /// If not set, the system will choose an offset automatically. pub fn offset(mut self, offset: usize) -> Self { - self.offset = offset; + self.offset = Some(offset); self } diff --git a/src/kxos-std/src/vm/vmar/static_cap.rs b/src/kxos-std/src/vm/vmar/static_cap.rs index a14b1ae6..2b7ff119 100644 --- a/src/kxos-std/src/vm/vmar/static_cap.rs +++ b/src/kxos-std/src/vm/vmar/static_cap.rs @@ -1,3 +1,14 @@ +use core::ops::Range; + +use alloc::sync::Arc; +use kxos_frame::{vm::VmIo, Error}; +use kxos_rights_proc::require; +use kxos_frame::prelude::Result; + +use crate::{rights::*, vm::vmo::Vmo}; + +use super::{Vmar, Vmar_, VmPerms, options::{VmarMapOptions, VmarChildOptions}}; + impl Vmar { /// Creates a root VMAR. /// @@ -5,7 +16,7 @@ impl Vmar { /// /// A root VMAR is initially given full access rights. pub fn new() -> Result { - let inner = Arc::new(Vmar_::new()); + let inner = Arc::new(Vmar_::new()?); let rights = R::new(); let new_self = Self(inner, rights); Ok(new_self) @@ -46,9 +57,10 @@ impl Vmar { /// Memory permissions may be changed through the `protect` method, /// which ensures that any updated memory permissions do not go beyond /// the access rights of the underlying VMOs. - pub fn new_map(&self, vmo: Vmo, perms: VmPerms) -> VmarMapOptions<'_, Rights> { - let dup_self = self.dup(); - VmarMapOptions::new(dup_self, vmo_ref) + #[require(R > Dup)] + pub fn new_map(&self, vmo: Vmo, perms: VmPerms) -> Result> { + let dup_self = self.dup()?; + Ok(VmarMapOptions::new(dup_self, vmo,perms)) } /// Creates a new child VMAR through a set of VMAR child options. @@ -71,9 +83,9 @@ impl Vmar { /// The new VMAR child will be of the same capability class and /// access rights as the parent. #[require(R > Dup)] - pub fn new_child(&self, size: usize) -> VmarChildOptions<'a, R> { - let dup_self = self.dup(); - VmarChildOptions::new(dup_self, size) + pub fn new_child(&self, size: usize) -> Result> { + let dup_self = self.dup()?; + Ok(VmarChildOptions::new(dup_self, size)) } /// Change the permissions of the memory mappings in the specified range. @@ -112,24 +124,49 @@ impl Vmar { /// As for children VMARs, they must be fully within the range. /// All children VMARs that fall within the range get their `destroy` methods /// called. - pub fn destroy(&self, range: &Range) -> Result<()> { + pub fn destroy(&self, range: Range) -> Result<()> { self.0.destroy(range) } + /// Duplicate the capability. + /// + /// # Access rights + /// + /// The method requires the Dup right. + #[require(R > Dup)] + pub fn dup(&self) -> Result { + todo!() + } + + /// Strict the access rights. + #[require(R > R1)] + pub fn restrict(mut self) -> Vmo { + todo!() + } + /// Returns the access 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 VmIo for Vmar { +impl VmIo for Vmar { 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) } fn write_bytes(&self, offset: usize, buf: &[u8]) -> Result<()> { - self.check_rights!(Rights::WRITE)?; + // self.check_rights!(Rights::WRITE)?; self.0.write(offset, buf) } } \ No newline at end of file diff --git a/src/kxos-std/src/vm/vmo/dyn_cap.rs b/src/kxos-std/src/vm/vmo/dyn_cap.rs index 15d8b974..6422e645 100644 --- a/src/kxos-std/src/vm/vmo/dyn_cap.rs +++ b/src/kxos-std/src/vm/vmo/dyn_cap.rs @@ -1,3 +1,12 @@ +use core::ops::Range; + +use kxos_frame::{vm::VmIo, Error}; +use kxos_frame::prelude::Result; + +use crate::rights::{Rights, TRights}; + +use super::{VmoChildOptions, options::{VmoSliceChild, VmoCowChild}, Vmo}; + impl Vmo { /// Creates a new slice VMO through a set of VMO child options. /// @@ -18,9 +27,9 @@ impl Vmo { /// /// The new VMO child will be of the same capability flavor as the parent; /// so are the access rights. - pub fn new_slice_child(&self, range: Range) -> VmoChildOptions<'_, Rights, VmoSliceChild> { + pub fn new_slice_child(&self, range: Range) -> Result> { 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. @@ -43,9 +52,9 @@ impl Vmo { /// 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 /// plus the Write right. - pub fn new_cow_child(&self, range: Range) -> VmoChildOptions<'_, Rights, VmoCowChild> { + pub fn new_cow_child(&self, range: Range) -> Result> { 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). @@ -117,7 +126,7 @@ impl Vmo { /// Converts to a static capability. pub fn to_static(self) -> Result> { - self.check_rights(R1::BITS)?; + self.check_rights(Rights::from_bits(R1::BITS).ok_or(Error::InvalidArgs)?)?; todo!() } @@ -125,16 +134,24 @@ impl Vmo { pub fn rights(&self) -> Rights { self.1 } + + pub fn check_rights(&self, rights: Rights) -> Result<()> { + if self.rights().contains(rights) { + Ok(()) + } else { + Err(Error::AccessDenied) + } + } } impl VmIo for Vmo { fn read_bytes(&self, offset: usize, buf: &mut [u8]) -> Result<()> { 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<()> { self.check_rights(Rights::WRITE)?; - self.0.write(offset, buf) + self.0.write_bytes(offset, buf) } } \ No newline at end of file diff --git a/src/kxos-std/src/vm/vmo/mod.rs b/src/kxos-std/src/vm/vmo/mod.rs index cf50d749..03911bd9 100644 --- a/src/kxos-std/src/vm/vmo/mod.rs +++ b/src/kxos-std/src/vm/vmo/mod.rs @@ -1,8 +1,11 @@ //! Virtual Memory Objects (VMOs). -use kx_frame::vm::VmIo; +use core::ops::Range; -use crate::rights::{Rights, TRights}; +use kxos_frame::{prelude::Result, vm::Paddr, Error}; +use crate::rights::Rights; +use alloc::sync::Arc; +use bitflags::bitflags; mod static_cap; mod dyn_cap; @@ -11,6 +14,9 @@ mod pager; pub use options::{VmoOptions, VmoChildOptions}; pub use pager::Pager; +use spin::Mutex; + + /// Virtual Memory Objects (VMOs) are a type of capability that represents a /// range of memory pages. @@ -73,16 +79,16 @@ bitflags! { /// VMO flags. pub struct VmoFlags: u32 { /// 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 /// pages. /// /// To ensure the memory pages to be contiguous, these pages /// 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 /// Direct Memory Access (DMA) by devices. - const DMA: u32 = 1 << 2; + const DMA = 1 << 2; } } @@ -126,7 +132,7 @@ impl Vmo_ { } pub fn size(&self) -> usize { - self.0.size() + todo!() } pub fn resize(&self, new_size: usize) -> Result<()> { @@ -160,11 +166,4 @@ impl Vmo { self.0.flags() } - fn check_rights(&self, rights: Rights) -> Result<()> { - if self.rights().contains(rights) { - Ok(()) - } else { - Err(Error::AccessDenied) - } - } } \ No newline at end of file diff --git a/src/kxos-std/src/vm/vmo/options.rs b/src/kxos-std/src/vm/vmo/options.rs index 78cd7ccb..9d25173b 100644 --- a/src/kxos-std/src/vm/vmo/options.rs +++ b/src/kxos-std/src/vm/vmo/options.rs @@ -1,5 +1,17 @@ //! Options for allocating root and child VMOs. +use core::marker::PhantomData; +use core::ops::Range; + +use alloc::sync::Arc; +use kxos_frame::vm::Paddr; +use kxos_frame::prelude::Result; +use kxos_rights_proc::require; + +use crate::rights::{Dup,TRights,Rights}; + +use super::{Vmo, VmoFlags, Pager}; + /// Options for allocating a root VMO. /// /// # Examples @@ -38,7 +50,8 @@ pub struct VmoOptions { size: usize, paddr: Option, flags: VmoFlags, - supplier: Option>, + rights: R, + // supplier: Option>, } impl VmoOptions { @@ -81,7 +94,7 @@ impl VmoOptions { /// # Access rights /// /// The VMO is initially assigned full access rights. - pub fn alloc(mut self) -> Result> { + pub fn alloc(mut self) -> Result> { todo!() } } @@ -185,10 +198,10 @@ pub struct VmoChildOptions { range: Range, flags: VmoFlags, // Specifies whether the child is a slice or a COW - child_marker: PhantomData, + marker: PhantomData, } -impl VmoChildOptions { +impl VmoChildOptions { /// 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 @@ -199,9 +212,30 @@ impl VmoChildOptions { #[require(R > Dup)] pub fn new_slice(parent: Vmo, range: Range) -> Self { Self { + flags: parent.flags() & Self::PARENT_FLAGS_MASK, + parent, + range, + marker: PhantomData, + } + } +} + +impl VmoChildOptions { + /// 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, range: Range) -> 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, range, - flags: parent.flags & Self::PARENT_FLAGS_MASK, marker: PhantomData, } } @@ -219,9 +253,9 @@ impl VmoChildOptions { /// Any pages that are beyond the parent's range are initially all zeros. pub fn new_cow(parent: Vmo, range: Range) -> Self { Self { + flags: parent.flags() & Self::PARENT_FLAGS_MASK, parent, range, - flags: parent.flags & Self::PARENT_FLAGS_MASK, marker: PhantomData, } } @@ -229,10 +263,9 @@ impl VmoChildOptions { impl VmoChildOptions { /// Flags that a VMO child inherits from its parent. - pub const PARENT_FLAGS_MASK: VmoFlags = VmoFlags::CONTIGUOUS.bits | - VmoFlags::DMA.bits; + pub const PARENT_FLAGS_MASK: VmoFlags = VmoFlags::from_bits(VmoFlags::CONTIGUOUS.bits | VmoFlags::DMA.bits).unwrap(); /// 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. /// @@ -248,7 +281,7 @@ impl VmoChildOptions { } } -impl<'a, C> VmoChildOptions<'a, Rights, C> { +impl VmoChildOptions { /// Allocates the child VMO. /// /// # Access rights @@ -259,7 +292,7 @@ impl<'a, C> VmoChildOptions<'a, Rights, C> { } } -impl<'a, R: TRights> VmoChildOptions<'a, R, VmoSliceChild> { +impl VmoChildOptions { /// Allocates the child VMO. /// /// # Access rights @@ -270,23 +303,35 @@ impl<'a, R: TRights> VmoChildOptions<'a, R, VmoSliceChild> { } } -impl<'a, R: TRights> VmoChildOptions<'a, R, VmoCowChild> { +impl VmoChildOptions { /// Allocates the child VMO. /// /// # Access rights /// /// The child VMO is initially assigned all the parent's access rights /// plus the Write right. - pub fn alloc(mut self) -> Result> + pub fn alloc(mut self) -> Result> 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 + // TRightsExtend { todo!() } + + // original: + // pub fn alloc(mut self) -> Result> + // 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 + // { + // todo!() + // } } /// A type to specify the "type" of a child, which is either a slice or a COW. @@ -295,9 +340,9 @@ pub trait VmoChildType {} /// A type to mark a child is slice. #[derive(Copy, Clone, Debug)] pub struct VmoSliceChild; -impl VmoChildType for VmoSliceChild {}; +impl VmoChildType for VmoSliceChild {} /// A type to mark a child is COW. #[derive(Copy, Clone, Debug)] pub struct VmoCowChild; -impl VmoChildType for VmoCowChild {}; +impl VmoChildType for VmoCowChild {} diff --git a/src/kxos-std/src/vm/vmo/pager.rs b/src/kxos-std/src/vm/vmo/pager.rs index f40b3b6c..46b93fa3 100644 --- a/src/kxos-std/src/vm/vmo/pager.rs +++ b/src/kxos-std/src/vm/vmo/pager.rs @@ -1,3 +1,6 @@ +use kxos_frame::vm::VmFrame; +use kxos_frame::prelude::Result; + /// Pagers provide frame to a VMO. /// /// A `Pager` object can be attached to a VMO. Whenever the diff --git a/src/kxos-std/src/vm/vmo/static_cap.rs b/src/kxos-std/src/vm/vmo/static_cap.rs index 9276487a..826874b7 100644 --- a/src/kxos-std/src/vm/vmo/static_cap.rs +++ b/src/kxos-std/src/vm/vmo/static_cap.rs @@ -1,3 +1,13 @@ +use core::ops::Range; + +use kxos_frame::{vm::VmIo, Error}; +use kxos_frame::prelude::Result; +use kxos_rights_proc::require; + +use crate::rights::*; + +use super::{Vmo, VmoChildOptions, options::{VmoSliceChild, VmoCowChild}}; + impl Vmo { /// Creates a new slice VMO through a set of VMO child options. /// @@ -19,9 +29,9 @@ impl Vmo { /// The new VMO child will be of the same capability flavor as the parent; /// so are the access rights. #[require(R > Dup)] - pub fn new_slice_child(&self, range: Range) -> VmoChildOptions<'_, R, VmoSliceChild> { - let dup_self = self.dup(); - VmoChildOptions::new_slice(dup_self, range) + pub fn new_slice_child(&self, range: Range) -> Result> { + let dup_self = self.dup()?; + Ok(VmoChildOptions::new_slice(dup_self, range)) } /// Creates a new COW VMO through a set of VMO child options. @@ -45,9 +55,9 @@ impl Vmo { /// The child will be given the access rights of the parent /// plus the Write right. #[require(R > Dup)] - pub fn new_cow_child(&self, range: Range) -> VmoChildOptions<'_, R, VmoCowChild> { - let dup_self = self.dup(); - VmoChildOptions::new_cow(dup_self, range) + pub fn new_cow_child(&self, range: Range) -> Result> { + let dup_self = self.dup()?; + Ok(VmoChildOptions::new_cow(dup_self, range)) } /// Commit the pages specified in the range (in bytes). @@ -102,11 +112,6 @@ impl Vmo { self.0.clear(range) } - /// Returns the size of the VMO in bytes. - pub fn size(&self) -> usize { - self.0.size() - } - /// Duplicate the capability. /// /// # Access rights @@ -124,13 +129,21 @@ impl Vmo { } /// Converts to a dynamic capability. - pub fn to_dyn(self) -> Vmo { + pub fn to_dyn(self) -> Vmo { todo!() } /// Returns the access 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) + } } } diff --git a/src/kxos-typeflags-util/src/bool.rs b/src/kxos-typeflags-util/src/bool.rs index d685a766..dc9743bc 100644 --- a/src/kxos-typeflags-util/src/bool.rs +++ b/src/kxos-typeflags-util/src/bool.rs @@ -1,8 +1,9 @@ //! Type level bools -pub use std::ops::BitAnd as And; -pub use std::ops::BitOr as Or; -pub use std::ops::Not; +pub use core::ops::BitAnd as And; +pub use core::ops::BitOr as Or; +pub use core::ops::Not; +use core::unimplemented; pub trait Bool {} diff --git a/src/kxos-typeflags-util/src/lib.rs b/src/kxos-typeflags-util/src/lib.rs index 9d7b6400..8df37355 100644 --- a/src/kxos-typeflags-util/src/lib.rs +++ b/src/kxos-typeflags-util/src/lib.rs @@ -2,7 +2,7 @@ //! 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. //! When use kxos-typeflags or kxos-rights-poc, this crate should also be added as a dependency. - +#![no_std] pub mod assert; pub mod bool; pub mod if_; diff --git a/src/kxos-typeflags-util/src/set.rs b/src/kxos-typeflags-util/src/set.rs index d8fae0a6..bd89bed6 100644 --- a/src/kxos-typeflags-util/src/set.rs +++ b/src/kxos-typeflags-util/src/set.rs @@ -1,13 +1,13 @@ //! Common types and traits to deal with type-level sets -use std::marker::PhantomData; +use core::marker::PhantomData; use crate::{ if_::{If, IfOp}, 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. pub trait Set {} diff --git a/src/kxos-typeflags/src/type_flag.rs b/src/kxos-typeflags/src/type_flag.rs index b9a0d321..6516c503 100644 --- a/src/kxos-typeflags/src/type_flag.rs +++ b/src/kxos-typeflags/src/type_flag.rs @@ -65,11 +65,12 @@ impl TypeFlagDef { let ident = self.ident.clone(); let type_ = self.type_.clone(); quote!( - #vis trait #ident { + #vis trait #ident : Sync + Send{ const BITS: #type_; fn new() -> Self; } + ) } From 40cbd93ae8b65ad3262e8ee13f8cb2e135db2086 Mon Sep 17 00:00:00 2001 From: Yuke Peng Date: Thu, 10 Nov 2022 18:14:42 -0800 Subject: [PATCH 4/4] format files --- src/kxos-frame-pod-derive/src/lib.rs | 11 +- src/kxos-frame/src/device/mod.rs | 6 +- src/kxos-frame/src/device/pic.rs | 26 ++-- src/kxos-frame/src/timer.rs | 75 +++++++----- src/kxos-frame/src/trap/handler.rs | 2 +- src/kxos-pci/src/msix.rs | 2 +- src/kxos-std/src/driver/pci/virtio/block.rs | 10 +- src/kxos-std/src/lib.rs | 2 +- src/kxos-std/src/rights.rs | 20 ++- src/kxos-std/src/vm/mod.rs | 10 +- src/kxos-std/src/vm/vmar/dyn_cap.rs | 74 +++++------ src/kxos-std/src/vm/vmar/mod.rs | 44 ++++--- src/kxos-std/src/vm/vmar/options.rs | 84 ++++++------- src/kxos-std/src/vm/vmar/static_cap.rs | 78 ++++++------ src/kxos-std/src/vm/vmo/dyn_cap.rs | 85 +++++++------ src/kxos-std/src/vm/vmo/mod.rs | 64 +++++----- src/kxos-std/src/vm/vmo/options.rs | 128 ++++++++++---------- src/kxos-std/src/vm/vmo/pager.rs | 42 +++---- src/kxos-std/src/vm/vmo/static_cap.rs | 80 ++++++------ src/kxos-virtio/src/block.rs | 8 +- src/kxos-virtio/src/lib.rs | 5 +- src/kxos-virtio/src/queue.rs | 10 +- src/tests/timer_test.rs | 10 +- 23 files changed, 450 insertions(+), 426 deletions(-) diff --git a/src/kxos-frame-pod-derive/src/lib.rs b/src/kxos-frame-pod-derive/src/lib.rs index 17769688..80a18249 100644 --- a/src/kxos-frame-pod-derive/src/lib.rs +++ b/src/kxos-frame-pod-derive/src/lib.rs @@ -1,6 +1,9 @@ use proc_macro2::TokenStream; use quote::quote; -use syn::{parse_macro_input, Data, DataStruct, DeriveInput, Fields, DataEnum, punctuated::Punctuated, token::Comma, Field}; +use syn::{ + parse_macro_input, punctuated::Punctuated, token::Comma, Data, DataEnum, DataStruct, + DeriveInput, Field, Fields, +}; #[proc_macro_derive(Pod)] pub fn derive_pod(input_token: proc_macro::TokenStream) -> proc_macro::TokenStream { @@ -16,9 +19,9 @@ fn expand_derive_pod(input: DeriveInput) -> TokenStream { Fields::Unnamed(fields_unnamed) => fields_unnamed.unnamed, Fields::Unit => Punctuated::new(), }, - Data::Enum(DataEnum{variants,..})=>{ - let mut fields : Punctuated = Punctuated::new(); - for var in variants{ + Data::Enum(DataEnum { variants, .. }) => { + let mut fields: Punctuated = 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, diff --git a/src/kxos-frame/src/device/mod.rs b/src/kxos-frame/src/device/mod.rs index e0337b7b..d8a0dbfa 100644 --- a/src/kxos-frame/src/device/mod.rs +++ b/src/kxos-frame/src/device/mod.rs @@ -3,12 +3,12 @@ pub mod framebuffer; mod io_port; pub mod pci; -pub mod serial; mod pic; +pub mod serial; -pub use pic::{TimerCallback, TIMER_FREQ}; -pub(crate) use pic::{add_timeout_list,TICK}; 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) { framebuffer::init(framebuffer); diff --git a/src/kxos-frame/src/device/pic.rs b/src/kxos-frame/src/device/pic.rs index c55282cb..3c705859 100644 --- a/src/kxos-frame/src/device/pic.rs +++ b/src/kxos-frame/src/device/pic.rs @@ -78,7 +78,7 @@ fn timer_callback(trap_frame: &TrapFrame) { TICK += 1; } let timeout_list = TIMEOUT_LIST.get(); - let mut callbacks : Vec>= Vec::new(); + let mut callbacks: Vec> = Vec::new(); while let Some(t) = timeout_list.peek() { if t.expire_ms <= current_ms { callbacks.push(timeout_list.pop().unwrap()); @@ -86,8 +86,8 @@ fn timer_callback(trap_frame: &TrapFrame) { break; } } - for callback in callbacks{ - if callback.is_enable(){ + for callback in callbacks { + if callback.is_enable() { callback.callback.call((&callback,)); } } @@ -95,7 +95,7 @@ fn timer_callback(trap_frame: &TrapFrame) { } lazy_static! { - static ref TIMEOUT_LIST: Cell>> = Cell::new(BinaryHeap::new()) ; + static ref TIMEOUT_LIST: Cell>> = Cell::new(BinaryHeap::new()); } pub struct TimerCallback { @@ -115,7 +115,7 @@ impl TimerCallback { expire_ms: timeout_ms, data, callback, - enable:Cell::new(true), + enable: Cell::new(true), } } @@ -124,19 +124,18 @@ impl TimerCallback { } /// disable this timeout - pub fn disable(&self){ + pub fn disable(&self) { *self.enable.get() = false; } /// enable this timeout - pub fn enable(&self){ + pub fn enable(&self) { *self.enable.get() = true; } - pub fn is_enable(&self) -> bool{ + pub fn is_enable(&self) -> bool { *self.enable } - } impl PartialEq for TimerCallback { @@ -166,15 +165,10 @@ impl Ord for TimerCallback { pub fn add_timeout_list(timeout: u64, data: T, callback: F) -> Arc where F: Fn(&TimerCallback) + Send + Sync + 'static, - T: Any + Send + Sync, - + T: Any + Send + Sync, { unsafe { - let timer_callback = TimerCallback::new( - TICK + timeout, - Arc::new(data), - Box::new(callback), - ); + 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 diff --git a/src/kxos-frame/src/timer.rs b/src/kxos-frame/src/timer.rs index ba9a3820..a30d0332 100644 --- a/src/kxos-frame/src/timer.rs +++ b/src/kxos-frame/src/timer.rs @@ -1,8 +1,11 @@ //! Timer. -use crate::{prelude::*, device::{TimerCallback, TICK,TIMER_FREQ}}; -use spin::Mutex; +use crate::{ + device::{TimerCallback, TICK, TIMER_FREQ}, + prelude::*, +}; use core::time::Duration; +use spin::Mutex; /// A timer invokes a callback function after a specified span of time elapsed. /// @@ -13,57 +16,67 @@ use core::time::Duration; /// Timers are one-shot. If the time is out, one has to set the timer again /// in order to trigger the callback again. pub struct Timer { - function: Arc)+Send+Sync>, + function: Arc) + Send + Sync>, inner: Mutex, } #[derive(Default)] -struct TimerInner{ +struct TimerInner { start_tick: u64, - timeout_tick:u64, - timer_callback:Option>, + timeout_tick: u64, + timer_callback: Option>, } -fn timer_callback(callback:&TimerCallback){ +fn timer_callback(callback: &TimerCallback) { let data = callback.data(); - if data.is::>(){ + if data.is::>() { let timer = data.downcast_ref::>().unwrap(); timer.function.call((timer.clone(),)); - }else{ + } else { panic!("the timer callback is not Timer structure"); } } -const NANOS_DIVIDE : u64 = 1_000_000_000/TIMER_FREQ; +const NANOS_DIVIDE: u64 = 1_000_000_000 / TIMER_FREQ; impl Timer { /// Creates a new instance, given a callback function. pub fn new(f: F) -> Result> where - F: Fn(Arc) +Send+Sync+'static, + F: Fn(Arc) + Send + Sync + 'static, { - Ok(Arc::new(Self { function: Arc::new(f),inner:Mutex::new(TimerInner::default()) })) + Ok(Arc::new(Self { + function: Arc::new(f), + inner: Mutex::new(TimerInner::default()), + })) } /// Set a timeout value. /// /// If a timeout value is already set, the timeout value will be refreshed. - /// - pub fn set(self : Arc, timeout: Duration) { + /// + pub fn set(self: Arc, timeout: Duration) { let mut lock = self.inner.lock(); - match &lock.timer_callback{ + match &lock.timer_callback { Some(callback) => { callback.disable(); - }, - None => {}, + } + 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{ + 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.timeout_tick = TICK + tick_count; } - lock.timer_callback = Some(crate::device::add_timeout_list(tick_count, self.clone(), timer_callback)); - + lock.timer_callback = Some(crate::device::add_timeout_list( + tick_count, + self.clone(), + timer_callback, + )); } /// Returns the remaining timeout value. @@ -72,22 +85,22 @@ impl Timer { pub fn remain(&self) -> Duration { let lock = self.inner.lock(); let tick_remain; - unsafe{ - tick_remain = lock.timeout_tick as i64-TICK as i64; + 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; + 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) + Duration::new(second_count, (remain_count * NANOS_DIVIDE) as u32) } } /// Clear the timeout value. pub fn clear(&self) { let mut lock = self.inner.lock(); - if let Some(callback) = &lock.timer_callback{ + if let Some(callback) = &lock.timer_callback { callback.disable(); } lock.timeout_tick = 0; diff --git a/src/kxos-frame/src/trap/handler.rs b/src/kxos-frame/src/trap/handler.rs index b3d4cabf..95c67ca1 100644 --- a/src/kxos-frame/src/trap/handler.rs +++ b/src/kxos-frame/src/trap/handler.rs @@ -41,7 +41,7 @@ pub(crate) extern "C" fn trap_handler(f: &mut TrapFrame) { } } } else { - if is_cpu_fault(f){ + if is_cpu_fault(f) { panic!("cannot handle kernel cpu fault now"); } let irq_line = IRQ_LIST.get(f.id as usize).unwrap(); diff --git a/src/kxos-pci/src/msix.rs b/src/kxos-pci/src/msix.rs index 8fc03b60..d7accb32 100644 --- a/src/kxos-pci/src/msix.rs +++ b/src/kxos-pci/src/msix.rs @@ -22,7 +22,7 @@ pub struct MSIXEntry { pub irq_handle: IrqAllocateHandle, } -#[derive(Debug, Default, Copy, Clone, PartialEq, Eq,Pod)] +#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, Pod)] #[repr(C)] pub struct MSIXTableEntry { pub msg_addr: u32, diff --git a/src/kxos-std/src/driver/pci/virtio/block.rs b/src/kxos-std/src/driver/pci/virtio/block.rs index bd2fe26c..5a26112c 100644 --- a/src/kxos-std/src/driver/pci/virtio/block.rs +++ b/src/kxos-std/src/driver/pci/virtio/block.rs @@ -4,9 +4,9 @@ use crate::process::Process; use alloc::sync::Arc; use alloc::vec::Vec; use kxos_frame::info; +use kxos_frame_pod_derive::Pod; use kxos_pci::PCIDevice; use kxos_virtio::PCIVirtioDevice; -use kxos_frame_pod_derive::Pod; use lazy_static::lazy_static; use spin::mutex::Mutex; @@ -19,7 +19,7 @@ pub struct VirtioBlockDevice { } #[repr(C)] -#[derive(Debug, Copy, Clone,Pod)] +#[derive(Debug, Copy, Clone, Pod)] pub struct BlkReq { pub type_: ReqType, pub reserved: u32, @@ -28,13 +28,13 @@ pub struct BlkReq { /// Response of a VirtIOBlk request. #[repr(C)] -#[derive(Debug, Copy, Clone,Pod)] +#[derive(Debug, Copy, Clone, Pod)] pub struct BlkResp { pub status: RespStatus, } #[repr(u32)] -#[derive(Debug, Copy, Clone,Pod)] +#[derive(Debug, Copy, Clone, Pod)] pub enum ReqType { In = 0, Out = 1, @@ -44,7 +44,7 @@ pub enum ReqType { } #[repr(u8)] -#[derive(Debug, Eq, PartialEq, Copy, Clone,Pod)] +#[derive(Debug, Eq, PartialEq, Copy, Clone, Pod)] pub enum RespStatus { /// Ok. Ok = 0, diff --git a/src/kxos-std/src/lib.rs b/src/kxos-std/src/lib.rs index aa79ba43..dd1f109d 100644 --- a/src/kxos-std/src/lib.rs +++ b/src/kxos-std/src/lib.rs @@ -23,11 +23,11 @@ pub mod fs; mod memory; pub mod prelude; mod process; +pub mod rights; pub mod syscall; mod user_apps; mod util; pub mod vm; -pub mod rights; #[macro_use] extern crate kxos_frame_pod_derive; diff --git a/src/kxos-std/src/rights.rs b/src/kxos-std/src/rights.rs index cbb51f35..ff12228b 100644 --- a/src/kxos-std/src/rights.rs +++ b/src/kxos-std/src/rights.rs @@ -1,11 +1,11 @@ -use kxos_typeflags::type_flags; use bitflags::bitflags; +use kxos_typeflags::type_flags; bitflags! { /// Value-based access rights. - /// + /// /// These access rights are provided to cover a wide range of use cases. - /// The access rights' semantics and how they would restrict the behaviors + /// The access rights' semantics and how they would restrict the behaviors /// of a capability are decided by the capability's designer. /// Here, we give some sensible semantics for each access right. pub struct Rights: u32 { @@ -24,10 +24,10 @@ bitflags! { } } /// Type-based access rights. -/// +/// /// Similar to value-based access rights (`Rights`), but represented in /// types. -/// +/// /// pub trait TRights: u32 { /// /// Allows duplicating a capability. /// struct Dup: u32 = Rights::DUP; @@ -42,7 +42,7 @@ bitflags! { /// /// Allows sending notifications or signals. /// struct Signal: u32 = Rights::SIGNAL; /// } -/// +/// type_flags! { pub trait TRights: u32 { pub struct Dup = 1 <<0; @@ -54,10 +54,4 @@ type_flags! { } /// The full set of access rights. -pub type Full = TRights![ - Dup, - Read, - Write, - Exec, - Signal -]; +pub type Full = TRights![Dup, Read, Write, Exec, Signal]; diff --git a/src/kxos-std/src/vm/mod.rs b/src/kxos-std/src/vm/mod.rs index 7d6a2e57..440c45bc 100644 --- a/src/kxos-std/src/vm/mod.rs +++ b/src/kxos-std/src/vm/mod.rs @@ -1,18 +1,18 @@ //! Virtual memory (VM). -//! +//! //! There are two primary VM abstractions: //! * Virtual Memory Address Regions (VMARs) a type of capability that manages //! 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. -//! +//! //! The concepts of VMARs and VMOs are originally introduced by //! [Zircon](https://fuchsia.dev/fuchsia-src/reference/kernel_objects/vm_object). //! As capabilities, the two abstractions are aligned with our goal -//! of everything-is-a-capability, although their specifications and +//! of everything-is-a-capability, although their specifications and //! implementations in C/C++ cannot apply directly to KxOS. //! In KxOS, VMARs and VMOs, as well as other capabilities, are implemented //! as zero-cost capabilities. mod vmar; -mod vmo; \ No newline at end of file +mod vmo; diff --git a/src/kxos-std/src/vm/vmar/dyn_cap.rs b/src/kxos-std/src/vm/vmar/dyn_cap.rs index 1d7d77e0..7d295a27 100644 --- a/src/kxos-std/src/vm/vmar/dyn_cap.rs +++ b/src/kxos-std/src/vm/vmar/dyn_cap.rs @@ -1,12 +1,15 @@ use core::ops::Range; use alloc::sync::Arc; -use kxos_frame::{vm::VmIo, Error}; use kxos_frame::prelude::Result; +use kxos_frame::{vm::VmIo, Error}; use crate::{rights::Rights, vm::vmo::Vmo}; -use super::{Vmar, VmPerms, options::{VmarChildOptions, VmarMapOptions}, Vmar_}; +use super::{ + options::{VmarChildOptions, VmarMapOptions}, + VmPerms, Vmar, Vmar_, +}; impl Vmar { /// Creates a root VMAR. @@ -18,13 +21,13 @@ impl Vmar { } /// Maps the given VMO into the VMAR through a set of VMAR mapping options. - /// + /// /// # Example - /// + /// /// ``` /// use kxos_std::prelude::*; /// use kxos_std::vm::{PAGE_SIZE, Vmar, VmoOptions}; - /// + /// /// let vmar = Vmar::new().unwrap(); /// let vmo = VmoOptions::new(PAGE_SIZE).alloc().unwrap(); /// let target_vaddr = 0x1234000; @@ -37,44 +40,48 @@ impl Vmar { /// .unwrap(); /// assert!(real_vaddr == target_vaddr); /// ``` - /// + /// /// For more details on the available options, see `VmarMapOptions`. - /// + /// /// # Access rights - /// + /// /// This method requires the following access rights: - /// 1. The VMAR contains the rights corresponding to the memory permissions of - /// the mapping. For example, if `perms` contains `VmPerm::WRITE`, + /// 1. The VMAR contains the rights corresponding to the memory permissions of + /// the mapping. For example, if `perms` contains `VmPerm::WRITE`, /// then the VMAR must have the Write right. - /// 2. Similarly, the VMO contains the rights corresponding to the memory + /// 2. Similarly, the VMO contains the rights corresponding to the memory /// permissions of the mapping. - /// + /// /// Memory permissions may be changed through the `protect` method, /// which ensures that any updated memory permissions do not go beyond /// the access rights of the underlying VMOs. - pub fn new_map(&self, vmo: Vmo, perms: VmPerms) -> Result> { + pub fn new_map( + &self, + vmo: Vmo, + perms: VmPerms, + ) -> Result> { let dup_self = self.dup()?; Ok(VmarMapOptions::new(dup_self, vmo, perms)) } /// Creates a new child VMAR through a set of VMAR child options. - /// + /// /// # Example - /// + /// /// ``` /// let parent = Vmar::new().unwrap(); /// let child_size = 10 * PAGE_SIZE; /// let child = parent.new_child(child_size).alloc().unwrap(); /// assert!(child.size() == child_size); - /// ``` - /// + /// ``` + /// /// For more details on the available options, see `VmarChildOptions`. - /// + /// /// # Access rights - /// + /// /// This method requires the Dup right. - /// - /// 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. pub fn new_child(&self, size: usize) -> Result> { let dup_self = self.dup()?; @@ -82,25 +89,25 @@ impl Vmar { } /// Change the permissions of the memory mappings in the specified range. - /// + /// /// The range's start and end addresses must be page-aligned. /// Also, the range must be completely mapped. - /// + /// /// # Access rights - /// + /// /// The VMAR must have the rights corresponding to the specified memory /// permissions. - /// + /// /// The mappings overlapped with the specified range must be backed by /// VMOs whose rights contain the rights corresponding to the specified - /// memory permissions. + /// memory permissions. pub fn protect(&self, perms: VmPerms, range: Range) -> Result<()> { self.check_rights(perms.into())?; self.0.protect(perms, range) } /// Destroy a VMAR, including all its mappings and children VMARs. - /// + /// /// After being destroyed, the VMAR becomes useless and returns errors /// for most of its methods. pub fn destroy_all(&self) -> Result<()> { @@ -109,10 +116,10 @@ impl Vmar { /// Destroy all mappings and children VMARs that fall within the specified /// range in bytes. - /// + /// /// The range's start and end addresses must be page-aligned. - /// - /// Mappings may fall partially within the range; only the overlapped + /// + /// Mappings may fall partially within the range; only the overlapped /// portions of the mappings are unmapped. /// As for children VMARs, they must be fully within the range. /// All children VMARs that fall within the range get their `destroy` methods @@ -122,10 +129,10 @@ impl Vmar { } /// Duplicates the capability. - /// + /// /// # Access rights /// - /// The method requires the Dup right. + /// The method requires the Dup right. pub fn dup(&self) -> Result { self.check_rights(Rights::DUP)?; todo!() @@ -143,7 +150,6 @@ impl Vmar { Err(Error::AccessDenied) } } - } impl VmIo for Vmar { @@ -156,4 +162,4 @@ impl VmIo for Vmar { self.check_rights(Rights::WRITE)?; self.0.write(offset, buf) } -} \ No newline at end of file +} diff --git a/src/kxos-std/src/vm/vmar/mod.rs b/src/kxos-std/src/vm/vmar/mod.rs index d5038dc5..5a4be03a 100644 --- a/src/kxos-std/src/vm/vmar/mod.rs +++ b/src/kxos-std/src/vm/vmar/mod.rs @@ -1,46 +1,46 @@ //! Virtual Memory Address Regions (VMARs). -mod static_cap; mod dyn_cap; mod options; +mod static_cap; -use core::ops::Range; -use kxos_frame::vm::VmSpace; -use kxos_frame::vm::Vaddr; -use spin::Mutex; -use alloc::sync::Arc; -use kxos_frame::prelude::Result; -use kxos_frame::Error; 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 /// user address spaces. -/// +/// /// # Capabilities -/// -/// As a capability, each VMAR is associated with a set of access rights, +/// +/// As a capability, each VMAR is associated with a set of access rights, /// whose semantics are explained below. -/// +/// /// The semantics of each access rights for VMARs are described below: -/// * The Dup right allows duplicating a VMAR and creating children out of +/// * The Dup right allows duplicating a VMAR and creating children out of /// a VMAR. -/// * The Read, Write, Exec rights allow creating memory mappings with +/// * The Read, Write, Exec rights allow creating memory mappings with /// readable, writable, and executable access permissions, respectively. /// * The Read and Write rights allow the VMAR to be read from and written to /// directly. -/// +/// /// VMARs are implemented with two flavors of capabilities: /// the dynamic one (`Vmar`) and the static one (`Vmar). -/// +/// /// # Implementation -/// -/// `Vmar` provides high-level APIs for address space management by wrapping +/// +/// `Vmar` provides high-level APIs for address space management by wrapping /// around its low-level counterpart `kx_frame::vm::VmFrames`. /// Compared with `VmFrames`, -/// `Vmar` is easier to use (by offering more powerful APIs) and +/// `Vmar` is easier to use (by offering more powerful APIs) and /// harder to misuse (thanks to its nature of being capability). -/// +/// pub struct Vmar(Arc, R); // TODO: how page faults can be delivered to and handled by the current VMAR. @@ -86,13 +86,11 @@ impl Vmar_ { impl Vmar { /// The base address, i.e., the offset relative to the root VMAR. - /// + /// /// The base address of a root VMAR is zero. pub fn base(&self) -> Vaddr { self.0.base } - - } bitflags! { diff --git a/src/kxos-std/src/vm/vmar/options.rs b/src/kxos-std/src/vm/vmar/options.rs index e48e2e5d..20a83b33 100644 --- a/src/kxos-std/src/vm/vmar/options.rs +++ b/src/kxos-std/src/vm/vmar/options.rs @@ -1,23 +1,23 @@ //! Options for allocating child VMARs and creating mappings. -use kxos_frame::{config::PAGE_SIZE, vm::Vaddr}; use kxos_frame::prelude::Result; +use kxos_frame::{config::PAGE_SIZE, vm::Vaddr}; use crate::vm::vmo::Vmo; -use super::{Vmar, VmPerms}; +use super::{VmPerms, Vmar}; /// Options for allocating a child VMAR, which must not overlap with any /// existing mappings or child VMARs. -/// +/// /// # Examples -/// +/// /// A child VMAR created from a parent VMAR of _dynamic_ capability is also a /// _dynamic_ capability. /// ``` /// use kxo_std::vm::{PAGE_SIZE, Vmar}; /// -/// let parent_vmar = Vmar::new(); +/// let parent_vmar = Vmar::new(); /// let child_size = 10 * PAGE_SIZE; /// let child_vmar = parent_vmar /// .new_child(child_size) @@ -26,14 +26,14 @@ use super::{Vmar, VmPerms}; /// assert!(child_vmar.rights() == parent_vmo.rights()); /// assert!(child_vmar.size() == child_size); /// ``` -/// +/// /// A child VMO created from a parent VMO of _static_ capability is also a /// _static_ capability. /// ``` /// use kxos_std::prelude::*; /// use kxos_std::vm::{PAGE_SIZE, Vmar}; -/// -/// let parent_vmar: Vmar = Vmar::new(); +/// +/// let parent_vmar: Vmar = Vmar::new(); /// let child_size = 10 * PAGE_SIZE; /// let child_vmar = parent_vmar /// .new_child(child_size) @@ -46,13 +46,13 @@ pub struct VmarChildOptions { parent: Vmar, size: usize, offset: usize, - align:usize, + align: usize, } impl VmarChildOptions { /// Creates a default set of options with the specified size of the VMAR /// (in bytes). - /// + /// /// The size of the VMAR will be rounded up to align with the page size. pub fn new(parent: Vmar, size: usize) -> Self { Self { @@ -64,9 +64,9 @@ impl VmarChildOptions { } /// Set the alignment of the child VMAR. - /// + /// /// By default, the alignment is the page size. - /// + /// /// The alignment must be a power of two and a multiple of the page size. pub fn align(mut self, align: usize) -> Self { todo!() @@ -75,34 +75,34 @@ impl VmarChildOptions { /// Sets the offset of the child VMAR. /// /// If not set, the system will choose an offset automatically. - /// + /// /// The offset must satisfy the alignment requirement. /// Also, the child VMAR's range `[offset, offset + size)` must be within /// the VMAR. - /// - /// If not specified, - /// + /// + /// If not specified, + /// /// The offset must be page-aligned. pub fn offset(mut self, offset: usize) -> Self { todo!() } /// Allocates the child VMAR according to the specified options. - /// - /// The new child VMAR - /// + /// + /// The new child VMAR + /// /// # Access rights - /// + /// /// The child VMAR is initially assigned all the parent's access rights. pub fn alloc(mut self) -> Result> { todo!() } } -/// 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 +/// 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 /// to overlap with any existing mapping, either. -pub struct VmarMapOptions { +pub struct VmarMapOptions { parent: Vmar, vmo: Vmo, perms: VmPerms, @@ -113,10 +113,10 @@ pub struct VmarMapOptions { can_overwrite: bool, } -impl VmarMapOptions { - /// Creates a default set of options with the VMO and the memory access - /// permissions. - /// +impl VmarMapOptions { + /// Creates a default set of options with the VMO and the memory access + /// permissions. + /// /// The VMO must have access rights that correspond to the memory /// access permissions. For example, if `perms` contains `VmPerm::Write`, /// then `vmo.rights()` should contain `Rights::WRITE`. @@ -136,9 +136,9 @@ impl VmarMapOptions { /// Sets the offset of the first memory page in the VMO that is to be /// mapped into the VMAR. - /// + /// /// The offset must be page-aligned and within the VMO. - /// + /// /// The default value is zero. pub fn vmo_offset(mut self, offset: usize) -> Self { self.vmo_offset = offset; @@ -146,12 +146,12 @@ impl VmarMapOptions { } /// Sets the size of the mapping. - /// + /// /// The size of a mapping may not be equal to that of the VMO. /// For example, it is ok to create a mapping whose size is larger than - /// that of the VMO, although one cannot read from or write to the - /// part of the mapping that is not backed by the VMO. - /// So you may wonder: what is the point of supporting such _oversized_ + /// that of the VMO, although one cannot read from or write to the + /// part of the mapping that is not backed by the VMO. + /// So you may wonder: what is the point of supporting such _oversized_ /// mappings? The reason is two-fold. /// 1. VMOs are resizable. So even if a mapping is backed by a VMO whose /// size is equal to that of the mapping initially, we cannot prevent @@ -159,7 +159,7 @@ impl VmarMapOptions { /// 2. Mappings are not allowed to overlap by default. As a result, /// oversized mappings can serve as a placeholder to prevent future /// mappings from occupying some particular address ranges accidentally. - /// + /// /// The default value is the size of the VMO. pub fn size(mut self, size: usize) -> Self { self.size = size; @@ -167,9 +167,9 @@ impl VmarMapOptions { } /// Sets the mapping's alignment. - /// + /// /// The default value is the page size. - /// + /// /// The provided alignment must be a power of two and a multiple of the /// page size. pub fn align(mut self, align: usize) -> Self { @@ -178,11 +178,11 @@ impl VmarMapOptions { } /// Sets the mapping's offset inside the VMAR. - /// + /// /// The offset must satisfy the alignment requirement. /// Also, the mapping's range `[offset, offset + size)` must be within /// the VMAR. - /// + /// /// If not set, the system will choose an offset automatically. pub fn offset(mut self, offset: usize) -> Self { self.offset = Some(offset); @@ -190,9 +190,9 @@ impl VmarMapOptions { } /// Sets whether the mapping can overwrite existing mappings. - /// + /// /// The default value is false. - /// + /// /// If this option is set to true, then the `offset` option must be /// set. pub fn can_overwrite(mut self, can_overwrite: bool) -> Self { @@ -201,9 +201,9 @@ impl VmarMapOptions { } /// Creates the mapping. - /// + /// /// All options will be checked at this point. - /// + /// /// On success, the virtual address of the new mapping is returned. pub fn build(mut self) -> Result { todo!() diff --git a/src/kxos-std/src/vm/vmar/static_cap.rs b/src/kxos-std/src/vm/vmar/static_cap.rs index 2b7ff119..6d3b9045 100644 --- a/src/kxos-std/src/vm/vmar/static_cap.rs +++ b/src/kxos-std/src/vm/vmar/static_cap.rs @@ -1,19 +1,22 @@ 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 kxos_frame::prelude::Result; use crate::{rights::*, vm::vmo::Vmo}; -use super::{Vmar, Vmar_, VmPerms, options::{VmarMapOptions, VmarChildOptions}}; +use super::{ + options::{VmarChildOptions, VmarMapOptions}, + VmPerms, Vmar, Vmar_, +}; impl Vmar { /// Creates a root VMAR. - /// + /// /// # Access rights - /// + /// /// A root VMAR is initially given full access rights. pub fn new() -> Result { let inner = Arc::new(Vmar_::new()?); @@ -23,13 +26,13 @@ impl Vmar { } /// Maps the given VMO into the VMAR through a set of VMAR mapping options. - /// + /// /// # Example - /// + /// /// ``` /// use kxos_std::prelude::*; /// use kxos_std::vm::{PAGE_SIZE, Vmar, VmoOptions}; - /// + /// /// let vmar = Vmar::::new().unwrap(); /// let vmo = VmoOptions::new(PAGE_SIZE).alloc().unwrap(); /// let target_vaddr = 0x1234000; @@ -42,45 +45,45 @@ impl Vmar { /// .unwrap(); /// assert!(real_vaddr == target_vaddr); /// ``` - /// + /// /// For more details on the available options, see `VmarMapOptions`. - /// + /// /// # Access rights - /// + /// /// This method requires the following access rights: - /// 1. The VMAR contains the rights corresponding to the memory permissions of - /// the mapping. For example, if `perms` contains `VmPerm::WRITE`, + /// 1. The VMAR contains the rights corresponding to the memory permissions of + /// the mapping. For example, if `perms` contains `VmPerm::WRITE`, /// then the VMAR must have the Write right. - /// 2. Similarly, the VMO contains the rights corresponding to the memory + /// 2. Similarly, the VMO contains the rights corresponding to the memory /// permissions of the mapping. - /// + /// /// Memory permissions may be changed through the `protect` method, /// which ensures that any updated memory permissions do not go beyond /// the access rights of the underlying VMOs. #[require(R > Dup)] - pub fn new_map(&self, vmo: Vmo, perms: VmPerms) -> Result> { + pub fn new_map(&self, vmo: Vmo, perms: VmPerms) -> Result> { let dup_self = self.dup()?; - Ok(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. - /// + /// /// # Example - /// + /// /// ``` /// let parent = Vmar::new().unwrap(); /// let child_size = 10 * PAGE_SIZE; /// let child = parent.new_child(child_size).alloc().unwrap(); /// assert!(child.size() == child_size); - /// ``` - /// + /// ``` + /// /// For more details on the available options, see `VmarChildOptions`. - /// + /// /// # Access rights - /// + /// /// This method requires the Dup right. - /// - /// 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. #[require(R > Dup)] pub fn new_child(&self, size: usize) -> Result> { @@ -89,25 +92,25 @@ impl Vmar { } /// Change the permissions of the memory mappings in the specified range. - /// + /// /// The range's start and end addresses must be page-aligned. /// Also, the range must be completely mapped. - /// + /// /// # Access rights - /// + /// /// The VMAR must have the rights corresponding to the specified memory /// permissions. - /// + /// /// The mappings overlapped with the specified range must be backed by /// VMOs whose rights contain the rights corresponding to the specified - /// memory permissions. + /// memory permissions. pub fn protect(&self, perms: VmPerms, range: Range) -> Result<()> { self.check_rights(perms.into())?; self.0.protect(perms, range) } /// Destroy a VMAR, including all its mappings and children VMARs. - /// + /// /// After being destroyed, the VMAR becomes useless and returns errors /// for most of its methods. pub fn destroy_all(&self) -> Result<()> { @@ -116,10 +119,10 @@ impl Vmar { /// Destroy all mappings and children VMARs that fall within the specified /// range in bytes. - /// + /// /// The range's start and end addresses must be page-aligned. - /// - /// Mappings may fall partially within the range; only the overlapped + /// + /// Mappings may fall partially within the range; only the overlapped /// portions of the mappings are unmapped. /// As for children VMARs, they must be fully within the range. /// All children VMARs that fall within the range get their `destroy` methods @@ -129,10 +132,10 @@ impl Vmar { } /// Duplicate the capability. - /// + /// /// # Access rights /// - /// The method requires the Dup right. + /// The method requires the Dup right. #[require(R > Dup)] pub fn dup(&self) -> Result { todo!() @@ -156,10 +159,9 @@ impl Vmar { Err(Error::AccessDenied) } } - } -impl VmIo for Vmar { +impl VmIo for Vmar { fn read_bytes(&self, offset: usize, buf: &mut [u8]) -> Result<()> { // self.check_rights!(Rights::READ)?; self.0.read(offset, buf) @@ -169,4 +171,4 @@ impl VmIo for Vmar { // self.check_rights!(Rights::WRITE)?; self.0.write(offset, buf) } -} \ No newline at end of file +} diff --git a/src/kxos-std/src/vm/vmo/dyn_cap.rs b/src/kxos-std/src/vm/vmo/dyn_cap.rs index 6422e645..af46ca90 100644 --- a/src/kxos-std/src/vm/vmo/dyn_cap.rs +++ b/src/kxos-std/src/vm/vmo/dyn_cap.rs @@ -1,119 +1,128 @@ use core::ops::Range; -use kxos_frame::{vm::VmIo, Error}; use kxos_frame::prelude::Result; +use kxos_frame::{vm::VmIo, Error}; use crate::rights::{Rights, TRights}; -use super::{VmoChildOptions, options::{VmoSliceChild, VmoCowChild}, Vmo}; +use super::{ + options::{VmoCowChild, VmoSliceChild}, + Vmo, VmoChildOptions, +}; impl Vmo { /// Creates a new slice VMO through a set of VMO child options. - /// + /// /// # Example - /// + /// /// ``` /// let parent = VmoOptions::new(PAGE_SIZE).alloc().unwrap(); /// let child_size = parent.size(); /// let child = parent.new_slice_child(0..child_size).alloc().unwrap(); /// assert!(child.size() == child_size); - /// ``` - /// + /// ``` + /// /// For more details on the available options, see `VmoChildOptions`. - /// + /// /// # Access rights - /// + /// /// This method requires the Dup right. - /// + /// /// The new VMO child will be of the same capability flavor as the parent; /// so are the access rights. - pub fn new_slice_child(&self, range: Range) -> Result> { + pub fn new_slice_child( + &self, + range: Range, + ) -> Result> { let dup_self = self.dup()?; Ok(VmoChildOptions::new_slice_rights(dup_self, range)) } /// Creates a new COW VMO through a set of VMO child options. - /// + /// /// # Example - /// + /// /// ``` /// let parent = VmoOptions::new(PAGE_SIZE).alloc().unwrap(); /// let child_size = 2 * parent.size(); /// let child = parent.new_cow_child(0..child_size).alloc().unwrap(); /// assert!(child.size() == child_size); - /// ``` - /// + /// ``` + /// /// For more details on the available options, see `VmoChildOptions`. - /// + /// /// # Access rights - /// + /// /// This method requires the Dup right. - /// + /// /// 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 /// plus the Write right. - pub fn new_cow_child(&self, range: Range) -> Result> { + pub fn new_cow_child( + &self, + range: Range, + ) -> Result> { let dup_self = self.dup()?; Ok(VmoChildOptions::new_cow(dup_self, range)) } /// Commits the pages specified in the range (in bytes). - /// + /// /// The range must be within the size of the VMO. - /// + /// /// The start and end addresses will be rounded down and up to page boundaries. - /// + /// /// # Access rights /// - /// The method requires the Write right. + /// The method requires the Write right. pub fn commit(&self, range: Range) -> Result<()> { self.check_rights(Rights::WRITE)?; self.0.commit(range) } /// Decommits the pages specified in the range (in bytes). - /// + /// /// The range must be within the size of the VMO. - /// + /// /// The start and end addresses will be rounded down and up to page boundaries. - /// + /// /// # Access rights /// - /// The method requires the Write right. + /// The method requires the Write right. pub fn decommit(&self, range: Range) -> Result<()> { self.check_rights(Rights::WRITE)?; self.0.decommit(range) } /// Resizes the VMO by giving a new size. - /// + /// /// The VMO must be resizable. - /// + /// /// The new size will be rounded up to page boundaries. - /// + /// /// # Access rights /// - /// The method requires the Write right. + /// The method requires the Write right. pub fn resize(&self, new_size: usize) -> Result<()> { self.check_rights(Rights::WRITE)?; self.0.resize(new_size) } - /// Clears the specified range by writing zeros. - /// + /// Clears the specified range by writing zeros. + /// /// # Access rights /// - /// The method requires the Write right. + /// The method requires the Write right. pub fn clear(&self, range: Range) -> Result<()> { self.check_rights(Rights::WRITE)?; - self.0.clear(range) + self.0.clear(range) } /// Duplicates the capability. - /// + /// /// # Access rights /// - /// The method requires the Dup right. + /// The method requires the Dup right. pub fn dup(&self) -> Result { self.check_rights(Rights::DUP)?; todo!() @@ -137,7 +146,7 @@ impl Vmo { pub fn check_rights(&self, rights: Rights) -> Result<()> { if self.rights().contains(rights) { - Ok(()) + Ok(()) } else { Err(Error::AccessDenied) } @@ -154,4 +163,4 @@ impl VmIo for Vmo { self.check_rights(Rights::WRITE)?; self.0.write_bytes(offset, buf) } -} \ No newline at end of file +} diff --git a/src/kxos-std/src/vm/vmo/mod.rs b/src/kxos-std/src/vm/vmo/mod.rs index 03911bd9..328bcb87 100644 --- a/src/kxos-std/src/vm/vmo/mod.rs +++ b/src/kxos-std/src/vm/vmo/mod.rs @@ -2,30 +2,28 @@ use core::ops::Range; -use kxos_frame::{prelude::Result, vm::Paddr, Error}; 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 options; mod pager; +mod static_cap; -pub use options::{VmoOptions, VmoChildOptions}; +pub use options::{VmoChildOptions, VmoOptions}; 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. -/// +/// /// # Features -/// +/// /// * **I/O interface.** A VMO provides read and write methods to access the /// memory pages that it contain. -/// * **On-demand paging.** The memory pages of a VMO (except for _contiguous_ +/// * **On-demand paging.** The memory pages of a VMO (except for _contiguous_ /// VMOs) are allocated lazily when the page is first accessed. /// * **Tree structure.** Given a VMO, one can create a child VMO from it. /// The child VMO can only access a subset of the parent's memory, @@ -33,46 +31,46 @@ use spin::Mutex; /// * **Copy-on-write (COW).** A child VMO may be created with COW semantics, /// which prevents any writes on the child from affecting the parent /// by duplicating memory pages only upon the first writes. -/// * **Access control.** As capabilities, VMOs restrict the +/// * **Access control.** As capabilities, VMOs restrict the /// accessible range of memory and the allowed I/O operations. /// * **Device driver support.** If specified upon creation, VMOs will be /// backed by physically contiguous memory pages starting at a target address. /// * **File system support.** By default, a VMO's memory pages are initially -/// all zeros. But if a VMO is attached to a pager (`Pager`) upon creation, +/// all zeros. But if a VMO is attached to a pager (`Pager`) upon creation, /// then its memory pages will be populated by the pager. /// With this pager mechanism, file systems can easily implement page caches /// with VMOs by attaching the VMOs to pagers backed by inodes. -/// +/// /// # Capabilities -/// -/// As a capability, each VMO is associated with a set of access rights, +/// +/// As a capability, each VMO is associated with a set of access rights, /// whose semantics are explained below. -/// -/// * The Dup right allows duplicating a VMO and creating children out of +/// +/// * The Dup right allows duplicating a VMO and creating children out of /// a VMO. -/// * The Read, Write, Exec rights allow creating memory mappings with +/// * The Read, Write, Exec rights allow creating memory mappings with /// readable, writable, and executable access permissions, respectively. /// * The Read and Write rights allow the VMO to be read from and written to /// directly. /// * The Write right allows resizing a resizable VMO. -/// +/// /// VMOs are implemented with two flavors of capabilities: /// the dynamic one (`Vmo`) and the static one (`Vmo). -/// +/// /// # Examples -/// +/// /// For creating root VMOs, see `VmoOptions`.` -/// +/// /// For creating child VMOs, see `VmoChildOptions`. -/// +/// /// # Implementation -/// -/// `Vmo` provides high-level APIs for address space management by wrapping +/// +/// `Vmo` provides high-level APIs for address space management by wrapping /// around its low-level counterpart `kx_frame::vm::VmFrames`. /// Compared with `VmFrames`, -/// `Vmo` is easier to use (by offering more powerful APIs) and +/// `Vmo` is easier to use (by offering more powerful APIs) and /// harder to misuse (thanks to its nature of being capability). -/// +/// pub struct Vmo(Arc, R); bitflags! { @@ -80,13 +78,13 @@ bitflags! { pub struct VmoFlags: u32 { /// Set this flag if a VMO is resizable. 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. - /// + /// /// 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 = 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. const DMA = 1 << 2; } @@ -94,7 +92,7 @@ bitflags! { struct Vmo_ { flags: VmoFlags, - inner: Mutex, + inner: Mutex, parent: Option>, } @@ -148,7 +146,6 @@ impl Vmo_ { } } - impl Vmo { /// Returns the size (in bytes) of a VMO. pub fn size(&self) -> usize { @@ -165,5 +162,4 @@ impl Vmo { pub fn flags(&self) -> VmoFlags { self.0.flags() } - -} \ No newline at end of file +} diff --git a/src/kxos-std/src/vm/vmo/options.rs b/src/kxos-std/src/vm/vmo/options.rs index 9d25173b..7e534918 100644 --- a/src/kxos-std/src/vm/vmo/options.rs +++ b/src/kxos-std/src/vm/vmo/options.rs @@ -4,43 +4,43 @@ use core::marker::PhantomData; use core::ops::Range; use alloc::sync::Arc; -use kxos_frame::vm::Paddr; use kxos_frame::prelude::Result; +use kxos_frame::vm::Paddr; use kxos_rights_proc::require; -use crate::rights::{Dup,TRights,Rights}; +use crate::rights::{Dup, Rights, TRights}; -use super::{Vmo, VmoFlags, Pager}; +use super::{Pager, Vmo, VmoFlags}; /// Options for allocating a root VMO. -/// +/// /// # Examples -/// +/// /// Creating a VMO as a _dynamic_ capability with full access rights: /// ``` /// use kxo_std::vm::{PAGE_SIZE, VmoOptions}; -/// +/// /// let vmo = VmoOptions::new(PAGE_SIZE) /// .alloc() /// .unwrap(); /// ``` -/// +/// /// Creating a VMO as a _static_ capability with all access rights: /// ``` /// use kxos_std::prelude::*; /// use kxo_std::vm::{PAGE_SIZE, VmoOptions}; -/// +/// /// let vmo = VmoOptions::::new(PAGE_SIZE) /// .alloc() /// .unwrap(); /// ``` -/// -/// Creating a resizable VMO backed by 10 memory pages that may not be +/// +/// Creating a resizable VMO backed by 10 memory pages that may not be /// physically contiguous: -/// +/// /// ``` /// use kxos_std::vm::{PAGE_SIZE, VmoOptions, VmoFlags}; -/// +/// /// let vmo = VmoOptions::new(10 * PAGE_SIZE) /// .flags(VmoFlags::RESIZABLE) /// .alloc() @@ -55,18 +55,18 @@ pub struct VmoOptions { } impl VmoOptions { - /// Creates a default set of options with the specified size of the VMO + /// Creates a default set of options with the specified size of the VMO /// (in bytes). - /// + /// /// The size of the VMO will be rounded up to align with the page size. pub fn new(size: usize) -> Self { todo!() } /// Sets the starting physical address of the VMO. - /// + /// /// By default, this option is not set. - /// + /// /// If this option is set, then the underlying pages of VMO must be contiguous. /// So `VmoFlags::IS_CONTIGUOUS` will be set automatically. pub fn paddr(mut self, paddr: Paddr) -> Self { @@ -74,9 +74,9 @@ impl VmoOptions { } /// Sets the VMO flags. - /// + /// /// The default value is `VmoFlags::empty()`. - /// + /// /// For more information about the flags, see `VmoFlags`. pub fn flags(mut self, flags: VmoFlags) -> Self { todo!() @@ -90,10 +90,10 @@ impl VmoOptions { impl VmoOptions { /// Allocates the VMO according to the specified options. - /// + /// /// # Access rights - /// - /// The VMO is initially assigned full access rights. + /// + /// The VMO is initially assigned full access rights. pub fn alloc(mut self) -> Result> { todo!() } @@ -101,10 +101,10 @@ impl VmoOptions { impl VmoOptions { /// Allocates the VMO according to the specified options. - /// + /// /// # Access rights - /// - /// The VMO is initially assigned the access rights represented + /// + /// The VMO is initially assigned the access rights represented /// by `R: TRights`. pub fn alloc(mut self) -> Result> { todo!() @@ -112,14 +112,14 @@ impl VmoOptions { } /// Options for allocating a child VMO out of a parent VMO. -/// +/// /// # Examples -/// +/// /// A child VMO created from a parent VMO of _dynamic_ capability is also a /// _dynamic_ capability. /// ``` /// use kxo_std::vm::{PAGE_SIZE, VmoOptions}; -/// +/// /// let parent_vmo = VmoOptions::new(PAGE_SIZE) /// .alloc() /// .unwrap(); @@ -128,13 +128,13 @@ impl VmoOptions { /// .unwrap(); /// assert!(parent_vmo.rights() == child_vmo.rights()); /// ``` -/// +/// /// A child VMO created from a parent VMO of _static_ capability is also a /// _static_ capability. /// ``` /// use kxos_std::prelude::*; /// use kxos_std::vm::{PAGE_SIZE, VmoOptions, VmoChildOptions}; -/// +/// /// let parent_vmo: Vmo = VmoOptions::new(PAGE_SIZE) /// .alloc() /// .unwrap(); @@ -143,15 +143,15 @@ impl VmoOptions { /// .unwrap(); /// assert!(parent_vmo.rights() == child_vmo.rights()); /// ``` -/// -/// Normally, a child VMO is initially given the same set of access rights -/// as its parent (as shown above). But there is one exception: +/// +/// Normally, a child VMO is initially given the same set of access rights +/// as its parent (as shown above). But there is one exception: /// if the child VMO is created as a COW child, then it is granted the Write /// right regardless of whether the parent is writable or not. -/// +/// /// ``` /// use kxo_std::vm::{PAGE_SIZE, VmoOptions, VmoChildOptions}; -/// +/// /// let parent_vmo = VmoOptions::new(PAGE_SIZE) /// .alloc() /// .unwrap() @@ -162,11 +162,11 @@ impl VmoOptions { /// assert!(child_vmo.rights().contains(Rights::WRITE)); /// ``` /// -/// The above rule for COW VMO children also applies to static capabilities. -/// +/// The above rule for COW VMO children also applies to static capabilities. +/// /// ``` /// use kxos_std::vm::{PAGE_SIZE, VmoOptions, VmoChildOptions}; -/// +/// /// let parent_vmo = VmoOptions::::new(PAGE_SIZE) /// .alloc() /// .unwrap(); @@ -175,14 +175,14 @@ impl VmoOptions { /// .unwrap(); /// assert!(child_vmo.rights().contains(Rights::WRITE)); /// ``` -/// +/// /// One can set VMO flags for a child VMO. Currently, the only flag that is /// valid when creating VMO children is `VmoFlags::RESIZABLE`. /// Note that a slice VMO child and its parent cannot not be resizable. -/// +/// /// ```rust /// use kxo_std::vm::{PAGE_SIZE, VmoOptions}; -/// +/// /// let parent_vmo = VmoOptions::new(PAGE_SIZE) /// .alloc() /// .unwrap(); @@ -201,13 +201,13 @@ pub struct VmoChildOptions { marker: PhantomData, } -impl VmoChildOptions { +impl VmoChildOptions { /// 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 /// 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. #[require(R > Dup)] pub fn new_slice(parent: Vmo, range: Range) -> Self { @@ -222,16 +222,18 @@ impl VmoChildOptions { impl VmoChildOptions { /// 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, range: Range) -> Self { - parent.check_rights(Rights::DUP).expect("function new_slice_rights should called with rights Dup"); + parent + .check_rights(Rights::DUP) + .expect("function new_slice_rights should called with rights Dup"); Self { flags: parent.flags() & Self::PARENT_FLAGS_MASK, parent, @@ -242,38 +244,39 @@ impl VmoChildOptions { } impl VmoChildOptions { - /// Creates a default set of options for creating a copy-on-write (COW) + /// Creates a default set of options for creating a copy-on-write (COW) /// VMO child. - /// - /// A COW VMO child behaves as if all its + /// + /// A COW VMO child behaves as if all its /// memory pages are copied from the parent VMO upon creation, although /// the copying is done lazily when the parent's memory pages are updated. - /// + /// /// The range of a child may go beyond that of the parent. - /// 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, range: Range) -> Self { Self { flags: parent.flags() & Self::PARENT_FLAGS_MASK, parent, range, - marker: PhantomData, + marker: PhantomData, } } } impl VmoChildOptions { /// Flags that a VMO child inherits from its parent. - pub const PARENT_FLAGS_MASK: VmoFlags = VmoFlags::from_bits(VmoFlags::CONTIGUOUS.bits | VmoFlags::DMA.bits).unwrap(); + pub const PARENT_FLAGS_MASK: VmoFlags = + VmoFlags::from_bits(VmoFlags::CONTIGUOUS.bits | VmoFlags::DMA.bits).unwrap(); /// Flags that a VMO child may differ from its parent. pub const CHILD_FLAGS_MASK: VmoFlags = VmoFlags::RESIZABLE; /// Sets the VMO flags. - /// + /// /// Only the flags among `Self::CHILD_FLAGS_MASK` may be set through this /// method. - /// + /// /// To set `VmoFlags::RESIZABLE`, the child must be COW. - /// + /// /// The default value is `VmoFlags::empty()`. pub fn flags(mut self, flags: VmoFlags) -> Self { self.flags = flags & Self::CHILD_FLAGS_MASK; @@ -283,7 +286,7 @@ impl VmoChildOptions { impl VmoChildOptions { /// Allocates the child VMO. - /// + /// /// # Access rights /// /// The child VMO is initially assigned all the parent's access rights. @@ -294,7 +297,7 @@ impl VmoChildOptions { impl VmoChildOptions { /// Allocates the child VMO. - /// + /// /// # Access rights /// /// The child VMO is initially assigned all the parent's access rights. @@ -305,14 +308,13 @@ impl VmoChildOptions { impl VmoChildOptions { /// Allocates the child VMO. - /// + /// /// # Access rights /// /// The child VMO is initially assigned all the parent's access rights /// plus the Write right. pub fn alloc(mut self) -> Result> - 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 // (say, `TRightsExtend(L, F)`) // that may extend a list (`L`) of type-level flags with an extra flag `F`. @@ -323,7 +325,7 @@ impl VmoChildOptions { // original: // pub fn alloc(mut self) -> Result> - // where + // 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)`) diff --git a/src/kxos-std/src/vm/vmo/pager.rs b/src/kxos-std/src/vm/vmo/pager.rs index 46b93fa3..805aa72a 100644 --- a/src/kxos-std/src/vm/vmo/pager.rs +++ b/src/kxos-std/src/vm/vmo/pager.rs @@ -1,58 +1,58 @@ -use kxos_frame::vm::VmFrame; use kxos_frame::prelude::Result; +use kxos_frame::vm::VmFrame; /// 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 /// VMO needs more frames (i.e., on commits), it will turn to the pager, /// which should then provide frames whose data have been initialized properly. -/// Any time a frame is updated through the VMO, the VMO will +/// Any time a frame is updated through the VMO, the VMO will /// notify the attached pager that the frame has been updated. /// Finally, when a frame is no longer needed (i.e., on decommits), /// the frame pager will also be notified. pub trait Pager { /// Ask the pager to provide a frame at a specified offset (in bytes). - /// + /// /// After a page of a VMO is committed, the VMO shall not call this method /// again until the page is decommitted. But a robust implementation of /// `Pager` should not rely on this behavior for its correctness; /// instead, it should returns the _same_ frame. - /// + /// /// If a VMO page has been previously committed and decommited, - /// and is to be committed again, then the pager is free to return + /// and is to be committed again, then the pager is free to return /// whatever frame that may or may not be the same as the last time. - /// + /// /// It is up to the pager to decide the range of valid offsets. - /// + /// /// The offset will be rounded down to page boundary. fn commit_page(&self, offset: usize) -> Result; - /// Notify the pager that the frame at a specified offset (in bytes) + /// Notify the pager that the frame at a specified offset (in bytes) /// has been updated. - /// - /// Being aware of the updates allow the pager (e.g., an inode) to - /// know which pages are dirty and only write back the _dirty_ pages back + /// + /// Being aware of the updates allow the pager (e.g., an inode) to + /// know which pages are dirty and only write back the _dirty_ pages back /// to disk. - /// + /// /// The VMO will not call this method for an uncommitted page. /// But a robust implementation of `Pager` should not make - /// such an assumption for its correctness; instead, it should simply ignore the + /// such an assumption for its correctness; instead, it should simply ignore the /// call or return an error. - /// + /// /// The offset will be rounded down to page boundary. fn update_page(&self, offset: usize) -> Result<()>; - /// Notify the pager that the frame at the specified offset (in bytes) + /// Notify the pager that the frame at the specified offset (in bytes) /// has been decommitted. - /// + /// /// Knowing that a frame is no longer needed, the pager (e.g., an inode) /// can free the frame after writing back its data to the disk. - /// + /// /// The VMO will not call this method for an uncommitted page. /// But a robust implementation of `Pager` should not make - /// such an assumption for its correctness; instead, it should simply ignore the + /// such an assumption for its correctness; instead, it should simply ignore the /// call or return an error. - /// + /// /// The offset will be rounded down to page boundary. fn decommit_page(&self, offset: usize) -> Result<()>; -} \ No newline at end of file +} diff --git a/src/kxos-std/src/vm/vmo/static_cap.rs b/src/kxos-std/src/vm/vmo/static_cap.rs index 826874b7..9dfa407d 100644 --- a/src/kxos-std/src/vm/vmo/static_cap.rs +++ b/src/kxos-std/src/vm/vmo/static_cap.rs @@ -1,56 +1,62 @@ use core::ops::Range; -use kxos_frame::{vm::VmIo, Error}; use kxos_frame::prelude::Result; +use kxos_frame::{vm::VmIo, Error}; use kxos_rights_proc::require; use crate::rights::*; -use super::{Vmo, VmoChildOptions, options::{VmoSliceChild, VmoCowChild}}; +use super::{ + options::{VmoCowChild, VmoSliceChild}, + Vmo, VmoChildOptions, +}; impl Vmo { /// Creates a new slice VMO through a set of VMO child options. - /// + /// /// # Example - /// + /// /// ``` /// let parent = VmoOptions::new(PAGE_SIZE).alloc().unwrap(); /// let child_size = parent.size(); /// let child = parent.new_slice_child(0..child_size).alloc().unwrap(); /// assert!(child.size() == child_size); - /// ``` - /// + /// ``` + /// /// For more details on the available options, see `VmoChildOptions`. - /// + /// /// # Access rights - /// + /// /// This method requires the Dup right. - /// + /// /// The new VMO child will be of the same capability flavor as the parent; /// so are the access rights. #[require(R > Dup)] - pub fn new_slice_child(&self, range: Range) -> Result> { + pub fn new_slice_child( + &self, + range: Range, + ) -> Result> { let dup_self = self.dup()?; Ok(VmoChildOptions::new_slice(dup_self, range)) } /// Creates a new COW VMO through a set of VMO child options. - /// + /// /// # Example - /// + /// /// ``` /// let parent = VmoOptions::new(PAGE_SIZE).alloc().unwrap(); /// let child_size = 2 * parent.size(); /// let child = parent.new_cow_child(0..child_size).alloc().unwrap(); /// assert!(child.size() == child_size); - /// ``` - /// + /// ``` + /// /// For more details on the available options, see `VmoChildOptions`. - /// + /// /// # Access rights - /// + /// /// This method requires the Dup right. - /// + /// /// 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 /// plus the Write right. @@ -61,62 +67,62 @@ impl Vmo { } /// Commit the pages specified in the range (in bytes). - /// + /// /// The range must be within the size of the VMO. - /// + /// /// The start and end addresses will be rounded down and up to page boundaries. - /// + /// /// # Access rights /// - /// The method requires the Write right. + /// The method requires the Write right. #[require(R > Write)] pub fn commit(&self, range: Range) -> Result<()> { self.0.commit(range) } /// Decommit the pages specified in the range (in bytes). - /// + /// /// The range must be within the size of the VMO. - /// + /// /// The start and end addresses will be rounded down and up to page boundaries. - /// + /// /// # Access rights /// - /// The method requires the Write right. + /// The method requires the Write right. #[require(R > Write)] pub fn decommit(&self, range: Range) -> Result<()> { self.0.decommit(range) } /// Resize the VMO by giving a new size. - /// + /// /// The VMO must be resizable. - /// + /// /// The new size will be rounded up to page boundaries. - /// + /// /// # Access rights /// - /// The method requires the Write right. + /// The method requires the Write right. #[require(R > Write)] pub fn resize(&self, new_size: usize) -> Result<()> { self.0.resize(new_size) } - /// Clear the specified range by writing zeros. - /// + /// Clear the specified range by writing zeros. + /// /// # Access rights /// - /// The method requires the Write right. + /// The method requires the Write right. #[require(R > Write)] pub fn clear(&self, range: Range) -> Result<()> { - self.0.clear(range) + self.0.clear(range) } /// Duplicate the capability. - /// + /// /// # Access rights /// - /// The method requires the Dup right. + /// The method requires the Dup right. #[require(R > Dup)] pub fn dup(&self) -> Result { todo!() @@ -140,7 +146,7 @@ impl Vmo { fn check_rights(&self, rights: Rights) -> Result<()> { if self.rights().contains(rights) { - Ok(()) + Ok(()) } else { Err(Error::AccessDenied) } @@ -157,4 +163,4 @@ impl VmIo for Vmo { self.check_rights(Rights::WRITE)?; self.0.write_bytes(offset, buf) } -} \ No newline at end of file +} diff --git a/src/kxos-virtio/src/block.rs b/src/kxos-virtio/src/block.rs index d79e5f39..60f6e3ad 100644 --- a/src/kxos-virtio/src/block.rs +++ b/src/kxos-virtio/src/block.rs @@ -1,12 +1,12 @@ use kxos_frame::Pod; +use kxos_frame_pod_derive::Pod; use kxos_pci::capability::vendor::virtio::CapabilityVirtioData; use kxos_pci::util::BAR; use kxos_util::frame_ptr::InFramePtr; -use kxos_frame_pod_derive::Pod; pub const BLK_SIZE: usize = 512; -#[derive(Debug, Copy, Clone,Pod)] +#[derive(Debug, Copy, Clone, Pod)] #[repr(C)] pub struct VirtioBLKConfig { capacity: u64, @@ -25,7 +25,7 @@ pub struct VirtioBLKConfig { unused1: [u8; 3], } -#[derive(Debug, Copy, Clone,Pod)] +#[derive(Debug, Copy, Clone, Pod)] #[repr(C)] pub struct VirtioBLKGeometry { cylinders: u16, @@ -33,7 +33,7 @@ pub struct VirtioBLKGeometry { sectors: u8, } -#[derive(Debug, Copy, Clone,Pod)] +#[derive(Debug, Copy, Clone, Pod)] #[repr(C)] pub struct VirtioBLKTopology { physical_block_exp: u8, diff --git a/src/kxos-virtio/src/lib.rs b/src/kxos-virtio/src/lib.rs index a6d1b737..d226a4ee 100644 --- a/src/kxos-virtio/src/lib.rs +++ b/src/kxos-virtio/src/lib.rs @@ -7,13 +7,12 @@ extern crate alloc; use alloc::{sync::Arc, vec::Vec}; use bitflags::bitflags; use kxos_frame::{info, offset_of, TrapFrame}; +use kxos_frame_pod_derive::Pod; use kxos_pci::util::{PCIDevice, BAR}; use kxos_util::frame_ptr::InFramePtr; -use kxos_frame_pod_derive::Pod; use spin::{mutex::Mutex, MutexGuard}; - use self::{block::VirtioBLKConfig, queue::VirtQueue}; use kxos_frame::Pod; @@ -57,7 +56,7 @@ bitflags! { } } -#[derive(Debug, Default, Copy, Clone,Pod)] +#[derive(Debug, Default, Copy, Clone, Pod)] #[repr(C)] pub struct VitrioPciCommonCfg { device_feature_select: u32, diff --git a/src/kxos-virtio/src/queue.rs b/src/kxos-virtio/src/queue.rs index 85a12249..92f357ed 100644 --- a/src/kxos-virtio/src/queue.rs +++ b/src/kxos-virtio/src/queue.rs @@ -6,8 +6,8 @@ use bitflags::bitflags; use core::sync::atomic::{fence, Ordering}; use kxos_frame::offset_of; use kxos_frame::Pod; -use kxos_util::frame_ptr::InFramePtr; use kxos_frame_pod_derive::Pod; +use kxos_util::frame_ptr::InFramePtr; #[derive(Debug)] pub enum QueueError { InvalidArgs, @@ -231,7 +231,7 @@ impl VirtQueue { } #[repr(C, align(16))] -#[derive(Debug, Default, Copy, Clone,Pod)] +#[derive(Debug, Default, Copy, Clone, Pod)] struct Descriptor { addr: u64, len: u32, @@ -274,7 +274,7 @@ impl Default for DescFlags { /// each ring entry refers to the head of a descriptor chain. /// It is only written by the driver and read by the device. #[repr(C)] -#[derive(Debug, Default, Copy, Clone,Pod)] +#[derive(Debug, Default, Copy, Clone, Pod)] struct AvailRing { flags: u16, /// A driver MUST NOT decrement the idx. @@ -286,7 +286,7 @@ struct AvailRing { /// 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. #[repr(C)] -#[derive(Debug, Default, Copy, Clone,Pod)] +#[derive(Debug, Default, Copy, Clone, Pod)] struct UsedRing { flags: u16, idx: u16, @@ -295,7 +295,7 @@ struct UsedRing { } #[repr(C)] -#[derive(Debug, Default, Copy, Clone,Pod)] +#[derive(Debug, Default, Copy, Clone, Pod)] struct UsedElem { id: u32, len: u32, diff --git a/src/tests/timer_test.rs b/src/tests/timer_test.rs index 7d9cad0a..e0e3bc77 100644 --- a/src/tests/timer_test.rs +++ b/src/tests/timer_test.rs @@ -7,8 +7,8 @@ use bootloader::{entry_point, BootInfo}; use kxos_frame::timer::Timer; extern crate alloc; use alloc::sync::Arc; -use core::time::Duration; use core::panic::PanicInfo; +use core::time::Duration; use kxos_frame::println; static mut TICK: usize = 0; @@ -28,7 +28,9 @@ fn panic(info: &PanicInfo) -> ! { #[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!( + "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(); @@ -39,8 +41,8 @@ fn test_timer() { pub fn timer_callback(timer: Arc) { unsafe { - TICK+=1; - println!("TICK:{}",TICK); + TICK += 1; + println!("TICK:{}", TICK); timer.set(Duration::from_secs(1)); } }