forked from AbleOS/ableos
Compare commits
127 commits
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 | ||
Able | f64f654610 | ||
Able | 7d4b12a103 | ||
Able | 758629df0a | ||
Able | 04a449965b | ||
koniifer | 0bbc76124f | ||
Able | 6ad68dabac | ||
Able | 07c7d52b8c | ||
Able | 2edc8148ca | ||
5f59f05dce | |||
Able | 0bc757164f | ||
Able | f5f68bc2df | ||
Able | 7a256dde68 | ||
Able | 570b566310 | ||
Able | d2488689fe | ||
Able | fe70d81bd0 | ||
Able | cc076d9540 | ||
Able | 3173b63c93 | ||
koniifer | 48027196b1 | ||
koniifer | 78553a3190 | ||
koniifer | df74b09134 | ||
koniifer | 2321efd2e7 | ||
Able | d9caa17f3c | ||
Able | b0ecbfa168 | ||
Able | 1fe20360f6 | ||
Able | fb42351638 |
|
@ -1,3 +1,3 @@
|
||||||
[alias]
|
[alias]
|
||||||
repbuild = "run --manifest-path ./repbuild/Cargo.toml -r --"
|
repbuild = "run --manifest-path ./repbuild/Cargo.toml -- "
|
||||||
dev = "run --manifest-path ./dev/Cargo.toml -r --"
|
dev = "run --manifest-path ./dev/Cargo.toml -r --"
|
||||||
|
|
1231
Cargo.lock
generated
1231
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">
|
<img src="https://img.shields.io/liberapay/patrons/AbleTheAbove.svg?logo=liberapay">
|
||||||
|
|
||||||
# Compiling
|
# Compiling
|
||||||
AbleOS should be able to be built on any platform which is supported by
|
See [HELP.md](HELP.md)
|
||||||
[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`
|
|
||||||
|
|
||||||
# Developing
|
# 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)
|
|
@ -72,6 +72,27 @@ pub fn new(development_type: DevelopmentType, name: String) {
|
||||||
let readme_contents = format!("# {}", name);
|
let readme_contents = format!("# {}", name);
|
||||||
readme_file.write_all(readme_contents.as_bytes()).unwrap();
|
readme_file.write_all(readme_contents.as_bytes()).unwrap();
|
||||||
|
|
||||||
|
let contents = format!(
|
||||||
|
"[package]
|
||||||
|
name = \"{}\"
|
||||||
|
authors = [\"\"]
|
||||||
|
|
||||||
|
[dependants.libraries]
|
||||||
|
|
||||||
|
[dependants.binaries]
|
||||||
|
hblang.version = \"1.0.0\"
|
||||||
|
|
||||||
|
[build]
|
||||||
|
command = \"hblang src/main.hb\"
|
||||||
|
",
|
||||||
|
name
|
||||||
|
);
|
||||||
|
|
||||||
|
let toml_path_string = format!("{}/meta.toml", project_folder_path_string);
|
||||||
|
let mut readme_file = std::fs::File::create(toml_path_string.clone()).unwrap();
|
||||||
|
|
||||||
|
readme_file.write_all(contents.as_bytes()).unwrap();
|
||||||
|
|
||||||
let src_folder_path_string = format!("{}/src", project_folder_path_string);
|
let src_folder_path_string = format!("{}/src", project_folder_path_string);
|
||||||
std::fs::create_dir(src_folder_path_string.clone()).unwrap();
|
std::fs::create_dir(src_folder_path_string.clone()).unwrap();
|
||||||
|
|
||||||
|
@ -117,8 +138,8 @@ fn build(name: String) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn build_program(name: String) {}
|
pub fn build_program(_name: String) {}
|
||||||
pub fn build_library(name: String) {}
|
pub fn build_library(_name: String) {}
|
||||||
|
|
||||||
fn help() {
|
fn help() {
|
||||||
println!(
|
println!(
|
||||||
|
|
|
@ -4,6 +4,3 @@ build-std-features = ["compiler-builtins-mem"]
|
||||||
|
|
||||||
[build]
|
[build]
|
||||||
target = "./targets/x86_64-ableos.json"
|
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]
|
[dependencies]
|
||||||
embedded-graphics = "0.8"
|
# embedded-graphics = "0.8"
|
||||||
hbvm.git = "https://git.ablecorp.us/ableos/holey-bytes"
|
hbvm = { git = "https://git.ablecorp.us/AbleOS/holey-bytes.git", features = [
|
||||||
|
"nightly",
|
||||||
|
] }
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
spin = "0.9"
|
spin = "0.9"
|
||||||
slab = { version = "0.4", default-features = false }
|
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"
|
xml.git = "https://git.ablecorp.us/ableos/ableos_userland"
|
||||||
versioning.git = "https://git.ablecorp.us/ableos/ableos_userland"
|
versioning.git = "https://git.ablecorp.us/ableos/ableos_userland"
|
||||||
# able_graphics_library.git = "https://git.ablecorp.us/ableos/ableos_userland"
|
# able_graphics_library.git = "https://git.ablecorp.us/ableos/ableos_userland"
|
||||||
hashbrown = { version = "0.14", features = ["nightly"] }
|
hashbrown = { version = "0.15", features = ["nightly"] }
|
||||||
|
limine = "0.1"
|
||||||
[dependencies.limine]
|
|
||||||
version = "0.1"
|
|
||||||
#git = "https://github.com/limine-bootloader/limine-rs"
|
|
||||||
|
|
||||||
[dependencies.crossbeam-queue]
|
[dependencies.crossbeam-queue]
|
||||||
version = "0.3"
|
version = "0.3"
|
||||||
default-features = false
|
default-features = false
|
||||||
features = ["alloc", "nightly"]
|
features = ["alloc", "nightly"]
|
||||||
|
|
||||||
# [dependencies.clparse]
|
|
||||||
# git = "https://git.ablecorp.us/ableos/ableos_userland"
|
|
||||||
# default-features = false
|
|
||||||
|
|
||||||
[dependencies.derive_more]
|
[dependencies.derive_more]
|
||||||
version = "1"
|
version = "1"
|
||||||
default-features = false
|
default-features = false
|
||||||
features = [
|
features = [
|
||||||
"add",
|
"add",
|
||||||
"add_assign",
|
"add_assign",
|
||||||
"constructor",
|
"constructor",
|
||||||
"display",
|
"display",
|
||||||
"from",
|
"from",
|
||||||
"into",
|
"into",
|
||||||
"mul",
|
"mul",
|
||||||
"mul_assign",
|
"mul_assign",
|
||||||
"not",
|
"not",
|
||||||
"sum",
|
"sum",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
[target.'cfg(target_arch = "x86_64")'.dependencies]
|
[target.'cfg(target_arch = "x86_64")'.dependencies]
|
||||||
x86_64 = "0.15"
|
x86_64 = "0.15"
|
||||||
x2apic = "0.4"
|
x2apic = "0.4"
|
||||||
virtio-drivers = "0.7"
|
# virtio-drivers = "0.7"
|
||||||
|
|
||||||
[target.'cfg(target_arch = "riscv64")'.dependencies]
|
[target.'cfg(target_arch = "riscv64")'.dependencies]
|
||||||
sbi = "0.2.0"
|
sbi = "0.2.0"
|
||||||
|
|
|
@ -38,6 +38,7 @@ SECTIONS
|
||||||
|
|
||||||
.data : {
|
.data : {
|
||||||
*(.data .data.*)
|
*(.data .data.*)
|
||||||
|
*(.got .got.*)
|
||||||
} :data
|
} :data
|
||||||
|
|
||||||
.bss : {
|
.bss : {
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
use {
|
use {
|
||||||
crate::{alloc::string::ToString, device_tree::DeviceTree, kmain::DEVICE_TREE},
|
crate::{device_tree::DeviceTree, kmain::DEVICE_TREE},
|
||||||
alloc::string::String,
|
|
||||||
core::arch::asm,
|
core::arch::asm,
|
||||||
xml::XMLElement,
|
xml::XMLElement,
|
||||||
};
|
};
|
||||||
|
@ -28,7 +27,7 @@ fn collect_cpu_info(device_tree: &mut DeviceTree) {
|
||||||
cpus.push(cpu);
|
cpus.push(cpu);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cpu_id() -> (String, u64) {
|
fn cpu_id<'a>() -> (&'a str, u64) {
|
||||||
let mut cpu_id: u64;
|
let mut cpu_id: u64;
|
||||||
unsafe {
|
unsafe {
|
||||||
asm!("mrs {cpu_id}, MIDR_EL1",
|
asm!("mrs {cpu_id}, MIDR_EL1",
|
||||||
|
@ -39,11 +38,11 @@ fn cpu_id() -> (String, u64) {
|
||||||
let cpu_name = match cpu_id {
|
let cpu_name = match cpu_id {
|
||||||
// the source of these two was a stackoverflow question
|
// the source of these two was a stackoverflow question
|
||||||
// https://raspberrypi.stackexchange.com/questions/117175/how-do-i-read-the-cpuid-in-aarch64-asm
|
// https://raspberrypi.stackexchange.com/questions/117175/how-do-i-read-the-cpuid-in-aarch64-asm
|
||||||
0x410FD034 => "Cortex-A53".to_string(),
|
0x410FD034 => "Cortex-A53",
|
||||||
0x410FD083 => "Cortex-A72".to_string(),
|
0x410FD083 => "Cortex-A72",
|
||||||
// the source of this one was checking the cpu id :thinking:
|
// the source of this one was checking the cpu id :thinking:
|
||||||
0x410FD493 => "Neoverse N2".to_string(),
|
0x410FD493 => "Neoverse N2",
|
||||||
_ => "Unknown".to_string(),
|
_ => "Unknown",
|
||||||
};
|
};
|
||||||
log::trace!("CPU Name: {cpu_name} - CPU ID: 0x{:X}", cpu_id);
|
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,
|
uart: 0x09000000 as *mut u8,
|
||||||
});
|
});
|
||||||
|
|
||||||
struct SerialConsole {
|
pub struct SerialConsole {
|
||||||
uart: *mut u8,
|
uart: *mut u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@ unsafe impl Send for SerialConsole {}
|
||||||
|
|
||||||
pub fn log(args: core::fmt::Arguments<'_>) -> core::fmt::Result {
|
pub fn log(args: core::fmt::Arguments<'_>) -> core::fmt::Result {
|
||||||
SERIAL_CONSOLE.lock().write_fmt(args)?;
|
SERIAL_CONSOLE.lock().write_fmt(args)?;
|
||||||
TERMINAL_LOGGER.lock().write_fmt(args)?;
|
// TERMINAL_LOGGER.lock().write_fmt(args)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,3 +14,29 @@ arch_cond!(
|
||||||
riscv64: "riscv64",
|
riscv64: "riscv64",
|
||||||
x86_64: "x86_64",
|
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)
|
||||||
|
});
|
||||||
|
|
|
@ -12,7 +12,7 @@ use {
|
||||||
pub const DOUBLE_FAULT_IX: u16 = 0;
|
pub const DOUBLE_FAULT_IX: u16 = 0;
|
||||||
|
|
||||||
const STACK_SIZE: usize = 5 * 1024;
|
const STACK_SIZE: usize = 5 * 1024;
|
||||||
const STACK_ALIGNMENT: usize = 4096;
|
const STACK_ALIGNMENT: usize = 1;
|
||||||
|
|
||||||
pub unsafe fn init() {
|
pub unsafe fn init() {
|
||||||
use x86_64::instructions::{
|
use x86_64::instructions::{
|
||||||
|
@ -39,7 +39,7 @@ static TSS: Lazy<TaskStateSegment> = Lazy::new(|| {
|
||||||
let stack_ptr = unsafe {
|
let stack_ptr = unsafe {
|
||||||
let layout = alloc::alloc::Layout::from_size_align(STACK_SIZE, STACK_ALIGNMENT)
|
let layout = alloc::alloc::Layout::from_size_align(STACK_SIZE, STACK_ALIGNMENT)
|
||||||
.expect("Failed to create stack layout");
|
.expect("Failed to create stack layout");
|
||||||
let stack = alloc::alloc::alloc_zeroed(layout);
|
let stack = alloc::alloc::alloc(layout);
|
||||||
VirtAddr::from_ptr(stack) + STACK_SIZE as u64
|
VirtAddr::from_ptr(stack) + STACK_SIZE as u64
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,56 +1,54 @@
|
||||||
// TODO: Turn apic keyboard interrupt into a standard ipc message
|
|
||||||
use {
|
use {
|
||||||
|
core::mem::MaybeUninit,
|
||||||
log::trace,
|
log::trace,
|
||||||
spin::{Lazy, Mutex},
|
|
||||||
x2apic::lapic::{LocalApic, LocalApicBuilder},
|
x2apic::lapic::{LocalApic, LocalApicBuilder},
|
||||||
x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame, PageFaultErrorCode},
|
x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame, PageFaultErrorCode},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub unsafe fn init() {
|
/// Safety: Using LAPIC or IDT before init() is UB
|
||||||
trace!("Initialising IDT");
|
/// Using
|
||||||
IDT.load();
|
static mut LAPIC: LocalApic = unsafe { MaybeUninit::zeroed().assume_init() };
|
||||||
Lazy::force(&LAPIC);
|
static mut IDT: InterruptDescriptorTable = unsafe { MaybeUninit::zeroed().assume_init() };
|
||||||
x86_64::instructions::interrupts::enable();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
enum Interrupt {
|
#[derive(Debug, Eq, Hash, PartialEq)]
|
||||||
Timer = 32,
|
|
||||||
|
|
||||||
|
pub enum Interrupt {
|
||||||
|
Timer = 32,
|
||||||
ApicErr = u8::MAX - 1,
|
ApicErr = u8::MAX - 1,
|
||||||
Spurious = u8::MAX,
|
Spurious = u8::MAX,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) static LAPIC: Lazy<Mutex<LocalApic>> = Lazy::new(|| {
|
pub unsafe fn init() {
|
||||||
let mut lapic = LocalApicBuilder::new()
|
trace!("Initializing IDT and LAPIC");
|
||||||
|
|
||||||
|
// Initialize and load the IDT
|
||||||
|
IDT = InterruptDescriptorTable::new();
|
||||||
|
IDT.double_fault
|
||||||
|
.set_handler_fn(double_fault)
|
||||||
|
.set_stack_index(super::gdt::DOUBLE_FAULT_IX);
|
||||||
|
IDT.page_fault.set_handler_fn(page_fault);
|
||||||
|
|
||||||
|
IDT[Interrupt::ApicErr as u8].set_handler_fn(apic_err);
|
||||||
|
IDT[Interrupt::Spurious as u8].set_handler_fn(spurious);
|
||||||
|
IDT[Interrupt::Timer as u8].set_handler_fn(timer);
|
||||||
|
|
||||||
|
IDT.load();
|
||||||
|
|
||||||
|
LAPIC = LocalApicBuilder::new()
|
||||||
.timer_vector(Interrupt::Timer as usize)
|
.timer_vector(Interrupt::Timer as usize)
|
||||||
.error_vector(Interrupt::ApicErr as usize)
|
.error_vector(Interrupt::ApicErr as usize)
|
||||||
.spurious_vector(Interrupt::Spurious as usize)
|
.spurious_vector(Interrupt::Spurious as usize)
|
||||||
.set_xapic_base(
|
.set_xapic_base(
|
||||||
unsafe { x2apic::lapic::xapic_base() }
|
x2apic::lapic::xapic_base()
|
||||||
+ super::memory::HHDM_OFFSET.load(core::sync::atomic::Ordering::Relaxed),
|
+ super::memory::HHDM_OFFSET.load(core::sync::atomic::Ordering::Relaxed),
|
||||||
)
|
)
|
||||||
.build()
|
.build()
|
||||||
.expect("failed to setup Local APIC");
|
.expect("Failed to setup Local APIC");
|
||||||
unsafe { lapic.enable() };
|
LAPIC.enable();
|
||||||
Mutex::new(lapic)
|
|
||||||
});
|
|
||||||
|
|
||||||
static IDT: Lazy<InterruptDescriptorTable> = Lazy::new(|| {
|
x86_64::instructions::interrupts::enable();
|
||||||
let mut idt = InterruptDescriptorTable::new();
|
}
|
||||||
unsafe {
|
|
||||||
idt.double_fault
|
|
||||||
.set_handler_fn(double_fault)
|
|
||||||
.set_stack_index(super::gdt::DOUBLE_FAULT_IX);
|
|
||||||
}
|
|
||||||
idt.page_fault.set_handler_fn(page_fault);
|
|
||||||
|
|
||||||
idt[Interrupt::ApicErr as u8].set_handler_fn(apic_err);
|
|
||||||
idt[Interrupt::Spurious as u8].set_handler_fn(spurious);
|
|
||||||
idt[Interrupt::Timer as u8].set_handler_fn(timer);
|
|
||||||
|
|
||||||
idt
|
|
||||||
});
|
|
||||||
|
|
||||||
extern "x86-interrupt" fn double_fault(stack_frame: InterruptStackFrame, error_code: u64) -> ! {
|
extern "x86-interrupt" fn double_fault(stack_frame: InterruptStackFrame, error_code: u64) -> ! {
|
||||||
panic!("Double fault: error code {error_code} \n{stack_frame:#?}")
|
panic!("Double fault: error code {error_code} \n{stack_frame:#?}")
|
||||||
|
@ -64,13 +62,49 @@ extern "x86-interrupt" fn page_fault(
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "x86-interrupt" fn timer(_isf: InterruptStackFrame) {
|
extern "x86-interrupt" fn timer(_isf: InterruptStackFrame) {
|
||||||
unsafe { LAPIC.lock().end_of_interrupt() };
|
// interrupt(Interrupt::Timer);
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
LAPIC.end_of_interrupt();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "x86-interrupt" fn apic_err(_: InterruptStackFrame) {
|
extern "x86-interrupt" fn apic_err(_: InterruptStackFrame) {
|
||||||
|
interrupt(Interrupt::ApicErr);
|
||||||
|
|
||||||
panic!("Internal APIC error");
|
panic!("Internal APIC error");
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "x86-interrupt" fn spurious(_: InterruptStackFrame) {
|
extern "x86-interrupt" fn spurious(_: InterruptStackFrame) {
|
||||||
unsafe { LAPIC.lock().end_of_interrupt() };
|
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(crate) mod interrupts;
|
||||||
pub mod logging;
|
pub mod logging;
|
||||||
pub mod pci;
|
pub mod pci;
|
||||||
pub mod virtio;
|
// pub mod virtio;
|
||||||
|
|
||||||
pub use {logging::log, memory::PAGE_SIZE};
|
pub use {logging::log, memory::PAGE_SIZE};
|
||||||
|
|
||||||
|
@ -30,9 +30,11 @@ const INITIAL_KERNEL_HEAP_SIZE: *const () = _initial_kernel_heap_size as _;
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
#[naked]
|
#[naked]
|
||||||
|
#[cfg(not(target_feature = "avx2"))]
|
||||||
unsafe extern "C" fn _kernel_start() -> ! {
|
unsafe extern "C" fn _kernel_start() -> ! {
|
||||||
// Initialise SSE and jump to kernel entrypoint
|
// Initialise SSE, then jump to kernel entrypoint
|
||||||
core::arch::asm!(
|
core::arch::naked_asm!(
|
||||||
|
// Initialise SSE
|
||||||
"mov rax, cr0",
|
"mov rax, cr0",
|
||||||
"and ax, 0xfffb",
|
"and ax, 0xfffb",
|
||||||
"or ax, 0x2",
|
"or ax, 0x2",
|
||||||
|
@ -40,16 +42,74 @@ unsafe extern "C" fn _kernel_start() -> ! {
|
||||||
"mov rax, cr4",
|
"mov rax, cr4",
|
||||||
"or ax, 3 << 9",
|
"or ax, 3 << 9",
|
||||||
"mov cr4, rax",
|
"mov cr4, rax",
|
||||||
|
|
||||||
|
// Jump to the kernel entry point
|
||||||
"jmp {}",
|
"jmp {}",
|
||||||
sym start,
|
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() -> ! {
|
unsafe extern "C" fn start() -> ! {
|
||||||
logging::init();
|
logging::init();
|
||||||
crate::logger::init().expect("failed to set logger");
|
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);
|
static HDHM_REQ: HhdmRequest = HhdmRequest::new(0);
|
||||||
memory::init_pt(VirtAddr::new(
|
memory::init_pt(VirtAddr::new(
|
||||||
|
@ -128,7 +188,7 @@ unsafe extern "C" fn start() -> ! {
|
||||||
// TODO: Add in rdseed and rdrand as sources for randomness
|
// TODO: Add in rdseed and rdrand as sources for randomness
|
||||||
let _rand = xml::XMLElement::new("Random");
|
let _rand = xml::XMLElement::new("Random");
|
||||||
|
|
||||||
log::trace!("Getting boot modules");
|
log::debug!("Getting boot modules");
|
||||||
let bm = MOD_REQ.get_response().get();
|
let bm = MOD_REQ.get_response().get();
|
||||||
|
|
||||||
let mut bootmodules = alloc::vec::Vec::new();
|
let mut bootmodules = alloc::vec::Vec::new();
|
||||||
|
@ -166,7 +226,7 @@ unsafe extern "C" fn start() -> ! {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
log::info!("Boot module count: {:?}", bootmodules.len());
|
log::debug!("Boot module count: {:?}", bootmodules.len());
|
||||||
assert_eq!(bm.module_count, bootmodules.len() as u64);
|
assert_eq!(bm.module_count, bootmodules.len() as u64);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -189,6 +249,7 @@ unsafe extern "C" fn start() -> ! {
|
||||||
/// Spin loop
|
/// Spin loop
|
||||||
pub fn spin_loop() -> ! {
|
pub fn spin_loop() -> ! {
|
||||||
loop {
|
loop {
|
||||||
|
core::hint::spin_loop();
|
||||||
x86_64::instructions::hlt()
|
x86_64::instructions::hlt()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,13 +8,12 @@ pub struct PciDeviceInfo {
|
||||||
pub full_class: PciFullClass,
|
pub full_class: PciFullClass,
|
||||||
pub rev_id: u8,
|
pub rev_id: u8,
|
||||||
}
|
}
|
||||||
use crate::alloc::string::ToString;
|
|
||||||
|
|
||||||
/// Enumerate PCI devices and run initialisation routines on ones we support
|
/// Enumerate PCI devices and run initialisation routines on ones we support
|
||||||
pub fn init(device_tree: &mut DeviceTree) {
|
pub fn init(device_tree: &mut DeviceTree) {
|
||||||
device_tree
|
device_tree
|
||||||
.devices
|
.devices
|
||||||
.insert("Unidentified PCI".to_string(), alloc::vec![]);
|
.insert("Unidentified PCI", alloc::vec![]);
|
||||||
let mut devices = alloc::vec![];
|
let mut devices = alloc::vec![];
|
||||||
|
|
||||||
for bus in 0..=255 {
|
for bus in 0..=255 {
|
||||||
|
@ -47,7 +46,8 @@ pub fn init(device_tree: &mut DeviceTree) {
|
||||||
pci_info.set_attribute("id", id);
|
pci_info.set_attribute("id", id);
|
||||||
pci_info.set_attribute("device", device_info.device);
|
pci_info.set_attribute("device", device_info.device);
|
||||||
pci_info.set_attribute("vendor", vendor);
|
pci_info.set_attribute("vendor", vendor);
|
||||||
pci_info.set_attribute("class", device_info.full_class.to_string());
|
pci_info.set_attribute("bus", bus);
|
||||||
|
pci_info.set_attribute("class", device_info.full_class);
|
||||||
dev.set_child(pci_info);
|
dev.set_child(pci_info);
|
||||||
devices.push((dev_type, dev));
|
devices.push((dev_type, dev));
|
||||||
}
|
}
|
||||||
|
@ -68,7 +68,8 @@ pub fn check_device(bus: u8, device: u8) -> Option<PciDeviceInfo> {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
let reg2 = unsafe { pci_config_read(bus, device, 0, 0x8) };
|
let (reg2, addr) = unsafe { pci_config_read_2(bus, device, 0, 0x8) };
|
||||||
|
log::debug!("pci device-({}) addr {} is {}", device, addr, reg2);
|
||||||
let class = ((reg2 >> 16) & 0x0000_FFFF) as u16;
|
let class = ((reg2 >> 16) & 0x0000_FFFF) as u16;
|
||||||
let pci_class = PciFullClass::from_u16(class);
|
let pci_class = PciFullClass::from_u16(class);
|
||||||
let header_type = get_header_type(bus, device, 0);
|
let header_type = get_header_type(bus, device, 0);
|
||||||
|
@ -459,9 +460,7 @@ unsafe fn pci_config_read(bus: u8, device: u8, func: u8, offset: u8) -> u32 {
|
||||||
let func = func as u32;
|
let func = func as u32;
|
||||||
let offset = offset as u32;
|
let offset = offset as u32;
|
||||||
// construct address param
|
// construct address param
|
||||||
let address =
|
let address = (bus << 16) | (device << 11) | (func << 8) | (offset & 0xFC) | 0x8000_0000;
|
||||||
((bus << 16) | (device << 11) | (func << 8) | (offset & 0xFC) | 0x8000_0000) as u32;
|
|
||||||
|
|
||||||
// write address
|
// write address
|
||||||
Port::new(0xCF8).write(address);
|
Port::new(0xCF8).write(address);
|
||||||
|
|
||||||
|
@ -469,6 +468,20 @@ unsafe fn pci_config_read(bus: u8, device: u8, func: u8, offset: u8) -> u32 {
|
||||||
Port::new(0xCFC).read()
|
Port::new(0xCFC).read()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsafe fn pci_config_read_2(bus: u8, device: u8, func: u8, offset: u8) -> (u32, u32) {
|
||||||
|
let bus = bus as u32;
|
||||||
|
let device = device as u32;
|
||||||
|
let func = func as u32;
|
||||||
|
let offset = offset as u32;
|
||||||
|
// construct address param
|
||||||
|
let address = (bus << 16) | (device << 11) | (func << 8) | (offset & 0xFC) | 0x8000_0000;
|
||||||
|
// write address
|
||||||
|
Port::new(0xCF8).write(address);
|
||||||
|
|
||||||
|
// read data
|
||||||
|
(Port::new(0xCFC).read(), address)
|
||||||
|
}
|
||||||
|
|
||||||
unsafe fn pci_config_write(bus: u8, device: u8, func: u8, offset: u8, value: u32) {
|
unsafe fn pci_config_write(bus: u8, device: u8, func: u8, offset: u8, value: u32) {
|
||||||
let bus = bus as u32;
|
let bus = bus as u32;
|
||||||
let device = device as u32;
|
let device = device as u32;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use {
|
use {
|
||||||
core::{ptr::NonNull},
|
core::ptr::NonNull,
|
||||||
virtio_drivers::{BufferDirection, Hal, PhysAddr},
|
virtio_drivers::{BufferDirection, Hal, PhysAddr},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,6 @@
|
||||||
//! A tree of hardware devices
|
//! A tree of hardware devices
|
||||||
|
|
||||||
use {
|
use {alloc::vec::Vec, core::fmt, hashbrown::HashMap};
|
||||||
crate::alloc::string::ToString,
|
|
||||||
alloc::{string::String, vec::Vec},
|
|
||||||
core::fmt,
|
|
||||||
hashbrown::HashMap,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// A device object.
|
/// A device object.
|
||||||
/// TODO define device
|
/// TODO define device
|
||||||
|
@ -14,11 +9,11 @@ pub type Device = xml::XMLElement;
|
||||||
/// A tree of devices
|
/// A tree of devices
|
||||||
// TODO: alphabetize this list
|
// TODO: alphabetize this list
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct DeviceTree {
|
pub struct DeviceTree<'a> {
|
||||||
/// The device tree
|
/// 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
|
/// Build the device tree. Does not populate the device tree
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
let mut dt = Self {
|
let mut dt = Self {
|
||||||
|
@ -47,7 +42,7 @@ impl DeviceTree {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
use crate::{device_tree, tab, utils::TAB};
|
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 {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
writeln!(f)?;
|
writeln!(f)?;
|
||||||
for (device_type, devices) in &self.devices {
|
for (device_type, devices) in &self.devices {
|
||||||
|
|
35
kernel/src/exe_format.rs
Normal file
35
kernel/src/exe_format.rs
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
enum Sections {
|
||||||
|
Header,
|
||||||
|
Code,
|
||||||
|
Data,
|
||||||
|
Debug,
|
||||||
|
Config,
|
||||||
|
Metadata,
|
||||||
|
}
|
||||||
|
|
||||||
|
// 64 byte header
|
||||||
|
#[repr(packed)]
|
||||||
|
struct AbleOsExecutableHeader {
|
||||||
|
magic_number: [u8; 3],
|
||||||
|
executable_version: u32,
|
||||||
|
|
||||||
|
code_length: u64,
|
||||||
|
data_length: u64,
|
||||||
|
debug_length: u64,
|
||||||
|
config_length: u64,
|
||||||
|
metadata_length: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AbleOsExecutableHeader {
|
||||||
|
fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
magic_number: [0x15, 0x91, 0xD2],
|
||||||
|
executable_version: 0,
|
||||||
|
code_length: 0,
|
||||||
|
config_length: 0,
|
||||||
|
data_length: 0,
|
||||||
|
debug_length: 0,
|
||||||
|
metadata_length: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,22 +1,41 @@
|
||||||
//! Environment call handling routines
|
//! Environment call handling routines
|
||||||
|
|
||||||
use crate::holeybytes::kernel_services::{
|
use {alloc::boxed::Box, core::cell::LazyCell, hbvm::mem::Address};
|
||||||
block_read, dt_msg_handler::dt_msg_handler, logging_service::log_msg_handler,
|
|
||||||
service_definition_service::sds_msg_handler,
|
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 {
|
use {
|
||||||
super::Vm,
|
super::Vm,
|
||||||
crate::{arch, ipc::buffer::IpcBuffer, kmain::IPC_BUFFERS},
|
crate::{arch, ipc::buffer::IpcBuffer, kmain::IPC_BUFFERS},
|
||||||
|
hbvm::value::Value,
|
||||||
log::{debug, error, info, trace},
|
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) {
|
pub fn handler(vm: &mut Vm) {
|
||||||
let ecall_number = vm.registers[2].cast::<u64>();
|
let ecall_number = vm.registers[2].cast::<u64>();
|
||||||
|
|
||||||
// debug!("Ecall number {:?}", ecall_number);
|
|
||||||
//info!("Register dump: {:?}", vm.registers);
|
|
||||||
|
|
||||||
match ecall_number {
|
match ecall_number {
|
||||||
0 => {
|
0 => {
|
||||||
// TODO: explode computer
|
// TODO: explode computer
|
||||||
|
@ -28,9 +47,9 @@ pub fn handler(vm: &mut Vm) {
|
||||||
1 => {
|
1 => {
|
||||||
// Make buffer
|
// Make buffer
|
||||||
|
|
||||||
let bounded = match vm.registers[3].cast::<u64>() {
|
let bounded = match vm.registers[3] {
|
||||||
0 => false,
|
Value(0) => false,
|
||||||
1 => true,
|
Value(1) => true,
|
||||||
_ => {
|
_ => {
|
||||||
panic!("Bad");
|
panic!("Bad");
|
||||||
}
|
}
|
||||||
|
@ -39,22 +58,19 @@ pub fn handler(vm: &mut Vm) {
|
||||||
let length = vm.registers[4].cast::<u64>();
|
let length = vm.registers[4].cast::<u64>();
|
||||||
|
|
||||||
let mut buffs = IPC_BUFFERS.lock();
|
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();
|
let buff_id = arch::hardware_random_u64();
|
||||||
buffs.insert(buff_id, abc);
|
buffs.insert(
|
||||||
info!("Buffer ID: {}", buff_id);
|
buff_id,
|
||||||
|
match bounded {
|
||||||
|
false => IpcBuffer::new(false, 0),
|
||||||
|
true => IpcBuffer::new(true, length),
|
||||||
|
},
|
||||||
|
);
|
||||||
vm.registers[1] = hbvm::value::Value(buff_id);
|
vm.registers[1] = hbvm::value::Value(buff_id);
|
||||||
}
|
}
|
||||||
2 => {
|
2 => {
|
||||||
|
log::error!("Oops, deleting buffers is not implemented.")
|
||||||
// Delete buffer
|
// Delete buffer
|
||||||
}
|
}
|
||||||
3 => {
|
3 => {
|
||||||
|
@ -63,7 +79,6 @@ pub fn handler(vm: &mut Vm) {
|
||||||
let mem_addr = vm.registers[4].cast::<u64>();
|
let mem_addr = vm.registers[4].cast::<u64>();
|
||||||
let length = vm.registers[5].cast::<u64>() as usize;
|
let length = vm.registers[5].cast::<u64>() as usize;
|
||||||
trace!("IPC address: {:?}", mem_addr);
|
trace!("IPC address: {:?}", mem_addr);
|
||||||
use alloc::vec::Vec;
|
|
||||||
|
|
||||||
match buffer_id {
|
match buffer_id {
|
||||||
0 => match sds_msg_handler(vm, mem_addr, length) {
|
0 => match sds_msg_handler(vm, mem_addr, length) {
|
||||||
|
@ -81,77 +96,43 @@ pub fn handler(vm: &mut Vm) {
|
||||||
Err(_) => {}
|
Err(_) => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[cfg(not(target_arch = "x86_64"))]
|
|
||||||
3 => info!("TODO: implement whatever buffer 3 does for no x86_64"),
|
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
3 => {
|
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_vec = block_read(mem_addr, length);
|
||||||
let msg_type = msg_vec[0];
|
let msg_type = msg_vec[0];
|
||||||
match msg_type {
|
match msg_type {
|
||||||
0 => 'wow: {
|
0 => unsafe {
|
||||||
let size = match msg_vec[0] {
|
let size = msg_vec[1];
|
||||||
0 => 1,
|
let addr =
|
||||||
1 => 2,
|
u16::from_le_bytes(msg_vec[2..4].try_into().unwrap_unchecked());
|
||||||
2 => 4,
|
let value = match size {
|
||||||
_ => {
|
0 => x86_in::<u8>(addr) as u64,
|
||||||
error!("Tried to write more than 32 bits");
|
1 => x86_in::<u16>(addr) as u64,
|
||||||
break 'wow;
|
2 => x86_in::<u32>(addr) as u64,
|
||||||
}
|
_ => panic!("Trying to read size other than: 8, 16, 32 from port."),
|
||||||
};
|
};
|
||||||
let addr = u16::from_le_bytes(msg_vec[1..3].try_into().unwrap());
|
// info!("Read the value {} from address {}", value, addr);
|
||||||
let value = unsafe {
|
|
||||||
match size {
|
|
||||||
1 => x86_in::<u8>(addr) as u64,
|
|
||||||
2 => x86_in::<u16>(addr) as u64,
|
|
||||||
4 => x86_in::<u32>(addr) as u64,
|
|
||||||
_ => panic!("how?"),
|
|
||||||
}
|
|
||||||
};
|
|
||||||
trace!("Read the value {} from address {}", value, addr);
|
|
||||||
vm.registers[1] = hbvm::value::Value(value);
|
vm.registers[1] = hbvm::value::Value(value);
|
||||||
}
|
},
|
||||||
1 => 'wow: {
|
1 => unsafe {
|
||||||
let size = match msg_vec[1] {
|
let size = msg_vec[1];
|
||||||
0 => 1,
|
let addr =
|
||||||
1 => 2,
|
u16::from_le_bytes(msg_vec[2..4].try_into().unwrap_unchecked());
|
||||||
2 => 4,
|
// info!("Setting address {}", addr);
|
||||||
_ => {
|
|
||||||
error!("Tried to write more than 32 bits");
|
match size {
|
||||||
break 'wow;
|
0 => x86_out(addr, msg_vec[4]),
|
||||||
}
|
1 => x86_out(
|
||||||
};
|
addr,
|
||||||
let addr = unsafe {
|
u16::from_le_bytes(msg_vec[4..6].try_into().unwrap_unchecked()),
|
||||||
u16::from_le_bytes(msg_vec[1..3].try_into().unwrap_unchecked())
|
),
|
||||||
};
|
2 => x86_out(
|
||||||
trace!("Setting address {}", addr);
|
addr,
|
||||||
unsafe {
|
u32::from_le_bytes(msg_vec[4..8].try_into().unwrap_unchecked()),
|
||||||
match size {
|
),
|
||||||
1 => x86_out(addr, msg_vec[3]),
|
_ => panic!("How?"),
|
||||||
2 => x86_out(
|
|
||||||
addr,
|
|
||||||
u16::from_le_bytes(
|
|
||||||
msg_vec[3..5].try_into().unwrap_unchecked(),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
4 => x86_out(
|
|
||||||
addr,
|
|
||||||
u32::from_le_bytes(
|
|
||||||
msg_vec[3..7].try_into().unwrap_unchecked(),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
_ => panic!("How?"),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -159,68 +140,95 @@ pub fn handler(vm: &mut Vm) {
|
||||||
3 => unimplemented!("TODO: implement whatever buffer 3 does for no x86_64"),
|
3 => unimplemented!("TODO: implement whatever buffer 3 does for no x86_64"),
|
||||||
// source of rng
|
// source of rng
|
||||||
4 => {
|
4 => {
|
||||||
// limit to last 32 bits
|
let block = block_read(mem_addr, length);
|
||||||
vm.registers[1] =
|
block.chunks_mut(8.min(length)).for_each(|chunk| {
|
||||||
hbvm::value::Value(crate::arch::hardware_random_u64() & 0xFFFFFFFF);
|
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) {
|
5 => match dt_msg_handler(vm, mem_addr, length) {
|
||||||
Ok(()) => {}
|
Ok(()) => {}
|
||||||
Err(_) => log::error!("Improper dt query"),
|
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 => {
|
buffer_id => {
|
||||||
let mut buffs = IPC_BUFFERS.lock();
|
let mut buffs = IPC_BUFFERS.lock();
|
||||||
match buffs.get_mut(&buffer_id) {
|
match buffs.get_mut(&buffer_id) {
|
||||||
Some(buff) => {
|
Some(buff) => {
|
||||||
let mut msg_vec = Vec::with_capacity(length);
|
let msg_vec = block_read(mem_addr, length);
|
||||||
|
buff.push(msg_vec.to_vec());
|
||||||
for x in 0..(length as isize) {
|
debug!("Sent Message {:?} to Buffer({})", msg_vec, buffer_id);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
log::error!("Access of non-existent buffer {}", buffer_id)
|
log::error!("Access of non-existent buffer {}", buffer_id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
drop(buffs);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
4 => {
|
4 => {
|
||||||
let buffer_id = vm.registers[3].cast::<u64>();
|
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 max_length = vm.registers[5].cast::<u64>();
|
||||||
|
|
||||||
let mut buffs = IPC_BUFFERS.lock();
|
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() {
|
let msg = match buff.pop() {
|
||||||
buff = buffs.get_mut(&buffer_id).unwrap();
|
Ok(msg) => msg,
|
||||||
} else {
|
Err(_) => return,
|
||||||
// info!("AHHH");
|
};
|
||||||
vm.registers[1] = hbvm::value::Value(0);
|
if msg.len() > unsafe { max_length.try_into().unwrap_unchecked() } {
|
||||||
return;
|
|
||||||
}
|
|
||||||
let pop = buff.pop();
|
|
||||||
if pop.is_err() {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let msg = pop.unwrap();
|
|
||||||
if msg.len() > max_length.try_into().unwrap() {
|
|
||||||
info!("{}", max_length);
|
info!("{}", max_length);
|
||||||
error!("Message is too long to map in.");
|
error!("Message is too long to map in.");
|
||||||
} else {
|
} else {
|
||||||
unsafe {
|
unsafe {
|
||||||
let ptr: *mut u64 = &mut map_ptr;
|
let ptr = map_ptr as *mut u8;
|
||||||
for (index, byte) in msg.iter().enumerate() {
|
ptr.copy_from_nonoverlapping(msg.as_ptr(), msg.len());
|
||||||
ptr.offset(index.try_into().unwrap()).write_bytes(*byte, 1);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
debug!("Recieve {:?} from Buffer({})", msg, buffer_id);
|
debug!("Recieve {:?} from Buffer({})", msg, buffer_id);
|
||||||
|
@ -230,14 +238,8 @@ pub fn handler(vm: &mut Vm) {
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
{
|
{
|
||||||
let r2 = vm.registers[2].cast::<u64>();
|
let r2 = vm.registers[2].cast::<u64>();
|
||||||
unsafe fn x86_in(address: u16) -> u32 {
|
let x = hbvm::value::Value(unsafe { x86_in::<u8>(r2 as u16) } as u64);
|
||||||
x86_64::instructions::port::Port::new(address).read()
|
// info!("Read {:?} from Port {:?}", x, r2);
|
||||||
}
|
|
||||||
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);
|
|
||||||
info!("Read {:?} from Port {:?}", x, r2);
|
|
||||||
vm.registers[3] = x
|
vm.registers[3] = x
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -252,15 +254,3 @@ pub enum LogError {
|
||||||
NoMessages,
|
NoMessages,
|
||||||
InvalidLogFormat,
|
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 {
|
use {
|
||||||
crate::holeybytes::{kernel_services::block_read, Vm},
|
crate::holeybytes::{kernel_services::block_read, Vm},
|
||||||
alloc::{
|
alloc::vec::Vec,
|
||||||
string::{String, ToString},
|
|
||||||
vec::Vec,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
pub enum DtError {
|
pub enum DtError {
|
||||||
QueryFailure,
|
QueryFailure,
|
||||||
|
@ -11,14 +8,13 @@ pub enum DtError {
|
||||||
|
|
||||||
pub fn dt_msg_handler(vm: &mut Vm, mem_addr: u64, length: usize) -> Result<(), DtError> {
|
pub fn dt_msg_handler(vm: &mut Vm, mem_addr: u64, length: usize) -> Result<(), DtError> {
|
||||||
let msg_vec = block_read(mem_addr, length);
|
let msg_vec = block_read(mem_addr, length);
|
||||||
let mut bytes: Vec<u8> = Vec::new();
|
let query_string = core::str::from_utf8(
|
||||||
for byte in msg_vec {
|
msg_vec
|
||||||
if *byte == 0 {
|
.split_once(|&byte| byte == 0)
|
||||||
break;
|
.unwrap_or((msg_vec, &[]))
|
||||||
}
|
.0,
|
||||||
bytes.push(*byte)
|
)
|
||||||
}
|
.unwrap();
|
||||||
let query_string = String::from_utf8(bytes).unwrap();
|
|
||||||
log::trace!("Query {}", query_string);
|
log::trace!("Query {}", query_string);
|
||||||
|
|
||||||
let ret = query_parse(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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn query_parse(query_string: String) -> u64 {
|
fn query_parse(query_string: &str) -> u64 {
|
||||||
let qt_parse_step_one = query_string.split("/");
|
let query = query_string.split('/').collect::<Vec<&str>>();
|
||||||
let mut qt_parse_step_two: Vec<String> = Vec::new();
|
|
||||||
for a in qt_parse_step_one {
|
|
||||||
qt_parse_step_two.push(a.to_string());
|
|
||||||
}
|
|
||||||
|
|
||||||
let first_fragment: &str = &qt_parse_step_two[0];
|
let first_fragment: &str = &query[0];
|
||||||
let ret = match first_fragment {
|
let ret = match first_fragment {
|
||||||
"framebuffer" => framebuffer_parse(qt_parse_step_two),
|
"framebuffer" => framebuffer_parse(query),
|
||||||
"cpu" => cpu_parse(qt_parse_step_two),
|
"cpu" => cpu_parse(query),
|
||||||
|
|
||||||
_ => 0,
|
_ => 0,
|
||||||
};
|
};
|
||||||
|
@ -47,8 +39,8 @@ fn query_parse(query_string: String) -> u64 {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cpu_parse(qt_parse_step_two: Vec<String>) -> u64 {
|
fn cpu_parse(qt_parse_step_two: Vec<&str>) -> u64 {
|
||||||
let second_fragment: &str = &qt_parse_step_two[1];
|
let second_fragment: &str = qt_parse_step_two[1];
|
||||||
match second_fragment {
|
match second_fragment {
|
||||||
// "architecture" => {
|
// "architecture" => {
|
||||||
// return 0;
|
// 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;
|
use crate::kmain::FB_REQ;
|
||||||
let fbs = &FB_REQ.get_response().get().unwrap().framebuffers();
|
let fbs = &mut FB_REQ.get_response().get().unwrap().framebuffers();
|
||||||
|
let second_fragment: &str = qt_parse_step_two[1];
|
||||||
let second_fragment: &str = &qt_parse_step_two[1];
|
|
||||||
match second_fragment {
|
match second_fragment {
|
||||||
"fb0" => {
|
"fb0" => {
|
||||||
let fb_front = &fbs[0];
|
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 {
|
let ret = match third_fragment {
|
||||||
"ptr" => {
|
"ptr" => {
|
||||||
let ptr = fb_front.address.as_ptr().unwrap();
|
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> {
|
pub fn log_msg_handler(_vm: &mut Vm, mem_addr: u64, length: usize) -> Result<(), LogError> {
|
||||||
let msg_vec = block_read(mem_addr, length);
|
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 file_name = "None";
|
||||||
let line_number = 0;
|
let line_number = 0;
|
||||||
|
|
||||||
match core::str::from_utf8(&msg_vec[..msg_vec.len()]) {
|
match core::str::from_utf8(&str) {
|
||||||
Ok(strr) => {
|
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(
|
log::logger().log(
|
||||||
&Record::builder()
|
&Record::builder()
|
||||||
.args(format_args!("{}", strr))
|
.args(format_args!("{}", strr))
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use {
|
use {
|
||||||
crate::holeybytes::{kernel_services::block_read, Vm},
|
crate::holeybytes::{kernel_services::block_read, Vm},
|
||||||
alloc::alloc::{alloc_zeroed, dealloc},
|
alloc::alloc::{alloc, dealloc},
|
||||||
core::alloc::Layout,
|
core::alloc::Layout,
|
||||||
log::{debug, info},
|
log::{debug, info},
|
||||||
};
|
};
|
||||||
|
@ -17,13 +17,28 @@ pub enum MemoryQuotaType {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn alloc_page(vm: &mut Vm, _mem_addr: u64, _length: usize) -> Result<(), MemoryServiceError> {
|
fn alloc_page(vm: &mut Vm, _mem_addr: u64, _length: usize) -> Result<(), MemoryServiceError> {
|
||||||
let ptr = unsafe { alloc_zeroed(Layout::new::<[u8; 4096]>()) };
|
let ptr = unsafe { alloc(Layout::from_size_align_unchecked(4096, 8)) };
|
||||||
info!("Block address: {:?}", ptr);
|
info!("Block address: {:?}", ptr);
|
||||||
vm.registers[1] = hbvm::value::Value(ptr as u64);
|
vm.registers[1] = hbvm::value::Value(ptr as u64);
|
||||||
vm.registers[2] = hbvm::value::Value(4096);
|
vm.registers[2] = hbvm::value::Value(4096);
|
||||||
Ok(())
|
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(
|
pub fn memory_msg_handler(
|
||||||
vm: &mut Vm,
|
vm: &mut Vm,
|
||||||
mem_addr: u64,
|
mem_addr: u64,
|
||||||
|
@ -32,40 +47,35 @@ pub fn memory_msg_handler(
|
||||||
let msg_vec = block_read(mem_addr, length);
|
let msg_vec = block_read(mem_addr, length);
|
||||||
let msg_type = msg_vec[0];
|
let msg_type = msg_vec[0];
|
||||||
match msg_type {
|
match msg_type {
|
||||||
0 => {
|
0 => unsafe {
|
||||||
let page_count = msg_vec[1];
|
let page_count = msg_vec[1];
|
||||||
let mptr_raw: [u8; 8] = msg_vec[2..10].try_into().unwrap();
|
|
||||||
let mptr: u64 = u64::from_le_bytes(mptr_raw);
|
|
||||||
|
|
||||||
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 {
|
log::debug!("Allocating {} pages @ {:x}", page_count, ptr as u64);
|
||||||
alloc_zeroed(Layout::from_size_align_unchecked(
|
|
||||||
page_count as usize * 4096,
|
|
||||||
1,
|
|
||||||
))
|
|
||||||
};
|
|
||||||
|
|
||||||
vm.registers[1] = hbvm::value::Value(ptr as u64);
|
vm.registers[1] = hbvm::value::Value(ptr as u64);
|
||||||
log::debug!("Kernel ptr: {:x}", ptr as u64);
|
log::debug!("Kernel ptr: {:x}", ptr as u64);
|
||||||
}
|
},
|
||||||
|
|
||||||
1 => {
|
1 => unsafe {
|
||||||
let page_count = msg_vec[1];
|
let page_count = msg_vec[1];
|
||||||
|
|
||||||
let mptr_raw: [u8; 8] = msg_vec[2..10].try_into().unwrap();
|
let mptr_raw: [u8; 8] = msg_vec[2..10].try_into().unwrap();
|
||||||
let mptr: u64 = u64::from_le_bytes(mptr_raw);
|
let mptr: u64 = u64::from_le_bytes(mptr_raw);
|
||||||
log::debug!("Deallocating {} pages @ {:x}", page_count, mptr);
|
log::debug!("Deallocating {} pages @ {:x}", page_count, mptr);
|
||||||
unsafe {
|
|
||||||
dealloc(
|
dealloc(
|
||||||
mptr as *mut u8,
|
mptr as *mut u8,
|
||||||
Layout::from_size_align_unchecked(page_count as usize * 4096, 1),
|
Layout::from_size_align_unchecked(page_count as usize * 4096, 8),
|
||||||
)
|
)
|
||||||
}
|
},
|
||||||
}
|
|
||||||
2 => {
|
2 => {
|
||||||
use MemoryQuotaType::*;
|
use MemoryQuotaType::*;
|
||||||
let quota_type = match msg_vec[0] {
|
let quota_type = match msg_vec[1] {
|
||||||
0 => NoQuota,
|
0 => NoQuota,
|
||||||
1 => SoftQuota,
|
1 => SoftQuota,
|
||||||
2 => HardQuota,
|
2 => HardQuota,
|
||||||
|
@ -82,10 +92,24 @@ pub fn memory_msg_handler(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
3 => {
|
3 => {
|
||||||
let page_count = msg_vec[0];
|
let page_count = msg_vec[1];
|
||||||
log::debug!(" {} pages", page_count);
|
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);
|
log::debug!("Unknown memory service message type: {}", msg_type);
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,6 @@ pub mod mem_serve;
|
||||||
pub mod service_definition_service;
|
pub mod service_definition_service;
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn block_read<'a>(mem_addr: u64, length: usize) -> &'a [u8] {
|
pub fn block_read<'a>(mem_addr: u64, length: usize) -> &'a mut [u8] {
|
||||||
unsafe { slice::from_raw_parts(mem_addr as *const u8, length) }
|
unsafe { slice::from_raw_parts_mut(mem_addr as *mut _, length) }
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,21 +22,19 @@ pub enum ServiceError {
|
||||||
pub fn sds_msg_handler(vm: &mut Vm, mem_addr: u64, length: usize) -> Result<(), ServiceError> {
|
pub fn sds_msg_handler(vm: &mut Vm, mem_addr: u64, length: usize) -> Result<(), ServiceError> {
|
||||||
let msg_vec = block_read(mem_addr, length);
|
let msg_vec = block_read(mem_addr, length);
|
||||||
let sds_event_type: ServiceEventType = msg_vec[0].into();
|
let sds_event_type: ServiceEventType = msg_vec[0].into();
|
||||||
|
let strptr = u64::from_le_bytes(msg_vec[1..9].try_into().unwrap());
|
||||||
// info!("Length {}", msg_vec.len());
|
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::*;
|
use ServiceEventType::*;
|
||||||
match sds_event_type {
|
match sds_event_type {
|
||||||
CreateService => {
|
CreateService => {
|
||||||
let string =
|
|
||||||
core::str::from_utf8(&msg_vec[1..]).expect("Our bytes should be valid utf8");
|
|
||||||
let ret = sds_create_service(string);
|
let ret = sds_create_service(string);
|
||||||
vm.registers[1] = hbvm::value::Value(ret as u64);
|
vm.registers[1] = hbvm::value::Value(ret as u64);
|
||||||
}
|
}
|
||||||
DeleteService => todo!(),
|
DeleteService => todo!(),
|
||||||
SearchServices => {
|
SearchServices => {
|
||||||
let string =
|
|
||||||
core::str::from_utf8(&msg_vec[1..]).expect("Our bytes should be valid utf8");
|
|
||||||
let ret = sds_search_service(string);
|
let ret = sds_search_service(string);
|
||||||
vm.registers[1] = hbvm::value::Value(ret as u64);
|
vm.registers[1] = hbvm::value::Value(ret as u64);
|
||||||
}
|
}
|
||||||
|
@ -94,8 +92,7 @@ fn sds_create_service(protocol: &'static str) -> u64 {
|
||||||
// let a: protocol::Protocol = protocol.into();
|
// let a: protocol::Protocol = protocol.into();
|
||||||
buff_id
|
buff_id
|
||||||
}
|
}
|
||||||
|
pub fn sds_search_service(protocol: &str) -> u64 {
|
||||||
fn sds_search_service(protocol: &str) -> u64 {
|
|
||||||
let services = SERVICES.lock();
|
let services = SERVICES.lock();
|
||||||
let compare = Protocol::from(protocol);
|
let compare = Protocol::from(protocol);
|
||||||
for (bid, protocol_canidate) in &services.0 {
|
for (bid, protocol_canidate) in &services.0 {
|
||||||
|
|
|
@ -30,30 +30,29 @@ impl Memory {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl hbvm::mem::Memory for Memory {
|
impl hbvm::mem::Memory for Memory {
|
||||||
#[inline]
|
#[inline(always)]
|
||||||
unsafe fn load(
|
unsafe fn load(
|
||||||
&mut self,
|
&mut self,
|
||||||
addr: Address,
|
addr: Address,
|
||||||
target: *mut u8,
|
target: *mut u8,
|
||||||
count: usize,
|
count: usize,
|
||||||
) -> Result<(), hbvm::mem::LoadError> {
|
) -> Result<(), hbvm::mem::LoadError> {
|
||||||
if addr.get() % 4096 == 0 {}
|
core::ptr::copy_nonoverlapping(addr.get() as *const u8, target, count);
|
||||||
core::ptr::copy(addr.get() as *const u8, target, count);
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline(always)]
|
||||||
unsafe fn store(
|
unsafe fn store(
|
||||||
&mut self,
|
&mut self,
|
||||||
addr: Address,
|
addr: Address,
|
||||||
source: *const u8,
|
source: *const u8,
|
||||||
count: usize,
|
count: usize,
|
||||||
) -> Result<(), hbvm::mem::StoreError> {
|
) -> 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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline(always)]
|
||||||
unsafe fn prog_read<T: Copy>(&mut self, addr: Address) -> T {
|
unsafe fn prog_read<T: Copy>(&mut self, addr: Address) -> T {
|
||||||
(addr.get() as *const T).read()
|
(addr.get() as *const T).read()
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
mod ecah;
|
mod ecah;
|
||||||
mod kernel_services;
|
pub mod kernel_services;
|
||||||
mod mem;
|
mod mem;
|
||||||
|
|
||||||
use {
|
use {
|
||||||
alloc::alloc::{alloc_zeroed, dealloc},
|
alloc::alloc::{alloc, dealloc},
|
||||||
core::{
|
core::{
|
||||||
alloc::Layout,
|
alloc::Layout,
|
||||||
future::Future,
|
future::Future,
|
||||||
|
@ -61,28 +61,22 @@ impl<'p> Future for ExecThread {
|
||||||
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||||
match self.vm.run() {
|
match self.vm.run() {
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
error!("HBVM Error\r\nRegister dump: {:?}", self.vm.registers);
|
log::error!("HBVM Error\r\nRegister dump: {:?}", self.vm.registers,);
|
||||||
Poll::Ready(Err(err))
|
return Poll::Ready(Err(err));
|
||||||
}
|
|
||||||
Ok(VmRunOk::End) => Poll::Ready(Ok(())),
|
|
||||||
Ok(VmRunOk::Ecall) => {
|
|
||||||
ecah::handler(&mut self.vm);
|
|
||||||
cx.waker().wake_by_ref();
|
|
||||||
Poll::Pending
|
|
||||||
}
|
|
||||||
Ok(VmRunOk::Timer) => {
|
|
||||||
cx.waker().wake_by_ref();
|
|
||||||
Poll::Pending
|
|
||||||
}
|
}
|
||||||
|
Ok(VmRunOk::End) => return Poll::Ready(Ok(())),
|
||||||
|
Ok(VmRunOk::Ecall) => ecah::handler(&mut self.vm),
|
||||||
|
Ok(VmRunOk::Timer) => (),
|
||||||
Ok(VmRunOk::Breakpoint) => {
|
Ok(VmRunOk::Breakpoint) => {
|
||||||
error!(
|
log::error!(
|
||||||
"HBVM Debug breakpoint\r\nRegister dump: {:?}",
|
"HBVM Debug breakpoint\r\nRegister dump: {:?}",
|
||||||
self.vm.registers
|
self.vm.registers,
|
||||||
);
|
);
|
||||||
cx.waker().wake_by_ref();
|
|
||||||
Poll::Pending
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cx.waker().wake_by_ref();
|
||||||
|
Poll::Pending
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -103,10 +97,10 @@ impl HandlePageFault for PageFaultHandler {
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
const fn stack_layout() -> Layout {
|
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)]
|
#[inline(always)]
|
||||||
fn allocate_stack() -> *mut u8 {
|
fn allocate_stack() -> *mut u8 {
|
||||||
unsafe { alloc_zeroed(stack_layout()) }
|
unsafe { alloc(stack_layout()) }
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,9 +49,7 @@ impl<'a> IpcBuffer<'a> {
|
||||||
pub fn push(&mut self, msg: Message) {
|
pub fn push(&mut self, msg: Message) {
|
||||||
match &self.buffer {
|
match &self.buffer {
|
||||||
BufferTypes::Unbound(buff) => buff.push(msg),
|
BufferTypes::Unbound(buff) => buff.push(msg),
|
||||||
BufferTypes::Bound(buff) => {
|
BufferTypes::Bound(buff) => buff.push(msg).unwrap(),
|
||||||
let _ = buff.push(msg);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
pub fn pop(&mut self) -> Result<Message, IpcError> {
|
pub fn pop(&mut self) -> Result<Message, IpcError> {
|
||||||
|
|
|
@ -1,18 +1,15 @@
|
||||||
use {
|
use {alloc::vec::Vec, hashbrown::HashMap};
|
||||||
alloc::{string::String, vec::Vec},
|
|
||||||
hashbrown::HashMap,
|
|
||||||
};
|
|
||||||
#[derive(Debug, PartialEq, Clone)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub struct Type {}
|
pub struct Type {}
|
||||||
#[derive(Debug, PartialEq, Clone)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub struct Funct {
|
pub struct Funct<'a> {
|
||||||
takes: Vec<String>,
|
takes: Vec<&'a str>,
|
||||||
gives: Vec<String>,
|
gives: Vec<&'a str>,
|
||||||
}
|
}
|
||||||
#[derive(Debug, PartialEq, Clone)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub struct Protocol<'a> {
|
pub struct Protocol<'a> {
|
||||||
types: HashMap<&'a str, Type>,
|
types: HashMap<&'a str, Type>,
|
||||||
fns: HashMap<&'a str, Funct>,
|
fns: HashMap<&'a str, Funct<'a>>,
|
||||||
}
|
}
|
||||||
impl<'a> Protocol<'a> {
|
impl<'a> Protocol<'a> {
|
||||||
pub fn void() -> Self {
|
pub fn void() -> Self {
|
||||||
|
|
|
@ -8,11 +8,14 @@ use {
|
||||||
device_tree::DeviceTree,
|
device_tree::DeviceTree,
|
||||||
holeybytes::ExecThread,
|
holeybytes::ExecThread,
|
||||||
ipc::buffer::IpcBuffer,
|
ipc::buffer::IpcBuffer,
|
||||||
|
task::Executor,
|
||||||
},
|
},
|
||||||
|
alloc::boxed::Box,
|
||||||
|
core::cell::LazyCell,
|
||||||
hashbrown::HashMap,
|
hashbrown::HashMap,
|
||||||
hbvm::mem::Address,
|
hbvm::mem::Address,
|
||||||
limine::{Framebuffer, FramebufferRequest, NonNullPtr},
|
limine::{Framebuffer, FramebufferRequest, NonNullPtr},
|
||||||
log::{debug, info},
|
log::{debug, error, trace},
|
||||||
spin::{Lazy, Mutex},
|
spin::{Lazy, Mutex},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -36,9 +39,9 @@ pub fn kmain(_cmdline: &str, boot_modules: BootModules) -> ! {
|
||||||
let dt = DEVICE_TREE.lock();
|
let dt = DEVICE_TREE.lock();
|
||||||
|
|
||||||
// TODO(Able): This line causes a deadlock
|
// TODO(Able): This line causes a deadlock
|
||||||
info!("Device Tree: {}", dt);
|
debug!("Device Tree: {}", dt);
|
||||||
|
|
||||||
info!("Boot complete. Moving to init_system");
|
trace!("Boot complete. Moving to init_system");
|
||||||
|
|
||||||
// TODO: schedule the disk driver from the initramfs
|
// TODO: schedule the disk driver from the initramfs
|
||||||
// TODO: schedule the filesystem driver from the initramfs
|
// TODO: schedule the filesystem driver from the initramfs
|
||||||
|
@ -50,49 +53,73 @@ pub fn kmain(_cmdline: &str, boot_modules: BootModules) -> ! {
|
||||||
let fb1: &NonNullPtr<Framebuffer> = &FB_REQ.get_response().get().unwrap().framebuffers()[0];
|
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 dt = DEVICE_TREE.lock();
|
||||||
let mut disp = xml::XMLElement::new("display_0");
|
let mut disp = xml::XMLElement::new("display_0");
|
||||||
|
|
||||||
disp.set_attribute("width", fb1.width);
|
disp.set_attribute("width", fb1.width);
|
||||||
disp.set_attribute("height", fb1.height);
|
disp.set_attribute("height", fb1.height);
|
||||||
disp.set_attribute("bits per pixel", fb1.bpp);
|
disp.set_attribute("bpp", fb1.bpp);
|
||||||
disp.set_attribute("pitch", fb1.pitch);
|
disp.set_attribute("pitch", fb1.pitch);
|
||||||
dt.devices.insert("Displays".to_string(), alloc::vec![disp]);
|
dt.devices.insert("Displays", alloc::vec![disp]);
|
||||||
}
|
}
|
||||||
log::info!("Graphics initialised");
|
debug!("Graphics initialised");
|
||||||
log::info!(
|
debug!(
|
||||||
"Graphics front ptr {:?}",
|
"Graphics front ptr {:?}",
|
||||||
fb1.address.as_ptr().unwrap() as *const u8
|
fb1.address.as_ptr().unwrap() as *const u8
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut executor = crate::task::Executor::new(256);
|
|
||||||
let bm_take = boot_modules.len();
|
|
||||||
unsafe {
|
unsafe {
|
||||||
for module in boot_modules.into_iter().take(bm_take) {
|
let executor = LazyCell::<Executor>::force_mut(&mut EXECUTOR);
|
||||||
let mut cmd = module.cmd;
|
for module in boot_modules.iter() {
|
||||||
if cmd.len() > 2 {
|
let cmd = module.cmd.trim_matches('"');
|
||||||
// // Remove the quotes
|
|
||||||
// cmd.remove(0);
|
|
||||||
// cmd.pop();
|
|
||||||
cmd = &cmd[1..cmd.len()]
|
|
||||||
}
|
|
||||||
let cmd_len = cmd.len() as u64;
|
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);
|
||||||
|
|
||||||
executor.spawn(async move {
|
// decode AbleOS Executable format
|
||||||
let mut thr = ExecThread::new(&module.bytes, Address::new(0));
|
let header = &module.bytes[0..46];
|
||||||
if cmd_len > 0 {
|
let magic_slice = &header[0..3];
|
||||||
thr.set_arguments(cmd.as_bytes().as_ptr() as u64, cmd_len);
|
if magic_slice != [0x15, 0x91, 0xD2] {
|
||||||
}
|
log::error!("Invalid magic number at the start of executable.");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
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.");
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
|
||||||
|
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 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(Box::pin(async move {
|
||||||
if let Err(e) = thr.await {
|
if let Err(e) = thr.await {
|
||||||
log::error!("{e:?}");
|
log::error!("{e:?}");
|
||||||
}
|
}
|
||||||
})
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
info!("Random number: {}", hardware_random_u64());
|
debug!("Random number: {}", hardware_random_u64());
|
||||||
|
|
||||||
executor.run();
|
executor.run();
|
||||||
};
|
};
|
||||||
|
@ -100,6 +127,10 @@ pub fn kmain(_cmdline: &str, boot_modules: BootModules) -> ! {
|
||||||
crate::arch::spin_loop()
|
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(|| {
|
pub static DEVICE_TREE: Lazy<Mutex<DeviceTree>> = Lazy::new(|| {
|
||||||
let dt = DeviceTree::new();
|
let dt = DeviceTree::new();
|
||||||
Mutex::new(dt)
|
Mutex::new(dt)
|
||||||
|
|
|
@ -2,9 +2,12 @@
|
||||||
//! Named akern.
|
//! Named akern.
|
||||||
//! Akern is woefully undersupported at the moment but we are looking to add support improve hardware discovery and make our lives as kernel and operating system developers easier and better
|
//! Akern is woefully undersupported at the moment but we are looking to add support improve hardware discovery and make our lives as kernel and operating system developers easier and better
|
||||||
#![no_std]
|
#![no_std]
|
||||||
#![feature(new_uninit)]
|
|
||||||
#![feature(
|
#![feature(
|
||||||
|
slice_split_once,
|
||||||
|
exclusive_wrapper,
|
||||||
|
core_intrinsics,
|
||||||
abi_x86_interrupt,
|
abi_x86_interrupt,
|
||||||
|
lazy_get,
|
||||||
alloc_error_handler,
|
alloc_error_handler,
|
||||||
ptr_sub_ptr,
|
ptr_sub_ptr,
|
||||||
custom_test_frameworks,
|
custom_test_frameworks,
|
||||||
|
@ -12,8 +15,7 @@
|
||||||
pointer_is_aligned_to
|
pointer_is_aligned_to
|
||||||
)]
|
)]
|
||||||
#![test_runner(crate::test_runner)]
|
#![test_runner(crate::test_runner)]
|
||||||
#![cfg_attr(not(debug_assertions), allow(unused, deprecated))]
|
#![allow(dead_code, internal_features, static_mut_refs)]
|
||||||
#![allow(dead_code)]
|
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
|
|
||||||
mod allocator;
|
mod allocator;
|
||||||
|
@ -21,6 +23,7 @@ mod arch;
|
||||||
mod bootmodules;
|
mod bootmodules;
|
||||||
mod capabilities;
|
mod capabilities;
|
||||||
mod device_tree;
|
mod device_tree;
|
||||||
|
mod exe_format;
|
||||||
mod handle;
|
mod handle;
|
||||||
mod holeybytes;
|
mod holeybytes;
|
||||||
mod ipc;
|
mod ipc;
|
||||||
|
|
|
@ -36,13 +36,26 @@ impl log::Log for Logger {
|
||||||
Level::Debug => "25",
|
Level::Debug => "25",
|
||||||
Level::Trace => "103",
|
Level::Trace => "103",
|
||||||
};
|
};
|
||||||
let module = record.module_path().unwrap_or_default();
|
let module = record
|
||||||
let line = record.line().unwrap_or_default();
|
.module_path()
|
||||||
crate::arch::log(format_args!(
|
.unwrap_or_default()
|
||||||
"\x1b[38;5;{lvl_color}m{lvl}\x1b[0m [{module}:{line}]: {}\r\n",
|
.rsplit_once(':')
|
||||||
record.args(),
|
.unwrap_or_default()
|
||||||
))
|
.1;
|
||||||
.expect("write to serial console");
|
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) {}
|
fn flush(&self) {}
|
||||||
|
|
|
@ -29,24 +29,24 @@ pub fn yield_now() -> impl Future<Output = ()> {
|
||||||
YieldNow(false)
|
YieldNow(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Executor<F: Future<Output = ()> + Send> {
|
pub struct Executor {
|
||||||
tasks: Slab<Task<F>>,
|
tasks: Slab<Task>,
|
||||||
task_queue: Arc<TaskQueue>,
|
task_queue: Arc<TaskQueue>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F: Future<Output = ()> + Send> Executor<F> {
|
impl Executor {
|
||||||
pub fn new(size: usize) -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
tasks: Slab::with_capacity(size),
|
tasks: Slab::new(),
|
||||||
task_queue: Arc::new(TaskQueue::new()),
|
task_queue: Arc::new(TaskQueue::new()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn spawn(&mut self, future: F) {
|
pub fn spawn(&mut self, future: Pin<Box<dyn Future<Output = ()> + Send>>) -> usize {
|
||||||
self.task_queue
|
let id = self.tasks.insert(Task::new(future));
|
||||||
.queue
|
self.task_queue.queue.push(id);
|
||||||
.push(self.tasks.insert(Task::new(future)));
|
id
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run(&mut self) {
|
pub fn run(&mut self) {
|
||||||
|
@ -83,17 +83,17 @@ impl<F: Future<Output = ()> + Send> Executor<F> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Task<F: Future<Output = ()> + Send> {
|
struct Task {
|
||||||
future: Pin<Box<F>>,
|
future: Pin<Box<dyn Future<Output = ()> + Send>>,
|
||||||
waker: Option<TaskWaker>,
|
waker: Option<TaskWaker>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F: Future<Output = ()> + Send> Task<F> {
|
impl Task {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn new(future: F) -> Self {
|
pub fn new(future: Pin<Box<dyn Future<Output = ()> + Send>>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
future: Box::pin(future),
|
future,
|
||||||
waker: None,
|
waker: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
/// Used when tab `\t` in hardware is not known and we will default to two spaces
|
/// Used when tab `\t` in hardware is not known and we will default to two spaces
|
||||||
pub const TAB: &str = " ";
|
pub const TAB: &str = " ";
|
||||||
|
|
||||||
|
|
||||||
// NOTE: this only reduces the code duplication in source code not in generated code!
|
// NOTE: this only reduces the code duplication in source code not in generated code!
|
||||||
// Written by Yours Truly: Munir
|
// Written by Yours Truly: Munir
|
||||||
/// A simple macro to reduce code duplication when we use TAB internally
|
/// A simple macro to reduce code duplication when we use TAB internally
|
||||||
|
@ -12,7 +11,7 @@ pub const TAB: &str = " ";
|
||||||
macro_rules! tab {
|
macro_rules! tab {
|
||||||
($num:expr) => {
|
($num:expr) => {
|
||||||
TAB.repeat($num)
|
TAB.repeat($num)
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: this only reduces the code duplication in source code not in generated code!
|
// 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 {
|
macro_rules! device_tree {
|
||||||
($devtree:expr, $dev_type_vec:expr) => {
|
($devtree:expr, $dev_type_vec:expr) => {
|
||||||
for each_device_type in $dev_type_vec {
|
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",
|
"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,
|
"disable-redzone": true,
|
||||||
"env": "",
|
"env": "",
|
||||||
"executables": true,
|
"executables": true,
|
||||||
|
|
|
@ -1,22 +1,22 @@
|
||||||
{
|
{
|
||||||
"llvm-target": "x86_64-unknown-none",
|
"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",
|
"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",
|
"arch": "x86_64",
|
||||||
"target-endian": "little",
|
"target-endian": "little",
|
||||||
"target-pointer-width": "64",
|
"target-pointer-width": "64",
|
||||||
"target-c-int-width": "32",
|
"target-c-int-width": "32",
|
||||||
"os": "none",
|
"os": "none",
|
||||||
"executables": true,
|
"executables": true,
|
||||||
"linker-flavor": "ld.lld",
|
"linker-flavor": "ld.lld",
|
||||||
"linker": "rust-lld",
|
"linker": "rust-lld",
|
||||||
"panic-strategy": "abort",
|
"panic-strategy": "abort",
|
||||||
"disable-redzone": true,
|
"disable-redzone": true,
|
||||||
"features": "",
|
"features": "",
|
||||||
"code-model": "kernel",
|
"code-model": "kernel",
|
||||||
"pre-link-args": {
|
"pre-link-args": {
|
||||||
"ld.lld": [
|
"ld.lld": [
|
||||||
"--gc-sections",
|
"--gc-sections",
|
||||||
"--script=kernel/lds/x86_64.ld"
|
"--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]
|
[dependencies]
|
||||||
str-reader = "0.1"
|
str-reader = "0.1"
|
||||||
derive_more = { version = "1", default-features = false, features = [
|
derive_more = { version = "1", default-features = false, features = [
|
||||||
"add",
|
"display",
|
||||||
"add_assign",
|
|
||||||
"constructor",
|
|
||||||
"display",
|
|
||||||
"from",
|
|
||||||
"into",
|
|
||||||
"mul",
|
|
||||||
"mul_assign",
|
|
||||||
"not",
|
|
||||||
"sum",
|
|
||||||
] }
|
] }
|
||||||
error-stack = "0.5"
|
error-stack = "0.5"
|
||||||
fatfs = "0.3"
|
fatfs = { version = "0.3", default-features = false, features = [
|
||||||
|
"std",
|
||||||
|
"alloc",
|
||||||
|
] }
|
||||||
toml = "0.8"
|
toml = "0.8"
|
||||||
# hbasm.git = "https://git.ablecorp.us/AbleOS/holey-bytes.git"
|
|
||||||
hblang.git = "https://git.ablecorp.us/AbleOS/holey-bytes.git"
|
hblang.git = "https://git.ablecorp.us/AbleOS/holey-bytes.git"
|
||||||
|
log = "0.4"
|
||||||
[dependencies.reqwest]
|
raw-cpuid = "11"
|
||||||
version = "0.12"
|
ureq = { version = "2", default-features = false, features = ["tls"] }
|
||||||
default-features = false
|
|
||||||
features = ["rustls-tls", "blocking"]
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#![allow(unused)]
|
#![allow(unused)]
|
||||||
use std::{
|
use std::{
|
||||||
|
collections::HashMap,
|
||||||
fmt::format,
|
fmt::format,
|
||||||
fs::{read_to_string, File},
|
fs::{read_to_string, File},
|
||||||
io::{BufWriter, Write},
|
io::{BufWriter, Write},
|
||||||
|
@ -13,6 +14,7 @@ pub struct Package {
|
||||||
name: String,
|
name: String,
|
||||||
binaries: Vec<String>,
|
binaries: Vec<String>,
|
||||||
build_cmd: String,
|
build_cmd: String,
|
||||||
|
args: HashMap<String, String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Package {
|
impl Package {
|
||||||
|
@ -46,57 +48,79 @@ impl Package {
|
||||||
let mut binaries = vec![];
|
let mut binaries = vec![];
|
||||||
|
|
||||||
for (count, (name, table)) in bin_table.into_iter().enumerate() {
|
for (count, (name, table)) in bin_table.into_iter().enumerate() {
|
||||||
// if count != 0 {
|
|
||||||
println!("{}", name);
|
|
||||||
binaries.push(name.clone());
|
binaries.push(name.clone());
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
let build_table = data.get("build").unwrap();
|
let build_table = data.get("build").unwrap();
|
||||||
|
|
||||||
let mut build_cmd: String = build_table.get("command").unwrap().as_str().unwrap().into();
|
let mut build_cmd: String = build_table.get("command").unwrap().as_str().unwrap().into();
|
||||||
build_cmd.remove(0);
|
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 {
|
Self {
|
||||||
name,
|
name,
|
||||||
binaries,
|
binaries,
|
||||||
build_cmd,
|
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()) {
|
if self.binaries.contains(&"hblang".to_string()) {
|
||||||
let file = self.build_cmd.split_ascii_whitespace().last().unwrap();
|
let file = self.build_cmd.split_ascii_whitespace().last().unwrap();
|
||||||
|
|
||||||
let path = format!("sysdata/programs/{}/{}", self.name, file);
|
let path = format!("sysdata/programs/{}/{}", self.name, file);
|
||||||
let mut bytes = Vec::new();
|
|
||||||
// compile here
|
// compile here
|
||||||
|
|
||||||
let _ = hblang::run_compiler(
|
let mut warnings = String::new();
|
||||||
|
|
||||||
|
hblang::run_compiler(
|
||||||
&path,
|
&path,
|
||||||
Options {
|
Options {
|
||||||
fmt: true,
|
fmt: true,
|
||||||
|
in_house_regalloc: true,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
&mut bytes,
|
out,
|
||||||
);
|
&mut warnings,
|
||||||
let _ = hblang::run_compiler(&path, Default::default(), &mut bytes);
|
)?;
|
||||||
|
|
||||||
match std::fs::create_dir("target/programs") {
|
match std::fs::create_dir("target/programs") {
|
||||||
Ok(_) => (),
|
Ok(_) => (),
|
||||||
Err(e) if e.kind() == std::io::ErrorKind::AlreadyExists => (),
|
Err(e) if e.kind() == std::io::ErrorKind::AlreadyExists => (),
|
||||||
Err(e) => panic!("{}", e),
|
Err(e) => panic!("{}", e),
|
||||||
}
|
}
|
||||||
std::fs::write(format!("target/programs/{}.hbf", self.name), &bytes).unwrap();
|
|
||||||
bytes.clear();
|
hblang::run_compiler(
|
||||||
let _ = 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,
|
&path,
|
||||||
Options {
|
Options {
|
||||||
dump_asm: true,
|
dump_asm: true,
|
||||||
|
in_house_regalloc: true,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
&mut bytes,
|
out,
|
||||||
);
|
&mut warnings,
|
||||||
std::fs::write(format!("target/programs/{}.hba", self.name), &bytes).unwrap();
|
)?;
|
||||||
|
std::fs::write(format!("target/programs/{}.hba", self.name), &out)?;
|
||||||
|
out.clear();
|
||||||
}
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,18 +1,16 @@
|
||||||
// #![allow(unused)]
|
|
||||||
|
|
||||||
mod dev;
|
mod dev;
|
||||||
|
|
||||||
use {
|
use {
|
||||||
|
core::fmt::Write as _,
|
||||||
derive_more::Display,
|
derive_more::Display,
|
||||||
dev::Package,
|
dev::Package,
|
||||||
error_stack::{bail, report, Context, Report, Result, ResultExt},
|
error_stack::{bail, report, Context, Report, Result, ResultExt},
|
||||||
fatfs::{FileSystem, FormatVolumeOptions, FsOptions, ReadWriteSeek},
|
fatfs::{FileSystem, FormatVolumeOptions, FsOptions, ReadWriteSeek},
|
||||||
std::{
|
std::{
|
||||||
// fmt::Display,
|
|
||||||
fs::{self, File},
|
fs::{self, File},
|
||||||
io::{self, Write},
|
io::{self, Write},
|
||||||
path::Path,
|
path::Path,
|
||||||
process::{exit, Command},
|
process::{exit, Command, Stdio},
|
||||||
},
|
},
|
||||||
toml::Value,
|
toml::Value,
|
||||||
};
|
};
|
||||||
|
@ -21,6 +19,9 @@ fn main() -> Result<(), Error> {
|
||||||
let mut args = std::env::args();
|
let mut args = std::env::args();
|
||||||
args.next();
|
args.next();
|
||||||
|
|
||||||
|
log::set_logger(&hblang::Logger).unwrap();
|
||||||
|
log::set_max_level(log::LevelFilter::Error);
|
||||||
|
|
||||||
match args.next().as_deref() {
|
match args.next().as_deref() {
|
||||||
Some("build" | "b") => {
|
Some("build" | "b") => {
|
||||||
let mut release = false;
|
let mut release = false;
|
||||||
|
@ -35,6 +36,8 @@ fn main() -> Result<(), Error> {
|
||||||
target = Target::Riscv64Virt;
|
target = Target::Riscv64Virt;
|
||||||
} else if arg == "arm64" || arg == "aarch64" || arg == "aarch64-virt" {
|
} else if arg == "arm64" || arg == "aarch64" || arg == "aarch64-virt" {
|
||||||
target = Target::Aarch64;
|
target = Target::Aarch64;
|
||||||
|
} else if arg == "avx2" {
|
||||||
|
target = Target::X86_64Avx2;
|
||||||
} else {
|
} else {
|
||||||
return Err(report!(Error::InvalidSubCom));
|
return Err(report!(Error::InvalidSubCom));
|
||||||
}
|
}
|
||||||
|
@ -46,6 +49,7 @@ fn main() -> Result<(), Error> {
|
||||||
let mut release = false;
|
let mut release = false;
|
||||||
let mut debuginfo = false;
|
let mut debuginfo = false;
|
||||||
let mut target = Target::X86_64;
|
let mut target = Target::X86_64;
|
||||||
|
let mut do_accel = true;
|
||||||
for arg in args {
|
for arg in args {
|
||||||
if arg == "-r" || arg == "--release" {
|
if arg == "-r" || arg == "--release" {
|
||||||
release = true;
|
release = true;
|
||||||
|
@ -55,13 +59,17 @@ fn main() -> Result<(), Error> {
|
||||||
target = Target::Riscv64Virt;
|
target = Target::Riscv64Virt;
|
||||||
} else if arg == "arm64" || arg == "aarch64" || arg == "aarch64-virt" {
|
} else if arg == "arm64" || arg == "aarch64" || arg == "aarch64-virt" {
|
||||||
target = Target::Aarch64;
|
target = Target::Aarch64;
|
||||||
|
} else if arg == "--noaccel" {
|
||||||
|
do_accel = false;
|
||||||
|
} else if arg == "avx2" {
|
||||||
|
target = Target::X86_64Avx2;
|
||||||
} else {
|
} else {
|
||||||
return Err(report!(Error::InvalidSubCom));
|
return Err(report!(Error::InvalidSubCom));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
build(release, target, debuginfo)?;
|
build(release, target, debuginfo)?;
|
||||||
run(release, target)
|
run(release, target, do_accel)
|
||||||
}
|
}
|
||||||
Some("help" | "h") => {
|
Some("help" | "h") => {
|
||||||
println!(concat!(
|
println!(concat!(
|
||||||
|
@ -71,8 +79,10 @@ fn main() -> Result<(), Error> {
|
||||||
" help (h): Print this message\n",
|
" help (h): Print this message\n",
|
||||||
" run (r): Build and run AbleOS in QEMU\n\n",
|
" run (r): Build and run AbleOS in QEMU\n\n",
|
||||||
"Options for build and run:\n",
|
"Options for build and run:\n",
|
||||||
" -r: build in release mode",
|
" -r / --release: build in release mode\n",
|
||||||
" [target]: sets target"
|
" -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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -195,21 +205,43 @@ TERM_BACKDROP={}
|
||||||
let modules = value.get_mut("modules").unwrap().as_table_mut().unwrap();
|
let modules = value.get_mut("modules").unwrap().as_table_mut().unwrap();
|
||||||
// let mut real_modules = modules.clone();
|
// let mut real_modules = modules.clone();
|
||||||
|
|
||||||
modules.into_iter().for_each(|(_, value)| {
|
let mut errors = String::new();
|
||||||
if value.is_table() {
|
let mut out = Vec::new();
|
||||||
let path = get_path_without_boot_prefix(
|
|
||||||
value.get("path").expect("You must have `path` as a value"),
|
modules
|
||||||
)
|
.into_iter()
|
||||||
.unwrap()
|
.map(|(_, value)| -> Result<(), io::Error> {
|
||||||
.split(".")
|
if value.is_table() {
|
||||||
.next()
|
let path = get_path_without_boot_prefix(
|
||||||
.unwrap();
|
value.get("path").expect("You must have `path` as a value"),
|
||||||
let p = Package::load_from_file(
|
)
|
||||||
format!("sysdata/programs/{}/meta.toml", path).to_owned(),
|
.unwrap()
|
||||||
);
|
.split(".")
|
||||||
p.build();
|
.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)| {
|
modules.into_iter().for_each(|(_key, value)| {
|
||||||
if value.is_table() {
|
if value.is_table() {
|
||||||
let path = value.get("path").expect("You must have `path` as a value");
|
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 {
|
if target == Target::Aarch64 {
|
||||||
com.args(["--target", "targets/aarch64-virt-ableos.json"]);
|
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() {
|
match com.status() {
|
||||||
Ok(s) if s.code() != Some(0) => bail!(Error::Build),
|
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");
|
path.push_str("_x86-64");
|
||||||
"target/x86_64-ableos"
|
"target/x86_64-ableos"
|
||||||
}
|
}
|
||||||
|
Target::X86_64Avx2 => {
|
||||||
|
path.push_str("_x86-64");
|
||||||
|
"target/x86_64_v3-ableos"
|
||||||
|
}
|
||||||
Target::Riscv64Virt => "target/riscv64-virt-ableos",
|
Target::Riscv64Virt => "target/riscv64-virt-ableos",
|
||||||
Target::Aarch64 => {
|
Target::Aarch64 => {
|
||||||
path.push_str("_aarch64");
|
path.push_str("_aarch64");
|
||||||
|
@ -331,25 +370,68 @@ fn build(release: bool, target: Target, debuginfo: bool) -> Result<(), Error> {
|
||||||
.change_context(Error::Io)
|
.change_context(Error::Io)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(release: bool, target: Target) -> Result<(), Error> {
|
fn run(release: bool, target: Target, do_accel: bool) -> Result<(), Error> {
|
||||||
let mut com = match target {
|
let target_str = match target {
|
||||||
Target::X86_64 => Command::new("qemu-system-x86_64"),
|
Target::X86_64 | Target::X86_64Avx2 => "qemu-system-x86_64",
|
||||||
Target::Riscv64Virt => Command::new("qemu-system-riscv64"),
|
Target::Riscv64Virt => "qemu-system-riscv64",
|
||||||
Target::Aarch64 => Command::new("qemu-system-aarch64"),
|
Target::Aarch64 => "qemu-system-aarch64",
|
||||||
};
|
};
|
||||||
|
let (mut com, mut com2) = (Command::new(target_str), Command::new(target_str));
|
||||||
let ovmf_path = fetch_ovmf(target);
|
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 {
|
match target {
|
||||||
Target::X86_64 => {
|
Target::X86_64 | Target::X86_64Avx2 => {
|
||||||
#[rustfmt::skip]
|
#[rustfmt::skip]
|
||||||
com.args([
|
com.args([
|
||||||
"-bios", &ovmf_path.change_context(Error::OvmfFetch)?,
|
"-bios", &ovmf_path.change_context(Error::OvmfFetch)?,
|
||||||
"-drive", "file=target/disk.img,format=raw",
|
"-drive", "file=target/disk.img,format=raw",
|
||||||
"-m", "4G",
|
"-device", "vmware-svga",
|
||||||
"-smp", "cores=4",
|
// "-serial", "stdio",
|
||||||
"-enable-kvm",
|
"-m", "2G",
|
||||||
"-cpu", "host",
|
"-smp", "1",
|
||||||
"-device", "isa-debug-exit,iobase=0xf4,iosize=0x04"
|
"-parallel", "none",
|
||||||
|
"-monitor", "none",
|
||||||
|
"-machine", accel,
|
||||||
|
"-cpu", "max",
|
||||||
|
"-device", "isa-debug-exit,iobase=0xf4,iosize=0x04",
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
Target::Riscv64Virt => {
|
Target::Riscv64Virt => {
|
||||||
|
@ -393,7 +475,7 @@ fn run(release: bool, target: Target) -> Result<(), Error> {
|
||||||
|
|
||||||
fn fetch_ovmf(target: Target) -> Result<String, OvmfFetchError> {
|
fn fetch_ovmf(target: Target) -> Result<String, OvmfFetchError> {
|
||||||
let (ovmf_url, ovmf_path) = match target {
|
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",
|
"https://retrage.github.io/edk2-nightly/bin/RELEASEX64_OVMF.fd",
|
||||||
"target/RELEASEX64_OVMF.fd",
|
"target/RELEASEX64_OVMF.fd",
|
||||||
),
|
),
|
||||||
|
@ -415,12 +497,12 @@ fn fetch_ovmf(target: Target) -> Result<String, OvmfFetchError> {
|
||||||
Ok(_) => return Ok(ovmf_path.to_owned()),
|
Ok(_) => return Ok(ovmf_path.to_owned()),
|
||||||
Err(e) => return Err(report!(e).change_context(OvmfFetchError::Io)),
|
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)
|
.map_err(Report::from)
|
||||||
.change_context(OvmfFetchError::Fetch)?;
|
.change_context(OvmfFetchError::Fetch)?;
|
||||||
|
|
||||||
bytes
|
std::io::copy(&mut req.into_reader(), &mut file)
|
||||||
.copy_to(&mut file)
|
|
||||||
.map_err(Report::from)
|
.map_err(Report::from)
|
||||||
.change_context(OvmfFetchError::Io)?;
|
.change_context(OvmfFetchError::Io)?;
|
||||||
|
|
||||||
|
@ -442,6 +524,7 @@ impl Context for OvmfFetchError {}
|
||||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||||
enum Target {
|
enum Target {
|
||||||
X86_64,
|
X86_64,
|
||||||
|
X86_64Avx2,
|
||||||
Riscv64Virt,
|
Riscv64Virt,
|
||||||
Aarch64,
|
Aarch64,
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
[toolchain]
|
[toolchain]
|
||||||
channel = "nightly-2024-07-27"
|
# old toolchain
|
||||||
|
# channel = "nightly-2024-07-27"
|
||||||
|
channel = "nightly"
|
||||||
components = ["rust-src", "llvm-tools"]
|
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("rel:../../stn/src/lib.hb");
|
|
||||||
.{string, memory, buffer} := stn
|
|
||||||
|
|
||||||
dt_get := fn(query: ^u8): int {
|
|
||||||
message_length := string.length(query)
|
|
||||||
|
|
||||||
return @eca(int, 3, 5, query, message_length)
|
|
||||||
}
|
|
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,24 +1,49 @@
|
||||||
stn := @use("rel:../../stn/src/lib.hb");
|
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 {
|
WindowID := struct {
|
||||||
host_id: int,
|
host_id: int,
|
||||||
window_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
|
// get the horizon buffer
|
||||||
// request a new window and provide the callback buffer
|
// request a new window and provide the callback buffer
|
||||||
// wait to recieve a message
|
// wait to recieve a message
|
||||||
|
|
||||||
windowing_system_buffer := buffer.search("XHorizon\0")
|
windowing_system_buffer := buffer.search("XHorizon\0")
|
||||||
|
mem_buf := memory.request_page(1)
|
||||||
|
|
||||||
if windowing_system_buffer == 0 {
|
if windowing_system_buffer == 0 {
|
||||||
|
return @as(^render.Surface, idk)
|
||||||
} else {
|
} else {
|
||||||
msg := "\{01}\0"
|
// ! bad able, stop using string messages :ragey:
|
||||||
msg_length := 2
|
// msg := "\{01}\0"
|
||||||
@eca(void, 3, windowing_system_buffer, msg, msg_length)
|
// msg_length := 2
|
||||||
}
|
|
||||||
|
|
||||||
return
|
// @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,
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
structures := @use("rel:structures.hb")
|
structures := @use("structures.hb")
|
||||||
version := @use("rel:version.hb")
|
version := @use("version.hb")
|
||||||
|
|
||||||
// Refer to here https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkApplicationInfo.html
|
// Refer to here https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkApplicationInfo.html
|
||||||
ApplicationInfo := struct {
|
ApplicationInfo := struct {
|
||||||
|
@ -7,7 +7,7 @@ ApplicationInfo := struct {
|
||||||
pNext: ^int,
|
pNext: ^int,
|
||||||
application_name: ^u8,
|
application_name: ^u8,
|
||||||
application_version: int,
|
application_version: int,
|
||||||
engine_name: int,
|
engine_name: ^u8,
|
||||||
engine_version: int,
|
engine_version: int,
|
||||||
api_version: int,
|
api_version: int,
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
application := @use("rel:application.hb");
|
application := @use("application.hb");
|
||||||
.{ApplicationInfo} := application
|
.{ApplicationInfo} := application
|
||||||
|
|
||||||
structures := @use("rel:structures.hb")
|
structures := @use("structures.hb")
|
||||||
errors := @use("rel:errors.hb")
|
errors := @use("errors.hb")
|
||||||
|
|
||||||
// https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkInstanceCreateInfo.html
|
// https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkInstanceCreateInfo.html
|
||||||
InstanceCreateInfo := struct {
|
InstanceCreateInfo := struct {
|
||||||
|
|
|
@ -1,16 +1,16 @@
|
||||||
application := @use("rel:application.hb")
|
application := @use("application.hb")
|
||||||
|
|
||||||
results := @use("rel:results.hb")
|
results := @use("results.hb")
|
||||||
errors := @use("rel:errors.hb")
|
errors := @use("errors.hb")
|
||||||
|
|
||||||
offsets := @use("rel:offset.hb")
|
offsets := @use("offset.hb")
|
||||||
extends := @use("rel:extends.hb")
|
extends := @use("extends.hb")
|
||||||
|
|
||||||
rect := @use("rel:rect.hb")
|
rect := @use("rect.hb")
|
||||||
structures := @use("rel:structures.hb")
|
structures := @use("structures.hb")
|
||||||
instance := @use("rel:instance.hb")
|
instance := @use("instance.hb")
|
||||||
|
|
||||||
version := @use("rel:version.hb")
|
version := @use("version.hb")
|
||||||
|
|
||||||
init_vulkan := fn(): int {
|
init_vulkan := fn(): int {
|
||||||
return errors.IncompatibleDriver
|
return errors.IncompatibleDriver
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
offsets := @use("rel:offset.hb")
|
offsets := @use("offset.hb")
|
||||||
extends := @use("rel:extends.hb")
|
extends := @use("extends.hb")
|
||||||
|
|
||||||
Rect2D := struct {
|
Rect2D := struct {
|
||||||
offset: offsets.Offset2D,
|
offset: offsets.Offset2D,
|
||||||
|
|
20
sysdata/libraries/intouch/README.md
Normal file
20
sysdata/libraries/intouch/README.md
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
# intouch
|
||||||
|
This library is exclusively focused on allowing your to get input regardless of which devices you have.
|
||||||
|
|
||||||
|
Partially modeled after SDL.
|
||||||
|
|
||||||
|
Current goals include
|
||||||
|
- Interfaces
|
||||||
|
- PS/2
|
||||||
|
- Device Types
|
||||||
|
- Keyboard
|
||||||
|
- Mouse
|
||||||
|
|
||||||
|
Longer Term goals
|
||||||
|
- Interfaces
|
||||||
|
- USB
|
||||||
|
- USB-HID
|
||||||
|
- Device Types
|
||||||
|
- Gamepads/controllers
|
||||||
|
- Drawing Tablets
|
||||||
|
- Microphones
|
2
sysdata/libraries/intouch/key_maps/ps2.map
Normal file
2
sysdata/libraries/intouch/key_maps/ps2.map
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
0x0D -> press Tab
|
||||||
|
0xF0 0x0D -> release Tab
|
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 {}
|
121
sysdata/libraries/intouch/src/keycodes.hb
Normal file
121
sysdata/libraries/intouch/src/keycodes.hb
Normal file
|
@ -0,0 +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
|
||||||
|
|
||||||
|
// Typically this is not a keycode you will ever recieve.
|
||||||
|
None := KeyCode.(0)
|
||||||
|
|
||||||
|
Escape := KeyCode.(1)
|
||||||
|
/* Alphabet keycodes */
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
/* Numeric keycodes*/
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
KeypadPeriod := KeyCode.(48)
|
||||||
|
KeypadDivide := KeyCode.(49)
|
||||||
|
KeypadMultiply := KeyCode.(50)
|
||||||
|
KeypadMinus := KeyCode.(51)
|
||||||
|
KeypadPlus := KeyCode.(52)
|
||||||
|
KeypadEnter := KeyCode.(53)
|
||||||
|
KeypadEquals := KeyCode.(54)
|
||||||
|
|
||||||
|
Delete := KeyCode.(55)
|
||||||
|
/* Locking Keys */
|
||||||
|
NumLock := KeyCode.(56)
|
||||||
|
CapsLock := KeyCode.(57)
|
||||||
|
ScrollLock := KeyCode.(58)
|
||||||
|
|
||||||
|
/* "Alt Gr" key */
|
||||||
|
Mode := KeyCode.(59)
|
||||||
|
|
||||||
|
/* Multi-key compose key */
|
||||||
|
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)
|
36
sysdata/libraries/intouch/src/lib.hb
Normal file
36
sysdata/libraries/intouch/src/lib.hb
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
stn := @use("../../stn/src/lib.hb");
|
||||||
|
.{log, buffer, memory} := stn
|
||||||
|
keycodes := @use("keycodes.hb")
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
recieve_mouse_event := fn(): ?MouseEvent {
|
||||||
|
mevent := MouseEvent.(0, 0, false, false, false)
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
|
@ -1,11 +1,75 @@
|
||||||
|
.{string, memory, buffer, log} := @use("../../stn/src/lib.hb")
|
||||||
|
|
||||||
PCIAddress := struct {
|
PCIAddress := struct {
|
||||||
bus: u8,
|
bus: u8,
|
||||||
device: u8,
|
device: u8,
|
||||||
function: u8,
|
function: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
find_device := fn(vendor_id: int, device_id: int, pci_address: PCIAddress): int {
|
PCI_ID := struct {
|
||||||
return 1
|
vendor: u16,
|
||||||
|
device: u16,
|
||||||
|
inner: int,
|
||||||
|
}
|
||||||
|
|
||||||
|
get_ids := fn(bus: u8, device: u8, function: u8): PCI_ID {
|
||||||
|
res := config_read32(bus, device, function, 0)
|
||||||
|
dev_id := res >> 16
|
||||||
|
dev_id &= 0xFFFF
|
||||||
|
|
||||||
|
vnd_id := res & 0xFFFF
|
||||||
|
return PCI_ID.(dev_id, vnd_id, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
PciDeviceInfo := struct {
|
||||||
|
header_type: u8,
|
||||||
|
device: u8,
|
||||||
|
bus: u8,
|
||||||
|
device_id: PCI_ID,
|
||||||
|
class: u16,
|
||||||
|
rev_id: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
calculate_address := fn(bus: u8, device: u8, function: u8, offset: u8): int {
|
||||||
|
address := bus << 16
|
||||||
|
address |= device << 11
|
||||||
|
address |= function << 8
|
||||||
|
address |= offset & 0xFC
|
||||||
|
address |= 0x80000000
|
||||||
|
return address
|
||||||
|
}
|
||||||
|
|
||||||
|
get_header_type := fn(bus: u8, device: u8, function: u8): u8 {
|
||||||
|
res := config_read32(bus, device, function, 0xC)
|
||||||
|
ret := res >> 16
|
||||||
|
ret &= 0xFF
|
||||||
|
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
check_device := fn(bus: u8, device: u8): PciDeviceInfo {
|
||||||
|
pci_id := get_ids(bus, device, 0)
|
||||||
|
|
||||||
|
if pci_id.vendor == 0xFFFF {
|
||||||
|
log.warn(":|\0")
|
||||||
|
} else {
|
||||||
|
log.info(":)\0")
|
||||||
|
}
|
||||||
|
address := calculate_address(bus, device, 0, 0x8)
|
||||||
|
reg2 := config_read32(bus, device, 0, 0x8)
|
||||||
|
|
||||||
|
class := reg2 >> 16 & 0xFFFF
|
||||||
|
|
||||||
|
header_type := get_header_type(bus, device, 0)
|
||||||
|
|
||||||
|
rev_id := reg2 & 0xFF
|
||||||
|
return PciDeviceInfo.(header_type, device, bus, pci_id, class, rev_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
find_device := fn(vendor_id: int, device_id: int, pci_address: PCIAddress): PCI_ID {
|
||||||
|
pci_id := get_ids(0, 2, 0)
|
||||||
|
|
||||||
|
return pci_id
|
||||||
}
|
}
|
||||||
|
|
||||||
scan_bus := fn(): void {
|
scan_bus := fn(): void {
|
||||||
|
@ -13,16 +77,17 @@ scan_bus := fn(): void {
|
||||||
|
|
||||||
config_read32 := fn(bus: u32, device: u32, func: u32, offset: u32): u32 {
|
config_read32 := fn(bus: u32, device: u32, func: u32, offset: u32): u32 {
|
||||||
// construct address param
|
// construct address param
|
||||||
address := bus << 16 | device << 11 | func << 8
|
offset_and := offset & 0xFC
|
||||||
address |= offset
|
|
||||||
address &= 0xFC
|
address := bus << 16
|
||||||
|
address |= device << 11
|
||||||
|
address |= func << 8
|
||||||
|
address |= offset_and
|
||||||
address |= 0x80000000
|
address |= 0x80000000
|
||||||
|
|
||||||
// write address
|
// write address
|
||||||
//Port::new(0xCF8).write(address);
|
memory.outl(0xCF8, address)
|
||||||
|
|
||||||
// read data
|
// read data
|
||||||
//Port::new(0xCFC).read()
|
return memory.inl(0xCFC)
|
||||||
|
|
||||||
return
|
|
||||||
}
|
}
|
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("rel:svga.hb")
|
software := @use("software.hb")
|
||||||
software := @use("rel:software.hb")
|
image := @use("image/lib.hb")
|
||||||
|
text := @use("text.hb")
|
||||||
|
|
||||||
// default mode
|
// default mode
|
||||||
mode := software
|
mode := software
|
||||||
|
|
||||||
init := mode.init
|
init := mode.init
|
||||||
doublebuffer := mode.doublebuffer
|
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
|
// Colours
|
||||||
Color := mode.Color
|
Color := packed struct {b: u8, g: u8, r: u8, a: u8}
|
||||||
white := mode.white
|
$white := Color.(255, 255, 255, 255)
|
||||||
black := mode.black
|
$black := Color.(0, 0, 0, 255)
|
||||||
gray := mode.gray
|
$gray := Color.(127, 127, 127, 255)
|
||||||
red := mode.red
|
$red := Color.(0, 0, 205, 255)
|
||||||
green := mode.green
|
$green := Color.(0, 205, 0, 255)
|
||||||
yellow := mode.yellow
|
$yellow := Color.(0, 205, 205, 255)
|
||||||
blue := mode.blue
|
$blue := Color.(205, 0, 0, 255)
|
||||||
magenta := mode.magenta
|
$magenta := Color.(205, 0, 205, 255)
|
||||||
cyan := mode.cyan
|
$cyan := Color.(205, 205, 0, 255)
|
||||||
light_gray := mode.light_gray
|
$light_gray := Color.(229, 229, 229, 255)
|
||||||
light_red := mode.light_red
|
$light_red := Color.(0, 0, 255, 255)
|
||||||
light_green := mode.light_green
|
$light_green := Color.(0, 255, 0, 255)
|
||||||
light_yellow := mode.light_yellow
|
$light_yellow := Color.(0, 255, 255, 255)
|
||||||
light_blue := mode.light_blue
|
$light_blue := Color.(255, 0, 0, 255)
|
||||||
light_magenta := mode.light_magenta
|
$light_magenta := Color.(255, 0, 255, 255)
|
||||||
light_cyan := mode.light_cyan
|
$light_cyan := Color.(255, 255, 0, 255)
|
||||||
|
|
||||||
// Drawing
|
// Drawing
|
||||||
put_pixel := mode.put_pixel
|
put_pixel := mode.put_pixel
|
||||||
put_rect := mode.put_rect
|
put_rect := mode.put_rect
|
||||||
put_filled_rect := mode.put_filled_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_line := mode.put_line
|
||||||
|
put_vline := mode.put_vline
|
||||||
|
put_hline := mode.put_hline
|
||||||
clear := mode.clear
|
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
|
// 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
|
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");
|
.{math, memory, dt} := @use("../../stn/src/lib.hb");
|
||||||
.{dt_get} := @use("../../dt_api/src/lib.hb");
|
.{Color, text} := @use("lib.hb");
|
||||||
.{IVec2} := @use("rel:lib.hb")
|
.{get_glyph, get_glyph_unicode, Font, UNC_TABLE_SIZE} := text;
|
||||||
|
.{Vec2} := math
|
||||||
|
|
||||||
Color := struct {b: u8, g: u8, r: u8, a: u8}
|
// safety: don't use before init() or you will get a memory access violation
|
||||||
white := Color.(255, 255, 255, 255)
|
framebuffer := memory.dangling(Color)
|
||||||
black := Color.(0, 0, 0, 255)
|
|
||||||
gray := Color.(127, 127, 127, 255)
|
|
||||||
red := Color.(0, 0, 205, 255)
|
|
||||||
green := Color.(0, 205, 0, 255)
|
|
||||||
yellow := Color.(0, 205, 205, 255)
|
|
||||||
blue := Color.(205, 0, 0, 255)
|
|
||||||
magenta := Color.(205, 0, 205, 255)
|
|
||||||
cyan := Color.(205, 205, 0, 255)
|
|
||||||
light_gray := Color.(229, 229, 229, 255)
|
|
||||||
light_red := Color.(0, 0, 255, 255)
|
|
||||||
light_green := Color.(0, 255, 0, 255)
|
|
||||||
light_yellow := Color.(0, 255, 255, 255)
|
|
||||||
light_blue := Color.(255, 0, 0, 255)
|
|
||||||
light_magenta := Color.(255, 0, 255, 255)
|
|
||||||
light_cyan := Color.(255, 255, 0, 255)
|
|
||||||
|
|
||||||
// might not work for some resolutions, but needs to be comptime because...
|
Surface := struct {
|
||||||
copy_pixels := 0xC000 >> 2
|
|
||||||
|
|
||||||
ctx := @as(Context, idk)
|
|
||||||
|
|
||||||
// some of these are redudant holdovers from fb_driver
|
|
||||||
// will keep them for future work if necessary
|
|
||||||
Context := struct {
|
|
||||||
fb: ^Color,
|
|
||||||
bb: ^Color,
|
|
||||||
buf: ^Color,
|
buf: ^Color,
|
||||||
width: int,
|
width: uint,
|
||||||
height: int,
|
height: uint,
|
||||||
partitions: int,
|
size: uint,
|
||||||
pixels: int,
|
|
||||||
bb_pages: int,
|
|
||||||
double_buffer: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
init := fn(): void {
|
new_surface := fn(width: uint, height: uint): Surface {
|
||||||
width := dt_get("framebuffer/fb0/width\0")
|
return .(
|
||||||
height := dt_get("framebuffer/fb0/height\0")
|
memory.alloc(Color, width * height),
|
||||||
// width := 1024
|
|
||||||
// height := 768
|
|
||||||
pixels := width * height
|
|
||||||
bytes := pixels << 2
|
|
||||||
partitions := pixels / copy_pixels
|
|
||||||
pages := 1 + bytes >> 12
|
|
||||||
back_buffer := create_back_buffer(pages)
|
|
||||||
ctx = Context.{
|
|
||||||
fb: dt_get("framebuffer/fb0/ptr\0"),
|
|
||||||
bb: back_buffer,
|
|
||||||
buf: back_buffer,
|
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
partitions,
|
width * height,
|
||||||
pixels,
|
)
|
||||||
bb_pages: pages,
|
|
||||||
double_buffer: true,
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
doublebuffer := fn(enable: bool): void {
|
clone_surface := fn(surface: ^Surface): Surface {
|
||||||
if enable {
|
new := new_surface(surface.width, surface.height)
|
||||||
ctx.buf = ctx.bb
|
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 {
|
} 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
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
create_back_buffer := fn(pages: int): ^Color {
|
put_rect := fn(surface: Surface, pos: Vec2(uint), tr: Vec2(uint), color: Color): void {
|
||||||
if pages <= 0xFF {
|
start_idx := indexptr(surface, pos.x, pos.y)
|
||||||
return @bitcast(@inline(memory.request_page, pages))
|
end_idx := indexptr(surface, pos.x, pos.y + tr.y)
|
||||||
}
|
right_start_idx := indexptr(surface, pos.x + tr.x, pos.y)
|
||||||
ptr := @inline(memory.request_page, 255)
|
|
||||||
remaining := pages - 0xFF
|
|
||||||
loop if remaining <= 0 break else {
|
|
||||||
if remaining < 0xFF {
|
|
||||||
memory.request_page(remaining)
|
|
||||||
} else {
|
|
||||||
memory.request_page(0xFF)
|
|
||||||
}
|
|
||||||
remaining -= 0xFF
|
|
||||||
}
|
|
||||||
return @bitcast(ptr)
|
|
||||||
}
|
|
||||||
|
|
||||||
clear := fn(color: Color): void {
|
loop if start_idx > end_idx break else {
|
||||||
cursor := ctx.buf
|
*start_idx = color;
|
||||||
boundary := cursor + 512
|
*right_start_idx = color
|
||||||
loop if cursor == boundary break else {
|
start_idx += surface.width
|
||||||
*cursor = color
|
right_start_idx += surface.width
|
||||||
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])
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
sync := fn(): void {
|
put_line_low := fn(surface: Surface, p0: Vec2(uint), p1: Vec2(uint), color: Color): void {
|
||||||
if ctx.double_buffer {
|
dx := @as(int, @bitcast(p1.x - p0.x))
|
||||||
bb := ctx.buf
|
dy := @as(int, @bitcast(p1.y - p0.y))
|
||||||
fb := ctx.fb
|
|
||||||
boundary := bb + ctx.pixels
|
|
||||||
loop if bb == boundary break else {
|
|
||||||
*@as(^[Color; copy_pixels], @bitcast(fb)) = *@as(^[Color; copy_pixels], @bitcast(bb))
|
|
||||||
bb += copy_pixels
|
|
||||||
fb += copy_pixels
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
width := fn(): int {
|
|
||||||
return ctx.width
|
|
||||||
}
|
|
||||||
|
|
||||||
height := fn(): int {
|
|
||||||
return ctx.height
|
|
||||||
}
|
|
||||||
|
|
||||||
screenidx := fn(x: int, y: int): int {
|
|
||||||
return x + ctx.width * y
|
|
||||||
}
|
|
||||||
|
|
||||||
put_pixel := fn(pos: IVec2, color: Color): void {
|
|
||||||
*(ctx.buf + @inline(screenidx, pos.x, pos.y)) = color
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
put_filled_rect := fn(pos: IVec2, tr: IVec2, color: Color): void {
|
|
||||||
x := pos.x
|
|
||||||
y := pos.y
|
|
||||||
end := pos + tr
|
|
||||||
loop if x == end.x break else {
|
|
||||||
loop if y == end.y break else {
|
|
||||||
*(ctx.buf + @inline(screenidx, x, y)) = color
|
|
||||||
y += 1
|
|
||||||
}
|
|
||||||
x += 1
|
|
||||||
y = pos.y
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
put_rect := fn(pos: IVec2, tr: IVec2, color: Color): void {
|
|
||||||
x := pos.x
|
|
||||||
y := pos.y
|
|
||||||
end := pos + tr
|
|
||||||
loop if y == end.y break else {
|
|
||||||
*(ctx.buf + @inline(screenidx, x, y)) = color;
|
|
||||||
*(ctx.buf + @inline(screenidx, x + tr.x, y)) = color
|
|
||||||
y += 1
|
|
||||||
}
|
|
||||||
y = pos.y
|
|
||||||
loop if x == end.x break else {
|
|
||||||
*(ctx.buf + @inline(screenidx, x, y)) = color;
|
|
||||||
*(ctx.buf + @inline(screenidx, x, y + tr.y)) = color
|
|
||||||
x += 1
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
put_line_low := fn(p0: IVec2, p1: IVec2, color: Color): void {
|
|
||||||
dx := p1.x - p0.x
|
|
||||||
dy := p1.y - p0.y
|
|
||||||
yi := 1
|
yi := 1
|
||||||
if dy < 0 {
|
if dy < 0 {
|
||||||
yi = -1
|
yi = -1
|
||||||
dy = -dy
|
dy = -dy
|
||||||
}
|
}
|
||||||
D := 2 * dy - dx
|
D := @as(int, 2) * dy - dx
|
||||||
y := p0.y
|
y := p0.y
|
||||||
x := p0.x
|
x := p0.x
|
||||||
loop if x == p1.x break else {
|
loop if x == p1.x break else {
|
||||||
*(ctx.buf + @inline(screenidx, x, y)) = color
|
*indexptr(surface, x, y) = color
|
||||||
if D > 0 {
|
if D > 0 {
|
||||||
y += yi
|
y += yi
|
||||||
D += 2 * (dy - dx)
|
D += 2 * (dy - dx)
|
||||||
|
@ -203,19 +122,19 @@ put_line_low := fn(p0: IVec2, p1: IVec2, color: Color): void {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
put_line_high := fn(p0: IVec2, p1: IVec2, color: Color): void {
|
put_line_high := fn(surface: Surface, p0: Vec2(uint), p1: Vec2(uint), color: Color): void {
|
||||||
dx := p1.x - p0.x
|
dx := @as(int, @bitcast(p1.x - p0.x))
|
||||||
dy := p1.y - p0.y
|
dy := @as(int, @bitcast(p1.y - p0.y))
|
||||||
xi := 1
|
xi := 1
|
||||||
if dy < 0 {
|
if dy < 0 {
|
||||||
xi = -1
|
xi = -1
|
||||||
dx = -dx
|
dx = -dx
|
||||||
}
|
}
|
||||||
D := 2 * dx - dy
|
D := @as(int, 2) * dx - dy
|
||||||
x := p0.x
|
x := p0.x
|
||||||
y := p0.y
|
y := p0.y
|
||||||
loop if y == p1.y break else {
|
loop if y == p1.y break else {
|
||||||
*(ctx.buf + @inline(screenidx, x, y)) = color
|
*indexptr(surface, x, y) = color
|
||||||
if D > 0 {
|
if D > 0 {
|
||||||
x += xi
|
x += xi
|
||||||
D += 2 * (dx - dy)
|
D += 2 * (dx - dy)
|
||||||
|
@ -227,35 +146,327 @@ put_line_high := fn(p0: IVec2, p1: IVec2, color: Color): void {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
put_line := fn(p0: IVec2, p1: IVec2, color: Color): void {
|
put_line := fn(surface: Surface, p0: Vec2(uint), p1: Vec2(uint), color: Color): void {
|
||||||
if @inline(math.abs, p1.y - p0.y) < @inline(math.abs, p1.x - p0.x) {
|
if math.abs(uint, p1.y - p0.y) < math.abs(uint, p1.x - p0.x) {
|
||||||
if p0.x > p1.x {
|
if p0.x > p1.x {
|
||||||
@inline(put_line_low, p1, p0, color)
|
@inline(put_line_low, surface, p1, p0, color)
|
||||||
} else {
|
} else {
|
||||||
@inline(put_line_low, p0, p1, color)
|
@inline(put_line_low, surface, p0, p1, color)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if p0.y > p1.y {
|
if p0.y > p1.y {
|
||||||
@inline(put_line_high, p1, p0, color)
|
@inline(put_line_high, surface, p1, p0, color)
|
||||||
} else {
|
} else {
|
||||||
@inline(put_line_high, p0, p1, color)
|
@inline(put_line_high, surface, p0, p1, color)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return
|
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
|
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
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
dimensions := fn(): IVec2 {
|
// peony-made
|
||||||
return .(ctx.width, ctx.height)
|
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
|
return
|
||||||
}
|
}
|
|
@ -1,80 +0,0 @@
|
||||||
.{IVec2} := @use("rel:lib.hb")
|
|
||||||
// .{pci, memory, string, log} := @use("../../stn/src/lib.hb");
|
|
||||||
|
|
||||||
Color := struct {b: u8, g: u8, r: u8, a: u8}
|
|
||||||
white := Color.(255, 255, 255, 255)
|
|
||||||
black := Color.(0, 0, 0, 255)
|
|
||||||
gray := Color.(127, 127, 127, 255)
|
|
||||||
red := Color.(0, 0, 205, 255)
|
|
||||||
green := Color.(0, 205, 0, 255)
|
|
||||||
yellow := Color.(0, 205, 205, 255)
|
|
||||||
blue := Color.(205, 0, 0, 255)
|
|
||||||
magenta := Color.(205, 0, 205, 255)
|
|
||||||
cyan := Color.(205, 205, 0, 255)
|
|
||||||
light_gray := Color.(229, 229, 229, 255)
|
|
||||||
light_red := Color.(0, 0, 255, 255)
|
|
||||||
light_green := Color.(0, 255, 0, 255)
|
|
||||||
light_yellow := Color.(0, 255, 255, 255)
|
|
||||||
light_blue := Color.(255, 0, 0, 255)
|
|
||||||
light_magenta := Color.(255, 0, 255, 255)
|
|
||||||
light_cyan := Color.(255, 255, 0, 255)
|
|
||||||
|
|
||||||
clear := fn(color: Color): void {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
width := fn(): int {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
height := fn(): int {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
dimensions := fn(): IVec2 {
|
|
||||||
return .(0, 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
put_pixel := fn(position: IVec2, color: Color): void {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
put_filled_rect := fn(pos: IVec2, tr: IVec2, color: Color): void {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
put_rect := fn(pos: IVec2, tr: IVec2, color: Color): void {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
put_line_low := fn(p0: IVec2, p1: IVec2, color: Color): void {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// do not use, use line() instead
|
|
||||||
put_line_high := fn(p0: IVec2, p1: IVec2, color: Color): void {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
put_line := fn(p0: IVec2, p1: IVec2, color: Color): void {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
set_height := fn(new: int): void {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
set_width := fn(new: int): void {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
set_dimensions := fn(new: IVec2): void {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
sync := fn(): void {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
init := fn(): void {
|
|
||||||
return
|
|
||||||
}
|
|
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
|
||||||
|
}
|
||||||
|
}
|
31
sysdata/libraries/stn/src/acs.hb
Normal file
31
sysdata/libraries/stn/src/acs.hb
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
//! This is a reserved file for use with the AbleOS Clustering System
|
||||||
|
|
||||||
|
HostID := int
|
||||||
|
ID := int
|
||||||
|
|
||||||
|
FileID := struct {
|
||||||
|
host_id: HostID,
|
||||||
|
id: ID,
|
||||||
|
}
|
||||||
|
|
||||||
|
// A DeviceID points to a specific device in the ACS.
|
||||||
|
DeviceID := struct {
|
||||||
|
host_id: HostID,
|
||||||
|
id: ID,
|
||||||
|
}
|
||||||
|
DiskID := DeviceID
|
||||||
|
|
||||||
|
BufferID := struct {
|
||||||
|
host_id: HostID,
|
||||||
|
id: ID,
|
||||||
|
}
|
||||||
|
|
||||||
|
ProcessID := struct {
|
||||||
|
host_id: HostID,
|
||||||
|
id: ID,
|
||||||
|
}
|
||||||
|
|
||||||
|
WindowID := struct {
|
||||||
|
host_id: HostID,
|
||||||
|
id: ID,
|
||||||
|
}
|
|
@ -1,24 +1,35 @@
|
||||||
string := @use("rel:string.hb")
|
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(^u8, 4, buffer_id, memory_map_location, length)
|
return @eca(4, buffer_id, memory_map_location, @sizeof(Expr))
|
||||||
}
|
}
|
||||||
|
|
||||||
send_message := fn(msg: ^u8, buffer_id: int): void {
|
$write := fn($Expr: type, buffer_id: uint, msg: ^Expr): void {
|
||||||
msg_length := @inline(string.length, msg)
|
return @eca(3, buffer_id, msg, @sizeof(Expr))
|
||||||
@eca(i32, 3, buffer_id, msg, msg_length)
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
create := fn(msg: ^u8): int {
|
$recv_length := fn(length: uint, memory_map_location: ^u8, buffer_id: uint): void {
|
||||||
msg_length := @inline(string.length, msg);
|
return @eca(4, buffer_id, memory_map_location, length)
|
||||||
*msg = 0
|
|
||||||
return @eca(int, 3, 0, msg, msg_length)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
search := fn(msg: ^u8): int {
|
$write_length := fn(length: uint, msg: ^u8, buffer_id: uint): void {
|
||||||
msg_length := @inline(string.length, msg);
|
return @eca(3, buffer_id, msg, length)
|
||||||
*msg = 3
|
}
|
||||||
|
|
||||||
return @eca(int, 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))
|
||||||
|
}
|
||||||
|
|
||||||
|
$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))
|
||||||
|
}
|
31
sysdata/libraries/stn/src/file_io.hb
Normal file
31
sysdata/libraries/stn/src/file_io.hb
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
acs := @use("acs.hb");
|
||||||
|
.{DiskID, FileID} := acs
|
||||||
|
|
||||||
|
// Paths without a node-disk component are to be treated as local files.
|
||||||
|
// file_path := "DID:/test\0";
|
||||||
|
Path := struct {
|
||||||
|
// DiskID holds the host id
|
||||||
|
disk_id: DiskID,
|
||||||
|
length: u8,
|
||||||
|
data: ^u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
open := fn(file_path: Path): FileID {
|
||||||
|
}
|
||||||
|
close := fn(file_id: FileID): int {
|
||||||
|
}
|
||||||
|
// This reads in page_count of pages out of the file. If file_size is less than an exact multiple of pages do something.
|
||||||
|
// TODO: Figureout how to encode errors.
|
||||||
|
read_pages := fn(file_id: FileID, offset: int, page_count: int): void {
|
||||||
|
}
|
||||||
|
|
||||||
|
// This writes out page_count of pages out of the file.
|
||||||
|
write_pages := fn(file_id: FileID, offset: int, page_count: int): void {
|
||||||
|
}
|
||||||
|
|
||||||
|
// This reads out byte_count of bytes from the file.
|
||||||
|
read_bytes := fn(file_id: FileID, offset: int, byte_count: int): void {
|
||||||
|
}
|
||||||
|
|
||||||
|
write_bytes := fn(file_id: FileID, offset: int, byte_count: int): void {
|
||||||
|
}
|
|
@ -1,7 +1,20 @@
|
||||||
string := @use("rel:string.hb")
|
acs := @use("acs.hb")
|
||||||
log := @use("rel:log.hb")
|
string := @use("string.hb")
|
||||||
memory := @use("rel:memory.hb")
|
log := @use("log.hb")
|
||||||
buffer := @use("rel:buffer.hb")
|
memory := @use("memory.hb")
|
||||||
math := @use("rel:math.hb")
|
buffer := @use("buffer.hb")
|
||||||
random := @use("rel:random.hb")
|
math := @use("math.hb")
|
||||||
pci := @use("rel:pci.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("rel:string.hb")
|
string := @use("string.hb")
|
||||||
buffer := @use("rel:buffer.hb")
|
|
||||||
|
|
||||||
log := fn(message: ^u8, level: u8): void {
|
LogMsg := packed struct {level: u8, string: ^u8, strlen: uint}
|
||||||
message_length := @inline(string.length, message);
|
|
||||||
*(message + message_length) = level
|
log := fn(level: u8, message: ^u8): void {
|
||||||
@eca(i32, 3, 1, message, message_length + 1)
|
return @eca(3, 1, LogMsg.(level, message, @inline(string.length, message)), @sizeof(LogMsg))
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
error := fn(message: ^u8): void return log(message, 0)
|
error := fn(message: ^u8): void return @inline(log, 0, message)
|
||||||
warn := fn(message: ^u8): void return log(message, 1)
|
warn := fn(message: ^u8): void return @inline(log, 1, message)
|
||||||
info := fn(message: ^u8): void return log(message, 2)
|
info := fn(message: ^u8): void return @inline(log, 2, message)
|
||||||
debug := fn(message: ^u8): void return log(message, 3)
|
debug := fn(message: ^u8): void return @inline(log, 3, message)
|
||||||
trace := fn(message: ^u8): void return log(message, 4)
|
trace := fn(message: ^u8): void return @inline(log, 4, message)
|
File diff suppressed because one or more lines are too long
|
@ -1,54 +1,76 @@
|
||||||
request_page := fn(page_count: u8): ^u8 {
|
$PAGE_SIZE := 4096
|
||||||
msg := "\{00}\{01}xxxxxxxx\0"
|
$MAX_ALLOC := 0xFF
|
||||||
msg_page_count := msg + 1;
|
$MAX_FREE := 0xFF
|
||||||
*msg_page_count = page_count
|
|
||||||
return @eca(^u8, 3, 2, msg, 12)
|
$uninit := fn($Expr: type): ?Expr {
|
||||||
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
release_page := fn(ptr: ^u8, page_count: u8): void {
|
$dangling := fn($Expr: type): ^Expr {
|
||||||
msg := "\{01}\{00}xxxxxxxx\0"
|
return @bitcast(@alignof(Expr))
|
||||||
|
|
||||||
msg_page_count := msg + 1;
|
|
||||||
*msg_page_count = page_count
|
|
||||||
|
|
||||||
msg_ptr := @as(^^u8, @bitcast(msg + 2));
|
|
||||||
*msg_ptr = ptr
|
|
||||||
|
|
||||||
return @eca(void, 3, 2, msg, 12)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
outb := fn(addr: u16, value: u8): void {
|
$calc_pages := fn($Expr: type, num: uint): uint {
|
||||||
msg := "\0\0\0\0\0";
|
return 1 + @sizeof(Expr) * num / PAGE_SIZE
|
||||||
*@as(^u8, msg) = @as(u8, 1);
|
}
|
||||||
*@as(^u8, msg + 1) = @as(u8, 0);
|
|
||||||
*@as(^u16, @bitcast(msg + 2)) = addr;
|
// ! will be replaced, don't get attached
|
||||||
*@as(^u8, msg + 4) = value
|
alloc := fn($Expr: type, num: uint): ^Expr {
|
||||||
@eca(void, 3, 3, msg, 5)
|
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
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
inb := fn(addr: u16): u8 {
|
RqPageMsg := packed struct {a: u8, count: u8}
|
||||||
msg := "\0\0\0\0";
|
$request_page := fn(count: u8): ^u8 {
|
||||||
*@as(^u8, msg) = @as(u8, 0);
|
return @eca(3, 2, &RqPageMsg.(0, count), @sizeof(RqPageMsg))
|
||||||
*@as(^u8, msg + 1) = @as(u8, 0);
|
|
||||||
*@as(^u16, @bitcast(msg + 2)) = addr
|
|
||||||
return @eca(u8, 3, 3, msg, 4)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
outl := fn(addr: u16, value: u32): void {
|
RlPageMsg := packed struct {a: u8, count: u8, ptr: ^u8}
|
||||||
msg := "\0\0\0\0\0\0\0\0";
|
$release_page := fn(ptr: ^u8, count: u8): void {
|
||||||
*@as(^u8, msg) = @as(u8, 1);
|
return @eca(3, 2, &RlPageMsg.(1, count, ptr), @sizeof(RlPageMsg))
|
||||||
*@as(^u8, msg + 1) = @as(u8, 2);
|
|
||||||
*@as(^u16, @bitcast(msg + 2)) = addr;
|
|
||||||
*@as(^u32, @bitcast(msg + 4)) = value
|
|
||||||
@eca(void, 3, 3, msg, 8)
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inl := fn(addr: u16): u32 {
|
OutbMsg := packed struct {a: u8, b: u8, addr: u16, value: u8}
|
||||||
msg := "\0\0\0\0";
|
$outb := fn(addr: u16, value: u8): void {
|
||||||
*@as(^u8, msg) = @as(u8, 0);
|
return @eca(3, 3, &OutbMsg.(1, 0, addr, value), @sizeof(OutbMsg))
|
||||||
*@as(^u8, msg + 1) = @as(u8, 2);
|
}
|
||||||
*@as(^u16, @bitcast(msg + 2)) = addr
|
|
||||||
return @eca(u32, 3, 3, msg, 4)
|
InbMsg := packed struct {a: u8, b: u8, addr: u16}
|
||||||
|
$inb := fn(addr: u16): u8 {
|
||||||
|
return @eca(3, 3, &InbMsg.(0, 0, addr), @sizeof(InbMsg))
|
||||||
|
}
|
||||||
|
|
||||||
|
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))
|
||||||
|
}
|
||||||
|
|
||||||
|
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))
|
||||||
}
|
}
|
|
@ -1,50 +0,0 @@
|
||||||
.{inl, outl} := @use("rel:memory.hb")
|
|
||||||
|
|
||||||
config_read := fn(bus: u8, device: u8, func: u8, offset: u8): u32 {
|
|
||||||
lbus := @as(u32, bus)
|
|
||||||
ldevice := @as(u32, device)
|
|
||||||
lfunc := @as(u32, func)
|
|
||||||
loffset := @as(u32, offset)
|
|
||||||
|
|
||||||
address := lbus << 16 | ldevice << 11 | lfunc << 8 | loffset & 0xFC | @as(u32, 0x80000000)
|
|
||||||
|
|
||||||
outl(0xCF8, address)
|
|
||||||
return inl(0xCFC)
|
|
||||||
}
|
|
||||||
|
|
||||||
config_write := fn(bus: u8, device: u8, func: u8, offset: u8, value: u32): void {
|
|
||||||
lbus := @as(u32, bus)
|
|
||||||
ldevice := @as(u32, device)
|
|
||||||
lfunc := @as(u32, func)
|
|
||||||
loffset := @as(u32, offset)
|
|
||||||
|
|
||||||
address := lbus << 16 | ldevice << 11 | lfunc << 8 | loffset & 0xFC | @as(u32, 0x80000000)
|
|
||||||
|
|
||||||
outl(0xCF8, address)
|
|
||||||
outl(0xCFC, value)
|
|
||||||
}
|
|
||||||
|
|
||||||
get_header_type := fn(bus: u8, device: u8, func: u8): u8 {
|
|
||||||
return @as(u8, config_read(bus, device, func, 0xC) >> 16 & 0xFF)
|
|
||||||
}
|
|
||||||
|
|
||||||
Ids := struct {vendor: u16, device: u16}
|
|
||||||
|
|
||||||
get_ids := fn(bus: u8, device: u8, func: u8): Ids {
|
|
||||||
res := config_read(bus, device, func, 0)
|
|
||||||
return .(@as(u16, res >> 16 & 0xFFFF), @as(u16, res & 0xFFFF))
|
|
||||||
}
|
|
||||||
|
|
||||||
PciDeviceInfo := struct {header_type: u8, device: u8, bus: u8, device_id: Ids, full_class: u16, rev_id: u8}
|
|
||||||
|
|
||||||
check_device := fn(bus: u8, device: u8): PciDeviceInfo {
|
|
||||||
ids := get_ids(bus, device, 0)
|
|
||||||
if ids.vendor == 0xFFFF {
|
|
||||||
return .(0, 0, 0, .(0, 0), 0, 0)
|
|
||||||
}
|
|
||||||
reg2 := config_read(bus, device, 0, 0x8)
|
|
||||||
class := @as(u16, reg2 >> 16 & 0xFFFF)
|
|
||||||
header_type := get_header_type(bus, device, 0)
|
|
||||||
|
|
||||||
return .(header_type, device, bus, ids, class, @as(u8, reg2 & 0xFF))
|
|
||||||
}
|
|
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 */
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue