Compare commits

...

12 commits

Author SHA1 Message Date
koniifer 555bc49663 minor jank auto resolution detection 2024-09-13 22:36:08 +01:00
koniifer 63c3544012 amogus example 2024-09-12 20:10:22 +01:00
koniifer e577572299 amazing random driver update 2024-09-12 19:44:27 +01:00
koniifer c2183d5138 auto framebuffer ptr 2024-09-12 18:25:30 +01:00
koniifer 022c1c196a works on arm and x86 without fiddling with stuff
memory bug fixes
update hblang
update render examples
obliterate render_driver (not useful)
2024-09-12 18:14:26 +01:00
koniifer fef5487e62 able told me to push 🙏 2024-09-11 23:09:47 +01:00
koniifer 3a6778149b update hblang 2024-09-10 00:17:59 +01:00
koniifer 3b95371c41 a touch more fiddling 2024-09-10 00:10:10 +01:00
koniifer fd155ea26a a touch of fiddling 2024-09-09 01:42:11 +01:00
koniifer 9b34e19005 fix stupid bug 2024-09-08 19:32:37 +01:00
koniifer 3ca7e13f3e pci interface skeleton
update hblang
improve libraries/render
hide some annoying warnings
minor changes to page allocator and buffers
implement page dealloc
fiddle with sysdata
2024-09-08 19:25:13 +01:00
koniifer 1031ca6314 reimplement fb_driver as software render interface. sufficiently jank double buffering implementation waiting on an intelligent design. 2024-09-07 23:08:58 +01:00
67 changed files with 1599 additions and 1281 deletions

777
Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -1,3 +1,9 @@
[workspace] [workspace]
resolver = "2" resolver = "2"
members = [ "dev","kernel", "repbuild"] members = ["dev", "kernel", "repbuild"]
# [profile.release]
# strip = "symbols"
# codegen-units = 1
# lto = true
# panic = "abort"

View file

@ -5,17 +5,16 @@ version = "0.2.0"
[dependencies] [dependencies]
embedded-graphics = "0.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"
uart_16550 = "0.2"
slab = { version = "0.4", default-features = false } slab = { version = "0.4", default-features = false }
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"
able_graphics_library.git = "https://git.ablecorp.us/ableos/ableos_userland" # able_graphics_library.git = "https://git.ablecorp.us/ableos/ableos_userland"
hashbrown = "*" hashbrown = { version = "0.14", features = ["nightly"] }
kiam = "0.1.1"
[dependencies.limine] [dependencies.limine]
version = "0.1" version = "0.1"
@ -24,14 +23,14 @@ version = "0.1"
[dependencies.crossbeam-queue] [dependencies.crossbeam-queue]
version = "0.3" version = "0.3"
default-features = false default-features = false
features = ["alloc"] features = ["alloc", "nightly"]
[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
[dependencies.derive_more] [dependencies.derive_more]
version = "0.99" version = "1"
default-features = false default-features = false
features = [ features = [
"add", "add",
@ -48,12 +47,12 @@ features = [
[target.'cfg(target_arch = "x86_64")'.dependencies] [target.'cfg(target_arch = "x86_64")'.dependencies]
x86_64 = "0.14" x86_64 = "0.15"
x2apic = "0.4" x2apic = "0.4"
virtio-drivers = "0.4.0" virtio-drivers = "0.7"
# rdrand = "*"
rdrand = { version = "0.8", default-features = false }
[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

@ -29,7 +29,7 @@ fn collect_cpu_info(device_tree: &mut DeviceTree) {
} }
fn cpu_id() -> (String, u64) { fn cpu_id() -> (String, u64) {
let mut cpu_id: u64 = 0; let mut cpu_id: u64;
unsafe { unsafe {
asm!("mrs {cpu_id}, MIDR_EL1", asm!("mrs {cpu_id}, MIDR_EL1",
cpu_id = out(reg) cpu_id, cpu_id = out(reg) cpu_id,
@ -41,6 +41,8 @@ fn cpu_id() -> (String, u64) {
// https://raspberrypi.stackexchange.com/questions/117175/how-do-i-read-the-cpuid-in-aarch64-asm // https://raspberrypi.stackexchange.com/questions/117175/how-do-i-read-the-cpuid-in-aarch64-asm
0x410FD034 => "Cortex-A53".to_string(), 0x410FD034 => "Cortex-A53".to_string(),
0x410FD083 => "Cortex-A72".to_string(), 0x410FD083 => "Cortex-A72".to_string(),
// the source of this one was checking the cpu id :thinking:
0x410FD493 => "Neoverse N2".to_string(),
_ => "Unknown".to_string(), _ => "Unknown".to_string(),
}; };
log::trace!("CPU Name: {cpu_name} - CPU ID: 0x{:X}", cpu_id); log::trace!("CPU Name: {cpu_name} - CPU ID: 0x{:X}", cpu_id);

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() -> ! {
@ -109,8 +103,19 @@ pub fn spin_loop() -> ! {
} }
} }
/// I am sorry.
static mut A_REAL_RANDOM_U64_I_PROMISE: u64 = 0;
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() {
return rnd;
}
}
unsafe {
A_REAL_RANDOM_U64_I_PROMISE += 1;
A_REAL_RANDOM_U64_I_PROMISE
}
} }
pub fn register_dump() {} pub fn register_dump() {}

View file

@ -1,8 +1,10 @@
use core::num; use core::num;
use alloc::boxed::Box; use {
use spin::{Mutex, Once}; crate::memory::{MemoryManager, PhysicalAddress, VirtualAddress},
use crate::memory::{MemoryManager, PhysicalAddress, VirtualAddress}; alloc::boxed::Box,
spin::{Mutex, Once},
};
use super::PAGE_SIZE; use super::PAGE_SIZE;
@ -28,7 +30,7 @@ impl PageSize {
} }
pub struct PageTable { pub struct PageTable {
entries: [PageEntry; 512] entries: [PageEntry; 512],
} }
impl PageTable { impl PageTable {
@ -72,8 +74,14 @@ impl PageTable {
/// flags MUST include one or more of the following: /// flags MUST include one or more of the following:
/// Read, Write, Execute /// Read, Write, Execute
/// The valid bit automatically gets added /// The valid bit automatically gets added
pub fn map(&mut self, vaddr: VirtualAddress, paddr: PhysicalAddress, flags: PageEntryFlags, page_size: PageSize) { pub fn map(
assert!(flags as usize & 0xe != 0); &mut self,
vaddr: VirtualAddress,
paddr: PhysicalAddress,
flags: PageEntryFlags,
page_size: PageSize,
) {
assert!(flags as usize & 0xE != 0);
let vpn = vaddr.vpns(); let vpn = vaddr.vpns();
let ppn = paddr.ppns(); let ppn = paddr.ppns();
@ -91,7 +99,7 @@ impl PageTable {
} }
let entry = v.addr().as_mut_ptr::<PageEntry>(); let entry = v.addr().as_mut_ptr::<PageEntry>();
v = unsafe { entry.add(vpn[i]).as_mut().unwrap() }; v = unsafe { entry.add(vpn[i]).as_mut().unwrap() };
} }
// When we get here, we should be at VPN[0] and v should be pointing to our entry. // When we get here, we should be at VPN[0] and v should be pointing to our entry.
@ -105,14 +113,24 @@ impl PageTable {
} }
/// Identity maps a page of memory /// Identity maps a page of memory
pub fn identity_map(&mut self, addr: PhysicalAddress, flags: PageEntryFlags, page_size: PageSize) { pub fn identity_map(
&mut self,
addr: PhysicalAddress,
flags: PageEntryFlags,
page_size: PageSize,
) {
// log::debug!("identity mapped {addr}"); // log::debug!("identity mapped {addr}");
self.map(addr.as_addr().into(), addr, flags, page_size); self.map(addr.as_addr().into(), addr, flags, page_size);
} }
/// Identity maps a range of contiguous memory /// Identity maps a range of contiguous memory
/// This assumes that start <= end /// This assumes that start <= end
pub fn identity_map_range(&mut self, start: PhysicalAddress, end: PhysicalAddress, flags: PageEntryFlags) { pub fn identity_map_range(
&mut self,
start: PhysicalAddress,
end: PhysicalAddress,
flags: PageEntryFlags,
) {
log::debug!("start: {start}, end: {end}"); log::debug!("start: {start}, end: {end}");
let mut mem_addr = start.as_addr() & !(PAGE_SIZE - 1); let mut mem_addr = start.as_addr() & !(PAGE_SIZE - 1);
let num_pages = (align_val(end.as_addr(), 12) - mem_addr - 1) / PAGE_SIZE + 1; let num_pages = (align_val(end.as_addr(), 12) - mem_addr - 1) / PAGE_SIZE + 1;
@ -142,7 +160,7 @@ impl PageTable {
} }
let entry = v.addr().as_mut_ptr::<PageEntry>(); let entry = v.addr().as_mut_ptr::<PageEntry>();
v = unsafe { entry.add(vpn[i]).as_mut().unwrap() }; v = unsafe { entry.add(vpn[i]).as_mut().unwrap() };
} }
// If we're here this is an unmapped page // If we're here this is an unmapped page
@ -228,7 +246,7 @@ impl PageEntry {
} }
fn addr(&self) -> PhysicalAddress { fn addr(&self) -> PhysicalAddress {
((self.entry() as usize & !0x3ff) << 2).into() ((self.entry() as usize & !0x3FF) << 2).into()
} }
fn destroy(&mut self) { fn destroy(&mut self) {

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,24 +35,24 @@ 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
}; };
tss.interrupt_stack_table[usize::from(DOUBLE_FAULT_IX)] = stack_ptr;
tss tss
}); });
static GDT: Lazy<(GlobalDescriptorTable, Selectors)> = Lazy::new(|| { static GDT: Lazy<(GlobalDescriptorTable, Selectors)> = Lazy::new(|| {
let mut gdt = GlobalDescriptorTable::new(); let mut gdt = GlobalDescriptorTable::new();
let sels = Selectors { let sels = Selectors {
kcode: gdt.add_entry(Descriptor::kernel_code_segment()), kcode: gdt.append(Descriptor::kernel_code_segment()),
kdata: gdt.add_entry(Descriptor::kernel_data_segment()), kdata: gdt.append(Descriptor::kernel_data_segment()),
tss: gdt.add_entry(Descriptor::tss_segment(&TSS)), tss: gdt.append(Descriptor::tss_segment(&TSS)),
}; };
(gdt, sels) (gdt, sels)
}); });

View file

@ -45,9 +45,9 @@ static IDT: Lazy<InterruptDescriptorTable> = Lazy::new(|| {
} }
idt.page_fault.set_handler_fn(page_fault); idt.page_fault.set_handler_fn(page_fault);
idt[Interrupt::ApicErr as usize].set_handler_fn(apic_err); idt[Interrupt::ApicErr as u8].set_handler_fn(apic_err);
idt[Interrupt::Spurious as usize].set_handler_fn(spurious); idt[Interrupt::Spurious as u8].set_handler_fn(spurious);
idt[Interrupt::Timer as usize].set_handler_fn(timer); idt[Interrupt::Timer as u8].set_handler_fn(timer);
idt idt
}); });

View file

@ -1,11 +1,6 @@
//! Logging (as in terms of console / serial output) //! Logging (as in terms of console / serial output)
#![allow(deprecated)] #![allow(deprecated)]
use { use {core::fmt::Write, spin::Mutex, uart_16550::SerialPort};
core::fmt::Write,
limine::{TerminalRequest, TerminalResponse},
spin::{Lazy, Mutex},
uart_16550::SerialPort,
};
pub static SERIAL_CONSOLE: Mutex<SerialPort> = Mutex::new(unsafe { SerialPort::new(0x3F8) }); pub static SERIAL_CONSOLE: Mutex<SerialPort> = Mutex::new(unsafe { SerialPort::new(0x3F8) });

View file

@ -1,7 +1,6 @@
use { use core::arch::x86_64::{_rdrand64_step, _rdseed64_step};
crate::bootmodules::BootModule, core::arch::asm, embedded_graphics::pixelcolor::Rgb888,
log::warn, rdrand::RdSeed, use {crate::bootmodules::BootModule, core::arch::asm, log::warn};
};
pub mod memory; pub mod memory;
mod cpuid; mod cpuid;
@ -143,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);
} }
@ -195,59 +189,20 @@ unsafe extern "C" fn start() -> ! {
/// Spin loop /// Spin loop
pub fn spin_loop() -> ! { pub fn spin_loop() -> ! {
loop { loop {
x86_64::instructions::hlt(); x86_64::instructions::hlt()
} }
} }
pub fn hardware_random_u64() -> u64 { pub fn hardware_random_u64() -> u64 {
use {log::trace, rdrand::RdRand}; let mut out: u64 = 0;
let gen = RdRand::new(); match unsafe { _rdrand64_step(&mut out) } {
match gen { 1 => out,
Ok(gen) => { _ => {
let ret = gen.try_next_u64().unwrap();
trace!("Random {}", ret);
return ret;
}
Err(err) => {
warn!("RDRand not supported."); warn!("RDRand not supported.");
// Try rdseed // Try rdseed
let gen = RdSeed::new(); match unsafe { _rdseed64_step(&mut out) } {
match gen { 1 => out,
Ok(gen) => { _ => panic!("Neither RDRand or RDSeed are supported"),
let ret = gen.try_next_u64().unwrap();
trace!("Random {}", ret);
return ret;
}
Err(err) => {
panic!("Neither RDRand or RDSeed are supported")
}
}
}
}
}
pub fn hardware_random_u32() -> u32 {
use {log::trace, rdrand::RdRand};
let gen = RdRand::new();
match gen {
Ok(gen) => {
let ret = gen.try_next_u32().unwrap();
trace!("Random {}", ret);
return ret;
}
Err(err) => {
warn!("RDRand not supported.");
// Try rdseed
let gen = RdSeed::new();
match gen {
Ok(gen) => {
let ret = gen.try_next_u32().unwrap();
trace!("Random {}", ret);
return ret;
}
Err(err) => {
panic!("Neither RDRand or RDSeed are supported")
}
} }
} }
} }
@ -255,6 +210,7 @@ pub fn hardware_random_u32() -> u32 {
pub fn get_edid() {} pub fn get_edid() {}
#[allow(unused)]
pub fn register_dump() { pub fn register_dump() {
let rax: u64; let rax: u64;
let rbx: u64 = 0; let rbx: u64 = 0;

View file

@ -1,36 +1,36 @@
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 }
} }
} }
pub fn build_cmd<T: Display + Debug>(name: T, cmdline: T) -> XMLElement { // pub fn build_cmd<T: Display + Debug>(name: T, cmdline: T) -> XMLElement {
let mut cmdline = cmdline.to_string(); // let mut cmdline = cmdline.to_string();
cmdline.pop(); // cmdline.pop();
cmdline.remove(0); // cmdline.remove(0);
let cmd = Arguments::parse(cmdline.to_string()).unwrap(); // let cmd = Arguments::parse(cmdline.to_string()).unwrap();
trace!("Cmdline: {cmd:?}"); // trace!("Cmdline: {cmd:?}");
let mut clo = XMLElement::new(name); // let mut clo = XMLElement::new(name);
for (key, value) in cmd.arguments { // for (key, value) in cmd.arguments {
clo.set_attribute(key, value); // clo.set_attribute(key, value);
} // }
trace!("command line object: {:?}", clo); // trace!("command line object: {:?}", clo);
clo // clo
} // }

View file

@ -1,19 +1,10 @@
//! Environment call handling routines //! Environment call handling routines
use core::borrow::Borrow; use crate::holeybytes::kernel_services::{block_read, service_definition_service::sds_msg_handler};
use crate::{
allocator,
holeybytes::kernel_services::{
block_read,
service_definition_service::{sds_msg_handler, SERVICES},
},
};
use { use {
super::{mem::Memory, Vm}, super::Vm,
crate::{arch, holeybytes::mem, 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},
}; };
@ -78,7 +69,7 @@ pub fn handler(vm: &mut Vm) {
}, },
1 => match log_msg_handler(vm, mem_addr, length) { 1 => match log_msg_handler(vm, mem_addr, length) {
Ok(()) => {} Ok(()) => {}
Err(err) => log::error!("Improper log format"), Err(_) => log::error!("Improper log format"),
}, },
2 => { 2 => {
use crate::holeybytes::kernel_services::mem_serve::memory_msg_handler; use crate::holeybytes::kernel_services::mem_serve::memory_msg_handler;
@ -87,29 +78,21 @@ 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) { let msg_vec = block_read(mem_addr, length);
x86_64::instructions::port::Port::new(address).write(value);
}
let mut msg_vec = block_read(mem_addr, length);
let msg_type = msg_vec[0]; let msg_type = msg_vec[0];
msg_vec.remove(0);
match msg_type { match msg_type {
0 => 'wow: { 0 => 'wow: {
let size = match msg_vec[0] { let size = match msg_vec[0] {
@ -121,24 +104,20 @@ pub fn handler(vm: &mut Vm) {
break 'wow; break 'wow;
} }
}; };
msg_vec.remove(0); let addr = u16::from_le_bytes(msg_vec[1..3].try_into().unwrap());
let addr = u16::from_le_bytes(msg_vec[0..2].try_into().unwrap());
msg_vec.remove(0);
msg_vec.remove(0);
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?"),
} }
}; };
msg_vec.clear();
trace!("Read the value {} from address {}", value, addr); trace!("Read the value {} from address {}", value, addr);
vm.registers[1] = hbvm::value::Value(value); vm.registers[1] = hbvm::value::Value(value);
} }
1 => 'wow: { 1 => 'wow: {
let size = match msg_vec[0] { let size = match msg_vec[1] {
0 => 1, 0 => 1,
1 => 2, 1 => 2,
2 => 4, 2 => 4,
@ -147,50 +126,88 @@ pub fn handler(vm: &mut Vm) {
break 'wow; break 'wow;
} }
}; };
msg_vec.remove(0); let addr = unsafe {
let addr = u16::from_le_bytes(msg_vec[0..2].try_into().unwrap()); u16::from_le_bytes(msg_vec[1..3].try_into().unwrap_unchecked())
msg_vec.remove(0); };
msg_vec.remove(0);
trace!("Setting address {}", addr); trace!("Setting address {}", addr);
unsafe { unsafe {
match size { match size {
1 => x86_out(addr, msg_vec[0]), 1 => x86_out(addr, msg_vec[3]),
2 => x86_out_16( 2 => x86_out(
addr, addr,
u16::from_le_bytes(msg_vec[0..2].try_into().unwrap()), u16::from_le_bytes(
msg_vec[3..5].try_into().unwrap_unchecked(),
),
), ),
4 => x86_out_32( 4 => x86_out(
addr, addr,
u32::from_le_bytes(msg_vec[0..4].try_into().unwrap()), u32::from_le_bytes(
msg_vec[3..7].try_into().unwrap_unchecked(),
),
), ),
_ => panic!("How?"), _ => panic!("How?"),
} }
} }
msg_vec.clear();
} }
_ => {} _ => {}
} }
} }
// 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);
}
// get arch
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)
}
}
// AbleCode™ (get fb ptr)
6 => {
use {
crate::kmain::FB_REQ,
limine::{Framebuffer, NonNullPtr},
};
let fb1: &NonNullPtr<Framebuffer> =
&FB_REQ.get_response().get().unwrap().framebuffers()[0];
let msg = block_read(mem_addr, length)[0];
if msg == b'p' {
// ptr
let fb_front = fb1.address.as_ptr().unwrap() as *const u8;
log::info!("Graphics front ptr {:?}", fb_front);
vm.registers[1] = hbvm::value::Value(fb_front as u64);
} else if msg == b'w' {
// width
log::info!("FB Width: {}", fb1.width);
vm.registers[1] = hbvm::value::Value(fb1.width);
} else if msg == b'h' {
// height
log::info!("FB Height: {}", fb1.height);
vm.registers[1] = hbvm::value::Value(fb1.height);
}
} }
buffer_id => { buffer_id => {
let mut buffs = IPC_BUFFERS.lock(); let mut buffs = IPC_BUFFERS.lock();
match buffs.get_mut(&buffer_id) { match buffs.get_mut(&buffer_id) {
Some(buff) => { Some(buff) => {
let mut msg_vec = vec![]; let mut msg_vec = Vec::with_capacity(length);
for x in 0..(length as isize) { for x in 0..(length as isize) {
let xyz = mem_addr as *const u8; let xyz = mem_addr as *const u8;
let value = unsafe { xyz.offset(x).read() }; let value = unsafe { xyz.offset(x).read() };
msg_vec.push(value); msg_vec.push(value);
} }
buff.push(msg_vec.clone());
debug!( debug!(
"Message {:?} has been sent to Buffer({})", "Message {:?} has been sent to Buffer({})",
msg_vec, buffer_id msg_vec, buffer_id
); );
buff.push(msg_vec);
} }
None => { None => {
log::error!("Access of non-existent buffer {}", buffer_id) log::error!("Access of non-existent buffer {}", buffer_id)
@ -206,7 +223,7 @@ pub fn handler(vm: &mut Vm) {
let max_length = vm.registers[5].cast::<u64>(); let max_length = vm.registers[5].cast::<u64>();
let mut buffs = IPC_BUFFERS.lock(); let mut buffs = IPC_BUFFERS.lock();
let mut buff: &mut IpcBuffer; let buff: &mut IpcBuffer;
if buffs.get_mut(&buffer_id).is_some() { if buffs.get_mut(&buffer_id).is_some() {
buff = buffs.get_mut(&buffer_id).unwrap(); buff = buffs.get_mut(&buffer_id).unwrap();
@ -255,16 +272,16 @@ 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 {
0 | 48 => error!("{}", strr), 0 | 48 => error!("{}", strr),
1 | 49 => warn!("{}", strr), 1 | 49 => warn!("{}", strr),
2 | 50 => info!("{}", strr), 2 | 50 => info!("{}", strr),
@ -288,8 +305,8 @@ pub enum LogError {
NoMessages, NoMessages,
InvalidLogFormat, InvalidLogFormat,
} }
use {alloc::vec, log::Record};
// use {alloc::vec, log::Record};
// fn memory_msg_handler(vm: &mut Vm, mem_addr: u64, length: usize) -> Result<(), LogError> { // fn memory_msg_handler(vm: &mut Vm, mem_addr: u64, length: usize) -> Result<(), LogError> {
// let mut val = alloc::vec::Vec::new(); // let mut val = alloc::vec::Vec::new();
// for _ in 0..4096 { // for _ in 0..4096 {

View file

@ -1,10 +1,7 @@
use { use {
crate::holeybytes::{ crate::holeybytes::{kernel_services::block_read, Vm},
ecah::LogError, alloc::alloc::{alloc_zeroed, dealloc},
kernel_services::{block_read, mem_serve}, core::alloc::Layout,
Vm,
},
alloc::alloc::alloc_zeroed,
log::{debug, info}, log::{debug, info},
}; };
@ -19,13 +16,10 @@ pub enum MemoryQuotaType {
KillQuota = 3, KillQuota = 3,
} }
fn alloc_page(vm: &mut Vm, mem_addr: u64, length: usize) -> Result<(), MemoryServiceError> { fn alloc_page(vm: &mut Vm, _mem_addr: u64, _length: usize) -> Result<(), MemoryServiceError> {
let mut val = alloc::vec::Vec::new(); let ptr = unsafe { alloc_zeroed(Layout::new::<[u8; 4096]>()) };
for _ in 0..4096 { info!("Block address: {:?}", ptr);
val.push(0); vm.registers[1] = hbvm::value::Value(ptr as u64);
}
info!("Block address: {:?}", val.as_ptr());
vm.registers[1] = hbvm::value::Value(val.as_ptr() as u64);
vm.registers[2] = hbvm::value::Value(4096); vm.registers[2] = hbvm::value::Value(4096);
Ok(()) Ok(())
} }
@ -35,34 +29,39 @@ pub fn memory_msg_handler(
mem_addr: u64, mem_addr: u64,
length: usize, length: usize,
) -> Result<(), MemoryServiceError> { ) -> Result<(), MemoryServiceError> {
let mut 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];
msg_vec.remove(0);
match msg_type { match msg_type {
0 => { 0 => {
let page_count = msg_vec[0]; let page_count = msg_vec[1];
msg_vec.remove(0); let mptr_raw: [u8; 8] = msg_vec[2..10].try_into().unwrap();
let mptr_raw: [u8; 8] = msg_vec[0..8].try_into().unwrap();
let mptr: u64 = u64::from_le_bytes(mptr_raw); let mptr: u64 = u64::from_le_bytes(mptr_raw);
log::debug!("Allocating {} pages @ {:x}", page_count, mptr); log::debug!("Allocating {} pages @ {:x}", page_count, mptr);
let mut val = alloc::vec::Vec::new(); let ptr = unsafe {
for _ in 0..(page_count as isize * 4096) { alloc_zeroed(Layout::from_size_align_unchecked(
val.push(0); page_count as usize * 4096,
} 1,
vm.registers[1] = hbvm::value::Value(val.as_ptr() as u64); ))
log::debug!("Kernel ptr: {:x}", val.as_ptr() as u64); };
}
1 => {
let page_count = msg_vec[0];
msg_vec.remove(0);
let mptr_raw: [u8; 8] = msg_vec[0..8].try_into().unwrap(); vm.registers[1] = hbvm::value::Value(ptr as u64);
log::debug!("Kernel ptr: {:x}", ptr as u64);
}
1 => {
let page_count = msg_vec[1];
let mptr_raw: [u8; 8] = msg_vec[2..10].try_into().unwrap();
let mptr: u64 = u64::from_le_bytes(mptr_raw); let mptr: u64 = u64::from_le_bytes(mptr_raw);
log::debug!("Deallocating {} pages @ {:x}", page_count, mptr); log::debug!("Deallocating {} pages @ {:x}", page_count, mptr);
unsafe {
dealloc(
mptr as *mut u8,
Layout::from_size_align_unchecked(page_count as usize * 4096, 1),
)
}
} }
2 => { 2 => {
use MemoryQuotaType::*; use MemoryQuotaType::*;
@ -73,19 +72,10 @@ pub fn memory_msg_handler(
3 => KillQuota, 3 => KillQuota,
_ => NoQuota, _ => NoQuota,
}; };
msg_vec.remove(0); let hid_raw: [u8; 8] = msg_vec[2..10].try_into().unwrap();
let hid_raw: [u8; 8] = msg_vec[0..8].try_into().unwrap();
let hid: u64 = u64::from_le_bytes(hid_raw); let hid: u64 = u64::from_le_bytes(hid_raw);
for _ in 0..8 { let pid_raw: [u8; 8] = msg_vec[10..18].try_into().unwrap();
msg_vec.remove(0); let pid: u64 = u64::from_le_bytes(pid_raw);
}
let pid_raw: [u8; 8] = msg_vec[0..8].try_into().unwrap();
let pid: u64 = u64::from_le_bytes(hid_raw);
for _ in 0..8 {
msg_vec.remove(0);
}
debug!( debug!(
"Setting HID-{:x}:PID-{:x}'s quota type to {:?}", "Setting HID-{:x}:PID-{:x}'s quota type to {:?}",
hid, pid, quota_type hid, pid, quota_type
@ -94,7 +84,6 @@ pub fn memory_msg_handler(
3 => { 3 => {
let page_count = msg_vec[0]; let page_count = msg_vec[0];
log::debug!(" {} pages", page_count); log::debug!(" {} pages", page_count);
msg_vec.remove(0);
} }
_ => { _ => {

View file

@ -1,15 +1,9 @@
use alloc::{vec, 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![]; pub fn block_read<'a>(mem_addr: u64, length: usize) -> &'a [u8] {
unsafe { slice::from_raw_parts(mem_addr as *const u8, length) }
for x in 0..(length as isize) {
let xyz = mem_addr as *const u8;
let value = unsafe { xyz.offset(x).read() };
msg_vec.push(value);
}
msg_vec
} }

View file

@ -1,20 +1,15 @@
use { use {
crate::{ crate::{
alloc::string::ToString,
arch::hardware_random_u64, arch::hardware_random_u64,
holeybytes::{ecah::LogError, kernel_services::block_read, Vm}, holeybytes::{ecah::LogError, kernel_services::block_read, Vm},
ipc::{ ipc::{buffer::IpcBuffer, protocol::Protocol},
buffer::IpcBuffer,
protocol::{self, 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());
@ -22,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);
} }
@ -82,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);
@ -99,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 mut 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

@ -7,7 +7,7 @@
use hbvm::mem::Address; use hbvm::mem::Address;
fn calc_start_of_page(ptr: u64) -> u64 { fn calc_start_of_page(ptr: u64) -> u64 {
let mut page_aligned = false; let _page_aligned = false;
if ptr % 4096 == 0 { if ptr % 4096 == 0 {
// page_aligned = true; // page_aligned = true;
return ptr / 4096; return ptr / 4096;
@ -21,11 +21,11 @@ pub struct Memory {
impl Memory { impl Memory {
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
fn read_device(addr: Address) { fn read_device(_addr: Address) {
unsafe { //unsafe {
// //
// x86_64::instructions::port::Port::new(addr.get()).read() // x86_64::instructions::port::Port::new(addr.get()).read()
} //}
} }
} }
@ -37,7 +37,6 @@ impl hbvm::mem::Memory for Memory {
target: *mut u8, target: *mut u8,
count: usize, count: usize,
) -> Result<(), hbvm::mem::LoadError> { ) -> Result<(), hbvm::mem::LoadError> {
use log::{error, info};
if addr.get() % 4096 == 0 {} if addr.get() % 4096 == 0 {}
core::ptr::copy(addr.get() as *const u8, target, count); core::ptr::copy(addr.get() as *const u8, target, count);
Ok(()) Ok(())
@ -56,6 +55,6 @@ impl hbvm::mem::Memory for Memory {
#[inline] #[inline]
unsafe fn prog_read<T: Copy>(&mut self, addr: Address) -> T { unsafe fn prog_read<T: Copy>(&mut self, addr: Address) -> T {
(addr.get() as *const T).read_unaligned() (addr.get() as *const T).read()
} }
} }

View file

@ -3,86 +3,86 @@ mod kernel_services;
mod mem; mod mem;
use { use {
crate::{arch, ipc::buffer::IpcBuffer, kmain::IPC_BUFFERS}, alloc::alloc::{alloc_zeroed, dealloc},
alloc::boxed::Box, core::{
core::{default, future::Future, marker::PhantomData, ptr::NonNull, task::Poll}, alloc::Layout,
future::Future,
pin::Pin,
task::{Context, Poll},
},
hbvm::{ hbvm::{
mem::{ mem::{softpaging::HandlePageFault, Address},
softpaging::{icache::ICache, HandlePageFault, SoftPagedMem},
Address, Memory,
},
VmRunError, VmRunOk, VmRunError, VmRunOk,
}, },
log::{debug, error, info, trace, warn}, log::error,
}; };
const STACK_SIZE: usize = 1024 * 1024; const STACK_SIZE: usize = 1024 * 1024;
const TIMER_QUOTIENT: usize = 100; 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: *mut 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 = unsafe { let mut vm = Vm::new(
Vm::new( mem::Memory {},
mem::Memory {}, Address::new(program.as_ptr() as u64 + entrypoint.get()),
Address::new(program.as_ptr() as u64 + entrypoint.get()), );
)
}; let stack_bottom = allocate_stack();
let stack_bottom = unsafe { allocate_stack().as_ptr() };
vm.write_reg(254, (stack_bottom as usize + STACK_SIZE - 1) as u64); vm.write_reg(254, (stack_bottom as usize + STACK_SIZE - 1) as u64);
ExecThread { ExecThread { vm, stack_bottom }
vm,
stack_bottom,
_phantom: Default::default(),
}
} }
} }
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, 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>;
fn poll( #[inline(always)]
mut self: core::pin::Pin<&mut Self>, fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
cx: &mut core::task::Context<'_>,
) -> Poll<Self::Output> {
match self.vm.run() { match self.vm.run() {
Err(err) => { Err(err) => {
log::error!("HBVM Error\r\nRegister dump: {:?}", self.vm.registers,); error!("HBVM Error\r\nRegister dump: {:?}", self.vm.registers);
return Poll::Ready(Err(err)); Poll::Ready(Err(err))
}
Ok(VmRunOk::End) => Poll::Ready(Ok(())),
Ok(VmRunOk::Ecall) => {
ecah::handler(&mut self.vm);
cx.waker().wake_by_ref();
Poll::Pending
}
Ok(VmRunOk::Timer) => {
cx.waker().wake_by_ref();
Poll::Pending
} }
Ok(VmRunOk::End) => return Poll::Ready(Ok(())),
Ok(VmRunOk::Ecall) => ecah::handler(&mut self.vm),
Ok(VmRunOk::Timer) => (),
Ok(VmRunOk::Breakpoint) => { Ok(VmRunOk::Breakpoint) => {
log::error!( error!(
"HBVM Debug breakpoint\r\nRegister dump: {:?}", "HBVM Debug breakpoint\r\nRegister dump: {:?}",
self.vm.registers, self.vm.registers
); );
cx.waker().wake_by_ref();
Poll::Pending
} }
} }
cx.waker().wake_by_ref();
Poll::Pending
} }
} }
@ -91,33 +91,22 @@ impl HandlePageFault for PageFaultHandler {
fn page_fault( fn page_fault(
&mut self, &mut self,
reason: hbvm::mem::MemoryAccessReason, reason: hbvm::mem::MemoryAccessReason,
pagetable: &mut hbvm::mem::softpaging::paging::PageTable, _pagetable: &mut hbvm::mem::softpaging::paging::PageTable,
vaddr: hbvm::mem::Address, vaddr: hbvm::mem::Address,
size: hbvm::mem::softpaging::PageSize, size: hbvm::mem::softpaging::PageSize,
dataptr: *mut u8, dataptr: *mut u8,
) -> bool ) -> bool {
where error!("REASON: {reason} vaddr: {vaddr} size: {size:?} Dataptr {dataptr:p}");
Self: Sized,
{
log::error!(
"REASON: {reason} \
vaddr: {vaddr} \
size: {size:?} \
Dataptr {dataptr:p}",
);
false false
} }
} }
const fn stack_layout() -> core::alloc::Layout { #[inline(always)]
unsafe { alloc::alloc::Layout::from_size_align_unchecked(STACK_SIZE, 4096) } const fn stack_layout() -> Layout {
unsafe { Layout::from_size_align_unchecked(STACK_SIZE, 4096) }
} }
fn allocate_stack() -> NonNull<u8> { #[inline(always)]
let layout = stack_layout(); fn allocate_stack() -> *mut u8 {
match NonNull::new(unsafe { alloc::alloc::alloc_zeroed(layout) }) { unsafe { alloc_zeroed(stack_layout()) }
Some(ptr) => ptr,
None => 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
@ -24,7 +24,7 @@ impl IpcBuffer {
length length
); );
match (bounded, length) { match (bounded, length) {
(false, a) => { (false, ..) => {
let buftype = BufferTypes::Unbound(SegQueue::new()); let buftype = BufferTypes::Unbound(SegQueue::new());
Self { Self {
@ -48,9 +48,9 @@ impl IpcBuffer {
} }
pub fn push(&mut self, msg: Message) { pub fn push(&mut self, msg: Message) {
match &self.buffer { match &self.buffer {
BufferTypes::Unbound(buff) => buff.push(msg.clone()), BufferTypes::Unbound(buff) => buff.push(msg),
BufferTypes::Bound(buff) => { BufferTypes::Bound(buff) => {
let _ = buff.push(msg.clone()); let _ = buff.push(msg);
} }
}; };
} }

View file

@ -1,7 +1,6 @@
use { use {
alloc::{string::String, vec::Vec}, alloc::{string::String, vec::Vec},
hashbrown::HashMap, hashbrown::HashMap,
log::info,
}; };
#[derive(Debug, PartialEq, Clone)] #[derive(Debug, PartialEq, Clone)]
pub struct Type {} pub struct Type {}
@ -11,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(),
@ -28,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

@ -2,27 +2,25 @@
use { use {
crate::{ crate::{
arch::{hardware_random_u64, logging::SERIAL_CONSOLE}, arch::hardware_random_u64,
bootmodules::{build_cmd, BootModules}, bootmodules::BootModules,
capabilities, //bootmodules::build_cmd,
device_tree::DeviceTree, device_tree::DeviceTree,
holeybytes::ExecThread, holeybytes::ExecThread,
ipc::buffer::{self, IpcBuffer}, ipc::buffer::IpcBuffer,
}, },
alloc::format,
hashbrown::HashMap, hashbrown::HashMap,
hbvm::mem::Address, hbvm::mem::Address,
limine::{Framebuffer, FramebufferRequest, NonNullPtr}, limine::{Framebuffer, FramebufferRequest, NonNullPtr},
log::{debug, info, trace}, log::{debug, info},
spin::{Lazy, Mutex}, spin::{Lazy, Mutex},
xml::XMLElement,
}; };
pub fn kmain(cmdline: &str, boot_modules: BootModules) -> ! { pub fn kmain(_cmdline: &str, boot_modules: BootModules) -> ! {
debug!("Entered kmain"); debug!("Entered kmain");
let kcmd = build_cmd("Kernel Command Line", cmdline); // let kcmd = build_cmd("Kernel Command Line", cmdline);
trace!("Cmdline: {kcmd:?}"); // trace!("Cmdline: {kcmd:?}");
// for (i, bm) in boot_modules.iter().enumerate() { // for (i, bm) in boot_modules.iter().enumerate() {
// let name = format!("module-{}", i); // let name = format!("module-{}", i);
@ -68,17 +66,18 @@ pub fn kmain(cmdline: &str, boot_modules: BootModules) -> ! {
fb1.address.as_ptr().unwrap() as *const u8 fb1.address.as_ptr().unwrap() as *const u8
); );
let mut executor = crate::task::Executor::default(); let mut executor = crate::task::Executor::new(256);
let bm_take = boot_modules.len(); let bm_take = boot_modules.len();
unsafe { unsafe {
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);
@ -87,11 +86,10 @@ pub fn kmain(cmdline: &str, boot_modules: BootModules) -> ! {
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);
} }
if let Err(e) = thr.await { if let Err(e) = thr.await {
log::error!("{e:?}"); log::error!("{e:?}");
} }
}); })
} }
info!("Random number: {}", hardware_random_u64()); info!("Random number: {}", hardware_random_u64());
@ -108,8 +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);
use alloc::vec::Vec; pub type IpcBuffers<'a> = HashMap<u64, IpcBuffer<'a>>;
pub type IpcBuffers = HashMap<u64, IpcBuffer>;
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,21 +1,19 @@
//! The ableOS kernel. //! The ableOS kernel.
//! Named akern. //! Named akern.
//! Akern is woefully undersupported at the moment but we are looking to add support improve hardware discovery and make our lives as kernel and operating system developers easier and better //! Akern is woefully undersupported at the moment but we are looking to add support improve hardware discovery and make our lives as kernel and operating system developers easier and better
#![no_std] #![no_std]
#![feature(new_uninit)]
#![feature( #![feature(
abi_x86_interrupt, abi_x86_interrupt,
alloc_error_handler, alloc_error_handler,
inline_const,
panic_info_message,
pointer_is_aligned,
ptr_sub_ptr, ptr_sub_ptr,
custom_test_frameworks, custom_test_frameworks,
naked_functions, naked_functions,
pointer_is_aligned_to pointer_is_aligned_to
)] )]
#![allow(dead_code)]
#![test_runner(crate::test_runner)] #![test_runner(crate::test_runner)]
#![cfg_attr(not(debug_assertions), allow(unused, deprecated))]
#![allow(dead_code)]
extern crate alloc; extern crate alloc;
mod allocator; mod allocator;
@ -42,6 +40,7 @@ pub const VERSION: Version = Version {
}; };
#[panic_handler] #[panic_handler]
#[cfg(target_os = "none")]
fn panic(info: &core::panic::PanicInfo) -> ! { fn panic(info: &core::panic::PanicInfo) -> ! {
arch::register_dump(); arch::register_dump();
@ -54,10 +53,8 @@ fn panic(info: &core::panic::PanicInfo) -> ! {
)); ));
} }
if let Some(msg) = info.message() { let msg = info.message();
let _ = crate::arch::log(format_args!("{msg}\r\n")); let _ = crate::arch::log(format_args!("{msg}\r\n"));
}
loop {} loop {}
} }

View file

@ -1,3 +1,4 @@
#![allow(deprecated)]
// TODO: Add a logger api with logger levels and various outputs // TODO: Add a logger api with logger levels and various outputs
pub static TERMINAL_LOGGER: Lazy<Mutex<TermLogger>> = Lazy::new(|| Mutex::new(TermLogger::new())); pub static TERMINAL_LOGGER: Lazy<Mutex<TermLogger>> = Lazy::new(|| Mutex::new(TermLogger::new()));

View file

@ -1,7 +1,6 @@
//! The Memory Manager //! The Memory Manager
use alloc::collections::VecDeque; use {alloc::collections::VecDeque, derive_more::*};
use derive_more::*;
pub use crate::arch::PAGE_SIZE; pub use crate::arch::PAGE_SIZE;
pub const MAX_ORDER: usize = 10; pub const MAX_ORDER: usize = 10;
@ -44,7 +43,7 @@ pub const MAX_ORDER: usize = 10;
Sum, Sum,
UpperHex, UpperHex,
)] )]
#[display(fmt = "0x{:x}", _0)] #[display("0x{:x}", _0)]
#[from(forward)] #[from(forward)]
pub struct VirtualAddress(usize); pub struct VirtualAddress(usize);
@ -55,11 +54,11 @@ impl VirtualAddress {
pub fn vpns(&self) -> [usize; 3] { pub fn vpns(&self) -> [usize; 3] {
[ [
// [20:12] // [20:12]
(self.0 >> 12) & 0x1ff, (self.0 >> 12) & 0x1FF,
// [29:21] // [29:21]
(self.0 >> 21) & 0x1ff, (self.0 >> 21) & 0x1FF,
// [38:30] // [38:30]
(self.0 >> 30) & 0x1ff, (self.0 >> 30) & 0x1FF,
] ]
} }
@ -114,7 +113,7 @@ impl VirtualAddress {
Sum, Sum,
UpperHex, UpperHex,
)] )]
#[display(fmt = "0x{:x}", _0)] #[display("0x{:x}", _0)]
#[from(forward)] #[from(forward)]
pub struct PhysicalAddress(usize); pub struct PhysicalAddress(usize);
@ -125,11 +124,11 @@ impl PhysicalAddress {
pub fn ppns(&self) -> [usize; 3] { pub fn ppns(&self) -> [usize; 3] {
[ [
// [20:12] // [20:12]
(self.0 >> 12) & 0x1ff, (self.0 >> 12) & 0x1FF,
// [29:21] // [29:21]
(self.0 >> 21) & 0x1ff, (self.0 >> 21) & 0x1FF,
// [55:30] // [55:30]
(self.0 >> 30) & 0x3ffffff, (self.0 >> 30) & 0x3FFFFFF,
] ]
} }

View file

@ -1,31 +1,20 @@
#![allow(unused)]
use { use {
alloc::{boxed::Box, collections::BTreeMap, sync::Arc, task::Wake}, alloc::{boxed::Box, sync::Arc},
core::{ core::{
future::Future, future::Future,
pin::Pin, pin::Pin,
task::{Context, Poll, Waker}, task::{Context, Poll, RawWaker, RawWakerVTable, Waker},
}, },
crossbeam_queue::SegQueue, crossbeam_queue::SegQueue,
kiam::when,
slab::Slab, slab::Slab,
spin::RwLock,
}; };
static SPAWN_QUEUE: RwLock<Option<SpawnQueue>> = RwLock::new(None);
pub fn spawn(future: impl Future<Output = ()> + Send + 'static) {
match &*SPAWN_QUEUE.read() {
Some(s) => s.push(Task::new(future)),
None => panic!("no task executor is running"),
}
}
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 {
type Output = (); type Output = ();
#[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> {
if self.0 { if self.0 {
Poll::Ready(()) Poll::Ready(())
@ -40,101 +29,150 @@ 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: Slab<Task>, task_queue: Arc<TaskQueue>,
queue: TaskQueue,
to_spawn: SpawnQueue,
wakers: BTreeMap<TaskId, Waker>,
} }
impl Executor { impl<F: Future<Output = ()> + Send> Executor<F> {
pub fn spawn(&mut self, future: impl Future<Output = ()> + Send + 'static) { pub fn new(size: usize) -> Self {
self.queue Self {
.push(TaskId(self.tasks.insert(Task::new(future)))); tasks: Slab::with_capacity(size),
task_queue: Arc::new(TaskQueue::new()),
}
}
#[inline]
pub fn spawn(&mut self, future: F) {
self.task_queue
.queue
.push(self.tasks.insert(Task::new(future)));
} }
pub fn run(&mut self) { pub fn run(&mut self) {
{ let mut task_batch = [0; 32];
let mut global_spawner = SPAWN_QUEUE.write(); let mut batch_len = 0;
if global_spawner.is_some() {
panic!("Task executor is already running");
}
*global_spawner = Some(Arc::clone(&self.to_spawn));
}
loop { loop {
when! { self.task_queue.batch_pop(&mut task_batch, &mut batch_len);
let Some(id) = self
.to_spawn
.pop()
.map(|t| TaskId(self.tasks.insert(t)))
.or_else(|| self.queue.pop())
=> {
let Some(task) = self.tasks.get_mut(id.0) else {
panic!("Attempted to get task from empty slot: {}", id.0);
};
let mut cx = Context::from_waker(self.wakers.entry(id).or_insert_with(|| { if batch_len == 0 {
Waker::from(Arc::new(TaskWaker { if self.task_queue.is_empty() {
id, break;
queue: Arc::clone(&self.queue), } else {
})) continue;
})); }
}
match task.poll(&mut cx) { for &id in &task_batch[..batch_len] {
Poll::Ready(()) => { if let Some(task) = self.tasks.get_mut(id) {
self.tasks.remove(id.0); let waker = task
self.wakers.remove(&id); .waker
} .get_or_insert_with(|| TaskWaker::new(id, Arc::clone(&self.task_queue)));
Poll::Pending => (),
let waker = unsafe { Waker::from_raw(TaskWaker::into_raw_waker(waker)) };
let mut cx = Context::from_waker(&waker);
if let Poll::Ready(()) = task.poll(&mut cx) {
self.tasks.remove(id);
self.task_queue.free_tasks.push(id);
} }
}, }
self.tasks.is_empty() => break,
_ => (),
} }
} }
*SPAWN_QUEUE.write() = None;
} }
} }
struct Task { struct Task<F: Future<Output = ()> + Send> {
future: Pin<Box<dyn Future<Output = ()> + Send>>, future: Pin<Box<F>>,
waker: Option<TaskWaker>,
} }
impl Task { impl<F: Future<Output = ()> + Send> Task<F> {
pub fn new(future: impl Future<Output = ()> + Send + 'static) -> Self { #[inline(always)]
log::trace!("New task scheduled"); pub fn new(future: F) -> Self {
Self { Self {
future: Box::pin(future), future: Box::pin(future),
waker: None,
} }
} }
#[inline(always)]
fn poll(&mut self, cx: &mut Context) -> Poll<()> { fn poll(&mut self, cx: &mut Context) -> Poll<()> {
self.future.as_mut().poll(cx) self.future.as_mut().poll(cx)
} }
} }
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
struct TaskId(usize);
type TaskQueue = Arc<SegQueue<TaskId>>;
type SpawnQueue = Arc<SegQueue<Task>>;
struct TaskWaker { struct TaskWaker {
id: TaskId, id: usize,
queue: TaskQueue, task_queue: Arc<TaskQueue>,
} }
impl Wake for TaskWaker { impl TaskWaker {
fn wake(self: Arc<Self>) { #[inline(always)]
log::trace!("Woke Task-{:?}", self.id); fn new(id: usize, task_queue: Arc<TaskQueue>) -> Self {
self.wake_by_ref(); Self { id, task_queue }
} }
fn wake_by_ref(self: &Arc<Self>) { #[inline(always)]
self.queue.push(self.id); fn wake(&self) {
self.task_queue.queue.push(self.id);
}
fn into_raw_waker(waker: &TaskWaker) -> RawWaker {
let ptr = waker as *const TaskWaker;
RawWaker::new(ptr.cast(), &VTABLE)
}
}
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 {
queue: SegQueue<usize>,
next_task: usize,
free_tasks: SegQueue<usize>,
}
impl TaskQueue {
fn new() -> Self {
Self {
queue: SegQueue::new(),
next_task: 0,
free_tasks: SegQueue::new(),
}
}
#[inline(always)]
fn batch_pop(&self, output: &mut [usize], len: &mut usize) {
*len = 0;
while let Some(id) = self.queue.pop() {
output[*len] = id;
*len += 1;
if *len == output.len() {
break;
}
}
}
#[inline(always)]
fn is_empty(&self) -> bool {
self.queue.is_empty()
} }
} }

View file

@ -4,15 +4,26 @@ version = "0.2.0"
edition = "2021" edition = "2021"
[dependencies] [dependencies]
str-reader = "0.1.2" str-reader = "0.1"
derive_more = "0.99" derive_more = { version = "1", default-features = false, features = [
error-stack = "0.4" "add",
"add_assign",
"constructor",
"display",
"from",
"into",
"mul",
"mul_assign",
"not",
"sum",
] }
error-stack = "0.5"
fatfs = "0.3" fatfs = "0.3"
toml = "0.5.2" toml = "0.8"
# hbasm.git = "https://git.ablecorp.us/AbleOS/holey-bytes.git" # hbasm.git = "https://git.ablecorp.us/AbleOS/holey-bytes.git"
hblang.git = "https://git.ablecorp.us/AbleOS/holey-bytes.git" hblang.git = "https://git.ablecorp.us/AbleOS/holey-bytes.git"
[dependencies.reqwest] [dependencies.reqwest]
version = "0.11" version = "0.12"
default-features = false default-features = false
features = ["rustls-tls", "blocking"] features = ["rustls-tls", "blocking"]

View file

@ -1,3 +1,4 @@
#![allow(unused)]
use std::{ use std::{
fmt::format, fmt::format,
fs::{read_to_string, File}, fs::{read_to_string, File},

View file

@ -1,3 +1,5 @@
// #![allow(unused)]
mod dev; mod dev;
use { use {
@ -6,7 +8,7 @@ use {
error_stack::{bail, report, Context, Report, Result, ResultExt}, error_stack::{bail, report, Context, Report, Result, ResultExt},
fatfs::{FileSystem, FormatVolumeOptions, FsOptions, ReadWriteSeek}, fatfs::{FileSystem, FormatVolumeOptions, FsOptions, ReadWriteSeek},
std::{ std::{
fmt::Display, // fmt::Display,
fs::{self, File}, fs::{self, File},
io::{self, Write}, io::{self, Write},
path::Path, path::Path,
@ -193,7 +195,7 @@ TERM_BACKDROP={}
let modules = value.get_mut("modules").unwrap().as_table_mut().unwrap(); let modules = value.get_mut("modules").unwrap().as_table_mut().unwrap();
// let mut real_modules = modules.clone(); // let mut real_modules = modules.clone();
modules.into_iter().for_each(|(key, value)| { modules.into_iter().for_each(|(_, value)| {
if value.is_table() { if value.is_table() {
let path = get_path_without_boot_prefix( let path = get_path_without_boot_prefix(
value.get("path").expect("You must have `path` as a value"), value.get("path").expect("You must have `path` as a value"),
@ -242,7 +244,7 @@ TERM_BACKDROP={}
let bootdir = fs.root_dir().create_dir("efi")?.create_dir("boot")?; let bootdir = fs.root_dir().create_dir("efi")?.create_dir("boot")?;
let mut f = fs.root_dir().create_file("limine.cfg")?; let mut f = fs.root_dir().create_file("limine.cfg")?;
let a = f.write(limine_str.as_bytes())?; let _ = f.write(limine_str.as_bytes())?;
drop(f); drop(f);
io::copy( io::copy(
@ -368,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", "neoverse-n2",
"-device", "ramfb", "-device", "ramfb",
"-device", "qemu-xhci", "-device", "qemu-xhci",
"-device", "usb-kbd", "-device", "usb-kbd",
@ -427,11 +429,11 @@ fn fetch_ovmf(target: Target) -> Result<String, OvmfFetchError> {
#[derive(Debug, Display)] #[derive(Debug, Display)]
enum OvmfFetchError { enum OvmfFetchError {
#[display(fmt = "Failed to fetch OVMF package")] #[display("Failed to fetch OVMF package")]
Fetch, Fetch,
#[display(fmt = "No OVMF package available")] #[display("No OVMF package available")]
Empty, Empty,
#[display(fmt = "IO Error")] #[display("IO Error")]
Io, Io,
} }
@ -444,26 +446,28 @@ enum Target {
Aarch64, Aarch64,
} }
#[allow(unused)]
#[derive(Debug, Display)] #[derive(Debug, Display)]
enum Error { enum Error {
#[display(fmt = "Failed to build the kernel")] #[display("Failed to build the kernel")]
Build, Build,
#[display(fmt = "Missing or invalid subcommand (available: build, run)")] #[display("Missing or invalid subcommand (available: build, run)")]
InvalidSubCom, InvalidSubCom,
#[display(fmt = "IO Error")] #[display("IO Error")]
Io, Io,
#[display(fmt = "Failed to spawn a process")] #[display("Failed to spawn a process")]
ProcessSpawn, ProcessSpawn,
#[display(fmt = "Failed to fetch UEFI firmware")] #[display("Failed to fetch UEFI firmware")]
OvmfFetch, OvmfFetch,
#[display(fmt = "Failed to assemble Holey Bytes code")] #[display("Failed to assemble Holey Bytes code")]
Assembler, Assembler,
#[display(fmt = "QEMU Error: {}", "fmt_qemu_err(*_0)")] #[display("QEMU Error: {}", "fmt_qemu_err(*_0)")]
Qemu(Option<i32>), Qemu(Option<i32>),
} }
impl Context for Error {} impl Context for Error {}
#[allow(dead_code)]
fn fmt_qemu_err(e: Option<i32>) -> impl Display { fn fmt_qemu_err(e: Option<i32>) -> impl Display {
struct W(Option<i32>); struct W(Option<i32>);
impl Display for W { impl Display for W {

View file

@ -1,3 +1,3 @@
[toolchain] [toolchain]
channel = "nightly-2024-05-17" channel = "nightly-2024-07-27"
components = ["rust-src", "llvm-tools"] components = ["rust-src", "llvm-tools"]

View file

@ -0,0 +1,9 @@
Rendering interface for SVGA and Software renderers
# TODO:
- SVGA Driver
- needs pci driver
- needs init (requiring program)
- Double Buffer mode for Software renderer
- needs init (requiring program)

View file

@ -0,0 +1,47 @@
svga := @use("rel:svga.hb")
software := @use("rel:software.hb")
// default mode
mode := software
init := mode.init
doublebuffer := mode.doublebuffer
// Colours
Color := mode.Color
white := mode.white
black := mode.black
gray := mode.gray
red := mode.red
green := mode.green
yellow := mode.yellow
blue := mode.blue
magenta := mode.magenta
cyan := mode.cyan
light_gray := mode.light_gray
light_red := mode.light_red
light_green := mode.light_green
light_yellow := mode.light_yellow
light_blue := mode.light_blue
light_magenta := mode.light_magenta
light_cyan := mode.light_cyan
// Drawing
put_pixel := mode.put_pixel
put_rect := mode.put_rect
put_filled_rect := mode.put_filled_rect
put_line := mode.put_line
clear := mode.clear
// Display
width := mode.width
height := mode.height
dimensions := mode.dimensions
set_height := mode.set_height
set_width := mode.set_width
set_dimensions := mode.set_dimensions
sync := mode.sync
// Math
UVec2 := struct {x: uint, y: uint}
IVec2 := struct {x: int, y: int}

View file

@ -0,0 +1,263 @@
.{math, memory} := @use("../../stn/src/lib.hb");
.{IVec2} := @use("rel:lib.hb")
Color := struct {b: u8, g: u8, r: u8, a: u8}
white := Color.(255, 255, 255, 255)
black := Color.(0, 0, 0, 255)
gray := Color.(127, 127, 127, 255)
red := Color.(0, 0, 205, 255)
green := Color.(0, 205, 0, 255)
yellow := Color.(0, 205, 205, 255)
blue := Color.(205, 0, 0, 255)
magenta := Color.(205, 0, 205, 255)
cyan := Color.(205, 205, 0, 255)
light_gray := Color.(229, 229, 229, 255)
light_red := Color.(0, 0, 255, 255)
light_green := Color.(0, 255, 0, 255)
light_yellow := Color.(0, 255, 255, 255)
light_blue := Color.(255, 0, 0, 255)
light_magenta := Color.(255, 0, 255, 255)
light_cyan := Color.(255, 255, 0, 255)
// fb_width := 1024
// fb_height := 768
// fb_pixels := fb_width * fb_height
// fb_bytes := fb_pixels << 2
copy_pixels := 0xC000 >> 2
// partitions := fb_pixels / copy_pixels
// total_pages := 1 + fb_bytes >> 12
ctx := @as(Context, idk)
Context := struct {
fb: ^Color,
bb: ^Color,
buf: ^Color,
width: int,
height: int,
partitions: int,
pixels: int,
bb_pages: int,
double_buffer: bool,
}
init := fn(): void {
width := @eca(int, 3, 6, "w\0", 2)
height := @eca(int, 3, 6, "h\0", 2)
// width := 1024
// height := 768
pixels := width * height
bytes := pixels << 2
partitions := pixels / copy_pixels
pages := 1 + bytes >> 12
back_buffer := create_back_buffer(pages)
ctx = Context.{
fb: @eca(^Color, 3, 6, "p\0", 2),
bb: back_buffer,
buf: back_buffer,
width,
height,
partitions,
pixels,
bb_pages: pages,
double_buffer: true,
}
return
}
doublebuffer := fn(enable: bool): void {
if enable {
ctx.buf = ctx.bb
} else {
ctx.buf = ctx.fb
}
ctx.double_buffer = enable
return
}
create_back_buffer := fn(pages: int): ^Color {
if pages <= 0xFF {
return @bitcast(@inline(memory.request_page, pages))
}
ptr := @inline(memory.request_page, 255)
remaining := pages - 0xFF
loop if remaining <= 0 break else {
if remaining < 0xFF {
memory.request_page(remaining)
} else {
memory.request_page(0xFF)
}
remaining -= 0xFF
}
return @bitcast(ptr)
}
clear := fn(color: Color): void {
cursor := ctx.buf
boundary := cursor + 512
loop if cursor == boundary break else {
*cursor = color
cursor += 1
}
boundary += 512 * 7
loop if cursor == boundary break else {
*@as(^[Color; 512], @bitcast(cursor)) = *@as(^[Color; 512], @bitcast(ctx.buf))
cursor += 512
}
boundary += copy_pixels - 4096
loop if cursor == boundary break else {
*@as(^[Color; 4096], @bitcast(cursor)) = *@as(^[Color; 4096], @bitcast(ctx.buf))
cursor += 4096
}
boundary += (ctx.partitions - 1) * copy_pixels
loop if cursor == boundary break else {
*@as(^[Color; copy_pixels], @bitcast(cursor)) = *@as(^[Color; copy_pixels], @bitcast(ctx.buf))
cursor += @sizeof([u8; copy_pixels])
}
return
}
sync := fn(): void {
if ctx.double_buffer {
bb := ctx.buf
fb := ctx.fb
boundary := bb + ctx.pixels
loop if bb == boundary break else {
*@as(^[Color; copy_pixels], @bitcast(fb)) = *@as(^[Color; copy_pixels], @bitcast(bb))
bb += copy_pixels
fb += copy_pixels
}
}
return
}
width := fn(): int {
return ctx.width
}
height := fn(): int {
return ctx.height
}
screenidx := fn(x: int, y: int): int {
return x + ctx.width * y
}
put_pixel := fn(pos: IVec2, color: Color): void {
*(ctx.buf + @inline(screenidx, pos.x, pos.y)) = color
return
}
put_filled_rect := fn(pos: IVec2, tr: IVec2, color: Color): void {
x := pos.x
y := pos.y
end := pos + tr
loop if x == end.x break else {
loop if y == end.y break else {
*(ctx.buf + @inline(screenidx, x, y)) = color
y += 1
}
x += 1
y = pos.y
}
return
}
put_rect := fn(pos: IVec2, tr: IVec2, color: Color): void {
x := pos.x
y := pos.y
end := pos + tr
loop if y == end.y break else {
*(ctx.buf + @inline(screenidx, x, y)) = color;
*(ctx.buf + @inline(screenidx, x + tr.x, y)) = color
y += 1
}
y = pos.y
loop if x == end.x break else {
*(ctx.buf + @inline(screenidx, x, y)) = color;
*(ctx.buf + @inline(screenidx, x, y + tr.y)) = color
x += 1
}
return
}
put_line_low := fn(p0: IVec2, p1: IVec2, color: Color): void {
dx := p1.x - p0.x
dy := p1.y - p0.y
yi := 1
if dy < 0 {
yi = 0 - 1
dy = 0 - dy
}
D := 2 * dy - dx
y := p0.y
x := p0.x
loop if x == p1.x break else {
*(ctx.buf + @inline(screenidx, x, y)) = color
if D > 0 {
y += yi
D += 2 * (dy - dx)
} else {
D += 2 * dy
}
x += 1
}
return
}
put_line_high := fn(p0: IVec2, p1: IVec2, color: Color): void {
dx := p1.x - p0.x
dy := p1.y - p0.y
xi := 1
if dy < 0 {
xi = 0 - 1
dx = 0 - dx
}
D := 2 * dx - dy
x := p0.x
y := p0.y
loop if y == p1.y break else {
*(ctx.buf + @inline(screenidx, x, y)) = color
if D > 0 {
x += xi
D += 2 * (dx - dy)
} else {
D += 2 * dx
}
y += 1
}
return
}
put_line := fn(p0: IVec2, p1: IVec2, color: Color): void {
if @inline(math.abs, p1.y - p0.y) < @inline(math.abs, p1.x - p0.x) {
if p0.x > p1.x {
@inline(put_line_low, p1, p0, color)
} else {
@inline(put_line_low, p0, p1, color)
}
} else {
if p0.y > p1.y {
@inline(put_line_high, p1, p0, color)
} else {
@inline(put_line_high, p0, p1, color)
}
}
return
}
set_height := fn(new: int): void {
return
}
set_width := fn(new: int): void {
return
}
dimensions := fn(): IVec2 {
return .(ctx.width, ctx.height)
}
set_dimensions := fn(new: IVec2): void {
return
}

View file

@ -0,0 +1,91 @@
.{pci, memory, string, log} := @use("../../stn/src/lib.hb");
.{IVec2} := @use("rel:lib.hb")
Color := struct {b: u8, g: u8, r: u8, a: u8}
white := Color.(255, 255, 255, 255)
black := Color.(0, 0, 0, 255)
gray := Color.(127, 127, 127, 255)
red := Color.(0, 0, 205, 255)
green := Color.(0, 205, 0, 255)
yellow := Color.(0, 205, 205, 255)
blue := Color.(205, 0, 0, 255)
magenta := Color.(205, 0, 205, 255)
cyan := Color.(205, 205, 0, 255)
light_gray := Color.(229, 229, 229, 255)
light_red := Color.(0, 0, 255, 255)
light_green := Color.(0, 255, 0, 255)
light_yellow := Color.(0, 255, 255, 255)
light_blue := Color.(255, 0, 0, 255)
light_magenta := Color.(255, 0, 255, 255)
light_cyan := Color.(255, 255, 0, 255)
clear := fn(color: Color): void {
return
}
width := fn(): int {
return 0
}
height := fn(): int {
return 0
}
dimensions := fn(): IVec2 {
return .(0, 0)
}
put_pixel := fn(position: IVec2, color: Color): void {
return
}
put_filled_rect := fn(pos: IVec2, tr: IVec2, color: Color): void {
return
}
put_rect := fn(pos: IVec2, tr: IVec2, color: Color): void {
return
}
put_line_low := fn(p0: IVec2, p1: IVec2, color: Color): void {
return
}
// do not use, use line() instead
put_line_high := fn(p0: IVec2, p1: IVec2, color: Color): void {
return
}
put_line := fn(p0: IVec2, p1: IVec2, color: Color): void {
return
}
set_height := fn(new: int): void {
return
}
set_width := fn(new: int): void {
return
}
set_dimensions := fn(new: IVec2): void {
return
}
sync := fn(): void {
return
}
init := fn(): void {
b := memory.request_page(1)
bus := 0
device := 0
loop if bus == 256 break else {
loop if device == 32 break else {
a := pci.config_read(0, 0, 0, 0)
log.info(string.display_int(a, b))
device += 1
}
bus += 1
}
return
}

View file

@ -4,3 +4,4 @@ memory := @use("rel:memory.hb")
buffer := @use("rel:buffer.hb") buffer := @use("rel:buffer.hb")
math := @use("rel:math.hb") math := @use("rel:math.hb")
random := @use("rel:random.hb") random := @use("rel:random.hb")
pci := @use("rel:pci.hb")

View file

@ -1,14 +1,15 @@
SIZEOF_INT := 31 shift := 31
// following only work for: int
abs := fn(x: int): int { abs := fn(x: int): int {
mask := x >> SIZEOF_INT mask := x >> shift
return (x ^ mask) - mask return (x ^ mask) - mask
} }
min := fn(a: int, b: int): int { min := fn(a: int, b: int): int {
c := a - b c := a - b
return b + (c & c >> SIZEOF_INT) return b + (c & c >> shift)
} }
max := fn(a: int, b: int): int { max := fn(a: int, b: uint): int {
c := a - b c := a - b
return a - (c & c >> SIZEOF_INT) return a - (c & c >> shift)
} }

View file

@ -19,26 +19,26 @@ release_page := fn(ptr: ^u8, page_count: u8): void {
outb := fn(addr: u16, value: u8): void { outb := fn(addr: u16, value: u8): void {
msg := "\0\0\0\0\0"; msg := "\0\0\0\0\0";
*msg = 1; *@as(^u8, msg) = @as(u8, 1);
*(msg + 1) = 0; *@as(^u8, msg + 1) = @as(u8, 0);
*@as(^u16, @bitcast(msg + 2)) = addr; *@as(^u16, @bitcast(msg + 2)) = addr;
*(msg + 4) = value *@as(^u8, msg + 4) = value
@eca(void, 3, 3, msg, 5) @eca(void, 3, 3, msg, 5)
return return
} }
inb := fn(addr: u16): u8 { inb := fn(addr: u16): u8 {
msg := "\0\0\0\0"; msg := "\0\0\0\0";
*msg = 0; *@as(^u8, msg) = @as(u8, 0);
*(msg + 1) = 0; *@as(^u8, msg + 1) = @as(u8, 0);
*@as(^u16, @bitcast(msg + 2)) = addr *@as(^u16, @bitcast(msg + 2)) = addr
return @eca(u8, 3, 3, msg, 4) return @eca(u8, 3, 3, msg, 4)
} }
outl := fn(addr: u16, value: u32): void { outl := fn(addr: u16, value: u32): void {
msg := "\0\0\0\0\0\0\0\0"; msg := "\0\0\0\0\0\0\0\0";
*msg = 1; *@as(^u8, msg) = @as(u8, 1);
*(msg + 1) = 2; *@as(^u8, msg + 1) = @as(u8, 2);
*@as(^u16, @bitcast(msg + 2)) = addr; *@as(^u16, @bitcast(msg + 2)) = addr;
*@as(^u32, @bitcast(msg + 4)) = value *@as(^u32, @bitcast(msg + 4)) = value
@eca(void, 3, 3, msg, 8) @eca(void, 3, 3, msg, 8)
@ -47,8 +47,8 @@ outl := fn(addr: u16, value: u32): void {
inl := fn(addr: u16): u32 { inl := fn(addr: u16): u32 {
msg := "\0\0\0\0"; msg := "\0\0\0\0";
*msg = 0; *@as(^u8, msg) = @as(u8, 0);
*(msg + 1) = 2; *@as(^u8, msg + 1) = @as(u8, 2);
*@as(^u16, @bitcast(msg + 2)) = addr *@as(^u16, @bitcast(msg + 2)) = addr
return @eca(u32, 3, 3, msg, 4) return @eca(u32, 3, 3, msg, 4)
} }

View file

@ -0,0 +1,50 @@
.{inl, outl} := @use("rel:memory.hb")
config_read := fn(bus: u8, device: u8, func: u8, offset: u8): u32 {
lbus := @as(u32, bus)
ldevice := @as(u32, device)
lfunc := @as(u32, func)
loffset := @as(u32, offset)
address := lbus << 16 | ldevice << 11 | lfunc << 8 | loffset & 0xFC | @as(u32, 0x80000000)
outl(0xCF8, address)
return inl(0xCFC)
}
config_write := fn(bus: u8, device: u8, func: u8, offset: u8, value: u32): void {
lbus := @as(u32, bus)
ldevice := @as(u32, device)
lfunc := @as(u32, func)
loffset := @as(u32, offset)
address := lbus << 16 | ldevice << 11 | lfunc << 8 | loffset & 0xFC | @as(u32, 0x80000000)
outl(0xCF8, address)
outl(0xCFC, value)
}
get_header_type := fn(bus: u8, device: u8, func: u8): u8 {
return @as(u8, config_read(bus, device, func, 0xC) >> 16 & 0xFF)
}
Ids := struct {vendor: u16, device: u16}
get_ids := fn(bus: u8, device: u8, func: u8): Ids {
res := config_read(bus, device, func, 0)
return .(@as(u16, res >> 16 & 0xFFFF), @as(u16, res & 0xFFFF))
}
PciDeviceInfo := struct {header_type: u8, device: u8, bus: u8, device_id: Ids, full_class: u16, rev_id: u8}
check_device := fn(bus: u8, device: u8): PciDeviceInfo {
ids := get_ids(bus, device, 0)
if ids.vendor == 0xFFFF {
return .(0, 0, 0, .(0, 0), 0, 0)
}
reg2 := config_read(bus, device, 0, 0x8)
class := @as(u16, reg2 >> 16 & 0xFFFF)
header_type := get_header_type(bus, device, 0)
return .(header_type, device, bus, ids, class, @as(u8, reg2 & 0xFF))
}

View file

@ -1,8 +1,7 @@
integer := fn(min: int, max: int): int { integer := fn(): int {
rng := @eca(int, 3, 4) return @eca(int, 3, 4)
}
if min != 0 | max != 0 {
return rng % (max - min + 1) + min integer_range := fn(min: int, max: int): int {
} return @eca(int, 3, 4) % (max - min + 1) + min
return rng
} }

View file

@ -2,7 +2,7 @@
main := fn(): int { main := fn(): int {
// shuts down ableOS // shuts down ableOS
//memory.outb(0xF400, 0) // memory.outb(0xF400, 0)
a := memory.inb(0x4600) a := memory.inb(0x4600)
b := memory.inb(0x4700) b := memory.inb(0x4700)

View file

@ -1,2 +0,0 @@
# Framebuffer Driver
A simple framebuffer driver.

View file

@ -1,7 +0,0 @@
color.blend
lib.composite
lib.screen2rect
lib.rect2screen
draw.tri_line

View file

@ -1,27 +0,0 @@
ColorBGRA := struct {b: u8, g: u8, r: u8, a: u8}
/* ALL the colo(u)rs you will ever need.
they dont work though, cause hblang bug (reg id leaked, again) */
WHITE := ColorBGRA.{b: 255, g: 255, r: 255, a: 255}
BLACK := ColorBGRA.{b: 0, g: 0, r: 0, a: 255}
GRAY := ColorBGRA.{b: 127, g: 127, r: 127, a: 255}
RED := ColorBGRA.{b: 0, g: 0, r: 205, a: 255}
GREEN := ColorBGRA.{b: 0, g: 205, r: 0, a: 255}
YELLOW := ColorBGRA.{b: 0, g: 205, r: 205, a: 255}
BLUE := ColorBGRA.{b: 205, g: 0, r: 0, a: 255}
MAGENTA := ColorBGRA.{b: 205, g: 0, r: 205, a: 255}
CYAN := ColorBGRA.{b: 205, g: 205, r: 0, a: 255}
LIGHTGRAY := ColorBGRA.{b: 229, g: 229, r: 229, a: 255}
LIGHTRED := ColorBGRA.{b: 0, g: 0, r: 255, a: 255}
LIGHTGREEN := ColorBGRA.{b: 0, g: 255, r: 0, a: 255}
LIGHTYELLOW := ColorBGRA.{b: 0, g: 255, r: 255, a: 255}
LIGHTBLUE := ColorBGRA.{b: 255, g: 0, r: 0, a: 255}
LIGHTMAGENTA := ColorBGRA.{b: 255, g: 0, r: 255, a: 255}
LIGHTCYAN := ColorBGRA.{b: 255, g: 255, r: 0, a: 255}
// i have no clue if this works. please don't me ask how it works. -koniifer
blend := fn(fg: ColorBGRA, bg: ColorBGRA): ColorBGRA {
s := fg + bg
m := s - ((fg ^ bg) & 0x1010100) & 0x1010100
return (m >> 8 | 0x1000000 * (s < fg)) * 0xFF | s - m
}

View file

@ -1,113 +0,0 @@
.{draw_pixel, screenidx, Transform, Point, Rect, Buffer, FB_WIDTH} := @use("rel:lib.hb");
.{math} := @use("../../../libraries/stn/src/lib.hb");
.{ColorBGRA} := @use("rel:color.hb")
/* draws a filled rectangle to the screen
will be optimised later */
rect_fill := fn(buffer: Buffer, pos: Point, tr: Transform, color: ColorBGRA): void {
n := 0
loop if n == tr.height * tr.width break else {
*(buffer.write + @inline(screenidx, .(n % tr.width + pos.x, n / tr.width + pos.y))) = color
n += 1
}
return
}
/* draws a wireframe rectangle to the screen
will also be optimised later */
rect_line := fn(buffer: Buffer, pos: Point, tr: Transform, color: ColorBGRA, thickness: int): void {
t := 0
y := 0
x := 0
loop if t == thickness break else {
y = pos.y
x = pos.x
loop if y == pos.y + tr.height break else {
*(buffer.write + @inline(screenidx, .(pos.x + t, y))) = color;
*(buffer.write + @inline(screenidx, .(pos.x + tr.width - t, y))) = color
y += 1
}
loop if x == pos.x + tr.width break else {
*(buffer.write + @inline(screenidx, .(x, pos.y + t))) = color;
*(buffer.write + @inline(screenidx, .(x, pos.y + tr.height - t))) = color
x += 1
}
t += 1
}
return
}
// do not use, use line() instead
line_low := fn(buffer: Buffer, p0: Point, p1: Point, color: ColorBGRA): void {
dx := p1.x - p0.x
dy := p1.y - p0.y
yi := 1
if dy < 0 {
yi = 0 - 1
dy = 0 - dy
}
D := 2 * dy - dx
y := p0.y
x := p0.x
loop if x == p1.x break else {
*(buffer.write + @inline(screenidx, .(x, y))) = color
if D > 0 {
y += yi
D += 2 * (dy - dx)
} else {
D += 2 * dy
}
x += 1
}
return
}
// do not use, use line() instead
line_high := fn(buffer: Buffer, p0: Point, p1: Point, color: ColorBGRA): void {
dx := p1.x - p0.x
dy := p1.y - p0.y
xi := 1
if dy < 0 {
xi = 0 - 1
dx = 0 - dx
}
D := 2 * dx - dy
x := p0.x
y := p0.y
loop if y == p1.y break else {
*(buffer.write + @inline(screenidx, .(x, y))) = color
if D > 0 {
x += xi
D += 2 * (dx - dy)
} else {
D += 2 * dx
}
y += 1
}
return
}
/* implementation of Bresenham's line algorithm
TODO: thickness, might need better math library */
line := fn(buffer: Buffer, p0: Point, p1: Point, color: ColorBGRA, thickness: int): void {
if @inline(math.abs, p1.y - p0.y) < @inline(math.abs, p1.x - p0.x) {
if p0.x > p1.x {
@inline(line_low, buffer, p1, p0, color)
} else {
@inline(line_low, buffer, p0, p1, color)
}
} else {
if p0.y > p1.y {
@inline(line_high, buffer, p1, p0, color)
} else {
@inline(line_high, buffer, p0, p1, color)
}
}
return
}
// theoretically draws a wireframe polygon to the screen. untested.
tri_line := fn(buffer: Buffer, p0: Point, p1: Point, p2: Point, color: ColorBGRA, thickness: int): void {
line(buffer, p0, p1, color, thickness)
line(buffer, p1, p2, color, thickness)
line(buffer, p2, p0, color, thickness)
return
}

View file

@ -1,26 +0,0 @@
.{rect_line} := @use("../draw.hb");
.{present, create_buffer, clear} := @use("../lib.hb")
/* expected result:
the impostor travels left and loops around the screen */
example := fn(): void {
// Creates a back buffer, which we write to, to avoid screen flickering
buffer := create_buffer()
x := 0
loop {
// draw all our shapes to the back buffer
rect_line(buffer, .(200 - x, 80), .(430, 380), .(0, 0, 255, 0), 1)
rect_line(buffer, .(630 - x, 120), .(120, 300), .(0, 0, 255, 0), 1)
rect_line(buffer, .(200 - x, 460), .(160, 270), .(0, 0, 255, 0), 1)
rect_line(buffer, .(470 - x, 460), .(160, 270), .(0, 0, 255, 0), 1)
rect_line(buffer, .(140 - x, 140), .(340, 250), .(255, 255, 0, 0), 1)
/* push the back buffer to the front buffer
this displays our image to the screen */
present(buffer)
// erase our old image
clear(buffer, .(0, 0, 0, 0))
x += 1
}
return
}

View file

@ -1,19 +0,0 @@
.{front_buffer_ptr, front_buffer_copy, get_front_buffer, Buffer} := @use("../lib.hb");
example := fn(): void {
// you can get the raw frontbuffer pointer using
raw_buffer := front_buffer_ptr
// this buffer is the one that you write individual pixels to
// you can gete the copy frontbuffer pointer using
copy_buffer := front_buffer_copy
/* this buffer is used for massive writing
operations by taking advantage of
static copying */
// you can construct a buffer like so
buffer := Buffer.{write: raw_buffer, copy: copy_buffer}
// this is the operation that get_front_buffer does
same_buffer := get_front_buffer()
return
}

View file

@ -1,27 +0,0 @@
.{clear, create_buffer, present} := @use("../lib.hb");
.{ColorBGRA} := @use("../color.hb")
/* expected result:
the screen fades from green to cyan
then wraps back to green
note that this may happen too fast for you to notice... */
example := fn(): void {
// creates a back buffer, which we write to, to avoid screen flickering
buffer := create_buffer()
color := ColorBGRA.(0, 255, 0, 255)
/* have to explicitly say 0 is a u8, or we do something crazy to the colors.
looks like a compiler bug */
n := @as(u8, 0) - 1
loop {
clear(buffer, color)
present(buffer)
/* because for some reason just comparing doesnt work.
also looks like a compiler bug */
if (color.b & 255) == 255 | (color.b & 255) == 0 {
n = 0 - n
}
color.b += n
}
return
}

View file

@ -1,25 +0,0 @@
.{line} := @use("../draw.hb");
.{clear, create_buffer, present, FB_WIDTH, FB_HEIGHT, Point} := @use("../lib.hb")
/* expected result:
a 3d-looking blue set of lines
created on a blue background */
example := fn(): void {
// creates a back buffer, which we write to, to avoid screen flickering
buffer := create_buffer()
// fill the screen in blue
clear(buffer, .(100, 50, 0, 255))
p0 := Point.(0, 0 - 1)
p1 := Point.(0, FB_HEIGHT - 1)
loop if p0.y >= FB_HEIGHT break else {
// draw a line between p0 and p1
line(buffer, p0, p1, .(255, 180, 100, 255), 3)
p0.y += FB_HEIGHT >> 6
p1.x += FB_WIDTH >> 6
}
/* push the back buffer to the front buffer
this displays our image to the screen */
present(buffer)
return
}

View file

@ -1,17 +0,0 @@
.{clear, get_front_buffer, screenidx} := @use("../lib.hb");
.{ColorBGRA} := @use("../color.hb");
.{random} := @use("../../../../libraries/stn/src/lib.hb")
example := fn(): void {
buffer := get_front_buffer()
clear(buffer)
loop {
x := random.integer(0, 1024)
y := random.integer(0, 768)
r := random.integer(0, 255)
g := random.integer(0, 75)
b := random.integer(0, 155);
*(buffer.write + @inline(screenidx, .(x, y))) = ColorBGRA.(b, g, r, 255)
}
return
}

View file

@ -1,32 +0,0 @@
.{rect_line} := @use("../draw.hb");
.{clear, create_buffer, present, Point, FB_HEIGHT, FB_WIDTH} := @use("../lib.hb")
/* expected result:
the white outline of a square bounces around the screen */
example := fn(): void {
// creates a back buffer, which we write to, to avoid screen flickering
buffer := create_buffer()
vel := Point.{x: 1, y: 1}
pos := Point.{x: 100, y: 100}
loop {
// draw the square at our current position
rect_line(buffer, pos, .(100, 100), .(255, 255, 255, 255), 3)
/* push the back buffer to the front buffer
this displays our image to the screen */
present(buffer)
// erase our old image
clear(buffer, .(0, 0, 0, 0))
// bounce the square if it touches the screen edges
if pos.x == 0 | pos.x == FB_WIDTH - 100 {
vel.x = 0 - vel.x
}
if pos.y == 0 | pos.y == FB_HEIGHT - 100 {
vel.y = 0 - vel.y
}
pos += vel
}
return
}

View file

@ -1,20 +0,0 @@
.{clear, create_buffer, present} := @use("../lib.hb")
/* expected result: (EPILEPSY WARNING)
the screen rapidly flashes red then black */
example := fn(): void {
// creates a back buffer, which we write to, to avoid screen flickering
buffer := create_buffer()
loop {
// screen go red
clear(buffer, .(0, 0, 255, 0))
// show the red
present(buffer)
// screen go black
clear(buffer, .(0, 255, 255, 0))
// show the black
present(buffer)
}
return
}

View file

@ -1,88 +0,0 @@
.{memory, math} := @use("../../../libraries/stn/src/lib.hb");
.{ColorBGRA, blend} := @use("rel:color.hb")
FB_WIDTH := 1024
FB_HEIGHT := 768
FB_PIXELS := FB_WIDTH * FB_HEIGHT
FB_BYTES := FB_PIXELS << 2
// actual enforced max copy size is 0xFFFF, but this was faster
MAX_COPY_SIZE := 0x1800
COPY_PIXELS := math.min(MAX_COPY_SIZE, FB_BYTES) >> 2
PARTITIONS := FB_PIXELS / COPY_PIXELS
TOTAL_PAGES := 1 + FB_BYTES >> 12
Buffer := struct {write: ^ColorBGRA, copy: ^[ColorBGRA; COPY_PIXELS]}
Point := struct {x: int, y: int}
Transform := struct {width: int, height: int}
front_buffer_ptr := @as(^ColorBGRA, @bitcast(0xFFFF8000C0000000))
front_buffer_copy := @as(^[ColorBGRA; COPY_PIXELS], @bitcast(front_buffer_ptr))
get_front_buffer := fn(): Buffer {
// trying to return front_buffer_ptr or front_buffer_copy causes reg id leak
buffer := Buffer.{write: front_buffer_ptr, copy: front_buffer_copy}
return buffer
}
/* this is separate to create_raw_buffer because returning a Buffer from
create_raw_buffer causes reg id leak */
create_buffer := fn(): Buffer {
ptr := @inline(create_raw_buffer)
buffer := Buffer.{write: ptr, copy: @as(^[ColorBGRA; COPY_PIXELS], @bitcast(ptr))}
return buffer
}
create_raw_buffer := fn(): ^ColorBGRA {
if TOTAL_PAGES <= 0xFF {
return @bitcast(@inline(memory.request_page, TOTAL_PAGES))
}
ptr := @inline(memory.request_page, 255)
remaining := TOTAL_PAGES - 0xFF
loop if remaining <= 0 break else {
if remaining < 0xFF {
memory.request_page(remaining)
} else {
memory.request_page(0xFF)
}
remaining -= 0xFF
}
return @bitcast(ptr)
}
// sets the buffer to the color. very fast.
clear := fn(buffer: Buffer, color: ColorBGRA): void {
n := 0
// write the first pixel chunk
loop if n >= COPY_PIXELS break else {
*(buffer.write + n) = color
n += 1
}
n = 1
// copy that pixel chunk through the buffer, taking advantage of memory copying
loop if n >= PARTITIONS break else {
*(buffer.copy + n) = *buffer.copy
n += 1
}
return
}
// only required to be called when using a back buffer. if using single-buffered rendering, do not call this.
present := fn(buffer: Buffer): void {
n := 0
// copy chunks of the read buffer to the front buffer
loop if n >= PARTITIONS break else {
*(front_buffer_copy + n) = *(buffer.copy + n)
n += 1
}
return
}
// composites the contents of buffer1 into buffer2, accounting for alpha transparency
// i dont know if it works. i have not tested it. it probably doesnt work
composite := fn(buffer1: Buffer, buffer2: Buffer): void {
n := 0
loop if n == FB_PIXELS break else {
bg := *(buffer2.write + n);
*(buffer2.write + n) = blend(*(buffer1.write + n), bg)
n += 1
}
return
}
screenidx := fn(pos: Point): int {
return pos.x + FB_WIDTH * pos.y
}

View file

@ -1,6 +0,0 @@
.{example} := @use("./examples/lines.hb")
main := fn(): int {
@inline(example)
return 0
}

View file

@ -1,6 +1,6 @@
[package] [package]
name = "fb_driver" name = "render_example"
authors = ["able", "aurlex"] authors = ["koniifer"]
[dependants.libraries] [dependants.libraries]

View file

@ -0,0 +1,20 @@
render := @use("../../../../libraries/render/src/lib.hb")
/* expected result:
the impostor travels left and loops around the screen */
example := fn(): void {
render.init()
x := 0
loop {
render.put_rect(.(200 - x, 80), .(430, 380), render.red)
render.put_rect(.(630 - x, 120), .(120, 300), render.red)
render.put_rect(.(200 - x, 460), .(160, 270), render.red)
render.put_rect(.(470 - x, 460), .(160, 270), render.red)
render.put_rect(.(140 - x, 140), .(340, 250), render.cyan)
render.sync()
render.clear(render.black)
x += 1
}
return
}

View file

@ -0,0 +1,21 @@
render := @use("../../../../libraries/render/src/lib.hb")
/* expected result:
the screen fades from cyan to green
then wraps back to cyan
note that this may happen too fast for you to notice... */
example := fn(): void {
render.init()
color := render.light_cyan
n := @as(u8, 1)
loop {
render.clear(color)
render.sync()
if (color.b & 255) == 255 | (color.b & 255) == 0 {
n = 0 - n
}
color.b += n
}
return
}

View file

@ -0,0 +1,22 @@
render := @use("../../../../libraries/render/src/lib.hb")
/* expected result:
a 3d-looking set of blue lines
created on a blue background */
example := fn(): void {
render.init()
render.clear(.(100, 50, 0, 255))
width := render.width()
height := render.height()
p0 := render.IVec2.(0, 0)
p1 := render.IVec2.(0, height)
loop if p0.y >= height break else {
render.put_line(p0, p1, .(255, 180, 100, 255))
render.put_line(.(width, height) - p0, .(width, height) - p1, .(255, 180, 100, 255))
p0.y += height >> 6
p1.x += width >> 6
}
render.sync()
return
}

View file

@ -0,0 +1,17 @@
.{random} := @use("../../../../libraries/stn/src/lib.hb")
render := @use("../../../../libraries/render/src/lib.hb")
example := fn(): void {
render.init()
render.doublebuffer(false)
render.clear(render.black)
loop {
x := random.integer_range(0, 1024)
y := random.integer_range(0, 768)
r := random.integer_range(0, 255)
g := random.integer_range(0, 75)
b := random.integer_range(0, 155)
render.put_pixel(.(x, y), .(b, g, r, 255))
}
return
}

View file

@ -0,0 +1,27 @@
render := @use("../../../../libraries/render/src/lib.hb")
/* expected result:
the white outline of a square bounces around the screen */
example := fn(): void {
render.init()
vel := render.IVec2.(1, 1)
pos := render.IVec2.(100, 100)
width := render.width()
height := render.height()
loop {
render.put_rect(pos, .(100, 100), render.white)
render.sync()
render.clear(render.black)
if pos.x == 0 | pos.x == width - 100 {
vel.x = 0 - vel.x
}
if pos.y == 0 | pos.y == height - 100 {
vel.y = 0 - vel.y
}
pos += vel
}
return
}

View file

@ -0,0 +1,15 @@
render := @use("../../../../libraries/render/src/lib.hb")
/* expected result: (EPILEPSY WARNING)
the screen rapidly flashes red then black */
example := fn(): void {
render.init()
loop {
render.clear(render.red)
render.sync()
render.clear(render.yellow)
render.sync()
}
return
}

View file

@ -0,0 +1,8 @@
render := @use("../../../../libraries/render/src/lib.hb")
render.mode = render.svga
example := fn(): void {
render.init()
return
}

View file

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

View file

@ -1,5 +1,5 @@
[package] [package]
name = "a_serial_driver" name = "serial_driver"
authors = ["Able"] authors = ["Able"]
[dependants.libraries] [dependants.libraries]

View file

@ -1,5 +1,4 @@
stn := @use("../../../libraries/stn/src/lib.hb"); .{memory, buffer} := @use("../../../libraries/stn/src/lib.hb")
.{log, string, memory, buffer} := stn
serial_print := fn(ptr: ^u8): void { serial_print := fn(ptr: ^u8): void {
letter := 0 letter := 0

View file

@ -1,4 +1,4 @@
.{string, memory, buffer} := @use("../../../libraries/stn/src/lib.hb") .{string, buffer} := @use("../../../libraries/stn/src/lib.hb")
log_info := fn(): void { log_info := fn(): void {
a := buffer.search("XNumber\0") a := buffer.search("XNumber\0")

View file

@ -17,17 +17,17 @@ resolution = "1024x768x24"
[boot.limine.ableos.modules] [boot.limine.ableos.modules]
# [boot.limine.ableos.modules.tests] [boot.limine.ableos.modules.tests]
# path = "boot:///tests.hbf" path = "boot:///tests.hbf"
[boot.limine.ableos.modules.a_serial_driver] [boot.limine.ableos.modules.0serial_driver]
path = "boot:///a_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.fb_driver] [boot.limine.ableos.modules.render_example]
path = "boot:///fb_driver.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"