able told me to push 🙏

This commit is contained in:
koniifer 2024-09-11 23:09:47 +01:00
parent 3a6778149b
commit fef5487e62
20 changed files with 270 additions and 296 deletions

40
Cargo.lock generated
View file

@ -2,6 +2,15 @@
# It is not intended for manual editing. # It is not intended for manual editing.
version = 3 version = 3
[[package]]
name = "aarch64-cpu"
version = "9.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac42a04a61c19fc8196dd728022a784baecc5d63d7e256c01ad1b3fbfab26287"
dependencies = [
"tock-registers",
]
[[package]] [[package]]
name = "addr2line" name = "addr2line"
version = "0.24.1" version = "0.24.1"
@ -52,9 +61,9 @@ dependencies = [
[[package]] [[package]]
name = "anyhow" name = "anyhow"
version = "1.0.87" version = "1.0.88"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "10f00e1f6e58a40e807377c75c6a7f97bf9044fab57816f2414e6f5f4499d7b8" checksum = "4e1496f8fb1fbf272686b8d37f523dab3e4a7443300055e74cdaa449f3114356"
[[package]] [[package]]
name = "autocfg" name = "autocfg"
@ -381,17 +390,17 @@ dependencies = [
[[package]] [[package]]
name = "hbbytecode" name = "hbbytecode"
version = "0.1.0" version = "0.1.0"
source = "git+https://git.ablecorp.us/AbleOS/holey-bytes.git#b51f964caee71ad350d0c1f66e4694202a5d7f12" source = "git+https://git.ablecorp.us/AbleOS/holey-bytes.git#dc418bd5e0b962ec9413af72e5d624e17febcbf2"
[[package]] [[package]]
name = "hbbytecode" name = "hbbytecode"
version = "0.1.0" version = "0.1.0"
source = "git+https://git.ablecorp.us/ableos/holey-bytes#b51f964caee71ad350d0c1f66e4694202a5d7f12" source = "git+https://git.ablecorp.us/ableos/holey-bytes#dc418bd5e0b962ec9413af72e5d624e17febcbf2"
[[package]] [[package]]
name = "hblang" name = "hblang"
version = "0.1.0" version = "0.1.0"
source = "git+https://git.ablecorp.us/AbleOS/holey-bytes.git#b51f964caee71ad350d0c1f66e4694202a5d7f12" source = "git+https://git.ablecorp.us/AbleOS/holey-bytes.git#dc418bd5e0b962ec9413af72e5d624e17febcbf2"
dependencies = [ dependencies = [
"hbvm 0.1.0 (git+https://git.ablecorp.us/AbleOS/holey-bytes.git)", "hbvm 0.1.0 (git+https://git.ablecorp.us/AbleOS/holey-bytes.git)",
] ]
@ -399,7 +408,7 @@ dependencies = [
[[package]] [[package]]
name = "hbvm" name = "hbvm"
version = "0.1.0" version = "0.1.0"
source = "git+https://git.ablecorp.us/AbleOS/holey-bytes.git#b51f964caee71ad350d0c1f66e4694202a5d7f12" source = "git+https://git.ablecorp.us/AbleOS/holey-bytes.git#dc418bd5e0b962ec9413af72e5d624e17febcbf2"
dependencies = [ dependencies = [
"hbbytecode 0.1.0 (git+https://git.ablecorp.us/AbleOS/holey-bytes.git)", "hbbytecode 0.1.0 (git+https://git.ablecorp.us/AbleOS/holey-bytes.git)",
] ]
@ -407,7 +416,7 @@ dependencies = [
[[package]] [[package]]
name = "hbvm" name = "hbvm"
version = "0.1.0" version = "0.1.0"
source = "git+https://git.ablecorp.us/ableos/holey-bytes#b51f964caee71ad350d0c1f66e4694202a5d7f12" source = "git+https://git.ablecorp.us/ableos/holey-bytes#dc418bd5e0b962ec9413af72e5d624e17febcbf2"
dependencies = [ dependencies = [
"hbbytecode 0.1.0 (git+https://git.ablecorp.us/ableos/holey-bytes)", "hbbytecode 0.1.0 (git+https://git.ablecorp.us/ableos/holey-bytes)",
] ]
@ -583,8 +592,8 @@ dependencies = [
name = "kernel" name = "kernel"
version = "0.2.0" version = "0.2.0"
dependencies = [ dependencies = [
"aarch64-cpu",
"crossbeam-queue", "crossbeam-queue",
"crossbeam-utils",
"derive_more", "derive_more",
"embedded-graphics", "embedded-graphics",
"hashbrown", "hashbrown",
@ -592,6 +601,7 @@ dependencies = [
"limine", "limine",
"log", "log",
"sbi", "sbi",
"slab",
"spin", "spin",
"uart_16550", "uart_16550",
"versioning", "versioning",
@ -989,9 +999,9 @@ dependencies = [
[[package]] [[package]]
name = "rustls" name = "rustls"
version = "0.23.12" version = "0.23.13"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c58f8c84392efc0a126acce10fa59ff7b3d2ac06ab451a33f2741989b806b044" checksum = "f2dabaac7466917e566adb06783a81ca48944c6898a1b08b9374106dd671f4c8"
dependencies = [ dependencies = [
"once_cell", "once_cell",
"ring", "ring",
@ -1218,6 +1228,12 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
[[package]]
name = "tock-registers"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "696941a0aee7e276a165a978b37918fd5d22c55c3d6bda197813070ca9c0f21c"
[[package]] [[package]]
name = "tokio" name = "tokio"
version = "1.40.0" version = "1.40.0"
@ -1349,9 +1365,9 @@ checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75"
[[package]] [[package]]
name = "unicode-ident" name = "unicode-ident"
version = "1.0.12" version = "1.0.13"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe"
[[package]] [[package]]
name = "unicode-normalization" name = "unicode-normalization"

View file

@ -9,6 +9,7 @@ embedded-graphics = "0.8"
hbvm.git = "https://git.ablecorp.us/ableos/holey-bytes" hbvm.git = "https://git.ablecorp.us/ableos/holey-bytes"
log = "0.4" log = "0.4"
spin = "0.9" spin = "0.9"
slab = { version = "0.4", default-features = false }
uart_16550 = { version = "0.3", features = ["nightly"] } uart_16550 = { version = "0.3", features = ["nightly"] }
xml.git = "https://git.ablecorp.us/ableos/ableos_userland" xml.git = "https://git.ablecorp.us/ableos/ableos_userland"
versioning.git = "https://git.ablecorp.us/ableos/ableos_userland" versioning.git = "https://git.ablecorp.us/ableos/ableos_userland"
@ -24,10 +25,6 @@ version = "0.3"
default-features = false default-features = false
features = ["alloc", "nightly"] features = ["alloc", "nightly"]
[dependencies.crossbeam-utils]
version = "0.8"
default-features = false
# [dependencies.clparse] # [dependencies.clparse]
# git = "https://git.ablecorp.us/ableos/ableos_userland" # git = "https://git.ablecorp.us/ableos/ableos_userland"
# default-features = false # default-features = false
@ -56,3 +53,6 @@ virtio-drivers = "0.7"
[target.'cfg(target_arch = "riscv64")'.dependencies] [target.'cfg(target_arch = "riscv64")'.dependencies]
sbi = "0.2.0" sbi = "0.2.0"
[target.'cfg(target_arch = "aarch64")'.dependencies]
aarch64-cpu = "9"

View file

@ -1,5 +1,5 @@
use {crate::logger::TERMINAL_LOGGER, core::fmt::Write, spin::Mutex}; use {crate::logger::TERMINAL_LOGGER, core::fmt::Write, spin::Mutex};
const SERIAL_CONSOLE: Mutex<SerialConsole> = Mutex::new(SerialConsole { static SERIAL_CONSOLE: Mutex<SerialConsole> = Mutex::new(SerialConsole {
uart: 0x09000000 as *mut u8, uart: 0x09000000 as *mut u8,
}); });
@ -17,6 +17,9 @@ impl core::fmt::Write for SerialConsole {
} }
} }
unsafe impl Sync for SerialConsole {}
unsafe impl Send for SerialConsole {}
pub fn log(args: core::fmt::Arguments<'_>) -> core::fmt::Result { pub fn log(args: core::fmt::Arguments<'_>) -> core::fmt::Result {
SERIAL_CONSOLE.lock().write_fmt(args)?; SERIAL_CONSOLE.lock().write_fmt(args)?;
TERMINAL_LOGGER.lock().write_fmt(args)?; TERMINAL_LOGGER.lock().write_fmt(args)?;

View file

@ -1,6 +1,7 @@
pub use logging::log; pub use logging::log;
use { use {
crate::{allocator, bootmodules::BootModule, kmain::kmain}, crate::{allocator, bootmodules::BootModule, kmain::kmain},
alloc::vec::Vec,
core::arch::asm, core::arch::asm,
limine::FramebufferRequest, limine::FramebufferRequest,
}; };
@ -41,7 +42,7 @@ unsafe extern "C" fn _kernel_start() -> ! {
static KFILE_REQ: KernelFileRequest = KernelFileRequest::new(0); static KFILE_REQ: KernelFileRequest = KernelFileRequest::new(0);
static MOD_REQ: ModuleRequest = ModuleRequest::new(0); static MOD_REQ: ModuleRequest = ModuleRequest::new(0);
let mut bootmodules = alloc::vec::Vec::new(); let mut bootmodules = Vec::new();
if bm.is_some() { if bm.is_some() {
let bm = bm.unwrap(); let bm = bm.unwrap();
@ -52,18 +53,13 @@ unsafe extern "C" fn _kernel_start() -> ! {
let raw_bytes = core::slice::from_raw_parts( let raw_bytes = core::slice::from_raw_parts(
file.base.as_ptr().expect("invalid initrd"), file.base.as_ptr().expect("invalid initrd"),
file.length as usize, file.length as usize,
)
.to_vec();
let file_path = alloc::string::String::from_utf8(
file.path.to_str().unwrap().to_bytes().to_vec(),
); );
let file_path = file.path.to_str().unwrap().to_str();
if file_path.is_err() { if file_path.is_err() {
panic!("invalid file path: {:?}", file_path); panic!("invalid file path: {:?}", file_path);
} }
let file_cmd = alloc::string::String::from_utf8( let file_cmd = file.cmdline.to_str().unwrap().to_str();
file.cmdline.to_str().unwrap().to_bytes().to_vec(),
);
if file_cmd.is_err() { if file_cmd.is_err() {
panic!("invalid module cmd: {:?}", file_cmd); panic!("invalid module cmd: {:?}", file_cmd);
} }
@ -85,7 +81,7 @@ unsafe extern "C" fn _kernel_start() -> ! {
assert_eq!(bm.module_count, bootmodules.len() as u64); assert_eq!(bm.module_count, bootmodules.len() as u64);
} }
crate::kmain::kmain( kmain(
KFILE_REQ KFILE_REQ
.get_response() .get_response()
.get() .get()
@ -99,8 +95,6 @@ unsafe extern "C" fn _kernel_start() -> ! {
.unwrap_or_default(), .unwrap_or_default(),
bootmodules, bootmodules,
); );
spin_loop();
} }
pub fn spin_loop() -> ! { pub fn spin_loop() -> ! {
@ -110,7 +104,15 @@ pub fn spin_loop() -> ! {
} }
pub fn hardware_random_u64() -> u64 { pub fn hardware_random_u64() -> u64 {
0 if let Some(rng) = aarch64_cpu::asm::random::ArmRng::new() {
if let Some(rnd) = rng.rndr() {
rnd
} else {
panic!("RNG failure :(")
}
} else {
panic!("RNDR failure :(((")
}
} }
pub fn register_dump() {} pub fn register_dump() {}

View file

@ -1,7 +1,7 @@
mod memory; mod memory;
use { use {
alloc::boxed::Box, alloc::{boxed::Box, vec::Vec},
core::{ core::{
arch::{asm, global_asm}, arch::{asm, global_asm},
fmt::Write, fmt::Write,
@ -45,7 +45,7 @@ extern "C" {
static USABLE_MEMORY_SIZE: usize; static USABLE_MEMORY_SIZE: usize;
} }
static SERIAL_CONSOLE: Once<Mutex<MmioSerialPort>> = Once::new(); pub static SERIAL_CONSOLE: Once<Mutex<MmioSerialPort>> = Once::new();
#[no_mangle] #[no_mangle]
unsafe extern "C" fn _kernel_start() -> ! { unsafe extern "C" fn _kernel_start() -> ! {
@ -95,7 +95,7 @@ unsafe extern "C" fn _kernel_start() -> ! {
in(reg) satp_value, in(reg) satp_value,
); );
crate::kmain::kmain("baka=9", None); crate::kmain::kmain("baka=9", Vec::new());
} }
/// Spin loop /// Spin loop
@ -105,6 +105,12 @@ pub fn spin_loop() -> ! {
} }
} }
pub fn hardware_random_u64() -> u64 {
0
}
pub fn register_dump() {}
pub fn log(args: core::fmt::Arguments<'_>) -> core::fmt::Result { pub fn log(args: core::fmt::Arguments<'_>) -> core::fmt::Result {
SERIAL_CONSOLE.get().unwrap().lock().write_fmt(args) SERIAL_CONSOLE.get().unwrap().lock().write_fmt(args)
} }

View file

@ -11,6 +11,9 @@ use {
pub const DOUBLE_FAULT_IX: u16 = 0; pub const DOUBLE_FAULT_IX: u16 = 0;
const STACK_SIZE: usize = 5 * 1024;
const STACK_ALIGNMENT: usize = 4096;
pub unsafe fn init() { pub unsafe fn init() {
use x86_64::instructions::{ use x86_64::instructions::{
segmentation::{Segment, CS, SS}, segmentation::{Segment, CS, SS},
@ -32,15 +35,15 @@ struct Selectors {
static TSS: Lazy<TaskStateSegment> = Lazy::new(|| { static TSS: Lazy<TaskStateSegment> = Lazy::new(|| {
let mut tss = TaskStateSegment::new(); let mut tss = TaskStateSegment::new();
tss.interrupt_stack_table[usize::from(DOUBLE_FAULT_IX)] = {
const SIZE: usize = 5 * 1024; let stack_ptr = unsafe {
let stack = unsafe { let layout = alloc::alloc::Layout::from_size_align(STACK_SIZE, STACK_ALIGNMENT)
alloc::alloc::alloc_zeroed( .expect("Failed to create stack layout");
alloc::alloc::Layout::from_size_align(SIZE, 1).expect("stack pointer"), let stack = alloc::alloc::alloc_zeroed(layout);
) VirtAddr::from_ptr(stack) + STACK_SIZE as u64
};
VirtAddr::from_ptr(stack) + SIZE as u64
}; };
tss.interrupt_stack_table[usize::from(DOUBLE_FAULT_IX)] = stack_ptr;
tss tss
}); });

View file

@ -1,4 +1,4 @@
use core::arch::x86_64::{_rdrand32_step, _rdrand64_step, _rdseed32_step, _rdseed64_step}; use core::arch::x86_64::{_rdrand64_step, _rdseed64_step};
use {crate::bootmodules::BootModule, core::arch::asm, log::warn}; use {crate::bootmodules::BootModule, core::arch::asm, log::warn};
pub mod memory; pub mod memory;
@ -142,18 +142,13 @@ unsafe extern "C" fn start() -> ! {
let raw_bytes = core::slice::from_raw_parts( let raw_bytes = core::slice::from_raw_parts(
file.base.as_ptr().expect("invalid initrd"), file.base.as_ptr().expect("invalid initrd"),
file.length as usize, file.length as usize,
)
.to_vec();
let file_path = alloc::string::String::from_utf8(
file.path.to_str().unwrap().to_bytes().to_vec(),
); );
let file_path = file.path.to_str().unwrap().to_str();
if file_path.is_err() { if file_path.is_err() {
panic!("invalid file path: {:?}", file_path); panic!("invalid file path: {:?}", file_path);
} }
let file_cmd = alloc::string::String::from_utf8( let file_cmd = file.cmdline.to_str().unwrap().to_str();
file.cmdline.to_str().unwrap().to_bytes().to_vec(),
);
if file_cmd.is_err() { if file_cmd.is_err() {
panic!("invalid module cmd: {:?}", file_cmd); panic!("invalid module cmd: {:?}", file_cmd);
} }
@ -191,15 +186,10 @@ unsafe extern "C" fn start() -> ! {
) )
} }
use crossbeam_utils::Backoff;
/// Spin loop /// Spin loop
pub fn spin_loop() -> ! { pub fn spin_loop() -> ! {
let backoff = Backoff::new();
loop { loop {
core::hint::spin_loop(); x86_64::instructions::hlt()
// x86_64::instructions::hlt();
backoff.spin()
} }
} }
@ -218,21 +208,6 @@ pub fn hardware_random_u64() -> u64 {
} }
} }
pub fn hardware_random_u32() -> u32 {
let mut out: u32 = 0;
match unsafe { _rdrand32_step(&mut out) } {
1 => out,
_ => {
warn!("RDRand not supported.");
// Try rdseed
match unsafe { _rdseed32_step(&mut out) } {
1 => out,
_ => panic!("Neither RDRand or RDSeed are supported"),
}
}
}
}
pub fn get_edid() {} pub fn get_edid() {}
#[allow(unused)] #[allow(unused)]

View file

@ -1,20 +1,20 @@
use { use {
// crate::alloc::string::ToString, // crate::alloc::string::ToString,
alloc::{string::String, vec::Vec}, alloc::vec::Vec,
// clparse::Arguments, // clparse::Arguments,
// core::fmt::{Debug, Display}, // core::fmt::{Debug, Display},
// log::trace, // log::trace,
// xml::XMLElement, // xml::XMLElement,
}; };
pub type BootModules = Vec<BootModule>; pub type BootModules<'a> = Vec<BootModule<'a>>;
pub struct BootModule { pub struct BootModule<'a> {
pub path: String, pub path: &'a str,
pub bytes: Vec<u8>, pub bytes: &'a [u8],
pub cmd: String, pub cmd: &'a str,
} }
impl BootModule { impl<'a> BootModule<'a> {
pub fn new(path: String, bytes: Vec<u8>, cmd: String) -> Self { pub fn new(path: &'a str, bytes: &'a [u8], cmd: &'a str) -> Self {
Self { path, bytes, cmd } Self { path, bytes, cmd }
} }
} }

View file

@ -5,7 +5,6 @@ use crate::holeybytes::kernel_services::{block_read, service_definition_service:
use { use {
super::Vm, super::Vm,
crate::{arch, ipc::buffer::IpcBuffer, kmain::IPC_BUFFERS}, crate::{arch, ipc::buffer::IpcBuffer, kmain::IPC_BUFFERS},
alloc::string::String,
log::{debug, error, info, trace, warn}, log::{debug, error, info, trace, warn},
}; };
@ -79,26 +78,19 @@ pub fn handler(vm: &mut Vm) {
Err(_) => {} Err(_) => {}
} }
} }
#[cfg(not(target_arch = "x86_64"))]
3 => info!("TODO: implement whatever buffer 3 does for no x86_64"),
#[cfg(target_arch = "x86_64")]
3 => { 3 => {
unsafe fn x86_in(address: u16) -> u8 { unsafe fn x86_out<T: x86_64::instructions::port::PortWrite>(
x86_64::instructions::port::Port::new(address).read() address: u16,
} value: T,
unsafe fn x86_in_16(address: u16) -> u16 { ) {
x86_64::instructions::port::Port::new(address).read()
}
unsafe fn x86_in_32(address: u16) -> u32 {
x86_64::instructions::port::Port::new(address).read()
}
unsafe fn x86_out(address: u16, value: u8) {
x86_64::instructions::port::Port::new(address).write(value); x86_64::instructions::port::Port::new(address).write(value);
} }
unsafe fn x86_out_16(address: u16, value: u16) { unsafe fn x86_in<T: x86_64::instructions::port::PortRead>(address: u16) -> T {
x86_64::instructions::port::Port::new(address).write(value); x86_64::instructions::port::Port::new(address).read()
} }
unsafe fn x86_out_32(address: u16, value: u32) {
x86_64::instructions::port::Port::new(address).write(value);
}
let msg_vec = block_read(mem_addr, length); let msg_vec = block_read(mem_addr, length);
let msg_type = msg_vec[0]; let msg_type = msg_vec[0];
match msg_type { match msg_type {
@ -115,9 +107,9 @@ pub fn handler(vm: &mut Vm) {
let addr = u16::from_le_bytes(msg_vec[1..3].try_into().unwrap()); let addr = u16::from_le_bytes(msg_vec[1..3].try_into().unwrap());
let value = unsafe { let value = unsafe {
match size { match size {
1 => x86_in(addr) as u64, 1 => x86_in::<u8>(addr) as u64,
2 => x86_in_16(addr) as u64, 2 => x86_in::<u16>(addr) as u64,
4 => x86_in_32(addr) as u64, 4 => x86_in::<u32>(addr) as u64,
_ => panic!("how?"), _ => panic!("how?"),
} }
}; };
@ -141,13 +133,13 @@ pub fn handler(vm: &mut Vm) {
unsafe { unsafe {
match size { match size {
1 => x86_out(addr, msg_vec[3]), 1 => x86_out(addr, msg_vec[3]),
2 => x86_out_16( 2 => x86_out(
addr, addr,
u16::from_le_bytes( u16::from_le_bytes(
msg_vec[3..5].try_into().unwrap_unchecked(), msg_vec[3..5].try_into().unwrap_unchecked(),
), ),
), ),
4 => x86_out_32( 4 => x86_out(
addr, addr,
u32::from_le_bytes( u32::from_le_bytes(
msg_vec[3..7].try_into().unwrap_unchecked(), msg_vec[3..7].try_into().unwrap_unchecked(),
@ -162,7 +154,18 @@ pub fn handler(vm: &mut Vm) {
} }
// source of rng // source of rng
4 => { 4 => {
vm.registers[1] = hbvm::value::Value(crate::arch::hardware_random_u32() as u64); // limit to last 32 bits
vm.registers[1] =
hbvm::value::Value(crate::arch::hardware_random_u64() & 0xFFFFFFFF);
}
5 => {
if cfg!(target_arch = "x86_64") {
vm.registers[1] = hbvm::value::Value(0);
} else if cfg!(target_arch = "aarch64") {
vm.registers[1] = hbvm::value::Value(1);
} else {
vm.registers[1] = hbvm::value::Value(u64::MAX)
}
} }
buffer_id => { buffer_id => {
let mut buffs = IPC_BUFFERS.lock(); let mut buffs = IPC_BUFFERS.lock();
@ -247,10 +250,10 @@ pub fn handler(vm: &mut Vm) {
fn log_msg_handler(_vm: &mut Vm, mem_addr: u64, length: usize) -> Result<(), LogError> { fn log_msg_handler(_vm: &mut Vm, mem_addr: u64, length: usize) -> Result<(), LogError> {
// let message_length = 8 + 8 + 8; // let message_length = 8 + 8 + 8;
// log::info!("Mem Addr 0x{:x?} length {}", mem_addr, length); // log::info!("Mem Addr 0x{:x?} length {}", mem_addr, length);
let mut msg_vec = block_read(mem_addr, length); let msg_vec = block_read(mem_addr, length);
let log_level = msg_vec.pop().unwrap(); let log_level = msg_vec.last().unwrap();
match String::from_utf8(msg_vec) { match core::str::from_utf8(&msg_vec[1..]) {
Ok(strr) => { Ok(strr) => {
// use LogLevel::*; // use LogLevel::*;
let _ll = match log_level { let _ll = match log_level {

View file

@ -1,15 +1,9 @@
use alloc::vec::Vec; use core::slice;
pub mod mem_serve; pub mod mem_serve;
pub mod service_definition_service; pub mod service_definition_service;
pub fn block_read(mem_addr: u64, length: usize) -> Vec<u8> { #[inline(always)]
let mut msg_vec = Vec::with_capacity(length); pub fn block_read<'a>(mem_addr: u64, length: usize) -> &'a [u8] {
let xyz = mem_addr as *const u8; unsafe { slice::from_raw_parts(mem_addr as *const u8, length) }
for x in 0..(length as isize) {
let value = unsafe { xyz.offset(x).read() };
msg_vec.push(value);
}
msg_vec
} }

View file

@ -5,12 +5,11 @@ use {
ipc::{buffer::IpcBuffer, protocol::Protocol}, ipc::{buffer::IpcBuffer, protocol::Protocol},
kmain::IPC_BUFFERS, kmain::IPC_BUFFERS,
}, },
alloc::string::String,
hashbrown::HashMap, hashbrown::HashMap,
log::{info, trace}, log::{info, trace},
spin::{lazy::Lazy, Mutex}, spin::{lazy::Lazy, Mutex},
}; };
pub struct Services(HashMap<u64, Protocol>); pub struct Services<'a>(HashMap<u64, Protocol<'a>>);
pub static SERVICES: Lazy<Mutex<Services>> = Lazy::new(|| { pub static SERVICES: Lazy<Mutex<Services>> = Lazy::new(|| {
let mut dt = Services(HashMap::new()); let mut dt = Services(HashMap::new());
dt.0.insert(0, Protocol::void()); dt.0.insert(0, Protocol::void());
@ -18,25 +17,26 @@ pub static SERVICES: Lazy<Mutex<Services>> = Lazy::new(|| {
}); });
pub fn sds_msg_handler(vm: &mut Vm, mem_addr: u64, length: usize) -> Result<(), LogError> { pub fn sds_msg_handler(vm: &mut Vm, mem_addr: u64, length: usize) -> Result<(), LogError> {
let mut msg_vec = block_read(mem_addr, length); let msg_vec = block_read(mem_addr, length);
if msg_vec.is_empty() { if msg_vec.is_empty() {
return Err(LogError::NoMessages); return Err(LogError::NoMessages);
} }
let sds_event_type: ServiceEventType = msg_vec[0].into(); let sds_event_type: ServiceEventType = msg_vec[0].into();
msg_vec.remove(0);
// info!("Length {}", msg_vec.len()); // info!("Length {}", msg_vec.len());
use ServiceEventType::*; use ServiceEventType::*;
match sds_event_type { match sds_event_type {
CreateService => { CreateService => {
let string = String::from_utf8(msg_vec).expect("Our bytes should be valid utf8"); let string =
core::str::from_utf8(&msg_vec[1..]).expect("Our bytes should be valid utf8");
let ret = sds_create_service(string); let ret = sds_create_service(string);
vm.registers[1] = hbvm::value::Value(ret as u64); vm.registers[1] = hbvm::value::Value(ret as u64);
} }
DeleteService => todo!(), DeleteService => todo!(),
SearchServices => { SearchServices => {
let string = String::from_utf8(msg_vec).expect("Our bytes should be valid utf8"); let string =
core::str::from_utf8(&msg_vec[1..]).expect("Our bytes should be valid utf8");
let ret = sds_search_service(string); let ret = sds_search_service(string);
vm.registers[1] = hbvm::value::Value(ret as u64); vm.registers[1] = hbvm::value::Value(ret as u64);
} }
@ -78,16 +78,16 @@ impl From<u8> for ServiceEventType {
} }
} }
fn sds_create_service(protocol: String) -> u64 { fn sds_create_service(protocol: &'static str) -> u64 {
let buff_id = hardware_random_u64(); let buff_id = hardware_random_u64();
let mut services = SERVICES.lock(); let mut services = SERVICES.lock();
let mut buffers = IPC_BUFFERS.lock(); let mut buffers = IPC_BUFFERS.lock();
let protocol_ = Protocol::from(protocol.clone()); let protocol_ = Protocol::from(protocol);
let mut buff = IpcBuffer::new(false, 0); let mut buff = IpcBuffer::new(false, 0);
services.0.insert(buff_id, protocol_.clone()); services.0.insert(buff_id, protocol_.clone());
buff.protocol = protocol_.clone(); buff.protocol = protocol_;
buffers.insert(buff_id, buff); buffers.insert(buff_id, buff);
trace!("BufferID({}) => {}", buff_id, protocol); trace!("BufferID({}) => {}", buff_id, protocol);
@ -95,13 +95,13 @@ fn sds_create_service(protocol: String) -> u64 {
buff_id buff_id
} }
fn sds_search_service(protocol: String) -> u64 { fn sds_search_service(protocol: &str) -> u64 {
let services = SERVICES.lock(); let services = SERVICES.lock();
let compare = Protocol::from(protocol.clone()); let compare = Protocol::from(protocol);
for (bid, protocol_canidate) in &services.0 { for (bid, protocol_canidate) in &services.0 {
trace!("BID-{bid} protocol_canidate {:?}", protocol_canidate); trace!("BID-{bid} protocol_canidate {:?}", protocol_canidate);
if protocol_canidate == &compare { if protocol_canidate == &compare {
trace!("BufferID({}) => {}", bid, protocol.clone()); trace!("BufferID({}) => {}", bid, protocol);
return *bid; return *bid;
} }
} }

View file

@ -3,12 +3,11 @@ mod kernel_services;
mod mem; mod mem;
use { use {
alloc::alloc::{alloc_zeroed, dealloc},
core::{ core::{
alloc::Layout, alloc::Layout,
future::Future, future::Future,
marker::PhantomData,
pin::Pin, pin::Pin,
ptr::NonNull,
task::{Context, Poll}, task::{Context, Poll},
}, },
hbvm::{ hbvm::{
@ -22,21 +21,20 @@ const STACK_SIZE: usize = 1024 * 1024;
const TIMER_QUOTIENT: usize = 1000; const TIMER_QUOTIENT: usize = 1000;
type Vm = hbvm::Vm<mem::Memory, TIMER_QUOTIENT>; type Vm = hbvm::Vm<mem::Memory, TIMER_QUOTIENT>;
pub struct ExecThread<'p> { pub struct ExecThread {
vm: Vm, vm: Vm,
stack_bottom: NonNull<u8>, stack_bottom: *mut u8,
_phantom: PhantomData<&'p [u8]>,
} }
unsafe impl<'p> Send for ExecThread<'p> {} unsafe impl Send for ExecThread {}
impl<'p> ExecThread<'p> { impl ExecThread {
pub fn set_arguments(&mut self, ptr: u64, length: u64) { pub fn set_arguments(&mut self, ptr: u64, length: u64) {
self.vm.registers[1] = hbvm::value::Value(ptr); self.vm.registers[1] = hbvm::value::Value(ptr);
self.vm.registers[2] = hbvm::value::Value(length); self.vm.registers[2] = hbvm::value::Value(length);
} }
pub unsafe fn new(program: &'p [u8], entrypoint: Address) -> Self { pub unsafe fn new(program: &[u8], entrypoint: Address) -> Self {
let mut vm = Vm::new( let mut vm = Vm::new(
mem::Memory {}, mem::Memory {},
Address::new(program.as_ptr() as u64 + entrypoint.get()), Address::new(program.as_ptr() as u64 + entrypoint.get()),
@ -44,27 +42,21 @@ impl<'p> ExecThread<'p> {
let stack_bottom = allocate_stack(); let stack_bottom = allocate_stack();
vm.write_reg( vm.write_reg(254, (stack_bottom as usize + STACK_SIZE - 1) as u64);
254,
(stack_bottom.as_ptr() as usize + STACK_SIZE - 1) as u64,
);
ExecThread { ExecThread { vm, stack_bottom }
vm,
stack_bottom,
_phantom: PhantomData,
}
} }
} }
impl<'p> Drop for ExecThread<'p> { impl<'p> Drop for ExecThread {
fn drop(&mut self) { fn drop(&mut self) {
unsafe { alloc::alloc::dealloc(self.stack_bottom.as_ptr(), stack_layout()) }; unsafe { dealloc(self.stack_bottom, stack_layout()) };
} }
} }
impl<'p> Future for ExecThread<'p> { impl<'p> Future for ExecThread {
type Output = Result<(), VmRunError>; type Output = Result<(), VmRunError>;
#[inline(always)] #[inline(always)]
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
match self.vm.run() { match self.vm.run() {
@ -105,7 +97,6 @@ impl HandlePageFault for PageFaultHandler {
dataptr: *mut u8, dataptr: *mut u8,
) -> bool { ) -> bool {
error!("REASON: {reason} vaddr: {vaddr} size: {size:?} Dataptr {dataptr:p}"); error!("REASON: {reason} vaddr: {vaddr} size: {size:?} Dataptr {dataptr:p}");
false false
} }
} }
@ -116,8 +107,6 @@ const fn stack_layout() -> Layout {
} }
#[inline(always)] #[inline(always)]
fn allocate_stack() -> NonNull<u8> { fn allocate_stack() -> *mut u8 {
let layout = stack_layout(); unsafe { alloc_zeroed(stack_layout()) }
NonNull::new(unsafe { alloc::alloc::alloc_zeroed(layout) })
.unwrap_or_else(|| alloc::alloc::handle_alloc_error(layout))
} }

View file

@ -9,12 +9,12 @@ pub enum BufferTypes {
Bound(ArrayQueue<Message>), Bound(ArrayQueue<Message>),
} }
/// Interproccess buffer /// Interproccess buffer
pub struct IpcBuffer { pub struct IpcBuffer<'a> {
pub protocol: Protocol, pub protocol: Protocol<'a>,
pub buffer: BufferTypes, pub buffer: BufferTypes,
} }
impl IpcBuffer { impl<'a> IpcBuffer<'a> {
pub fn new(bounded: bool, length: u64) -> Self { pub fn new(bounded: bool, length: u64) -> Self {
log::debug!( log::debug!(
"New IPCBuffer\r "New IPCBuffer\r

View file

@ -10,11 +10,11 @@ pub struct Funct {
gives: Vec<String>, gives: Vec<String>,
} }
#[derive(Debug, PartialEq, Clone)] #[derive(Debug, PartialEq, Clone)]
pub struct Protocol { pub struct Protocol<'a> {
types: HashMap<String, Type>, types: HashMap<&'a str, Type>,
fns: HashMap<String, Funct>, fns: HashMap<&'a str, Funct>,
} }
impl Protocol { impl<'a> Protocol<'a> {
pub fn void() -> Self { pub fn void() -> Self {
Self { Self {
types: HashMap::new(), types: HashMap::new(),
@ -27,8 +27,8 @@ impl Protocol {
} }
} }
impl From<String> for Protocol { impl<'a> From<&'a str> for Protocol<'a> {
fn from(value: alloc::string::String) -> Self { fn from(value: &'a str) -> Self {
let mut hm_t = HashMap::new(); let mut hm_t = HashMap::new();
hm_t.insert(value, Type {}); hm_t.insert(value, Type {});
Self { Self {

View file

@ -72,16 +72,16 @@ pub fn kmain(_cmdline: &str, boot_modules: BootModules) -> ! {
for module in boot_modules.into_iter().take(bm_take) { for module in boot_modules.into_iter().take(bm_take) {
let mut cmd = module.cmd; let mut cmd = module.cmd;
if cmd.len() > 2 { if cmd.len() > 2 {
// Remove the quotes // // Remove the quotes
cmd.remove(0); // cmd.remove(0);
cmd.pop(); // cmd.pop();
cmd = &cmd[1..cmd.len()]
} }
let cmd_len = cmd.as_bytes().len() as u64; let cmd_len = cmd.len() as u64;
log::info!("Spawning {} with arguments \"{}\"", module.path, cmd); log::info!("Spawning {} with arguments \"{}\"", module.path, cmd);
executor executor.spawn(async move {
.spawn(async move {
let mut thr = ExecThread::new(&module.bytes, Address::new(0)); let mut thr = ExecThread::new(&module.bytes, Address::new(0));
if cmd_len > 0 { if cmd_len > 0 {
thr.set_arguments(cmd.as_bytes().as_ptr() as u64, cmd_len); thr.set_arguments(cmd.as_bytes().as_ptr() as u64, cmd_len);
@ -90,7 +90,6 @@ pub fn kmain(_cmdline: &str, boot_modules: BootModules) -> ! {
log::error!("{e:?}"); log::error!("{e:?}");
} }
}) })
.unwrap();
} }
info!("Random number: {}", hardware_random_u64()); info!("Random number: {}", hardware_random_u64());
@ -107,7 +106,7 @@ pub static DEVICE_TREE: Lazy<Mutex<DeviceTree>> = Lazy::new(|| {
}); });
pub static FB_REQ: FramebufferRequest = FramebufferRequest::new(0); pub static FB_REQ: FramebufferRequest = FramebufferRequest::new(0);
pub type IpcBuffers = HashMap<u64, IpcBuffer>; pub type IpcBuffers<'a> = HashMap<u64, IpcBuffer<'a>>;
pub static IPC_BUFFERS: Lazy<Mutex<IpcBuffers>> = Lazy::new(|| { pub static IPC_BUFFERS: Lazy<Mutex<IpcBuffers>> = Lazy::new(|| {
let mut bufs = HashMap::new(); let mut bufs = HashMap::new();
let log_buffer = IpcBuffer::new(false, 0); let log_buffer = IpcBuffer::new(false, 0);

View file

@ -1,17 +1,14 @@
use { use {
alloc::{boxed::Box, sync::Arc, task::Wake}, alloc::{boxed::Box, sync::Arc},
core::{ core::{
future::Future, future::Future,
pin::Pin, pin::Pin,
sync::atomic::{AtomicUsize, Ordering}, task::{Context, Poll, RawWaker, RawWakerVTable, Waker},
task::{Context, Poll, Waker},
}, },
crossbeam_queue::SegQueue, crossbeam_queue::SegQueue,
crossbeam_utils::CachePadded, slab::Slab,
}; };
use alloc::vec::Vec;
pub fn yield_now() -> impl Future<Output = ()> { pub fn yield_now() -> impl Future<Output = ()> {
struct YieldNow(bool); struct YieldNow(bool);
impl Future for YieldNow { impl Future for YieldNow {
@ -32,37 +29,34 @@ pub fn yield_now() -> impl Future<Output = ()> {
YieldNow(false) YieldNow(false)
} }
#[derive(Default)] pub struct Executor<F: Future<Output = ()> + Send> {
pub struct Executor { tasks: Slab<Task<F>>,
tasks: Vec<CachePadded<TaskSlot>>,
task_queue: Arc<TaskQueue>, task_queue: Arc<TaskQueue>,
max_tasks: usize,
} }
impl Executor { impl<F: Future<Output = ()> + Send> Executor<F> {
pub fn new(max_tasks: usize) -> Self { pub fn new(size: usize) -> Self {
Self { Self {
tasks: (0..max_tasks) tasks: Slab::with_capacity(size),
.map(|_| CachePadded::new(TaskSlot::default())) task_queue: Arc::new(TaskQueue::new()),
.collect(),
task_queue: Arc::new(TaskQueue::new(max_tasks)),
max_tasks,
} }
} }
pub fn spawn(&mut self, future: impl Future<Output = ()> + Send + 'static) -> Result<(), ()> { #[inline]
let task_id = self.task_queue.allocate_task_id().ok_or(())?; pub fn spawn(&mut self, future: F) {
self.tasks[task_id.0].lock.replace(Task::new(future)); self.task_queue
self.task_queue.push(task_id); .queue
Ok(()) .push(self.tasks.insert(Task::new(future)));
} }
pub fn run(&mut self) { pub fn run(&mut self) {
let mut task_batch = Vec::with_capacity(16); let mut task_batch = [0; 32];
let mut batch_len = 0;
loop { loop {
self.task_queue.batch_pop(&mut task_batch); self.task_queue.batch_pop(&mut task_batch, &mut batch_len);
if task_batch.is_empty() {
if batch_len == 0 {
if self.task_queue.is_empty() { if self.task_queue.is_empty() {
break; break;
} else { } else {
@ -70,23 +64,18 @@ impl Executor {
} }
} }
for id in task_batch.drain(..) { for &id in &task_batch[..batch_len] {
let task_slot = &mut self.tasks[id.0]; if let Some(task) = self.tasks.get_mut(id) {
let waker = task
.waker
.get_or_insert_with(|| TaskWaker::new(id, Arc::clone(&self.task_queue)));
let mut task_opt = task_slot.lock.take(); let waker = unsafe { Waker::from_raw(TaskWaker::into_raw_waker(waker)) };
if let Some(task) = &mut task_opt {
let waker = task_slot.waker.get_or_insert_with(|| {
Arc::new(TaskWaker::new(id, Arc::clone(&self.task_queue)))
});
let waker = Waker::from(Arc::clone(waker));
let mut cx = Context::from_waker(&waker); let mut cx = Context::from_waker(&waker);
if let Poll::Ready(()) = task.poll(&mut cx) { if let Poll::Ready(()) = task.poll(&mut cx) {
task_slot.waker = None; self.tasks.remove(id);
self.task_queue.free_task_id(id); self.task_queue.free_tasks.push(id);
} else {
task_slot.lock.replace(task_opt.take().unwrap());
} }
} }
} }
@ -94,21 +83,17 @@ impl Executor {
} }
} }
#[derive(Default)] struct Task<F: Future<Output = ()> + Send> {
struct TaskSlot { future: Pin<Box<F>>,
lock: Option<Task>, waker: Option<TaskWaker>,
waker: Option<Arc<TaskWaker>>,
} }
struct Task { impl<F: Future<Output = ()> + Send> Task<F> {
future: Pin<Box<dyn Future<Output = ()> + Send>>,
}
impl Task {
#[inline(always)] #[inline(always)]
pub fn new(future: impl Future<Output = ()> + Send + 'static) -> Self { pub fn new(future: F) -> Self {
Self { Self {
future: Box::pin(future), future: Box::pin(future),
waker: None,
} }
} }
@ -118,77 +103,69 @@ impl Task {
} }
} }
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
struct TaskId(usize);
struct TaskWaker { struct TaskWaker {
id: TaskId, id: usize,
task_queue: Arc<TaskQueue>, task_queue: Arc<TaskQueue>,
} }
impl TaskWaker { impl TaskWaker {
#[inline(always)] #[inline(always)]
pub fn new(id: TaskId, task_queue: Arc<TaskQueue>) -> Self { fn new(id: usize, task_queue: Arc<TaskQueue>) -> Self {
Self { id, task_queue } Self { id, task_queue }
} }
}
impl Wake for TaskWaker {
#[inline(always)] #[inline(always)]
fn wake(self: Arc<Self>) { fn wake(&self) {
self.task_queue.push(self.id); self.task_queue.queue.push(self.id);
} }
#[inline(always)] fn into_raw_waker(waker: &TaskWaker) -> RawWaker {
fn wake_by_ref(self: &Arc<Self>) { let ptr = waker as *const TaskWaker;
self.task_queue.push(self.id); RawWaker::new(ptr.cast(), &VTABLE)
} }
} }
#[derive(Default)] const VTABLE: RawWakerVTable = RawWakerVTable::new(clone_raw, wake_raw, wake_by_ref_raw, drop_raw);
unsafe fn clone_raw(ptr: *const ()) -> RawWaker {
let waker = &*(ptr as *const TaskWaker);
TaskWaker::into_raw_waker(waker)
}
unsafe fn wake_raw(ptr: *const ()) {
let waker = &*(ptr as *const TaskWaker);
waker.wake();
}
unsafe fn wake_by_ref_raw(ptr: *const ()) {
let waker = &*(ptr as *const TaskWaker);
waker.wake();
}
unsafe fn drop_raw(_: *const ()) {}
struct TaskQueue { struct TaskQueue {
queue: SegQueue<TaskId>, queue: SegQueue<usize>,
next_task: AtomicUsize, next_task: usize,
max_tasks: usize, free_tasks: SegQueue<usize>,
free_tasks: SegQueue<TaskId>,
} }
impl TaskQueue { impl TaskQueue {
fn new(max_tasks: usize) -> Self { fn new() -> Self {
Self { Self {
queue: SegQueue::new(), queue: SegQueue::new(),
next_task: AtomicUsize::new(0), next_task: 0,
max_tasks,
free_tasks: SegQueue::new(), free_tasks: SegQueue::new(),
} }
} }
fn allocate_task_id(&self) -> Option<TaskId> {
self.free_tasks.pop().or_else(|| {
let id = self.next_task.fetch_add(1, Ordering::Relaxed);
if id < self.max_tasks {
Some(TaskId(id))
} else {
None
}
})
}
#[inline(always)] #[inline(always)]
fn free_task_id(&self, id: TaskId) { fn batch_pop(&self, output: &mut [usize], len: &mut usize) {
self.free_tasks.push(id); *len = 0;
}
#[inline(always)]
fn push(&self, id: TaskId) {
self.queue.push(id);
}
#[inline(always)]
fn batch_pop(&self, output: &mut Vec<TaskId>) {
while let Some(id) = self.queue.pop() { while let Some(id) = self.queue.pop() {
output.push(id); output[*len] = id;
if output.len() >= output.capacity() { *len += 1;
if *len == output.len() {
break; break;
} }
} }

View file

@ -370,7 +370,7 @@ fn run(release: bool, target: Target) -> Result<(), Error> {
#[rustfmt::skip] #[rustfmt::skip]
com.args([ com.args([
"-M", "virt", "-M", "virt",
"-cpu", "cortex-a72", "-cpu", "max",
"-device", "ramfb", "-device", "ramfb",
"-device", "qemu-xhci", "-device", "qemu-xhci",
"-device", "usb-kbd", "-device", "usb-kbd",

View file

@ -29,8 +29,7 @@ total_pages := 1 + fb_bytes >> 12
front_buffer := @as(^Color, @bitcast(0xFFFF8000C0000000)) front_buffer := @as(^Color, @bitcast(0xFFFF8000C0000000))
// jank back buffer time, im sure nothing will go wrong // jank back buffer time, im sure nothing will go wrong
// will be removed as soon as i can figure out a fast way of doing runtime global scope back_buffer := front_buffer + fb_pixels
back_buffer := @as(^Color, @bitcast(0xFFFF8000C0000000 + fb_bytes))
create_back_buffer := fn(): ^Color { create_back_buffer := fn(): ^Color {
if total_pages <= 0xFF { if total_pages <= 0xFF {
@ -50,25 +49,26 @@ create_back_buffer := fn(): ^Color {
} }
clear := fn(color: Color): void { clear := fn(color: Color): void {
n := 0 cursor := back_buffer
loop if n == 512 break else { boundary := cursor + 512
*(back_buffer + n) = color loop if cursor == boundary break else {
n += 1 *cursor = color
cursor += 1
} }
n = 1 boundary += 512 * 7
loop if n == 8 break else { loop if cursor == boundary break else {
*(@as(^[Color; 512], @bitcast(back_buffer)) + n) = *@as(^[Color; 512], @bitcast(back_buffer)) *@as(^[Color; 512], @bitcast(cursor)) = *@as(^[Color; 512], @bitcast(back_buffer))
n += 1 cursor += 512
} }
n = 1 boundary += copy_pixels - 4096
loop if n == copy_pixels >> 12 break else { loop if cursor == boundary break else {
*(@as(^[Color; 4096], @bitcast(back_buffer)) + n) = *@as(^[Color; 4096], @bitcast(back_buffer)) *@as(^[Color; 4096], @bitcast(cursor)) = *@as(^[Color; 4096], @bitcast(back_buffer))
n += 1 cursor += 4096
} }
n = 1 boundary += (partitions - 1) * copy_pixels
loop if n == partitions break else { loop if cursor == boundary break else {
*(@as(^[Color; copy_pixels], @bitcast(back_buffer)) + n) = *@as(^[Color; copy_pixels], @bitcast(back_buffer)) *@as(^[Color; copy_pixels], @bitcast(cursor)) = *@as(^[Color; copy_pixels], @bitcast(back_buffer))
n += 1 cursor += @sizeof([u8; copy_pixels])
} }
return return
} }
@ -214,6 +214,13 @@ set_dimensions := fn(new: IVec2): void {
} }
init := fn(): void { init := fn(): void {
arch := @eca(int, 3, 5)
// 0: x86_64, 1: aarch64, 2: riscv, (2^64)-1: other
if arch == 0 {
front_buffer = @as(^Color, @bitcast(0xFFFF8000C0000000))
} else if arch == 1 {
front_buffer = @as(^Color, @bitcast(0xFFFF8000BC430000))
}
back_buffer = create_back_buffer() back_buffer = create_back_buffer()
return return
} }

View file

@ -1,4 +1,4 @@
.{example} := @use("./examples/amogus.hb") .{example} := @use("./examples/random.hb")
main := fn(): void { main := fn(): void {
@inline(example) @inline(example)

View file

@ -23,14 +23,14 @@ resolution = "1024x768x24"
[boot.limine.ableos.modules.1render_driver] [boot.limine.ableos.modules.1render_driver]
path = "boot:///render_driver.hbf" path = "boot:///render_driver.hbf"
[boot.limine.ableos.modules.0serial_driver] # [boot.limine.ableos.modules.0serial_driver]
path = "boot:///serial_driver.hbf" # path = "boot:///serial_driver.hbf"
[boot.limine.ableos.modules.diskio_driver] # [boot.limine.ableos.modules.diskio_driver]
path = "boot:///diskio_driver.hbf" # path = "boot:///diskio_driver.hbf"
[boot.limine.ableos.modules.render_example] [boot.limine.ableos.modules.render_example]
path = "boot:///render_example.hbf" path = "boot:///render_example.hbf"
[boot.limine.ableos.modules.serial_driver_test] # [boot.limine.ableos.modules.serial_driver_test]
path = "boot:///serial_driver_test.hbf" # path = "boot:///serial_driver_test.hbf"