forked from AbleOS/ableos
Compare commits
235 commits
Author | SHA1 | Date | |
---|---|---|---|
Able | 635ed1be42 | ||
Able | 36d50f6b38 | ||
Able | 559f25bb4e | ||
Able | 82b9cb1206 | ||
Able | 2afa83a615 | ||
Able | 28258e0d45 | ||
Able | 190f0941dc | ||
Able | 68840571c0 | ||
Able | dc3b7f71d5 | ||
Able | bff8db4c13 | ||
peony | 13c4649fd6 | ||
peony | f7f5b677e9 | ||
peony | 821497fbe6 | ||
Able | 5abdef4be6 | ||
Able | b5282ea6fb | ||
peony | 498cfbf913 | ||
peony | e3abec2927 | ||
peony | b3d07b5235 | ||
peony | a93512eed1 | ||
peony | c429641f98 | ||
koniifer | db01da58e1 | ||
koniifer | 38d3a10659 | ||
koniifer | a551b2672f | ||
koniifer | fd26ec734b | ||
koniifer | 9d1c59b65d | ||
cda022e6f0 | |||
95cf948d59 | |||
koniifer | f6a8a78b6c | ||
kodin | 5d152811b2 | ||
koniifer | 685c6f0b20 | ||
Able | 1b3dc153e8 | ||
Able | 9aa84a0f40 | ||
Able | bdb762c986 | ||
koniifer | 0b57c2e9bb | ||
Able | 8c88c0b5ae | ||
Able | 8b2b50e433 | ||
Able | d7e0d573e2 | ||
Able | 0ee8b7a4e4 | ||
Able | 2261f36101 | ||
Able | 6f82c92c30 | ||
koniifer | 5ea3ee9fe1 | ||
Able | 241139f5af | ||
Able | 5c4056bc5c | ||
peony | 5028062e39 | ||
peony | f7f9fece4f | ||
b505622601 | |||
80ae717dd9 | |||
ab8b2309ae | |||
koniifer | 7b7e02976d | ||
koniifer | c1c02ffefd | ||
peony | f4ceab972c | ||
able | 8602ceb0d3 | ||
peony | 96c07e137b | ||
peony | d78878a12f | ||
Able | 6b673bc7e6 | ||
peony | 8f265ebf40 | ||
peony | 3d5a8f6f10 | ||
peony | f11122e58e | ||
peony | 2fdede7199 | ||
koniifer | 0af4d142a4 | ||
peony | 13422dfd9f | ||
peony | 90a97cd160 | ||
peony | 23b45b1887 | ||
koniifer | 36f0d357cf | ||
peony | cf37eaf086 | ||
peony | 284aa5a5e6 | ||
koniifer | ccddf36050 | ||
peony | 11976b752f | ||
peony | 98b15d4c10 | ||
peony | f5c6d7d822 | ||
koniifer | da5f1a7a19 | ||
koniifer | 2808bc9e7c | ||
koniifer | d958a103fa | ||
koniifer | ee82bc5705 | ||
Able | 3d53b641bf | ||
peony | efcd6c0631 | ||
peony | b795aced8e | ||
peony | 08099b0877 | ||
koniifer | cea7f1fa5c | ||
Able | 614bef7ec5 | ||
Able | b0f6aa53bd | ||
Able | d5f4ce18a3 | ||
koniifer | 907c0d0dd4 | ||
koniifer | 95b4a921dc | ||
koniifer | b6261d014d | ||
Able | 56ee0fe851 | ||
koniifer | b07bac1f1f | ||
peony | a1bfd8e85f | ||
koniifer | dc9273b3c1 | ||
Able | e6d8f5c822 | ||
koniifer | 8ad7542b9c | ||
Able | e40a22fccd | ||
koniifer | cf917927a5 | ||
peony | edfb588060 | ||
peony | cc4a32afaa | ||
koniifer | 97ceb12d6e | ||
koniifer | bae58ade61 | ||
koniifer | b21c05e924 | ||
Able | 2f5bc73665 | ||
Able | 0003464099 | ||
koniifer | 77a708d41e | ||
peony | be6a095c14 | ||
peony | 3409f5051a | ||
peony | aac1164d55 | ||
peony | 89d08d8a62 | ||
peony | 8f5833955f | ||
peony | 4c0adbe15d | ||
peony | 3708acc077 | ||
peony | b5b122f451 | ||
Able | 8c7b95277d | ||
koniifer | 7da32b263f | ||
Able | 2439722c88 | ||
koniifer | 3333b1706f | ||
Able | 8808ed5bfe | ||
koniifer | 68d3236cc0 | ||
Able | eea23d967b | ||
Able | d2152537ad | ||
Able | 7723799e76 | ||
koniifer | 8b04b275f3 | ||
Able | 1345f294b8 | ||
Able | 818bcb458f | ||
Able | d2b5f09511 | ||
2676bd7b62 | |||
koniifer | 444fcdb0c4 | ||
koniifer | adbf32d970 | ||
Able | 7f01b0e0f8 | ||
Able | e8edee4ccc | ||
koniifer | ba59233ce7 | ||
Able | f13c682171 | ||
Able | b6b097a872 | ||
koniifer | 6a8d92d2c2 | ||
Able | ab8522fbe1 | ||
Able | a49ac7bca0 | ||
Able | 12883ac926 | ||
Able | 6a319c55b0 | ||
Able | 879bbfa173 | ||
Able | 795f10986f | ||
Able | 85e63eb51c | ||
koniifer | aafe047b51 | ||
koniifer | 404ea22c46 | ||
koniifer | 664334fd00 | ||
Able | 086948d47a | ||
Able | b795215b62 | ||
Able | 16135ae536 | ||
Able | 941eed0ac9 | ||
Able | f4ad4b6856 | ||
koniifer | 9e83707a28 | ||
Able | 6894ef2360 | ||
Able | 69c95c35b5 | ||
Able | 80d363bc59 | ||
Able | 3c3c156eb0 | ||
koniifer | eaace7d9c1 | ||
koniifer | 5af5631755 | ||
Able | fac573837f | ||
koniifer | 6ff65eee41 | ||
koniifer | b35b430047 | ||
koniifer | bcfaf89ed0 | ||
koniifer | 2ba2dcb464 | ||
koniifer | 41d9c0b82a | ||
koniifer | a94332370a | ||
koniifer | 7caa47b9fb | ||
Able | 34101d2e8c | ||
Able | 2bc13cd7d8 | ||
koniifer | 086cc4aef0 | ||
Able | 84f86488c7 | ||
Able | ed7c8f20cb | ||
koniifer | 34cbd9a5e6 | ||
koniifer | 0ebb1f200e | ||
Able | fc06820332 | ||
koniifer | 2a082d8283 | ||
koniifer | 1eee33ce8b | ||
peony | 39ebaa03ba | ||
Able | 6fa1c829fd | ||
koniifer | 820c3e459b | ||
koniifer | 3af28f1666 | ||
koniifer | 96c2bd5cd5 | ||
peony | de8000f596 | ||
koniifer | ea8eca1089 | ||
koniifer | 7f4a040505 | ||
koniifer | 82f5cdbe21 | ||
koniifer | aac6d61dc6 | ||
koniifer | 3df6f18c85 | ||
koniifer | 07ee8de9f1 | ||
Able | f64f654610 | ||
Able | 7d4b12a103 | ||
Able | 758629df0a | ||
Able | 04a449965b | ||
koniifer | 0bbc76124f | ||
Able | 6ad68dabac | ||
Able | 07c7d52b8c | ||
Able | 2edc8148ca | ||
5f59f05dce | |||
Able | 0bc757164f | ||
Able | f5f68bc2df | ||
Able | 7a256dde68 | ||
Able | 570b566310 | ||
Able | d2488689fe | ||
Able | fe70d81bd0 | ||
Able | cc076d9540 | ||
Able | 3173b63c93 | ||
koniifer | 48027196b1 | ||
koniifer | 78553a3190 | ||
koniifer | df74b09134 | ||
koniifer | 2321efd2e7 | ||
Able | d9caa17f3c | ||
Able | b0ecbfa168 | ||
Able | 1fe20360f6 | ||
Able | fb42351638 | ||
5f2b181f22 | |||
koniifer | 43ea77c18f | ||
Able | 2b2e0c514b | ||
Able | fcca015866 | ||
Able | cc9337348e | ||
Able | 028949559b | ||
Able | 91380539d9 | ||
Able | ec25c0f207 | ||
Able | 1b5cb54a2b | ||
Able | 9686349476 | ||
koniifer | f8c7873978 | ||
Able | 40cc412ab3 | ||
Able | cd369b39d5 | ||
331cbf5da1 | |||
63e2f546c5 | |||
1a2b60b53b | |||
koniifer | a7517005de | ||
koniifer | e3f7a2d455 | ||
koniifer | 19992595fc | ||
koniifer | f7b970eaf0 | ||
koniifer | c752028c73 | ||
koniifer | 8577920d90 | ||
12ee3a9b87 | |||
58bc6facbc | |||
1615297536 | |||
0d3641e199 | |||
ad85f82be3 |
|
@ -1,3 +1,3 @@
|
|||
[alias]
|
||||
repbuild = "run --manifest-path ./repbuild/Cargo.toml -r --"
|
||||
repbuild = "run --manifest-path ./repbuild/Cargo.toml -- "
|
||||
dev = "run --manifest-path ./dev/Cargo.toml -r --"
|
||||
|
|
2
.vscode/settings.json
vendored
2
.vscode/settings.json
vendored
|
@ -1,4 +1,6 @@
|
|||
{
|
||||
"editor.insertSpaces": false,
|
||||
"editor.detectIndentation": false,
|
||||
"rust-analyzer.checkOnSave.allTargets": false,
|
||||
"rust-analyzer.showUnlinkedFileNotification": false,
|
||||
"C_Cpp.errorSquiggles": "disabled"
|
||||
|
|
1420
Cargo.lock
generated
1420
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
|
@ -1,3 +1,9 @@
|
|||
[workspace]
|
||||
resolver = "2"
|
||||
members = ["dev", "kernel", "repbuild"]
|
||||
|
||||
# [profile.release]
|
||||
# strip = "symbols"
|
||||
# codegen-units = 1
|
||||
# lto = true
|
||||
# panic = "abort"
|
||||
|
|
69
HELP.md
Normal file
69
HELP.md
Normal file
|
@ -0,0 +1,69 @@
|
|||
### What are the requirements?
|
||||
- A machine with [Rustc Tier 1 platform support](https://doc.rust-lang.org/nightly/rustc/platform-support.html#tier-1-with-host-tools)
|
||||
- Rustup
|
||||
- QEMU (for executing)
|
||||
- GIT CLI
|
||||
|
||||
### How do I run ableos?
|
||||
- It is recommended to run ableos under QEMU. Here is how:
|
||||
- Install QEMU
|
||||
- Clone ableos
|
||||
- Go to ableos directory
|
||||
- Pull the limine submodule with `git submodule update --init`
|
||||
- Run `cargo repbuild help`
|
||||
|
||||
### How can I contribute?
|
||||
- [Contribute code](#how-do-i-contribute-code)
|
||||
- [Run ableos on your machine](#how-do-i-run-ableos)
|
||||
- Find bugs
|
||||
- Create media showing ableos
|
||||
|
||||
### How do I contribute code?
|
||||
- Start by forking ableos
|
||||
- Write something that runs in the userspace, for example:
|
||||
- System drivers
|
||||
- Programs
|
||||
- Libraries
|
||||
- Patch bugs and improve code in the kernel
|
||||
- Ensure that the code is OK to be maintained by asking in the [discord](https://discord.gg/t5Wt3K4YNA)
|
||||
- When you have finished your changes, you can submit a pull request for review [here](https://git.ablecorp.us/ableos/ableos)
|
||||
|
||||
### repbuild and kernel compile, but QEMU isn't starting
|
||||
- Ensure you have the `qemu-desktop-{arch}` for your OS and target architecture installed
|
||||
- Try running again with `--noaccel` if you have QEMU already
|
||||
|
||||
### I have run using repbuild but it's slow
|
||||
- Ensure release mode is enabled with the `-r` flag
|
||||
- Remove the `--noaccel` flag if you can
|
||||
- If both of these are already done, there may be a problem with thee VM, kernel, your program, or the hblang compiler
|
||||
|
||||
### Compiler is complaining about "reg id leaked"
|
||||
- [Submit](#how-do-i-report-a-compiler-bug) an issue, reg id leaked is a bug
|
||||
|
||||
### My program isn't running
|
||||
- Refer to [here](#i-have-run-using-repbuild-but-its-slow), it may be that your program is simply starting slowly
|
||||
- Ensure that your program has a properly written meta.toml file
|
||||
- Ensure that your program is enabled in [system_config.toml](sysdata/system_config.toml)
|
||||
- Try running again with `--noaccel`, there is a known bug with some systems that prevents programs from starting.
|
||||
|
||||
### Kernel panic??? Huh???
|
||||
- Kernel panics can be caused by improperly using memory (e.g, writing out of bounds)
|
||||
- Kernel panics are most likely to be caused when accessing memory or using `@eca` for kernel ecalls
|
||||
- [Report](#how-do-i-report-an-ableos-bug) a kernel panic
|
||||
|
||||
### I am running in release mode but I have no debug info
|
||||
- Add the `-d` flag for debug info
|
||||
|
||||
### What is `@eca`? How do I use it?
|
||||
- Eca is an ecall. They are similar to syscalls
|
||||
- The `@eca` directive takes the following arguments:
|
||||
- `@eca(ecall_number, reg_1, ..., reg_n)`
|
||||
- The various ecalls have different arguments that are given by register values
|
||||
- Most ecalls are wrapped by `stn`, for example, `random`, `buffer`, and `memory` all make use of ecalls
|
||||
- All ecalls can be found [ecah.rs](kernel/src/holeybytes/ecah.rs)
|
||||
|
||||
### How do I report an ableos bug?
|
||||
- Submit an issue [here](https://git.ablecorp.us/ableos/ableos/issues) or report it in the [discord](https://discord.gg/t5Wt3K4YNA)
|
||||
|
||||
### How do I report a compiler bug?
|
||||
- Submit an issue [here](https://git.ablecorp.us/ableos/holey-bytes/issues) or report it in the [discord](https://discord.gg/t5Wt3K4YNA)
|
12
README.md
12
README.md
|
@ -10,15 +10,7 @@ Donations can be made [here on Liberapay](https://liberapay.com/AbleTheAbove) or
|
|||
<img src="https://img.shields.io/liberapay/patrons/AbleTheAbove.svg?logo=liberapay">
|
||||
|
||||
# Compiling
|
||||
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`
|
||||
See [HELP.md](HELP.md)
|
||||
|
||||
# Developing
|
||||
There is a new work in progress developer tool for hblang.
|
||||
There is a new work in progress developer tool for hblang. (see: dev folder)
|
77
STYLE_GUIDE.md
Normal file
77
STYLE_GUIDE.md
Normal file
|
@ -0,0 +1,77 @@
|
|||
# Style Guide
|
||||
This style guide has two modes that a guideline may be.
|
||||
|
||||
`strict` means that prs will be rejected if they do not follow the guideline.
|
||||
|
||||
`loose` means that a pr would be accepted but should later be fixed.
|
||||
|
||||
## Empty Functions | loose
|
||||
Empty functions are typically a sign of an unfinished program or driver.
|
||||
|
||||
In cases where there is a clear reason to have an empty function it will be allowed.
|
||||
For example FakeAlloc is only empty functions because it is a example of an the allocator api.
|
||||
|
||||
### Allowed
|
||||
```rust
|
||||
/// in example.hb
|
||||
a := fn(): void {}
|
||||
```
|
||||
### Not Allowed
|
||||
```rust
|
||||
/// in fat32.hb
|
||||
a := fn(): void {}
|
||||
```
|
||||
## Magic Functions | loose
|
||||
'Magic functions' are what I am calling small helper functions that do one or two things.
|
||||
### Example
|
||||
```rust
|
||||
a := null
|
||||
magic_a := fn(){
|
||||
a = 10
|
||||
}
|
||||
```
|
||||
The exact policy I want to have here is a bit fuzzy. I think that functions like this are nice in certain situations and not in others.
|
||||
Regardless of if you use them or not, put a comment above the function explaining rational.
|
||||
|
||||
|
||||
## Magic Numbers | loose
|
||||
The policy on magic numbers is make them const and have a comment above them. Typically linking to a source of information about the magic number.
|
||||
|
||||
This helps cut down on magic numbers while making acceptable names and atleast half assed documentation.
|
||||
|
||||
Constants are inlined anyways, so its the same thing in the binary.
|
||||
|
||||
```rust
|
||||
// The standard vga port is mapped at 0xB8000
|
||||
$VGA_PTR := 0xB8000
|
||||
```
|
||||
|
||||
## Tabs Vs Spaces | strict
|
||||
I prefer for hblang code to use hard tabs.
|
||||
|
||||
The rational behind this is that a tab is `1 Indent` which some developers might want to be various different sizes when displayed
|
||||
|
||||
Soft tabs do not allow this user/editor specific as soft tabs always become spaces.
|
||||
|
||||
Bottom line is this is an accessibility feature.
|
||||
|
||||
There are some samples below.
|
||||
```
|
||||
\t means hard tab
|
||||
\n means new line
|
||||
\0x20 means space
|
||||
```
|
||||
|
||||
### Allowed
|
||||
```rust
|
||||
if x == y {\n
|
||||
\tlog(z)\n
|
||||
}\n
|
||||
```
|
||||
|
||||
### Not Allowed
|
||||
```rust
|
||||
if x == y {\n
|
||||
\0x20\0x20\0x20\0x20log(z)\n
|
||||
}\n
|
||||
```
|
31
dev/aldi.bnf
31
dev/aldi.bnf
|
@ -1,31 +0,0 @@
|
|||
|
||||
|
||||
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,78 +1,56 @@
|
|||
mod parser;
|
||||
mod types;
|
||||
mod protocol;
|
||||
pub mod protocol;
|
||||
|
||||
use crate::idl::{parser::parse, types::get_protocols};
|
||||
use std::io::Read;
|
||||
|
||||
use logos::{Lexer, Logos, Skip};
|
||||
use {
|
||||
logos::{Lexer, Logos},
|
||||
protocol::Protocol,
|
||||
};
|
||||
|
||||
#[derive(Logos, Debug, PartialEq, Clone)]
|
||||
#[logos(extras = (usize, usize))]
|
||||
#[logos(skip r"[ \t\n\f]+")] // Ignore this regex pattern between tokens
|
||||
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.
|
||||
#[token("protocol", get_token_position)]
|
||||
Protocol((usize,usize)),
|
||||
#[token("protocol")]
|
||||
Protocol,
|
||||
|
||||
// Tokens can be literal strings, of any length.
|
||||
#[token("type", get_token_position)]
|
||||
Type((usize, usize)),
|
||||
#[token("{")]
|
||||
LBrace,
|
||||
|
||||
#[token("fn", priority = 5, callback = get_token_position)]
|
||||
Fn((usize, usize)),
|
||||
#[token("}")]
|
||||
RBrace,
|
||||
|
||||
#[token("enum", get_token_position)]
|
||||
Enum((usize, usize)),
|
||||
#[token("(")]
|
||||
LParen,
|
||||
|
||||
#[token("struct", get_token_position)]
|
||||
Struct((usize, usize)),
|
||||
#[token(")")]
|
||||
RParen,
|
||||
|
||||
#[token("{", get_token_position)]
|
||||
LBrace((usize, usize)),
|
||||
#[token(":")]
|
||||
Colon,
|
||||
#[token(";")]
|
||||
SemiColon,
|
||||
|
||||
#[token("}", get_token_position)]
|
||||
RBrace((usize, usize)),
|
||||
#[token(",")]
|
||||
Comma,
|
||||
|
||||
#[token("(", get_token_position)]
|
||||
LParen((usize, usize)),
|
||||
#[token("=")]
|
||||
Equal,
|
||||
|
||||
#[token(")", get_token_position)]
|
||||
RParen((usize, usize)),
|
||||
#[token("->")]
|
||||
RArrow,
|
||||
|
||||
#[token(":", get_token_position)]
|
||||
Colon((usize, usize)),
|
||||
#[regex("[a-zA-Z_]+", |lex|{lex.slice().to_string()})]
|
||||
Text(String),
|
||||
|
||||
#[token(";", get_token_position)]
|
||||
SemiColon((usize, usize)),
|
||||
#[regex("[1234567890]+", |lex|{lex.slice().parse::<u64>().unwrap()})]
|
||||
Number(u64),
|
||||
|
||||
#[token(",", get_token_position)] Comma((usize, usize)),
|
||||
#[regex(r"@[a-zA-Z_]+", |lex|{lex.slice().to_string()})]
|
||||
Decorator(String),
|
||||
|
||||
#[token("=", get_token_position)]
|
||||
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,
|
||||
#[regex(r#"@[a-zA-Z_]+\([a-zA-Z,0-9=]+\)"#, |lex|{lex.slice().to_string()})]
|
||||
DecoratorOption(String),
|
||||
}
|
||||
|
||||
pub fn build_idl(name: String) {
|
||||
|
@ -82,36 +60,25 @@ pub fn build_idl(name: String) {
|
|||
for x in lex {
|
||||
match x {
|
||||
Ok(token) => {
|
||||
println!("{:?}", token);
|
||||
tokens.push(token);
|
||||
}
|
||||
Err(err) => println!("{:?}", err),
|
||||
}
|
||||
}
|
||||
build(tokens);
|
||||
}
|
||||
|
||||
let protocols = get_protocols(parse(tokens));
|
||||
let data : Vec<u8> = vec![1, 5, 12, 12, 12, 12, 3, 28, 8, 28];
|
||||
println!("{:#?}", &protocols);
|
||||
protocols.validate("Foo", "bar" , data).unwrap();
|
||||
fn build(a: Vec<Token>) {
|
||||
for toke in a {
|
||||
println!("{:?}", toke);
|
||||
}
|
||||
}
|
||||
|
||||
fn open_protocol(name: String) -> String {
|
||||
let path = format!("sysdata/idl/{}/src/protocol.aldi", name);
|
||||
let path = format!("sysdata/idl/{}/src/protocol.aidl", name);
|
||||
let mut file = std::fs::File::open(path).unwrap();
|
||||
let mut contents = String::new();
|
||||
file.read_to_string(&mut contents).unwrap();
|
||||
contents
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
|
|
@ -1,277 +0,0 @@
|
|||
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,167 +1,17 @@
|
|||
use std::collections::HashMap;
|
||||
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 enum ProtocolTypes {
|
||||
Byte,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct Protocols {
|
||||
protocols : HashMap<String, Protocol>,
|
||||
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 add_protocol(&mut self, name : String, interface : HashMap<String, Function>) {
|
||||
self.protocols.insert(name, Protocol::new(interface));
|
||||
}
|
||||
|
||||
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),
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
pub struct Protocol {}
|
||||
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),
|
||||
}
|
||||
}
|
||||
pub fn is_empty(&self) -> bool {
|
||||
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);
|
||||
pub fn validate_data(&self, data: Vec<u8>) -> bool {
|
||||
if !data.is_empty() && self.is_empty() {
|
||||
return false;
|
||||
}
|
||||
else{
|
||||
return Err(ValidationError::NonExistentType(arg.to_string()));
|
||||
true
|
||||
}
|
||||
}
|
||||
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(())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -1,98 +0,0 @@
|
|||
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 {
|
||||
DevelopmentType::Program => ("programs", "main.hb"),
|
||||
DevelopmentType::Library => ("libraries", "lib.hb"),
|
||||
DevelopmentType::IDL => ("idl", "protocol.aldi"),
|
||||
DevelopmentType::IDL => ("idl", "protocol.aidl"),
|
||||
};
|
||||
let project_folder_path_string = format!("sysdata/{folder_hierarchy}/{name}");
|
||||
|
||||
|
@ -72,6 +72,27 @@ pub fn new(development_type: DevelopmentType, name: String) {
|
|||
let readme_contents = format!("# {}", name);
|
||||
readme_file.write_all(readme_contents.as_bytes()).unwrap();
|
||||
|
||||
let contents = format!(
|
||||
"[package]
|
||||
name = \"{}\"
|
||||
authors = [\"\"]
|
||||
|
||||
[dependants.libraries]
|
||||
|
||||
[dependants.binaries]
|
||||
hblang.version = \"1.0.0\"
|
||||
|
||||
[build]
|
||||
command = \"hblang src/main.hb\"
|
||||
",
|
||||
name
|
||||
);
|
||||
|
||||
let toml_path_string = format!("{}/meta.toml", project_folder_path_string);
|
||||
let mut readme_file = std::fs::File::create(toml_path_string.clone()).unwrap();
|
||||
|
||||
readme_file.write_all(contents.as_bytes()).unwrap();
|
||||
|
||||
let src_folder_path_string = format!("{}/src", project_folder_path_string);
|
||||
std::fs::create_dir(src_folder_path_string.clone()).unwrap();
|
||||
|
||||
|
|
96
flake.lock
Normal file
96
flake.lock
Normal file
|
@ -0,0 +1,96 @@
|
|||
{
|
||||
"nodes": {
|
||||
"flake-utils": {
|
||||
"inputs": {
|
||||
"systems": "systems"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1731533236,
|
||||
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1732014248,
|
||||
"narHash": "sha256-y/MEyuJ5oBWrWAic/14LaIr/u5E0wRVzyYsouYY3W6w=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "23e89b7da85c3640bbc2173fe04f4bd114342367",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixos-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs_2": {
|
||||
"locked": {
|
||||
"lastModified": 1728538411,
|
||||
"narHash": "sha256-f0SBJz1eZ2yOuKUr5CA9BHULGXVSn6miBuUWdTyhUhU=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "b69de56fac8c2b6f8fd27f2eca01dcda8e0a4221",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixpkgs-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"flake-utils": "flake-utils",
|
||||
"nixpkgs": "nixpkgs",
|
||||
"rust-overlay": "rust-overlay"
|
||||
}
|
||||
},
|
||||
"rust-overlay": {
|
||||
"inputs": {
|
||||
"nixpkgs": "nixpkgs_2"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1732328983,
|
||||
"narHash": "sha256-RHt12f/slrzDpSL7SSkydh8wUE4Nr4r23HlpWywed9E=",
|
||||
"owner": "oxalica",
|
||||
"repo": "rust-overlay",
|
||||
"rev": "ed8aa5b64f7d36d9338eb1d0a3bb60cf52069a72",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "oxalica",
|
||||
"repo": "rust-overlay",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"systems": {
|
||||
"locked": {
|
||||
"lastModified": 1681028828,
|
||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"type": "github"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
"version": 7
|
||||
}
|
30
flake.nix
Normal file
30
flake.nix
Normal file
|
@ -0,0 +1,30 @@
|
|||
{
|
||||
description = "A devShell example";
|
||||
|
||||
inputs = {
|
||||
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
||||
rust-overlay.url = "github:oxalica/rust-overlay";
|
||||
flake-utils.url = "github:numtide/flake-utils";
|
||||
};
|
||||
|
||||
outputs = { self, nixpkgs, rust-overlay, flake-utils }:
|
||||
flake-utils.lib.eachDefaultSystem (system:
|
||||
let
|
||||
overlays = [ (import rust-overlay) ];
|
||||
pkgs = import nixpkgs {
|
||||
inherit system overlays;
|
||||
};
|
||||
|
||||
rustToolchain = pkgs.pkgsBuildHost.rust-bin.fromRustupToolchainFile ./rust-toolchain.toml;
|
||||
in
|
||||
with pkgs;
|
||||
{
|
||||
devShells.default = mkShell {
|
||||
buildInputs = [
|
||||
rustToolchain
|
||||
qemu_full
|
||||
];
|
||||
};
|
||||
}
|
||||
);
|
||||
}
|
|
@ -4,6 +4,3 @@ build-std-features = ["compiler-builtins-mem"]
|
|||
|
||||
[build]
|
||||
target = "./targets/x86_64-ableos.json"
|
||||
|
||||
[target.'cfg(target_arch = "x86_64")']
|
||||
rustflags = ["-C", "target-feature=+rdrand"]
|
||||
|
|
|
@ -3,35 +3,32 @@ edition = "2021"
|
|||
name = "kernel"
|
||||
version = "0.2.0"
|
||||
|
||||
[features]
|
||||
ktest = []
|
||||
|
||||
[dependencies]
|
||||
embedded-graphics = "0.7"
|
||||
hbvm.git = "https://git.ablecorp.us/ableos/holey-bytes"
|
||||
# embedded-graphics = "0.8"
|
||||
hbvm = { git = "https://git.ablecorp.us/AbleOS/holey-bytes.git", features = [
|
||||
"nightly",
|
||||
] }
|
||||
ktest_macro = { path = "ktest_macro" }
|
||||
log = "0.4"
|
||||
spin = "0.9"
|
||||
uart_16550 = "0.2"
|
||||
slab = { version = "0.4", default-features = false }
|
||||
uart_16550 = { version = "0.3", features = ["nightly"] }
|
||||
xml.git = "https://git.ablecorp.us/ableos/ableos_userland"
|
||||
versioning.git = "https://git.ablecorp.us/ableos/ableos_userland"
|
||||
able_graphics_library.git = "https://git.ablecorp.us/ableos/ableos_userland"
|
||||
hashbrown = "*"
|
||||
kiam = "0.1.1"
|
||||
|
||||
[dependencies.limine]
|
||||
version = "0.1"
|
||||
git = "https://github.com/limine-bootloader/limine-rs"
|
||||
# able_graphics_library.git = "https://git.ablecorp.us/ableos/ableos_userland"
|
||||
hashbrown = { version = "0.15", features = ["nightly"] }
|
||||
limine = "0.1"
|
||||
|
||||
[dependencies.crossbeam-queue]
|
||||
version = "0.3"
|
||||
default-features = false
|
||||
features = ["alloc"]
|
||||
|
||||
[dependencies.clparse]
|
||||
git = "https://git.ablecorp.us/ableos/ableos_userland"
|
||||
default-features = false
|
||||
features = ["alloc", "nightly"]
|
||||
|
||||
[dependencies.derive_more]
|
||||
version = "0.99"
|
||||
version = "1"
|
||||
default-features = false
|
||||
features = [
|
||||
"add",
|
||||
|
@ -48,12 +45,12 @@ features = [
|
|||
|
||||
|
||||
[target.'cfg(target_arch = "x86_64")'.dependencies]
|
||||
x86_64 = "0.14"
|
||||
x86_64 = "0.15"
|
||||
x2apic = "0.4"
|
||||
virtio-drivers = "0.4.0"
|
||||
# rdrand = "*"
|
||||
rdrand = { version = "0.8", default-features = false }
|
||||
|
||||
# virtio-drivers = "0.7"
|
||||
|
||||
[target.'cfg(target_arch = "riscv64")'.dependencies]
|
||||
sbi = "0.2.0"
|
||||
|
||||
[target.'cfg(target_arch = "aarch64")'.dependencies]
|
||||
aarch64-cpu = "9"
|
||||
|
|
11
kernel/ktest_macro/Cargo.toml
Normal file
11
kernel/ktest_macro/Cargo.toml
Normal file
|
@ -0,0 +1,11 @@
|
|||
[package]
|
||||
edition = "2021"
|
||||
name = "ktest_macro"
|
||||
version = "0.1.0"
|
||||
|
||||
[lib]
|
||||
proc-macro = true
|
||||
|
||||
[dependencies]
|
||||
quote = "1.0.37"
|
||||
syn = { version = "2.0.89", features = ["full"] }
|
86
kernel/ktest_macro/src/lib.rs
Normal file
86
kernel/ktest_macro/src/lib.rs
Normal file
|
@ -0,0 +1,86 @@
|
|||
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,6 +6,11 @@ SECTIONS
|
|||
.text.boot : { *(.text.boot) }
|
||||
.text : { *(.text) }
|
||||
.data : { *(.data) }
|
||||
.note.ktest : {
|
||||
__ktest_start = .;
|
||||
*(.note.ktest)
|
||||
__ktest_end = .;
|
||||
}
|
||||
.rodata : { *(.rodata) }
|
||||
.bss : {
|
||||
*(COMMON)
|
||||
|
|
|
@ -38,8 +38,16 @@ SECTIONS
|
|||
|
||||
.data : {
|
||||
*(.data .data.*)
|
||||
*(.got .got.*)
|
||||
} :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 : {
|
||||
*(COMMON)
|
||||
*(.bss .bss.*)
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
use {
|
||||
crate::{alloc::string::ToString, device_tree::DeviceTree, kmain::DEVICE_TREE},
|
||||
alloc::string::String,
|
||||
crate::{device_tree::DeviceTree, kmain::DEVICE_TREE},
|
||||
core::arch::asm,
|
||||
xml::XMLElement,
|
||||
};
|
||||
|
@ -28,8 +27,8 @@ fn collect_cpu_info(device_tree: &mut DeviceTree) {
|
|||
cpus.push(cpu);
|
||||
}
|
||||
|
||||
fn cpu_id() -> (String, u64) {
|
||||
let mut cpu_id: u64 = 0;
|
||||
fn cpu_id<'a>() -> (&'a str, u64) {
|
||||
let mut cpu_id: u64;
|
||||
unsafe {
|
||||
asm!("mrs {cpu_id}, MIDR_EL1",
|
||||
cpu_id = out(reg) cpu_id,
|
||||
|
@ -39,9 +38,11 @@ fn cpu_id() -> (String, u64) {
|
|||
let cpu_name = match cpu_id {
|
||||
// the source of these two was a stackoverflow question
|
||||
// https://raspberrypi.stackexchange.com/questions/117175/how-do-i-read-the-cpuid-in-aarch64-asm
|
||||
0x410FD034 => "Cortex-A53".to_string(),
|
||||
0x410FD083 => "Cortex-A72".to_string(),
|
||||
_ => "Unknown".to_string(),
|
||||
0x410FD034 => "Cortex-A53",
|
||||
0x410FD083 => "Cortex-A72",
|
||||
// the source of this one was checking the cpu id :thinking:
|
||||
0x410FD493 => "Neoverse N2",
|
||||
_ => "Unknown",
|
||||
};
|
||||
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};
|
||||
const SERIAL_CONSOLE: Mutex<SerialConsole> = Mutex::new(SerialConsole {
|
||||
pub static SERIAL_CONSOLE: Mutex<SerialConsole> = Mutex::new(SerialConsole {
|
||||
uart: 0x09000000 as *mut u8,
|
||||
});
|
||||
|
||||
struct SerialConsole {
|
||||
pub struct SerialConsole {
|
||||
uart: *mut u8,
|
||||
}
|
||||
|
||||
|
@ -17,9 +17,12 @@ impl core::fmt::Write for SerialConsole {
|
|||
}
|
||||
}
|
||||
|
||||
unsafe impl Sync for SerialConsole {}
|
||||
unsafe impl Send for SerialConsole {}
|
||||
|
||||
pub fn log(args: core::fmt::Arguments<'_>) -> core::fmt::Result {
|
||||
SERIAL_CONSOLE.lock().write_fmt(args)?;
|
||||
TERMINAL_LOGGER.lock().write_fmt(args)?;
|
||||
// TERMINAL_LOGGER.lock().write_fmt(args)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
pub use logging::log;
|
||||
use {
|
||||
crate::{allocator, bootmodules::BootModule, kmain::kmain},
|
||||
alloc::vec::Vec,
|
||||
core::arch::asm,
|
||||
limine::FramebufferRequest,
|
||||
};
|
||||
|
@ -41,7 +42,7 @@ unsafe extern "C" fn _kernel_start() -> ! {
|
|||
static KFILE_REQ: KernelFileRequest = KernelFileRequest::new(0);
|
||||
static MOD_REQ: ModuleRequest = ModuleRequest::new(0);
|
||||
|
||||
let mut bootmodules = alloc::vec::Vec::new();
|
||||
let mut bootmodules = Vec::new();
|
||||
|
||||
if bm.is_some() {
|
||||
let bm = bm.unwrap();
|
||||
|
@ -52,18 +53,13 @@ unsafe extern "C" fn _kernel_start() -> ! {
|
|||
let raw_bytes = core::slice::from_raw_parts(
|
||||
file.base.as_ptr().expect("invalid initrd"),
|
||||
file.length as usize,
|
||||
)
|
||||
.to_vec();
|
||||
|
||||
let file_path = alloc::string::String::from_utf8(
|
||||
file.path.to_str().unwrap().to_bytes().to_vec(),
|
||||
);
|
||||
|
||||
let file_path = file.path.to_str().unwrap().to_str();
|
||||
if file_path.is_err() {
|
||||
panic!("invalid file path: {:?}", file_path);
|
||||
}
|
||||
let file_cmd = alloc::string::String::from_utf8(
|
||||
file.cmdline.to_str().unwrap().to_bytes().to_vec(),
|
||||
);
|
||||
let file_cmd = file.cmdline.to_str().unwrap().to_str();
|
||||
if file_cmd.is_err() {
|
||||
panic!("invalid module cmd: {:?}", file_cmd);
|
||||
}
|
||||
|
@ -85,7 +81,7 @@ unsafe extern "C" fn _kernel_start() -> ! {
|
|||
assert_eq!(bm.module_count, bootmodules.len() as u64);
|
||||
}
|
||||
|
||||
crate::kmain::kmain(
|
||||
kmain(
|
||||
KFILE_REQ
|
||||
.get_response()
|
||||
.get()
|
||||
|
@ -99,8 +95,6 @@ unsafe extern "C" fn _kernel_start() -> ! {
|
|||
.unwrap_or_default(),
|
||||
bootmodules,
|
||||
);
|
||||
|
||||
spin_loop();
|
||||
}
|
||||
|
||||
pub fn spin_loop() -> ! {
|
||||
|
@ -109,8 +103,19 @@ pub fn spin_loop() -> ! {
|
|||
}
|
||||
}
|
||||
|
||||
/// I am sorry.
|
||||
static mut A_REAL_RANDOM_U64_I_PROMISE: u64 = 0;
|
||||
|
||||
pub fn hardware_random_u64() -> u64 {
|
||||
0
|
||||
if let Some(rng) = aarch64_cpu::asm::random::ArmRng::new() {
|
||||
if let Some(rnd) = rng.rndr() {
|
||||
return rnd;
|
||||
}
|
||||
}
|
||||
unsafe {
|
||||
A_REAL_RANDOM_U64_I_PROMISE += 1;
|
||||
A_REAL_RANDOM_U64_I_PROMISE
|
||||
}
|
||||
}
|
||||
|
||||
pub fn register_dump() {}
|
||||
|
|
|
@ -14,3 +14,29 @@ arch_cond!(
|
|||
riscv64: "riscv64",
|
||||
x86_64: "x86_64",
|
||||
);
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
use {crate::arch::interrupts::Interrupt, alloc::string::String};
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
pub struct InterruptList {
|
||||
list: HashMap<Interrupt, String>,
|
||||
}
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
use hashbrown::HashMap;
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
impl InterruptList {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
list: HashMap::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
use spin::{Lazy, Mutex};
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
pub static INTERRUPT_LIST: Lazy<Mutex<InterruptList>> = Lazy::new(|| {
|
||||
let mut il = InterruptList::new();
|
||||
use crate::alloc::string::ToString;
|
||||
il.list.insert(Interrupt::Timer, "PS/2 Mouse".to_string());
|
||||
Mutex::new(il)
|
||||
});
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
use core::num;
|
||||
|
||||
use alloc::boxed::Box;
|
||||
use spin::{Mutex, Once};
|
||||
use crate::memory::{MemoryManager, PhysicalAddress, VirtualAddress};
|
||||
use {
|
||||
crate::memory::{MemoryManager, PhysicalAddress, VirtualAddress},
|
||||
alloc::boxed::Box,
|
||||
spin::{Mutex, Once},
|
||||
};
|
||||
|
||||
use super::PAGE_SIZE;
|
||||
|
||||
|
@ -28,7 +30,7 @@ impl PageSize {
|
|||
}
|
||||
|
||||
pub struct PageTable {
|
||||
entries: [PageEntry; 512]
|
||||
entries: [PageEntry; 512],
|
||||
}
|
||||
|
||||
impl PageTable {
|
||||
|
@ -72,8 +74,14 @@ impl PageTable {
|
|||
/// flags MUST include one or more of the following:
|
||||
/// Read, Write, Execute
|
||||
/// The valid bit automatically gets added
|
||||
pub fn map(&mut self, vaddr: VirtualAddress, paddr: PhysicalAddress, flags: PageEntryFlags, page_size: PageSize) {
|
||||
assert!(flags as usize & 0xe != 0);
|
||||
pub fn map(
|
||||
&mut self,
|
||||
vaddr: VirtualAddress,
|
||||
paddr: PhysicalAddress,
|
||||
flags: PageEntryFlags,
|
||||
page_size: PageSize,
|
||||
) {
|
||||
assert!(flags as usize & 0xE != 0);
|
||||
|
||||
let vpn = vaddr.vpns();
|
||||
let ppn = paddr.ppns();
|
||||
|
@ -105,14 +113,24 @@ impl PageTable {
|
|||
}
|
||||
|
||||
/// Identity maps a page of memory
|
||||
pub fn identity_map(&mut self, addr: PhysicalAddress, flags: PageEntryFlags, page_size: PageSize) {
|
||||
pub fn identity_map(
|
||||
&mut self,
|
||||
addr: PhysicalAddress,
|
||||
flags: PageEntryFlags,
|
||||
page_size: PageSize,
|
||||
) {
|
||||
// log::debug!("identity mapped {addr}");
|
||||
self.map(addr.as_addr().into(), addr, flags, page_size);
|
||||
}
|
||||
|
||||
/// Identity maps a range of contiguous memory
|
||||
/// This assumes that start <= end
|
||||
pub fn identity_map_range(&mut self, start: PhysicalAddress, end: PhysicalAddress, flags: PageEntryFlags) {
|
||||
pub fn identity_map_range(
|
||||
&mut self,
|
||||
start: PhysicalAddress,
|
||||
end: PhysicalAddress,
|
||||
flags: PageEntryFlags,
|
||||
) {
|
||||
log::debug!("start: {start}, end: {end}");
|
||||
let mut mem_addr = start.as_addr() & !(PAGE_SIZE - 1);
|
||||
let num_pages = (align_val(end.as_addr(), 12) - mem_addr - 1) / PAGE_SIZE + 1;
|
||||
|
@ -228,7 +246,7 @@ impl PageEntry {
|
|||
}
|
||||
|
||||
fn addr(&self) -> PhysicalAddress {
|
||||
((self.entry() as usize & !0x3ff) << 2).into()
|
||||
((self.entry() as usize & !0x3FF) << 2).into()
|
||||
}
|
||||
|
||||
fn destroy(&mut self) {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
mod memory;
|
||||
|
||||
use {
|
||||
alloc::boxed::Box,
|
||||
alloc::{boxed::Box, vec::Vec},
|
||||
core::{
|
||||
arch::{asm, global_asm},
|
||||
fmt::Write,
|
||||
|
@ -45,7 +45,7 @@ extern "C" {
|
|||
static USABLE_MEMORY_SIZE: usize;
|
||||
}
|
||||
|
||||
static SERIAL_CONSOLE: Once<Mutex<MmioSerialPort>> = Once::new();
|
||||
pub static SERIAL_CONSOLE: Once<Mutex<MmioSerialPort>> = Once::new();
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn _kernel_start() -> ! {
|
||||
|
@ -95,7 +95,7 @@ unsafe extern "C" fn _kernel_start() -> ! {
|
|||
in(reg) satp_value,
|
||||
);
|
||||
|
||||
crate::kmain::kmain("baka=9", None);
|
||||
crate::kmain::kmain("baka=9", Vec::new());
|
||||
}
|
||||
|
||||
/// Spin loop
|
||||
|
@ -105,6 +105,12 @@ pub fn spin_loop() -> ! {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn hardware_random_u64() -> u64 {
|
||||
0
|
||||
}
|
||||
|
||||
pub fn register_dump() {}
|
||||
|
||||
pub fn log(args: core::fmt::Arguments<'_>) -> core::fmt::Result {
|
||||
SERIAL_CONSOLE.get().unwrap().lock().write_fmt(args)
|
||||
}
|
||||
|
|
|
@ -11,6 +11,9 @@ use {
|
|||
|
||||
pub const DOUBLE_FAULT_IX: u16 = 0;
|
||||
|
||||
const STACK_SIZE: usize = 5 * 1024;
|
||||
const STACK_ALIGNMENT: usize = 1;
|
||||
|
||||
pub unsafe fn init() {
|
||||
use x86_64::instructions::{
|
||||
segmentation::{Segment, CS, SS},
|
||||
|
@ -32,24 +35,24 @@ struct Selectors {
|
|||
|
||||
static TSS: Lazy<TaskStateSegment> = Lazy::new(|| {
|
||||
let mut tss = TaskStateSegment::new();
|
||||
tss.interrupt_stack_table[usize::from(DOUBLE_FAULT_IX)] = {
|
||||
const SIZE: usize = 5 * 1024;
|
||||
let stack = unsafe {
|
||||
alloc::alloc::alloc_zeroed(
|
||||
alloc::alloc::Layout::from_size_align(SIZE, 1).expect("stack pointer"),
|
||||
)
|
||||
};
|
||||
VirtAddr::from_ptr(stack) + SIZE
|
||||
|
||||
let stack_ptr = unsafe {
|
||||
let layout = alloc::alloc::Layout::from_size_align(STACK_SIZE, STACK_ALIGNMENT)
|
||||
.expect("Failed to create stack layout");
|
||||
let stack = alloc::alloc::alloc(layout);
|
||||
VirtAddr::from_ptr(stack) + STACK_SIZE as u64
|
||||
};
|
||||
|
||||
tss.interrupt_stack_table[usize::from(DOUBLE_FAULT_IX)] = stack_ptr;
|
||||
tss
|
||||
});
|
||||
|
||||
static GDT: Lazy<(GlobalDescriptorTable, Selectors)> = Lazy::new(|| {
|
||||
let mut gdt = GlobalDescriptorTable::new();
|
||||
let sels = Selectors {
|
||||
kcode: gdt.add_entry(Descriptor::kernel_code_segment()),
|
||||
kdata: gdt.add_entry(Descriptor::kernel_data_segment()),
|
||||
tss: gdt.add_entry(Descriptor::tss_segment(&TSS)),
|
||||
kcode: gdt.append(Descriptor::kernel_code_segment()),
|
||||
kdata: gdt.append(Descriptor::kernel_data_segment()),
|
||||
tss: gdt.append(Descriptor::tss_segment(&TSS)),
|
||||
};
|
||||
(gdt, sels)
|
||||
});
|
||||
|
|
|
@ -1,56 +1,54 @@
|
|||
// TODO: Turn apic keyboard interrupt into a standard ipc message
|
||||
use {
|
||||
core::mem::MaybeUninit,
|
||||
log::trace,
|
||||
spin::{Lazy, Mutex},
|
||||
x2apic::lapic::{LocalApic, LocalApicBuilder},
|
||||
x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame, PageFaultErrorCode},
|
||||
};
|
||||
|
||||
pub unsafe fn init() {
|
||||
trace!("Initialising IDT");
|
||||
IDT.load();
|
||||
Lazy::force(&LAPIC);
|
||||
x86_64::instructions::interrupts::enable();
|
||||
}
|
||||
/// Safety: Using LAPIC or IDT before init() is UB
|
||||
/// Using
|
||||
static mut LAPIC: LocalApic = unsafe { MaybeUninit::zeroed().assume_init() };
|
||||
static mut IDT: InterruptDescriptorTable = unsafe { MaybeUninit::zeroed().assume_init() };
|
||||
|
||||
#[repr(u8)]
|
||||
enum Interrupt {
|
||||
Timer = 32,
|
||||
#[derive(Debug, Eq, Hash, PartialEq)]
|
||||
|
||||
pub enum Interrupt {
|
||||
Timer = 32,
|
||||
ApicErr = u8::MAX - 1,
|
||||
Spurious = u8::MAX,
|
||||
}
|
||||
|
||||
pub(crate) static LAPIC: Lazy<Mutex<LocalApic>> = Lazy::new(|| {
|
||||
let mut lapic = LocalApicBuilder::new()
|
||||
pub unsafe fn init() {
|
||||
trace!("Initializing IDT and LAPIC");
|
||||
|
||||
// Initialize and load the IDT
|
||||
IDT = InterruptDescriptorTable::new();
|
||||
IDT.double_fault
|
||||
.set_handler_fn(double_fault)
|
||||
.set_stack_index(super::gdt::DOUBLE_FAULT_IX);
|
||||
IDT.page_fault.set_handler_fn(page_fault);
|
||||
|
||||
IDT[Interrupt::ApicErr as u8].set_handler_fn(apic_err);
|
||||
IDT[Interrupt::Spurious as u8].set_handler_fn(spurious);
|
||||
IDT[Interrupt::Timer as u8].set_handler_fn(timer);
|
||||
|
||||
IDT.load();
|
||||
|
||||
LAPIC = LocalApicBuilder::new()
|
||||
.timer_vector(Interrupt::Timer as usize)
|
||||
.error_vector(Interrupt::ApicErr as usize)
|
||||
.spurious_vector(Interrupt::Spurious as usize)
|
||||
.set_xapic_base(
|
||||
unsafe { x2apic::lapic::xapic_base() }
|
||||
x2apic::lapic::xapic_base()
|
||||
+ super::memory::HHDM_OFFSET.load(core::sync::atomic::Ordering::Relaxed),
|
||||
)
|
||||
.build()
|
||||
.expect("failed to setup Local APIC");
|
||||
unsafe { lapic.enable() };
|
||||
Mutex::new(lapic)
|
||||
});
|
||||
.expect("Failed to setup Local APIC");
|
||||
LAPIC.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);
|
||||
x86_64::instructions::interrupts::enable();
|
||||
}
|
||||
idt.page_fault.set_handler_fn(page_fault);
|
||||
|
||||
idt[Interrupt::ApicErr as usize].set_handler_fn(apic_err);
|
||||
idt[Interrupt::Spurious as usize].set_handler_fn(spurious);
|
||||
idt[Interrupt::Timer as usize].set_handler_fn(timer);
|
||||
|
||||
idt
|
||||
});
|
||||
|
||||
extern "x86-interrupt" fn double_fault(stack_frame: InterruptStackFrame, error_code: u64) -> ! {
|
||||
panic!("Double fault: error code {error_code} \n{stack_frame:#?}")
|
||||
|
@ -64,13 +62,52 @@ extern "x86-interrupt" fn page_fault(
|
|||
}
|
||||
|
||||
extern "x86-interrupt" fn timer(_isf: InterruptStackFrame) {
|
||||
unsafe { LAPIC.lock().end_of_interrupt() };
|
||||
interrupt(Interrupt::Timer);
|
||||
|
||||
unsafe {
|
||||
LAPIC.end_of_interrupt();
|
||||
}
|
||||
}
|
||||
|
||||
extern "x86-interrupt" fn apic_err(_: InterruptStackFrame) {
|
||||
interrupt(Interrupt::ApicErr);
|
||||
|
||||
panic!("Internal APIC error");
|
||||
}
|
||||
|
||||
extern "x86-interrupt" fn spurious(_: InterruptStackFrame) {
|
||||
unsafe { LAPIC.lock().end_of_interrupt() };
|
||||
interrupt(Interrupt::Spurious);
|
||||
|
||||
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,11 +1,6 @@
|
|||
//! Logging (as in terms of console / serial output)
|
||||
#![allow(deprecated)]
|
||||
use {
|
||||
core::fmt::Write,
|
||||
limine::{TerminalRequest, TerminalResponse},
|
||||
spin::{Lazy, Mutex},
|
||||
uart_16550::SerialPort,
|
||||
};
|
||||
use {core::fmt::Write, spin::Mutex, uart_16550::SerialPort};
|
||||
|
||||
pub static SERIAL_CONSOLE: Mutex<SerialPort> = Mutex::new(unsafe { SerialPort::new(0x3F8) });
|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
use {
|
||||
crate::bootmodules::BootModule, core::arch::asm, embedded_graphics::pixelcolor::Rgb888,
|
||||
log::warn, rdrand::RdSeed,
|
||||
};
|
||||
use core::arch::x86_64::{_rdrand64_step, _rdseed64_step};
|
||||
|
||||
use {crate::bootmodules::BootModule, core::arch::asm, log::warn};
|
||||
pub mod memory;
|
||||
|
||||
mod cpuid;
|
||||
|
@ -11,7 +10,7 @@ pub mod graphics;
|
|||
pub(crate) mod interrupts;
|
||||
pub mod logging;
|
||||
pub mod pci;
|
||||
pub mod virtio;
|
||||
// pub mod virtio;
|
||||
|
||||
pub use {logging::log, memory::PAGE_SIZE};
|
||||
|
||||
|
@ -31,9 +30,11 @@ const INITIAL_KERNEL_HEAP_SIZE: *const () = _initial_kernel_heap_size as _;
|
|||
|
||||
#[no_mangle]
|
||||
#[naked]
|
||||
#[cfg(not(target_feature = "avx2"))]
|
||||
unsafe extern "C" fn _kernel_start() -> ! {
|
||||
// Initialise SSE and jump to kernel entrypoint
|
||||
core::arch::asm!(
|
||||
// Initialise SSE, then jump to kernel entrypoint
|
||||
core::arch::naked_asm!(
|
||||
// Initialise SSE
|
||||
"mov rax, cr0",
|
||||
"and ax, 0xfffb",
|
||||
"or ax, 0x2",
|
||||
|
@ -41,16 +42,74 @@ unsafe extern "C" fn _kernel_start() -> ! {
|
|||
"mov rax, cr4",
|
||||
"or ax, 3 << 9",
|
||||
"mov cr4, rax",
|
||||
|
||||
// Jump to the kernel entry point
|
||||
"jmp {}",
|
||||
sym start,
|
||||
options(noreturn),
|
||||
)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[naked]
|
||||
#[cfg(target_feature = "avx2")]
|
||||
unsafe extern "C" fn _kernel_start() -> ! {
|
||||
core::arch::naked_asm!(
|
||||
// Enable protected mode and configure control registers
|
||||
"mov rax, cr0",
|
||||
"and ax, 0xFFFB", // Clear CR0.EM (bit 2) for coprocessor emulation
|
||||
"or ax, 0x2", // Set CR0.MP (bit 1) for coprocessor monitoring
|
||||
"mov cr0, rax",
|
||||
|
||||
"mov rax, cr4",
|
||||
"or ax, (1 << 9) | (1 << 10)", // Set CR4.OSFXSR (bit 9) and CR4.OSXMMEXCPT (bit 10)
|
||||
"mov cr4, rax",
|
||||
|
||||
// Enable OSXSAVE (required for AVX, AVX2, and XSAVE)
|
||||
"mov rax, cr4",
|
||||
"or eax, 1 << 18", // Set CR4.OSXSAVE (bit 18)
|
||||
"mov cr4, rax",
|
||||
|
||||
// Enable AVX and AVX2 state saving
|
||||
"xor rcx, rcx",
|
||||
"xgetbv",
|
||||
"or eax, 7", // Enable SSE, AVX, and AVX2 state saving
|
||||
"xsetbv",
|
||||
|
||||
// Check for AVX and XSAVE support
|
||||
"mov eax, 1",
|
||||
"cpuid",
|
||||
"and ecx, 0x18000000",
|
||||
"cmp ecx, 0x18000000",
|
||||
"jne {1}", // Jump if AVX/OSXSAVE is not supported
|
||||
|
||||
// Check for BMI2 and AVX2 support
|
||||
"mov eax, 7",
|
||||
"xor ecx, ecx",
|
||||
"cpuid",
|
||||
"and ebx, (1 << 8) | (1 << 5)", // Check BMI2 (bit 8) and AVX2 (bit 5)
|
||||
"cmp ebx, (1 << 8) | (1 << 5)", // Compare to ensure both are supported
|
||||
|
||||
// Check for LZCNT and POPCNT support
|
||||
"mov eax, 1",
|
||||
"cpuid",
|
||||
"and ecx, (1 << 5) | (1 << 23)", // Check LZCNT (bit 5) and POPCNT (bit 23)
|
||||
"cmp ecx, (1 << 5) | (1 << 23)", // Compare to ensure both are supported
|
||||
|
||||
// Jump to the kernel entry point
|
||||
"jmp {0}",
|
||||
sym start,
|
||||
sym oops,
|
||||
)
|
||||
}
|
||||
|
||||
unsafe extern "C" fn oops() -> ! {
|
||||
panic!("your cpu is ancient >:(")
|
||||
}
|
||||
|
||||
unsafe extern "C" fn start() -> ! {
|
||||
logging::init();
|
||||
crate::logger::init().expect("failed to set logger");
|
||||
log::info!("Initialising AKern {}", crate::VERSION);
|
||||
log::debug!("Initialising AKern {}", crate::VERSION);
|
||||
|
||||
static HDHM_REQ: HhdmRequest = HhdmRequest::new(0);
|
||||
memory::init_pt(VirtAddr::new(
|
||||
|
@ -129,7 +188,7 @@ unsafe extern "C" fn start() -> ! {
|
|||
// TODO: Add in rdseed and rdrand as sources for randomness
|
||||
let _rand = xml::XMLElement::new("Random");
|
||||
|
||||
log::trace!("Getting boot modules");
|
||||
log::debug!("Getting boot modules");
|
||||
let bm = MOD_REQ.get_response().get();
|
||||
|
||||
let mut bootmodules = alloc::vec::Vec::new();
|
||||
|
@ -143,18 +202,13 @@ unsafe extern "C" fn start() -> ! {
|
|||
let raw_bytes = core::slice::from_raw_parts(
|
||||
file.base.as_ptr().expect("invalid initrd"),
|
||||
file.length as usize,
|
||||
)
|
||||
.to_vec();
|
||||
|
||||
let file_path = alloc::string::String::from_utf8(
|
||||
file.path.to_str().unwrap().to_bytes().to_vec(),
|
||||
);
|
||||
|
||||
let file_path = file.path.to_str().unwrap().to_str();
|
||||
if file_path.is_err() {
|
||||
panic!("invalid file path: {:?}", file_path);
|
||||
}
|
||||
let file_cmd = alloc::string::String::from_utf8(
|
||||
file.cmdline.to_str().unwrap().to_bytes().to_vec(),
|
||||
);
|
||||
let file_cmd = file.cmdline.to_str().unwrap().to_str();
|
||||
if file_cmd.is_err() {
|
||||
panic!("invalid module cmd: {:?}", file_cmd);
|
||||
}
|
||||
|
@ -172,7 +226,7 @@ unsafe extern "C" fn start() -> ! {
|
|||
break;
|
||||
}
|
||||
}
|
||||
log::info!("Boot module count: {:?}", bootmodules.len());
|
||||
log::debug!("Boot module count: {:?}", bootmodules.len());
|
||||
assert_eq!(bm.module_count, bootmodules.len() as u64);
|
||||
}
|
||||
|
||||
|
@ -195,32 +249,21 @@ unsafe extern "C" fn start() -> ! {
|
|||
/// Spin loop
|
||||
pub fn spin_loop() -> ! {
|
||||
loop {
|
||||
x86_64::instructions::hlt();
|
||||
core::hint::spin_loop();
|
||||
x86_64::instructions::hlt()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn hardware_random_u64() -> u64 {
|
||||
use {log::trace, rdrand::RdRand};
|
||||
let gen = RdRand::new();
|
||||
match gen {
|
||||
Ok(gen) => {
|
||||
let ret = gen.try_next_u64().unwrap();
|
||||
trace!("Random {}", ret);
|
||||
return ret;
|
||||
}
|
||||
Err(err) => {
|
||||
let mut out: u64 = 0;
|
||||
match unsafe { _rdrand64_step(&mut out) } {
|
||||
1 => out,
|
||||
_ => {
|
||||
warn!("RDRand not supported.");
|
||||
// Try rdseed
|
||||
let gen = RdSeed::new();
|
||||
match gen {
|
||||
Ok(gen) => {
|
||||
let ret = gen.try_next_u64().unwrap();
|
||||
trace!("Random {}", ret);
|
||||
return ret;
|
||||
}
|
||||
Err(err) => {
|
||||
panic!("Neither RDRand or RDSeed are supported")
|
||||
}
|
||||
match unsafe { _rdseed64_step(&mut out) } {
|
||||
1 => out,
|
||||
_ => panic!("Neither RDRand or RDSeed are supported"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -228,6 +271,7 @@ pub fn hardware_random_u64() -> u64 {
|
|||
|
||||
pub fn get_edid() {}
|
||||
|
||||
#[allow(unused)]
|
||||
pub fn register_dump() {
|
||||
let rax: u64;
|
||||
let rbx: u64 = 0;
|
||||
|
|
|
@ -8,12 +8,12 @@ pub struct PciDeviceInfo {
|
|||
pub full_class: PciFullClass,
|
||||
pub rev_id: u8,
|
||||
}
|
||||
use crate::alloc::string::ToString;
|
||||
|
||||
/// Enumerate PCI devices and run initialisation routines on ones we support
|
||||
pub fn init(device_tree: &mut DeviceTree) {
|
||||
device_tree.devices
|
||||
.insert("Unidentified PCI".to_string(), alloc::vec![]);
|
||||
device_tree
|
||||
.devices
|
||||
.insert("Unidentified PCI", alloc::vec![]);
|
||||
let mut devices = alloc::vec![];
|
||||
|
||||
for bus in 0..=255 {
|
||||
|
@ -23,6 +23,7 @@ pub fn init(device_tree: &mut DeviceTree) {
|
|||
let id = device_info.device_id.id;
|
||||
use Vendor::*;
|
||||
let (dev_type, dev_name) = match (vendor, id) {
|
||||
(VMWareInc, 1029) => ("GPUs", "SVGAII PCI GPU"),
|
||||
(Qemu, 4369) => ("GPUs", "QEMU VGA"),
|
||||
(VirtIO, 4176) => ("GPUs", "VirtIO PCI GPU"),
|
||||
(CirrusLogic, 184) => ("GPUs", "Cirrus SVGA"), //GD 5446?
|
||||
|
@ -45,7 +46,8 @@ pub fn init(device_tree: &mut DeviceTree) {
|
|||
pci_info.set_attribute("id", id);
|
||||
pci_info.set_attribute("device", device_info.device);
|
||||
pci_info.set_attribute("vendor", vendor);
|
||||
pci_info.set_attribute("class", device_info.full_class.to_string());
|
||||
pci_info.set_attribute("bus", bus);
|
||||
pci_info.set_attribute("class", device_info.full_class);
|
||||
dev.set_child(pci_info);
|
||||
devices.push((dev_type, dev));
|
||||
}
|
||||
|
@ -66,7 +68,8 @@ pub fn check_device(bus: u8, device: u8) -> Option<PciDeviceInfo> {
|
|||
return None;
|
||||
}
|
||||
|
||||
let reg2 = unsafe { pci_config_read(bus, device, 0, 0x8) };
|
||||
let (reg2, addr) = unsafe { pci_config_read_2(bus, device, 0, 0x8) };
|
||||
log::debug!("pci device-({}) addr {} is {}", device, addr, reg2);
|
||||
let class = ((reg2 >> 16) & 0x0000_FFFF) as u16;
|
||||
let pci_class = PciFullClass::from_u16(class);
|
||||
let header_type = get_header_type(bus, device, 0);
|
||||
|
@ -269,8 +272,7 @@ impl Display for Vendor {
|
|||
|
||||
use core::fmt::Display;
|
||||
|
||||
use x86_64::instructions::port::Port;
|
||||
use crate::device_tree::DeviceTree;
|
||||
use {crate::device_tree::DeviceTree, x86_64::instructions::port::Port};
|
||||
|
||||
#[allow(non_camel_case_types, dead_code)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
|
@ -458,9 +460,7 @@ unsafe fn pci_config_read(bus: u8, device: u8, func: u8, offset: u8) -> u32 {
|
|||
let func = func as u32;
|
||||
let offset = offset as u32;
|
||||
// construct address param
|
||||
let address =
|
||||
((bus << 16) | (device << 11) | (func << 8) | (offset & 0xFC) | 0x8000_0000) as u32;
|
||||
|
||||
let address = (bus << 16) | (device << 11) | (func << 8) | (offset & 0xFC) | 0x8000_0000;
|
||||
// write address
|
||||
Port::new(0xCF8).write(address);
|
||||
|
||||
|
@ -468,6 +468,20 @@ unsafe fn pci_config_read(bus: u8, device: u8, func: u8, offset: u8) -> u32 {
|
|||
Port::new(0xCFC).read()
|
||||
}
|
||||
|
||||
unsafe fn pci_config_read_2(bus: u8, device: u8, func: u8, offset: u8) -> (u32, u32) {
|
||||
let bus = bus as u32;
|
||||
let device = device as u32;
|
||||
let func = func as u32;
|
||||
let offset = offset as u32;
|
||||
// construct address param
|
||||
let address = (bus << 16) | (device << 11) | (func << 8) | (offset & 0xFC) | 0x8000_0000;
|
||||
// write address
|
||||
Port::new(0xCF8).write(address);
|
||||
|
||||
// read data
|
||||
(Port::new(0xCFC).read(), address)
|
||||
}
|
||||
|
||||
unsafe fn pci_config_write(bus: u8, device: u8, func: u8, offset: u8, value: u32) {
|
||||
let bus = bus as u32;
|
||||
let device = device as u32;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use {
|
||||
core::{ptr::NonNull},
|
||||
core::ptr::NonNull,
|
||||
virtio_drivers::{BufferDirection, Hal, PhysAddr},
|
||||
};
|
||||
|
||||
|
|
|
@ -1,36 +1,36 @@
|
|||
use {
|
||||
crate::alloc::string::ToString,
|
||||
alloc::{string::String, vec::Vec},
|
||||
clparse::Arguments,
|
||||
core::fmt::{Debug, Display},
|
||||
log::trace,
|
||||
xml::XMLElement,
|
||||
// crate::alloc::string::ToString,
|
||||
alloc::vec::Vec,
|
||||
// clparse::Arguments,
|
||||
// core::fmt::{Debug, Display},
|
||||
// log::trace,
|
||||
// xml::XMLElement,
|
||||
};
|
||||
pub type BootModules = Vec<BootModule>;
|
||||
pub type BootModules<'a> = Vec<BootModule<'a>>;
|
||||
|
||||
pub struct BootModule {
|
||||
pub path: String,
|
||||
pub bytes: Vec<u8>,
|
||||
pub cmd: String,
|
||||
pub struct BootModule<'a> {
|
||||
pub path: &'a str,
|
||||
pub bytes: &'a [u8],
|
||||
pub cmd: &'a str,
|
||||
}
|
||||
impl BootModule {
|
||||
pub fn new(path: String, bytes: Vec<u8>, cmd: String) -> Self {
|
||||
impl<'a> BootModule<'a> {
|
||||
pub fn new(path: &'a str, bytes: &'a [u8], cmd: &'a str) -> Self {
|
||||
Self { path, bytes, cmd }
|
||||
}
|
||||
}
|
||||
|
||||
pub fn build_cmd<T: Display + Debug>(name: T, cmdline: T) -> XMLElement {
|
||||
let mut cmdline = cmdline.to_string();
|
||||
cmdline.pop();
|
||||
cmdline.remove(0);
|
||||
// pub fn build_cmd<T: Display + Debug>(name: T, cmdline: T) -> XMLElement {
|
||||
// let mut cmdline = cmdline.to_string();
|
||||
// cmdline.pop();
|
||||
// cmdline.remove(0);
|
||||
|
||||
let cmd = Arguments::parse(cmdline.to_string()).unwrap();
|
||||
trace!("Cmdline: {cmd:?}");
|
||||
// let cmd = Arguments::parse(cmdline.to_string()).unwrap();
|
||||
// trace!("Cmdline: {cmd:?}");
|
||||
|
||||
let mut clo = XMLElement::new(name);
|
||||
for (key, value) in cmd.arguments {
|
||||
clo.set_attribute(key, value);
|
||||
}
|
||||
trace!("command line object: {:?}", clo);
|
||||
clo
|
||||
}
|
||||
// let mut clo = XMLElement::new(name);
|
||||
// for (key, value) in cmd.arguments {
|
||||
// clo.set_attribute(key, value);
|
||||
// }
|
||||
// trace!("command line object: {:?}", clo);
|
||||
// clo
|
||||
// }
|
||||
|
|
|
@ -1,11 +1,7 @@
|
|||
//! A tree of hardware devices
|
||||
|
||||
use {
|
||||
crate::alloc::string::ToString,
|
||||
alloc::{string::String, vec::Vec},
|
||||
core::fmt,
|
||||
hashbrown::HashMap,
|
||||
};
|
||||
use {alloc::vec::Vec, core::fmt, hashbrown::HashMap};
|
||||
|
||||
/// A device object.
|
||||
/// TODO define device
|
||||
pub type Device = xml::XMLElement;
|
||||
|
@ -13,17 +9,19 @@ pub type Device = xml::XMLElement;
|
|||
/// A tree of devices
|
||||
// TODO: alphabetize this list
|
||||
#[derive(Debug)]
|
||||
pub struct DeviceTree {
|
||||
pub struct DeviceTree<'a> {
|
||||
/// The device tree
|
||||
pub devices: HashMap<String, Vec<Device>>,
|
||||
pub devices: HashMap<&'a str, Vec<Device>>,
|
||||
}
|
||||
impl DeviceTree {
|
||||
impl<'a> DeviceTree<'a> {
|
||||
/// Build the device tree. Does not populate the device tree
|
||||
pub fn new() -> Self {
|
||||
let mut dt = Self {
|
||||
devices: HashMap::new(),
|
||||
};
|
||||
device_tree!(dt, [
|
||||
device_tree!(
|
||||
dt,
|
||||
[
|
||||
"Mice",
|
||||
"Keyboards",
|
||||
"Controllers",
|
||||
|
@ -38,13 +36,13 @@ impl DeviceTree {
|
|||
"Serial Ports",
|
||||
"Cameras",
|
||||
"Biometric Devices",
|
||||
]);
|
||||
]
|
||||
);
|
||||
dt
|
||||
}
|
||||
}
|
||||
use crate::{utils::TAB, device_tree};
|
||||
use crate::tab;
|
||||
impl fmt::Display for DeviceTree {
|
||||
use crate::{device_tree, tab, utils::TAB};
|
||||
impl<'a> fmt::Display for DeviceTree<'a> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
writeln!(f)?;
|
||||
for (device_type, devices) in &self.devices {
|
35
kernel/src/exe_format.rs
Normal file
35
kernel/src/exe_format.rs
Normal file
|
@ -0,0 +1,35 @@
|
|||
enum Sections {
|
||||
Header,
|
||||
Code,
|
||||
Data,
|
||||
Debug,
|
||||
Config,
|
||||
Metadata,
|
||||
}
|
||||
|
||||
// 64 byte header
|
||||
#[repr(packed)]
|
||||
struct AbleOsExecutableHeader {
|
||||
magic_number: [u8; 3],
|
||||
executable_version: u32,
|
||||
|
||||
code_length: u64,
|
||||
data_length: u64,
|
||||
debug_length: u64,
|
||||
config_length: u64,
|
||||
metadata_length: u64,
|
||||
}
|
||||
|
||||
impl AbleOsExecutableHeader {
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
magic_number: [0x15, 0x91, 0xD2],
|
||||
executable_version: 0,
|
||||
code_length: 0,
|
||||
config_length: 0,
|
||||
data_length: 0,
|
||||
debug_length: 0,
|
||||
metadata_length: 0,
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,27 +1,40 @@
|
|||
//! Environment call handling routines
|
||||
|
||||
use core::borrow::Borrow;
|
||||
use {alloc::boxed::Box, core::cell::LazyCell, hbvm::mem::Address};
|
||||
|
||||
use crate::{
|
||||
allocator,
|
||||
holeybytes::kernel_services::{
|
||||
block_read,
|
||||
service_definition_service::{sds_msg_handler, SERVICES},
|
||||
holeybytes::{
|
||||
kernel_services::{
|
||||
block_read, dt_msg_handler::dt_msg_handler, logging_service::log_msg_handler,
|
||||
service_definition_service::sds_msg_handler,
|
||||
},
|
||||
ExecThread,
|
||||
},
|
||||
kmain::EXECUTOR,
|
||||
task::Executor,
|
||||
};
|
||||
|
||||
use {
|
||||
super::{mem::Memory, Vm},
|
||||
crate::{arch, holeybytes::mem, ipc::buffer::IpcBuffer, kmain::IPC_BUFFERS},
|
||||
alloc::string::String,
|
||||
log::{debug, error, info, trace, warn},
|
||||
super::Vm,
|
||||
crate::{arch, ipc::buffer::IpcBuffer, kmain::IPC_BUFFERS},
|
||||
hbvm::value::Value,
|
||||
log::{debug, error, info, trace},
|
||||
};
|
||||
|
||||
pub fn handler(vm: &mut Vm) {
|
||||
let ecall_number = vm.registers[2].cast::<u64>();
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
#[inline(always)]
|
||||
unsafe fn x86_out<T: x86_64::instructions::port::PortWrite>(address: u16, value: T) {
|
||||
x86_64::instructions::port::Port::new(address).write(value);
|
||||
}
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
#[inline(always)]
|
||||
unsafe fn x86_in<T: x86_64::instructions::port::PortRead>(address: u16) -> T {
|
||||
x86_64::instructions::port::Port::new(address).read()
|
||||
}
|
||||
|
||||
// debug!("Ecall number {:?}", ecall_number);
|
||||
//info!("Register dump: {:?}", vm.registers);
|
||||
#[inline(always)]
|
||||
pub fn handler(vm: &mut Vm, pid: &usize) {
|
||||
let ecall_number = vm.registers[2].cast::<u64>();
|
||||
|
||||
match ecall_number {
|
||||
0 => {
|
||||
|
@ -34,9 +47,9 @@ pub fn handler(vm: &mut Vm) {
|
|||
1 => {
|
||||
// Make buffer
|
||||
|
||||
let bounded = match vm.registers[3].cast::<u64>() {
|
||||
0 => false,
|
||||
1 => true,
|
||||
let bounded = match vm.registers[3] {
|
||||
Value(0) => false,
|
||||
Value(1) => true,
|
||||
_ => {
|
||||
panic!("Bad");
|
||||
}
|
||||
|
@ -45,22 +58,19 @@ pub fn handler(vm: &mut Vm) {
|
|||
let length = vm.registers[4].cast::<u64>();
|
||||
|
||||
let mut buffs = IPC_BUFFERS.lock();
|
||||
let abc;
|
||||
|
||||
match bounded {
|
||||
false => {
|
||||
abc = IpcBuffer::new(false, 0);
|
||||
}
|
||||
true => {
|
||||
abc = IpcBuffer::new(true, length);
|
||||
}
|
||||
};
|
||||
let buff_id = arch::hardware_random_u64();
|
||||
buffs.insert(buff_id, abc);
|
||||
info!("Buffer ID: {}", buff_id);
|
||||
buffs.insert(
|
||||
buff_id,
|
||||
match bounded {
|
||||
false => IpcBuffer::new(false, 0),
|
||||
true => IpcBuffer::new(true, length),
|
||||
},
|
||||
);
|
||||
vm.registers[1] = hbvm::value::Value(buff_id);
|
||||
}
|
||||
2 => {
|
||||
log::error!("Oops, deleting buffers is not implemented.")
|
||||
// Delete buffer
|
||||
}
|
||||
3 => {
|
||||
|
@ -69,16 +79,19 @@ pub fn handler(vm: &mut Vm) {
|
|||
let mem_addr = vm.registers[4].cast::<u64>();
|
||||
let length = vm.registers[5].cast::<u64>() as usize;
|
||||
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 {
|
||||
0 => match sds_msg_handler(vm, mem_addr, length) {
|
||||
Ok(()) => {}
|
||||
Err(err) => log::error!("Improper sds format"),
|
||||
Err(err) => log::error!("Improper sds format: {err:?}"),
|
||||
},
|
||||
1 => match log_msg_handler(vm, mem_addr, length) {
|
||||
Ok(()) => {}
|
||||
Err(err) => log::error!("Improper log format"),
|
||||
Err(_) => log::error!("Improper log format"),
|
||||
},
|
||||
2 => {
|
||||
use crate::holeybytes::kernel_services::mem_serve::memory_msg_handler;
|
||||
|
@ -86,173 +99,183 @@ pub fn handler(vm: &mut Vm) {
|
|||
Ok(_) => {}
|
||||
Err(_) => {}
|
||||
}
|
||||
//
|
||||
}
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
3 => {
|
||||
unsafe fn x86_in(address: u16) -> u8 {
|
||||
x86_64::instructions::port::Port::new(address).read()
|
||||
}
|
||||
unsafe fn x86_out(address: u16, value: u8) {
|
||||
x86_64::instructions::port::Port::new(address).write(value);
|
||||
}
|
||||
|
||||
let mut msg_vec = block_read(mem_addr, length);
|
||||
let msg_vec = block_read(mem_addr, length);
|
||||
let msg_type = msg_vec[0];
|
||||
msg_vec.remove(0);
|
||||
match msg_type {
|
||||
0 => {
|
||||
let mut addr = msg_vec[0] as u16;
|
||||
msg_vec.remove(0);
|
||||
0 => unsafe {
|
||||
let size = msg_vec[1];
|
||||
let addr =
|
||||
u16::from_le_bytes(msg_vec[2..4].try_into().unwrap_unchecked());
|
||||
let value = match size {
|
||||
0 => x86_in::<u8>(addr) as u64,
|
||||
1 => x86_in::<u16>(addr) as u64,
|
||||
2 => x86_in::<u32>(addr) as u64,
|
||||
_ => panic!("Trying to read size other than: 8, 16, 32 from port."),
|
||||
};
|
||||
// info!("Read the value {} from address {}", value, addr);
|
||||
vm.registers[1] = hbvm::value::Value(value);
|
||||
},
|
||||
1 => unsafe {
|
||||
let size = msg_vec[1];
|
||||
let addr =
|
||||
u16::from_le_bytes(msg_vec[2..4].try_into().unwrap_unchecked());
|
||||
// info!("Setting address {}", addr);
|
||||
|
||||
let addr2 = msg_vec[0] as u16;
|
||||
msg_vec.remove(0);
|
||||
|
||||
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) };
|
||||
match size {
|
||||
0 => x86_out(addr, msg_vec[4]),
|
||||
1 => x86_out(
|
||||
addr,
|
||||
u16::from_le_bytes(msg_vec[4..6].try_into().unwrap_unchecked()),
|
||||
),
|
||||
2 => x86_out(
|
||||
addr,
|
||||
u32::from_le_bytes(msg_vec[4..8].try_into().unwrap_unchecked()),
|
||||
),
|
||||
_ => panic!("How?"),
|
||||
}
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
#[cfg(not(target_arch = "x86_64"))]
|
||||
3 => unimplemented!("TODO: implement whatever buffer 3 does for no x86_64"),
|
||||
// source of rng
|
||||
4 => {
|
||||
let block = block_read(mem_addr, length);
|
||||
block.chunks_mut(8.min(length)).for_each(|chunk| {
|
||||
chunk.clone_from_slice(
|
||||
&crate::arch::hardware_random_u64().to_le_bytes()[..chunk.len()],
|
||||
);
|
||||
});
|
||||
vm.registers[1] = hbvm::value::Value(mem_addr);
|
||||
}
|
||||
5 => match dt_msg_handler(vm, mem_addr, length) {
|
||||
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 => {
|
||||
let mut buffs = IPC_BUFFERS.lock();
|
||||
match buffs.get_mut(&buffer_id) {
|
||||
Some(buff) => {
|
||||
let mut msg_vec = vec![];
|
||||
|
||||
for x in 0..(length as isize) {
|
||||
let xyz = mem_addr as *const u8;
|
||||
let value = unsafe { xyz.offset(x).read() };
|
||||
msg_vec.push(value);
|
||||
}
|
||||
buff.push(msg_vec.clone());
|
||||
info!(
|
||||
"Message {:?} has been sent to Buffer({})",
|
||||
msg_vec, buffer_id
|
||||
);
|
||||
let msg_vec = block_read(mem_addr, length);
|
||||
buff.push(msg_vec.to_vec());
|
||||
debug!("Sent Message {:?} to Buffer({})", msg_vec, buffer_id);
|
||||
}
|
||||
None => {
|
||||
log::error!("Access of non-existent buffer {}", buffer_id)
|
||||
}
|
||||
}
|
||||
drop(buffs);
|
||||
}
|
||||
}
|
||||
}
|
||||
4 => {
|
||||
let buffer_id = vm.registers[3].cast::<u64>();
|
||||
let mut map_ptr = vm.registers[4].cast::<u64>();
|
||||
let map_ptr = vm.registers[4].cast::<u64>();
|
||||
let max_length = vm.registers[5].cast::<u64>();
|
||||
|
||||
let mut buffs = IPC_BUFFERS.lock();
|
||||
let mut buff: &mut IpcBuffer;
|
||||
let buff: &mut IpcBuffer = match buffs.get_mut(&buffer_id) {
|
||||
Some(buff) => buff,
|
||||
None => panic!(
|
||||
"Failed to get buffer: id={buffer_id}, ptr={map_ptr}, length={max_length}"
|
||||
),
|
||||
};
|
||||
|
||||
if buffs.get_mut(&buffer_id).is_some() {
|
||||
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() {
|
||||
let msg = match buff.pop() {
|
||||
Ok(msg) => msg,
|
||||
Err(_) => return,
|
||||
};
|
||||
if msg.len() > unsafe { max_length.try_into().unwrap_unchecked() } {
|
||||
info!("{}", max_length);
|
||||
error!("Message is too long to map in.");
|
||||
} else {
|
||||
unsafe {
|
||||
let ptr: *mut u64 = &mut map_ptr;
|
||||
for (index, byte) in msg.iter().enumerate() {
|
||||
ptr.offset(index.try_into().unwrap()).write_bytes(*byte, 1);
|
||||
}
|
||||
let ptr = map_ptr as *mut u8;
|
||||
ptr.copy_from_nonoverlapping(msg.as_ptr(), msg.len());
|
||||
}
|
||||
|
||||
info!("Recieve {:?} from Buffer({})", msg, buffer_id);
|
||||
debug!("Recieve {:?} from Buffer({})", msg, buffer_id);
|
||||
}
|
||||
}
|
||||
5 => {
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
{
|
||||
let r2 = vm.registers[2].cast::<u64>();
|
||||
unsafe fn x86_in(address: u16) -> u32 {
|
||||
x86_64::instructions::port::Port::new(address).read()
|
||||
}
|
||||
unsafe fn x86_out(address: u16, value: u32) {
|
||||
x86_64::instructions::port::Port::new(address).write(value);
|
||||
}
|
||||
let x = hbvm::value::Value(unsafe { x86_in(r2 as u16) } as u64);
|
||||
info!("Read {:?} from Port {:?}", x, r2);
|
||||
let x = hbvm::value::Value(unsafe { x86_in::<u8>(r2 as u16) } as u64);
|
||||
// info!("Read {:?} from Port {:?}", x, r2);
|
||||
vm.registers[3] = x
|
||||
}
|
||||
}
|
||||
// 5
|
||||
6 => {
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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)]
|
||||
pub enum LogError {
|
||||
NoMessages,
|
||||
InvalidLogFormat,
|
||||
}
|
||||
use {alloc::vec, log::Record};
|
||||
|
||||
// fn memory_msg_handler(vm: &mut Vm, mem_addr: u64, length: usize) -> Result<(), LogError> {
|
||||
// let mut val = alloc::vec::Vec::new();
|
||||
// for _ in 0..4096 {
|
||||
// val.push(0);
|
||||
// }
|
||||
// info!("Block address: {:?}", val.as_ptr());
|
||||
// vm.registers[1] = hbvm::value::Value(val.as_ptr() as u64);
|
||||
// vm.registers[2] = hbvm::value::Value(4096);
|
||||
// Ok(())
|
||||
// }
|
||||
|
|
78
kernel/src/holeybytes/kernel_services/dt_msg_handler.rs
Normal file
78
kernel/src/holeybytes/kernel_services/dt_msg_handler.rs
Normal file
|
@ -0,0 +1,78 @@
|
|||
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;
|
||||
}
|
||||
};
|
||||
}
|
54
kernel/src/holeybytes/kernel_services/logging_service.rs
Normal file
54
kernel/src/holeybytes/kernel_services/logging_service.rs
Normal file
|
@ -0,0 +1,54 @@
|
|||
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,10 +1,7 @@
|
|||
use {
|
||||
crate::holeybytes::{
|
||||
ecah::LogError,
|
||||
kernel_services::{block_read, mem_serve},
|
||||
Vm,
|
||||
},
|
||||
alloc::alloc::alloc_zeroed,
|
||||
crate::holeybytes::{kernel_services::block_read, Vm},
|
||||
alloc::alloc::{alloc, dealloc},
|
||||
core::alloc::Layout,
|
||||
log::{debug, info},
|
||||
};
|
||||
|
||||
|
@ -19,84 +16,100 @@ pub enum MemoryQuotaType {
|
|||
KillQuota = 3,
|
||||
}
|
||||
|
||||
fn alloc_page(vm: &mut Vm, mem_addr: u64, length: usize) -> Result<(), MemoryServiceError> {
|
||||
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);
|
||||
fn alloc_page(vm: &mut Vm, _mem_addr: u64, _length: usize) -> Result<(), MemoryServiceError> {
|
||||
let ptr = unsafe { alloc(Layout::from_size_align_unchecked(4096, 8)) };
|
||||
info!("Block address: {:?}", ptr);
|
||||
vm.registers[1] = hbvm::value::Value(ptr as u64);
|
||||
vm.registers[2] = hbvm::value::Value(4096);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
unsafe fn memset(dest: *mut u8, src: *const u8, count: usize, size: usize) {
|
||||
let total_size = count * size;
|
||||
src.copy_to_nonoverlapping(dest, size);
|
||||
|
||||
let mut copied = size;
|
||||
|
||||
while copied < total_size {
|
||||
let copy_size = copied.min(total_size - copied);
|
||||
dest.add(copied).copy_from_nonoverlapping(dest, copy_size);
|
||||
copied += copy_size;
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn memory_msg_handler(
|
||||
vm: &mut Vm,
|
||||
mem_addr: u64,
|
||||
length: usize,
|
||||
) -> Result<(), MemoryServiceError> {
|
||||
let mut msg_vec = block_read(mem_addr, length);
|
||||
let msg_vec = block_read(mem_addr, length);
|
||||
let msg_type = msg_vec[0];
|
||||
|
||||
msg_vec.remove(0);
|
||||
match msg_type {
|
||||
0 => {
|
||||
let page_count = msg_vec[0];
|
||||
msg_vec.remove(0);
|
||||
0 => unsafe {
|
||||
let page_count = msg_vec[1];
|
||||
|
||||
let mptr_raw: [u8; 8] = msg_vec[0..8].try_into().unwrap();
|
||||
let mptr: u64 = u64::from_le_bytes(mptr_raw);
|
||||
let ptr = alloc(Layout::from_size_align_unchecked(
|
||||
page_count as usize * 4096,
|
||||
8,
|
||||
));
|
||||
|
||||
log::debug!("Allocating {} pages @ {:x}", page_count, mptr);
|
||||
log::debug!("Allocating {} pages @ {:x}", page_count, ptr as u64);
|
||||
|
||||
let mut val = alloc::vec::Vec::new();
|
||||
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);
|
||||
vm.registers[1] = hbvm::value::Value(ptr as u64);
|
||||
log::debug!("Kernel ptr: {:x}", ptr as u64);
|
||||
},
|
||||
|
||||
let mptr_raw: [u8; 8] = msg_vec[0..8].try_into().unwrap();
|
||||
1 => unsafe {
|
||||
let page_count = msg_vec[1];
|
||||
|
||||
let mptr_raw: [u8; 8] = msg_vec[2..10].try_into().unwrap();
|
||||
let mptr: u64 = u64::from_le_bytes(mptr_raw);
|
||||
log::debug!("Deallocating {} pages @ {:x}", page_count, mptr);
|
||||
}
|
||||
|
||||
dealloc(
|
||||
mptr as *mut u8,
|
||||
Layout::from_size_align_unchecked(page_count as usize * 4096, 8),
|
||||
)
|
||||
},
|
||||
2 => {
|
||||
use MemoryQuotaType::*;
|
||||
let quota_type = match msg_vec[0] {
|
||||
let quota_type = match msg_vec[1] {
|
||||
0 => NoQuota,
|
||||
1 => SoftQuota,
|
||||
2 => HardQuota,
|
||||
3 => KillQuota,
|
||||
_ => NoQuota,
|
||||
};
|
||||
msg_vec.remove(0);
|
||||
let hid_raw: [u8; 8] = msg_vec[0..8].try_into().unwrap();
|
||||
let hid_raw: [u8; 8] = msg_vec[2..10].try_into().unwrap();
|
||||
let hid: u64 = u64::from_le_bytes(hid_raw);
|
||||
for _ in 0..8 {
|
||||
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);
|
||||
}
|
||||
|
||||
let pid_raw: [u8; 8] = msg_vec[10..18].try_into().unwrap();
|
||||
let pid: u64 = u64::from_le_bytes(pid_raw);
|
||||
debug!(
|
||||
"Setting HID-{:x}:PID-{:x}'s quota type to {:?}",
|
||||
hid, pid, quota_type
|
||||
)
|
||||
}
|
||||
3 => {
|
||||
let page_count = msg_vec[0];
|
||||
let page_count = msg_vec[1];
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -1,15 +1,11 @@
|
|||
use alloc::{vec, vec::Vec};
|
||||
use core::slice;
|
||||
|
||||
pub mod dt_msg_handler;
|
||||
pub mod logging_service;
|
||||
pub mod mem_serve;
|
||||
pub mod service_definition_service;
|
||||
|
||||
pub fn block_read(mem_addr: u64, length: usize) -> Vec<u8> {
|
||||
let mut msg_vec = vec![];
|
||||
|
||||
for x in 0..(length as isize) {
|
||||
let xyz = mem_addr as *const u8;
|
||||
let value = unsafe { xyz.offset(x).read() };
|
||||
msg_vec.push(value);
|
||||
}
|
||||
msg_vec
|
||||
#[inline(always)]
|
||||
pub fn block_read<'a>(mem_addr: u64, length: usize) -> &'a mut [u8] {
|
||||
unsafe { slice::from_raw_parts_mut(mem_addr as *mut _, length) }
|
||||
}
|
||||
|
|
|
@ -1,43 +1,40 @@
|
|||
use {
|
||||
crate::{
|
||||
alloc::string::ToString,
|
||||
arch::hardware_random_u64,
|
||||
holeybytes::{ecah::LogError, kernel_services::block_read, Vm},
|
||||
ipc::{
|
||||
buffer::IpcBuffer,
|
||||
protocol::{self, Protocol},
|
||||
},
|
||||
holeybytes::{kernel_services::block_read, Vm},
|
||||
ipc::{buffer::IpcBuffer, protocol::Protocol},
|
||||
kmain::IPC_BUFFERS,
|
||||
},
|
||||
alloc::string::String,
|
||||
hashbrown::HashMap,
|
||||
log::{info, trace},
|
||||
spin::{lazy::Lazy, Mutex},
|
||||
};
|
||||
pub struct Services(HashMap<u64, Protocol>);
|
||||
pub struct Services<'a>(HashMap<u64, Protocol<'a>>);
|
||||
pub static SERVICES: Lazy<Mutex<Services>> = Lazy::new(|| {
|
||||
let mut dt = Services(HashMap::new());
|
||||
dt.0.insert(0, Protocol::void());
|
||||
Mutex::new(dt)
|
||||
});
|
||||
|
||||
pub fn sds_msg_handler(vm: &mut Vm, mem_addr: u64, length: usize) -> Result<(), LogError> {
|
||||
let mut msg_vec = block_read(mem_addr, length);
|
||||
#[derive(Debug)]
|
||||
pub enum ServiceError {
|
||||
InvalidFormat,
|
||||
}
|
||||
pub fn sds_msg_handler(vm: &mut Vm, mem_addr: u64, length: usize) -> Result<(), ServiceError> {
|
||||
let msg_vec = block_read(mem_addr, length);
|
||||
let sds_event_type: ServiceEventType = msg_vec[0].into();
|
||||
msg_vec.remove(0);
|
||||
|
||||
// info!("Length {}", msg_vec.len());
|
||||
let strptr = u64::from_le_bytes(msg_vec[1..9].try_into().unwrap());
|
||||
let strlen = u64::from_le_bytes(msg_vec[9..17].try_into().unwrap()) as usize;
|
||||
let string_vec = block_read(strptr, strlen);
|
||||
let string = core::str::from_utf8(string_vec).expect("Our bytes should be valid utf8");
|
||||
|
||||
use ServiceEventType::*;
|
||||
match sds_event_type {
|
||||
CreateService => {
|
||||
let string = String::from_utf8(msg_vec).expect("Our bytes should be valid utf8");
|
||||
let ret = sds_create_service(string);
|
||||
vm.registers[1] = hbvm::value::Value(ret as u64);
|
||||
}
|
||||
DeleteService => todo!(),
|
||||
SearchServices => {
|
||||
let string = String::from_utf8(msg_vec).expect("Our bytes should be valid utf8");
|
||||
let ret = sds_search_service(string);
|
||||
vm.registers[1] = hbvm::value::Value(ret as u64);
|
||||
}
|
||||
|
@ -79,30 +76,29 @@ impl From<u8> for ServiceEventType {
|
|||
}
|
||||
}
|
||||
|
||||
fn sds_create_service(protocol: String) -> u64 {
|
||||
fn sds_create_service(protocol: &'static str) -> u64 {
|
||||
let buff_id = hardware_random_u64();
|
||||
let mut services = SERVICES.lock();
|
||||
let mut buffers = IPC_BUFFERS.lock();
|
||||
|
||||
let protocol_ = Protocol::from(protocol.clone());
|
||||
let protocol_ = Protocol::from(protocol);
|
||||
let mut buff = IpcBuffer::new(false, 0);
|
||||
|
||||
services.0.insert(buff_id, protocol_.clone());
|
||||
buff.protocol = protocol_.clone();
|
||||
buff.protocol = protocol_;
|
||||
buffers.insert(buff_id, buff);
|
||||
|
||||
trace!("BufferID({}) => {}", buff_id, protocol);
|
||||
// let a: protocol::Protocol = protocol.into();
|
||||
buff_id
|
||||
}
|
||||
|
||||
fn sds_search_service(protocol: String) -> u64 {
|
||||
let mut services = SERVICES.lock();
|
||||
let compare = Protocol::from(protocol.clone());
|
||||
pub fn sds_search_service(protocol: &str) -> u64 {
|
||||
let services = SERVICES.lock();
|
||||
let compare = Protocol::from(protocol);
|
||||
for (bid, protocol_canidate) in &services.0 {
|
||||
trace!("BID-{bid} protocol_canidate {:?}", protocol_canidate);
|
||||
if protocol_canidate == &compare {
|
||||
trace!("BufferID({}) => {}", bid, protocol.clone());
|
||||
trace!("BufferID({}) => {}", bid, protocol);
|
||||
return *bid;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
use hbvm::mem::Address;
|
||||
|
||||
fn calc_start_of_page(ptr: u64) -> u64 {
|
||||
let mut page_aligned = false;
|
||||
let _page_aligned = false;
|
||||
if ptr % 4096 == 0 {
|
||||
// page_aligned = true;
|
||||
return ptr / 4096;
|
||||
|
@ -21,41 +21,39 @@ pub struct Memory {
|
|||
|
||||
impl Memory {
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
fn read_device(addr: Address) {
|
||||
unsafe {
|
||||
fn read_device(_addr: Address) {
|
||||
//unsafe {
|
||||
//
|
||||
// x86_64::instructions::port::Port::new(addr.get()).read()
|
||||
}
|
||||
//}
|
||||
}
|
||||
}
|
||||
|
||||
impl hbvm::mem::Memory for Memory {
|
||||
#[inline]
|
||||
#[inline(always)]
|
||||
unsafe fn load(
|
||||
&mut self,
|
||||
addr: Address,
|
||||
target: *mut u8,
|
||||
count: usize,
|
||||
) -> Result<(), hbvm::mem::LoadError> {
|
||||
use log::{error, info};
|
||||
if addr.get() % 4096 == 0 {}
|
||||
core::ptr::copy(addr.get() as *const u8, target, count);
|
||||
core::ptr::copy_nonoverlapping(addr.get() as *const u8, target, count);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[inline(always)]
|
||||
unsafe fn store(
|
||||
&mut self,
|
||||
addr: Address,
|
||||
source: *const u8,
|
||||
count: usize,
|
||||
) -> Result<(), hbvm::mem::StoreError> {
|
||||
core::ptr::copy(source, addr.get() as *mut u8, count);
|
||||
core::ptr::copy_nonoverlapping(source, addr.get() as *mut u8, count);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[inline(always)]
|
||||
unsafe fn prog_read<T: Copy>(&mut self, addr: Address) -> T {
|
||||
(addr.get() as *const T).read_unaligned()
|
||||
(addr.get() as *const T).read()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,77 +1,76 @@
|
|||
mod ecah;
|
||||
mod kernel_services;
|
||||
pub mod kernel_services;
|
||||
mod mem;
|
||||
|
||||
use {
|
||||
crate::{arch, ipc::buffer::IpcBuffer, kmain::IPC_BUFFERS},
|
||||
alloc::boxed::Box,
|
||||
core::{default, future::Future, marker::PhantomData, ptr::NonNull, task::Poll},
|
||||
hbvm::{
|
||||
mem::{
|
||||
softpaging::{icache::ICache, HandlePageFault, SoftPagedMem},
|
||||
Address, Memory,
|
||||
alloc::alloc::{alloc, dealloc},
|
||||
core::{
|
||||
alloc::Layout,
|
||||
future::Future,
|
||||
pin::Pin,
|
||||
task::{Context, Poll},
|
||||
},
|
||||
hbvm::{
|
||||
mem::{softpaging::HandlePageFault, Address},
|
||||
VmRunError, VmRunOk,
|
||||
},
|
||||
log::{debug, error, info, trace, warn},
|
||||
log::error,
|
||||
};
|
||||
|
||||
const STACK_SIZE: usize = 1024 * 1024;
|
||||
const TIMER_QUOTIENT: usize = 100;
|
||||
const TIMER_QUOTIENT: usize = 1000;
|
||||
type Vm = hbvm::Vm<mem::Memory, TIMER_QUOTIENT>;
|
||||
|
||||
pub struct ExecThread<'p> {
|
||||
pub struct ExecThread {
|
||||
vm: Vm,
|
||||
stack_bottom: *mut u8,
|
||||
_phantom: PhantomData<&'p [u8]>,
|
||||
}
|
||||
|
||||
unsafe impl<'p> Send for ExecThread<'p> {}
|
||||
impl<'p> ExecThread<'p> {
|
||||
unsafe impl Send for ExecThread {}
|
||||
|
||||
impl ExecThread {
|
||||
pub fn set_arguments(&mut self, ptr: u64, length: u64) {
|
||||
self.vm.registers[1] = hbvm::value::Value(ptr);
|
||||
self.vm.registers[2] = hbvm::value::Value(length);
|
||||
}
|
||||
|
||||
pub unsafe fn new(program: &'p [u8], entrypoint: Address) -> Self {
|
||||
let mut vm = unsafe {
|
||||
Vm::new(
|
||||
pub unsafe fn new(program: &[u8], entrypoint: Address) -> Self {
|
||||
let mut vm = Vm::new(
|
||||
mem::Memory {},
|
||||
Address::new(program.as_ptr() as u64 + entrypoint.get()),
|
||||
)
|
||||
};
|
||||
);
|
||||
|
||||
let stack_bottom = allocate_stack();
|
||||
|
||||
let stack_bottom = unsafe { allocate_stack().as_ptr() };
|
||||
vm.write_reg(254, (stack_bottom as usize + STACK_SIZE - 1) as u64);
|
||||
|
||||
ExecThread {
|
||||
vm,
|
||||
stack_bottom,
|
||||
_phantom: Default::default(),
|
||||
}
|
||||
ExecThread { vm, stack_bottom }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'p> Drop for ExecThread<'p> {
|
||||
impl<'p> Drop for ExecThread {
|
||||
fn drop(&mut self) {
|
||||
unsafe { alloc::alloc::dealloc(self.stack_bottom, stack_layout()) };
|
||||
unsafe { dealloc(self.stack_bottom, stack_layout()) };
|
||||
}
|
||||
}
|
||||
|
||||
impl<'p> Future for ExecThread<'p> {
|
||||
impl<'p> Future for ExecThread {
|
||||
type Output = Result<(), VmRunError>;
|
||||
|
||||
fn poll(
|
||||
mut self: core::pin::Pin<&mut Self>,
|
||||
cx: &mut core::task::Context<'_>,
|
||||
) -> Poll<Self::Output> {
|
||||
#[inline(always)]
|
||||
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
match self.vm.run() {
|
||||
Err(err) => {
|
||||
log::error!("HBVM Error\r\nRegister dump: {:?}", self.vm.registers,);
|
||||
return Poll::Ready(Err(err));
|
||||
}
|
||||
Ok(VmRunOk::End) => return Poll::Ready(Ok(())),
|
||||
Ok(VmRunOk::Ecall) => ecah::handler(&mut self.vm),
|
||||
Ok(VmRunOk::Ecall) => ecah::handler(
|
||||
&mut self.vm,
|
||||
cx.ext()
|
||||
.downcast_ref()
|
||||
.expect("PID did not exist in Context"),
|
||||
),
|
||||
Ok(VmRunOk::Timer) => (),
|
||||
Ok(VmRunOk::Breakpoint) => {
|
||||
log::error!(
|
||||
|
@ -91,33 +90,22 @@ impl HandlePageFault for PageFaultHandler {
|
|||
fn page_fault(
|
||||
&mut self,
|
||||
reason: hbvm::mem::MemoryAccessReason,
|
||||
pagetable: &mut hbvm::mem::softpaging::paging::PageTable,
|
||||
_pagetable: &mut hbvm::mem::softpaging::paging::PageTable,
|
||||
vaddr: hbvm::mem::Address,
|
||||
size: hbvm::mem::softpaging::PageSize,
|
||||
dataptr: *mut u8,
|
||||
) -> bool
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
log::error!(
|
||||
"REASON: {reason} \
|
||||
vaddr: {vaddr} \
|
||||
size: {size:?} \
|
||||
Dataptr {dataptr:p}",
|
||||
);
|
||||
|
||||
) -> bool {
|
||||
error!("REASON: {reason} vaddr: {vaddr} size: {size:?} Dataptr {dataptr:p}");
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
const fn stack_layout() -> core::alloc::Layout {
|
||||
unsafe { alloc::alloc::Layout::from_size_align_unchecked(STACK_SIZE, 4096) }
|
||||
#[inline(always)]
|
||||
const fn stack_layout() -> Layout {
|
||||
unsafe { Layout::from_size_align_unchecked(STACK_SIZE, 8) }
|
||||
}
|
||||
|
||||
fn allocate_stack() -> NonNull<u8> {
|
||||
let layout = stack_layout();
|
||||
match NonNull::new(unsafe { alloc::alloc::alloc_zeroed(layout) }) {
|
||||
Some(ptr) => ptr,
|
||||
None => alloc::alloc::handle_alloc_error(layout),
|
||||
}
|
||||
#[inline(always)]
|
||||
fn allocate_stack() -> *mut u8 {
|
||||
unsafe { alloc(stack_layout()) }
|
||||
}
|
||||
|
|
|
@ -9,12 +9,12 @@ pub enum BufferTypes {
|
|||
Bound(ArrayQueue<Message>),
|
||||
}
|
||||
/// Interproccess buffer
|
||||
pub struct IpcBuffer {
|
||||
pub protocol: Protocol,
|
||||
pub struct IpcBuffer<'a> {
|
||||
pub protocol: Protocol<'a>,
|
||||
pub buffer: BufferTypes,
|
||||
}
|
||||
|
||||
impl IpcBuffer {
|
||||
impl<'a> IpcBuffer<'a> {
|
||||
pub fn new(bounded: bool, length: u64) -> Self {
|
||||
log::debug!(
|
||||
"New IPCBuffer\r
|
||||
|
@ -24,7 +24,7 @@ impl IpcBuffer {
|
|||
length
|
||||
);
|
||||
match (bounded, length) {
|
||||
(false, a) => {
|
||||
(false, ..) => {
|
||||
let buftype = BufferTypes::Unbound(SegQueue::new());
|
||||
|
||||
Self {
|
||||
|
@ -48,10 +48,8 @@ impl IpcBuffer {
|
|||
}
|
||||
pub fn push(&mut self, msg: Message) {
|
||||
match &self.buffer {
|
||||
BufferTypes::Unbound(buff) => buff.push(msg.clone()),
|
||||
BufferTypes::Bound(buff) => {
|
||||
let _ = buff.push(msg.clone());
|
||||
}
|
||||
BufferTypes::Unbound(buff) => buff.push(msg),
|
||||
BufferTypes::Bound(buff) => buff.push(msg).unwrap(),
|
||||
};
|
||||
}
|
||||
pub fn pop(&mut self) -> Result<Message, IpcError> {
|
||||
|
|
|
@ -1,21 +1,17 @@
|
|||
use {
|
||||
alloc::{string::String, vec::Vec},
|
||||
hashbrown::HashMap,
|
||||
log::info,
|
||||
};
|
||||
use {alloc::vec::Vec, hashbrown::HashMap};
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
pub struct Type {}
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
pub struct Funct {
|
||||
takes: Vec<String>,
|
||||
gives: Vec<String>,
|
||||
pub struct Funct<'a> {
|
||||
takes: Vec<&'a str>,
|
||||
gives: Vec<&'a str>,
|
||||
}
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
pub struct Protocol {
|
||||
types: HashMap<String, Type>,
|
||||
fns: HashMap<String, Funct>,
|
||||
pub struct Protocol<'a> {
|
||||
types: HashMap<&'a str, Type>,
|
||||
fns: HashMap<&'a str, Funct<'a>>,
|
||||
}
|
||||
impl Protocol {
|
||||
impl<'a> Protocol<'a> {
|
||||
pub fn void() -> Self {
|
||||
Self {
|
||||
types: HashMap::new(),
|
||||
|
@ -28,8 +24,8 @@ impl Protocol {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<String> for Protocol {
|
||||
fn from(value: alloc::string::String) -> Self {
|
||||
impl<'a> From<&'a str> for Protocol<'a> {
|
||||
fn from(value: &'a str) -> Self {
|
||||
let mut hm_t = HashMap::new();
|
||||
hm_t.insert(value, Type {});
|
||||
Self {
|
||||
|
|
|
@ -2,27 +2,40 @@
|
|||
|
||||
use {
|
||||
crate::{
|
||||
arch::{hardware_random_u64, logging::SERIAL_CONSOLE},
|
||||
bootmodules::{build_cmd, BootModules},
|
||||
capabilities,
|
||||
arch::hardware_random_u64,
|
||||
bootmodules::BootModules,
|
||||
//bootmodules::build_cmd,
|
||||
device_tree::DeviceTree,
|
||||
holeybytes::ExecThread,
|
||||
ipc::buffer::{self, IpcBuffer},
|
||||
ipc::buffer::IpcBuffer,
|
||||
task::Executor,
|
||||
},
|
||||
alloc::format,
|
||||
alloc::boxed::Box,
|
||||
core::cell::LazyCell,
|
||||
hashbrown::HashMap,
|
||||
hbvm::mem::Address,
|
||||
limine::{Framebuffer, FramebufferRequest, NonNullPtr},
|
||||
log::{debug, info, trace},
|
||||
log::{debug, error, trace},
|
||||
spin::{Lazy, Mutex},
|
||||
xml::XMLElement,
|
||||
};
|
||||
|
||||
pub fn kmain(cmdline: &str, boot_modules: BootModules) -> ! {
|
||||
pub fn kmain(_cmdline: &str, boot_modules: BootModules) -> ! {
|
||||
debug!("Entered kmain");
|
||||
|
||||
let kcmd = build_cmd("Kernel Command Line", cmdline);
|
||||
trace!("Cmdline: {kcmd:?}");
|
||||
#[cfg(feature = "ktest")]
|
||||
{
|
||||
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() {
|
||||
// let name = format!("module-{}", i);
|
||||
|
@ -38,9 +51,9 @@ pub fn kmain(cmdline: &str, boot_modules: BootModules) -> ! {
|
|||
let dt = DEVICE_TREE.lock();
|
||||
|
||||
// TODO(Able): This line causes a deadlock
|
||||
info!("Device Tree: {}", dt);
|
||||
debug!("Device Tree: {}", dt);
|
||||
|
||||
info!("Boot complete. Moving to init_system");
|
||||
trace!("Boot complete. Moving to init_system");
|
||||
|
||||
// TODO: schedule the disk driver from the initramfs
|
||||
// TODO: schedule the filesystem driver from the initramfs
|
||||
|
@ -52,64 +65,91 @@ pub fn kmain(cmdline: &str, boot_modules: BootModules) -> ! {
|
|||
let fb1: &NonNullPtr<Framebuffer> = &FB_REQ.get_response().get().unwrap().framebuffers()[0];
|
||||
|
||||
{
|
||||
use crate::alloc::string::ToString;
|
||||
let mut dt = DEVICE_TREE.lock();
|
||||
let mut disp = xml::XMLElement::new("display_0");
|
||||
|
||||
disp.set_attribute("width", fb1.width);
|
||||
disp.set_attribute("height", fb1.height);
|
||||
disp.set_attribute("bits per pixel", fb1.bpp);
|
||||
disp.set_attribute("bpp", fb1.bpp);
|
||||
disp.set_attribute("pitch", fb1.pitch);
|
||||
dt.devices.insert("Displays".to_string(), alloc::vec![disp]);
|
||||
dt.devices.insert("Displays", alloc::vec![disp]);
|
||||
}
|
||||
log::info!("Graphics initialised");
|
||||
log::info!(
|
||||
debug!("Graphics initialised");
|
||||
debug!(
|
||||
"Graphics front ptr {:?}",
|
||||
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 {
|
||||
for module in boot_modules.into_iter().take(bm_take) {
|
||||
let mut cmd = module.cmd;
|
||||
if cmd.len() > 2 {
|
||||
// Remove the quotes
|
||||
cmd.remove(0);
|
||||
cmd.pop();
|
||||
let executor = LazyCell::<Executor>::force_mut(&mut EXECUTOR);
|
||||
for module in boot_modules.iter() {
|
||||
let cmd = module.cmd.trim_matches('"');
|
||||
let cmd_len = cmd.len() as u64;
|
||||
|
||||
log::info!(
|
||||
"Starting {}",
|
||||
module
|
||||
.path
|
||||
.split('/')
|
||||
.last()
|
||||
.unwrap()
|
||||
.split('.')
|
||||
.next()
|
||||
.unwrap()
|
||||
);
|
||||
log::debug!("Spawning {} with arguments \"{}\"", module.path, cmd);
|
||||
|
||||
// decode AbleOS Executable format
|
||||
let header = &module.bytes[0..46];
|
||||
let magic_slice = &header[0..3];
|
||||
if magic_slice != [0x15, 0x91, 0xD2] {
|
||||
log::error!("Invalid magic number at the start of executable.");
|
||||
continue;
|
||||
}
|
||||
let cmd_len = cmd.as_bytes().len() as u64;
|
||||
|
||||
log::info!("Spawning {} with arguments \"{}\"", module.path, cmd);
|
||||
let executable_format_version = u32::from_le_bytes(header[3..7].try_into().unwrap());
|
||||
let offset = if executable_format_version == 0 {
|
||||
47
|
||||
} else {
|
||||
error!("Invalid executable format.");
|
||||
continue;
|
||||
};
|
||||
|
||||
executor.spawn(async move {
|
||||
let mut thr = ExecThread::new(&module.bytes, Address::new(0));
|
||||
let code_length = u64::from_le_bytes(header[7..15].try_into().unwrap());
|
||||
let data_length = u64::from_le_bytes(header[15..23].try_into().unwrap());
|
||||
let end = (code_length + data_length) as usize;
|
||||
log::debug!("{code_length} + {data_length} = {end}");
|
||||
|
||||
let mut thr = ExecThread::new(&module.bytes[offset..end], Address::new(0));
|
||||
if cmd_len > 0 {
|
||||
thr.set_arguments(cmd.as_bytes().as_ptr() as u64, cmd_len);
|
||||
thr.set_arguments(cmd.as_ptr() as u64, cmd_len);
|
||||
}
|
||||
|
||||
executor.spawn(Box::pin(async {
|
||||
if let Err(e) = thr.await {
|
||||
log::error!("{e:?}");
|
||||
}
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
||||
info!("Random number: {}", hardware_random_u64());
|
||||
debug!("Random number: {}", hardware_random_u64());
|
||||
|
||||
executor.run();
|
||||
};
|
||||
|
||||
crate::arch::spin_loop()
|
||||
}
|
||||
|
||||
// ! SAFETY: this is not threadsafe at all, like even a little bit.
|
||||
// ! SERIOUSLY
|
||||
pub static mut EXECUTOR: LazyCell<Executor> = LazyCell::new(|| Executor::new());
|
||||
|
||||
pub static DEVICE_TREE: Lazy<Mutex<DeviceTree>> = Lazy::new(|| {
|
||||
let dt = DeviceTree::new();
|
||||
Mutex::new(dt)
|
||||
});
|
||||
pub static FB_REQ: FramebufferRequest = FramebufferRequest::new(0);
|
||||
|
||||
use alloc::vec::Vec;
|
||||
pub type IpcBuffers = HashMap<u64, IpcBuffer>;
|
||||
pub type IpcBuffers<'a> = HashMap<u64, IpcBuffer<'a>>;
|
||||
pub static IPC_BUFFERS: Lazy<Mutex<IpcBuffers>> = Lazy::new(|| {
|
||||
let mut bufs = HashMap::new();
|
||||
let log_buffer = IpcBuffer::new(false, 0);
|
||||
|
@ -120,10 +160,3 @@ pub static IPC_BUFFERS: Lazy<Mutex<IpcBuffers>> = Lazy::new(|| {
|
|||
|
||||
Mutex::new(bufs)
|
||||
});
|
||||
|
||||
#[test_case]
|
||||
fn trivial_assertion() {
|
||||
trace!("trivial assertion... ");
|
||||
assert_eq!(1, 1);
|
||||
info!("[ok]");
|
||||
}
|
||||
|
|
51
kernel/src/ktest.rs
Normal file
51
kernel/src/ktest.rs
Normal file
|
@ -0,0 +1,51 @@
|
|||
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,21 +1,22 @@
|
|||
//! The ableOS kernel.
|
||||
//! Named akern.
|
||||
//! Akern is woefully undersupported at the moment but we are looking to add support improve hardware discovery and make our lives as kernel and operating system developers easier and better
|
||||
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
#![feature(
|
||||
slice_split_once,
|
||||
exclusive_wrapper,
|
||||
core_intrinsics,
|
||||
abi_x86_interrupt,
|
||||
lazy_get,
|
||||
alloc_error_handler,
|
||||
inline_const,
|
||||
panic_info_message,
|
||||
pointer_is_aligned,
|
||||
local_waker,
|
||||
context_ext,
|
||||
ptr_sub_ptr,
|
||||
custom_test_frameworks,
|
||||
naked_functions,
|
||||
pointer_is_aligned_to
|
||||
)]
|
||||
#![allow(dead_code)]
|
||||
#![test_runner(crate::test_runner)]
|
||||
#![allow(dead_code, internal_features, static_mut_refs)]
|
||||
extern crate alloc;
|
||||
|
||||
mod allocator;
|
||||
|
@ -23,6 +24,7 @@ mod arch;
|
|||
mod bootmodules;
|
||||
mod capabilities;
|
||||
mod device_tree;
|
||||
mod exe_format;
|
||||
mod handle;
|
||||
mod holeybytes;
|
||||
mod ipc;
|
||||
|
@ -32,6 +34,9 @@ mod memory;
|
|||
mod task;
|
||||
mod utils;
|
||||
|
||||
#[allow(improper_ctypes, non_upper_case_globals)]
|
||||
mod ktest;
|
||||
|
||||
use versioning::Version;
|
||||
|
||||
/// Kernel's version
|
||||
|
@ -42,7 +47,9 @@ pub const VERSION: Version = Version {
|
|||
};
|
||||
|
||||
#[panic_handler]
|
||||
#[cfg(target_os = "none")]
|
||||
fn panic(info: &core::panic::PanicInfo) -> ! {
|
||||
use alloc::string::ToString;
|
||||
arch::register_dump();
|
||||
|
||||
if let Some(loc) = info.location() {
|
||||
|
@ -54,17 +61,7 @@ fn panic(info: &core::panic::PanicInfo) -> ! {
|
|||
));
|
||||
}
|
||||
|
||||
if let Some(msg) = info.message() {
|
||||
let msg = info.message().to_string().replace("\n", "\r\n");
|
||||
let _ = crate::arch::log(format_args!("{msg}\r\n"));
|
||||
}
|
||||
|
||||
loop {}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
fn test_runner(tests: &[&dyn Fn()]) {
|
||||
println!("Running {} tests", tests.len());
|
||||
for test in tests {
|
||||
test();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
#![allow(deprecated)]
|
||||
// TODO: Add a logger api with logger levels and various outputs
|
||||
pub static TERMINAL_LOGGER: Lazy<Mutex<TermLogger>> = Lazy::new(|| Mutex::new(TermLogger::new()));
|
||||
|
||||
|
@ -9,7 +10,11 @@ use {
|
|||
|
||||
pub fn init() -> Result<(), SetLoggerError> {
|
||||
log::set_logger(&crate::logger::Logger)?;
|
||||
if cfg!(debug_assertions) {
|
||||
log::set_max_level(log::LevelFilter::Debug);
|
||||
} else {
|
||||
log::set_max_level(log::LevelFilter::Info);
|
||||
}
|
||||
|
||||
Lazy::force(&TERMINAL_LOGGER);
|
||||
|
||||
|
@ -31,7 +36,19 @@ impl log::Log for Logger {
|
|||
Level::Debug => "25",
|
||||
Level::Trace => "103",
|
||||
};
|
||||
let module = record.module_path().unwrap_or_default();
|
||||
let module = record
|
||||
.module_path()
|
||||
.unwrap_or_default()
|
||||
.rsplit_once(':')
|
||||
.unwrap_or_default()
|
||||
.1;
|
||||
if module == "" {
|
||||
crate::arch::log(format_args!(
|
||||
"\x1b[38;5;{lvl_color}m{lvl}\x1b[0m: {}\r\n",
|
||||
record.args(),
|
||||
))
|
||||
.expect("write to serial console");
|
||||
} else {
|
||||
let line = record.line().unwrap_or_default();
|
||||
crate::arch::log(format_args!(
|
||||
"\x1b[38;5;{lvl_color}m{lvl}\x1b[0m [{module}:{line}]: {}\r\n",
|
||||
|
@ -39,6 +56,7 @@ impl log::Log for Logger {
|
|||
))
|
||||
.expect("write to serial console");
|
||||
}
|
||||
}
|
||||
|
||||
fn flush(&self) {}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
//! The Memory Manager
|
||||
|
||||
use alloc::collections::VecDeque;
|
||||
use derive_more::*;
|
||||
use {alloc::collections::VecDeque, derive_more::*};
|
||||
|
||||
pub use crate::arch::PAGE_SIZE;
|
||||
pub const MAX_ORDER: usize = 10;
|
||||
|
@ -44,7 +43,7 @@ pub const MAX_ORDER: usize = 10;
|
|||
Sum,
|
||||
UpperHex,
|
||||
)]
|
||||
#[display(fmt = "0x{:x}", _0)]
|
||||
#[display("0x{:x}", _0)]
|
||||
#[from(forward)]
|
||||
pub struct VirtualAddress(usize);
|
||||
|
||||
|
@ -55,11 +54,11 @@ impl VirtualAddress {
|
|||
pub fn vpns(&self) -> [usize; 3] {
|
||||
[
|
||||
// [20:12]
|
||||
(self.0 >> 12) & 0x1ff,
|
||||
(self.0 >> 12) & 0x1FF,
|
||||
// [29:21]
|
||||
(self.0 >> 21) & 0x1ff,
|
||||
(self.0 >> 21) & 0x1FF,
|
||||
// [38:30]
|
||||
(self.0 >> 30) & 0x1ff,
|
||||
(self.0 >> 30) & 0x1FF,
|
||||
]
|
||||
}
|
||||
|
||||
|
@ -114,7 +113,7 @@ impl VirtualAddress {
|
|||
Sum,
|
||||
UpperHex,
|
||||
)]
|
||||
#[display(fmt = "0x{:x}", _0)]
|
||||
#[display("0x{:x}", _0)]
|
||||
#[from(forward)]
|
||||
pub struct PhysicalAddress(usize);
|
||||
|
||||
|
@ -125,11 +124,11 @@ impl PhysicalAddress {
|
|||
pub fn ppns(&self) -> [usize; 3] {
|
||||
[
|
||||
// [20:12]
|
||||
(self.0 >> 12) & 0x1ff,
|
||||
(self.0 >> 12) & 0x1FF,
|
||||
// [29:21]
|
||||
(self.0 >> 21) & 0x1ff,
|
||||
(self.0 >> 21) & 0x1FF,
|
||||
// [55:30]
|
||||
(self.0 >> 30) & 0x3ffffff,
|
||||
(self.0 >> 30) & 0x3FFFFFF,
|
||||
]
|
||||
}
|
||||
|
||||
|
|
|
@ -1,26 +1,19 @@
|
|||
#![allow(unused)]
|
||||
|
||||
use {
|
||||
alloc::{boxed::Box, collections::BTreeMap, sync::Arc, task::Wake},
|
||||
alloc::{
|
||||
boxed::Box,
|
||||
collections::{BTreeMap, BTreeSet},
|
||||
sync::Arc,
|
||||
},
|
||||
core::{
|
||||
future::Future,
|
||||
pin::Pin,
|
||||
task::{Context, Poll, Waker},
|
||||
sync::atomic::{AtomicBool, Ordering},
|
||||
task::{Context, ContextBuilder, Poll, RawWaker, RawWakerVTable, Waker},
|
||||
},
|
||||
crossbeam_queue::SegQueue,
|
||||
kiam::when,
|
||||
slab::Slab,
|
||||
spin::RwLock,
|
||||
};
|
||||
|
||||
static SPAWN_QUEUE: RwLock<Option<SpawnQueue>> = RwLock::new(None);
|
||||
pub fn spawn(future: impl Future<Output = ()> + Send + 'static) {
|
||||
match &*SPAWN_QUEUE.read() {
|
||||
Some(s) => s.push(Task::new(future)),
|
||||
None => panic!("no task executor is running"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn yield_now() -> impl Future<Output = ()> {
|
||||
struct YieldNow(bool);
|
||||
impl Future for YieldNow {
|
||||
|
@ -40,101 +33,184 @@ pub fn yield_now() -> impl Future<Output = ()> {
|
|||
YieldNow(false)
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub trait Process: Future<Output = ()> + Send {}
|
||||
impl<T: Future<Output = ()> + Send> Process for T {}
|
||||
|
||||
pub struct Executor {
|
||||
tasks: Slab<Task>,
|
||||
queue: TaskQueue,
|
||||
to_spawn: SpawnQueue,
|
||||
wakers: BTreeMap<TaskId, Waker>,
|
||||
task_queue: Arc<SegQueue<usize>>,
|
||||
interrupt_lookup: [Option<usize>; u8::MAX as usize],
|
||||
buffer_lookup: BTreeMap<usize, BTreeSet<usize>>,
|
||||
}
|
||||
|
||||
impl Executor {
|
||||
pub fn spawn(&mut self, future: impl Future<Output = ()> + Send + 'static) {
|
||||
self.queue
|
||||
.push(TaskId(self.tasks.insert(Task::new(future))));
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
tasks: Slab::new(),
|
||||
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) {
|
||||
{
|
||||
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));
|
||||
}
|
||||
|
||||
let mut task_batch = [0; 32];
|
||||
loop {
|
||||
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);
|
||||
};
|
||||
let mut batch_len = 0;
|
||||
|
||||
let mut cx = Context::from_waker(self.wakers.entry(id).or_insert_with(|| {
|
||||
Waker::from(Arc::new(TaskWaker {
|
||||
id,
|
||||
queue: Arc::clone(&self.queue),
|
||||
}))
|
||||
}));
|
||||
|
||||
match task.poll(&mut cx) {
|
||||
Poll::Ready(()) => {
|
||||
self.tasks.remove(id.0);
|
||||
self.wakers.remove(&id);
|
||||
}
|
||||
Poll::Pending => (),
|
||||
}
|
||||
},
|
||||
self.tasks.is_empty() => break,
|
||||
_ => (),
|
||||
while let Some(id) = self.task_queue.pop() {
|
||||
task_batch[batch_len] = id;
|
||||
batch_len += 1;
|
||||
if batch_len == task_batch.len() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
*SPAWN_QUEUE.write() = None;
|
||||
if batch_len == 0 {
|
||||
// break;
|
||||
continue;
|
||||
}
|
||||
|
||||
for &(mut id) in &task_batch[..batch_len] {
|
||||
if let Some(task) = self.tasks.get_mut(id) {
|
||||
if task.is_paused() {
|
||||
continue;
|
||||
}
|
||||
|
||||
let waker = create_waker(id, Arc::clone(&self.task_queue));
|
||||
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) {
|
||||
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 {
|
||||
future: Pin<Box<dyn Future<Output = ()> + Send>>,
|
||||
future: Pin<Box<dyn Process>>,
|
||||
paused: AtomicBool,
|
||||
}
|
||||
|
||||
impl Task {
|
||||
pub fn new(future: impl Future<Output = ()> + Send + 'static) -> Self {
|
||||
log::trace!("New task scheduled");
|
||||
fn new(future: Pin<Box<dyn Process>>) -> Self {
|
||||
Self {
|
||||
future: Box::pin(future),
|
||||
future,
|
||||
paused: AtomicBool::new(false),
|
||||
}
|
||||
}
|
||||
|
||||
fn poll(&mut self, cx: &mut Context) -> Poll<()> {
|
||||
self.future.as_mut().poll(cx)
|
||||
}
|
||||
|
||||
fn is_paused(&self) -> bool {
|
||||
self.paused.load(Ordering::Acquire)
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||
struct TaskId(usize);
|
||||
fn set_paused(&self, paused: bool) {
|
||||
self.paused.store(paused, Ordering::Release)
|
||||
}
|
||||
}
|
||||
|
||||
type TaskQueue = Arc<SegQueue<TaskId>>;
|
||||
type SpawnQueue = Arc<SegQueue<Task>>;
|
||||
fn create_waker(task_id: usize, task_queue: Arc<SegQueue<usize>>) -> Waker {
|
||||
let data = Box::new(TaskWaker {
|
||||
task_id,
|
||||
task_queue,
|
||||
});
|
||||
let raw_waker = RawWaker::new(Box::into_raw(data) as *const (), &VTABLE);
|
||||
unsafe { Waker::from_raw(raw_waker) }
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct TaskWaker {
|
||||
id: TaskId,
|
||||
queue: TaskQueue,
|
||||
task_id: usize,
|
||||
task_queue: Arc<SegQueue<usize>>,
|
||||
}
|
||||
|
||||
impl Wake for TaskWaker {
|
||||
fn wake(self: Arc<Self>) {
|
||||
log::trace!("Woke Task-{:?}", self.id);
|
||||
self.wake_by_ref();
|
||||
impl TaskWaker {
|
||||
fn wake(&self) {
|
||||
self.task_queue.push(self.task_id);
|
||||
}
|
||||
}
|
||||
|
||||
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,7 +4,6 @@
|
|||
/// Used when tab `\t` in hardware is not known and we will default to two spaces
|
||||
pub const TAB: &str = " ";
|
||||
|
||||
|
||||
// NOTE: this only reduces the code duplication in source code not in generated code!
|
||||
// Written by Yours Truly: Munir
|
||||
/// A simple macro to reduce code duplication when we use TAB internally
|
||||
|
@ -12,7 +11,7 @@ pub const TAB: &str = " ";
|
|||
macro_rules! tab {
|
||||
($num:expr) => {
|
||||
TAB.repeat($num)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// NOTE: this only reduces the code duplication in source code not in generated code!
|
||||
|
@ -22,7 +21,7 @@ macro_rules! tab {
|
|||
macro_rules! device_tree {
|
||||
($devtree:expr, $dev_type_vec:expr) => {
|
||||
for each_device_type in $dev_type_vec {
|
||||
$devtree.devices.insert(each_device_type.to_string(), Vec::new());
|
||||
$devtree.devices.insert(each_device_type, Vec::new());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"arch": "aarch64",
|
||||
"data-layout": "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128",
|
||||
"data-layout": "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32",
|
||||
"disable-redzone": true,
|
||||
"env": "",
|
||||
"executables": true,
|
||||
|
@ -21,5 +21,5 @@
|
|||
"target-c-int-width": "32",
|
||||
"target-endian": "little",
|
||||
"target-pointer-width": "64",
|
||||
"vendor": ""
|
||||
"vendor": "ablecorp"
|
||||
}
|
22
kernel/targets/x86_64_v3-ableos.json
Normal file
22
kernel/targets/x86_64_v3-ableos.json
Normal file
|
@ -0,0 +1,22 @@
|
|||
{
|
||||
"llvm-target": "x86_64-unknown-none",
|
||||
"data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128",
|
||||
"arch": "x86_64",
|
||||
"target-endian": "little",
|
||||
"target-pointer-width": "64",
|
||||
"target-c-int-width": "32",
|
||||
"os": "none",
|
||||
"executables": true,
|
||||
"linker-flavor": "ld.lld",
|
||||
"linker": "rust-lld",
|
||||
"panic-strategy": "abort",
|
||||
"disable-redzone": true,
|
||||
"features": "+sse4.1,+avx,+aes,+fma,+popcnt,+bmi2,+avx2,+lzcnt,+xsave",
|
||||
"code-model": "kernel",
|
||||
"pre-link-args": {
|
||||
"ld.lld": [
|
||||
"--gc-sections",
|
||||
"--script=kernel/lds/x86_64.ld"
|
||||
]
|
||||
}
|
||||
}
|
2
known_bugs.md
Normal file
2
known_bugs.md
Normal file
|
@ -0,0 +1,2 @@
|
|||
# i did not know where to put this
|
||||
- memcpy / memset cause crash on debug builds due to ptr misalignment that is not present on release builds
|
|
@ -4,15 +4,17 @@ version = "0.2.0"
|
|||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
str-reader = "0.1.2"
|
||||
derive_more = "0.99"
|
||||
error-stack = "0.4"
|
||||
fatfs = "0.3"
|
||||
toml = "0.5.2"
|
||||
# hbasm.git = "https://git.ablecorp.us/AbleOS/holey-bytes.git"
|
||||
str-reader = "0.1"
|
||||
derive_more = { version = "1", default-features = false, features = [
|
||||
"display",
|
||||
] }
|
||||
error-stack = "0.5"
|
||||
fatfs = { version = "0.3", default-features = false, features = [
|
||||
"std",
|
||||
"alloc",
|
||||
] }
|
||||
toml = "0.8"
|
||||
hblang.git = "https://git.ablecorp.us/AbleOS/holey-bytes.git"
|
||||
|
||||
[dependencies.reqwest]
|
||||
version = "0.11"
|
||||
default-features = false
|
||||
features = ["rustls-tls", "blocking"]
|
||||
log = "0.4"
|
||||
raw-cpuid = "11"
|
||||
ureq = { version = "2", default-features = false, features = ["tls"] }
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
#![allow(unused)]
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
fmt::format,
|
||||
fs::{read_to_string, File},
|
||||
io::{BufWriter, Write},
|
||||
|
@ -12,6 +14,7 @@ pub struct Package {
|
|||
name: String,
|
||||
binaries: Vec<String>,
|
||||
build_cmd: String,
|
||||
args: HashMap<String, String>,
|
||||
}
|
||||
|
||||
impl Package {
|
||||
|
@ -45,49 +48,81 @@ impl Package {
|
|||
let mut binaries = vec![];
|
||||
|
||||
for (count, (name, table)) in bin_table.into_iter().enumerate() {
|
||||
// if count != 0 {
|
||||
println!("{}", name);
|
||||
binaries.push(name.clone());
|
||||
// }
|
||||
}
|
||||
let build_table = data.get("build").unwrap();
|
||||
|
||||
let mut build_cmd: String = build_table.get("command").unwrap().as_str().unwrap().into();
|
||||
build_cmd.remove(0);
|
||||
// build_cmd.pop();
|
||||
let mut args: HashMap<String, String> = match build_table.get("args") {
|
||||
None => HashMap::new(),
|
||||
Some(v) => v
|
||||
.as_table()
|
||||
.unwrap()
|
||||
.into_iter()
|
||||
.map(|(k, v)| (k.clone(), v.to_string()))
|
||||
.collect::<HashMap<String, String>>(),
|
||||
};
|
||||
|
||||
Self {
|
||||
name,
|
||||
binaries,
|
||||
build_cmd,
|
||||
args,
|
||||
}
|
||||
}
|
||||
pub fn build(&self) {
|
||||
pub fn build(&self, out: &mut Vec<u8>) -> std::io::Result<()> {
|
||||
if self.binaries.contains(&"hblang".to_string()) {
|
||||
let file = self.build_cmd.split_ascii_whitespace().last().unwrap();
|
||||
|
||||
let path = format!("sysdata/programs/{}/{}", self.name, file);
|
||||
let mut bytes = Vec::new();
|
||||
// compile here
|
||||
|
||||
let _ = hblang::run_compiler(
|
||||
let mut warnings = String::new();
|
||||
|
||||
hblang::run_compiler(
|
||||
&path,
|
||||
Options {
|
||||
fmt: true,
|
||||
resolver: Some(hblang::ABLEOS_PATH_RESOLVER),
|
||||
|
||||
..Default::default()
|
||||
},
|
||||
&mut bytes,
|
||||
);
|
||||
let _ = hblang::run_compiler(&path, Default::default(), &mut bytes);
|
||||
out,
|
||||
&mut warnings,
|
||||
)?;
|
||||
|
||||
match std::fs::create_dir("target/programs") {
|
||||
Ok(_) => (),
|
||||
Err(e) if e.kind() == std::io::ErrorKind::AlreadyExists => (),
|
||||
Err(e) => panic!("{}", e),
|
||||
}
|
||||
let path = format!("target/programs/{}.hbf", self.name);
|
||||
let mut file = File::create(path).unwrap();
|
||||
file.write_all(&bytes).unwrap();
|
||||
}
|
||||
|
||||
hblang::run_compiler(
|
||||
&path,
|
||||
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;
|
||||
|
||||
use {
|
||||
core::fmt::Write as _,
|
||||
derive_more::Display,
|
||||
dev::Package,
|
||||
error_stack::{bail, report, Context, Report, Result, ResultExt},
|
||||
fatfs::{FileSystem, FormatVolumeOptions, FsOptions, ReadWriteSeek},
|
||||
std::{
|
||||
fmt::Display,
|
||||
fs::{self, File},
|
||||
io::{self, Write},
|
||||
path::Path,
|
||||
process::{exit, Command},
|
||||
process::{exit, Command, Stdio},
|
||||
},
|
||||
toml::Value,
|
||||
};
|
||||
|
@ -19,41 +19,85 @@ fn main() -> Result<(), Error> {
|
|||
let mut args = std::env::args();
|
||||
args.next();
|
||||
|
||||
log::set_logger(&hblang::Logger).unwrap();
|
||||
log::set_max_level(log::LevelFilter::Error);
|
||||
|
||||
match args.next().as_deref() {
|
||||
Some("build" | "b") => {
|
||||
let mut release = false;
|
||||
let mut debuginfo = false;
|
||||
let mut target = Target::X86_64;
|
||||
let mut tests = false;
|
||||
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 if arg == "--ktest" {
|
||||
tests = true;
|
||||
} else {
|
||||
return Err(report!(Error::InvalidSubCom));
|
||||
}
|
||||
}
|
||||
|
||||
build(release, target).change_context(Error::Build)
|
||||
build(release, target, debuginfo, tests).change_context(Error::Build)
|
||||
}
|
||||
// Some("test" | "t") => {
|
||||
// let mut release = false;
|
||||
// let mut debuginfo = false;
|
||||
// let mut target = Target::X86_64;
|
||||
// for arg in args {
|
||||
// if arg == "-r" || arg == "--release" {
|
||||
// release = true;
|
||||
// } else if arg == "-d" || arg == "--debuginfo" {
|
||||
// debuginfo = true;
|
||||
// } else if arg == "rv64" || arg == "riscv64" || arg == "riscv64-virt" {
|
||||
// target = Target::Riscv64Virt;
|
||||
// } else if arg == "arm64" || arg == "aarch64" || arg == "aarch64-virt" {
|
||||
// target = Target::Aarch64;
|
||||
// } else if arg == "avx2" {
|
||||
// target = Target::X86_64Avx2;
|
||||
// } else {
|
||||
// return Err(report!(Error::InvalidSubCom));
|
||||
// }
|
||||
// }
|
||||
|
||||
// test(release, target, debuginfo).change_context(Error::Build)
|
||||
// }
|
||||
Some("run" | "r") => {
|
||||
let mut release = false;
|
||||
let mut debuginfo = false;
|
||||
let mut target = Target::X86_64;
|
||||
let mut tests = false;
|
||||
let mut do_accel = true;
|
||||
for arg in args {
|
||||
if arg == "-r" || arg == "--release" {
|
||||
release = true;
|
||||
} else if arg == "-d" || arg == "--debuginfo" {
|
||||
debuginfo = true;
|
||||
} else if arg == "rv64" || arg == "riscv64" || arg == "riscv64-virt" {
|
||||
target = Target::Riscv64Virt;
|
||||
} else if arg == "arm64" || arg == "aarch64" || arg == "aarch64-virt" {
|
||||
target = Target::Aarch64;
|
||||
} else if arg == "--noaccel" {
|
||||
do_accel = false;
|
||||
} else if arg == "avx2" {
|
||||
target = Target::X86_64Avx2;
|
||||
} else if arg == "--ktest" {
|
||||
tests = true;
|
||||
} else {
|
||||
return Err(report!(Error::InvalidSubCom));
|
||||
}
|
||||
}
|
||||
|
||||
build(release, target)?;
|
||||
run(release, target)
|
||||
build(release, target, debuginfo, tests)?;
|
||||
run(release, target, do_accel)
|
||||
}
|
||||
Some("help" | "h") => {
|
||||
println!(concat!(
|
||||
|
@ -63,8 +107,11 @@ fn main() -> Result<(), Error> {
|
|||
" help (h): Print this message\n",
|
||||
" run (r): Build and run AbleOS in QEMU\n\n",
|
||||
"Options for build and run:\n",
|
||||
" -r: build in release mode",
|
||||
" [target]: sets target"
|
||||
" -r / --release: build in release mode\n",
|
||||
" -d / --debuginfo: build with debug info\n",
|
||||
" --noaccel: run without acceleration (e.g, no kvm)\n",
|
||||
" --ktest: Enables tests via ktest\n",
|
||||
"[ rv64 / riscv64 / riscv64-virt / aarch64 / arm64 / aarch64-virt / avx2 ]: sets target"
|
||||
),);
|
||||
Ok(())
|
||||
}
|
||||
|
@ -187,7 +234,12 @@ TERM_BACKDROP={}
|
|||
let modules = value.get_mut("modules").unwrap().as_table_mut().unwrap();
|
||||
// let mut real_modules = modules.clone();
|
||||
|
||||
modules.into_iter().for_each(|(key, value)| {
|
||||
let mut errors = String::new();
|
||||
let mut out = Vec::new();
|
||||
|
||||
modules
|
||||
.into_iter()
|
||||
.map(|(_, value)| -> Result<(), io::Error> {
|
||||
if value.is_table() {
|
||||
let path = get_path_without_boot_prefix(
|
||||
value.get("path").expect("You must have `path` as a value"),
|
||||
|
@ -199,9 +251,26 @@ TERM_BACKDROP={}
|
|||
let p = Package::load_from_file(
|
||||
format!("sysdata/programs/{}/meta.toml", path).to_owned(),
|
||||
);
|
||||
p.build();
|
||||
match p.build(&mut out) {
|
||||
Ok(()) => {}
|
||||
Err(_) => {
|
||||
writeln!(errors, "========= while compiling {} =========", path)
|
||||
.unwrap();
|
||||
errors.push_str(core::str::from_utf8(&out).expect("no"));
|
||||
out.clear();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
})
|
||||
.for_each(drop);
|
||||
|
||||
if !errors.is_empty() {
|
||||
let _ = writeln!(errors, "!!! STOPPING DUE TO PREVIOUS ERRORS !!!");
|
||||
std::eprint!("{errors}");
|
||||
continue;
|
||||
}
|
||||
|
||||
modules.into_iter().for_each(|(_key, value)| {
|
||||
if value.is_table() {
|
||||
let path = value.get("path").expect("You must have `path` as a value");
|
||||
|
@ -236,7 +305,7 @@ TERM_BACKDROP={}
|
|||
let bootdir = fs.root_dir().create_dir("efi")?.create_dir("boot")?;
|
||||
|
||||
let mut f = fs.root_dir().create_file("limine.cfg")?;
|
||||
let a = f.write(limine_str.as_bytes())?;
|
||||
let _ = f.write(limine_str.as_bytes())?;
|
||||
drop(f);
|
||||
|
||||
io::copy(
|
||||
|
@ -270,7 +339,7 @@ fn copy_file_to_img(fpath: &str, fs: &FileSystem<File>) {
|
|||
.expect("Copy failed");
|
||||
}
|
||||
|
||||
fn build(release: bool, target: Target) -> Result<(), Error> {
|
||||
fn build(release: bool, target: Target, debuginfo: bool, tests: bool) -> Result<(), Error> {
|
||||
let fs = get_fs().change_context(Error::Io)?;
|
||||
let mut com = Command::new("cargo");
|
||||
com.current_dir("kernel");
|
||||
|
@ -278,6 +347,13 @@ fn build(release: bool, target: Target) -> Result<(), Error> {
|
|||
if release {
|
||||
com.arg("-r");
|
||||
}
|
||||
if debuginfo {
|
||||
com.env("RUSTFLAGS", "-Cdebug-assertions=true");
|
||||
}
|
||||
|
||||
if tests {
|
||||
com.args(["--features", "ktest"]);
|
||||
}
|
||||
|
||||
if target == Target::Riscv64Virt {
|
||||
com.args(["--target", "targets/riscv64-virt-ableos.json"]);
|
||||
|
@ -285,6 +361,9 @@ fn build(release: bool, target: Target) -> Result<(), Error> {
|
|||
if target == Target::Aarch64 {
|
||||
com.args(["--target", "targets/aarch64-virt-ableos.json"]);
|
||||
}
|
||||
if target == Target::X86_64Avx2 {
|
||||
com.args(["--target", "targets/x86_64_v3-ableos.json"]);
|
||||
}
|
||||
|
||||
match com.status() {
|
||||
Ok(s) if s.code() != Some(0) => bail!(Error::Build),
|
||||
|
@ -298,6 +377,10 @@ fn build(release: bool, target: Target) -> Result<(), Error> {
|
|||
path.push_str("_x86-64");
|
||||
"target/x86_64-ableos"
|
||||
}
|
||||
Target::X86_64Avx2 => {
|
||||
path.push_str("_x86-64");
|
||||
"target/x86_64_v3-ableos"
|
||||
}
|
||||
Target::Riscv64Virt => "target/riscv64-virt-ableos",
|
||||
Target::Aarch64 => {
|
||||
path.push_str("_aarch64");
|
||||
|
@ -320,25 +403,72 @@ fn build(release: bool, target: Target) -> Result<(), Error> {
|
|||
.change_context(Error::Io)
|
||||
}
|
||||
|
||||
fn run(release: bool, target: Target) -> Result<(), Error> {
|
||||
let mut com = match target {
|
||||
Target::X86_64 => Command::new("qemu-system-x86_64"),
|
||||
Target::Riscv64Virt => Command::new("qemu-system-riscv64"),
|
||||
Target::Aarch64 => Command::new("qemu-system-aarch64"),
|
||||
fn run(release: bool, target: Target, do_accel: bool) -> Result<(), Error> {
|
||||
let target_str = match target {
|
||||
Target::X86_64 | Target::X86_64Avx2 => "qemu-system-x86_64",
|
||||
Target::Riscv64Virt => "qemu-system-riscv64",
|
||||
Target::Aarch64 => "qemu-system-aarch64",
|
||||
};
|
||||
let (mut com, mut com2) = (Command::new(target_str), Command::new(target_str));
|
||||
let ovmf_path = fetch_ovmf(target);
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
let accel = if do_accel {
|
||||
let supported = String::from_utf8(
|
||||
com2.args(["--accel", "help"])
|
||||
.stdout(Stdio::piped())
|
||||
.stderr(Stdio::piped())
|
||||
.spawn()
|
||||
.unwrap()
|
||||
.wait_with_output()
|
||||
.unwrap()
|
||||
.stdout,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let cpuid = raw_cpuid::CpuId::new();
|
||||
let vmx = cpuid.get_feature_info().unwrap().has_vmx();
|
||||
let svm = cpuid.get_svm_info().is_some();
|
||||
|
||||
if supported.contains("kvm") && (vmx || svm) {
|
||||
"accel=kvm"
|
||||
} else if cpuid
|
||||
.get_processor_brand_string()
|
||||
.filter(|a| a.as_str() == "GenuineIntel")
|
||||
.is_some()
|
||||
&& supported.contains("hax")
|
||||
&& vmx
|
||||
{
|
||||
"accel=hax"
|
||||
} else if supported.contains("whpx") {
|
||||
"accel=whpx"
|
||||
} else {
|
||||
"accel=tcg"
|
||||
}
|
||||
} else {
|
||||
"accel=tcg"
|
||||
};
|
||||
#[cfg(not(target_arch = "x86_64"))]
|
||||
let accel = "accel=tcg";
|
||||
|
||||
match target {
|
||||
Target::X86_64 => {
|
||||
Target::X86_64 | Target::X86_64Avx2 => {
|
||||
#[rustfmt::skip]
|
||||
com.args([
|
||||
"-bios", &ovmf_path.change_context(Error::OvmfFetch)?,
|
||||
"-drive", "file=target/disk.img,format=raw",
|
||||
"-m", "4G",
|
||||
"-smp", "cores=4",
|
||||
"-enable-kvm",
|
||||
"-cpu", "host",
|
||||
"-device", "isa-debug-exit,iobase=0xf4,iosize=0x04"
|
||||
"-device", "vmware-svga",
|
||||
// "-serial", "stdio",
|
||||
"-m", "2G",
|
||||
"-smp", "1",
|
||||
"-audiodev",
|
||||
"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 => {
|
||||
|
@ -359,7 +489,7 @@ fn run(release: bool, target: Target) -> Result<(), Error> {
|
|||
#[rustfmt::skip]
|
||||
com.args([
|
||||
"-M", "virt",
|
||||
"-cpu", "cortex-a72",
|
||||
"-cpu", "max",
|
||||
"-device", "ramfb",
|
||||
"-device", "qemu-xhci",
|
||||
"-device", "usb-kbd",
|
||||
|
@ -382,7 +512,7 @@ fn run(release: bool, target: Target) -> Result<(), Error> {
|
|||
|
||||
fn fetch_ovmf(target: Target) -> Result<String, OvmfFetchError> {
|
||||
let (ovmf_url, ovmf_path) = match target {
|
||||
Target::X86_64 => (
|
||||
Target::X86_64 | Target::X86_64Avx2 => (
|
||||
"https://retrage.github.io/edk2-nightly/bin/RELEASEX64_OVMF.fd",
|
||||
"target/RELEASEX64_OVMF.fd",
|
||||
),
|
||||
|
@ -404,12 +534,12 @@ fn fetch_ovmf(target: Target) -> Result<String, OvmfFetchError> {
|
|||
Ok(_) => return Ok(ovmf_path.to_owned()),
|
||||
Err(e) => return Err(report!(e).change_context(OvmfFetchError::Io)),
|
||||
};
|
||||
let mut bytes = reqwest::blocking::get(ovmf_url)
|
||||
let req = ureq::get(ovmf_url)
|
||||
.call()
|
||||
.map_err(Report::from)
|
||||
.change_context(OvmfFetchError::Fetch)?;
|
||||
|
||||
bytes
|
||||
.copy_to(&mut file)
|
||||
std::io::copy(&mut req.into_reader(), &mut file)
|
||||
.map_err(Report::from)
|
||||
.change_context(OvmfFetchError::Io)?;
|
||||
|
||||
|
@ -418,11 +548,11 @@ fn fetch_ovmf(target: Target) -> Result<String, OvmfFetchError> {
|
|||
|
||||
#[derive(Debug, Display)]
|
||||
enum OvmfFetchError {
|
||||
#[display(fmt = "Failed to fetch OVMF package")]
|
||||
#[display("Failed to fetch OVMF package")]
|
||||
Fetch,
|
||||
#[display(fmt = "No OVMF package available")]
|
||||
#[display("No OVMF package available")]
|
||||
Empty,
|
||||
#[display(fmt = "IO Error")]
|
||||
#[display("IO Error")]
|
||||
Io,
|
||||
}
|
||||
|
||||
|
@ -431,30 +561,33 @@ impl Context for OvmfFetchError {}
|
|||
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||
enum Target {
|
||||
X86_64,
|
||||
X86_64Avx2,
|
||||
Riscv64Virt,
|
||||
Aarch64,
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
#[derive(Debug, Display)]
|
||||
enum Error {
|
||||
#[display(fmt = "Failed to build the kernel")]
|
||||
#[display("Failed to build the kernel")]
|
||||
Build,
|
||||
#[display(fmt = "Missing or invalid subcommand (available: build, run)")]
|
||||
#[display("Missing or invalid subcommand (available: build, run)")]
|
||||
InvalidSubCom,
|
||||
#[display(fmt = "IO Error")]
|
||||
#[display("IO Error")]
|
||||
Io,
|
||||
#[display(fmt = "Failed to spawn a process")]
|
||||
#[display("Failed to spawn a process")]
|
||||
ProcessSpawn,
|
||||
#[display(fmt = "Failed to fetch UEFI firmware")]
|
||||
#[display("Failed to fetch UEFI firmware")]
|
||||
OvmfFetch,
|
||||
#[display(fmt = "Failed to assemble Holey Bytes code")]
|
||||
#[display("Failed to assemble Holey Bytes code")]
|
||||
Assembler,
|
||||
#[display(fmt = "QEMU Error: {}", "fmt_qemu_err(*_0)")]
|
||||
#[display("QEMU Error: {}", "fmt_qemu_err(*_0)")]
|
||||
Qemu(Option<i32>),
|
||||
}
|
||||
|
||||
impl Context for Error {}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn fmt_qemu_err(e: Option<i32>) -> impl Display {
|
||||
struct W(Option<i32>);
|
||||
impl Display for W {
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
[toolchain]
|
||||
channel = "nightly-2024-05-17"
|
||||
# old toolchain
|
||||
# channel = "nightly-2024-07-27"
|
||||
# last stable
|
||||
# channel = "nightly-2024-11-20"
|
||||
channel = "nightly"
|
||||
components = ["rust-src", "llvm-tools"]
|
||||
|
|
BIN
sysdata/assets/able.bmp
Normal file
BIN
sysdata/assets/able.bmp
Normal file
Binary file not shown.
After Width: | Height: | Size: 100 KiB |
BIN
sysdata/assets/consolefonts/tamsyn/10x20b.psf
Normal file
BIN
sysdata/assets/consolefonts/tamsyn/10x20b.psf
Normal file
Binary file not shown.
BIN
sysdata/assets/consolefonts/tamsyn/10x20r.psf
Normal file
BIN
sysdata/assets/consolefonts/tamsyn/10x20r.psf
Normal file
Binary file not shown.
BIN
sysdata/assets/consolefonts/tamsyn/5x9b.psf
Normal file
BIN
sysdata/assets/consolefonts/tamsyn/5x9b.psf
Normal file
Binary file not shown.
BIN
sysdata/assets/consolefonts/tamsyn/5x9r.psf
Normal file
BIN
sysdata/assets/consolefonts/tamsyn/5x9r.psf
Normal file
Binary file not shown.
BIN
sysdata/assets/consolefonts/tamsyn/6x12b.psf
Normal file
BIN
sysdata/assets/consolefonts/tamsyn/6x12b.psf
Normal file
Binary file not shown.
BIN
sysdata/assets/consolefonts/tamsyn/6x12r.psf
Normal file
BIN
sysdata/assets/consolefonts/tamsyn/6x12r.psf
Normal file
Binary file not shown.
BIN
sysdata/assets/consolefonts/tamsyn/7x13b.psf
Normal file
BIN
sysdata/assets/consolefonts/tamsyn/7x13b.psf
Normal file
Binary file not shown.
BIN
sysdata/assets/consolefonts/tamsyn/7x13r.psf
Normal file
BIN
sysdata/assets/consolefonts/tamsyn/7x13r.psf
Normal file
Binary file not shown.
BIN
sysdata/assets/consolefonts/tamsyn/7x14b.psf
Normal file
BIN
sysdata/assets/consolefonts/tamsyn/7x14b.psf
Normal file
Binary file not shown.
BIN
sysdata/assets/consolefonts/tamsyn/7x14r.psf
Normal file
BIN
sysdata/assets/consolefonts/tamsyn/7x14r.psf
Normal file
Binary file not shown.
BIN
sysdata/assets/consolefonts/tamsyn/8x15b.psf
Normal file
BIN
sysdata/assets/consolefonts/tamsyn/8x15b.psf
Normal file
Binary file not shown.
BIN
sysdata/assets/consolefonts/tamsyn/8x15r.psf
Normal file
BIN
sysdata/assets/consolefonts/tamsyn/8x15r.psf
Normal file
Binary file not shown.
BIN
sysdata/assets/consolefonts/tamsyn/8x16b.psf
Normal file
BIN
sysdata/assets/consolefonts/tamsyn/8x16b.psf
Normal file
Binary file not shown.
BIN
sysdata/assets/consolefonts/tamsyn/8x16r.psf
Normal file
BIN
sysdata/assets/consolefonts/tamsyn/8x16r.psf
Normal file
Binary file not shown.
10
sysdata/assets/consolefonts/tamsyn/LICENSE
Normal file
10
sysdata/assets/consolefonts/tamsyn/LICENSE
Normal file
|
@ -0,0 +1,10 @@
|
|||
Tamsyn font is free. You are hereby granted permission to use, copy, modify,
|
||||
and distribute it as you see fit.
|
||||
|
||||
Tamsyn font is provided "as is" without any express or implied warranty.
|
||||
|
||||
The author makes no representations about the suitability of this font for
|
||||
a particular purpose.
|
||||
|
||||
In no event will the author be held liable for damages arising from the use
|
||||
of this font.
|
BIN
sysdata/assets/mini.bmp
Normal file
BIN
sysdata/assets/mini.bmp
Normal file
Binary file not shown.
After Width: | Height: | Size: 100 KiB |
BIN
sysdata/assets/mini.qoi
Normal file
BIN
sysdata/assets/mini.qoi
Normal file
Binary file not shown.
BIN
sysdata/assets/wallpaper.qoi
Normal file
BIN
sysdata/assets/wallpaper.qoi
Normal file
Binary file not shown.
BIN
sysdata/empty-background.bmp
Normal file
BIN
sysdata/empty-background.bmp
Normal file
Binary file not shown.
After Width: | Height: | Size: 66 B |
|
@ -1,24 +1,23 @@
|
|||
// A comment
|
||||
//@auto_increment
|
||||
@auto_increment
|
||||
enum LogLevel {
|
||||
Error = 0,
|
||||
Warn = 1,
|
||||
Info = 2,
|
||||
Debug = 3,
|
||||
Trace = 4,
|
||||
Warn,
|
||||
Info,
|
||||
Debug,
|
||||
Trace,
|
||||
}
|
||||
|
||||
//@auto_increment
|
||||
@auto_increment
|
||||
enum LogResult {
|
||||
Err = 0,
|
||||
Ok = 1,
|
||||
Ok,
|
||||
}
|
||||
|
||||
struct Log {
|
||||
log_level: LogLevel,
|
||||
}
|
||||
|
||||
//@visibility(public)
|
||||
@visibility(public)
|
||||
protocol Log {
|
||||
fn log(Log) -> LogResult;
|
||||
fn flush() -> LogResult;
|
|
@ -1,3 +0,0 @@
|
|||
protocol Foo{
|
||||
fn bar(i32, u8, bool) -> void;
|
||||
}
|
4
sysdata/libraries/horizon_api/examples/horizontal.lui
Normal file
4
sysdata/libraries/horizon_api/examples/horizontal.lui
Normal file
|
@ -0,0 +1,4 @@
|
|||
(horizontal
|
||||
spacing : 10
|
||||
(label "hi")
|
||||
(label "goodbye"))
|
1
sysdata/libraries/horizon_api/examples/label.lui
Normal file
1
sysdata/libraries/horizon_api/examples/label.lui
Normal file
|
@ -0,0 +1 @@
|
|||
(label "hello")
|
3
sysdata/libraries/horizon_api/examples/vertical.lui
Normal file
3
sysdata/libraries/horizon_api/examples/vertical.lui
Normal file
|
@ -0,0 +1,3 @@
|
|||
(vertical
|
||||
(label "hello")
|
||||
(label "hello" color:red))
|
|
@ -1,14 +0,0 @@
|
|||
Element := struct {
|
||||
width: int,
|
||||
height: int,
|
||||
|
||||
x: u16,
|
||||
y: u16,
|
||||
|
||||
id: int,
|
||||
}
|
||||
|
||||
create_element := fn(): Element {
|
||||
return Element.(0, 0, 0, 0, 0)
|
||||
}
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
FrameID := struct {
|
||||
|
||||
}
|
|
@ -1,12 +1,43 @@
|
|||
stn := @use("../../stn/src/lib.hb");
|
||||
.{string, memory, buffer, log} := stn
|
||||
|
||||
render := @use("../../../libraries/render/src/lib.hb")
|
||||
|
||||
input := @use("../../intouch/src/lib.hb")
|
||||
|
||||
widgets := @use("widgets/widgets.hb")
|
||||
ui := @use("ui.hb")
|
||||
|
||||
WindowID := struct {
|
||||
host_id: int,
|
||||
window_id: int,
|
||||
}
|
||||
|
||||
create_window := fn(): WindowID {
|
||||
return WindowID.(1, 2)
|
||||
VoidWindowID := WindowID.(0, 0)
|
||||
|
||||
create_window := fn(channel: int): ^render.Surface {
|
||||
// get the horizon buffer
|
||||
// request a new window and provide the callback buffer
|
||||
// wait to recieve a message
|
||||
|
||||
windowing_system_buffer := buffer.search("XHorizon\0")
|
||||
mem_buf := memory.request_page(1)
|
||||
|
||||
if windowing_system_buffer == 0 {
|
||||
return @as(^render.Surface, idk)
|
||||
} else {
|
||||
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")
|
||||
}
|
||||
|
||||
update_ui := fn(window_id: WindowID): void {
|
||||
return
|
||||
if *mem_buf == 0 {
|
||||
log.info("No messages\0")
|
||||
}
|
||||
|
||||
return @as(^render.Surface, idk)
|
||||
}
|
||||
}
|
|
@ -1,3 +0,0 @@
|
|||
ui_lisp_text_example := "(text id_1)\0";
|
||||
|
||||
|
47
sysdata/libraries/horizon_api/src/ui.hb
Normal file
47
sysdata/libraries/horizon_api/src/ui.hb
Normal file
|
@ -0,0 +1,47 @@
|
|||
stn := @use("../../../libraries/stn/src/lib.hb");
|
||||
.{string, log} := stn;
|
||||
.{Vec2} := stn.math
|
||||
|
||||
render := @use("../../../libraries/render/src/lib.hb");
|
||||
.{Surface} := render;
|
||||
.{Font} := render.text
|
||||
|
||||
UI := struct {raw: ^u8, raw_length: uint, is_dirty: bool, surface: Surface, // Each child has their WidgetType as their first byte
|
||||
// children: ^^u8,
|
||||
}
|
||||
|
||||
render_ui := fn(surface: Surface, ui: UI): void {
|
||||
if ui.is_dirty {
|
||||
render.clear(ui.surface, render.black)
|
||||
ui.is_dirty = false
|
||||
}
|
||||
pos := Vec2(uint).(0, 0)
|
||||
render.put_surface(surface, ui.surface, pos, false)
|
||||
}
|
||||
|
||||
sexpr_parser := fn(sexpr: ^u8): UI {
|
||||
cursor := sexpr
|
||||
paren_balance := 0
|
||||
loop {
|
||||
if *cursor == 0 {
|
||||
if paren_balance != 0 {
|
||||
log.error("Unbalanced Parens\0")
|
||||
}
|
||||
break
|
||||
} else if *cursor == 40 {
|
||||
log.info("Open paren\0")
|
||||
paren_balance += 1
|
||||
} else if *cursor == 41 {
|
||||
log.info("Closed paren\0")
|
||||
paren_balance -= 1
|
||||
}
|
||||
|
||||
cursor += 1
|
||||
}
|
||||
|
||||
length := string.length(sexpr)
|
||||
|
||||
ui_surface := render.new_surface(100, 100)
|
||||
|
||||
return UI.(sexpr, length, true, ui_surface)
|
||||
}
|
13
sysdata/libraries/horizon_api/src/widgets/image.hb
Normal file
13
sysdata/libraries/horizon_api/src/widgets/image.hb
Normal file
|
@ -0,0 +1,13 @@
|
|||
render := @use("../../../../libraries/render/src/lib.hb");
|
||||
.{Surface} := render
|
||||
|
||||
Image := struct {
|
||||
magic: uint,
|
||||
is_dirty: bool,
|
||||
surface: Surface,
|
||||
}
|
||||
|
||||
image_from_surface := fn(surface: Surface): Image {
|
||||
img := Image.(4, true, surface)
|
||||
return img
|
||||
}
|
46
sysdata/libraries/horizon_api/src/widgets/label.hb
Normal file
46
sysdata/libraries/horizon_api/src/widgets/label.hb
Normal file
|
@ -0,0 +1,46 @@
|
|||
stn := @use("../../../../libraries/stn/src/lib.hb");
|
||||
.{string, log} := stn;
|
||||
.{Vec2} := stn.math
|
||||
|
||||
render := @use("../../../../libraries/render/src/lib.hb");
|
||||
.{Surface, Color} := render;
|
||||
.{Font} := render.text
|
||||
|
||||
Label := struct {
|
||||
magic: uint,
|
||||
is_dirty: bool,
|
||||
surface: Surface,
|
||||
text: ^u8,
|
||||
text_length: uint,
|
||||
bg: Color,
|
||||
fg: Color,
|
||||
|
||||
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)
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
NoWidget := 0
|
||||
|
||||
VerticalWidgetType := 1
|
||||
HorizontalWidgetType := 2
|
||||
|
||||
LabelWidgetType := 3
|
||||
ImageWidgetType := 4
|
36
sysdata/libraries/horizon_api/src/widgets/widgets.hb
Normal file
36
sysdata/libraries/horizon_api/src/widgets/widgets.hb
Normal file
|
@ -0,0 +1,36 @@
|
|||
// Widget types
|
||||
|
||||
// End types
|
||||
stn := @use("../../../../libraries/stn/src/lib.hb");
|
||||
.{string, log} := stn;
|
||||
.{Vec2} := stn.math
|
||||
|
||||
render := @use("../../../../libraries/render/src/lib.hb");
|
||||
.{Surface} := render;
|
||||
.{Font} := render.text
|
||||
|
||||
widget_types := @use("widget_types.hb")
|
||||
label := @use("label.hb")
|
||||
image := @use("image.hb")
|
||||
|
||||
Size := struct {
|
||||
min_width: int,
|
||||
max_width: int,
|
||||
min_height: int,
|
||||
max_height: int,
|
||||
}
|
||||
|
||||
Vertical := packed struct {
|
||||
magic: uint,
|
||||
// array of children, idk
|
||||
// use a vec or linked list or whatever
|
||||
|
||||
children: ^^u8,
|
||||
}
|
||||
|
||||
Horizontal := packed struct {
|
||||
magic: uint,
|
||||
// array of children, idk
|
||||
// use a vec or linked list or whatever
|
||||
children: ^^u8,
|
||||
}
|
21
sysdata/libraries/ignim/src/application.hb
Normal file
21
sysdata/libraries/ignim/src/application.hb
Normal file
|
@ -0,0 +1,21 @@
|
|||
structures := @use("structures.hb")
|
||||
version := @use("version.hb")
|
||||
|
||||
// Refer to here https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkApplicationInfo.html
|
||||
ApplicationInfo := struct {
|
||||
sType: int,
|
||||
pNext: ^int,
|
||||
application_name: ^u8,
|
||||
application_version: int,
|
||||
engine_name: ^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
|
||||
}
|
14
sysdata/libraries/ignim/src/errors.hb
Normal file
14
sysdata/libraries/ignim/src/errors.hb
Normal file
|
@ -0,0 +1,14 @@
|
|||
OutOfHostMemory := -1
|
||||
OutOfDeviceMemory := -2
|
||||
InitializationFailed := -3
|
||||
DeviceLost := -4
|
||||
MemoryMapFailed := -5
|
||||
|
||||
LayerNotPresent := -6
|
||||
ExtensionNotPresent := -7
|
||||
FeatureNotPresent := -8
|
||||
IncompatibleDriver := -9
|
||||
TooManyObjects := -10
|
||||
FormatNotSupported := -11
|
||||
FragmentedPool := -12
|
||||
Unknown := -13
|
10
sysdata/libraries/ignim/src/extends.hb
Normal file
10
sysdata/libraries/ignim/src/extends.hb
Normal file
|
@ -0,0 +1,10 @@
|
|||
Extent3D := struct {
|
||||
width: int,
|
||||
height: int,
|
||||
depth: int,
|
||||
}
|
||||
|
||||
Extent2D := struct {
|
||||
width: int,
|
||||
height: int,
|
||||
}
|
35
sysdata/libraries/ignim/src/instance.hb
Normal file
35
sysdata/libraries/ignim/src/instance.hb
Normal file
|
@ -0,0 +1,35 @@
|
|||
application := @use("application.hb");
|
||||
.{ApplicationInfo} := application
|
||||
|
||||
structures := @use("structures.hb")
|
||||
errors := @use("errors.hb")
|
||||
|
||||
// https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkInstanceCreateInfo.html
|
||||
InstanceCreateInfo := struct {
|
||||
sType: int,
|
||||
pNext: int,
|
||||
flags: int,
|
||||
application_info: ^ApplicationInfo,
|
||||
enabled_layer_count: int,
|
||||
ppEnabledLayerNames: int,
|
||||
enabled_extension_count: int,
|
||||
ppEnabledExtensionNames: int,
|
||||
}
|
||||
|
||||
new_create_info := fn(application_info: ^ApplicationInfo): InstanceCreateInfo {
|
||||
create_info_type := structures.InstanceCreateInfoType
|
||||
enabled_layer_count := 0
|
||||
|
||||
create_info := InstanceCreateInfo.(create_info_type, 0, 0, application_info, enabled_layer_count, 0, 0, 0)
|
||||
return create_info
|
||||
}
|
||||
|
||||
// TODO
|
||||
Instance := struct {inner: int}
|
||||
void_instance := fn(): Instance {
|
||||
return Instance.(0)
|
||||
}
|
||||
|
||||
create_instance := fn(create_info: ^InstanceCreateInfo, allocator_callback: int, new_obj: ^Instance): int {
|
||||
return errors.IncompatibleDriver
|
||||
}
|
|
@ -1,7 +1,17 @@
|
|||
VK_VERSION_MAJOR := 1;
|
||||
VK_VERSION_MINOR := 0;
|
||||
application := @use("application.hb")
|
||||
|
||||
init_vulkan := fn(): void {
|
||||
results := @use("results.hb")
|
||||
errors := @use("errors.hb")
|
||||
|
||||
return
|
||||
offsets := @use("offset.hb")
|
||||
extends := @use("extends.hb")
|
||||
|
||||
rect := @use("rect.hb")
|
||||
structures := @use("structures.hb")
|
||||
instance := @use("instance.hb")
|
||||
|
||||
version := @use("version.hb")
|
||||
|
||||
init_vulkan := fn(): int {
|
||||
return errors.IncompatibleDriver
|
||||
}
|
10
sysdata/libraries/ignim/src/offset.hb
Normal file
10
sysdata/libraries/ignim/src/offset.hb
Normal file
|
@ -0,0 +1,10 @@
|
|||
Offset3D := struct {
|
||||
x: int,
|
||||
y: int,
|
||||
z: int,
|
||||
}
|
||||
|
||||
Offset2D := struct {
|
||||
x: int,
|
||||
y: int,
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue