Compare commits
120 commits
devcontain
...
master
Author | SHA1 | Date | |
---|---|---|---|
Able | 9aa84a0f40 | ||
Able | bdb762c986 | ||
koniifer | 0b57c2e9bb | ||
Able | 8c88c0b5ae | ||
Able | 8b2b50e433 | ||
Able | d7e0d573e2 | ||
Able | 0ee8b7a4e4 | ||
Able | 2261f36101 | ||
Able | 6f82c92c30 | ||
koniifer | 5ea3ee9fe1 | ||
Able | 241139f5af | ||
Able | 5c4056bc5c | ||
b505622601 | |||
80ae717dd9 | |||
ab8b2309ae | |||
koniifer | 7b7e02976d | ||
koniifer | c1c02ffefd | ||
able | 8602ceb0d3 | ||
Able | 6b673bc7e6 | ||
koniifer | 0af4d142a4 | ||
koniifer | 36f0d357cf | ||
koniifer | ccddf36050 | ||
koniifer | da5f1a7a19 | ||
koniifer | 2808bc9e7c | ||
koniifer | d958a103fa | ||
koniifer | ee82bc5705 | ||
Able | 3d53b641bf | ||
koniifer | cea7f1fa5c | ||
Able | 614bef7ec5 | ||
Able | b0f6aa53bd | ||
Able | d5f4ce18a3 | ||
koniifer | 907c0d0dd4 | ||
koniifer | 95b4a921dc | ||
koniifer | b6261d014d | ||
Able | 56ee0fe851 | ||
koniifer | b07bac1f1f | ||
koniifer | dc9273b3c1 | ||
Able | e6d8f5c822 | ||
koniifer | 8ad7542b9c | ||
Able | e40a22fccd | ||
koniifer | cf917927a5 | ||
koniifer | 97ceb12d6e | ||
koniifer | bae58ade61 | ||
koniifer | b21c05e924 | ||
Able | 2f5bc73665 | ||
Able | 0003464099 | ||
koniifer | 77a708d41e | ||
peony | 3409f5051a | ||
Able | 8c7b95277d | ||
koniifer | 7da32b263f | ||
Able | 2439722c88 | ||
koniifer | 3333b1706f | ||
Able | 8808ed5bfe | ||
koniifer | 68d3236cc0 | ||
Able | eea23d967b | ||
Able | d2152537ad | ||
Able | 7723799e76 | ||
koniifer | 8b04b275f3 | ||
Able | 1345f294b8 | ||
Able | 818bcb458f | ||
Able | d2b5f09511 | ||
2676bd7b62 | |||
koniifer | 444fcdb0c4 | ||
koniifer | adbf32d970 | ||
Able | 7f01b0e0f8 | ||
Able | e8edee4ccc | ||
koniifer | ba59233ce7 | ||
Able | f13c682171 | ||
Able | b6b097a872 | ||
koniifer | 6a8d92d2c2 | ||
Able | ab8522fbe1 | ||
Able | a49ac7bca0 | ||
Able | 12883ac926 | ||
Able | 6a319c55b0 | ||
Able | 879bbfa173 | ||
Able | 795f10986f | ||
Able | 85e63eb51c | ||
koniifer | aafe047b51 | ||
koniifer | 404ea22c46 | ||
koniifer | 664334fd00 | ||
Able | 086948d47a | ||
Able | b795215b62 | ||
Able | 16135ae536 | ||
Able | 941eed0ac9 | ||
Able | f4ad4b6856 | ||
koniifer | 9e83707a28 | ||
Able | 6894ef2360 | ||
Able | 69c95c35b5 | ||
Able | 80d363bc59 | ||
Able | 3c3c156eb0 | ||
koniifer | eaace7d9c1 | ||
koniifer | 5af5631755 | ||
Able | fac573837f | ||
koniifer | 6ff65eee41 | ||
koniifer | b35b430047 | ||
koniifer | bcfaf89ed0 | ||
koniifer | 2ba2dcb464 | ||
koniifer | 41d9c0b82a | ||
koniifer | a94332370a | ||
koniifer | 7caa47b9fb | ||
Able | 34101d2e8c | ||
Able | 2bc13cd7d8 | ||
koniifer | 086cc4aef0 | ||
Able | 84f86488c7 | ||
Able | ed7c8f20cb | ||
koniifer | 34cbd9a5e6 | ||
koniifer | 0ebb1f200e | ||
Able | fc06820332 | ||
koniifer | 2a082d8283 | ||
koniifer | 1eee33ce8b | ||
Able | 6fa1c829fd | ||
koniifer | 820c3e459b | ||
koniifer | 3af28f1666 | ||
koniifer | 96c2bd5cd5 | ||
koniifer | ea8eca1089 | ||
koniifer | 7f4a040505 | ||
koniifer | 82f5cdbe21 | ||
koniifer | aac6d61dc6 | ||
koniifer | 3df6f18c85 | ||
koniifer | 07ee8de9f1 |
|
@ -1,3 +1,3 @@
|
||||||
[alias]
|
[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 --"
|
||||||
|
|
2
.vscode/settings.json
vendored
2
.vscode/settings.json
vendored
|
@ -1,4 +1,6 @@
|
||||||
{
|
{
|
||||||
|
"editor.insertSpaces": false,
|
||||||
|
"editor.detectIndentation": false,
|
||||||
"rust-analyzer.checkOnSave.allTargets": false,
|
"rust-analyzer.checkOnSave.allTargets": false,
|
||||||
"rust-analyzer.showUnlinkedFileNotification": false,
|
"rust-analyzer.showUnlinkedFileNotification": false,
|
||||||
"C_Cpp.errorSquiggles": "disabled"
|
"C_Cpp.errorSquiggles": "disabled"
|
||||||
|
|
1207
Cargo.lock
generated
1207
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)
|
77
STYLE_GUIDE.md
Normal file
77
STYLE_GUIDE.md
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
# Style Guide
|
||||||
|
This style guide has two modes that a guideline may be.
|
||||||
|
|
||||||
|
`strict` means that prs will be rejected if they do not follow the guideline.
|
||||||
|
|
||||||
|
`loose` means that a pr would be accepted but should later be fixed.
|
||||||
|
|
||||||
|
## Empty Functions | loose
|
||||||
|
Empty functions are typically a sign of an unfinished program or driver.
|
||||||
|
|
||||||
|
In cases where there is a clear reason to have an empty function it will be allowed.
|
||||||
|
For example FakeAlloc is only empty functions because it is a example of an the allocator api.
|
||||||
|
|
||||||
|
### Allowed
|
||||||
|
```rust
|
||||||
|
/// in example.hb
|
||||||
|
a := fn(): void {}
|
||||||
|
```
|
||||||
|
### Not Allowed
|
||||||
|
```rust
|
||||||
|
/// in fat32.hb
|
||||||
|
a := fn(): void {}
|
||||||
|
```
|
||||||
|
## Magic Functions | loose
|
||||||
|
'Magic functions' are what I am calling small helper functions that do one or two things.
|
||||||
|
### Example
|
||||||
|
```rust
|
||||||
|
a := null
|
||||||
|
magic_a := fn(){
|
||||||
|
a = 10
|
||||||
|
}
|
||||||
|
```
|
||||||
|
The exact policy I want to have here is a bit fuzzy. I think that functions like this are nice in certain situations and not in others.
|
||||||
|
Regardless of if you use them or not, put a comment above the function explaining rational.
|
||||||
|
|
||||||
|
|
||||||
|
## Magic Numbers | loose
|
||||||
|
The policy on magic numbers is make them const and have a comment above them. Typically linking to a source of information about the magic number.
|
||||||
|
|
||||||
|
This helps cut down on magic numbers while making acceptable names and atleast half assed documentation.
|
||||||
|
|
||||||
|
Constants are inlined anyways, so its the same thing in the binary.
|
||||||
|
|
||||||
|
```rust
|
||||||
|
// The standard vga port is mapped at 0xB8000
|
||||||
|
$VGA_PTR := 0xB8000
|
||||||
|
```
|
||||||
|
|
||||||
|
## Tabs Vs Spaces | strict
|
||||||
|
I prefer for hblang code to use hard tabs.
|
||||||
|
|
||||||
|
The rational behind this is that a tab is `1 Indent` which some developers might want to be various different sizes when displayed
|
||||||
|
|
||||||
|
Soft tabs do not allow this user/editor specific as soft tabs always become spaces.
|
||||||
|
|
||||||
|
Bottom line is this is an accessibility feature.
|
||||||
|
|
||||||
|
There are some samples below.
|
||||||
|
```
|
||||||
|
\t means hard tab
|
||||||
|
\n means new line
|
||||||
|
\0x20 means space
|
||||||
|
```
|
||||||
|
|
||||||
|
### Allowed
|
||||||
|
```rust
|
||||||
|
if x == y {\n
|
||||||
|
\tlog(z)\n
|
||||||
|
}\n
|
||||||
|
```
|
||||||
|
|
||||||
|
### Not Allowed
|
||||||
|
```rust
|
||||||
|
if x == y {\n
|
||||||
|
\0x20\0x20\0x20\0x20log(z)\n
|
||||||
|
}\n
|
||||||
|
```
|
|
@ -138,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!(
|
||||||
|
|
96
flake.lock
Normal file
96
flake.lock
Normal file
|
@ -0,0 +1,96 @@
|
||||||
|
{
|
||||||
|
"nodes": {
|
||||||
|
"flake-utils": {
|
||||||
|
"inputs": {
|
||||||
|
"systems": "systems"
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1731533236,
|
||||||
|
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nixpkgs": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1732014248,
|
||||||
|
"narHash": "sha256-y/MEyuJ5oBWrWAic/14LaIr/u5E0wRVzyYsouYY3W6w=",
|
||||||
|
"owner": "NixOS",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "23e89b7da85c3640bbc2173fe04f4bd114342367",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "NixOS",
|
||||||
|
"ref": "nixos-unstable",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nixpkgs_2": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1728538411,
|
||||||
|
"narHash": "sha256-f0SBJz1eZ2yOuKUr5CA9BHULGXVSn6miBuUWdTyhUhU=",
|
||||||
|
"owner": "NixOS",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "b69de56fac8c2b6f8fd27f2eca01dcda8e0a4221",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "NixOS",
|
||||||
|
"ref": "nixpkgs-unstable",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": {
|
||||||
|
"inputs": {
|
||||||
|
"flake-utils": "flake-utils",
|
||||||
|
"nixpkgs": "nixpkgs",
|
||||||
|
"rust-overlay": "rust-overlay"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"rust-overlay": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs": "nixpkgs_2"
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1732328983,
|
||||||
|
"narHash": "sha256-RHt12f/slrzDpSL7SSkydh8wUE4Nr4r23HlpWywed9E=",
|
||||||
|
"owner": "oxalica",
|
||||||
|
"repo": "rust-overlay",
|
||||||
|
"rev": "ed8aa5b64f7d36d9338eb1d0a3bb60cf52069a72",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "oxalica",
|
||||||
|
"repo": "rust-overlay",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"systems": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1681028828,
|
||||||
|
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "default",
|
||||||
|
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "default",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": "root",
|
||||||
|
"version": 7
|
||||||
|
}
|
30
flake.nix
Normal file
30
flake.nix
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
{
|
||||||
|
description = "A devShell example";
|
||||||
|
|
||||||
|
inputs = {
|
||||||
|
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
||||||
|
rust-overlay.url = "github:oxalica/rust-overlay";
|
||||||
|
flake-utils.url = "github:numtide/flake-utils";
|
||||||
|
};
|
||||||
|
|
||||||
|
outputs = { self, nixpkgs, rust-overlay, flake-utils }:
|
||||||
|
flake-utils.lib.eachDefaultSystem (system:
|
||||||
|
let
|
||||||
|
overlays = [ (import rust-overlay) ];
|
||||||
|
pkgs = import nixpkgs {
|
||||||
|
inherit system overlays;
|
||||||
|
};
|
||||||
|
|
||||||
|
rustToolchain = pkgs.pkgsBuildHost.rust-bin.fromRustupToolchainFile ./rust-toolchain.toml;
|
||||||
|
in
|
||||||
|
with pkgs;
|
||||||
|
{
|
||||||
|
devShells.default = mkShell {
|
||||||
|
buildInputs = [
|
||||||
|
rustToolchain
|
||||||
|
qemu_full
|
||||||
|
];
|
||||||
|
};
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
|
@ -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"]
|
|
||||||
|
|
|
@ -3,10 +3,15 @@ edition = "2021"
|
||||||
name = "kernel"
|
name = "kernel"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
|
|
||||||
|
[features]
|
||||||
|
ktest = []
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
embedded-graphics = "0.8"
|
# embedded-graphics = "0.8"
|
||||||
hbvm.git = "https://git.ablecorp.us/AbleOS/holey-bytes.git"
|
hbvm = { git = "https://git.ablecorp.us/AbleOS/holey-bytes.git", features = [
|
||||||
|
"nightly",
|
||||||
|
] }
|
||||||
|
ktest_macro = { path = "ktest_macro" }
|
||||||
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,21 +19,14 @@ 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
|
||||||
|
@ -49,7 +47,7 @@ features = [
|
||||||
[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"
|
||||||
|
|
11
kernel/ktest_macro/Cargo.toml
Normal file
11
kernel/ktest_macro/Cargo.toml
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
[package]
|
||||||
|
edition = "2021"
|
||||||
|
name = "ktest_macro"
|
||||||
|
version = "0.1.0"
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
proc-macro = true
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
quote = "1.0.37"
|
||||||
|
syn = { version = "2.0.89", features = ["full"] }
|
29
kernel/ktest_macro/src/lib.rs
Normal file
29
kernel/ktest_macro/src/lib.rs
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
extern crate proc_macro;
|
||||||
|
extern crate quote;
|
||||||
|
extern crate syn;
|
||||||
|
use {
|
||||||
|
proc_macro::TokenStream,
|
||||||
|
quote::quote,
|
||||||
|
syn::{parse_macro_input, ItemFn}
|
||||||
|
};
|
||||||
|
|
||||||
|
#[proc_macro_attribute]
|
||||||
|
pub fn ktest(_attr: TokenStream, item: TokenStream) -> TokenStream {
|
||||||
|
let input = parse_macro_input!(item as ItemFn);
|
||||||
|
let test_name = &input.sig.ident;
|
||||||
|
let static_var_name = syn::Ident::new(
|
||||||
|
&format!("__ktest_{}", test_name),
|
||||||
|
test_name.span(),
|
||||||
|
);
|
||||||
|
let out = quote! {
|
||||||
|
// #[cfg(feature = "ktest")]
|
||||||
|
#input
|
||||||
|
|
||||||
|
// #[cfg(feature = "ktest")]
|
||||||
|
#[unsafe(link_section = ".note.ktest")]
|
||||||
|
#[used]
|
||||||
|
pub static #static_var_name: fn() = #test_name;
|
||||||
|
};
|
||||||
|
|
||||||
|
TokenStream::from(out)
|
||||||
|
}
|
|
@ -38,8 +38,16 @@ SECTIONS
|
||||||
|
|
||||||
.data : {
|
.data : {
|
||||||
*(.data .data.*)
|
*(.data .data.*)
|
||||||
|
*(.got .got.*)
|
||||||
} :data
|
} :data
|
||||||
|
|
||||||
|
/* Add the .ktest section for test functions */
|
||||||
|
.note.ktest : {
|
||||||
|
__ktest_start = .; /* Mark the beginning of the section */
|
||||||
|
*(.note.ktest) /* Include all items in the .ktest section */
|
||||||
|
__ktest_end = .; /* Mark the end of the section */
|
||||||
|
}
|
||||||
|
|
||||||
.bss : {
|
.bss : {
|
||||||
*(COMMON)
|
*(COMMON)
|
||||||
*(.bss .bss.*)
|
*(.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,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
});
|
||||||
|
|
|
@ -11,7 +11,9 @@ static mut LAPIC: LocalApic = unsafe { MaybeUninit::zeroed().assume_init() };
|
||||||
static mut IDT: InterruptDescriptorTable = unsafe { MaybeUninit::zeroed().assume_init() };
|
static mut IDT: InterruptDescriptorTable = unsafe { MaybeUninit::zeroed().assume_init() };
|
||||||
|
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
enum Interrupt {
|
#[derive(Debug, Eq, Hash, PartialEq)]
|
||||||
|
|
||||||
|
pub enum Interrupt {
|
||||||
Timer = 32,
|
Timer = 32,
|
||||||
ApicErr = u8::MAX - 1,
|
ApicErr = u8::MAX - 1,
|
||||||
Spurious = u8::MAX,
|
Spurious = u8::MAX,
|
||||||
|
@ -60,17 +62,49 @@ extern "x86-interrupt" fn page_fault(
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "x86-interrupt" fn timer(_isf: InterruptStackFrame) {
|
extern "x86-interrupt" fn timer(_isf: InterruptStackFrame) {
|
||||||
|
// interrupt(Interrupt::Timer);
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
LAPIC.end_of_interrupt();
|
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) {
|
||||||
|
interrupt(Interrupt::Spurious);
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
LAPIC.end_of_interrupt();
|
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 {
|
||||||
|
@ -48,7 +47,7 @@ pub fn init(device_tree: &mut DeviceTree) {
|
||||||
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("bus", bus);
|
pci_info.set_attribute("bus", bus);
|
||||||
pci_info.set_attribute("class", device_info.full_class.to_string());
|
pci_info.set_attribute("class", device_info.full_class);
|
||||||
dev.set_child(pci_info);
|
dev.set_child(pci_info);
|
||||||
devices.push((dev_type, dev));
|
devices.push((dev_type, dev));
|
||||||
}
|
}
|
||||||
|
@ -70,7 +69,7 @@ pub fn check_device(bus: u8, device: u8) -> Option<PciDeviceInfo> {
|
||||||
}
|
}
|
||||||
|
|
||||||
let (reg2, addr) = unsafe { pci_config_read_2(bus, device, 0, 0x8) };
|
let (reg2, addr) = unsafe { pci_config_read_2(bus, device, 0, 0x8) };
|
||||||
log::info!("pci device-({}) addr {} is {}", device, addr, reg2);
|
log::debug!("pci device-({}) addr {} is {}", device, addr, reg2);
|
||||||
let class = ((reg2 >> 16) & 0x0000_FFFF) as u16;
|
let 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);
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -1,21 +1,40 @@
|
||||||
//! Environment call handling routines
|
//! Environment call handling routines
|
||||||
|
|
||||||
use crate::holeybytes::kernel_services::{
|
use {alloc::boxed::Box, core::cell::LazyCell, hbvm::mem::Address};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
holeybytes::{
|
||||||
|
kernel_services::{
|
||||||
block_read, dt_msg_handler::dt_msg_handler, logging_service::log_msg_handler,
|
block_read, dt_msg_handler::dt_msg_handler, logging_service::log_msg_handler,
|
||||||
service_definition_service::sds_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>();
|
||||||
// log::info!("eca called :pensive:");
|
|
||||||
// debug!("Ecall number {:?}", ecall_number);
|
|
||||||
//info!("Register dump: {:?}", vm.registers);
|
|
||||||
|
|
||||||
match ecall_number {
|
match ecall_number {
|
||||||
0 => {
|
0 => {
|
||||||
|
@ -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,25 +96,15 @@ 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 => unsafe {
|
0 => unsafe {
|
||||||
let size = msg_vec[1];
|
let size = msg_vec[1];
|
||||||
let addr = u16::from_le_bytes(msg_vec[2..4].try_into().unwrap());
|
let addr =
|
||||||
|
u16::from_le_bytes(msg_vec[2..4].try_into().unwrap_unchecked());
|
||||||
let value = match size {
|
let value = match size {
|
||||||
0 => x86_in::<u8>(addr) as u64,
|
0 => x86_in::<u8>(addr) as u64,
|
||||||
1 => x86_in::<u16>(addr) as u64,
|
1 => x86_in::<u16>(addr) as u64,
|
||||||
|
@ -111,7 +116,8 @@ pub fn handler(vm: &mut Vm) {
|
||||||
},
|
},
|
||||||
1 => unsafe {
|
1 => unsafe {
|
||||||
let size = msg_vec[1];
|
let size = msg_vec[1];
|
||||||
let addr = u16::from_le_bytes(msg_vec[2..4].try_into().unwrap());
|
let addr =
|
||||||
|
u16::from_le_bytes(msg_vec[2..4].try_into().unwrap_unchecked());
|
||||||
// info!("Setting address {}", addr);
|
// info!("Setting address {}", addr);
|
||||||
|
|
||||||
match size {
|
match size {
|
||||||
|
@ -134,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);
|
||||||
|
@ -205,13 +238,7 @@ 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()
|
|
||||||
}
|
|
||||||
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);
|
// info!("Read {:?} from Port {:?}", x, r2);
|
||||||
vm.registers[3] = x
|
vm.registers[3] = x
|
||||||
}
|
}
|
||||||
|
@ -227,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,15 +9,8 @@ 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();
|
|
||||||
|
|
||||||
let file_name = "None";
|
|
||||||
let line_number = 0;
|
|
||||||
|
|
||||||
match core::str::from_utf8(&msg_vec[..msg_vec.len()]) {
|
|
||||||
Ok(strr) => {
|
|
||||||
use log::Level::*;
|
use log::Level::*;
|
||||||
let log_level = match log_level {
|
let log_level = match msg_vec[0] {
|
||||||
0 | 48 => Error,
|
0 | 48 => Error,
|
||||||
1 | 49 => Warn,
|
1 | 49 => Warn,
|
||||||
2 | 50 => Info,
|
2 | 50 => Info,
|
||||||
|
@ -27,7 +20,19 @@ pub fn log_msg_handler(_vm: &mut Vm, mem_addr: u64, length: usize) -> Result<(),
|
||||||
return Err(LogError::InvalidLogFormat);
|
return Err(LogError::InvalidLogFormat);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
if log_level > log::max_level() {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
let strptr = u64::from_le_bytes(msg_vec[1..9].try_into().unwrap());
|
||||||
|
let strlen = u64::from_le_bytes(msg_vec[9..17].try_into().unwrap()) as usize;
|
||||||
|
|
||||||
|
let str = block_read(strptr, strlen);
|
||||||
|
|
||||||
|
let file_name = "None";
|
||||||
|
let line_number = 0;
|
||||||
|
|
||||||
|
match core::str::from_utf8(&str) {
|
||||||
|
Ok(strr) => {
|
||||||
log::logger().log(
|
log::logger().log(
|
||||||
&Record::builder()
|
&Record::builder()
|
||||||
.args(format_args!("{}", strr))
|
.args(format_args!("{}", strr))
|
||||||
|
|
|
@ -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(Layout::from_size_align_unchecked(4096, 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(
|
||||||
|
|
||||||
let ptr = unsafe {
|
|
||||||
alloc(Layout::from_size_align_unchecked(
|
|
||||||
page_count as usize * 4096,
|
page_count as usize * 4096,
|
||||||
4096,
|
8,
|
||||||
))
|
));
|
||||||
};
|
|
||||||
|
log::debug!("Allocating {} pages @ {:x}", page_count, ptr as u64);
|
||||||
|
|
||||||
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, 4096),
|
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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,5 +1,5 @@
|
||||||
mod ecah;
|
mod ecah;
|
||||||
mod kernel_services;
|
pub mod kernel_services;
|
||||||
mod mem;
|
mod mem;
|
||||||
|
|
||||||
use {
|
use {
|
||||||
|
@ -97,7 +97,7 @@ 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)]
|
||||||
|
|
|
@ -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,7 +8,10 @@ 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},
|
||||||
|
@ -19,6 +22,15 @@ use {
|
||||||
pub fn kmain(_cmdline: &str, boot_modules: BootModules) -> ! {
|
pub fn kmain(_cmdline: &str, boot_modules: BootModules) -> ! {
|
||||||
debug!("Entered kmain");
|
debug!("Entered kmain");
|
||||||
|
|
||||||
|
#[cfg(feature = "ktest")]
|
||||||
|
{
|
||||||
|
use crate::ktest;
|
||||||
|
debug!("TESTING");
|
||||||
|
ktest::test_main();
|
||||||
|
|
||||||
|
loop {}
|
||||||
|
}
|
||||||
|
|
||||||
// let kcmd = build_cmd("Kernel Command Line", cmdline);
|
// let kcmd = build_cmd("Kernel Command Line", cmdline);
|
||||||
// trace!("Cmdline: {kcmd:?}");
|
// trace!("Cmdline: {kcmd:?}");
|
||||||
|
|
||||||
|
@ -50,7 +62,6 @@ 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");
|
||||||
|
|
||||||
|
@ -58,21 +69,33 @@ pub fn kmain(_cmdline: &str, boot_modules: BootModules) -> ! {
|
||||||
disp.set_attribute("height", fb1.height);
|
disp.set_attribute("height", fb1.height);
|
||||||
disp.set_attribute("bpp", 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]);
|
||||||
}
|
}
|
||||||
debug!("Graphics initialised");
|
debug!("Graphics initialised");
|
||||||
debug!(
|
debug!(
|
||||||
"Graphics front ptr {:?}",
|
"Graphics front ptr {:?}",
|
||||||
fb1.address.as_ptr().unwrap() as *const u8
|
fb1.address.as_ptr().unwrap() as *const u8
|
||||||
);
|
);
|
||||||
|
log::info!("Started AbleOS");
|
||||||
|
|
||||||
let mut executor = crate::task::Executor::new(256);
|
|
||||||
unsafe {
|
unsafe {
|
||||||
|
let executor = LazyCell::<Executor>::force_mut(&mut EXECUTOR);
|
||||||
for module in boot_modules.iter() {
|
for module in boot_modules.iter() {
|
||||||
let cmd = module.cmd.trim_matches('"');
|
let cmd = module.cmd.trim_matches('"');
|
||||||
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);
|
||||||
|
|
||||||
// decode AbleOS Executable format
|
// decode AbleOS Executable format
|
||||||
let header = &module.bytes[0..46];
|
let header = &module.bytes[0..46];
|
||||||
|
@ -93,27 +116,30 @@ pub fn kmain(_cmdline: &str, boot_modules: BootModules) -> ! {
|
||||||
let code_length = u64::from_le_bytes(header[7..15].try_into().unwrap());
|
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 data_length = u64::from_le_bytes(header[15..23].try_into().unwrap());
|
||||||
let end = (code_length + data_length) as usize;
|
let end = (code_length + data_length) as usize;
|
||||||
log::info!("{code_length} + {data_length} = {end}");
|
log::debug!("{code_length} + {data_length} = {end}");
|
||||||
|
|
||||||
let mut thr = ExecThread::new(&module.bytes[offset..end], Address::new(0));
|
let mut thr = ExecThread::new(&module.bytes[offset..end], Address::new(0));
|
||||||
if cmd_len > 0 {
|
if cmd_len > 0 {
|
||||||
thr.set_arguments(cmd.as_ptr() as u64, cmd_len);
|
thr.set_arguments(cmd.as_ptr() as u64, cmd_len);
|
||||||
}
|
}
|
||||||
executor.spawn(async move {
|
executor.spawn(Box::pin(async move {
|
||||||
if let Err(e) = thr.await {
|
if let Err(e) = thr.await {
|
||||||
log::error!("{e:?}");
|
log::error!("{e:?}");
|
||||||
}
|
}
|
||||||
})
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
debug!("Random number: {}", hardware_random_u64());
|
debug!("Random number: {}", hardware_random_u64());
|
||||||
|
|
||||||
executor.run();
|
executor.run();
|
||||||
};
|
};
|
||||||
|
|
||||||
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)
|
||||||
|
@ -131,10 +157,3 @@ pub static IPC_BUFFERS: Lazy<Mutex<IpcBuffers>> = Lazy::new(|| {
|
||||||
|
|
||||||
Mutex::new(bufs)
|
Mutex::new(bufs)
|
||||||
});
|
});
|
||||||
|
|
||||||
#[test_case]
|
|
||||||
fn trivial_assertion() {
|
|
||||||
trace!("trivial assertion... ");
|
|
||||||
assert_eq!(1, 1);
|
|
||||||
info!("[ok]");
|
|
||||||
}
|
|
||||||
|
|
38
kernel/src/ktest.rs
Normal file
38
kernel/src/ktest.rs
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
pub use ktest_macro::ktest;
|
||||||
|
use log::debug;
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
static __ktest_start: fn();
|
||||||
|
static __ktest_end: fn();
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Get test_fn linker name (may require no_mangle in macro)
|
||||||
|
// More info on tests (run the rest even if panic)
|
||||||
|
// Implement ktest for arm and riscv (Later problems, see below)
|
||||||
|
// Allow for arch specific tests (Leave for now)
|
||||||
|
// Allow for ktest test name attr
|
||||||
|
// Usefull message at the end of testing
|
||||||
|
pub fn test_main() {
|
||||||
|
unsafe {
|
||||||
|
let mut current_test = &__ktest_start as *const fn();
|
||||||
|
let mut current = 1;
|
||||||
|
let test_end = &__ktest_end as *const fn();
|
||||||
|
|
||||||
|
while current_test < test_end {
|
||||||
|
let test_fn = *current_test;
|
||||||
|
|
||||||
|
debug!("Running test {}", current);
|
||||||
|
|
||||||
|
test_fn();
|
||||||
|
debug!("Test {} passed", current);
|
||||||
|
|
||||||
|
current_test = current_test.add(1);
|
||||||
|
current += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[ktest]
|
||||||
|
pub fn trivial_assertion() {
|
||||||
|
assert_eq!(1, 1);
|
||||||
|
}
|
|
@ -2,19 +2,19 @@
|
||||||
//! 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]
|
||||||
|
#![no_main]
|
||||||
#![feature(
|
#![feature(
|
||||||
|
slice_split_once,
|
||||||
exclusive_wrapper,
|
exclusive_wrapper,
|
||||||
new_uninit,
|
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,
|
|
||||||
naked_functions,
|
naked_functions,
|
||||||
pointer_is_aligned_to
|
pointer_is_aligned_to,
|
||||||
)]
|
)]
|
||||||
#![test_runner(crate::test_runner)]
|
#![allow(dead_code, internal_features, static_mut_refs)]
|
||||||
#![cfg_attr(not(debug_assertions), allow(unused, deprecated))]
|
|
||||||
#![allow(dead_code)]
|
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
|
|
||||||
mod allocator;
|
mod allocator;
|
||||||
|
@ -32,6 +32,10 @@ mod memory;
|
||||||
mod task;
|
mod task;
|
||||||
mod utils;
|
mod utils;
|
||||||
|
|
||||||
|
// #[cfg(feature = "tests")]
|
||||||
|
mod ktest;
|
||||||
|
|
||||||
|
use alloc::string::ToString;
|
||||||
use versioning::Version;
|
use versioning::Version;
|
||||||
|
|
||||||
/// Kernel's version
|
/// Kernel's version
|
||||||
|
@ -55,15 +59,7 @@ fn panic(info: &core::panic::PanicInfo) -> ! {
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
let msg = info.message();
|
let msg = info.message().to_string().replace("\n", "\r\n");
|
||||||
let _ = crate::arch::log(format_args!("{msg}\r\n"));
|
let _ = crate::arch::log(format_args!("{msg}\r\n"));
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
fn test_runner(tests: &[&dyn Fn()]) {
|
|
||||||
println!("Running {} tests", tests.len());
|
|
||||||
for test in tests {
|
|
||||||
test();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -36,7 +36,19 @@ 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
|
||||||
|
.module_path()
|
||||||
|
.unwrap_or_default()
|
||||||
|
.rsplit_once(':')
|
||||||
|
.unwrap_or_default()
|
||||||
|
.1;
|
||||||
|
if module == "" {
|
||||||
|
crate::arch::log(format_args!(
|
||||||
|
"\x1b[38;5;{lvl_color}m{lvl}\x1b[0m: {}\r\n",
|
||||||
|
record.args(),
|
||||||
|
))
|
||||||
|
.expect("write to serial console");
|
||||||
|
} else {
|
||||||
let line = record.line().unwrap_or_default();
|
let line = record.line().unwrap_or_default();
|
||||||
crate::arch::log(format_args!(
|
crate::arch::log(format_args!(
|
||||||
"\x1b[38;5;{lvl_color}m{lvl}\x1b[0m [{module}:{line}]: {}\r\n",
|
"\x1b[38;5;{lvl_color}m{lvl}\x1b[0m [{module}:{line}]: {}\r\n",
|
||||||
|
@ -44,6 +56,7 @@ impl log::Log for Logger {
|
||||||
))
|
))
|
||||||
.expect("write to serial console");
|
.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,16 +83,16 @@ 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,
|
||||||
|
|
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",
|
|
||||||
"add_assign",
|
|
||||||
"constructor",
|
|
||||||
"display",
|
"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,11 +19,15 @@ 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;
|
||||||
let mut debuginfo = false;
|
let mut debuginfo = false;
|
||||||
let mut target = Target::X86_64;
|
let mut target = Target::X86_64;
|
||||||
|
let mut tests = false;
|
||||||
for arg in args {
|
for arg in args {
|
||||||
if arg == "-r" || arg == "--release" {
|
if arg == "-r" || arg == "--release" {
|
||||||
release = true;
|
release = true;
|
||||||
|
@ -35,17 +37,45 @@ 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 if arg == "--ktest" {
|
||||||
|
tests = true;
|
||||||
} else {
|
} else {
|
||||||
return Err(report!(Error::InvalidSubCom));
|
return Err(report!(Error::InvalidSubCom));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
build(release, target, debuginfo).change_context(Error::Build)
|
build(release, target, debuginfo, tests).change_context(Error::Build)
|
||||||
}
|
}
|
||||||
|
// Some("test" | "t") => {
|
||||||
|
// let mut release = false;
|
||||||
|
// let mut debuginfo = false;
|
||||||
|
// let mut target = Target::X86_64;
|
||||||
|
// for arg in args {
|
||||||
|
// if arg == "-r" || arg == "--release" {
|
||||||
|
// release = true;
|
||||||
|
// } else if arg == "-d" || arg == "--debuginfo" {
|
||||||
|
// debuginfo = true;
|
||||||
|
// } else if arg == "rv64" || arg == "riscv64" || arg == "riscv64-virt" {
|
||||||
|
// target = Target::Riscv64Virt;
|
||||||
|
// } else if arg == "arm64" || arg == "aarch64" || arg == "aarch64-virt" {
|
||||||
|
// target = Target::Aarch64;
|
||||||
|
// } else if arg == "avx2" {
|
||||||
|
// target = Target::X86_64Avx2;
|
||||||
|
// } else {
|
||||||
|
// return Err(report!(Error::InvalidSubCom));
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// test(release, target, debuginfo).change_context(Error::Build)
|
||||||
|
// }
|
||||||
Some("run" | "r") => {
|
Some("run" | "r") => {
|
||||||
let mut release = false;
|
let mut release = false;
|
||||||
let mut debuginfo = false;
|
let mut debuginfo = false;
|
||||||
let mut target = Target::X86_64;
|
let mut target = Target::X86_64;
|
||||||
|
let mut tests = false;
|
||||||
|
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 +85,19 @@ 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 if arg == "--ktest" {
|
||||||
|
tests = true;
|
||||||
} else {
|
} else {
|
||||||
return Err(report!(Error::InvalidSubCom));
|
return Err(report!(Error::InvalidSubCom));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
build(release, target, debuginfo)?;
|
build(release, target, debuginfo, tests)?;
|
||||||
run(release, target)
|
run(release, target, do_accel)
|
||||||
}
|
}
|
||||||
Some("help" | "h") => {
|
Some("help" | "h") => {
|
||||||
println!(concat!(
|
println!(concat!(
|
||||||
|
@ -71,8 +107,11 @@ 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",
|
||||||
|
" --ktest: Enables tests via ktest\n",
|
||||||
|
"[ rv64 / riscv64 / riscv64-virt / aarch64 / arm64 / aarch64-virt / avx2 ]: sets target"
|
||||||
),);
|
),);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -195,7 +234,12 @@ 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();
|
||||||
|
let mut out = Vec::new();
|
||||||
|
|
||||||
|
modules
|
||||||
|
.into_iter()
|
||||||
|
.map(|(_, value)| -> Result<(), io::Error> {
|
||||||
if value.is_table() {
|
if value.is_table() {
|
||||||
let path = get_path_without_boot_prefix(
|
let path = get_path_without_boot_prefix(
|
||||||
value.get("path").expect("You must have `path` as a value"),
|
value.get("path").expect("You must have `path` as a value"),
|
||||||
|
@ -207,9 +251,26 @@ TERM_BACKDROP={}
|
||||||
let p = Package::load_from_file(
|
let p = Package::load_from_file(
|
||||||
format!("sysdata/programs/{}/meta.toml", path).to_owned(),
|
format!("sysdata/programs/{}/meta.toml", path).to_owned(),
|
||||||
);
|
);
|
||||||
p.build();
|
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");
|
||||||
|
@ -278,7 +339,7 @@ fn copy_file_to_img(fpath: &str, fs: &FileSystem<File>) {
|
||||||
.expect("Copy failed");
|
.expect("Copy failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build(release: bool, target: Target, debuginfo: bool) -> Result<(), Error> {
|
fn build(release: bool, target: Target, debuginfo: bool, tests: bool) -> Result<(), Error> {
|
||||||
let fs = get_fs().change_context(Error::Io)?;
|
let fs = get_fs().change_context(Error::Io)?;
|
||||||
let mut com = Command::new("cargo");
|
let mut com = Command::new("cargo");
|
||||||
com.current_dir("kernel");
|
com.current_dir("kernel");
|
||||||
|
@ -290,12 +351,19 @@ fn build(release: bool, target: Target, debuginfo: bool) -> Result<(), Error> {
|
||||||
com.env("RUSTFLAGS", "-Cdebug-assertions=true");
|
com.env("RUSTFLAGS", "-Cdebug-assertions=true");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if tests {
|
||||||
|
com.args(["--features", "ktest"]);
|
||||||
|
}
|
||||||
|
|
||||||
if target == Target::Riscv64Virt {
|
if target == Target::Riscv64Virt {
|
||||||
com.args(["--target", "targets/riscv64-virt-ableos.json"]);
|
com.args(["--target", "targets/riscv64-virt-ableos.json"]);
|
||||||
}
|
}
|
||||||
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 +377,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 +403,67 @@ 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",
|
||||||
"-device", "vmware-svga",
|
"-device", "vmware-svga",
|
||||||
|
// "-serial", "stdio",
|
||||||
"-m", "2G",
|
"-m", "2G",
|
||||||
"-smp", "1",
|
"-smp", "1",
|
||||||
"-machine", "accel=kvm",
|
"-parallel", "none",
|
||||||
"-cpu", "host",
|
"-monitor", "none",
|
||||||
|
"-machine", accel,
|
||||||
|
"-cpu", "max",
|
||||||
"-device", "isa-debug-exit,iobase=0xf4,iosize=0x04",
|
"-device", "isa-debug-exit,iobase=0xf4,iosize=0x04",
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
@ -371,7 +485,7 @@ fn run(release: bool, target: Target) -> Result<(), Error> {
|
||||||
#[rustfmt::skip]
|
#[rustfmt::skip]
|
||||||
com.args([
|
com.args([
|
||||||
"-M", "virt",
|
"-M", "virt",
|
||||||
"-cpu", "neoverse-n2",
|
"-cpu", "max",
|
||||||
"-device", "ramfb",
|
"-device", "ramfb",
|
||||||
"-device", "qemu-xhci",
|
"-device", "qemu-xhci",
|
||||||
"-device", "usb-kbd",
|
"-device", "usb-kbd",
|
||||||
|
@ -392,9 +506,10 @@ 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",
|
||||||
),
|
),
|
||||||
|
@ -416,12 +531,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)?;
|
||||||
|
|
||||||
|
@ -443,6 +558,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-2024-11-20"
|
||||||
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("../../stn/src/lib.hb");
|
|
||||||
.{string, memory, buffer} := stn
|
|
||||||
|
|
||||||
dt_get := fn(query: ^u8): int {
|
|
||||||
message_length := string.length(query)
|
|
||||||
|
|
||||||
return @eca(3, 5, query, message_length)
|
|
||||||
}
|
|
4
sysdata/libraries/horizon_api/examples/horizontal.lui
Normal file
4
sysdata/libraries/horizon_api/examples/horizontal.lui
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
(horizontal
|
||||||
|
spacing : 10
|
||||||
|
(label "hi")
|
||||||
|
(label "goodbye"))
|
1
sysdata/libraries/horizon_api/examples/label.lui
Normal file
1
sysdata/libraries/horizon_api/examples/label.lui
Normal file
|
@ -0,0 +1 @@
|
||||||
|
(label "hello")
|
3
sysdata/libraries/horizon_api/examples/vertical.lui
Normal file
3
sysdata/libraries/horizon_api/examples/vertical.lui
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
(vertical
|
||||||
|
(label "hello")
|
||||||
|
(label "hello" color:red))
|
|
@ -1,25 +1,49 @@
|
||||||
stn := @use("../../stn/src/lib.hb");
|
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")
|
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
|
return @as(^render.Surface, idk)
|
||||||
} else {
|
} else {
|
||||||
msg := "\{01}\0"
|
// ! bad able, stop using string messages :ragey:
|
||||||
msg_length := 2
|
// msg := "\{01}\0"
|
||||||
return @eca(3, windowing_system_buffer, msg, msg_length)
|
// msg_length := 2
|
||||||
|
|
||||||
|
// @as(void, @eca(3, windowing_system_buffer, msg, msg_length))
|
||||||
|
|
||||||
|
x := 0
|
||||||
|
loop if x > 1000 break else x += 1
|
||||||
|
|
||||||
|
ret := buffer.recv([u8; 4096], windowing_system_buffer, mem_buf)
|
||||||
|
if ret == null {
|
||||||
|
log.info("No messages\0")
|
||||||
|
}
|
||||||
|
|
||||||
|
if *mem_buf == 0 {
|
||||||
|
log.info("No messages\0")
|
||||||
|
}
|
||||||
|
|
||||||
|
return @as(^render.Surface, idk)
|
||||||
}
|
}
|
||||||
}
|
}
|
47
sysdata/libraries/horizon_api/src/ui.hb
Normal file
47
sysdata/libraries/horizon_api/src/ui.hb
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
stn := @use("../../../libraries/stn/src/lib.hb");
|
||||||
|
.{string, log} := stn;
|
||||||
|
.{Vec2} := stn.math
|
||||||
|
|
||||||
|
render := @use("../../../libraries/render/src/lib.hb");
|
||||||
|
.{Surface} := render;
|
||||||
|
.{Font} := render.text
|
||||||
|
|
||||||
|
UI := struct {raw: ^u8, raw_length: uint, is_dirty: bool, surface: Surface, // Each child has their WidgetType as their first byte
|
||||||
|
// children: ^^u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
render_ui := fn(surface: Surface, ui: UI): void {
|
||||||
|
if ui.is_dirty {
|
||||||
|
render.clear(ui.surface, render.black)
|
||||||
|
ui.is_dirty = false
|
||||||
|
}
|
||||||
|
pos := Vec2(uint).(0, 0)
|
||||||
|
render.put_surface(surface, ui.surface, pos, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
sexpr_parser := fn(sexpr: ^u8): UI {
|
||||||
|
cursor := sexpr
|
||||||
|
paren_balance := 0
|
||||||
|
loop {
|
||||||
|
if *cursor == 0 {
|
||||||
|
if paren_balance != 0 {
|
||||||
|
log.error("Unbalanced Parens\0")
|
||||||
|
}
|
||||||
|
break
|
||||||
|
} else if *cursor == 40 {
|
||||||
|
log.info("Open paren\0")
|
||||||
|
paren_balance += 1
|
||||||
|
} else if *cursor == 41 {
|
||||||
|
log.info("Closed paren\0")
|
||||||
|
paren_balance -= 1
|
||||||
|
}
|
||||||
|
|
||||||
|
cursor += 1
|
||||||
|
}
|
||||||
|
|
||||||
|
length := string.length(sexpr)
|
||||||
|
|
||||||
|
ui_surface := render.new_surface(100, 100)
|
||||||
|
|
||||||
|
return UI.(sexpr, length, true, ui_surface)
|
||||||
|
}
|
13
sysdata/libraries/horizon_api/src/widgets/image.hb
Normal file
13
sysdata/libraries/horizon_api/src/widgets/image.hb
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
render := @use("../../../../libraries/render/src/lib.hb");
|
||||||
|
.{Surface} := render
|
||||||
|
|
||||||
|
Image := struct {
|
||||||
|
magic: uint,
|
||||||
|
is_dirty: bool,
|
||||||
|
surface: Surface,
|
||||||
|
}
|
||||||
|
|
||||||
|
image_from_surface := fn(surface: Surface): Image {
|
||||||
|
img := Image.(4, true, surface)
|
||||||
|
return img
|
||||||
|
}
|
46
sysdata/libraries/horizon_api/src/widgets/label.hb
Normal file
46
sysdata/libraries/horizon_api/src/widgets/label.hb
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
stn := @use("../../../../libraries/stn/src/lib.hb");
|
||||||
|
.{string, log} := stn;
|
||||||
|
.{Vec2} := stn.math
|
||||||
|
|
||||||
|
render := @use("../../../../libraries/render/src/lib.hb");
|
||||||
|
.{Surface, Color} := render;
|
||||||
|
.{Font} := render.text
|
||||||
|
|
||||||
|
Label := struct {
|
||||||
|
magic: uint,
|
||||||
|
is_dirty: bool,
|
||||||
|
surface: Surface,
|
||||||
|
text: ^u8,
|
||||||
|
text_length: uint,
|
||||||
|
bg: Color,
|
||||||
|
fg: Color,
|
||||||
|
}
|
||||||
|
|
||||||
|
set_label_text := fn(label: Label, text: ^u8): void {
|
||||||
|
text_length := string.length(text)
|
||||||
|
|
||||||
|
label.is_dirty = true
|
||||||
|
label.text = text
|
||||||
|
label.text_length = text_length
|
||||||
|
}
|
||||||
|
|
||||||
|
render_label_to_surface := fn(surface: Surface, label: Label, font: Font, pos: Vec2(uint)): void {
|
||||||
|
if label.is_dirty {
|
||||||
|
render.clear(label.surface, label.bg)
|
||||||
|
render.put_text(label.surface, font, .(0, 0), label.fg, label.text)
|
||||||
|
}
|
||||||
|
render.put_surface(surface, label.surface, pos, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
new_label := fn(text: ^u8): Label {
|
||||||
|
text_surface := render.new_surface(1024, 20)
|
||||||
|
text_length := string.length(text)
|
||||||
|
label := Label.(3, true, text_surface, text, text_length, render.black, render.white)
|
||||||
|
return label
|
||||||
|
}
|
||||||
|
|
||||||
|
$set_color := fn(label: Label, bg: Color, fg: Color): void {
|
||||||
|
label.bg = bg
|
||||||
|
label.fg = fg
|
||||||
|
label.is_dirty = true
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
NoWidget := 0
|
||||||
|
|
||||||
|
VerticalWidgetType := 1
|
||||||
|
HorizontalWidgetType := 2
|
||||||
|
|
||||||
|
LabelWidgetType := 3
|
||||||
|
ImageWidgetType := 4
|
36
sysdata/libraries/horizon_api/src/widgets/widgets.hb
Normal file
36
sysdata/libraries/horizon_api/src/widgets/widgets.hb
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
// Widget types
|
||||||
|
|
||||||
|
// End types
|
||||||
|
stn := @use("../../../../libraries/stn/src/lib.hb");
|
||||||
|
.{string, log} := stn;
|
||||||
|
.{Vec2} := stn.math
|
||||||
|
|
||||||
|
render := @use("../../../../libraries/render/src/lib.hb");
|
||||||
|
.{Surface} := render;
|
||||||
|
.{Font} := render.text
|
||||||
|
|
||||||
|
widget_types := @use("widget_types.hb")
|
||||||
|
label := @use("label.hb")
|
||||||
|
image := @use("image.hb")
|
||||||
|
|
||||||
|
Size := struct {
|
||||||
|
min_width: int,
|
||||||
|
max_width: int,
|
||||||
|
min_height: int,
|
||||||
|
max_height: int,
|
||||||
|
}
|
||||||
|
|
||||||
|
Vertical := packed struct {
|
||||||
|
magic: uint,
|
||||||
|
// array of children, idk
|
||||||
|
// use a vec or linked list or whatever
|
||||||
|
|
||||||
|
children: ^^u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
Horizontal := packed struct {
|
||||||
|
magic: uint,
|
||||||
|
// array of children, idk
|
||||||
|
// use a vec or linked list or whatever
|
||||||
|
children: ^^u8,
|
||||||
|
}
|
|
@ -7,7 +7,7 @@ ApplicationInfo := struct {
|
||||||
pNext: ^int,
|
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,
|
||||||
}
|
}
|
||||||
|
|
18
sysdata/libraries/intouch/src/events.hb
Normal file
18
sysdata/libraries/intouch/src/events.hb
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
keycodes := @use("keycodes.hb");
|
||||||
|
.{KeyCode} := keycodes
|
||||||
|
|
||||||
|
KeyEvent := packed struct {
|
||||||
|
up: bool,
|
||||||
|
just_triggered: bool,
|
||||||
|
key: KeyCode,
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseEvent := packed struct {
|
||||||
|
x_change: i8,
|
||||||
|
y_change: i8,
|
||||||
|
left: bool,
|
||||||
|
middle: bool,
|
||||||
|
right: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
GamepadEvent := struct {}
|
|
@ -1,67 +1,121 @@
|
||||||
|
/*
|
||||||
|
Originally I was modelling this after the following(1). I have since changed my mind.
|
||||||
|
I am now modelling it as I see fit. This is likely not the final version.
|
||||||
|
|
||||||
|
1) https://www.libsdl.org/release/SDL-1.2.15/include/SDL_keysym.h
|
||||||
|
*/
|
||||||
|
|
||||||
KeyCode := u32
|
KeyCode := u32
|
||||||
|
|
||||||
// https://www.libsdl.org/release/SDL-1.2.15/include/SDL_keysym.h
|
// Typically this is not a keycode you will ever recieve.
|
||||||
Backspace := KeyCode.(8)
|
None := KeyCode.(0)
|
||||||
Tab := KeyCode.(9)
|
|
||||||
Clear := KeyCode.(12)
|
|
||||||
Return := KeyCode.(13)
|
|
||||||
Pause := KeyCode.(19)
|
|
||||||
Escape := KeyCode.(27)
|
|
||||||
Space := KeyCode.(32)
|
|
||||||
|
|
||||||
A := KeyCode.(97)
|
Escape := KeyCode.(1)
|
||||||
/*
|
/* Alphabet keycodes */
|
||||||
ETC
|
|
||||||
*/
|
|
||||||
Z := KeyCode.(122)
|
|
||||||
|
|
||||||
Delete := KeyCode.(127)
|
A := KeyCode.(2)
|
||||||
|
B := KeyCode.(3)
|
||||||
|
C := KeyCode.(4)
|
||||||
|
D := KeyCode.(5)
|
||||||
|
E := KeyCode.(6)
|
||||||
|
F := KeyCode.(7)
|
||||||
|
G := KeyCode.(8)
|
||||||
|
H := KeyCode.(9)
|
||||||
|
I := KeyCode.(10)
|
||||||
|
J := KeyCode.(11)
|
||||||
|
K := KeyCode.(12)
|
||||||
|
L := KeyCode.(13)
|
||||||
|
M := KeyCode.(14)
|
||||||
|
N := KeyCode.(15)
|
||||||
|
O := KeyCode.(16)
|
||||||
|
P := KeyCode.(17)
|
||||||
|
Q := KeyCode.(18)
|
||||||
|
R := KeyCode.(19)
|
||||||
|
S := KeyCode.(20)
|
||||||
|
T := KeyCode.(21)
|
||||||
|
U := KeyCode.(22)
|
||||||
|
V := KeyCode.(23)
|
||||||
|
W := KeyCode.(24)
|
||||||
|
X := KeyCode.(25)
|
||||||
|
Y := KeyCode.(26)
|
||||||
|
Z := KeyCode.(27)
|
||||||
|
|
||||||
/*
|
/* Numeric keycodes*/
|
||||||
ETC
|
|
||||||
*/
|
|
||||||
|
|
||||||
KeypadNumber0 := KeyCode.(256)
|
Number0 := KeyCode.(28)
|
||||||
KeypadNumber1 := KeyCode.(257)
|
Number1 := KeyCode.(29)
|
||||||
KeypadNumber2 := KeyCode.(258)
|
Number2 := KeyCode.(30)
|
||||||
KeypadNumber3 := KeyCode.(259)
|
Number3 := KeyCode.(31)
|
||||||
KeypadNumber4 := KeyCode.(260)
|
Number4 := KeyCode.(32)
|
||||||
KeypadNumber5 := KeyCode.(261)
|
Number5 := KeyCode.(33)
|
||||||
KeypadNumber6 := KeyCode.(262)
|
Number6 := KeyCode.(34)
|
||||||
KeypadNumber7 := KeyCode.(263)
|
Number7 := KeyCode.(35)
|
||||||
KeypadNumber8 := KeyCode.(264)
|
Number8 := KeyCode.(36)
|
||||||
KeypadNumber9 := KeyCode.(265)
|
Number9 := KeyCode.(37)
|
||||||
|
|
||||||
KeypadPeriod := KeyCode.(266)
|
KeypadNumber0 := KeyCode.(38)
|
||||||
KeypadDivide := KeyCode.(267)
|
KeypadNumber1 := KeyCode.(39)
|
||||||
KeypadMultiply := KeyCode.(268)
|
KeypadNumber2 := KeyCode.(40)
|
||||||
KeypadMinus := KeyCode.(269)
|
KeypadNumber3 := KeyCode.(41)
|
||||||
KeypadPlus := KeyCode.(270)
|
KeypadNumber4 := KeyCode.(42)
|
||||||
KeypadEnter := KeyCode.(271)
|
KeypadNumber5 := KeyCode.(43)
|
||||||
KeypadEquals := KeyCode.(272)
|
KeypadNumber6 := KeyCode.(44)
|
||||||
|
KeypadNumber7 := KeyCode.(45)
|
||||||
|
KeypadNumber8 := KeyCode.(46)
|
||||||
|
KeypadNumber9 := KeyCode.(47)
|
||||||
|
|
||||||
NumLock := KeyCode.(300)
|
KeypadPeriod := KeyCode.(48)
|
||||||
CapsLock := KeyCode.(301)
|
KeypadDivide := KeyCode.(49)
|
||||||
ScrollLock := KeyCode.(302)
|
KeypadMultiply := KeyCode.(50)
|
||||||
|
KeypadMinus := KeyCode.(51)
|
||||||
|
KeypadPlus := KeyCode.(52)
|
||||||
|
KeypadEnter := KeyCode.(53)
|
||||||
|
KeypadEquals := KeyCode.(54)
|
||||||
|
|
||||||
RightShift := KeyCode.(303)
|
Delete := KeyCode.(55)
|
||||||
LeftShift := KeyCode.(304)
|
/* Locking Keys */
|
||||||
|
NumLock := KeyCode.(56)
|
||||||
RightControl := KeyCode.(305)
|
CapsLock := KeyCode.(57)
|
||||||
LeftControl := KeyCode.(306)
|
ScrollLock := KeyCode.(58)
|
||||||
RightAlt := KeyCode.(307)
|
|
||||||
LeftAlt := KeyCode.(308)
|
|
||||||
RightMeta := KeyCode.(309)
|
|
||||||
LeftMeta := KeyCode.(310)
|
|
||||||
|
|
||||||
/* Left "Windows" key */
|
|
||||||
LeftSuper := KeyCode.(311)
|
|
||||||
|
|
||||||
/* Right "Windows" key */
|
|
||||||
RightSuper := KeyCode.(312)
|
|
||||||
|
|
||||||
/* "Alt Gr" key */
|
/* "Alt Gr" key */
|
||||||
Mode := KeyCode.(313)
|
Mode := KeyCode.(59)
|
||||||
|
|
||||||
/* Multi-key compose key */
|
/* Multi-key compose key */
|
||||||
Compose := KeyCode.(314)
|
Compose := KeyCode.(60)
|
||||||
|
|
||||||
|
LeftAlt := KeyCode.(61)
|
||||||
|
LeftControl := KeyCode.(62)
|
||||||
|
LeftMeta := KeyCode.(63)
|
||||||
|
LeftShift := KeyCode.(64)
|
||||||
|
/* Left "Windows" key */
|
||||||
|
LeftSuper := KeyCode.(65)
|
||||||
|
|
||||||
|
RightAlt := KeyCode.(66)
|
||||||
|
RightControl := KeyCode.(67)
|
||||||
|
RightMeta := KeyCode.(68)
|
||||||
|
RightShift := KeyCode.(69)
|
||||||
|
/* Right "Windows" key */
|
||||||
|
RightSuper := KeyCode.(70)
|
||||||
|
|
||||||
|
/*
|
||||||
|
This block of any triggers on any press of any of the keys.
|
||||||
|
Typically this is the event to care about.
|
||||||
|
*/
|
||||||
|
AnyNumber0 := KeyCode.(71)
|
||||||
|
AnyNumber1 := KeyCode.(72)
|
||||||
|
AnyNumber2 := KeyCode.(73)
|
||||||
|
AnyNumber3 := KeyCode.(74)
|
||||||
|
AnyNumber4 := KeyCode.(75)
|
||||||
|
AnyNumber5 := KeyCode.(76)
|
||||||
|
AnyNumber6 := KeyCode.(77)
|
||||||
|
AnyNumber7 := KeyCode.(78)
|
||||||
|
AnyNumber8 := KeyCode.(79)
|
||||||
|
AnyNumber9 := KeyCode.(80)
|
||||||
|
|
||||||
|
AnyAlt := KeyCode.(81)
|
||||||
|
AnyControl := KeyCode.(82)
|
||||||
|
AnyMeta := KeyCode.(83)
|
||||||
|
AnyShift := KeyCode.(84)
|
||||||
|
/* Any "Windows" key */
|
||||||
|
AnySuper := KeyCode.(85)
|
|
@ -1,22 +1,36 @@
|
||||||
keycodes := @use("keycodes.hb");
|
stn := @use("../../stn/src/lib.hb");
|
||||||
.{KeyCode} := keycodes
|
.{log, buffer, memory} := stn
|
||||||
|
keycodes := @use("keycodes.hb")
|
||||||
|
|
||||||
MouseEvent := struct {
|
events := @use("events.hb");
|
||||||
x_change: u8,
|
.{KeyEvent, MouseEvent} := events
|
||||||
y_change: u8,
|
|
||||||
left: u8,
|
recieve_key_event := fn(): ?KeyEvent {
|
||||||
middle: u8,
|
kevent := KeyEvent.(false, false, 0)
|
||||||
right: u8,
|
|
||||||
|
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
|
||||||
}
|
}
|
||||||
|
|
||||||
KeyEvent := struct {
|
return null
|
||||||
// 0 if down
|
|
||||||
// 1 if up
|
|
||||||
up: u8,
|
|
||||||
// 0 if not just triggered
|
|
||||||
// 1 if just triggered
|
|
||||||
just_triggered: u8,
|
|
||||||
key: KeyCode,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
GamepadEvent := struct {}
|
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
|
||||||
|
}
|
27
sysdata/libraries/render/TODO.md
Normal file
27
sysdata/libraries/render/TODO.md
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
# Images
|
||||||
|
- Animation
|
||||||
|
|
||||||
|
# API
|
||||||
|
- Colour operations:
|
||||||
|
- Alpha Composite
|
||||||
|
- Invert
|
||||||
|
- Surface Operations:
|
||||||
|
- FlipH
|
||||||
|
- Resize
|
||||||
|
- Wrap the colour operations
|
||||||
|
- Tile
|
||||||
|
- Gradient overlay
|
||||||
|
- Draw operations:
|
||||||
|
- Curve raster algorithm
|
||||||
|
- VGA font fast blit
|
||||||
|
- Polygon
|
||||||
|
- Rounded rects
|
||||||
|
|
||||||
|
# Backend
|
||||||
|
- SVGA Driver
|
||||||
|
- Support whatever vulkan stuff able is cooking
|
||||||
|
|
||||||
|
# Bits and bobs on the table
|
||||||
|
- Funny 3D Renderer
|
||||||
|
- stn.memory.swap & kernel message
|
||||||
|
- Make memory.{copy, set} smart
|
49
sysdata/libraries/render/src/image/bmp.hb
Normal file
49
sysdata/libraries/render/src/image/bmp.hb
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
.{Color, Surface, new_surface, put_surface} := @use("../lib.hb");
|
||||||
|
.{log} := @use("../../../stn/src/lib.hb")
|
||||||
|
|
||||||
|
BitmapFileHeader := packed struct {
|
||||||
|
magic: u16,
|
||||||
|
size: u32,
|
||||||
|
reserved_1: u16,
|
||||||
|
reserved_2: u16,
|
||||||
|
offset: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
BitmapInfoHeader := packed struct {
|
||||||
|
size: u32,
|
||||||
|
width: i32,
|
||||||
|
height: i32,
|
||||||
|
planes: u16,
|
||||||
|
bits: u16,
|
||||||
|
compression: u32,
|
||||||
|
image_size: u32,
|
||||||
|
x_resolution: i32,
|
||||||
|
y_resolution: i32,
|
||||||
|
n_colours: u32,
|
||||||
|
important_colours: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
BitmapColorHeader := packed struct {
|
||||||
|
red_mask: u32,
|
||||||
|
green_mask: u32,
|
||||||
|
blue_mask: u32,
|
||||||
|
alpha_mask: u32,
|
||||||
|
color_space_type: u32,
|
||||||
|
unused: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
from := fn(bmp: ^u8): ?Surface {
|
||||||
|
file_header := @as(^BitmapFileHeader, @bitcast(bmp))
|
||||||
|
info_header := @as(^BitmapInfoHeader, @bitcast(bmp + @sizeof(BitmapFileHeader)))
|
||||||
|
|
||||||
|
if file_header.magic != 0x4D42 | info_header.width == 0 | info_header.height == 0 {
|
||||||
|
log.error("Invalid BMP image.\0")
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
lhs := Surface.(@bitcast(bmp + file_header.offset), info_header.width, info_header.height, info_header.width * info_header.height)
|
||||||
|
rhs := new_surface(info_header.width, info_header.height)
|
||||||
|
put_surface(rhs, lhs, .(0, 0), true)
|
||||||
|
|
||||||
|
return rhs
|
||||||
|
}
|
31
sysdata/libraries/render/src/image/lib.hb
Normal file
31
sysdata/libraries/render/src/image/lib.hb
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
.{log} := @use("../../../stn/src/lib.hb");
|
||||||
|
.{Surface} := @use("../lib.hb")
|
||||||
|
bmp := @use("bmp.hb")
|
||||||
|
qoi := @use("qoi.hb")
|
||||||
|
$BMP := 0x4D42
|
||||||
|
$QOI := 0x66696F71
|
||||||
|
|
||||||
|
get_format := fn(file: ^u8): ?uint {
|
||||||
|
if *@as(^u16, @bitcast(file)) == BMP {
|
||||||
|
return BMP
|
||||||
|
} else if *@as(^u32, @bitcast(file)) == QOI {
|
||||||
|
return QOI
|
||||||
|
} else {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
from := fn(file: ^u8): ?Surface {
|
||||||
|
format := get_format(file)
|
||||||
|
|
||||||
|
if format == null {
|
||||||
|
log.error("Could not detect image format.\0")
|
||||||
|
return null
|
||||||
|
} else if format == BMP {
|
||||||
|
return bmp.from(file)
|
||||||
|
} else if format == QOI {
|
||||||
|
return qoi.from(file)
|
||||||
|
}
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
101
sysdata/libraries/render/src/image/qoi.hb
Normal file
101
sysdata/libraries/render/src/image/qoi.hb
Normal file
|
@ -0,0 +1,101 @@
|
||||||
|
.{Color, Surface, new_surface} := @use("../lib.hb");
|
||||||
|
.{log} := @use("../../../stn/src/lib.hb")
|
||||||
|
|
||||||
|
/* source:
|
||||||
|
https://github.com/phoboslab/qoi/blob/master/qoi.h */
|
||||||
|
|
||||||
|
$QOI_SRGB := 0
|
||||||
|
$QOI_LINEAR := 1
|
||||||
|
$QOI_OP_INDEX := 0x0
|
||||||
|
$QOI_OP_DIFF := 0x40
|
||||||
|
$QOI_OP_LUMA := 0x80
|
||||||
|
$QOI_OP_RUN := 0xC0
|
||||||
|
$QOI_OP_RGB := 0xFE
|
||||||
|
$QOI_OP_RGBA := 0xFF
|
||||||
|
$QOI_MASK_2 := 0xC0
|
||||||
|
$QOI_COLOR_HASH := fn(c: Color): u8 {
|
||||||
|
return (c.r * 3 + c.g * 5 + c.b * 7 + c.a * 11) % 64
|
||||||
|
}
|
||||||
|
$QOI_MAGIC := 0x716F6966
|
||||||
|
$QOI_PIXELS_MAX := 400000000
|
||||||
|
|
||||||
|
QuiteOkayHeader := packed struct {
|
||||||
|
magic: u32,
|
||||||
|
width: u32,
|
||||||
|
height: u32,
|
||||||
|
channels: u8,
|
||||||
|
colorspace: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
be_to_le := fn(big: u32): u32 {
|
||||||
|
return big >> 24 | big >> 8 & 0xFF00 | big << 8 & 0xFF0000 | big << 24
|
||||||
|
}
|
||||||
|
|
||||||
|
from := fn(qoi: ^u8): ?Surface {
|
||||||
|
header := @as(^QuiteOkayHeader, @bitcast(qoi))
|
||||||
|
|
||||||
|
qoi += @sizeof(QuiteOkayHeader)
|
||||||
|
|
||||||
|
width := be_to_le(header.width)
|
||||||
|
height := be_to_le(header.height)
|
||||||
|
|
||||||
|
if be_to_le(header.magic) != QOI_MAGIC | width == 0 | height == 0 | header.channels < 3 | header.channels > 4 {
|
||||||
|
log.error("Invalid QOI image.\0")
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
surface := new_surface(width, height)
|
||||||
|
index := @as([Color; 64], idk)
|
||||||
|
|
||||||
|
run := 0
|
||||||
|
px := Color.(0, 0, 0, 255)
|
||||||
|
px_pos := 0
|
||||||
|
|
||||||
|
total_pixels := width * height
|
||||||
|
|
||||||
|
loop if px_pos >= total_pixels break else {
|
||||||
|
if run > 0 {
|
||||||
|
run -= 1
|
||||||
|
} else {
|
||||||
|
b1 := *qoi
|
||||||
|
qoi += 1
|
||||||
|
|
||||||
|
if b1 == QOI_OP_RGB {
|
||||||
|
px.r = *qoi
|
||||||
|
px.g = *(qoi + 1)
|
||||||
|
px.b = *(qoi + 2)
|
||||||
|
qoi += 3
|
||||||
|
} else if b1 == QOI_OP_RGBA {
|
||||||
|
px.r = *qoi
|
||||||
|
px.g = *(qoi + 1)
|
||||||
|
px.b = *(qoi + 2)
|
||||||
|
px.a = *(qoi + 3)
|
||||||
|
qoi += 4
|
||||||
|
} else if (b1 & QOI_MASK_2) == QOI_OP_INDEX {
|
||||||
|
px = index[b1 & 0x3F]
|
||||||
|
} else if (b1 & QOI_MASK_2) == QOI_OP_DIFF {
|
||||||
|
px.r = px.r + (b1 >> 4 & 0x3) - 2 & 0xFF
|
||||||
|
px.g = px.g + (b1 >> 2 & 0x3) - 2 & 0xFF
|
||||||
|
px.b = px.b + (b1 & 0x3) - 2 & 0xFF
|
||||||
|
} else if (b1 & QOI_MASK_2) == QOI_OP_LUMA {
|
||||||
|
b2 := *qoi
|
||||||
|
vg := (b1 & 0x3F) - 32
|
||||||
|
|
||||||
|
px.r = px.r + vg - 8 + (b2 >> 4 & 0xF) & 0xFF
|
||||||
|
px.g = px.g + vg & 0xFF
|
||||||
|
px.b = px.b + vg - 8 + (b2 & 0xF) & 0xFF
|
||||||
|
qoi += 1
|
||||||
|
} else if (b1 & QOI_MASK_2) == QOI_OP_RUN {
|
||||||
|
run = b1 & 0x3F
|
||||||
|
}
|
||||||
|
|
||||||
|
index[QOI_COLOR_HASH(px)] = px
|
||||||
|
};
|
||||||
|
|
||||||
|
*(surface.buf + px_pos) = px
|
||||||
|
|
||||||
|
px_pos += 1
|
||||||
|
}
|
||||||
|
|
||||||
|
return surface
|
||||||
|
}
|
|
@ -1,47 +1,57 @@
|
||||||
svga := @use("svga.hb")
|
|
||||||
software := @use("software.hb")
|
software := @use("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("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 start_idx > end_idx break else {
|
||||||
loop if remaining <= 0 break else {
|
*start_idx = color;
|
||||||
if remaining < 0xFF {
|
*right_start_idx = color
|
||||||
memory.request_page(remaining)
|
start_idx += surface.width
|
||||||
} else {
|
right_start_idx += surface.width
|
||||||
memory.request_page(0xFF)
|
|
||||||
}
|
|
||||||
remaining -= 0xFF
|
|
||||||
}
|
|
||||||
return @bitcast(ptr)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
clear := fn(color: Color): void {
|
memory.set(Color, &color, indexptr(surface, pos.x, pos.y), @bitcast(tr.x + 1))
|
||||||
cursor := ctx.buf
|
memory.set(Color, &color, indexptr(surface, pos.x, pos.y + tr.y), @bitcast(tr.x + 1))
|
||||||
boundary := cursor + 512
|
|
||||||
loop if cursor == boundary break else {
|
|
||||||
*cursor = color
|
|
||||||
cursor += 1
|
|
||||||
}
|
|
||||||
boundary += 512 * 7
|
|
||||||
loop if cursor == boundary break else {
|
|
||||||
*@as(^[Color; 512], @bitcast(cursor)) = *@as(^[Color; 512], @bitcast(ctx.buf))
|
|
||||||
cursor += 512
|
|
||||||
}
|
|
||||||
boundary += copy_pixels - 4096
|
|
||||||
loop if cursor == boundary break else {
|
|
||||||
*@as(^[Color; 4096], @bitcast(cursor)) = *@as(^[Color; 4096], @bitcast(ctx.buf))
|
|
||||||
cursor += 4096
|
|
||||||
}
|
|
||||||
boundary += (ctx.partitions - 1) * copy_pixels
|
|
||||||
loop if cursor == boundary break else {
|
|
||||||
*@as(^[Color; copy_pixels], @bitcast(cursor)) = *@as(^[Color; copy_pixels], @bitcast(ctx.buf))
|
|
||||||
cursor += @sizeof([u8; copy_pixels])
|
|
||||||
}
|
|
||||||
return
|
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("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
|
||||||
|
}
|
||||||
|
}
|
4
sysdata/libraries/stn/src/alloc/alloc_return.hb
Normal file
4
sysdata/libraries/stn/src/alloc/alloc_return.hb
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
AllocReturn := struct {
|
||||||
|
byte_count: uint,
|
||||||
|
ptr: ?^u8,
|
||||||
|
}
|
90
sysdata/libraries/stn/src/alloc/block_alloc.hb
Normal file
90
sysdata/libraries/stn/src/alloc/block_alloc.hb
Normal file
|
@ -0,0 +1,90 @@
|
||||||
|
.{log, panic, memory} := @use("../lib.hb")
|
||||||
|
alloc_return := @use("alloc_return.hb")
|
||||||
|
|
||||||
|
/* the block size is 64 bytes, 64 blocks of 64 bytes.
|
||||||
|
this will very quickly lead to exhaustion of free blocks.
|
||||||
|
*/
|
||||||
|
BlockAlloc := struct {
|
||||||
|
// hi
|
||||||
|
state: uint,
|
||||||
|
ptr: ?^u8,
|
||||||
|
|
||||||
|
$init := fn(): Self {
|
||||||
|
alloc_page_ptr := memory.request_page(1)
|
||||||
|
state := 0xFFFFFFFFFFFFFFFF
|
||||||
|
return .(state, alloc_page_ptr)
|
||||||
|
}
|
||||||
|
|
||||||
|
alloc := fn(self: Self, alloc_type: type, count: uint): alloc_return.AllocReturn {
|
||||||
|
offset := 0
|
||||||
|
state_2 := 0
|
||||||
|
loop {
|
||||||
|
xyz := self.state & 1
|
||||||
|
abc := if xyz == 1 {
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
// check if the `offset` bit is 1, if it is move to the next offset
|
||||||
|
if abc {
|
||||||
|
offset += 1
|
||||||
|
return .(0, null)
|
||||||
|
} else {
|
||||||
|
log.info("Already Allocated\0")
|
||||||
|
}
|
||||||
|
|
||||||
|
// else {
|
||||||
|
// // self it to 1 and return the ptr to the allocation
|
||||||
|
// self.state |= a
|
||||||
|
// // return ptr + offset * 64
|
||||||
|
// if self.ptr != null {
|
||||||
|
// return .(64, self.ptr + offset * 64)
|
||||||
|
// } else {
|
||||||
|
// // panic.panic("Allocator is not inited.\0")
|
||||||
|
// // return .(0, null)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// there are only 64 blocks
|
||||||
|
if offset >= 64 {
|
||||||
|
return .(0, null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dealloc := fn(self: Self, ptr: ^u8, alloc_type: type, count: uint): void {
|
||||||
|
// size := size_of(alloc_type)*count
|
||||||
|
size := 64
|
||||||
|
// get the size alligned to the nearest block
|
||||||
|
// rounded_size := nearest_block_size_rounded_up(size)
|
||||||
|
rounded_size := 64
|
||||||
|
|
||||||
|
state_bit_start := {
|
||||||
|
// Do math here to figure out what starting ptr corresponds to what bit
|
||||||
|
3
|
||||||
|
}
|
||||||
|
|
||||||
|
offset := 0
|
||||||
|
|
||||||
|
loop {
|
||||||
|
if rounded_size > 0 {
|
||||||
|
// set state_bit_start+offset to 0
|
||||||
|
|
||||||
|
// at the end move to the next one
|
||||||
|
offset += 1
|
||||||
|
} else {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
rounded_size -= 64
|
||||||
|
}
|
||||||
|
return void
|
||||||
|
}
|
||||||
|
|
||||||
|
$deinit := fn(self: Self): void {
|
||||||
|
self.state = 0
|
||||||
|
self.ptr = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// request a kernel page
|
||||||
|
// ptr := memory.alloc(1)
|
19
sysdata/libraries/stn/src/alloc/fake_alloc.hb
Normal file
19
sysdata/libraries/stn/src/alloc/fake_alloc.hb
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
alloc_return := @use("alloc_return.hb")
|
||||||
|
|
||||||
|
FakeAlloc := struct {
|
||||||
|
$init := fn(): Self {
|
||||||
|
return .()
|
||||||
|
}
|
||||||
|
|
||||||
|
$alloc := fn(self: Self, alloc_type: type, count: uint): alloc_return.AllocReturn {
|
||||||
|
return .(0, null)
|
||||||
|
}
|
||||||
|
|
||||||
|
$dealloc := fn(self: Self, ptr: ^u8, alloc_type: type, count: uint): void {
|
||||||
|
return void
|
||||||
|
}
|
||||||
|
// Nothing to clean up here
|
||||||
|
$deinit := fn(self: Self): void {
|
||||||
|
return void
|
||||||
|
}
|
||||||
|
}
|
2
sysdata/libraries/stn/src/alloc/lib.hb
Normal file
2
sysdata/libraries/stn/src/alloc/lib.hb
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
.{BlockAlloc} := @use("block_alloc.hb");
|
||||||
|
.{FakeAlloc} := @use("fake_alloc.hb")
|
25
sysdata/libraries/stn/src/alloc/main.hb
Normal file
25
sysdata/libraries/stn/src/alloc/main.hb
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
allocators := @use("alloc/alloc.hb")
|
||||||
|
|
||||||
|
AStruct := struct {
|
||||||
|
a_field: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
main := fn():void{
|
||||||
|
alloc := allocators.FakeAlloc.init()
|
||||||
|
astruct := alloc.alloc(AStruct, 2)
|
||||||
|
if astruct.ptr != null{
|
||||||
|
panic("FakeAlloc actually allocated.")
|
||||||
|
}
|
||||||
|
alloc.dealloc(astruct_ptr, AStruct, 2)
|
||||||
|
alloc.deinit()
|
||||||
|
|
||||||
|
balloc := allocators.BlockAlloc.init()
|
||||||
|
bstruct_ptr := balloc.alloc(AStruct, 2)
|
||||||
|
if bstruct_ptr == null {
|
||||||
|
panic("BlockAlloc actually didn't allocate.")
|
||||||
|
}
|
||||||
|
balloc.dealloc(bstruct_ptr, AStruct, 2)
|
||||||
|
balloc.deinit()
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -1,22 +1,35 @@
|
||||||
string := @use("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(4, buffer_id, memory_map_location, @sizeof(Expr))
|
||||||
|
}
|
||||||
|
|
||||||
|
$write := fn($Expr: type, buffer_id: uint, msg: ^Expr): void {
|
||||||
|
return @eca(3, buffer_id, msg, @sizeof(Expr))
|
||||||
|
}
|
||||||
|
|
||||||
|
$recv_length := fn(length: uint, memory_map_location: ^u8, buffer_id: uint): void {
|
||||||
return @eca(4, buffer_id, memory_map_location, length)
|
return @eca(4, buffer_id, memory_map_location, length)
|
||||||
}
|
}
|
||||||
|
|
||||||
send_message := fn(msg: ^u8, buffer_id: int, length: int): void {
|
$write_length := fn(length: uint, msg: ^u8, buffer_id: uint): void {
|
||||||
return @eca(3, buffer_id, msg, length)
|
return @eca(3, buffer_id, msg, length)
|
||||||
}
|
}
|
||||||
|
|
||||||
create := fn(msg: ^u8): int {
|
BufferMsg := packed struct {operation: u8, msg: ^u8, msg_len: uint}
|
||||||
msg_length := @inline(string.length, msg);
|
|
||||||
*msg = 0
|
create := fn(msg: ^u8): uint {
|
||||||
return @eca(3, 0, msg, msg_length)
|
return @eca(3, 0, BufferMsg.(0, msg, @inline(string.length, msg)), @sizeof(BufferMsg))
|
||||||
}
|
}
|
||||||
|
|
||||||
search := fn(msg: ^u8): int {
|
$create_nameless := fn(): uint {
|
||||||
msg_length := @inline(string.length, msg);
|
return @eca(1, 0)
|
||||||
*msg = 3
|
}
|
||||||
|
|
||||||
return @eca(3, 0, msg, msg_length)
|
$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))
|
||||||
|
}
|
189
sysdata/libraries/stn/src/hash/foldhash.hb
Normal file
189
sysdata/libraries/stn/src/hash/foldhash.hb
Normal file
|
@ -0,0 +1,189 @@
|
||||||
|
/*
|
||||||
|
* This code is an implementation of the FoldHash algorithm from https://github.com/orlp/foldhash,
|
||||||
|
* originally written by Orson Peters under the zlib license.
|
||||||
|
*
|
||||||
|
* Changes to the original code were made to meet the simplicity requirements of this implementation.
|
||||||
|
* Behaviour aims to be equivalent but not identical to the original code.
|
||||||
|
*
|
||||||
|
* Copyright (c) 2024 Orson Peters
|
||||||
|
*
|
||||||
|
* This software is provided 'as-is', without any express or implied warranty. In
|
||||||
|
* no event will the authors be held liable for any damages arising from the use of
|
||||||
|
* this software.
|
||||||
|
*
|
||||||
|
* Permission is granted to anyone to use this software for any purpose, including
|
||||||
|
* commercial applications, and to alter it and redistribute it freely, subject to
|
||||||
|
* the following restrictions:
|
||||||
|
*
|
||||||
|
* 1. The origin of this software must not be misrepresented; you must not claim
|
||||||
|
* that you wrote the original software. If you use this software in a product,
|
||||||
|
* an acknowledgment in the product documentation would be appreciated but is
|
||||||
|
* not required.
|
||||||
|
*
|
||||||
|
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
* misrepresented as being the original software.
|
||||||
|
*
|
||||||
|
* 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
*/;
|
||||||
|
|
||||||
|
.{math, random} := @use("../lib.hb")
|
||||||
|
|
||||||
|
$ARBITRARY0 := 0x243F6A8885A308D3
|
||||||
|
$ARBITRARY1 := 0x13198A2E03707344
|
||||||
|
$ARBITRARY2 := 0xA4093822299F31D0
|
||||||
|
$ARBITRARY3 := 0x82EFA98EC4E6C89
|
||||||
|
$ARBITRARY4 := 0x452821E638D01377
|
||||||
|
$ARBITRARY5 := 0xBE5466CF34E90C6C
|
||||||
|
$ARBITRARY6 := 0xC0AC29B7C97C50DD
|
||||||
|
$ARBITRARY7 := 0x3F84D5B5B5470917
|
||||||
|
$ARBITRARY8 := 0x9216D5D98979FB1B
|
||||||
|
$ARBITRARY9 := 0xD1310BA698DFB5AC
|
||||||
|
$FIXED_GLOBAL_SEED := [uint].(ARBITRARY4, ARBITRARY5, ARBITRARY6, ARBITRARY7)
|
||||||
|
|
||||||
|
global_seed := 0
|
||||||
|
|
||||||
|
u128 := packed struct {a: uint, b: uint}
|
||||||
|
|
||||||
|
$folded_multiply := fn(x: uint, y: uint): uint {
|
||||||
|
lx := @as(u32, @intcast(x))
|
||||||
|
ly := @as(u32, @intcast(y))
|
||||||
|
hx := x >> 32
|
||||||
|
hy := y >> 32
|
||||||
|
afull := lx * hy
|
||||||
|
bfull := hx * ly
|
||||||
|
return afull ^ (bfull << 32 | bfull >> 32)
|
||||||
|
}
|
||||||
|
|
||||||
|
hash_bytes_medium := fn(bytes: ^u8, len: uint, s0: uint, s1: uint, fold_seed: uint): uint {
|
||||||
|
lo := bytes
|
||||||
|
end := bytes + len
|
||||||
|
hi := end - 16
|
||||||
|
|
||||||
|
loop if lo >= hi break else {
|
||||||
|
a := *@as(^uint, @bitcast(lo))
|
||||||
|
b := *@as(^uint, @bitcast(lo + 8))
|
||||||
|
c := *@as(^uint, @bitcast(hi))
|
||||||
|
d := *@as(^uint, @bitcast(hi + 8))
|
||||||
|
s0 = folded_multiply(a ^ s0, c ^ fold_seed)
|
||||||
|
s1 = folded_multiply(b ^ s1, d ^ fold_seed)
|
||||||
|
hi -= 16
|
||||||
|
lo += 16
|
||||||
|
}
|
||||||
|
return s0 ^ s1
|
||||||
|
}
|
||||||
|
|
||||||
|
hash_bytes_long := fn(bytes: ^u8, len: uint, s0: uint, s1: uint, s2: uint, s3: uint, fold_seed: uint): uint {
|
||||||
|
$chunk_size := 64
|
||||||
|
chunks := len / chunk_size
|
||||||
|
remainder := len % chunk_size
|
||||||
|
|
||||||
|
ptr := bytes
|
||||||
|
i := 0
|
||||||
|
loop if i >= chunks break else {
|
||||||
|
a := *@as(^uint, @bitcast(ptr))
|
||||||
|
b := *@as(^uint, @bitcast(ptr + 8))
|
||||||
|
c := *@as(^uint, @bitcast(ptr + 16))
|
||||||
|
d := *@as(^uint, @bitcast(ptr + 24))
|
||||||
|
e := *@as(^uint, @bitcast(ptr + 32))
|
||||||
|
f := *@as(^uint, @bitcast(ptr + 40))
|
||||||
|
g := *@as(^uint, @bitcast(ptr + 48))
|
||||||
|
h := *@as(^uint, @bitcast(ptr + 56))
|
||||||
|
|
||||||
|
s0 = folded_multiply(a ^ s0, e ^ fold_seed)
|
||||||
|
s1 = folded_multiply(b ^ s1, f ^ fold_seed)
|
||||||
|
s2 = folded_multiply(c ^ s2, g ^ fold_seed)
|
||||||
|
s3 = folded_multiply(d ^ s3, h ^ fold_seed)
|
||||||
|
|
||||||
|
ptr += chunk_size
|
||||||
|
i += 1
|
||||||
|
}
|
||||||
|
|
||||||
|
s0 ^= s2
|
||||||
|
s1 ^= s3
|
||||||
|
|
||||||
|
if remainder > 0 {
|
||||||
|
remainder_start := bytes + len - math.max(uint, remainder, 16)
|
||||||
|
return hash_bytes_medium(remainder_start, math.max(uint, remainder, 16), s0, s1, fold_seed)
|
||||||
|
}
|
||||||
|
|
||||||
|
return s0 ^ s1
|
||||||
|
}
|
||||||
|
|
||||||
|
FoldHasher := struct {
|
||||||
|
accumulator: uint,
|
||||||
|
original_seed: uint,
|
||||||
|
sponge: u128,
|
||||||
|
sponge_len: u8,
|
||||||
|
fold_seed: uint,
|
||||||
|
expand_seed: uint,
|
||||||
|
expand_seed2: uint,
|
||||||
|
expand_seed3: uint,
|
||||||
|
|
||||||
|
$new := fn(seed: uint): Self {
|
||||||
|
return .(
|
||||||
|
seed,
|
||||||
|
seed,
|
||||||
|
.(0, 0),
|
||||||
|
0,
|
||||||
|
FIXED_GLOBAL_SEED[0],
|
||||||
|
FIXED_GLOBAL_SEED[1],
|
||||||
|
FIXED_GLOBAL_SEED[2],
|
||||||
|
FIXED_GLOBAL_SEED[3],
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
default := fn(): Self {
|
||||||
|
if global_seed == 0 {
|
||||||
|
// ! consider this "secure enough" for now
|
||||||
|
global_seed = random.any(uint)
|
||||||
|
}
|
||||||
|
return Self.new(global_seed)
|
||||||
|
}
|
||||||
|
|
||||||
|
write := fn(self: ^Self, bytes: ^u8, len: uint): void {
|
||||||
|
s0 := self.accumulator
|
||||||
|
s1 := self.expand_seed
|
||||||
|
if len <= 16 {
|
||||||
|
if len >= 8 {
|
||||||
|
s0 ^= *@bitcast(bytes)
|
||||||
|
s1 ^= *@bitcast(bytes + len - 8)
|
||||||
|
} else if len >= 4 {
|
||||||
|
s0 ^= *@as(^u32, @bitcast(bytes))
|
||||||
|
s1 ^= *@as(^u32, @bitcast(bytes + len - 4))
|
||||||
|
} else if len > 0 {
|
||||||
|
lo := *bytes
|
||||||
|
mid := *(bytes + len / 2)
|
||||||
|
hi := *(bytes + len - 1)
|
||||||
|
s0 ^= lo
|
||||||
|
s1 ^= @as(uint, hi) << 8 | mid
|
||||||
|
}
|
||||||
|
self.accumulator = folded_multiply(s0, s1)
|
||||||
|
} else if len < 256 {
|
||||||
|
self.accumulator = hash_bytes_medium(bytes, len, s0, s1, self.fold_seed)
|
||||||
|
} else {
|
||||||
|
self.accumulator = hash_bytes_long(
|
||||||
|
bytes,
|
||||||
|
len,
|
||||||
|
s0,
|
||||||
|
s1,
|
||||||
|
self.expand_seed2,
|
||||||
|
self.expand_seed3,
|
||||||
|
self.fold_seed,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
finish := fn(self: ^Self): uint {
|
||||||
|
if self.sponge_len > 0 {
|
||||||
|
return folded_multiply(self.sponge.b ^ self.accumulator, self.sponge.a ^ self.fold_seed)
|
||||||
|
} else {
|
||||||
|
return self.accumulator
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
reset := fn(self: ^Self): void {
|
||||||
|
self.accumulator = self.original_seed
|
||||||
|
self.sponge = .(0, 0)
|
||||||
|
self.sponge_len = 0
|
||||||
|
}
|
||||||
|
}
|
2
sysdata/libraries/stn/src/hash/lib.hb
Normal file
2
sysdata/libraries/stn/src/hash/lib.hb
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
//! NON CRYPTOGRAPHIC HASHER
|
||||||
|
foldhash := @use("foldhash.hb")
|
|
@ -1,5 +1,6 @@
|
||||||
acs := @use("acs.hb")
|
acs := @use("acs.hb")
|
||||||
|
allocators := @use("alloc/lib.hb")
|
||||||
|
hashers := @use("hash/lib.hb")
|
||||||
string := @use("string.hb")
|
string := @use("string.hb")
|
||||||
log := @use("log.hb")
|
log := @use("log.hb")
|
||||||
memory := @use("memory.hb")
|
memory := @use("memory.hb")
|
||||||
|
@ -7,3 +8,15 @@ buffer := @use("buffer.hb")
|
||||||
math := @use("math.hb")
|
math := @use("math.hb")
|
||||||
random := @use("random.hb")
|
random := @use("random.hb")
|
||||||
file := @use("file_io.hb")
|
file := @use("file_io.hb")
|
||||||
|
dt := @use("dt.hb")
|
||||||
|
process := @use("process.hb")
|
||||||
|
|
||||||
|
panic := fn(message: ?^u8): never {
|
||||||
|
log.error("Error: Panic Called, Message:\0")
|
||||||
|
if message == null {
|
||||||
|
log.error("None\0")
|
||||||
|
} else {
|
||||||
|
log.error(message)
|
||||||
|
}
|
||||||
|
die
|
||||||
|
}
|
|
@ -1,15 +1,13 @@
|
||||||
string := @use("string.hb")
|
string := @use("string.hb")
|
||||||
buffer := @use("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
|
|
||||||
|
|
||||||
return @eca(3, 1, message, message_length + 1)
|
log := fn(level: u8, message: ^u8): void {
|
||||||
|
return @eca(3, 1, LogMsg.(level, message, @inline(string.length, message)), @sizeof(LogMsg))
|
||||||
}
|
}
|
||||||
|
|
||||||
error := fn(message: ^u8): void return log(message, 0)
|
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,39 +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(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(3, 2, msg, 12)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
OutbMsg := struct {a: u8, b: u8, addr: u16, value: u8}
|
$calc_pages := fn($Expr: type, num: uint): uint {
|
||||||
InbMsg := struct {a: u8, b: u8, addr: u16}
|
return 1 + @sizeof(Expr) * num / PAGE_SIZE
|
||||||
OutlMsg := struct {a: u8, b: u8, addr: u16, value: u32}
|
}
|
||||||
InlMsg := struct {a: u8, b: u8, addr: u16}
|
|
||||||
|
|
||||||
outb := fn(addr: u16, value: u8): void {
|
// ! will be replaced, don't get attached
|
||||||
|
alloc := fn($Expr: type, num: uint): ^Expr {
|
||||||
|
pages := calc_pages(Expr, num)
|
||||||
|
if pages <= MAX_ALLOC {
|
||||||
|
return @bitcast(request_page(@intcast(pages)))
|
||||||
|
}
|
||||||
|
ptr := request_page(MAX_ALLOC)
|
||||||
|
remaining := pages - MAX_ALLOC
|
||||||
|
loop if remaining < MAX_ALLOC break else {
|
||||||
|
_ = request_page(MAX_ALLOC)
|
||||||
|
remaining -= MAX_ALLOC
|
||||||
|
}
|
||||||
|
_ = request_page(@intcast(remaining))
|
||||||
|
return @bitcast(ptr)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ! stub
|
||||||
|
$free := fn($Expr: type, ptr: ^Expr, num: uint, nullify: bool): void {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
RqPageMsg := packed struct {a: u8, count: u8}
|
||||||
|
$request_page := fn(count: u8): ^u8 {
|
||||||
|
return @eca(3, 2, &RqPageMsg.(0, count), @sizeof(RqPageMsg))
|
||||||
|
}
|
||||||
|
|
||||||
|
RlPageMsg := packed struct {a: u8, count: u8, ptr: ^u8}
|
||||||
|
$release_page := fn(ptr: ^u8, count: u8): void {
|
||||||
|
return @eca(3, 2, &RlPageMsg.(1, count, ptr), @sizeof(RlPageMsg))
|
||||||
|
}
|
||||||
|
|
||||||
|
OutbMsg := packed struct {a: u8, b: u8, addr: u16, value: u8}
|
||||||
|
$outb := fn(addr: u16, value: u8): void {
|
||||||
return @eca(3, 3, &OutbMsg.(1, 0, addr, value), @sizeof(OutbMsg))
|
return @eca(3, 3, &OutbMsg.(1, 0, addr, value), @sizeof(OutbMsg))
|
||||||
}
|
}
|
||||||
|
|
||||||
inb := fn(addr: u16): u8 {
|
InbMsg := packed struct {a: u8, b: u8, addr: u16}
|
||||||
|
$inb := fn(addr: u16): u8 {
|
||||||
return @eca(3, 3, &InbMsg.(0, 0, addr), @sizeof(InbMsg))
|
return @eca(3, 3, &InbMsg.(0, 0, addr), @sizeof(InbMsg))
|
||||||
}
|
}
|
||||||
|
|
||||||
outl := fn(addr: u16, value: u32): void {
|
OutlMsg := packed struct {a: u8, b: u8, addr: u16, value: u32}
|
||||||
|
$outl := fn(addr: u16, value: u32): void {
|
||||||
return @eca(3, 3, &OutlMsg.(1, 2, addr, value), @sizeof(OutlMsg))
|
return @eca(3, 3, &OutlMsg.(1, 2, addr, value), @sizeof(OutlMsg))
|
||||||
}
|
}
|
||||||
|
|
||||||
inl := fn(addr: u16): u32 {
|
InlMsg := packed struct {a: u8, b: u8, addr: u16}
|
||||||
|
$inl := fn(addr: u16): u32 {
|
||||||
return @eca(3, 3, &InlMsg.(0, 2, addr), @sizeof(InlMsg))
|
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))
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue