Compare commits

..

88 commits

Author SHA1 Message Date
Christian Westrom c5605bad0d change shell.nix to flake with all deps 2024-09-26 17:55:41 +09:00
Able f64f654610 Device work 2024-09-21 19:20:38 -05:00
Able 7d4b12a103 remove debugging info + fix the updating of hbvm 2024-09-21 19:20:14 -05:00
Able 758629df0a thumbs up 2024-09-20 05:06:08 -05:00
Able 04a449965b + 2024-09-20 04:02:58 -05:00
koniifer 0bbc76124f minor changes, svga work 2024-09-19 20:40:10 +01:00
Able 6ad68dabac hblang executable format update 2024-09-19 07:11:57 -05:00
Able 07c7d52b8c misc 2024-09-19 06:05:11 -05:00
Able 2edc8148ca no merge whamies pls 2024-09-18 03:41:41 -05:00
mlokr 5f59f05dce
removing deprecated rel: path prefix 2024-09-18 10:38:49 +02:00
Able 0bc757164f Input work 2024-09-17 19:26:37 -05:00
Able f5f68bc2df my changes and then boom 2024-09-17 17:23:32 -05:00
Able 7a256dde68 single file change 2024-09-17 12:08:19 -05:00
Able 570b566310 svga device struct updated to mostly reflect real device 2024-09-17 10:02:43 -05:00
Able d2488689fe fixs 2024-09-17 09:52:27 -05:00
Able fe70d81bd0 fat32 stub 2024-09-17 09:49:19 -05:00
Able cc076d9540 pumpkin print 2024-09-17 09:48:10 -05:00
Able 3173b63c93 minor changes 2024-09-17 09:47:53 -05:00
koniifer 48027196b1 omfg it's fixed 🙏 2024-09-17 09:47:53 -05:00
koniifer 78553a3190 let's just use strings for now 2024-09-17 09:47:11 -05:00
koniifer df74b09134 please bugs begone 2024-09-17 09:47:11 -05:00
koniifer 2321efd2e7 bug squashing & testing 2024-09-17 09:46:31 -05:00
Able d9caa17f3c commits 2024-09-17 09:39:46 -05:00
Able b0ecbfa168 fat32 stub 2024-09-17 08:01:16 -05:00
Able 1fe20360f6 pumpkin print 2024-09-16 20:59:24 -05:00
Able fb42351638 minor changes 2024-09-16 20:45:00 -05:00
able 5f2b181f22 Merge pull request 'good luck able' (#17) from koniifer/ableos-framebuffer:master into master
Reviewed-on: https://git.ablecorp.us/AbleOS/ableos/pulls/17
2024-09-14 16:44:05 +00:00
koniifer 43ea77c18f merge mainline branch and do some housekeeping 2024-09-14 11:26:32 +01:00
Able 2b2e0c514b multiline 2024-09-14 04:28:45 -05:00
Able fcca015866 minor changes 2024-09-14 04:05:40 -05:00
Able cc9337348e PCI+SVGA skeleton 2024-09-14 03:51:57 -05:00
Able 028949559b ignim checkpoint 2024-09-14 00:31:35 -05:00
Able 91380539d9 Ignim work 2024-09-13 23:11:50 -05:00
Able ec25c0f207 update on the logger
Further changes pending on the IDL
2024-09-13 20:50:12 -05:00
Able 1b5cb54a2b ignim work 2024-09-13 20:17:47 -05:00
Able 9686349476 add support for the device tree 2024-09-13 18:11:23 -05:00
koniifer f8c7873978 squash 2024-09-13 22:41:31 +01:00
Able 40cc412ab3 Horizon API work 2024-09-13 16:40:05 -05:00
Able cd369b39d5 more changes to make konii so anger 2024-09-12 15:34:28 -05:00
mlokr 331cbf5da1
fixing arm compilation errors 2024-09-10 21:52:57 +02:00
koniifer 63e2f546c5 Merge pull request 'adding disasembly in case something goes wrong' (#1) from mlokis/ableos-framebuffer:disasm into master
Reviewed-on: https://git.ablecorp.us/koniifer/ableos-framebuffer/pulls/1
2024-09-04 17:32:19 +00:00
mlokr 1a2b60b53b
foo 2024-09-04 19:14:30 +02:00
koniifer a7517005de update to latest hblang 2024-09-04 16:08:01 +01:00
Able 0594b99a59 cleanup 2024-09-03 03:34:29 -05:00
Able 1855307cd9 IDL tokenization 2024-09-02 21:50:43 -05:00
koniifer e3f7a2d455 inline fb_driver, update to latest hblang 2024-09-02 04:36:03 +01:00
koniifer 19992595fc update hblang to latest git
remove old ps/2 driver
remove defunct time driver
clean up stuff
i promise im done fiddling with ecah.rs and memory.hb
2024-09-02 01:04:00 +01:00
koniifer f7b970eaf0 hexadecimal support!!
remove fb_driver_stresstest, move examples back to fb_driver, update hblang, update Cargo.lock
2024-09-01 22:29:42 +01:00
koniifer c752028c73 fix ecah.rs, implement -d, --debuginfo to print debug info in serial (requires recompilation) 2024-08-31 19:34:14 +01:00
koniifer 8577920d90 port ecah changes from svga_driver branch 2024-08-31 15:38:15 +01:00
Able 7426bf479f idl work 2024-08-30 12:31:45 -05:00
koniifer 12ee3a9b87 fix random
implement hardware_random_u32
implement math.max, alter math.min
remove unneeded dependencies from fb_driver
2024-08-30 16:22:13 +01:00
koniifer 58bc6facbc Merge remote-tracking branch 'origin/kodin/keyboard-driver' 2024-08-30 14:55:22 +01:00
Talha Qamar 1615297536 Detecting keypresses 2024-08-30 18:06:24 +05:00
Talha Qamar 0d3641e199 just getting started 2024-08-30 18:04:10 +05:00
Able 6295a7118e Added beef to ableOS 2024-08-30 07:38:04 -05:00
koniifer ad85f82be3 begin work for fb_driver interface
create hardware rng buffer & stn.random.uint_64 (currently weird)
move examples out of fb_driver (currently broken)
remove literal kernel panic from `info!("AHHH")`
re-implement stn.buffer.send_message()
2024-08-29 21:37:49 +01:00
Able 9100b3ce44 dev update 2024-08-29 06:51:48 -05:00
Able 1c491e70e0 dev tool prototype 2024-08-28 14:35:08 -05:00
Able 0444fe4dfa readme update 2024-08-27 12:35:52 -05:00
able db08a249e1 Merge pull request 'fb driver' (#16) from aurlex/ableos-framebuffer:master into master
Reviewed-on: https://git.ablecorp.us/AbleOS/ableos/pulls/16
2024-08-21 03:26:45 +00:00
aurlex acc9d19a32 fb driver 2024-08-20 13:03:39 +01:00
Able 6fd47695a6 changes 2024-08-19 13:13:58 -05:00
Able fb8a835926 this ia bad way to handle this but oh well 2024-08-12 08:21:31 -05:00
Able f4246ae387 SEARCHING for dynamically created buffers now works using buffer.create / buffer.search 2024-08-12 08:15:50 -05:00
Able c7214a5a9b commit 2024-08-11 15:10:36 -05:00
Able bf86d9219c disable all programs 2024-07-25 09:28:56 -05:00
Able ea6ba3bdb0 in/out b 2024-07-23 19:37:43 -05:00
Able 3f183e231d compiler update 2024-07-22 18:43:19 -05:00
Able 514dadc667 rename 2024-07-21 06:47:25 -05:00
Able 9ec3bb1f99 fix 2024-07-20 12:54:58 -05:00
Able b99cb09a74 cleanup 2024-07-20 04:10:15 -05:00
Able 528b1fc66c formatted code 2024-07-19 08:53:45 -05:00
Able f0956b529c formater 2024-07-19 07:31:01 -05:00
Able bb37de554f update the compiler 2024-07-19 05:47:59 -05:00
able 0f3c94c0c9 Merge pull request 'String Library Update' (#15) from Trees/ableos_time:my-branch into master
Reviewed-on: https://git.ablecorp.us/AbleOS/ableos/pulls/15
2024-07-17 01:52:52 +00:00
Sam Buckley 314523fce7 Reenable fb driver 2024-07-17 01:28:04 +01:00
Sam Buckley 9f9c7af85f Add string stuff to library 2024-07-17 01:24:24 +01:00
Sam Buckley f59776e792 Update string lib for num format - Trees 2024-07-16 22:42:49 +01:00
Able 1adc381399 Hack in an inb/outb api 2024-07-15 16:56:46 -05:00
Able f33cc0bf70 did some stuff /shrug 2024-07-07 08:35:07 -05:00
Able 5f136a66af patch in the fb stuff 2024-07-06 11:23:44 -05:00
Able 54d7e6b02b work 2024-07-06 09:24:23 -05:00
Able 62c181fb6a checkpoint 2024-06-14 11:48:53 -05:00
Able e9e813220b update 2024-06-08 15:18:21 -05:00
able 02455e2cd8 deprecate the old assembler 2024-05-31 13:35:46 -05:00
able e08eab8627 patching together some broken stuff 2024-05-31 13:31:06 -05:00
able c57ef99948 Merge pull request 'un-hard-code the tests' (#14) from wildwestrom/ableos:master into master
Reviewed-on: https://git.ablecorp.us/AbleOS/ableos/pulls/14
2024-05-31 15:44:43 +00:00
148 changed files with 4132 additions and 1806 deletions

View file

@ -1,2 +1,3 @@
[alias] [alias]
repbuild = "run --manifest-path ./repbuild/Cargo.toml -r --" repbuild = "run --manifest-path ./repbuild/Cargo.toml -r --"
dev = "run --manifest-path ./dev/Cargo.toml -r --"

1
.envrc Normal file
View file

@ -0,0 +1 @@
use flake . --impure

1
.gitignore vendored
View file

@ -1 +1,2 @@
target/ target/
.direnv

1190
Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -1,3 +1,9 @@
[workspace] [workspace]
resolver = "2" resolver = "2"
members = ["kernel", "repbuild"] members = ["dev", "kernel", "repbuild"]
# [profile.release]
# strip = "symbols"
# codegen-units = 1
# lto = true
# panic = "abort"

View file

@ -1,6 +1,8 @@
# AbleOS # AbleOS
An UNIX-unlike micro-kernel written in rust with an embedded bytecode virtual machine. An UNIX-unlike micro-kernel written in rust with an embedded bytecode virtual machine.
Please note that a custom target directory is not supported and support will not be added.
# Community # Community
[Discord](https://discord.gg/JrKVukDtgs) [Discord](https://discord.gg/JrKVukDtgs)
@ -14,5 +16,11 @@ AbleOS should be able to be built on any platform which is supported by
For running AbleOS, `repbuild` uses QEMU. For running AbleOS, `repbuild` uses QEMU.
## Steps ## Steps
1. `git submodule update --init` 1. Ensure you have qemu installed
2. `cargo repbuild` 2. `git submodule update --init`
3. `cargo repbuild run`
# Developing
There is a new work in progress developer tool for hblang.
There is also a flake you can run by typing `nix develop .`.

7
dev/Cargo.toml Normal file
View file

@ -0,0 +1,7 @@
[package]
name = "dev"
version = "0.1.0"
edition = "2021"
[dependencies]
logos = "0.14.1"

6
dev/README.md Normal file
View file

@ -0,0 +1,6 @@
# dev
`dev` is an ableOS specific tool meant to help the development of ableOS.
At the current stage changes are not welcome. If you have feature suggestions ping me on discord `@abletheabove`.
Run `cargo dev help` to see usage.

84
dev/src/idl/mod.rs Normal file
View file

@ -0,0 +1,84 @@
pub mod protocol;
use std::io::Read;
use {
logos::{Lexer, Logos},
protocol::Protocol,
};
#[derive(Logos, Debug, PartialEq, Clone)]
#[logos(skip r"[ \t\n\f]+")] // Ignore this regex pattern between tokens
enum Token {
// Tokens can be literal strings, of any length.
#[token("protocol")]
Protocol,
#[token("{")]
LBrace,
#[token("}")]
RBrace,
#[token("(")]
LParen,
#[token(")")]
RParen,
#[token(":")]
Colon,
#[token(";")]
SemiColon,
#[token(",")]
Comma,
#[token("=")]
Equal,
#[token("->")]
RArrow,
#[regex("[a-zA-Z_]+", |lex|{lex.slice().to_string()})]
Text(String),
#[regex("[1234567890]+", |lex|{lex.slice().parse::<u64>().unwrap()})]
Number(u64),
#[regex(r"@[a-zA-Z_]+", |lex|{lex.slice().to_string()})]
Decorator(String),
#[regex(r#"@[a-zA-Z_]+\([a-zA-Z,0-9=]+\)"#, |lex|{lex.slice().to_string()})]
DecoratorOption(String),
}
pub fn build_idl(name: String) {
let contents = open_protocol(name);
let lex = Token::lexer(&contents);
let mut tokens = vec![];
for x in lex {
match x {
Ok(token) => {
println!("{:?}", token);
tokens.push(token);
}
Err(err) => println!("{:?}", err),
}
}
build(tokens);
}
fn build(a: Vec<Token>) {
for toke in a {
println!("{:?}", toke);
}
}
fn open_protocol(name: String) -> String {
let path = format!("sysdata/idl/{}/src/protocol.aidl", name);
let mut file = std::fs::File::open(path).unwrap();
let mut contents = String::new();
file.read_to_string(&mut contents).unwrap();
contents
}

17
dev/src/idl/protocol.rs Normal file
View file

@ -0,0 +1,17 @@
pub enum ProtocolTypes {
Byte,
}
pub struct Protocol {}
impl Protocol {
pub fn is_empty(&self) -> bool {
true
}
pub fn validate_data(&self, data: Vec<u8>) -> bool {
if !data.is_empty() && self.is_empty() {
return false;
}
true
}
}

152
dev/src/main.rs Normal file
View file

@ -0,0 +1,152 @@
use std::io::Write;
use idl::build_idl;
pub mod idl;
pub enum Options {
Build,
Clean,
New,
Run,
}
#[derive(PartialEq, Debug)]
pub enum DevelopmentType {
Program,
Library,
IDL,
}
fn main() {
let mut args: Vec<String> = std::env::args().collect();
args.remove(0);
args.reverse();
let binding = args.pop().unwrap_or("help".to_string());
let subcommand = binding.as_str();
match subcommand {
"build" => {
let name = &args.pop().unwrap();
build(name.to_string())
}
"new" => {
let binding = args.pop().unwrap();
let dev_type = binding.as_str();
let name = args.pop().unwrap();
use DevelopmentType::*;
match dev_type {
"lib" | "library" => new(Library, name),
"prog" | "program" => new(Program, name),
"idl" => {
new(IDL, name);
// idl::main();
panic!("IDL is not finalized yet.")
}
_ => {}
};
}
"run" => run(),
"help" => help(),
_ => {
println!("Error");
}
}
}
pub fn new(development_type: DevelopmentType, name: String) {
let (folder_hierarchy, entry_name) = match development_type {
DevelopmentType::Program => ("programs", "main.hb"),
DevelopmentType::Library => ("libraries", "lib.hb"),
DevelopmentType::IDL => ("idl", "protocol.aidl"),
};
let project_folder_path_string = format!("sysdata/{folder_hierarchy}/{name}");
if std::path::Path::new(&project_folder_path_string).exists() {
panic!("Project already exists.")
}
std::fs::create_dir(project_folder_path_string.clone()).unwrap();
let readme_path_string = format!("{}/README.md", project_folder_path_string);
let mut readme_file = std::fs::File::create(readme_path_string.clone()).unwrap();
let readme_contents = format!("# {}", name);
readme_file.write_all(readme_contents.as_bytes()).unwrap();
let contents = format!(
"[package]
name = \"{}\"
authors = [\"\"]
[dependants.libraries]
[dependants.binaries]
hblang.version = \"1.0.0\"
[build]
command = \"hblang src/main.hb\"
",
name
);
let toml_path_string = format!("{}/meta.toml", project_folder_path_string);
let mut readme_file = std::fs::File::create(toml_path_string.clone()).unwrap();
readme_file.write_all(contents.as_bytes()).unwrap();
let src_folder_path_string = format!("{}/src", project_folder_path_string);
std::fs::create_dir(src_folder_path_string.clone()).unwrap();
let full_path_string = format!("{src_folder_path_string}/{entry_name}");
let mut file = std::fs::File::create(full_path_string.clone()).unwrap();
let file_contents = match development_type {
DevelopmentType::Program => "main := fn(): int {
return 0
}"
.to_string(),
DevelopmentType::Library => "".to_string(),
DevelopmentType::IDL => format!(
"protocol {} {{
}}",
name
)
.to_owned(),
}
.to_string();
file.write_all(file_contents.as_bytes()).unwrap();
println!("New project created.");
if development_type == DevelopmentType::Program {
println!("You should add your project into the ableOS system configuration in sysdata/system_config.toml")
}
}
fn run() {
println!("Running is not supported on a non-ableOS platform");
}
fn build(name: String) {
println!("building {}", name);
let mut a = name.split("/");
let dev_type = a.next().unwrap();
let name = a.next().unwrap().to_string();
match dev_type {
"programs" => build_program(name),
"idl" => build_idl(name),
_ => {
panic!()
}
}
}
pub fn build_program(name: String) {}
pub fn build_library(name: String) {}
fn help() {
println!(
"==========
= Help =
==========
Subcommands
- new Usage: `cargo dev new library name` or `cargo dev new program name`"
)
}

57
flake.lock Normal file
View file

@ -0,0 +1,57 @@
{
"nodes": {
"flake-utils": {
"inputs": {
"systems": "systems"
},
"locked": {
"lastModified": 1726560853,
"narHash": "sha256-X6rJYSESBVr3hBoH0WbKE5KvhPU5bloyZ2L4K60/fPQ=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "c1dfcf08411b08f6b8615f7d8971a2bfa81d5e8a",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 0,
"narHash": "sha256-6H95HGJHhEZtyYA3rIQpvamMKAGoa8Yh2rFV29QnuGw=",
"path": "/nix/store/nra828scc8qs92b9pxra5csqzffb6hpl-source",
"type": "path"
},
"original": {
"id": "nixpkgs",
"type": "indirect"
}
},
"root": {
"inputs": {
"flake-utils": "flake-utils",
"nixpkgs": "nixpkgs"
}
},
"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
}

62
flake.nix Normal file
View file

@ -0,0 +1,62 @@
{
description = "ableos flake";
inputs = {
flake-utils.url = "github:numtide/flake-utils";
};
outputs =
{
self,
nixpkgs,
flake-utils,
}:
flake-utils.lib.eachDefaultSystem (
system:
let
# legacyPackages is a misnomer, it's just using your system packages
pkgs = nixpkgs.legacyPackages.${system};
in
{
devShell = pkgs.mkShell rec {
buildInputs = with pkgs; [
clang
llvmPackages.bintools
rustup
qemu_full
# OMVFFull
# OMVF
];
extraCmds = '''';
RUSTC_VERSION = pkgs.lib.readFile ./rust-toolchain.toml;
# https://github.com/rust-lang/rust-bindgen#environment-variables
LIBCLANG_PATH = pkgs.lib.makeLibraryPath [ pkgs.llvmPackages_latest.libclang.lib ];
shellHook = ''
export REPBUILD_QEMU_FIRMWARE_PATH=${pkgs.OVMF.fd}/FV/OVMF.fd
export PATH=$PATH:''${CARGO_HOME:-~/.cargo}/bin
export PATH=$PATH:''${RUSTUP_HOME:-~/.rustup}/toolchains/$RUSTC_VERSION-x86_64-unknown-linux-gnu/bin/
'';
# Add precompiled library to rustc search path
RUSTFLAGS = (
builtins.map (a: "-L ${a}/lib") [
# add libraries here (e.g. pkgs.libvmi)
]
);
# Add glibc, clang, glib and other headers to bindgen search path
BINDGEN_EXTRA_CLANG_ARGS =
# Includes with normal include path
(builtins.map (a: ''-I"${a}/include"'') [
# add dev libraries here (e.g. pkgs.libvmi.dev)
pkgs.glibc.dev
])
# Includes with special directory paths
++ [
''-I"${pkgs.llvmPackages_latest.libclang.lib}/lib/clang/${pkgs.llvmPackages_latest.libclang.version}/include"''
''-I"${pkgs.glib.dev}/include/glib-2.0"''
"-I${pkgs.glib.out}/lib/glib-2.0/include/"
];
};
}
);
}

View file

@ -5,33 +5,32 @@ version = "0.2.0"
[dependencies] [dependencies]
embedded-graphics = "0.7" embedded-graphics = "0.8"
hbvm.git = "https://git.ablecorp.us/ableos/holey-bytes" hbvm.git = "https://git.ablecorp.us/AbleOS/holey-bytes.git"
log = "0.4" log = "0.4"
spin = "0.9" spin = "0.9"
uart_16550 = "0.2" slab = { version = "0.4", default-features = false }
slab = { version = "0.4", default-features = false } uart_16550 = { version = "0.3", features = ["nightly"] }
xml.git = "https://git.ablecorp.us/ableos/ableos_userland" xml.git = "https://git.ablecorp.us/ableos/ableos_userland"
versioning.git = "https://git.ablecorp.us/ableos/ableos_userland" versioning.git = "https://git.ablecorp.us/ableos/ableos_userland"
able_graphics_library.git = "https://git.ablecorp.us/ableos/ableos_userland" # able_graphics_library.git = "https://git.ablecorp.us/ableos/ableos_userland"
hashbrown = "*" hashbrown = { version = "0.14", features = ["nightly"] }
kiam = "0.1.1"
[dependencies.limine] [dependencies.limine]
version = "0.1" version = "0.1"
git = "https://github.com/limine-bootloader/limine-rs" #git = "https://github.com/limine-bootloader/limine-rs"
[dependencies.crossbeam-queue] [dependencies.crossbeam-queue]
version = "0.3" version = "0.3"
default-features = false default-features = false
features = ["alloc"] features = ["alloc", "nightly"]
[dependencies.clparse] # [dependencies.clparse]
git = "https://git.ablecorp.us/ableos/ableos_userland" # git = "https://git.ablecorp.us/ableos/ableos_userland"
default-features = false # default-features = false
[dependencies.derive_more] [dependencies.derive_more]
version = "0.99" version = "1"
default-features = false default-features = false
features = [ features = [
"add", "add",
@ -48,12 +47,12 @@ features = [
[target.'cfg(target_arch = "x86_64")'.dependencies] [target.'cfg(target_arch = "x86_64")'.dependencies]
x86_64 = "0.14" x86_64 = "0.15"
x2apic = "0.4" x2apic = "0.4"
virtio-drivers = "0.4.0" virtio-drivers = "0.7"
# rdrand = "*"
rdrand = { version = "0.8", default-features = false }
[target.'cfg(target_arch = "riscv64")'.dependencies] [target.'cfg(target_arch = "riscv64")'.dependencies]
sbi = "0.2.0" sbi = "0.2.0"
[target.'cfg(target_arch = "aarch64")'.dependencies]
aarch64-cpu = "9"

View file

@ -29,7 +29,7 @@ fn collect_cpu_info(device_tree: &mut DeviceTree) {
} }
fn cpu_id() -> (String, u64) { fn cpu_id() -> (String, u64) {
let mut cpu_id: u64 = 0; let mut cpu_id: u64;
unsafe { unsafe {
asm!("mrs {cpu_id}, MIDR_EL1", asm!("mrs {cpu_id}, MIDR_EL1",
cpu_id = out(reg) cpu_id, cpu_id = out(reg) cpu_id,
@ -41,6 +41,8 @@ fn cpu_id() -> (String, u64) {
// https://raspberrypi.stackexchange.com/questions/117175/how-do-i-read-the-cpuid-in-aarch64-asm // https://raspberrypi.stackexchange.com/questions/117175/how-do-i-read-the-cpuid-in-aarch64-asm
0x410FD034 => "Cortex-A53".to_string(), 0x410FD034 => "Cortex-A53".to_string(),
0x410FD083 => "Cortex-A72".to_string(), 0x410FD083 => "Cortex-A72".to_string(),
// the source of this one was checking the cpu id :thinking:
0x410FD493 => "Neoverse N2".to_string(),
_ => "Unknown".to_string(), _ => "Unknown".to_string(),
}; };
log::trace!("CPU Name: {cpu_name} - CPU ID: 0x{:X}", cpu_id); log::trace!("CPU Name: {cpu_name} - CPU ID: 0x{:X}", cpu_id);

View file

@ -1,5 +1,5 @@
use {crate::logger::TERMINAL_LOGGER, core::fmt::Write, spin::Mutex}; use {crate::logger::TERMINAL_LOGGER, core::fmt::Write, spin::Mutex};
const SERIAL_CONSOLE: Mutex<SerialConsole> = Mutex::new(SerialConsole { pub static SERIAL_CONSOLE: Mutex<SerialConsole> = Mutex::new(SerialConsole {
uart: 0x09000000 as *mut u8, uart: 0x09000000 as *mut u8,
}); });
@ -17,9 +17,12 @@ impl core::fmt::Write for SerialConsole {
} }
} }
unsafe impl Sync for SerialConsole {}
unsafe impl Send for SerialConsole {}
pub fn log(args: core::fmt::Arguments<'_>) -> core::fmt::Result { pub fn log(args: core::fmt::Arguments<'_>) -> core::fmt::Result {
SERIAL_CONSOLE.lock().write_fmt(args)?; SERIAL_CONSOLE.lock().write_fmt(args)?;
TERMINAL_LOGGER.lock().write_fmt(args)?; // TERMINAL_LOGGER.lock().write_fmt(args)?;
Ok(()) Ok(())
} }

View file

@ -1,6 +1,7 @@
pub use logging::log; pub use logging::log;
use { use {
crate::{allocator, bootmodules::BootModule, kmain::kmain}, crate::{allocator, bootmodules::BootModule, kmain::kmain},
alloc::vec::Vec,
core::arch::asm, core::arch::asm,
limine::FramebufferRequest, limine::FramebufferRequest,
}; };
@ -41,7 +42,7 @@ unsafe extern "C" fn _kernel_start() -> ! {
static KFILE_REQ: KernelFileRequest = KernelFileRequest::new(0); static KFILE_REQ: KernelFileRequest = KernelFileRequest::new(0);
static MOD_REQ: ModuleRequest = ModuleRequest::new(0); static MOD_REQ: ModuleRequest = ModuleRequest::new(0);
let mut bootmodules = alloc::vec::Vec::new(); let mut bootmodules = Vec::new();
if bm.is_some() { if bm.is_some() {
let bm = bm.unwrap(); let bm = bm.unwrap();
@ -52,18 +53,13 @@ unsafe extern "C" fn _kernel_start() -> ! {
let raw_bytes = core::slice::from_raw_parts( let raw_bytes = core::slice::from_raw_parts(
file.base.as_ptr().expect("invalid initrd"), file.base.as_ptr().expect("invalid initrd"),
file.length as usize, file.length as usize,
)
.to_vec();
let file_path = alloc::string::String::from_utf8(
file.path.to_str().unwrap().to_bytes().to_vec(),
); );
let file_path = file.path.to_str().unwrap().to_str();
if file_path.is_err() { if file_path.is_err() {
panic!("invalid file path: {:?}", file_path); panic!("invalid file path: {:?}", file_path);
} }
let file_cmd = alloc::string::String::from_utf8( let file_cmd = file.cmdline.to_str().unwrap().to_str();
file.cmdline.to_str().unwrap().to_bytes().to_vec(),
);
if file_cmd.is_err() { if file_cmd.is_err() {
panic!("invalid module cmd: {:?}", file_cmd); panic!("invalid module cmd: {:?}", file_cmd);
} }
@ -85,7 +81,7 @@ unsafe extern "C" fn _kernel_start() -> ! {
assert_eq!(bm.module_count, bootmodules.len() as u64); assert_eq!(bm.module_count, bootmodules.len() as u64);
} }
crate::kmain::kmain( kmain(
KFILE_REQ KFILE_REQ
.get_response() .get_response()
.get() .get()
@ -99,8 +95,6 @@ unsafe extern "C" fn _kernel_start() -> ! {
.unwrap_or_default(), .unwrap_or_default(),
bootmodules, bootmodules,
); );
spin_loop();
} }
pub fn spin_loop() -> ! { pub fn spin_loop() -> ! {
@ -109,8 +103,19 @@ pub fn spin_loop() -> ! {
} }
} }
/// I am sorry.
static mut A_REAL_RANDOM_U64_I_PROMISE: u64 = 0;
pub fn hardware_random_u64() -> u64 { pub fn hardware_random_u64() -> u64 {
0 if let Some(rng) = aarch64_cpu::asm::random::ArmRng::new() {
if let Some(rnd) = rng.rndr() {
return rnd;
}
}
unsafe {
A_REAL_RANDOM_U64_I_PROMISE += 1;
A_REAL_RANDOM_U64_I_PROMISE
}
} }
pub fn register_dump() {} pub fn register_dump() {}

View file

@ -1,8 +1,10 @@
use core::num; use core::num;
use alloc::boxed::Box; use {
use spin::{Mutex, Once}; crate::memory::{MemoryManager, PhysicalAddress, VirtualAddress},
use crate::memory::{MemoryManager, PhysicalAddress, VirtualAddress}; alloc::boxed::Box,
spin::{Mutex, Once},
};
use super::PAGE_SIZE; use super::PAGE_SIZE;
@ -28,7 +30,7 @@ impl PageSize {
} }
pub struct PageTable { pub struct PageTable {
entries: [PageEntry; 512] entries: [PageEntry; 512],
} }
impl PageTable { impl PageTable {
@ -72,8 +74,14 @@ impl PageTable {
/// flags MUST include one or more of the following: /// flags MUST include one or more of the following:
/// Read, Write, Execute /// Read, Write, Execute
/// The valid bit automatically gets added /// The valid bit automatically gets added
pub fn map(&mut self, vaddr: VirtualAddress, paddr: PhysicalAddress, flags: PageEntryFlags, page_size: PageSize) { pub fn map(
assert!(flags as usize & 0xe != 0); &mut self,
vaddr: VirtualAddress,
paddr: PhysicalAddress,
flags: PageEntryFlags,
page_size: PageSize,
) {
assert!(flags as usize & 0xE != 0);
let vpn = vaddr.vpns(); let vpn = vaddr.vpns();
let ppn = paddr.ppns(); let ppn = paddr.ppns();
@ -91,7 +99,7 @@ impl PageTable {
} }
let entry = v.addr().as_mut_ptr::<PageEntry>(); let entry = v.addr().as_mut_ptr::<PageEntry>();
v = unsafe { entry.add(vpn[i]).as_mut().unwrap() }; v = unsafe { entry.add(vpn[i]).as_mut().unwrap() };
} }
// When we get here, we should be at VPN[0] and v should be pointing to our entry. // When we get here, we should be at VPN[0] and v should be pointing to our entry.
@ -105,14 +113,24 @@ impl PageTable {
} }
/// Identity maps a page of memory /// Identity maps a page of memory
pub fn identity_map(&mut self, addr: PhysicalAddress, flags: PageEntryFlags, page_size: PageSize) { pub fn identity_map(
&mut self,
addr: PhysicalAddress,
flags: PageEntryFlags,
page_size: PageSize,
) {
// log::debug!("identity mapped {addr}"); // log::debug!("identity mapped {addr}");
self.map(addr.as_addr().into(), addr, flags, page_size); self.map(addr.as_addr().into(), addr, flags, page_size);
} }
/// Identity maps a range of contiguous memory /// Identity maps a range of contiguous memory
/// This assumes that start <= end /// This assumes that start <= end
pub fn identity_map_range(&mut self, start: PhysicalAddress, end: PhysicalAddress, flags: PageEntryFlags) { pub fn identity_map_range(
&mut self,
start: PhysicalAddress,
end: PhysicalAddress,
flags: PageEntryFlags,
) {
log::debug!("start: {start}, end: {end}"); log::debug!("start: {start}, end: {end}");
let mut mem_addr = start.as_addr() & !(PAGE_SIZE - 1); let mut mem_addr = start.as_addr() & !(PAGE_SIZE - 1);
let num_pages = (align_val(end.as_addr(), 12) - mem_addr - 1) / PAGE_SIZE + 1; let num_pages = (align_val(end.as_addr(), 12) - mem_addr - 1) / PAGE_SIZE + 1;
@ -142,7 +160,7 @@ impl PageTable {
} }
let entry = v.addr().as_mut_ptr::<PageEntry>(); let entry = v.addr().as_mut_ptr::<PageEntry>();
v = unsafe { entry.add(vpn[i]).as_mut().unwrap() }; v = unsafe { entry.add(vpn[i]).as_mut().unwrap() };
} }
// If we're here this is an unmapped page // If we're here this is an unmapped page
@ -182,7 +200,7 @@ pub enum PageEntryFlags {
Global = 1 << 5, Global = 1 << 5,
Access = 1 << 6, Access = 1 << 6,
Dirty = 1 << 7, Dirty = 1 << 7,
// for convenience // for convenience
ReadWrite = Self::Read as usize | Self::Write as usize, ReadWrite = Self::Read as usize | Self::Write as usize,
ReadExecute = Self::Read as usize | Self::Execute as usize, ReadExecute = Self::Read as usize | Self::Execute as usize,
@ -228,7 +246,7 @@ impl PageEntry {
} }
fn addr(&self) -> PhysicalAddress { fn addr(&self) -> PhysicalAddress {
((self.entry() as usize & !0x3ff) << 2).into() ((self.entry() as usize & !0x3FF) << 2).into()
} }
fn destroy(&mut self) { fn destroy(&mut self) {

View file

@ -1,7 +1,7 @@
mod memory; mod memory;
use { use {
alloc::boxed::Box, alloc::{boxed::Box, vec::Vec},
core::{ core::{
arch::{asm, global_asm}, arch::{asm, global_asm},
fmt::Write, fmt::Write,
@ -45,7 +45,7 @@ extern "C" {
static USABLE_MEMORY_SIZE: usize; static USABLE_MEMORY_SIZE: usize;
} }
static SERIAL_CONSOLE: Once<Mutex<MmioSerialPort>> = Once::new(); pub static SERIAL_CONSOLE: Once<Mutex<MmioSerialPort>> = Once::new();
#[no_mangle] #[no_mangle]
unsafe extern "C" fn _kernel_start() -> ! { unsafe extern "C" fn _kernel_start() -> ! {
@ -95,7 +95,7 @@ unsafe extern "C" fn _kernel_start() -> ! {
in(reg) satp_value, in(reg) satp_value,
); );
crate::kmain::kmain("baka=9", None); crate::kmain::kmain("baka=9", Vec::new());
} }
/// Spin loop /// Spin loop
@ -105,6 +105,12 @@ pub fn spin_loop() -> ! {
} }
} }
pub fn hardware_random_u64() -> u64 {
0
}
pub fn register_dump() {}
pub fn log(args: core::fmt::Arguments<'_>) -> core::fmt::Result { pub fn log(args: core::fmt::Arguments<'_>) -> core::fmt::Result {
SERIAL_CONSOLE.get().unwrap().lock().write_fmt(args) SERIAL_CONSOLE.get().unwrap().lock().write_fmt(args)
} }

View file

@ -11,6 +11,9 @@ use {
pub const DOUBLE_FAULT_IX: u16 = 0; pub const DOUBLE_FAULT_IX: u16 = 0;
const STACK_SIZE: usize = 5 * 1024;
const STACK_ALIGNMENT: usize = 1;
pub unsafe fn init() { pub unsafe fn init() {
use x86_64::instructions::{ use x86_64::instructions::{
segmentation::{Segment, CS, SS}, segmentation::{Segment, CS, SS},
@ -32,24 +35,24 @@ struct Selectors {
static TSS: Lazy<TaskStateSegment> = Lazy::new(|| { static TSS: Lazy<TaskStateSegment> = Lazy::new(|| {
let mut tss = TaskStateSegment::new(); let mut tss = TaskStateSegment::new();
tss.interrupt_stack_table[usize::from(DOUBLE_FAULT_IX)] = {
const SIZE: usize = 5 * 1024; let stack_ptr = unsafe {
let stack = unsafe { let layout = alloc::alloc::Layout::from_size_align(STACK_SIZE, STACK_ALIGNMENT)
alloc::alloc::alloc_zeroed( .expect("Failed to create stack layout");
alloc::alloc::Layout::from_size_align(SIZE, 1).expect("stack pointer"), let stack = alloc::alloc::alloc(layout);
) VirtAddr::from_ptr(stack) + STACK_SIZE as u64
};
VirtAddr::from_ptr(stack) + SIZE
}; };
tss.interrupt_stack_table[usize::from(DOUBLE_FAULT_IX)] = stack_ptr;
tss tss
}); });
static GDT: Lazy<(GlobalDescriptorTable, Selectors)> = Lazy::new(|| { static GDT: Lazy<(GlobalDescriptorTable, Selectors)> = Lazy::new(|| {
let mut gdt = GlobalDescriptorTable::new(); let mut gdt = GlobalDescriptorTable::new();
let sels = Selectors { let sels = Selectors {
kcode: gdt.add_entry(Descriptor::kernel_code_segment()), kcode: gdt.append(Descriptor::kernel_code_segment()),
kdata: gdt.add_entry(Descriptor::kernel_data_segment()), kdata: gdt.append(Descriptor::kernel_data_segment()),
tss: gdt.add_entry(Descriptor::tss_segment(&TSS)), tss: gdt.append(Descriptor::tss_segment(&TSS)),
}; };
(gdt, sels) (gdt, sels)
}); });

View file

@ -1,56 +1,52 @@
// TODO: Turn apic keyboard interrupt into a standard ipc message
use { use {
core::mem::MaybeUninit,
log::trace, log::trace,
spin::{Lazy, Mutex},
x2apic::lapic::{LocalApic, LocalApicBuilder}, x2apic::lapic::{LocalApic, LocalApicBuilder},
x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame, PageFaultErrorCode}, x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame, PageFaultErrorCode},
}; };
pub unsafe fn init() { /// Safety: Using LAPIC or IDT before init() is UB
trace!("Initialising IDT"); /// Using
IDT.load(); static mut LAPIC: LocalApic = unsafe { MaybeUninit::zeroed().assume_init() };
Lazy::force(&LAPIC); static mut IDT: InterruptDescriptorTable = unsafe { MaybeUninit::zeroed().assume_init() };
x86_64::instructions::interrupts::enable();
}
#[repr(u8)] #[repr(u8)]
enum Interrupt { enum Interrupt {
Timer = 32, Timer = 32,
ApicErr = u8::MAX - 1, ApicErr = u8::MAX - 1,
Spurious = u8::MAX, Spurious = u8::MAX,
} }
pub(crate) static LAPIC: Lazy<Mutex<LocalApic>> = Lazy::new(|| { pub unsafe fn init() {
let mut lapic = LocalApicBuilder::new() trace!("Initializing IDT and LAPIC");
// Initialize and load the IDT
IDT = InterruptDescriptorTable::new();
IDT.double_fault
.set_handler_fn(double_fault)
.set_stack_index(super::gdt::DOUBLE_FAULT_IX);
IDT.page_fault.set_handler_fn(page_fault);
IDT[Interrupt::ApicErr as u8].set_handler_fn(apic_err);
IDT[Interrupt::Spurious as u8].set_handler_fn(spurious);
IDT[Interrupt::Timer as u8].set_handler_fn(timer);
IDT.load();
LAPIC = LocalApicBuilder::new()
.timer_vector(Interrupt::Timer as usize) .timer_vector(Interrupt::Timer as usize)
.error_vector(Interrupt::ApicErr as usize) .error_vector(Interrupt::ApicErr as usize)
.spurious_vector(Interrupt::Spurious as usize) .spurious_vector(Interrupt::Spurious as usize)
.set_xapic_base( .set_xapic_base(
unsafe { x2apic::lapic::xapic_base() } x2apic::lapic::xapic_base()
+ super::memory::HHDM_OFFSET.load(core::sync::atomic::Ordering::Relaxed), + super::memory::HHDM_OFFSET.load(core::sync::atomic::Ordering::Relaxed),
) )
.build() .build()
.expect("failed to setup Local APIC"); .expect("Failed to setup Local APIC");
unsafe { lapic.enable() }; LAPIC.enable();
Mutex::new(lapic)
});
static IDT: Lazy<InterruptDescriptorTable> = Lazy::new(|| { x86_64::instructions::interrupts::enable();
let mut idt = InterruptDescriptorTable::new(); }
unsafe {
idt.double_fault
.set_handler_fn(double_fault)
.set_stack_index(super::gdt::DOUBLE_FAULT_IX);
}
idt.page_fault.set_handler_fn(page_fault);
idt[Interrupt::ApicErr as usize].set_handler_fn(apic_err);
idt[Interrupt::Spurious as usize].set_handler_fn(spurious);
idt[Interrupt::Timer as usize].set_handler_fn(timer);
idt
});
extern "x86-interrupt" fn double_fault(stack_frame: InterruptStackFrame, error_code: u64) -> ! { extern "x86-interrupt" fn double_fault(stack_frame: InterruptStackFrame, error_code: u64) -> ! {
panic!("Double fault: error code {error_code} \n{stack_frame:#?}") panic!("Double fault: error code {error_code} \n{stack_frame:#?}")
@ -64,7 +60,9 @@ extern "x86-interrupt" fn page_fault(
} }
extern "x86-interrupt" fn timer(_isf: InterruptStackFrame) { extern "x86-interrupt" fn timer(_isf: InterruptStackFrame) {
unsafe { LAPIC.lock().end_of_interrupt() }; unsafe {
LAPIC.end_of_interrupt();
}
} }
extern "x86-interrupt" fn apic_err(_: InterruptStackFrame) { extern "x86-interrupt" fn apic_err(_: InterruptStackFrame) {
@ -72,5 +70,7 @@ extern "x86-interrupt" fn apic_err(_: InterruptStackFrame) {
} }
extern "x86-interrupt" fn spurious(_: InterruptStackFrame) { extern "x86-interrupt" fn spurious(_: InterruptStackFrame) {
unsafe { LAPIC.lock().end_of_interrupt() }; unsafe {
LAPIC.end_of_interrupt();
}
} }

View file

@ -1,11 +1,6 @@
//! Logging (as in terms of console / serial output) //! Logging (as in terms of console / serial output)
#![allow(deprecated)] #![allow(deprecated)]
use { use {core::fmt::Write, spin::Mutex, uart_16550::SerialPort};
core::fmt::Write,
limine::{TerminalRequest, TerminalResponse},
spin::{Lazy, Mutex},
uart_16550::SerialPort,
};
pub static SERIAL_CONSOLE: Mutex<SerialPort> = Mutex::new(unsafe { SerialPort::new(0x3F8) }); pub static SERIAL_CONSOLE: Mutex<SerialPort> = Mutex::new(unsafe { SerialPort::new(0x3F8) });

View file

@ -1,7 +1,6 @@
use { use core::arch::x86_64::{_rdrand64_step, _rdseed64_step};
crate::bootmodules::BootModule, core::arch::asm, embedded_graphics::pixelcolor::Rgb888,
log::warn, rdrand::RdSeed, use {crate::bootmodules::BootModule, core::arch::asm, log::warn};
};
pub mod memory; pub mod memory;
mod cpuid; mod cpuid;
@ -143,18 +142,13 @@ unsafe extern "C" fn start() -> ! {
let raw_bytes = core::slice::from_raw_parts( let raw_bytes = core::slice::from_raw_parts(
file.base.as_ptr().expect("invalid initrd"), file.base.as_ptr().expect("invalid initrd"),
file.length as usize, file.length as usize,
)
.to_vec();
let file_path = alloc::string::String::from_utf8(
file.path.to_str().unwrap().to_bytes().to_vec(),
); );
let file_path = file.path.to_str().unwrap().to_str();
if file_path.is_err() { if file_path.is_err() {
panic!("invalid file path: {:?}", file_path); panic!("invalid file path: {:?}", file_path);
} }
let file_cmd = alloc::string::String::from_utf8( let file_cmd = file.cmdline.to_str().unwrap().to_str();
file.cmdline.to_str().unwrap().to_bytes().to_vec(),
);
if file_cmd.is_err() { if file_cmd.is_err() {
panic!("invalid module cmd: {:?}", file_cmd); panic!("invalid module cmd: {:?}", file_cmd);
} }
@ -195,32 +189,20 @@ unsafe extern "C" fn start() -> ! {
/// Spin loop /// Spin loop
pub fn spin_loop() -> ! { pub fn spin_loop() -> ! {
loop { loop {
x86_64::instructions::hlt(); x86_64::instructions::hlt()
} }
} }
pub fn hardware_random_u64() -> u64 { pub fn hardware_random_u64() -> u64 {
use {log::trace, rdrand::RdRand}; let mut out: u64 = 0;
let gen = RdRand::new(); match unsafe { _rdrand64_step(&mut out) } {
match gen { 1 => out,
Ok(gen) => { _ => {
let ret = gen.try_next_u64().unwrap();
trace!("Random {}", ret);
return ret;
}
Err(err) => {
warn!("RDRand not supported."); warn!("RDRand not supported.");
// Try rdseed // Try rdseed
let gen = RdSeed::new(); match unsafe { _rdseed64_step(&mut out) } {
match gen { 1 => out,
Ok(gen) => { _ => panic!("Neither RDRand or RDSeed are supported"),
let ret = gen.try_next_u64().unwrap();
trace!("Random {}", ret);
return ret;
}
Err(err) => {
panic!("Neither RDRand or RDSeed are supported")
}
} }
} }
} }
@ -228,6 +210,7 @@ pub fn hardware_random_u64() -> u64 {
pub fn get_edid() {} pub fn get_edid() {}
#[allow(unused)]
pub fn register_dump() { pub fn register_dump() {
let rax: u64; let rax: u64;
let rbx: u64 = 0; let rbx: u64 = 0;

View file

@ -12,7 +12,8 @@ use crate::alloc::string::ToString;
/// Enumerate PCI devices and run initialisation routines on ones we support /// Enumerate PCI devices and run initialisation routines on ones we support
pub fn init(device_tree: &mut DeviceTree) { pub fn init(device_tree: &mut DeviceTree) {
device_tree.devices device_tree
.devices
.insert("Unidentified PCI".to_string(), alloc::vec![]); .insert("Unidentified PCI".to_string(), alloc::vec![]);
let mut devices = alloc::vec![]; let mut devices = alloc::vec![];
@ -23,6 +24,7 @@ pub fn init(device_tree: &mut DeviceTree) {
let id = device_info.device_id.id; let id = device_info.device_id.id;
use Vendor::*; use Vendor::*;
let (dev_type, dev_name) = match (vendor, id) { let (dev_type, dev_name) = match (vendor, id) {
(VMWareInc, 1029) => ("GPUs", "SVGAII PCI GPU"),
(Qemu, 4369) => ("GPUs", "QEMU VGA"), (Qemu, 4369) => ("GPUs", "QEMU VGA"),
(VirtIO, 4176) => ("GPUs", "VirtIO PCI GPU"), (VirtIO, 4176) => ("GPUs", "VirtIO PCI GPU"),
(CirrusLogic, 184) => ("GPUs", "Cirrus SVGA"), //GD 5446? (CirrusLogic, 184) => ("GPUs", "Cirrus SVGA"), //GD 5446?
@ -45,6 +47,7 @@ pub fn init(device_tree: &mut DeviceTree) {
pci_info.set_attribute("id", id); pci_info.set_attribute("id", id);
pci_info.set_attribute("device", device_info.device); pci_info.set_attribute("device", device_info.device);
pci_info.set_attribute("vendor", vendor); pci_info.set_attribute("vendor", vendor);
pci_info.set_attribute("bus", bus);
pci_info.set_attribute("class", device_info.full_class.to_string()); pci_info.set_attribute("class", device_info.full_class.to_string());
dev.set_child(pci_info); dev.set_child(pci_info);
devices.push((dev_type, dev)); devices.push((dev_type, dev));
@ -66,7 +69,8 @@ pub fn check_device(bus: u8, device: u8) -> Option<PciDeviceInfo> {
return None; return None;
} }
let reg2 = unsafe { pci_config_read(bus, device, 0, 0x8) }; let (reg2, addr) = unsafe { pci_config_read_2(bus, device, 0, 0x8) };
log::info!("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);
@ -269,8 +273,7 @@ impl Display for Vendor {
use core::fmt::Display; use core::fmt::Display;
use x86_64::instructions::port::Port; use {crate::device_tree::DeviceTree, x86_64::instructions::port::Port};
use crate::device_tree::DeviceTree;
#[allow(non_camel_case_types, dead_code)] #[allow(non_camel_case_types, dead_code)]
#[derive(Debug, Clone, Copy, PartialEq)] #[derive(Debug, Clone, Copy, PartialEq)]
@ -458,9 +461,7 @@ unsafe fn pci_config_read(bus: u8, device: u8, func: u8, offset: u8) -> u32 {
let func = func as u32; let func = func as u32;
let offset = offset as u32; let offset = offset as u32;
// construct address param // construct address param
let address = let address = (bus << 16) | (device << 11) | (func << 8) | (offset & 0xFC) | 0x8000_0000;
((bus << 16) | (device << 11) | (func << 8) | (offset & 0xFC) | 0x8000_0000) as u32;
// write address // write address
Port::new(0xCF8).write(address); Port::new(0xCF8).write(address);
@ -468,6 +469,20 @@ unsafe fn pci_config_read(bus: u8, device: u8, func: u8, offset: u8) -> u32 {
Port::new(0xCFC).read() Port::new(0xCFC).read()
} }
unsafe fn pci_config_read_2(bus: u8, device: u8, func: u8, offset: u8) -> (u32, u32) {
let bus = bus as u32;
let device = device as u32;
let func = func as u32;
let offset = offset as u32;
// construct address param
let address = (bus << 16) | (device << 11) | (func << 8) | (offset & 0xFC) | 0x8000_0000;
// write address
Port::new(0xCF8).write(address);
// read data
(Port::new(0xCFC).read(), address)
}
unsafe fn pci_config_write(bus: u8, device: u8, func: u8, offset: u8, value: u32) { unsafe fn pci_config_write(bus: u8, device: u8, func: u8, offset: u8, value: u32) {
let bus = bus as u32; let bus = bus as u32;
let device = device as u32; let device = device as u32;

View file

@ -1,36 +1,36 @@
use { use {
crate::alloc::string::ToString, // crate::alloc::string::ToString,
alloc::{string::String, vec::Vec}, alloc::vec::Vec,
clparse::Arguments, // clparse::Arguments,
core::fmt::{Debug, Display}, // core::fmt::{Debug, Display},
log::trace, // log::trace,
xml::XMLElement, // xml::XMLElement,
}; };
pub type BootModules = Vec<BootModule>; pub type BootModules<'a> = Vec<BootModule<'a>>;
pub struct BootModule { pub struct BootModule<'a> {
pub path: String, pub path: &'a str,
pub bytes: Vec<u8>, pub bytes: &'a [u8],
pub cmd: String, pub cmd: &'a str,
} }
impl BootModule { impl<'a> BootModule<'a> {
pub fn new(path: String, bytes: Vec<u8>, cmd: String) -> Self { pub fn new(path: &'a str, bytes: &'a [u8], cmd: &'a str) -> Self {
Self { path, bytes, cmd } Self { path, bytes, cmd }
} }
} }
pub fn build_cmd<T: Display + Debug>(name: T, cmdline: T) -> XMLElement { // pub fn build_cmd<T: Display + Debug>(name: T, cmdline: T) -> XMLElement {
let mut cmdline = cmdline.to_string(); // let mut cmdline = cmdline.to_string();
cmdline.pop(); // cmdline.pop();
cmdline.remove(0); // cmdline.remove(0);
let cmd = Arguments::parse(cmdline.to_string()).unwrap(); // let cmd = Arguments::parse(cmdline.to_string()).unwrap();
trace!("Cmdline: {cmd:?}"); // trace!("Cmdline: {cmd:?}");
let mut clo = XMLElement::new(name); // let mut clo = XMLElement::new(name);
for (key, value) in cmd.arguments { // for (key, value) in cmd.arguments {
clo.set_attribute(key, value); // clo.set_attribute(key, value);
} // }
trace!("command line object: {:?}", clo); // trace!("command line object: {:?}", clo);
clo // clo
} // }

View file

@ -6,6 +6,7 @@ use {
core::fmt, core::fmt,
hashbrown::HashMap, hashbrown::HashMap,
}; };
/// A device object. /// A device object.
/// TODO define device /// TODO define device
pub type Device = xml::XMLElement; pub type Device = xml::XMLElement;
@ -23,27 +24,29 @@ impl DeviceTree {
let mut dt = Self { let mut dt = Self {
devices: HashMap::new(), devices: HashMap::new(),
}; };
device_tree!(dt, [ device_tree!(
"Mice", dt,
"Keyboards", [
"Controllers", "Mice",
"Generic HIDs", "Keyboards",
"Disk Drives", "Controllers",
"CD Drives", "Generic HIDs",
"Batteries", "Disk Drives",
"Monitors", "CD Drives",
"GPUs", "Batteries",
"CPUs", "Monitors",
"USB", "GPUs",
"Serial Ports", "CPUs",
"Cameras", "USB",
"Biometric Devices", "Serial Ports",
]); "Cameras",
"Biometric Devices",
]
);
dt dt
} }
} }
use crate::{utils::TAB, device_tree}; use crate::{device_tree, tab, utils::TAB};
use crate::tab;
impl fmt::Display for DeviceTree { impl fmt::Display for DeviceTree {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
writeln!(f)?; writeln!(f)?;

35
kernel/src/exe_format.rs Normal file
View file

@ -0,0 +1,35 @@
enum Sections {
Header,
Code,
Data,
Debug,
Config,
Metadata,
}
// 64 byte header
#[repr(packed)]
struct AbleOsExecutableHeader {
magic_number: [u8; 3],
executable_version: u32,
code_length: u64,
data_length: u64,
debug_length: u64,
config_length: u64,
metadata_length: u64,
}
impl AbleOsExecutableHeader {
fn new() -> Self {
Self {
magic_number: [0x15, 0x91, 0xD2],
executable_version: 0,
code_length: 0,
config_length: 0,
data_length: 0,
debug_length: 0,
metadata_length: 0,
}
}
}

View file

@ -1,27 +1,21 @@
//! Environment call handling routines //! Environment call handling routines
use core::borrow::Borrow; use crate::holeybytes::kernel_services::{
block_read, dt_msg_handler::dt_msg_handler, logging_service::log_msg_handler,
use crate::{ service_definition_service::sds_msg_handler,
allocator,
holeybytes::kernel_services::{
block_read,
service_definition_service::{sds_msg_handler, SERVICES},
},
}; };
use { use {
super::{mem::Memory, Vm}, super::Vm,
crate::{arch, holeybytes::mem, ipc::buffer::IpcBuffer, kmain::IPC_BUFFERS}, crate::{arch, ipc::buffer::IpcBuffer, kmain::IPC_BUFFERS},
alloc::string::String, log::{debug, error, info, trace},
log::{debug, error, info, trace, warn},
}; };
pub fn handler(vm: &mut Vm) { pub fn handler(vm: &mut Vm) {
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); // debug!("Ecall number {:?}", ecall_number);
// trace!("Register dump: {:?}", vm.registers); //info!("Register dump: {:?}", vm.registers);
match ecall_number { match ecall_number {
0 => { 0 => {
@ -57,7 +51,7 @@ pub fn handler(vm: &mut Vm) {
}; };
let buff_id = arch::hardware_random_u64(); let buff_id = arch::hardware_random_u64();
buffs.insert(buff_id, abc); buffs.insert(buff_id, abc);
debug!("Buffer ID: {}", buff_id); info!("Buffer ID: {}", buff_id);
vm.registers[1] = hbvm::value::Value(buff_id); vm.registers[1] = hbvm::value::Value(buff_id);
} }
2 => { 2 => {
@ -74,11 +68,11 @@ pub fn handler(vm: &mut Vm) {
match buffer_id { match buffer_id {
0 => match sds_msg_handler(vm, mem_addr, length) { 0 => match sds_msg_handler(vm, mem_addr, length) {
Ok(()) => {} Ok(()) => {}
Err(err) => log::error!("Improper sds format"), Err(err) => log::error!("Improper sds format: {err:?}"),
}, },
1 => match log_msg_handler(vm, mem_addr, length) { 1 => match log_msg_handler(vm, mem_addr, length) {
Ok(()) => {} Ok(()) => {}
Err(err) => log::error!("Improper log format"), Err(_) => log::error!("Improper log format"),
}, },
2 => { 2 => {
use crate::holeybytes::kernel_services::mem_serve::memory_msg_handler; use crate::holeybytes::kernel_services::mem_serve::memory_msg_handler;
@ -86,25 +80,84 @@ pub fn handler(vm: &mut Vm) {
Ok(_) => {} Ok(_) => {}
Err(_) => {} Err(_) => {}
} }
//
} }
#[cfg(not(target_arch = "x86_64"))]
3 => info!("TODO: implement whatever buffer 3 does for no x86_64"),
#[cfg(target_arch = "x86_64")]
3 => {
unsafe fn x86_out<T: x86_64::instructions::port::PortWrite>(
address: u16,
value: T,
) {
x86_64::instructions::port::Port::new(address).write(value);
}
unsafe fn x86_in<T: x86_64::instructions::port::PortRead>(address: u16) -> T {
x86_64::instructions::port::Port::new(address).read()
}
let msg_vec = block_read(mem_addr, length);
let msg_type = msg_vec[0];
match msg_type {
0 => unsafe {
let size = msg_vec[1];
let addr = u16::from_le_bytes(msg_vec[2..4].try_into().unwrap());
let value = match size {
0 => x86_in::<u8>(addr) as u64,
1 => x86_in::<u16>(addr) as u64,
2 => x86_in::<u32>(addr) as u64,
_ => panic!("Trying to read size other than: 8, 16, 32 from port."),
};
// info!("Read the value {} from address {}", value, addr);
vm.registers[1] = hbvm::value::Value(value);
},
1 => unsafe {
let size = msg_vec[1];
let addr = u16::from_le_bytes(msg_vec[2..4].try_into().unwrap());
// info!("Setting address {}", addr);
match size {
0 => x86_out(addr, msg_vec[4]),
1 => x86_out(
addr,
u16::from_le_bytes(msg_vec[4..6].try_into().unwrap_unchecked()),
),
2 => x86_out(
addr,
u32::from_le_bytes(msg_vec[4..8].try_into().unwrap_unchecked()),
),
_ => panic!("How?"),
}
},
_ => {}
}
}
#[cfg(not(target_arch = "x86_64"))]
3 => unimplemented!("TODO: implement whatever buffer 3 does for no x86_64"),
// source of rng
4 => {
// limit to last 32 bits
vm.registers[1] =
hbvm::value::Value(crate::arch::hardware_random_u64() & 0xFFFFFFFF);
}
5 => match dt_msg_handler(vm, mem_addr, length) {
Ok(()) => {}
Err(_) => log::error!("Improper dt query"),
},
buffer_id => { buffer_id => {
let mut buffs = IPC_BUFFERS.lock(); let mut buffs = IPC_BUFFERS.lock();
match buffs.get_mut(&buffer_id) { match buffs.get_mut(&buffer_id) {
Some(buff) => { Some(buff) => {
let mut msg_vec = vec![]; let mut msg_vec = Vec::with_capacity(length);
for x in 0..(length as isize) { for x in 0..(length as isize) {
let xyz = mem_addr as *const u8; let xyz = mem_addr as *const u8;
let value = unsafe { xyz.offset(x).read() }; let value = unsafe { xyz.offset(x).read() };
msg_vec.push(value); msg_vec.push(value);
} }
buff.push(msg_vec.clone()); debug!(
info!(
"Message {:?} has been sent to Buffer({})", "Message {:?} has been sent to Buffer({})",
msg_vec, buffer_id msg_vec, buffer_id
); );
buff.push(msg_vec);
} }
None => { None => {
log::error!("Access of non-existent buffer {}", buffer_id) log::error!("Access of non-existent buffer {}", buffer_id)
@ -116,11 +169,37 @@ pub fn handler(vm: &mut Vm) {
} }
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 max_length = vm.registers[5].cast::<u64>();
let mut buffs = IPC_BUFFERS.lock(); let mut buffs = IPC_BUFFERS.lock();
let mut buff = buffs.get_mut(&buffer_id).unwrap(); let buff: &mut IpcBuffer;
let msg = buff.pop();
info!("Recieve {:?} from Buffer({})", msg, buffer_id); if buffs.get_mut(&buffer_id).is_some() {
buff = buffs.get_mut(&buffer_id).unwrap();
} else {
// info!("AHHH");
vm.registers[1] = hbvm::value::Value(0);
return;
}
let pop = buff.pop();
if pop.is_err() {
return;
}
let msg = pop.unwrap();
if msg.len() > max_length.try_into().unwrap() {
info!("{}", max_length);
error!("Message is too long to map in.");
} else {
unsafe {
let ptr: *mut u64 = &mut map_ptr;
for (index, byte) in msg.iter().enumerate() {
ptr.offset(index.try_into().unwrap()).write_bytes(*byte, 1);
}
}
debug!("Recieve {:?} from Buffer({})", msg, buffer_id);
}
} }
5 => { 5 => {
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
@ -132,50 +211,24 @@ pub fn handler(vm: &mut Vm) {
unsafe fn x86_out(address: u16, value: u32) { unsafe fn x86_out(address: u16, value: u32) {
x86_64::instructions::port::Port::new(address).write(value); x86_64::instructions::port::Port::new(address).write(value);
} }
vm.registers[3] = hbvm::value::Value(unsafe { x86_in(r2 as u16) } as u64); let x = hbvm::value::Value(unsafe { x86_in(r2 as u16) } as u64);
// info!("Read {:?} from Port {:?}", x, r2);
vm.registers[3] = x
} }
} }
// 5
_ => { _ => {
log::error!("Syscall unknown {:?}{:?}", ecall_number, vm.registers); log::error!("Syscall unknown {:?}{:?}", ecall_number, vm.registers);
} }
} }
} }
fn log_msg_handler(vm: &mut Vm, mem_addr: u64, length: usize) -> Result<(), LogError> {
// let message_length = 8 + 8 + 8;
// log::info!("Mem Addr 0x{:x?} length {}", mem_addr, length);
let mut msg_vec = block_read(mem_addr, length);
let log_level = msg_vec.pop().unwrap();
match String::from_utf8(msg_vec) {
Ok(strr) => {
// use LogLevel::*;
let ll = match log_level {
0 | 48 => error!("{}", strr),
1 | 49 => warn!("{}", strr),
2 | 50 => info!("{}", strr),
3 | 51 => debug!("{}", strr),
4 | 52 => trace!("{}", strr),
_ => {
return Err(LogError::InvalidLogFormat);
}
};
}
Err(e) => {
error!("{:?}", e);
}
}
Ok(())
}
#[derive(Debug)] #[derive(Debug)]
pub enum LogError { pub enum LogError {
NoMessages,
InvalidLogFormat, InvalidLogFormat,
} }
use {alloc::vec, log::Record};
// use {alloc::vec, log::Record};
// fn memory_msg_handler(vm: &mut Vm, mem_addr: u64, length: usize) -> Result<(), LogError> { // fn memory_msg_handler(vm: &mut Vm, mem_addr: u64, length: usize) -> Result<(), LogError> {
// let mut val = alloc::vec::Vec::new(); // let mut val = alloc::vec::Vec::new();
// for _ in 0..4096 { // for _ in 0..4096 {

View file

@ -0,0 +1,87 @@
use {
crate::holeybytes::{kernel_services::block_read, Vm},
alloc::{
string::{String, ToString},
vec::Vec,
},
};
pub enum DtError {
QueryFailure,
}
pub fn dt_msg_handler(vm: &mut Vm, mem_addr: u64, length: usize) -> Result<(), DtError> {
let msg_vec = block_read(mem_addr, length);
let mut bytes: Vec<u8> = Vec::new();
for byte in msg_vec {
if *byte == 0 {
break;
}
bytes.push(*byte)
}
let query_string = String::from_utf8(bytes).unwrap();
log::trace!("Query {}", query_string);
let ret = query_parse(query_string);
log::trace!("Query response {}", ret);
vm.registers[1] = hbvm::value::Value(ret);
Ok(())
}
fn query_parse(query_string: String) -> u64 {
let qt_parse_step_one = query_string.split("/");
let mut qt_parse_step_two: Vec<String> = Vec::new();
for a in qt_parse_step_one {
qt_parse_step_two.push(a.to_string());
}
let first_fragment: &str = &qt_parse_step_two[0];
let ret = match first_fragment {
"framebuffer" => framebuffer_parse(qt_parse_step_two),
"cpu" => cpu_parse(qt_parse_step_two),
_ => 0,
};
return ret;
}
fn cpu_parse(qt_parse_step_two: Vec<String>) -> u64 {
let second_fragment: &str = &qt_parse_step_two[1];
match second_fragment {
// "architecture" => {
// return 0;
// }
_ => {
return 0;
}
};
}
fn framebuffer_parse(qt_parse_step_two: Vec<String>) -> u64 {
use crate::kmain::FB_REQ;
let fbs = &FB_REQ.get_response().get().unwrap().framebuffers();
let second_fragment: &str = &qt_parse_step_two[1];
match second_fragment {
"fb0" => {
let fb_front = &fbs[0];
let third_fragment: &str = &qt_parse_step_two[2];
let ret = match third_fragment {
"ptr" => {
let ptr = fb_front.address.as_ptr().unwrap();
ptr as usize as u64
}
"width" => fb_front.width,
"height" => fb_front.height,
_ => 0,
};
return ret;
}
_ => {
return 0;
}
};
}

View file

@ -0,0 +1,49 @@
use crate::holeybytes::{kernel_services::block_read, Vm};
#[derive(Debug)]
pub enum LogError {
InvalidLogFormat,
}
use log::Record;
pub fn log_msg_handler(_vm: &mut Vm, mem_addr: u64, length: usize) -> Result<(), LogError> {
let msg_vec = block_read(mem_addr, length);
let log_level = msg_vec.last().unwrap();
let file_name = "None";
let line_number = 0;
match core::str::from_utf8(&msg_vec[..msg_vec.len()]) {
Ok(strr) => {
use log::Level::*;
let log_level = match log_level {
0 | 48 => Error,
1 | 49 => Warn,
2 | 50 => Info,
3 | 51 => Debug,
4 | 52 => Trace,
_ => {
return Err(LogError::InvalidLogFormat);
}
};
log::logger().log(
&Record::builder()
.args(format_args!("{}", strr))
.level(log_level)
.target("Userspace")
.file(Some(file_name))
.line(Some(line_number))
.module_path(Some(&file_name))
.build(),
);
}
Err(e) => {
log::error!("{:?}", e);
}
}
Ok(())
}

View file

@ -1,10 +1,7 @@
use { use {
crate::holeybytes::{ crate::holeybytes::{kernel_services::block_read, Vm},
ecah::LogError, alloc::alloc::{alloc, dealloc},
kernel_services::{block_read, mem_serve}, core::alloc::Layout,
Vm,
},
alloc::alloc::alloc_zeroed,
log::{debug, info}, log::{debug, info},
}; };
@ -19,13 +16,10 @@ pub enum MemoryQuotaType {
KillQuota = 3, KillQuota = 3,
} }
fn alloc_page(vm: &mut Vm, mem_addr: u64, length: usize) -> Result<(), MemoryServiceError> { fn alloc_page(vm: &mut Vm, _mem_addr: u64, _length: usize) -> Result<(), MemoryServiceError> {
let mut val = alloc::vec::Vec::new(); let ptr = unsafe { alloc(Layout::from_size_align_unchecked(4096, 4096)) };
for _ in 0..4096 { info!("Block address: {:?}", ptr);
val.push(0); vm.registers[1] = hbvm::value::Value(ptr as u64);
}
info!("Block address: {:?}", val.as_ptr());
vm.registers[1] = hbvm::value::Value(val.as_ptr() as u64);
vm.registers[2] = hbvm::value::Value(4096); vm.registers[2] = hbvm::value::Value(4096);
Ok(()) Ok(())
} }
@ -35,28 +29,39 @@ pub fn memory_msg_handler(
mem_addr: u64, mem_addr: u64,
length: usize, length: usize,
) -> Result<(), MemoryServiceError> { ) -> Result<(), MemoryServiceError> {
let mut msg_vec = block_read(mem_addr, length); let msg_vec = block_read(mem_addr, length);
let msg_type = msg_vec[0]; let msg_type = msg_vec[0];
msg_vec.remove(0);
match msg_type { match msg_type {
0 => { 0 => {
let page_count = msg_vec[0]; let page_count = msg_vec[1];
msg_vec.remove(0); let mptr_raw: [u8; 8] = msg_vec[2..10].try_into().unwrap();
let mptr: u64 = u64::from_le_bytes(mptr_raw);
// let mptr_raw: [u8; 8] = msg_vec[0..8].try_into().unwrap(); log::debug!("Allocating {} pages @ {:x}", page_count, mptr);
// let mptr: u64 = u64::from_le_bytes(mptr_raw);
// log::debug!("Allocating {} pages @ {}", page_count, mptr); let ptr = unsafe {
alloc(Layout::from_size_align_unchecked(
page_count as usize * 4096,
4096,
))
};
let mut val = alloc::vec::Vec::new(); vm.registers[1] = hbvm::value::Value(ptr as u64);
for _ in 0..(page_count as isize * 4096) { log::debug!("Kernel ptr: {:x}", ptr as u64);
val.push(0);
}
vm.registers[1] = hbvm::value::Value(val.as_ptr() as u64);
} }
1 => { 1 => {
let page_count = msg_vec[0]; let page_count = msg_vec[1];
msg_vec.remove(0);
let mptr_raw: [u8; 8] = msg_vec[2..10].try_into().unwrap();
let mptr: u64 = u64::from_le_bytes(mptr_raw);
log::debug!("Deallocating {} pages @ {:x}", page_count, mptr);
unsafe {
dealloc(
mptr as *mut u8,
Layout::from_size_align_unchecked(page_count as usize * 4096, 4096),
)
}
} }
2 => { 2 => {
use MemoryQuotaType::*; use MemoryQuotaType::*;
@ -67,25 +72,23 @@ pub fn memory_msg_handler(
3 => KillQuota, 3 => KillQuota,
_ => NoQuota, _ => NoQuota,
}; };
msg_vec.remove(0); let hid_raw: [u8; 8] = msg_vec[2..10].try_into().unwrap();
let hid_raw: [u8; 8] = msg_vec[0..8].try_into().unwrap();
let hid: u64 = u64::from_le_bytes(hid_raw); let hid: u64 = u64::from_le_bytes(hid_raw);
for _ in 0..8 { let pid_raw: [u8; 8] = msg_vec[10..18].try_into().unwrap();
msg_vec.remove(0); let pid: u64 = u64::from_le_bytes(pid_raw);
}
let pid_raw: [u8; 8] = msg_vec[0..8].try_into().unwrap();
let pid: u64 = u64::from_le_bytes(hid_raw);
for _ in 0..8 {
msg_vec.remove(0);
}
debug!( debug!(
"Setting HID-{:x}:PID-{:x}'s quota type to {:?}", "Setting HID-{:x}:PID-{:x}'s quota type to {:?}",
hid, pid, quota_type hid, pid, quota_type
) )
} }
_ => {} 3 => {
let page_count = msg_vec[0];
log::debug!(" {} pages", page_count);
}
_ => {
log::debug!("Unknown memory service message type: {}", msg_type);
}
} }
Ok(()) Ok(())

View file

@ -1,15 +1,11 @@
use alloc::{vec, vec::Vec}; use core::slice;
pub mod dt_msg_handler;
pub mod logging_service;
pub mod mem_serve; pub mod mem_serve;
pub mod service_definition_service; pub mod service_definition_service;
pub fn block_read(mem_addr: u64, length: usize) -> Vec<u8> { #[inline(always)]
let mut msg_vec = vec![]; pub fn block_read<'a>(mem_addr: u64, length: usize) -> &'a mut [u8] {
unsafe { slice::from_raw_parts_mut(mem_addr as *mut _, length) }
for x in 0..(length as isize) {
let xyz = mem_addr as *const u8;
let value = unsafe { xyz.offset(x).read() };
msg_vec.push(value);
}
msg_vec
} }

View file

@ -1,35 +1,45 @@
use { use {
crate::{ crate::{
alloc::string::ToString,
arch::hardware_random_u64, arch::hardware_random_u64,
holeybytes::{ecah::LogError, kernel_services::block_read, Vm}, holeybytes::{kernel_services::block_read, Vm},
ipc::{protocol, protocol::Protocol}, ipc::{buffer::IpcBuffer, protocol::Protocol},
kmain::IPC_BUFFERS,
}, },
alloc::string::String,
hashbrown::HashMap, hashbrown::HashMap,
log::info, log::{info, trace},
spin::{lazy::Lazy, Mutex}, spin::{lazy::Lazy, Mutex},
}; };
pub struct Services(HashMap<u64, Protocol>); pub struct Services<'a>(HashMap<u64, Protocol<'a>>);
pub static SERVICES: Lazy<Mutex<Services>> = Lazy::new(|| { pub static SERVICES: Lazy<Mutex<Services>> = Lazy::new(|| {
let mut dt = Services(HashMap::new()); let mut dt = Services(HashMap::new());
dt.0.insert(0, Protocol::void()); dt.0.insert(0, Protocol::void());
Mutex::new(dt) Mutex::new(dt)
}); });
#[derive(Debug)]
pub fn sds_msg_handler(vm: &mut Vm, mem_addr: u64, length: usize) -> Result<(), LogError> { pub enum ServiceError {
let mut msg_vec = block_read(mem_addr, length); InvalidFormat,
}
pub fn sds_msg_handler(vm: &mut Vm, mem_addr: u64, length: usize) -> Result<(), ServiceError> {
let msg_vec = block_read(mem_addr, length);
let sds_event_type: ServiceEventType = msg_vec[0].into(); let sds_event_type: ServiceEventType = msg_vec[0].into();
msg_vec.remove(0);
// info!("Length {}", msg_vec.len());
use ServiceEventType::*; use ServiceEventType::*;
match sds_event_type { match sds_event_type {
CreateService => { CreateService => {
let string = String::from_utf8(msg_vec).expect("Our bytes should be valid utf8"); let string =
sds_create_service(string); core::str::from_utf8(&msg_vec[1..]).expect("Our bytes should be valid utf8");
let ret = sds_create_service(string);
vm.registers[1] = hbvm::value::Value(ret as u64);
} }
DeleteService => todo!(), DeleteService => todo!(),
SearchServices => todo!(), SearchServices => {
let string =
core::str::from_utf8(&msg_vec[1..]).expect("Our bytes should be valid utf8");
let ret = sds_search_service(string);
vm.registers[1] = hbvm::value::Value(ret as u64);
}
} }
// let buffer_id_raw = &msg_vec[0..8]; // let buffer_id_raw = &msg_vec[0..8];
// let mut arr = [0u8; 8]; // let mut arr = [0u8; 8];
@ -59,16 +69,41 @@ impl From<u8> for ServiceEventType {
// 1 => // 1 =>
2 => Self::DeleteService, 2 => Self::DeleteService,
3 => Self::SearchServices, 3 => Self::SearchServices,
10 => {
info!("TEST");
panic!()
}
1_u8 | 4_u8..=u8::MAX => todo!(), 1_u8 | 4_u8..=u8::MAX => todo!(),
} }
} }
} }
fn sds_create_service(protocol: String) -> u64 { fn sds_create_service(protocol: &'static str) -> u64 {
let buff_id = hardware_random_u64(); let buff_id = hardware_random_u64();
let mut services = SERVICES.lock(); let mut services = SERVICES.lock();
services.0.insert(buff_id, protocol.clone().into()); let mut buffers = IPC_BUFFERS.lock();
info!("BufferID({}) => {}", buff_id, protocol);
let a: protocol::Protocol = protocol.into(); let protocol_ = Protocol::from(protocol);
let mut buff = IpcBuffer::new(false, 0);
services.0.insert(buff_id, protocol_.clone());
buff.protocol = protocol_;
buffers.insert(buff_id, buff);
trace!("BufferID({}) => {}", buff_id, protocol);
// let a: protocol::Protocol = protocol.into();
buff_id buff_id
} }
fn sds_search_service(protocol: &str) -> u64 {
let services = SERVICES.lock();
let compare = Protocol::from(protocol);
for (bid, protocol_canidate) in &services.0 {
trace!("BID-{bid} protocol_canidate {:?}", protocol_canidate);
if protocol_canidate == &compare {
trace!("BufferID({}) => {}", bid, protocol);
return *bid;
}
}
0
}

View file

@ -7,7 +7,7 @@
use hbvm::mem::Address; use hbvm::mem::Address;
fn calc_start_of_page(ptr: u64) -> u64 { fn calc_start_of_page(ptr: u64) -> u64 {
let mut page_aligned = false; let _page_aligned = false;
if ptr % 4096 == 0 { if ptr % 4096 == 0 {
// page_aligned = true; // page_aligned = true;
return ptr / 4096; return ptr / 4096;
@ -21,11 +21,11 @@ pub struct Memory {
impl Memory { impl Memory {
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
fn read_device(addr: Address) { fn read_device(_addr: Address) {
unsafe { //unsafe {
// //
// x86_64::instructions::port::Port::new(addr.get()).read() // x86_64::instructions::port::Port::new(addr.get()).read()
} //}
} }
} }
@ -37,7 +37,6 @@ impl hbvm::mem::Memory for Memory {
target: *mut u8, target: *mut u8,
count: usize, count: usize,
) -> Result<(), hbvm::mem::LoadError> { ) -> Result<(), hbvm::mem::LoadError> {
use log::{error, info};
if addr.get() % 4096 == 0 {} if addr.get() % 4096 == 0 {}
core::ptr::copy(addr.get() as *const u8, target, count); core::ptr::copy(addr.get() as *const u8, target, count);
Ok(()) Ok(())
@ -56,6 +55,6 @@ impl hbvm::mem::Memory for Memory {
#[inline] #[inline]
unsafe fn prog_read<T: Copy>(&mut self, addr: Address) -> T { unsafe fn prog_read<T: Copy>(&mut self, addr: Address) -> T {
(addr.get() as *const T).read_unaligned() (addr.get() as *const T).read()
} }
} }

View file

@ -3,68 +3,62 @@ mod kernel_services;
mod mem; mod mem;
use { use {
crate::{arch, ipc::buffer::IpcBuffer, kmain::IPC_BUFFERS}, alloc::alloc::{alloc, dealloc},
alloc::boxed::Box, core::{
core::{default, future::Future, marker::PhantomData, ptr::NonNull, task::Poll}, alloc::Layout,
future::Future,
pin::Pin,
task::{Context, Poll},
},
hbvm::{ hbvm::{
mem::{ mem::{softpaging::HandlePageFault, Address},
softpaging::{icache::ICache, HandlePageFault, SoftPagedMem},
Address, Memory,
},
VmRunError, VmRunOk, VmRunError, VmRunOk,
}, },
log::{debug, error, info, trace, warn}, log::error,
}; };
const STACK_SIZE: usize = 1024 * 1024; const STACK_SIZE: usize = 1024 * 1024;
const TIMER_QUOTIENT: usize = 100; const TIMER_QUOTIENT: usize = 1000;
type Vm = hbvm::Vm<mem::Memory, TIMER_QUOTIENT>; type Vm = hbvm::Vm<mem::Memory, TIMER_QUOTIENT>;
pub struct ExecThread<'p> { pub struct ExecThread {
vm: Vm, vm: Vm,
stack_bottom: *mut u8, stack_bottom: *mut u8,
_phantom: PhantomData<&'p [u8]>,
} }
unsafe impl<'p> Send for ExecThread<'p> {} unsafe impl Send for ExecThread {}
impl<'p> ExecThread<'p> {
impl ExecThread {
pub fn set_arguments(&mut self, ptr: u64, length: u64) { pub fn set_arguments(&mut self, ptr: u64, length: u64) {
self.vm.registers[1] = hbvm::value::Value(ptr); self.vm.registers[1] = hbvm::value::Value(ptr);
self.vm.registers[2] = hbvm::value::Value(length); self.vm.registers[2] = hbvm::value::Value(length);
} }
pub unsafe fn new(program: &'p [u8], entrypoint: Address) -> Self { pub unsafe fn new(program: &[u8], entrypoint: Address) -> Self {
let mut vm = unsafe { let mut vm = Vm::new(
Vm::new( mem::Memory {},
mem::Memory {}, Address::new(program.as_ptr() as u64 + entrypoint.get()),
Address::new(program.as_ptr() as u64 + entrypoint.get()), );
)
}; let stack_bottom = allocate_stack();
let stack_bottom = unsafe { allocate_stack().as_ptr() };
vm.write_reg(254, (stack_bottom as usize + STACK_SIZE - 1) as u64); vm.write_reg(254, (stack_bottom as usize + STACK_SIZE - 1) as u64);
ExecThread { ExecThread { vm, stack_bottom }
vm,
stack_bottom,
_phantom: Default::default(),
}
} }
} }
impl<'p> Drop for ExecThread<'p> { impl<'p> Drop for ExecThread {
fn drop(&mut self) { fn drop(&mut self) {
unsafe { alloc::alloc::dealloc(self.stack_bottom, stack_layout()) }; unsafe { dealloc(self.stack_bottom, stack_layout()) };
} }
} }
impl<'p> Future for ExecThread<'p> { impl<'p> Future for ExecThread {
type Output = Result<(), VmRunError>; type Output = Result<(), VmRunError>;
fn poll( #[inline(always)]
mut self: core::pin::Pin<&mut Self>, fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
cx: &mut core::task::Context<'_>,
) -> Poll<Self::Output> {
match self.vm.run() { match self.vm.run() {
Err(err) => { Err(err) => {
log::error!("HBVM Error\r\nRegister dump: {:?}", self.vm.registers,); log::error!("HBVM Error\r\nRegister dump: {:?}", self.vm.registers,);
@ -91,33 +85,22 @@ impl HandlePageFault for PageFaultHandler {
fn page_fault( fn page_fault(
&mut self, &mut self,
reason: hbvm::mem::MemoryAccessReason, reason: hbvm::mem::MemoryAccessReason,
pagetable: &mut hbvm::mem::softpaging::paging::PageTable, _pagetable: &mut hbvm::mem::softpaging::paging::PageTable,
vaddr: hbvm::mem::Address, vaddr: hbvm::mem::Address,
size: hbvm::mem::softpaging::PageSize, size: hbvm::mem::softpaging::PageSize,
dataptr: *mut u8, dataptr: *mut u8,
) -> bool ) -> bool {
where error!("REASON: {reason} vaddr: {vaddr} size: {size:?} Dataptr {dataptr:p}");
Self: Sized,
{
log::error!(
"REASON: {reason} \
vaddr: {vaddr} \
size: {size:?} \
Dataptr {dataptr:p}",
);
false false
} }
} }
const fn stack_layout() -> core::alloc::Layout { #[inline(always)]
unsafe { alloc::alloc::Layout::from_size_align_unchecked(STACK_SIZE, 4096) } const fn stack_layout() -> Layout {
unsafe { Layout::from_size_align_unchecked(STACK_SIZE, 4096) }
} }
fn allocate_stack() -> NonNull<u8> { #[inline(always)]
let layout = stack_layout(); fn allocate_stack() -> *mut u8 {
match NonNull::new(unsafe { alloc::alloc::alloc_zeroed(layout) }) { unsafe { alloc(stack_layout()) }
Some(ptr) => ptr,
None => alloc::alloc::handle_alloc_error(layout),
}
} }

View file

@ -9,12 +9,12 @@ pub enum BufferTypes {
Bound(ArrayQueue<Message>), Bound(ArrayQueue<Message>),
} }
/// Interproccess buffer /// Interproccess buffer
pub struct IpcBuffer { pub struct IpcBuffer<'a> {
pub protocol: Protocol, pub protocol: Protocol<'a>,
pub buffer: BufferTypes, pub buffer: BufferTypes,
} }
impl IpcBuffer { impl<'a> IpcBuffer<'a> {
pub fn new(bounded: bool, length: u64) -> Self { pub fn new(bounded: bool, length: u64) -> Self {
log::debug!( log::debug!(
"New IPCBuffer\r "New IPCBuffer\r
@ -23,9 +23,8 @@ impl IpcBuffer {
bounded, bounded,
length length
); );
match (bounded, length) { match (bounded, length) {
(false, a) => { (false, ..) => {
let buftype = BufferTypes::Unbound(SegQueue::new()); let buftype = BufferTypes::Unbound(SegQueue::new());
Self { Self {
@ -49,25 +48,27 @@ impl IpcBuffer {
} }
pub fn push(&mut self, msg: Message) { pub fn push(&mut self, msg: Message) {
match &self.buffer { match &self.buffer {
BufferTypes::Unbound(buff) => buff.push(msg.clone()), BufferTypes::Unbound(buff) => buff.push(msg),
BufferTypes::Bound(buff) => { BufferTypes::Bound(buff) => {
let _ = buff.push(msg.clone()); let _ = buff.push(msg);
} }
}; };
} }
pub fn pop(&mut self) -> Message { pub fn pop(&mut self) -> Result<Message, IpcError> {
let msg = match &self.buffer { let msg = match &self.buffer {
BufferTypes::Unbound(buff) => buff.pop(), BufferTypes::Unbound(buff) => buff.pop(),
BufferTypes::Bound(buff) => buff.pop(), BufferTypes::Bound(buff) => buff.pop(),
}; };
match msg { match msg {
Some(msg) => return msg, Some(msg) => return Ok(msg),
None => panic!("Recieving msg error. No messages!"), None => return Err(IpcError::NoMessagesInBuffer),
} }
} }
} }
/// Interprocess Communication Errors /// Interprocess Communication Errors
#[derive(Debug)]
pub enum IpcError { pub enum IpcError {
/// An invalid message error returned to the sender /// An invalid message error returned to the sender
InvalidMessage, InvalidMessage,
NoMessagesInBuffer,
} }

View file

@ -1,20 +1,20 @@
use { use {
alloc::{string::String, vec::Vec}, alloc::{string::String, vec::Vec},
hashbrown::HashMap, hashbrown::HashMap,
log::info,
}; };
#[derive(Debug, PartialEq, Clone)]
pub struct Type {} pub struct Type {}
#[derive(Debug, PartialEq, Clone)]
pub struct Funct { pub struct Funct {
takes: Vec<String>, takes: Vec<String>,
gives: Vec<String>, gives: Vec<String>,
} }
#[derive(Debug, PartialEq, Clone)]
pub struct Protocol { pub struct Protocol<'a> {
types: HashMap<String, Type>, types: HashMap<&'a str, Type>,
fns: HashMap<String, Funct>, fns: HashMap<&'a str, Funct>,
} }
impl Protocol { impl<'a> Protocol<'a> {
pub fn void() -> Self { pub fn void() -> Self {
Self { Self {
types: HashMap::new(), types: HashMap::new(),
@ -27,13 +27,12 @@ impl Protocol {
} }
} }
impl From<String> for Protocol { impl<'a> From<&'a str> for Protocol<'a> {
fn from(value: alloc::string::String) -> Self { fn from(value: &'a str) -> Self {
if value.starts_with("protocol") { let mut hm_t = HashMap::new();
info!("ABC"); hm_t.insert(value, Type {});
}
Self { Self {
types: HashMap::new(), types: hm_t,
fns: HashMap::new(), fns: HashMap::new(),
} }
} }

View file

@ -2,27 +2,25 @@
use { use {
crate::{ crate::{
arch::{hardware_random_u64, logging::SERIAL_CONSOLE}, arch::hardware_random_u64,
bootmodules::{build_cmd, BootModules}, bootmodules::BootModules,
capabilities, //bootmodules::build_cmd,
device_tree::DeviceTree, device_tree::DeviceTree,
holeybytes::ExecThread, holeybytes::ExecThread,
ipc::buffer::{self, IpcBuffer}, ipc::buffer::IpcBuffer,
}, },
alloc::format,
hashbrown::HashMap, hashbrown::HashMap,
hbvm::mem::Address, hbvm::mem::Address,
limine::{Framebuffer, FramebufferRequest, NonNullPtr}, limine::{Framebuffer, FramebufferRequest, NonNullPtr},
log::{debug, info, trace}, log::{debug, error, trace},
spin::{Lazy, Mutex}, spin::{Lazy, Mutex},
xml::XMLElement,
}; };
pub fn kmain(cmdline: &str, boot_modules: BootModules) -> ! { pub fn kmain(_cmdline: &str, boot_modules: BootModules) -> ! {
debug!("Entered kmain"); debug!("Entered kmain");
let kcmd = build_cmd("Kernel Command Line", cmdline); // let kcmd = build_cmd("Kernel Command Line", cmdline);
trace!("Cmdline: {kcmd:?}"); // trace!("Cmdline: {kcmd:?}");
// for (i, bm) in boot_modules.iter().enumerate() { // for (i, bm) in boot_modules.iter().enumerate() {
// let name = format!("module-{}", i); // let name = format!("module-{}", i);
@ -38,9 +36,9 @@ pub fn kmain(cmdline: &str, boot_modules: BootModules) -> ! {
let dt = DEVICE_TREE.lock(); let dt = DEVICE_TREE.lock();
// TODO(Able): This line causes a deadlock // TODO(Able): This line causes a deadlock
info!("Device Tree: {}", dt); debug!("Device Tree: {}", dt);
info!("Boot complete. Moving to init_system"); trace!("Boot complete. Moving to init_system");
// TODO: schedule the disk driver from the initramfs // TODO: schedule the disk driver from the initramfs
// TODO: schedule the filesystem driver from the initramfs // TODO: schedule the filesystem driver from the initramfs
@ -58,43 +56,57 @@ pub fn kmain(cmdline: &str, boot_modules: BootModules) -> ! {
disp.set_attribute("width", fb1.width); disp.set_attribute("width", fb1.width);
disp.set_attribute("height", fb1.height); disp.set_attribute("height", fb1.height);
disp.set_attribute("bits per pixel", fb1.bpp); disp.set_attribute("bpp", fb1.bpp);
disp.set_attribute("pitch", fb1.pitch); disp.set_attribute("pitch", fb1.pitch);
dt.devices.insert("Displays".to_string(), alloc::vec![disp]); dt.devices.insert("Displays".to_string(), alloc::vec![disp]);
} }
log::info!("Graphics initialised"); debug!("Graphics initialised");
log::info!( debug!(
"Graphics front ptr {:?}", "Graphics front ptr {:?}",
fb1.address.as_ptr().unwrap() as *const u8 fb1.address.as_ptr().unwrap() as *const u8
); );
let mut executor = crate::task::Executor::default(); let mut executor = crate::task::Executor::new(256);
let bm_take = boot_modules.len();
unsafe { unsafe {
for module in boot_modules.into_iter().take(bm_take) { for module in boot_modules.iter() {
let mut cmd = module.cmd; let cmd = module.cmd.trim_matches('"');
if cmd.len() > 2 { let cmd_len = cmd.len() as u64;
// Remove the quotes
cmd.remove(0);
cmd.pop();
}
let cmd_len = cmd.as_bytes().len() as u64;
log::info!("Spawning {} with arguments \"{}\"", module.path, cmd); log::info!("Spawning {} with arguments \"{}\"", module.path, cmd);
executor.spawn(async move { // decode AbleOS Executable format
let mut thr = ExecThread::new(&module.bytes, Address::new(0)); let header = &module.bytes[0..46];
if cmd_len > 0 { let magic_slice = &header[0..3];
thr.set_arguments(cmd.as_bytes().as_ptr() as u64, cmd_len); if magic_slice != [0x15, 0x91, 0xD2] {
} log::error!("Invalid magic number at the start of executable.");
continue;
}
let executable_format_version = u32::from_le_bytes(header[3..7].try_into().unwrap());
let offset = if executable_format_version == 0 {
47
} else {
error!("Invalid executable format.");
continue;
};
let code_length = u64::from_le_bytes(header[7..15].try_into().unwrap());
let data_length = u64::from_le_bytes(header[15..23].try_into().unwrap());
let end = (code_length + data_length) as usize;
log::info!("{code_length} + {data_length} = {end}");
let mut thr = ExecThread::new(&module.bytes[offset..end], Address::new(0));
if cmd_len > 0 {
thr.set_arguments(cmd.as_ptr() as u64, cmd_len);
}
executor.spawn(async move {
if let Err(e) = thr.await { if let Err(e) = thr.await {
log::error!("{e:?}"); log::error!("{e:?}");
} }
}); })
} }
info!("Random number: {}", hardware_random_u64()); debug!("Random number: {}", hardware_random_u64());
executor.run(); executor.run();
}; };
@ -108,8 +120,7 @@ pub static DEVICE_TREE: Lazy<Mutex<DeviceTree>> = Lazy::new(|| {
}); });
pub static FB_REQ: FramebufferRequest = FramebufferRequest::new(0); pub static FB_REQ: FramebufferRequest = FramebufferRequest::new(0);
use alloc::vec::Vec; pub type IpcBuffers<'a> = HashMap<u64, IpcBuffer<'a>>;
pub type IpcBuffers = HashMap<u64, IpcBuffer>;
pub static IPC_BUFFERS: Lazy<Mutex<IpcBuffers>> = Lazy::new(|| { pub static IPC_BUFFERS: Lazy<Mutex<IpcBuffers>> = Lazy::new(|| {
let mut bufs = HashMap::new(); let mut bufs = HashMap::new();
let log_buffer = IpcBuffer::new(false, 0); let log_buffer = IpcBuffer::new(false, 0);

View file

@ -1,21 +1,20 @@
//! The ableOS kernel. //! The ableOS kernel.
//! Named akern. //! Named akern.
//! Akern is woefully undersupported at the moment but we are looking to add support improve hardware discovery and make our lives as kernel and operating system developers easier and better //! Akern is woefully undersupported at the moment but we are looking to add support improve hardware discovery and make our lives as kernel and operating system developers easier and better
#![no_std] #![no_std]
#![feature( #![feature(
exclusive_wrapper,
new_uninit,
abi_x86_interrupt, abi_x86_interrupt,
alloc_error_handler, alloc_error_handler,
inline_const,
panic_info_message,
pointer_is_aligned,
ptr_sub_ptr, ptr_sub_ptr,
custom_test_frameworks, custom_test_frameworks,
naked_functions, naked_functions,
pointer_is_aligned_to pointer_is_aligned_to
)] )]
#![allow(dead_code)]
#![test_runner(crate::test_runner)] #![test_runner(crate::test_runner)]
#![cfg_attr(not(debug_assertions), allow(unused, deprecated))]
#![allow(dead_code)]
extern crate alloc; extern crate alloc;
mod allocator; mod allocator;
@ -23,6 +22,7 @@ mod arch;
mod bootmodules; mod bootmodules;
mod capabilities; mod capabilities;
mod device_tree; mod device_tree;
mod exe_format;
mod handle; mod handle;
mod holeybytes; mod holeybytes;
mod ipc; mod ipc;
@ -42,6 +42,7 @@ pub const VERSION: Version = Version {
}; };
#[panic_handler] #[panic_handler]
#[cfg(target_os = "none")]
fn panic(info: &core::panic::PanicInfo) -> ! { fn panic(info: &core::panic::PanicInfo) -> ! {
arch::register_dump(); arch::register_dump();
@ -54,10 +55,8 @@ fn panic(info: &core::panic::PanicInfo) -> ! {
)); ));
} }
if let Some(msg) = info.message() { let msg = info.message();
let _ = crate::arch::log(format_args!("{msg}\r\n")); let _ = crate::arch::log(format_args!("{msg}\r\n"));
}
loop {} loop {}
} }

View file

@ -1,3 +1,4 @@
#![allow(deprecated)]
// TODO: Add a logger api with logger levels and various outputs // TODO: Add a logger api with logger levels and various outputs
pub static TERMINAL_LOGGER: Lazy<Mutex<TermLogger>> = Lazy::new(|| Mutex::new(TermLogger::new())); pub static TERMINAL_LOGGER: Lazy<Mutex<TermLogger>> = Lazy::new(|| Mutex::new(TermLogger::new()));
@ -9,7 +10,11 @@ use {
pub fn init() -> Result<(), SetLoggerError> { pub fn init() -> Result<(), SetLoggerError> {
log::set_logger(&crate::logger::Logger)?; log::set_logger(&crate::logger::Logger)?;
log::set_max_level(log::LevelFilter::Debug); if cfg!(debug_assertions) {
log::set_max_level(log::LevelFilter::Debug);
} else {
log::set_max_level(log::LevelFilter::Info);
}
Lazy::force(&TERMINAL_LOGGER); Lazy::force(&TERMINAL_LOGGER);

View file

@ -1,7 +1,6 @@
//! The Memory Manager //! The Memory Manager
use alloc::collections::VecDeque; use {alloc::collections::VecDeque, derive_more::*};
use derive_more::*;
pub use crate::arch::PAGE_SIZE; pub use crate::arch::PAGE_SIZE;
pub const MAX_ORDER: usize = 10; pub const MAX_ORDER: usize = 10;
@ -44,7 +43,7 @@ pub const MAX_ORDER: usize = 10;
Sum, Sum,
UpperHex, UpperHex,
)] )]
#[display(fmt = "0x{:x}", _0)] #[display("0x{:x}", _0)]
#[from(forward)] #[from(forward)]
pub struct VirtualAddress(usize); pub struct VirtualAddress(usize);
@ -55,11 +54,11 @@ impl VirtualAddress {
pub fn vpns(&self) -> [usize; 3] { pub fn vpns(&self) -> [usize; 3] {
[ [
// [20:12] // [20:12]
(self.0 >> 12) & 0x1ff, (self.0 >> 12) & 0x1FF,
// [29:21] // [29:21]
(self.0 >> 21) & 0x1ff, (self.0 >> 21) & 0x1FF,
// [38:30] // [38:30]
(self.0 >> 30) & 0x1ff, (self.0 >> 30) & 0x1FF,
] ]
} }
@ -114,7 +113,7 @@ impl VirtualAddress {
Sum, Sum,
UpperHex, UpperHex,
)] )]
#[display(fmt = "0x{:x}", _0)] #[display("0x{:x}", _0)]
#[from(forward)] #[from(forward)]
pub struct PhysicalAddress(usize); pub struct PhysicalAddress(usize);
@ -125,11 +124,11 @@ impl PhysicalAddress {
pub fn ppns(&self) -> [usize; 3] { pub fn ppns(&self) -> [usize; 3] {
[ [
// [20:12] // [20:12]
(self.0 >> 12) & 0x1ff, (self.0 >> 12) & 0x1FF,
// [29:21] // [29:21]
(self.0 >> 21) & 0x1ff, (self.0 >> 21) & 0x1FF,
// [55:30] // [55:30]
(self.0 >> 30) & 0x3ffffff, (self.0 >> 30) & 0x3FFFFFF,
] ]
} }

View file

@ -1,31 +1,20 @@
#![allow(unused)]
use { use {
alloc::{boxed::Box, collections::BTreeMap, sync::Arc, task::Wake}, alloc::{boxed::Box, sync::Arc},
core::{ core::{
future::Future, future::Future,
pin::Pin, pin::Pin,
task::{Context, Poll, Waker}, task::{Context, Poll, RawWaker, RawWakerVTable, Waker},
}, },
crossbeam_queue::SegQueue, crossbeam_queue::SegQueue,
kiam::when,
slab::Slab, slab::Slab,
spin::RwLock,
}; };
static SPAWN_QUEUE: RwLock<Option<SpawnQueue>> = RwLock::new(None);
pub fn spawn(future: impl Future<Output = ()> + Send + 'static) {
match &*SPAWN_QUEUE.read() {
Some(s) => s.push(Task::new(future)),
None => panic!("no task executor is running"),
}
}
pub fn yield_now() -> impl Future<Output = ()> { pub fn yield_now() -> impl Future<Output = ()> {
struct YieldNow(bool); struct YieldNow(bool);
impl Future for YieldNow { impl Future for YieldNow {
type Output = (); type Output = ();
#[inline(always)]
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
if self.0 { if self.0 {
Poll::Ready(()) Poll::Ready(())
@ -40,101 +29,150 @@ pub fn yield_now() -> impl Future<Output = ()> {
YieldNow(false) YieldNow(false)
} }
#[derive(Default)] pub struct Executor<F: Future<Output = ()> + Send> {
pub struct Executor { tasks: Slab<Task<F>>,
tasks: Slab<Task>, task_queue: Arc<TaskQueue>,
queue: TaskQueue,
to_spawn: SpawnQueue,
wakers: BTreeMap<TaskId, Waker>,
} }
impl Executor { impl<F: Future<Output = ()> + Send> Executor<F> {
pub fn spawn(&mut self, future: impl Future<Output = ()> + Send + 'static) { pub fn new(size: usize) -> Self {
self.queue Self {
.push(TaskId(self.tasks.insert(Task::new(future)))); tasks: Slab::with_capacity(size),
task_queue: Arc::new(TaskQueue::new()),
}
}
#[inline]
pub fn spawn(&mut self, future: F) {
self.task_queue
.queue
.push(self.tasks.insert(Task::new(future)));
} }
pub fn run(&mut self) { pub fn run(&mut self) {
{ let mut task_batch = [0; 32];
let mut global_spawner = SPAWN_QUEUE.write(); let mut batch_len = 0;
if global_spawner.is_some() {
panic!("Task executor is already running");
}
*global_spawner = Some(Arc::clone(&self.to_spawn));
}
loop { loop {
when! { self.task_queue.batch_pop(&mut task_batch, &mut batch_len);
let Some(id) = self
.to_spawn
.pop()
.map(|t| TaskId(self.tasks.insert(t)))
.or_else(|| self.queue.pop())
=> {
let Some(task) = self.tasks.get_mut(id.0) else {
panic!("Attempted to get task from empty slot: {}", id.0);
};
let mut cx = Context::from_waker(self.wakers.entry(id).or_insert_with(|| { if batch_len == 0 {
Waker::from(Arc::new(TaskWaker { if self.task_queue.is_empty() {
id, break;
queue: Arc::clone(&self.queue), } else {
})) continue;
})); }
}
match task.poll(&mut cx) { for &id in &task_batch[..batch_len] {
Poll::Ready(()) => { if let Some(task) = self.tasks.get_mut(id) {
self.tasks.remove(id.0); let waker = task
self.wakers.remove(&id); .waker
} .get_or_insert_with(|| TaskWaker::new(id, Arc::clone(&self.task_queue)));
Poll::Pending => (),
let waker = unsafe { Waker::from_raw(TaskWaker::into_raw_waker(waker)) };
let mut cx = Context::from_waker(&waker);
if let Poll::Ready(()) = task.poll(&mut cx) {
self.tasks.remove(id);
self.task_queue.free_tasks.push(id);
} }
}, }
self.tasks.is_empty() => break,
_ => (),
} }
} }
*SPAWN_QUEUE.write() = None;
} }
} }
struct Task { struct Task<F: Future<Output = ()> + Send> {
future: Pin<Box<dyn Future<Output = ()> + Send>>, future: Pin<Box<F>>,
waker: Option<TaskWaker>,
} }
impl Task { impl<F: Future<Output = ()> + Send> Task<F> {
pub fn new(future: impl Future<Output = ()> + Send + 'static) -> Self { #[inline(always)]
log::trace!("New task scheduled"); pub fn new(future: F) -> Self {
Self { Self {
future: Box::pin(future), future: Box::pin(future),
waker: None,
} }
} }
#[inline(always)]
fn poll(&mut self, cx: &mut Context) -> Poll<()> { fn poll(&mut self, cx: &mut Context) -> Poll<()> {
self.future.as_mut().poll(cx) self.future.as_mut().poll(cx)
} }
} }
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
struct TaskId(usize);
type TaskQueue = Arc<SegQueue<TaskId>>;
type SpawnQueue = Arc<SegQueue<Task>>;
struct TaskWaker { struct TaskWaker {
id: TaskId, id: usize,
queue: TaskQueue, task_queue: Arc<TaskQueue>,
} }
impl Wake for TaskWaker { impl TaskWaker {
fn wake(self: Arc<Self>) { #[inline(always)]
log::trace!("Woke Task-{:?}", self.id); fn new(id: usize, task_queue: Arc<TaskQueue>) -> Self {
self.wake_by_ref(); Self { id, task_queue }
} }
fn wake_by_ref(self: &Arc<Self>) { #[inline(always)]
self.queue.push(self.id); fn wake(&self) {
self.task_queue.queue.push(self.id);
}
fn into_raw_waker(waker: &TaskWaker) -> RawWaker {
let ptr = waker as *const TaskWaker;
RawWaker::new(ptr.cast(), &VTABLE)
}
}
const VTABLE: RawWakerVTable = RawWakerVTable::new(clone_raw, wake_raw, wake_by_ref_raw, drop_raw);
unsafe fn clone_raw(ptr: *const ()) -> RawWaker {
let waker = &*(ptr as *const TaskWaker);
TaskWaker::into_raw_waker(waker)
}
unsafe fn wake_raw(ptr: *const ()) {
let waker = &*(ptr as *const TaskWaker);
waker.wake();
}
unsafe fn wake_by_ref_raw(ptr: *const ()) {
let waker = &*(ptr as *const TaskWaker);
waker.wake();
}
unsafe fn drop_raw(_: *const ()) {}
struct TaskQueue {
queue: SegQueue<usize>,
next_task: usize,
free_tasks: SegQueue<usize>,
}
impl TaskQueue {
fn new() -> Self {
Self {
queue: SegQueue::new(),
next_task: 0,
free_tasks: SegQueue::new(),
}
}
#[inline(always)]
fn batch_pop(&self, output: &mut [usize], len: &mut usize) {
*len = 0;
while let Some(id) = self.queue.pop() {
output[*len] = id;
*len += 1;
if *len == output.len() {
break;
}
}
}
#[inline(always)]
fn is_empty(&self) -> bool {
self.queue.is_empty()
} }
} }

View file

@ -4,15 +4,26 @@ version = "0.2.0"
edition = "2021" edition = "2021"
[dependencies] [dependencies]
str-reader = "0.1.2" str-reader = "0.1"
derive_more = "0.99" derive_more = { version = "1", default-features = false, features = [
error-stack = "0.4" "add",
"add_assign",
"constructor",
"display",
"from",
"into",
"mul",
"mul_assign",
"not",
"sum",
] }
error-stack = "0.5"
fatfs = "0.3" fatfs = "0.3"
toml = "0.5.2" toml = "0.8"
# hbasm.git = "https://git.ablecorp.us/AbleOS/holey-bytes.git" # hbasm.git = "https://git.ablecorp.us/AbleOS/holey-bytes.git"
hblang.git = "https://git.ablecorp.us/AbleOS/holey-bytes.git" hblang.git = "https://git.ablecorp.us/AbleOS/holey-bytes.git"
[dependencies.reqwest] [dependencies.reqwest]
version = "0.11" version = "0.12"
default-features = false default-features = false
features = ["rustls-tls", "blocking"] features = ["rustls-tls", "blocking"]

View file

@ -1,10 +1,12 @@
#![allow(unused)]
use std::{ use std::{
fmt::format,
fs::{read_to_string, File}, fs::{read_to_string, File},
io::{BufWriter, Write}, io::{BufWriter, Write},
process::exit, process::exit,
}; };
use error_stack::Report; use {error_stack::Report, hblang::Options};
use crate::Error; use crate::Error;
pub struct Package { pub struct Package {
@ -63,38 +65,38 @@ impl Package {
} }
pub fn build(&self) { pub fn build(&self) {
if self.binaries.contains(&"hblang".to_string()) { if self.binaries.contains(&"hblang".to_string()) {
let file_order = self.build_cmd.split_ascii_whitespace(); let file = self.build_cmd.split_ascii_whitespace().last().unwrap();
let mut files = vec![];
for (count, file) in file_order.enumerate() { let path = format!("sysdata/programs/{}/{}", self.name, file);
if count != 0 { let mut bytes = Vec::new();
println!("{}", file); // compile here
files.push(file);
} let _ = hblang::run_compiler(
} &path,
let mut bundle = vec![]; Options {
for file in files { fmt: true,
let contents = read_to_string(file).unwrap(); ..Default::default()
bundle.push((file, contents)); },
} &mut bytes,
);
let _ = hblang::run_compiler(&path, Default::default(), &mut bytes);
use hblang::{codegen, parser};
let mut codegen = codegen::Codegen::default();
for (path, content) in bundle.iter() {
println!("A");
codegen.files = vec![parser::Ast::new(&path, &content, &parser::no_loader)];
codegen.generate();
}
let mut buf = BufWriter::new(Vec::new());
codegen.dump(&mut buf);
let bytes = buf.into_inner().unwrap();
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!(), Err(e) => panic!("{}", e),
} }
let path = format!("target/test-programs/{}.hbf", self.name); std::fs::write(format!("target/programs/{}.hbf", self.name), &bytes).unwrap();
let mut file = File::create(path).unwrap(); bytes.clear();
file.write_all(&bytes).unwrap(); let _ = hblang::run_compiler(
&path,
Options {
dump_asm: true,
..Default::default()
},
&mut bytes,
);
std::fs::write(format!("target/programs/{}.hba", self.name), &bytes).unwrap();
} }
} }
} }

View file

@ -1,3 +1,5 @@
// #![allow(unused)]
mod dev; mod dev;
use { use {
@ -6,7 +8,7 @@ use {
error_stack::{bail, report, Context, Report, Result, ResultExt}, error_stack::{bail, report, Context, Report, Result, ResultExt},
fatfs::{FileSystem, FormatVolumeOptions, FsOptions, ReadWriteSeek}, fatfs::{FileSystem, FormatVolumeOptions, FsOptions, ReadWriteSeek},
std::{ std::{
fmt::Display, // fmt::Display,
fs::{self, File}, fs::{self, File},
io::{self, Write}, io::{self, Write},
path::Path, path::Path,
@ -19,21 +21,16 @@ fn main() -> Result<(), Error> {
let mut args = std::env::args(); let mut args = std::env::args();
args.next(); args.next();
// let disk_meta = fs::metadata("target/disk.img").unwrap();
// let config_meta = fs::metadata("system.toml").unwrap();
// if disk_meta.modified().unwrap() < config_meta.modified().unwrap() {
// // TODO: work on adding in system.toml support
// // TODO: rebuild the disk
// }
match args.next().as_deref() { match args.next().as_deref() {
Some("build" | "b") => { Some("build" | "b") => {
let mut release = false; let mut release = false;
let mut debuginfo = false;
let mut target = Target::X86_64; let mut target = Target::X86_64;
for arg in args { for arg in args {
if arg == "-r" || arg == "--release" { if arg == "-r" || arg == "--release" {
release = true; release = true;
} else if arg == "-d" || arg == "--debuginfo" {
debuginfo = true;
} else if arg == "rv64" || arg == "riscv64" || arg == "riscv64-virt" { } else if arg == "rv64" || arg == "riscv64" || arg == "riscv64-virt" {
target = Target::Riscv64Virt; target = Target::Riscv64Virt;
} else if arg == "arm64" || arg == "aarch64" || arg == "aarch64-virt" { } else if arg == "arm64" || arg == "aarch64" || arg == "aarch64-virt" {
@ -43,15 +40,17 @@ fn main() -> Result<(), Error> {
} }
} }
assemble()?; build(release, target, debuginfo).change_context(Error::Build)
build(release, target).change_context(Error::Build)
} }
Some("run" | "r") => { Some("run" | "r") => {
let mut release = false; let mut release = false;
let mut debuginfo = false;
let mut target = Target::X86_64; let mut target = Target::X86_64;
for arg in args { for arg in args {
if arg == "-r" || arg == "--release" { if arg == "-r" || arg == "--release" {
release = true; release = true;
} else if arg == "-d" || arg == "--debuginfo" {
debuginfo = true;
} else if arg == "rv64" || arg == "riscv64" || arg == "riscv64-virt" { } else if arg == "rv64" || arg == "riscv64" || arg == "riscv64-virt" {
target = Target::Riscv64Virt; target = Target::Riscv64Virt;
} else if arg == "arm64" || arg == "aarch64" || arg == "aarch64-virt" { } else if arg == "arm64" || arg == "aarch64" || arg == "aarch64-virt" {
@ -61,8 +60,7 @@ fn main() -> Result<(), Error> {
} }
} }
assemble()?; build(release, target, debuginfo)?;
build(release, target)?;
run(release, target) run(release, target)
} }
Some("help" | "h") => { Some("help" | "h") => {
@ -82,49 +80,6 @@ fn main() -> Result<(), Error> {
} }
} }
fn assemble() -> Result<(), Error> {
match std::fs::create_dir("target/test-programs") {
Ok(_) => (),
Err(e) if e.kind() == std::io::ErrorKind::AlreadyExists => (),
Err(e) => return Err(Report::new(e).change_context(Error::Io)),
}
for entry in std::fs::read_dir("sysdata/test-programs")
.map_err(Report::from)
.change_context(Error::Io)?
{
let entry = entry.map_err(Report::from).change_context(Error::Io)?;
if !entry
.file_type()
.map_err(Report::from)
.change_context(Error::Io)?
.is_file()
{
continue;
}
let name = entry.file_name();
let name = name.to_string_lossy();
let name = name.trim_end_matches(".rhai");
let mut out = File::options()
.write(true)
.create(true)
.open(Path::new("target/test-programs").join(format!("{name}.hbf")))
.map_err(Report::from)
.change_context(Error::Io)?;
out.set_len(0)
.map_err(Report::from)
.change_context(Error::Io)?;
// hbasm::assembler(&mut out, |engine| engine.run_file(entry.path()))
// .map_err(|e| report!(Error::Assembler).attach_printable(e.to_string()))?;
}
Ok(())
}
fn get_path_without_boot_prefix(val: &Value) -> Option<&str> { fn get_path_without_boot_prefix(val: &Value) -> Option<&str> {
val.as_str()?.split("boot:///").last() val.as_str()?.split("boot:///").last()
} }
@ -240,8 +195,8 @@ TERM_BACKDROP={}
let modules = value.get_mut("modules").unwrap().as_table_mut().unwrap(); let modules = value.get_mut("modules").unwrap().as_table_mut().unwrap();
// let mut real_modules = modules.clone(); // let mut real_modules = modules.clone();
modules.into_iter().for_each(|(key, value)| { modules.into_iter().for_each(|(_, value)| {
if value.is_table() && key == "tests" { 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"),
) )
@ -280,7 +235,7 @@ TERM_BACKDROP={}
.expect("You must have a `path` as a value"), .expect("You must have a `path` as a value"),
) )
.unwrap(); .unwrap();
let fpath = format!("target/test-programs/{}", path); let fpath = format!("target/programs/{}", path);
copy_file_to_img(&fpath, &fs); copy_file_to_img(&fpath, &fs);
} }
}); });
@ -289,7 +244,7 @@ TERM_BACKDROP={}
let bootdir = fs.root_dir().create_dir("efi")?.create_dir("boot")?; let bootdir = fs.root_dir().create_dir("efi")?.create_dir("boot")?;
let mut f = fs.root_dir().create_file("limine.cfg")?; let mut f = fs.root_dir().create_file("limine.cfg")?;
let a = f.write(limine_str.as_bytes())?; let _ = f.write(limine_str.as_bytes())?;
drop(f); drop(f);
io::copy( io::copy(
@ -312,6 +267,7 @@ TERM_BACKDROP={}
fn copy_file_to_img(fpath: &str, fs: &FileSystem<File>) { fn copy_file_to_img(fpath: &str, fs: &FileSystem<File>) {
let path = Path::new(fpath); let path = Path::new(fpath);
// println!("{path:?}");
io::copy( io::copy(
&mut File::open(path).expect(&format!("Could not open file {fpath}")), &mut File::open(path).expect(&format!("Could not open file {fpath}")),
&mut fs &mut fs
@ -322,7 +278,7 @@ fn copy_file_to_img(fpath: &str, fs: &FileSystem<File>) {
.expect("Copy failed"); .expect("Copy failed");
} }
fn build(release: bool, target: Target) -> Result<(), Error> { fn build(release: bool, target: Target, debuginfo: bool) -> Result<(), Error> {
let fs = get_fs().change_context(Error::Io)?; let fs = get_fs().change_context(Error::Io)?;
let mut com = Command::new("cargo"); let mut com = Command::new("cargo");
com.current_dir("kernel"); com.current_dir("kernel");
@ -330,6 +286,9 @@ fn build(release: bool, target: Target) -> Result<(), Error> {
if release { if release {
com.arg("-r"); com.arg("-r");
} }
if debuginfo {
com.env("RUSTFLAGS", "-Cdebug-assertions=true");
}
if target == Target::Riscv64Virt { if target == Target::Riscv64Virt {
com.args(["--target", "targets/riscv64-virt-ableos.json"]); com.args(["--target", "targets/riscv64-virt-ableos.json"]);
@ -386,10 +345,12 @@ fn run(release: bool, target: Target) -> Result<(), Error> {
com.args([ com.args([
"-bios", &ovmf_path.change_context(Error::OvmfFetch)?, "-bios", &ovmf_path.change_context(Error::OvmfFetch)?,
"-drive", "file=target/disk.img,format=raw", "-drive", "file=target/disk.img,format=raw",
"-m", "4G", "-device", "vmware-svga",
"-smp", "cores=4", "-m", "2G",
// "-enable-kvm", "-smp", "1",
"-cpu", "Broadwell-v4" "-machine", "accel=kvm",
"-cpu", "host",
"-device", "isa-debug-exit,iobase=0xf4,iosize=0x04",
]); ]);
} }
Target::Riscv64Virt => { Target::Riscv64Virt => {
@ -410,7 +371,7 @@ fn run(release: bool, target: Target) -> Result<(), Error> {
#[rustfmt::skip] #[rustfmt::skip]
com.args([ com.args([
"-M", "virt", "-M", "virt",
"-cpu", "cortex-a72", "-cpu", "neoverse-n2",
"-device", "ramfb", "-device", "ramfb",
"-device", "qemu-xhci", "-device", "qemu-xhci",
"-device", "usb-kbd", "-device", "usb-kbd",
@ -469,11 +430,11 @@ fn fetch_ovmf(target: Target) -> Result<String, OvmfFetchError> {
#[derive(Debug, Display)] #[derive(Debug, Display)]
enum OvmfFetchError { enum OvmfFetchError {
#[display(fmt = "Failed to fetch OVMF package")] #[display("Failed to fetch OVMF package")]
Fetch, Fetch,
#[display(fmt = "No OVMF package available")] #[display("No OVMF package available")]
Empty, Empty,
#[display(fmt = "IO Error")] #[display("IO Error")]
Io, Io,
} }
@ -486,26 +447,28 @@ enum Target {
Aarch64, Aarch64,
} }
#[allow(unused)]
#[derive(Debug, Display)] #[derive(Debug, Display)]
enum Error { enum Error {
#[display(fmt = "Failed to build the kernel")] #[display("Failed to build the kernel")]
Build, Build,
#[display(fmt = "Missing or invalid subcommand (available: build, run)")] #[display("Missing or invalid subcommand (available: build, run)")]
InvalidSubCom, InvalidSubCom,
#[display(fmt = "IO Error")] #[display("IO Error")]
Io, Io,
#[display(fmt = "Failed to spawn a process")] #[display("Failed to spawn a process")]
ProcessSpawn, ProcessSpawn,
#[display(fmt = "Failed to fetch UEFI firmware")] #[display("Failed to fetch UEFI firmware")]
OvmfFetch, OvmfFetch,
#[display(fmt = "Failed to assemble Holey Bytes code")] #[display("Failed to assemble Holey Bytes code")]
Assembler, Assembler,
#[display(fmt = "QEMU Error: {}", "fmt_qemu_err(*_0)")] #[display("QEMU Error: {}", "fmt_qemu_err(*_0)")]
Qemu(Option<i32>), Qemu(Option<i32>),
} }
impl Context for Error {} impl Context for Error {}
#[allow(dead_code)]
fn fmt_qemu_err(e: Option<i32>) -> impl Display { fn fmt_qemu_err(e: Option<i32>) -> impl Display {
struct W(Option<i32>); struct W(Option<i32>);
impl Display for W { impl Display for W {

View file

@ -1,3 +1,3 @@
[toolchain] [toolchain]
channel = "nightly-2024-05-17" channel = "nightly-2024-07-27"
components = ["rust-src", "llvm-tools"] components = ["rust-src", "llvm-tools", "rust-analyzer"]

View file

@ -1,41 +0,0 @@
{ pkgs ? import <nixpkgs> { } }:
pkgs.mkShell rec {
buildInputs = with pkgs; [
clang
llvmPackages.bintools
rustup
qemu_full
# OMVFFull
# OMVF
];
extraCmds = '''';
RUSTC_VERSION = pkgs.lib.readFile ./rust-toolchain.toml;
# https://github.com/rust-lang/rust-bindgen#environment-variables
LIBCLANG_PATH =
pkgs.lib.makeLibraryPath [ pkgs.llvmPackages_latest.libclang.lib ];
shellHook = ''
export REPBUILD_QEMU_FIRMWARE_PATH=${pkgs.OVMF.fd}/FV/OVMF.fd
export PATH=$PATH:''${CARGO_HOME:-~/.cargo}/bin
export PATH=$PATH:''${RUSTUP_HOME:-~/.rustup}/toolchains/$RUSTC_VERSION-x86_64-unknown-linux-gnu/bin/
'';
# Add precompiled library to rustc search path
RUSTFLAGS = (builtins.map (a: "-L ${a}/lib") [
# add libraries here (e.g. pkgs.libvmi)
]);
# Add glibc, clang, glib and other headers to bindgen search path
BINDGEN_EXTRA_CLANG_ARGS =
# Includes with normal include path
(builtins.map (a: ''-I"${a}/include"'') [
# add dev libraries here (e.g. pkgs.libvmi.dev)
pkgs.glibc.dev
])
# Includes with special directory paths
++ [
''
-I"${pkgs.llvmPackages_latest.libclang.lib}/lib/clang/${pkgs.llvmPackages_latest.libclang.version}/include"''
''-I"${pkgs.glib.dev}/include/glib-2.0"''
"-I${pkgs.glib.out}/lib/glib-2.0/include/"
];
}

View file

@ -0,0 +1 @@
# abc

View file

@ -0,0 +1,24 @@
@auto_increment
enum LogLevel {
Error = 0,
Warn,
Info,
Debug,
Trace,
}
@auto_increment
enum LogResult {
Err = 0,
Ok,
}
struct Log {
log_level: LogLevel,
}
@visibility(public)
protocol Log {
fn log(Log) -> LogResult;
fn flush() -> LogResult;
}

View file

@ -0,0 +1 @@
# dt_api

View file

@ -0,0 +1,8 @@
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)
}

View file

@ -0,0 +1,3 @@
# Horizon
Horizon is the windowing system for ableOS.
This is the API library to handle it nicely.

View file

@ -0,0 +1,25 @@
stn := @use("../../stn/src/lib.hb");
.{string, memory, buffer} := stn
input := @use("../../intouch/src/lib.hb")
WindowID := struct {
host_id: int,
window_id: int,
}
create_window := fn(channel: int): void {
// get the horizon buffer
// request a new window and provide the callback buffer
// wait to recieve a message
windowing_system_buffer := buffer.search("XHorizon\0")
if windowing_system_buffer == 0 {
return
} else {
msg := "\{01}\0"
msg_length := 2
return @eca(3, windowing_system_buffer, msg, msg_length)
}
}

View file

@ -0,0 +1,2 @@
# Ignim
Ignim is the ableOS vulkan interface library.

View file

@ -0,0 +1,21 @@
structures := @use("structures.hb")
version := @use("version.hb")
// Refer to here https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkApplicationInfo.html
ApplicationInfo := struct {
sType: int,
pNext: ^int,
application_name: ^u8,
application_version: int,
engine_name: int,
engine_version: int,
api_version: int,
}
new_application_info := fn(app_name: ^u8, app_version: int, engine_name: ^u8, engine_version: int, api_version: int): ApplicationInfo {
app_info_type := structures.ApplicationInfoType
app_info := ApplicationInfo.(app_info_type, 0, app_name, app_version, engine_name, engine_version, api_version)
return app_info
}

View file

@ -0,0 +1,14 @@
OutOfHostMemory := -1
OutOfDeviceMemory := -2
InitializationFailed := -3
DeviceLost := -4
MemoryMapFailed := -5
LayerNotPresent := -6
ExtensionNotPresent := -7
FeatureNotPresent := -8
IncompatibleDriver := -9
TooManyObjects := -10
FormatNotSupported := -11
FragmentedPool := -12
Unknown := -13

View file

@ -0,0 +1,10 @@
Extent3D := struct {
width: int,
height: int,
depth: int,
}
Extent2D := struct {
width: int,
height: int,
}

View file

@ -0,0 +1,35 @@
application := @use("application.hb");
.{ApplicationInfo} := application
structures := @use("structures.hb")
errors := @use("errors.hb")
// https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkInstanceCreateInfo.html
InstanceCreateInfo := struct {
sType: int,
pNext: int,
flags: int,
application_info: ^ApplicationInfo,
enabled_layer_count: int,
ppEnabledLayerNames: int,
enabled_extension_count: int,
ppEnabledExtensionNames: int,
}
new_create_info := fn(application_info: ^ApplicationInfo): InstanceCreateInfo {
create_info_type := structures.InstanceCreateInfoType
enabled_layer_count := 0
create_info := InstanceCreateInfo.(create_info_type, 0, 0, application_info, enabled_layer_count, 0, 0, 0)
return create_info
}
// TODO
Instance := struct {inner: int}
void_instance := fn(): Instance {
return Instance.(0)
}
create_instance := fn(create_info: ^InstanceCreateInfo, allocator_callback: int, new_obj: ^Instance): int {
return errors.IncompatibleDriver
}

View file

@ -0,0 +1,17 @@
application := @use("application.hb")
results := @use("results.hb")
errors := @use("errors.hb")
offsets := @use("offset.hb")
extends := @use("extends.hb")
rect := @use("rect.hb")
structures := @use("structures.hb")
instance := @use("instance.hb")
version := @use("version.hb")
init_vulkan := fn(): int {
return errors.IncompatibleDriver
}

View file

@ -0,0 +1,10 @@
Offset3D := struct {
x: int,
y: int,
z: int,
}
Offset2D := struct {
x: int,
y: int,
}

View file

@ -0,0 +1,7 @@
offsets := @use("offset.hb")
extends := @use("extends.hb")
Rect2D := struct {
offset: offsets.Offset2D,
extent: extends.Extent2D,
}

View file

@ -0,0 +1,7 @@
// NonErrors
Success := 0
NotReady := 1
Timeout := 2
EventSet := 3
EventReset := 4
Incomplete := 5

View file

@ -0,0 +1,61 @@
ApplicationInfoType := 0
InstanceCreateInfoType := 1
DeviceQueueCreateInfo := 2
DeviceCreateInfo := 3
SubmitInfo := 4
MemoryAllocateInfo := 5
MappedMemoryRange := 6
BindSparseInfo := 7
FenceCreateInfo := 8
SemaphoreCreateInfo := 9
EventCreateInfo := 10
QueryPoolCreateInfo := 11
BufferCreateInfo := 12
BufferViewCreateInfo := 13
ImageCreateInfo := 14
ImageViewCreateInfo := 15
ShaderModuleCreateInfo := 16
PipelineCacheCreateInfo := 17
PipelineShaderStageCreateInfo := 18
PipelineVertexInputStateCreateInfo := 19
PipelineInputAssemblyStateCreateInfo := 20
PipelineTessellationStateCreateInfo := 21
PipelineViewportStateCreateInfo := 22
PipelineRasterizationStateCreateInfo := 23
PipelineMultisampleStateCreateInfo := 24
PipelineDepthStencilStateCreateInfo := 25
PipelineColorBlendStateCreateInfo := 26
PipelineDynamicStateCreateInfo := 27
GraphicsPipelineCreateInfo := 28
ComputePipelineCreateInfo := 29
PipelineLayoutCreateInfo := 30
SamplerCreateInfo := 31
DescriptorSetLayoutCreateInfo := 32
DescriptorPoolCreateInfo := 33
DescriptorSetAllocateInfo := 34
WriteDescriptorSet := 35
CopyDescriptorSet := 36
FramebufferCreateInfo := 37
RenderPassCreateInfo := 38
CommandPoolCreateInfo := 39
CommandBufferAllocateInfo := 40
CommandBufferInheritanceInfo := 41
CommandBufferBeginInfo := 42
RenderPassBeginInfo := 43
BufferMemoryBarrier := 44
ImageMemoryBarrier := 45
MemoryBarrier := 46
LoaderInstanceCreateInfo := 47
LoaderDeviceCreateInfo := 48

View file

@ -0,0 +1,9 @@
ApiVersion1_0 := make_api_version(0, 1, 0, 0)
make_version := fn(major: int, minor: int, patch: int): int {
return major << 22 | minor << 12 | patch
}
make_api_version := fn(variant: int, major: int, minor: int, patch: int): int {
return variant << 29 | major << 22 | minor << 12 | patch
}

View file

@ -0,0 +1,20 @@
# intouch
This library is exclusively focused on allowing your to get input regardless of which devices you have.
Partially modeled after SDL.
Current goals include
- Interfaces
- PS/2
- Device Types
- Keyboard
- Mouse
Longer Term goals
- Interfaces
- USB
- USB-HID
- Device Types
- Gamepads/controllers
- Drawing Tablets
- Microphones

View file

@ -0,0 +1,2 @@
0x0D -> press Tab
0xF0 0x0D -> release Tab

View file

@ -0,0 +1,67 @@
KeyCode := u32
// https://www.libsdl.org/release/SDL-1.2.15/include/SDL_keysym.h
Backspace := KeyCode.(8)
Tab := KeyCode.(9)
Clear := KeyCode.(12)
Return := KeyCode.(13)
Pause := KeyCode.(19)
Escape := KeyCode.(27)
Space := KeyCode.(32)
A := KeyCode.(97)
/*
ETC
*/
Z := KeyCode.(122)
Delete := KeyCode.(127)
/*
ETC
*/
KeypadNumber0 := KeyCode.(256)
KeypadNumber1 := KeyCode.(257)
KeypadNumber2 := KeyCode.(258)
KeypadNumber3 := KeyCode.(259)
KeypadNumber4 := KeyCode.(260)
KeypadNumber5 := KeyCode.(261)
KeypadNumber6 := KeyCode.(262)
KeypadNumber7 := KeyCode.(263)
KeypadNumber8 := KeyCode.(264)
KeypadNumber9 := KeyCode.(265)
KeypadPeriod := KeyCode.(266)
KeypadDivide := KeyCode.(267)
KeypadMultiply := KeyCode.(268)
KeypadMinus := KeyCode.(269)
KeypadPlus := KeyCode.(270)
KeypadEnter := KeyCode.(271)
KeypadEquals := KeyCode.(272)
NumLock := KeyCode.(300)
CapsLock := KeyCode.(301)
ScrollLock := KeyCode.(302)
RightShift := KeyCode.(303)
LeftShift := KeyCode.(304)
RightControl := KeyCode.(305)
LeftControl := KeyCode.(306)
RightAlt := KeyCode.(307)
LeftAlt := KeyCode.(308)
RightMeta := KeyCode.(309)
LeftMeta := KeyCode.(310)
/* Left "Windows" key */
LeftSuper := KeyCode.(311)
/* Right "Windows" key */
RightSuper := KeyCode.(312)
/* "Alt Gr" key */
Mode := KeyCode.(313)
/* Multi-key compose key */
Compose := KeyCode.(314)

View file

@ -0,0 +1,22 @@
keycodes := @use("keycodes.hb");
.{KeyCode} := keycodes
MouseEvent := struct {
x_change: u8,
y_change: u8,
left: u8,
middle: u8,
right: u8,
}
KeyEvent := struct {
// 0 if down
// 1 if up
up: u8,
// 0 if not just triggered
// 1 if just triggered
just_triggered: u8,
key: KeyCode,
}
GamepadEvent := struct {}

View file

@ -0,0 +1 @@
# pci

View file

@ -0,0 +1,93 @@
.{string, memory, buffer, log} := @use("../../stn/src/lib.hb")
PCIAddress := struct {
bus: u8,
device: u8,
function: u8,
}
PCI_ID := struct {
vendor: u16,
device: u16,
inner: int,
}
get_ids := fn(bus: u8, device: u8, function: u8): PCI_ID {
res := config_read32(bus, device, function, 0)
dev_id := res >> 16
dev_id &= 0xFFFF
vnd_id := res & 0xFFFF
return PCI_ID.(dev_id, vnd_id, 0)
}
PciDeviceInfo := struct {
header_type: u8,
device: u8,
bus: u8,
device_id: PCI_ID,
class: u16,
rev_id: u8,
}
calculate_address := fn(bus: u8, device: u8, function: u8, offset: u8): int {
address := bus << 16
address |= device << 11
address |= function << 8
address |= offset & 0xFC
address |= 0x80000000
return address
}
get_header_type := fn(bus: u8, device: u8, function: u8): u8 {
res := config_read32(bus, device, function, 0xC)
ret := res >> 16
ret &= 0xFF
return ret
}
check_device := fn(bus: u8, device: u8): PciDeviceInfo {
pci_id := get_ids(bus, device, 0)
if pci_id.vendor == 0xFFFF {
log.warn(":|\0")
} else {
log.info(":)\0")
}
address := calculate_address(bus, device, 0, 0x8)
reg2 := config_read32(bus, device, 0, 0x8)
class := reg2 >> 16 & 0xFFFF
header_type := get_header_type(bus, device, 0)
rev_id := reg2 & 0xFF
return PciDeviceInfo.(header_type, device, bus, pci_id, class, rev_id)
}
find_device := fn(vendor_id: int, device_id: int, pci_address: PCIAddress): PCI_ID {
pci_id := get_ids(0, 2, 0)
return pci_id
}
scan_bus := fn(): void {
}
config_read32 := fn(bus: u32, device: u32, func: u32, offset: u32): u32 {
// construct address param
offset_and := offset & 0xFC
address := bus << 16
address |= device << 11
address |= func << 8
address |= offset_and
address |= 0x80000000
// write address
memory.outl(0xCF8, address)
// read data
return memory.inl(0xCFC)
}

View file

@ -0,0 +1,9 @@
Rendering interface for SVGA and Software renderers
# TODO:
- SVGA Driver
- needs pci driver
- needs init (requiring program)
- Double Buffer mode for Software renderer
- needs init (requiring program)

View file

@ -0,0 +1,47 @@
svga := @use("svga.hb")
software := @use("software.hb")
// default mode
mode := software
init := mode.init
doublebuffer := mode.doublebuffer
// Colours
Color := mode.Color
white := mode.white
black := mode.black
gray := mode.gray
red := mode.red
green := mode.green
yellow := mode.yellow
blue := mode.blue
magenta := mode.magenta
cyan := mode.cyan
light_gray := mode.light_gray
light_red := mode.light_red
light_green := mode.light_green
light_yellow := mode.light_yellow
light_blue := mode.light_blue
light_magenta := mode.light_magenta
light_cyan := mode.light_cyan
// Drawing
put_pixel := mode.put_pixel
put_rect := mode.put_rect
put_filled_rect := mode.put_filled_rect
put_line := mode.put_line
clear := mode.clear
// Display
width := mode.width
height := mode.height
dimensions := mode.dimensions
set_height := mode.set_height
set_width := mode.set_width
set_dimensions := mode.set_dimensions
sync := mode.sync
// Math
UVec2 := struct {x: uint, y: uint}
IVec2 := struct {x: int, y: int}

View file

@ -0,0 +1,261 @@
.{math, memory} := @use("../../stn/src/lib.hb");
.{dt_get} := @use("../../dt_api/src/lib.hb");
.{IVec2} := @use("lib.hb")
Color := struct {b: u8, g: u8, r: u8, a: u8}
white := Color.(255, 255, 255, 255)
black := Color.(0, 0, 0, 255)
gray := Color.(127, 127, 127, 255)
red := Color.(0, 0, 205, 255)
green := Color.(0, 205, 0, 255)
yellow := Color.(0, 205, 205, 255)
blue := Color.(205, 0, 0, 255)
magenta := Color.(205, 0, 205, 255)
cyan := Color.(205, 205, 0, 255)
light_gray := Color.(229, 229, 229, 255)
light_red := Color.(0, 0, 255, 255)
light_green := Color.(0, 255, 0, 255)
light_yellow := Color.(0, 255, 255, 255)
light_blue := Color.(255, 0, 0, 255)
light_magenta := Color.(255, 0, 255, 255)
light_cyan := Color.(255, 255, 0, 255)
// might not work for some resolutions, but needs to be comptime because...
copy_pixels := 0xC000 >> 2
ctx := @as(Context, idk)
// some of these are redudant holdovers from fb_driver
// will keep them for future work if necessary
Context := struct {
fb: ^Color,
bb: ^Color,
buf: ^Color,
width: int,
height: int,
partitions: int,
pixels: int,
bb_pages: int,
double_buffer: bool,
}
init := fn(): void {
width := dt_get("framebuffer/fb0/width\0")
height := dt_get("framebuffer/fb0/height\0")
// width := 1024
// height := 768
pixels := width * height
bytes := pixels << 2
partitions := pixels / copy_pixels
pages := 1 + bytes >> 12
back_buffer := create_back_buffer(pages)
ctx = Context.{
fb: dt_get("framebuffer/fb0/ptr\0"),
bb: back_buffer,
buf: back_buffer,
width,
height,
partitions,
pixels,
bb_pages: pages,
double_buffer: true,
}
return
}
doublebuffer := fn(enable: bool): void {
if enable {
ctx.buf = ctx.bb
} else {
ctx.buf = ctx.fb
}
ctx.double_buffer = enable
return
}
create_back_buffer := fn(pages: int): ^Color {
if pages <= 0xFF {
return @bitcast(@inline(memory.request_page, pages))
}
ptr := @inline(memory.request_page, 255)
remaining := pages - 0xFF
loop if remaining <= 0 break else {
if remaining < 0xFF {
memory.request_page(remaining)
} else {
memory.request_page(0xFF)
}
remaining -= 0xFF
}
return @bitcast(ptr)
}
clear := fn(color: Color): void {
cursor := ctx.buf
boundary := cursor + 512
loop if cursor == boundary break else {
*cursor = color
cursor += 1
}
boundary += 512 * 7
loop if cursor == boundary break else {
*@as(^[Color; 512], @bitcast(cursor)) = *@as(^[Color; 512], @bitcast(ctx.buf))
cursor += 512
}
boundary += copy_pixels - 4096
loop if cursor == boundary break else {
*@as(^[Color; 4096], @bitcast(cursor)) = *@as(^[Color; 4096], @bitcast(ctx.buf))
cursor += 4096
}
boundary += (ctx.partitions - 1) * copy_pixels
loop if cursor == boundary break else {
*@as(^[Color; copy_pixels], @bitcast(cursor)) = *@as(^[Color; copy_pixels], @bitcast(ctx.buf))
cursor += @sizeof([u8; copy_pixels])
}
return
}
sync := fn(): void {
if ctx.double_buffer {
bb := ctx.buf
fb := ctx.fb
boundary := bb + ctx.pixels
loop if bb == boundary break else {
*@as(^[Color; copy_pixels], @bitcast(fb)) = *@as(^[Color; copy_pixels], @bitcast(bb))
bb += copy_pixels
fb += copy_pixels
}
}
return
}
width := fn(): int {
return ctx.width
}
height := fn(): int {
return ctx.height
}
screenidx := fn(x: int, y: int): int {
return x + ctx.width * y
}
put_pixel := fn(pos: IVec2, color: Color): void {
*(ctx.buf + @inline(screenidx, pos.x, pos.y)) = color
return
}
put_filled_rect := fn(pos: IVec2, tr: IVec2, color: Color): void {
x := pos.x
y := pos.y
end := pos + tr
loop if x == end.x break else {
loop if y == end.y break else {
*(ctx.buf + @inline(screenidx, x, y)) = color
y += 1
}
x += 1
y = pos.y
}
return
}
put_rect := fn(pos: IVec2, tr: IVec2, color: Color): void {
x := pos.x
y := pos.y
end := pos + tr
loop if y == end.y break else {
*(ctx.buf + @inline(screenidx, x, y)) = color;
*(ctx.buf + @inline(screenidx, x + tr.x, y)) = color
y += 1
}
y = pos.y
loop if x == end.x break else {
*(ctx.buf + @inline(screenidx, x, y)) = color;
*(ctx.buf + @inline(screenidx, x, y + tr.y)) = color
x += 1
}
return
}
put_line_low := fn(p0: IVec2, p1: IVec2, color: Color): void {
dx := p1.x - p0.x
dy := p1.y - p0.y
yi := 1
if dy < 0 {
yi = -1
dy = -dy
}
D := 2 * dy - dx
y := p0.y
x := p0.x
loop if x == p1.x break else {
*(ctx.buf + @inline(screenidx, x, y)) = color
if D > 0 {
y += yi
D += 2 * (dy - dx)
} else {
D += 2 * dy
}
x += 1
}
return
}
put_line_high := fn(p0: IVec2, p1: IVec2, color: Color): void {
dx := p1.x - p0.x
dy := p1.y - p0.y
xi := 1
if dy < 0 {
xi = -1
dx = -dx
}
D := 2 * dx - dy
x := p0.x
y := p0.y
loop if y == p1.y break else {
*(ctx.buf + @inline(screenidx, x, y)) = color
if D > 0 {
x += xi
D += 2 * (dx - dy)
} else {
D += 2 * dx
}
y += 1
}
return
}
put_line := fn(p0: IVec2, p1: IVec2, color: Color): void {
if @inline(math.abs, p1.y - p0.y) < @inline(math.abs, p1.x - p0.x) {
if p0.x > p1.x {
@inline(put_line_low, p1, p0, color)
} else {
@inline(put_line_low, p0, p1, color)
}
} else {
if p0.y > p1.y {
@inline(put_line_high, p1, p0, color)
} else {
@inline(put_line_high, p0, p1, color)
}
}
return
}
set_height := fn(new: int): void {
return
}
set_width := fn(new: int): void {
return
}
dimensions := fn(): IVec2 {
return .(ctx.width, ctx.height)
}
set_dimensions := fn(new: IVec2): void {
return
}

View file

@ -0,0 +1,80 @@
.{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
}

View file

@ -0,0 +1,31 @@
//! This is a reserved file for use with the AbleOS Clustering System
HostID := int
ID := int
FileID := struct {
host_id: HostID,
id: ID,
}
// A DeviceID points to a specific device in the ACS.
DeviceID := struct {
host_id: HostID,
id: ID,
}
DiskID := DeviceID
BufferID := struct {
host_id: HostID,
id: ID,
}
ProcessID := struct {
host_id: HostID,
id: ID,
}
WindowID := struct {
host_id: HostID,
id: ID,
}

View file

@ -0,0 +1,22 @@
string := @use("string.hb")
receive_message := fn(buffer_id: int, memory_map_location: ^u8, length: int): ^u8 {
return @eca(4, buffer_id, memory_map_location, length)
}
send_message := fn(msg: ^u8, buffer_id: int, length: int): void {
return @eca(3, buffer_id, msg, length)
}
create := fn(msg: ^u8): int {
msg_length := @inline(string.length, msg);
*msg = 0
return @eca(3, 0, msg, msg_length)
}
search := fn(msg: ^u8): int {
msg_length := @inline(string.length, msg);
*msg = 3
return @eca(3, 0, msg, msg_length)
}

View file

@ -0,0 +1,31 @@
acs := @use("acs.hb");
.{DiskID, FileID} := acs
// Paths without a node-disk component are to be treated as local files.
// file_path := "DID:/test\0";
Path := struct {
// DiskID holds the host id
disk_id: DiskID,
length: u8,
data: ^u8,
}
open := fn(file_path: Path): FileID {
}
close := fn(file_id: FileID): int {
}
// This reads in page_count of pages out of the file. If file_size is less than an exact multiple of pages do something.
// TODO: Figureout how to encode errors.
read_pages := fn(file_id: FileID, offset: int, page_count: int): void {
}
// This writes out page_count of pages out of the file.
write_pages := fn(file_id: FileID, offset: int, page_count: int): void {
}
// This reads out byte_count of bytes from the file.
read_bytes := fn(file_id: FileID, offset: int, byte_count: int): void {
}
write_bytes := fn(file_id: FileID, offset: int, byte_count: int): void {
}

View file

@ -1,31 +1,9 @@
char := struct {} acs := @use("acs.hb")
string := @use("string.hb")
log := fn(log_level: int, message: ^char, message_length: int): int { log := @use("log.hb")
memory := @use("memory.hb")
return 0; buffer := @use("buffer.hb")
} math := @use("math.hb")
random := @use("random.hb")
error := fn(message: ^char, message_length: int): int { file := @use("file_io.hb")
log(0, message, message_length)
}
warn := fn(message: ^char, message_length: int): int {
log(1, message, message_length)
}
info := fn(message: ^char, message_length: int): int {
log(2, message, message_length)
}
debug := fn(message: ^char, message_length: int): int {
log(3, message, message_length)
}
trace := fn(message: ^char, message_length: int): int {
log(4, message, message_length)
}
main := fn(): int {
return 0;
}

View file

@ -0,0 +1,15 @@
string := @use("string.hb")
buffer := @use("buffer.hb")
log := fn(message: ^u8, level: u8): void {
message_length := @inline(string.length, message);
*(message + message_length) = level
return @eca(3, 1, message, message_length + 1)
}
error := fn(message: ^u8): void return log(message, 0)
warn := fn(message: ^u8): void return log(message, 1)
info := fn(message: ^u8): void return log(message, 2)
debug := fn(message: ^u8): void return log(message, 3)
trace := fn(message: ^u8): void return log(message, 4)

View file

@ -0,0 +1,15 @@
shift := 31
// following only work for: int
abs := fn(x: int): int {
mask := x >> shift
return (x ^ mask) - mask
}
min := fn(a: int, b: int): int {
c := a - b
return b + (c & c >> shift)
}
max := fn(a: int, b: uint): int {
c := a - b
return a - (c & c >> shift)
}

View file

@ -0,0 +1,39 @@
request_page := fn(page_count: u8): ^u8 {
msg := "\{00}\{01}xxxxxxxx\0"
msg_page_count := msg + 1;
*msg_page_count = page_count
return @eca(3, 2, msg, 12)
}
release_page := fn(ptr: ^u8, page_count: u8): void {
msg := "\{01}\{00}xxxxxxxx\0"
msg_page_count := msg + 1;
*msg_page_count = page_count
msg_ptr := @as(^^u8, @bitcast(msg + 2));
*msg_ptr = ptr
return @eca(3, 2, msg, 12)
}
OutbMsg := struct {a: u8, b: u8, addr: u16, value: u8}
InbMsg := struct {a: u8, b: u8, addr: u16}
OutlMsg := struct {a: u8, b: u8, addr: u16, value: u32}
InlMsg := struct {a: u8, b: u8, addr: u16}
outb := fn(addr: u16, value: u8): void {
return @eca(3, 3, &OutbMsg.(1, 0, addr, value), @sizeof(OutbMsg))
}
inb := fn(addr: u16): u8 {
return @eca(3, 3, &InbMsg.(0, 0, addr), @sizeof(InbMsg))
}
outl := fn(addr: u16, value: u32): void {
return @eca(3, 3, &OutlMsg.(1, 2, addr, value), @sizeof(OutlMsg))
}
inl := fn(addr: u16): u32 {
return @eca(3, 3, &InlMsg.(0, 2, addr), @sizeof(InlMsg))
}

View file

@ -0,0 +1,7 @@
integer := fn(): int {
return @eca(3, 4)
}
integer_range := fn(min: int, max: int): int {
return @eca(3, 4) % (max - min + 1) + min
}

View file

@ -0,0 +1,48 @@
length := fn(ptr: ^u8): int {
len := 0
loop if *(ptr + len) == 0 break else len += 1
return len
}
// WTFFF is wrong with display_int
display_int := fn(num: int, p: ^u8): ^u8 {
ptr := p
negative := num < 0
if negative {
num = -num
}
if num == 0 {
*ptr = 48
ptr += 1
} else {
loop if num == 0 break else {
*ptr = num % 10 + 48
ptr += 1
num /= 10
}
}
if negative {
*ptr = 45
ptr += 1
};
*ptr = 0
@inline(reverse, p)
return p
}
reverse := fn(s: ^u8): void {
//reverse a string, don't remove digits
len := 0
loop if *(s + len) == 0 break else len += 1
i := 0
j := len - 1
temp := 0
loop if i >= j break else {
temp = *(s + i);
*(s + i) = *(s + j);
*(s + j) = temp
i += 1
j -= 1
}
return
}

View file

@ -1,40 +0,0 @@
${ABLEOS_KERNEL}=boot:///kernel
# TODO: Make a boot background image for ableOS
DEFAULT_ENTRY=1
TIMEOUT=0
VERBOSE=yes
INTERFACE_RESOLUTION=1024x768
# Terminal related settings
TERM_WALLPAPER=boot:///background.bmp
TERM_BACKDROP=008080
:AbleOS
COMMENT=Default AbleOS boot entry.
PROTOCOL=limine
KERNEL_PATH=boot:///kernel_${ARCH}
# execute is an array of boot modules to execute
KERNEL_CMDLINE=""
# Setting a default resolution for the framebuffer
RESOLUTION=1024x768x24
MODULE_PATH=boot:///failure.hbf
MODULE_CMDLINE=""
MODULE_PATH=boot:///ecall.hbf
MODULE_CMDLINE=""
MODULE_PATH=boot:///main.hbf
MODULE_CMDLINE=""
MODULE_PATH=boot:///keyboard_driver.hbf
MODULE_CMDLINE="arch=${ARCH}"
MODULE_PATH=boot:///vfs_test.hbf
MODULE_CMDLINE=""
MODULE_PATH=boot:///limine_framebuffer_driver.hbf
MODULE_CMDLINE="height=10 width=10 arch=${ARCH}"
MODULE_PATH=boot:///serial_driver.hbf
MODULE_CMDLINE="arch=${ARCH}"

View file

@ -1,5 +1,5 @@
[package] [package]
name = "dev" name = "diskio_driver"
authors = ["able"] authors = ["able"]
[dependants.libraries] [dependants.libraries]
@ -7,5 +7,5 @@ authors = ["able"]
[dependants.binaries] [dependants.binaries]
hblang.version = "1.0.0" hblang.version = "1.0.0"
[build.debug] [build]
command = "hblang libraries/stn/src/lib.hb src/main.hbl" command = "hblang src/main.hb"

View file

@ -1,4 +1,13 @@
main := fn(): int { .{memory, buffer} := @use("../../../libraries/stn/src/lib.hb")
return 0; main := fn(): int {
// shuts down ableOS
// memory.outb(0xF400, 0)
a := memory.inb(0x4600)
b := memory.inb(0x4700)
c := buffer.search("XNumber\0")
return 0
} }

View file

@ -0,0 +1 @@
# dt_buffer_test

View file

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

View file

@ -0,0 +1,14 @@
dt_api := @use("../../../libraries/dt_api/src/lib.hb");
.{dt_get} := dt_api
main := fn(): int {
dt_api.dt_get("framebuffer/fb0/width\0")
dt_api.dt_get("cpu/cpu0/architecture\0")
// Checking if the first detected serial port is memory mapped or port mapped
// 0 -> memory mapped
// 1 -> port mapped
dt_get("serial_ports/sp0/mapping\0")
return 0
}

View file

@ -1,7 +0,0 @@
main := fn(): int {
loop {
}
return 0;
}

View file

@ -0,0 +1 @@
# filesystem_fat32

View file

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

View file

@ -0,0 +1,7 @@
READ_ONLY := 0x1
HIDDEN := 0x2
SYSTEM := 0x4
VOLUME_ID := 0x8
DIRECTORY := 0x10
ARCHIVE := 0x20
LFN := READ_ONLY | HIDDEN | SYSTEM | VOLUME_ID

View file

@ -0,0 +1,181 @@
stn := @use("../../../libraries/stn/src/lib.hb");
.{string, memory, buffer, log} := stn
VALID_JUMP_BYTES := [u8].(0xEB, 0x3C, 0x90)
OemIdent := struct {
dos_version: [u8; 8],
dos_version_name: [u8; 8],
}
new_oem_ident := fn(major: int, minor: int): OemIdent {
ver := [u8].(0, 0, 0, 0, 0, 0, 0, 0)
return OemIdent.(ver, ver)
}
BiosParameterBlock := struct {
jump_bytes: [u8; 3],
oem_ident: OemIdent,
bytes_per_sector: u16,
sectors_per_cluster: u8,
reserved_sectors: u16,
// The amount of FileAllocationTables on the disk. Often 2.
fat_count: u8,
root_directory_count: u16,
// if 0 then refer to large_sector_count
total_sectors: u16,
media_type: u8,
// if 0 refer to sectors_per_fat in the ExtendedBootRecord
sectors_per_fat: u16,
sectors_per_track: u16,
head_count: u16,
hidden_sectors: u32,
large_sector_count: u32,
}
bpb_sanity_check := fn(bpb: BiosParameterBlock): int {
return 0
}
new_bpb := fn(): BiosParameterBlock {
oem := new_oem_ident(0, 0)
return BiosParameterBlock.(VALID_JUMP_BYTES, oem, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
}
sector_count := fn(bpb: BiosParameterBlock): u32 {
if bpb.total_sectors == 0 {
return bpb.large_sector_count
} else {
return bpb.total_sectors
}
}
FatVersionNumber := struct {
major_version: u8,
minor_version: u8,
}
FormatReservation := [u8; 12]
// Padded with spaces.
VolumeName := [u8; 11]
SystemIdentifierString := [u8; 8]
VALID_SYSTEM_IDENTIFIER_STRING := [u8].(46, 41, 54, 33, 32, 20, 20, 20)
BOOTABLE_PARTITION_SIGNATURE := 0xAA55
BootCode := [u8; 420]
ExtendedBootRecord := struct {
sectors_per_fat: u32,
flags: u16,
fat_version_number: FatVersionNumber,
// Typically set to 2.
root_directory_cluster_number: u32,
fsinfo_structure: u16,
backup_boot_sector: u16,
// When a volume is formated these bytes should be zero. As a sanity check I guess?
format_reserved: FormatReservation,
// 0x00 floppy or 0x80 hard disk
drive_number: u8,
nt_reserved: u8,
// must be 0x28 or 0x29
signature: u8,
volume_id_serial: u32,
volume_id_name: VolumeName,
// The spec says this is always FAT32. Untrustworthy and another sanity check I guess.
system_identifier_string: SystemIdentifierString,
boot_code: BootCode,
partition_signature: u16,
}
ebr_sanity_check := fn(ebr: ExtendedBootRecord): int {
ret := 0
if ebr.drive_number != 0x0 | ebr.drive_number != 0x80 {
log.warn("EBR-Drive-Number sanity check failed\0")
}
if ebr.signature != 0x28 | ebr.signature != 0x29 {
log.warn("EBR-Signature sanity check failed\0")
}
if ebr.system_identifier_string != VALID_SYSTEM_IDENTIFIER_STRING {
log.warn("EBR-Signature-Identifier-String sanity check failed\0")
}
return 0
}
new_ebr := fn(): ExtendedBootRecord {
version := FatVersionNumber.(0, 0)
fmt_res := FormatReservation.(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
vol_name := @as([u8; 11], idk)
boot_code := @as([u8; 420], idk)
return ExtendedBootRecord.(
0,
0,
version,
0,
0,
0,
fmt_res,
0,
0,
0,
0,
vol_name,
VALID_SYSTEM_IDENTIFIER_STRING,
boot_code,
0,
)
}
VALID_LEAD_FS_INFO := 0x41615252
VALID_TRAIL_FS_INFO := 0xAA550000
FSInfo := struct {
// Must be 0x41615252 to indicate a valid FSInfo structure
lead_signature: u32,
lead_reserved: [u8; 480],
// If the value is 0xFFFFFFFF, then the free count is unknown and must be computed. However, this value might be incorrect and should at least be range checked (<= volume cluster count)
last_known_free_cluster_count: u32,
last_known_avalible_cluster: u32,
trail_reserved: [u8; 12],
trail_signature: u32,
}
fs_info_sanity_check := fn(fs_info: FSInfo): int {
ret := 0
if fs_info.lead_signature != VALID_LEAD_FS_INFO {
ret &= 1
log.warn("Invalid leading signature in FSInfo.\0")
}
if fs_info.last_known_free_cluster_count == 0xFFFFFFFF {
ret &= 2
log.warn("Last known free cluster count unknown.\0")
}
if fs_info.last_known_avalible_cluster == 0xFFFFFFFF {
ret &= 4
log.warn("Last known avalible cluster count unknown.\0")
}
if fs_info.trail_signature != VALID_TRAIL_FS_INFO {
ret &= 8
log.warn("Invalid trailing signature in FSInfo.\0")
}
return ret
}
new_fs_info := fn(): FSInfo {
lead_reserved := @as([u8; 480], idk)
trail_reserved := @as([u8; 12], idk)
return FSInfo.(
VALID_LEAD_FS_INFO,
lead_reserved,
0,
0,
trail_reserved,
VALID_TRAIL_FS_INFO,
)
}

View file

@ -0,0 +1,25 @@
Date := struct {
year: u16,
month: u16,
day: u16,
}
Time := struct {
hour: u16,
minutes: u16,
seconds: u16,
}
compress_date := fn(year: u16, month: u16, day: u16): u16 {
return 0
}
decompress_date := fn(date: u16): Date {
return Date.(0, 0, 0)
}
compress_time := fn(hour: u16, minutes: u16, seconds: u16): u16 {
return 0
}
decompress_time := fn(time: u16): Time {
return Time.(0, 0, 0)
}

View file

@ -0,0 +1,21 @@
attributes := @use("attributes.hb")
datetime := @use("datetime.hb")
FileName := [u8; 11]
// This is the File Allocation Table entry that tells us where on disk the File is.
FileEntry := struct {
file_name: FileName,
attributes: u8,
// We could use this byte for something but we likely will not
nt_reserved: u8,
hundredths_seconds_creation: u8,
creation_time: datetime.time,
creation_date: datetime.date,
last_accessed_date: datetime.date,
high_cluster_number: u16,
last_modification_time: datetime.time,
last_modification_date: datetime.date,
low_cluster_number: u16,
file_size: u32,
}

View file

@ -0,0 +1,59 @@
stn := @use("../../../libraries/stn/src/lib.hb");
.{string, memory, buffer, log} := stn
attributes := @use("attributes.hb")
datetime := @use("datetime.hb")
directory := @use("file.hb")
bios_parameter_block := @use("bios_parameter_block.hb");
.{bpb_sanity_check, ebr_sanity_check, fs_info_sanity_check} := bios_parameter_block;
.{new_bpb, new_ebr, new_fs_info} := bios_parameter_block
FAT12_THRESHOLD := 4085
FAT16_THRESHOLD := 65525
ExFAT := 0
FAT12 := 1
FAT16 := 2
FAT32 := 3
calculate_fat_type := fn(sector_size: int, total_clusters: int): int {
if sector_size == 0 {
return ExFAT
} else if total_clusters < 4085 {
return FAT12
} else if total_clusters < 65525 {
return FAT16
} else {
return FAT32
}
}
main := fn(): int {
bpb := new_bpb()
ebr := new_ebr()
fsi := new_fs_info()
fat_type := calculate_fat_type(1, 100)
if fat_type != FAT32 {
log.warn("filesystem_fat32 driver only supports Fat32.\0")
}
bsc := bpb_sanity_check(bpb)
esc := ebr_sanity_check(ebr)
fssc := fs_info_sanity_check(fsi)
msg_type := 0
loop {
// Open file
if msg_type == 0 {
// Paths without a node-disk component are to be treated as local files.
file_path := "node-disk:/test\0"
} else {
// error
}
}
return 0
}

View file

@ -0,0 +1,3 @@
# Horizon
The Horizon Windowing system server. This is the component that spawns/layouts and renders windows.
For the api look in libraries/horizon_api.

Some files were not shown because too many files have changed in this diff Show more