Compare commits
11 commits
Author | SHA1 | Date | |
---|---|---|---|
923e8b7218 | |||
0e5d5f7de7 | |||
d0d6f0475e | |||
0775d0c70a | |||
86e1020bc7 | |||
39f7d5aba4 | |||
45950fdb34 | |||
f9451e3d7d | |||
6be6635e4e | |||
b5cdc9c4fd | |||
94b7aabdec |
|
@ -1,3 +1,3 @@
|
||||||
[alias]
|
[alias]
|
||||||
repbuild = "run --manifest-path ./repbuild/Cargo.toml -- "
|
repbuild = "run --manifest-path ./repbuild/Cargo.toml -r --"
|
||||||
dev = "run --manifest-path ./dev/Cargo.toml -r --"
|
dev = "run --manifest-path ./dev/Cargo.toml -r --"
|
||||||
|
|
2
.vscode/settings.json
vendored
2
.vscode/settings.json
vendored
|
@ -1,6 +1,4 @@
|
||||||
{
|
{
|
||||||
"editor.insertSpaces": false,
|
|
||||||
"editor.detectIndentation": false,
|
|
||||||
"rust-analyzer.checkOnSave.allTargets": false,
|
"rust-analyzer.checkOnSave.allTargets": false,
|
||||||
"rust-analyzer.showUnlinkedFileNotification": false,
|
"rust-analyzer.showUnlinkedFileNotification": false,
|
||||||
"C_Cpp.errorSquiggles": "disabled"
|
"C_Cpp.errorSquiggles": "disabled"
|
||||||
|
|
1430
Cargo.lock
generated
1430
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
|
@ -1,9 +1,3 @@
|
||||||
[workspace]
|
[workspace]
|
||||||
resolver = "2"
|
resolver = "2"
|
||||||
members = ["dev", "kernel", "repbuild"]
|
members = [ "dev","kernel", "repbuild"]
|
||||||
|
|
||||||
# [profile.release]
|
|
||||||
# strip = "symbols"
|
|
||||||
# codegen-units = 1
|
|
||||||
# lto = true
|
|
||||||
# panic = "abort"
|
|
||||||
|
|
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
|
@ -10,7 +10,15 @@ Donations can be made [here on Liberapay](https://liberapay.com/AbleTheAbove) or
|
||||||
<img src="https://img.shields.io/liberapay/patrons/AbleTheAbove.svg?logo=liberapay">
|
<img src="https://img.shields.io/liberapay/patrons/AbleTheAbove.svg?logo=liberapay">
|
||||||
|
|
||||||
# Compiling
|
# Compiling
|
||||||
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).
|
||||||
|
|
||||||
|
For running AbleOS, `repbuild` uses QEMU.
|
||||||
|
|
||||||
|
## Steps
|
||||||
|
1. Ensure you have qemu installed
|
||||||
|
2. `git submodule update --init`
|
||||||
|
3. `cargo repbuild run`
|
||||||
|
|
||||||
# Developing
|
# Developing
|
||||||
There is a new work in progress developer tool for hblang. (see: dev folder)
|
There is a new work in progress developer tool for hblang.
|
|
@ -1,77 +0,0 @@
|
||||||
# Style Guide
|
|
||||||
This style guide has two modes that a guideline may be.
|
|
||||||
|
|
||||||
`strict` means that prs will be rejected if they do not follow the guideline.
|
|
||||||
|
|
||||||
`loose` means that a pr would be accepted but should later be fixed.
|
|
||||||
|
|
||||||
## Empty Functions | loose
|
|
||||||
Empty functions are typically a sign of an unfinished program or driver.
|
|
||||||
|
|
||||||
In cases where there is a clear reason to have an empty function it will be allowed.
|
|
||||||
For example FakeAlloc is only empty functions because it is a example of an the allocator api.
|
|
||||||
|
|
||||||
### Allowed
|
|
||||||
```rust
|
|
||||||
/// in example.hb
|
|
||||||
a := fn(): void {}
|
|
||||||
```
|
|
||||||
### Not Allowed
|
|
||||||
```rust
|
|
||||||
/// in fat32.hb
|
|
||||||
a := fn(): void {}
|
|
||||||
```
|
|
||||||
## Magic Functions | loose
|
|
||||||
'Magic functions' are what I am calling small helper functions that do one or two things.
|
|
||||||
### Example
|
|
||||||
```rust
|
|
||||||
a := null
|
|
||||||
magic_a := fn(){
|
|
||||||
a = 10
|
|
||||||
}
|
|
||||||
```
|
|
||||||
The exact policy I want to have here is a bit fuzzy. I think that functions like this are nice in certain situations and not in others.
|
|
||||||
Regardless of if you use them or not, put a comment above the function explaining rational.
|
|
||||||
|
|
||||||
|
|
||||||
## Magic Numbers | loose
|
|
||||||
The policy on magic numbers is make them const and have a comment above them. Typically linking to a source of information about the magic number.
|
|
||||||
|
|
||||||
This helps cut down on magic numbers while making acceptable names and atleast half assed documentation.
|
|
||||||
|
|
||||||
Constants are inlined anyways, so its the same thing in the binary.
|
|
||||||
|
|
||||||
```rust
|
|
||||||
// The standard vga port is mapped at 0xB8000
|
|
||||||
$VGA_PTR := 0xB8000
|
|
||||||
```
|
|
||||||
|
|
||||||
## Tabs Vs Spaces | strict
|
|
||||||
I prefer for hblang code to use hard tabs.
|
|
||||||
|
|
||||||
The rational behind this is that a tab is `1 Indent` which some developers might want to be various different sizes when displayed
|
|
||||||
|
|
||||||
Soft tabs do not allow this user/editor specific as soft tabs always become spaces.
|
|
||||||
|
|
||||||
Bottom line is this is an accessibility feature.
|
|
||||||
|
|
||||||
There are some samples below.
|
|
||||||
```
|
|
||||||
\t means hard tab
|
|
||||||
\n means new line
|
|
||||||
\0x20 means space
|
|
||||||
```
|
|
||||||
|
|
||||||
### Allowed
|
|
||||||
```rust
|
|
||||||
if x == y {\n
|
|
||||||
\tlog(z)\n
|
|
||||||
}\n
|
|
||||||
```
|
|
||||||
|
|
||||||
### Not Allowed
|
|
||||||
```rust
|
|
||||||
if x == y {\n
|
|
||||||
\0x20\0x20\0x20\0x20log(z)\n
|
|
||||||
}\n
|
|
||||||
```
|
|
31
dev/aldi.bnf
Normal file
31
dev/aldi.bnf
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
|
||||||
|
|
||||||
|
declarations ::= <declaration> <declarations>
|
||||||
|
declaration ::= <enum_decl> | <struct_decl> | <type_decl> | <protocol_decl>
|
||||||
|
|
||||||
|
type_decl ::= "type" <ident> <ident> ";"
|
||||||
|
|
||||||
|
enum_decl ::= "enum" <ident> "{" "}"
|
||||||
|
| "enum" <ident> "{" <enum_members> "}"
|
||||||
|
|
||||||
|
|
||||||
|
enum_members ::= <enum_member> ["," <enum_member>]+ [","]
|
||||||
|
|
||||||
|
enum_member ::= <ident> "=" <number>
|
||||||
|
|
||||||
|
|
||||||
|
struct_decl ::= "struct" <ident> "{" "}"
|
||||||
|
| "struct" <ident> "{" <struct_members> "}"
|
||||||
|
|
||||||
|
struct_members ::= <struct_member>
|
||||||
|
| <struct_member> ","
|
||||||
|
| <struct_member> "," <struct_members>
|
||||||
|
| <struct_member> "," <struct_members>
|
||||||
|
|
||||||
|
protocol_decl ::= "protocol" <ident> "{" "}"
|
||||||
|
| "protocol" <ident> "{" <protocol_member>+ "}"
|
||||||
|
|
||||||
|
protocol_member ::= "fn" <ident>"("[<arg_list>]")" "->" <ident> ";"
|
||||||
|
|
||||||
|
arg_list ::= <ident> ["," <ident>]+
|
||||||
|
|
|
@ -1,56 +1,78 @@
|
||||||
pub mod protocol;
|
mod parser;
|
||||||
|
mod types;
|
||||||
|
mod protocol;
|
||||||
|
|
||||||
|
use crate::idl::{parser::parse, types::get_protocols};
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
|
|
||||||
use {
|
use logos::{Lexer, Logos, Skip};
|
||||||
logos::{Lexer, Logos},
|
|
||||||
protocol::Protocol,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[derive(Logos, Debug, PartialEq, Clone)]
|
#[derive(Logos, Debug, PartialEq, Clone)]
|
||||||
#[logos(skip r"[ \t\n\f]+")] // Ignore this regex pattern between tokens
|
#[logos(extras = (usize, usize))]
|
||||||
enum Token {
|
enum Token {
|
||||||
|
#[regex("//[^\n]*", logos::skip)]
|
||||||
|
Comment,
|
||||||
|
|
||||||
|
#[regex(r"[ \t\f]+", logos::skip)]
|
||||||
|
Ignored,
|
||||||
|
|
||||||
|
#[regex(r"\n", newline_callback)]
|
||||||
|
Newline,
|
||||||
|
|
||||||
// Tokens can be literal strings, of any length.
|
// Tokens can be literal strings, of any length.
|
||||||
#[token("protocol")]
|
#[token("protocol", get_token_position)]
|
||||||
Protocol,
|
Protocol((usize,usize)),
|
||||||
|
|
||||||
#[token("{")]
|
// Tokens can be literal strings, of any length.
|
||||||
LBrace,
|
#[token("type", get_token_position)]
|
||||||
|
Type((usize, usize)),
|
||||||
|
|
||||||
#[token("}")]
|
#[token("fn", priority = 5, callback = get_token_position)]
|
||||||
RBrace,
|
Fn((usize, usize)),
|
||||||
|
|
||||||
#[token("(")]
|
#[token("enum", get_token_position)]
|
||||||
LParen,
|
Enum((usize, usize)),
|
||||||
|
|
||||||
#[token(")")]
|
#[token("struct", get_token_position)]
|
||||||
RParen,
|
Struct((usize, usize)),
|
||||||
|
|
||||||
#[token(":")]
|
#[token("{", get_token_position)]
|
||||||
Colon,
|
LBrace((usize, usize)),
|
||||||
#[token(";")]
|
|
||||||
SemiColon,
|
|
||||||
|
|
||||||
#[token(",")]
|
#[token("}", get_token_position)]
|
||||||
Comma,
|
RBrace((usize, usize)),
|
||||||
|
|
||||||
#[token("=")]
|
#[token("(", get_token_position)]
|
||||||
Equal,
|
LParen((usize, usize)),
|
||||||
|
|
||||||
#[token("->")]
|
#[token(")", get_token_position)]
|
||||||
RArrow,
|
RParen((usize, usize)),
|
||||||
|
|
||||||
#[regex("[a-zA-Z_]+", |lex|{lex.slice().to_string()})]
|
#[token(":", get_token_position)]
|
||||||
Text(String),
|
Colon((usize, usize)),
|
||||||
|
|
||||||
#[regex("[1234567890]+", |lex|{lex.slice().parse::<u64>().unwrap()})]
|
#[token(";", get_token_position)]
|
||||||
Number(u64),
|
SemiColon((usize, usize)),
|
||||||
|
|
||||||
#[regex(r"@[a-zA-Z_]+", |lex|{lex.slice().to_string()})]
|
#[token(",", get_token_position)] Comma((usize, usize)),
|
||||||
Decorator(String),
|
|
||||||
|
|
||||||
#[regex(r#"@[a-zA-Z_]+\([a-zA-Z,0-9=]+\)"#, |lex|{lex.slice().to_string()})]
|
#[token("=", get_token_position)]
|
||||||
DecoratorOption(String),
|
Equal((usize, usize)),
|
||||||
|
|
||||||
|
#[token("->", get_token_position)]
|
||||||
|
RArrow((usize, usize)),
|
||||||
|
|
||||||
|
#[regex("[a-zA-Z_][a-zA-Z_1234567890]+", |lex|{let text = lex.slice().to_string(); let (line, col) = get_token_position(lex); (line, col, text)})]
|
||||||
|
Identifier((usize, usize, String)),
|
||||||
|
|
||||||
|
#[regex("[1234567890]+", |lex|{let num = lex.slice().parse::<u64>().unwrap(); let (line, col) = get_token_position(lex); (line, col, num) })]
|
||||||
|
Number((usize, usize, u64)),
|
||||||
|
|
||||||
|
#[regex(r"@[a-zA-Z_]+", /*|lex|{lex.slice().to_string()}*/ logos::skip)]
|
||||||
|
Decorator,
|
||||||
|
|
||||||
|
#[regex(r#"@[a-zA-Z_]+\([a-zA-Z,0-9=]+\)"#, /*|lex|{lex.slice().to_string()}*/ logos::skip)]
|
||||||
|
DecoratorOption,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn build_idl(name: String) {
|
pub fn build_idl(name: String) {
|
||||||
|
@ -60,25 +82,36 @@ pub fn build_idl(name: String) {
|
||||||
for x in lex {
|
for x in lex {
|
||||||
match x {
|
match x {
|
||||||
Ok(token) => {
|
Ok(token) => {
|
||||||
println!("{:?}", token);
|
|
||||||
tokens.push(token);
|
tokens.push(token);
|
||||||
}
|
}
|
||||||
Err(err) => println!("{:?}", err),
|
Err(err) => println!("{:?}", err),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
build(tokens);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn build(a: Vec<Token>) {
|
let protocols = get_protocols(parse(tokens));
|
||||||
for toke in a {
|
let data : Vec<u8> = vec![1, 5, 12, 12, 12, 12, 3, 28, 8, 28];
|
||||||
println!("{:?}", toke);
|
println!("{:#?}", &protocols);
|
||||||
}
|
protocols.validate("Foo", "bar" , data).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn open_protocol(name: String) -> String {
|
fn open_protocol(name: String) -> String {
|
||||||
let path = format!("sysdata/idl/{}/src/protocol.aidl", name);
|
let path = format!("sysdata/idl/{}/src/protocol.aldi", name);
|
||||||
let mut file = std::fs::File::open(path).unwrap();
|
let mut file = std::fs::File::open(path).unwrap();
|
||||||
let mut contents = String::new();
|
let mut contents = String::new();
|
||||||
file.read_to_string(&mut contents).unwrap();
|
file.read_to_string(&mut contents).unwrap();
|
||||||
contents
|
contents
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_token_position(lex : &mut Lexer<Token>) -> (usize, usize) {
|
||||||
|
let line = lex.extras.0;
|
||||||
|
let column = lex.span().start - lex.extras.1;
|
||||||
|
|
||||||
|
(line, column + 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Update the line count and the char index.
|
||||||
|
fn newline_callback(lex: &mut Lexer<Token>) -> Skip {
|
||||||
|
lex.extras.0 += 1;
|
||||||
|
lex.extras.1 = lex.span().end;
|
||||||
|
Skip
|
||||||
|
}
|
||||||
|
|
277
dev/src/idl/parser.rs
Normal file
277
dev/src/idl/parser.rs
Normal file
|
@ -0,0 +1,277 @@
|
||||||
|
use std::{iter::Peekable, slice::Iter};
|
||||||
|
use super::Token;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
pub struct AST(pub Vec<Declaration>);
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
pub enum Declaration{
|
||||||
|
EnumDeclaration(EnumDeclaration),
|
||||||
|
StructDeclaration(StructDeclaration),
|
||||||
|
TypeDeclaration(TypeDeclaration),
|
||||||
|
ProtocolDeclaration(ProtocolDeclaration),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
pub struct StructDeclaration {
|
||||||
|
pub name : String,
|
||||||
|
pub members : Vec<StructMember>,
|
||||||
|
}
|
||||||
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
pub struct TypeDeclaration {
|
||||||
|
pub name : String,
|
||||||
|
pub type_name : String,
|
||||||
|
}
|
||||||
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
pub struct StructMember {
|
||||||
|
pub name : String,
|
||||||
|
pub type_name : String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
pub struct EnumDeclaration {
|
||||||
|
pub name : String,
|
||||||
|
pub members : Vec<EnumMember>,
|
||||||
|
}
|
||||||
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
pub struct EnumMember {
|
||||||
|
pub name : String,
|
||||||
|
pub number: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
pub struct ProtocolDeclaration{
|
||||||
|
pub name : String,
|
||||||
|
pub interface : Vec<FuncDeclaration>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
pub struct FuncDeclaration {
|
||||||
|
pub name : String,
|
||||||
|
pub arg_list : Vec<String>,
|
||||||
|
pub return_type : String,
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! consume {
|
||||||
|
($tokens:ident, $token_type:path) => {
|
||||||
|
let a = $tokens.next();
|
||||||
|
match a {
|
||||||
|
None => panic!("Expected {}, Got End Of Tokens", stringify!($token_type)),
|
||||||
|
Some(t) => {
|
||||||
|
if matches!(t, $token_type(_)){}
|
||||||
|
else {
|
||||||
|
panic!("Expected {:?}, Got {:?}", stringify!($token_type), t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn parse(tokens : Vec<Token>) -> AST{
|
||||||
|
let mut tokens_iter = tokens.iter().peekable();
|
||||||
|
AST(declarations(&mut tokens_iter))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn declarations(tokens : &mut Peekable<Iter<'_, Token>>) -> Vec<Declaration> {
|
||||||
|
let mut decls : Vec<Declaration> = Vec::new();
|
||||||
|
loop {
|
||||||
|
match declaration(tokens) {
|
||||||
|
Some(x) => decls.push(x),
|
||||||
|
None => break,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
decls
|
||||||
|
}
|
||||||
|
|
||||||
|
fn declaration(tokens : &mut Peekable<Iter<'_, Token>>) -> Option<Declaration> {
|
||||||
|
match tokens.peek(){
|
||||||
|
None => None,
|
||||||
|
Some(tok) => match tok {
|
||||||
|
Token::Enum(_) => Some(enum_decl(tokens)),
|
||||||
|
Token::Struct(_) => Some(struct_decl(tokens)),
|
||||||
|
Token::Type(_) => Some(type_declaration(tokens)),
|
||||||
|
Token::Protocol(_) => Some(protocol_declaration(tokens)),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn enum_decl(tokens : &mut Peekable<Iter<'_, Token>>) -> Declaration {
|
||||||
|
consume!(tokens, Token::Enum);
|
||||||
|
let name = identifier(tokens).expect("Expected Identifier after `enum`");
|
||||||
|
consume!(tokens, Token::LBrace);
|
||||||
|
let mut members = Vec::new();
|
||||||
|
|
||||||
|
match tokens.peek().expect("Unexpected EOF after LBrace") {
|
||||||
|
Token::RBrace(_) => {}, // skip checking for enum_members if empty
|
||||||
|
_ => {
|
||||||
|
enum_members(tokens, &mut members);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
consume!(tokens, Token::RBrace);
|
||||||
|
|
||||||
|
Declaration::EnumDeclaration(EnumDeclaration{name, members})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn enum_members(tokens : &mut Peekable<Iter<'_, Token>>, members: &mut Vec<EnumMember>) {
|
||||||
|
members.push(enum_member(tokens).unwrap());
|
||||||
|
loop {
|
||||||
|
match tokens.peek().expect("Unexpected EOF inside enum declaration") {
|
||||||
|
Token::Comma(_) => {
|
||||||
|
consume!(tokens, Token::Comma);
|
||||||
|
if let Some(member) = enum_member(tokens) {
|
||||||
|
members.push(member);
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn enum_member(tokens : &mut Peekable<Iter<'_, Token>>) -> Option<EnumMember> {
|
||||||
|
let name = identifier(tokens);
|
||||||
|
if let Some(name) = name {
|
||||||
|
consume!(tokens, Token::Equal);
|
||||||
|
let number = parse_number(tokens).expect("Expected Number after `=`");
|
||||||
|
Some(EnumMember{name, number})
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn struct_decl(tokens : &mut Peekable<Iter<'_, Token>>) -> Declaration {
|
||||||
|
consume!(tokens, Token::Struct);
|
||||||
|
let name = identifier(tokens).expect("Expected Identifier after `struct`");
|
||||||
|
consume!(tokens, Token::LBrace);
|
||||||
|
let mut members = Vec::new();
|
||||||
|
|
||||||
|
match tokens.peek().expect("Unexpected EOF after LBrace") {
|
||||||
|
Token::RBrace(_) => {}, // skip checking for struct_members if empty
|
||||||
|
_ => {
|
||||||
|
struct_members(tokens, &mut members);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
consume!(tokens, Token::RBrace);
|
||||||
|
|
||||||
|
Declaration::StructDeclaration(StructDeclaration{name, members})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn struct_members(tokens : &mut Peekable<Iter<'_, Token>>, members: &mut Vec<StructMember>) {
|
||||||
|
members.push(struct_member(tokens).unwrap());
|
||||||
|
loop {
|
||||||
|
match tokens.peek().expect("Unexpected EOF inside struct declaration") {
|
||||||
|
Token::Comma(_) => {
|
||||||
|
consume!(tokens, Token::Comma);
|
||||||
|
if let Some(member) = struct_member(tokens) {
|
||||||
|
members.push(member);
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn struct_member(tokens : &mut Peekable<Iter<'_, Token>>) -> Option<StructMember> {
|
||||||
|
let name = identifier(tokens);
|
||||||
|
if let Some(name) = name {
|
||||||
|
consume!(tokens, Token::Colon);
|
||||||
|
let type_name = identifier(tokens).expect("Expected Type after Colon");
|
||||||
|
Some(StructMember{name, type_name})
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
fn type_declaration(tokens : &mut Peekable<Iter<'_, Token>>) -> Declaration {
|
||||||
|
consume!(tokens, Token::Type);
|
||||||
|
let name = identifier(tokens).expect("Expected Identifier after `type`");
|
||||||
|
let type_name = identifier(tokens).expect("Expected type after Identifier");
|
||||||
|
Declaration::TypeDeclaration(TypeDeclaration{name, type_name})
|
||||||
|
}
|
||||||
|
fn identifier(tokens : &mut Peekable<Iter<'_, Token>>) -> Option<String> {
|
||||||
|
let result = tokens.peek().map_or(None, |x| match x {
|
||||||
|
Token::Identifier((_, _, s)) => {
|
||||||
|
Some(s.to_string())
|
||||||
|
},
|
||||||
|
_ => None
|
||||||
|
});
|
||||||
|
|
||||||
|
if let Some(_) = result {
|
||||||
|
tokens.next();
|
||||||
|
}
|
||||||
|
result
|
||||||
|
|
||||||
|
}
|
||||||
|
fn parse_number(tokens : &mut Peekable<Iter<'_, Token>>) -> Option<u64> {
|
||||||
|
let result = tokens.peek().map_or(None, |x| match x {
|
||||||
|
Token::Number((_, _, s)) => Some(*s),
|
||||||
|
_ => None
|
||||||
|
});
|
||||||
|
if let Some(_) = result {
|
||||||
|
tokens.next();
|
||||||
|
}
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
fn protocol_declaration(tokens : &mut Peekable<Iter<'_, Token>>) -> Declaration {
|
||||||
|
consume!(tokens, Token::Protocol);
|
||||||
|
let name = identifier(tokens).expect("Expected Identifier after `protocol`");
|
||||||
|
consume!(tokens, Token::LBrace);
|
||||||
|
let mut interface = Vec::new();
|
||||||
|
match tokens.peek().expect("Unexpected EOF after LBrace") {
|
||||||
|
Token::RBrace(_) => {},
|
||||||
|
_ => {
|
||||||
|
functions(tokens, &mut interface);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
Declaration::ProtocolDeclaration(ProtocolDeclaration{name, interface})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn functions(tokens : &mut Peekable<Iter<'_, Token>>, interface : &mut Vec<FuncDeclaration>) {
|
||||||
|
loop {
|
||||||
|
match function(tokens) {
|
||||||
|
Some(x) => interface.push(x),
|
||||||
|
None => break,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn function(tokens : &mut Peekable<Iter<'_, Token>>) -> Option<FuncDeclaration>{
|
||||||
|
if let Some(Token::Fn(_)) = tokens.peek() {
|
||||||
|
consume!(tokens, Token::Fn);
|
||||||
|
let name = identifier(tokens).expect("Expected Identifier after `fn`");
|
||||||
|
consume!(tokens, Token::LParen);
|
||||||
|
let arg_list = arg_list(tokens);
|
||||||
|
consume!(tokens, Token::RParen);
|
||||||
|
consume!(tokens, Token::RArrow);
|
||||||
|
let return_type = identifier(tokens).expect("Expected return type after `->");
|
||||||
|
Some(FuncDeclaration{name, arg_list, return_type})
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn arg_list(tokens : &mut Peekable<Iter<'_, Token>>) -> Vec<String> {
|
||||||
|
let mut result = Vec::new();
|
||||||
|
loop {
|
||||||
|
match identifier(tokens) {
|
||||||
|
None => break,
|
||||||
|
Some(i) =>{
|
||||||
|
result.push(i);
|
||||||
|
if let Token::Comma(_) = **tokens.peek().expect("Unexpected EOF in argument list"){
|
||||||
|
consume!(tokens, Token::Comma);
|
||||||
|
match tokens.peek().expect("Unexpected EOF in argument list") {
|
||||||
|
Token::Identifier(_) => {},
|
||||||
|
_ => panic!("Unexpected symbol after Comma in argument list"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result
|
||||||
|
}
|
|
@ -1,17 +1,167 @@
|
||||||
pub enum ProtocolTypes {
|
use std::collections::HashMap;
|
||||||
Byte,
|
use crate::idl::types::Type;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
pub struct Function{
|
||||||
|
pub arguments : Vec<String>,
|
||||||
|
}
|
||||||
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
pub struct Protocol{
|
||||||
|
interface : HashMap<String, Function>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Protocol {}
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
impl Protocol {
|
pub struct Protocols {
|
||||||
pub fn is_empty(&self) -> bool {
|
protocols : HashMap<String, Protocol>,
|
||||||
true
|
symbol_table : HashMap<String, Type>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
pub enum ValidationError{
|
||||||
|
IncorrectVersion,
|
||||||
|
InvalidHeader,
|
||||||
|
FunctionDoesNotExist,
|
||||||
|
ProtocolDoesNotExist,
|
||||||
|
InvalidSize,
|
||||||
|
InvalidArgument,
|
||||||
|
NonExistentType(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Protocols {
|
||||||
|
pub fn new(symbol_table: HashMap<String, Type>) -> Self {
|
||||||
|
let protocols = HashMap::new();
|
||||||
|
Self { protocols, symbol_table }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn validate_data(&self, data: Vec<u8>) -> bool {
|
pub fn add_protocol(&mut self, name : String, interface : HashMap<String, Function>) {
|
||||||
if !data.is_empty() && self.is_empty() {
|
self.protocols.insert(name, Protocol::new(interface));
|
||||||
return false;
|
}
|
||||||
|
|
||||||
|
pub fn validate(&self, protocol_name : &str, function_name : &str, data : Vec<u8>) -> Result<(), ValidationError>{
|
||||||
|
match self.protocols.get(protocol_name) {
|
||||||
|
Some(s) => s.validate(function_name, data, &self.symbol_table),
|
||||||
|
None => Err(ValidationError::ProtocolDoesNotExist),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
impl Protocol {
|
||||||
|
pub fn new(interface: HashMap<String, Function>) -> Self {
|
||||||
|
Self {interface}
|
||||||
|
}
|
||||||
|
fn validate(&self, function_name : &str, data : Vec<u8>, symbols : &HashMap<String, Type>) -> Result<(), ValidationError> {
|
||||||
|
match self.interface.get(function_name){
|
||||||
|
Some(s) => s.validate(data, symbols),
|
||||||
|
None => Err(ValidationError::FunctionDoesNotExist),
|
||||||
}
|
}
|
||||||
true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Function {
|
||||||
|
fn validate(&self, data : Vec<u8>, symbols : &HashMap<String, Type>) -> Result<(), ValidationError> {
|
||||||
|
let mut types = Vec::new();
|
||||||
|
for arg in self.arguments.iter() {
|
||||||
|
let type_value = symbols.get(arg);
|
||||||
|
if let Some(type_value) = type_value {
|
||||||
|
types.push(type_value);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
return Err(ValidationError::NonExistentType(arg.to_string()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let mut data = data.iter();
|
||||||
|
if let Some(ver) = data.next() {
|
||||||
|
if *ver == 1 {
|
||||||
|
// We got the correct version number
|
||||||
|
// Now to parse individual argumebts
|
||||||
|
let mut types = types.iter().peekable();
|
||||||
|
loop {
|
||||||
|
let type_byte = data.next();
|
||||||
|
if let Some(type_byte) = type_byte {
|
||||||
|
let type_value = types.next();
|
||||||
|
if type_value.is_none() {
|
||||||
|
return Err(ValidationError::InvalidSize);
|
||||||
|
}
|
||||||
|
let type_value = type_value.unwrap();
|
||||||
|
let data_type = match type_byte {
|
||||||
|
0 => Some(Type::U64),
|
||||||
|
1 => Some(Type::U32),
|
||||||
|
2 => Some(Type::U16),
|
||||||
|
3 => Some(Type::U8),
|
||||||
|
4 => Some(Type::I64),
|
||||||
|
5 => Some(Type::I32),
|
||||||
|
6 => Some(Type::I16),
|
||||||
|
7 => Some(Type::I8),
|
||||||
|
8 => Some(Type::Bool),
|
||||||
|
9 => Some(Type::F32),
|
||||||
|
10 => Some(Type::F64),
|
||||||
|
11 => Some(Type::Str),
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
|
if data_type.is_none() || data_type.as_ref().unwrap() != *type_value {
|
||||||
|
println!("{:#?}", *type_value);
|
||||||
|
return Err(ValidationError::InvalidArgument);
|
||||||
|
}
|
||||||
|
|
||||||
|
match data_type.unwrap(){
|
||||||
|
Type::U64 | Type::I64 | Type::F64 => {
|
||||||
|
data.next();
|
||||||
|
data.next();
|
||||||
|
data.next();
|
||||||
|
data.next();
|
||||||
|
data.next();
|
||||||
|
data.next();
|
||||||
|
data.next();
|
||||||
|
data.next();
|
||||||
|
},
|
||||||
|
Type::U32 | Type::I32 | Type::F32 => {
|
||||||
|
data.next();
|
||||||
|
data.next();
|
||||||
|
data.next();
|
||||||
|
data.next();
|
||||||
|
},
|
||||||
|
Type::U16 | Type::I16 => {
|
||||||
|
data.next();
|
||||||
|
data.next();
|
||||||
|
},
|
||||||
|
Type::U8 | Type::I8 | Type::Bool => {
|
||||||
|
data.next();
|
||||||
|
},
|
||||||
|
Type::Str => todo!(),
|
||||||
|
_ => panic!("Should not be possible"),
|
||||||
|
}
|
||||||
|
} else if types.peek().is_none() {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return Err(ValidationError::IncorrectVersion);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return Err(ValidationError::InvalidHeader);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
98
dev/src/idl/types.rs
Normal file
98
dev/src/idl/types.rs
Normal file
|
@ -0,0 +1,98 @@
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use crate::idl::parser::AST;
|
||||||
|
|
||||||
|
use super::protocol::{Function, Protocols};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
pub enum Type {
|
||||||
|
U64,
|
||||||
|
U32,
|
||||||
|
U16,
|
||||||
|
U8,
|
||||||
|
|
||||||
|
I64,
|
||||||
|
I32,
|
||||||
|
I16,
|
||||||
|
I8,
|
||||||
|
|
||||||
|
Bool,
|
||||||
|
|
||||||
|
F32,
|
||||||
|
F64,
|
||||||
|
Str,
|
||||||
|
|
||||||
|
Struct(StructType),
|
||||||
|
Enum(EnumType),
|
||||||
|
Alias(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
pub struct StructType {
|
||||||
|
members : HashMap<String, String>
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
pub struct EnumType {
|
||||||
|
members : HashMap<String, u8>
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn add_builtin_types(symbol_table : &mut HashMap<String, Type>) {
|
||||||
|
symbol_table.insert("u8".to_string(), Type::U8);
|
||||||
|
symbol_table.insert("u16".to_string(), Type::U16);
|
||||||
|
symbol_table.insert("u32".to_string(), Type::U32);
|
||||||
|
symbol_table.insert("u64".to_string(), Type::U64);
|
||||||
|
symbol_table.insert("i8".to_string(), Type::I8);
|
||||||
|
symbol_table.insert("i16".to_string(), Type::I16);
|
||||||
|
symbol_table.insert("i32".to_string(), Type::I32);
|
||||||
|
symbol_table.insert("i64".to_string(), Type::I64);
|
||||||
|
symbol_table.insert("bool".to_string(), Type::Bool);
|
||||||
|
symbol_table.insert("f32".to_string(), Type::F32);
|
||||||
|
symbol_table.insert("f64".to_string(), Type::F64);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_protocols(ast : AST) -> Protocols{
|
||||||
|
let mut symbol_table : HashMap<String, Type> = HashMap::new();
|
||||||
|
let declarations = ast.0;
|
||||||
|
add_builtin_types(&mut symbol_table);
|
||||||
|
// First Pass
|
||||||
|
// We just populate the symbol table here
|
||||||
|
for decl in declarations.iter() {
|
||||||
|
match decl{
|
||||||
|
super::parser::Declaration::EnumDeclaration(e) => {
|
||||||
|
let mut members = HashMap::new();
|
||||||
|
for m in e.members.iter(){
|
||||||
|
members.insert(m.name.to_string(), m.number as u8);
|
||||||
|
}
|
||||||
|
symbol_table.insert(e.name.to_string(), Type::Enum(EnumType{members}));
|
||||||
|
},
|
||||||
|
super::parser::Declaration::StructDeclaration(s) => {
|
||||||
|
let mut members = HashMap::new();
|
||||||
|
for m in s.members.iter() {
|
||||||
|
members.insert(m.name.to_string(), m.type_name.to_string());
|
||||||
|
}
|
||||||
|
symbol_table.insert(s.name.to_string(), Type::Struct(StructType{members}));
|
||||||
|
},
|
||||||
|
super::parser::Declaration::TypeDeclaration(t) => {
|
||||||
|
symbol_table.insert(t.name.to_string(), Type::Alias(t.type_name.to_string()));
|
||||||
|
},
|
||||||
|
super::parser::Declaration::ProtocolDeclaration(_) => {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut protocols = Protocols::new(symbol_table);
|
||||||
|
for decl in declarations.iter(){
|
||||||
|
match decl {
|
||||||
|
super::parser::Declaration::ProtocolDeclaration(p) => {
|
||||||
|
let mut funcs : HashMap<String, Function> = HashMap::new();
|
||||||
|
for i in p.interface.iter(){
|
||||||
|
funcs.insert(i.name.to_string(), Function{arguments : i.arg_list.clone()});
|
||||||
|
}
|
||||||
|
protocols.add_protocol(p.name.to_string(), funcs);
|
||||||
|
},
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
protocols
|
||||||
|
}
|
|
@ -57,7 +57,7 @@ pub fn new(development_type: DevelopmentType, name: String) {
|
||||||
let (folder_hierarchy, entry_name) = match development_type {
|
let (folder_hierarchy, entry_name) = match development_type {
|
||||||
DevelopmentType::Program => ("programs", "main.hb"),
|
DevelopmentType::Program => ("programs", "main.hb"),
|
||||||
DevelopmentType::Library => ("libraries", "lib.hb"),
|
DevelopmentType::Library => ("libraries", "lib.hb"),
|
||||||
DevelopmentType::IDL => ("idl", "protocol.aidl"),
|
DevelopmentType::IDL => ("idl", "protocol.aldi"),
|
||||||
};
|
};
|
||||||
let project_folder_path_string = format!("sysdata/{folder_hierarchy}/{name}");
|
let project_folder_path_string = format!("sysdata/{folder_hierarchy}/{name}");
|
||||||
|
|
||||||
|
@ -72,27 +72,6 @@ pub fn new(development_type: DevelopmentType, name: String) {
|
||||||
let readme_contents = format!("# {}", name);
|
let readme_contents = format!("# {}", name);
|
||||||
readme_file.write_all(readme_contents.as_bytes()).unwrap();
|
readme_file.write_all(readme_contents.as_bytes()).unwrap();
|
||||||
|
|
||||||
let contents = format!(
|
|
||||||
"[package]
|
|
||||||
name = \"{}\"
|
|
||||||
authors = [\"\"]
|
|
||||||
|
|
||||||
[dependants.libraries]
|
|
||||||
|
|
||||||
[dependants.binaries]
|
|
||||||
hblang.version = \"1.0.0\"
|
|
||||||
|
|
||||||
[build]
|
|
||||||
command = \"hblang src/main.hb\"
|
|
||||||
",
|
|
||||||
name
|
|
||||||
);
|
|
||||||
|
|
||||||
let toml_path_string = format!("{}/meta.toml", project_folder_path_string);
|
|
||||||
let mut readme_file = std::fs::File::create(toml_path_string.clone()).unwrap();
|
|
||||||
|
|
||||||
readme_file.write_all(contents.as_bytes()).unwrap();
|
|
||||||
|
|
||||||
let src_folder_path_string = format!("{}/src", project_folder_path_string);
|
let src_folder_path_string = format!("{}/src", project_folder_path_string);
|
||||||
std::fs::create_dir(src_folder_path_string.clone()).unwrap();
|
std::fs::create_dir(src_folder_path_string.clone()).unwrap();
|
||||||
|
|
||||||
|
|
96
flake.lock
96
flake.lock
|
@ -1,96 +0,0 @@
|
||||||
{
|
|
||||||
"nodes": {
|
|
||||||
"flake-utils": {
|
|
||||||
"inputs": {
|
|
||||||
"systems": "systems"
|
|
||||||
},
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1731533236,
|
|
||||||
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
|
|
||||||
"owner": "numtide",
|
|
||||||
"repo": "flake-utils",
|
|
||||||
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "numtide",
|
|
||||||
"repo": "flake-utils",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nixpkgs": {
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1732014248,
|
|
||||||
"narHash": "sha256-y/MEyuJ5oBWrWAic/14LaIr/u5E0wRVzyYsouYY3W6w=",
|
|
||||||
"owner": "NixOS",
|
|
||||||
"repo": "nixpkgs",
|
|
||||||
"rev": "23e89b7da85c3640bbc2173fe04f4bd114342367",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "NixOS",
|
|
||||||
"ref": "nixos-unstable",
|
|
||||||
"repo": "nixpkgs",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nixpkgs_2": {
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1728538411,
|
|
||||||
"narHash": "sha256-f0SBJz1eZ2yOuKUr5CA9BHULGXVSn6miBuUWdTyhUhU=",
|
|
||||||
"owner": "NixOS",
|
|
||||||
"repo": "nixpkgs",
|
|
||||||
"rev": "b69de56fac8c2b6f8fd27f2eca01dcda8e0a4221",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "NixOS",
|
|
||||||
"ref": "nixpkgs-unstable",
|
|
||||||
"repo": "nixpkgs",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"root": {
|
|
||||||
"inputs": {
|
|
||||||
"flake-utils": "flake-utils",
|
|
||||||
"nixpkgs": "nixpkgs",
|
|
||||||
"rust-overlay": "rust-overlay"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"rust-overlay": {
|
|
||||||
"inputs": {
|
|
||||||
"nixpkgs": "nixpkgs_2"
|
|
||||||
},
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1732328983,
|
|
||||||
"narHash": "sha256-RHt12f/slrzDpSL7SSkydh8wUE4Nr4r23HlpWywed9E=",
|
|
||||||
"owner": "oxalica",
|
|
||||||
"repo": "rust-overlay",
|
|
||||||
"rev": "ed8aa5b64f7d36d9338eb1d0a3bb60cf52069a72",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "oxalica",
|
|
||||||
"repo": "rust-overlay",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"systems": {
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1681028828,
|
|
||||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
|
||||||
"owner": "nix-systems",
|
|
||||||
"repo": "default",
|
|
||||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "nix-systems",
|
|
||||||
"repo": "default",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"root": "root",
|
|
||||||
"version": 7
|
|
||||||
}
|
|
30
flake.nix
30
flake.nix
|
@ -1,30 +0,0 @@
|
||||||
{
|
|
||||||
description = "A devShell example";
|
|
||||||
|
|
||||||
inputs = {
|
|
||||||
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
|
||||||
rust-overlay.url = "github:oxalica/rust-overlay";
|
|
||||||
flake-utils.url = "github:numtide/flake-utils";
|
|
||||||
};
|
|
||||||
|
|
||||||
outputs = { self, nixpkgs, rust-overlay, flake-utils }:
|
|
||||||
flake-utils.lib.eachDefaultSystem (system:
|
|
||||||
let
|
|
||||||
overlays = [ (import rust-overlay) ];
|
|
||||||
pkgs = import nixpkgs {
|
|
||||||
inherit system overlays;
|
|
||||||
};
|
|
||||||
|
|
||||||
rustToolchain = pkgs.pkgsBuildHost.rust-bin.fromRustupToolchainFile ./rust-toolchain.toml;
|
|
||||||
in
|
|
||||||
with pkgs;
|
|
||||||
{
|
|
||||||
devShells.default = mkShell {
|
|
||||||
buildInputs = [
|
|
||||||
rustToolchain
|
|
||||||
qemu_full
|
|
||||||
];
|
|
||||||
};
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
|
@ -4,3 +4,6 @@ build-std-features = ["compiler-builtins-mem"]
|
||||||
|
|
||||||
[build]
|
[build]
|
||||||
target = "./targets/x86_64-ableos.json"
|
target = "./targets/x86_64-ableos.json"
|
||||||
|
|
||||||
|
[target.'cfg(target_arch = "x86_64")']
|
||||||
|
rustflags = ["-C", "target-feature=+rdrand"]
|
||||||
|
|
|
@ -3,54 +3,57 @@ edition = "2021"
|
||||||
name = "kernel"
|
name = "kernel"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
|
|
||||||
[features]
|
|
||||||
ktest = []
|
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
# embedded-graphics = "0.8"
|
embedded-graphics = "0.7"
|
||||||
hbvm = { git = "https://git.ablecorp.us/AbleOS/holey-bytes.git", features = [
|
hbvm.git = "https://git.ablecorp.us/ableos/holey-bytes"
|
||||||
"nightly",
|
|
||||||
] }
|
|
||||||
ktest_macro = { path = "ktest_macro" }
|
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
spin = "0.9"
|
spin = "0.9"
|
||||||
|
uart_16550 = "0.2"
|
||||||
slab = { version = "0.4", default-features = false }
|
slab = { version = "0.4", default-features = false }
|
||||||
uart_16550 = { version = "0.3", features = ["nightly"] }
|
|
||||||
xml.git = "https://git.ablecorp.us/ableos/ableos_userland"
|
xml.git = "https://git.ablecorp.us/ableos/ableos_userland"
|
||||||
versioning.git = "https://git.ablecorp.us/ableos/ableos_userland"
|
versioning.git = "https://git.ablecorp.us/ableos/ableos_userland"
|
||||||
# able_graphics_library.git = "https://git.ablecorp.us/ableos/ableos_userland"
|
able_graphics_library.git = "https://git.ablecorp.us/ableos/ableos_userland"
|
||||||
hashbrown = { version = "0.15", features = ["nightly"] }
|
hashbrown = "*"
|
||||||
limine = "0.1"
|
kiam = "0.1.1"
|
||||||
|
|
||||||
|
[dependencies.limine]
|
||||||
|
version = "0.1"
|
||||||
|
git = "https://github.com/limine-bootloader/limine-rs"
|
||||||
|
|
||||||
[dependencies.crossbeam-queue]
|
[dependencies.crossbeam-queue]
|
||||||
version = "0.3"
|
version = "0.3"
|
||||||
default-features = false
|
default-features = false
|
||||||
features = ["alloc", "nightly"]
|
features = ["alloc"]
|
||||||
|
|
||||||
|
[dependencies.clparse]
|
||||||
|
git = "https://git.ablecorp.us/ableos/ableos_userland"
|
||||||
|
default-features = false
|
||||||
|
|
||||||
[dependencies.derive_more]
|
[dependencies.derive_more]
|
||||||
version = "1"
|
version = "0.99"
|
||||||
default-features = false
|
default-features = false
|
||||||
features = [
|
features = [
|
||||||
"add",
|
"add",
|
||||||
"add_assign",
|
"add_assign",
|
||||||
"constructor",
|
"constructor",
|
||||||
"display",
|
"display",
|
||||||
"from",
|
"from",
|
||||||
"into",
|
"into",
|
||||||
"mul",
|
"mul",
|
||||||
"mul_assign",
|
"mul_assign",
|
||||||
"not",
|
"not",
|
||||||
"sum",
|
"sum",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
[target.'cfg(target_arch = "x86_64")'.dependencies]
|
[target.'cfg(target_arch = "x86_64")'.dependencies]
|
||||||
x86_64 = "0.15"
|
x86_64 = "0.14"
|
||||||
x2apic = "0.4"
|
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]
|
[target.'cfg(target_arch = "riscv64")'.dependencies]
|
||||||
sbi = "0.2.0"
|
sbi = "0.2.0"
|
||||||
|
|
||||||
[target.'cfg(target_arch = "aarch64")'.dependencies]
|
|
||||||
aarch64-cpu = "9"
|
|
||||||
|
|
|
@ -1,11 +0,0 @@
|
||||||
[package]
|
|
||||||
edition = "2021"
|
|
||||||
name = "ktest_macro"
|
|
||||||
version = "0.1.0"
|
|
||||||
|
|
||||||
[lib]
|
|
||||||
proc-macro = true
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
quote = "1.0.37"
|
|
||||||
syn = { version = "2.0.89", features = ["full"] }
|
|
|
@ -1,86 +0,0 @@
|
||||||
extern crate proc_macro;
|
|
||||||
extern crate quote;
|
|
||||||
extern crate syn;
|
|
||||||
|
|
||||||
use {
|
|
||||||
proc_macro::TokenStream,
|
|
||||||
quote::quote,
|
|
||||||
syn::{parse::Parse, parse_macro_input, Expr, ItemFn, Token}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct KtestInput {
|
|
||||||
lhs: Expr,
|
|
||||||
_comma: Token![,],
|
|
||||||
rhs: Expr,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Parse for KtestInput {
|
|
||||||
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
|
|
||||||
Ok(Self {
|
|
||||||
lhs: input.parse()?,
|
|
||||||
_comma: input.parse()?,
|
|
||||||
rhs: input.parse()?,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[proc_macro]
|
|
||||||
pub fn ktest_eq(item: TokenStream) -> TokenStream {
|
|
||||||
let input = parse_macro_input!(item as KtestInput);
|
|
||||||
|
|
||||||
let lhs = input.lhs;
|
|
||||||
let rhs = input.rhs;
|
|
||||||
|
|
||||||
let out = quote! {
|
|
||||||
if #lhs != #rhs {
|
|
||||||
return Err(name);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
TokenStream::from(out)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[proc_macro]
|
|
||||||
pub fn ktest_neq(item: TokenStream) -> TokenStream {
|
|
||||||
let input = parse_macro_input!(item as KtestInput);
|
|
||||||
|
|
||||||
let lhs = input.lhs;
|
|
||||||
let rhs = input.rhs;
|
|
||||||
|
|
||||||
let out = quote! {
|
|
||||||
if #lhs == #rhs {
|
|
||||||
return Err(name);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
TokenStream::from(out)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[proc_macro_attribute]
|
|
||||||
pub fn ktest(_attr: TokenStream, item: TokenStream) -> TokenStream {
|
|
||||||
let input = parse_macro_input!(item as ItemFn);
|
|
||||||
let test_name = &input.sig.ident;
|
|
||||||
let test_string = test_name.to_string();
|
|
||||||
let static_var_name = syn::Ident::new(
|
|
||||||
&format!("__ktest_{}", test_name).to_uppercase(),
|
|
||||||
test_name.span(),
|
|
||||||
);
|
|
||||||
|
|
||||||
let block = &input.block;
|
|
||||||
let out = quote! {
|
|
||||||
#[cfg(feature = "ktest")]
|
|
||||||
fn #test_name() -> Result<String, String> {
|
|
||||||
use crate::alloc::string::ToString;
|
|
||||||
let name = #test_string.to_string();
|
|
||||||
|
|
||||||
#block
|
|
||||||
|
|
||||||
return Ok(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "ktest")]
|
|
||||||
#[unsafe(link_section = ".note.ktest")]
|
|
||||||
#[used]
|
|
||||||
pub static #static_var_name: fn() -> Result<String, String> = #test_name;
|
|
||||||
};
|
|
||||||
|
|
||||||
TokenStream::from(out)
|
|
||||||
}
|
|
|
@ -6,11 +6,6 @@ SECTIONS
|
||||||
.text.boot : { *(.text.boot) }
|
.text.boot : { *(.text.boot) }
|
||||||
.text : { *(.text) }
|
.text : { *(.text) }
|
||||||
.data : { *(.data) }
|
.data : { *(.data) }
|
||||||
.note.ktest : {
|
|
||||||
__ktest_start = .;
|
|
||||||
*(.note.ktest)
|
|
||||||
__ktest_end = .;
|
|
||||||
}
|
|
||||||
.rodata : { *(.rodata) }
|
.rodata : { *(.rodata) }
|
||||||
.bss : {
|
.bss : {
|
||||||
*(COMMON)
|
*(COMMON)
|
||||||
|
|
|
@ -38,16 +38,8 @@ SECTIONS
|
||||||
|
|
||||||
.data : {
|
.data : {
|
||||||
*(.data .data.*)
|
*(.data .data.*)
|
||||||
*(.got .got.*)
|
|
||||||
} :data
|
} :data
|
||||||
|
|
||||||
/* Add the .ktest section for test functions */
|
|
||||||
.note.ktest : {
|
|
||||||
__ktest_start = .; /* Mark the beginning of the section */
|
|
||||||
*(.note.ktest) /* Include all items in the .ktest section */
|
|
||||||
__ktest_end = .; /* Mark the end of the section */
|
|
||||||
}
|
|
||||||
|
|
||||||
.bss : {
|
.bss : {
|
||||||
*(COMMON)
|
*(COMMON)
|
||||||
*(.bss .bss.*)
|
*(.bss .bss.*)
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use {
|
use {
|
||||||
crate::{device_tree::DeviceTree, kmain::DEVICE_TREE},
|
crate::{alloc::string::ToString, device_tree::DeviceTree, kmain::DEVICE_TREE},
|
||||||
|
alloc::string::String,
|
||||||
core::arch::asm,
|
core::arch::asm,
|
||||||
xml::XMLElement,
|
xml::XMLElement,
|
||||||
};
|
};
|
||||||
|
@ -27,8 +28,8 @@ fn collect_cpu_info(device_tree: &mut DeviceTree) {
|
||||||
cpus.push(cpu);
|
cpus.push(cpu);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cpu_id<'a>() -> (&'a str, u64) {
|
fn cpu_id() -> (String, u64) {
|
||||||
let mut cpu_id: u64;
|
let mut cpu_id: u64 = 0;
|
||||||
unsafe {
|
unsafe {
|
||||||
asm!("mrs {cpu_id}, MIDR_EL1",
|
asm!("mrs {cpu_id}, MIDR_EL1",
|
||||||
cpu_id = out(reg) cpu_id,
|
cpu_id = out(reg) cpu_id,
|
||||||
|
@ -38,11 +39,9 @@ fn cpu_id<'a>() -> (&'a str, u64) {
|
||||||
let cpu_name = match cpu_id {
|
let cpu_name = match cpu_id {
|
||||||
// the source of these two was a stackoverflow question
|
// the source of these two was a stackoverflow question
|
||||||
// https://raspberrypi.stackexchange.com/questions/117175/how-do-i-read-the-cpuid-in-aarch64-asm
|
// https://raspberrypi.stackexchange.com/questions/117175/how-do-i-read-the-cpuid-in-aarch64-asm
|
||||||
0x410FD034 => "Cortex-A53",
|
0x410FD034 => "Cortex-A53".to_string(),
|
||||||
0x410FD083 => "Cortex-A72",
|
0x410FD083 => "Cortex-A72".to_string(),
|
||||||
// the source of this one was checking the cpu id :thinking:
|
_ => "Unknown".to_string(),
|
||||||
0x410FD493 => "Neoverse N2",
|
|
||||||
_ => "Unknown",
|
|
||||||
};
|
};
|
||||||
log::trace!("CPU Name: {cpu_name} - CPU ID: 0x{:X}", cpu_id);
|
log::trace!("CPU Name: {cpu_name} - CPU ID: 0x{:X}", cpu_id);
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
use {crate::logger::TERMINAL_LOGGER, core::fmt::Write, spin::Mutex};
|
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,
|
uart: 0x09000000 as *mut u8,
|
||||||
});
|
});
|
||||||
|
|
||||||
pub struct SerialConsole {
|
struct SerialConsole {
|
||||||
uart: *mut u8,
|
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 {
|
pub fn log(args: core::fmt::Arguments<'_>) -> core::fmt::Result {
|
||||||
SERIAL_CONSOLE.lock().write_fmt(args)?;
|
SERIAL_CONSOLE.lock().write_fmt(args)?;
|
||||||
// TERMINAL_LOGGER.lock().write_fmt(args)?;
|
TERMINAL_LOGGER.lock().write_fmt(args)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
pub use logging::log;
|
pub use logging::log;
|
||||||
use {
|
use {
|
||||||
crate::{allocator, bootmodules::BootModule, kmain::kmain},
|
crate::{allocator, bootmodules::BootModule, kmain::kmain},
|
||||||
alloc::vec::Vec,
|
|
||||||
core::arch::asm,
|
core::arch::asm,
|
||||||
limine::FramebufferRequest,
|
limine::FramebufferRequest,
|
||||||
};
|
};
|
||||||
|
@ -42,7 +41,7 @@ unsafe extern "C" fn _kernel_start() -> ! {
|
||||||
static KFILE_REQ: KernelFileRequest = KernelFileRequest::new(0);
|
static KFILE_REQ: KernelFileRequest = KernelFileRequest::new(0);
|
||||||
static MOD_REQ: ModuleRequest = ModuleRequest::new(0);
|
static MOD_REQ: ModuleRequest = ModuleRequest::new(0);
|
||||||
|
|
||||||
let mut bootmodules = Vec::new();
|
let mut bootmodules = alloc::vec::Vec::new();
|
||||||
|
|
||||||
if bm.is_some() {
|
if bm.is_some() {
|
||||||
let bm = bm.unwrap();
|
let bm = bm.unwrap();
|
||||||
|
@ -53,13 +52,18 @@ unsafe extern "C" fn _kernel_start() -> ! {
|
||||||
let raw_bytes = core::slice::from_raw_parts(
|
let raw_bytes = core::slice::from_raw_parts(
|
||||||
file.base.as_ptr().expect("invalid initrd"),
|
file.base.as_ptr().expect("invalid initrd"),
|
||||||
file.length as usize,
|
file.length as usize,
|
||||||
);
|
)
|
||||||
|
.to_vec();
|
||||||
|
|
||||||
let file_path = 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() {
|
if file_path.is_err() {
|
||||||
panic!("invalid file path: {:?}", file_path);
|
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() {
|
if file_cmd.is_err() {
|
||||||
panic!("invalid module cmd: {:?}", file_cmd);
|
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);
|
assert_eq!(bm.module_count, bootmodules.len() as u64);
|
||||||
}
|
}
|
||||||
|
|
||||||
kmain(
|
crate::kmain::kmain(
|
||||||
KFILE_REQ
|
KFILE_REQ
|
||||||
.get_response()
|
.get_response()
|
||||||
.get()
|
.get()
|
||||||
|
@ -95,6 +99,8 @@ unsafe extern "C" fn _kernel_start() -> ! {
|
||||||
.unwrap_or_default(),
|
.unwrap_or_default(),
|
||||||
bootmodules,
|
bootmodules,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
spin_loop();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn 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 {
|
pub fn hardware_random_u64() -> u64 {
|
||||||
if let Some(rng) = aarch64_cpu::asm::random::ArmRng::new() {
|
0
|
||||||
if let Some(rnd) = rng.rndr() {
|
|
||||||
return rnd;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
unsafe {
|
|
||||||
A_REAL_RANDOM_U64_I_PROMISE += 1;
|
|
||||||
A_REAL_RANDOM_U64_I_PROMISE
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn register_dump() {}
|
pub fn register_dump() {}
|
||||||
|
|
|
@ -14,29 +14,3 @@ arch_cond!(
|
||||||
riscv64: "riscv64",
|
riscv64: "riscv64",
|
||||||
x86_64: "x86_64",
|
x86_64: "x86_64",
|
||||||
);
|
);
|
||||||
|
|
||||||
#[cfg(target_arch = "x86_64")]
|
|
||||||
use {crate::arch::interrupts::Interrupt, alloc::string::String};
|
|
||||||
#[cfg(target_arch = "x86_64")]
|
|
||||||
pub struct InterruptList {
|
|
||||||
list: HashMap<Interrupt, String>,
|
|
||||||
}
|
|
||||||
#[cfg(target_arch = "x86_64")]
|
|
||||||
use hashbrown::HashMap;
|
|
||||||
#[cfg(target_arch = "x86_64")]
|
|
||||||
impl InterruptList {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Self {
|
|
||||||
list: HashMap::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#[cfg(target_arch = "x86_64")]
|
|
||||||
use spin::{Lazy, Mutex};
|
|
||||||
#[cfg(target_arch = "x86_64")]
|
|
||||||
pub static INTERRUPT_LIST: Lazy<Mutex<InterruptList>> = Lazy::new(|| {
|
|
||||||
let mut il = InterruptList::new();
|
|
||||||
use crate::alloc::string::ToString;
|
|
||||||
il.list.insert(Interrupt::Timer, "PS/2 Mouse".to_string());
|
|
||||||
Mutex::new(il)
|
|
||||||
});
|
|
||||||
|
|
|
@ -1,10 +1,8 @@
|
||||||
use core::num;
|
use core::num;
|
||||||
|
|
||||||
use {
|
use alloc::boxed::Box;
|
||||||
crate::memory::{MemoryManager, PhysicalAddress, VirtualAddress},
|
use spin::{Mutex, Once};
|
||||||
alloc::boxed::Box,
|
use crate::memory::{MemoryManager, PhysicalAddress, VirtualAddress};
|
||||||
spin::{Mutex, Once},
|
|
||||||
};
|
|
||||||
|
|
||||||
use super::PAGE_SIZE;
|
use super::PAGE_SIZE;
|
||||||
|
|
||||||
|
@ -30,7 +28,7 @@ impl PageSize {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct PageTable {
|
pub struct PageTable {
|
||||||
entries: [PageEntry; 512],
|
entries: [PageEntry; 512]
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PageTable {
|
impl PageTable {
|
||||||
|
@ -74,14 +72,8 @@ impl PageTable {
|
||||||
/// flags MUST include one or more of the following:
|
/// flags MUST include one or more of the following:
|
||||||
/// Read, Write, Execute
|
/// Read, Write, Execute
|
||||||
/// The valid bit automatically gets added
|
/// The valid bit automatically gets added
|
||||||
pub fn map(
|
pub fn map(&mut self, vaddr: VirtualAddress, paddr: PhysicalAddress, flags: PageEntryFlags, page_size: PageSize) {
|
||||||
&mut self,
|
assert!(flags as usize & 0xe != 0);
|
||||||
vaddr: VirtualAddress,
|
|
||||||
paddr: PhysicalAddress,
|
|
||||||
flags: PageEntryFlags,
|
|
||||||
page_size: PageSize,
|
|
||||||
) {
|
|
||||||
assert!(flags as usize & 0xE != 0);
|
|
||||||
|
|
||||||
let vpn = vaddr.vpns();
|
let vpn = vaddr.vpns();
|
||||||
let ppn = paddr.ppns();
|
let ppn = paddr.ppns();
|
||||||
|
@ -99,7 +91,7 @@ impl PageTable {
|
||||||
}
|
}
|
||||||
|
|
||||||
let entry = v.addr().as_mut_ptr::<PageEntry>();
|
let entry = v.addr().as_mut_ptr::<PageEntry>();
|
||||||
v = unsafe { entry.add(vpn[i]).as_mut().unwrap() };
|
v = unsafe { entry.add(vpn[i]).as_mut().unwrap() };
|
||||||
}
|
}
|
||||||
|
|
||||||
// When we get here, we should be at VPN[0] and v should be pointing to our entry.
|
// When we get here, we should be at VPN[0] and v should be pointing to our entry.
|
||||||
|
@ -113,24 +105,14 @@ impl PageTable {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Identity maps a page of memory
|
/// Identity maps a page of memory
|
||||||
pub fn identity_map(
|
pub fn identity_map(&mut self, addr: PhysicalAddress, flags: PageEntryFlags, page_size: PageSize) {
|
||||||
&mut self,
|
|
||||||
addr: PhysicalAddress,
|
|
||||||
flags: PageEntryFlags,
|
|
||||||
page_size: PageSize,
|
|
||||||
) {
|
|
||||||
// log::debug!("identity mapped {addr}");
|
// log::debug!("identity mapped {addr}");
|
||||||
self.map(addr.as_addr().into(), addr, flags, page_size);
|
self.map(addr.as_addr().into(), addr, flags, page_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Identity maps a range of contiguous memory
|
/// Identity maps a range of contiguous memory
|
||||||
/// This assumes that start <= end
|
/// This assumes that start <= end
|
||||||
pub fn identity_map_range(
|
pub fn identity_map_range(&mut self, start: PhysicalAddress, end: PhysicalAddress, flags: PageEntryFlags) {
|
||||||
&mut self,
|
|
||||||
start: PhysicalAddress,
|
|
||||||
end: PhysicalAddress,
|
|
||||||
flags: PageEntryFlags,
|
|
||||||
) {
|
|
||||||
log::debug!("start: {start}, end: {end}");
|
log::debug!("start: {start}, end: {end}");
|
||||||
let mut mem_addr = start.as_addr() & !(PAGE_SIZE - 1);
|
let mut mem_addr = start.as_addr() & !(PAGE_SIZE - 1);
|
||||||
let num_pages = (align_val(end.as_addr(), 12) - mem_addr - 1) / PAGE_SIZE + 1;
|
let num_pages = (align_val(end.as_addr(), 12) - mem_addr - 1) / PAGE_SIZE + 1;
|
||||||
|
@ -160,7 +142,7 @@ impl PageTable {
|
||||||
}
|
}
|
||||||
|
|
||||||
let entry = v.addr().as_mut_ptr::<PageEntry>();
|
let entry = v.addr().as_mut_ptr::<PageEntry>();
|
||||||
v = unsafe { entry.add(vpn[i]).as_mut().unwrap() };
|
v = unsafe { entry.add(vpn[i]).as_mut().unwrap() };
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we're here this is an unmapped page
|
// If we're here this is an unmapped page
|
||||||
|
@ -246,7 +228,7 @@ impl PageEntry {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn addr(&self) -> PhysicalAddress {
|
fn addr(&self) -> PhysicalAddress {
|
||||||
((self.entry() as usize & !0x3FF) << 2).into()
|
((self.entry() as usize & !0x3ff) << 2).into()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn destroy(&mut self) {
|
fn destroy(&mut self) {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
mod memory;
|
mod memory;
|
||||||
|
|
||||||
use {
|
use {
|
||||||
alloc::{boxed::Box, vec::Vec},
|
alloc::boxed::Box,
|
||||||
core::{
|
core::{
|
||||||
arch::{asm, global_asm},
|
arch::{asm, global_asm},
|
||||||
fmt::Write,
|
fmt::Write,
|
||||||
|
@ -45,7 +45,7 @@ extern "C" {
|
||||||
static USABLE_MEMORY_SIZE: usize;
|
static USABLE_MEMORY_SIZE: usize;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub static SERIAL_CONSOLE: Once<Mutex<MmioSerialPort>> = Once::new();
|
static SERIAL_CONSOLE: Once<Mutex<MmioSerialPort>> = Once::new();
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
unsafe extern "C" fn _kernel_start() -> ! {
|
unsafe extern "C" fn _kernel_start() -> ! {
|
||||||
|
@ -95,7 +95,7 @@ unsafe extern "C" fn _kernel_start() -> ! {
|
||||||
in(reg) satp_value,
|
in(reg) satp_value,
|
||||||
);
|
);
|
||||||
|
|
||||||
crate::kmain::kmain("baka=9", Vec::new());
|
crate::kmain::kmain("baka=9", None);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Spin loop
|
/// 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 {
|
pub fn log(args: core::fmt::Arguments<'_>) -> core::fmt::Result {
|
||||||
SERIAL_CONSOLE.get().unwrap().lock().write_fmt(args)
|
SERIAL_CONSOLE.get().unwrap().lock().write_fmt(args)
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,9 +11,6 @@ use {
|
||||||
|
|
||||||
pub const DOUBLE_FAULT_IX: u16 = 0;
|
pub const DOUBLE_FAULT_IX: u16 = 0;
|
||||||
|
|
||||||
const STACK_SIZE: usize = 5 * 1024;
|
|
||||||
const STACK_ALIGNMENT: usize = 1;
|
|
||||||
|
|
||||||
pub unsafe fn init() {
|
pub unsafe fn init() {
|
||||||
use x86_64::instructions::{
|
use x86_64::instructions::{
|
||||||
segmentation::{Segment, CS, SS},
|
segmentation::{Segment, CS, SS},
|
||||||
|
@ -35,24 +32,24 @@ struct Selectors {
|
||||||
|
|
||||||
static TSS: Lazy<TaskStateSegment> = Lazy::new(|| {
|
static TSS: Lazy<TaskStateSegment> = Lazy::new(|| {
|
||||||
let mut tss = TaskStateSegment::new();
|
let mut tss = TaskStateSegment::new();
|
||||||
|
tss.interrupt_stack_table[usize::from(DOUBLE_FAULT_IX)] = {
|
||||||
let stack_ptr = unsafe {
|
const SIZE: usize = 5 * 1024;
|
||||||
let layout = alloc::alloc::Layout::from_size_align(STACK_SIZE, STACK_ALIGNMENT)
|
let stack = unsafe {
|
||||||
.expect("Failed to create stack layout");
|
alloc::alloc::alloc_zeroed(
|
||||||
let stack = alloc::alloc::alloc(layout);
|
alloc::alloc::Layout::from_size_align(SIZE, 1).expect("stack pointer"),
|
||||||
VirtAddr::from_ptr(stack) + STACK_SIZE as u64
|
)
|
||||||
|
};
|
||||||
|
VirtAddr::from_ptr(stack) + SIZE
|
||||||
};
|
};
|
||||||
|
|
||||||
tss.interrupt_stack_table[usize::from(DOUBLE_FAULT_IX)] = stack_ptr;
|
|
||||||
tss
|
tss
|
||||||
});
|
});
|
||||||
|
|
||||||
static GDT: Lazy<(GlobalDescriptorTable, Selectors)> = Lazy::new(|| {
|
static GDT: Lazy<(GlobalDescriptorTable, Selectors)> = Lazy::new(|| {
|
||||||
let mut gdt = GlobalDescriptorTable::new();
|
let mut gdt = GlobalDescriptorTable::new();
|
||||||
let sels = Selectors {
|
let sels = Selectors {
|
||||||
kcode: gdt.append(Descriptor::kernel_code_segment()),
|
kcode: gdt.add_entry(Descriptor::kernel_code_segment()),
|
||||||
kdata: gdt.append(Descriptor::kernel_data_segment()),
|
kdata: gdt.add_entry(Descriptor::kernel_data_segment()),
|
||||||
tss: gdt.append(Descriptor::tss_segment(&TSS)),
|
tss: gdt.add_entry(Descriptor::tss_segment(&TSS)),
|
||||||
};
|
};
|
||||||
(gdt, sels)
|
(gdt, sels)
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,54 +1,56 @@
|
||||||
|
// TODO: Turn apic keyboard interrupt into a standard ipc message
|
||||||
use {
|
use {
|
||||||
core::mem::MaybeUninit,
|
|
||||||
log::trace,
|
log::trace,
|
||||||
|
spin::{Lazy, Mutex},
|
||||||
x2apic::lapic::{LocalApic, LocalApicBuilder},
|
x2apic::lapic::{LocalApic, LocalApicBuilder},
|
||||||
x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame, PageFaultErrorCode},
|
x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame, PageFaultErrorCode},
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Safety: Using LAPIC or IDT before init() is UB
|
pub unsafe fn init() {
|
||||||
/// Using
|
trace!("Initialising IDT");
|
||||||
static mut LAPIC: LocalApic = unsafe { MaybeUninit::zeroed().assume_init() };
|
IDT.load();
|
||||||
static mut IDT: InterruptDescriptorTable = unsafe { MaybeUninit::zeroed().assume_init() };
|
Lazy::force(&LAPIC);
|
||||||
|
x86_64::instructions::interrupts::enable();
|
||||||
|
}
|
||||||
|
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
#[derive(Debug, Eq, Hash, PartialEq)]
|
enum Interrupt {
|
||||||
|
|
||||||
pub enum Interrupt {
|
|
||||||
Timer = 32,
|
Timer = 32,
|
||||||
|
|
||||||
ApicErr = u8::MAX - 1,
|
ApicErr = u8::MAX - 1,
|
||||||
Spurious = u8::MAX,
|
Spurious = u8::MAX,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn init() {
|
pub(crate) static LAPIC: Lazy<Mutex<LocalApic>> = Lazy::new(|| {
|
||||||
trace!("Initializing IDT and LAPIC");
|
let mut lapic = LocalApicBuilder::new()
|
||||||
|
|
||||||
// Initialize and load the IDT
|
|
||||||
IDT = InterruptDescriptorTable::new();
|
|
||||||
IDT.double_fault
|
|
||||||
.set_handler_fn(double_fault)
|
|
||||||
.set_stack_index(super::gdt::DOUBLE_FAULT_IX);
|
|
||||||
IDT.page_fault.set_handler_fn(page_fault);
|
|
||||||
|
|
||||||
IDT[Interrupt::ApicErr as u8].set_handler_fn(apic_err);
|
|
||||||
IDT[Interrupt::Spurious as u8].set_handler_fn(spurious);
|
|
||||||
IDT[Interrupt::Timer as u8].set_handler_fn(timer);
|
|
||||||
|
|
||||||
IDT.load();
|
|
||||||
|
|
||||||
LAPIC = LocalApicBuilder::new()
|
|
||||||
.timer_vector(Interrupt::Timer as usize)
|
.timer_vector(Interrupt::Timer as usize)
|
||||||
.error_vector(Interrupt::ApicErr as usize)
|
.error_vector(Interrupt::ApicErr as usize)
|
||||||
.spurious_vector(Interrupt::Spurious as usize)
|
.spurious_vector(Interrupt::Spurious as usize)
|
||||||
.set_xapic_base(
|
.set_xapic_base(
|
||||||
x2apic::lapic::xapic_base()
|
unsafe { x2apic::lapic::xapic_base() }
|
||||||
+ super::memory::HHDM_OFFSET.load(core::sync::atomic::Ordering::Relaxed),
|
+ super::memory::HHDM_OFFSET.load(core::sync::atomic::Ordering::Relaxed),
|
||||||
)
|
)
|
||||||
.build()
|
.build()
|
||||||
.expect("Failed to setup Local APIC");
|
.expect("failed to setup Local APIC");
|
||||||
LAPIC.enable();
|
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) -> ! {
|
extern "x86-interrupt" fn double_fault(stack_frame: InterruptStackFrame, error_code: u64) -> ! {
|
||||||
panic!("Double fault: error code {error_code} \n{stack_frame:#?}")
|
panic!("Double fault: error code {error_code} \n{stack_frame:#?}")
|
||||||
|
@ -62,52 +64,13 @@ extern "x86-interrupt" fn page_fault(
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "x86-interrupt" fn timer(_isf: InterruptStackFrame) {
|
extern "x86-interrupt" fn timer(_isf: InterruptStackFrame) {
|
||||||
interrupt(Interrupt::Timer);
|
unsafe { LAPIC.lock().end_of_interrupt() };
|
||||||
|
|
||||||
unsafe {
|
|
||||||
LAPIC.end_of_interrupt();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "x86-interrupt" fn apic_err(_: InterruptStackFrame) {
|
extern "x86-interrupt" fn apic_err(_: InterruptStackFrame) {
|
||||||
interrupt(Interrupt::ApicErr);
|
|
||||||
|
|
||||||
panic!("Internal APIC error");
|
panic!("Internal APIC error");
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "x86-interrupt" fn spurious(_: InterruptStackFrame) {
|
extern "x86-interrupt" fn spurious(_: InterruptStackFrame) {
|
||||||
interrupt(Interrupt::Spurious);
|
unsafe { LAPIC.lock().end_of_interrupt() };
|
||||||
|
|
||||||
unsafe {
|
|
||||||
LAPIC.end_of_interrupt();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(unused_imports)]
|
|
||||||
fn interrupt(interrupt_type: Interrupt) {
|
|
||||||
use crate::{arch::INTERRUPT_LIST, kmain::EXECUTOR};
|
|
||||||
// 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)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
EXECUTOR.send_interrupt(interrupt_type as u8);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,11 @@
|
||||||
//! Logging (as in terms of console / serial output)
|
//! Logging (as in terms of console / serial output)
|
||||||
#![allow(deprecated)]
|
#![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) });
|
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, embedded_graphics::pixelcolor::Rgb888,
|
||||||
use {crate::bootmodules::BootModule, core::arch::asm, log::warn};
|
log::warn, rdrand::RdSeed,
|
||||||
|
};
|
||||||
pub mod memory;
|
pub mod memory;
|
||||||
|
|
||||||
mod cpuid;
|
mod cpuid;
|
||||||
|
@ -10,7 +11,7 @@ pub mod graphics;
|
||||||
pub(crate) mod interrupts;
|
pub(crate) mod interrupts;
|
||||||
pub mod logging;
|
pub mod logging;
|
||||||
pub mod pci;
|
pub mod pci;
|
||||||
// pub mod virtio;
|
pub mod virtio;
|
||||||
|
|
||||||
pub use {logging::log, memory::PAGE_SIZE};
|
pub use {logging::log, memory::PAGE_SIZE};
|
||||||
|
|
||||||
|
@ -30,11 +31,9 @@ const INITIAL_KERNEL_HEAP_SIZE: *const () = _initial_kernel_heap_size as _;
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
#[naked]
|
#[naked]
|
||||||
#[cfg(not(target_feature = "avx2"))]
|
|
||||||
unsafe extern "C" fn _kernel_start() -> ! {
|
unsafe extern "C" fn _kernel_start() -> ! {
|
||||||
// Initialise SSE, then jump to kernel entrypoint
|
// Initialise SSE and jump to kernel entrypoint
|
||||||
core::arch::naked_asm!(
|
core::arch::asm!(
|
||||||
// Initialise SSE
|
|
||||||
"mov rax, cr0",
|
"mov rax, cr0",
|
||||||
"and ax, 0xfffb",
|
"and ax, 0xfffb",
|
||||||
"or ax, 0x2",
|
"or ax, 0x2",
|
||||||
|
@ -42,74 +41,16 @@ unsafe extern "C" fn _kernel_start() -> ! {
|
||||||
"mov rax, cr4",
|
"mov rax, cr4",
|
||||||
"or ax, 3 << 9",
|
"or ax, 3 << 9",
|
||||||
"mov cr4, rax",
|
"mov cr4, rax",
|
||||||
|
|
||||||
// Jump to the kernel entry point
|
|
||||||
"jmp {}",
|
"jmp {}",
|
||||||
sym start,
|
sym start,
|
||||||
|
options(noreturn),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
#[naked]
|
|
||||||
#[cfg(target_feature = "avx2")]
|
|
||||||
unsafe extern "C" fn _kernel_start() -> ! {
|
|
||||||
core::arch::naked_asm!(
|
|
||||||
// Enable protected mode and configure control registers
|
|
||||||
"mov rax, cr0",
|
|
||||||
"and ax, 0xFFFB", // Clear CR0.EM (bit 2) for coprocessor emulation
|
|
||||||
"or ax, 0x2", // Set CR0.MP (bit 1) for coprocessor monitoring
|
|
||||||
"mov cr0, rax",
|
|
||||||
|
|
||||||
"mov rax, cr4",
|
|
||||||
"or ax, (1 << 9) | (1 << 10)", // Set CR4.OSFXSR (bit 9) and CR4.OSXMMEXCPT (bit 10)
|
|
||||||
"mov cr4, rax",
|
|
||||||
|
|
||||||
// Enable OSXSAVE (required for AVX, AVX2, and XSAVE)
|
|
||||||
"mov rax, cr4",
|
|
||||||
"or eax, 1 << 18", // Set CR4.OSXSAVE (bit 18)
|
|
||||||
"mov cr4, rax",
|
|
||||||
|
|
||||||
// Enable AVX and AVX2 state saving
|
|
||||||
"xor rcx, rcx",
|
|
||||||
"xgetbv",
|
|
||||||
"or eax, 7", // Enable SSE, AVX, and AVX2 state saving
|
|
||||||
"xsetbv",
|
|
||||||
|
|
||||||
// Check for AVX and XSAVE support
|
|
||||||
"mov eax, 1",
|
|
||||||
"cpuid",
|
|
||||||
"and ecx, 0x18000000",
|
|
||||||
"cmp ecx, 0x18000000",
|
|
||||||
"jne {1}", // Jump if AVX/OSXSAVE is not supported
|
|
||||||
|
|
||||||
// Check for BMI2 and AVX2 support
|
|
||||||
"mov eax, 7",
|
|
||||||
"xor ecx, ecx",
|
|
||||||
"cpuid",
|
|
||||||
"and ebx, (1 << 8) | (1 << 5)", // Check BMI2 (bit 8) and AVX2 (bit 5)
|
|
||||||
"cmp ebx, (1 << 8) | (1 << 5)", // Compare to ensure both are supported
|
|
||||||
|
|
||||||
// Check for LZCNT and POPCNT support
|
|
||||||
"mov eax, 1",
|
|
||||||
"cpuid",
|
|
||||||
"and ecx, (1 << 5) | (1 << 23)", // Check LZCNT (bit 5) and POPCNT (bit 23)
|
|
||||||
"cmp ecx, (1 << 5) | (1 << 23)", // Compare to ensure both are supported
|
|
||||||
|
|
||||||
// Jump to the kernel entry point
|
|
||||||
"jmp {0}",
|
|
||||||
sym start,
|
|
||||||
sym oops,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe extern "C" fn oops() -> ! {
|
|
||||||
panic!("your cpu is ancient >:(")
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe extern "C" fn start() -> ! {
|
unsafe extern "C" fn start() -> ! {
|
||||||
logging::init();
|
logging::init();
|
||||||
crate::logger::init().expect("failed to set logger");
|
crate::logger::init().expect("failed to set logger");
|
||||||
log::debug!("Initialising AKern {}", crate::VERSION);
|
log::info!("Initialising AKern {}", crate::VERSION);
|
||||||
|
|
||||||
static HDHM_REQ: HhdmRequest = HhdmRequest::new(0);
|
static HDHM_REQ: HhdmRequest = HhdmRequest::new(0);
|
||||||
memory::init_pt(VirtAddr::new(
|
memory::init_pt(VirtAddr::new(
|
||||||
|
@ -188,7 +129,7 @@ unsafe extern "C" fn start() -> ! {
|
||||||
// TODO: Add in rdseed and rdrand as sources for randomness
|
// TODO: Add in rdseed and rdrand as sources for randomness
|
||||||
let _rand = xml::XMLElement::new("Random");
|
let _rand = xml::XMLElement::new("Random");
|
||||||
|
|
||||||
log::debug!("Getting boot modules");
|
log::trace!("Getting boot modules");
|
||||||
let bm = MOD_REQ.get_response().get();
|
let bm = MOD_REQ.get_response().get();
|
||||||
|
|
||||||
let mut bootmodules = alloc::vec::Vec::new();
|
let mut bootmodules = alloc::vec::Vec::new();
|
||||||
|
@ -202,13 +143,18 @@ unsafe extern "C" fn start() -> ! {
|
||||||
let raw_bytes = core::slice::from_raw_parts(
|
let raw_bytes = core::slice::from_raw_parts(
|
||||||
file.base.as_ptr().expect("invalid initrd"),
|
file.base.as_ptr().expect("invalid initrd"),
|
||||||
file.length as usize,
|
file.length as usize,
|
||||||
);
|
)
|
||||||
|
.to_vec();
|
||||||
|
|
||||||
let file_path = 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() {
|
if file_path.is_err() {
|
||||||
panic!("invalid file path: {:?}", file_path);
|
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() {
|
if file_cmd.is_err() {
|
||||||
panic!("invalid module cmd: {:?}", file_cmd);
|
panic!("invalid module cmd: {:?}", file_cmd);
|
||||||
}
|
}
|
||||||
|
@ -226,7 +172,7 @@ unsafe extern "C" fn start() -> ! {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
log::debug!("Boot module count: {:?}", bootmodules.len());
|
log::info!("Boot module count: {:?}", bootmodules.len());
|
||||||
assert_eq!(bm.module_count, bootmodules.len() as u64);
|
assert_eq!(bm.module_count, bootmodules.len() as u64);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -249,21 +195,32 @@ unsafe extern "C" fn start() -> ! {
|
||||||
/// Spin loop
|
/// Spin loop
|
||||||
pub fn spin_loop() -> ! {
|
pub fn spin_loop() -> ! {
|
||||||
loop {
|
loop {
|
||||||
core::hint::spin_loop();
|
x86_64::instructions::hlt();
|
||||||
x86_64::instructions::hlt()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn hardware_random_u64() -> u64 {
|
pub fn hardware_random_u64() -> u64 {
|
||||||
let mut out: u64 = 0;
|
use {log::trace, rdrand::RdRand};
|
||||||
match unsafe { _rdrand64_step(&mut out) } {
|
let gen = RdRand::new();
|
||||||
1 => out,
|
match gen {
|
||||||
_ => {
|
Ok(gen) => {
|
||||||
|
let ret = gen.try_next_u64().unwrap();
|
||||||
|
trace!("Random {}", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
warn!("RDRand not supported.");
|
warn!("RDRand not supported.");
|
||||||
// Try rdseed
|
// Try rdseed
|
||||||
match unsafe { _rdseed64_step(&mut out) } {
|
let gen = RdSeed::new();
|
||||||
1 => out,
|
match gen {
|
||||||
_ => panic!("Neither RDRand or RDSeed are supported"),
|
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() {}
|
pub fn get_edid() {}
|
||||||
|
|
||||||
#[allow(unused)]
|
|
||||||
pub fn register_dump() {
|
pub fn register_dump() {
|
||||||
let rax: u64;
|
let rax: u64;
|
||||||
let rbx: u64 = 0;
|
let rbx: u64 = 0;
|
||||||
|
|
|
@ -8,12 +8,12 @@ pub struct PciDeviceInfo {
|
||||||
pub full_class: PciFullClass,
|
pub full_class: PciFullClass,
|
||||||
pub rev_id: u8,
|
pub rev_id: u8,
|
||||||
}
|
}
|
||||||
|
use crate::alloc::string::ToString;
|
||||||
|
|
||||||
/// Enumerate PCI devices and run initialisation routines on ones we support
|
/// Enumerate PCI devices and run initialisation routines on ones we support
|
||||||
pub fn init(device_tree: &mut DeviceTree) {
|
pub fn init(device_tree: &mut DeviceTree) {
|
||||||
device_tree
|
device_tree.devices
|
||||||
.devices
|
.insert("Unidentified PCI".to_string(), alloc::vec![]);
|
||||||
.insert("Unidentified PCI", alloc::vec![]);
|
|
||||||
let mut devices = alloc::vec![];
|
let mut devices = alloc::vec![];
|
||||||
|
|
||||||
for bus in 0..=255 {
|
for bus in 0..=255 {
|
||||||
|
@ -23,7 +23,6 @@ pub fn init(device_tree: &mut DeviceTree) {
|
||||||
let id = device_info.device_id.id;
|
let id = device_info.device_id.id;
|
||||||
use Vendor::*;
|
use Vendor::*;
|
||||||
let (dev_type, dev_name) = match (vendor, id) {
|
let (dev_type, dev_name) = match (vendor, id) {
|
||||||
(VMWareInc, 1029) => ("GPUs", "SVGAII PCI GPU"),
|
|
||||||
(Qemu, 4369) => ("GPUs", "QEMU VGA"),
|
(Qemu, 4369) => ("GPUs", "QEMU VGA"),
|
||||||
(VirtIO, 4176) => ("GPUs", "VirtIO PCI GPU"),
|
(VirtIO, 4176) => ("GPUs", "VirtIO PCI GPU"),
|
||||||
(CirrusLogic, 184) => ("GPUs", "Cirrus SVGA"), //GD 5446?
|
(CirrusLogic, 184) => ("GPUs", "Cirrus SVGA"), //GD 5446?
|
||||||
|
@ -46,8 +45,7 @@ pub fn init(device_tree: &mut DeviceTree) {
|
||||||
pci_info.set_attribute("id", id);
|
pci_info.set_attribute("id", id);
|
||||||
pci_info.set_attribute("device", device_info.device);
|
pci_info.set_attribute("device", device_info.device);
|
||||||
pci_info.set_attribute("vendor", vendor);
|
pci_info.set_attribute("vendor", vendor);
|
||||||
pci_info.set_attribute("bus", bus);
|
pci_info.set_attribute("class", device_info.full_class.to_string());
|
||||||
pci_info.set_attribute("class", device_info.full_class);
|
|
||||||
dev.set_child(pci_info);
|
dev.set_child(pci_info);
|
||||||
devices.push((dev_type, dev));
|
devices.push((dev_type, dev));
|
||||||
}
|
}
|
||||||
|
@ -68,8 +66,7 @@ pub fn check_device(bus: u8, device: u8) -> Option<PciDeviceInfo> {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
let (reg2, addr) = unsafe { pci_config_read_2(bus, device, 0, 0x8) };
|
let reg2 = unsafe { pci_config_read(bus, device, 0, 0x8) };
|
||||||
log::debug!("pci device-({}) addr {} is {}", device, addr, reg2);
|
|
||||||
let class = ((reg2 >> 16) & 0x0000_FFFF) as u16;
|
let class = ((reg2 >> 16) & 0x0000_FFFF) as u16;
|
||||||
let pci_class = PciFullClass::from_u16(class);
|
let pci_class = PciFullClass::from_u16(class);
|
||||||
let header_type = get_header_type(bus, device, 0);
|
let header_type = get_header_type(bus, device, 0);
|
||||||
|
@ -272,7 +269,8 @@ impl Display for Vendor {
|
||||||
|
|
||||||
use core::fmt::Display;
|
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)]
|
#[allow(non_camel_case_types, dead_code)]
|
||||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
#[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 func = func as u32;
|
||||||
let offset = offset as u32;
|
let offset = offset as u32;
|
||||||
// construct address param
|
// 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
|
// write address
|
||||||
Port::new(0xCF8).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()
|
Port::new(0xCFC).read()
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn pci_config_read_2(bus: u8, device: u8, func: u8, offset: u8) -> (u32, u32) {
|
|
||||||
let bus = bus as u32;
|
|
||||||
let device = device as u32;
|
|
||||||
let func = func as u32;
|
|
||||||
let offset = offset as u32;
|
|
||||||
// construct address param
|
|
||||||
let address = (bus << 16) | (device << 11) | (func << 8) | (offset & 0xFC) | 0x8000_0000;
|
|
||||||
// write address
|
|
||||||
Port::new(0xCF8).write(address);
|
|
||||||
|
|
||||||
// read data
|
|
||||||
(Port::new(0xCFC).read(), address)
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe fn pci_config_write(bus: u8, device: u8, func: u8, offset: u8, value: u32) {
|
unsafe fn pci_config_write(bus: u8, device: u8, func: u8, offset: u8, value: u32) {
|
||||||
let bus = bus as u32;
|
let bus = bus as u32;
|
||||||
let device = device as u32;
|
let device = device as u32;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use {
|
use {
|
||||||
core::ptr::NonNull,
|
core::{ptr::NonNull},
|
||||||
virtio_drivers::{BufferDirection, Hal, PhysAddr},
|
virtio_drivers::{BufferDirection, Hal, PhysAddr},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,36 +1,36 @@
|
||||||
use {
|
use {
|
||||||
// crate::alloc::string::ToString,
|
crate::alloc::string::ToString,
|
||||||
alloc::vec::Vec,
|
alloc::{string::String, vec::Vec},
|
||||||
// clparse::Arguments,
|
clparse::Arguments,
|
||||||
// core::fmt::{Debug, Display},
|
core::fmt::{Debug, Display},
|
||||||
// log::trace,
|
log::trace,
|
||||||
// xml::XMLElement,
|
xml::XMLElement,
|
||||||
};
|
};
|
||||||
pub type BootModules<'a> = Vec<BootModule<'a>>;
|
pub type BootModules = Vec<BootModule>;
|
||||||
|
|
||||||
pub struct BootModule<'a> {
|
pub struct BootModule {
|
||||||
pub path: &'a str,
|
pub path: String,
|
||||||
pub bytes: &'a [u8],
|
pub bytes: Vec<u8>,
|
||||||
pub cmd: &'a str,
|
pub cmd: String,
|
||||||
}
|
}
|
||||||
impl<'a> BootModule<'a> {
|
impl BootModule {
|
||||||
pub fn new(path: &'a str, bytes: &'a [u8], cmd: &'a str) -> Self {
|
pub fn new(path: String, bytes: Vec<u8>, cmd: String) -> Self {
|
||||||
Self { path, bytes, cmd }
|
Self { path, bytes, cmd }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// pub fn build_cmd<T: Display + Debug>(name: T, cmdline: T) -> XMLElement {
|
pub fn build_cmd<T: Display + Debug>(name: T, cmdline: T) -> XMLElement {
|
||||||
// let mut cmdline = cmdline.to_string();
|
let mut cmdline = cmdline.to_string();
|
||||||
// cmdline.pop();
|
cmdline.pop();
|
||||||
// cmdline.remove(0);
|
cmdline.remove(0);
|
||||||
|
|
||||||
// let cmd = Arguments::parse(cmdline.to_string()).unwrap();
|
let cmd = Arguments::parse(cmdline.to_string()).unwrap();
|
||||||
// trace!("Cmdline: {cmd:?}");
|
trace!("Cmdline: {cmd:?}");
|
||||||
|
|
||||||
// let mut clo = XMLElement::new(name);
|
let mut clo = XMLElement::new(name);
|
||||||
// for (key, value) in cmd.arguments {
|
for (key, value) in cmd.arguments {
|
||||||
// clo.set_attribute(key, value);
|
clo.set_attribute(key, value);
|
||||||
// }
|
}
|
||||||
// trace!("command line object: {:?}", clo);
|
trace!("command line object: {:?}", clo);
|
||||||
// clo
|
clo
|
||||||
// }
|
}
|
||||||
|
|
|
@ -1,7 +1,11 @@
|
||||||
//! A tree of hardware devices
|
//! 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.
|
/// A device object.
|
||||||
/// TODO define device
|
/// TODO define device
|
||||||
pub type Device = xml::XMLElement;
|
pub type Device = xml::XMLElement;
|
||||||
|
@ -9,40 +13,38 @@ pub type Device = xml::XMLElement;
|
||||||
/// A tree of devices
|
/// A tree of devices
|
||||||
// TODO: alphabetize this list
|
// TODO: alphabetize this list
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct DeviceTree<'a> {
|
pub struct DeviceTree {
|
||||||
/// The device tree
|
/// 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
|
/// Build the device tree. Does not populate the device tree
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
let mut dt = Self {
|
let mut dt = Self {
|
||||||
devices: HashMap::new(),
|
devices: HashMap::new(),
|
||||||
};
|
};
|
||||||
device_tree!(
|
device_tree!(dt, [
|
||||||
dt,
|
"Mice",
|
||||||
[
|
"Keyboards",
|
||||||
"Mice",
|
"Controllers",
|
||||||
"Keyboards",
|
"Generic HIDs",
|
||||||
"Controllers",
|
"Disk Drives",
|
||||||
"Generic HIDs",
|
"CD Drives",
|
||||||
"Disk Drives",
|
"Batteries",
|
||||||
"CD Drives",
|
"Monitors",
|
||||||
"Batteries",
|
"GPUs",
|
||||||
"Monitors",
|
"CPUs",
|
||||||
"GPUs",
|
"USB",
|
||||||
"CPUs",
|
"Serial Ports",
|
||||||
"USB",
|
"Cameras",
|
||||||
"Serial Ports",
|
"Biometric Devices",
|
||||||
"Cameras",
|
]);
|
||||||
"Biometric Devices",
|
|
||||||
]
|
|
||||||
);
|
|
||||||
dt
|
dt
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
use crate::{device_tree, tab, utils::TAB};
|
use crate::{utils::TAB, device_tree};
|
||||||
impl<'a> fmt::Display for DeviceTree<'a> {
|
use crate::tab;
|
||||||
|
impl fmt::Display for DeviceTree {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
writeln!(f)?;
|
writeln!(f)?;
|
||||||
for (device_type, devices) in &self.devices {
|
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,41 +1,28 @@
|
||||||
//! Environment call handling routines
|
//! Environment call handling routines
|
||||||
|
|
||||||
use {alloc::boxed::Box, core::cell::LazyCell, hbvm::mem::Address};
|
use core::borrow::Borrow;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
holeybytes::{
|
allocator,
|
||||||
kernel_services::{
|
holeybytes::kernel_services::{
|
||||||
block_read, dt_msg_handler::dt_msg_handler, logging_service::log_msg_handler,
|
block_read,
|
||||||
service_definition_service::sds_msg_handler,
|
service_definition_service::{sds_msg_handler, SERVICES},
|
||||||
},
|
|
||||||
ExecThread,
|
|
||||||
},
|
},
|
||||||
kmain::EXECUTOR,
|
|
||||||
task::Executor,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use {
|
use {
|
||||||
super::Vm,
|
super::{mem::Memory, Vm},
|
||||||
crate::{arch, ipc::buffer::IpcBuffer, kmain::IPC_BUFFERS},
|
crate::{arch, holeybytes::mem, ipc::buffer::IpcBuffer, kmain::IPC_BUFFERS},
|
||||||
hbvm::value::Value,
|
alloc::string::String,
|
||||||
log::{debug, error, info, trace},
|
log::{debug, error, info, trace, warn},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(target_arch = "x86_64")]
|
pub fn handler(vm: &mut Vm) {
|
||||||
#[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, pid: &usize) {
|
|
||||||
let ecall_number = vm.registers[2].cast::<u64>();
|
let ecall_number = vm.registers[2].cast::<u64>();
|
||||||
|
|
||||||
|
// debug!("Ecall number {:?}", ecall_number);
|
||||||
|
//info!("Register dump: {:?}", vm.registers);
|
||||||
|
|
||||||
match ecall_number {
|
match ecall_number {
|
||||||
0 => {
|
0 => {
|
||||||
// TODO: explode computer
|
// TODO: explode computer
|
||||||
|
@ -47,9 +34,9 @@ pub fn handler(vm: &mut Vm, pid: &usize) {
|
||||||
1 => {
|
1 => {
|
||||||
// Make buffer
|
// Make buffer
|
||||||
|
|
||||||
let bounded = match vm.registers[3] {
|
let bounded = match vm.registers[3].cast::<u64>() {
|
||||||
Value(0) => false,
|
0 => false,
|
||||||
Value(1) => true,
|
1 => true,
|
||||||
_ => {
|
_ => {
|
||||||
panic!("Bad");
|
panic!("Bad");
|
||||||
}
|
}
|
||||||
|
@ -58,19 +45,22 @@ pub fn handler(vm: &mut Vm, pid: &usize) {
|
||||||
let length = vm.registers[4].cast::<u64>();
|
let length = vm.registers[4].cast::<u64>();
|
||||||
|
|
||||||
let mut buffs = IPC_BUFFERS.lock();
|
let mut buffs = IPC_BUFFERS.lock();
|
||||||
|
let abc;
|
||||||
|
|
||||||
|
match bounded {
|
||||||
|
false => {
|
||||||
|
abc = IpcBuffer::new(false, 0);
|
||||||
|
}
|
||||||
|
true => {
|
||||||
|
abc = IpcBuffer::new(true, length);
|
||||||
|
}
|
||||||
|
};
|
||||||
let buff_id = arch::hardware_random_u64();
|
let buff_id = arch::hardware_random_u64();
|
||||||
buffs.insert(
|
buffs.insert(buff_id, abc);
|
||||||
buff_id,
|
info!("Buffer ID: {}", buff_id);
|
||||||
match bounded {
|
|
||||||
false => IpcBuffer::new(false, 0),
|
|
||||||
true => IpcBuffer::new(true, length),
|
|
||||||
},
|
|
||||||
);
|
|
||||||
vm.registers[1] = hbvm::value::Value(buff_id);
|
vm.registers[1] = hbvm::value::Value(buff_id);
|
||||||
}
|
}
|
||||||
2 => {
|
2 => {
|
||||||
log::error!("Oops, deleting buffers is not implemented.")
|
|
||||||
// Delete buffer
|
// Delete buffer
|
||||||
}
|
}
|
||||||
3 => {
|
3 => {
|
||||||
|
@ -79,19 +69,16 @@ pub fn handler(vm: &mut Vm, pid: &usize) {
|
||||||
let mem_addr = vm.registers[4].cast::<u64>();
|
let mem_addr = vm.registers[4].cast::<u64>();
|
||||||
let length = vm.registers[5].cast::<u64>() as usize;
|
let length = vm.registers[5].cast::<u64>() as usize;
|
||||||
trace!("IPC address: {:?}", mem_addr);
|
trace!("IPC address: {:?}", mem_addr);
|
||||||
|
use alloc::vec::Vec;
|
||||||
unsafe { LazyCell::<Executor>::get_mut(&mut EXECUTOR) }
|
|
||||||
.unwrap()
|
|
||||||
.send_buffer(buffer_id as usize);
|
|
||||||
|
|
||||||
match buffer_id {
|
match buffer_id {
|
||||||
0 => match sds_msg_handler(vm, mem_addr, length) {
|
0 => match sds_msg_handler(vm, mem_addr, length) {
|
||||||
Ok(()) => {}
|
Ok(()) => {}
|
||||||
Err(err) => log::error!("Improper sds format: {err:?}"),
|
Err(err) => log::error!("Improper sds format"),
|
||||||
},
|
},
|
||||||
1 => match log_msg_handler(vm, mem_addr, length) {
|
1 => match log_msg_handler(vm, mem_addr, length) {
|
||||||
Ok(()) => {}
|
Ok(()) => {}
|
||||||
Err(_) => log::error!("Improper log format"),
|
Err(err) => log::error!("Improper log format"),
|
||||||
},
|
},
|
||||||
2 => {
|
2 => {
|
||||||
use crate::holeybytes::kernel_services::mem_serve::memory_msg_handler;
|
use crate::holeybytes::kernel_services::mem_serve::memory_msg_handler;
|
||||||
|
@ -99,183 +86,173 @@ pub fn handler(vm: &mut Vm, pid: &usize) {
|
||||||
Ok(_) => {}
|
Ok(_) => {}
|
||||||
Err(_) => {}
|
Err(_) => {}
|
||||||
}
|
}
|
||||||
|
//
|
||||||
}
|
}
|
||||||
#[cfg(target_arch = "x86_64")]
|
|
||||||
3 => {
|
3 => {
|
||||||
let msg_vec = block_read(mem_addr, length);
|
unsafe fn x86_in(address: u16) -> u8 {
|
||||||
let msg_type = msg_vec[0];
|
x86_64::instructions::port::Port::new(address).read()
|
||||||
match msg_type {
|
}
|
||||||
0 => unsafe {
|
unsafe fn x86_out(address: u16, value: u8) {
|
||||||
let size = msg_vec[1];
|
x86_64::instructions::port::Port::new(address).write(value);
|
||||||
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 {
|
let mut msg_vec = block_read(mem_addr, length);
|
||||||
0 => x86_out(addr, msg_vec[4]),
|
let msg_type = msg_vec[0];
|
||||||
1 => x86_out(
|
msg_vec.remove(0);
|
||||||
addr,
|
match msg_type {
|
||||||
u16::from_le_bytes(msg_vec[4..6].try_into().unwrap_unchecked()),
|
0 => {
|
||||||
),
|
let mut addr = msg_vec[0] as u16;
|
||||||
2 => x86_out(
|
msg_vec.remove(0);
|
||||||
addr,
|
|
||||||
u32::from_le_bytes(msg_vec[4..8].try_into().unwrap_unchecked()),
|
let addr2 = msg_vec[0] as u16;
|
||||||
),
|
msg_vec.remove(0);
|
||||||
_ => panic!("How?"),
|
|
||||||
}
|
addr = ((addr) << 8) | addr2;
|
||||||
},
|
|
||||||
|
let value = unsafe { x86_in(addr) };
|
||||||
|
|
||||||
|
trace!("Read the value {} from address {}", value, addr);
|
||||||
|
vm.registers[1] = hbvm::value::Value(value as u64);
|
||||||
|
}
|
||||||
|
1 => {
|
||||||
|
let mut addr = msg_vec[0] as u16;
|
||||||
|
msg_vec.remove(0);
|
||||||
|
|
||||||
|
let addr2 = msg_vec[0] as u16;
|
||||||
|
msg_vec.remove(0);
|
||||||
|
|
||||||
|
addr = ((addr) << 8) | addr2;
|
||||||
|
|
||||||
|
let value = msg_vec[0];
|
||||||
|
msg_vec.remove(0);
|
||||||
|
trace!("Setting the address {} to {}", addr, value);
|
||||||
|
unsafe { x86_out(addr, value) };
|
||||||
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[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) {
|
|
||||||
Ok(()) => {}
|
|
||||||
Err(_) => log::error!("Improper dt query"),
|
|
||||||
},
|
|
||||||
6 => unsafe {
|
|
||||||
let program = block_read(mem_addr, length);
|
|
||||||
|
|
||||||
// decode AbleOS Executable format
|
|
||||||
let header = &program[0..46];
|
|
||||||
let magic_slice = &header[0..3];
|
|
||||||
if magic_slice != [0x15, 0x91, 0xD2] {
|
|
||||||
log::error!("Invalid magic number at the start of executable.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let executable_format_version =
|
|
||||||
u32::from_le_bytes(header[3..7].try_into().unwrap());
|
|
||||||
let offset = if executable_format_version == 0 {
|
|
||||||
47
|
|
||||||
} else {
|
|
||||||
error!("Invalid executable format.");
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
|
|
||||||
let code_length = u64::from_le_bytes(header[7..15].try_into().unwrap());
|
|
||||||
let data_length = u64::from_le_bytes(header[15..23].try_into().unwrap());
|
|
||||||
let end = (code_length + data_length) as usize;
|
|
||||||
log::debug!("{code_length} + {data_length} = {end}");
|
|
||||||
|
|
||||||
let thr = ExecThread::new(&program[offset..end], Address::new(0));
|
|
||||||
vm.registers[1] = Value(
|
|
||||||
LazyCell::<Executor>::get_mut(&mut EXECUTOR)
|
|
||||||
.unwrap()
|
|
||||||
.spawn(Box::pin(async move {
|
|
||||||
if let Err(e) = thr.await {
|
|
||||||
log::error!("{e:?}");
|
|
||||||
}
|
|
||||||
})) as u64,
|
|
||||||
);
|
|
||||||
log::debug!("spawned a process");
|
|
||||||
},
|
|
||||||
|
|
||||||
buffer_id => {
|
buffer_id => {
|
||||||
let mut buffs = IPC_BUFFERS.lock();
|
let mut buffs = IPC_BUFFERS.lock();
|
||||||
match buffs.get_mut(&buffer_id) {
|
match buffs.get_mut(&buffer_id) {
|
||||||
Some(buff) => {
|
Some(buff) => {
|
||||||
let msg_vec = block_read(mem_addr, length);
|
let mut msg_vec = vec![];
|
||||||
buff.push(msg_vec.to_vec());
|
|
||||||
debug!("Sent Message {:?} to Buffer({})", msg_vec, buffer_id);
|
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 => {
|
None => {
|
||||||
log::error!("Access of non-existent buffer {}", buffer_id)
|
log::error!("Access of non-existent buffer {}", buffer_id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
drop(buffs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
4 => {
|
4 => {
|
||||||
let buffer_id = vm.registers[3].cast::<u64>();
|
let buffer_id = vm.registers[3].cast::<u64>();
|
||||||
let map_ptr = vm.registers[4].cast::<u64>();
|
let mut map_ptr = vm.registers[4].cast::<u64>();
|
||||||
let max_length = vm.registers[5].cast::<u64>();
|
let max_length = vm.registers[5].cast::<u64>();
|
||||||
let mut buffs = IPC_BUFFERS.lock();
|
|
||||||
let 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() {
|
let mut buffs = IPC_BUFFERS.lock();
|
||||||
Ok(msg) => msg,
|
let mut buff: &mut IpcBuffer;
|
||||||
Err(_) => return,
|
|
||||||
};
|
if buffs.get_mut(&buffer_id).is_some() {
|
||||||
if msg.len() > unsafe { max_length.try_into().unwrap_unchecked() } {
|
buff = buffs.get_mut(&buffer_id).unwrap();
|
||||||
|
} else {
|
||||||
|
info!("AHHH");
|
||||||
|
vm.registers[1] = hbvm::value::Value(0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let pop = buff.pop();
|
||||||
|
if pop.is_err() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let msg = pop.unwrap();
|
||||||
|
if msg.len() > max_length.try_into().unwrap() {
|
||||||
info!("{}", max_length);
|
info!("{}", max_length);
|
||||||
error!("Message is too long to map in.");
|
error!("Message is too long to map in.");
|
||||||
} else {
|
} else {
|
||||||
unsafe {
|
unsafe {
|
||||||
let ptr = map_ptr as *mut u8;
|
let ptr: *mut u64 = &mut map_ptr;
|
||||||
ptr.copy_from_nonoverlapping(msg.as_ptr(), msg.len());
|
for (index, byte) in msg.iter().enumerate() {
|
||||||
|
ptr.offset(index.try_into().unwrap()).write_bytes(*byte, 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
debug!("Recieve {:?} from Buffer({})", msg, buffer_id);
|
info!("Recieve {:?} from Buffer({})", msg, buffer_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
5 => {
|
5 => {
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
{
|
{
|
||||||
let r2 = vm.registers[2].cast::<u64>();
|
let r2 = vm.registers[2].cast::<u64>();
|
||||||
let x = hbvm::value::Value(unsafe { x86_in::<u8>(r2 as u16) } as u64);
|
unsafe fn x86_in(address: u16) -> u32 {
|
||||||
// info!("Read {:?} from Port {:?}", x, r2);
|
x86_64::instructions::port::Port::new(address).read()
|
||||||
|
}
|
||||||
|
unsafe fn x86_out(address: u16, value: u32) {
|
||||||
|
x86_64::instructions::port::Port::new(address).write(value);
|
||||||
|
}
|
||||||
|
let x = hbvm::value::Value(unsafe { x86_in(r2 as u16) } as u64);
|
||||||
|
info!("Read {:?} from Port {:?}", x, r2);
|
||||||
vm.registers[3] = x
|
vm.registers[3] = x
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
6 => {
|
// 5
|
||||||
// Wait till interrupt
|
|
||||||
use crate::kmain::EXECUTOR;
|
|
||||||
let interrupt_type = vm.registers[3].cast::<u8>();
|
|
||||||
debug!("Interrupt subscribed: {}", interrupt_type);
|
|
||||||
unsafe {
|
|
||||||
LazyCell::<Executor>::get_mut(&mut EXECUTOR)
|
|
||||||
.unwrap()
|
|
||||||
.interrupt_subscribe(*pid, interrupt_type);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
7 => {
|
|
||||||
// Wait till buffer
|
|
||||||
use crate::kmain::EXECUTOR;
|
|
||||||
let buffer_id = vm.registers[3].cast::<u64>() as usize;
|
|
||||||
debug!("Buffer subscribed: {}", buffer_id);
|
|
||||||
unsafe {
|
|
||||||
LazyCell::<Executor>::get_mut(&mut EXECUTOR)
|
|
||||||
.unwrap()
|
|
||||||
.buffer_subscribe(*pid, buffer_id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {
|
_ => {
|
||||||
log::error!("Syscall unknown {:?}{:?}", ecall_number, vm.registers);
|
log::error!("Syscall unknown {:?}{:?}", ecall_number, vm.registers);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn log_msg_handler(vm: &mut Vm, mem_addr: u64, length: usize) -> Result<(), LogError> {
|
||||||
|
// let message_length = 8 + 8 + 8;
|
||||||
|
// log::info!("Mem Addr 0x{:x?} length {}", mem_addr, length);
|
||||||
|
let mut msg_vec = block_read(mem_addr, length);
|
||||||
|
|
||||||
|
let log_level = msg_vec.pop().unwrap();
|
||||||
|
match String::from_utf8(msg_vec) {
|
||||||
|
Ok(strr) => {
|
||||||
|
// use LogLevel::*;
|
||||||
|
let ll = match log_level {
|
||||||
|
0 | 48 => error!("{}", strr),
|
||||||
|
1 | 49 => warn!("{}", strr),
|
||||||
|
2 | 50 => info!("{}", strr),
|
||||||
|
3 | 51 => debug!("{}", strr),
|
||||||
|
4 | 52 => trace!("{}", strr),
|
||||||
|
_ => {
|
||||||
|
return Err(LogError::InvalidLogFormat);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
error!("{:?}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum LogError {
|
pub enum LogError {
|
||||||
NoMessages,
|
|
||||||
InvalidLogFormat,
|
InvalidLogFormat,
|
||||||
}
|
}
|
||||||
|
use {alloc::vec, log::Record};
|
||||||
|
|
||||||
|
// 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,7 +1,10 @@
|
||||||
use {
|
use {
|
||||||
crate::holeybytes::{kernel_services::block_read, Vm},
|
crate::holeybytes::{
|
||||||
alloc::alloc::{alloc, dealloc},
|
ecah::LogError,
|
||||||
core::alloc::Layout,
|
kernel_services::{block_read, mem_serve},
|
||||||
|
Vm,
|
||||||
|
},
|
||||||
|
alloc::alloc::alloc_zeroed,
|
||||||
log::{debug, info},
|
log::{debug, info},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -16,100 +19,84 @@ pub enum MemoryQuotaType {
|
||||||
KillQuota = 3,
|
KillQuota = 3,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn alloc_page(vm: &mut Vm, _mem_addr: u64, _length: usize) -> Result<(), MemoryServiceError> {
|
fn alloc_page(vm: &mut Vm, mem_addr: u64, length: usize) -> Result<(), MemoryServiceError> {
|
||||||
let ptr = unsafe { alloc(Layout::from_size_align_unchecked(4096, 8)) };
|
let mut val = alloc::vec::Vec::new();
|
||||||
info!("Block address: {:?}", ptr);
|
for _ in 0..4096 {
|
||||||
vm.registers[1] = hbvm::value::Value(ptr as u64);
|
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);
|
vm.registers[2] = hbvm::value::Value(4096);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
unsafe fn memset(dest: *mut u8, src: *const u8, count: usize, size: usize) {
|
|
||||||
let total_size = count * size;
|
|
||||||
src.copy_to_nonoverlapping(dest, size);
|
|
||||||
|
|
||||||
let mut copied = size;
|
|
||||||
|
|
||||||
while copied < total_size {
|
|
||||||
let copy_size = copied.min(total_size - copied);
|
|
||||||
dest.add(copied).copy_from_nonoverlapping(dest, copy_size);
|
|
||||||
copied += copy_size;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn memory_msg_handler(
|
pub fn memory_msg_handler(
|
||||||
vm: &mut Vm,
|
vm: &mut Vm,
|
||||||
mem_addr: u64,
|
mem_addr: u64,
|
||||||
length: usize,
|
length: usize,
|
||||||
) -> Result<(), MemoryServiceError> {
|
) -> Result<(), MemoryServiceError> {
|
||||||
let msg_vec = block_read(mem_addr, length);
|
let mut msg_vec = block_read(mem_addr, length);
|
||||||
let msg_type = msg_vec[0];
|
let msg_type = msg_vec[0];
|
||||||
|
|
||||||
|
msg_vec.remove(0);
|
||||||
match msg_type {
|
match msg_type {
|
||||||
0 => unsafe {
|
0 => {
|
||||||
let page_count = msg_vec[1];
|
let page_count = msg_vec[0];
|
||||||
|
msg_vec.remove(0);
|
||||||
|
|
||||||
let ptr = alloc(Layout::from_size_align_unchecked(
|
let mptr_raw: [u8; 8] = msg_vec[0..8].try_into().unwrap();
|
||||||
page_count as usize * 4096,
|
let mptr: u64 = u64::from_le_bytes(mptr_raw);
|
||||||
8,
|
|
||||||
));
|
|
||||||
|
|
||||||
log::debug!("Allocating {} pages @ {:x}", page_count, ptr as u64);
|
log::debug!("Allocating {} pages @ {:x}", page_count, mptr);
|
||||||
|
|
||||||
vm.registers[1] = hbvm::value::Value(ptr as u64);
|
let mut val = alloc::vec::Vec::new();
|
||||||
log::debug!("Kernel ptr: {:x}", ptr as u64);
|
for _ in 0..(page_count as isize * 4096) {
|
||||||
},
|
val.push(0);
|
||||||
|
}
|
||||||
|
vm.registers[1] = hbvm::value::Value(val.as_ptr() as u64);
|
||||||
|
log::debug!("Kernel ptr: {:x}", val.as_ptr() as u64);
|
||||||
|
}
|
||||||
|
1 => {
|
||||||
|
let page_count = msg_vec[0];
|
||||||
|
msg_vec.remove(0);
|
||||||
|
|
||||||
1 => unsafe {
|
let mptr_raw: [u8; 8] = msg_vec[0..8].try_into().unwrap();
|
||||||
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);
|
let mptr: u64 = u64::from_le_bytes(mptr_raw);
|
||||||
log::debug!("Deallocating {} pages @ {:x}", page_count, mptr);
|
log::debug!("Deallocating {} pages @ {:x}", page_count, mptr);
|
||||||
|
}
|
||||||
dealloc(
|
|
||||||
mptr as *mut u8,
|
|
||||||
Layout::from_size_align_unchecked(page_count as usize * 4096, 8),
|
|
||||||
)
|
|
||||||
},
|
|
||||||
2 => {
|
2 => {
|
||||||
use MemoryQuotaType::*;
|
use MemoryQuotaType::*;
|
||||||
let quota_type = match msg_vec[1] {
|
let quota_type = match msg_vec[0] {
|
||||||
0 => NoQuota,
|
0 => NoQuota,
|
||||||
1 => SoftQuota,
|
1 => SoftQuota,
|
||||||
2 => HardQuota,
|
2 => HardQuota,
|
||||||
3 => KillQuota,
|
3 => KillQuota,
|
||||||
_ => NoQuota,
|
_ => NoQuota,
|
||||||
};
|
};
|
||||||
let hid_raw: [u8; 8] = msg_vec[2..10].try_into().unwrap();
|
msg_vec.remove(0);
|
||||||
|
let hid_raw: [u8; 8] = msg_vec[0..8].try_into().unwrap();
|
||||||
let hid: u64 = u64::from_le_bytes(hid_raw);
|
let hid: u64 = u64::from_le_bytes(hid_raw);
|
||||||
let pid_raw: [u8; 8] = msg_vec[10..18].try_into().unwrap();
|
for _ in 0..8 {
|
||||||
let pid: u64 = u64::from_le_bytes(pid_raw);
|
msg_vec.remove(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
let pid_raw: [u8; 8] = msg_vec[0..8].try_into().unwrap();
|
||||||
|
let pid: u64 = u64::from_le_bytes(hid_raw);
|
||||||
|
for _ in 0..8 {
|
||||||
|
msg_vec.remove(0);
|
||||||
|
}
|
||||||
|
|
||||||
debug!(
|
debug!(
|
||||||
"Setting HID-{:x}:PID-{:x}'s quota type to {:?}",
|
"Setting HID-{:x}:PID-{:x}'s quota type to {:?}",
|
||||||
hid, pid, quota_type
|
hid, pid, quota_type
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
3 => {
|
3 => {
|
||||||
let page_count = msg_vec[1];
|
let page_count = msg_vec[0];
|
||||||
log::debug!(" {} pages", page_count);
|
log::debug!(" {} pages", page_count);
|
||||||
|
msg_vec.remove(0);
|
||||||
}
|
}
|
||||||
4 => unsafe {
|
|
||||||
let count = u32::from_le_bytes(msg_vec[1..5].try_into().unwrap_unchecked()) as usize;
|
|
||||||
let src = u64::from_le_bytes(msg_vec[5..13].try_into().unwrap_unchecked()) as *const u8;
|
|
||||||
let dest = u64::from_le_bytes(msg_vec[13..21].try_into().unwrap_unchecked()) as *mut u8;
|
|
||||||
|
|
||||||
src.copy_to_nonoverlapping(dest, count);
|
|
||||||
},
|
|
||||||
5 => unsafe {
|
|
||||||
let count = u32::from_le_bytes(msg_vec[1..5].try_into().unwrap_unchecked()) as usize;
|
|
||||||
let size = u32::from_le_bytes(msg_vec[5..9].try_into().unwrap_unchecked()) as usize;
|
|
||||||
let src = u64::from_le_bytes(msg_vec[9..17].try_into().unwrap_unchecked()) as *const u8;
|
|
||||||
let dest = u64::from_le_bytes(msg_vec[17..25].try_into().unwrap_unchecked()) as *mut u8;
|
|
||||||
|
|
||||||
memset(dest, src, count, size);
|
|
||||||
},
|
|
||||||
_ => {
|
_ => {
|
||||||
log::debug!("Unknown memory service message type: {}", msg_type);
|
log::debug!("Unknown memory service message type: {}", msg_type);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,15 @@
|
||||||
use core::slice;
|
use alloc::{vec, vec::Vec};
|
||||||
|
|
||||||
pub mod dt_msg_handler;
|
|
||||||
pub mod logging_service;
|
|
||||||
pub mod mem_serve;
|
pub mod mem_serve;
|
||||||
pub mod service_definition_service;
|
pub mod service_definition_service;
|
||||||
|
|
||||||
#[inline(always)]
|
pub fn block_read(mem_addr: u64, length: usize) -> Vec<u8> {
|
||||||
pub fn block_read<'a>(mem_addr: u64, length: usize) -> &'a mut [u8] {
|
let mut msg_vec = vec![];
|
||||||
unsafe { slice::from_raw_parts_mut(mem_addr as *mut _, length) }
|
|
||||||
|
for x in 0..(length as isize) {
|
||||||
|
let xyz = mem_addr as *const u8;
|
||||||
|
let value = unsafe { xyz.offset(x).read() };
|
||||||
|
msg_vec.push(value);
|
||||||
|
}
|
||||||
|
msg_vec
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,40 +1,43 @@
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
|
alloc::string::ToString,
|
||||||
arch::hardware_random_u64,
|
arch::hardware_random_u64,
|
||||||
holeybytes::{kernel_services::block_read, Vm},
|
holeybytes::{ecah::LogError, kernel_services::block_read, Vm},
|
||||||
ipc::{buffer::IpcBuffer, protocol::Protocol},
|
ipc::{
|
||||||
|
buffer::IpcBuffer,
|
||||||
|
protocol::{self, Protocol},
|
||||||
|
},
|
||||||
kmain::IPC_BUFFERS,
|
kmain::IPC_BUFFERS,
|
||||||
},
|
},
|
||||||
|
alloc::string::String,
|
||||||
hashbrown::HashMap,
|
hashbrown::HashMap,
|
||||||
log::{info, trace},
|
log::{info, trace},
|
||||||
spin::{lazy::Lazy, Mutex},
|
spin::{lazy::Lazy, Mutex},
|
||||||
};
|
};
|
||||||
pub struct Services<'a>(HashMap<u64, Protocol<'a>>);
|
pub struct Services(HashMap<u64, Protocol>);
|
||||||
pub static SERVICES: Lazy<Mutex<Services>> = Lazy::new(|| {
|
pub static SERVICES: Lazy<Mutex<Services>> = Lazy::new(|| {
|
||||||
let mut dt = Services(HashMap::new());
|
let mut dt = Services(HashMap::new());
|
||||||
dt.0.insert(0, Protocol::void());
|
dt.0.insert(0, Protocol::void());
|
||||||
Mutex::new(dt)
|
Mutex::new(dt)
|
||||||
});
|
});
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum ServiceError {
|
pub fn sds_msg_handler(vm: &mut Vm, mem_addr: u64, length: usize) -> Result<(), LogError> {
|
||||||
InvalidFormat,
|
let mut msg_vec = block_read(mem_addr, length);
|
||||||
}
|
|
||||||
pub fn sds_msg_handler(vm: &mut Vm, mem_addr: u64, length: usize) -> Result<(), ServiceError> {
|
|
||||||
let msg_vec = block_read(mem_addr, length);
|
|
||||||
let sds_event_type: ServiceEventType = msg_vec[0].into();
|
let sds_event_type: ServiceEventType = msg_vec[0].into();
|
||||||
let strptr = u64::from_le_bytes(msg_vec[1..9].try_into().unwrap());
|
msg_vec.remove(0);
|
||||||
let strlen = u64::from_le_bytes(msg_vec[9..17].try_into().unwrap()) as usize;
|
|
||||||
let string_vec = block_read(strptr, strlen);
|
// info!("Length {}", msg_vec.len());
|
||||||
let string = core::str::from_utf8(string_vec).expect("Our bytes should be valid utf8");
|
|
||||||
|
|
||||||
use ServiceEventType::*;
|
use ServiceEventType::*;
|
||||||
match sds_event_type {
|
match sds_event_type {
|
||||||
CreateService => {
|
CreateService => {
|
||||||
|
let string = String::from_utf8(msg_vec).expect("Our bytes should be valid utf8");
|
||||||
let ret = sds_create_service(string);
|
let ret = sds_create_service(string);
|
||||||
vm.registers[1] = hbvm::value::Value(ret as u64);
|
vm.registers[1] = hbvm::value::Value(ret as u64);
|
||||||
}
|
}
|
||||||
DeleteService => todo!(),
|
DeleteService => todo!(),
|
||||||
SearchServices => {
|
SearchServices => {
|
||||||
|
let string = String::from_utf8(msg_vec).expect("Our bytes should be valid utf8");
|
||||||
let ret = sds_search_service(string);
|
let ret = sds_search_service(string);
|
||||||
vm.registers[1] = hbvm::value::Value(ret as u64);
|
vm.registers[1] = hbvm::value::Value(ret as u64);
|
||||||
}
|
}
|
||||||
|
@ -76,29 +79,30 @@ impl From<u8> for ServiceEventType {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sds_create_service(protocol: &'static str) -> u64 {
|
fn sds_create_service(protocol: String) -> u64 {
|
||||||
let buff_id = hardware_random_u64();
|
let buff_id = hardware_random_u64();
|
||||||
let mut services = SERVICES.lock();
|
let mut services = SERVICES.lock();
|
||||||
let mut buffers = IPC_BUFFERS.lock();
|
let mut buffers = IPC_BUFFERS.lock();
|
||||||
|
|
||||||
let protocol_ = Protocol::from(protocol);
|
let protocol_ = Protocol::from(protocol.clone());
|
||||||
let mut buff = IpcBuffer::new(false, 0);
|
let mut buff = IpcBuffer::new(false, 0);
|
||||||
|
|
||||||
services.0.insert(buff_id, protocol_.clone());
|
services.0.insert(buff_id, protocol_.clone());
|
||||||
buff.protocol = protocol_;
|
buff.protocol = protocol_.clone();
|
||||||
buffers.insert(buff_id, buff);
|
buffers.insert(buff_id, buff);
|
||||||
|
|
||||||
trace!("BufferID({}) => {}", buff_id, protocol);
|
trace!("BufferID({}) => {}", buff_id, protocol);
|
||||||
// let a: protocol::Protocol = protocol.into();
|
// let a: protocol::Protocol = protocol.into();
|
||||||
buff_id
|
buff_id
|
||||||
}
|
}
|
||||||
pub fn sds_search_service(protocol: &str) -> u64 {
|
|
||||||
let services = SERVICES.lock();
|
fn sds_search_service(protocol: String) -> u64 {
|
||||||
let compare = Protocol::from(protocol);
|
let mut services = SERVICES.lock();
|
||||||
|
let compare = Protocol::from(protocol.clone());
|
||||||
for (bid, protocol_canidate) in &services.0 {
|
for (bid, protocol_canidate) in &services.0 {
|
||||||
trace!("BID-{bid} protocol_canidate {:?}", protocol_canidate);
|
trace!("BID-{bid} protocol_canidate {:?}", protocol_canidate);
|
||||||
if protocol_canidate == &compare {
|
if protocol_canidate == &compare {
|
||||||
trace!("BufferID({}) => {}", bid, protocol);
|
trace!("BufferID({}) => {}", bid, protocol.clone());
|
||||||
return *bid;
|
return *bid;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
use hbvm::mem::Address;
|
use hbvm::mem::Address;
|
||||||
|
|
||||||
fn calc_start_of_page(ptr: u64) -> u64 {
|
fn calc_start_of_page(ptr: u64) -> u64 {
|
||||||
let _page_aligned = false;
|
let mut page_aligned = false;
|
||||||
if ptr % 4096 == 0 {
|
if ptr % 4096 == 0 {
|
||||||
// page_aligned = true;
|
// page_aligned = true;
|
||||||
return ptr / 4096;
|
return ptr / 4096;
|
||||||
|
@ -21,39 +21,41 @@ pub struct Memory {
|
||||||
|
|
||||||
impl Memory {
|
impl Memory {
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
fn read_device(_addr: Address) {
|
fn read_device(addr: Address) {
|
||||||
//unsafe {
|
unsafe {
|
||||||
//
|
//
|
||||||
// x86_64::instructions::port::Port::new(addr.get()).read()
|
// x86_64::instructions::port::Port::new(addr.get()).read()
|
||||||
//}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl hbvm::mem::Memory for Memory {
|
impl hbvm::mem::Memory for Memory {
|
||||||
#[inline(always)]
|
#[inline]
|
||||||
unsafe fn load(
|
unsafe fn load(
|
||||||
&mut self,
|
&mut self,
|
||||||
addr: Address,
|
addr: Address,
|
||||||
target: *mut u8,
|
target: *mut u8,
|
||||||
count: usize,
|
count: usize,
|
||||||
) -> Result<(), hbvm::mem::LoadError> {
|
) -> Result<(), hbvm::mem::LoadError> {
|
||||||
core::ptr::copy_nonoverlapping(addr.get() as *const u8, target, count);
|
use log::{error, info};
|
||||||
|
if addr.get() % 4096 == 0 {}
|
||||||
|
core::ptr::copy(addr.get() as *const u8, target, count);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline]
|
||||||
unsafe fn store(
|
unsafe fn store(
|
||||||
&mut self,
|
&mut self,
|
||||||
addr: Address,
|
addr: Address,
|
||||||
source: *const u8,
|
source: *const u8,
|
||||||
count: usize,
|
count: usize,
|
||||||
) -> Result<(), hbvm::mem::StoreError> {
|
) -> Result<(), hbvm::mem::StoreError> {
|
||||||
core::ptr::copy_nonoverlapping(source, addr.get() as *mut u8, count);
|
core::ptr::copy(source, addr.get() as *mut u8, count);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline]
|
||||||
unsafe fn prog_read<T: Copy>(&mut self, addr: Address) -> T {
|
unsafe fn prog_read<T: Copy>(&mut self, addr: Address) -> T {
|
||||||
(addr.get() as *const T).read()
|
(addr.get() as *const T).read_unaligned()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,76 +1,77 @@
|
||||||
mod ecah;
|
mod ecah;
|
||||||
pub mod kernel_services;
|
mod kernel_services;
|
||||||
mod mem;
|
mod mem;
|
||||||
|
|
||||||
use {
|
use {
|
||||||
alloc::alloc::{alloc, dealloc},
|
crate::{arch, ipc::buffer::IpcBuffer, kmain::IPC_BUFFERS},
|
||||||
core::{
|
alloc::boxed::Box,
|
||||||
alloc::Layout,
|
core::{default, future::Future, marker::PhantomData, ptr::NonNull, task::Poll},
|
||||||
future::Future,
|
|
||||||
pin::Pin,
|
|
||||||
task::{Context, Poll},
|
|
||||||
},
|
|
||||||
hbvm::{
|
hbvm::{
|
||||||
mem::{softpaging::HandlePageFault, Address},
|
mem::{
|
||||||
|
softpaging::{icache::ICache, HandlePageFault, SoftPagedMem},
|
||||||
|
Address, Memory,
|
||||||
|
},
|
||||||
VmRunError, VmRunOk,
|
VmRunError, VmRunOk,
|
||||||
},
|
},
|
||||||
log::error,
|
log::{debug, error, info, trace, warn},
|
||||||
};
|
};
|
||||||
|
|
||||||
const STACK_SIZE: usize = 1024 * 1024;
|
const STACK_SIZE: usize = 1024 * 1024;
|
||||||
const TIMER_QUOTIENT: usize = 1000;
|
const TIMER_QUOTIENT: usize = 100;
|
||||||
type Vm = hbvm::Vm<mem::Memory, TIMER_QUOTIENT>;
|
type Vm = hbvm::Vm<mem::Memory, TIMER_QUOTIENT>;
|
||||||
|
|
||||||
pub struct ExecThread {
|
pub struct ExecThread<'p> {
|
||||||
vm: Vm,
|
vm: Vm,
|
||||||
stack_bottom: *mut u8,
|
stack_bottom: *mut u8,
|
||||||
|
_phantom: PhantomData<&'p [u8]>,
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl Send for ExecThread {}
|
unsafe impl<'p> Send for ExecThread<'p> {}
|
||||||
|
impl<'p> ExecThread<'p> {
|
||||||
impl ExecThread {
|
|
||||||
pub fn set_arguments(&mut self, ptr: u64, length: u64) {
|
pub fn set_arguments(&mut self, ptr: u64, length: u64) {
|
||||||
self.vm.registers[1] = hbvm::value::Value(ptr);
|
self.vm.registers[1] = hbvm::value::Value(ptr);
|
||||||
self.vm.registers[2] = hbvm::value::Value(length);
|
self.vm.registers[2] = hbvm::value::Value(length);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn new(program: &[u8], entrypoint: Address) -> Self {
|
pub unsafe fn new(program: &'p [u8], entrypoint: Address) -> Self {
|
||||||
let mut vm = Vm::new(
|
let mut vm = unsafe {
|
||||||
mem::Memory {},
|
Vm::new(
|
||||||
Address::new(program.as_ptr() as u64 + entrypoint.get()),
|
mem::Memory {},
|
||||||
);
|
Address::new(program.as_ptr() as u64 + entrypoint.get()),
|
||||||
|
)
|
||||||
let stack_bottom = allocate_stack();
|
};
|
||||||
|
|
||||||
|
let stack_bottom = unsafe { allocate_stack().as_ptr() };
|
||||||
vm.write_reg(254, (stack_bottom as usize + STACK_SIZE - 1) as u64);
|
vm.write_reg(254, (stack_bottom as usize + STACK_SIZE - 1) as u64);
|
||||||
|
|
||||||
ExecThread { 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) {
|
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>;
|
type Output = Result<(), VmRunError>;
|
||||||
|
|
||||||
#[inline(always)]
|
fn poll(
|
||||||
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
mut self: core::pin::Pin<&mut Self>,
|
||||||
|
cx: &mut core::task::Context<'_>,
|
||||||
|
) -> Poll<Self::Output> {
|
||||||
match self.vm.run() {
|
match self.vm.run() {
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
log::error!("HBVM Error\r\nRegister dump: {:?}", self.vm.registers,);
|
log::error!("HBVM Error\r\nRegister dump: {:?}", self.vm.registers,);
|
||||||
return Poll::Ready(Err(err));
|
return Poll::Ready(Err(err));
|
||||||
}
|
}
|
||||||
Ok(VmRunOk::End) => return Poll::Ready(Ok(())),
|
Ok(VmRunOk::End) => return Poll::Ready(Ok(())),
|
||||||
Ok(VmRunOk::Ecall) => ecah::handler(
|
Ok(VmRunOk::Ecall) => ecah::handler(&mut self.vm),
|
||||||
&mut self.vm,
|
|
||||||
cx.ext()
|
|
||||||
.downcast_ref()
|
|
||||||
.expect("PID did not exist in Context"),
|
|
||||||
),
|
|
||||||
Ok(VmRunOk::Timer) => (),
|
Ok(VmRunOk::Timer) => (),
|
||||||
Ok(VmRunOk::Breakpoint) => {
|
Ok(VmRunOk::Breakpoint) => {
|
||||||
log::error!(
|
log::error!(
|
||||||
|
@ -90,22 +91,33 @@ impl HandlePageFault for PageFaultHandler {
|
||||||
fn page_fault(
|
fn page_fault(
|
||||||
&mut self,
|
&mut self,
|
||||||
reason: hbvm::mem::MemoryAccessReason,
|
reason: hbvm::mem::MemoryAccessReason,
|
||||||
_pagetable: &mut hbvm::mem::softpaging::paging::PageTable,
|
pagetable: &mut hbvm::mem::softpaging::paging::PageTable,
|
||||||
vaddr: hbvm::mem::Address,
|
vaddr: hbvm::mem::Address,
|
||||||
size: hbvm::mem::softpaging::PageSize,
|
size: hbvm::mem::softpaging::PageSize,
|
||||||
dataptr: *mut u8,
|
dataptr: *mut u8,
|
||||||
) -> bool {
|
) -> bool
|
||||||
error!("REASON: {reason} vaddr: {vaddr} size: {size:?} Dataptr {dataptr:p}");
|
where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
|
log::error!(
|
||||||
|
"REASON: {reason} \
|
||||||
|
vaddr: {vaddr} \
|
||||||
|
size: {size:?} \
|
||||||
|
Dataptr {dataptr:p}",
|
||||||
|
);
|
||||||
|
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
const fn stack_layout() -> core::alloc::Layout {
|
||||||
const fn stack_layout() -> Layout {
|
unsafe { alloc::alloc::Layout::from_size_align_unchecked(STACK_SIZE, 4096) }
|
||||||
unsafe { Layout::from_size_align_unchecked(STACK_SIZE, 8) }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
fn allocate_stack() -> NonNull<u8> {
|
||||||
fn allocate_stack() -> *mut u8 {
|
let layout = stack_layout();
|
||||||
unsafe { alloc(stack_layout()) }
|
match NonNull::new(unsafe { alloc::alloc::alloc_zeroed(layout) }) {
|
||||||
|
Some(ptr) => ptr,
|
||||||
|
None => alloc::alloc::handle_alloc_error(layout),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,12 +9,12 @@ pub enum BufferTypes {
|
||||||
Bound(ArrayQueue<Message>),
|
Bound(ArrayQueue<Message>),
|
||||||
}
|
}
|
||||||
/// Interproccess buffer
|
/// Interproccess buffer
|
||||||
pub struct IpcBuffer<'a> {
|
pub struct IpcBuffer {
|
||||||
pub protocol: Protocol<'a>,
|
pub protocol: Protocol,
|
||||||
pub buffer: BufferTypes,
|
pub buffer: BufferTypes,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> IpcBuffer<'a> {
|
impl IpcBuffer {
|
||||||
pub fn new(bounded: bool, length: u64) -> Self {
|
pub fn new(bounded: bool, length: u64) -> Self {
|
||||||
log::debug!(
|
log::debug!(
|
||||||
"New IPCBuffer\r
|
"New IPCBuffer\r
|
||||||
|
@ -24,7 +24,7 @@ impl<'a> IpcBuffer<'a> {
|
||||||
length
|
length
|
||||||
);
|
);
|
||||||
match (bounded, length) {
|
match (bounded, length) {
|
||||||
(false, ..) => {
|
(false, a) => {
|
||||||
let buftype = BufferTypes::Unbound(SegQueue::new());
|
let buftype = BufferTypes::Unbound(SegQueue::new());
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
|
@ -48,8 +48,10 @@ impl<'a> IpcBuffer<'a> {
|
||||||
}
|
}
|
||||||
pub fn push(&mut self, msg: Message) {
|
pub fn push(&mut self, msg: Message) {
|
||||||
match &self.buffer {
|
match &self.buffer {
|
||||||
BufferTypes::Unbound(buff) => buff.push(msg),
|
BufferTypes::Unbound(buff) => buff.push(msg.clone()),
|
||||||
BufferTypes::Bound(buff) => buff.push(msg).unwrap(),
|
BufferTypes::Bound(buff) => {
|
||||||
|
let _ = buff.push(msg.clone());
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
pub fn pop(&mut self) -> Result<Message, IpcError> {
|
pub fn pop(&mut self) -> Result<Message, IpcError> {
|
||||||
|
|
|
@ -1,17 +1,21 @@
|
||||||
use {alloc::vec::Vec, hashbrown::HashMap};
|
use {
|
||||||
|
alloc::{string::String, vec::Vec},
|
||||||
|
hashbrown::HashMap,
|
||||||
|
log::info,
|
||||||
|
};
|
||||||
#[derive(Debug, PartialEq, Clone)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub struct Type {}
|
pub struct Type {}
|
||||||
#[derive(Debug, PartialEq, Clone)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub struct Funct<'a> {
|
pub struct Funct {
|
||||||
takes: Vec<&'a str>,
|
takes: Vec<String>,
|
||||||
gives: Vec<&'a str>,
|
gives: Vec<String>,
|
||||||
}
|
}
|
||||||
#[derive(Debug, PartialEq, Clone)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub struct Protocol<'a> {
|
pub struct Protocol {
|
||||||
types: HashMap<&'a str, Type>,
|
types: HashMap<String, Type>,
|
||||||
fns: HashMap<&'a str, Funct<'a>>,
|
fns: HashMap<String, Funct>,
|
||||||
}
|
}
|
||||||
impl<'a> Protocol<'a> {
|
impl Protocol {
|
||||||
pub fn void() -> Self {
|
pub fn void() -> Self {
|
||||||
Self {
|
Self {
|
||||||
types: HashMap::new(),
|
types: HashMap::new(),
|
||||||
|
@ -24,8 +28,8 @@ impl<'a> Protocol<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> From<&'a str> for Protocol<'a> {
|
impl From<String> for Protocol {
|
||||||
fn from(value: &'a str) -> Self {
|
fn from(value: alloc::string::String) -> Self {
|
||||||
let mut hm_t = HashMap::new();
|
let mut hm_t = HashMap::new();
|
||||||
hm_t.insert(value, Type {});
|
hm_t.insert(value, Type {});
|
||||||
Self {
|
Self {
|
||||||
|
|
|
@ -2,40 +2,27 @@
|
||||||
|
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
arch::hardware_random_u64,
|
arch::{hardware_random_u64, logging::SERIAL_CONSOLE},
|
||||||
bootmodules::BootModules,
|
bootmodules::{build_cmd, BootModules},
|
||||||
//bootmodules::build_cmd,
|
capabilities,
|
||||||
device_tree::DeviceTree,
|
device_tree::DeviceTree,
|
||||||
holeybytes::ExecThread,
|
holeybytes::ExecThread,
|
||||||
ipc::buffer::IpcBuffer,
|
ipc::buffer::{self, IpcBuffer},
|
||||||
task::Executor,
|
|
||||||
},
|
},
|
||||||
alloc::boxed::Box,
|
alloc::format,
|
||||||
core::cell::LazyCell,
|
|
||||||
hashbrown::HashMap,
|
hashbrown::HashMap,
|
||||||
hbvm::mem::Address,
|
hbvm::mem::Address,
|
||||||
limine::{Framebuffer, FramebufferRequest, NonNullPtr},
|
limine::{Framebuffer, FramebufferRequest, NonNullPtr},
|
||||||
log::{debug, error, trace},
|
log::{debug, info, trace},
|
||||||
spin::{Lazy, Mutex},
|
spin::{Lazy, Mutex},
|
||||||
|
xml::XMLElement,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn kmain(_cmdline: &str, boot_modules: BootModules) -> ! {
|
pub fn kmain(cmdline: &str, boot_modules: BootModules) -> ! {
|
||||||
debug!("Entered kmain");
|
debug!("Entered kmain");
|
||||||
|
|
||||||
#[cfg(feature = "ktest")]
|
let kcmd = build_cmd("Kernel Command Line", cmdline);
|
||||||
{
|
trace!("Cmdline: {kcmd:?}");
|
||||||
use {
|
|
||||||
crate::ktest,
|
|
||||||
log::info,
|
|
||||||
};
|
|
||||||
info!("Running tests");
|
|
||||||
ktest::test_main();
|
|
||||||
|
|
||||||
loop {}
|
|
||||||
}
|
|
||||||
|
|
||||||
// let kcmd = build_cmd("Kernel Command Line", cmdline);
|
|
||||||
// trace!("Cmdline: {kcmd:?}");
|
|
||||||
|
|
||||||
// for (i, bm) in boot_modules.iter().enumerate() {
|
// for (i, bm) in boot_modules.iter().enumerate() {
|
||||||
// let name = format!("module-{}", i);
|
// let name = format!("module-{}", i);
|
||||||
|
@ -51,9 +38,9 @@ pub fn kmain(_cmdline: &str, boot_modules: BootModules) -> ! {
|
||||||
let dt = DEVICE_TREE.lock();
|
let dt = DEVICE_TREE.lock();
|
||||||
|
|
||||||
// TODO(Able): This line causes a deadlock
|
// TODO(Able): This line causes a deadlock
|
||||||
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 disk driver from the initramfs
|
||||||
// TODO: schedule the filesystem driver from the initramfs
|
// TODO: schedule the filesystem driver from the initramfs
|
||||||
|
@ -65,91 +52,64 @@ pub fn kmain(_cmdline: &str, boot_modules: BootModules) -> ! {
|
||||||
let fb1: &NonNullPtr<Framebuffer> = &FB_REQ.get_response().get().unwrap().framebuffers()[0];
|
let fb1: &NonNullPtr<Framebuffer> = &FB_REQ.get_response().get().unwrap().framebuffers()[0];
|
||||||
|
|
||||||
{
|
{
|
||||||
|
use crate::alloc::string::ToString;
|
||||||
let mut dt = DEVICE_TREE.lock();
|
let mut dt = DEVICE_TREE.lock();
|
||||||
let mut disp = xml::XMLElement::new("display_0");
|
let mut disp = xml::XMLElement::new("display_0");
|
||||||
|
|
||||||
disp.set_attribute("width", fb1.width);
|
disp.set_attribute("width", fb1.width);
|
||||||
disp.set_attribute("height", fb1.height);
|
disp.set_attribute("height", fb1.height);
|
||||||
disp.set_attribute("bpp", fb1.bpp);
|
disp.set_attribute("bits per pixel", fb1.bpp);
|
||||||
disp.set_attribute("pitch", fb1.pitch);
|
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");
|
log::info!("Graphics initialised");
|
||||||
debug!(
|
log::info!(
|
||||||
"Graphics front ptr {:?}",
|
"Graphics front ptr {:?}",
|
||||||
fb1.address.as_ptr().unwrap() as *const u8
|
fb1.address.as_ptr().unwrap() as *const u8
|
||||||
);
|
);
|
||||||
log::info!("Started AbleOS");
|
|
||||||
|
|
||||||
|
let mut executor = crate::task::Executor::default();
|
||||||
|
let bm_take = boot_modules.len();
|
||||||
unsafe {
|
unsafe {
|
||||||
let executor = LazyCell::<Executor>::force_mut(&mut EXECUTOR);
|
for module in boot_modules.into_iter().take(bm_take) {
|
||||||
for module in boot_modules.iter() {
|
let mut cmd = module.cmd;
|
||||||
let cmd = module.cmd.trim_matches('"');
|
if cmd.len() > 2 {
|
||||||
let cmd_len = cmd.len() as u64;
|
// Remove the quotes
|
||||||
|
cmd.remove(0);
|
||||||
log::info!(
|
cmd.pop();
|
||||||
"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;
|
|
||||||
}
|
}
|
||||||
|
let cmd_len = cmd.as_bytes().len() as u64;
|
||||||
|
|
||||||
let executable_format_version = u32::from_le_bytes(header[3..7].try_into().unwrap());
|
log::info!("Spawning {} with arguments \"{}\"", module.path, cmd);
|
||||||
let offset = if executable_format_version == 0 {
|
|
||||||
47
|
|
||||||
} else {
|
|
||||||
error!("Invalid executable format.");
|
|
||||||
continue;
|
|
||||||
};
|
|
||||||
|
|
||||||
let code_length = u64::from_le_bytes(header[7..15].try_into().unwrap());
|
executor.spawn(async move {
|
||||||
let data_length = u64::from_le_bytes(header[15..23].try_into().unwrap());
|
let mut thr = ExecThread::new(&module.bytes, Address::new(0));
|
||||||
let end = (code_length + data_length) as usize;
|
if cmd_len > 0 {
|
||||||
log::debug!("{code_length} + {data_length} = {end}");
|
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 {
|
|
||||||
if let Err(e) = thr.await {
|
if let Err(e) = thr.await {
|
||||||
log::error!("{e:?}");
|
log::error!("{e:?}");
|
||||||
}
|
}
|
||||||
}));
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
debug!("Random number: {}", hardware_random_u64());
|
info!("Random number: {}", hardware_random_u64());
|
||||||
|
|
||||||
executor.run();
|
executor.run();
|
||||||
};
|
};
|
||||||
|
|
||||||
crate::arch::spin_loop()
|
crate::arch::spin_loop()
|
||||||
}
|
}
|
||||||
|
|
||||||
// ! SAFETY: this is not threadsafe at all, like even a little bit.
|
|
||||||
// ! SERIOUSLY
|
|
||||||
pub static mut EXECUTOR: LazyCell<Executor> = LazyCell::new(|| Executor::new());
|
|
||||||
|
|
||||||
pub static DEVICE_TREE: Lazy<Mutex<DeviceTree>> = Lazy::new(|| {
|
pub static DEVICE_TREE: Lazy<Mutex<DeviceTree>> = Lazy::new(|| {
|
||||||
let dt = DeviceTree::new();
|
let dt = DeviceTree::new();
|
||||||
Mutex::new(dt)
|
Mutex::new(dt)
|
||||||
});
|
});
|
||||||
pub static FB_REQ: FramebufferRequest = FramebufferRequest::new(0);
|
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(|| {
|
pub static IPC_BUFFERS: Lazy<Mutex<IpcBuffers>> = Lazy::new(|| {
|
||||||
let mut bufs = HashMap::new();
|
let mut bufs = HashMap::new();
|
||||||
let log_buffer = IpcBuffer::new(false, 0);
|
let log_buffer = IpcBuffer::new(false, 0);
|
||||||
|
@ -160,3 +120,10 @@ pub static IPC_BUFFERS: Lazy<Mutex<IpcBuffers>> = Lazy::new(|| {
|
||||||
|
|
||||||
Mutex::new(bufs)
|
Mutex::new(bufs)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
#[test_case]
|
||||||
|
fn trivial_assertion() {
|
||||||
|
trace!("trivial assertion... ");
|
||||||
|
assert_eq!(1, 1);
|
||||||
|
info!("[ok]");
|
||||||
|
}
|
||||||
|
|
|
@ -1,51 +0,0 @@
|
||||||
pub use ktest_macro::*;
|
|
||||||
|
|
||||||
use {
|
|
||||||
alloc::string::String,
|
|
||||||
log::{error, info},
|
|
||||||
};
|
|
||||||
|
|
||||||
extern "C" {
|
|
||||||
static __ktest_start: fn() -> Result<String, String>;
|
|
||||||
static __ktest_end: fn() -> Result<String, String>;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Implement ktest for arm and riscv (Later problems, see below)
|
|
||||||
// Allow for arch specific tests (Leave for now)
|
|
||||||
// Should panic tests
|
|
||||||
// Test specific panic handler
|
|
||||||
pub fn test_main() {
|
|
||||||
unsafe {
|
|
||||||
let mut current_test = &__ktest_start as *const fn() -> Result<String, String>;
|
|
||||||
let test_end = &__ktest_end as *const fn() -> Result<String, String>;
|
|
||||||
|
|
||||||
let mut pass = 0;
|
|
||||||
let mut fail = 0;
|
|
||||||
|
|
||||||
while current_test < test_end {
|
|
||||||
let test_fn = *current_test;
|
|
||||||
|
|
||||||
let test_name = test_fn();
|
|
||||||
match test_name {
|
|
||||||
Ok(name) => {
|
|
||||||
info!("Test: {} passed", name);
|
|
||||||
pass += 1;
|
|
||||||
},
|
|
||||||
Err(name) => {
|
|
||||||
error!("Test: {} failed", name);
|
|
||||||
fail += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
current_test = current_test.add(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
info!("{}/{} tests passed", pass, pass + fail);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[ktest]
|
|
||||||
pub fn trivial_assertion() {
|
|
||||||
ktest_eq!(1, 1);
|
|
||||||
ktest_neq!(0, 1);
|
|
||||||
}
|
|
|
@ -1,22 +1,21 @@
|
||||||
//! The ableOS kernel.
|
//! The ableOS kernel.
|
||||||
//! Named akern.
|
//! Named akern.
|
||||||
//! Akern is woefully undersupported at the moment but we are looking to add support improve hardware discovery and make our lives as kernel and operating system developers easier and better
|
//! Akern is woefully undersupported at the moment but we are looking to add support improve hardware discovery and make our lives as kernel and operating system developers easier and better
|
||||||
|
|
||||||
#![no_std]
|
#![no_std]
|
||||||
#![no_main]
|
|
||||||
#![feature(
|
#![feature(
|
||||||
slice_split_once,
|
|
||||||
exclusive_wrapper,
|
|
||||||
core_intrinsics,
|
|
||||||
abi_x86_interrupt,
|
abi_x86_interrupt,
|
||||||
lazy_get,
|
|
||||||
alloc_error_handler,
|
alloc_error_handler,
|
||||||
local_waker,
|
inline_const,
|
||||||
context_ext,
|
panic_info_message,
|
||||||
|
pointer_is_aligned,
|
||||||
ptr_sub_ptr,
|
ptr_sub_ptr,
|
||||||
|
custom_test_frameworks,
|
||||||
naked_functions,
|
naked_functions,
|
||||||
pointer_is_aligned_to
|
pointer_is_aligned_to
|
||||||
)]
|
)]
|
||||||
#![allow(dead_code, internal_features, static_mut_refs)]
|
#![allow(dead_code)]
|
||||||
|
#![test_runner(crate::test_runner)]
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
|
|
||||||
mod allocator;
|
mod allocator;
|
||||||
|
@ -24,7 +23,6 @@ mod arch;
|
||||||
mod bootmodules;
|
mod bootmodules;
|
||||||
mod capabilities;
|
mod capabilities;
|
||||||
mod device_tree;
|
mod device_tree;
|
||||||
mod exe_format;
|
|
||||||
mod handle;
|
mod handle;
|
||||||
mod holeybytes;
|
mod holeybytes;
|
||||||
mod ipc;
|
mod ipc;
|
||||||
|
@ -34,9 +32,6 @@ mod memory;
|
||||||
mod task;
|
mod task;
|
||||||
mod utils;
|
mod utils;
|
||||||
|
|
||||||
#[allow(improper_ctypes, non_upper_case_globals)]
|
|
||||||
mod ktest;
|
|
||||||
|
|
||||||
use versioning::Version;
|
use versioning::Version;
|
||||||
|
|
||||||
/// Kernel's version
|
/// Kernel's version
|
||||||
|
@ -47,9 +42,7 @@ pub const VERSION: Version = Version {
|
||||||
};
|
};
|
||||||
|
|
||||||
#[panic_handler]
|
#[panic_handler]
|
||||||
#[cfg(target_os = "none")]
|
|
||||||
fn panic(info: &core::panic::PanicInfo) -> ! {
|
fn panic(info: &core::panic::PanicInfo) -> ! {
|
||||||
use alloc::string::ToString;
|
|
||||||
arch::register_dump();
|
arch::register_dump();
|
||||||
|
|
||||||
if let Some(loc) = info.location() {
|
if let Some(loc) = info.location() {
|
||||||
|
@ -61,7 +54,17 @@ fn panic(info: &core::panic::PanicInfo) -> ! {
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
let msg = info.message().to_string().replace("\n", "\r\n");
|
if let Some(msg) = info.message() {
|
||||||
let _ = crate::arch::log(format_args!("{msg}\r\n"));
|
let _ = crate::arch::log(format_args!("{msg}\r\n"));
|
||||||
|
}
|
||||||
|
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
fn test_runner(tests: &[&dyn Fn()]) {
|
||||||
|
println!("Running {} tests", tests.len());
|
||||||
|
for test in tests {
|
||||||
|
test();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
#![allow(deprecated)]
|
|
||||||
// TODO: Add a logger api with logger levels and various outputs
|
// TODO: Add a logger api with logger levels and various outputs
|
||||||
pub static TERMINAL_LOGGER: Lazy<Mutex<TermLogger>> = Lazy::new(|| Mutex::new(TermLogger::new()));
|
pub static TERMINAL_LOGGER: Lazy<Mutex<TermLogger>> = Lazy::new(|| Mutex::new(TermLogger::new()));
|
||||||
|
|
||||||
|
@ -10,11 +9,7 @@ use {
|
||||||
|
|
||||||
pub fn init() -> Result<(), SetLoggerError> {
|
pub fn init() -> Result<(), SetLoggerError> {
|
||||||
log::set_logger(&crate::logger::Logger)?;
|
log::set_logger(&crate::logger::Logger)?;
|
||||||
if cfg!(debug_assertions) {
|
log::set_max_level(log::LevelFilter::Debug);
|
||||||
log::set_max_level(log::LevelFilter::Debug);
|
|
||||||
} else {
|
|
||||||
log::set_max_level(log::LevelFilter::Info);
|
|
||||||
}
|
|
||||||
|
|
||||||
Lazy::force(&TERMINAL_LOGGER);
|
Lazy::force(&TERMINAL_LOGGER);
|
||||||
|
|
||||||
|
@ -36,26 +31,13 @@ impl log::Log for Logger {
|
||||||
Level::Debug => "25",
|
Level::Debug => "25",
|
||||||
Level::Trace => "103",
|
Level::Trace => "103",
|
||||||
};
|
};
|
||||||
let module = record
|
let module = record.module_path().unwrap_or_default();
|
||||||
.module_path()
|
let line = record.line().unwrap_or_default();
|
||||||
.unwrap_or_default()
|
crate::arch::log(format_args!(
|
||||||
.rsplit_once(':')
|
"\x1b[38;5;{lvl_color}m{lvl}\x1b[0m [{module}:{line}]: {}\r\n",
|
||||||
.unwrap_or_default()
|
record.args(),
|
||||||
.1;
|
))
|
||||||
if module == "" {
|
.expect("write to serial console");
|
||||||
crate::arch::log(format_args!(
|
|
||||||
"\x1b[38;5;{lvl_color}m{lvl}\x1b[0m: {}\r\n",
|
|
||||||
record.args(),
|
|
||||||
))
|
|
||||||
.expect("write to serial console");
|
|
||||||
} else {
|
|
||||||
let line = record.line().unwrap_or_default();
|
|
||||||
crate::arch::log(format_args!(
|
|
||||||
"\x1b[38;5;{lvl_color}m{lvl}\x1b[0m [{module}:{line}]: {}\r\n",
|
|
||||||
record.args(),
|
|
||||||
))
|
|
||||||
.expect("write to serial console");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn flush(&self) {}
|
fn flush(&self) {}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
//! The Memory Manager
|
//! The Memory Manager
|
||||||
|
|
||||||
use {alloc::collections::VecDeque, derive_more::*};
|
use alloc::collections::VecDeque;
|
||||||
|
use derive_more::*;
|
||||||
|
|
||||||
pub use crate::arch::PAGE_SIZE;
|
pub use crate::arch::PAGE_SIZE;
|
||||||
pub const MAX_ORDER: usize = 10;
|
pub const MAX_ORDER: usize = 10;
|
||||||
|
@ -43,7 +44,7 @@ pub const MAX_ORDER: usize = 10;
|
||||||
Sum,
|
Sum,
|
||||||
UpperHex,
|
UpperHex,
|
||||||
)]
|
)]
|
||||||
#[display("0x{:x}", _0)]
|
#[display(fmt = "0x{:x}", _0)]
|
||||||
#[from(forward)]
|
#[from(forward)]
|
||||||
pub struct VirtualAddress(usize);
|
pub struct VirtualAddress(usize);
|
||||||
|
|
||||||
|
@ -54,11 +55,11 @@ impl VirtualAddress {
|
||||||
pub fn vpns(&self) -> [usize; 3] {
|
pub fn vpns(&self) -> [usize; 3] {
|
||||||
[
|
[
|
||||||
// [20:12]
|
// [20:12]
|
||||||
(self.0 >> 12) & 0x1FF,
|
(self.0 >> 12) & 0x1ff,
|
||||||
// [29:21]
|
// [29:21]
|
||||||
(self.0 >> 21) & 0x1FF,
|
(self.0 >> 21) & 0x1ff,
|
||||||
// [38:30]
|
// [38:30]
|
||||||
(self.0 >> 30) & 0x1FF,
|
(self.0 >> 30) & 0x1ff,
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -113,7 +114,7 @@ impl VirtualAddress {
|
||||||
Sum,
|
Sum,
|
||||||
UpperHex,
|
UpperHex,
|
||||||
)]
|
)]
|
||||||
#[display("0x{:x}", _0)]
|
#[display(fmt = "0x{:x}", _0)]
|
||||||
#[from(forward)]
|
#[from(forward)]
|
||||||
pub struct PhysicalAddress(usize);
|
pub struct PhysicalAddress(usize);
|
||||||
|
|
||||||
|
@ -124,11 +125,11 @@ impl PhysicalAddress {
|
||||||
pub fn ppns(&self) -> [usize; 3] {
|
pub fn ppns(&self) -> [usize; 3] {
|
||||||
[
|
[
|
||||||
// [20:12]
|
// [20:12]
|
||||||
(self.0 >> 12) & 0x1FF,
|
(self.0 >> 12) & 0x1ff,
|
||||||
// [29:21]
|
// [29:21]
|
||||||
(self.0 >> 21) & 0x1FF,
|
(self.0 >> 21) & 0x1ff,
|
||||||
// [55:30]
|
// [55:30]
|
||||||
(self.0 >> 30) & 0x3FFFFFF,
|
(self.0 >> 30) & 0x3ffffff,
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,19 +1,26 @@
|
||||||
|
#![allow(unused)]
|
||||||
|
|
||||||
use {
|
use {
|
||||||
alloc::{
|
alloc::{boxed::Box, collections::BTreeMap, sync::Arc, task::Wake},
|
||||||
boxed::Box,
|
|
||||||
collections::{BTreeMap, BTreeSet},
|
|
||||||
sync::Arc,
|
|
||||||
},
|
|
||||||
core::{
|
core::{
|
||||||
future::Future,
|
future::Future,
|
||||||
pin::Pin,
|
pin::Pin,
|
||||||
sync::atomic::{AtomicBool, Ordering},
|
task::{Context, Poll, Waker},
|
||||||
task::{Context, ContextBuilder, Poll, RawWaker, RawWakerVTable, Waker},
|
|
||||||
},
|
},
|
||||||
crossbeam_queue::SegQueue,
|
crossbeam_queue::SegQueue,
|
||||||
|
kiam::when,
|
||||||
slab::Slab,
|
slab::Slab,
|
||||||
|
spin::RwLock,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static SPAWN_QUEUE: RwLock<Option<SpawnQueue>> = RwLock::new(None);
|
||||||
|
pub fn spawn(future: impl Future<Output = ()> + Send + 'static) {
|
||||||
|
match &*SPAWN_QUEUE.read() {
|
||||||
|
Some(s) => s.push(Task::new(future)),
|
||||||
|
None => panic!("no task executor is running"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn yield_now() -> impl Future<Output = ()> {
|
pub fn yield_now() -> impl Future<Output = ()> {
|
||||||
struct YieldNow(bool);
|
struct YieldNow(bool);
|
||||||
impl Future for YieldNow {
|
impl Future for YieldNow {
|
||||||
|
@ -33,184 +40,101 @@ pub fn yield_now() -> impl Future<Output = ()> {
|
||||||
YieldNow(false)
|
YieldNow(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Process: Future<Output = ()> + Send {}
|
#[derive(Default)]
|
||||||
impl<T: Future<Output = ()> + Send> Process for T {}
|
|
||||||
|
|
||||||
pub struct Executor {
|
pub struct Executor {
|
||||||
tasks: Slab<Task>,
|
tasks: Slab<Task>,
|
||||||
task_queue: Arc<SegQueue<usize>>,
|
queue: TaskQueue,
|
||||||
interrupt_lookup: [Option<usize>; u8::MAX as usize],
|
to_spawn: SpawnQueue,
|
||||||
buffer_lookup: BTreeMap<usize, BTreeSet<usize>>,
|
wakers: BTreeMap<TaskId, Waker>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Executor {
|
impl Executor {
|
||||||
pub fn new() -> Self {
|
pub fn spawn(&mut self, future: impl Future<Output = ()> + Send + 'static) {
|
||||||
Self {
|
self.queue
|
||||||
tasks: Slab::new(),
|
.push(TaskId(self.tasks.insert(Task::new(future))));
|
||||||
task_queue: Arc::new(SegQueue::new()),
|
|
||||||
interrupt_lookup: [None; u8::MAX as usize],
|
|
||||||
buffer_lookup: BTreeMap::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn spawn(&mut self, future: Pin<Box<dyn Process>>) -> usize {
|
|
||||||
let id = self.tasks.insert(Task::new(future));
|
|
||||||
self.task_queue.push(id);
|
|
||||||
|
|
||||||
id
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn pause(&self, id: usize) {
|
|
||||||
if let Some(task) = self.tasks.get(id) {
|
|
||||||
task.set_paused(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn unpause(&self, id: usize) {
|
|
||||||
if let Some(task) = self.tasks.get(id) {
|
|
||||||
task.set_paused(false);
|
|
||||||
self.task_queue.push(id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn interrupt_subscribe(&mut self, pid: usize, interrupt_type: u8) {
|
|
||||||
self.pause(pid);
|
|
||||||
self.interrupt_lookup[interrupt_type as usize] = Some(pid);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn buffer_subscribe(&mut self, pid: usize, buffer_id: usize) {
|
|
||||||
self.pause(pid);
|
|
||||||
if let Some(buf) = self.buffer_lookup.get_mut(&buffer_id) {
|
|
||||||
buf.insert(pid);
|
|
||||||
} else {
|
|
||||||
self.buffer_lookup.insert(buffer_id, BTreeSet::from([pid]));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run(&mut self) {
|
pub fn run(&mut self) {
|
||||||
let mut task_batch = [0; 32];
|
{
|
||||||
|
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 {
|
loop {
|
||||||
let mut batch_len = 0;
|
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);
|
||||||
|
};
|
||||||
|
|
||||||
while let Some(id) = self.task_queue.pop() {
|
let mut cx = Context::from_waker(self.wakers.entry(id).or_insert_with(|| {
|
||||||
task_batch[batch_len] = id;
|
Waker::from(Arc::new(TaskWaker {
|
||||||
batch_len += 1;
|
id,
|
||||||
if batch_len == task_batch.len() {
|
queue: Arc::clone(&self.queue),
|
||||||
break;
|
}))
|
||||||
}
|
}));
|
||||||
}
|
|
||||||
|
|
||||||
if batch_len == 0 {
|
match task.poll(&mut cx) {
|
||||||
// break;
|
Poll::Ready(()) => {
|
||||||
continue;
|
self.tasks.remove(id.0);
|
||||||
}
|
self.wakers.remove(&id);
|
||||||
|
}
|
||||||
for &(mut id) in &task_batch[..batch_len] {
|
Poll::Pending => (),
|
||||||
if let Some(task) = self.tasks.get_mut(id) {
|
|
||||||
if task.is_paused() {
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
},
|
||||||
let waker = create_waker(id, Arc::clone(&self.task_queue));
|
self.tasks.is_empty() => break,
|
||||||
let mut cx = ContextBuilder::from_waker(&waker).ext(&mut id).build();
|
_ => (),
|
||||||
|
|
||||||
if let Poll::Ready(()) = task.poll(&mut cx) {
|
|
||||||
self.tasks.remove(id);
|
|
||||||
self.interrupt_lookup.map(|pid| {
|
|
||||||
if let Some(pid) = pid {
|
|
||||||
if pid == id {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return pid;
|
|
||||||
});
|
|
||||||
self.buffer_lookup.iter_mut().for_each(|(_, pid_set)| {
|
|
||||||
pid_set.remove(&id);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
pub fn send_interrupt(&self, interrupt: u8) {
|
*SPAWN_QUEUE.write() = None;
|
||||||
let id = self.interrupt_lookup[interrupt as usize];
|
|
||||||
if let Some(id) = id {
|
|
||||||
self.unpause(id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub fn send_buffer(&self, id: usize) {
|
|
||||||
if let Some(buf) = self.buffer_lookup.get(&id) {
|
|
||||||
buf.iter().for_each(|pid| self.unpause(*pid));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Task {
|
struct Task {
|
||||||
future: Pin<Box<dyn Process>>,
|
future: Pin<Box<dyn Future<Output = ()> + Send>>,
|
||||||
paused: AtomicBool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Task {
|
impl Task {
|
||||||
fn new(future: Pin<Box<dyn Process>>) -> Self {
|
pub fn new(future: impl Future<Output = ()> + Send + 'static) -> Self {
|
||||||
|
log::trace!("New task scheduled");
|
||||||
Self {
|
Self {
|
||||||
future,
|
future: Box::pin(future),
|
||||||
paused: AtomicBool::new(false),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn poll(&mut self, cx: &mut Context) -> Poll<()> {
|
fn poll(&mut self, cx: &mut Context) -> Poll<()> {
|
||||||
self.future.as_mut().poll(cx)
|
self.future.as_mut().poll(cx)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_paused(&self) -> bool {
|
|
||||||
self.paused.load(Ordering::Acquire)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_paused(&self, paused: bool) {
|
|
||||||
self.paused.store(paused, Ordering::Release)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_waker(task_id: usize, task_queue: Arc<SegQueue<usize>>) -> Waker {
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
let data = Box::new(TaskWaker {
|
struct TaskId(usize);
|
||||||
task_id,
|
|
||||||
task_queue,
|
type TaskQueue = Arc<SegQueue<TaskId>>;
|
||||||
});
|
type SpawnQueue = Arc<SegQueue<Task>>;
|
||||||
let raw_waker = RawWaker::new(Box::into_raw(data) as *const (), &VTABLE);
|
|
||||||
unsafe { Waker::from_raw(raw_waker) }
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
struct TaskWaker {
|
struct TaskWaker {
|
||||||
task_id: usize,
|
id: TaskId,
|
||||||
task_queue: Arc<SegQueue<usize>>,
|
queue: TaskQueue,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TaskWaker {
|
impl Wake for TaskWaker {
|
||||||
fn wake(&self) {
|
fn wake(self: Arc<Self>) {
|
||||||
self.task_queue.push(self.task_id);
|
log::trace!("Woke Task-{:?}", self.id);
|
||||||
|
self.wake_by_ref();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn wake_by_ref(self: &Arc<Self>) {
|
||||||
|
self.queue.push(self.id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const VTABLE: RawWakerVTable = RawWakerVTable::new(clone_raw, wake_raw, wake_by_ref_raw, drop_raw);
|
|
||||||
|
|
||||||
unsafe fn clone_raw(ptr: *const ()) -> RawWaker {
|
|
||||||
let task_waker = Box::from_raw(ptr as *mut TaskWaker);
|
|
||||||
let raw_waker = RawWaker::new(Box::into_raw(task_waker.clone()) as *const (), &VTABLE);
|
|
||||||
raw_waker
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe fn wake_raw(ptr: *const ()) {
|
|
||||||
let task_waker = Box::from_raw(ptr as *mut TaskWaker);
|
|
||||||
task_waker.wake();
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe fn wake_by_ref_raw(ptr: *const ()) {
|
|
||||||
let task_waker = &*(ptr as *const TaskWaker);
|
|
||||||
task_waker.wake();
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe fn drop_raw(ptr: *const ()) {
|
|
||||||
drop(Box::from_raw(ptr as *mut TaskWaker));
|
|
||||||
}
|
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
/// Used when tab `\t` in hardware is not known and we will default to two spaces
|
/// Used when tab `\t` in hardware is not known and we will default to two spaces
|
||||||
pub const TAB: &str = " ";
|
pub const TAB: &str = " ";
|
||||||
|
|
||||||
|
|
||||||
// NOTE: this only reduces the code duplication in source code not in generated code!
|
// NOTE: this only reduces the code duplication in source code not in generated code!
|
||||||
// Written by Yours Truly: Munir
|
// Written by Yours Truly: Munir
|
||||||
/// A simple macro to reduce code duplication when we use TAB internally
|
/// A simple macro to reduce code duplication when we use TAB internally
|
||||||
|
@ -11,7 +12,7 @@ pub const TAB: &str = " ";
|
||||||
macro_rules! tab {
|
macro_rules! tab {
|
||||||
($num:expr) => {
|
($num:expr) => {
|
||||||
TAB.repeat($num)
|
TAB.repeat($num)
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: this only reduces the code duplication in source code not in generated code!
|
// NOTE: this only reduces the code duplication in source code not in generated code!
|
||||||
|
@ -21,7 +22,7 @@ macro_rules! tab {
|
||||||
macro_rules! device_tree {
|
macro_rules! device_tree {
|
||||||
($devtree:expr, $dev_type_vec:expr) => {
|
($devtree:expr, $dev_type_vec:expr) => {
|
||||||
for each_device_type in $dev_type_vec {
|
for each_device_type in $dev_type_vec {
|
||||||
$devtree.devices.insert(each_device_type, Vec::new());
|
$devtree.devices.insert(each_device_type.to_string(), Vec::new());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,25 +1,25 @@
|
||||||
{
|
{
|
||||||
"arch": "aarch64",
|
"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,
|
"disable-redzone": true,
|
||||||
"env": "",
|
"env": "",
|
||||||
"executables": true,
|
"executables": true,
|
||||||
"features": "+strict-align,+neon,+fp-armv8",
|
"features": "+strict-align,+neon,+fp-armv8",
|
||||||
"linker": "rust-lld",
|
"linker": "rust-lld",
|
||||||
"linker-flavor": "ld.lld",
|
"linker-flavor": "ld.lld",
|
||||||
"linker-is-gnu": true,
|
"linker-is-gnu": true,
|
||||||
"pre-link-args": {
|
"pre-link-args": {
|
||||||
"ld.lld": [
|
"ld.lld": [
|
||||||
"-Tkernel/lds/aarch64-qemu.ld"
|
"-Tkernel/lds/aarch64-qemu.ld"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"llvm-target": "aarch64-unknown-none",
|
"llvm-target": "aarch64-unknown-none",
|
||||||
"max-atomic-width": 128,
|
"max-atomic-width": 128,
|
||||||
"os": "none",
|
"os": "none",
|
||||||
"panic-strategy": "abort",
|
"panic-strategy": "abort",
|
||||||
"relocation-model": "static",
|
"relocation-model": "static",
|
||||||
"target-c-int-width": "32",
|
"target-c-int-width": "32",
|
||||||
"target-endian": "little",
|
"target-endian": "little",
|
||||||
"target-pointer-width": "64",
|
"target-pointer-width": "64",
|
||||||
"vendor": "ablecorp"
|
"vendor": ""
|
||||||
}
|
}
|
|
@ -1,22 +1,22 @@
|
||||||
{
|
{
|
||||||
"llvm-target": "x86_64-unknown-none",
|
"llvm-target": "x86_64-unknown-none",
|
||||||
"data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128",
|
"data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128",
|
||||||
"arch": "x86_64",
|
"arch": "x86_64",
|
||||||
"target-endian": "little",
|
"target-endian": "little",
|
||||||
"target-pointer-width": "64",
|
"target-pointer-width": "64",
|
||||||
"target-c-int-width": "32",
|
"target-c-int-width": "32",
|
||||||
"os": "none",
|
"os": "none",
|
||||||
"executables": true,
|
"executables": true,
|
||||||
"linker-flavor": "ld.lld",
|
"linker-flavor": "ld.lld",
|
||||||
"linker": "rust-lld",
|
"linker": "rust-lld",
|
||||||
"panic-strategy": "abort",
|
"panic-strategy": "abort",
|
||||||
"disable-redzone": true,
|
"disable-redzone": true,
|
||||||
"features": "",
|
"features": "",
|
||||||
"code-model": "kernel",
|
"code-model": "kernel",
|
||||||
"pre-link-args": {
|
"pre-link-args": {
|
||||||
"ld.lld": [
|
"ld.lld": [
|
||||||
"--gc-sections",
|
"--gc-sections",
|
||||||
"--script=kernel/lds/x86_64.ld"
|
"--script=kernel/lds/x86_64.ld"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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,15 @@ version = "0.2.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
str-reader = "0.1"
|
str-reader = "0.1.2"
|
||||||
derive_more = { version = "1", default-features = false, features = [
|
derive_more = "0.99"
|
||||||
"display",
|
error-stack = "0.4"
|
||||||
] }
|
fatfs = "0.3"
|
||||||
error-stack = "0.5"
|
toml = "0.5.2"
|
||||||
fatfs = { version = "0.3", default-features = false, features = [
|
# hbasm.git = "https://git.ablecorp.us/AbleOS/holey-bytes.git"
|
||||||
"std",
|
|
||||||
"alloc",
|
|
||||||
] }
|
|
||||||
toml = "0.8"
|
|
||||||
hblang.git = "https://git.ablecorp.us/AbleOS/holey-bytes.git"
|
hblang.git = "https://git.ablecorp.us/AbleOS/holey-bytes.git"
|
||||||
log = "0.4"
|
|
||||||
raw-cpuid = "11"
|
[dependencies.reqwest]
|
||||||
ureq = { version = "2", default-features = false, features = ["tls"] }
|
version = "0.11"
|
||||||
|
default-features = false
|
||||||
|
features = ["rustls-tls", "blocking"]
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
#![allow(unused)]
|
|
||||||
use std::{
|
use std::{
|
||||||
collections::HashMap,
|
|
||||||
fmt::format,
|
fmt::format,
|
||||||
fs::{read_to_string, File},
|
fs::{read_to_string, File},
|
||||||
io::{BufWriter, Write},
|
io::{BufWriter, Write},
|
||||||
|
@ -14,7 +12,6 @@ pub struct Package {
|
||||||
name: String,
|
name: String,
|
||||||
binaries: Vec<String>,
|
binaries: Vec<String>,
|
||||||
build_cmd: String,
|
build_cmd: String,
|
||||||
args: HashMap<String, String>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Package {
|
impl Package {
|
||||||
|
@ -48,81 +45,49 @@ impl Package {
|
||||||
let mut binaries = vec![];
|
let mut binaries = vec![];
|
||||||
|
|
||||||
for (count, (name, table)) in bin_table.into_iter().enumerate() {
|
for (count, (name, table)) in bin_table.into_iter().enumerate() {
|
||||||
|
// if count != 0 {
|
||||||
|
println!("{}", name);
|
||||||
binaries.push(name.clone());
|
binaries.push(name.clone());
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
let build_table = data.get("build").unwrap();
|
let build_table = data.get("build").unwrap();
|
||||||
|
|
||||||
let mut build_cmd: String = build_table.get("command").unwrap().as_str().unwrap().into();
|
let mut build_cmd: String = build_table.get("command").unwrap().as_str().unwrap().into();
|
||||||
build_cmd.remove(0);
|
build_cmd.remove(0);
|
||||||
let mut args: HashMap<String, String> = match build_table.get("args") {
|
// build_cmd.pop();
|
||||||
None => HashMap::new(),
|
|
||||||
Some(v) => v
|
|
||||||
.as_table()
|
|
||||||
.unwrap()
|
|
||||||
.into_iter()
|
|
||||||
.map(|(k, v)| (k.clone(), v.to_string()))
|
|
||||||
.collect::<HashMap<String, String>>(),
|
|
||||||
};
|
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
name,
|
name,
|
||||||
binaries,
|
binaries,
|
||||||
build_cmd,
|
build_cmd,
|
||||||
args,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn build(&self, out: &mut Vec<u8>) -> std::io::Result<()> {
|
pub fn build(&self) {
|
||||||
if self.binaries.contains(&"hblang".to_string()) {
|
if self.binaries.contains(&"hblang".to_string()) {
|
||||||
let file = self.build_cmd.split_ascii_whitespace().last().unwrap();
|
let file = self.build_cmd.split_ascii_whitespace().last().unwrap();
|
||||||
|
|
||||||
let path = format!("sysdata/programs/{}/{}", self.name, file);
|
let path = format!("sysdata/programs/{}/{}", self.name, file);
|
||||||
|
let mut bytes = Vec::new();
|
||||||
// compile here
|
// compile here
|
||||||
|
|
||||||
let mut warnings = String::new();
|
let _ = hblang::run_compiler(
|
||||||
|
|
||||||
hblang::run_compiler(
|
|
||||||
&path,
|
&path,
|
||||||
Options {
|
Options {
|
||||||
fmt: true,
|
fmt: true,
|
||||||
resolver: Some(hblang::ABLEOS_PATH_RESOLVER),
|
|
||||||
|
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
out,
|
&mut bytes,
|
||||||
&mut warnings,
|
);
|
||||||
)?;
|
let _ = hblang::run_compiler(&path, Default::default(), &mut bytes);
|
||||||
|
|
||||||
match std::fs::create_dir("target/programs") {
|
match std::fs::create_dir("target/programs") {
|
||||||
Ok(_) => (),
|
Ok(_) => (),
|
||||||
Err(e) if e.kind() == std::io::ErrorKind::AlreadyExists => (),
|
Err(e) if e.kind() == std::io::ErrorKind::AlreadyExists => (),
|
||||||
Err(e) => panic!("{}", e),
|
Err(e) => panic!("{}", e),
|
||||||
}
|
}
|
||||||
|
let path = format!("target/programs/{}.hbf", self.name);
|
||||||
hblang::run_compiler(
|
let mut file = File::create(path).unwrap();
|
||||||
&path,
|
file.write_all(&bytes).unwrap();
|
||||||
Options {
|
|
||||||
resolver: Some(hblang::ABLEOS_PATH_RESOLVER),
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
out,
|
|
||||||
&mut warnings,
|
|
||||||
)?;
|
|
||||||
std::fs::write(format!("target/programs/{}.hbf", self.name), &out)?;
|
|
||||||
out.clear();
|
|
||||||
|
|
||||||
hblang::run_compiler(
|
|
||||||
&path,
|
|
||||||
Options {
|
|
||||||
resolver: Some(hblang::ABLEOS_PATH_RESOLVER),
|
|
||||||
dump_asm: true,
|
|
||||||
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
out,
|
|
||||||
&mut warnings,
|
|
||||||
)?;
|
|
||||||
std::fs::write(format!("target/programs/{}.hba", self.name), &out)?;
|
|
||||||
out.clear();
|
|
||||||
}
|
}
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,16 +1,16 @@
|
||||||
mod dev;
|
mod dev;
|
||||||
|
|
||||||
use {
|
use {
|
||||||
core::fmt::Write as _,
|
|
||||||
derive_more::Display,
|
derive_more::Display,
|
||||||
dev::Package,
|
dev::Package,
|
||||||
error_stack::{bail, report, Context, Report, Result, ResultExt},
|
error_stack::{bail, report, Context, Report, Result, ResultExt},
|
||||||
fatfs::{FileSystem, FormatVolumeOptions, FsOptions, ReadWriteSeek},
|
fatfs::{FileSystem, FormatVolumeOptions, FsOptions, ReadWriteSeek},
|
||||||
std::{
|
std::{
|
||||||
|
fmt::Display,
|
||||||
fs::{self, File},
|
fs::{self, File},
|
||||||
io::{self, Write},
|
io::{self, Write},
|
||||||
path::Path,
|
path::Path,
|
||||||
process::{exit, Command, Stdio},
|
process::{exit, Command},
|
||||||
},
|
},
|
||||||
toml::Value,
|
toml::Value,
|
||||||
};
|
};
|
||||||
|
@ -19,85 +19,41 @@ fn main() -> Result<(), Error> {
|
||||||
let mut args = std::env::args();
|
let mut args = std::env::args();
|
||||||
args.next();
|
args.next();
|
||||||
|
|
||||||
log::set_logger(&hblang::Logger).unwrap();
|
|
||||||
log::set_max_level(log::LevelFilter::Error);
|
|
||||||
|
|
||||||
match args.next().as_deref() {
|
match args.next().as_deref() {
|
||||||
Some("build" | "b") => {
|
Some("build" | "b") => {
|
||||||
let mut release = false;
|
let mut release = false;
|
||||||
let mut debuginfo = false;
|
|
||||||
let mut target = Target::X86_64;
|
let mut target = Target::X86_64;
|
||||||
let mut tests = false;
|
|
||||||
for arg in args {
|
for arg in args {
|
||||||
if arg == "-r" || arg == "--release" {
|
if arg == "-r" || arg == "--release" {
|
||||||
release = true;
|
release = true;
|
||||||
} else if arg == "-d" || arg == "--debuginfo" {
|
|
||||||
debuginfo = true;
|
|
||||||
} else if arg == "rv64" || arg == "riscv64" || arg == "riscv64-virt" {
|
} else if arg == "rv64" || arg == "riscv64" || arg == "riscv64-virt" {
|
||||||
target = Target::Riscv64Virt;
|
target = Target::Riscv64Virt;
|
||||||
} else if arg == "arm64" || arg == "aarch64" || arg == "aarch64-virt" {
|
} else if arg == "arm64" || arg == "aarch64" || arg == "aarch64-virt" {
|
||||||
target = Target::Aarch64;
|
target = Target::Aarch64;
|
||||||
} else if arg == "avx2" {
|
|
||||||
target = Target::X86_64Avx2;
|
|
||||||
} else if arg == "--ktest" {
|
|
||||||
tests = true;
|
|
||||||
} else {
|
} else {
|
||||||
return Err(report!(Error::InvalidSubCom));
|
return Err(report!(Error::InvalidSubCom));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
build(release, target, debuginfo, tests).change_context(Error::Build)
|
build(release, target).change_context(Error::Build)
|
||||||
}
|
}
|
||||||
// Some("test" | "t") => {
|
|
||||||
// let mut release = false;
|
|
||||||
// let mut debuginfo = false;
|
|
||||||
// let mut target = Target::X86_64;
|
|
||||||
// for arg in args {
|
|
||||||
// if arg == "-r" || arg == "--release" {
|
|
||||||
// release = true;
|
|
||||||
// } else if arg == "-d" || arg == "--debuginfo" {
|
|
||||||
// debuginfo = true;
|
|
||||||
// } else if arg == "rv64" || arg == "riscv64" || arg == "riscv64-virt" {
|
|
||||||
// target = Target::Riscv64Virt;
|
|
||||||
// } else if arg == "arm64" || arg == "aarch64" || arg == "aarch64-virt" {
|
|
||||||
// target = Target::Aarch64;
|
|
||||||
// } else if arg == "avx2" {
|
|
||||||
// target = Target::X86_64Avx2;
|
|
||||||
// } else {
|
|
||||||
// return Err(report!(Error::InvalidSubCom));
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// test(release, target, debuginfo).change_context(Error::Build)
|
|
||||||
// }
|
|
||||||
Some("run" | "r") => {
|
Some("run" | "r") => {
|
||||||
let mut release = false;
|
let mut release = false;
|
||||||
let mut debuginfo = false;
|
|
||||||
let mut target = Target::X86_64;
|
let mut target = Target::X86_64;
|
||||||
let mut tests = false;
|
|
||||||
let mut do_accel = true;
|
|
||||||
for arg in args {
|
for arg in args {
|
||||||
if arg == "-r" || arg == "--release" {
|
if arg == "-r" || arg == "--release" {
|
||||||
release = true;
|
release = true;
|
||||||
} else if arg == "-d" || arg == "--debuginfo" {
|
|
||||||
debuginfo = true;
|
|
||||||
} else if arg == "rv64" || arg == "riscv64" || arg == "riscv64-virt" {
|
} else if arg == "rv64" || arg == "riscv64" || arg == "riscv64-virt" {
|
||||||
target = Target::Riscv64Virt;
|
target = Target::Riscv64Virt;
|
||||||
} else if arg == "arm64" || arg == "aarch64" || arg == "aarch64-virt" {
|
} else if arg == "arm64" || arg == "aarch64" || arg == "aarch64-virt" {
|
||||||
target = Target::Aarch64;
|
target = Target::Aarch64;
|
||||||
} else if arg == "--noaccel" {
|
|
||||||
do_accel = false;
|
|
||||||
} else if arg == "avx2" {
|
|
||||||
target = Target::X86_64Avx2;
|
|
||||||
} else if arg == "--ktest" {
|
|
||||||
tests = true;
|
|
||||||
} else {
|
} else {
|
||||||
return Err(report!(Error::InvalidSubCom));
|
return Err(report!(Error::InvalidSubCom));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
build(release, target, debuginfo, tests)?;
|
build(release, target)?;
|
||||||
run(release, target, do_accel)
|
run(release, target)
|
||||||
}
|
}
|
||||||
Some("help" | "h") => {
|
Some("help" | "h") => {
|
||||||
println!(concat!(
|
println!(concat!(
|
||||||
|
@ -107,11 +63,8 @@ fn main() -> Result<(), Error> {
|
||||||
" help (h): Print this message\n",
|
" help (h): Print this message\n",
|
||||||
" run (r): Build and run AbleOS in QEMU\n\n",
|
" run (r): Build and run AbleOS in QEMU\n\n",
|
||||||
"Options for build and run:\n",
|
"Options for build and run:\n",
|
||||||
" -r / --release: build in release mode\n",
|
" -r: build in release mode",
|
||||||
" -d / --debuginfo: build with debug info\n",
|
" [target]: sets target"
|
||||||
" --noaccel: run without acceleration (e.g, no kvm)\n",
|
|
||||||
" --ktest: Enables tests via ktest\n",
|
|
||||||
"[ rv64 / riscv64 / riscv64-virt / aarch64 / arm64 / aarch64-virt / avx2 ]: sets target"
|
|
||||||
),);
|
),);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -234,43 +187,21 @@ TERM_BACKDROP={}
|
||||||
let modules = value.get_mut("modules").unwrap().as_table_mut().unwrap();
|
let modules = value.get_mut("modules").unwrap().as_table_mut().unwrap();
|
||||||
// let mut real_modules = modules.clone();
|
// let mut real_modules = modules.clone();
|
||||||
|
|
||||||
let mut errors = String::new();
|
modules.into_iter().for_each(|(key, value)| {
|
||||||
let mut out = Vec::new();
|
if value.is_table() {
|
||||||
|
let path = get_path_without_boot_prefix(
|
||||||
modules
|
value.get("path").expect("You must have `path` as a value"),
|
||||||
.into_iter()
|
)
|
||||||
.map(|(_, value)| -> Result<(), io::Error> {
|
.unwrap()
|
||||||
if value.is_table() {
|
.split(".")
|
||||||
let path = get_path_without_boot_prefix(
|
.next()
|
||||||
value.get("path").expect("You must have `path` as a value"),
|
.unwrap();
|
||||||
)
|
let p = Package::load_from_file(
|
||||||
.unwrap()
|
format!("sysdata/programs/{}/meta.toml", path).to_owned(),
|
||||||
.split(".")
|
);
|
||||||
.next()
|
p.build();
|
||||||
.unwrap();
|
}
|
||||||
let p = Package::load_from_file(
|
});
|
||||||
format!("sysdata/programs/{}/meta.toml", path).to_owned(),
|
|
||||||
);
|
|
||||||
match p.build(&mut out) {
|
|
||||||
Ok(()) => {}
|
|
||||||
Err(_) => {
|
|
||||||
writeln!(errors, "========= while compiling {} =========", path)
|
|
||||||
.unwrap();
|
|
||||||
errors.push_str(core::str::from_utf8(&out).expect("no"));
|
|
||||||
out.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
})
|
|
||||||
.for_each(drop);
|
|
||||||
|
|
||||||
if !errors.is_empty() {
|
|
||||||
let _ = writeln!(errors, "!!! STOPPING DUE TO PREVIOUS ERRORS !!!");
|
|
||||||
std::eprint!("{errors}");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
modules.into_iter().for_each(|(_key, value)| {
|
modules.into_iter().for_each(|(_key, value)| {
|
||||||
if value.is_table() {
|
if value.is_table() {
|
||||||
let path = value.get("path").expect("You must have `path` as a value");
|
let path = value.get("path").expect("You must have `path` as a value");
|
||||||
|
@ -305,7 +236,7 @@ TERM_BACKDROP={}
|
||||||
let bootdir = fs.root_dir().create_dir("efi")?.create_dir("boot")?;
|
let bootdir = fs.root_dir().create_dir("efi")?.create_dir("boot")?;
|
||||||
|
|
||||||
let mut f = fs.root_dir().create_file("limine.cfg")?;
|
let mut f = fs.root_dir().create_file("limine.cfg")?;
|
||||||
let _ = f.write(limine_str.as_bytes())?;
|
let a = f.write(limine_str.as_bytes())?;
|
||||||
drop(f);
|
drop(f);
|
||||||
|
|
||||||
io::copy(
|
io::copy(
|
||||||
|
@ -339,7 +270,7 @@ fn copy_file_to_img(fpath: &str, fs: &FileSystem<File>) {
|
||||||
.expect("Copy failed");
|
.expect("Copy failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build(release: bool, target: Target, debuginfo: bool, tests: bool) -> Result<(), Error> {
|
fn build(release: bool, target: Target) -> Result<(), Error> {
|
||||||
let fs = get_fs().change_context(Error::Io)?;
|
let fs = get_fs().change_context(Error::Io)?;
|
||||||
let mut com = Command::new("cargo");
|
let mut com = Command::new("cargo");
|
||||||
com.current_dir("kernel");
|
com.current_dir("kernel");
|
||||||
|
@ -347,13 +278,6 @@ fn build(release: bool, target: Target, debuginfo: bool, tests: bool) -> Result<
|
||||||
if release {
|
if release {
|
||||||
com.arg("-r");
|
com.arg("-r");
|
||||||
}
|
}
|
||||||
if debuginfo {
|
|
||||||
com.env("RUSTFLAGS", "-Cdebug-assertions=true");
|
|
||||||
}
|
|
||||||
|
|
||||||
if tests {
|
|
||||||
com.args(["--features", "ktest"]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if target == Target::Riscv64Virt {
|
if target == Target::Riscv64Virt {
|
||||||
com.args(["--target", "targets/riscv64-virt-ableos.json"]);
|
com.args(["--target", "targets/riscv64-virt-ableos.json"]);
|
||||||
|
@ -361,9 +285,6 @@ fn build(release: bool, target: Target, debuginfo: bool, tests: bool) -> Result<
|
||||||
if target == Target::Aarch64 {
|
if target == Target::Aarch64 {
|
||||||
com.args(["--target", "targets/aarch64-virt-ableos.json"]);
|
com.args(["--target", "targets/aarch64-virt-ableos.json"]);
|
||||||
}
|
}
|
||||||
if target == Target::X86_64Avx2 {
|
|
||||||
com.args(["--target", "targets/x86_64_v3-ableos.json"]);
|
|
||||||
}
|
|
||||||
|
|
||||||
match com.status() {
|
match com.status() {
|
||||||
Ok(s) if s.code() != Some(0) => bail!(Error::Build),
|
Ok(s) if s.code() != Some(0) => bail!(Error::Build),
|
||||||
|
@ -377,10 +298,6 @@ fn build(release: bool, target: Target, debuginfo: bool, tests: bool) -> Result<
|
||||||
path.push_str("_x86-64");
|
path.push_str("_x86-64");
|
||||||
"target/x86_64-ableos"
|
"target/x86_64-ableos"
|
||||||
}
|
}
|
||||||
Target::X86_64Avx2 => {
|
|
||||||
path.push_str("_x86-64");
|
|
||||||
"target/x86_64_v3-ableos"
|
|
||||||
}
|
|
||||||
Target::Riscv64Virt => "target/riscv64-virt-ableos",
|
Target::Riscv64Virt => "target/riscv64-virt-ableos",
|
||||||
Target::Aarch64 => {
|
Target::Aarch64 => {
|
||||||
path.push_str("_aarch64");
|
path.push_str("_aarch64");
|
||||||
|
@ -403,72 +320,25 @@ fn build(release: bool, target: Target, debuginfo: bool, tests: bool) -> Result<
|
||||||
.change_context(Error::Io)
|
.change_context(Error::Io)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(release: bool, target: Target, do_accel: bool) -> Result<(), Error> {
|
fn run(release: bool, target: Target) -> Result<(), Error> {
|
||||||
let target_str = match target {
|
let mut com = match target {
|
||||||
Target::X86_64 | Target::X86_64Avx2 => "qemu-system-x86_64",
|
Target::X86_64 => Command::new("qemu-system-x86_64"),
|
||||||
Target::Riscv64Virt => "qemu-system-riscv64",
|
Target::Riscv64Virt => Command::new("qemu-system-riscv64"),
|
||||||
Target::Aarch64 => "qemu-system-aarch64",
|
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);
|
let ovmf_path = fetch_ovmf(target);
|
||||||
#[cfg(target_arch = "x86_64")]
|
|
||||||
let accel = if do_accel {
|
|
||||||
let supported = String::from_utf8(
|
|
||||||
com2.args(["--accel", "help"])
|
|
||||||
.stdout(Stdio::piped())
|
|
||||||
.stderr(Stdio::piped())
|
|
||||||
.spawn()
|
|
||||||
.unwrap()
|
|
||||||
.wait_with_output()
|
|
||||||
.unwrap()
|
|
||||||
.stdout,
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let cpuid = raw_cpuid::CpuId::new();
|
|
||||||
let vmx = cpuid.get_feature_info().unwrap().has_vmx();
|
|
||||||
let svm = cpuid.get_svm_info().is_some();
|
|
||||||
|
|
||||||
if supported.contains("kvm") && (vmx || svm) {
|
|
||||||
"accel=kvm"
|
|
||||||
} else if cpuid
|
|
||||||
.get_processor_brand_string()
|
|
||||||
.filter(|a| a.as_str() == "GenuineIntel")
|
|
||||||
.is_some()
|
|
||||||
&& supported.contains("hax")
|
|
||||||
&& vmx
|
|
||||||
{
|
|
||||||
"accel=hax"
|
|
||||||
} else if supported.contains("whpx") {
|
|
||||||
"accel=whpx"
|
|
||||||
} else {
|
|
||||||
"accel=tcg"
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
"accel=tcg"
|
|
||||||
};
|
|
||||||
#[cfg(not(target_arch = "x86_64"))]
|
|
||||||
let accel = "accel=tcg";
|
|
||||||
|
|
||||||
match target {
|
match target {
|
||||||
Target::X86_64 | Target::X86_64Avx2 => {
|
Target::X86_64 => {
|
||||||
#[rustfmt::skip]
|
#[rustfmt::skip]
|
||||||
com.args([
|
com.args([
|
||||||
"-bios", &ovmf_path.change_context(Error::OvmfFetch)?,
|
"-bios", &ovmf_path.change_context(Error::OvmfFetch)?,
|
||||||
"-drive", "file=target/disk.img,format=raw",
|
"-drive", "file=target/disk.img,format=raw",
|
||||||
"-device", "vmware-svga",
|
"-m", "4G",
|
||||||
// "-serial", "stdio",
|
"-smp", "cores=4",
|
||||||
"-m", "2G",
|
"-enable-kvm",
|
||||||
"-smp", "1",
|
"-cpu", "host",
|
||||||
"-audiodev",
|
"-device", "isa-debug-exit,iobase=0xf4,iosize=0x04"
|
||||||
"pa,id=speaker",
|
|
||||||
"-machine",
|
|
||||||
"pcspk-audiodev=speaker",
|
|
||||||
"-parallel", "none",
|
|
||||||
"-monitor", "none",
|
|
||||||
"-machine", accel,
|
|
||||||
"-cpu", "max",
|
|
||||||
"-device", "isa-debug-exit,iobase=0xf4,iosize=0x04",
|
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
Target::Riscv64Virt => {
|
Target::Riscv64Virt => {
|
||||||
|
@ -489,7 +359,7 @@ fn run(release: bool, target: Target, do_accel: bool) -> Result<(), Error> {
|
||||||
#[rustfmt::skip]
|
#[rustfmt::skip]
|
||||||
com.args([
|
com.args([
|
||||||
"-M", "virt",
|
"-M", "virt",
|
||||||
"-cpu", "max",
|
"-cpu", "cortex-a72",
|
||||||
"-device", "ramfb",
|
"-device", "ramfb",
|
||||||
"-device", "qemu-xhci",
|
"-device", "qemu-xhci",
|
||||||
"-device", "usb-kbd",
|
"-device", "usb-kbd",
|
||||||
|
@ -512,7 +382,7 @@ fn run(release: bool, target: Target, do_accel: bool) -> Result<(), Error> {
|
||||||
|
|
||||||
fn fetch_ovmf(target: Target) -> Result<String, OvmfFetchError> {
|
fn fetch_ovmf(target: Target) -> Result<String, OvmfFetchError> {
|
||||||
let (ovmf_url, ovmf_path) = match target {
|
let (ovmf_url, ovmf_path) = match target {
|
||||||
Target::X86_64 | Target::X86_64Avx2 => (
|
Target::X86_64 => (
|
||||||
"https://retrage.github.io/edk2-nightly/bin/RELEASEX64_OVMF.fd",
|
"https://retrage.github.io/edk2-nightly/bin/RELEASEX64_OVMF.fd",
|
||||||
"target/RELEASEX64_OVMF.fd",
|
"target/RELEASEX64_OVMF.fd",
|
||||||
),
|
),
|
||||||
|
@ -534,12 +404,12 @@ fn fetch_ovmf(target: Target) -> Result<String, OvmfFetchError> {
|
||||||
Ok(_) => return Ok(ovmf_path.to_owned()),
|
Ok(_) => return Ok(ovmf_path.to_owned()),
|
||||||
Err(e) => return Err(report!(e).change_context(OvmfFetchError::Io)),
|
Err(e) => return Err(report!(e).change_context(OvmfFetchError::Io)),
|
||||||
};
|
};
|
||||||
let req = ureq::get(ovmf_url)
|
let mut bytes = reqwest::blocking::get(ovmf_url)
|
||||||
.call()
|
|
||||||
.map_err(Report::from)
|
.map_err(Report::from)
|
||||||
.change_context(OvmfFetchError::Fetch)?;
|
.change_context(OvmfFetchError::Fetch)?;
|
||||||
|
|
||||||
std::io::copy(&mut req.into_reader(), &mut file)
|
bytes
|
||||||
|
.copy_to(&mut file)
|
||||||
.map_err(Report::from)
|
.map_err(Report::from)
|
||||||
.change_context(OvmfFetchError::Io)?;
|
.change_context(OvmfFetchError::Io)?;
|
||||||
|
|
||||||
|
@ -548,11 +418,11 @@ fn fetch_ovmf(target: Target) -> Result<String, OvmfFetchError> {
|
||||||
|
|
||||||
#[derive(Debug, Display)]
|
#[derive(Debug, Display)]
|
||||||
enum OvmfFetchError {
|
enum OvmfFetchError {
|
||||||
#[display("Failed to fetch OVMF package")]
|
#[display(fmt = "Failed to fetch OVMF package")]
|
||||||
Fetch,
|
Fetch,
|
||||||
#[display("No OVMF package available")]
|
#[display(fmt = "No OVMF package available")]
|
||||||
Empty,
|
Empty,
|
||||||
#[display("IO Error")]
|
#[display(fmt = "IO Error")]
|
||||||
Io,
|
Io,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -561,33 +431,30 @@ impl Context for OvmfFetchError {}
|
||||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||||
enum Target {
|
enum Target {
|
||||||
X86_64,
|
X86_64,
|
||||||
X86_64Avx2,
|
|
||||||
Riscv64Virt,
|
Riscv64Virt,
|
||||||
Aarch64,
|
Aarch64,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused)]
|
|
||||||
#[derive(Debug, Display)]
|
#[derive(Debug, Display)]
|
||||||
enum Error {
|
enum Error {
|
||||||
#[display("Failed to build the kernel")]
|
#[display(fmt = "Failed to build the kernel")]
|
||||||
Build,
|
Build,
|
||||||
#[display("Missing or invalid subcommand (available: build, run)")]
|
#[display(fmt = "Missing or invalid subcommand (available: build, run)")]
|
||||||
InvalidSubCom,
|
InvalidSubCom,
|
||||||
#[display("IO Error")]
|
#[display(fmt = "IO Error")]
|
||||||
Io,
|
Io,
|
||||||
#[display("Failed to spawn a process")]
|
#[display(fmt = "Failed to spawn a process")]
|
||||||
ProcessSpawn,
|
ProcessSpawn,
|
||||||
#[display("Failed to fetch UEFI firmware")]
|
#[display(fmt = "Failed to fetch UEFI firmware")]
|
||||||
OvmfFetch,
|
OvmfFetch,
|
||||||
#[display("Failed to assemble Holey Bytes code")]
|
#[display(fmt = "Failed to assemble Holey Bytes code")]
|
||||||
Assembler,
|
Assembler,
|
||||||
#[display("QEMU Error: {}", "fmt_qemu_err(*_0)")]
|
#[display(fmt = "QEMU Error: {}", "fmt_qemu_err(*_0)")]
|
||||||
Qemu(Option<i32>),
|
Qemu(Option<i32>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Context for Error {}
|
impl Context for Error {}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
fn fmt_qemu_err(e: Option<i32>) -> impl Display {
|
fn fmt_qemu_err(e: Option<i32>) -> impl Display {
|
||||||
struct W(Option<i32>);
|
struct W(Option<i32>);
|
||||||
impl Display for W {
|
impl Display for W {
|
||||||
|
|
|
@ -1,7 +1,3 @@
|
||||||
[toolchain]
|
[toolchain]
|
||||||
# old toolchain
|
channel = "nightly-2024-05-17"
|
||||||
# channel = "nightly-2024-07-27"
|
|
||||||
# last stable
|
|
||||||
# channel = "nightly-2024-11-20"
|
|
||||||
channel = "nightly"
|
|
||||||
components = ["rust-src", "llvm-tools"]
|
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.
Binary file not shown.
Before Width: | Height: | Size: 66 B |
|
@ -1,23 +1,24 @@
|
||||||
@auto_increment
|
// A comment
|
||||||
|
//@auto_increment
|
||||||
enum LogLevel {
|
enum LogLevel {
|
||||||
Error = 0,
|
Error = 0,
|
||||||
Warn,
|
Warn = 1,
|
||||||
Info,
|
Info = 2,
|
||||||
Debug,
|
Debug = 3,
|
||||||
Trace,
|
Trace = 4,
|
||||||
}
|
}
|
||||||
|
|
||||||
@auto_increment
|
//@auto_increment
|
||||||
enum LogResult {
|
enum LogResult {
|
||||||
Err = 0,
|
Err = 0,
|
||||||
Ok,
|
Ok = 1,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Log {
|
struct Log {
|
||||||
log_level: LogLevel,
|
log_level: LogLevel,
|
||||||
}
|
}
|
||||||
|
|
||||||
@visibility(public)
|
//@visibility(public)
|
||||||
protocol Log {
|
protocol Log {
|
||||||
fn log(Log) -> LogResult;
|
fn log(Log) -> LogResult;
|
||||||
fn flush() -> LogResult;
|
fn flush() -> LogResult;
|
3
sysdata/idl/test/src/protocol.aldi
Normal file
3
sysdata/idl/test/src/protocol.aldi
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
protocol Foo{
|
||||||
|
fn bar(i32, u8, bool) -> void;
|
||||||
|
}
|
|
@ -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))
|
|
14
sysdata/libraries/horizon_api/src/element.hb
Normal file
14
sysdata/libraries/horizon_api/src/element.hb
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
Element := struct {
|
||||||
|
width: int,
|
||||||
|
height: int,
|
||||||
|
|
||||||
|
x: u16,
|
||||||
|
y: u16,
|
||||||
|
|
||||||
|
id: int,
|
||||||
|
}
|
||||||
|
|
||||||
|
create_element := fn(): Element {
|
||||||
|
return Element.(0, 0, 0, 0, 0)
|
||||||
|
}
|
||||||
|
|
3
sysdata/libraries/horizon_api/src/frame.hb
Normal file
3
sysdata/libraries/horizon_api/src/frame.hb
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
FrameID := struct {
|
||||||
|
|
||||||
|
}
|
|
@ -1,43 +1,12 @@
|
||||||
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 {
|
WindowID := struct {
|
||||||
host_id: int,
|
host_id: int,
|
||||||
window_id: int,
|
window_id: int,
|
||||||
}
|
}
|
||||||
|
|
||||||
VoidWindowID := WindowID.(0, 0)
|
create_window := fn(): WindowID {
|
||||||
|
return WindowID.(1, 2)
|
||||||
create_window := fn(channel: int): ^render.Surface {
|
}
|
||||||
// get the horizon buffer
|
|
||||||
// request a new window and provide the callback buffer
|
update_ui := fn(window_id: WindowID): void {
|
||||||
// wait to recieve a message
|
return
|
||||||
|
|
||||||
windowing_system_buffer := buffer.search("XHorizon\0")
|
|
||||||
mem_buf := memory.request_page(1)
|
|
||||||
|
|
||||||
if windowing_system_buffer == 0 {
|
|
||||||
return @as(^render.Surface, idk)
|
|
||||||
} else {
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
}
|
3
sysdata/libraries/horizon_api/src/text.hb
Normal file
3
sysdata/libraries/horizon_api/src/text.hb
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
ui_lisp_text_example := "(text id_1)\0";
|
||||||
|
|
||||||
|
|
|
@ -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,
|
|
||||||
|
|
||||||
new_label := fn(text: ^u8, width: uint): Self {
|
|
||||||
text_surface := render.new_surface(width, 20)
|
|
||||||
text_length := string.length(text)
|
|
||||||
label := Self.(3, true, text_surface, text, text_length, render.black, render.white)
|
|
||||||
return label
|
|
||||||
}
|
|
||||||
|
|
||||||
set_label_text := fn(self: Self, text: ^u8): void {
|
|
||||||
text_length := string.length(text)
|
|
||||||
|
|
||||||
self.is_dirty = true
|
|
||||||
self.text = text
|
|
||||||
self.text_length = text_length
|
|
||||||
}
|
|
||||||
|
|
||||||
$set_color := fn(self: Self, bg: Color, fg: Color): void {
|
|
||||||
self.bg = bg
|
|
||||||
self.fg = fg
|
|
||||||
self.is_dirty = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
|
|
@ -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,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 +1,7 @@
|
||||||
application := @use("application.hb")
|
VK_VERSION_MAJOR := 1;
|
||||||
|
VK_VERSION_MINOR := 0;
|
||||||
|
|
||||||
results := @use("results.hb")
|
init_vulkan := fn(): void {
|
||||||
errors := @use("errors.hb")
|
|
||||||
|
|
||||||
offsets := @use("offset.hb")
|
return
|
||||||
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
|
|
||||||
}
|
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue