Compare commits

...

340 commits

Author SHA1 Message Date
Able 2fb17ac610 VFSaur restructuring 2024-12-22 05:47:53 -06:00
koniifer 1ec9d0fd46 printf, various syntax updates, better string manipulation miscellaneous changes 2024-12-21 19:28:10 +00:00
Able 59cf6ef4d7 VFSaur work. String split bug. 2024-12-21 06:05:12 -06:00
koniifer 8cce5ef731 fiddling 2024-12-21 12:01:48 +00:00
koniifer 0fc95160cc tuple and array syntax 2024-12-20 11:21:03 +00:00
koniifer 25fecab5b3 new broken 2024-12-20 10:47:22 +00:00
Jakub Doka f6bfb73bd7
migrating to new hblang syntax
Signed-off-by: Jakub Doka <jakub.doka2@gmail.com>
2024-12-20 11:37:06 +01:00
koniifer f8523f5b3e working + fiddling 2024-12-19 19:07:54 +00:00
koniifer d2cb73c2ce almost enums 2024-12-19 17:29:39 +00:00
koniifer d0bd3714ee logger work 2024-12-19 17:19:57 +00:00
koniifer e8f1bce4d6 update test 2024-12-17 23:22:04 +00:00
Jakub Doka dc4878bc2b
fixing the optional formatting
Signed-off-by: Jakub Doka <jakub.doka2@gmail.com>
2024-12-18 00:08:59 +01:00
koniifer 04ca5f07d5 more and less broken 2024-12-17 22:30:22 +00:00
Jakub Doka ad587fe464
fixing a bug in a disasm
Signed-off-by: Jakub Doka <jakub.doka2@gmail.com>
2024-12-17 20:24:53 +01:00
Jakub Doka 9a06b329f4
save 2024-12-17 19:23:01 +01:00
koniifer 936c9e6525 less less broken 2024-12-17 18:22:39 +00:00
koniifer a8572da351 less broken 2024-12-17 18:20:16 +00:00
koniifer b059faa7f8 broken for now 2024-12-17 17:43:00 +00:00
koniifer d55fd895c9 formatter update 2024-12-17 13:50:04 +00:00
koniifer e2dd379fea minor change 2024-12-17 02:10:30 +00:00
koniifer d907df14dd primitive string formatter with struct & array support 2024-12-17 02:06:48 +00:00
koniifer 3506c83535 math changes & compiler update 2024-12-16 14:36:14 +00:00
Able eff1323e94 fixes for the absolutely huge breakage pushed 2024-12-16 08:12:12 -06:00
Able 8849017db2 Merge branch 'master' of ssh://git.ablecorp.us:20/AbleOS/ableos 2024-12-16 08:01:46 -06:00
Able f3b78d1699 local changes 👍 2024-12-16 07:58:04 -06:00
koniifer 5eff0facb1 push 2024-12-16 13:22:03 +00:00
koniifer 6e3fea0713 fiddling and move some stuff to stn.math 2024-12-16 01:06:55 +00:00
koniifer 55c8d9b8b2 hblang update 2024-12-15 22:27:09 +00:00
koniifer 642b0b74b5 cooler mandelbrot 2024-12-15 22:05:06 +00:00
koniifer 5b3a97e580 fixed struct method things 2024-12-14 19:43:33 +00:00
koniifer ee68a2662c broken struct method things 2024-12-14 16:39:45 +00:00
Able 72cf91a928 proposed replacement for system.toml 2024-12-10 08:43:47 -06:00
Able f714775091 Stress testing. 2024-12-07 19:25:01 -06:00
Able 6af68994d8 Merge branch 'master' of ssh://git.ablecorp.us:20/AbleOS/ableos 2024-12-07 10:44:56 -06:00
Able df7982d9e5 ata pio mode 2024-12-07 10:44:29 -06:00
koniifer e688fdf4f0 cool mandelbrot also fix circle rendering a bit 2024-12-07 15:41:58 +00:00
Able bcc7c827ab omnibar change & conceptualization. 2024-12-05 11:04:28 -06:00
Able eff2a22018 begin work on hblang2 2024-12-05 11:03:07 -06:00
Able 883c01b2ba minor patch to make things more clear 2024-12-05 11:02:48 -06:00
Able 635ed1be42 theoretically works but is broken in practice :( 2024-12-04 04:21:24 -06:00
Able 36d50f6b38 filling out the ide_select_drive function 2024-12-04 03:58:23 -06:00
Able 559f25bb4e minor sketch work for ata 2024-12-04 03:53:13 -06:00
Able 82b9cb1206 a 2024-12-03 12:31:33 -06:00
Able 2afa83a615 update hblang compiler 2024-12-02 07:13:37 -06:00
Able 28258e0d45 hacky impl of a fetch program 2024-12-01 15:31:39 -06:00
Able 190f0941dc Remove old ps2_keyboard driver 2024-12-01 14:20:51 -06:00
Able 68840571c0 fat32 cleanup patch 2024-12-01 11:52:26 -06:00
Able dc3b7f71d5 arm arch patch 2024-12-01 11:44:46 -06:00
Able bff8db4c13 Merge branch 'peony-master' 2024-12-01 06:54:45 -06:00
peony 13c4649fd6 /shrug 2024-12-01 13:53:45 +01:00
peony f7f5b677e9 Merge 2024-12-01 13:53:44 +01:00
peony 821497fbe6 Deleted Cargo.lock 2024-12-01 13:52:12 +01:00
Able 5abdef4be6 Merge branch 'master' of ssh://git.ablecorp.us:20/AbleOS/ableos 2024-12-01 06:46:08 -06:00
Able b5282ea6fb rtc+tempfs skeleton 2024-12-01 06:45:34 -06:00
peony 498cfbf913 Removed error dump. 2024-12-01 13:39:40 +01:00
peony e3abec2927 Errorrr 2024-12-01 13:36:12 +01:00
peony b3d07b5235 Uhm, I dunno how that got there. 2024-12-01 13:13:13 +01:00
peony a93512eed1 Merged master. 2024-12-01 13:11:53 +01:00
peony c429641f98 Tiny commit. 2024-12-01 13:10:41 +01:00
koniifer db01da58e1 new path resolver and stuff 2024-11-30 21:52:18 +00:00
koniifer 38d3a10659 updates and updates 2024-11-30 11:46:33 +00:00
koniifer a551b2672f buffer awaiting -> free performance and free bugs 2024-11-27 16:53:17 +00:00
koniifer fd26ec734b temp interrupt fix, problem with sds_search_service 2024-11-27 12:52:48 +00:00
koniifer 9d1c59b65d consolidate simple tests, bug revealed 2024-11-27 12:41:51 +00:00
able cda022e6f0 Merge pull request 'Ktest major improvements' (#23) from funky/ableos:ktest_merge_conflict_fix into master
Reviewed-on: https://git.ablecorp.us/AbleOS/ableos/pulls/23
2024-11-27 06:16:25 -06:00
funky 95cf948d59 Ktest major improvements 2024-11-27 19:09:15 +11:00
koniifer f6a8a78b6c mini size fixes 2024-11-26 22:02:54 +00:00
kodin 5d152811b2 Interrupt Forwarding (#22)
Co-authored-by: Talha Qamar <qamartalha@proton.me>
Reviewed-on: https://git.ablecorp.us/AbleOS/ableos/pulls/22
Co-authored-by: kodin <kodin@yourmoms.house>
Co-committed-by: kodin <kodin@yourmoms.house>
2024-11-26 15:53:50 -06:00
koniifer 685c6f0b20 task scheduler weirdness 2024-11-26 19:32:19 +00:00
Able 1b3dc153e8 SDoom + pcspkr: Both prerelease 2024-11-26 07:39:16 -06:00
Able 9aa84a0f40 👍 checkpoint 2024-11-24 23:51:37 -06:00
Able bdb762c986 Magic function style guide 2024-11-24 23:50:46 -06:00
koniifer 0b57c2e9bb simple foldhash implementation 2024-11-24 20:58:14 +00:00
Able 8c88c0b5ae defer in alloc 2024-11-24 12:43:15 -06:00
Able 8b2b50e433 Style guide update, vscode config to make tab indent follow the style guide 2024-11-24 12:22:06 -06:00
Able d7e0d573e2 Style guide commit. Feel free to bikeshed about it. What should be added etcetc 2024-11-24 11:57:06 -06:00
Able 0ee8b7a4e4 janky error handling 2024-11-24 11:08:22 -06:00
Able 2261f36101 simply just dont inline 2024-11-24 11:04:12 -06:00
Able 6f82c92c30 sorta alloc support. Compiler error checkpoint 2024-11-24 11:03:06 -06:00
koniifer 5ea3ee9fe1 able sanity check 2024-11-24 16:39:24 +00:00
Able 241139f5af changes 2024-11-24 10:18:09 -06:00
Able 5c4056bc5c commit checkpoint 2024-11-24 10:00:24 -06:00
peony 5028062e39 Merge branch 'master' of https://git.ablecorp.us/AbleOS/ableos 2024-11-24 13:32:27 +01:00
peony f7f9fece4f Merged once more 2024-11-24 13:31:57 +01:00
able b505622601 Merge pull request 'Ktest + Nix Flake' (#20) from FunkyEgg/ableos:master into master
Reviewed-on: https://git.ablecorp.us/AbleOS/ableos/pulls/20
2024-11-23 21:13:23 -06:00
funky 80ae717dd9 Introduced kernel testing system ktest
This commit also fixed a small issue with panic handler formatting
2024-11-24 11:21:39 +11:00
funky ab8b2309ae Nix Flake Support
nix-shell is broken on both my systems, so better be safe than sorry.
2024-11-24 11:12:24 +11:00
koniifer 7b7e02976d random change 2024-11-23 18:06:48 +00:00
koniifer c1c02ffefd silly string 2024-11-23 16:51:39 +00:00
peony f4ceab972c Merge branch 'master' of https://git.ablecorp.us/AbleOS/ableos 2024-11-23 17:13:04 +01:00
able 8602ceb0d3 nightly revert 2024-11-23 04:59:32 -06:00
peony 96c07e137b Removed error.error because its in #aos-geeral. 2024-11-18 20:47:46 +01:00
peony d78878a12f Compiler error 2024-11-18 20:29:51 +01:00
Able 6b673bc7e6 labels now have bg/fg color 2024-11-18 09:19:04 -06:00
peony 8f265ebf40 PS/2 literally almost work 2024-11-17 22:59:05 +01:00
peony 3d5a8f6f10 End meeeee 2024-11-17 22:38:07 +01:00
peony f11122e58e Merge master 2024-11-17 21:31:51 +01:00
peony 2fdede7199 PS/2 workkkk 2024-11-17 21:30:58 +01:00
koniifer 0af4d142a4 bad process spawning, compiler updates 2024-11-17 20:29:32 +00:00
peony 13422dfd9f Merge branch 'master' of https://git.ablecorp.us/AbleOS/ableos 2024-11-17 19:11:33 +01:00
peony 90a97cd160 more work 2024-11-17 19:11:13 +01:00
peony 23b45b1887 Driver workkkk 2024-11-17 17:57:06 +01:00
koniifer 36f0d357cf arm cpuid fix 2024-11-17 10:52:13 +00:00
peony cf37eaf086 Merge branch 'master' of https://git.ablecorp.us/AbleOS/ableos 2024-11-17 11:17:59 +01:00
peony 284aa5a5e6 PS/2 is so close 2024-11-17 11:17:32 +01:00
koniifer ccddf36050 fix 2024-11-17 10:11:14 +00:00
peony 11976b752f PS/2 driver going well (it still doesn't work) 2024-11-16 22:56:00 +01:00
peony 98b15d4c10 Merge master 2024-11-16 21:52:45 +01:00
peony f5c6d7d822 PS/2 driver refactoring and poassibly completion process 2024-11-16 21:51:55 +01:00
koniifer da5f1a7a19 compiler update 2024-11-16 20:42:16 +00:00
koniifer 2808bc9e7c various fixes, update to latest rust nightly 2024-11-16 16:34:45 +00:00
koniifer d958a103fa fix 2024-11-16 09:34:17 +00:00
koniifer ee82bc5705 minor changes 2024-11-16 09:30:53 +00:00
Able 3d53b641bf interrupt work 2024-11-16 02:51:58 -06:00
peony efcd6c0631 Uuugh, jesus this sucks 2024-11-15 22:55:44 +01:00
peony b795aced8e Merge branch 'master' of https://git.ablecorp.us/AbleOS/ableos 2024-11-15 20:48:23 +01:00
peony 08099b0877 Barely any PS/2 driver work 2024-11-15 20:47:11 +01:00
koniifer cea7f1fa5c use new register allocator by default 2024-11-15 19:46:36 +00:00
Able 614bef7ec5 ok now there is colors 2024-11-14 18:40:44 -06:00
Able b0f6aa53bd Mouse updates 2024-11-14 18:33:29 -06:00
Able d5f4ce18a3 push changes 2024-11-14 18:09:54 -06:00
koniifer 907c0d0dd4 multi-client support and demo 2024-11-14 21:28:21 +00:00
koniifer 95b4a921dc improve & optimise window decoration code 2024-11-14 16:43:23 +00:00
koniifer b6261d014d bad frame synchronisation implementation 2024-11-13 23:08:20 +00:00
Able 56ee0fe851 misc 2024-11-13 14:17:15 -06:00
koniifer b07bac1f1f broken 2024-11-13 17:03:31 +00:00
peony a1bfd8e85f Driver not work 2024-11-12 22:36:43 +01:00
koniifer dc9273b3c1 various opts and keeping on top of compiler changes 2024-11-12 20:14:37 +00:00
Able e6d8f5c822 todo changes 2024-11-11 17:49:11 -06:00
koniifer 8ad7542b9c sunset work, stn changes, and fiddling with kernel logging clutter 2024-11-11 21:48:43 +00:00
Able e40a22fccd Commit 2024-11-11 01:23:14 -06:00
koniifer cf917927a5 incomplete sunset redesign 2024-11-11 01:03:01 +00:00
peony edfb588060 Merge main. 2024-11-10 21:26:54 +01:00
peony cc4a32afaa PS/2 work 2024-11-10 21:24:19 +01:00
koniifer 97ceb12d6e double skill issue 2024-11-10 20:07:03 +00:00
koniifer bae58ade61 skill issue fix 2024-11-10 20:04:49 +00:00
koniifer b21c05e924 compiler bugfix 2024-11-10 19:37:37 +00:00
Able 2f5bc73665 The List 2024-11-10 13:13:38 -06:00
Able 0003464099 sunsetting sunset 2024-11-10 13:00:41 -06:00
koniifer 77a708d41e sunrising sunset 2024-11-10 18:57:48 +00:00
peony be6a095c14 Cargo stuff 2024-11-10 19:14:20 +01:00
peony 3409f5051a Circle rendering support (janky) (#18)
circle rendering
Reviewed-on: https://git.ablecorp.us/AbleOS/ableos/pulls/18
Co-authored-by: peony <peony@email.com>
Co-committed-by: peony <peony@email.com>
2024-11-10 09:03:14 -06:00
peony aac1164d55 More git stuff 2024-11-10 15:45:01 +01:00
peony 89d08d8a62 Alighning with master. 2024-11-10 15:44:17 +01:00
peony 8f5833955f Circle test. (Precision issues) 2024-11-10 15:42:41 +01:00
peony 4c0adbe15d Circle rendring. 2024-11-10 15:19:55 +01:00
peony 3708acc077 Revert to mainline 2024-11-10 15:09:41 +01:00
peony b5b122f451 Complete revert to mainline, I think? 2024-11-10 15:04:59 +01:00
Able 8c7b95277d reorg 2024-11-10 06:18:23 -06:00
koniifer 7da32b263f make the cursor more visible 2024-11-10 11:58:42 +00:00
Able 2439722c88 misc 2024-11-10 05:52:51 -06:00
koniifer 3333b1706f minor optimisations 2024-11-10 11:48:55 +00:00
Able 8808ed5bfe misc 2024-11-10 04:33:50 -06:00
koniifer 68d3236cc0 misc 2024-11-10 10:11:40 +00:00
Able eea23d967b mouse cursor functional 2024-11-10 02:36:37 -06:00
Able d2152537ad clean up 2024-11-09 22:34:24 -06:00
Able 7723799e76 changes or something idk 2024-11-09 20:44:10 -06:00
koniifer 8b04b275f3 text editor is actually a text editor 2024-11-09 01:54:33 +00:00
Able 1345f294b8 changes 2024-11-08 14:42:58 -06:00
Able 818bcb458f widgets 2024-11-08 10:29:06 -06:00
Able d2b5f09511 changes + lui examples 2024-11-08 10:16:24 -06:00
Jakub Doka 2676bd7b62
fixing error messages 2024-11-08 15:04:10 +01:00
koniifer 444fcdb0c4 more text editor work 2024-11-08 13:47:24 +00:00
koniifer adbf32d970 text editor work and misc changes 2024-11-08 01:48:17 +00:00
Able 7f01b0e0f8 👍 2024-11-07 09:57:50 -06:00
Able e8edee4ccc broken 👍 2024-11-07 09:57:39 -06:00
koniifer ba59233ce7 untested string.contains(haystack, needle) 2024-11-07 02:22:58 +00:00
Able f13c682171 refactor and widgeting magic 2024-11-06 20:11:36 -06:00
Able b6b097a872 widgeting work 2024-11-06 19:57:47 -06:00
koniifer 6a8d92d2c2 mostly qoi image support
refactor image loader for multiple filetypes
port some broken math stuff
make logger more readable
2024-11-07 01:55:29 +00:00
Able ab8522fbe1 widget UI 2024-11-06 11:43:40 -06:00
Able a49ac7bca0 Label Widget inside horizon 2024-11-06 09:36:17 -06:00
Able 12883ac926 Remove busy loop 2024-11-05 23:04:29 -06:00
Able 6a319c55b0 Proper Y direction 2024-11-05 23:01:15 -06:00
Able 879bbfa173 rework logic 2024-11-05 23:01:06 -06:00
Able 795f10986f Add partial support for sending mouse position updates 2024-11-05 22:58:52 -06:00
Able 85e63eb51c Add backspace 2024-11-05 22:16:08 -06:00
koniifer aafe047b51 forgor 2024-11-06 01:50:28 +00:00
koniifer 404ea22c46 rebase 2024-11-06 01:49:57 +00:00
koniifer 664334fd00 unicode stuff for psf rendering
make silly keyboard app
2024-11-06 01:47:33 +00:00
Able 086948d47a rename 2024-11-03 19:53:09 -06:00
Able b795215b62 enable horizon and ps2 driver 2024-11-03 19:38:40 -06:00
Able 16135ae536 mouse render 2024-11-03 18:37:39 -06:00
Able 941eed0ac9 patch 2024-11-03 18:34:48 -06:00
Able f4ad4b6856 mouse driver 2024-11-03 16:48:36 -06:00
koniifer 9e83707a28 misc changes 2024-11-03 22:31:53 +00:00
Able 6894ef2360 keycode nonsense 2024-11-02 11:09:31 -05:00
Able 69c95c35b5 fix serial argument 2024-11-01 17:37:47 -05:00
Able 80d363bc59 panic func in stn 2024-11-01 15:11:33 -05:00
Able 3c3c156eb0 misc changes + mouse driver work 2024-11-01 13:09:12 -05:00
koniifer eaace7d9c1 unoptimised text load & render 2024-10-26 09:23:28 +01:00
koniifer 5af5631755 minor changes 2024-10-25 16:37:38 +01:00
Able fac573837f Work 2024-10-25 09:17:37 -05:00
koniifer 6ff65eee41 kaboom 2024-10-23 21:49:40 +01:00
koniifer b35b430047 display_int radices 2024-10-20 13:31:44 +01:00
koniifer bcfaf89ed0 fix buffer mutating message 2024-10-20 12:36:34 +01:00
koniifer 2ba2dcb464 change logger message format so it doesn't mutate the string 2024-10-20 12:11:29 +01:00
koniifer 41d9c0b82a miscellaneous changes, free performance tweaks, and fiddle with enabling avx finally 2024-10-19 19:45:41 +01:00
koniifer a94332370a various render changes, implement sine & cosine for stn.math 2024-10-19 15:54:19 +01:00
koniifer 7caa47b9fb make surface example cooler 2024-10-17 15:31:42 +01:00
Able 34101d2e8c Windowing changes 2024-10-15 20:30:24 -05:00
Able 2bc13cd7d8 fix 👍 2024-10-15 18:06:37 -05:00
koniifer 086cc4aef0 patch minor logging bug 2024-10-16 00:03:23 +01:00
Able 84f86488c7 buggy code 2024-10-15 17:25:11 -05:00
Able ed7c8f20cb animal crossing new Horizon beginnings 2024-10-15 17:06:38 -05:00
koniifer 34cbd9a5e6 fiddling 2024-10-15 21:43:23 +01:00
koniifer 0ebb1f200e make surface example more interesting, optimise memory filling 2024-10-15 21:11:06 +01:00
Able fc06820332 fix visibility 2024-10-15 03:44:12 -05:00
koniifer 2a082d8283 rudimentary render surfaces 2024-10-15 01:24:29 +01:00
koniifer 1eee33ce8b fix icky pointer misalignment
move dt_api to stn for ease of use
do away with now redundant strobe example (colour example is basically strobe now)
2024-10-14 18:54:53 +01:00
peony 39ebaa03ba Uuuugh 2024-10-14 14:35:41 +02:00
Able 6fa1c829fd Horizon work 2024-10-13 22:34:33 -05:00
koniifer 820c3e459b optimisations 2024-10-14 01:31:23 +01:00
koniifer 3af28f1666 use able image 2024-10-13 23:41:17 +01:00
koniifer 96c2bd5cd5 bitmap image support & better mem opts
restructure render lib
add peony's render api additions and example
add image example
fix some dubious bugs i had made in unused code in mem_serve.rs
remove tetris stub (now in peony's fork)
update hblang
2024-10-13 23:38:43 +01:00
peony de8000f596 Fixed software renderer; added vline,hline,trirect 2024-10-13 23:15:10 +02:00
koniifer ea8eca1089 various stn & render-api changes 2024-10-12 21:39:09 +01:00
koniifer 7f4a040505 WIP help doc 2024-10-12 15:53:32 +01:00
koniifer 82f5cdbe21 add --noaccel flag to disable vm acceleration, update repbuild help 2024-10-12 15:02:55 +01:00
koniifer aac6d61dc6 stupid fix 2024-10-12 13:39:23 +01:00
koniifer 3df6f18c85 fix buffers
update hblang
auto cpu feature detection for repbuild
less verbose buffer api
add peony's tetris stub
2024-10-12 13:35:49 +01:00
koniifer 07ee8de9f1 push it to prod 😄
experimental avx stuff (enable it yourself, coward)
update hblang & fiddle with stuff
2024-09-30 21:45:57 +01:00
Able f64f654610 Device work 2024-09-21 19:20:38 -05:00
Able 7d4b12a103 remove debugging info + fix the updating of hbvm 2024-09-21 19:20:14 -05:00
Able 758629df0a thumbs up 2024-09-20 05:06:08 -05:00
Able 04a449965b + 2024-09-20 04:02:58 -05:00
koniifer 0bbc76124f minor changes, svga work 2024-09-19 20:40:10 +01:00
Able 6ad68dabac hblang executable format update 2024-09-19 07:11:57 -05:00
Able 07c7d52b8c misc 2024-09-19 06:05:11 -05:00
Able 2edc8148ca no merge whamies pls 2024-09-18 03:41:41 -05:00
mlokr 5f59f05dce
removing deprecated rel: path prefix 2024-09-18 10:38:49 +02:00
Able 0bc757164f Input work 2024-09-17 19:26:37 -05:00
Able f5f68bc2df my changes and then boom 2024-09-17 17:23:32 -05:00
Able 7a256dde68 single file change 2024-09-17 12:08:19 -05:00
Able 570b566310 svga device struct updated to mostly reflect real device 2024-09-17 10:02:43 -05:00
Able d2488689fe fixs 2024-09-17 09:52:27 -05:00
Able fe70d81bd0 fat32 stub 2024-09-17 09:49:19 -05:00
Able cc076d9540 pumpkin print 2024-09-17 09:48:10 -05:00
Able 3173b63c93 minor changes 2024-09-17 09:47:53 -05:00
koniifer 48027196b1 omfg it's fixed 🙏 2024-09-17 09:47:53 -05:00
koniifer 78553a3190 let's just use strings for now 2024-09-17 09:47:11 -05:00
koniifer df74b09134 please bugs begone 2024-09-17 09:47:11 -05:00
koniifer 2321efd2e7 bug squashing & testing 2024-09-17 09:46:31 -05:00
Able d9caa17f3c commits 2024-09-17 09:39:46 -05:00
Able b0ecbfa168 fat32 stub 2024-09-17 08:01:16 -05:00
Able 1fe20360f6 pumpkin print 2024-09-16 20:59:24 -05:00
Able fb42351638 minor changes 2024-09-16 20:45:00 -05: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
270 changed files with 9758 additions and 2368 deletions

View file

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

View file

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

Binary file not shown.

1564
Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

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

69
HELP.md Normal file
View file

@ -0,0 +1,69 @@
### What are the requirements?
- A machine with [Rustc Tier 1 platform support](https://doc.rust-lang.org/nightly/rustc/platform-support.html#tier-1-with-host-tools)
- Rustup
- QEMU (for executing)
- GIT CLI
### How do I run ableos?
- It is recommended to run ableos under QEMU. Here is how:
- Install QEMU
- Clone ableos
- Go to ableos directory
- Pull the limine submodule with `git submodule update --init`
- Run `cargo repbuild help`
### How can I contribute?
- [Contribute code](#how-do-i-contribute-code)
- [Run ableos on your machine](#how-do-i-run-ableos)
- Find bugs
- Create media showing ableos
### How do I contribute code?
- Start by forking ableos
- Write something that runs in the userspace, for example:
- System drivers
- Programs
- Libraries
- Patch bugs and improve code in the kernel
- Ensure that the code is OK to be maintained by asking in the [discord](https://discord.gg/t5Wt3K4YNA)
- When you have finished your changes, you can submit a pull request for review [here](https://git.ablecorp.us/ableos/ableos)
### repbuild and kernel compile, but QEMU isn't starting
- Ensure you have the `qemu-desktop-{arch}` for your OS and target architecture installed
- Try running again with `--noaccel` if you have QEMU already
### I have run using repbuild but it's slow
- Ensure release mode is enabled with the `-r` flag
- Remove the `--noaccel` flag if you can
- If both of these are already done, there may be a problem with thee VM, kernel, your program, or the hblang compiler
### Compiler is complaining about "reg id leaked"
- [Submit](#how-do-i-report-a-compiler-bug) an issue, reg id leaked is a bug
### My program isn't running
- Refer to [here](#i-have-run-using-repbuild-but-its-slow), it may be that your program is simply starting slowly
- Ensure that your program has a properly written meta.toml file
- Ensure that your program is enabled in [system_config.toml](sysdata/system_config.toml)
- Try running again with `--noaccel`, there is a known bug with some systems that prevents programs from starting.
### Kernel panic??? Huh???
- Kernel panics can be caused by improperly using memory (e.g, writing out of bounds)
- Kernel panics are most likely to be caused when accessing memory or using `@eca` for kernel ecalls
- [Report](#how-do-i-report-an-ableos-bug) a kernel panic
### I am running in release mode but I have no debug info
- Add the `-d` flag for debug info
### What is `@eca`? How do I use it?
- Eca is an ecall. They are similar to syscalls
- The `@eca` directive takes the following arguments:
- `@eca(ecall_number, reg_1, ..., reg_n)`
- The various ecalls have different arguments that are given by register values
- Most ecalls are wrapped by `stn`, for example, `random`, `buffer`, and `memory` all make use of ecalls
- All ecalls can be found [ecah.rs](kernel/src/holeybytes/ecah.rs)
### How do I report an ableos bug?
- Submit an issue [here](https://git.ablecorp.us/ableos/ableos/issues) or report it in the [discord](https://discord.gg/t5Wt3K4YNA)
### How do I report a compiler bug?
- Submit an issue [here](https://git.ablecorp.us/ableos/holey-bytes/issues) or report it in the [discord](https://discord.gg/t5Wt3K4YNA)

View file

@ -1,6 +1,8 @@
# AbleOS
An UNIX-unlike micro-kernel written in rust with an embedded bytecode virtual machine.
Please note that a custom target directory is not supported and support will not be added.
# Community
[Discord](https://discord.gg/JrKVukDtgs)
@ -8,11 +10,7 @@ Donations can be made [here on Liberapay](https://liberapay.com/AbleTheAbove) or
<img src="https://img.shields.io/liberapay/patrons/AbleTheAbove.svg?logo=liberapay">
# 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).
See [HELP.md](HELP.md)
For running AbleOS, `repbuild` uses QEMU.
## Steps
1. `git submodule update --init`
2. `cargo repbuild`
# Developing
There is a new work in progress developer tool for hblang. (see: dev folder)

77
STYLE_GUIDE.md Normal file
View file

@ -0,0 +1,77 @@
# Style Guide
This style guide has two modes that a guideline may be.
`strict` means that prs will be rejected if they do not follow the guideline.
`loose` means that a pr would be accepted but should later be fixed.
## Empty Functions | loose
Empty functions are typically a sign of an unfinished program or driver.
In cases where there is a clear reason to have an empty function it will be allowed.
For example FakeAlloc is only empty functions because it is a example of an the allocator api.
### Allowed
```rust
/// in example.hb
a := fn(): void {}
```
### Not Allowed
```rust
/// in fat32.hb
a := fn(): void {}
```
## Magic Functions | loose
'Magic functions' are what I am calling small helper functions that do one or two things.
### Example
```rust
a := null
magic_a := fn(){
a = 10
}
```
The exact policy I want to have here is a bit fuzzy. I think that functions like this are nice in certain situations and not in others.
Regardless of if you use them or not, put a comment above the function explaining rational.
## Magic Numbers | loose
The policy on magic numbers is make them const and have a comment above them. Typically linking to a source of information about the magic number.
This helps cut down on magic numbers while making acceptable names and atleast half assed documentation.
Constants are inlined anyways, so its the same thing in the binary.
```rust
// The standard vga port is mapped at 0xB8000
$VGA_PTR := 0xB8000
```
## Tabs Vs Spaces | strict
I prefer for hblang code to use hard tabs.
The rational behind this is that a tab is `1 Indent` which some developers might want to be various different sizes when displayed
Soft tabs do not allow this user/editor specific as soft tabs always become spaces.
Bottom line is this is an accessibility feature.
There are some samples below.
```
\t means hard tab
\n means new line
\0x20 means space
```
### Allowed
```rust
if x == y {\n
\tlog(z)\n
}\n
```
### Not Allowed
```rust
if x == y {\n
\0x20\0x20\0x20\0x20log(z)\n
}\n
```

View file

@ -1,31 +0,0 @@
[boot]
# This package must be installed system wide
init = "init_server"
[boot.limine]
default_entry = 1
timeout = 0
verbose = true
interface_resolution = "1024x768x24"
# Terminal related settings
term_wallpaper = "boot:///background.bmp"
term_background = "008080"
[boot.limine.ableos]
comment = "Default AbleOS boot entry."
protocol = "limine"
kernel_path = "boot:///kernel"
kernel_cmdline = "baka=false foobles=true"
resolution = "1024x768x24"
[repositories]
core = "https://git.ablecorp.us/AbleOS/core"
userspace = "https://git.ablecorp.us/AbleOS/ableos_userland"
[packages]
[packages.init_server]
version = "1.0"
hash = ""
repo = "core"

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
}
}

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

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

96
flake.lock Normal file
View file

@ -0,0 +1,96 @@
{
"nodes": {
"flake-utils": {
"inputs": {
"systems": "systems"
},
"locked": {
"lastModified": 1731533236,
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1732014248,
"narHash": "sha256-y/MEyuJ5oBWrWAic/14LaIr/u5E0wRVzyYsouYY3W6w=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "23e89b7da85c3640bbc2173fe04f4bd114342367",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs_2": {
"locked": {
"lastModified": 1728538411,
"narHash": "sha256-f0SBJz1eZ2yOuKUr5CA9BHULGXVSn6miBuUWdTyhUhU=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "b69de56fac8c2b6f8fd27f2eca01dcda8e0a4221",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixpkgs-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"flake-utils": "flake-utils",
"nixpkgs": "nixpkgs",
"rust-overlay": "rust-overlay"
}
},
"rust-overlay": {
"inputs": {
"nixpkgs": "nixpkgs_2"
},
"locked": {
"lastModified": 1732328983,
"narHash": "sha256-RHt12f/slrzDpSL7SSkydh8wUE4Nr4r23HlpWywed9E=",
"owner": "oxalica",
"repo": "rust-overlay",
"rev": "ed8aa5b64f7d36d9338eb1d0a3bb60cf52069a72",
"type": "github"
},
"original": {
"owner": "oxalica",
"repo": "rust-overlay",
"type": "github"
}
},
"systems": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
}
},
"root": "root",
"version": 7
}

30
flake.nix Normal file
View file

@ -0,0 +1,30 @@
{
description = "A devShell example";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
rust-overlay.url = "github:oxalica/rust-overlay";
flake-utils.url = "github:numtide/flake-utils";
};
outputs = { self, nixpkgs, rust-overlay, flake-utils }:
flake-utils.lib.eachDefaultSystem (system:
let
overlays = [ (import rust-overlay) ];
pkgs = import nixpkgs {
inherit system overlays;
};
rustToolchain = pkgs.pkgsBuildHost.rust-bin.fromRustupToolchainFile ./rust-toolchain.toml;
in
with pkgs;
{
devShells.default = mkShell {
buildInputs = [
rustToolchain
qemu_full
];
};
}
);
}

View file

@ -4,6 +4,3 @@ build-std-features = ["compiler-builtins-mem"]
[build]
target = "./targets/x86_64-ableos.json"
[target.'cfg(target_arch = "x86_64")']
rustflags = ["-C", "target-feature=+rdrand"]

View file

@ -3,57 +3,54 @@ edition = "2021"
name = "kernel"
version = "0.2.0"
[features]
ktest = []
[dependencies]
embedded-graphics = "0.7"
hbvm.git = "https://git.ablecorp.us/ableos/holey-bytes"
log = "0.4"
spin = "0.9"
uart_16550 = "0.2"
slab = { version = "0.4", default-features = false }
xml.git = "https://git.ablecorp.us/ableos/ableos_userland"
versioning.git = "https://git.ablecorp.us/ableos/ableos_userland"
able_graphics_library.git = "https://git.ablecorp.us/ableos/ableos_userland"
hashbrown = "*"
kiam = "0.1.1"
[dependencies.limine]
version = "0.1"
git = "https://github.com/limine-bootloader/limine-rs"
# embedded-graphics = "0.8"
hbvm = { git = "https://git.ablecorp.us/AbleOS/holey-bytes.git", features = [
"nightly",
] }
ktest_macro = { path = "ktest_macro" }
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.15", features = ["nightly"] }
limine = "0.1"
[dependencies.crossbeam-queue]
version = "0.3"
default-features = false
features = ["alloc"]
[dependencies.clparse]
git = "https://git.ablecorp.us/ableos/ableos_userland"
version = "0.3"
default-features = false
features = ["alloc", "nightly"]
[dependencies.derive_more]
version = "0.99"
version = "1"
default-features = false
features = [
"add",
"add_assign",
"constructor",
"display",
"from",
"into",
"mul",
"mul_assign",
"not",
"sum",
"add",
"add_assign",
"constructor",
"display",
"from",
"into",
"mul",
"mul_assign",
"not",
"sum",
]
[target.'cfg(target_arch = "x86_64")'.dependencies]
x86_64 = "0.14"
x86_64 = "0.15"
x2apic = "0.4"
virtio-drivers = "0.4.0"
# rdrand = "*"
rdrand = { version = "0.8", default-features = false }
# 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

@ -0,0 +1,11 @@
[package]
edition = "2021"
name = "ktest_macro"
version = "0.1.0"
[lib]
proc-macro = true
[dependencies]
quote = "1.0.37"
syn = { version = "2.0.89", features = ["full"] }

View file

@ -0,0 +1,86 @@
extern crate proc_macro;
extern crate quote;
extern crate syn;
use {
proc_macro::TokenStream,
quote::quote,
syn::{parse::Parse, parse_macro_input, Expr, ItemFn, Token}
};
struct KtestInput {
lhs: Expr,
_comma: Token![,],
rhs: Expr,
}
impl Parse for KtestInput {
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
Ok(Self {
lhs: input.parse()?,
_comma: input.parse()?,
rhs: input.parse()?,
})
}
}
#[proc_macro]
pub fn ktest_eq(item: TokenStream) -> TokenStream {
let input = parse_macro_input!(item as KtestInput);
let lhs = input.lhs;
let rhs = input.rhs;
let out = quote! {
if #lhs != #rhs {
return Err(name);
}
};
TokenStream::from(out)
}
#[proc_macro]
pub fn ktest_neq(item: TokenStream) -> TokenStream {
let input = parse_macro_input!(item as KtestInput);
let lhs = input.lhs;
let rhs = input.rhs;
let out = quote! {
if #lhs == #rhs {
return Err(name);
}
};
TokenStream::from(out)
}
#[proc_macro_attribute]
pub fn ktest(_attr: TokenStream, item: TokenStream) -> TokenStream {
let input = parse_macro_input!(item as ItemFn);
let test_name = &input.sig.ident;
let test_string = test_name.to_string();
let static_var_name = syn::Ident::new(
&format!("__ktest_{}", test_name).to_uppercase(),
test_name.span(),
);
let block = &input.block;
let out = quote! {
#[cfg(feature = "ktest")]
fn #test_name() -> Result<String, String> {
use crate::alloc::string::ToString;
let name = #test_string.to_string();
#block
return Ok(name);
}
#[cfg(feature = "ktest")]
#[unsafe(link_section = ".note.ktest")]
#[used]
pub static #static_var_name: fn() -> Result<String, String> = #test_name;
};
TokenStream::from(out)
}

View file

@ -6,6 +6,11 @@ SECTIONS
.text.boot : { *(.text.boot) }
.text : { *(.text) }
.data : { *(.data) }
.note.ktest : {
__ktest_start = .;
*(.note.ktest)
__ktest_end = .;
}
.rodata : { *(.rodata) }
.bss : {
*(COMMON)

View file

@ -38,7 +38,15 @@ SECTIONS
.data : {
*(.data .data.*)
*(.got .got.*)
} :data
/* Add the .ktest section for test functions */
.note.ktest : {
__ktest_start = .; /* Mark the beginning of the section */
*(.note.ktest) /* Include all items in the .ktest section */
__ktest_end = .; /* Mark the end of the section */
}
.bss : {
*(COMMON)

View file

@ -324,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
}
@ -345,3 +345,7 @@ fn alloc_error_handler(layout: alloc::alloc::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

@ -1,6 +1,5 @@
use {
crate::{alloc::string::ToString, device_tree::DeviceTree, kmain::DEVICE_TREE},
alloc::string::String,
crate::{device_tree::DeviceTree, kmain::DEVICE_TREE},
core::arch::asm,
xml::XMLElement,
};
@ -28,8 +27,8 @@ fn collect_cpu_info(device_tree: &mut DeviceTree) {
cpus.push(cpu);
}
fn cpu_id() -> (String, u64) {
let mut cpu_id: u64 = 0;
fn cpu_id<'a>() -> (&'a str, u64) {
let mut cpu_id: u64;
unsafe {
asm!("mrs {cpu_id}, MIDR_EL1",
cpu_id = out(reg) cpu_id,
@ -39,9 +38,11 @@ fn cpu_id() -> (String, u64) {
let cpu_name = match cpu_id {
// the source of these two was a stackoverflow question
// https://raspberrypi.stackexchange.com/questions/117175/how-do-i-read-the-cpuid-in-aarch64-asm
0x410FD034 => "Cortex-A53".to_string(),
0x410FD083 => "Cortex-A72".to_string(),
_ => "Unknown".to_string(),
0x410FD034 => "Cortex-A53",
0x410FD083 => "Cortex-A72",
// the source of this one was checking the cpu id :thinking:
0x410FD493 => "Neoverse N2",
_ => "Unknown",
};
log::trace!("CPU Name: {cpu_name} - CPU ID: 0x{:X}", cpu_id);

View file

@ -1,9 +1,9 @@
use {crate::logger::TERMINAL_LOGGER, core::fmt::Write, spin::Mutex};
const SERIAL_CONSOLE: Mutex<SerialConsole> = Mutex::new(SerialConsole {
pub static SERIAL_CONSOLE: Mutex<SerialConsole> = Mutex::new(SerialConsole {
uart: 0x09000000 as *mut u8,
});
struct SerialConsole {
pub struct SerialConsole {
uart: *mut u8,
}
@ -17,9 +17,12 @@ impl core::fmt::Write for SerialConsole {
}
}
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)?;
// TERMINAL_LOGGER.lock().write_fmt(args)?;
Ok(())
}

View file

@ -1,6 +1,7 @@
pub use logging::log;
use {
crate::{allocator, bootmodules::BootModule, kmain::kmain},
alloc::vec::Vec,
core::arch::asm,
limine::FramebufferRequest,
};
@ -41,7 +42,7 @@ unsafe extern "C" fn _kernel_start() -> ! {
static KFILE_REQ: KernelFileRequest = KernelFileRequest::new(0);
static MOD_REQ: ModuleRequest = ModuleRequest::new(0);
let mut bootmodules = alloc::vec::Vec::new();
let mut bootmodules = Vec::new();
if bm.is_some() {
let bm = bm.unwrap();
@ -52,18 +53,13 @@ unsafe extern "C" fn _kernel_start() -> ! {
let raw_bytes = core::slice::from_raw_parts(
file.base.as_ptr().expect("invalid initrd"),
file.length as usize,
)
.to_vec();
let file_path = alloc::string::String::from_utf8(
file.path.to_str().unwrap().to_bytes().to_vec(),
);
let file_path = file.path.to_str().unwrap().to_str();
if file_path.is_err() {
panic!("invalid file path: {:?}", file_path);
}
let file_cmd = alloc::string::String::from_utf8(
file.cmdline.to_str().unwrap().to_bytes().to_vec(),
);
let file_cmd = file.cmdline.to_str().unwrap().to_str();
if file_cmd.is_err() {
panic!("invalid module cmd: {:?}", file_cmd);
}
@ -85,7 +81,7 @@ unsafe extern "C" fn _kernel_start() -> ! {
assert_eq!(bm.module_count, bootmodules.len() as u64);
}
crate::kmain::kmain(
kmain(
KFILE_REQ
.get_response()
.get()
@ -99,8 +95,6 @@ unsafe extern "C" fn _kernel_start() -> ! {
.unwrap_or_default(),
bootmodules,
);
spin_loop();
}
pub fn spin_loop() -> ! {
@ -109,8 +103,19 @@ pub fn spin_loop() -> ! {
}
}
/// I am sorry.
static mut A_REAL_RANDOM_U64_I_PROMISE: u64 = 0;
pub fn hardware_random_u64() -> u64 {
0
if let Some(rng) = aarch64_cpu::asm::random::ArmRng::new() {
if let Some(rnd) = rng.rndr() {
return rnd;
}
}
unsafe {
A_REAL_RANDOM_U64_I_PROMISE += 1;
A_REAL_RANDOM_U64_I_PROMISE
}
}
pub fn register_dump() {}

View file

@ -14,3 +14,29 @@ arch_cond!(
riscv64: "riscv64",
x86_64: "x86_64",
);
#[cfg(target_arch = "x86_64")]
use {crate::arch::interrupts::Interrupt, alloc::string::String};
#[cfg(target_arch = "x86_64")]
pub struct InterruptList {
list: HashMap<Interrupt, String>,
}
#[cfg(target_arch = "x86_64")]
use hashbrown::HashMap;
#[cfg(target_arch = "x86_64")]
impl InterruptList {
pub fn new() -> Self {
Self {
list: HashMap::new(),
}
}
}
#[cfg(target_arch = "x86_64")]
use spin::{Lazy, Mutex};
#[cfg(target_arch = "x86_64")]
pub static INTERRUPT_LIST: Lazy<Mutex<InterruptList>> = Lazy::new(|| {
let mut il = InterruptList::new();
use crate::alloc::string::ToString;
il.list.insert(Interrupt::Timer, "PS/2 Mouse".to_string());
Mutex::new(il)
});

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,7 +1,7 @@
mod memory;
use {
alloc::boxed::Box,
alloc::{boxed::Box, vec::Vec},
core::{
arch::{asm, global_asm},
fmt::Write,
@ -45,7 +45,7 @@ extern "C" {
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 "C" fn _kernel_start() -> ! {
@ -95,7 +95,7 @@ unsafe extern "C" fn _kernel_start() -> ! {
in(reg) satp_value,
);
crate::kmain::kmain("baka=9", None);
crate::kmain::kmain("baka=9", Vec::new());
}
/// Spin loop
@ -105,6 +105,12 @@ pub fn spin_loop() -> ! {
}
}
pub fn hardware_random_u64() -> u64 {
0
}
pub fn register_dump() {}
pub fn log(args: core::fmt::Arguments<'_>) -> core::fmt::Result {
SERIAL_CONSOLE.get().unwrap().lock().write_fmt(args)
}

View file

@ -11,6 +11,9 @@ use {
pub const DOUBLE_FAULT_IX: u16 = 0;
const STACK_SIZE: usize = 5 * 1024;
const STACK_ALIGNMENT: usize = 1;
pub unsafe fn init() {
use x86_64::instructions::{
segmentation::{Segment, CS, SS},
@ -32,24 +35,24 @@ struct Selectors {
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)),
kcode: gdt.append(Descriptor::kernel_code_segment()),
kdata: gdt.append(Descriptor::kernel_data_segment()),
tss: gdt.append(Descriptor::tss_segment(&TSS)),
};
(gdt, sels)
});

View file

@ -1,56 +1,54 @@
// TODO: Turn apic keyboard interrupt into a standard ipc message
use {
core::mem::MaybeUninit,
log::trace,
spin::{Lazy, Mutex},
x2apic::lapic::{LocalApic, LocalApicBuilder},
x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame, PageFaultErrorCode},
};
pub unsafe fn init() {
trace!("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 {
Timer = 32,
#[derive(Debug, Eq, Hash, PartialEq)]
pub enum Interrupt {
Timer = 32,
ApicErr = u8::MAX - 1,
Spurious = u8::MAX,
}
pub(crate) 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::ApicErr as usize].set_handler_fn(apic_err);
idt[Interrupt::Spurious as usize].set_handler_fn(spurious);
idt[Interrupt::Timer as usize].set_handler_fn(timer);
idt
});
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:#?}")
@ -64,13 +62,52 @@ extern "x86-interrupt" fn page_fault(
}
extern "x86-interrupt" fn timer(_isf: InterruptStackFrame) {
unsafe { LAPIC.lock().end_of_interrupt() };
interrupt(Interrupt::Timer);
unsafe {
LAPIC.end_of_interrupt();
}
}
extern "x86-interrupt" fn apic_err(_: InterruptStackFrame) {
interrupt(Interrupt::ApicErr);
panic!("Internal APIC error");
}
extern "x86-interrupt" fn spurious(_: InterruptStackFrame) {
unsafe { LAPIC.lock().end_of_interrupt() };
interrupt(Interrupt::Spurious);
unsafe {
LAPIC.end_of_interrupt();
}
}
#[allow(unused_imports)]
fn interrupt(interrupt_type: Interrupt) {
use crate::{arch::INTERRUPT_LIST, kmain::EXECUTOR};
// let il = INTERRUPT_LIST.lock();
// let val = il.list.get(&interrupt_type).unwrap();
// use crate::holeybytes::kernel_services::service_definition_service::sds_search_service;
// let buffer = sds_search_service(val);
// if buffer != 0 {
// use {crate::kmain::IPC_BUFFERS, alloc::vec::Vec};
// let mut buffs = IPC_BUFFERS.lock();
// match buffs.get_mut(&buffer) {
// Some(buff) => {
// let mut msg_vec = Vec::new();
// msg_vec.push(0xFF);
// buff.push(msg_vec.to_vec());
// log::debug!("Sent Message {:?} to Buffer({})", msg_vec, buffer);
// }
// None => {
// log::error!("Access of non-existent buffer {}", buffer)
// }
// }
// }
unsafe {
EXECUTOR.send_interrupt(interrupt_type as u8);
}
}

View file

@ -1,11 +1,6 @@
//! Logging (as in terms of console / serial output)
#![allow(deprecated)]
use {
core::fmt::Write,
limine::{TerminalRequest, TerminalResponse},
spin::{Lazy, Mutex},
uart_16550::SerialPort,
};
use {core::fmt::Write, spin::Mutex, uart_16550::SerialPort};
pub static SERIAL_CONSOLE: Mutex<SerialPort> = Mutex::new(unsafe { SerialPort::new(0x3F8) });

View file

@ -1,7 +1,6 @@
use {
crate::bootmodules::BootModule, core::arch::asm, embedded_graphics::pixelcolor::Rgb888,
log::warn, rdrand::RdSeed,
};
use core::arch::x86_64::{_rdrand64_step, _rdseed64_step};
use {crate::bootmodules::BootModule, core::arch::asm, log::warn};
pub mod memory;
mod cpuid;
@ -11,7 +10,7 @@ pub mod graphics;
pub(crate) mod interrupts;
pub mod logging;
pub mod pci;
pub mod virtio;
// pub mod virtio;
pub use {logging::log, memory::PAGE_SIZE};
@ -31,9 +30,11 @@ const INITIAL_KERNEL_HEAP_SIZE: *const () = _initial_kernel_heap_size as _;
#[no_mangle]
#[naked]
#[cfg(not(target_feature = "avx2"))]
unsafe extern "C" fn _kernel_start() -> ! {
// Initialise SSE and jump to kernel entrypoint
core::arch::asm!(
// Initialise SSE, then jump to kernel entrypoint
core::arch::naked_asm!(
// Initialise SSE
"mov rax, cr0",
"and ax, 0xfffb",
"or ax, 0x2",
@ -41,16 +42,74 @@ unsafe extern "C" fn _kernel_start() -> ! {
"mov rax, cr4",
"or ax, 3 << 9",
"mov cr4, rax",
// Jump to the kernel entry point
"jmp {}",
sym start,
options(noreturn),
)
}
#[no_mangle]
#[naked]
#[cfg(target_feature = "avx2")]
unsafe extern "C" fn _kernel_start() -> ! {
core::arch::naked_asm!(
// Enable protected mode and configure control registers
"mov rax, cr0",
"and ax, 0xFFFB", // Clear CR0.EM (bit 2) for coprocessor emulation
"or ax, 0x2", // Set CR0.MP (bit 1) for coprocessor monitoring
"mov cr0, rax",
"mov rax, cr4",
"or ax, (1 << 9) | (1 << 10)", // Set CR4.OSFXSR (bit 9) and CR4.OSXMMEXCPT (bit 10)
"mov cr4, rax",
// Enable OSXSAVE (required for AVX, AVX2, and XSAVE)
"mov rax, cr4",
"or eax, 1 << 18", // Set CR4.OSXSAVE (bit 18)
"mov cr4, rax",
// Enable AVX and AVX2 state saving
"xor rcx, rcx",
"xgetbv",
"or eax, 7", // Enable SSE, AVX, and AVX2 state saving
"xsetbv",
// Check for AVX and XSAVE support
"mov eax, 1",
"cpuid",
"and ecx, 0x18000000",
"cmp ecx, 0x18000000",
"jne {1}", // Jump if AVX/OSXSAVE is not supported
// Check for BMI2 and AVX2 support
"mov eax, 7",
"xor ecx, ecx",
"cpuid",
"and ebx, (1 << 8) | (1 << 5)", // Check BMI2 (bit 8) and AVX2 (bit 5)
"cmp ebx, (1 << 8) | (1 << 5)", // Compare to ensure both are supported
// Check for LZCNT and POPCNT support
"mov eax, 1",
"cpuid",
"and ecx, (1 << 5) | (1 << 23)", // Check LZCNT (bit 5) and POPCNT (bit 23)
"cmp ecx, (1 << 5) | (1 << 23)", // Compare to ensure both are supported
// Jump to the kernel entry point
"jmp {0}",
sym start,
sym oops,
)
}
unsafe extern "C" fn oops() -> ! {
panic!("your cpu is ancient >:(")
}
unsafe extern "C" fn start() -> ! {
logging::init();
crate::logger::init().expect("failed to set logger");
log::info!("Initialising AKern {}", crate::VERSION);
log::debug!("Initialising AKern {}", crate::VERSION);
static HDHM_REQ: HhdmRequest = HhdmRequest::new(0);
memory::init_pt(VirtAddr::new(
@ -129,7 +188,7 @@ unsafe extern "C" fn start() -> ! {
// TODO: Add in rdseed and rdrand as sources for randomness
let _rand = xml::XMLElement::new("Random");
log::trace!("Getting boot modules");
log::debug!("Getting boot modules");
let bm = MOD_REQ.get_response().get();
let mut bootmodules = alloc::vec::Vec::new();
@ -143,18 +202,13 @@ unsafe extern "C" fn start() -> ! {
let raw_bytes = core::slice::from_raw_parts(
file.base.as_ptr().expect("invalid initrd"),
file.length as usize,
)
.to_vec();
let file_path = alloc::string::String::from_utf8(
file.path.to_str().unwrap().to_bytes().to_vec(),
);
let file_path = file.path.to_str().unwrap().to_str();
if file_path.is_err() {
panic!("invalid file path: {:?}", file_path);
}
let file_cmd = alloc::string::String::from_utf8(
file.cmdline.to_str().unwrap().to_bytes().to_vec(),
);
let file_cmd = file.cmdline.to_str().unwrap().to_str();
if file_cmd.is_err() {
panic!("invalid module cmd: {:?}", file_cmd);
}
@ -172,7 +226,7 @@ unsafe extern "C" fn start() -> ! {
break;
}
}
log::info!("Boot module count: {:?}", bootmodules.len());
log::debug!("Boot module count: {:?}", bootmodules.len());
assert_eq!(bm.module_count, bootmodules.len() as u64);
}
@ -195,32 +249,21 @@ unsafe extern "C" fn start() -> ! {
/// Spin loop
pub fn spin_loop() -> ! {
loop {
x86_64::instructions::hlt();
core::hint::spin_loop();
x86_64::instructions::hlt()
}
}
pub fn hardware_random_u64() -> u64 {
use {log::trace, rdrand::RdRand};
let gen = RdRand::new();
match gen {
Ok(gen) => {
let ret = gen.try_next_u64().unwrap();
trace!("Random {}", ret);
return ret;
}
Err(err) => {
let mut out: u64 = 0;
match unsafe { _rdrand64_step(&mut out) } {
1 => out,
_ => {
warn!("RDRand not supported.");
// Try rdseed
let gen = RdSeed::new();
match gen {
Ok(gen) => {
let ret = gen.try_next_u64().unwrap();
trace!("Random {}", ret);
return ret;
}
Err(err) => {
panic!("Neither RDRand or RDSeed are supported")
}
match unsafe { _rdseed64_step(&mut out) } {
1 => out,
_ => panic!("Neither RDRand or RDSeed are supported"),
}
}
}
@ -228,6 +271,7 @@ pub fn hardware_random_u64() -> u64 {
pub fn get_edid() {}
#[allow(unused)]
pub fn register_dump() {
let rax: u64;
let rbx: u64 = 0;

View file

@ -8,12 +8,12 @@ pub struct PciDeviceInfo {
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![]);
device_tree
.devices
.insert("Unidentified PCI", alloc::vec![]);
let mut devices = alloc::vec![];
for bus in 0..=255 {
@ -23,6 +23,7 @@ pub fn init(device_tree: &mut DeviceTree) {
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?
@ -45,7 +46,8 @@ pub fn init(device_tree: &mut DeviceTree) {
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());
pci_info.set_attribute("bus", bus);
pci_info.set_attribute("class", device_info.full_class);
dev.set_child(pci_info);
devices.push((dev_type, dev));
}
@ -66,7 +68,8 @@ pub fn check_device(bus: u8, device: u8) -> Option<PciDeviceInfo> {
return None;
}
let reg2 = unsafe { pci_config_read(bus, device, 0, 0x8) };
let (reg2, addr) = unsafe { pci_config_read_2(bus, device, 0, 0x8) };
log::debug!("pci device-({}) addr {} is {}", device, addr, reg2);
let class = ((reg2 >> 16) & 0x0000_FFFF) as u16;
let pci_class = PciFullClass::from_u16(class);
let header_type = get_header_type(bus, device, 0);
@ -269,8 +272,7 @@ impl Display for Vendor {
use core::fmt::Display;
use x86_64::instructions::port::Port;
use crate::device_tree::DeviceTree;
use {crate::device_tree::DeviceTree, x86_64::instructions::port::Port};
#[allow(non_camel_case_types, dead_code)]
#[derive(Debug, Clone, Copy, PartialEq)]
@ -458,9 +460,7 @@ unsafe fn pci_config_read(bus: u8, device: u8, func: u8, offset: u8) -> u32 {
let func = func as u32;
let offset = offset as u32;
// construct address param
let address =
((bus << 16) | (device << 11) | (func << 8) | (offset & 0xFC) | 0x8000_0000) as u32;
let address = (bus << 16) | (device << 11) | (func << 8) | (offset & 0xFC) | 0x8000_0000;
// write address
Port::new(0xCF8).write(address);
@ -468,6 +468,20 @@ unsafe fn pci_config_read(bus: u8, device: u8, func: u8, offset: u8) -> u32 {
Port::new(0xCFC).read()
}
unsafe fn pci_config_read_2(bus: u8, device: u8, func: u8, offset: u8) -> (u32, u32) {
let bus = bus as u32;
let device = device as u32;
let func = func as u32;
let offset = offset as u32;
// construct address param
let address = (bus << 16) | (device << 11) | (func << 8) | (offset & 0xFC) | 0x8000_0000;
// write address
Port::new(0xCF8).write(address);
// read data
(Port::new(0xCFC).read(), address)
}
unsafe fn pci_config_write(bus: u8, device: u8, func: u8, offset: u8, value: u32) {
let bus = bus as u32;
let device = device as u32;

View file

@ -1,5 +1,5 @@
use {
core::{ptr::NonNull},
core::ptr::NonNull,
virtio_drivers::{BufferDirection, Hal, PhysAddr},
};

View file

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

View file

@ -1,11 +1,7 @@
//! A tree of hardware devices
use {
crate::alloc::string::ToString,
alloc::{string::String, vec::Vec},
core::fmt,
hashbrown::HashMap,
};
use {alloc::vec::Vec, core::fmt, hashbrown::HashMap};
/// A device object.
/// TODO define device
pub type Device = xml::XMLElement;
@ -13,38 +9,40 @@ pub type Device = xml::XMLElement;
/// A tree of devices
// TODO: alphabetize this list
#[derive(Debug)]
pub struct DeviceTree {
pub struct DeviceTree<'a> {
/// The device tree
pub devices: HashMap<String, Vec<Device>>,
pub devices: HashMap<&'a str, Vec<Device>>,
}
impl DeviceTree {
impl<'a> DeviceTree<'a> {
/// Build the device tree. Does not populate the device tree
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",
]);
device_tree!(
dt,
[
"Mice",
"Keyboards",
"Controllers",
"Generic HIDs",
"Disk Drives",
"CD Drives",
"Batteries",
"Monitors",
"GPUs",
"CPUs",
"USB",
"Serial Ports",
"Cameras",
"Biometric Devices",
]
);
dt
}
}
use crate::{utils::TAB, device_tree};
use crate::tab;
impl fmt::Display for DeviceTree {
use crate::{device_tree, tab, utils::TAB};
impl<'a> fmt::Display for DeviceTree<'a> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
writeln!(f)?;
for (device_type, devices) in &self.devices {

35
kernel/src/exe_format.rs Normal file
View file

@ -0,0 +1,35 @@
enum Sections {
Header,
Code,
Data,
Debug,
Config,
Metadata,
}
// 64 byte header
#[repr(packed)]
struct AbleOsExecutableHeader {
magic_number: [u8; 3],
executable_version: u32,
code_length: u64,
data_length: u64,
debug_length: u64,
config_length: u64,
metadata_length: u64,
}
impl AbleOsExecutableHeader {
fn new() -> Self {
Self {
magic_number: [0x15, 0x91, 0xD2],
executable_version: 0,
code_length: 0,
config_length: 0,
data_length: 0,
debug_length: 0,
metadata_length: 0,
}
}
}

View file

@ -1,19 +1,42 @@
//! Environment call handling routines
use {
super::{mem::Memory, Vm},
crate::{arch, holeybytes::mem, ipc::buffer::IpcBuffer, kmain::IPC_BUFFERS},
alloc::string::String,
log::{debug, error, info, trace, warn},
use {alloc::boxed::Box, core::cell::LazyCell, hbvm::mem::Address};
use crate::{
holeybytes::{
kernel_services::{
block_read, dt_msg_handler::dt_msg_handler, logging_service::log_msg_handler,
service_definition_service::sds_msg_handler,
},
ExecThread,
},
kmain::EXECUTOR,
task::Executor,
};
pub fn handler(vm: &mut Vm) {
let r1 = vm.registers[1].cast::<u64>();
use {
super::Vm,
crate::{arch, ipc::buffer::IpcBuffer, kmain::IPC_BUFFERS},
hbvm::value::Value,
log::{debug, error, info, trace},
};
// debug!("Ecall number {:?}", r1);
// trace!("Register dump: {:?}", vm.registers);
#[cfg(target_arch = "x86_64")]
#[inline(always)]
unsafe fn x86_out<T: x86_64::instructions::port::PortWrite>(address: u16, value: T) {
x86_64::instructions::port::Port::new(address).write(value);
}
#[cfg(target_arch = "x86_64")]
#[inline(always)]
unsafe fn x86_in<T: x86_64::instructions::port::PortRead>(address: u16) -> T {
x86_64::instructions::port::Port::new(address).read()
}
match r1 {
#[inline(always)]
pub fn handler(vm: &mut Vm, pid: &usize) {
let ecall_number = vm.registers[2].cast::<u64>();
match ecall_number {
0 => {
// TODO: explode computer
// hello world ecall
@ -24,155 +47,235 @@ pub fn handler(vm: &mut Vm) {
1 => {
// Make buffer
let bounded = match vm.registers[2].cast::<u64>() {
0 => false,
1 => true,
let bounded = match vm.registers[3] {
Value(0) => false,
Value(1) => true,
_ => {
panic!("Bad");
}
};
let length = vm.registers[3].cast::<u64>();
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);
debug!("Buffer ID: {}", buff_id);
buffs.insert(
buff_id,
match bounded {
false => IpcBuffer::new(false, 0),
true => IpcBuffer::new(true, length),
},
);
vm.registers[1] = hbvm::value::Value(buff_id);
}
2 => {
log::error!("Oops, deleting buffers is not implemented.")
// Delete buffer
}
3 => {
// Send a message to a buffer
let r2 = vm.registers[2].cast::<u64>();
let r3 = vm.registers[3].cast::<u64>();
let r4 = vm.registers[4].cast::<u64>();
let buffer_id = r2;
let mem_addr = r3;
let length = r4 as usize;
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;
unsafe { LazyCell::<Executor>::get_mut(&mut EXECUTOR) }
.unwrap()
.send_buffer(buffer_id as usize);
match buffer_id {
0 => match sds_msg_handler(vm, mem_addr, length) {
Ok(()) => {}
Err(err) => log::error!("Improper sds format: {err:?}"),
},
1 => match log_msg_handler(vm, mem_addr, length) {
Ok(()) => {}
Err(err) => log::error!("Improper log format"),
Err(_) => log::error!("Improper log format"),
},
2 => match memory_msg_handler(vm, mem_addr, length) {
2 => {
use crate::holeybytes::kernel_services::mem_serve::memory_msg_handler;
match memory_msg_handler(vm, mem_addr, length) {
Ok(_) => {}
Err(_) => {}
}
}
#[cfg(target_arch = "x86_64")]
3 => {
let msg_vec = block_read(mem_addr, length);
let msg_type = msg_vec[0];
match msg_type {
0 => unsafe {
let size = msg_vec[1];
let addr =
u16::from_le_bytes(msg_vec[2..4].try_into().unwrap_unchecked());
let value = match size {
0 => x86_in::<u8>(addr) as u64,
1 => x86_in::<u16>(addr) as u64,
2 => x86_in::<u32>(addr) as u64,
_ => panic!("Trying to read size other than: 8, 16, 32 from port."),
};
// info!("Read the value {} from address {}", value, addr);
vm.registers[1] = hbvm::value::Value(value);
},
1 => unsafe {
let size = msg_vec[1];
let addr =
u16::from_le_bytes(msg_vec[2..4].try_into().unwrap_unchecked());
// info!("Setting address {}", addr);
match size {
0 => x86_out(addr, msg_vec[4]),
1 => x86_out(
addr,
u16::from_le_bytes(msg_vec[4..6].try_into().unwrap_unchecked()),
),
2 => x86_out(
addr,
u32::from_le_bytes(msg_vec[4..8].try_into().unwrap_unchecked()),
),
_ => panic!("How?"),
}
},
_ => {}
}
}
#[cfg(not(target_arch = "x86_64"))]
3 => unimplemented!("TODO: implement whatever buffer 3 does for no x86_64"),
// source of rng
4 => {
let block = block_read(mem_addr, length);
block.chunks_mut(8.min(length)).for_each(|chunk| {
chunk.clone_from_slice(
&crate::arch::hardware_random_u64().to_le_bytes()[..chunk.len()],
);
});
vm.registers[1] = hbvm::value::Value(mem_addr);
}
5 => match dt_msg_handler(vm, mem_addr, length) {
Ok(()) => {}
Err(err) => log::error!("Improper log format"),
Err(_) => log::error!("Improper dt query"),
},
6 => unsafe {
let program = block_read(mem_addr, length);
// decode AbleOS Executable format
let header = &program[0..46];
let magic_slice = &header[0..3];
if magic_slice != [0x15, 0x91, 0xD2] {
log::error!("Invalid magic number at the start of executable.");
return;
}
let executable_format_version =
u32::from_le_bytes(header[3..7].try_into().unwrap());
let offset = if executable_format_version == 0 {
47
} else {
error!("Invalid executable format.");
return;
};
let code_length = u64::from_le_bytes(header[7..15].try_into().unwrap());
let data_length = u64::from_le_bytes(header[15..23].try_into().unwrap());
let end = (code_length + data_length) as usize;
log::debug!("{code_length} + {data_length} = {end}");
let thr = ExecThread::new(&program[offset..end], Address::new(0));
vm.registers[1] = Value(
LazyCell::<Executor>::get_mut(&mut EXECUTOR)
.unwrap()
.spawn(Box::pin(async move {
if let Err(e) = thr.await {
log::error!("{e:?}");
}
})) as u64,
);
log::debug!("spawned a process");
},
buffer_id => {
let mut buffs = IPC_BUFFERS.lock();
match buffs.get_mut(&buffer_id) {
Some(buff) => {
let mut msg_vec = vec![];
for x in 0..(length as isize) {
let xyz = mem_addr as *const u8;
let value = unsafe { xyz.offset(x).read() };
msg_vec.push(value);
}
buff.push(msg_vec.clone());
info!(
"Message {:?} has been sent to Buffer({})",
msg_vec, buffer_id
);
let msg_vec = block_read(mem_addr, length);
buff.push(msg_vec.to_vec());
debug!("Sent Message {:?} to Buffer({})", msg_vec, buffer_id);
}
None => {
log::error!("Access of non-existent buffer {}", buffer_id)
}
}
drop(buffs);
}
}
}
4 => {
let r2 = vm.registers[2].cast::<u64>();
let buffer_id = vm.registers[3].cast::<u64>();
let map_ptr = vm.registers[4].cast::<u64>();
let max_length = vm.registers[5].cast::<u64>();
let mut buffs = IPC_BUFFERS.lock();
let mut buff = buffs.get_mut(&r2).unwrap();
let msg = buff.pop();
info!("Recieve {:?} from Buffer({})", msg, r2);
let buff: &mut IpcBuffer = match buffs.get_mut(&buffer_id) {
Some(buff) => buff,
None => panic!(
"Failed to get buffer: id={buffer_id}, ptr={map_ptr}, length={max_length}"
),
};
let msg = match buff.pop() {
Ok(msg) => msg,
Err(_) => return,
};
if msg.len() > unsafe { max_length.try_into().unwrap_unchecked() } {
info!("{}", max_length);
error!("Message is too long to map in.");
} else {
unsafe {
let ptr = map_ptr as *mut u8;
ptr.copy_from_nonoverlapping(msg.as_ptr(), msg.len());
}
debug!("Recieve {:?} from Buffer({})", msg, buffer_id);
}
}
5 => {
let r2 = vm.registers[2].cast::<u64>();
vm.registers[3] = hbvm::value::Value( unsafe { x86_in(r2 as u16) } as u64);
#[cfg(target_arch = "x86_64")]
{
let r2 = vm.registers[2].cast::<u64>();
let x = hbvm::value::Value(unsafe { x86_in::<u8>(r2 as u16) } as u64);
// info!("Read {:?} from Port {:?}", x, r2);
vm.registers[3] = x
}
}
6 => {
// Wait till interrupt
use crate::kmain::EXECUTOR;
let interrupt_type = vm.registers[3].cast::<u8>();
debug!("Interrupt subscribed: {}", interrupt_type);
unsafe {
LazyCell::<Executor>::get_mut(&mut EXECUTOR)
.unwrap()
.interrupt_subscribe(*pid, interrupt_type);
}
}
7 => {
// Wait till buffer
use crate::kmain::EXECUTOR;
let buffer_id = vm.registers[3].cast::<u64>() as usize;
debug!("Buffer subscribed: {}", buffer_id);
unsafe {
LazyCell::<Executor>::get_mut(&mut EXECUTOR)
.unwrap()
.buffer_subscribe(*pid, buffer_id);
}
}
// 5
_ => {
log::error!("Syscall unknown {:?}{:?}", r1, vm.registers);
log::error!("Syscall unknown {:?}{:?}", ecall_number, vm.registers);
}
}
}
unsafe fn x86_in(address: u16) -> u32{
x86_64::instructions::port::Port::new(address).read()
}
unsafe fn x86_out(address: u16, value: u32){
x86_64::instructions::port::Port::new(address).write(value);
}
fn log_msg_handler(vm: &mut Vm, mem_addr: u64, length: usize) -> Result<(), LogError> {
// let message_length = 8 + 8 + 8;
// log::info!("Mem Addr 0x{:x?} length {}", mem_addr, length);
let mut msg_vec = vec![];
for x in 0..(length as isize) {
let xyz = mem_addr as *const u8;
let value = unsafe { xyz.offset(x).read() };
// info!("{} - 0x{:x?} - {}", value, value, value as char);
msg_vec.push(value);
}
let log_level = msg_vec.pop().unwrap();
match String::from_utf8(msg_vec) {
Ok (strr) => {
// use LogLevel::*;
let ll = match log_level {
0 | 48 => error!("{}", strr),
1 | 49 => warn!("{}", strr),
2 | 50 => info!("{}", strr),
3 | 51 => debug!("{}", strr),
4 | 52 => trace!("{}", strr),
_ => {
return Err(LogError::InvalidLogFormat);
}
};
}
Err(e) => {
error!("{:?}", e);
}
}
Ok(())
}
#[derive(Debug)]
pub enum LogError {
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,78 @@
use {
crate::holeybytes::{kernel_services::block_read, Vm},
alloc::vec::Vec,
};
pub enum DtError {
QueryFailure,
}
pub fn dt_msg_handler(vm: &mut Vm, mem_addr: u64, length: usize) -> Result<(), DtError> {
let msg_vec = block_read(mem_addr, length);
let query_string = core::str::from_utf8(
msg_vec
.split_once(|&byte| byte == 0)
.unwrap_or((msg_vec, &[]))
.0,
)
.unwrap();
log::trace!("Query {}", query_string);
let ret = query_parse(query_string);
log::trace!("Query response {}", ret);
vm.registers[1] = hbvm::value::Value(ret);
Ok(())
}
fn query_parse(query_string: &str) -> u64 {
let query = query_string.split('/').collect::<Vec<&str>>();
let first_fragment: &str = &query[0];
let ret = match first_fragment {
"framebuffer" => framebuffer_parse(query),
"cpu" => cpu_parse(query),
_ => 0,
};
return ret;
}
fn cpu_parse(qt_parse_step_two: Vec<&str>) -> u64 {
let second_fragment: &str = qt_parse_step_two[1];
match second_fragment {
// "architecture" => {
// return 0;
// }
_ => {
return 0;
}
};
}
fn framebuffer_parse(qt_parse_step_two: Vec<&str>) -> u64 {
use crate::kmain::FB_REQ;
let fbs = &mut FB_REQ.get_response().get().unwrap().framebuffers();
let second_fragment: &str = qt_parse_step_two[1];
match second_fragment {
"fb0" => {
let fb_front = &fbs[0];
let third_fragment: &str = qt_parse_step_two[2];
let ret = match third_fragment {
"ptr" => {
let ptr = fb_front.address.as_ptr().unwrap();
ptr as usize as u64
}
"width" => fb_front.width,
"height" => fb_front.height,
_ => 0,
};
return ret;
}
_ => {
return 0;
}
};
}

View file

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

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,122 @@
use {
crate::holeybytes::{kernel_services::block_read, Vm},
alloc::alloc::{alloc, dealloc},
core::alloc::Layout,
log::{debug, info},
};
pub enum MemoryServiceError {
InvalidMemoryFormat,
}
#[derive(Debug)]
pub enum MemoryQuotaType {
NoQuota = 0,
SoftQuota = 1,
HardQuota = 2,
KillQuota = 3,
}
fn alloc_page(vm: &mut Vm, _mem_addr: u64, _length: usize) -> Result<(), MemoryServiceError> {
let ptr = unsafe { alloc(Layout::from_size_align_unchecked(4096, 8)) };
info!("Block address: {:?}", ptr);
vm.registers[1] = hbvm::value::Value(ptr as u64);
vm.registers[2] = hbvm::value::Value(4096);
Ok(())
}
#[inline(always)]
unsafe fn memset(dest: *mut u8, src: *const u8, count: usize, size: usize) {
let total_size = count * size;
src.copy_to_nonoverlapping(dest, size);
let mut copied = size;
while copied < total_size {
let copy_size = copied.min(total_size - copied);
dest.add(copied).copy_from_nonoverlapping(dest, copy_size);
copied += copy_size;
}
}
#[inline(always)]
pub fn memory_msg_handler(
vm: &mut Vm,
mem_addr: u64,
length: usize,
) -> Result<(), MemoryServiceError> {
let msg_vec = block_read(mem_addr, length);
let msg_type = msg_vec[0];
match msg_type {
0 => unsafe {
let page_count = msg_vec[1];
let ptr = alloc(Layout::from_size_align_unchecked(
page_count as usize * 4096,
8,
));
log::debug!("Allocating {} pages @ {:x}", page_count, ptr as u64);
vm.registers[1] = hbvm::value::Value(ptr as u64);
log::debug!("Kernel ptr: {:x}", ptr as u64);
},
1 => unsafe {
let page_count = msg_vec[1];
let mptr_raw: [u8; 8] = msg_vec[2..10].try_into().unwrap();
let mptr: u64 = u64::from_le_bytes(mptr_raw);
log::debug!("Deallocating {} pages @ {:x}", page_count, mptr);
dealloc(
mptr as *mut u8,
Layout::from_size_align_unchecked(page_count as usize * 4096, 8),
)
},
2 => {
use MemoryQuotaType::*;
let quota_type = match msg_vec[1] {
0 => NoQuota,
1 => SoftQuota,
2 => HardQuota,
3 => KillQuota,
_ => NoQuota,
};
let hid_raw: [u8; 8] = msg_vec[2..10].try_into().unwrap();
let hid: u64 = u64::from_le_bytes(hid_raw);
let pid_raw: [u8; 8] = msg_vec[10..18].try_into().unwrap();
let pid: u64 = u64::from_le_bytes(pid_raw);
debug!(
"Setting HID-{:x}:PID-{:x}'s quota type to {:?}",
hid, pid, quota_type
)
}
3 => {
let page_count = msg_vec[1];
log::debug!(" {} pages", page_count);
}
4 => unsafe {
let count = u64::from_le_bytes(msg_vec[1..9].try_into().unwrap_unchecked()) as usize;
let src = u64::from_le_bytes(msg_vec[9..17].try_into().unwrap_unchecked()) as *const u8;
let dest = u64::from_le_bytes(msg_vec[17..25].try_into().unwrap_unchecked()) as *mut u8;
debug_assert!(src.addr() & 0xFFFF000000000000 != 0);
debug_assert!(dest.addr() & 0xFFFF000000000000 != 0);
src.copy_to_nonoverlapping(dest, count);
},
5 => unsafe {
let count = u64::from_le_bytes(msg_vec[1..9].try_into().unwrap_unchecked()) as usize;
let size = u64::from_le_bytes(msg_vec[9..17].try_into().unwrap_unchecked()) as usize;
let src =
u64::from_le_bytes(msg_vec[17..25].try_into().unwrap_unchecked()) as *const u8;
let dest = u64::from_le_bytes(msg_vec[25..33].try_into().unwrap_unchecked()) as *mut u8;
debug_assert!(src.addr() & 0xFFFF000000000000 != 0);
debug_assert!(dest.addr() & 0xFFFF000000000000 != 0);
memset(dest, src, count, size);
},
_ => {
log::debug!("Unknown memory service message type: {}", msg_type);
}
}
Ok(())
}

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

View file

@ -6,34 +6,54 @@
use hbvm::mem::Address;
pub struct Memory;
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]
#[inline(always)]
unsafe fn load(
&mut self,
addr: Address,
target: *mut u8,
count: usize,
) -> Result<(), hbvm::mem::LoadError> {
core::ptr::copy(addr.get() as *const u8, target, count);
core::ptr::copy_nonoverlapping(addr.get() as *const u8, target, count);
Ok(())
}
#[inline]
#[inline(always)]
unsafe fn store(
&mut self,
addr: Address,
source: *const u8,
count: usize,
) -> Result<(), hbvm::mem::StoreError> {
// log::info!("Storing memory");
core::ptr::copy(source, addr.get() as *mut u8, count);
core::ptr::copy_nonoverlapping(source, addr.get() as *mut u8, count);
Ok(())
}
#[inline]
#[inline(always)]
unsafe fn prog_read<T: Copy>(&mut self, addr: Address) -> T {
(addr.get() as *const T).read_unaligned()
(addr.get() as *const T).read()
}
}

View file

@ -1,76 +1,76 @@
mod ecah;
pub mod kernel_services;
mod mem;
use {
crate::{arch, ipc::buffer::IpcBuffer, kmain::IPC_BUFFERS},
alloc::boxed::Box,
core::{default, future::Future, marker::PhantomData, ptr::NonNull, task::Poll},
alloc::alloc::{alloc, dealloc},
core::{
alloc::Layout,
future::Future,
pin::Pin,
task::{Context, Poll},
},
hbvm::{
mem::{
softpaging::{icache::ICache, HandlePageFault, SoftPagedMem},
Address, Memory,
},
mem::{softpaging::HandlePageFault, Address},
VmRunError, VmRunOk,
},
log::{debug, error, info, trace, warn},
log::error,
};
const STACK_SIZE: usize = 1024 * 1024;
const TIMER_QUOTIENT: usize = 100;
const TIMER_QUOTIENT: usize = 1000;
type Vm = hbvm::Vm<mem::Memory, TIMER_QUOTIENT>;
pub struct ExecThread<'p> {
pub struct ExecThread {
vm: Vm,
stack_bottom: *mut u8,
_phantom: PhantomData<&'p [u8]>,
}
unsafe impl<'p> Send for ExecThread<'p> {}
impl<'p> ExecThread<'p> {
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: &'p [u8], entrypoint: Address) -> Self {
let mut vm = unsafe {
Vm::new(
mem::Memory,
Address::new(program.as_ptr() as u64 + entrypoint.get()),
)
};
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();
let stack_bottom = unsafe { allocate_stack().as_ptr() };
vm.write_reg(254, (stack_bottom as usize + STACK_SIZE - 1) as u64);
ExecThread {
vm,
stack_bottom,
_phantom: Default::default(),
}
ExecThread { vm, stack_bottom }
}
}
impl<'p> Drop for ExecThread<'p> {
impl<'p> Drop for ExecThread {
fn drop(&mut self) {
unsafe { alloc::alloc::dealloc(self.stack_bottom, stack_layout()) };
unsafe { dealloc(self.stack_bottom, stack_layout()) };
}
}
impl<'p> Future for ExecThread<'p> {
impl<'p> Future for ExecThread {
type Output = Result<(), VmRunError>;
fn poll(
mut self: core::pin::Pin<&mut Self>,
cx: &mut core::task::Context<'_>,
) -> Poll<Self::Output> {
#[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::Ecall) => ecah::handler(
&mut self.vm,
cx.ext()
.downcast_ref()
.expect("PID did not exist in Context"),
),
Ok(VmRunOk::Timer) => (),
Ok(VmRunOk::Breakpoint) => {
log::error!(
@ -90,33 +90,22 @@ impl HandlePageFault for PageFaultHandler {
fn page_fault(
&mut self,
reason: hbvm::mem::MemoryAccessReason,
pagetable: &mut hbvm::mem::softpaging::paging::PageTable,
_pagetable: &mut hbvm::mem::softpaging::paging::PageTable,
vaddr: hbvm::mem::Address,
size: hbvm::mem::softpaging::PageSize,
dataptr: *mut u8,
) -> bool
where
Self: Sized,
{
log::error!(
"REASON: {reason} \
vaddr: {vaddr} \
size: {size:?} \
Dataptr {dataptr:p}",
);
) -> bool {
error!("REASON: {reason} vaddr: {vaddr} size: {size:?} Dataptr {dataptr:p}");
false
}
}
const fn stack_layout() -> core::alloc::Layout {
unsafe { alloc::alloc::Layout::from_size_align_unchecked(STACK_SIZE, 4096) }
#[inline(always)]
const fn stack_layout() -> Layout {
unsafe { Layout::from_size_align_unchecked(STACK_SIZE, 8) }
}
fn allocate_stack() -> NonNull<u8> {
let layout = stack_layout();
match NonNull::new(unsafe { alloc::alloc::alloc_zeroed(layout) }) {
Some(ptr) => ptr,
None => alloc::alloc::handle_alloc_error(layout),
}
#[inline(always)]
fn allocate_stack() -> *mut u8 {
unsafe { alloc(stack_layout()) }
}

View file

@ -1,21 +1,20 @@
//!
use {
super::message::Message,
super::{message::Message, protocol::Protocol},
crossbeam_queue::{ArrayQueue, SegQueue},
};
pub enum BufferTypes {
Unbound(SegQueue<Message>),
Bound(ArrayQueue<Message>),
}
/// Interproccess buffer
pub struct IpcBuffer {
pub protocol: Protocol,
pub struct IpcBuffer<'a> {
pub protocol: Protocol<'a>,
pub buffer: BufferTypes,
}
impl IpcBuffer {
impl<'a> IpcBuffer<'a> {
pub fn new(bounded: bool, length: u64) -> Self {
log::debug!(
"New IPCBuffer\r
@ -24,20 +23,19 @@ impl IpcBuffer {
bounded,
length
);
match (bounded, length) {
(false, a) => {
(false, ..) => {
let buftype = BufferTypes::Unbound(SegQueue::new());
Self {
protocol: Protocol {},
protocol: Protocol::void(),
buffer: buftype,
}
}
(true, length) => {
let buftype = BufferTypes::Bound(ArrayQueue::new(length as usize));
Self {
protocol: Protocol {},
protocol: Protocol::void(),
buffer: buftype,
}
}
@ -50,39 +48,25 @@ impl IpcBuffer {
}
pub fn push(&mut self, msg: Message) {
match &self.buffer {
BufferTypes::Unbound(buff) => buff.push(msg.clone()),
BufferTypes::Bound(buff) => {
let _ = buff.push(msg.clone());
}
BufferTypes::Unbound(buff) => buff.push(msg),
BufferTypes::Bound(buff) => buff.push(msg).unwrap(),
};
}
pub fn pop(&mut self) -> Message {
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 msg,
None => panic!("Recieving msg error. No messages!"),
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,
}
/// TODO: define this, possibly as the binary form of the IDL
/// DEPEND: This depends on an IDL
pub struct Protocol {
// TODO: add in settings
// like `invalid_message_handler` with some options similar to
// `Deny` Drops the message
// `Allow` Allows invalid messages (This disables validators IPC side and relies on programs to handle invalid messages)
// `CustomFunct` a callback
// and `report_invalid_messages_to_sender`
// `True`
// `False`
// settings: PSettings,
NoMessagesInBuffer,
}

View file

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

View file

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

View file

@ -2,26 +2,40 @@
use {
crate::{
bootmodules::{build_cmd, BootModules},
capabilities,
arch::hardware_random_u64,
bootmodules::BootModules,
//bootmodules::build_cmd,
device_tree::DeviceTree,
holeybytes::ExecThread,
ipc::buffer::{self, IpcBuffer},
ipc::buffer::IpcBuffer,
task::Executor,
},
alloc::format,
alloc::boxed::Box,
core::cell::LazyCell,
hashbrown::HashMap,
hbvm::mem::Address,
limine::{Framebuffer, FramebufferRequest, NonNullPtr},
log::{debug, info, trace},
log::{debug, error, trace},
spin::{Lazy, Mutex},
xml::XMLElement,
};
pub fn kmain(cmdline: &str, boot_modules: BootModules) -> ! {
pub fn kmain(_cmdline: &str, boot_modules: BootModules) -> ! {
debug!("Entered kmain");
let kcmd = build_cmd("Kernel Command Line", cmdline);
trace!("Cmdline: {kcmd:?}");
#[cfg(feature = "ktest")]
{
use {
crate::ktest,
log::info,
};
info!("Running tests");
ktest::test_main();
loop {}
}
// let kcmd = build_cmd("Kernel Command Line", cmdline);
// trace!("Cmdline: {kcmd:?}");
// for (i, bm) in boot_modules.iter().enumerate() {
// let name = format!("module-{}", i);
@ -37,9 +51,9 @@ pub fn kmain(cmdline: &str, boot_modules: BootModules) -> ! {
let dt = DEVICE_TREE.lock();
// TODO(Able): This line causes a deadlock
info!("Device Tree: {}", dt);
debug!("Device Tree: {}", dt);
info!("Boot complete. Moving to init_system");
trace!("Boot complete. Moving to init_system");
// TODO: schedule the disk driver from the initramfs
// TODO: schedule the filesystem driver from the initramfs
@ -51,62 +65,91 @@ pub fn kmain(cmdline: &str, boot_modules: BootModules) -> ! {
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("bpp", fb1.bpp);
disp.set_attribute("pitch", fb1.pitch);
dt.devices.insert("Displays".to_string(), alloc::vec![disp]);
dt.devices.insert("Displays", alloc::vec![disp]);
}
log::info!("Graphics initialised");
log::info!(
debug!("Graphics initialised");
debug!(
"Graphics front ptr {:?}",
fb1.address.as_ptr().unwrap() as *const u8
);
log::info!("Started AbleOS");
let mut executor = crate::task::Executor::default();
let bm_take = boot_modules.len();
unsafe {
for module in boot_modules.into_iter().take(bm_take) {
let mut cmd = module.cmd;
if cmd.len() > 2 {
// Remove the quotes
cmd.remove(0);
cmd.pop();
let executor = LazyCell::<Executor>::force_mut(&mut EXECUTOR);
for module in boot_modules.iter() {
let cmd = module.cmd.trim_matches('"');
let cmd_len = cmd.len() as u64;
log::info!(
"Starting {}",
module
.path
.split('/')
.last()
.unwrap()
.split('.')
.next()
.unwrap()
);
log::debug!("Spawning {} with arguments \"{}\"", module.path, cmd);
// decode AbleOS Executable format
let header = &module.bytes[0..46];
let magic_slice = &header[0..3];
if magic_slice != [0x15, 0x91, 0xD2] {
log::error!("Invalid magic number at the start of executable.");
continue;
}
let cmd_len = cmd.as_bytes().len() as u64;
log::info!("Spawning {} with arguments \"{}\"", module.path, cmd);
let executable_format_version = u32::from_le_bytes(header[3..7].try_into().unwrap());
let offset = if executable_format_version == 0 {
47
} else {
error!("Invalid executable format.");
continue;
};
executor.spawn(async move {
let mut thr = ExecThread::new(&module.bytes, Address::new(0));
if cmd_len > 0 {
thr.set_arguments(cmd.as_bytes().as_ptr() as u64, cmd_len);
}
let code_length = u64::from_le_bytes(header[7..15].try_into().unwrap());
let data_length = u64::from_le_bytes(header[15..23].try_into().unwrap());
let end = (code_length + data_length) as usize;
log::debug!("{code_length} + {data_length} = {end}");
let mut thr = ExecThread::new(&module.bytes[offset..end], Address::new(0));
if cmd_len > 0 {
thr.set_arguments(cmd.as_ptr() as u64, cmd_len);
}
executor.spawn(Box::pin(async {
if let Err(e) = thr.await {
log::error!("{e:?}");
}
});
}));
}
debug!("Random number: {}", hardware_random_u64());
executor.run();
};
crate::arch::spin_loop()
}
// ! SAFETY: this is not threadsafe at all, like even a little bit.
// ! SERIOUSLY
pub static mut EXECUTOR: LazyCell<Executor> = LazyCell::new(|| Executor::new());
pub static DEVICE_TREE: Lazy<Mutex<DeviceTree>> = Lazy::new(|| {
let dt = DeviceTree::new();
Mutex::new(dt)
});
pub static FB_REQ: FramebufferRequest = FramebufferRequest::new(0);
use alloc::vec::Vec;
pub type IpcBuffers = HashMap<u64, IpcBuffer>;
pub 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);
@ -117,10 +160,3 @@ pub static IPC_BUFFERS: Lazy<Mutex<IpcBuffers>> = Lazy::new(|| {
Mutex::new(bufs)
});
#[test_case]
fn trivial_assertion() {
trace!("trivial assertion... ");
assert_eq!(1, 1);
info!("[ok]");
}

51
kernel/src/ktest.rs Normal file
View file

@ -0,0 +1,51 @@
pub use ktest_macro::*;
use {
alloc::string::String,
log::{error, info},
};
extern "C" {
static __ktest_start: fn() -> Result<String, String>;
static __ktest_end: fn() -> Result<String, String>;
}
// TODO: Implement ktest for arm and riscv (Later problems, see below)
// Allow for arch specific tests (Leave for now)
// Should panic tests
// Test specific panic handler
pub fn test_main() {
unsafe {
let mut current_test = &__ktest_start as *const fn() -> Result<String, String>;
let test_end = &__ktest_end as *const fn() -> Result<String, String>;
let mut pass = 0;
let mut fail = 0;
while current_test < test_end {
let test_fn = *current_test;
let test_name = test_fn();
match test_name {
Ok(name) => {
info!("Test: {} passed", name);
pass += 1;
},
Err(name) => {
error!("Test: {} failed", name);
fail += 1;
}
}
current_test = current_test.add(1);
}
info!("{}/{} tests passed", pass, pass + fail);
}
}
#[ktest]
pub fn trivial_assertion() {
ktest_eq!(1, 1);
ktest_neq!(0, 1);
}

View file

@ -1,20 +1,22 @@
//! The ableOS kernel.
//! Named akern.
//! Akern is woefully undersupported at the moment but we are looking to add support improve hardware discovery and make our lives as kernel and operating system developers easier and better
#![no_std]
#![no_main]
#![feature(
slice_split_once,
exclusive_wrapper,
core_intrinsics,
abi_x86_interrupt,
lazy_get,
alloc_error_handler,
inline_const,
panic_info_message,
pointer_is_aligned,
local_waker,
context_ext,
ptr_sub_ptr,
custom_test_frameworks,
naked_functions,
pointer_is_aligned_to
)]
#![allow(dead_code)]
#![test_runner(crate::test_runner)]
#![allow(dead_code, internal_features, static_mut_refs)]
extern crate alloc;
mod allocator;
@ -22,6 +24,7 @@ mod arch;
mod bootmodules;
mod capabilities;
mod device_tree;
mod exe_format;
mod handle;
mod holeybytes;
mod ipc;
@ -31,6 +34,9 @@ mod memory;
mod task;
mod utils;
#[allow(improper_ctypes, non_upper_case_globals)]
mod ktest;
use versioning::Version;
/// Kernel's version
@ -41,7 +47,9 @@ pub const VERSION: Version = Version {
};
#[panic_handler]
#[cfg(target_os = "none")]
fn panic(info: &core::panic::PanicInfo) -> ! {
use alloc::string::ToString;
arch::register_dump();
if let Some(loc) = info.location() {
@ -53,17 +61,7 @@ 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().to_string().replace("\n", "\r\n");
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,3 +1,4 @@
#![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()));
@ -9,7 +10,11 @@ use {
pub fn init() -> Result<(), SetLoggerError> {
log::set_logger(&crate::logger::Logger)?;
log::set_max_level(log::LevelFilter::Debug);
if cfg!(debug_assertions) {
log::set_max_level(log::LevelFilter::Debug);
} else {
log::set_max_level(log::LevelFilter::Info);
}
Lazy::force(&TERMINAL_LOGGER);
@ -31,13 +36,26 @@ impl log::Log for Logger {
Level::Debug => "25",
Level::Trace => "103",
};
let module = record.module_path().unwrap_or_default();
let line = record.line().unwrap_or_default();
crate::arch::log(format_args!(
"\x1b[38;5;{lvl_color}m{lvl}\x1b[0m [{module}:{line}]: {}\r\n",
record.args(),
))
.expect("write to serial console");
let module = record
.module_path()
.unwrap_or_default()
.rsplit_once(':')
.unwrap_or_default()
.1;
if module == "" {
crate::arch::log(format_args!(
"\x1b[38;5;{lvl_color}m{lvl}\x1b[0m: {}\r\n",
record.args(),
))
.expect("write to serial console");
} else {
let line = record.line().unwrap_or_default();
crate::arch::log(format_args!(
"\x1b[38;5;{lvl_color}m{lvl}\x1b[0m [{module}:{line}]: {}\r\n",
record.args(),
))
.expect("write to serial console");
}
}
fn flush(&self) {}

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,26 +1,19 @@
#![allow(unused)]
use {
alloc::{boxed::Box, collections::BTreeMap, sync::Arc, task::Wake},
alloc::{
boxed::Box,
collections::{BTreeMap, BTreeSet},
sync::Arc,
},
core::{
future::Future,
pin::Pin,
task::{Context, Poll, Waker},
sync::atomic::{AtomicBool, Ordering},
task::{Context, ContextBuilder, Poll, RawWaker, RawWakerVTable, Waker},
},
crossbeam_queue::SegQueue,
kiam::when,
slab::Slab,
spin::RwLock,
};
static SPAWN_QUEUE: RwLock<Option<SpawnQueue>> = RwLock::new(None);
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"),
}
}
pub fn yield_now() -> impl Future<Output = ()> {
struct YieldNow(bool);
impl Future for YieldNow {
@ -40,101 +33,184 @@ pub fn yield_now() -> impl Future<Output = ()> {
YieldNow(false)
}
#[derive(Default)]
pub trait Process: Future<Output = ()> + Send {}
impl<T: Future<Output = ()> + Send> Process for T {}
pub struct Executor {
tasks: Slab<Task>,
queue: TaskQueue,
to_spawn: SpawnQueue,
wakers: BTreeMap<TaskId, Waker>,
tasks: Slab<Task>,
task_queue: Arc<SegQueue<usize>>,
interrupt_lookup: [Option<usize>; u8::MAX as usize],
buffer_lookup: BTreeMap<usize, BTreeSet<usize>>,
}
impl Executor {
pub fn spawn(&mut self, future: impl Future<Output = ()> + Send + 'static) {
self.queue
.push(TaskId(self.tasks.insert(Task::new(future))));
pub fn new() -> Self {
Self {
tasks: Slab::new(),
task_queue: Arc::new(SegQueue::new()),
interrupt_lookup: [None; u8::MAX as usize],
buffer_lookup: BTreeMap::new(),
}
}
pub fn spawn(&mut self, future: Pin<Box<dyn Process>>) -> usize {
let id = self.tasks.insert(Task::new(future));
self.task_queue.push(id);
id
}
pub fn pause(&self, id: usize) {
if let Some(task) = self.tasks.get(id) {
task.set_paused(true);
}
}
pub fn unpause(&self, id: usize) {
if let Some(task) = self.tasks.get(id) {
task.set_paused(false);
self.task_queue.push(id);
}
}
pub fn interrupt_subscribe(&mut self, pid: usize, interrupt_type: u8) {
self.pause(pid);
self.interrupt_lookup[interrupt_type as usize] = Some(pid);
}
pub fn buffer_subscribe(&mut self, pid: usize, buffer_id: usize) {
self.pause(pid);
if let Some(buf) = self.buffer_lookup.get_mut(&buffer_id) {
buf.insert(pid);
} else {
self.buffer_lookup.insert(buffer_id, BTreeSet::from([pid]));
}
}
pub fn run(&mut self) {
{
let mut global_spawner = SPAWN_QUEUE.write();
if global_spawner.is_some() {
panic!("Task executor is already running");
}
*global_spawner = Some(Arc::clone(&self.to_spawn));
}
let mut task_batch = [0; 32];
loop {
when! {
let Some(id) = self
.to_spawn
.pop()
.map(|t| TaskId(self.tasks.insert(t)))
.or_else(|| self.queue.pop())
=> {
let Some(task) = self.tasks.get_mut(id.0) else {
panic!("Attempted to get task from empty slot: {}", id.0);
};
let mut batch_len = 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),
}))
}));
while let Some(id) = self.task_queue.pop() {
task_batch[batch_len] = id;
batch_len += 1;
if batch_len == task_batch.len() {
break;
}
}
match task.poll(&mut cx) {
Poll::Ready(()) => {
self.tasks.remove(id.0);
self.wakers.remove(&id);
}
Poll::Pending => (),
if batch_len == 0 {
// break;
continue;
}
for &(mut id) in &task_batch[..batch_len] {
if let Some(task) = self.tasks.get_mut(id) {
if task.is_paused() {
continue;
}
},
self.tasks.is_empty() => break,
_ => (),
let waker = create_waker(id, Arc::clone(&self.task_queue));
let mut cx = ContextBuilder::from_waker(&waker).ext(&mut id).build();
if let Poll::Ready(()) = task.poll(&mut cx) {
self.tasks.remove(id);
self.interrupt_lookup.map(|pid| {
if let Some(pid) = pid {
if pid == id {
return None;
}
}
return pid;
});
self.buffer_lookup.iter_mut().for_each(|(_, pid_set)| {
pid_set.remove(&id);
});
}
}
}
}
}
*SPAWN_QUEUE.write() = None;
pub fn send_interrupt(&self, interrupt: u8) {
let id = self.interrupt_lookup[interrupt as usize];
if let Some(id) = id {
self.unpause(id);
}
}
pub fn send_buffer(&self, id: usize) {
if let Some(buf) = self.buffer_lookup.get(&id) {
buf.iter().for_each(|pid| self.unpause(*pid));
}
}
}
struct Task {
future: Pin<Box<dyn Future<Output = ()> + Send>>,
future: Pin<Box<dyn Process>>,
paused: AtomicBool,
}
impl Task {
pub fn new(future: impl Future<Output = ()> + Send + 'static) -> Self {
log::trace!("New task scheduled");
fn new(future: Pin<Box<dyn Process>>) -> Self {
Self {
future: Box::pin(future),
future,
paused: AtomicBool::new(false),
}
}
fn poll(&mut self, cx: &mut Context) -> Poll<()> {
self.future.as_mut().poll(cx)
}
fn is_paused(&self) -> bool {
self.paused.load(Ordering::Acquire)
}
fn set_paused(&self, paused: bool) {
self.paused.store(paused, Ordering::Release)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
struct TaskId(usize);
type TaskQueue = Arc<SegQueue<TaskId>>;
type SpawnQueue = Arc<SegQueue<Task>>;
fn create_waker(task_id: usize, task_queue: Arc<SegQueue<usize>>) -> Waker {
let data = Box::new(TaskWaker {
task_id,
task_queue,
});
let raw_waker = RawWaker::new(Box::into_raw(data) as *const (), &VTABLE);
unsafe { Waker::from_raw(raw_waker) }
}
#[derive(Clone)]
struct TaskWaker {
id: TaskId,
queue: TaskQueue,
task_id: usize,
task_queue: Arc<SegQueue<usize>>,
}
impl Wake for TaskWaker {
fn wake(self: Arc<Self>) {
log::trace!("Woke Task-{:?}", self.id);
self.wake_by_ref();
}
fn wake_by_ref(self: &Arc<Self>) {
self.queue.push(self.id);
impl TaskWaker {
fn wake(&self) {
self.task_queue.push(self.task_id);
}
}
const VTABLE: RawWakerVTable = RawWakerVTable::new(clone_raw, wake_raw, wake_by_ref_raw, drop_raw);
unsafe fn clone_raw(ptr: *const ()) -> RawWaker {
let task_waker = Box::from_raw(ptr as *mut TaskWaker);
let raw_waker = RawWaker::new(Box::into_raw(task_waker.clone()) as *const (), &VTABLE);
raw_waker
}
unsafe fn wake_raw(ptr: *const ()) {
let task_waker = Box::from_raw(ptr as *mut TaskWaker);
task_waker.wake();
}
unsafe fn wake_by_ref_raw(ptr: *const ()) {
let task_waker = &*(ptr as *const TaskWaker);
task_waker.wake();
}
unsafe fn drop_raw(ptr: *const ()) {
drop(Box::from_raw(ptr as *mut TaskWaker));
}

View file

@ -4,15 +4,14 @@
/// 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) => {
($num:expr) => {
TAB.repeat($num)
}
};
}
// NOTE: this only reduces the code duplication in source code not in generated code!
@ -22,7 +21,7 @@ macro_rules! tab {
macro_rules! device_tree {
($devtree:expr, $dev_type_vec:expr) => {
for each_device_type in $dev_type_vec {
$devtree.devices.insert(each_device_type.to_string(), Vec::new());
$devtree.devices.insert(each_device_type, Vec::new());
}
};
}
@ -50,4 +49,4 @@ macro_rules! cpu_features {
$result_vec.push(("rdseed", rdseed));
$result_vec.push(("x2apic", x2));
};
}
}

View file

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

View file

@ -1,22 +1,22 @@
{
"llvm-target": "x86_64-unknown-none",
"data-layout": "e-m:e-i64:64-f80:128-n8:16:32:64-S128",
"arch": "x86_64",
"target-endian": "little",
"target-pointer-width": "64",
"target-c-int-width": "32",
"os": "none",
"executables": true,
"linker-flavor": "ld.lld",
"linker": "rust-lld",
"panic-strategy": "abort",
"disable-redzone": true,
"features": "",
"code-model": "kernel",
"pre-link-args": {
"ld.lld": [
"--gc-sections",
"--script=kernel/lds/x86_64.ld"
]
}
"llvm-target": "x86_64-unknown-none",
"data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128",
"arch": "x86_64",
"target-endian": "little",
"target-pointer-width": "64",
"target-c-int-width": "32",
"os": "none",
"executables": true,
"linker-flavor": "ld.lld",
"linker": "rust-lld",
"panic-strategy": "abort",
"disable-redzone": true,
"features": "",
"code-model": "kernel",
"pre-link-args": {
"ld.lld": [
"--gc-sections",
"--script=kernel/lds/x86_64.ld"
]
}
}

View file

@ -0,0 +1,22 @@
{
"llvm-target": "x86_64-unknown-none",
"data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128",
"arch": "x86_64",
"target-endian": "little",
"target-pointer-width": "64",
"target-c-int-width": "32",
"os": "none",
"executables": true,
"linker-flavor": "ld.lld",
"linker": "rust-lld",
"panic-strategy": "abort",
"disable-redzone": true,
"features": "+sse4.1,+avx,+aes,+fma,+popcnt,+bmi2,+avx2,+lzcnt,+xsave",
"code-model": "kernel",
"pre-link-args": {
"ld.lld": [
"--gc-sections",
"--script=kernel/lds/x86_64.ld"
]
}
}

2
known_bugs.md Normal file
View file

@ -0,0 +1,2 @@
# i did not know where to put this
- memcpy / memset cause crash on debug builds due to ptr misalignment that is not present on release builds

View file

@ -4,12 +4,18 @@ version = "0.2.0"
edition = "2021"
[dependencies]
derive_more = "0.99"
error-stack = "0.4"
fatfs = "0.3"
hbasm.git = "https://git.ablecorp.us/AbleOS/holey-bytes.git"
[dependencies.reqwest]
version = "0.11"
default-features = false
features = ["rustls-tls", "blocking"]
str-reader = "0.1"
derive_more = { version = "1", default-features = false, features = [
"display",
] }
error-stack = "0.5"
fatfs = { version = "0.3", default-features = false, features = [
"std",
"alloc",
] }
toml = "0.8"
hblang.git = "https://git.ablecorp.us/AbleOS/holey-bytes.git"
# hblang.path = "../../holey-bytes/lang/"
log = "0.4"
raw-cpuid = "11"
ureq = { version = "2", default-features = false, features = ["tls"] }

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

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

View file

@ -1,59 +1,103 @@
mod dev;
use {
core::fmt::Write as _,
derive_more::Display,
dev::Package,
error_stack::{bail, report, Context, Report, Result, ResultExt},
fatfs::{FileSystem, FormatVolumeOptions, FsOptions, ReadWriteSeek},
std::{fmt::Display, fs::File, io, path::Path, process::Command},
std::{
fs::{self, File},
io::{self, Write},
path::Path,
process::{exit, Command, Stdio},
},
toml::Value,
};
fn main() -> Result<(), Error> {
let mut args = std::env::args();
args.next();
// let disk_meta = fs::metadata("target/disk.img").unwrap();
// let config_meta = fs::metadata("system.toml").unwrap();
// if disk_meta.modified().unwrap() < config_meta.modified().unwrap() {
// // TODO: work on adding in system.toml support
// // TODO: rebuild the disk
// }
log::set_logger(&hblang::Logger).unwrap();
log::set_max_level(log::LevelFilter::Error);
match args.next().as_deref() {
Some("build" | "b") => {
let mut release = false;
let mut debuginfo = false;
let mut target = Target::X86_64;
let mut tests = false;
for arg in args {
if arg == "-r" || arg == "--release" {
release = true;
} else if arg == "-d" || arg == "--debuginfo" {
debuginfo = true;
} else if arg == "rv64" || arg == "riscv64" || arg == "riscv64-virt" {
target = Target::Riscv64Virt;
} else if arg == "arm64" || arg == "aarch64" || arg == "aarch64-virt" {
target = Target::Aarch64;
} else if arg == "avx2" {
target = Target::X86_64Avx2;
} else if arg == "--ktest" {
tests = true;
} else {
return Err(report!(Error::InvalidSubCom));
}
}
assemble()?;
build(release, target).change_context(Error::Build)
build(release, target, debuginfo, tests).change_context(Error::Build)
}
// Some("test" | "t") => {
// let mut release = false;
// let mut debuginfo = false;
// let mut target = Target::X86_64;
// for arg in args {
// if arg == "-r" || arg == "--release" {
// release = true;
// } else if arg == "-d" || arg == "--debuginfo" {
// debuginfo = true;
// } else if arg == "rv64" || arg == "riscv64" || arg == "riscv64-virt" {
// target = Target::Riscv64Virt;
// } else if arg == "arm64" || arg == "aarch64" || arg == "aarch64-virt" {
// target = Target::Aarch64;
// } else if arg == "avx2" {
// target = Target::X86_64Avx2;
// } else {
// return Err(report!(Error::InvalidSubCom));
// }
// }
// test(release, target, debuginfo).change_context(Error::Build)
// }
Some("run" | "r") => {
let mut release = false;
let mut debuginfo = false;
let mut target = Target::X86_64;
let mut tests = false;
let mut do_accel = true;
for arg in args {
if arg == "-r" || arg == "--release" {
release = true;
} else if arg == "-d" || arg == "--debuginfo" {
debuginfo = true;
} else if arg == "rv64" || arg == "riscv64" || arg == "riscv64-virt" {
target = Target::Riscv64Virt;
} else if arg == "arm64" || arg == "aarch64" || arg == "aarch64-virt" {
target = Target::Aarch64;
} else if arg == "--noaccel" {
do_accel = false;
} else if arg == "avx2" {
target = Target::X86_64Avx2;
} else if arg == "--ktest" {
tests = true;
} else {
return Err(report!(Error::InvalidSubCom));
}
}
assemble()?;
build(release, target)?;
run(release, target)
build(release, target, debuginfo, tests)?;
run(release, target, do_accel)
}
Some("help" | "h") => {
println!(concat!(
@ -63,8 +107,11 @@ fn main() -> Result<(), Error> {
" help (h): Print this message\n",
" run (r): Build and run AbleOS in QEMU\n\n",
"Options for build and run:\n",
" -r: build in release mode",
" [target]: sets target"
" -r / --release: build in release mode\n",
" -d / --debuginfo: build with debug info\n",
" --noaccel: run without acceleration (e.g, no kvm)\n",
" --ktest: Enables tests via ktest\n",
"[ rv64 / riscv64 / riscv64-virt / aarch64 / arm64 / aarch64-virt / avx2 ]: sets target"
),);
Ok(())
}
@ -72,50 +119,13 @@ fn main() -> Result<(), Error> {
}
}
fn assemble() -> Result<(), Error> {
match std::fs::create_dir("target/test-programs") {
Ok(_) => (),
Err(e) if e.kind() == std::io::ErrorKind::AlreadyExists => (),
Err(e) => return Err(Report::new(e).change_context(Error::Io)),
}
for entry in std::fs::read_dir("sysdata/test-programs")
.map_err(Report::from)
.change_context(Error::Io)?
{
let entry = entry.map_err(Report::from).change_context(Error::Io)?;
if !entry
.file_type()
.map_err(Report::from)
.change_context(Error::Io)?
.is_file()
{
continue;
}
let name = entry.file_name();
let name = name.to_string_lossy();
let name = name.trim_end_matches(".rhai");
let mut out = File::options()
.write(true)
.create(true)
.open(Path::new("target/test-programs").join(format!("{name}.hbf")))
.map_err(Report::from)
.change_context(Error::Io)?;
out.set_len(0)
.map_err(Report::from)
.change_context(Error::Io)?;
hbasm::assembler(&mut out, |engine| engine.run_file(entry.path()))
.map_err(|e| report!(Error::Assembler).attach_printable(e.to_string()))?;
}
Ok(())
fn get_path_without_boot_prefix(val: &Value) -> Option<&str> {
val.as_str()?.split("boot:///").last()
}
fn get_fs() -> Result<FileSystem<impl ReadWriteSeek>, io::Error> {
let filename = "sysdata/system_config.toml";
let mut img = File::options()
.read(true)
.write(true)
@ -127,8 +137,177 @@ fn get_fs() -> Result<FileSystem<impl ReadWriteSeek>, io::Error> {
fatfs::format_volume(&mut img, FormatVolumeOptions::new())?;
let fs = FileSystem::new(img, FsOptions::new())?;
// Read the contents of the file using a `match` block
// to return the `data: Ok(c)` as a `String`
// or handle any `errors: Err(_)`.
let contents = match fs::read_to_string(filename) {
// If successful return the files text as `contents`.
// `c` is a local variable.
Ok(c) => c,
// Handle the `error` case.
Err(_) => {
// Write `msg` to `stderr`.
eprintln!("Could not read file `{}`", filename);
// Exit the program with exit code `1`.
exit(1);
}
};
use toml::Value;
let mut limine_str = String::new();
let mut data: Value = toml::from_str(&contents).unwrap();
let boot_table = data.get_mut("boot");
let limine_table = boot_table.unwrap().get_mut("limine").unwrap();
let default_entry = limine_table.get("default_entry").unwrap();
let timeout = limine_table.get("timeout").unwrap();
let interface_resolution = limine_table.get("interface_resolution").unwrap();
let verbose = limine_table.get("verbose").unwrap();
let term_wallpaper = limine_table.get("term_wallpaper").unwrap();
let vb_post = match verbose.as_bool().unwrap() {
true => "yes",
false => "no",
};
let term_background = limine_table
.get("term_backdrop")
.unwrap_or(&Value::Integer(0));
let base = format!(
"DEFAULT_ENTRY={}
TIMEOUT={}
VERBOSE={}
INTERFACE_RESOLUTION={}
# Terminal related settings
TERM_WALLPAPER={}
TERM_BACKDROP={}
",
default_entry,
timeout,
vb_post,
interface_resolution,
term_wallpaper.as_str().unwrap(),
term_background
);
// Copy the term_wallpaper to the image
let term_wallpaper_path = get_path_without_boot_prefix(term_wallpaper).unwrap();
copy_file_to_img(&format!("sysdata/{}", term_wallpaper_path), &fs);
limine_str.push_str(&base);
let boot_entries = limine_table.as_table_mut().unwrap();
let mut real_boot_entries = boot_entries.clone();
for (key, value) in boot_entries.into_iter() {
if !value.is_table() {
real_boot_entries.remove(key);
}
}
for (name, mut value) in real_boot_entries {
let comment = value.get("comment").unwrap();
let protocol = value.get("protocol").unwrap();
let resolution = value.get("resolution").unwrap();
let kernel_path = value.get("kernel_path").unwrap();
let kernel_cmdline = value.get("kernel_cmdline").unwrap();
let text_entry = format!(
"
:{}
COMMENT={}
PROTOCOL={}
RESOLUTION={}
KERNEL_PATH={}
KERNEL_CMDLINE={}
",
name,
comment.as_str().unwrap(),
protocol.as_str().unwrap(),
resolution.as_str().unwrap(),
kernel_path.as_str().unwrap(),
kernel_cmdline,
);
limine_str.push_str(&text_entry);
let modules = value.get_mut("modules").unwrap().as_table_mut().unwrap();
// let mut real_modules = modules.clone();
let mut errors = String::new();
let mut out = Vec::new();
modules
.into_iter()
.map(|(_, value)| -> Result<(), io::Error> {
if value.is_table() {
let path = get_path_without_boot_prefix(
value.get("path").expect("You must have `path` as a value"),
)
.unwrap()
.split(".")
.next()
.unwrap();
let p = Package::load_from_file(
format!("sysdata/programs/{}/meta.toml", path).to_owned(),
);
match p.build(&mut out) {
Ok(()) => {}
Err(e) => {
writeln!(errors, "========= while compiling {} {} =========", path, e)
.unwrap();
errors.push_str(&String::from_utf8_lossy(&out));
out.clear();
}
}
}
Ok(())
})
.for_each(drop);
if !errors.is_empty() {
let _ = writeln!(errors, "!!! STOPPING DUE TO PREVIOUS ERRORS !!!");
std::eprint!("{errors}");
continue;
}
modules.into_iter().for_each(|(_key, value)| {
if value.is_table() {
let path = value.get("path").expect("You must have `path` as a value");
let default_value = Value::String("".into());
let cmd_line = value.get("cmd_line").unwrap_or(&default_value);
let a = format!(
" MODULE_PATH={}
MODULE_CMDLINE={}\n\n",
path.as_str().unwrap(),
cmd_line
);
limine_str.push_str(&a);
}
});
// Copy modules into the test_programs directory
modules.into_iter().for_each(|(_key, value)| {
if value.is_table() {
let path = get_path_without_boot_prefix(
value
.get("path")
.expect("You must have a `path` as a value"),
)
.unwrap();
let fpath = format!("target/programs/{}", path);
copy_file_to_img(&fpath, &fs);
}
});
}
let bootdir = fs.root_dir().create_dir("efi")?.create_dir("boot")?;
let mut f = fs.root_dir().create_file("limine.cfg")?;
let _ = f.write(limine_str.as_bytes())?;
drop(f);
io::copy(
&mut File::open("limine/BOOTX64.EFI")
.map_err(Report::from)
@ -143,31 +322,24 @@ fn get_fs() -> Result<FileSystem<impl ReadWriteSeek>, io::Error> {
&mut bootdir.create_file("bootaa64.efi")?,
)?;
for fpath in [
"sysdata/limine.cfg",
"sysdata/background.bmp",
"target/test-programs/failure.hbf",
"target/test-programs/ecall.hbf",
"target/test-programs/main.hbf",
"target/test-programs/serial_driver.hbf",
"target/test-programs/vfs_test.hbf",
"target/test-programs/limine_framebuffer_driver.hbf",
"target/test-programs/keyboard_driver.hbf",
] {
let path = Path::new(fpath);
io::copy(
&mut File::open(path)?,
&mut fs
.root_dir()
.create_file(&path.file_name().unwrap().to_string_lossy())?,
)?;
}
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, tests: bool) -> Result<(), Error> {
let fs = get_fs().change_context(Error::Io)?;
let mut com = Command::new("cargo");
com.current_dir("kernel");
@ -175,6 +347,13 @@ fn build(release: bool, target: Target) -> Result<(), Error> {
if release {
com.arg("-r");
}
if debuginfo {
com.env("RUSTFLAGS", "-Cdebug-assertions=true");
}
if tests {
com.args(["--features", "ktest"]);
}
if target == Target::Riscv64Virt {
com.args(["--target", "targets/riscv64-virt-ableos.json"]);
@ -182,6 +361,9 @@ fn build(release: bool, target: Target) -> Result<(), Error> {
if target == Target::Aarch64 {
com.args(["--target", "targets/aarch64-virt-ableos.json"]);
}
if target == Target::X86_64Avx2 {
com.args(["--target", "targets/x86_64_v3-ableos.json"]);
}
match com.status() {
Ok(s) if s.code() != Some(0) => bail!(Error::Build),
@ -195,6 +377,10 @@ fn build(release: bool, target: Target) -> Result<(), Error> {
path.push_str("_x86-64");
"target/x86_64-ableos"
}
Target::X86_64Avx2 => {
path.push_str("_x86-64");
"target/x86_64_v3-ableos"
}
Target::Riscv64Virt => "target/riscv64-virt-ableos",
Target::Aarch64 => {
path.push_str("_aarch64");
@ -217,24 +403,73 @@ fn build(release: bool, target: Target) -> Result<(), Error> {
.change_context(Error::Io)
}
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"),
fn run(release: bool, target: Target, do_accel: bool) -> Result<(), Error> {
let target_str = match target {
Target::X86_64 | Target::X86_64Avx2 => "qemu-system-x86_64",
Target::Riscv64Virt => "qemu-system-riscv64",
Target::Aarch64 => "qemu-system-aarch64",
};
let (mut com, mut com2) = (Command::new(target_str), Command::new(target_str));
let ovmf_path = fetch_ovmf(target);
#[cfg(target_arch = "x86_64")]
let accel = if do_accel {
let supported = String::from_utf8(
com2.args(["--accel", "help"])
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()
.unwrap()
.wait_with_output()
.unwrap()
.stdout,
)
.unwrap();
let cpuid = raw_cpuid::CpuId::new();
let vmx = cpuid.get_feature_info().unwrap().has_vmx();
let svm = cpuid.get_svm_info().is_some();
if supported.contains("kvm") && (vmx || svm) {
"accel=kvm"
} else if cpuid
.get_processor_brand_string()
.filter(|a| a.as_str() == "GenuineIntel")
.is_some()
&& supported.contains("hax")
&& vmx
{
"accel=hax"
} else if supported.contains("whpx") {
"accel=whpx"
} else {
"accel=tcg"
}
} else {
"accel=tcg"
};
#[cfg(not(target_arch = "x86_64"))]
let accel = "accel=tcg";
match target {
Target::X86_64 => {
Target::X86_64 | Target::X86_64Avx2 => {
#[rustfmt::skip]
com.args([
"-bios", &ovmf_path.change_context(Error::OvmfFetch)?,
"-drive", "file=target/disk.img,format=raw",
"-m", "4G",
"-smp", "cores=4",
// "-enable-kvm",
"-cpu", "Broadwell-v4"
//"-hda", "target/disk.img",
"-drive", "file=target/disk.img,index=0,if=ide,format=raw",
"-device", "vmware-svga",
// "-serial", "stdio",
"-m", "2G",
"-smp", "1",
"-audiodev",
"pa,id=speaker",
"-machine",
"pcspk-audiodev=speaker",
"-parallel", "none",
"-monitor", "none",
"-machine", accel,
"-cpu", "max",
"-device", "isa-debug-exit,iobase=0xf4,iosize=0x04",
]);
}
Target::Riscv64Virt => {
@ -255,7 +490,7 @@ fn run(release: bool, target: Target) -> Result<(), Error> {
#[rustfmt::skip]
com.args([
"-M", "virt",
"-cpu", "cortex-a72",
"-cpu", "max",
"-device", "ramfb",
"-device", "qemu-xhci",
"-device", "usb-kbd",
@ -278,7 +513,7 @@ 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 => (
Target::X86_64 | Target::X86_64Avx2 => (
"https://retrage.github.io/edk2-nightly/bin/RELEASEX64_OVMF.fd",
"target/RELEASEX64_OVMF.fd",
),
@ -300,12 +535,12 @@ fn fetch_ovmf(target: Target) -> Result<String, OvmfFetchError> {
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)
let req = ureq::get(ovmf_url)
.call()
.map_err(Report::from)
.change_context(OvmfFetchError::Fetch)?;
bytes
.copy_to(&mut file)
std::io::copy(&mut req.into_reader(), &mut file)
.map_err(Report::from)
.change_context(OvmfFetchError::Io)?;
@ -314,11 +549,11 @@ fn fetch_ovmf(target: Target) -> Result<String, OvmfFetchError> {
#[derive(Debug, Display)]
enum OvmfFetchError {
#[display(fmt = "Failed to fetch OVMF package")]
#[display("Failed to fetch OVMF package")]
Fetch,
#[display(fmt = "No OVMF package available")]
#[display("No OVMF package available")]
Empty,
#[display(fmt = "IO Error")]
#[display("IO Error")]
Io,
}
@ -327,30 +562,33 @@ impl Context for OvmfFetchError {}
#[derive(Clone, Copy, PartialEq, Eq)]
enum Target {
X86_64,
X86_64Avx2,
Riscv64Virt,
Aarch64,
}
#[allow(unused)]
#[derive(Debug, Display)]
enum Error {
#[display(fmt = "Failed to build the kernel")]
#[display("Failed to build the kernel")]
Build,
#[display(fmt = "Missing or invalid subcommand (available: build, run)")]
#[display("Missing or invalid subcommand (available: build, run)")]
InvalidSubCom,
#[display(fmt = "IO Error")]
#[display("IO Error")]
Io,
#[display(fmt = "Failed to spawn a process")]
#[display("Failed to spawn a process")]
ProcessSpawn,
#[display(fmt = "Failed to fetch UEFI firmware")]
#[display("Failed to fetch UEFI firmware")]
OvmfFetch,
#[display(fmt = "Failed to assemble Holey Bytes code")]
#[display("Failed to assemble Holey Bytes code")]
Assembler,
#[display(fmt = "QEMU Error: {}", "fmt_qemu_err(*_0)")]
#[display("QEMU Error: {}", "fmt_qemu_err(*_0)")]
Qemu(Option<i32>),
}
impl Context for Error {}
#[allow(dead_code)]
fn fmt_qemu_err(e: Option<i32>) -> impl Display {
struct W(Option<i32>);
impl Display for W {

View file

@ -1,3 +1,7 @@
[toolchain]
channel = "nightly"
# old toolchain
# channel = "nightly-2024-07-27"
# last stable
# channel = "nightly-2024-11-20"
channel = "nightly"
components = ["rust-src", "llvm-tools"]

BIN
sysdata/assets/able.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 100 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -0,0 +1,10 @@
Tamsyn font is free. You are hereby granted permission to use, copy, modify,
and distribute it as you see fit.
Tamsyn font is provided "as is" without any express or implied warranty.
The author makes no representations about the suitability of this font for
a particular purpose.
In no event will the author be held liable for damages arising from the use
of this font.

BIN
sysdata/assets/mini.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 100 KiB

BIN
sysdata/assets/mini.qoi Normal file

Binary file not shown.

Binary file not shown.

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>

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 B

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,3 @@
# Horizon
Horizon is the windowing system for ableOS.
This is the API library to handle it nicely.

View file

@ -0,0 +1,4 @@
(horizontal
spacing : 10
(label "hi")
(label "goodbye"))

View file

@ -0,0 +1 @@
(label "hello")

View file

@ -0,0 +1,3 @@
(vertical
(label "hello")
(label "hello" color:red))

View file

@ -0,0 +1,43 @@
stn := @use("../../stn/src/lib.hb");
.{string, memory, buffer, log} := stn
render := @use("../../../libraries/render/src/lib.hb")
input := @use("../../intouch/src/lib.hb")
widgets := @use("widgets/widgets.hb")
ui := @use("ui.hb")
WindowID := struct {
host_id: int,
window_id: int,
}
VoidWindowID := WindowID.(0, 0)
create_window := fn(channel: int): ^render.Surface {
// 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")
mem_buf := memory.request_page(1)
if windowing_system_buffer == 0 {
return @as(^render.Surface, idk)
} else {
x := 0
loop if x > 1000 break else x += 1
ret := buffer.recv([4096]u8, windowing_system_buffer, mem_buf)
if ret == null {
log.info("No messages\0")
}
if *mem_buf == 0 {
log.info("No messages\0")
}
return @as(^render.Surface, idk)
}
}

View file

@ -0,0 +1,47 @@
stn := @use("../../../libraries/stn/src/lib.hb");
.{string, log} := stn;
.{Vec2} := stn.math
render := @use("../../../libraries/render/src/lib.hb");
.{Surface} := render;
.{Font} := render.text
UI := struct {raw: ^u8, raw_length: uint, is_dirty: bool, surface: Surface, // Each child has their WidgetType as their first byte
// children: ^^u8,
}
render_ui := fn(surface: Surface, ui: UI): void {
if ui.is_dirty {
render.clear(ui.surface, render.black)
ui.is_dirty = false
}
pos := Vec2(uint).(0, 0)
render.put_surface(surface, ui.surface, pos, false)
}
sexpr_parser := fn(sexpr: ^u8): UI {
cursor := sexpr
paren_balance := 0
loop {
if *cursor == 0 {
if paren_balance != 0 {
log.error("Unbalanced Parens\0")
}
break
} else if *cursor == 40 {
log.info("Open paren\0")
paren_balance += 1
} else if *cursor == 41 {
log.info("Closed paren\0")
paren_balance -= 1
}
cursor += 1
}
length := string.length(sexpr)
ui_surface := render.new_surface(100, 100)
return UI.(sexpr, length, true, ui_surface)
}

View file

@ -0,0 +1,13 @@
render := @use("../../../../libraries/render/src/lib.hb");
.{Surface} := render
Image := struct {
magic: uint,
is_dirty: bool,
surface: Surface,
}
image_from_surface := fn(surface: Surface): Image {
img := Image.(4, true, surface)
return img
}

View file

@ -0,0 +1,46 @@
stn := @use("../../../../libraries/stn/src/lib.hb");
.{string, log} := stn;
.{Vec2} := stn.math
render := @use("../../../../libraries/render/src/lib.hb");
.{Surface, Color} := render;
.{Font} := render.text
Label := struct {
magic: uint,
is_dirty: bool,
surface: Surface,
text: ^u8,
text_length: uint,
bg: Color,
fg: Color,
new_label := fn(text: ^u8, width: uint): Self {
text_surface := render.Surface.new(width, 20)
text_length := string.length(text)
label := Self.(3, true, text_surface, text, text_length, render.BLACK, render.WHITE)
return label
}
set_label_text := fn(self: Self, text: ^u8): void {
text_length := string.length(text)
self.is_dirty = true
self.text = text
self.text_length = text_length
}
$set_color := fn(self: Self, bg: Color, fg: Color): void {
self.bg = bg
self.fg = fg
self.is_dirty = true
}
}
render_label_to_surface := fn(surface: Surface, label: Label, font: Font, pos: Vec2(uint)): void {
if label.is_dirty {
label.surface.clear(label.bg)
label.surface.put_text(font, .(0, 0), label.fg, label.text)
}
surface.put_surface(label.surface, pos, false)
}

View file

@ -0,0 +1,7 @@
NoWidget := 0
VerticalWidgetType := 1
HorizontalWidgetType := 2
LabelWidgetType := 3
ImageWidgetType := 4

View file

@ -0,0 +1,36 @@
// Widget types
// End types
stn := @use("../../../../libraries/stn/src/lib.hb");
.{string, log} := stn;
.{Vec2} := stn.math
render := @use("../../../../libraries/render/src/lib.hb");
.{Surface} := render;
.{Font} := render.text
widget_types := @use("widget_types.hb")
label := @use("label.hb")
image := @use("image.hb")
Size := struct {
min_width: int,
max_width: int,
min_height: int,
max_height: int,
}
Vertical := packed struct {
magic: uint,
// array of children, idk
// use a vec or linked list or whatever
children: ^^u8,
}
Horizontal := packed struct {
magic: uint,
// array of children, idk
// use a vec or linked list or whatever
children: ^^u8,
}

View file

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

View file

@ -0,0 +1,21 @@
structures := @use("structures.hb")
version := @use("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: ^u8,
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
}

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