forked from AbleOS/ableos
Compare commits
102 commits
devcontain
...
master
Author | SHA1 | Date | |
---|---|---|---|
Able | 6b673bc7e6 | ||
koniifer | 0af4d142a4 | ||
koniifer | 36f0d357cf | ||
koniifer | ccddf36050 | ||
koniifer | da5f1a7a19 | ||
koniifer | 2808bc9e7c | ||
koniifer | d958a103fa | ||
koniifer | ee82bc5705 | ||
Able | 3d53b641bf | ||
koniifer | cea7f1fa5c | ||
Able | 614bef7ec5 | ||
Able | b0f6aa53bd | ||
Able | d5f4ce18a3 | ||
koniifer | 907c0d0dd4 | ||
koniifer | 95b4a921dc | ||
koniifer | b6261d014d | ||
Able | 56ee0fe851 | ||
koniifer | b07bac1f1f | ||
koniifer | dc9273b3c1 | ||
Able | e6d8f5c822 | ||
koniifer | 8ad7542b9c | ||
Able | e40a22fccd | ||
koniifer | cf917927a5 | ||
koniifer | 97ceb12d6e | ||
koniifer | bae58ade61 | ||
koniifer | b21c05e924 | ||
Able | 2f5bc73665 | ||
Able | 0003464099 | ||
koniifer | 77a708d41e | ||
peony | 3409f5051a | ||
Able | 8c7b95277d | ||
koniifer | 7da32b263f | ||
Able | 2439722c88 | ||
koniifer | 3333b1706f | ||
Able | 8808ed5bfe | ||
koniifer | 68d3236cc0 | ||
Able | eea23d967b | ||
Able | d2152537ad | ||
Able | 7723799e76 | ||
koniifer | 8b04b275f3 | ||
Able | 1345f294b8 | ||
Able | 818bcb458f | ||
Able | d2b5f09511 | ||
2676bd7b62 | |||
koniifer | 444fcdb0c4 | ||
koniifer | adbf32d970 | ||
Able | 7f01b0e0f8 | ||
Able | e8edee4ccc | ||
koniifer | ba59233ce7 | ||
Able | f13c682171 | ||
Able | b6b097a872 | ||
koniifer | 6a8d92d2c2 | ||
Able | ab8522fbe1 | ||
Able | a49ac7bca0 | ||
Able | 12883ac926 | ||
Able | 6a319c55b0 | ||
Able | 879bbfa173 | ||
Able | 795f10986f | ||
Able | 85e63eb51c | ||
koniifer | aafe047b51 | ||
koniifer | 404ea22c46 | ||
koniifer | 664334fd00 | ||
Able | 086948d47a | ||
Able | b795215b62 | ||
Able | 16135ae536 | ||
Able | 941eed0ac9 | ||
Able | f4ad4b6856 | ||
koniifer | 9e83707a28 | ||
Able | 6894ef2360 | ||
Able | 69c95c35b5 | ||
Able | 80d363bc59 | ||
Able | 3c3c156eb0 | ||
koniifer | eaace7d9c1 | ||
koniifer | 5af5631755 | ||
Able | fac573837f | ||
koniifer | 6ff65eee41 | ||
koniifer | b35b430047 | ||
koniifer | bcfaf89ed0 | ||
koniifer | 2ba2dcb464 | ||
koniifer | 41d9c0b82a | ||
koniifer | a94332370a | ||
koniifer | 7caa47b9fb | ||
Able | 34101d2e8c | ||
Able | 2bc13cd7d8 | ||
koniifer | 086cc4aef0 | ||
Able | 84f86488c7 | ||
Able | ed7c8f20cb | ||
koniifer | 34cbd9a5e6 | ||
koniifer | 0ebb1f200e | ||
Able | fc06820332 | ||
koniifer | 2a082d8283 | ||
koniifer | 1eee33ce8b | ||
Able | 6fa1c829fd | ||
koniifer | 820c3e459b | ||
koniifer | 3af28f1666 | ||
koniifer | 96c2bd5cd5 | ||
koniifer | ea8eca1089 | ||
koniifer | 7f4a040505 | ||
koniifer | 82f5cdbe21 | ||
koniifer | aac6d61dc6 | ||
koniifer | 3df6f18c85 | ||
koniifer | 07ee8de9f1 |
|
@ -1,3 +1,3 @@
|
|||
[alias]
|
||||
repbuild = "run --manifest-path ./repbuild/Cargo.toml -r --"
|
||||
repbuild = "run --manifest-path ./repbuild/Cargo.toml -- "
|
||||
dev = "run --manifest-path ./dev/Cargo.toml -r --"
|
||||
|
|
|
@ -1,31 +0,0 @@
|
|||
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
|
||||
// README at: https://github.com/devcontainers/templates/tree/main/src/rust
|
||||
{
|
||||
"name": "Rust",
|
||||
// Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
|
||||
"image": "mcr.microsoft.com/devcontainers/rust:1-1-bullseye"
|
||||
|
||||
// Use 'mounts' to make the cargo cache persistent in a Docker Volume.
|
||||
// "mounts": [
|
||||
// {
|
||||
// "source": "devcontainer-cargo-cache-${devcontainerId}",
|
||||
// "target": "/usr/local/cargo",
|
||||
// "type": "volume"
|
||||
// }
|
||||
// ]
|
||||
|
||||
// Features to add to the dev container. More info: https://containers.dev/features.
|
||||
// "features": {},
|
||||
|
||||
// Use 'forwardPorts' to make a list of ports inside the container available locally.
|
||||
// "forwardPorts": [],
|
||||
|
||||
// Use 'postCreateCommand' to run commands after the container is created.
|
||||
// "postCreateCommand": "rustc --version",
|
||||
|
||||
// Configure tool-specific properties.
|
||||
// "customizations": {},
|
||||
|
||||
// Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
|
||||
// "remoteUser": "root"
|
||||
}
|
1190
Cargo.lock
generated
1190
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
69
HELP.md
Normal file
69
HELP.md
Normal file
|
@ -0,0 +1,69 @@
|
|||
### What are the requirements?
|
||||
- A machine with [Rustc Tier 1 platform support](https://doc.rust-lang.org/nightly/rustc/platform-support.html#tier-1-with-host-tools)
|
||||
- Rustup
|
||||
- QEMU (for executing)
|
||||
- GIT CLI
|
||||
|
||||
### How do I run ableos?
|
||||
- It is recommended to run ableos under QEMU. Here is how:
|
||||
- Install QEMU
|
||||
- Clone ableos
|
||||
- Go to ableos directory
|
||||
- Pull the limine submodule with `git submodule update --init`
|
||||
- Run `cargo repbuild help`
|
||||
|
||||
### How can I contribute?
|
||||
- [Contribute code](#how-do-i-contribute-code)
|
||||
- [Run ableos on your machine](#how-do-i-run-ableos)
|
||||
- Find bugs
|
||||
- Create media showing ableos
|
||||
|
||||
### How do I contribute code?
|
||||
- Start by forking ableos
|
||||
- Write something that runs in the userspace, for example:
|
||||
- System drivers
|
||||
- Programs
|
||||
- Libraries
|
||||
- Patch bugs and improve code in the kernel
|
||||
- Ensure that the code is OK to be maintained by asking in the [discord](https://discord.gg/t5Wt3K4YNA)
|
||||
- When you have finished your changes, you can submit a pull request for review [here](https://git.ablecorp.us/ableos/ableos)
|
||||
|
||||
### repbuild and kernel compile, but QEMU isn't starting
|
||||
- Ensure you have the `qemu-desktop-{arch}` for your OS and target architecture installed
|
||||
- Try running again with `--noaccel` if you have QEMU already
|
||||
|
||||
### I have run using repbuild but it's slow
|
||||
- Ensure release mode is enabled with the `-r` flag
|
||||
- Remove the `--noaccel` flag if you can
|
||||
- If both of these are already done, there may be a problem with thee VM, kernel, your program, or the hblang compiler
|
||||
|
||||
### Compiler is complaining about "reg id leaked"
|
||||
- [Submit](#how-do-i-report-a-compiler-bug) an issue, reg id leaked is a bug
|
||||
|
||||
### My program isn't running
|
||||
- Refer to [here](#i-have-run-using-repbuild-but-its-slow), it may be that your program is simply starting slowly
|
||||
- Ensure that your program has a properly written meta.toml file
|
||||
- Ensure that your program is enabled in [system_config.toml](sysdata/system_config.toml)
|
||||
- Try running again with `--noaccel`, there is a known bug with some systems that prevents programs from starting.
|
||||
|
||||
### Kernel panic??? Huh???
|
||||
- Kernel panics can be caused by improperly using memory (e.g, writing out of bounds)
|
||||
- Kernel panics are most likely to be caused when accessing memory or using `@eca` for kernel ecalls
|
||||
- [Report](#how-do-i-report-an-ableos-bug) a kernel panic
|
||||
|
||||
### I am running in release mode but I have no debug info
|
||||
- Add the `-d` flag for debug info
|
||||
|
||||
### What is `@eca`? How do I use it?
|
||||
- Eca is an ecall. They are similar to syscalls
|
||||
- The `@eca` directive takes the following arguments:
|
||||
- `@eca(ecall_number, reg_1, ..., reg_n)`
|
||||
- The various ecalls have different arguments that are given by register values
|
||||
- Most ecalls are wrapped by `stn`, for example, `random`, `buffer`, and `memory` all make use of ecalls
|
||||
- All ecalls can be found [ecah.rs](kernel/src/holeybytes/ecah.rs)
|
||||
|
||||
### How do I report an ableos bug?
|
||||
- Submit an issue [here](https://git.ablecorp.us/ableos/ableos/issues) or report it in the [discord](https://discord.gg/t5Wt3K4YNA)
|
||||
|
||||
### How do I report a compiler bug?
|
||||
- Submit an issue [here](https://git.ablecorp.us/ableos/holey-bytes/issues) or report it in the [discord](https://discord.gg/t5Wt3K4YNA)
|
12
README.md
12
README.md
|
@ -10,15 +10,7 @@ Donations can be made [here on Liberapay](https://liberapay.com/AbleTheAbove) or
|
|||
<img src="https://img.shields.io/liberapay/patrons/AbleTheAbove.svg?logo=liberapay">
|
||||
|
||||
# Compiling
|
||||
AbleOS should be able to be built on any platform which is supported by
|
||||
[Rustc Tier 1 platform support](https://doc.rust-lang.org/nightly/rustc/platform-support.html#tier-1-with-host-tools).
|
||||
|
||||
For running AbleOS, `repbuild` uses QEMU.
|
||||
|
||||
## Steps
|
||||
1. Ensure you have qemu installed
|
||||
2. `git submodule update --init`
|
||||
3. `cargo repbuild run`
|
||||
See [HELP.md](HELP.md)
|
||||
|
||||
# Developing
|
||||
There is a new work in progress developer tool for hblang.
|
||||
There is a new work in progress developer tool for hblang. (see: dev folder)
|
|
@ -138,8 +138,8 @@ fn build(name: String) {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn build_program(name: String) {}
|
||||
pub fn build_library(name: String) {}
|
||||
pub fn build_program(_name: String) {}
|
||||
pub fn build_library(_name: String) {}
|
||||
|
||||
fn help() {
|
||||
println!(
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
sudo apt-get update && sudo apt install -y qemu-utils qemu-system-x86 qemu-system-gui clang
|
|
@ -4,6 +4,3 @@ build-std-features = ["compiler-builtins-mem"]
|
|||
|
||||
[build]
|
||||
target = "./targets/x86_64-ableos.json"
|
||||
|
||||
[target.'cfg(target_arch = "x86_64")']
|
||||
rustflags = ["-C", "target-feature=+rdrand"]
|
||||
|
|
|
@ -5,8 +5,10 @@ version = "0.2.0"
|
|||
|
||||
|
||||
[dependencies]
|
||||
embedded-graphics = "0.8"
|
||||
hbvm.git = "https://git.ablecorp.us/AbleOS/holey-bytes.git"
|
||||
# embedded-graphics = "0.8"
|
||||
hbvm = { git = "https://git.ablecorp.us/AbleOS/holey-bytes.git", features = [
|
||||
"nightly",
|
||||
] }
|
||||
log = "0.4"
|
||||
spin = "0.9"
|
||||
slab = { version = "0.4", default-features = false }
|
||||
|
@ -14,42 +16,35 @@ uart_16550 = { version = "0.3", features = ["nightly"] }
|
|||
xml.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"
|
||||
hashbrown = { version = "0.14", features = ["nightly"] }
|
||||
|
||||
[dependencies.limine]
|
||||
version = "0.1"
|
||||
#git = "https://github.com/limine-bootloader/limine-rs"
|
||||
hashbrown = { version = "0.15", features = ["nightly"] }
|
||||
limine = "0.1"
|
||||
|
||||
[dependencies.crossbeam-queue]
|
||||
version = "0.3"
|
||||
default-features = false
|
||||
features = ["alloc", "nightly"]
|
||||
|
||||
# [dependencies.clparse]
|
||||
# git = "https://git.ablecorp.us/ableos/ableos_userland"
|
||||
# default-features = false
|
||||
|
||||
[dependencies.derive_more]
|
||||
version = "1"
|
||||
default-features = false
|
||||
features = [
|
||||
"add",
|
||||
"add_assign",
|
||||
"constructor",
|
||||
"display",
|
||||
"from",
|
||||
"into",
|
||||
"mul",
|
||||
"mul_assign",
|
||||
"not",
|
||||
"sum",
|
||||
"add",
|
||||
"add_assign",
|
||||
"constructor",
|
||||
"display",
|
||||
"from",
|
||||
"into",
|
||||
"mul",
|
||||
"mul_assign",
|
||||
"not",
|
||||
"sum",
|
||||
]
|
||||
|
||||
|
||||
[target.'cfg(target_arch = "x86_64")'.dependencies]
|
||||
x86_64 = "0.15"
|
||||
x2apic = "0.4"
|
||||
virtio-drivers = "0.7"
|
||||
# virtio-drivers = "0.7"
|
||||
|
||||
[target.'cfg(target_arch = "riscv64")'.dependencies]
|
||||
sbi = "0.2.0"
|
||||
|
|
|
@ -38,6 +38,7 @@ SECTIONS
|
|||
|
||||
.data : {
|
||||
*(.data .data.*)
|
||||
*(.got .got.*)
|
||||
} :data
|
||||
|
||||
.bss : {
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
use {
|
||||
crate::{alloc::string::ToString, device_tree::DeviceTree, kmain::DEVICE_TREE},
|
||||
alloc::string::String,
|
||||
crate::{device_tree::DeviceTree, kmain::DEVICE_TREE},
|
||||
core::arch::asm,
|
||||
xml::XMLElement,
|
||||
};
|
||||
|
@ -28,7 +27,7 @@ fn collect_cpu_info(device_tree: &mut DeviceTree) {
|
|||
cpus.push(cpu);
|
||||
}
|
||||
|
||||
fn cpu_id() -> (String, u64) {
|
||||
fn cpu_id<'a>() -> (&'a str, u64) {
|
||||
let mut cpu_id: u64;
|
||||
unsafe {
|
||||
asm!("mrs {cpu_id}, MIDR_EL1",
|
||||
|
@ -39,11 +38,11 @@ fn cpu_id() -> (String, u64) {
|
|||
let cpu_name = match cpu_id {
|
||||
// the source of these two was a stackoverflow question
|
||||
// https://raspberrypi.stackexchange.com/questions/117175/how-do-i-read-the-cpuid-in-aarch64-asm
|
||||
0x410FD034 => "Cortex-A53".to_string(),
|
||||
0x410FD083 => "Cortex-A72".to_string(),
|
||||
0x410FD034 => "Cortex-A53",
|
||||
0x410FD083 => "Cortex-A72",
|
||||
// the source of this one was checking the cpu id :thinking:
|
||||
0x410FD493 => "Neoverse N2".to_string(),
|
||||
_ => "Unknown".to_string(),
|
||||
0x410FD493 => "Neoverse N2",
|
||||
_ => "Unknown",
|
||||
};
|
||||
log::trace!("CPU Name: {cpu_name} - CPU ID: 0x{:X}", cpu_id);
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ pub static SERIAL_CONSOLE: Mutex<SerialConsole> = Mutex::new(SerialConsole {
|
|||
uart: 0x09000000 as *mut u8,
|
||||
});
|
||||
|
||||
struct SerialConsole {
|
||||
pub struct SerialConsole {
|
||||
uart: *mut u8,
|
||||
}
|
||||
|
||||
|
|
|
@ -14,3 +14,29 @@ arch_cond!(
|
|||
riscv64: "riscv64",
|
||||
x86_64: "x86_64",
|
||||
);
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
use {crate::arch::interrupts::Interrupt, alloc::string::String};
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
pub struct InterruptList {
|
||||
list: HashMap<Interrupt, String>,
|
||||
}
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
use hashbrown::HashMap;
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
impl InterruptList {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
list: HashMap::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
use spin::{Lazy, Mutex};
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
pub static INTERRUPT_LIST: Lazy<Mutex<InterruptList>> = Lazy::new(|| {
|
||||
let mut il = InterruptList::new();
|
||||
use crate::alloc::string::ToString;
|
||||
il.list.insert(Interrupt::Timer, "PS/2 Mouse".to_string());
|
||||
Mutex::new(il)
|
||||
});
|
||||
|
|
|
@ -11,7 +11,9 @@ static mut LAPIC: LocalApic = unsafe { MaybeUninit::zeroed().assume_init() };
|
|||
static mut IDT: InterruptDescriptorTable = unsafe { MaybeUninit::zeroed().assume_init() };
|
||||
|
||||
#[repr(u8)]
|
||||
enum Interrupt {
|
||||
#[derive(Debug, Eq, Hash, PartialEq)]
|
||||
|
||||
pub enum Interrupt {
|
||||
Timer = 32,
|
||||
ApicErr = u8::MAX - 1,
|
||||
Spurious = u8::MAX,
|
||||
|
@ -60,17 +62,49 @@ extern "x86-interrupt" fn page_fault(
|
|||
}
|
||||
|
||||
extern "x86-interrupt" fn timer(_isf: InterruptStackFrame) {
|
||||
// interrupt(Interrupt::Timer);
|
||||
|
||||
unsafe {
|
||||
LAPIC.end_of_interrupt();
|
||||
}
|
||||
}
|
||||
|
||||
extern "x86-interrupt" fn apic_err(_: InterruptStackFrame) {
|
||||
interrupt(Interrupt::ApicErr);
|
||||
|
||||
panic!("Internal APIC error");
|
||||
}
|
||||
|
||||
extern "x86-interrupt" fn spurious(_: InterruptStackFrame) {
|
||||
interrupt(Interrupt::Spurious);
|
||||
|
||||
unsafe {
|
||||
LAPIC.end_of_interrupt();
|
||||
}
|
||||
}
|
||||
|
||||
fn interrupt(interrupt_type: Interrupt) {
|
||||
use crate::arch::INTERRUPT_LIST;
|
||||
let il = INTERRUPT_LIST.lock();
|
||||
let val = il.list.get(&interrupt_type).unwrap();
|
||||
|
||||
use crate::holeybytes::kernel_services::service_definition_service::sds_search_service;
|
||||
let buffer = sds_search_service(val);
|
||||
if buffer != 0 {
|
||||
use {crate::kmain::IPC_BUFFERS, alloc::vec::Vec};
|
||||
let mut buffs = IPC_BUFFERS.lock();
|
||||
match buffs.get_mut(&buffer) {
|
||||
Some(buff) => {
|
||||
let mut msg_vec = Vec::new();
|
||||
msg_vec.push(0xFF);
|
||||
buff.push(msg_vec.to_vec());
|
||||
log::debug!("Sent Message {:?} to Buffer({})", msg_vec, buffer);
|
||||
}
|
||||
None => {
|
||||
log::error!("Access of non-existent buffer {}", buffer)
|
||||
}
|
||||
}
|
||||
|
||||
// log::info!("{}", buffer);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ pub mod graphics;
|
|||
pub(crate) mod interrupts;
|
||||
pub mod logging;
|
||||
pub mod pci;
|
||||
pub mod virtio;
|
||||
// pub mod virtio;
|
||||
|
||||
pub use {logging::log, memory::PAGE_SIZE};
|
||||
|
||||
|
@ -30,9 +30,11 @@ const INITIAL_KERNEL_HEAP_SIZE: *const () = _initial_kernel_heap_size as _;
|
|||
|
||||
#[no_mangle]
|
||||
#[naked]
|
||||
#[cfg(not(target_feature = "avx2"))]
|
||||
unsafe extern "C" fn _kernel_start() -> ! {
|
||||
// Initialise SSE and jump to kernel entrypoint
|
||||
core::arch::asm!(
|
||||
// Initialise SSE, then jump to kernel entrypoint
|
||||
core::arch::naked_asm!(
|
||||
// Initialise SSE
|
||||
"mov rax, cr0",
|
||||
"and ax, 0xfffb",
|
||||
"or ax, 0x2",
|
||||
|
@ -40,16 +42,74 @@ unsafe extern "C" fn _kernel_start() -> ! {
|
|||
"mov rax, cr4",
|
||||
"or ax, 3 << 9",
|
||||
"mov cr4, rax",
|
||||
|
||||
// Jump to the kernel entry point
|
||||
"jmp {}",
|
||||
sym start,
|
||||
options(noreturn),
|
||||
)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[naked]
|
||||
#[cfg(target_feature = "avx2")]
|
||||
unsafe extern "C" fn _kernel_start() -> ! {
|
||||
core::arch::naked_asm!(
|
||||
// Enable protected mode and configure control registers
|
||||
"mov rax, cr0",
|
||||
"and ax, 0xFFFB", // Clear CR0.EM (bit 2) for coprocessor emulation
|
||||
"or ax, 0x2", // Set CR0.MP (bit 1) for coprocessor monitoring
|
||||
"mov cr0, rax",
|
||||
|
||||
"mov rax, cr4",
|
||||
"or ax, (1 << 9) | (1 << 10)", // Set CR4.OSFXSR (bit 9) and CR4.OSXMMEXCPT (bit 10)
|
||||
"mov cr4, rax",
|
||||
|
||||
// Enable OSXSAVE (required for AVX, AVX2, and XSAVE)
|
||||
"mov rax, cr4",
|
||||
"or eax, 1 << 18", // Set CR4.OSXSAVE (bit 18)
|
||||
"mov cr4, rax",
|
||||
|
||||
// Enable AVX and AVX2 state saving
|
||||
"xor rcx, rcx",
|
||||
"xgetbv",
|
||||
"or eax, 7", // Enable SSE, AVX, and AVX2 state saving
|
||||
"xsetbv",
|
||||
|
||||
// Check for AVX and XSAVE support
|
||||
"mov eax, 1",
|
||||
"cpuid",
|
||||
"and ecx, 0x18000000",
|
||||
"cmp ecx, 0x18000000",
|
||||
"jne {1}", // Jump if AVX/OSXSAVE is not supported
|
||||
|
||||
// Check for BMI2 and AVX2 support
|
||||
"mov eax, 7",
|
||||
"xor ecx, ecx",
|
||||
"cpuid",
|
||||
"and ebx, (1 << 8) | (1 << 5)", // Check BMI2 (bit 8) and AVX2 (bit 5)
|
||||
"cmp ebx, (1 << 8) | (1 << 5)", // Compare to ensure both are supported
|
||||
|
||||
// Check for LZCNT and POPCNT support
|
||||
"mov eax, 1",
|
||||
"cpuid",
|
||||
"and ecx, (1 << 5) | (1 << 23)", // Check LZCNT (bit 5) and POPCNT (bit 23)
|
||||
"cmp ecx, (1 << 5) | (1 << 23)", // Compare to ensure both are supported
|
||||
|
||||
// Jump to the kernel entry point
|
||||
"jmp {0}",
|
||||
sym start,
|
||||
sym oops,
|
||||
)
|
||||
}
|
||||
|
||||
unsafe extern "C" fn oops() -> ! {
|
||||
panic!("your cpu is ancient >:(")
|
||||
}
|
||||
|
||||
unsafe extern "C" fn start() -> ! {
|
||||
logging::init();
|
||||
crate::logger::init().expect("failed to set logger");
|
||||
log::info!("Initialising AKern {}", crate::VERSION);
|
||||
log::debug!("Initialising AKern {}", crate::VERSION);
|
||||
|
||||
static HDHM_REQ: HhdmRequest = HhdmRequest::new(0);
|
||||
memory::init_pt(VirtAddr::new(
|
||||
|
@ -128,7 +188,7 @@ unsafe extern "C" fn start() -> ! {
|
|||
// TODO: Add in rdseed and rdrand as sources for randomness
|
||||
let _rand = xml::XMLElement::new("Random");
|
||||
|
||||
log::trace!("Getting boot modules");
|
||||
log::debug!("Getting boot modules");
|
||||
let bm = MOD_REQ.get_response().get();
|
||||
|
||||
let mut bootmodules = alloc::vec::Vec::new();
|
||||
|
@ -166,7 +226,7 @@ unsafe extern "C" fn start() -> ! {
|
|||
break;
|
||||
}
|
||||
}
|
||||
log::info!("Boot module count: {:?}", bootmodules.len());
|
||||
log::debug!("Boot module count: {:?}", bootmodules.len());
|
||||
assert_eq!(bm.module_count, bootmodules.len() as u64);
|
||||
}
|
||||
|
||||
|
@ -189,6 +249,7 @@ unsafe extern "C" fn start() -> ! {
|
|||
/// Spin loop
|
||||
pub fn spin_loop() -> ! {
|
||||
loop {
|
||||
core::hint::spin_loop();
|
||||
x86_64::instructions::hlt()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,13 +8,12 @@ pub struct PciDeviceInfo {
|
|||
pub full_class: PciFullClass,
|
||||
pub rev_id: u8,
|
||||
}
|
||||
use crate::alloc::string::ToString;
|
||||
|
||||
/// Enumerate PCI devices and run initialisation routines on ones we support
|
||||
pub fn init(device_tree: &mut DeviceTree) {
|
||||
device_tree
|
||||
.devices
|
||||
.insert("Unidentified PCI".to_string(), alloc::vec![]);
|
||||
.insert("Unidentified PCI", alloc::vec![]);
|
||||
let mut devices = alloc::vec![];
|
||||
|
||||
for bus in 0..=255 {
|
||||
|
@ -48,7 +47,7 @@ pub fn init(device_tree: &mut DeviceTree) {
|
|||
pci_info.set_attribute("device", device_info.device);
|
||||
pci_info.set_attribute("vendor", vendor);
|
||||
pci_info.set_attribute("bus", bus);
|
||||
pci_info.set_attribute("class", device_info.full_class.to_string());
|
||||
pci_info.set_attribute("class", device_info.full_class);
|
||||
dev.set_child(pci_info);
|
||||
devices.push((dev_type, dev));
|
||||
}
|
||||
|
@ -70,7 +69,7 @@ pub fn check_device(bus: u8, device: u8) -> Option<PciDeviceInfo> {
|
|||
}
|
||||
|
||||
let (reg2, addr) = unsafe { pci_config_read_2(bus, device, 0, 0x8) };
|
||||
log::info!("pci device-({}) addr {} is {}", device, addr, reg2);
|
||||
log::debug!("pci device-({}) addr {} is {}", device, addr, reg2);
|
||||
let class = ((reg2 >> 16) & 0x0000_FFFF) as u16;
|
||||
let pci_class = PciFullClass::from_u16(class);
|
||||
let header_type = get_header_type(bus, device, 0);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use {
|
||||
core::{ptr::NonNull},
|
||||
core::ptr::NonNull,
|
||||
virtio_drivers::{BufferDirection, Hal, PhysAddr},
|
||||
};
|
||||
|
||||
|
|
|
@ -1,11 +1,6 @@
|
|||
//! A tree of hardware devices
|
||||
|
||||
use {
|
||||
crate::alloc::string::ToString,
|
||||
alloc::{string::String, vec::Vec},
|
||||
core::fmt,
|
||||
hashbrown::HashMap,
|
||||
};
|
||||
use {alloc::vec::Vec, core::fmt, hashbrown::HashMap};
|
||||
|
||||
/// A device object.
|
||||
/// TODO define device
|
||||
|
@ -14,11 +9,11 @@ pub type Device = xml::XMLElement;
|
|||
/// A tree of devices
|
||||
// TODO: alphabetize this list
|
||||
#[derive(Debug)]
|
||||
pub struct DeviceTree {
|
||||
pub struct DeviceTree<'a> {
|
||||
/// The device tree
|
||||
pub devices: HashMap<String, Vec<Device>>,
|
||||
pub devices: HashMap<&'a str, Vec<Device>>,
|
||||
}
|
||||
impl DeviceTree {
|
||||
impl<'a> DeviceTree<'a> {
|
||||
/// Build the device tree. Does not populate the device tree
|
||||
pub fn new() -> Self {
|
||||
let mut dt = Self {
|
||||
|
@ -47,7 +42,7 @@ impl DeviceTree {
|
|||
}
|
||||
}
|
||||
use crate::{device_tree, tab, utils::TAB};
|
||||
impl fmt::Display for DeviceTree {
|
||||
impl<'a> fmt::Display for DeviceTree<'a> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
writeln!(f)?;
|
||||
for (device_type, devices) in &self.devices {
|
||||
|
|
|
@ -1,21 +1,40 @@
|
|||
//! Environment call handling routines
|
||||
|
||||
use crate::holeybytes::kernel_services::{
|
||||
block_read, dt_msg_handler::dt_msg_handler, logging_service::log_msg_handler,
|
||||
service_definition_service::sds_msg_handler,
|
||||
use {alloc::boxed::Box, core::cell::LazyCell, hbvm::mem::Address};
|
||||
|
||||
use crate::{
|
||||
holeybytes::{
|
||||
kernel_services::{
|
||||
block_read, dt_msg_handler::dt_msg_handler, logging_service::log_msg_handler,
|
||||
service_definition_service::sds_msg_handler,
|
||||
},
|
||||
ExecThread,
|
||||
},
|
||||
kmain::EXECUTOR,
|
||||
task::Executor,
|
||||
};
|
||||
|
||||
use {
|
||||
super::Vm,
|
||||
crate::{arch, ipc::buffer::IpcBuffer, kmain::IPC_BUFFERS},
|
||||
hbvm::value::Value,
|
||||
log::{debug, error, info, trace},
|
||||
};
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
#[inline(always)]
|
||||
unsafe fn x86_out<T: x86_64::instructions::port::PortWrite>(address: u16, value: T) {
|
||||
x86_64::instructions::port::Port::new(address).write(value);
|
||||
}
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
#[inline(always)]
|
||||
unsafe fn x86_in<T: x86_64::instructions::port::PortRead>(address: u16) -> T {
|
||||
x86_64::instructions::port::Port::new(address).read()
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn handler(vm: &mut Vm) {
|
||||
let ecall_number = vm.registers[2].cast::<u64>();
|
||||
// log::info!("eca called :pensive:");
|
||||
// debug!("Ecall number {:?}", ecall_number);
|
||||
//info!("Register dump: {:?}", vm.registers);
|
||||
|
||||
match ecall_number {
|
||||
0 => {
|
||||
|
@ -28,9 +47,9 @@ pub fn handler(vm: &mut Vm) {
|
|||
1 => {
|
||||
// Make buffer
|
||||
|
||||
let bounded = match vm.registers[3].cast::<u64>() {
|
||||
0 => false,
|
||||
1 => true,
|
||||
let bounded = match vm.registers[3] {
|
||||
Value(0) => false,
|
||||
Value(1) => true,
|
||||
_ => {
|
||||
panic!("Bad");
|
||||
}
|
||||
|
@ -39,22 +58,19 @@ pub fn handler(vm: &mut Vm) {
|
|||
let length = vm.registers[4].cast::<u64>();
|
||||
|
||||
let mut buffs = IPC_BUFFERS.lock();
|
||||
let abc;
|
||||
|
||||
match bounded {
|
||||
false => {
|
||||
abc = IpcBuffer::new(false, 0);
|
||||
}
|
||||
true => {
|
||||
abc = IpcBuffer::new(true, length);
|
||||
}
|
||||
};
|
||||
let buff_id = arch::hardware_random_u64();
|
||||
buffs.insert(buff_id, abc);
|
||||
info!("Buffer ID: {}", buff_id);
|
||||
buffs.insert(
|
||||
buff_id,
|
||||
match bounded {
|
||||
false => IpcBuffer::new(false, 0),
|
||||
true => IpcBuffer::new(true, length),
|
||||
},
|
||||
);
|
||||
vm.registers[1] = hbvm::value::Value(buff_id);
|
||||
}
|
||||
2 => {
|
||||
log::error!("Oops, deleting buffers is not implemented.")
|
||||
// Delete buffer
|
||||
}
|
||||
3 => {
|
||||
|
@ -63,7 +79,6 @@ pub fn handler(vm: &mut Vm) {
|
|||
let mem_addr = vm.registers[4].cast::<u64>();
|
||||
let length = vm.registers[5].cast::<u64>() as usize;
|
||||
trace!("IPC address: {:?}", mem_addr);
|
||||
use alloc::vec::Vec;
|
||||
|
||||
match buffer_id {
|
||||
0 => match sds_msg_handler(vm, mem_addr, length) {
|
||||
|
@ -81,25 +96,15 @@ pub fn handler(vm: &mut Vm) {
|
|||
Err(_) => {}
|
||||
}
|
||||
}
|
||||
#[cfg(not(target_arch = "x86_64"))]
|
||||
3 => info!("TODO: implement whatever buffer 3 does for no x86_64"),
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
3 => {
|
||||
unsafe fn x86_out<T: x86_64::instructions::port::PortWrite>(
|
||||
address: u16,
|
||||
value: T,
|
||||
) {
|
||||
x86_64::instructions::port::Port::new(address).write(value);
|
||||
}
|
||||
unsafe fn x86_in<T: x86_64::instructions::port::PortRead>(address: u16) -> T {
|
||||
x86_64::instructions::port::Port::new(address).read()
|
||||
}
|
||||
let msg_vec = block_read(mem_addr, length);
|
||||
let msg_type = msg_vec[0];
|
||||
match msg_type {
|
||||
0 => unsafe {
|
||||
let size = msg_vec[1];
|
||||
let addr = u16::from_le_bytes(msg_vec[2..4].try_into().unwrap());
|
||||
let addr =
|
||||
u16::from_le_bytes(msg_vec[2..4].try_into().unwrap_unchecked());
|
||||
let value = match size {
|
||||
0 => x86_in::<u8>(addr) as u64,
|
||||
1 => x86_in::<u16>(addr) as u64,
|
||||
|
@ -111,7 +116,8 @@ pub fn handler(vm: &mut Vm) {
|
|||
},
|
||||
1 => unsafe {
|
||||
let size = msg_vec[1];
|
||||
let addr = u16::from_le_bytes(msg_vec[2..4].try_into().unwrap());
|
||||
let addr =
|
||||
u16::from_le_bytes(msg_vec[2..4].try_into().unwrap_unchecked());
|
||||
// info!("Setting address {}", addr);
|
||||
|
||||
match size {
|
||||
|
@ -134,68 +140,95 @@ pub fn handler(vm: &mut Vm) {
|
|||
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);
|
||||
let block = block_read(mem_addr, length);
|
||||
block.chunks_mut(8.min(length)).for_each(|chunk| {
|
||||
chunk.clone_from_slice(
|
||||
&crate::arch::hardware_random_u64().to_le_bytes()[..chunk.len()],
|
||||
);
|
||||
});
|
||||
vm.registers[1] = hbvm::value::Value(mem_addr);
|
||||
}
|
||||
5 => match dt_msg_handler(vm, mem_addr, length) {
|
||||
Ok(()) => {}
|
||||
Err(_) => log::error!("Improper dt query"),
|
||||
},
|
||||
6 => unsafe {
|
||||
let program = block_read(mem_addr, length);
|
||||
|
||||
// decode AbleOS Executable format
|
||||
let header = &program[0..46];
|
||||
let magic_slice = &header[0..3];
|
||||
if magic_slice != [0x15, 0x91, 0xD2] {
|
||||
log::error!("Invalid magic number at the start of executable.");
|
||||
return;
|
||||
}
|
||||
|
||||
let executable_format_version =
|
||||
u32::from_le_bytes(header[3..7].try_into().unwrap());
|
||||
let offset = if executable_format_version == 0 {
|
||||
47
|
||||
} else {
|
||||
error!("Invalid executable format.");
|
||||
return;
|
||||
};
|
||||
|
||||
let code_length = u64::from_le_bytes(header[7..15].try_into().unwrap());
|
||||
let data_length = u64::from_le_bytes(header[15..23].try_into().unwrap());
|
||||
let end = (code_length + data_length) as usize;
|
||||
log::debug!("{code_length} + {data_length} = {end}");
|
||||
|
||||
let thr = ExecThread::new(&program[offset..end], Address::new(0));
|
||||
vm.registers[1] = Value(
|
||||
LazyCell::<Executor>::get_mut(&mut EXECUTOR)
|
||||
.unwrap()
|
||||
.spawn(Box::pin(async move {
|
||||
if let Err(e) = thr.await {
|
||||
log::error!("{e:?}");
|
||||
}
|
||||
})) as u64,
|
||||
);
|
||||
log::debug!("spawned a process");
|
||||
},
|
||||
|
||||
buffer_id => {
|
||||
let mut buffs = IPC_BUFFERS.lock();
|
||||
match buffs.get_mut(&buffer_id) {
|
||||
Some(buff) => {
|
||||
let mut msg_vec = Vec::with_capacity(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);
|
||||
}
|
||||
debug!(
|
||||
"Message {:?} has been sent to Buffer({})",
|
||||
msg_vec, buffer_id
|
||||
);
|
||||
buff.push(msg_vec);
|
||||
let msg_vec = block_read(mem_addr, length);
|
||||
buff.push(msg_vec.to_vec());
|
||||
debug!("Sent Message {:?} to Buffer({})", msg_vec, buffer_id);
|
||||
}
|
||||
None => {
|
||||
log::error!("Access of non-existent buffer {}", buffer_id)
|
||||
}
|
||||
}
|
||||
drop(buffs);
|
||||
}
|
||||
}
|
||||
}
|
||||
4 => {
|
||||
let buffer_id = vm.registers[3].cast::<u64>();
|
||||
let mut map_ptr = vm.registers[4].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;
|
||||
let buff: &mut IpcBuffer = match buffs.get_mut(&buffer_id) {
|
||||
Some(buff) => buff,
|
||||
None => panic!(
|
||||
"Failed to get buffer: id={buffer_id}, ptr={map_ptr}, length={max_length}"
|
||||
),
|
||||
};
|
||||
|
||||
if buffs.get_mut(&buffer_id).is_some() {
|
||||
buff = buffs.get_mut(&buffer_id).unwrap();
|
||||
} else {
|
||||
// info!("AHHH");
|
||||
vm.registers[1] = hbvm::value::Value(0);
|
||||
return;
|
||||
}
|
||||
let pop = buff.pop();
|
||||
if pop.is_err() {
|
||||
return;
|
||||
}
|
||||
let msg = pop.unwrap();
|
||||
if msg.len() > max_length.try_into().unwrap() {
|
||||
let msg = match buff.pop() {
|
||||
Ok(msg) => msg,
|
||||
Err(_) => return,
|
||||
};
|
||||
if msg.len() > unsafe { max_length.try_into().unwrap_unchecked() } {
|
||||
info!("{}", max_length);
|
||||
error!("Message is too long to map in.");
|
||||
} else {
|
||||
unsafe {
|
||||
let ptr: *mut u64 = &mut map_ptr;
|
||||
for (index, byte) in msg.iter().enumerate() {
|
||||
ptr.offset(index.try_into().unwrap()).write_bytes(*byte, 1);
|
||||
}
|
||||
let ptr = map_ptr as *mut u8;
|
||||
ptr.copy_from_nonoverlapping(msg.as_ptr(), msg.len());
|
||||
}
|
||||
|
||||
debug!("Recieve {:?} from Buffer({})", msg, buffer_id);
|
||||
|
@ -205,13 +238,7 @@ pub fn handler(vm: &mut Vm) {
|
|||
#[cfg(target_arch = "x86_64")]
|
||||
{
|
||||
let r2 = vm.registers[2].cast::<u64>();
|
||||
unsafe fn x86_in(address: u16) -> u32 {
|
||||
x86_64::instructions::port::Port::new(address).read()
|
||||
}
|
||||
unsafe fn x86_out(address: u16, value: u32) {
|
||||
x86_64::instructions::port::Port::new(address).write(value);
|
||||
}
|
||||
let x = hbvm::value::Value(unsafe { x86_in(r2 as u16) } as u64);
|
||||
let x = hbvm::value::Value(unsafe { x86_in::<u8>(r2 as u16) } as u64);
|
||||
// info!("Read {:?} from Port {:?}", x, r2);
|
||||
vm.registers[3] = x
|
||||
}
|
||||
|
@ -227,15 +254,3 @@ pub enum LogError {
|
|||
NoMessages,
|
||||
InvalidLogFormat,
|
||||
}
|
||||
|
||||
// use {alloc::vec, log::Record};
|
||||
// fn memory_msg_handler(vm: &mut Vm, mem_addr: u64, length: usize) -> Result<(), LogError> {
|
||||
// let mut val = alloc::vec::Vec::new();
|
||||
// for _ in 0..4096 {
|
||||
// val.push(0);
|
||||
// }
|
||||
// info!("Block address: {:?}", val.as_ptr());
|
||||
// vm.registers[1] = hbvm::value::Value(val.as_ptr() as u64);
|
||||
// vm.registers[2] = hbvm::value::Value(4096);
|
||||
// Ok(())
|
||||
// }
|
||||
|
|
|
@ -1,9 +1,6 @@
|
|||
use {
|
||||
crate::holeybytes::{kernel_services::block_read, Vm},
|
||||
alloc::{
|
||||
string::{String, ToString},
|
||||
vec::Vec,
|
||||
},
|
||||
alloc::vec::Vec,
|
||||
};
|
||||
pub enum DtError {
|
||||
QueryFailure,
|
||||
|
@ -11,14 +8,13 @@ pub enum DtError {
|
|||
|
||||
pub fn dt_msg_handler(vm: &mut Vm, mem_addr: u64, length: usize) -> Result<(), DtError> {
|
||||
let msg_vec = block_read(mem_addr, length);
|
||||
let mut bytes: Vec<u8> = Vec::new();
|
||||
for byte in msg_vec {
|
||||
if *byte == 0 {
|
||||
break;
|
||||
}
|
||||
bytes.push(*byte)
|
||||
}
|
||||
let query_string = String::from_utf8(bytes).unwrap();
|
||||
let query_string = core::str::from_utf8(
|
||||
msg_vec
|
||||
.split_once(|&byte| byte == 0)
|
||||
.unwrap_or((msg_vec, &[]))
|
||||
.0,
|
||||
)
|
||||
.unwrap();
|
||||
log::trace!("Query {}", query_string);
|
||||
|
||||
let ret = query_parse(query_string);
|
||||
|
@ -29,17 +25,13 @@ pub fn dt_msg_handler(vm: &mut Vm, mem_addr: u64, length: usize) -> Result<(), D
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn query_parse(query_string: String) -> u64 {
|
||||
let qt_parse_step_one = query_string.split("/");
|
||||
let mut qt_parse_step_two: Vec<String> = Vec::new();
|
||||
for a in qt_parse_step_one {
|
||||
qt_parse_step_two.push(a.to_string());
|
||||
}
|
||||
fn query_parse(query_string: &str) -> u64 {
|
||||
let query = query_string.split('/').collect::<Vec<&str>>();
|
||||
|
||||
let first_fragment: &str = &qt_parse_step_two[0];
|
||||
let first_fragment: &str = &query[0];
|
||||
let ret = match first_fragment {
|
||||
"framebuffer" => framebuffer_parse(qt_parse_step_two),
|
||||
"cpu" => cpu_parse(qt_parse_step_two),
|
||||
"framebuffer" => framebuffer_parse(query),
|
||||
"cpu" => cpu_parse(query),
|
||||
|
||||
_ => 0,
|
||||
};
|
||||
|
@ -47,8 +39,8 @@ fn query_parse(query_string: String) -> u64 {
|
|||
return ret;
|
||||
}
|
||||
|
||||
fn cpu_parse(qt_parse_step_two: Vec<String>) -> u64 {
|
||||
let second_fragment: &str = &qt_parse_step_two[1];
|
||||
fn cpu_parse(qt_parse_step_two: Vec<&str>) -> u64 {
|
||||
let second_fragment: &str = qt_parse_step_two[1];
|
||||
match second_fragment {
|
||||
// "architecture" => {
|
||||
// return 0;
|
||||
|
@ -59,15 +51,14 @@ 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<&str>) -> u64 {
|
||||
use crate::kmain::FB_REQ;
|
||||
let fbs = &FB_REQ.get_response().get().unwrap().framebuffers();
|
||||
|
||||
let second_fragment: &str = &qt_parse_step_two[1];
|
||||
let fbs = &mut FB_REQ.get_response().get().unwrap().framebuffers();
|
||||
let second_fragment: &str = qt_parse_step_two[1];
|
||||
match second_fragment {
|
||||
"fb0" => {
|
||||
let fb_front = &fbs[0];
|
||||
let third_fragment: &str = &qt_parse_step_two[2];
|
||||
let third_fragment: &str = qt_parse_step_two[2];
|
||||
let ret = match third_fragment {
|
||||
"ptr" => {
|
||||
let ptr = fb_front.address.as_ptr().unwrap();
|
||||
|
|
|
@ -9,25 +9,30 @@ use log::Record;
|
|||
pub fn log_msg_handler(_vm: &mut Vm, mem_addr: u64, length: usize) -> Result<(), LogError> {
|
||||
let msg_vec = block_read(mem_addr, length);
|
||||
|
||||
let log_level = msg_vec.last().unwrap();
|
||||
use log::Level::*;
|
||||
let log_level = match msg_vec[0] {
|
||||
0 | 48 => Error,
|
||||
1 | 49 => Warn,
|
||||
2 | 50 => Info,
|
||||
3 | 51 => Debug,
|
||||
4 | 52 => Trace,
|
||||
_ => {
|
||||
return Err(LogError::InvalidLogFormat);
|
||||
}
|
||||
};
|
||||
if log_level > log::max_level() {
|
||||
return Ok(());
|
||||
}
|
||||
let strptr = u64::from_le_bytes(msg_vec[1..9].try_into().unwrap());
|
||||
let strlen = u64::from_le_bytes(msg_vec[9..17].try_into().unwrap()) as usize;
|
||||
|
||||
let str = block_read(strptr, strlen);
|
||||
|
||||
let file_name = "None";
|
||||
let line_number = 0;
|
||||
|
||||
match core::str::from_utf8(&msg_vec[..msg_vec.len()]) {
|
||||
match core::str::from_utf8(&str) {
|
||||
Ok(strr) => {
|
||||
use log::Level::*;
|
||||
let log_level = match log_level {
|
||||
0 | 48 => Error,
|
||||
1 | 49 => Warn,
|
||||
2 | 50 => Info,
|
||||
3 | 51 => Debug,
|
||||
4 | 52 => Trace,
|
||||
_ => {
|
||||
return Err(LogError::InvalidLogFormat);
|
||||
}
|
||||
};
|
||||
|
||||
log::logger().log(
|
||||
&Record::builder()
|
||||
.args(format_args!("{}", strr))
|
||||
|
|
|
@ -17,13 +17,28 @@ pub enum MemoryQuotaType {
|
|||
}
|
||||
|
||||
fn alloc_page(vm: &mut Vm, _mem_addr: u64, _length: usize) -> Result<(), MemoryServiceError> {
|
||||
let ptr = unsafe { alloc(Layout::from_size_align_unchecked(4096, 4096)) };
|
||||
let ptr = unsafe { alloc(Layout::from_size_align_unchecked(4096, 8)) };
|
||||
info!("Block address: {:?}", ptr);
|
||||
vm.registers[1] = hbvm::value::Value(ptr as u64);
|
||||
vm.registers[2] = hbvm::value::Value(4096);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
unsafe fn memset(dest: *mut u8, src: *const u8, count: usize, size: usize) {
|
||||
let total_size = count * size;
|
||||
src.copy_to_nonoverlapping(dest, size);
|
||||
|
||||
let mut copied = size;
|
||||
|
||||
while copied < total_size {
|
||||
let copy_size = copied.min(total_size - copied);
|
||||
dest.add(copied).copy_from_nonoverlapping(dest, copy_size);
|
||||
copied += copy_size;
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn memory_msg_handler(
|
||||
vm: &mut Vm,
|
||||
mem_addr: u64,
|
||||
|
@ -32,40 +47,35 @@ pub fn memory_msg_handler(
|
|||
let msg_vec = block_read(mem_addr, length);
|
||||
let msg_type = msg_vec[0];
|
||||
match msg_type {
|
||||
0 => {
|
||||
0 => unsafe {
|
||||
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);
|
||||
|
||||
log::debug!("Allocating {} pages @ {:x}", page_count, mptr);
|
||||
let ptr = alloc(Layout::from_size_align_unchecked(
|
||||
page_count as usize * 4096,
|
||||
8,
|
||||
));
|
||||
|
||||
let ptr = unsafe {
|
||||
alloc(Layout::from_size_align_unchecked(
|
||||
page_count as usize * 4096,
|
||||
4096,
|
||||
))
|
||||
};
|
||||
log::debug!("Allocating {} pages @ {:x}", page_count, ptr as u64);
|
||||
|
||||
vm.registers[1] = hbvm::value::Value(ptr as u64);
|
||||
log::debug!("Kernel ptr: {:x}", ptr as u64);
|
||||
}
|
||||
},
|
||||
|
||||
1 => {
|
||||
1 => unsafe {
|
||||
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);
|
||||
log::debug!("Deallocating {} pages @ {:x}", page_count, mptr);
|
||||
unsafe {
|
||||
dealloc(
|
||||
mptr as *mut u8,
|
||||
Layout::from_size_align_unchecked(page_count as usize * 4096, 4096),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
dealloc(
|
||||
mptr as *mut u8,
|
||||
Layout::from_size_align_unchecked(page_count as usize * 4096, 8),
|
||||
)
|
||||
},
|
||||
2 => {
|
||||
use MemoryQuotaType::*;
|
||||
let quota_type = match msg_vec[0] {
|
||||
let quota_type = match msg_vec[1] {
|
||||
0 => NoQuota,
|
||||
1 => SoftQuota,
|
||||
2 => HardQuota,
|
||||
|
@ -82,10 +92,24 @@ pub fn memory_msg_handler(
|
|||
)
|
||||
}
|
||||
3 => {
|
||||
let page_count = msg_vec[0];
|
||||
let page_count = msg_vec[1];
|
||||
log::debug!(" {} pages", page_count);
|
||||
}
|
||||
4 => unsafe {
|
||||
let count = u32::from_le_bytes(msg_vec[1..5].try_into().unwrap_unchecked()) as usize;
|
||||
let src = u64::from_le_bytes(msg_vec[5..13].try_into().unwrap_unchecked()) as *const u8;
|
||||
let dest = u64::from_le_bytes(msg_vec[13..21].try_into().unwrap_unchecked()) as *mut u8;
|
||||
|
||||
src.copy_to_nonoverlapping(dest, count);
|
||||
},
|
||||
5 => unsafe {
|
||||
let count = u32::from_le_bytes(msg_vec[1..5].try_into().unwrap_unchecked()) as usize;
|
||||
let size = u32::from_le_bytes(msg_vec[5..9].try_into().unwrap_unchecked()) as usize;
|
||||
let src = u64::from_le_bytes(msg_vec[9..17].try_into().unwrap_unchecked()) as *const u8;
|
||||
let dest = u64::from_le_bytes(msg_vec[17..25].try_into().unwrap_unchecked()) as *mut u8;
|
||||
|
||||
memset(dest, src, count, size);
|
||||
},
|
||||
_ => {
|
||||
log::debug!("Unknown memory service message type: {}", msg_type);
|
||||
}
|
||||
|
|
|
@ -22,21 +22,19 @@ pub enum ServiceError {
|
|||
pub fn sds_msg_handler(vm: &mut Vm, mem_addr: u64, length: usize) -> Result<(), ServiceError> {
|
||||
let msg_vec = block_read(mem_addr, length);
|
||||
let sds_event_type: ServiceEventType = msg_vec[0].into();
|
||||
|
||||
// info!("Length {}", msg_vec.len());
|
||||
let strptr = u64::from_le_bytes(msg_vec[1..9].try_into().unwrap());
|
||||
let strlen = u64::from_le_bytes(msg_vec[9..17].try_into().unwrap()) as usize;
|
||||
let string_vec = block_read(strptr, strlen);
|
||||
let string = core::str::from_utf8(string_vec).expect("Our bytes should be valid utf8");
|
||||
|
||||
use ServiceEventType::*;
|
||||
match sds_event_type {
|
||||
CreateService => {
|
||||
let string =
|
||||
core::str::from_utf8(&msg_vec[1..]).expect("Our bytes should be valid utf8");
|
||||
let ret = sds_create_service(string);
|
||||
vm.registers[1] = hbvm::value::Value(ret as u64);
|
||||
}
|
||||
DeleteService => todo!(),
|
||||
SearchServices => {
|
||||
let string =
|
||||
core::str::from_utf8(&msg_vec[1..]).expect("Our bytes should be valid utf8");
|
||||
let ret = sds_search_service(string);
|
||||
vm.registers[1] = hbvm::value::Value(ret as u64);
|
||||
}
|
||||
|
@ -94,8 +92,7 @@ fn sds_create_service(protocol: &'static str) -> u64 {
|
|||
// let a: protocol::Protocol = protocol.into();
|
||||
buff_id
|
||||
}
|
||||
|
||||
fn sds_search_service(protocol: &str) -> u64 {
|
||||
pub fn sds_search_service(protocol: &str) -> u64 {
|
||||
let services = SERVICES.lock();
|
||||
let compare = Protocol::from(protocol);
|
||||
for (bid, protocol_canidate) in &services.0 {
|
||||
|
|
|
@ -30,30 +30,29 @@ impl Memory {
|
|||
}
|
||||
|
||||
impl hbvm::mem::Memory for Memory {
|
||||
#[inline]
|
||||
#[inline(always)]
|
||||
unsafe fn load(
|
||||
&mut self,
|
||||
addr: Address,
|
||||
target: *mut u8,
|
||||
count: usize,
|
||||
) -> Result<(), hbvm::mem::LoadError> {
|
||||
if addr.get() % 4096 == 0 {}
|
||||
core::ptr::copy(addr.get() as *const u8, target, count);
|
||||
core::ptr::copy_nonoverlapping(addr.get() as *const u8, target, count);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[inline(always)]
|
||||
unsafe fn store(
|
||||
&mut self,
|
||||
addr: Address,
|
||||
source: *const u8,
|
||||
count: usize,
|
||||
) -> Result<(), hbvm::mem::StoreError> {
|
||||
core::ptr::copy(source, addr.get() as *mut u8, count);
|
||||
core::ptr::copy_nonoverlapping(source, addr.get() as *mut u8, count);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[inline(always)]
|
||||
unsafe fn prog_read<T: Copy>(&mut self, addr: Address) -> T {
|
||||
(addr.get() as *const T).read()
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
mod ecah;
|
||||
mod kernel_services;
|
||||
pub mod kernel_services;
|
||||
mod mem;
|
||||
|
||||
use {
|
||||
|
@ -97,7 +97,7 @@ impl HandlePageFault for PageFaultHandler {
|
|||
|
||||
#[inline(always)]
|
||||
const fn stack_layout() -> Layout {
|
||||
unsafe { Layout::from_size_align_unchecked(STACK_SIZE, 4096) }
|
||||
unsafe { Layout::from_size_align_unchecked(STACK_SIZE, 8) }
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
|
|
|
@ -49,9 +49,7 @@ impl<'a> IpcBuffer<'a> {
|
|||
pub fn push(&mut self, msg: Message) {
|
||||
match &self.buffer {
|
||||
BufferTypes::Unbound(buff) => buff.push(msg),
|
||||
BufferTypes::Bound(buff) => {
|
||||
let _ = buff.push(msg);
|
||||
}
|
||||
BufferTypes::Bound(buff) => buff.push(msg).unwrap(),
|
||||
};
|
||||
}
|
||||
pub fn pop(&mut self) -> Result<Message, IpcError> {
|
||||
|
|
|
@ -1,18 +1,15 @@
|
|||
use {
|
||||
alloc::{string::String, vec::Vec},
|
||||
hashbrown::HashMap,
|
||||
};
|
||||
use {alloc::vec::Vec, hashbrown::HashMap};
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
pub struct Type {}
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
pub struct Funct {
|
||||
takes: Vec<String>,
|
||||
gives: Vec<String>,
|
||||
pub struct Funct<'a> {
|
||||
takes: Vec<&'a str>,
|
||||
gives: Vec<&'a str>,
|
||||
}
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
pub struct Protocol<'a> {
|
||||
types: HashMap<&'a str, Type>,
|
||||
fns: HashMap<&'a str, Funct>,
|
||||
fns: HashMap<&'a str, Funct<'a>>,
|
||||
}
|
||||
impl<'a> Protocol<'a> {
|
||||
pub fn void() -> Self {
|
||||
|
|
|
@ -8,7 +8,10 @@ use {
|
|||
device_tree::DeviceTree,
|
||||
holeybytes::ExecThread,
|
||||
ipc::buffer::IpcBuffer,
|
||||
task::Executor,
|
||||
},
|
||||
alloc::boxed::Box,
|
||||
core::cell::LazyCell,
|
||||
hashbrown::HashMap,
|
||||
hbvm::mem::Address,
|
||||
limine::{Framebuffer, FramebufferRequest, NonNullPtr},
|
||||
|
@ -50,7 +53,6 @@ pub fn kmain(_cmdline: &str, boot_modules: BootModules) -> ! {
|
|||
let fb1: &NonNullPtr<Framebuffer> = &FB_REQ.get_response().get().unwrap().framebuffers()[0];
|
||||
|
||||
{
|
||||
use crate::alloc::string::ToString;
|
||||
let mut dt = DEVICE_TREE.lock();
|
||||
let mut disp = xml::XMLElement::new("display_0");
|
||||
|
||||
|
@ -58,7 +60,7 @@ pub fn kmain(_cmdline: &str, boot_modules: BootModules) -> ! {
|
|||
disp.set_attribute("height", fb1.height);
|
||||
disp.set_attribute("bpp", fb1.bpp);
|
||||
disp.set_attribute("pitch", fb1.pitch);
|
||||
dt.devices.insert("Displays".to_string(), alloc::vec![disp]);
|
||||
dt.devices.insert("Displays", alloc::vec![disp]);
|
||||
}
|
||||
debug!("Graphics initialised");
|
||||
debug!(
|
||||
|
@ -66,13 +68,24 @@ pub fn kmain(_cmdline: &str, boot_modules: BootModules) -> ! {
|
|||
fb1.address.as_ptr().unwrap() as *const u8
|
||||
);
|
||||
|
||||
let mut executor = crate::task::Executor::new(256);
|
||||
unsafe {
|
||||
let executor = LazyCell::<Executor>::force_mut(&mut EXECUTOR);
|
||||
for module in boot_modules.iter() {
|
||||
let cmd = module.cmd.trim_matches('"');
|
||||
let cmd_len = cmd.len() as u64;
|
||||
|
||||
log::info!("Spawning {} with arguments \"{}\"", module.path, cmd);
|
||||
log::info!(
|
||||
"Starting {}",
|
||||
module
|
||||
.path
|
||||
.split('/')
|
||||
.last()
|
||||
.unwrap()
|
||||
.split('.')
|
||||
.next()
|
||||
.unwrap()
|
||||
);
|
||||
log::debug!("Spawning {} with arguments \"{}\"", module.path, cmd);
|
||||
|
||||
// decode AbleOS Executable format
|
||||
let header = &module.bytes[0..46];
|
||||
|
@ -93,17 +106,17 @@ pub fn kmain(_cmdline: &str, boot_modules: BootModules) -> ! {
|
|||
let code_length = u64::from_le_bytes(header[7..15].try_into().unwrap());
|
||||
let data_length = u64::from_le_bytes(header[15..23].try_into().unwrap());
|
||||
let end = (code_length + data_length) as usize;
|
||||
log::info!("{code_length} + {data_length} = {end}");
|
||||
log::debug!("{code_length} + {data_length} = {end}");
|
||||
|
||||
let mut thr = ExecThread::new(&module.bytes[offset..end], Address::new(0));
|
||||
if cmd_len > 0 {
|
||||
thr.set_arguments(cmd.as_ptr() as u64, cmd_len);
|
||||
}
|
||||
executor.spawn(async move {
|
||||
executor.spawn(Box::pin(async move {
|
||||
if let Err(e) = thr.await {
|
||||
log::error!("{e:?}");
|
||||
}
|
||||
})
|
||||
}));
|
||||
}
|
||||
|
||||
debug!("Random number: {}", hardware_random_u64());
|
||||
|
@ -114,6 +127,10 @@ pub fn kmain(_cmdline: &str, boot_modules: BootModules) -> ! {
|
|||
crate::arch::spin_loop()
|
||||
}
|
||||
|
||||
// ! SAFETY: this is not threadsafe at all, like even a little bit.
|
||||
// ! SERIOUSLY
|
||||
pub static mut EXECUTOR: LazyCell<Executor> = LazyCell::new(|| Executor::new());
|
||||
|
||||
pub static DEVICE_TREE: Lazy<Mutex<DeviceTree>> = Lazy::new(|| {
|
||||
let dt = DeviceTree::new();
|
||||
Mutex::new(dt)
|
||||
|
|
|
@ -3,9 +3,11 @@
|
|||
//! 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]
|
||||
#![feature(
|
||||
slice_split_once,
|
||||
exclusive_wrapper,
|
||||
new_uninit,
|
||||
core_intrinsics,
|
||||
abi_x86_interrupt,
|
||||
lazy_get,
|
||||
alloc_error_handler,
|
||||
ptr_sub_ptr,
|
||||
custom_test_frameworks,
|
||||
|
@ -13,8 +15,7 @@
|
|||
pointer_is_aligned_to
|
||||
)]
|
||||
#![test_runner(crate::test_runner)]
|
||||
#![cfg_attr(not(debug_assertions), allow(unused, deprecated))]
|
||||
#![allow(dead_code)]
|
||||
#![allow(dead_code, internal_features, static_mut_refs)]
|
||||
extern crate alloc;
|
||||
|
||||
mod allocator;
|
||||
|
|
|
@ -36,13 +36,26 @@ impl log::Log for Logger {
|
|||
Level::Debug => "25",
|
||||
Level::Trace => "103",
|
||||
};
|
||||
let module = record.module_path().unwrap_or_default();
|
||||
let line = record.line().unwrap_or_default();
|
||||
crate::arch::log(format_args!(
|
||||
"\x1b[38;5;{lvl_color}m{lvl}\x1b[0m [{module}:{line}]: {}\r\n",
|
||||
record.args(),
|
||||
))
|
||||
.expect("write to serial console");
|
||||
let module = record
|
||||
.module_path()
|
||||
.unwrap_or_default()
|
||||
.rsplit_once(':')
|
||||
.unwrap_or_default()
|
||||
.1;
|
||||
if module == "" {
|
||||
crate::arch::log(format_args!(
|
||||
"\x1b[38;5;{lvl_color}m{lvl}\x1b[0m: {}\r\n",
|
||||
record.args(),
|
||||
))
|
||||
.expect("write to serial console");
|
||||
} else {
|
||||
let line = record.line().unwrap_or_default();
|
||||
crate::arch::log(format_args!(
|
||||
"\x1b[38;5;{lvl_color}m{lvl}\x1b[0m [{module}:{line}]: {}\r\n",
|
||||
record.args(),
|
||||
))
|
||||
.expect("write to serial console");
|
||||
}
|
||||
}
|
||||
|
||||
fn flush(&self) {}
|
||||
|
|
|
@ -29,24 +29,24 @@ pub fn yield_now() -> impl Future<Output = ()> {
|
|||
YieldNow(false)
|
||||
}
|
||||
|
||||
pub struct Executor<F: Future<Output = ()> + Send> {
|
||||
tasks: Slab<Task<F>>,
|
||||
pub struct Executor {
|
||||
tasks: Slab<Task>,
|
||||
task_queue: Arc<TaskQueue>,
|
||||
}
|
||||
|
||||
impl<F: Future<Output = ()> + Send> Executor<F> {
|
||||
pub fn new(size: usize) -> Self {
|
||||
impl Executor {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
tasks: Slab::with_capacity(size),
|
||||
tasks: Slab::new(),
|
||||
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 spawn(&mut self, future: Pin<Box<dyn Future<Output = ()> + Send>>) -> usize {
|
||||
let id = self.tasks.insert(Task::new(future));
|
||||
self.task_queue.queue.push(id);
|
||||
id
|
||||
}
|
||||
|
||||
pub fn run(&mut self) {
|
||||
|
@ -83,17 +83,17 @@ impl<F: Future<Output = ()> + Send> Executor<F> {
|
|||
}
|
||||
}
|
||||
|
||||
struct Task<F: Future<Output = ()> + Send> {
|
||||
future: Pin<Box<F>>,
|
||||
struct Task {
|
||||
future: Pin<Box<dyn Future<Output = ()> + Send>>,
|
||||
waker: Option<TaskWaker>,
|
||||
}
|
||||
|
||||
impl<F: Future<Output = ()> + Send> Task<F> {
|
||||
impl Task {
|
||||
#[inline(always)]
|
||||
pub fn new(future: F) -> Self {
|
||||
pub fn new(future: Pin<Box<dyn Future<Output = ()> + Send>>) -> Self {
|
||||
Self {
|
||||
future: Box::pin(future),
|
||||
waker: None,
|
||||
future,
|
||||
waker: None,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
/// Used when tab `\t` in hardware is not known and we will default to two spaces
|
||||
pub const TAB: &str = " ";
|
||||
|
||||
|
||||
// NOTE: this only reduces the code duplication in source code not in generated code!
|
||||
// Written by Yours Truly: Munir
|
||||
/// A simple macro to reduce code duplication when we use TAB internally
|
||||
|
@ -12,7 +11,7 @@ pub const TAB: &str = " ";
|
|||
macro_rules! tab {
|
||||
($num:expr) => {
|
||||
TAB.repeat($num)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// NOTE: this only reduces the code duplication in source code not in generated code!
|
||||
|
@ -22,7 +21,7 @@ macro_rules! tab {
|
|||
macro_rules! device_tree {
|
||||
($devtree:expr, $dev_type_vec:expr) => {
|
||||
for each_device_type in $dev_type_vec {
|
||||
$devtree.devices.insert(each_device_type.to_string(), Vec::new());
|
||||
$devtree.devices.insert(each_device_type, Vec::new());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"arch": "aarch64",
|
||||
"data-layout": "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128",
|
||||
"data-layout": "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32",
|
||||
"disable-redzone": true,
|
||||
"env": "",
|
||||
"executables": true,
|
||||
|
|
|
@ -1,22 +1,22 @@
|
|||
{
|
||||
"llvm-target": "x86_64-unknown-none",
|
||||
"data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128",
|
||||
"arch": "x86_64",
|
||||
"target-endian": "little",
|
||||
"target-pointer-width": "64",
|
||||
"target-c-int-width": "32",
|
||||
"os": "none",
|
||||
"executables": true,
|
||||
"linker-flavor": "ld.lld",
|
||||
"linker": "rust-lld",
|
||||
"panic-strategy": "abort",
|
||||
"disable-redzone": true,
|
||||
"features": "",
|
||||
"code-model": "kernel",
|
||||
"pre-link-args": {
|
||||
"ld.lld": [
|
||||
"--gc-sections",
|
||||
"--script=kernel/lds/x86_64.ld"
|
||||
]
|
||||
}
|
||||
"llvm-target": "x86_64-unknown-none",
|
||||
"data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128",
|
||||
"arch": "x86_64",
|
||||
"target-endian": "little",
|
||||
"target-pointer-width": "64",
|
||||
"target-c-int-width": "32",
|
||||
"os": "none",
|
||||
"executables": true,
|
||||
"linker-flavor": "ld.lld",
|
||||
"linker": "rust-lld",
|
||||
"panic-strategy": "abort",
|
||||
"disable-redzone": true,
|
||||
"features": "",
|
||||
"code-model": "kernel",
|
||||
"pre-link-args": {
|
||||
"ld.lld": [
|
||||
"--gc-sections",
|
||||
"--script=kernel/lds/x86_64.ld"
|
||||
]
|
||||
}
|
||||
}
|
22
kernel/targets/x86_64_v3-ableos.json
Normal file
22
kernel/targets/x86_64_v3-ableos.json
Normal file
|
@ -0,0 +1,22 @@
|
|||
{
|
||||
"llvm-target": "x86_64-unknown-none",
|
||||
"data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128",
|
||||
"arch": "x86_64",
|
||||
"target-endian": "little",
|
||||
"target-pointer-width": "64",
|
||||
"target-c-int-width": "32",
|
||||
"os": "none",
|
||||
"executables": true,
|
||||
"linker-flavor": "ld.lld",
|
||||
"linker": "rust-lld",
|
||||
"panic-strategy": "abort",
|
||||
"disable-redzone": true,
|
||||
"features": "+sse4.1,+avx,+aes,+fma,+popcnt,+bmi2,+avx2,+lzcnt,+xsave",
|
||||
"code-model": "kernel",
|
||||
"pre-link-args": {
|
||||
"ld.lld": [
|
||||
"--gc-sections",
|
||||
"--script=kernel/lds/x86_64.ld"
|
||||
]
|
||||
}
|
||||
}
|
2
known_bugs.md
Normal file
2
known_bugs.md
Normal file
|
@ -0,0 +1,2 @@
|
|||
# i did not know where to put this
|
||||
- memcpy / memset cause crash on debug builds due to ptr misalignment that is not present on release builds
|
|
@ -6,24 +6,15 @@ edition = "2021"
|
|||
[dependencies]
|
||||
str-reader = "0.1"
|
||||
derive_more = { version = "1", default-features = false, features = [
|
||||
"add",
|
||||
"add_assign",
|
||||
"constructor",
|
||||
"display",
|
||||
"from",
|
||||
"into",
|
||||
"mul",
|
||||
"mul_assign",
|
||||
"not",
|
||||
"sum",
|
||||
"display",
|
||||
] }
|
||||
error-stack = "0.5"
|
||||
fatfs = "0.3"
|
||||
fatfs = { version = "0.3", default-features = false, features = [
|
||||
"std",
|
||||
"alloc",
|
||||
] }
|
||||
toml = "0.8"
|
||||
# hbasm.git = "https://git.ablecorp.us/AbleOS/holey-bytes.git"
|
||||
hblang.git = "https://git.ablecorp.us/AbleOS/holey-bytes.git"
|
||||
|
||||
[dependencies.reqwest]
|
||||
version = "0.12"
|
||||
default-features = false
|
||||
features = ["rustls-tls", "blocking"]
|
||||
log = "0.4"
|
||||
raw-cpuid = "11"
|
||||
ureq = { version = "2", default-features = false, features = ["tls"] }
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#![allow(unused)]
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
fmt::format,
|
||||
fs::{read_to_string, File},
|
||||
io::{BufWriter, Write},
|
||||
|
@ -13,6 +14,7 @@ pub struct Package {
|
|||
name: String,
|
||||
binaries: Vec<String>,
|
||||
build_cmd: String,
|
||||
args: HashMap<String, String>,
|
||||
}
|
||||
|
||||
impl Package {
|
||||
|
@ -46,57 +48,79 @@ impl Package {
|
|||
let mut binaries = vec![];
|
||||
|
||||
for (count, (name, table)) in bin_table.into_iter().enumerate() {
|
||||
// if count != 0 {
|
||||
println!("{}", name);
|
||||
binaries.push(name.clone());
|
||||
// }
|
||||
}
|
||||
let build_table = data.get("build").unwrap();
|
||||
|
||||
let mut build_cmd: String = build_table.get("command").unwrap().as_str().unwrap().into();
|
||||
build_cmd.remove(0);
|
||||
// build_cmd.pop();
|
||||
let mut args: HashMap<String, String> = match build_table.get("args") {
|
||||
None => HashMap::new(),
|
||||
Some(v) => v
|
||||
.as_table()
|
||||
.unwrap()
|
||||
.into_iter()
|
||||
.map(|(k, v)| (k.clone(), v.to_string()))
|
||||
.collect::<HashMap<String, String>>(),
|
||||
};
|
||||
|
||||
Self {
|
||||
name,
|
||||
binaries,
|
||||
build_cmd,
|
||||
args,
|
||||
}
|
||||
}
|
||||
pub fn build(&self) {
|
||||
pub fn build(&self, out: &mut Vec<u8>) -> std::io::Result<()> {
|
||||
if self.binaries.contains(&"hblang".to_string()) {
|
||||
let file = self.build_cmd.split_ascii_whitespace().last().unwrap();
|
||||
|
||||
let path = format!("sysdata/programs/{}/{}", self.name, file);
|
||||
let mut bytes = Vec::new();
|
||||
// compile here
|
||||
|
||||
let _ = hblang::run_compiler(
|
||||
let mut warnings = String::new();
|
||||
|
||||
hblang::run_compiler(
|
||||
&path,
|
||||
Options {
|
||||
fmt: true,
|
||||
in_house_regalloc: true,
|
||||
..Default::default()
|
||||
},
|
||||
&mut bytes,
|
||||
);
|
||||
let _ = hblang::run_compiler(&path, Default::default(), &mut bytes);
|
||||
out,
|
||||
&mut warnings,
|
||||
)?;
|
||||
|
||||
match std::fs::create_dir("target/programs") {
|
||||
Ok(_) => (),
|
||||
Err(e) if e.kind() == std::io::ErrorKind::AlreadyExists => (),
|
||||
Err(e) => panic!("{}", e),
|
||||
}
|
||||
std::fs::write(format!("target/programs/{}.hbf", self.name), &bytes).unwrap();
|
||||
bytes.clear();
|
||||
let _ = hblang::run_compiler(
|
||||
|
||||
hblang::run_compiler(
|
||||
&path,
|
||||
Options {
|
||||
in_house_regalloc: true,
|
||||
..Default::default()
|
||||
},
|
||||
out,
|
||||
&mut warnings,
|
||||
)?;
|
||||
std::fs::write(format!("target/programs/{}.hbf", self.name), &out)?;
|
||||
out.clear();
|
||||
|
||||
hblang::run_compiler(
|
||||
&path,
|
||||
Options {
|
||||
dump_asm: true,
|
||||
in_house_regalloc: true,
|
||||
..Default::default()
|
||||
},
|
||||
&mut bytes,
|
||||
);
|
||||
std::fs::write(format!("target/programs/{}.hba", self.name), &bytes).unwrap();
|
||||
out,
|
||||
&mut warnings,
|
||||
)?;
|
||||
std::fs::write(format!("target/programs/{}.hba", self.name), &out)?;
|
||||
out.clear();
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,18 +1,16 @@
|
|||
// #![allow(unused)]
|
||||
|
||||
mod dev;
|
||||
|
||||
use {
|
||||
core::fmt::Write as _,
|
||||
derive_more::Display,
|
||||
dev::Package,
|
||||
error_stack::{bail, report, Context, Report, Result, ResultExt},
|
||||
fatfs::{FileSystem, FormatVolumeOptions, FsOptions, ReadWriteSeek},
|
||||
std::{
|
||||
// fmt::Display,
|
||||
fs::{self, File},
|
||||
io::{self, Write},
|
||||
path::Path,
|
||||
process::{exit, Command},
|
||||
process::{exit, Command, Stdio},
|
||||
},
|
||||
toml::Value,
|
||||
};
|
||||
|
@ -21,6 +19,9 @@ fn main() -> Result<(), Error> {
|
|||
let mut args = std::env::args();
|
||||
args.next();
|
||||
|
||||
log::set_logger(&hblang::Logger).unwrap();
|
||||
log::set_max_level(log::LevelFilter::Error);
|
||||
|
||||
match args.next().as_deref() {
|
||||
Some("build" | "b") => {
|
||||
let mut release = false;
|
||||
|
@ -35,6 +36,8 @@ fn main() -> Result<(), Error> {
|
|||
target = Target::Riscv64Virt;
|
||||
} else if arg == "arm64" || arg == "aarch64" || arg == "aarch64-virt" {
|
||||
target = Target::Aarch64;
|
||||
} else if arg == "avx2" {
|
||||
target = Target::X86_64Avx2;
|
||||
} else {
|
||||
return Err(report!(Error::InvalidSubCom));
|
||||
}
|
||||
|
@ -46,6 +49,7 @@ fn main() -> Result<(), Error> {
|
|||
let mut release = false;
|
||||
let mut debuginfo = false;
|
||||
let mut target = Target::X86_64;
|
||||
let mut do_accel = true;
|
||||
for arg in args {
|
||||
if arg == "-r" || arg == "--release" {
|
||||
release = true;
|
||||
|
@ -55,13 +59,17 @@ fn main() -> Result<(), Error> {
|
|||
target = Target::Riscv64Virt;
|
||||
} else if arg == "arm64" || arg == "aarch64" || arg == "aarch64-virt" {
|
||||
target = Target::Aarch64;
|
||||
} else if arg == "--noaccel" {
|
||||
do_accel = false;
|
||||
} else if arg == "avx2" {
|
||||
target = Target::X86_64Avx2;
|
||||
} else {
|
||||
return Err(report!(Error::InvalidSubCom));
|
||||
}
|
||||
}
|
||||
|
||||
build(release, target, debuginfo)?;
|
||||
run(release, target)
|
||||
run(release, target, do_accel)
|
||||
}
|
||||
Some("help" | "h") => {
|
||||
println!(concat!(
|
||||
|
@ -71,8 +79,10 @@ fn main() -> Result<(), Error> {
|
|||
" help (h): Print this message\n",
|
||||
" run (r): Build and run AbleOS in QEMU\n\n",
|
||||
"Options for build and run:\n",
|
||||
" -r: build in release mode",
|
||||
" [target]: sets target"
|
||||
" -r / --release: build in release mode\n",
|
||||
" -d / --debuginfo: build with debug info\n",
|
||||
" --noaccel: run without acceleration (e.g, no kvm)\n",
|
||||
"[ rv64 / riscv64 / riscv64-virt / aarch64 / arm64 / aarch64-virt / avx2 ]: sets target"
|
||||
),);
|
||||
Ok(())
|
||||
}
|
||||
|
@ -195,21 +205,43 @@ TERM_BACKDROP={}
|
|||
let modules = value.get_mut("modules").unwrap().as_table_mut().unwrap();
|
||||
// let mut real_modules = modules.clone();
|
||||
|
||||
modules.into_iter().for_each(|(_, value)| {
|
||||
if value.is_table() {
|
||||
let path = get_path_without_boot_prefix(
|
||||
value.get("path").expect("You must have `path` as a value"),
|
||||
)
|
||||
.unwrap()
|
||||
.split(".")
|
||||
.next()
|
||||
.unwrap();
|
||||
let p = Package::load_from_file(
|
||||
format!("sysdata/programs/{}/meta.toml", path).to_owned(),
|
||||
);
|
||||
p.build();
|
||||
}
|
||||
});
|
||||
let mut errors = String::new();
|
||||
let mut out = Vec::new();
|
||||
|
||||
modules
|
||||
.into_iter()
|
||||
.map(|(_, value)| -> Result<(), io::Error> {
|
||||
if value.is_table() {
|
||||
let path = get_path_without_boot_prefix(
|
||||
value.get("path").expect("You must have `path` as a value"),
|
||||
)
|
||||
.unwrap()
|
||||
.split(".")
|
||||
.next()
|
||||
.unwrap();
|
||||
let p = Package::load_from_file(
|
||||
format!("sysdata/programs/{}/meta.toml", path).to_owned(),
|
||||
);
|
||||
match p.build(&mut out) {
|
||||
Ok(()) => {}
|
||||
Err(_) => {
|
||||
writeln!(errors, "========= while compiling {} =========", path)
|
||||
.unwrap();
|
||||
errors.push_str(core::str::from_utf8(&out).expect("no"));
|
||||
out.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
})
|
||||
.for_each(drop);
|
||||
|
||||
if !errors.is_empty() {
|
||||
let _ = writeln!(errors, "!!! STOPPING DUE TO PREVIOUS ERRORS !!!");
|
||||
std::eprint!("{errors}");
|
||||
continue;
|
||||
}
|
||||
|
||||
modules.into_iter().for_each(|(_key, value)| {
|
||||
if value.is_table() {
|
||||
let path = value.get("path").expect("You must have `path` as a value");
|
||||
|
@ -296,6 +328,9 @@ fn build(release: bool, target: Target, debuginfo: bool) -> Result<(), Error> {
|
|||
if target == Target::Aarch64 {
|
||||
com.args(["--target", "targets/aarch64-virt-ableos.json"]);
|
||||
}
|
||||
if target == Target::X86_64Avx2 {
|
||||
com.args(["--target", "targets/x86_64_v3-ableos.json"]);
|
||||
}
|
||||
|
||||
match com.status() {
|
||||
Ok(s) if s.code() != Some(0) => bail!(Error::Build),
|
||||
|
@ -309,6 +344,10 @@ fn build(release: bool, target: Target, debuginfo: bool) -> Result<(), Error> {
|
|||
path.push_str("_x86-64");
|
||||
"target/x86_64-ableos"
|
||||
}
|
||||
Target::X86_64Avx2 => {
|
||||
path.push_str("_x86-64");
|
||||
"target/x86_64_v3-ableos"
|
||||
}
|
||||
Target::Riscv64Virt => "target/riscv64-virt-ableos",
|
||||
Target::Aarch64 => {
|
||||
path.push_str("_aarch64");
|
||||
|
@ -331,25 +370,67 @@ fn build(release: bool, target: Target, debuginfo: bool) -> Result<(), Error> {
|
|||
.change_context(Error::Io)
|
||||
}
|
||||
|
||||
fn run(release: bool, target: Target) -> Result<(), Error> {
|
||||
let mut com = match target {
|
||||
Target::X86_64 => Command::new("qemu-system-x86_64"),
|
||||
Target::Riscv64Virt => Command::new("qemu-system-riscv64"),
|
||||
Target::Aarch64 => Command::new("qemu-system-aarch64"),
|
||||
fn run(release: bool, target: Target, do_accel: bool) -> Result<(), Error> {
|
||||
let target_str = match target {
|
||||
Target::X86_64 | Target::X86_64Avx2 => "qemu-system-x86_64",
|
||||
Target::Riscv64Virt => "qemu-system-riscv64",
|
||||
Target::Aarch64 => "qemu-system-aarch64",
|
||||
};
|
||||
let (mut com, mut com2) = (Command::new(target_str), Command::new(target_str));
|
||||
let ovmf_path = fetch_ovmf(target);
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
let accel = if do_accel {
|
||||
let supported = String::from_utf8(
|
||||
com2.args(["--accel", "help"])
|
||||
.stdout(Stdio::piped())
|
||||
.stderr(Stdio::piped())
|
||||
.spawn()
|
||||
.unwrap()
|
||||
.wait_with_output()
|
||||
.unwrap()
|
||||
.stdout,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let cpuid = raw_cpuid::CpuId::new();
|
||||
let vmx = cpuid.get_feature_info().unwrap().has_vmx();
|
||||
let svm = cpuid.get_svm_info().is_some();
|
||||
|
||||
if supported.contains("kvm") && (vmx || svm) {
|
||||
"accel=kvm"
|
||||
} else if cpuid
|
||||
.get_processor_brand_string()
|
||||
.filter(|a| a.as_str() == "GenuineIntel")
|
||||
.is_some()
|
||||
&& supported.contains("hax")
|
||||
&& vmx
|
||||
{
|
||||
"accel=hax"
|
||||
} else if supported.contains("whpx") {
|
||||
"accel=whpx"
|
||||
} else {
|
||||
"accel=tcg"
|
||||
}
|
||||
} else {
|
||||
"accel=tcg"
|
||||
};
|
||||
#[cfg(not(target_arch = "x86_64"))]
|
||||
let accel = "accel=tcg";
|
||||
|
||||
match target {
|
||||
Target::X86_64 => {
|
||||
Target::X86_64 | Target::X86_64Avx2 => {
|
||||
#[rustfmt::skip]
|
||||
com.args([
|
||||
"-bios", &ovmf_path.change_context(Error::OvmfFetch)?,
|
||||
"-drive", "file=target/disk.img,format=raw",
|
||||
// "-device", "vmware-svga",
|
||||
"-device", "vmware-svga",
|
||||
// "-serial", "stdio",
|
||||
"-m", "2G",
|
||||
"-smp", "1",
|
||||
// "-machine", "accel=kvm",
|
||||
"-cpu", "Broadwell",
|
||||
"-parallel", "none",
|
||||
"-monitor", "none",
|
||||
"-machine", accel,
|
||||
"-cpu", "max",
|
||||
"-device", "isa-debug-exit,iobase=0xf4,iosize=0x04",
|
||||
]);
|
||||
}
|
||||
|
@ -394,7 +475,7 @@ fn run(release: bool, target: Target) -> Result<(), Error> {
|
|||
|
||||
fn fetch_ovmf(target: Target) -> Result<String, OvmfFetchError> {
|
||||
let (ovmf_url, ovmf_path) = match target {
|
||||
Target::X86_64 => (
|
||||
Target::X86_64 | Target::X86_64Avx2 => (
|
||||
"https://retrage.github.io/edk2-nightly/bin/RELEASEX64_OVMF.fd",
|
||||
"target/RELEASEX64_OVMF.fd",
|
||||
),
|
||||
|
@ -416,12 +497,12 @@ fn fetch_ovmf(target: Target) -> Result<String, OvmfFetchError> {
|
|||
Ok(_) => return Ok(ovmf_path.to_owned()),
|
||||
Err(e) => return Err(report!(e).change_context(OvmfFetchError::Io)),
|
||||
};
|
||||
let mut bytes = reqwest::blocking::get(ovmf_url)
|
||||
let req = ureq::get(ovmf_url)
|
||||
.call()
|
||||
.map_err(Report::from)
|
||||
.change_context(OvmfFetchError::Fetch)?;
|
||||
|
||||
bytes
|
||||
.copy_to(&mut file)
|
||||
std::io::copy(&mut req.into_reader(), &mut file)
|
||||
.map_err(Report::from)
|
||||
.change_context(OvmfFetchError::Io)?;
|
||||
|
||||
|
@ -443,6 +524,7 @@ impl Context for OvmfFetchError {}
|
|||
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||
enum Target {
|
||||
X86_64,
|
||||
X86_64Avx2,
|
||||
Riscv64Virt,
|
||||
Aarch64,
|
||||
}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
[toolchain]
|
||||
channel = "nightly-2024-07-27"
|
||||
# old toolchain
|
||||
# channel = "nightly-2024-07-27"
|
||||
channel = "nightly"
|
||||
components = ["rust-src", "llvm-tools"]
|
||||
|
|
BIN
sysdata/assets/able.bmp
Normal file
BIN
sysdata/assets/able.bmp
Normal file
Binary file not shown.
After Width: | Height: | Size: 100 KiB |
BIN
sysdata/assets/consolefonts/tamsyn/10x20b.psf
Normal file
BIN
sysdata/assets/consolefonts/tamsyn/10x20b.psf
Normal file
Binary file not shown.
BIN
sysdata/assets/consolefonts/tamsyn/10x20r.psf
Normal file
BIN
sysdata/assets/consolefonts/tamsyn/10x20r.psf
Normal file
Binary file not shown.
BIN
sysdata/assets/consolefonts/tamsyn/5x9b.psf
Normal file
BIN
sysdata/assets/consolefonts/tamsyn/5x9b.psf
Normal file
Binary file not shown.
BIN
sysdata/assets/consolefonts/tamsyn/5x9r.psf
Normal file
BIN
sysdata/assets/consolefonts/tamsyn/5x9r.psf
Normal file
Binary file not shown.
BIN
sysdata/assets/consolefonts/tamsyn/6x12b.psf
Normal file
BIN
sysdata/assets/consolefonts/tamsyn/6x12b.psf
Normal file
Binary file not shown.
BIN
sysdata/assets/consolefonts/tamsyn/6x12r.psf
Normal file
BIN
sysdata/assets/consolefonts/tamsyn/6x12r.psf
Normal file
Binary file not shown.
BIN
sysdata/assets/consolefonts/tamsyn/7x13b.psf
Normal file
BIN
sysdata/assets/consolefonts/tamsyn/7x13b.psf
Normal file
Binary file not shown.
BIN
sysdata/assets/consolefonts/tamsyn/7x13r.psf
Normal file
BIN
sysdata/assets/consolefonts/tamsyn/7x13r.psf
Normal file
Binary file not shown.
BIN
sysdata/assets/consolefonts/tamsyn/7x14b.psf
Normal file
BIN
sysdata/assets/consolefonts/tamsyn/7x14b.psf
Normal file
Binary file not shown.
BIN
sysdata/assets/consolefonts/tamsyn/7x14r.psf
Normal file
BIN
sysdata/assets/consolefonts/tamsyn/7x14r.psf
Normal file
Binary file not shown.
BIN
sysdata/assets/consolefonts/tamsyn/8x15b.psf
Normal file
BIN
sysdata/assets/consolefonts/tamsyn/8x15b.psf
Normal file
Binary file not shown.
BIN
sysdata/assets/consolefonts/tamsyn/8x15r.psf
Normal file
BIN
sysdata/assets/consolefonts/tamsyn/8x15r.psf
Normal file
Binary file not shown.
BIN
sysdata/assets/consolefonts/tamsyn/8x16b.psf
Normal file
BIN
sysdata/assets/consolefonts/tamsyn/8x16b.psf
Normal file
Binary file not shown.
BIN
sysdata/assets/consolefonts/tamsyn/8x16r.psf
Normal file
BIN
sysdata/assets/consolefonts/tamsyn/8x16r.psf
Normal file
Binary file not shown.
10
sysdata/assets/consolefonts/tamsyn/LICENSE
Normal file
10
sysdata/assets/consolefonts/tamsyn/LICENSE
Normal file
|
@ -0,0 +1,10 @@
|
|||
Tamsyn font is free. You are hereby granted permission to use, copy, modify,
|
||||
and distribute it as you see fit.
|
||||
|
||||
Tamsyn font is provided "as is" without any express or implied warranty.
|
||||
|
||||
The author makes no representations about the suitability of this font for
|
||||
a particular purpose.
|
||||
|
||||
In no event will the author be held liable for damages arising from the use
|
||||
of this font.
|
BIN
sysdata/assets/mini.bmp
Normal file
BIN
sysdata/assets/mini.bmp
Normal file
Binary file not shown.
After Width: | Height: | Size: 100 KiB |
BIN
sysdata/assets/mini.qoi
Normal file
BIN
sysdata/assets/mini.qoi
Normal file
Binary file not shown.
BIN
sysdata/assets/wallpaper.qoi
Normal file
BIN
sysdata/assets/wallpaper.qoi
Normal file
Binary file not shown.
BIN
sysdata/empty-background.bmp
Normal file
BIN
sysdata/empty-background.bmp
Normal file
Binary file not shown.
After Width: | Height: | Size: 66 B |
|
@ -1 +0,0 @@
|
|||
# dt_api
|
|
@ -1,8 +0,0 @@
|
|||
stn := @use("../../stn/src/lib.hb");
|
||||
.{string, memory, buffer} := stn
|
||||
|
||||
dt_get := fn(query: ^u8): int {
|
||||
message_length := string.length(query)
|
||||
|
||||
return @eca(3, 5, query, message_length)
|
||||
}
|
4
sysdata/libraries/horizon_api/examples/horizontal.lui
Normal file
4
sysdata/libraries/horizon_api/examples/horizontal.lui
Normal file
|
@ -0,0 +1,4 @@
|
|||
(horizontal
|
||||
spacing : 10
|
||||
(label "hi")
|
||||
(label "goodbye"))
|
1
sysdata/libraries/horizon_api/examples/label.lui
Normal file
1
sysdata/libraries/horizon_api/examples/label.lui
Normal file
|
@ -0,0 +1 @@
|
|||
(label "hello")
|
3
sysdata/libraries/horizon_api/examples/vertical.lui
Normal file
3
sysdata/libraries/horizon_api/examples/vertical.lui
Normal file
|
@ -0,0 +1,3 @@
|
|||
(vertical
|
||||
(label "hello")
|
||||
(label "hello" color:red))
|
|
@ -1,25 +1,49 @@
|
|||
stn := @use("../../stn/src/lib.hb");
|
||||
.{string, memory, buffer} := stn
|
||||
.{string, memory, buffer, log} := stn
|
||||
|
||||
render := @use("../../../libraries/render/src/lib.hb")
|
||||
|
||||
input := @use("../../intouch/src/lib.hb")
|
||||
|
||||
widgets := @use("widgets/widgets.hb")
|
||||
ui := @use("ui.hb")
|
||||
|
||||
WindowID := struct {
|
||||
host_id: int,
|
||||
window_id: int,
|
||||
}
|
||||
|
||||
create_window := fn(channel: int): void {
|
||||
VoidWindowID := WindowID.(0, 0)
|
||||
|
||||
create_window := fn(channel: int): ^render.Surface {
|
||||
// get the horizon buffer
|
||||
// request a new window and provide the callback buffer
|
||||
// wait to recieve a message
|
||||
|
||||
windowing_system_buffer := buffer.search("XHorizon\0")
|
||||
mem_buf := memory.request_page(1)
|
||||
|
||||
if windowing_system_buffer == 0 {
|
||||
return
|
||||
return @as(^render.Surface, idk)
|
||||
} else {
|
||||
msg := "\{01}\0"
|
||||
msg_length := 2
|
||||
return @eca(3, windowing_system_buffer, msg, msg_length)
|
||||
// ! 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
|
||||
|
||||
ret := buffer.recv([u8; 4096], windowing_system_buffer, mem_buf)
|
||||
if ret == null {
|
||||
log.info("No messages\0")
|
||||
}
|
||||
|
||||
if *mem_buf == 0 {
|
||||
log.info("No messages\0")
|
||||
}
|
||||
|
||||
return @as(^render.Surface, idk)
|
||||
}
|
||||
}
|
47
sysdata/libraries/horizon_api/src/ui.hb
Normal file
47
sysdata/libraries/horizon_api/src/ui.hb
Normal file
|
@ -0,0 +1,47 @@
|
|||
stn := @use("../../../libraries/stn/src/lib.hb");
|
||||
.{string, log} := stn;
|
||||
.{Vec2} := stn.math
|
||||
|
||||
render := @use("../../../libraries/render/src/lib.hb");
|
||||
.{Surface} := render;
|
||||
.{Font} := render.text
|
||||
|
||||
UI := struct {raw: ^u8, raw_length: uint, is_dirty: bool, surface: Surface, // Each child has their WidgetType as their first byte
|
||||
// children: ^^u8,
|
||||
}
|
||||
|
||||
render_ui := fn(surface: Surface, ui: UI): void {
|
||||
if ui.is_dirty {
|
||||
render.clear(ui.surface, render.black)
|
||||
ui.is_dirty = false
|
||||
}
|
||||
pos := Vec2(uint).(0, 0)
|
||||
render.put_surface(surface, ui.surface, pos, false)
|
||||
}
|
||||
|
||||
sexpr_parser := fn(sexpr: ^u8): UI {
|
||||
cursor := sexpr
|
||||
paren_balance := 0
|
||||
loop {
|
||||
if *cursor == 0 {
|
||||
if paren_balance != 0 {
|
||||
log.error("Unbalanced Parens\0")
|
||||
}
|
||||
break
|
||||
} else if *cursor == 40 {
|
||||
log.info("Open paren\0")
|
||||
paren_balance += 1
|
||||
} else if *cursor == 41 {
|
||||
log.info("Closed paren\0")
|
||||
paren_balance -= 1
|
||||
}
|
||||
|
||||
cursor += 1
|
||||
}
|
||||
|
||||
length := string.length(sexpr)
|
||||
|
||||
ui_surface := render.new_surface(100, 100)
|
||||
|
||||
return UI.(sexpr, length, true, ui_surface)
|
||||
}
|
13
sysdata/libraries/horizon_api/src/widgets/image.hb
Normal file
13
sysdata/libraries/horizon_api/src/widgets/image.hb
Normal file
|
@ -0,0 +1,13 @@
|
|||
render := @use("../../../../libraries/render/src/lib.hb");
|
||||
.{Surface} := render
|
||||
|
||||
Image := struct {
|
||||
magic: uint,
|
||||
is_dirty: bool,
|
||||
surface: Surface,
|
||||
}
|
||||
|
||||
image_from_surface := fn(surface: Surface): Image {
|
||||
img := Image.(4, true, surface)
|
||||
return img
|
||||
}
|
46
sysdata/libraries/horizon_api/src/widgets/label.hb
Normal file
46
sysdata/libraries/horizon_api/src/widgets/label.hb
Normal file
|
@ -0,0 +1,46 @@
|
|||
stn := @use("../../../../libraries/stn/src/lib.hb");
|
||||
.{string, log} := stn;
|
||||
.{Vec2} := stn.math
|
||||
|
||||
render := @use("../../../../libraries/render/src/lib.hb");
|
||||
.{Surface, Color} := render;
|
||||
.{Font} := render.text
|
||||
|
||||
Label := struct {
|
||||
magic: uint,
|
||||
is_dirty: bool,
|
||||
surface: Surface,
|
||||
text: ^u8,
|
||||
text_length: uint,
|
||||
bg: Color,
|
||||
fg: Color,
|
||||
}
|
||||
|
||||
set_label_text := fn(label: Label, text: ^u8): void {
|
||||
text_length := string.length(text)
|
||||
|
||||
label.is_dirty = true
|
||||
label.text = text
|
||||
label.text_length = text_length
|
||||
}
|
||||
|
||||
render_label_to_surface := fn(surface: Surface, label: Label, font: Font, pos: Vec2(uint)): void {
|
||||
if label.is_dirty {
|
||||
render.clear(label.surface, label.bg)
|
||||
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
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
NoWidget := 0
|
||||
|
||||
VerticalWidgetType := 1
|
||||
HorizontalWidgetType := 2
|
||||
|
||||
LabelWidgetType := 3
|
||||
ImageWidgetType := 4
|
36
sysdata/libraries/horizon_api/src/widgets/widgets.hb
Normal file
36
sysdata/libraries/horizon_api/src/widgets/widgets.hb
Normal file
|
@ -0,0 +1,36 @@
|
|||
// Widget types
|
||||
|
||||
// End types
|
||||
stn := @use("../../../../libraries/stn/src/lib.hb");
|
||||
.{string, log} := stn;
|
||||
.{Vec2} := stn.math
|
||||
|
||||
render := @use("../../../../libraries/render/src/lib.hb");
|
||||
.{Surface} := render;
|
||||
.{Font} := render.text
|
||||
|
||||
widget_types := @use("widget_types.hb")
|
||||
label := @use("label.hb")
|
||||
image := @use("image.hb")
|
||||
|
||||
Size := struct {
|
||||
min_width: int,
|
||||
max_width: int,
|
||||
min_height: int,
|
||||
max_height: int,
|
||||
}
|
||||
|
||||
Vertical := packed struct {
|
||||
magic: uint,
|
||||
// array of children, idk
|
||||
// use a vec or linked list or whatever
|
||||
|
||||
children: ^^u8,
|
||||
}
|
||||
|
||||
Horizontal := packed struct {
|
||||
magic: uint,
|
||||
// array of children, idk
|
||||
// use a vec or linked list or whatever
|
||||
children: ^^u8,
|
||||
}
|
|
@ -7,7 +7,7 @@ ApplicationInfo := struct {
|
|||
pNext: ^int,
|
||||
application_name: ^u8,
|
||||
application_version: int,
|
||||
engine_name: int,
|
||||
engine_name: ^u8,
|
||||
engine_version: int,
|
||||
api_version: int,
|
||||
}
|
||||
|
|
18
sysdata/libraries/intouch/src/events.hb
Normal file
18
sysdata/libraries/intouch/src/events.hb
Normal file
|
@ -0,0 +1,18 @@
|
|||
keycodes := @use("keycodes.hb");
|
||||
.{KeyCode} := keycodes
|
||||
|
||||
KeyEvent := packed struct {
|
||||
up: bool,
|
||||
just_triggered: bool,
|
||||
key: KeyCode,
|
||||
}
|
||||
|
||||
MouseEvent := packed struct {
|
||||
x_change: i8,
|
||||
y_change: i8,
|
||||
left: bool,
|
||||
middle: bool,
|
||||
right: bool,
|
||||
}
|
||||
|
||||
GamepadEvent := struct {}
|
|
@ -1,67 +1,121 @@
|
|||
/*
|
||||
Originally I was modelling this after the following(1). I have since changed my mind.
|
||||
I am now modelling it as I see fit. This is likely not the final version.
|
||||
|
||||
1) https://www.libsdl.org/release/SDL-1.2.15/include/SDL_keysym.h
|
||||
*/
|
||||
|
||||
KeyCode := u32
|
||||
|
||||
// https://www.libsdl.org/release/SDL-1.2.15/include/SDL_keysym.h
|
||||
Backspace := KeyCode.(8)
|
||||
Tab := KeyCode.(9)
|
||||
Clear := KeyCode.(12)
|
||||
Return := KeyCode.(13)
|
||||
Pause := KeyCode.(19)
|
||||
Escape := KeyCode.(27)
|
||||
Space := KeyCode.(32)
|
||||
// Typically this is not a keycode you will ever recieve.
|
||||
None := KeyCode.(0)
|
||||
|
||||
A := KeyCode.(97)
|
||||
/*
|
||||
ETC
|
||||
*/
|
||||
Z := KeyCode.(122)
|
||||
Escape := KeyCode.(1)
|
||||
/* Alphabet keycodes */
|
||||
|
||||
Delete := KeyCode.(127)
|
||||
A := KeyCode.(2)
|
||||
B := KeyCode.(3)
|
||||
C := KeyCode.(4)
|
||||
D := KeyCode.(5)
|
||||
E := KeyCode.(6)
|
||||
F := KeyCode.(7)
|
||||
G := KeyCode.(8)
|
||||
H := KeyCode.(9)
|
||||
I := KeyCode.(10)
|
||||
J := KeyCode.(11)
|
||||
K := KeyCode.(12)
|
||||
L := KeyCode.(13)
|
||||
M := KeyCode.(14)
|
||||
N := KeyCode.(15)
|
||||
O := KeyCode.(16)
|
||||
P := KeyCode.(17)
|
||||
Q := KeyCode.(18)
|
||||
R := KeyCode.(19)
|
||||
S := KeyCode.(20)
|
||||
T := KeyCode.(21)
|
||||
U := KeyCode.(22)
|
||||
V := KeyCode.(23)
|
||||
W := KeyCode.(24)
|
||||
X := KeyCode.(25)
|
||||
Y := KeyCode.(26)
|
||||
Z := KeyCode.(27)
|
||||
|
||||
/*
|
||||
ETC
|
||||
*/
|
||||
/* Numeric keycodes*/
|
||||
|
||||
KeypadNumber0 := KeyCode.(256)
|
||||
KeypadNumber1 := KeyCode.(257)
|
||||
KeypadNumber2 := KeyCode.(258)
|
||||
KeypadNumber3 := KeyCode.(259)
|
||||
KeypadNumber4 := KeyCode.(260)
|
||||
KeypadNumber5 := KeyCode.(261)
|
||||
KeypadNumber6 := KeyCode.(262)
|
||||
KeypadNumber7 := KeyCode.(263)
|
||||
KeypadNumber8 := KeyCode.(264)
|
||||
KeypadNumber9 := KeyCode.(265)
|
||||
Number0 := KeyCode.(28)
|
||||
Number1 := KeyCode.(29)
|
||||
Number2 := KeyCode.(30)
|
||||
Number3 := KeyCode.(31)
|
||||
Number4 := KeyCode.(32)
|
||||
Number5 := KeyCode.(33)
|
||||
Number6 := KeyCode.(34)
|
||||
Number7 := KeyCode.(35)
|
||||
Number8 := KeyCode.(36)
|
||||
Number9 := KeyCode.(37)
|
||||
|
||||
KeypadPeriod := KeyCode.(266)
|
||||
KeypadDivide := KeyCode.(267)
|
||||
KeypadMultiply := KeyCode.(268)
|
||||
KeypadMinus := KeyCode.(269)
|
||||
KeypadPlus := KeyCode.(270)
|
||||
KeypadEnter := KeyCode.(271)
|
||||
KeypadEquals := KeyCode.(272)
|
||||
KeypadNumber0 := KeyCode.(38)
|
||||
KeypadNumber1 := KeyCode.(39)
|
||||
KeypadNumber2 := KeyCode.(40)
|
||||
KeypadNumber3 := KeyCode.(41)
|
||||
KeypadNumber4 := KeyCode.(42)
|
||||
KeypadNumber5 := KeyCode.(43)
|
||||
KeypadNumber6 := KeyCode.(44)
|
||||
KeypadNumber7 := KeyCode.(45)
|
||||
KeypadNumber8 := KeyCode.(46)
|
||||
KeypadNumber9 := KeyCode.(47)
|
||||
|
||||
NumLock := KeyCode.(300)
|
||||
CapsLock := KeyCode.(301)
|
||||
ScrollLock := KeyCode.(302)
|
||||
KeypadPeriod := KeyCode.(48)
|
||||
KeypadDivide := KeyCode.(49)
|
||||
KeypadMultiply := KeyCode.(50)
|
||||
KeypadMinus := KeyCode.(51)
|
||||
KeypadPlus := KeyCode.(52)
|
||||
KeypadEnter := KeyCode.(53)
|
||||
KeypadEquals := KeyCode.(54)
|
||||
|
||||
RightShift := KeyCode.(303)
|
||||
LeftShift := KeyCode.(304)
|
||||
|
||||
RightControl := KeyCode.(305)
|
||||
LeftControl := KeyCode.(306)
|
||||
RightAlt := KeyCode.(307)
|
||||
LeftAlt := KeyCode.(308)
|
||||
RightMeta := KeyCode.(309)
|
||||
LeftMeta := KeyCode.(310)
|
||||
|
||||
/* Left "Windows" key */
|
||||
LeftSuper := KeyCode.(311)
|
||||
|
||||
/* Right "Windows" key */
|
||||
RightSuper := KeyCode.(312)
|
||||
Delete := KeyCode.(55)
|
||||
/* Locking Keys */
|
||||
NumLock := KeyCode.(56)
|
||||
CapsLock := KeyCode.(57)
|
||||
ScrollLock := KeyCode.(58)
|
||||
|
||||
/* "Alt Gr" key */
|
||||
Mode := KeyCode.(313)
|
||||
Mode := KeyCode.(59)
|
||||
|
||||
/* Multi-key compose key */
|
||||
Compose := KeyCode.(314)
|
||||
Compose := KeyCode.(60)
|
||||
|
||||
LeftAlt := KeyCode.(61)
|
||||
LeftControl := KeyCode.(62)
|
||||
LeftMeta := KeyCode.(63)
|
||||
LeftShift := KeyCode.(64)
|
||||
/* Left "Windows" key */
|
||||
LeftSuper := KeyCode.(65)
|
||||
|
||||
RightAlt := KeyCode.(66)
|
||||
RightControl := KeyCode.(67)
|
||||
RightMeta := KeyCode.(68)
|
||||
RightShift := KeyCode.(69)
|
||||
/* Right "Windows" key */
|
||||
RightSuper := KeyCode.(70)
|
||||
|
||||
/*
|
||||
This block of any triggers on any press of any of the keys.
|
||||
Typically this is the event to care about.
|
||||
*/
|
||||
AnyNumber0 := KeyCode.(71)
|
||||
AnyNumber1 := KeyCode.(72)
|
||||
AnyNumber2 := KeyCode.(73)
|
||||
AnyNumber3 := KeyCode.(74)
|
||||
AnyNumber4 := KeyCode.(75)
|
||||
AnyNumber5 := KeyCode.(76)
|
||||
AnyNumber6 := KeyCode.(77)
|
||||
AnyNumber7 := KeyCode.(78)
|
||||
AnyNumber8 := KeyCode.(79)
|
||||
AnyNumber9 := KeyCode.(80)
|
||||
|
||||
AnyAlt := KeyCode.(81)
|
||||
AnyControl := KeyCode.(82)
|
||||
AnyMeta := KeyCode.(83)
|
||||
AnyShift := KeyCode.(84)
|
||||
/* Any "Windows" key */
|
||||
AnySuper := KeyCode.(85)
|
|
@ -1,22 +1,36 @@
|
|||
keycodes := @use("keycodes.hb");
|
||||
.{KeyCode} := keycodes
|
||||
stn := @use("../../stn/src/lib.hb");
|
||||
.{log, buffer, memory} := stn
|
||||
keycodes := @use("keycodes.hb")
|
||||
|
||||
MouseEvent := struct {
|
||||
x_change: u8,
|
||||
y_change: u8,
|
||||
left: u8,
|
||||
middle: u8,
|
||||
right: u8,
|
||||
events := @use("events.hb");
|
||||
.{KeyEvent, MouseEvent} := events
|
||||
|
||||
recieve_key_event := fn(): ?KeyEvent {
|
||||
kevent := KeyEvent.(false, false, 0)
|
||||
|
||||
buf_id := buffer.search("PS/2 Keyboard\0")
|
||||
|
||||
// Read out of the Keyboard buffer here
|
||||
buffer.recv(KeyEvent, buf_id, &kevent)
|
||||
|
||||
if kevent.just_triggered {
|
||||
return kevent
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
KeyEvent := struct {
|
||||
// 0 if down
|
||||
// 1 if up
|
||||
up: u8,
|
||||
// 0 if not just triggered
|
||||
// 1 if just triggered
|
||||
just_triggered: u8,
|
||||
key: KeyCode,
|
||||
}
|
||||
recieve_mouse_event := fn(): ?MouseEvent {
|
||||
mevent := MouseEvent.(0, 0, false, false, false)
|
||||
|
||||
GamepadEvent := struct {}
|
||||
buf_id := buffer.search("PS/2 Mouse\0")
|
||||
|
||||
// Read out of the Mouse buffer here
|
||||
buffer.recv(MouseEvent, buf_id, &mevent)
|
||||
|
||||
if mevent.x_change != 0 | mevent.y_change != 0 | mevent.left | mevent.middle | mevent.right {
|
||||
return mevent
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
27
sysdata/libraries/render/TODO.md
Normal file
27
sysdata/libraries/render/TODO.md
Normal file
|
@ -0,0 +1,27 @@
|
|||
# Images
|
||||
- Animation
|
||||
|
||||
# API
|
||||
- Colour operations:
|
||||
- Alpha Composite
|
||||
- Invert
|
||||
- Surface Operations:
|
||||
- FlipH
|
||||
- Resize
|
||||
- Wrap the colour operations
|
||||
- Tile
|
||||
- Gradient overlay
|
||||
- Draw operations:
|
||||
- Curve raster algorithm
|
||||
- VGA font fast blit
|
||||
- Polygon
|
||||
- Rounded rects
|
||||
|
||||
# Backend
|
||||
- SVGA Driver
|
||||
- Support whatever vulkan stuff able is cooking
|
||||
|
||||
# Bits and bobs on the table
|
||||
- Funny 3D Renderer
|
||||
- stn.memory.swap & kernel message
|
||||
- Make memory.{copy, set} smart
|
49
sysdata/libraries/render/src/image/bmp.hb
Normal file
49
sysdata/libraries/render/src/image/bmp.hb
Normal file
|
@ -0,0 +1,49 @@
|
|||
.{Color, Surface, new_surface, put_surface} := @use("../lib.hb");
|
||||
.{log} := @use("../../../stn/src/lib.hb")
|
||||
|
||||
BitmapFileHeader := packed struct {
|
||||
magic: u16,
|
||||
size: u32,
|
||||
reserved_1: u16,
|
||||
reserved_2: u16,
|
||||
offset: u32,
|
||||
}
|
||||
|
||||
BitmapInfoHeader := packed struct {
|
||||
size: u32,
|
||||
width: i32,
|
||||
height: i32,
|
||||
planes: u16,
|
||||
bits: u16,
|
||||
compression: u32,
|
||||
image_size: u32,
|
||||
x_resolution: i32,
|
||||
y_resolution: i32,
|
||||
n_colours: u32,
|
||||
important_colours: u32,
|
||||
}
|
||||
|
||||
BitmapColorHeader := packed struct {
|
||||
red_mask: u32,
|
||||
green_mask: u32,
|
||||
blue_mask: u32,
|
||||
alpha_mask: u32,
|
||||
color_space_type: u32,
|
||||
unused: u32,
|
||||
}
|
||||
|
||||
from := fn(bmp: ^u8): ?Surface {
|
||||
file_header := @as(^BitmapFileHeader, @bitcast(bmp))
|
||||
info_header := @as(^BitmapInfoHeader, @bitcast(bmp + @sizeof(BitmapFileHeader)))
|
||||
|
||||
if file_header.magic != 0x4D42 | info_header.width == 0 | info_header.height == 0 {
|
||||
log.error("Invalid BMP image.\0")
|
||||
return null
|
||||
}
|
||||
|
||||
lhs := Surface.(@bitcast(bmp + file_header.offset), info_header.width, info_header.height, info_header.width * info_header.height)
|
||||
rhs := new_surface(info_header.width, info_header.height)
|
||||
put_surface(rhs, lhs, .(0, 0), true)
|
||||
|
||||
return rhs
|
||||
}
|
31
sysdata/libraries/render/src/image/lib.hb
Normal file
31
sysdata/libraries/render/src/image/lib.hb
Normal file
|
@ -0,0 +1,31 @@
|
|||
.{log} := @use("../../../stn/src/lib.hb");
|
||||
.{Surface} := @use("../lib.hb")
|
||||
bmp := @use("bmp.hb")
|
||||
qoi := @use("qoi.hb")
|
||||
$BMP := 0x4D42
|
||||
$QOI := 0x66696F71
|
||||
|
||||
get_format := fn(file: ^u8): ?uint {
|
||||
if *@as(^u16, @bitcast(file)) == BMP {
|
||||
return BMP
|
||||
} else if *@as(^u32, @bitcast(file)) == QOI {
|
||||
return QOI
|
||||
} else {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
from := fn(file: ^u8): ?Surface {
|
||||
format := get_format(file)
|
||||
|
||||
if format == null {
|
||||
log.error("Could not detect image format.\0")
|
||||
return null
|
||||
} else if format == BMP {
|
||||
return bmp.from(file)
|
||||
} else if format == QOI {
|
||||
return qoi.from(file)
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
101
sysdata/libraries/render/src/image/qoi.hb
Normal file
101
sysdata/libraries/render/src/image/qoi.hb
Normal file
|
@ -0,0 +1,101 @@
|
|||
.{Color, Surface, new_surface} := @use("../lib.hb");
|
||||
.{log} := @use("../../../stn/src/lib.hb")
|
||||
|
||||
/* source:
|
||||
https://github.com/phoboslab/qoi/blob/master/qoi.h */
|
||||
|
||||
$QOI_SRGB := 0
|
||||
$QOI_LINEAR := 1
|
||||
$QOI_OP_INDEX := 0x0
|
||||
$QOI_OP_DIFF := 0x40
|
||||
$QOI_OP_LUMA := 0x80
|
||||
$QOI_OP_RUN := 0xC0
|
||||
$QOI_OP_RGB := 0xFE
|
||||
$QOI_OP_RGBA := 0xFF
|
||||
$QOI_MASK_2 := 0xC0
|
||||
$QOI_COLOR_HASH := fn(c: Color): u8 {
|
||||
return (c.r * 3 + c.g * 5 + c.b * 7 + c.a * 11) % 64
|
||||
}
|
||||
$QOI_MAGIC := 0x716F6966
|
||||
$QOI_PIXELS_MAX := 400000000
|
||||
|
||||
QuiteOkayHeader := packed struct {
|
||||
magic: u32,
|
||||
width: u32,
|
||||
height: u32,
|
||||
channels: u8,
|
||||
colorspace: u8,
|
||||
}
|
||||
|
||||
be_to_le := fn(big: u32): u32 {
|
||||
return big >> 24 | big >> 8 & 0xFF00 | big << 8 & 0xFF0000 | big << 24
|
||||
}
|
||||
|
||||
from := fn(qoi: ^u8): ?Surface {
|
||||
header := @as(^QuiteOkayHeader, @bitcast(qoi))
|
||||
|
||||
qoi += @sizeof(QuiteOkayHeader)
|
||||
|
||||
width := be_to_le(header.width)
|
||||
height := be_to_le(header.height)
|
||||
|
||||
if be_to_le(header.magic) != QOI_MAGIC | width == 0 | height == 0 | header.channels < 3 | header.channels > 4 {
|
||||
log.error("Invalid QOI image.\0")
|
||||
return null
|
||||
}
|
||||
|
||||
surface := new_surface(width, height)
|
||||
index := @as([Color; 64], idk)
|
||||
|
||||
run := 0
|
||||
px := Color.(0, 0, 0, 255)
|
||||
px_pos := 0
|
||||
|
||||
total_pixels := width * height
|
||||
|
||||
loop if px_pos >= total_pixels break else {
|
||||
if run > 0 {
|
||||
run -= 1
|
||||
} else {
|
||||
b1 := *qoi
|
||||
qoi += 1
|
||||
|
||||
if b1 == QOI_OP_RGB {
|
||||
px.r = *qoi
|
||||
px.g = *(qoi + 1)
|
||||
px.b = *(qoi + 2)
|
||||
qoi += 3
|
||||
} else if b1 == QOI_OP_RGBA {
|
||||
px.r = *qoi
|
||||
px.g = *(qoi + 1)
|
||||
px.b = *(qoi + 2)
|
||||
px.a = *(qoi + 3)
|
||||
qoi += 4
|
||||
} else if (b1 & QOI_MASK_2) == QOI_OP_INDEX {
|
||||
px = index[b1 & 0x3F]
|
||||
} else if (b1 & QOI_MASK_2) == QOI_OP_DIFF {
|
||||
px.r = px.r + (b1 >> 4 & 0x3) - 2 & 0xFF
|
||||
px.g = px.g + (b1 >> 2 & 0x3) - 2 & 0xFF
|
||||
px.b = px.b + (b1 & 0x3) - 2 & 0xFF
|
||||
} else if (b1 & QOI_MASK_2) == QOI_OP_LUMA {
|
||||
b2 := *qoi
|
||||
vg := (b1 & 0x3F) - 32
|
||||
|
||||
px.r = px.r + vg - 8 + (b2 >> 4 & 0xF) & 0xFF
|
||||
px.g = px.g + vg & 0xFF
|
||||
px.b = px.b + vg - 8 + (b2 & 0xF) & 0xFF
|
||||
qoi += 1
|
||||
} else if (b1 & QOI_MASK_2) == QOI_OP_RUN {
|
||||
run = b1 & 0x3F
|
||||
}
|
||||
|
||||
index[QOI_COLOR_HASH(px)] = px
|
||||
};
|
||||
|
||||
*(surface.buf + px_pos) = px
|
||||
|
||||
px_pos += 1
|
||||
}
|
||||
|
||||
return surface
|
||||
}
|
|
@ -1,47 +1,57 @@
|
|||
svga := @use("svga.hb")
|
||||
software := @use("software.hb")
|
||||
image := @use("image/lib.hb")
|
||||
text := @use("text.hb")
|
||||
|
||||
// default mode
|
||||
mode := software
|
||||
|
||||
init := mode.init
|
||||
doublebuffer := mode.doublebuffer
|
||||
Surface := mode.Surface
|
||||
new_surface := mode.new_surface
|
||||
surface_from_ptr := mode.surface_from_ptr
|
||||
clone_surface := mode.clone_surface
|
||||
free_surface := mode.free_surface
|
||||
index := mode.index
|
||||
indexptr := mode.indexptr
|
||||
|
||||
// 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
|
||||
Color := packed 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)
|
||||
|
||||
// Drawing
|
||||
put_pixel := mode.put_pixel
|
||||
put_rect := mode.put_rect
|
||||
put_filled_rect := mode.put_filled_rect
|
||||
put_trirect := mode.put_trirect
|
||||
put_circle := mode.put_circle
|
||||
put_filled_circle := mode.put_filled_circle
|
||||
put_textured_circle := mode.put_textured_circle
|
||||
put_line := mode.put_line
|
||||
put_vline := mode.put_vline
|
||||
put_hline := mode.put_hline
|
||||
clear := mode.clear
|
||||
put_surface := mode.put_surface
|
||||
put_text := mode.put_text
|
||||
// thanks peony for these three!
|
||||
//put_trirect := mode.put_trirect
|
||||
//put_vline := mode.put_vline
|
||||
//put_hline := mode.put_hline
|
||||
|
||||
// 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}
|
|
@ -1,197 +1,116 @@
|
|||
.{math, memory} := @use("../../stn/src/lib.hb");
|
||||
.{dt_get} := @use("../../dt_api/src/lib.hb");
|
||||
.{IVec2} := @use("lib.hb")
|
||||
.{math, memory, dt} := @use("../../stn/src/lib.hb");
|
||||
.{Color, text} := @use("lib.hb");
|
||||
.{get_glyph, get_glyph_unicode, Font, UNC_TABLE_SIZE} := text;
|
||||
.{Vec2} := math
|
||||
|
||||
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)
|
||||
// safety: don't use before init() or you will get a memory access violation
|
||||
framebuffer := memory.dangling(Color)
|
||||
|
||||
// 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,
|
||||
Surface := struct {
|
||||
buf: ^Color,
|
||||
width: int,
|
||||
height: int,
|
||||
partitions: int,
|
||||
pixels: int,
|
||||
bb_pages: int,
|
||||
double_buffer: bool,
|
||||
width: uint,
|
||||
height: uint,
|
||||
size: uint,
|
||||
}
|
||||
|
||||
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,
|
||||
new_surface := fn(width: uint, height: uint): Surface {
|
||||
return .(
|
||||
memory.alloc(Color, width * height),
|
||||
width,
|
||||
height,
|
||||
partitions,
|
||||
pixels,
|
||||
bb_pages: pages,
|
||||
double_buffer: true,
|
||||
}
|
||||
return
|
||||
width * height,
|
||||
)
|
||||
}
|
||||
|
||||
doublebuffer := fn(enable: bool): void {
|
||||
if enable {
|
||||
ctx.buf = ctx.bb
|
||||
clone_surface := fn(surface: ^Surface): Surface {
|
||||
new := new_surface(surface.width, surface.height)
|
||||
memory.copy(Color, surface.buf, new.buf, @intcast(surface.size))
|
||||
return new
|
||||
}
|
||||
|
||||
init := fn(doublebuffer: bool): Surface {
|
||||
framebuffer = dt.get(^Color, "framebuffer/fb0/ptr\0")
|
||||
width := dt.get(uint, "framebuffer/fb0/width\0")
|
||||
height := dt.get(uint, "framebuffer/fb0/height\0")
|
||||
if doublebuffer {
|
||||
return new_surface(width, height)
|
||||
} else {
|
||||
ctx.buf = ctx.fb
|
||||
return .(framebuffer, width, height, width * height)
|
||||
}
|
||||
ctx.double_buffer = enable
|
||||
}
|
||||
|
||||
$clear := fn(surface: Surface, color: Color): void {
|
||||
memory.set(Color, &color, surface.buf, surface.width * surface.height)
|
||||
}
|
||||
|
||||
$sync := fn(surface: Surface): void {
|
||||
memory.copy(Color, surface.buf, framebuffer, @bitcast(surface.width * surface.height))
|
||||
}
|
||||
|
||||
$index := fn(surface: Surface, x: uint, y: uint): uint {
|
||||
return x + surface.width * y
|
||||
}
|
||||
|
||||
$indexptr := fn(surface: Surface, x: uint, y: uint): ^Color {
|
||||
return surface.buf + index(surface, x, y)
|
||||
}
|
||||
|
||||
$put_pixel := fn(surface: Surface, pos: Vec2(uint), color: Color): void {
|
||||
return *indexptr(surface, pos.x, pos.y) = color
|
||||
}
|
||||
|
||||
put_filled_rect := fn(surface: Surface, pos: Vec2(uint), tr: Vec2(uint), color: Color): void {
|
||||
top_start_idx := indexptr(surface, pos.x, pos.y)
|
||||
bottom_start_idx := indexptr(surface, pos.x, pos.y + tr.y - 1)
|
||||
rows_to_fill := tr.y
|
||||
|
||||
loop if rows_to_fill <= 1 break else {
|
||||
memory.set(Color, &color, top_start_idx, tr.x)
|
||||
memory.set(Color, &color, bottom_start_idx, tr.x)
|
||||
|
||||
top_start_idx += surface.width
|
||||
bottom_start_idx -= surface.width
|
||||
rows_to_fill -= 2
|
||||
}
|
||||
|
||||
if rows_to_fill == 1 {
|
||||
memory.set(Color, &color, top_start_idx, tr.x)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
put_rect := fn(surface: Surface, pos: Vec2(uint), tr: Vec2(uint), color: Color): void {
|
||||
start_idx := indexptr(surface, pos.x, pos.y)
|
||||
end_idx := indexptr(surface, pos.x, pos.y + tr.y)
|
||||
right_start_idx := indexptr(surface, pos.x + tr.x, pos.y)
|
||||
|
||||
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])
|
||||
loop if start_idx > end_idx break else {
|
||||
*start_idx = color;
|
||||
*right_start_idx = color
|
||||
start_idx += surface.width
|
||||
right_start_idx += surface.width
|
||||
}
|
||||
|
||||
memory.set(Color, &color, indexptr(surface, pos.x, pos.y), @bitcast(tr.x + 1))
|
||||
memory.set(Color, &color, indexptr(surface, pos.x, pos.y + tr.y), @bitcast(tr.x + 1))
|
||||
|
||||
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
|
||||
put_line_low := fn(surface: Surface, p0: Vec2(uint), p1: Vec2(uint), color: Color): void {
|
||||
dx := @as(int, @bitcast(p1.x - p0.x))
|
||||
dy := @as(int, @bitcast(p1.y - p0.y))
|
||||
yi := 1
|
||||
if dy < 0 {
|
||||
yi = -1
|
||||
dy = -dy
|
||||
}
|
||||
D := 2 * dy - dx
|
||||
D := @as(int, 2) * dy - dx
|
||||
y := p0.y
|
||||
x := p0.x
|
||||
loop if x == p1.x break else {
|
||||
*(ctx.buf + @inline(screenidx, x, y)) = color
|
||||
*indexptr(surface, x, y) = color
|
||||
if D > 0 {
|
||||
y += yi
|
||||
D += 2 * (dy - dx)
|
||||
|
@ -203,19 +122,19 @@ put_line_low := fn(p0: IVec2, p1: IVec2, color: Color): void {
|
|||
return
|
||||
}
|
||||
|
||||
put_line_high := fn(p0: IVec2, p1: IVec2, color: Color): void {
|
||||
dx := p1.x - p0.x
|
||||
dy := p1.y - p0.y
|
||||
put_line_high := fn(surface: Surface, p0: Vec2(uint), p1: Vec2(uint), color: Color): void {
|
||||
dx := @as(int, @bitcast(p1.x - p0.x))
|
||||
dy := @as(int, @bitcast(p1.y - p0.y))
|
||||
xi := 1
|
||||
if dy < 0 {
|
||||
xi = -1
|
||||
dx = -dx
|
||||
}
|
||||
D := 2 * dx - dy
|
||||
D := @as(int, 2) * dx - dy
|
||||
x := p0.x
|
||||
y := p0.y
|
||||
loop if y == p1.y break else {
|
||||
*(ctx.buf + @inline(screenidx, x, y)) = color
|
||||
*indexptr(surface, x, y) = color
|
||||
if D > 0 {
|
||||
x += xi
|
||||
D += 2 * (dx - dy)
|
||||
|
@ -227,35 +146,327 @@ put_line_high := fn(p0: IVec2, p1: IVec2, color: Color): void {
|
|||
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) {
|
||||
put_line := fn(surface: Surface, p0: Vec2(uint), p1: Vec2(uint), color: Color): void {
|
||||
if math.abs(uint, p1.y - p0.y) < math.abs(uint, p1.x - p0.x) {
|
||||
if p0.x > p1.x {
|
||||
@inline(put_line_low, p1, p0, color)
|
||||
@inline(put_line_low, surface, p1, p0, color)
|
||||
} else {
|
||||
@inline(put_line_low, p0, p1, color)
|
||||
@inline(put_line_low, surface, p0, p1, color)
|
||||
}
|
||||
} else {
|
||||
if p0.y > p1.y {
|
||||
@inline(put_line_high, p1, p0, color)
|
||||
@inline(put_line_high, surface, p1, p0, color)
|
||||
} else {
|
||||
@inline(put_line_high, p0, p1, color)
|
||||
@inline(put_line_high, surface, p0, p1, color)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
set_height := fn(new: int): void {
|
||||
put_surface := fn(surface: Surface, top: Surface, pos: Vec2(uint), flip_v: bool): void {
|
||||
src_top_cursor := top.buf
|
||||
src_bottom_cursor := top.buf + top.width * (top.height - 1)
|
||||
|
||||
dst_top_idx := indexptr(surface, pos.x, pos.y)
|
||||
dst_bottom_idx := indexptr(surface, pos.x, pos.y + top.height - 1)
|
||||
|
||||
dst_increment := surface.width
|
||||
|
||||
if flip_v {
|
||||
dst_increment = -dst_increment
|
||||
tmp := dst_top_idx
|
||||
dst_top_idx = dst_bottom_idx
|
||||
dst_bottom_idx = tmp
|
||||
}
|
||||
|
||||
rows_to_copy := top.height
|
||||
|
||||
loop if rows_to_copy <= 1 break else {
|
||||
memory.copy(Color, src_top_cursor, dst_top_idx, top.width)
|
||||
memory.copy(Color, src_bottom_cursor, dst_bottom_idx, top.width)
|
||||
|
||||
dst_top_idx += dst_increment
|
||||
dst_bottom_idx -= dst_increment
|
||||
src_top_cursor += top.width
|
||||
src_bottom_cursor -= top.width
|
||||
rows_to_copy -= 2
|
||||
}
|
||||
|
||||
if rows_to_copy == 1 {
|
||||
memory.copy(Color, src_top_cursor, dst_top_idx, top.width)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
set_width := fn(new: int): void {
|
||||
// peony-made
|
||||
put_trirect := fn(surface: Surface, pos: Vec2(uint), size: Vec2(int), color0: Color, color1: Color): void {
|
||||
step := Vec2(int).(1, 1)
|
||||
if size.x < 0 {
|
||||
step.x = -1
|
||||
}
|
||||
if size.y < 0 {
|
||||
step.y /= @bitcast(size.x)
|
||||
}
|
||||
|
||||
start_y := pos.y
|
||||
target := pos + @bitcast(size)
|
||||
|
||||
loop if pos.x == target.x break else {
|
||||
@inline(put_vline, surface, pos.x, pos.y, target.y, color0)
|
||||
@inline(put_vline, surface, pos.x, pos.y, start_y, color1)
|
||||
pos += @bitcast(step)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
dimensions := fn(): IVec2 {
|
||||
return .(ctx.width, ctx.height)
|
||||
}
|
||||
// peony-made
|
||||
put_vline := fn(surface: Surface, x: uint, y0: uint, y1: uint, color: Color): void {
|
||||
if y1 < y0 {
|
||||
tmp := y0
|
||||
y0 = y1
|
||||
y1 = tmp
|
||||
}
|
||||
y := y0
|
||||
|
||||
loop if y == y1 break else {
|
||||
*indexptr(surface, x, y) = color
|
||||
y += 1
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// peony-made
|
||||
put_hline := fn(surface: Surface, y: uint, x0: uint, x1: uint, color: Color): void {
|
||||
if x1 < x0 {
|
||||
tmp := x0
|
||||
x0 = x1
|
||||
x1 = tmp
|
||||
}
|
||||
// x0 = math.min(x0, x1)
|
||||
memory.set(Color, &color, indexptr(surface, x0, y), @bitcast(x1 - x0 - 1))
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
put_circle := fn(surface: Surface, pos: Vec2(uint), radius: uint, color: Color): void {
|
||||
x := 0
|
||||
y := radius
|
||||
error := @as(int, 3) - @intcast(2 * radius);
|
||||
*indexptr(surface, pos.x + radius, pos.y) = color;
|
||||
*indexptr(surface, pos.x - radius, pos.y) = color;
|
||||
*indexptr(surface, pos.x, pos.y + radius) = color;
|
||||
*indexptr(surface, pos.x, pos.y - radius) = color
|
||||
|
||||
loop if y < x break else {
|
||||
x += 1
|
||||
|
||||
if error > 0 {
|
||||
y -= 1
|
||||
error += 4 * (@intcast(x) - @intcast(y)) + 10
|
||||
} else {
|
||||
error += 4 * @intcast(x) + 6
|
||||
};
|
||||
*indexptr(surface, pos.x + x, pos.y + y) = color;
|
||||
*indexptr(surface, pos.x + y, pos.y + x) = color;
|
||||
*indexptr(surface, pos.x - x, pos.y + y) = color;
|
||||
*indexptr(surface, pos.x - y, pos.y + x) = color;
|
||||
*indexptr(surface, pos.x + x, pos.y - y) = color;
|
||||
*indexptr(surface, pos.x + y, pos.y - x) = color;
|
||||
*indexptr(surface, pos.x - x, pos.y - y) = color;
|
||||
*indexptr(surface, pos.x - y, pos.y - x) = color
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
put_filled_circle := fn(surface: Surface, pos: Vec2(uint), radius: uint, color: Color): void {
|
||||
x := 0
|
||||
y := radius
|
||||
error := @as(int, 3) - @intcast(2 * radius)
|
||||
put_hline(surface, pos.y - x, pos.x - radius, pos.x + radius, color);
|
||||
*indexptr(surface, pos.x, pos.y + radius) = color;
|
||||
*indexptr(surface, pos.x, pos.y - radius) = color
|
||||
|
||||
loop if y < x break else {
|
||||
x += 1
|
||||
|
||||
if error > 0 {
|
||||
put_hline(surface, pos.y + y, pos.x - x, pos.x + x, color)
|
||||
put_hline(surface, pos.y - y, pos.x - x, pos.x + x, color)
|
||||
y -= 1
|
||||
error += 4 * (@intcast(x) - @intcast(y)) + 10
|
||||
} else {
|
||||
error += 4 * @intcast(x) + 6
|
||||
}
|
||||
put_hline(surface, pos.y + x, pos.x - y, pos.x + y, color)
|
||||
put_hline(surface, pos.y - x, pos.x - y, pos.x + y, color)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
put_textured_circle := fn(surface: Surface, source: Surface, source_pos: Vec2(uint), pos: Vec2(uint), radius: uint): void {
|
||||
x := 0
|
||||
y := radius
|
||||
error := @as(int, 3) - @intcast(2 * radius)
|
||||
memory.copy(Color, indexptr(source, source_pos.x - y, source_pos.y), indexptr(surface, pos.x - y, pos.y), 2 * y);
|
||||
*indexptr(surface, pos.x, pos.y + y) = *indexptr(source, source_pos.x, source_pos.y + y);
|
||||
*indexptr(surface, pos.x, pos.y - y) = *indexptr(source, source_pos.x, source_pos.y - y)
|
||||
|
||||
loop if y < x break else {
|
||||
x += 1
|
||||
|
||||
if error > 0 {
|
||||
memory.copy(Color, indexptr(source, source_pos.x - x, source_pos.y + y), indexptr(surface, pos.x - x, pos.y + y), 2 * x)
|
||||
memory.copy(Color, indexptr(source, source_pos.x - x, source_pos.y - y), indexptr(surface, pos.x - x, pos.y - y), 2 * x)
|
||||
y -= 1
|
||||
error += 4 * (@intcast(x) - @intcast(y)) + 10
|
||||
} else {
|
||||
error += 4 * @intcast(x) + 6
|
||||
}
|
||||
memory.copy(Color, indexptr(source, source_pos.x - y, source_pos.y + x), indexptr(surface, pos.x - y, pos.y + x), 2 * y)
|
||||
memory.copy(Color, indexptr(source, source_pos.x - y, source_pos.y - x), indexptr(surface, pos.x - y, pos.y - x), 2 * y)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
utf8_len_table := [u8].(0, 0, 2, 3)
|
||||
|
||||
put_text := fn(surface: Surface, font: Font, pos: Vec2(uint), color: Color, str: ^u8): void {
|
||||
cursor := Vec2(uint).(pos.x, pos.y)
|
||||
|
||||
max_y := surface.height - font.height
|
||||
next_line_y := font.height + font.line_gap
|
||||
char_advance := font.width + font.char_gap
|
||||
surface_width := surface.width
|
||||
|
||||
loop if *str == 0 break else {
|
||||
if cursor.y > max_y break
|
||||
|
||||
glyph_data := @as(^u8, idk)
|
||||
code_point := @as(uint, 0)
|
||||
|
||||
if (*str & 0x80) == 0 {
|
||||
if *str == 10 {
|
||||
cursor.x = pos.x
|
||||
cursor.y += next_line_y
|
||||
str += 1
|
||||
continue
|
||||
}
|
||||
|
||||
if font.unicode == null {
|
||||
if *str > font.num_glyphs {
|
||||
str += 1
|
||||
continue
|
||||
}
|
||||
glyph_data = get_glyph(font, *str)
|
||||
} else {
|
||||
if *str < UNC_TABLE_SIZE {
|
||||
glyph_index := *(font.unicode + *str)
|
||||
if glyph_index == 0xFFFF {
|
||||
str += 1
|
||||
continue
|
||||
}
|
||||
glyph_data = font.data + glyph_index * font.bytes_per_glyph
|
||||
} else {
|
||||
str += 1
|
||||
continue
|
||||
}
|
||||
}
|
||||
str += 1
|
||||
} else if font.unicode != null {
|
||||
first_byte := *str
|
||||
num_bytes := @as(uint, 0)
|
||||
|
||||
num_bytes = utf8_len_table[first_byte >> 5 & 0x3]
|
||||
|
||||
if num_bytes == 0 {
|
||||
str += 1
|
||||
continue
|
||||
}
|
||||
|
||||
code_point = first_byte & (0x7F >> num_bytes | 0x1F)
|
||||
|
||||
valid_sequence := true
|
||||
bytes_processed := 1
|
||||
|
||||
loop if bytes_processed >= num_bytes break else {
|
||||
str += 1
|
||||
if *str == 0 | (*str & 0xC0) != 0x80 {
|
||||
valid_sequence = false
|
||||
}
|
||||
if valid_sequence == false {
|
||||
break
|
||||
}
|
||||
code_point = code_point << 6 | *str & 0x3F
|
||||
bytes_processed += 1
|
||||
}
|
||||
|
||||
if valid_sequence == false {
|
||||
str += 1
|
||||
continue
|
||||
}
|
||||
|
||||
str += 1
|
||||
|
||||
if code_point == 10 {
|
||||
cursor.x = pos.x
|
||||
cursor.y += next_line_y
|
||||
continue
|
||||
}
|
||||
|
||||
if code_point >= UNC_TABLE_SIZE {
|
||||
continue
|
||||
}
|
||||
|
||||
glyph_index := *(font.unicode + code_point)
|
||||
if glyph_index == 0xFFFF {
|
||||
continue
|
||||
}
|
||||
glyph_data = font.data + glyph_index * font.bytes_per_glyph
|
||||
}
|
||||
|
||||
if cursor.x + font.width >= surface_width {
|
||||
cursor.x = pos.x
|
||||
cursor.y += next_line_y
|
||||
}
|
||||
|
||||
dest := indexptr(surface, cursor.x, cursor.y)
|
||||
rows := font.height
|
||||
|
||||
loop if rows == 0 break else {
|
||||
byte := *glyph_data
|
||||
pixel_dest := dest
|
||||
mask := @as(u8, 0x80)
|
||||
bits := font.width
|
||||
|
||||
loop if bits == 0 break else {
|
||||
if (byte & mask) != 0 {
|
||||
*pixel_dest = color
|
||||
}
|
||||
pixel_dest += 1
|
||||
mask >>= 1
|
||||
if mask == 0 & bits > 0 {
|
||||
glyph_data += 1
|
||||
byte = *glyph_data
|
||||
mask = 0x80
|
||||
}
|
||||
bits -= 1
|
||||
}
|
||||
|
||||
if mask != 0x80 {
|
||||
glyph_data += 1
|
||||
}
|
||||
dest += surface_width
|
||||
rows -= 1
|
||||
}
|
||||
|
||||
cursor.x += char_advance
|
||||
}
|
||||
|
||||
set_dimensions := fn(new: IVec2): void {
|
||||
return
|
||||
}
|
|
@ -1,80 +0,0 @@
|
|||
.{IVec2} := @use("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
|
||||
}
|
160
sysdata/libraries/render/src/text.hb
Normal file
160
sysdata/libraries/render/src/text.hb
Normal file
|
@ -0,0 +1,160 @@
|
|||
.{log, memory} := @use("../../stn/src/lib.hb")
|
||||
|
||||
PSF1Header := packed struct {
|
||||
magic: u16,
|
||||
font_mode: u8,
|
||||
character_size: u8,
|
||||
}
|
||||
|
||||
PSF2Header := packed struct {
|
||||
magic: u32,
|
||||
version: u32,
|
||||
header_size: u32,
|
||||
flags: u32,
|
||||
num_glyph: u32,
|
||||
bytes_per_glyph: u32,
|
||||
height: u32,
|
||||
width: u32,
|
||||
}
|
||||
|
||||
Font := struct {
|
||||
data: ^u8,
|
||||
width: uint,
|
||||
height: uint,
|
||||
num_glyphs: uint,
|
||||
bytes_per_glyph: uint,
|
||||
line_gap: uint,
|
||||
char_gap: uint,
|
||||
unicode: ?^u16,
|
||||
}
|
||||
|
||||
font_from_psf1 := fn(psf: ^u8): ?Font {
|
||||
header := @as(^PSF1Header, @bitcast(psf))
|
||||
if header.magic != 0x436 {
|
||||
log.error("failed to load psf font: not a psf1 font, idiot\0")
|
||||
return null
|
||||
}
|
||||
|
||||
psf += @sizeof(PSF1Header)
|
||||
|
||||
return .(
|
||||
psf,
|
||||
8,
|
||||
header.character_size,
|
||||
256,
|
||||
header.character_size,
|
||||
0,
|
||||
0,
|
||||
null,
|
||||
)
|
||||
}
|
||||
|
||||
font_from_psf2 := fn(psf: ^u8, unicode: bool): ?Font {
|
||||
header := @as(^PSF2Header, @bitcast(psf))
|
||||
if header.magic != 0x864AB572 {
|
||||
log.error("failed to load psf font: not a psf2 font, idiot\0")
|
||||
return null
|
||||
}
|
||||
|
||||
psf += header.header_size
|
||||
|
||||
font := Font.(
|
||||
psf,
|
||||
header.width,
|
||||
header.height,
|
||||
header.num_glyph,
|
||||
header.bytes_per_glyph,
|
||||
0,
|
||||
0,
|
||||
null,
|
||||
)
|
||||
if (header.flags & 1) != 0 & unicode {
|
||||
init_unicode(&font)
|
||||
}
|
||||
return font
|
||||
}
|
||||
|
||||
$get_glyph := fn(font: Font, index: u8): ^u8 {
|
||||
return font.data + @as(uint, index) * font.bytes_per_glyph
|
||||
}
|
||||
|
||||
$UNC_TABLE_SIZE := 1 << 16
|
||||
|
||||
init_unicode := fn(font: ^Font): void {
|
||||
font.unicode = memory.alloc(u16, UNC_TABLE_SIZE)
|
||||
|
||||
memory.set(u16, &0xFFFF, font.unicode, UNC_TABLE_SIZE)
|
||||
|
||||
table := font.data + font.num_glyphs * font.bytes_per_glyph
|
||||
curr_glyph := @as(u16, 0)
|
||||
|
||||
loop if curr_glyph >= font.num_glyphs break else {
|
||||
loop {
|
||||
byte := *table
|
||||
table += 1
|
||||
|
||||
if byte == 0xFF break
|
||||
if byte == 0xFE {
|
||||
continue
|
||||
}
|
||||
|
||||
unicode := @as(uint, 0)
|
||||
bytes_to_read := @as(uint, 1)
|
||||
|
||||
if (byte & 0x80) == 0 {
|
||||
unicode = byte
|
||||
} else if (byte & 0xE0) == 0xC0 {
|
||||
unicode = byte & 0x1F
|
||||
bytes_to_read = 2
|
||||
} else if (byte & 0xF0) == 0xE0 {
|
||||
unicode = byte & 0xF
|
||||
bytes_to_read = 3
|
||||
} else if (byte & 0xF8) == 0xF0 {
|
||||
unicode = byte & 0x7
|
||||
bytes_to_read = 4
|
||||
} else {
|
||||
continue
|
||||
}
|
||||
|
||||
valid := true
|
||||
loop if bytes_to_read <= 1 break else {
|
||||
next_byte := *table
|
||||
if (next_byte & 0xC0) != 0x80 {
|
||||
valid = false
|
||||
break
|
||||
}
|
||||
unicode = unicode << 6 | next_byte & 0x3F
|
||||
table += 1
|
||||
bytes_to_read -= 1
|
||||
}
|
||||
|
||||
if valid == false continue
|
||||
|
||||
if bytes_to_read == 4 {
|
||||
if unicode < 0x10000 | unicode > 0x10FFFF continue
|
||||
|
||||
if unicode <= 0xFFFF {
|
||||
if unicode < UNC_TABLE_SIZE {
|
||||
*(@unwrap(font.unicode) + unicode) = curr_glyph
|
||||
}
|
||||
} else {
|
||||
unicode -= 0x10000
|
||||
high_surrogate := 0xD800 | unicode >> 10 & 0x3FF
|
||||
low_surrogate := 0xDC00 | unicode & 0x3FF
|
||||
|
||||
if high_surrogate < UNC_TABLE_SIZE {
|
||||
*(@unwrap(font.unicode) + high_surrogate) = curr_glyph
|
||||
}
|
||||
if low_surrogate < UNC_TABLE_SIZE {
|
||||
*(@unwrap(font.unicode) + low_surrogate) = curr_glyph
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if unicode < UNC_TABLE_SIZE {
|
||||
*(@unwrap(font.unicode) + unicode) = curr_glyph
|
||||
}
|
||||
}
|
||||
}
|
||||
curr_glyph += 1
|
||||
}
|
||||
}
|
|
@ -1,22 +1,35 @@
|
|||
string := @use("string.hb")
|
||||
|
||||
receive_message := fn(buffer_id: int, memory_map_location: ^u8, length: int): ^u8 {
|
||||
$recv := fn($Expr: type, buffer_id: uint, memory_map_location: ^Expr): void {
|
||||
return @eca(4, buffer_id, memory_map_location, @sizeof(Expr))
|
||||
}
|
||||
|
||||
$write := fn($Expr: type, buffer_id: uint, msg: ^Expr): void {
|
||||
return @eca(3, buffer_id, msg, @sizeof(Expr))
|
||||
}
|
||||
|
||||
$recv_length := fn(length: uint, memory_map_location: ^u8, buffer_id: uint): void {
|
||||
return @eca(4, buffer_id, memory_map_location, length)
|
||||
}
|
||||
|
||||
send_message := fn(msg: ^u8, buffer_id: int, length: int): void {
|
||||
$write_length := fn(length: uint, msg: ^u8, buffer_id: uint): void {
|
||||
return @eca(3, buffer_id, msg, length)
|
||||
}
|
||||
|
||||
create := fn(msg: ^u8): int {
|
||||
msg_length := @inline(string.length, msg);
|
||||
*msg = 0
|
||||
return @eca(3, 0, msg, msg_length)
|
||||
BufferMsg := packed struct {operation: u8, msg: ^u8, msg_len: uint}
|
||||
|
||||
create := fn(msg: ^u8): uint {
|
||||
return @eca(3, 0, BufferMsg.(0, msg, @inline(string.length, msg)), @sizeof(BufferMsg))
|
||||
}
|
||||
|
||||
search := fn(msg: ^u8): int {
|
||||
msg_length := @inline(string.length, msg);
|
||||
*msg = 3
|
||||
|
||||
return @eca(3, 0, msg, msg_length)
|
||||
$create_nameless := fn(): uint {
|
||||
return @eca(1, 0)
|
||||
}
|
||||
|
||||
$delete_buffer := fn(buffer_id: uint): void {
|
||||
return @eca(2, buffer_id)
|
||||
}
|
||||
|
||||
search := fn(msg: ^u8): uint {
|
||||
return @eca(3, 0, BufferMsg.(3, msg, @inline(string.length, msg)), @sizeof(BufferMsg))
|
||||
}
|
5
sysdata/libraries/stn/src/dt.hb
Normal file
5
sysdata/libraries/stn/src/dt.hb
Normal file
|
@ -0,0 +1,5 @@
|
|||
.{string} := @use("../../stn/src/lib.hb")
|
||||
|
||||
get := fn($Expr: type, query: ^u8): Expr {
|
||||
return @eca(3, 5, query, @inline(string.length, query))
|
||||
}
|
|
@ -1,5 +1,4 @@
|
|||
acs := @use("acs.hb")
|
||||
|
||||
string := @use("string.hb")
|
||||
log := @use("log.hb")
|
||||
memory := @use("memory.hb")
|
||||
|
@ -7,3 +6,15 @@ buffer := @use("buffer.hb")
|
|||
math := @use("math.hb")
|
||||
random := @use("random.hb")
|
||||
file := @use("file_io.hb")
|
||||
dt := @use("dt.hb")
|
||||
process := @use("process.hb")
|
||||
|
||||
panic := fn(message: ?^u8): never {
|
||||
log.error("Error: Panic Called, Message:\0")
|
||||
if message == null {
|
||||
log.error("None\0")
|
||||
} else {
|
||||
log.error(message)
|
||||
}
|
||||
die
|
||||
}
|
|
@ -1,15 +1,13 @@
|
|||
string := @use("string.hb")
|
||||
buffer := @use("buffer.hb")
|
||||
|
||||
log := fn(message: ^u8, level: u8): void {
|
||||
message_length := @inline(string.length, message);
|
||||
*(message + message_length) = level
|
||||
LogMsg := packed struct {level: u8, string: ^u8, strlen: uint}
|
||||
|
||||
return @eca(3, 1, message, message_length + 1)
|
||||
log := fn(level: u8, message: ^u8): void {
|
||||
return @eca(3, 1, LogMsg.(level, message, @inline(string.length, message)), @sizeof(LogMsg))
|
||||
}
|
||||
|
||||
error := fn(message: ^u8): void return log(message, 0)
|
||||
warn := fn(message: ^u8): void return log(message, 1)
|
||||
info := fn(message: ^u8): void return log(message, 2)
|
||||
debug := fn(message: ^u8): void return log(message, 3)
|
||||
trace := fn(message: ^u8): void return log(message, 4)
|
||||
error := fn(message: ^u8): void return @inline(log, 0, message)
|
||||
warn := fn(message: ^u8): void return @inline(log, 1, message)
|
||||
info := fn(message: ^u8): void return @inline(log, 2, message)
|
||||
debug := fn(message: ^u8): void return @inline(log, 3, message)
|
||||
trace := fn(message: ^u8): void return @inline(log, 4, message)
|
File diff suppressed because one or more lines are too long
|
@ -1,39 +1,76 @@
|
|||
request_page := fn(page_count: u8): ^u8 {
|
||||
msg := "\{00}\{01}xxxxxxxx\0"
|
||||
msg_page_count := msg + 1;
|
||||
*msg_page_count = page_count
|
||||
return @eca(3, 2, msg, 12)
|
||||
$PAGE_SIZE := 4096
|
||||
$MAX_ALLOC := 0xFF
|
||||
$MAX_FREE := 0xFF
|
||||
|
||||
$uninit := fn($Expr: type): ?Expr {
|
||||
return null
|
||||
}
|
||||
|
||||
release_page := fn(ptr: ^u8, page_count: u8): void {
|
||||
msg := "\{01}\{00}xxxxxxxx\0"
|
||||
|
||||
msg_page_count := msg + 1;
|
||||
*msg_page_count = page_count
|
||||
|
||||
msg_ptr := @as(^^u8, @bitcast(msg + 2));
|
||||
*msg_ptr = ptr
|
||||
|
||||
return @eca(3, 2, msg, 12)
|
||||
$dangling := fn($Expr: type): ^Expr {
|
||||
return @bitcast(@alignof(Expr))
|
||||
}
|
||||
|
||||
OutbMsg := struct {a: u8, b: u8, addr: u16, value: u8}
|
||||
InbMsg := struct {a: u8, b: u8, addr: u16}
|
||||
OutlMsg := struct {a: u8, b: u8, addr: u16, value: u32}
|
||||
InlMsg := struct {a: u8, b: u8, addr: u16}
|
||||
$calc_pages := fn($Expr: type, num: uint): uint {
|
||||
return 1 + @sizeof(Expr) * num / PAGE_SIZE
|
||||
}
|
||||
|
||||
outb := fn(addr: u16, value: u8): void {
|
||||
// ! will be replaced, don't get attached
|
||||
alloc := fn($Expr: type, num: uint): ^Expr {
|
||||
pages := calc_pages(Expr, num)
|
||||
if pages <= MAX_ALLOC {
|
||||
return @bitcast(request_page(@intcast(pages)))
|
||||
}
|
||||
ptr := request_page(MAX_ALLOC)
|
||||
remaining := pages - MAX_ALLOC
|
||||
loop if remaining < MAX_ALLOC break else {
|
||||
_ = request_page(MAX_ALLOC)
|
||||
remaining -= MAX_ALLOC
|
||||
}
|
||||
_ = request_page(@intcast(remaining))
|
||||
return @bitcast(ptr)
|
||||
}
|
||||
|
||||
// ! stub
|
||||
$free := fn($Expr: type, ptr: ^Expr, num: uint, nullify: bool): void {
|
||||
return
|
||||
}
|
||||
|
||||
RqPageMsg := packed struct {a: u8, count: u8}
|
||||
$request_page := fn(count: u8): ^u8 {
|
||||
return @eca(3, 2, &RqPageMsg.(0, count), @sizeof(RqPageMsg))
|
||||
}
|
||||
|
||||
RlPageMsg := packed struct {a: u8, count: u8, ptr: ^u8}
|
||||
$release_page := fn(ptr: ^u8, count: u8): void {
|
||||
return @eca(3, 2, &RlPageMsg.(1, count, ptr), @sizeof(RlPageMsg))
|
||||
}
|
||||
|
||||
OutbMsg := packed struct {a: u8, b: u8, addr: u16, value: u8}
|
||||
$outb := fn(addr: u16, value: u8): void {
|
||||
return @eca(3, 3, &OutbMsg.(1, 0, addr, value), @sizeof(OutbMsg))
|
||||
}
|
||||
|
||||
inb := fn(addr: u16): u8 {
|
||||
InbMsg := packed struct {a: u8, b: u8, addr: u16}
|
||||
$inb := fn(addr: u16): u8 {
|
||||
return @eca(3, 3, &InbMsg.(0, 0, addr), @sizeof(InbMsg))
|
||||
}
|
||||
|
||||
outl := fn(addr: u16, value: u32): void {
|
||||
OutlMsg := packed struct {a: u8, b: u8, addr: u16, value: u32}
|
||||
$outl := fn(addr: u16, value: u32): void {
|
||||
return @eca(3, 3, &OutlMsg.(1, 2, addr, value), @sizeof(OutlMsg))
|
||||
}
|
||||
|
||||
inl := fn(addr: u16): u32 {
|
||||
InlMsg := packed struct {a: u8, b: u8, addr: u16}
|
||||
$inl := fn(addr: u16): u32 {
|
||||
return @eca(3, 3, &InlMsg.(0, 2, addr), @sizeof(InlMsg))
|
||||
}
|
||||
|
||||
CopyMsg := packed struct {a: u8, count: u32, src: ^u8, dest: ^u8}
|
||||
$copy := fn($Expr: type, src: ^Expr, dest: ^Expr, count: uint): void {
|
||||
return @eca(3, 2, &CopyMsg.(4, @intcast(count * @sizeof(Expr)), @bitcast(src), @bitcast(dest)), @sizeof(CopyMsg))
|
||||
}
|
||||
|
||||
SetMsg := packed struct {a: u8, count: u32, size: u32, src: ^u8, dest: ^u8}
|
||||
$set := fn($Expr: type, src: ^Expr, dest: ^Expr, count: uint): void {
|
||||
return @eca(3, 2, &SetMsg.(5, @intcast(count), @intcast(@sizeof(Expr)), @bitcast(src), @bitcast(dest)), @sizeof(SetMsg))
|
||||
}
|
12
sysdata/libraries/stn/src/process.hb
Normal file
12
sysdata/libraries/stn/src/process.hb
Normal file
|
@ -0,0 +1,12 @@
|
|||
// ! will be rewritten to take a file object when filesystem is exist
|
||||
// returns PID
|
||||
$spawn := fn(proc_exe: ^u8, length: uint): uint {
|
||||
return @eca(3, 6, proc_exe, length)
|
||||
}
|
||||
|
||||
/* TODO:
|
||||
- Spawn an empty process
|
||||
- Call a function to load bytes into that process from a function
|
||||
Or
|
||||
- Manually fill the bytes in
|
||||
- Execute the process via a run type command */
|
|
@ -1,7 +1,7 @@
|
|||
integer := fn(): int {
|
||||
return @eca(3, 4)
|
||||
any := fn($Expr: type): Expr {
|
||||
return *@eca(3, 4, &@as(Expr, idk), @sizeof(Expr))
|
||||
}
|
||||
|
||||
integer_range := fn(min: int, max: int): int {
|
||||
return @eca(3, 4) % (max - min + 1) + min
|
||||
range := fn($Expr: type, min: Expr, max: Expr): Expr {
|
||||
return *@eca(3, 4, &@as(Expr, idk), @sizeof(Expr)) % (max - min) + *@bitcast(&1) + min
|
||||
}
|
6
sysdata/libraries/stn/src/sleep.hb
Normal file
6
sysdata/libraries/stn/src/sleep.hb
Normal file
|
@ -0,0 +1,6 @@
|
|||
subscribe_to_interrupt := fn(interrupt_number: u8): bool {
|
||||
return false
|
||||
}
|
||||
// Pauses execution until the interrupt occures
|
||||
sleep_until_interrupt := fn(interrupt_number: u8): void {
|
||||
}
|
|
@ -1,48 +1,63 @@
|
|||
length := fn(ptr: ^u8): int {
|
||||
length := fn(ptr: ^u8): uint {
|
||||
len := 0
|
||||
loop if *(ptr + len) == 0 break else len += 1
|
||||
return len
|
||||
loop if *(ptr + len) == 0 return len else len += 1
|
||||
}
|
||||
|
||||
// WTFFF is wrong with display_int
|
||||
display_int := fn(num: int, p: ^u8): ^u8 {
|
||||
display_int := fn(num: int, p: ^u8, radix: uint): ^u8 {
|
||||
is_negative := num < 0
|
||||
if is_negative num = -num
|
||||
|
||||
ptr := p
|
||||
negative := num < 0
|
||||
if negative {
|
||||
num = -num
|
||||
}
|
||||
|
||||
if num == 0 {
|
||||
*ptr = 48
|
||||
ptr += 1
|
||||
} else {
|
||||
loop if num == 0 break else {
|
||||
*ptr = num % 10 + 48
|
||||
ptr += 1
|
||||
num /= 10
|
||||
}
|
||||
*ptr = 0x30;
|
||||
*(ptr + 1) = 0
|
||||
return p
|
||||
}
|
||||
if negative {
|
||||
*ptr = 45
|
||||
|
||||
loop if num == 0 break else {
|
||||
remainder := num % @bitcast(radix)
|
||||
num /= @bitcast(radix);
|
||||
*ptr = @intcast(remainder + 0x30)
|
||||
if remainder > 9 {
|
||||
*ptr = @intcast(remainder - 10 + 0x41)
|
||||
}
|
||||
ptr += 1
|
||||
};
|
||||
*ptr = 0
|
||||
}
|
||||
|
||||
if is_negative {
|
||||
*ptr = 0x2D
|
||||
ptr += 1
|
||||
}
|
||||
// ! it gets broked when you do this ??
|
||||
// *ptr = 0
|
||||
|
||||
@inline(reverse, p)
|
||||
return p
|
||||
}
|
||||
|
||||
reverse := fn(s: ^u8): void {
|
||||
//reverse a string, don't remove digits
|
||||
len := 0
|
||||
loop if *(s + len) == 0 break else len += 1
|
||||
i := 0
|
||||
j := len - 1
|
||||
temp := 0
|
||||
loop if i >= j break else {
|
||||
temp = *(s + i);
|
||||
*(s + i) = *(s + j);
|
||||
*(s + j) = temp
|
||||
i += 1
|
||||
j := s + @inline(length, s) - 1
|
||||
temp := @as(u8, 0)
|
||||
loop if s < j {
|
||||
temp = *s;
|
||||
*s = *j;
|
||||
*j = temp
|
||||
s += 1
|
||||
j -= 1
|
||||
}
|
||||
return
|
||||
} else return
|
||||
}
|
||||
|
||||
equals := fn(lhs: ^u8, rhs: ^u8): bool {
|
||||
if lhs == rhs {
|
||||
return true
|
||||
}
|
||||
loop if *lhs != *rhs {
|
||||
return false
|
||||
} else if *lhs == 0 {
|
||||
return true
|
||||
} else {
|
||||
lhs += 1
|
||||
rhs += 1
|
||||
}
|
||||
}
|
63
sysdata/libraries/sunset_proto/src/client.hb
Normal file
63
sysdata/libraries/sunset_proto/src/client.hb
Normal file
|
@ -0,0 +1,63 @@
|
|||
.{math: .{Vec2}, buffer, log, memory, string} := @use("../../stn/src/lib.hb");
|
||||
.{Channel, Window, send_header, send_message, await_channel, await_header, await_message, message, BUFFER_SERVER, BUFFER_CLIENT, WindowProps, WindowData} := @use("./lib.hb");
|
||||
.{new_surface, Color} := @use("../../render/src/lib.hb")
|
||||
|
||||
// ! in the future this should be safely handled
|
||||
channel := Channel.(0, 0)
|
||||
|
||||
find_server := fn(): void {
|
||||
log.info("client: locating server\0")
|
||||
channel2 := await_channel()
|
||||
channel.server = channel2.server
|
||||
channel.client = channel2.client
|
||||
log.info("client: server located\0")
|
||||
}
|
||||
|
||||
new := fn(props: WindowProps): ?Window {
|
||||
send_header(message.syn, channel.server)
|
||||
response := await_message(Channel, channel.client)
|
||||
if response.header.kind != message.ack {
|
||||
return null
|
||||
}
|
||||
log.info("client: recv ack\0")
|
||||
send_message(WindowProps, message.props, props, response.body.server)
|
||||
windowdata := await_message(WindowData, response.body.client)
|
||||
if windowdata.header.kind != message.ack {
|
||||
return null
|
||||
}
|
||||
log.info("client: recv windowdata\0")
|
||||
surface := new_surface(windowdata.body.props.dimensions.x, windowdata.body.props.dimensions.y)
|
||||
return .(windowdata.body, surface)
|
||||
}
|
||||
|
||||
quit := fn(client: Window): void {
|
||||
send_header(message.quit, client.data.channel.server)
|
||||
}
|
||||
|
||||
connected := fn(client: Window): bool {
|
||||
return true
|
||||
}
|
||||
|
||||
shutdown_server := fn(client: Window): bool {
|
||||
return false
|
||||
}
|
||||
|
||||
update_props := fn(client: Window): bool {
|
||||
return false
|
||||
}
|
||||
|
||||
update_permissions := fn(client: Window): bool {
|
||||
return false
|
||||
}
|
||||
|
||||
send_frame := fn(client: Window): bool {
|
||||
send_header(message.frame_ready, client.data.channel.server)
|
||||
response := await_message(uint, client.data.channel.client)
|
||||
if response.header.kind != message.ack {
|
||||
return false
|
||||
}
|
||||
// ! FOR NOW, server will ALWAYS be local,
|
||||
// ! so we can send pointer to surface.
|
||||
send_message(^Color, message.ack, client.surface.buf, client.data.channel.server)
|
||||
return true
|
||||
}
|
97
sysdata/libraries/sunset_proto/src/lib.hb
Normal file
97
sysdata/libraries/sunset_proto/src/lib.hb
Normal file
|
@ -0,0 +1,97 @@
|
|||
.{math: .{Vec2}, buffer, memory} := @use("../../stn/src/lib.hb");
|
||||
.{Surface} := @use("../../render/src/lib.hb")
|
||||
|
||||
$BUFFER_SERVER := "sunset_server\0"
|
||||
$BUFFER_CLIENT := "sunset_client\0"
|
||||
|
||||
Channel := packed struct {
|
||||
client: uint,
|
||||
server: uint,
|
||||
}
|
||||
|
||||
client := @use("./client.hb")
|
||||
server := @use("./server.hb")
|
||||
message := @use("./message.hb")
|
||||
permissions := @use("./permissions.hb")
|
||||
|
||||
$send_message := fn($Expr: type, kind: MessageKind, msg: Expr, buffer_id: uint): void {
|
||||
buffer.write(?Message(Expr), buffer_id, &@as(?Message(Expr), .(.(kind), msg)))
|
||||
}
|
||||
|
||||
$send_header := fn(kind: MessageKind, buffer_id: uint): void {
|
||||
buffer.write(?MessageHeader, buffer_id, &@as(?MessageHeader, .(kind)))
|
||||
}
|
||||
|
||||
$recv_message := fn($Expr: type, buffer_id: uint): Message(Expr) {
|
||||
response := @as(?Message(Expr), null)
|
||||
buffer.recv(?Message(Expr), buffer_id, &response)
|
||||
return response
|
||||
}
|
||||
|
||||
$recv_header := fn(buffer_id: uint): ?MessageHeader {
|
||||
response := @as(?MessageHeader, null)
|
||||
buffer.recv(?MessageHeader, buffer_id, &response)
|
||||
return response
|
||||
}
|
||||
|
||||
await_channel := fn(): Channel {
|
||||
channel := Channel.(0, 0)
|
||||
loop if channel.server != 0 break else {
|
||||
channel.server = buffer.search(BUFFER_SERVER)
|
||||
}
|
||||
loop if channel.client != 0 break else {
|
||||
channel.client = buffer.search(BUFFER_CLIENT)
|
||||
}
|
||||
return channel
|
||||
}
|
||||
|
||||
await_message := fn($Expr: type, buffer_id: uint): Message(Expr) {
|
||||
response := @as(?Message(Expr), null)
|
||||
loop {
|
||||
buffer.recv(?Message(Expr), buffer_id, &response)
|
||||
if response != null {
|
||||
return @as(Message(Expr), response)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
await_header := fn(buffer_id: uint): MessageHeader {
|
||||
response := @as(?MessageHeader, null)
|
||||
loop {
|
||||
buffer.recv(?MessageHeader, buffer_id, &response)
|
||||
if response != null {
|
||||
return @as(?MessageHeader, response)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MessageKind := u8
|
||||
|
||||
MessageHeader := packed struct {
|
||||
kind: MessageKind,
|
||||
}
|
||||
|
||||
Message := fn($Expr: type): type {
|
||||
return packed struct {
|
||||
header: MessageHeader,
|
||||
body: Expr,
|
||||
}
|
||||
}
|
||||
|
||||
WindowProps := struct {
|
||||
position: Vec2(uint),
|
||||
dimensions: Vec2(uint),
|
||||
// ! replace with owned string type later
|
||||
title: ^u8,
|
||||
}
|
||||
|
||||
WindowData := struct {
|
||||
props: WindowProps,
|
||||
channel: Channel,
|
||||
permissions: uint,
|
||||
}
|
||||
|
||||
Window := struct {
|
||||
data: WindowData,
|
||||
surface: Surface,
|
||||
}
|
8
sysdata/libraries/sunset_proto/src/message.hb
Normal file
8
sysdata/libraries/sunset_proto/src/message.hb
Normal file
|
@ -0,0 +1,8 @@
|
|||
// ! all values in this file are subject to change.
|
||||
$syn := 1
|
||||
$ack := 2
|
||||
$refused := 3
|
||||
$quit := 4
|
||||
$props := 5
|
||||
$shutdown := 6
|
||||
$frame_ready := 7
|
5
sysdata/libraries/sunset_proto/src/permissions.hb
Normal file
5
sysdata/libraries/sunset_proto/src/permissions.hb
Normal file
|
@ -0,0 +1,5 @@
|
|||
$none := 0b0
|
||||
$exclusive_framebuffer := 0b1
|
||||
$shutdown := 0b100
|
||||
|
||||
$default := none
|
135
sysdata/libraries/sunset_proto/src/server.hb
Normal file
135
sysdata/libraries/sunset_proto/src/server.hb
Normal file
|
@ -0,0 +1,135 @@
|
|||
.{math, log, string, random, buffer, memory} := @use("../../stn/src/lib.hb");
|
||||
.{Color, Surface, new_surface, put_surface, sync, put_rect, put_filled_rect, text, put_text, clear, white, black} := @use("../../render/src/lib.hb");
|
||||
.{Channel, Window, WindowProps, WindowData, MessageHeader, BUFFER_SERVER, BUFFER_CLIENT, message, permissions, recv_header, recv_message, send_message, send_header, await_message} := @use("./lib.hb")
|
||||
|
||||
WindowServer := struct {
|
||||
window_count: uint,
|
||||
channel: Channel,
|
||||
// ! replace this with a collection when we get an allocator
|
||||
windows: [?Window; 10],
|
||||
font: text.Font,
|
||||
}
|
||||
|
||||
// ! in the future this should be safely handled
|
||||
server := @as(WindowServer, idk)
|
||||
|
||||
psf := @embed("../../../assets/consolefonts/tamsyn/10x20r.psf")
|
||||
|
||||
start := fn(): void {
|
||||
font := text.font_from_psf2(@bitcast(&psf), false)
|
||||
if font == null {
|
||||
log.error("server: failed to load asset\0")
|
||||
return
|
||||
}
|
||||
server = .(
|
||||
0,
|
||||
.{client: buffer.create(BUFFER_CLIENT), server: buffer.create(BUFFER_SERVER)},
|
||||
.(null, null, null, null, null, null, null, null, null, null),
|
||||
@as(text.Font, font),
|
||||
)
|
||||
log.info("server: started server\0")
|
||||
}
|
||||
|
||||
incoming := fn(): bool {
|
||||
msg := recv_header(server.channel.server)
|
||||
if msg == null {
|
||||
return true
|
||||
}
|
||||
if msg.kind == message.syn {
|
||||
log.info("server: recv syn\0")
|
||||
channel := Channel.(buffer.create_nameless(), buffer.create_nameless())
|
||||
send_message(Channel, message.ack, channel, server.channel.client)
|
||||
props := await_message(WindowProps, channel.server)
|
||||
if props.header.kind != message.props {
|
||||
return true
|
||||
}
|
||||
log.info("server: recv props\0")
|
||||
// ! do inspection of requested props here
|
||||
data := WindowData.(props.body, channel, permissions.default)
|
||||
send_message(WindowData, message.ack, data, channel.client)
|
||||
surface := new_window_decorations(data.props.dimensions)
|
||||
// decorations
|
||||
{
|
||||
title := data.props.title
|
||||
title_length := string.length(title)
|
||||
deco_length := title_length * 10
|
||||
// draw the window tab bar
|
||||
put_filled_rect(surface, .(0, 0), .(data.props.dimensions.x + DECO_WIDTH + deco_length, DECO_HEIGHT_TOP), DECO_COLOUR)
|
||||
// Draw the window tab
|
||||
put_filled_rect(surface, .(0, 0), .(deco_length, DECO_HEIGHT_TOP - 1), DECO_COLOUR_DARKER)
|
||||
|
||||
// Draw the outside box
|
||||
put_rect(surface, .(0, 0), data.props.dimensions + .(DECO_WIDTH - 1, DECO_HEIGHT_TOP + DECO_HEIGHT_BOTTOM - 1), DECO_COLOUR)
|
||||
|
||||
put_text(surface, server.font, .(2, 1), .(0, 0, 0, 255), data.props.title)
|
||||
}
|
||||
server.windows[server.window_count] = .(data, surface)
|
||||
server.window_count += 1
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
$DECO_WIDTH := 2
|
||||
$DECO_HEIGHT_TOP := 20
|
||||
$DECO_HEIGHT_BOTTOM := 1
|
||||
$DECO_COLOUR := Color.(100, 200, 255, 255)
|
||||
$DECO_COLOUR_DARKER := Color.(89, 57, 89, 255)
|
||||
|
||||
new_window_decorations := fn(dimensions: math.Vec2(uint)): Surface {
|
||||
return new_surface(
|
||||
dimensions.x + DECO_WIDTH,
|
||||
dimensions.y + DECO_HEIGHT_TOP + DECO_HEIGHT_BOTTOM,
|
||||
)
|
||||
}
|
||||
|
||||
// ! compositor code. this currently disallows tearing.
|
||||
|
||||
collect_frames := fn(): void {
|
||||
i := 0
|
||||
loop if i == 10 break else {
|
||||
window := server.windows[i]
|
||||
if window == null {
|
||||
i += 1
|
||||
continue
|
||||
}
|
||||
header := recv_header(window.data.channel.server)
|
||||
if header == null {
|
||||
i += 1
|
||||
continue
|
||||
}
|
||||
if header.kind != message.frame_ready {
|
||||
i += 1
|
||||
continue
|
||||
}
|
||||
send_header(message.ack, window.data.channel.client)
|
||||
ptr := await_message(^Color, window.data.channel.server)
|
||||
if ptr.header.kind != message.ack {
|
||||
return
|
||||
}
|
||||
put_surface(
|
||||
window.surface,
|
||||
Surface.(
|
||||
ptr.body,
|
||||
window.data.props.dimensions.x,
|
||||
window.data.props.dimensions.y,
|
||||
window.data.props.dimensions.x * window.data.props.dimensions.y,
|
||||
),
|
||||
.(DECO_WIDTH / 2, DECO_HEIGHT_TOP),
|
||||
false,
|
||||
)
|
||||
i += 1
|
||||
}
|
||||
}
|
||||
|
||||
render_clients := fn(screen: Surface): void {
|
||||
i := 0
|
||||
loop if i == 10 break else {
|
||||
window := server.windows[i]
|
||||
if window == null {
|
||||
i += 1
|
||||
continue
|
||||
}
|
||||
put_surface(screen, window.surface, window.data.props.position, false)
|
||||
i += 1
|
||||
}
|
||||
}
|
|
@ -1,14 +1,13 @@
|
|||
dt_api := @use("../../../libraries/dt_api/src/lib.hb");
|
||||
.{dt_get} := dt_api
|
||||
.{dt} := @use("../../../libraries/stn/src/lib.hb")
|
||||
|
||||
main := fn(): int {
|
||||
dt_api.dt_get("framebuffer/fb0/width\0")
|
||||
dt_api.dt_get("cpu/cpu0/architecture\0")
|
||||
main := fn(): void {
|
||||
dt.get(void, "framebuffer/fb0/width\0")
|
||||
dt.get(void, "cpu/cpu0/architecture\0")
|
||||
|
||||
// Checking if the first detected serial port is memory mapped or port mapped
|
||||
// 0 -> memory mapped
|
||||
// 1 -> port mapped
|
||||
dt_get("serial_ports/sp0/mapping\0")
|
||||
dt.get(void, "serial_ports/sp0/mapping\0")
|
||||
|
||||
return 0
|
||||
return
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
READ_ONLY := 0x1
|
||||
HIDDEN := 0x2
|
||||
SYSTEM := 0x4
|
||||
VOLUME_ID := 0x8
|
||||
DIRECTORY := 0x10
|
||||
ARCHIVE := 0x20
|
||||
READ_ONLY := @as(u32, 0x1)
|
||||
HIDDEN := @as(u32, 0x2)
|
||||
SYSTEM := @as(u32, 0x4)
|
||||
VOLUME_ID := @as(u32, 0x8)
|
||||
DIRECTORY := @as(u32, 0x10)
|
||||
ARCHIVE := @as(u32, 0x20)
|
||||
LFN := READ_ONLY | HIDDEN | SYSTEM | VOLUME_ID
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue