forked from koniifer/ableos
Merge pull request 'good luck able' (#17) from koniifer/ableos-framebuffer:master into master
Reviewed-on: https://git.ablecorp.us/AbleOS/ableos/pulls/17
This commit is contained in:
commit
5f2b181f22
1117
Cargo.lock
generated
1117
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
|
@ -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"
|
||||||
|
|
|
@ -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"
|
||||||
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"
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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() {}
|
||||||
|
|
|
@ -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();
|
||||||
|
@ -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;
|
||||||
|
@ -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) {
|
||||||
|
|
|
@ -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,
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,9 @@ use {
|
||||||
|
|
||||||
pub const DOUBLE_FAULT_IX: u16 = 0;
|
pub const DOUBLE_FAULT_IX: u16 = 0;
|
||||||
|
|
||||||
|
const STACK_SIZE: usize = 5 * 1024;
|
||||||
|
const STACK_ALIGNMENT: usize = 4096;
|
||||||
|
|
||||||
pub unsafe fn init() {
|
pub unsafe fn init() {
|
||||||
use x86_64::instructions::{
|
use x86_64::instructions::{
|
||||||
segmentation::{Segment, CS, SS},
|
segmentation::{Segment, CS, SS},
|
||||||
|
@ -32,24 +35,24 @@ struct Selectors {
|
||||||
|
|
||||||
static TSS: Lazy<TaskStateSegment> = Lazy::new(|| {
|
static TSS: Lazy<TaskStateSegment> = Lazy::new(|| {
|
||||||
let mut tss = TaskStateSegment::new();
|
let mut tss = TaskStateSegment::new();
|
||||||
tss.interrupt_stack_table[usize::from(DOUBLE_FAULT_IX)] = {
|
|
||||||
const SIZE: usize = 5 * 1024;
|
let stack_ptr = unsafe {
|
||||||
let stack = unsafe {
|
let layout = alloc::alloc::Layout::from_size_align(STACK_SIZE, STACK_ALIGNMENT)
|
||||||
alloc::alloc::alloc_zeroed(
|
.expect("Failed to create stack layout");
|
||||||
alloc::alloc::Layout::from_size_align(SIZE, 1).expect("stack pointer"),
|
let stack = alloc::alloc::alloc_zeroed(layout);
|
||||||
)
|
VirtAddr::from_ptr(stack) + STACK_SIZE as u64
|
||||||
};
|
|
||||||
VirtAddr::from_ptr(stack) + SIZE
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
tss.interrupt_stack_table[usize::from(DOUBLE_FAULT_IX)] = stack_ptr;
|
||||||
tss
|
tss
|
||||||
});
|
});
|
||||||
|
|
||||||
static GDT: Lazy<(GlobalDescriptorTable, Selectors)> = Lazy::new(|| {
|
static GDT: Lazy<(GlobalDescriptorTable, Selectors)> = Lazy::new(|| {
|
||||||
let mut gdt = GlobalDescriptorTable::new();
|
let mut gdt = GlobalDescriptorTable::new();
|
||||||
let sels = Selectors {
|
let sels = Selectors {
|
||||||
kcode: gdt.add_entry(Descriptor::kernel_code_segment()),
|
kcode: gdt.append(Descriptor::kernel_code_segment()),
|
||||||
kdata: gdt.add_entry(Descriptor::kernel_data_segment()),
|
kdata: gdt.append(Descriptor::kernel_data_segment()),
|
||||||
tss: gdt.add_entry(Descriptor::tss_segment(&TSS)),
|
tss: gdt.append(Descriptor::tss_segment(&TSS)),
|
||||||
};
|
};
|
||||||
(gdt, sels)
|
(gdt, sels)
|
||||||
});
|
});
|
||||||
|
|
|
@ -45,9 +45,9 @@ static IDT: Lazy<InterruptDescriptorTable> = Lazy::new(|| {
|
||||||
}
|
}
|
||||||
idt.page_fault.set_handler_fn(page_fault);
|
idt.page_fault.set_handler_fn(page_fault);
|
||||||
|
|
||||||
idt[Interrupt::ApicErr as usize].set_handler_fn(apic_err);
|
idt[Interrupt::ApicErr as u8].set_handler_fn(apic_err);
|
||||||
idt[Interrupt::Spurious as usize].set_handler_fn(spurious);
|
idt[Interrupt::Spurious as u8].set_handler_fn(spurious);
|
||||||
idt[Interrupt::Timer as usize].set_handler_fn(timer);
|
idt[Interrupt::Timer as u8].set_handler_fn(timer);
|
||||||
|
|
||||||
idt
|
idt
|
||||||
});
|
});
|
||||||
|
|
|
@ -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) });
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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)]
|
||||||
|
|
|
@ -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
|
||||||
}
|
// }
|
||||||
|
|
|
@ -1,22 +1,14 @@
|
||||||
//! 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,
|
|
||||||
dt_msg_handler::dt_msg_handler,
|
|
||||||
logging_service::log_msg_handler,
|
|
||||||
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) {
|
||||||
|
@ -76,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;
|
||||||
|
@ -88,77 +80,109 @@ 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")]
|
#[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_type = msg_vec[0];
|
}
|
||||||
msg_vec.remove(0);
|
let msg_vec = block_read(mem_addr, length);
|
||||||
match msg_type {
|
let msg_type = msg_vec[0];
|
||||||
0 => {
|
match msg_type {
|
||||||
let mut addr = msg_vec[0] as u16;
|
0 => 'wow: {
|
||||||
msg_vec.remove(0);
|
let size = match msg_vec[0] {
|
||||||
|
0 => 1,
|
||||||
let addr2 = msg_vec[0] as u16;
|
1 => 2,
|
||||||
msg_vec.remove(0);
|
2 => 4,
|
||||||
|
_ => {
|
||||||
addr = ((addr) << 8) | addr2;
|
error!("Tried to write more than 32 bits");
|
||||||
|
break 'wow;
|
||||||
let value = unsafe { x86_in(addr) };
|
}
|
||||||
|
};
|
||||||
trace!("Read the value {} from address {}", value, addr);
|
let addr = u16::from_le_bytes(msg_vec[1..3].try_into().unwrap());
|
||||||
vm.registers[1] = hbvm::value::Value(value as u64);
|
let value = unsafe {
|
||||||
|
match size {
|
||||||
|
1 => x86_in::<u8>(addr) as u64,
|
||||||
|
2 => x86_in::<u16>(addr) as u64,
|
||||||
|
4 => x86_in::<u32>(addr) as u64,
|
||||||
|
_ => panic!("how?"),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
trace!("Read the value {} from address {}", value, addr);
|
||||||
|
vm.registers[1] = hbvm::value::Value(value);
|
||||||
|
}
|
||||||
|
1 => 'wow: {
|
||||||
|
let size = match msg_vec[1] {
|
||||||
|
0 => 1,
|
||||||
|
1 => 2,
|
||||||
|
2 => 4,
|
||||||
|
_ => {
|
||||||
|
error!("Tried to write more than 32 bits");
|
||||||
|
break 'wow;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let addr = unsafe {
|
||||||
|
u16::from_le_bytes(msg_vec[1..3].try_into().unwrap_unchecked())
|
||||||
|
};
|
||||||
|
trace!("Setting address {}", addr);
|
||||||
|
unsafe {
|
||||||
|
match size {
|
||||||
|
1 => x86_out(addr, msg_vec[3]),
|
||||||
|
2 => x86_out(
|
||||||
|
addr,
|
||||||
|
u16::from_le_bytes(
|
||||||
|
msg_vec[3..5].try_into().unwrap_unchecked(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
4 => x86_out(
|
||||||
|
addr,
|
||||||
|
u32::from_le_bytes(
|
||||||
|
msg_vec[3..7].try_into().unwrap_unchecked(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
_ => panic!("How?"),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
1 => {
|
|
||||||
let mut addr = msg_vec[0] as u16;
|
|
||||||
msg_vec.remove(0);
|
|
||||||
|
|
||||||
let addr2 = msg_vec[0] as u16;
|
|
||||||
msg_vec.remove(0);
|
|
||||||
|
|
||||||
addr = ((addr) << 8) | addr2;
|
|
||||||
|
|
||||||
let value = msg_vec[0];
|
|
||||||
msg_vec.remove(0);
|
|
||||||
trace!("Setting the address {} to {}", addr, value);
|
|
||||||
unsafe { x86_out(addr, value) };
|
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[cfg(not(target_arch = "x86_64"))]
|
#[cfg(not(target_arch = "x86_64"))]
|
||||||
3 => unimplemented!("TODO: implement whatever buffer 3 does for no x86_64"),
|
3 => unimplemented!("TODO: implement whatever buffer 3 does for no x86_64"),
|
||||||
|
// source of rng
|
||||||
|
4 => {
|
||||||
|
// 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) {
|
5 => match dt_msg_handler(vm, mem_addr, length) {
|
||||||
Ok(()) => {}
|
Ok(()) => {}
|
||||||
Err(err) => log::error!("Improper dt query"),
|
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) => {
|
||||||
use alloc::vec;
|
let mut msg_vec = Vec::with_capacity(length);
|
||||||
let mut msg_vec = vec![];
|
|
||||||
|
|
||||||
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)
|
||||||
|
@ -174,12 +198,12 @@ 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();
|
||||||
} else {
|
} else {
|
||||||
info!("AHHH");
|
// info!("AHHH");
|
||||||
vm.registers[1] = hbvm::value::Value(0);
|
vm.registers[1] = hbvm::value::Value(0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -199,7 +223,7 @@ pub fn handler(vm: &mut Vm) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
info!("Recieve {:?} from Buffer({})", msg, buffer_id);
|
debug!("Recieve {:?} from Buffer({})", msg, buffer_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
5 => {
|
5 => {
|
||||||
|
@ -217,13 +241,19 @@ pub fn handler(vm: &mut Vm) {
|
||||||
vm.registers[3] = x
|
vm.registers[3] = x
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 5
|
|
||||||
_ => {
|
_ => {
|
||||||
log::error!("Syscall unknown {:?}{:?}", ecall_number, vm.registers);
|
log::error!("Syscall unknown {:?}{:?}", ecall_number, vm.registers);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum LogError {
|
||||||
|
NoMessages,
|
||||||
|
InvalidLogFormat,
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 {
|
||||||
|
|
|
@ -1,24 +1,22 @@
|
||||||
use {
|
use {
|
||||||
crate::holeybytes::{kernel_services::block_read, Vm},
|
crate::holeybytes::{kernel_services::block_read, Vm},
|
||||||
alloc::{
|
alloc::{
|
||||||
borrow::ToOwned,
|
|
||||||
string::{String, ToString},
|
string::{String, ToString},
|
||||||
vec::Vec,
|
vec::Vec,
|
||||||
},
|
},
|
||||||
log::debug,
|
|
||||||
};
|
};
|
||||||
pub enum DtError {
|
pub enum DtError {
|
||||||
QueryFailure,
|
QueryFailure,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn dt_msg_handler(vm: &mut Vm, mem_addr: u64, length: usize) -> Result<(), DtError> {
|
pub fn dt_msg_handler(vm: &mut Vm, mem_addr: u64, length: usize) -> Result<(), DtError> {
|
||||||
let mut msg_vec = block_read(mem_addr, length);
|
let msg_vec = block_read(mem_addr, length);
|
||||||
let mut bytes: Vec<u8> = Vec::new();
|
let mut bytes: Vec<u8> = Vec::new();
|
||||||
for byte in msg_vec {
|
for byte in msg_vec {
|
||||||
if byte == 0 {
|
if *byte == 0 {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
bytes.push(byte)
|
bytes.push(*byte)
|
||||||
}
|
}
|
||||||
let query_string = String::from_utf8(bytes).unwrap();
|
let query_string = String::from_utf8(bytes).unwrap();
|
||||||
log::trace!("Query {}", query_string);
|
log::trace!("Query {}", query_string);
|
||||||
|
@ -62,10 +60,7 @@ fn cpu_parse(qt_parse_step_two: Vec<String>) -> u64 {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn framebuffer_parse(qt_parse_step_two: Vec<String>) -> u64 {
|
fn framebuffer_parse(qt_parse_step_two: Vec<String>) -> u64 {
|
||||||
use {
|
use crate::kmain::FB_REQ;
|
||||||
crate::kmain::FB_REQ,
|
|
||||||
limine::{Framebuffer, NonNullPtr},
|
|
||||||
};
|
|
||||||
let fbs = &FB_REQ.get_response().get().unwrap().framebuffers();
|
let fbs = &FB_REQ.get_response().get().unwrap().framebuffers();
|
||||||
|
|
||||||
let second_fragment: &str = &qt_parse_step_two[1];
|
let second_fragment: &str = &qt_parse_step_two[1];
|
||||||
|
|
|
@ -1,25 +1,20 @@
|
||||||
use crate::logger::TermLogger;
|
use crate::holeybytes::{kernel_services::block_read, Vm};
|
||||||
|
|
||||||
use {
|
|
||||||
crate::holeybytes::{kernel_services::block_read, Vm},
|
|
||||||
alloc::string::String,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum LogError {
|
pub enum LogError {
|
||||||
InvalidLogFormat,
|
InvalidLogFormat,
|
||||||
}
|
}
|
||||||
use {alloc::vec, log::Record};
|
use log::Record;
|
||||||
|
|
||||||
pub fn log_msg_handler(vm: &mut Vm, mem_addr: u64, length: usize) -> Result<(), LogError> {
|
pub fn log_msg_handler(_vm: &mut Vm, mem_addr: u64, length: usize) -> Result<(), LogError> {
|
||||||
let mut msg_vec = block_read(mem_addr, length);
|
let msg_vec = block_read(mem_addr, length);
|
||||||
|
|
||||||
let log_level = msg_vec.pop().unwrap();
|
let log_level = msg_vec.last().unwrap();
|
||||||
|
|
||||||
let file_name = "None";
|
let file_name = "None";
|
||||||
let line_number = 0;
|
let line_number = 0;
|
||||||
|
|
||||||
match String::from_utf8(msg_vec) {
|
match core::str::from_utf8(&msg_vec[..msg_vec.len()]) {
|
||||||
Ok(strr) => {
|
Ok(strr) => {
|
||||||
use log::Level::*;
|
use log::Level::*;
|
||||||
let log_level = match log_level {
|
let log_level = match log_level {
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
use {
|
use {
|
||||||
crate::holeybytes::{
|
crate::holeybytes::{kernel_services::block_read, Vm},
|
||||||
kernel_services::{block_read, mem_serve},
|
alloc::alloc::{alloc_zeroed, dealloc},
|
||||||
Vm,
|
core::alloc::Layout,
|
||||||
},
|
|
||||||
alloc::alloc::alloc_zeroed,
|
|
||||||
log::{debug, info},
|
log::{debug, info},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -18,13 +16,10 @@ pub enum MemoryQuotaType {
|
||||||
KillQuota = 3,
|
KillQuota = 3,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn alloc_page(vm: &mut Vm, mem_addr: u64, length: usize) -> Result<(), MemoryServiceError> {
|
fn alloc_page(vm: &mut Vm, _mem_addr: u64, _length: usize) -> Result<(), MemoryServiceError> {
|
||||||
let mut val = alloc::vec::Vec::new();
|
let ptr = unsafe { alloc_zeroed(Layout::new::<[u8; 4096]>()) };
|
||||||
for _ in 0..4096 {
|
info!("Block address: {:?}", ptr);
|
||||||
val.push(0);
|
vm.registers[1] = hbvm::value::Value(ptr as u64);
|
||||||
}
|
|
||||||
info!("Block address: {:?}", val.as_ptr());
|
|
||||||
vm.registers[1] = hbvm::value::Value(val.as_ptr() as u64);
|
|
||||||
vm.registers[2] = hbvm::value::Value(4096);
|
vm.registers[2] = hbvm::value::Value(4096);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -34,34 +29,39 @@ pub fn memory_msg_handler(
|
||||||
mem_addr: u64,
|
mem_addr: u64,
|
||||||
length: usize,
|
length: usize,
|
||||||
) -> Result<(), MemoryServiceError> {
|
) -> Result<(), MemoryServiceError> {
|
||||||
let mut msg_vec = block_read(mem_addr, length);
|
let msg_vec = block_read(mem_addr, length);
|
||||||
let msg_type = msg_vec[0];
|
let msg_type = msg_vec[0];
|
||||||
|
|
||||||
msg_vec.remove(0);
|
|
||||||
match msg_type {
|
match msg_type {
|
||||||
0 => {
|
0 => {
|
||||||
let page_count = msg_vec[0];
|
let page_count = msg_vec[1];
|
||||||
msg_vec.remove(0);
|
let mptr_raw: [u8; 8] = msg_vec[2..10].try_into().unwrap();
|
||||||
|
|
||||||
let mptr_raw: [u8; 8] = msg_vec[0..8].try_into().unwrap();
|
|
||||||
let mptr: u64 = u64::from_le_bytes(mptr_raw);
|
let mptr: u64 = u64::from_le_bytes(mptr_raw);
|
||||||
|
|
||||||
log::debug!("Allocating {} pages @ {:x}", page_count, mptr);
|
log::debug!("Allocating {} pages @ {:x}", page_count, mptr);
|
||||||
|
|
||||||
let mut val = alloc::vec::Vec::new();
|
let ptr = unsafe {
|
||||||
for _ in 0..(page_count as isize * 4096) {
|
alloc_zeroed(Layout::from_size_align_unchecked(
|
||||||
val.push(0);
|
page_count as usize * 4096,
|
||||||
}
|
1,
|
||||||
vm.registers[1] = hbvm::value::Value(val.as_ptr() as u64);
|
))
|
||||||
log::debug!("Kernel ptr: {:x}", val.as_ptr() as u64);
|
};
|
||||||
}
|
|
||||||
1 => {
|
|
||||||
let page_count = msg_vec[0];
|
|
||||||
msg_vec.remove(0);
|
|
||||||
|
|
||||||
let mptr_raw: [u8; 8] = msg_vec[0..8].try_into().unwrap();
|
vm.registers[1] = hbvm::value::Value(ptr as u64);
|
||||||
|
log::debug!("Kernel ptr: {:x}", ptr as u64);
|
||||||
|
}
|
||||||
|
|
||||||
|
1 => {
|
||||||
|
let page_count = msg_vec[1];
|
||||||
|
|
||||||
|
let mptr_raw: [u8; 8] = msg_vec[2..10].try_into().unwrap();
|
||||||
let mptr: u64 = u64::from_le_bytes(mptr_raw);
|
let mptr: u64 = u64::from_le_bytes(mptr_raw);
|
||||||
log::debug!("Deallocating {} pages @ {:x}", page_count, mptr);
|
log::debug!("Deallocating {} pages @ {:x}", page_count, mptr);
|
||||||
|
unsafe {
|
||||||
|
dealloc(
|
||||||
|
mptr as *mut u8,
|
||||||
|
Layout::from_size_align_unchecked(page_count as usize * 4096, 1),
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
2 => {
|
2 => {
|
||||||
use MemoryQuotaType::*;
|
use MemoryQuotaType::*;
|
||||||
|
@ -72,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
|
||||||
|
@ -93,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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_ => {
|
_ => {
|
||||||
|
|
|
@ -1,17 +1,11 @@
|
||||||
use alloc::{vec, vec::Vec};
|
use core::slice;
|
||||||
|
|
||||||
pub mod dt_msg_handler;
|
pub mod dt_msg_handler;
|
||||||
pub mod logging_service;
|
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 [u8] {
|
||||||
|
unsafe { slice::from_raw_parts(mem_addr as *const u8, length) }
|
||||||
for x in 0..(length as isize) {
|
|
||||||
let xyz = mem_addr as *const u8;
|
|
||||||
let value = unsafe { xyz.offset(x).read() };
|
|
||||||
msg_vec.push(value);
|
|
||||||
}
|
|
||||||
msg_vec
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,45 +1,42 @@
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
alloc::string::ToString,
|
|
||||||
arch::hardware_random_u64,
|
arch::hardware_random_u64,
|
||||||
holeybytes::{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 enum ServiceError {
|
pub enum ServiceError {
|
||||||
InvalidFormat,
|
InvalidFormat,
|
||||||
}
|
}
|
||||||
pub fn sds_msg_handler(vm: &mut Vm, mem_addr: u64, length: usize) -> Result<(), ServiceError> {
|
pub fn sds_msg_handler(vm: &mut Vm, mem_addr: u64, length: usize) -> Result<(), ServiceError> {
|
||||||
let mut msg_vec = block_read(mem_addr, length);
|
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);
|
||||||
}
|
}
|
||||||
|
@ -81,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);
|
||||||
|
@ -98,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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,87 +3,87 @@ mod kernel_services;
|
||||||
mod mem;
|
mod mem;
|
||||||
|
|
||||||
use {
|
use {
|
||||||
crate::{arch, ipc::buffer::IpcBuffer, kmain::IPC_BUFFERS},
|
alloc::alloc::{alloc_zeroed, dealloc},
|
||||||
alloc::boxed::Box,
|
core::{
|
||||||
core::{default, future::Future, marker::PhantomData, ptr::NonNull, task::Poll},
|
alloc::Layout,
|
||||||
hbvm::{
|
future::Future,
|
||||||
mem::{
|
pin::Pin,
|
||||||
softpaging::{icache::ICache, HandlePageFault, SoftPagedMem},
|
task::{Context, Poll},
|
||||||
Address, Memory,
|
|
||||||
},
|
},
|
||||||
|
hbvm::{
|
||||||
|
mem::{softpaging::HandlePageFault, Address},
|
||||||
VmRunError, VmRunOk,
|
VmRunError, VmRunOk,
|
||||||
},
|
},
|
||||||
log::{debug, error, info, trace, warn},
|
log::error,
|
||||||
};
|
};
|
||||||
|
|
||||||
const STACK_SIZE: usize = 1024 * 1024;
|
const STACK_SIZE: usize = 1024 * 1024;
|
||||||
const TIMER_QUOTIENT: usize = 100;
|
const TIMER_QUOTIENT: usize = 1000;
|
||||||
type Vm = hbvm::Vm<mem::Memory, TIMER_QUOTIENT>;
|
type Vm = hbvm::Vm<mem::Memory, TIMER_QUOTIENT>;
|
||||||
|
|
||||||
pub struct ExecThread<'p> {
|
pub struct ExecThread {
|
||||||
vm: Vm,
|
vm: Vm,
|
||||||
stack_bottom: *mut u8,
|
stack_bottom: *mut u8,
|
||||||
_phantom: PhantomData<&'p [u8]>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl<'p> Send for ExecThread<'p> {}
|
unsafe impl Send for ExecThread {}
|
||||||
impl<'p> ExecThread<'p> {
|
|
||||||
|
impl ExecThread {
|
||||||
pub fn set_arguments(&mut self, ptr: u64, length: u64) {
|
pub fn set_arguments(&mut self, ptr: u64, length: u64) {
|
||||||
self.vm.registers[1] = hbvm::value::Value(ptr);
|
self.vm.registers[1] = hbvm::value::Value(ptr);
|
||||||
self.vm.registers[2] = hbvm::value::Value(length);
|
self.vm.registers[2] = hbvm::value::Value(length);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn new(program: &'p [u8], entrypoint: Address) -> Self {
|
pub unsafe fn new(program: &[u8], entrypoint: Address) -> Self {
|
||||||
let mut vm = unsafe {
|
let mut vm = Vm::new(
|
||||||
Vm::new(
|
|
||||||
mem::Memory {},
|
mem::Memory {},
|
||||||
Address::new(program.as_ptr() as u64 + entrypoint.get()),
|
Address::new(program.as_ptr() as u64 + entrypoint.get()),
|
||||||
)
|
);
|
||||||
};
|
|
||||||
|
let stack_bottom = allocate_stack();
|
||||||
|
|
||||||
let stack_bottom = unsafe { allocate_stack().as_ptr() };
|
|
||||||
vm.write_reg(254, (stack_bottom as usize + STACK_SIZE - 1) as u64);
|
vm.write_reg(254, (stack_bottom as usize + STACK_SIZE - 1) as u64);
|
||||||
|
|
||||||
ExecThread {
|
ExecThread { vm, stack_bottom }
|
||||||
vm,
|
|
||||||
stack_bottom,
|
|
||||||
_phantom: Default::default(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'p> Drop for ExecThread<'p> {
|
impl<'p> Drop for ExecThread {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
unsafe { alloc::alloc::dealloc(self.stack_bottom, stack_layout()) };
|
unsafe { dealloc(self.stack_bottom, stack_layout()) };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'p> Future for ExecThread<'p> {
|
impl<'p> Future for ExecThread {
|
||||||
type Output = Result<(), VmRunError>;
|
type Output = Result<(), VmRunError>;
|
||||||
|
|
||||||
fn poll(
|
#[inline(always)]
|
||||||
mut self: core::pin::Pin<&mut Self>,
|
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||||
cx: &mut core::task::Context<'_>,
|
|
||||||
) -> Poll<Self::Output> {
|
|
||||||
match self.vm.run() {
|
match self.vm.run() {
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
log::error!("HBVM Error\r\nRegister dump: {:?}", self.vm.registers,);
|
error!("HBVM Error\r\nRegister dump: {:?}", self.vm.registers);
|
||||||
return Poll::Ready(Err(err));
|
Poll::Ready(Err(err))
|
||||||
}
|
}
|
||||||
Ok(VmRunOk::End) => return Poll::Ready(Ok(())),
|
Ok(VmRunOk::End) => Poll::Ready(Ok(())),
|
||||||
Ok(VmRunOk::Ecall) => ecah::handler(&mut self.vm),
|
Ok(VmRunOk::Ecall) => {
|
||||||
Ok(VmRunOk::Timer) => (),
|
ecah::handler(&mut self.vm);
|
||||||
Ok(VmRunOk::Breakpoint) => {
|
|
||||||
log::error!(
|
|
||||||
"HBVM Debug breakpoint\r\nRegister dump: {:?}",
|
|
||||||
self.vm.registers,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cx.waker().wake_by_ref();
|
cx.waker().wake_by_ref();
|
||||||
Poll::Pending
|
Poll::Pending
|
||||||
}
|
}
|
||||||
|
Ok(VmRunOk::Timer) => {
|
||||||
|
cx.waker().wake_by_ref();
|
||||||
|
Poll::Pending
|
||||||
|
}
|
||||||
|
Ok(VmRunOk::Breakpoint) => {
|
||||||
|
error!(
|
||||||
|
"HBVM Debug breakpoint\r\nRegister dump: {:?}",
|
||||||
|
self.vm.registers
|
||||||
|
);
|
||||||
|
cx.waker().wake_by_ref();
|
||||||
|
Poll::Pending
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct PageFaultHandler;
|
struct PageFaultHandler;
|
||||||
|
@ -91,33 +91,22 @@ impl HandlePageFault for PageFaultHandler {
|
||||||
fn page_fault(
|
fn page_fault(
|
||||||
&mut self,
|
&mut self,
|
||||||
reason: hbvm::mem::MemoryAccessReason,
|
reason: hbvm::mem::MemoryAccessReason,
|
||||||
pagetable: &mut hbvm::mem::softpaging::paging::PageTable,
|
_pagetable: &mut hbvm::mem::softpaging::paging::PageTable,
|
||||||
vaddr: hbvm::mem::Address,
|
vaddr: hbvm::mem::Address,
|
||||||
size: hbvm::mem::softpaging::PageSize,
|
size: hbvm::mem::softpaging::PageSize,
|
||||||
dataptr: *mut u8,
|
dataptr: *mut u8,
|
||||||
) -> bool
|
) -> bool {
|
||||||
where
|
error!("REASON: {reason} vaddr: {vaddr} size: {size:?} Dataptr {dataptr:p}");
|
||||||
Self: Sized,
|
|
||||||
{
|
|
||||||
log::error!(
|
|
||||||
"REASON: {reason} \
|
|
||||||
vaddr: {vaddr} \
|
|
||||||
size: {size:?} \
|
|
||||||
Dataptr {dataptr:p}",
|
|
||||||
);
|
|
||||||
|
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const fn stack_layout() -> core::alloc::Layout {
|
#[inline(always)]
|
||||||
unsafe { alloc::alloc::Layout::from_size_align_unchecked(STACK_SIZE, 4096) }
|
const fn stack_layout() -> Layout {
|
||||||
|
unsafe { Layout::from_size_align_unchecked(STACK_SIZE, 4096) }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn allocate_stack() -> NonNull<u8> {
|
#[inline(always)]
|
||||||
let layout = stack_layout();
|
fn allocate_stack() -> *mut u8 {
|
||||||
match NonNull::new(unsafe { alloc::alloc::alloc_zeroed(layout) }) {
|
unsafe { alloc_zeroed(stack_layout()) }
|
||||||
Some(ptr) => ptr,
|
|
||||||
None => alloc::alloc::handle_alloc_error(layout),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -2,27 +2,25 @@
|
||||||
|
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
arch::{hardware_random_u64, logging::SERIAL_CONSOLE},
|
arch::hardware_random_u64,
|
||||||
bootmodules::{build_cmd, BootModules},
|
bootmodules::BootModules,
|
||||||
capabilities,
|
//bootmodules::build_cmd,
|
||||||
device_tree::DeviceTree,
|
device_tree::DeviceTree,
|
||||||
holeybytes::ExecThread,
|
holeybytes::ExecThread,
|
||||||
ipc::buffer::{self, IpcBuffer},
|
ipc::buffer::IpcBuffer,
|
||||||
},
|
},
|
||||||
alloc::format,
|
|
||||||
hashbrown::HashMap,
|
hashbrown::HashMap,
|
||||||
hbvm::mem::Address,
|
hbvm::mem::Address,
|
||||||
limine::{Framebuffer, FramebufferRequest, NonNullPtr},
|
limine::{Framebuffer, FramebufferRequest, NonNullPtr},
|
||||||
log::{debug, info, trace},
|
log::{debug, info},
|
||||||
spin::{Lazy, Mutex},
|
spin::{Lazy, Mutex},
|
||||||
xml::XMLElement,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn kmain(cmdline: &str, boot_modules: BootModules) -> ! {
|
pub fn kmain(_cmdline: &str, boot_modules: BootModules) -> ! {
|
||||||
debug!("Entered kmain");
|
debug!("Entered kmain");
|
||||||
|
|
||||||
let kcmd = build_cmd("Kernel Command Line", cmdline);
|
// let kcmd = build_cmd("Kernel Command Line", cmdline);
|
||||||
trace!("Cmdline: {kcmd:?}");
|
// trace!("Cmdline: {kcmd:?}");
|
||||||
|
|
||||||
// for (i, bm) in boot_modules.iter().enumerate() {
|
// for (i, bm) in boot_modules.iter().enumerate() {
|
||||||
// let name = format!("module-{}", i);
|
// let name = format!("module-{}", i);
|
||||||
|
@ -68,17 +66,18 @@ pub fn kmain(cmdline: &str, boot_modules: BootModules) -> ! {
|
||||||
fb1.address.as_ptr().unwrap() as *const u8
|
fb1.address.as_ptr().unwrap() as *const u8
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut executor = crate::task::Executor::default();
|
let mut executor = crate::task::Executor::new(256);
|
||||||
let bm_take = boot_modules.len();
|
let bm_take = boot_modules.len();
|
||||||
unsafe {
|
unsafe {
|
||||||
for module in boot_modules.into_iter().take(bm_take) {
|
for module in boot_modules.into_iter().take(bm_take) {
|
||||||
let mut cmd = module.cmd;
|
let mut cmd = module.cmd;
|
||||||
if cmd.len() > 2 {
|
if cmd.len() > 2 {
|
||||||
// Remove the quotes
|
// // Remove the quotes
|
||||||
cmd.remove(0);
|
// cmd.remove(0);
|
||||||
cmd.pop();
|
// cmd.pop();
|
||||||
|
cmd = &cmd[1..cmd.len()]
|
||||||
}
|
}
|
||||||
let cmd_len = cmd.as_bytes().len() as u64;
|
let cmd_len = cmd.len() as u64;
|
||||||
|
|
||||||
log::info!("Spawning {} with arguments \"{}\"", module.path, cmd);
|
log::info!("Spawning {} with arguments \"{}\"", module.path, cmd);
|
||||||
|
|
||||||
|
@ -87,11 +86,10 @@ pub fn kmain(cmdline: &str, boot_modules: BootModules) -> ! {
|
||||||
if cmd_len > 0 {
|
if cmd_len > 0 {
|
||||||
thr.set_arguments(cmd.as_bytes().as_ptr() as u64, cmd_len);
|
thr.set_arguments(cmd.as_bytes().as_ptr() as u64, cmd_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Err(e) = thr.await {
|
if let Err(e) = thr.await {
|
||||||
log::error!("{e:?}");
|
log::error!("{e:?}");
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
info!("Random number: {}", hardware_random_u64());
|
info!("Random number: {}", hardware_random_u64());
|
||||||
|
@ -108,8 +106,7 @@ pub static DEVICE_TREE: Lazy<Mutex<DeviceTree>> = Lazy::new(|| {
|
||||||
});
|
});
|
||||||
pub static FB_REQ: FramebufferRequest = FramebufferRequest::new(0);
|
pub static FB_REQ: FramebufferRequest = FramebufferRequest::new(0);
|
||||||
|
|
||||||
use alloc::vec::Vec;
|
pub type IpcBuffers<'a> = HashMap<u64, IpcBuffer<'a>>;
|
||||||
pub type IpcBuffers = HashMap<u64, IpcBuffer>;
|
|
||||||
pub static IPC_BUFFERS: Lazy<Mutex<IpcBuffers>> = Lazy::new(|| {
|
pub static IPC_BUFFERS: Lazy<Mutex<IpcBuffers>> = Lazy::new(|| {
|
||||||
let mut bufs = HashMap::new();
|
let mut bufs = HashMap::new();
|
||||||
let log_buffer = IpcBuffer::new(false, 0);
|
let log_buffer = IpcBuffer::new(false, 0);
|
||||||
|
|
|
@ -1,21 +1,19 @@
|
||||||
//! The ableOS kernel.
|
//! The ableOS kernel.
|
||||||
//! Named akern.
|
//! Named akern.
|
||||||
//! Akern is woefully undersupported at the moment but we are looking to add support improve hardware discovery and make our lives as kernel and operating system developers easier and better
|
//! Akern is woefully undersupported at the moment but we are looking to add support improve hardware discovery and make our lives as kernel and operating system developers easier and better
|
||||||
|
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
#![feature(new_uninit)]
|
||||||
#![feature(
|
#![feature(
|
||||||
abi_x86_interrupt,
|
abi_x86_interrupt,
|
||||||
alloc_error_handler,
|
alloc_error_handler,
|
||||||
inline_const,
|
|
||||||
panic_info_message,
|
|
||||||
pointer_is_aligned,
|
|
||||||
ptr_sub_ptr,
|
ptr_sub_ptr,
|
||||||
custom_test_frameworks,
|
custom_test_frameworks,
|
||||||
naked_functions,
|
naked_functions,
|
||||||
pointer_is_aligned_to
|
pointer_is_aligned_to
|
||||||
)]
|
)]
|
||||||
#![allow(dead_code)]
|
|
||||||
#![test_runner(crate::test_runner)]
|
#![test_runner(crate::test_runner)]
|
||||||
|
#![cfg_attr(not(debug_assertions), allow(unused, deprecated))]
|
||||||
|
#![allow(dead_code)]
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
|
|
||||||
mod allocator;
|
mod allocator;
|
||||||
|
@ -42,6 +40,7 @@ pub const VERSION: Version = Version {
|
||||||
};
|
};
|
||||||
|
|
||||||
#[panic_handler]
|
#[panic_handler]
|
||||||
|
#[cfg(target_os = "none")]
|
||||||
fn panic(info: &core::panic::PanicInfo) -> ! {
|
fn panic(info: &core::panic::PanicInfo) -> ! {
|
||||||
arch::register_dump();
|
arch::register_dump();
|
||||||
|
|
||||||
|
@ -54,10 +53,8 @@ fn panic(info: &core::panic::PanicInfo) -> ! {
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(msg) = info.message() {
|
let msg = info.message();
|
||||||
let _ = crate::arch::log(format_args!("{msg}\r\n"));
|
let _ = crate::arch::log(format_args!("{msg}\r\n"));
|
||||||
}
|
|
||||||
|
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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)?;
|
||||||
|
if cfg!(debug_assertions) {
|
||||||
log::set_max_level(log::LevelFilter::Debug);
|
log::set_max_level(log::LevelFilter::Debug);
|
||||||
|
} else {
|
||||||
|
log::set_max_level(log::LevelFilter::Info);
|
||||||
|
}
|
||||||
|
|
||||||
Lazy::force(&TERMINAL_LOGGER);
|
Lazy::force(&TERMINAL_LOGGER);
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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) {
|
|
||||||
Poll::Ready(()) => {
|
|
||||||
self.tasks.remove(id.0);
|
|
||||||
self.wakers.remove(&id);
|
|
||||||
}
|
|
||||||
Poll::Pending => (),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
self.tasks.is_empty() => break,
|
|
||||||
_ => (),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
*SPAWN_QUEUE.write() = None;
|
for &id in &task_batch[..batch_len] {
|
||||||
|
if let Some(task) = self.tasks.get_mut(id) {
|
||||||
|
let waker = task
|
||||||
|
.waker
|
||||||
|
.get_or_insert_with(|| TaskWaker::new(id, Arc::clone(&self.task_queue)));
|
||||||
|
|
||||||
|
let 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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"]
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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"]
|
||||||
|
|
|
@ -1,16 +1,14 @@
|
||||||
// the 0- thing is scuffed
|
OutOfHostMemory := -1
|
||||||
|
OutOfDeviceMemory := -2
|
||||||
|
InitializationFailed := -3
|
||||||
|
DeviceLost := -4
|
||||||
|
MemoryMapFailed := -5
|
||||||
|
|
||||||
OutOfHostMemory := 0 - 1
|
LayerNotPresent := -6
|
||||||
OutOfDeviceMemory := 0 - 2
|
ExtensionNotPresent := -7
|
||||||
InitializationFailed := 0 - 3
|
FeatureNotPresent := -8
|
||||||
DeviceLost := 0 - 4
|
IncompatibleDriver := -9
|
||||||
MemoryMapFailed := 0 - 5
|
TooManyObjects := -10
|
||||||
|
FormatNotSupported := -11
|
||||||
LayerNotPresent := 0 - 6
|
FragmentedPool := -12
|
||||||
ExtensionNotPresent := 0 - 7
|
Unknown := -13
|
||||||
FeatureNotPresent := 0 - 8
|
|
||||||
IncompatibleDriver := 0 - 9
|
|
||||||
TooManyObjects := 0 - 10
|
|
||||||
FormatNotSupported := 0 - 11
|
|
||||||
FragmentedPool := 0 - 12
|
|
||||||
Unknown := 0 - 13
|
|
9
sysdata/libraries/render/README.md
Normal file
9
sysdata/libraries/render/README.md
Normal 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)
|
47
sysdata/libraries/render/src/lib.hb
Normal file
47
sysdata/libraries/render/src/lib.hb
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
svga := @use("rel:svga.hb")
|
||||||
|
software := @use("rel:software.hb")
|
||||||
|
|
||||||
|
// default mode
|
||||||
|
mode := software
|
||||||
|
|
||||||
|
init := mode.init
|
||||||
|
doublebuffer := mode.doublebuffer
|
||||||
|
|
||||||
|
// Colours
|
||||||
|
Color := mode.Color
|
||||||
|
white := mode.white
|
||||||
|
black := mode.black
|
||||||
|
gray := mode.gray
|
||||||
|
red := mode.red
|
||||||
|
green := mode.green
|
||||||
|
yellow := mode.yellow
|
||||||
|
blue := mode.blue
|
||||||
|
magenta := mode.magenta
|
||||||
|
cyan := mode.cyan
|
||||||
|
light_gray := mode.light_gray
|
||||||
|
light_red := mode.light_red
|
||||||
|
light_green := mode.light_green
|
||||||
|
light_yellow := mode.light_yellow
|
||||||
|
light_blue := mode.light_blue
|
||||||
|
light_magenta := mode.light_magenta
|
||||||
|
light_cyan := mode.light_cyan
|
||||||
|
|
||||||
|
// Drawing
|
||||||
|
put_pixel := mode.put_pixel
|
||||||
|
put_rect := mode.put_rect
|
||||||
|
put_filled_rect := mode.put_filled_rect
|
||||||
|
put_line := mode.put_line
|
||||||
|
clear := mode.clear
|
||||||
|
|
||||||
|
// Display
|
||||||
|
width := mode.width
|
||||||
|
height := mode.height
|
||||||
|
dimensions := mode.dimensions
|
||||||
|
set_height := mode.set_height
|
||||||
|
set_width := mode.set_width
|
||||||
|
set_dimensions := mode.set_dimensions
|
||||||
|
sync := mode.sync
|
||||||
|
|
||||||
|
// Math
|
||||||
|
UVec2 := struct {x: uint, y: uint}
|
||||||
|
IVec2 := struct {x: int, y: int}
|
261
sysdata/libraries/render/src/software.hb
Normal file
261
sysdata/libraries/render/src/software.hb
Normal file
|
@ -0,0 +1,261 @@
|
||||||
|
.{math, memory} := @use("../../stn/src/lib.hb");
|
||||||
|
.{dt_get} := @use("../../dt_api/src/lib.hb");
|
||||||
|
.{IVec2} := @use("rel:lib.hb")
|
||||||
|
|
||||||
|
Color := struct {b: u8, g: u8, r: u8, a: u8}
|
||||||
|
white := Color.(255, 255, 255, 255)
|
||||||
|
black := Color.(0, 0, 0, 255)
|
||||||
|
gray := Color.(127, 127, 127, 255)
|
||||||
|
red := Color.(0, 0, 205, 255)
|
||||||
|
green := Color.(0, 205, 0, 255)
|
||||||
|
yellow := Color.(0, 205, 205, 255)
|
||||||
|
blue := Color.(205, 0, 0, 255)
|
||||||
|
magenta := Color.(205, 0, 205, 255)
|
||||||
|
cyan := Color.(205, 205, 0, 255)
|
||||||
|
light_gray := Color.(229, 229, 229, 255)
|
||||||
|
light_red := Color.(0, 0, 255, 255)
|
||||||
|
light_green := Color.(0, 255, 0, 255)
|
||||||
|
light_yellow := Color.(0, 255, 255, 255)
|
||||||
|
light_blue := Color.(255, 0, 0, 255)
|
||||||
|
light_magenta := Color.(255, 0, 255, 255)
|
||||||
|
light_cyan := Color.(255, 255, 0, 255)
|
||||||
|
|
||||||
|
// 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,
|
||||||
|
}
|
||||||
|
|
||||||
|
init := fn(): void {
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
doublebuffer := fn(enable: bool): void {
|
||||||
|
if enable {
|
||||||
|
ctx.buf = ctx.bb
|
||||||
|
} else {
|
||||||
|
ctx.buf = ctx.fb
|
||||||
|
}
|
||||||
|
ctx.double_buffer = enable
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
create_back_buffer := fn(pages: int): ^Color {
|
||||||
|
if pages <= 0xFF {
|
||||||
|
return @bitcast(@inline(memory.request_page, pages))
|
||||||
|
}
|
||||||
|
ptr := @inline(memory.request_page, 255)
|
||||||
|
remaining := pages - 0xFF
|
||||||
|
loop if remaining <= 0 break else {
|
||||||
|
if remaining < 0xFF {
|
||||||
|
memory.request_page(remaining)
|
||||||
|
} else {
|
||||||
|
memory.request_page(0xFF)
|
||||||
|
}
|
||||||
|
remaining -= 0xFF
|
||||||
|
}
|
||||||
|
return @bitcast(ptr)
|
||||||
|
}
|
||||||
|
|
||||||
|
clear := fn(color: Color): void {
|
||||||
|
cursor := ctx.buf
|
||||||
|
boundary := cursor + 512
|
||||||
|
loop if cursor == boundary break else {
|
||||||
|
*cursor = color
|
||||||
|
cursor += 1
|
||||||
|
}
|
||||||
|
boundary += 512 * 7
|
||||||
|
loop if cursor == boundary break else {
|
||||||
|
*@as(^[Color; 512], @bitcast(cursor)) = *@as(^[Color; 512], @bitcast(ctx.buf))
|
||||||
|
cursor += 512
|
||||||
|
}
|
||||||
|
boundary += copy_pixels - 4096
|
||||||
|
loop if cursor == boundary break else {
|
||||||
|
*@as(^[Color; 4096], @bitcast(cursor)) = *@as(^[Color; 4096], @bitcast(ctx.buf))
|
||||||
|
cursor += 4096
|
||||||
|
}
|
||||||
|
boundary += (ctx.partitions - 1) * copy_pixels
|
||||||
|
loop if cursor == boundary break else {
|
||||||
|
*@as(^[Color; copy_pixels], @bitcast(cursor)) = *@as(^[Color; copy_pixels], @bitcast(ctx.buf))
|
||||||
|
cursor += @sizeof([u8; copy_pixels])
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
sync := fn(): void {
|
||||||
|
if ctx.double_buffer {
|
||||||
|
bb := ctx.buf
|
||||||
|
fb := ctx.fb
|
||||||
|
boundary := bb + ctx.pixels
|
||||||
|
loop if bb == boundary break else {
|
||||||
|
*@as(^[Color; copy_pixels], @bitcast(fb)) = *@as(^[Color; copy_pixels], @bitcast(bb))
|
||||||
|
bb += copy_pixels
|
||||||
|
fb += copy_pixels
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
width := fn(): int {
|
||||||
|
return ctx.width
|
||||||
|
}
|
||||||
|
|
||||||
|
height := fn(): int {
|
||||||
|
return ctx.height
|
||||||
|
}
|
||||||
|
|
||||||
|
screenidx := fn(x: int, y: int): int {
|
||||||
|
return x + ctx.width * y
|
||||||
|
}
|
||||||
|
|
||||||
|
put_pixel := fn(pos: IVec2, color: Color): void {
|
||||||
|
*(ctx.buf + @inline(screenidx, pos.x, pos.y)) = color
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
put_filled_rect := fn(pos: IVec2, tr: IVec2, color: Color): void {
|
||||||
|
x := pos.x
|
||||||
|
y := pos.y
|
||||||
|
end := pos + tr
|
||||||
|
loop if x == end.x break else {
|
||||||
|
loop if y == end.y break else {
|
||||||
|
*(ctx.buf + @inline(screenidx, x, y)) = color
|
||||||
|
y += 1
|
||||||
|
}
|
||||||
|
x += 1
|
||||||
|
y = pos.y
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
put_rect := fn(pos: IVec2, tr: IVec2, color: Color): void {
|
||||||
|
x := pos.x
|
||||||
|
y := pos.y
|
||||||
|
end := pos + tr
|
||||||
|
loop if y == end.y break else {
|
||||||
|
*(ctx.buf + @inline(screenidx, x, y)) = color;
|
||||||
|
*(ctx.buf + @inline(screenidx, x + tr.x, y)) = color
|
||||||
|
y += 1
|
||||||
|
}
|
||||||
|
y = pos.y
|
||||||
|
loop if x == end.x break else {
|
||||||
|
*(ctx.buf + @inline(screenidx, x, y)) = color;
|
||||||
|
*(ctx.buf + @inline(screenidx, x, y + tr.y)) = color
|
||||||
|
x += 1
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
put_line_low := fn(p0: IVec2, p1: IVec2, color: Color): void {
|
||||||
|
dx := p1.x - p0.x
|
||||||
|
dy := p1.y - p0.y
|
||||||
|
yi := 1
|
||||||
|
if dy < 0 {
|
||||||
|
yi = -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
|
||||||
|
}
|
80
sysdata/libraries/render/src/svga.hb
Normal file
80
sysdata/libraries/render/src/svga.hb
Normal 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
|
||||||
|
}
|
|
@ -4,21 +4,20 @@ 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(buffer_id: int): void {
|
send_message := fn(msg: ^u8, buffer_id: int): void {
|
||||||
message := "Hello there\0"
|
msg_length := @inline(string.length, msg)
|
||||||
message_length := string.length(message)
|
@eca(i32, 3, buffer_id, msg, msg_length)
|
||||||
@eca(i32, 3, buffer_id, message, message_length)
|
|
||||||
return
|
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)
|
||||||
|
|
|
@ -3,3 +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")
|
||||||
|
pci := @use("rel:pci.hb")
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
|
@ -17,19 +17,38 @@ 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 {
|
outb := fn(addr: u16, value: u8): void {
|
||||||
msg := "\0\0\0\0";
|
msg := "\0\0\0\0\0";
|
||||||
*msg = 1;
|
*@as(^u8, msg) = @as(u8, 1);
|
||||||
*(msg + 1) = addr_high;
|
*@as(^u8, msg + 1) = @as(u8, 0);
|
||||||
*(msg + 2) = addr_low;
|
*@as(^u16, @bitcast(msg + 2)) = addr;
|
||||||
*(msg + 3) = value
|
*@as(^u8, msg + 4) = value
|
||||||
@eca(void, 3, 3, msg, 4)
|
@eca(void, 3, 3, msg, 5)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
inb := fn(addr_high: u8, addr_low: u8): u8 {
|
inb := fn(addr: u16): u8 {
|
||||||
msg := "\0\0\0\0";
|
msg := "\0\0\0\0";
|
||||||
*(msg + 1) = addr_high;
|
*@as(^u8, msg) = @as(u8, 0);
|
||||||
*(msg + 2) = addr_low
|
*@as(^u8, msg + 1) = @as(u8, 0);
|
||||||
return @eca(u8, 3, 3, msg, 3)
|
*@as(^u16, @bitcast(msg + 2)) = addr
|
||||||
|
return @eca(u8, 3, 3, msg, 4)
|
||||||
|
}
|
||||||
|
|
||||||
|
outl := fn(addr: u16, value: u32): void {
|
||||||
|
msg := "\0\0\0\0\0\0\0\0";
|
||||||
|
*@as(^u8, msg) = @as(u8, 1);
|
||||||
|
*@as(^u8, msg + 1) = @as(u8, 2);
|
||||||
|
*@as(^u16, @bitcast(msg + 2)) = addr;
|
||||||
|
*@as(^u32, @bitcast(msg + 4)) = value
|
||||||
|
@eca(void, 3, 3, msg, 8)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
inl := fn(addr: u16): u32 {
|
||||||
|
msg := "\0\0\0\0";
|
||||||
|
*@as(^u8, msg) = @as(u8, 0);
|
||||||
|
*@as(^u8, msg + 1) = @as(u8, 2);
|
||||||
|
*@as(^u16, @bitcast(msg + 2)) = addr
|
||||||
|
return @eca(u32, 3, 3, msg, 4)
|
||||||
}
|
}
|
50
sysdata/libraries/stn/src/pci.hb
Normal file
50
sysdata/libraries/stn/src/pci.hb
Normal 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))
|
||||||
|
}
|
7
sysdata/libraries/stn/src/random.hb
Normal file
7
sysdata/libraries/stn/src/random.hb
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
integer := fn(): int {
|
||||||
|
return @eca(int, 3, 4)
|
||||||
|
}
|
||||||
|
|
||||||
|
integer_range := fn(min: int, max: int): int {
|
||||||
|
return @eca(int, 3, 4) % (max - min + 1) + min
|
||||||
|
}
|
|
@ -1,42 +1,34 @@
|
||||||
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
|
||||||
}
|
}
|
||||||
|
|
||||||
display_int := fn(num: int, p: ^u8): ^u8 {
|
display_int := fn(num: int, p: ^u8): ^u8 {
|
||||||
i := 0
|
i := 0
|
||||||
if num == 0 {
|
if num == 0 {
|
||||||
set(p, 48)
|
*p = 48
|
||||||
return p
|
return p
|
||||||
}
|
}
|
||||||
loop {
|
loop if num == 0 break else {
|
||||||
if num == 0 break
|
*(p + i) = num % 10 + 48
|
||||||
set(p + i, num % 10 + 48)
|
|
||||||
num /= 10
|
num /= 10
|
||||||
i += 1
|
i += 1
|
||||||
}
|
}
|
||||||
reverse(p)
|
@inline(reverse, p);
|
||||||
//null terminate
|
*(p + i) = 0
|
||||||
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
|
||||||
|
@ -44,8 +36,3 @@ reverse := fn(s: ^u8): void {
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
set := fn(change: ^u8, new: int): void {
|
|
||||||
*change = new
|
|
||||||
return
|
|
||||||
}
|
|
|
@ -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")
|
||||||
|
|
||||||
|
|
|
@ -1,2 +0,0 @@
|
||||||
# Framebuffer Driver
|
|
||||||
A simple framebuffer driver.
|
|
|
@ -1,7 +0,0 @@
|
||||||
color.blend
|
|
||||||
|
|
||||||
lib.composite
|
|
||||||
lib.screen2rect
|
|
||||||
lib.rect2screen
|
|
||||||
|
|
||||||
draw.tri_line
|
|
|
@ -1,11 +0,0 @@
|
||||||
[package]
|
|
||||||
name = "fb_driver"
|
|
||||||
authors = ["able", "aurlex"]
|
|
||||||
|
|
||||||
[dependants.libraries]
|
|
||||||
|
|
||||||
[dependants.binaries]
|
|
||||||
hblang.version = "1.0.0"
|
|
||||||
|
|
||||||
[build]
|
|
||||||
command = "hblang src/main.hb"
|
|
|
@ -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
|
|
||||||
}
|
|
|
@ -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
|
|
||||||
}
|
|
|
@ -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
|
|
||||||
}
|
|
|
@ -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
|
|
||||||
}
|
|
|
@ -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
|
|
||||||
}
|
|
|
@ -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
|
|
||||||
}
|
|
|
@ -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
|
|
||||||
}
|
|
|
@ -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
|
|
||||||
}
|
|
|
@ -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(0 - 140734267129856))
|
|
||||||
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(0 - 140734267129856)), copy: @as(^[ColorBGRA; COPY_PIXELS], @bitcast(0 - 140734267129856))}
|
|
||||||
}
|
|
||||||
/* 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))
|
|
||||||
}
|
|
|
@ -1,7 +0,0 @@
|
||||||
// change "lines.hb" to another example to see it onscreen
|
|
||||||
example := @use("examples/square.hb").example
|
|
||||||
|
|
||||||
main := fn(): int {
|
|
||||||
example()
|
|
||||||
return 0
|
|
||||||
}
|
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "time_driver"
|
name = "render_example"
|
||||||
authors = ["SamBuckley"]
|
authors = ["koniifer"]
|
||||||
|
|
||||||
[dependants.libraries]
|
[dependants.libraries]
|
||||||
|
|
20
sysdata/programs/render_example/src/examples/amogus.hb
Normal file
20
sysdata/programs/render_example/src/examples/amogus.hb
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
render := @use("../../../../libraries/render/src/lib.hb")
|
||||||
|
|
||||||
|
/* expected result:
|
||||||
|
the impostor travels left and loops around the screen */
|
||||||
|
|
||||||
|
example := fn(): void {
|
||||||
|
render.init()
|
||||||
|
x := 0
|
||||||
|
loop {
|
||||||
|
render.put_rect(.(200 - x, 80), .(430, 380), render.red)
|
||||||
|
render.put_rect(.(630 - x, 120), .(120, 300), render.red)
|
||||||
|
render.put_rect(.(200 - x, 460), .(160, 270), render.red)
|
||||||
|
render.put_rect(.(470 - x, 460), .(160, 270), render.red)
|
||||||
|
render.put_rect(.(140 - x, 140), .(340, 250), render.cyan)
|
||||||
|
render.sync()
|
||||||
|
render.clear(render.black)
|
||||||
|
x += 1
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
21
sysdata/programs/render_example/src/examples/colors.hb
Normal file
21
sysdata/programs/render_example/src/examples/colors.hb
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
render := @use("../../../../libraries/render/src/lib.hb")
|
||||||
|
|
||||||
|
/* expected result:
|
||||||
|
the screen fades from cyan to green
|
||||||
|
then wraps back to cyan
|
||||||
|
note that this may happen too fast for you to notice... */
|
||||||
|
|
||||||
|
example := fn(): void {
|
||||||
|
render.init()
|
||||||
|
color := render.light_cyan
|
||||||
|
n := @as(u8, 1)
|
||||||
|
loop {
|
||||||
|
render.clear(color)
|
||||||
|
render.sync()
|
||||||
|
if (color.b & 255) == 255 | (color.b & 255) == 0 {
|
||||||
|
n = -n
|
||||||
|
}
|
||||||
|
color.b += n
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
22
sysdata/programs/render_example/src/examples/lines.hb
Normal file
22
sysdata/programs/render_example/src/examples/lines.hb
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
render := @use("../../../../libraries/render/src/lib.hb")
|
||||||
|
|
||||||
|
/* expected result:
|
||||||
|
a 3d-looking set of blue lines
|
||||||
|
created on a blue background */
|
||||||
|
|
||||||
|
example := fn(): void {
|
||||||
|
render.init()
|
||||||
|
render.clear(.(100, 50, 0, 255))
|
||||||
|
width := render.width()
|
||||||
|
height := render.height()
|
||||||
|
p0 := render.IVec2.(0, 0)
|
||||||
|
p1 := render.IVec2.(0, height)
|
||||||
|
loop if p0.y >= height break else {
|
||||||
|
render.put_line(p0, p1, .(255, 180, 100, 255))
|
||||||
|
render.put_line(.(width, height) - p0, .(width, height) - p1, .(255, 180, 100, 255))
|
||||||
|
p0.y += height >> 6
|
||||||
|
p1.x += width >> 6
|
||||||
|
}
|
||||||
|
render.sync()
|
||||||
|
return
|
||||||
|
}
|
17
sysdata/programs/render_example/src/examples/random.hb
Normal file
17
sysdata/programs/render_example/src/examples/random.hb
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
.{random} := @use("../../../../libraries/stn/src/lib.hb")
|
||||||
|
render := @use("../../../../libraries/render/src/lib.hb")
|
||||||
|
|
||||||
|
example := fn(): void {
|
||||||
|
render.init()
|
||||||
|
render.doublebuffer(false)
|
||||||
|
render.clear(render.black)
|
||||||
|
loop {
|
||||||
|
x := random.integer_range(0, 1024)
|
||||||
|
y := random.integer_range(0, 768)
|
||||||
|
r := random.integer_range(0, 255)
|
||||||
|
g := random.integer_range(0, 75)
|
||||||
|
b := random.integer_range(0, 155)
|
||||||
|
render.put_pixel(.(x, y), .(b, g, r, 255))
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
27
sysdata/programs/render_example/src/examples/square.hb
Normal file
27
sysdata/programs/render_example/src/examples/square.hb
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
render := @use("../../../../libraries/render/src/lib.hb")
|
||||||
|
|
||||||
|
/* expected result:
|
||||||
|
the white outline of a square bounces around the screen */
|
||||||
|
|
||||||
|
example := fn(): void {
|
||||||
|
render.init()
|
||||||
|
vel := render.IVec2.(1, 1)
|
||||||
|
pos := render.IVec2.(100, 100)
|
||||||
|
width := render.width()
|
||||||
|
height := render.height()
|
||||||
|
loop {
|
||||||
|
render.put_rect(pos, .(100, 100), render.white)
|
||||||
|
render.sync()
|
||||||
|
render.clear(render.black)
|
||||||
|
|
||||||
|
if pos.x == 0 | pos.x == width - 100 {
|
||||||
|
vel.x = -vel.x
|
||||||
|
}
|
||||||
|
if pos.y == 0 | pos.y == height - 100 {
|
||||||
|
vel.y = -vel.y
|
||||||
|
}
|
||||||
|
|
||||||
|
pos += vel
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
15
sysdata/programs/render_example/src/examples/strobe.hb
Normal file
15
sysdata/programs/render_example/src/examples/strobe.hb
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
render := @use("../../../../libraries/render/src/lib.hb")
|
||||||
|
|
||||||
|
/* expected result: (EPILEPSY WARNING)
|
||||||
|
the screen rapidly flashes red then black */
|
||||||
|
|
||||||
|
example := fn(): void {
|
||||||
|
render.init()
|
||||||
|
loop {
|
||||||
|
render.clear(render.red)
|
||||||
|
render.sync()
|
||||||
|
render.clear(render.yellow)
|
||||||
|
render.sync()
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
8
sysdata/programs/render_example/src/examples/svga.hb
Normal file
8
sysdata/programs/render_example/src/examples/svga.hb
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
render := @use("../../../../libraries/render/src/lib.hb")
|
||||||
|
|
||||||
|
render.mode = render.svga
|
||||||
|
|
||||||
|
example := fn(): void {
|
||||||
|
render.init()
|
||||||
|
return
|
||||||
|
}
|
6
sysdata/programs/render_example/src/main.hb
Normal file
6
sysdata/programs/render_example/src/main.hb
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
.{example} := @use("./examples/colors.hb")
|
||||||
|
|
||||||
|
main := fn(): void {
|
||||||
|
@inline(example)
|
||||||
|
return
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
[package]
|
[package]
|
||||||
name = "a_serial_driver"
|
name = "serial_driver"
|
||||||
authors = ["Able"]
|
authors = ["Able"]
|
||||||
|
|
||||||
[dependants.libraries]
|
[dependants.libraries]
|
|
@ -1,11 +1,10 @@
|
||||||
stn := @use("../../../libraries/stn/src/lib.hb");
|
.{memory, buffer} := @use("../../../libraries/stn/src/lib.hb")
|
||||||
.{log, string, memory, buffer} := stn
|
|
||||||
|
|
||||||
serial_print := fn(ptr: ^u8): void {
|
serial_print := fn(ptr: ^u8): void {
|
||||||
letter := 0
|
letter := 0
|
||||||
loop if *ptr == 0 break else {
|
loop if *ptr == 0 break else {
|
||||||
letter = *ptr
|
letter = *ptr
|
||||||
memory.outb(3, 248, letter)
|
memory.outb(0xF803, letter)
|
||||||
ptr += 1
|
ptr += 1
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
|
@ -13,8 +12,8 @@ serial_print := fn(ptr: ^u8): void {
|
||||||
|
|
||||||
serial_println := fn(ptr: ^u8): void {
|
serial_println := fn(ptr: ^u8): void {
|
||||||
serial_print(ptr)
|
serial_print(ptr)
|
||||||
memory.outb(3, 248, 12)
|
memory.outb(0xF803, 12)
|
||||||
memory.outb(3, 248, 13)
|
memory.outb(0xF803, 13)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,7 +25,7 @@ main := fn(): int {
|
||||||
mem := memory.request_page(1)
|
mem := memory.request_page(1)
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
ptr := @eca(int, 4, a, mem, 4096)
|
ptr := @eca(int, 4, a, mem, 0x1000)
|
||||||
if ptr == 0 {
|
if ptr == 0 {
|
||||||
serial_println("No message\0")
|
serial_println("No message\0")
|
||||||
}
|
}
|
|
@ -1,14 +1,11 @@
|
||||||
stn := @use("../../../libraries/stn/src/lib.hb");
|
.{string, buffer} := @use("../../../libraries/stn/src/lib.hb")
|
||||||
.{string, memory, buffer} := stn
|
|
||||||
|
|
||||||
frame_buffer := @as(^u8, @bitcast(0 - 140734267129856))
|
|
||||||
|
|
||||||
log_info := fn(): void {
|
log_info := fn(): void {
|
||||||
a := buffer.search("XNumber\0")
|
a := buffer.search("XNumber\0")
|
||||||
if a == 0 {
|
if a == 0 {
|
||||||
} else {
|
} else {
|
||||||
msg := "XABC\0"
|
msg := "XABC\0"
|
||||||
msg_length := string.length(msg)
|
msg_length := @inline(string.length, msg)
|
||||||
@eca(void, 3, a, msg, msg_length)
|
@eca(void, 3, a, msg, msg_length)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
stn := @use("../../../libraries/stn/src/lib.hb");
|
.{log, string, memory, buffer} := @use("../../../libraries/stn/src/lib.hb")
|
||||||
.{log, string, memory, buffer} := stn
|
|
||||||
|
|
||||||
service_search := fn(): void {
|
service_search := fn(): void {
|
||||||
a := "\{01}\0"
|
a := "\{01}\0"
|
||||||
|
|
|
@ -1,22 +0,0 @@
|
||||||
stn := @use("../../../libraries/stn/src/lib.hb")
|
|
||||||
log := stn.log
|
|
||||||
mem := stn.memory
|
|
||||||
s := stn.string
|
|
||||||
page := 0
|
|
||||||
|
|
||||||
main := fn(): void {
|
|
||||||
page += mem.request_page(1)
|
|
||||||
port_str := "\0\0\{47}\0"
|
|
||||||
a := @eca(u8, 3, 3, port_str, 4)
|
|
||||||
|
|
||||||
n := 5000000
|
|
||||||
loop {
|
|
||||||
if n == 0 break
|
|
||||||
n -= 1
|
|
||||||
stack_reclamation_edge_case := 0
|
|
||||||
}
|
|
||||||
td := s.display_int(a, page)
|
|
||||||
log.debug(td)
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
|
@ -19,31 +19,27 @@ resolution = "1024x768x24"
|
||||||
|
|
||||||
# [boot.limine.ableos.modules.tests]
|
# [boot.limine.ableos.modules.tests]
|
||||||
# path = "boot:///tests.hbf"
|
# path = "boot:///tests.hbf"
|
||||||
# [boot.limine.ableos.modules.a_serial_driver]
|
|
||||||
# path = "boot:///a_serial_driver.hbf"
|
|
||||||
|
|
||||||
|
# [boot.limine.ableos.modules.0serial_driver]
|
||||||
|
# path = "boot:///serial_driver.hbf"
|
||||||
|
|
||||||
# [boot.limine.ableos.modules.diskio_driver]
|
# [boot.limine.ableos.modules.diskio_driver]
|
||||||
# path = "boot:///diskio_driver.hbf"
|
# path = "boot:///diskio_driver.hbf"
|
||||||
|
|
||||||
# [boot.limine.ableos.modules.fb_driver]
|
# [boot.limine.ableos.modules.render_example]
|
||||||
# path = "boot:///fb_driver.hbf"
|
# path = "boot:///render_example.hbf"
|
||||||
|
|
||||||
|
|
||||||
# [boot.limine.ableos.modules.serial_driver_test]
|
# [boot.limine.ableos.modules.serial_driver_test]
|
||||||
# path = "boot:///serial_driver_test.hbf"
|
# path = "boot:///serial_driver_test.hbf"
|
||||||
|
|
||||||
|
|
||||||
# [boot.limine.ableos.modules.horizon]
|
# [boot.limine.ableos.modules.horizon]
|
||||||
# path = "boot:///horizon.hbf"
|
# path = "boot:///horizon.hbf"
|
||||||
|
|
||||||
# [boot.limine.ableos.modules.horizon_testing_program]
|
# [boot.limine.ableos.modules.horizon_testing_program]
|
||||||
# path = "boot:///horizon_testing_program.hbf"
|
# path = "boot:///horizon_testing_program.hbf"
|
||||||
|
|
||||||
|
|
||||||
# [boot.limine.ableos.modules.dt_buffer_test]
|
# [boot.limine.ableos.modules.dt_buffer_test]
|
||||||
# path = "boot:///dt_buffer_test.hbf"
|
# path = "boot:///dt_buffer_test.hbf"
|
||||||
|
|
||||||
|
|
||||||
[boot.limine.ableos.modules.svga_driver]
|
[boot.limine.ableos.modules.svga_driver]
|
||||||
path = "boot:///svga_driver.hbf"
|
path = "boot:///svga_driver.hbf"
|
||||||
|
|
Loading…
Reference in a new issue