Compare commits
6 commits
Author | SHA1 | Date | |
---|---|---|---|
Graham Kelly | 4e2819f025 | ||
Graham Kelly | 2a7f15239e | ||
Graham Kelly | 4f1e82e70a | ||
Graham Kelly | 4c2e52c9bb | ||
Graham Kelly | 2b5076baa7 | ||
Graham Kelly | 9975d08054 |
|
@ -1,3 +1,2 @@
|
|||
[alias]
|
||||
repbuild = "run --manifest-path ./repbuild/Cargo.toml -- "
|
||||
dev = "run --manifest-path ./dev/Cargo.toml -r --"
|
||||
repbuild = "run --manifest-path ./repbuild/Cargo.toml --"
|
5
.vscode/settings.json
vendored
5
.vscode/settings.json
vendored
|
@ -1,7 +1,4 @@
|
|||
{
|
||||
"editor.insertSpaces": false,
|
||||
"editor.detectIndentation": false,
|
||||
"rust-analyzer.checkOnSave.allTargets": false,
|
||||
"rust-analyzer.showUnlinkedFileNotification": false,
|
||||
"C_Cpp.errorSquiggles": "disabled"
|
||||
"rust-analyzer.showUnlinkedFileNotification": false
|
||||
}
|
1338
Cargo.lock
generated
1338
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
10
Cargo.toml
10
Cargo.toml
|
@ -1,9 +1,5 @@
|
|||
[workspace]
|
||||
resolver = "2"
|
||||
members = ["dev", "kernel", "repbuild"]
|
||||
|
||||
# [profile.release]
|
||||
# strip = "symbols"
|
||||
# codegen-units = 1
|
||||
# lto = true
|
||||
# panic = "abort"
|
||||
|
||||
[workspace]
|
||||
members = ["kernel", "repbuild", "user/ablewasi"]
|
||||
|
|
69
HELP.md
69
HELP.md
|
@ -1,69 +0,0 @@
|
|||
### What are the requirements?
|
||||
- A machine with [Rustc Tier 1 platform support](https://doc.rust-lang.org/nightly/rustc/platform-support.html#tier-1-with-host-tools)
|
||||
- Rustup
|
||||
- QEMU (for executing)
|
||||
- GIT CLI
|
||||
|
||||
### How do I run ableos?
|
||||
- It is recommended to run ableos under QEMU. Here is how:
|
||||
- Install QEMU
|
||||
- Clone ableos
|
||||
- Go to ableos directory
|
||||
- Pull the limine submodule with `git submodule update --init`
|
||||
- Run `cargo repbuild help`
|
||||
|
||||
### How can I contribute?
|
||||
- [Contribute code](#how-do-i-contribute-code)
|
||||
- [Run ableos on your machine](#how-do-i-run-ableos)
|
||||
- Find bugs
|
||||
- Create media showing ableos
|
||||
|
||||
### How do I contribute code?
|
||||
- Start by forking ableos
|
||||
- Write something that runs in the userspace, for example:
|
||||
- System drivers
|
||||
- Programs
|
||||
- Libraries
|
||||
- Patch bugs and improve code in the kernel
|
||||
- Ensure that the code is OK to be maintained by asking in the [discord](https://discord.gg/t5Wt3K4YNA)
|
||||
- When you have finished your changes, you can submit a pull request for review [here](https://git.ablecorp.us/ableos/ableos)
|
||||
|
||||
### repbuild and kernel compile, but QEMU isn't starting
|
||||
- Ensure you have the `qemu-desktop-{arch}` for your OS and target architecture installed
|
||||
- Try running again with `--noaccel` if you have QEMU already
|
||||
|
||||
### I have run using repbuild but it's slow
|
||||
- Ensure release mode is enabled with the `-r` flag
|
||||
- Remove the `--noaccel` flag if you can
|
||||
- If both of these are already done, there may be a problem with thee VM, kernel, your program, or the hblang compiler
|
||||
|
||||
### Compiler is complaining about "reg id leaked"
|
||||
- [Submit](#how-do-i-report-a-compiler-bug) an issue, reg id leaked is a bug
|
||||
|
||||
### My program isn't running
|
||||
- Refer to [here](#i-have-run-using-repbuild-but-its-slow), it may be that your program is simply starting slowly
|
||||
- Ensure that your program has a properly written meta.toml file
|
||||
- Ensure that your program is enabled in [system_config.toml](sysdata/system_config.toml)
|
||||
- Try running again with `--noaccel`, there is a known bug with some systems that prevents programs from starting.
|
||||
|
||||
### Kernel panic??? Huh???
|
||||
- Kernel panics can be caused by improperly using memory (e.g, writing out of bounds)
|
||||
- Kernel panics are most likely to be caused when accessing memory or using `@eca` for kernel ecalls
|
||||
- [Report](#how-do-i-report-an-ableos-bug) a kernel panic
|
||||
|
||||
### I am running in release mode but I have no debug info
|
||||
- Add the `-d` flag for debug info
|
||||
|
||||
### What is `@eca`? How do I use it?
|
||||
- Eca is an ecall. They are similar to syscalls
|
||||
- The `@eca` directive takes the following arguments:
|
||||
- `@eca(ecall_number, reg_1, ..., reg_n)`
|
||||
- The various ecalls have different arguments that are given by register values
|
||||
- Most ecalls are wrapped by `stn`, for example, `random`, `buffer`, and `memory` all make use of ecalls
|
||||
- All ecalls can be found [ecah.rs](kernel/src/holeybytes/ecah.rs)
|
||||
|
||||
### How do I report an ableos bug?
|
||||
- Submit an issue [here](https://git.ablecorp.us/ableos/ableos/issues) or report it in the [discord](https://discord.gg/t5Wt3K4YNA)
|
||||
|
||||
### How do I report a compiler bug?
|
||||
- Submit an issue [here](https://git.ablecorp.us/ableos/holey-bytes/issues) or report it in the [discord](https://discord.gg/t5Wt3K4YNA)
|
32
README.md
32
README.md
|
@ -1,16 +1,26 @@
|
|||
# AbleOS
|
||||
An UNIX-unlike micro-kernel written in rust with an embedded bytecode virtual machine.
|
||||
# ableOS
|
||||
![Discord](https://img.shields.io/discord/831368967385120810) ![Code Size](https://img.shields.io/github/languages/code-size/abletheabove/ableos)
|
||||
## Set up
|
||||
Install [Qemu](https://www.qemu.org/)
|
||||
|
||||
Please note that a custom target directory is not supported and support will not be added.
|
||||
> On Windows be sure to add `C:\Program Files\qemu` to your `PATH` variable
|
||||
|
||||
# Community
|
||||
[Discord](https://discord.gg/JrKVukDtgs)
|
||||
`rustup component add rust-src`
|
||||
|
||||
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">
|
||||
`rustup component add llvm-tools-preview`
|
||||
|
||||
# Compiling
|
||||
See [HELP.md](HELP.md)
|
||||
`cargo install bootimage`
|
||||
|
||||
# Developing
|
||||
There is a new work in progress developer tool for hblang. (see: dev folder)
|
||||
|
||||
## Running
|
||||
repbuild can be used to run and build docs for able os
|
||||
|
||||
`cargo repbuild doc`
|
||||
`cargo repbuild run`
|
||||
|
||||
## Testing on real hardware
|
||||
I recommend using an old x86_64 computer
|
||||
* `cargo run --release` to generate a binary image that is bootable
|
||||
* flash it to a USB device via `dd` or balenaEtcher
|
||||
* Remove said USB device and plug into test machine
|
||||
* assure test machine boots from USB devices
|
||||
|
|
|
@ -1,77 +0,0 @@
|
|||
# Style Guide
|
||||
This style guide has two modes that a guideline may be.
|
||||
|
||||
`strict` means that prs will be rejected if they do not follow the guideline.
|
||||
|
||||
`loose` means that a pr would be accepted but should later be fixed.
|
||||
|
||||
## Empty Functions | loose
|
||||
Empty functions are typically a sign of an unfinished program or driver.
|
||||
|
||||
In cases where there is a clear reason to have an empty function it will be allowed.
|
||||
For example FakeAlloc is only empty functions because it is a example of an the allocator api.
|
||||
|
||||
### Allowed
|
||||
```rust
|
||||
/// in example.hb
|
||||
a := fn(): void {}
|
||||
```
|
||||
### Not Allowed
|
||||
```rust
|
||||
/// in fat32.hb
|
||||
a := fn(): void {}
|
||||
```
|
||||
## Magic Functions | loose
|
||||
'Magic functions' are what I am calling small helper functions that do one or two things.
|
||||
### Example
|
||||
```rust
|
||||
a := null
|
||||
magic_a := fn(){
|
||||
a = 10
|
||||
}
|
||||
```
|
||||
The exact policy I want to have here is a bit fuzzy. I think that functions like this are nice in certain situations and not in others.
|
||||
Regardless of if you use them or not, put a comment above the function explaining rational.
|
||||
|
||||
|
||||
## Magic Numbers | loose
|
||||
The policy on magic numbers is make them const and have a comment above them. Typically linking to a source of information about the magic number.
|
||||
|
||||
This helps cut down on magic numbers while making acceptable names and atleast half assed documentation.
|
||||
|
||||
Constants are inlined anyways, so its the same thing in the binary.
|
||||
|
||||
```rust
|
||||
// The standard vga port is mapped at 0xB8000
|
||||
$VGA_PTR := 0xB8000
|
||||
```
|
||||
|
||||
## Tabs Vs Spaces | strict
|
||||
I prefer for hblang code to use hard tabs.
|
||||
|
||||
The rational behind this is that a tab is `1 Indent` which some developers might want to be various different sizes when displayed
|
||||
|
||||
Soft tabs do not allow this user/editor specific as soft tabs always become spaces.
|
||||
|
||||
Bottom line is this is an accessibility feature.
|
||||
|
||||
There are some samples below.
|
||||
```
|
||||
\t means hard tab
|
||||
\n means new line
|
||||
\0x20 means space
|
||||
```
|
||||
|
||||
### Allowed
|
||||
```rust
|
||||
if x == y {\n
|
||||
\tlog(z)\n
|
||||
}\n
|
||||
```
|
||||
|
||||
### Not Allowed
|
||||
```rust
|
||||
if x == y {\n
|
||||
\0x20\0x20\0x20\0x20log(z)\n
|
||||
}\n
|
||||
```
|
|
@ -1,79 +0,0 @@
|
|||
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;
|
||||
}
|
|
@ -1,677 +0,0 @@
|
|||
<?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>
|
Before Width: | Height: | Size: 36 KiB |
|
@ -1,4 +0,0 @@
|
|||
# Commit style
|
||||
`[SCOPE]: [COMMENT]`
|
||||
SCOPE is what you changed
|
||||
COMMENT is why you changed that
|
|
@ -1,32 +0,0 @@
|
|||
# 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
|
|
@ -1,50 +0,0 @@
|
|||
strict graph OS {
|
||||
layout=dot;
|
||||
ModelingSoftware -- GraphicsAPI;
|
||||
ModelingSoftware -- HID;
|
||||
ModelingSoftware -- VFS;
|
||||
|
||||
GameEngine3D -- GraphicsAPI;
|
||||
GameEngine3D -- VFS;
|
||||
GameEngine3D -- AudioSubsystem;
|
||||
GameEngine3D -- HID;
|
||||
GameEngine3D -- Networking;
|
||||
|
||||
Git -- VFS;
|
||||
Git -- Networking;
|
||||
|
||||
ListFile -- VFS;
|
||||
MakeFile -- VFS;
|
||||
|
||||
AudioSubsystem -- AbleOSInterface;
|
||||
GraphicsAPI -- AbleOSInterface;
|
||||
HID -- AbleOSInterface;
|
||||
Networking -- AbleOSInterface;
|
||||
|
||||
FatFileSystemProc -- VFS;
|
||||
NTFSFileSystemProc -- VFS;
|
||||
EXT2 -- VFS;
|
||||
|
||||
FatFileSystemProc -- DriveSystemProc;
|
||||
NTFSFileSystemProc -- DriveSystemProc;
|
||||
EXT2 -- DriveSystemProc;
|
||||
|
||||
|
||||
DriveSystemProc -- AbleOSInterface;
|
||||
|
||||
AbleOSInterface -- DriveSystemProc;
|
||||
AbleOSInterface -- Kernel;
|
||||
|
||||
|
||||
Kernel -- x86HAL;
|
||||
Kernel -- riscvHAL;
|
||||
Kernel -- aarch64HAL;
|
||||
|
||||
x86HAL -- GPU;
|
||||
riscvHAL -- GPU;
|
||||
aarch64HAL -- GPU;
|
||||
|
||||
x86HAL -- SoundCard;
|
||||
riscvHAL -- SoundCard;
|
||||
aarch64HAL -- SoundCard;
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
[package]
|
||||
name = "dev"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
logos = "0.14.1"
|
|
@ -1,6 +0,0 @@
|
|||
# dev
|
||||
`dev` is an ableOS specific tool meant to help the development of ableOS.
|
||||
|
||||
At the current stage changes are not welcome. If you have feature suggestions ping me on discord `@abletheabove`.
|
||||
|
||||
Run `cargo dev help` to see usage.
|
|
@ -1,84 +0,0 @@
|
|||
pub mod protocol;
|
||||
|
||||
use std::io::Read;
|
||||
|
||||
use {
|
||||
logos::{Lexer, Logos},
|
||||
protocol::Protocol,
|
||||
};
|
||||
|
||||
#[derive(Logos, Debug, PartialEq, Clone)]
|
||||
#[logos(skip r"[ \t\n\f]+")] // Ignore this regex pattern between tokens
|
||||
enum Token {
|
||||
// Tokens can be literal strings, of any length.
|
||||
#[token("protocol")]
|
||||
Protocol,
|
||||
|
||||
#[token("{")]
|
||||
LBrace,
|
||||
|
||||
#[token("}")]
|
||||
RBrace,
|
||||
|
||||
#[token("(")]
|
||||
LParen,
|
||||
|
||||
#[token(")")]
|
||||
RParen,
|
||||
|
||||
#[token(":")]
|
||||
Colon,
|
||||
#[token(";")]
|
||||
SemiColon,
|
||||
|
||||
#[token(",")]
|
||||
Comma,
|
||||
|
||||
#[token("=")]
|
||||
Equal,
|
||||
|
||||
#[token("->")]
|
||||
RArrow,
|
||||
|
||||
#[regex("[a-zA-Z_]+", |lex|{lex.slice().to_string()})]
|
||||
Text(String),
|
||||
|
||||
#[regex("[1234567890]+", |lex|{lex.slice().parse::<u64>().unwrap()})]
|
||||
Number(u64),
|
||||
|
||||
#[regex(r"@[a-zA-Z_]+", |lex|{lex.slice().to_string()})]
|
||||
Decorator(String),
|
||||
|
||||
#[regex(r#"@[a-zA-Z_]+\([a-zA-Z,0-9=]+\)"#, |lex|{lex.slice().to_string()})]
|
||||
DecoratorOption(String),
|
||||
}
|
||||
|
||||
pub fn build_idl(name: String) {
|
||||
let contents = open_protocol(name);
|
||||
let lex = Token::lexer(&contents);
|
||||
let mut tokens = vec![];
|
||||
for x in lex {
|
||||
match x {
|
||||
Ok(token) => {
|
||||
println!("{:?}", token);
|
||||
tokens.push(token);
|
||||
}
|
||||
Err(err) => println!("{:?}", err),
|
||||
}
|
||||
}
|
||||
build(tokens);
|
||||
}
|
||||
|
||||
fn build(a: Vec<Token>) {
|
||||
for toke in a {
|
||||
println!("{:?}", toke);
|
||||
}
|
||||
}
|
||||
|
||||
fn open_protocol(name: String) -> String {
|
||||
let path = format!("sysdata/idl/{}/src/protocol.aidl", name);
|
||||
let mut file = std::fs::File::open(path).unwrap();
|
||||
let mut contents = String::new();
|
||||
file.read_to_string(&mut contents).unwrap();
|
||||
contents
|
||||
}
|
|
@ -1,17 +0,0 @@
|
|||
pub enum ProtocolTypes {
|
||||
Byte,
|
||||
}
|
||||
|
||||
pub struct Protocol {}
|
||||
impl Protocol {
|
||||
pub fn is_empty(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
pub fn validate_data(&self, data: Vec<u8>) -> bool {
|
||||
if !data.is_empty() && self.is_empty() {
|
||||
return false;
|
||||
}
|
||||
true
|
||||
}
|
||||
}
|
152
dev/src/main.rs
152
dev/src/main.rs
|
@ -1,152 +0,0 @@
|
|||
use std::io::Write;
|
||||
|
||||
use idl::build_idl;
|
||||
pub mod idl;
|
||||
|
||||
pub enum Options {
|
||||
Build,
|
||||
Clean,
|
||||
New,
|
||||
Run,
|
||||
}
|
||||
#[derive(PartialEq, Debug)]
|
||||
pub enum DevelopmentType {
|
||||
Program,
|
||||
Library,
|
||||
IDL,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let mut args: Vec<String> = std::env::args().collect();
|
||||
args.remove(0);
|
||||
args.reverse();
|
||||
|
||||
let binding = args.pop().unwrap_or("help".to_string());
|
||||
let subcommand = binding.as_str();
|
||||
|
||||
match subcommand {
|
||||
"build" => {
|
||||
let name = &args.pop().unwrap();
|
||||
build(name.to_string())
|
||||
}
|
||||
"new" => {
|
||||
let binding = args.pop().unwrap();
|
||||
let dev_type = binding.as_str();
|
||||
let name = args.pop().unwrap();
|
||||
use DevelopmentType::*;
|
||||
match dev_type {
|
||||
"lib" | "library" => new(Library, name),
|
||||
"prog" | "program" => new(Program, name),
|
||||
"idl" => {
|
||||
new(IDL, name);
|
||||
// idl::main();
|
||||
panic!("IDL is not finalized yet.")
|
||||
}
|
||||
_ => {}
|
||||
};
|
||||
}
|
||||
"run" => run(),
|
||||
"help" => help(),
|
||||
_ => {
|
||||
println!("Error");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new(development_type: DevelopmentType, name: String) {
|
||||
let (folder_hierarchy, entry_name) = match development_type {
|
||||
DevelopmentType::Program => ("programs", "main.hb"),
|
||||
DevelopmentType::Library => ("libraries", "lib.hb"),
|
||||
DevelopmentType::IDL => ("idl", "protocol.aidl"),
|
||||
};
|
||||
let project_folder_path_string = format!("sysdata/{folder_hierarchy}/{name}");
|
||||
|
||||
if std::path::Path::new(&project_folder_path_string).exists() {
|
||||
panic!("Project already exists.")
|
||||
}
|
||||
|
||||
std::fs::create_dir(project_folder_path_string.clone()).unwrap();
|
||||
let readme_path_string = format!("{}/README.md", project_folder_path_string);
|
||||
let mut readme_file = std::fs::File::create(readme_path_string.clone()).unwrap();
|
||||
|
||||
let readme_contents = format!("# {}", name);
|
||||
readme_file.write_all(readme_contents.as_bytes()).unwrap();
|
||||
|
||||
let contents = format!(
|
||||
"[package]
|
||||
name = \"{}\"
|
||||
authors = [\"\"]
|
||||
|
||||
[dependants.libraries]
|
||||
|
||||
[dependants.binaries]
|
||||
hblang.version = \"1.0.0\"
|
||||
|
||||
[build]
|
||||
command = \"hblang src/main.hb\"
|
||||
",
|
||||
name
|
||||
);
|
||||
|
||||
let toml_path_string = format!("{}/meta.toml", project_folder_path_string);
|
||||
let mut readme_file = std::fs::File::create(toml_path_string.clone()).unwrap();
|
||||
|
||||
readme_file.write_all(contents.as_bytes()).unwrap();
|
||||
|
||||
let src_folder_path_string = format!("{}/src", project_folder_path_string);
|
||||
std::fs::create_dir(src_folder_path_string.clone()).unwrap();
|
||||
|
||||
let full_path_string = format!("{src_folder_path_string}/{entry_name}");
|
||||
let mut file = std::fs::File::create(full_path_string.clone()).unwrap();
|
||||
let file_contents = match development_type {
|
||||
DevelopmentType::Program => "main := fn(): int {
|
||||
return 0
|
||||
}"
|
||||
.to_string(),
|
||||
DevelopmentType::Library => "".to_string(),
|
||||
DevelopmentType::IDL => format!(
|
||||
"protocol {} {{
|
||||
}}",
|
||||
name
|
||||
)
|
||||
.to_owned(),
|
||||
}
|
||||
.to_string();
|
||||
file.write_all(file_contents.as_bytes()).unwrap();
|
||||
|
||||
println!("New project created.");
|
||||
if development_type == DevelopmentType::Program {
|
||||
println!("You should add your project into the ableOS system configuration in sysdata/system_config.toml")
|
||||
}
|
||||
}
|
||||
|
||||
fn run() {
|
||||
println!("Running is not supported on a non-ableOS platform");
|
||||
}
|
||||
|
||||
fn build(name: String) {
|
||||
println!("building {}", name);
|
||||
let mut a = name.split("/");
|
||||
let dev_type = a.next().unwrap();
|
||||
let name = a.next().unwrap().to_string();
|
||||
match dev_type {
|
||||
"programs" => build_program(name),
|
||||
"idl" => build_idl(name),
|
||||
_ => {
|
||||
panic!()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn build_program(_name: String) {}
|
||||
pub fn build_library(_name: String) {}
|
||||
|
||||
fn help() {
|
||||
println!(
|
||||
"==========
|
||||
= Help =
|
||||
==========
|
||||
Subcommands
|
||||
- new Usage: `cargo dev new library name` or `cargo dev new program name`"
|
||||
)
|
||||
}
|
96
flake.lock
96
flake.lock
|
@ -1,96 +0,0 @@
|
|||
{
|
||||
"nodes": {
|
||||
"flake-utils": {
|
||||
"inputs": {
|
||||
"systems": "systems"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1731533236,
|
||||
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1732014248,
|
||||
"narHash": "sha256-y/MEyuJ5oBWrWAic/14LaIr/u5E0wRVzyYsouYY3W6w=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "23e89b7da85c3640bbc2173fe04f4bd114342367",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixos-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs_2": {
|
||||
"locked": {
|
||||
"lastModified": 1728538411,
|
||||
"narHash": "sha256-f0SBJz1eZ2yOuKUr5CA9BHULGXVSn6miBuUWdTyhUhU=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "b69de56fac8c2b6f8fd27f2eca01dcda8e0a4221",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixpkgs-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"flake-utils": "flake-utils",
|
||||
"nixpkgs": "nixpkgs",
|
||||
"rust-overlay": "rust-overlay"
|
||||
}
|
||||
},
|
||||
"rust-overlay": {
|
||||
"inputs": {
|
||||
"nixpkgs": "nixpkgs_2"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1732328983,
|
||||
"narHash": "sha256-RHt12f/slrzDpSL7SSkydh8wUE4Nr4r23HlpWywed9E=",
|
||||
"owner": "oxalica",
|
||||
"repo": "rust-overlay",
|
||||
"rev": "ed8aa5b64f7d36d9338eb1d0a3bb60cf52069a72",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "oxalica",
|
||||
"repo": "rust-overlay",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"systems": {
|
||||
"locked": {
|
||||
"lastModified": 1681028828,
|
||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"type": "github"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
"version": 7
|
||||
}
|
30
flake.nix
30
flake.nix
|
@ -1,30 +0,0 @@
|
|||
{
|
||||
description = "A devShell example";
|
||||
|
||||
inputs = {
|
||||
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
||||
rust-overlay.url = "github:oxalica/rust-overlay";
|
||||
flake-utils.url = "github:numtide/flake-utils";
|
||||
};
|
||||
|
||||
outputs = { self, nixpkgs, rust-overlay, flake-utils }:
|
||||
flake-utils.lib.eachDefaultSystem (system:
|
||||
let
|
||||
overlays = [ (import rust-overlay) ];
|
||||
pkgs = import nixpkgs {
|
||||
inherit system overlays;
|
||||
};
|
||||
|
||||
rustToolchain = pkgs.pkgsBuildHost.rust-bin.fromRustupToolchainFile ./rust-toolchain.toml;
|
||||
in
|
||||
with pkgs;
|
||||
{
|
||||
devShells.default = mkShell {
|
||||
buildInputs = [
|
||||
rustToolchain
|
||||
qemu_full
|
||||
];
|
||||
};
|
||||
}
|
||||
);
|
||||
}
|
|
@ -4,3 +4,6 @@ build-std-features = ["compiler-builtins-mem"]
|
|||
|
||||
[build]
|
||||
target = "./targets/x86_64-ableos.json"
|
||||
|
||||
[target.'cfg(target_arch = "x86_64")']
|
||||
rustflags = ["-C", "target-feature=+rdrand"]
|
||||
|
|
|
@ -2,33 +2,28 @@
|
|||
edition = "2021"
|
||||
name = "kernel"
|
||||
version = "0.2.0"
|
||||
|
||||
[features]
|
||||
ktest = []
|
||||
resolver = "2"
|
||||
|
||||
[dependencies]
|
||||
# embedded-graphics = "0.8"
|
||||
hbvm = { git = "https://git.ablecorp.us/AbleOS/holey-bytes.git", features = [
|
||||
"nightly", "alloc", "disasm"
|
||||
] }
|
||||
ktest_macro = { path = "ktest_macro" }
|
||||
error-stack = { version = "0.3", default-features = false }
|
||||
log = "0.4"
|
||||
spin = "0.9"
|
||||
uart_16550 = "0.2"
|
||||
slab = { version = "0.4", default-features = false }
|
||||
uart_16550 = { version = "0.3", features = ["nightly"] }
|
||||
xml.git = "https://git.ablecorp.us/ableos/ableos_userland"
|
||||
versioning.git = "https://git.ablecorp.us/ableos/ableos_userland"
|
||||
# able_graphics_library.git = "https://git.ablecorp.us/ableos/ableos_userland"
|
||||
hashbrown = { version = "0.15", features = ["nightly"] }
|
||||
limine = "0.1"
|
||||
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" }
|
||||
wasmi = { version = "0.29.0", default-features = false }
|
||||
hashbrown = "*"
|
||||
|
||||
[dependencies.crossbeam-queue]
|
||||
version = "0.3"
|
||||
default-features = false
|
||||
features = ["alloc", "nightly"]
|
||||
features = ["alloc"]
|
||||
|
||||
[dependencies.derive_more]
|
||||
version = "1"
|
||||
version = "0.99"
|
||||
default-features = false
|
||||
features = [
|
||||
"add",
|
||||
|
@ -45,12 +40,12 @@ features = [
|
|||
|
||||
|
||||
[target.'cfg(target_arch = "x86_64")'.dependencies]
|
||||
x86_64 = "0.15"
|
||||
limine = { version = "0.1", git = "https://github.com/limine-bootloader/limine-rs" }
|
||||
x86_64 = "0.14"
|
||||
x2apic = "0.4"
|
||||
# virtio-drivers = "0.7"
|
||||
# rdrand = "*"
|
||||
rdrand = { version = "0.8", default-features = false }
|
||||
|
||||
|
||||
[target.'cfg(target_arch = "riscv64")'.dependencies]
|
||||
sbi = "0.2.0"
|
||||
|
||||
[target.'cfg(target_arch = "aarch64")'.dependencies]
|
||||
aarch64-cpu = "9"
|
||||
|
|
36
kernel/data/test.wat
Normal file
36
kernel/data/test.wat
Normal file
|
@ -0,0 +1,36 @@
|
|||
(module
|
||||
(data "mouse")
|
||||
(data "x")
|
||||
(data "y")
|
||||
(func $rma (import "host" "read_mem_addr")(param i32)(result i32))
|
||||
(func $co (import "host" "create_object")(param i32 i32)(result i64))
|
||||
(func $roa (import "host" "read_object_attribute")(param i64 i32 i32)(result i32 i32))
|
||||
(memory (export "memory") 1)
|
||||
|
||||
(func
|
||||
(export "start")(result i64)
|
||||
;; Copy into memory the object name
|
||||
(memory.init 0
|
||||
(i32.const 0) ;; target offset
|
||||
(i32.const 0) ;; source offset
|
||||
(i32.const 5))
|
||||
(memory.init 1
|
||||
(i32.const 6) ;; target offset
|
||||
(i32.const 0) ;; source offset
|
||||
(i32.const 1))
|
||||
(memory.init 2
|
||||
(i32.const 7) ;; target offset
|
||||
(i32.const 0) ;; source offset
|
||||
(i32.const 1))
|
||||
|
||||
i32.const 0
|
||||
i32.const 5
|
||||
call $co
|
||||
|
||||
;; i32.const 6
|
||||
;; i32.const 1
|
||||
|
||||
;; call $roa
|
||||
|
||||
)
|
||||
)
|
33
kernel/data/⑨. バカ
Normal file
33
kernel/data/⑨. バカ
Normal file
|
@ -0,0 +1,33 @@
|
|||
|
||||
.//// *(####
|
||||
(####((/, (########,
|
||||
(##%##(###(( ,(#########%#
|
||||
#%%%%###(###((. *((####%%&%%%%#
|
||||
.#####%%%%%####((. *(####%&&&&&%%%%#
|
||||
#(((((((##%%&&%#((/ /#(##%&&%##########
|
||||
/######%%%%%%%(..........(#%%%%%%#####%%#
|
||||
,#%%%%%%#/...... ..............,&&&%%###.
|
||||
,%%#(#(...........................(#&&%%#
|
||||
.###%...............................%%#(#.
|
||||
#%&.................................%#
|
||||
,%&&*.................................&&%(
|
||||
%%#//........./............*/..,......&&&%#
|
||||
.......,..............*,*.,,,,,,.
|
||||
......./....,.........*,,,,.,,,,,,
|
||||
,...../..(###%,.....&*&%###/..,.,,.
|
||||
,,..../%(((#(,.....,%%%%###,..,..,.
|
||||
.,,*.../..,#,.........,(&(,,**.,,,,,
|
||||
,/((..,*..........,,.,,,,,**.,##((
|
||||
/(((%%%,,,,,.,,,,,,,,,,,#/##(,(/
|
||||
.***..(,.#%%%&&#/%,,(%*,,**#
|
||||
**,...,(#%%%%&#%%%#%%%%,,.,,***.
|
||||
.....,*,*#%%%%%###%##%%%&,,*,,....
|
||||
......,*/. (############%%%&&&&#*,,....
|
||||
...,*,..,(((((((((((#((((((((((((&&&#*,
|
||||
,##///////(((((((((((((#///#///(##/.
|
||||
/*/**//... ...**(((((((,. .,*......
|
||||
....... ......,,/*,. ...........
|
||||
,..,,,,...... .. .... ,,....... ..,,,
|
||||
........,.,.,*//////*,......,.
|
||||
...,,,, ,,,,,,
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
[package]
|
||||
edition = "2021"
|
||||
name = "ktest_macro"
|
||||
version = "0.1.0"
|
||||
|
||||
[lib]
|
||||
proc-macro = true
|
||||
|
||||
[dependencies]
|
||||
quote = "1.0.37"
|
||||
syn = { version = "2.0.89", features = ["full"] }
|
|
@ -1,86 +0,0 @@
|
|||
extern crate proc_macro;
|
||||
extern crate quote;
|
||||
extern crate syn;
|
||||
|
||||
use {
|
||||
proc_macro::TokenStream,
|
||||
quote::quote,
|
||||
syn::{parse::Parse, parse_macro_input, Expr, ItemFn, Token}
|
||||
};
|
||||
|
||||
struct KtestInput {
|
||||
lhs: Expr,
|
||||
_comma: Token![,],
|
||||
rhs: Expr,
|
||||
}
|
||||
|
||||
impl Parse for KtestInput {
|
||||
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
|
||||
Ok(Self {
|
||||
lhs: input.parse()?,
|
||||
_comma: input.parse()?,
|
||||
rhs: input.parse()?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[proc_macro]
|
||||
pub fn ktest_eq(item: TokenStream) -> TokenStream {
|
||||
let input = parse_macro_input!(item as KtestInput);
|
||||
|
||||
let lhs = input.lhs;
|
||||
let rhs = input.rhs;
|
||||
|
||||
let out = quote! {
|
||||
if #lhs != #rhs {
|
||||
return Err(name);
|
||||
}
|
||||
};
|
||||
TokenStream::from(out)
|
||||
}
|
||||
|
||||
#[proc_macro]
|
||||
pub fn ktest_neq(item: TokenStream) -> TokenStream {
|
||||
let input = parse_macro_input!(item as KtestInput);
|
||||
|
||||
let lhs = input.lhs;
|
||||
let rhs = input.rhs;
|
||||
|
||||
let out = quote! {
|
||||
if #lhs == #rhs {
|
||||
return Err(name);
|
||||
}
|
||||
};
|
||||
TokenStream::from(out)
|
||||
}
|
||||
|
||||
#[proc_macro_attribute]
|
||||
pub fn ktest(_attr: TokenStream, item: TokenStream) -> TokenStream {
|
||||
let input = parse_macro_input!(item as ItemFn);
|
||||
let test_name = &input.sig.ident;
|
||||
let test_string = test_name.to_string();
|
||||
let static_var_name = syn::Ident::new(
|
||||
&format!("__ktest_{}", test_name).to_uppercase(),
|
||||
test_name.span(),
|
||||
);
|
||||
|
||||
let block = &input.block;
|
||||
let out = quote! {
|
||||
#[cfg(feature = "ktest")]
|
||||
fn #test_name() -> Result<String, String> {
|
||||
use crate::alloc::string::ToString;
|
||||
let name = #test_string.to_string();
|
||||
|
||||
#block
|
||||
|
||||
return Ok(name);
|
||||
}
|
||||
|
||||
#[cfg(feature = "ktest")]
|
||||
#[unsafe(link_section = ".note.ktest")]
|
||||
#[used]
|
||||
pub static #static_var_name: fn() -> Result<String, String> = #test_name;
|
||||
};
|
||||
|
||||
TokenStream::from(out)
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
ENTRY(_kernel_start)
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
. = 0xffffffff80000000;
|
||||
.text.boot : { *(.text.boot) }
|
||||
.text : { *(.text) }
|
||||
.data : { *(.data) }
|
||||
.note.ktest : {
|
||||
__ktest_start = .;
|
||||
*(.note.ktest)
|
||||
__ktest_end = .;
|
||||
}
|
||||
.rodata : { *(.rodata) }
|
||||
.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);
|
||||
. = . + 0x4000;
|
||||
LD_STACK_PTR = .;
|
||||
}
|
|
@ -38,16 +38,8 @@ SECTIONS
|
|||
|
||||
.data : {
|
||||
*(.data .data.*)
|
||||
*(.got .got.*)
|
||||
} :data
|
||||
|
||||
/* Add the .ktest section for test functions */
|
||||
.note.ktest : {
|
||||
__ktest_start = .; /* Mark the beginning of the section */
|
||||
*(.note.ktest) /* Include all items in the .ktest section */
|
||||
__ktest_end = .; /* Mark the end of the section */
|
||||
}
|
||||
|
||||
.bss : {
|
||||
*(COMMON)
|
||||
*(.bss .bss.*)
|
||||
|
@ -55,8 +47,7 @@ SECTIONS
|
|||
/* 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);
|
||||
PROVIDE(_initial_kernel_heap_size = 1024 * 1024);
|
||||
. += _initial_kernel_heap_size;
|
||||
} :data
|
||||
}
|
||||
|
|
|
@ -27,16 +27,14 @@
|
|||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
use {
|
||||
core::{
|
||||
use core::{
|
||||
alloc::{GlobalAlloc, Layout},
|
||||
mem,
|
||||
ptr::{self, NonNull},
|
||||
},
|
||||
log::trace,
|
||||
spin::Mutex,
|
||||
};
|
||||
|
||||
use spin::Mutex;
|
||||
|
||||
struct Allocator(Mutex<Option<Heap>>);
|
||||
|
||||
unsafe impl GlobalAlloc for Allocator {
|
||||
|
@ -62,7 +60,7 @@ static ALLOCATOR: Allocator = Allocator(Mutex::new(None));
|
|||
|
||||
// FIXME: umm is `memory` VirtualAddress or PhysicalAddress? both?
|
||||
pub fn init(memory: *mut u8, memory_size: usize) {
|
||||
trace!("Initialising kernel heap allocator");
|
||||
log::info!("Initialising kernel heap allocator");
|
||||
*ALLOCATOR.0.lock() = Some(unsafe { Heap::new(memory, memory_size) });
|
||||
}
|
||||
|
||||
|
@ -146,30 +144,19 @@ impl Heap {
|
|||
self.allocated_chunks += chunks_needed;
|
||||
|
||||
let ptr: *mut u8 = unsafe { mem::transmute(header.add(1)) };
|
||||
{
|
||||
#[cfg(debug_assertions)]
|
||||
trace!("Allocating {:?}", ptr);
|
||||
}
|
||||
|
||||
unsafe { core::ptr::write_bytes(ptr, 0, size) };
|
||||
|
||||
// FIXME: zero or scrub memory?
|
||||
assert!(ptr.is_aligned_to(alignment));
|
||||
NonNull::new(ptr)
|
||||
}
|
||||
|
||||
fn deallocate(&mut self, ptr: *mut u8) {
|
||||
{
|
||||
#[cfg(debug_assertions)]
|
||||
log::trace!("Deallocating {:?}", ptr);
|
||||
}
|
||||
let header = Self::allocation_header(ptr);
|
||||
let start = (header as usize - self.chunks as usize) / CHUNK_SIZE;
|
||||
assert!(self.bitmap_get(start));
|
||||
let size = unsafe { (*header).size_in_chunks };
|
||||
self.bitmap_set_range(start, size, false);
|
||||
self.allocated_chunks -= size;
|
||||
// FIXME: zero out memory to prevent leaking data
|
||||
// REPLY: When we zero on alloc, do we really need it?
|
||||
// FIXME: zero or scrub memory?
|
||||
}
|
||||
|
||||
/// Finds first hole that can fit an allocation of `size` chunks, returns the start of the
|
||||
|
@ -251,10 +238,7 @@ impl Heap {
|
|||
return Some(start_of_free_chunks);
|
||||
}
|
||||
}
|
||||
#[cfg(debug_assertions)]
|
||||
{
|
||||
trace!("No first fit found");
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
|
@ -324,7 +308,7 @@ impl Heap {
|
|||
(unsafe { *self.bitmap.add(index / 8) } & (1 << (index % 8))) != 0
|
||||
}
|
||||
|
||||
pub const fn free_chunks(&self) -> usize {
|
||||
const fn free_chunks(&self) -> usize {
|
||||
self.total_chunks - self.allocated_chunks
|
||||
}
|
||||
|
||||
|
@ -341,11 +325,5 @@ unsafe impl Send for Heap {}
|
|||
|
||||
#[alloc_error_handler]
|
||||
fn alloc_error_handler(layout: alloc::alloc::Layout) -> ! {
|
||||
log::error!("allocation error: {:?}", layout);
|
||||
// Todo: Maybe panic here instead
|
||||
crate::arch::spin_loop()
|
||||
}
|
||||
|
||||
pub fn get_free_chunks_count() -> usize {
|
||||
ALLOCATOR.0.lock().as_ref().unwrap().free_chunks()
|
||||
crate::arch::sloop()
|
||||
}
|
||||
|
|
|
@ -1,50 +0,0 @@
|
|||
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)
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
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,123 +1 @@
|
|||
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;
|
||||
static FB_REQ: FramebufferRequest = FramebufferRequest::new(0);
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn _kernel_start() -> ! {
|
||||
crate::logger::init().expect("failed to set logger");
|
||||
log::info!("Initialising AKern {}", crate::VERSION);
|
||||
|
||||
static HDHM_REQ: HhdmRequest = HhdmRequest::new(0);
|
||||
// memory::init_pt(VirtAddr::new(
|
||||
// HDHM_REQ
|
||||
// .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);
|
||||
}
|
||||
|
||||
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() -> ! {
|
||||
loop {
|
||||
unsafe { asm!("wfi") }
|
||||
}
|
||||
}
|
||||
|
||||
/// I am sorry.
|
||||
static mut A_REAL_RANDOM_U64_I_PROMISE: u64 = 0;
|
||||
|
||||
pub fn hardware_random_u64() -> u64 {
|
||||
if let Some(rng) = aarch64_cpu::asm::random::ArmRng::new() {
|
||||
if let Some(rnd) = rng.rndr() {
|
||||
return rnd;
|
||||
}
|
||||
}
|
||||
unsafe {
|
||||
A_REAL_RANDOM_U64_I_PROMISE += 1;
|
||||
A_REAL_RANDOM_U64_I_PROMISE
|
||||
}
|
||||
}
|
||||
|
||||
pub fn register_dump() {}
|
||||
#[no_mangle]
|
||||
pub fn fmod() {}
|
||||
//!
|
|
@ -14,29 +14,3 @@ arch_cond!(
|
|||
riscv64: "riscv64",
|
||||
x86_64: "x86_64",
|
||||
);
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
use {crate::arch::interrupts::Interrupt, alloc::string::String};
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
pub struct InterruptList {
|
||||
list: HashMap<Interrupt, String>,
|
||||
}
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
use hashbrown::HashMap;
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
impl InterruptList {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
list: HashMap::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
use spin::{Lazy, Mutex};
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
pub static INTERRUPT_LIST: Lazy<Mutex<InterruptList>> = Lazy::new(|| {
|
||||
let mut il = InterruptList::new();
|
||||
use crate::alloc::string::ToString;
|
||||
il.list.insert(Interrupt::Timer, "PS/2 Mouse".to_string());
|
||||
Mutex::new(il)
|
||||
});
|
||||
|
|
|
@ -1,10 +1,8 @@
|
|||
use core::num;
|
||||
|
||||
use {
|
||||
crate::memory::{MemoryManager, PhysicalAddress, VirtualAddress},
|
||||
alloc::boxed::Box,
|
||||
spin::{Mutex, Once},
|
||||
};
|
||||
use alloc::boxed::Box;
|
||||
use spin::{Mutex, Once};
|
||||
use crate::memory::{MemoryManager, PhysicalAddress, VirtualAddress};
|
||||
|
||||
use super::PAGE_SIZE;
|
||||
|
||||
|
@ -30,7 +28,7 @@ impl PageSize {
|
|||
}
|
||||
|
||||
pub struct PageTable {
|
||||
entries: [PageEntry; 512],
|
||||
entries: [PageEntry; 512]
|
||||
}
|
||||
|
||||
impl PageTable {
|
||||
|
@ -74,14 +72,8 @@ impl PageTable {
|
|||
/// flags MUST include one or more of the following:
|
||||
/// Read, Write, Execute
|
||||
/// The valid bit automatically gets added
|
||||
pub fn map(
|
||||
&mut self,
|
||||
vaddr: VirtualAddress,
|
||||
paddr: PhysicalAddress,
|
||||
flags: PageEntryFlags,
|
||||
page_size: PageSize,
|
||||
) {
|
||||
assert!(flags as usize & 0xE != 0);
|
||||
pub fn map(&mut self, vaddr: VirtualAddress, paddr: PhysicalAddress, flags: PageEntryFlags, page_size: PageSize) {
|
||||
assert!(flags as usize & 0xe != 0);
|
||||
|
||||
let vpn = vaddr.vpns();
|
||||
let ppn = paddr.ppns();
|
||||
|
@ -113,24 +105,14 @@ impl PageTable {
|
|||
}
|
||||
|
||||
/// Identity maps a page of memory
|
||||
pub fn identity_map(
|
||||
&mut self,
|
||||
addr: PhysicalAddress,
|
||||
flags: PageEntryFlags,
|
||||
page_size: PageSize,
|
||||
) {
|
||||
pub fn identity_map(&mut self, addr: PhysicalAddress, flags: PageEntryFlags, page_size: PageSize) {
|
||||
// log::debug!("identity mapped {addr}");
|
||||
self.map(addr.as_addr().into(), addr, flags, page_size);
|
||||
}
|
||||
|
||||
/// Identity maps a range of contiguous memory
|
||||
/// This assumes that start <= end
|
||||
pub fn identity_map_range(
|
||||
&mut self,
|
||||
start: PhysicalAddress,
|
||||
end: PhysicalAddress,
|
||||
flags: PageEntryFlags,
|
||||
) {
|
||||
pub fn identity_map_range(&mut self, start: PhysicalAddress, end: PhysicalAddress, flags: PageEntryFlags) {
|
||||
log::debug!("start: {start}, end: {end}");
|
||||
let mut mem_addr = start.as_addr() & !(PAGE_SIZE - 1);
|
||||
let num_pages = (align_val(end.as_addr(), 12) - mem_addr - 1) / PAGE_SIZE + 1;
|
||||
|
@ -246,7 +228,7 @@ impl PageEntry {
|
|||
}
|
||||
|
||||
fn addr(&self) -> PhysicalAddress {
|
||||
((self.entry() as usize & !0x3FF) << 2).into()
|
||||
((self.entry() as usize & !0x3ff) << 2).into()
|
||||
}
|
||||
|
||||
fn destroy(&mut self) {
|
||||
|
|
|
@ -1,28 +1,19 @@
|
|||
mod memory;
|
||||
|
||||
use {
|
||||
alloc::{boxed::Box, vec::Vec},
|
||||
core::{
|
||||
arch::{asm, global_asm},
|
||||
fmt::Write,
|
||||
},
|
||||
sbi::system_reset::{system_reset, ResetReason, ResetType},
|
||||
spin::{Mutex, Once},
|
||||
uart_16550::MmioSerialPort,
|
||||
};
|
||||
use core::{arch::{asm, global_asm}, fmt::Write};
|
||||
use alloc::boxed::Box;
|
||||
use sbi::system_reset::{ResetType, ResetReason, system_reset};
|
||||
use spin::{Mutex, Once};
|
||||
use uart_16550::MmioSerialPort;
|
||||
|
||||
use crate::{
|
||||
allocator,
|
||||
arch::riscv64::memory::{PageEntryFlags, PageSize, PageTable, PAGE_TABLE},
|
||||
memory::PhysicalAddress,
|
||||
};
|
||||
use crate::{allocator, memory::PhysicalAddress, arch::riscv64::memory::{PAGE_TABLE, PageEntryFlags, PageSize, PageTable}};
|
||||
|
||||
global_asm!(include_str!("entry.s"));
|
||||
global_asm!(include_str!("memory_regions.s"));
|
||||
|
||||
pub const PAGE_SIZE: usize = 4096;
|
||||
|
||||
extern "C" {
|
||||
extern {
|
||||
static TEXT_START: PhysicalAddress;
|
||||
static TEXT_END: PhysicalAddress;
|
||||
|
||||
|
@ -45,18 +36,15 @@ extern "C" {
|
|||
static USABLE_MEMORY_SIZE: usize;
|
||||
}
|
||||
|
||||
pub static SERIAL_CONSOLE: Once<Mutex<MmioSerialPort>> = Once::new();
|
||||
static SERIAL_CONSOLE: Once<Mutex<MmioSerialPort>> = Once::new();
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn _kernel_start() -> ! {
|
||||
unsafe extern fn _kernel_start() -> ! {
|
||||
SERIAL_CONSOLE.call_once(|| Mutex::new(unsafe { MmioSerialPort::new(0x1000_0000) }));
|
||||
crate::logger::init().expect("failed to set logger");
|
||||
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);
|
||||
|
||||
let mut page_table_addr = PAGE_TABLE.get().unwrap().lock();
|
||||
|
@ -73,17 +61,9 @@ unsafe extern "C" fn _kernel_start() -> ! {
|
|||
// Map bss section (includes stack and initial kernel heap)
|
||||
page_table.identity_map_range(BSS_START, BSS_END, PageEntryFlags::ReadWrite);
|
||||
// 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
|
||||
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 satp_value = 8 << 60 | table_ppn;
|
||||
|
@ -95,22 +75,16 @@ unsafe extern "C" fn _kernel_start() -> ! {
|
|||
in(reg) satp_value,
|
||||
);
|
||||
|
||||
crate::kmain::kmain("baka=9", Vec::new());
|
||||
crate::kmain::kmain("baka=9", None);
|
||||
}
|
||||
|
||||
/// Spin loop
|
||||
pub fn spin_loop() -> ! {
|
||||
pub fn sloop() -> ! {
|
||||
loop {
|
||||
unsafe { asm!("wfi") }
|
||||
}
|
||||
}
|
||||
|
||||
pub fn hardware_random_u64() -> u64 {
|
||||
0
|
||||
}
|
||||
|
||||
pub fn register_dump() {}
|
||||
|
||||
pub fn log(args: core::fmt::Arguments<'_>) -> core::fmt::Result {
|
||||
SERIAL_CONSOLE.get().unwrap().lock().write_fmt(args)
|
||||
}
|
||||
|
|
|
@ -1,934 +0,0 @@
|
|||
use crate::cpu_features;
|
||||
|
||||
use {
|
||||
alloc::vec::Vec,
|
||||
core::{arch::asm, fmt, ops::Deref, slice, str},
|
||||
};
|
||||
#[repr(u32)]
|
||||
pub enum RequestType {
|
||||
BasicInformation = 0x0000_0000,
|
||||
VersionInformation = 0x0000_0001,
|
||||
ThermalPowerManagementInformation = 0x0000_0006,
|
||||
StructuredExtendedInformation = 0x0000_0007,
|
||||
ExtendedFunctionInformation = 0x8000_0000,
|
||||
ExtendedProcessorSignature = 0x8000_0001,
|
||||
BrandString1 = 0x8000_0002,
|
||||
BrandString2 = 0x8000_0003,
|
||||
BrandString3 = 0x8000_0004,
|
||||
// reserved = 0x80000005,
|
||||
CacheLine = 0x8000_0006,
|
||||
TimeStampCounter = 0x8000_0007,
|
||||
PhysicalAddressSize = 0x8000_0008,
|
||||
}
|
||||
#[allow(clippy::similar_names)]
|
||||
pub fn cpuid(code: RequestType) -> (u32, u32, u32, u32) {
|
||||
let eax;
|
||||
let ebx;
|
||||
let ecx;
|
||||
let edx;
|
||||
|
||||
unsafe {
|
||||
asm!(
|
||||
"movq %rbx, {0:r}",
|
||||
"cpuid",
|
||||
"xchgq %rbx, {0:r}",
|
||||
lateout(reg) ebx,
|
||||
inlateout("eax") code as u32 => eax,
|
||||
inlateout("ecx") 0 => ecx,
|
||||
lateout("edx") edx,
|
||||
options(nostack, preserves_flags, att_syntax),
|
||||
);
|
||||
}
|
||||
|
||||
(eax, ebx, ecx, edx)
|
||||
}
|
||||
|
||||
/// The main entrypoint to the CPU information
|
||||
#[cfg(any(target_arch = "x86_64", target_arch = "x86"))]
|
||||
pub fn master() -> Option<Master> {
|
||||
Some(Master::new())
|
||||
}
|
||||
|
||||
// This matches the Intel Architecture guide, with bits 31 -> 0.
|
||||
// The bit positions are inclusive.
|
||||
fn bits_of(val: u32, start_bit: u8, end_bit: u8) -> u32 {
|
||||
let mut silly = 0;
|
||||
|
||||
for _ in start_bit..end_bit + 1 {
|
||||
silly <<= 1;
|
||||
silly |= 1;
|
||||
}
|
||||
|
||||
(val >> start_bit) & silly
|
||||
}
|
||||
|
||||
pub fn as_bytes(v: &u32) -> &[u8] {
|
||||
let start = v as *const u32 as *const u8;
|
||||
// TODO: use u32::BYTES
|
||||
unsafe { slice::from_raw_parts(start, 4) }
|
||||
}
|
||||
|
||||
macro_rules! bit {
|
||||
($reg:ident, {$($idx:expr => $name:ident),+}) => {
|
||||
$(pub fn $name(self) -> bool {
|
||||
((self.$reg >> $idx) & 1) != 0
|
||||
})+
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! dump {
|
||||
($me:expr, $f: expr, $sname:expr, {$($name:ident),+}) => {
|
||||
$f.debug_struct($sname)
|
||||
$(.field(stringify!($name), &$me.$name()))+
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! delegate_flag {
|
||||
($item:ident, {$($name:ident),+}) => {
|
||||
$(pub fn $name(&self) -> bool {
|
||||
self.$item.map(|i| i.$name()).unwrap_or(false)
|
||||
})+
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! master_attr_reader {
|
||||
($name:ident, $kind:ty) => {
|
||||
pub fn $name(&self) -> Option<&$kind> {
|
||||
self.$name.as_ref()
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct VersionInformation {
|
||||
eax: u32,
|
||||
ebx: u32,
|
||||
ecx: u32,
|
||||
edx: u32,
|
||||
}
|
||||
|
||||
impl VersionInformation {
|
||||
pub fn new() -> VersionInformation {
|
||||
let (a, b, c, d) = cpuid(RequestType::VersionInformation);
|
||||
VersionInformation {
|
||||
eax: a,
|
||||
ebx: b,
|
||||
ecx: c,
|
||||
edx: d,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn family_id(self) -> u32 {
|
||||
let family_id = bits_of(self.eax, 8, 11);
|
||||
let extended_family_id = bits_of(self.eax, 20, 27);
|
||||
|
||||
if family_id != 0x0F {
|
||||
family_id
|
||||
} else {
|
||||
extended_family_id + family_id
|
||||
}
|
||||
}
|
||||
|
||||
pub fn model_id(self) -> u32 {
|
||||
let family_id = self.family_id();
|
||||
let model_id = bits_of(self.eax, 4, 7);
|
||||
let extended_model_id = bits_of(self.eax, 16, 19);
|
||||
|
||||
if family_id == 0x06 || family_id == 0x0F {
|
||||
(extended_model_id << 4) + model_id
|
||||
} else {
|
||||
model_id
|
||||
}
|
||||
}
|
||||
|
||||
pub fn stepping(self) -> u32 {
|
||||
bits_of(self.eax, 0, 3)
|
||||
}
|
||||
|
||||
fn processor_signature(self) -> u32 {
|
||||
self.eax
|
||||
}
|
||||
// TODO: Change return type and move this to a file that has the list
|
||||
pub fn brand_string(self) -> Option<&'static str> {
|
||||
let brand_index = bits_of(self.ebx, 0, 7);
|
||||
let processor_signature = self.processor_signature();
|
||||
|
||||
match brand_index {
|
||||
0x00 => None,
|
||||
0x01 => Some("Intel(R) Celeron(R)"),
|
||||
0x02 => Some("Intel(R) Pentium(R) III"),
|
||||
0x03 => {
|
||||
if processor_signature == 0x06B1 {
|
||||
Some("Intel(R) Celeron(R)")
|
||||
} else {
|
||||
Some("Intel(R) Pentium(R) III Xeon(R)")
|
||||
}
|
||||
}
|
||||
0x04 => Some("Intel(R) Pentium(R) III"),
|
||||
0x06 => Some("Mobile Intel(R) Pentium(R) III-M"),
|
||||
0x07 => Some("Mobile Intel(R) Celeron(R)"),
|
||||
0x08 => Some("Intel(R) Pentium(R) 4"),
|
||||
0x09 => Some("Intel(R) Pentium(R) 4"),
|
||||
0x0A => Some("Intel(R) Celeron(R)"),
|
||||
0x0B => {
|
||||
if processor_signature == 0x0F13 {
|
||||
Some("Intel(R) Xeon(R) MP")
|
||||
} else {
|
||||
Some("Intel(R) Xeon(R)")
|
||||
}
|
||||
}
|
||||
0x0C => Some("Intel(R) Xeon(R) MP"),
|
||||
0x0E => {
|
||||
if processor_signature == 0x0F13 {
|
||||
Some("Intel(R) Xeon(R)")
|
||||
} else {
|
||||
Some("Mobile Intel(R) Pentium(R) 4-M")
|
||||
}
|
||||
}
|
||||
0x0F => Some("Mobile Intel(R) Celeron(R)"),
|
||||
0x11 => Some("Mobile Genuine Intel(R)"),
|
||||
0x12 => Some("Intel(R) Celeron(R) M"),
|
||||
0x13 => Some("Mobile Intel(R) Celeron(R)"),
|
||||
0x14 => Some("Intel(R) Celeron(R)"),
|
||||
0x15 => Some("Mobile Genuine Intel(R)"),
|
||||
0x16 => Some("Intel(R) Pentium(R) M"),
|
||||
0x17 => Some("Mobile Intel(R) Celeron(R)"),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
bit!(ecx, {
|
||||
0 => sse3,
|
||||
1 => pclmulqdq,
|
||||
2 => dtes64,
|
||||
3 => monitor,
|
||||
4 => ds_cpl,
|
||||
5 => vmx,
|
||||
6 => smx,
|
||||
7 => eist,
|
||||
8 => tm2,
|
||||
9 => ssse3,
|
||||
10 => cnxt_id,
|
||||
11 => sdbg,
|
||||
12 => fma,
|
||||
13 => cmpxchg16b,
|
||||
14 => xtpr_update_control,
|
||||
15 => pdcm,
|
||||
// 16 - reserved
|
||||
17 => pcid,
|
||||
18 => dca,
|
||||
19 => sse4_1,
|
||||
20 => sse4_2,
|
||||
21 => x2apic,
|
||||
22 => movbe,
|
||||
23 => popcnt,
|
||||
24 => tsc_deadline,
|
||||
25 => aesni,
|
||||
26 => xsave,
|
||||
27 => osxsave,
|
||||
28 => avx,
|
||||
29 => f16c,
|
||||
30 => rdrand
|
||||
// 31 - unused
|
||||
});
|
||||
|
||||
bit!(edx, {
|
||||
0 => fpu,
|
||||
1 => vme,
|
||||
2 => de,
|
||||
3 => pse,
|
||||
4 => tsc,
|
||||
5 => msr,
|
||||
6 => pae,
|
||||
7 => mce,
|
||||
8 => cx8,
|
||||
9 => apic,
|
||||
// 10 - reserved
|
||||
11 => sep,
|
||||
12 => mtrr,
|
||||
13 => pge,
|
||||
14 => mca,
|
||||
15 => cmov,
|
||||
16 => pat,
|
||||
17 => pse_36,
|
||||
18 => psn,
|
||||
19 => clfsh,
|
||||
// 20 - reserved
|
||||
21 => ds,
|
||||
22 => acpi,
|
||||
23 => mmx,
|
||||
24 => fxsr,
|
||||
25 => sse,
|
||||
26 => sse2,
|
||||
27 => ss,
|
||||
28 => htt,
|
||||
29 => tm,
|
||||
// 30 -reserved
|
||||
31 => pbe
|
||||
});
|
||||
}
|
||||
|
||||
impl fmt::Debug for VersionInformation {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
dump!(self, f, "VersionInformation", {
|
||||
family_id,
|
||||
model_id,
|
||||
stepping,
|
||||
brand_string,
|
||||
sse3,
|
||||
pclmulqdq,
|
||||
dtes64,
|
||||
monitor,
|
||||
ds_cpl,
|
||||
vmx,
|
||||
smx,
|
||||
eist,
|
||||
tm2,
|
||||
ssse3,
|
||||
cnxt_id,
|
||||
sdbg,
|
||||
fma,
|
||||
cmpxchg16b,
|
||||
xtpr_update_control,
|
||||
pdcm,
|
||||
pcid,
|
||||
dca,
|
||||
sse4_1,
|
||||
sse4_2,
|
||||
x2apic,
|
||||
movbe,
|
||||
popcnt,
|
||||
tsc_deadline,
|
||||
aesni,
|
||||
xsave,
|
||||
osxsave,
|
||||
avx,
|
||||
f16c,
|
||||
rdrand,
|
||||
fpu,
|
||||
vme,
|
||||
de,
|
||||
pse,
|
||||
tsc,
|
||||
msr,
|
||||
pae,
|
||||
mce,
|
||||
cx8,
|
||||
apic,
|
||||
sep,
|
||||
mtrr,
|
||||
pge,
|
||||
mca,
|
||||
cmov,
|
||||
pat,
|
||||
pse_36,
|
||||
psn,
|
||||
clfsh,
|
||||
ds,
|
||||
acpi,
|
||||
mmx,
|
||||
fxsr,
|
||||
sse,
|
||||
sse2,
|
||||
ss,
|
||||
htt,
|
||||
tm,
|
||||
pbe
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct ExtendedProcessorSignature {
|
||||
ecx: u32,
|
||||
edx: u32,
|
||||
}
|
||||
|
||||
impl ExtendedProcessorSignature {
|
||||
fn new() -> ExtendedProcessorSignature {
|
||||
let (_, _, c, d) = cpuid(RequestType::ExtendedProcessorSignature);
|
||||
ExtendedProcessorSignature { ecx: c, edx: d }
|
||||
}
|
||||
|
||||
bit!(ecx, {
|
||||
0 => lahf_sahf_in_64_bit,
|
||||
// 1-4 reserved
|
||||
5 => lzcnt,
|
||||
// 6-7 reserved
|
||||
8 => prefetchw
|
||||
// 9-31 reserved
|
||||
});
|
||||
|
||||
bit!(edx, {
|
||||
// 0-10 reserved
|
||||
11 => syscall_sysret_in_64_bit,
|
||||
// 12-19 reserved
|
||||
20 => execute_disable,
|
||||
// 21-25 reserved
|
||||
26 => gigabyte_pages,
|
||||
27 => rdtscp_and_ia32_tsc_aux,
|
||||
// 28 reserved
|
||||
29 => intel_64_bit_architecture
|
||||
// 30-31 reserved
|
||||
});
|
||||
}
|
||||
|
||||
impl fmt::Debug for ExtendedProcessorSignature {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
dump!(self, f, "ThermalPowerManagementInformation", {
|
||||
lahf_sahf_in_64_bit,
|
||||
lzcnt,
|
||||
prefetchw,
|
||||
syscall_sysret_in_64_bit,
|
||||
execute_disable,
|
||||
gigabyte_pages,
|
||||
rdtscp_and_ia32_tsc_aux,
|
||||
intel_64_bit_architecture
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 3 calls of 4 registers of 4 bytes
|
||||
const BRAND_STRING_LENGTH: usize = 3 * 4 * 4;
|
||||
|
||||
pub struct BrandString {
|
||||
bytes: [u8; BRAND_STRING_LENGTH],
|
||||
}
|
||||
|
||||
impl BrandString {
|
||||
fn new() -> BrandString {
|
||||
fn append_bytes(a: RequestType, bytes: &mut [u8]) {
|
||||
let (a, b, c, d) = cpuid(a);
|
||||
|
||||
let result_bytes = as_bytes(&a)
|
||||
.iter()
|
||||
.chain(as_bytes(&b).iter())
|
||||
.chain(as_bytes(&c).iter())
|
||||
.chain(as_bytes(&d).iter());
|
||||
|
||||
for (output, input) in bytes.iter_mut().zip(result_bytes) {
|
||||
*output = *input
|
||||
}
|
||||
}
|
||||
|
||||
let mut brand_string = BrandString {
|
||||
bytes: [0; BRAND_STRING_LENGTH],
|
||||
};
|
||||
append_bytes(RequestType::BrandString1, &mut brand_string.bytes[0..]);
|
||||
append_bytes(RequestType::BrandString2, &mut brand_string.bytes[16..]);
|
||||
append_bytes(RequestType::BrandString3, &mut brand_string.bytes[32..]);
|
||||
brand_string
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for BrandString {
|
||||
fn clone(&self) -> Self {
|
||||
let mut bytes = [0; BRAND_STRING_LENGTH];
|
||||
for (d, s) in bytes.iter_mut().zip(self.bytes.iter()) {
|
||||
*d = *s;
|
||||
}
|
||||
BrandString { bytes }
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for BrandString {
|
||||
type Target = str;
|
||||
|
||||
fn deref(&self) -> &str {
|
||||
let nul_terminator = self.bytes.iter().position(|&b| b == 0).unwrap_or(0);
|
||||
let usable_bytes = &self.bytes[..nul_terminator];
|
||||
unsafe { str::from_utf8_unchecked(usable_bytes) }.trim()
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for BrandString {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
(self as &str).fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for BrandString {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
(self as &str).fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct ThermalPowerManagementInformation {
|
||||
eax: u32,
|
||||
ebx: u32,
|
||||
ecx: u32,
|
||||
}
|
||||
|
||||
impl ThermalPowerManagementInformation {
|
||||
fn new() -> ThermalPowerManagementInformation {
|
||||
let (a, b, c, _) = cpuid(RequestType::ThermalPowerManagementInformation);
|
||||
ThermalPowerManagementInformation {
|
||||
eax: a,
|
||||
ebx: b,
|
||||
ecx: c,
|
||||
}
|
||||
}
|
||||
|
||||
bit!(eax, {
|
||||
0 => digital_temperature_sensor,
|
||||
1 => intel_turbo_boost,
|
||||
2 => arat,
|
||||
// 3 - reserved
|
||||
4 => pln,
|
||||
5 => ecmd,
|
||||
6 => ptm,
|
||||
7 => hwp,
|
||||
8 => hwp_notification,
|
||||
9 => hwp_activity_window,
|
||||
10 => hwp_energy_performance_preference,
|
||||
// 12 - reserved
|
||||
13 => hdc
|
||||
});
|
||||
|
||||
pub fn number_of_interrupt_thresholds(self) -> u32 {
|
||||
bits_of(self.ebx, 0, 3)
|
||||
}
|
||||
|
||||
bit!(ecx, {
|
||||
0 => hardware_coordination_feedback,
|
||||
// 1-2 - reserved
|
||||
3 => performance_energy_bias
|
||||
});
|
||||
}
|
||||
|
||||
impl fmt::Debug for ThermalPowerManagementInformation {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
dump!(self, f, "ThermalPowerManagementInformation", {
|
||||
digital_temperature_sensor,
|
||||
intel_turbo_boost,
|
||||
arat,
|
||||
pln,
|
||||
ecmd,
|
||||
ptm,
|
||||
hwp,
|
||||
hwp_notification,
|
||||
hwp_activity_window,
|
||||
hwp_energy_performance_preference,
|
||||
hdc,
|
||||
|
||||
number_of_interrupt_thresholds,
|
||||
|
||||
hardware_coordination_feedback,
|
||||
performance_energy_bias
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct StructuredExtendedInformation {
|
||||
ebx: u32,
|
||||
ecx: u32,
|
||||
}
|
||||
|
||||
impl StructuredExtendedInformation {
|
||||
fn new() -> StructuredExtendedInformation {
|
||||
let (_, b, c, _) = cpuid(RequestType::StructuredExtendedInformation);
|
||||
StructuredExtendedInformation { ebx: b, ecx: c }
|
||||
}
|
||||
|
||||
bit!(ebx, {
|
||||
0 => fsgsbase,
|
||||
1 => ia32_tsc_adjust_msr,
|
||||
// 2 - reserved
|
||||
3 => bmi1,
|
||||
4 => hle,
|
||||
5 => avx2,
|
||||
// 6 - reserved
|
||||
7 => smep,
|
||||
8 => bmi2,
|
||||
9 => enhanced_rep_movsb_stosb,
|
||||
10 => invpcid,
|
||||
11 => rtm,
|
||||
12 => pqm,
|
||||
13 => deprecates_fpu_cs_ds,
|
||||
// 14 - reserved
|
||||
15 => pqe,
|
||||
// 16-17 - reserved
|
||||
18 => rdseed,
|
||||
19 => adx,
|
||||
20 => smap,
|
||||
// 21-24 - reserved
|
||||
25 => intel_processor_trace
|
||||
// 26-31 - reserved
|
||||
});
|
||||
|
||||
bit!(ecx, {
|
||||
0 => prefetchwt1
|
||||
});
|
||||
}
|
||||
|
||||
impl fmt::Debug for StructuredExtendedInformation {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
dump!(self, f, "StructuredExtendedInformation", {
|
||||
fsgsbase,
|
||||
ia32_tsc_adjust_msr,
|
||||
bmi1,
|
||||
hle,
|
||||
avx2,
|
||||
smep,
|
||||
bmi2,
|
||||
enhanced_rep_movsb_stosb,
|
||||
invpcid,
|
||||
rtm,
|
||||
pqm,
|
||||
deprecates_fpu_cs_ds,
|
||||
pqe,
|
||||
rdseed,
|
||||
adx,
|
||||
smap,
|
||||
intel_processor_trace,
|
||||
prefetchwt1
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub enum CacheLineAssociativity {
|
||||
Disabled,
|
||||
DirectMapped,
|
||||
TwoWay,
|
||||
FourWay,
|
||||
EightWay,
|
||||
SixteenWay,
|
||||
Full,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct CacheLine(u32);
|
||||
|
||||
impl CacheLine {
|
||||
fn new() -> CacheLine {
|
||||
let (_, _, c, _) = cpuid(RequestType::CacheLine);
|
||||
CacheLine(c)
|
||||
}
|
||||
|
||||
pub fn cache_line_size(self) -> u32 {
|
||||
bits_of(self.0, 0, 7)
|
||||
}
|
||||
|
||||
pub fn l2_associativity(self) -> Option<CacheLineAssociativity> {
|
||||
match bits_of(self.0, 12, 15) {
|
||||
0x00 => Some(CacheLineAssociativity::Disabled),
|
||||
0x01 => Some(CacheLineAssociativity::DirectMapped),
|
||||
0x02 => Some(CacheLineAssociativity::TwoWay),
|
||||
0x04 => Some(CacheLineAssociativity::FourWay),
|
||||
0x06 => Some(CacheLineAssociativity::EightWay),
|
||||
0x08 => Some(CacheLineAssociativity::SixteenWay),
|
||||
0x0F => Some(CacheLineAssociativity::Full),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn cache_size(self) -> u32 {
|
||||
bits_of(self.0, 16, 31)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for CacheLine {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
dump!(self, f, "CacheLine", {
|
||||
cache_line_size,
|
||||
l2_associativity,
|
||||
cache_size
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct TimeStampCounter {
|
||||
edx: u32,
|
||||
}
|
||||
|
||||
impl TimeStampCounter {
|
||||
fn new() -> TimeStampCounter {
|
||||
let (_, _, _, d) = cpuid(RequestType::TimeStampCounter);
|
||||
TimeStampCounter { edx: d }
|
||||
}
|
||||
|
||||
bit!(edx, {
|
||||
// 0-7 - reserved
|
||||
8 => invariant_tsc
|
||||
// 9-31 - reserved
|
||||
});
|
||||
}
|
||||
|
||||
impl fmt::Debug for TimeStampCounter {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
dump!(self, f, "TimeStampCounter", { invariant_tsc })
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct PhysicalAddressSize(u32);
|
||||
|
||||
impl PhysicalAddressSize {
|
||||
fn new() -> PhysicalAddressSize {
|
||||
let (a, _, _, _) = cpuid(RequestType::PhysicalAddressSize);
|
||||
PhysicalAddressSize(a)
|
||||
}
|
||||
|
||||
pub fn physical_address_bits(self) -> u32 {
|
||||
bits_of(self.0, 0, 7)
|
||||
}
|
||||
|
||||
pub fn linear_address_bits(self) -> u32 {
|
||||
bits_of(self.0, 8, 15)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for PhysicalAddressSize {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
dump!(self, f, "PhysicalAddressSize", {
|
||||
physical_address_bits,
|
||||
linear_address_bits
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Information about the currently running processor
|
||||
///
|
||||
/// Feature flags match the feature mnemonic listed in the Intel
|
||||
/// Instruction Set Reference. This struct provides a facade for flags
|
||||
/// so the consumer doesn't need to worry about which particular CPUID
|
||||
/// leaf provides the information.
|
||||
///
|
||||
/// For data beyond simple feature flags, you will need to retrieve
|
||||
/// the nested struct and call the appropriate methods on it.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Master {
|
||||
// TODO: Rename struct
|
||||
version_information: Option<VersionInformation>,
|
||||
thermal_power_management_information: Option<ThermalPowerManagementInformation>,
|
||||
structured_extended_information: Option<StructuredExtendedInformation>,
|
||||
extended_processor_signature: Option<ExtendedProcessorSignature>,
|
||||
brand_string: Option<BrandString>,
|
||||
cache_line: Option<CacheLine>,
|
||||
time_stamp_counter: Option<TimeStampCounter>,
|
||||
physical_address_size: Option<PhysicalAddressSize>,
|
||||
}
|
||||
|
||||
impl Master {
|
||||
pub fn new() -> Master {
|
||||
fn when_supported<F, T>(max: u32, kind: RequestType, then: F) -> Option<T>
|
||||
where
|
||||
F: FnOnce() -> T,
|
||||
{
|
||||
if max >= kind as u32 {
|
||||
Some(then())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
let (max_value, _, _, _) = cpuid(RequestType::BasicInformation);
|
||||
|
||||
let vi = when_supported(max_value, RequestType::VersionInformation, || {
|
||||
VersionInformation::new()
|
||||
});
|
||||
let tpm = when_supported(
|
||||
max_value,
|
||||
RequestType::ThermalPowerManagementInformation,
|
||||
|| ThermalPowerManagementInformation::new(),
|
||||
);
|
||||
let sei = when_supported(
|
||||
max_value,
|
||||
RequestType::StructuredExtendedInformation,
|
||||
|| StructuredExtendedInformation::new(),
|
||||
);
|
||||
|
||||
// Extended information
|
||||
|
||||
let (max_value, _, _, _) = cpuid(RequestType::ExtendedFunctionInformation);
|
||||
|
||||
let eps = when_supported(max_value, RequestType::ExtendedProcessorSignature, || {
|
||||
ExtendedProcessorSignature::new()
|
||||
});
|
||||
let brand_string =
|
||||
when_supported(max_value, RequestType::BrandString3, || BrandString::new());
|
||||
let cache_line = when_supported(max_value, RequestType::CacheLine, || CacheLine::new());
|
||||
let tsc = when_supported(max_value, RequestType::TimeStampCounter, || {
|
||||
TimeStampCounter::new()
|
||||
});
|
||||
let pas = when_supported(max_value, RequestType::PhysicalAddressSize, || {
|
||||
PhysicalAddressSize::new()
|
||||
});
|
||||
|
||||
Master {
|
||||
version_information: vi,
|
||||
thermal_power_management_information: tpm,
|
||||
structured_extended_information: sei,
|
||||
extended_processor_signature: eps,
|
||||
brand_string,
|
||||
cache_line,
|
||||
time_stamp_counter: tsc,
|
||||
physical_address_size: pas,
|
||||
}
|
||||
}
|
||||
// TODO: Macroify this and also include all of the cpu features from self
|
||||
pub fn features(&self) -> Vec<(&str, bool)> {
|
||||
let mut fv = Vec::new();
|
||||
cpu_features!(self, fv);
|
||||
return fv;
|
||||
}
|
||||
|
||||
master_attr_reader!(version_information, VersionInformation);
|
||||
master_attr_reader!(
|
||||
thermal_power_management_information,
|
||||
ThermalPowerManagementInformation
|
||||
);
|
||||
master_attr_reader!(
|
||||
structured_extended_information,
|
||||
StructuredExtendedInformation
|
||||
);
|
||||
master_attr_reader!(extended_processor_signature, ExtendedProcessorSignature);
|
||||
master_attr_reader!(cache_line, CacheLine);
|
||||
master_attr_reader!(time_stamp_counter, TimeStampCounter);
|
||||
master_attr_reader!(physical_address_size, PhysicalAddressSize);
|
||||
|
||||
pub fn brand_string(&self) -> Option<&str> {
|
||||
self.brand_string
|
||||
.as_ref()
|
||||
.map(|bs| bs as &str)
|
||||
.or(self.version_information.and_then(|vi| vi.brand_string()))
|
||||
}
|
||||
|
||||
delegate_flag!(version_information, {
|
||||
sse3,
|
||||
pclmulqdq,
|
||||
dtes64,
|
||||
monitor,
|
||||
ds_cpl,
|
||||
vmx,
|
||||
smx,
|
||||
eist,
|
||||
tm2,
|
||||
ssse3,
|
||||
cnxt_id,
|
||||
sdbg,
|
||||
fma,
|
||||
cmpxchg16b,
|
||||
xtpr_update_control,
|
||||
pdcm,
|
||||
pcid,
|
||||
dca,
|
||||
sse4_1,
|
||||
sse4_2,
|
||||
x2apic,
|
||||
movbe,
|
||||
popcnt,
|
||||
tsc_deadline,
|
||||
aesni,
|
||||
xsave,
|
||||
osxsave,
|
||||
avx,
|
||||
f16c,
|
||||
rdrand,
|
||||
fpu,
|
||||
vme,
|
||||
de,
|
||||
pse,
|
||||
tsc,
|
||||
msr,
|
||||
pae,
|
||||
mce,
|
||||
cx8,
|
||||
apic,
|
||||
sep,
|
||||
mtrr,
|
||||
pge,
|
||||
mca,
|
||||
cmov,
|
||||
pat,
|
||||
pse_36,
|
||||
psn,
|
||||
clfsh,
|
||||
ds,
|
||||
acpi,
|
||||
mmx,
|
||||
fxsr,
|
||||
sse,
|
||||
sse2,
|
||||
ss,
|
||||
htt,
|
||||
tm,
|
||||
pbe
|
||||
});
|
||||
|
||||
delegate_flag!(thermal_power_management_information, {
|
||||
digital_temperature_sensor,
|
||||
intel_turbo_boost,
|
||||
arat,
|
||||
pln,
|
||||
ecmd,
|
||||
ptm,
|
||||
hwp,
|
||||
hwp_notification,
|
||||
hwp_activity_window,
|
||||
hwp_energy_performance_preference,
|
||||
hdc,
|
||||
hardware_coordination_feedback,
|
||||
performance_energy_bias
|
||||
});
|
||||
|
||||
delegate_flag!(structured_extended_information, {
|
||||
fsgsbase,
|
||||
ia32_tsc_adjust_msr,
|
||||
bmi1,
|
||||
hle,
|
||||
avx2,
|
||||
smep,
|
||||
bmi2,
|
||||
enhanced_rep_movsb_stosb,
|
||||
invpcid,
|
||||
rtm,
|
||||
pqm,
|
||||
deprecates_fpu_cs_ds,
|
||||
pqe,
|
||||
rdseed,
|
||||
adx,
|
||||
smap,
|
||||
intel_processor_trace,
|
||||
prefetchwt1
|
||||
});
|
||||
|
||||
delegate_flag!(extended_processor_signature, {
|
||||
lahf_sahf_in_64_bit,
|
||||
lzcnt,
|
||||
prefetchw,
|
||||
syscall_sysret_in_64_bit,
|
||||
execute_disable,
|
||||
gigabyte_pages,
|
||||
rdtscp_and_ia32_tsc_aux,
|
||||
intel_64_bit_architecture
|
||||
});
|
||||
|
||||
delegate_flag!(time_stamp_counter, { invariant_tsc });
|
||||
}
|
||||
/*
|
||||
cfg_if! {
|
||||
if #[cfg(any(target_arch = "x86_64", target_arch = "x86"))] {
|
||||
|
||||
#[test]
|
||||
fn basic_genuine_intel() {
|
||||
let (_, b, c, d) = cpuid(RequestType::BasicInformation);
|
||||
|
||||
assert_eq!(b"Genu", as_bytes(&b));
|
||||
assert_eq!(b"ntel", as_bytes(&c));
|
||||
assert_eq!(b"ineI", as_bytes(&d));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn brand_string_contains_intel() {
|
||||
assert!(master().unwrap().brand_string().unwrap().contains("Intel(R)"))
|
||||
}
|
||||
|
||||
} else {}
|
||||
}
|
||||
*/
|
|
@ -1,68 +0,0 @@
|
|||
use {
|
||||
crate::{
|
||||
arch::{pci, x86_64::cpuid},
|
||||
device_tree::DeviceTree,
|
||||
kmain::DEVICE_TREE,
|
||||
},
|
||||
limine::SmpRequest,
|
||||
xml::XMLElement,
|
||||
};
|
||||
|
||||
fn collect_cpu_info(device_tree: &mut DeviceTree) {
|
||||
use crate::alloc::string::ToString;
|
||||
|
||||
static SMP: SmpRequest = SmpRequest::new(0);
|
||||
let smp_response = SMP.get_response().get().unwrap();
|
||||
|
||||
let mut cpu = XMLElement::new("cpu");
|
||||
|
||||
// Get the amount of cores on the CPU
|
||||
let core_count = smp_response.cpu_count.to_string();
|
||||
cpu.set_attribute("core count", core_count);
|
||||
for x in 0..smp_response.cpu_count {
|
||||
let core_name = alloc::format!("core_{}", x);
|
||||
let core = XMLElement::new(core_name);
|
||||
cpu.set_child(core);
|
||||
}
|
||||
|
||||
let cpu_info = cpuid::master().unwrap();
|
||||
|
||||
let brand_string = cpu_info.brand_string().unwrap_or("Unknown").to_string();
|
||||
cpu.set_attribute("brand string", brand_string);
|
||||
|
||||
cpu.set_attribute("speed", "unknown");
|
||||
|
||||
// Get CPU features and add them to the device tree entry.
|
||||
let mut cpu_features = XMLElement::new("CPU Features");
|
||||
for (feature_key, feature_enabled) in cpu_info.features() {
|
||||
cpu_features.set_attribute(feature_key, feature_enabled.to_string());
|
||||
}
|
||||
cpu.set_child(cpu_features);
|
||||
|
||||
// CPU temperature
|
||||
if cpu_info.digital_temperature_sensor() {
|
||||
let mut temperature_child = XMLElement::new("Temperature");
|
||||
|
||||
temperature_child.set_attribute("degrees", "Unknown");
|
||||
cpu.set_child(temperature_child);
|
||||
}
|
||||
|
||||
// Add CPU to device tree
|
||||
let cpus = device_tree.devices.get_mut("CPUs").unwrap();
|
||||
cpus.push(cpu);
|
||||
}
|
||||
|
||||
pub fn collect_device_info() {
|
||||
log::trace!("Collecting devices on x86_64");
|
||||
// Lock device tree
|
||||
unsafe {
|
||||
DEVICE_TREE.force_unlock();
|
||||
}
|
||||
let device_tree = &mut DEVICE_TREE.lock();
|
||||
|
||||
// Generate device tree from PCI enumeration.
|
||||
pci::init(device_tree);
|
||||
|
||||
// Collect CPU info and add it to the device tree
|
||||
collect_cpu_info(device_tree);
|
||||
}
|
|
@ -1,26 +1,19 @@
|
|||
use {
|
||||
spin::Lazy,
|
||||
x86_64::{
|
||||
use spin::Lazy;
|
||||
use x86_64::{
|
||||
structures::{
|
||||
gdt::{Descriptor, GlobalDescriptorTable, SegmentSelector},
|
||||
tss::TaskStateSegment,
|
||||
},
|
||||
VirtAddr,
|
||||
},
|
||||
};
|
||||
|
||||
pub const DOUBLE_FAULT_IX: u16 = 0;
|
||||
|
||||
const STACK_SIZE: usize = 5 * 1024;
|
||||
const STACK_ALIGNMENT: usize = 1;
|
||||
|
||||
pub unsafe fn init() {
|
||||
use x86_64::instructions::{
|
||||
segmentation::{Segment, CS, SS},
|
||||
tables::load_tss,
|
||||
};
|
||||
use x86_64::instructions::segmentation::{Segment, CS, SS};
|
||||
use x86_64::instructions::tables::load_tss;
|
||||
|
||||
log::trace!("Initialising GDT");
|
||||
log::info!("Initialising GDT");
|
||||
GDT.0.load();
|
||||
CS::set_reg(GDT.1.kcode);
|
||||
SS::set_reg(GDT.1.kdata);
|
||||
|
@ -35,24 +28,24 @@ struct Selectors {
|
|||
|
||||
static TSS: Lazy<TaskStateSegment> = Lazy::new(|| {
|
||||
let mut tss = TaskStateSegment::new();
|
||||
|
||||
let stack_ptr = unsafe {
|
||||
let layout = alloc::alloc::Layout::from_size_align(STACK_SIZE, STACK_ALIGNMENT)
|
||||
.expect("Failed to create stack layout");
|
||||
let stack = alloc::alloc::alloc(layout);
|
||||
VirtAddr::from_ptr(stack) + STACK_SIZE as u64
|
||||
tss.interrupt_stack_table[usize::from(DOUBLE_FAULT_IX)] = {
|
||||
const SIZE: usize = 5 * 1024;
|
||||
let stack = unsafe {
|
||||
alloc::alloc::alloc_zeroed(
|
||||
alloc::alloc::Layout::from_size_align(SIZE, 1).expect("stack pointer"),
|
||||
)
|
||||
};
|
||||
VirtAddr::from_ptr(stack) + SIZE
|
||||
};
|
||||
|
||||
tss.interrupt_stack_table[usize::from(DOUBLE_FAULT_IX)] = stack_ptr;
|
||||
tss
|
||||
});
|
||||
|
||||
static GDT: Lazy<(GlobalDescriptorTable, Selectors)> = Lazy::new(|| {
|
||||
let mut gdt = GlobalDescriptorTable::new();
|
||||
let sels = Selectors {
|
||||
kcode: gdt.append(Descriptor::kernel_code_segment()),
|
||||
kdata: gdt.append(Descriptor::kernel_data_segment()),
|
||||
tss: gdt.append(Descriptor::tss_segment(&TSS)),
|
||||
kcode: gdt.add_entry(Descriptor::kernel_code_segment()),
|
||||
kdata: gdt.add_entry(Descriptor::kernel_data_segment()),
|
||||
tss: gdt.add_entry(Descriptor::tss_segment(&TSS)),
|
||||
};
|
||||
(gdt, sels)
|
||||
});
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
|
|
@ -1,54 +1,53 @@
|
|||
use {
|
||||
core::mem::MaybeUninit,
|
||||
log::trace,
|
||||
x2apic::lapic::{LocalApic, LocalApicBuilder},
|
||||
x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame, PageFaultErrorCode},
|
||||
};
|
||||
use spin::{Lazy, Mutex};
|
||||
use x2apic::lapic::{LocalApic, LocalApicBuilder};
|
||||
use x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame, PageFaultErrorCode};
|
||||
|
||||
/// Safety: Using LAPIC or IDT before init() is UB
|
||||
/// Using
|
||||
static mut LAPIC: LocalApic = unsafe { MaybeUninit::zeroed().assume_init() };
|
||||
static mut IDT: InterruptDescriptorTable = unsafe { MaybeUninit::zeroed().assume_init() };
|
||||
use crate::interp::wasm;
|
||||
|
||||
pub unsafe fn init() {
|
||||
log::info!("Initialising IDT");
|
||||
IDT.load();
|
||||
Lazy::force(&LAPIC);
|
||||
x86_64::instructions::interrupts::enable();
|
||||
}
|
||||
|
||||
#[repr(u8)]
|
||||
#[derive(Debug, Eq, Hash, PartialEq)]
|
||||
|
||||
pub enum Interrupt {
|
||||
enum Interrupt {
|
||||
Timer = 32,
|
||||
ApicErr = u8::MAX - 1,
|
||||
Spurious = u8::MAX,
|
||||
}
|
||||
|
||||
pub unsafe fn init() {
|
||||
trace!("Initializing IDT and LAPIC");
|
||||
|
||||
// Initialize and load the IDT
|
||||
IDT = InterruptDescriptorTable::new();
|
||||
IDT.double_fault
|
||||
.set_handler_fn(double_fault)
|
||||
.set_stack_index(super::gdt::DOUBLE_FAULT_IX);
|
||||
IDT.page_fault.set_handler_fn(page_fault);
|
||||
|
||||
IDT[Interrupt::ApicErr as u8].set_handler_fn(apic_err);
|
||||
IDT[Interrupt::Spurious as u8].set_handler_fn(spurious);
|
||||
IDT[Interrupt::Timer as u8].set_handler_fn(timer);
|
||||
|
||||
IDT.load();
|
||||
|
||||
LAPIC = LocalApicBuilder::new()
|
||||
pub(crate) static LAPIC: Lazy<Mutex<LocalApic>> = Lazy::new(|| {
|
||||
let mut lapic = LocalApicBuilder::new()
|
||||
.timer_vector(Interrupt::Timer as usize)
|
||||
.error_vector(Interrupt::ApicErr as usize)
|
||||
.spurious_vector(Interrupt::Spurious as usize)
|
||||
.set_xapic_base(
|
||||
x2apic::lapic::xapic_base()
|
||||
unsafe { x2apic::lapic::xapic_base() }
|
||||
+ super::memory::HHDM_OFFSET.load(core::sync::atomic::Ordering::Relaxed),
|
||||
)
|
||||
.build()
|
||||
.expect("Failed to setup Local APIC");
|
||||
LAPIC.enable();
|
||||
.expect("failed to setup Local APIC");
|
||||
unsafe { lapic.enable() };
|
||||
Mutex::new(lapic)
|
||||
});
|
||||
|
||||
x86_64::instructions::interrupts::enable();
|
||||
}
|
||||
static IDT: Lazy<InterruptDescriptorTable> = Lazy::new(|| {
|
||||
let mut idt = InterruptDescriptorTable::new();
|
||||
unsafe {
|
||||
idt.double_fault
|
||||
.set_handler_fn(double_fault)
|
||||
.set_stack_index(super::gdt::DOUBLE_FAULT_IX);
|
||||
}
|
||||
idt.page_fault.set_handler_fn(page_fault);
|
||||
|
||||
idt[Interrupt::ApicErr as usize].set_handler_fn(apic_err);
|
||||
idt[Interrupt::Spurious as usize].set_handler_fn(spurious);
|
||||
|
||||
idt[Interrupt::Timer as usize].set_handler_fn(timer);
|
||||
idt
|
||||
});
|
||||
|
||||
extern "x86-interrupt" fn double_fault(stack_frame: InterruptStackFrame, error_code: u64) -> ! {
|
||||
panic!("Double fault: error code {error_code} \n{stack_frame:#?}")
|
||||
|
@ -61,53 +60,14 @@ extern "x86-interrupt" fn page_fault(
|
|||
panic!("Page fault ({error_code:?}): {stack_frame:?}")
|
||||
}
|
||||
|
||||
extern "x86-interrupt" fn timer(_isf: InterruptStackFrame) {
|
||||
interrupt(Interrupt::Timer);
|
||||
|
||||
unsafe {
|
||||
LAPIC.end_of_interrupt();
|
||||
}
|
||||
extern "x86-interrupt" fn timer(isf: InterruptStackFrame) {
|
||||
unsafe { LAPIC.lock().end_of_interrupt() };
|
||||
}
|
||||
|
||||
extern "x86-interrupt" fn apic_err(_: InterruptStackFrame) {
|
||||
interrupt(Interrupt::ApicErr);
|
||||
|
||||
panic!("Internal APIC error");
|
||||
}
|
||||
|
||||
extern "x86-interrupt" fn spurious(_: InterruptStackFrame) {
|
||||
interrupt(Interrupt::Spurious);
|
||||
|
||||
unsafe {
|
||||
LAPIC.end_of_interrupt();
|
||||
}
|
||||
}
|
||||
|
||||
#[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);
|
||||
}
|
||||
unsafe { LAPIC.lock().end_of_interrupt() };
|
||||
}
|
||||
|
|
|
@ -1,17 +1,46 @@
|
|||
//! Logging (as in terms of console / serial output)
|
||||
#![allow(deprecated)]
|
||||
use {core::fmt::Write, spin::Mutex, uart_16550::SerialPort};
|
||||
|
||||
pub static SERIAL_CONSOLE: Mutex<SerialPort> = Mutex::new(unsafe { SerialPort::new(0x3F8) });
|
||||
use core::fmt::Write;
|
||||
use limine::{TerminalRequest, TerminalResponse};
|
||||
use spin::{Lazy, Mutex};
|
||||
use uart_16550::SerialPort;
|
||||
|
||||
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() {
|
||||
SERIAL_CONSOLE.lock().init();
|
||||
// Lazy::force(&TERMINAL_LOGGER);
|
||||
Lazy::force(&TERMINAL_LOGGER);
|
||||
}
|
||||
|
||||
pub fn log(args: core::fmt::Arguments<'_>) -> core::fmt::Result {
|
||||
x86_64::instructions::interrupts::without_interrupts(|| {
|
||||
// TERMINAL_LOGGER.lock().write_fmt(args)?;
|
||||
TERMINAL_LOGGER.lock().write_fmt(args)?;
|
||||
SERIAL_CONSOLE.lock().write_fmt(args)
|
||||
})
|
||||
}
|
||||
|
||||
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,10 +1,8 @@
|
|||
use {
|
||||
crate::memory::{MemoryManager, MAX_ORDER},
|
||||
core::sync::atomic::AtomicU64,
|
||||
limine::{MemmapEntry, MemoryMapEntryType, NonNullPtr},
|
||||
spin::{Mutex, Once},
|
||||
x86_64::{structures::paging::OffsetPageTable, VirtAddr},
|
||||
};
|
||||
use crate::memory::{MemoryManager, MAX_ORDER};
|
||||
use core::sync::atomic::AtomicU64;
|
||||
use limine::{MemmapEntry, MemoryMapEntryType, NonNullPtr};
|
||||
use spin::{Mutex, Once};
|
||||
use x86_64::{structures::paging::OffsetPageTable, VirtAddr};
|
||||
|
||||
pub const PAGE_SIZE: usize = 4096;
|
||||
|
||||
|
@ -14,7 +12,7 @@ static PAGE_TABLE: Once<Mutex<OffsetPageTable>> = Once::new();
|
|||
|
||||
/// Initialise page table
|
||||
pub unsafe fn init_pt(phys_base: VirtAddr) {
|
||||
log::debug!("Retrieving page table");
|
||||
log::info!("Retrieving page table");
|
||||
HHDM_OFFSET.store(phys_base.as_u64(), core::sync::atomic::Ordering::Relaxed);
|
||||
PAGE_TABLE.call_once(|| {
|
||||
Mutex::new(OffsetPageTable::new(
|
||||
|
|
|
@ -1,24 +1,15 @@
|
|||
use core::arch::x86_64::{_rdrand64_step, _rdseed64_step};
|
||||
|
||||
use {crate::bootmodules::BootModule, core::arch::asm, log::warn};
|
||||
pub mod memory;
|
||||
|
||||
mod cpuid;
|
||||
mod device_info_collector;
|
||||
mod gdt;
|
||||
pub mod graphics;
|
||||
pub(crate) mod interrupts;
|
||||
pub mod logging;
|
||||
pub mod pci;
|
||||
// pub mod virtio;
|
||||
mod logging;
|
||||
|
||||
pub use {logging::log, memory::PAGE_SIZE};
|
||||
pub use logging::log;
|
||||
pub use memory::PAGE_SIZE;
|
||||
|
||||
use {
|
||||
crate::allocator,
|
||||
limine::{HhdmRequest, KernelFileRequest, MemmapRequest, ModuleRequest},
|
||||
x86_64::VirtAddr,
|
||||
};
|
||||
use crate::allocator;
|
||||
use limine::{HhdmRequest, KernelFileRequest, MemmapRequest, ModuleRequest};
|
||||
use x86_64::VirtAddr;
|
||||
|
||||
extern "C" {
|
||||
fn _initial_kernel_heap_start();
|
||||
|
@ -29,87 +20,10 @@ const INITIAL_KERNEL_HEAP_START: *mut u8 = _initial_kernel_heap_start as _;
|
|||
const INITIAL_KERNEL_HEAP_SIZE: *const () = _initial_kernel_heap_size as _;
|
||||
|
||||
#[no_mangle]
|
||||
#[naked]
|
||||
#[cfg(not(target_feature = "avx2"))]
|
||||
unsafe extern "C" fn _kernel_start() -> ! {
|
||||
// Initialise SSE, then jump to kernel entrypoint
|
||||
core::arch::naked_asm!(
|
||||
// Initialise SSE
|
||||
"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();
|
||||
crate::logger::init().expect("failed to set logger");
|
||||
log::debug!("Initialising AKern {}", crate::VERSION);
|
||||
log::info!("Initialising AKern {}", crate::VERSION);
|
||||
|
||||
static HDHM_REQ: HhdmRequest = HhdmRequest::new(0);
|
||||
memory::init_pt(VirtAddr::new(
|
||||
|
@ -119,6 +33,7 @@ unsafe extern "C" fn start() -> ! {
|
|||
.expect("tried to get physical memory mapping offset from Limine")
|
||||
.offset,
|
||||
));
|
||||
|
||||
allocator::init(INITIAL_KERNEL_HEAP_START, INITIAL_KERNEL_HEAP_SIZE as _);
|
||||
|
||||
static MMAP_REQ: MemmapRequest = MemmapRequest::new(0);
|
||||
|
@ -136,100 +51,6 @@ unsafe extern "C" fn start() -> ! {
|
|||
static KFILE_REQ: KernelFileRequest = KernelFileRequest::new(0);
|
||||
static MOD_REQ: ModuleRequest = ModuleRequest::new(0);
|
||||
|
||||
device_info_collector::collect_device_info();
|
||||
|
||||
// Graphics test
|
||||
// {
|
||||
// graphics::init();
|
||||
// let mut dis = DISPLAY.lock();
|
||||
// use embedded_graphics::prelude::RgbColor;
|
||||
|
||||
// let _ = dis.set_color(Rgb888::YELLOW);
|
||||
// let thick = 6;
|
||||
// let p1 = (400, 30);
|
||||
// let p2 = (200, 150);
|
||||
// let p3 = (600, 150);
|
||||
// let p4 = (200, 350);
|
||||
// let p5 = (600, 350);
|
||||
// let p6 = (400, 470);
|
||||
|
||||
// {
|
||||
// //HEXAGON
|
||||
|
||||
// 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(p2.0, p2.1, p4.0, p4.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, p5.0, p5.1, thick);
|
||||
// }
|
||||
// {
|
||||
// let _ = dis.line(600, 150, 200, 350, thick);
|
||||
// let _ = dis.line(600, 350, 400, 250, thick);
|
||||
// }
|
||||
|
||||
// {
|
||||
// let _ = dis.set_color(Rgb888::WHITE);
|
||||
// let hp1 = (350, 150);
|
||||
// let hp2 = (350, 350);
|
||||
// let hp3 = (450, 250);
|
||||
// let hp4 = (350, 250);
|
||||
// let hp5 = (450, 150);
|
||||
// let hp6 = (450, 350);
|
||||
|
||||
// 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(hp5.0, hp5.1, hp6.0, hp6.1, thick);
|
||||
// }
|
||||
|
||||
// dis.swap_buffers();
|
||||
// };
|
||||
|
||||
// TODO: Add in rdseed and rdrand as sources for randomness
|
||||
let _rand = xml::XMLElement::new("Random");
|
||||
|
||||
log::debug!("Getting boot modules");
|
||||
let bm = MOD_REQ.get_response().get();
|
||||
|
||||
let mut bootmodules = alloc::vec::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);
|
||||
}
|
||||
|
||||
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::debug!("Boot module count: {:?}", bootmodules.len());
|
||||
assert_eq!(bm.module_count, bootmodules.len() as u64);
|
||||
}
|
||||
|
||||
crate::kmain::kmain(
|
||||
KFILE_REQ
|
||||
.get_response()
|
||||
|
@ -242,100 +63,32 @@ unsafe extern "C" fn start() -> ! {
|
|||
.transpose()
|
||||
.expect("expected valid cmdline string")
|
||||
.unwrap_or_default(),
|
||||
bootmodules,
|
||||
MOD_REQ
|
||||
.get_response()
|
||||
.get()
|
||||
.and_then(|m| m.modules().get(0))
|
||||
.map(|file| unsafe {
|
||||
core::slice::from_raw_parts(
|
||||
file.base.as_ptr().expect("invalid initrd"),
|
||||
file.length as usize,
|
||||
)
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
/// Spin loop
|
||||
pub fn spin_loop() -> ! {
|
||||
pub fn sloop() -> ! {
|
||||
loop {
|
||||
core::hint::spin_loop();
|
||||
x86_64::instructions::hlt()
|
||||
x86_64::instructions::hlt();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn hardware_random_u64() -> u64 {
|
||||
let mut out: u64 = 0;
|
||||
match unsafe { _rdrand64_step(&mut out) } {
|
||||
1 => out,
|
||||
_ => {
|
||||
warn!("RDRand not supported.");
|
||||
// Try rdseed
|
||||
match unsafe { _rdseed64_step(&mut out) } {
|
||||
1 => out,
|
||||
_ => panic!("Neither RDRand or RDSeed are supported"),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
);
|
||||
use log::trace;
|
||||
use rdrand::RdRand;
|
||||
let gen = RdRand::new().unwrap();
|
||||
let ret = gen.try_next_u64().unwrap();
|
||||
trace!("Random {}", ret);
|
||||
|
||||
ret
|
||||
}
|
||||
|
|
|
@ -1,515 +0,0 @@
|
|||
#[derive(Copy, Clone, Debug)]
|
||||
/// A struct containing info about a PCI device.
|
||||
pub struct PciDeviceInfo {
|
||||
pub header_type: u8,
|
||||
pub device: u8,
|
||||
pub bus: u8,
|
||||
pub device_id: DeviceID,
|
||||
pub full_class: PciFullClass,
|
||||
pub rev_id: u8,
|
||||
}
|
||||
|
||||
/// Enumerate PCI devices and run initialisation routines on ones we support
|
||||
pub fn init(device_tree: &mut DeviceTree) {
|
||||
device_tree
|
||||
.devices
|
||||
.insert("Unidentified PCI", alloc::vec![]);
|
||||
let mut devices = alloc::vec![];
|
||||
|
||||
for bus in 0..=255 {
|
||||
for device in 0..32 {
|
||||
if let Some(device_info) = check_device(bus, device) {
|
||||
let vendor = device_info.device_id.vendor;
|
||||
let id = device_info.device_id.id;
|
||||
use Vendor::*;
|
||||
let (dev_type, dev_name) = match (vendor, id) {
|
||||
(VMWareInc, 1029) => ("GPUs", "SVGAII PCI GPU"),
|
||||
(Qemu, 4369) => ("GPUs", "QEMU VGA"),
|
||||
(VirtIO, 4176) => ("GPUs", "VirtIO PCI GPU"),
|
||||
(CirrusLogic, 184) => ("GPUs", "Cirrus SVGA"), //GD 5446?
|
||||
(_, _) => ("Unidentified PCI", "UNKNOWN DEVICE"),
|
||||
};
|
||||
// let (dev_type, dev_name) = match device_info.full_class {
|
||||
// PciFullClass::Unclassified_NonVgaCompatible => todo!(),
|
||||
// PciFullClass::Unclassified_VgaCompatible => todo!(),
|
||||
|
||||
// PciFullClass::Display_VGA => ("GPUs", "VGA Device"),
|
||||
// PciFullClass::Display_XGA => ("GPUs", "XGA Device"),
|
||||
// PciFullClass::Display_3D => ("GPUs", "3D Device"),
|
||||
// PciFullClass::Display_Other => ("GPUs", "Other"),
|
||||
|
||||
// _ => ("Unidentified PCI", "UNKNOWN DEVICE"),
|
||||
// };
|
||||
|
||||
let mut dev = xml::XMLElement::new(dev_name);
|
||||
let mut pci_info = xml::XMLElement::new("PCI Info");
|
||||
pci_info.set_attribute("id", id);
|
||||
pci_info.set_attribute("device", device_info.device);
|
||||
pci_info.set_attribute("vendor", vendor);
|
||||
pci_info.set_attribute("bus", bus);
|
||||
pci_info.set_attribute("class", device_info.full_class);
|
||||
dev.set_child(pci_info);
|
||||
devices.push((dev_type, dev));
|
||||
}
|
||||
}
|
||||
}
|
||||
for (dev_type, dev) in devices {
|
||||
if let Some(abc) = device_tree.devices.get_mut(dev_type) {
|
||||
abc.push(dev);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn check_device(bus: u8, device: u8) -> Option<PciDeviceInfo> {
|
||||
assert!(device < 32);
|
||||
let (device_id, vendor_id) = get_ids(bus, device, 0);
|
||||
if vendor_id == 0xFFFF {
|
||||
// Device doesn't exist
|
||||
return None;
|
||||
}
|
||||
|
||||
let (reg2, addr) = unsafe { pci_config_read_2(bus, device, 0, 0x8) };
|
||||
log::debug!("pci device-({}) addr {} is {}", device, addr, reg2);
|
||||
let class = ((reg2 >> 16) & 0x0000_FFFF) as u16;
|
||||
let pci_class = PciFullClass::from_u16(class);
|
||||
let header_type = get_header_type(bus, device, 0);
|
||||
|
||||
Some(PciDeviceInfo {
|
||||
header_type,
|
||||
device,
|
||||
bus,
|
||||
device_id: DeviceID {
|
||||
vendor: vendor_id.into(),
|
||||
id: device_id,
|
||||
},
|
||||
full_class: pci_class,
|
||||
rev_id: (reg2 & 0x0000_00FF) as u8,
|
||||
})
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub struct DeviceID {
|
||||
pub vendor: Vendor,
|
||||
pub id: u16,
|
||||
}
|
||||
impl DeviceID {
|
||||
pub const fn new(vendor: Vendor, id: u16) -> Self {
|
||||
Self { vendor, id }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Debug, Copy, Clone, Eq)]
|
||||
#[repr(u16)]
|
||||
pub enum Vendor {
|
||||
ThreeDfxInteractiveInc = 0x121A,
|
||||
ThreeDLabs = 0x3D3D,
|
||||
AllianceSemiconductorCorp = 0x1142,
|
||||
ARKLogicInc = 0xEDD8,
|
||||
ATITechnologiesInc = 0x1002,
|
||||
AvanceLogicIncALI = 0x1005,
|
||||
ChipsandTechnologies = 0x102C,
|
||||
CirrusLogic = 0x1013,
|
||||
Compaq = 0x0E11,
|
||||
CyrixCorp = 0x1078,
|
||||
DiamondMultimediaSystems = 0x1092,
|
||||
DigitalEquipmentCorp = 0x1011,
|
||||
Iit = 0x1061,
|
||||
IntegratedMicroSolutionsInc = 0x10E0,
|
||||
IntelCorp = 0x8086,
|
||||
IntergraphicsSystems = 0x10EA,
|
||||
MacronixInc = 0x10D9,
|
||||
MatroxGraphicsInc = 0x102B,
|
||||
MiroComputersProductsAG = 0x1031,
|
||||
NationalSemiconductorCorp = 0x100B,
|
||||
NeoMagicCorp = 0x10C8,
|
||||
Number9ComputerCompany = 0x105D,
|
||||
NVidiaCorporation = 0x10DE,
|
||||
NVidiaSgsthomson = 0x12D2,
|
||||
OakTechnologyInc = 0x104E,
|
||||
Qemu = 0x1234,
|
||||
QuantumDesignsHKLtd = 0x1098,
|
||||
Real3D = 0x003D,
|
||||
Rendition = 0x1163,
|
||||
S3Inc = 0x5333,
|
||||
SierraSemiconductor = 0x10A8,
|
||||
SiliconIntegratedSystemsSiS = 0x1039,
|
||||
SiliconMotionInc = 0x126F,
|
||||
STBSystemsInc = 0x10B4,
|
||||
TexasInstruments = 0x104C,
|
||||
ToshibaAmericaInfoSystems = 0x1179,
|
||||
TridentMicrosystems = 0x1023,
|
||||
TsengLabsInc = 0x100C,
|
||||
TundraSemiconductorCorp = 0x10E3,
|
||||
VIATechnologiesInc = 0x1106,
|
||||
VirtIO = 0x1AF4,
|
||||
VMWareInc = 0x15AD,
|
||||
Weitek = 0x100E,
|
||||
Unknown(u16),
|
||||
}
|
||||
|
||||
impl From<u16> for Vendor {
|
||||
fn from(vendor_id: u16) -> Self {
|
||||
use Vendor::*;
|
||||
match vendor_id {
|
||||
0x121A => ThreeDfxInteractiveInc,
|
||||
0x3D3D => ThreeDLabs,
|
||||
0x1142 => AllianceSemiconductorCorp,
|
||||
0xEDD8 => ARKLogicInc,
|
||||
0x1002 => ATITechnologiesInc,
|
||||
0x1005 => AvanceLogicIncALI,
|
||||
0x102C => ChipsandTechnologies,
|
||||
0x1013 => CirrusLogic,
|
||||
0x0E11 => Compaq,
|
||||
0x1078 => CyrixCorp,
|
||||
0x1092 => DiamondMultimediaSystems,
|
||||
0x1011 => DigitalEquipmentCorp,
|
||||
0x1061 => Iit,
|
||||
0x10E0 => IntegratedMicroSolutionsInc,
|
||||
0x8086 => IntelCorp,
|
||||
0x10EA => IntergraphicsSystems,
|
||||
0x10D9 => MacronixInc,
|
||||
0x102B => MatroxGraphicsInc,
|
||||
0x1031 => MiroComputersProductsAG,
|
||||
0x100B => NationalSemiconductorCorp,
|
||||
0x10C8 => NeoMagicCorp,
|
||||
0x105D => Number9ComputerCompany,
|
||||
0x10DE => NVidiaCorporation,
|
||||
0x12D2 => NVidiaSgsthomson,
|
||||
0x104E => OakTechnologyInc,
|
||||
0x1234 => Qemu,
|
||||
0x1098 => QuantumDesignsHKLtd,
|
||||
0x003D => Real3D,
|
||||
0x1163 => Rendition,
|
||||
0x5333 => S3Inc,
|
||||
0x10A8 => SierraSemiconductor,
|
||||
0x1039 => SiliconIntegratedSystemsSiS,
|
||||
0x126F => SiliconMotionInc,
|
||||
0x10B4 => STBSystemsInc,
|
||||
0x104C => TexasInstruments,
|
||||
0x1179 => ToshibaAmericaInfoSystems,
|
||||
0x1023 => TridentMicrosystems,
|
||||
0x100C => TsengLabsInc,
|
||||
0x10E3 => TundraSemiconductorCorp,
|
||||
0x1106 => VIATechnologiesInc,
|
||||
0x1AF4 => VirtIO,
|
||||
0x15AD => VMWareInc,
|
||||
0x100E => Weitek,
|
||||
id => Unknown(id),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<u16> for Vendor {
|
||||
fn into(self) -> u16 {
|
||||
use Vendor::*;
|
||||
match self {
|
||||
ThreeDfxInteractiveInc => 0x121A,
|
||||
ThreeDLabs => 0x3D3D,
|
||||
AllianceSemiconductorCorp => 0x1142,
|
||||
ARKLogicInc => 0xEDD8,
|
||||
ATITechnologiesInc => 0x1002,
|
||||
AvanceLogicIncALI => 0x1005,
|
||||
ChipsandTechnologies => 0x102C,
|
||||
CirrusLogic => 0x1013,
|
||||
Compaq => 0x0E11,
|
||||
CyrixCorp => 0x1078,
|
||||
DiamondMultimediaSystems => 0x1092,
|
||||
DigitalEquipmentCorp => 0x1011,
|
||||
Iit => 0x1061,
|
||||
IntegratedMicroSolutionsInc => 0x10E0,
|
||||
IntelCorp => 0x8086,
|
||||
IntergraphicsSystems => 0x10EA,
|
||||
MacronixInc => 0x10D9,
|
||||
MatroxGraphicsInc => 0x102B,
|
||||
MiroComputersProductsAG => 0x1031,
|
||||
NationalSemiconductorCorp => 0x100B,
|
||||
NeoMagicCorp => 0x10C8,
|
||||
Number9ComputerCompany => 0x105D,
|
||||
NVidiaCorporation => 0x10DE,
|
||||
NVidiaSgsthomson => 0x12D2,
|
||||
OakTechnologyInc => 0x104E,
|
||||
Qemu => 0x1234,
|
||||
QuantumDesignsHKLtd => 0x1098,
|
||||
Real3D => 0x003D,
|
||||
Rendition => 0x1163,
|
||||
S3Inc => 0x5333,
|
||||
SierraSemiconductor => 0x10A8,
|
||||
SiliconIntegratedSystemsSiS => 0x1039,
|
||||
SiliconMotionInc => 0x126F,
|
||||
STBSystemsInc => 0x10B4,
|
||||
TexasInstruments => 0x104C,
|
||||
ToshibaAmericaInfoSystems => 0x1179,
|
||||
TridentMicrosystems => 0x1023,
|
||||
TsengLabsInc => 0x100C,
|
||||
TundraSemiconductorCorp => 0x10E3,
|
||||
VIATechnologiesInc => 0x1106,
|
||||
VirtIO => 0x1AF4,
|
||||
VMWareInc => 0x15AD,
|
||||
Weitek => 0x100E,
|
||||
Unknown(id) => id,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Vendor {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
use Vendor::*;
|
||||
|
||||
match self {
|
||||
Qemu => write!(f, "QEMU (0x1234)"),
|
||||
VirtIO => write!(f, "VirtIO (0x1AF4)"),
|
||||
VMWareInc => write!(f, "VMWARE (0x15AD)"),
|
||||
S3Inc => write!(f, "S3 Incorporated (0x5333)"),
|
||||
IntelCorp => write!(f, "Intel Corp. (0x8086)"),
|
||||
ATITechnologiesInc => write!(f, "ATI (0x1002)"),
|
||||
Unknown(id) => write!(f, "Unknown ({:#6})", id),
|
||||
other => write!(f, "{other:?}"),
|
||||
}?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
use core::fmt::Display;
|
||||
|
||||
use {crate::device_tree::DeviceTree, x86_64::instructions::port::Port};
|
||||
|
||||
#[allow(non_camel_case_types, dead_code)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
#[repr(C)]
|
||||
/// Class specification for a PCI device
|
||||
pub enum PciClass {
|
||||
Unclassified = 0x00,
|
||||
MassStorage = 0x01,
|
||||
Network = 0x02,
|
||||
Display = 0x03,
|
||||
Multimedia = 0x04,
|
||||
Memory = 0x05,
|
||||
Bridge = 0x06,
|
||||
Unknown = 0xFF,
|
||||
}
|
||||
|
||||
impl From<u8> for PciClass {
|
||||
/// Convert a u8 into the corresponding PciClass
|
||||
fn from(n: u8) -> Self {
|
||||
use PciClass::*;
|
||||
match n {
|
||||
0x00 => Unclassified,
|
||||
0x01 => MassStorage,
|
||||
0x02 => Network,
|
||||
0x03 => Display,
|
||||
0x04 => Multimedia,
|
||||
0x05 => Memory,
|
||||
0x06 => Bridge,
|
||||
_ => Unknown,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(non_camel_case_types, dead_code)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
#[repr(C)]
|
||||
/// Full class specification (type and subtype) for a PCI device.
|
||||
///
|
||||
/// Uses non-camel-case types for readability.
|
||||
pub enum PciFullClass {
|
||||
Unclassified_NonVgaCompatible = 0x0000,
|
||||
Unclassified_VgaCompatible = 0x0001,
|
||||
|
||||
MassStorage_ScsiBus = 0x0100,
|
||||
MassStorage_IDE = 0x0101,
|
||||
MassStorage_Floppy = 0x0102,
|
||||
MassStorage_IpiBus = 0x0103,
|
||||
MassStorage_RAID = 0x0104,
|
||||
MassStorage_ATA = 0x0105,
|
||||
MassStorage_SATA = 0x0106,
|
||||
MassStorage_SerialSCSI = 0x0107,
|
||||
MassStorage_NVM = 0x0108,
|
||||
MassStorage_Other = 0x0180,
|
||||
|
||||
Network_Ethernet = 0x0200,
|
||||
Network_TokenRing = 0x0201,
|
||||
Network_FDDI = 0x0202,
|
||||
Network_ATM = 0x0203,
|
||||
Network_ISDN = 0x0204,
|
||||
Network_WorldFlip = 0x0205,
|
||||
Network_PICMG = 0x0206,
|
||||
Network_Infiniband = 0x0207,
|
||||
Network_Fabric = 0x0208,
|
||||
Network_Other = 0x0280,
|
||||
|
||||
Display_VGA = 0x0300,
|
||||
Display_XGA = 0x0301,
|
||||
Display_3D = 0x0302,
|
||||
Display_Other = 0x0380,
|
||||
|
||||
Multimedia_Video = 0x0400,
|
||||
Multimedia_AudioController = 0x0401,
|
||||
Multimedia_Telephony = 0x0402,
|
||||
Multimedia_AudioDevice = 0x0403,
|
||||
Multimedia_Other = 0x0480,
|
||||
|
||||
Memory_RAM = 0x0500,
|
||||
Memory_Flash = 0x0501,
|
||||
Memory_Other = 0x0580,
|
||||
|
||||
Bridge_Host = 0x0600,
|
||||
Bridge_ISA = 0x0601,
|
||||
Bridge_EISA = 0x0602,
|
||||
Bridge_MCA = 0x0603,
|
||||
Bridge_PciToPci = 0x0604,
|
||||
Bridge_PCMCIA = 0x0605,
|
||||
Bridge_NuBus = 0x0606,
|
||||
Bridge_CardBus = 0x0607,
|
||||
Bridge_RACEway = 0x0608,
|
||||
Bridge_PciToPciSemiTransparent = 0x0609,
|
||||
Bridge_InfinibandToPci = 0x060A,
|
||||
Bridge_Other = 0x0680,
|
||||
|
||||
Unknown = 0xFFFF,
|
||||
}
|
||||
|
||||
impl PciFullClass {
|
||||
// listen, i know this sucks, but i didn't want to include
|
||||
// `num`, `num-traits` and `num-derive` as dependencies for
|
||||
// this crate just for a convenience function
|
||||
/// Convert a u16 into the corresponding PciFullClass
|
||||
pub fn from_u16(n: u16) -> PciFullClass {
|
||||
match n {
|
||||
0x0000 => PciFullClass::Unclassified_NonVgaCompatible,
|
||||
0x0001 => PciFullClass::Unclassified_VgaCompatible,
|
||||
|
||||
0x0100 => PciFullClass::MassStorage_ScsiBus,
|
||||
0x0101 => PciFullClass::MassStorage_IDE,
|
||||
0x0102 => PciFullClass::MassStorage_Floppy,
|
||||
0x0103 => PciFullClass::MassStorage_IpiBus,
|
||||
0x0104 => PciFullClass::MassStorage_RAID,
|
||||
0x0105 => PciFullClass::MassStorage_ATA,
|
||||
0x0106 => PciFullClass::MassStorage_SATA,
|
||||
0x0107 => PciFullClass::MassStorage_SerialSCSI,
|
||||
0x0108 => PciFullClass::MassStorage_NVM,
|
||||
0x0180 => PciFullClass::MassStorage_Other,
|
||||
|
||||
0x0200 => PciFullClass::Network_Ethernet,
|
||||
0x0201 => PciFullClass::Network_TokenRing,
|
||||
0x0202 => PciFullClass::Network_FDDI,
|
||||
0x0203 => PciFullClass::Network_ATM,
|
||||
0x0204 => PciFullClass::Network_ISDN,
|
||||
0x0205 => PciFullClass::Network_WorldFlip,
|
||||
0x0206 => PciFullClass::Network_PICMG,
|
||||
0x0207 => PciFullClass::Network_Infiniband,
|
||||
0x0208 => PciFullClass::Network_Fabric,
|
||||
0x0280 => PciFullClass::Network_Other,
|
||||
|
||||
0x0300 => PciFullClass::Display_VGA,
|
||||
0x0301 => PciFullClass::Display_XGA,
|
||||
0x0302 => PciFullClass::Display_3D,
|
||||
0x0380 => PciFullClass::Display_Other,
|
||||
|
||||
0x0400 => PciFullClass::Multimedia_Video,
|
||||
0x0401 => PciFullClass::Multimedia_AudioController,
|
||||
0x0402 => PciFullClass::Multimedia_Telephony,
|
||||
0x0403 => PciFullClass::Multimedia_AudioDevice,
|
||||
0x0480 => PciFullClass::Multimedia_Other,
|
||||
|
||||
0x0500 => PciFullClass::Memory_RAM,
|
||||
0x0501 => PciFullClass::Memory_Flash,
|
||||
0x0580 => PciFullClass::Memory_Other,
|
||||
|
||||
0x0600 => PciFullClass::Bridge_Host,
|
||||
0x0601 => PciFullClass::Bridge_ISA,
|
||||
0x0602 => PciFullClass::Bridge_EISA,
|
||||
0x0603 => PciFullClass::Bridge_MCA,
|
||||
0x0604 => PciFullClass::Bridge_PciToPci,
|
||||
0x0605 => PciFullClass::Bridge_PCMCIA,
|
||||
0x0606 => PciFullClass::Bridge_NuBus,
|
||||
0x0607 => PciFullClass::Bridge_CardBus,
|
||||
0x0608 => PciFullClass::Bridge_RACEway,
|
||||
0x0609 => PciFullClass::Bridge_PciToPciSemiTransparent,
|
||||
0x060A => PciFullClass::Bridge_InfinibandToPci,
|
||||
0x0680 => PciFullClass::Bridge_Other,
|
||||
|
||||
_ => PciFullClass::Unknown,
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert a PciFullClass to its u16 representation
|
||||
pub fn as_u16(&self) -> u16 {
|
||||
*self as u16
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u16> for PciFullClass {
|
||||
/// Convert a u16 into the corresponding PciFullClass
|
||||
fn from(n: u16) -> Self {
|
||||
Self::from_u16(n)
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for PciFullClass {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
write!(f, "{:?} ({:#06X})", self, self.as_u16())?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn pci_config_read(bus: u8, device: u8, func: u8, offset: u8) -> 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()
|
||||
}
|
||||
|
||||
unsafe fn pci_config_read_2(bus: u8, device: u8, func: u8, offset: u8) -> (u32, u32) {
|
||||
let bus = bus as u32;
|
||||
let device = device as u32;
|
||||
let func = func as u32;
|
||||
let offset = offset as u32;
|
||||
// construct address param
|
||||
let address = (bus << 16) | (device << 11) | (func << 8) | (offset & 0xFC) | 0x8000_0000;
|
||||
// write address
|
||||
Port::new(0xCF8).write(address);
|
||||
|
||||
// read data
|
||||
(Port::new(0xCFC).read(), address)
|
||||
}
|
||||
|
||||
unsafe fn pci_config_write(bus: u8, device: u8, func: u8, offset: u8, value: u32) {
|
||||
let bus = bus as u32;
|
||||
let device = device as u32;
|
||||
let func = func as u32;
|
||||
let offset = offset as u32;
|
||||
// construct address param
|
||||
let address =
|
||||
((bus << 16) | (device << 11) | (func << 8) | (offset & 0xFC) | 0x8000_0000) as u32;
|
||||
|
||||
// write address
|
||||
Port::new(0xCF8).write(address);
|
||||
|
||||
// write data
|
||||
Port::new(0xCFC).write(value);
|
||||
}
|
||||
|
||||
fn get_header_type(bus: u8, device: u8, function: u8) -> u8 {
|
||||
assert!(device < 32);
|
||||
assert!(function < 8);
|
||||
let res = unsafe { pci_config_read(bus, device, function, 0x0C) };
|
||||
((res >> 16) & 0xFF) as u8
|
||||
}
|
||||
|
||||
fn get_ids(bus: u8, device: u8, function: u8) -> (u16, u16) {
|
||||
assert!(device < 32);
|
||||
assert!(function < 8);
|
||||
let res = unsafe { pci_config_read(bus, device, function, 0) };
|
||||
let dev_id = ((res >> 16) & 0xFFFF) as u16;
|
||||
let vnd_id = (res & 0xFFFF) as u16;
|
||||
(dev_id, vnd_id)
|
||||
}
|
|
@ -1,37 +0,0 @@
|
|||
use {
|
||||
core::ptr::NonNull,
|
||||
virtio_drivers::{BufferDirection, Hal, PhysAddr},
|
||||
};
|
||||
|
||||
pub fn test() {
|
||||
let _ps = virtio_drivers::PAGE_SIZE;
|
||||
}
|
||||
|
||||
pub struct AbleosHal;
|
||||
|
||||
unsafe impl Hal for AbleosHal {
|
||||
fn dma_alloc(_pages: usize, _direction: BufferDirection) -> (PhysAddr, NonNull<u8>) {
|
||||
todo!();
|
||||
}
|
||||
|
||||
unsafe fn dma_dealloc(_paddr: PhysAddr, _vaddr: NonNull<u8>, _pages: usize) -> i32 {
|
||||
todo!()
|
||||
}
|
||||
|
||||
unsafe fn mmio_phys_to_virt(paddr: PhysAddr, _size: usize) -> NonNull<u8> {
|
||||
NonNull::new(paddr as _).unwrap()
|
||||
}
|
||||
|
||||
unsafe fn share(_buffer: NonNull<[u8]>, _direction: BufferDirection) -> PhysAddr {
|
||||
todo!()
|
||||
}
|
||||
|
||||
unsafe fn unshare(_paddr: PhysAddr, _buffer: NonNull<[u8]>, _direction: BufferDirection) {
|
||||
// Nothing to do, as the host already has access to all memory and we didn't copy the buffer
|
||||
// anywhere else.
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
fn virt_to_phys(vaddr: usize) -> PhysAddr {
|
||||
vaddr
|
||||
}
|
|
@ -1,36 +0,0 @@
|
|||
use {
|
||||
// crate::alloc::string::ToString,
|
||||
alloc::vec::Vec,
|
||||
// clparse::Arguments,
|
||||
// core::fmt::{Debug, Display},
|
||||
// log::trace,
|
||||
// xml::XMLElement,
|
||||
};
|
||||
pub type BootModules<'a> = Vec<BootModule<'a>>;
|
||||
|
||||
pub struct BootModule<'a> {
|
||||
pub path: &'a str,
|
||||
pub bytes: &'a [u8],
|
||||
pub cmd: &'a str,
|
||||
}
|
||||
impl<'a> BootModule<'a> {
|
||||
pub fn new(path: &'a str, bytes: &'a [u8], cmd: &'a str) -> Self {
|
||||
Self { path, bytes, cmd }
|
||||
}
|
||||
}
|
||||
|
||||
// pub fn build_cmd<T: Display + Debug>(name: T, cmdline: T) -> XMLElement {
|
||||
// let mut cmdline = cmdline.to_string();
|
||||
// cmdline.pop();
|
||||
// cmdline.remove(0);
|
||||
|
||||
// let cmd = Arguments::parse(cmdline.to_string()).unwrap();
|
||||
// trace!("Cmdline: {cmd:?}");
|
||||
|
||||
// let mut clo = XMLElement::new(name);
|
||||
// for (key, value) in cmd.arguments {
|
||||
// clo.set_attribute(key, value);
|
||||
// }
|
||||
// trace!("command line object: {:?}", clo);
|
||||
// clo
|
||||
// }
|
|
@ -1,186 +0,0 @@
|
|||
//! AbleOS capability tree implementation
|
||||
|
||||
use {
|
||||
crate::{tab, utils::TAB},
|
||||
alloc::{
|
||||
string::{String, ToString},
|
||||
vec,
|
||||
},
|
||||
core::fmt,
|
||||
};
|
||||
|
||||
// Seperate
|
||||
use alloc::vec::Vec;
|
||||
|
||||
struct Argument {
|
||||
name: String,
|
||||
type_: String,
|
||||
}
|
||||
|
||||
struct Function {
|
||||
name: String,
|
||||
args: Vec<Argument>,
|
||||
ret: String,
|
||||
}
|
||||
|
||||
struct Capability {
|
||||
name: String,
|
||||
functions: Vec<Function>,
|
||||
sub_capabilities: Vec<Capability>,
|
||||
}
|
||||
|
||||
impl Capability {
|
||||
fn new(name: String) -> Capability {
|
||||
Capability {
|
||||
name,
|
||||
functions: Vec::new(),
|
||||
sub_capabilities: Vec::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Capability {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "Capability: {}\r\n", self.name)?;
|
||||
for function in &self.functions {
|
||||
write!(f, "{}Function: {}\r\n", tab!(1), function.name)?;
|
||||
for arg in &function.args {
|
||||
write!(
|
||||
f,
|
||||
"{}Argument: {} (Type: {})\r\n",
|
||||
tab!(2),
|
||||
arg.name,
|
||||
arg.type_
|
||||
)?;
|
||||
}
|
||||
write!(f, "{}Return Type: {}\r\n", tab!(2), &function.ret)?;
|
||||
}
|
||||
for sub_capability in &self.sub_capabilities {
|
||||
write!(f, "{}{}\r\n", tab!(1), sub_capability)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
// impl Capability {
|
||||
// fn to_string_with_indentation(&self, level: usize) -> String {
|
||||
// let indent = tab!(level);
|
||||
// let mut result = format!("{}Capability: {}\n", indent, self.name);
|
||||
// for function in &self.functions {
|
||||
// result.push_str(&format!(
|
||||
// "{}Function: {}\n",
|
||||
// tab!(indent + 1),
|
||||
// function.name
|
||||
// ));
|
||||
// for arg in &function.args {
|
||||
// result.push_str(&format!(
|
||||
// "{}Argument: {} (Type: {})\n",
|
||||
// tab!(indent + 2),
|
||||
// arg.name,
|
||||
// arg.type_
|
||||
// ));
|
||||
// }
|
||||
// result.push_str(&format!(
|
||||
// "{}Return Type: {}\n",
|
||||
// tab!(indent + 2),
|
||||
// &function.ret
|
||||
// ));
|
||||
// }
|
||||
// for sub_capability in &self.sub_capabilities {
|
||||
// result.push_str(&sub_capability.to_string_with_indentation(level + 1));
|
||||
// }
|
||||
// result
|
||||
// }
|
||||
// }
|
||||
|
||||
struct CapabilityTree {
|
||||
capabilities: Vec<Capability>,
|
||||
}
|
||||
|
||||
impl CapabilityTree {
|
||||
fn new() -> CapabilityTree {
|
||||
CapabilityTree {
|
||||
capabilities: Vec::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A super simple capabilities example
|
||||
pub fn example() {
|
||||
let mut capability_tree = Capability::new("VFS".to_string());
|
||||
|
||||
let mut file_management_capability = Capability::new("File Management".to_string());
|
||||
file_management_capability.functions.push(Function {
|
||||
name: "OpenFile".to_string(),
|
||||
args: vec![
|
||||
Argument {
|
||||
name: "path".to_string(),
|
||||
type_: "String".to_string(),
|
||||
},
|
||||
Argument {
|
||||
name: "mode".to_string(),
|
||||
type_: "String".to_string(),
|
||||
},
|
||||
],
|
||||
ret: "FileHandle".to_string(),
|
||||
});
|
||||
file_management_capability.functions.push(Function {
|
||||
name: "ReadFile".to_string(),
|
||||
args: vec![
|
||||
Argument {
|
||||
name: "file".to_string(),
|
||||
type_: "FileHandle".to_string(),
|
||||
},
|
||||
Argument {
|
||||
name: "buffer".to_string(),
|
||||
type_: "&mut [u8]".to_string(),
|
||||
},
|
||||
Argument {
|
||||
name: "length".to_string(),
|
||||
type_: "usize".to_string(),
|
||||
},
|
||||
],
|
||||
ret: "usize".to_string(),
|
||||
});
|
||||
file_management_capability.functions.push(Function {
|
||||
name: "WriteFile".to_string(),
|
||||
args: vec![
|
||||
Argument {
|
||||
name: "file".to_string(),
|
||||
type_: "FileHandle".to_string(),
|
||||
},
|
||||
Argument {
|
||||
name: "buffer".to_string(),
|
||||
type_: "&[u8]".to_string(),
|
||||
},
|
||||
],
|
||||
ret: "None".to_string(),
|
||||
});
|
||||
|
||||
let mut directory_management_capability = Capability::new("Directory Management".to_string());
|
||||
directory_management_capability.functions.push(Function {
|
||||
name: "CreateDirectory".to_string(),
|
||||
args: vec![Argument {
|
||||
name: "path".to_string(),
|
||||
type_: "String".to_string(),
|
||||
}],
|
||||
ret: "bool".to_string(),
|
||||
});
|
||||
directory_management_capability.functions.push(Function {
|
||||
name: "ListDirectory".to_string(),
|
||||
args: vec![Argument {
|
||||
name: "path".to_string(),
|
||||
type_: "String".to_string(),
|
||||
}],
|
||||
ret: "Vec<String>".to_string(),
|
||||
});
|
||||
|
||||
capability_tree
|
||||
.sub_capabilities
|
||||
.push(file_management_capability);
|
||||
capability_tree
|
||||
.sub_capabilities
|
||||
.push(directory_management_capability);
|
||||
|
||||
log::debug!("CapTree\r\n{}", capability_tree);
|
||||
}
|
|
@ -1,71 +0,0 @@
|
|||
//! A tree of hardware devices
|
||||
|
||||
use {alloc::vec::Vec, core::fmt, hashbrown::HashMap};
|
||||
|
||||
/// A device object.
|
||||
/// TODO define device
|
||||
pub type Device = xml::XMLElement;
|
||||
|
||||
/// A tree of devices
|
||||
// TODO: alphabetize this list
|
||||
#[derive(Debug)]
|
||||
pub struct DeviceTree<'a> {
|
||||
/// The device tree
|
||||
pub devices: HashMap<&'a str, Vec<Device>>,
|
||||
}
|
||||
impl<'a> DeviceTree<'a> {
|
||||
/// Build the device tree. Does not populate the device tree
|
||||
pub fn new() -> Self {
|
||||
let mut dt = Self {
|
||||
devices: HashMap::new(),
|
||||
};
|
||||
device_tree!(
|
||||
dt,
|
||||
[
|
||||
"Mice",
|
||||
"Keyboards",
|
||||
"Controllers",
|
||||
"Generic HIDs",
|
||||
"Disk Drives",
|
||||
"CD Drives",
|
||||
"Batteries",
|
||||
"Monitors",
|
||||
"GPUs",
|
||||
"CPUs",
|
||||
"USB",
|
||||
"Serial Ports",
|
||||
"Cameras",
|
||||
"Biometric Devices",
|
||||
]
|
||||
);
|
||||
dt
|
||||
}
|
||||
}
|
||||
use crate::{device_tree, tab, utils::TAB};
|
||||
impl<'a> fmt::Display for DeviceTree<'a> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
writeln!(f)?;
|
||||
for (device_type, devices) in &self.devices {
|
||||
writeln!(f, "\r{}{}/\r", tab!(1), device_type)?;
|
||||
for device in devices {
|
||||
writeln!(f, "{}{}/\r", tab!(2), device.name)?;
|
||||
for attr in &device.attributes {
|
||||
writeln!(f, "{}{}\r", tab!(3), attr)?;
|
||||
}
|
||||
for child in &device.children {
|
||||
writeln!(f, "{}{}\r", tab!(3), child.name)?;
|
||||
for attr in &child.attributes {
|
||||
writeln!(f, "{}{}\r", tab!(4), attr)?;
|
||||
}
|
||||
for child in &child.children {
|
||||
writeln!(f, "{}{}\r", tab!(4), child.name)?;
|
||||
for attr in &child.attributes {
|
||||
writeln!(f, "{}{}\r", tab!(5), attr)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
|
@ -1,35 +0,0 @@
|
|||
enum Sections {
|
||||
Header,
|
||||
Code,
|
||||
Data,
|
||||
Debug,
|
||||
Config,
|
||||
Metadata,
|
||||
}
|
||||
|
||||
// 64 byte header
|
||||
#[repr(packed)]
|
||||
struct AbleOsExecutableHeader {
|
||||
magic_number: [u8; 3],
|
||||
executable_version: u32,
|
||||
|
||||
code_length: u64,
|
||||
data_length: u64,
|
||||
debug_length: u64,
|
||||
config_length: u64,
|
||||
metadata_length: u64,
|
||||
}
|
||||
|
||||
impl AbleOsExecutableHeader {
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
magic_number: [0x15, 0x91, 0xD2],
|
||||
executable_version: 0,
|
||||
code_length: 0,
|
||||
config_length: 0,
|
||||
data_length: 0,
|
||||
debug_length: 0,
|
||||
metadata_length: 0,
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,66 +1,85 @@
|
|||
//! A handle module
|
||||
use spin::Lazy;
|
||||
|
||||
use spin::{Mutex};
|
||||
|
||||
use crate::interp::objects::{Object,HandleTarget, TARGETS};
|
||||
|
||||
use {
|
||||
crate::arch::hardware_random_u64,
|
||||
alloc::vec::Vec,
|
||||
core::fmt::{self, Formatter},
|
||||
};
|
||||
/// An operating system handle without permissions attached
|
||||
|
||||
use alloc::{
|
||||
collections::BTreeMap,
|
||||
};
|
||||
#[derive(Debug, Eq, Hash, PartialEq, Clone, Copy)]
|
||||
pub struct OSHandle {
|
||||
id: u64,
|
||||
pub id: u64,
|
||||
}
|
||||
|
||||
impl OSHandle {
|
||||
/// turn a u64 into an OSHandle
|
||||
pub fn new_from_u64(id: u64) -> Self {
|
||||
Self { id }
|
||||
}
|
||||
/// Generate a new OSHandle using the HAL random function
|
||||
pub fn random_new() -> Self {
|
||||
Self {
|
||||
id: hardware_random_u64(),
|
||||
}
|
||||
}
|
||||
}
|
||||
/// A handle for resources
|
||||
|
||||
#[derive(Debug, Eq, Hash, PartialEq, Clone, Copy)]
|
||||
pub struct Handle {
|
||||
id: OSHandle,
|
||||
// TODO: Update this to be indexes into the caps
|
||||
perms: Permissions,
|
||||
pub id: OSHandle,
|
||||
pub perms: Permissions,
|
||||
pub r#ref: usize,
|
||||
}
|
||||
|
||||
impl Handle {
|
||||
/// make a new handle
|
||||
pub fn new() -> Handle {
|
||||
pub fn new(r#ref: usize) -> Handle {
|
||||
Handle {
|
||||
id: OSHandle::random_new(),
|
||||
perms: Permissions::new(),
|
||||
r#ref,
|
||||
}
|
||||
}
|
||||
/// represent the os handle as a u64
|
||||
|
||||
pub fn as_u64(&self) -> u64 {
|
||||
self.id.id
|
||||
}
|
||||
|
||||
pub fn get<R, F: for<'a> FnOnce(Option<&'a mut HandleTarget>) -> R>(&self, f: F) -> R {
|
||||
let l = TARGETS;
|
||||
let mut olock = l.lock();
|
||||
let a = olock.get_mut(self.r#ref).and_then(|a| a.as_mut());
|
||||
return f(a);
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Handle {
|
||||
fn fmt(&self, w: &mut Formatter<'_>) -> Result<(), core::fmt::Error> {
|
||||
write!(w, "{:?}", self.id)?;
|
||||
write!(w, "{:?}", self.id);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Hash, Eq, Debug, Clone, Copy)]
|
||||
struct Permissions {
|
||||
|
||||
pub struct Permissions {
|
||||
edit_children: bool,
|
||||
edit_attributes: bool,
|
||||
}
|
||||
impl Permissions {
|
||||
fn new() -> Self {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
edit_children: true,
|
||||
edit_attributes: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub const GLOBALS: Lazy<Mutex<BTreeMap<[u64; 4], Handle>>> = Lazy::new(|| {
|
||||
let mut globals = BTreeMap::new();
|
||||
Mutex::new(globals)
|
||||
});
|
||||
|
|
|
@ -1,281 +0,0 @@
|
|||
//! 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,
|
||||
}
|
|
@ -1,78 +0,0 @@
|
|||
use {
|
||||
crate::holeybytes::{kernel_services::block_read, Vm},
|
||||
alloc::vec::Vec,
|
||||
};
|
||||
pub enum DtError {
|
||||
QueryFailure,
|
||||
}
|
||||
|
||||
pub fn dt_msg_handler(vm: &mut Vm, mem_addr: u64, length: usize) -> Result<(), DtError> {
|
||||
let msg_vec = block_read(mem_addr, length);
|
||||
let query_string = core::str::from_utf8(
|
||||
msg_vec
|
||||
.split_once(|&byte| byte == 0)
|
||||
.unwrap_or((msg_vec, &[]))
|
||||
.0,
|
||||
)
|
||||
.unwrap();
|
||||
log::trace!("Query {}", query_string);
|
||||
|
||||
let ret = query_parse(query_string);
|
||||
log::trace!("Query response {}", ret);
|
||||
|
||||
vm.registers[1] = hbvm::value::Value(ret);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn query_parse(query_string: &str) -> u64 {
|
||||
let query = query_string.split('/').collect::<Vec<&str>>();
|
||||
|
||||
let first_fragment: &str = &query[0];
|
||||
let ret = match first_fragment {
|
||||
"framebuffer" => framebuffer_parse(query),
|
||||
"cpu" => cpu_parse(query),
|
||||
|
||||
_ => 0,
|
||||
};
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
fn cpu_parse(qt_parse_step_two: Vec<&str>) -> u64 {
|
||||
let second_fragment: &str = qt_parse_step_two[1];
|
||||
match second_fragment {
|
||||
// "architecture" => {
|
||||
// return 0;
|
||||
// }
|
||||
_ => {
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
fn framebuffer_parse(qt_parse_step_two: Vec<&str>) -> u64 {
|
||||
use crate::kmain::FB_REQ;
|
||||
let fbs = &mut FB_REQ.get_response().get().unwrap().framebuffers();
|
||||
let second_fragment: &str = qt_parse_step_two[1];
|
||||
match second_fragment {
|
||||
"fb0" => {
|
||||
let fb_front = &fbs[0];
|
||||
let third_fragment: &str = qt_parse_step_two[2];
|
||||
let ret = match third_fragment {
|
||||
"ptr" => {
|
||||
let ptr = fb_front.address.as_ptr().unwrap();
|
||||
ptr as usize as u64
|
||||
}
|
||||
"width" => fb_front.width,
|
||||
"height" => fb_front.height,
|
||||
|
||||
_ => 0,
|
||||
};
|
||||
return ret;
|
||||
}
|
||||
_ => {
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
}
|
|
@ -1,54 +0,0 @@
|
|||
use crate::holeybytes::{kernel_services::block_read, Vm};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum LogError {
|
||||
InvalidLogFormat,
|
||||
}
|
||||
use log::Record;
|
||||
|
||||
pub fn log_msg_handler(_vm: &mut Vm, mem_addr: u64, length: usize) -> Result<(), LogError> {
|
||||
let msg_vec = block_read(mem_addr, length);
|
||||
|
||||
use log::Level::*;
|
||||
let log_level = match msg_vec[0] {
|
||||
0 | 48 => Error,
|
||||
1 | 49 => Warn,
|
||||
2 | 50 => Info,
|
||||
3 | 51 => Debug,
|
||||
4 | 52 => Trace,
|
||||
_ => {
|
||||
return Err(LogError::InvalidLogFormat);
|
||||
}
|
||||
};
|
||||
if log_level > log::max_level() {
|
||||
return Ok(());
|
||||
}
|
||||
let strptr = u64::from_le_bytes(msg_vec[1..9].try_into().unwrap());
|
||||
let strlen = u64::from_le_bytes(msg_vec[9..17].try_into().unwrap()) as usize;
|
||||
|
||||
let str = block_read(strptr, strlen);
|
||||
|
||||
let file_name = "None";
|
||||
let line_number = 0;
|
||||
|
||||
match core::str::from_utf8(&str) {
|
||||
Ok(strr) => {
|
||||
log::logger().log(
|
||||
&Record::builder()
|
||||
.args(format_args!("{}", strr))
|
||||
.level(log_level)
|
||||
.target("Userspace")
|
||||
.file(Some(file_name))
|
||||
.line(Some(line_number))
|
||||
.module_path(Some(&file_name))
|
||||
.build(),
|
||||
);
|
||||
}
|
||||
|
||||
Err(e) => {
|
||||
log::error!("{:?}", e);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
enum MemoryServiceResult {
|
||||
|
||||
}
|
||||
|
||||
@alignment(4096)
|
||||
type PageAlignedPointer = pointer;
|
||||
|
||||
type RID = u64;
|
||||
|
||||
|
||||
|
||||
@nonexhaustive
|
||||
@version 1.0
|
||||
protocol MemoryService {
|
||||
@validator(page_count, Range(1..16))
|
||||
fn map_pages(page_count: u8, ptr: Optional<PageAlignedPointer>) -> MemoryServiceResult;
|
||||
fn unmap_pages(ptr: PageAlignedPointer) -> MemoryServiceResult;
|
||||
// ptr must be page aligned and already mapped from map_pages
|
||||
fn map_hardware(hw: RID, ptr: PageAlignedPointer) -> MemoryServiceResult;
|
||||
fn unmap_hardware(hw: RID) -> MemoryServiceResult;
|
||||
|
||||
}
|
|
@ -1,122 +0,0 @@
|
|||
use {
|
||||
crate::holeybytes::{kernel_services::block_read, Vm},
|
||||
alloc::alloc::{alloc, dealloc},
|
||||
core::alloc::Layout,
|
||||
log::{debug, info},
|
||||
};
|
||||
|
||||
pub enum MemoryServiceError {
|
||||
InvalidMemoryFormat,
|
||||
}
|
||||
#[derive(Debug)]
|
||||
pub enum MemoryQuotaType {
|
||||
NoQuota = 0,
|
||||
SoftQuota = 1,
|
||||
HardQuota = 2,
|
||||
KillQuota = 3,
|
||||
}
|
||||
|
||||
fn alloc_page(vm: &mut Vm, _mem_addr: u64, _length: usize) -> Result<(), MemoryServiceError> {
|
||||
let ptr = unsafe { alloc(Layout::from_size_align_unchecked(4096, 8)) };
|
||||
info!("Block address: {:?}", ptr);
|
||||
vm.registers[1] = hbvm::value::Value(ptr as u64);
|
||||
vm.registers[2] = hbvm::value::Value(4096);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
unsafe fn memset(dest: *mut u8, src: *const u8, count: usize, size: usize) {
|
||||
let total_size = count * size;
|
||||
src.copy_to_nonoverlapping(dest, size);
|
||||
|
||||
let mut copied = size;
|
||||
|
||||
while copied < total_size {
|
||||
let copy_size = copied.min(total_size - copied);
|
||||
dest.add(copied).copy_from_nonoverlapping(dest, copy_size);
|
||||
copied += copy_size;
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn memory_msg_handler(
|
||||
vm: &mut Vm,
|
||||
mem_addr: u64,
|
||||
length: usize,
|
||||
) -> Result<(), MemoryServiceError> {
|
||||
let msg_vec = block_read(mem_addr, length);
|
||||
let msg_type = msg_vec[0];
|
||||
match msg_type {
|
||||
0 => unsafe {
|
||||
let page_count = msg_vec[1];
|
||||
|
||||
let ptr = alloc(Layout::from_size_align_unchecked(
|
||||
page_count as usize * 4096,
|
||||
8,
|
||||
));
|
||||
|
||||
log::debug!("Allocating {} pages @ {:x}", page_count, ptr as u64);
|
||||
|
||||
vm.registers[1] = hbvm::value::Value(ptr as u64);
|
||||
log::debug!("Kernel ptr: {:x}", ptr as u64);
|
||||
},
|
||||
|
||||
1 => unsafe {
|
||||
let page_count = msg_vec[1];
|
||||
|
||||
let mptr_raw: [u8; 8] = msg_vec[2..10].try_into().unwrap();
|
||||
let mptr: u64 = u64::from_le_bytes(mptr_raw);
|
||||
log::debug!("Deallocating {} pages @ {:x}", page_count, mptr);
|
||||
|
||||
dealloc(
|
||||
mptr as *mut u8,
|
||||
Layout::from_size_align_unchecked(page_count as usize * 4096, 8),
|
||||
)
|
||||
},
|
||||
2 => {
|
||||
use MemoryQuotaType::*;
|
||||
let quota_type = match msg_vec[1] {
|
||||
0 => NoQuota,
|
||||
1 => SoftQuota,
|
||||
2 => HardQuota,
|
||||
3 => KillQuota,
|
||||
_ => NoQuota,
|
||||
};
|
||||
let hid_raw: [u8; 8] = msg_vec[2..10].try_into().unwrap();
|
||||
let hid: u64 = u64::from_le_bytes(hid_raw);
|
||||
let pid_raw: [u8; 8] = msg_vec[10..18].try_into().unwrap();
|
||||
let pid: u64 = u64::from_le_bytes(pid_raw);
|
||||
debug!(
|
||||
"Setting HID-{:x}:PID-{:x}'s quota type to {:?}",
|
||||
hid, pid, quota_type
|
||||
)
|
||||
}
|
||||
3 => {
|
||||
let page_count = msg_vec[1];
|
||||
log::debug!(" {} pages", page_count);
|
||||
}
|
||||
4 => unsafe {
|
||||
let count = 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(())
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
use core::slice;
|
||||
|
||||
pub mod dt_msg_handler;
|
||||
pub mod logging_service;
|
||||
pub mod mem_serve;
|
||||
pub mod service_definition_service;
|
||||
|
||||
#[inline(always)]
|
||||
pub fn block_read<'a>(mem_addr: u64, length: usize) -> &'a mut [u8] {
|
||||
unsafe { slice::from_raw_parts_mut(mem_addr as *mut _, length) }
|
||||
}
|
|
@ -1,106 +0,0 @@
|
|||
use {
|
||||
crate::{
|
||||
arch::hardware_random_u64,
|
||||
holeybytes::{kernel_services::block_read, Vm},
|
||||
ipc::{buffer::IpcBuffer, protocol::Protocol},
|
||||
kmain::IPC_BUFFERS,
|
||||
},
|
||||
hashbrown::HashMap,
|
||||
log::{info, trace},
|
||||
spin::{lazy::Lazy, Mutex},
|
||||
};
|
||||
pub struct Services<'a>(HashMap<u64, Protocol<'a>>);
|
||||
pub static SERVICES: Lazy<Mutex<Services>> = Lazy::new(|| {
|
||||
let mut dt = Services(HashMap::new());
|
||||
dt.0.insert(0, Protocol::void());
|
||||
Mutex::new(dt)
|
||||
});
|
||||
#[derive(Debug)]
|
||||
pub enum ServiceError {
|
||||
InvalidFormat,
|
||||
}
|
||||
pub fn sds_msg_handler(vm: &mut Vm, mem_addr: u64, length: usize) -> Result<(), ServiceError> {
|
||||
let msg_vec = block_read(mem_addr, length);
|
||||
let sds_event_type: ServiceEventType = msg_vec[0].into();
|
||||
let strptr = u64::from_le_bytes(msg_vec[1..9].try_into().unwrap());
|
||||
let strlen = u64::from_le_bytes(msg_vec[9..17].try_into().unwrap()) as usize;
|
||||
let string_vec = block_read(strptr, strlen);
|
||||
let string = core::str::from_utf8(string_vec).expect("Our bytes should be valid utf8");
|
||||
|
||||
use ServiceEventType::*;
|
||||
match sds_event_type {
|
||||
CreateService => {
|
||||
let ret = sds_create_service(string);
|
||||
vm.registers[1] = hbvm::value::Value(ret as u64);
|
||||
}
|
||||
DeleteService => todo!(),
|
||||
SearchServices => {
|
||||
let ret = sds_search_service(string);
|
||||
vm.registers[1] = hbvm::value::Value(ret as u64);
|
||||
}
|
||||
}
|
||||
// let buffer_id_raw = &msg_vec[0..8];
|
||||
// let mut arr = [0u8; 8];
|
||||
// arr.copy_from_slice(&buffer_id_raw);
|
||||
// let buffer_id = u64::from_le_bytes(arr);
|
||||
// info!("BufferID({:x?})", buffer_id);
|
||||
|
||||
// let mut services = SERVICES.lock();
|
||||
// let string = String::from_utf8(msg_vec).expect("Our bytes should be valid utf8");
|
||||
// use core::borrow::BorrowMut;
|
||||
// services.borrow_mut().0.insert(buffer_id, string);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
enum ServiceEventType {
|
||||
CreateService = 0,
|
||||
// UpdateService = 1,
|
||||
DeleteService = 2,
|
||||
SearchServices = 3,
|
||||
}
|
||||
impl From<u8> for ServiceEventType {
|
||||
fn from(value: u8) -> Self {
|
||||
use self::*;
|
||||
match value {
|
||||
0 => Self::CreateService,
|
||||
// 1 =>
|
||||
2 => Self::DeleteService,
|
||||
3 => Self::SearchServices,
|
||||
10 => {
|
||||
info!("TEST");
|
||||
panic!()
|
||||
}
|
||||
1_u8 | 4_u8..=u8::MAX => todo!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn sds_create_service(protocol: &'static str) -> u64 {
|
||||
let buff_id = hardware_random_u64();
|
||||
let mut services = SERVICES.lock();
|
||||
let mut buffers = IPC_BUFFERS.lock();
|
||||
|
||||
let protocol_ = Protocol::from(protocol);
|
||||
let mut buff = IpcBuffer::new(false, 0);
|
||||
|
||||
services.0.insert(buff_id, protocol_.clone());
|
||||
buff.protocol = protocol_;
|
||||
buffers.insert(buff_id, buff);
|
||||
|
||||
trace!("BufferID({}) => {}", buff_id, protocol);
|
||||
// let a: protocol::Protocol = protocol.into();
|
||||
buff_id
|
||||
}
|
||||
pub fn sds_search_service(protocol: &str) -> u64 {
|
||||
let services = SERVICES.lock();
|
||||
let compare = Protocol::from(protocol);
|
||||
for (bid, protocol_canidate) in &services.0 {
|
||||
trace!("BID-{bid} protocol_canidate {:?}", protocol_canidate);
|
||||
if protocol_canidate == &compare {
|
||||
trace!("BufferID({}) => {}", bid, protocol);
|
||||
return *bid;
|
||||
}
|
||||
}
|
||||
0
|
||||
}
|
|
@ -1,68 +0,0 @@
|
|||
//! 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)
|
||||
//});
|
||||
}
|
||||
}
|
|
@ -1,111 +0,0 @@
|
|||
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()) }
|
||||
}
|
109
kernel/src/interp/host_functions.rs
Normal file
109
kernel/src/interp/host_functions.rs
Normal file
|
@ -0,0 +1,109 @@
|
|||
use {
|
||||
crate::interp::{HFIDT, TARGETS},
|
||||
alloc::string::String,
|
||||
log::trace,
|
||||
wasmi::{Caller, TypedFunc},
|
||||
};
|
||||
|
||||
use super::{HostState, WasmContext};
|
||||
|
||||
pub fn host_register_idt_handler(
|
||||
caller: Caller<'_, HostState>,
|
||||
interupt_number: i32,
|
||||
address_start: i32,
|
||||
length_of_string: i32,
|
||||
) -> i32 {
|
||||
// TODO: get the proc_id to address which function it is
|
||||
// TODO: Register the function name and proc_id into the idt handler
|
||||
|
||||
let mem = caller.get_export("memory").unwrap().into_memory().unwrap();
|
||||
let mem_array = mem.data(&caller);
|
||||
let mut name = String::new();
|
||||
for i in address_start..(address_start + length_of_string) {
|
||||
let ch = mem_array[i as usize] as char;
|
||||
name.push(ch);
|
||||
}
|
||||
|
||||
let index = interupt_number as usize;
|
||||
|
||||
let hf = HFIDT.lock();
|
||||
|
||||
// hf.insert(index);
|
||||
|
||||
trace!("{}", name);
|
||||
0
|
||||
}
|
||||
|
||||
use crate::{
|
||||
arch::hardware_random_u64,
|
||||
handle::GLOBALS,
|
||||
interp::{
|
||||
objects::{HandleTarget, Object},
|
||||
Handle,
|
||||
},
|
||||
};
|
||||
|
||||
pub fn host_make_object(
|
||||
mut caller: Caller<'_, HostState>,
|
||||
address_start: i32,
|
||||
length_of_string: i32,
|
||||
) -> i64 {
|
||||
trace!(
|
||||
"Called with addr {{ start {} length {} }}",
|
||||
address_start,
|
||||
length_of_string
|
||||
);
|
||||
let mem = caller.get_export("memory").unwrap().into_memory().unwrap();
|
||||
let mem_array = mem.data(&caller);
|
||||
let mut name = String::new();
|
||||
for i in address_start..(address_start + length_of_string) {
|
||||
let ch = mem_array[i as usize] as char;
|
||||
name.push(ch);
|
||||
}
|
||||
trace!("Object Name {}", name);
|
||||
let binding = TARGETS;
|
||||
let mut olock = binding.lock();
|
||||
let hand = Handle::new(olock.len());
|
||||
let obj = xml::XMLElement::new(name);
|
||||
|
||||
olock.push(Some(HandleTarget::Object(Object { xml: obj })));
|
||||
caller.data_mut().add_handle(hand).try_into().unwrap()
|
||||
}
|
||||
|
||||
pub type WFIDT = TypedFunc<(), ()>;
|
||||
|
||||
fn get_fn_from_wc(wc: WasmContext, function_name: String) -> WFIDT {
|
||||
wc.instance
|
||||
.get_typed_func(wc.store, &function_name)
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
pub fn host_make_global(mut caller: Caller<'_, HostState>, h: i64) -> (u64, u64, u64, u64) {
|
||||
let binding = GLOBALS;
|
||||
let Some(hand): Option<&mut Option<Handle>> = caller.data_mut().handles.get_mut(h as usize) else {
|
||||
return (0,0,0,0);
|
||||
};
|
||||
let Some(t) = hand.take() else {
|
||||
return (0,0,0,0);
|
||||
};
|
||||
let a = [hardware_random_u64(); 4];
|
||||
let mut l = binding.lock();
|
||||
l.insert(a, t);
|
||||
return (a[0], a[1], a[2], a[3]);
|
||||
}
|
||||
|
||||
pub fn host_take_global(mut caller: Caller<'_, HostState>, a: u64, b: u64, c: u64, d: u64) -> i64 {
|
||||
let binding = GLOBALS;
|
||||
let mut l = binding.lock();
|
||||
let mut j: [u64; 4] = [0u64; 4];
|
||||
j[0] = a;
|
||||
j[1] = b;
|
||||
j[2] = c;
|
||||
j[3] = d;
|
||||
let Some(m) = l.remove::<[u64; 4]>({
|
||||
&j
|
||||
}) else{
|
||||
return -1;
|
||||
};
|
||||
caller.data_mut().add_handle(m) as i64
|
||||
}
|
251
kernel/src/interp/mod.rs
Normal file
251
kernel/src/interp/mod.rs
Normal file
|
@ -0,0 +1,251 @@
|
|||
mod host_functions;
|
||||
pub mod objects;
|
||||
use {
|
||||
crate::{
|
||||
handle::{self, Handle},
|
||||
interp::{host_functions::host_make_object, objects::TARGETS},
|
||||
},
|
||||
alloc::{string::String, vec::Vec},
|
||||
hashbrown::HashMap,
|
||||
log::trace,
|
||||
spin::{Lazy, Mutex},
|
||||
wasmi::{Caller, Error, Func, Instance, Linker, Module, Store, TypedFunc},
|
||||
xml::XMLElement,
|
||||
};
|
||||
// Seperate use statement
|
||||
use {
|
||||
alloc::{fmt::format, format, vec},
|
||||
wasmi::Value,
|
||||
};
|
||||
|
||||
use self::objects::HandleTarget;
|
||||
|
||||
#[derive(Debug)]
|
||||
|
||||
pub struct WasmContext {
|
||||
pub proc_id: Option<u64>,
|
||||
pub instance: Instance,
|
||||
pub store: Store<HostState>,
|
||||
}
|
||||
|
||||
pub fn wasm() -> Result<(), wasmi::Error> {
|
||||
use wasmi::{Config, Engine};
|
||||
let mut conf = Config::default();
|
||||
conf.wasm_bulk_memory(true);
|
||||
// conf.,
|
||||
let engine = Engine::new(&conf);
|
||||
// trace!("Engine constructed");
|
||||
|
||||
// let wasm = include_bytes!("../../wasm_syscall_test.wasm");
|
||||
let wasm = include_bytes!("../../../test.wasm");
|
||||
|
||||
// trace!("Loading WASM binary");
|
||||
let module = Module::new(&engine, &wasm[..]).unwrap();
|
||||
// trace!("Constructing wasm module");
|
||||
let hs = HostState { handles: vec![] };
|
||||
let mut store = Store::new(&engine, hs);
|
||||
// trace!("constructing host store");
|
||||
|
||||
let read_mem_addr = Func::wrap(
|
||||
&mut store,
|
||||
|caller: Caller<'_, HostState>, param: i32| -> i32 { read_memory_address(caller, param) },
|
||||
);
|
||||
|
||||
let mut linker = <Linker<HostState>>::new(&engine);
|
||||
|
||||
linker.define(
|
||||
"host",
|
||||
"read_mem_addr",
|
||||
Func::wrap(
|
||||
&mut store,
|
||||
|caller: Caller<'_, HostState>, param: i32| -> i32 {
|
||||
read_memory_address(caller, param)
|
||||
},
|
||||
),
|
||||
)?;
|
||||
|
||||
linker.define(
|
||||
"host",
|
||||
"register_idt_handler",
|
||||
Func::wrap(&mut store, host_functions::host_register_idt_handler),
|
||||
)?;
|
||||
|
||||
linker.define(
|
||||
"host",
|
||||
"read_object_attribute",
|
||||
Func::wrap(&mut store, host_read_object_attribute),
|
||||
)?;
|
||||
|
||||
linker.define(
|
||||
"host",
|
||||
"create_object",
|
||||
Func::wrap(&mut store, host_make_object),
|
||||
)?;
|
||||
|
||||
let instance = linker
|
||||
.instantiate(&mut store, &module)?
|
||||
.ensure_no_start(&mut store)?;
|
||||
|
||||
let version = instance.get_global(&store, "VERSION");
|
||||
|
||||
// trace!("Version: {:?}", version);
|
||||
let hello = instance.get_typed_func::<(), i64>(&store, "start")?;
|
||||
|
||||
let ret = hello.call(&mut store, ())?;
|
||||
trace!("Called start got return of {:?}", ret);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct HostState {
|
||||
handles: Vec<Option<Handle>>,
|
||||
}
|
||||
|
||||
impl HostState {
|
||||
pub fn add_handle(&mut self, hand: Handle) -> usize {
|
||||
for (i, h) in self.handles.iter_mut().enumerate() {
|
||||
if let None = h {
|
||||
*h = Some(hand);
|
||||
return i;
|
||||
}
|
||||
}
|
||||
self.handles.push(Some(hand));
|
||||
return (self.handles.len() - 1);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read_memory_address(caller: Caller<'_, HostState>, address: i32) -> i32 {
|
||||
trace!("Address: {}", address);
|
||||
// let obj = host_make_object(caller, 16, 23);
|
||||
0
|
||||
}
|
||||
|
||||
pub fn host_read_object_attribute(
|
||||
mut caller: Caller<'_, HostState>,
|
||||
handle: i64,
|
||||
address_start: i32,
|
||||
length_of_string: i32,
|
||||
) -> (i32, i32) {
|
||||
let binding = TARGETS;
|
||||
let mut olock = binding.lock();
|
||||
|
||||
// olock.get(&handle);
|
||||
|
||||
let mem = caller.get_export("memory").unwrap().into_memory().unwrap();
|
||||
let mem_array = mem.data_mut(&mut caller);
|
||||
let mut name = String::new();
|
||||
for i in address_start..(address_start + length_of_string) {
|
||||
let ch = mem_array[i as usize] as char;
|
||||
name.push(ch);
|
||||
}
|
||||
let Some(Some(a)) = caller.data().handles.get(handle as usize) else {
|
||||
return (0,0);
|
||||
};
|
||||
let Some(Some(HandleTarget::Object(o))) = olock.get(a.r#ref) else{
|
||||
return (0,0);
|
||||
};
|
||||
let Some(r) = o.xml.attributes.iter().find(|a|{
|
||||
let f = format!("{:?}",a);
|
||||
f.contains(&format!("Attribute{{ name: \"{}",name))
|
||||
})else{
|
||||
return (0,0);
|
||||
};
|
||||
let f = format!("{:?}", r);
|
||||
let p = format!("Attribute{{ name: \"{}\", value: \"", name);
|
||||
let s = format!("\" }}");
|
||||
let h = f.replace(&p, "").replace(&s, "");
|
||||
|
||||
let i = vec![Value::I32(h.len().try_into().unwrap())];
|
||||
let mut o = vec![Value::I32(0)];
|
||||
|
||||
let a = caller
|
||||
.get_export("malloc")
|
||||
.unwrap()
|
||||
.into_func()
|
||||
.unwrap()
|
||||
.call(&mut caller, &i, &mut o);
|
||||
let mem_array = mem.data_mut(&mut caller);
|
||||
|
||||
let Value::I32(a) = o[0] else{
|
||||
panic!("invalid malloc");
|
||||
};
|
||||
|
||||
for (s, b) in h.clone().into_bytes().iter().enumerate() {
|
||||
mem_array[(a as usize) + s] = *b;
|
||||
}
|
||||
|
||||
(a, h.len().try_into().unwrap())
|
||||
}
|
||||
|
||||
pub fn build_wasm_context(bytes: Vec<u8>) -> Result<WasmContext, wasmi::Error> {
|
||||
use wasmi::{Config, Engine};
|
||||
let mut conf = Config::default();
|
||||
conf.wasm_bulk_memory(true);
|
||||
// conf.,
|
||||
let engine = Engine::new(&conf);
|
||||
// trace!("Engine constructed");
|
||||
|
||||
// let wasm = include_bytes!("../../wasm_syscall_test.wasm");
|
||||
let wasm = include_bytes!("../../../test.wasm");
|
||||
|
||||
// trace!("Loading WASM binary");
|
||||
let module = Module::new(&engine, &wasm[..]).unwrap();
|
||||
// trace!("Constructing wasm module");
|
||||
let hs = HostState { handles: vec![] };
|
||||
let mut store = Store::new(&engine, hs);
|
||||
// trace!("constructing host store");
|
||||
|
||||
let read_mem_addr = Func::wrap(
|
||||
&mut store,
|
||||
|caller: Caller<'_, HostState>, param: i32| -> i32 { read_memory_address(caller, param) },
|
||||
);
|
||||
|
||||
let mut linker = <Linker<HostState>>::new(&engine);
|
||||
linker.define(
|
||||
"host",
|
||||
"read_mem_addr",
|
||||
Func::wrap(
|
||||
&mut store,
|
||||
|caller: Caller<'_, HostState>, param: i32| -> i32 {
|
||||
read_memory_address(caller, param)
|
||||
},
|
||||
),
|
||||
)?;
|
||||
|
||||
linker.define(
|
||||
"host",
|
||||
"read_object_attribute",
|
||||
Func::wrap(&mut store, host_read_object_attribute),
|
||||
)?;
|
||||
|
||||
linker.define(
|
||||
"host",
|
||||
"create_object",
|
||||
Func::wrap(&mut store, host_make_object),
|
||||
)?;
|
||||
|
||||
let instance = linker
|
||||
.instantiate(&mut store, &module)?
|
||||
.ensure_no_start(&mut store)?;
|
||||
|
||||
let wc = WasmContext {
|
||||
instance,
|
||||
store,
|
||||
proc_id: None,
|
||||
};
|
||||
|
||||
Ok(wc)
|
||||
}
|
||||
|
||||
pub type HostFunctionIDT = HashMap<usize, WCFunction>;
|
||||
pub struct WCFunction {
|
||||
wc: WasmContext,
|
||||
function: TypedFunc<(), ()>,
|
||||
}
|
||||
|
||||
pub static HFIDT: Lazy<Mutex<HostFunctionIDT>> = Lazy::new(|| {
|
||||
let mut hfidt = HashMap::new();
|
||||
|
||||
Mutex::new(hfidt)
|
||||
});
|
19
kernel/src/interp/objects.rs
Normal file
19
kernel/src/interp/objects.rs
Normal file
|
@ -0,0 +1,19 @@
|
|||
use alloc::{vec, vec::Vec, collections::BTreeMap};
|
||||
|
||||
use spin::{Lazy, Mutex};
|
||||
|
||||
use crate::handle::Handle;
|
||||
|
||||
pub struct Object{
|
||||
pub xml: xml::XMLElement
|
||||
}
|
||||
pub enum HandleTarget{
|
||||
Object(Object)
|
||||
}
|
||||
|
||||
pub type HostTargets = Vec<Option<HandleTarget>>;
|
||||
|
||||
pub const TARGETS: Lazy<Mutex<HostTargets>> = Lazy::new(|| {
|
||||
let mut obj = vec![];
|
||||
Mutex::new(obj)
|
||||
});
|
|
@ -1,72 +0,0 @@
|
|||
//!
|
||||
|
||||
use {
|
||||
super::{message::Message, protocol::Protocol},
|
||||
crossbeam_queue::{ArrayQueue, SegQueue},
|
||||
};
|
||||
pub enum BufferTypes {
|
||||
Unbound(SegQueue<Message>),
|
||||
Bound(ArrayQueue<Message>),
|
||||
}
|
||||
/// Interproccess buffer
|
||||
pub struct IpcBuffer<'a> {
|
||||
pub protocol: Protocol<'a>,
|
||||
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,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Validate a message to match the `IPC.protocol`
|
||||
pub fn validate_messages(&mut self) -> Result<(), IpcError> {
|
||||
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
|
||||
#[derive(Debug)]
|
||||
pub enum IpcError {
|
||||
/// An invalid message error returned to the sender
|
||||
InvalidMessage,
|
||||
NoMessagesInBuffer,
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
//! An ipc message structured in a nice convenient way
|
||||
|
||||
use alloc::vec::Vec;
|
||||
|
||||
/// TODO: Extend this into a full structure
|
||||
/// DEPEND: This depends on an IDL
|
||||
pub type Message = Vec<u8>;
|
|
@ -1,4 +0,0 @@
|
|||
//! Interprocess communication
|
||||
pub mod buffer;
|
||||
pub mod message;
|
||||
pub mod protocol;
|
|
@ -1,36 +0,0 @@
|
|||
use {alloc::vec::Vec, hashbrown::HashMap};
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
pub struct Type {}
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
pub struct Funct<'a> {
|
||||
takes: Vec<&'a str>,
|
||||
gives: Vec<&'a str>,
|
||||
}
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
pub struct Protocol<'a> {
|
||||
types: HashMap<&'a str, Type>,
|
||||
fns: HashMap<&'a str, Funct<'a>>,
|
||||
}
|
||||
impl<'a> Protocol<'a> {
|
||||
pub fn void() -> Self {
|
||||
Self {
|
||||
types: HashMap::new(),
|
||||
fns: HashMap::new(),
|
||||
}
|
||||
}
|
||||
// Check if a protocol defines all types it needs too
|
||||
fn validate_protocol() -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a str> for Protocol<'a> {
|
||||
fn from(value: &'a str) -> Self {
|
||||
let mut hm_t = HashMap::new();
|
||||
hm_t.insert(value, Type {});
|
||||
Self {
|
||||
types: hm_t,
|
||||
fns: HashMap::new(),
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,162 +1,65 @@
|
|||
//! AbleOS Kernel Entrypoint
|
||||
|
||||
use {
|
||||
crate::{
|
||||
arch::hardware_random_u64,
|
||||
bootmodules::BootModules,
|
||||
//bootmodules::build_cmd,
|
||||
device_tree::DeviceTree,
|
||||
holeybytes::ExecThread,
|
||||
ipc::buffer::IpcBuffer,
|
||||
task::Executor,
|
||||
},
|
||||
alloc::boxed::Box,
|
||||
core::cell::LazyCell,
|
||||
hashbrown::HashMap,
|
||||
hbvm::mem::Address,
|
||||
limine::{Framebuffer, FramebufferRequest, NonNullPtr},
|
||||
log::{debug, error, trace},
|
||||
spin::{Lazy, Mutex},
|
||||
};
|
||||
// use std::collections::HashMap;
|
||||
|
||||
pub fn kmain(_cmdline: &str, boot_modules: BootModules) -> ! {
|
||||
debug!("Entered kmain");
|
||||
use alloc::vec::Vec;
|
||||
use log::{info, trace};
|
||||
use spin::{Lazy, Mutex};
|
||||
|
||||
#[cfg(feature = "ktest")]
|
||||
{
|
||||
use {
|
||||
crate::ktest,
|
||||
log::info,
|
||||
};
|
||||
info!("Running tests");
|
||||
ktest::test_main();
|
||||
use crate::arch::{hardware_random_u64, sloop};
|
||||
use crate::handle::Handle;
|
||||
use crate::schedule::Scheduler;
|
||||
use crate::{interp, task};
|
||||
|
||||
loop {}
|
||||
}
|
||||
use crate::alloc::string::ToString;
|
||||
|
||||
// let kcmd = build_cmd("Kernel Command Line", cmdline);
|
||||
// trace!("Cmdline: {kcmd:?}");
|
||||
pub fn kmain(cmdline: &str, bootstrap: Option<&'static [u8]>) -> ! {
|
||||
log::debug!("Entered kmain");
|
||||
|
||||
// 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 mut cmdline = cmdline.to_string();
|
||||
cmdline.pop();
|
||||
cmdline.remove(0);
|
||||
|
||||
let kcmd = clparse::Arguments::parse(cmdline.to_string()).unwrap();
|
||||
log::info!("Cmdline: {kcmd:?}");
|
||||
|
||||
// if kcmd.arguments.get("baka") == Some(&"true".to_string()) {
|
||||
// let _ = crate::arch::log(format_args!(include_str!("../data/⑨. バカ")));
|
||||
// }
|
||||
|
||||
let dt = DEVICE_TREE.lock();
|
||||
// if kcmd.arguments.get("foobles") == Some(&"true".to_string()) {
|
||||
// let _ = crate::arch::log(format_args!("foobles\n"));
|
||||
// }
|
||||
|
||||
// TODO(Able): This line causes a deadlock
|
||||
debug!("Device Tree: {}", dt);
|
||||
|
||||
trace!("Boot complete. Moving to init_system");
|
||||
|
||||
// TODO: schedule the disk 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
|
||||
|
||||
drop(dt);
|
||||
|
||||
let fb1: &NonNullPtr<Framebuffer> = &FB_REQ.get_response().get().unwrap().framebuffers()[0];
|
||||
|
||||
{
|
||||
let mut dt = DEVICE_TREE.lock();
|
||||
let mut disp = xml::XMLElement::new("display_0");
|
||||
|
||||
disp.set_attribute("width", fb1.width);
|
||||
disp.set_attribute("height", fb1.height);
|
||||
disp.set_attribute("bpp", fb1.bpp);
|
||||
disp.set_attribute("pitch", fb1.pitch);
|
||||
dt.devices.insert("Displays", alloc::vec![disp]);
|
||||
let bootstrap = bootstrap/*.expect("no bootstrap found")*/;
|
||||
match bootstrap {
|
||||
Some(bootstrap_mod) => {}
|
||||
None => {
|
||||
info!("No bootstrap module loaded.")
|
||||
}
|
||||
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;
|
||||
};
|
||||
// use xml::XMLElement;
|
||||
// let kcmd = XMLElement::new("cmdline");
|
||||
// let hnd = Handle::new();
|
||||
// kcmd.set_attribute("")
|
||||
// OBJECTS.lock().insert(hnd, kcmd);
|
||||
|
||||
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 abc = interp::wasm();
|
||||
|
||||
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:?}");
|
||||
}
|
||||
}));
|
||||
}
|
||||
trace!("{:?}", abc);
|
||||
|
||||
debug!("Random number: {}", hardware_random_u64());
|
||||
// let sch = SCHEDULER;
|
||||
// let mut sch = sch.lock();
|
||||
// let wc = interp::build_wasm_context(alloc::vec::Vec::new()).unwrap();
|
||||
// sch.schedule(wc, crate::schedule::ContextWake::None);
|
||||
|
||||
executor.run();
|
||||
};
|
||||
crate::arch::spin_loop()
|
||||
// sch.run();
|
||||
|
||||
crate::arch::sloop()
|
||||
}
|
||||
|
||||
// ! SAFETY: this is not threadsafe at all, like even a little bit.
|
||||
// ! SERIOUSLY
|
||||
pub static mut EXECUTOR: LazyCell<Executor> = LazyCell::new(|| Executor::new());
|
||||
|
||||
pub static DEVICE_TREE: Lazy<Mutex<DeviceTree>> = Lazy::new(|| {
|
||||
let dt = DeviceTree::new();
|
||||
Mutex::new(dt)
|
||||
});
|
||||
pub static FB_REQ: FramebufferRequest = FramebufferRequest::new(0);
|
||||
|
||||
pub type IpcBuffers<'a> = HashMap<u64, IpcBuffer<'a>>;
|
||||
pub static IPC_BUFFERS: Lazy<Mutex<IpcBuffers>> = Lazy::new(|| {
|
||||
let mut bufs = HashMap::new();
|
||||
let log_buffer = IpcBuffer::new(false, 0);
|
||||
let file_buffer = IpcBuffer::new(false, 0);
|
||||
|
||||
bufs.insert(1, log_buffer);
|
||||
bufs.insert(2, file_buffer);
|
||||
|
||||
Mutex::new(bufs)
|
||||
pub const SCHEDULER: Lazy<Mutex<Scheduler>> = Lazy::new(|| {
|
||||
let mut sch = Scheduler::new();
|
||||
Mutex::new(sch)
|
||||
});
|
||||
|
|
|
@ -1,51 +0,0 @@
|
|||
pub use ktest_macro::*;
|
||||
|
||||
use {
|
||||
alloc::string::String,
|
||||
log::{error, info},
|
||||
};
|
||||
|
||||
extern "C" {
|
||||
static __ktest_start: fn() -> Result<String, String>;
|
||||
static __ktest_end: fn() -> Result<String, String>;
|
||||
}
|
||||
|
||||
// TODO: Implement ktest for arm and riscv (Later problems, see below)
|
||||
// Allow for arch specific tests (Leave for now)
|
||||
// Should panic tests
|
||||
// Test specific panic handler
|
||||
pub fn test_main() {
|
||||
unsafe {
|
||||
let mut current_test = &__ktest_start as *const fn() -> Result<String, String>;
|
||||
let test_end = &__ktest_end as *const fn() -> Result<String, String>;
|
||||
|
||||
let mut pass = 0;
|
||||
let mut fail = 0;
|
||||
|
||||
while current_test < test_end {
|
||||
let test_fn = *current_test;
|
||||
|
||||
let test_name = test_fn();
|
||||
match test_name {
|
||||
Ok(name) => {
|
||||
info!("Test: {} passed", name);
|
||||
pass += 1;
|
||||
},
|
||||
Err(name) => {
|
||||
error!("Test: {} failed", name);
|
||||
fail += 1;
|
||||
}
|
||||
}
|
||||
|
||||
current_test = current_test.add(1);
|
||||
}
|
||||
|
||||
info!("{}/{} tests passed", pass, pass + fail);
|
||||
}
|
||||
}
|
||||
|
||||
#[ktest]
|
||||
pub fn trivial_assertion() {
|
||||
ktest_eq!(1, 1);
|
||||
ktest_neq!(0, 1);
|
||||
}
|
|
@ -1,41 +1,28 @@
|
|||
//! The ableOS kernel.
|
||||
//! Named akern.
|
||||
//! Akern is woefully undersupported at the moment but we are looking to add support improve hardware discovery and make our lives as kernel and operating system developers easier and better
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
#![feature(
|
||||
slice_split_once,
|
||||
exclusive_wrapper,
|
||||
core_intrinsics,
|
||||
abi_x86_interrupt,
|
||||
lazy_get,
|
||||
alloc_error_handler,
|
||||
local_waker,
|
||||
context_ext,
|
||||
ptr_sub_ptr,
|
||||
naked_functions,
|
||||
pointer_is_aligned_to
|
||||
inline_const,
|
||||
panic_info_message,
|
||||
pointer_is_aligned,
|
||||
prelude_import,
|
||||
ptr_sub_ptr
|
||||
)]
|
||||
#![allow(dead_code, internal_features, static_mut_refs)]
|
||||
#![no_std]
|
||||
// #![deny(missing_docs)]
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
mod allocator;
|
||||
mod arch;
|
||||
mod bootmodules;
|
||||
mod capabilities;
|
||||
mod device_tree;
|
||||
mod exe_format;
|
||||
mod handle;
|
||||
mod holeybytes;
|
||||
mod ipc;
|
||||
pub mod handle;
|
||||
pub mod interp;
|
||||
mod kmain;
|
||||
mod logger;
|
||||
mod memory;
|
||||
mod schedule;
|
||||
mod task;
|
||||
mod utils;
|
||||
|
||||
#[allow(improper_ctypes, non_upper_case_globals)]
|
||||
mod ktest;
|
||||
|
||||
use versioning::Version;
|
||||
|
||||
|
@ -47,11 +34,7 @@ pub const VERSION: Version = Version {
|
|||
};
|
||||
|
||||
#[panic_handler]
|
||||
#[cfg(target_os = "none")]
|
||||
fn panic(info: &core::panic::PanicInfo) -> ! {
|
||||
use alloc::string::ToString;
|
||||
arch::register_dump();
|
||||
|
||||
if let Some(loc) = info.location() {
|
||||
let _ = crate::arch::log(format_args!(
|
||||
"Location: {}: {}, {}\r\n",
|
||||
|
@ -61,7 +44,9 @@ fn panic(info: &core::panic::PanicInfo) -> ! {
|
|||
));
|
||||
}
|
||||
|
||||
let msg = info.message().to_string().replace("\n", "\r\n");
|
||||
if let Some(msg) = info.message() {
|
||||
let _ = crate::arch::log(format_args!("{msg}\r\n"));
|
||||
}
|
||||
|
||||
loop {}
|
||||
}
|
||||
|
|
|
@ -1,87 +1,33 @@
|
|||
#![allow(deprecated)]
|
||||
// TODO: Add a logger api with logger levels and various outputs
|
||||
pub static TERMINAL_LOGGER: Lazy<Mutex<TermLogger>> = Lazy::new(|| Mutex::new(TermLogger::new()));
|
||||
|
||||
use {
|
||||
limine::{TerminalRequest, TerminalResponse},
|
||||
log::{Level, SetLoggerError},
|
||||
spin::{lazy::Lazy, mutex::Mutex},
|
||||
};
|
||||
use log::{Level, SetLoggerError};
|
||||
|
||||
pub fn init() -> Result<(), SetLoggerError> {
|
||||
log::set_logger(&crate::logger::Logger)?;
|
||||
if cfg!(debug_assertions) {
|
||||
log::set_max_level(log::LevelFilter::Debug);
|
||||
} else {
|
||||
log::set_max_level(log::LevelFilter::Info);
|
||||
}
|
||||
|
||||
Lazy::force(&TERMINAL_LOGGER);
|
||||
|
||||
log::set_max_level(log::LevelFilter::Trace);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
struct Logger;
|
||||
impl log::Log for Logger {
|
||||
fn enabled(&self, _metadata: &log::Metadata) -> bool {
|
||||
fn enabled(&self, metadata: &log::Metadata) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn log(&self, record: &log::Record) {
|
||||
let lvl = record.level();
|
||||
let lvl_color = match lvl {
|
||||
crate::arch::log(format_args!(
|
||||
"\x1b[38;5;{}m{lvl}\x1b[0m [{}]: {}\r\n",
|
||||
match lvl {
|
||||
Level::Error => "160",
|
||||
Level::Warn => "172",
|
||||
Level::Info => "47",
|
||||
Level::Debug => "25",
|
||||
Level::Trace => "103",
|
||||
};
|
||||
let module = record
|
||||
.module_path()
|
||||
.unwrap_or_default()
|
||||
.rsplit_once(':')
|
||||
.unwrap_or_default()
|
||||
.1;
|
||||
if module == "" {
|
||||
crate::arch::log(format_args!(
|
||||
"\x1b[38;5;{lvl_color}m{lvl}\x1b[0m: {}\r\n",
|
||||
},
|
||||
record.module_path().unwrap_or_default(),
|
||||
record.args(),
|
||||
))
|
||||
.expect("write to serial console");
|
||||
} else {
|
||||
let line = record.line().unwrap_or_default();
|
||||
crate::arch::log(format_args!(
|
||||
"\x1b[38;5;{lvl_color}m{lvl}\x1b[0m [{module}:{line}]: {}\r\n",
|
||||
record.args(),
|
||||
))
|
||||
.expect("write to serial console");
|
||||
}
|
||||
}
|
||||
|
||||
fn flush(&self) {}
|
||||
}
|
||||
|
||||
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,6 +1,7 @@
|
|||
//! The Memory Manager
|
||||
|
||||
use {alloc::collections::VecDeque, derive_more::*};
|
||||
use alloc::collections::VecDeque;
|
||||
use derive_more::*;
|
||||
|
||||
pub use crate::arch::PAGE_SIZE;
|
||||
pub const MAX_ORDER: usize = 10;
|
||||
|
@ -43,7 +44,7 @@ pub const MAX_ORDER: usize = 10;
|
|||
Sum,
|
||||
UpperHex,
|
||||
)]
|
||||
#[display("0x{:x}", _0)]
|
||||
#[display(fmt = "0x{:x}", _0)]
|
||||
#[from(forward)]
|
||||
pub struct VirtualAddress(usize);
|
||||
|
||||
|
@ -54,11 +55,11 @@ impl VirtualAddress {
|
|||
pub fn vpns(&self) -> [usize; 3] {
|
||||
[
|
||||
// [20:12]
|
||||
(self.0 >> 12) & 0x1FF,
|
||||
(self.0 >> 12) & 0x1ff,
|
||||
// [29:21]
|
||||
(self.0 >> 21) & 0x1FF,
|
||||
(self.0 >> 21) & 0x1ff,
|
||||
// [38:30]
|
||||
(self.0 >> 30) & 0x1FF,
|
||||
(self.0 >> 30) & 0x1ff,
|
||||
]
|
||||
}
|
||||
|
||||
|
@ -113,7 +114,7 @@ impl VirtualAddress {
|
|||
Sum,
|
||||
UpperHex,
|
||||
)]
|
||||
#[display("0x{:x}", _0)]
|
||||
#[display(fmt = "0x{:x}", _0)]
|
||||
#[from(forward)]
|
||||
pub struct PhysicalAddress(usize);
|
||||
|
||||
|
@ -124,11 +125,11 @@ impl PhysicalAddress {
|
|||
pub fn ppns(&self) -> [usize; 3] {
|
||||
[
|
||||
// [20:12]
|
||||
(self.0 >> 12) & 0x1FF,
|
||||
(self.0 >> 12) & 0x1ff,
|
||||
// [29:21]
|
||||
(self.0 >> 21) & 0x1FF,
|
||||
(self.0 >> 21) & 0x1ff,
|
||||
// [55:30]
|
||||
(self.0 >> 30) & 0x3FFFFFF,
|
||||
(self.0 >> 30) & 0x3ffffff,
|
||||
]
|
||||
}
|
||||
|
||||
|
|
104
kernel/src/schedule.rs
Normal file
104
kernel/src/schedule.rs
Normal file
|
@ -0,0 +1,104 @@
|
|||
use core::arch;
|
||||
|
||||
// WasmContext
|
||||
use crate::{arch::sloop, interp::WasmContext};
|
||||
use alloc::vec::Vec;
|
||||
use log::trace;
|
||||
|
||||
pub type ProcId = u64;
|
||||
|
||||
pub struct Scheduler {
|
||||
running: Vec<WasmContext>,
|
||||
halted: Vec<(ContextWake, WasmContext)>,
|
||||
// time_halt: Vec<(ContextWake, WasmContext)>,
|
||||
next_proc_id: ProcId,
|
||||
}
|
||||
|
||||
impl Scheduler {
|
||||
pub fn new() -> Scheduler {
|
||||
Self {
|
||||
running: Vec::new(),
|
||||
halted: Vec::new(),
|
||||
// time_halt: Vec::new(),
|
||||
next_proc_id: 0,
|
||||
}
|
||||
}
|
||||
pub fn run(&mut self) -> ! {
|
||||
loop {
|
||||
let proc = self.running.pop();
|
||||
|
||||
// self.time_halt.sort();
|
||||
|
||||
match proc {
|
||||
Some(proc) => {
|
||||
// trace!("SWAP WasmContext");
|
||||
self.running.push(proc);
|
||||
}
|
||||
|
||||
None => {
|
||||
panic!("nothing scheduled.");
|
||||
sloop();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
fn sleep_inner(&self, id: ProcId) -> Result<usize, SchedulerError> {
|
||||
let proc_len = self.running.len();
|
||||
let mut proc_found = true;
|
||||
let mut sleep_index = 0;
|
||||
let mut i = 0;
|
||||
for wc in &self.running {
|
||||
if wc.proc_id == Some(id) {
|
||||
sleep_index = i;
|
||||
proc_found = true;
|
||||
break;
|
||||
}
|
||||
if i == proc_len {
|
||||
proc_found = false;
|
||||
trace!("no process with ID {} found", id);
|
||||
return Err(SchedulerError::ProcessIDNotFound(id));
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
|
||||
Ok(sleep_index)
|
||||
}
|
||||
pub fn sleep(&mut self, id: ProcId, time: u64) -> Result<(), SchedulerError> {
|
||||
match self.sleep_inner(id) {
|
||||
Ok(sid) => self
|
||||
.halted
|
||||
.push((ContextWake::Time(time), self.running.remove(sid))),
|
||||
Err(error) => return Err(error),
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn schedule(&mut self, wc: WasmContext, cw: ContextWake) -> Result<(), SchedulerError> {
|
||||
if wc.proc_id != None {
|
||||
panic!("Already Scheduled with PROC_ID {}", wc.proc_id.unwrap());
|
||||
}
|
||||
trace!("Scheduling WC with ProcID {}", self.next_proc_id);
|
||||
|
||||
if cw == ContextWake::None {
|
||||
self.running.push(wc)
|
||||
} else {
|
||||
self.halted.push((cw, wc));
|
||||
}
|
||||
|
||||
self.next_proc_id += 1;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
#[derive(PartialEq)]
|
||||
pub enum ContextWake {
|
||||
/// Used when spawning a new process to have it instantly start
|
||||
None,
|
||||
Time(u64),
|
||||
ObjectEvent,
|
||||
}
|
||||
|
||||
pub enum SchedulerError {
|
||||
ProcessIDNotFound(ProcId),
|
||||
AlreadyScheduled(),
|
||||
}
|
|
@ -1,19 +1,29 @@
|
|||
use {
|
||||
alloc::{
|
||||
boxed::Box,
|
||||
collections::{BTreeMap, BTreeSet},
|
||||
sync::Arc,
|
||||
},
|
||||
core::{
|
||||
//! Async task and executor
|
||||
|
||||
use alloc::{boxed::Box, collections::BTreeMap, sync::Arc, task::Wake};
|
||||
use core::{
|
||||
future::Future,
|
||||
pin::Pin,
|
||||
sync::atomic::{AtomicBool, Ordering},
|
||||
task::{Context, ContextBuilder, Poll, RawWaker, RawWakerVTable, Waker},
|
||||
},
|
||||
crossbeam_queue::SegQueue,
|
||||
slab::Slab,
|
||||
task::{Context, Poll, Waker},
|
||||
};
|
||||
use crossbeam_queue::SegQueue;
|
||||
use slab::Slab;
|
||||
use spin::RwLock;
|
||||
|
||||
type TaskQueue = Arc<SegQueue<TaskId>>;
|
||||
type SpawnQueue = Arc<SegQueue<Task>>;
|
||||
|
||||
static SPAWN_QUEUE: RwLock<Option<SpawnQueue>> = RwLock::new(None);
|
||||
|
||||
/// Spawn a new task
|
||||
pub fn spawn(future: impl Future<Output = ()> + Send + 'static) {
|
||||
match &*SPAWN_QUEUE.read() {
|
||||
Some(s) => s.push(Task::new(future)),
|
||||
None => panic!("no task executor is running"),
|
||||
}
|
||||
}
|
||||
|
||||
/// Forcibly yield a task
|
||||
pub fn yield_now() -> impl Future<Output = ()> {
|
||||
struct YieldNow(bool);
|
||||
impl Future for YieldNow {
|
||||
|
@ -33,184 +43,107 @@ pub fn yield_now() -> impl Future<Output = ()> {
|
|||
YieldNow(false)
|
||||
}
|
||||
|
||||
pub trait Process: Future<Output = ()> + Send {}
|
||||
impl<T: Future<Output = ()> + Send> Process for T {}
|
||||
|
||||
/// Tasks executor
|
||||
#[derive(Default)]
|
||||
pub struct Executor {
|
||||
/// All spawned tasks' stash
|
||||
tasks: Slab<Task>,
|
||||
task_queue: Arc<SegQueue<usize>>,
|
||||
interrupt_lookup: [Option<usize>; u8::MAX as usize],
|
||||
buffer_lookup: BTreeMap<usize, BTreeSet<usize>>,
|
||||
|
||||
/// Awake tasks' queue
|
||||
queue: TaskQueue,
|
||||
|
||||
/// Incoming tasks to enqueue
|
||||
incoming: SpawnQueue,
|
||||
|
||||
/// Wakers
|
||||
wakers: BTreeMap<TaskId, Waker>,
|
||||
}
|
||||
|
||||
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]));
|
||||
}
|
||||
/// Spawn a task
|
||||
pub fn spawn(&mut self, future: impl Future<Output = ()> + Send + 'static) {
|
||||
self.queue
|
||||
.push(TaskId(self.tasks.insert(Task::new(future))));
|
||||
}
|
||||
|
||||
/// Spin poll loop until it runs out of tasks
|
||||
pub fn run(&mut self) {
|
||||
let mut task_batch = [0; 32];
|
||||
loop {
|
||||
let mut batch_len = 0;
|
||||
// Assign `self.incoming` to global spawn queue to spawn tasks
|
||||
// from within
|
||||
{
|
||||
let mut spawner = SPAWN_QUEUE.write();
|
||||
if spawner.is_some() {
|
||||
panic!("task executor is already running");
|
||||
}
|
||||
|
||||
while let Some(id) = self.task_queue.pop() {
|
||||
task_batch[batch_len] = id;
|
||||
batch_len += 1;
|
||||
if batch_len == task_batch.len() {
|
||||
break;
|
||||
*spawner = Some(Arc::clone(&self.incoming));
|
||||
}
|
||||
|
||||
// Try to get incoming task, if none available, poll
|
||||
// enqueued one
|
||||
while let Some(id) = self
|
||||
.incoming
|
||||
.pop()
|
||||
.map(|t| TaskId(self.tasks.insert(t)))
|
||||
.or_else(|| self.queue.pop())
|
||||
{
|
||||
let Some(task) = self.tasks.get_mut(id.0) else {
|
||||
panic!("attempted to get non-extant task with id {}", id.0)
|
||||
};
|
||||
|
||||
let mut cx = Context::from_waker(self.wakers.entry(id).or_insert_with(|| {
|
||||
Waker::from(Arc::new(TaskWaker {
|
||||
id,
|
||||
queue: Arc::clone(&self.queue),
|
||||
}))
|
||||
}));
|
||||
|
||||
match task.poll(&mut cx) {
|
||||
Poll::Ready(()) => {
|
||||
// Task done, unregister
|
||||
self.tasks.remove(id.0);
|
||||
self.wakers.remove(&id);
|
||||
}
|
||||
Poll::Pending => (),
|
||||
}
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
*SPAWN_QUEUE.write() = None;
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||
struct TaskId(usize);
|
||||
|
||||
/// Async task
|
||||
struct Task {
|
||||
future: Pin<Box<dyn Process>>,
|
||||
paused: AtomicBool,
|
||||
future: Pin<Box<dyn Future<Output = ()> + Send>>,
|
||||
}
|
||||
|
||||
impl Task {
|
||||
fn new(future: Pin<Box<dyn Process>>) -> Self {
|
||||
/// Create a new task from a future
|
||||
fn new(future: impl Future<Output = ()> + Send + 'static) -> Self {
|
||||
Self {
|
||||
future,
|
||||
paused: AtomicBool::new(false),
|
||||
future: Box::pin(future),
|
||||
}
|
||||
}
|
||||
|
||||
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>>,
|
||||
id: TaskId,
|
||||
queue: TaskQueue,
|
||||
}
|
||||
|
||||
impl TaskWaker {
|
||||
fn wake(&self) {
|
||||
self.task_queue.push(self.task_id);
|
||||
impl Wake for TaskWaker {
|
||||
fn wake(self: Arc<Self>) {
|
||||
self.wake_by_ref();
|
||||
}
|
||||
|
||||
fn wake_by_ref(self: &Arc<Self>) {
|
||||
self.queue.push(self.id);
|
||||
}
|
||||
}
|
||||
|
||||
const VTABLE: RawWakerVTable = RawWakerVTable::new(clone_raw, wake_raw, wake_by_ref_raw, drop_raw);
|
||||
|
||||
unsafe fn clone_raw(ptr: *const ()) -> RawWaker {
|
||||
let task_waker = Box::from_raw(ptr as *mut TaskWaker);
|
||||
let raw_waker = RawWaker::new(Box::into_raw(task_waker.clone()) as *const (), &VTABLE);
|
||||
raw_waker
|
||||
}
|
||||
|
||||
unsafe fn wake_raw(ptr: *const ()) {
|
||||
let task_waker = Box::from_raw(ptr as *mut TaskWaker);
|
||||
task_waker.wake();
|
||||
}
|
||||
|
||||
unsafe fn wake_by_ref_raw(ptr: *const ()) {
|
||||
let task_waker = &*(ptr as *const TaskWaker);
|
||||
task_waker.wake();
|
||||
}
|
||||
|
||||
unsafe fn drop_raw(ptr: *const ()) {
|
||||
drop(Box::from_raw(ptr as *mut TaskWaker));
|
||||
}
|
||||
|
|
|
@ -1,52 +0,0 @@
|
|||
//! A module for small utilities to be used kernel wide
|
||||
//! Simple functions and constants
|
||||
|
||||
/// Used when tab `\t` in hardware is not known and we will default to two spaces
|
||||
pub const TAB: &str = " ";
|
||||
|
||||
// NOTE: this only reduces the code duplication in source code not in generated code!
|
||||
// Written by Yours Truly: Munir
|
||||
/// A simple macro to reduce code duplication when we use TAB internally
|
||||
#[macro_export]
|
||||
macro_rules! tab {
|
||||
($num:expr) => {
|
||||
TAB.repeat($num)
|
||||
};
|
||||
}
|
||||
|
||||
// NOTE: this only reduces the code duplication in source code not in generated code!
|
||||
// Written by Yours Truly: Munir
|
||||
/// A simple macro to reduce code duplication when we insert device types into the device tree
|
||||
#[macro_export]
|
||||
macro_rules! device_tree {
|
||||
($devtree:expr, $dev_type_vec:expr) => {
|
||||
for each_device_type in $dev_type_vec {
|
||||
$devtree.devices.insert(each_device_type, Vec::new());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// NOTE: this only reduces the code duplication in source code not in generated code!
|
||||
// Written by Yours Truly: Munir
|
||||
/// A simple macro to reduce code duplication when we insert cpu features into the array/vector
|
||||
#[macro_export]
|
||||
macro_rules! cpu_features {
|
||||
($cpu_master_object:expr, $result_vec:expr) => {
|
||||
// checks for cpu features and returns bool for each feature
|
||||
let apic = $cpu_master_object.apic();
|
||||
let avx = $cpu_master_object.avx();
|
||||
let avx2 = $cpu_master_object.avx2();
|
||||
let x2 = $cpu_master_object.x2apic();
|
||||
let gb_pages = $cpu_master_object.gigabyte_pages();
|
||||
let rdseed = $cpu_master_object.rdseed();
|
||||
let rdrand = $cpu_master_object.rdrand();
|
||||
|
||||
$result_vec.push(("apic", apic));
|
||||
$result_vec.push(("avx", avx));
|
||||
$result_vec.push(("avx2", avx2));
|
||||
$result_vec.push(("gigabyte pages", gb_pages));
|
||||
$result_vec.push(("rdrand", rdrand));
|
||||
$result_vec.push(("rdseed", rdseed));
|
||||
$result_vec.push(("x2apic", x2));
|
||||
};
|
||||
}
|
24
kernel/sycall.md
Normal file
24
kernel/sycall.md
Normal file
|
@ -0,0 +1,24 @@
|
|||
|
||||
|
||||
|
||||
`create_object`
|
||||
```
|
||||
params
|
||||
i32
|
||||
start address of the string to use as the object name
|
||||
i32
|
||||
length of string
|
||||
returns
|
||||
i64 Handle to the object
|
||||
```
|
||||
|
||||
`read_object_attribute`
|
||||
```
|
||||
params
|
||||
i64 Handle to the object
|
||||
i32
|
||||
start address of the string to use as the attribute name
|
||||
i32
|
||||
end address of the string to use as the attribute name
|
||||
returns
|
||||
```
|
|
@ -1,25 +0,0 @@
|
|||
{
|
||||
"arch": "aarch64",
|
||||
"data-layout": "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32",
|
||||
"disable-redzone": true,
|
||||
"env": "",
|
||||
"executables": true,
|
||||
"features": "+strict-align,+neon,+fp-armv8",
|
||||
"linker": "rust-lld",
|
||||
"linker-flavor": "ld.lld",
|
||||
"linker-is-gnu": true,
|
||||
"pre-link-args": {
|
||||
"ld.lld": [
|
||||
"-Tkernel/lds/aarch64-qemu.ld"
|
||||
]
|
||||
},
|
||||
"llvm-target": "aarch64-unknown-none",
|
||||
"max-atomic-width": 128,
|
||||
"os": "none",
|
||||
"panic-strategy": "abort",
|
||||
"relocation-model": "static",
|
||||
"target-c-int-width": "32",
|
||||
"target-endian": "little",
|
||||
"target-pointer-width": "64",
|
||||
"vendor": "ablecorp"
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"llvm-target": "x86_64-unknown-none",
|
||||
"data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128",
|
||||
"data-layout": "e-m:e-i64:64-f80:128-n8:16:32:64-S128",
|
||||
"arch": "x86_64",
|
||||
"target-endian": "little",
|
||||
"target-pointer-width": "64",
|
||||
|
@ -11,7 +11,7 @@
|
|||
"linker": "rust-lld",
|
||||
"panic-strategy": "abort",
|
||||
"disable-redzone": true,
|
||||
"features": "",
|
||||
"features": "-mmx,-sse,+soft-float",
|
||||
"code-model": "kernel",
|
||||
"pre-link-args": {
|
||||
"ld.lld": [
|
||||
|
|
|
@ -1,22 +0,0 @@
|
|||
{
|
||||
"llvm-target": "x86_64-unknown-none",
|
||||
"data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128",
|
||||
"arch": "x86_64",
|
||||
"target-endian": "little",
|
||||
"target-pointer-width": "64",
|
||||
"target-c-int-width": "32",
|
||||
"os": "none",
|
||||
"executables": true,
|
||||
"linker-flavor": "ld.lld",
|
||||
"linker": "rust-lld",
|
||||
"panic-strategy": "abort",
|
||||
"disable-redzone": true,
|
||||
"features": "+sse4.1,+avx,+aes,+fma,+popcnt,+bmi2,+avx2,+lzcnt,+xsave",
|
||||
"code-model": "kernel",
|
||||
"pre-link-args": {
|
||||
"ld.lld": [
|
||||
"--gc-sections",
|
||||
"--script=kernel/lds/x86_64.ld"
|
||||
]
|
||||
}
|
||||
}
|
|
@ -1,2 +0,0 @@
|
|||
# i did not know where to put this
|
||||
- memcpy / memset cause crash on debug builds due to ptr misalignment that is not present on release builds
|
2
limine
2
limine
|
@ -1 +1 @@
|
|||
Subproject commit 2d3d7b2633b5d95ce404a177ada0d5cbee802721
|
||||
Subproject commit 751e802e173392e8637759e2b3c96bbf59456f87
|
51
meta.md
Normal file
51
meta.md
Normal file
|
@ -0,0 +1,51 @@
|
|||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
ARI AbleOS Remote Install
|
||||
|
||||
Server
|
||||
/boot/server_kernel_x86_64.bin
|
||||
/boot/kernel_x86_64.bin
|
||||
/boot/kernel_aarch64.bin
|
||||
|
||||
/home/projects/askl.askl - aksldfhlkasjdhflkajshdflkj
|
||||
|
||||
|
||||
ARI_SERVER.wasm
|
||||
NAS 10.1.10.10
|
||||
|
||||
ARI 10.1.10.10
|
||||
/boot/limine.cfg
|
||||
/boot/kernel_x86_64.bin
|
||||
/boot/kernel.toml
|
||||
/home/projects/askl.askl
|
||||
aksldfhlkasjdhflkajshdflkj
|
||||
|
||||
|
||||
ARI 10.1.10.10
|
||||
/boot/limine.cfg
|
||||
/boot/kernel_aarch64.bin
|
||||
/boot/kernel.toml
|
||||
|
||||
|
||||
|
||||
/system/
|
||||
/shared/
|
||||
/home/programs/
|
||||
project_name/
|
||||
project_name.wasm
|
||||
project_name.toml
|
||||
|
||||
|
||||
|
||||
|
||||
/system/pkgman.toml
|
||||
|
||||
//////
|
||||
[repositories]
|
||||
PUR = "https://git.ablecorp.us/ableos/pur"
|
||||
|
|
@ -4,18 +4,7 @@ version = "0.2.0"
|
|||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
str-reader = "0.1"
|
||||
derive_more = { version = "1", default-features = false, features = [
|
||||
"display",
|
||||
] }
|
||||
error-stack = "0.5"
|
||||
fatfs = { version = "0.3", default-features = false, features = [
|
||||
"std",
|
||||
"alloc",
|
||||
] }
|
||||
toml = "0.8"
|
||||
hblang.git = "https://git.ablecorp.us/AbleOS/holey-bytes.git"
|
||||
# hblang.path = "../../holey-bytes/lang/"
|
||||
env_logger = "0.10"
|
||||
error-stack = "0.2"
|
||||
fatfs = "0.3"
|
||||
log = "0.4"
|
||||
raw-cpuid = "11"
|
||||
ureq = { version = "2", default-features = false, features = ["tls"] }
|
||||
|
|
Before Width: | Height: | Size: 1.8 MiB After Width: | Height: | Size: 1.8 MiB |
22
repbuild/limine.cfg
Normal file
22
repbuild/limine.cfg
Normal file
|
@ -0,0 +1,22 @@
|
|||
${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}
|
||||
KERNEL_CMDLINE="baka=false foobles=true"
|
||||
# KERNEL_CMDLINE=""
|
||||
# Setting a default resolution for the framebuffer
|
||||
RESOLUTION=1024x768x24
|
||||
|
||||
# MODULE_PATH=boot:///boot/fs.wasm
|
||||
# MODULE_CMDLINE=This is the first module.
|
|
@ -1,129 +0,0 @@
|
|||
#![allow(unused)]
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
fmt::format,
|
||||
fs::{read_to_string, File},
|
||||
io::{BufWriter, Write},
|
||||
process::exit,
|
||||
};
|
||||
|
||||
use {error_stack::Report, hblang::Options};
|
||||
|
||||
use crate::Error;
|
||||
pub struct Package {
|
||||
name: String,
|
||||
binaries: Vec<String>,
|
||||
build_cmd: String,
|
||||
args: HashMap<String, String>,
|
||||
}
|
||||
|
||||
impl Package {
|
||||
pub fn load_from_file(path: String) -> Self {
|
||||
let contents = match std::fs::read_to_string(path.clone()) {
|
||||
// If successful return the files text as `contents`.
|
||||
// `c` is a local variable.
|
||||
Ok(c) => c,
|
||||
// Handle the `error` case.
|
||||
Err(_) => {
|
||||
// Write `msg` to `stderr`.
|
||||
eprintln!("Could not read file `{}`", path);
|
||||
// Exit the program with exit code `1`.
|
||||
exit(1);
|
||||
}
|
||||
};
|
||||
use toml::Value;
|
||||
|
||||
let mut data: Value = toml::from_str(&contents).unwrap();
|
||||
let mut name = data
|
||||
.get("package")
|
||||
.unwrap()
|
||||
.get("name")
|
||||
.unwrap()
|
||||
.to_string();
|
||||
name.pop();
|
||||
name.remove(0);
|
||||
|
||||
let dependants = data.get("dependants").unwrap();
|
||||
let bin_table = dependants.get("binaries").unwrap().as_table().unwrap();
|
||||
let mut binaries = vec![];
|
||||
|
||||
for (count, (name, table)) in bin_table.into_iter().enumerate() {
|
||||
binaries.push(name.clone());
|
||||
}
|
||||
let build_table = data.get("build").unwrap();
|
||||
|
||||
let mut build_cmd: String = build_table.get("command").unwrap().as_str().unwrap().into();
|
||||
build_cmd.remove(0);
|
||||
let mut args: HashMap<String, String> = match build_table.get("args") {
|
||||
None => HashMap::new(),
|
||||
Some(v) => v
|
||||
.as_table()
|
||||
.unwrap()
|
||||
.into_iter()
|
||||
.map(|(k, v)| (k.clone(), v.to_string()))
|
||||
.collect::<HashMap<String, String>>(),
|
||||
};
|
||||
|
||||
Self {
|
||||
name,
|
||||
binaries,
|
||||
build_cmd,
|
||||
args,
|
||||
}
|
||||
}
|
||||
pub fn build(&self, out: &mut Vec<u8>) -> std::io::Result<()> {
|
||||
if self.binaries.contains(&"hblang".to_string()) {
|
||||
let file = self.build_cmd.split_ascii_whitespace().last().unwrap();
|
||||
let path = format!("sysdata/programs/{}/{}", self.name, file);
|
||||
// compile here
|
||||
|
||||
let mut warnings = String::new();
|
||||
|
||||
hblang::run_compiler(
|
||||
&path,
|
||||
Options {
|
||||
fmt: true,
|
||||
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,103 +1,41 @@
|
|||
mod dev;
|
||||
|
||||
use {
|
||||
core::fmt::Write as _,
|
||||
derive_more::Display,
|
||||
dev::Package,
|
||||
error_stack::{bail, report, Context, Report, Result, ResultExt},
|
||||
fatfs::{FileSystem, FormatVolumeOptions, FsOptions, ReadWriteSeek},
|
||||
std::{
|
||||
fs::{self, File},
|
||||
io::{self, Write},
|
||||
path::Path,
|
||||
process::{exit, Command, Stdio},
|
||||
},
|
||||
toml::Value,
|
||||
};
|
||||
use error_stack::{bail, report, Context, IntoReport, Result, ResultExt};
|
||||
use fatfs::{FileSystem, FormatVolumeOptions, FsOptions, ReadWriteSeek};
|
||||
use std::{fmt::Display, fs::File, io, path::Path, process::Command};
|
||||
|
||||
fn main() -> Result<(), Error> {
|
||||
env_logger::init();
|
||||
let mut args = std::env::args();
|
||||
args.next();
|
||||
|
||||
log::set_logger(&hblang::Logger).unwrap();
|
||||
log::set_max_level(log::LevelFilter::Error);
|
||||
|
||||
match args.next().as_deref() {
|
||||
Some("build" | "b") => {
|
||||
let mut release = false;
|
||||
let mut debuginfo = false;
|
||||
let mut target = Target::X86_64;
|
||||
let mut tests = false;
|
||||
for arg in args {
|
||||
if arg == "-r" || arg == "--release" {
|
||||
release = true;
|
||||
} else if arg == "-d" || arg == "--debuginfo" {
|
||||
debuginfo = true;
|
||||
} else if arg == "rv64" || arg == "riscv64" || arg == "riscv64-virt" {
|
||||
}
|
||||
if arg == "rv64" || arg == "riscv64" || arg == "riscv64-virt" {
|
||||
target = Target::Riscv64Virt;
|
||||
} else if arg == "arm64" || arg == "aarch64" || arg == "aarch64-virt" {
|
||||
target = Target::Aarch64;
|
||||
} else if arg == "avx2" {
|
||||
target = Target::X86_64Avx2;
|
||||
} else if arg == "--ktest" {
|
||||
tests = true;
|
||||
} else {
|
||||
return Err(report!(Error::InvalidSubCom));
|
||||
}
|
||||
}
|
||||
|
||||
build(release, target, debuginfo, tests).change_context(Error::Build)
|
||||
build(release, target).change_context(Error::Build)
|
||||
}
|
||||
// Some("test" | "t") => {
|
||||
// let mut release = false;
|
||||
// let mut debuginfo = false;
|
||||
// let mut target = Target::X86_64;
|
||||
// for arg in args {
|
||||
// if arg == "-r" || arg == "--release" {
|
||||
// release = true;
|
||||
// } else if arg == "-d" || arg == "--debuginfo" {
|
||||
// debuginfo = true;
|
||||
// } else if arg == "rv64" || arg == "riscv64" || arg == "riscv64-virt" {
|
||||
// target = Target::Riscv64Virt;
|
||||
// } else if arg == "arm64" || arg == "aarch64" || arg == "aarch64-virt" {
|
||||
// target = Target::Aarch64;
|
||||
// } else if arg == "avx2" {
|
||||
// target = Target::X86_64Avx2;
|
||||
// } else {
|
||||
// return Err(report!(Error::InvalidSubCom));
|
||||
// }
|
||||
// }
|
||||
|
||||
// test(release, target, debuginfo).change_context(Error::Build)
|
||||
// }
|
||||
Some("run" | "r") => {
|
||||
let mut release = false;
|
||||
let mut debuginfo = false;
|
||||
let mut target = Target::X86_64;
|
||||
let mut tests = false;
|
||||
let mut do_accel = true;
|
||||
for arg in args {
|
||||
if arg == "-r" || arg == "--release" {
|
||||
release = true;
|
||||
} else if arg == "-d" || arg == "--debuginfo" {
|
||||
debuginfo = true;
|
||||
} else if arg == "rv64" || arg == "riscv64" || arg == "riscv64-virt" {
|
||||
}
|
||||
if arg == "rv64" || arg == "riscv64" || arg == "riscv64-virt" {
|
||||
target = Target::Riscv64Virt;
|
||||
} else if arg == "arm64" || arg == "aarch64" || arg == "aarch64-virt" {
|
||||
target = Target::Aarch64;
|
||||
} else if arg == "--noaccel" {
|
||||
do_accel = false;
|
||||
} else if arg == "avx2" {
|
||||
target = Target::X86_64Avx2;
|
||||
} else if arg == "--ktest" {
|
||||
tests = true;
|
||||
} else {
|
||||
return Err(report!(Error::InvalidSubCom));
|
||||
}
|
||||
}
|
||||
|
||||
build(release, target, debuginfo, tests)?;
|
||||
run(release, target, do_accel)
|
||||
build(release, target)?;
|
||||
run(release, target)
|
||||
}
|
||||
Some("help" | "h") => {
|
||||
println!(concat!(
|
||||
|
@ -107,11 +45,8 @@ fn main() -> Result<(), Error> {
|
|||
" help (h): Print this message\n",
|
||||
" run (r): Build and run AbleOS in QEMU\n\n",
|
||||
"Options for build and run:\n",
|
||||
" -r / --release: build in release mode\n",
|
||||
" -d / --debuginfo: build with debug info\n",
|
||||
" --noaccel: run without acceleration (e.g, no kvm)\n",
|
||||
" --ktest: Enables tests via ktest\n",
|
||||
"[ rv64 / riscv64 / riscv64-virt / aarch64 / arm64 / aarch64-virt / avx2 ]: sets target"
|
||||
" -r: build in release mode",
|
||||
" [target]: sets target"
|
||||
),);
|
||||
Ok(())
|
||||
}
|
||||
|
@ -119,227 +54,56 @@ fn main() -> Result<(), Error> {
|
|||
}
|
||||
}
|
||||
|
||||
fn get_path_without_boot_prefix(val: &Value) -> Option<&str> {
|
||||
val.as_str()?.split("boot:///").last()
|
||||
}
|
||||
|
||||
fn get_fs() -> Result<FileSystem<impl ReadWriteSeek>, io::Error> {
|
||||
let filename = "sysdata/system_config.toml";
|
||||
let path = Path::new("target/disk.img");
|
||||
|
||||
match std::fs::metadata(path) {
|
||||
Err(e) if e.kind() == io::ErrorKind::NotFound => (),
|
||||
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()
|
||||
.read(true)
|
||||
.write(true)
|
||||
.create(true)
|
||||
.open(Path::new("target/disk.img"))?;
|
||||
.open(path)?;
|
||||
|
||||
img.set_len(1024 * 1024 * 64)?;
|
||||
|
||||
fatfs::format_volume(&mut img, FormatVolumeOptions::new())?;
|
||||
|
||||
let fs = FileSystem::new(img, FsOptions::new())?;
|
||||
|
||||
// Read the contents of the file using a `match` block
|
||||
// to return the `data: Ok(c)` as a `String`
|
||||
// or handle any `errors: Err(_)`.
|
||||
let contents = match fs::read_to_string(filename) {
|
||||
// If successful return the files text as `contents`.
|
||||
// `c` is a local variable.
|
||||
Ok(c) => c,
|
||||
// Handle the `error` case.
|
||||
Err(_) => {
|
||||
// Write `msg` to `stderr`.
|
||||
eprintln!("Could not read file `{}`", filename);
|
||||
// Exit the program with exit code `1`.
|
||||
exit(1);
|
||||
}
|
||||
};
|
||||
use toml::Value;
|
||||
|
||||
let mut limine_str = String::new();
|
||||
|
||||
let mut data: Value = toml::from_str(&contents).unwrap();
|
||||
let boot_table = data.get_mut("boot");
|
||||
let limine_table = boot_table.unwrap().get_mut("limine").unwrap();
|
||||
let default_entry = limine_table.get("default_entry").unwrap();
|
||||
let timeout = limine_table.get("timeout").unwrap();
|
||||
let interface_resolution = limine_table.get("interface_resolution").unwrap();
|
||||
let verbose = limine_table.get("verbose").unwrap();
|
||||
let term_wallpaper = limine_table.get("term_wallpaper").unwrap();
|
||||
|
||||
let vb_post = match verbose.as_bool().unwrap() {
|
||||
true => "yes",
|
||||
false => "no",
|
||||
};
|
||||
let term_background = limine_table
|
||||
.get("term_backdrop")
|
||||
.unwrap_or(&Value::Integer(0));
|
||||
let base = format!(
|
||||
"DEFAULT_ENTRY={}
|
||||
TIMEOUT={}
|
||||
VERBOSE={}
|
||||
INTERFACE_RESOLUTION={}
|
||||
# Terminal related settings
|
||||
TERM_WALLPAPER={}
|
||||
TERM_BACKDROP={}
|
||||
",
|
||||
default_entry,
|
||||
timeout,
|
||||
vb_post,
|
||||
interface_resolution,
|
||||
term_wallpaper.as_str().unwrap(),
|
||||
term_background
|
||||
);
|
||||
|
||||
// Copy the term_wallpaper to the image
|
||||
let term_wallpaper_path = get_path_without_boot_prefix(term_wallpaper).unwrap();
|
||||
copy_file_to_img(&format!("sysdata/{}", term_wallpaper_path), &fs);
|
||||
|
||||
limine_str.push_str(&base);
|
||||
|
||||
let boot_entries = limine_table.as_table_mut().unwrap();
|
||||
let mut real_boot_entries = boot_entries.clone();
|
||||
for (key, value) in boot_entries.into_iter() {
|
||||
if !value.is_table() {
|
||||
real_boot_entries.remove(key);
|
||||
}
|
||||
}
|
||||
|
||||
for (name, mut value) in real_boot_entries {
|
||||
let comment = value.get("comment").unwrap();
|
||||
let protocol = value.get("protocol").unwrap();
|
||||
let resolution = value.get("resolution").unwrap();
|
||||
let kernel_path = value.get("kernel_path").unwrap();
|
||||
let kernel_cmdline = value.get("kernel_cmdline").unwrap();
|
||||
|
||||
let text_entry = format!(
|
||||
"
|
||||
:{}
|
||||
COMMENT={}
|
||||
PROTOCOL={}
|
||||
RESOLUTION={}
|
||||
KERNEL_PATH={}
|
||||
KERNEL_CMDLINE={}
|
||||
|
||||
",
|
||||
name,
|
||||
comment.as_str().unwrap(),
|
||||
protocol.as_str().unwrap(),
|
||||
resolution.as_str().unwrap(),
|
||||
kernel_path.as_str().unwrap(),
|
||||
kernel_cmdline,
|
||||
);
|
||||
|
||||
limine_str.push_str(&text_entry);
|
||||
|
||||
let modules = value.get_mut("modules").unwrap().as_table_mut().unwrap();
|
||||
// let mut real_modules = modules.clone();
|
||||
|
||||
let mut errors = String::new();
|
||||
let mut out = Vec::new();
|
||||
|
||||
modules
|
||||
.into_iter()
|
||||
.map(|(_, value)| -> Result<(), io::Error> {
|
||||
if value.is_table() {
|
||||
let path = get_path_without_boot_prefix(
|
||||
value.get("path").expect("You must have `path` as a value"),
|
||||
)
|
||||
.unwrap()
|
||||
.split(".")
|
||||
.next()
|
||||
.unwrap();
|
||||
let p = Package::load_from_file(
|
||||
format!("sysdata/programs/{}/meta.toml", path).to_owned(),
|
||||
);
|
||||
match p.build(&mut out) {
|
||||
Ok(()) => {}
|
||||
Err(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 mut f = fs.root_dir().create_file("limine.cfg")?;
|
||||
let _ = f.write(limine_str.as_bytes())?;
|
||||
drop(f);
|
||||
|
||||
io::copy(
|
||||
&mut File::open("limine/BOOTX64.EFI")
|
||||
.map_err(Report::from)
|
||||
.attach_printable("Copying Limine (x86_64): have you pulled the submodule?")?,
|
||||
.into_report()
|
||||
.attach_printable("copying Limine bootloader (have you pulled the submodule?)")?,
|
||||
&mut bootdir.create_file("bootx64.efi")?,
|
||||
)?;
|
||||
|
||||
io::copy(
|
||||
&mut File::open("limine/BOOTAA64.EFI")
|
||||
.map_err(Report::from)
|
||||
.attach_printable("Copying Limine (ARM): have you pulled the submodule?")?,
|
||||
&mut bootdir.create_file("bootaa64.efi")?,
|
||||
&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")?,
|
||||
)?;
|
||||
|
||||
drop(bootdir);
|
||||
Ok(fs)
|
||||
}
|
||||
|
||||
fn copy_file_to_img(fpath: &str, fs: &FileSystem<File>) {
|
||||
let path = Path::new(fpath);
|
||||
// println!("{path:?}");
|
||||
io::copy(
|
||||
&mut File::open(path).expect(&format!("Could not open file {fpath}")),
|
||||
&mut fs
|
||||
.root_dir()
|
||||
.create_file(&path.file_name().unwrap().to_string_lossy())
|
||||
.expect("Unable to create file"),
|
||||
)
|
||||
.expect("Copy failed");
|
||||
}
|
||||
|
||||
fn build(release: bool, target: Target, debuginfo: bool, tests: bool) -> Result<(), Error> {
|
||||
fn build(release: bool, target: Target) -> Result<(), Error> {
|
||||
let fs = get_fs().change_context(Error::Io)?;
|
||||
let mut com = Command::new("cargo");
|
||||
com.current_dir("kernel");
|
||||
|
@ -347,22 +111,12 @@ fn build(release: bool, target: Target, debuginfo: bool, tests: bool) -> Result<
|
|||
if release {
|
||||
com.arg("-r");
|
||||
}
|
||||
if debuginfo {
|
||||
com.env("RUSTFLAGS", "-Cdebug-assertions=true");
|
||||
}
|
||||
|
||||
if tests {
|
||||
com.args(["--features", "ktest"]);
|
||||
}
|
||||
|
||||
if target == Target::Riscv64Virt {
|
||||
match target {
|
||||
Target::Riscv64Virt => {
|
||||
com.args(["--target", "targets/riscv64-virt-ableos.json"]);
|
||||
}
|
||||
if target == Target::Aarch64 {
|
||||
com.args(["--target", "targets/aarch64-virt-ableos.json"]);
|
||||
}
|
||||
if target == Target::X86_64Avx2 {
|
||||
com.args(["--target", "targets/x86_64_v3-ableos.json"]);
|
||||
_ => {}
|
||||
}
|
||||
|
||||
match com.status() {
|
||||
|
@ -371,108 +125,51 @@ fn build(release: bool, target: Target, debuginfo: bool, tests: bool) -> Result<
|
|||
_ => (),
|
||||
}
|
||||
|
||||
let mut path: String = "kernel".to_string();
|
||||
let kernel_dir = match target {
|
||||
Target::X86_64 => {
|
||||
path.push_str("_x86-64");
|
||||
"target/x86_64-ableos"
|
||||
if target != Target::X86_64 {
|
||||
return Ok(());
|
||||
}
|
||||
Target::X86_64Avx2 => {
|
||||
path.push_str("_x86-64");
|
||||
"target/x86_64_v3-ableos"
|
||||
}
|
||||
Target::Riscv64Virt => "target/riscv64-virt-ableos",
|
||||
Target::Aarch64 => {
|
||||
path.push_str("_aarch64");
|
||||
"target/aarch64-virt-ableos"
|
||||
}
|
||||
};
|
||||
|
||||
(|| -> std::io::Result<_> {
|
||||
io::copy(
|
||||
&mut File::open(
|
||||
Path::new(kernel_dir)
|
||||
Path::new("target/x86_64-ableos")
|
||||
.join(if release { "release" } else { "debug" })
|
||||
.join("kernel"),
|
||||
)?,
|
||||
&mut fs.root_dir().create_file(&path)?,
|
||||
&mut fs.root_dir().create_file("kernel")?,
|
||||
)
|
||||
.map(|_| ())
|
||||
})()
|
||||
.map_err(Report::from)
|
||||
.into_report()
|
||||
.change_context(Error::Io)
|
||||
}
|
||||
|
||||
fn run(release: bool, target: Target, do_accel: bool) -> Result<(), Error> {
|
||||
let target_str = match target {
|
||||
Target::X86_64 | Target::X86_64Avx2 => "qemu-system-x86_64",
|
||||
Target::Riscv64Virt => "qemu-system-riscv64",
|
||||
Target::Aarch64 => "qemu-system-aarch64",
|
||||
fn run(release: bool, target: Target) -> Result<(), Error> {
|
||||
let mut com = match target {
|
||||
Target::X86_64 => Command::new("qemu-system-x86_64"),
|
||||
Target::Riscv64Virt => Command::new("qemu-system-riscv64"),
|
||||
};
|
||||
let (mut com, mut com2) = (Command::new(target_str), Command::new(target_str));
|
||||
let ovmf_path = fetch_ovmf(target);
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
let accel = if do_accel {
|
||||
let supported = String::from_utf8(
|
||||
com2.args(["--accel", "help"])
|
||||
.stdout(Stdio::piped())
|
||||
.stderr(Stdio::piped())
|
||||
.spawn()
|
||||
.unwrap()
|
||||
.wait_with_output()
|
||||
.unwrap()
|
||||
.stdout,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let cpuid = raw_cpuid::CpuId::new();
|
||||
let vmx = cpuid.get_feature_info().unwrap().has_vmx();
|
||||
let svm = cpuid.get_svm_info().is_some();
|
||||
|
||||
if supported.contains("kvm") && (vmx || svm) {
|
||||
"accel=kvm"
|
||||
} else if cpuid
|
||||
.get_processor_brand_string()
|
||||
.filter(|a| a.as_str() == "GenuineIntel")
|
||||
.is_some()
|
||||
&& supported.contains("hax")
|
||||
&& vmx
|
||||
{
|
||||
"accel=hax"
|
||||
} else if supported.contains("whpx") {
|
||||
"accel=whpx"
|
||||
} else {
|
||||
"accel=tcg"
|
||||
}
|
||||
} else {
|
||||
"accel=tcg"
|
||||
};
|
||||
#[cfg(not(target_arch = "x86_64"))]
|
||||
let accel = "accel=tcg";
|
||||
|
||||
match target {
|
||||
Target::X86_64 | Target::X86_64Avx2 => {
|
||||
if target == Target::X86_64 {
|
||||
#[rustfmt::skip]
|
||||
com.args([
|
||||
"-bios", &ovmf_path.change_context(Error::OvmfFetch)?,
|
||||
//"-hda", "target/disk.img",
|
||||
"-drive", "file=target/disk.img,index=0,if=ide,format=raw",
|
||||
"-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",
|
||||
"-bios",
|
||||
std::env::var("REPBUILD_QEMU_FIRMWARE_PATH")
|
||||
.as_deref()
|
||||
.unwrap_or("/usr/share/ovmf/x64/OVMF_CODE.fd"),
|
||||
"-drive", "file=target/disk.img,format=raw",
|
||||
"-m", "4G",
|
||||
"-serial", "stdio",
|
||||
"-smp", "cores=2",
|
||||
]);
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
{
|
||||
com.args(["-enable-kvm", "-cpu", "host"]);
|
||||
}
|
||||
Target::Riscv64Virt => {
|
||||
}
|
||||
|
||||
if target == Target::Riscv64Virt {
|
||||
#[rustfmt::skip]
|
||||
com.args([
|
||||
"-M", "virt",
|
||||
|
@ -486,24 +183,10 @@ fn run(release: bool, target: Target, do_accel: bool) -> Result<(), Error> {
|
|||
}
|
||||
]);
|
||||
}
|
||||
Target::Aarch64 => {
|
||||
#[rustfmt::skip]
|
||||
com.args([
|
||||
"-M", "virt",
|
||||
"-cpu", "max",
|
||||
"-device", "ramfb",
|
||||
"-device", "qemu-xhci",
|
||||
"-device", "usb-kbd",
|
||||
"-m", "2G",
|
||||
"-bios", &ovmf_path.change_context(Error::OvmfFetch)?,
|
||||
"-drive", "file=target/disk.img,format=raw",
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
match com
|
||||
.status()
|
||||
.map_err(Report::from)
|
||||
.into_report()
|
||||
.change_context(Error::ProcessSpawn)?
|
||||
{
|
||||
s if s.success() => Ok(()),
|
||||
|
@ -511,95 +194,33 @@ fn run(release: bool, target: Target, do_accel: bool) -> Result<(), Error> {
|
|||
}
|
||||
}
|
||||
|
||||
fn fetch_ovmf(target: Target) -> Result<String, OvmfFetchError> {
|
||||
let (ovmf_url, ovmf_path) = match target {
|
||||
Target::X86_64 | Target::X86_64Avx2 => (
|
||||
"https://retrage.github.io/edk2-nightly/bin/RELEASEX64_OVMF.fd",
|
||||
"target/RELEASEX64_OVMF.fd",
|
||||
),
|
||||
Target::Riscv64Virt => return Err(OvmfFetchError::Empty.into()),
|
||||
Target::Aarch64 => (
|
||||
"https://retrage.github.io/edk2-nightly/bin/RELEASEAARCH64_QEMU_EFI.fd",
|
||||
"target/RELEASEAARCH64_QEMU_EFI.fd",
|
||||
),
|
||||
};
|
||||
|
||||
let mut file = match std::fs::metadata(ovmf_path) {
|
||||
Err(e) if e.kind() == std::io::ErrorKind::NotFound => std::fs::OpenOptions::new()
|
||||
.create(true)
|
||||
.write(true)
|
||||
.read(true)
|
||||
.open(ovmf_path)
|
||||
.map_err(Report::from)
|
||||
.change_context(OvmfFetchError::Io)?,
|
||||
Ok(_) => return Ok(ovmf_path.to_owned()),
|
||||
Err(e) => return Err(report!(e).change_context(OvmfFetchError::Io)),
|
||||
};
|
||||
let req = ureq::get(ovmf_url)
|
||||
.call()
|
||||
.map_err(Report::from)
|
||||
.change_context(OvmfFetchError::Fetch)?;
|
||||
|
||||
std::io::copy(&mut req.into_reader(), &mut file)
|
||||
.map_err(Report::from)
|
||||
.change_context(OvmfFetchError::Io)?;
|
||||
|
||||
Ok(ovmf_path.to_owned())
|
||||
}
|
||||
|
||||
#[derive(Debug, Display)]
|
||||
enum OvmfFetchError {
|
||||
#[display("Failed to fetch OVMF package")]
|
||||
Fetch,
|
||||
#[display("No OVMF package available")]
|
||||
Empty,
|
||||
#[display("IO Error")]
|
||||
Io,
|
||||
}
|
||||
|
||||
impl Context for OvmfFetchError {}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||
enum Target {
|
||||
X86_64,
|
||||
X86_64Avx2,
|
||||
Riscv64Virt,
|
||||
Aarch64,
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
#[derive(Debug, Display)]
|
||||
#[derive(Debug)]
|
||||
enum Error {
|
||||
#[display("Failed to build the kernel")]
|
||||
Build,
|
||||
#[display("Missing or invalid subcommand (available: build, run)")]
|
||||
InvalidSubCom,
|
||||
#[display("IO Error")]
|
||||
Io,
|
||||
#[display("Failed to spawn a process")]
|
||||
ProcessSpawn,
|
||||
#[display("Failed to fetch UEFI firmware")]
|
||||
OvmfFetch,
|
||||
#[display("Failed to assemble Holey Bytes code")]
|
||||
Assembler,
|
||||
#[display("QEMU Error: {}", "fmt_qemu_err(*_0)")]
|
||||
Qemu(Option<i32>),
|
||||
}
|
||||
|
||||
impl Context for Error {}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn fmt_qemu_err(e: Option<i32>) -> impl Display {
|
||||
struct W(Option<i32>);
|
||||
impl Display for W {
|
||||
impl Display for Error {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
if let Some(c) = self.0 {
|
||||
c.fmt(f)
|
||||
} else {
|
||||
f.write_str("Interrupted by signal")
|
||||
match self {
|
||||
Self::Build => f.write_str("failed to build the kernel"),
|
||||
Self::InvalidSubCom => {
|
||||
f.write_str("missing or invalid subcommand (available: build, run)")
|
||||
}
|
||||
Self::Io => f.write_str("IO error"),
|
||||
Self::ProcessSpawn => f.write_str("failed to spawn a process"),
|
||||
Self::Qemu(Some(c)) => write!(f, "QEMU Error: {c}"),
|
||||
Self::Qemu(None) => write!(f, "QEMU Error: interrupted by signal"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
W(e)
|
||||
}
|
||||
|
|
|
@ -1,7 +1,3 @@
|
|||
[toolchain]
|
||||
# old toolchain
|
||||
# channel = "nightly-2024-07-27"
|
||||
# last stable
|
||||
# channel = "nightly-2024-11-20"
|
||||
channel = "nightly"
|
||||
components = ["rust-src", "llvm-tools"]
|
||||
|
|
|
@ -1,3 +1,2 @@
|
|||
hex_literal_case = "Upper"
|
||||
imports_granularity = "One"
|
||||
struct_field_align_threshold = 5
|
||||
|
|
41
shell.nix
41
shell.nix
|
@ -1,41 +0,0 @@
|
|||
{ pkgs ? import <nixpkgs> { } }:
|
||||
pkgs.mkShell rec {
|
||||
buildInputs = with pkgs; [
|
||||
clang
|
||||
llvmPackages.bintools
|
||||
rustup
|
||||
qemu_full
|
||||
# OMVFFull
|
||||
# OMVF
|
||||
];
|
||||
extraCmds = '''';
|
||||
RUSTC_VERSION = pkgs.lib.readFile ./rust-toolchain.toml;
|
||||
# https://github.com/rust-lang/rust-bindgen#environment-variables
|
||||
LIBCLANG_PATH =
|
||||
pkgs.lib.makeLibraryPath [ pkgs.llvmPackages_latest.libclang.lib ];
|
||||
shellHook = ''
|
||||
export REPBUILD_QEMU_FIRMWARE_PATH=${pkgs.OVMF.fd}/FV/OVMF.fd
|
||||
|
||||
export PATH=$PATH:''${CARGO_HOME:-~/.cargo}/bin
|
||||
export PATH=$PATH:''${RUSTUP_HOME:-~/.rustup}/toolchains/$RUSTC_VERSION-x86_64-unknown-linux-gnu/bin/
|
||||
'';
|
||||
# Add precompiled library to rustc search path
|
||||
RUSTFLAGS = (builtins.map (a: "-L ${a}/lib") [
|
||||
# add libraries here (e.g. pkgs.libvmi)
|
||||
]);
|
||||
# Add glibc, clang, glib and other headers to bindgen search path
|
||||
BINDGEN_EXTRA_CLANG_ARGS =
|
||||
# Includes with normal include path
|
||||
(builtins.map (a: ''-I"${a}/include"'') [
|
||||
# add dev libraries here (e.g. pkgs.libvmi.dev)
|
||||
pkgs.glibc.dev
|
||||
])
|
||||
# Includes with special directory paths
|
||||
++ [
|
||||
''
|
||||
-I"${pkgs.llvmPackages_latest.libclang.lib}/lib/clang/${pkgs.llvmPackages_latest.libclang.version}/include"''
|
||||
''-I"${pkgs.glib.dev}/include/glib-2.0"''
|
||||
"-I${pkgs.glib.out}/lib/glib-2.0/include/"
|
||||
];
|
||||
|
||||
}
|
Binary file not shown.
Before Width: | Height: | Size: 100 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue