Compare commits

...

30 commits

Author SHA1 Message Date
koniifer 41b339dfd0 omfg it's fixed 🙏 2024-09-16 21:56:52 +01:00
koniifer a8d38e04c4 let's just use strings for now 2024-09-16 20:45:19 +01:00
koniifer 1f4fce0f66 please bugs begone 2024-09-16 20:15:51 +01:00
koniifer b021fc5b86 bug squashing & testing 2024-09-15 17:01:29 +01:00
able 5f2b181f22 Merge pull request 'good luck able' (#17) from koniifer/ableos-framebuffer:master into master
Reviewed-on: https://git.ablecorp.us/AbleOS/ableos/pulls/17
2024-09-14 16:44:05 +00:00
koniifer 43ea77c18f merge mainline branch and do some housekeeping 2024-09-14 11:26:32 +01:00
Able 2b2e0c514b multiline 2024-09-14 04:28:45 -05:00
Able fcca015866 minor changes 2024-09-14 04:05:40 -05:00
Able cc9337348e PCI+SVGA skeleton 2024-09-14 03:51:57 -05:00
Able 028949559b ignim checkpoint 2024-09-14 00:31:35 -05:00
Able 91380539d9 Ignim work 2024-09-13 23:11:50 -05:00
Able ec25c0f207 update on the logger
Further changes pending on the IDL
2024-09-13 20:50:12 -05:00
Able 1b5cb54a2b ignim work 2024-09-13 20:17:47 -05:00
Able 9686349476 add support for the device tree 2024-09-13 18:11:23 -05:00
koniifer f8c7873978 squash 2024-09-13 22:41:31 +01:00
Able 40cc412ab3 Horizon API work 2024-09-13 16:40:05 -05:00
Able cd369b39d5 more changes to make konii so anger 2024-09-12 15:34:28 -05:00
mlokr 331cbf5da1
fixing arm compilation errors 2024-09-10 21:52:57 +02:00
koniifer 63e2f546c5 Merge pull request 'adding disasembly in case something goes wrong' (#1) from mlokis/ableos-framebuffer:disasm into master
Reviewed-on: https://git.ablecorp.us/koniifer/ableos-framebuffer/pulls/1
2024-09-04 17:32:19 +00:00
mlokr 1a2b60b53b
foo 2024-09-04 19:14:30 +02:00
koniifer a7517005de update to latest hblang 2024-09-04 16:08:01 +01:00
Able 0594b99a59 cleanup 2024-09-03 03:34:29 -05:00
Able 1855307cd9 IDL tokenization 2024-09-02 21:50:43 -05:00
koniifer e3f7a2d455 inline fb_driver, update to latest hblang 2024-09-02 04:36:03 +01:00
koniifer 19992595fc update hblang to latest git
remove old ps/2 driver
remove defunct time driver
clean up stuff
i promise im done fiddling with ecah.rs and memory.hb
2024-09-02 01:04:00 +01:00
koniifer f7b970eaf0 hexadecimal support!!
remove fb_driver_stresstest, move examples back to fb_driver, update hblang, update Cargo.lock
2024-09-01 22:29:42 +01:00
koniifer c752028c73 fix ecah.rs, implement -d, --debuginfo to print debug info in serial (requires recompilation) 2024-08-31 19:34:14 +01:00
koniifer 8577920d90 port ecah changes from svga_driver branch 2024-08-31 15:38:15 +01:00
Able 7426bf479f idl work 2024-08-30 12:31:45 -05:00
koniifer 12ee3a9b87 fix random
implement hardware_random_u32
implement math.max, alter math.min
remove unneeded dependencies from fb_driver
2024-08-30 16:22:13 +01:00
126 changed files with 2636 additions and 1716 deletions

1121
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

@ -1,20 +1,84 @@
use logos::Logos; pub mod protocol;
#[derive(Logos, Debug, PartialEq)] use std::io::Read;
use {
logos::{Lexer, Logos},
protocol::Protocol,
};
#[derive(Logos, Debug, PartialEq, Clone)]
#[logos(skip r"[ \t\n\f]+")] // Ignore this regex pattern between tokens #[logos(skip r"[ \t\n\f]+")] // Ignore this regex pattern between tokens
enum Token { enum Token {
// Tokens can be literal strings, of any length. // Tokens can be literal strings, of any length.
#[token("protocol")] #[token("protocol")]
Protocol, Protocol,
#[token(".")] #[token("{")]
Period, LBrace,
// Or regular expressions. #[token("}")]
#[regex("[a-zA-Z]+")] RBrace,
Text,
#[token("(")]
LParen,
#[token(")")]
RParen,
#[token(":")]
Colon,
#[token(";")]
SemiColon,
#[token(",")]
Comma,
#[token("=")]
Equal,
#[token("->")]
RArrow,
#[regex("[a-zA-Z_]+", |lex|{lex.slice().to_string()})]
Text(String),
#[regex("[1234567890]+", |lex|{lex.slice().parse::<u64>().unwrap()})]
Number(u64),
#[regex(r"@[a-zA-Z_]+", |lex|{lex.slice().to_string()})]
Decorator(String),
#[regex(r#"@[a-zA-Z_]+\([a-zA-Z,0-9=]+\)"#, |lex|{lex.slice().to_string()})]
DecoratorOption(String),
} }
pub fn main() { pub fn build_idl(name: String) {
let mut lex = Token::lexer("Create ridiculously fast Lexers."); let contents = open_protocol(name);
let lex = Token::lexer(&contents);
let mut tokens = vec![];
for x in lex {
match x {
Ok(token) => {
println!("{:?}", token);
tokens.push(token);
}
Err(err) => println!("{:?}", err),
}
}
build(tokens);
}
fn build(a: Vec<Token>) {
for toke in a {
println!("{:?}", toke);
}
}
fn open_protocol(name: String) -> String {
let path = format!("sysdata/idl/{}/src/protocol.aidl", name);
let mut file = std::fs::File::open(path).unwrap();
let mut contents = String::new();
file.read_to_string(&mut contents).unwrap();
contents
} }

17
dev/src/idl/protocol.rs Normal file
View file

@ -0,0 +1,17 @@
pub enum ProtocolTypes {
Byte,
}
pub struct Protocol {}
impl Protocol {
pub fn is_empty(&self) -> bool {
true
}
pub fn validate_data(&self, data: Vec<u8>) -> bool {
if !data.is_empty() && self.is_empty() {
return false;
}
true
}
}

View file

@ -1,4 +1,6 @@
use std::io::Write; use std::io::Write;
use idl::build_idl;
pub mod idl; pub mod idl;
pub enum Options { pub enum Options {
@ -7,7 +9,7 @@ pub enum Options {
New, New,
Run, Run,
} }
#[derive(PartialEq)] #[derive(PartialEq, Debug)]
pub enum DevelopmentType { pub enum DevelopmentType {
Program, Program,
Library, Library,
@ -24,7 +26,7 @@ fn main() {
match subcommand { match subcommand {
"build" => { "build" => {
let name = &args[1]; let name = &args.pop().unwrap();
build(name.to_string()) build(name.to_string())
} }
"new" => { "new" => {
@ -103,8 +105,21 @@ fn run() {
fn build(name: String) { fn build(name: String) {
println!("building {}", name); println!("building {}", name);
let mut a = name.split("/");
let dev_type = a.next().unwrap();
let name = a.next().unwrap().to_string();
match dev_type {
"programs" => build_program(name),
"idl" => build_idl(name),
_ => {
panic!()
}
}
} }
pub fn build_program(name: String) {}
pub fn build_library(name: String) {}
fn help() { fn help() {
println!( println!(
"========== "==========

View file

@ -5,33 +5,32 @@ 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.git"
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"
git = "https://github.com/limine-bootloader/limine-rs" #git = "https://github.com/limine-bootloader/limine-rs"
[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 { pub 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
@ -182,7 +200,7 @@ pub enum PageEntryFlags {
Global = 1 << 5, Global = 1 << 5,
Access = 1 << 6, Access = 1 << 6,
Dirty = 1 << 7, Dirty = 1 << 7,
// for convenience // for convenience
ReadWrite = Self::Read as usize | Self::Write as usize, ReadWrite = Self::Read as usize | Self::Write as usize,
ReadExecute = Self::Read as usize | Self::Execute as usize, ReadExecute = Self::Read as usize | Self::Execute as usize,
@ -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 = 1;
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(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

@ -1,56 +1,52 @@
// TODO: Turn apic keyboard interrupt into a standard ipc message
use { use {
core::mem::MaybeUninit,
log::trace, log::trace,
spin::{Lazy, Mutex},
x2apic::lapic::{LocalApic, LocalApicBuilder}, x2apic::lapic::{LocalApic, LocalApicBuilder},
x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame, PageFaultErrorCode}, x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame, PageFaultErrorCode},
}; };
pub unsafe fn init() { /// Safety: Using LAPIC or IDT before init() is UB
trace!("Initialising IDT"); /// Using
IDT.load(); static mut LAPIC: LocalApic = unsafe { MaybeUninit::zeroed().assume_init() };
Lazy::force(&LAPIC); static mut IDT: InterruptDescriptorTable = unsafe { MaybeUninit::zeroed().assume_init() };
x86_64::instructions::interrupts::enable();
}
#[repr(u8)] #[repr(u8)]
enum Interrupt { enum Interrupt {
Timer = 32, Timer = 32,
ApicErr = u8::MAX - 1, ApicErr = u8::MAX - 1,
Spurious = u8::MAX, Spurious = u8::MAX,
} }
pub(crate) static LAPIC: Lazy<Mutex<LocalApic>> = Lazy::new(|| { pub unsafe fn init() {
let mut lapic = LocalApicBuilder::new() trace!("Initializing IDT and LAPIC");
// Initialize and load the IDT
IDT = InterruptDescriptorTable::new();
IDT.double_fault
.set_handler_fn(double_fault)
.set_stack_index(super::gdt::DOUBLE_FAULT_IX);
IDT.page_fault.set_handler_fn(page_fault);
IDT[Interrupt::ApicErr as u8].set_handler_fn(apic_err);
IDT[Interrupt::Spurious as u8].set_handler_fn(spurious);
IDT[Interrupt::Timer as u8].set_handler_fn(timer);
IDT.load();
LAPIC = LocalApicBuilder::new()
.timer_vector(Interrupt::Timer as usize) .timer_vector(Interrupt::Timer as usize)
.error_vector(Interrupt::ApicErr as usize) .error_vector(Interrupt::ApicErr as usize)
.spurious_vector(Interrupt::Spurious as usize) .spurious_vector(Interrupt::Spurious as usize)
.set_xapic_base( .set_xapic_base(
unsafe { x2apic::lapic::xapic_base() } x2apic::lapic::xapic_base()
+ super::memory::HHDM_OFFSET.load(core::sync::atomic::Ordering::Relaxed), + super::memory::HHDM_OFFSET.load(core::sync::atomic::Ordering::Relaxed),
) )
.build() .build()
.expect("failed to setup Local APIC"); .expect("Failed to setup Local APIC");
unsafe { lapic.enable() }; LAPIC.enable();
Mutex::new(lapic)
});
static IDT: Lazy<InterruptDescriptorTable> = Lazy::new(|| { x86_64::instructions::interrupts::enable();
let mut idt = InterruptDescriptorTable::new(); }
unsafe {
idt.double_fault
.set_handler_fn(double_fault)
.set_stack_index(super::gdt::DOUBLE_FAULT_IX);
}
idt.page_fault.set_handler_fn(page_fault);
idt[Interrupt::ApicErr as usize].set_handler_fn(apic_err);
idt[Interrupt::Spurious as usize].set_handler_fn(spurious);
idt[Interrupt::Timer as usize].set_handler_fn(timer);
idt
});
extern "x86-interrupt" fn double_fault(stack_frame: InterruptStackFrame, error_code: u64) -> ! { extern "x86-interrupt" fn double_fault(stack_frame: InterruptStackFrame, error_code: u64) -> ! {
panic!("Double fault: error code {error_code} \n{stack_frame:#?}") panic!("Double fault: error code {error_code} \n{stack_frame:#?}")
@ -64,7 +60,9 @@ extern "x86-interrupt" fn page_fault(
} }
extern "x86-interrupt" fn timer(_isf: InterruptStackFrame) { extern "x86-interrupt" fn timer(_isf: InterruptStackFrame) {
unsafe { LAPIC.lock().end_of_interrupt() }; unsafe {
LAPIC.end_of_interrupt();
}
} }
extern "x86-interrupt" fn apic_err(_: InterruptStackFrame) { extern "x86-interrupt" fn apic_err(_: InterruptStackFrame) {
@ -72,5 +70,7 @@ extern "x86-interrupt" fn apic_err(_: InterruptStackFrame) {
} }
extern "x86-interrupt" fn spurious(_: InterruptStackFrame) { extern "x86-interrupt" fn spurious(_: InterruptStackFrame) {
unsafe { LAPIC.lock().end_of_interrupt() }; unsafe {
LAPIC.end_of_interrupt();
}
} }

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,32 +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")
}
} }
} }
} }
@ -228,6 +210,7 @@ pub fn hardware_random_u64() -> u64 {
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

@ -12,7 +12,8 @@ use crate::alloc::string::ToString;
/// Enumerate PCI devices and run initialisation routines on ones we support /// Enumerate PCI devices and run initialisation routines on ones we support
pub fn init(device_tree: &mut DeviceTree) { pub fn init(device_tree: &mut DeviceTree) {
device_tree.devices device_tree
.devices
.insert("Unidentified PCI".to_string(), alloc::vec![]); .insert("Unidentified PCI".to_string(), alloc::vec![]);
let mut devices = alloc::vec![]; let mut devices = alloc::vec![];
@ -23,6 +24,7 @@ pub fn init(device_tree: &mut DeviceTree) {
let id = device_info.device_id.id; let id = device_info.device_id.id;
use Vendor::*; use Vendor::*;
let (dev_type, dev_name) = match (vendor, id) { let (dev_type, dev_name) = match (vendor, id) {
(VMWareInc, 1029) => ("GPUs", "SVGAII PCI GPU"),
(Qemu, 4369) => ("GPUs", "QEMU VGA"), (Qemu, 4369) => ("GPUs", "QEMU VGA"),
(VirtIO, 4176) => ("GPUs", "VirtIO PCI GPU"), (VirtIO, 4176) => ("GPUs", "VirtIO PCI GPU"),
(CirrusLogic, 184) => ("GPUs", "Cirrus SVGA"), //GD 5446? (CirrusLogic, 184) => ("GPUs", "Cirrus SVGA"), //GD 5446?
@ -269,8 +271,7 @@ impl Display for Vendor {
use core::fmt::Display; use core::fmt::Display;
use x86_64::instructions::port::Port; use {crate::device_tree::DeviceTree, x86_64::instructions::port::Port};
use crate::device_tree::DeviceTree;
#[allow(non_camel_case_types, dead_code)] #[allow(non_camel_case_types, dead_code)]
#[derive(Debug, Clone, Copy, PartialEq)] #[derive(Debug, Clone, Copy, PartialEq)]

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

@ -6,6 +6,7 @@ use {
core::fmt, core::fmt,
hashbrown::HashMap, hashbrown::HashMap,
}; };
/// A device object. /// A device object.
/// TODO define device /// TODO define device
pub type Device = xml::XMLElement; pub type Device = xml::XMLElement;
@ -23,27 +24,29 @@ impl DeviceTree {
let mut dt = Self { let mut dt = Self {
devices: HashMap::new(), devices: HashMap::new(),
}; };
device_tree!(dt, [ device_tree!(
"Mice", dt,
"Keyboards", [
"Controllers", "Mice",
"Generic HIDs", "Keyboards",
"Disk Drives", "Controllers",
"CD Drives", "Generic HIDs",
"Batteries", "Disk Drives",
"Monitors", "CD Drives",
"GPUs", "Batteries",
"CPUs", "Monitors",
"USB", "GPUs",
"Serial Ports", "CPUs",
"Cameras", "USB",
"Biometric Devices", "Serial Ports",
]); "Cameras",
"Biometric Devices",
]
);
dt dt
} }
} }
use crate::{utils::TAB, device_tree}; use crate::{device_tree, tab, utils::TAB};
use crate::tab;
impl fmt::Display for DeviceTree { impl fmt::Display for DeviceTree {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
writeln!(f)?; writeln!(f)?;

View file

@ -1,25 +1,19 @@
//! Environment call handling routines //! Environment call handling routines
use core::borrow::Borrow; use crate::holeybytes::kernel_services::{
block_read, dt_msg_handler::dt_msg_handler, logging_service::log_msg_handler,
use crate::{ service_definition_service::sds_msg_handler,
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},
log::{debug, error, info, trace, warn},
}; };
pub fn handler(vm: &mut Vm) { pub fn handler(vm: &mut Vm) {
let ecall_number = vm.registers[2].cast::<u64>(); let ecall_number = vm.registers[2].cast::<u64>();
// log::info!("eca called :pensive:");
// debug!("Ecall number {:?}", ecall_number); // debug!("Ecall number {:?}", ecall_number);
//info!("Register dump: {:?}", vm.registers); //info!("Register dump: {:?}", vm.registers);
@ -74,11 +68,11 @@ pub fn handler(vm: &mut Vm) {
match buffer_id { match buffer_id {
0 => match sds_msg_handler(vm, mem_addr, length) { 0 => match sds_msg_handler(vm, mem_addr, length) {
Ok(()) => {} Ok(()) => {}
Err(err) => log::error!("Improper sds format"), Err(err) => log::error!("Improper sds format: {err:?}"),
}, },
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;
@ -86,71 +80,83 @@ pub fn handler(vm: &mut Vm) {
Ok(_) => {} Ok(_) => {}
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_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_in<T: x86_64::instructions::port::PortRead>(address: u16) -> T {
let mut msg_vec = block_read(mem_addr, length); x86_64::instructions::port::Port::new(address).read()
}
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 => unsafe {
let mut addr = msg_vec[0] as u16; let size = msg_vec[1];
msg_vec.remove(0); let addr = u16::from_le_bytes(msg_vec[2..4].try_into().unwrap());
let value = match size {
let addr2 = msg_vec[0] as u16; 0 => x86_in::<u8>(addr) as u64,
msg_vec.remove(0); 1 => x86_in::<u16>(addr) as u64,
2 => x86_in::<u32>(addr) as u64,
addr = ((addr) << 8) | addr2; _ => panic!("Trying to read size other than: 8, 16, 32 from port."),
};
let value = unsafe { x86_in(addr) }; // info!("Read the value {} from address {}", value, addr);
vm.registers[1] = hbvm::value::Value(value);
trace!("Read the value {} from address {}", value, addr); },
vm.registers[1] = hbvm::value::Value(value as u64); 1 => unsafe {
} let size = msg_vec[1];
1 => { let addr = u16::from_le_bytes(msg_vec[2..4].try_into().unwrap());
let mut addr = msg_vec[0] as u16; trace!("Setting address {}", addr);
msg_vec.remove(0); match size {
0 => x86_out(addr, msg_vec[4]),
let addr2 = msg_vec[0] as u16; 1 => x86_out(
msg_vec.remove(0); addr,
u16::from_le_bytes(msg_vec[4..6].try_into().unwrap_unchecked()),
addr = ((addr) << 8) | addr2; ),
2 => x86_out(
let value = msg_vec[0]; addr,
msg_vec.remove(0); u32::from_le_bytes(msg_vec[4..8].try_into().unwrap_unchecked()),
trace!("Setting the address {} to {}", addr, value); ),
unsafe { x86_out(addr, value) }; _ => panic!("How?"),
} }
},
_ => {} _ => {}
} }
} }
#[cfg(not(target_arch = "x86_64"))]
3 => unimplemented!("TODO: implement whatever buffer 3 does for no x86_64"),
// source of rng // source of rng
4 => { 4 => {
vm.registers[1] = hbvm::value::Value(crate::arch::hardware_random_u64()); // limit to last 32 bits
vm.registers[1] =
hbvm::value::Value(crate::arch::hardware_random_u64() & 0xFFFFFFFF);
} }
5 => match dt_msg_handler(vm, mem_addr, length) {
Ok(()) => {}
Err(_) => log::error!("Improper dt query"),
},
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!(
info!(
"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)
@ -166,7 +172,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();
@ -191,7 +197,7 @@ pub fn handler(vm: &mut Vm) {
} }
} }
info!("Recieve {:?} from Buffer({})", msg, buffer_id); debug!("Recieve {:?} from Buffer({})", msg, buffer_id);
} }
} }
5 => { 5 => {
@ -215,40 +221,13 @@ pub fn handler(vm: &mut Vm) {
} }
} }
fn log_msg_handler(vm: &mut Vm, mem_addr: u64, length: usize) -> Result<(), LogError> {
// let message_length = 8 + 8 + 8;
// log::info!("Mem Addr 0x{:x?} length {}", mem_addr, length);
let mut msg_vec = block_read(mem_addr, length);
let log_level = msg_vec.pop().unwrap();
match String::from_utf8(msg_vec) {
Ok(strr) => {
// use LogLevel::*;
let ll = match log_level {
0 | 48 => error!("{}", strr),
1 | 49 => warn!("{}", strr),
2 | 50 => info!("{}", strr),
3 | 51 => debug!("{}", strr),
4 | 52 => trace!("{}", strr),
_ => {
return Err(LogError::InvalidLogFormat);
}
};
}
Err(e) => {
error!("{:?}", e);
}
}
Ok(())
}
#[derive(Debug)] #[derive(Debug)]
pub enum LogError { pub enum LogError {
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

@ -0,0 +1,87 @@
use {
crate::holeybytes::{kernel_services::block_read, Vm},
alloc::{
string::{String, ToString},
vec::Vec,
},
};
pub enum DtError {
QueryFailure,
}
pub fn dt_msg_handler(vm: &mut Vm, mem_addr: u64, length: usize) -> Result<(), DtError> {
let msg_vec = block_read(mem_addr, length);
let mut bytes: Vec<u8> = Vec::new();
for byte in msg_vec {
if *byte == 0 {
break;
}
bytes.push(*byte)
}
let query_string = String::from_utf8(bytes).unwrap();
log::trace!("Query {}", query_string);
let ret = query_parse(query_string);
log::trace!("Query response {}", ret);
vm.registers[1] = hbvm::value::Value(ret);
Ok(())
}
fn query_parse(query_string: String) -> u64 {
let qt_parse_step_one = query_string.split("/");
let mut qt_parse_step_two: Vec<String> = Vec::new();
for a in qt_parse_step_one {
qt_parse_step_two.push(a.to_string());
}
let first_fragment: &str = &qt_parse_step_two[0];
let ret = match first_fragment {
"framebuffer" => framebuffer_parse(qt_parse_step_two),
"cpu" => cpu_parse(qt_parse_step_two),
_ => 0,
};
return ret;
}
fn cpu_parse(qt_parse_step_two: Vec<String>) -> u64 {
let second_fragment: &str = &qt_parse_step_two[1];
match second_fragment {
// "architecture" => {
// return 0;
// }
_ => {
return 0;
}
};
}
fn framebuffer_parse(qt_parse_step_two: Vec<String>) -> u64 {
use crate::kmain::FB_REQ;
let fbs = &FB_REQ.get_response().get().unwrap().framebuffers();
let second_fragment: &str = &qt_parse_step_two[1];
match second_fragment {
"fb0" => {
let fb_front = &fbs[0];
let third_fragment: &str = &qt_parse_step_two[2];
let ret = match third_fragment {
"ptr" => {
let ptr = fb_front.address.as_ptr().unwrap();
ptr as usize as u64
}
"width" => fb_front.width,
"height" => fb_front.height,
_ => 0,
};
return ret;
}
_ => {
return 0;
}
};
}

View file

@ -0,0 +1,49 @@
use crate::holeybytes::{kernel_services::block_read, Vm};
#[derive(Debug)]
pub enum LogError {
InvalidLogFormat,
}
use log::Record;
pub fn log_msg_handler(_vm: &mut Vm, mem_addr: u64, length: usize) -> Result<(), LogError> {
let msg_vec = block_read(mem_addr, length);
let log_level = msg_vec.last().unwrap();
let file_name = "None";
let line_number = 0;
match core::str::from_utf8(&msg_vec[..msg_vec.len()]) {
Ok(strr) => {
use log::Level::*;
let log_level = match log_level {
0 | 48 => Error,
1 | 49 => Warn,
2 | 50 => Info,
3 | 51 => Debug,
4 | 52 => Trace,
_ => {
return Err(LogError::InvalidLogFormat);
}
};
log::logger().log(
&Record::builder()
.args(format_args!("{}", strr))
.level(log_level)
.target("Userspace")
.file(Some(file_name))
.line(Some(line_number))
.module_path(Some(&file_name))
.build(),
);
}
Err(e) => {
log::error!("{:?}", e);
}
}
Ok(())
}

View file

@ -1,10 +1,7 @@
use { use {
crate::holeybytes::{ crate::holeybytes::{kernel_services::block_read, Vm},
ecah::LogError, alloc::alloc::{alloc, 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(Layout::from_size_align_unchecked(4096, 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(Layout::from_size_align_unchecked(
val.push(0); page_count as usize * 4096,
} 4096,
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, 4096),
)
}
} }
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,11 @@
use alloc::{vec, vec::Vec}; use core::slice;
pub mod dt_msg_handler;
pub mod logging_service;
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 mut [u8] {
unsafe { slice::from_raw_parts_mut(mem_addr as *mut _, 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,43 +1,42 @@
use { use {
crate::{ crate::{
alloc::string::ToString,
arch::hardware_random_u64, arch::hardware_random_u64,
holeybytes::{ecah::LogError, kernel_services::block_read, Vm}, holeybytes::{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());
Mutex::new(dt) Mutex::new(dt)
}); });
#[derive(Debug)]
pub fn sds_msg_handler(vm: &mut Vm, mem_addr: u64, length: usize) -> Result<(), LogError> { pub enum ServiceError {
let mut msg_vec = block_read(mem_addr, length); InvalidFormat,
}
pub fn sds_msg_handler(vm: &mut Vm, mem_addr: u64, length: usize) -> Result<(), ServiceError> {
let msg_vec = block_read(mem_addr, length);
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);
} }
@ -79,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);
@ -96,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,68 +3,62 @@ mod kernel_services;
mod mem; mod mem;
use { use {
crate::{arch, ipc::buffer::IpcBuffer, kmain::IPC_BUFFERS}, alloc::alloc::{alloc, 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,); log::error!("HBVM Error\r\nRegister dump: {:?}", self.vm.registers,);
@ -91,33 +85,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(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, trace},
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);
@ -38,9 +36,9 @@ pub fn kmain(cmdline: &str, boot_modules: BootModules) -> ! {
let dt = DEVICE_TREE.lock(); let dt = DEVICE_TREE.lock();
// TODO(Able): This line causes a deadlock // TODO(Able): This line causes a deadlock
info!("Device Tree: {}", dt); debug!("Device Tree: {}", dt);
info!("Boot complete. Moving to init_system"); trace!("Boot complete. Moving to init_system");
// TODO: schedule the disk driver from the initramfs // TODO: schedule the disk driver from the initramfs
// TODO: schedule the filesystem driver from the initramfs // TODO: schedule the filesystem driver from the initramfs
@ -62,39 +60,32 @@ pub fn kmain(cmdline: &str, boot_modules: BootModules) -> ! {
disp.set_attribute("pitch", fb1.pitch); disp.set_attribute("pitch", fb1.pitch);
dt.devices.insert("Displays".to_string(), alloc::vec![disp]); dt.devices.insert("Displays".to_string(), alloc::vec![disp]);
} }
log::info!("Graphics initialised"); debug!("Graphics initialised");
log::info!( debug!(
"Graphics front ptr {:?}", "Graphics front ptr {:?}",
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();
unsafe { unsafe {
for module in boot_modules.into_iter().take(bm_take) { for module in boot_modules.iter() {
let mut cmd = module.cmd; let cmd = module.cmd.trim_matches('"');
if cmd.len() > 2 { let cmd_len = cmd.len() as u64;
// Remove the quotes
cmd.remove(0);
cmd.pop();
}
let cmd_len = cmd.as_bytes().len() as u64;
log::info!("Spawning {} with arguments \"{}\"", module.path, cmd); log::info!("Spawning {} with arguments \"{}\"", module.path, cmd);
let mut thr = ExecThread::new(&module.bytes, Address::new(0));
if cmd_len > 0 {
thr.set_arguments(cmd.as_ptr() as u64, cmd_len);
}
executor.spawn(async move { executor.spawn(async move {
let mut thr = ExecThread::new(&module.bytes, Address::new(0));
if cmd_len > 0 {
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()); debug!("Random number: {}", hardware_random_u64());
executor.run(); executor.run();
}; };
@ -108,8 +99,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,20 @@
//! 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( #![feature(
exclusive_wrapper,
new_uninit,
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 +41,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 +54,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()));
@ -9,7 +10,11 @@ use {
pub fn init() -> Result<(), SetLoggerError> { pub fn init() -> Result<(), SetLoggerError> {
log::set_logger(&crate::logger::Logger)?; log::set_logger(&crate::logger::Logger)?;
log::set_max_level(log::LevelFilter::Debug); if cfg!(debug_assertions) {
log::set_max_level(log::LevelFilter::Debug);
} else {
log::set_max_level(log::LevelFilter::Info);
}
Lazy::force(&TERMINAL_LOGGER); Lazy::force(&TERMINAL_LOGGER);

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},
@ -85,9 +86,17 @@ impl Package {
Err(e) if e.kind() == std::io::ErrorKind::AlreadyExists => (), Err(e) if e.kind() == std::io::ErrorKind::AlreadyExists => (),
Err(e) => panic!("{}", e), Err(e) => panic!("{}", e),
} }
let path = format!("target/programs/{}.hbf", self.name); std::fs::write(format!("target/programs/{}.hbf", self.name), &bytes).unwrap();
let mut file = File::create(path).unwrap(); bytes.clear();
file.write_all(&bytes).unwrap(); let _ = hblang::run_compiler(
&path,
Options {
dump_asm: true,
..Default::default()
},
&mut bytes,
);
std::fs::write(format!("target/programs/{}.hba", self.name), &bytes).unwrap();
} }
} }
} }

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,
@ -22,10 +24,13 @@ fn main() -> Result<(), Error> {
match args.next().as_deref() { match args.next().as_deref() {
Some("build" | "b") => { Some("build" | "b") => {
let mut release = false; let mut release = false;
let mut debuginfo = false;
let mut target = Target::X86_64; let mut target = Target::X86_64;
for arg in args { for arg in args {
if arg == "-r" || arg == "--release" { if arg == "-r" || arg == "--release" {
release = true; release = true;
} else if arg == "-d" || arg == "--debuginfo" {
debuginfo = true;
} else if arg == "rv64" || arg == "riscv64" || arg == "riscv64-virt" { } else if arg == "rv64" || arg == "riscv64" || arg == "riscv64-virt" {
target = Target::Riscv64Virt; target = Target::Riscv64Virt;
} else if arg == "arm64" || arg == "aarch64" || arg == "aarch64-virt" { } else if arg == "arm64" || arg == "aarch64" || arg == "aarch64-virt" {
@ -35,14 +40,17 @@ fn main() -> Result<(), Error> {
} }
} }
build(release, target).change_context(Error::Build) build(release, target, debuginfo).change_context(Error::Build)
} }
Some("run" | "r") => { Some("run" | "r") => {
let mut release = false; let mut release = false;
let mut debuginfo = false;
let mut target = Target::X86_64; let mut target = Target::X86_64;
for arg in args { for arg in args {
if arg == "-r" || arg == "--release" { if arg == "-r" || arg == "--release" {
release = true; release = true;
} else if arg == "-d" || arg == "--debuginfo" {
debuginfo = true;
} else if arg == "rv64" || arg == "riscv64" || arg == "riscv64-virt" { } else if arg == "rv64" || arg == "riscv64" || arg == "riscv64-virt" {
target = Target::Riscv64Virt; target = Target::Riscv64Virt;
} else if arg == "arm64" || arg == "aarch64" || arg == "aarch64-virt" { } else if arg == "arm64" || arg == "aarch64" || arg == "aarch64-virt" {
@ -52,7 +60,7 @@ fn main() -> Result<(), Error> {
} }
} }
build(release, target)?; build(release, target, debuginfo)?;
run(release, target) run(release, target)
} }
Some("help" | "h") => { Some("help" | "h") => {
@ -187,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"),
@ -236,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(
@ -270,7 +278,7 @@ fn copy_file_to_img(fpath: &str, fs: &FileSystem<File>) {
.expect("Copy failed"); .expect("Copy failed");
} }
fn build(release: bool, target: Target) -> Result<(), Error> { fn build(release: bool, target: Target, debuginfo: bool) -> Result<(), Error> {
let fs = get_fs().change_context(Error::Io)?; let fs = get_fs().change_context(Error::Io)?;
let mut com = Command::new("cargo"); let mut com = Command::new("cargo");
com.current_dir("kernel"); com.current_dir("kernel");
@ -278,6 +286,9 @@ fn build(release: bool, target: Target) -> Result<(), Error> {
if release { if release {
com.arg("-r"); com.arg("-r");
} }
if debuginfo {
com.env("RUSTFLAGS", "-Cdebug-assertions=true");
}
if target == Target::Riscv64Virt { if target == Target::Riscv64Virt {
com.args(["--target", "targets/riscv64-virt-ableos.json"]); com.args(["--target", "targets/riscv64-virt-ableos.json"]);
@ -359,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",
@ -418,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,
} }
@ -435,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

@ -1,2 +0,0 @@
protocol abc {
}

View file

@ -0,0 +1,24 @@
@auto_increment
enum LogLevel {
Error = 0,
Warn,
Info,
Debug,
Trace,
}
@auto_increment
enum LogResult {
Err = 0,
Ok,
}
struct Log {
log_level: LogLevel,
}
@visibility(public)
protocol Log {
fn log(Log) -> LogResult;
fn flush() -> LogResult;
}

View file

@ -0,0 +1 @@
# dt_api

View file

@ -0,0 +1,8 @@
stn := @use("rel:../../stn/src/lib.hb");
.{string, memory, buffer} := stn
dt_get := fn(query: ^u8): int {
message_length := string.length(query)
return @eca(int, 3, 5, query, message_length)
}

View file

@ -1,14 +0,0 @@
Element := struct {
width: int,
height: int,
x: u16,
y: u16,
id: int,
}
create_element := fn(): Element {
return Element.(0, 0, 0, 0, 0)
}

View file

@ -1,3 +0,0 @@
FrameID := struct {
}

View file

@ -1,12 +1,24 @@
stn := @use("rel:../../stn/src/lib.hb");
.{string, memory, buffer} := stn
WindowID := struct { WindowID := struct {
host_id: int, host_id: int,
window_id: int, window_id: int,
} }
create_window := fn(): WindowID { create_window := fn(channel: int): void {
return WindowID.(1, 2) // get the horizon buffer
} // request a new window and provide the callback buffer
// wait to recieve a message
windowing_system_buffer := buffer.search("XHorizon\0")
if windowing_system_buffer == 0 {
} else {
msg := "\{01}\0"
msg_length := 2
@eca(void, 3, windowing_system_buffer, msg, msg_length)
}
update_ui := fn(window_id: WindowID): void {
return return
} }

View file

@ -1,3 +0,0 @@
ui_lisp_text_example := "(text id_1)\0";

View file

@ -0,0 +1,21 @@
structures := @use("rel:structures.hb")
version := @use("rel:version.hb")
// Refer to here https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkApplicationInfo.html
ApplicationInfo := struct {
sType: int,
pNext: ^int,
application_name: ^u8,
application_version: int,
engine_name: int,
engine_version: int,
api_version: int,
}
new_application_info := fn(app_name: ^u8, app_version: int, engine_name: ^u8, engine_version: int, api_version: int): ApplicationInfo {
app_info_type := structures.ApplicationInfoType
app_info := ApplicationInfo.(app_info_type, 0, app_name, app_version, engine_name, engine_version, api_version)
return app_info
}

View file

@ -0,0 +1,14 @@
OutOfHostMemory := -1
OutOfDeviceMemory := -2
InitializationFailed := -3
DeviceLost := -4
MemoryMapFailed := -5
LayerNotPresent := -6
ExtensionNotPresent := -7
FeatureNotPresent := -8
IncompatibleDriver := -9
TooManyObjects := -10
FormatNotSupported := -11
FragmentedPool := -12
Unknown := -13

View file

@ -0,0 +1,10 @@
Extent3D := struct {
width: int,
height: int,
depth: int,
}
Extent2D := struct {
width: int,
height: int,
}

View file

@ -0,0 +1,35 @@
application := @use("rel:application.hb");
.{ApplicationInfo} := application
structures := @use("rel:structures.hb")
errors := @use("rel:errors.hb")
// https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkInstanceCreateInfo.html
InstanceCreateInfo := struct {
sType: int,
pNext: int,
flags: int,
application_info: ^ApplicationInfo,
enabled_layer_count: int,
ppEnabledLayerNames: int,
enabled_extension_count: int,
ppEnabledExtensionNames: int,
}
new_create_info := fn(application_info: ^ApplicationInfo): InstanceCreateInfo {
create_info_type := structures.InstanceCreateInfoType
enabled_layer_count := 0
create_info := InstanceCreateInfo.(create_info_type, 0, 0, application_info, enabled_layer_count, 0, 0, 0)
return create_info
}
// TODO
Instance := struct {inner: int}
void_instance := fn(): Instance {
return Instance.(0)
}
create_instance := fn(create_info: ^InstanceCreateInfo, allocator_callback: int, new_obj: ^Instance): int {
return errors.IncompatibleDriver
}

View file

@ -1,7 +1,17 @@
VK_VERSION_MAJOR := 1; application := @use("rel:application.hb")
VK_VERSION_MINOR := 0;
init_vulkan := fn(): void { results := @use("rel:results.hb")
errors := @use("rel:errors.hb")
return
offsets := @use("rel:offset.hb")
extends := @use("rel:extends.hb")
rect := @use("rel:rect.hb")
structures := @use("rel:structures.hb")
instance := @use("rel:instance.hb")
version := @use("rel:version.hb")
init_vulkan := fn(): int {
return errors.IncompatibleDriver
} }

View file

@ -0,0 +1,10 @@
Offset3D := struct {
x: int,
y: int,
z: int,
}
Offset2D := struct {
x: int,
y: int,
}

View file

@ -0,0 +1,7 @@
offsets := @use("rel:offset.hb")
extends := @use("rel:extends.hb")
Rect2D := struct {
offset: offsets.Offset2D,
extent: extends.Extent2D,
}

View file

@ -0,0 +1,7 @@
// NonErrors
Success := 0
NotReady := 1
Timeout := 2
EventSet := 3
EventReset := 4
Incomplete := 5

View file

@ -0,0 +1,61 @@
ApplicationInfoType := 0
InstanceCreateInfoType := 1
DeviceQueueCreateInfo := 2
DeviceCreateInfo := 3
SubmitInfo := 4
MemoryAllocateInfo := 5
MappedMemoryRange := 6
BindSparseInfo := 7
FenceCreateInfo := 8
SemaphoreCreateInfo := 9
EventCreateInfo := 10
QueryPoolCreateInfo := 11
BufferCreateInfo := 12
BufferViewCreateInfo := 13
ImageCreateInfo := 14
ImageViewCreateInfo := 15
ShaderModuleCreateInfo := 16
PipelineCacheCreateInfo := 17
PipelineShaderStageCreateInfo := 18
PipelineVertexInputStateCreateInfo := 19
PipelineInputAssemblyStateCreateInfo := 20
PipelineTessellationStateCreateInfo := 21
PipelineViewportStateCreateInfo := 22
PipelineRasterizationStateCreateInfo := 23
PipelineMultisampleStateCreateInfo := 24
PipelineDepthStencilStateCreateInfo := 25
PipelineColorBlendStateCreateInfo := 26
PipelineDynamicStateCreateInfo := 27
GraphicsPipelineCreateInfo := 28
ComputePipelineCreateInfo := 29
PipelineLayoutCreateInfo := 30
SamplerCreateInfo := 31
DescriptorSetLayoutCreateInfo := 32
DescriptorPoolCreateInfo := 33
DescriptorSetAllocateInfo := 34
WriteDescriptorSet := 35
CopyDescriptorSet := 36
FramebufferCreateInfo := 37
RenderPassCreateInfo := 38
CommandPoolCreateInfo := 39
CommandBufferAllocateInfo := 40
CommandBufferInheritanceInfo := 41
CommandBufferBeginInfo := 42
RenderPassBeginInfo := 43
BufferMemoryBarrier := 44
ImageMemoryBarrier := 45
MemoryBarrier := 46
LoaderInstanceCreateInfo := 47
LoaderDeviceCreateInfo := 48

View file

@ -0,0 +1,9 @@
ApiVersion1_0 := make_api_version(0, 1, 0, 0)
make_version := fn(major: int, minor: int, patch: int): int {
return major << 22 | minor << 12 | patch
}
make_api_version := fn(variant: int, major: int, minor: int, patch: int): int {
return variant << 29 | major << 22 | minor << 12 | patch
}

View file

@ -0,0 +1 @@
# pci

View file

@ -0,0 +1,28 @@
PCIAddress := struct {
bus: u8,
device: u8,
function: u8,
}
find_device := fn(vendor_id: int, device_id: int, pci_address: PCIAddress): int {
return 1
}
scan_bus := fn(): void {
}
config_read32 := fn(bus: u32, device: u32, func: u32, offset: u32): u32 {
// construct address param
address := bus << 16 | device << 11 | func << 8
address |= offset
address &= 0xFC
address |= 0x80000000
// write address
//Port::new(0xCF8).write(address);
// read data
//Port::new(0xCFC).read()
return
}

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

@ -1 +1,47 @@
software := @use("rel:software.hb") 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

@ -1,16 +1,261 @@
.{buffer} := @use("../../stn/src/lib.hb") .{math, memory} := @use("../../stn/src/lib.hb");
.{dt_get} := @use("../../dt_api/src/lib.hb");
.{IVec2} := @use("rel:lib.hb")
test := fn(): int { Color := struct {b: u8, g: u8, r: u8, a: u8}
buffer_id := buffer.search("XGraphics\0") white := Color.(255, 255, 255, 255)
msg := "\0" black := Color.(0, 0, 0, 255)
buffer.send_message(msg, buffer_id) gray := Color.(127, 127, 127, 255)
return 0 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)
// might not work for some resolutions, but needs to be comptime because...
copy_pixels := 0xC000 >> 2
ctx := @as(Context, idk)
// some of these are redudant holdovers from fb_driver
// will keep them for future work if necessary
Context := struct {
fb: ^Color,
bb: ^Color,
buf: ^Color,
width: int,
height: int,
partitions: int,
pixels: int,
bb_pages: int,
double_buffer: bool,
} }
put_pixel := fn(): int { init := fn(): void {
return 0 width := dt_get("framebuffer/fb0/width\0")
height := dt_get("framebuffer/fb0/height\0")
// 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: dt_get("framebuffer/fb0/ptr\0"),
bb: back_buffer,
buf: back_buffer,
width,
height,
partitions,
pixels,
bb_pages: pages,
double_buffer: true,
}
return
} }
sync := fn(): int { doublebuffer := fn(enable: bool): void {
return 0 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 = -1
dy = -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 = -1
dx = -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,80 @@
.{IVec2} := @use("rel:lib.hb")
// .{pci, memory, string, log} := @use("../../stn/src/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 {
return
}

View file

@ -4,20 +4,18 @@ receive_message := fn(buffer_id: int, memory_map_location: ^u8, length: int): ^u
return @eca(^u8, 4, buffer_id, memory_map_location, length) return @eca(^u8, 4, buffer_id, memory_map_location, length)
} }
send_message := fn(msg: ^u8, buffer_id: int): void { send_message := fn(msg: ^u8, buffer_id: int, length: int): void {
msg_length := string.length(msg) return @eca(void, 3, buffer_id, msg, length)
@eca(i32, 3, buffer_id, msg, msg_length)
return
} }
create := fn(msg: ^u8): int { create := fn(msg: ^u8): int {
msg_length := string.length(msg); msg_length := @inline(string.length, msg);
*msg = 0 *msg = 0
return @eca(int, 3, 0, msg, msg_length) return @eca(int, 3, 0, msg, msg_length)
} }
search := fn(msg: ^u8): int { search := fn(msg: ^u8): int {
msg_length := string.length(msg); msg_length := @inline(string.length, msg);
*msg = 3 *msg = 3
return @eca(int, 3, 0, msg, msg_length) return @eca(int, 3, 0, msg, msg_length)

View file

@ -3,4 +3,5 @@ log := @use("rel:log.hb")
memory := @use("rel:memory.hb") 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

@ -2,7 +2,7 @@ string := @use("rel:string.hb")
buffer := @use("rel:buffer.hb") buffer := @use("rel:buffer.hb")
log := fn(message: ^u8, level: u8): void { log := fn(message: ^u8, level: u8): void {
message_length := string.length(message); message_length := @inline(string.length, message);
*(message + message_length) = level *(message + message_length) = level
@eca(i32, 3, 1, message, message_length + 1) @eca(i32, 3, 1, message, message_length + 1)
return return

View file

@ -1,7 +1,15 @@
shift := 31
// following only work for: int
abs := fn(x: int): int { abs := fn(x: int): int {
mask := x >> 31 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 {
return b + (a - b & a - b >> 31) c := a - b
return b + (c & c >> shift)
}
max := fn(a: int, b: uint): int {
c := a - b
return a - (c & c >> shift)
} }

View file

@ -17,19 +17,23 @@ release_page := fn(ptr: ^u8, page_count: u8): void {
return @eca(void, 3, 2, msg, 12) return @eca(void, 3, 2, msg, 12)
} }
outb := fn(addr_high: u8, addr_low: u8, value: u8): void { OutbMsg := struct {a: u8, b: u8, addr: u16, value: u8}
msg := "\0\0\0\0"; InbMsg := struct {a: u8, b: u8, addr: u16}
*msg = 1; OutlMsg := struct {a: u8, b: u8, addr: u16, value: u32}
*(msg + 1) = addr_high; InlMsg := struct {a: u8, b: u8, addr: u16}
*(msg + 2) = addr_low;
*(msg + 3) = value outb := fn(addr: u16, value: u8): void {
@eca(void, 3, 3, msg, 4) return @eca(void, 3, 3, &OutbMsg.(1, 0, addr, value), @sizeof(OutbMsg))
return
} }
inb := fn(addr_high: u8, addr_low: u8): u8 { inb := fn(addr: u16): u8 {
msg := "\0\0\0\0"; return @eca(u8, 3, 3, &InbMsg.(0, 0, addr), @sizeof(InbMsg))
*(msg + 1) = addr_high; }
*(msg + 2) = addr_low
return @eca(u8, 3, 3, msg, 3) outl := fn(addr: u16, value: u32): void {
return @eca(void, 3, 3, &OutlMsg.(1, 2, addr, value), @sizeof(OutlMsg))
}
inl := fn(addr: u16): u32 {
return @eca(u32, 3, 3, &InlMsg.(0, 2, addr), @sizeof(InlMsg))
} }

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 @@
uint_64 := fn(min: uint, max: uint): uint { integer := fn(): int {
rng := @eca(uint, 3, 4) return @eca(int, 3, 4)
}
if min != 0 | max != 0 { integer_range := fn(min: int, max: int): int {
return rng % (max - min + 1) + min return @eca(int, 3, 4) % (max - min + 1) + min
}
return rng
} }

View file

@ -1,51 +1,48 @@
length := fn(ptr: ^u8): int { length := fn(ptr: ^u8): int {
len := 0 len := 0
loop if *ptr == 0 break else { loop if *(ptr + len) == 0 break else len += 1
len += 1
ptr += 1
}
return len return len
} }
// WTFFF is wrong with display_int
display_int := fn(num: int, p: ^u8): ^u8 { display_int := fn(num: int, p: ^u8): ^u8 {
i := 0 ptr := p
negative := num < 0
if negative {
num = -num
}
if num == 0 { if num == 0 {
set(p, 48) *ptr = 48
return p ptr += 1
} else {
loop if num == 0 break else {
*ptr = num % 10 + 48
ptr += 1
num /= 10
}
} }
loop { if negative {
if num == 0 break *ptr = 45
set(p + i, num % 10 + 48) ptr += 1
num /= 10 };
i += 1 *ptr = 0
} @inline(reverse, p)
reverse(p)
//null terminate
set(p + i, 0)
return p return p
} }
reverse := fn(s: ^u8): void { reverse := fn(s: ^u8): void {
//reverse a string, don't remove digits //reverse a string, don't remove digits
len := 0 len := 0
loop { loop if *(s + len) == 0 break else len += 1
if *(s + len) == 0 break
len += 1
}
i := 0 i := 0
j := len - 1 j := len - 1
loop { temp := 0
if i >= j break loop if i >= j break else {
temp := *(s + i); temp = *(s + i);
*(s + i) = *(s + j); *(s + i) = *(s + j);
*(s + j) = temp *(s + j) = temp
i += 1 i += 1
j -= 1 j -= 1
} }
return return
}
set := fn(change: ^u8, new: int): void {
*change = new
return
} }

View file

@ -1,12 +1,11 @@
stn := @use("../../../libraries/stn/src/lib.hb"); .{memory, buffer} := @use("../../../libraries/stn/src/lib.hb")
.{log, string, memory, buffer} := stn
main := fn(): int { main := fn(): int {
// shuts down ableOS // shuts down ableOS
//memory.outb(0, 244, 0) // memory.outb(0xF400, 0)
a := memory.inb(0, 70) a := memory.inb(0x4600)
b := memory.inb(0, 71) b := memory.inb(0x4700)
c := buffer.search("XNumber\0") c := buffer.search("XNumber\0")

View file

@ -0,0 +1 @@
# dt_buffer_test

View file

@ -1,6 +1,6 @@
[package] [package]
name = "time_driver" name = "dt_buffer_test"
authors = ["SamBuckley"] authors = ["able"]
[dependants.libraries] [dependants.libraries]

View file

@ -0,0 +1,14 @@
dt_api := @use("../../../libraries/dt_api/src/lib.hb");
.{dt_get} := dt_api
main := fn(): int {
dt_api.dt_get("framebuffer/fb0/width\0")
dt_api.dt_get("cpu/cpu0/architecture\0")
// Checking if the first detected serial port is memory mapped or port mapped
// 0 -> memory mapped
// 1 -> port mapped
dt_get("serial_ports/sp0/mapping\0")
return 0
}

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. -aurlex
blend := fn(fg: ColorBGRA, bg: ColorBGRA): ColorBGRA {
s := fg + bg
m := s - ((fg ^ bg) & 16843008) & 16843008
return (m >> 8 | 16777216 * (s < fg)) * 255 | s - m
}

View file

@ -1,113 +0,0 @@
.{draw_pixel, screenidx, Transform, Point, Rect, Buffer, FB_WIDTH} := @use("rel:lib.hb")
ColorBGRA := @use("rel:color.hb").ColorBGRA
math := @use("../../../libraries/stn/src/lib.hb").math
/* 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 + 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 + pos.x + t + FB_WIDTH * y) = color;
*(buffer.write + pos.x + tr.width - t + FB_WIDTH * y) = color
y += 1
}
loop if x == pos.x + tr.width break else {
*(buffer.write + x + (pos.y + t) * FB_WIDTH) = color;
*(buffer.write + x + (pos.y + tr.height - t) * FB_WIDTH) = 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 + x + y * FB_WIDTH) = 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 + x + y * FB_WIDTH) = 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 math.abs(p1.y - p0.y) < math.abs(p1.x - p0.x) {
if p0.x > p1.x {
line_low(buffer, p1, p0, color)
} else {
line_low(buffer, p0, p1, color)
}
} else {
if p0.y > p1.y {
line_high(buffer, p1, p0, color)
} else {
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,100 +0,0 @@
.{memory, log, 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 (1 << 16) - 1, but this was faster
MAX_COPY_SIZE := 6144
// see stn.math.min, cant use here due to compiler bug (reg id leaked)
COPY_PIXELS := MAX_COPY_SIZE + (FB_BYTES - MAX_COPY_SIZE & FB_BYTES - MAX_COPY_SIZE >> 31) >> 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}
Rect := struct {p1: Point, p2: Point}
front_buffer_ptr := @as(^ColorBGRA, @bitcast(18446603339442421760))
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
return Buffer.{write: @as(^ColorBGRA, @bitcast(18446603339442421760)), copy: @as(^[ColorBGRA; COPY_PIXELS], @bitcast(18446603339442421760))}
}
/* this is separate to create_raw_buffer because returning a Buffer from
create_raw_buffer causes reg id leak */
create_buffer := fn(): Buffer {
ptr := create_raw_buffer()
ptr_copy := @as(^[ColorBGRA; COPY_PIXELS], @bitcast(ptr))
// same here, bitcasting inside the struct literal causes reg id leak
buffer := Buffer.{write: ptr, copy: ptr_copy}
return buffer
}
create_raw_buffer := fn(): ^ColorBGRA {
// helps to trace allocation bugs
log.info("Creating buffer. This will allocate.\0")
if TOTAL_PAGES <= 255 {
return @bitcast(memory.request_page(TOTAL_PAGES))
}
ptr := memory.request_page(255)
remaining := TOTAL_PAGES - 255
loop if remaining <= 0 break else {
if remaining < 255 {
memory.request_page(remaining)
} else {
memory.request_page(255)
}
remaining -= 255
}
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 {
offset := 0
// copy chunks of the read buffer to the front buffer
loop if offset >= PARTITIONS break else {
*(front_buffer_copy + offset) = *(buffer.copy + offset)
offset += 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
}
// really need to be able to inline this please - aurlex
screenidx := fn(pos: Point): int {
return pos.x + FB_WIDTH * pos.y
}
point2rect := fn(pos: Point, tr: Transform): Rect {
return .(pos, .(pos.x + tr.x, pos.y + tr.y))
}
rect2point := fn(rect: Rect): struct {point: Point, transform: Transform} {
return .(.(0, 0), .(0, 0))
}

View file

@ -1,20 +0,0 @@
.{log, memory, string, buffer} := @use("../../../libraries/stn/src/lib.hb");
.{front_buffer_ptr, screenidx, ColorBGRA, Point} := @use("./lib.hb")
main := fn(): int {
buffer_id := buffer.create("XGraphics\0")
memmap := memory.request_page(1)
x := 0
loop {
msg := buffer.receive_message(buffer_id, memmap, 0)
if msg != 0 {
log.info("Hello, Framebuffer!\0")
}
loop if x == 4096 {
*(memmap + x) = 0
x += 1
}
x = 0
}
return 0
}

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,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(i8, @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,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 := copy_buffer_ptr
/* 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,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,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,6 +0,0 @@
.{test, put_pixel, sync} := @use("../../../libraries/render/src/lib.hb").software
main := fn(): int {
test()
return 0
}

View file

@ -0,0 +1,3 @@
# Horizon
The Horizon Windowing system server. This is the component that spawns/layouts and renders windows.
For the api look in libraries/horizon_api.

View file

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

View file

@ -0,0 +1,6 @@
alias HostID = u64;
struct WindowID {
host_id: HostID,
window_id: u64
}

View file

@ -0,0 +1,12 @@
stn := @use("../../../libraries/stn/src/lib.hb");
.{string, memory, buffer} := stn
horizon_api := @use("../../../libraries/horizon_api/src/lib.hb")
main := fn(): int {
a := buffer.create("XHorizon\0")
loop {
}
return 0
}

View file

@ -0,0 +1 @@
# horizon_testing_program

View file

@ -0,0 +1,11 @@
[package]
name = "horizon_testing_program"
authors = ["able"]
[dependants.libraries]
[dependants.binaries]
hblang.version = "1.0.0"
[build]
command = "hblang src/main.hb"

View file

@ -0,0 +1,35 @@
stn := @use("../../../libraries/stn/src/lib.hb");
.{string, memory, buffer, log} := stn
horizon_api := @use("../../../libraries/horizon_api/src/lib.hb");
.{create_window} := horizon_api
ignim := @use("../../../libraries/ignim/src/lib.hb");
.{errors} := ignim
main := fn(): int {
windowing_system_buffer := buffer.create("XHorizon\0")
// TODO: get WindowID
create_window(windowing_system_buffer)
program_name := "Horizon Testing Program\0"
program_version := ignim.version.make_version(0, 1, 0)
engine_name := "None\0"
engine_version := ignim.version.make_version(0, 0, 0)
api_version := ignim.version.make_api_version(0, 1, 0, 0)
app_info := ignim.application.new_application_info(program_name, program_version, engine_name, engine_version, api_version)
create_info := ignim.instance.new_create_info(&app_info)
instance := ignim.instance.void_instance()
// TODO: recursively follow this https://vulkan-tutorial.com/Drawing_a_triangle/Setup/Instance
ret := ignim.instance.create_instance(&create_info, 0, &instance)
if ret == errors.IncompatibleDriver {
log.error("Driver Incompatible with Vulkan\0")
}
return 0
}

View file

@ -1,2 +0,0 @@
# KVStore
This is a small single process in memory key value store.

View file

@ -1,37 +0,0 @@
Message := struct {
msg_type: u8,
key: String,
value: String,
}
/*
# Message Type
0 => Set Key type
1 => Get Key
*/
recv_msg:= fn(): Message {
return Message.{
msg_type: 0,
key: "",
value: "",
}
}
main := fn(): int {
loop {
msg := recv_msg();
if msg.msg_type == 0 {
continue;
}
if msg.msg_type == 1 {
continue;
}
if 2 <= msg.msg_type {
error("Unexpected message type in the bagging area");
continue;
}
}
return 0;
}

View file

@ -1,3 +1,3 @@
# PS/2 Driver # PS/2 Driver
This program is a simple driver to read keypresses from a PS/2 Keyboard
Also will contain an abstraction for the PS/2 controller in general so the Mouse code will probably also live here...maybe This program is a simple driver to read keypresses from a PS/2 Keyboard Also will contain an abstraction for the PS/2 controller in general so the Mouse code will probably also live here...maybe

View file

@ -1,15 +1,18 @@
.{memory, log, string, buffer} := @use("../../../libraries/stn/src/lib.hb") .{memory, log, string, buffer} := @use("../../../libraries/stn/src/lib.hb")
send_byte := fn(byte: u8): u8 { send_byte := fn(byte: u8): u8 {
memory.outb(0, 96, byte) memory.outb(96, byte)
return memory.inb(0, 96) return memory.inb(96)
} }
main := fn(): int { main := fn(): int {
send_byte(238)
log.info("PS/2 Driver Loaded\0") log.info("PS/2 Driver Loaded\0")
if send_byte(238) == 238 { if send_byte(238) == 238 {
log.info("PS/2 Keyboard Echoed\0") log.info("PS/2 Keyboard Echoed\0")
} }
a := 0
// a += 1
if send_byte(244) == 250 { if send_byte(244) == 250 {
log.info("Enabled scanning\0") log.info("Enabled scanning\0")
} }
@ -17,14 +20,14 @@ main := fn(): int {
ptr := memory.request_page(1) ptr := memory.request_page(1)
prev_input := 250 prev_input := 250
loop { loop {
input := memory.inb(0, 96) input := memory.inb(96)
if input == prev_input { if input == prev_input {
continue continue
} }
prev_input = input prev_input = input
keycode_str := string.display_int(input, ptr) keycode_str := string.display_int(input, ptr)
log.info(string.display_int(buf)) log.info(keycode_str)
buffer.send_message(keycode_str, buf) buffer.send_message(&input, buf, 1)
} }
return 0 return 0
} }

Some files were not shown because too many files have changed in this diff Show more