1
0
Fork 0
forked from AbleOS/ableos

Compare commits

...

10 commits

Author SHA1 Message Date
funky 95cf948d59 Ktest major improvements 2024-11-27 19:09:15 +11:00
koniifer f6a8a78b6c mini size fixes 2024-11-26 22:02:54 +00:00
kodin 5d152811b2 Interrupt Forwarding (#22)
Co-authored-by: Talha Qamar <qamartalha@proton.me>
Reviewed-on: https://git.ablecorp.us/AbleOS/ableos/pulls/22
Co-authored-by: kodin <kodin@yourmoms.house>
Co-committed-by: kodin <kodin@yourmoms.house>
2024-11-26 15:53:50 -06:00
koniifer 685c6f0b20 task scheduler weirdness 2024-11-26 19:32:19 +00:00
Able 1b3dc153e8 SDoom + pcspkr: Both prerelease 2024-11-26 07:39:16 -06:00
Able 9aa84a0f40 👍 checkpoint 2024-11-24 23:51:37 -06:00
Able bdb762c986 Magic function style guide 2024-11-24 23:50:46 -06:00
koniifer 0b57c2e9bb simple foldhash implementation 2024-11-24 20:58:14 +00:00
Able 8c88c0b5ae defer in alloc 2024-11-24 12:43:15 -06:00
Able 8b2b50e433 Style guide update, vscode config to make tab indent follow the style guide 2024-11-24 12:22:06 -06:00
35 changed files with 736 additions and 187 deletions

View file

@ -1,4 +1,6 @@
{
"editor.insertSpaces": false,
"editor.detectIndentation": false,
"rust-analyzer.checkOnSave.allTargets": false,
"rust-analyzer.showUnlinkedFileNotification": false,
"C_Cpp.errorSquiggles": "disabled"

6
Cargo.lock generated
View file

@ -213,12 +213,12 @@ dependencies = [
[[package]]
name = "hbbytecode"
version = "0.1.0"
source = "git+https://git.ablecorp.us/AbleOS/holey-bytes.git#784d552c1dee2a3cfde4b83e01523d91988bb554"
source = "git+https://git.ablecorp.us/AbleOS/holey-bytes.git#a3355a59c0727e58519a94a8f65013beb9c2331b"
[[package]]
name = "hblang"
version = "0.1.0"
source = "git+https://git.ablecorp.us/AbleOS/holey-bytes.git#784d552c1dee2a3cfde4b83e01523d91988bb554"
source = "git+https://git.ablecorp.us/AbleOS/holey-bytes.git#a3355a59c0727e58519a94a8f65013beb9c2331b"
dependencies = [
"hashbrown",
"hbbytecode",
@ -229,7 +229,7 @@ dependencies = [
[[package]]
name = "hbvm"
version = "0.1.0"
source = "git+https://git.ablecorp.us/AbleOS/holey-bytes.git#784d552c1dee2a3cfde4b83e01523d91988bb554"
source = "git+https://git.ablecorp.us/AbleOS/holey-bytes.git#a3355a59c0727e58519a94a8f65013beb9c2331b"
dependencies = [
"hbbytecode",
]

View file

@ -5,18 +5,48 @@ This style guide has two modes that a guideline may be.
`loose` means that a pr would be accepted but should later be fixed.
## Empty Functions | loose
Empty functions are typically a sign of an unfinished program or driver.
In cases where there is a clear reason to have an empty function it will be allowed.
For example FakeAlloc is only empty functions because it is a example of an the allocator api.
### Allowed
```rust
/// in example.hb
a := fn(): void {}
```
### Not Allowed
```rust
/// in fat32.hb
a := fn(): void {}
```
## Magic Functions | loose
'Magic functions' are what I am calling small helper functions that do one or two things.
### Example
```rust
a := null
magic_a := fn(){
a = 10
}
```
The exact policy I want to have here is a bit fuzzy. I think that functions like this are nice in certain situations and not in others.
Regardless of if you use them or not, put a comment above the function explaining rational.
## Magic Numbers | loose
The policy on magic numbers is make them const and have a comment above them. Typically linking to a source of information about the magic number.
This helps cut down on magic numbers while making acceptable names and atleast half assed documentation.
This helps cut down on magic numbers while making acceptable names and atleast half assed documentation.
Constants are inlined anyways, so its the same thing in the binary.
```rust
// The standard vga port is mapped at 0xB8000
$VGA_PTR := 0xB8000
```
## Tabs Vs Spaces | loose
## Tabs Vs Spaces | strict
I prefer for hblang code to use hard tabs.
The rational behind this is that a tab is `1 Indent` which some developers might want to be various different sizes when displayed

View file

@ -1,28 +1,85 @@
extern crate proc_macro;
extern crate quote;
extern crate syn;
use {
proc_macro::TokenStream,
quote::quote,
syn::{parse_macro_input, ItemFn}
syn::{parse::Parse, parse_macro_input, Expr, ItemFn, Token}
};
struct KtestInput {
lhs: Expr,
_comma: Token![,],
rhs: Expr,
}
impl Parse for KtestInput {
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
Ok(Self {
lhs: input.parse()?,
_comma: input.parse()?,
rhs: input.parse()?,
})
}
}
#[proc_macro]
pub fn ktest_eq(item: TokenStream) -> TokenStream {
let input = parse_macro_input!(item as KtestInput);
let lhs = input.lhs;
let rhs = input.rhs;
let out = quote! {
if #lhs != #rhs {
return Err(name);
}
};
TokenStream::from(out)
}
#[proc_macro]
pub fn ktest_neq(item: TokenStream) -> TokenStream {
let input = parse_macro_input!(item as KtestInput);
let lhs = input.lhs;
let rhs = input.rhs;
let out = quote! {
if #lhs == #rhs {
return Err(name);
}
};
TokenStream::from(out)
}
#[proc_macro_attribute]
pub fn ktest(_attr: TokenStream, item: TokenStream) -> TokenStream {
let input = parse_macro_input!(item as ItemFn);
let test_name = &input.sig.ident;
let test_string = test_name.to_string();
let static_var_name = syn::Ident::new(
&format!("__ktest_{}", test_name),
&format!("__ktest_{}", test_name).to_uppercase(),
test_name.span(),
);
let out = quote! {
// #[cfg(feature = "ktest")]
#input
// #[cfg(feature = "ktest")]
let block = &input.block;
let out = quote! {
#[cfg(feature = "ktest")]
fn #test_name() -> Result<String, String> {
use crate::alloc::string::ToString;
let name = #test_string.to_string();
#block
return Ok(name);
}
#[cfg(feature = "ktest")]
#[unsafe(link_section = ".note.ktest")]
#[used]
pub static #static_var_name: fn() = #test_name;
pub static #static_var_name: fn() -> Result<String, String> = #test_name;
};
TokenStream::from(out)

View file

@ -6,6 +6,11 @@ SECTIONS
.text.boot : { *(.text.boot) }
.text : { *(.text) }
.data : { *(.data) }
.note.ktest : {
__ktest_start = .;
*(.note.ktest)
__ktest_end = .;
}
.rodata : { *(.rodata) }
.bss : {
*(COMMON)

View file

@ -62,7 +62,7 @@ extern "x86-interrupt" fn page_fault(
}
extern "x86-interrupt" fn timer(_isf: InterruptStackFrame) {
// interrupt(Interrupt::Timer);
interrupt(Interrupt::Timer);
unsafe {
LAPIC.end_of_interrupt();
@ -85,6 +85,7 @@ extern "x86-interrupt" fn spurious(_: InterruptStackFrame) {
fn interrupt(interrupt_type: Interrupt) {
use crate::arch::INTERRUPT_LIST;
use crate::kmain::EXECUTOR;
let il = INTERRUPT_LIST.lock();
let val = il.list.get(&interrupt_type).unwrap();
@ -107,4 +108,8 @@ fn interrupt(interrupt_type: Interrupt) {
// log::info!("{}", buffer);
}
unsafe{
EXECUTOR.send_interrupt(interrupt_type as u8);
}
}

View file

@ -33,7 +33,7 @@ unsafe fn x86_in<T: x86_64::instructions::port::PortRead>(address: u16) -> T {
}
#[inline(always)]
pub fn handler(vm: &mut Vm) {
pub fn handler(vm: &mut Vm, pid: &usize) {
let ecall_number = vm.registers[2].cast::<u64>();
match ecall_number {
@ -209,7 +209,6 @@ pub fn handler(vm: &mut Vm) {
let buffer_id = vm.registers[3].cast::<u64>();
let map_ptr = vm.registers[4].cast::<u64>();
let max_length = vm.registers[5].cast::<u64>();
let mut buffs = IPC_BUFFERS.lock();
let buff: &mut IpcBuffer = match buffs.get_mut(&buffer_id) {
Some(buff) => buff,
@ -243,6 +242,18 @@ pub fn handler(vm: &mut Vm) {
vm.registers[3] = x
}
}
6 => {
// Wait till interrupt
use crate::kmain::EXECUTOR;
let interrupt_type = vm.registers[3].cast::<u8>();
info!("Interrupt subscribled: {}", interrupt_type);
unsafe {
EXECUTOR.pause(pid.clone());
LazyCell::<Executor>::get_mut(&mut EXECUTOR)
.unwrap()
.interrupt_subscribe(pid.clone(), interrupt_type);
}
}
_ => {
log::error!("Syscall unknown {:?}{:?}", ecall_number, vm.registers);
}

View file

@ -65,7 +65,12 @@ impl<'p> Future for ExecThread {
return Poll::Ready(Err(err));
}
Ok(VmRunOk::End) => return Poll::Ready(Ok(())),
Ok(VmRunOk::Ecall) => ecah::handler(&mut self.vm),
Ok(VmRunOk::Ecall) => ecah::handler(
&mut self.vm,
cx.ext()
.downcast_ref()
.expect("PID did not exist in Context"),
),
Ok(VmRunOk::Timer) => (),
Ok(VmRunOk::Breakpoint) => {
log::error!(

View file

@ -24,8 +24,11 @@ pub fn kmain(_cmdline: &str, boot_modules: BootModules) -> ! {
#[cfg(feature = "ktest")]
{
use crate::ktest;
debug!("TESTING");
use {
crate::ktest,
log::info,
};
info!("Running tests");
ktest::test_main();
loop {}
@ -76,6 +79,7 @@ pub fn kmain(_cmdline: &str, boot_modules: BootModules) -> ! {
"Graphics front ptr {:?}",
fb1.address.as_ptr().unwrap() as *const u8
);
log::info!("Started AbleOS");
unsafe {
let executor = LazyCell::<Executor>::force_mut(&mut EXECUTOR);
@ -121,7 +125,7 @@ pub fn kmain(_cmdline: &str, boot_modules: BootModules) -> ! {
if cmd_len > 0 {
thr.set_arguments(cmd.as_ptr() as u64, cmd_len);
}
executor.spawn(Box::pin(async move {
executor.spawn(Box::pin(async {
if let Err(e) = thr.await {
log::error!("{e:?}");
}
@ -132,7 +136,6 @@ pub fn kmain(_cmdline: &str, boot_modules: BootModules) -> ! {
executor.run();
};
log::info!("Started AbleOS");
crate::arch::spin_loop()
}

View file

@ -1,38 +1,51 @@
pub use ktest_macro::ktest;
use log::debug;
pub use ktest_macro::*;
use {
alloc::string::String,
log::{error, info},
};
extern "C" {
static __ktest_start: fn();
static __ktest_end: fn();
static __ktest_start: fn() -> Result<String, String>;
static __ktest_end: fn() -> Result<String, String>;
}
// TODO: Get test_fn linker name (may require no_mangle in macro)
// More info on tests (run the rest even if panic)
// Implement ktest for arm and riscv (Later problems, see below)
// TODO: Implement ktest for arm and riscv (Later problems, see below)
// Allow for arch specific tests (Leave for now)
// Allow for ktest test name attr
// Usefull message at the end of testing
// Should panic tests
// Test specific panic handler
pub fn test_main() {
unsafe {
let mut current_test = &__ktest_start as *const fn();
let mut current = 1;
let test_end = &__ktest_end as *const fn();
let mut current_test = &__ktest_start as *const fn() -> Result<String, String>;
let test_end = &__ktest_end as *const fn() -> Result<String, String>;
let mut pass = 0;
let mut fail = 0;
while current_test < test_end {
let test_fn = *current_test;
debug!("Running test {}", current);
test_fn();
debug!("Test {} passed", current);
let test_name = test_fn();
match test_name {
Ok(name) => {
info!("Test: {} passed", name);
pass += 1;
},
Err(name) => {
error!("Test: {} failed", name);
fail += 1;
}
}
current_test = current_test.add(1);
current += 1;
}
info!("{}/{} tests passed", pass, pass + fail);
}
}
#[ktest]
pub fn trivial_assertion() {
assert_eq!(1, 1);
}
ktest_eq!(1, 1);
ktest_neq!(0, 1);
}

View file

@ -10,9 +10,11 @@
abi_x86_interrupt,
lazy_get,
alloc_error_handler,
local_waker,
context_ext,
ptr_sub_ptr,
naked_functions,
pointer_is_aligned_to,
pointer_is_aligned_to
)]
#![allow(dead_code, internal_features, static_mut_refs)]
extern crate alloc;
@ -32,10 +34,9 @@ mod memory;
mod task;
mod utils;
// #[cfg(feature = "tests")]
#[allow(improper_ctypes, non_upper_case_globals)]
mod ktest;
use alloc::string::ToString;
use versioning::Version;
/// Kernel's version
@ -48,6 +49,7 @@ pub const VERSION: Version = Version {
#[panic_handler]
#[cfg(target_os = "none")]
fn panic(info: &core::panic::PanicInfo) -> ! {
use alloc::string::ToString;
arch::register_dump();
if let Some(loc) = info.location() {

View file

@ -3,7 +3,8 @@ use {
core::{
future::Future,
pin::Pin,
task::{Context, Poll, RawWaker, RawWakerVTable, Waker},
sync::atomic::{AtomicBool, Ordering},
task::{Context, ContextBuilder, Poll, RawWaker, RawWakerVTable, Waker},
},
crossbeam_queue::SegQueue,
slab::Slab,
@ -14,7 +15,6 @@ pub fn yield_now() -> impl Future<Output = ()> {
impl Future for YieldNow {
type Output = ();
#[inline(always)]
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
if self.0 {
Poll::Ready(())
@ -29,150 +29,164 @@ pub fn yield_now() -> impl Future<Output = ()> {
YieldNow(false)
}
pub trait Process: Future<Output = ()> + Send {}
impl<T: Future<Output = ()> + Send> Process for T {}
pub struct Executor {
tasks: Slab<Task>,
task_queue: Arc<TaskQueue>,
task_queue: Arc<SegQueue<usize>>,
interrupt_lookup: [Option<usize>; u8::MAX as usize],
}
impl Executor {
pub fn new() -> Self {
Self {
tasks: Slab::new(),
task_queue: Arc::new(TaskQueue::new()),
task_queue: Arc::new(SegQueue::new()),
interrupt_lookup: [None; u8::MAX as usize],
}
}
#[inline]
pub fn spawn(&mut self, future: Pin<Box<dyn Future<Output = ()> + Send>>) -> usize {
pub fn spawn(&mut self, future: Pin<Box<dyn Process>>) -> usize {
let id = self.tasks.insert(Task::new(future));
self.task_queue.queue.push(id);
self.task_queue.push(id);
id
}
pub fn pause(&self, id: usize) {
if let Some(task) = self.tasks.get(id) {
task.set_paused(true);
}
}
pub fn unpause(&self, id: usize) {
if let Some(task) = self.tasks.get(id) {
task.set_paused(false);
self.task_queue.push(id);
}
}
pub fn interrupt_subscribe(&mut self, pid : usize, interrupt_type: u8){
self.interrupt_lookup[interrupt_type as usize] = Some(pid);
}
pub fn run(&mut self) {
let mut task_batch = [0; 32];
let mut batch_len = 0;
loop {
self.task_queue.batch_pop(&mut task_batch, &mut batch_len);
let mut batch_len = 0;
if batch_len == 0 {
if self.task_queue.is_empty() {
while let Some(id) = self.task_queue.pop() {
task_batch[batch_len] = id;
batch_len += 1;
if batch_len == task_batch.len() {
break;
} else {
continue;
}
}
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)));
if batch_len == 0 {
//break;
continue;
}
let waker = unsafe { Waker::from_raw(TaskWaker::into_raw_waker(waker)) };
let mut cx = Context::from_waker(&waker);
for &(mut id) in &task_batch[..batch_len] {
if let Some(task) = self.tasks.get_mut(id) {
if task.is_paused() {
continue;
}
let waker = create_waker(id, Arc::clone(&self.task_queue));
let mut cx = ContextBuilder::from_waker(&waker).ext(&mut id).build();
if let Poll::Ready(()) = task.poll(&mut cx) {
self.tasks.remove(id);
self.task_queue.free_tasks.push(id);
self.interrupt_lookup.map(|pid|{
if let Some(pid) = pid{
if pid == id {
return None;
}
}
return pid;
});
}
}
}
}
}
pub fn send_interrupt(&self, interrupt : u8){
let id = self.interrupt_lookup[interrupt as usize];
if let Some(id) = id{
self.unpause(id);
}
}
}
struct Task {
future: Pin<Box<dyn Future<Output = ()> + Send>>,
waker: Option<TaskWaker>,
future: Pin<Box<dyn Process>>,
paused: AtomicBool,
}
impl Task {
#[inline(always)]
pub fn new(future: Pin<Box<dyn Future<Output = ()> + Send>>) -> Self {
fn new(future: Pin<Box<dyn Process>>) -> Self {
Self {
future,
waker: None,
paused: AtomicBool::new(false),
}
}
#[inline(always)]
fn poll(&mut self, cx: &mut Context) -> Poll<()> {
self.future.as_mut().poll(cx)
}
fn is_paused(&self) -> bool {
self.paused.load(Ordering::Acquire)
}
fn set_paused(&self, paused: bool) {
self.paused.store(paused, Ordering::Release)
}
}
fn create_waker(task_id: usize, task_queue: Arc<SegQueue<usize>>) -> Waker {
let data = Box::new(TaskWaker {
task_id,
task_queue,
});
let raw_waker = RawWaker::new(Box::into_raw(data) as *const (), &VTABLE);
unsafe { Waker::from_raw(raw_waker) }
}
#[derive(Clone)]
struct TaskWaker {
id: usize,
task_queue: Arc<TaskQueue>,
task_id: usize,
task_queue: Arc<SegQueue<usize>>,
}
impl TaskWaker {
#[inline(always)]
fn new(id: usize, task_queue: Arc<TaskQueue>) -> Self {
Self { id, task_queue }
}
#[inline(always)]
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)
self.task_queue.push(self.task_id);
}
}
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)
let task_waker = Box::from_raw(ptr as *mut TaskWaker);
let raw_waker = RawWaker::new(Box::into_raw(task_waker.clone()) as *const (), &VTABLE);
raw_waker
}
unsafe fn wake_raw(ptr: *const ()) {
let waker = &*(ptr as *const TaskWaker);
waker.wake();
let task_waker = Box::from_raw(ptr as *mut TaskWaker);
task_waker.wake();
}
unsafe fn wake_by_ref_raw(ptr: *const ()) {
let waker = &*(ptr as *const TaskWaker);
waker.wake();
let task_waker = &*(ptr as *const TaskWaker);
task_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()
}
unsafe fn drop_raw(ptr: *const ()) {
drop(Box::from_raw(ptr as *mut TaskWaker));
}

View file

@ -460,6 +460,10 @@ fn run(release: bool, target: Target, do_accel: bool) -> Result<(), Error> {
// "-serial", "stdio",
"-m", "2G",
"-smp", "1",
"-audiodev",
"pa,id=speaker",
"-machine",
"pcspk-audiodev=speaker",
"-parallel", "none",
"-monitor", "none",
"-machine", accel,

View file

@ -26,12 +26,6 @@ create_window := fn(channel: int): ^render.Surface {
if windowing_system_buffer == 0 {
return @as(^render.Surface, idk)
} else {
// ! bad able, stop using string messages :ragey:
// msg := "\{01}\0"
// msg_length := 2
// @as(void, @eca(3, windowing_system_buffer, msg, msg_length))
x := 0
loop if x > 1000 break else x += 1

View file

@ -14,14 +14,27 @@ Label := struct {
text_length: uint,
bg: Color,
fg: Color,
}
set_label_text := fn(label: Label, text: ^u8): void {
text_length := string.length(text)
new_label := fn(text: ^u8): Self {
text_surface := render.new_surface(1024, 20)
text_length := string.length(text)
label := Self.(3, true, text_surface, text, text_length, render.black, render.white)
return label
}
label.is_dirty = true
label.text = text
label.text_length = text_length
set_label_text := fn(self: Self, text: ^u8): void {
text_length := string.length(text)
self.is_dirty = true
self.text = text
self.text_length = text_length
}
$set_color := fn(self: Self, bg: Color, fg: Color): void {
self.bg = bg
self.fg = fg
self.is_dirty = true
}
}
render_label_to_surface := fn(surface: Surface, label: Label, font: Font, pos: Vec2(uint)): void {
@ -30,17 +43,4 @@ render_label_to_surface := fn(surface: Surface, label: Label, font: Font, pos: V
render.put_text(label.surface, font, .(0, 0), label.fg, label.text)
}
render.put_surface(surface, label.surface, pos, false)
}
new_label := fn(text: ^u8): Label {
text_surface := render.new_surface(1024, 20)
text_length := string.length(text)
label := Label.(3, true, text_surface, text, text_length, render.black, render.white)
return label
}
$set_color := fn(label: Label, bg: Color, fg: Color): void {
label.bg = bg
label.fg = fg
label.is_dirty = true
}

View file

@ -1,4 +1,4 @@
.{log, panic} := @use("../lib.hb")
.{log, panic, memory} := @use("../lib.hb")
alloc_return := @use("alloc_return.hb")
/* the block size is 64 bytes, 64 blocks of 64 bytes.
@ -10,29 +10,40 @@ BlockAlloc := struct {
ptr: ?^u8,
$init := fn(): Self {
return .(0, null)
alloc_page_ptr := memory.request_page(1)
state := 0xFFFFFFFFFFFFFFFF
return .(state, alloc_page_ptr)
}
alloc := fn(self: Self, alloc_type: type, count: uint): alloc_return.AllocReturn {
offset := 1
a := 1
offset := 0
state_2 := 0
loop {
// a = self.state >> offset
// check if the `offset` bit is 1, if it is move to the next offset
if a == 1 {
offset += 1
log.info("Already Allocated\0")
xyz := self.state & 1
abc := if xyz == 1 {
true
} else {
// self it to 1 and return the ptr to the allocation
self.state |= a
// return ptr + offset * 64
if self.ptr != null {
return .(64, self.ptr + offset * 64)
} else {
// panic.panic("Allocator is not inited.\0")
// return .(0, null)
}
false
}
// check if the `offset` bit is 1, if it is move to the next offset
if abc {
offset += 1
return .(0, null)
} else {
log.info("Already Allocated\0")
}
// else {
// // self it to 1 and return the ptr to the allocation
// self.state |= a
// // return ptr + offset * 64
// if self.ptr != null {
// return .(64, self.ptr + offset * 64)
// } else {
// // panic.panic("Allocator is not inited.\0")
// // return .(0, null)
// }
// }
// there are only 64 blocks
if offset >= 64 {
return .(0, null)

View file

@ -0,0 +1,189 @@
/*
* This code is an implementation of the FoldHash algorithm from https://github.com/orlp/foldhash,
* originally written by Orson Peters under the zlib license.
*
* Changes to the original code were made to meet the simplicity requirements of this implementation.
* Behaviour aims to be equivalent but not identical to the original code.
*
* Copyright (c) 2024 Orson Peters
*
* This software is provided 'as-is', without any express or implied warranty. In
* no event will the authors be held liable for any damages arising from the use of
* this software.
*
* Permission is granted to anyone to use this software for any purpose, including
* commercial applications, and to alter it and redistribute it freely, subject to
* the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not claim
* that you wrote the original software. If you use this software in a product,
* an acknowledgment in the product documentation would be appreciated but is
* not required.
*
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source distribution.
*/;
.{math, random} := @use("../lib.hb")
$ARBITRARY0 := 0x243F6A8885A308D3
$ARBITRARY1 := 0x13198A2E03707344
$ARBITRARY2 := 0xA4093822299F31D0
$ARBITRARY3 := 0x82EFA98EC4E6C89
$ARBITRARY4 := 0x452821E638D01377
$ARBITRARY5 := 0xBE5466CF34E90C6C
$ARBITRARY6 := 0xC0AC29B7C97C50DD
$ARBITRARY7 := 0x3F84D5B5B5470917
$ARBITRARY8 := 0x9216D5D98979FB1B
$ARBITRARY9 := 0xD1310BA698DFB5AC
$FIXED_GLOBAL_SEED := [uint].(ARBITRARY4, ARBITRARY5, ARBITRARY6, ARBITRARY7)
global_seed := 0
u128 := packed struct {a: uint, b: uint}
$folded_multiply := fn(x: uint, y: uint): uint {
lx := @as(u32, @intcast(x))
ly := @as(u32, @intcast(y))
hx := x >> 32
hy := y >> 32
afull := lx * hy
bfull := hx * ly
return afull ^ (bfull << 32 | bfull >> 32)
}
hash_bytes_medium := fn(bytes: ^u8, len: uint, s0: uint, s1: uint, fold_seed: uint): uint {
lo := bytes
end := bytes + len
hi := end - 16
loop if lo >= hi break else {
a := *@as(^uint, @bitcast(lo))
b := *@as(^uint, @bitcast(lo + 8))
c := *@as(^uint, @bitcast(hi))
d := *@as(^uint, @bitcast(hi + 8))
s0 = folded_multiply(a ^ s0, c ^ fold_seed)
s1 = folded_multiply(b ^ s1, d ^ fold_seed)
hi -= 16
lo += 16
}
return s0 ^ s1
}
hash_bytes_long := fn(bytes: ^u8, len: uint, s0: uint, s1: uint, s2: uint, s3: uint, fold_seed: uint): uint {
$chunk_size := 64
chunks := len / chunk_size
remainder := len % chunk_size
ptr := bytes
i := 0
loop if i >= chunks break else {
a := *@as(^uint, @bitcast(ptr))
b := *@as(^uint, @bitcast(ptr + 8))
c := *@as(^uint, @bitcast(ptr + 16))
d := *@as(^uint, @bitcast(ptr + 24))
e := *@as(^uint, @bitcast(ptr + 32))
f := *@as(^uint, @bitcast(ptr + 40))
g := *@as(^uint, @bitcast(ptr + 48))
h := *@as(^uint, @bitcast(ptr + 56))
s0 = folded_multiply(a ^ s0, e ^ fold_seed)
s1 = folded_multiply(b ^ s1, f ^ fold_seed)
s2 = folded_multiply(c ^ s2, g ^ fold_seed)
s3 = folded_multiply(d ^ s3, h ^ fold_seed)
ptr += chunk_size
i += 1
}
s0 ^= s2
s1 ^= s3
if remainder > 0 {
remainder_start := bytes + len - math.max(uint, remainder, 16)
return hash_bytes_medium(remainder_start, math.max(uint, remainder, 16), s0, s1, fold_seed)
}
return s0 ^ s1
}
FoldHasher := struct {
accumulator: uint,
original_seed: uint,
sponge: u128,
sponge_len: u8,
fold_seed: uint,
expand_seed: uint,
expand_seed2: uint,
expand_seed3: uint,
$new := fn(seed: uint): Self {
return .(
seed,
seed,
.(0, 0),
0,
FIXED_GLOBAL_SEED[0],
FIXED_GLOBAL_SEED[1],
FIXED_GLOBAL_SEED[2],
FIXED_GLOBAL_SEED[3],
)
}
default := fn(): Self {
if global_seed == 0 {
// ! consider this "secure enough" for now
global_seed = random.any(uint)
}
return Self.new(global_seed)
}
write := fn(self: ^Self, bytes: ^u8, len: uint): void {
s0 := self.accumulator
s1 := self.expand_seed
if len <= 16 {
if len >= 8 {
s0 ^= *@bitcast(bytes)
s1 ^= *@bitcast(bytes + len - 8)
} else if len >= 4 {
s0 ^= *@as(^u32, @bitcast(bytes))
s1 ^= *@as(^u32, @bitcast(bytes + len - 4))
} else if len > 0 {
lo := *bytes
mid := *(bytes + len / 2)
hi := *(bytes + len - 1)
s0 ^= lo
s1 ^= @as(uint, hi) << 8 | mid
}
self.accumulator = folded_multiply(s0, s1)
} else if len < 256 {
self.accumulator = hash_bytes_medium(bytes, len, s0, s1, self.fold_seed)
} else {
self.accumulator = hash_bytes_long(
bytes,
len,
s0,
s1,
self.expand_seed2,
self.expand_seed3,
self.fold_seed,
)
}
}
finish := fn(self: ^Self): uint {
if self.sponge_len > 0 {
return folded_multiply(self.sponge.b ^ self.accumulator, self.sponge.a ^ self.fold_seed)
} else {
return self.accumulator
}
}
reset := fn(self: ^Self): void {
self.accumulator = self.original_seed
self.sponge = .(0, 0)
self.sponge_len = 0
}
}

View file

@ -0,0 +1,2 @@
//! NON CRYPTOGRAPHIC HASHER
foldhash := @use("foldhash.hb")

View file

@ -1,5 +1,6 @@
acs := @use("acs.hb")
allocators := @use("alloc/lib.hb")
hashers := @use("hash/lib.hb")
string := @use("string.hb")
log := @use("log.hb")
memory := @use("memory.hb")

View file

@ -3,4 +3,5 @@ subscribe_to_interrupt := fn(interrupt_number: u8): bool {
}
// Pauses execution until the interrupt occures
sleep_until_interrupt := fn(interrupt_number: u8): void {
@eca(6, interrupt_number)
}

View file

@ -15,14 +15,16 @@ main := fn(): void {
// alloc.deinit()
balloc := allocators.BlockAlloc.init()
// defer {
// balloc.deinit()
// }
bstruct := balloc.alloc(AStruct, 2)
if bstruct.ptr == null {
log.info("Hi\0")
// panic.panic("BlockAlloc actually didn't allocate.")
} else {
log.info("Allocator functioned.\0")
}
// if bstruct.ptr == null {
// log.info("Hi\0")
// // panic.panic("BlockAlloc actually didn't allocate.")
// } else {
// log.info("Allocator functioned.\0")
// }
// balloc.dealloc(bstruct_ptr, AStruct, 2)
// balloc.deinit()
return
}

View file

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

View file

@ -0,0 +1,31 @@
.{hashers, log, memory, string} := @use("../../../libraries/stn/src/lib.hb")
main := fn(): void {
buffer := memory.request_page(1)
target := "abcdefghijklmnop\0"
strings := [^u8].("abcdefshijklmnop\0", "abcdefghijklnnop\0", "abcdefshijklmnop\0", "abcdefghijklmnop\0", "abcdefghijflmnop\0", "dbcdefghijklmnop\0", "abcdefghijklmnop\0")
len := @sizeof(@TypeOf(strings)) / @sizeof(^u8)
strlen := string.length(target)
// hasher := hashers.foldhash.FoldHasher.new(1)
hasher := hashers.foldhash.FoldHasher.default()
hasher.write(target, strlen)
correct := hasher.finish()
log.warn("target:\0")
log.warn(target)
i := 0
loop if i == len break else {
defer i += 1
hasher.reset()
hasher.write(strings[i], strlen)
d := hasher.finish()
if d == correct {
log.warn("match found\0")
}
log.info(strings[i])
log.debug(string.display_int(@bitcast(d), buffer, 16))
string.clear(buffer)
}
}

View file

@ -0,0 +1 @@
# pcspkr

View file

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

View file

@ -0,0 +1,45 @@
stn := @use("../../../libraries/stn/src/lib.hb");
.{memory, buffer, log, string, math} := stn;
.{inb, outb} := memory
$PIT_CLOCK := 1193180
play_sound := fn(frequency: u32): void {
div := 0
div = PIT_CLOCK / frequency
memory.outb(0x43, 0xB6)
memory.outb(0x42, @intcast(div))
memory.outb(0x42, @intcast(div >> 8))
tmp := inb(0x61)
if tmp != (tmp | 3) {
outb(0x61, tmp | 3)
}
}
no_sound := fn(): void {
tmp := memory.inb(0x61) & 0xFC
memory.outb(0x61, tmp)
}
beep := fn(): void {
play_sound(1000)
idx := 0
loop {
if idx >= 1000000 {
idx += 1
} else {
break
}
}
no_sound()
}
main := fn(): int {
no_sound()
beep()
return 0
}

View file

@ -0,0 +1,4 @@
# sdoom
SDoom stands for simple doom.
This is not a full implementation of doom and is instead a doom style renderer.

View file

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

View file

@ -0,0 +1,53 @@
sunset := @use("../../../libraries/sunset_proto/src/lib.hb")
render := @use("../../../libraries/render/src/lib.hb")
stn := @use("../../../libraries/stn/src/lib.hb");
.{log} := stn;
.{Vec2} := stn.math
Player := struct {
x: i8,
y: i8,
$new := fn(x: i8, y: i8): Self {
return Self.(x, y)
}
}
GameState := struct {
player: Player,
$new := fn(): Self {
p := Player.new(0, 0)
return Self.(p)
}
}
main := fn(): void {
sunset.client.find_server()
window := sunset.client.new(.(.(600, 400), .(200, 200), "SDoom\0"))
if window == null {
log.error("got no window\0")
return
}
game_state := GameState.new()
loop {
render.clear(window.surface, render.black)
width := 100
idx := 1
loop {
if idx >= width {
break
}
render.put_vline(window.surface, idx, 10, 100, render.white)
idx += 1
}
_ = sunset.client.send_frame(window)
}
}

View file

View file

@ -13,7 +13,7 @@ main := fn(): void {
return
}
window := sunset.client.new(.(.(400, 300), .(400, 240), "Sunset!\0"))
window := sunset.client.new(.(.(400, 100), .(400, 240), "Sunset!\0"))
if window == null {
log.error("got no window\0")

View file

@ -3,7 +3,7 @@ render := @use("../../../libraries/render/src/lib.hb")
intouch := @use("../../../libraries/intouch/src/lib.hb")
horizon_api := @use("../../../libraries/horizon_api/src/lib.hb");
.{new_label, render_label_to_surface, set_label_text, set_color} := horizon_api.widgets.label
.{set_color, render_label_to_surface, Label} := horizon_api.widgets.label
stn := @use("../../../libraries/stn/src/lib.hb");
.{Vec2} := stn.math
@ -13,6 +13,9 @@ img := @embed("../../../assets/wallpaper.qoi")
main := fn(): int {
sunset.server.start()
defer {
stn.log.info("Sunset Server Exit\0")
}
screen := render.init(true)
render.clear(screen, render.black)
@ -28,8 +31,8 @@ main := fn(): int {
mouse_x := 100
mouse_y := 100
text_label := new_label("Hi\0")
set_color(text_label, sunset.server.DECO_COLOUR, render.black)
text_label := Label.new_label("Hi\0")
text_label.set_color(sunset.server.DECO_COLOUR, render.black)
loop {
mouse_event := intouch.recieve_mouse_event()
@ -59,13 +62,13 @@ main := fn(): int {
}
if mouse_event.left {
set_label_text(text_label, "LEFT CLICK\0")
text_label.set_label_text("LEFT CLICK\0")
}
if mouse_event.middle {
set_label_text(text_label, "MIDDLE CLICK\0")
text_label.set_label_text("MIDDLE CLICK\0")
}
if mouse_event.right {
set_label_text(text_label, "RIGHT CLICK\0")
text_label.set_label_text("RIGHT CLICK\0")
}
}
{

View file

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

View file

@ -0,0 +1,8 @@
sleep := @use("../../../libraries/stn/src/sleep.hb")
log := @use("../../../libraries/stn/src/log.hb")
main := fn(): void {
log.info("BEFORE\0")
sleep.sleep_until_interrupt(32)
log.info("AFTER\0")
}

View file

@ -28,23 +28,32 @@ resolution = "1024x768x24"