1
0
Fork 0
forked from koniifer/ableos

Compare commits

..

253 commits

Author SHA1 Message Date
koniifer 41b339dfd0 omfg it's fixed 🙏 2024-09-16 21:56:52 +01:00
koniifer a8d38e04c4 let's just use strings for now 2024-09-16 20:45:19 +01:00
koniifer 1f4fce0f66 please bugs begone 2024-09-16 20:15:51 +01:00
koniifer b021fc5b86 bug squashing & testing 2024-09-15 17:01:29 +01:00
able 5f2b181f22 Merge pull request 'good luck able' (#17) from koniifer/ableos-framebuffer:master into master
Reviewed-on: https://git.ablecorp.us/AbleOS/ableos/pulls/17
2024-09-14 16:44:05 +00:00
koniifer 43ea77c18f merge mainline branch and do some housekeeping 2024-09-14 11:26:32 +01:00
Able 2b2e0c514b multiline 2024-09-14 04:28:45 -05:00
Able fcca015866 minor changes 2024-09-14 04:05:40 -05:00
Able cc9337348e PCI+SVGA skeleton 2024-09-14 03:51:57 -05:00
Able 028949559b ignim checkpoint 2024-09-14 00:31:35 -05:00
Able 91380539d9 Ignim work 2024-09-13 23:11:50 -05:00
Able ec25c0f207 update on the logger
Further changes pending on the IDL
2024-09-13 20:50:12 -05:00
Able 1b5cb54a2b ignim work 2024-09-13 20:17:47 -05:00
Able 9686349476 add support for the device tree 2024-09-13 18:11:23 -05:00
koniifer f8c7873978 squash 2024-09-13 22:41:31 +01:00
Able 40cc412ab3 Horizon API work 2024-09-13 16:40:05 -05:00
Able cd369b39d5 more changes to make konii so anger 2024-09-12 15:34:28 -05:00
mlokr 331cbf5da1
fixing arm compilation errors 2024-09-10 21:52:57 +02:00
koniifer 63e2f546c5 Merge pull request 'adding disasembly in case something goes wrong' (#1) from mlokis/ableos-framebuffer:disasm into master
Reviewed-on: https://git.ablecorp.us/koniifer/ableos-framebuffer/pulls/1
2024-09-04 17:32:19 +00:00
mlokr 1a2b60b53b
foo 2024-09-04 19:14:30 +02:00
koniifer a7517005de update to latest hblang 2024-09-04 16:08:01 +01:00
Able 0594b99a59 cleanup 2024-09-03 03:34:29 -05:00
Able 1855307cd9 IDL tokenization 2024-09-02 21:50:43 -05:00
koniifer e3f7a2d455 inline fb_driver, update to latest hblang 2024-09-02 04:36:03 +01:00
koniifer 19992595fc update hblang to latest git
remove old ps/2 driver
remove defunct time driver
clean up stuff
i promise im done fiddling with ecah.rs and memory.hb
2024-09-02 01:04:00 +01:00
koniifer f7b970eaf0 hexadecimal support!!
remove fb_driver_stresstest, move examples back to fb_driver, update hblang, update Cargo.lock
2024-09-01 22:29:42 +01:00
koniifer c752028c73 fix ecah.rs, implement -d, --debuginfo to print debug info in serial (requires recompilation) 2024-08-31 19:34:14 +01:00
koniifer 8577920d90 port ecah changes from svga_driver branch 2024-08-31 15:38:15 +01:00
Able 7426bf479f idl work 2024-08-30 12:31:45 -05:00
koniifer 12ee3a9b87 fix random
implement hardware_random_u32
implement math.max, alter math.min
remove unneeded dependencies from fb_driver
2024-08-30 16:22:13 +01:00
koniifer 58bc6facbc Merge remote-tracking branch 'origin/kodin/keyboard-driver' 2024-08-30 14:55:22 +01:00
Talha Qamar 1615297536 Detecting keypresses 2024-08-30 18:06:24 +05:00
Talha Qamar 0d3641e199 just getting started 2024-08-30 18:04:10 +05:00
Able 6295a7118e Added beef to ableOS 2024-08-30 07:38:04 -05:00
koniifer ad85f82be3 begin work for fb_driver interface
create hardware rng buffer & stn.random.uint_64 (currently weird)
move examples out of fb_driver (currently broken)
remove literal kernel panic from `info!("AHHH")`
re-implement stn.buffer.send_message()
2024-08-29 21:37:49 +01:00
Able 9100b3ce44 dev update 2024-08-29 06:51:48 -05:00
Able 1c491e70e0 dev tool prototype 2024-08-28 14:35:08 -05:00
Able 0444fe4dfa readme update 2024-08-27 12:35:52 -05:00
able db08a249e1 Merge pull request 'fb driver' (#16) from aurlex/ableos-framebuffer:master into master
Reviewed-on: https://git.ablecorp.us/AbleOS/ableos/pulls/16
2024-08-21 03:26:45 +00:00
aurlex acc9d19a32 fb driver 2024-08-20 13:03:39 +01:00
Able 6fd47695a6 changes 2024-08-19 13:13:58 -05:00
Able fb8a835926 this ia bad way to handle this but oh well 2024-08-12 08:21:31 -05:00
Able f4246ae387 SEARCHING for dynamically created buffers now works using buffer.create / buffer.search 2024-08-12 08:15:50 -05:00
Able c7214a5a9b commit 2024-08-11 15:10:36 -05:00
Able bf86d9219c disable all programs 2024-07-25 09:28:56 -05:00
Able ea6ba3bdb0 in/out b 2024-07-23 19:37:43 -05:00
Able 3f183e231d compiler update 2024-07-22 18:43:19 -05:00
Able 514dadc667 rename 2024-07-21 06:47:25 -05:00
Able 9ec3bb1f99 fix 2024-07-20 12:54:58 -05:00
Able b99cb09a74 cleanup 2024-07-20 04:10:15 -05:00
Able 528b1fc66c formatted code 2024-07-19 08:53:45 -05:00
Able f0956b529c formater 2024-07-19 07:31:01 -05:00
Able bb37de554f update the compiler 2024-07-19 05:47:59 -05:00
able 0f3c94c0c9 Merge pull request 'String Library Update' (#15) from Trees/ableos_time:my-branch into master
Reviewed-on: https://git.ablecorp.us/AbleOS/ableos/pulls/15
2024-07-17 01:52:52 +00:00
Sam Buckley 314523fce7 Reenable fb driver 2024-07-17 01:28:04 +01:00
Sam Buckley 9f9c7af85f Add string stuff to library 2024-07-17 01:24:24 +01:00
Sam Buckley f59776e792 Update string lib for num format - Trees 2024-07-16 22:42:49 +01:00
Able 1adc381399 Hack in an inb/outb api 2024-07-15 16:56:46 -05:00
Able f33cc0bf70 did some stuff /shrug 2024-07-07 08:35:07 -05:00
Able 5f136a66af patch in the fb stuff 2024-07-06 11:23:44 -05:00
Able 54d7e6b02b work 2024-07-06 09:24:23 -05:00
Able 62c181fb6a checkpoint 2024-06-14 11:48:53 -05:00
Able e9e813220b update 2024-06-08 15:18:21 -05:00
able 02455e2cd8 deprecate the old assembler 2024-05-31 13:35:46 -05:00
able e08eab8627 patching together some broken stuff 2024-05-31 13:31:06 -05:00
able c57ef99948 Merge pull request 'un-hard-code the tests' (#14) from wildwestrom/ableos:master into master
Reviewed-on: https://git.ablecorp.us/AbleOS/ableos/pulls/14
2024-05-31 15:44:43 +00:00
Christian Westrom b0358efab8 factor out separating path names from the boot prefix 2024-06-01 00:43:40 +09:00
Christian Westrom da606facb0 un-hard-code the tests 2024-06-01 00:31:04 +09:00
able b427ae1c27 Probably this works on someone elses machine. 2024-05-31 10:07:22 -05:00
able a511e99606 Update ecalls to match the spec 2024-05-31 09:15:55 -05:00
able d90016f28e checkpoint 2024-05-31 09:11:45 -05:00
able c20376464e reorg sysdata 2024-05-23 16:59:17 -05:00
able bbe29d54ab Merge pull request 'Repbuild will add files to the disk image programmatically' (#13) from wildwestrom/ableos:master into master
Reviewed-on: https://git.ablecorp.us/AbleOS/ableos/pulls/13
2024-05-05 15:54:56 +00:00
Christian Westrom a5cab167c5 load the modules programmatically instead of manually 2024-05-06 00:48:37 +09:00
Christian Westrom b96927d61a remove the fuckywucky memory shit 2024-05-06 00:48:24 +09:00
able edda52e857 Make repbuild safe(er) again. 2024-05-05 05:52:49 -05:00
able d7efa8ca20 Spec typification 2024-05-05 05:08:42 -05:00
able 5fc2e2a6be spec work 2024-05-04 14:46:24 -05:00
able d21654dd4b Starting to spec out the interface with the kernel 2024-05-04 13:20:30 -05:00
able 38986193ca mem stuff 2024-05-04 12:41:47 -05:00
able 779f3bdd1f perchance it works 2024-04-29 05:30:42 -05:00
able f767362ad0 fix :thumb: 2024-04-29 04:43:47 -05:00
able 088e628cde Hypothetical ideas laid out 2024-04-24 23:08:34 -05:00
able 1cc414eaaf meta info 2024-04-24 20:09:45 -05:00
able 5e73e7a370 begin work on ipc protocols 2024-03-22 05:13:17 -05:00
able cc4de4ab5e sds prelim work 2024-03-22 03:58:59 -05:00
able 634d05acea UI Lisp idea 2024-03-13 05:10:45 -05:00
able 189ad503c7 remove a random binary that was checked in 2024-03-11 09:49:11 -05:00
able fac1f77270 memory service 2024-03-11 09:48:56 -05:00
able eb30ee3c12 example of a new build tool for programs 2024-02-15 15:24:01 -06:00
able 89b495d318 more changes 2024-02-15 14:21:00 -06:00
able 7c68609af5 Worked on various small bits 2024-02-15 14:19:51 -06:00
able dfacc91f40 fix the dang lock file 2024-02-10 16:28:51 -06:00
able 307020b96b Un fucked the thingy 2024-02-10 16:15:33 -06:00
able d8cb4d4e64 reorganization 2024-01-18 02:36:24 -06:00
able 195192db8a compiling on arm works again 2023-12-13 04:21:32 -06:00
able 5fba1eb890 Merge pull request 'ECAH: Add error handling for accessing non-existant buffers. As well as add keyboard driver.' (#12) from jcodefox/ableos:master into master
Reviewed-on: https://git.ablecorp.us/AbleOS/ableos/pulls/12
2023-12-05 06:04:34 +00:00
Jcodefox 0a6085061a ECAH: Add a simple keyboard driver 2023-12-05 00:56:23 -05:00
Jcodefox 6f061153e6 Log number with buffer error 2023-12-01 10:02:56 -05:00
Jcodefox cb66c07a5f Add check for non-existent buffer 2023-12-01 09:48:57 -05:00
able 15515e6643 add in a Memory Service
Currently it fully ignores messages and only allocates blocks in 4096 byte chunks
2023-12-01 06:11:33 -06:00
able 7a2372d32a Donation 2023-11-27 07:12:04 -06:00
able 65b6f52d2e POC serial driver for arm
Does not work for x86 yet
2023-11-21 03:56:18 -06:00
able 562fb7c9b2 meow 2023-11-20 03:13:18 -06:00
able 762b2aa3ae working on logs 2023-11-19 18:15:03 -06:00
able fe6cccc70d attempt to log arguments in the limine framebuffer
Still needs work having to do with setting the log level
2023-11-18 02:17:54 -06:00
able 815c424248 Minor fixes 2023-11-18 01:32:09 -06:00
Erin b8ce78b6dd Sussy stuff 2023-11-15 19:41:44 +01:00
Erin d396da5f3c Stack grows downwards, baka. 2023-11-15 19:37:52 +01:00
Erin 0f7525b7e3 Stack for programs 2023-11-15 19:33:21 +01:00
able ebf31cba3d add in liberapay 2023-11-14 15:02:50 -06:00
able f074527e42 Arguments are actually passed into programs 2023-11-13 23:51:30 -06:00
Erin f2e561e242 Merge pull request 'Refactored project structure to make it more clean.' (#11) from struct-refactor into master
Reviewed-on: https://git.ablecorp.us/AbleOS/ableos/pulls/11
2023-11-11 15:12:02 +00:00
Erin 2c1d24ab37 Little reorg 2023-11-11 15:45:45 +01:00
Erin 4e9b75a517 kernel(detail): remove logging on memory load 2023-11-11 13:58:52 +01:00
able 0af4758a45 beop 2023-11-03 08:25:31 -05:00
Erin fd575a17c9 Fixed memory bug 2023-11-03 09:04:22 +01:00
able bda8659747 beepo 2023-11-02 14:12:10 -05:00
able 631e1dc288 Panic rn 2023-11-02 14:08:48 -05:00
able b7f9b071bf :) limine 2023-10-29 09:25:13 -05:00
able 94569624f6 update the limine CFG 2023-10-29 08:41:20 -05:00
able 080bb8b188 More work on the psuedo STD lib and IPC 2023-10-29 07:27:10 -05:00
able 1ae1d2ceac Logging works enough. Still unstructured however. 2023-10-28 23:14:36 -05:00
able 707528ef86 A nice stopping point so I can lament work 2023-10-28 08:43:32 -05:00
able c8f500470e Getting some basic userland logger setup 2023-10-28 08:28:07 -05:00
Erin 6885f1cdaf Updated HBVM version 2023-10-28 03:26:04 +02:00
able fa328add42 remove redundant comment bb 2023-10-25 08:36:12 -05:00
able d1d1bd7fd7 cursed-ness 2023-10-23 09:12:43 -05:00
Erin ebfc9c1c4e Zero memory on allocation 2023-10-08 11:24:55 +02:00
able ada43910d2 edits to support multi-arch iso 2023-09-20 12:26:36 -05:00
able 29bcce58b3 CPUID support 2023-09-20 12:01:12 -05:00
able 9105469c3b Arm now logs to the framebuffer 2023-09-17 17:13:23 -05:00
able e7bbb9a375 Arm is now feature parity with x86 2023-09-17 16:03:32 -05:00
able 008a8eb336 More tracing 2023-09-13 02:19:37 -05:00
able e0aa63bebf DOC: Improved driver dependencies and such 2023-09-11 01:36:13 -05:00
able 9cf6f93949 TODO updates 2023-09-09 15:52:01 -05:00
able 1be13d30d1 Ecall work 2023-09-09 02:35:16 -05:00
able 8fec90db95 X86 Timer cleanup 2023-09-09 02:34:43 -05:00
able c16c235c95 Module fix 2023-09-09 02:34:29 -05:00
able 54844b46a0 ECALL work and expanded errors on HBVM shutdown 2023-09-07 14:36:53 -05:00
able b04ee13185 Register dump on panic 2023-09-07 14:31:31 -05:00
Erin 0e8fb17f3a REPBUILD: Fix 2023-08-30 01:12:40 +02:00
Erin 3c45720fa3 Better example 2023-08-22 15:57:57 +02:00
Erin cbed32526b KERNEL: Fixed holeybytes 2023-08-22 15:52:30 +02:00
Erin 0f151fdd52 阿呆: changed trait impls 2023-08-22 15:31:28 +02:00
Erin f948e35e3f Updated deps
+ manage your local editor ignores locally, we are not here for supporting all possible editors on the world.
2023-08-22 15:17:27 +02:00
Erin 88213a7df0 AMOGUS: Fixed compilation 2023-08-13 02:36:26 +02:00
able 239ee43064 Merge pull request 'ARM: Add serial console logging' (#9) from microtau/ableos:master into master
Reviewed-on: https://git.ablecorp.us/AbleOS/ableos/pulls/9
2023-07-20 11:03:57 +00:00
microtau c9ab181d95 REPBUILD: Always regenerate the image 2023-07-20 10:42:48 +00:00
microtau f474f0fb69 CLEAN: Remove env_logger dependency 2023-07-20 10:02:10 +00:00
microtau d0a2f436a8 CLEAN: Remove unnecessary dependencies 2023-07-20 09:24:33 +00:00
microtau 7865bca782 ARM: Add serial console logging 2023-07-20 09:21:00 +00:00
able c0744d5596 Merge pull request 'LIMINE: Bump version' (#8) from microtau/ableos:master into master
Reviewed-on: https://git.ablecorp.us/AbleOS/ableos/pulls/8
2023-07-19 17:14:08 +00:00
microtau ea49841de2 LIMINE: Bump version 2023-07-19 16:54:01 +00:00
able 84757f7060 Revert "LIMINE: I think this updates the submodule?"
This reverts commit 2dcd096de9.
2023-07-19 11:21:15 -05:00
able e7b46f639c SUBMODULE: Removed it temporarily 2023-07-19 10:55:58 -05:00
able 2dcd096de9 LIMINE: I think this updates the submodule? 2023-07-17 09:51:57 -05:00
able 9225d2d773 ARM: checkpoint from micro-tau 2023-07-17 09:36:39 -05:00
able ede52eb1db ARM: work done on getting the bootloader working 2023-07-17 00:36:06 -05:00
able 81e2603c4d Merge pull request 'x86_64: Refactor device info fetching' (#7) from JohnyTheCarrot/ableos:chore/refactor-device-info into master
Reviewed-on: https://git.ablecorp.us/AbleOS/ableos/pulls/7

LG2M
2023-07-15 13:05:33 +00:00
JohnyTheCarrot af7bcc8efb Merge remote-tracking branch 'origin/chore/refactor-device-info' into chore/refactor-device-info 2023-07-15 15:05:01 +02:00
JohnyTheCarrot f0be41ec49 make requested changes 2023-07-15 15:04:53 +02:00
JohnyTheCarrot c955f3a0de Merge branch 'master' into chore/refactor-device-info 2023-07-15 12:50:07 +00:00
JohnyTheCarrot 53fca04786 x86_64: Refactor device info fetching 2023-07-15 14:47:46 +02:00
able 4cf933c62b TODO: Add some more info 2023-07-15 06:16:00 -05:00
able 6c4eee0c56 SCHED: Two programs are now running in ableOS 2023-07-15 05:51:19 -05:00
able d3e019ffe1 ARM: Commit the sin of binarys into a git repo 2023-07-15 05:50:54 -05:00
able a8005728bf ARM: moved dep to proper location 2023-07-14 23:13:29 -05:00
able 80bfcb83b9 CLEAN: remove old data and set default target to x86 2023-07-14 20:30:47 -05:00
able 3a62f65cd1 ARM: Whoe knows 2023-07-14 20:00:50 -05:00
able d8a68aabee Merge branch 'master' of ssh://git.ablecorp.us:20/AbleOS/ableos 2023-07-14 19:38:46 -05:00
able 9bbc0e19a1 ARM: it compiles but does not yet run :V 2023-07-14 19:38:13 -05:00
able 490f15db48 Merge pull request 'another shrimple macro!' (#6) from IntoTheNight/ableos:master into master
Reviewed-on: https://git.ablecorp.us/AbleOS/ableos/pulls/6
2023-07-15 00:12:03 +00:00
able 4dd3699e0e frowny 2023-07-13 22:41:09 -05:00
IntoTheNight bea92d996c Merge branch 'master' into master 2023-07-13 14:25:20 +00:00
IntoTheNight 6a404b8227 another shrimple macro!
(NOTE: I was unable to test on my Nix system for some reason, QEMU just refuses to work even though I ran it within the Nix Shell environment)
2023-07-13 19:50:44 +05:30
able a9350952b7 SCHED: Set a sane TQ 2023-07-13 03:41:15 -05:00
able b9af2ae9c4 SCHEDULER: added in some super simple bootmodules and run them 2023-07-13 03:27:47 -05:00
Erin aa5ea3fb8f Auto-fetch OVMF 2023-07-13 03:21:33 +02:00
able 3b6dce674d SCHEDULER: add register dumps 2023-07-12 12:24:52 -05:00
able 2f24089938 SCHEDULER: cut out deadcode and added ifguard 2023-07-12 12:22:13 -05:00
able d1a6e627ef Increase the default heapsize 2023-07-12 12:21:31 -05:00
able 1455f1712c Merge pull request 'master' (#5) from IntoTheNight/ableos:master into master
Reviewed-on: https://git.ablecorp.us/AbleOS/ableos/pulls/5
2023-07-12 16:48:02 +00:00
able 473598d5df Merge branch 'master' into master 2023-07-12 16:47:55 +00:00
MunirG05 56ec28550f does this fix the issue?? 2023-07-12 22:16:14 +05:30
able a18ca4335f REPBUILD: Space 2023-07-12 11:27:42 -05:00
able de8661be62 COMMUNITY: Discord link update 2023-07-12 10:04:20 -05:00
able c264865d49 X86: cpuid changes 2023-07-12 09:01:58 -05:00
able 340d76fd13 CAPS: Changing the printing of caps 2023-07-12 06:03:29 -05:00
able b7da4f17c2 REPBUILD: default devices changed 2023-07-12 06:03:06 -05:00
MunirG05 2af7684532 fix the dumb 2023-07-11 13:32:40 +05:30
MunirG05 7a00dff4b9 fix the dumb 2023-07-11 13:30:45 +05:30
able ae321a9923 CAPS: Adding in capabilities 2023-07-10 22:54:05 -05:00
MunirG05 bb27f48f4a scheduler but i stole the code from the engine and tried to stuff it into the scheduler and i have no idea if it works or not but it porbably does 2023-07-10 23:43:42 +05:30
MunirG05 359d62c1b0 i pushed so i can work on it in windows thanks 2023-07-10 17:14:11 +05:30
able a2a2b509bb Merge pull request 'master' (#4) from IntoTheNight/ableos:master into master
Reviewed-on: https://git.ablecorp.us/AbleOS/ableos/pulls/4
2023-07-09 12:46:49 +00:00
IntoTheNight 4252719a72 another shrimple macro! 2023-07-09 17:18:41 +05:30
IntoTheNight 7ac33efcbc uauhfa 2023-07-09 16:37:13 +05:30
IntoTheNight 87c3d0bb3a add a shrimple macro
add a shrimple macro
2023-07-09 16:33:47 +05:30
IntoTheNight dc03601ac0 add a shrimple macro 2023-07-09 16:30:16 +05:30
able 8e8289f5ba BOOT: Work on boot modules 2023-07-08 23:22:44 -05:00
able c276476068 WORKSPACE: fix resolver 2023-07-08 23:22:13 -05:00
able e8d854a171 REPBUILD: Fix disk.img generation 2023-07-08 23:21:27 -05:00
able 06868b516f fix compile error 2023-06-26 18:42:55 -05:00
able 567871d18e Scheduler work 2023-06-26 07:55:37 -05:00
able 1dd330e604 Revert "prelim scheduler work"
This reverts commit 1be36455e4.
2023-06-26 07:54:48 -05:00
able 1be36455e4 prelim scheduler work 2023-06-26 07:54:37 -05:00
able 36f2a8336f most recent HBVM works 2023-06-26 06:36:30 -05:00
able 432af37737 TODO: init stuff 2023-06-25 22:34:24 -05:00
able 0508140f40 CLEANUP: turned if statement into match 2023-06-21 17:16:22 -05:00
able 65f1695b46 ROADMAP 2023-06-16 06:09:22 -05:00
able c2b8341667 FORMAT 2023-06-16 05:20:37 -05:00
able 1a98fe8908 CONFIG: adding in a spawn command 2023-06-15 03:45:27 -05:00
able d4670cb85d REPBUILD: Minor todo fix 2023-06-13 21:03:09 -05:00
able 16ccd51e4a cleanup and docs 2023-06-13 06:00:11 -05:00
able b9b798efff DOCS: adding in some docs in various spots and added a contrib guide 2023-05-28 04:51:51 -05:00
able 03667f6039 CPU: minor changes in cpuid 2023-05-28 02:04:20 -05:00
able 8eebd50179 ALLOCATOR: misc 2023-05-28 02:01:11 -05:00
able bb3c1b6120 CPU: Added more cpu feature detection 2023-05-28 02:00:54 -05:00
able b9bfd99335 GRAPHICS: Line thickness change for the HBVM logo 2023-05-26 06:31:52 -05:00
able 49105e668d LOGGING: Begin work on consistent logging style 2023-05-26 06:30:17 -05:00
able 40c072ad99 ROADMAP: Taking down notes on the order in which things should proceed with ableOS 2023-05-25 07:15:53 -05:00
able a2bf48f56b minor cleanups 2023-05-25 07:04:19 -05:00
able 5af29efe17 Remove warnings 2023-05-23 05:16:14 -05:00
able e513caf499 nix WORKS 2023-05-23 04:52:26 -05:00
able ad22051a20 Working on booting on nixOS 2023-05-23 04:26:32 -05:00
Able 2744e8e67b tack inplace hbvm 2023-05-15 02:19:34 -05:00
Able 282688d48b purge wasm 2023-05-08 04:42:02 -05:00
Able 88df7c2c34 remove interp and all wasm related code 2023-05-08 04:35:37 -05:00
Able 4a8b56a474 dynamically support display discovery 2023-05-08 03:53:15 -05:00
Able 308592cbf9 fix 2023-05-06 07:05:45 -05:00
Able fb0dcc786d ableos update 2023-05-06 06:50:24 -05:00
able e53d7896a7 Merge pull request 'Add some minimal instructions' (#3) from wildwestrom/ableos:master into master
Reviewed-on: https://git.ablecorp.us/AbleOS/ableos/pulls/3
2023-04-30 04:20:14 +00:00
Christian Westrom 6843023a44 add some minimal instructions 2023-04-30 13:19:03 +09:00
Able 174b621acd add an example system.toml 2023-04-26 14:33:40 -05:00
Able 01cdd68b28 cleanup + rustfmt config 2023-04-12 13:08:07 -05:00
Able ec7a80c93a Change 2023-04-10 01:16:30 -05:00
Able 530a8a9d60 changes 2023-04-07 16:44:33 -05:00
Able 20e3ce15be hacking in a wasm interpreter 2023-04-05 12:29:20 -05:00
Erin 0a77e691d7 boom! 2023-03-30 23:43:04 +02:00
Able d6e27bc1f4 add a pci device view on boot 2022-11-30 01:47:15 -06:00
Able 64a02bbf01 solid 2022-11-23 06:23:36 -06:00
Able 40c99b47b5 changing color parsing from \0 to \1a 2022-11-23 02:32:12 -06:00
Able 1f8ea529f9 fix echo command and add traces to vfs 2022-11-23 01:55:09 -06:00
Erin f396c3642d Skeleton for architecture-specific things 2022-11-07 21:21:16 +01:00
Erin 4812e59c09 Threw stuff from the microkernel. Start of moving core parts there. 2022-11-07 20:29:42 +01:00
Erin d31f17f07e clippy 2022-11-05 01:43:41 +01:00
Erin 4e6bed0b57 removed module that I forgot to remove + 1.65 stuff 2022-11-05 01:40:38 +01:00
Erin 56700a7986 removed sus messaging module 2022-11-05 00:39:37 +01:00
Erin b943714093 update 2022-10-29 19:53:08 +02:00
Erin 8ebaf1b244 fixed sound 2022-10-29 19:20:23 +02:00
Erin 84f163f534 merge 2022-08-28 22:04:55 +02:00
Erin 3b1e51d1ba fixed qr code 2022-08-21 11:45:28 +02:00
147 changed files with 8435 additions and 913 deletions

View file

@ -1,2 +1,3 @@
[alias]
repbuild = "run --manifest-path ./repbuild/Cargo.toml --"
repbuild = "run --manifest-path ./repbuild/Cargo.toml -r --"
dev = "run --manifest-path ./dev/Cargo.toml -r --"

View file

@ -1,4 +0,0 @@
set history save on
file target/x86_64-ableos/debug/ableos
target remote localhost:9000
tui enable

View file

@ -1,6 +1,5 @@
{
"files.associations": {
"stddef.h": "c"
},
"rust-analyzer.checkOnSave.allTargets": false
"rust-analyzer.checkOnSave.allTargets": false,
"rust-analyzer.showUnlinkedFileNotification": false,
"C_Cpp.errorSquiggles": "disabled"
}

1638
Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -1,2 +1,9 @@
[workspace]
members = ["kernel", "repbuild"]
resolver = "2"
members = ["dev", "kernel", "repbuild"]
# [profile.release]
# strip = "symbols"
# codegen-units = 1
# lto = true
# panic = "abort"

View file

@ -1,26 +1,24 @@
# ableOS
![Discord](https://img.shields.io/discord/831368967385120810) ![Code Size](https://img.shields.io/github/languages/code-size/abletheabove/ableos)
## Set up
Install [Qemu](https://www.qemu.org/)
# AbleOS
An UNIX-unlike micro-kernel written in rust with an embedded bytecode virtual machine.
> On Windows be sure to add `C:\Program Files\qemu` to your `PATH` variable
Please note that a custom target directory is not supported and support will not be added.
`rustup component add rust-src`
# Community
[Discord](https://discord.gg/JrKVukDtgs)
`rustup component add llvm-tools-preview`
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">
`cargo install bootimage`
# 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.
## Running
repbuild can be used to run and build docs for able os
## Steps
1. Ensure you have qemu installed
2. `git submodule update --init`
3. `cargo repbuild run`
`cargo repbuild doc`
`cargo repbuild run`
## Testing on real hardware
I recommend using an old x86_64 computer
* `cargo run --release` to generate a binary image that is bootable
* flash it to a USB device via `dd` or balenaEtcher
* Remove said USB device and plug into test machine
* assure test machine boots from USB devices
# Developing
There is a new work in progress developer tool for hblang.

View file

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

677
contrib/DriverDepGraph.svg Normal file
View file

@ -0,0 +1,677 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<!-- Generated by graphviz version 2.40.1 (20161225.0304)
-->
<!-- Title: Drivers Pages: 1 -->
<svg width="2629pt" height="404pt" viewBox="0.00 0.00 2628.89 404.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 400)">
<title>Drivers</title>
<polygon fill="#ffffff" stroke="transparent" points="-4,4 -4,-400 2624.8933,-400 2624.8933,4 -4,4"/>
<!-- InitSystem -->
<g id="node1" class="node">
<title>InitSystem</title>
<ellipse fill="none" stroke="#000000" cx="443.0953" cy="-378" rx="52.7642" ry="18"/>
<text text-anchor="middle" x="443.0953" y="-373.8" font-family="Times,serif" font-size="14.00" fill="#000000">InitSystem</text>
</g>
<!-- VFS -->
<g id="node2" class="node">
<title>VFS</title>
<ellipse fill="none" stroke="#000000" cx="409.0953" cy="-234" rx="28.991" ry="18"/>
<text text-anchor="middle" x="409.0953" y="-229.8" font-family="Times,serif" font-size="14.00" fill="#000000">VFS</text>
</g>
<!-- InitSystem&#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>

After

Width:  |  Height:  |  Size: 36 KiB

4
contrib/README.md Normal file
View file

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

32
contrib/TODO.md Normal file
View file

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

50
contrib/design.dot Normal file
View file

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

7
dev/Cargo.toml Normal file
View file

@ -0,0 +1,7 @@
[package]
name = "dev"
version = "0.1.0"
edition = "2021"
[dependencies]
logos = "0.14.1"

6
dev/README.md Normal file
View file

@ -0,0 +1,6 @@
# dev
`dev` is an ableOS specific tool meant to help the development of ableOS.
At the current stage changes are not welcome. If you have feature suggestions ping me on discord `@abletheabove`.
Run `cargo dev help` to see usage.

84
dev/src/idl/mod.rs Normal file
View file

@ -0,0 +1,84 @@
pub mod protocol;
use std::io::Read;
use {
logos::{Lexer, Logos},
protocol::Protocol,
};
#[derive(Logos, Debug, PartialEq, Clone)]
#[logos(skip r"[ \t\n\f]+")] // Ignore this regex pattern between tokens
enum Token {
// Tokens can be literal strings, of any length.
#[token("protocol")]
Protocol,
#[token("{")]
LBrace,
#[token("}")]
RBrace,
#[token("(")]
LParen,
#[token(")")]
RParen,
#[token(":")]
Colon,
#[token(";")]
SemiColon,
#[token(",")]
Comma,
#[token("=")]
Equal,
#[token("->")]
RArrow,
#[regex("[a-zA-Z_]+", |lex|{lex.slice().to_string()})]
Text(String),
#[regex("[1234567890]+", |lex|{lex.slice().parse::<u64>().unwrap()})]
Number(u64),
#[regex(r"@[a-zA-Z_]+", |lex|{lex.slice().to_string()})]
Decorator(String),
#[regex(r#"@[a-zA-Z_]+\([a-zA-Z,0-9=]+\)"#, |lex|{lex.slice().to_string()})]
DecoratorOption(String),
}
pub fn build_idl(name: String) {
let contents = open_protocol(name);
let lex = Token::lexer(&contents);
let mut tokens = vec![];
for x in lex {
match x {
Ok(token) => {
println!("{:?}", token);
tokens.push(token);
}
Err(err) => println!("{:?}", err),
}
}
build(tokens);
}
fn build(a: Vec<Token>) {
for toke in a {
println!("{:?}", toke);
}
}
fn open_protocol(name: String) -> String {
let path = format!("sysdata/idl/{}/src/protocol.aidl", name);
let mut file = std::fs::File::open(path).unwrap();
let mut contents = String::new();
file.read_to_string(&mut contents).unwrap();
contents
}

17
dev/src/idl/protocol.rs Normal file
View file

@ -0,0 +1,17 @@
pub enum ProtocolTypes {
Byte,
}
pub struct Protocol {}
impl Protocol {
pub fn is_empty(&self) -> bool {
true
}
pub fn validate_data(&self, data: Vec<u8>) -> bool {
if !data.is_empty() && self.is_empty() {
return false;
}
true
}
}

131
dev/src/main.rs Normal file
View file

@ -0,0 +1,131 @@
use std::io::Write;
use idl::build_idl;
pub mod idl;
pub enum Options {
Build,
Clean,
New,
Run,
}
#[derive(PartialEq, Debug)]
pub enum DevelopmentType {
Program,
Library,
IDL,
}
fn main() {
let mut args: Vec<String> = std::env::args().collect();
args.remove(0);
args.reverse();
let binding = args.pop().unwrap_or("help".to_string());
let subcommand = binding.as_str();
match subcommand {
"build" => {
let name = &args.pop().unwrap();
build(name.to_string())
}
"new" => {
let binding = args.pop().unwrap();
let dev_type = binding.as_str();
let name = args.pop().unwrap();
use DevelopmentType::*;
match dev_type {
"lib" | "library" => new(Library, name),
"prog" | "program" => new(Program, name),
"idl" => {
new(IDL, name);
// idl::main();
panic!("IDL is not finalized yet.")
}
_ => {}
};
}
"run" => run(),
"help" => help(),
_ => {
println!("Error");
}
}
}
pub fn new(development_type: DevelopmentType, name: String) {
let (folder_hierarchy, entry_name) = match development_type {
DevelopmentType::Program => ("programs", "main.hb"),
DevelopmentType::Library => ("libraries", "lib.hb"),
DevelopmentType::IDL => ("idl", "protocol.aidl"),
};
let project_folder_path_string = format!("sysdata/{folder_hierarchy}/{name}");
if std::path::Path::new(&project_folder_path_string).exists() {
panic!("Project already exists.")
}
std::fs::create_dir(project_folder_path_string.clone()).unwrap();
let readme_path_string = format!("{}/README.md", project_folder_path_string);
let mut readme_file = std::fs::File::create(readme_path_string.clone()).unwrap();
let readme_contents = format!("# {}", name);
readme_file.write_all(readme_contents.as_bytes()).unwrap();
let src_folder_path_string = format!("{}/src", project_folder_path_string);
std::fs::create_dir(src_folder_path_string.clone()).unwrap();
let full_path_string = format!("{src_folder_path_string}/{entry_name}");
let mut file = std::fs::File::create(full_path_string.clone()).unwrap();
let file_contents = match development_type {
DevelopmentType::Program => "main := fn(): int {
return 0
}"
.to_string(),
DevelopmentType::Library => "".to_string(),
DevelopmentType::IDL => format!(
"protocol {} {{
}}",
name
)
.to_owned(),
}
.to_string();
file.write_all(file_contents.as_bytes()).unwrap();
println!("New project created.");
if development_type == DevelopmentType::Program {
println!("You should add your project into the ableOS system configuration in sysdata/system_config.toml")
}
}
fn run() {
println!("Running is not supported on a non-ableOS platform");
}
fn build(name: String) {
println!("building {}", name);
let mut a = name.split("/");
let dev_type = a.next().unwrap();
let name = a.next().unwrap().to_string();
match dev_type {
"programs" => build_program(name),
"idl" => build_idl(name),
_ => {
panic!()
}
}
}
pub fn build_program(name: String) {}
pub fn build_library(name: String) {}
fn help() {
println!(
"==========
= Help =
==========
Subcommands
- new Usage: `cargo dev new library name` or `cargo dev new program name`"
)
}

View file

@ -3,22 +3,34 @@ edition = "2021"
name = "kernel"
version = "0.2.0"
[dependencies]
elfloader = "0.16"
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 }
versioning = { git = "https://git.ablecorp.us/able/aos_userland" }
embedded-graphics = "0.8"
hbvm.git = "https://git.ablecorp.us/ableos/holey-bytes.git"
log = "0.4"
spin = "0.9"
slab = { version = "0.4", default-features = false }
uart_16550 = { version = "0.3", features = ["nightly"] }
xml.git = "https://git.ablecorp.us/ableos/ableos_userland"
versioning.git = "https://git.ablecorp.us/ableos/ableos_userland"
# able_graphics_library.git = "https://git.ablecorp.us/ableos/ableos_userland"
hashbrown = { version = "0.14", features = ["nightly"] }
[dependencies.limine]
version = "0.1"
#git = "https://github.com/limine-bootloader/limine-rs"
[dependencies.crossbeam-queue]
version = "0.3"
default-features = false
features = ["alloc"]
features = ["alloc", "nightly"]
# [dependencies.clparse]
# git = "https://git.ablecorp.us/ableos/ableos_userland"
# default-features = false
[dependencies.derive_more]
version = "0.99"
version = "1"
default-features = false
features = [
"add",
@ -33,10 +45,14 @@ features = [
"sum",
]
[target.'cfg(target_arch = "x86_64")'.dependencies]
limine = { version = "0.1", git = "https://github.com/limine-bootloader/limine-rs" }
x86_64 = "0.14"
x86_64 = "0.15"
x2apic = "0.4"
virtio-drivers = "0.7"
[target.'cfg(target_arch = "riscv64")'.dependencies]
sbi = "0.2.0"
[target.'cfg(target_arch = "aarch64")'.dependencies]
aarch64-cpu = "9"

View file

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

View file

@ -0,0 +1,24 @@
ENTRY(_kernel_start)
SECTIONS
{
. = 0xffffffff80000000;
.text.boot : { *(.text.boot) }
.text : { *(.text) }
.data : { *(.data) }
.rodata : { *(.rodata) }
.bss : {
*(COMMON)
*(.bss .bss.*)
/* Align initial kernel heap to page boundary */
. = ALIGN(4K);
PROVIDE(_initial_kernel_heap_start = .);
/* PROVIDE(_initial_kernel_heap_size = 1024 * 1024); */
PROVIDE(_initial_kernel_heap_size = 1024 * 4096 * 100);
. += _initial_kernel_heap_size;
} :data
. = ALIGN(8);
. = . + 0x4000;
LD_STACK_PTR = .;
}

View file

@ -47,7 +47,8 @@ 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 * 1024); */
PROVIDE(_initial_kernel_heap_size = 1024 * 4096 * 100);
. += _initial_kernel_heap_size;
} :data
}

View file

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

View file

@ -0,0 +1,51 @@
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;
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(),
// the source of this one was checking the cpu id :thinking:
0x410FD493 => "Neoverse N2".to_string(),
_ => "Unknown".to_string(),
};
log::trace!("CPU Name: {cpu_name} - CPU ID: 0x{:X}", cpu_id);
(cpu_name, cpu_id)
}

View file

@ -0,0 +1,28 @@
use {crate::logger::TERMINAL_LOGGER, core::fmt::Write, spin::Mutex};
pub static SERIAL_CONSOLE: Mutex<SerialConsole> = Mutex::new(SerialConsole {
uart: 0x09000000 as *mut u8,
});
struct SerialConsole {
uart: *mut u8,
}
impl core::fmt::Write for SerialConsole {
fn write_str(&mut self, s: &str) -> core::fmt::Result {
for c in s.chars() {
unsafe { *self.uart = c as u8 }
}
Ok(())
}
}
unsafe impl Sync for SerialConsole {}
unsafe impl Send for SerialConsole {}
pub fn log(args: core::fmt::Arguments<'_>) -> core::fmt::Result {
SERIAL_CONSOLE.lock().write_fmt(args)?;
TERMINAL_LOGGER.lock().write_fmt(args)?;
Ok(())
}

View file

@ -1 +1,123 @@
//!
pub use logging::log;
use {
crate::{allocator, bootmodules::BootModule, kmain::kmain},
alloc::vec::Vec,
core::arch::asm,
limine::FramebufferRequest,
};
mod device_info_collector;
use device_info_collector::collect_device_info;
pub mod logging;
use limine::HhdmRequest;
extern "C" {
fn _initial_kernel_heap_start();
fn _initial_kernel_heap_size();
}
const INITIAL_KERNEL_HEAP_START: *mut u8 = _initial_kernel_heap_start as _;
const INITIAL_KERNEL_HEAP_SIZE: *const () = _initial_kernel_heap_size as _;
pub const PAGE_SIZE: usize = 4096;
static FB_REQ: FramebufferRequest = FramebufferRequest::new(0);
#[no_mangle]
unsafe extern "C" fn _kernel_start() -> ! {
crate::logger::init().expect("failed to set logger");
log::info!("Initialising AKern {}", crate::VERSION);
static HDHM_REQ: HhdmRequest = HhdmRequest::new(0);
// memory::init_pt(VirtAddr::new(
// HDHM_REQ
// .get_response()
// .get()
// .expect("tried to get physical memory mapping offset from Limine")
// .offset,
// ));
allocator::init(INITIAL_KERNEL_HEAP_START, INITIAL_KERNEL_HEAP_SIZE as _);
collect_device_info();
let bm = MOD_REQ.get_response().get();
use limine::{KernelFileRequest, ModuleRequest};
static KFILE_REQ: KernelFileRequest = KernelFileRequest::new(0);
static MOD_REQ: ModuleRequest = ModuleRequest::new(0);
let mut bootmodules = Vec::new();
if bm.is_some() {
let bm = bm.unwrap();
for x in 0..bm.module_count {
let file = bm.modules().get(x as usize);
if file.is_some() {
let file = file.unwrap();
let raw_bytes = core::slice::from_raw_parts(
file.base.as_ptr().expect("invalid initrd"),
file.length as usize,
);
let file_path = file.path.to_str().unwrap().to_str();
if file_path.is_err() {
panic!("invalid file path: {:?}", file_path);
}
let file_cmd = file.cmdline.to_str().unwrap().to_str();
if file_cmd.is_err() {
panic!("invalid module cmd: {:?}", file_cmd);
}
log::trace!("module path: {:?}", file_path);
log::trace!("module cmd: {:?}", file_cmd);
bootmodules.push(BootModule::new(
file_path.unwrap(),
raw_bytes,
file_cmd.unwrap(),
));
} else {
log::error!("You should not be here");
break;
}
}
log::info!("Boot module count: {:?}", bootmodules.len());
assert_eq!(bm.module_count, bootmodules.len() as u64);
}
kmain(
KFILE_REQ
.get_response()
.get()
.and_then(|r| r.kernel_file.get())
.expect("failed to get kernel file from Limine")
.cmdline
.to_str()
.map(core::ffi::CStr::to_str)
.transpose()
.expect("expected valid cmdline string")
.unwrap_or_default(),
bootmodules,
);
}
pub fn spin_loop() -> ! {
loop {
unsafe { asm!("wfi") }
}
}
/// I am sorry.
static mut A_REAL_RANDOM_U64_I_PROMISE: u64 = 0;
pub fn hardware_random_u64() -> u64 {
if let Some(rng) = aarch64_cpu::asm::random::ArmRng::new() {
if let Some(rnd) = rng.rndr() {
return rnd;
}
}
unsafe {
A_REAL_RANDOM_U64_I_PROMISE += 1;
A_REAL_RANDOM_U64_I_PROMISE
}
}
pub fn register_dump() {}
#[no_mangle]
pub fn fmod() {}

View file

@ -1,8 +1,10 @@
use core::num;
use alloc::boxed::Box;
use spin::{Mutex, Once};
use crate::memory::{MemoryManager, PhysicalAddress, VirtualAddress};
use {
crate::memory::{MemoryManager, PhysicalAddress, VirtualAddress},
alloc::boxed::Box,
spin::{Mutex, Once},
};
use super::PAGE_SIZE;
@ -28,7 +30,7 @@ impl PageSize {
}
pub struct PageTable {
entries: [PageEntry; 512]
entries: [PageEntry; 512],
}
impl PageTable {
@ -72,8 +74,14 @@ impl PageTable {
/// flags MUST include one or more of the following:
/// Read, Write, Execute
/// The valid bit automatically gets added
pub fn map(&mut self, vaddr: VirtualAddress, paddr: PhysicalAddress, flags: PageEntryFlags, page_size: PageSize) {
assert!(flags as usize & 0xe != 0);
pub fn map(
&mut self,
vaddr: VirtualAddress,
paddr: PhysicalAddress,
flags: PageEntryFlags,
page_size: PageSize,
) {
assert!(flags as usize & 0xE != 0);
let vpn = vaddr.vpns();
let ppn = paddr.ppns();
@ -91,7 +99,7 @@ impl PageTable {
}
let entry = v.addr().as_mut_ptr::<PageEntry>();
v = unsafe { entry.add(vpn[i]).as_mut().unwrap() };
v = unsafe { entry.add(vpn[i]).as_mut().unwrap() };
}
// When we get here, we should be at VPN[0] and v should be pointing to our entry.
@ -105,14 +113,24 @@ impl PageTable {
}
/// Identity maps a page of memory
pub fn identity_map(&mut self, addr: PhysicalAddress, flags: PageEntryFlags, page_size: PageSize) {
pub fn identity_map(
&mut self,
addr: PhysicalAddress,
flags: PageEntryFlags,
page_size: PageSize,
) {
// log::debug!("identity mapped {addr}");
self.map(addr.as_addr().into(), addr, flags, page_size);
}
/// Identity maps a range of contiguous memory
/// This assumes that start <= end
pub fn identity_map_range(&mut self, start: PhysicalAddress, end: PhysicalAddress, flags: PageEntryFlags) {
pub fn identity_map_range(
&mut self,
start: PhysicalAddress,
end: PhysicalAddress,
flags: PageEntryFlags,
) {
log::debug!("start: {start}, end: {end}");
let mut mem_addr = start.as_addr() & !(PAGE_SIZE - 1);
let num_pages = (align_val(end.as_addr(), 12) - mem_addr - 1) / PAGE_SIZE + 1;
@ -142,7 +160,7 @@ impl PageTable {
}
let entry = v.addr().as_mut_ptr::<PageEntry>();
v = unsafe { entry.add(vpn[i]).as_mut().unwrap() };
v = unsafe { entry.add(vpn[i]).as_mut().unwrap() };
}
// If we're here this is an unmapped page
@ -182,7 +200,7 @@ pub enum PageEntryFlags {
Global = 1 << 5,
Access = 1 << 6,
Dirty = 1 << 7,
// for convenience
ReadWrite = Self::Read as usize | Self::Write as usize,
ReadExecute = Self::Read as usize | Self::Execute as usize,
@ -228,7 +246,7 @@ impl PageEntry {
}
fn addr(&self) -> PhysicalAddress {
((self.entry() as usize & !0x3ff) << 2).into()
((self.entry() as usize & !0x3FF) << 2).into()
}
fn destroy(&mut self) {

View file

@ -1,50 +1,62 @@
mod memory;
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 {
alloc::{boxed::Box, vec::Vec},
core::{
arch::{asm, global_asm},
fmt::Write,
},
sbi::system_reset::{system_reset, ResetReason, ResetType},
spin::{Mutex, Once},
uart_16550::MmioSerialPort,
};
use crate::{allocator, memory::PhysicalAddress, arch::riscv64::memory::{PAGE_TABLE, PageEntryFlags, PageSize, PageTable}};
use crate::{
allocator,
arch::riscv64::memory::{PageEntryFlags, PageSize, PageTable, PAGE_TABLE},
memory::PhysicalAddress,
};
global_asm!(include_str!("entry.s"));
global_asm!(include_str!("memory_regions.s"));
pub const PAGE_SIZE: usize = 4096;
extern {
extern "C" {
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;
}
static SERIAL_CONSOLE: Once<Mutex<MmioSerialPort>> = Once::new();
pub static SERIAL_CONSOLE: Once<Mutex<MmioSerialPort>> = Once::new();
#[no_mangle]
unsafe extern fn _kernel_start() -> ! {
unsafe extern "C" 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();
@ -61,9 +73,17 @@ unsafe extern 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;
@ -75,16 +95,22 @@ unsafe extern fn _kernel_start() -> ! {
in(reg) satp_value,
);
crate::kmain::kmain("baka=9", None);
crate::kmain::kmain("baka=9", Vec::new());
}
/// Spin loop
pub fn sloop() -> ! {
pub fn spin_loop() -> ! {
loop {
unsafe { asm!("wfi") }
}
}
pub fn hardware_random_u64() -> u64 {
0
}
pub fn register_dump() {}
pub fn log(args: core::fmt::Arguments<'_>) -> core::fmt::Result {
SERIAL_CONSOLE.get().unwrap().lock().write_fmt(args)
}

View file

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

View file

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

View file

@ -1,76 +1,58 @@
use spin::Lazy;
use x86_64::{
structures::{
gdt::{Descriptor, GlobalDescriptorTable, SegmentSelector},
tss::TaskStateSegment,
use {
spin::Lazy,
x86_64::{
structures::{
gdt::{Descriptor, GlobalDescriptorTable, SegmentSelector},
tss::TaskStateSegment,
},
VirtAddr,
},
VirtAddr,
};
pub const DOUBLE_FAULT_IX: u16 = 0;
pub unsafe fn init() {
use x86_64::instructions::segmentation::{Segment, CS, DS, ES, SS};
use x86_64::instructions::tables::load_tss;
const STACK_SIZE: usize = 5 * 1024;
const STACK_ALIGNMENT: usize = 1;
log::info!("Initialising GDT");
pub unsafe fn init() {
use x86_64::instructions::{
segmentation::{Segment, CS, SS},
tables::load_tss,
};
log::trace!("Initialising GDT");
GDT.0.load();
CS::set_reg(GDT.1.kcode);
DS::set_reg(GDT.1.kdata);
ES::set_reg(GDT.1.kdata);
SS::set_reg(GDT.1.kdata);
load_tss(GDT.1.tss);
init_syscalls(&GDT.1);
}
struct Selectors {
kcode: SegmentSelector,
kdata: SegmentSelector,
tss: SegmentSelector,
udata: SegmentSelector,
ucode: SegmentSelector,
tss: SegmentSelector,
}
static TSS: Lazy<TaskStateSegment> = Lazy::new(|| {
let mut tss = TaskStateSegment::new();
tss.interrupt_stack_table[usize::from(DOUBLE_FAULT_IX)] = {
const SIZE: usize = 5 * 1024;
let stack = unsafe {
alloc::alloc::alloc_zeroed(
alloc::alloc::Layout::from_size_align(SIZE, 1).expect("stack pointer"),
)
};
VirtAddr::from_ptr(stack) + SIZE
let stack_ptr = unsafe {
let layout = alloc::alloc::Layout::from_size_align(STACK_SIZE, STACK_ALIGNMENT)
.expect("Failed to create stack layout");
let stack = alloc::alloc::alloc(layout);
VirtAddr::from_ptr(stack) + STACK_SIZE as u64
};
tss.interrupt_stack_table[usize::from(DOUBLE_FAULT_IX)] = stack_ptr;
tss
});
static GDT: Lazy<(GlobalDescriptorTable, Selectors)> = Lazy::new(|| {
let mut gdt = GlobalDescriptorTable::new();
let sels = Selectors {
kcode: gdt.add_entry(Descriptor::kernel_code_segment()),
kdata: gdt.add_entry(Descriptor::kernel_data_segment()),
tss: gdt.add_entry(Descriptor::tss_segment(&TSS)),
udata: gdt.add_entry(Descriptor::user_data_segment()),
ucode: gdt.add_entry(Descriptor::user_code_segment()),
kcode: gdt.append(Descriptor::kernel_code_segment()),
kdata: gdt.append(Descriptor::kernel_data_segment()),
tss: gdt.append(Descriptor::tss_segment(&TSS)),
};
(gdt, sels)
});
/// Initialize syscalls
unsafe fn init_syscalls(sls: &Selectors) {
use x86_64::registers::{
model_specific::{Efer, EferFlags, LStar, SFMask, Star},
rflags::RFlags,
};
Star::write(sls.ucode, sls.udata, sls.kcode, sls.kdata);
SFMask::write(RFlags::from_bits(0x200).expect("Invalid RFlags for SFMask"));
LStar::write(VirtAddr::from_ptr(handle_syscall as *const ()));
Efer::update(|x| *x |= EferFlags::SYSTEM_CALL_EXTENSIONS);
}
extern "C" fn handle_syscall(a: u64) -> ! {
log::info!("called syscall {a}");
todo!("Return from syscall");
}

View file

@ -0,0 +1 @@

View file

@ -1,13 +1,14 @@
use spin::{Lazy, Mutex};
use x2apic::lapic::{LocalApic, LocalApicBuilder};
use x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame, PageFaultErrorCode};
use {
core::mem::MaybeUninit,
log::trace,
x2apic::lapic::{LocalApic, LocalApicBuilder},
x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame, PageFaultErrorCode},
};
pub unsafe fn init() {
log::info!("Initialising IDT");
IDT.load();
Lazy::force(&LAPIC);
x86_64::instructions::interrupts::enable();
}
/// Safety: Using LAPIC or IDT before init() is UB
/// Using
static mut LAPIC: LocalApic = unsafe { MaybeUninit::zeroed().assume_init() };
static mut IDT: InterruptDescriptorTable = unsafe { MaybeUninit::zeroed().assume_init() };
#[repr(u8)]
enum Interrupt {
@ -16,32 +17,36 @@ enum Interrupt {
Spurious = u8::MAX,
}
static LAPIC: Lazy<Mutex<LocalApic>> = Lazy::new(|| {
let mut lapic = LocalApicBuilder::new()
pub unsafe fn init() {
trace!("Initializing IDT and LAPIC");
// Initialize and load the IDT
IDT = InterruptDescriptorTable::new();
IDT.double_fault
.set_handler_fn(double_fault)
.set_stack_index(super::gdt::DOUBLE_FAULT_IX);
IDT.page_fault.set_handler_fn(page_fault);
IDT[Interrupt::ApicErr as u8].set_handler_fn(apic_err);
IDT[Interrupt::Spurious as u8].set_handler_fn(spurious);
IDT[Interrupt::Timer as u8].set_handler_fn(timer);
IDT.load();
LAPIC = LocalApicBuilder::new()
.timer_vector(Interrupt::Timer as usize)
.error_vector(Interrupt::ApicErr as usize)
.spurious_vector(Interrupt::Spurious as usize)
.set_xapic_base(
unsafe { x2apic::lapic::xapic_base() }
x2apic::lapic::xapic_base()
+ super::memory::HHDM_OFFSET.load(core::sync::atomic::Ordering::Relaxed),
)
.build()
.expect("failed to setup Local APIC");
unsafe { lapic.enable() };
Mutex::new(lapic)
});
.expect("Failed to setup Local APIC");
LAPIC.enable();
static IDT: Lazy<InterruptDescriptorTable> = Lazy::new(|| {
let mut idt = InterruptDescriptorTable::new();
unsafe {
idt.double_fault
.set_handler_fn(double_fault)
.set_stack_index(super::gdt::DOUBLE_FAULT_IX);
}
idt.page_fault.set_handler_fn(page_fault);
idt[Interrupt::Timer as usize].set_handler_fn(timer);
idt
});
x86_64::instructions::interrupts::enable();
}
extern "x86-interrupt" fn double_fault(stack_frame: InterruptStackFrame, error_code: u64) -> ! {
panic!("Double fault: error code {error_code} \n{stack_frame:#?}")
@ -54,8 +59,10 @@ extern "x86-interrupt" fn page_fault(
panic!("Page fault ({error_code:?}): {stack_frame:?}")
}
extern "x86-interrupt" fn timer(_: InterruptStackFrame) {
unsafe { LAPIC.lock().end_of_interrupt() };
extern "x86-interrupt" fn timer(_isf: InterruptStackFrame) {
unsafe {
LAPIC.end_of_interrupt();
}
}
extern "x86-interrupt" fn apic_err(_: InterruptStackFrame) {
@ -63,5 +70,7 @@ extern "x86-interrupt" fn apic_err(_: InterruptStackFrame) {
}
extern "x86-interrupt" fn spurious(_: InterruptStackFrame) {
unsafe { LAPIC.lock().end_of_interrupt() };
unsafe {
LAPIC.end_of_interrupt();
}
}

View file

@ -1,46 +1,17 @@
//! Logging (as in terms of console / serial output)
#![allow(deprecated)]
use {core::fmt::Write, spin::Mutex, uart_16550::SerialPort};
use core::fmt::Write;
use limine::{LimineTerminalRequest, LimineTerminalResponse};
use spin::{Lazy, Mutex};
use uart_16550::SerialPort;
static SERIAL_CONSOLE: Mutex<SerialPort> = Mutex::new(unsafe { SerialPort::new(0x3f8) });
static TERMINAL_LOGGER: Lazy<Mutex<TermLogger>> = Lazy::new(|| Mutex::new(TermLogger::new()));
pub static SERIAL_CONSOLE: Mutex<SerialPort> = Mutex::new(unsafe { SerialPort::new(0x3F8) });
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 LimineTerminalResponse);
unsafe impl Send for TermLogger {}
impl TermLogger {
pub fn new() -> Self {
static TERM_REQ: LimineTerminalRequest = LimineTerminalRequest::new(0);
Self(
TERM_REQ
.get_response()
.get()
.expect("failed to get terminal response"),
)
}
}
impl Write for TermLogger {
fn write_str(&mut self, s: &str) -> core::fmt::Result {
if let (Some(w), ts) = (self.0.write(), self.0.terminals()) {
for term in ts {
w(term, s);
}
}
Ok(())
}
}

View file

@ -1,8 +1,10 @@
use core::sync::atomic::AtomicU64;
use limine::{LimineMemmapEntry, LimineMemoryMapEntryType, NonNullPtr};
use spin::{Mutex, Once};
use x86_64::{structures::paging::OffsetPageTable, VirtAddr};
use crate::memory::{MemoryManager, MAX_ORDER};
use {
crate::memory::{MemoryManager, MAX_ORDER},
core::sync::atomic::AtomicU64,
limine::{MemmapEntry, MemoryMapEntryType, NonNullPtr},
spin::{Mutex, Once},
x86_64::{structures::paging::OffsetPageTable, VirtAddr},
};
pub const PAGE_SIZE: usize = 4096;
@ -12,7 +14,7 @@ static PAGE_TABLE: Once<Mutex<OffsetPageTable>> = Once::new();
/// Initialise page table
pub unsafe fn init_pt(phys_base: VirtAddr) {
log::info!("Retrieving page table");
log::debug!("Retrieving page table");
HHDM_OFFSET.store(phys_base.as_u64(), core::sync::atomic::Ordering::Relaxed);
PAGE_TABLE.call_once(|| {
Mutex::new(OffsetPageTable::new(
@ -28,11 +30,11 @@ pub unsafe fn init_pt(phys_base: VirtAddr) {
}
/// Initialise memory manager
pub fn initialize(mmap: &'static [NonNullPtr<LimineMemmapEntry>]) {
pub fn initialize(mmap: &'static [NonNullPtr<MemmapEntry>]) {
let mut memory_manager = MemoryManager::new();
for entry in mmap {
if entry.typ != LimineMemoryMapEntryType::Usable {
if entry.typ != MemoryMapEntryType::Usable {
continue;
}

View file

@ -1,17 +1,24 @@
use core::arch::x86_64::{_rdrand64_step, _rdseed64_step};
use {crate::bootmodules::BootModule, core::arch::asm, log::warn};
pub mod memory;
mod cpuid;
mod device_info_collector;
mod gdt;
mod interrupts;
mod logging;
pub mod graphics;
pub(crate) mod interrupts;
pub mod logging;
pub mod pci;
pub mod virtio;
pub use logging::log;
pub use memory::PAGE_SIZE;
pub use {logging::log, memory::PAGE_SIZE};
use crate::allocator;
use memory::MEMORY_MANAGER;
use limine::{
LimineHhdmRequest, LimineKernelFileRequest, LimineMemmapRequest, LimineModuleRequest,
use {
crate::allocator,
limine::{HhdmRequest, KernelFileRequest, MemmapRequest, ModuleRequest},
x86_64::VirtAddr,
};
use x86_64::VirtAddr;
extern "C" {
fn _initial_kernel_heap_start();
@ -22,12 +29,29 @@ 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);
static HDHM_REQ: LimineHhdmRequest = LimineHhdmRequest::new(0);
static HDHM_REQ: HhdmRequest = HhdmRequest::new(0);
memory::init_pt(VirtAddr::new(
HDHM_REQ
.get_response()
@ -35,10 +59,9 @@ unsafe extern "C" fn _kernel_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: LimineMemmapRequest = LimineMemmapRequest::new(0);
static MMAP_REQ: MemmapRequest = MemmapRequest::new(0);
memory::initialize(
MMAP_REQ
.get_response()
@ -50,24 +73,103 @@ unsafe extern "C" fn _kernel_start() -> ! {
gdt::init();
interrupts::init();
{
let mut mm = MEMORY_MANAGER.get().unwrap().lock();
let alloc_0 = mm.allocate_pages(0).unwrap();
log::debug!("Addr: {alloc_0}");
let alloc_1 = mm.allocate_pages(0).unwrap();
log::debug!("Addr: {alloc_1}");
mm.deallocate_pages(alloc_0, 0);
let alloc_2 = mm.allocate_pages(1).unwrap();
log::debug!("Addr: {alloc_2}");
mm.deallocate_pages(alloc_1, 0);
mm.deallocate_pages(alloc_2, 1);
let alloc_3 = mm.allocate_pages(1).unwrap();
log::debug!("Addr: {alloc_3}");
mm.deallocate_pages(alloc_3, 1);
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,
);
let file_path = file.path.to_str().unwrap().to_str();
if file_path.is_err() {
panic!("invalid file path: {:?}", file_path);
}
let file_cmd = file.cmdline.to_str().unwrap().to_str();
if file_cmd.is_err() {
panic!("invalid module cmd: {:?}", file_cmd);
}
log::trace!("module path: {:?}", file_path);
log::trace!("module cmd: {:?}", file_cmd);
bootmodules.push(BootModule::new(
file_path.unwrap(),
raw_bytes,
file_cmd.unwrap(),
));
} else {
log::error!("You should not be here");
break;
}
}
log::info!("Boot module count: {:?}", bootmodules.len());
assert_eq!(bm.module_count, bootmodules.len() as u64);
}
static KFILE_REQ: LimineKernelFileRequest = LimineKernelFileRequest::new(0);
static MOD_REQ: LimineModuleRequest = LimineModuleRequest::new(0);
crate::kmain::kmain(
KFILE_REQ
.get_response()
@ -80,22 +182,99 @@ unsafe extern "C" fn _kernel_start() -> ! {
.transpose()
.expect("expected valid cmdline string")
.unwrap_or_default(),
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,
)
}),
bootmodules,
)
}
/// Spin loop
pub fn sloop() -> ! {
pub fn spin_loop() -> ! {
loop {
x86_64::instructions::hlt();
x86_64::instructions::hlt()
}
}
pub fn hardware_random_u64() -> u64 {
let mut out: u64 = 0;
match unsafe { _rdrand64_step(&mut out) } {
1 => out,
_ => {
warn!("RDRand not supported.");
// Try rdseed
match unsafe { _rdseed64_step(&mut out) } {
1 => out,
_ => panic!("Neither RDRand or RDSeed are supported"),
}
}
}
}
pub fn get_edid() {}
#[allow(unused)]
pub fn register_dump() {
let rax: u64;
let rbx: u64 = 0;
let rcx: u64;
let rdx: u64;
let si: u64;
let di: u64;
let r8: u64; // TODO: r8-r15
let r9: u64;
let r10: u64;
let r11: u64;
let r12: u64;
let r13: u64;
let r14: u64;
let r15: u64;
unsafe {
asm!("",
out("rax") rax,
out("rcx") rcx,
out("rdx") rdx,
out("si") si,
out("di") di,
out("r8") r8,
out("r9") r9,
out("r10") r10,
out("r11") r11,
out("r12") r12,
out("r13") r13,
out("r14") r14,
out("r15") r15,
)
};
log::error!(
"Kernel Panic!\r
Register Dump\r
rax: {:#x}\r
rbx: {:#x}\r
rcx: {:#x}\r
rdx: {:#x}\r
si : {:#x}\r
di : {:#x}\r
r8 : {:#x}\r
r9 : {:#x}\r
r11: {:#x}\r
r12: {:#x}\r
r13: {:#x}\r
r14: {:#x}\r
r15: {:#x}\r
",
rax,
rbx,
rcx,
rdx,
si,
di,
r8,
r9,
r11,
r12,
r13,
r14,
r15,
);
}

View file

@ -0,0 +1,502 @@
#[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) {
(VMWareInc, 1029) => ("GPUs", "SVGAII PCI GPU"),
(Qemu, 4369) => ("GPUs", "QEMU VGA"),
(VirtIO, 4176) => ("GPUs", "VirtIO PCI GPU"),
(CirrusLogic, 184) => ("GPUs", "Cirrus SVGA"), //GD 5446?
(_, _) => ("Unidentified PCI", "UNKNOWN DEVICE"),
};
// let (dev_type, dev_name) = match device_info.full_class {
// PciFullClass::Unclassified_NonVgaCompatible => todo!(),
// PciFullClass::Unclassified_VgaCompatible => todo!(),
// PciFullClass::Display_VGA => ("GPUs", "VGA Device"),
// PciFullClass::Display_XGA => ("GPUs", "XGA Device"),
// PciFullClass::Display_3D => ("GPUs", "3D Device"),
// PciFullClass::Display_Other => ("GPUs", "Other"),
// _ => ("Unidentified PCI", "UNKNOWN DEVICE"),
// };
let mut dev = xml::XMLElement::new(dev_name);
let mut pci_info = xml::XMLElement::new("PCI Info");
pci_info.set_attribute("id", id);
pci_info.set_attribute("device", device_info.device);
pci_info.set_attribute("vendor", vendor);
pci_info.set_attribute("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 {crate::device_tree::DeviceTree, x86_64::instructions::port::Port};
#[allow(non_camel_case_types, dead_code)]
#[derive(Debug, Clone, Copy, PartialEq)]
#[repr(C)]
/// Class specification for a PCI device
pub enum PciClass {
Unclassified = 0x00,
MassStorage = 0x01,
Network = 0x02,
Display = 0x03,
Multimedia = 0x04,
Memory = 0x05,
Bridge = 0x06,
Unknown = 0xFF,
}
impl From<u8> for PciClass {
/// Convert a u8 into the corresponding PciClass
fn from(n: u8) -> Self {
use PciClass::*;
match n {
0x00 => Unclassified,
0x01 => MassStorage,
0x02 => Network,
0x03 => Display,
0x04 => Multimedia,
0x05 => Memory,
0x06 => Bridge,
_ => Unknown,
}
}
}
#[allow(non_camel_case_types, dead_code)]
#[derive(Debug, Clone, Copy, PartialEq)]
#[repr(C)]
/// Full class specification (type and subtype) for a PCI device.
///
/// Uses non-camel-case types for readability.
pub enum PciFullClass {
Unclassified_NonVgaCompatible = 0x0000,
Unclassified_VgaCompatible = 0x0001,
MassStorage_ScsiBus = 0x0100,
MassStorage_IDE = 0x0101,
MassStorage_Floppy = 0x0102,
MassStorage_IpiBus = 0x0103,
MassStorage_RAID = 0x0104,
MassStorage_ATA = 0x0105,
MassStorage_SATA = 0x0106,
MassStorage_SerialSCSI = 0x0107,
MassStorage_NVM = 0x0108,
MassStorage_Other = 0x0180,
Network_Ethernet = 0x0200,
Network_TokenRing = 0x0201,
Network_FDDI = 0x0202,
Network_ATM = 0x0203,
Network_ISDN = 0x0204,
Network_WorldFlip = 0x0205,
Network_PICMG = 0x0206,
Network_Infiniband = 0x0207,
Network_Fabric = 0x0208,
Network_Other = 0x0280,
Display_VGA = 0x0300,
Display_XGA = 0x0301,
Display_3D = 0x0302,
Display_Other = 0x0380,
Multimedia_Video = 0x0400,
Multimedia_AudioController = 0x0401,
Multimedia_Telephony = 0x0402,
Multimedia_AudioDevice = 0x0403,
Multimedia_Other = 0x0480,
Memory_RAM = 0x0500,
Memory_Flash = 0x0501,
Memory_Other = 0x0580,
Bridge_Host = 0x0600,
Bridge_ISA = 0x0601,
Bridge_EISA = 0x0602,
Bridge_MCA = 0x0603,
Bridge_PciToPci = 0x0604,
Bridge_PCMCIA = 0x0605,
Bridge_NuBus = 0x0606,
Bridge_CardBus = 0x0607,
Bridge_RACEway = 0x0608,
Bridge_PciToPciSemiTransparent = 0x0609,
Bridge_InfinibandToPci = 0x060A,
Bridge_Other = 0x0680,
Unknown = 0xFFFF,
}
impl PciFullClass {
// listen, i know this sucks, but i didn't want to include
// `num`, `num-traits` and `num-derive` as dependencies for
// this crate just for a convenience function
/// Convert a u16 into the corresponding PciFullClass
pub fn from_u16(n: u16) -> PciFullClass {
match n {
0x0000 => PciFullClass::Unclassified_NonVgaCompatible,
0x0001 => PciFullClass::Unclassified_VgaCompatible,
0x0100 => PciFullClass::MassStorage_ScsiBus,
0x0101 => PciFullClass::MassStorage_IDE,
0x0102 => PciFullClass::MassStorage_Floppy,
0x0103 => PciFullClass::MassStorage_IpiBus,
0x0104 => PciFullClass::MassStorage_RAID,
0x0105 => PciFullClass::MassStorage_ATA,
0x0106 => PciFullClass::MassStorage_SATA,
0x0107 => PciFullClass::MassStorage_SerialSCSI,
0x0108 => PciFullClass::MassStorage_NVM,
0x0180 => PciFullClass::MassStorage_Other,
0x0200 => PciFullClass::Network_Ethernet,
0x0201 => PciFullClass::Network_TokenRing,
0x0202 => PciFullClass::Network_FDDI,
0x0203 => PciFullClass::Network_ATM,
0x0204 => PciFullClass::Network_ISDN,
0x0205 => PciFullClass::Network_WorldFlip,
0x0206 => PciFullClass::Network_PICMG,
0x0207 => PciFullClass::Network_Infiniband,
0x0208 => PciFullClass::Network_Fabric,
0x0280 => PciFullClass::Network_Other,
0x0300 => PciFullClass::Display_VGA,
0x0301 => PciFullClass::Display_XGA,
0x0302 => PciFullClass::Display_3D,
0x0380 => PciFullClass::Display_Other,
0x0400 => PciFullClass::Multimedia_Video,
0x0401 => PciFullClass::Multimedia_AudioController,
0x0402 => PciFullClass::Multimedia_Telephony,
0x0403 => PciFullClass::Multimedia_AudioDevice,
0x0480 => PciFullClass::Multimedia_Other,
0x0500 => PciFullClass::Memory_RAM,
0x0501 => PciFullClass::Memory_Flash,
0x0580 => PciFullClass::Memory_Other,
0x0600 => PciFullClass::Bridge_Host,
0x0601 => PciFullClass::Bridge_ISA,
0x0602 => PciFullClass::Bridge_EISA,
0x0603 => PciFullClass::Bridge_MCA,
0x0604 => PciFullClass::Bridge_PciToPci,
0x0605 => PciFullClass::Bridge_PCMCIA,
0x0606 => PciFullClass::Bridge_NuBus,
0x0607 => PciFullClass::Bridge_CardBus,
0x0608 => PciFullClass::Bridge_RACEway,
0x0609 => PciFullClass::Bridge_PciToPciSemiTransparent,
0x060A => PciFullClass::Bridge_InfinibandToPci,
0x0680 => PciFullClass::Bridge_Other,
_ => PciFullClass::Unknown,
}
}
/// Convert a PciFullClass to its u16 representation
pub fn as_u16(&self) -> u16 {
*self as u16
}
}
impl From<u16> for PciFullClass {
/// Convert a u16 into the corresponding PciFullClass
fn from(n: u16) -> Self {
Self::from_u16(n)
}
}
impl Display for PciFullClass {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "{:?} ({:#06X})", self, self.as_u16())?;
Ok(())
}
}
unsafe fn pci_config_read(bus: u8, device: u8, func: u8, offset: u8) -> u32 {
let bus = bus as u32;
let device = device as u32;
let func = func as u32;
let offset = offset as u32;
// construct address param
let address =
((bus << 16) | (device << 11) | (func << 8) | (offset & 0xFC) | 0x8000_0000) 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

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

36
kernel/src/bootmodules.rs Normal file
View file

@ -0,0 +1,36 @@
use {
// crate::alloc::string::ToString,
alloc::vec::Vec,
// clparse::Arguments,
// core::fmt::{Debug, Display},
// log::trace,
// xml::XMLElement,
};
pub type BootModules<'a> = Vec<BootModule<'a>>;
pub struct BootModule<'a> {
pub path: &'a str,
pub bytes: &'a [u8],
pub cmd: &'a str,
}
impl<'a> BootModule<'a> {
pub fn new(path: &'a str, bytes: &'a [u8], cmd: &'a str) -> Self {
Self { path, bytes, cmd }
}
}
// pub fn build_cmd<T: Display + Debug>(name: T, cmdline: T) -> XMLElement {
// let mut cmdline = cmdline.to_string();
// cmdline.pop();
// cmdline.remove(0);
// let cmd = Arguments::parse(cmdline.to_string()).unwrap();
// trace!("Cmdline: {cmd:?}");
// let mut clo = XMLElement::new(name);
// for (key, value) in cmd.arguments {
// clo.set_attribute(key, value);
// }
// trace!("command line object: {:?}", clo);
// clo
// }

186
kernel/src/capabilities.rs Normal file
View file

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

View file

@ -0,0 +1,76 @@
//! 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::{device_tree, tab, utils::TAB};
impl fmt::Display for DeviceTree {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
writeln!(f)?;
for (device_type, devices) in &self.devices {
writeln!(f, "\r{}{}/\r", tab!(1), device_type)?;
for device in devices {
writeln!(f, "{}{}/\r", tab!(2), device.name)?;
for attr in &device.attributes {
writeln!(f, "{}{}\r", tab!(3), attr)?;
}
for child in &device.children {
writeln!(f, "{}{}\r", tab!(3), child.name)?;
for attr in &child.attributes {
writeln!(f, "{}{}\r", tab!(4), attr)?;
}
for child in &child.children {
writeln!(f, "{}{}\r", tab!(4), child.name)?;
for attr in &child.attributes {
writeln!(f, "{}{}\r", tab!(5), attr)?;
}
}
}
}
}
Ok(())
}
}

66
kernel/src/handle.rs Normal file
View file

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

View file

@ -0,0 +1,240 @@
//! Environment call handling routines
use crate::holeybytes::kernel_services::{
block_read, dt_msg_handler::dt_msg_handler, logging_service::log_msg_handler,
service_definition_service::sds_msg_handler,
};
use {
super::Vm,
crate::{arch, ipc::buffer::IpcBuffer, kmain::IPC_BUFFERS},
log::{debug, error, info, trace},
};
pub fn handler(vm: &mut Vm) {
let ecall_number = vm.registers[2].cast::<u64>();
// log::info!("eca called :pensive:");
// debug!("Ecall number {:?}", ecall_number);
//info!("Register dump: {:?}", vm.registers);
match ecall_number {
0 => {
// TODO: explode computer
// hello world ecall
for x in 0u64..=255 {
vm.registers[x as usize] = x.into();
}
}
1 => {
// Make buffer
let bounded = match vm.registers[3].cast::<u64>() {
0 => false,
1 => true,
_ => {
panic!("Bad");
}
};
let length = vm.registers[4].cast::<u64>();
let mut buffs = IPC_BUFFERS.lock();
let abc;
match bounded {
false => {
abc = IpcBuffer::new(false, 0);
}
true => {
abc = IpcBuffer::new(true, length);
}
};
let buff_id = arch::hardware_random_u64();
buffs.insert(buff_id, abc);
info!("Buffer ID: {}", buff_id);
vm.registers[1] = hbvm::value::Value(buff_id);
}
2 => {
// Delete buffer
}
3 => {
// Send a message to a buffer
let buffer_id = vm.registers[3].cast::<u64>();
let mem_addr = vm.registers[4].cast::<u64>();
let length = vm.registers[5].cast::<u64>() as usize;
trace!("IPC address: {:?}", mem_addr);
use alloc::vec::Vec;
match buffer_id {
0 => match sds_msg_handler(vm, mem_addr, length) {
Ok(()) => {}
Err(err) => log::error!("Improper sds format: {err:?}"),
},
1 => match log_msg_handler(vm, mem_addr, length) {
Ok(()) => {}
Err(_) => log::error!("Improper log format"),
},
2 => {
use crate::holeybytes::kernel_services::mem_serve::memory_msg_handler;
match memory_msg_handler(vm, mem_addr, length) {
Ok(_) => {}
Err(_) => {}
}
}
#[cfg(not(target_arch = "x86_64"))]
3 => info!("TODO: implement whatever buffer 3 does for no x86_64"),
#[cfg(target_arch = "x86_64")]
3 => {
unsafe fn x86_out<T: x86_64::instructions::port::PortWrite>(
address: u16,
value: T,
) {
x86_64::instructions::port::Port::new(address).write(value);
}
unsafe fn x86_in<T: x86_64::instructions::port::PortRead>(address: u16) -> T {
x86_64::instructions::port::Port::new(address).read()
}
let msg_vec = block_read(mem_addr, length);
let msg_type = msg_vec[0];
match msg_type {
0 => unsafe {
let size = msg_vec[1];
let addr = u16::from_le_bytes(msg_vec[2..4].try_into().unwrap());
let value = match size {
0 => x86_in::<u8>(addr) as u64,
1 => x86_in::<u16>(addr) as u64,
2 => x86_in::<u32>(addr) as u64,
_ => panic!("Trying to read size other than: 8, 16, 32 from port."),
};
// info!("Read the value {} from address {}", value, addr);
vm.registers[1] = hbvm::value::Value(value);
},
1 => unsafe {
let size = msg_vec[1];
let addr = u16::from_le_bytes(msg_vec[2..4].try_into().unwrap());
trace!("Setting address {}", addr);
match size {
0 => x86_out(addr, msg_vec[4]),
1 => x86_out(
addr,
u16::from_le_bytes(msg_vec[4..6].try_into().unwrap_unchecked()),
),
2 => x86_out(
addr,
u32::from_le_bytes(msg_vec[4..8].try_into().unwrap_unchecked()),
),
_ => panic!("How?"),
}
},
_ => {}
}
}
#[cfg(not(target_arch = "x86_64"))]
3 => unimplemented!("TODO: implement whatever buffer 3 does for no x86_64"),
// source of rng
4 => {
// limit to last 32 bits
vm.registers[1] =
hbvm::value::Value(crate::arch::hardware_random_u64() & 0xFFFFFFFF);
}
5 => match dt_msg_handler(vm, mem_addr, length) {
Ok(()) => {}
Err(_) => log::error!("Improper dt query"),
},
buffer_id => {
let mut buffs = IPC_BUFFERS.lock();
match buffs.get_mut(&buffer_id) {
Some(buff) => {
let mut msg_vec = Vec::with_capacity(length);
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);
}
debug!(
"Message {:?} has been sent to Buffer({})",
msg_vec, buffer_id
);
buff.push(msg_vec);
}
None => {
log::error!("Access of non-existent buffer {}", buffer_id)
}
}
drop(buffs);
}
}
}
4 => {
let buffer_id = vm.registers[3].cast::<u64>();
let mut map_ptr = vm.registers[4].cast::<u64>();
let max_length = vm.registers[5].cast::<u64>();
let mut buffs = IPC_BUFFERS.lock();
let buff: &mut IpcBuffer;
if buffs.get_mut(&buffer_id).is_some() {
buff = buffs.get_mut(&buffer_id).unwrap();
} else {
// info!("AHHH");
vm.registers[1] = hbvm::value::Value(0);
return;
}
let pop = buff.pop();
if pop.is_err() {
return;
}
let msg = pop.unwrap();
if msg.len() > max_length.try_into().unwrap() {
info!("{}", max_length);
error!("Message is too long to map in.");
} else {
unsafe {
let ptr: *mut u64 = &mut map_ptr;
for (index, byte) in msg.iter().enumerate() {
ptr.offset(index.try_into().unwrap()).write_bytes(*byte, 1);
}
}
debug!("Recieve {:?} from Buffer({})", msg, buffer_id);
}
}
5 => {
#[cfg(target_arch = "x86_64")]
{
let r2 = vm.registers[2].cast::<u64>();
unsafe fn x86_in(address: u16) -> u32 {
x86_64::instructions::port::Port::new(address).read()
}
unsafe fn x86_out(address: u16, value: u32) {
x86_64::instructions::port::Port::new(address).write(value);
}
let x = hbvm::value::Value(unsafe { x86_in(r2 as u16) } as u64);
info!("Read {:?} from Port {:?}", x, r2);
vm.registers[3] = x
}
}
_ => {
log::error!("Syscall unknown {:?}{:?}", ecall_number, vm.registers);
}
}
}
#[derive(Debug)]
pub enum LogError {
NoMessages,
InvalidLogFormat,
}
// use {alloc::vec, log::Record};
// fn memory_msg_handler(vm: &mut Vm, mem_addr: u64, length: usize) -> Result<(), LogError> {
// let mut val = alloc::vec::Vec::new();
// for _ in 0..4096 {
// val.push(0);
// }
// info!("Block address: {:?}", val.as_ptr());
// vm.registers[1] = hbvm::value::Value(val.as_ptr() as u64);
// vm.registers[2] = hbvm::value::Value(4096);
// Ok(())
// }

View file

@ -0,0 +1,87 @@
use {
crate::holeybytes::{kernel_services::block_read, Vm},
alloc::{
string::{String, ToString},
vec::Vec,
},
};
pub enum DtError {
QueryFailure,
}
pub fn dt_msg_handler(vm: &mut Vm, mem_addr: u64, length: usize) -> Result<(), DtError> {
let msg_vec = block_read(mem_addr, length);
let mut bytes: Vec<u8> = Vec::new();
for byte in msg_vec {
if *byte == 0 {
break;
}
bytes.push(*byte)
}
let query_string = String::from_utf8(bytes).unwrap();
log::trace!("Query {}", query_string);
let ret = query_parse(query_string);
log::trace!("Query response {}", ret);
vm.registers[1] = hbvm::value::Value(ret);
Ok(())
}
fn query_parse(query_string: String) -> u64 {
let qt_parse_step_one = query_string.split("/");
let mut qt_parse_step_two: Vec<String> = Vec::new();
for a in qt_parse_step_one {
qt_parse_step_two.push(a.to_string());
}
let first_fragment: &str = &qt_parse_step_two[0];
let ret = match first_fragment {
"framebuffer" => framebuffer_parse(qt_parse_step_two),
"cpu" => cpu_parse(qt_parse_step_two),
_ => 0,
};
return ret;
}
fn cpu_parse(qt_parse_step_two: Vec<String>) -> u64 {
let second_fragment: &str = &qt_parse_step_two[1];
match second_fragment {
// "architecture" => {
// return 0;
// }
_ => {
return 0;
}
};
}
fn framebuffer_parse(qt_parse_step_two: Vec<String>) -> u64 {
use crate::kmain::FB_REQ;
let fbs = &FB_REQ.get_response().get().unwrap().framebuffers();
let second_fragment: &str = &qt_parse_step_two[1];
match second_fragment {
"fb0" => {
let fb_front = &fbs[0];
let third_fragment: &str = &qt_parse_step_two[2];
let ret = match third_fragment {
"ptr" => {
let ptr = fb_front.address.as_ptr().unwrap();
ptr as usize as u64
}
"width" => fb_front.width,
"height" => fb_front.height,
_ => 0,
};
return ret;
}
_ => {
return 0;
}
};
}

View file

@ -0,0 +1,49 @@
use crate::holeybytes::{kernel_services::block_read, Vm};
#[derive(Debug)]
pub enum LogError {
InvalidLogFormat,
}
use log::Record;
pub fn log_msg_handler(_vm: &mut Vm, mem_addr: u64, length: usize) -> Result<(), LogError> {
let msg_vec = block_read(mem_addr, length);
let log_level = msg_vec.last().unwrap();
let file_name = "None";
let line_number = 0;
match core::str::from_utf8(&msg_vec[..msg_vec.len()]) {
Ok(strr) => {
use log::Level::*;
let log_level = match log_level {
0 | 48 => Error,
1 | 49 => Warn,
2 | 50 => Info,
3 | 51 => Debug,
4 | 52 => Trace,
_ => {
return Err(LogError::InvalidLogFormat);
}
};
log::logger().log(
&Record::builder()
.args(format_args!("{}", strr))
.level(log_level)
.target("Userspace")
.file(Some(file_name))
.line(Some(line_number))
.module_path(Some(&file_name))
.build(),
);
}
Err(e) => {
log::error!("{:?}", e);
}
}
Ok(())
}

View file

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

View file

@ -0,0 +1,95 @@
use {
crate::holeybytes::{kernel_services::block_read, Vm},
alloc::alloc::{alloc, dealloc},
core::alloc::Layout,
log::{debug, info},
};
pub enum MemoryServiceError {
InvalidMemoryFormat,
}
#[derive(Debug)]
pub enum MemoryQuotaType {
NoQuota = 0,
SoftQuota = 1,
HardQuota = 2,
KillQuota = 3,
}
fn alloc_page(vm: &mut Vm, _mem_addr: u64, _length: usize) -> Result<(), MemoryServiceError> {
let ptr = unsafe { alloc(Layout::from_size_align_unchecked(4096, 4096)) };
info!("Block address: {:?}", ptr);
vm.registers[1] = hbvm::value::Value(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 msg_vec = block_read(mem_addr, length);
let msg_type = msg_vec[0];
match msg_type {
0 => {
let page_count = msg_vec[1];
let mptr_raw: [u8; 8] = msg_vec[2..10].try_into().unwrap();
let mptr: u64 = u64::from_le_bytes(mptr_raw);
log::debug!("Allocating {} pages @ {:x}", page_count, mptr);
let ptr = unsafe {
alloc(Layout::from_size_align_unchecked(
page_count as usize * 4096,
4096,
))
};
vm.registers[1] = hbvm::value::Value(ptr as u64);
log::debug!("Kernel ptr: {:x}", ptr as u64);
}
1 => {
let page_count = msg_vec[1];
let mptr_raw: [u8; 8] = msg_vec[2..10].try_into().unwrap();
let mptr: u64 = u64::from_le_bytes(mptr_raw);
log::debug!("Deallocating {} pages @ {:x}", page_count, mptr);
unsafe {
dealloc(
mptr as *mut u8,
Layout::from_size_align_unchecked(page_count as usize * 4096, 4096),
)
}
}
2 => {
use MemoryQuotaType::*;
let quota_type = match msg_vec[0] {
0 => NoQuota,
1 => SoftQuota,
2 => HardQuota,
3 => KillQuota,
_ => NoQuota,
};
let hid_raw: [u8; 8] = msg_vec[2..10].try_into().unwrap();
let hid: u64 = u64::from_le_bytes(hid_raw);
let pid_raw: [u8; 8] = msg_vec[10..18].try_into().unwrap();
let pid: u64 = u64::from_le_bytes(pid_raw);
debug!(
"Setting HID-{:x}:PID-{:x}'s quota type to {:?}",
hid, pid, quota_type
)
}
3 => {
let page_count = msg_vec[0];
log::debug!(" {} pages", page_count);
}
_ => {
log::debug!("Unknown memory service message type: {}", msg_type);
}
}
Ok(())
}

View file

@ -0,0 +1,11 @@
use core::slice;
pub mod dt_msg_handler;
pub mod logging_service;
pub mod mem_serve;
pub mod service_definition_service;
#[inline(always)]
pub fn block_read<'a>(mem_addr: u64, length: usize) -> &'a mut [u8] {
unsafe { slice::from_raw_parts_mut(mem_addr as *mut _, length) }
}

View file

@ -0,0 +1,109 @@
use {
crate::{
arch::hardware_random_u64,
holeybytes::{kernel_services::block_read, Vm},
ipc::{buffer::IpcBuffer, protocol::Protocol},
kmain::IPC_BUFFERS,
},
hashbrown::HashMap,
log::{info, trace},
spin::{lazy::Lazy, Mutex},
};
pub struct Services<'a>(HashMap<u64, Protocol<'a>>);
pub static SERVICES: Lazy<Mutex<Services>> = Lazy::new(|| {
let mut dt = Services(HashMap::new());
dt.0.insert(0, Protocol::void());
Mutex::new(dt)
});
#[derive(Debug)]
pub enum ServiceError {
InvalidFormat,
}
pub fn sds_msg_handler(vm: &mut Vm, mem_addr: u64, length: usize) -> Result<(), ServiceError> {
let msg_vec = block_read(mem_addr, length);
let sds_event_type: ServiceEventType = msg_vec[0].into();
// info!("Length {}", msg_vec.len());
use ServiceEventType::*;
match sds_event_type {
CreateService => {
let string =
core::str::from_utf8(&msg_vec[1..]).expect("Our bytes should be valid utf8");
let ret = sds_create_service(string);
vm.registers[1] = hbvm::value::Value(ret as u64);
}
DeleteService => todo!(),
SearchServices => {
let string =
core::str::from_utf8(&msg_vec[1..]).expect("Our bytes should be valid utf8");
let ret = sds_search_service(string);
vm.registers[1] = hbvm::value::Value(ret as u64);
}
}
// let buffer_id_raw = &msg_vec[0..8];
// let mut arr = [0u8; 8];
// arr.copy_from_slice(&buffer_id_raw);
// let buffer_id = u64::from_le_bytes(arr);
// info!("BufferID({:x?})", buffer_id);
// let mut services = SERVICES.lock();
// let string = String::from_utf8(msg_vec).expect("Our bytes should be valid utf8");
// use core::borrow::BorrowMut;
// services.borrow_mut().0.insert(buffer_id, string);
Ok(())
}
enum ServiceEventType {
CreateService = 0,
// UpdateService = 1,
DeleteService = 2,
SearchServices = 3,
}
impl From<u8> for ServiceEventType {
fn from(value: u8) -> Self {
use self::*;
match value {
0 => Self::CreateService,
// 1 =>
2 => Self::DeleteService,
3 => Self::SearchServices,
10 => {
info!("TEST");
panic!()
}
1_u8 | 4_u8..=u8::MAX => todo!(),
}
}
}
fn sds_create_service(protocol: &'static str) -> u64 {
let buff_id = hardware_random_u64();
let mut services = SERVICES.lock();
let mut buffers = IPC_BUFFERS.lock();
let protocol_ = Protocol::from(protocol);
let mut buff = IpcBuffer::new(false, 0);
services.0.insert(buff_id, protocol_.clone());
buff.protocol = protocol_;
buffers.insert(buff_id, buff);
trace!("BufferID({}) => {}", buff_id, protocol);
// let a: protocol::Protocol = protocol.into();
buff_id
}
fn sds_search_service(protocol: &str) -> u64 {
let services = SERVICES.lock();
let compare = Protocol::from(protocol);
for (bid, protocol_canidate) in &services.0 {
trace!("BID-{bid} protocol_canidate {:?}", protocol_canidate);
if protocol_canidate == &compare {
trace!("BufferID({}) => {}", bid, protocol);
return *bid;
}
}
0
}

View file

@ -0,0 +1,60 @@
//! Security? Multiple address spaces? What are you talking about
//! young adventurer. In this temple, we know no such words.
//!
//! Want your program to override other program's data or even the
//! data of the kernel itself? Sure. This right shall not be infringed.
use hbvm::mem::Address;
fn calc_start_of_page(ptr: u64) -> u64 {
let _page_aligned = false;
if ptr % 4096 == 0 {
// page_aligned = true;
return ptr / 4096;
}
panic!("unaligned");
}
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> {
if addr.get() % 4096 == 0 {}
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()
}
}

View file

@ -0,0 +1,106 @@
mod ecah;
mod kernel_services;
mod mem;
use {
alloc::alloc::{alloc, dealloc},
core::{
alloc::Layout,
future::Future,
pin::Pin,
task::{Context, Poll},
},
hbvm::{
mem::{softpaging::HandlePageFault, Address},
VmRunError, VmRunOk,
},
log::error,
};
const STACK_SIZE: usize = 1024 * 1024;
const TIMER_QUOTIENT: usize = 1000;
type Vm = hbvm::Vm<mem::Memory, TIMER_QUOTIENT>;
pub struct ExecThread {
vm: Vm,
stack_bottom: *mut u8,
}
unsafe impl Send for ExecThread {}
impl ExecThread {
pub fn set_arguments(&mut self, ptr: u64, length: u64) {
self.vm.registers[1] = hbvm::value::Value(ptr);
self.vm.registers[2] = hbvm::value::Value(length);
}
pub unsafe fn new(program: &[u8], entrypoint: Address) -> Self {
let mut vm = Vm::new(
mem::Memory {},
Address::new(program.as_ptr() as u64 + entrypoint.get()),
);
let stack_bottom = allocate_stack();
vm.write_reg(254, (stack_bottom as usize + STACK_SIZE - 1) as u64);
ExecThread { vm, stack_bottom }
}
}
impl<'p> Drop for ExecThread {
fn drop(&mut self) {
unsafe { dealloc(self.stack_bottom, stack_layout()) };
}
}
impl<'p> Future for ExecThread {
type Output = Result<(), VmRunError>;
#[inline(always)]
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
match self.vm.run() {
Err(err) => {
log::error!("HBVM Error\r\nRegister dump: {:?}", self.vm.registers,);
return Poll::Ready(Err(err));
}
Ok(VmRunOk::End) => return Poll::Ready(Ok(())),
Ok(VmRunOk::Ecall) => ecah::handler(&mut self.vm),
Ok(VmRunOk::Timer) => (),
Ok(VmRunOk::Breakpoint) => {
log::error!(
"HBVM Debug breakpoint\r\nRegister dump: {:?}",
self.vm.registers,
);
}
}
cx.waker().wake_by_ref();
Poll::Pending
}
}
struct PageFaultHandler;
impl HandlePageFault for PageFaultHandler {
fn page_fault(
&mut self,
reason: hbvm::mem::MemoryAccessReason,
_pagetable: &mut hbvm::mem::softpaging::paging::PageTable,
vaddr: hbvm::mem::Address,
size: hbvm::mem::softpaging::PageSize,
dataptr: *mut u8,
) -> bool {
error!("REASON: {reason} vaddr: {vaddr} size: {size:?} Dataptr {dataptr:p}");
false
}
}
#[inline(always)]
const fn stack_layout() -> Layout {
unsafe { Layout::from_size_align_unchecked(STACK_SIZE, 4096) }
}
#[inline(always)]
fn allocate_stack() -> *mut u8 {
unsafe { alloc(stack_layout()) }
}

74
kernel/src/ipc/buffer.rs Normal file
View file

@ -0,0 +1,74 @@
//!
use {
super::{message::Message, protocol::Protocol},
crossbeam_queue::{ArrayQueue, SegQueue},
};
pub enum BufferTypes {
Unbound(SegQueue<Message>),
Bound(ArrayQueue<Message>),
}
/// Interproccess buffer
pub struct IpcBuffer<'a> {
pub protocol: Protocol<'a>,
pub buffer: BufferTypes,
}
impl<'a> IpcBuffer<'a> {
pub fn new(bounded: bool, length: u64) -> Self {
log::debug!(
"New IPCBuffer\r
bounded: {}\r
length: {:?}\r",
bounded,
length
);
match (bounded, length) {
(false, ..) => {
let buftype = BufferTypes::Unbound(SegQueue::new());
Self {
protocol: Protocol::void(),
buffer: buftype,
}
}
(true, length) => {
let buftype = BufferTypes::Bound(ArrayQueue::new(length as usize));
Self {
protocol: Protocol::void(),
buffer: buftype,
}
}
}
}
/// Validate a message to match the `IPC.protocol`
pub fn validate_messages(&mut self) -> Result<(), IpcError> {
Ok(())
}
pub fn push(&mut self, msg: Message) {
match &self.buffer {
BufferTypes::Unbound(buff) => buff.push(msg),
BufferTypes::Bound(buff) => {
let _ = buff.push(msg);
}
};
}
pub fn pop(&mut self) -> Result<Message, IpcError> {
let msg = match &self.buffer {
BufferTypes::Unbound(buff) => buff.pop(),
BufferTypes::Bound(buff) => buff.pop(),
};
match msg {
Some(msg) => return Ok(msg),
None => return Err(IpcError::NoMessagesInBuffer),
}
}
}
/// Interprocess Communication Errors
#[derive(Debug)]
pub enum IpcError {
/// An invalid message error returned to the sender
InvalidMessage,
NoMessagesInBuffer,
}

View file

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

4
kernel/src/ipc/mod.rs Normal file
View file

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

View file

@ -0,0 +1,39 @@
use {
alloc::{string::String, vec::Vec},
hashbrown::HashMap,
};
#[derive(Debug, PartialEq, Clone)]
pub struct Type {}
#[derive(Debug, PartialEq, Clone)]
pub struct Funct {
takes: Vec<String>,
gives: Vec<String>,
}
#[derive(Debug, PartialEq, Clone)]
pub struct Protocol<'a> {
types: HashMap<&'a str, Type>,
fns: HashMap<&'a str, Funct>,
}
impl<'a> Protocol<'a> {
pub fn void() -> Self {
Self {
types: HashMap::new(),
fns: HashMap::new(),
}
}
// Check if a protocol defines all types it needs too
fn validate_protocol() -> bool {
false
}
}
impl<'a> From<&'a str> for Protocol<'a> {
fn from(value: &'a str) -> Self {
let mut hm_t = HashMap::new();
hm_t.insert(value, Type {});
Self {
types: hm_t,
fns: HashMap::new(),
}
}
}

View file

@ -1,15 +1,119 @@
//! AbleOS Kernel Entrypoint
pub fn kmain(cmdline: &str, bootstrap: Option<&'static [u8]>) -> ! {
log::debug!("Entered kmain");
use {
crate::{
arch::hardware_random_u64,
bootmodules::BootModules,
//bootmodules::build_cmd,
device_tree::DeviceTree,
holeybytes::ExecThread,
ipc::buffer::IpcBuffer,
},
hashbrown::HashMap,
hbvm::mem::Address,
limine::{Framebuffer, FramebufferRequest, NonNullPtr},
log::{debug, trace},
spin::{Lazy, Mutex},
};
// TODO: Actual cmdline parsing (Serde?)
if cmdline.contains("baka=9") {
let _ = crate::arch::log(format_args!(include_str!("../data/⑨. バカ")));
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
debug!("Device Tree: {}", dt);
trace!("Boot complete. Moving to init_system");
// TODO: schedule the disk driver from the initramfs
// TODO: schedule the filesystem driver from the initramfs
// TODO: Schedule the VFS from initramfs
// TODO: schedule the init system from the initramfs
drop(dt);
let fb1: &NonNullPtr<Framebuffer> = &FB_REQ.get_response().get().unwrap().framebuffers()[0];
{
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]);
}
debug!("Graphics initialised");
debug!(
"Graphics front ptr {:?}",
fb1.address.as_ptr().unwrap() as *const u8
);
log::info!("Cmdline: \"{cmdline}\"");
let bootstrap = bootstrap.expect("no bootstrap found");
let mut executor = crate::task::Executor::new(256);
unsafe {
for module in boot_modules.iter() {
let cmd = module.cmd.trim_matches('"');
let cmd_len = cmd.len() as u64;
crate::arch::sloop()
log::info!("Spawning {} with arguments \"{}\"", module.path, cmd);
let mut thr = ExecThread::new(&module.bytes, Address::new(0));
if cmd_len > 0 {
thr.set_arguments(cmd.as_ptr() as u64, cmd_len);
}
executor.spawn(async move {
if let Err(e) = thr.await {
log::error!("{e:?}");
}
})
}
debug!("Random number: {}", 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);
pub type IpcBuffers<'a> = HashMap<u64, IpcBuffer<'a>>;
pub static IPC_BUFFERS: Lazy<Mutex<IpcBuffers>> = Lazy::new(|| {
let mut bufs = HashMap::new();
let log_buffer = IpcBuffer::new(false, 0);
let file_buffer = IpcBuffer::new(false, 0);
bufs.insert(1, log_buffer);
bufs.insert(2, file_buffer);
Mutex::new(bufs)
});
#[test_case]
fn trivial_assertion() {
trace!("trivial assertion... ");
assert_eq!(1, 1);
info!("[ok]");
}

View file

@ -1,25 +1,35 @@
//! 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(
exclusive_wrapper,
new_uninit,
abi_x86_interrupt,
alloc_error_handler,
inline_const,
panic_info_message,
pointer_is_aligned,
prelude_import,
ptr_sub_ptr
ptr_sub_ptr,
custom_test_frameworks,
naked_functions,
pointer_is_aligned_to
)]
#![no_std]
#![test_runner(crate::test_runner)]
#![cfg_attr(not(debug_assertions), allow(unused, deprecated))]
#![allow(dead_code)]
extern crate alloc;
mod allocator;
mod arch;
mod bootmodules;
mod capabilities;
mod device_tree;
mod handle;
mod holeybytes;
mod ipc;
mod kmain;
mod logger;
mod memory;
mod task;
mod ubloader;
mod utils;
use versioning::Version;
@ -31,7 +41,10 @@ pub const VERSION: Version = Version {
};
#[panic_handler]
#[cfg(target_os = "none")]
fn panic(info: &core::panic::PanicInfo) -> ! {
arch::register_dump();
if let Some(loc) = info.location() {
let _ = crate::arch::log(format_args!(
"Location: {}: {}, {}\r\n",
@ -41,9 +54,15 @@ fn panic(info: &core::panic::PanicInfo) -> ! {
));
}
if let Some(msg) = info.message() {
let _ = crate::arch::log(format_args!("{msg}\r\n"));
}
let msg = info.message();
let _ = crate::arch::log(format_args!("{msg}\r\n"));
loop {}
}
#[cfg(test)]
fn test_runner(tests: &[&dyn Fn()]) {
println!("Running {} tests", tests.len());
for test in tests {
test();
}
}

View file

@ -1,29 +1,45 @@
use log::{Level, SetLoggerError};
#![allow(deprecated)]
// TODO: Add a logger api with logger levels and various outputs
pub static TERMINAL_LOGGER: Lazy<Mutex<TermLogger>> = Lazy::new(|| Mutex::new(TermLogger::new()));
use {
limine::{TerminalRequest, TerminalResponse},
log::{Level, SetLoggerError},
spin::{lazy::Lazy, mutex::Mutex},
};
pub fn init() -> Result<(), SetLoggerError> {
log::set_logger(&crate::logger::Logger)?;
log::set_max_level(log::LevelFilter::Trace);
if cfg!(debug_assertions) {
log::set_max_level(log::LevelFilter::Debug);
} else {
log::set_max_level(log::LevelFilter::Info);
}
Lazy::force(&TERMINAL_LOGGER);
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;{}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(),
"\x1b[38;5;{lvl_color}m{lvl}\x1b[0m [{module}:{line}]: {}\r\n",
record.args(),
))
.expect("write to serial console");
@ -31,3 +47,28 @@ 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(())
}
}

View file

@ -1,7 +1,6 @@
//! The Memory Manager
use alloc::collections::VecDeque;
use derive_more::*;
use {alloc::collections::VecDeque, derive_more::*};
pub use crate::arch::PAGE_SIZE;
pub const MAX_ORDER: usize = 10;
@ -44,7 +43,7 @@ pub const MAX_ORDER: usize = 10;
Sum,
UpperHex,
)]
#[display(fmt = "0x{:x}", _0)]
#[display("0x{:x}", _0)]
#[from(forward)]
pub struct VirtualAddress(usize);
@ -55,11 +54,11 @@ impl VirtualAddress {
pub fn vpns(&self) -> [usize; 3] {
[
// [20:12]
(self.0 >> 12) & 0x1ff,
(self.0 >> 12) & 0x1FF,
// [29:21]
(self.0 >> 21) & 0x1ff,
(self.0 >> 21) & 0x1FF,
// [38:30]
(self.0 >> 30) & 0x1ff,
(self.0 >> 30) & 0x1FF,
]
}
@ -114,7 +113,7 @@ impl VirtualAddress {
Sum,
UpperHex,
)]
#[display(fmt = "0x{:x}", _0)]
#[display("0x{:x}", _0)]
#[from(forward)]
pub struct PhysicalAddress(usize);
@ -125,11 +124,11 @@ impl PhysicalAddress {
pub fn ppns(&self) -> [usize; 3] {
[
// [20:12]
(self.0 >> 12) & 0x1ff,
(self.0 >> 12) & 0x1FF,
// [29:21]
(self.0 >> 21) & 0x1ff,
(self.0 >> 21) & 0x1FF,
// [55:30]
(self.0 >> 30) & 0x3ffffff,
(self.0 >> 30) & 0x3FFFFFF,
]
}

View file

@ -1,34 +1,20 @@
//! Async task and executor
use alloc::{boxed::Box, collections::BTreeMap, sync::Arc, task::Wake};
use core::{
future::Future,
pin::Pin,
task::{Context, Poll, Waker},
use {
alloc::{boxed::Box, sync::Arc},
core::{
future::Future,
pin::Pin,
task::{Context, Poll, RawWaker, RawWakerVTable, Waker},
},
crossbeam_queue::SegQueue,
slab::Slab,
};
use crossbeam_queue::SegQueue;
use slab::Slab;
use spin::RwLock;
type TaskQueue = Arc<SegQueue<TaskId>>;
type SpawnQueue = Arc<SegQueue<Task>>;
static SPAWN_QUEUE: RwLock<Option<SpawnQueue>> = RwLock::new(None);
/// Spawn a new task
pub fn spawn(future: impl Future<Output = ()> + Send + 'static) {
match &*SPAWN_QUEUE.read() {
Some(s) => s.push(Task::new(future)),
None => panic!("no task executor is running"),
}
}
/// Forcibly yield a task
pub fn yield_now() -> impl Future<Output = ()> {
struct YieldNow(bool);
impl Future for YieldNow {
type Output = ();
#[inline(always)]
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
if self.0 {
Poll::Ready(())
@ -43,107 +29,150 @@ pub fn yield_now() -> impl Future<Output = ()> {
YieldNow(false)
}
/// Tasks executor
#[derive(Default)]
pub struct Executor {
/// All spawned tasks' stash
tasks: Slab<Task>,
/// Awake tasks' queue
queue: TaskQueue,
/// Incoming tasks to enqueue
incoming: SpawnQueue,
/// Wakers
wakers: BTreeMap<TaskId, Waker>,
pub struct Executor<F: Future<Output = ()> + Send> {
tasks: Slab<Task<F>>,
task_queue: Arc<TaskQueue>,
}
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))));
impl<F: Future<Output = ()> + Send> Executor<F> {
pub fn new(size: usize) -> Self {
Self {
tasks: Slab::with_capacity(size),
task_queue: Arc::new(TaskQueue::new()),
}
}
#[inline]
pub fn spawn(&mut self, future: F) {
self.task_queue
.queue
.push(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 spawner = SPAWN_QUEUE.write();
if spawner.is_some() {
panic!("task executor is already running");
}
let mut task_batch = [0; 32];
let mut batch_len = 0;
*spawner = Some(Arc::clone(&self.incoming));
}
loop {
self.task_queue.batch_pop(&mut task_batch, &mut batch_len);
// Try to get incoming task, if none available, poll
// enqueued one
while let Some(id) = self
.incoming
.pop()
.map(|t| TaskId(self.tasks.insert(t)))
.or_else(|| self.queue.pop())
{
let Some(task) = self.tasks.get_mut(id.0) else {
panic!("attempted to get non-extant task with id {}", id.0)
};
let mut cx = Context::from_waker(self.wakers.entry(id).or_insert_with(|| {
Waker::from(Arc::new(TaskWaker {
id,
queue: Arc::clone(&self.queue),
}))
}));
match task.poll(&mut cx) {
Poll::Ready(()) => {
// Task done, unregister
self.tasks.remove(id.0);
self.wakers.remove(&id);
if batch_len == 0 {
if self.task_queue.is_empty() {
break;
} else {
continue;
}
}
for &id in &task_batch[..batch_len] {
if let Some(task) = self.tasks.get_mut(id) {
let waker = task
.waker
.get_or_insert_with(|| TaskWaker::new(id, Arc::clone(&self.task_queue)));
let waker = unsafe { Waker::from_raw(TaskWaker::into_raw_waker(waker)) };
let mut cx = Context::from_waker(&waker);
if let Poll::Ready(()) = task.poll(&mut cx) {
self.tasks.remove(id);
self.task_queue.free_tasks.push(id);
}
}
Poll::Pending => (),
}
}
*SPAWN_QUEUE.write() = None;
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
struct TaskId(usize);
/// Async task
struct Task {
future: Pin<Box<dyn Future<Output = ()> + Send>>,
struct Task<F: Future<Output = ()> + Send> {
future: Pin<Box<F>>,
waker: Option<TaskWaker>,
}
impl Task {
/// Create a new task from a future
fn new(future: impl Future<Output = ()> + Send + 'static) -> Self {
impl<F: Future<Output = ()> + Send> Task<F> {
#[inline(always)]
pub fn new(future: F) -> Self {
Self {
future: Box::pin(future),
waker: None,
}
}
#[inline(always)]
fn poll(&mut self, cx: &mut Context) -> Poll<()> {
self.future.as_mut().poll(cx)
}
}
struct TaskWaker {
id: TaskId,
queue: TaskQueue,
id: usize,
task_queue: Arc<TaskQueue>,
}
impl Wake for TaskWaker {
fn wake(self: Arc<Self>) {
self.wake_by_ref();
impl TaskWaker {
#[inline(always)]
fn new(id: usize, task_queue: Arc<TaskQueue>) -> Self {
Self { id, task_queue }
}
fn wake_by_ref(self: &Arc<Self>) {
self.queue.push(self.id);
#[inline(always)]
fn wake(&self) {
self.task_queue.queue.push(self.id);
}
fn into_raw_waker(waker: &TaskWaker) -> RawWaker {
let ptr = waker as *const TaskWaker;
RawWaker::new(ptr.cast(), &VTABLE)
}
}
const VTABLE: RawWakerVTable = RawWakerVTable::new(clone_raw, wake_raw, wake_by_ref_raw, drop_raw);
unsafe fn clone_raw(ptr: *const ()) -> RawWaker {
let waker = &*(ptr as *const TaskWaker);
TaskWaker::into_raw_waker(waker)
}
unsafe fn wake_raw(ptr: *const ()) {
let waker = &*(ptr as *const TaskWaker);
waker.wake();
}
unsafe fn wake_by_ref_raw(ptr: *const ()) {
let waker = &*(ptr as *const TaskWaker);
waker.wake();
}
unsafe fn drop_raw(_: *const ()) {}
struct TaskQueue {
queue: SegQueue<usize>,
next_task: usize,
free_tasks: SegQueue<usize>,
}
impl TaskQueue {
fn new() -> Self {
Self {
queue: SegQueue::new(),
next_task: 0,
free_tasks: SegQueue::new(),
}
}
#[inline(always)]
fn batch_pop(&self, output: &mut [usize], len: &mut usize) {
*len = 0;
while let Some(id) = self.queue.pop() {
output[*len] = id;
*len += 1;
if *len == output.len() {
break;
}
}
}
#[inline(always)]
fn is_empty(&self) -> bool {
self.queue.is_empty()
}
}

53
kernel/src/utils.rs Normal file
View file

@ -0,0 +1,53 @@
//! A module for small utilities to be used kernel wide
//! Simple functions and constants
/// Used when tab `\t` in hardware is not known and we will default to two spaces
pub const TAB: &str = " ";
// NOTE: this only reduces the code duplication in source code not in generated code!
// Written by Yours Truly: Munir
/// A simple macro to reduce code duplication when we use TAB internally
#[macro_export]
macro_rules! tab {
($num:expr) => {
TAB.repeat($num)
}
}
// NOTE: this only reduces the code duplication in source code not in generated code!
// Written by Yours Truly: Munir
/// A simple macro to reduce code duplication when we insert device types into the device tree
#[macro_export]
macro_rules! device_tree {
($devtree:expr, $dev_type_vec:expr) => {
for each_device_type in $dev_type_vec {
$devtree.devices.insert(each_device_type.to_string(), Vec::new());
}
};
}
// NOTE: this only reduces the code duplication in source code not in generated code!
// Written by Yours Truly: Munir
/// A simple macro to reduce code duplication when we insert cpu features into the array/vector
#[macro_export]
macro_rules! cpu_features {
($cpu_master_object:expr, $result_vec:expr) => {
// checks for cpu features and returns bool for each feature
let apic = $cpu_master_object.apic();
let avx = $cpu_master_object.avx();
let avx2 = $cpu_master_object.avx2();
let x2 = $cpu_master_object.x2apic();
let gb_pages = $cpu_master_object.gigabyte_pages();
let rdseed = $cpu_master_object.rdseed();
let rdrand = $cpu_master_object.rdrand();
$result_vec.push(("apic", apic));
$result_vec.push(("avx", avx));
$result_vec.push(("avx2", avx2));
$result_vec.push(("gigabyte pages", gb_pages));
$result_vec.push(("rdrand", rdrand));
$result_vec.push(("rdseed", rdseed));
$result_vec.push(("x2apic", x2));
};
}

View file

@ -0,0 +1,25 @@
{
"arch": "aarch64",
"data-layout": "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128",
"disable-redzone": true,
"env": "",
"executables": true,
"features": "+strict-align,+neon,+fp-armv8",
"linker": "rust-lld",
"linker-flavor": "ld.lld",
"linker-is-gnu": true,
"pre-link-args": {
"ld.lld": [
"-Tkernel/lds/aarch64-qemu.ld"
]
},
"llvm-target": "aarch64-unknown-none",
"max-atomic-width": 128,
"os": "none",
"panic-strategy": "abort",
"relocation-model": "static",
"target-c-int-width": "32",
"target-endian": "little",
"target-pointer-width": "64",
"vendor": ""
}

View file

@ -1,6 +1,6 @@
{
"llvm-target": "x86_64-unknown-none",
"data-layout": "e-m:e-i64:64-f80:128-n8:16:32:64-S128",
"data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128",
"arch": "x86_64",
"target-endian": "little",
"target-pointer-width": "64",
@ -11,7 +11,7 @@
"linker": "rust-lld",
"panic-strategy": "abort",
"disable-redzone": true,
"features": "-mmx,-sse,+soft-float",
"features": "",
"code-model": "kernel",
"pre-link-args": {
"ld.lld": [

2
limine

@ -1 +1 @@
Subproject commit 83779119f658c8ce337c33492266ecf8300db429
Subproject commit 2d3d7b2633b5d95ce404a177ada0d5cbee802721

View file

@ -4,7 +4,26 @@ version = "0.2.0"
edition = "2021"
[dependencies]
env_logger = "0.10"
error-stack = "0.2"
str-reader = "0.1"
derive_more = { version = "1", default-features = false, features = [
"add",
"add_assign",
"constructor",
"display",
"from",
"into",
"mul",
"mul_assign",
"not",
"sum",
] }
error-stack = "0.5"
fatfs = "0.3"
log = "0.4"
toml = "0.8"
# hbasm.git = "https://git.ablecorp.us/AbleOS/holey-bytes.git"
hblang.git = "https://git.ablecorp.us/AbleOS/holey-bytes.git"
[dependencies.reqwest]
version = "0.12"
default-features = false
features = ["rustls-tls", "blocking"]

View file

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

102
repbuild/src/dev.rs Normal file
View file

@ -0,0 +1,102 @@
#![allow(unused)]
use std::{
fmt::format,
fs::{read_to_string, File},
io::{BufWriter, Write},
process::exit,
};
use {error_stack::Report, hblang::Options};
use crate::Error;
pub struct Package {
name: String,
binaries: Vec<String>,
build_cmd: String,
}
impl Package {
pub fn load_from_file(path: String) -> Self {
let contents = match std::fs::read_to_string(path.clone()) {
// If successful return the files text as `contents`.
// `c` is a local variable.
Ok(c) => c,
// Handle the `error` case.
Err(_) => {
// Write `msg` to `stderr`.
eprintln!("Could not read file `{}`", path);
// Exit the program with exit code `1`.
exit(1);
}
};
use toml::Value;
let mut data: Value = toml::from_str(&contents).unwrap();
let mut name = data
.get("package")
.unwrap()
.get("name")
.unwrap()
.to_string();
name.pop();
name.remove(0);
let dependants = data.get("dependants").unwrap();
let bin_table = dependants.get("binaries").unwrap().as_table().unwrap();
let mut binaries = vec![];
for (count, (name, table)) in bin_table.into_iter().enumerate() {
// if count != 0 {
println!("{}", name);
binaries.push(name.clone());
// }
}
let build_table = data.get("build").unwrap();
let mut build_cmd: String = build_table.get("command").unwrap().as_str().unwrap().into();
build_cmd.remove(0);
// build_cmd.pop();
Self {
name,
binaries,
build_cmd,
}
}
pub fn build(&self) {
if self.binaries.contains(&"hblang".to_string()) {
let file = self.build_cmd.split_ascii_whitespace().last().unwrap();
let path = format!("sysdata/programs/{}/{}", self.name, file);
let mut bytes = Vec::new();
// compile here
let _ = hblang::run_compiler(
&path,
Options {
fmt: true,
..Default::default()
},
&mut bytes,
);
let _ = hblang::run_compiler(&path, Default::default(), &mut bytes);
match std::fs::create_dir("target/programs") {
Ok(_) => (),
Err(e) if e.kind() == std::io::ErrorKind::AlreadyExists => (),
Err(e) => panic!("{}", e),
}
std::fs::write(format!("target/programs/{}.hbf", self.name), &bytes).unwrap();
bytes.clear();
let _ = hblang::run_compiler(
&path,
Options {
dump_asm: true,
..Default::default()
},
&mut bytes,
);
std::fs::write(format!("target/programs/{}.hba", self.name), &bytes).unwrap();
}
}
}

View file

@ -1,40 +1,66 @@
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};
// #![allow(unused)]
mod dev;
use {
derive_more::Display,
dev::Package,
error_stack::{bail, report, Context, Report, Result, ResultExt},
fatfs::{FileSystem, FormatVolumeOptions, FsOptions, ReadWriteSeek},
std::{
// fmt::Display,
fs::{self, File},
io::{self, Write},
path::Path,
process::{exit, Command},
},
toml::Value,
};
fn main() -> Result<(), Error> {
env_logger::init();
let mut args = std::env::args();
args.next();
match args.next().as_deref() {
Some("build" | "b") => {
let mut release = false;
let mut debuginfo = false;
let mut target = Target::X86_64;
for arg in args {
if arg == "-r" || arg == "--release" {
release = true;
}
if arg == "rv64" || arg == "riscv64" || arg == "riscv64-virt" {
} else if arg == "-d" || arg == "--debuginfo" {
debuginfo = true;
} else if arg == "rv64" || arg == "riscv64" || arg == "riscv64-virt" {
target = Target::Riscv64Virt;
} else if arg == "arm64" || arg == "aarch64" || arg == "aarch64-virt" {
target = Target::Aarch64;
} else {
return Err(report!(Error::InvalidSubCom));
}
}
build(release, target).change_context(Error::Build)
build(release, target, debuginfo).change_context(Error::Build)
}
Some("run" | "r") => {
let mut release = false;
let mut debuginfo = false;
let mut target = Target::X86_64;
for arg in args {
if arg == "-r" || arg == "--release" {
release = true;
}
if arg == "rv64" || arg == "riscv64" || arg == "riscv64-virt" {
} else if arg == "-d" || arg == "--debuginfo" {
debuginfo = true;
} else if arg == "rv64" || arg == "riscv64" || arg == "riscv64-virt" {
target = Target::Riscv64Virt;
} else if arg == "arm64" || arg == "aarch64" || arg == "aarch64-virt" {
target = Target::Aarch64;
} else {
return Err(report!(Error::InvalidSubCom));
}
}
build(release, target)?;
build(release, target, debuginfo)?;
run(release, target)
}
Some("help" | "h") => {
@ -54,56 +80,205 @@ fn main() -> Result<(), Error> {
}
}
fn get_fs() -> Result<FileSystem<impl ReadWriteSeek>, io::Error> {
let path = Path::new("target/disk.img");
fn get_path_without_boot_prefix(val: &Value) -> Option<&str> {
val.as_str()?.split("boot:///").last()
}
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()
}
}
fn get_fs() -> Result<FileSystem<impl ReadWriteSeek>, io::Error> {
let filename = "sysdata/system_config.toml";
let mut img = File::options()
.read(true)
.write(true)
.create(true)
.open(path)?;
.open(Path::new("target/disk.img"))?;
img.set_len(1024 * 1024 * 64)?;
fatfs::format_volume(&mut img, FormatVolumeOptions::new())?;
let fs = FileSystem::new(img, FsOptions::new())?;
// Read the contents of the file using a `match` block
// to return the `data: Ok(c)` as a `String`
// or handle any `errors: Err(_)`.
let contents = match fs::read_to_string(filename) {
// If successful return the files text as `contents`.
// `c` is a local variable.
Ok(c) => c,
// Handle the `error` case.
Err(_) => {
// Write `msg` to `stderr`.
eprintln!("Could not read file `{}`", filename);
// Exit the program with exit code `1`.
exit(1);
}
};
use toml::Value;
let mut limine_str = String::new();
let mut data: Value = toml::from_str(&contents).unwrap();
let boot_table = data.get_mut("boot");
let limine_table = boot_table.unwrap().get_mut("limine").unwrap();
let default_entry = limine_table.get("default_entry").unwrap();
let timeout = limine_table.get("timeout").unwrap();
let interface_resolution = limine_table.get("interface_resolution").unwrap();
let verbose = limine_table.get("verbose").unwrap();
let term_wallpaper = limine_table.get("term_wallpaper").unwrap();
let vb_post = match verbose.as_bool().unwrap() {
true => "yes",
false => "no",
};
let term_background = limine_table
.get("term_backdrop")
.unwrap_or(&Value::Integer(0));
let base = format!(
"DEFAULT_ENTRY={}
TIMEOUT={}
VERBOSE={}
INTERFACE_RESOLUTION={}
# Terminal related settings
TERM_WALLPAPER={}
TERM_BACKDROP={}
",
default_entry,
timeout,
vb_post,
interface_resolution,
term_wallpaper.as_str().unwrap(),
term_background
);
// Copy the term_wallpaper to the image
let term_wallpaper_path = get_path_without_boot_prefix(term_wallpaper).unwrap();
copy_file_to_img(&format!("sysdata/{}", term_wallpaper_path), &fs);
limine_str.push_str(&base);
let boot_entries = limine_table.as_table_mut().unwrap();
let mut real_boot_entries = boot_entries.clone();
for (key, value) in boot_entries.into_iter() {
if !value.is_table() {
real_boot_entries.remove(key);
}
}
for (name, mut value) in real_boot_entries {
let comment = value.get("comment").unwrap();
let protocol = value.get("protocol").unwrap();
let resolution = value.get("resolution").unwrap();
let kernel_path = value.get("kernel_path").unwrap();
let kernel_cmdline = value.get("kernel_cmdline").unwrap();
let text_entry = format!(
"
:{}
COMMENT={}
PROTOCOL={}
RESOLUTION={}
KERNEL_PATH={}
KERNEL_CMDLINE={}
",
name,
comment.as_str().unwrap(),
protocol.as_str().unwrap(),
resolution.as_str().unwrap(),
kernel_path.as_str().unwrap(),
kernel_cmdline,
);
limine_str.push_str(&text_entry);
let modules = value.get_mut("modules").unwrap().as_table_mut().unwrap();
// let mut real_modules = modules.clone();
modules.into_iter().for_each(|(_, value)| {
if value.is_table() {
let path = get_path_without_boot_prefix(
value.get("path").expect("You must have `path` as a value"),
)
.unwrap()
.split(".")
.next()
.unwrap();
let p = Package::load_from_file(
format!("sysdata/programs/{}/meta.toml", path).to_owned(),
);
p.build();
}
});
modules.into_iter().for_each(|(_key, value)| {
if value.is_table() {
let path = value.get("path").expect("You must have `path` as a value");
let default_value = Value::String("".into());
let cmd_line = value.get("cmd_line").unwrap_or(&default_value);
let a = format!(
" MODULE_PATH={}
MODULE_CMDLINE={}\n\n",
path.as_str().unwrap(),
cmd_line
);
limine_str.push_str(&a);
}
});
// Copy modules into the test_programs directory
modules.into_iter().for_each(|(_key, value)| {
if value.is_table() {
let path = get_path_without_boot_prefix(
value
.get("path")
.expect("You must have a `path` as a value"),
)
.unwrap();
let fpath = format!("target/programs/{}", path);
copy_file_to_img(&fpath, &fs);
}
});
}
let bootdir = fs.root_dir().create_dir("efi")?.create_dir("boot")?;
let mut f = fs.root_dir().create_file("limine.cfg")?;
let _ = f.write(limine_str.as_bytes())?;
drop(f);
io::copy(
&mut File::open("limine/BOOTX64.EFI")
.into_report()
.attach_printable("copying Limine bootloader (have you pulled the submodule?)")?,
.map_err(Report::from)
.attach_printable("Copying Limine (x86_64): have you pulled the submodule?")?,
&mut bootdir.create_file("bootx64.efi")?,
)?;
io::copy(
&mut File::open("repbuild/limine.cfg")?,
&mut fs.root_dir().create_file("limine.cfg")?,
)?;
io::copy(
&mut File::open("repbuild/background.bmp")?,
&mut fs.root_dir().create_file("background.bmp")?,
&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")?,
)?;
drop(bootdir);
Ok(fs)
}
fn build(release: bool, target: Target) -> Result<(), Error> {
fn copy_file_to_img(fpath: &str, fs: &FileSystem<File>) {
let path = Path::new(fpath);
// println!("{path:?}");
io::copy(
&mut File::open(path).expect(&format!("Could not open file {fpath}")),
&mut fs
.root_dir()
.create_file(&path.file_name().unwrap().to_string_lossy())
.expect("Unable to create file"),
)
.expect("Copy failed");
}
fn build(release: bool, target: Target, debuginfo: bool) -> Result<(), Error> {
let fs = get_fs().change_context(Error::Io)?;
let mut com = Command::new("cargo");
com.current_dir("kernel");
@ -111,12 +286,15 @@ fn build(release: bool, target: Target) -> Result<(), Error> {
if release {
com.arg("-r");
}
if debuginfo {
com.env("RUSTFLAGS", "-Cdebug-assertions=true");
}
match target {
Target::Riscv64Virt => {
com.args(["--target", "targets/riscv64-virt-ableos.json"]);
}
_ => {}
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 com.status() {
@ -125,22 +303,31 @@ fn build(release: bool, target: Target) -> Result<(), Error> {
_ => (),
}
if target != Target::X86_64 {
return Ok(());
}
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"
}
};
(|| -> std::io::Result<_> {
io::copy(
&mut File::open(
Path::new("target/x86_64-ableos")
Path::new(kernel_dir)
.join(if release { "release" } else { "debug" })
.join("kernel"),
)?,
&mut fs.root_dir().create_file("kernel")?,
&mut fs.root_dir().create_file(&path)?,
)
.map(|_| ())
})()
.into_report()
.map_err(Report::from)
.change_context(Error::Io)
}
@ -148,45 +335,55 @@ 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);
if target == Target::X86_64 {
#[rustfmt::skip]
com.args([
"-bios",
std::env::var("REPBUILD_QEMU_FIRMWARE_PATH")
.as_deref()
.unwrap_or("/usr/share/OVMF/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"]);
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", "host",
"-device", "isa-debug-exit,iobase=0xf4,iosize=0x04"
]);
}
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", "neoverse-n2",
"-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::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()
.into_report()
.map_err(Report::from)
.change_context(Error::ProcessSpawn)?
{
s if s.success() => Ok(()),
@ -194,33 +391,94 @@ 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("Failed to fetch OVMF package")]
Fetch,
#[display("No OVMF package available")]
Empty,
#[display("IO Error")]
Io,
}
impl Context for OvmfFetchError {}
#[derive(Clone, Copy, PartialEq, Eq)]
enum Target {
X86_64,
Riscv64Virt,
Aarch64,
}
#[derive(Debug)]
#[allow(unused)]
#[derive(Debug, Display)]
enum Error {
#[display("Failed to build the kernel")]
Build,
#[display("Missing or invalid subcommand (available: build, run)")]
InvalidSubCom,
#[display("IO Error")]
Io,
#[display("Failed to spawn a process")]
ProcessSpawn,
#[display("Failed to fetch UEFI firmware")]
OvmfFetch,
#[display("Failed to assemble Holey Bytes code")]
Assembler,
#[display("QEMU Error: {}", "fmt_qemu_err(*_0)")]
Qemu(Option<i32>),
}
impl Context for Error {}
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)")
#[allow(dead_code)]
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")
}
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"
channel = "nightly-2024-07-27"
components = ["rust-src", "llvm-tools"]

3
rustfmt.toml Normal file
View file

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

41
shell.nix Normal file
View file

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

View file

Before

Width:  |  Height:  |  Size: 1.8 MiB

After

Width:  |  Height:  |  Size: 1.8 MiB

22
sysdata/config.format Normal file
View file

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

@ -0,0 +1 @@
# abc

View file

@ -0,0 +1,24 @@
@auto_increment
enum LogLevel {
Error = 0,
Warn,
Info,
Debug,
Trace,
}
@auto_increment
enum LogResult {
Err = 0,
Ok,
}
struct Log {
log_level: LogLevel,
}
@visibility(public)
protocol Log {
fn log(Log) -> LogResult;
fn flush() -> LogResult;
}

View file

@ -0,0 +1 @@
# dt_api

View file

@ -0,0 +1,8 @@
stn := @use("rel:../../stn/src/lib.hb");
.{string, memory, buffer} := stn
dt_get := fn(query: ^u8): int {
message_length := string.length(query)
return @eca(int, 3, 5, query, message_length)
}

View file

@ -0,0 +1,3 @@
# Horizon
Horizon is the windowing system for ableOS.
This is the API library to handle it nicely.

View file

@ -0,0 +1,24 @@
stn := @use("rel:../../stn/src/lib.hb");
.{string, memory, buffer} := stn
WindowID := struct {
host_id: int,
window_id: int,
}
create_window := fn(channel: int): void {
// get the horizon buffer
// request a new window and provide the callback buffer
// wait to recieve a message
windowing_system_buffer := buffer.search("XHorizon\0")
if windowing_system_buffer == 0 {
} else {
msg := "\{01}\0"
msg_length := 2
@eca(void, 3, windowing_system_buffer, msg, msg_length)
}
return
}

View file

@ -0,0 +1,2 @@
# Ignim
Ignim is the ableOS vulkan interface library.

View file

@ -0,0 +1,21 @@
structures := @use("rel:structures.hb")
version := @use("rel:version.hb")
// Refer to here https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkApplicationInfo.html
ApplicationInfo := struct {
sType: int,
pNext: ^int,
application_name: ^u8,
application_version: int,
engine_name: int,
engine_version: int,
api_version: int,
}
new_application_info := fn(app_name: ^u8, app_version: int, engine_name: ^u8, engine_version: int, api_version: int): ApplicationInfo {
app_info_type := structures.ApplicationInfoType
app_info := ApplicationInfo.(app_info_type, 0, app_name, app_version, engine_name, engine_version, api_version)
return app_info
}

View file

@ -0,0 +1,14 @@
OutOfHostMemory := -1
OutOfDeviceMemory := -2
InitializationFailed := -3
DeviceLost := -4
MemoryMapFailed := -5
LayerNotPresent := -6
ExtensionNotPresent := -7
FeatureNotPresent := -8
IncompatibleDriver := -9
TooManyObjects := -10
FormatNotSupported := -11
FragmentedPool := -12
Unknown := -13

View file

@ -0,0 +1,10 @@
Extent3D := struct {
width: int,
height: int,
depth: int,
}
Extent2D := struct {
width: int,
height: int,
}

View file

@ -0,0 +1,35 @@
application := @use("rel:application.hb");
.{ApplicationInfo} := application
structures := @use("rel:structures.hb")
errors := @use("rel:errors.hb")
// https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkInstanceCreateInfo.html
InstanceCreateInfo := struct {
sType: int,
pNext: int,
flags: int,
application_info: ^ApplicationInfo,
enabled_layer_count: int,
ppEnabledLayerNames: int,
enabled_extension_count: int,
ppEnabledExtensionNames: int,
}
new_create_info := fn(application_info: ^ApplicationInfo): InstanceCreateInfo {
create_info_type := structures.InstanceCreateInfoType
enabled_layer_count := 0
create_info := InstanceCreateInfo.(create_info_type, 0, 0, application_info, enabled_layer_count, 0, 0, 0)
return create_info
}
// TODO
Instance := struct {inner: int}
void_instance := fn(): Instance {
return Instance.(0)
}
create_instance := fn(create_info: ^InstanceCreateInfo, allocator_callback: int, new_obj: ^Instance): int {
return errors.IncompatibleDriver
}

View file

@ -0,0 +1,17 @@
application := @use("rel:application.hb")
results := @use("rel:results.hb")
errors := @use("rel:errors.hb")
offsets := @use("rel:offset.hb")
extends := @use("rel:extends.hb")
rect := @use("rel:rect.hb")
structures := @use("rel:structures.hb")
instance := @use("rel:instance.hb")
version := @use("rel:version.hb")
init_vulkan := fn(): int {
return errors.IncompatibleDriver
}

View file

@ -0,0 +1,10 @@
Offset3D := struct {
x: int,
y: int,
z: int,
}
Offset2D := struct {
x: int,
y: int,
}

View file

@ -0,0 +1,7 @@
offsets := @use("rel:offset.hb")
extends := @use("rel:extends.hb")
Rect2D := struct {
offset: offsets.Offset2D,
extent: extends.Extent2D,
}

View file

@ -0,0 +1,7 @@
// NonErrors
Success := 0
NotReady := 1
Timeout := 2
EventSet := 3
EventReset := 4
Incomplete := 5

View file

@ -0,0 +1,61 @@
ApplicationInfoType := 0
InstanceCreateInfoType := 1
DeviceQueueCreateInfo := 2
DeviceCreateInfo := 3
SubmitInfo := 4
MemoryAllocateInfo := 5
MappedMemoryRange := 6
BindSparseInfo := 7
FenceCreateInfo := 8
SemaphoreCreateInfo := 9
EventCreateInfo := 10
QueryPoolCreateInfo := 11
BufferCreateInfo := 12
BufferViewCreateInfo := 13
ImageCreateInfo := 14
ImageViewCreateInfo := 15
ShaderModuleCreateInfo := 16
PipelineCacheCreateInfo := 17
PipelineShaderStageCreateInfo := 18
PipelineVertexInputStateCreateInfo := 19
PipelineInputAssemblyStateCreateInfo := 20
PipelineTessellationStateCreateInfo := 21
PipelineViewportStateCreateInfo := 22
PipelineRasterizationStateCreateInfo := 23
PipelineMultisampleStateCreateInfo := 24
PipelineDepthStencilStateCreateInfo := 25
PipelineColorBlendStateCreateInfo := 26
PipelineDynamicStateCreateInfo := 27
GraphicsPipelineCreateInfo := 28
ComputePipelineCreateInfo := 29
PipelineLayoutCreateInfo := 30
SamplerCreateInfo := 31
DescriptorSetLayoutCreateInfo := 32
DescriptorPoolCreateInfo := 33
DescriptorSetAllocateInfo := 34
WriteDescriptorSet := 35
CopyDescriptorSet := 36
FramebufferCreateInfo := 37
RenderPassCreateInfo := 38
CommandPoolCreateInfo := 39
CommandBufferAllocateInfo := 40
CommandBufferInheritanceInfo := 41
CommandBufferBeginInfo := 42
RenderPassBeginInfo := 43
BufferMemoryBarrier := 44
ImageMemoryBarrier := 45
MemoryBarrier := 46
LoaderInstanceCreateInfo := 47
LoaderDeviceCreateInfo := 48

View file

@ -0,0 +1,9 @@
ApiVersion1_0 := make_api_version(0, 1, 0, 0)
make_version := fn(major: int, minor: int, patch: int): int {
return major << 22 | minor << 12 | patch
}
make_api_version := fn(variant: int, major: int, minor: int, patch: int): int {
return variant << 29 | major << 22 | minor << 12 | patch
}

View file

@ -0,0 +1 @@
# pci

View file

@ -0,0 +1,28 @@
PCIAddress := struct {
bus: u8,
device: u8,
function: u8,
}
find_device := fn(vendor_id: int, device_id: int, pci_address: PCIAddress): int {
return 1
}
scan_bus := fn(): void {
}
config_read32 := fn(bus: u32, device: u32, func: u32, offset: u32): u32 {
// construct address param
address := bus << 16 | device << 11 | func << 8
address |= offset
address &= 0xFC
address |= 0x80000000
// write address
//Port::new(0xCF8).write(address);
// read data
//Port::new(0xCFC).read()
return
}

View file

@ -0,0 +1,9 @@
Rendering interface for SVGA and Software renderers
# TODO:
- SVGA Driver
- needs pci driver
- needs init (requiring program)
- Double Buffer mode for Software renderer
- needs init (requiring program)

View file

@ -0,0 +1,47 @@
svga := @use("rel:svga.hb")
software := @use("rel:software.hb")
// default mode
mode := software
init := mode.init
doublebuffer := mode.doublebuffer
// Colours
Color := mode.Color
white := mode.white
black := mode.black
gray := mode.gray
red := mode.red
green := mode.green
yellow := mode.yellow
blue := mode.blue
magenta := mode.magenta
cyan := mode.cyan
light_gray := mode.light_gray
light_red := mode.light_red
light_green := mode.light_green
light_yellow := mode.light_yellow
light_blue := mode.light_blue
light_magenta := mode.light_magenta
light_cyan := mode.light_cyan
// Drawing
put_pixel := mode.put_pixel
put_rect := mode.put_rect
put_filled_rect := mode.put_filled_rect
put_line := mode.put_line
clear := mode.clear
// Display
width := mode.width
height := mode.height
dimensions := mode.dimensions
set_height := mode.set_height
set_width := mode.set_width
set_dimensions := mode.set_dimensions
sync := mode.sync
// Math
UVec2 := struct {x: uint, y: uint}
IVec2 := struct {x: int, y: int}

View file

@ -0,0 +1,261 @@
.{math, memory} := @use("../../stn/src/lib.hb");
.{dt_get} := @use("../../dt_api/src/lib.hb");
.{IVec2} := @use("rel:lib.hb")
Color := struct {b: u8, g: u8, r: u8, a: u8}
white := Color.(255, 255, 255, 255)
black := Color.(0, 0, 0, 255)
gray := Color.(127, 127, 127, 255)
red := Color.(0, 0, 205, 255)
green := Color.(0, 205, 0, 255)
yellow := Color.(0, 205, 205, 255)
blue := Color.(205, 0, 0, 255)
magenta := Color.(205, 0, 205, 255)
cyan := Color.(205, 205, 0, 255)
light_gray := Color.(229, 229, 229, 255)
light_red := Color.(0, 0, 255, 255)
light_green := Color.(0, 255, 0, 255)
light_yellow := Color.(0, 255, 255, 255)
light_blue := Color.(255, 0, 0, 255)
light_magenta := Color.(255, 0, 255, 255)
light_cyan := Color.(255, 255, 0, 255)
// might not work for some resolutions, but needs to be comptime because...
copy_pixels := 0xC000 >> 2
ctx := @as(Context, idk)
// some of these are redudant holdovers from fb_driver
// will keep them for future work if necessary
Context := struct {
fb: ^Color,
bb: ^Color,
buf: ^Color,
width: int,
height: int,
partitions: int,
pixels: int,
bb_pages: int,
double_buffer: bool,
}
init := fn(): void {
width := dt_get("framebuffer/fb0/width\0")
height := dt_get("framebuffer/fb0/height\0")
// width := 1024
// height := 768
pixels := width * height
bytes := pixels << 2
partitions := pixels / copy_pixels
pages := 1 + bytes >> 12
back_buffer := create_back_buffer(pages)
ctx = Context.{
fb: dt_get("framebuffer/fb0/ptr\0"),
bb: back_buffer,
buf: back_buffer,
width,
height,
partitions,
pixels,
bb_pages: pages,
double_buffer: true,
}
return
}
doublebuffer := fn(enable: bool): void {
if enable {
ctx.buf = ctx.bb
} else {
ctx.buf = ctx.fb
}
ctx.double_buffer = enable
return
}
create_back_buffer := fn(pages: int): ^Color {
if pages <= 0xFF {
return @bitcast(@inline(memory.request_page, pages))
}
ptr := @inline(memory.request_page, 255)
remaining := pages - 0xFF
loop if remaining <= 0 break else {
if remaining < 0xFF {
memory.request_page(remaining)
} else {
memory.request_page(0xFF)
}
remaining -= 0xFF
}
return @bitcast(ptr)
}
clear := fn(color: Color): void {
cursor := ctx.buf
boundary := cursor + 512
loop if cursor == boundary break else {
*cursor = color
cursor += 1
}
boundary += 512 * 7
loop if cursor == boundary break else {
*@as(^[Color; 512], @bitcast(cursor)) = *@as(^[Color; 512], @bitcast(ctx.buf))
cursor += 512
}
boundary += copy_pixels - 4096
loop if cursor == boundary break else {
*@as(^[Color; 4096], @bitcast(cursor)) = *@as(^[Color; 4096], @bitcast(ctx.buf))
cursor += 4096
}
boundary += (ctx.partitions - 1) * copy_pixels
loop if cursor == boundary break else {
*@as(^[Color; copy_pixels], @bitcast(cursor)) = *@as(^[Color; copy_pixels], @bitcast(ctx.buf))
cursor += @sizeof([u8; copy_pixels])
}
return
}
sync := fn(): void {
if ctx.double_buffer {
bb := ctx.buf
fb := ctx.fb
boundary := bb + ctx.pixels
loop if bb == boundary break else {
*@as(^[Color; copy_pixels], @bitcast(fb)) = *@as(^[Color; copy_pixels], @bitcast(bb))
bb += copy_pixels
fb += copy_pixels
}
}
return
}
width := fn(): int {
return ctx.width
}
height := fn(): int {
return ctx.height
}
screenidx := fn(x: int, y: int): int {
return x + ctx.width * y
}
put_pixel := fn(pos: IVec2, color: Color): void {
*(ctx.buf + @inline(screenidx, pos.x, pos.y)) = color
return
}
put_filled_rect := fn(pos: IVec2, tr: IVec2, color: Color): void {
x := pos.x
y := pos.y
end := pos + tr
loop if x == end.x break else {
loop if y == end.y break else {
*(ctx.buf + @inline(screenidx, x, y)) = color
y += 1
}
x += 1
y = pos.y
}
return
}
put_rect := fn(pos: IVec2, tr: IVec2, color: Color): void {
x := pos.x
y := pos.y
end := pos + tr
loop if y == end.y break else {
*(ctx.buf + @inline(screenidx, x, y)) = color;
*(ctx.buf + @inline(screenidx, x + tr.x, y)) = color
y += 1
}
y = pos.y
loop if x == end.x break else {
*(ctx.buf + @inline(screenidx, x, y)) = color;
*(ctx.buf + @inline(screenidx, x, y + tr.y)) = color
x += 1
}
return
}
put_line_low := fn(p0: IVec2, p1: IVec2, color: Color): void {
dx := p1.x - p0.x
dy := p1.y - p0.y
yi := 1
if dy < 0 {
yi = -1
dy = -dy
}
D := 2 * dy - dx
y := p0.y
x := p0.x
loop if x == p1.x break else {
*(ctx.buf + @inline(screenidx, x, y)) = color
if D > 0 {
y += yi
D += 2 * (dy - dx)
} else {
D += 2 * dy
}
x += 1
}
return
}
put_line_high := fn(p0: IVec2, p1: IVec2, color: Color): void {
dx := p1.x - p0.x
dy := p1.y - p0.y
xi := 1
if dy < 0 {
xi = -1
dx = -dx
}
D := 2 * dx - dy
x := p0.x
y := p0.y
loop if y == p1.y break else {
*(ctx.buf + @inline(screenidx, x, y)) = color
if D > 0 {
x += xi
D += 2 * (dx - dy)
} else {
D += 2 * dx
}
y += 1
}
return
}
put_line := fn(p0: IVec2, p1: IVec2, color: Color): void {
if @inline(math.abs, p1.y - p0.y) < @inline(math.abs, p1.x - p0.x) {
if p0.x > p1.x {
@inline(put_line_low, p1, p0, color)
} else {
@inline(put_line_low, p0, p1, color)
}
} else {
if p0.y > p1.y {
@inline(put_line_high, p1, p0, color)
} else {
@inline(put_line_high, p0, p1, color)
}
}
return
}
set_height := fn(new: int): void {
return
}
set_width := fn(new: int): void {
return
}
dimensions := fn(): IVec2 {
return .(ctx.width, ctx.height)
}
set_dimensions := fn(new: IVec2): void {
return
}

View file

@ -0,0 +1,80 @@
.{IVec2} := @use("rel:lib.hb")
// .{pci, memory, string, log} := @use("../../stn/src/lib.hb");
Color := struct {b: u8, g: u8, r: u8, a: u8}
white := Color.(255, 255, 255, 255)
black := Color.(0, 0, 0, 255)
gray := Color.(127, 127, 127, 255)
red := Color.(0, 0, 205, 255)
green := Color.(0, 205, 0, 255)
yellow := Color.(0, 205, 205, 255)
blue := Color.(205, 0, 0, 255)
magenta := Color.(205, 0, 205, 255)
cyan := Color.(205, 205, 0, 255)
light_gray := Color.(229, 229, 229, 255)
light_red := Color.(0, 0, 255, 255)
light_green := Color.(0, 255, 0, 255)
light_yellow := Color.(0, 255, 255, 255)
light_blue := Color.(255, 0, 0, 255)
light_magenta := Color.(255, 0, 255, 255)
light_cyan := Color.(255, 255, 0, 255)
clear := fn(color: Color): void {
return
}
width := fn(): int {
return 0
}
height := fn(): int {
return 0
}
dimensions := fn(): IVec2 {
return .(0, 0)
}
put_pixel := fn(position: IVec2, color: Color): void {
return
}
put_filled_rect := fn(pos: IVec2, tr: IVec2, color: Color): void {
return
}
put_rect := fn(pos: IVec2, tr: IVec2, color: Color): void {
return
}
put_line_low := fn(p0: IVec2, p1: IVec2, color: Color): void {
return
}
// do not use, use line() instead
put_line_high := fn(p0: IVec2, p1: IVec2, color: Color): void {
return
}
put_line := fn(p0: IVec2, p1: IVec2, color: Color): void {
return
}
set_height := fn(new: int): void {
return
}
set_width := fn(new: int): void {
return
}
set_dimensions := fn(new: IVec2): void {
return
}
sync := fn(): void {
return
}
init := fn(): void {
return
}

View file

@ -0,0 +1 @@
The standard library for ableOS.

View file

@ -0,0 +1,22 @@
string := @use("rel:string.hb")
receive_message := fn(buffer_id: int, memory_map_location: ^u8, length: int): ^u8 {
return @eca(^u8, 4, buffer_id, memory_map_location, length)
}
send_message := fn(msg: ^u8, buffer_id: int, length: int): void {
return @eca(void, 3, buffer_id, msg, length)
}
create := fn(msg: ^u8): int {
msg_length := @inline(string.length, msg);
*msg = 0
return @eca(int, 3, 0, msg, msg_length)
}
search := fn(msg: ^u8): int {
msg_length := @inline(string.length, msg);
*msg = 3
return @eca(int, 3, 0, msg, msg_length)
}

View file

@ -0,0 +1,7 @@
string := @use("rel:string.hb")
log := @use("rel:log.hb")
memory := @use("rel:memory.hb")
buffer := @use("rel:buffer.hb")
math := @use("rel:math.hb")
random := @use("rel:random.hb")
pci := @use("rel:pci.hb")

View file

@ -0,0 +1,15 @@
string := @use("rel:string.hb")
buffer := @use("rel:buffer.hb")
log := fn(message: ^u8, level: u8): void {
message_length := @inline(string.length, message);
*(message + message_length) = level
@eca(i32, 3, 1, message, message_length + 1)
return
}
error := fn(message: ^u8): void return log(message, 0)
warn := fn(message: ^u8): void return log(message, 1)
info := fn(message: ^u8): void return log(message, 2)
debug := fn(message: ^u8): void return log(message, 3)
trace := fn(message: ^u8): void return log(message, 4)

View file

@ -0,0 +1,15 @@
shift := 31
// following only work for: int
abs := fn(x: int): int {
mask := x >> shift
return (x ^ mask) - mask
}
min := fn(a: int, b: int): int {
c := a - b
return b + (c & c >> shift)
}
max := fn(a: int, b: uint): int {
c := a - b
return a - (c & c >> shift)
}

View file

@ -0,0 +1,39 @@
request_page := fn(page_count: u8): ^u8 {
msg := "\{00}\{01}xxxxxxxx\0"
msg_page_count := msg + 1;
*msg_page_count = page_count
return @eca(^u8, 3, 2, msg, 12)
}
release_page := fn(ptr: ^u8, page_count: u8): void {
msg := "\{01}\{00}xxxxxxxx\0"
msg_page_count := msg + 1;
*msg_page_count = page_count
msg_ptr := @as(^^u8, @bitcast(msg + 2));
*msg_ptr = ptr
return @eca(void, 3, 2, msg, 12)
}
OutbMsg := struct {a: u8, b: u8, addr: u16, value: u8}
InbMsg := struct {a: u8, b: u8, addr: u16}
OutlMsg := struct {a: u8, b: u8, addr: u16, value: u32}
InlMsg := struct {a: u8, b: u8, addr: u16}
outb := fn(addr: u16, value: u8): void {
return @eca(void, 3, 3, &OutbMsg.(1, 0, addr, value), @sizeof(OutbMsg))
}
inb := fn(addr: u16): u8 {
return @eca(u8, 3, 3, &InbMsg.(0, 0, addr), @sizeof(InbMsg))
}
outl := fn(addr: u16, value: u32): void {
return @eca(void, 3, 3, &OutlMsg.(1, 2, addr, value), @sizeof(OutlMsg))
}
inl := fn(addr: u16): u32 {
return @eca(u32, 3, 3, &InlMsg.(0, 2, addr), @sizeof(InlMsg))
}

Some files were not shown because too many files have changed in this diff Show more