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