forked from AbleOS/ableos
Merge branch 'master' of ssh://git.ablecorp.us:20/able/ableos
This commit is contained in:
commit
6f306b9ece
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -429,6 +429,7 @@ dependencies = [
|
|||
name = "kernel"
|
||||
version = "0.1.2"
|
||||
dependencies = [
|
||||
"linked_list_allocator",
|
||||
"log",
|
||||
"versioning",
|
||||
]
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::allocator::{HEAP_SIZE, HEAP_START};
|
||||
use alloc::alloc::{GlobalAlloc, Layout};
|
||||
use core::ptr::null_mut;
|
||||
use kernel::allocator::{HEAP_SIZE, HEAP_START};
|
||||
use x86_64::{
|
||||
structures::paging::{
|
||||
mapper::MapToError, FrameAllocator, Mapper, Page, PageTableFlags, Size4KiB,
|
||||
|
@ -39,7 +39,7 @@ pub fn init_heap(
|
|||
}
|
||||
|
||||
unsafe {
|
||||
crate::allocator::ALLOCATOR
|
||||
kernel::allocator::ALLOCATOR
|
||||
.lock()
|
||||
.init(HEAP_START, HEAP_SIZE);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use super::systeminfo::SystemMemory;
|
||||
use crate::{arch::drivers::sysinfo::master, ALLOCATOR};
|
||||
use crate::arch::drivers::sysinfo::master;
|
||||
use core::fmt::Display;
|
||||
use kernel::allocator::ALLOCATOR;
|
||||
use versioning::Version;
|
||||
use x86_64::instructions::interrupts::{disable, enable};
|
||||
|
||||
|
|
|
@ -40,7 +40,6 @@ pub mod print;
|
|||
#[macro_use]
|
||||
pub mod serial_print;
|
||||
|
||||
pub mod allocator;
|
||||
pub mod boot_conf;
|
||||
pub mod devices;
|
||||
pub mod driver_traits;
|
||||
|
@ -68,7 +67,6 @@ mod unicode_utils;
|
|||
#[prelude_import]
|
||||
pub use prelude::rust_2021::*;
|
||||
|
||||
pub use allocator::*;
|
||||
pub use driver_traits::*;
|
||||
pub use experiments::*;
|
||||
pub use graphics::*;
|
||||
|
|
|
@ -2,13 +2,13 @@ use crate::arch::drivers::sysinfo::master;
|
|||
use crate::filesystem::FILE_SYSTEM;
|
||||
use crate::time::fetch_time;
|
||||
use crate::wasm_jumploader::interp;
|
||||
use crate::ALLOCATOR;
|
||||
use crate::{
|
||||
arch::{shutdown, sloop},
|
||||
systeminfo::{KERNEL_VERSION, RELEASE_TYPE},
|
||||
KERNEL_STATE,
|
||||
};
|
||||
use genfs::{Fs, OpenOptions};
|
||||
use kernel::allocator::ALLOCATOR;
|
||||
use rhai::Engine;
|
||||
use spin::Lazy;
|
||||
use x86_64::instructions::interrupts::{disable, enable};
|
||||
|
|
|
@ -1,15 +1,51 @@
|
|||
use core::alloc::Layout;
|
||||
|
||||
use crate::arch::generate_process_pass;
|
||||
use crate::arch::interrupts::{reset_pit_for_cpu, set_pit_2};
|
||||
use crate::devices::{self, pci, pci_inner};
|
||||
use crate::encoding::bin;
|
||||
use crate::port_io::{read32, read8, write8};
|
||||
use crate::devices::pci;
|
||||
use crate::filesystem::FILE_SYSTEM;
|
||||
use crate::rhai_shell::shell;
|
||||
use crate::rhai_shell::KEYBUFF;
|
||||
use crate::wasm_jumploader::run_program;
|
||||
use acpi::{AcpiTables, PlatformInfo};
|
||||
use cpuio::inb;
|
||||
use cpuio::outb;
|
||||
use genfs::Fs;
|
||||
use genfs::OpenOptions;
|
||||
|
||||
// TODO: move to a better place
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub struct AcpiStruct {}
|
||||
impl acpi::AcpiHandler for AcpiStruct {
|
||||
unsafe fn map_physical_region<T>(
|
||||
&self,
|
||||
physical_address: usize,
|
||||
size: usize,
|
||||
) -> acpi::PhysicalMapping<Self, T> {
|
||||
info!("PHYS ADDR: {:?}", physical_address);
|
||||
info!("Size: {:?}", size);
|
||||
todo!("map_physical_region");
|
||||
}
|
||||
fn unmap_physical_region<T>(_region: &acpi::PhysicalMapping<Self, T>) {
|
||||
todo!("unmap_physical_region");
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Path {
|
||||
pub path: Vec<String>,
|
||||
}
|
||||
|
||||
impl Path {
|
||||
pub fn new(path: String) -> Self {
|
||||
let mut path_vec_string = vec![];
|
||||
|
||||
for part in path.split(&['\\', '/'][..]) {
|
||||
path_vec_string.push(part.to_string());
|
||||
}
|
||||
|
||||
Path {
|
||||
path: path_vec_string,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Experimental scratchpad for testing.
|
||||
pub fn scratchpad() {
|
||||
|
@ -22,7 +58,7 @@ pub fn scratchpad() {
|
|||
}";
|
||||
let axel = axel::parse(axel_raw.to_string());
|
||||
|
||||
let xyz = devices::pci::brute_force_scan();
|
||||
let xyz = pci::brute_force_scan();
|
||||
for dev in xyz {
|
||||
trace!("{:?}", dev);
|
||||
dev.bars.iter().for_each(|bar| {
|
||||
|
@ -59,7 +95,6 @@ pub fn scratchpad() {
|
|||
|
||||
real_shell();
|
||||
}
|
||||
use crate::port_io::write16;
|
||||
|
||||
pub fn acpi() {
|
||||
let acpi_handler = AcpiStruct {};
|
||||
|
@ -71,33 +106,13 @@ pub fn acpi() {
|
|||
PlatformInfo {
|
||||
power_profile,
|
||||
interrupt_model,
|
||||
processor_info,
|
||||
pm_timer,
|
||||
..
|
||||
} => {
|
||||
info!("{:?}", power_profile);
|
||||
info!("{:?}", interrupt_model);
|
||||
// info!("{:?}", processor_info.unwrap());
|
||||
// info!("{:?}", pm_timer.unwrap());
|
||||
}
|
||||
|
||||
_ => todo!(),
|
||||
}
|
||||
}
|
||||
// TODO: move to a better place
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub struct AcpiStruct {}
|
||||
impl acpi::AcpiHandler for AcpiStruct {
|
||||
unsafe fn map_physical_region<T>(
|
||||
&self,
|
||||
physical_address: usize,
|
||||
size: usize,
|
||||
) -> acpi::PhysicalMapping<Self, T> {
|
||||
info!("PHYS ADDR: {:?}", physical_address);
|
||||
info!("Size: {:?}", size);
|
||||
todo!("map_physical_region");
|
||||
}
|
||||
fn unmap_physical_region<T>(_region: &acpi::PhysicalMapping<Self, T>) {
|
||||
todo!("unmap_physical_region");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -139,7 +154,6 @@ pub fn real_shell() {
|
|||
}
|
||||
}
|
||||
}
|
||||
use crate::rhai_shell::KEYBUFF;
|
||||
|
||||
pub fn command_parser(user: String, command: String) {
|
||||
let fs = &*FILE_SYSTEM.lock();
|
||||
|
@ -210,9 +224,6 @@ pub fn command_parser(user: String, command: String) {
|
|||
}
|
||||
}
|
||||
|
||||
use crate::filesystem::FILE_SYSTEM;
|
||||
use genfs::OpenOptions;
|
||||
|
||||
pub fn sound(n_frequency: u32) {
|
||||
let div: u32;
|
||||
let tmp: u8;
|
||||
|
@ -238,45 +249,3 @@ pub fn sound_off() {
|
|||
};
|
||||
reset_pit_for_cpu();
|
||||
}
|
||||
|
||||
use cpuio::inb;
|
||||
|
||||
pub struct Path {
|
||||
pub path: Vec<String>,
|
||||
}
|
||||
impl Path {
|
||||
pub fn new(path: String) -> Self {
|
||||
let mut path_vec_string = vec![];
|
||||
|
||||
for part in path.split(&['\\', '/'][..]) {
|
||||
path_vec_string.push(part.to_string());
|
||||
}
|
||||
|
||||
Path {
|
||||
path: path_vec_string,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_path(&self) -> String {
|
||||
let mut path = String::new();
|
||||
for part in &self.path {
|
||||
path.push_str(part);
|
||||
path.push('/');
|
||||
}
|
||||
path
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub enum GpuFormats {
|
||||
BGRA8Unorm = 1,
|
||||
BGRX8Unorm = 2,
|
||||
ARGB8Unorm = 3,
|
||||
XRGB8Unorm = 4,
|
||||
|
||||
RGBA8Unorm = 67,
|
||||
XBGR8Unorm = 68,
|
||||
|
||||
ABGR8Unorm = 121,
|
||||
RGBX8Unorm = 134,
|
||||
}
|
||||
|
|
|
@ -4,188 +4,78 @@ use wasmi::{
|
|||
Signature, Trap, ValueType,
|
||||
};
|
||||
|
||||
const ADD_FUNC_INDEX: usize = 0;
|
||||
const GET_TIME_INDEX: usize = 2;
|
||||
const GET_RANDOM_INDEX: usize = 3;
|
||||
const GET_INPUT_INDEX: usize = 4;
|
||||
const PRINT_CHAR: usize = 6;
|
||||
const SEND_SIGNAL_INDEX: usize = 1;
|
||||
macro_rules! wasmi_type {
|
||||
(bool) => {
|
||||
ValueType::I32
|
||||
};
|
||||
(u8) => {
|
||||
ValueType::I32
|
||||
};
|
||||
(u16) => {
|
||||
ValueType::I32
|
||||
};
|
||||
(u32) => {
|
||||
ValueType::I32
|
||||
};
|
||||
(u64) => {
|
||||
ValueType::I64
|
||||
};
|
||||
(i8) => {
|
||||
ValueType::I32
|
||||
};
|
||||
(i16) => {
|
||||
ValueType::I32
|
||||
};
|
||||
(i32) => {
|
||||
ValueType::I32
|
||||
};
|
||||
(i64) => {
|
||||
ValueType::I64
|
||||
};
|
||||
(f32) => {
|
||||
ValueType::F32
|
||||
};
|
||||
(f64) => {
|
||||
ValueType::F64
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! wasmi_return_type {
|
||||
() => {
|
||||
None
|
||||
};
|
||||
($type: ident) => {
|
||||
Some(wasmi_type!($type))
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! host_externals {
|
||||
(
|
||||
$($index: literal: $name: ident ($($arg_name: ident: $arg_type: ident),* $(,)?) $(-> $return_type: ident)? $block: block)*
|
||||
) => {
|
||||
pub struct HostExternals;
|
||||
impl HostExternals {
|
||||
fn check_signature(&self, index: usize, signature: &Signature) -> bool {
|
||||
match index {
|
||||
ADD_FUNC_INDEX => {
|
||||
let (params, ret_ty): (&[ValueType], Option<ValueType>) =
|
||||
(&[ValueType::I32, ValueType::I32], Some(ValueType::I32));
|
||||
if params.len() != signature.params().len() {
|
||||
return false;
|
||||
}
|
||||
if ret_ty != signature.return_type() {
|
||||
return false;
|
||||
}
|
||||
for (ty, param) in params.iter().zip(signature.params()) {
|
||||
if *ty != *param {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
SEND_SIGNAL_INDEX => {
|
||||
let (params, ret_ty): (&[ValueType], Option<ValueType>) =
|
||||
(&[ValueType::I32, ValueType::I32], Some(ValueType::I32));
|
||||
if params.len() != signature.params().len() {
|
||||
return false;
|
||||
}
|
||||
if ret_ty != signature.return_type() {
|
||||
return false;
|
||||
}
|
||||
for (ty, param) in params.iter().zip(signature.params()) {
|
||||
if *ty != *param {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
GET_TIME_INDEX => {
|
||||
let (params, ret_ty): (&[ValueType], Option<ValueType>) =
|
||||
(&[], Some(ValueType::I32));
|
||||
if params.len() != signature.params().len() {
|
||||
return false;
|
||||
}
|
||||
if ret_ty != signature.return_type() {
|
||||
return false;
|
||||
}
|
||||
for (ty, param) in params.iter().zip(signature.params()) {
|
||||
if *ty != *param {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
GET_RANDOM_INDEX => {
|
||||
let (params, ret_ty): (&[ValueType], Option<ValueType>) =
|
||||
(&[], Some(ValueType::I32));
|
||||
if params.len() != signature.params().len() {
|
||||
return false;
|
||||
}
|
||||
if ret_ty != signature.return_type() {
|
||||
return false;
|
||||
}
|
||||
for (ty, param) in params.iter().zip(signature.params()) {
|
||||
if *ty != *param {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
GET_INPUT_INDEX => {
|
||||
let (params, ret_ty): (&[ValueType], Option<ValueType>) =
|
||||
(&[], Some(ValueType::I32));
|
||||
if params.len() != signature.params().len() {
|
||||
return false;
|
||||
}
|
||||
if ret_ty != signature.return_type() {
|
||||
return false;
|
||||
}
|
||||
for (ty, param) in params.iter().zip(signature.params()) {
|
||||
if *ty != *param {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
PRINT_CHAR => {
|
||||
let (params, ret_ty): (&[ValueType], Option<ValueType>) = (&[ValueType::I32], None);
|
||||
if params.len() != signature.params().len() {
|
||||
return false;
|
||||
}
|
||||
if ret_ty != signature.return_type() {
|
||||
return false;
|
||||
}
|
||||
for (ty, param) in params.iter().zip(signature.params()) {
|
||||
if *ty != *param {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Externals for HostExternals {
|
||||
fn invoke_index(
|
||||
&mut self,
|
||||
index: usize,
|
||||
args: RuntimeArgs,
|
||||
args: RuntimeArgs
|
||||
) -> Result<Option<RuntimeValue>, Trap> {
|
||||
match index {
|
||||
ADD_FUNC_INDEX => {
|
||||
let a: u32 = args.nth_checked(0)?;
|
||||
let b: u32 = args.nth_checked(1)?;
|
||||
let result = a + b;
|
||||
trace!("SYSCALL: {} + {} = {}", a, b, result);
|
||||
Ok(Some(RuntimeValue::I32(result as i32)))
|
||||
}
|
||||
|
||||
SEND_SIGNAL_INDEX => {
|
||||
let pid: u32 = args.nth_checked(0)?;
|
||||
let signal: u32 = args.nth_checked(1)?;
|
||||
|
||||
trace!("SYSCALL: send signal {} to pid {}", signal, pid);
|
||||
let ret = RuntimeValue::I32(0);
|
||||
Ok(Some(ret))
|
||||
}
|
||||
|
||||
GET_TIME_INDEX => {
|
||||
use core::sync::atomic::Ordering::*;
|
||||
trace!("SYSCALL: get time");
|
||||
|
||||
x86_64::instructions::interrupts::disable();
|
||||
let tick_time = kernel::TICK.load(Relaxed);
|
||||
x86_64::instructions::interrupts::enable();
|
||||
|
||||
let ret = RuntimeValue::I32(tick_time.try_into().unwrap());
|
||||
Ok(Some(ret))
|
||||
}
|
||||
|
||||
GET_RANDOM_INDEX => {
|
||||
trace!("SYSCALL: get random");
|
||||
let rand = generate_process_pass();
|
||||
|
||||
let ret = RuntimeValue::I32(rand as i32);
|
||||
|
||||
// let ret = RuntimeValue::I32(rand.try_into().unwrap());
|
||||
Ok(Some(ret))
|
||||
}
|
||||
|
||||
GET_INPUT_INDEX => {
|
||||
let input = None;
|
||||
x86_64::instructions::interrupts::without_interrupts(|| KEYBUFF.lock().pop());
|
||||
if let Some(chr) = input {
|
||||
trace!("SYSCALL: input: {}", chr);
|
||||
}
|
||||
|
||||
let ret = RuntimeValue::I32(input.unwrap_or(0x00 as char) as i32);
|
||||
|
||||
Ok(Some(ret))
|
||||
}
|
||||
|
||||
PRINT_CHAR => {
|
||||
let chr: u8 = args.nth_checked(0)?;
|
||||
trace!("SYSCALL: print: {}", chr);
|
||||
print!("{}", char::from(chr));
|
||||
Ok(None)
|
||||
$(
|
||||
$index => match args.as_ref() {
|
||||
[$($arg_name),*] => {
|
||||
$(
|
||||
let $arg_name: $arg_type = (*$arg_name)
|
||||
.try_into()
|
||||
.ok_or(wasmi::TrapKind::UnexpectedSignature)?;
|
||||
)*
|
||||
$block
|
||||
},
|
||||
_ => return Err(wasmi::TrapKind::UnexpectedSignature.into()),
|
||||
}
|
||||
),*
|
||||
_ => {
|
||||
error!("Unimplemented function at {}", index);
|
||||
error!("Unimplemented function at {index}");
|
||||
Err(Trap::new(wasmi::TrapKind::Unreachable))
|
||||
}
|
||||
}
|
||||
|
@ -194,29 +84,85 @@ impl Externals for HostExternals {
|
|||
|
||||
impl ModuleImportResolver for HostExternals {
|
||||
fn resolve_func(&self, field_name: &str, signature: &Signature) -> Result<FuncRef, Error> {
|
||||
let index = match field_name {
|
||||
"add" => ADD_FUNC_INDEX,
|
||||
"send_signal" => SEND_SIGNAL_INDEX,
|
||||
"get_time" => GET_TIME_INDEX,
|
||||
"get_random" => GET_RANDOM_INDEX,
|
||||
"get_input" => GET_INPUT_INDEX,
|
||||
"print_char" => PRINT_CHAR,
|
||||
let (index, param_types, return_type): (usize, &[ValueType], Option<ValueType>) =
|
||||
match field_name {
|
||||
$(
|
||||
stringify!($name) => (
|
||||
$index,
|
||||
&[$(wasmi_type!($arg_type)),*],
|
||||
wasmi_return_type!($($return_type)?),
|
||||
),
|
||||
)*
|
||||
_ => {
|
||||
return Err(Error::Instantiation(format!(
|
||||
"Export {} not found",
|
||||
field_name
|
||||
)))
|
||||
}
|
||||
"Export {field_name} not found",
|
||||
)));
|
||||
},
|
||||
};
|
||||
|
||||
if !self.check_signature(index, signature) {
|
||||
return Err(Error::Instantiation(format!(
|
||||
"Export {} has a bad signature {:?}",
|
||||
field_name, signature
|
||||
)));
|
||||
if !(param_types.len() != signature.params().len() || return_type != signature.return_type())
|
||||
&& param_types
|
||||
.iter()
|
||||
.zip(signature.params())
|
||||
.find(|(ty, param)| ty != param)
|
||||
.is_none()
|
||||
{
|
||||
trace!("Resolved export {field_name} at func {index}");
|
||||
Ok(FuncInstance::alloc_host(signature.clone(), index))
|
||||
} else {
|
||||
Err(Error::Instantiation(format!(
|
||||
"Export {field_name} has a bad signature {signature:?}",
|
||||
)))
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
trace!("Resolved export {} as func {}", field_name, index);
|
||||
Ok(FuncInstance::alloc_host(signature.clone(), index))
|
||||
host_externals! {
|
||||
0: add(a: u32, b: u32) -> u32 {
|
||||
let result = a + b;
|
||||
trace!("SYSCALL: {} + {} = {}", a, b, result);
|
||||
Ok(Some(result.into()))
|
||||
}
|
||||
|
||||
1: send_signal(pid: u32, signal: u32) -> i32 {
|
||||
trace!("SYSCALL: send signal {} to pid {}", signal, pid);
|
||||
Ok(Some(0.into()))
|
||||
}
|
||||
|
||||
2: get_time() -> u32 {
|
||||
use core::sync::atomic::Ordering::*;
|
||||
trace!("SYSCALL: get time");
|
||||
|
||||
x86_64::instructions::interrupts::disable();
|
||||
let tick_time = kernel::TICK.load(Relaxed);
|
||||
x86_64::instructions::interrupts::enable();
|
||||
|
||||
let ret: u32 = tick_time.try_into().unwrap();
|
||||
Ok(Some(ret.into()))
|
||||
}
|
||||
|
||||
3: get_random() -> i32 {
|
||||
trace!("SYSCALL: get random");
|
||||
let rand = generate_process_pass() as i32;
|
||||
Ok(Some(rand.into()))
|
||||
}
|
||||
|
||||
4: get_input() -> i32 {
|
||||
let input = None;
|
||||
x86_64::instructions::interrupts::without_interrupts(|| KEYBUFF.lock().pop());
|
||||
if let Some(chr) = input {
|
||||
trace!("SYSCALL: input: {}", chr);
|
||||
}
|
||||
|
||||
let ret = input.unwrap_or(0x00 as char) as i32;
|
||||
Ok(Some(ret.into()))
|
||||
}
|
||||
|
||||
5: print_char(chr: u8) {
|
||||
trace!("SYSCALL: print: {}", chr);
|
||||
print!("{}", char::from(chr));
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ name = "kernel"
|
|||
version = "0.1.2"
|
||||
|
||||
[dependencies]
|
||||
linked_list_allocator = "0.9"
|
||||
log = "0.4.14"
|
||||
|
||||
[dependencies.versioning]
|
||||
|
|
24
kernel/src/allocator.rs
Normal file
24
kernel/src/allocator.rs
Normal file
|
@ -0,0 +1,24 @@
|
|||
//! Memory allocator
|
||||
|
||||
use linked_list_allocator::LockedHeap;
|
||||
|
||||
///
|
||||
pub const HEAP_START: usize = 0x_4444_4444_0000;
|
||||
|
||||
///
|
||||
pub const HEAP_MULTIPLIER: usize = 100000;
|
||||
|
||||
///
|
||||
pub const HEAP_BASE: usize = 100;
|
||||
|
||||
///
|
||||
pub const HEAP_SIZE: usize = HEAP_BASE * HEAP_MULTIPLIER;
|
||||
|
||||
/// Global allocator
|
||||
#[global_allocator]
|
||||
pub static ALLOCATOR: LockedHeap = LockedHeap::empty();
|
||||
|
||||
#[alloc_error_handler]
|
||||
fn alloc_error_handler(layout: alloc::alloc::Layout) -> ! {
|
||||
panic!("allocation error: {:?}", layout)
|
||||
}
|
|
@ -1,10 +1,14 @@
|
|||
//! The ableOS kernel.
|
||||
|
||||
#![deny(missing_docs)]
|
||||
#![no_std]
|
||||
#![feature(prelude_import)]
|
||||
#![feature(alloc_error_handler)]
|
||||
#![feature(arbitrary_enum_discriminant)]
|
||||
#![feature(prelude_import)]
|
||||
#![no_std]
|
||||
#![deny(missing_docs)]
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
pub mod allocator;
|
||||
pub mod device_interface;
|
||||
pub mod messaging;
|
||||
pub mod panic;
|
||||
|
|
Loading…
Reference in a new issue