Compare commits

..

1 Commits

Author SHA1 Message Date
Christian Westrom 7d85d70c7f
rename syscall file 2023-04-30 13:57:26 +09:00
94 changed files with 18650 additions and 6466 deletions

View File

@ -1,5 +1,4 @@
{
"rust-analyzer.checkOnSave.allTargets": false,
"rust-analyzer.showUnlinkedFileNotification": false,
"C_Cpp.errorSquiggles": "disabled"
"rust-analyzer.showUnlinkedFileNotification": false
}

1465
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -1,3 +1,5 @@
[workspace]
resolver = "2"
[workspace]
members = ["kernel", "repbuild"]

View File

@ -1,18 +1,7 @@
# AbleOS
An UNIX-unlike micro-kernel written in rust with an embedded bytecode virtual machine.
# Community
[Discord](https://discord.gg/JrKVukDtgs)
Donations can be made [here on Liberapay](https://liberapay.com/AbleTheAbove) or on [Patreon](https://www.patreon.com/ablecorp)
<img src="https://img.shields.io/liberapay/patrons/AbleTheAbove.svg?logo=liberapay">
TODO:
Support cache drives
# Compiling
AbleOS should be able to be built on any platform which is supported by
[Rustc Tier 1 platform support](https://doc.rust-lang.org/nightly/rustc/platform-support.html#tier-1-with-host-tools).
For running AbleOS, `repbuild` uses QEMU.
## Steps
1. `git submodule update --init`
2. `cargo repbuild`
1. `git submodule --update init`
1. Add [this binary](https://git.ablecorp.us/AbleOS/ableos/src/commit/e6c8d184d42961cf3cfa2e4aa319fc86c8880585/test.wasm) to the root.
1. `cargo repbuild`

View File

@ -1,79 +0,0 @@
digraph Drivers {
InitSystem -> VFS;
InitSystem -> Logger;
TCP -> NetworkingStack;
UDP -> NetworkingStack;
NetworkingStack -> PhysLayer;
PhysLayer -> Ethernet;
Ethernet -> Threec90x;
Ethernet -> Intel8254x;
Ethernet -> Ne2000;
Ethernet -> RTL8139;
Ethernet -> RTL8169;
Ethernet -> IntelEtherneti217;
Ethernet -> AMDPCnet;
PhysLayer -> Wifi;
Wifi -> Eight02Dot11;
Audio -> PCSpeaker;
Audio -> SoundBlaster16;
RNG -> CpuRNG;
RNG -> NetworkingStack;
RNG -> GraphicsLibrary;
RNG -> Input;
Slint -> GraphicsLibrary;
GraphicsLibrary -> ShaderCompiler;
ShaderCompiler -> GraphicsDriver;
GraphicsLibrary -> GraphicsDriver;
// Todo: dreak out the GPU into specific drivers
GraphicsDriver -> GPU;
Logger -> Serial;
Logger -> VFS;
Input -> Keyboard;
Input -> GraphicsTablet;
Input -> Mouse;
Input -> Serial;
Input -> Controllers;
Controllers -> Playstation;
Playstation -> DualShock;
Playstation -> DualSense;
DualShock -> DualShock1;
DualShock -> DualShock2;
DualShock -> DualShock3;
DualShock -> DualShock4;
Mouse -> PS2Mouse;
Mouse -> USBMouse;
USBMouse -> GenericUSBMouse;
Mouse -> MouseTrackPad;
Mouse -> MouseTrackPoint;
VFS -> Fat32;
VFS -> TarFS;
VFS -> Ext2;
Ext2 -> VirtualDisk;
TarFS -> VirtualDisk;
Fat32 -> VirtualDisk;
VirtualDisk -> IDEDiskDriver;
VirtualDisk -> ATADiskDriver;
VirtualDisk -> FloppyController;
VirtualDisk -> CDROM;
VirtualDisk -> NVME;
BlueToothStack;
}

View File

@ -1,677 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<!-- Generated by graphviz version 2.40.1 (20161225.0304)
-->
<!-- Title: Drivers Pages: 1 -->
<svg width="2629pt" height="404pt" viewBox="0.00 0.00 2628.89 404.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 400)">
<title>Drivers</title>
<polygon fill="#ffffff" stroke="transparent" points="-4,4 -4,-400 2624.8933,-400 2624.8933,4 -4,4"/>
<!-- InitSystem -->
<g id="node1" class="node">
<title>InitSystem</title>
<ellipse fill="none" stroke="#000000" cx="443.0953" cy="-378" rx="52.7642" ry="18"/>
<text text-anchor="middle" x="443.0953" y="-373.8" font-family="Times,serif" font-size="14.00" fill="#000000">InitSystem</text>
</g>
<!-- VFS -->
<g id="node2" class="node">
<title>VFS</title>
<ellipse fill="none" stroke="#000000" cx="409.0953" cy="-234" rx="28.991" ry="18"/>
<text text-anchor="middle" x="409.0953" y="-229.8" font-family="Times,serif" font-size="14.00" fill="#000000">VFS</text>
</g>
<!-- InitSystem&#45;&gt;VFS -->
<g id="edge1" class="edge">
<title>InitSystem-&gt;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&#45;&gt;Logger -->
<g id="edge2" class="edge">
<title>InitSystem-&gt;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&#45;&gt;Fat32 -->
<g id="edge46" class="edge">
<title>VFS-&gt;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&#45;&gt;TarFS -->
<g id="edge47" class="edge">
<title>VFS-&gt;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&#45;&gt;Ext2 -->
<g id="edge48" class="edge">
<title>VFS-&gt;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&#45;&gt;VFS -->
<g id="edge28" class="edge">
<title>Logger-&gt;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&#45;&gt;Serial -->
<g id="edge27" class="edge">
<title>Logger-&gt;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&#45;&gt;NetworkingStack -->
<g id="edge3" class="edge">
<title>TCP-&gt;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&#45;&gt;PhysLayer -->
<g id="edge5" class="edge">
<title>NetworkingStack-&gt;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&#45;&gt;NetworkingStack -->
<g id="edge4" class="edge">
<title>UDP-&gt;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&#45;&gt;Ethernet -->
<g id="edge6" class="edge">
<title>PhysLayer-&gt;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&#45;&gt;Wifi -->
<g id="edge14" class="edge">
<title>PhysLayer-&gt;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&#45;&gt;Threec90x -->
<g id="edge7" class="edge">
<title>Ethernet-&gt;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&#45;&gt;Intel8254x -->
<g id="edge8" class="edge">
<title>Ethernet-&gt;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&#45;&gt;Ne2000 -->
<g id="edge9" class="edge">
<title>Ethernet-&gt;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&#45;&gt;RTL8139 -->
<g id="edge10" class="edge">
<title>Ethernet-&gt;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&#45;&gt;RTL8169 -->
<g id="edge11" class="edge">
<title>Ethernet-&gt;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&#45;&gt;IntelEtherneti217 -->
<g id="edge12" class="edge">
<title>Ethernet-&gt;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&#45;&gt;AMDPCnet -->
<g id="edge13" class="edge">
<title>Ethernet-&gt;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&#45;&gt;Eight02Dot11 -->
<g id="edge15" class="edge">
<title>Wifi-&gt;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&#45;&gt;PCSpeaker -->
<g id="edge16" class="edge">
<title>Audio-&gt;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&#45;&gt;SoundBlaster16 -->
<g id="edge17" class="edge">
<title>Audio-&gt;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&#45;&gt;NetworkingStack -->
<g id="edge19" class="edge">
<title>RNG-&gt;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&#45;&gt;CpuRNG -->
<g id="edge18" class="edge">
<title>RNG-&gt;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&#45;&gt;GraphicsLibrary -->
<g id="edge20" class="edge">
<title>RNG-&gt;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&#45;&gt;Input -->
<g id="edge21" class="edge">
<title>RNG-&gt;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&#45;&gt;ShaderCompiler -->
<g id="edge23" class="edge">
<title>GraphicsLibrary-&gt;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&#45;&gt;GraphicsDriver -->
<g id="edge25" class="edge">
<title>GraphicsLibrary-&gt;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&#45;&gt;Serial -->
<g id="edge32" class="edge">
<title>Input-&gt;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&#45;&gt;Keyboard -->
<g id="edge29" class="edge">
<title>Input-&gt;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&#45;&gt;GraphicsTablet -->
<g id="edge30" class="edge">
<title>Input-&gt;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&#45;&gt;Mouse -->
<g id="edge31" class="edge">
<title>Input-&gt;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&#45;&gt;Controllers -->
<g id="edge33" class="edge">
<title>Input-&gt;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&#45;&gt;GraphicsLibrary -->
<g id="edge22" class="edge">
<title>Slint-&gt;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&#45;&gt;GraphicsDriver -->
<g id="edge24" class="edge">
<title>ShaderCompiler-&gt;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&#45;&gt;GPU -->
<g id="edge26" class="edge">
<title>GraphicsDriver-&gt;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&#45;&gt;PS2Mouse -->
<g id="edge41" class="edge">
<title>Mouse-&gt;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&#45;&gt;USBMouse -->
<g id="edge42" class="edge">
<title>Mouse-&gt;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&#45;&gt;MouseTrackPad -->
<g id="edge44" class="edge">
<title>Mouse-&gt;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&#45;&gt;MouseTrackPoint -->
<g id="edge45" class="edge">
<title>Mouse-&gt;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&#45;&gt;Playstation -->
<g id="edge34" class="edge">
<title>Controllers-&gt;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&#45;&gt;DualShock -->
<g id="edge35" class="edge">
<title>Playstation-&gt;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&#45;&gt;DualSense -->
<g id="edge36" class="edge">
<title>Playstation-&gt;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&#45;&gt;DualShock1 -->
<g id="edge37" class="edge">
<title>DualShock-&gt;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&#45;&gt;DualShock2 -->
<g id="edge38" class="edge">
<title>DualShock-&gt;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&#45;&gt;DualShock3 -->
<g id="edge39" class="edge">
<title>DualShock-&gt;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&#45;&gt;DualShock4 -->
<g id="edge40" class="edge">
<title>DualShock-&gt;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&#45;&gt;GenericUSBMouse -->
<g id="edge43" class="edge">
<title>USBMouse-&gt;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&#45;&gt;VirtualDisk -->
<g id="edge51" class="edge">
<title>Fat32-&gt;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&#45;&gt;VirtualDisk -->
<g id="edge50" class="edge">
<title>TarFS-&gt;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&#45;&gt;VirtualDisk -->
<g id="edge49" class="edge">
<title>Ext2-&gt;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&#45;&gt;IDEDiskDriver -->
<g id="edge52" class="edge">
<title>VirtualDisk-&gt;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&#45;&gt;ATADiskDriver -->
<g id="edge53" class="edge">
<title>VirtualDisk-&gt;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&#45;&gt;FloppyController -->
<g id="edge54" class="edge">
<title>VirtualDisk-&gt;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&#45;&gt;CDROM -->
<g id="edge55" class="edge">
<title>VirtualDisk-&gt;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&#45;&gt;NVME -->
<g id="edge56" class="edge">
<title>VirtualDisk-&gt;NVME</title>
<path fill="none" stroke="#000000" d="M325.0953,-71.8314C325.0953,-64.131 325.0953,-54.9743 325.0953,-46.4166"/>
<polygon fill="#000000" stroke="#000000" points="328.5954,-46.4132 325.0953,-36.4133 321.5954,-46.4133 328.5954,-46.4132"/>
</g>
<!-- BlueToothStack -->
<g id="node55" class="node">
<title>BlueToothStack</title>
<ellipse fill="none" stroke="#000000" cx="2547.0953" cy="-378" rx="73.5965" ry="18"/>
<text text-anchor="middle" x="2547.0953" y="-373.8" font-family="Times,serif" font-size="14.00" fill="#000000">BlueToothStack</text>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 36 KiB

View File

@ -1,4 +0,0 @@
# Commit style
`[SCOPE]: [COMMENT]`
SCOPE is what you changed
COMMENT is why you changed that

View File

@ -1,32 +0,0 @@
# TODO
- Build out the object system
- Build or Find an acceptable IDL
Short List of potentials
- [comline](https://git.ablecorp.us/DOOME1M8Cover/comline)
- Work on a styleguide for commits
Maybe something allong the lines of
[relevant shorthand note] Explination
- Language support on HBVM
- HBVM assembler (with IDL support)
- HBVM Lisp/s-expr Compiler (Also (with (IDL (support))))
- Documentation
- Drivers
- serial driver
- PS/2 mouse driver
- PS/2 Keyboard driver
- VGA driver
- SVGA driver
- File system
- Depends on Disk driver
- TarFS
Pass in a tar file as an initrd and parse it with TarFS
- VFS
Being (written)[https://git.ablecorp.us/bee/ableos-vfs] by Bee
- Disk driver
- IDE Driver
- ATA Driver
- Floppy Driver
- A ton more
- Port (Slint)[https://slint.dev]
- Depends on
- Graphics Driver

View File

@ -1,50 +0,0 @@
strict graph OS {
layout=dot;
ModelingSoftware -- GraphicsAPI;
ModelingSoftware -- HID;
ModelingSoftware -- VFS;
GameEngine3D -- GraphicsAPI;
GameEngine3D -- VFS;
GameEngine3D -- AudioSubsystem;
GameEngine3D -- HID;
GameEngine3D -- Networking;
Git -- VFS;
Git -- Networking;
ListFile -- VFS;
MakeFile -- VFS;
AudioSubsystem -- AbleOSInterface;
GraphicsAPI -- AbleOSInterface;
HID -- AbleOSInterface;
Networking -- AbleOSInterface;
FatFileSystemProc -- VFS;
NTFSFileSystemProc -- VFS;
EXT2 -- VFS;
FatFileSystemProc -- DriveSystemProc;
NTFSFileSystemProc -- DriveSystemProc;
EXT2 -- DriveSystemProc;
DriveSystemProc -- AbleOSInterface;
AbleOSInterface -- DriveSystemProc;
AbleOSInterface -- Kernel;
Kernel -- x86HAL;
Kernel -- riscvHAL;
Kernel -- aarch64HAL;
x86HAL -- GPU;
riscvHAL -- GPU;
aarch64HAL -- GPU;
x86HAL -- SoundCard;
riscvHAL -- SoundCard;
aarch64HAL -- SoundCard;
}

View File

@ -2,33 +2,25 @@
edition = "2021"
name = "kernel"
version = "0.2.0"
resolver = "2"
[dependencies]
embedded-graphics = "0.7"
hbvm.git = "https://git.ablecorp.us/ableos/holey-bytes"
log = "0.4"
spin = "0.9"
uart_16550 = "0.2"
slab = { version = "0.4", default-features = false }
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"
error-stack = { version = "0.3", default-features = false }
log = "0.4"
spin = "0.9"
uart_16550 = "0.2"
slab = { version = "0.4", default-features = false }
xml = { git = "https://git.ablecorp.us/ableos/ableos_userland" }
[dependencies.limine]
version = "0.1"
git = "https://github.com/limine-bootloader/limine-rs"
clparse = { git = "https://git.ablecorp.us/ableos/ableos_userland", default-features = false }
versioning = { git = "https://git.ablecorp.us/ableos/ableos_userland" }
wasmi = { version = "0.29.0", default-features = false }
hashbrown = "*"
[dependencies.crossbeam-queue]
version = "0.3"
default-features = false
features = ["alloc"]
[dependencies.clparse]
git = "https://git.ablecorp.us/ableos/ableos_userland"
version = "0.3"
default-features = false
features = ["alloc"]
[dependencies.derive_more]
version = "0.99"
@ -48,9 +40,9 @@ features = [
[target.'cfg(target_arch = "x86_64")'.dependencies]
limine = { version = "0.1", git = "https://github.com/limine-bootloader/limine-rs" }
x86_64 = "0.14"
x2apic = "0.4"
virtio-drivers = "0.4.0"
# rdrand = "*"
rdrand = { version = "0.8", default-features = false }

36
kernel/data/test.wat Normal file
View File

@ -0,0 +1,36 @@
(module
(data "mouse")
(data "x")
(data "y")
(func $rma (import "host" "read_mem_addr")(param i32)(result i32))
(func $co (import "host" "create_object")(param i32 i32)(result i64))
(func $roa (import "host" "read_object_attribute")(param i64 i32 i32)(result i32 i32))
(memory (export "memory") 1)
(func
(export "start")(result i64)
;; Copy into memory the object name
(memory.init 0
(i32.const 0) ;; target offset
(i32.const 0) ;; source offset
(i32.const 5))
(memory.init 1
(i32.const 6) ;; target offset
(i32.const 0) ;; source offset
(i32.const 1))
(memory.init 2
(i32.const 7) ;; target offset
(i32.const 0) ;; source offset
(i32.const 1))
i32.const 0
i32.const 5
call $co
;; i32.const 6
;; i32.const 1
;; call $roa
)
)

33
kernel/data/⑨. バカ Normal file
View File

@ -0,0 +1,33 @@
.//// *(####
(####((/, (########,
(##%##(###(( ,(#########%#
#%%%%###(###((. *((####%%&%%%%#
.#####%%%%%####((. *(####%&&&&&%%%%#
#(((((((##%%&&%#((/ /#(##%&&%##########
/######%%%%%%%(..........(#%%%%%%#####%%#
,#%%%%%%#/...... ..............,&&&%%###.
,%%#(#(...........................(#&&%%#
.###%...............................%%#(#.
#%&.................................%#
,%&&*.................................&&%(
%%#//........./............*/..,......&&&%#
.......,..............*,*.,,,,,,.
......./....,.........*,,,,.,,,,,,
,...../..(###%,.....&*&%###/..,.,,.
,,..../%(((#(,.....,%%%%###,..,..,.
.,,*.../..,#,.........,(&(,,**.,,,,,
,/((..,*..........,,.,,,,,**.,##((
/(((%%%,,,,,.,,,,,,,,,,,#/##(,(/
.***..(,.#%%%&&#/%,,(%*,,**#
**,...,(#%%%%&#%%%#%%%%,,.,,***.
.....,*,*#%%%%%###%##%%%&,,*,,....
......,*/. (############%%%&&&&#*,,....
...,*,..,(((((((((((#((((((((((((&&&#*,
,##///////(((((((((((((#///#///(##/.
/*/**//... ...**(((((((,. .,*......
....... ......,,/*,. ...........
,..,,,,...... .. .... ,,....... ..,,,
........,.,.,*//////*,......,.
...,,,, ,,,,,,

View File

@ -1,24 +0,0 @@
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 = .;
}

View File

@ -47,8 +47,7 @@ SECTIONS
/* Align initial kernel heap to page boundary */
. = ALIGN(4K);
PROVIDE(_initial_kernel_heap_start = .);
/* PROVIDE(_initial_kernel_heap_size = 1024 * 1024); */
PROVIDE(_initial_kernel_heap_size = 1024 * 4096 * 100);
PROVIDE(_initial_kernel_heap_size = 1024 * 1024);
. += _initial_kernel_heap_size;
} :data
}

View File

@ -27,16 +27,14 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
use {
core::{
alloc::{GlobalAlloc, Layout},
mem,
ptr::{self, NonNull},
},
log::trace,
spin::Mutex,
use core::{
alloc::{GlobalAlloc, Layout},
mem,
ptr::{self, NonNull},
};
use spin::Mutex;
struct Allocator(Mutex<Option<Heap>>);
unsafe impl GlobalAlloc for Allocator {
@ -62,7 +60,7 @@ static ALLOCATOR: Allocator = Allocator(Mutex::new(None));
// FIXME: umm is `memory` VirtualAddress or PhysicalAddress? both?
pub fn init(memory: *mut u8, memory_size: usize) {
trace!("Initialising kernel heap allocator");
log::info!("Initialising kernel heap allocator");
*ALLOCATOR.0.lock() = Some(unsafe { Heap::new(memory, memory_size) });
}
@ -146,30 +144,19 @@ impl Heap {
self.allocated_chunks += chunks_needed;
let ptr: *mut u8 = unsafe { mem::transmute(header.add(1)) };
{
#[cfg(debug_assertions)]
trace!("Allocating {:?}", ptr);
}
unsafe { core::ptr::write_bytes(ptr, 0, size) };
// FIXME: zero or scrub memory?
assert!(ptr.is_aligned_to(alignment));
NonNull::new(ptr)
}
fn deallocate(&mut self, ptr: *mut u8) {
{
#[cfg(debug_assertions)]
log::trace!("Deallocating {:?}", ptr);
}
let header = Self::allocation_header(ptr);
let start = (header as usize - self.chunks as usize) / CHUNK_SIZE;
assert!(self.bitmap_get(start));
let size = unsafe { (*header).size_in_chunks };
self.bitmap_set_range(start, size, false);
self.allocated_chunks -= size;
// FIXME: zero out memory to prevent leaking data
// REPLY: When we zero on alloc, do we really need it?
// FIXME: zero or scrub memory?
}
/// Finds first hole that can fit an allocation of `size` chunks, returns the start of the
@ -251,10 +238,7 @@ impl Heap {
return Some(start_of_free_chunks);
}
}
#[cfg(debug_assertions)]
{
trace!("No first fit found");
}
None
}
@ -324,7 +308,7 @@ impl Heap {
(unsafe { *self.bitmap.add(index / 8) } & (1 << (index % 8))) != 0
}
pub const fn free_chunks(&self) -> usize {
const fn free_chunks(&self) -> usize {
self.total_chunks - self.allocated_chunks
}
@ -341,11 +325,5 @@ unsafe impl Send for Heap {}
#[alloc_error_handler]
fn alloc_error_handler(layout: alloc::alloc::Layout) -> ! {
log::error!("allocation error: {:?}", layout);
// Todo: Maybe panic here instead
crate::arch::spin_loop()
}
pub fn get_free_chunks_count() -> usize {
ALLOCATOR.0.lock().as_ref().unwrap().free_chunks()
crate::arch::sloop()
}

View File

@ -1,49 +0,0 @@
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)
}

View File

@ -1,25 +0,0 @@
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(())
}

View File

@ -1,118 +1 @@
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() {}
//!

View File

@ -1,46 +1,37 @@
mod memory;
use {
alloc::boxed::Box,
core::{
arch::{asm, global_asm},
fmt::Write,
},
sbi::system_reset::{system_reset, ResetReason, ResetType},
spin::{Mutex, Once},
uart_16550::MmioSerialPort,
};
use core::{arch::{asm, global_asm}, fmt::Write};
use alloc::boxed::Box;
use sbi::system_reset::{ResetType, ResetReason, system_reset};
use spin::{Mutex, Once};
use uart_16550::MmioSerialPort;
use crate::{
allocator,
arch::riscv64::memory::{PageEntryFlags, PageSize, PageTable, PAGE_TABLE},
memory::PhysicalAddress,
};
use crate::{allocator, memory::PhysicalAddress, arch::riscv64::memory::{PAGE_TABLE, PageEntryFlags, PageSize, PageTable}};
global_asm!(include_str!("entry.s"));
global_asm!(include_str!("memory_regions.s"));
pub const PAGE_SIZE: usize = 4096;
extern "C" {
extern {
static TEXT_START: PhysicalAddress;
static TEXT_END: PhysicalAddress;
static RODATA_START: PhysicalAddress;
static RODATA_END: PhysicalAddress;
static DATA_START: PhysicalAddress;
static DATA_END: PhysicalAddress;
static SDATA_START: PhysicalAddress;
static SDATA_END: PhysicalAddress;
static BSS_START: PhysicalAddress;
static BSS_END: PhysicalAddress;
static INITIAL_KERNEL_HEAP_START: PhysicalAddress;
static INITIAL_KERNEL_HEAP_SIZE: usize;
static USABLE_MEMORY_START: PhysicalAddress;
static USABLE_MEMORY_SIZE: usize;
}
@ -48,15 +39,12 @@ extern "C" {
static SERIAL_CONSOLE: Once<Mutex<MmioSerialPort>> = Once::new();
#[no_mangle]
unsafe extern "C" fn _kernel_start() -> ! {
unsafe extern fn _kernel_start() -> ! {
SERIAL_CONSOLE.call_once(|| Mutex::new(unsafe { MmioSerialPort::new(0x1000_0000) }));
crate::logger::init().expect("failed to set logger");
log::info!("Initialising AKern {}", crate::VERSION);
allocator::init(
INITIAL_KERNEL_HEAP_START.as_mut_ptr::<u8>(),
INITIAL_KERNEL_HEAP_SIZE,
);
allocator::init(INITIAL_KERNEL_HEAP_START.as_mut_ptr::<u8>(), INITIAL_KERNEL_HEAP_SIZE);
memory::init(USABLE_MEMORY_START.into(), USABLE_MEMORY_SIZE / PAGE_SIZE);
let mut page_table_addr = PAGE_TABLE.get().unwrap().lock();
@ -73,17 +61,9 @@ unsafe extern "C" fn _kernel_start() -> ! {
// Map bss section (includes stack and initial kernel heap)
page_table.identity_map_range(BSS_START, BSS_END, PageEntryFlags::ReadWrite);
// Map usable memory range (as rw so not executable)
page_table.identity_map_range(
USABLE_MEMORY_START,
USABLE_MEMORY_START + USABLE_MEMORY_SIZE.into(),
PageEntryFlags::ReadWrite,
);
page_table.identity_map_range(USABLE_MEMORY_START, USABLE_MEMORY_START + USABLE_MEMORY_SIZE.into(), PageEntryFlags::ReadWrite);
// Map Uart so we can continue using serial
page_table.identity_map(
0x1000_0000_usize.into(),
PageEntryFlags::ReadWrite,
PageSize::Size4KiB,
);
page_table.identity_map(0x1000_0000_usize.into(), PageEntryFlags::ReadWrite, PageSize::Size4KiB);
let table_ppn = page_table_addr.as_addr() as usize >> 12;
let satp_value = 8 << 60 | table_ppn;
@ -99,7 +79,7 @@ unsafe extern "C" fn _kernel_start() -> ! {
}
/// Spin loop
pub fn spin_loop() -> ! {
pub fn sloop() -> ! {
loop {
unsafe { asm!("wfi") }
}

View File

@ -1,934 +0,0 @@
use crate::cpu_features;
use {
alloc::vec::Vec,
core::{arch::asm, fmt, ops::Deref, slice, str},
};
#[repr(u32)]
pub enum RequestType {
BasicInformation = 0x0000_0000,
VersionInformation = 0x0000_0001,
ThermalPowerManagementInformation = 0x0000_0006,
StructuredExtendedInformation = 0x0000_0007,
ExtendedFunctionInformation = 0x8000_0000,
ExtendedProcessorSignature = 0x8000_0001,
BrandString1 = 0x8000_0002,
BrandString2 = 0x8000_0003,
BrandString3 = 0x8000_0004,
// reserved = 0x80000005,
CacheLine = 0x8000_0006,
TimeStampCounter = 0x8000_0007,
PhysicalAddressSize = 0x8000_0008,
}
#[allow(clippy::similar_names)]
pub fn cpuid(code: RequestType) -> (u32, u32, u32, u32) {
let eax;
let ebx;
let ecx;
let edx;
unsafe {
asm!(
"movq %rbx, {0:r}",
"cpuid",
"xchgq %rbx, {0:r}",
lateout(reg) ebx,
inlateout("eax") code as u32 => eax,
inlateout("ecx") 0 => ecx,
lateout("edx") edx,
options(nostack, preserves_flags, att_syntax),
);
}
(eax, ebx, ecx, edx)
}
/// The main entrypoint to the CPU information
#[cfg(any(target_arch = "x86_64", target_arch = "x86"))]
pub fn master() -> Option<Master> {
Some(Master::new())
}
// This matches the Intel Architecture guide, with bits 31 -> 0.
// The bit positions are inclusive.
fn bits_of(val: u32, start_bit: u8, end_bit: u8) -> u32 {
let mut silly = 0;
for _ in start_bit..end_bit + 1 {
silly <<= 1;
silly |= 1;
}
(val >> start_bit) & silly
}
pub fn as_bytes(v: &u32) -> &[u8] {
let start = v as *const u32 as *const u8;
// TODO: use u32::BYTES
unsafe { slice::from_raw_parts(start, 4) }
}
macro_rules! bit {
($reg:ident, {$($idx:expr => $name:ident),+}) => {
$(pub fn $name(self) -> bool {
((self.$reg >> $idx) & 1) != 0
})+
}
}
macro_rules! dump {
($me:expr, $f: expr, $sname:expr, {$($name:ident),+}) => {
$f.debug_struct($sname)
$(.field(stringify!($name), &$me.$name()))+
.finish()
}
}
macro_rules! delegate_flag {
($item:ident, {$($name:ident),+}) => {
$(pub fn $name(&self) -> bool {
self.$item.map(|i| i.$name()).unwrap_or(false)
})+
}
}
macro_rules! master_attr_reader {
($name:ident, $kind:ty) => {
pub fn $name(&self) -> Option<&$kind> {
self.$name.as_ref()
}
};
}
#[derive(Copy, Clone)]
pub struct VersionInformation {
eax: u32,
ebx: u32,
ecx: u32,
edx: u32,
}
impl VersionInformation {
pub fn new() -> VersionInformation {
let (a, b, c, d) = cpuid(RequestType::VersionInformation);
VersionInformation {
eax: a,
ebx: b,
ecx: c,
edx: d,
}
}
pub fn family_id(self) -> u32 {
let family_id = bits_of(self.eax, 8, 11);
let extended_family_id = bits_of(self.eax, 20, 27);
if family_id != 0x0F {
family_id
} else {
extended_family_id + family_id
}
}
pub fn model_id(self) -> u32 {
let family_id = self.family_id();
let model_id = bits_of(self.eax, 4, 7);
let extended_model_id = bits_of(self.eax, 16, 19);
if family_id == 0x06 || family_id == 0x0F {
(extended_model_id << 4) + model_id
} else {
model_id
}
}
pub fn stepping(self) -> u32 {
bits_of(self.eax, 0, 3)
}
fn processor_signature(self) -> u32 {
self.eax
}
// TODO: Change return type and move this to a file that has the list
pub fn brand_string(self) -> Option<&'static str> {
let brand_index = bits_of(self.ebx, 0, 7);
let processor_signature = self.processor_signature();
match brand_index {
0x00 => None,
0x01 => Some("Intel(R) Celeron(R)"),
0x02 => Some("Intel(R) Pentium(R) III"),
0x03 => {
if processor_signature == 0x06B1 {
Some("Intel(R) Celeron(R)")
} else {
Some("Intel(R) Pentium(R) III Xeon(R)")
}
}
0x04 => Some("Intel(R) Pentium(R) III"),
0x06 => Some("Mobile Intel(R) Pentium(R) III-M"),
0x07 => Some("Mobile Intel(R) Celeron(R)"),
0x08 => Some("Intel(R) Pentium(R) 4"),
0x09 => Some("Intel(R) Pentium(R) 4"),
0x0A => Some("Intel(R) Celeron(R)"),
0x0B => {
if processor_signature == 0x0F13 {
Some("Intel(R) Xeon(R) MP")
} else {
Some("Intel(R) Xeon(R)")
}
}
0x0C => Some("Intel(R) Xeon(R) MP"),
0x0E => {
if processor_signature == 0x0F13 {
Some("Intel(R) Xeon(R)")
} else {
Some("Mobile Intel(R) Pentium(R) 4-M")
}
}
0x0F => Some("Mobile Intel(R) Celeron(R)"),
0x11 => Some("Mobile Genuine Intel(R)"),
0x12 => Some("Intel(R) Celeron(R) M"),
0x13 => Some("Mobile Intel(R) Celeron(R)"),
0x14 => Some("Intel(R) Celeron(R)"),
0x15 => Some("Mobile Genuine Intel(R)"),
0x16 => Some("Intel(R) Pentium(R) M"),
0x17 => Some("Mobile Intel(R) Celeron(R)"),
_ => None,
}
}
bit!(ecx, {
0 => sse3,
1 => pclmulqdq,
2 => dtes64,
3 => monitor,
4 => ds_cpl,
5 => vmx,
6 => smx,
7 => eist,
8 => tm2,
9 => ssse3,
10 => cnxt_id,
11 => sdbg,
12 => fma,
13 => cmpxchg16b,
14 => xtpr_update_control,
15 => pdcm,
// 16 - reserved
17 => pcid,
18 => dca,
19 => sse4_1,
20 => sse4_2,
21 => x2apic,
22 => movbe,
23 => popcnt,
24 => tsc_deadline,
25 => aesni,
26 => xsave,
27 => osxsave,
28 => avx,
29 => f16c,
30 => rdrand
// 31 - unused
});
bit!(edx, {
0 => fpu,
1 => vme,
2 => de,
3 => pse,
4 => tsc,
5 => msr,
6 => pae,
7 => mce,
8 => cx8,
9 => apic,
// 10 - reserved
11 => sep,
12 => mtrr,
13 => pge,
14 => mca,
15 => cmov,
16 => pat,
17 => pse_36,
18 => psn,
19 => clfsh,
// 20 - reserved
21 => ds,
22 => acpi,
23 => mmx,
24 => fxsr,
25 => sse,
26 => sse2,
27 => ss,
28 => htt,
29 => tm,
// 30 -reserved
31 => pbe
});
}
impl fmt::Debug for VersionInformation {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
dump!(self, f, "VersionInformation", {
family_id,
model_id,
stepping,
brand_string,
sse3,
pclmulqdq,
dtes64,
monitor,
ds_cpl,
vmx,
smx,
eist,
tm2,
ssse3,
cnxt_id,
sdbg,
fma,
cmpxchg16b,
xtpr_update_control,
pdcm,
pcid,
dca,
sse4_1,
sse4_2,
x2apic,
movbe,
popcnt,
tsc_deadline,
aesni,
xsave,
osxsave,
avx,
f16c,
rdrand,
fpu,
vme,
de,
pse,
tsc,
msr,
pae,
mce,
cx8,
apic,
sep,
mtrr,
pge,
mca,
cmov,
pat,
pse_36,
psn,
clfsh,
ds,
acpi,
mmx,
fxsr,
sse,
sse2,
ss,
htt,
tm,
pbe
})
}
}
#[derive(Copy, Clone)]
pub struct ExtendedProcessorSignature {
ecx: u32,
edx: u32,
}
impl ExtendedProcessorSignature {
fn new() -> ExtendedProcessorSignature {
let (_, _, c, d) = cpuid(RequestType::ExtendedProcessorSignature);
ExtendedProcessorSignature { ecx: c, edx: d }
}
bit!(ecx, {
0 => lahf_sahf_in_64_bit,
// 1-4 reserved
5 => lzcnt,
// 6-7 reserved
8 => prefetchw
// 9-31 reserved
});
bit!(edx, {
// 0-10 reserved
11 => syscall_sysret_in_64_bit,
// 12-19 reserved
20 => execute_disable,
// 21-25 reserved
26 => gigabyte_pages,
27 => rdtscp_and_ia32_tsc_aux,
// 28 reserved
29 => intel_64_bit_architecture
// 30-31 reserved
});
}
impl fmt::Debug for ExtendedProcessorSignature {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
dump!(self, f, "ThermalPowerManagementInformation", {
lahf_sahf_in_64_bit,
lzcnt,
prefetchw,
syscall_sysret_in_64_bit,
execute_disable,
gigabyte_pages,
rdtscp_and_ia32_tsc_aux,
intel_64_bit_architecture
})
}
}
// 3 calls of 4 registers of 4 bytes
const BRAND_STRING_LENGTH: usize = 3 * 4 * 4;
pub struct BrandString {
bytes: [u8; BRAND_STRING_LENGTH],
}
impl BrandString {
fn new() -> BrandString {
fn append_bytes(a: RequestType, bytes: &mut [u8]) {
let (a, b, c, d) = cpuid(a);
let result_bytes = as_bytes(&a)
.iter()
.chain(as_bytes(&b).iter())
.chain(as_bytes(&c).iter())
.chain(as_bytes(&d).iter());
for (output, input) in bytes.iter_mut().zip(result_bytes) {
*output = *input
}
}
let mut brand_string = BrandString {
bytes: [0; BRAND_STRING_LENGTH],
};
append_bytes(RequestType::BrandString1, &mut brand_string.bytes[0..]);
append_bytes(RequestType::BrandString2, &mut brand_string.bytes[16..]);
append_bytes(RequestType::BrandString3, &mut brand_string.bytes[32..]);
brand_string
}
}
impl Clone for BrandString {
fn clone(&self) -> Self {
let mut bytes = [0; BRAND_STRING_LENGTH];
for (d, s) in bytes.iter_mut().zip(self.bytes.iter()) {
*d = *s;
}
BrandString { bytes }
}
}
impl Deref for BrandString {
type Target = str;
fn deref(&self) -> &str {
let nul_terminator = self.bytes.iter().position(|&b| b == 0).unwrap_or(0);
let usable_bytes = &self.bytes[..nul_terminator];
unsafe { str::from_utf8_unchecked(usable_bytes) }.trim()
}
}
impl fmt::Display for BrandString {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
(self as &str).fmt(f)
}
}
impl fmt::Debug for BrandString {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
(self as &str).fmt(f)
}
}
#[derive(Copy, Clone)]
pub struct ThermalPowerManagementInformation {
eax: u32,
ebx: u32,
ecx: u32,
}
impl ThermalPowerManagementInformation {
fn new() -> ThermalPowerManagementInformation {
let (a, b, c, _) = cpuid(RequestType::ThermalPowerManagementInformation);
ThermalPowerManagementInformation {
eax: a,
ebx: b,
ecx: c,
}
}
bit!(eax, {
0 => digital_temperature_sensor,
1 => intel_turbo_boost,
2 => arat,
// 3 - reserved
4 => pln,
5 => ecmd,
6 => ptm,
7 => hwp,
8 => hwp_notification,
9 => hwp_activity_window,
10 => hwp_energy_performance_preference,
// 12 - reserved
13 => hdc
});
pub fn number_of_interrupt_thresholds(self) -> u32 {
bits_of(self.ebx, 0, 3)
}
bit!(ecx, {
0 => hardware_coordination_feedback,
// 1-2 - reserved
3 => performance_energy_bias
});
}
impl fmt::Debug for ThermalPowerManagementInformation {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
dump!(self, f, "ThermalPowerManagementInformation", {
digital_temperature_sensor,
intel_turbo_boost,
arat,
pln,
ecmd,
ptm,
hwp,
hwp_notification,
hwp_activity_window,
hwp_energy_performance_preference,
hdc,
number_of_interrupt_thresholds,
hardware_coordination_feedback,
performance_energy_bias
})
}
}
#[derive(Copy, Clone)]
pub struct StructuredExtendedInformation {
ebx: u32,
ecx: u32,
}
impl StructuredExtendedInformation {
fn new() -> StructuredExtendedInformation {
let (_, b, c, _) = cpuid(RequestType::StructuredExtendedInformation);
StructuredExtendedInformation { ebx: b, ecx: c }
}
bit!(ebx, {
0 => fsgsbase,
1 => ia32_tsc_adjust_msr,
// 2 - reserved
3 => bmi1,
4 => hle,
5 => avx2,
// 6 - reserved
7 => smep,
8 => bmi2,
9 => enhanced_rep_movsb_stosb,
10 => invpcid,
11 => rtm,
12 => pqm,
13 => deprecates_fpu_cs_ds,
// 14 - reserved
15 => pqe,
// 16-17 - reserved
18 => rdseed,
19 => adx,
20 => smap,
// 21-24 - reserved
25 => intel_processor_trace
// 26-31 - reserved
});
bit!(ecx, {
0 => prefetchwt1
});
}
impl fmt::Debug for StructuredExtendedInformation {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
dump!(self, f, "StructuredExtendedInformation", {
fsgsbase,
ia32_tsc_adjust_msr,
bmi1,
hle,
avx2,
smep,
bmi2,
enhanced_rep_movsb_stosb,
invpcid,
rtm,
pqm,
deprecates_fpu_cs_ds,
pqe,
rdseed,
adx,
smap,
intel_processor_trace,
prefetchwt1
})
}
}
#[derive(Debug, Copy, Clone)]
pub enum CacheLineAssociativity {
Disabled,
DirectMapped,
TwoWay,
FourWay,
EightWay,
SixteenWay,
Full,
}
#[derive(Copy, Clone)]
pub struct CacheLine(u32);
impl CacheLine {
fn new() -> CacheLine {
let (_, _, c, _) = cpuid(RequestType::CacheLine);
CacheLine(c)
}
pub fn cache_line_size(self) -> u32 {
bits_of(self.0, 0, 7)
}
pub fn l2_associativity(self) -> Option<CacheLineAssociativity> {
match bits_of(self.0, 12, 15) {
0x00 => Some(CacheLineAssociativity::Disabled),
0x01 => Some(CacheLineAssociativity::DirectMapped),
0x02 => Some(CacheLineAssociativity::TwoWay),
0x04 => Some(CacheLineAssociativity::FourWay),
0x06 => Some(CacheLineAssociativity::EightWay),
0x08 => Some(CacheLineAssociativity::SixteenWay),
0x0F => Some(CacheLineAssociativity::Full),
_ => None,
}
}
pub fn cache_size(self) -> u32 {
bits_of(self.0, 16, 31)
}
}
impl fmt::Debug for CacheLine {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
dump!(self, f, "CacheLine", {
cache_line_size,
l2_associativity,
cache_size
})
}
}
#[derive(Copy, Clone)]
pub struct TimeStampCounter {
edx: u32,
}
impl TimeStampCounter {
fn new() -> TimeStampCounter {
let (_, _, _, d) = cpuid(RequestType::TimeStampCounter);
TimeStampCounter { edx: d }
}
bit!(edx, {
// 0-7 - reserved
8 => invariant_tsc
// 9-31 - reserved
});
}
impl fmt::Debug for TimeStampCounter {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
dump!(self, f, "TimeStampCounter", { invariant_tsc })
}
}
#[derive(Copy, Clone)]
pub struct PhysicalAddressSize(u32);
impl PhysicalAddressSize {
fn new() -> PhysicalAddressSize {
let (a, _, _, _) = cpuid(RequestType::PhysicalAddressSize);
PhysicalAddressSize(a)
}
pub fn physical_address_bits(self) -> u32 {
bits_of(self.0, 0, 7)
}
pub fn linear_address_bits(self) -> u32 {
bits_of(self.0, 8, 15)
}
}
impl fmt::Debug for PhysicalAddressSize {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
dump!(self, f, "PhysicalAddressSize", {
physical_address_bits,
linear_address_bits
})
}
}
/// Information about the currently running processor
///
/// Feature flags match the feature mnemonic listed in the Intel
/// Instruction Set Reference. This struct provides a facade for flags
/// so the consumer doesn't need to worry about which particular CPUID
/// leaf provides the information.
///
/// For data beyond simple feature flags, you will need to retrieve
/// the nested struct and call the appropriate methods on it.
#[derive(Debug, Clone)]
pub struct Master {
// TODO: Rename struct
version_information: Option<VersionInformation>,
thermal_power_management_information: Option<ThermalPowerManagementInformation>,
structured_extended_information: Option<StructuredExtendedInformation>,
extended_processor_signature: Option<ExtendedProcessorSignature>,
brand_string: Option<BrandString>,
cache_line: Option<CacheLine>,
time_stamp_counter: Option<TimeStampCounter>,
physical_address_size: Option<PhysicalAddressSize>,
}
impl Master {
pub fn new() -> Master {
fn when_supported<F, T>(max: u32, kind: RequestType, then: F) -> Option<T>
where
F: FnOnce() -> T,
{
if max >= kind as u32 {
Some(then())
} else {
None
}
}
let (max_value, _, _, _) = cpuid(RequestType::BasicInformation);
let vi = when_supported(max_value, RequestType::VersionInformation, || {
VersionInformation::new()
});
let tpm = when_supported(
max_value,
RequestType::ThermalPowerManagementInformation,
|| ThermalPowerManagementInformation::new(),
);
let sei = when_supported(
max_value,
RequestType::StructuredExtendedInformation,
|| StructuredExtendedInformation::new(),
);
// Extended information
let (max_value, _, _, _) = cpuid(RequestType::ExtendedFunctionInformation);
let eps = when_supported(max_value, RequestType::ExtendedProcessorSignature, || {
ExtendedProcessorSignature::new()
});
let brand_string =
when_supported(max_value, RequestType::BrandString3, || BrandString::new());
let cache_line = when_supported(max_value, RequestType::CacheLine, || CacheLine::new());
let tsc = when_supported(max_value, RequestType::TimeStampCounter, || {
TimeStampCounter::new()
});
let pas = when_supported(max_value, RequestType::PhysicalAddressSize, || {
PhysicalAddressSize::new()
});
Master {
version_information: vi,
thermal_power_management_information: tpm,
structured_extended_information: sei,
extended_processor_signature: eps,
brand_string,
cache_line,
time_stamp_counter: tsc,
physical_address_size: pas,
}
}
// TODO: Macroify this and also include all of the cpu features from self
pub fn features(&self) -> Vec<(&str, bool)> {
let mut fv = Vec::new();
cpu_features!(self, fv);
return fv;
}
master_attr_reader!(version_information, VersionInformation);
master_attr_reader!(
thermal_power_management_information,
ThermalPowerManagementInformation
);
master_attr_reader!(
structured_extended_information,
StructuredExtendedInformation
);
master_attr_reader!(extended_processor_signature, ExtendedProcessorSignature);
master_attr_reader!(cache_line, CacheLine);
master_attr_reader!(time_stamp_counter, TimeStampCounter);
master_attr_reader!(physical_address_size, PhysicalAddressSize);
pub fn brand_string(&self) -> Option<&str> {
self.brand_string
.as_ref()
.map(|bs| bs as &str)
.or(self.version_information.and_then(|vi| vi.brand_string()))
}
delegate_flag!(version_information, {
sse3,
pclmulqdq,
dtes64,
monitor,
ds_cpl,
vmx,
smx,
eist,
tm2,
ssse3,
cnxt_id,
sdbg,
fma,
cmpxchg16b,
xtpr_update_control,
pdcm,
pcid,
dca,
sse4_1,
sse4_2,
x2apic,
movbe,
popcnt,
tsc_deadline,
aesni,
xsave,
osxsave,
avx,
f16c,
rdrand,
fpu,
vme,
de,
pse,
tsc,
msr,
pae,
mce,
cx8,
apic,
sep,
mtrr,
pge,
mca,
cmov,
pat,
pse_36,
psn,
clfsh,
ds,
acpi,
mmx,
fxsr,
sse,
sse2,
ss,
htt,
tm,
pbe
});
delegate_flag!(thermal_power_management_information, {
digital_temperature_sensor,
intel_turbo_boost,
arat,
pln,
ecmd,
ptm,
hwp,
hwp_notification,
hwp_activity_window,
hwp_energy_performance_preference,
hdc,
hardware_coordination_feedback,
performance_energy_bias
});
delegate_flag!(structured_extended_information, {
fsgsbase,
ia32_tsc_adjust_msr,
bmi1,
hle,
avx2,
smep,
bmi2,
enhanced_rep_movsb_stosb,
invpcid,
rtm,
pqm,
deprecates_fpu_cs_ds,
pqe,
rdseed,
adx,
smap,
intel_processor_trace,
prefetchwt1
});
delegate_flag!(extended_processor_signature, {
lahf_sahf_in_64_bit,
lzcnt,
prefetchw,
syscall_sysret_in_64_bit,
execute_disable,
gigabyte_pages,
rdtscp_and_ia32_tsc_aux,
intel_64_bit_architecture
});
delegate_flag!(time_stamp_counter, { invariant_tsc });
}
/*
cfg_if! {
if #[cfg(any(target_arch = "x86_64", target_arch = "x86"))] {
#[test]
fn basic_genuine_intel() {
let (_, b, c, d) = cpuid(RequestType::BasicInformation);
assert_eq!(b"Genu", as_bytes(&b));
assert_eq!(b"ntel", as_bytes(&c));
assert_eq!(b"ineI", as_bytes(&d));
}
#[test]
fn brand_string_contains_intel() {
assert!(master().unwrap().brand_string().unwrap().contains("Intel(R)"))
}
} else {}
}
*/

View File

@ -1,68 +0,0 @@
use {
crate::{
arch::{pci, x86_64::cpuid},
device_tree::DeviceTree,
kmain::DEVICE_TREE,
},
limine::SmpRequest,
xml::XMLElement,
};
fn collect_cpu_info(device_tree: &mut DeviceTree) {
use crate::alloc::string::ToString;
static SMP: SmpRequest = SmpRequest::new(0);
let smp_response = SMP.get_response().get().unwrap();
let mut cpu = XMLElement::new("cpu");
// Get the amount of cores on the CPU
let core_count = smp_response.cpu_count.to_string();
cpu.set_attribute("core count", core_count);
for x in 0..smp_response.cpu_count {
let core_name = alloc::format!("core_{}", x);
let core = XMLElement::new(core_name);
cpu.set_child(core);
}
let cpu_info = cpuid::master().unwrap();
let brand_string = cpu_info.brand_string().unwrap_or("Unknown").to_string();
cpu.set_attribute("brand string", brand_string);
cpu.set_attribute("speed", "unknown");
// Get CPU features and add them to the device tree entry.
let mut cpu_features = XMLElement::new("CPU Features");
for (feature_key, feature_enabled) in cpu_info.features() {
cpu_features.set_attribute(feature_key, feature_enabled.to_string());
}
cpu.set_child(cpu_features);
// CPU temperature
if cpu_info.digital_temperature_sensor() {
let mut temperature_child = XMLElement::new("Temperature");
temperature_child.set_attribute("degrees", "Unknown");
cpu.set_child(temperature_child);
}
// Add CPU to device tree
let cpus = device_tree.devices.get_mut("CPUs").unwrap();
cpus.push(cpu);
}
pub fn collect_device_info() {
log::trace!("Collecting devices on x86_64");
// Lock device tree
unsafe {
DEVICE_TREE.force_unlock();
}
let device_tree = &mut DEVICE_TREE.lock();
// Generate device tree from PCI enumeration.
pci::init(device_tree);
// Collect CPU info and add it to the device tree
collect_cpu_info(device_tree);
}

View File

@ -17,7 +17,7 @@ pub unsafe fn init() {
tables::load_tss,
};
log::trace!("Initialising GDT");
log::info!("Initialising GDT");
GDT.0.load();
CS::set_reg(GDT.1.kcode);
SS::set_reg(GDT.1.kdata);

View File

@ -1 +0,0 @@

View File

@ -1,13 +1,11 @@
// TODO: Turn apic keyboard interrupt into a standard ipc message
use {
log::trace,
spin::{Lazy, Mutex},
x2apic::lapic::{LocalApic, LocalApicBuilder},
x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame, PageFaultErrorCode},
};
use spin::{Lazy, Mutex};
use x2apic::lapic::{LocalApic, LocalApicBuilder};
use x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame, PageFaultErrorCode};
use crate::interp::wasm;
pub unsafe fn init() {
trace!("Initialising IDT");
log::info!("Initialising IDT");
IDT.load();
Lazy::force(&LAPIC);
x86_64::instructions::interrupts::enable();
@ -16,7 +14,6 @@ pub unsafe fn init() {
#[repr(u8)]
enum Interrupt {
Timer = 32,
ApicErr = u8::MAX - 1,
Spurious = u8::MAX,
}
@ -47,8 +44,8 @@ static IDT: Lazy<InterruptDescriptorTable> = Lazy::new(|| {
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
});
@ -63,7 +60,7 @@ extern "x86-interrupt" fn page_fault(
panic!("Page fault ({error_code:?}): {stack_frame:?}")
}
extern "x86-interrupt" fn timer(_isf: InterruptStackFrame) {
extern "x86-interrupt" fn timer(isf: InterruptStackFrame) {
unsafe { LAPIC.lock().end_of_interrupt() };
}

View File

@ -1,22 +1,46 @@
//! Logging (as in terms of console / serial output)
#![allow(deprecated)]
use {
core::fmt::Write,
limine::{TerminalRequest, TerminalResponse},
spin::{Lazy, Mutex},
uart_16550::SerialPort,
};
pub static SERIAL_CONSOLE: Mutex<SerialPort> = Mutex::new(unsafe { SerialPort::new(0x3F8) });
use core::fmt::Write;
use limine::{TerminalRequest, TerminalResponse};
use spin::{Lazy, Mutex};
use uart_16550::SerialPort;
static SERIAL_CONSOLE: Mutex<SerialPort> = Mutex::new(unsafe { SerialPort::new(0x3f8) });
static TERMINAL_LOGGER: Lazy<Mutex<TermLogger>> = Lazy::new(|| Mutex::new(TermLogger::new()));
pub fn init() {
SERIAL_CONSOLE.lock().init();
// Lazy::force(&TERMINAL_LOGGER);
Lazy::force(&TERMINAL_LOGGER);
}
pub fn log(args: core::fmt::Arguments<'_>) -> core::fmt::Result {
x86_64::instructions::interrupts::without_interrupts(|| {
// TERMINAL_LOGGER.lock().write_fmt(args)?;
TERMINAL_LOGGER.lock().write_fmt(args)?;
SERIAL_CONSOLE.lock().write_fmt(args)
})
}
struct TermLogger(&'static TerminalResponse);
unsafe impl Send for TermLogger {}
impl TermLogger {
pub fn new() -> Self {
static TERM_REQ: TerminalRequest = TerminalRequest::new(0);
Self(
TERM_REQ
.get_response()
.get()
.expect("failed to get terminal response"),
)
}
}
impl Write for TermLogger {
fn write_str(&mut self, s: &str) -> core::fmt::Result {
if let (Some(w), ts) = (self.0.write(), self.0.terminals()) {
for term in ts {
w(term, s);
}
}
Ok(())
}
}

View File

@ -1,10 +1,8 @@
use {
crate::memory::{MemoryManager, MAX_ORDER},
core::sync::atomic::AtomicU64,
limine::{MemmapEntry, MemoryMapEntryType, NonNullPtr},
spin::{Mutex, Once},
x86_64::{structures::paging::OffsetPageTable, VirtAddr},
};
use crate::memory::{MemoryManager, MAX_ORDER};
use core::sync::atomic::AtomicU64;
use limine::{MemmapEntry, MemoryMapEntryType, NonNullPtr};
use spin::{Mutex, Once};
use x86_64::{structures::paging::OffsetPageTable, VirtAddr};
pub const PAGE_SIZE: usize = 4096;
@ -14,7 +12,7 @@ static PAGE_TABLE: Once<Mutex<OffsetPageTable>> = Once::new();
/// Initialise page table
pub unsafe fn init_pt(phys_base: VirtAddr) {
log::debug!("Retrieving page table");
log::info!("Retrieving page table");
HHDM_OFFSET.store(phys_base.as_u64(), core::sync::atomic::Ordering::Relaxed);
PAGE_TABLE.call_once(|| {
Mutex::new(OffsetPageTable::new(

View File

@ -1,25 +1,15 @@
use {
crate::bootmodules::BootModule, core::arch::asm, embedded_graphics::pixelcolor::Rgb888,
log::warn, rdrand::RdSeed,
};
pub mod memory;
mod cpuid;
mod device_info_collector;
mod gdt;
pub mod graphics;
pub(crate) mod interrupts;
pub mod logging;
pub mod pci;
pub mod virtio;
mod logging;
pub use {logging::log, memory::PAGE_SIZE};
pub use logging::log;
pub use memory::PAGE_SIZE;
use {
crate::allocator,
limine::{HhdmRequest, KernelFileRequest, MemmapRequest, ModuleRequest},
x86_64::VirtAddr,
};
use crate::allocator;
use limine::{HhdmRequest, KernelFileRequest, MemmapRequest, ModuleRequest};
use x86_64::VirtAddr;
extern "C" {
fn _initial_kernel_heap_start();
@ -30,24 +20,7 @@ const INITIAL_KERNEL_HEAP_START: *mut u8 = _initial_kernel_heap_start as _;
const INITIAL_KERNEL_HEAP_SIZE: *const () = _initial_kernel_heap_size as _;
#[no_mangle]
#[naked]
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();
crate::logger::init().expect("failed to set logger");
log::info!("Initialising AKern {}", crate::VERSION);
@ -60,6 +33,7 @@ unsafe extern "C" fn start() -> ! {
.expect("tried to get physical memory mapping offset from Limine")
.offset,
));
allocator::init(INITIAL_KERNEL_HEAP_START, INITIAL_KERNEL_HEAP_SIZE as _);
static MMAP_REQ: MemmapRequest = MemmapRequest::new(0);
@ -77,105 +51,6 @@ unsafe extern "C" fn start() -> ! {
static KFILE_REQ: KernelFileRequest = KernelFileRequest::new(0);
static MOD_REQ: ModuleRequest = ModuleRequest::new(0);
device_info_collector::collect_device_info();
// Graphics test
// {
// graphics::init();
// let mut dis = DISPLAY.lock();
// use embedded_graphics::prelude::RgbColor;
// let _ = dis.set_color(Rgb888::YELLOW);
// let thick = 6;
// let p1 = (400, 30);
// let p2 = (200, 150);
// let p3 = (600, 150);
// let p4 = (200, 350);
// let p5 = (600, 350);
// let p6 = (400, 470);
// {
// //HEXAGON
// let _ = dis.line(p1.0, p1.1, p2.0, p2.1, thick);
// let _ = dis.line(p1.0, p1.1, p3.0, p3.1, thick);
// let _ = dis.line(p2.0, p2.1, p4.0, p4.1, thick);
// let _ = dis.line(p3.0, p3.1, p5.0, p5.1, thick);
// let _ = dis.line(p6.0, p6.1, p4.0, p4.1, thick);
// let _ = dis.line(p6.0, p6.1, p5.0, p5.1, thick);
// }
// {
// let _ = dis.line(600, 150, 200, 350, thick);
// let _ = dis.line(600, 350, 400, 250, thick);
// }
// {
// let _ = dis.set_color(Rgb888::WHITE);
// let hp1 = (350, 150);
// let hp2 = (350, 350);
// let hp3 = (450, 250);
// let hp4 = (350, 250);
// let hp5 = (450, 150);
// let hp6 = (450, 350);
// let _ = dis.line(hp1.0, hp1.1, hp2.0, hp2.1, thick);
// let _ = dis.line(hp3.0, hp3.1, hp4.0, hp4.1, thick);
// let _ = dis.line(hp5.0, hp5.1, hp6.0, hp6.1, thick);
// }
// dis.swap_buffers();
// };
// TODO: Add in rdseed and rdrand as sources for randomness
let _rand = xml::XMLElement::new("Random");
log::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);
}
crate::kmain::kmain(
KFILE_REQ
.get_response()
@ -188,110 +63,32 @@ unsafe extern "C" fn start() -> ! {
.transpose()
.expect("expected valid cmdline string")
.unwrap_or_default(),
bootmodules,
MOD_REQ
.get_response()
.get()
.and_then(|m| m.modules().get(0))
.map(|file| unsafe {
core::slice::from_raw_parts(
file.base.as_ptr().expect("invalid initrd"),
file.length as usize,
)
}),
)
}
/// Spin loop
pub fn spin_loop() -> ! {
pub fn sloop() -> ! {
loop {
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,
);
use log::trace;
use rdrand::RdRand;
let gen = RdRand::new().unwrap();
let ret = gen.try_next_u64().unwrap();
trace!("Random {}", ret);
ret
}

View File

@ -1,501 +0,0 @@
#[derive(Copy, Clone, Debug)]
/// A struct containing info about a PCI device.
pub struct PciDeviceInfo {
pub header_type: u8,
pub device: u8,
pub bus: u8,
pub device_id: DeviceID,
pub full_class: PciFullClass,
pub rev_id: u8,
}
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)
}

View File

@ -1,37 +0,0 @@
use {
core::{ptr::NonNull},
virtio_drivers::{BufferDirection, Hal, PhysAddr},
};
pub fn test() {
let _ps = virtio_drivers::PAGE_SIZE;
}
pub struct AbleosHal;
unsafe impl Hal for AbleosHal {
fn dma_alloc(_pages: usize, _direction: BufferDirection) -> (PhysAddr, NonNull<u8>) {
todo!();
}
unsafe fn dma_dealloc(_paddr: PhysAddr, _vaddr: NonNull<u8>, _pages: usize) -> i32 {
todo!()
}
unsafe fn mmio_phys_to_virt(paddr: PhysAddr, _size: usize) -> NonNull<u8> {
NonNull::new(paddr as _).unwrap()
}
unsafe fn share(_buffer: NonNull<[u8]>, _direction: BufferDirection) -> PhysAddr {
todo!()
}
unsafe fn unshare(_paddr: PhysAddr, _buffer: NonNull<[u8]>, _direction: BufferDirection) {
// Nothing to do, as the host already has access to all memory and we didn't copy the buffer
// anywhere else.
todo!()
}
}
fn virt_to_phys(vaddr: usize) -> PhysAddr {
vaddr
}

View File

@ -1,36 +0,0 @@
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
}

View File

@ -1,186 +0,0 @@
//! AbleOS capability tree implementation
use {
crate::{tab, utils::TAB},
alloc::{
string::{String, ToString},
vec,
},
core::fmt,
};
// Seperate
use alloc::vec::Vec;
struct Argument {
name: String,
type_: String,
}
struct Function {
name: String,
args: Vec<Argument>,
ret: String,
}
struct Capability {
name: String,
functions: Vec<Function>,
sub_capabilities: Vec<Capability>,
}
impl Capability {
fn new(name: String) -> Capability {
Capability {
name,
functions: Vec::new(),
sub_capabilities: Vec::new(),
}
}
}
impl fmt::Display for Capability {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Capability: {}\r\n", self.name)?;
for function in &self.functions {
write!(f, "{}Function: {}\r\n", tab!(1), function.name)?;
for arg in &function.args {
write!(
f,
"{}Argument: {} (Type: {})\r\n",
tab!(2),
arg.name,
arg.type_
)?;
}
write!(f, "{}Return Type: {}\r\n", tab!(2), &function.ret)?;
}
for sub_capability in &self.sub_capabilities {
write!(f, "{}{}\r\n", tab!(1), sub_capability)?;
}
Ok(())
}
}
// impl Capability {
// fn to_string_with_indentation(&self, level: usize) -> String {
// let indent = tab!(level);
// let mut result = format!("{}Capability: {}\n", indent, self.name);
// for function in &self.functions {
// result.push_str(&format!(
// "{}Function: {}\n",
// tab!(indent + 1),
// function.name
// ));
// for arg in &function.args {
// result.push_str(&format!(
// "{}Argument: {} (Type: {})\n",
// tab!(indent + 2),
// arg.name,
// arg.type_
// ));
// }
// result.push_str(&format!(
// "{}Return Type: {}\n",
// tab!(indent + 2),
// &function.ret
// ));
// }
// for sub_capability in &self.sub_capabilities {
// result.push_str(&sub_capability.to_string_with_indentation(level + 1));
// }
// result
// }
// }
struct CapabilityTree {
capabilities: Vec<Capability>,
}
impl CapabilityTree {
fn new() -> CapabilityTree {
CapabilityTree {
capabilities: Vec::new(),
}
}
}
/// A super simple capabilities example
pub fn example() {
let mut capability_tree = Capability::new("VFS".to_string());
let mut file_management_capability = Capability::new("File Management".to_string());
file_management_capability.functions.push(Function {
name: "OpenFile".to_string(),
args: vec![
Argument {
name: "path".to_string(),
type_: "String".to_string(),
},
Argument {
name: "mode".to_string(),
type_: "String".to_string(),
},
],
ret: "FileHandle".to_string(),
});
file_management_capability.functions.push(Function {
name: "ReadFile".to_string(),
args: vec![
Argument {
name: "file".to_string(),
type_: "FileHandle".to_string(),
},
Argument {
name: "buffer".to_string(),
type_: "&mut [u8]".to_string(),
},
Argument {
name: "length".to_string(),
type_: "usize".to_string(),
},
],
ret: "usize".to_string(),
});
file_management_capability.functions.push(Function {
name: "WriteFile".to_string(),
args: vec![
Argument {
name: "file".to_string(),
type_: "FileHandle".to_string(),
},
Argument {
name: "buffer".to_string(),
type_: "&[u8]".to_string(),
},
],
ret: "None".to_string(),
});
let mut directory_management_capability = Capability::new("Directory Management".to_string());
directory_management_capability.functions.push(Function {
name: "CreateDirectory".to_string(),
args: vec![Argument {
name: "path".to_string(),
type_: "String".to_string(),
}],
ret: "bool".to_string(),
});
directory_management_capability.functions.push(Function {
name: "ListDirectory".to_string(),
args: vec![Argument {
name: "path".to_string(),
type_: "String".to_string(),
}],
ret: "Vec<String>".to_string(),
});
capability_tree
.sub_capabilities
.push(file_management_capability);
capability_tree
.sub_capabilities
.push(directory_management_capability);
log::debug!("CapTree\r\n{}", capability_tree);
}

View File

@ -1,73 +0,0 @@
//! 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(())
}
}

View File

@ -1,44 +1,38 @@
//! A handle module
use {
crate::arch::hardware_random_u64,
alloc::vec::Vec,
core::fmt::{self, Formatter},
};
/// An operating system handle without permissions attached
#[derive(Debug, Eq, Hash, PartialEq, Clone, Copy)]
pub struct OSHandle {
id: u64,
pub id: u64,
}
impl OSHandle {
/// turn a u64 into an OSHandle
pub fn new_from_u64(id: u64) -> Self {
Self { id }
}
/// Generate a new OSHandle using the HAL random function
pub fn random_new() -> Self {
Self {
id: hardware_random_u64(),
}
}
}
/// A handle for resources
#[derive(Debug, Eq, Hash, PartialEq, Clone, Copy)]
pub struct Handle {
id: OSHandle,
// TODO: Update this to be indexes into the caps
perms: Permissions,
}
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
}
@ -46,18 +40,19 @@ impl Handle {
impl fmt::Display for Handle {
fn fmt(&self, w: &mut Formatter<'_>) -> Result<(), core::fmt::Error> {
write!(w, "{:?}", self.id)?;
write!(w, "{:?}", self.id);
Ok(())
}
}
#[derive(PartialEq, Hash, Eq, Debug, Clone, Copy)]
struct Permissions {
pub struct Permissions {
edit_children: bool,
edit_attributes: bool,
}
impl Permissions {
fn new() -> Self {
pub fn new() -> Self {
Self {
edit_children: true,
edit_attributes: true,

View File

@ -1,192 +0,0 @@
//! Environment call handling routines
use core::borrow::Borrow;
use crate::{
allocator,
holeybytes::kernel_services::{
block_read,
service_definition_service::{sds_msg_handler, SERVICES},
},
};
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 {
0 => match sds_msg_handler(vm, mem_addr, length) {
Ok(()) => {}
Err(err) => log::error!("Improper sds format"),
},
1 => match log_msg_handler(vm, mem_addr, length) {
Ok(()) => {}
Err(err) => log::error!("Improper log format"),
},
2 => {
use crate::holeybytes::kernel_services::mem_serve::memory_msg_handler;
match memory_msg_handler(vm, mem_addr, length) {
Ok(_) => {}
Err(_) => {}
}
//
}
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 => {
#[cfg(target_arch = "x86_64")]
{
let r2 = vm.registers[2].cast::<u64>();
unsafe fn x86_in(address: u16) -> u32 {
x86_64::instructions::port::Port::new(address).read()
}
unsafe fn x86_out(address: u16, value: u32) {
x86_64::instructions::port::Port::new(address).write(value);
}
vm.registers[3] = hbvm::value::Value(unsafe { x86_in(r2 as u16) } as u64);
}
}
// 5
_ => {
log::error!("Syscall unknown {:?}{:?}", r1, vm.registers);
}
}
}
fn log_msg_handler(vm: &mut Vm, mem_addr: u64, length: usize) -> Result<(), LogError> {
// let message_length = 8 + 8 + 8;
// log::info!("Mem Addr 0x{:x?} length {}", mem_addr, length);
let mut msg_vec = block_read(mem_addr, length);
let log_level = msg_vec.pop().unwrap();
match String::from_utf8(msg_vec) {
Ok(strr) => {
// use LogLevel::*;
let ll = match log_level {
0 | 48 => error!("{}", strr),
1 | 49 => warn!("{}", strr),
2 | 50 => info!("{}", strr),
3 | 51 => debug!("{}", strr),
4 | 52 => trace!("{}", strr),
_ => {
return Err(LogError::InvalidLogFormat);
}
};
}
Err(e) => {
error!("{:?}", e);
}
}
Ok(())
}
#[derive(Debug)]
pub enum LogError {
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(())
// }

View File

@ -1,22 +0,0 @@
enum MemoryServiceResult {
}
@alignment(4096)
type PageAlignedPointer = pointer;
type RID = u64;
@nonexhaustive
@version 1.0
protocol MemoryService {
@validator(page_count, Range(1..16))
fn map_pages(page_count: u8, ptr: Optional<PageAlignedPointer>) -> MemoryServiceResult;
fn unmap_pages(ptr: PageAlignedPointer) -> MemoryServiceResult;
// ptr must be page aligned and already mapped from map_pages
fn map_hardware(hw: RID, ptr: PageAlignedPointer) -> MemoryServiceResult;
fn unmap_hardware(hw: RID) -> MemoryServiceResult;
}

View File

@ -1,41 +0,0 @@
use {
crate::holeybytes::{
ecah::LogError,
kernel_services::{block_read, mem_serve},
Vm,
},
log::info,
};
pub enum MemoryServiceError {
InvalidMemoryFormat,
}
fn alloc_page(vm: &mut Vm, mem_addr: u64, length: usize) -> Result<(), MemoryServiceError> {
let mut val = alloc::vec::Vec::new();
for _ in 0..4096 {
val.push(0);
}
info!("Block address: {:?}", val.as_ptr());
vm.registers[1] = hbvm::value::Value(val.as_ptr() as u64);
vm.registers[2] = hbvm::value::Value(4096);
Ok(())
}
pub fn memory_msg_handler(
vm: &mut Vm,
mem_addr: u64,
length: usize,
) -> Result<(), MemoryServiceError> {
let mut msg_vec = block_read(mem_addr, length);
Ok(())
}
// match memory_msg_handler(vm, mem_addr, length) {
// Ok(()) => {
// let free_chunks = allocator::get_free_chunks_count();
// debug!("Free chunk count: {}", free_chunks);
// }
// Err(err) => log::error!("Improper log format"),
// };

View File

@ -1,15 +0,0 @@
use alloc::{vec, vec::Vec};
pub mod mem_serve;
pub mod service_definition_service;
pub fn block_read(mem_addr: u64, length: usize) -> Vec<u8> {
let mut msg_vec = vec![];
for x in 0..(length as isize) {
let xyz = mem_addr as *const u8;
let value = unsafe { xyz.offset(x).read() };
msg_vec.push(value);
}
msg_vec
}

View File

@ -1,74 +0,0 @@
use {
crate::{
alloc::string::ToString,
arch::hardware_random_u64,
holeybytes::{ecah::LogError, kernel_services::block_read, Vm},
ipc::{protocol, protocol::Protocol},
},
alloc::string::String,
hashbrown::HashMap,
log::info,
spin::{lazy::Lazy, Mutex},
};
pub struct Services(HashMap<u64, Protocol>);
pub static SERVICES: Lazy<Mutex<Services>> = Lazy::new(|| {
let mut dt = Services(HashMap::new());
dt.0.insert(0, Protocol::void());
Mutex::new(dt)
});
pub fn sds_msg_handler(vm: &mut Vm, mem_addr: u64, length: usize) -> Result<(), LogError> {
let mut msg_vec = block_read(mem_addr, length);
let sds_event_type: ServiceEventType = msg_vec[0].into();
msg_vec.remove(0);
use ServiceEventType::*;
match sds_event_type {
CreateService => {
let string = String::from_utf8(msg_vec).expect("Our bytes should be valid utf8");
sds_create_service(string);
}
DeleteService => todo!(),
SearchServices => todo!(),
}
// let buffer_id_raw = &msg_vec[0..8];
// let mut arr = [0u8; 8];
// arr.copy_from_slice(&buffer_id_raw);
// let buffer_id = u64::from_le_bytes(arr);
// info!("BufferID({:x?})", buffer_id);
// let mut services = SERVICES.lock();
// let string = String::from_utf8(msg_vec).expect("Our bytes should be valid utf8");
// use core::borrow::BorrowMut;
// services.borrow_mut().0.insert(buffer_id, string);
Ok(())
}
enum ServiceEventType {
CreateService = 0,
// UpdateService = 1,
DeleteService = 2,
SearchServices = 3,
}
impl From<u8> for ServiceEventType {
fn from(value: u8) -> Self {
use self::*;
match value {
0 => Self::CreateService,
// 1 =>
2 => Self::DeleteService,
3 => Self::SearchServices,
1_u8 | 4_u8..=u8::MAX => todo!(),
}
}
}
fn sds_create_service(protocol: String) -> u64 {
let buff_id = hardware_random_u64();
let mut services = SERVICES.lock();
services.0.insert(buff_id, protocol.clone().into());
info!("BufferID({}) => {}", buff_id, protocol);
let a: protocol::Protocol = protocol.into();
buff_id
}

View File

@ -1,62 +0,0 @@
//! Security? Multiple address spaces? What are you talking about
//! young adventurer. In this temple, we know no such words.
//!
//! Want your program to override other program's data or even the
//! data of the kernel itself? Sure. This right shall not be infringed.
use hbvm::mem::Address;
fn calc_start_of_page(ptr: u64) -> u64 {
let mut page_aligned = false;
if ptr % 4096 == 0 {
// page_aligned = true;
return ptr / 4096;
}
panic!("unaligned");
}
pub struct Memory {
// TODO: map page aligned segments of memory into a table or some sort here
}
impl Memory {
#[cfg(target_arch = "x86_64")]
fn read_device(addr: Address) {
unsafe {
//
// x86_64::instructions::port::Port::new(addr.get()).read()
}
}
}
impl hbvm::mem::Memory for Memory {
#[inline]
unsafe fn load(
&mut self,
addr: Address,
target: *mut u8,
count: usize,
) -> Result<(), hbvm::mem::LoadError> {
use log::{error, info};
if addr.get() % 4096 == 0 {}
info!("a");
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> {
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()
}
}

View File

@ -1,123 +0,0 @@
mod ecah;
mod kernel_services;
mod mem;
use {
crate::{arch, ipc::buffer::IpcBuffer, kmain::IPC_BUFFERS},
alloc::boxed::Box,
core::{default, future::Future, marker::PhantomData, ptr::NonNull, task::Poll},
hbvm::{
mem::{
softpaging::{icache::ICache, HandlePageFault, SoftPagedMem},
Address, Memory,
},
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),
}
}

View File

@ -0,0 +1,76 @@
use {
crate::interp::{HFIDT, OBJECTS},
alloc::string::String,
log::trace,
wasmi::{Caller, TypedFunc},
};
use super::{HostState, WasmContext};
pub fn host_register_idt_handler(
caller: Caller<'_, HostState>,
interupt_number: i32,
address_start: i32,
length_of_string: i32,
) -> i32 {
// TODO: get the proc_id to address which function it is
// TODO: Register the function name and proc_id into the idt handler
let mem = caller.get_export("memory").unwrap().into_memory().unwrap();
let mem_array = mem.data(&caller);
let mut name = String::new();
for i in address_start..(address_start + length_of_string) {
let ch = mem_array[i as usize] as char;
name.push(ch);
}
let index = interupt_number as usize;
let hf = HFIDT.lock();
// hf.insert(index);
trace!("{}", name);
0
}
use crate::interp::Handle;
pub fn host_make_object(
mut caller: Caller<'_, HostState>,
address_start: i32,
length_of_string: i32,
) -> i64 {
trace!(
"Called with addr {{ start {} length {} }}",
address_start,
length_of_string
);
let mem = caller.get_export("memory").unwrap().into_memory().unwrap();
let mem_array = mem.data(&caller);
let mut name = String::new();
for i in address_start..(address_start + length_of_string) {
let ch = mem_array[i as usize] as char;
name.push(ch);
}
trace!("Object Name {}", name);
let hand = Handle::new();
{
let binding = OBJECTS;
let mut olock = binding.lock();
let obj = xml::XMLElement::new(name);
olock.push(Some(obj))
}
caller.data_mut().handles.push(hand);
// hand.into()
hand.as_u64().try_into().unwrap()
}
pub type WFIDT = TypedFunc<(), ()>;
fn get_fn_from_wc(wc: WasmContext, function_name: String) -> WFIDT {
wc.instance
.get_typed_func(wc.store, &function_name)
.unwrap()
}

200
kernel/src/interp/mod.rs Normal file
View File

@ -0,0 +1,200 @@
mod host_functions;
mod objects;
use {
crate::{
handle::{self, Handle},
interp::{host_functions::host_make_object, objects::OBJECTS},
},
alloc::{string::String, vec::Vec},
hashbrown::HashMap,
log::trace,
spin::{Lazy, Mutex},
wasmi::{Caller, Error, Func, Instance, Linker, Module, Store, TypedFunc},
xml::XMLElement,
};
// Seperate use statement
use alloc::vec;
#[derive(Debug)]
pub struct WasmContext {
pub proc_id: Option<u64>,
pub instance: Instance,
pub store: Store<HostState>,
}
pub fn wasm() -> Result<(), wasmi::Error> {
use wasmi::{Config, Engine};
let mut conf = Config::default();
conf.wasm_bulk_memory(true);
// conf.,
let engine = Engine::new(&conf);
// trace!("Engine constructed");
// let wasm = include_bytes!("../../wasm_syscall_test.wasm");
let wasm = include_bytes!("../../../test.wasm");
// trace!("Loading WASM binary");
let module = Module::new(&engine, &wasm[..]).unwrap();
// trace!("Constructing wasm module");
let hs = HostState { handles: vec![] };
let mut store = Store::new(&engine, hs);
// trace!("constructing host store");
let read_mem_addr = Func::wrap(
&mut store,
|caller: Caller<'_, HostState>, param: i32| -> i32 { read_memory_address(caller, param) },
);
let mut linker = <Linker<HostState>>::new(&engine);
linker.define(
"host",
"read_mem_addr",
Func::wrap(
&mut store,
|caller: Caller<'_, HostState>, param: i32| -> i32 {
read_memory_address(caller, param)
},
),
)?;
linker.define(
"host",
"register_idt_handler",
Func::wrap(&mut store, host_functions::host_register_idt_handler),
)?;
linker.define(
"host",
"read_object_attribute",
Func::wrap(&mut store, host_read_object_attribute),
)?;
linker.define(
"host",
"create_object",
Func::wrap(&mut store, host_make_object),
)?;
let instance = linker
.instantiate(&mut store, &module)?
.ensure_no_start(&mut store)?;
let version = instance.get_global(&store, "VERSION");
// trace!("Version: {:?}", version);
let hello = instance.get_typed_func::<(), i64>(&store, "start")?;
let ret = hello.call(&mut store, ())?;
trace!("Called start got return of {:?}", ret);
Ok(())
}
#[derive(Clone, Debug)]
pub struct HostState {
handles: Vec<Handle>,
}
pub fn read_memory_address(caller: Caller<'_, HostState>, address: i32) -> i32 {
trace!("Address: {}", address);
// let obj = host_make_object(caller, 16, 23);
0
}
pub fn host_read_object_attribute(
caller: Caller<'_, HostState>,
handle: i64,
address_start: i32,
length_of_string: i32,
) -> (i32, i32) {
{
let binding = OBJECTS;
let mut olock = binding.lock();
// olock.get(&handle);
}
let mem = caller.get_export("memory").unwrap().into_memory().unwrap();
let mem_array = mem.data(&caller);
let mut name = String::new();
for i in address_start..(address_start + length_of_string) {
let ch = mem_array[i as usize] as char;
name.push(ch);
}
(0, 0)
}
pub fn build_wasm_context(bytes: Vec<u8>) -> Result<WasmContext, wasmi::Error> {
use wasmi::{Config, Engine};
let mut conf = Config::default();
conf.wasm_bulk_memory(true);
// conf.,
let engine = Engine::new(&conf);
// trace!("Engine constructed");
// let wasm = include_bytes!("../../wasm_syscall_test.wasm");
let wasm = include_bytes!("../../../test.wasm");
// trace!("Loading WASM binary");
let module = Module::new(&engine, &wasm[..]).unwrap();
// trace!("Constructing wasm module");
let hs = HostState { handles: vec![] };
let mut store = Store::new(&engine, hs);
// trace!("constructing host store");
let read_mem_addr = Func::wrap(
&mut store,
|caller: Caller<'_, HostState>, param: i32| -> i32 { read_memory_address(caller, param) },
);
let mut linker = <Linker<HostState>>::new(&engine);
linker.define(
"host",
"read_mem_addr",
Func::wrap(
&mut store,
|caller: Caller<'_, HostState>, param: i32| -> i32 {
read_memory_address(caller, param)
},
),
)?;
linker.define(
"host",
"read_object_attribute",
Func::wrap(&mut store, host_read_object_attribute),
)?;
linker.define(
"host",
"create_object",
Func::wrap(&mut store, host_make_object),
)?;
let instance = linker
.instantiate(&mut store, &module)?
.ensure_no_start(&mut store)?;
let wc = WasmContext {
instance,
store,
proc_id: None,
};
Ok(wc)
}
pub type HostFunctionIDT = HashMap<usize, WCFunction>;
pub struct WCFunction {
wc: WasmContext,
function: TypedFunc<(), ()>,
}
pub static HFIDT: Lazy<Mutex<HostFunctionIDT>> = Lazy::new(|| {
let mut hfidt = HashMap::new();
Mutex::new(hfidt)
});

View File

@ -0,0 +1,14 @@
use {
alloc::vec::Vec,
spin::{Lazy, Mutex},
};
// Seperate use statement
use alloc::vec;
pub type HostObjects = Vec<Option<xml::XMLElement>>;
pub const OBJECTS: Lazy<Mutex<HostObjects>> = Lazy::new(|| {
let mut obj = vec![];
Mutex::new(obj)
});

View File

@ -1,73 +0,0 @@
//!
use {
super::{message::Message, protocol::Protocol},
crossbeam_queue::{ArrayQueue, SegQueue},
};
pub enum BufferTypes {
Unbound(SegQueue<Message>),
Bound(ArrayQueue<Message>),
}
/// Interproccess buffer
pub struct IpcBuffer {
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::void(),
buffer: buftype,
}
}
(true, length) => {
let buftype = BufferTypes::Bound(ArrayQueue::new(length as usize));
Self {
protocol: Protocol::void(),
buffer: buftype,
}
}
}
}
/// Validate a message to match the `IPC.protocol`
pub fn validate_messages(&mut self) -> Result<(), IpcError> {
Ok(())
}
pub fn push(&mut self, msg: Message) {
match &self.buffer {
BufferTypes::Unbound(buff) => buff.push(msg.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,
}

View File

@ -1,7 +0,0 @@
//! An ipc message structured in a nice convenient way
use alloc::vec::Vec;
/// TODO: Extend this into a full structure
/// DEPEND: This depends on an IDL
pub type Message = Vec<u8>;

View File

@ -1,4 +0,0 @@
//! Interprocess communication
pub mod buffer;
pub mod message;
pub mod protocol;

View File

@ -1,40 +0,0 @@
use {
alloc::{string::String, vec::Vec},
hashbrown::HashMap,
log::info,
};
pub struct Type {}
pub struct Funct {
takes: Vec<String>,
gives: Vec<String>,
}
pub struct Protocol {
types: HashMap<String, Type>,
fns: HashMap<String, Funct>,
}
impl Protocol {
pub fn void() -> Self {
Self {
types: HashMap::new(),
fns: HashMap::new(),
}
}
// Check if a protocol defines all types it needs too
fn validate_protocol() -> bool {
false
}
}
impl From<String> for Protocol {
fn from(value: alloc::string::String) -> Self {
if value.starts_with("protocol") {
info!("ABC");
}
Self {
types: HashMap::new(),
fns: HashMap::new(),
}
}
}

View File

@ -1,129 +1,65 @@
//! AbleOS Kernel Entrypoint
use {
crate::{
arch::{hardware_random_u64, logging::SERIAL_CONSOLE},
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,
};
pub fn kmain(cmdline: &str, boot_modules: BootModules) -> ! {
debug!("Entered kmain");
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);
}
if let Err(e) = thr.await {
log::error!("{e:?}");
}
});
}
info!("{}", hardware_random_u64());
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 std::collections::HashMap;
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);
use log::{info, trace};
use spin::{Lazy, Mutex};
bufs.insert(1, log_buffer);
bufs.insert(2, file_buffer);
use crate::arch::{hardware_random_u64, sloop};
use crate::handle::Handle;
use crate::schedule::Scheduler;
use crate::{interp, task};
Mutex::new(bufs)
});
use crate::alloc::string::ToString;
#[test_case]
fn trivial_assertion() {
trace!("trivial assertion... ");
assert_eq!(1, 1);
info!("[ok]");
pub fn kmain(cmdline: &str, bootstrap: Option<&'static [u8]>) -> ! {
log::debug!("Entered kmain");
let mut cmdline = cmdline.to_string();
cmdline.pop();
cmdline.remove(0);
let kcmd = clparse::Arguments::parse(cmdline.to_string()).unwrap();
log::info!("Cmdline: {kcmd:?}");
// if kcmd.arguments.get("baka") == Some(&"true".to_string()) {
// let _ = crate::arch::log(format_args!(include_str!("../data/⑨. バカ")));
// }
// if kcmd.arguments.get("foobles") == Some(&"true".to_string()) {
// let _ = crate::arch::log(format_args!("foobles\n"));
// }
let bootstrap = bootstrap/*.expect("no bootstrap found")*/;
match bootstrap {
Some(bootstrap_mod) => {}
None => {
info!("No bootstrap module loaded.")
}
}
// use xml::XMLElement;
// let kcmd = XMLElement::new("cmdline");
// let hnd = Handle::new();
// kcmd.set_attribute("")
// OBJECTS.lock().insert(hnd, kcmd);
let abc = interp::wasm();
trace!("{:?}", abc);
// let sch = SCHEDULER;
// let mut sch = sch.lock();
// let wc = interp::build_wasm_context(alloc::vec::Vec::new()).unwrap();
// sch.schedule(wc, crate::schedule::ContextWake::None);
// sch.run();
crate::arch::sloop()
}
pub const SCHEDULER: Lazy<Mutex<Scheduler>> = Lazy::new(|| {
let mut sch = Scheduler::new();
Mutex::new(sch)
});

View File

@ -1,35 +1,28 @@
//! The ableOS kernel.
//! Named akern.
//! Akern is woefully undersupported at the moment but we are looking to add support improve hardware discovery and make our lives as kernel and operating system developers easier and better
#![no_std]
#![feature(
abi_x86_interrupt,
alloc_error_handler,
inline_const,
panic_info_message,
pointer_is_aligned,
ptr_sub_ptr,
custom_test_frameworks,
naked_functions,
prelude_import,
ptr_sub_ptr
)]
#![allow(dead_code)]
#![test_runner(crate::test_runner)]
#![no_std]
// #![deny(missing_docs)]
extern crate alloc;
mod allocator;
mod arch;
mod bootmodules;
mod capabilities;
mod device_tree;
mod handle;
mod holeybytes;
mod ipc;
pub mod handle;
pub mod interp;
mod kmain;
mod logger;
mod memory;
mod schedule;
mod task;
mod utils;
use versioning::Version;
@ -42,8 +35,6 @@ pub const VERSION: Version = Version {
#[panic_handler]
fn panic(info: &core::panic::PanicInfo) -> ! {
arch::register_dump();
if let Some(loc) = info.location() {
let _ = crate::arch::log(format_args!(
"Location: {}: {}, {}\r\n",
@ -59,11 +50,3 @@ fn panic(info: &core::panic::PanicInfo) -> ! {
loop {}
}
#[cfg(test)]
fn test_runner(tests: &[&dyn Fn()]) {
println!("Running {} tests", tests.len());
for test in tests {
test();
}
}

View File

@ -1,40 +1,29 @@
// TODO: Add a logger api with logger levels and various outputs
pub static TERMINAL_LOGGER: Lazy<Mutex<TermLogger>> = Lazy::new(|| Mutex::new(TermLogger::new()));
use {
limine::{TerminalRequest, TerminalResponse},
log::{Level, SetLoggerError},
spin::{lazy::Lazy, mutex::Mutex},
};
use log::{Level, SetLoggerError};
pub fn init() -> Result<(), SetLoggerError> {
log::set_logger(&crate::logger::Logger)?;
log::set_max_level(log::LevelFilter::Debug);
Lazy::force(&TERMINAL_LOGGER);
log::set_max_level(log::LevelFilter::Trace);
Ok(())
}
struct Logger;
impl log::Log for Logger {
fn enabled(&self, _metadata: &log::Metadata) -> bool {
fn enabled(&self, metadata: &log::Metadata) -> bool {
true
}
fn log(&self, record: &log::Record) {
let lvl = record.level();
let lvl_color = match lvl {
Level::Error => "160",
Level::Warn => "172",
Level::Info => "47",
Level::Debug => "25",
Level::Trace => "103",
};
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",
"\x1b[38;5;{}m{lvl}\x1b[0m [{}]: {}\r\n",
match lvl {
Level::Error => "160",
Level::Warn => "172",
Level::Info => "47",
Level::Debug => "25",
Level::Trace => "103",
},
record.module_path().unwrap_or_default(),
record.args(),
))
.expect("write to serial console");
@ -42,28 +31,3 @@ impl log::Log for Logger {
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(())
}
}

104
kernel/src/schedule.rs Normal file
View File

@ -0,0 +1,104 @@
use core::arch;
// WasmContext
use crate::{arch::sloop, interp::WasmContext};
use alloc::vec::Vec;
use log::trace;
pub type ProcId = u64;
pub struct Scheduler {
running: Vec<WasmContext>,
halted: Vec<(ContextWake, WasmContext)>,
// time_halt: Vec<(ContextWake, WasmContext)>,
next_proc_id: ProcId,
}
impl Scheduler {
pub fn new() -> Scheduler {
Self {
running: Vec::new(),
halted: Vec::new(),
// time_halt: Vec::new(),
next_proc_id: 0,
}
}
pub fn run(&mut self) -> ! {
loop {
let proc = self.running.pop();
// self.time_halt.sort();
match proc {
Some(proc) => {
// trace!("SWAP WasmContext");
self.running.push(proc);
}
None => {
panic!("nothing scheduled.");
sloop();
}
}
}
}
fn sleep_inner(&self, id: ProcId) -> Result<usize, SchedulerError> {
let proc_len = self.running.len();
let mut proc_found = true;
let mut sleep_index = 0;
let mut i = 0;
for wc in &self.running {
if wc.proc_id == Some(id) {
sleep_index = i;
proc_found = true;
break;
}
if i == proc_len {
proc_found = false;
trace!("no process with ID {} found", id);
return Err(SchedulerError::ProcessIDNotFound(id));
}
i += 1;
}
Ok(sleep_index)
}
pub fn sleep(&mut self, id: ProcId, time: u64) -> Result<(), SchedulerError> {
match self.sleep_inner(id) {
Ok(sid) => self
.halted
.push((ContextWake::Time(time), self.running.remove(sid))),
Err(error) => return Err(error),
}
Ok(())
}
pub fn schedule(&mut self, wc: WasmContext, cw: ContextWake) -> Result<(), SchedulerError> {
if wc.proc_id != None {
panic!("Already Scheduled with PROC_ID {}", wc.proc_id.unwrap());
}
trace!("Scheduling WC with ProcID {}", self.next_proc_id);
if cw == ContextWake::None {
self.running.push(wc)
} else {
self.halted.push((cw, wc));
}
self.next_proc_id += 1;
Ok(())
}
}
#[derive(PartialEq)]
pub enum ContextWake {
/// Used when spawning a new process to have it instantly start
None,
Time(u64),
ObjectEvent,
}
pub enum SchedulerError {
ProcessIDNotFound(ProcId),
AlreadyScheduled(),
}

View File

@ -1,19 +1,21 @@
#![allow(unused)]
//! Async task and executor
use {
alloc::{boxed::Box, collections::BTreeMap, sync::Arc, task::Wake},
core::{
future::Future,
pin::Pin,
task::{Context, Poll, Waker},
},
crossbeam_queue::SegQueue,
kiam::when,
slab::Slab,
spin::RwLock,
use alloc::{boxed::Box, collections::BTreeMap, sync::Arc, task::Wake};
use core::{
future::Future,
pin::Pin,
task::{Context, Poll, Waker},
};
use crossbeam_queue::SegQueue;
use slab::Slab;
use spin::RwLock;
type TaskQueue = Arc<SegQueue<TaskId>>;
type SpawnQueue = Arc<SegQueue<Task>>;
static SPAWN_QUEUE: RwLock<Option<SpawnQueue>> = RwLock::new(None);
/// Spawn a new task
pub fn spawn(future: impl Future<Output = ()> + Send + 'static) {
match &*SPAWN_QUEUE.read() {
Some(s) => s.push(Task::new(future)),
@ -21,6 +23,7 @@ pub fn spawn(future: impl Future<Output = ()> + Send + 'static) {
}
}
/// Forcibly yield a task
pub fn yield_now() -> impl Future<Output = ()> {
struct YieldNow(bool);
impl Future for YieldNow {
@ -40,59 +43,68 @@ pub fn yield_now() -> impl Future<Output = ()> {
YieldNow(false)
}
/// Tasks executor
#[derive(Default)]
pub struct Executor {
tasks: Slab<Task>,
queue: TaskQueue,
to_spawn: SpawnQueue,
wakers: BTreeMap<TaskId, Waker>,
/// All spawned tasks' stash
tasks: Slab<Task>,
/// Awake tasks' queue
queue: TaskQueue,
/// Incoming tasks to enqueue
incoming: SpawnQueue,
/// Wakers
wakers: BTreeMap<TaskId, Waker>,
}
impl Executor {
/// Spawn a task
pub fn spawn(&mut self, future: impl Future<Output = ()> + Send + 'static) {
self.queue
.push(TaskId(self.tasks.insert(Task::new(future))));
}
/// Spin poll loop until it runs out of tasks
pub fn run(&mut self) {
// Assign `self.incoming` to global spawn queue to spawn tasks
// from within
{
let mut global_spawner = SPAWN_QUEUE.write();
if global_spawner.is_some() {
panic!("Task executor is already running");
let mut spawner = SPAWN_QUEUE.write();
if spawner.is_some() {
panic!("task executor is already running");
}
*global_spawner = Some(Arc::clone(&self.to_spawn));
*spawner = Some(Arc::clone(&self.incoming));
}
loop {
when! {
let Some(id) = self
.to_spawn
.pop()
.map(|t| TaskId(self.tasks.insert(t)))
.or_else(|| self.queue.pop())
=> {
let Some(task) = self.tasks.get_mut(id.0) else {
panic!("Attempted to get task from empty slot: {}", id.0);
};
// Try to get incoming task, if none available, poll
// enqueued one
while let Some(id) = self
.incoming
.pop()
.map(|t| TaskId(self.tasks.insert(t)))
.or_else(|| self.queue.pop())
{
let Some(task) = self.tasks.get_mut(id.0) else {
panic!("attempted to get non-extant task with id {}", id.0)
};
let mut cx = Context::from_waker(self.wakers.entry(id).or_insert_with(|| {
Waker::from(Arc::new(TaskWaker {
id,
queue: Arc::clone(&self.queue),
}))
}));
let mut cx = Context::from_waker(self.wakers.entry(id).or_insert_with(|| {
Waker::from(Arc::new(TaskWaker {
id,
queue: Arc::clone(&self.queue),
}))
}));
match task.poll(&mut cx) {
Poll::Ready(()) => {
self.tasks.remove(id.0);
self.wakers.remove(&id);
}
Poll::Pending => (),
}
},
self.tasks.is_empty() => break,
_ => (),
match task.poll(&mut cx) {
Poll::Ready(()) => {
// Task done, unregister
self.tasks.remove(id.0);
self.wakers.remove(&id);
}
Poll::Pending => (),
}
}
@ -100,13 +112,17 @@ impl Executor {
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
struct TaskId(usize);
/// Async task
struct Task {
future: Pin<Box<dyn Future<Output = ()> + Send>>,
}
impl Task {
pub fn new(future: impl Future<Output = ()> + Send + 'static) -> Self {
log::trace!("New task scheduled");
/// Create a new task from a future
fn new(future: impl Future<Output = ()> + Send + 'static) -> Self {
Self {
future: Box::pin(future),
}
@ -117,20 +133,13 @@ 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 {
id: TaskId,
id: TaskId,
queue: TaskQueue,
}
impl Wake for TaskWaker {
fn wake(self: Arc<Self>) {
log::trace!("Woke Task-{:?}", self.id);
self.wake_by_ref();
}

View File

@ -1,53 +0,0 @@
//! A module for small utilities to be used kernel wide
//! Simple functions and constants
/// Used when tab `\t` in hardware is not known and we will default to two spaces
pub const TAB: &str = " ";
// NOTE: this only reduces the code duplication in source code not in generated code!
// Written by Yours Truly: Munir
/// A simple macro to reduce code duplication when we use TAB internally
#[macro_export]
macro_rules! tab {
($num:expr) => {
TAB.repeat($num)
}
}
// NOTE: this only reduces the code duplication in source code not in generated code!
// Written by Yours Truly: Munir
/// A simple macro to reduce code duplication when we insert device types into the device tree
#[macro_export]
macro_rules! device_tree {
($devtree:expr, $dev_type_vec:expr) => {
for each_device_type in $dev_type_vec {
$devtree.devices.insert(each_device_type.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));
};
}

24
kernel/syscall.md Normal file
View File

@ -0,0 +1,24 @@
`create_object`
```
params
i32
start address of the string to use as the object name
i32
length of string
returns
i64 Handle to the object
```
`read_object_attribute`
```
params
i64 Handle to the object
i32
start address of the string to use as the attribute name
i32
end address of the string to use as the attribute name
returns
```

View File

@ -1,25 +0,0 @@
{
"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": ""
}

View File

@ -11,7 +11,7 @@
"linker": "rust-lld",
"panic-strategy": "abort",
"disable-redzone": true,
"features": "",
"features": "-mmx,-sse,+soft-float",
"code-model": "kernel",
"pre-link-args": {
"ld.lld": [

2
limine

@ -1 +1 @@
Subproject commit 2d3d7b2633b5d95ce404a177ada0d5cbee802721
Subproject commit 751e802e173392e8637759e2b3c96bbf59456f87

51
meta.md Normal file
View File

@ -0,0 +1,51 @@
ARI AbleOS Remote Install
Server
/boot/server_kernel_x86_64.bin
/boot/kernel_x86_64.bin
/boot/kernel_aarch64.bin
/home/projects/askl.askl - aksldfhlkasjdhflkajshdflkj
ARI_SERVER.wasm
NAS 10.1.10.10
ARI 10.1.10.10
/boot/limine.cfg
/boot/kernel_x86_64.bin
/boot/kernel.toml
/home/projects/askl.askl
aksldfhlkasjdhflkajshdflkj
ARI 10.1.10.10
/boot/limine.cfg
/boot/kernel_aarch64.bin
/boot/kernel.toml
/system/
/shared/
/home/programs/
project_name/
project_name.wasm
project_name.toml
/system/pkgman.toml
//////
[repositories]
PUR = "https://git.ablecorp.us/ableos/pur"

17232
out.txt Normal file

File diff suppressed because it is too large Load Diff

View File

@ -4,15 +4,7 @@ version = "0.2.0"
edition = "2021"
[dependencies]
str-reader = "0.1.2"
derive_more = "0.99"
error-stack = "0.4"
env_logger = "0.10"
error-stack = "0.2"
fatfs = "0.3"
toml = "0.5.2"
hbasm.git = "https://git.ablecorp.us/AbleOS/holey-bytes.git"
[dependencies.reqwest]
version = "0.11"
default-features = false
features = ["rustls-tls", "blocking"]
log = "0.4"

View File

Before

Width:  |  Height:  |  Size: 1.8 MiB

After

Width:  |  Height:  |  Size: 1.8 MiB

22
repbuild/limine.cfg Normal file
View File

@ -0,0 +1,22 @@
${ABLEOS_KERNEL}=boot:///kernel
# TODO: Make a boot background image for ableOS
DEFAULT_ENTRY=1
TIMEOUT=50
VERBOSE=yes
INTERFACE_RESOLUTION=1024x768
# Terminal related settings
TERM_WALLPAPER=boot:///background.bmp
TERM_BACKDROP=008080
:AbleOS
COMMENT=Default AbleOS boot entry.
PROTOCOL=limine
KERNEL_PATH=${ABLEOS_KERNEL}
KERNEL_CMDLINE="baka=false foobles=true"
# KERNEL_CMDLINE=""
# Setting a default resolution for the framebuffer
RESOLUTION=1024x768x24
# MODULE_PATH=boot:///boot/fs.wasm
# MODULE_CMDLINE=This is the first module.

View File

@ -1,28 +1,12 @@
use {
derive_more::Display,
error_stack::{bail, report, Context, Report, Result, ResultExt},
fatfs::{FileSystem, FormatVolumeOptions, FsOptions, ReadWriteSeek},
std::{
fmt::Display,
fs::{self, File},
io::{self, Write},
path::Path,
process::{exit, Command},
},
};
use error_stack::{bail, report, Context, IntoReport, Result, ResultExt};
use fatfs::{FileSystem, FormatVolumeOptions, FsOptions, ReadWriteSeek};
use std::{fmt::Display, fs::File, io, path::Path, process::Command};
fn main() -> Result<(), Error> {
env_logger::init();
let mut args = std::env::args();
args.next();
// 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() {
Some("build" | "b") => {
let mut release = false;
@ -30,16 +14,12 @@ fn main() -> Result<(), Error> {
for arg in args {
if arg == "-r" || arg == "--release" {
release = true;
} else if arg == "rv64" || arg == "riscv64" || arg == "riscv64-virt" {
}
if arg == "rv64" || arg == "riscv64" || arg == "riscv64-virt" {
target = Target::Riscv64Virt;
} else if arg == "arm64" || arg == "aarch64" || arg == "aarch64-virt" {
target = Target::Aarch64;
} else {
return Err(report!(Error::InvalidSubCom));
}
}
assemble()?;
build(release, target).change_context(Error::Build)
}
Some("run" | "r") => {
@ -48,16 +28,12 @@ fn main() -> Result<(), Error> {
for arg in args {
if arg == "-r" || arg == "--release" {
release = true;
} else if arg == "rv64" || arg == "riscv64" || arg == "riscv64-virt" {
}
if arg == "rv64" || arg == "riscv64" || arg == "riscv64-virt" {
target = Target::Riscv64Virt;
} else if arg == "arm64" || arg == "aarch64" || arg == "aarch64-virt" {
target = Target::Aarch64;
} else {
return Err(report!(Error::InvalidSubCom));
}
}
assemble()?;
build(release, target)?;
run(release, target)
}
@ -78,208 +54,50 @@ 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> {
let filename = "sysdata/system_config.toml";
let path = Path::new("target/disk.img");
// Read the contents of the file using a `match` block
// to return the `data: Ok(c)` as a `String`
// or handle any `errors: Err(_)`.
let contents = match fs::read_to_string(filename) {
// If successful return the files text as `contents`.
// `c` is a local variable.
Ok(c) => c,
// Handle the `error` case.
Err(_) => {
// Write `msg` to `stderr`.
eprintln!("Could not read file `{}`", filename);
// Exit the program with exit code `1`.
exit(1);
}
};
use toml::Value;
let mut limine_str = String::new();
let mut data: Value = toml::from_str(&contents).unwrap();
let boot_table = data.get_mut("boot");
let limine_table = boot_table.unwrap().get_mut("limine").unwrap();
let default_entry = limine_table.get("default_entry").unwrap();
let timeout = limine_table.get("timeout").unwrap();
let interface_resolution = limine_table.get("interface_resolution").unwrap();
let verbose = limine_table.get("verbose").unwrap();
let term_wallpaper = limine_table.get("term_wallpaper").unwrap();
let vb_post = match verbose.as_bool().unwrap() {
true => "yes",
false => "no",
};
let term_background = limine_table
.get("term_backdrop")
.unwrap_or(&Value::Integer(0));
let base = format!(
"DEFAULT_ENTRY={}
TIMEOUT={}
VERBOSE={}
INTERFACE_RESOLUTION={}
# Terminal related settings
TERM_WALLPAPER={}
TERM_BACKDROP={}
",
default_entry,
timeout,
vb_post,
interface_resolution,
term_wallpaper.as_str().unwrap(),
term_background
);
limine_str.push_str(&base);
let boot_entries = limine_table.as_table_mut().unwrap();
let mut real_boot_entries = boot_entries.clone();
for (key, value) in boot_entries.into_iter() {
if !value.is_table() {
real_boot_entries.remove(key);
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()
}
}
for (name, mut value) in real_boot_entries {
let comment = value.get("comment").unwrap();
let protocol = value.get("protocol").unwrap();
let resolution = value.get("resolution").unwrap();
let kernel_path = value.get("kernel_path").unwrap();
let kernel_cmdline = value.get("kernel_cmdline").unwrap();
let text_entry = format!(
"
:{}
COMMENT={}
PROTOCOL={}
RESOLUTION={}
KERNEL_PATH={}
KERNEL_CMDLINE={}
",
name,
comment.as_str().unwrap(),
protocol.as_str().unwrap(),
resolution.as_str().unwrap(),
kernel_path.as_str().unwrap(),
kernel_cmdline,
);
limine_str.push_str(&text_entry);
let modules = value.get_mut("modules").unwrap().as_table_mut().unwrap();
// let mut real_modules = modules.clone();
for (key, value) in modules.into_iter() {
if value.is_table() {
let path = value.get("path").unwrap();
let cmd_line = value.get("cmd_line").unwrap();
let a = format!(
" MODULE_PATH={}
MODULE_CMDLINE={}\n\n",
path.as_str().unwrap(),
cmd_line
);
limine_str.push_str(&a);
}
}
}
let mut img = File::options()
.read(true)
.write(true)
.create(true)
.open(Path::new("target/disk.img"))?;
.open(path)?;
img.set_len(1024 * 1024 * 64)?;
fatfs::format_volume(&mut img, FormatVolumeOptions::new())?;
let fs = FileSystem::new(img, FsOptions::new())?;
let bootdir = fs.root_dir().create_dir("efi")?.create_dir("boot")?;
let mut f = fs.root_dir().create_file("limine.cfg")?;
let a = f.write(limine_str.as_bytes())?;
drop(f);
io::copy(
&mut File::open("limine/BOOTX64.EFI")
.map_err(Report::from)
.attach_printable("Copying Limine (x86_64): have you pulled the submodule?")?,
.into_report()
.attach_printable("copying Limine bootloader (have you pulled the submodule?)")?,
&mut bootdir.create_file("bootx64.efi")?,
)?;
io::copy(
&mut File::open("limine/BOOTAA64.EFI")
.map_err(Report::from)
.attach_printable("Copying Limine (ARM): have you pulled the submodule?")?,
&mut bootdir.create_file("bootaa64.efi")?,
&mut File::open("repbuild/limine.cfg")?,
&mut fs.root_dir().create_file("limine.cfg")?,
)?;
io::copy(
&mut File::open("repbuild/background.bmp")?,
&mut fs.root_dir().create_file("background.bmp")?,
)?;
// TODO: Remove this and replace it with pulling executables from the system_config
for fpath in [
"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/sds_test.hbf",
"target/test-programs/limine_framebuffer_driver.hbf",
"target/test-programs/keyboard_driver.hbf",
] {
let path = Path::new(fpath);
io::copy(
&mut File::open(path)?,
&mut fs
.root_dir()
.create_file(&path.file_name().unwrap().to_string_lossy())?,
)?;
}
drop(bootdir);
Ok(fs)
@ -294,11 +112,11 @@ fn build(release: bool, target: Target) -> Result<(), Error> {
com.arg("-r");
}
if target == Target::Riscv64Virt {
com.args(["--target", "targets/riscv64-virt-ableos.json"]);
}
if target == Target::Aarch64 {
com.args(["--target", "targets/aarch64-virt-ableos.json"]);
match target {
Target::Riscv64Virt => {
com.args(["--target", "targets/riscv64-virt-ableos.json"]);
}
_ => {}
}
match com.status() {
@ -307,31 +125,22 @@ fn build(release: bool, target: Target) -> Result<(), Error> {
_ => (),
}
let mut path: String = "kernel".to_string();
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"
}
};
if target != Target::X86_64 {
return Ok(());
}
(|| -> std::io::Result<_> {
io::copy(
&mut File::open(
Path::new(kernel_dir)
Path::new("target/x86_64-ableos")
.join(if release { "release" } else { "debug" })
.join("kernel"),
)?,
&mut fs.root_dir().create_file(&path)?,
&mut fs.root_dir().create_file("kernel")?,
)
.map(|_| ())
})()
.map_err(Report::from)
.into_report()
.change_context(Error::Io)
}
@ -339,54 +148,45 @@ fn run(release: bool, target: Target) -> Result<(), Error> {
let mut com = match target {
Target::X86_64 => Command::new("qemu-system-x86_64"),
Target::Riscv64Virt => Command::new("qemu-system-riscv64"),
Target::Aarch64 => Command::new("qemu-system-aarch64"),
};
let ovmf_path = fetch_ovmf(target);
match target {
Target::X86_64 => {
#[rustfmt::skip]
com.args([
"-bios", &ovmf_path.change_context(Error::OvmfFetch)?,
"-drive", "file=target/disk.img,format=raw",
"-m", "4G",
"-smp", "cores=4",
// "-enable-kvm",
"-cpu", "Broadwell-v4"
]);
}
Target::Riscv64Virt => {
#[rustfmt::skip]
com.args([
"-M", "virt",
"-m", "128M",
"-serial", "stdio",
"-kernel",
if release {
"target/riscv64-virt-ableos/release/kernel"
} else {
"target/riscv64-virt-ableos/debug/kernel"
}
]);
}
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",
]);
if target == Target::X86_64 {
#[rustfmt::skip]
com.args([
"-bios",
std::env::var("REPBUILD_QEMU_FIRMWARE_PATH")
.as_deref()
.unwrap_or("/usr/share/ovmf/x64/OVMF_CODE.fd"),
"-drive", "file=target/disk.img,format=raw",
"-m", "4G",
"-serial", "stdio",
"-smp", "cores=2",
]);
#[cfg(target_os = "linux")]
{
com.args(["-enable-kvm", "-cpu", "host"]);
}
}
if target == Target::Riscv64Virt {
#[rustfmt::skip]
com.args([
"-M", "virt",
"-m", "128M",
"-serial", "stdio",
"-kernel",
if release {
"target/riscv64-virt-ableos/release/kernel"
} else {
"target/riscv64-virt-ableos/debug/kernel"
}
]);
}
match com
.status()
.map_err(Report::from)
.into_report()
.change_context(Error::ProcessSpawn)?
{
s if s.success() => Ok(()),
@ -394,92 +194,33 @@ 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)]
enum Target {
X86_64,
Riscv64Virt,
Aarch64,
}
#[derive(Debug, Display)]
#[derive(Debug)]
enum Error {
#[display(fmt = "Failed to build the kernel")]
Build,
#[display(fmt = "Missing or invalid subcommand (available: build, run)")]
InvalidSubCom,
#[display(fmt = "IO Error")]
Io,
#[display(fmt = "Failed to spawn a process")]
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>),
}
impl Context 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 {
if let Some(c) = self.0 {
c.fmt(f)
} else {
f.write_str("Interrupted by signal")
impl Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Build => f.write_str("failed to build the kernel"),
Self::InvalidSubCom => {
f.write_str("missing or invalid subcommand (available: build, run)")
}
Self::Io => f.write_str("IO error"),
Self::ProcessSpawn => f.write_str("failed to spawn a process"),
Self::Qemu(Some(c)) => write!(f, "QEMU Error: {c}"),
Self::Qemu(None) => write!(f, "QEMU Error: interrupted by signal"),
}
}
W(e)
}

View File

@ -1,3 +1,3 @@
[toolchain]
channel = "nightly-2023-09-17"
channel = "nightly"
components = ["rust-src", "llvm-tools"]

View File

@ -1,3 +1,3 @@
hex_literal_case = "Upper"
imports_granularity = "One"
hex_literal_case = "Upper"
imports_granularity = "One"
struct_field_align_threshold = 5

View File

@ -1,41 +0,0 @@
{ pkgs ? import <nixpkgs> { } }:
pkgs.mkShell rec {
buildInputs = with pkgs; [
clang
llvmPackages.bintools
rustup
qemu_full
# OMVFFull
# OMVF
];
extraCmds = '''';
RUSTC_VERSION = pkgs.lib.readFile ./rust-toolchain.toml;
# https://github.com/rust-lang/rust-bindgen#environment-variables
LIBCLANG_PATH =
pkgs.lib.makeLibraryPath [ pkgs.llvmPackages_latest.libclang.lib ];
shellHook = ''
export REPBUILD_QEMU_FIRMWARE_PATH=${pkgs.OVMF.fd}/FV/OVMF.fd
export PATH=$PATH:''${CARGO_HOME:-~/.cargo}/bin
export PATH=$PATH:''${RUSTUP_HOME:-~/.rustup}/toolchains/$RUSTC_VERSION-x86_64-unknown-linux-gnu/bin/
'';
# Add precompiled library to rustc search path
RUSTFLAGS = (builtins.map (a: "-L ${a}/lib") [
# add libraries here (e.g. pkgs.libvmi)
]);
# Add glibc, clang, glib and other headers to bindgen search path
BINDGEN_EXTRA_CLANG_ARGS =
# Includes with normal include path
(builtins.map (a: ''-I"${a}/include"'') [
# add dev libraries here (e.g. pkgs.libvmi.dev)
pkgs.glibc.dev
])
# Includes with special directory paths
++ [
''
-I"${pkgs.llvmPackages_latest.libclang.lib}/lib/clang/${pkgs.llvmPackages_latest.libclang.version}/include"''
''-I"${pkgs.glib.dev}/include/glib-2.0"''
"-I${pkgs.glib.out}/lib/glib-2.0/include/"
];
}

View File

@ -1,22 +0,0 @@
Boolean
Stuffed into a u8 to be indexed into
00_00_00_01
^^--- One Boolean
|the Second Boolean
UTF8 String
"Able The Above" => UTF8 14 bytes long
Date Time (U128 seconds since the beginning of the universe)
Binary Blob
List<T>
Bound/Unbound
// Ordered/Unordered
Examples:
OSPath Is Unbounded List <String>
Hashmap<K, V>

View File

@ -1,40 +0,0 @@
${ABLEOS_KERNEL}=boot:///kernel
# TODO: Make a boot background image for ableOS
DEFAULT_ENTRY=1
TIMEOUT=0
VERBOSE=yes
INTERFACE_RESOLUTION=1024x768
# Terminal related settings
TERM_WALLPAPER=boot:///background.bmp
TERM_BACKDROP=008080
:AbleOS
COMMENT=Default AbleOS boot entry.
PROTOCOL=limine
KERNEL_PATH=boot:///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="arch=${ARCH}"
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}"

View File

@ -1,14 +0,0 @@
# Dev
Dev is a (currently) hypothetical tool meant to be used to ease development and compilation on ableOS.
## Usage
A `meta.toml` file must be in the project root. A `src` folder and a `lib` folder must exist.
Binaries should be put into a folder named `bin`.
```
bin/
lib/
src/
```
The folders `lib/` and `bin/` should both be left out of source tracking.

View File

@ -1,16 +0,0 @@
[package]
name = "dev"
authors = ["able"]
[dependants.libraries]
file_service = "0.0.1"
[dependants.binaries]
susc.version = "1.0.0"
[build.debug]
command = "susc src/main.hbl"
[run.debug]
depends = ["build.debug"]
command = "bin/main.hbf"

View File

@ -1,5 +0,0 @@
#include "lib/file_service.h"
int main() {
File fhand = file_open("meta.toml");
}

View File

@ -1,15 +0,0 @@
[package]
name = "fisp_test"
authors = ["able"]
[dependants.libraries]
[dependants.binaries]
# Refers to @FunkyEgg's lisp compiler for ableOS
fisp = ""
[build.debug]
command = "fisp src/main.fisp"
[run.debug]
depends = ["build.debug"]
command = "bin/main.hbf"

View File

@ -1 +0,0 @@
(log info "Hello World\n")

View File

@ -1,16 +0,0 @@
[package]
name = "htasm_test"
authors = ["able"]
# Similar to cargo libraries
[dependants.libraries]
# Similar to cargo install
[dependants.binaries]
htasm = ""
[build.debug]
command = "htasm src/main.S"
[run.debug]
depends = ["build.debug"]
command = "bin/main.hbf"

View File

@ -1,10 +0,0 @@
jmp start
start:
li64 r1, 3
li64 r2, 1
lra16 r3, r0, hello_string
li64 r4, 0x14
string
.db "Hello, world!\n"

View File

@ -1,5 +0,0 @@
type BufferID = u64;
protocol SDS {
fn register_protocol(BufferID, String) -> bool;
}

View File

@ -1,50 +0,0 @@
[boot]
[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_${ARCH}"
kernel_cmdline = ""
resolution = "1024x768x24"
[boot.limine.ableos.modules]
[boot.limine.ableos.modules.failure]
path = "boot:///failure.hbf"
cmd_line = ""
[boot.limine.ableos.modules.ecall]
path = "boot:///ecall.hbf"
cmd_line = ""
[boot.limine.ableos.modules.sds_test]
path = "boot:///sds_test.hbf"
cmd_line = ""
[boot.limine.ableos.modules.main]
path = "boot:///main.hbf"
cmd_line = ""
[boot.limine.ableos.modules.keyboard_driver]
path = "boot:///keyboard_driver.hbf"
cmd_line = "arch=${ARCH}"
[boot.limine.ableos.modules.vfs_test]
path = "boot:///vfs_test.hbf"
cmd_line = ""
[boot.limine.ableos.modules.limine_framebuffer_driver]
path = "boot:///limine_framebuffer_driver.hbf"
cmd_line = "height=10 width=10 arch=${ARCH}"
[boot.limine.ableos.modules.serial_driver]
path = "boot:///serial_driver.hbf"
cmd_line = "arch=${ARCH}"

View File

@ -1,3 +0,0 @@
li64 (r1, 2);
eca ();
tx ();

View File

@ -1 +0,0 @@
un();

View File

@ -1 +0,0 @@
A kind of standard library.

View File

@ -1,54 +0,0 @@
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(){}

View File

@ -1,199 +0,0 @@
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();

View File

@ -1,164 +0,0 @@
// 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;
// let BUFFER = 0xFFFF8000BC430000;
// 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();

View File

@ -1,33 +0,0 @@
import "sysdata/test-programs/hblib/std" as std;
fn main(){
std::Error(":o) h0nk");
std::Warn("Your mom is a worm!");
std::Info("Hello, world!");
// std::Debug("XYZ");
// std::Trace("Trace Deez");
let ADDR = 0xFFFF_FFFF_8100_0000;
let ADDR_PLUS_ONE = ADDR + 1;
let ADDR_PLUS_NINE = ADDR + 9;
li64(r25, 1);
st(r25, r0, ADDR, 1);
li64(r25, 0);
st(r25, r0, ADDR_PLUS_ONE, 8);
li64(r25, 17);
st(r25, r0, ADDR_PLUS_NINE, 1);
li64(r1, 3);
li64(r2, 2);
li64(r3, ADDR);
li64(r4, 0);
eca();
tx();
}
main();

View File

@ -1,19 +0,0 @@
fn create_buffer_protocol(string) {
let str = data::str("0" + string);
li8(r10, 0);
str(r10, r0, str, 1);
li64(r1, 3);
li64(r2, 0);
lra(r3, r0, str);
li64(r4, str.len);
eca();
}
create_buffer_protocol("protocol Math {\n\r"+
"\tfn add(i64, i64) -> i64;\n\r"+
"\tfn div(i64, i64) -> i64;\n\r"+
"}");
tx();

View File

@ -1,27 +0,0 @@
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();

View File

@ -1,11 +0,0 @@
/// 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();

View File

@ -1,15 +0,0 @@
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();

View File

@ -1,63 +0,0 @@
type String {
length uint32,
data [u8; length],
}
// needs three bits to store this
@exhaustive
enum LogLevel {
Error = 0,
Warn = 1,
Info = 2,
Debug = 3,
Trace = 4,
}
type LogMessage {
log_level = LogLevel,
log_message = String,
}
// This is displayed as bits sent over the wire
[
010 // INFO
00000000_00000000_00000000_00000011 // Length of the string
01001000 // H
01101001 // i
00100001 // !
]
// This is displayed as bytes in memory
[
0x3 // INFO
0xD // Length of the string
0x48
0x69
0x21
]
enum LogResult {
Ok,
Error,
}
@exhaustive
protocol Logger {
fn log(LogMessage) -> LogResult;
fn error(String) -> LogResult;
fn warn(String) -> LogResult;
fn info(String) -> LogResult;
fn debug(String) -> LogResult;
fn trace(String) -> LogResult;
fn flush() -> LogResult;
}
TODO argue about time being added after the fact in the logger or inplace by the loggee

View File

@ -1,4 +0,0 @@
/// a b c
void main(){}
// Generated documentation below

View File

@ -1,2 +0,0 @@
(label "Documentation")
(label "")

View File

@ -1,7 +0,0 @@
(vertical
(horizontal
(label "Function main")
(button "goto declaration" (on_click "src/main.c:2")))
(label "takes void")
(label "returns void")
(label "a b c"))

View File

@ -1,5 +0,0 @@
- container
- horizontal
- vertical
- framebuffer
-

31
system.toml Normal file
View File

@ -0,0 +1,31 @@
[boot]
[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"
nya = "https://git.ablecorp.us/AbleOS/nya"
[packages]
[packages.list_files]
version = "0.1.1"
hash = ""
repo = "userspace"
authors = []
[packages.list_files.configuration]