mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-23 17:33:23 +00:00
Add missing docs in aster-frame
This commit is contained in:
committed by
Tate, Hongliang Tian
parent
a93f922a25
commit
6e59617fc7
@ -1,5 +1,9 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
//! Platform-specific code.
|
||||
//!
|
||||
//! Each architecture that Asterinas supports may contain a submodule here.
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
pub mod x86;
|
||||
|
||||
|
@ -1,5 +1,7 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
//! The console I/O.
|
||||
|
||||
#![allow(dead_code)]
|
||||
#![allow(unused_variables)]
|
||||
|
||||
@ -13,13 +15,16 @@ use trapframe::TrapFrame;
|
||||
use super::{device::serial::SerialPort, kernel::IO_APIC};
|
||||
use crate::{sync::SpinLock, trap::IrqLine};
|
||||
|
||||
/// Prints the formatted arguments to the standard output.
|
||||
#[inline]
|
||||
pub fn print(args: fmt::Arguments) {
|
||||
Stdout.write_fmt(args).unwrap();
|
||||
}
|
||||
|
||||
/// The callback function for console input.
|
||||
pub type InputCallback = dyn Fn(u8) + Send + Sync + 'static;
|
||||
|
||||
/// Registers a callback function to be called when there is console input.
|
||||
pub fn register_console_input_callback(f: &'static InputCallback) {
|
||||
SERIAL_INPUT_CALLBACKS.lock_irq_disabled().push(Arc::new(f));
|
||||
}
|
||||
|
@ -38,12 +38,14 @@ pub fn this_cpu() -> u32 {
|
||||
0
|
||||
}
|
||||
|
||||
/// A set of CPUs.
|
||||
#[derive(Default)]
|
||||
pub struct CpuSet {
|
||||
bitset: BitVec,
|
||||
}
|
||||
|
||||
impl CpuSet {
|
||||
/// Creates a new `CpuSet` with all CPUs included.
|
||||
pub fn new_full() -> Self {
|
||||
let num_cpus = num_cpus();
|
||||
let mut bitset = BitVec::with_capacity(num_cpus as usize);
|
||||
@ -51,6 +53,7 @@ impl CpuSet {
|
||||
Self { bitset }
|
||||
}
|
||||
|
||||
/// Creates a new `CpuSet` with no CPUs included.
|
||||
pub fn new_empty() -> Self {
|
||||
let num_cpus = num_cpus();
|
||||
let mut bitset = BitVec::with_capacity(num_cpus as usize);
|
||||
@ -58,38 +61,46 @@ impl CpuSet {
|
||||
Self { bitset }
|
||||
}
|
||||
|
||||
/// Adds a CPU with identifier `cpu_id` to the `CpuSet`.
|
||||
pub fn add(&mut self, cpu_id: u32) {
|
||||
self.bitset.set(cpu_id as usize, true);
|
||||
}
|
||||
|
||||
/// Adds multiple CPUs from a vector to the `CpuSet`.
|
||||
pub fn add_from_vec(&mut self, cpu_ids: Vec<u32>) {
|
||||
for cpu_id in cpu_ids {
|
||||
self.add(cpu_id)
|
||||
}
|
||||
}
|
||||
|
||||
/// Adds all available CPUs to the `CpuSet`.
|
||||
pub fn add_all(&mut self) {
|
||||
self.bitset.fill(true);
|
||||
}
|
||||
|
||||
/// Removes a CPU with identifier `cpu_id` from the `CpuSet`.
|
||||
pub fn remove(&mut self, cpu_id: u32) {
|
||||
self.bitset.set(cpu_id as usize, false);
|
||||
}
|
||||
|
||||
/// Removes multiple CPUs from a vector from the `CpuSet`.
|
||||
pub fn remove_from_vec(&mut self, cpu_ids: Vec<u32>) {
|
||||
for cpu_id in cpu_ids {
|
||||
self.remove(cpu_id);
|
||||
}
|
||||
}
|
||||
|
||||
/// Clears the `CpuSet`, removing all CPUs.
|
||||
pub fn clear(&mut self) {
|
||||
self.bitset.fill(false);
|
||||
}
|
||||
|
||||
/// Checks if the `CpuSet` contains a specific CPU.
|
||||
pub fn contains(&self, cpu_id: u32) -> bool {
|
||||
self.bitset.get(cpu_id as usize).as_deref() == Some(&true)
|
||||
}
|
||||
|
||||
/// Returns an iterator over the set CPUs.
|
||||
pub fn iter(&self) -> IterOnes<'_, usize, Lsb0> {
|
||||
self.bitset.iter_ones()
|
||||
}
|
||||
@ -104,11 +115,15 @@ pub struct UserContext {
|
||||
cpu_exception_info: CpuExceptionInfo,
|
||||
}
|
||||
|
||||
/// CPU exception information.
|
||||
#[derive(Clone, Default, Copy, Debug)]
|
||||
#[repr(C)]
|
||||
pub struct CpuExceptionInfo {
|
||||
/// The ID of the exception.
|
||||
pub id: usize,
|
||||
/// The error code associated with the exception.
|
||||
pub error_code: usize,
|
||||
/// The virtual address where a page fault occurred.
|
||||
pub page_fault_addr: usize,
|
||||
}
|
||||
|
||||
@ -212,6 +227,7 @@ impl TdxTrapFrame for GeneralRegs {
|
||||
}
|
||||
}
|
||||
|
||||
/// User Preemption.
|
||||
pub struct UserPreemption {
|
||||
count: u32,
|
||||
}
|
||||
@ -219,10 +235,12 @@ pub struct UserPreemption {
|
||||
impl UserPreemption {
|
||||
const PREEMPTION_INTERVAL: u32 = 100;
|
||||
|
||||
/// Creates a new instance of `UserPreemption`.
|
||||
pub const fn new() -> Self {
|
||||
UserPreemption { count: 0 }
|
||||
}
|
||||
|
||||
/// Checks if preemption might occur and takes necessary actions.
|
||||
pub fn might_preempt(&mut self) {
|
||||
self.count = (self.count + 1) % Self::PREEMPTION_INTERVAL;
|
||||
|
||||
@ -235,22 +253,27 @@ impl UserPreemption {
|
||||
}
|
||||
|
||||
impl UserContext {
|
||||
/// Returns a reference to the general registers.
|
||||
pub fn general_regs(&self) -> &GeneralRegs {
|
||||
&self.user_context.general
|
||||
}
|
||||
|
||||
/// Returns a mutable reference to the general registers
|
||||
pub fn general_regs_mut(&mut self) -> &mut GeneralRegs {
|
||||
&mut self.user_context.general
|
||||
}
|
||||
|
||||
/// Returns the trap information.
|
||||
pub fn trap_information(&self) -> &CpuExceptionInfo {
|
||||
&self.cpu_exception_info
|
||||
}
|
||||
|
||||
/// Returns a reference to the floating point registers
|
||||
pub fn fp_regs(&self) -> &FpRegs {
|
||||
&self.fp_regs
|
||||
}
|
||||
|
||||
/// Returns a mutable reference to the floating point registers
|
||||
pub fn fp_regs_mut(&mut self) -> &mut FpRegs {
|
||||
&mut self.fp_regs
|
||||
}
|
||||
@ -358,17 +381,26 @@ impl UserContextApiInternal for UserContext {
|
||||
/// So here we also define FaultOrTrap and Interrupt
|
||||
#[derive(PartialEq, Eq, Debug)]
|
||||
pub enum CpuExceptionType {
|
||||
/// CPU faults. Faults can be corrected, and the program may continue as if nothing happened.
|
||||
Fault,
|
||||
/// CPU traps. Traps are reported immediately after the execution of the trapping instruction
|
||||
Trap,
|
||||
/// Faults or traps
|
||||
FaultOrTrap,
|
||||
/// CPU interrupts
|
||||
Interrupt,
|
||||
/// Some severe unrecoverable error
|
||||
Abort,
|
||||
/// Reserved for future use
|
||||
Reserved,
|
||||
}
|
||||
|
||||
/// CPU exception.
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
pub struct CpuException {
|
||||
/// The ID of the CPU exception.
|
||||
pub number: u16,
|
||||
/// The type of the CPU exception.
|
||||
pub typ: CpuExceptionType,
|
||||
}
|
||||
|
||||
@ -390,6 +422,7 @@ macro_rules! define_cpu_exception {
|
||||
$($name,)*
|
||||
];
|
||||
$(
|
||||
#[doc = concat!("The ", stringify!($name), " exception")]
|
||||
pub const $name : CpuException = CpuException{
|
||||
number: $exception_num,
|
||||
typ: CpuExceptionType::$exception_type,
|
||||
@ -462,10 +495,12 @@ bitflags! {
|
||||
}
|
||||
|
||||
impl CpuException {
|
||||
/// Checks if the given `trap_num` is a valid CPU exception.
|
||||
pub fn is_cpu_exception(trap_num: u16) -> bool {
|
||||
trap_num < EXCEPTION_LIST.len() as u16
|
||||
}
|
||||
|
||||
/// Maps a `trap_num` to its corresponding CPU exception.
|
||||
pub fn to_cpu_exception(trap_num: u16) -> Option<&'static CpuException> {
|
||||
EXCEPTION_LIST.get(trap_num as usize)
|
||||
}
|
||||
@ -501,11 +536,13 @@ macro_rules! cpu_context_impl_getter_setter {
|
||||
( $( [ $field: ident, $setter_name: ident] ),*) => {
|
||||
impl UserContext {
|
||||
$(
|
||||
#[doc = concat!("Gets the value of ", stringify!($field))]
|
||||
#[inline(always)]
|
||||
pub fn $field(&self) -> usize {
|
||||
self.user_context.general.$field
|
||||
}
|
||||
|
||||
#[doc = concat!("Sets the value of ", stringify!(field))]
|
||||
#[inline(always)]
|
||||
pub fn $setter_name(&mut self, $field: usize) {
|
||||
self.user_context.general.$field = $field;
|
||||
|
@ -3,6 +3,9 @@
|
||||
//! Device-related APIs.
|
||||
//! This module mainly contains the APIs that should exposed to the device driver like PCI, RTC
|
||||
|
||||
// FIXME: remove this lint when the documentation of this module is extensively added.
|
||||
#![allow(missing_docs)]
|
||||
|
||||
pub mod cmos;
|
||||
pub mod io_port;
|
||||
pub mod serial;
|
||||
|
@ -1,5 +1,7 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
//! The IOMMU support.
|
||||
|
||||
mod context_table;
|
||||
mod fault;
|
||||
mod remapping;
|
||||
@ -17,9 +19,12 @@ use crate::{
|
||||
sync::Mutex,
|
||||
};
|
||||
|
||||
/// An enumeration representing possible errors related to IOMMU.
|
||||
#[derive(Debug)]
|
||||
pub enum IommuError {
|
||||
/// No IOMMU is available.
|
||||
NoIommu,
|
||||
/// Error encountered during modification of the page table.
|
||||
ModificationError(PageTableError),
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,7 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
//! Interrupts.
|
||||
|
||||
#![allow(dead_code)]
|
||||
|
||||
use alloc::{boxed::Box, fmt::Debug, sync::Arc, vec::Vec};
|
||||
|
@ -1,5 +1,7 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
//! Platform-specific code for the x86 platform.
|
||||
|
||||
pub mod boot;
|
||||
pub mod console;
|
||||
pub(crate) mod cpu;
|
||||
|
@ -10,7 +10,9 @@
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
#[repr(u32)]
|
||||
pub enum QemuExitCode {
|
||||
/// The code that indicates a successful exit.
|
||||
Success = 0x10,
|
||||
/// The code that indicates a failed exit.
|
||||
Failed = 0x20,
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,7 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
//! The architecture support of context switch.
|
||||
|
||||
use crate::task::TaskContextApi;
|
||||
|
||||
core::arch::global_asm!(include_str!("switch.S"));
|
||||
@ -23,12 +25,19 @@ impl TaskContext {
|
||||
#[derive(Debug, Default, Clone, Copy)]
|
||||
#[repr(C)]
|
||||
pub struct CalleeRegs {
|
||||
/// RSP
|
||||
pub rsp: u64,
|
||||
/// RBX
|
||||
pub rbx: u64,
|
||||
/// RBP
|
||||
pub rbp: u64,
|
||||
/// R12
|
||||
pub r12: u64,
|
||||
/// R13
|
||||
pub r13: u64,
|
||||
/// R14
|
||||
pub r14: u64,
|
||||
/// R15
|
||||
pub r15: u64,
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,7 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
//! The timer support.
|
||||
|
||||
mod apic;
|
||||
mod hpet;
|
||||
mod jiffies;
|
||||
|
@ -27,9 +27,12 @@ struct InitprocArgs {
|
||||
envp: Vec<CString>,
|
||||
}
|
||||
|
||||
/// Kernel module arguments
|
||||
#[derive(PartialEq, Debug, Clone)]
|
||||
pub enum ModuleArg {
|
||||
/// A string argument
|
||||
Arg(CString),
|
||||
/// A key-value argument
|
||||
KeyVal(CString, CString),
|
||||
}
|
||||
|
||||
|
@ -71,6 +71,7 @@ impl MemoryRegion {
|
||||
self.len
|
||||
}
|
||||
|
||||
/// Checks whether the region is empty
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.len == 0
|
||||
}
|
||||
|
@ -36,8 +36,11 @@ pub enum BootloaderAcpiArg {
|
||||
/// The framebuffer arguments.
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct BootloaderFramebufferArg {
|
||||
/// The address of the buffer.
|
||||
pub address: usize,
|
||||
/// The width of the buffer.
|
||||
pub width: usize,
|
||||
/// The height of the buffer.
|
||||
pub height: usize,
|
||||
/// Bits per pixel of the buffer.
|
||||
pub bpp: usize,
|
||||
|
@ -1,14 +1,23 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
//! Bus operations
|
||||
|
||||
// FIXME: remove this lint when the docs of the whole bus module are added.
|
||||
#![allow(missing_docs)]
|
||||
|
||||
pub mod mmio;
|
||||
pub mod pci;
|
||||
|
||||
/// An error that occurs during bus probing.
|
||||
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub enum BusProbeError {
|
||||
/// The device does not match the expected criteria.
|
||||
DeviceNotMatch,
|
||||
/// An error in accessing the configuration space of the device.
|
||||
ConfigurationSpaceError,
|
||||
}
|
||||
|
||||
/// Initializes the bus
|
||||
pub fn init() {
|
||||
pci::init();
|
||||
mmio::init();
|
||||
|
@ -1,11 +1,15 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
//! Console output.
|
||||
|
||||
use core::fmt::Arguments;
|
||||
|
||||
/// Prints formatted arguments to the console.
|
||||
pub fn print(args: Arguments) {
|
||||
crate::arch::console::print(args);
|
||||
}
|
||||
|
||||
/// Prints to the console.
|
||||
#[macro_export]
|
||||
macro_rules! early_print {
|
||||
($fmt: literal $(, $($arg: tt)+)?) => {
|
||||
@ -13,6 +17,7 @@ macro_rules! early_print {
|
||||
}
|
||||
}
|
||||
|
||||
/// Prints to the console, with a newline.
|
||||
#[macro_export]
|
||||
macro_rules! early_println {
|
||||
() => { $crate::early_print!("\n") };
|
||||
|
@ -5,13 +5,21 @@ use crate::mm::page_table::PageTableError;
|
||||
/// The error type which is returned from the APIs of this crate.
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||
pub enum Error {
|
||||
/// Invalid arguments provided.
|
||||
InvalidArgs,
|
||||
/// Insufficient memory available.
|
||||
NoMemory,
|
||||
/// Page fault occurred.
|
||||
PageFault,
|
||||
/// Access to a resource is denied.
|
||||
AccessDenied,
|
||||
/// Input/output error.
|
||||
IoError,
|
||||
/// Insufficient system resources.
|
||||
NotEnoughResources,
|
||||
/// Arithmetic Overflow occurred.
|
||||
Overflow,
|
||||
/// Memory mapping already exists for the given virtual address.
|
||||
MapAlreadyMappedVaddr,
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,7 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
//! I/O memory.
|
||||
|
||||
use core::{mem::size_of, ops::Range};
|
||||
|
||||
use pod::Pod;
|
||||
@ -9,6 +11,7 @@ use crate::{
|
||||
Error, Result,
|
||||
};
|
||||
|
||||
/// I/O memory.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct IoMem {
|
||||
virtual_address: Vaddr,
|
||||
@ -59,6 +62,8 @@ impl HasPaddr for IoMem {
|
||||
}
|
||||
|
||||
impl IoMem {
|
||||
/// Creates a new `IoMem`.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// User must ensure the given physical range is in the I/O memory region.
|
||||
@ -69,14 +74,21 @@ impl IoMem {
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the physical address of the I/O memory.
|
||||
pub fn paddr(&self) -> Paddr {
|
||||
self.virtual_address - LINEAR_MAPPING_BASE_VADDR
|
||||
}
|
||||
|
||||
/// Returns the length of the I/O memory region.
|
||||
pub fn length(&self) -> usize {
|
||||
self.limit
|
||||
}
|
||||
|
||||
/// Resizes the I/O memory region to the new `range`.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Returns an error if the new `range` is not within the current range.
|
||||
pub fn resize(&mut self, range: Range<Paddr>) -> Result<()> {
|
||||
let start_vaddr = paddr_to_vaddr(range.start);
|
||||
let virtual_end = self
|
||||
|
@ -20,6 +20,7 @@
|
||||
// const generic implementation. We are using this feature in a conservative manner.
|
||||
#![allow(incomplete_features)]
|
||||
#![no_std]
|
||||
#![warn(missing_docs)]
|
||||
|
||||
extern crate alloc;
|
||||
#[cfg(ktest)]
|
||||
|
@ -1,5 +1,7 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
//! Logging support.
|
||||
|
||||
use log::{Level, Metadata, Record};
|
||||
|
||||
use crate::early_println;
|
||||
|
@ -40,13 +40,16 @@ struct DmaStreamInner {
|
||||
/// prevents users from reading and writing to `DmaStream` unexpectedly.
|
||||
#[derive(Debug, PartialEq, Clone, Copy)]
|
||||
pub enum DmaDirection {
|
||||
/// Data flows to the device
|
||||
ToDevice,
|
||||
/// Data flows form the device
|
||||
FromDevice,
|
||||
/// Data flows both from and to the device
|
||||
Bidirectional,
|
||||
}
|
||||
|
||||
impl DmaStream {
|
||||
/// Establish DMA stream mapping for a given `Segment`.
|
||||
/// Establishes DMA stream mapping for a given [`Segment`].
|
||||
///
|
||||
/// The method fails if the segment already belongs to a DMA mapping.
|
||||
pub fn map(
|
||||
@ -98,7 +101,7 @@ impl DmaStream {
|
||||
})
|
||||
}
|
||||
|
||||
/// Get the underlying VM segment.
|
||||
/// Get the underlying [`VmSegment`].
|
||||
///
|
||||
/// Usually, the CPU side should not access the memory
|
||||
/// after the DMA mapping is established because
|
||||
@ -108,10 +111,12 @@ impl DmaStream {
|
||||
&self.inner.vm_segment
|
||||
}
|
||||
|
||||
/// Returns the number of frames
|
||||
pub fn nframes(&self) -> usize {
|
||||
self.inner.vm_segment.nframes()
|
||||
}
|
||||
|
||||
/// Returns the number of bytes
|
||||
pub fn nbytes(&self) -> usize {
|
||||
self.inner.vm_segment.nbytes()
|
||||
}
|
||||
@ -120,10 +125,13 @@ impl DmaStream {
|
||||
///
|
||||
/// This method should be called under one of the two conditions:
|
||||
/// 1. The data of the stream DMA mapping has been updated by the device side.
|
||||
/// The CPU side needs to call the `sync` method before reading data (e.g., using `read_bytes`).
|
||||
/// The CPU side needs to call the `sync` method before reading data (e.g., using [`read_bytes`]).
|
||||
/// 2. The data of the stream DMA mapping has been updated by the CPU side
|
||||
/// (e.g., using `write_bytes`).
|
||||
/// (e.g., using [`write_bytes`]).
|
||||
/// Before the CPU side notifies the device side to read, it must call the `sync` method first.
|
||||
///
|
||||
/// [`read_bytes`]: Self::read_bytes
|
||||
/// [`write_bytes`]: Self::write_bytes
|
||||
pub fn sync(&self, byte_range: Range<usize>) -> Result<(), Error> {
|
||||
if byte_range.end > self.nbytes() {
|
||||
return Err(Error::InvalidArgs);
|
||||
|
@ -31,6 +31,7 @@ pub enum DmaError {
|
||||
AlreadyMapped,
|
||||
}
|
||||
|
||||
/// Has mapped address in the device address space.
|
||||
pub trait HasDaddr {
|
||||
/// Get the base address of the mapping in the
|
||||
/// device address space.
|
||||
|
@ -107,13 +107,16 @@ pub(crate) const KERNEL_VADDR_RANGE: Range<Vaddr> = 0xffff_8000_0000_0000..0xfff
|
||||
|
||||
/// Get physical address trait
|
||||
pub trait HasPaddr {
|
||||
/// Returns the physical address.
|
||||
fn paddr(&self) -> Paddr;
|
||||
}
|
||||
|
||||
/// Checks if the given address is page-aligned.
|
||||
pub const fn is_page_aligned(p: usize) -> bool {
|
||||
(p & (PAGE_SIZE - 1)) == 0
|
||||
}
|
||||
|
||||
/// Memory regions used for frame buffer.
|
||||
pub static FRAMEBUFFER_REGIONS: Once<Vec<MemoryRegion>> = Once::new();
|
||||
|
||||
pub(crate) fn misc_init() {
|
||||
|
@ -9,7 +9,9 @@ use bitflags::bitflags;
|
||||
/// The property of a mapped virtual memory page.
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub struct PageProperty {
|
||||
/// The flags associated with the page,
|
||||
pub flags: PageFlags,
|
||||
/// The cache policy for the page.
|
||||
pub cache: CachePolicy,
|
||||
pub(crate) priv_flags: PrivilegedPageFlags,
|
||||
}
|
||||
|
@ -127,7 +127,7 @@ impl VmSpace {
|
||||
/// Query about the mapping information about a byte in virtual memory.
|
||||
/// This is more handy than [`query_range`], but less efficient if you want
|
||||
/// to query in a batch.
|
||||
///
|
||||
///
|
||||
/// [`query_range`]: VmSpace::query_range
|
||||
pub fn query(&self, vaddr: Vaddr) -> Result<Option<PageProperty>> {
|
||||
if !(0..MAX_USERSPACE_VADDR).contains(&vaddr) {
|
||||
|
@ -46,7 +46,7 @@ pub fn panic_handler(info: &core::panic::PanicInfo) -> ! {
|
||||
abort();
|
||||
}
|
||||
|
||||
// Aborts the QEMU
|
||||
/// Aborts the QEMU
|
||||
pub fn abort() -> ! {
|
||||
exit_qemu(QemuExitCode::Failed);
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
//! The prelude.
|
||||
|
||||
/// A specialized [`core::result::Result``] type for this crate.
|
||||
pub type Result<T> = core::result::Result<T, crate::error::Error>;
|
||||
|
||||
pub(crate) use alloc::{boxed::Box, sync::Arc, vec::Vec};
|
||||
|
@ -1,5 +1,7 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
//! Useful synchronization primitives.
|
||||
|
||||
mod atomic_bits;
|
||||
mod mutex;
|
||||
// TODO: refactor this rcu implementation
|
||||
|
@ -92,7 +92,10 @@ pub struct MutexGuard_<T: ?Sized, R: Deref<Target = Mutex<T>>> {
|
||||
mutex: R,
|
||||
}
|
||||
|
||||
/// A guard that provides exclusive access to the data protected by a [`Mutex`].
|
||||
pub type MutexGuard<'a, T> = MutexGuard_<T, &'a Mutex<T>>;
|
||||
|
||||
/// An guard that provides exclusive access to the data protected by a [`Arc<Mutex>`].
|
||||
pub type ArcMutexGuard<T> = MutexGuard_<T, Arc<Mutex<T>>>;
|
||||
|
||||
impl<T: ?Sized, R: Deref<Target = Mutex<T>>> Deref for MutexGuard_<T, R> {
|
||||
|
@ -544,7 +544,10 @@ pub struct RwLockReadGuard_<T: ?Sized, R: Deref<Target = RwLock<T>> + Clone> {
|
||||
inner: R,
|
||||
}
|
||||
|
||||
/// A guard that provides shared read access to the data protected by a [`RwLock`].
|
||||
pub type RwLockReadGuard<'a, T> = RwLockReadGuard_<T, &'a RwLock<T>>;
|
||||
|
||||
/// A guard that provides shared read access to the data protected by a [`Arc<RwLock>`].
|
||||
pub type ArcRwLockReadGuard<T> = RwLockReadGuard_<T, Arc<RwLock<T>>>;
|
||||
|
||||
impl<T: ?Sized, R: Deref<Target = RwLock<T>> + Clone> Deref for RwLockReadGuard_<T, R> {
|
||||
@ -575,7 +578,9 @@ pub struct RwLockWriteGuard_<T: ?Sized, R: Deref<Target = RwLock<T>> + Clone> {
|
||||
inner: R,
|
||||
}
|
||||
|
||||
/// A guard that provides exclusive write access to the data protected by a [`RwLock`].
|
||||
pub type RwLockWriteGuard<'a, T> = RwLockWriteGuard_<T, &'a RwLock<T>>;
|
||||
/// A guard that provides exclusive write access to the data protected by a [`Arc<RwLock>`].
|
||||
pub type ArcRwLockWriteGuard<T> = RwLockWriteGuard_<T, Arc<RwLock<T>>>;
|
||||
|
||||
impl<T: ?Sized, R: Deref<Target = RwLock<T>> + Clone> Deref for RwLockWriteGuard_<T, R> {
|
||||
@ -644,7 +649,9 @@ pub struct RwLockUpgradeableGuard_<T: ?Sized, R: Deref<Target = RwLock<T>> + Clo
|
||||
inner: R,
|
||||
}
|
||||
|
||||
/// A upgradable guard that provides read access to the data protected by a [`RwLock`].
|
||||
pub type RwLockUpgradeableGuard<'a, T> = RwLockUpgradeableGuard_<T, &'a RwLock<T>>;
|
||||
/// A upgradable guard that provides read access to the data protected by a [`Arc<RwLock>`].
|
||||
pub type ArcRwLockUpgradeableGuard<T> = RwLockUpgradeableGuard_<T, Arc<RwLock<T>>>;
|
||||
|
||||
impl<T: ?Sized, R: Deref<Target = RwLock<T>> + Clone> RwLockUpgradeableGuard_<T, R> {
|
||||
|
@ -225,7 +225,9 @@ pub struct RwMutexReadGuard_<T: ?Sized, R: Deref<Target = RwMutex<T>>> {
|
||||
inner: R,
|
||||
}
|
||||
|
||||
/// A guard that provides shared read access to the data protected by a [`RwMutex`].
|
||||
pub type RwMutexReadGuard<'a, T> = RwMutexReadGuard_<T, &'a RwMutex<T>>;
|
||||
/// A guard that provides shared read access to the data protected by a [`Arc<RwMutex>`].
|
||||
pub type ArcRwMutexReadGuard<T> = RwMutexReadGuard_<T, Arc<RwMutex<T>>>;
|
||||
|
||||
impl<T: ?Sized, R: Deref<Target = RwMutex<T>>> Deref for RwMutexReadGuard_<T, R> {
|
||||
@ -250,7 +252,9 @@ pub struct RwMutexWriteGuard_<T: ?Sized, R: Deref<Target = RwMutex<T>>> {
|
||||
inner: R,
|
||||
}
|
||||
|
||||
/// A guard that provides exclusive write access to the data protected by a [`RwMutex`].
|
||||
pub type RwMutexWriteGuard<'a, T> = RwMutexWriteGuard_<T, &'a RwMutex<T>>;
|
||||
/// A guard that provides exclusive write access to the data protected by a [`Arc<RwMutex>`].
|
||||
pub type ArcRwMutexWriteGuard<T> = RwMutexWriteGuard_<T, Arc<RwMutex<T>>>;
|
||||
|
||||
impl<T: ?Sized, R: Deref<Target = RwMutex<T>>> Deref for RwMutexWriteGuard_<T, R> {
|
||||
@ -315,7 +319,9 @@ pub struct RwMutexUpgradeableGuard_<T: ?Sized, R: Deref<Target = RwMutex<T>>> {
|
||||
inner: R,
|
||||
}
|
||||
|
||||
/// A upgradable guard that provides read access to the data protected by a [`RwMutex`].
|
||||
pub type RwMutexUpgradeableGuard<'a, T> = RwMutexUpgradeableGuard_<T, &'a RwMutex<T>>;
|
||||
/// A upgradable guard that provides read access to the data protected by a [`Arc<RwMutex>`].
|
||||
pub type ArcRwMutexUpgradeableGuard<T> = RwMutexUpgradeableGuard_<T, Arc<RwMutex<T>>>;
|
||||
|
||||
impl<T: ?Sized, R: Deref<Target = RwMutex<T>> + Clone> RwMutexUpgradeableGuard_<T, R> {
|
||||
|
@ -135,7 +135,9 @@ enum InnerGuard {
|
||||
PreemptGuard(DisablePreemptGuard),
|
||||
}
|
||||
|
||||
/// A guard that provides exclusive access to the data protected by a [`SpinLock`].
|
||||
pub type SpinLockGuard<'a, T> = SpinLockGuard_<T, &'a SpinLock<T>>;
|
||||
/// A guard that provides exclusive access to the data protected by a [`Arc<SpinLock>`].
|
||||
pub type ArcSpinLockGuard<T> = SpinLockGuard_<T, Arc<SpinLock<T>>>;
|
||||
|
||||
/// The guard of a spin lock that disables the local IRQs.
|
||||
|
@ -3,6 +3,7 @@
|
||||
pub const REAL_TIME_TASK_PRIORITY: u16 = 100;
|
||||
|
||||
/// The priority of a task.
|
||||
///
|
||||
/// Similar to Linux, a larger value represents a lower priority,
|
||||
/// with a range of 0 to 139. Priorities ranging from 0 to 99 are considered real-time,
|
||||
/// while those ranging from 100 to 139 are considered normal.
|
||||
@ -10,39 +11,52 @@ pub const REAL_TIME_TASK_PRIORITY: u16 = 100;
|
||||
pub struct Priority(u16);
|
||||
|
||||
impl Priority {
|
||||
/// Creates a new `Priority` with the specified value.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if the `val` is greater than 139.
|
||||
pub const fn new(val: u16) -> Self {
|
||||
assert!(val <= 139);
|
||||
Self(val)
|
||||
}
|
||||
|
||||
/// Returns a `Priority` representing the lowest priority (139).
|
||||
pub const fn lowest() -> Self {
|
||||
Self::new(139)
|
||||
}
|
||||
|
||||
/// Returns a `Priority` representing a low priority.
|
||||
pub const fn low() -> Self {
|
||||
Self::new(110)
|
||||
}
|
||||
|
||||
/// Returns a `Priority` representing a normal priority.
|
||||
pub const fn normal() -> Self {
|
||||
Self::new(100)
|
||||
}
|
||||
|
||||
/// Returns a `Priority` representing a high priority.
|
||||
pub const fn high() -> Self {
|
||||
Self::new(10)
|
||||
}
|
||||
|
||||
/// Returns a `Priority` representing the highest priority (0).
|
||||
pub const fn highest() -> Self {
|
||||
Self::new(0)
|
||||
}
|
||||
|
||||
/// Sets the value of the `Priority`.
|
||||
pub const fn set(&mut self, val: u16) {
|
||||
self.0 = val;
|
||||
}
|
||||
|
||||
/// Returns the value of the `Priority`.
|
||||
pub const fn get(self) -> u16 {
|
||||
self.0
|
||||
}
|
||||
|
||||
/// Checks if the `Priority` is considered a real-time priority.
|
||||
pub const fn is_real_time(&self) -> bool {
|
||||
self.0 < REAL_TIME_TASK_PRIORITY
|
||||
}
|
||||
|
@ -55,6 +55,7 @@ pub fn take_current_task() -> Option<Arc<Task>> {
|
||||
})
|
||||
}
|
||||
|
||||
/// Retrieves the current task running on the processor.
|
||||
pub fn current_task() -> Option<Arc<Task>> {
|
||||
CpuLocal::borrow_with(&PROCESSOR, |processor| processor.borrow().current())
|
||||
}
|
||||
@ -72,10 +73,10 @@ pub fn schedule() {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: This interface of this method is error prone.
|
||||
// The method takes an argument for the current task to optimize its efficiency,
|
||||
// but the argument provided by the caller may not be the current task, really.
|
||||
// Thus, this method should be removed or reworked in the future.
|
||||
/// TODO: This interface of this method is error prone.
|
||||
/// The method takes an argument for the current task to optimize its efficiency,
|
||||
/// but the argument provided by the caller may not be the current task, really.
|
||||
/// Thus, this method should be removed or reworked in the future.
|
||||
pub fn preempt(task: &Arc<Task>) {
|
||||
// TODO: Refactor `preempt` and `schedule`
|
||||
// after the Atomic mode and `might_break` is enabled.
|
||||
@ -219,6 +220,7 @@ impl Drop for DisablePreemptGuard {
|
||||
}
|
||||
}
|
||||
|
||||
/// Disables preemption.
|
||||
#[must_use]
|
||||
pub fn disable_preempt() -> DisablePreemptGuard {
|
||||
DisablePreemptGuard::new()
|
||||
|
@ -18,8 +18,10 @@ lazy_static! {
|
||||
/// An implementation of scheduler can attach scheduler-related information
|
||||
/// with the `TypeMap` returned from `task.data()`.
|
||||
pub trait Scheduler: Sync + Send {
|
||||
/// Enqueues a task to the scheduler.
|
||||
fn enqueue(&self, task: Arc<Task>);
|
||||
|
||||
/// Dequeues a task from the scheduler.
|
||||
fn dequeue(&self) -> Option<Arc<Task>>;
|
||||
|
||||
/// Tells whether the given task should be preempted by other tasks in the queue.
|
||||
@ -61,6 +63,7 @@ pub fn fetch_task() -> Option<Arc<Task>> {
|
||||
GLOBAL_SCHEDULER.lock_irq_disabled().dequeue()
|
||||
}
|
||||
|
||||
/// Adds a task to the global scheduler.
|
||||
pub fn add_task(task: Arc<Task>) {
|
||||
GLOBAL_SCHEDULER.lock_irq_disabled().enqueue(task);
|
||||
}
|
||||
|
@ -1,5 +1,8 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
// FIXME: the `intrusive_adapter` macro will generate methods without docs.
|
||||
// So we temporary allow missing_docs for this module.
|
||||
#![allow(missing_docs)]
|
||||
#![allow(dead_code)]
|
||||
|
||||
use core::cell::UnsafeCell;
|
||||
@ -22,6 +25,7 @@ use crate::{
|
||||
|
||||
pub const KERNEL_STACK_SIZE: usize = PAGE_SIZE * 64;
|
||||
|
||||
/// Trait for manipulating the task context.
|
||||
pub trait TaskContextApi {
|
||||
/// Set instruction pointer
|
||||
fn set_instruction_pointer(&mut self, ip: usize);
|
||||
@ -195,6 +199,7 @@ impl Task {
|
||||
unreachable!()
|
||||
}
|
||||
|
||||
/// Checks if the task has a real-time priority.
|
||||
pub fn is_real_time(&self) -> bool {
|
||||
self.priority.is_real_time()
|
||||
}
|
||||
@ -238,6 +243,7 @@ impl TaskOptions {
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets the function that represents the entry point of the task.
|
||||
pub fn func<F>(mut self, func: F) -> Self
|
||||
where
|
||||
F: Fn() + Send + Sync + 'static,
|
||||
@ -246,6 +252,7 @@ impl TaskOptions {
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the data associated with the task.
|
||||
pub fn data<T>(mut self, data: T) -> Self
|
||||
where
|
||||
T: Any + Send + Sync,
|
||||
@ -266,6 +273,10 @@ impl TaskOptions {
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the CPU affinity mask for the task.
|
||||
///
|
||||
/// The `cpu_affinity` parameter is an instance of the [`CpuSet`] struct
|
||||
/// that represents the desired set of CPUs to run the task on.
|
||||
pub fn cpu_affinity(mut self, cpu_affinity: CpuSet) -> Self {
|
||||
self.cpu_affinity = cpu_affinity;
|
||||
self
|
||||
|
@ -13,12 +13,16 @@ use crate::{
|
||||
Error,
|
||||
};
|
||||
|
||||
/// Type alias for the irq callback function.
|
||||
pub type IrqCallbackFunction = dyn Fn(&TrapFrame) + Sync + Send + 'static;
|
||||
|
||||
/// An Interrupt ReQuest(IRQ) line. User can use `alloc` or `alloc_specific` to get specific IRQ line.
|
||||
/// An Interrupt ReQuest(IRQ) line. User can use [`alloc`] or [`alloc_specific`] to get specific IRQ line.
|
||||
///
|
||||
/// The IRQ number is guaranteed to be external IRQ number and user can register callback functions to this IRQ resource.
|
||||
/// When this resource is dropped, all the callback in this will be unregistered automatically.
|
||||
///
|
||||
/// [`alloc`]: Self::alloc
|
||||
/// [`alloc_specific`]: Self::alloc_specific
|
||||
#[derive(Debug)]
|
||||
#[must_use]
|
||||
pub struct IrqLine {
|
||||
@ -29,6 +33,7 @@ pub struct IrqLine {
|
||||
}
|
||||
|
||||
impl IrqLine {
|
||||
/// Allocates a specific IRQ line.
|
||||
pub fn alloc_specific(irq: u8) -> Result<Self> {
|
||||
IRQ_ALLOCATOR
|
||||
.get()
|
||||
@ -39,6 +44,7 @@ impl IrqLine {
|
||||
.ok_or(Error::NotEnoughResources)
|
||||
}
|
||||
|
||||
/// Allocates an available IRQ line.
|
||||
pub fn alloc() -> Result<Self> {
|
||||
let Some(irq_num) = IRQ_ALLOCATOR.get().unwrap().lock().alloc() else {
|
||||
return Err(Error::NotEnoughResources);
|
||||
@ -71,6 +77,7 @@ impl IrqLine {
|
||||
self.callbacks.push(self.irq.on_active(callback))
|
||||
}
|
||||
|
||||
/// Checks if there are no registered callbacks.
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.callbacks.is_empty()
|
||||
}
|
||||
|
@ -1,5 +1,7 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
//! Handle trap across kernel and user space.
|
||||
|
||||
mod handler;
|
||||
mod irq;
|
||||
pub mod softirq;
|
||||
|
@ -112,6 +112,7 @@ pub struct UserMode<'a> {
|
||||
impl<'a> !Send for UserMode<'a> {}
|
||||
|
||||
impl<'a> UserMode<'a> {
|
||||
/// Creates a new `UserMode`.
|
||||
pub fn new(user_space: &'a Arc<UserSpace>) -> Self {
|
||||
Self {
|
||||
current: Task::current(),
|
||||
|
@ -5,4 +5,4 @@ edition = "2021"
|
||||
description = " An extension trait for Rust integer types to make integers aligned to a power of two"
|
||||
license = "MPL-2.0"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
Reference in New Issue
Block a user