Compare commits
No commits in common. "master" and "master" have entirely different histories.
|
@ -1,3 +1,2 @@
|
|||
[alias]
|
||||
repbuild = "run --manifest-path ./repbuild/Cargo.toml -- "
|
||||
dev = "run --manifest-path ./dev/Cargo.toml -r --"
|
||||
repbuild = "run --manifest-path ./repbuild/Cargo.toml --"
|
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
|
@ -1,5 +1,4 @@
|
|||
{
|
||||
"rust-analyzer.checkOnSave.allTargets": false,
|
||||
"rust-analyzer.showUnlinkedFileNotification": false,
|
||||
"C_Cpp.errorSquiggles": "disabled"
|
||||
"rust-analyzer.showUnlinkedFileNotification": false
|
||||
}
|
BIN
AAVMF_CODE.fd
Normal file
BIN
AAVMF_CODE.fd
Normal file
Binary file not shown.
1577
Cargo.lock
generated
1577
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
|
@ -1,9 +1,3 @@
|
|||
[workspace]
|
||||
resolver = "2"
|
||||
members = ["dev", "kernel", "repbuild"]
|
||||
|
||||
# [profile.release]
|
||||
# strip = "symbols"
|
||||
# codegen-units = 1
|
||||
# lto = true
|
||||
# panic = "abort"
|
||||
members = ["kernel", "repbuild"]
|
||||
|
|
69
HELP.md
69
HELP.md
|
@ -1,69 +0,0 @@
|
|||
### What are the requirements?
|
||||
- A machine with [Rustc Tier 1 platform support](https://doc.rust-lang.org/nightly/rustc/platform-support.html#tier-1-with-host-tools)
|
||||
- Rustup
|
||||
- QEMU (for executing)
|
||||
- GIT CLI
|
||||
|
||||
### How do I run ableos?
|
||||
- It is recommended to run ableos under QEMU. Here is how:
|
||||
- Install QEMU
|
||||
- Clone ableos
|
||||
- Go to ableos directory
|
||||
- Pull the limine submodule with `git submodule update --init`
|
||||
- Run `cargo repbuild help`
|
||||
|
||||
### How can I contribute?
|
||||
- [Contribute code](#how-do-i-contribute-code)
|
||||
- [Run ableos on your machine](#how-do-i-run-ableos)
|
||||
- Find bugs
|
||||
- Create media showing ableos
|
||||
|
||||
### How do I contribute code?
|
||||
- Start by forking ableos
|
||||
- Write something that runs in the userspace, for example:
|
||||
- System drivers
|
||||
- Programs
|
||||
- Libraries
|
||||
- Patch bugs and improve code in the kernel
|
||||
- Ensure that the code is OK to be maintained by asking in the [discord](https://discord.gg/t5Wt3K4YNA)
|
||||
- When you have finished your changes, you can submit a pull request for review [here](https://git.ablecorp.us/ableos/ableos)
|
||||
|
||||
### repbuild and kernel compile, but QEMU isn't starting
|
||||
- Ensure you have the `qemu-desktop-{arch}` for your OS and target architecture installed
|
||||
- Try running again with `--noaccel` if you have QEMU already
|
||||
|
||||
### I have run using repbuild but it's slow
|
||||
- Ensure release mode is enabled with the `-r` flag
|
||||
- Remove the `--noaccel` flag if you can
|
||||
- If both of these are already done, there may be a problem with thee VM, kernel, your program, or the hblang compiler
|
||||
|
||||
### Compiler is complaining about "reg id leaked"
|
||||
- [Submit](#how-do-i-report-a-compiler-bug) an issue, reg id leaked is a bug
|
||||
|
||||
### My program isn't running
|
||||
- Refer to [here](#i-have-run-using-repbuild-but-its-slow), it may be that your program is simply starting slowly
|
||||
- Ensure that your program has a properly written meta.toml file
|
||||
- Ensure that your program is enabled in [system_config.toml](sysdata/system_config.toml)
|
||||
- Try running again with `--noaccel`, there is a known bug with some systems that prevents programs from starting.
|
||||
|
||||
### Kernel panic??? Huh???
|
||||
- Kernel panics can be caused by improperly using memory (e.g, writing out of bounds)
|
||||
- Kernel panics are most likely to be caused when accessing memory or using `@eca` for kernel ecalls
|
||||
- [Report](#how-do-i-report-an-ableos-bug) a kernel panic
|
||||
|
||||
### I am running in release mode but I have no debug info
|
||||
- Add the `-d` flag for debug info
|
||||
|
||||
### What is `@eca`? How do I use it?
|
||||
- Eca is an ecall. They are similar to syscalls
|
||||
- The `@eca` directive takes the following arguments:
|
||||
- `@eca(ecall_number, reg_1, ..., reg_n)`
|
||||
- The various ecalls have different arguments that are given by register values
|
||||
- Most ecalls are wrapped by `stn`, for example, `random`, `buffer`, and `memory` all make use of ecalls
|
||||
- All ecalls can be found [ecah.rs](kernel/src/holeybytes/ecah.rs)
|
||||
|
||||
### How do I report an ableos bug?
|
||||
- Submit an issue [here](https://git.ablecorp.us/ableos/ableos/issues) or report it in the [discord](https://discord.gg/t5Wt3K4YNA)
|
||||
|
||||
### How do I report a compiler bug?
|
||||
- Submit an issue [here](https://git.ablecorp.us/ableos/holey-bytes/issues) or report it in the [discord](https://discord.gg/t5Wt3K4YNA)
|
12
README.md
12
README.md
|
@ -1,8 +1,6 @@
|
|||
# AbleOS
|
||||
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
|
||||
[Discord](https://discord.gg/JrKVukDtgs)
|
||||
|
||||
|
@ -10,7 +8,11 @@ Donations can be made [here on Liberapay](https://liberapay.com/AbleTheAbove) or
|
|||
<img src="https://img.shields.io/liberapay/patrons/AbleTheAbove.svg?logo=liberapay">
|
||||
|
||||
# Compiling
|
||||
See [HELP.md](HELP.md)
|
||||
AbleOS should be able to be built on any platform which is supported by
|
||||
[Rustc Tier 1 platform support](https://doc.rust-lang.org/nightly/rustc/platform-support.html#tier-1-with-host-tools).
|
||||
|
||||
# Developing
|
||||
There is a new work in progress developer tool for hblang. (see: dev folder)
|
||||
For running AbleOS, `repbuild` uses QEMU.
|
||||
|
||||
## Steps
|
||||
1. `git submodule update --init`
|
||||
2. `cargo repbuild`
|
||||
|
|
31
concepts/system.toml
Normal file
31
concepts/system.toml
Normal file
|
@ -0,0 +1,31 @@
|
|||
[boot]
|
||||
# This package must be installed system wide
|
||||
init = "init_server"
|
||||
|
||||
|
||||
[boot.limine]
|
||||
default_entry = 1
|
||||
timeout = 0
|
||||
verbose = true
|
||||
interface_resolution = "1024x768x24"
|
||||
# Terminal related settings
|
||||
term_wallpaper = "boot:///background.bmp"
|
||||
term_background = "008080"
|
||||
|
||||
[boot.limine.ableos]
|
||||
comment = "Default AbleOS boot entry."
|
||||
protocol = "limine"
|
||||
kernel_path = "boot:///kernel"
|
||||
kernel_cmdline = "baka=false foobles=true"
|
||||
resolution = "1024x768x24"
|
||||
|
||||
[repositories]
|
||||
core = "https://git.ablecorp.us/AbleOS/core"
|
||||
userspace = "https://git.ablecorp.us/AbleOS/ableos_userland"
|
||||
|
||||
|
||||
[packages]
|
||||
[packages.init_server]
|
||||
version = "1.0"
|
||||
hash = ""
|
||||
repo = "core"
|
|
@ -1,7 +0,0 @@
|
|||
[package]
|
||||
name = "dev"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
logos = "0.14.1"
|
|
@ -1,6 +0,0 @@
|
|||
# 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.
|
|
@ -1,84 +0,0 @@
|
|||
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
|
||||
}
|
|
@ -1,17 +0,0 @@
|
|||
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
152
dev/src/main.rs
|
@ -1,152 +0,0 @@
|
|||
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`"
|
||||
)
|
||||
}
|
|
@ -4,3 +4,6 @@ build-std-features = ["compiler-builtins-mem"]
|
|||
|
||||
[build]
|
||||
target = "./targets/x86_64-ableos.json"
|
||||
|
||||
[target.'cfg(target_arch = "x86_64")']
|
||||
rustflags = ["-C", "target-feature=+rdrand"]
|
||||
|
|
|
@ -5,49 +5,55 @@ version = "0.2.0"
|
|||
|
||||
|
||||
[dependencies]
|
||||
# embedded-graphics = "0.8"
|
||||
hbvm = { git = "https://git.ablecorp.us/AbleOS/holey-bytes.git", features = [
|
||||
"nightly",
|
||||
] }
|
||||
log = "0.4"
|
||||
spin = "0.9"
|
||||
slab = { version = "0.4", default-features = false }
|
||||
uart_16550 = { version = "0.3", features = ["nightly"] }
|
||||
xml.git = "https://git.ablecorp.us/ableos/ableos_userland"
|
||||
versioning.git = "https://git.ablecorp.us/ableos/ableos_userland"
|
||||
# able_graphics_library.git = "https://git.ablecorp.us/ableos/ableos_userland"
|
||||
hashbrown = { version = "0.15", features = ["nightly"] }
|
||||
limine = "0.1"
|
||||
embedded-graphics = "0.7"
|
||||
hbvm.git = "https://git.ablecorp.us/ableos/holey-bytes"
|
||||
log = "0.4"
|
||||
spin = "0.9"
|
||||
uart_16550 = "0.2"
|
||||
slab = { version = "0.4", default-features = false }
|
||||
xml.git = "https://git.ablecorp.us/ableos/ableos_userland"
|
||||
versioning.git = "https://git.ablecorp.us/ableos/ableos_userland"
|
||||
able_graphics_library.git = "https://git.ablecorp.us/ableos/ableos_userland"
|
||||
hashbrown = "*"
|
||||
kiam = "0.1.1"
|
||||
|
||||
[dependencies.limine]
|
||||
version = "0.1"
|
||||
git = "https://github.com/limine-bootloader/limine-rs"
|
||||
|
||||
[dependencies.crossbeam-queue]
|
||||
version = "0.3"
|
||||
version = "0.3"
|
||||
default-features = false
|
||||
features = ["alloc"]
|
||||
|
||||
[dependencies.clparse]
|
||||
git = "https://git.ablecorp.us/ableos/ableos_userland"
|
||||
default-features = false
|
||||
features = ["alloc", "nightly"]
|
||||
|
||||
[dependencies.derive_more]
|
||||
version = "1"
|
||||
version = "0.99"
|
||||
default-features = false
|
||||
features = [
|
||||
"add",
|
||||
"add_assign",
|
||||
"constructor",
|
||||
"display",
|
||||
"from",
|
||||
"into",
|
||||
"mul",
|
||||
"mul_assign",
|
||||
"not",
|
||||
"sum",
|
||||
"add",
|
||||
"add_assign",
|
||||
"constructor",
|
||||
"display",
|
||||
"from",
|
||||
"into",
|
||||
"mul",
|
||||
"mul_assign",
|
||||
"not",
|
||||
"sum",
|
||||
]
|
||||
|
||||
|
||||
[target.'cfg(target_arch = "x86_64")'.dependencies]
|
||||
x86_64 = "0.15"
|
||||
x86_64 = "0.14"
|
||||
x2apic = "0.4"
|
||||
# virtio-drivers = "0.7"
|
||||
virtio-drivers = "0.4.0"
|
||||
# rdrand = "*"
|
||||
rdrand = { version = "0.8", default-features = false }
|
||||
|
||||
|
||||
[target.'cfg(target_arch = "riscv64")'.dependencies]
|
||||
sbi = "0.2.0"
|
||||
|
||||
[target.'cfg(target_arch = "aarch64")'.dependencies]
|
||||
aarch64-cpu = "9"
|
||||
|
|
|
@ -38,7 +38,6 @@ SECTIONS
|
|||
|
||||
.data : {
|
||||
*(.data .data.*)
|
||||
*(.got .got.*)
|
||||
} :data
|
||||
|
||||
.bss : {
|
||||
|
|
|
@ -324,7 +324,7 @@ impl Heap {
|
|||
(unsafe { *self.bitmap.add(index / 8) } & (1 << (index % 8))) != 0
|
||||
}
|
||||
|
||||
pub const fn free_chunks(&self) -> usize {
|
||||
const fn free_chunks(&self) -> usize {
|
||||
self.total_chunks - self.allocated_chunks
|
||||
}
|
||||
|
||||
|
@ -345,7 +345,3 @@ fn alloc_error_handler(layout: alloc::alloc::Layout) -> ! {
|
|||
// Todo: Maybe panic here instead
|
||||
crate::arch::spin_loop()
|
||||
}
|
||||
|
||||
pub fn get_free_chunks_count() -> usize {
|
||||
ALLOCATOR.0.lock().as_ref().unwrap().free_chunks()
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use {
|
||||
crate::{device_tree::DeviceTree, kmain::DEVICE_TREE},
|
||||
crate::{alloc::string::ToString, device_tree::DeviceTree, kmain::DEVICE_TREE},
|
||||
alloc::string::String,
|
||||
core::arch::asm,
|
||||
xml::XMLElement,
|
||||
};
|
||||
|
@ -27,8 +28,8 @@ fn collect_cpu_info(device_tree: &mut DeviceTree) {
|
|||
cpus.push(cpu);
|
||||
}
|
||||
|
||||
fn cpu_id<'a>() -> (&'a str, u64) {
|
||||
let mut cpu_id: u64;
|
||||
fn cpu_id() -> (String, u64) {
|
||||
let mut cpu_id: u64 = 0;
|
||||
unsafe {
|
||||
asm!("mrs {cpu_id}, MIDR_EL1",
|
||||
cpu_id = out(reg) cpu_id,
|
||||
|
@ -38,11 +39,9 @@ fn cpu_id<'a>() -> (&'a str, u64) {
|
|||
let cpu_name = match cpu_id {
|
||||
// the source of these two was a stackoverflow question
|
||||
// https://raspberrypi.stackexchange.com/questions/117175/how-do-i-read-the-cpuid-in-aarch64-asm
|
||||
0x410FD034 => "Cortex-A53",
|
||||
0x410FD083 => "Cortex-A72",
|
||||
// the source of this one was checking the cpu id :thinking:
|
||||
0x410FD493 => "Neoverse N2",
|
||||
_ => "Unknown",
|
||||
0x410FD034 => "Cortex-A53".to_string(),
|
||||
0x410FD083 => "Cortex-A72".to_string(),
|
||||
_ => "Unknown".to_string(),
|
||||
};
|
||||
log::trace!("CPU Name: {cpu_name} - CPU ID: 0x{:X}", cpu_id);
|
||||
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
use {crate::logger::TERMINAL_LOGGER, core::fmt::Write, spin::Mutex};
|
||||
pub static SERIAL_CONSOLE: Mutex<SerialConsole> = Mutex::new(SerialConsole {
|
||||
const SERIAL_CONSOLE: Mutex<SerialConsole> = Mutex::new(SerialConsole {
|
||||
uart: 0x09000000 as *mut u8,
|
||||
});
|
||||
|
||||
pub struct SerialConsole {
|
||||
struct SerialConsole {
|
||||
uart: *mut u8,
|
||||
}
|
||||
|
||||
|
@ -17,12 +17,9 @@ 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 {
|
||||
SERIAL_CONSOLE.lock().write_fmt(args)?;
|
||||
// TERMINAL_LOGGER.lock().write_fmt(args)?;
|
||||
TERMINAL_LOGGER.lock().write_fmt(args)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
pub use logging::log;
|
||||
use {
|
||||
crate::{allocator, bootmodules::BootModule, kmain::kmain},
|
||||
alloc::vec::Vec,
|
||||
core::arch::asm,
|
||||
limine::FramebufferRequest,
|
||||
};
|
||||
|
@ -42,7 +41,7 @@ unsafe extern "C" fn _kernel_start() -> ! {
|
|||
static KFILE_REQ: KernelFileRequest = KernelFileRequest::new(0);
|
||||
static MOD_REQ: ModuleRequest = ModuleRequest::new(0);
|
||||
|
||||
let mut bootmodules = Vec::new();
|
||||
let mut bootmodules = alloc::vec::Vec::new();
|
||||
|
||||
if bm.is_some() {
|
||||
let bm = bm.unwrap();
|
||||
|
@ -53,13 +52,18 @@ unsafe extern "C" fn _kernel_start() -> ! {
|
|||
let raw_bytes = core::slice::from_raw_parts(
|
||||
file.base.as_ptr().expect("invalid initrd"),
|
||||
file.length as usize,
|
||||
);
|
||||
)
|
||||
.to_vec();
|
||||
|
||||
let file_path = file.path.to_str().unwrap().to_str();
|
||||
let file_path = alloc::string::String::from_utf8(
|
||||
file.path.to_str().unwrap().to_bytes().to_vec(),
|
||||
);
|
||||
if file_path.is_err() {
|
||||
panic!("invalid file path: {:?}", file_path);
|
||||
}
|
||||
let file_cmd = file.cmdline.to_str().unwrap().to_str();
|
||||
let file_cmd = alloc::string::String::from_utf8(
|
||||
file.cmdline.to_str().unwrap().to_bytes().to_vec(),
|
||||
);
|
||||
if file_cmd.is_err() {
|
||||
panic!("invalid module cmd: {:?}", file_cmd);
|
||||
}
|
||||
|
@ -81,7 +85,7 @@ unsafe extern "C" fn _kernel_start() -> ! {
|
|||
assert_eq!(bm.module_count, bootmodules.len() as u64);
|
||||
}
|
||||
|
||||
kmain(
|
||||
crate::kmain::kmain(
|
||||
KFILE_REQ
|
||||
.get_response()
|
||||
.get()
|
||||
|
@ -95,6 +99,8 @@ unsafe extern "C" fn _kernel_start() -> ! {
|
|||
.unwrap_or_default(),
|
||||
bootmodules,
|
||||
);
|
||||
|
||||
spin_loop();
|
||||
}
|
||||
|
||||
pub fn spin_loop() -> ! {
|
||||
|
@ -103,19 +109,8 @@ pub fn spin_loop() -> ! {
|
|||
}
|
||||
}
|
||||
|
||||
/// I am sorry.
|
||||
static mut A_REAL_RANDOM_U64_I_PROMISE: u64 = 0;
|
||||
|
||||
pub fn hardware_random_u64() -> u64 {
|
||||
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
|
||||
}
|
||||
0
|
||||
}
|
||||
|
||||
pub fn register_dump() {}
|
||||
|
|
|
@ -14,29 +14,3 @@ arch_cond!(
|
|||
riscv64: "riscv64",
|
||||
x86_64: "x86_64",
|
||||
);
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
use {crate::arch::interrupts::Interrupt, alloc::string::String};
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
pub struct InterruptList {
|
||||
list: HashMap<Interrupt, String>,
|
||||
}
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
use hashbrown::HashMap;
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
impl InterruptList {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
list: HashMap::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
use spin::{Lazy, Mutex};
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
pub static INTERRUPT_LIST: Lazy<Mutex<InterruptList>> = Lazy::new(|| {
|
||||
let mut il = InterruptList::new();
|
||||
use crate::alloc::string::ToString;
|
||||
il.list.insert(Interrupt::Timer, "PS/2 Mouse".to_string());
|
||||
Mutex::new(il)
|
||||
});
|
||||
|
|
|
@ -1,10 +1,8 @@
|
|||
use core::num;
|
||||
|
||||
use {
|
||||
crate::memory::{MemoryManager, PhysicalAddress, VirtualAddress},
|
||||
alloc::boxed::Box,
|
||||
spin::{Mutex, Once},
|
||||
};
|
||||
use alloc::boxed::Box;
|
||||
use spin::{Mutex, Once};
|
||||
use crate::memory::{MemoryManager, PhysicalAddress, VirtualAddress};
|
||||
|
||||
use super::PAGE_SIZE;
|
||||
|
||||
|
@ -30,7 +28,7 @@ impl PageSize {
|
|||
}
|
||||
|
||||
pub struct PageTable {
|
||||
entries: [PageEntry; 512],
|
||||
entries: [PageEntry; 512]
|
||||
}
|
||||
|
||||
impl PageTable {
|
||||
|
@ -74,14 +72,8 @@ impl PageTable {
|
|||
/// flags MUST include one or more of the following:
|
||||
/// Read, Write, Execute
|
||||
/// The valid bit automatically gets added
|
||||
pub fn map(
|
||||
&mut self,
|
||||
vaddr: VirtualAddress,
|
||||
paddr: PhysicalAddress,
|
||||
flags: PageEntryFlags,
|
||||
page_size: PageSize,
|
||||
) {
|
||||
assert!(flags as usize & 0xE != 0);
|
||||
pub fn map(&mut self, vaddr: VirtualAddress, paddr: PhysicalAddress, flags: PageEntryFlags, page_size: PageSize) {
|
||||
assert!(flags as usize & 0xe != 0);
|
||||
|
||||
let vpn = vaddr.vpns();
|
||||
let ppn = paddr.ppns();
|
||||
|
@ -99,7 +91,7 @@ impl PageTable {
|
|||
}
|
||||
|
||||
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.
|
||||
|
@ -113,24 +105,14 @@ impl PageTable {
|
|||
}
|
||||
|
||||
/// 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}");
|
||||
self.map(addr.as_addr().into(), addr, flags, page_size);
|
||||
}
|
||||
|
||||
/// Identity maps a range of contiguous memory
|
||||
/// 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}");
|
||||
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;
|
||||
|
@ -160,7 +142,7 @@ impl PageTable {
|
|||
}
|
||||
|
||||
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
|
||||
|
@ -200,7 +182,7 @@ pub enum PageEntryFlags {
|
|||
Global = 1 << 5,
|
||||
Access = 1 << 6,
|
||||
Dirty = 1 << 7,
|
||||
|
||||
|
||||
// for convenience
|
||||
ReadWrite = Self::Read as usize | Self::Write as usize,
|
||||
ReadExecute = Self::Read as usize | Self::Execute as usize,
|
||||
|
@ -246,7 +228,7 @@ impl PageEntry {
|
|||
}
|
||||
|
||||
fn addr(&self) -> PhysicalAddress {
|
||||
((self.entry() as usize & !0x3FF) << 2).into()
|
||||
((self.entry() as usize & !0x3ff) << 2).into()
|
||||
}
|
||||
|
||||
fn destroy(&mut self) {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
mod memory;
|
||||
|
||||
use {
|
||||
alloc::{boxed::Box, vec::Vec},
|
||||
alloc::boxed::Box,
|
||||
core::{
|
||||
arch::{asm, global_asm},
|
||||
fmt::Write,
|
||||
|
@ -45,7 +45,7 @@ extern "C" {
|
|||
static USABLE_MEMORY_SIZE: usize;
|
||||
}
|
||||
|
||||
pub static SERIAL_CONSOLE: Once<Mutex<MmioSerialPort>> = Once::new();
|
||||
static SERIAL_CONSOLE: Once<Mutex<MmioSerialPort>> = Once::new();
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn _kernel_start() -> ! {
|
||||
|
@ -95,7 +95,7 @@ unsafe extern "C" fn _kernel_start() -> ! {
|
|||
in(reg) satp_value,
|
||||
);
|
||||
|
||||
crate::kmain::kmain("baka=9", Vec::new());
|
||||
crate::kmain::kmain("baka=9", None);
|
||||
}
|
||||
|
||||
/// Spin loop
|
||||
|
@ -105,12 +105,6 @@ 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 {
|
||||
SERIAL_CONSOLE.get().unwrap().lock().write_fmt(args)
|
||||
}
|
||||
|
|
|
@ -11,9 +11,6 @@ use {
|
|||
|
||||
pub const DOUBLE_FAULT_IX: u16 = 0;
|
||||
|
||||
const STACK_SIZE: usize = 5 * 1024;
|
||||
const STACK_ALIGNMENT: usize = 1;
|
||||
|
||||
pub unsafe fn init() {
|
||||
use x86_64::instructions::{
|
||||
segmentation::{Segment, CS, SS},
|
||||
|
@ -35,24 +32,24 @@ struct Selectors {
|
|||
|
||||
static TSS: Lazy<TaskStateSegment> = Lazy::new(|| {
|
||||
let mut tss = TaskStateSegment::new();
|
||||
|
||||
let stack_ptr = unsafe {
|
||||
let layout = alloc::alloc::Layout::from_size_align(STACK_SIZE, STACK_ALIGNMENT)
|
||||
.expect("Failed to create stack layout");
|
||||
let stack = alloc::alloc::alloc(layout);
|
||||
VirtAddr::from_ptr(stack) + STACK_SIZE as u64
|
||||
tss.interrupt_stack_table[usize::from(DOUBLE_FAULT_IX)] = {
|
||||
const SIZE: usize = 5 * 1024;
|
||||
let stack = unsafe {
|
||||
alloc::alloc::alloc_zeroed(
|
||||
alloc::alloc::Layout::from_size_align(SIZE, 1).expect("stack pointer"),
|
||||
)
|
||||
};
|
||||
VirtAddr::from_ptr(stack) + SIZE
|
||||
};
|
||||
|
||||
tss.interrupt_stack_table[usize::from(DOUBLE_FAULT_IX)] = stack_ptr;
|
||||
tss
|
||||
});
|
||||
|
||||
static GDT: Lazy<(GlobalDescriptorTable, Selectors)> = Lazy::new(|| {
|
||||
let mut gdt = GlobalDescriptorTable::new();
|
||||
let sels = Selectors {
|
||||
kcode: gdt.append(Descriptor::kernel_code_segment()),
|
||||
kdata: gdt.append(Descriptor::kernel_data_segment()),
|
||||
tss: gdt.append(Descriptor::tss_segment(&TSS)),
|
||||
kcode: gdt.add_entry(Descriptor::kernel_code_segment()),
|
||||
kdata: gdt.add_entry(Descriptor::kernel_data_segment()),
|
||||
tss: gdt.add_entry(Descriptor::tss_segment(&TSS)),
|
||||
};
|
||||
(gdt, sels)
|
||||
});
|
||||
|
|
|
@ -1,54 +1,56 @@
|
|||
// TODO: Turn apic keyboard interrupt into a standard ipc message
|
||||
use {
|
||||
core::mem::MaybeUninit,
|
||||
log::trace,
|
||||
spin::{Lazy, Mutex},
|
||||
x2apic::lapic::{LocalApic, LocalApicBuilder},
|
||||
x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame, PageFaultErrorCode},
|
||||
};
|
||||
|
||||
/// Safety: Using LAPIC or IDT before init() is UB
|
||||
/// Using
|
||||
static mut LAPIC: LocalApic = unsafe { MaybeUninit::zeroed().assume_init() };
|
||||
static mut IDT: InterruptDescriptorTable = unsafe { MaybeUninit::zeroed().assume_init() };
|
||||
pub unsafe fn init() {
|
||||
trace!("Initialising IDT");
|
||||
IDT.load();
|
||||
Lazy::force(&LAPIC);
|
||||
x86_64::instructions::interrupts::enable();
|
||||
}
|
||||
|
||||
#[repr(u8)]
|
||||
#[derive(Debug, Eq, Hash, PartialEq)]
|
||||
|
||||
pub enum Interrupt {
|
||||
enum Interrupt {
|
||||
Timer = 32,
|
||||
|
||||
ApicErr = u8::MAX - 1,
|
||||
Spurious = u8::MAX,
|
||||
}
|
||||
|
||||
pub unsafe fn init() {
|
||||
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()
|
||||
pub(crate) static LAPIC: Lazy<Mutex<LocalApic>> = Lazy::new(|| {
|
||||
let mut lapic = LocalApicBuilder::new()
|
||||
.timer_vector(Interrupt::Timer as usize)
|
||||
.error_vector(Interrupt::ApicErr as usize)
|
||||
.spurious_vector(Interrupt::Spurious as usize)
|
||||
.set_xapic_base(
|
||||
x2apic::lapic::xapic_base()
|
||||
unsafe { x2apic::lapic::xapic_base() }
|
||||
+ super::memory::HHDM_OFFSET.load(core::sync::atomic::Ordering::Relaxed),
|
||||
)
|
||||
.build()
|
||||
.expect("Failed to setup Local APIC");
|
||||
LAPIC.enable();
|
||||
.expect("failed to setup Local APIC");
|
||||
unsafe { lapic.enable() };
|
||||
Mutex::new(lapic)
|
||||
});
|
||||
|
||||
x86_64::instructions::interrupts::enable();
|
||||
}
|
||||
static IDT: Lazy<InterruptDescriptorTable> = Lazy::new(|| {
|
||||
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) -> ! {
|
||||
panic!("Double fault: error code {error_code} \n{stack_frame:#?}")
|
||||
|
@ -62,49 +64,13 @@ extern "x86-interrupt" fn page_fault(
|
|||
}
|
||||
|
||||
extern "x86-interrupt" fn timer(_isf: InterruptStackFrame) {
|
||||
// interrupt(Interrupt::Timer);
|
||||
|
||||
unsafe {
|
||||
LAPIC.end_of_interrupt();
|
||||
}
|
||||
unsafe { LAPIC.lock().end_of_interrupt() };
|
||||
}
|
||||
|
||||
extern "x86-interrupt" fn apic_err(_: InterruptStackFrame) {
|
||||
interrupt(Interrupt::ApicErr);
|
||||
|
||||
panic!("Internal APIC error");
|
||||
}
|
||||
|
||||
extern "x86-interrupt" fn spurious(_: InterruptStackFrame) {
|
||||
interrupt(Interrupt::Spurious);
|
||||
|
||||
unsafe {
|
||||
LAPIC.end_of_interrupt();
|
||||
}
|
||||
}
|
||||
|
||||
fn interrupt(interrupt_type: Interrupt) {
|
||||
use crate::arch::INTERRUPT_LIST;
|
||||
let il = INTERRUPT_LIST.lock();
|
||||
let val = il.list.get(&interrupt_type).unwrap();
|
||||
|
||||
use crate::holeybytes::kernel_services::service_definition_service::sds_search_service;
|
||||
let buffer = sds_search_service(val);
|
||||
if buffer != 0 {
|
||||
use {crate::kmain::IPC_BUFFERS, alloc::vec::Vec};
|
||||
let mut buffs = IPC_BUFFERS.lock();
|
||||
match buffs.get_mut(&buffer) {
|
||||
Some(buff) => {
|
||||
let mut msg_vec = Vec::new();
|
||||
msg_vec.push(0xFF);
|
||||
buff.push(msg_vec.to_vec());
|
||||
log::debug!("Sent Message {:?} to Buffer({})", msg_vec, buffer);
|
||||
}
|
||||
None => {
|
||||
log::error!("Access of non-existent buffer {}", buffer)
|
||||
}
|
||||
}
|
||||
|
||||
// log::info!("{}", buffer);
|
||||
}
|
||||
unsafe { LAPIC.lock().end_of_interrupt() };
|
||||
}
|
||||
|
|
|
@ -1,6 +1,11 @@
|
|||
//! Logging (as in terms of console / serial output)
|
||||
#![allow(deprecated)]
|
||||
use {core::fmt::Write, spin::Mutex, uart_16550::SerialPort};
|
||||
use {
|
||||
core::fmt::Write,
|
||||
limine::{TerminalRequest, TerminalResponse},
|
||||
spin::{Lazy, Mutex},
|
||||
uart_16550::SerialPort,
|
||||
};
|
||||
|
||||
pub static SERIAL_CONSOLE: Mutex<SerialPort> = Mutex::new(unsafe { SerialPort::new(0x3F8) });
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use core::arch::x86_64::{_rdrand64_step, _rdseed64_step};
|
||||
|
||||
use {crate::bootmodules::BootModule, core::arch::asm, log::warn};
|
||||
use {
|
||||
crate::bootmodules::BootModule, core::arch::asm, embedded_graphics::pixelcolor::Rgb888,
|
||||
log::warn, rdrand::RdSeed,
|
||||
};
|
||||
pub mod memory;
|
||||
|
||||
mod cpuid;
|
||||
|
@ -10,7 +11,7 @@ pub mod graphics;
|
|||
pub(crate) mod interrupts;
|
||||
pub mod logging;
|
||||
pub mod pci;
|
||||
// pub mod virtio;
|
||||
pub mod virtio;
|
||||
|
||||
pub use {logging::log, memory::PAGE_SIZE};
|
||||
|
||||
|
@ -30,11 +31,9 @@ const INITIAL_KERNEL_HEAP_SIZE: *const () = _initial_kernel_heap_size as _;
|
|||
|
||||
#[no_mangle]
|
||||
#[naked]
|
||||
#[cfg(not(target_feature = "avx2"))]
|
||||
unsafe extern "C" fn _kernel_start() -> ! {
|
||||
// Initialise SSE, then jump to kernel entrypoint
|
||||
core::arch::naked_asm!(
|
||||
// Initialise SSE
|
||||
// Initialise SSE and jump to kernel entrypoint
|
||||
core::arch::asm!(
|
||||
"mov rax, cr0",
|
||||
"and ax, 0xfffb",
|
||||
"or ax, 0x2",
|
||||
|
@ -42,74 +41,16 @@ unsafe extern "C" fn _kernel_start() -> ! {
|
|||
"mov rax, cr4",
|
||||
"or ax, 3 << 9",
|
||||
"mov cr4, rax",
|
||||
|
||||
// Jump to the kernel entry point
|
||||
"jmp {}",
|
||||
sym start,
|
||||
options(noreturn),
|
||||
)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[naked]
|
||||
#[cfg(target_feature = "avx2")]
|
||||
unsafe extern "C" fn _kernel_start() -> ! {
|
||||
core::arch::naked_asm!(
|
||||
// Enable protected mode and configure control registers
|
||||
"mov rax, cr0",
|
||||
"and ax, 0xFFFB", // Clear CR0.EM (bit 2) for coprocessor emulation
|
||||
"or ax, 0x2", // Set CR0.MP (bit 1) for coprocessor monitoring
|
||||
"mov cr0, rax",
|
||||
|
||||
"mov rax, cr4",
|
||||
"or ax, (1 << 9) | (1 << 10)", // Set CR4.OSFXSR (bit 9) and CR4.OSXMMEXCPT (bit 10)
|
||||
"mov cr4, rax",
|
||||
|
||||
// Enable OSXSAVE (required for AVX, AVX2, and XSAVE)
|
||||
"mov rax, cr4",
|
||||
"or eax, 1 << 18", // Set CR4.OSXSAVE (bit 18)
|
||||
"mov cr4, rax",
|
||||
|
||||
// Enable AVX and AVX2 state saving
|
||||
"xor rcx, rcx",
|
||||
"xgetbv",
|
||||
"or eax, 7", // Enable SSE, AVX, and AVX2 state saving
|
||||
"xsetbv",
|
||||
|
||||
// Check for AVX and XSAVE support
|
||||
"mov eax, 1",
|
||||
"cpuid",
|
||||
"and ecx, 0x18000000",
|
||||
"cmp ecx, 0x18000000",
|
||||
"jne {1}", // Jump if AVX/OSXSAVE is not supported
|
||||
|
||||
// Check for BMI2 and AVX2 support
|
||||
"mov eax, 7",
|
||||
"xor ecx, ecx",
|
||||
"cpuid",
|
||||
"and ebx, (1 << 8) | (1 << 5)", // Check BMI2 (bit 8) and AVX2 (bit 5)
|
||||
"cmp ebx, (1 << 8) | (1 << 5)", // Compare to ensure both are supported
|
||||
|
||||
// Check for LZCNT and POPCNT support
|
||||
"mov eax, 1",
|
||||
"cpuid",
|
||||
"and ecx, (1 << 5) | (1 << 23)", // Check LZCNT (bit 5) and POPCNT (bit 23)
|
||||
"cmp ecx, (1 << 5) | (1 << 23)", // Compare to ensure both are supported
|
||||
|
||||
// Jump to the kernel entry point
|
||||
"jmp {0}",
|
||||
sym start,
|
||||
sym oops,
|
||||
)
|
||||
}
|
||||
|
||||
unsafe extern "C" fn oops() -> ! {
|
||||
panic!("your cpu is ancient >:(")
|
||||
}
|
||||
|
||||
unsafe extern "C" fn start() -> ! {
|
||||
logging::init();
|
||||
crate::logger::init().expect("failed to set logger");
|
||||
log::debug!("Initialising AKern {}", crate::VERSION);
|
||||
log::info!("Initialising AKern {}", crate::VERSION);
|
||||
|
||||
static HDHM_REQ: HhdmRequest = HhdmRequest::new(0);
|
||||
memory::init_pt(VirtAddr::new(
|
||||
|
@ -188,7 +129,7 @@ unsafe extern "C" fn start() -> ! {
|
|||
// TODO: Add in rdseed and rdrand as sources for randomness
|
||||
let _rand = xml::XMLElement::new("Random");
|
||||
|
||||
log::debug!("Getting boot modules");
|
||||
log::trace!("Getting boot modules");
|
||||
let bm = MOD_REQ.get_response().get();
|
||||
|
||||
let mut bootmodules = alloc::vec::Vec::new();
|
||||
|
@ -202,13 +143,18 @@ unsafe extern "C" fn start() -> ! {
|
|||
let raw_bytes = core::slice::from_raw_parts(
|
||||
file.base.as_ptr().expect("invalid initrd"),
|
||||
file.length as usize,
|
||||
);
|
||||
)
|
||||
.to_vec();
|
||||
|
||||
let file_path = file.path.to_str().unwrap().to_str();
|
||||
let file_path = alloc::string::String::from_utf8(
|
||||
file.path.to_str().unwrap().to_bytes().to_vec(),
|
||||
);
|
||||
if file_path.is_err() {
|
||||
panic!("invalid file path: {:?}", file_path);
|
||||
}
|
||||
let file_cmd = file.cmdline.to_str().unwrap().to_str();
|
||||
let file_cmd = alloc::string::String::from_utf8(
|
||||
file.cmdline.to_str().unwrap().to_bytes().to_vec(),
|
||||
);
|
||||
if file_cmd.is_err() {
|
||||
panic!("invalid module cmd: {:?}", file_cmd);
|
||||
}
|
||||
|
@ -226,7 +172,7 @@ unsafe extern "C" fn start() -> ! {
|
|||
break;
|
||||
}
|
||||
}
|
||||
log::debug!("Boot module count: {:?}", bootmodules.len());
|
||||
log::info!("Boot module count: {:?}", bootmodules.len());
|
||||
assert_eq!(bm.module_count, bootmodules.len() as u64);
|
||||
}
|
||||
|
||||
|
@ -249,21 +195,32 @@ unsafe extern "C" fn start() -> ! {
|
|||
/// Spin loop
|
||||
pub fn spin_loop() -> ! {
|
||||
loop {
|
||||
core::hint::spin_loop();
|
||||
x86_64::instructions::hlt()
|
||||
x86_64::instructions::hlt();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn hardware_random_u64() -> u64 {
|
||||
let mut out: u64 = 0;
|
||||
match unsafe { _rdrand64_step(&mut out) } {
|
||||
1 => out,
|
||||
_ => {
|
||||
use {log::trace, rdrand::RdRand};
|
||||
let gen = RdRand::new();
|
||||
match gen {
|
||||
Ok(gen) => {
|
||||
let ret = gen.try_next_u64().unwrap();
|
||||
trace!("Random {}", ret);
|
||||
return ret;
|
||||
}
|
||||
Err(err) => {
|
||||
warn!("RDRand not supported.");
|
||||
// Try rdseed
|
||||
match unsafe { _rdseed64_step(&mut out) } {
|
||||
1 => out,
|
||||
_ => panic!("Neither RDRand or RDSeed are supported"),
|
||||
let gen = RdSeed::new();
|
||||
match gen {
|
||||
Ok(gen) => {
|
||||
let ret = gen.try_next_u64().unwrap();
|
||||
trace!("Random {}", ret);
|
||||
return ret;
|
||||
}
|
||||
Err(err) => {
|
||||
panic!("Neither RDRand or RDSeed are supported")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -271,7 +228,6 @@ pub fn hardware_random_u64() -> u64 {
|
|||
|
||||
pub fn get_edid() {}
|
||||
|
||||
#[allow(unused)]
|
||||
pub fn register_dump() {
|
||||
let rax: u64;
|
||||
let rbx: u64 = 0;
|
||||
|
|
|
@ -8,12 +8,12 @@ pub struct PciDeviceInfo {
|
|||
pub full_class: PciFullClass,
|
||||
pub rev_id: u8,
|
||||
}
|
||||
use crate::alloc::string::ToString;
|
||||
|
||||
/// Enumerate PCI devices and run initialisation routines on ones we support
|
||||
pub fn init(device_tree: &mut DeviceTree) {
|
||||
device_tree
|
||||
.devices
|
||||
.insert("Unidentified PCI", alloc::vec![]);
|
||||
device_tree.devices
|
||||
.insert("Unidentified PCI".to_string(), alloc::vec![]);
|
||||
let mut devices = alloc::vec![];
|
||||
|
||||
for bus in 0..=255 {
|
||||
|
@ -23,7 +23,6 @@ pub fn init(device_tree: &mut DeviceTree) {
|
|||
let id = device_info.device_id.id;
|
||||
use Vendor::*;
|
||||
let (dev_type, dev_name) = match (vendor, id) {
|
||||
(VMWareInc, 1029) => ("GPUs", "SVGAII PCI GPU"),
|
||||
(Qemu, 4369) => ("GPUs", "QEMU VGA"),
|
||||
(VirtIO, 4176) => ("GPUs", "VirtIO PCI GPU"),
|
||||
(CirrusLogic, 184) => ("GPUs", "Cirrus SVGA"), //GD 5446?
|
||||
|
@ -46,8 +45,7 @@ pub fn init(device_tree: &mut DeviceTree) {
|
|||
pci_info.set_attribute("id", id);
|
||||
pci_info.set_attribute("device", device_info.device);
|
||||
pci_info.set_attribute("vendor", vendor);
|
||||
pci_info.set_attribute("bus", bus);
|
||||
pci_info.set_attribute("class", device_info.full_class);
|
||||
pci_info.set_attribute("class", device_info.full_class.to_string());
|
||||
dev.set_child(pci_info);
|
||||
devices.push((dev_type, dev));
|
||||
}
|
||||
|
@ -68,8 +66,7 @@ pub fn check_device(bus: u8, device: u8) -> Option<PciDeviceInfo> {
|
|||
return None;
|
||||
}
|
||||
|
||||
let (reg2, addr) = unsafe { pci_config_read_2(bus, device, 0, 0x8) };
|
||||
log::debug!("pci device-({}) addr {} is {}", device, addr, reg2);
|
||||
let reg2 = unsafe { pci_config_read(bus, device, 0, 0x8) };
|
||||
let class = ((reg2 >> 16) & 0x0000_FFFF) as u16;
|
||||
let pci_class = PciFullClass::from_u16(class);
|
||||
let header_type = get_header_type(bus, device, 0);
|
||||
|
@ -272,7 +269,8 @@ impl Display for Vendor {
|
|||
|
||||
use core::fmt::Display;
|
||||
|
||||
use {crate::device_tree::DeviceTree, x86_64::instructions::port::Port};
|
||||
use x86_64::instructions::port::Port;
|
||||
use crate::device_tree::DeviceTree;
|
||||
|
||||
#[allow(non_camel_case_types, dead_code)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
|
@ -460,7 +458,9 @@ unsafe fn pci_config_read(bus: u8, device: u8, func: u8, offset: u8) -> 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;
|
||||
let address =
|
||||
((bus << 16) | (device << 11) | (func << 8) | (offset & 0xFC) | 0x8000_0000) as u32;
|
||||
|
||||
// write address
|
||||
Port::new(0xCF8).write(address);
|
||||
|
||||
|
@ -468,20 +468,6 @@ unsafe fn pci_config_read(bus: u8, device: u8, func: u8, offset: u8) -> u32 {
|
|||
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) {
|
||||
let bus = bus as u32;
|
||||
let device = device as u32;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use {
|
||||
core::ptr::NonNull,
|
||||
core::{ptr::NonNull},
|
||||
virtio_drivers::{BufferDirection, Hal, PhysAddr},
|
||||
};
|
||||
|
||||
|
|
|
@ -1,36 +1,36 @@
|
|||
use {
|
||||
// crate::alloc::string::ToString,
|
||||
alloc::vec::Vec,
|
||||
// clparse::Arguments,
|
||||
// core::fmt::{Debug, Display},
|
||||
// log::trace,
|
||||
// xml::XMLElement,
|
||||
crate::alloc::string::ToString,
|
||||
alloc::{string::String, vec::Vec},
|
||||
clparse::Arguments,
|
||||
core::fmt::{Debug, Display},
|
||||
log::trace,
|
||||
xml::XMLElement,
|
||||
};
|
||||
pub type BootModules<'a> = Vec<BootModule<'a>>;
|
||||
pub type BootModules = Vec<BootModule>;
|
||||
|
||||
pub struct BootModule<'a> {
|
||||
pub path: &'a str,
|
||||
pub bytes: &'a [u8],
|
||||
pub cmd: &'a str,
|
||||
pub struct BootModule {
|
||||
pub path: String,
|
||||
pub bytes: Vec<u8>,
|
||||
pub cmd: String,
|
||||
}
|
||||
impl<'a> BootModule<'a> {
|
||||
pub fn new(path: &'a str, bytes: &'a [u8], cmd: &'a str) -> Self {
|
||||
impl BootModule {
|
||||
pub fn new(path: String, bytes: Vec<u8>, cmd: String) -> Self {
|
||||
Self { path, bytes, cmd }
|
||||
}
|
||||
}
|
||||
|
||||
// pub fn build_cmd<T: Display + Debug>(name: T, cmdline: T) -> XMLElement {
|
||||
// let mut cmdline = cmdline.to_string();
|
||||
// cmdline.pop();
|
||||
// cmdline.remove(0);
|
||||
pub fn build_cmd<T: Display + Debug>(name: T, cmdline: T) -> XMLElement {
|
||||
let mut cmdline = cmdline.to_string();
|
||||
cmdline.pop();
|
||||
cmdline.remove(0);
|
||||
|
||||
// let cmd = Arguments::parse(cmdline.to_string()).unwrap();
|
||||
// trace!("Cmdline: {cmd:?}");
|
||||
let cmd = Arguments::parse(cmdline.to_string()).unwrap();
|
||||
trace!("Cmdline: {cmd:?}");
|
||||
|
||||
// let mut clo = XMLElement::new(name);
|
||||
// for (key, value) in cmd.arguments {
|
||||
// clo.set_attribute(key, value);
|
||||
// }
|
||||
// trace!("command line object: {:?}", clo);
|
||||
// clo
|
||||
// }
|
||||
let mut clo = XMLElement::new(name);
|
||||
for (key, value) in cmd.arguments {
|
||||
clo.set_attribute(key, value);
|
||||
}
|
||||
trace!("command line object: {:?}", clo);
|
||||
clo
|
||||
}
|
||||
|
|
|
@ -1,7 +1,11 @@
|
|||
//! A tree of hardware devices
|
||||
|
||||
use {alloc::vec::Vec, core::fmt, hashbrown::HashMap};
|
||||
|
||||
use {
|
||||
crate::alloc::string::ToString,
|
||||
alloc::{string::String, vec::Vec},
|
||||
core::fmt,
|
||||
hashbrown::HashMap,
|
||||
};
|
||||
/// A device object.
|
||||
/// TODO define device
|
||||
pub type Device = xml::XMLElement;
|
||||
|
@ -9,40 +13,38 @@ pub type Device = xml::XMLElement;
|
|||
/// A tree of devices
|
||||
// TODO: alphabetize this list
|
||||
#[derive(Debug)]
|
||||
pub struct DeviceTree<'a> {
|
||||
pub struct DeviceTree {
|
||||
/// The device tree
|
||||
pub devices: HashMap<&'a str, Vec<Device>>,
|
||||
pub devices: HashMap<String, Vec<Device>>,
|
||||
}
|
||||
impl<'a> DeviceTree<'a> {
|
||||
impl DeviceTree {
|
||||
/// Build the device tree. Does not populate the device tree
|
||||
pub fn new() -> Self {
|
||||
let mut dt = Self {
|
||||
devices: HashMap::new(),
|
||||
};
|
||||
device_tree!(
|
||||
dt,
|
||||
[
|
||||
"Mice",
|
||||
"Keyboards",
|
||||
"Controllers",
|
||||
"Generic HIDs",
|
||||
"Disk Drives",
|
||||
"CD Drives",
|
||||
"Batteries",
|
||||
"Monitors",
|
||||
"GPUs",
|
||||
"CPUs",
|
||||
"USB",
|
||||
"Serial Ports",
|
||||
"Cameras",
|
||||
"Biometric Devices",
|
||||
]
|
||||
);
|
||||
device_tree!(dt, [
|
||||
"Mice",
|
||||
"Keyboards",
|
||||
"Controllers",
|
||||
"Generic HIDs",
|
||||
"Disk Drives",
|
||||
"CD Drives",
|
||||
"Batteries",
|
||||
"Monitors",
|
||||
"GPUs",
|
||||
"CPUs",
|
||||
"USB",
|
||||
"Serial Ports",
|
||||
"Cameras",
|
||||
"Biometric Devices",
|
||||
]);
|
||||
dt
|
||||
}
|
||||
}
|
||||
use crate::{device_tree, tab, utils::TAB};
|
||||
impl<'a> fmt::Display for DeviceTree<'a> {
|
||||
use crate::{utils::TAB, device_tree};
|
||||
use crate::tab;
|
||||
impl fmt::Display for DeviceTree {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
writeln!(f)?;
|
||||
for (device_type, devices) in &self.devices {
|
|
@ -1,35 +0,0 @@
|
|||
enum Sections {
|
||||
Header,
|
||||
Code,
|
||||
Data,
|
||||
Debug,
|
||||
Config,
|
||||
Metadata,
|
||||
}
|
||||
|
||||
// 64 byte header
|
||||
#[repr(packed)]
|
||||
struct AbleOsExecutableHeader {
|
||||
magic_number: [u8; 3],
|
||||
executable_version: u32,
|
||||
|
||||
code_length: u64,
|
||||
data_length: u64,
|
||||
debug_length: u64,
|
||||
config_length: u64,
|
||||
metadata_length: u64,
|
||||
}
|
||||
|
||||
impl AbleOsExecutableHeader {
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
magic_number: [0x15, 0x91, 0xD2],
|
||||
executable_version: 0,
|
||||
code_length: 0,
|
||||
config_length: 0,
|
||||
data_length: 0,
|
||||
debug_length: 0,
|
||||
metadata_length: 0,
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,42 +1,19 @@
|
|||
//! Environment call handling routines
|
||||
|
||||
use {alloc::boxed::Box, core::cell::LazyCell, hbvm::mem::Address};
|
||||
|
||||
use crate::{
|
||||
holeybytes::{
|
||||
kernel_services::{
|
||||
block_read, dt_msg_handler::dt_msg_handler, logging_service::log_msg_handler,
|
||||
service_definition_service::sds_msg_handler,
|
||||
},
|
||||
ExecThread,
|
||||
},
|
||||
kmain::EXECUTOR,
|
||||
task::Executor,
|
||||
};
|
||||
|
||||
use {
|
||||
super::Vm,
|
||||
crate::{arch, ipc::buffer::IpcBuffer, kmain::IPC_BUFFERS},
|
||||
hbvm::value::Value,
|
||||
log::{debug, error, info, trace},
|
||||
super::{mem::Memory, Vm},
|
||||
crate::{arch, holeybytes::mem, ipc::buffer::IpcBuffer, kmain::IPC_BUFFERS},
|
||||
alloc::string::String,
|
||||
log::{debug, error, info, trace, warn},
|
||||
};
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
#[inline(always)]
|
||||
unsafe fn x86_out<T: x86_64::instructions::port::PortWrite>(address: u16, value: T) {
|
||||
x86_64::instructions::port::Port::new(address).write(value);
|
||||
}
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
#[inline(always)]
|
||||
unsafe fn x86_in<T: x86_64::instructions::port::PortRead>(address: u16) -> T {
|
||||
x86_64::instructions::port::Port::new(address).read()
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn handler(vm: &mut Vm) {
|
||||
let ecall_number = vm.registers[2].cast::<u64>();
|
||||
let r1 = vm.registers[1].cast::<u64>();
|
||||
|
||||
match ecall_number {
|
||||
// debug!("Ecall number {:?}", r1);
|
||||
// trace!("Register dump: {:?}", vm.registers);
|
||||
|
||||
match r1 {
|
||||
0 => {
|
||||
// TODO: explode computer
|
||||
// hello world ecall
|
||||
|
@ -47,210 +24,155 @@ pub fn handler(vm: &mut Vm) {
|
|||
1 => {
|
||||
// Make buffer
|
||||
|
||||
let bounded = match vm.registers[3] {
|
||||
Value(0) => false,
|
||||
Value(1) => true,
|
||||
let bounded = match vm.registers[2].cast::<u64>() {
|
||||
0 => false,
|
||||
1 => true,
|
||||
_ => {
|
||||
panic!("Bad");
|
||||
}
|
||||
};
|
||||
|
||||
let length = vm.registers[4].cast::<u64>();
|
||||
let length = vm.registers[3].cast::<u64>();
|
||||
|
||||
let mut buffs = IPC_BUFFERS.lock();
|
||||
let abc;
|
||||
|
||||
match bounded {
|
||||
false => {
|
||||
abc = IpcBuffer::new(false, 0);
|
||||
}
|
||||
true => {
|
||||
abc = IpcBuffer::new(true, length);
|
||||
}
|
||||
};
|
||||
let buff_id = arch::hardware_random_u64();
|
||||
buffs.insert(
|
||||
buff_id,
|
||||
match bounded {
|
||||
false => IpcBuffer::new(false, 0),
|
||||
true => IpcBuffer::new(true, length),
|
||||
},
|
||||
);
|
||||
buffs.insert(buff_id, abc);
|
||||
debug!("Buffer ID: {}", buff_id);
|
||||
vm.registers[1] = hbvm::value::Value(buff_id);
|
||||
}
|
||||
2 => {
|
||||
log::error!("Oops, deleting buffers is not implemented.")
|
||||
// Delete buffer
|
||||
}
|
||||
3 => {
|
||||
// Send a message to a buffer
|
||||
let buffer_id = vm.registers[3].cast::<u64>();
|
||||
let mem_addr = vm.registers[4].cast::<u64>();
|
||||
let length = vm.registers[5].cast::<u64>() as usize;
|
||||
let r2 = vm.registers[2].cast::<u64>();
|
||||
let r3 = vm.registers[3].cast::<u64>();
|
||||
let r4 = vm.registers[4].cast::<u64>();
|
||||
|
||||
let buffer_id = r2;
|
||||
let mem_addr = r3;
|
||||
let length = r4 as usize;
|
||||
trace!("IPC address: {:?}", mem_addr);
|
||||
use alloc::vec::Vec;
|
||||
|
||||
match buffer_id {
|
||||
0 => match sds_msg_handler(vm, mem_addr, length) {
|
||||
Ok(()) => {}
|
||||
Err(err) => log::error!("Improper sds format: {err:?}"),
|
||||
},
|
||||
1 => match log_msg_handler(vm, mem_addr, length) {
|
||||
Ok(()) => {}
|
||||
Err(_) => log::error!("Improper log format"),
|
||||
Err(err) => log::error!("Improper log format"),
|
||||
},
|
||||
2 => {
|
||||
use crate::holeybytes::kernel_services::mem_serve::memory_msg_handler;
|
||||
match memory_msg_handler(vm, mem_addr, length) {
|
||||
Ok(_) => {}
|
||||
Err(_) => {}
|
||||
}
|
||||
}
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
3 => {
|
||||
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_unchecked());
|
||||
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_unchecked());
|
||||
// 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 => {
|
||||
let block = block_read(mem_addr, length);
|
||||
block.chunks_mut(8.min(length)).for_each(|chunk| {
|
||||
chunk.clone_from_slice(
|
||||
&crate::arch::hardware_random_u64().to_le_bytes()[..chunk.len()],
|
||||
);
|
||||
});
|
||||
vm.registers[1] = hbvm::value::Value(mem_addr);
|
||||
}
|
||||
5 => match dt_msg_handler(vm, mem_addr, length) {
|
||||
2 => match memory_msg_handler(vm, mem_addr, length) {
|
||||
Ok(()) => {}
|
||||
Err(_) => log::error!("Improper dt query"),
|
||||
Err(err) => log::error!("Improper log format"),
|
||||
},
|
||||
6 => unsafe {
|
||||
let program = block_read(mem_addr, length);
|
||||
|
||||
// decode AbleOS Executable format
|
||||
let header = &program[0..46];
|
||||
let magic_slice = &header[0..3];
|
||||
if magic_slice != [0x15, 0x91, 0xD2] {
|
||||
log::error!("Invalid magic number at the start of executable.");
|
||||
return;
|
||||
}
|
||||
|
||||
let executable_format_version =
|
||||
u32::from_le_bytes(header[3..7].try_into().unwrap());
|
||||
let offset = if executable_format_version == 0 {
|
||||
47
|
||||
} else {
|
||||
error!("Invalid executable format.");
|
||||
return;
|
||||
};
|
||||
|
||||
let code_length = u64::from_le_bytes(header[7..15].try_into().unwrap());
|
||||
let data_length = u64::from_le_bytes(header[15..23].try_into().unwrap());
|
||||
let end = (code_length + data_length) as usize;
|
||||
log::debug!("{code_length} + {data_length} = {end}");
|
||||
|
||||
let thr = ExecThread::new(&program[offset..end], Address::new(0));
|
||||
vm.registers[1] = Value(
|
||||
LazyCell::<Executor>::get_mut(&mut EXECUTOR)
|
||||
.unwrap()
|
||||
.spawn(Box::pin(async move {
|
||||
if let Err(e) = thr.await {
|
||||
log::error!("{e:?}");
|
||||
}
|
||||
})) as u64,
|
||||
);
|
||||
log::debug!("spawned a process");
|
||||
},
|
||||
|
||||
buffer_id => {
|
||||
let mut buffs = IPC_BUFFERS.lock();
|
||||
|
||||
match buffs.get_mut(&buffer_id) {
|
||||
Some(buff) => {
|
||||
let msg_vec = block_read(mem_addr, length);
|
||||
buff.push(msg_vec.to_vec());
|
||||
debug!("Sent Message {:?} to Buffer({})", msg_vec, buffer_id);
|
||||
let mut msg_vec = vec![];
|
||||
|
||||
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);
|
||||
}
|
||||
buff.push(msg_vec.clone());
|
||||
info!(
|
||||
"Message {:?} has been sent to Buffer({})",
|
||||
msg_vec, buffer_id
|
||||
);
|
||||
}
|
||||
None => {
|
||||
log::error!("Access of non-existent buffer {}", buffer_id)
|
||||
}
|
||||
}
|
||||
drop(buffs);
|
||||
}
|
||||
}
|
||||
}
|
||||
4 => {
|
||||
let buffer_id = vm.registers[3].cast::<u64>();
|
||||
let map_ptr = vm.registers[4].cast::<u64>();
|
||||
let max_length = vm.registers[5].cast::<u64>();
|
||||
let r2 = vm.registers[2].cast::<u64>();
|
||||
|
||||
let mut buffs = IPC_BUFFERS.lock();
|
||||
let buff: &mut IpcBuffer = match buffs.get_mut(&buffer_id) {
|
||||
Some(buff) => buff,
|
||||
None => panic!(
|
||||
"Failed to get buffer: id={buffer_id}, ptr={map_ptr}, length={max_length}"
|
||||
),
|
||||
};
|
||||
|
||||
let msg = match buff.pop() {
|
||||
Ok(msg) => msg,
|
||||
Err(_) => return,
|
||||
};
|
||||
if msg.len() > unsafe { max_length.try_into().unwrap_unchecked() } {
|
||||
info!("{}", max_length);
|
||||
error!("Message is too long to map in.");
|
||||
} else {
|
||||
unsafe {
|
||||
let ptr = map_ptr as *mut u8;
|
||||
ptr.copy_from_nonoverlapping(msg.as_ptr(), msg.len());
|
||||
}
|
||||
|
||||
debug!("Recieve {:?} from Buffer({})", msg, buffer_id);
|
||||
}
|
||||
let mut buff = buffs.get_mut(&r2).unwrap();
|
||||
let msg = buff.pop();
|
||||
info!("Recieve {:?} from Buffer({})", msg, r2);
|
||||
}
|
||||
5 => {
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
{
|
||||
let r2 = vm.registers[2].cast::<u64>();
|
||||
let x = hbvm::value::Value(unsafe { x86_in::<u8>(r2 as u16) } as u64);
|
||||
// info!("Read {:?} from Port {:?}", x, r2);
|
||||
vm.registers[3] = x
|
||||
}
|
||||
let r2 = vm.registers[2].cast::<u64>();
|
||||
vm.registers[3] = hbvm::value::Value( unsafe { x86_in(r2 as u16) } as u64);
|
||||
}
|
||||
// 5
|
||||
_ => {
|
||||
log::error!("Syscall unknown {:?}{:?}", ecall_number, vm.registers);
|
||||
log::error!("Syscall unknown {:?}{:?}", r1, vm.registers);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn x86_in(address: u16) -> u32{
|
||||
x86_64::instructions::port::Port::new(address).read()
|
||||
}
|
||||
unsafe fn x86_out(address: u16, value: u32){
|
||||
x86_64::instructions::port::Port::new(address).write(value);
|
||||
}
|
||||
|
||||
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 = vec![];
|
||||
|
||||
for x in 0..(length as isize) {
|
||||
let xyz = mem_addr as *const u8;
|
||||
let value = unsafe { xyz.offset(x).read() };
|
||||
// info!("{} - 0x{:x?} - {}", value, value, value as char);
|
||||
msg_vec.push(value);
|
||||
}
|
||||
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)]
|
||||
pub enum LogError {
|
||||
NoMessages,
|
||||
InvalidLogFormat,
|
||||
}
|
||||
use {alloc::vec, log::Record};
|
||||
|
||||
fn memory_msg_handler(vm: &mut Vm, mem_addr: u64, length: usize) -> Result<(), LogError> {
|
||||
let mut val = alloc::vec::Vec::new();
|
||||
for _ in 0..4096 {
|
||||
val.push(0);
|
||||
}
|
||||
info!("Block address: {:?}", val.as_ptr());
|
||||
vm.registers[1] = hbvm::value::Value(val.as_ptr() as u64);
|
||||
vm.registers[2] = hbvm::value::Value(4096);
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -1,78 +0,0 @@
|
|||
use {
|
||||
crate::holeybytes::{kernel_services::block_read, Vm},
|
||||
alloc::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 query_string = core::str::from_utf8(
|
||||
msg_vec
|
||||
.split_once(|&byte| byte == 0)
|
||||
.unwrap_or((msg_vec, &[]))
|
||||
.0,
|
||||
)
|
||||
.unwrap();
|
||||
log::trace!("Query {}", query_string);
|
||||
|
||||
let ret = query_parse(query_string);
|
||||
log::trace!("Query response {}", ret);
|
||||
|
||||
vm.registers[1] = hbvm::value::Value(ret);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn query_parse(query_string: &str) -> u64 {
|
||||
let query = query_string.split('/').collect::<Vec<&str>>();
|
||||
|
||||
let first_fragment: &str = &query[0];
|
||||
let ret = match first_fragment {
|
||||
"framebuffer" => framebuffer_parse(query),
|
||||
"cpu" => cpu_parse(query),
|
||||
|
||||
_ => 0,
|
||||
};
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
fn cpu_parse(qt_parse_step_two: Vec<&str>) -> u64 {
|
||||
let second_fragment: &str = qt_parse_step_two[1];
|
||||
match second_fragment {
|
||||
// "architecture" => {
|
||||
// return 0;
|
||||
// }
|
||||
_ => {
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
fn framebuffer_parse(qt_parse_step_two: Vec<&str>) -> u64 {
|
||||
use crate::kmain::FB_REQ;
|
||||
let fbs = &mut FB_REQ.get_response().get().unwrap().framebuffers();
|
||||
let second_fragment: &str = qt_parse_step_two[1];
|
||||
match second_fragment {
|
||||
"fb0" => {
|
||||
let fb_front = &fbs[0];
|
||||
let third_fragment: &str = qt_parse_step_two[2];
|
||||
let 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;
|
||||
}
|
||||
};
|
||||
}
|
|
@ -1,54 +0,0 @@
|
|||
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);
|
||||
|
||||
use log::Level::*;
|
||||
let log_level = match msg_vec[0] {
|
||||
0 | 48 => Error,
|
||||
1 | 49 => Warn,
|
||||
2 | 50 => Info,
|
||||
3 | 51 => Debug,
|
||||
4 | 52 => Trace,
|
||||
_ => {
|
||||
return Err(LogError::InvalidLogFormat);
|
||||
}
|
||||
};
|
||||
if log_level > log::max_level() {
|
||||
return Ok(());
|
||||
}
|
||||
let strptr = u64::from_le_bytes(msg_vec[1..9].try_into().unwrap());
|
||||
let strlen = u64::from_le_bytes(msg_vec[9..17].try_into().unwrap()) as usize;
|
||||
|
||||
let str = block_read(strptr, strlen);
|
||||
|
||||
let file_name = "None";
|
||||
let line_number = 0;
|
||||
|
||||
match core::str::from_utf8(&str) {
|
||||
Ok(strr) => {
|
||||
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(())
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
enum MemoryServiceResult {
|
||||
|
||||
}
|
||||
|
||||
@alignment(4096)
|
||||
type PageAlignedPointer = pointer;
|
||||
|
||||
type RID = u64;
|
||||
|
||||
|
||||
|
||||
@nonexhaustive
|
||||
@version 1.0
|
||||
protocol MemoryService {
|
||||
@validator(page_count, Range(1..16))
|
||||
fn map_pages(page_count: u8, ptr: Optional<PageAlignedPointer>) -> MemoryServiceResult;
|
||||
fn unmap_pages(ptr: PageAlignedPointer) -> MemoryServiceResult;
|
||||
// ptr must be page aligned and already mapped from map_pages
|
||||
fn map_hardware(hw: RID, ptr: PageAlignedPointer) -> MemoryServiceResult;
|
||||
fn unmap_hardware(hw: RID) -> MemoryServiceResult;
|
||||
|
||||
}
|
|
@ -1,119 +0,0 @@
|
|||
use {
|
||||
crate::holeybytes::{kernel_services::block_read, Vm},
|
||||
alloc::alloc::{alloc, dealloc},
|
||||
core::alloc::Layout,
|
||||
log::{debug, info},
|
||||
};
|
||||
|
||||
pub enum MemoryServiceError {
|
||||
InvalidMemoryFormat,
|
||||
}
|
||||
#[derive(Debug)]
|
||||
pub enum MemoryQuotaType {
|
||||
NoQuota = 0,
|
||||
SoftQuota = 1,
|
||||
HardQuota = 2,
|
||||
KillQuota = 3,
|
||||
}
|
||||
|
||||
fn alloc_page(vm: &mut Vm, _mem_addr: u64, _length: usize) -> Result<(), MemoryServiceError> {
|
||||
let ptr = unsafe { alloc(Layout::from_size_align_unchecked(4096, 8)) };
|
||||
info!("Block address: {:?}", ptr);
|
||||
vm.registers[1] = hbvm::value::Value(ptr as u64);
|
||||
vm.registers[2] = hbvm::value::Value(4096);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
unsafe fn memset(dest: *mut u8, src: *const u8, count: usize, size: usize) {
|
||||
let total_size = count * size;
|
||||
src.copy_to_nonoverlapping(dest, size);
|
||||
|
||||
let mut copied = size;
|
||||
|
||||
while copied < total_size {
|
||||
let copy_size = copied.min(total_size - copied);
|
||||
dest.add(copied).copy_from_nonoverlapping(dest, copy_size);
|
||||
copied += copy_size;
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn memory_msg_handler(
|
||||
vm: &mut Vm,
|
||||
mem_addr: u64,
|
||||
length: usize,
|
||||
) -> Result<(), MemoryServiceError> {
|
||||
let msg_vec = block_read(mem_addr, length);
|
||||
let msg_type = msg_vec[0];
|
||||
match msg_type {
|
||||
0 => unsafe {
|
||||
let page_count = msg_vec[1];
|
||||
|
||||
let ptr = alloc(Layout::from_size_align_unchecked(
|
||||
page_count as usize * 4096,
|
||||
8,
|
||||
));
|
||||
|
||||
log::debug!("Allocating {} pages @ {:x}", page_count, ptr as u64);
|
||||
|
||||
vm.registers[1] = hbvm::value::Value(ptr as u64);
|
||||
log::debug!("Kernel ptr: {:x}", ptr as u64);
|
||||
},
|
||||
|
||||
1 => unsafe {
|
||||
let page_count = msg_vec[1];
|
||||
|
||||
let mptr_raw: [u8; 8] = msg_vec[2..10].try_into().unwrap();
|
||||
let mptr: u64 = u64::from_le_bytes(mptr_raw);
|
||||
log::debug!("Deallocating {} pages @ {:x}", page_count, mptr);
|
||||
|
||||
dealloc(
|
||||
mptr as *mut u8,
|
||||
Layout::from_size_align_unchecked(page_count as usize * 4096, 8),
|
||||
)
|
||||
},
|
||||
2 => {
|
||||
use MemoryQuotaType::*;
|
||||
let quota_type = match msg_vec[1] {
|
||||
0 => NoQuota,
|
||||
1 => SoftQuota,
|
||||
2 => HardQuota,
|
||||
3 => KillQuota,
|
||||
_ => NoQuota,
|
||||
};
|
||||
let hid_raw: [u8; 8] = msg_vec[2..10].try_into().unwrap();
|
||||
let hid: u64 = u64::from_le_bytes(hid_raw);
|
||||
let pid_raw: [u8; 8] = msg_vec[10..18].try_into().unwrap();
|
||||
let pid: u64 = u64::from_le_bytes(pid_raw);
|
||||
debug!(
|
||||
"Setting HID-{:x}:PID-{:x}'s quota type to {:?}",
|
||||
hid, pid, quota_type
|
||||
)
|
||||
}
|
||||
3 => {
|
||||
let page_count = msg_vec[1];
|
||||
log::debug!(" {} pages", page_count);
|
||||
}
|
||||
4 => unsafe {
|
||||
let count = u32::from_le_bytes(msg_vec[1..5].try_into().unwrap_unchecked()) as usize;
|
||||
let src = u64::from_le_bytes(msg_vec[5..13].try_into().unwrap_unchecked()) as *const u8;
|
||||
let dest = u64::from_le_bytes(msg_vec[13..21].try_into().unwrap_unchecked()) as *mut u8;
|
||||
|
||||
src.copy_to_nonoverlapping(dest, count);
|
||||
},
|
||||
5 => unsafe {
|
||||
let count = u32::from_le_bytes(msg_vec[1..5].try_into().unwrap_unchecked()) as usize;
|
||||
let size = u32::from_le_bytes(msg_vec[5..9].try_into().unwrap_unchecked()) as usize;
|
||||
let src = u64::from_le_bytes(msg_vec[9..17].try_into().unwrap_unchecked()) as *const u8;
|
||||
let dest = u64::from_le_bytes(msg_vec[17..25].try_into().unwrap_unchecked()) as *mut u8;
|
||||
|
||||
memset(dest, src, count, size);
|
||||
},
|
||||
_ => {
|
||||
log::debug!("Unknown memory service message type: {}", msg_type);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
use core::slice;
|
||||
|
||||
pub mod dt_msg_handler;
|
||||
pub mod logging_service;
|
||||
pub mod mem_serve;
|
||||
pub mod service_definition_service;
|
||||
|
||||
#[inline(always)]
|
||||
pub fn block_read<'a>(mem_addr: u64, length: usize) -> &'a mut [u8] {
|
||||
unsafe { slice::from_raw_parts_mut(mem_addr as *mut _, length) }
|
||||
}
|
|
@ -1,106 +0,0 @@
|
|||
use {
|
||||
crate::{
|
||||
arch::hardware_random_u64,
|
||||
holeybytes::{kernel_services::block_read, Vm},
|
||||
ipc::{buffer::IpcBuffer, protocol::Protocol},
|
||||
kmain::IPC_BUFFERS,
|
||||
},
|
||||
hashbrown::HashMap,
|
||||
log::{info, trace},
|
||||
spin::{lazy::Lazy, Mutex},
|
||||
};
|
||||
pub struct Services<'a>(HashMap<u64, Protocol<'a>>);
|
||||
pub static SERVICES: Lazy<Mutex<Services>> = Lazy::new(|| {
|
||||
let mut dt = Services(HashMap::new());
|
||||
dt.0.insert(0, Protocol::void());
|
||||
Mutex::new(dt)
|
||||
});
|
||||
#[derive(Debug)]
|
||||
pub enum ServiceError {
|
||||
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 strptr = u64::from_le_bytes(msg_vec[1..9].try_into().unwrap());
|
||||
let strlen = u64::from_le_bytes(msg_vec[9..17].try_into().unwrap()) as usize;
|
||||
let string_vec = block_read(strptr, strlen);
|
||||
let string = core::str::from_utf8(string_vec).expect("Our bytes should be valid utf8");
|
||||
|
||||
use ServiceEventType::*;
|
||||
match sds_event_type {
|
||||
CreateService => {
|
||||
let ret = sds_create_service(string);
|
||||
vm.registers[1] = hbvm::value::Value(ret as u64);
|
||||
}
|
||||
DeleteService => todo!(),
|
||||
SearchServices => {
|
||||
let ret = sds_search_service(string);
|
||||
vm.registers[1] = hbvm::value::Value(ret as u64);
|
||||
}
|
||||
}
|
||||
// let buffer_id_raw = &msg_vec[0..8];
|
||||
// let mut arr = [0u8; 8];
|
||||
// arr.copy_from_slice(&buffer_id_raw);
|
||||
// let buffer_id = u64::from_le_bytes(arr);
|
||||
// info!("BufferID({:x?})", buffer_id);
|
||||
|
||||
// let mut services = SERVICES.lock();
|
||||
// let string = String::from_utf8(msg_vec).expect("Our bytes should be valid utf8");
|
||||
// use core::borrow::BorrowMut;
|
||||
// services.borrow_mut().0.insert(buffer_id, string);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
enum ServiceEventType {
|
||||
CreateService = 0,
|
||||
// UpdateService = 1,
|
||||
DeleteService = 2,
|
||||
SearchServices = 3,
|
||||
}
|
||||
impl From<u8> for ServiceEventType {
|
||||
fn from(value: u8) -> Self {
|
||||
use self::*;
|
||||
match value {
|
||||
0 => Self::CreateService,
|
||||
// 1 =>
|
||||
2 => Self::DeleteService,
|
||||
3 => Self::SearchServices,
|
||||
10 => {
|
||||
info!("TEST");
|
||||
panic!()
|
||||
}
|
||||
1_u8 | 4_u8..=u8::MAX => todo!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn sds_create_service(protocol: &'static str) -> u64 {
|
||||
let buff_id = hardware_random_u64();
|
||||
let mut services = SERVICES.lock();
|
||||
let mut buffers = IPC_BUFFERS.lock();
|
||||
|
||||
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
|
||||
}
|
||||
pub 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
|
||||
}
|
|
@ -6,54 +6,34 @@
|
|||
|
||||
use hbvm::mem::Address;
|
||||
|
||||
fn calc_start_of_page(ptr: u64) -> u64 {
|
||||
let _page_aligned = false;
|
||||
if ptr % 4096 == 0 {
|
||||
// page_aligned = true;
|
||||
return ptr / 4096;
|
||||
}
|
||||
panic!("unaligned");
|
||||
}
|
||||
|
||||
pub struct Memory {
|
||||
// TODO: map page aligned segments of memory into a table or some sort here
|
||||
}
|
||||
|
||||
impl Memory {
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
fn read_device(_addr: Address) {
|
||||
//unsafe {
|
||||
//
|
||||
// x86_64::instructions::port::Port::new(addr.get()).read()
|
||||
//}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Memory;
|
||||
impl hbvm::mem::Memory for Memory {
|
||||
#[inline(always)]
|
||||
#[inline]
|
||||
unsafe fn load(
|
||||
&mut self,
|
||||
addr: Address,
|
||||
target: *mut u8,
|
||||
count: usize,
|
||||
) -> Result<(), hbvm::mem::LoadError> {
|
||||
core::ptr::copy_nonoverlapping(addr.get() as *const u8, target, count);
|
||||
core::ptr::copy(addr.get() as *const u8, target, count);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
#[inline]
|
||||
unsafe fn store(
|
||||
&mut self,
|
||||
addr: Address,
|
||||
source: *const u8,
|
||||
count: usize,
|
||||
) -> Result<(), hbvm::mem::StoreError> {
|
||||
core::ptr::copy_nonoverlapping(source, addr.get() as *mut u8, count);
|
||||
// log::info!("Storing memory");
|
||||
|
||||
core::ptr::copy(source, addr.get() as *mut u8, count);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
#[inline]
|
||||
unsafe fn prog_read<T: Copy>(&mut self, addr: Address) -> T {
|
||||
(addr.get() as *const T).read()
|
||||
(addr.get() as *const T).read_unaligned()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,64 +1,69 @@
|
|||
mod ecah;
|
||||
pub mod kernel_services;
|
||||
mod mem;
|
||||
|
||||
use {
|
||||
alloc::alloc::{alloc, dealloc},
|
||||
core::{
|
||||
alloc::Layout,
|
||||
future::Future,
|
||||
pin::Pin,
|
||||
task::{Context, Poll},
|
||||
},
|
||||
crate::{arch, ipc::buffer::IpcBuffer, kmain::IPC_BUFFERS},
|
||||
alloc::boxed::Box,
|
||||
core::{default, future::Future, marker::PhantomData, ptr::NonNull, task::Poll},
|
||||
hbvm::{
|
||||
mem::{softpaging::HandlePageFault, Address},
|
||||
mem::{
|
||||
softpaging::{icache::ICache, HandlePageFault, SoftPagedMem},
|
||||
Address, Memory,
|
||||
},
|
||||
VmRunError, VmRunOk,
|
||||
},
|
||||
log::error,
|
||||
log::{debug, error, info, trace, warn},
|
||||
};
|
||||
|
||||
const STACK_SIZE: usize = 1024 * 1024;
|
||||
const TIMER_QUOTIENT: usize = 1000;
|
||||
const TIMER_QUOTIENT: usize = 100;
|
||||
type Vm = hbvm::Vm<mem::Memory, TIMER_QUOTIENT>;
|
||||
|
||||
pub struct ExecThread {
|
||||
pub struct ExecThread<'p> {
|
||||
vm: Vm,
|
||||
stack_bottom: *mut u8,
|
||||
_phantom: PhantomData<&'p [u8]>,
|
||||
}
|
||||
|
||||
unsafe impl Send for ExecThread {}
|
||||
|
||||
impl ExecThread {
|
||||
unsafe impl<'p> Send for ExecThread<'p> {}
|
||||
impl<'p> ExecThread<'p> {
|
||||
pub fn set_arguments(&mut self, ptr: u64, length: u64) {
|
||||
self.vm.registers[1] = hbvm::value::Value(ptr);
|
||||
self.vm.registers[2] = hbvm::value::Value(length);
|
||||
}
|
||||
|
||||
pub unsafe fn new(program: &[u8], entrypoint: Address) -> Self {
|
||||
let mut vm = Vm::new(
|
||||
mem::Memory {},
|
||||
Address::new(program.as_ptr() as u64 + entrypoint.get()),
|
||||
);
|
||||
|
||||
let stack_bottom = allocate_stack();
|
||||
pub unsafe fn new(program: &'p [u8], entrypoint: Address) -> Self {
|
||||
let mut vm = unsafe {
|
||||
Vm::new(
|
||||
mem::Memory,
|
||||
Address::new(program.as_ptr() as u64 + entrypoint.get()),
|
||||
)
|
||||
};
|
||||
|
||||
let stack_bottom = unsafe { allocate_stack().as_ptr() };
|
||||
vm.write_reg(254, (stack_bottom as usize + STACK_SIZE - 1) as u64);
|
||||
|
||||
ExecThread { vm, stack_bottom }
|
||||
ExecThread {
|
||||
vm,
|
||||
stack_bottom,
|
||||
_phantom: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'p> Drop for ExecThread {
|
||||
impl<'p> Drop for ExecThread<'p> {
|
||||
fn drop(&mut self) {
|
||||
unsafe { dealloc(self.stack_bottom, stack_layout()) };
|
||||
unsafe { alloc::alloc::dealloc(self.stack_bottom, stack_layout()) };
|
||||
}
|
||||
}
|
||||
|
||||
impl<'p> Future for ExecThread {
|
||||
impl<'p> Future for ExecThread<'p> {
|
||||
type Output = Result<(), VmRunError>;
|
||||
|
||||
#[inline(always)]
|
||||
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
fn poll(
|
||||
mut self: core::pin::Pin<&mut Self>,
|
||||
cx: &mut core::task::Context<'_>,
|
||||
) -> Poll<Self::Output> {
|
||||
match self.vm.run() {
|
||||
Err(err) => {
|
||||
log::error!("HBVM Error\r\nRegister dump: {:?}", self.vm.registers,);
|
||||
|
@ -85,22 +90,33 @@ impl HandlePageFault for PageFaultHandler {
|
|||
fn page_fault(
|
||||
&mut self,
|
||||
reason: hbvm::mem::MemoryAccessReason,
|
||||
_pagetable: &mut hbvm::mem::softpaging::paging::PageTable,
|
||||
pagetable: &mut hbvm::mem::softpaging::paging::PageTable,
|
||||
vaddr: hbvm::mem::Address,
|
||||
size: hbvm::mem::softpaging::PageSize,
|
||||
dataptr: *mut u8,
|
||||
) -> bool {
|
||||
error!("REASON: {reason} vaddr: {vaddr} size: {size:?} Dataptr {dataptr:p}");
|
||||
) -> bool
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
log::error!(
|
||||
"REASON: {reason} \
|
||||
vaddr: {vaddr} \
|
||||
size: {size:?} \
|
||||
Dataptr {dataptr:p}",
|
||||
);
|
||||
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
const fn stack_layout() -> Layout {
|
||||
unsafe { Layout::from_size_align_unchecked(STACK_SIZE, 8) }
|
||||
const fn stack_layout() -> core::alloc::Layout {
|
||||
unsafe { alloc::alloc::Layout::from_size_align_unchecked(STACK_SIZE, 4096) }
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn allocate_stack() -> *mut u8 {
|
||||
unsafe { alloc(stack_layout()) }
|
||||
fn allocate_stack() -> NonNull<u8> {
|
||||
let layout = stack_layout();
|
||||
match NonNull::new(unsafe { alloc::alloc::alloc_zeroed(layout) }) {
|
||||
Some(ptr) => ptr,
|
||||
None => alloc::alloc::handle_alloc_error(layout),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,20 +1,21 @@
|
|||
//!
|
||||
|
||||
use {
|
||||
super::{message::Message, protocol::Protocol},
|
||||
super::message::Message,
|
||||
crossbeam_queue::{ArrayQueue, SegQueue},
|
||||
};
|
||||
|
||||
pub enum BufferTypes {
|
||||
Unbound(SegQueue<Message>),
|
||||
Bound(ArrayQueue<Message>),
|
||||
}
|
||||
/// Interproccess buffer
|
||||
pub struct IpcBuffer<'a> {
|
||||
pub protocol: Protocol<'a>,
|
||||
pub struct IpcBuffer {
|
||||
pub protocol: Protocol,
|
||||
pub buffer: BufferTypes,
|
||||
}
|
||||
|
||||
impl<'a> IpcBuffer<'a> {
|
||||
impl IpcBuffer {
|
||||
pub fn new(bounded: bool, length: u64) -> Self {
|
||||
log::debug!(
|
||||
"New IPCBuffer\r
|
||||
|
@ -23,19 +24,20 @@ impl<'a> IpcBuffer<'a> {
|
|||
bounded,
|
||||
length
|
||||
);
|
||||
|
||||
match (bounded, length) {
|
||||
(false, ..) => {
|
||||
(false, a) => {
|
||||
let buftype = BufferTypes::Unbound(SegQueue::new());
|
||||
|
||||
Self {
|
||||
protocol: Protocol::void(),
|
||||
protocol: Protocol {},
|
||||
buffer: buftype,
|
||||
}
|
||||
}
|
||||
(true, length) => {
|
||||
let buftype = BufferTypes::Bound(ArrayQueue::new(length as usize));
|
||||
Self {
|
||||
protocol: Protocol::void(),
|
||||
protocol: Protocol {},
|
||||
buffer: buftype,
|
||||
}
|
||||
}
|
||||
|
@ -48,25 +50,39 @@ impl<'a> IpcBuffer<'a> {
|
|||
}
|
||||
pub fn push(&mut self, msg: Message) {
|
||||
match &self.buffer {
|
||||
BufferTypes::Unbound(buff) => buff.push(msg),
|
||||
BufferTypes::Bound(buff) => buff.push(msg).unwrap(),
|
||||
BufferTypes::Unbound(buff) => buff.push(msg.clone()),
|
||||
BufferTypes::Bound(buff) => {
|
||||
let _ = buff.push(msg.clone());
|
||||
}
|
||||
};
|
||||
}
|
||||
pub fn pop(&mut self) -> Result<Message, IpcError> {
|
||||
pub fn pop(&mut self) -> Message {
|
||||
let msg = match &self.buffer {
|
||||
BufferTypes::Unbound(buff) => buff.pop(),
|
||||
BufferTypes::Bound(buff) => buff.pop(),
|
||||
};
|
||||
match msg {
|
||||
Some(msg) => return Ok(msg),
|
||||
None => return Err(IpcError::NoMessagesInBuffer),
|
||||
Some(msg) => return msg,
|
||||
None => panic!("Recieving msg error. No messages!"),
|
||||
}
|
||||
}
|
||||
}
|
||||
/// Interprocess Communication Errors
|
||||
#[derive(Debug)]
|
||||
pub enum IpcError {
|
||||
/// An invalid message error returned to the sender
|
||||
InvalidMessage,
|
||||
NoMessagesInBuffer,
|
||||
}
|
||||
|
||||
/// TODO: define this, possibly as the binary form of the IDL
|
||||
/// DEPEND: This depends on an IDL
|
||||
pub struct Protocol {
|
||||
// TODO: add in settings
|
||||
// like `invalid_message_handler` with some options similar to
|
||||
// `Deny` Drops the message
|
||||
// `Allow` Allows invalid messages (This disables validators IPC side and relies on programs to handle invalid messages)
|
||||
// `CustomFunct` a callback
|
||||
// and `report_invalid_messages_to_sender`
|
||||
// `True`
|
||||
// `False`
|
||||
// settings: PSettings,
|
||||
}
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
//! Interprocess communication
|
||||
pub mod buffer;
|
||||
pub mod message;
|
||||
pub mod protocol;
|
||||
|
|
|
@ -1,36 +0,0 @@
|
|||
use {alloc::vec::Vec, hashbrown::HashMap};
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
pub struct Type {}
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
pub struct Funct<'a> {
|
||||
takes: Vec<&'a str>,
|
||||
gives: Vec<&'a str>,
|
||||
}
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
pub struct Protocol<'a> {
|
||||
types: HashMap<&'a str, Type>,
|
||||
fns: HashMap<&'a str, Funct<'a>>,
|
||||
}
|
||||
impl<'a> Protocol<'a> {
|
||||
pub fn void() -> Self {
|
||||
Self {
|
||||
types: HashMap::new(),
|
||||
fns: HashMap::new(),
|
||||
}
|
||||
}
|
||||
// Check if a protocol defines all types it needs too
|
||||
fn validate_protocol() -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a str> for Protocol<'a> {
|
||||
fn from(value: &'a str) -> Self {
|
||||
let mut hm_t = HashMap::new();
|
||||
hm_t.insert(value, Type {});
|
||||
Self {
|
||||
types: hm_t,
|
||||
fns: HashMap::new(),
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,28 +2,26 @@
|
|||
|
||||
use {
|
||||
crate::{
|
||||
arch::hardware_random_u64,
|
||||
bootmodules::BootModules,
|
||||
//bootmodules::build_cmd,
|
||||
bootmodules::{build_cmd, BootModules},
|
||||
capabilities,
|
||||
device_tree::DeviceTree,
|
||||
holeybytes::ExecThread,
|
||||
ipc::buffer::IpcBuffer,
|
||||
task::Executor,
|
||||
ipc::buffer::{self, IpcBuffer},
|
||||
},
|
||||
alloc::boxed::Box,
|
||||
core::cell::LazyCell,
|
||||
alloc::format,
|
||||
hashbrown::HashMap,
|
||||
hbvm::mem::Address,
|
||||
limine::{Framebuffer, FramebufferRequest, NonNullPtr},
|
||||
log::{debug, error, trace},
|
||||
log::{debug, info, trace},
|
||||
spin::{Lazy, Mutex},
|
||||
xml::XMLElement,
|
||||
};
|
||||
|
||||
pub fn kmain(_cmdline: &str, boot_modules: BootModules) -> ! {
|
||||
pub fn kmain(cmdline: &str, boot_modules: BootModules) -> ! {
|
||||
debug!("Entered kmain");
|
||||
|
||||
// let kcmd = build_cmd("Kernel Command Line", cmdline);
|
||||
// trace!("Cmdline: {kcmd:?}");
|
||||
let kcmd = build_cmd("Kernel Command Line", cmdline);
|
||||
trace!("Cmdline: {kcmd:?}");
|
||||
|
||||
// for (i, bm) in boot_modules.iter().enumerate() {
|
||||
// let name = format!("module-{}", i);
|
||||
|
@ -39,9 +37,9 @@ pub fn kmain(_cmdline: &str, boot_modules: BootModules) -> ! {
|
|||
let dt = DEVICE_TREE.lock();
|
||||
|
||||
// TODO(Able): This line causes a deadlock
|
||||
debug!("Device Tree: {}", dt);
|
||||
info!("Device Tree: {}", dt);
|
||||
|
||||
trace!("Boot complete. Moving to init_system");
|
||||
info!("Boot complete. Moving to init_system");
|
||||
|
||||
// TODO: schedule the disk driver from the initramfs
|
||||
// TODO: schedule the filesystem driver from the initramfs
|
||||
|
@ -53,91 +51,62 @@ pub fn kmain(_cmdline: &str, boot_modules: BootModules) -> ! {
|
|||
let fb1: &NonNullPtr<Framebuffer> = &FB_REQ.get_response().get().unwrap().framebuffers()[0];
|
||||
|
||||
{
|
||||
use crate::alloc::string::ToString;
|
||||
let mut dt = DEVICE_TREE.lock();
|
||||
let mut disp = xml::XMLElement::new("display_0");
|
||||
|
||||
disp.set_attribute("width", fb1.width);
|
||||
disp.set_attribute("height", fb1.height);
|
||||
disp.set_attribute("bpp", fb1.bpp);
|
||||
disp.set_attribute("bits per pixel", fb1.bpp);
|
||||
disp.set_attribute("pitch", fb1.pitch);
|
||||
dt.devices.insert("Displays", alloc::vec![disp]);
|
||||
dt.devices.insert("Displays".to_string(), alloc::vec![disp]);
|
||||
}
|
||||
debug!("Graphics initialised");
|
||||
debug!(
|
||||
log::info!("Graphics initialised");
|
||||
log::info!(
|
||||
"Graphics front ptr {:?}",
|
||||
fb1.address.as_ptr().unwrap() as *const u8
|
||||
);
|
||||
|
||||
let mut executor = crate::task::Executor::default();
|
||||
let bm_take = boot_modules.len();
|
||||
unsafe {
|
||||
let executor = LazyCell::<Executor>::force_mut(&mut EXECUTOR);
|
||||
for module in boot_modules.iter() {
|
||||
let cmd = module.cmd.trim_matches('"');
|
||||
let cmd_len = cmd.len() as u64;
|
||||
|
||||
log::info!(
|
||||
"Starting {}",
|
||||
module
|
||||
.path
|
||||
.split('/')
|
||||
.last()
|
||||
.unwrap()
|
||||
.split('.')
|
||||
.next()
|
||||
.unwrap()
|
||||
);
|
||||
log::debug!("Spawning {} with arguments \"{}\"", module.path, cmd);
|
||||
|
||||
// decode AbleOS Executable format
|
||||
let header = &module.bytes[0..46];
|
||||
let magic_slice = &header[0..3];
|
||||
if magic_slice != [0x15, 0x91, 0xD2] {
|
||||
log::error!("Invalid magic number at the start of executable.");
|
||||
continue;
|
||||
for module in boot_modules.into_iter().take(bm_take) {
|
||||
let mut cmd = module.cmd;
|
||||
if cmd.len() > 2 {
|
||||
// Remove the quotes
|
||||
cmd.remove(0);
|
||||
cmd.pop();
|
||||
}
|
||||
let cmd_len = cmd.as_bytes().len() as u64;
|
||||
|
||||
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;
|
||||
};
|
||||
log::info!("Spawning {} with arguments \"{}\"", module.path, cmd);
|
||||
|
||||
let code_length = u64::from_le_bytes(header[7..15].try_into().unwrap());
|
||||
let data_length = u64::from_le_bytes(header[15..23].try_into().unwrap());
|
||||
let end = (code_length + data_length) as usize;
|
||||
log::debug!("{code_length} + {data_length} = {end}");
|
||||
executor.spawn(async move {
|
||||
let mut thr = ExecThread::new(&module.bytes, Address::new(0));
|
||||
if cmd_len > 0 {
|
||||
thr.set_arguments(cmd.as_bytes().as_ptr() as u64, cmd_len);
|
||||
}
|
||||
|
||||
let mut thr = ExecThread::new(&module.bytes[offset..end], Address::new(0));
|
||||
if cmd_len > 0 {
|
||||
thr.set_arguments(cmd.as_ptr() as u64, cmd_len);
|
||||
}
|
||||
executor.spawn(Box::pin(async move {
|
||||
if let Err(e) = thr.await {
|
||||
log::error!("{e:?}");
|
||||
}
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
||||
debug!("Random number: {}", hardware_random_u64());
|
||||
|
||||
executor.run();
|
||||
};
|
||||
|
||||
crate::arch::spin_loop()
|
||||
}
|
||||
|
||||
// ! SAFETY: this is not threadsafe at all, like even a little bit.
|
||||
// ! SERIOUSLY
|
||||
pub static mut EXECUTOR: LazyCell<Executor> = LazyCell::new(|| Executor::new());
|
||||
|
||||
pub static DEVICE_TREE: Lazy<Mutex<DeviceTree>> = Lazy::new(|| {
|
||||
let dt = DeviceTree::new();
|
||||
Mutex::new(dt)
|
||||
});
|
||||
pub static FB_REQ: FramebufferRequest = FramebufferRequest::new(0);
|
||||
|
||||
pub type IpcBuffers<'a> = HashMap<u64, IpcBuffer<'a>>;
|
||||
use alloc::vec::Vec;
|
||||
pub type IpcBuffers = HashMap<u64, IpcBuffer>;
|
||||
pub static IPC_BUFFERS: Lazy<Mutex<IpcBuffers>> = Lazy::new(|| {
|
||||
let mut bufs = HashMap::new();
|
||||
let log_buffer = IpcBuffer::new(false, 0);
|
||||
|
|
|
@ -1,21 +1,20 @@
|
|||
//! The ableOS kernel.
|
||||
//! 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
|
||||
|
||||
#![no_std]
|
||||
#![feature(
|
||||
slice_split_once,
|
||||
exclusive_wrapper,
|
||||
core_intrinsics,
|
||||
abi_x86_interrupt,
|
||||
lazy_get,
|
||||
alloc_error_handler,
|
||||
inline_const,
|
||||
panic_info_message,
|
||||
pointer_is_aligned,
|
||||
ptr_sub_ptr,
|
||||
custom_test_frameworks,
|
||||
naked_functions,
|
||||
pointer_is_aligned_to
|
||||
)]
|
||||
#![allow(dead_code)]
|
||||
#![test_runner(crate::test_runner)]
|
||||
#![allow(dead_code, internal_features, static_mut_refs)]
|
||||
extern crate alloc;
|
||||
|
||||
mod allocator;
|
||||
|
@ -23,7 +22,6 @@ mod arch;
|
|||
mod bootmodules;
|
||||
mod capabilities;
|
||||
mod device_tree;
|
||||
mod exe_format;
|
||||
mod handle;
|
||||
mod holeybytes;
|
||||
mod ipc;
|
||||
|
@ -43,7 +41,6 @@ pub const VERSION: Version = Version {
|
|||
};
|
||||
|
||||
#[panic_handler]
|
||||
#[cfg(target_os = "none")]
|
||||
fn panic(info: &core::panic::PanicInfo) -> ! {
|
||||
arch::register_dump();
|
||||
|
||||
|
@ -56,8 +53,10 @@ fn panic(info: &core::panic::PanicInfo) -> ! {
|
|||
));
|
||||
}
|
||||
|
||||
let msg = info.message();
|
||||
let _ = crate::arch::log(format_args!("{msg}\r\n"));
|
||||
if let Some(msg) = info.message() {
|
||||
let _ = crate::arch::log(format_args!("{msg}\r\n"));
|
||||
}
|
||||
|
||||
loop {}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
#![allow(deprecated)]
|
||||
// TODO: Add a logger api with logger levels and various outputs
|
||||
pub static TERMINAL_LOGGER: Lazy<Mutex<TermLogger>> = Lazy::new(|| Mutex::new(TermLogger::new()));
|
||||
|
||||
|
@ -10,11 +9,7 @@ use {
|
|||
|
||||
pub fn init() -> Result<(), SetLoggerError> {
|
||||
log::set_logger(&crate::logger::Logger)?;
|
||||
if cfg!(debug_assertions) {
|
||||
log::set_max_level(log::LevelFilter::Debug);
|
||||
} else {
|
||||
log::set_max_level(log::LevelFilter::Info);
|
||||
}
|
||||
log::set_max_level(log::LevelFilter::Debug);
|
||||
|
||||
Lazy::force(&TERMINAL_LOGGER);
|
||||
|
||||
|
@ -36,26 +31,13 @@ impl log::Log for Logger {
|
|||
Level::Debug => "25",
|
||||
Level::Trace => "103",
|
||||
};
|
||||
let module = record
|
||||
.module_path()
|
||||
.unwrap_or_default()
|
||||
.rsplit_once(':')
|
||||
.unwrap_or_default()
|
||||
.1;
|
||||
if module == "" {
|
||||
crate::arch::log(format_args!(
|
||||
"\x1b[38;5;{lvl_color}m{lvl}\x1b[0m: {}\r\n",
|
||||
record.args(),
|
||||
))
|
||||
.expect("write to serial console");
|
||||
} else {
|
||||
let line = record.line().unwrap_or_default();
|
||||
crate::arch::log(format_args!(
|
||||
"\x1b[38;5;{lvl_color}m{lvl}\x1b[0m [{module}:{line}]: {}\r\n",
|
||||
record.args(),
|
||||
))
|
||||
.expect("write to serial console");
|
||||
}
|
||||
let module = record.module_path().unwrap_or_default();
|
||||
let line = record.line().unwrap_or_default();
|
||||
crate::arch::log(format_args!(
|
||||
"\x1b[38;5;{lvl_color}m{lvl}\x1b[0m [{module}:{line}]: {}\r\n",
|
||||
record.args(),
|
||||
))
|
||||
.expect("write to serial console");
|
||||
}
|
||||
|
||||
fn flush(&self) {}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
//! The Memory Manager
|
||||
|
||||
use {alloc::collections::VecDeque, derive_more::*};
|
||||
use alloc::collections::VecDeque;
|
||||
use derive_more::*;
|
||||
|
||||
pub use crate::arch::PAGE_SIZE;
|
||||
pub const MAX_ORDER: usize = 10;
|
||||
|
@ -43,7 +44,7 @@ pub const MAX_ORDER: usize = 10;
|
|||
Sum,
|
||||
UpperHex,
|
||||
)]
|
||||
#[display("0x{:x}", _0)]
|
||||
#[display(fmt = "0x{:x}", _0)]
|
||||
#[from(forward)]
|
||||
pub struct VirtualAddress(usize);
|
||||
|
||||
|
@ -54,11 +55,11 @@ impl VirtualAddress {
|
|||
pub fn vpns(&self) -> [usize; 3] {
|
||||
[
|
||||
// [20:12]
|
||||
(self.0 >> 12) & 0x1FF,
|
||||
(self.0 >> 12) & 0x1ff,
|
||||
// [29:21]
|
||||
(self.0 >> 21) & 0x1FF,
|
||||
(self.0 >> 21) & 0x1ff,
|
||||
// [38:30]
|
||||
(self.0 >> 30) & 0x1FF,
|
||||
(self.0 >> 30) & 0x1ff,
|
||||
]
|
||||
}
|
||||
|
||||
|
@ -113,7 +114,7 @@ impl VirtualAddress {
|
|||
Sum,
|
||||
UpperHex,
|
||||
)]
|
||||
#[display("0x{:x}", _0)]
|
||||
#[display(fmt = "0x{:x}", _0)]
|
||||
#[from(forward)]
|
||||
pub struct PhysicalAddress(usize);
|
||||
|
||||
|
@ -124,11 +125,11 @@ impl PhysicalAddress {
|
|||
pub fn ppns(&self) -> [usize; 3] {
|
||||
[
|
||||
// [20:12]
|
||||
(self.0 >> 12) & 0x1FF,
|
||||
(self.0 >> 12) & 0x1ff,
|
||||
// [29:21]
|
||||
(self.0 >> 21) & 0x1FF,
|
||||
(self.0 >> 21) & 0x1ff,
|
||||
// [55:30]
|
||||
(self.0 >> 30) & 0x3FFFFFF,
|
||||
(self.0 >> 30) & 0x3ffffff,
|
||||
]
|
||||
}
|
||||
|
||||
|
|
|
@ -1,20 +1,31 @@
|
|||
#![allow(unused)]
|
||||
|
||||
use {
|
||||
alloc::{boxed::Box, sync::Arc},
|
||||
alloc::{boxed::Box, collections::BTreeMap, sync::Arc, task::Wake},
|
||||
core::{
|
||||
future::Future,
|
||||
pin::Pin,
|
||||
task::{Context, Poll, RawWaker, RawWakerVTable, Waker},
|
||||
task::{Context, Poll, Waker},
|
||||
},
|
||||
crossbeam_queue::SegQueue,
|
||||
kiam::when,
|
||||
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 = ()> {
|
||||
struct YieldNow(bool);
|
||||
impl Future for YieldNow {
|
||||
type Output = ();
|
||||
|
||||
#[inline(always)]
|
||||
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
if self.0 {
|
||||
Poll::Ready(())
|
||||
|
@ -29,150 +40,101 @@ pub fn yield_now() -> impl Future<Output = ()> {
|
|||
YieldNow(false)
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Executor {
|
||||
tasks: Slab<Task>,
|
||||
task_queue: Arc<TaskQueue>,
|
||||
tasks: Slab<Task>,
|
||||
queue: TaskQueue,
|
||||
to_spawn: SpawnQueue,
|
||||
wakers: BTreeMap<TaskId, Waker>,
|
||||
}
|
||||
|
||||
impl Executor {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
tasks: Slab::new(),
|
||||
task_queue: Arc::new(TaskQueue::new()),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn spawn(&mut self, future: Pin<Box<dyn Future<Output = ()> + Send>>) -> usize {
|
||||
let id = self.tasks.insert(Task::new(future));
|
||||
self.task_queue.queue.push(id);
|
||||
id
|
||||
pub fn spawn(&mut self, future: impl Future<Output = ()> + Send + 'static) {
|
||||
self.queue
|
||||
.push(TaskId(self.tasks.insert(Task::new(future))));
|
||||
}
|
||||
|
||||
pub fn run(&mut self) {
|
||||
let mut task_batch = [0; 32];
|
||||
let mut batch_len = 0;
|
||||
{
|
||||
let mut global_spawner = SPAWN_QUEUE.write();
|
||||
if global_spawner.is_some() {
|
||||
panic!("Task executor is already running");
|
||||
}
|
||||
|
||||
*global_spawner = Some(Arc::clone(&self.to_spawn));
|
||||
}
|
||||
|
||||
loop {
|
||||
self.task_queue.batch_pop(&mut task_batch, &mut batch_len);
|
||||
when! {
|
||||
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);
|
||||
};
|
||||
|
||||
if batch_len == 0 {
|
||||
if self.task_queue.is_empty() {
|
||||
break;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
let mut cx = Context::from_waker(self.wakers.entry(id).or_insert_with(|| {
|
||||
Waker::from(Arc::new(TaskWaker {
|
||||
id,
|
||||
queue: Arc::clone(&self.queue),
|
||||
}))
|
||||
}));
|
||||
|
||||
for &id in &task_batch[..batch_len] {
|
||||
if let Some(task) = self.tasks.get_mut(id) {
|
||||
let waker = task
|
||||
.waker
|
||||
.get_or_insert_with(|| TaskWaker::new(id, Arc::clone(&self.task_queue)));
|
||||
|
||||
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);
|
||||
match task.poll(&mut cx) {
|
||||
Poll::Ready(()) => {
|
||||
self.tasks.remove(id.0);
|
||||
self.wakers.remove(&id);
|
||||
}
|
||||
Poll::Pending => (),
|
||||
}
|
||||
}
|
||||
},
|
||||
self.tasks.is_empty() => break,
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
*SPAWN_QUEUE.write() = None;
|
||||
}
|
||||
}
|
||||
|
||||
struct Task {
|
||||
future: Pin<Box<dyn Future<Output = ()> + Send>>,
|
||||
waker: Option<TaskWaker>,
|
||||
}
|
||||
|
||||
impl Task {
|
||||
#[inline(always)]
|
||||
pub fn new(future: Pin<Box<dyn Future<Output = ()> + Send>>) -> Self {
|
||||
pub fn new(future: impl Future<Output = ()> + Send + 'static) -> Self {
|
||||
log::trace!("New task scheduled");
|
||||
Self {
|
||||
future,
|
||||
waker: None,
|
||||
future: Box::pin(future),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn poll(&mut self, cx: &mut Context) -> Poll<()> {
|
||||
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 {
|
||||
id: usize,
|
||||
task_queue: Arc<TaskQueue>,
|
||||
id: TaskId,
|
||||
queue: TaskQueue,
|
||||
}
|
||||
|
||||
impl TaskWaker {
|
||||
#[inline(always)]
|
||||
fn new(id: usize, task_queue: Arc<TaskQueue>) -> Self {
|
||||
Self { id, task_queue }
|
||||
impl Wake for TaskWaker {
|
||||
fn wake(self: Arc<Self>) {
|
||||
log::trace!("Woke Task-{:?}", self.id);
|
||||
self.wake_by_ref();
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn wake(&self) {
|
||||
self.task_queue.queue.push(self.id);
|
||||
}
|
||||
|
||||
fn into_raw_waker(waker: &TaskWaker) -> RawWaker {
|
||||
let ptr = waker as *const TaskWaker;
|
||||
RawWaker::new(ptr.cast(), &VTABLE)
|
||||
}
|
||||
}
|
||||
|
||||
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()
|
||||
fn wake_by_ref(self: &Arc<Self>) {
|
||||
self.queue.push(self.id);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,14 +4,15 @@
|
|||
/// Used when tab `\t` in hardware is not known and we will default to two spaces
|
||||
pub const TAB: &str = " ";
|
||||
|
||||
|
||||
// NOTE: this only reduces the code duplication in source code not in generated code!
|
||||
// Written by Yours Truly: Munir
|
||||
/// A simple macro to reduce code duplication when we use TAB internally
|
||||
#[macro_export]
|
||||
macro_rules! tab {
|
||||
($num:expr) => {
|
||||
($num:expr) => {
|
||||
TAB.repeat($num)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: this only reduces the code duplication in source code not in generated code!
|
||||
|
@ -21,7 +22,7 @@ macro_rules! tab {
|
|||
macro_rules! device_tree {
|
||||
($devtree:expr, $dev_type_vec:expr) => {
|
||||
for each_device_type in $dev_type_vec {
|
||||
$devtree.devices.insert(each_device_type, Vec::new());
|
||||
$devtree.devices.insert(each_device_type.to_string(), Vec::new());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -49,4 +50,4 @@ macro_rules! cpu_features {
|
|||
$result_vec.push(("rdseed", rdseed));
|
||||
$result_vec.push(("x2apic", x2));
|
||||
};
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"arch": "aarch64",
|
||||
"data-layout": "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32",
|
||||
"data-layout": "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128",
|
||||
"disable-redzone": true,
|
||||
"env": "",
|
||||
"executables": true,
|
||||
|
|
|
@ -1,22 +1,22 @@
|
|||
{
|
||||
"llvm-target": "x86_64-unknown-none",
|
||||
"data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128",
|
||||
"arch": "x86_64",
|
||||
"target-endian": "little",
|
||||
"target-pointer-width": "64",
|
||||
"target-c-int-width": "32",
|
||||
"os": "none",
|
||||
"executables": true,
|
||||
"linker-flavor": "ld.lld",
|
||||
"linker": "rust-lld",
|
||||
"panic-strategy": "abort",
|
||||
"disable-redzone": true,
|
||||
"features": "",
|
||||
"code-model": "kernel",
|
||||
"pre-link-args": {
|
||||
"ld.lld": [
|
||||
"--gc-sections",
|
||||
"--script=kernel/lds/x86_64.ld"
|
||||
]
|
||||
}
|
||||
"llvm-target": "x86_64-unknown-none",
|
||||
"data-layout": "e-m:e-i64:64-f80:128-n8:16:32:64-S128",
|
||||
"arch": "x86_64",
|
||||
"target-endian": "little",
|
||||
"target-pointer-width": "64",
|
||||
"target-c-int-width": "32",
|
||||
"os": "none",
|
||||
"executables": true,
|
||||
"linker-flavor": "ld.lld",
|
||||
"linker": "rust-lld",
|
||||
"panic-strategy": "abort",
|
||||
"disable-redzone": true,
|
||||
"features": "",
|
||||
"code-model": "kernel",
|
||||
"pre-link-args": {
|
||||
"ld.lld": [
|
||||
"--gc-sections",
|
||||
"--script=kernel/lds/x86_64.ld"
|
||||
]
|
||||
}
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
{
|
||||
"llvm-target": "x86_64-unknown-none",
|
||||
"data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128",
|
||||
"arch": "x86_64",
|
||||
"target-endian": "little",
|
||||
"target-pointer-width": "64",
|
||||
"target-c-int-width": "32",
|
||||
"os": "none",
|
||||
"executables": true,
|
||||
"linker-flavor": "ld.lld",
|
||||
"linker": "rust-lld",
|
||||
"panic-strategy": "abort",
|
||||
"disable-redzone": true,
|
||||
"features": "+sse4.1,+avx,+aes,+fma,+popcnt,+bmi2,+avx2,+lzcnt,+xsave",
|
||||
"code-model": "kernel",
|
||||
"pre-link-args": {
|
||||
"ld.lld": [
|
||||
"--gc-sections",
|
||||
"--script=kernel/lds/x86_64.ld"
|
||||
]
|
||||
}
|
||||
}
|
|
@ -1,2 +0,0 @@
|
|||
# i did not know where to put this
|
||||
- memcpy / memset cause crash on debug builds due to ptr misalignment that is not present on release builds
|
|
@ -4,17 +4,12 @@ version = "0.2.0"
|
|||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
str-reader = "0.1"
|
||||
derive_more = { version = "1", default-features = false, features = [
|
||||
"display",
|
||||
] }
|
||||
error-stack = "0.5"
|
||||
fatfs = { version = "0.3", default-features = false, features = [
|
||||
"std",
|
||||
"alloc",
|
||||
] }
|
||||
toml = "0.8"
|
||||
hblang.git = "https://git.ablecorp.us/AbleOS/holey-bytes.git"
|
||||
log = "0.4"
|
||||
raw-cpuid = "11"
|
||||
ureq = { version = "2", default-features = false, features = ["tls"] }
|
||||
derive_more = "0.99"
|
||||
error-stack = "0.4"
|
||||
fatfs = "0.3"
|
||||
hbasm.git = "https://git.ablecorp.us/AbleOS/holey-bytes.git"
|
||||
|
||||
[dependencies.reqwest]
|
||||
version = "0.11"
|
||||
default-features = false
|
||||
features = ["rustls-tls", "blocking"]
|
||||
|
|
|
@ -1,126 +0,0 @@
|
|||
#![allow(unused)]
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
fmt::format,
|
||||
fs::{read_to_string, File},
|
||||
io::{BufWriter, Write},
|
||||
process::exit,
|
||||
};
|
||||
|
||||
use {error_stack::Report, hblang::Options};
|
||||
|
||||
use crate::Error;
|
||||
pub struct Package {
|
||||
name: String,
|
||||
binaries: Vec<String>,
|
||||
build_cmd: String,
|
||||
args: HashMap<String, String>,
|
||||
}
|
||||
|
||||
impl Package {
|
||||
pub fn load_from_file(path: String) -> Self {
|
||||
let contents = match std::fs::read_to_string(path.clone()) {
|
||||
// If successful return the files text as `contents`.
|
||||
// `c` is a local variable.
|
||||
Ok(c) => c,
|
||||
// Handle the `error` case.
|
||||
Err(_) => {
|
||||
// Write `msg` to `stderr`.
|
||||
eprintln!("Could not read file `{}`", path);
|
||||
// Exit the program with exit code `1`.
|
||||
exit(1);
|
||||
}
|
||||
};
|
||||
use toml::Value;
|
||||
|
||||
let mut data: Value = toml::from_str(&contents).unwrap();
|
||||
let mut name = data
|
||||
.get("package")
|
||||
.unwrap()
|
||||
.get("name")
|
||||
.unwrap()
|
||||
.to_string();
|
||||
name.pop();
|
||||
name.remove(0);
|
||||
|
||||
let dependants = data.get("dependants").unwrap();
|
||||
let bin_table = dependants.get("binaries").unwrap().as_table().unwrap();
|
||||
let mut binaries = vec![];
|
||||
|
||||
for (count, (name, table)) in bin_table.into_iter().enumerate() {
|
||||
binaries.push(name.clone());
|
||||
}
|
||||
let build_table = data.get("build").unwrap();
|
||||
|
||||
let mut build_cmd: String = build_table.get("command").unwrap().as_str().unwrap().into();
|
||||
build_cmd.remove(0);
|
||||
let mut args: HashMap<String, String> = match build_table.get("args") {
|
||||
None => HashMap::new(),
|
||||
Some(v) => v
|
||||
.as_table()
|
||||
.unwrap()
|
||||
.into_iter()
|
||||
.map(|(k, v)| (k.clone(), v.to_string()))
|
||||
.collect::<HashMap<String, String>>(),
|
||||
};
|
||||
|
||||
Self {
|
||||
name,
|
||||
binaries,
|
||||
build_cmd,
|
||||
args,
|
||||
}
|
||||
}
|
||||
pub fn build(&self, out: &mut Vec<u8>) -> std::io::Result<()> {
|
||||
if self.binaries.contains(&"hblang".to_string()) {
|
||||
let file = self.build_cmd.split_ascii_whitespace().last().unwrap();
|
||||
let path = format!("sysdata/programs/{}/{}", self.name, file);
|
||||
// compile here
|
||||
|
||||
let mut warnings = String::new();
|
||||
|
||||
hblang::run_compiler(
|
||||
&path,
|
||||
Options {
|
||||
fmt: true,
|
||||
in_house_regalloc: true,
|
||||
..Default::default()
|
||||
},
|
||||
out,
|
||||
&mut warnings,
|
||||
)?;
|
||||
|
||||
match std::fs::create_dir("target/programs") {
|
||||
Ok(_) => (),
|
||||
Err(e) if e.kind() == std::io::ErrorKind::AlreadyExists => (),
|
||||
Err(e) => panic!("{}", e),
|
||||
}
|
||||
|
||||
hblang::run_compiler(
|
||||
&path,
|
||||
Options {
|
||||
in_house_regalloc: true,
|
||||
..Default::default()
|
||||
},
|
||||
out,
|
||||
&mut warnings,
|
||||
)?;
|
||||
std::fs::write(format!("target/programs/{}.hbf", self.name), &out)?;
|
||||
out.clear();
|
||||
|
||||
hblang::run_compiler(
|
||||
&path,
|
||||
Options {
|
||||
dump_asm: true,
|
||||
in_house_regalloc: true,
|
||||
..Default::default()
|
||||
},
|
||||
out,
|
||||
&mut warnings,
|
||||
)?;
|
||||
std::fs::write(format!("target/programs/{}.hba", self.name), &out)?;
|
||||
out.clear();
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
|
@ -1,75 +1,59 @@
|
|||
mod dev;
|
||||
|
||||
use {
|
||||
core::fmt::Write as _,
|
||||
derive_more::Display,
|
||||
dev::Package,
|
||||
error_stack::{bail, report, Context, Report, Result, ResultExt},
|
||||
fatfs::{FileSystem, FormatVolumeOptions, FsOptions, ReadWriteSeek},
|
||||
std::{
|
||||
fs::{self, File},
|
||||
io::{self, Write},
|
||||
path::Path,
|
||||
process::{exit, Command, Stdio},
|
||||
},
|
||||
toml::Value,
|
||||
std::{fmt::Display, fs::File, io, path::Path, process::Command},
|
||||
};
|
||||
|
||||
fn main() -> Result<(), Error> {
|
||||
let mut args = std::env::args();
|
||||
args.next();
|
||||
|
||||
log::set_logger(&hblang::Logger).unwrap();
|
||||
log::set_max_level(log::LevelFilter::Error);
|
||||
// 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() {
|
||||
Some("build" | "b") => {
|
||||
let mut release = false;
|
||||
let mut debuginfo = false;
|
||||
let mut target = Target::X86_64;
|
||||
for arg in args {
|
||||
if arg == "-r" || arg == "--release" {
|
||||
release = true;
|
||||
} else if arg == "-d" || arg == "--debuginfo" {
|
||||
debuginfo = true;
|
||||
} else if arg == "rv64" || arg == "riscv64" || arg == "riscv64-virt" {
|
||||
target = Target::Riscv64Virt;
|
||||
} else if arg == "arm64" || arg == "aarch64" || arg == "aarch64-virt" {
|
||||
target = Target::Aarch64;
|
||||
} else if arg == "avx2" {
|
||||
target = Target::X86_64Avx2;
|
||||
} else {
|
||||
return Err(report!(Error::InvalidSubCom));
|
||||
}
|
||||
}
|
||||
|
||||
build(release, target, debuginfo).change_context(Error::Build)
|
||||
assemble()?;
|
||||
build(release, target).change_context(Error::Build)
|
||||
}
|
||||
Some("run" | "r") => {
|
||||
let mut release = false;
|
||||
let mut debuginfo = false;
|
||||
let mut target = Target::X86_64;
|
||||
let mut do_accel = true;
|
||||
for arg in args {
|
||||
if arg == "-r" || arg == "--release" {
|
||||
release = true;
|
||||
} else if arg == "-d" || arg == "--debuginfo" {
|
||||
debuginfo = true;
|
||||
} else if arg == "rv64" || arg == "riscv64" || arg == "riscv64-virt" {
|
||||
target = Target::Riscv64Virt;
|
||||
} else if arg == "arm64" || arg == "aarch64" || arg == "aarch64-virt" {
|
||||
target = Target::Aarch64;
|
||||
} else if arg == "--noaccel" {
|
||||
do_accel = false;
|
||||
} else if arg == "avx2" {
|
||||
target = Target::X86_64Avx2;
|
||||
} else {
|
||||
return Err(report!(Error::InvalidSubCom));
|
||||
}
|
||||
}
|
||||
|
||||
build(release, target, debuginfo)?;
|
||||
run(release, target, do_accel)
|
||||
assemble()?;
|
||||
build(release, target)?;
|
||||
run(release, target)
|
||||
}
|
||||
Some("help" | "h") => {
|
||||
println!(concat!(
|
||||
|
@ -79,10 +63,8 @@ fn main() -> Result<(), Error> {
|
|||
" help (h): Print this message\n",
|
||||
" run (r): Build and run AbleOS in QEMU\n\n",
|
||||
"Options for build and run:\n",
|
||||
" -r / --release: build in release mode\n",
|
||||
" -d / --debuginfo: build with debug info\n",
|
||||
" --noaccel: run without acceleration (e.g, no kvm)\n",
|
||||
"[ rv64 / riscv64 / riscv64-virt / aarch64 / arm64 / aarch64-virt / avx2 ]: sets target"
|
||||
" -r: build in release mode",
|
||||
" [target]: sets target"
|
||||
),);
|
||||
Ok(())
|
||||
}
|
||||
|
@ -90,13 +72,50 @@ fn main() -> Result<(), Error> {
|
|||
}
|
||||
}
|
||||
|
||||
fn get_path_without_boot_prefix(val: &Value) -> Option<&str> {
|
||||
val.as_str()?.split("boot:///").last()
|
||||
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_fs() -> Result<FileSystem<impl ReadWriteSeek>, io::Error> {
|
||||
let filename = "sysdata/system_config.toml";
|
||||
|
||||
let mut img = File::options()
|
||||
.read(true)
|
||||
.write(true)
|
||||
|
@ -108,177 +127,8 @@ fn get_fs() -> Result<FileSystem<impl ReadWriteSeek>, io::Error> {
|
|||
fatfs::format_volume(&mut img, FormatVolumeOptions::new())?;
|
||||
|
||||
let fs = FileSystem::new(img, FsOptions::new())?;
|
||||
|
||||
// Read the contents of the file using a `match` block
|
||||
// to return the `data: Ok(c)` as a `String`
|
||||
// or handle any `errors: Err(_)`.
|
||||
let contents = match fs::read_to_string(filename) {
|
||||
// If successful return the files text as `contents`.
|
||||
// `c` is a local variable.
|
||||
Ok(c) => c,
|
||||
// Handle the `error` case.
|
||||
Err(_) => {
|
||||
// Write `msg` to `stderr`.
|
||||
eprintln!("Could not read file `{}`", filename);
|
||||
// Exit the program with exit code `1`.
|
||||
exit(1);
|
||||
}
|
||||
};
|
||||
use toml::Value;
|
||||
|
||||
let mut limine_str = String::new();
|
||||
|
||||
let mut data: Value = toml::from_str(&contents).unwrap();
|
||||
let boot_table = data.get_mut("boot");
|
||||
let limine_table = boot_table.unwrap().get_mut("limine").unwrap();
|
||||
let default_entry = limine_table.get("default_entry").unwrap();
|
||||
let timeout = limine_table.get("timeout").unwrap();
|
||||
let interface_resolution = limine_table.get("interface_resolution").unwrap();
|
||||
let verbose = limine_table.get("verbose").unwrap();
|
||||
let term_wallpaper = limine_table.get("term_wallpaper").unwrap();
|
||||
|
||||
let vb_post = match verbose.as_bool().unwrap() {
|
||||
true => "yes",
|
||||
false => "no",
|
||||
};
|
||||
let term_background = limine_table
|
||||
.get("term_backdrop")
|
||||
.unwrap_or(&Value::Integer(0));
|
||||
let base = format!(
|
||||
"DEFAULT_ENTRY={}
|
||||
TIMEOUT={}
|
||||
VERBOSE={}
|
||||
INTERFACE_RESOLUTION={}
|
||||
# Terminal related settings
|
||||
TERM_WALLPAPER={}
|
||||
TERM_BACKDROP={}
|
||||
",
|
||||
default_entry,
|
||||
timeout,
|
||||
vb_post,
|
||||
interface_resolution,
|
||||
term_wallpaper.as_str().unwrap(),
|
||||
term_background
|
||||
);
|
||||
|
||||
// Copy the term_wallpaper to the image
|
||||
let term_wallpaper_path = get_path_without_boot_prefix(term_wallpaper).unwrap();
|
||||
copy_file_to_img(&format!("sysdata/{}", term_wallpaper_path), &fs);
|
||||
|
||||
limine_str.push_str(&base);
|
||||
|
||||
let boot_entries = limine_table.as_table_mut().unwrap();
|
||||
let mut real_boot_entries = boot_entries.clone();
|
||||
for (key, value) in boot_entries.into_iter() {
|
||||
if !value.is_table() {
|
||||
real_boot_entries.remove(key);
|
||||
}
|
||||
}
|
||||
|
||||
for (name, mut value) in real_boot_entries {
|
||||
let comment = value.get("comment").unwrap();
|
||||
let protocol = value.get("protocol").unwrap();
|
||||
let resolution = value.get("resolution").unwrap();
|
||||
let kernel_path = value.get("kernel_path").unwrap();
|
||||
let kernel_cmdline = value.get("kernel_cmdline").unwrap();
|
||||
|
||||
let text_entry = format!(
|
||||
"
|
||||
:{}
|
||||
COMMENT={}
|
||||
PROTOCOL={}
|
||||
RESOLUTION={}
|
||||
KERNEL_PATH={}
|
||||
KERNEL_CMDLINE={}
|
||||
|
||||
",
|
||||
name,
|
||||
comment.as_str().unwrap(),
|
||||
protocol.as_str().unwrap(),
|
||||
resolution.as_str().unwrap(),
|
||||
kernel_path.as_str().unwrap(),
|
||||
kernel_cmdline,
|
||||
);
|
||||
|
||||
limine_str.push_str(&text_entry);
|
||||
|
||||
let modules = value.get_mut("modules").unwrap().as_table_mut().unwrap();
|
||||
// let mut real_modules = modules.clone();
|
||||
|
||||
let mut errors = String::new();
|
||||
let mut out = Vec::new();
|
||||
|
||||
modules
|
||||
.into_iter()
|
||||
.map(|(_, value)| -> Result<(), io::Error> {
|
||||
if value.is_table() {
|
||||
let path = get_path_without_boot_prefix(
|
||||
value.get("path").expect("You must have `path` as a value"),
|
||||
)
|
||||
.unwrap()
|
||||
.split(".")
|
||||
.next()
|
||||
.unwrap();
|
||||
let p = Package::load_from_file(
|
||||
format!("sysdata/programs/{}/meta.toml", path).to_owned(),
|
||||
);
|
||||
match p.build(&mut out) {
|
||||
Ok(()) => {}
|
||||
Err(_) => {
|
||||
writeln!(errors, "========= while compiling {} =========", path)
|
||||
.unwrap();
|
||||
errors.push_str(core::str::from_utf8(&out).expect("no"));
|
||||
out.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
})
|
||||
.for_each(drop);
|
||||
|
||||
if !errors.is_empty() {
|
||||
let _ = writeln!(errors, "!!! STOPPING DUE TO PREVIOUS ERRORS !!!");
|
||||
std::eprint!("{errors}");
|
||||
continue;
|
||||
}
|
||||
|
||||
modules.into_iter().for_each(|(_key, value)| {
|
||||
if value.is_table() {
|
||||
let path = value.get("path").expect("You must have `path` as a value");
|
||||
let default_value = Value::String("".into());
|
||||
let cmd_line = value.get("cmd_line").unwrap_or(&default_value);
|
||||
|
||||
let a = format!(
|
||||
" MODULE_PATH={}
|
||||
MODULE_CMDLINE={}\n\n",
|
||||
path.as_str().unwrap(),
|
||||
cmd_line
|
||||
);
|
||||
limine_str.push_str(&a);
|
||||
}
|
||||
});
|
||||
|
||||
// Copy modules into the test_programs directory
|
||||
modules.into_iter().for_each(|(_key, value)| {
|
||||
if value.is_table() {
|
||||
let path = get_path_without_boot_prefix(
|
||||
value
|
||||
.get("path")
|
||||
.expect("You must have a `path` as a value"),
|
||||
)
|
||||
.unwrap();
|
||||
let fpath = format!("target/programs/{}", path);
|
||||
copy_file_to_img(&fpath, &fs);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
let bootdir = fs.root_dir().create_dir("efi")?.create_dir("boot")?;
|
||||
|
||||
let mut f = fs.root_dir().create_file("limine.cfg")?;
|
||||
let _ = f.write(limine_str.as_bytes())?;
|
||||
drop(f);
|
||||
|
||||
io::copy(
|
||||
&mut File::open("limine/BOOTX64.EFI")
|
||||
.map_err(Report::from)
|
||||
|
@ -293,24 +143,31 @@ TERM_BACKDROP={}
|
|||
&mut bootdir.create_file("bootaa64.efi")?,
|
||||
)?;
|
||||
|
||||
for fpath in [
|
||||
"sysdata/limine.cfg",
|
||||
"sysdata/background.bmp",
|
||||
"target/test-programs/failure.hbf",
|
||||
"target/test-programs/ecall.hbf",
|
||||
"target/test-programs/main.hbf",
|
||||
"target/test-programs/serial_driver.hbf",
|
||||
"target/test-programs/vfs_test.hbf",
|
||||
"target/test-programs/limine_framebuffer_driver.hbf",
|
||||
"target/test-programs/keyboard_driver.hbf",
|
||||
] {
|
||||
let path = Path::new(fpath);
|
||||
io::copy(
|
||||
&mut File::open(path)?,
|
||||
&mut fs
|
||||
.root_dir()
|
||||
.create_file(&path.file_name().unwrap().to_string_lossy())?,
|
||||
)?;
|
||||
}
|
||||
|
||||
drop(bootdir);
|
||||
Ok(fs)
|
||||
}
|
||||
|
||||
fn copy_file_to_img(fpath: &str, fs: &FileSystem<File>) {
|
||||
let path = Path::new(fpath);
|
||||
// println!("{path:?}");
|
||||
io::copy(
|
||||
&mut File::open(path).expect(&format!("Could not open file {fpath}")),
|
||||
&mut fs
|
||||
.root_dir()
|
||||
.create_file(&path.file_name().unwrap().to_string_lossy())
|
||||
.expect("Unable to create file"),
|
||||
)
|
||||
.expect("Copy failed");
|
||||
}
|
||||
|
||||
fn build(release: bool, target: Target, debuginfo: bool) -> Result<(), Error> {
|
||||
fn build(release: bool, target: Target) -> Result<(), Error> {
|
||||
let fs = get_fs().change_context(Error::Io)?;
|
||||
let mut com = Command::new("cargo");
|
||||
com.current_dir("kernel");
|
||||
|
@ -318,9 +175,6 @@ fn build(release: bool, target: Target, debuginfo: bool) -> Result<(), Error> {
|
|||
if release {
|
||||
com.arg("-r");
|
||||
}
|
||||
if debuginfo {
|
||||
com.env("RUSTFLAGS", "-Cdebug-assertions=true");
|
||||
}
|
||||
|
||||
if target == Target::Riscv64Virt {
|
||||
com.args(["--target", "targets/riscv64-virt-ableos.json"]);
|
||||
|
@ -328,9 +182,6 @@ fn build(release: bool, target: Target, debuginfo: bool) -> Result<(), Error> {
|
|||
if target == Target::Aarch64 {
|
||||
com.args(["--target", "targets/aarch64-virt-ableos.json"]);
|
||||
}
|
||||
if target == Target::X86_64Avx2 {
|
||||
com.args(["--target", "targets/x86_64_v3-ableos.json"]);
|
||||
}
|
||||
|
||||
match com.status() {
|
||||
Ok(s) if s.code() != Some(0) => bail!(Error::Build),
|
||||
|
@ -344,10 +195,6 @@ fn build(release: bool, target: Target, debuginfo: bool) -> Result<(), Error> {
|
|||
path.push_str("_x86-64");
|
||||
"target/x86_64-ableos"
|
||||
}
|
||||
Target::X86_64Avx2 => {
|
||||
path.push_str("_x86-64");
|
||||
"target/x86_64_v3-ableos"
|
||||
}
|
||||
Target::Riscv64Virt => "target/riscv64-virt-ableos",
|
||||
Target::Aarch64 => {
|
||||
path.push_str("_aarch64");
|
||||
|
@ -370,68 +217,24 @@ fn build(release: bool, target: Target, debuginfo: bool) -> Result<(), Error> {
|
|||
.change_context(Error::Io)
|
||||
}
|
||||
|
||||
fn run(release: bool, target: Target, do_accel: bool) -> Result<(), Error> {
|
||||
let target_str = match target {
|
||||
Target::X86_64 | Target::X86_64Avx2 => "qemu-system-x86_64",
|
||||
Target::Riscv64Virt => "qemu-system-riscv64",
|
||||
Target::Aarch64 => "qemu-system-aarch64",
|
||||
fn run(release: bool, target: Target) -> Result<(), Error> {
|
||||
let mut com = match target {
|
||||
Target::X86_64 => Command::new("qemu-system-x86_64"),
|
||||
Target::Riscv64Virt => Command::new("qemu-system-riscv64"),
|
||||
Target::Aarch64 => Command::new("qemu-system-aarch64"),
|
||||
};
|
||||
let (mut com, mut com2) = (Command::new(target_str), Command::new(target_str));
|
||||
let ovmf_path = fetch_ovmf(target);
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
let accel = if do_accel {
|
||||
let supported = String::from_utf8(
|
||||
com2.args(["--accel", "help"])
|
||||
.stdout(Stdio::piped())
|
||||
.stderr(Stdio::piped())
|
||||
.spawn()
|
||||
.unwrap()
|
||||
.wait_with_output()
|
||||
.unwrap()
|
||||
.stdout,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let cpuid = raw_cpuid::CpuId::new();
|
||||
let vmx = cpuid.get_feature_info().unwrap().has_vmx();
|
||||
let svm = cpuid.get_svm_info().is_some();
|
||||
|
||||
if supported.contains("kvm") && (vmx || svm) {
|
||||
"accel=kvm"
|
||||
} else if cpuid
|
||||
.get_processor_brand_string()
|
||||
.filter(|a| a.as_str() == "GenuineIntel")
|
||||
.is_some()
|
||||
&& supported.contains("hax")
|
||||
&& vmx
|
||||
{
|
||||
"accel=hax"
|
||||
} else if supported.contains("whpx") {
|
||||
"accel=whpx"
|
||||
} else {
|
||||
"accel=tcg"
|
||||
}
|
||||
} else {
|
||||
"accel=tcg"
|
||||
};
|
||||
#[cfg(not(target_arch = "x86_64"))]
|
||||
let accel = "accel=tcg";
|
||||
|
||||
match target {
|
||||
Target::X86_64 | Target::X86_64Avx2 => {
|
||||
Target::X86_64 => {
|
||||
#[rustfmt::skip]
|
||||
com.args([
|
||||
"-bios", &ovmf_path.change_context(Error::OvmfFetch)?,
|
||||
"-drive", "file=target/disk.img,format=raw",
|
||||
"-device", "vmware-svga",
|
||||
// "-serial", "stdio",
|
||||
"-m", "2G",
|
||||
"-smp", "1",
|
||||
"-parallel", "none",
|
||||
"-monitor", "none",
|
||||
"-machine", accel,
|
||||
"-cpu", "max",
|
||||
"-device", "isa-debug-exit,iobase=0xf4,iosize=0x04",
|
||||
"-m", "4G",
|
||||
"-smp", "cores=4",
|
||||
// "-enable-kvm",
|
||||
"-cpu", "Broadwell-v4"
|
||||
]);
|
||||
}
|
||||
Target::Riscv64Virt => {
|
||||
|
@ -452,7 +255,7 @@ fn run(release: bool, target: Target, do_accel: bool) -> Result<(), Error> {
|
|||
#[rustfmt::skip]
|
||||
com.args([
|
||||
"-M", "virt",
|
||||
"-cpu", "neoverse-n2",
|
||||
"-cpu", "cortex-a72",
|
||||
"-device", "ramfb",
|
||||
"-device", "qemu-xhci",
|
||||
"-device", "usb-kbd",
|
||||
|
@ -475,7 +278,7 @@ fn run(release: bool, target: Target, do_accel: bool) -> Result<(), Error> {
|
|||
|
||||
fn fetch_ovmf(target: Target) -> Result<String, OvmfFetchError> {
|
||||
let (ovmf_url, ovmf_path) = match target {
|
||||
Target::X86_64 | Target::X86_64Avx2 => (
|
||||
Target::X86_64 => (
|
||||
"https://retrage.github.io/edk2-nightly/bin/RELEASEX64_OVMF.fd",
|
||||
"target/RELEASEX64_OVMF.fd",
|
||||
),
|
||||
|
@ -497,12 +300,12 @@ fn fetch_ovmf(target: Target) -> Result<String, OvmfFetchError> {
|
|||
Ok(_) => return Ok(ovmf_path.to_owned()),
|
||||
Err(e) => return Err(report!(e).change_context(OvmfFetchError::Io)),
|
||||
};
|
||||
let req = ureq::get(ovmf_url)
|
||||
.call()
|
||||
let mut bytes = reqwest::blocking::get(ovmf_url)
|
||||
.map_err(Report::from)
|
||||
.change_context(OvmfFetchError::Fetch)?;
|
||||
|
||||
std::io::copy(&mut req.into_reader(), &mut file)
|
||||
bytes
|
||||
.copy_to(&mut file)
|
||||
.map_err(Report::from)
|
||||
.change_context(OvmfFetchError::Io)?;
|
||||
|
||||
|
@ -511,11 +314,11 @@ fn fetch_ovmf(target: Target) -> Result<String, OvmfFetchError> {
|
|||
|
||||
#[derive(Debug, Display)]
|
||||
enum OvmfFetchError {
|
||||
#[display("Failed to fetch OVMF package")]
|
||||
#[display(fmt = "Failed to fetch OVMF package")]
|
||||
Fetch,
|
||||
#[display("No OVMF package available")]
|
||||
#[display(fmt = "No OVMF package available")]
|
||||
Empty,
|
||||
#[display("IO Error")]
|
||||
#[display(fmt = "IO Error")]
|
||||
Io,
|
||||
}
|
||||
|
||||
|
@ -524,33 +327,30 @@ impl Context for OvmfFetchError {}
|
|||
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||
enum Target {
|
||||
X86_64,
|
||||
X86_64Avx2,
|
||||
Riscv64Virt,
|
||||
Aarch64,
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
#[derive(Debug, Display)]
|
||||
enum Error {
|
||||
#[display("Failed to build the kernel")]
|
||||
#[display(fmt = "Failed to build the kernel")]
|
||||
Build,
|
||||
#[display("Missing or invalid subcommand (available: build, run)")]
|
||||
#[display(fmt = "Missing or invalid subcommand (available: build, run)")]
|
||||
InvalidSubCom,
|
||||
#[display("IO Error")]
|
||||
#[display(fmt = "IO Error")]
|
||||
Io,
|
||||
#[display("Failed to spawn a process")]
|
||||
#[display(fmt = "Failed to spawn a process")]
|
||||
ProcessSpawn,
|
||||
#[display("Failed to fetch UEFI firmware")]
|
||||
#[display(fmt = "Failed to fetch UEFI firmware")]
|
||||
OvmfFetch,
|
||||
#[display("Failed to assemble Holey Bytes code")]
|
||||
#[display(fmt = "Failed to assemble Holey Bytes code")]
|
||||
Assembler,
|
||||
#[display("QEMU Error: {}", "fmt_qemu_err(*_0)")]
|
||||
#[display(fmt = "QEMU Error: {}", "fmt_qemu_err(*_0)")]
|
||||
Qemu(Option<i32>),
|
||||
}
|
||||
|
||||
impl Context for Error {}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn fmt_qemu_err(e: Option<i32>) -> impl Display {
|
||||
struct W(Option<i32>);
|
||||
impl Display for W {
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
[toolchain]
|
||||
# old toolchain
|
||||
# channel = "nightly-2024-07-27"
|
||||
channel = "nightly"
|
||||
channel = "nightly"
|
||||
components = ["rust-src", "llvm-tools"]
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 100 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -1,10 +0,0 @@
|
|||
Tamsyn font is free. You are hereby granted permission to use, copy, modify,
|
||||
and distribute it as you see fit.
|
||||
|
||||
Tamsyn font is provided "as is" without any express or implied warranty.
|
||||
|
||||
The author makes no representations about the suitability of this font for
|
||||
a particular purpose.
|
||||
|
||||
In no event will the author be held liable for damages arising from the use
|
||||
of this font.
|
Binary file not shown.
Before Width: | Height: | Size: 100 KiB |
Binary file not shown.
Binary file not shown.
|
@ -1,22 +0,0 @@
|
|||
Boolean
|
||||
Stuffed into a u8 to be indexed into
|
||||
|
||||
00_00_00_01
|
||||
^^--- One Boolean
|
||||
|the Second Boolean
|
||||
|
||||
UTF8 String
|
||||
"Able The Above" => UTF8 14 bytes long
|
||||
Date Time (U128 seconds since the beginning of the universe)
|
||||
|
||||
Binary Blob
|
||||
|
||||
List<T>
|
||||
Bound/Unbound
|
||||
// Ordered/Unordered
|
||||
|
||||
|
||||
Examples:
|
||||
OSPath Is Unbounded List <String>
|
||||
|
||||
Hashmap<K, V>
|
Binary file not shown.
Before Width: | Height: | Size: 66 B |
|
@ -1 +0,0 @@
|
|||
# abc
|
|
@ -1,24 +0,0 @@
|
|||
@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;
|
||||
}
|
|
@ -1,3 +0,0 @@
|
|||
# Horizon
|
||||
Horizon is the windowing system for ableOS.
|
||||
This is the API library to handle it nicely.
|
|
@ -1,4 +0,0 @@
|
|||
(horizontal
|
||||
spacing : 10
|
||||
(label "hi")
|
||||
(label "goodbye"))
|
|
@ -1 +0,0 @@
|
|||
(label "hello")
|
|
@ -1,3 +0,0 @@
|
|||
(vertical
|
||||
(label "hello")
|
||||
(label "hello" color:red))
|
|
@ -1,49 +0,0 @@
|
|||
stn := @use("../../stn/src/lib.hb");
|
||||
.{string, memory, buffer, log} := stn
|
||||
|
||||
render := @use("../../../libraries/render/src/lib.hb")
|
||||
|
||||
input := @use("../../intouch/src/lib.hb")
|
||||
|
||||
widgets := @use("widgets/widgets.hb")
|
||||
ui := @use("ui.hb")
|
||||
|
||||
WindowID := struct {
|
||||
host_id: int,
|
||||
window_id: int,
|
||||
}
|
||||
|
||||
VoidWindowID := WindowID.(0, 0)
|
||||
|
||||
create_window := fn(channel: int): ^render.Surface {
|
||||
// get the horizon buffer
|
||||
// request a new window and provide the callback buffer
|
||||
// wait to recieve a message
|
||||
|
||||
windowing_system_buffer := buffer.search("XHorizon\0")
|
||||
mem_buf := memory.request_page(1)
|
||||
|
||||
if windowing_system_buffer == 0 {
|
||||
return @as(^render.Surface, idk)
|
||||
} else {
|
||||
// ! bad able, stop using string messages :ragey:
|
||||
// msg := "\{01}\0"
|
||||
// msg_length := 2
|
||||
|
||||
// @as(void, @eca(3, windowing_system_buffer, msg, msg_length))
|
||||
|
||||
x := 0
|
||||
loop if x > 1000 break else x += 1
|
||||
|
||||
ret := buffer.recv([u8; 4096], windowing_system_buffer, mem_buf)
|
||||
if ret == null {
|
||||
log.info("No messages\0")
|
||||
}
|
||||
|
||||
if *mem_buf == 0 {
|
||||
log.info("No messages\0")
|
||||
}
|
||||
|
||||
return @as(^render.Surface, idk)
|
||||
}
|
||||
}
|
|
@ -1,47 +0,0 @@
|
|||
stn := @use("../../../libraries/stn/src/lib.hb");
|
||||
.{string, log} := stn;
|
||||
.{Vec2} := stn.math
|
||||
|
||||
render := @use("../../../libraries/render/src/lib.hb");
|
||||
.{Surface} := render;
|
||||
.{Font} := render.text
|
||||
|
||||
UI := struct {raw: ^u8, raw_length: uint, is_dirty: bool, surface: Surface, // Each child has their WidgetType as their first byte
|
||||
// children: ^^u8,
|
||||
}
|
||||
|
||||
render_ui := fn(surface: Surface, ui: UI): void {
|
||||
if ui.is_dirty {
|
||||
render.clear(ui.surface, render.black)
|
||||
ui.is_dirty = false
|
||||
}
|
||||
pos := Vec2(uint).(0, 0)
|
||||
render.put_surface(surface, ui.surface, pos, false)
|
||||
}
|
||||
|
||||
sexpr_parser := fn(sexpr: ^u8): UI {
|
||||
cursor := sexpr
|
||||
paren_balance := 0
|
||||
loop {
|
||||
if *cursor == 0 {
|
||||
if paren_balance != 0 {
|
||||
log.error("Unbalanced Parens\0")
|
||||
}
|
||||
break
|
||||
} else if *cursor == 40 {
|
||||
log.info("Open paren\0")
|
||||
paren_balance += 1
|
||||
} else if *cursor == 41 {
|
||||
log.info("Closed paren\0")
|
||||
paren_balance -= 1
|
||||
}
|
||||
|
||||
cursor += 1
|
||||
}
|
||||
|
||||
length := string.length(sexpr)
|
||||
|
||||
ui_surface := render.new_surface(100, 100)
|
||||
|
||||
return UI.(sexpr, length, true, ui_surface)
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
render := @use("../../../../libraries/render/src/lib.hb");
|
||||
.{Surface} := render
|
||||
|
||||
Image := struct {
|
||||
magic: uint,
|
||||
is_dirty: bool,
|
||||
surface: Surface,
|
||||
}
|
||||
|
||||
image_from_surface := fn(surface: Surface): Image {
|
||||
img := Image.(4, true, surface)
|
||||
return img
|
||||
}
|
|
@ -1,46 +0,0 @@
|
|||
stn := @use("../../../../libraries/stn/src/lib.hb");
|
||||
.{string, log} := stn;
|
||||
.{Vec2} := stn.math
|
||||
|
||||
render := @use("../../../../libraries/render/src/lib.hb");
|
||||
.{Surface, Color} := render;
|
||||
.{Font} := render.text
|
||||
|
||||
Label := struct {
|
||||
magic: uint,
|
||||
is_dirty: bool,
|
||||
surface: Surface,
|
||||
text: ^u8,
|
||||
text_length: uint,
|
||||
bg: Color,
|
||||
fg: Color,
|
||||
}
|
||||
|
||||
set_label_text := fn(label: Label, text: ^u8): void {
|
||||
text_length := string.length(text)
|
||||
|
||||
label.is_dirty = true
|
||||
label.text = text
|
||||
label.text_length = text_length
|
||||
}
|
||||
|
||||
render_label_to_surface := fn(surface: Surface, label: Label, font: Font, pos: Vec2(uint)): void {
|
||||
if label.is_dirty {
|
||||
render.clear(label.surface, label.bg)
|
||||
render.put_text(label.surface, font, .(0, 0), label.fg, label.text)
|
||||
}
|
||||
render.put_surface(surface, label.surface, pos, false)
|
||||
}
|
||||
|
||||
new_label := fn(text: ^u8): Label {
|
||||
text_surface := render.new_surface(1024, 20)
|
||||
text_length := string.length(text)
|
||||
label := Label.(3, true, text_surface, text, text_length, render.black, render.white)
|
||||
return label
|
||||
}
|
||||
|
||||
$set_color := fn(label: Label, bg: Color, fg: Color): void {
|
||||
label.bg = bg
|
||||
label.fg = fg
|
||||
label.is_dirty = true
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
NoWidget := 0
|
||||
|
||||
VerticalWidgetType := 1
|
||||
HorizontalWidgetType := 2
|
||||
|
||||
LabelWidgetType := 3
|
||||
ImageWidgetType := 4
|
|
@ -1,36 +0,0 @@
|
|||
// Widget types
|
||||
|
||||
// End types
|
||||
stn := @use("../../../../libraries/stn/src/lib.hb");
|
||||
.{string, log} := stn;
|
||||
.{Vec2} := stn.math
|
||||
|
||||
render := @use("../../../../libraries/render/src/lib.hb");
|
||||
.{Surface} := render;
|
||||
.{Font} := render.text
|
||||
|
||||
widget_types := @use("widget_types.hb")
|
||||
label := @use("label.hb")
|
||||
image := @use("image.hb")
|
||||
|
||||
Size := struct {
|
||||
min_width: int,
|
||||
max_width: int,
|
||||
min_height: int,
|
||||
max_height: int,
|
||||
}
|
||||
|
||||
Vertical := packed struct {
|
||||
magic: uint,
|
||||
// array of children, idk
|
||||
// use a vec or linked list or whatever
|
||||
|
||||
children: ^^u8,
|
||||
}
|
||||
|
||||
Horizontal := packed struct {
|
||||
magic: uint,
|
||||
// array of children, idk
|
||||
// use a vec or linked list or whatever
|
||||
children: ^^u8,
|
||||
}
|
|
@ -1,2 +0,0 @@
|
|||
# Ignim
|
||||
Ignim is the ableOS vulkan interface library.
|
|
@ -1,21 +0,0 @@
|
|||
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: ^u8,
|
||||
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
|
||||
}
|
|
@ -1,14 +0,0 @@
|
|||
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
|
|
@ -1,10 +0,0 @@
|
|||
Extent3D := struct {
|
||||
width: int,
|
||||
height: int,
|
||||
depth: int,
|
||||
}
|
||||
|
||||
Extent2D := struct {
|
||||
width: int,
|
||||
height: int,
|
||||
}
|
|
@ -1,35 +0,0 @@
|
|||
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
|
||||
}
|
|
@ -1,17 +0,0 @@
|
|||
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
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
Offset3D := struct {
|
||||
x: int,
|
||||
y: int,
|
||||
z: int,
|
||||
}
|
||||
|
||||
Offset2D := struct {
|
||||
x: int,
|
||||
y: int,
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
offsets := @use("offset.hb")
|
||||
extends := @use("extends.hb")
|
||||
|
||||
Rect2D := struct {
|
||||
offset: offsets.Offset2D,
|
||||
extent: extends.Extent2D,
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
// NonErrors
|
||||
Success := 0
|
||||
NotReady := 1
|
||||
Timeout := 2
|
||||
EventSet := 3
|
||||
EventReset := 4
|
||||
Incomplete := 5
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue