forked from AbleOS/ableos
Compare commits
402 commits
Author | SHA1 | Date | |
---|---|---|---|
koniifer | 90f1b3fdc5 | ||
koniifer | 986077435f | ||
koniifer | 530b62aa3d | ||
Able | b864463ad8 | ||
Able | 1e1943d940 | ||
47d727855d | |||
koniifer | 5b123be9ea | ||
Able | 2fb17ac610 | ||
koniifer | 1ec9d0fd46 | ||
Able | 59cf6ef4d7 | ||
koniifer | 8cce5ef731 | ||
koniifer | 0fc95160cc | ||
koniifer | 25fecab5b3 | ||
f6bfb73bd7 | |||
koniifer | f8523f5b3e | ||
koniifer | d2cb73c2ce | ||
koniifer | d0bd3714ee | ||
koniifer | e8f1bce4d6 | ||
dc4878bc2b | |||
koniifer | 04ca5f07d5 | ||
ad587fe464 | |||
9a06b329f4 | |||
koniifer | 936c9e6525 | ||
koniifer | a8572da351 | ||
koniifer | b059faa7f8 | ||
koniifer | d55fd895c9 | ||
koniifer | e2dd379fea | ||
koniifer | d907df14dd | ||
koniifer | 3506c83535 | ||
Able | eff1323e94 | ||
Able | 8849017db2 | ||
Able | f3b78d1699 | ||
koniifer | 5eff0facb1 | ||
koniifer | 6e3fea0713 | ||
koniifer | 55c8d9b8b2 | ||
koniifer | 642b0b74b5 | ||
koniifer | 5b3a97e580 | ||
koniifer | ee68a2662c | ||
Able | 72cf91a928 | ||
Able | f714775091 | ||
Able | 6af68994d8 | ||
Able | df7982d9e5 | ||
koniifer | e688fdf4f0 | ||
Able | bcc7c827ab | ||
Able | eff2a22018 | ||
Able | 883c01b2ba | ||
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 | ||
Able | 0594b99a59 | ||
Able | 1855307cd9 | ||
koniifer | e3f7a2d455 | ||
koniifer | 19992595fc | ||
koniifer | f7b970eaf0 | ||
koniifer | c752028c73 | ||
koniifer | 8577920d90 | ||
Able | 7426bf479f | ||
12ee3a9b87 | |||
58bc6facbc | |||
1615297536 | |||
0d3641e199 | |||
Able | 6295a7118e | ||
ad85f82be3 | |||
Able | 9100b3ce44 | ||
Able | 1c491e70e0 | ||
Able | 0444fe4dfa | ||
db08a249e1 | |||
acc9d19a32 | |||
Able | 6fd47695a6 | ||
Able | fb8a835926 | ||
Able | f4246ae387 | ||
Able | c7214a5a9b | ||
Able | bf86d9219c | ||
Able | ea6ba3bdb0 | ||
Able | 3f183e231d | ||
Able | 514dadc667 | ||
Able | 9ec3bb1f99 | ||
Able | b99cb09a74 | ||
Able | 528b1fc66c | ||
Able | f0956b529c | ||
Able | bb37de554f | ||
0f3c94c0c9 | |||
Sam Buckley | 314523fce7 | ||
Sam Buckley | 9f9c7af85f | ||
Sam Buckley | f59776e792 | ||
Able | 1adc381399 | ||
Able | f33cc0bf70 | ||
Able | 5f136a66af | ||
Able | 54d7e6b02b | ||
Able | 62c181fb6a | ||
Able | e9e813220b | ||
able | 02455e2cd8 | ||
able | e08eab8627 | ||
c57ef99948 | |||
Christian Westrom | b0358efab8 | ||
Christian Westrom | da606facb0 | ||
able | b427ae1c27 | ||
able | a511e99606 | ||
able | d90016f28e | ||
able | c20376464e | ||
bbe29d54ab | |||
Christian Westrom | a5cab167c5 | ||
Christian Westrom | b96927d61a | ||
able | edda52e857 | ||
able | d7efa8ca20 | ||
able | 5fc2e2a6be | ||
able | d21654dd4b | ||
able | 38986193ca | ||
able | 779f3bdd1f | ||
able | f767362ad0 | ||
able | 088e628cde | ||
able | 1cc414eaaf | ||
able | 5e73e7a370 | ||
able | cc4de4ab5e | ||
able | 634d05acea | ||
able | 189ad503c7 | ||
able | fac1f77270 | ||
able | eb30ee3c12 | ||
able | 89b495d318 | ||
able | 7c68609af5 | ||
able | dfacc91f40 | ||
able | 307020b96b | ||
able | d8cb4d4e64 | ||
able | 195192db8a | ||
5fba1eb890 | |||
0a6085061a | |||
6f061153e6 | |||
cb66c07a5f | |||
able | 15515e6643 | ||
able | 7a2372d32a | ||
able | 65b6f52d2e | ||
able | 562fb7c9b2 | ||
able | 762b2aa3ae | ||
able | fe6cccc70d | ||
able | 815c424248 | ||
Erin | b8ce78b6dd | ||
Erin | d396da5f3c | ||
Erin | 0f7525b7e3 | ||
able | ebf31cba3d | ||
able | f074527e42 | ||
Erin | f2e561e242 | ||
Erin | 2c1d24ab37 | ||
Erin | 4e9b75a517 | ||
able | 0af4758a45 | ||
Erin | fd575a17c9 | ||
able | bda8659747 | ||
able | 631e1dc288 | ||
able | b7f9b071bf | ||
able | 94569624f6 | ||
able | 080bb8b188 | ||
able | 1ae1d2ceac | ||
able | 707528ef86 | ||
able | c8f500470e | ||
Erin | 6885f1cdaf | ||
able | fa328add42 | ||
able | d1d1bd7fd7 | ||
Erin | ebfc9c1c4e | ||
able | ada43910d2 | ||
able | 29bcce58b3 | ||
able | 9105469c3b | ||
able | e7bbb9a375 | ||
able | 008a8eb336 | ||
able | e0aa63bebf | ||
able | 9cf6f93949 | ||
able | 1be13d30d1 | ||
able | 8fec90db95 | ||
able | c16c235c95 | ||
able | 54844b46a0 | ||
able | b04ee13185 | ||
Erin | 0e8fb17f3a | ||
Erin | 3c45720fa3 | ||
Erin | cbed32526b | ||
Erin | 0f151fdd52 | ||
Erin | f948e35e3f | ||
Erin | 88213a7df0 | ||
239ee43064 | |||
microtau | c9ab181d95 | ||
microtau | f474f0fb69 | ||
microtau | d0a2f436a8 | ||
microtau | 7865bca782 |
|
@ -1,2 +1,3 @@
|
||||||
[alias]
|
[alias]
|
||||||
repbuild = "run --manifest-path ./repbuild/Cargo.toml -- "
|
repbuild = "run --manifest-path ./repbuild/Cargo.toml -- "
|
||||||
|
dev = "run --manifest-path ./dev/Cargo.toml -r --"
|
||||||
|
|
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1,2 +1 @@
|
||||||
target/
|
target/
|
||||||
/.idea
|
|
5
.vscode/settings.json
vendored
5
.vscode/settings.json
vendored
|
@ -1,4 +1,7 @@
|
||||||
{
|
{
|
||||||
|
"editor.insertSpaces": false,
|
||||||
|
"editor.detectIndentation": false,
|
||||||
"rust-analyzer.checkOnSave.allTargets": false,
|
"rust-analyzer.checkOnSave.allTargets": false,
|
||||||
"rust-analyzer.showUnlinkedFileNotification": false
|
"rust-analyzer.showUnlinkedFileNotification": false,
|
||||||
|
"C_Cpp.errorSquiggles": "disabled"
|
||||||
}
|
}
|
BIN
AAVMF_CODE.fd
BIN
AAVMF_CODE.fd
Binary file not shown.
2558
Cargo.lock
generated
2558
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
|
@ -1,3 +1,9 @@
|
||||||
[workspace]
|
[workspace]
|
||||||
resolver = "2"
|
resolver = "2"
|
||||||
members = ["kernel", "repbuild"]
|
members = ["dev", "kernel", "repbuild"]
|
||||||
|
|
||||||
|
# [profile.release]
|
||||||
|
# strip = "symbols"
|
||||||
|
# codegen-units = 1
|
||||||
|
# lto = true
|
||||||
|
# panic = "abort"
|
||||||
|
|
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)
|
45
README.md
45
README.md
|
@ -1,43 +1,16 @@
|
||||||
```
|
# AbleOS
|
||||||
TODO
|
An UNIX-unlike micro-kernel written in rust with an embedded bytecode virtual machine.
|
||||||
- Integrate HBVM
|
|
||||||
HBVM also needs full spec compliance
|
Please note that a custom target directory is not supported and support will not be added.
|
||||||
- Build out the object system
|
|
||||||
- Build or Find an acceptable IDL
|
|
||||||
Short List of potentials
|
|
||||||
- [comline](https://git.ablecorp.us/DOOME1M8Cover/comline)
|
|
||||||
- Work on a styleguide for commits
|
|
||||||
Maybe something allong the lines of
|
|
||||||
[relevant shorthand note] Explination
|
|
||||||
- Build a scheduler for HBVM
|
|
||||||
- Language support on HBVM
|
|
||||||
- HBVM assembler (with IDL support)
|
|
||||||
- HBVM Lisp/s-expr Compiler (Also (with (IDL (support))))
|
|
||||||
- Documentation
|
|
||||||
- Drivers
|
|
||||||
- serial driver
|
|
||||||
- PS/2 mouse driver
|
|
||||||
- PS/2 Keyboard driver
|
|
||||||
- VGA driver
|
|
||||||
- SVGA driver
|
|
||||||
- File system
|
|
||||||
TarFS
|
|
||||||
Pass in a tar file as an initrd and parse it with TarFS
|
|
||||||
- VFS
|
|
||||||
Being (written)[https://git.ablecorp.us/bee/ableos-vfs] by Bee
|
|
||||||
- Disk driver
|
|
||||||
- A ton more
|
|
||||||
```
|
|
||||||
|
|
||||||
# Community
|
# Community
|
||||||
[Discord](https://discord.gg/JrKVukDtgs)
|
[Discord](https://discord.gg/JrKVukDtgs)
|
||||||
|
|
||||||
|
Donations can be made [here on Liberapay](https://liberapay.com/AbleTheAbove) or on [Patreon](https://www.patreon.com/ablecorp)
|
||||||
|
<img src="https://img.shields.io/liberapay/patrons/AbleTheAbove.svg?logo=liberapay">
|
||||||
|
|
||||||
# Compiling
|
# Compiling
|
||||||
Firstly, I would like to apologize. I am not capable of supporting building on any random machine with any random operating system.
|
See [HELP.md](HELP.md)
|
||||||
|
|
||||||
AbleOS very likely builds with `nix-shell` on your operating system.
|
# Developing
|
||||||
|
There is a new work in progress developer tool for hblang. (see: dev folder)
|
||||||
1. `git submodule update --init`
|
|
||||||
1. `cargo repbuild`
|
|
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
|
||||||
|
```
|
11
arm.sh
11
arm.sh
|
@ -1,11 +0,0 @@
|
||||||
qemu-system-aarch64 -m 1024 -cpu cortex-a57 \
|
|
||||||
-M virt -pflash "AAVMF_CODE.fd" \
|
|
||||||
-device virtio-gpu-pci \
|
|
||||||
-device virtio-mouse-device \
|
|
||||||
-device virtio-keyboard-device \
|
|
||||||
-kernel limine/BOOTX64.EFI
|
|
||||||
# -device virtio-serial-pci \
|
|
||||||
# -drive if=none,file=target/disk.img,id=hd0 \
|
|
||||||
# -device virtio-blk-device,drive=hd0
|
|
||||||
|
|
||||||
# -kernel target/aarch64-virt-ableos/debug/kernel
|
|
79
contrib/DriverDepGraph.dot
Normal file
79
contrib/DriverDepGraph.dot
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
digraph Drivers {
|
||||||
|
InitSystem -> VFS;
|
||||||
|
InitSystem -> Logger;
|
||||||
|
|
||||||
|
TCP -> NetworkingStack;
|
||||||
|
UDP -> NetworkingStack;
|
||||||
|
|
||||||
|
NetworkingStack -> PhysLayer;
|
||||||
|
PhysLayer -> Ethernet;
|
||||||
|
|
||||||
|
Ethernet -> Threec90x;
|
||||||
|
Ethernet -> Intel8254x;
|
||||||
|
Ethernet -> Ne2000;
|
||||||
|
Ethernet -> RTL8139;
|
||||||
|
Ethernet -> RTL8169;
|
||||||
|
Ethernet -> IntelEtherneti217;
|
||||||
|
Ethernet -> AMDPCnet;
|
||||||
|
|
||||||
|
PhysLayer -> Wifi;
|
||||||
|
Wifi -> Eight02Dot11;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Audio -> PCSpeaker;
|
||||||
|
Audio -> SoundBlaster16;
|
||||||
|
|
||||||
|
RNG -> CpuRNG;
|
||||||
|
RNG -> NetworkingStack;
|
||||||
|
RNG -> GraphicsLibrary;
|
||||||
|
RNG -> Input;
|
||||||
|
|
||||||
|
Slint -> GraphicsLibrary;
|
||||||
|
GraphicsLibrary -> ShaderCompiler;
|
||||||
|
ShaderCompiler -> GraphicsDriver;
|
||||||
|
GraphicsLibrary -> GraphicsDriver;
|
||||||
|
// Todo: dreak out the GPU into specific drivers
|
||||||
|
GraphicsDriver -> GPU;
|
||||||
|
|
||||||
|
Logger -> Serial;
|
||||||
|
Logger -> VFS;
|
||||||
|
|
||||||
|
Input -> Keyboard;
|
||||||
|
Input -> GraphicsTablet;
|
||||||
|
Input -> Mouse;
|
||||||
|
Input -> Serial;
|
||||||
|
Input -> Controllers;
|
||||||
|
|
||||||
|
Controllers -> Playstation;
|
||||||
|
Playstation -> DualShock;
|
||||||
|
Playstation -> DualSense;
|
||||||
|
DualShock -> DualShock1;
|
||||||
|
DualShock -> DualShock2;
|
||||||
|
DualShock -> DualShock3;
|
||||||
|
DualShock -> DualShock4;
|
||||||
|
|
||||||
|
|
||||||
|
Mouse -> PS2Mouse;
|
||||||
|
Mouse -> USBMouse;
|
||||||
|
USBMouse -> GenericUSBMouse;
|
||||||
|
Mouse -> MouseTrackPad;
|
||||||
|
Mouse -> MouseTrackPoint;
|
||||||
|
|
||||||
|
VFS -> Fat32;
|
||||||
|
VFS -> TarFS;
|
||||||
|
VFS -> Ext2;
|
||||||
|
|
||||||
|
Ext2 -> VirtualDisk;
|
||||||
|
TarFS -> VirtualDisk;
|
||||||
|
Fat32 -> VirtualDisk;
|
||||||
|
|
||||||
|
VirtualDisk -> IDEDiskDriver;
|
||||||
|
VirtualDisk -> ATADiskDriver;
|
||||||
|
VirtualDisk -> FloppyController;
|
||||||
|
VirtualDisk -> CDROM;
|
||||||
|
VirtualDisk -> NVME;
|
||||||
|
|
||||||
|
BlueToothStack;
|
||||||
|
}
|
677
contrib/DriverDepGraph.svg
Normal file
677
contrib/DriverDepGraph.svg
Normal file
|
@ -0,0 +1,677 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<!-- Generated by graphviz version 2.40.1 (20161225.0304)
|
||||||
|
-->
|
||||||
|
<!-- Title: Drivers Pages: 1 -->
|
||||||
|
<svg width="2629pt" height="404pt" viewBox="0.00 0.00 2628.89 404.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||||
|
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 400)">
|
||||||
|
<title>Drivers</title>
|
||||||
|
<polygon fill="#ffffff" stroke="transparent" points="-4,4 -4,-400 2624.8933,-400 2624.8933,4 -4,4"/>
|
||||||
|
<!-- InitSystem -->
|
||||||
|
<g id="node1" class="node">
|
||||||
|
<title>InitSystem</title>
|
||||||
|
<ellipse fill="none" stroke="#000000" cx="443.0953" cy="-378" rx="52.7642" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="443.0953" y="-373.8" font-family="Times,serif" font-size="14.00" fill="#000000">InitSystem</text>
|
||||||
|
</g>
|
||||||
|
<!-- VFS -->
|
||||||
|
<g id="node2" class="node">
|
||||||
|
<title>VFS</title>
|
||||||
|
<ellipse fill="none" stroke="#000000" cx="409.0953" cy="-234" rx="28.991" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="409.0953" y="-229.8" font-family="Times,serif" font-size="14.00" fill="#000000">VFS</text>
|
||||||
|
</g>
|
||||||
|
<!-- InitSystem->VFS -->
|
||||||
|
<g id="edge1" class="edge">
|
||||||
|
<title>InitSystem->VFS</title>
|
||||||
|
<path fill="none" stroke="#000000" d="M437.8111,-360.0742C434.7997,-349.5989 431.0497,-336.0989 428.0953,-324 423.0522,-303.3476 418.1161,-279.8366 414.5395,-262.025"/>
|
||||||
|
<polygon fill="#000000" stroke="#000000" points="417.9306,-261.1317 412.55,-252.0049 411.0646,-262.4951 417.9306,-261.1317"/>
|
||||||
|
</g>
|
||||||
|
<!-- Logger -->
|
||||||
|
<g id="node3" class="node">
|
||||||
|
<title>Logger</title>
|
||||||
|
<ellipse fill="none" stroke="#000000" cx="476.0953" cy="-306" rx="38.8459" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="476.0953" y="-301.8" font-family="Times,serif" font-size="14.00" fill="#000000">Logger</text>
|
||||||
|
</g>
|
||||||
|
<!-- InitSystem->Logger -->
|
||||||
|
<g id="edge2" class="edge">
|
||||||
|
<title>InitSystem->Logger</title>
|
||||||
|
<path fill="none" stroke="#000000" d="M451.2526,-360.2022C454.981,-352.0675 459.4807,-342.2501 463.6203,-333.2181"/>
|
||||||
|
<polygon fill="#000000" stroke="#000000" points="466.9326,-334.3915 467.9175,-323.8425 460.5691,-331.4749 466.9326,-334.3915"/>
|
||||||
|
</g>
|
||||||
|
<!-- Fat32 -->
|
||||||
|
<g id="node46" class="node">
|
||||||
|
<title>Fat32</title>
|
||||||
|
<ellipse fill="none" stroke="#000000" cx="282.0953" cy="-162" rx="33.0643" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="282.0953" y="-157.8" font-family="Times,serif" font-size="14.00" fill="#000000">Fat32</text>
|
||||||
|
</g>
|
||||||
|
<!-- VFS->Fat32 -->
|
||||||
|
<g id="edge46" class="edge">
|
||||||
|
<title>VFS->Fat32</title>
|
||||||
|
<path fill="none" stroke="#000000" d="M387.5515,-221.7862C367.3094,-210.3103 336.7716,-192.9976 313.7591,-179.9511"/>
|
||||||
|
<polygon fill="#000000" stroke="#000000" points="315.4597,-176.8919 305.0343,-175.0048 312.0074,-182.9814 315.4597,-176.8919"/>
|
||||||
|
</g>
|
||||||
|
<!-- TarFS -->
|
||||||
|
<g id="node47" class="node">
|
||||||
|
<title>TarFS</title>
|
||||||
|
<ellipse fill="none" stroke="#000000" cx="368.0953" cy="-162" rx="35.3489" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="368.0953" y="-157.8" font-family="Times,serif" font-size="14.00" fill="#000000">TarFS</text>
|
||||||
|
</g>
|
||||||
|
<!-- VFS->TarFS -->
|
||||||
|
<g id="edge47" class="edge">
|
||||||
|
<title>VFS->TarFS</title>
|
||||||
|
<path fill="none" stroke="#000000" d="M399.3789,-216.937C394.4978,-208.3654 388.4765,-197.7914 383.0242,-188.2165"/>
|
||||||
|
<polygon fill="#000000" stroke="#000000" points="386.0167,-186.3986 378.0268,-179.4407 379.9338,-189.8625 386.0167,-186.3986"/>
|
||||||
|
</g>
|
||||||
|
<!-- Ext2 -->
|
||||||
|
<g id="node48" class="node">
|
||||||
|
<title>Ext2</title>
|
||||||
|
<ellipse fill="none" stroke="#000000" cx="450.0953" cy="-162" rx="29.0548" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="450.0953" y="-157.8" font-family="Times,serif" font-size="14.00" fill="#000000">Ext2</text>
|
||||||
|
</g>
|
||||||
|
<!-- VFS->Ext2 -->
|
||||||
|
<g id="edge48" class="edge">
|
||||||
|
<title>VFS->Ext2</title>
|
||||||
|
<path fill="none" stroke="#000000" d="M418.8117,-216.937C423.6928,-208.3654 429.7141,-197.7914 435.1664,-188.2165"/>
|
||||||
|
<polygon fill="#000000" stroke="#000000" points="438.2568,-189.8625 440.1638,-179.4407 432.1739,-186.3986 438.2568,-189.8625"/>
|
||||||
|
</g>
|
||||||
|
<!-- Logger->VFS -->
|
||||||
|
<g id="edge28" class="edge">
|
||||||
|
<title>Logger->VFS</title>
|
||||||
|
<path fill="none" stroke="#000000" d="M460.5557,-289.3008C451.6839,-279.7669 440.4261,-267.6689 430.7037,-257.221"/>
|
||||||
|
<polygon fill="#000000" stroke="#000000" points="433.0079,-254.5593 423.6333,-249.6229 427.8834,-259.328 433.0079,-254.5593"/>
|
||||||
|
</g>
|
||||||
|
<!-- Serial -->
|
||||||
|
<g id="node29" class="node">
|
||||||
|
<title>Serial</title>
|
||||||
|
<ellipse fill="none" stroke="#000000" cx="1400.0953" cy="-234" rx="33.6208" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="1400.0953" y="-229.8" font-family="Times,serif" font-size="14.00" fill="#000000">Serial</text>
|
||||||
|
</g>
|
||||||
|
<!-- Logger->Serial -->
|
||||||
|
<g id="edge27" class="edge">
|
||||||
|
<title>Logger->Serial</title>
|
||||||
|
<path fill="none" stroke="#000000" d="M515.2345,-305.3369C663.9095,-302.5495 1193.4867,-290.1059 1357.0953,-252 1359.9033,-251.346 1362.7624,-250.5254 1365.6042,-249.5973"/>
|
||||||
|
<polygon fill="#000000" stroke="#000000" points="1366.9168,-252.844 1375.0991,-246.1134 1364.5054,-246.2724 1366.9168,-252.844"/>
|
||||||
|
</g>
|
||||||
|
<!-- TCP -->
|
||||||
|
<g id="node4" class="node">
|
||||||
|
<title>TCP</title>
|
||||||
|
<ellipse fill="none" stroke="#000000" cx="1436.0953" cy="-378" rx="28.991" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="1436.0953" y="-373.8" font-family="Times,serif" font-size="14.00" fill="#000000">TCP</text>
|
||||||
|
</g>
|
||||||
|
<!-- NetworkingStack -->
|
||||||
|
<g id="node5" class="node">
|
||||||
|
<title>NetworkingStack</title>
|
||||||
|
<ellipse fill="none" stroke="#000000" cx="1398.0953" cy="-306" rx="78.7318" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="1398.0953" y="-301.8" font-family="Times,serif" font-size="14.00" fill="#000000">NetworkingStack</text>
|
||||||
|
</g>
|
||||||
|
<!-- TCP->NetworkingStack -->
|
||||||
|
<g id="edge3" class="edge">
|
||||||
|
<title>TCP->NetworkingStack</title>
|
||||||
|
<path fill="none" stroke="#000000" d="M1426.8966,-360.5708C1422.5145,-352.2679 1417.1746,-342.1502 1412.2886,-332.8925"/>
|
||||||
|
<polygon fill="#000000" stroke="#000000" points="1415.3692,-331.2308 1407.6062,-324.0206 1409.1785,-334.4981 1415.3692,-331.2308"/>
|
||||||
|
</g>
|
||||||
|
<!-- PhysLayer -->
|
||||||
|
<g id="node7" class="node">
|
||||||
|
<title>PhysLayer</title>
|
||||||
|
<ellipse fill="none" stroke="#000000" cx="1296.0953" cy="-234" rx="52.1675" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="1296.0953" y="-229.8" font-family="Times,serif" font-size="14.00" fill="#000000">PhysLayer</text>
|
||||||
|
</g>
|
||||||
|
<!-- NetworkingStack->PhysLayer -->
|
||||||
|
<g id="edge5" class="edge">
|
||||||
|
<title>NetworkingStack->PhysLayer</title>
|
||||||
|
<path fill="none" stroke="#000000" d="M1373.6638,-288.7542C1359.8688,-279.0166 1342.4757,-266.7391 1327.6572,-256.279"/>
|
||||||
|
<polygon fill="#000000" stroke="#000000" points="1329.4647,-253.2707 1319.2765,-250.3632 1325.4278,-258.9895 1329.4647,-253.2707"/>
|
||||||
|
</g>
|
||||||
|
<!-- UDP -->
|
||||||
|
<g id="node6" class="node">
|
||||||
|
<title>UDP</title>
|
||||||
|
<ellipse fill="none" stroke="#000000" cx="1359.0953" cy="-378" rx="30.1958" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="1359.0953" y="-373.8" font-family="Times,serif" font-size="14.00" fill="#000000">UDP</text>
|
||||||
|
</g>
|
||||||
|
<!-- UDP->NetworkingStack -->
|
||||||
|
<g id="edge4" class="edge">
|
||||||
|
<title>UDP->NetworkingStack</title>
|
||||||
|
<path fill="none" stroke="#000000" d="M1368.5361,-360.5708C1373.0335,-352.2679 1378.5139,-342.1502 1383.5285,-332.8925"/>
|
||||||
|
<polygon fill="#000000" stroke="#000000" points="1386.6488,-334.4805 1388.3341,-324.0206 1380.4937,-331.1465 1386.6488,-334.4805"/>
|
||||||
|
</g>
|
||||||
|
<!-- Ethernet -->
|
||||||
|
<g id="node8" class="node">
|
||||||
|
<title>Ethernet</title>
|
||||||
|
<ellipse fill="none" stroke="#000000" cx="852.0953" cy="-162" rx="43.9983" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="852.0953" y="-157.8" font-family="Times,serif" font-size="14.00" fill="#000000">Ethernet</text>
|
||||||
|
</g>
|
||||||
|
<!-- PhysLayer->Ethernet -->
|
||||||
|
<g id="edge6" class="edge">
|
||||||
|
<title>PhysLayer->Ethernet</title>
|
||||||
|
<path fill="none" stroke="#000000" d="M1248.5795,-226.2947C1164.418,-212.6469 989.8747,-184.3426 903.2098,-170.2888"/>
|
||||||
|
<polygon fill="#000000" stroke="#000000" points="903.5198,-166.7935 893.0885,-168.6475 902.3993,-173.7032 903.5198,-166.7935"/>
|
||||||
|
</g>
|
||||||
|
<!-- Wifi -->
|
||||||
|
<g id="node16" class="node">
|
||||||
|
<title>Wifi</title>
|
||||||
|
<ellipse fill="none" stroke="#000000" cx="1314.0953" cy="-162" rx="28.9696" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="1314.0953" y="-157.8" font-family="Times,serif" font-size="14.00" fill="#000000">Wifi</text>
|
||||||
|
</g>
|
||||||
|
<!-- PhysLayer->Wifi -->
|
||||||
|
<g id="edge14" class="edge">
|
||||||
|
<title>PhysLayer->Wifi</title>
|
||||||
|
<path fill="none" stroke="#000000" d="M1300.6375,-215.8314C1302.6137,-207.9266 1304.9735,-198.4872 1307.1612,-189.7365"/>
|
||||||
|
<polygon fill="#000000" stroke="#000000" points="1310.587,-190.4637 1309.6169,-179.9134 1303.796,-188.7659 1310.587,-190.4637"/>
|
||||||
|
</g>
|
||||||
|
<!-- Threec90x -->
|
||||||
|
<g id="node9" class="node">
|
||||||
|
<title>Threec90x</title>
|
||||||
|
<ellipse fill="none" stroke="#000000" cx="452.0953" cy="-90" rx="52.1501" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="452.0953" y="-85.8" font-family="Times,serif" font-size="14.00" fill="#000000">Threec90x</text>
|
||||||
|
</g>
|
||||||
|
<!-- Ethernet->Threec90x -->
|
||||||
|
<g id="edge7" class="edge">
|
||||||
|
<title>Ethernet->Threec90x</title>
|
||||||
|
<path fill="none" stroke="#000000" d="M810.0127,-157.0708C745.598,-149.1277 618.8877,-131.9297 513.0953,-108 508.9759,-107.0682 504.7257,-106.013 500.4758,-104.8921"/>
|
||||||
|
<polygon fill="#000000" stroke="#000000" points="501.1913,-101.4591 490.6213,-102.1845 499.3366,-108.2089 501.1913,-101.4591"/>
|
||||||
|
</g>
|
||||||
|
<!-- Intel8254x -->
|
||||||
|
<g id="node10" class="node">
|
||||||
|
<title>Intel8254x</title>
|
||||||
|
<ellipse fill="none" stroke="#000000" cx="575.0953" cy="-90" rx="52.7527" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="575.0953" y="-85.8" font-family="Times,serif" font-size="14.00" fill="#000000">Intel8254x</text>
|
||||||
|
</g>
|
||||||
|
<!-- Ethernet->Intel8254x -->
|
||||||
|
<g id="edge8" class="edge">
|
||||||
|
<title>Ethernet->Intel8254x</title>
|
||||||
|
<path fill="none" stroke="#000000" d="M814.1219,-153.017C770.8839,-142.6703 698.1916,-124.9158 636.0953,-108 632.3083,-106.9684 628.3969,-105.8762 624.4686,-104.7602"/>
|
||||||
|
<polygon fill="#000000" stroke="#000000" points="625.3084,-101.3599 614.7304,-101.9578 623.3725,-108.0868 625.3084,-101.3599"/>
|
||||||
|
</g>
|
||||||
|
<!-- Ne2000 -->
|
||||||
|
<g id="node11" class="node">
|
||||||
|
<title>Ne2000</title>
|
||||||
|
<ellipse fill="none" stroke="#000000" cx="687.0953" cy="-90" rx="41.7172" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="687.0953" y="-85.8" font-family="Times,serif" font-size="14.00" fill="#000000">Ne2000</text>
|
||||||
|
</g>
|
||||||
|
<!-- Ethernet->Ne2000 -->
|
||||||
|
<g id="edge9" class="edge">
|
||||||
|
<title>Ethernet->Ne2000</title>
|
||||||
|
<path fill="none" stroke="#000000" d="M821.8318,-148.7941C794.9169,-137.0494 755.4014,-119.8063 726.1176,-107.0279"/>
|
||||||
|
<polygon fill="#000000" stroke="#000000" points="727.1771,-103.6716 716.6118,-102.8799 724.3774,-110.0873 727.1771,-103.6716"/>
|
||||||
|
</g>
|
||||||
|
<!-- RTL8139 -->
|
||||||
|
<g id="node12" class="node">
|
||||||
|
<title>RTL8139</title>
|
||||||
|
<ellipse fill="none" stroke="#000000" cx="795.0953" cy="-90" rx="48.6791" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="795.0953" y="-85.8" font-family="Times,serif" font-size="14.00" fill="#000000">RTL8139</text>
|
||||||
|
</g>
|
||||||
|
<!-- Ethernet->RTL8139 -->
|
||||||
|
<g id="edge10" class="edge">
|
||||||
|
<title>Ethernet->RTL8139</title>
|
||||||
|
<path fill="none" stroke="#000000" d="M838.2972,-144.5708C831.4167,-135.8797 822.962,-125.2001 815.3618,-115.5998"/>
|
||||||
|
<polygon fill="#000000" stroke="#000000" points="817.9151,-113.1862 808.9639,-107.5182 812.4268,-117.5312 817.9151,-113.1862"/>
|
||||||
|
</g>
|
||||||
|
<!-- RTL8169 -->
|
||||||
|
<g id="node13" class="node">
|
||||||
|
<title>RTL8169</title>
|
||||||
|
<ellipse fill="none" stroke="#000000" cx="910.0953" cy="-90" rx="48.6791" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="910.0953" y="-85.8" font-family="Times,serif" font-size="14.00" fill="#000000">RTL8169</text>
|
||||||
|
</g>
|
||||||
|
<!-- Ethernet->RTL8169 -->
|
||||||
|
<g id="edge11" class="edge">
|
||||||
|
<title>Ethernet->RTL8169</title>
|
||||||
|
<path fill="none" stroke="#000000" d="M866.1355,-144.5708C873.2597,-135.7269 882.0427,-124.8239 889.8803,-115.0945"/>
|
||||||
|
<polygon fill="#000000" stroke="#000000" points="892.6367,-117.2519 896.1844,-107.2687 887.1854,-112.8606 892.6367,-117.2519"/>
|
||||||
|
</g>
|
||||||
|
<!-- IntelEtherneti217 -->
|
||||||
|
<g id="node14" class="node">
|
||||||
|
<title>IntelEtherneti217</title>
|
||||||
|
<ellipse fill="none" stroke="#000000" cx="1055.0953" cy="-90" rx="78.7298" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="1055.0953" y="-85.8" font-family="Times,serif" font-size="14.00" fill="#000000">IntelEtherneti217</text>
|
||||||
|
</g>
|
||||||
|
<!-- Ethernet->IntelEtherneti217 -->
|
||||||
|
<g id="edge12" class="edge">
|
||||||
|
<title>Ethernet->IntelEtherneti217</title>
|
||||||
|
<path fill="none" stroke="#000000" d="M885.6166,-150.1107C917.4561,-138.8178 965.8122,-121.6669 1002.7343,-108.5714"/>
|
||||||
|
<polygon fill="#000000" stroke="#000000" points="1004.084,-111.8064 1012.3387,-105.1649 1001.744,-105.2091 1004.084,-111.8064"/>
|
||||||
|
</g>
|
||||||
|
<!-- AMDPCnet -->
|
||||||
|
<g id="node15" class="node">
|
||||||
|
<title>AMDPCnet</title>
|
||||||
|
<ellipse fill="none" stroke="#000000" cx="1209.0953" cy="-90" rx="57.3418" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="1209.0953" y="-85.8" font-family="Times,serif" font-size="14.00" fill="#000000">AMDPCnet</text>
|
||||||
|
</g>
|
||||||
|
<!-- Ethernet->AMDPCnet -->
|
||||||
|
<g id="edge13" class="edge">
|
||||||
|
<title>Ethernet->AMDPCnet</title>
|
||||||
|
<path fill="none" stroke="#000000" d="M893.2785,-155.4619C949.8599,-146.2284 1054.687,-128.222 1143.0953,-108 1147.513,-106.9895 1152.0799,-105.8804 1156.6536,-104.7245"/>
|
||||||
|
<polygon fill="#000000" stroke="#000000" points="1157.8203,-108.0378 1166.6214,-102.1393 1156.063,-101.2619 1157.8203,-108.0378"/>
|
||||||
|
</g>
|
||||||
|
<!-- Eight02Dot11 -->
|
||||||
|
<g id="node17" class="node">
|
||||||
|
<title>Eight02Dot11</title>
|
||||||
|
<ellipse fill="none" stroke="#000000" cx="1350.0953" cy="-90" rx="65.5161" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="1350.0953" y="-85.8" font-family="Times,serif" font-size="14.00" fill="#000000">Eight02Dot11</text>
|
||||||
|
</g>
|
||||||
|
<!-- Wifi->Eight02Dot11 -->
|
||||||
|
<g id="edge15" class="edge">
|
||||||
|
<title>Wifi->Eight02Dot11</title>
|
||||||
|
<path fill="none" stroke="#000000" d="M1322.8099,-144.5708C1326.9181,-136.3544 1331.9149,-126.3608 1336.5042,-117.1821"/>
|
||||||
|
<polygon fill="#000000" stroke="#000000" points="1339.7433,-118.5301 1341.085,-108.0206 1333.4823,-115.3996 1339.7433,-118.5301"/>
|
||||||
|
</g>
|
||||||
|
<!-- Audio -->
|
||||||
|
<g id="node18" class="node">
|
||||||
|
<title>Audio</title>
|
||||||
|
<ellipse fill="none" stroke="#000000" cx="2420.0953" cy="-378" rx="35.3548" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="2420.0953" y="-373.8" font-family="Times,serif" font-size="14.00" fill="#000000">Audio</text>
|
||||||
|
</g>
|
||||||
|
<!-- PCSpeaker -->
|
||||||
|
<g id="node19" class="node">
|
||||||
|
<title>PCSpeaker</title>
|
||||||
|
<ellipse fill="none" stroke="#000000" cx="2348.0953" cy="-306" rx="53.8905" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="2348.0953" y="-301.8" font-family="Times,serif" font-size="14.00" fill="#000000">PCSpeaker</text>
|
||||||
|
</g>
|
||||||
|
<!-- Audio->PCSpeaker -->
|
||||||
|
<g id="edge16" class="edge">
|
||||||
|
<title>Audio->PCSpeaker</title>
|
||||||
|
<path fill="none" stroke="#000000" d="M2403.7574,-361.6621C2394.5427,-352.4474 2382.8487,-340.7534 2372.5602,-330.4649"/>
|
||||||
|
<polygon fill="#000000" stroke="#000000" points="2374.9186,-327.8735 2365.3726,-323.2773 2369.9688,-332.8233 2374.9186,-327.8735"/>
|
||||||
|
</g>
|
||||||
|
<!-- SoundBlaster16 -->
|
||||||
|
<g id="node20" class="node">
|
||||||
|
<title>SoundBlaster16</title>
|
||||||
|
<ellipse fill="none" stroke="#000000" cx="2493.0953" cy="-306" rx="72.9547" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="2493.0953" y="-301.8" font-family="Times,serif" font-size="14.00" fill="#000000">SoundBlaster16</text>
|
||||||
|
</g>
|
||||||
|
<!-- Audio->SoundBlaster16 -->
|
||||||
|
<g id="edge17" class="edge">
|
||||||
|
<title>Audio->SoundBlaster16</title>
|
||||||
|
<path fill="none" stroke="#000000" d="M2436.2964,-362.0209C2445.5577,-352.8864 2457.3757,-341.2303 2467.8308,-330.9184"/>
|
||||||
|
<polygon fill="#000000" stroke="#000000" points="2470.485,-333.2166 2475.1469,-323.7025 2465.5695,-328.2328 2470.485,-333.2166"/>
|
||||||
|
</g>
|
||||||
|
<!-- RNG -->
|
||||||
|
<g id="node21" class="node">
|
||||||
|
<title>RNG</title>
|
||||||
|
<ellipse fill="none" stroke="#000000" cx="1676.0953" cy="-378" rx="31.339" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="1676.0953" y="-373.8" font-family="Times,serif" font-size="14.00" fill="#000000">RNG</text>
|
||||||
|
</g>
|
||||||
|
<!-- RNG->NetworkingStack -->
|
||||||
|
<g id="edge19" class="edge">
|
||||||
|
<title>RNG->NetworkingStack</title>
|
||||||
|
<path fill="none" stroke="#000000" d="M1647.3915,-370.5659C1603.4593,-359.1878 1518.5016,-337.1844 1460.0749,-322.0523"/>
|
||||||
|
<polygon fill="#000000" stroke="#000000" points="1460.7723,-318.6175 1450.2142,-319.4984 1459.0172,-325.3939 1460.7723,-318.6175"/>
|
||||||
|
</g>
|
||||||
|
<!-- CpuRNG -->
|
||||||
|
<g id="node22" class="node">
|
||||||
|
<title>CpuRNG</title>
|
||||||
|
<ellipse fill="none" stroke="#000000" cx="1725.0953" cy="-306" rx="47.5332" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="1725.0953" y="-301.8" font-family="Times,serif" font-size="14.00" fill="#000000">CpuRNG</text>
|
||||||
|
</g>
|
||||||
|
<!-- RNG->CpuRNG -->
|
||||||
|
<g id="edge18" class="edge">
|
||||||
|
<title>RNG->CpuRNG</title>
|
||||||
|
<path fill="none" stroke="#000000" d="M1687.7076,-360.937C1693.6012,-352.277 1700.8858,-341.5731 1707.4548,-331.9207"/>
|
||||||
|
<polygon fill="#000000" stroke="#000000" points="1710.4932,-333.677 1713.2259,-323.4407 1704.7062,-329.7386 1710.4932,-333.677"/>
|
||||||
|
</g>
|
||||||
|
<!-- GraphicsLibrary -->
|
||||||
|
<g id="node23" class="node">
|
||||||
|
<title>GraphicsLibrary</title>
|
||||||
|
<ellipse fill="none" stroke="#000000" cx="2201.0953" cy="-306" rx="74.6976" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="2201.0953" y="-301.8" font-family="Times,serif" font-size="14.00" fill="#000000">GraphicsLibrary</text>
|
||||||
|
</g>
|
||||||
|
<!-- RNG->GraphicsLibrary -->
|
||||||
|
<g id="edge20" class="edge">
|
||||||
|
<title>RNG->GraphicsLibrary</title>
|
||||||
|
<path fill="none" stroke="#000000" d="M1706.9764,-373.7649C1788.0277,-362.6493 2008.637,-332.3943 2125.7369,-316.3349"/>
|
||||||
|
<polygon fill="#000000" stroke="#000000" points="2126.2743,-319.794 2135.706,-314.9677 2125.3232,-312.8589 2126.2743,-319.794"/>
|
||||||
|
</g>
|
||||||
|
<!-- Input -->
|
||||||
|
<g id="node24" class="node">
|
||||||
|
<title>Input</title>
|
||||||
|
<ellipse fill="none" stroke="#000000" cx="1628.0953" cy="-306" rx="31.341" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="1628.0953" y="-301.8" font-family="Times,serif" font-size="14.00" fill="#000000">Input</text>
|
||||||
|
</g>
|
||||||
|
<!-- RNG->Input -->
|
||||||
|
<g id="edge21" class="edge">
|
||||||
|
<title>RNG->Input</title>
|
||||||
|
<path fill="none" stroke="#000000" d="M1664.72,-360.937C1658.8617,-352.1496 1651.6005,-341.2579 1645.0924,-331.4956"/>
|
||||||
|
<polygon fill="#000000" stroke="#000000" points="1647.8482,-329.3196 1639.389,-322.9405 1642.0238,-333.2025 1647.8482,-329.3196"/>
|
||||||
|
</g>
|
||||||
|
<!-- ShaderCompiler -->
|
||||||
|
<g id="node26" class="node">
|
||||||
|
<title>ShaderCompiler</title>
|
||||||
|
<ellipse fill="none" stroke="#000000" cx="2303.0953" cy="-234" rx="74.1566" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="2303.0953" y="-229.8" font-family="Times,serif" font-size="14.00" fill="#000000">ShaderCompiler</text>
|
||||||
|
</g>
|
||||||
|
<!-- GraphicsLibrary->ShaderCompiler -->
|
||||||
|
<g id="edge23" class="edge">
|
||||||
|
<title>GraphicsLibrary->ShaderCompiler</title>
|
||||||
|
<path fill="none" stroke="#000000" d="M2225.2679,-288.937C2238.7614,-279.4122 2255.7576,-267.4149 2270.4221,-257.0635"/>
|
||||||
|
<polygon fill="#000000" stroke="#000000" points="2272.5915,-259.8163 2278.7427,-251.19 2268.5546,-254.0975 2272.5915,-259.8163"/>
|
||||||
|
</g>
|
||||||
|
<!-- GraphicsDriver -->
|
||||||
|
<g id="node27" class="node">
|
||||||
|
<title>GraphicsDriver</title>
|
||||||
|
<ellipse fill="none" stroke="#000000" cx="2303.0953" cy="-162" rx="71.1843" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="2303.0953" y="-157.8" font-family="Times,serif" font-size="14.00" fill="#000000">GraphicsDriver</text>
|
||||||
|
</g>
|
||||||
|
<!-- GraphicsLibrary->GraphicsDriver -->
|
||||||
|
<g id="edge25" class="edge">
|
||||||
|
<title>GraphicsLibrary->GraphicsDriver</title>
|
||||||
|
<path fill="none" stroke="#000000" d="M2200.955,-287.8528C2201.653,-268.4612 2205.2852,-237.6002 2220.0953,-216 2229.5949,-202.1451 2243.9358,-190.9993 2258.0378,-182.5131"/>
|
||||||
|
<polygon fill="#000000" stroke="#000000" points="2259.7731,-185.5528 2266.7421,-177.5726 2256.3176,-179.4651 2259.7731,-185.5528"/>
|
||||||
|
</g>
|
||||||
|
<!-- Input->Serial -->
|
||||||
|
<g id="edge32" class="edge">
|
||||||
|
<title>Input->Serial</title>
|
||||||
|
<path fill="none" stroke="#000000" d="M1599.2541,-298.6597C1562.5858,-289.0822 1497.5027,-271.2595 1443.0953,-252 1440.6921,-251.1493 1438.2293,-250.2354 1435.758,-249.2868"/>
|
||||||
|
<polygon fill="#000000" stroke="#000000" points="1436.8768,-245.9651 1426.2915,-245.5159 1434.2863,-252.4682 1436.8768,-245.9651"/>
|
||||||
|
</g>
|
||||||
|
<!-- Keyboard -->
|
||||||
|
<g id="node30" class="node">
|
||||||
|
<title>Keyboard</title>
|
||||||
|
<ellipse fill="none" stroke="#000000" cx="1628.0953" cy="-234" rx="49.2202" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="1628.0953" y="-229.8" font-family="Times,serif" font-size="14.00" fill="#000000">Keyboard</text>
|
||||||
|
</g>
|
||||||
|
<!-- Input->Keyboard -->
|
||||||
|
<g id="edge29" class="edge">
|
||||||
|
<title>Input->Keyboard</title>
|
||||||
|
<path fill="none" stroke="#000000" d="M1628.0953,-287.8314C1628.0953,-280.131 1628.0953,-270.9743 1628.0953,-262.4166"/>
|
||||||
|
<polygon fill="#000000" stroke="#000000" points="1631.5954,-262.4132 1628.0953,-252.4133 1624.5954,-262.4133 1631.5954,-262.4132"/>
|
||||||
|
</g>
|
||||||
|
<!-- GraphicsTablet -->
|
||||||
|
<g id="node31" class="node">
|
||||||
|
<title>GraphicsTablet</title>
|
||||||
|
<ellipse fill="none" stroke="#000000" cx="1766.0953" cy="-234" rx="70.622" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="1766.0953" y="-229.8" font-family="Times,serif" font-size="14.00" fill="#000000">GraphicsTablet</text>
|
||||||
|
</g>
|
||||||
|
<!-- Input->GraphicsTablet -->
|
||||||
|
<g id="edge30" class="edge">
|
||||||
|
<title>Input->GraphicsTablet</title>
|
||||||
|
<path fill="none" stroke="#000000" d="M1651.5051,-293.7862C1671.8931,-283.149 1701.8932,-267.4967 1726.0835,-254.8757"/>
|
||||||
|
<polygon fill="#000000" stroke="#000000" points="1727.7912,-257.9325 1735.0381,-250.2038 1724.5532,-251.7264 1727.7912,-257.9325"/>
|
||||||
|
</g>
|
||||||
|
<!-- Mouse -->
|
||||||
|
<g id="node32" class="node">
|
||||||
|
<title>Mouse</title>
|
||||||
|
<ellipse fill="none" stroke="#000000" cx="1892.0953" cy="-234" rx="37.1405" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="1892.0953" y="-229.8" font-family="Times,serif" font-size="14.00" fill="#000000">Mouse</text>
|
||||||
|
</g>
|
||||||
|
<!-- Input->Mouse -->
|
||||||
|
<g id="edge31" class="edge">
|
||||||
|
<title>Input->Mouse</title>
|
||||||
|
<path fill="none" stroke="#000000" d="M1652.2936,-294.0726C1657.4281,-291.8373 1662.8757,-289.6789 1668.0953,-288 1744.9312,-263.2853 1768.6672,-274.7915 1846.0953,-252 1848.7047,-251.2319 1851.3737,-250.3778 1854.0474,-249.4708"/>
|
||||||
|
<polygon fill="#000000" stroke="#000000" points="1855.4284,-252.6936 1863.6524,-246.014 1853.058,-246.1072 1855.4284,-252.6936"/>
|
||||||
|
</g>
|
||||||
|
<!-- Controllers -->
|
||||||
|
<g id="node33" class="node">
|
||||||
|
<title>Controllers</title>
|
||||||
|
<ellipse fill="none" stroke="#000000" cx="1506.0953" cy="-234" rx="54.4701" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="1506.0953" y="-229.8" font-family="Times,serif" font-size="14.00" fill="#000000">Controllers</text>
|
||||||
|
</g>
|
||||||
|
<!-- Input->Controllers -->
|
||||||
|
<g id="edge33" class="edge">
|
||||||
|
<title>Input->Controllers</title>
|
||||||
|
<path fill="none" stroke="#000000" d="M1606.002,-292.9613C1588.1773,-282.4418 1562.7456,-267.433 1542.0025,-255.1911"/>
|
||||||
|
<polygon fill="#000000" stroke="#000000" points="1543.5325,-252.03 1533.1415,-249.9617 1539.9747,-258.0585 1543.5325,-252.03"/>
|
||||||
|
</g>
|
||||||
|
<!-- Slint -->
|
||||||
|
<g id="node25" class="node">
|
||||||
|
<title>Slint</title>
|
||||||
|
<ellipse fill="none" stroke="#000000" cx="2201.0953" cy="-378" rx="29.0701" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="2201.0953" y="-373.8" font-family="Times,serif" font-size="14.00" fill="#000000">Slint</text>
|
||||||
|
</g>
|
||||||
|
<!-- Slint->GraphicsLibrary -->
|
||||||
|
<g id="edge22" class="edge">
|
||||||
|
<title>Slint->GraphicsLibrary</title>
|
||||||
|
<path fill="none" stroke="#000000" d="M2201.0953,-359.8314C2201.0953,-352.131 2201.0953,-342.9743 2201.0953,-334.4166"/>
|
||||||
|
<polygon fill="#000000" stroke="#000000" points="2204.5954,-334.4132 2201.0953,-324.4133 2197.5954,-334.4133 2204.5954,-334.4132"/>
|
||||||
|
</g>
|
||||||
|
<!-- ShaderCompiler->GraphicsDriver -->
|
||||||
|
<g id="edge24" class="edge">
|
||||||
|
<title>ShaderCompiler->GraphicsDriver</title>
|
||||||
|
<path fill="none" stroke="#000000" d="M2303.0953,-215.8314C2303.0953,-208.131 2303.0953,-198.9743 2303.0953,-190.4166"/>
|
||||||
|
<polygon fill="#000000" stroke="#000000" points="2306.5954,-190.4132 2303.0953,-180.4133 2299.5954,-190.4133 2306.5954,-190.4132"/>
|
||||||
|
</g>
|
||||||
|
<!-- GPU -->
|
||||||
|
<g id="node28" class="node">
|
||||||
|
<title>GPU</title>
|
||||||
|
<ellipse fill="none" stroke="#000000" cx="2303.0953" cy="-90" rx="30.1958" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="2303.0953" y="-85.8" font-family="Times,serif" font-size="14.00" fill="#000000">GPU</text>
|
||||||
|
</g>
|
||||||
|
<!-- GraphicsDriver->GPU -->
|
||||||
|
<g id="edge26" class="edge">
|
||||||
|
<title>GraphicsDriver->GPU</title>
|
||||||
|
<path fill="none" stroke="#000000" d="M2303.0953,-143.8314C2303.0953,-136.131 2303.0953,-126.9743 2303.0953,-118.4166"/>
|
||||||
|
<polygon fill="#000000" stroke="#000000" points="2306.5954,-118.4132 2303.0953,-108.4133 2299.5954,-118.4133 2306.5954,-118.4132"/>
|
||||||
|
</g>
|
||||||
|
<!-- PS2Mouse -->
|
||||||
|
<g id="node41" class="node">
|
||||||
|
<title>PS2Mouse</title>
|
||||||
|
<ellipse fill="none" stroke="#000000" cx="2161.0953" cy="-162" rx="52.77" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="2161.0953" y="-157.8" font-family="Times,serif" font-size="14.00" fill="#000000">PS2Mouse</text>
|
||||||
|
</g>
|
||||||
|
<!-- Mouse->PS2Mouse -->
|
||||||
|
<g id="edge41" class="edge">
|
||||||
|
<title>Mouse->PS2Mouse</title>
|
||||||
|
<path fill="none" stroke="#000000" d="M1925.5125,-225.5822C1966.4961,-215.1894 2038.0464,-196.8215 2099.0953,-180 2102.9364,-178.9416 2106.9061,-177.8301 2110.8948,-176.7007"/>
|
||||||
|
<polygon fill="#000000" stroke="#000000" points="2112.1314,-179.9875 2120.786,-173.8761 2110.2093,-173.2566 2112.1314,-179.9875"/>
|
||||||
|
</g>
|
||||||
|
<!-- USBMouse -->
|
||||||
|
<g id="node42" class="node">
|
||||||
|
<title>USBMouse</title>
|
||||||
|
<ellipse fill="none" stroke="#000000" cx="1689.0953" cy="-162" rx="56.1995" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="1689.0953" y="-157.8" font-family="Times,serif" font-size="14.00" fill="#000000">USBMouse</text>
|
||||||
|
</g>
|
||||||
|
<!-- Mouse->USBMouse -->
|
||||||
|
<g id="edge42" class="edge">
|
||||||
|
<title>Mouse->USBMouse</title>
|
||||||
|
<path fill="none" stroke="#000000" d="M1862.9639,-222.3895C1857.3804,-220.2241 1851.569,-218.0113 1846.0953,-216 1810.0856,-202.7684 1769.0818,-188.6989 1738.0104,-178.2392"/>
|
||||||
|
<polygon fill="#000000" stroke="#000000" points="1738.8841,-174.8407 1728.2902,-174.9757 1736.6561,-181.4766 1738.8841,-174.8407"/>
|
||||||
|
</g>
|
||||||
|
<!-- MouseTrackPad -->
|
||||||
|
<g id="node44" class="node">
|
||||||
|
<title>MouseTrackPad</title>
|
||||||
|
<ellipse fill="none" stroke="#000000" cx="1837.0953" cy="-162" rx="74.1393" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="1837.0953" y="-157.8" font-family="Times,serif" font-size="14.00" fill="#000000">MouseTrackPad</text>
|
||||||
|
</g>
|
||||||
|
<!-- Mouse->MouseTrackPad -->
|
||||||
|
<g id="edge44" class="edge">
|
||||||
|
<title>Mouse->MouseTrackPad</title>
|
||||||
|
<path fill="none" stroke="#000000" d="M1879.0611,-216.937C1872.4765,-208.3173 1864.3453,-197.6727 1856.9988,-188.0555"/>
|
||||||
|
<polygon fill="#000000" stroke="#000000" points="1859.6553,-185.7673 1850.8035,-179.9453 1854.0926,-190.0166 1859.6553,-185.7673"/>
|
||||||
|
</g>
|
||||||
|
<!-- MouseTrackPoint -->
|
||||||
|
<g id="node45" class="node">
|
||||||
|
<title>MouseTrackPoint</title>
|
||||||
|
<ellipse fill="none" stroke="#000000" cx="2010.0953" cy="-162" rx="80.4577" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="2010.0953" y="-157.8" font-family="Times,serif" font-size="14.00" fill="#000000">MouseTrackPoint</text>
|
||||||
|
</g>
|
||||||
|
<!-- Mouse->MouseTrackPoint -->
|
||||||
|
<g id="edge45" class="edge">
|
||||||
|
<title>Mouse->MouseTrackPoint</title>
|
||||||
|
<path fill="none" stroke="#000000" d="M1915.4083,-219.7751C1931.9914,-209.6566 1954.5994,-195.8619 1973.5655,-184.2894"/>
|
||||||
|
<polygon fill="#000000" stroke="#000000" points="1975.5507,-187.1782 1982.264,-178.9818 1971.9046,-181.2027 1975.5507,-187.1782"/>
|
||||||
|
</g>
|
||||||
|
<!-- Playstation -->
|
||||||
|
<g id="node34" class="node">
|
||||||
|
<title>Playstation</title>
|
||||||
|
<ellipse fill="none" stroke="#000000" cx="1506.0953" cy="-162" rx="53.9078" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="1506.0953" y="-157.8" font-family="Times,serif" font-size="14.00" fill="#000000">Playstation</text>
|
||||||
|
</g>
|
||||||
|
<!-- Controllers->Playstation -->
|
||||||
|
<g id="edge34" class="edge">
|
||||||
|
<title>Controllers->Playstation</title>
|
||||||
|
<path fill="none" stroke="#000000" d="M1506.0953,-215.8314C1506.0953,-208.131 1506.0953,-198.9743 1506.0953,-190.4166"/>
|
||||||
|
<polygon fill="#000000" stroke="#000000" points="1509.5954,-190.4132 1506.0953,-180.4133 1502.5954,-190.4133 1509.5954,-190.4132"/>
|
||||||
|
</g>
|
||||||
|
<!-- DualShock -->
|
||||||
|
<g id="node35" class="node">
|
||||||
|
<title>DualShock</title>
|
||||||
|
<ellipse fill="none" stroke="#000000" cx="1488.0953" cy="-90" rx="53.8943" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="1488.0953" y="-85.8" font-family="Times,serif" font-size="14.00" fill="#000000">DualShock</text>
|
||||||
|
</g>
|
||||||
|
<!-- Playstation->DualShock -->
|
||||||
|
<g id="edge35" class="edge">
|
||||||
|
<title>Playstation->DualShock</title>
|
||||||
|
<path fill="none" stroke="#000000" d="M1501.5531,-143.8314C1499.6069,-136.0463 1497.2885,-126.7729 1495.129,-118.1347"/>
|
||||||
|
<polygon fill="#000000" stroke="#000000" points="1498.5195,-117.2658 1492.6986,-108.4133 1491.7285,-118.9636 1498.5195,-117.2658"/>
|
||||||
|
</g>
|
||||||
|
<!-- DualSense -->
|
||||||
|
<g id="node36" class="node">
|
||||||
|
<title>DualSense</title>
|
||||||
|
<ellipse fill="none" stroke="#000000" cx="1612.0953" cy="-90" rx="52.1655" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="1612.0953" y="-85.8" font-family="Times,serif" font-size="14.00" fill="#000000">DualSense</text>
|
||||||
|
</g>
|
||||||
|
<!-- Playstation->DualSense -->
|
||||||
|
<g id="edge36" class="edge">
|
||||||
|
<title>Playstation->DualSense</title>
|
||||||
|
<path fill="none" stroke="#000000" d="M1529.8838,-145.8418C1544.6134,-135.8368 1563.7207,-122.8582 1579.8071,-111.9316"/>
|
||||||
|
<polygon fill="#000000" stroke="#000000" points="1582.0806,-114.6184 1588.3862,-106.1043 1578.1474,-108.8279 1582.0806,-114.6184"/>
|
||||||
|
</g>
|
||||||
|
<!-- DualShock1 -->
|
||||||
|
<g id="node37" class="node">
|
||||||
|
<title>DualShock1</title>
|
||||||
|
<ellipse fill="none" stroke="#000000" cx="1420.0953" cy="-18" rx="58.5521" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="1420.0953" y="-13.8" font-family="Times,serif" font-size="14.00" fill="#000000">DualShock1</text>
|
||||||
|
</g>
|
||||||
|
<!-- DualShock->DualShock1 -->
|
||||||
|
<g id="edge37" class="edge">
|
||||||
|
<title>DualShock->DualShock1</title>
|
||||||
|
<path fill="none" stroke="#000000" d="M1471.6344,-72.5708C1463.2603,-63.7041 1452.9315,-52.7678 1443.7247,-43.0194"/>
|
||||||
|
<polygon fill="#000000" stroke="#000000" points="1446.0511,-40.3852 1436.6403,-35.5182 1440.962,-45.1916 1446.0511,-40.3852"/>
|
||||||
|
</g>
|
||||||
|
<!-- DualShock2 -->
|
||||||
|
<g id="node38" class="node">
|
||||||
|
<title>DualShock2</title>
|
||||||
|
<ellipse fill="none" stroke="#000000" cx="1556.0953" cy="-18" rx="58.5521" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="1556.0953" y="-13.8" font-family="Times,serif" font-size="14.00" fill="#000000">DualShock2</text>
|
||||||
|
</g>
|
||||||
|
<!-- DualShock->DualShock2 -->
|
||||||
|
<g id="edge38" class="edge">
|
||||||
|
<title>DualShock->DualShock2</title>
|
||||||
|
<path fill="none" stroke="#000000" d="M1504.5562,-72.5708C1512.9303,-63.7041 1523.2591,-52.7678 1532.4659,-43.0194"/>
|
||||||
|
<polygon fill="#000000" stroke="#000000" points="1535.2286,-45.1916 1539.5503,-35.5182 1530.1395,-40.3852 1535.2286,-45.1916"/>
|
||||||
|
</g>
|
||||||
|
<!-- DualShock3 -->
|
||||||
|
<g id="node39" class="node">
|
||||||
|
<title>DualShock3</title>
|
||||||
|
<ellipse fill="none" stroke="#000000" cx="1692.0953" cy="-18" rx="58.5521" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="1692.0953" y="-13.8" font-family="Times,serif" font-size="14.00" fill="#000000">DualShock3</text>
|
||||||
|
</g>
|
||||||
|
<!-- DualShock->DualShock3 -->
|
||||||
|
<g id="edge39" class="edge">
|
||||||
|
<title>DualShock->DualShock3</title>
|
||||||
|
<path fill="none" stroke="#000000" d="M1525.512,-76.7941C1558.7364,-65.0678 1607.4912,-47.8603 1643.6793,-35.088"/>
|
||||||
|
<polygon fill="#000000" stroke="#000000" points="1645.2646,-38.2401 1653.5296,-31.6114 1642.9348,-31.6392 1645.2646,-38.2401"/>
|
||||||
|
</g>
|
||||||
|
<!-- DualShock4 -->
|
||||||
|
<g id="node40" class="node">
|
||||||
|
<title>DualShock4</title>
|
||||||
|
<ellipse fill="none" stroke="#000000" cx="1284.0953" cy="-18" rx="58.5521" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="1284.0953" y="-13.8" font-family="Times,serif" font-size="14.00" fill="#000000">DualShock4</text>
|
||||||
|
</g>
|
||||||
|
<!-- DualShock->DualShock4 -->
|
||||||
|
<g id="edge40" class="edge">
|
||||||
|
<title>DualShock->DualShock4</title>
|
||||||
|
<path fill="none" stroke="#000000" d="M1450.6786,-76.7941C1417.4541,-65.0678 1368.6994,-47.8603 1332.5113,-35.088"/>
|
||||||
|
<polygon fill="#000000" stroke="#000000" points="1333.2558,-31.6392 1322.661,-31.6114 1330.926,-38.2401 1333.2558,-31.6392"/>
|
||||||
|
</g>
|
||||||
|
<!-- GenericUSBMouse -->
|
||||||
|
<g id="node43" class="node">
|
||||||
|
<title>GenericUSBMouse</title>
|
||||||
|
<ellipse fill="none" stroke="#000000" cx="1769.0953" cy="-90" rx="86.8165" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="1769.0953" y="-85.8" font-family="Times,serif" font-size="14.00" fill="#000000">GenericUSBMouse</text>
|
||||||
|
</g>
|
||||||
|
<!-- USBMouse->GenericUSBMouse -->
|
||||||
|
<g id="edge43" class="edge">
|
||||||
|
<title>USBMouse->GenericUSBMouse</title>
|
||||||
|
<path fill="none" stroke="#000000" d="M1708.0542,-144.937C1718.1905,-135.8144 1730.8468,-124.4237 1742.0028,-114.3833"/>
|
||||||
|
<polygon fill="#000000" stroke="#000000" points="1744.3455,-116.9836 1749.4371,-107.6924 1739.6627,-111.7806 1744.3455,-116.9836"/>
|
||||||
|
</g>
|
||||||
|
<!-- VirtualDisk -->
|
||||||
|
<g id="node49" class="node">
|
||||||
|
<title>VirtualDisk</title>
|
||||||
|
<ellipse fill="none" stroke="#000000" cx="325.0953" cy="-90" rx="56.7561" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="325.0953" y="-85.8" font-family="Times,serif" font-size="14.00" fill="#000000">VirtualDisk</text>
|
||||||
|
</g>
|
||||||
|
<!-- Fat32->VirtualDisk -->
|
||||||
|
<g id="edge51" class="edge">
|
||||||
|
<title>Fat32->VirtualDisk</title>
|
||||||
|
<path fill="none" stroke="#000000" d="M292.5044,-144.5708C297.5524,-136.1184 303.7236,-125.7851 309.3328,-116.3931"/>
|
||||||
|
<polygon fill="#000000" stroke="#000000" points="312.3608,-118.1489 314.4833,-107.7689 306.351,-114.5597 312.3608,-118.1489"/>
|
||||||
|
</g>
|
||||||
|
<!-- TarFS->VirtualDisk -->
|
||||||
|
<g id="edge50" class="edge">
|
||||||
|
<title>TarFS->VirtualDisk</title>
|
||||||
|
<path fill="none" stroke="#000000" d="M357.6862,-144.5708C352.6382,-136.1184 346.467,-125.7851 340.8578,-116.3931"/>
|
||||||
|
<polygon fill="#000000" stroke="#000000" points="343.8396,-114.5597 335.7073,-107.7689 337.8298,-118.1489 343.8396,-114.5597"/>
|
||||||
|
</g>
|
||||||
|
<!-- Ext2->VirtualDisk -->
|
||||||
|
<g id="edge49" class="edge">
|
||||||
|
<title>Ext2->VirtualDisk</title>
|
||||||
|
<path fill="none" stroke="#000000" d="M428.607,-149.6228C410.2018,-139.0214 383.3012,-123.5266 361.5364,-110.9901"/>
|
||||||
|
<polygon fill="#000000" stroke="#000000" points="363.2806,-107.9557 352.8684,-105.9973 359.7868,-114.0214 363.2806,-107.9557"/>
|
||||||
|
</g>
|
||||||
|
<!-- IDEDiskDriver -->
|
||||||
|
<g id="node50" class="node">
|
||||||
|
<title>IDEDiskDriver</title>
|
||||||
|
<ellipse fill="none" stroke="#000000" cx="453.0953" cy="-18" rx="70.622" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="453.0953" y="-13.8" font-family="Times,serif" font-size="14.00" fill="#000000">IDEDiskDriver</text>
|
||||||
|
</g>
|
||||||
|
<!-- VirtualDisk->IDEDiskDriver -->
|
||||||
|
<g id="edge52" class="edge">
|
||||||
|
<title>VirtualDisk->IDEDiskDriver</title>
|
||||||
|
<path fill="none" stroke="#000000" d="M353.1854,-74.1993C371.3097,-64.0044 395.1147,-50.6141 414.9419,-39.4613"/>
|
||||||
|
<polygon fill="#000000" stroke="#000000" points="416.7372,-42.4672 423.737,-34.514 413.3053,-36.3662 416.7372,-42.4672"/>
|
||||||
|
</g>
|
||||||
|
<!-- ATADiskDriver -->
|
||||||
|
<g id="node51" class="node">
|
||||||
|
<title>ATADiskDriver</title>
|
||||||
|
<ellipse fill="none" stroke="#000000" cx="616.0953" cy="-18" rx="74.1354" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="616.0953" y="-13.8" font-family="Times,serif" font-size="14.00" fill="#000000">ATADiskDriver</text>
|
||||||
|
</g>
|
||||||
|
<!-- VirtualDisk->ATADiskDriver -->
|
||||||
|
<g id="edge53" class="edge">
|
||||||
|
<title>VirtualDisk->ATADiskDriver</title>
|
||||||
|
<path fill="none" stroke="#000000" d="M368.0029,-78.0928C375.6815,-76.0205 383.6171,-73.9167 391.0953,-72 445.1811,-58.1378 506.8603,-43.4105 551.945,-32.8436"/>
|
||||||
|
<polygon fill="#000000" stroke="#000000" points="552.9392,-36.2055 561.879,-30.5196 551.3446,-29.3896 552.9392,-36.2055"/>
|
||||||
|
</g>
|
||||||
|
<!-- FloppyController -->
|
||||||
|
<g id="node52" class="node">
|
||||||
|
<title>FloppyController</title>
|
||||||
|
<ellipse fill="none" stroke="#000000" cx="78.0953" cy="-18" rx="78.1907" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="78.0953" y="-13.8" font-family="Times,serif" font-size="14.00" fill="#000000">FloppyController</text>
|
||||||
|
</g>
|
||||||
|
<!-- VirtualDisk->FloppyController -->
|
||||||
|
<g id="edge54" class="edge">
|
||||||
|
<title>VirtualDisk->FloppyController</title>
|
||||||
|
<path fill="none" stroke="#000000" d="M283.1951,-77.7862C242.8032,-66.012 181.3328,-48.0935 136.2175,-34.9425"/>
|
||||||
|
<polygon fill="#000000" stroke="#000000" points="137.1453,-31.5673 126.5653,-32.1289 135.1863,-38.2877 137.1453,-31.5673"/>
|
||||||
|
</g>
|
||||||
|
<!-- CDROM -->
|
||||||
|
<g id="node53" class="node">
|
||||||
|
<title>CDROM</title>
|
||||||
|
<ellipse fill="none" stroke="#000000" cx="221.0953" cy="-18" rx="46.3875" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="221.0953" y="-13.8" font-family="Times,serif" font-size="14.00" fill="#000000">CDROM</text>
|
||||||
|
</g>
|
||||||
|
<!-- VirtualDisk->CDROM -->
|
||||||
|
<g id="edge55" class="edge">
|
||||||
|
<title>VirtualDisk->CDROM</title>
|
||||||
|
<path fill="none" stroke="#000000" d="M301.2356,-73.4817C286.7642,-63.4631 268.1319,-50.5638 252.4754,-39.7247"/>
|
||||||
|
<polygon fill="#000000" stroke="#000000" points="254.3431,-36.7608 244.1289,-33.9463 250.3586,-42.5161 254.3431,-36.7608"/>
|
||||||
|
</g>
|
||||||
|
<!-- NVME -->
|
||||||
|
<g id="node54" class="node">
|
||||||
|
<title>NVME</title>
|
||||||
|
<ellipse fill="none" stroke="#000000" cx="325.0953" cy="-18" rx="39.4254" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="325.0953" y="-13.8" font-family="Times,serif" font-size="14.00" fill="#000000">NVME</text>
|
||||||
|
</g>
|
||||||
|
<!-- VirtualDisk->NVME -->
|
||||||
|
<g id="edge56" class="edge">
|
||||||
|
<title>VirtualDisk->NVME</title>
|
||||||
|
<path fill="none" stroke="#000000" d="M325.0953,-71.8314C325.0953,-64.131 325.0953,-54.9743 325.0953,-46.4166"/>
|
||||||
|
<polygon fill="#000000" stroke="#000000" points="328.5954,-46.4132 325.0953,-36.4133 321.5954,-46.4133 328.5954,-46.4132"/>
|
||||||
|
</g>
|
||||||
|
<!-- BlueToothStack -->
|
||||||
|
<g id="node55" class="node">
|
||||||
|
<title>BlueToothStack</title>
|
||||||
|
<ellipse fill="none" stroke="#000000" cx="2547.0953" cy="-378" rx="73.5965" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="2547.0953" y="-373.8" font-family="Times,serif" font-size="14.00" fill="#000000">BlueToothStack</text>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 36 KiB |
32
contrib/TODO.md
Normal file
32
contrib/TODO.md
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
# TODO
|
||||||
|
- Build out the object system
|
||||||
|
- Build or Find an acceptable IDL
|
||||||
|
Short List of potentials
|
||||||
|
- [comline](https://git.ablecorp.us/DOOME1M8Cover/comline)
|
||||||
|
- Work on a styleguide for commits
|
||||||
|
Maybe something allong the lines of
|
||||||
|
[relevant shorthand note] Explination
|
||||||
|
- Language support on HBVM
|
||||||
|
- HBVM assembler (with IDL support)
|
||||||
|
- HBVM Lisp/s-expr Compiler (Also (with (IDL (support))))
|
||||||
|
- Documentation
|
||||||
|
- Drivers
|
||||||
|
- serial driver
|
||||||
|
- PS/2 mouse driver
|
||||||
|
- PS/2 Keyboard driver
|
||||||
|
- VGA driver
|
||||||
|
- SVGA driver
|
||||||
|
- File system
|
||||||
|
- Depends on Disk driver
|
||||||
|
- TarFS
|
||||||
|
Pass in a tar file as an initrd and parse it with TarFS
|
||||||
|
- VFS
|
||||||
|
Being (written)[https://git.ablecorp.us/bee/ableos-vfs] by Bee
|
||||||
|
- Disk driver
|
||||||
|
- IDE Driver
|
||||||
|
- ATA Driver
|
||||||
|
- Floppy Driver
|
||||||
|
- A ton more
|
||||||
|
- Port (Slint)[https://slint.dev]
|
||||||
|
- Depends on
|
||||||
|
- Graphics Driver
|
7
dev/Cargo.toml
Normal file
7
dev/Cargo.toml
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
[package]
|
||||||
|
name = "dev"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
logos = "0.14.1"
|
6
dev/README.md
Normal file
6
dev/README.md
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
# dev
|
||||||
|
`dev` is an ableOS specific tool meant to help the development of ableOS.
|
||||||
|
|
||||||
|
At the current stage changes are not welcome. If you have feature suggestions ping me on discord `@abletheabove`.
|
||||||
|
|
||||||
|
Run `cargo dev help` to see usage.
|
84
dev/src/idl/mod.rs
Normal file
84
dev/src/idl/mod.rs
Normal file
|
@ -0,0 +1,84 @@
|
||||||
|
pub mod protocol;
|
||||||
|
|
||||||
|
use std::io::Read;
|
||||||
|
|
||||||
|
use {
|
||||||
|
logos::{Lexer, Logos},
|
||||||
|
protocol::Protocol,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Logos, Debug, PartialEq, Clone)]
|
||||||
|
#[logos(skip r"[ \t\n\f]+")] // Ignore this regex pattern between tokens
|
||||||
|
enum Token {
|
||||||
|
// Tokens can be literal strings, of any length.
|
||||||
|
#[token("protocol")]
|
||||||
|
Protocol,
|
||||||
|
|
||||||
|
#[token("{")]
|
||||||
|
LBrace,
|
||||||
|
|
||||||
|
#[token("}")]
|
||||||
|
RBrace,
|
||||||
|
|
||||||
|
#[token("(")]
|
||||||
|
LParen,
|
||||||
|
|
||||||
|
#[token(")")]
|
||||||
|
RParen,
|
||||||
|
|
||||||
|
#[token(":")]
|
||||||
|
Colon,
|
||||||
|
#[token(";")]
|
||||||
|
SemiColon,
|
||||||
|
|
||||||
|
#[token(",")]
|
||||||
|
Comma,
|
||||||
|
|
||||||
|
#[token("=")]
|
||||||
|
Equal,
|
||||||
|
|
||||||
|
#[token("->")]
|
||||||
|
RArrow,
|
||||||
|
|
||||||
|
#[regex("[a-zA-Z_]+", |lex|{lex.slice().to_string()})]
|
||||||
|
Text(String),
|
||||||
|
|
||||||
|
#[regex("[1234567890]+", |lex|{lex.slice().parse::<u64>().unwrap()})]
|
||||||
|
Number(u64),
|
||||||
|
|
||||||
|
#[regex(r"@[a-zA-Z_]+", |lex|{lex.slice().to_string()})]
|
||||||
|
Decorator(String),
|
||||||
|
|
||||||
|
#[regex(r#"@[a-zA-Z_]+\([a-zA-Z,0-9=]+\)"#, |lex|{lex.slice().to_string()})]
|
||||||
|
DecoratorOption(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn build_idl(name: String) {
|
||||||
|
let contents = open_protocol(name);
|
||||||
|
let lex = Token::lexer(&contents);
|
||||||
|
let mut tokens = vec![];
|
||||||
|
for x in lex {
|
||||||
|
match x {
|
||||||
|
Ok(token) => {
|
||||||
|
println!("{:?}", token);
|
||||||
|
tokens.push(token);
|
||||||
|
}
|
||||||
|
Err(err) => println!("{:?}", err),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
build(tokens);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn build(a: Vec<Token>) {
|
||||||
|
for toke in a {
|
||||||
|
println!("{:?}", toke);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn open_protocol(name: String) -> String {
|
||||||
|
let path = format!("sysdata/idl/{}/src/protocol.aidl", name);
|
||||||
|
let mut file = std::fs::File::open(path).unwrap();
|
||||||
|
let mut contents = String::new();
|
||||||
|
file.read_to_string(&mut contents).unwrap();
|
||||||
|
contents
|
||||||
|
}
|
17
dev/src/idl/protocol.rs
Normal file
17
dev/src/idl/protocol.rs
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
pub enum ProtocolTypes {
|
||||||
|
Byte,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Protocol {}
|
||||||
|
impl Protocol {
|
||||||
|
pub fn is_empty(&self) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn validate_data(&self, data: Vec<u8>) -> bool {
|
||||||
|
if !data.is_empty() && self.is_empty() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
152
dev/src/main.rs
Normal file
152
dev/src/main.rs
Normal file
|
@ -0,0 +1,152 @@
|
||||||
|
use std::io::Write;
|
||||||
|
|
||||||
|
use idl::build_idl;
|
||||||
|
pub mod idl;
|
||||||
|
|
||||||
|
pub enum Options {
|
||||||
|
Build,
|
||||||
|
Clean,
|
||||||
|
New,
|
||||||
|
Run,
|
||||||
|
}
|
||||||
|
#[derive(PartialEq, Debug)]
|
||||||
|
pub enum DevelopmentType {
|
||||||
|
Program,
|
||||||
|
Library,
|
||||||
|
IDL,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let mut args: Vec<String> = std::env::args().collect();
|
||||||
|
args.remove(0);
|
||||||
|
args.reverse();
|
||||||
|
|
||||||
|
let binding = args.pop().unwrap_or("help".to_string());
|
||||||
|
let subcommand = binding.as_str();
|
||||||
|
|
||||||
|
match subcommand {
|
||||||
|
"build" => {
|
||||||
|
let name = &args.pop().unwrap();
|
||||||
|
build(name.to_string())
|
||||||
|
}
|
||||||
|
"new" => {
|
||||||
|
let binding = args.pop().unwrap();
|
||||||
|
let dev_type = binding.as_str();
|
||||||
|
let name = args.pop().unwrap();
|
||||||
|
use DevelopmentType::*;
|
||||||
|
match dev_type {
|
||||||
|
"lib" | "library" => new(Library, name),
|
||||||
|
"prog" | "program" => new(Program, name),
|
||||||
|
"idl" => {
|
||||||
|
new(IDL, name);
|
||||||
|
// idl::main();
|
||||||
|
panic!("IDL is not finalized yet.")
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
"run" => run(),
|
||||||
|
"help" => help(),
|
||||||
|
_ => {
|
||||||
|
println!("Error");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new(development_type: DevelopmentType, name: String) {
|
||||||
|
let (folder_hierarchy, entry_name) = match development_type {
|
||||||
|
DevelopmentType::Program => ("programs", "main.hb"),
|
||||||
|
DevelopmentType::Library => ("libraries", "lib.hb"),
|
||||||
|
DevelopmentType::IDL => ("idl", "protocol.aidl"),
|
||||||
|
};
|
||||||
|
let project_folder_path_string = format!("sysdata/{folder_hierarchy}/{name}");
|
||||||
|
|
||||||
|
if std::path::Path::new(&project_folder_path_string).exists() {
|
||||||
|
panic!("Project already exists.")
|
||||||
|
}
|
||||||
|
|
||||||
|
std::fs::create_dir(project_folder_path_string.clone()).unwrap();
|
||||||
|
let readme_path_string = format!("{}/README.md", project_folder_path_string);
|
||||||
|
let mut readme_file = std::fs::File::create(readme_path_string.clone()).unwrap();
|
||||||
|
|
||||||
|
let readme_contents = format!("# {}", name);
|
||||||
|
readme_file.write_all(readme_contents.as_bytes()).unwrap();
|
||||||
|
|
||||||
|
let contents = format!(
|
||||||
|
"[package]
|
||||||
|
name = \"{}\"
|
||||||
|
authors = [\"\"]
|
||||||
|
|
||||||
|
[dependants.libraries]
|
||||||
|
|
||||||
|
[dependants.binaries]
|
||||||
|
hblang.version = \"1.0.0\"
|
||||||
|
|
||||||
|
[build]
|
||||||
|
command = \"hblang src/main.hb\"
|
||||||
|
",
|
||||||
|
name
|
||||||
|
);
|
||||||
|
|
||||||
|
let toml_path_string = format!("{}/meta.toml", project_folder_path_string);
|
||||||
|
let mut readme_file = std::fs::File::create(toml_path_string.clone()).unwrap();
|
||||||
|
|
||||||
|
readme_file.write_all(contents.as_bytes()).unwrap();
|
||||||
|
|
||||||
|
let src_folder_path_string = format!("{}/src", project_folder_path_string);
|
||||||
|
std::fs::create_dir(src_folder_path_string.clone()).unwrap();
|
||||||
|
|
||||||
|
let full_path_string = format!("{src_folder_path_string}/{entry_name}");
|
||||||
|
let mut file = std::fs::File::create(full_path_string.clone()).unwrap();
|
||||||
|
let file_contents = match development_type {
|
||||||
|
DevelopmentType::Program => "main := fn(): int {
|
||||||
|
return 0
|
||||||
|
}"
|
||||||
|
.to_string(),
|
||||||
|
DevelopmentType::Library => "".to_string(),
|
||||||
|
DevelopmentType::IDL => format!(
|
||||||
|
"protocol {} {{
|
||||||
|
}}",
|
||||||
|
name
|
||||||
|
)
|
||||||
|
.to_owned(),
|
||||||
|
}
|
||||||
|
.to_string();
|
||||||
|
file.write_all(file_contents.as_bytes()).unwrap();
|
||||||
|
|
||||||
|
println!("New project created.");
|
||||||
|
if development_type == DevelopmentType::Program {
|
||||||
|
println!("You should add your project into the ableOS system configuration in sysdata/system_config.toml")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run() {
|
||||||
|
println!("Running is not supported on a non-ableOS platform");
|
||||||
|
}
|
||||||
|
|
||||||
|
fn build(name: String) {
|
||||||
|
println!("building {}", name);
|
||||||
|
let mut a = name.split("/");
|
||||||
|
let dev_type = a.next().unwrap();
|
||||||
|
let name = a.next().unwrap().to_string();
|
||||||
|
match dev_type {
|
||||||
|
"programs" => build_program(name),
|
||||||
|
"idl" => build_idl(name),
|
||||||
|
_ => {
|
||||||
|
panic!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn build_program(_name: String) {}
|
||||||
|
pub fn build_library(_name: String) {}
|
||||||
|
|
||||||
|
fn help() {
|
||||||
|
println!(
|
||||||
|
"==========
|
||||||
|
= Help =
|
||||||
|
==========
|
||||||
|
Subcommands
|
||||||
|
- new Usage: `cargo dev new library name` or `cargo dev new program name`"
|
||||||
|
)
|
||||||
|
}
|
96
flake.lock
Normal file
96
flake.lock
Normal file
|
@ -0,0 +1,96 @@
|
||||||
|
{
|
||||||
|
"nodes": {
|
||||||
|
"flake-utils": {
|
||||||
|
"inputs": {
|
||||||
|
"systems": "systems"
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1731533236,
|
||||||
|
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nixpkgs": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1732014248,
|
||||||
|
"narHash": "sha256-y/MEyuJ5oBWrWAic/14LaIr/u5E0wRVzyYsouYY3W6w=",
|
||||||
|
"owner": "NixOS",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "23e89b7da85c3640bbc2173fe04f4bd114342367",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "NixOS",
|
||||||
|
"ref": "nixos-unstable",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nixpkgs_2": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1728538411,
|
||||||
|
"narHash": "sha256-f0SBJz1eZ2yOuKUr5CA9BHULGXVSn6miBuUWdTyhUhU=",
|
||||||
|
"owner": "NixOS",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "b69de56fac8c2b6f8fd27f2eca01dcda8e0a4221",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "NixOS",
|
||||||
|
"ref": "nixpkgs-unstable",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": {
|
||||||
|
"inputs": {
|
||||||
|
"flake-utils": "flake-utils",
|
||||||
|
"nixpkgs": "nixpkgs",
|
||||||
|
"rust-overlay": "rust-overlay"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"rust-overlay": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs": "nixpkgs_2"
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1732328983,
|
||||||
|
"narHash": "sha256-RHt12f/slrzDpSL7SSkydh8wUE4Nr4r23HlpWywed9E=",
|
||||||
|
"owner": "oxalica",
|
||||||
|
"repo": "rust-overlay",
|
||||||
|
"rev": "ed8aa5b64f7d36d9338eb1d0a3bb60cf52069a72",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "oxalica",
|
||||||
|
"repo": "rust-overlay",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"systems": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1681028828,
|
||||||
|
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "default",
|
||||||
|
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "default",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": "root",
|
||||||
|
"version": 7
|
||||||
|
}
|
30
flake.nix
Normal file
30
flake.nix
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
{
|
||||||
|
description = "A devShell example";
|
||||||
|
|
||||||
|
inputs = {
|
||||||
|
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
||||||
|
rust-overlay.url = "github:oxalica/rust-overlay";
|
||||||
|
flake-utils.url = "github:numtide/flake-utils";
|
||||||
|
};
|
||||||
|
|
||||||
|
outputs = { self, nixpkgs, rust-overlay, flake-utils }:
|
||||||
|
flake-utils.lib.eachDefaultSystem (system:
|
||||||
|
let
|
||||||
|
overlays = [ (import rust-overlay) ];
|
||||||
|
pkgs = import nixpkgs {
|
||||||
|
inherit system overlays;
|
||||||
|
};
|
||||||
|
|
||||||
|
rustToolchain = pkgs.pkgsBuildHost.rust-bin.fromRustupToolchainFile ./rust-toolchain.toml;
|
||||||
|
in
|
||||||
|
with pkgs;
|
||||||
|
{
|
||||||
|
devShells.default = mkShell {
|
||||||
|
buildInputs = [
|
||||||
|
rustToolchain
|
||||||
|
qemu_full
|
||||||
|
];
|
||||||
|
};
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
|
@ -4,6 +4,3 @@ build-std-features = ["compiler-builtins-mem"]
|
||||||
|
|
||||||
[build]
|
[build]
|
||||||
target = "./targets/x86_64-ableos.json"
|
target = "./targets/x86_64-ableos.json"
|
||||||
|
|
||||||
[target.'cfg(target_arch = "x86_64")']
|
|
||||||
rustflags = ["-C", "target-feature=+rdrand"]
|
|
||||||
|
|
|
@ -3,35 +3,32 @@ edition = "2021"
|
||||||
name = "kernel"
|
name = "kernel"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
|
|
||||||
|
[features]
|
||||||
|
ktest = []
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
limine = { version = "0.1", git = "https://github.com/limine-bootloader/limine-rs" }
|
# embedded-graphics = "0.8"
|
||||||
|
hbvm = { git = "https://git.ablecorp.us/AbleOS/holey-bytes.git", features = [
|
||||||
hbvm = { git = "https://git.ablecorp.us/ableos/holey-bytes" }
|
"nightly", "alloc", "disasm"
|
||||||
# hbasm = { git = "https://git.ablecorp.us/ableos/holey-bytes" }
|
] }
|
||||||
|
ktest_macro = { path = "ktest_macro" }
|
||||||
embedded-graphics = "0.7.1"
|
|
||||||
|
|
||||||
|
|
||||||
error-stack = { version = "0.3", default-features = false }
|
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
spin = "0.9"
|
spin = "0.9"
|
||||||
uart_16550 = "0.2"
|
|
||||||
slab = { version = "0.4", default-features = false }
|
slab = { version = "0.4", default-features = false }
|
||||||
xml = { git = "https://git.ablecorp.us/ableos/ableos_userland" }
|
uart_16550 = { version = "0.3", features = ["nightly"] }
|
||||||
|
xml.git = "https://git.ablecorp.us/ableos/ableos_userland"
|
||||||
clparse = { git = "https://git.ablecorp.us/ableos/ableos_userland", default-features = false }
|
versioning.git = "https://git.ablecorp.us/ableos/ableos_userland"
|
||||||
versioning = { git = "https://git.ablecorp.us/ableos/ableos_userland" }
|
# able_graphics_library.git = "https://git.ablecorp.us/ableos/ableos_userland"
|
||||||
able_graphics_library = { git = "https://git.ablecorp.us/ableos/ableos_userland" }
|
hashbrown = { version = "0.15", features = ["nightly"] }
|
||||||
hashbrown = "*"
|
limine = "0.1"
|
||||||
|
|
||||||
[dependencies.crossbeam-queue]
|
[dependencies.crossbeam-queue]
|
||||||
version = "0.3"
|
version = "0.3"
|
||||||
default-features = false
|
default-features = false
|
||||||
features = ["alloc"]
|
features = ["alloc", "nightly"]
|
||||||
|
|
||||||
[dependencies.derive_more]
|
[dependencies.derive_more]
|
||||||
version = "0.99"
|
version = "1"
|
||||||
default-features = false
|
default-features = false
|
||||||
features = [
|
features = [
|
||||||
"add",
|
"add",
|
||||||
|
@ -48,12 +45,12 @@ features = [
|
||||||
|
|
||||||
|
|
||||||
[target.'cfg(target_arch = "x86_64")'.dependencies]
|
[target.'cfg(target_arch = "x86_64")'.dependencies]
|
||||||
x86_64 = "0.14"
|
x86_64 = "0.15"
|
||||||
x2apic = "0.4"
|
x2apic = "0.4"
|
||||||
virtio-drivers = "0.4.0"
|
# virtio-drivers = "0.7"
|
||||||
# rdrand = "*"
|
|
||||||
rdrand = { version = "0.8", default-features = false }
|
|
||||||
|
|
||||||
|
|
||||||
[target.'cfg(target_arch = "riscv64")'.dependencies]
|
[target.'cfg(target_arch = "riscv64")'.dependencies]
|
||||||
sbi = "0.2.0"
|
sbi = "0.2.0"
|
||||||
|
|
||||||
|
[target.'cfg(target_arch = "aarch64")'.dependencies]
|
||||||
|
aarch64-cpu = "9"
|
||||||
|
|
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,9 +6,23 @@ SECTIONS
|
||||||
.text.boot : { *(.text.boot) }
|
.text.boot : { *(.text.boot) }
|
||||||
.text : { *(.text) }
|
.text : { *(.text) }
|
||||||
.data : { *(.data) }
|
.data : { *(.data) }
|
||||||
|
.note.ktest : {
|
||||||
|
__ktest_start = .;
|
||||||
|
*(.note.ktest)
|
||||||
|
__ktest_end = .;
|
||||||
|
}
|
||||||
.rodata : { *(.rodata) }
|
.rodata : { *(.rodata) }
|
||||||
.bss : { *(.bss) }
|
.bss : {
|
||||||
|
*(COMMON)
|
||||||
|
*(.bss .bss.*)
|
||||||
|
|
||||||
|
/* Align initial kernel heap to page boundary */
|
||||||
|
. = ALIGN(4K);
|
||||||
|
PROVIDE(_initial_kernel_heap_start = .);
|
||||||
|
/* PROVIDE(_initial_kernel_heap_size = 1024 * 1024); */
|
||||||
|
PROVIDE(_initial_kernel_heap_size = 1024 * 4096 * 100);
|
||||||
|
. += _initial_kernel_heap_size;
|
||||||
|
} :data
|
||||||
. = ALIGN(8);
|
. = ALIGN(8);
|
||||||
. = . + 0x4000;
|
. = . + 0x4000;
|
||||||
LD_STACK_PTR = .;
|
LD_STACK_PTR = .;
|
||||||
|
|
|
@ -38,8 +38,16 @@ SECTIONS
|
||||||
|
|
||||||
.data : {
|
.data : {
|
||||||
*(.data .data.*)
|
*(.data .data.*)
|
||||||
|
*(.got .got.*)
|
||||||
} :data
|
} :data
|
||||||
|
|
||||||
|
/* Add the .ktest section for test functions */
|
||||||
|
.note.ktest : {
|
||||||
|
__ktest_start = .; /* Mark the beginning of the section */
|
||||||
|
*(.note.ktest) /* Include all items in the .ktest section */
|
||||||
|
__ktest_end = .; /* Mark the end of the section */
|
||||||
|
}
|
||||||
|
|
||||||
.bss : {
|
.bss : {
|
||||||
*(COMMON)
|
*(COMMON)
|
||||||
*(.bss .bss.*)
|
*(.bss .bss.*)
|
||||||
|
|
|
@ -150,7 +150,8 @@ impl Heap {
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
trace!("Allocating {:?}", ptr);
|
trace!("Allocating {:?}", ptr);
|
||||||
}
|
}
|
||||||
// FIXME: zero out memory to prevent leaking data
|
|
||||||
|
unsafe { core::ptr::write_bytes(ptr, 0, size) };
|
||||||
|
|
||||||
assert!(ptr.is_aligned_to(alignment));
|
assert!(ptr.is_aligned_to(alignment));
|
||||||
NonNull::new(ptr)
|
NonNull::new(ptr)
|
||||||
|
@ -168,6 +169,7 @@ impl Heap {
|
||||||
self.bitmap_set_range(start, size, false);
|
self.bitmap_set_range(start, size, false);
|
||||||
self.allocated_chunks -= size;
|
self.allocated_chunks -= size;
|
||||||
// FIXME: zero out memory to prevent leaking data
|
// FIXME: zero out memory to prevent leaking data
|
||||||
|
// REPLY: When we zero on alloc, do we really need it?
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Finds first hole that can fit an allocation of `size` chunks, returns the start of the
|
/// Finds first hole that can fit an allocation of `size` chunks, returns the start of the
|
||||||
|
@ -322,7 +324,7 @@ impl Heap {
|
||||||
(unsafe { *self.bitmap.add(index / 8) } & (1 << (index % 8))) != 0
|
(unsafe { *self.bitmap.add(index / 8) } & (1 << (index % 8))) != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
const fn free_chunks(&self) -> usize {
|
pub const fn free_chunks(&self) -> usize {
|
||||||
self.total_chunks - self.allocated_chunks
|
self.total_chunks - self.allocated_chunks
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -343,3 +345,7 @@ fn alloc_error_handler(layout: alloc::alloc::Layout) -> ! {
|
||||||
// Todo: Maybe panic here instead
|
// Todo: Maybe panic here instead
|
||||||
crate::arch::spin_loop()
|
crate::arch::spin_loop()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_free_chunks_count() -> usize {
|
||||||
|
ALLOCATOR.0.lock().as_ref().unwrap().free_chunks()
|
||||||
|
}
|
||||||
|
|
50
kernel/src/arch/aarch64/device_info_collector.rs
Normal file
50
kernel/src/arch/aarch64/device_info_collector.rs
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
use {
|
||||||
|
crate::{device_tree::DeviceTree, kmain::DEVICE_TREE},
|
||||||
|
core::arch::asm,
|
||||||
|
xml::XMLElement,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn collect_device_info() {
|
||||||
|
log::trace!("Collecting devices on aarch64");
|
||||||
|
// Lock device tree
|
||||||
|
unsafe {
|
||||||
|
DEVICE_TREE.force_unlock();
|
||||||
|
}
|
||||||
|
let device_tree = &mut DEVICE_TREE.lock();
|
||||||
|
collect_cpu_info(device_tree);
|
||||||
|
// let dt = DEVICE_TREE.lock();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn collect_cpu_info(device_tree: &mut DeviceTree) {
|
||||||
|
let mut cpu = XMLElement::new("cpu");
|
||||||
|
|
||||||
|
let cpu_id = cpu_id();
|
||||||
|
|
||||||
|
cpu.set_attribute("CPU Name", cpu_id.0);
|
||||||
|
cpu.set_attribute("CPU Id", cpu_id.1);
|
||||||
|
|
||||||
|
let cpus = device_tree.devices.get_mut("CPUs").unwrap();
|
||||||
|
cpus.push(cpu);
|
||||||
|
}
|
||||||
|
|
||||||
|
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,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
let cpu_name = match cpu_id {
|
||||||
|
// the source of these two was a stackoverflow question
|
||||||
|
// https://raspberrypi.stackexchange.com/questions/117175/how-do-i-read-the-cpuid-in-aarch64-asm
|
||||||
|
0x410FD034 => "Cortex-A53",
|
||||||
|
0x410FD083 => "Cortex-A72",
|
||||||
|
// the source of this one was checking the cpu id :thinking:
|
||||||
|
0x410FD493 => "Neoverse N2",
|
||||||
|
_ => "Unknown",
|
||||||
|
};
|
||||||
|
log::trace!("CPU Name: {cpu_name} - CPU ID: 0x{:X}", cpu_id);
|
||||||
|
|
||||||
|
(cpu_name, cpu_id)
|
||||||
|
}
|
28
kernel/src/arch/aarch64/logging.rs
Normal file
28
kernel/src/arch/aarch64/logging.rs
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
use {crate::logger::TERMINAL_LOGGER, core::fmt::Write, spin::Mutex};
|
||||||
|
pub static SERIAL_CONSOLE: Mutex<SerialConsole> = Mutex::new(SerialConsole {
|
||||||
|
uart: 0x09000000 as *mut u8,
|
||||||
|
});
|
||||||
|
|
||||||
|
pub struct SerialConsole {
|
||||||
|
uart: *mut u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl core::fmt::Write for SerialConsole {
|
||||||
|
fn write_str(&mut self, s: &str) -> core::fmt::Result {
|
||||||
|
for c in s.chars() {
|
||||||
|
unsafe { *self.uart = c as u8 }
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
|
@ -1,20 +1,100 @@
|
||||||
use {core::arch::asm, limine::FramebufferRequest};
|
pub use logging::log;
|
||||||
|
use {
|
||||||
|
crate::{allocator, bootmodules::BootModule, kmain::kmain},
|
||||||
|
alloc::vec::Vec,
|
||||||
|
core::arch::asm,
|
||||||
|
limine::FramebufferRequest,
|
||||||
|
};
|
||||||
|
mod device_info_collector;
|
||||||
|
use device_info_collector::collect_device_info;
|
||||||
|
|
||||||
|
pub mod logging;
|
||||||
|
use limine::HhdmRequest;
|
||||||
|
extern "C" {
|
||||||
|
fn _initial_kernel_heap_start();
|
||||||
|
fn _initial_kernel_heap_size();
|
||||||
|
}
|
||||||
|
const INITIAL_KERNEL_HEAP_START: *mut u8 = _initial_kernel_heap_start as _;
|
||||||
|
const INITIAL_KERNEL_HEAP_SIZE: *const () = _initial_kernel_heap_size as _;
|
||||||
|
|
||||||
pub const PAGE_SIZE: usize = 4096;
|
pub const PAGE_SIZE: usize = 4096;
|
||||||
|
static FB_REQ: FramebufferRequest = FramebufferRequest::new(0);
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
unsafe extern "C" fn _kernel_start() -> ! {
|
unsafe extern "C" fn _kernel_start() -> ! {
|
||||||
static FB_REQ: FramebufferRequest = FramebufferRequest::new(0);
|
crate::logger::init().expect("failed to set logger");
|
||||||
let fb1 = &FB_REQ.get_response().get().unwrap().framebuffers()[0];
|
log::info!("Initialising AKern {}", crate::VERSION);
|
||||||
|
|
||||||
for i in 0..100_usize {
|
static HDHM_REQ: HhdmRequest = HhdmRequest::new(0);
|
||||||
let offset = i * fb1.pitch as usize + i * 4;
|
// memory::init_pt(VirtAddr::new(
|
||||||
unsafe {
|
// HDHM_REQ
|
||||||
*(fb1.address.as_ptr().unwrap().offset(offset as isize) as *mut u32) = 0xFFFFFFFF;
|
// .get_response()
|
||||||
|
// .get()
|
||||||
|
// .expect("tried to get physical memory mapping offset from Limine")
|
||||||
|
// .offset,
|
||||||
|
// ));
|
||||||
|
allocator::init(INITIAL_KERNEL_HEAP_START, INITIAL_KERNEL_HEAP_SIZE as _);
|
||||||
|
|
||||||
|
collect_device_info();
|
||||||
|
|
||||||
|
let bm = MOD_REQ.get_response().get();
|
||||||
|
use limine::{KernelFileRequest, ModuleRequest};
|
||||||
|
static KFILE_REQ: KernelFileRequest = KernelFileRequest::new(0);
|
||||||
|
static MOD_REQ: ModuleRequest = ModuleRequest::new(0);
|
||||||
|
|
||||||
|
let mut bootmodules = Vec::new();
|
||||||
|
|
||||||
|
if bm.is_some() {
|
||||||
|
let bm = bm.unwrap();
|
||||||
|
for x in 0..bm.module_count {
|
||||||
|
let file = bm.modules().get(x as usize);
|
||||||
|
if file.is_some() {
|
||||||
|
let file = file.unwrap();
|
||||||
|
let raw_bytes = core::slice::from_raw_parts(
|
||||||
|
file.base.as_ptr().expect("invalid initrd"),
|
||||||
|
file.length as usize,
|
||||||
|
);
|
||||||
|
|
||||||
|
let file_path = file.path.to_str().unwrap().to_str();
|
||||||
|
if file_path.is_err() {
|
||||||
|
panic!("invalid file path: {:?}", file_path);
|
||||||
}
|
}
|
||||||
|
let file_cmd = file.cmdline.to_str().unwrap().to_str();
|
||||||
|
if file_cmd.is_err() {
|
||||||
|
panic!("invalid module cmd: {:?}", file_cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
spin_loop();
|
log::trace!("module path: {:?}", file_path);
|
||||||
|
log::trace!("module cmd: {:?}", file_cmd);
|
||||||
|
|
||||||
|
bootmodules.push(BootModule::new(
|
||||||
|
file_path.unwrap(),
|
||||||
|
raw_bytes,
|
||||||
|
file_cmd.unwrap(),
|
||||||
|
));
|
||||||
|
} else {
|
||||||
|
log::error!("You should not be here");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log::info!("Boot module count: {:?}", bootmodules.len());
|
||||||
|
assert_eq!(bm.module_count, bootmodules.len() as u64);
|
||||||
|
}
|
||||||
|
|
||||||
|
kmain(
|
||||||
|
KFILE_REQ
|
||||||
|
.get_response()
|
||||||
|
.get()
|
||||||
|
.and_then(|r| r.kernel_file.get())
|
||||||
|
.expect("failed to get kernel file from Limine")
|
||||||
|
.cmdline
|
||||||
|
.to_str()
|
||||||
|
.map(core::ffi::CStr::to_str)
|
||||||
|
.transpose()
|
||||||
|
.expect("expected valid cmdline string")
|
||||||
|
.unwrap_or_default(),
|
||||||
|
bootmodules,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn spin_loop() -> ! {
|
pub fn spin_loop() -> ! {
|
||||||
|
@ -23,10 +103,21 @@ pub fn spin_loop() -> ! {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// I am sorry.
|
||||||
|
static mut A_REAL_RANDOM_U64_I_PROMISE: u64 = 0;
|
||||||
|
|
||||||
pub fn hardware_random_u64() -> u64 {
|
pub fn hardware_random_u64() -> u64 {
|
||||||
0
|
if let Some(rng) = aarch64_cpu::asm::random::ArmRng::new() {
|
||||||
|
if let Some(rnd) = rng.rndr() {
|
||||||
|
return rnd;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
unsafe {
|
||||||
|
A_REAL_RANDOM_U64_I_PROMISE += 1;
|
||||||
|
A_REAL_RANDOM_U64_I_PROMISE
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn log(_args: core::fmt::Arguments<'_>) -> core::fmt::Result {
|
pub fn register_dump() {}
|
||||||
panic!()
|
#[no_mangle]
|
||||||
}
|
pub fn fmod() {}
|
||||||
|
|
|
@ -14,3 +14,29 @@ arch_cond!(
|
||||||
riscv64: "riscv64",
|
riscv64: "riscv64",
|
||||||
x86_64: "x86_64",
|
x86_64: "x86_64",
|
||||||
);
|
);
|
||||||
|
|
||||||
|
#[cfg(target_arch = "x86_64")]
|
||||||
|
use {crate::arch::interrupts::Interrupt, alloc::string::String};
|
||||||
|
#[cfg(target_arch = "x86_64")]
|
||||||
|
pub struct InterruptList {
|
||||||
|
list: HashMap<Interrupt, String>,
|
||||||
|
}
|
||||||
|
#[cfg(target_arch = "x86_64")]
|
||||||
|
use hashbrown::HashMap;
|
||||||
|
#[cfg(target_arch = "x86_64")]
|
||||||
|
impl InterruptList {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
list: HashMap::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[cfg(target_arch = "x86_64")]
|
||||||
|
use spin::{Lazy, Mutex};
|
||||||
|
#[cfg(target_arch = "x86_64")]
|
||||||
|
pub static INTERRUPT_LIST: Lazy<Mutex<InterruptList>> = Lazy::new(|| {
|
||||||
|
let mut il = InterruptList::new();
|
||||||
|
use crate::alloc::string::ToString;
|
||||||
|
il.list.insert(Interrupt::Timer, "PS/2 Mouse".to_string());
|
||||||
|
Mutex::new(il)
|
||||||
|
});
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
use core::num;
|
use core::num;
|
||||||
|
|
||||||
use alloc::boxed::Box;
|
use {
|
||||||
use spin::{Mutex, Once};
|
crate::memory::{MemoryManager, PhysicalAddress, VirtualAddress},
|
||||||
use crate::memory::{MemoryManager, PhysicalAddress, VirtualAddress};
|
alloc::boxed::Box,
|
||||||
|
spin::{Mutex, Once},
|
||||||
|
};
|
||||||
|
|
||||||
use super::PAGE_SIZE;
|
use super::PAGE_SIZE;
|
||||||
|
|
||||||
|
@ -28,7 +30,7 @@ impl PageSize {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct PageTable {
|
pub struct PageTable {
|
||||||
entries: [PageEntry; 512]
|
entries: [PageEntry; 512],
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PageTable {
|
impl PageTable {
|
||||||
|
@ -72,8 +74,14 @@ impl PageTable {
|
||||||
/// flags MUST include one or more of the following:
|
/// flags MUST include one or more of the following:
|
||||||
/// Read, Write, Execute
|
/// Read, Write, Execute
|
||||||
/// The valid bit automatically gets added
|
/// The valid bit automatically gets added
|
||||||
pub fn map(&mut self, vaddr: VirtualAddress, paddr: PhysicalAddress, flags: PageEntryFlags, page_size: PageSize) {
|
pub fn map(
|
||||||
assert!(flags as usize & 0xe != 0);
|
&mut self,
|
||||||
|
vaddr: VirtualAddress,
|
||||||
|
paddr: PhysicalAddress,
|
||||||
|
flags: PageEntryFlags,
|
||||||
|
page_size: PageSize,
|
||||||
|
) {
|
||||||
|
assert!(flags as usize & 0xE != 0);
|
||||||
|
|
||||||
let vpn = vaddr.vpns();
|
let vpn = vaddr.vpns();
|
||||||
let ppn = paddr.ppns();
|
let ppn = paddr.ppns();
|
||||||
|
@ -105,14 +113,24 @@ impl PageTable {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Identity maps a page of memory
|
/// Identity maps a page of memory
|
||||||
pub fn identity_map(&mut self, addr: PhysicalAddress, flags: PageEntryFlags, page_size: PageSize) {
|
pub fn identity_map(
|
||||||
|
&mut self,
|
||||||
|
addr: PhysicalAddress,
|
||||||
|
flags: PageEntryFlags,
|
||||||
|
page_size: PageSize,
|
||||||
|
) {
|
||||||
// log::debug!("identity mapped {addr}");
|
// log::debug!("identity mapped {addr}");
|
||||||
self.map(addr.as_addr().into(), addr, flags, page_size);
|
self.map(addr.as_addr().into(), addr, flags, page_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Identity maps a range of contiguous memory
|
/// Identity maps a range of contiguous memory
|
||||||
/// This assumes that start <= end
|
/// This assumes that start <= end
|
||||||
pub fn identity_map_range(&mut self, start: PhysicalAddress, end: PhysicalAddress, flags: PageEntryFlags) {
|
pub fn identity_map_range(
|
||||||
|
&mut self,
|
||||||
|
start: PhysicalAddress,
|
||||||
|
end: PhysicalAddress,
|
||||||
|
flags: PageEntryFlags,
|
||||||
|
) {
|
||||||
log::debug!("start: {start}, end: {end}");
|
log::debug!("start: {start}, end: {end}");
|
||||||
let mut mem_addr = start.as_addr() & !(PAGE_SIZE - 1);
|
let mut mem_addr = start.as_addr() & !(PAGE_SIZE - 1);
|
||||||
let num_pages = (align_val(end.as_addr(), 12) - mem_addr - 1) / PAGE_SIZE + 1;
|
let num_pages = (align_val(end.as_addr(), 12) - mem_addr - 1) / PAGE_SIZE + 1;
|
||||||
|
@ -228,7 +246,7 @@ impl PageEntry {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn addr(&self) -> PhysicalAddress {
|
fn addr(&self) -> PhysicalAddress {
|
||||||
((self.entry() as usize & !0x3ff) << 2).into()
|
((self.entry() as usize & !0x3FF) << 2).into()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn destroy(&mut self) {
|
fn destroy(&mut self) {
|
||||||
|
|
|
@ -1,19 +1,28 @@
|
||||||
mod memory;
|
mod memory;
|
||||||
|
|
||||||
use core::{arch::{asm, global_asm}, fmt::Write};
|
use {
|
||||||
use alloc::boxed::Box;
|
alloc::{boxed::Box, vec::Vec},
|
||||||
use sbi::system_reset::{ResetType, ResetReason, system_reset};
|
core::{
|
||||||
use spin::{Mutex, Once};
|
arch::{asm, global_asm},
|
||||||
use uart_16550::MmioSerialPort;
|
fmt::Write,
|
||||||
|
},
|
||||||
|
sbi::system_reset::{system_reset, ResetReason, ResetType},
|
||||||
|
spin::{Mutex, Once},
|
||||||
|
uart_16550::MmioSerialPort,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::{allocator, memory::PhysicalAddress, arch::riscv64::memory::{PAGE_TABLE, PageEntryFlags, PageSize, PageTable}};
|
use crate::{
|
||||||
|
allocator,
|
||||||
|
arch::riscv64::memory::{PageEntryFlags, PageSize, PageTable, PAGE_TABLE},
|
||||||
|
memory::PhysicalAddress,
|
||||||
|
};
|
||||||
|
|
||||||
global_asm!(include_str!("entry.s"));
|
global_asm!(include_str!("entry.s"));
|
||||||
global_asm!(include_str!("memory_regions.s"));
|
global_asm!(include_str!("memory_regions.s"));
|
||||||
|
|
||||||
pub const PAGE_SIZE: usize = 4096;
|
pub const PAGE_SIZE: usize = 4096;
|
||||||
|
|
||||||
extern {
|
extern "C" {
|
||||||
static TEXT_START: PhysicalAddress;
|
static TEXT_START: PhysicalAddress;
|
||||||
static TEXT_END: PhysicalAddress;
|
static TEXT_END: PhysicalAddress;
|
||||||
|
|
||||||
|
@ -36,15 +45,18 @@ extern {
|
||||||
static USABLE_MEMORY_SIZE: usize;
|
static USABLE_MEMORY_SIZE: usize;
|
||||||
}
|
}
|
||||||
|
|
||||||
static SERIAL_CONSOLE: Once<Mutex<MmioSerialPort>> = Once::new();
|
pub static SERIAL_CONSOLE: Once<Mutex<MmioSerialPort>> = Once::new();
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
unsafe extern fn _kernel_start() -> ! {
|
unsafe extern "C" fn _kernel_start() -> ! {
|
||||||
SERIAL_CONSOLE.call_once(|| Mutex::new(unsafe { MmioSerialPort::new(0x1000_0000) }));
|
SERIAL_CONSOLE.call_once(|| Mutex::new(unsafe { MmioSerialPort::new(0x1000_0000) }));
|
||||||
crate::logger::init().expect("failed to set logger");
|
crate::logger::init().expect("failed to set logger");
|
||||||
log::info!("Initialising AKern {}", crate::VERSION);
|
log::info!("Initialising AKern {}", crate::VERSION);
|
||||||
|
|
||||||
allocator::init(INITIAL_KERNEL_HEAP_START.as_mut_ptr::<u8>(), INITIAL_KERNEL_HEAP_SIZE);
|
allocator::init(
|
||||||
|
INITIAL_KERNEL_HEAP_START.as_mut_ptr::<u8>(),
|
||||||
|
INITIAL_KERNEL_HEAP_SIZE,
|
||||||
|
);
|
||||||
memory::init(USABLE_MEMORY_START.into(), USABLE_MEMORY_SIZE / PAGE_SIZE);
|
memory::init(USABLE_MEMORY_START.into(), USABLE_MEMORY_SIZE / PAGE_SIZE);
|
||||||
|
|
||||||
let mut page_table_addr = PAGE_TABLE.get().unwrap().lock();
|
let mut page_table_addr = PAGE_TABLE.get().unwrap().lock();
|
||||||
|
@ -61,9 +73,17 @@ unsafe extern fn _kernel_start() -> ! {
|
||||||
// Map bss section (includes stack and initial kernel heap)
|
// Map bss section (includes stack and initial kernel heap)
|
||||||
page_table.identity_map_range(BSS_START, BSS_END, PageEntryFlags::ReadWrite);
|
page_table.identity_map_range(BSS_START, BSS_END, PageEntryFlags::ReadWrite);
|
||||||
// Map usable memory range (as rw so not executable)
|
// Map usable memory range (as rw so not executable)
|
||||||
page_table.identity_map_range(USABLE_MEMORY_START, USABLE_MEMORY_START + USABLE_MEMORY_SIZE.into(), PageEntryFlags::ReadWrite);
|
page_table.identity_map_range(
|
||||||
|
USABLE_MEMORY_START,
|
||||||
|
USABLE_MEMORY_START + USABLE_MEMORY_SIZE.into(),
|
||||||
|
PageEntryFlags::ReadWrite,
|
||||||
|
);
|
||||||
// Map Uart so we can continue using serial
|
// Map Uart so we can continue using serial
|
||||||
page_table.identity_map(0x1000_0000_usize.into(), PageEntryFlags::ReadWrite, PageSize::Size4KiB);
|
page_table.identity_map(
|
||||||
|
0x1000_0000_usize.into(),
|
||||||
|
PageEntryFlags::ReadWrite,
|
||||||
|
PageSize::Size4KiB,
|
||||||
|
);
|
||||||
|
|
||||||
let table_ppn = page_table_addr.as_addr() as usize >> 12;
|
let table_ppn = page_table_addr.as_addr() as usize >> 12;
|
||||||
let satp_value = 8 << 60 | table_ppn;
|
let satp_value = 8 << 60 | table_ppn;
|
||||||
|
@ -75,7 +95,7 @@ unsafe extern fn _kernel_start() -> ! {
|
||||||
in(reg) satp_value,
|
in(reg) satp_value,
|
||||||
);
|
);
|
||||||
|
|
||||||
crate::kmain::kmain("baka=9", None);
|
crate::kmain::kmain("baka=9", Vec::new());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Spin loop
|
/// Spin loop
|
||||||
|
@ -85,6 +105,12 @@ pub fn spin_loop() -> ! {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn hardware_random_u64() -> u64 {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn register_dump() {}
|
||||||
|
|
||||||
pub fn log(args: core::fmt::Arguments<'_>) -> core::fmt::Result {
|
pub fn log(args: core::fmt::Arguments<'_>) -> core::fmt::Result {
|
||||||
SERIAL_CONSOLE.get().unwrap().lock().write_fmt(args)
|
SERIAL_CONSOLE.get().unwrap().lock().write_fmt(args)
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,6 +53,7 @@ fn collect_cpu_info(device_tree: &mut DeviceTree) {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn collect_device_info() {
|
pub fn collect_device_info() {
|
||||||
|
log::trace!("Collecting devices on x86_64");
|
||||||
// Lock device tree
|
// Lock device tree
|
||||||
unsafe {
|
unsafe {
|
||||||
DEVICE_TREE.force_unlock();
|
DEVICE_TREE.force_unlock();
|
||||||
|
|
|
@ -11,6 +11,9 @@ use {
|
||||||
|
|
||||||
pub const DOUBLE_FAULT_IX: u16 = 0;
|
pub const DOUBLE_FAULT_IX: u16 = 0;
|
||||||
|
|
||||||
|
const STACK_SIZE: usize = 5 * 1024;
|
||||||
|
const STACK_ALIGNMENT: usize = 1;
|
||||||
|
|
||||||
pub unsafe fn init() {
|
pub unsafe fn init() {
|
||||||
use x86_64::instructions::{
|
use x86_64::instructions::{
|
||||||
segmentation::{Segment, CS, SS},
|
segmentation::{Segment, CS, SS},
|
||||||
|
@ -32,24 +35,24 @@ struct Selectors {
|
||||||
|
|
||||||
static TSS: Lazy<TaskStateSegment> = Lazy::new(|| {
|
static TSS: Lazy<TaskStateSegment> = Lazy::new(|| {
|
||||||
let mut tss = TaskStateSegment::new();
|
let mut tss = TaskStateSegment::new();
|
||||||
tss.interrupt_stack_table[usize::from(DOUBLE_FAULT_IX)] = {
|
|
||||||
const SIZE: usize = 5 * 1024;
|
let stack_ptr = unsafe {
|
||||||
let stack = unsafe {
|
let layout = alloc::alloc::Layout::from_size_align(STACK_SIZE, STACK_ALIGNMENT)
|
||||||
alloc::alloc::alloc_zeroed(
|
.expect("Failed to create stack layout");
|
||||||
alloc::alloc::Layout::from_size_align(SIZE, 1).expect("stack pointer"),
|
let stack = alloc::alloc::alloc(layout);
|
||||||
)
|
VirtAddr::from_ptr(stack) + STACK_SIZE as u64
|
||||||
};
|
|
||||||
VirtAddr::from_ptr(stack) + SIZE
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
tss.interrupt_stack_table[usize::from(DOUBLE_FAULT_IX)] = stack_ptr;
|
||||||
tss
|
tss
|
||||||
});
|
});
|
||||||
|
|
||||||
static GDT: Lazy<(GlobalDescriptorTable, Selectors)> = Lazy::new(|| {
|
static GDT: Lazy<(GlobalDescriptorTable, Selectors)> = Lazy::new(|| {
|
||||||
let mut gdt = GlobalDescriptorTable::new();
|
let mut gdt = GlobalDescriptorTable::new();
|
||||||
let sels = Selectors {
|
let sels = Selectors {
|
||||||
kcode: gdt.add_entry(Descriptor::kernel_code_segment()),
|
kcode: gdt.append(Descriptor::kernel_code_segment()),
|
||||||
kdata: gdt.add_entry(Descriptor::kernel_data_segment()),
|
kdata: gdt.append(Descriptor::kernel_data_segment()),
|
||||||
tss: gdt.add_entry(Descriptor::tss_segment(&TSS)),
|
tss: gdt.append(Descriptor::tss_segment(&TSS)),
|
||||||
};
|
};
|
||||||
(gdt, sels)
|
(gdt, sels)
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,69 +1 @@
|
||||||
use {limine::NonNullPtr};
|
|
||||||
|
|
||||||
use {
|
|
||||||
crate::{kmain::DEVICE_TREE},
|
|
||||||
able_graphics_library::raw_pixel::Display,
|
|
||||||
embedded_graphics::{pixelcolor::Rgb888, prelude::*},
|
|
||||||
limine::{Framebuffer, FramebufferRequest},
|
|
||||||
spin::{Lazy, Mutex},
|
|
||||||
};
|
|
||||||
|
|
||||||
pub static DISPLAY: Lazy<Mutex<Display>> = Lazy::new(|| {
|
|
||||||
static FB_REQ: FramebufferRequest = FramebufferRequest::new(0);
|
|
||||||
let fb1: &NonNullPtr<Framebuffer> = &FB_REQ.get_response().get().unwrap().framebuffers()[0];
|
|
||||||
|
|
||||||
{
|
|
||||||
use crate::alloc::string::ToString;
|
|
||||||
let mut dt = DEVICE_TREE.lock();
|
|
||||||
let mut 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);
|
|
||||||
dt.devices.insert("Displays".to_string(), alloc::vec![disp]);
|
|
||||||
}
|
|
||||||
let _size: usize = (fb1.width * fb1.height).try_into().unwrap();
|
|
||||||
let back_buffer: alloc::vec::Vec<u32> = alloc::vec![0; 800*600];
|
|
||||||
|
|
||||||
let m = Mutex::new(Display {
|
|
||||||
fb: fb1.address.as_ptr().unwrap().cast(),
|
|
||||||
// bb: fb1.address.as_ptr().unwrap().cast(),
|
|
||||||
bb: back_buffer.as_slice().as_ptr() as *mut u32,
|
|
||||||
size: Size::new(fb1.width as u32, fb1.height as u32),
|
|
||||||
color: Rgb888::WHITE,
|
|
||||||
});
|
|
||||||
log::info!("Graphics initialised");
|
|
||||||
m
|
|
||||||
});
|
|
||||||
|
|
||||||
pub fn init() {
|
|
||||||
Lazy::force(&DISPLAY);
|
|
||||||
}
|
|
||||||
// pub fn virtio_gpu<T: Transport>(transport: T) {
|
|
||||||
// let mut gpu = VirtIOGpu::<AbleosHal, T>::new(transport).expect("failed to create gpu driver");
|
|
||||||
// let (width, height) = gpu.resolution().expect("failed to get resolution");
|
|
||||||
// let width = width as usize;
|
|
||||||
// let height = height as usize;
|
|
||||||
// log::info!("GPU resolution is {}x{}", width, height);
|
|
||||||
// let fb = gpu.setup_framebuffer().expect("failed to get fb");
|
|
||||||
// for y in 0..height {
|
|
||||||
// for x in 0..width {
|
|
||||||
// let idx = (y * width + x) * 4;
|
|
||||||
// fb[idx] = x as u8;
|
|
||||||
// fb[idx + 1] = y as u8;
|
|
||||||
// fb[idx + 2] = (x + y) as u8;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// gpu.flush().expect("failed to flush");
|
|
||||||
// //delay some time
|
|
||||||
// log::info!("virtio-gpu show graphics....");
|
|
||||||
// for _ in 0..100000 {
|
|
||||||
// for _ in 0..100000 {
|
|
||||||
// unsafe {
|
|
||||||
// core::arch::asm!("nop");
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// log::info!("virtio-gpu test finished");
|
|
||||||
// }
|
|
||||||
|
|
|
@ -1,56 +1,54 @@
|
||||||
// TODO: Turn apic keyboard interrupt into a standard ipc message
|
|
||||||
use {
|
use {
|
||||||
|
core::mem::MaybeUninit,
|
||||||
log::trace,
|
log::trace,
|
||||||
spin::{Lazy, Mutex},
|
|
||||||
x2apic::lapic::{LocalApic, LocalApicBuilder},
|
x2apic::lapic::{LocalApic, LocalApicBuilder},
|
||||||
x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame, PageFaultErrorCode},
|
x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame, PageFaultErrorCode},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub unsafe fn init() {
|
/// Safety: Using LAPIC or IDT before init() is UB
|
||||||
trace!("Initialising IDT");
|
/// Using
|
||||||
IDT.load();
|
static mut LAPIC: LocalApic = unsafe { MaybeUninit::zeroed().assume_init() };
|
||||||
Lazy::force(&LAPIC);
|
static mut IDT: InterruptDescriptorTable = unsafe { MaybeUninit::zeroed().assume_init() };
|
||||||
x86_64::instructions::interrupts::enable();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
enum Interrupt {
|
#[derive(Debug, Eq, Hash, PartialEq)]
|
||||||
Timer = 32,
|
|
||||||
|
|
||||||
|
pub enum Interrupt {
|
||||||
|
Timer = 32,
|
||||||
ApicErr = u8::MAX - 1,
|
ApicErr = u8::MAX - 1,
|
||||||
Spurious = u8::MAX,
|
Spurious = u8::MAX,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) static LAPIC: Lazy<Mutex<LocalApic>> = Lazy::new(|| {
|
pub unsafe fn init() {
|
||||||
let mut lapic = LocalApicBuilder::new()
|
trace!("Initializing IDT and LAPIC");
|
||||||
|
|
||||||
|
// Initialize and load the IDT
|
||||||
|
IDT = InterruptDescriptorTable::new();
|
||||||
|
IDT.double_fault
|
||||||
|
.set_handler_fn(double_fault)
|
||||||
|
.set_stack_index(super::gdt::DOUBLE_FAULT_IX);
|
||||||
|
IDT.page_fault.set_handler_fn(page_fault);
|
||||||
|
|
||||||
|
IDT[Interrupt::ApicErr as u8].set_handler_fn(apic_err);
|
||||||
|
IDT[Interrupt::Spurious as u8].set_handler_fn(spurious);
|
||||||
|
IDT[Interrupt::Timer as u8].set_handler_fn(timer);
|
||||||
|
|
||||||
|
IDT.load();
|
||||||
|
|
||||||
|
LAPIC = LocalApicBuilder::new()
|
||||||
.timer_vector(Interrupt::Timer as usize)
|
.timer_vector(Interrupt::Timer as usize)
|
||||||
.error_vector(Interrupt::ApicErr as usize)
|
.error_vector(Interrupt::ApicErr as usize)
|
||||||
.spurious_vector(Interrupt::Spurious as usize)
|
.spurious_vector(Interrupt::Spurious as usize)
|
||||||
.set_xapic_base(
|
.set_xapic_base(
|
||||||
unsafe { x2apic::lapic::xapic_base() }
|
x2apic::lapic::xapic_base()
|
||||||
+ super::memory::HHDM_OFFSET.load(core::sync::atomic::Ordering::Relaxed),
|
+ super::memory::HHDM_OFFSET.load(core::sync::atomic::Ordering::Relaxed),
|
||||||
)
|
)
|
||||||
.build()
|
.build()
|
||||||
.expect("failed to setup Local APIC");
|
.expect("Failed to setup Local APIC");
|
||||||
unsafe { lapic.enable() };
|
LAPIC.enable();
|
||||||
Mutex::new(lapic)
|
|
||||||
});
|
|
||||||
|
|
||||||
static IDT: Lazy<InterruptDescriptorTable> = Lazy::new(|| {
|
x86_64::instructions::interrupts::enable();
|
||||||
let mut idt = InterruptDescriptorTable::new();
|
|
||||||
unsafe {
|
|
||||||
idt.double_fault
|
|
||||||
.set_handler_fn(double_fault)
|
|
||||||
.set_stack_index(super::gdt::DOUBLE_FAULT_IX);
|
|
||||||
}
|
}
|
||||||
idt.page_fault.set_handler_fn(page_fault);
|
|
||||||
|
|
||||||
idt[Interrupt::ApicErr as usize].set_handler_fn(apic_err);
|
|
||||||
idt[Interrupt::Spurious as usize].set_handler_fn(spurious);
|
|
||||||
idt[Interrupt::Timer as usize].set_handler_fn(timer);
|
|
||||||
|
|
||||||
idt
|
|
||||||
});
|
|
||||||
|
|
||||||
extern "x86-interrupt" fn double_fault(stack_frame: InterruptStackFrame, error_code: u64) -> ! {
|
extern "x86-interrupt" fn double_fault(stack_frame: InterruptStackFrame, error_code: u64) -> ! {
|
||||||
panic!("Double fault: error code {error_code} \n{stack_frame:#?}")
|
panic!("Double fault: error code {error_code} \n{stack_frame:#?}")
|
||||||
|
@ -64,15 +62,52 @@ extern "x86-interrupt" fn page_fault(
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "x86-interrupt" fn timer(_isf: InterruptStackFrame) {
|
extern "x86-interrupt" fn timer(_isf: InterruptStackFrame) {
|
||||||
// TODO: Pause the running program then schedule the next program
|
interrupt(Interrupt::Timer);
|
||||||
|
|
||||||
unsafe { LAPIC.lock().end_of_interrupt() };
|
unsafe {
|
||||||
|
LAPIC.end_of_interrupt();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "x86-interrupt" fn apic_err(_: InterruptStackFrame) {
|
extern "x86-interrupt" fn apic_err(_: InterruptStackFrame) {
|
||||||
|
interrupt(Interrupt::ApicErr);
|
||||||
|
|
||||||
panic!("Internal APIC error");
|
panic!("Internal APIC error");
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "x86-interrupt" fn spurious(_: InterruptStackFrame) {
|
extern "x86-interrupt" fn spurious(_: InterruptStackFrame) {
|
||||||
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,51 +1,17 @@
|
||||||
//! Logging (as in terms of console / serial output)
|
//! Logging (as in terms of console / serial output)
|
||||||
#![allow(deprecated)]
|
#![allow(deprecated)]
|
||||||
|
use {core::fmt::Write, spin::Mutex, uart_16550::SerialPort};
|
||||||
use {
|
|
||||||
core::fmt::Write,
|
|
||||||
limine::{TerminalRequest, TerminalResponse},
|
|
||||||
spin::{Lazy, Mutex},
|
|
||||||
uart_16550::SerialPort,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub static SERIAL_CONSOLE: Mutex<SerialPort> = Mutex::new(unsafe { SerialPort::new(0x3F8) });
|
pub static SERIAL_CONSOLE: Mutex<SerialPort> = Mutex::new(unsafe { SerialPort::new(0x3F8) });
|
||||||
static TERMINAL_LOGGER: Lazy<Mutex<TermLogger>> = Lazy::new(|| Mutex::new(TermLogger::new()));
|
|
||||||
|
|
||||||
pub fn init() {
|
pub fn init() {
|
||||||
SERIAL_CONSOLE.lock().init();
|
SERIAL_CONSOLE.lock().init();
|
||||||
Lazy::force(&TERMINAL_LOGGER);
|
// Lazy::force(&TERMINAL_LOGGER);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn log(args: core::fmt::Arguments<'_>) -> core::fmt::Result {
|
pub fn log(args: core::fmt::Arguments<'_>) -> core::fmt::Result {
|
||||||
x86_64::instructions::interrupts::without_interrupts(|| {
|
x86_64::instructions::interrupts::without_interrupts(|| {
|
||||||
// TERMINAL_LOGGER.lock().write_fmt(args)?;
|
// TERMINAL_LOGGER.lock().write_fmt(args)?;
|
||||||
let mut sc = SERIAL_CONSOLE.lock();
|
SERIAL_CONSOLE.lock().write_fmt(args)
|
||||||
sc.write_fmt(args)?;
|
|
||||||
Ok(())
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
struct TermLogger(&'static TerminalResponse);
|
|
||||||
unsafe impl Send for TermLogger {}
|
|
||||||
impl TermLogger {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
static TERM_REQ: TerminalRequest = TerminalRequest::new(0);
|
|
||||||
Self(
|
|
||||||
TERM_REQ
|
|
||||||
.get_response()
|
|
||||||
.get()
|
|
||||||
.expect("failed to get terminal response"),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Write for TermLogger {
|
|
||||||
fn write_str(&mut self, s: &str) -> core::fmt::Result {
|
|
||||||
if let (Some(w), ts) = (self.0.write(), self.0.terminals()) {
|
|
||||||
for term in ts {
|
|
||||||
w(term, s);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,17 +1,16 @@
|
||||||
use embedded_graphics::pixelcolor::Rgb888;
|
use core::arch::x86_64::{_rdrand64_step, _rdseed64_step};
|
||||||
|
|
||||||
use crate::{arch::x86_64::graphics::DISPLAY, bootmodules::BootModule};
|
|
||||||
|
|
||||||
|
use {crate::bootmodules::BootModule, core::arch::asm, log::warn};
|
||||||
pub mod memory;
|
pub mod memory;
|
||||||
|
|
||||||
mod cpuid;
|
mod cpuid;
|
||||||
|
mod device_info_collector;
|
||||||
mod gdt;
|
mod gdt;
|
||||||
pub mod graphics;
|
pub mod graphics;
|
||||||
pub(crate) mod interrupts;
|
pub(crate) mod interrupts;
|
||||||
pub mod logging;
|
pub mod logging;
|
||||||
pub mod pci;
|
pub mod pci;
|
||||||
pub mod virtio;
|
// pub mod virtio;
|
||||||
mod device_info_collector;
|
|
||||||
|
|
||||||
pub use {logging::log, memory::PAGE_SIZE};
|
pub use {logging::log, memory::PAGE_SIZE};
|
||||||
|
|
||||||
|
@ -30,10 +29,87 @@ const INITIAL_KERNEL_HEAP_START: *mut u8 = _initial_kernel_heap_start as _;
|
||||||
const INITIAL_KERNEL_HEAP_SIZE: *const () = _initial_kernel_heap_size as _;
|
const INITIAL_KERNEL_HEAP_SIZE: *const () = _initial_kernel_heap_size as _;
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
|
#[naked]
|
||||||
|
#[cfg(not(target_feature = "avx2"))]
|
||||||
unsafe extern "C" fn _kernel_start() -> ! {
|
unsafe extern "C" fn _kernel_start() -> ! {
|
||||||
|
// Initialise SSE, then jump to kernel entrypoint
|
||||||
|
core::arch::naked_asm!(
|
||||||
|
// Initialise SSE
|
||||||
|
"mov rax, cr0",
|
||||||
|
"and ax, 0xfffb",
|
||||||
|
"or ax, 0x2",
|
||||||
|
"mov cr0, rax",
|
||||||
|
"mov rax, cr4",
|
||||||
|
"or ax, 3 << 9",
|
||||||
|
"mov cr4, rax",
|
||||||
|
|
||||||
|
// Jump to the kernel entry point
|
||||||
|
"jmp {}",
|
||||||
|
sym start,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[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();
|
logging::init();
|
||||||
crate::logger::init().expect("failed to set logger");
|
crate::logger::init().expect("failed to set logger");
|
||||||
log::info!("Initialising AKern {}", crate::VERSION);
|
log::debug!("Initialising AKern {}", crate::VERSION);
|
||||||
|
|
||||||
static HDHM_REQ: HhdmRequest = HhdmRequest::new(0);
|
static HDHM_REQ: HhdmRequest = HhdmRequest::new(0);
|
||||||
memory::init_pt(VirtAddr::new(
|
memory::init_pt(VirtAddr::new(
|
||||||
|
@ -43,7 +119,6 @@ unsafe extern "C" fn _kernel_start() -> ! {
|
||||||
.expect("tried to get physical memory mapping offset from Limine")
|
.expect("tried to get physical memory mapping offset from Limine")
|
||||||
.offset,
|
.offset,
|
||||||
));
|
));
|
||||||
|
|
||||||
allocator::init(INITIAL_KERNEL_HEAP_START, INITIAL_KERNEL_HEAP_SIZE as _);
|
allocator::init(INITIAL_KERNEL_HEAP_START, INITIAL_KERNEL_HEAP_SIZE as _);
|
||||||
|
|
||||||
static MMAP_REQ: MemmapRequest = MemmapRequest::new(0);
|
static MMAP_REQ: MemmapRequest = MemmapRequest::new(0);
|
||||||
|
@ -64,55 +139,56 @@ unsafe extern "C" fn _kernel_start() -> ! {
|
||||||
device_info_collector::collect_device_info();
|
device_info_collector::collect_device_info();
|
||||||
|
|
||||||
// Graphics test
|
// Graphics test
|
||||||
{
|
// {
|
||||||
graphics::init();
|
// graphics::init();
|
||||||
let mut dis = DISPLAY.lock();
|
// let mut dis = DISPLAY.lock();
|
||||||
use embedded_graphics::prelude::RgbColor;
|
// use embedded_graphics::prelude::RgbColor;
|
||||||
|
|
||||||
let _ = dis.set_color(Rgb888::YELLOW);
|
// let _ = dis.set_color(Rgb888::YELLOW);
|
||||||
let thick = 6;
|
// let thick = 6;
|
||||||
let p1 = (400, 30);
|
// let p1 = (400, 30);
|
||||||
let p2 = (200, 150);
|
// let p2 = (200, 150);
|
||||||
let p3 = (600, 150);
|
// let p3 = (600, 150);
|
||||||
let p4 = (200, 350);
|
// let p4 = (200, 350);
|
||||||
let p5 = (600, 350);
|
// let p5 = (600, 350);
|
||||||
let p6 = (400, 470);
|
// let p6 = (400, 470);
|
||||||
|
|
||||||
{
|
// {
|
||||||
//HEXAGON
|
// //HEXAGON
|
||||||
|
|
||||||
let _ = dis.line(p1.0, p1.1, p2.0, p2.1, thick);
|
// let _ = dis.line(p1.0, p1.1, p2.0, p2.1, thick);
|
||||||
let _ = dis.line(p1.0, p1.1, p3.0, p3.1, thick);
|
// let _ = dis.line(p1.0, p1.1, p3.0, p3.1, thick);
|
||||||
let _ = dis.line(p2.0, p2.1, p4.0, p4.1, thick);
|
// let _ = dis.line(p2.0, p2.1, p4.0, p4.1, thick);
|
||||||
let _ = dis.line(p3.0, p3.1, p5.0, p5.1, thick);
|
// let _ = dis.line(p3.0, p3.1, p5.0, p5.1, thick);
|
||||||
let _ = dis.line(p6.0, p6.1, p4.0, p4.1, thick);
|
// let _ = dis.line(p6.0, p6.1, p4.0, p4.1, thick);
|
||||||
let _ = dis.line(p6.0, p6.1, p5.0, p5.1, thick);
|
// let _ = dis.line(p6.0, p6.1, p5.0, p5.1, thick);
|
||||||
}
|
// }
|
||||||
{
|
// {
|
||||||
let _ = dis.line(600, 150, 200, 350, thick);
|
// let _ = dis.line(600, 150, 200, 350, thick);
|
||||||
let _ = dis.line(600, 350, 400, 250, thick);
|
// let _ = dis.line(600, 350, 400, 250, thick);
|
||||||
}
|
// }
|
||||||
|
|
||||||
{
|
// {
|
||||||
let _ = dis.set_color(Rgb888::WHITE);
|
// let _ = dis.set_color(Rgb888::WHITE);
|
||||||
let hp1 = (350, 150);
|
// let hp1 = (350, 150);
|
||||||
let hp2 = (350, 350);
|
// let hp2 = (350, 350);
|
||||||
let hp3 = (450, 250);
|
// let hp3 = (450, 250);
|
||||||
let hp4 = (350, 250);
|
// let hp4 = (350, 250);
|
||||||
let hp5 = (450, 150);
|
// let hp5 = (450, 150);
|
||||||
let hp6 = (450, 350);
|
// let hp6 = (450, 350);
|
||||||
|
|
||||||
let _ = dis.line(hp1.0, hp1.1, hp2.0, hp2.1, thick);
|
// let _ = dis.line(hp1.0, hp1.1, hp2.0, hp2.1, thick);
|
||||||
let _ = dis.line(hp3.0, hp3.1, hp4.0, hp4.1, thick);
|
// let _ = dis.line(hp3.0, hp3.1, hp4.0, hp4.1, thick);
|
||||||
let _ = dis.line(hp5.0, hp5.1, hp6.0, hp6.1, thick);
|
// let _ = dis.line(hp5.0, hp5.1, hp6.0, hp6.1, thick);
|
||||||
}
|
// }
|
||||||
|
|
||||||
dis.swap_buffers();
|
// dis.swap_buffers();
|
||||||
};
|
// };
|
||||||
|
|
||||||
// TODO: Add in rdseed and rdrand as sources for randomness
|
// TODO: Add in rdseed and rdrand as sources for randomness
|
||||||
let _rand = xml::XMLElement::new("Random");
|
let _rand = xml::XMLElement::new("Random");
|
||||||
|
|
||||||
|
log::debug!("Getting boot modules");
|
||||||
let bm = MOD_REQ.get_response().get();
|
let bm = MOD_REQ.get_response().get();
|
||||||
|
|
||||||
let mut bootmodules = alloc::vec::Vec::new();
|
let mut bootmodules = alloc::vec::Vec::new();
|
||||||
|
@ -126,18 +202,13 @@ unsafe extern "C" fn _kernel_start() -> ! {
|
||||||
let raw_bytes = core::slice::from_raw_parts(
|
let raw_bytes = core::slice::from_raw_parts(
|
||||||
file.base.as_ptr().expect("invalid initrd"),
|
file.base.as_ptr().expect("invalid initrd"),
|
||||||
file.length as usize,
|
file.length as usize,
|
||||||
)
|
|
||||||
.to_vec();
|
|
||||||
|
|
||||||
let file_path = alloc::string::String::from_utf8(
|
|
||||||
file.path.to_str().unwrap().to_bytes().to_vec(),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let file_path = file.path.to_str().unwrap().to_str();
|
||||||
if file_path.is_err() {
|
if file_path.is_err() {
|
||||||
panic!("invalid file path: {:?}", file_path);
|
panic!("invalid file path: {:?}", file_path);
|
||||||
}
|
}
|
||||||
let file_cmd = alloc::string::String::from_utf8(
|
let file_cmd = file.cmdline.to_str().unwrap().to_str();
|
||||||
file.cmdline.to_str().unwrap().to_bytes().to_vec(),
|
|
||||||
);
|
|
||||||
if file_cmd.is_err() {
|
if file_cmd.is_err() {
|
||||||
panic!("invalid module cmd: {:?}", file_cmd);
|
panic!("invalid module cmd: {:?}", file_cmd);
|
||||||
}
|
}
|
||||||
|
@ -155,7 +226,7 @@ unsafe extern "C" fn _kernel_start() -> ! {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
log::info!("Boot module count: {:?}", bootmodules.len());
|
log::debug!("Boot module count: {:?}", bootmodules.len());
|
||||||
assert_eq!(bm.module_count, bootmodules.len() as u64);
|
assert_eq!(bm.module_count, bootmodules.len() as u64);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -178,17 +249,93 @@ unsafe extern "C" fn _kernel_start() -> ! {
|
||||||
/// Spin loop
|
/// Spin loop
|
||||||
pub fn spin_loop() -> ! {
|
pub fn spin_loop() -> ! {
|
||||||
loop {
|
loop {
|
||||||
x86_64::instructions::hlt();
|
core::hint::spin_loop();
|
||||||
|
x86_64::instructions::hlt()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn hardware_random_u64() -> u64 {
|
pub fn hardware_random_u64() -> u64 {
|
||||||
use {log::trace, rdrand::RdRand};
|
let mut out: u64 = 0;
|
||||||
let gen = RdRand::new().unwrap();
|
match unsafe { _rdrand64_step(&mut out) } {
|
||||||
let ret = gen.try_next_u64().unwrap();
|
1 => out,
|
||||||
trace!("Random {}", ret);
|
_ => {
|
||||||
|
warn!("RDRand not supported.");
|
||||||
ret
|
// Try rdseed
|
||||||
|
match unsafe { _rdseed64_step(&mut out) } {
|
||||||
|
1 => out,
|
||||||
|
_ => panic!("Neither RDRand or RDSeed are supported"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_edid() {}
|
pub fn get_edid() {}
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
|
pub fn register_dump() {
|
||||||
|
let rax: u64;
|
||||||
|
let rbx: u64 = 0;
|
||||||
|
let rcx: u64;
|
||||||
|
let rdx: u64;
|
||||||
|
let si: u64;
|
||||||
|
let di: u64;
|
||||||
|
|
||||||
|
let r8: u64; // TODO: r8-r15
|
||||||
|
let r9: u64;
|
||||||
|
let r10: u64;
|
||||||
|
let r11: u64;
|
||||||
|
let r12: u64;
|
||||||
|
let r13: u64;
|
||||||
|
let r14: u64;
|
||||||
|
let r15: u64;
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
asm!("",
|
||||||
|
out("rax") rax,
|
||||||
|
out("rcx") rcx,
|
||||||
|
out("rdx") rdx,
|
||||||
|
out("si") si,
|
||||||
|
out("di") di,
|
||||||
|
out("r8") r8,
|
||||||
|
out("r9") r9,
|
||||||
|
out("r10") r10,
|
||||||
|
out("r11") r11,
|
||||||
|
out("r12") r12,
|
||||||
|
out("r13") r13,
|
||||||
|
out("r14") r14,
|
||||||
|
out("r15") r15,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
log::error!(
|
||||||
|
"Kernel Panic!\r
|
||||||
|
Register Dump\r
|
||||||
|
rax: {:#x}\r
|
||||||
|
rbx: {:#x}\r
|
||||||
|
rcx: {:#x}\r
|
||||||
|
rdx: {:#x}\r
|
||||||
|
si : {:#x}\r
|
||||||
|
di : {:#x}\r
|
||||||
|
r8 : {:#x}\r
|
||||||
|
r9 : {:#x}\r
|
||||||
|
r11: {:#x}\r
|
||||||
|
r12: {:#x}\r
|
||||||
|
r13: {:#x}\r
|
||||||
|
r14: {:#x}\r
|
||||||
|
r15: {:#x}\r
|
||||||
|
",
|
||||||
|
rax,
|
||||||
|
rbx,
|
||||||
|
rcx,
|
||||||
|
rdx,
|
||||||
|
si,
|
||||||
|
di,
|
||||||
|
r8,
|
||||||
|
r9,
|
||||||
|
r11,
|
||||||
|
r12,
|
||||||
|
r13,
|
||||||
|
r14,
|
||||||
|
r15,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
|
@ -8,12 +8,12 @@ pub struct PciDeviceInfo {
|
||||||
pub full_class: PciFullClass,
|
pub full_class: PciFullClass,
|
||||||
pub rev_id: u8,
|
pub rev_id: u8,
|
||||||
}
|
}
|
||||||
use crate::alloc::string::ToString;
|
|
||||||
|
|
||||||
/// Enumerate PCI devices and run initialisation routines on ones we support
|
/// Enumerate PCI devices and run initialisation routines on ones we support
|
||||||
pub fn init(device_tree: &mut DeviceTree) {
|
pub fn init(device_tree: &mut DeviceTree) {
|
||||||
device_tree.devices
|
device_tree
|
||||||
.insert("Unidentified PCI".to_string(), alloc::vec![]);
|
.devices
|
||||||
|
.insert("Unidentified PCI", alloc::vec![]);
|
||||||
let mut devices = alloc::vec![];
|
let mut devices = alloc::vec![];
|
||||||
|
|
||||||
for bus in 0..=255 {
|
for bus in 0..=255 {
|
||||||
|
@ -23,6 +23,7 @@ pub fn init(device_tree: &mut DeviceTree) {
|
||||||
let id = device_info.device_id.id;
|
let id = device_info.device_id.id;
|
||||||
use Vendor::*;
|
use Vendor::*;
|
||||||
let (dev_type, dev_name) = match (vendor, id) {
|
let (dev_type, dev_name) = match (vendor, id) {
|
||||||
|
(VMWareInc, 1029) => ("GPUs", "SVGAII PCI GPU"),
|
||||||
(Qemu, 4369) => ("GPUs", "QEMU VGA"),
|
(Qemu, 4369) => ("GPUs", "QEMU VGA"),
|
||||||
(VirtIO, 4176) => ("GPUs", "VirtIO PCI GPU"),
|
(VirtIO, 4176) => ("GPUs", "VirtIO PCI GPU"),
|
||||||
(CirrusLogic, 184) => ("GPUs", "Cirrus SVGA"), //GD 5446?
|
(CirrusLogic, 184) => ("GPUs", "Cirrus SVGA"), //GD 5446?
|
||||||
|
@ -45,7 +46,8 @@ pub fn init(device_tree: &mut DeviceTree) {
|
||||||
pci_info.set_attribute("id", id);
|
pci_info.set_attribute("id", id);
|
||||||
pci_info.set_attribute("device", device_info.device);
|
pci_info.set_attribute("device", device_info.device);
|
||||||
pci_info.set_attribute("vendor", vendor);
|
pci_info.set_attribute("vendor", vendor);
|
||||||
pci_info.set_attribute("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);
|
dev.set_child(pci_info);
|
||||||
devices.push((dev_type, dev));
|
devices.push((dev_type, dev));
|
||||||
}
|
}
|
||||||
|
@ -66,7 +68,8 @@ pub fn check_device(bus: u8, device: u8) -> Option<PciDeviceInfo> {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
let reg2 = unsafe { pci_config_read(bus, device, 0, 0x8) };
|
let (reg2, addr) = unsafe { pci_config_read_2(bus, device, 0, 0x8) };
|
||||||
|
log::debug!("pci device-({}) addr {} is {}", device, addr, reg2);
|
||||||
let class = ((reg2 >> 16) & 0x0000_FFFF) as u16;
|
let class = ((reg2 >> 16) & 0x0000_FFFF) as u16;
|
||||||
let pci_class = PciFullClass::from_u16(class);
|
let pci_class = PciFullClass::from_u16(class);
|
||||||
let header_type = get_header_type(bus, device, 0);
|
let header_type = get_header_type(bus, device, 0);
|
||||||
|
@ -269,8 +272,7 @@ impl Display for Vendor {
|
||||||
|
|
||||||
use core::fmt::Display;
|
use core::fmt::Display;
|
||||||
|
|
||||||
use x86_64::instructions::port::Port;
|
use {crate::device_tree::DeviceTree, x86_64::instructions::port::Port};
|
||||||
use crate::device_tree::DeviceTree;
|
|
||||||
|
|
||||||
#[allow(non_camel_case_types, dead_code)]
|
#[allow(non_camel_case_types, dead_code)]
|
||||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||||
|
@ -458,9 +460,7 @@ unsafe fn pci_config_read(bus: u8, device: u8, func: u8, offset: u8) -> u32 {
|
||||||
let func = func as u32;
|
let func = func as u32;
|
||||||
let offset = offset as u32;
|
let offset = offset as u32;
|
||||||
// construct address param
|
// construct address param
|
||||||
let address =
|
let address = (bus << 16) | (device << 11) | (func << 8) | (offset & 0xFC) | 0x8000_0000;
|
||||||
((bus << 16) | (device << 11) | (func << 8) | (offset & 0xFC) | 0x8000_0000) as u32;
|
|
||||||
|
|
||||||
// write address
|
// write address
|
||||||
Port::new(0xCF8).write(address);
|
Port::new(0xCF8).write(address);
|
||||||
|
|
||||||
|
@ -468,6 +468,20 @@ unsafe fn pci_config_read(bus: u8, device: u8, func: u8, offset: u8) -> u32 {
|
||||||
Port::new(0xCFC).read()
|
Port::new(0xCFC).read()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsafe fn pci_config_read_2(bus: u8, device: u8, func: u8, offset: u8) -> (u32, u32) {
|
||||||
|
let bus = bus as u32;
|
||||||
|
let device = device as u32;
|
||||||
|
let func = func as u32;
|
||||||
|
let offset = offset as u32;
|
||||||
|
// construct address param
|
||||||
|
let address = (bus << 16) | (device << 11) | (func << 8) | (offset & 0xFC) | 0x8000_0000;
|
||||||
|
// write address
|
||||||
|
Port::new(0xCF8).write(address);
|
||||||
|
|
||||||
|
// read data
|
||||||
|
(Port::new(0xCFC).read(), address)
|
||||||
|
}
|
||||||
|
|
||||||
unsafe fn pci_config_write(bus: u8, device: u8, func: u8, offset: u8, value: u32) {
|
unsafe fn pci_config_write(bus: u8, device: u8, func: u8, offset: u8, value: u32) {
|
||||||
let bus = bus as u32;
|
let bus = bus as u32;
|
||||||
let device = device as u32;
|
let device = device as u32;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use {
|
use {
|
||||||
core::{ptr::NonNull},
|
core::ptr::NonNull,
|
||||||
virtio_drivers::{BufferDirection, Hal, PhysAddr},
|
virtio_drivers::{BufferDirection, Hal, PhysAddr},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,36 +1,36 @@
|
||||||
use {
|
use {
|
||||||
crate::alloc::string::ToString,
|
// crate::alloc::string::ToString,
|
||||||
alloc::{string::String, vec::Vec},
|
alloc::vec::Vec,
|
||||||
clparse::Arguments,
|
// clparse::Arguments,
|
||||||
core::fmt::{Debug, Display},
|
// core::fmt::{Debug, Display},
|
||||||
log::trace,
|
// log::trace,
|
||||||
xml::XMLElement,
|
// xml::XMLElement,
|
||||||
};
|
};
|
||||||
pub type BootModules = Vec<BootModule>;
|
pub type BootModules<'a> = Vec<BootModule<'a>>;
|
||||||
|
|
||||||
pub struct BootModule {
|
pub struct BootModule<'a> {
|
||||||
pub path: String,
|
pub path: &'a str,
|
||||||
pub bytes: Vec<u8>,
|
pub bytes: &'a [u8],
|
||||||
pub cmd: String,
|
pub cmd: &'a str,
|
||||||
}
|
}
|
||||||
impl BootModule {
|
impl<'a> BootModule<'a> {
|
||||||
pub fn new(path: String, bytes: Vec<u8>, cmd: String) -> Self {
|
pub fn new(path: &'a str, bytes: &'a [u8], cmd: &'a str) -> Self {
|
||||||
Self { path, bytes, cmd }
|
Self { path, bytes, cmd }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn build_cmd<T: Display + Debug>(name: T, cmdline: T) -> XMLElement {
|
// pub fn build_cmd<T: Display + Debug>(name: T, cmdline: T) -> XMLElement {
|
||||||
let mut cmdline = cmdline.to_string();
|
// let mut cmdline = cmdline.to_string();
|
||||||
cmdline.pop();
|
// cmdline.pop();
|
||||||
cmdline.remove(0);
|
// cmdline.remove(0);
|
||||||
|
|
||||||
let cmd = Arguments::parse(cmdline.to_string()).unwrap();
|
// let cmd = Arguments::parse(cmdline.to_string()).unwrap();
|
||||||
trace!("Cmdline: {cmd:?}");
|
// trace!("Cmdline: {cmd:?}");
|
||||||
|
|
||||||
let mut clo = XMLElement::new(name);
|
// let mut clo = XMLElement::new(name);
|
||||||
for (key, value) in cmd.arguments {
|
// for (key, value) in cmd.arguments {
|
||||||
clo.set_attribute(key, value);
|
// clo.set_attribute(key, value);
|
||||||
}
|
// }
|
||||||
trace!("command line object: {:?}", clo);
|
// trace!("command line object: {:?}", clo);
|
||||||
clo
|
// clo
|
||||||
}
|
// }
|
||||||
|
|
|
@ -1,11 +1,7 @@
|
||||||
//! A tree of hardware devices
|
//! A tree of hardware devices
|
||||||
|
|
||||||
use {
|
use {alloc::vec::Vec, core::fmt, hashbrown::HashMap};
|
||||||
crate::alloc::string::ToString,
|
|
||||||
alloc::{string::String, vec::Vec},
|
|
||||||
core::fmt,
|
|
||||||
hashbrown::HashMap,
|
|
||||||
};
|
|
||||||
/// A device object.
|
/// A device object.
|
||||||
/// TODO define device
|
/// TODO define device
|
||||||
pub type Device = xml::XMLElement;
|
pub type Device = xml::XMLElement;
|
||||||
|
@ -13,17 +9,19 @@ pub type Device = xml::XMLElement;
|
||||||
/// A tree of devices
|
/// A tree of devices
|
||||||
// TODO: alphabetize this list
|
// TODO: alphabetize this list
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct DeviceTree {
|
pub struct DeviceTree<'a> {
|
||||||
/// The device tree
|
/// The device tree
|
||||||
pub devices: HashMap<String, Vec<Device>>,
|
pub devices: HashMap<&'a str, Vec<Device>>,
|
||||||
}
|
}
|
||||||
impl DeviceTree {
|
impl<'a> DeviceTree<'a> {
|
||||||
/// Build the device tree. Does not populate the device tree
|
/// Build the device tree. Does not populate the device tree
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
let mut dt = Self {
|
let mut dt = Self {
|
||||||
devices: HashMap::new(),
|
devices: HashMap::new(),
|
||||||
};
|
};
|
||||||
device_tree!(dt, [
|
device_tree!(
|
||||||
|
dt,
|
||||||
|
[
|
||||||
"Mice",
|
"Mice",
|
||||||
"Keyboards",
|
"Keyboards",
|
||||||
"Controllers",
|
"Controllers",
|
||||||
|
@ -38,13 +36,13 @@ impl DeviceTree {
|
||||||
"Serial Ports",
|
"Serial Ports",
|
||||||
"Cameras",
|
"Cameras",
|
||||||
"Biometric Devices",
|
"Biometric Devices",
|
||||||
]);
|
]
|
||||||
|
);
|
||||||
dt
|
dt
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
use crate::{utils::TAB, device_tree};
|
use crate::{device_tree, tab, utils::TAB};
|
||||||
use crate::tab;
|
impl<'a> fmt::Display for DeviceTree<'a> {
|
||||||
impl fmt::Display for DeviceTree {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
writeln!(f)?;
|
writeln!(f)?;
|
||||||
for (device_type, devices) in &self.devices {
|
for (device_type, devices) in &self.devices {
|
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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
281
kernel/src/holeybytes/ecah.rs
Normal file
281
kernel/src/holeybytes/ecah.rs
Normal file
|
@ -0,0 +1,281 @@
|
||||||
|
//! Environment call handling routines
|
||||||
|
|
||||||
|
use {alloc::boxed::Box, core::cell::LazyCell, hbvm::mem::Address};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
holeybytes::{
|
||||||
|
kernel_services::{
|
||||||
|
block_read, dt_msg_handler::dt_msg_handler, logging_service::log_msg_handler,
|
||||||
|
service_definition_service::sds_msg_handler,
|
||||||
|
},
|
||||||
|
ExecThread,
|
||||||
|
},
|
||||||
|
kmain::EXECUTOR,
|
||||||
|
task::Executor,
|
||||||
|
};
|
||||||
|
|
||||||
|
use {
|
||||||
|
super::Vm,
|
||||||
|
crate::{arch, ipc::buffer::IpcBuffer, kmain::IPC_BUFFERS},
|
||||||
|
hbvm::value::Value,
|
||||||
|
log::{debug, error, info, trace},
|
||||||
|
};
|
||||||
|
|
||||||
|
#[cfg(target_arch = "x86_64")]
|
||||||
|
#[inline(always)]
|
||||||
|
unsafe fn x86_out<T: x86_64::instructions::port::PortWrite>(address: u16, value: T) {
|
||||||
|
x86_64::instructions::port::Port::new(address).write(value);
|
||||||
|
}
|
||||||
|
#[cfg(target_arch = "x86_64")]
|
||||||
|
#[inline(always)]
|
||||||
|
unsafe fn x86_in<T: x86_64::instructions::port::PortRead>(address: u16) -> T {
|
||||||
|
x86_64::instructions::port::Port::new(address).read()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn handler(vm: &mut Vm, pid: &usize) {
|
||||||
|
let ecall_number = vm.registers[2].cast::<u64>();
|
||||||
|
|
||||||
|
match ecall_number {
|
||||||
|
0 => {
|
||||||
|
// TODO: explode computer
|
||||||
|
// hello world ecall
|
||||||
|
for x in 0u64..=255 {
|
||||||
|
vm.registers[x as usize] = x.into();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
1 => {
|
||||||
|
// Make buffer
|
||||||
|
|
||||||
|
let bounded = match vm.registers[3] {
|
||||||
|
Value(0) => false,
|
||||||
|
Value(1) => true,
|
||||||
|
_ => {
|
||||||
|
panic!("Bad");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let length = vm.registers[4].cast::<u64>();
|
||||||
|
|
||||||
|
let mut buffs = IPC_BUFFERS.lock();
|
||||||
|
|
||||||
|
let buff_id = arch::hardware_random_u64();
|
||||||
|
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 => {
|
||||||
|
// Send a message to a buffer
|
||||||
|
let buffer_id = vm.registers[3].cast::<u64>();
|
||||||
|
let mem_addr = vm.registers[4].cast::<u64>();
|
||||||
|
let length = vm.registers[5].cast::<u64>() as usize;
|
||||||
|
trace!("IPC address: {:?}", mem_addr);
|
||||||
|
|
||||||
|
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:?}"),
|
||||||
|
},
|
||||||
|
1 => match log_msg_handler(vm, mem_addr, length) {
|
||||||
|
Ok(()) => {}
|
||||||
|
Err(_) => log::error!("Improper log format"),
|
||||||
|
},
|
||||||
|
2 => {
|
||||||
|
use crate::holeybytes::kernel_services::mem_serve::memory_msg_handler;
|
||||||
|
match memory_msg_handler(vm, mem_addr, length) {
|
||||||
|
Ok(_) => {}
|
||||||
|
Err(_) => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[cfg(target_arch = "x86_64")]
|
||||||
|
3 => {
|
||||||
|
let msg_vec = block_read(mem_addr, length);
|
||||||
|
let msg_type = msg_vec[0];
|
||||||
|
match msg_type {
|
||||||
|
0 => unsafe {
|
||||||
|
let size = msg_vec[1];
|
||||||
|
let addr =
|
||||||
|
u16::from_le_bytes(msg_vec[2..4].try_into().unwrap_unchecked());
|
||||||
|
let value = match size {
|
||||||
|
0 => x86_in::<u8>(addr) as u64,
|
||||||
|
1 => x86_in::<u16>(addr) as u64,
|
||||||
|
2 => x86_in::<u32>(addr) as u64,
|
||||||
|
_ => panic!("Trying to read size other than: 8, 16, 32 from port."),
|
||||||
|
};
|
||||||
|
// info!("Read the value {} from address {}", value, addr);
|
||||||
|
vm.registers[1] = hbvm::value::Value(value);
|
||||||
|
},
|
||||||
|
1 => unsafe {
|
||||||
|
let size = msg_vec[1];
|
||||||
|
let addr =
|
||||||
|
u16::from_le_bytes(msg_vec[2..4].try_into().unwrap_unchecked());
|
||||||
|
// info!("Setting address {}", addr);
|
||||||
|
|
||||||
|
match size {
|
||||||
|
0 => x86_out(addr, msg_vec[4]),
|
||||||
|
1 => x86_out(
|
||||||
|
addr,
|
||||||
|
u16::from_le_bytes(msg_vec[4..6].try_into().unwrap_unchecked()),
|
||||||
|
),
|
||||||
|
2 => x86_out(
|
||||||
|
addr,
|
||||||
|
u32::from_le_bytes(msg_vec[4..8].try_into().unwrap_unchecked()),
|
||||||
|
),
|
||||||
|
_ => panic!("How?"),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[cfg(not(target_arch = "x86_64"))]
|
||||||
|
3 => unimplemented!("TODO: implement whatever buffer 3 does for no x86_64"),
|
||||||
|
// source of rng
|
||||||
|
4 => {
|
||||||
|
let block = block_read(mem_addr, length);
|
||||||
|
block.chunks_mut(8.min(length)).for_each(|chunk| {
|
||||||
|
chunk.clone_from_slice(
|
||||||
|
&crate::arch::hardware_random_u64().to_le_bytes()[..chunk.len()],
|
||||||
|
);
|
||||||
|
});
|
||||||
|
vm.registers[1] = hbvm::value::Value(mem_addr);
|
||||||
|
}
|
||||||
|
5 => match dt_msg_handler(vm, mem_addr, length) {
|
||||||
|
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 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
4 => {
|
||||||
|
let buffer_id = vm.registers[3].cast::<u64>();
|
||||||
|
let map_ptr = vm.registers[4].cast::<u64>();
|
||||||
|
let max_length = vm.registers[5].cast::<u64>();
|
||||||
|
let mut buffs = IPC_BUFFERS.lock();
|
||||||
|
let buff: &mut IpcBuffer = match buffs.get_mut(&buffer_id) {
|
||||||
|
Some(buff) => buff,
|
||||||
|
None => panic!(
|
||||||
|
"Failed to get buffer: id={buffer_id}, ptr={map_ptr}, length={max_length}"
|
||||||
|
),
|
||||||
|
};
|
||||||
|
|
||||||
|
let msg = match buff.pop() {
|
||||||
|
Ok(msg) => msg,
|
||||||
|
Err(_) => return,
|
||||||
|
};
|
||||||
|
if msg.len() > unsafe { max_length.try_into().unwrap_unchecked() } {
|
||||||
|
info!("{}", max_length);
|
||||||
|
error!("Message is too long to map in.");
|
||||||
|
} else {
|
||||||
|
unsafe {
|
||||||
|
let ptr = map_ptr as *mut u8;
|
||||||
|
ptr.copy_from_nonoverlapping(msg.as_ptr(), msg.len());
|
||||||
|
}
|
||||||
|
|
||||||
|
debug!("Recieve {:?} from Buffer({})", msg, buffer_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
5 => {
|
||||||
|
#[cfg(target_arch = "x86_64")]
|
||||||
|
{
|
||||||
|
let r2 = vm.registers[2].cast::<u64>();
|
||||||
|
let x = hbvm::value::Value(unsafe { x86_in::<u8>(r2 as u16) } as u64);
|
||||||
|
// info!("Read {:?} from Port {:?}", x, r2);
|
||||||
|
vm.registers[3] = x
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum LogError {
|
||||||
|
NoMessages,
|
||||||
|
InvalidLogFormat,
|
||||||
|
}
|
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(())
|
||||||
|
}
|
22
kernel/src/holeybytes/kernel_services/mem_serve.idl
Normal file
22
kernel/src/holeybytes/kernel_services/mem_serve.idl
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
enum MemoryServiceResult {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@alignment(4096)
|
||||||
|
type PageAlignedPointer = pointer;
|
||||||
|
|
||||||
|
type RID = u64;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@nonexhaustive
|
||||||
|
@version 1.0
|
||||||
|
protocol MemoryService {
|
||||||
|
@validator(page_count, Range(1..16))
|
||||||
|
fn map_pages(page_count: u8, ptr: Optional<PageAlignedPointer>) -> MemoryServiceResult;
|
||||||
|
fn unmap_pages(ptr: PageAlignedPointer) -> MemoryServiceResult;
|
||||||
|
// ptr must be page aligned and already mapped from map_pages
|
||||||
|
fn map_hardware(hw: RID, ptr: PageAlignedPointer) -> MemoryServiceResult;
|
||||||
|
fn unmap_hardware(hw: RID) -> MemoryServiceResult;
|
||||||
|
|
||||||
|
}
|
122
kernel/src/holeybytes/kernel_services/mem_serve.rs
Normal file
122
kernel/src/holeybytes/kernel_services/mem_serve.rs
Normal file
|
@ -0,0 +1,122 @@
|
||||||
|
use {
|
||||||
|
crate::holeybytes::{kernel_services::block_read, Vm},
|
||||||
|
alloc::alloc::{alloc, dealloc},
|
||||||
|
core::alloc::Layout,
|
||||||
|
log::{debug, info},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub enum MemoryServiceError {
|
||||||
|
InvalidMemoryFormat,
|
||||||
|
}
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum MemoryQuotaType {
|
||||||
|
NoQuota = 0,
|
||||||
|
SoftQuota = 1,
|
||||||
|
HardQuota = 2,
|
||||||
|
KillQuota = 3,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn alloc_page(vm: &mut Vm, _mem_addr: u64, _length: usize) -> Result<(), MemoryServiceError> {
|
||||||
|
let ptr = unsafe { alloc(Layout::from_size_align_unchecked(4096, 8)) };
|
||||||
|
info!("Block address: {:?}", ptr);
|
||||||
|
vm.registers[1] = hbvm::value::Value(ptr as u64);
|
||||||
|
vm.registers[2] = hbvm::value::Value(4096);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
unsafe fn memset(dest: *mut u8, src: *const u8, count: usize, size: usize) {
|
||||||
|
let total_size = count * size;
|
||||||
|
src.copy_to_nonoverlapping(dest, size);
|
||||||
|
|
||||||
|
let mut copied = size;
|
||||||
|
|
||||||
|
while copied < total_size {
|
||||||
|
let copy_size = copied.min(total_size - copied);
|
||||||
|
dest.add(copied).copy_from_nonoverlapping(dest, copy_size);
|
||||||
|
copied += copy_size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn memory_msg_handler(
|
||||||
|
vm: &mut Vm,
|
||||||
|
mem_addr: u64,
|
||||||
|
length: usize,
|
||||||
|
) -> Result<(), MemoryServiceError> {
|
||||||
|
let msg_vec = block_read(mem_addr, length);
|
||||||
|
let msg_type = msg_vec[0];
|
||||||
|
match msg_type {
|
||||||
|
0 => unsafe {
|
||||||
|
let page_count = msg_vec[1];
|
||||||
|
|
||||||
|
let ptr = alloc(Layout::from_size_align_unchecked(
|
||||||
|
page_count as usize * 4096,
|
||||||
|
8,
|
||||||
|
));
|
||||||
|
|
||||||
|
log::debug!("Allocating {} pages @ {:x}", page_count, ptr as u64);
|
||||||
|
|
||||||
|
vm.registers[1] = hbvm::value::Value(ptr as u64);
|
||||||
|
log::debug!("Kernel ptr: {:x}", ptr as u64);
|
||||||
|
},
|
||||||
|
|
||||||
|
1 => unsafe {
|
||||||
|
let page_count = msg_vec[1];
|
||||||
|
|
||||||
|
let mptr_raw: [u8; 8] = msg_vec[2..10].try_into().unwrap();
|
||||||
|
let mptr: u64 = u64::from_le_bytes(mptr_raw);
|
||||||
|
log::debug!("Deallocating {} pages @ {:x}", page_count, mptr);
|
||||||
|
|
||||||
|
dealloc(
|
||||||
|
mptr as *mut u8,
|
||||||
|
Layout::from_size_align_unchecked(page_count as usize * 4096, 8),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
2 => {
|
||||||
|
use MemoryQuotaType::*;
|
||||||
|
let quota_type = match msg_vec[1] {
|
||||||
|
0 => NoQuota,
|
||||||
|
1 => SoftQuota,
|
||||||
|
2 => HardQuota,
|
||||||
|
3 => KillQuota,
|
||||||
|
_ => NoQuota,
|
||||||
|
};
|
||||||
|
let hid_raw: [u8; 8] = msg_vec[2..10].try_into().unwrap();
|
||||||
|
let hid: u64 = u64::from_le_bytes(hid_raw);
|
||||||
|
let pid_raw: [u8; 8] = msg_vec[10..18].try_into().unwrap();
|
||||||
|
let pid: u64 = u64::from_le_bytes(pid_raw);
|
||||||
|
debug!(
|
||||||
|
"Setting HID-{:x}:PID-{:x}'s quota type to {:?}",
|
||||||
|
hid, pid, quota_type
|
||||||
|
)
|
||||||
|
}
|
||||||
|
3 => {
|
||||||
|
let page_count = msg_vec[1];
|
||||||
|
log::debug!(" {} pages", page_count);
|
||||||
|
}
|
||||||
|
4 => unsafe {
|
||||||
|
let count = u64::from_le_bytes(msg_vec[1..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;
|
||||||
|
debug_assert!(src.addr() & 0xFFFF000000000000 != 0);
|
||||||
|
debug_assert!(dest.addr() & 0xFFFF000000000000 != 0);
|
||||||
|
src.copy_to_nonoverlapping(dest, count);
|
||||||
|
},
|
||||||
|
5 => unsafe {
|
||||||
|
let count = u64::from_le_bytes(msg_vec[1..9].try_into().unwrap_unchecked()) as usize;
|
||||||
|
let size = u64::from_le_bytes(msg_vec[9..17].try_into().unwrap_unchecked()) as usize;
|
||||||
|
let src =
|
||||||
|
u64::from_le_bytes(msg_vec[17..25].try_into().unwrap_unchecked()) as *const u8;
|
||||||
|
let dest = u64::from_le_bytes(msg_vec[25..33].try_into().unwrap_unchecked()) as *mut u8;
|
||||||
|
debug_assert!(src.addr() & 0xFFFF000000000000 != 0);
|
||||||
|
debug_assert!(dest.addr() & 0xFFFF000000000000 != 0);
|
||||||
|
memset(dest, src, count, size);
|
||||||
|
},
|
||||||
|
_ => {
|
||||||
|
log::debug!("Unknown memory service message type: {}", msg_type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
11
kernel/src/holeybytes/kernel_services/mod.rs
Normal file
11
kernel/src/holeybytes/kernel_services/mod.rs
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
use core::slice;
|
||||||
|
|
||||||
|
pub mod dt_msg_handler;
|
||||||
|
pub mod logging_service;
|
||||||
|
pub mod mem_serve;
|
||||||
|
pub mod service_definition_service;
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn block_read<'a>(mem_addr: u64, length: usize) -> &'a mut [u8] {
|
||||||
|
unsafe { slice::from_raw_parts_mut(mem_addr as *mut _, length) }
|
||||||
|
}
|
|
@ -0,0 +1,106 @@
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
arch::hardware_random_u64,
|
||||||
|
holeybytes::{kernel_services::block_read, Vm},
|
||||||
|
ipc::{buffer::IpcBuffer, protocol::Protocol},
|
||||||
|
kmain::IPC_BUFFERS,
|
||||||
|
},
|
||||||
|
hashbrown::HashMap,
|
||||||
|
log::{info, trace},
|
||||||
|
spin::{lazy::Lazy, Mutex},
|
||||||
|
};
|
||||||
|
pub struct Services<'a>(HashMap<u64, Protocol<'a>>);
|
||||||
|
pub static SERVICES: Lazy<Mutex<Services>> = Lazy::new(|| {
|
||||||
|
let mut dt = Services(HashMap::new());
|
||||||
|
dt.0.insert(0, Protocol::void());
|
||||||
|
Mutex::new(dt)
|
||||||
|
});
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum ServiceError {
|
||||||
|
InvalidFormat,
|
||||||
|
}
|
||||||
|
pub fn sds_msg_handler(vm: &mut Vm, mem_addr: u64, length: usize) -> Result<(), ServiceError> {
|
||||||
|
let msg_vec = block_read(mem_addr, length);
|
||||||
|
let sds_event_type: ServiceEventType = msg_vec[0].into();
|
||||||
|
let strptr = u64::from_le_bytes(msg_vec[1..9].try_into().unwrap());
|
||||||
|
let strlen = u64::from_le_bytes(msg_vec[9..17].try_into().unwrap()) as usize;
|
||||||
|
let string_vec = block_read(strptr, strlen);
|
||||||
|
let string = core::str::from_utf8(string_vec).expect("Our bytes should be valid utf8");
|
||||||
|
|
||||||
|
use ServiceEventType::*;
|
||||||
|
match sds_event_type {
|
||||||
|
CreateService => {
|
||||||
|
let ret = sds_create_service(string);
|
||||||
|
vm.registers[1] = hbvm::value::Value(ret as u64);
|
||||||
|
}
|
||||||
|
DeleteService => todo!(),
|
||||||
|
SearchServices => {
|
||||||
|
let ret = sds_search_service(string);
|
||||||
|
vm.registers[1] = hbvm::value::Value(ret as u64);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// let buffer_id_raw = &msg_vec[0..8];
|
||||||
|
// let mut arr = [0u8; 8];
|
||||||
|
// arr.copy_from_slice(&buffer_id_raw);
|
||||||
|
// let buffer_id = u64::from_le_bytes(arr);
|
||||||
|
// info!("BufferID({:x?})", buffer_id);
|
||||||
|
|
||||||
|
// let mut services = SERVICES.lock();
|
||||||
|
// let string = String::from_utf8(msg_vec).expect("Our bytes should be valid utf8");
|
||||||
|
// use core::borrow::BorrowMut;
|
||||||
|
// services.borrow_mut().0.insert(buffer_id, string);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
enum ServiceEventType {
|
||||||
|
CreateService = 0,
|
||||||
|
// UpdateService = 1,
|
||||||
|
DeleteService = 2,
|
||||||
|
SearchServices = 3,
|
||||||
|
}
|
||||||
|
impl From<u8> for ServiceEventType {
|
||||||
|
fn from(value: u8) -> Self {
|
||||||
|
use self::*;
|
||||||
|
match value {
|
||||||
|
0 => Self::CreateService,
|
||||||
|
// 1 =>
|
||||||
|
2 => Self::DeleteService,
|
||||||
|
3 => Self::SearchServices,
|
||||||
|
10 => {
|
||||||
|
info!("TEST");
|
||||||
|
panic!()
|
||||||
|
}
|
||||||
|
1_u8 | 4_u8..=u8::MAX => todo!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sds_create_service(protocol: &'static str) -> u64 {
|
||||||
|
let buff_id = hardware_random_u64();
|
||||||
|
let mut services = SERVICES.lock();
|
||||||
|
let mut buffers = IPC_BUFFERS.lock();
|
||||||
|
|
||||||
|
let protocol_ = Protocol::from(protocol);
|
||||||
|
let mut buff = IpcBuffer::new(false, 0);
|
||||||
|
|
||||||
|
services.0.insert(buff_id, protocol_.clone());
|
||||||
|
buff.protocol = protocol_;
|
||||||
|
buffers.insert(buff_id, buff);
|
||||||
|
|
||||||
|
trace!("BufferID({}) => {}", buff_id, protocol);
|
||||||
|
// let a: protocol::Protocol = protocol.into();
|
||||||
|
buff_id
|
||||||
|
}
|
||||||
|
pub fn sds_search_service(protocol: &str) -> u64 {
|
||||||
|
let services = SERVICES.lock();
|
||||||
|
let compare = Protocol::from(protocol);
|
||||||
|
for (bid, protocol_canidate) in &services.0 {
|
||||||
|
trace!("BID-{bid} protocol_canidate {:?}", protocol_canidate);
|
||||||
|
if protocol_canidate == &compare {
|
||||||
|
trace!("BufferID({}) => {}", bid, protocol);
|
||||||
|
return *bid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
0
|
||||||
|
}
|
68
kernel/src/holeybytes/mem.rs
Normal file
68
kernel/src/holeybytes/mem.rs
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
//! Security? Multiple address spaces? What are you talking about
|
||||||
|
//! young adventurer. In this temple, we know no such words.
|
||||||
|
//!
|
||||||
|
//! Want your program to override other program's data or even the
|
||||||
|
//! data of the kernel itself? Sure. This right shall not be infringed.
|
||||||
|
|
||||||
|
use hbvm::mem::Address;
|
||||||
|
|
||||||
|
fn calc_start_of_page(ptr: u64) -> u64 {
|
||||||
|
let _page_aligned = false;
|
||||||
|
if ptr % 4096 == 0 {
|
||||||
|
// page_aligned = true;
|
||||||
|
return ptr / 4096;
|
||||||
|
}
|
||||||
|
panic!("unaligned");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct Memory {
|
||||||
|
// TODO: map page aligned segments of memory into a table or some sort here
|
||||||
|
logger: hbvm::mem::InstrLogger,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Memory {
|
||||||
|
#[cfg(target_arch = "x86_64")]
|
||||||
|
fn read_device(_addr: Address) {
|
||||||
|
//unsafe {
|
||||||
|
//
|
||||||
|
// x86_64::instructions::port::Port::new(addr.get()).read()
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl hbvm::mem::Memory for Memory {
|
||||||
|
#[inline(always)]
|
||||||
|
unsafe fn load(
|
||||||
|
&mut self,
|
||||||
|
addr: Address,
|
||||||
|
target: *mut u8,
|
||||||
|
count: usize,
|
||||||
|
) -> Result<(), hbvm::mem::LoadError> {
|
||||||
|
core::ptr::copy_nonoverlapping(addr.get() as *const u8, target, count);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
unsafe fn store(
|
||||||
|
&mut self,
|
||||||
|
addr: Address,
|
||||||
|
source: *const u8,
|
||||||
|
count: usize,
|
||||||
|
) -> Result<(), hbvm::mem::StoreError> {
|
||||||
|
core::ptr::copy_nonoverlapping(source, addr.get() as *mut u8, count);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
unsafe fn prog_read<T: Copy>(&mut self, addr: Address) -> T {
|
||||||
|
(addr.get() as *const T).read()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn log_instr(&mut self, at: Address, regs: &[hbvm::value::Value]) {
|
||||||
|
log::debug!("exec: [{:02x}] {}", at.get(), unsafe {
|
||||||
|
self.logger.display_instr(at, regs)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
111
kernel/src/holeybytes/mod.rs
Normal file
111
kernel/src/holeybytes/mod.rs
Normal file
|
@ -0,0 +1,111 @@
|
||||||
|
mod ecah;
|
||||||
|
pub mod kernel_services;
|
||||||
|
mod mem;
|
||||||
|
|
||||||
|
use {
|
||||||
|
alloc::alloc::{alloc, dealloc},
|
||||||
|
core::{
|
||||||
|
alloc::Layout,
|
||||||
|
future::Future,
|
||||||
|
pin::Pin,
|
||||||
|
task::{Context, Poll},
|
||||||
|
},
|
||||||
|
hbvm::{
|
||||||
|
mem::{softpaging::HandlePageFault, Address},
|
||||||
|
VmRunError, VmRunOk,
|
||||||
|
},
|
||||||
|
log::error,
|
||||||
|
};
|
||||||
|
|
||||||
|
const STACK_SIZE: usize = 1024 * 1024;
|
||||||
|
const TIMER_QUOTIENT: usize = 1000;
|
||||||
|
type Vm = hbvm::Vm<mem::Memory, TIMER_QUOTIENT>;
|
||||||
|
|
||||||
|
pub struct ExecThread {
|
||||||
|
vm: Vm,
|
||||||
|
stack_bottom: *mut u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
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: &[u8], entrypoint: Address) -> Self {
|
||||||
|
let mut vm = Vm::new(
|
||||||
|
mem::Memory::default(),
|
||||||
|
Address::new(program.as_ptr() as u64 + entrypoint.get()),
|
||||||
|
);
|
||||||
|
|
||||||
|
let stack_bottom = allocate_stack();
|
||||||
|
|
||||||
|
vm.write_reg(254, (stack_bottom as usize + STACK_SIZE - 1) as u64);
|
||||||
|
|
||||||
|
ExecThread { vm, stack_bottom }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'p> Drop for ExecThread {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
unsafe { dealloc(self.stack_bottom, stack_layout()) };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'p> Future for ExecThread {
|
||||||
|
type Output = Result<(), VmRunError>;
|
||||||
|
|
||||||
|
#[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,
|
||||||
|
cx.ext()
|
||||||
|
.downcast_ref()
|
||||||
|
.expect("PID did not exist in Context"),
|
||||||
|
),
|
||||||
|
Ok(VmRunOk::Timer) => (),
|
||||||
|
Ok(VmRunOk::Breakpoint) => {
|
||||||
|
log::error!(
|
||||||
|
"HBVM Debug breakpoint\r\nRegister dump: {:?}",
|
||||||
|
self.vm.registers,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cx.waker().wake_by_ref();
|
||||||
|
Poll::Pending
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct PageFaultHandler;
|
||||||
|
impl HandlePageFault for PageFaultHandler {
|
||||||
|
fn page_fault(
|
||||||
|
&mut self,
|
||||||
|
reason: hbvm::mem::MemoryAccessReason,
|
||||||
|
_pagetable: &mut hbvm::mem::softpaging::paging::PageTable,
|
||||||
|
vaddr: hbvm::mem::Address,
|
||||||
|
size: hbvm::mem::softpaging::PageSize,
|
||||||
|
dataptr: *mut u8,
|
||||||
|
) -> bool {
|
||||||
|
error!("REASON: {reason} vaddr: {vaddr} size: {size:?} Dataptr {dataptr:p}");
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
const fn stack_layout() -> Layout {
|
||||||
|
unsafe { Layout::from_size_align_unchecked(STACK_SIZE, 8) }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn allocate_stack() -> *mut u8 {
|
||||||
|
unsafe { alloc(stack_layout()) }
|
||||||
|
}
|
|
@ -1,88 +0,0 @@
|
||||||
//! the system interface
|
|
||||||
|
|
||||||
// use {
|
|
||||||
// crate::ipc::message::Message,
|
|
||||||
// alloc::vec::Vec,
|
|
||||||
// crossbeam_queue::{ArrayQueue, SegQueue},
|
|
||||||
// // hbvm::engine::Engine,
|
|
||||||
// log::trace,
|
|
||||||
// HostError::MemoryError,
|
|
||||||
// };
|
|
||||||
/// Host errors
|
|
||||||
pub enum HostError {
|
|
||||||
/// A host memory error
|
|
||||||
MemoryError,
|
|
||||||
}
|
|
||||||
|
|
||||||
// / Check f0 register for the handle
|
|
||||||
// / check f1 for the message ptr
|
|
||||||
// / check f2 for the message length
|
|
||||||
// pub fn ipc_send(engine: &mut Engine) -> Result<(), HostError> {
|
|
||||||
// let _handle = engine.registers.f0;
|
|
||||||
// let message_start = engine.registers.f1;
|
|
||||||
// let message_length = engine.registers.f2;
|
|
||||||
|
|
||||||
// let mut ipc_msg: Vec<u8> = alloc::vec![];
|
|
||||||
|
|
||||||
// for x in message_start..message_start + message_length {
|
|
||||||
// let byte = engine.read_mem_addr_8(x);
|
|
||||||
// match byte {
|
|
||||||
// Ok(byte) => ipc_msg.push(byte),
|
|
||||||
// Err(_) => return Err(MemoryError),
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// log::trace!("Message bytes {:?}", ipc_msg);
|
|
||||||
// Ok(())
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // pub fn ipc_recv(_engine: &mut Engine) {}
|
|
||||||
|
|
||||||
// /// Check f0 for the buffer type
|
|
||||||
// /// 0 means an unbound buffer
|
|
||||||
// /// 1 means a bound buffer
|
|
||||||
// /// Check f1 if the buffer is bound
|
|
||||||
// ///
|
|
||||||
// /// f2 Return a handle to the sender
|
|
||||||
// /// f3 returns a handle the the reciever
|
|
||||||
// pub fn ipc_mkbuf(engine: &mut Engine) {
|
|
||||||
// match engine.registers.f0 as usize {
|
|
||||||
// 0 => {
|
|
||||||
// trace!("Making a new ipc unbound buffer");
|
|
||||||
// let _buf: SegQueue<Message> = SegQueue::new();
|
|
||||||
// }
|
|
||||||
// 1 => {
|
|
||||||
// let buf_len = engine.registers.f1 as usize;
|
|
||||||
// trace!("Making a new ipc buffer with capacity {}", buf_len);
|
|
||||||
// let _buf: ArrayQueue<Message> = ArrayQueue::new(buf_len);
|
|
||||||
// }
|
|
||||||
// _ => {}
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // pub fn rpc_discover(_engine: &mut Engine) {}
|
|
||||||
// // pub fn rpc_register(_engine: &mut Engine) {}
|
|
||||||
// // pub fn rpc_call(_engine: &mut Engine) {}
|
|
||||||
|
|
||||||
use {hbvm::vm::mem::HandlePageFault, log::error};
|
|
||||||
/// AbleOS HBVM traphandler
|
|
||||||
pub struct TrapHandler;
|
|
||||||
impl HandlePageFault for TrapHandler {
|
|
||||||
fn page_fault(
|
|
||||||
&mut self,
|
|
||||||
reason: hbvm::vm::mem::MemoryAccessReason,
|
|
||||||
memory: &mut hbvm::vm::mem::Memory,
|
|
||||||
vaddr: u64,
|
|
||||||
size: hbvm::vm::mem::PageSize,
|
|
||||||
dataptr: *mut u8,
|
|
||||||
) -> bool {
|
|
||||||
error!(
|
|
||||||
"REASON: {}
|
|
||||||
memory: {:?}
|
|
||||||
vaddr: {}
|
|
||||||
size: {:?}
|
|
||||||
Dataptr {:?}",
|
|
||||||
reason, memory, vaddr, size, dataptr
|
|
||||||
);
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,42 +1,72 @@
|
||||||
//!
|
//!
|
||||||
|
|
||||||
use {
|
use {
|
||||||
super::message::Message,
|
super::{message::Message, protocol::Protocol},
|
||||||
crossbeam_queue::{ArrayQueue, SegQueue},
|
crossbeam_queue::{ArrayQueue, SegQueue},
|
||||||
};
|
};
|
||||||
|
pub enum BufferTypes {
|
||||||
enum BufferTypes {
|
|
||||||
Unbound(SegQueue<Message>),
|
Unbound(SegQueue<Message>),
|
||||||
Bound(ArrayQueue<Message>),
|
Bound(ArrayQueue<Message>),
|
||||||
}
|
}
|
||||||
/// Interproccess buffer
|
/// Interproccess buffer
|
||||||
pub struct IpcBuffer {
|
pub struct IpcBuffer<'a> {
|
||||||
protocol: Protocol,
|
pub protocol: Protocol<'a>,
|
||||||
buffer: BufferTypes,
|
pub buffer: BufferTypes,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> IpcBuffer<'a> {
|
||||||
|
pub fn new(bounded: bool, length: u64) -> Self {
|
||||||
|
log::debug!(
|
||||||
|
"New IPCBuffer\r
|
||||||
|
bounded: {}\r
|
||||||
|
length: {:?}\r",
|
||||||
|
bounded,
|
||||||
|
length
|
||||||
|
);
|
||||||
|
match (bounded, length) {
|
||||||
|
(false, ..) => {
|
||||||
|
let buftype = BufferTypes::Unbound(SegQueue::new());
|
||||||
|
|
||||||
|
Self {
|
||||||
|
protocol: Protocol::void(),
|
||||||
|
buffer: buftype,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(true, length) => {
|
||||||
|
let buftype = BufferTypes::Bound(ArrayQueue::new(length as usize));
|
||||||
|
Self {
|
||||||
|
protocol: Protocol::void(),
|
||||||
|
buffer: buftype,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IpcBuffer {
|
|
||||||
/// Validate a message to match the `IPC.protocol`
|
/// Validate a message to match the `IPC.protocol`
|
||||||
pub fn validate_messages(&mut self) -> Result<(), IpcError> {
|
pub fn validate_messages(&mut self) -> Result<(), IpcError> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
pub fn push(&mut self, msg: Message) {
|
||||||
|
match &self.buffer {
|
||||||
|
BufferTypes::Unbound(buff) => buff.push(msg),
|
||||||
|
BufferTypes::Bound(buff) => buff.push(msg).unwrap(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
pub fn pop(&mut self) -> Result<Message, IpcError> {
|
||||||
|
let msg = match &self.buffer {
|
||||||
|
BufferTypes::Unbound(buff) => buff.pop(),
|
||||||
|
BufferTypes::Bound(buff) => buff.pop(),
|
||||||
|
};
|
||||||
|
match msg {
|
||||||
|
Some(msg) => return Ok(msg),
|
||||||
|
None => return Err(IpcError::NoMessagesInBuffer),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
/// Interprocess Communication Errors
|
/// Interprocess Communication Errors
|
||||||
|
#[derive(Debug)]
|
||||||
pub enum IpcError {
|
pub enum IpcError {
|
||||||
/// An invalid message error returned to the sender
|
/// An invalid message error returned to the sender
|
||||||
InvalidMessage,
|
InvalidMessage,
|
||||||
}
|
NoMessagesInBuffer,
|
||||||
|
|
||||||
/// TODO: define this, possibly as the binary form of the IDL
|
|
||||||
/// DEPEND: This depends on an IDL
|
|
||||||
pub struct Protocol {
|
|
||||||
// TODO: add in settings
|
|
||||||
// like `invalid_message_handler` with some options similar to
|
|
||||||
// `Deny` Drops the message
|
|
||||||
// `Allow` Allows invalid messages (This disables validators IPC side and relies on programs to handle invalid messages)
|
|
||||||
// `CustomFunct` a callback
|
|
||||||
// and `report_invalid_messages_to_sender`
|
|
||||||
// `True`
|
|
||||||
// `False`
|
|
||||||
// settings: PSettings,
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
//! Interprocess communication
|
//! Interprocess communication
|
||||||
pub mod buffer;
|
pub mod buffer;
|
||||||
pub mod message;
|
pub mod message;
|
||||||
|
pub mod protocol;
|
||||||
|
|
36
kernel/src/ipc/protocol.rs
Normal file
36
kernel/src/ipc/protocol.rs
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
use {alloc::vec::Vec, hashbrown::HashMap};
|
||||||
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
|
pub struct Type {}
|
||||||
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
|
pub struct Funct<'a> {
|
||||||
|
takes: Vec<&'a str>,
|
||||||
|
gives: Vec<&'a str>,
|
||||||
|
}
|
||||||
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
|
pub struct Protocol<'a> {
|
||||||
|
types: HashMap<&'a str, Type>,
|
||||||
|
fns: HashMap<&'a str, Funct<'a>>,
|
||||||
|
}
|
||||||
|
impl<'a> Protocol<'a> {
|
||||||
|
pub fn void() -> Self {
|
||||||
|
Self {
|
||||||
|
types: HashMap::new(),
|
||||||
|
fns: HashMap::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Check if a protocol defines all types it needs too
|
||||||
|
fn validate_protocol() -> bool {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<&'a str> for Protocol<'a> {
|
||||||
|
fn from(value: &'a str) -> Self {
|
||||||
|
let mut hm_t = HashMap::new();
|
||||||
|
hm_t.insert(value, Type {});
|
||||||
|
Self {
|
||||||
|
types: hm_t,
|
||||||
|
fns: HashMap::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,61 +1,162 @@
|
||||||
//! AbleOS Kernel Entrypoint
|
//! AbleOS Kernel Entrypoint
|
||||||
|
|
||||||
// use crate::arch::sloop;
|
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
bootmodules::{build_cmd, BootModules},
|
arch::hardware_random_u64,
|
||||||
|
bootmodules::BootModules,
|
||||||
|
//bootmodules::build_cmd,
|
||||||
device_tree::DeviceTree,
|
device_tree::DeviceTree,
|
||||||
scheduler::Scheduler,
|
holeybytes::ExecThread,
|
||||||
|
ipc::buffer::IpcBuffer,
|
||||||
|
task::Executor,
|
||||||
},
|
},
|
||||||
alloc::format,
|
alloc::boxed::Box,
|
||||||
log::{debug, info, trace},
|
core::cell::LazyCell,
|
||||||
|
hashbrown::HashMap,
|
||||||
|
hbvm::mem::Address,
|
||||||
|
limine::{Framebuffer, FramebufferRequest, NonNullPtr},
|
||||||
|
log::{debug, error, trace},
|
||||||
spin::{Lazy, Mutex},
|
spin::{Lazy, Mutex},
|
||||||
xml::XMLElement,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn kmain(cmdline: &str, boot_modules: BootModules) -> ! {
|
pub fn kmain(_cmdline: &str, boot_modules: BootModules) -> ! {
|
||||||
debug!("Entered kmain");
|
debug!("Entered kmain");
|
||||||
|
|
||||||
let kcmd = build_cmd("Kernel Command Line", &cmdline);
|
#[cfg(feature = "ktest")]
|
||||||
trace!("Cmdline: {kcmd:?}");
|
{
|
||||||
|
use {
|
||||||
|
crate::ktest,
|
||||||
|
log::info,
|
||||||
|
};
|
||||||
|
info!("Running tests");
|
||||||
|
ktest::test_main();
|
||||||
|
|
||||||
for (i, bm) in boot_modules.iter().enumerate() {
|
loop {}
|
||||||
let name = format!("module-{}", i);
|
|
||||||
let _bmcmd: XMLElement;
|
|
||||||
if bm.cmd.len() >= 2 {
|
|
||||||
// TODO: pass into the program
|
|
||||||
_bmcmd = build_cmd(name, bm.cmd.clone());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// let kcmd = build_cmd("Kernel Command Line", cmdline);
|
||||||
|
// trace!("Cmdline: {kcmd:?}");
|
||||||
|
|
||||||
|
// for (i, bm) in boot_modules.iter().enumerate() {
|
||||||
|
// let name = format!("module-{}", i);
|
||||||
|
// let _bmcmd: XMLElement;
|
||||||
|
// if bm.cmd.len() >= 2 {
|
||||||
|
// // TODO: pass into the program
|
||||||
|
// // Pass CMDLine into an IPCBuffer and put the ptr to the IPCBuffer in r200
|
||||||
|
// _bmcmd = build_cmd(name, bm.cmd.clone());
|
||||||
|
// log::info!("{:?}", _bmcmd);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
let dt = DEVICE_TREE.lock();
|
let dt = DEVICE_TREE.lock();
|
||||||
|
|
||||||
info!("Device Tree: {}", dt);
|
// TODO(Able): This line causes a deadlock
|
||||||
info!("Boot complete. Moving to init_system");
|
debug!("Device Tree: {}", dt);
|
||||||
|
|
||||||
|
trace!("Boot complete. Moving to init_system");
|
||||||
|
|
||||||
// TODO: schedule the disk driver from the initramfs
|
// TODO: schedule the disk driver from the initramfs
|
||||||
// TODO: schedule the filesystem driver from the initramfs
|
// TODO: schedule the filesystem driver from the initramfs
|
||||||
|
// TODO: Schedule the VFS from initramfs
|
||||||
// TODO: schedule the init system from the initramfs
|
// TODO: schedule the init system from the initramfs
|
||||||
|
|
||||||
// capabilities::example();
|
drop(dt);
|
||||||
|
|
||||||
let mut sched = Scheduler::new();
|
let fb1: &NonNullPtr<Framebuffer> = &FB_REQ.get_response().get().unwrap().framebuffers()[0];
|
||||||
|
|
||||||
sched.new_process(boot_modules[0].bytes.clone());
|
{
|
||||||
sched.new_process(boot_modules[1].bytes.clone());
|
let mut dt = DEVICE_TREE.lock();
|
||||||
|
let mut disp = xml::XMLElement::new("display_0");
|
||||||
|
|
||||||
sched.run();
|
disp.set_attribute("width", fb1.width);
|
||||||
// spin_loop();
|
disp.set_attribute("height", fb1.height);
|
||||||
|
disp.set_attribute("bpp", fb1.bpp);
|
||||||
|
disp.set_attribute("pitch", fb1.pitch);
|
||||||
|
dt.devices.insert("Displays", alloc::vec![disp]);
|
||||||
}
|
}
|
||||||
|
debug!("Graphics initialised");
|
||||||
|
debug!(
|
||||||
|
"Graphics front ptr {:?}",
|
||||||
|
fb1.address.as_ptr().unwrap() as *const u8
|
||||||
|
);
|
||||||
|
log::info!("Started AbleOS");
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
let executor = LazyCell::<Executor>::force_mut(&mut EXECUTOR);
|
||||||
|
for module in boot_modules.iter() {
|
||||||
|
let cmd = module.cmd.trim_matches('"');
|
||||||
|
let cmd_len = cmd.len() as u64;
|
||||||
|
|
||||||
|
log::info!(
|
||||||
|
"Starting {}",
|
||||||
|
module
|
||||||
|
.path
|
||||||
|
.split('/')
|
||||||
|
.last()
|
||||||
|
.unwrap()
|
||||||
|
.split('.')
|
||||||
|
.next()
|
||||||
|
.unwrap()
|
||||||
|
);
|
||||||
|
log::debug!("Spawning {} with arguments \"{}\"", module.path, cmd);
|
||||||
|
|
||||||
|
// decode AbleOS Executable format
|
||||||
|
let header = &module.bytes[0..46];
|
||||||
|
let magic_slice = &header[0..3];
|
||||||
|
if magic_slice != [0x15, 0x91, 0xD2] {
|
||||||
|
log::error!("Invalid magic number at the start of executable.");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let executable_format_version = u32::from_le_bytes(header[3..7].try_into().unwrap());
|
||||||
|
let offset = if executable_format_version == 0 {
|
||||||
|
47
|
||||||
|
} else {
|
||||||
|
error!("Invalid executable format.");
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
|
||||||
|
let code_length = u64::from_le_bytes(header[7..15].try_into().unwrap());
|
||||||
|
let data_length = u64::from_le_bytes(header[15..23].try_into().unwrap());
|
||||||
|
let end = (code_length + data_length) as usize;
|
||||||
|
log::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_ptr() as u64, cmd_len);
|
||||||
|
}
|
||||||
|
executor.spawn(Box::pin(async {
|
||||||
|
if let Err(e) = thr.await {
|
||||||
|
log::error!("{e:?}");
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
debug!("Random number: {}", hardware_random_u64());
|
||||||
|
|
||||||
|
executor.run();
|
||||||
|
};
|
||||||
|
crate::arch::spin_loop()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ! SAFETY: this is not threadsafe at all, like even a little bit.
|
||||||
|
// ! SERIOUSLY
|
||||||
|
pub static mut EXECUTOR: LazyCell<Executor> = LazyCell::new(|| Executor::new());
|
||||||
|
|
||||||
pub static DEVICE_TREE: Lazy<Mutex<DeviceTree>> = Lazy::new(|| {
|
pub static DEVICE_TREE: Lazy<Mutex<DeviceTree>> = Lazy::new(|| {
|
||||||
let dt = DeviceTree::new();
|
let dt = DeviceTree::new();
|
||||||
Mutex::new(dt)
|
Mutex::new(dt)
|
||||||
});
|
});
|
||||||
|
pub static FB_REQ: FramebufferRequest = FramebufferRequest::new(0);
|
||||||
|
|
||||||
#[test_case]
|
pub type IpcBuffers<'a> = HashMap<u64, IpcBuffer<'a>>;
|
||||||
fn trivial_assertion() {
|
pub static IPC_BUFFERS: Lazy<Mutex<IpcBuffers>> = Lazy::new(|| {
|
||||||
trace!("trivial assertion... ");
|
let mut bufs = HashMap::new();
|
||||||
assert_eq!(1, 1);
|
let log_buffer = IpcBuffer::new(false, 0);
|
||||||
info!("[ok]");
|
let file_buffer = IpcBuffer::new(false, 0);
|
||||||
}
|
|
||||||
|
bufs.insert(1, log_buffer);
|
||||||
|
bufs.insert(2, file_buffer);
|
||||||
|
|
||||||
|
Mutex::new(bufs)
|
||||||
|
});
|
||||||
|
|
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,37 +1,41 @@
|
||||||
//! The ableOS kernel.
|
//! The ableOS kernel.
|
||||||
//! Named akern.
|
//! Named akern.
|
||||||
//! Akern is woefully undersupported at the moment but we are looking to add support improve hardware discovery and make our lives as kernel and operating system developers easier and better
|
//! Akern is woefully undersupported at the moment but we are looking to add support improve hardware discovery and make our lives as kernel and operating system developers easier and better
|
||||||
|
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
#![no_main]
|
||||||
#![feature(
|
#![feature(
|
||||||
|
slice_split_once,
|
||||||
|
exclusive_wrapper,
|
||||||
|
core_intrinsics,
|
||||||
abi_x86_interrupt,
|
abi_x86_interrupt,
|
||||||
|
lazy_get,
|
||||||
alloc_error_handler,
|
alloc_error_handler,
|
||||||
inline_const,
|
local_waker,
|
||||||
panic_info_message,
|
context_ext,
|
||||||
pointer_is_aligned,
|
|
||||||
prelude_import,
|
|
||||||
ptr_sub_ptr,
|
ptr_sub_ptr,
|
||||||
custom_test_frameworks
|
naked_functions,
|
||||||
|
pointer_is_aligned_to
|
||||||
)]
|
)]
|
||||||
#![deny(clippy::pedantic, missing_docs, warnings)]
|
#![allow(dead_code, internal_features, static_mut_refs)]
|
||||||
#![allow(dead_code)]
|
|
||||||
#![test_runner(crate::test_runner)]
|
|
||||||
|
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
|
|
||||||
mod allocator;
|
mod allocator;
|
||||||
mod arch;
|
mod arch;
|
||||||
mod bootmodules;
|
mod bootmodules;
|
||||||
pub mod capabilities;
|
mod capabilities;
|
||||||
pub mod device_tree;
|
mod device_tree;
|
||||||
pub mod handle;
|
mod exe_format;
|
||||||
pub mod host;
|
mod handle;
|
||||||
pub mod ipc;
|
mod holeybytes;
|
||||||
|
mod ipc;
|
||||||
mod kmain;
|
mod kmain;
|
||||||
mod logger;
|
mod logger;
|
||||||
mod memory;
|
mod memory;
|
||||||
mod scheduler;
|
mod task;
|
||||||
pub mod utils;
|
mod utils;
|
||||||
|
|
||||||
|
#[allow(improper_ctypes, non_upper_case_globals)]
|
||||||
|
mod ktest;
|
||||||
|
|
||||||
use versioning::Version;
|
use versioning::Version;
|
||||||
|
|
||||||
|
@ -43,7 +47,11 @@ pub const VERSION: Version = Version {
|
||||||
};
|
};
|
||||||
|
|
||||||
#[panic_handler]
|
#[panic_handler]
|
||||||
|
#[cfg(target_os = "none")]
|
||||||
fn panic(info: &core::panic::PanicInfo) -> ! {
|
fn panic(info: &core::panic::PanicInfo) -> ! {
|
||||||
|
use alloc::string::ToString;
|
||||||
|
arch::register_dump();
|
||||||
|
|
||||||
if let Some(loc) = info.location() {
|
if let Some(loc) = info.location() {
|
||||||
let _ = crate::arch::log(format_args!(
|
let _ = crate::arch::log(format_args!(
|
||||||
"Location: {}: {}, {}\r\n",
|
"Location: {}: {}, {}\r\n",
|
||||||
|
@ -53,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"));
|
let _ = crate::arch::log(format_args!("{msg}\r\n"));
|
||||||
}
|
|
||||||
|
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
fn test_runner(tests: &[&dyn Fn()]) {
|
|
||||||
println!("Running {} tests", tests.len());
|
|
||||||
for test in tests {
|
|
||||||
test();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,10 +1,23 @@
|
||||||
|
#![allow(deprecated)]
|
||||||
// TODO: Add a logger api with logger levels and various outputs
|
// TODO: Add a logger api with logger levels and various outputs
|
||||||
|
pub static TERMINAL_LOGGER: Lazy<Mutex<TermLogger>> = Lazy::new(|| Mutex::new(TermLogger::new()));
|
||||||
|
|
||||||
use log::{Level, SetLoggerError};
|
use {
|
||||||
|
limine::{TerminalRequest, TerminalResponse},
|
||||||
|
log::{Level, SetLoggerError},
|
||||||
|
spin::{lazy::Lazy, mutex::Mutex},
|
||||||
|
};
|
||||||
|
|
||||||
pub fn init() -> Result<(), SetLoggerError> {
|
pub fn init() -> Result<(), SetLoggerError> {
|
||||||
log::set_logger(&crate::logger::Logger)?;
|
log::set_logger(&crate::logger::Logger)?;
|
||||||
|
if cfg!(debug_assertions) {
|
||||||
log::set_max_level(log::LevelFilter::Debug);
|
log::set_max_level(log::LevelFilter::Debug);
|
||||||
|
} else {
|
||||||
|
log::set_max_level(log::LevelFilter::Info);
|
||||||
|
}
|
||||||
|
|
||||||
|
Lazy::force(&TERMINAL_LOGGER);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,7 +36,19 @@ impl log::Log for Logger {
|
||||||
Level::Debug => "25",
|
Level::Debug => "25",
|
||||||
Level::Trace => "103",
|
Level::Trace => "103",
|
||||||
};
|
};
|
||||||
let module = record.module_path().unwrap_or_default();
|
let module = record
|
||||||
|
.module_path()
|
||||||
|
.unwrap_or_default()
|
||||||
|
.rsplit_once(':')
|
||||||
|
.unwrap_or_default()
|
||||||
|
.1;
|
||||||
|
if module == "" {
|
||||||
|
crate::arch::log(format_args!(
|
||||||
|
"\x1b[38;5;{lvl_color}m{lvl}\x1b[0m: {}\r\n",
|
||||||
|
record.args(),
|
||||||
|
))
|
||||||
|
.expect("write to serial console");
|
||||||
|
} else {
|
||||||
let line = record.line().unwrap_or_default();
|
let line = record.line().unwrap_or_default();
|
||||||
crate::arch::log(format_args!(
|
crate::arch::log(format_args!(
|
||||||
"\x1b[38;5;{lvl_color}m{lvl}\x1b[0m [{module}:{line}]: {}\r\n",
|
"\x1b[38;5;{lvl_color}m{lvl}\x1b[0m [{module}:{line}]: {}\r\n",
|
||||||
|
@ -31,6 +56,32 @@ impl log::Log for Logger {
|
||||||
))
|
))
|
||||||
.expect("write to serial console");
|
.expect("write to serial console");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn flush(&self) {}
|
fn flush(&self) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct TermLogger(&'static TerminalResponse);
|
||||||
|
unsafe impl Send for TermLogger {}
|
||||||
|
impl TermLogger {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
static TERM_REQ: TerminalRequest = TerminalRequest::new(0);
|
||||||
|
Self(
|
||||||
|
TERM_REQ
|
||||||
|
.get_response()
|
||||||
|
.get()
|
||||||
|
.expect("failed to get terminal response"),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl core::fmt::Write for TermLogger {
|
||||||
|
fn write_str(&mut self, s: &str) -> core::fmt::Result {
|
||||||
|
if let (Some(w), ts) = (self.0.write(), self.0.terminals()) {
|
||||||
|
for term in ts {
|
||||||
|
w(term, s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
#![no_std]
|
#![no_std]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
|
|
||||||
extern crate kernel;
|
extern crate kernel;
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
//! The Memory Manager
|
//! The Memory Manager
|
||||||
|
|
||||||
use alloc::collections::VecDeque;
|
use {alloc::collections::VecDeque, derive_more::*};
|
||||||
use derive_more::*;
|
|
||||||
|
|
||||||
pub use crate::arch::PAGE_SIZE;
|
pub use crate::arch::PAGE_SIZE;
|
||||||
pub const MAX_ORDER: usize = 10;
|
pub const MAX_ORDER: usize = 10;
|
||||||
|
@ -44,7 +43,7 @@ pub const MAX_ORDER: usize = 10;
|
||||||
Sum,
|
Sum,
|
||||||
UpperHex,
|
UpperHex,
|
||||||
)]
|
)]
|
||||||
#[display(fmt = "0x{:x}", _0)]
|
#[display("0x{:x}", _0)]
|
||||||
#[from(forward)]
|
#[from(forward)]
|
||||||
pub struct VirtualAddress(usize);
|
pub struct VirtualAddress(usize);
|
||||||
|
|
||||||
|
@ -55,11 +54,11 @@ impl VirtualAddress {
|
||||||
pub fn vpns(&self) -> [usize; 3] {
|
pub fn vpns(&self) -> [usize; 3] {
|
||||||
[
|
[
|
||||||
// [20:12]
|
// [20:12]
|
||||||
(self.0 >> 12) & 0x1ff,
|
(self.0 >> 12) & 0x1FF,
|
||||||
// [29:21]
|
// [29:21]
|
||||||
(self.0 >> 21) & 0x1ff,
|
(self.0 >> 21) & 0x1FF,
|
||||||
// [38:30]
|
// [38:30]
|
||||||
(self.0 >> 30) & 0x1ff,
|
(self.0 >> 30) & 0x1FF,
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -114,7 +113,7 @@ impl VirtualAddress {
|
||||||
Sum,
|
Sum,
|
||||||
UpperHex,
|
UpperHex,
|
||||||
)]
|
)]
|
||||||
#[display(fmt = "0x{:x}", _0)]
|
#[display("0x{:x}", _0)]
|
||||||
#[from(forward)]
|
#[from(forward)]
|
||||||
pub struct PhysicalAddress(usize);
|
pub struct PhysicalAddress(usize);
|
||||||
|
|
||||||
|
@ -125,11 +124,11 @@ impl PhysicalAddress {
|
||||||
pub fn ppns(&self) -> [usize; 3] {
|
pub fn ppns(&self) -> [usize; 3] {
|
||||||
[
|
[
|
||||||
// [20:12]
|
// [20:12]
|
||||||
(self.0 >> 12) & 0x1ff,
|
(self.0 >> 12) & 0x1FF,
|
||||||
// [29:21]
|
// [29:21]
|
||||||
(self.0 >> 21) & 0x1ff,
|
(self.0 >> 21) & 0x1FF,
|
||||||
// [55:30]
|
// [55:30]
|
||||||
(self.0 >> 30) & 0x3ffffff,
|
(self.0 >> 30) & 0x3FFFFFF,
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,76 +0,0 @@
|
||||||
use {
|
|
||||||
alloc::{collections::VecDeque, rc::Rc, slice, vec::Vec},
|
|
||||||
hbvm::validate::validate,
|
|
||||||
};
|
|
||||||
|
|
||||||
use {crate::host::TrapHandler, hbvm::vm::Vm};
|
|
||||||
const TIMER_QUOTIENT: usize = 100;
|
|
||||||
|
|
||||||
pub struct Scheduler<'a> {
|
|
||||||
data: VecDeque<Vm<'a, TrapHandler, TIMER_QUOTIENT>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
// NOTE: This is a very simple schduler and it sucks and should be replaced with a better one
|
|
||||||
// Written By Yours Truly: Munir
|
|
||||||
|
|
||||||
impl Scheduler<'_> {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Self {
|
|
||||||
data: VecDeque::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub fn new_process(&mut self, program: Vec<u8>) {
|
|
||||||
let prog = program.clone();
|
|
||||||
let prog_arc = Rc::new(prog);
|
|
||||||
|
|
||||||
let binding = Rc::try_unwrap(prog_arc).ok().unwrap();
|
|
||||||
|
|
||||||
#[allow(clippy::redundant_else)]
|
|
||||||
if let Err(e) = validate(&program.as_slice()) {
|
|
||||||
log::error!("Program validation error: {e:?}");
|
|
||||||
} else {
|
|
||||||
log::info!("valid program");
|
|
||||||
unsafe {
|
|
||||||
let slice = slice::from_raw_parts(binding.as_ptr(), binding.len());
|
|
||||||
let mut vm = Vm::new_unchecked(&*slice, TrapHandler);
|
|
||||||
vm.memory.insert_test_page();
|
|
||||||
self.data.push_front(vm);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn run(&mut self) -> ! {
|
|
||||||
loop {
|
|
||||||
// If there are no programs to run then sleep.
|
|
||||||
if self.data.is_empty() {
|
|
||||||
use crate::arch::spin_loop;
|
|
||||||
spin_loop();
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut prog = self.data.pop_front().unwrap();
|
|
||||||
let ret = prog.run();
|
|
||||||
match ret {
|
|
||||||
Ok(oki) => match oki {
|
|
||||||
hbvm::vm::VmRunOk::End => {
|
|
||||||
log::info!(
|
|
||||||
"Program ended. {} programs remaining.",
|
|
||||||
// Add one here because we pop a program
|
|
||||||
self.data.len() + 1
|
|
||||||
)
|
|
||||||
}
|
|
||||||
hbvm::vm::VmRunOk::Timer => {
|
|
||||||
log::info!("Timer exhausted. Scheduled program");
|
|
||||||
self.data.push_back(prog);
|
|
||||||
}
|
|
||||||
hbvm::vm::VmRunOk::Ecall => {
|
|
||||||
// panic!();
|
|
||||||
log::info!("{:?}", prog.registers);
|
|
||||||
self.data.push_back(prog);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
Err(_) => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
216
kernel/src/task.rs
Normal file
216
kernel/src/task.rs
Normal file
|
@ -0,0 +1,216 @@
|
||||||
|
use {
|
||||||
|
alloc::{
|
||||||
|
boxed::Box,
|
||||||
|
collections::{BTreeMap, BTreeSet},
|
||||||
|
sync::Arc,
|
||||||
|
},
|
||||||
|
core::{
|
||||||
|
future::Future,
|
||||||
|
pin::Pin,
|
||||||
|
sync::atomic::{AtomicBool, Ordering},
|
||||||
|
task::{Context, ContextBuilder, Poll, RawWaker, RawWakerVTable, Waker},
|
||||||
|
},
|
||||||
|
crossbeam_queue::SegQueue,
|
||||||
|
slab::Slab,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn yield_now() -> impl Future<Output = ()> {
|
||||||
|
struct YieldNow(bool);
|
||||||
|
impl Future for YieldNow {
|
||||||
|
type Output = ();
|
||||||
|
|
||||||
|
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||||
|
if self.0 {
|
||||||
|
Poll::Ready(())
|
||||||
|
} else {
|
||||||
|
self.0 = true;
|
||||||
|
cx.waker().wake_by_ref();
|
||||||
|
Poll::Pending
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
YieldNow(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait Process: Future<Output = ()> + Send {}
|
||||||
|
impl<T: Future<Output = ()> + Send> Process for T {}
|
||||||
|
|
||||||
|
pub struct Executor {
|
||||||
|
tasks: Slab<Task>,
|
||||||
|
task_queue: Arc<SegQueue<usize>>,
|
||||||
|
interrupt_lookup: [Option<usize>; u8::MAX as usize],
|
||||||
|
buffer_lookup: BTreeMap<usize, BTreeSet<usize>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Executor {
|
||||||
|
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 task_batch = [0; 32];
|
||||||
|
loop {
|
||||||
|
let mut batch_len = 0;
|
||||||
|
|
||||||
|
while let Some(id) = self.task_queue.pop() {
|
||||||
|
task_batch[batch_len] = id;
|
||||||
|
batch_len += 1;
|
||||||
|
if batch_len == task_batch.len() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 Process>>,
|
||||||
|
paused: AtomicBool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Task {
|
||||||
|
fn new(future: Pin<Box<dyn Process>>) -> Self {
|
||||||
|
Self {
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_paused(&self, paused: bool) {
|
||||||
|
self.paused.store(paused, Ordering::Release)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {
|
||||||
|
task_id: usize,
|
||||||
|
task_queue: Arc<SegQueue<usize>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TaskWaker {
|
||||||
|
fn wake(&self) {
|
||||||
|
self.task_queue.push(self.task_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
|
/// Used when tab `\t` in hardware is not known and we will default to two spaces
|
||||||
pub const TAB: &str = " ";
|
pub const TAB: &str = " ";
|
||||||
|
|
||||||
|
|
||||||
// NOTE: this only reduces the code duplication in source code not in generated code!
|
// NOTE: this only reduces the code duplication in source code not in generated code!
|
||||||
// Written by Yours Truly: Munir
|
// Written by Yours Truly: Munir
|
||||||
/// A simple macro to reduce code duplication when we use TAB internally
|
/// A simple macro to reduce code duplication when we use TAB internally
|
||||||
|
@ -12,7 +11,7 @@ pub const TAB: &str = " ";
|
||||||
macro_rules! tab {
|
macro_rules! tab {
|
||||||
($num:expr) => {
|
($num:expr) => {
|
||||||
TAB.repeat($num)
|
TAB.repeat($num)
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: this only reduces the code duplication in source code not in generated code!
|
// NOTE: this only reduces the code duplication in source code not in generated code!
|
||||||
|
@ -22,7 +21,7 @@ macro_rules! tab {
|
||||||
macro_rules! device_tree {
|
macro_rules! device_tree {
|
||||||
($devtree:expr, $dev_type_vec:expr) => {
|
($devtree:expr, $dev_type_vec:expr) => {
|
||||||
for each_device_type in $dev_type_vec {
|
for each_device_type in $dev_type_vec {
|
||||||
$devtree.devices.insert(each_device_type.to_string(), Vec::new());
|
$devtree.devices.insert(each_device_type, Vec::new());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"arch": "aarch64",
|
"arch": "aarch64",
|
||||||
"data-layout": "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128",
|
"data-layout": "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32",
|
||||||
"disable-redzone": true,
|
"disable-redzone": true,
|
||||||
"env": "",
|
"env": "",
|
||||||
"executables": true,
|
"executables": true,
|
||||||
|
@ -21,5 +21,5 @@
|
||||||
"target-c-int-width": "32",
|
"target-c-int-width": "32",
|
||||||
"target-endian": "little",
|
"target-endian": "little",
|
||||||
"target-pointer-width": "64",
|
"target-pointer-width": "64",
|
||||||
"vendor": ""
|
"vendor": "ablecorp"
|
||||||
}
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"llvm-target": "x86_64-unknown-none",
|
"llvm-target": "x86_64-unknown-none",
|
||||||
"data-layout": "e-m:e-i64:64-f80:128-n8:16:32:64-S128",
|
"data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128",
|
||||||
"arch": "x86_64",
|
"arch": "x86_64",
|
||||||
"target-endian": "little",
|
"target-endian": "little",
|
||||||
"target-pointer-width": "64",
|
"target-pointer-width": "64",
|
||||||
|
@ -11,7 +11,7 @@
|
||||||
"linker": "rust-lld",
|
"linker": "rust-lld",
|
||||||
"panic-strategy": "abort",
|
"panic-strategy": "abort",
|
||||||
"disable-redzone": true,
|
"disable-redzone": true,
|
||||||
"features": "-mmx,-sse,+soft-float",
|
"features": "",
|
||||||
"code-model": "kernel",
|
"code-model": "kernel",
|
||||||
"pre-link-args": {
|
"pre-link-args": {
|
||||||
"ld.lld": [
|
"ld.lld": [
|
||||||
|
|
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,16 +4,18 @@ version = "0.2.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
cpio_reader = "0.1" # remove me
|
str-reader = "0.1"
|
||||||
derive_more = "0.99"
|
derive_more = { version = "1", default-features = false, features = [
|
||||||
env_logger = "0.10"
|
"display",
|
||||||
error-stack = "0.2"
|
] }
|
||||||
fatfs = "0.3"
|
error-stack = "0.5"
|
||||||
log = "0.4" # remove me
|
fatfs = { version = "0.3", default-features = false, features = [
|
||||||
rpm = "0.11" # remove me
|
"std",
|
||||||
zstd = "0.12" # remove me
|
"alloc",
|
||||||
|
] }
|
||||||
[dependencies.reqwest]
|
toml = "0.8"
|
||||||
version = "0.11"
|
hblang.git = "https://git.ablecorp.us/AbleOS/holey-bytes.git"
|
||||||
default-features = false
|
# hblang.path = "../../holey-bytes/lang/"
|
||||||
features = ["rustls-tls", "blocking"]
|
log = "0.4"
|
||||||
|
raw-cpuid = "11"
|
||||||
|
ureq = { version = "2", default-features = false, features = ["tls"] }
|
||||||
|
|
Binary file not shown.
Binary file not shown.
|
@ -1,25 +0,0 @@
|
||||||
${ABLEOS_KERNEL}=boot:///kernel
|
|
||||||
# TODO: Make a boot background image for ableOS
|
|
||||||
|
|
||||||
DEFAULT_ENTRY=1
|
|
||||||
TIMEOUT=0
|
|
||||||
VERBOSE=yes
|
|
||||||
INTERFACE_RESOLUTION=1024x768
|
|
||||||
# Terminal related settings
|
|
||||||
TERM_WALLPAPER=boot:///background.bmp
|
|
||||||
TERM_BACKDROP=008080
|
|
||||||
|
|
||||||
:AbleOS
|
|
||||||
COMMENT=Default AbleOS boot entry.
|
|
||||||
PROTOCOL=limine
|
|
||||||
KERNEL_PATH=${ABLEOS_KERNEL}
|
|
||||||
# execute is an array of boot modules to execute
|
|
||||||
KERNEL_CMDLINE="execute=[0,1]"
|
|
||||||
# Setting a default resolution for the framebuffer
|
|
||||||
RESOLUTION=1024x768x24
|
|
||||||
|
|
||||||
MODULE_PATH=boot:///inf_loop.hb
|
|
||||||
MODULE_CMDLINE="diskid=123456789"
|
|
||||||
|
|
||||||
MODULE_PATH=boot:///ecall.hb
|
|
||||||
MODULE_CMDLINE=""
|
|
129
repbuild/src/dev.rs
Normal file
129
repbuild/src/dev.rs
Normal file
|
@ -0,0 +1,129 @@
|
||||||
|
#![allow(unused)]
|
||||||
|
use std::{
|
||||||
|
collections::HashMap,
|
||||||
|
fmt::format,
|
||||||
|
fs::{read_to_string, File},
|
||||||
|
io::{BufWriter, Write},
|
||||||
|
process::exit,
|
||||||
|
};
|
||||||
|
|
||||||
|
use {error_stack::Report, hblang::Options};
|
||||||
|
|
||||||
|
use crate::Error;
|
||||||
|
pub struct Package {
|
||||||
|
name: String,
|
||||||
|
binaries: Vec<String>,
|
||||||
|
build_cmd: String,
|
||||||
|
args: HashMap<String, String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Package {
|
||||||
|
pub fn load_from_file(path: String) -> Self {
|
||||||
|
let contents = match std::fs::read_to_string(path.clone()) {
|
||||||
|
// If successful return the files text as `contents`.
|
||||||
|
// `c` is a local variable.
|
||||||
|
Ok(c) => c,
|
||||||
|
// Handle the `error` case.
|
||||||
|
Err(_) => {
|
||||||
|
// Write `msg` to `stderr`.
|
||||||
|
eprintln!("Could not read file `{}`", path);
|
||||||
|
// Exit the program with exit code `1`.
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
use toml::Value;
|
||||||
|
|
||||||
|
let mut data: Value = toml::from_str(&contents).unwrap();
|
||||||
|
let mut name = data
|
||||||
|
.get("package")
|
||||||
|
.unwrap()
|
||||||
|
.get("name")
|
||||||
|
.unwrap()
|
||||||
|
.to_string();
|
||||||
|
name.pop();
|
||||||
|
name.remove(0);
|
||||||
|
|
||||||
|
let dependants = data.get("dependants").unwrap();
|
||||||
|
let bin_table = dependants.get("binaries").unwrap().as_table().unwrap();
|
||||||
|
let mut binaries = vec![];
|
||||||
|
|
||||||
|
for (count, (name, table)) in bin_table.into_iter().enumerate() {
|
||||||
|
binaries.push(name.clone());
|
||||||
|
}
|
||||||
|
let build_table = data.get("build").unwrap();
|
||||||
|
|
||||||
|
let mut build_cmd: String = build_table.get("command").unwrap().as_str().unwrap().into();
|
||||||
|
build_cmd.remove(0);
|
||||||
|
let mut args: HashMap<String, String> = match build_table.get("args") {
|
||||||
|
None => HashMap::new(),
|
||||||
|
Some(v) => v
|
||||||
|
.as_table()
|
||||||
|
.unwrap()
|
||||||
|
.into_iter()
|
||||||
|
.map(|(k, v)| (k.clone(), v.to_string()))
|
||||||
|
.collect::<HashMap<String, String>>(),
|
||||||
|
};
|
||||||
|
|
||||||
|
Self {
|
||||||
|
name,
|
||||||
|
binaries,
|
||||||
|
build_cmd,
|
||||||
|
args,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn build(&self, out: &mut Vec<u8>) -> std::io::Result<()> {
|
||||||
|
if self.binaries.contains(&"hblang".to_string()) {
|
||||||
|
let file = self.build_cmd.split_ascii_whitespace().last().unwrap();
|
||||||
|
let path = format!("sysdata/programs/{}/{}", self.name, file);
|
||||||
|
// compile here
|
||||||
|
|
||||||
|
let mut warnings = String::new();
|
||||||
|
|
||||||
|
hblang::run_compiler(
|
||||||
|
&path,
|
||||||
|
Options {
|
||||||
|
fmt: true,
|
||||||
|
resolver: Some(hblang::ABLEOS_PATH_RESOLVER),
|
||||||
|
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
out,
|
||||||
|
&mut warnings,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
match std::fs::create_dir("target/programs") {
|
||||||
|
Ok(_) => (),
|
||||||
|
Err(e) if e.kind() == std::io::ErrorKind::AlreadyExists => (),
|
||||||
|
Err(e) => panic!("{}", e),
|
||||||
|
}
|
||||||
|
|
||||||
|
hblang::run_compiler(
|
||||||
|
&path,
|
||||||
|
Options {
|
||||||
|
resolver: Some(hblang::ABLEOS_PATH_RESOLVER),
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
out,
|
||||||
|
&mut warnings,
|
||||||
|
)?;
|
||||||
|
std::fs::write(format!("target/programs/{}.hbf", self.name), &out)?;
|
||||||
|
out.clear();
|
||||||
|
|
||||||
|
let err = 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();
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,57 +1,103 @@
|
||||||
|
mod dev;
|
||||||
|
|
||||||
use {
|
use {
|
||||||
|
core::fmt::Write as _,
|
||||||
derive_more::Display,
|
derive_more::Display,
|
||||||
error_stack::{bail, report, Context, IntoReport, Result, ResultExt},
|
dev::Package,
|
||||||
|
error_stack::{bail, report, Context, Report, Result, ResultExt},
|
||||||
fatfs::{FileSystem, FormatVolumeOptions, FsOptions, ReadWriteSeek},
|
fatfs::{FileSystem, FormatVolumeOptions, FsOptions, ReadWriteSeek},
|
||||||
std::{fmt::Display, fs::File, io, path::Path, process::Command},
|
std::{
|
||||||
|
fs::{self, File},
|
||||||
|
io::{self, Write},
|
||||||
|
path::Path,
|
||||||
|
process::{exit, Command, Stdio},
|
||||||
|
},
|
||||||
|
toml::Value,
|
||||||
};
|
};
|
||||||
|
|
||||||
fn main() -> Result<(), Error> {
|
fn main() -> Result<(), Error> {
|
||||||
let mut args = std::env::args();
|
let mut args = std::env::args();
|
||||||
args.next();
|
args.next();
|
||||||
|
|
||||||
// let disk_meta = fs::metadata("target/disk.img").unwrap();
|
log::set_logger(&hblang::Logger).unwrap();
|
||||||
// let config_meta = fs::metadata("system.toml").unwrap();
|
log::set_max_level(log::LevelFilter::Error);
|
||||||
|
|
||||||
// if disk_meta.modified().unwrap() < config_meta.modified().unwrap() {
|
|
||||||
// // TODO: work on adding in system.toml support
|
|
||||||
// // TODO: rebuild the disk
|
|
||||||
// }
|
|
||||||
|
|
||||||
match args.next().as_deref() {
|
match args.next().as_deref() {
|
||||||
Some("build" | "b") => {
|
Some("build" | "b") => {
|
||||||
let mut release = false;
|
let mut release = false;
|
||||||
|
let mut debuginfo = false;
|
||||||
let mut target = Target::X86_64;
|
let mut target = Target::X86_64;
|
||||||
|
let mut tests = false;
|
||||||
for arg in args {
|
for arg in args {
|
||||||
if arg == "-r" || arg == "--release" {
|
if arg == "-r" || arg == "--release" {
|
||||||
release = true;
|
release = true;
|
||||||
|
} else if arg == "-d" || arg == "--debuginfo" {
|
||||||
|
debuginfo = true;
|
||||||
} else if arg == "rv64" || arg == "riscv64" || arg == "riscv64-virt" {
|
} else if arg == "rv64" || arg == "riscv64" || arg == "riscv64-virt" {
|
||||||
target = Target::Riscv64Virt;
|
target = Target::Riscv64Virt;
|
||||||
} else if arg == "arm64" || arg == "aarch64" || arg == "aarch64-virt" {
|
} else if arg == "arm64" || arg == "aarch64" || arg == "aarch64-virt" {
|
||||||
target = Target::Aarch64;
|
target = Target::Aarch64;
|
||||||
|
} else if arg == "avx2" {
|
||||||
|
target = Target::X86_64Avx2;
|
||||||
|
} else if arg == "--ktest" {
|
||||||
|
tests = true;
|
||||||
} else {
|
} else {
|
||||||
return Err(report!(Error::InvalidSubCom));
|
return Err(report!(Error::InvalidSubCom));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
build(release, target).change_context(Error::Build)
|
build(release, target, debuginfo, tests).change_context(Error::Build)
|
||||||
}
|
}
|
||||||
|
// Some("test" | "t") => {
|
||||||
|
// let mut release = false;
|
||||||
|
// let mut debuginfo = false;
|
||||||
|
// let mut target = Target::X86_64;
|
||||||
|
// for arg in args {
|
||||||
|
// if arg == "-r" || arg == "--release" {
|
||||||
|
// release = true;
|
||||||
|
// } else if arg == "-d" || arg == "--debuginfo" {
|
||||||
|
// debuginfo = true;
|
||||||
|
// } else if arg == "rv64" || arg == "riscv64" || arg == "riscv64-virt" {
|
||||||
|
// target = Target::Riscv64Virt;
|
||||||
|
// } else if arg == "arm64" || arg == "aarch64" || arg == "aarch64-virt" {
|
||||||
|
// target = Target::Aarch64;
|
||||||
|
// } else if arg == "avx2" {
|
||||||
|
// target = Target::X86_64Avx2;
|
||||||
|
// } else {
|
||||||
|
// return Err(report!(Error::InvalidSubCom));
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// test(release, target, debuginfo).change_context(Error::Build)
|
||||||
|
// }
|
||||||
Some("run" | "r") => {
|
Some("run" | "r") => {
|
||||||
let mut release = false;
|
let mut release = false;
|
||||||
|
let mut debuginfo = false;
|
||||||
let mut target = Target::X86_64;
|
let mut target = Target::X86_64;
|
||||||
|
let mut tests = false;
|
||||||
|
let mut do_accel = true;
|
||||||
for arg in args {
|
for arg in args {
|
||||||
if arg == "-r" || arg == "--release" {
|
if arg == "-r" || arg == "--release" {
|
||||||
release = true;
|
release = true;
|
||||||
|
} else if arg == "-d" || arg == "--debuginfo" {
|
||||||
|
debuginfo = true;
|
||||||
} else if arg == "rv64" || arg == "riscv64" || arg == "riscv64-virt" {
|
} else if arg == "rv64" || arg == "riscv64" || arg == "riscv64-virt" {
|
||||||
target = Target::Riscv64Virt;
|
target = Target::Riscv64Virt;
|
||||||
} else if arg == "arm64" || arg == "aarch64" || arg == "aarch64-virt" {
|
} else if arg == "arm64" || arg == "aarch64" || arg == "aarch64-virt" {
|
||||||
target = Target::Aarch64;
|
target = Target::Aarch64;
|
||||||
|
} else if arg == "--noaccel" {
|
||||||
|
do_accel = false;
|
||||||
|
} else if arg == "avx2" {
|
||||||
|
target = Target::X86_64Avx2;
|
||||||
|
} else if arg == "--ktest" {
|
||||||
|
tests = true;
|
||||||
} else {
|
} else {
|
||||||
return Err(report!(Error::InvalidSubCom));
|
return Err(report!(Error::InvalidSubCom));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
build(release, target)?;
|
build(release, target, debuginfo, tests)?;
|
||||||
run(release, target)
|
run(release, target, do_accel)
|
||||||
}
|
}
|
||||||
Some("help" | "h") => {
|
Some("help" | "h") => {
|
||||||
println!(concat!(
|
println!(concat!(
|
||||||
|
@ -61,8 +107,11 @@ fn main() -> Result<(), Error> {
|
||||||
" help (h): Print this message\n",
|
" help (h): Print this message\n",
|
||||||
" run (r): Build and run AbleOS in QEMU\n\n",
|
" run (r): Build and run AbleOS in QEMU\n\n",
|
||||||
"Options for build and run:\n",
|
"Options for build and run:\n",
|
||||||
" -r: build in release mode",
|
" -r / --release: build in release mode\n",
|
||||||
" [target]: sets target"
|
" -d / --debuginfo: build with debug info\n",
|
||||||
|
" --noaccel: run without acceleration (e.g, no kvm)\n",
|
||||||
|
" --ktest: Enables tests via ktest\n",
|
||||||
|
"[ rv64 / riscv64 / riscv64-virt / aarch64 / arm64 / aarch64-virt / avx2 ]: sets target"
|
||||||
),);
|
),);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -70,74 +119,227 @@ fn main() -> Result<(), Error> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_fs() -> Result<FileSystem<impl ReadWriteSeek>, io::Error> {
|
fn get_path_without_boot_prefix(val: &Value) -> Option<&str> {
|
||||||
let path = Path::new("target/disk.img");
|
val.as_str()?.split("boot:///").last()
|
||||||
|
}
|
||||||
|
|
||||||
match std::fs::metadata(path) {
|
fn get_fs() -> Result<FileSystem<impl ReadWriteSeek>, io::Error> {
|
||||||
Err(e) if e.kind() == io::ErrorKind::NotFound => (),
|
let filename = "sysdata/system_config.toml";
|
||||||
Err(e) => bail!(e),
|
|
||||||
Ok(_) => {
|
|
||||||
return FileSystem::new(
|
|
||||||
File::options().read(true).write(true).open(path)?,
|
|
||||||
FsOptions::new(),
|
|
||||||
)
|
|
||||||
.into_report()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut img = File::options()
|
let mut img = File::options()
|
||||||
.read(true)
|
.read(true)
|
||||||
.write(true)
|
.write(true)
|
||||||
.create(true)
|
.create(true)
|
||||||
.open(path)?;
|
.open(Path::new("target/disk.img"))?;
|
||||||
|
|
||||||
img.set_len(1024 * 1024 * 64)?;
|
img.set_len(1024 * 1024 * 64)?;
|
||||||
|
|
||||||
fatfs::format_volume(&mut img, FormatVolumeOptions::new())?;
|
fatfs::format_volume(&mut img, FormatVolumeOptions::new())?;
|
||||||
|
|
||||||
let fs = FileSystem::new(img, FsOptions::new())?;
|
let fs = FileSystem::new(img, FsOptions::new())?;
|
||||||
|
|
||||||
|
// Read the contents of the file using a `match` block
|
||||||
|
// to return the `data: Ok(c)` as a `String`
|
||||||
|
// or handle any `errors: Err(_)`.
|
||||||
|
let contents = match fs::read_to_string(filename) {
|
||||||
|
// If successful return the files text as `contents`.
|
||||||
|
// `c` is a local variable.
|
||||||
|
Ok(c) => c,
|
||||||
|
// Handle the `error` case.
|
||||||
|
Err(_) => {
|
||||||
|
// Write `msg` to `stderr`.
|
||||||
|
eprintln!("Could not read file `{}`", filename);
|
||||||
|
// Exit the program with exit code `1`.
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
use toml::Value;
|
||||||
|
|
||||||
|
let mut limine_str = String::new();
|
||||||
|
|
||||||
|
let mut data: Value = toml::from_str(&contents).unwrap();
|
||||||
|
let boot_table = data.get_mut("boot");
|
||||||
|
let limine_table = boot_table.unwrap().get_mut("limine").unwrap();
|
||||||
|
let default_entry = limine_table.get("default_entry").unwrap();
|
||||||
|
let timeout = limine_table.get("timeout").unwrap();
|
||||||
|
let interface_resolution = limine_table.get("interface_resolution").unwrap();
|
||||||
|
let verbose = limine_table.get("verbose").unwrap();
|
||||||
|
let term_wallpaper = limine_table.get("term_wallpaper").unwrap();
|
||||||
|
|
||||||
|
let vb_post = match verbose.as_bool().unwrap() {
|
||||||
|
true => "yes",
|
||||||
|
false => "no",
|
||||||
|
};
|
||||||
|
let term_background = limine_table
|
||||||
|
.get("term_backdrop")
|
||||||
|
.unwrap_or(&Value::Integer(0));
|
||||||
|
let base = format!(
|
||||||
|
"DEFAULT_ENTRY={}
|
||||||
|
TIMEOUT={}
|
||||||
|
VERBOSE={}
|
||||||
|
INTERFACE_RESOLUTION={}
|
||||||
|
# Terminal related settings
|
||||||
|
TERM_WALLPAPER={}
|
||||||
|
TERM_BACKDROP={}
|
||||||
|
",
|
||||||
|
default_entry,
|
||||||
|
timeout,
|
||||||
|
vb_post,
|
||||||
|
interface_resolution,
|
||||||
|
term_wallpaper.as_str().unwrap(),
|
||||||
|
term_background
|
||||||
|
);
|
||||||
|
|
||||||
|
// Copy the term_wallpaper to the image
|
||||||
|
let term_wallpaper_path = get_path_without_boot_prefix(term_wallpaper).unwrap();
|
||||||
|
copy_file_to_img(&format!("sysdata/{}", term_wallpaper_path), &fs);
|
||||||
|
|
||||||
|
limine_str.push_str(&base);
|
||||||
|
|
||||||
|
let boot_entries = limine_table.as_table_mut().unwrap();
|
||||||
|
let mut real_boot_entries = boot_entries.clone();
|
||||||
|
for (key, value) in boot_entries.into_iter() {
|
||||||
|
if !value.is_table() {
|
||||||
|
real_boot_entries.remove(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (name, mut value) in real_boot_entries {
|
||||||
|
let comment = value.get("comment").unwrap();
|
||||||
|
let protocol = value.get("protocol").unwrap();
|
||||||
|
let resolution = value.get("resolution").unwrap();
|
||||||
|
let kernel_path = value.get("kernel_path").unwrap();
|
||||||
|
let kernel_cmdline = value.get("kernel_cmdline").unwrap();
|
||||||
|
|
||||||
|
let text_entry = format!(
|
||||||
|
"
|
||||||
|
:{}
|
||||||
|
COMMENT={}
|
||||||
|
PROTOCOL={}
|
||||||
|
RESOLUTION={}
|
||||||
|
KERNEL_PATH={}
|
||||||
|
KERNEL_CMDLINE={}
|
||||||
|
|
||||||
|
",
|
||||||
|
name,
|
||||||
|
comment.as_str().unwrap(),
|
||||||
|
protocol.as_str().unwrap(),
|
||||||
|
resolution.as_str().unwrap(),
|
||||||
|
kernel_path.as_str().unwrap(),
|
||||||
|
kernel_cmdline,
|
||||||
|
);
|
||||||
|
|
||||||
|
limine_str.push_str(&text_entry);
|
||||||
|
|
||||||
|
let modules = value.get_mut("modules").unwrap().as_table_mut().unwrap();
|
||||||
|
// let mut real_modules = modules.clone();
|
||||||
|
|
||||||
|
let mut errors = String::new();
|
||||||
|
let mut out = Vec::new();
|
||||||
|
|
||||||
|
modules
|
||||||
|
.into_iter()
|
||||||
|
.map(|(_, value)| -> Result<(), io::Error> {
|
||||||
|
if value.is_table() {
|
||||||
|
let path = get_path_without_boot_prefix(
|
||||||
|
value.get("path").expect("You must have `path` as a value"),
|
||||||
|
)
|
||||||
|
.unwrap()
|
||||||
|
.split(".")
|
||||||
|
.next()
|
||||||
|
.unwrap();
|
||||||
|
let p = Package::load_from_file(
|
||||||
|
format!("sysdata/programs/{}/meta.toml", path).to_owned(),
|
||||||
|
);
|
||||||
|
match p.build(&mut out) {
|
||||||
|
Ok(()) => {}
|
||||||
|
Err(e) => {
|
||||||
|
writeln!(errors, "========= while compiling {} {} =========", path, e)
|
||||||
|
.unwrap();
|
||||||
|
errors.push_str(&String::from_utf8_lossy(&out));
|
||||||
|
out.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
})
|
||||||
|
.for_each(drop);
|
||||||
|
|
||||||
|
if !errors.is_empty() {
|
||||||
|
let _ = writeln!(errors, "!!! STOPPING DUE TO PREVIOUS ERRORS !!!");
|
||||||
|
std::eprint!("{errors}");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
modules.into_iter().for_each(|(_key, value)| {
|
||||||
|
if value.is_table() {
|
||||||
|
let path = value.get("path").expect("You must have `path` as a value");
|
||||||
|
let default_value = Value::String("".into());
|
||||||
|
let cmd_line = value.get("cmd_line").unwrap_or(&default_value);
|
||||||
|
|
||||||
|
let a = format!(
|
||||||
|
" MODULE_PATH={}
|
||||||
|
MODULE_CMDLINE={}\n\n",
|
||||||
|
path.as_str().unwrap(),
|
||||||
|
cmd_line
|
||||||
|
);
|
||||||
|
limine_str.push_str(&a);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Copy modules into the test_programs directory
|
||||||
|
modules.into_iter().for_each(|(_key, value)| {
|
||||||
|
if value.is_table() {
|
||||||
|
let path = get_path_without_boot_prefix(
|
||||||
|
value
|
||||||
|
.get("path")
|
||||||
|
.expect("You must have a `path` as a value"),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
let fpath = format!("target/programs/{}", path);
|
||||||
|
copy_file_to_img(&fpath, &fs);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
let bootdir = fs.root_dir().create_dir("efi")?.create_dir("boot")?;
|
let bootdir = fs.root_dir().create_dir("efi")?.create_dir("boot")?;
|
||||||
|
|
||||||
|
let mut f = fs.root_dir().create_file("limine.cfg")?;
|
||||||
|
let _ = f.write(limine_str.as_bytes())?;
|
||||||
|
drop(f);
|
||||||
|
|
||||||
io::copy(
|
io::copy(
|
||||||
&mut File::open("limine/BOOTX64.EFI")
|
&mut File::open("limine/BOOTX64.EFI")
|
||||||
.into_report()
|
.map_err(Report::from)
|
||||||
.attach_printable("copying Limine bootloader (have you pulled the submodule?)")?,
|
.attach_printable("Copying Limine (x86_64): have you pulled the submodule?")?,
|
||||||
&mut bootdir.create_file("bootx64.efi")?,
|
&mut bootdir.create_file("bootx64.efi")?,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
io::copy(
|
io::copy(
|
||||||
&mut File::open("limine/BOOTAA64.EFI")
|
&mut File::open("limine/BOOTAA64.EFI")
|
||||||
.into_report()
|
.map_err(Report::from)
|
||||||
.attach_printable(
|
.attach_printable("Copying Limine (ARM): have you pulled the submodule?")?,
|
||||||
"copying Limine bootloader arm version (have you pulled the submodule?)",
|
|
||||||
)?,
|
|
||||||
&mut bootdir.create_file("bootaa64.efi")?,
|
&mut bootdir.create_file("bootaa64.efi")?,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
io::copy(
|
|
||||||
&mut File::open("repbuild/limine.cfg")?,
|
|
||||||
&mut fs.root_dir().create_file("limine.cfg")?,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
io::copy(
|
|
||||||
&mut File::open("repbuild/background.bmp")?,
|
|
||||||
&mut fs.root_dir().create_file("background.bmp")?,
|
|
||||||
)?;
|
|
||||||
io::copy(
|
|
||||||
&mut File::open("repbuild/holeybytes/inf_loop.hb")?,
|
|
||||||
&mut fs.root_dir().create_file("inf_loop.hb")?,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
io::copy(
|
|
||||||
&mut File::open("repbuild/holeybytes/ecall.hb")?,
|
|
||||||
&mut fs.root_dir().create_file("ecall.hb")?,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
drop(bootdir);
|
drop(bootdir);
|
||||||
Ok(fs)
|
Ok(fs)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build(release: bool, target: Target) -> Result<(), Error> {
|
fn copy_file_to_img(fpath: &str, fs: &FileSystem<File>) {
|
||||||
|
let path = Path::new(fpath);
|
||||||
|
// println!("{path:?}");
|
||||||
|
io::copy(
|
||||||
|
&mut File::open(path).expect(&format!("Could not open file {fpath}")),
|
||||||
|
&mut fs
|
||||||
|
.root_dir()
|
||||||
|
.create_file(&path.file_name().unwrap().to_string_lossy())
|
||||||
|
.expect("Unable to create file"),
|
||||||
|
)
|
||||||
|
.expect("Copy failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
fn build(release: bool, target: Target, debuginfo: bool, tests: bool) -> Result<(), Error> {
|
||||||
let fs = get_fs().change_context(Error::Io)?;
|
let fs = get_fs().change_context(Error::Io)?;
|
||||||
let mut com = Command::new("cargo");
|
let mut com = Command::new("cargo");
|
||||||
com.current_dir("kernel");
|
com.current_dir("kernel");
|
||||||
|
@ -145,6 +347,13 @@ fn build(release: bool, target: Target) -> Result<(), Error> {
|
||||||
if release {
|
if release {
|
||||||
com.arg("-r");
|
com.arg("-r");
|
||||||
}
|
}
|
||||||
|
if debuginfo {
|
||||||
|
com.env("RUSTFLAGS", "-Cdebug-assertions=true");
|
||||||
|
}
|
||||||
|
|
||||||
|
if tests {
|
||||||
|
com.args(["--features", "ktest"]);
|
||||||
|
}
|
||||||
|
|
||||||
if target == Target::Riscv64Virt {
|
if target == Target::Riscv64Virt {
|
||||||
com.args(["--target", "targets/riscv64-virt-ableos.json"]);
|
com.args(["--target", "targets/riscv64-virt-ableos.json"]);
|
||||||
|
@ -152,6 +361,9 @@ fn build(release: bool, target: Target) -> Result<(), Error> {
|
||||||
if target == Target::Aarch64 {
|
if target == Target::Aarch64 {
|
||||||
com.args(["--target", "targets/aarch64-virt-ableos.json"]);
|
com.args(["--target", "targets/aarch64-virt-ableos.json"]);
|
||||||
}
|
}
|
||||||
|
if target == Target::X86_64Avx2 {
|
||||||
|
com.args(["--target", "targets/x86_64_v3-ableos.json"]);
|
||||||
|
}
|
||||||
|
|
||||||
match com.status() {
|
match com.status() {
|
||||||
Ok(s) if s.code() != Some(0) => bail!(Error::Build),
|
Ok(s) if s.code() != Some(0) => bail!(Error::Build),
|
||||||
|
@ -159,10 +371,21 @@ fn build(release: bool, target: Target) -> Result<(), Error> {
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let mut path: String = "kernel".to_string();
|
||||||
let kernel_dir = match target {
|
let kernel_dir = match target {
|
||||||
Target::X86_64 => "target/x86_64-ableos",
|
Target::X86_64 => {
|
||||||
|
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::Riscv64Virt => "target/riscv64-virt-ableos",
|
||||||
Target::Aarch64 => "target/aarch64-virt-ableos",
|
Target::Aarch64 => {
|
||||||
|
path.push_str("_aarch64");
|
||||||
|
"target/aarch64-virt-ableos"
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
(|| -> std::io::Result<_> {
|
(|| -> std::io::Result<_> {
|
||||||
|
@ -172,30 +395,81 @@ fn build(release: bool, target: Target) -> Result<(), Error> {
|
||||||
.join(if release { "release" } else { "debug" })
|
.join(if release { "release" } else { "debug" })
|
||||||
.join("kernel"),
|
.join("kernel"),
|
||||||
)?,
|
)?,
|
||||||
&mut fs.root_dir().create_file("kernel")?,
|
&mut fs.root_dir().create_file(&path)?,
|
||||||
)
|
)
|
||||||
.map(|_| ())
|
.map(|_| ())
|
||||||
})()
|
})()
|
||||||
.into_report()
|
.map_err(Report::from)
|
||||||
.change_context(Error::Io)
|
.change_context(Error::Io)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(release: bool, target: Target) -> Result<(), Error> {
|
fn run(release: bool, target: Target, do_accel: bool) -> Result<(), Error> {
|
||||||
let mut com = match target {
|
let target_str = match target {
|
||||||
Target::X86_64 => Command::new("qemu-system-x86_64"),
|
Target::X86_64 | Target::X86_64Avx2 => "qemu-system-x86_64",
|
||||||
Target::Riscv64Virt => Command::new("qemu-system-riscv64"),
|
Target::Riscv64Virt => "qemu-system-riscv64",
|
||||||
Target::Aarch64 => Command::new("qemu-system-aarch64"),
|
Target::Aarch64 => "qemu-system-aarch64",
|
||||||
};
|
};
|
||||||
|
let (mut com, mut com2) = (Command::new(target_str), Command::new(target_str));
|
||||||
let ovmf_path = fetch_ovmf(target);
|
let ovmf_path = fetch_ovmf(target);
|
||||||
|
#[cfg(target_arch = "x86_64")]
|
||||||
|
let accel = if do_accel {
|
||||||
|
let supported = String::from_utf8(
|
||||||
|
com2.args(["--accel", "help"])
|
||||||
|
.stdout(Stdio::piped())
|
||||||
|
.stderr(Stdio::piped())
|
||||||
|
.spawn()
|
||||||
|
.unwrap()
|
||||||
|
.wait_with_output()
|
||||||
|
.unwrap()
|
||||||
|
.stdout,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let cpuid = raw_cpuid::CpuId::new();
|
||||||
|
let vmx = cpuid.get_feature_info().unwrap().has_vmx();
|
||||||
|
let svm = cpuid.get_svm_info().is_some();
|
||||||
|
|
||||||
|
if supported.contains("kvm") && (vmx || svm) {
|
||||||
|
"accel=kvm"
|
||||||
|
} else if cpuid
|
||||||
|
.get_processor_brand_string()
|
||||||
|
.filter(|a| a.as_str() == "GenuineIntel")
|
||||||
|
.is_some()
|
||||||
|
&& supported.contains("hax")
|
||||||
|
&& vmx
|
||||||
|
{
|
||||||
|
"accel=hax"
|
||||||
|
} else if supported.contains("whpx") {
|
||||||
|
"accel=whpx"
|
||||||
|
} else {
|
||||||
|
"accel=tcg"
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
"accel=tcg"
|
||||||
|
};
|
||||||
|
#[cfg(not(target_arch = "x86_64"))]
|
||||||
|
let accel = "accel=tcg";
|
||||||
|
|
||||||
match target {
|
match target {
|
||||||
Target::X86_64 => {
|
Target::X86_64 | Target::X86_64Avx2 => {
|
||||||
#[rustfmt::skip]
|
#[rustfmt::skip]
|
||||||
com.args([
|
com.args([
|
||||||
"-bios", &ovmf_path.change_context(Error::OvmfFetch)?,
|
"-bios", &ovmf_path.change_context(Error::OvmfFetch)?,
|
||||||
"-drive", "file=target/disk.img,format=raw",
|
//"-hda", "target/disk.img",
|
||||||
"-m", "4G",
|
"-drive", "file=target/disk.img,index=0,if=ide,format=raw",
|
||||||
"-smp", "cores=4",
|
"-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 => {
|
Target::Riscv64Virt => {
|
||||||
|
@ -216,7 +490,7 @@ fn run(release: bool, target: Target) -> Result<(), Error> {
|
||||||
#[rustfmt::skip]
|
#[rustfmt::skip]
|
||||||
com.args([
|
com.args([
|
||||||
"-M", "virt",
|
"-M", "virt",
|
||||||
"-cpu", "cortex-a72",
|
"-cpu", "max",
|
||||||
"-device", "ramfb",
|
"-device", "ramfb",
|
||||||
"-device", "qemu-xhci",
|
"-device", "qemu-xhci",
|
||||||
"-device", "usb-kbd",
|
"-device", "usb-kbd",
|
||||||
|
@ -229,7 +503,7 @@ fn run(release: bool, target: Target) -> Result<(), Error> {
|
||||||
|
|
||||||
match com
|
match com
|
||||||
.status()
|
.status()
|
||||||
.into_report()
|
.map_err(Report::from)
|
||||||
.change_context(Error::ProcessSpawn)?
|
.change_context(Error::ProcessSpawn)?
|
||||||
{
|
{
|
||||||
s if s.success() => Ok(()),
|
s if s.success() => Ok(()),
|
||||||
|
@ -239,7 +513,7 @@ fn run(release: bool, target: Target) -> Result<(), Error> {
|
||||||
|
|
||||||
fn fetch_ovmf(target: Target) -> Result<String, OvmfFetchError> {
|
fn fetch_ovmf(target: Target) -> Result<String, OvmfFetchError> {
|
||||||
let (ovmf_url, ovmf_path) = match target {
|
let (ovmf_url, ovmf_path) = match target {
|
||||||
Target::X86_64 => (
|
Target::X86_64 | Target::X86_64Avx2 => (
|
||||||
"https://retrage.github.io/edk2-nightly/bin/RELEASEX64_OVMF.fd",
|
"https://retrage.github.io/edk2-nightly/bin/RELEASEX64_OVMF.fd",
|
||||||
"target/RELEASEX64_OVMF.fd",
|
"target/RELEASEX64_OVMF.fd",
|
||||||
),
|
),
|
||||||
|
@ -256,18 +530,18 @@ fn fetch_ovmf(target: Target) -> Result<String, OvmfFetchError> {
|
||||||
.write(true)
|
.write(true)
|
||||||
.read(true)
|
.read(true)
|
||||||
.open(ovmf_path)
|
.open(ovmf_path)
|
||||||
.into_report()
|
.map_err(Report::from)
|
||||||
.change_context(OvmfFetchError::Io)?,
|
.change_context(OvmfFetchError::Io)?,
|
||||||
Ok(_) => return Ok(ovmf_path.to_owned()),
|
Ok(_) => return Ok(ovmf_path.to_owned()),
|
||||||
Err(e) => return Err(report!(e).change_context(OvmfFetchError::Io)),
|
Err(e) => return Err(report!(e).change_context(OvmfFetchError::Io)),
|
||||||
};
|
};
|
||||||
let mut bytes = reqwest::blocking::get(ovmf_url)
|
let req = ureq::get(ovmf_url)
|
||||||
.into_report()
|
.call()
|
||||||
|
.map_err(Report::from)
|
||||||
.change_context(OvmfFetchError::Fetch)?;
|
.change_context(OvmfFetchError::Fetch)?;
|
||||||
|
|
||||||
bytes
|
std::io::copy(&mut req.into_reader(), &mut file)
|
||||||
.copy_to(&mut file)
|
.map_err(Report::from)
|
||||||
.into_report()
|
|
||||||
.change_context(OvmfFetchError::Io)?;
|
.change_context(OvmfFetchError::Io)?;
|
||||||
|
|
||||||
Ok(ovmf_path.to_owned())
|
Ok(ovmf_path.to_owned())
|
||||||
|
@ -275,11 +549,11 @@ fn fetch_ovmf(target: Target) -> Result<String, OvmfFetchError> {
|
||||||
|
|
||||||
#[derive(Debug, Display)]
|
#[derive(Debug, Display)]
|
||||||
enum OvmfFetchError {
|
enum OvmfFetchError {
|
||||||
#[display(fmt = "Failed to fetch OVMF package")]
|
#[display("Failed to fetch OVMF package")]
|
||||||
Fetch,
|
Fetch,
|
||||||
#[display(fmt = "No OVMF package available")]
|
#[display("No OVMF package available")]
|
||||||
Empty,
|
Empty,
|
||||||
#[display(fmt = "IO Error")]
|
#[display("IO Error")]
|
||||||
Io,
|
Io,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -288,28 +562,33 @@ impl Context for OvmfFetchError {}
|
||||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||||
enum Target {
|
enum Target {
|
||||||
X86_64,
|
X86_64,
|
||||||
|
X86_64Avx2,
|
||||||
Riscv64Virt,
|
Riscv64Virt,
|
||||||
Aarch64,
|
Aarch64,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
#[derive(Debug, Display)]
|
#[derive(Debug, Display)]
|
||||||
enum Error {
|
enum Error {
|
||||||
#[display(fmt = "Failed to build the kernel")]
|
#[display("Failed to build the kernel")]
|
||||||
Build,
|
Build,
|
||||||
#[display(fmt = "Missing or invalid subcommand (available: build, run)")]
|
#[display("Missing or invalid subcommand (available: build, run)")]
|
||||||
InvalidSubCom,
|
InvalidSubCom,
|
||||||
#[display(fmt = "IO Error")]
|
#[display("IO Error")]
|
||||||
Io,
|
Io,
|
||||||
#[display(fmt = "Failed to spawn a process")]
|
#[display("Failed to spawn a process")]
|
||||||
ProcessSpawn,
|
ProcessSpawn,
|
||||||
#[display(fmt = "Failed to fetch UEFI firmware")]
|
#[display("Failed to fetch UEFI firmware")]
|
||||||
OvmfFetch,
|
OvmfFetch,
|
||||||
#[display(fmt = "QEMU Error: {}", "fmt_qemu_err(*_0)")]
|
#[display("Failed to assemble Holey Bytes code")]
|
||||||
|
Assembler,
|
||||||
|
#[display("QEMU Error: {}", "fmt_qemu_err(*_0)")]
|
||||||
Qemu(Option<i32>),
|
Qemu(Option<i32>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Context for Error {}
|
impl Context for Error {}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
fn fmt_qemu_err(e: Option<i32>) -> impl Display {
|
fn fmt_qemu_err(e: Option<i32>) -> impl Display {
|
||||||
struct W(Option<i32>);
|
struct W(Option<i32>);
|
||||||
impl Display for W {
|
impl Display for W {
|
||||||
|
|
|
@ -1,3 +1,7 @@
|
||||||
[toolchain]
|
[toolchain]
|
||||||
|
# old toolchain
|
||||||
|
# channel = "nightly-2024-07-27"
|
||||||
|
# last stable
|
||||||
|
# channel = "nightly-2024-11-20"
|
||||||
channel = "nightly"
|
channel = "nightly"
|
||||||
components = ["rust-src", "llvm-tools"]
|
components = ["rust-src", "llvm-tools"]
|
||||||
|
|
BIN
sysdata/assets/able.bmp
Normal file
BIN
sysdata/assets/able.bmp
Normal file
Binary file not shown.
After Width: | Height: | Size: 100 KiB |
BIN
sysdata/assets/consolefonts/tamsyn/10x20b.psf
Normal file
BIN
sysdata/assets/consolefonts/tamsyn/10x20b.psf
Normal file
Binary file not shown.
BIN
sysdata/assets/consolefonts/tamsyn/10x20r.psf
Normal file
BIN
sysdata/assets/consolefonts/tamsyn/10x20r.psf
Normal file
Binary file not shown.
BIN
sysdata/assets/consolefonts/tamsyn/5x9b.psf
Normal file
BIN
sysdata/assets/consolefonts/tamsyn/5x9b.psf
Normal file
Binary file not shown.
BIN
sysdata/assets/consolefonts/tamsyn/5x9r.psf
Normal file
BIN
sysdata/assets/consolefonts/tamsyn/5x9r.psf
Normal file
Binary file not shown.
BIN
sysdata/assets/consolefonts/tamsyn/6x12b.psf
Normal file
BIN
sysdata/assets/consolefonts/tamsyn/6x12b.psf
Normal file
Binary file not shown.
BIN
sysdata/assets/consolefonts/tamsyn/6x12r.psf
Normal file
BIN
sysdata/assets/consolefonts/tamsyn/6x12r.psf
Normal file
Binary file not shown.
BIN
sysdata/assets/consolefonts/tamsyn/7x13b.psf
Normal file
BIN
sysdata/assets/consolefonts/tamsyn/7x13b.psf
Normal file
Binary file not shown.
BIN
sysdata/assets/consolefonts/tamsyn/7x13r.psf
Normal file
BIN
sysdata/assets/consolefonts/tamsyn/7x13r.psf
Normal file
Binary file not shown.
BIN
sysdata/assets/consolefonts/tamsyn/7x14b.psf
Normal file
BIN
sysdata/assets/consolefonts/tamsyn/7x14b.psf
Normal file
Binary file not shown.
BIN
sysdata/assets/consolefonts/tamsyn/7x14r.psf
Normal file
BIN
sysdata/assets/consolefonts/tamsyn/7x14r.psf
Normal file
Binary file not shown.
BIN
sysdata/assets/consolefonts/tamsyn/8x15b.psf
Normal file
BIN
sysdata/assets/consolefonts/tamsyn/8x15b.psf
Normal file
Binary file not shown.
BIN
sysdata/assets/consolefonts/tamsyn/8x15r.psf
Normal file
BIN
sysdata/assets/consolefonts/tamsyn/8x15r.psf
Normal file
Binary file not shown.
BIN
sysdata/assets/consolefonts/tamsyn/8x16b.psf
Normal file
BIN
sysdata/assets/consolefonts/tamsyn/8x16b.psf
Normal file
Binary file not shown.
BIN
sysdata/assets/consolefonts/tamsyn/8x16r.psf
Normal file
BIN
sysdata/assets/consolefonts/tamsyn/8x16r.psf
Normal file
Binary file not shown.
10
sysdata/assets/consolefonts/tamsyn/LICENSE
Normal file
10
sysdata/assets/consolefonts/tamsyn/LICENSE
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
Tamsyn font is free. You are hereby granted permission to use, copy, modify,
|
||||||
|
and distribute it as you see fit.
|
||||||
|
|
||||||
|
Tamsyn font is provided "as is" without any express or implied warranty.
|
||||||
|
|
||||||
|
The author makes no representations about the suitability of this font for
|
||||||
|
a particular purpose.
|
||||||
|
|
||||||
|
In no event will the author be held liable for damages arising from the use
|
||||||
|
of this font.
|
BIN
sysdata/assets/mini.bmp
Normal file
BIN
sysdata/assets/mini.bmp
Normal file
Binary file not shown.
After Width: | Height: | Size: 100 KiB |
BIN
sysdata/assets/mini.qoi
Normal file
BIN
sysdata/assets/mini.qoi
Normal file
Binary file not shown.
BIN
sysdata/assets/wallpaper.qoi
Normal file
BIN
sysdata/assets/wallpaper.qoi
Normal file
Binary file not shown.
Before Width: | Height: | Size: 1.8 MiB After Width: | Height: | Size: 1.8 MiB |
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue