forked from AbleOS/ableos
Compare commits
156 commits
Author | SHA1 | Date | |
---|---|---|---|
0a6085061a | |||
6f061153e6 | |||
cb66c07a5f | |||
able | 15515e6643 | ||
able | 7a2372d32a | ||
able | 65b6f52d2e | ||
able | 562fb7c9b2 | ||
able | 762b2aa3ae | ||
able | fe6cccc70d | ||
able | 815c424248 | ||
Erin | b8ce78b6dd | ||
Erin | d396da5f3c | ||
Erin | 0f7525b7e3 | ||
able | ebf31cba3d | ||
able | f074527e42 | ||
Erin | f2e561e242 | ||
Erin | 2c1d24ab37 | ||
Erin | 4e9b75a517 | ||
able | 0af4758a45 | ||
Erin | fd575a17c9 | ||
able | bda8659747 | ||
able | 631e1dc288 | ||
able | b7f9b071bf | ||
able | 94569624f6 | ||
able | 080bb8b188 | ||
able | 1ae1d2ceac | ||
able | 707528ef86 | ||
able | c8f500470e | ||
Erin | 6885f1cdaf | ||
able | fa328add42 | ||
able | d1d1bd7fd7 | ||
Erin | ebfc9c1c4e | ||
able | ada43910d2 | ||
able | 29bcce58b3 | ||
able | 9105469c3b | ||
able | e7bbb9a375 | ||
able | 008a8eb336 | ||
able | e0aa63bebf | ||
able | 9cf6f93949 | ||
able | 1be13d30d1 | ||
able | 8fec90db95 | ||
able | c16c235c95 | ||
able | 54844b46a0 | ||
able | b04ee13185 | ||
Erin | 0e8fb17f3a | ||
Erin | 3c45720fa3 | ||
Erin | cbed32526b | ||
Erin | 0f151fdd52 | ||
Erin | f948e35e3f | ||
Erin | 88213a7df0 | ||
239ee43064 | |||
microtau | c9ab181d95 | ||
microtau | f474f0fb69 | ||
microtau | d0a2f436a8 | ||
microtau | 7865bca782 | ||
c0744d5596 | |||
microtau | ea49841de2 | ||
able | 84757f7060 | ||
able | e7b46f639c | ||
able | 2dcd096de9 | ||
able | 9225d2d773 | ||
able | ede52eb1db | ||
81e2603c4d | |||
af7bcc8efb | |||
f0be41ec49 | |||
JohnyTheCarrot | c955f3a0de | ||
53fca04786 | |||
able | 4cf933c62b | ||
able | 6c4eee0c56 | ||
able | d3e019ffe1 | ||
able | a8005728bf | ||
able | 80bfcb83b9 | ||
able | 3a62f65cd1 | ||
able | d8a68aabee | ||
able | 9bbc0e19a1 | ||
490f15db48 | |||
able | 4dd3699e0e | ||
IntoTheNight | bea92d996c | ||
6a404b8227 | |||
able | a9350952b7 | ||
able | b9af2ae9c4 | ||
Erin | aa5ea3fb8f | ||
able | 3b6dce674d | ||
able | 2f24089938 | ||
able | d1a6e627ef | ||
1455f1712c | |||
473598d5df | |||
56ec28550f | |||
able | a18ca4335f | ||
able | de8661be62 | ||
able | c264865d49 | ||
able | 340d76fd13 | ||
able | b7da4f17c2 | ||
2af7684532 | |||
7a00dff4b9 | |||
able | ae321a9923 | ||
bb27f48f4a | |||
359d62c1b0 | |||
a2a2b509bb | |||
4252719a72 | |||
7ac33efcbc | |||
87c3d0bb3a | |||
dc03601ac0 | |||
able | 8e8289f5ba | ||
able | c276476068 | ||
able | e8d854a171 | ||
able | 06868b516f | ||
able | 567871d18e | ||
able | 1dd330e604 | ||
able | 1be36455e4 | ||
able | 36f2a8336f | ||
able | 432af37737 | ||
able | 0508140f40 | ||
able | 65f1695b46 | ||
able | c2b8341667 | ||
able | 1a98fe8908 | ||
able | d4670cb85d | ||
able | 16ccd51e4a | ||
able | b9b798efff | ||
able | 03667f6039 | ||
able | 8eebd50179 | ||
able | bb3c1b6120 | ||
able | b9bfd99335 | ||
able | 49105e668d | ||
able | 40c072ad99 | ||
able | a2bf48f56b | ||
able | 5af29efe17 | ||
able | e513caf499 | ||
able | ad22051a20 | ||
Able | 2744e8e67b | ||
Able | 282688d48b | ||
Able | 88df7c2c34 | ||
Able | 4a8b56a474 | ||
Able | 308592cbf9 | ||
Able | fb0dcc786d | ||
e53d7896a7 | |||
Christian Westrom | 6843023a44 | ||
Able | 174b621acd | ||
Able | 01cdd68b28 | ||
Able | ec7a80c93a | ||
Able | 530a8a9d60 | ||
Able | 20e3ce15be | ||
Erin | 0a77e691d7 | ||
Able | d6e27bc1f4 | ||
Able | 64a02bbf01 | ||
Able | 40c99b47b5 | ||
Able | 1f8ea529f9 | ||
Erin | f396c3642d | ||
Erin | 4812e59c09 | ||
Erin | d31f17f07e | ||
Erin | 4e6bed0b57 | ||
Erin | 56700a7986 | ||
Erin | b943714093 | ||
Erin | 8ebaf1b244 | ||
Erin | 84f163f534 | ||
Erin | 3b1e51d1ba |
4
.gdbinit
4
.gdbinit
|
@ -1,4 +0,0 @@
|
||||||
set history save on
|
|
||||||
file target/x86_64-ableos/debug/ableos
|
|
||||||
target remote localhost:9000
|
|
||||||
tui enable
|
|
6
.vscode/settings.json
vendored
6
.vscode/settings.json
vendored
|
@ -1,6 +1,4 @@
|
||||||
{
|
{
|
||||||
"files.associations": {
|
"rust-analyzer.checkOnSave.allTargets": false,
|
||||||
"stddef.h": "c"
|
"rust-analyzer.showUnlinkedFileNotification": false
|
||||||
},
|
|
||||||
"rust-analyzer.checkOnSave.allTargets": false
|
|
||||||
}
|
}
|
BIN
AAVMF_CODE.fd
Normal file
BIN
AAVMF_CODE.fd
Normal file
Binary file not shown.
1454
Cargo.lock
generated
1454
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
|
@ -1,2 +1,3 @@
|
||||||
[workspace]
|
[workspace]
|
||||||
|
resolver = "2"
|
||||||
members = ["kernel", "repbuild"]
|
members = ["kernel", "repbuild"]
|
||||||
|
|
34
README.md
34
README.md
|
@ -1,26 +1,18 @@
|
||||||
# ableOS
|
# AbleOS
|
||||||
![Discord](https://img.shields.io/discord/831368967385120810) ![Code Size](https://img.shields.io/github/languages/code-size/abletheabove/ableos)
|
An UNIX-unlike micro-kernel written in rust with an embedded bytecode virtual machine.
|
||||||
## Set up
|
|
||||||
Install [Qemu](https://www.qemu.org/)
|
|
||||||
|
|
||||||
> 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
|
||||||
|
AbleOS should be able to be built on any platform which is supported by
|
||||||
|
[Rustc Tier 1 platform support](https://doc.rust-lang.org/nightly/rustc/platform-support.html#tier-1-with-host-tools).
|
||||||
|
|
||||||
`cargo install bootimage`
|
For running AbleOS, `repbuild` uses QEMU.
|
||||||
|
|
||||||
|
## Steps
|
||||||
## Running
|
1. `git submodule update --init`
|
||||||
repbuild can be used to run and build docs for able os
|
2. `cargo repbuild`
|
||||||
|
|
||||||
`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
|
|
||||||
|
|
31
concepts/system.toml
Normal file
31
concepts/system.toml
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
[boot]
|
||||||
|
# This package must be installed system wide
|
||||||
|
init = "init_server"
|
||||||
|
|
||||||
|
|
||||||
|
[boot.limine]
|
||||||
|
default_entry = 1
|
||||||
|
timeout = 0
|
||||||
|
verbose = true
|
||||||
|
interface_resolution = "1024x768x24"
|
||||||
|
# Terminal related settings
|
||||||
|
term_wallpaper = "boot:///background.bmp"
|
||||||
|
term_background = "008080"
|
||||||
|
|
||||||
|
[boot.limine.ableos]
|
||||||
|
comment = "Default AbleOS boot entry."
|
||||||
|
protocol = "limine"
|
||||||
|
kernel_path = "boot:///kernel"
|
||||||
|
kernel_cmdline = "baka=false foobles=true"
|
||||||
|
resolution = "1024x768x24"
|
||||||
|
|
||||||
|
[repositories]
|
||||||
|
core = "https://git.ablecorp.us/AbleOS/core"
|
||||||
|
userspace = "https://git.ablecorp.us/AbleOS/ableos_userland"
|
||||||
|
|
||||||
|
|
||||||
|
[packages]
|
||||||
|
[packages.init_server]
|
||||||
|
version = "1.0"
|
||||||
|
hash = ""
|
||||||
|
repo = "core"
|
79
contrib/DriverDepGraph.dot
Normal file
79
contrib/DriverDepGraph.dot
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
digraph Drivers {
|
||||||
|
InitSystem -> VFS;
|
||||||
|
InitSystem -> Logger;
|
||||||
|
|
||||||
|
TCP -> NetworkingStack;
|
||||||
|
UDP -> NetworkingStack;
|
||||||
|
|
||||||
|
NetworkingStack -> PhysLayer;
|
||||||
|
PhysLayer -> Ethernet;
|
||||||
|
|
||||||
|
Ethernet -> Threec90x;
|
||||||
|
Ethernet -> Intel8254x;
|
||||||
|
Ethernet -> Ne2000;
|
||||||
|
Ethernet -> RTL8139;
|
||||||
|
Ethernet -> RTL8169;
|
||||||
|
Ethernet -> IntelEtherneti217;
|
||||||
|
Ethernet -> AMDPCnet;
|
||||||
|
|
||||||
|
PhysLayer -> Wifi;
|
||||||
|
Wifi -> Eight02Dot11;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Audio -> PCSpeaker;
|
||||||
|
Audio -> SoundBlaster16;
|
||||||
|
|
||||||
|
RNG -> CpuRNG;
|
||||||
|
RNG -> NetworkingStack;
|
||||||
|
RNG -> GraphicsLibrary;
|
||||||
|
RNG -> Input;
|
||||||
|
|
||||||
|
Slint -> GraphicsLibrary;
|
||||||
|
GraphicsLibrary -> ShaderCompiler;
|
||||||
|
ShaderCompiler -> GraphicsDriver;
|
||||||
|
GraphicsLibrary -> GraphicsDriver;
|
||||||
|
// Todo: dreak out the GPU into specific drivers
|
||||||
|
GraphicsDriver -> GPU;
|
||||||
|
|
||||||
|
Logger -> Serial;
|
||||||
|
Logger -> VFS;
|
||||||
|
|
||||||
|
Input -> Keyboard;
|
||||||
|
Input -> GraphicsTablet;
|
||||||
|
Input -> Mouse;
|
||||||
|
Input -> Serial;
|
||||||
|
Input -> Controllers;
|
||||||
|
|
||||||
|
Controllers -> Playstation;
|
||||||
|
Playstation -> DualShock;
|
||||||
|
Playstation -> DualSense;
|
||||||
|
DualShock -> DualShock1;
|
||||||
|
DualShock -> DualShock2;
|
||||||
|
DualShock -> DualShock3;
|
||||||
|
DualShock -> DualShock4;
|
||||||
|
|
||||||
|
|
||||||
|
Mouse -> PS2Mouse;
|
||||||
|
Mouse -> USBMouse;
|
||||||
|
USBMouse -> GenericUSBMouse;
|
||||||
|
Mouse -> MouseTrackPad;
|
||||||
|
Mouse -> MouseTrackPoint;
|
||||||
|
|
||||||
|
VFS -> Fat32;
|
||||||
|
VFS -> TarFS;
|
||||||
|
VFS -> Ext2;
|
||||||
|
|
||||||
|
Ext2 -> VirtualDisk;
|
||||||
|
TarFS -> VirtualDisk;
|
||||||
|
Fat32 -> VirtualDisk;
|
||||||
|
|
||||||
|
VirtualDisk -> IDEDiskDriver;
|
||||||
|
VirtualDisk -> ATADiskDriver;
|
||||||
|
VirtualDisk -> FloppyController;
|
||||||
|
VirtualDisk -> CDROM;
|
||||||
|
VirtualDisk -> NVME;
|
||||||
|
|
||||||
|
BlueToothStack;
|
||||||
|
}
|
677
contrib/DriverDepGraph.svg
Normal file
677
contrib/DriverDepGraph.svg
Normal file
|
@ -0,0 +1,677 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<!-- Generated by graphviz version 2.40.1 (20161225.0304)
|
||||||
|
-->
|
||||||
|
<!-- Title: Drivers Pages: 1 -->
|
||||||
|
<svg width="2629pt" height="404pt" viewBox="0.00 0.00 2628.89 404.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||||
|
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 400)">
|
||||||
|
<title>Drivers</title>
|
||||||
|
<polygon fill="#ffffff" stroke="transparent" points="-4,4 -4,-400 2624.8933,-400 2624.8933,4 -4,4"/>
|
||||||
|
<!-- InitSystem -->
|
||||||
|
<g id="node1" class="node">
|
||||||
|
<title>InitSystem</title>
|
||||||
|
<ellipse fill="none" stroke="#000000" cx="443.0953" cy="-378" rx="52.7642" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="443.0953" y="-373.8" font-family="Times,serif" font-size="14.00" fill="#000000">InitSystem</text>
|
||||||
|
</g>
|
||||||
|
<!-- VFS -->
|
||||||
|
<g id="node2" class="node">
|
||||||
|
<title>VFS</title>
|
||||||
|
<ellipse fill="none" stroke="#000000" cx="409.0953" cy="-234" rx="28.991" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="409.0953" y="-229.8" font-family="Times,serif" font-size="14.00" fill="#000000">VFS</text>
|
||||||
|
</g>
|
||||||
|
<!-- InitSystem->VFS -->
|
||||||
|
<g id="edge1" class="edge">
|
||||||
|
<title>InitSystem->VFS</title>
|
||||||
|
<path fill="none" stroke="#000000" d="M437.8111,-360.0742C434.7997,-349.5989 431.0497,-336.0989 428.0953,-324 423.0522,-303.3476 418.1161,-279.8366 414.5395,-262.025"/>
|
||||||
|
<polygon fill="#000000" stroke="#000000" points="417.9306,-261.1317 412.55,-252.0049 411.0646,-262.4951 417.9306,-261.1317"/>
|
||||||
|
</g>
|
||||||
|
<!-- Logger -->
|
||||||
|
<g id="node3" class="node">
|
||||||
|
<title>Logger</title>
|
||||||
|
<ellipse fill="none" stroke="#000000" cx="476.0953" cy="-306" rx="38.8459" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="476.0953" y="-301.8" font-family="Times,serif" font-size="14.00" fill="#000000">Logger</text>
|
||||||
|
</g>
|
||||||
|
<!-- InitSystem->Logger -->
|
||||||
|
<g id="edge2" class="edge">
|
||||||
|
<title>InitSystem->Logger</title>
|
||||||
|
<path fill="none" stroke="#000000" d="M451.2526,-360.2022C454.981,-352.0675 459.4807,-342.2501 463.6203,-333.2181"/>
|
||||||
|
<polygon fill="#000000" stroke="#000000" points="466.9326,-334.3915 467.9175,-323.8425 460.5691,-331.4749 466.9326,-334.3915"/>
|
||||||
|
</g>
|
||||||
|
<!-- Fat32 -->
|
||||||
|
<g id="node46" class="node">
|
||||||
|
<title>Fat32</title>
|
||||||
|
<ellipse fill="none" stroke="#000000" cx="282.0953" cy="-162" rx="33.0643" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="282.0953" y="-157.8" font-family="Times,serif" font-size="14.00" fill="#000000">Fat32</text>
|
||||||
|
</g>
|
||||||
|
<!-- VFS->Fat32 -->
|
||||||
|
<g id="edge46" class="edge">
|
||||||
|
<title>VFS->Fat32</title>
|
||||||
|
<path fill="none" stroke="#000000" d="M387.5515,-221.7862C367.3094,-210.3103 336.7716,-192.9976 313.7591,-179.9511"/>
|
||||||
|
<polygon fill="#000000" stroke="#000000" points="315.4597,-176.8919 305.0343,-175.0048 312.0074,-182.9814 315.4597,-176.8919"/>
|
||||||
|
</g>
|
||||||
|
<!-- TarFS -->
|
||||||
|
<g id="node47" class="node">
|
||||||
|
<title>TarFS</title>
|
||||||
|
<ellipse fill="none" stroke="#000000" cx="368.0953" cy="-162" rx="35.3489" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="368.0953" y="-157.8" font-family="Times,serif" font-size="14.00" fill="#000000">TarFS</text>
|
||||||
|
</g>
|
||||||
|
<!-- VFS->TarFS -->
|
||||||
|
<g id="edge47" class="edge">
|
||||||
|
<title>VFS->TarFS</title>
|
||||||
|
<path fill="none" stroke="#000000" d="M399.3789,-216.937C394.4978,-208.3654 388.4765,-197.7914 383.0242,-188.2165"/>
|
||||||
|
<polygon fill="#000000" stroke="#000000" points="386.0167,-186.3986 378.0268,-179.4407 379.9338,-189.8625 386.0167,-186.3986"/>
|
||||||
|
</g>
|
||||||
|
<!-- Ext2 -->
|
||||||
|
<g id="node48" class="node">
|
||||||
|
<title>Ext2</title>
|
||||||
|
<ellipse fill="none" stroke="#000000" cx="450.0953" cy="-162" rx="29.0548" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="450.0953" y="-157.8" font-family="Times,serif" font-size="14.00" fill="#000000">Ext2</text>
|
||||||
|
</g>
|
||||||
|
<!-- VFS->Ext2 -->
|
||||||
|
<g id="edge48" class="edge">
|
||||||
|
<title>VFS->Ext2</title>
|
||||||
|
<path fill="none" stroke="#000000" d="M418.8117,-216.937C423.6928,-208.3654 429.7141,-197.7914 435.1664,-188.2165"/>
|
||||||
|
<polygon fill="#000000" stroke="#000000" points="438.2568,-189.8625 440.1638,-179.4407 432.1739,-186.3986 438.2568,-189.8625"/>
|
||||||
|
</g>
|
||||||
|
<!-- Logger->VFS -->
|
||||||
|
<g id="edge28" class="edge">
|
||||||
|
<title>Logger->VFS</title>
|
||||||
|
<path fill="none" stroke="#000000" d="M460.5557,-289.3008C451.6839,-279.7669 440.4261,-267.6689 430.7037,-257.221"/>
|
||||||
|
<polygon fill="#000000" stroke="#000000" points="433.0079,-254.5593 423.6333,-249.6229 427.8834,-259.328 433.0079,-254.5593"/>
|
||||||
|
</g>
|
||||||
|
<!-- Serial -->
|
||||||
|
<g id="node29" class="node">
|
||||||
|
<title>Serial</title>
|
||||||
|
<ellipse fill="none" stroke="#000000" cx="1400.0953" cy="-234" rx="33.6208" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="1400.0953" y="-229.8" font-family="Times,serif" font-size="14.00" fill="#000000">Serial</text>
|
||||||
|
</g>
|
||||||
|
<!-- Logger->Serial -->
|
||||||
|
<g id="edge27" class="edge">
|
||||||
|
<title>Logger->Serial</title>
|
||||||
|
<path fill="none" stroke="#000000" d="M515.2345,-305.3369C663.9095,-302.5495 1193.4867,-290.1059 1357.0953,-252 1359.9033,-251.346 1362.7624,-250.5254 1365.6042,-249.5973"/>
|
||||||
|
<polygon fill="#000000" stroke="#000000" points="1366.9168,-252.844 1375.0991,-246.1134 1364.5054,-246.2724 1366.9168,-252.844"/>
|
||||||
|
</g>
|
||||||
|
<!-- TCP -->
|
||||||
|
<g id="node4" class="node">
|
||||||
|
<title>TCP</title>
|
||||||
|
<ellipse fill="none" stroke="#000000" cx="1436.0953" cy="-378" rx="28.991" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="1436.0953" y="-373.8" font-family="Times,serif" font-size="14.00" fill="#000000">TCP</text>
|
||||||
|
</g>
|
||||||
|
<!-- NetworkingStack -->
|
||||||
|
<g id="node5" class="node">
|
||||||
|
<title>NetworkingStack</title>
|
||||||
|
<ellipse fill="none" stroke="#000000" cx="1398.0953" cy="-306" rx="78.7318" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="1398.0953" y="-301.8" font-family="Times,serif" font-size="14.00" fill="#000000">NetworkingStack</text>
|
||||||
|
</g>
|
||||||
|
<!-- TCP->NetworkingStack -->
|
||||||
|
<g id="edge3" class="edge">
|
||||||
|
<title>TCP->NetworkingStack</title>
|
||||||
|
<path fill="none" stroke="#000000" d="M1426.8966,-360.5708C1422.5145,-352.2679 1417.1746,-342.1502 1412.2886,-332.8925"/>
|
||||||
|
<polygon fill="#000000" stroke="#000000" points="1415.3692,-331.2308 1407.6062,-324.0206 1409.1785,-334.4981 1415.3692,-331.2308"/>
|
||||||
|
</g>
|
||||||
|
<!-- PhysLayer -->
|
||||||
|
<g id="node7" class="node">
|
||||||
|
<title>PhysLayer</title>
|
||||||
|
<ellipse fill="none" stroke="#000000" cx="1296.0953" cy="-234" rx="52.1675" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="1296.0953" y="-229.8" font-family="Times,serif" font-size="14.00" fill="#000000">PhysLayer</text>
|
||||||
|
</g>
|
||||||
|
<!-- NetworkingStack->PhysLayer -->
|
||||||
|
<g id="edge5" class="edge">
|
||||||
|
<title>NetworkingStack->PhysLayer</title>
|
||||||
|
<path fill="none" stroke="#000000" d="M1373.6638,-288.7542C1359.8688,-279.0166 1342.4757,-266.7391 1327.6572,-256.279"/>
|
||||||
|
<polygon fill="#000000" stroke="#000000" points="1329.4647,-253.2707 1319.2765,-250.3632 1325.4278,-258.9895 1329.4647,-253.2707"/>
|
||||||
|
</g>
|
||||||
|
<!-- UDP -->
|
||||||
|
<g id="node6" class="node">
|
||||||
|
<title>UDP</title>
|
||||||
|
<ellipse fill="none" stroke="#000000" cx="1359.0953" cy="-378" rx="30.1958" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="1359.0953" y="-373.8" font-family="Times,serif" font-size="14.00" fill="#000000">UDP</text>
|
||||||
|
</g>
|
||||||
|
<!-- UDP->NetworkingStack -->
|
||||||
|
<g id="edge4" class="edge">
|
||||||
|
<title>UDP->NetworkingStack</title>
|
||||||
|
<path fill="none" stroke="#000000" d="M1368.5361,-360.5708C1373.0335,-352.2679 1378.5139,-342.1502 1383.5285,-332.8925"/>
|
||||||
|
<polygon fill="#000000" stroke="#000000" points="1386.6488,-334.4805 1388.3341,-324.0206 1380.4937,-331.1465 1386.6488,-334.4805"/>
|
||||||
|
</g>
|
||||||
|
<!-- Ethernet -->
|
||||||
|
<g id="node8" class="node">
|
||||||
|
<title>Ethernet</title>
|
||||||
|
<ellipse fill="none" stroke="#000000" cx="852.0953" cy="-162" rx="43.9983" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="852.0953" y="-157.8" font-family="Times,serif" font-size="14.00" fill="#000000">Ethernet</text>
|
||||||
|
</g>
|
||||||
|
<!-- PhysLayer->Ethernet -->
|
||||||
|
<g id="edge6" class="edge">
|
||||||
|
<title>PhysLayer->Ethernet</title>
|
||||||
|
<path fill="none" stroke="#000000" d="M1248.5795,-226.2947C1164.418,-212.6469 989.8747,-184.3426 903.2098,-170.2888"/>
|
||||||
|
<polygon fill="#000000" stroke="#000000" points="903.5198,-166.7935 893.0885,-168.6475 902.3993,-173.7032 903.5198,-166.7935"/>
|
||||||
|
</g>
|
||||||
|
<!-- Wifi -->
|
||||||
|
<g id="node16" class="node">
|
||||||
|
<title>Wifi</title>
|
||||||
|
<ellipse fill="none" stroke="#000000" cx="1314.0953" cy="-162" rx="28.9696" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="1314.0953" y="-157.8" font-family="Times,serif" font-size="14.00" fill="#000000">Wifi</text>
|
||||||
|
</g>
|
||||||
|
<!-- PhysLayer->Wifi -->
|
||||||
|
<g id="edge14" class="edge">
|
||||||
|
<title>PhysLayer->Wifi</title>
|
||||||
|
<path fill="none" stroke="#000000" d="M1300.6375,-215.8314C1302.6137,-207.9266 1304.9735,-198.4872 1307.1612,-189.7365"/>
|
||||||
|
<polygon fill="#000000" stroke="#000000" points="1310.587,-190.4637 1309.6169,-179.9134 1303.796,-188.7659 1310.587,-190.4637"/>
|
||||||
|
</g>
|
||||||
|
<!-- Threec90x -->
|
||||||
|
<g id="node9" class="node">
|
||||||
|
<title>Threec90x</title>
|
||||||
|
<ellipse fill="none" stroke="#000000" cx="452.0953" cy="-90" rx="52.1501" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="452.0953" y="-85.8" font-family="Times,serif" font-size="14.00" fill="#000000">Threec90x</text>
|
||||||
|
</g>
|
||||||
|
<!-- Ethernet->Threec90x -->
|
||||||
|
<g id="edge7" class="edge">
|
||||||
|
<title>Ethernet->Threec90x</title>
|
||||||
|
<path fill="none" stroke="#000000" d="M810.0127,-157.0708C745.598,-149.1277 618.8877,-131.9297 513.0953,-108 508.9759,-107.0682 504.7257,-106.013 500.4758,-104.8921"/>
|
||||||
|
<polygon fill="#000000" stroke="#000000" points="501.1913,-101.4591 490.6213,-102.1845 499.3366,-108.2089 501.1913,-101.4591"/>
|
||||||
|
</g>
|
||||||
|
<!-- Intel8254x -->
|
||||||
|
<g id="node10" class="node">
|
||||||
|
<title>Intel8254x</title>
|
||||||
|
<ellipse fill="none" stroke="#000000" cx="575.0953" cy="-90" rx="52.7527" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="575.0953" y="-85.8" font-family="Times,serif" font-size="14.00" fill="#000000">Intel8254x</text>
|
||||||
|
</g>
|
||||||
|
<!-- Ethernet->Intel8254x -->
|
||||||
|
<g id="edge8" class="edge">
|
||||||
|
<title>Ethernet->Intel8254x</title>
|
||||||
|
<path fill="none" stroke="#000000" d="M814.1219,-153.017C770.8839,-142.6703 698.1916,-124.9158 636.0953,-108 632.3083,-106.9684 628.3969,-105.8762 624.4686,-104.7602"/>
|
||||||
|
<polygon fill="#000000" stroke="#000000" points="625.3084,-101.3599 614.7304,-101.9578 623.3725,-108.0868 625.3084,-101.3599"/>
|
||||||
|
</g>
|
||||||
|
<!-- Ne2000 -->
|
||||||
|
<g id="node11" class="node">
|
||||||
|
<title>Ne2000</title>
|
||||||
|
<ellipse fill="none" stroke="#000000" cx="687.0953" cy="-90" rx="41.7172" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="687.0953" y="-85.8" font-family="Times,serif" font-size="14.00" fill="#000000">Ne2000</text>
|
||||||
|
</g>
|
||||||
|
<!-- Ethernet->Ne2000 -->
|
||||||
|
<g id="edge9" class="edge">
|
||||||
|
<title>Ethernet->Ne2000</title>
|
||||||
|
<path fill="none" stroke="#000000" d="M821.8318,-148.7941C794.9169,-137.0494 755.4014,-119.8063 726.1176,-107.0279"/>
|
||||||
|
<polygon fill="#000000" stroke="#000000" points="727.1771,-103.6716 716.6118,-102.8799 724.3774,-110.0873 727.1771,-103.6716"/>
|
||||||
|
</g>
|
||||||
|
<!-- RTL8139 -->
|
||||||
|
<g id="node12" class="node">
|
||||||
|
<title>RTL8139</title>
|
||||||
|
<ellipse fill="none" stroke="#000000" cx="795.0953" cy="-90" rx="48.6791" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="795.0953" y="-85.8" font-family="Times,serif" font-size="14.00" fill="#000000">RTL8139</text>
|
||||||
|
</g>
|
||||||
|
<!-- Ethernet->RTL8139 -->
|
||||||
|
<g id="edge10" class="edge">
|
||||||
|
<title>Ethernet->RTL8139</title>
|
||||||
|
<path fill="none" stroke="#000000" d="M838.2972,-144.5708C831.4167,-135.8797 822.962,-125.2001 815.3618,-115.5998"/>
|
||||||
|
<polygon fill="#000000" stroke="#000000" points="817.9151,-113.1862 808.9639,-107.5182 812.4268,-117.5312 817.9151,-113.1862"/>
|
||||||
|
</g>
|
||||||
|
<!-- RTL8169 -->
|
||||||
|
<g id="node13" class="node">
|
||||||
|
<title>RTL8169</title>
|
||||||
|
<ellipse fill="none" stroke="#000000" cx="910.0953" cy="-90" rx="48.6791" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="910.0953" y="-85.8" font-family="Times,serif" font-size="14.00" fill="#000000">RTL8169</text>
|
||||||
|
</g>
|
||||||
|
<!-- Ethernet->RTL8169 -->
|
||||||
|
<g id="edge11" class="edge">
|
||||||
|
<title>Ethernet->RTL8169</title>
|
||||||
|
<path fill="none" stroke="#000000" d="M866.1355,-144.5708C873.2597,-135.7269 882.0427,-124.8239 889.8803,-115.0945"/>
|
||||||
|
<polygon fill="#000000" stroke="#000000" points="892.6367,-117.2519 896.1844,-107.2687 887.1854,-112.8606 892.6367,-117.2519"/>
|
||||||
|
</g>
|
||||||
|
<!-- IntelEtherneti217 -->
|
||||||
|
<g id="node14" class="node">
|
||||||
|
<title>IntelEtherneti217</title>
|
||||||
|
<ellipse fill="none" stroke="#000000" cx="1055.0953" cy="-90" rx="78.7298" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="1055.0953" y="-85.8" font-family="Times,serif" font-size="14.00" fill="#000000">IntelEtherneti217</text>
|
||||||
|
</g>
|
||||||
|
<!-- Ethernet->IntelEtherneti217 -->
|
||||||
|
<g id="edge12" class="edge">
|
||||||
|
<title>Ethernet->IntelEtherneti217</title>
|
||||||
|
<path fill="none" stroke="#000000" d="M885.6166,-150.1107C917.4561,-138.8178 965.8122,-121.6669 1002.7343,-108.5714"/>
|
||||||
|
<polygon fill="#000000" stroke="#000000" points="1004.084,-111.8064 1012.3387,-105.1649 1001.744,-105.2091 1004.084,-111.8064"/>
|
||||||
|
</g>
|
||||||
|
<!-- AMDPCnet -->
|
||||||
|
<g id="node15" class="node">
|
||||||
|
<title>AMDPCnet</title>
|
||||||
|
<ellipse fill="none" stroke="#000000" cx="1209.0953" cy="-90" rx="57.3418" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="1209.0953" y="-85.8" font-family="Times,serif" font-size="14.00" fill="#000000">AMDPCnet</text>
|
||||||
|
</g>
|
||||||
|
<!-- Ethernet->AMDPCnet -->
|
||||||
|
<g id="edge13" class="edge">
|
||||||
|
<title>Ethernet->AMDPCnet</title>
|
||||||
|
<path fill="none" stroke="#000000" d="M893.2785,-155.4619C949.8599,-146.2284 1054.687,-128.222 1143.0953,-108 1147.513,-106.9895 1152.0799,-105.8804 1156.6536,-104.7245"/>
|
||||||
|
<polygon fill="#000000" stroke="#000000" points="1157.8203,-108.0378 1166.6214,-102.1393 1156.063,-101.2619 1157.8203,-108.0378"/>
|
||||||
|
</g>
|
||||||
|
<!-- Eight02Dot11 -->
|
||||||
|
<g id="node17" class="node">
|
||||||
|
<title>Eight02Dot11</title>
|
||||||
|
<ellipse fill="none" stroke="#000000" cx="1350.0953" cy="-90" rx="65.5161" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="1350.0953" y="-85.8" font-family="Times,serif" font-size="14.00" fill="#000000">Eight02Dot11</text>
|
||||||
|
</g>
|
||||||
|
<!-- Wifi->Eight02Dot11 -->
|
||||||
|
<g id="edge15" class="edge">
|
||||||
|
<title>Wifi->Eight02Dot11</title>
|
||||||
|
<path fill="none" stroke="#000000" d="M1322.8099,-144.5708C1326.9181,-136.3544 1331.9149,-126.3608 1336.5042,-117.1821"/>
|
||||||
|
<polygon fill="#000000" stroke="#000000" points="1339.7433,-118.5301 1341.085,-108.0206 1333.4823,-115.3996 1339.7433,-118.5301"/>
|
||||||
|
</g>
|
||||||
|
<!-- Audio -->
|
||||||
|
<g id="node18" class="node">
|
||||||
|
<title>Audio</title>
|
||||||
|
<ellipse fill="none" stroke="#000000" cx="2420.0953" cy="-378" rx="35.3548" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="2420.0953" y="-373.8" font-family="Times,serif" font-size="14.00" fill="#000000">Audio</text>
|
||||||
|
</g>
|
||||||
|
<!-- PCSpeaker -->
|
||||||
|
<g id="node19" class="node">
|
||||||
|
<title>PCSpeaker</title>
|
||||||
|
<ellipse fill="none" stroke="#000000" cx="2348.0953" cy="-306" rx="53.8905" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="2348.0953" y="-301.8" font-family="Times,serif" font-size="14.00" fill="#000000">PCSpeaker</text>
|
||||||
|
</g>
|
||||||
|
<!-- Audio->PCSpeaker -->
|
||||||
|
<g id="edge16" class="edge">
|
||||||
|
<title>Audio->PCSpeaker</title>
|
||||||
|
<path fill="none" stroke="#000000" d="M2403.7574,-361.6621C2394.5427,-352.4474 2382.8487,-340.7534 2372.5602,-330.4649"/>
|
||||||
|
<polygon fill="#000000" stroke="#000000" points="2374.9186,-327.8735 2365.3726,-323.2773 2369.9688,-332.8233 2374.9186,-327.8735"/>
|
||||||
|
</g>
|
||||||
|
<!-- SoundBlaster16 -->
|
||||||
|
<g id="node20" class="node">
|
||||||
|
<title>SoundBlaster16</title>
|
||||||
|
<ellipse fill="none" stroke="#000000" cx="2493.0953" cy="-306" rx="72.9547" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="2493.0953" y="-301.8" font-family="Times,serif" font-size="14.00" fill="#000000">SoundBlaster16</text>
|
||||||
|
</g>
|
||||||
|
<!-- Audio->SoundBlaster16 -->
|
||||||
|
<g id="edge17" class="edge">
|
||||||
|
<title>Audio->SoundBlaster16</title>
|
||||||
|
<path fill="none" stroke="#000000" d="M2436.2964,-362.0209C2445.5577,-352.8864 2457.3757,-341.2303 2467.8308,-330.9184"/>
|
||||||
|
<polygon fill="#000000" stroke="#000000" points="2470.485,-333.2166 2475.1469,-323.7025 2465.5695,-328.2328 2470.485,-333.2166"/>
|
||||||
|
</g>
|
||||||
|
<!-- RNG -->
|
||||||
|
<g id="node21" class="node">
|
||||||
|
<title>RNG</title>
|
||||||
|
<ellipse fill="none" stroke="#000000" cx="1676.0953" cy="-378" rx="31.339" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="1676.0953" y="-373.8" font-family="Times,serif" font-size="14.00" fill="#000000">RNG</text>
|
||||||
|
</g>
|
||||||
|
<!-- RNG->NetworkingStack -->
|
||||||
|
<g id="edge19" class="edge">
|
||||||
|
<title>RNG->NetworkingStack</title>
|
||||||
|
<path fill="none" stroke="#000000" d="M1647.3915,-370.5659C1603.4593,-359.1878 1518.5016,-337.1844 1460.0749,-322.0523"/>
|
||||||
|
<polygon fill="#000000" stroke="#000000" points="1460.7723,-318.6175 1450.2142,-319.4984 1459.0172,-325.3939 1460.7723,-318.6175"/>
|
||||||
|
</g>
|
||||||
|
<!-- CpuRNG -->
|
||||||
|
<g id="node22" class="node">
|
||||||
|
<title>CpuRNG</title>
|
||||||
|
<ellipse fill="none" stroke="#000000" cx="1725.0953" cy="-306" rx="47.5332" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="1725.0953" y="-301.8" font-family="Times,serif" font-size="14.00" fill="#000000">CpuRNG</text>
|
||||||
|
</g>
|
||||||
|
<!-- RNG->CpuRNG -->
|
||||||
|
<g id="edge18" class="edge">
|
||||||
|
<title>RNG->CpuRNG</title>
|
||||||
|
<path fill="none" stroke="#000000" d="M1687.7076,-360.937C1693.6012,-352.277 1700.8858,-341.5731 1707.4548,-331.9207"/>
|
||||||
|
<polygon fill="#000000" stroke="#000000" points="1710.4932,-333.677 1713.2259,-323.4407 1704.7062,-329.7386 1710.4932,-333.677"/>
|
||||||
|
</g>
|
||||||
|
<!-- GraphicsLibrary -->
|
||||||
|
<g id="node23" class="node">
|
||||||
|
<title>GraphicsLibrary</title>
|
||||||
|
<ellipse fill="none" stroke="#000000" cx="2201.0953" cy="-306" rx="74.6976" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="2201.0953" y="-301.8" font-family="Times,serif" font-size="14.00" fill="#000000">GraphicsLibrary</text>
|
||||||
|
</g>
|
||||||
|
<!-- RNG->GraphicsLibrary -->
|
||||||
|
<g id="edge20" class="edge">
|
||||||
|
<title>RNG->GraphicsLibrary</title>
|
||||||
|
<path fill="none" stroke="#000000" d="M1706.9764,-373.7649C1788.0277,-362.6493 2008.637,-332.3943 2125.7369,-316.3349"/>
|
||||||
|
<polygon fill="#000000" stroke="#000000" points="2126.2743,-319.794 2135.706,-314.9677 2125.3232,-312.8589 2126.2743,-319.794"/>
|
||||||
|
</g>
|
||||||
|
<!-- Input -->
|
||||||
|
<g id="node24" class="node">
|
||||||
|
<title>Input</title>
|
||||||
|
<ellipse fill="none" stroke="#000000" cx="1628.0953" cy="-306" rx="31.341" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="1628.0953" y="-301.8" font-family="Times,serif" font-size="14.00" fill="#000000">Input</text>
|
||||||
|
</g>
|
||||||
|
<!-- RNG->Input -->
|
||||||
|
<g id="edge21" class="edge">
|
||||||
|
<title>RNG->Input</title>
|
||||||
|
<path fill="none" stroke="#000000" d="M1664.72,-360.937C1658.8617,-352.1496 1651.6005,-341.2579 1645.0924,-331.4956"/>
|
||||||
|
<polygon fill="#000000" stroke="#000000" points="1647.8482,-329.3196 1639.389,-322.9405 1642.0238,-333.2025 1647.8482,-329.3196"/>
|
||||||
|
</g>
|
||||||
|
<!-- ShaderCompiler -->
|
||||||
|
<g id="node26" class="node">
|
||||||
|
<title>ShaderCompiler</title>
|
||||||
|
<ellipse fill="none" stroke="#000000" cx="2303.0953" cy="-234" rx="74.1566" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="2303.0953" y="-229.8" font-family="Times,serif" font-size="14.00" fill="#000000">ShaderCompiler</text>
|
||||||
|
</g>
|
||||||
|
<!-- GraphicsLibrary->ShaderCompiler -->
|
||||||
|
<g id="edge23" class="edge">
|
||||||
|
<title>GraphicsLibrary->ShaderCompiler</title>
|
||||||
|
<path fill="none" stroke="#000000" d="M2225.2679,-288.937C2238.7614,-279.4122 2255.7576,-267.4149 2270.4221,-257.0635"/>
|
||||||
|
<polygon fill="#000000" stroke="#000000" points="2272.5915,-259.8163 2278.7427,-251.19 2268.5546,-254.0975 2272.5915,-259.8163"/>
|
||||||
|
</g>
|
||||||
|
<!-- GraphicsDriver -->
|
||||||
|
<g id="node27" class="node">
|
||||||
|
<title>GraphicsDriver</title>
|
||||||
|
<ellipse fill="none" stroke="#000000" cx="2303.0953" cy="-162" rx="71.1843" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="2303.0953" y="-157.8" font-family="Times,serif" font-size="14.00" fill="#000000">GraphicsDriver</text>
|
||||||
|
</g>
|
||||||
|
<!-- GraphicsLibrary->GraphicsDriver -->
|
||||||
|
<g id="edge25" class="edge">
|
||||||
|
<title>GraphicsLibrary->GraphicsDriver</title>
|
||||||
|
<path fill="none" stroke="#000000" d="M2200.955,-287.8528C2201.653,-268.4612 2205.2852,-237.6002 2220.0953,-216 2229.5949,-202.1451 2243.9358,-190.9993 2258.0378,-182.5131"/>
|
||||||
|
<polygon fill="#000000" stroke="#000000" points="2259.7731,-185.5528 2266.7421,-177.5726 2256.3176,-179.4651 2259.7731,-185.5528"/>
|
||||||
|
</g>
|
||||||
|
<!-- Input->Serial -->
|
||||||
|
<g id="edge32" class="edge">
|
||||||
|
<title>Input->Serial</title>
|
||||||
|
<path fill="none" stroke="#000000" d="M1599.2541,-298.6597C1562.5858,-289.0822 1497.5027,-271.2595 1443.0953,-252 1440.6921,-251.1493 1438.2293,-250.2354 1435.758,-249.2868"/>
|
||||||
|
<polygon fill="#000000" stroke="#000000" points="1436.8768,-245.9651 1426.2915,-245.5159 1434.2863,-252.4682 1436.8768,-245.9651"/>
|
||||||
|
</g>
|
||||||
|
<!-- Keyboard -->
|
||||||
|
<g id="node30" class="node">
|
||||||
|
<title>Keyboard</title>
|
||||||
|
<ellipse fill="none" stroke="#000000" cx="1628.0953" cy="-234" rx="49.2202" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="1628.0953" y="-229.8" font-family="Times,serif" font-size="14.00" fill="#000000">Keyboard</text>
|
||||||
|
</g>
|
||||||
|
<!-- Input->Keyboard -->
|
||||||
|
<g id="edge29" class="edge">
|
||||||
|
<title>Input->Keyboard</title>
|
||||||
|
<path fill="none" stroke="#000000" d="M1628.0953,-287.8314C1628.0953,-280.131 1628.0953,-270.9743 1628.0953,-262.4166"/>
|
||||||
|
<polygon fill="#000000" stroke="#000000" points="1631.5954,-262.4132 1628.0953,-252.4133 1624.5954,-262.4133 1631.5954,-262.4132"/>
|
||||||
|
</g>
|
||||||
|
<!-- GraphicsTablet -->
|
||||||
|
<g id="node31" class="node">
|
||||||
|
<title>GraphicsTablet</title>
|
||||||
|
<ellipse fill="none" stroke="#000000" cx="1766.0953" cy="-234" rx="70.622" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="1766.0953" y="-229.8" font-family="Times,serif" font-size="14.00" fill="#000000">GraphicsTablet</text>
|
||||||
|
</g>
|
||||||
|
<!-- Input->GraphicsTablet -->
|
||||||
|
<g id="edge30" class="edge">
|
||||||
|
<title>Input->GraphicsTablet</title>
|
||||||
|
<path fill="none" stroke="#000000" d="M1651.5051,-293.7862C1671.8931,-283.149 1701.8932,-267.4967 1726.0835,-254.8757"/>
|
||||||
|
<polygon fill="#000000" stroke="#000000" points="1727.7912,-257.9325 1735.0381,-250.2038 1724.5532,-251.7264 1727.7912,-257.9325"/>
|
||||||
|
</g>
|
||||||
|
<!-- Mouse -->
|
||||||
|
<g id="node32" class="node">
|
||||||
|
<title>Mouse</title>
|
||||||
|
<ellipse fill="none" stroke="#000000" cx="1892.0953" cy="-234" rx="37.1405" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="1892.0953" y="-229.8" font-family="Times,serif" font-size="14.00" fill="#000000">Mouse</text>
|
||||||
|
</g>
|
||||||
|
<!-- Input->Mouse -->
|
||||||
|
<g id="edge31" class="edge">
|
||||||
|
<title>Input->Mouse</title>
|
||||||
|
<path fill="none" stroke="#000000" d="M1652.2936,-294.0726C1657.4281,-291.8373 1662.8757,-289.6789 1668.0953,-288 1744.9312,-263.2853 1768.6672,-274.7915 1846.0953,-252 1848.7047,-251.2319 1851.3737,-250.3778 1854.0474,-249.4708"/>
|
||||||
|
<polygon fill="#000000" stroke="#000000" points="1855.4284,-252.6936 1863.6524,-246.014 1853.058,-246.1072 1855.4284,-252.6936"/>
|
||||||
|
</g>
|
||||||
|
<!-- Controllers -->
|
||||||
|
<g id="node33" class="node">
|
||||||
|
<title>Controllers</title>
|
||||||
|
<ellipse fill="none" stroke="#000000" cx="1506.0953" cy="-234" rx="54.4701" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="1506.0953" y="-229.8" font-family="Times,serif" font-size="14.00" fill="#000000">Controllers</text>
|
||||||
|
</g>
|
||||||
|
<!-- Input->Controllers -->
|
||||||
|
<g id="edge33" class="edge">
|
||||||
|
<title>Input->Controllers</title>
|
||||||
|
<path fill="none" stroke="#000000" d="M1606.002,-292.9613C1588.1773,-282.4418 1562.7456,-267.433 1542.0025,-255.1911"/>
|
||||||
|
<polygon fill="#000000" stroke="#000000" points="1543.5325,-252.03 1533.1415,-249.9617 1539.9747,-258.0585 1543.5325,-252.03"/>
|
||||||
|
</g>
|
||||||
|
<!-- Slint -->
|
||||||
|
<g id="node25" class="node">
|
||||||
|
<title>Slint</title>
|
||||||
|
<ellipse fill="none" stroke="#000000" cx="2201.0953" cy="-378" rx="29.0701" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="2201.0953" y="-373.8" font-family="Times,serif" font-size="14.00" fill="#000000">Slint</text>
|
||||||
|
</g>
|
||||||
|
<!-- Slint->GraphicsLibrary -->
|
||||||
|
<g id="edge22" class="edge">
|
||||||
|
<title>Slint->GraphicsLibrary</title>
|
||||||
|
<path fill="none" stroke="#000000" d="M2201.0953,-359.8314C2201.0953,-352.131 2201.0953,-342.9743 2201.0953,-334.4166"/>
|
||||||
|
<polygon fill="#000000" stroke="#000000" points="2204.5954,-334.4132 2201.0953,-324.4133 2197.5954,-334.4133 2204.5954,-334.4132"/>
|
||||||
|
</g>
|
||||||
|
<!-- ShaderCompiler->GraphicsDriver -->
|
||||||
|
<g id="edge24" class="edge">
|
||||||
|
<title>ShaderCompiler->GraphicsDriver</title>
|
||||||
|
<path fill="none" stroke="#000000" d="M2303.0953,-215.8314C2303.0953,-208.131 2303.0953,-198.9743 2303.0953,-190.4166"/>
|
||||||
|
<polygon fill="#000000" stroke="#000000" points="2306.5954,-190.4132 2303.0953,-180.4133 2299.5954,-190.4133 2306.5954,-190.4132"/>
|
||||||
|
</g>
|
||||||
|
<!-- GPU -->
|
||||||
|
<g id="node28" class="node">
|
||||||
|
<title>GPU</title>
|
||||||
|
<ellipse fill="none" stroke="#000000" cx="2303.0953" cy="-90" rx="30.1958" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="2303.0953" y="-85.8" font-family="Times,serif" font-size="14.00" fill="#000000">GPU</text>
|
||||||
|
</g>
|
||||||
|
<!-- GraphicsDriver->GPU -->
|
||||||
|
<g id="edge26" class="edge">
|
||||||
|
<title>GraphicsDriver->GPU</title>
|
||||||
|
<path fill="none" stroke="#000000" d="M2303.0953,-143.8314C2303.0953,-136.131 2303.0953,-126.9743 2303.0953,-118.4166"/>
|
||||||
|
<polygon fill="#000000" stroke="#000000" points="2306.5954,-118.4132 2303.0953,-108.4133 2299.5954,-118.4133 2306.5954,-118.4132"/>
|
||||||
|
</g>
|
||||||
|
<!-- PS2Mouse -->
|
||||||
|
<g id="node41" class="node">
|
||||||
|
<title>PS2Mouse</title>
|
||||||
|
<ellipse fill="none" stroke="#000000" cx="2161.0953" cy="-162" rx="52.77" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="2161.0953" y="-157.8" font-family="Times,serif" font-size="14.00" fill="#000000">PS2Mouse</text>
|
||||||
|
</g>
|
||||||
|
<!-- Mouse->PS2Mouse -->
|
||||||
|
<g id="edge41" class="edge">
|
||||||
|
<title>Mouse->PS2Mouse</title>
|
||||||
|
<path fill="none" stroke="#000000" d="M1925.5125,-225.5822C1966.4961,-215.1894 2038.0464,-196.8215 2099.0953,-180 2102.9364,-178.9416 2106.9061,-177.8301 2110.8948,-176.7007"/>
|
||||||
|
<polygon fill="#000000" stroke="#000000" points="2112.1314,-179.9875 2120.786,-173.8761 2110.2093,-173.2566 2112.1314,-179.9875"/>
|
||||||
|
</g>
|
||||||
|
<!-- USBMouse -->
|
||||||
|
<g id="node42" class="node">
|
||||||
|
<title>USBMouse</title>
|
||||||
|
<ellipse fill="none" stroke="#000000" cx="1689.0953" cy="-162" rx="56.1995" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="1689.0953" y="-157.8" font-family="Times,serif" font-size="14.00" fill="#000000">USBMouse</text>
|
||||||
|
</g>
|
||||||
|
<!-- Mouse->USBMouse -->
|
||||||
|
<g id="edge42" class="edge">
|
||||||
|
<title>Mouse->USBMouse</title>
|
||||||
|
<path fill="none" stroke="#000000" d="M1862.9639,-222.3895C1857.3804,-220.2241 1851.569,-218.0113 1846.0953,-216 1810.0856,-202.7684 1769.0818,-188.6989 1738.0104,-178.2392"/>
|
||||||
|
<polygon fill="#000000" stroke="#000000" points="1738.8841,-174.8407 1728.2902,-174.9757 1736.6561,-181.4766 1738.8841,-174.8407"/>
|
||||||
|
</g>
|
||||||
|
<!-- MouseTrackPad -->
|
||||||
|
<g id="node44" class="node">
|
||||||
|
<title>MouseTrackPad</title>
|
||||||
|
<ellipse fill="none" stroke="#000000" cx="1837.0953" cy="-162" rx="74.1393" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="1837.0953" y="-157.8" font-family="Times,serif" font-size="14.00" fill="#000000">MouseTrackPad</text>
|
||||||
|
</g>
|
||||||
|
<!-- Mouse->MouseTrackPad -->
|
||||||
|
<g id="edge44" class="edge">
|
||||||
|
<title>Mouse->MouseTrackPad</title>
|
||||||
|
<path fill="none" stroke="#000000" d="M1879.0611,-216.937C1872.4765,-208.3173 1864.3453,-197.6727 1856.9988,-188.0555"/>
|
||||||
|
<polygon fill="#000000" stroke="#000000" points="1859.6553,-185.7673 1850.8035,-179.9453 1854.0926,-190.0166 1859.6553,-185.7673"/>
|
||||||
|
</g>
|
||||||
|
<!-- MouseTrackPoint -->
|
||||||
|
<g id="node45" class="node">
|
||||||
|
<title>MouseTrackPoint</title>
|
||||||
|
<ellipse fill="none" stroke="#000000" cx="2010.0953" cy="-162" rx="80.4577" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="2010.0953" y="-157.8" font-family="Times,serif" font-size="14.00" fill="#000000">MouseTrackPoint</text>
|
||||||
|
</g>
|
||||||
|
<!-- Mouse->MouseTrackPoint -->
|
||||||
|
<g id="edge45" class="edge">
|
||||||
|
<title>Mouse->MouseTrackPoint</title>
|
||||||
|
<path fill="none" stroke="#000000" d="M1915.4083,-219.7751C1931.9914,-209.6566 1954.5994,-195.8619 1973.5655,-184.2894"/>
|
||||||
|
<polygon fill="#000000" stroke="#000000" points="1975.5507,-187.1782 1982.264,-178.9818 1971.9046,-181.2027 1975.5507,-187.1782"/>
|
||||||
|
</g>
|
||||||
|
<!-- Playstation -->
|
||||||
|
<g id="node34" class="node">
|
||||||
|
<title>Playstation</title>
|
||||||
|
<ellipse fill="none" stroke="#000000" cx="1506.0953" cy="-162" rx="53.9078" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="1506.0953" y="-157.8" font-family="Times,serif" font-size="14.00" fill="#000000">Playstation</text>
|
||||||
|
</g>
|
||||||
|
<!-- Controllers->Playstation -->
|
||||||
|
<g id="edge34" class="edge">
|
||||||
|
<title>Controllers->Playstation</title>
|
||||||
|
<path fill="none" stroke="#000000" d="M1506.0953,-215.8314C1506.0953,-208.131 1506.0953,-198.9743 1506.0953,-190.4166"/>
|
||||||
|
<polygon fill="#000000" stroke="#000000" points="1509.5954,-190.4132 1506.0953,-180.4133 1502.5954,-190.4133 1509.5954,-190.4132"/>
|
||||||
|
</g>
|
||||||
|
<!-- DualShock -->
|
||||||
|
<g id="node35" class="node">
|
||||||
|
<title>DualShock</title>
|
||||||
|
<ellipse fill="none" stroke="#000000" cx="1488.0953" cy="-90" rx="53.8943" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="1488.0953" y="-85.8" font-family="Times,serif" font-size="14.00" fill="#000000">DualShock</text>
|
||||||
|
</g>
|
||||||
|
<!-- Playstation->DualShock -->
|
||||||
|
<g id="edge35" class="edge">
|
||||||
|
<title>Playstation->DualShock</title>
|
||||||
|
<path fill="none" stroke="#000000" d="M1501.5531,-143.8314C1499.6069,-136.0463 1497.2885,-126.7729 1495.129,-118.1347"/>
|
||||||
|
<polygon fill="#000000" stroke="#000000" points="1498.5195,-117.2658 1492.6986,-108.4133 1491.7285,-118.9636 1498.5195,-117.2658"/>
|
||||||
|
</g>
|
||||||
|
<!-- DualSense -->
|
||||||
|
<g id="node36" class="node">
|
||||||
|
<title>DualSense</title>
|
||||||
|
<ellipse fill="none" stroke="#000000" cx="1612.0953" cy="-90" rx="52.1655" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="1612.0953" y="-85.8" font-family="Times,serif" font-size="14.00" fill="#000000">DualSense</text>
|
||||||
|
</g>
|
||||||
|
<!-- Playstation->DualSense -->
|
||||||
|
<g id="edge36" class="edge">
|
||||||
|
<title>Playstation->DualSense</title>
|
||||||
|
<path fill="none" stroke="#000000" d="M1529.8838,-145.8418C1544.6134,-135.8368 1563.7207,-122.8582 1579.8071,-111.9316"/>
|
||||||
|
<polygon fill="#000000" stroke="#000000" points="1582.0806,-114.6184 1588.3862,-106.1043 1578.1474,-108.8279 1582.0806,-114.6184"/>
|
||||||
|
</g>
|
||||||
|
<!-- DualShock1 -->
|
||||||
|
<g id="node37" class="node">
|
||||||
|
<title>DualShock1</title>
|
||||||
|
<ellipse fill="none" stroke="#000000" cx="1420.0953" cy="-18" rx="58.5521" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="1420.0953" y="-13.8" font-family="Times,serif" font-size="14.00" fill="#000000">DualShock1</text>
|
||||||
|
</g>
|
||||||
|
<!-- DualShock->DualShock1 -->
|
||||||
|
<g id="edge37" class="edge">
|
||||||
|
<title>DualShock->DualShock1</title>
|
||||||
|
<path fill="none" stroke="#000000" d="M1471.6344,-72.5708C1463.2603,-63.7041 1452.9315,-52.7678 1443.7247,-43.0194"/>
|
||||||
|
<polygon fill="#000000" stroke="#000000" points="1446.0511,-40.3852 1436.6403,-35.5182 1440.962,-45.1916 1446.0511,-40.3852"/>
|
||||||
|
</g>
|
||||||
|
<!-- DualShock2 -->
|
||||||
|
<g id="node38" class="node">
|
||||||
|
<title>DualShock2</title>
|
||||||
|
<ellipse fill="none" stroke="#000000" cx="1556.0953" cy="-18" rx="58.5521" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="1556.0953" y="-13.8" font-family="Times,serif" font-size="14.00" fill="#000000">DualShock2</text>
|
||||||
|
</g>
|
||||||
|
<!-- DualShock->DualShock2 -->
|
||||||
|
<g id="edge38" class="edge">
|
||||||
|
<title>DualShock->DualShock2</title>
|
||||||
|
<path fill="none" stroke="#000000" d="M1504.5562,-72.5708C1512.9303,-63.7041 1523.2591,-52.7678 1532.4659,-43.0194"/>
|
||||||
|
<polygon fill="#000000" stroke="#000000" points="1535.2286,-45.1916 1539.5503,-35.5182 1530.1395,-40.3852 1535.2286,-45.1916"/>
|
||||||
|
</g>
|
||||||
|
<!-- DualShock3 -->
|
||||||
|
<g id="node39" class="node">
|
||||||
|
<title>DualShock3</title>
|
||||||
|
<ellipse fill="none" stroke="#000000" cx="1692.0953" cy="-18" rx="58.5521" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="1692.0953" y="-13.8" font-family="Times,serif" font-size="14.00" fill="#000000">DualShock3</text>
|
||||||
|
</g>
|
||||||
|
<!-- DualShock->DualShock3 -->
|
||||||
|
<g id="edge39" class="edge">
|
||||||
|
<title>DualShock->DualShock3</title>
|
||||||
|
<path fill="none" stroke="#000000" d="M1525.512,-76.7941C1558.7364,-65.0678 1607.4912,-47.8603 1643.6793,-35.088"/>
|
||||||
|
<polygon fill="#000000" stroke="#000000" points="1645.2646,-38.2401 1653.5296,-31.6114 1642.9348,-31.6392 1645.2646,-38.2401"/>
|
||||||
|
</g>
|
||||||
|
<!-- DualShock4 -->
|
||||||
|
<g id="node40" class="node">
|
||||||
|
<title>DualShock4</title>
|
||||||
|
<ellipse fill="none" stroke="#000000" cx="1284.0953" cy="-18" rx="58.5521" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="1284.0953" y="-13.8" font-family="Times,serif" font-size="14.00" fill="#000000">DualShock4</text>
|
||||||
|
</g>
|
||||||
|
<!-- DualShock->DualShock4 -->
|
||||||
|
<g id="edge40" class="edge">
|
||||||
|
<title>DualShock->DualShock4</title>
|
||||||
|
<path fill="none" stroke="#000000" d="M1450.6786,-76.7941C1417.4541,-65.0678 1368.6994,-47.8603 1332.5113,-35.088"/>
|
||||||
|
<polygon fill="#000000" stroke="#000000" points="1333.2558,-31.6392 1322.661,-31.6114 1330.926,-38.2401 1333.2558,-31.6392"/>
|
||||||
|
</g>
|
||||||
|
<!-- GenericUSBMouse -->
|
||||||
|
<g id="node43" class="node">
|
||||||
|
<title>GenericUSBMouse</title>
|
||||||
|
<ellipse fill="none" stroke="#000000" cx="1769.0953" cy="-90" rx="86.8165" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="1769.0953" y="-85.8" font-family="Times,serif" font-size="14.00" fill="#000000">GenericUSBMouse</text>
|
||||||
|
</g>
|
||||||
|
<!-- USBMouse->GenericUSBMouse -->
|
||||||
|
<g id="edge43" class="edge">
|
||||||
|
<title>USBMouse->GenericUSBMouse</title>
|
||||||
|
<path fill="none" stroke="#000000" d="M1708.0542,-144.937C1718.1905,-135.8144 1730.8468,-124.4237 1742.0028,-114.3833"/>
|
||||||
|
<polygon fill="#000000" stroke="#000000" points="1744.3455,-116.9836 1749.4371,-107.6924 1739.6627,-111.7806 1744.3455,-116.9836"/>
|
||||||
|
</g>
|
||||||
|
<!-- VirtualDisk -->
|
||||||
|
<g id="node49" class="node">
|
||||||
|
<title>VirtualDisk</title>
|
||||||
|
<ellipse fill="none" stroke="#000000" cx="325.0953" cy="-90" rx="56.7561" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="325.0953" y="-85.8" font-family="Times,serif" font-size="14.00" fill="#000000">VirtualDisk</text>
|
||||||
|
</g>
|
||||||
|
<!-- Fat32->VirtualDisk -->
|
||||||
|
<g id="edge51" class="edge">
|
||||||
|
<title>Fat32->VirtualDisk</title>
|
||||||
|
<path fill="none" stroke="#000000" d="M292.5044,-144.5708C297.5524,-136.1184 303.7236,-125.7851 309.3328,-116.3931"/>
|
||||||
|
<polygon fill="#000000" stroke="#000000" points="312.3608,-118.1489 314.4833,-107.7689 306.351,-114.5597 312.3608,-118.1489"/>
|
||||||
|
</g>
|
||||||
|
<!-- TarFS->VirtualDisk -->
|
||||||
|
<g id="edge50" class="edge">
|
||||||
|
<title>TarFS->VirtualDisk</title>
|
||||||
|
<path fill="none" stroke="#000000" d="M357.6862,-144.5708C352.6382,-136.1184 346.467,-125.7851 340.8578,-116.3931"/>
|
||||||
|
<polygon fill="#000000" stroke="#000000" points="343.8396,-114.5597 335.7073,-107.7689 337.8298,-118.1489 343.8396,-114.5597"/>
|
||||||
|
</g>
|
||||||
|
<!-- Ext2->VirtualDisk -->
|
||||||
|
<g id="edge49" class="edge">
|
||||||
|
<title>Ext2->VirtualDisk</title>
|
||||||
|
<path fill="none" stroke="#000000" d="M428.607,-149.6228C410.2018,-139.0214 383.3012,-123.5266 361.5364,-110.9901"/>
|
||||||
|
<polygon fill="#000000" stroke="#000000" points="363.2806,-107.9557 352.8684,-105.9973 359.7868,-114.0214 363.2806,-107.9557"/>
|
||||||
|
</g>
|
||||||
|
<!-- IDEDiskDriver -->
|
||||||
|
<g id="node50" class="node">
|
||||||
|
<title>IDEDiskDriver</title>
|
||||||
|
<ellipse fill="none" stroke="#000000" cx="453.0953" cy="-18" rx="70.622" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="453.0953" y="-13.8" font-family="Times,serif" font-size="14.00" fill="#000000">IDEDiskDriver</text>
|
||||||
|
</g>
|
||||||
|
<!-- VirtualDisk->IDEDiskDriver -->
|
||||||
|
<g id="edge52" class="edge">
|
||||||
|
<title>VirtualDisk->IDEDiskDriver</title>
|
||||||
|
<path fill="none" stroke="#000000" d="M353.1854,-74.1993C371.3097,-64.0044 395.1147,-50.6141 414.9419,-39.4613"/>
|
||||||
|
<polygon fill="#000000" stroke="#000000" points="416.7372,-42.4672 423.737,-34.514 413.3053,-36.3662 416.7372,-42.4672"/>
|
||||||
|
</g>
|
||||||
|
<!-- ATADiskDriver -->
|
||||||
|
<g id="node51" class="node">
|
||||||
|
<title>ATADiskDriver</title>
|
||||||
|
<ellipse fill="none" stroke="#000000" cx="616.0953" cy="-18" rx="74.1354" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="616.0953" y="-13.8" font-family="Times,serif" font-size="14.00" fill="#000000">ATADiskDriver</text>
|
||||||
|
</g>
|
||||||
|
<!-- VirtualDisk->ATADiskDriver -->
|
||||||
|
<g id="edge53" class="edge">
|
||||||
|
<title>VirtualDisk->ATADiskDriver</title>
|
||||||
|
<path fill="none" stroke="#000000" d="M368.0029,-78.0928C375.6815,-76.0205 383.6171,-73.9167 391.0953,-72 445.1811,-58.1378 506.8603,-43.4105 551.945,-32.8436"/>
|
||||||
|
<polygon fill="#000000" stroke="#000000" points="552.9392,-36.2055 561.879,-30.5196 551.3446,-29.3896 552.9392,-36.2055"/>
|
||||||
|
</g>
|
||||||
|
<!-- FloppyController -->
|
||||||
|
<g id="node52" class="node">
|
||||||
|
<title>FloppyController</title>
|
||||||
|
<ellipse fill="none" stroke="#000000" cx="78.0953" cy="-18" rx="78.1907" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="78.0953" y="-13.8" font-family="Times,serif" font-size="14.00" fill="#000000">FloppyController</text>
|
||||||
|
</g>
|
||||||
|
<!-- VirtualDisk->FloppyController -->
|
||||||
|
<g id="edge54" class="edge">
|
||||||
|
<title>VirtualDisk->FloppyController</title>
|
||||||
|
<path fill="none" stroke="#000000" d="M283.1951,-77.7862C242.8032,-66.012 181.3328,-48.0935 136.2175,-34.9425"/>
|
||||||
|
<polygon fill="#000000" stroke="#000000" points="137.1453,-31.5673 126.5653,-32.1289 135.1863,-38.2877 137.1453,-31.5673"/>
|
||||||
|
</g>
|
||||||
|
<!-- CDROM -->
|
||||||
|
<g id="node53" class="node">
|
||||||
|
<title>CDROM</title>
|
||||||
|
<ellipse fill="none" stroke="#000000" cx="221.0953" cy="-18" rx="46.3875" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="221.0953" y="-13.8" font-family="Times,serif" font-size="14.00" fill="#000000">CDROM</text>
|
||||||
|
</g>
|
||||||
|
<!-- VirtualDisk->CDROM -->
|
||||||
|
<g id="edge55" class="edge">
|
||||||
|
<title>VirtualDisk->CDROM</title>
|
||||||
|
<path fill="none" stroke="#000000" d="M301.2356,-73.4817C286.7642,-63.4631 268.1319,-50.5638 252.4754,-39.7247"/>
|
||||||
|
<polygon fill="#000000" stroke="#000000" points="254.3431,-36.7608 244.1289,-33.9463 250.3586,-42.5161 254.3431,-36.7608"/>
|
||||||
|
</g>
|
||||||
|
<!-- NVME -->
|
||||||
|
<g id="node54" class="node">
|
||||||
|
<title>NVME</title>
|
||||||
|
<ellipse fill="none" stroke="#000000" cx="325.0953" cy="-18" rx="39.4254" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="325.0953" y="-13.8" font-family="Times,serif" font-size="14.00" fill="#000000">NVME</text>
|
||||||
|
</g>
|
||||||
|
<!-- VirtualDisk->NVME -->
|
||||||
|
<g id="edge56" class="edge">
|
||||||
|
<title>VirtualDisk->NVME</title>
|
||||||
|
<path fill="none" stroke="#000000" d="M325.0953,-71.8314C325.0953,-64.131 325.0953,-54.9743 325.0953,-46.4166"/>
|
||||||
|
<polygon fill="#000000" stroke="#000000" points="328.5954,-46.4132 325.0953,-36.4133 321.5954,-46.4133 328.5954,-46.4132"/>
|
||||||
|
</g>
|
||||||
|
<!-- BlueToothStack -->
|
||||||
|
<g id="node55" class="node">
|
||||||
|
<title>BlueToothStack</title>
|
||||||
|
<ellipse fill="none" stroke="#000000" cx="2547.0953" cy="-378" rx="73.5965" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="2547.0953" y="-373.8" font-family="Times,serif" font-size="14.00" fill="#000000">BlueToothStack</text>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 36 KiB |
4
contrib/README.md
Normal file
4
contrib/README.md
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
# Commit style
|
||||||
|
`[SCOPE]: [COMMENT]`
|
||||||
|
SCOPE is what you changed
|
||||||
|
COMMENT is why you changed that
|
32
contrib/TODO.md
Normal file
32
contrib/TODO.md
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
# TODO
|
||||||
|
- Build out the object system
|
||||||
|
- Build or Find an acceptable IDL
|
||||||
|
Short List of potentials
|
||||||
|
- [comline](https://git.ablecorp.us/DOOME1M8Cover/comline)
|
||||||
|
- Work on a styleguide for commits
|
||||||
|
Maybe something allong the lines of
|
||||||
|
[relevant shorthand note] Explination
|
||||||
|
- Language support on HBVM
|
||||||
|
- HBVM assembler (with IDL support)
|
||||||
|
- HBVM Lisp/s-expr Compiler (Also (with (IDL (support))))
|
||||||
|
- Documentation
|
||||||
|
- Drivers
|
||||||
|
- serial driver
|
||||||
|
- PS/2 mouse driver
|
||||||
|
- PS/2 Keyboard driver
|
||||||
|
- VGA driver
|
||||||
|
- SVGA driver
|
||||||
|
- File system
|
||||||
|
- Depends on Disk driver
|
||||||
|
- TarFS
|
||||||
|
Pass in a tar file as an initrd and parse it with TarFS
|
||||||
|
- VFS
|
||||||
|
Being (written)[https://git.ablecorp.us/bee/ableos-vfs] by Bee
|
||||||
|
- Disk driver
|
||||||
|
- IDE Driver
|
||||||
|
- ATA Driver
|
||||||
|
- Floppy Driver
|
||||||
|
- A ton more
|
||||||
|
- Port (Slint)[https://slint.dev]
|
||||||
|
- Depends on
|
||||||
|
- Graphics Driver
|
50
contrib/design.dot
Normal file
50
contrib/design.dot
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
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;
|
||||||
|
}
|
|
@ -3,20 +3,33 @@ edition = "2021"
|
||||||
name = "kernel"
|
name = "kernel"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
|
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
elfloader = "0.16"
|
embedded-graphics = "0.7"
|
||||||
error-stack = { version = "0.3", default-features = false}
|
hbvm.git = "https://git.ablecorp.us/ableos/holey-bytes"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
spin = "0.9"
|
spin = "0.9"
|
||||||
uart_16550 = "0.2"
|
uart_16550 = "0.2"
|
||||||
slab = { version = "0.4", default-features = false }
|
slab = { version = "0.4", default-features = false }
|
||||||
versioning = { git = "https://git.ablecorp.us/able/aos_userland" }
|
xml.git = "https://git.ablecorp.us/ableos/ableos_userland"
|
||||||
|
versioning.git = "https://git.ablecorp.us/ableos/ableos_userland"
|
||||||
|
able_graphics_library.git = "https://git.ablecorp.us/ableos/ableos_userland"
|
||||||
|
hashbrown = "*"
|
||||||
|
kiam = "0.1.1"
|
||||||
|
|
||||||
|
[dependencies.limine]
|
||||||
|
version = "0.1"
|
||||||
|
git = "https://github.com/limine-bootloader/limine-rs"
|
||||||
|
|
||||||
[dependencies.crossbeam-queue]
|
[dependencies.crossbeam-queue]
|
||||||
version = "0.3"
|
version = "0.3"
|
||||||
default-features = false
|
default-features = false
|
||||||
features = ["alloc"]
|
features = ["alloc"]
|
||||||
|
|
||||||
|
[dependencies.clparse]
|
||||||
|
git = "https://git.ablecorp.us/ableos/ableos_userland"
|
||||||
|
default-features = false
|
||||||
|
|
||||||
[dependencies.derive_more]
|
[dependencies.derive_more]
|
||||||
version = "0.99"
|
version = "0.99"
|
||||||
default-features = false
|
default-features = false
|
||||||
|
@ -33,10 +46,14 @@ features = [
|
||||||
"sum",
|
"sum",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
[target.'cfg(target_arch = "x86_64")'.dependencies]
|
[target.'cfg(target_arch = "x86_64")'.dependencies]
|
||||||
limine = { version = "0.1", git = "https://github.com/limine-bootloader/limine-rs" }
|
|
||||||
x86_64 = "0.14"
|
x86_64 = "0.14"
|
||||||
x2apic = "0.4"
|
x2apic = "0.4"
|
||||||
|
virtio-drivers = "0.4.0"
|
||||||
|
# rdrand = "*"
|
||||||
|
rdrand = { version = "0.8", default-features = false }
|
||||||
|
|
||||||
|
|
||||||
[target.'cfg(target_arch = "riscv64")'.dependencies]
|
[target.'cfg(target_arch = "riscv64")'.dependencies]
|
||||||
sbi = "0.2.0"
|
sbi = "0.2.0"
|
||||||
|
|
|
@ -1,33 +0,0 @@
|
||||||
|
|
||||||
.//// *(####
|
|
||||||
(####((/, (########,
|
|
||||||
(##%##(###(( ,(#########%#
|
|
||||||
#%%%%###(###((. *((####%%&%%%%#
|
|
||||||
.#####%%%%%####((. *(####%&&&&&%%%%#
|
|
||||||
#(((((((##%%&&%#((/ /#(##%&&%##########
|
|
||||||
/######%%%%%%%(..........(#%%%%%%#####%%#
|
|
||||||
,#%%%%%%#/...... ..............,&&&%%###.
|
|
||||||
,%%#(#(...........................(#&&%%#
|
|
||||||
.###%...............................%%#(#.
|
|
||||||
#%&.................................%#
|
|
||||||
,%&&*.................................&&%(
|
|
||||||
%%#//........./............*/..,......&&&%#
|
|
||||||
.......,..............*,*.,,,,,,.
|
|
||||||
......./....,.........*,,,,.,,,,,,
|
|
||||||
,...../..(###%,.....&*&%###/..,.,,.
|
|
||||||
,,..../%(((#(,.....,%%%%###,..,..,.
|
|
||||||
.,,*.../..,#,.........,(&(,,**.,,,,,
|
|
||||||
,/((..,*..........,,.,,,,,**.,##((
|
|
||||||
/(((%%%,,,,,.,,,,,,,,,,,#/##(,(/
|
|
||||||
.***..(,.#%%%&&#/%,,(%*,,**#
|
|
||||||
**,...,(#%%%%&#%%%#%%%%,,.,,***.
|
|
||||||
.....,*,*#%%%%%###%##%%%&,,*,,....
|
|
||||||
......,*/. (############%%%&&&&#*,,....
|
|
||||||
...,*,..,(((((((((((#((((((((((((&&&#*,
|
|
||||||
,##///////(((((((((((((#///#///(##/.
|
|
||||||
/*/**//... ...**(((((((,. .,*......
|
|
||||||
....... ......,,/*,. ...........
|
|
||||||
,..,,,,...... .. .... ,,....... ..,,,
|
|
||||||
........,.,.,*//////*,......,.
|
|
||||||
...,,,, ,,,,,,
|
|
||||||
|
|
24
kernel/lds/aarch64-qemu.ld
Normal file
24
kernel/lds/aarch64-qemu.ld
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
ENTRY(_kernel_start)
|
||||||
|
|
||||||
|
SECTIONS
|
||||||
|
{
|
||||||
|
. = 0xffffffff80000000;
|
||||||
|
.text.boot : { *(.text.boot) }
|
||||||
|
.text : { *(.text) }
|
||||||
|
.data : { *(.data) }
|
||||||
|
.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 = .;
|
||||||
|
}
|
|
@ -47,7 +47,8 @@ SECTIONS
|
||||||
/* Align initial kernel heap to page boundary */
|
/* Align initial kernel heap to page boundary */
|
||||||
. = ALIGN(4K);
|
. = ALIGN(4K);
|
||||||
PROVIDE(_initial_kernel_heap_start = .);
|
PROVIDE(_initial_kernel_heap_start = .);
|
||||||
PROVIDE(_initial_kernel_heap_size = 1024 * 1024);
|
/* PROVIDE(_initial_kernel_heap_size = 1024 * 1024); */
|
||||||
|
PROVIDE(_initial_kernel_heap_size = 1024 * 4096 * 100);
|
||||||
. += _initial_kernel_heap_size;
|
. += _initial_kernel_heap_size;
|
||||||
} :data
|
} :data
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,14 +27,16 @@
|
||||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
use core::{
|
use {
|
||||||
|
core::{
|
||||||
alloc::{GlobalAlloc, Layout},
|
alloc::{GlobalAlloc, Layout},
|
||||||
mem,
|
mem,
|
||||||
ptr::{self, NonNull},
|
ptr::{self, NonNull},
|
||||||
|
},
|
||||||
|
log::trace,
|
||||||
|
spin::Mutex,
|
||||||
};
|
};
|
||||||
|
|
||||||
use spin::Mutex;
|
|
||||||
|
|
||||||
struct Allocator(Mutex<Option<Heap>>);
|
struct Allocator(Mutex<Option<Heap>>);
|
||||||
|
|
||||||
unsafe impl GlobalAlloc for Allocator {
|
unsafe impl GlobalAlloc for Allocator {
|
||||||
|
@ -60,7 +62,7 @@ static ALLOCATOR: Allocator = Allocator(Mutex::new(None));
|
||||||
|
|
||||||
// FIXME: umm is `memory` VirtualAddress or PhysicalAddress? both?
|
// FIXME: umm is `memory` VirtualAddress or PhysicalAddress? both?
|
||||||
pub fn init(memory: *mut u8, memory_size: usize) {
|
pub fn init(memory: *mut u8, memory_size: usize) {
|
||||||
log::info!("Initialising kernel heap allocator");
|
trace!("Initialising kernel heap allocator");
|
||||||
*ALLOCATOR.0.lock() = Some(unsafe { Heap::new(memory, memory_size) });
|
*ALLOCATOR.0.lock() = Some(unsafe { Heap::new(memory, memory_size) });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -144,19 +146,30 @@ impl Heap {
|
||||||
self.allocated_chunks += chunks_needed;
|
self.allocated_chunks += chunks_needed;
|
||||||
|
|
||||||
let ptr: *mut u8 = unsafe { mem::transmute(header.add(1)) };
|
let ptr: *mut u8 = unsafe { mem::transmute(header.add(1)) };
|
||||||
// FIXME: zero or scrub memory?
|
{
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
trace!("Allocating {:?}", ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe { core::ptr::write_bytes(ptr, 0, size) };
|
||||||
|
|
||||||
assert!(ptr.is_aligned_to(alignment));
|
assert!(ptr.is_aligned_to(alignment));
|
||||||
NonNull::new(ptr)
|
NonNull::new(ptr)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deallocate(&mut self, ptr: *mut u8) {
|
fn deallocate(&mut self, ptr: *mut u8) {
|
||||||
|
{
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
log::trace!("Deallocating {:?}", ptr);
|
||||||
|
}
|
||||||
let header = Self::allocation_header(ptr);
|
let header = Self::allocation_header(ptr);
|
||||||
let start = (header as usize - self.chunks as usize) / CHUNK_SIZE;
|
let start = (header as usize - self.chunks as usize) / CHUNK_SIZE;
|
||||||
assert!(self.bitmap_get(start));
|
assert!(self.bitmap_get(start));
|
||||||
let size = unsafe { (*header).size_in_chunks };
|
let size = unsafe { (*header).size_in_chunks };
|
||||||
self.bitmap_set_range(start, size, false);
|
self.bitmap_set_range(start, size, false);
|
||||||
self.allocated_chunks -= size;
|
self.allocated_chunks -= size;
|
||||||
// FIXME: zero or scrub memory?
|
// FIXME: zero out memory to prevent leaking data
|
||||||
|
// REPLY: When we zero on alloc, do we really need it?
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Finds first hole that can fit an allocation of `size` chunks, returns the start of the
|
/// Finds first hole that can fit an allocation of `size` chunks, returns the start of the
|
||||||
|
@ -238,7 +251,10 @@ impl Heap {
|
||||||
return Some(start_of_free_chunks);
|
return Some(start_of_free_chunks);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
{
|
||||||
|
trace!("No first fit found");
|
||||||
|
}
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -325,5 +341,7 @@ unsafe impl Send for Heap {}
|
||||||
|
|
||||||
#[alloc_error_handler]
|
#[alloc_error_handler]
|
||||||
fn alloc_error_handler(layout: alloc::alloc::Layout) -> ! {
|
fn alloc_error_handler(layout: alloc::alloc::Layout) -> ! {
|
||||||
crate::arch::sloop()
|
log::error!("allocation error: {:?}", layout);
|
||||||
|
// Todo: Maybe panic here instead
|
||||||
|
crate::arch::spin_loop()
|
||||||
}
|
}
|
||||||
|
|
49
kernel/src/arch/aarch64/device_info_collector.rs
Normal file
49
kernel/src/arch/aarch64/device_info_collector.rs
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
use {
|
||||||
|
crate::{alloc::string::ToString, device_tree::DeviceTree, kmain::DEVICE_TREE},
|
||||||
|
alloc::string::String,
|
||||||
|
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() -> (String, u64) {
|
||||||
|
let mut cpu_id: u64 = 0;
|
||||||
|
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".to_string(),
|
||||||
|
0x410FD083 => "Cortex-A72".to_string(),
|
||||||
|
_ => "Unknown".to_string(),
|
||||||
|
};
|
||||||
|
log::trace!("CPU Name: {cpu_name} - CPU ID: 0x{:X}", cpu_id);
|
||||||
|
|
||||||
|
(cpu_name, cpu_id)
|
||||||
|
}
|
25
kernel/src/arch/aarch64/logging.rs
Normal file
25
kernel/src/arch/aarch64/logging.rs
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
use {crate::logger::TERMINAL_LOGGER, core::fmt::Write, spin::Mutex};
|
||||||
|
const SERIAL_CONSOLE: Mutex<SerialConsole> = Mutex::new(SerialConsole {
|
||||||
|
uart: 0x09000000 as *mut u8,
|
||||||
|
});
|
||||||
|
|
||||||
|
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(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn log(args: core::fmt::Arguments<'_>) -> core::fmt::Result {
|
||||||
|
SERIAL_CONSOLE.lock().write_fmt(args)?;
|
||||||
|
TERMINAL_LOGGER.lock().write_fmt(args)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
|
@ -1 +1,118 @@
|
||||||
//!
|
pub use logging::log;
|
||||||
|
use {
|
||||||
|
crate::{allocator, bootmodules::BootModule, kmain::kmain},
|
||||||
|
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 = 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,
|
||||||
|
)
|
||||||
|
.to_vec();
|
||||||
|
|
||||||
|
let file_path = alloc::string::String::from_utf8(
|
||||||
|
file.path.to_str().unwrap().to_bytes().to_vec(),
|
||||||
|
);
|
||||||
|
if file_path.is_err() {
|
||||||
|
panic!("invalid file path: {:?}", file_path);
|
||||||
|
}
|
||||||
|
let file_cmd = alloc::string::String::from_utf8(
|
||||||
|
file.cmdline.to_str().unwrap().to_bytes().to_vec(),
|
||||||
|
);
|
||||||
|
if file_cmd.is_err() {
|
||||||
|
panic!("invalid module cmd: {:?}", file_cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
crate::kmain::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,
|
||||||
|
);
|
||||||
|
|
||||||
|
spin_loop();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn spin_loop() -> ! {
|
||||||
|
loop {
|
||||||
|
unsafe { asm!("wfi") }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn hardware_random_u64() -> u64 {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn register_dump() {}
|
||||||
|
#[no_mangle]
|
||||||
|
pub fn fmod() {}
|
||||||
|
|
|
@ -1,19 +1,28 @@
|
||||||
mod memory;
|
mod memory;
|
||||||
|
|
||||||
use core::{arch::{asm, global_asm}, fmt::Write};
|
use {
|
||||||
use alloc::boxed::Box;
|
alloc::boxed::Box,
|
||||||
use sbi::system_reset::{ResetType, ResetReason, system_reset};
|
core::{
|
||||||
use spin::{Mutex, Once};
|
arch::{asm, global_asm},
|
||||||
use uart_16550::MmioSerialPort;
|
fmt::Write,
|
||||||
|
},
|
||||||
|
sbi::system_reset::{system_reset, ResetReason, ResetType},
|
||||||
|
spin::{Mutex, Once},
|
||||||
|
uart_16550::MmioSerialPort,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::{allocator, memory::PhysicalAddress, arch::riscv64::memory::{PAGE_TABLE, PageEntryFlags, PageSize, PageTable}};
|
use crate::{
|
||||||
|
allocator,
|
||||||
|
arch::riscv64::memory::{PageEntryFlags, PageSize, PageTable, PAGE_TABLE},
|
||||||
|
memory::PhysicalAddress,
|
||||||
|
};
|
||||||
|
|
||||||
global_asm!(include_str!("entry.s"));
|
global_asm!(include_str!("entry.s"));
|
||||||
global_asm!(include_str!("memory_regions.s"));
|
global_asm!(include_str!("memory_regions.s"));
|
||||||
|
|
||||||
pub const PAGE_SIZE: usize = 4096;
|
pub const PAGE_SIZE: usize = 4096;
|
||||||
|
|
||||||
extern {
|
extern "C" {
|
||||||
static TEXT_START: PhysicalAddress;
|
static TEXT_START: PhysicalAddress;
|
||||||
static TEXT_END: PhysicalAddress;
|
static TEXT_END: PhysicalAddress;
|
||||||
|
|
||||||
|
@ -39,12 +48,15 @@ extern {
|
||||||
static SERIAL_CONSOLE: Once<Mutex<MmioSerialPort>> = Once::new();
|
static SERIAL_CONSOLE: Once<Mutex<MmioSerialPort>> = Once::new();
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
unsafe extern fn _kernel_start() -> ! {
|
unsafe extern "C" fn _kernel_start() -> ! {
|
||||||
SERIAL_CONSOLE.call_once(|| Mutex::new(unsafe { MmioSerialPort::new(0x1000_0000) }));
|
SERIAL_CONSOLE.call_once(|| Mutex::new(unsafe { MmioSerialPort::new(0x1000_0000) }));
|
||||||
crate::logger::init().expect("failed to set logger");
|
crate::logger::init().expect("failed to set logger");
|
||||||
log::info!("Initialising AKern {}", crate::VERSION);
|
log::info!("Initialising AKern {}", crate::VERSION);
|
||||||
|
|
||||||
allocator::init(INITIAL_KERNEL_HEAP_START.as_mut_ptr::<u8>(), INITIAL_KERNEL_HEAP_SIZE);
|
allocator::init(
|
||||||
|
INITIAL_KERNEL_HEAP_START.as_mut_ptr::<u8>(),
|
||||||
|
INITIAL_KERNEL_HEAP_SIZE,
|
||||||
|
);
|
||||||
memory::init(USABLE_MEMORY_START.into(), USABLE_MEMORY_SIZE / PAGE_SIZE);
|
memory::init(USABLE_MEMORY_START.into(), USABLE_MEMORY_SIZE / PAGE_SIZE);
|
||||||
|
|
||||||
let mut page_table_addr = PAGE_TABLE.get().unwrap().lock();
|
let mut page_table_addr = PAGE_TABLE.get().unwrap().lock();
|
||||||
|
@ -61,9 +73,17 @@ unsafe extern fn _kernel_start() -> ! {
|
||||||
// Map bss section (includes stack and initial kernel heap)
|
// Map bss section (includes stack and initial kernel heap)
|
||||||
page_table.identity_map_range(BSS_START, BSS_END, PageEntryFlags::ReadWrite);
|
page_table.identity_map_range(BSS_START, BSS_END, PageEntryFlags::ReadWrite);
|
||||||
// Map usable memory range (as rw so not executable)
|
// Map usable memory range (as rw so not executable)
|
||||||
page_table.identity_map_range(USABLE_MEMORY_START, USABLE_MEMORY_START + USABLE_MEMORY_SIZE.into(), PageEntryFlags::ReadWrite);
|
page_table.identity_map_range(
|
||||||
|
USABLE_MEMORY_START,
|
||||||
|
USABLE_MEMORY_START + USABLE_MEMORY_SIZE.into(),
|
||||||
|
PageEntryFlags::ReadWrite,
|
||||||
|
);
|
||||||
// Map Uart so we can continue using serial
|
// Map Uart so we can continue using serial
|
||||||
page_table.identity_map(0x1000_0000_usize.into(), PageEntryFlags::ReadWrite, PageSize::Size4KiB);
|
page_table.identity_map(
|
||||||
|
0x1000_0000_usize.into(),
|
||||||
|
PageEntryFlags::ReadWrite,
|
||||||
|
PageSize::Size4KiB,
|
||||||
|
);
|
||||||
|
|
||||||
let table_ppn = page_table_addr.as_addr() as usize >> 12;
|
let table_ppn = page_table_addr.as_addr() as usize >> 12;
|
||||||
let satp_value = 8 << 60 | table_ppn;
|
let satp_value = 8 << 60 | table_ppn;
|
||||||
|
@ -79,7 +99,7 @@ unsafe extern fn _kernel_start() -> ! {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Spin loop
|
/// Spin loop
|
||||||
pub fn sloop() -> ! {
|
pub fn spin_loop() -> ! {
|
||||||
loop {
|
loop {
|
||||||
unsafe { asm!("wfi") }
|
unsafe { asm!("wfi") }
|
||||||
}
|
}
|
||||||
|
|
934
kernel/src/arch/x86_64/cpuid.rs
Normal file
934
kernel/src/arch/x86_64/cpuid.rs
Normal file
|
@ -0,0 +1,934 @@
|
||||||
|
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 {}
|
||||||
|
}
|
||||||
|
*/
|
68
kernel/src/arch/x86_64/device_info_collector.rs
Normal file
68
kernel/src/arch/x86_64/device_info_collector.rs
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
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,34 +1,33 @@
|
||||||
use spin::Lazy;
|
use {
|
||||||
use x86_64::{
|
spin::Lazy,
|
||||||
|
x86_64::{
|
||||||
structures::{
|
structures::{
|
||||||
gdt::{Descriptor, GlobalDescriptorTable, SegmentSelector},
|
gdt::{Descriptor, GlobalDescriptorTable, SegmentSelector},
|
||||||
tss::TaskStateSegment,
|
tss::TaskStateSegment,
|
||||||
},
|
},
|
||||||
VirtAddr,
|
VirtAddr,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const DOUBLE_FAULT_IX: u16 = 0;
|
pub const DOUBLE_FAULT_IX: u16 = 0;
|
||||||
|
|
||||||
pub unsafe fn init() {
|
pub unsafe fn init() {
|
||||||
use x86_64::instructions::segmentation::{Segment, CS, DS, ES, SS};
|
use x86_64::instructions::{
|
||||||
use x86_64::instructions::tables::load_tss;
|
segmentation::{Segment, CS, SS},
|
||||||
|
tables::load_tss,
|
||||||
|
};
|
||||||
|
|
||||||
log::info!("Initialising GDT");
|
log::trace!("Initialising GDT");
|
||||||
GDT.0.load();
|
GDT.0.load();
|
||||||
CS::set_reg(GDT.1.kcode);
|
CS::set_reg(GDT.1.kcode);
|
||||||
DS::set_reg(GDT.1.kdata);
|
|
||||||
ES::set_reg(GDT.1.kdata);
|
|
||||||
SS::set_reg(GDT.1.kdata);
|
SS::set_reg(GDT.1.kdata);
|
||||||
load_tss(GDT.1.tss);
|
load_tss(GDT.1.tss);
|
||||||
init_syscalls(&GDT.1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Selectors {
|
struct Selectors {
|
||||||
kcode: SegmentSelector,
|
kcode: SegmentSelector,
|
||||||
kdata: SegmentSelector,
|
kdata: SegmentSelector,
|
||||||
tss: SegmentSelector,
|
tss: SegmentSelector,
|
||||||
udata: SegmentSelector,
|
|
||||||
ucode: SegmentSelector,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static TSS: Lazy<TaskStateSegment> = Lazy::new(|| {
|
static TSS: Lazy<TaskStateSegment> = Lazy::new(|| {
|
||||||
|
@ -51,26 +50,6 @@ static GDT: Lazy<(GlobalDescriptorTable, Selectors)> = Lazy::new(|| {
|
||||||
kcode: gdt.add_entry(Descriptor::kernel_code_segment()),
|
kcode: gdt.add_entry(Descriptor::kernel_code_segment()),
|
||||||
kdata: gdt.add_entry(Descriptor::kernel_data_segment()),
|
kdata: gdt.add_entry(Descriptor::kernel_data_segment()),
|
||||||
tss: gdt.add_entry(Descriptor::tss_segment(&TSS)),
|
tss: gdt.add_entry(Descriptor::tss_segment(&TSS)),
|
||||||
udata: gdt.add_entry(Descriptor::user_data_segment()),
|
|
||||||
ucode: gdt.add_entry(Descriptor::user_code_segment()),
|
|
||||||
};
|
};
|
||||||
(gdt, sels)
|
(gdt, sels)
|
||||||
});
|
});
|
||||||
|
|
||||||
/// Initialize syscalls
|
|
||||||
unsafe fn init_syscalls(sls: &Selectors) {
|
|
||||||
use x86_64::registers::{
|
|
||||||
model_specific::{Efer, EferFlags, LStar, SFMask, Star},
|
|
||||||
rflags::RFlags,
|
|
||||||
};
|
|
||||||
|
|
||||||
Star::write(sls.ucode, sls.udata, sls.kcode, sls.kdata);
|
|
||||||
SFMask::write(RFlags::from_bits(0x200).expect("Invalid RFlags for SFMask"));
|
|
||||||
LStar::write(VirtAddr::from_ptr(handle_syscall as *const ()));
|
|
||||||
Efer::update(|x| *x |= EferFlags::SYSTEM_CALL_EXTENSIONS);
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "C" fn handle_syscall(a: u64) -> ! {
|
|
||||||
log::info!("called syscall {a}");
|
|
||||||
todo!("Return from syscall");
|
|
||||||
}
|
|
||||||
|
|
1
kernel/src/arch/x86_64/graphics.rs
Normal file
1
kernel/src/arch/x86_64/graphics.rs
Normal file
|
@ -0,0 +1 @@
|
||||||
|
|
|
@ -1,9 +1,13 @@
|
||||||
use spin::{Lazy, Mutex};
|
// TODO: Turn apic keyboard interrupt into a standard ipc message
|
||||||
use x2apic::lapic::{LocalApic, LocalApicBuilder};
|
use {
|
||||||
use x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame, PageFaultErrorCode};
|
log::trace,
|
||||||
|
spin::{Lazy, Mutex},
|
||||||
|
x2apic::lapic::{LocalApic, LocalApicBuilder},
|
||||||
|
x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame, PageFaultErrorCode},
|
||||||
|
};
|
||||||
|
|
||||||
pub unsafe fn init() {
|
pub unsafe fn init() {
|
||||||
log::info!("Initialising IDT");
|
trace!("Initialising IDT");
|
||||||
IDT.load();
|
IDT.load();
|
||||||
Lazy::force(&LAPIC);
|
Lazy::force(&LAPIC);
|
||||||
x86_64::instructions::interrupts::enable();
|
x86_64::instructions::interrupts::enable();
|
||||||
|
@ -12,11 +16,12 @@ pub unsafe fn init() {
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
enum Interrupt {
|
enum Interrupt {
|
||||||
Timer = 32,
|
Timer = 32,
|
||||||
|
|
||||||
ApicErr = u8::MAX - 1,
|
ApicErr = u8::MAX - 1,
|
||||||
Spurious = u8::MAX,
|
Spurious = u8::MAX,
|
||||||
}
|
}
|
||||||
|
|
||||||
static LAPIC: Lazy<Mutex<LocalApic>> = Lazy::new(|| {
|
pub(crate) static LAPIC: Lazy<Mutex<LocalApic>> = Lazy::new(|| {
|
||||||
let mut lapic = LocalApicBuilder::new()
|
let mut lapic = LocalApicBuilder::new()
|
||||||
.timer_vector(Interrupt::Timer as usize)
|
.timer_vector(Interrupt::Timer as usize)
|
||||||
.error_vector(Interrupt::ApicErr as usize)
|
.error_vector(Interrupt::ApicErr as usize)
|
||||||
|
@ -39,7 +44,11 @@ static IDT: Lazy<InterruptDescriptorTable> = Lazy::new(|| {
|
||||||
.set_stack_index(super::gdt::DOUBLE_FAULT_IX);
|
.set_stack_index(super::gdt::DOUBLE_FAULT_IX);
|
||||||
}
|
}
|
||||||
idt.page_fault.set_handler_fn(page_fault);
|
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[Interrupt::Timer as usize].set_handler_fn(timer);
|
||||||
|
|
||||||
idt
|
idt
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -54,7 +63,7 @@ extern "x86-interrupt" fn page_fault(
|
||||||
panic!("Page fault ({error_code:?}): {stack_frame:?}")
|
panic!("Page fault ({error_code:?}): {stack_frame:?}")
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "x86-interrupt" fn timer(_: InterruptStackFrame) {
|
extern "x86-interrupt" fn timer(_isf: InterruptStackFrame) {
|
||||||
unsafe { LAPIC.lock().end_of_interrupt() };
|
unsafe { LAPIC.lock().end_of_interrupt() };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,46 +1,22 @@
|
||||||
//! Logging (as in terms of console / serial output)
|
//! Logging (as in terms of console / serial output)
|
||||||
|
#![allow(deprecated)]
|
||||||
|
use {
|
||||||
|
core::fmt::Write,
|
||||||
|
limine::{TerminalRequest, TerminalResponse},
|
||||||
|
spin::{Lazy, Mutex},
|
||||||
|
uart_16550::SerialPort,
|
||||||
|
};
|
||||||
|
|
||||||
use core::fmt::Write;
|
pub static SERIAL_CONSOLE: Mutex<SerialPort> = Mutex::new(unsafe { SerialPort::new(0x3F8) });
|
||||||
use limine::{LimineTerminalRequest, LimineTerminalResponse};
|
|
||||||
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() {
|
pub fn init() {
|
||||||
SERIAL_CONSOLE.lock().init();
|
SERIAL_CONSOLE.lock().init();
|
||||||
Lazy::force(&TERMINAL_LOGGER);
|
// Lazy::force(&TERMINAL_LOGGER);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn log(args: core::fmt::Arguments<'_>) -> core::fmt::Result {
|
pub fn log(args: core::fmt::Arguments<'_>) -> core::fmt::Result {
|
||||||
x86_64::instructions::interrupts::without_interrupts(|| {
|
x86_64::instructions::interrupts::without_interrupts(|| {
|
||||||
TERMINAL_LOGGER.lock().write_fmt(args)?;
|
// TERMINAL_LOGGER.lock().write_fmt(args)?;
|
||||||
SERIAL_CONSOLE.lock().write_fmt(args)
|
SERIAL_CONSOLE.lock().write_fmt(args)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
struct TermLogger(&'static LimineTerminalResponse);
|
|
||||||
unsafe impl Send for TermLogger {}
|
|
||||||
impl TermLogger {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
static TERM_REQ: LimineTerminalRequest = LimineTerminalRequest::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,8 +1,10 @@
|
||||||
use core::sync::atomic::AtomicU64;
|
use {
|
||||||
use limine::{LimineMemmapEntry, LimineMemoryMapEntryType, NonNullPtr};
|
crate::memory::{MemoryManager, MAX_ORDER},
|
||||||
use spin::{Mutex, Once};
|
core::sync::atomic::AtomicU64,
|
||||||
use x86_64::{structures::paging::OffsetPageTable, VirtAddr};
|
limine::{MemmapEntry, MemoryMapEntryType, NonNullPtr},
|
||||||
use crate::memory::{MemoryManager, MAX_ORDER};
|
spin::{Mutex, Once},
|
||||||
|
x86_64::{structures::paging::OffsetPageTable, VirtAddr},
|
||||||
|
};
|
||||||
|
|
||||||
pub const PAGE_SIZE: usize = 4096;
|
pub const PAGE_SIZE: usize = 4096;
|
||||||
|
|
||||||
|
@ -12,7 +14,7 @@ static PAGE_TABLE: Once<Mutex<OffsetPageTable>> = Once::new();
|
||||||
|
|
||||||
/// Initialise page table
|
/// Initialise page table
|
||||||
pub unsafe fn init_pt(phys_base: VirtAddr) {
|
pub unsafe fn init_pt(phys_base: VirtAddr) {
|
||||||
log::info!("Retrieving page table");
|
log::debug!("Retrieving page table");
|
||||||
HHDM_OFFSET.store(phys_base.as_u64(), core::sync::atomic::Ordering::Relaxed);
|
HHDM_OFFSET.store(phys_base.as_u64(), core::sync::atomic::Ordering::Relaxed);
|
||||||
PAGE_TABLE.call_once(|| {
|
PAGE_TABLE.call_once(|| {
|
||||||
Mutex::new(OffsetPageTable::new(
|
Mutex::new(OffsetPageTable::new(
|
||||||
|
@ -28,11 +30,11 @@ pub unsafe fn init_pt(phys_base: VirtAddr) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Initialise memory manager
|
/// Initialise memory manager
|
||||||
pub fn initialize(mmap: &'static [NonNullPtr<LimineMemmapEntry>]) {
|
pub fn initialize(mmap: &'static [NonNullPtr<MemmapEntry>]) {
|
||||||
let mut memory_manager = MemoryManager::new();
|
let mut memory_manager = MemoryManager::new();
|
||||||
|
|
||||||
for entry in mmap {
|
for entry in mmap {
|
||||||
if entry.typ != LimineMemoryMapEntryType::Usable {
|
if entry.typ != MemoryMapEntryType::Usable {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,17 +1,25 @@
|
||||||
pub mod memory;
|
use {
|
||||||
mod gdt;
|
crate::bootmodules::BootModule, core::arch::asm, embedded_graphics::pixelcolor::Rgb888,
|
||||||
mod interrupts;
|
log::warn, rdrand::RdSeed,
|
||||||
mod logging;
|
};
|
||||||
|
pub mod memory;
|
||||||
pub use logging::log;
|
|
||||||
pub use memory::PAGE_SIZE;
|
mod cpuid;
|
||||||
|
mod device_info_collector;
|
||||||
use crate::allocator;
|
mod gdt;
|
||||||
use memory::MEMORY_MANAGER;
|
pub mod graphics;
|
||||||
use limine::{
|
pub(crate) mod interrupts;
|
||||||
LimineHhdmRequest, LimineKernelFileRequest, LimineMemmapRequest, LimineModuleRequest,
|
pub mod logging;
|
||||||
|
pub mod pci;
|
||||||
|
pub mod virtio;
|
||||||
|
|
||||||
|
pub use {logging::log, memory::PAGE_SIZE};
|
||||||
|
|
||||||
|
use {
|
||||||
|
crate::allocator,
|
||||||
|
limine::{HhdmRequest, KernelFileRequest, MemmapRequest, ModuleRequest},
|
||||||
|
x86_64::VirtAddr,
|
||||||
};
|
};
|
||||||
use x86_64::VirtAddr;
|
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
fn _initial_kernel_heap_start();
|
fn _initial_kernel_heap_start();
|
||||||
|
@ -22,12 +30,29 @@ const INITIAL_KERNEL_HEAP_START: *mut u8 = _initial_kernel_heap_start as _;
|
||||||
const INITIAL_KERNEL_HEAP_SIZE: *const () = _initial_kernel_heap_size as _;
|
const INITIAL_KERNEL_HEAP_SIZE: *const () = _initial_kernel_heap_size as _;
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
|
#[naked]
|
||||||
unsafe extern "C" fn _kernel_start() -> ! {
|
unsafe extern "C" fn _kernel_start() -> ! {
|
||||||
|
// Initialise SSE and jump to kernel entrypoint
|
||||||
|
core::arch::asm!(
|
||||||
|
"mov rax, cr0",
|
||||||
|
"and ax, 0xfffb",
|
||||||
|
"or ax, 0x2",
|
||||||
|
"mov cr0, rax",
|
||||||
|
"mov rax, cr4",
|
||||||
|
"or ax, 3 << 9",
|
||||||
|
"mov cr4, rax",
|
||||||
|
"jmp {}",
|
||||||
|
sym start,
|
||||||
|
options(noreturn),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe extern "C" fn start() -> ! {
|
||||||
logging::init();
|
logging::init();
|
||||||
crate::logger::init().expect("failed to set logger");
|
crate::logger::init().expect("failed to set logger");
|
||||||
log::info!("Initialising AKern {}", crate::VERSION);
|
log::info!("Initialising AKern {}", crate::VERSION);
|
||||||
|
|
||||||
static HDHM_REQ: LimineHhdmRequest = LimineHhdmRequest::new(0);
|
static HDHM_REQ: HhdmRequest = HhdmRequest::new(0);
|
||||||
memory::init_pt(VirtAddr::new(
|
memory::init_pt(VirtAddr::new(
|
||||||
HDHM_REQ
|
HDHM_REQ
|
||||||
.get_response()
|
.get_response()
|
||||||
|
@ -35,10 +60,9 @@ unsafe extern "C" fn _kernel_start() -> ! {
|
||||||
.expect("tried to get physical memory mapping offset from Limine")
|
.expect("tried to get physical memory mapping offset from Limine")
|
||||||
.offset,
|
.offset,
|
||||||
));
|
));
|
||||||
|
|
||||||
allocator::init(INITIAL_KERNEL_HEAP_START, INITIAL_KERNEL_HEAP_SIZE as _);
|
allocator::init(INITIAL_KERNEL_HEAP_START, INITIAL_KERNEL_HEAP_SIZE as _);
|
||||||
|
|
||||||
static MMAP_REQ: LimineMemmapRequest = LimineMemmapRequest::new(0);
|
static MMAP_REQ: MemmapRequest = MemmapRequest::new(0);
|
||||||
memory::initialize(
|
memory::initialize(
|
||||||
MMAP_REQ
|
MMAP_REQ
|
||||||
.get_response()
|
.get_response()
|
||||||
|
@ -50,24 +74,108 @@ unsafe extern "C" fn _kernel_start() -> ! {
|
||||||
gdt::init();
|
gdt::init();
|
||||||
interrupts::init();
|
interrupts::init();
|
||||||
|
|
||||||
{
|
static KFILE_REQ: KernelFileRequest = KernelFileRequest::new(0);
|
||||||
let mut mm = MEMORY_MANAGER.get().unwrap().lock();
|
static MOD_REQ: ModuleRequest = ModuleRequest::new(0);
|
||||||
let alloc_0 = mm.allocate_pages(0).unwrap();
|
|
||||||
log::debug!("Addr: {alloc_0}");
|
device_info_collector::collect_device_info();
|
||||||
let alloc_1 = mm.allocate_pages(0).unwrap();
|
|
||||||
log::debug!("Addr: {alloc_1}");
|
// Graphics test
|
||||||
mm.deallocate_pages(alloc_0, 0);
|
// {
|
||||||
let alloc_2 = mm.allocate_pages(1).unwrap();
|
// graphics::init();
|
||||||
log::debug!("Addr: {alloc_2}");
|
// let mut dis = DISPLAY.lock();
|
||||||
mm.deallocate_pages(alloc_1, 0);
|
// use embedded_graphics::prelude::RgbColor;
|
||||||
mm.deallocate_pages(alloc_2, 1);
|
|
||||||
let alloc_3 = mm.allocate_pages(1).unwrap();
|
// let _ = dis.set_color(Rgb888::YELLOW);
|
||||||
log::debug!("Addr: {alloc_3}");
|
// let thick = 6;
|
||||||
mm.deallocate_pages(alloc_3, 1);
|
// 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::trace!("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,
|
||||||
|
)
|
||||||
|
.to_vec();
|
||||||
|
|
||||||
|
let file_path = alloc::string::String::from_utf8(
|
||||||
|
file.path.to_str().unwrap().to_bytes().to_vec(),
|
||||||
|
);
|
||||||
|
if file_path.is_err() {
|
||||||
|
panic!("invalid file path: {:?}", file_path);
|
||||||
|
}
|
||||||
|
let file_cmd = alloc::string::String::from_utf8(
|
||||||
|
file.cmdline.to_str().unwrap().to_bytes().to_vec(),
|
||||||
|
);
|
||||||
|
if file_cmd.is_err() {
|
||||||
|
panic!("invalid module cmd: {:?}", file_cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
static KFILE_REQ: LimineKernelFileRequest = LimineKernelFileRequest::new(0);
|
|
||||||
static MOD_REQ: LimineModuleRequest = LimineModuleRequest::new(0);
|
|
||||||
crate::kmain::kmain(
|
crate::kmain::kmain(
|
||||||
KFILE_REQ
|
KFILE_REQ
|
||||||
.get_response()
|
.get_response()
|
||||||
|
@ -80,22 +188,110 @@ unsafe extern "C" fn _kernel_start() -> ! {
|
||||||
.transpose()
|
.transpose()
|
||||||
.expect("expected valid cmdline string")
|
.expect("expected valid cmdline string")
|
||||||
.unwrap_or_default(),
|
.unwrap_or_default(),
|
||||||
MOD_REQ
|
bootmodules,
|
||||||
.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
|
/// Spin loop
|
||||||
pub fn sloop() -> ! {
|
pub fn spin_loop() -> ! {
|
||||||
loop {
|
loop {
|
||||||
x86_64::instructions::hlt();
|
x86_64::instructions::hlt();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn hardware_random_u64() -> u64 {
|
||||||
|
use {log::trace, rdrand::RdRand};
|
||||||
|
let gen = RdRand::new();
|
||||||
|
match gen {
|
||||||
|
Ok(gen) => {
|
||||||
|
let ret = gen.try_next_u64().unwrap();
|
||||||
|
trace!("Random {}", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
warn!("RDRand not supported.");
|
||||||
|
// Try rdseed
|
||||||
|
let gen = RdSeed::new();
|
||||||
|
match gen {
|
||||||
|
Ok(gen) => {
|
||||||
|
let ret = gen.try_next_u64().unwrap();
|
||||||
|
trace!("Random {}", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
panic!("Neither RDRand or RDSeed are supported")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_edid() {}
|
||||||
|
|
||||||
|
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,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
501
kernel/src/arch/x86_64/pci/mod.rs
Normal file
501
kernel/src/arch/x86_64/pci/mod.rs
Normal file
|
@ -0,0 +1,501 @@
|
||||||
|
#[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,
|
||||||
|
}
|
||||||
|
use crate::alloc::string::ToString;
|
||||||
|
|
||||||
|
/// Enumerate PCI devices and run initialisation routines on ones we support
|
||||||
|
pub fn init(device_tree: &mut DeviceTree) {
|
||||||
|
device_tree.devices
|
||||||
|
.insert("Unidentified PCI".to_string(), alloc::vec![]);
|
||||||
|
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) {
|
||||||
|
(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("class", device_info.full_class.to_string());
|
||||||
|
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 = unsafe { pci_config_read(bus, device, 0, 0x8) };
|
||||||
|
let class = ((reg2 >> 16) & 0x0000_FFFF) as u16;
|
||||||
|
let pci_class = PciFullClass::from_u16(class);
|
||||||
|
let header_type = get_header_type(bus, device, 0);
|
||||||
|
|
||||||
|
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 x86_64::instructions::port::Port;
|
||||||
|
use crate::device_tree::DeviceTree;
|
||||||
|
|
||||||
|
#[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) as u32;
|
||||||
|
|
||||||
|
// write address
|
||||||
|
Port::new(0xCF8).write(address);
|
||||||
|
|
||||||
|
// read data
|
||||||
|
Port::new(0xCFC).read()
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
37
kernel/src/arch/x86_64/virtio/mod.rs
Normal file
37
kernel/src/arch/x86_64/virtio/mod.rs
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
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
|
||||||
|
}
|
36
kernel/src/bootmodules.rs
Normal file
36
kernel/src/bootmodules.rs
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
use {
|
||||||
|
crate::alloc::string::ToString,
|
||||||
|
alloc::{string::String, vec::Vec},
|
||||||
|
clparse::Arguments,
|
||||||
|
core::fmt::{Debug, Display},
|
||||||
|
log::trace,
|
||||||
|
xml::XMLElement,
|
||||||
|
};
|
||||||
|
pub type BootModules = Vec<BootModule>;
|
||||||
|
|
||||||
|
pub struct BootModule {
|
||||||
|
pub path: String,
|
||||||
|
pub bytes: Vec<u8>,
|
||||||
|
pub cmd: String,
|
||||||
|
}
|
||||||
|
impl BootModule {
|
||||||
|
pub fn new(path: String, bytes: Vec<u8>, cmd: String) -> Self {
|
||||||
|
Self { path, bytes, cmd }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn build_cmd<T: Display + Debug>(name: T, cmdline: T) -> XMLElement {
|
||||||
|
let mut cmdline = cmdline.to_string();
|
||||||
|
cmdline.pop();
|
||||||
|
cmdline.remove(0);
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
186
kernel/src/capabilities.rs
Normal file
186
kernel/src/capabilities.rs
Normal file
|
@ -0,0 +1,186 @@
|
||||||
|
//! 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);
|
||||||
|
}
|
73
kernel/src/device_tree.rs
Normal file
73
kernel/src/device_tree.rs
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
//! A tree of hardware devices
|
||||||
|
|
||||||
|
use {
|
||||||
|
crate::alloc::string::ToString,
|
||||||
|
alloc::{string::String, vec::Vec},
|
||||||
|
core::fmt,
|
||||||
|
hashbrown::HashMap,
|
||||||
|
};
|
||||||
|
/// A device object.
|
||||||
|
/// TODO define device
|
||||||
|
pub type Device = xml::XMLElement;
|
||||||
|
|
||||||
|
/// A tree of devices
|
||||||
|
// TODO: alphabetize this list
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct DeviceTree {
|
||||||
|
/// The device tree
|
||||||
|
pub devices: HashMap<String, Vec<Device>>,
|
||||||
|
}
|
||||||
|
impl DeviceTree {
|
||||||
|
/// Build the device tree. Does not populate the device tree
|
||||||
|
pub fn new() -> Self {
|
||||||
|
let mut dt = Self {
|
||||||
|
devices: HashMap::new(),
|
||||||
|
};
|
||||||
|
device_tree!(dt, [
|
||||||
|
"Mice",
|
||||||
|
"Keyboards",
|
||||||
|
"Controllers",
|
||||||
|
"Generic HIDs",
|
||||||
|
"Disk Drives",
|
||||||
|
"CD Drives",
|
||||||
|
"Batteries",
|
||||||
|
"Monitors",
|
||||||
|
"GPUs",
|
||||||
|
"CPUs",
|
||||||
|
"USB",
|
||||||
|
"Serial Ports",
|
||||||
|
"Cameras",
|
||||||
|
"Biometric Devices",
|
||||||
|
]);
|
||||||
|
dt
|
||||||
|
}
|
||||||
|
}
|
||||||
|
use crate::{utils::TAB, device_tree};
|
||||||
|
use crate::tab;
|
||||||
|
impl fmt::Display for DeviceTree {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
writeln!(f)?;
|
||||||
|
for (device_type, devices) in &self.devices {
|
||||||
|
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(())
|
||||||
|
}
|
||||||
|
}
|
66
kernel/src/handle.rs
Normal file
66
kernel/src/handle.rs
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
//! A handle module
|
||||||
|
|
||||||
|
use {
|
||||||
|
crate::arch::hardware_random_u64,
|
||||||
|
core::fmt::{self, Formatter},
|
||||||
|
};
|
||||||
|
/// An operating system handle without permissions attached
|
||||||
|
#[derive(Debug, Eq, Hash, PartialEq, Clone, Copy)]
|
||||||
|
pub struct OSHandle {
|
||||||
|
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,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Handle {
|
||||||
|
/// make a new handle
|
||||||
|
pub fn new() -> Handle {
|
||||||
|
Handle {
|
||||||
|
id: OSHandle::random_new(),
|
||||||
|
perms: Permissions::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// represent the os handle as a u64
|
||||||
|
pub fn as_u64(&self) -> u64 {
|
||||||
|
self.id.id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for Handle {
|
||||||
|
fn fmt(&self, w: &mut Formatter<'_>) -> Result<(), core::fmt::Error> {
|
||||||
|
write!(w, "{:?}", self.id)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(PartialEq, Hash, Eq, Debug, Clone, Copy)]
|
||||||
|
struct Permissions {
|
||||||
|
edit_children: bool,
|
||||||
|
edit_attributes: bool,
|
||||||
|
}
|
||||||
|
impl Permissions {
|
||||||
|
fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
edit_children: true,
|
||||||
|
edit_attributes: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
178
kernel/src/holeybytes/ecah.rs
Normal file
178
kernel/src/holeybytes/ecah.rs
Normal file
|
@ -0,0 +1,178 @@
|
||||||
|
//! Environment call handling routines
|
||||||
|
|
||||||
|
use {
|
||||||
|
super::{mem::Memory, Vm},
|
||||||
|
crate::{arch, holeybytes::mem, ipc::buffer::IpcBuffer, kmain::IPC_BUFFERS},
|
||||||
|
alloc::string::String,
|
||||||
|
log::{debug, error, info, trace, warn},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn handler(vm: &mut Vm) {
|
||||||
|
let r1 = vm.registers[1].cast::<u64>();
|
||||||
|
|
||||||
|
// debug!("Ecall number {:?}", r1);
|
||||||
|
// trace!("Register dump: {:?}", vm.registers);
|
||||||
|
|
||||||
|
match r1 {
|
||||||
|
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[2].cast::<u64>() {
|
||||||
|
0 => false,
|
||||||
|
1 => true,
|
||||||
|
_ => {
|
||||||
|
panic!("Bad");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let length = vm.registers[3].cast::<u64>();
|
||||||
|
|
||||||
|
let mut buffs = IPC_BUFFERS.lock();
|
||||||
|
let abc;
|
||||||
|
|
||||||
|
match bounded {
|
||||||
|
false => {
|
||||||
|
abc = IpcBuffer::new(false, 0);
|
||||||
|
}
|
||||||
|
true => {
|
||||||
|
abc = IpcBuffer::new(true, length);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let buff_id = arch::hardware_random_u64();
|
||||||
|
buffs.insert(buff_id, abc);
|
||||||
|
debug!("Buffer ID: {}", buff_id);
|
||||||
|
vm.registers[1] = hbvm::value::Value(buff_id);
|
||||||
|
}
|
||||||
|
2 => {
|
||||||
|
// Delete buffer
|
||||||
|
}
|
||||||
|
3 => {
|
||||||
|
// Send a message to a buffer
|
||||||
|
let r2 = vm.registers[2].cast::<u64>();
|
||||||
|
let r3 = vm.registers[3].cast::<u64>();
|
||||||
|
let r4 = vm.registers[4].cast::<u64>();
|
||||||
|
|
||||||
|
let buffer_id = r2;
|
||||||
|
let mem_addr = r3;
|
||||||
|
let length = r4 as usize;
|
||||||
|
trace!("IPC address: {:?}", mem_addr);
|
||||||
|
use alloc::vec::Vec;
|
||||||
|
|
||||||
|
match buffer_id {
|
||||||
|
1 => match log_msg_handler(vm, mem_addr, length) {
|
||||||
|
Ok(()) => {}
|
||||||
|
Err(err) => log::error!("Improper log format"),
|
||||||
|
},
|
||||||
|
2 => match memory_msg_handler(vm, mem_addr, length) {
|
||||||
|
Ok(()) => {}
|
||||||
|
Err(err) => log::error!("Improper log format"),
|
||||||
|
},
|
||||||
|
buffer_id => {
|
||||||
|
let mut buffs = IPC_BUFFERS.lock();
|
||||||
|
|
||||||
|
match buffs.get_mut(&buffer_id) {
|
||||||
|
Some(buff) => {
|
||||||
|
let mut msg_vec = vec![];
|
||||||
|
|
||||||
|
for x in 0..(length as isize) {
|
||||||
|
let xyz = mem_addr as *const u8;
|
||||||
|
let value = unsafe { xyz.offset(x).read() };
|
||||||
|
msg_vec.push(value);
|
||||||
|
}
|
||||||
|
buff.push(msg_vec.clone());
|
||||||
|
info!(
|
||||||
|
"Message {:?} has been sent to Buffer({})",
|
||||||
|
msg_vec, buffer_id
|
||||||
|
);
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
log::error!("Access of non-existent buffer {}", buffer_id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
drop(buffs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
4 => {
|
||||||
|
let r2 = vm.registers[2].cast::<u64>();
|
||||||
|
|
||||||
|
let mut buffs = IPC_BUFFERS.lock();
|
||||||
|
let mut buff = buffs.get_mut(&r2).unwrap();
|
||||||
|
let msg = buff.pop();
|
||||||
|
info!("Recieve {:?} from Buffer({})", msg, r2);
|
||||||
|
}
|
||||||
|
5 => {
|
||||||
|
let r2 = vm.registers[2].cast::<u64>();
|
||||||
|
vm.registers[3] = hbvm::value::Value( unsafe { x86_in(r2 as u16) } as u64);
|
||||||
|
}
|
||||||
|
// 5
|
||||||
|
_ => {
|
||||||
|
log::error!("Syscall unknown {:?}{:?}", r1, vm.registers);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn x86_in(address: u16) -> u32{
|
||||||
|
x86_64::instructions::port::Port::new(address).read()
|
||||||
|
}
|
||||||
|
unsafe fn x86_out(address: u16, value: u32){
|
||||||
|
x86_64::instructions::port::Port::new(address).write(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn log_msg_handler(vm: &mut Vm, mem_addr: u64, length: usize) -> Result<(), LogError> {
|
||||||
|
// let message_length = 8 + 8 + 8;
|
||||||
|
// log::info!("Mem Addr 0x{:x?} length {}", mem_addr, length);
|
||||||
|
let mut msg_vec = vec![];
|
||||||
|
|
||||||
|
for x in 0..(length as isize) {
|
||||||
|
let xyz = mem_addr as *const u8;
|
||||||
|
let value = unsafe { xyz.offset(x).read() };
|
||||||
|
// info!("{} - 0x{:x?} - {}", value, value, value as char);
|
||||||
|
msg_vec.push(value);
|
||||||
|
}
|
||||||
|
let log_level = msg_vec.pop().unwrap();
|
||||||
|
match String::from_utf8(msg_vec) {
|
||||||
|
Ok (strr) => {
|
||||||
|
// use LogLevel::*;
|
||||||
|
let ll = match log_level {
|
||||||
|
0 | 48 => error!("{}", strr),
|
||||||
|
1 | 49 => warn!("{}", strr),
|
||||||
|
2 | 50 => info!("{}", strr),
|
||||||
|
3 | 51 => debug!("{}", strr),
|
||||||
|
4 | 52 => trace!("{}", strr),
|
||||||
|
_ => {
|
||||||
|
return Err(LogError::InvalidLogFormat);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
error!("{:?}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum LogError {
|
||||||
|
InvalidLogFormat,
|
||||||
|
}
|
||||||
|
use {alloc::vec, log::Record};
|
||||||
|
|
||||||
|
fn memory_msg_handler(vm: &mut Vm, mem_addr: u64, length: usize) -> Result<(), LogError> {
|
||||||
|
let mut val = alloc::vec::Vec::new();
|
||||||
|
for _ in 0..4096 {
|
||||||
|
val.push(0);
|
||||||
|
}
|
||||||
|
info!("Block address: {:?}", val.as_ptr());
|
||||||
|
vm.registers[1] = hbvm::value::Value(val.as_ptr() as u64);
|
||||||
|
vm.registers[2] = hbvm::value::Value(4096);
|
||||||
|
Ok(())
|
||||||
|
}
|
39
kernel/src/holeybytes/mem.rs
Normal file
39
kernel/src/holeybytes/mem.rs
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
//! 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;
|
||||||
|
|
||||||
|
pub struct Memory;
|
||||||
|
impl hbvm::mem::Memory for Memory {
|
||||||
|
#[inline]
|
||||||
|
unsafe fn load(
|
||||||
|
&mut self,
|
||||||
|
addr: Address,
|
||||||
|
target: *mut u8,
|
||||||
|
count: usize,
|
||||||
|
) -> Result<(), hbvm::mem::LoadError> {
|
||||||
|
core::ptr::copy(addr.get() as *const u8, target, count);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
unsafe fn store(
|
||||||
|
&mut self,
|
||||||
|
addr: Address,
|
||||||
|
source: *const u8,
|
||||||
|
count: usize,
|
||||||
|
) -> Result<(), hbvm::mem::StoreError> {
|
||||||
|
// log::info!("Storing memory");
|
||||||
|
|
||||||
|
core::ptr::copy(source, addr.get() as *mut u8, count);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
unsafe fn prog_read<T: Copy>(&mut self, addr: Address) -> T {
|
||||||
|
(addr.get() as *const T).read_unaligned()
|
||||||
|
}
|
||||||
|
}
|
122
kernel/src/holeybytes/mod.rs
Normal file
122
kernel/src/holeybytes/mod.rs
Normal file
|
@ -0,0 +1,122 @@
|
||||||
|
mod ecah;
|
||||||
|
mod mem;
|
||||||
|
|
||||||
|
use {
|
||||||
|
crate::{arch, ipc::buffer::IpcBuffer, kmain::IPC_BUFFERS},
|
||||||
|
alloc::boxed::Box,
|
||||||
|
core::{default, future::Future, marker::PhantomData, ptr::NonNull, task::Poll},
|
||||||
|
hbvm::{
|
||||||
|
mem::{
|
||||||
|
softpaging::{icache::ICache, HandlePageFault, SoftPagedMem},
|
||||||
|
Address, Memory,
|
||||||
|
},
|
||||||
|
VmRunError, VmRunOk,
|
||||||
|
},
|
||||||
|
log::{debug, error, info, trace, warn},
|
||||||
|
};
|
||||||
|
|
||||||
|
const STACK_SIZE: usize = 1024 * 1024;
|
||||||
|
const TIMER_QUOTIENT: usize = 100;
|
||||||
|
type Vm = hbvm::Vm<mem::Memory, TIMER_QUOTIENT>;
|
||||||
|
|
||||||
|
pub struct ExecThread<'p> {
|
||||||
|
vm: Vm,
|
||||||
|
stack_bottom: *mut u8,
|
||||||
|
_phantom: PhantomData<&'p [u8]>,
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl<'p> Send for ExecThread<'p> {}
|
||||||
|
impl<'p> ExecThread<'p> {
|
||||||
|
pub fn set_arguments(&mut self, ptr: u64, length: u64) {
|
||||||
|
self.vm.registers[1] = hbvm::value::Value(ptr);
|
||||||
|
self.vm.registers[2] = hbvm::value::Value(length);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn new(program: &'p [u8], entrypoint: Address) -> Self {
|
||||||
|
let mut vm = unsafe {
|
||||||
|
Vm::new(
|
||||||
|
mem::Memory,
|
||||||
|
Address::new(program.as_ptr() as u64 + entrypoint.get()),
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
let stack_bottom = unsafe { allocate_stack().as_ptr() };
|
||||||
|
vm.write_reg(254, (stack_bottom as usize + STACK_SIZE - 1) as u64);
|
||||||
|
|
||||||
|
ExecThread {
|
||||||
|
vm,
|
||||||
|
stack_bottom,
|
||||||
|
_phantom: Default::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'p> Drop for ExecThread<'p> {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
unsafe { alloc::alloc::dealloc(self.stack_bottom, stack_layout()) };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'p> Future for ExecThread<'p> {
|
||||||
|
type Output = Result<(), VmRunError>;
|
||||||
|
|
||||||
|
fn poll(
|
||||||
|
mut self: core::pin::Pin<&mut Self>,
|
||||||
|
cx: &mut core::task::Context<'_>,
|
||||||
|
) -> Poll<Self::Output> {
|
||||||
|
match self.vm.run() {
|
||||||
|
Err(err) => {
|
||||||
|
log::error!("HBVM Error\r\nRegister dump: {:?}", self.vm.registers,);
|
||||||
|
return Poll::Ready(Err(err));
|
||||||
|
}
|
||||||
|
Ok(VmRunOk::End) => return Poll::Ready(Ok(())),
|
||||||
|
Ok(VmRunOk::Ecall) => ecah::handler(&mut self.vm),
|
||||||
|
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
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
|
log::error!(
|
||||||
|
"REASON: {reason} \
|
||||||
|
vaddr: {vaddr} \
|
||||||
|
size: {size:?} \
|
||||||
|
Dataptr {dataptr:p}",
|
||||||
|
);
|
||||||
|
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const fn stack_layout() -> core::alloc::Layout {
|
||||||
|
unsafe { alloc::alloc::Layout::from_size_align_unchecked(STACK_SIZE, 4096) }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn allocate_stack() -> NonNull<u8> {
|
||||||
|
let layout = stack_layout();
|
||||||
|
match NonNull::new(unsafe { alloc::alloc::alloc_zeroed(layout) }) {
|
||||||
|
Some(ptr) => ptr,
|
||||||
|
None => alloc::alloc::handle_alloc_error(layout),
|
||||||
|
}
|
||||||
|
}
|
88
kernel/src/ipc/buffer.rs
Normal file
88
kernel/src/ipc/buffer.rs
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
//!
|
||||||
|
|
||||||
|
use {
|
||||||
|
super::message::Message,
|
||||||
|
crossbeam_queue::{ArrayQueue, SegQueue},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub enum BufferTypes {
|
||||||
|
Unbound(SegQueue<Message>),
|
||||||
|
Bound(ArrayQueue<Message>),
|
||||||
|
}
|
||||||
|
/// Interproccess buffer
|
||||||
|
pub struct IpcBuffer {
|
||||||
|
pub protocol: Protocol,
|
||||||
|
pub buffer: BufferTypes,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IpcBuffer {
|
||||||
|
pub fn new(bounded: bool, length: u64) -> Self {
|
||||||
|
log::debug!(
|
||||||
|
"New IPCBuffer\r
|
||||||
|
bounded: {}\r
|
||||||
|
length: {:?}\r",
|
||||||
|
bounded,
|
||||||
|
length
|
||||||
|
);
|
||||||
|
|
||||||
|
match (bounded, length) {
|
||||||
|
(false, a) => {
|
||||||
|
let buftype = BufferTypes::Unbound(SegQueue::new());
|
||||||
|
|
||||||
|
Self {
|
||||||
|
protocol: Protocol {},
|
||||||
|
buffer: buftype,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(true, length) => {
|
||||||
|
let buftype = BufferTypes::Bound(ArrayQueue::new(length as usize));
|
||||||
|
Self {
|
||||||
|
protocol: Protocol {},
|
||||||
|
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.clone()),
|
||||||
|
BufferTypes::Bound(buff) => {
|
||||||
|
let _ = buff.push(msg.clone());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
pub fn pop(&mut self) -> Message {
|
||||||
|
let msg = match &self.buffer {
|
||||||
|
BufferTypes::Unbound(buff) => buff.pop(),
|
||||||
|
BufferTypes::Bound(buff) => buff.pop(),
|
||||||
|
};
|
||||||
|
match msg {
|
||||||
|
Some(msg) => return msg,
|
||||||
|
None => panic!("Recieving msg error. No messages!"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// Interprocess Communication Errors
|
||||||
|
pub enum IpcError {
|
||||||
|
/// An invalid message error returned to the sender
|
||||||
|
InvalidMessage,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// TODO: define this, possibly as the binary form of the IDL
|
||||||
|
/// DEPEND: This depends on an IDL
|
||||||
|
pub struct Protocol {
|
||||||
|
// TODO: add in settings
|
||||||
|
// like `invalid_message_handler` with some options similar to
|
||||||
|
// `Deny` Drops the message
|
||||||
|
// `Allow` Allows invalid messages (This disables validators IPC side and relies on programs to handle invalid messages)
|
||||||
|
// `CustomFunct` a callback
|
||||||
|
// and `report_invalid_messages_to_sender`
|
||||||
|
// `True`
|
||||||
|
// `False`
|
||||||
|
// settings: PSettings,
|
||||||
|
}
|
7
kernel/src/ipc/message.rs
Normal file
7
kernel/src/ipc/message.rs
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
//! 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>;
|
3
kernel/src/ipc/mod.rs
Normal file
3
kernel/src/ipc/mod.rs
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
//! Interprocess communication
|
||||||
|
pub mod buffer;
|
||||||
|
pub mod message;
|
|
@ -1,15 +1,126 @@
|
||||||
//! AbleOS Kernel Entrypoint
|
//! AbleOS Kernel Entrypoint
|
||||||
|
|
||||||
pub fn kmain(cmdline: &str, bootstrap: Option<&'static [u8]>) -> ! {
|
use {
|
||||||
log::debug!("Entered kmain");
|
crate::{
|
||||||
|
bootmodules::{build_cmd, BootModules},
|
||||||
|
capabilities,
|
||||||
|
device_tree::DeviceTree,
|
||||||
|
holeybytes::ExecThread,
|
||||||
|
ipc::buffer::{self, IpcBuffer},
|
||||||
|
},
|
||||||
|
alloc::format,
|
||||||
|
hashbrown::HashMap,
|
||||||
|
hbvm::mem::Address,
|
||||||
|
limine::{Framebuffer, FramebufferRequest, NonNullPtr},
|
||||||
|
log::{debug, info, trace},
|
||||||
|
spin::{Lazy, Mutex},
|
||||||
|
xml::XMLElement,
|
||||||
|
};
|
||||||
|
|
||||||
// TODO: Actual cmdline parsing (Serde?)
|
pub fn kmain(cmdline: &str, boot_modules: BootModules) -> ! {
|
||||||
if cmdline.contains("baka=9") {
|
debug!("Entered kmain");
|
||||||
let _ = crate::arch::log(format_args!(include_str!("../data/⑨. バカ")));
|
|
||||||
|
let kcmd = build_cmd("Kernel Command Line", cmdline);
|
||||||
|
trace!("Cmdline: {kcmd:?}");
|
||||||
|
|
||||||
|
// for (i, bm) in boot_modules.iter().enumerate() {
|
||||||
|
// let name = format!("module-{}", i);
|
||||||
|
// let _bmcmd: XMLElement;
|
||||||
|
// if bm.cmd.len() >= 2 {
|
||||||
|
// // TODO: pass into the program
|
||||||
|
// // Pass CMDLine into an IPCBuffer and put the ptr to the IPCBuffer in r200
|
||||||
|
// _bmcmd = build_cmd(name, bm.cmd.clone());
|
||||||
|
// log::info!("{:?}", _bmcmd);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
let dt = DEVICE_TREE.lock();
|
||||||
|
|
||||||
|
// TODO(Able): This line causes a deadlock
|
||||||
|
info!("Device Tree: {}", dt);
|
||||||
|
|
||||||
|
info!("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];
|
||||||
|
|
||||||
|
{
|
||||||
|
use crate::alloc::string::ToString;
|
||||||
|
let mut dt = DEVICE_TREE.lock();
|
||||||
|
let mut disp = xml::XMLElement::new("display_0");
|
||||||
|
|
||||||
|
disp.set_attribute("width", fb1.width);
|
||||||
|
disp.set_attribute("height", fb1.height);
|
||||||
|
disp.set_attribute("bits per pixel", fb1.bpp);
|
||||||
|
disp.set_attribute("pitch", fb1.pitch);
|
||||||
|
dt.devices.insert("Displays".to_string(), alloc::vec![disp]);
|
||||||
|
}
|
||||||
|
log::info!("Graphics initialised");
|
||||||
|
log::info!(
|
||||||
|
"Graphics front ptr {:?}",
|
||||||
|
fb1.address.as_ptr().unwrap() as *const u8
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut executor = crate::task::Executor::default();
|
||||||
|
let bm_take = boot_modules.len();
|
||||||
|
unsafe {
|
||||||
|
for module in boot_modules.into_iter().take(bm_take) {
|
||||||
|
let mut cmd = module.cmd;
|
||||||
|
if cmd.len() > 2 {
|
||||||
|
// Remove the quotes
|
||||||
|
cmd.remove(0);
|
||||||
|
cmd.pop();
|
||||||
|
}
|
||||||
|
let cmd_len = cmd.as_bytes().len() as u64;
|
||||||
|
|
||||||
|
log::info!("Spawning {} with arguments \"{}\"", module.path, cmd);
|
||||||
|
|
||||||
|
executor.spawn(async move {
|
||||||
|
let mut thr = ExecThread::new(&module.bytes, Address::new(0));
|
||||||
|
if cmd_len > 0 {
|
||||||
|
thr.set_arguments(cmd.as_bytes().as_ptr() as u64, cmd_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
log::info!("Cmdline: \"{cmdline}\"");
|
if let Err(e) = thr.await {
|
||||||
let bootstrap = bootstrap.expect("no bootstrap found");
|
log::error!("{e:?}");
|
||||||
|
}
|
||||||
crate::arch::sloop()
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
executor.run();
|
||||||
|
};
|
||||||
|
|
||||||
|
crate::arch::spin_loop()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub static DEVICE_TREE: Lazy<Mutex<DeviceTree>> = Lazy::new(|| {
|
||||||
|
let dt = DeviceTree::new();
|
||||||
|
Mutex::new(dt)
|
||||||
|
});
|
||||||
|
pub static FB_REQ: FramebufferRequest = FramebufferRequest::new(0);
|
||||||
|
|
||||||
|
use alloc::vec::Vec;
|
||||||
|
pub type IpcBuffers = HashMap<u64, IpcBuffer>;
|
||||||
|
pub 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)
|
||||||
|
});
|
||||||
|
|
||||||
|
#[test_case]
|
||||||
|
fn trivial_assertion() {
|
||||||
|
trace!("trivial assertion... ");
|
||||||
|
assert_eq!(1, 1);
|
||||||
|
info!("[ok]");
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,25 +1,35 @@
|
||||||
//! The ableOS kernel.
|
//! The ableOS kernel.
|
||||||
|
//! Named akern.
|
||||||
|
//! Akern is woefully undersupported at the moment but we are looking to add support improve hardware discovery and make our lives as kernel and operating system developers easier and better
|
||||||
|
|
||||||
|
#![no_std]
|
||||||
#![feature(
|
#![feature(
|
||||||
abi_x86_interrupt,
|
abi_x86_interrupt,
|
||||||
alloc_error_handler,
|
alloc_error_handler,
|
||||||
inline_const,
|
inline_const,
|
||||||
panic_info_message,
|
panic_info_message,
|
||||||
pointer_is_aligned,
|
pointer_is_aligned,
|
||||||
prelude_import,
|
ptr_sub_ptr,
|
||||||
ptr_sub_ptr
|
custom_test_frameworks,
|
||||||
|
naked_functions,
|
||||||
)]
|
)]
|
||||||
#![no_std]
|
#![allow(dead_code)]
|
||||||
|
#![test_runner(crate::test_runner)]
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
|
|
||||||
mod allocator;
|
mod allocator;
|
||||||
mod arch;
|
mod arch;
|
||||||
|
mod bootmodules;
|
||||||
|
mod capabilities;
|
||||||
|
mod device_tree;
|
||||||
|
mod handle;
|
||||||
|
mod holeybytes;
|
||||||
|
mod ipc;
|
||||||
mod kmain;
|
mod kmain;
|
||||||
mod logger;
|
mod logger;
|
||||||
mod memory;
|
mod memory;
|
||||||
mod task;
|
mod task;
|
||||||
mod ubloader;
|
mod utils;
|
||||||
|
|
||||||
use versioning::Version;
|
use versioning::Version;
|
||||||
|
|
||||||
|
@ -32,6 +42,8 @@ pub const VERSION: Version = Version {
|
||||||
|
|
||||||
#[panic_handler]
|
#[panic_handler]
|
||||||
fn panic(info: &core::panic::PanicInfo) -> ! {
|
fn panic(info: &core::panic::PanicInfo) -> ! {
|
||||||
|
arch::register_dump();
|
||||||
|
|
||||||
if let Some(loc) = info.location() {
|
if let Some(loc) = info.location() {
|
||||||
let _ = crate::arch::log(format_args!(
|
let _ = crate::arch::log(format_args!(
|
||||||
"Location: {}: {}, {}\r\n",
|
"Location: {}: {}, {}\r\n",
|
||||||
|
@ -47,3 +59,11 @@ fn panic(info: &core::panic::PanicInfo) -> ! {
|
||||||
|
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
fn test_runner(tests: &[&dyn Fn()]) {
|
||||||
|
println!("Running {} tests", tests.len());
|
||||||
|
for test in tests {
|
||||||
|
test();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,29 +1,40 @@
|
||||||
use log::{Level, SetLoggerError};
|
// 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},
|
||||||
|
};
|
||||||
|
|
||||||
pub fn init() -> Result<(), SetLoggerError> {
|
pub fn init() -> Result<(), SetLoggerError> {
|
||||||
log::set_logger(&crate::logger::Logger)?;
|
log::set_logger(&crate::logger::Logger)?;
|
||||||
log::set_max_level(log::LevelFilter::Trace);
|
log::set_max_level(log::LevelFilter::Debug);
|
||||||
|
|
||||||
|
Lazy::force(&TERMINAL_LOGGER);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Logger;
|
struct Logger;
|
||||||
impl log::Log for Logger {
|
impl log::Log for Logger {
|
||||||
fn enabled(&self, metadata: &log::Metadata) -> bool {
|
fn enabled(&self, _metadata: &log::Metadata) -> bool {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
fn log(&self, record: &log::Record) {
|
fn log(&self, record: &log::Record) {
|
||||||
let lvl = record.level();
|
let lvl = record.level();
|
||||||
crate::arch::log(format_args!(
|
let lvl_color = match lvl {
|
||||||
"\x1b[38;5;{}m{lvl}\x1b[0m [{}]: {}\r\n",
|
|
||||||
match lvl {
|
|
||||||
Level::Error => "160",
|
Level::Error => "160",
|
||||||
Level::Warn => "172",
|
Level::Warn => "172",
|
||||||
Level::Info => "47",
|
Level::Info => "47",
|
||||||
Level::Debug => "25",
|
Level::Debug => "25",
|
||||||
Level::Trace => "103",
|
Level::Trace => "103",
|
||||||
},
|
};
|
||||||
record.module_path().unwrap_or_default(),
|
let module = record.module_path().unwrap_or_default();
|
||||||
|
let line = record.line().unwrap_or_default();
|
||||||
|
crate::arch::log(format_args!(
|
||||||
|
"\x1b[38;5;{lvl_color}m{lvl}\x1b[0m [{module}:{line}]: {}\r\n",
|
||||||
record.args(),
|
record.args(),
|
||||||
))
|
))
|
||||||
.expect("write to serial console");
|
.expect("write to serial console");
|
||||||
|
@ -31,3 +42,28 @@ impl log::Log for Logger {
|
||||||
|
|
||||||
fn flush(&self) {}
|
fn flush(&self) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct TermLogger(&'static TerminalResponse);
|
||||||
|
unsafe impl Send for TermLogger {}
|
||||||
|
impl TermLogger {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
static TERM_REQ: TerminalRequest = TerminalRequest::new(0);
|
||||||
|
Self(
|
||||||
|
TERM_REQ
|
||||||
|
.get_response()
|
||||||
|
.get()
|
||||||
|
.expect("failed to get terminal response"),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl core::fmt::Write for TermLogger {
|
||||||
|
fn write_str(&mut self, s: &str) -> core::fmt::Result {
|
||||||
|
if let (Some(w), ts) = (self.0.write(), self.0.terminals()) {
|
||||||
|
for term in ts {
|
||||||
|
w(term, s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,21 +1,19 @@
|
||||||
//! Async task and executor
|
#![allow(unused)]
|
||||||
|
|
||||||
use alloc::{boxed::Box, collections::BTreeMap, sync::Arc, task::Wake};
|
use {
|
||||||
use core::{
|
alloc::{boxed::Box, collections::BTreeMap, sync::Arc, task::Wake},
|
||||||
|
core::{
|
||||||
future::Future,
|
future::Future,
|
||||||
pin::Pin,
|
pin::Pin,
|
||||||
task::{Context, Poll, Waker},
|
task::{Context, Poll, Waker},
|
||||||
|
},
|
||||||
|
crossbeam_queue::SegQueue,
|
||||||
|
kiam::when,
|
||||||
|
slab::Slab,
|
||||||
|
spin::RwLock,
|
||||||
};
|
};
|
||||||
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);
|
static SPAWN_QUEUE: RwLock<Option<SpawnQueue>> = RwLock::new(None);
|
||||||
|
|
||||||
/// Spawn a new task
|
|
||||||
pub fn spawn(future: impl Future<Output = ()> + Send + 'static) {
|
pub fn spawn(future: impl Future<Output = ()> + Send + 'static) {
|
||||||
match &*SPAWN_QUEUE.read() {
|
match &*SPAWN_QUEUE.read() {
|
||||||
Some(s) => s.push(Task::new(future)),
|
Some(s) => s.push(Task::new(future)),
|
||||||
|
@ -23,7 +21,6 @@ pub fn spawn(future: impl Future<Output = ()> + Send + 'static) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Forcibly yield a task
|
|
||||||
pub fn yield_now() -> impl Future<Output = ()> {
|
pub fn yield_now() -> impl Future<Output = ()> {
|
||||||
struct YieldNow(bool);
|
struct YieldNow(bool);
|
||||||
impl Future for YieldNow {
|
impl Future for YieldNow {
|
||||||
|
@ -43,52 +40,40 @@ pub fn yield_now() -> impl Future<Output = ()> {
|
||||||
YieldNow(false)
|
YieldNow(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Tasks executor
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct Executor {
|
pub struct Executor {
|
||||||
/// All spawned tasks' stash
|
|
||||||
tasks: Slab<Task>,
|
tasks: Slab<Task>,
|
||||||
|
|
||||||
/// Awake tasks' queue
|
|
||||||
queue: TaskQueue,
|
queue: TaskQueue,
|
||||||
|
to_spawn: SpawnQueue,
|
||||||
/// Incoming tasks to enqueue
|
|
||||||
incoming: SpawnQueue,
|
|
||||||
|
|
||||||
/// Wakers
|
|
||||||
wakers: BTreeMap<TaskId, Waker>,
|
wakers: BTreeMap<TaskId, Waker>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Executor {
|
impl Executor {
|
||||||
/// Spawn a task
|
|
||||||
pub fn spawn(&mut self, future: impl Future<Output = ()> + Send + 'static) {
|
pub fn spawn(&mut self, future: impl Future<Output = ()> + Send + 'static) {
|
||||||
self.queue
|
self.queue
|
||||||
.push(TaskId(self.tasks.insert(Task::new(future))));
|
.push(TaskId(self.tasks.insert(Task::new(future))));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Spin poll loop until it runs out of tasks
|
|
||||||
pub fn run(&mut self) {
|
pub fn run(&mut self) {
|
||||||
// Assign `self.incoming` to global spawn queue to spawn tasks
|
|
||||||
// from within
|
|
||||||
{
|
{
|
||||||
let mut spawner = SPAWN_QUEUE.write();
|
let mut global_spawner = SPAWN_QUEUE.write();
|
||||||
if spawner.is_some() {
|
if global_spawner.is_some() {
|
||||||
panic!("task executor is already running");
|
panic!("Task executor is already running");
|
||||||
}
|
}
|
||||||
|
|
||||||
*spawner = Some(Arc::clone(&self.incoming));
|
*global_spawner = Some(Arc::clone(&self.to_spawn));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try to get incoming task, if none available, poll
|
loop {
|
||||||
// enqueued one
|
when! {
|
||||||
while let Some(id) = self
|
let Some(id) = self
|
||||||
.incoming
|
.to_spawn
|
||||||
.pop()
|
.pop()
|
||||||
.map(|t| TaskId(self.tasks.insert(t)))
|
.map(|t| TaskId(self.tasks.insert(t)))
|
||||||
.or_else(|| self.queue.pop())
|
.or_else(|| self.queue.pop())
|
||||||
{
|
=> {
|
||||||
let Some(task) = self.tasks.get_mut(id.0) else {
|
let Some(task) = self.tasks.get_mut(id.0) else {
|
||||||
panic!("attempted to get non-extant task with id {}", id.0)
|
panic!("Attempted to get task from empty slot: {}", id.0);
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut cx = Context::from_waker(self.wakers.entry(id).or_insert_with(|| {
|
let mut cx = Context::from_waker(self.wakers.entry(id).or_insert_with(|| {
|
||||||
|
@ -100,29 +85,28 @@ impl Executor {
|
||||||
|
|
||||||
match task.poll(&mut cx) {
|
match task.poll(&mut cx) {
|
||||||
Poll::Ready(()) => {
|
Poll::Ready(()) => {
|
||||||
// Task done, unregister
|
|
||||||
self.tasks.remove(id.0);
|
self.tasks.remove(id.0);
|
||||||
self.wakers.remove(&id);
|
self.wakers.remove(&id);
|
||||||
}
|
}
|
||||||
Poll::Pending => (),
|
Poll::Pending => (),
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
self.tasks.is_empty() => break,
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
*SPAWN_QUEUE.write() = None;
|
*SPAWN_QUEUE.write() = None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
|
||||||
struct TaskId(usize);
|
|
||||||
|
|
||||||
/// Async task
|
|
||||||
struct Task {
|
struct Task {
|
||||||
future: Pin<Box<dyn Future<Output = ()> + Send>>,
|
future: Pin<Box<dyn Future<Output = ()> + Send>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Task {
|
impl Task {
|
||||||
/// Create a new task from a future
|
pub fn new(future: impl Future<Output = ()> + Send + 'static) -> Self {
|
||||||
fn new(future: impl Future<Output = ()> + Send + 'static) -> Self {
|
log::trace!("New task scheduled");
|
||||||
Self {
|
Self {
|
||||||
future: Box::pin(future),
|
future: Box::pin(future),
|
||||||
}
|
}
|
||||||
|
@ -133,6 +117,12 @@ impl Task {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
|
struct TaskId(usize);
|
||||||
|
|
||||||
|
type TaskQueue = Arc<SegQueue<TaskId>>;
|
||||||
|
type SpawnQueue = Arc<SegQueue<Task>>;
|
||||||
|
|
||||||
struct TaskWaker {
|
struct TaskWaker {
|
||||||
id: TaskId,
|
id: TaskId,
|
||||||
queue: TaskQueue,
|
queue: TaskQueue,
|
||||||
|
@ -140,6 +130,7 @@ struct TaskWaker {
|
||||||
|
|
||||||
impl Wake for TaskWaker {
|
impl Wake for TaskWaker {
|
||||||
fn wake(self: Arc<Self>) {
|
fn wake(self: Arc<Self>) {
|
||||||
|
log::trace!("Woke Task-{:?}", self.id);
|
||||||
self.wake_by_ref();
|
self.wake_by_ref();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
53
kernel/src/utils.rs
Normal file
53
kernel/src/utils.rs
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
//! 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.to_string(), 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));
|
||||||
|
};
|
||||||
|
}
|
25
kernel/targets/aarch64-virt-ableos.json
Normal file
25
kernel/targets/aarch64-virt-ableos.json
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
{
|
||||||
|
"arch": "aarch64",
|
||||||
|
"data-layout": "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128",
|
||||||
|
"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": ""
|
||||||
|
}
|
|
@ -11,7 +11,7 @@
|
||||||
"linker": "rust-lld",
|
"linker": "rust-lld",
|
||||||
"panic-strategy": "abort",
|
"panic-strategy": "abort",
|
||||||
"disable-redzone": true,
|
"disable-redzone": true,
|
||||||
"features": "-mmx,-sse,+soft-float",
|
"features": "",
|
||||||
"code-model": "kernel",
|
"code-model": "kernel",
|
||||||
"pre-link-args": {
|
"pre-link-args": {
|
||||||
"ld.lld": [
|
"ld.lld": [
|
||||||
|
|
2
limine
2
limine
|
@ -1 +1 @@
|
||||||
Subproject commit 83779119f658c8ce337c33492266ecf8300db429
|
Subproject commit 2d3d7b2633b5d95ce404a177ada0d5cbee802721
|
|
@ -4,7 +4,12 @@ version = "0.2.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
env_logger = "0.10"
|
derive_more = "0.99"
|
||||||
error-stack = "0.2"
|
error-stack = "0.4"
|
||||||
fatfs = "0.3"
|
fatfs = "0.3"
|
||||||
log = "0.4"
|
hbasm.git = "https://git.ablecorp.us/AbleOS/holey-bytes.git"
|
||||||
|
|
||||||
|
[dependencies.reqwest]
|
||||||
|
version = "0.11"
|
||||||
|
default-features = false
|
||||||
|
features = ["rustls-tls", "blocking"]
|
||||||
|
|
|
@ -1,21 +0,0 @@
|
||||||
${ABLEOS_KERNEL}=boot:///kernel
|
|
||||||
# TODO: Make a boot background image for ableOS
|
|
||||||
|
|
||||||
DEFAULT_ENTRY=1
|
|
||||||
TIMEOUT=3
|
|
||||||
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=
|
|
||||||
# Setting a default resolution for the framebuffer
|
|
||||||
RESOLUTION=1024x768x24
|
|
||||||
|
|
||||||
# MODULE_PATH=boot:///boot/initrd.tar
|
|
||||||
# MODULE_CMDLINE=This is the first module.
|
|
|
@ -1,12 +1,22 @@
|
||||||
use error_stack::{bail, report, Context, IntoReport, Result, ResultExt};
|
use {
|
||||||
use fatfs::{FileSystem, FormatVolumeOptions, FsOptions, ReadWriteSeek};
|
derive_more::Display,
|
||||||
use std::{fmt::Display, fs::File, io, path::Path, process::Command};
|
error_stack::{bail, report, Context, Report, Result, ResultExt},
|
||||||
|
fatfs::{FileSystem, FormatVolumeOptions, FsOptions, ReadWriteSeek},
|
||||||
|
std::{fmt::Display, fs::File, io, path::Path, process::Command},
|
||||||
|
};
|
||||||
|
|
||||||
fn main() -> Result<(), Error> {
|
fn main() -> Result<(), Error> {
|
||||||
env_logger::init();
|
|
||||||
let mut args = std::env::args();
|
let mut args = std::env::args();
|
||||||
args.next();
|
args.next();
|
||||||
|
|
||||||
|
// let disk_meta = fs::metadata("target/disk.img").unwrap();
|
||||||
|
// let config_meta = fs::metadata("system.toml").unwrap();
|
||||||
|
|
||||||
|
// if disk_meta.modified().unwrap() < config_meta.modified().unwrap() {
|
||||||
|
// // TODO: work on adding in system.toml support
|
||||||
|
// // TODO: rebuild the disk
|
||||||
|
// }
|
||||||
|
|
||||||
match args.next().as_deref() {
|
match args.next().as_deref() {
|
||||||
Some("build" | "b") => {
|
Some("build" | "b") => {
|
||||||
let mut release = false;
|
let mut release = false;
|
||||||
|
@ -14,12 +24,16 @@ fn main() -> Result<(), Error> {
|
||||||
for arg in args {
|
for arg in args {
|
||||||
if arg == "-r" || arg == "--release" {
|
if arg == "-r" || arg == "--release" {
|
||||||
release = true;
|
release = true;
|
||||||
}
|
} else if arg == "rv64" || arg == "riscv64" || arg == "riscv64-virt" {
|
||||||
if arg == "rv64" || arg == "riscv64" || arg == "riscv64-virt" {
|
|
||||||
target = Target::Riscv64Virt;
|
target = Target::Riscv64Virt;
|
||||||
|
} else if arg == "arm64" || arg == "aarch64" || arg == "aarch64-virt" {
|
||||||
|
target = Target::Aarch64;
|
||||||
|
} else {
|
||||||
|
return Err(report!(Error::InvalidSubCom));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
assemble()?;
|
||||||
build(release, target).change_context(Error::Build)
|
build(release, target).change_context(Error::Build)
|
||||||
}
|
}
|
||||||
Some("run" | "r") => {
|
Some("run" | "r") => {
|
||||||
|
@ -28,12 +42,16 @@ fn main() -> Result<(), Error> {
|
||||||
for arg in args {
|
for arg in args {
|
||||||
if arg == "-r" || arg == "--release" {
|
if arg == "-r" || arg == "--release" {
|
||||||
release = true;
|
release = true;
|
||||||
}
|
} else if arg == "rv64" || arg == "riscv64" || arg == "riscv64-virt" {
|
||||||
if arg == "rv64" || arg == "riscv64" || arg == "riscv64-virt" {
|
|
||||||
target = Target::Riscv64Virt;
|
target = Target::Riscv64Virt;
|
||||||
|
} else if arg == "arm64" || arg == "aarch64" || arg == "aarch64-virt" {
|
||||||
|
target = Target::Aarch64;
|
||||||
|
} else {
|
||||||
|
return Err(report!(Error::InvalidSubCom));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
assemble()?;
|
||||||
build(release, target)?;
|
build(release, target)?;
|
||||||
run(release, target)
|
run(release, target)
|
||||||
}
|
}
|
||||||
|
@ -54,26 +72,55 @@ fn main() -> Result<(), Error> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn assemble() -> Result<(), Error> {
|
||||||
|
match std::fs::create_dir("target/test-programs") {
|
||||||
|
Ok(_) => (),
|
||||||
|
Err(e) if e.kind() == std::io::ErrorKind::AlreadyExists => (),
|
||||||
|
Err(e) => return Err(Report::new(e).change_context(Error::Io)),
|
||||||
|
}
|
||||||
|
|
||||||
|
for entry in std::fs::read_dir("sysdata/test-programs")
|
||||||
|
.map_err(Report::from)
|
||||||
|
.change_context(Error::Io)?
|
||||||
|
{
|
||||||
|
let entry = entry.map_err(Report::from).change_context(Error::Io)?;
|
||||||
|
if !entry
|
||||||
|
.file_type()
|
||||||
|
.map_err(Report::from)
|
||||||
|
.change_context(Error::Io)?
|
||||||
|
.is_file()
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let name = entry.file_name();
|
||||||
|
let name = name.to_string_lossy();
|
||||||
|
let name = name.trim_end_matches(".rhai");
|
||||||
|
|
||||||
|
let mut out = File::options()
|
||||||
|
.write(true)
|
||||||
|
.create(true)
|
||||||
|
.open(Path::new("target/test-programs").join(format!("{name}.hbf")))
|
||||||
|
.map_err(Report::from)
|
||||||
|
.change_context(Error::Io)?;
|
||||||
|
|
||||||
|
out.set_len(0)
|
||||||
|
.map_err(Report::from)
|
||||||
|
.change_context(Error::Io)?;
|
||||||
|
|
||||||
|
hbasm::assembler(&mut out, |engine| engine.run_file(entry.path()))
|
||||||
|
.map_err(|e| report!(Error::Assembler).attach_printable(e.to_string()))?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn get_fs() -> Result<FileSystem<impl ReadWriteSeek>, io::Error> {
|
fn get_fs() -> Result<FileSystem<impl ReadWriteSeek>, io::Error> {
|
||||||
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()
|
let mut img = File::options()
|
||||||
.read(true)
|
.read(true)
|
||||||
.write(true)
|
.write(true)
|
||||||
.create(true)
|
.create(true)
|
||||||
.open(path)?;
|
.open(Path::new("target/disk.img"))?;
|
||||||
|
|
||||||
img.set_len(1024 * 1024 * 64)?;
|
img.set_len(1024 * 1024 * 64)?;
|
||||||
|
|
||||||
|
@ -84,20 +131,37 @@ fn get_fs() -> Result<FileSystem<impl ReadWriteSeek>, io::Error> {
|
||||||
|
|
||||||
io::copy(
|
io::copy(
|
||||||
&mut File::open("limine/BOOTX64.EFI")
|
&mut File::open("limine/BOOTX64.EFI")
|
||||||
.into_report()
|
.map_err(Report::from)
|
||||||
.attach_printable("copying Limine bootloader (have you pulled the submodule?)")?,
|
.attach_printable("Copying Limine (x86_64): have you pulled the submodule?")?,
|
||||||
&mut bootdir.create_file("bootx64.efi")?,
|
&mut bootdir.create_file("bootx64.efi")?,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
io::copy(
|
io::copy(
|
||||||
&mut File::open("repbuild/limine.cfg")?,
|
&mut File::open("limine/BOOTAA64.EFI")
|
||||||
&mut fs.root_dir().create_file("limine.cfg")?,
|
.map_err(Report::from)
|
||||||
|
.attach_printable("Copying Limine (ARM): have you pulled the submodule?")?,
|
||||||
|
&mut bootdir.create_file("bootaa64.efi")?,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
|
for fpath in [
|
||||||
|
"sysdata/limine.cfg",
|
||||||
|
"sysdata/background.bmp",
|
||||||
|
"target/test-programs/failure.hbf",
|
||||||
|
"target/test-programs/ecall.hbf",
|
||||||
|
"target/test-programs/main.hbf",
|
||||||
|
"target/test-programs/serial_driver.hbf",
|
||||||
|
"target/test-programs/vfs_test.hbf",
|
||||||
|
"target/test-programs/limine_framebuffer_driver.hbf",
|
||||||
|
"target/test-programs/keyboard_driver.hbf",
|
||||||
|
] {
|
||||||
|
let path = Path::new(fpath);
|
||||||
io::copy(
|
io::copy(
|
||||||
&mut File::open("repbuild/background.bmp")?,
|
&mut File::open(path)?,
|
||||||
&mut fs.root_dir().create_file("background.bmp")?,
|
&mut fs
|
||||||
|
.root_dir()
|
||||||
|
.create_file(&path.file_name().unwrap().to_string_lossy())?,
|
||||||
)?;
|
)?;
|
||||||
|
}
|
||||||
|
|
||||||
drop(bootdir);
|
drop(bootdir);
|
||||||
Ok(fs)
|
Ok(fs)
|
||||||
|
@ -112,11 +176,11 @@ fn build(release: bool, target: Target) -> Result<(), Error> {
|
||||||
com.arg("-r");
|
com.arg("-r");
|
||||||
}
|
}
|
||||||
|
|
||||||
match target {
|
if target == Target::Riscv64Virt {
|
||||||
Target::Riscv64Virt => {
|
|
||||||
com.args(["--target", "targets/riscv64-virt-ableos.json"]);
|
com.args(["--target", "targets/riscv64-virt-ableos.json"]);
|
||||||
}
|
}
|
||||||
_ => {}
|
if target == Target::Aarch64 {
|
||||||
|
com.args(["--target", "targets/aarch64-virt-ableos.json"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
match com.status() {
|
match com.status() {
|
||||||
|
@ -125,22 +189,31 @@ fn build(release: bool, target: Target) -> Result<(), Error> {
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
|
|
||||||
if target != Target::X86_64 {
|
let mut path: String = "kernel".to_string();
|
||||||
return Ok(());
|
let kernel_dir = match target {
|
||||||
|
Target::X86_64 => {
|
||||||
|
path.push_str("_x86-64");
|
||||||
|
"target/x86_64-ableos"
|
||||||
}
|
}
|
||||||
|
Target::Riscv64Virt => "target/riscv64-virt-ableos",
|
||||||
|
Target::Aarch64 => {
|
||||||
|
path.push_str("_aarch64");
|
||||||
|
"target/aarch64-virt-ableos"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
(|| -> std::io::Result<_> {
|
(|| -> std::io::Result<_> {
|
||||||
io::copy(
|
io::copy(
|
||||||
&mut File::open(
|
&mut File::open(
|
||||||
Path::new("target/x86_64-ableos")
|
Path::new(kernel_dir)
|
||||||
.join(if release { "release" } else { "debug" })
|
.join(if release { "release" } else { "debug" })
|
||||||
.join("kernel"),
|
.join("kernel"),
|
||||||
)?,
|
)?,
|
||||||
&mut fs.root_dir().create_file("kernel")?,
|
&mut fs.root_dir().create_file(&path)?,
|
||||||
)
|
)
|
||||||
.map(|_| ())
|
.map(|_| ())
|
||||||
})()
|
})()
|
||||||
.into_report()
|
.map_err(Report::from)
|
||||||
.change_context(Error::Io)
|
.change_context(Error::Io)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -148,28 +221,23 @@ fn run(release: bool, target: Target) -> Result<(), Error> {
|
||||||
let mut com = match target {
|
let mut com = match target {
|
||||||
Target::X86_64 => Command::new("qemu-system-x86_64"),
|
Target::X86_64 => Command::new("qemu-system-x86_64"),
|
||||||
Target::Riscv64Virt => Command::new("qemu-system-riscv64"),
|
Target::Riscv64Virt => Command::new("qemu-system-riscv64"),
|
||||||
|
Target::Aarch64 => Command::new("qemu-system-aarch64"),
|
||||||
};
|
};
|
||||||
|
let ovmf_path = fetch_ovmf(target);
|
||||||
|
|
||||||
if target == Target::X86_64 {
|
match target {
|
||||||
|
Target::X86_64 => {
|
||||||
#[rustfmt::skip]
|
#[rustfmt::skip]
|
||||||
com.args([
|
com.args([
|
||||||
"-bios",
|
"-bios", &ovmf_path.change_context(Error::OvmfFetch)?,
|
||||||
std::env::var("REPBUILD_QEMU_FIRMWARE_PATH")
|
|
||||||
.as_deref()
|
|
||||||
.unwrap_or("/usr/share/OVMF/OVMF_CODE.fd"),
|
|
||||||
"-drive", "file=target/disk.img,format=raw",
|
"-drive", "file=target/disk.img,format=raw",
|
||||||
"-m", "4G",
|
"-m", "4G",
|
||||||
"-serial", "stdio",
|
"-smp", "cores=4",
|
||||||
"-smp", "cores=2",
|
// "-enable-kvm",
|
||||||
|
"-cpu", "Broadwell-v4"
|
||||||
]);
|
]);
|
||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
|
||||||
{
|
|
||||||
com.args(["-enable-kvm", "-cpu", "host"]);
|
|
||||||
}
|
}
|
||||||
}
|
Target::Riscv64Virt => {
|
||||||
|
|
||||||
if target == Target::Riscv64Virt {
|
|
||||||
#[rustfmt::skip]
|
#[rustfmt::skip]
|
||||||
com.args([
|
com.args([
|
||||||
"-M", "virt",
|
"-M", "virt",
|
||||||
|
@ -183,10 +251,24 @@ fn run(release: bool, target: Target) -> Result<(), Error> {
|
||||||
}
|
}
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
Target::Aarch64 => {
|
||||||
|
#[rustfmt::skip]
|
||||||
|
com.args([
|
||||||
|
"-M", "virt",
|
||||||
|
"-cpu", "cortex-a72",
|
||||||
|
"-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
|
match com
|
||||||
.status()
|
.status()
|
||||||
.into_report()
|
.map_err(Report::from)
|
||||||
.change_context(Error::ProcessSpawn)?
|
.change_context(Error::ProcessSpawn)?
|
||||||
{
|
{
|
||||||
s if s.success() => Ok(()),
|
s if s.success() => Ok(()),
|
||||||
|
@ -194,33 +276,92 @@ fn run(release: bool, target: Target) -> Result<(), Error> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn fetch_ovmf(target: Target) -> Result<String, OvmfFetchError> {
|
||||||
|
let (ovmf_url, ovmf_path) = match target {
|
||||||
|
Target::X86_64 => (
|
||||||
|
"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 mut bytes = reqwest::blocking::get(ovmf_url)
|
||||||
|
.map_err(Report::from)
|
||||||
|
.change_context(OvmfFetchError::Fetch)?;
|
||||||
|
|
||||||
|
bytes
|
||||||
|
.copy_to(&mut file)
|
||||||
|
.map_err(Report::from)
|
||||||
|
.change_context(OvmfFetchError::Io)?;
|
||||||
|
|
||||||
|
Ok(ovmf_path.to_owned())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Display)]
|
||||||
|
enum OvmfFetchError {
|
||||||
|
#[display(fmt = "Failed to fetch OVMF package")]
|
||||||
|
Fetch,
|
||||||
|
#[display(fmt = "No OVMF package available")]
|
||||||
|
Empty,
|
||||||
|
#[display(fmt = "IO Error")]
|
||||||
|
Io,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Context for OvmfFetchError {}
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||||
enum Target {
|
enum Target {
|
||||||
X86_64,
|
X86_64,
|
||||||
Riscv64Virt,
|
Riscv64Virt,
|
||||||
|
Aarch64,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Display)]
|
||||||
enum Error {
|
enum Error {
|
||||||
|
#[display(fmt = "Failed to build the kernel")]
|
||||||
Build,
|
Build,
|
||||||
|
#[display(fmt = "Missing or invalid subcommand (available: build, run)")]
|
||||||
InvalidSubCom,
|
InvalidSubCom,
|
||||||
|
#[display(fmt = "IO Error")]
|
||||||
Io,
|
Io,
|
||||||
|
#[display(fmt = "Failed to spawn a process")]
|
||||||
ProcessSpawn,
|
ProcessSpawn,
|
||||||
|
#[display(fmt = "Failed to fetch UEFI firmware")]
|
||||||
|
OvmfFetch,
|
||||||
|
#[display(fmt = "Failed to assemble Holey Bytes code")]
|
||||||
|
Assembler,
|
||||||
|
#[display(fmt = "QEMU Error: {}", "fmt_qemu_err(*_0)")]
|
||||||
Qemu(Option<i32>),
|
Qemu(Option<i32>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Context for Error {}
|
impl Context for Error {}
|
||||||
impl Display for Error {
|
|
||||||
|
fn fmt_qemu_err(e: Option<i32>) -> impl Display {
|
||||||
|
struct W(Option<i32>);
|
||||||
|
impl Display for W {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
match self {
|
if let Some(c) = self.0 {
|
||||||
Self::Build => f.write_str("failed to build the kernel"),
|
c.fmt(f)
|
||||||
Self::InvalidSubCom => {
|
} else {
|
||||||
f.write_str("missing or invalid subcommand (available: build, run)")
|
f.write_str("Interrupted by signal")
|
||||||
}
|
|
||||||
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)
|
||||||
|
}
|
||||||
|
|
3
rustfmt.toml
Normal file
3
rustfmt.toml
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
hex_literal_case = "Upper"
|
||||||
|
imports_granularity = "One"
|
||||||
|
struct_field_align_threshold = 5
|
41
shell.nix
Normal file
41
shell.nix
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
{ 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/"
|
||||||
|
];
|
||||||
|
|
||||||
|
}
|
Before Width: | Height: | Size: 1.8 MiB After Width: | Height: | Size: 1.8 MiB |
40
sysdata/limine.cfg
Normal file
40
sysdata/limine.cfg
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
${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}_${ARCH}
|
||||||
|
# execute is an array of boot modules to execute
|
||||||
|
KERNEL_CMDLINE=""
|
||||||
|
# Setting a default resolution for the framebuffer
|
||||||
|
RESOLUTION=1024x768x24
|
||||||
|
|
||||||
|
MODULE_PATH=boot:///failure.hbf
|
||||||
|
MODULE_CMDLINE=""
|
||||||
|
|
||||||
|
MODULE_PATH=boot:///ecall.hbf
|
||||||
|
MODULE_CMDLINE=""
|
||||||
|
|
||||||
|
MODULE_PATH=boot:///main.hbf
|
||||||
|
MODULE_CMDLINE=""
|
||||||
|
|
||||||
|
MODULE_PATH=boot:///keyboard_driver.hbf
|
||||||
|
MODULE_CMDLINE=""
|
||||||
|
|
||||||
|
MODULE_PATH=boot:///vfs_test.hbf
|
||||||
|
MODULE_CMDLINE=""
|
||||||
|
|
||||||
|
MODULE_PATH=boot:///limine_framebuffer_driver.hbf
|
||||||
|
MODULE_CMDLINE="height=10 width=10 arch=${ARCH}"
|
||||||
|
|
||||||
|
MODULE_PATH=boot:///serial_driver.hbf
|
||||||
|
MODULE_CMDLINE="arch=${ARCH}"
|
3
sysdata/test-programs/ecall.rhai
Normal file
3
sysdata/test-programs/ecall.rhai
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
li64 (r1, 2);
|
||||||
|
eca ();
|
||||||
|
tx ();
|
1
sysdata/test-programs/failure.rhai
Normal file
1
sysdata/test-programs/failure.rhai
Normal file
|
@ -0,0 +1 @@
|
||||||
|
un();
|
1
sysdata/test-programs/hblib/README.md
Normal file
1
sysdata/test-programs/hblib/README.md
Normal file
|
@ -0,0 +1 @@
|
||||||
|
A kind of standard library.
|
55
sysdata/test-programs/hblib/std.rhai
Normal file
55
sysdata/test-programs/hblib/std.rhai
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
fn ipc_send(buffer_id, mem_addr, length){
|
||||||
|
// set the ecall
|
||||||
|
li64(r1, 3);
|
||||||
|
// Set the buffer ID to be the BufferID
|
||||||
|
li64(r2, buffer_id);
|
||||||
|
lra(r3, r0, mem_addr);
|
||||||
|
// set the length
|
||||||
|
li64(r4, length);
|
||||||
|
// ecall
|
||||||
|
eca();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn ipc_recv(buffer_id){
|
||||||
|
li64(r1, 4);
|
||||||
|
eca();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn ipc_make_bound_buffer(length) {
|
||||||
|
li64(r1, 1);
|
||||||
|
li64(r2, 1);
|
||||||
|
li64(r3, length);
|
||||||
|
eca();
|
||||||
|
|
||||||
|
// The ipc buffer id is in r1
|
||||||
|
}
|
||||||
|
|
||||||
|
private fn log(log_level, string){
|
||||||
|
// This is NOT the final format
|
||||||
|
let str = data::str(string + log_level);
|
||||||
|
|
||||||
|
// 1 byte for the log level
|
||||||
|
// 8 bytes for the length to the message
|
||||||
|
// 8 bytes for the pointer to the string
|
||||||
|
|
||||||
|
ipc_send(1, str, str.len);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn Error(string) {log(0, string);}
|
||||||
|
fn Warn(string) {log(1, string);}
|
||||||
|
fn Info(string) {log(2, string);}
|
||||||
|
// Due to rhai limitations this cannot be debug
|
||||||
|
// because of this all of the log levels are upper case
|
||||||
|
fn Debug(string) {log(3, string);}
|
||||||
|
fn Trace(string) {log(4, string);}
|
||||||
|
|
||||||
|
|
||||||
|
fn open(string_path){
|
||||||
|
let file_path = data::str(string_path);
|
||||||
|
ipc_send(2, file_path, file_path.len);
|
||||||
|
}
|
||||||
|
fn write(){}
|
||||||
|
fn read(){}
|
||||||
|
fn close(){}
|
199
sysdata/test-programs/keyboard_driver.rhai
Normal file
199
sysdata/test-programs/keyboard_driver.rhai
Normal file
|
@ -0,0 +1,199 @@
|
||||||
|
import "sysdata/test-programs/hblib/std" as std;
|
||||||
|
|
||||||
|
fn print_register(reg){
|
||||||
|
std::Debug("-----------------");
|
||||||
|
let c0 = declabel();
|
||||||
|
let c1 = declabel();
|
||||||
|
let c2 = declabel();
|
||||||
|
let c3 = declabel();
|
||||||
|
let c4 = declabel();
|
||||||
|
let c5 = declabel();
|
||||||
|
let c6 = declabel();
|
||||||
|
let c7 = declabel();
|
||||||
|
let c8 = declabel();
|
||||||
|
let c9 = declabel();
|
||||||
|
let ca = declabel();
|
||||||
|
let cb = declabel();
|
||||||
|
let cc = declabel();
|
||||||
|
let cd = declabel();
|
||||||
|
let ce = declabel();
|
||||||
|
let cf = declabel();
|
||||||
|
let end = declabel();
|
||||||
|
|
||||||
|
cp(r32, reg);
|
||||||
|
li64(r35, 16);
|
||||||
|
|
||||||
|
let next_loop = label();
|
||||||
|
|
||||||
|
addi64(r35, r35, -1);
|
||||||
|
li64(r37, 4);
|
||||||
|
mul64(r36, r35, r37);
|
||||||
|
sru64(r34, r32, r36);
|
||||||
|
|
||||||
|
andi(r34, r34, 0xf);
|
||||||
|
li64(r33, 0);
|
||||||
|
|
||||||
|
jeq(r34, r33, c0);
|
||||||
|
addi64(r33, r33, 1);
|
||||||
|
jeq(r34, r33, c1);
|
||||||
|
addi64(r33, r33, 1);
|
||||||
|
jeq(r34, r33, c2);
|
||||||
|
addi64(r33, r33, 1);
|
||||||
|
jeq(r34, r33, c3);
|
||||||
|
addi64(r33, r33, 1);
|
||||||
|
jeq(r34, r33, c4);
|
||||||
|
addi64(r33, r33, 1);
|
||||||
|
jeq(r34, r33, c5);
|
||||||
|
addi64(r33, r33, 1);
|
||||||
|
jeq(r34, r33, c6);
|
||||||
|
addi64(r33, r33, 1);
|
||||||
|
jeq(r34, r33, c7);
|
||||||
|
addi64(r33, r33, 1);
|
||||||
|
jeq(r34, r33, c8);
|
||||||
|
addi64(r33, r33, 1);
|
||||||
|
jeq(r34, r33, c9);
|
||||||
|
addi64(r33, r33, 1);
|
||||||
|
jeq(r34, r33, ca);
|
||||||
|
addi64(r33, r33, 1);
|
||||||
|
jeq(r34, r33, cb);
|
||||||
|
addi64(r33, r33, 1);
|
||||||
|
jeq(r34, r33, cc);
|
||||||
|
addi64(r33, r33, 1);
|
||||||
|
jeq(r34, r33, cd);
|
||||||
|
addi64(r33, r33, 1);
|
||||||
|
jeq(r34, r33, ce);
|
||||||
|
addi64(r33, r33, 1);
|
||||||
|
jeq(r34, r33, cf);
|
||||||
|
|
||||||
|
std::Error("This should be an invalid state");
|
||||||
|
|
||||||
|
let next = label();
|
||||||
|
jne(r0, r35, next_loop);
|
||||||
|
jeq(r0, r0, end);
|
||||||
|
|
||||||
|
here(c0);
|
||||||
|
std::Debug("0");
|
||||||
|
jeq(r0, r0, next);
|
||||||
|
here(c1);
|
||||||
|
std::Debug("1");
|
||||||
|
jeq(r0, r0, next);
|
||||||
|
here(c2);
|
||||||
|
std::Debug("2");
|
||||||
|
jeq(r0, r0, next);
|
||||||
|
here(c3);
|
||||||
|
std::Debug("3");
|
||||||
|
jeq(r0, r0, next);
|
||||||
|
here(c4);
|
||||||
|
std::Debug("4");
|
||||||
|
jeq(r0, r0, next);
|
||||||
|
here(c5);
|
||||||
|
std::Debug("5");
|
||||||
|
jeq(r0, r0, next);
|
||||||
|
here(c6);
|
||||||
|
std::Debug("6");
|
||||||
|
jeq(r0, r0, next);
|
||||||
|
here(c7);
|
||||||
|
std::Debug("7");
|
||||||
|
jeq(r0, r0, next);
|
||||||
|
here(c8);
|
||||||
|
std::Debug("8");
|
||||||
|
jeq(r0, r0, next);
|
||||||
|
here(c9);
|
||||||
|
std::Debug("9");
|
||||||
|
jeq(r0, r0, next);
|
||||||
|
here(ca);
|
||||||
|
std::Debug("A");
|
||||||
|
jeq(r0, r0, next);
|
||||||
|
here(cb);
|
||||||
|
std::Debug("B");
|
||||||
|
jeq(r0, r0, next);
|
||||||
|
here(cc);
|
||||||
|
std::Debug("C");
|
||||||
|
jeq(r0, r0, next);
|
||||||
|
here(cd);
|
||||||
|
std::Debug("D");
|
||||||
|
jeq(r0, r0, next);
|
||||||
|
here(ce);
|
||||||
|
std::Debug("E");
|
||||||
|
jeq(r0, r0, next);
|
||||||
|
here(cf);
|
||||||
|
std::Debug("F");
|
||||||
|
jeq(r0, r0, next);
|
||||||
|
|
||||||
|
here(end);
|
||||||
|
std::Debug("-----------------");
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_keyboard_status(){
|
||||||
|
li64(r1, 5);
|
||||||
|
li64(r2, 0x64);
|
||||||
|
eca();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_keyboard_input(){
|
||||||
|
li64(r1, 5);
|
||||||
|
li64(r2, 0x60);
|
||||||
|
eca();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_keyup(rb, ra){
|
||||||
|
li64(rb, 15);
|
||||||
|
sru64(rb, ra, rb);
|
||||||
|
andi(rb, rb, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn dump_registers(){
|
||||||
|
li64(r1, 0xff);
|
||||||
|
eca();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_ascii(rb, ra){
|
||||||
|
let str = data::str(
|
||||||
|
" 1234567890-= " +
|
||||||
|
"qwertyuiop[] " +
|
||||||
|
"asdfghjkl;'` \\" +
|
||||||
|
"zxcvbnm,./ " +
|
||||||
|
"* " +
|
||||||
|
"789-456+1230. "
|
||||||
|
);
|
||||||
|
andi(r33, ra, 0x00ff);
|
||||||
|
lra(rb, r0, str);
|
||||||
|
add64(rb, rb, r33);
|
||||||
|
ld(rb, rb, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn display_key(ra){
|
||||||
|
andi(r33, ra, 0x00ff);
|
||||||
|
ori(r33, r33, 0x0200);
|
||||||
|
let location = 0x20000;
|
||||||
|
li64(r32, location);
|
||||||
|
st(r33, r32, 0, 2);
|
||||||
|
|
||||||
|
li64(r1, 3);
|
||||||
|
li64(r2, 1);
|
||||||
|
li64(r3, location);
|
||||||
|
li64(r4, 2);
|
||||||
|
eca();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main(){
|
||||||
|
let key_up = declabel();
|
||||||
|
let main_loop = label();
|
||||||
|
get_keyboard_status();
|
||||||
|
andi(r12, r3, 1);
|
||||||
|
li64(r13, 0x1);
|
||||||
|
jne(r13, r12, main_loop);
|
||||||
|
get_keyboard_input();
|
||||||
|
cp(r12, r3);
|
||||||
|
is_keyup(r14, r12);
|
||||||
|
jne(r0, r14, key_up);
|
||||||
|
to_ascii(r15, r12);
|
||||||
|
display_key(r15);
|
||||||
|
jeq(r0, r0, main_loop);
|
||||||
|
here(key_up);
|
||||||
|
jeq(r0, r0, main_loop);
|
||||||
|
|
||||||
|
tx();
|
||||||
|
}
|
||||||
|
|
||||||
|
main();
|
163
sysdata/test-programs/limine_framebuffer_driver.rhai
Normal file
163
sysdata/test-programs/limine_framebuffer_driver.rhai
Normal file
|
@ -0,0 +1,163 @@
|
||||||
|
// Change and add to this as you see fit.
|
||||||
|
// The STD and even syscalls are still in flux.
|
||||||
|
// Do your best to avoid adding bad design.
|
||||||
|
// Use std abstractions if they exist like logging functionality
|
||||||
|
import "sysdata/test-programs/hblib/std" as std;
|
||||||
|
|
||||||
|
|
||||||
|
fn rect(reg_x, reg_y, w, h, color) {
|
||||||
|
li64(r3, 0);
|
||||||
|
li64(r4, 0);
|
||||||
|
li64(r5, w);
|
||||||
|
li64(r6, h);
|
||||||
|
|
||||||
|
let start_y = label();
|
||||||
|
|
||||||
|
let start_x = label();
|
||||||
|
|
||||||
|
add64(r9, r3, reg_x);
|
||||||
|
add64(r10, r4, reg_y);
|
||||||
|
pixel(r9, r10, color);
|
||||||
|
|
||||||
|
li64(r1, 1);
|
||||||
|
add64(r3, r3, r1);
|
||||||
|
|
||||||
|
jltu(r3, r5, start_x);
|
||||||
|
|
||||||
|
li64(r1, 1);
|
||||||
|
add64(r4, r4, r1);
|
||||||
|
|
||||||
|
li64(r3, 0);
|
||||||
|
|
||||||
|
jltu(r4, r6, start_y);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pixel(reg_x, reg_y, color) {
|
||||||
|
let BUFFER = 0xFFFF8000C0000000;
|
||||||
|
let WIDTH = 1024;
|
||||||
|
|
||||||
|
// r1 = y * WIDTH
|
||||||
|
li64(r1, WIDTH);
|
||||||
|
mul64(r1, reg_y, r1);
|
||||||
|
|
||||||
|
// r2 = x + r2
|
||||||
|
add64(r2, reg_x, r1);
|
||||||
|
|
||||||
|
// r2 = r2 * 4
|
||||||
|
li64(r1, 4);
|
||||||
|
mul64(r2, r2, r1);
|
||||||
|
|
||||||
|
// store pixel value
|
||||||
|
li64(r1, color);
|
||||||
|
st(r1, r2, BUFFER, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clear() {
|
||||||
|
// rect(r0, r0, 1024, 768, 0xff222222);
|
||||||
|
|
||||||
|
let BUFFER = 0xFFFF8000C0000000;
|
||||||
|
// on arm the FB is at 0xFFFF8000BC430000
|
||||||
|
// FIXME: get the framebuffer pointer from the starting arguments
|
||||||
|
|
||||||
|
li64(r1, 0xff222222);
|
||||||
|
li64(r2, 0);
|
||||||
|
li64(r3, 1);
|
||||||
|
li64(r4, 1024 * 768);
|
||||||
|
li64(r5, 4);
|
||||||
|
let start = label();
|
||||||
|
mul64(r6, r2, r5);
|
||||||
|
st(r1, r6, BUFFER, 4);
|
||||||
|
add64(r2, r2, r3);
|
||||||
|
jltu(r2, r4, start);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Define main
|
||||||
|
fn main(){
|
||||||
|
// Log the arguments
|
||||||
|
{
|
||||||
|
cp(r3, r1);
|
||||||
|
cp(r4, r2);
|
||||||
|
|
||||||
|
// log level
|
||||||
|
li8(r6, 2);
|
||||||
|
|
||||||
|
add64(r5, r3, r4);
|
||||||
|
li64(r7, 1);
|
||||||
|
st(r6, r5, 0, 1);
|
||||||
|
add64(r4, r4, r7);
|
||||||
|
|
||||||
|
li64(r1, 3);
|
||||||
|
li64(r2, 1);
|
||||||
|
|
||||||
|
eca();
|
||||||
|
// Zero out all used registers
|
||||||
|
li64(r1, 0);
|
||||||
|
li64(r2, 0);
|
||||||
|
li64(r3, 0);
|
||||||
|
li64(r4, 0);
|
||||||
|
li64(r5, 0);
|
||||||
|
li64(r6, 0);
|
||||||
|
li64(r7, 0);
|
||||||
|
}
|
||||||
|
std::Info("Starting the limine framebuffer driver.");
|
||||||
|
// un();
|
||||||
|
li64(r100, 300);
|
||||||
|
li64(r101, 300);
|
||||||
|
li64(r102, 1);
|
||||||
|
li64(r103, 1);
|
||||||
|
li64(r104, 1024 - 20);
|
||||||
|
li64(r105, 768 - 20);
|
||||||
|
li64(r106, 0);
|
||||||
|
li64(r107, 0);
|
||||||
|
|
||||||
|
clear();
|
||||||
|
|
||||||
|
let start = label();
|
||||||
|
|
||||||
|
rect(r100, r101, 20, 20, 0xff222222);
|
||||||
|
//clear();
|
||||||
|
|
||||||
|
add64(r100, r100, r102);
|
||||||
|
add64(r101, r101, r103);
|
||||||
|
|
||||||
|
let after_x_right = declabel();
|
||||||
|
jltu(r100, r104, after_x_right);
|
||||||
|
li64(r102, -1);
|
||||||
|
here(after_x_right);
|
||||||
|
|
||||||
|
let after_x_left = declabel();
|
||||||
|
jgtu(r100, r106, after_x_left);
|
||||||
|
li64(r102, 1);
|
||||||
|
li64(r100, 0);
|
||||||
|
here(after_x_left);
|
||||||
|
|
||||||
|
let after_y_right = declabel();
|
||||||
|
jltu(r101, r105, after_y_right);
|
||||||
|
li64(r103, -1);
|
||||||
|
here(after_y_right);
|
||||||
|
|
||||||
|
let after_y_left = declabel();
|
||||||
|
jgtu(r101, r107, after_y_left);
|
||||||
|
li64(r103, 1);
|
||||||
|
li64(r101, 0);
|
||||||
|
here(after_y_left);
|
||||||
|
|
||||||
|
rect(r100, r101, 20, 20, 0xffffffff);
|
||||||
|
|
||||||
|
li64(r200, 0);
|
||||||
|
li64(r201, 1);
|
||||||
|
li64(r202, 10000);
|
||||||
|
let wait = label();
|
||||||
|
add64(r200, r200, r201);
|
||||||
|
jltu(r200, r202, wait);
|
||||||
|
|
||||||
|
jeq(r0, r0, start);
|
||||||
|
//jmp(start);
|
||||||
|
|
||||||
|
std::Info("done");
|
||||||
|
|
||||||
|
// Terminate execution.
|
||||||
|
tx();
|
||||||
|
}
|
||||||
|
|
||||||
|
main();
|
15
sysdata/test-programs/main.rhai
Normal file
15
sysdata/test-programs/main.rhai
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
import "sysdata/test-programs/hblib/std" as std;
|
||||||
|
|
||||||
|
fn main(){
|
||||||
|
std::Error(":+)");
|
||||||
|
std::Warn("Your mom fell in a well!");
|
||||||
|
std::Info("Hello, world!");
|
||||||
|
std::Debug("XYZ");
|
||||||
|
std::Trace("Trace Deez");
|
||||||
|
|
||||||
|
std::ipc_send(2, 0, 0);
|
||||||
|
|
||||||
|
tx();
|
||||||
|
}
|
||||||
|
|
||||||
|
main();
|
27
sysdata/test-programs/serial_driver.rhai
Normal file
27
sysdata/test-programs/serial_driver.rhai
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
import "sysdata/test-programs/hblib/std" as std;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
fn main(){
|
||||||
|
let ADDR = 0;
|
||||||
|
// FIXME: Actually check the arch argument
|
||||||
|
let architecture = "ARM";
|
||||||
|
if architecture == "ARM" {
|
||||||
|
std::Info("Arm Serial Driver");
|
||||||
|
ADDR = 0x09000000;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
lra(r3, r0, ADDR);
|
||||||
|
|
||||||
|
li64(r1, 0);
|
||||||
|
li8(r1, 65);
|
||||||
|
st(r1, r0, ADDR, 1);
|
||||||
|
|
||||||
|
// New Line
|
||||||
|
li8(r1, 12);st(r1, r0, ADDR, 1);
|
||||||
|
|
||||||
|
tx();
|
||||||
|
}
|
||||||
|
|
||||||
|
main();
|
11
sysdata/test-programs/vfs.rhai
Normal file
11
sysdata/test-programs/vfs.rhai
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
/// Act as a shim of a virtual file system that recieves one message from buffer 2
|
||||||
|
import "sysdata/test-programs/hblib/std" as std;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
std::ipc_recv(2);
|
||||||
|
un();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
main();
|
||||||
|
tx();
|
15
sysdata/test-programs/vfs_test.rhai
Normal file
15
sysdata/test-programs/vfs_test.rhai
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
import "sysdata/test-programs/hblib/std" as std;
|
||||||
|
|
||||||
|
fn main(){
|
||||||
|
std::Info("Trying to open a file.");
|
||||||
|
std::open("/file.hbf");
|
||||||
|
std::write();
|
||||||
|
std::read();
|
||||||
|
std::close();
|
||||||
|
|
||||||
|
std::Info("VFS Test done!");
|
||||||
|
// un();
|
||||||
|
tx();
|
||||||
|
}
|
||||||
|
|
||||||
|
main();
|
Loading…
Reference in a new issue