1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215
use alloc::{boxed::Box, string::String, sync::Arc, vec::Vec};
use core::{any::Any, future::Future, ops::Range, time::Duration};
use crate::drivers::prelude::{IrqHandler, IrqPolarity, IrqTriggerMode};
use crate::{common, HalResult, KernelConfig, KernelHandler, PhysAddr, VirtAddr};
hal_fn_def! {
/// Bootstrap and initialization.
pub mod boot {
/// The kernel command line.
///
/// TODO: use `&'a str` as return type.
pub fn cmdline() -> String { String::new() }
/// Returns the slice of the initial RAM disk, or `None` if not exist.
pub fn init_ram_disk() -> Option<&'static mut [u8]> {
None
}
/// Initialize the primary CPU at an early stage (before the physical frame allocator).
pub fn primary_init_early(cfg: KernelConfig, handler: &'static impl KernelHandler) {}
/// The main part of the primary CPU initialization.
pub fn primary_init();
/// Initialize the secondary CPUs.
pub fn secondary_init() {}
}
/// CPU information.
pub mod cpu {
/// Current CPU ID.
pub fn cpu_id() -> u8 { 0 }
/// Current CPU frequency in MHz.
pub fn cpu_frequency() -> u16 { 3000 }
/// Shutdown/reboot the machine.
pub fn reset() -> !;
}
/// Physical memory operations.
pub mod mem: common::mem {
/// Convert physical address to virtual address.
pub fn phys_to_virt(paddr: PhysAddr) -> VirtAddr;
/// Convert virtual address to physical address.
pub fn virt_to_phys(vaddr: VirtAddr) -> PhysAddr;
/// Returns all free physical memory regions.
pub fn free_pmem_regions() -> Vec<Range<PhysAddr>>;
/// Read physical memory from `paddr` to `buf`.
pub fn pmem_read(paddr: PhysAddr, buf: &mut [u8]);
/// Write physical memory to `paddr` from `buf`.
pub fn pmem_write(paddr: PhysAddr, buf: &[u8]);
/// Zero physical memory at `[paddr, paddr + len)`.
pub fn pmem_zero(paddr: PhysAddr, len: usize);
/// Copy content of physical memory `src` to `dst` with `len` bytes.
pub fn pmem_copy(dst: PhysAddr, src: PhysAddr, len: usize);
/// Flush the physical frame.
pub fn frame_flush(target: PhysAddr);
}
/// Virtual memory operations.
pub mod vm: common::vm {
/// Read the current VM token, which is the page table root address on
/// various architectures. (e.g. CR3, SATP, ...)
pub fn current_vmtoken() -> PhysAddr;
/// Activate the page table associated with the `vmtoken` by writing the
/// page table root address.
pub fn activate_paging(vmtoken: PhysAddr);
/// Flush TLB by the associated `vaddr`, or flush the entire TLB. (`vaddr` is `None`).
pub(crate) fn flush_tlb(vaddr: Option<VirtAddr>);
/// Clone kernel space entries (top level only) from `src` page table to `dst` page table.
pub(crate) fn pt_clone_kernel_space(dst_pt_root: PhysAddr, src_pt_root: PhysAddr);
}
/// Interrupts management.
pub mod interrupt {
/// Suspend the CPU (also enable interrupts) and wait for an interrupt
/// to occurs, then disable interrupts.
pub fn wait_for_interrupt() {
core::hint::spin_loop();
}
/// Is a valid IRQ number.
pub fn is_valid_irq(vector: usize) -> bool;
/// Enable the interrupts
pub fn intr_on();
/// Disable the interrupts
pub fn intr_off();
/// Test weather interrupt is enabled
pub fn intr_get() -> bool;
/// Disable IRQ.
pub fn mask_irq(vector: usize) -> HalResult;
/// Enable IRQ.
pub fn unmask_irq(vector: usize) -> HalResult;
/// Configure the specified interrupt vector. If it is invoked, it must be
/// invoked prior to interrupt registration.
pub fn configure_irq(vector: usize, tm: IrqTriggerMode, pol: IrqPolarity) -> HalResult;
/// Add an interrupt handler to an IRQ.
pub fn register_irq_handler(vector: usize, handler: IrqHandler) -> HalResult;
/// Remove the interrupt handler to an IRQ.
pub fn unregister_irq_handler(vector: usize) -> HalResult;
/// Handle IRQ.
pub fn handle_irq(vector: usize);
/// Method used for platform allocation of blocks of MSI and MSI-X compatible
/// IRQ targets.
pub fn msi_alloc_block(requested_irqs: usize) -> HalResult<Range<usize>>;
/// Method used to free a block of MSI IRQs previously allocated by msi_alloc_block().
/// This does not unregister IRQ handlers.
pub fn msi_free_block(block: Range<usize>) -> HalResult;
/// Register a handler function for a given msi_id within an msi_block_t. Passing a
/// NULL handler will effectively unregister a handler for a given msi_id within the
/// block.
pub fn msi_register_handler(block: Range<usize>, msi_id: usize, handler: IrqHandler) -> HalResult;
pub fn send_ipi(cpuid: usize, reason: usize) -> HalResult;
pub fn ipi_reason() -> Vec<usize>;
}
pub mod console {
pub fn console_write_early(_s: &str) {}
}
/// Thread spawning.
pub mod thread: common::thread {
/// Spawn a new thread.
pub fn spawn(future: impl Future<Output = ()> + Send + 'static);
/// Set tid and pid of current task.
pub fn set_current_thread(thread: Option<Arc<dyn Any + Send + Sync>>) {}
/// Get tid and pid of current task.
pub fn get_current_thread() -> Option<Arc<dyn Any + Send + Sync>> { None }
}
/// Time and clock functions.
pub mod timer {
/// Set the first time interrupt
pub fn timer_enable();
/// Get current time.
/// TODO: use `Instant` as return type.
pub fn timer_now() -> Duration;
/// Converting from now-relative durations to absolute deadlines.
pub fn deadline_after(dur: Duration) -> Duration {
timer_now() + dur
}
/// Set a new timer. After `deadline`, the `callback` will be called.
/// TODO: use `Instant` as the type of `deadline`.
pub fn timer_set(deadline: Duration, callback: Box<dyn FnOnce(Duration) + Send + Sync>);
/// Check timers, call when timer interrupt happened.
pub(crate) fn timer_tick();
}
/// Random number generator.
pub mod rand {
/// Fill random bytes to the buffer
#[allow(unused_variables)]
pub fn fill_random(buf: &mut [u8]) {
cfg_if! {
if #[cfg(target_arch = "x86_64")] {
// TODO: optimize
for x in buf.iter_mut() {
let mut r = 0;
unsafe { core::arch::x86_64::_rdrand16_step(&mut r) };
*x = r as _;
}
} else {
static mut SEED: u64 = 0xdead_beef_cafe_babe;
for x in buf.iter_mut() {
unsafe {
// from musl
SEED = SEED.wrapping_mul(0x5851_f42d_4c95_7f2d);
*x = (SEED >> 33) as u8;
}
}
}
}
}
}
/// VDSO constants.
pub mod vdso: common::vdso {
/// Get platform specific information.
pub fn vdso_constants() -> VdsoConstants {
vdso_constants_template()
}
}
}