Add kxos-frame crate

This commit is contained in:
Tate, Hongliang Tian 2022-08-07 18:01:42 -07:00
parent a1f1b728cc
commit 92d29e2030
25 changed files with 1078 additions and 1 deletions

3
.gitignore vendored
View File

@ -1,6 +1,7 @@
# Generated by Cargo
# will have compiled files and executables
/target/
debug/
target/
# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html

View File

@ -0,0 +1,9 @@
[package]
name = "kxos-frame"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
bitflags = "1.3"

127
src/kxos-frame/src/cpu.rs Normal file
View File

@ -0,0 +1,127 @@
//! CPU.
/// Defines a CPU-local variable.
#[macro_export]
macro_rules! cpu_local {
() => {
todo!()
};
}
/// Returns the number of CPUs.
pub fn num_cpus() -> u32 {
todo!()
}
/// Returns the ID of this CPU.
pub fn this_cpu() -> u32 {
todo!()
}
/// Cpu context, including both general-purpose registers and floating-point registers.
#[derive(Clone, Default)]
#[repr(C)]
pub struct CpuContext {
pub gp_regs: GpRegs,
pub fs_base: u64,
pub fp_regs: FpRegs,
}
/// The general-purpose registers of CPU.
#[derive(Clone, Copy, Debug, Default)]
#[repr(C)]
pub struct GpRegs {
pub r8: u64,
pub r9: u64,
pub r10: u64,
pub r11: u64,
pub r12: u64,
pub r13: u64,
pub r14: u64,
pub r15: u64,
pub rdi: u64,
pub rsi: u64,
pub rbp: u64,
pub rbx: u64,
pub rdx: u64,
pub rax: u64,
pub rcx: u64,
pub rsp: u64,
pub rip: u64,
pub rflag: u64,
}
/// The floating-point state of CPU.
#[derive(Clone)]
#[repr(C)]
pub struct FpRegs {
//buf: Aligned<A16, [u8; 512]>,
is_valid: bool,
}
impl FpRegs {
/// Create a new instance.
///
/// Note that a newly-created instance's floating point state is not
/// initialized, thus considered invalid (i.e., `self.is_valid() == false`).
pub fn new() -> Self {
//let buf = Aligned(unsafe { MaybeUninit::uninit().assume_init() });
//let is_valid = false;
//Self { buf, is_valid }
todo!("import aligned")
}
/// Save CPU's current floating pointer states into this instance.
pub fn save(&mut self) {
// unsafe {
// _fxsave(self.buf.as_mut_ptr() as *mut u8);
// }
self.is_valid = true;
}
/// Save the floating state given by a slice of u8.
///
/// It is the caller's responsibility to ensure that the source slice contains
/// data that is in xsave/xrstor format. The slice must have a length of 512 bytes.
///
/// After calling this method, the state of the instance will be considered valid.
pub unsafe fn save_from_slice(&mut self, src: &[u8]) {
//(&mut self.buf).copy_from_slice(src);
//self.is_valid = true;
}
/// Returns whether the instance can contains data in valid xsave/xrstor format.
pub fn is_valid(&self) -> bool {
self.is_valid
}
/// Clear the state of the instance.
///
/// This method does not reset the underlying buffer that contains the floating
/// point state; it only marks the buffer __invalid__.
pub fn clear(&mut self) {
self.is_valid = false;
}
/// Restore CPU's CPU floating pointer states from this instance.
///
/// Panic. If the current state is invalid, the method will panic.
pub fn restore(&self) {
assert!(self.is_valid);
//unsafe { _fxrstor(self.buf.as_ptr()) };
}
/// Returns the floating point state as a slice.
///
/// Note that the slice may contain garbage if `self.is_valid() == false`.
pub fn as_slice(&self) -> &[u8] {
//&*self.buf
todo!()
}
}
impl Default for FpRegs {
fn default() -> Self {
Self::new()
}
}

View File

@ -0,0 +1,38 @@
use core::marker::PhantomData;
use crate::prelude::*;
/// An I/O port, representing a specific address in the I/O address of x86.
pub struct IoPort<T> {
addr: u32,
_phantom: PhantomData<T>,
}
impl<T> IoPort<T> {
/// Create an I/O port.
///
/// # Safety
///
/// This function is marked unsafe as creating an I/O port is considered
/// a privileged operation.
pub unsafe fn new(addr: u32) -> Result<Self> {
todo!()
}
}
impl IoPort<u32> {
/// Get the address of this I/O port.
pub fn addr(&self) -> u32 {
todo!()
}
/// Read a value of `u32`.
pub fn read_u32(&self) -> u32 {
todo!()
}
/// Write a value of `u32`.
pub fn write_u32(&self, val: u32) {
todo!()
}
}

View File

@ -0,0 +1,46 @@
use crate::prelude::*;
/// An interupt request (IRQ) line.
pub struct IrqLine {}
impl IrqLine {
/// Acquire an interrupt request line.
///
/// # Safety
///
/// This function is marked unsafe as manipulating interrupt lines is
/// considered a dangerous operation.
pub unsafe fn acquire(irq_num: u32) -> Arc<Self> {
todo!()
}
/// Get the IRQ number.
pub fn num(&self) -> u32 {
todo!()
}
/// Register a callback that will be invoked when the IRQ is active.
///
/// A handle to the callback is returned. Dropping the handle
/// automatically unregisters the callback.
///
/// For each IRQ line, multiple callbacks may be registered.
pub fn on_active<F>(&self, callback: F) -> IrqCallbackHandle
where
F: Fn(&Self),
{
todo!()
}
}
/// The handle to a registered callback for a IRQ line.
///
/// When the handle is dropped, the callback will be unregistered automatically.
#[must_use]
pub struct IrqCallbackHandle {}
impl Drop for IrqCallbackHandle {
fn drop(&mut self) {
todo!("unregister the callback")
}
}

View File

@ -0,0 +1,7 @@
//! Device-related APIs.
mod io_port;
mod irq;
pub use self::io_port::IoPort;
pub use self::irq::{IrqCallbackHandle, IrqLine};

View File

@ -0,0 +1,8 @@
/// The error type which is returned from the APIs of this crate.
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum Error {
InvalidArgs,
NoMemory,
PageFault,
AccessDenied,
}

19
src/kxos-frame/src/lib.rs Normal file
View File

@ -0,0 +1,19 @@
//! The framework part of KxOS.
#![no_std]
#![allow(dead_code)]
#![allow(unused_variables)]
#![feature(negative_impls)]
extern crate alloc;
pub mod cpu;
pub mod device;
mod error;
pub mod prelude;
pub mod task;
pub mod timer;
pub mod user;
mod util;
pub mod vm;
pub use self::error::Error;

View File

@ -0,0 +1,10 @@
//! The prelude.
pub type Result<T> = core::result::Result<T, crate::error::Error>;
pub(crate) use alloc::boxed::Box;
pub(crate) use alloc::sync::Arc;
pub(crate) use alloc::vec::Vec;
pub(crate) use core::any::Any;
pub use crate::vm::{Paddr, Vaddr};

View File

@ -0,0 +1,5 @@
mod spin;
mod wait;
pub use self::spin::{SpinLock, SpinLockGuard};
pub use self::wait::{WaitQueue};

View File

@ -0,0 +1,39 @@
/// A spin lock.
pub struct SpinLock<T: ?Sized> {
val: T,
}
impl<T> SpinLock<T> {
/// Creates a new spin lock.
pub fn new(val: T) -> Self {
todo!()
}
/// Acquire the spin lock.
///
/// This method runs in a busy loop until the lock can be acquired.
/// After acquiring the spin lock, all interrupts are disabled.
pub fn lock(&self) -> SpinLockGuard<'a> {
todo!()
}
}
unsafe impl<T: ?Sized + Send> Send for SpinLock<T> {}
unsafe impl<T: ?Sized + Send> Sync for SpinLock<T> {}
/// The guard of a spin lock.
pub struct SpinLockGuard<'a, T: ?Sized + 'a> {
lock: &'a SpinLock<T>
}
impl<'a, T> Deref for SpinLockGuard<'a, T> {
type Target = T;
fn deref(&self) -> &T {
todo!()
}
}
impl<'a, T: ?Sized> !Send for SpinLockGuard<'a, T> {}
unsafe impl<T: ?Sized + Sync> Sync for SpinLockGuard<'_, T> {}

View File

@ -0,0 +1,69 @@
/// A wait queue.
///
/// One may wait on a wait queue to put its executing thread to sleep.
/// Multiple threads may be the waiters of a wait queue.
/// Other threads may invoke the `wake`-family methods of a wait queue to
/// wake up one or many waiter threads.
pub struct WaitQueue {}
impl WaitQueue {
/// Creates a new instance.
pub fn new() -> Self {
todo!()
}
/// Wait until some condition becomes true.
///
/// This method takes a closure that tests a user-given condition.
/// The method only returns if the condition becomes true.
/// A waker thread should first make the condition true, then invoke the
/// `wake`-family method. This ordering is important to ensure that waiter
/// threads do not lose any wakeup notifiations.
///
/// By taking a condition closure, this wait-wakeup mechanism becomes
/// more efficient and robust.
pub fn wait_until<F>(&self, mut cond: F)
where
F: FnMut() -> bool,
{
let waiter = Waiter::new();
self.enqueue(&waiter);
loop {
if (cond)() {
self.dequeue(&waiter);
return;
}
waiter.wait();
}
self.dequeue(&waiter);
}
/// Wake one waiter thread, if there is one.
pub fn wake_one(&self) {
todo!()
}
/// Wake all waiter threads.
pub fn wake_all(&self) {
todo!()
}
fn enqueue(&self, waiter: &Waiter) {
todo!()
}
fn dequeue(&self, waiter: &Waiter) {
todo!()
}
}
struct Waiter {}
impl Waiter {
pub fn new() -> Self {
todo!()
}
pub fn wait(&self) {
todo!()
}
}

View File

@ -0,0 +1,7 @@
//! Tasks are the unit of code execution.
mod scheduler;
mod task;
pub use self::scheduler::{set_scheduler, Scheduler};
pub use self::task::{Task, TaskStatus};

View File

@ -0,0 +1,19 @@
use crate::prelude::*;
use crate::task::Task;
/// A scheduler for tasks.
///
/// An implementation of scheduler can attach scheduler-related information
/// with the `TypeMap` returned from `task.data()`.
pub trait Scheduler {
fn enqueue(&self, task: Arc<Task>);
fn dequeue(&self) -> Option<Arc<Task>>;
}
/// Set the global task scheduler.
///
/// This must be called before invoking `Task::spawn`.
pub fn set_scheduler(scheduler: &'static dyn Scheduler) {
todo!()
}

View File

@ -0,0 +1,66 @@
use crate::prelude::*;
use crate::user::UserSpace;
/// A task that executes a function to the end.
pub struct Task {
func: Box<dyn FnOnce()>,
data: Box<dyn Any + Send + Sync>,
user_space: Option<UserSpace>,
}
impl Task {
/// Gets the current task.
pub fn current() -> Arc<Task> {
todo!()
}
/// Yields execution so that another task may be scheduled.
///
/// Note that this method cannot be simply named "yield" as the name is
/// a Rust keyword.
pub fn yield_now() {
todo!()
}
/// Spawns a task that executes a function.
///
/// Each task is associated with a per-task data and an optional user space.
/// If having a user space, then the task can switch to the user space to
/// execute user code. Multiple tasks can share a single user space.
pub fn spawn<F, T>(
task_fn: F,
task_data: T,
user_space: Option<Arc<UserSpace>>,
) -> Result<Arc<Self>>
where
F: FnOnce(),
T: Any + Send + Sync,
{
todo!()
}
/// Returns the task status.
pub fn status(&self) -> TaskStatus {
todo!()
}
/// Returns the task data.
pub fn data(&self) -> &dyn Any {
todo!()
}
/// Returns the user space of this task, if it has.
pub fn user_space(&self) -> Option<&Arc<UserSpace>> {
todo!()
}
}
/// The status of a task.
pub enum TaskStatus {
/// The task is runnable.
Runnable,
/// The task is sleeping.
Sleeping,
/// The task has exited.
Exited,
}

View File

@ -0,0 +1,43 @@
//! Timer.
use crate::prelude::*;
use core::time::Duration;
/// A timer invokes a callback function after a specified span of time elapsed.
///
/// A new timer is initially inactive. Only after a timeout value is set with
/// the `set` method can the timer become active and the callback function
/// be triggered.
///
/// 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 {}
impl Timer {
/// Creates a new instance, given a callback function.
pub fn new<F>(f: F) -> Result<Self>
where
F: FnMut(&Self),
{
todo!()
}
/// Set a timeout value.
///
/// If a timeout value is already set, the timeout value will be refreshed.
pub fn set(&self, timeout: Duration) {
todo!()
}
/// Returns the remaining timeout value.
///
/// If the timer is not set, then the remaining timeout value is zero.
pub fn remain(&self) -> Duration {
todo!()
}
/// Clear the timeout value.
pub fn clear(&self) {
todo!()
}
}

105
src/kxos-frame/src/user.rs Normal file
View File

@ -0,0 +1,105 @@
//! User space.
use crate::cpu::CpuContext;
use crate::prelude::*;
use crate::task::Task;
use crate::vm::VmSpace;
/// A user space.
///
/// Each user space has a VM address space and allows a task to execute in
/// user mode.
pub struct UserSpace {}
impl UserSpace {
/// Creates a new instance.
///
/// Each instance maintains a VM address space and the CPU state to enable
/// execution in the user space.
pub fn new(vm_space: VmSpace, cpu_ctx: CpuContext) -> Self {
todo!()
}
/// Returns the VM address space.
pub fn vm_space(&self) -> &VmSpace {
todo!()
}
/// Returns the user mode that is bound to the current task and user space.
///
/// See `UserMode` on how to use it to execute user code.
///
/// # Panic
///
/// This method is intended to only allow each task to have at most one
/// instance of `UserMode` initiated. If this method is called again before
/// the first instance for the current task is dropped, then the method
/// panics.
pub fn user_mode(&self) -> UserMode<'_> {
todo!()
}
}
/// Code execution in the user mode.
///
/// This type enables executing the code in user space from a task in the kernel
/// space safely.
///
/// Here is a sample code on how to use `UserMode`.
///
/// ```
/// let current = Task::current();
/// let user_space = current.user_space()
/// .expect("the current task is associated with a user space");
/// let mut user_mode = user_space.user_mode();
/// loop {
/// // Execute in the user space until some interesting user event occurs
/// let user_event = user_mode.execute();
/// todo!("handle the user event, e.g., syscall");
/// }
/// ```
pub struct UserMode<'a> {
current: Arc<Task>,
user_space: &'a Arc<UserSpace>,
}
// An instance of `UserMode` is bound to the current task. So it cannot be
impl<'a> !Send for UserMode<'a> {}
impl<'a> UserMode<'a> {
/// Starts executing in the user mode.
///
/// The method returns for one of three possible reasons indicated by `UserEvent`.
/// 1. The user invokes a system call;
/// 2. The user triggers an exception;
/// 3. The user triggers a fault.
///
/// After handling the user event and updating the user-mode CPU context,
/// this method can be invoked again to go back to the user space.
pub fn execute(&mut self) -> UserEvent {
todo!()
}
/// Returns an immutable reference the user-mode CPU context.
pub fn context(&self) -> &CpuContext {
todo!()
}
/// Returns a mutable reference the user-mode CPU context.
pub fn context_mut(&mut self) -> &mut CpuContext {
todo!()
}
}
/// A user event is what brings back the control of the CPU back from
/// the user space to the kernel space.
///
/// Note that hardware interrupts are not considered user events as they
/// are triggered by devices and not visible to user programs.
/// To handle interrupts, one should register callback funtions for
/// IRQ lines (`IrqLine`).
pub enum UserEvent {
Syscall,
Exception,
Fault,
}

View File

@ -0,0 +1,3 @@
mod type_map;
pub use self::type_map::TypeMap;

View File

@ -0,0 +1,26 @@
/// A type map is a collection whose keys are types, rather than values.
pub struct TypeMap {}
pub trait Any: core::any::Any + Send + Sync {}
impl TypeMap {
/// Creates an empty typed map.
pub fn new() -> Self {
todo!()
}
/// Inserts a new item of type `T`.
pub fn insert<T: Any>(&mut self, val: T) -> Option<T> {
todo!()
}
/// Gets an item of type `T`.
pub fn get<T: Any>(&self) -> Option<&T> {
todo!()
}
/// Gets an item of type `T`.
pub fn remove<T: Any>(&self) -> Option<T> {
todo!()
}
}

View File

@ -0,0 +1,172 @@
use core::iter::Iterator;
use crate::prelude::*;
/// A collection of page frames (physical memory pages).
///
/// For the most parts, `VmFrameVec` is like `Vec<VmFrame>`. But the
/// implementation may or may not be based on `Vec`. Having a dedicated
/// type to represent a series of page frames is convenient because,
/// more often than not, one needs to operate on a batch of frames rather
/// a single frame.
pub struct VmFrameVec(Vec<VmFrame>);
impl VmFrameVec {
/// Allocate a collection of free frames according to the given options.
///
/// All returned frames are safe to use in the sense that they are
/// not _typed memory_. We define typed memory as the memory that
/// may store Rust objects or affect Rust memory safety, e.g.,
/// the code and data segments of the OS kernel, the stack and heap
/// allocated for the OS kernel.
///
/// For more information, see `VmAllocOptions`.
pub fn allocate(options: &VmAllocOptions) -> Result<Self> {
todo!()
}
/// Pushs a new frame to the collection.
pub fn push(&mut self, new_frame: VmFrame) {
todo!()
}
/// Pop a frame from the collection.
pub fn pop(&mut self) -> Option<VmFrame> {
todo!()
}
/// Removes a frame at a position.
pub fn remove(&mut self, at: usize) -> VmFrame {
todo!()
}
/// Append some frames.
pub fn append(&mut self, more: VmFrameVec) -> Result<()> {
todo!()
}
/// Truncate some frames.
///
/// If `new_len >= self.len()`, then this method has no effect.
pub fn truncate(&mut self, new_len: usize) {
todo!()
}
/// Returns an iterator
pub fn iter(&self) -> VmFrameVecIter<'_> {
todo!()
}
/// Returns the number of frames.
pub fn len(&self) -> usize {
todo!()
}
/// Returns the number of bytes.
///
/// This method is equivalent to `self.len() * PAGE_SIZE`.
pub fn nbytes(&self) -> usize {
todo!()
}
}
/// An iterator for frames.
pub struct VmFrameVecIter<'a> {
frames: &'a VmFrameVec,
// more...
}
impl<'a> Iterator for VmFrameVecIter<'a> {
type Item = &'a VmFrame;
fn next(&mut self) -> Option<Self::Item> {
todo!()
}
}
/// Options for allocating physical memory pages (or frames).
/// See `VmFrameVec::alloc`.
pub struct VmAllocOptions {}
impl VmAllocOptions {
/// Creates new options for allocating the specified number of frames.
pub fn new(len: usize) -> Self {
todo!()
}
/// Sets the physical address of the first frame.
///
/// If the physical address is given, then the allocated frames will be
/// contiguous.
///
/// The default value is `None`.
pub fn paddr(&mut self, paddr: Option<Paddr>) -> &mut Self {
todo!()
}
/// Sets whether the allocated frames should be contiguous.
///
/// If the physical address is set, then the frames must be contiguous.
///
/// The default value is `false`.
pub fn is_contiguous(&mut self, is_contiguous: bool) -> &mut Self {
todo!()
}
/// Sets whether the pages can be accessed by devices through
/// Direct Memory Access (DMA).
///
/// In a TEE environment, DMAable pages are untrusted pages shared with
/// the VMM.
pub fn can_dma(&mut self, can_dma: bool) -> &mut Self {
todo!()
}
}
/// A handle to a page frame.
///
/// An instance of `VmFrame` is a handle to a page frame (a physical memory
/// page). A cloned `VmFrame` refers to the same page frame as the original.
/// As the original and cloned instances point to the same physical address,
/// they are treated as equal to each other. Behind the scene,
/// a reference counter is maintained for each page frame so that
/// when all instances of `VmFrame` that refer to the
/// same page frame are dropped, the page frame will be freed.
/// Free page frames are allocated in bulk by `VmFrameVec::allocate`.
pub struct VmFrame {}
impl VmFrame {
/// Creates a new VmFrame.
///
/// # Safety
///
/// The given physical address must be valid for use.
pub(crate) unsafe fn new(paddr: Paddr) -> Self {
todo!()
}
/// Returns the physical address of the page frame.
pub fn paddr(&self) -> Paddr {
todo!()
}
/// Returns whether the page frame is accessible by DMA.
///
/// In a TEE environment, DMAable pages are untrusted pages shared with
/// the VMM.
pub fn can_dma(&self) -> bool {
todo!()
}
}
impl Clone for VmFrame {
fn clone(&self) -> Self {
todo!("inc ref cnt")
}
}
impl Drop for VmFrame {
fn drop(&mut self) {
todo!("dec ref cnt and if zero, free the page frame")
}
}

View File

@ -0,0 +1,64 @@
use crate::prelude::*;
use crate::vm::Pod;
/// A trait that enables reading/writing data from/to a VM object,
/// e.g., `VmSpace`, `VmFrameVec`, and `VmFrame`.
///
/// # Concurrency
///
/// The methods may be executed by multiple concurrent reader and writer
/// threads. In this case, if the results of concurrent reads or writes
/// desire predictability or atomicity, the users should add extra mechanism
/// for such properties.
pub trait VmIo: Send + Sync {
/// Read a specified number of bytes at a specified offset into a given buffer.
///
/// # No short reads
///
/// On success, the output `buf` must be filled with the requested data
/// completely. If, for any reason, the requested data is only partially
/// available, then the method shall return an error.
fn read_bytes(&self, offset: usize, buf: &mut [u8]) -> Result<()>;
/// Read a value of a specified type at a specified offset.
fn read_val<T: Pod>(&self, offset: usize) -> Result<T> {
let mut val = T::new_uninit();
self.read_bytes(offset, val.as_bytes_mut())?;
Ok(val)
}
/// Read a slice of a specified type at a specified offset.
///
/// # No short reads
///
/// Similar to `read_bytes`.
fn read_slice<T: Pod>(&self, offset: usize, slice: &mut [T]) -> Result<()> {
let buf = unsafe { core::mem::transmute(slice) };
self.read_bytes(offset, buf)
}
/// Write a specified number of bytes from a given buffer at a specified offset.
///
/// # No short writes
///
/// On success, the input `buf` must be written to the VM object entirely.
/// If, for any reason, the input data can only be written partially,
/// then the method shall return an error.
fn write_bytes(&self, offset: usize, buf: &[u8]) -> Result<()>;
/// Write a value of a specified type at a specified offset.
fn write_val<T: Pod>(&self, offset: usize, new_val: &T) -> Result<()> {
self.write_bytes(offset, new_val.as_bytes())?;
Ok(())
}
/// Write a slice of a specified type at a specified offset.
///
/// # No short write
///
/// Similar to `write_bytes`.
fn write_slice<T: Pod>(&self, offset: usize, slice: &[T]) -> Result<()> {
let buf = unsafe { core::mem::transmute(slice) };
self.write_bytes(offset, buf)
}
}

View File

@ -0,0 +1,20 @@
//! Virtual memory (VM).
/// Virtual addresses.
pub type Vaddr = usize;
/// Physical addresses.
pub type Paddr = usize;
/// The size of a VM page or a page frame.
pub const PAGE_SIZE: usize = 0x1000; // 4KB
mod frame;
mod io;
mod pod;
mod space;
pub use self::frame::{VmAllocOptions, VmFrame, VmFrameVec, VmFrameVecIter};
pub use self::io::VmIo;
pub use self::pod::Pod;
pub use self::space::{VmMapOptions, VmPerm, VmSpace};

View File

@ -0,0 +1,60 @@
use core::mem::MaybeUninit;
/// A marker trait for plain old data (POD).
///
/// A POD type `T:Pod` supports converting to and from arbitrary
/// `mem::size_of::<T>()` bytes _safely_.
/// For example, simple primitive types like `u8` and `i16`
/// are POD types. But perhaps surprisingly, `bool` is not POD
/// because Rust compiler makes implicit assumption that
/// a byte of `bool` has a value of either `0` or `1`.
/// Interpreting a byte of value `3` has a `bool` value has
/// undefined behavior.
///
/// # Safety
///
/// Marking a non-POD type as POD may cause undefined behaviors.
pub unsafe trait Pod: Copy + Sized {
/// Creates a new instance of Pod type that is filled with zeroes.
fn new_zeroed() -> Self {
// SAFETY. An all-zero value of `T: Pod` is always valid.
unsafe { core::mem::zeroed() }
}
/// Creates a new instance of Pod type with uninitialized content.
fn new_uninit() -> Self {
// SAFETY. A value of `T: Pod` can have arbitrary bits.
unsafe { MaybeUninit::uninit().assume_init() }
}
/// Creates a new instance from the given bytes.
fn from_bytes(bytes: &[u8]) -> Self {
let mut new_self = Self::new_uninit();
new_self.as_bytes_mut().copy_from_slice(bytes);
new_self
}
/// As a slice of bytes.
fn as_bytes(&self) -> &[u8] {
let ptr = self as *const Self as *const u8;
let len = core::mem::size_of::<Self>();
unsafe { core::slice::from_raw_parts(ptr, len) }
}
/// As a mutable slice of bytes.
fn as_bytes_mut(&mut self) -> &mut [u8] {
let ptr = self as *mut Self as *mut u8;
let len = core::mem::size_of::<Self>();
unsafe { core::slice::from_raw_parts_mut(ptr, len) }
}
}
macro_rules! impl_pod_for {
($($token:tt)*/* define the input */) => {
/* define the expansion */
};
}
impl_pod_for!(u8, u16, u32, u64, i8, i16, i32, i64,);
//unsafe impl<T: Pod, const N> [T; N] for Pod {}

View File

@ -0,0 +1,112 @@
use bitflags::bitflags;
use core::ops::Range;
use crate::prelude::*;
use crate::vm::VmFrameVec;
/// Virtual memory space.
///
/// A virtual memory space (`VmSpace`) can be created and assigned to a user space so that
/// the virtual memory of the user space can be manipulated safely. For example,
/// given an arbitrary user-space pointer, one can read and write the memory
/// location refered to by the user-space pointer without the risk of breaking the
/// memory safety of the kernel space.
///
/// A newly-created `VmSpace` is not backed by any physical memory pages.
/// To provide memory pages for a `VmSpace`, one can allocate and map
/// physical memory (`VmFrames`) to the `VmSpace`.
pub struct VmSpace {}
impl VmSpace {
/// Creates a new VM address space.
pub fn new() -> Self {
todo!()
}
/// Maps some physical memory pages into the VM space according to the given
/// options, returning the address where the mapping is created.
///
/// For more information, see `VmMapOptions`.
pub fn map(&self, frames: VmFrameVec, options: &VmMapOptions) -> Result<Vaddr> {
todo!()
}
/// Unmaps the physical memory pages within the VM address range.
///
/// The range is allowed to contain gaps, where no physical memory pages
/// are mapped.
pub fn unmap(&self, range: &Range<Vaddr>) -> Result<()> {
todo!()
}
/// Update the VM protection permissions within the VM address range.
///
/// The entire specified VM range must have been mapped with physical
/// memory pages.
pub fn protect(&self, range: &Range<Vaddr>, perm: VmPerm) -> Result<()> {
todo!()
}
}
/// Options for mapping physical memory pages into a VM address space.
/// See `VmSpace::map`.
pub struct VmMapOptions {}
impl VmMapOptions {
/// Creates the default options.
pub fn new() -> Self {
todo!()
}
/// Sets the alignment of the address of the mapping.
///
/// The alignment must be a power-of-2 and greater than or equal to the
/// page size.
///
/// The default value of this option is the page size.
pub fn align(&mut self, align: usize) -> &mut Self {
todo!()
}
/// Sets the permissions of the mapping, which affects whether
/// the mapping can be read, written, or executed.
///
/// The default value of this option is read-only.
pub fn perm(&mut self, perm: VmPerm) -> &mut Self {
todo!()
}
/// Sets the address of the new mapping.
///
/// The default value of this option is `None`.
pub fn addr(&mut self, addr: Option<Vaddr>) -> &mut Self {
todo!()
}
/// Sets whether the mapping can overwrite any existing mappings.
///
/// If this option is `true`, then the address option must be `Some(_)`.
///
/// The default value of this option is `false`.
pub fn can_overwrite(&mut self, can_overwrite: bool) -> &mut Self {
todo!()
}
}
bitflags! {
/// Virtual memory protection permissions.
pub struct VmPerm: u8 {
/// Readable.
const R = 0b00000001;
/// Writable.
const W = 0b00000010;
/// Executable.
const X = 0b00000100;
/// Readable + writable.
const RW = Self::R.bits | Self::W.bits;
/// Readable + execuable.
const RX = Self::R.bits | Self::X.bits;
/// Readable + writable + executable.
const RWX = Self::R.bits | Self::W.bits | Self::X.bits;
}
}

2
src/rust-toolchain.toml Normal file
View File

@ -0,0 +1,2 @@
[toolchain]
channel = "nightly-2022-08-01"