1
0
Fork 0
forked from AbleOS/ableos

Compare commits

..

235 commits

Author SHA1 Message Date
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
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
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
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
251 changed files with 7749 additions and 3131 deletions

View file

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

View file

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

1420
Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -1,3 +1,9 @@
[workspace]
resolver = "2"
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

@ -10,15 +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).
For running AbleOS, `repbuild` uses QEMU.
## Steps
1. Ensure you have qemu installed
2. `git submodule update --init`
3. `cargo repbuild run`
See [HELP.md](HELP.md)
# Developing
There is a new work in progress developer tool for hblang.
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 @@
declarations ::= <declaration> <declarations>
declaration ::= <enum_decl> | <struct_decl> | <type_decl> | <protocol_decl>
type_decl ::= "type" <ident> <ident> ";"
enum_decl ::= "enum" <ident> "{" "}"
| "enum" <ident> "{" <enum_members> "}"
enum_members ::= <enum_member> ["," <enum_member>]+ [","]
enum_member ::= <ident> "=" <number>
struct_decl ::= "struct" <ident> "{" "}"
| "struct" <ident> "{" <struct_members> "}"
struct_members ::= <struct_member>
| <struct_member> ","
| <struct_member> "," <struct_members>
| <struct_member> "," <struct_members>
protocol_decl ::= "protocol" <ident> "{" "}"
| "protocol" <ident> "{" <protocol_member>+ "}"
protocol_member ::= "fn" <ident>"("[<arg_list>]")" "->" <ident> ";"
arg_list ::= <ident> ["," <ident>]+

View file

@ -1,78 +1,56 @@
mod parser;
mod types;
mod protocol;
pub mod protocol;
use crate::idl::{parser::parse, types::get_protocols};
use std::io::Read;
use logos::{Lexer, Logos, Skip};
use {
logos::{Lexer, Logos},
protocol::Protocol,
};
#[derive(Logos, Debug, PartialEq, Clone)]
#[logos(extras = (usize, usize))]
#[logos(skip r"[ \t\n\f]+")] // Ignore this regex pattern between tokens
enum Token {
#[regex("//[^\n]*", logos::skip)]
Comment,
#[regex(r"[ \t\f]+", logos::skip)]
Ignored,
#[regex(r"\n", newline_callback)]
Newline,
// Tokens can be literal strings, of any length.
#[token("protocol", get_token_position)]
Protocol((usize,usize)),
#[token("protocol")]
Protocol,
// Tokens can be literal strings, of any length.
#[token("type", get_token_position)]
Type((usize, usize)),
#[token("{")]
LBrace,
#[token("fn", priority = 5, callback = get_token_position)]
Fn((usize, usize)),
#[token("}")]
RBrace,
#[token("enum", get_token_position)]
Enum((usize, usize)),
#[token("(")]
LParen,
#[token("struct", get_token_position)]
Struct((usize, usize)),
#[token(")")]
RParen,
#[token("{", get_token_position)]
LBrace((usize, usize)),
#[token(":")]
Colon,
#[token(";")]
SemiColon,
#[token("}", get_token_position)]
RBrace((usize, usize)),
#[token(",")]
Comma,
#[token("(", get_token_position)]
LParen((usize, usize)),
#[token("=")]
Equal,
#[token(")", get_token_position)]
RParen((usize, usize)),
#[token("->")]
RArrow,
#[token(":", get_token_position)]
Colon((usize, usize)),
#[regex("[a-zA-Z_]+", |lex|{lex.slice().to_string()})]
Text(String),
#[token(";", get_token_position)]
SemiColon((usize, usize)),
#[regex("[1234567890]+", |lex|{lex.slice().parse::<u64>().unwrap()})]
Number(u64),
#[token(",", get_token_position)] Comma((usize, usize)),
#[regex(r"@[a-zA-Z_]+", |lex|{lex.slice().to_string()})]
Decorator(String),
#[token("=", get_token_position)]
Equal((usize, usize)),
#[token("->", get_token_position)]
RArrow((usize, usize)),
#[regex("[a-zA-Z_][a-zA-Z_1234567890]+", |lex|{let text = lex.slice().to_string(); let (line, col) = get_token_position(lex); (line, col, text)})]
Identifier((usize, usize, String)),
#[regex("[1234567890]+", |lex|{let num = lex.slice().parse::<u64>().unwrap(); let (line, col) = get_token_position(lex); (line, col, num) })]
Number((usize, usize, u64)),
#[regex(r"@[a-zA-Z_]+", /*|lex|{lex.slice().to_string()}*/ logos::skip)]
Decorator,
#[regex(r#"@[a-zA-Z_]+\([a-zA-Z,0-9=]+\)"#, /*|lex|{lex.slice().to_string()}*/ logos::skip)]
DecoratorOption,
#[regex(r#"@[a-zA-Z_]+\([a-zA-Z,0-9=]+\)"#, |lex|{lex.slice().to_string()})]
DecoratorOption(String),
}
pub fn build_idl(name: String) {
@ -82,36 +60,25 @@ pub fn build_idl(name: String) {
for x in lex {
match x {
Ok(token) => {
println!("{:?}", token);
tokens.push(token);
}
Err(err) => println!("{:?}", err),
}
}
build(tokens);
}
let protocols = get_protocols(parse(tokens));
let data : Vec<u8> = vec![1, 5, 12, 12, 12, 12, 3, 28, 8, 28];
println!("{:#?}", &protocols);
protocols.validate("Foo", "bar" , data).unwrap();
fn build(a: Vec<Token>) {
for toke in a {
println!("{:?}", toke);
}
}
fn open_protocol(name: String) -> String {
let path = format!("sysdata/idl/{}/src/protocol.aldi", name);
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
}
fn get_token_position(lex : &mut Lexer<Token>) -> (usize, usize) {
let line = lex.extras.0;
let column = lex.span().start - lex.extras.1;
(line, column + 1)
}
/// Update the line count and the char index.
fn newline_callback(lex: &mut Lexer<Token>) -> Skip {
lex.extras.0 += 1;
lex.extras.1 = lex.span().end;
Skip
}

View file

@ -1,277 +0,0 @@
use std::{iter::Peekable, slice::Iter};
use super::Token;
#[derive(Debug, Clone, PartialEq)]
pub struct AST(pub Vec<Declaration>);
#[derive(Debug, Clone, PartialEq)]
pub enum Declaration{
EnumDeclaration(EnumDeclaration),
StructDeclaration(StructDeclaration),
TypeDeclaration(TypeDeclaration),
ProtocolDeclaration(ProtocolDeclaration),
}
#[derive(Debug, Clone, PartialEq)]
pub struct StructDeclaration {
pub name : String,
pub members : Vec<StructMember>,
}
#[derive(Debug, Clone, PartialEq)]
pub struct TypeDeclaration {
pub name : String,
pub type_name : String,
}
#[derive(Debug, Clone, PartialEq)]
pub struct StructMember {
pub name : String,
pub type_name : String,
}
#[derive(Debug, Clone, PartialEq)]
pub struct EnumDeclaration {
pub name : String,
pub members : Vec<EnumMember>,
}
#[derive(Debug, Clone, PartialEq)]
pub struct EnumMember {
pub name : String,
pub number: u64,
}
#[derive(Debug, Clone, PartialEq)]
pub struct ProtocolDeclaration{
pub name : String,
pub interface : Vec<FuncDeclaration>,
}
#[derive(Debug, Clone, PartialEq)]
pub struct FuncDeclaration {
pub name : String,
pub arg_list : Vec<String>,
pub return_type : String,
}
macro_rules! consume {
($tokens:ident, $token_type:path) => {
let a = $tokens.next();
match a {
None => panic!("Expected {}, Got End Of Tokens", stringify!($token_type)),
Some(t) => {
if matches!(t, $token_type(_)){}
else {
panic!("Expected {:?}, Got {:?}", stringify!($token_type), t);
}
}
}
};
}
pub fn parse(tokens : Vec<Token>) -> AST{
let mut tokens_iter = tokens.iter().peekable();
AST(declarations(&mut tokens_iter))
}
fn declarations(tokens : &mut Peekable<Iter<'_, Token>>) -> Vec<Declaration> {
let mut decls : Vec<Declaration> = Vec::new();
loop {
match declaration(tokens) {
Some(x) => decls.push(x),
None => break,
}
}
decls
}
fn declaration(tokens : &mut Peekable<Iter<'_, Token>>) -> Option<Declaration> {
match tokens.peek(){
None => None,
Some(tok) => match tok {
Token::Enum(_) => Some(enum_decl(tokens)),
Token::Struct(_) => Some(struct_decl(tokens)),
Token::Type(_) => Some(type_declaration(tokens)),
Token::Protocol(_) => Some(protocol_declaration(tokens)),
_ => None,
}
}
}
fn enum_decl(tokens : &mut Peekable<Iter<'_, Token>>) -> Declaration {
consume!(tokens, Token::Enum);
let name = identifier(tokens).expect("Expected Identifier after `enum`");
consume!(tokens, Token::LBrace);
let mut members = Vec::new();
match tokens.peek().expect("Unexpected EOF after LBrace") {
Token::RBrace(_) => {}, // skip checking for enum_members if empty
_ => {
enum_members(tokens, &mut members);
},
}
consume!(tokens, Token::RBrace);
Declaration::EnumDeclaration(EnumDeclaration{name, members})
}
fn enum_members(tokens : &mut Peekable<Iter<'_, Token>>, members: &mut Vec<EnumMember>) {
members.push(enum_member(tokens).unwrap());
loop {
match tokens.peek().expect("Unexpected EOF inside enum declaration") {
Token::Comma(_) => {
consume!(tokens, Token::Comma);
if let Some(member) = enum_member(tokens) {
members.push(member);
} else {
break;
}
},
_ => {},
}
}
}
fn enum_member(tokens : &mut Peekable<Iter<'_, Token>>) -> Option<EnumMember> {
let name = identifier(tokens);
if let Some(name) = name {
consume!(tokens, Token::Equal);
let number = parse_number(tokens).expect("Expected Number after `=`");
Some(EnumMember{name, number})
} else {
None
}
}
fn struct_decl(tokens : &mut Peekable<Iter<'_, Token>>) -> Declaration {
consume!(tokens, Token::Struct);
let name = identifier(tokens).expect("Expected Identifier after `struct`");
consume!(tokens, Token::LBrace);
let mut members = Vec::new();
match tokens.peek().expect("Unexpected EOF after LBrace") {
Token::RBrace(_) => {}, // skip checking for struct_members if empty
_ => {
struct_members(tokens, &mut members);
},
}
consume!(tokens, Token::RBrace);
Declaration::StructDeclaration(StructDeclaration{name, members})
}
fn struct_members(tokens : &mut Peekable<Iter<'_, Token>>, members: &mut Vec<StructMember>) {
members.push(struct_member(tokens).unwrap());
loop {
match tokens.peek().expect("Unexpected EOF inside struct declaration") {
Token::Comma(_) => {
consume!(tokens, Token::Comma);
if let Some(member) = struct_member(tokens) {
members.push(member);
} else {
break;
}
},
_ => {},
}
}
}
fn struct_member(tokens : &mut Peekable<Iter<'_, Token>>) -> Option<StructMember> {
let name = identifier(tokens);
if let Some(name) = name {
consume!(tokens, Token::Colon);
let type_name = identifier(tokens).expect("Expected Type after Colon");
Some(StructMember{name, type_name})
} else {
None
}
}
fn type_declaration(tokens : &mut Peekable<Iter<'_, Token>>) -> Declaration {
consume!(tokens, Token::Type);
let name = identifier(tokens).expect("Expected Identifier after `type`");
let type_name = identifier(tokens).expect("Expected type after Identifier");
Declaration::TypeDeclaration(TypeDeclaration{name, type_name})
}
fn identifier(tokens : &mut Peekable<Iter<'_, Token>>) -> Option<String> {
let result = tokens.peek().map_or(None, |x| match x {
Token::Identifier((_, _, s)) => {
Some(s.to_string())
},
_ => None
});
if let Some(_) = result {
tokens.next();
}
result
}
fn parse_number(tokens : &mut Peekable<Iter<'_, Token>>) -> Option<u64> {
let result = tokens.peek().map_or(None, |x| match x {
Token::Number((_, _, s)) => Some(*s),
_ => None
});
if let Some(_) = result {
tokens.next();
}
result
}
fn protocol_declaration(tokens : &mut Peekable<Iter<'_, Token>>) -> Declaration {
consume!(tokens, Token::Protocol);
let name = identifier(tokens).expect("Expected Identifier after `protocol`");
consume!(tokens, Token::LBrace);
let mut interface = Vec::new();
match tokens.peek().expect("Unexpected EOF after LBrace") {
Token::RBrace(_) => {},
_ => {
functions(tokens, &mut interface);
},
};
Declaration::ProtocolDeclaration(ProtocolDeclaration{name, interface})
}
fn functions(tokens : &mut Peekable<Iter<'_, Token>>, interface : &mut Vec<FuncDeclaration>) {
loop {
match function(tokens) {
Some(x) => interface.push(x),
None => break,
}
}
}
fn function(tokens : &mut Peekable<Iter<'_, Token>>) -> Option<FuncDeclaration>{
if let Some(Token::Fn(_)) = tokens.peek() {
consume!(tokens, Token::Fn);
let name = identifier(tokens).expect("Expected Identifier after `fn`");
consume!(tokens, Token::LParen);
let arg_list = arg_list(tokens);
consume!(tokens, Token::RParen);
consume!(tokens, Token::RArrow);
let return_type = identifier(tokens).expect("Expected return type after `->");
Some(FuncDeclaration{name, arg_list, return_type})
} else {
None
}
}
fn arg_list(tokens : &mut Peekable<Iter<'_, Token>>) -> Vec<String> {
let mut result = Vec::new();
loop {
match identifier(tokens) {
None => break,
Some(i) =>{
result.push(i);
if let Token::Comma(_) = **tokens.peek().expect("Unexpected EOF in argument list"){
consume!(tokens, Token::Comma);
match tokens.peek().expect("Unexpected EOF in argument list") {
Token::Identifier(_) => {},
_ => panic!("Unexpected symbol after Comma in argument list"),
}
}
}
}
}
result
}

View file

@ -1,167 +1,17 @@
use std::collections::HashMap;
use crate::idl::types::Type;
#[derive(Debug, Clone, PartialEq)]
pub struct Function{
pub arguments : Vec<String>,
}
#[derive(Debug, Clone, PartialEq)]
pub struct Protocol{
interface : HashMap<String, Function>,
pub enum ProtocolTypes {
Byte,
}
#[derive(Debug, Clone, PartialEq)]
pub struct Protocols {
protocols : HashMap<String, Protocol>,
symbol_table : HashMap<String, Type>,
}
#[derive(Debug, Clone, PartialEq)]
pub enum ValidationError{
IncorrectVersion,
InvalidHeader,
FunctionDoesNotExist,
ProtocolDoesNotExist,
InvalidSize,
InvalidArgument,
NonExistentType(String),
}
impl Protocols {
pub fn new(symbol_table: HashMap<String, Type>) -> Self {
let protocols = HashMap::new();
Self { protocols, symbol_table }
}
pub fn add_protocol(&mut self, name : String, interface : HashMap<String, Function>) {
self.protocols.insert(name, Protocol::new(interface));
}
pub fn validate(&self, protocol_name : &str, function_name : &str, data : Vec<u8>) -> Result<(), ValidationError>{
match self.protocols.get(protocol_name) {
Some(s) => s.validate(function_name, data, &self.symbol_table),
None => Err(ValidationError::ProtocolDoesNotExist),
}
}
}
pub struct Protocol {}
impl Protocol {
pub fn new(interface: HashMap<String, Function>) -> Self {
Self {interface}
}
fn validate(&self, function_name : &str, data : Vec<u8>, symbols : &HashMap<String, Type>) -> Result<(), ValidationError> {
match self.interface.get(function_name){
Some(s) => s.validate(data, symbols),
None => Err(ValidationError::FunctionDoesNotExist),
}
}
pub fn is_empty(&self) -> bool {
true
}
impl Function {
fn validate(&self, data : Vec<u8>, symbols : &HashMap<String, Type>) -> Result<(), ValidationError> {
let mut types = Vec::new();
for arg in self.arguments.iter() {
let type_value = symbols.get(arg);
if let Some(type_value) = type_value {
types.push(type_value);
pub fn validate_data(&self, data: Vec<u8>) -> bool {
if !data.is_empty() && self.is_empty() {
return false;
}
else{
return Err(ValidationError::NonExistentType(arg.to_string()));
true
}
}
let mut data = data.iter();
if let Some(ver) = data.next() {
if *ver == 1 {
// We got the correct version number
// Now to parse individual argumebts
let mut types = types.iter().peekable();
loop {
let type_byte = data.next();
if let Some(type_byte) = type_byte {
let type_value = types.next();
if type_value.is_none() {
return Err(ValidationError::InvalidSize);
}
let type_value = type_value.unwrap();
let data_type = match type_byte {
0 => Some(Type::U64),
1 => Some(Type::U32),
2 => Some(Type::U16),
3 => Some(Type::U8),
4 => Some(Type::I64),
5 => Some(Type::I32),
6 => Some(Type::I16),
7 => Some(Type::I8),
8 => Some(Type::Bool),
9 => Some(Type::F32),
10 => Some(Type::F64),
11 => Some(Type::Str),
_ => None,
};
if data_type.is_none() || data_type.as_ref().unwrap() != *type_value {
println!("{:#?}", *type_value);
return Err(ValidationError::InvalidArgument);
}
match data_type.unwrap(){
Type::U64 | Type::I64 | Type::F64 => {
data.next();
data.next();
data.next();
data.next();
data.next();
data.next();
data.next();
data.next();
},
Type::U32 | Type::I32 | Type::F32 => {
data.next();
data.next();
data.next();
data.next();
},
Type::U16 | Type::I16 => {
data.next();
data.next();
},
Type::U8 | Type::I8 | Type::Bool => {
data.next();
},
Type::Str => todo!(),
_ => panic!("Should not be possible"),
}
} else if types.peek().is_none() {
return Ok(());
}
break;
}
}
else {
return Err(ValidationError::IncorrectVersion);
}
} else {
return Err(ValidationError::InvalidHeader);
}
Ok(())
}
}

View file

@ -1,98 +0,0 @@
use std::collections::HashMap;
use crate::idl::parser::AST;
use super::protocol::{Function, Protocols};
#[derive(Debug, Clone, PartialEq)]
pub enum Type {
U64,
U32,
U16,
U8,
I64,
I32,
I16,
I8,
Bool,
F32,
F64,
Str,
Struct(StructType),
Enum(EnumType),
Alias(String),
}
#[derive(Debug, Clone, PartialEq)]
pub struct StructType {
members : HashMap<String, String>
}
#[derive(Debug, Clone, PartialEq)]
pub struct EnumType {
members : HashMap<String, u8>
}
fn add_builtin_types(symbol_table : &mut HashMap<String, Type>) {
symbol_table.insert("u8".to_string(), Type::U8);
symbol_table.insert("u16".to_string(), Type::U16);
symbol_table.insert("u32".to_string(), Type::U32);
symbol_table.insert("u64".to_string(), Type::U64);
symbol_table.insert("i8".to_string(), Type::I8);
symbol_table.insert("i16".to_string(), Type::I16);
symbol_table.insert("i32".to_string(), Type::I32);
symbol_table.insert("i64".to_string(), Type::I64);
symbol_table.insert("bool".to_string(), Type::Bool);
symbol_table.insert("f32".to_string(), Type::F32);
symbol_table.insert("f64".to_string(), Type::F64);
}
pub fn get_protocols(ast : AST) -> Protocols{
let mut symbol_table : HashMap<String, Type> = HashMap::new();
let declarations = ast.0;
add_builtin_types(&mut symbol_table);
// First Pass
// We just populate the symbol table here
for decl in declarations.iter() {
match decl{
super::parser::Declaration::EnumDeclaration(e) => {
let mut members = HashMap::new();
for m in e.members.iter(){
members.insert(m.name.to_string(), m.number as u8);
}
symbol_table.insert(e.name.to_string(), Type::Enum(EnumType{members}));
},
super::parser::Declaration::StructDeclaration(s) => {
let mut members = HashMap::new();
for m in s.members.iter() {
members.insert(m.name.to_string(), m.type_name.to_string());
}
symbol_table.insert(s.name.to_string(), Type::Struct(StructType{members}));
},
super::parser::Declaration::TypeDeclaration(t) => {
symbol_table.insert(t.name.to_string(), Type::Alias(t.type_name.to_string()));
},
super::parser::Declaration::ProtocolDeclaration(_) => {},
}
}
let mut protocols = Protocols::new(symbol_table);
for decl in declarations.iter(){
match decl {
super::parser::Declaration::ProtocolDeclaration(p) => {
let mut funcs : HashMap<String, Function> = HashMap::new();
for i in p.interface.iter(){
funcs.insert(i.name.to_string(), Function{arguments : i.arg_list.clone()});
}
protocols.add_protocol(p.name.to_string(), funcs);
},
_ => {}
}
}
protocols
}

View file

@ -57,7 +57,7 @@ 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.aldi"),
DevelopmentType::IDL => ("idl", "protocol.aidl"),
};
let project_folder_path_string = format!("sysdata/{folder_hierarchy}/{name}");
@ -72,6 +72,27 @@ pub fn new(development_type: DevelopmentType, name: String) {
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();

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,35 +3,32 @@ edition = "2021"
name = "kernel"
version = "0.2.0"
[features]
ktest = []
[dependencies]
embedded-graphics = "0.7"
hbvm.git = "https://git.ablecorp.us/ableos/holey-bytes"
# 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"
uart_16550 = "0.2"
slab = { version = "0.4", default-features = false }
uart_16550 = { version = "0.3", features = ["nightly"] }
xml.git = "https://git.ablecorp.us/ableos/ableos_userland"
versioning.git = "https://git.ablecorp.us/ableos/ableos_userland"
able_graphics_library.git = "https://git.ablecorp.us/ableos/ableos_userland"
hashbrown = "*"
kiam = "0.1.1"
[dependencies.limine]
version = "0.1"
git = "https://github.com/limine-bootloader/limine-rs"
# 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"
default-features = false
features = ["alloc", "nightly"]
[dependencies.derive_more]
version = "0.99"
version = "1"
default-features = false
features = [
"add",
@ -48,12 +45,12 @@ features = [
[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,8 +38,16 @@ SECTIONS
.data : {
*(.data .data.*)
*(.got .got.*)
} :data
/* Add the .ktest section for test functions */
.note.ktest : {
__ktest_start = .; /* Mark the beginning of the section */
*(.note.ktest) /* Include all items in the .ktest section */
__ktest_end = .; /* Mark the end of the section */
}
.bss : {
*(COMMON)
*(.bss .bss.*)

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();
@ -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;
@ -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);
x86_64::instructions::interrupts::enable();
}
idt.page_fault.set_handler_fn(page_fault);
idt[Interrupt::ApicErr as usize].set_handler_fn(apic_err);
idt[Interrupt::Spurious as usize].set_handler_fn(spurious);
idt[Interrupt::Timer as usize].set_handler_fn(timer);
idt
});
extern "x86-interrupt" fn double_fault(stack_frame: InterruptStackFrame, error_code: u64) -> ! {
panic!("Double fault: error code {error_code} \n{stack_frame:#?}")
@ -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,17 +9,19 @@ 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, [
device_tree!(
dt,
[
"Mice",
"Keyboards",
"Controllers",
@ -38,13 +36,13 @@ impl DeviceTree {
"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,27 +1,40 @@
//! Environment call handling routines
use core::borrow::Borrow;
use {alloc::boxed::Box, core::cell::LazyCell, hbvm::mem::Address};
use crate::{
allocator,
holeybytes::kernel_services::{
block_read,
service_definition_service::{sds_msg_handler, SERVICES},
holeybytes::{
kernel_services::{
block_read, dt_msg_handler::dt_msg_handler, logging_service::log_msg_handler,
service_definition_service::sds_msg_handler,
},
ExecThread,
},
kmain::EXECUTOR,
task::Executor,
};
use {
super::{mem::Memory, Vm},
crate::{arch, holeybytes::mem, ipc::buffer::IpcBuffer, kmain::IPC_BUFFERS},
alloc::string::String,
log::{debug, error, info, trace, warn},
super::Vm,
crate::{arch, ipc::buffer::IpcBuffer, kmain::IPC_BUFFERS},
hbvm::value::Value,
log::{debug, error, info, trace},
};
pub fn handler(vm: &mut Vm) {
let ecall_number = vm.registers[2].cast::<u64>();
#[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()
}
// debug!("Ecall number {:?}", ecall_number);
//info!("Register dump: {:?}", vm.registers);
#[inline(always)]
pub fn handler(vm: &mut Vm, pid: &usize) {
let ecall_number = vm.registers[2].cast::<u64>();
match ecall_number {
0 => {
@ -34,9 +47,9 @@ pub fn handler(vm: &mut Vm) {
1 => {
// Make buffer
let bounded = match vm.registers[3].cast::<u64>() {
0 => false,
1 => true,
let bounded = match vm.registers[3] {
Value(0) => false,
Value(1) => true,
_ => {
panic!("Bad");
}
@ -45,22 +58,19 @@ pub fn handler(vm: &mut Vm) {
let length = vm.registers[4].cast::<u64>();
let mut buffs = IPC_BUFFERS.lock();
let abc;
match bounded {
false => {
abc = IpcBuffer::new(false, 0);
}
true => {
abc = IpcBuffer::new(true, length);
}
};
let buff_id = arch::hardware_random_u64();
buffs.insert(buff_id, abc);
info!("Buffer ID: {}", buff_id);
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 => {
@ -69,16 +79,19 @@ pub fn handler(vm: &mut Vm) {
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(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 => {
use crate::holeybytes::kernel_services::mem_serve::memory_msg_handler;
@ -86,173 +99,183 @@ pub fn handler(vm: &mut Vm) {
Ok(_) => {}
Err(_) => {}
}
//
}
#[cfg(target_arch = "x86_64")]
3 => {
unsafe fn x86_in(address: u16) -> u8 {
x86_64::instructions::port::Port::new(address).read()
}
unsafe fn x86_out(address: u16, value: u8) {
x86_64::instructions::port::Port::new(address).write(value);
}
let mut msg_vec = block_read(mem_addr, length);
let msg_vec = block_read(mem_addr, length);
let msg_type = msg_vec[0];
msg_vec.remove(0);
match msg_type {
0 => {
let mut addr = msg_vec[0] as u16;
msg_vec.remove(0);
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);
let addr2 = msg_vec[0] as u16;
msg_vec.remove(0);
addr = ((addr) << 8) | addr2;
let value = unsafe { x86_in(addr) };
trace!("Read the value {} from address {}", value, addr);
vm.registers[1] = hbvm::value::Value(value as u64);
}
1 => {
let mut addr = msg_vec[0] as u16;
msg_vec.remove(0);
let addr2 = msg_vec[0] as u16;
msg_vec.remove(0);
addr = ((addr) << 8) | addr2;
let value = msg_vec[0];
msg_vec.remove(0);
trace!("Setting the address {} to {}", addr, value);
unsafe { x86_out(addr, value) };
match size {
0 => x86_out(addr, msg_vec[4]),
1 => x86_out(
addr,
u16::from_le_bytes(msg_vec[4..6].try_into().unwrap_unchecked()),
),
2 => x86_out(
addr,
u32::from_le_bytes(msg_vec[4..8].try_into().unwrap_unchecked()),
),
_ => panic!("How?"),
}
},
_ => {}
}
}
#[cfg(not(target_arch = "x86_64"))]
3 => unimplemented!("TODO: implement whatever buffer 3 does for no x86_64"),
// source of rng
4 => {
let block = block_read(mem_addr, length);
block.chunks_mut(8.min(length)).for_each(|chunk| {
chunk.clone_from_slice(
&crate::arch::hardware_random_u64().to_le_bytes()[..chunk.len()],
);
});
vm.registers[1] = hbvm::value::Value(mem_addr);
}
5 => match dt_msg_handler(vm, mem_addr, length) {
Ok(()) => {}
Err(_) => log::error!("Improper dt query"),
},
6 => unsafe {
let program = block_read(mem_addr, length);
// decode AbleOS Executable format
let header = &program[0..46];
let magic_slice = &header[0..3];
if magic_slice != [0x15, 0x91, 0xD2] {
log::error!("Invalid magic number at the start of executable.");
return;
}
let executable_format_version =
u32::from_le_bytes(header[3..7].try_into().unwrap());
let offset = if executable_format_version == 0 {
47
} else {
error!("Invalid executable format.");
return;
};
let code_length = u64::from_le_bytes(header[7..15].try_into().unwrap());
let data_length = u64::from_le_bytes(header[15..23].try_into().unwrap());
let end = (code_length + data_length) as usize;
log::debug!("{code_length} + {data_length} = {end}");
let thr = ExecThread::new(&program[offset..end], Address::new(0));
vm.registers[1] = Value(
LazyCell::<Executor>::get_mut(&mut EXECUTOR)
.unwrap()
.spawn(Box::pin(async move {
if let Err(e) = thr.await {
log::error!("{e:?}");
}
})) as u64,
);
log::debug!("spawned a process");
},
buffer_id => {
let mut buffs = IPC_BUFFERS.lock();
match buffs.get_mut(&buffer_id) {
Some(buff) => {
let 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 buffer_id = vm.registers[3].cast::<u64>();
let mut map_ptr = vm.registers[4].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: &mut IpcBuffer;
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}"
),
};
if buffs.get_mut(&buffer_id).is_some() {
buff = buffs.get_mut(&buffer_id).unwrap();
} else {
info!("AHHH");
vm.registers[1] = hbvm::value::Value(0);
return;
}
let pop = buff.pop();
if pop.is_err() {
return;
}
let msg = pop.unwrap();
if msg.len() > max_length.try_into().unwrap() {
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: *mut u64 = &mut map_ptr;
for (index, byte) in msg.iter().enumerate() {
ptr.offset(index.try_into().unwrap()).write_bytes(*byte, 1);
}
let ptr = map_ptr as *mut u8;
ptr.copy_from_nonoverlapping(msg.as_ptr(), msg.len());
}
info!("Recieve {:?} from Buffer({})", msg, buffer_id);
debug!("Recieve {:?} from Buffer({})", msg, buffer_id);
}
}
5 => {
#[cfg(target_arch = "x86_64")]
{
let r2 = vm.registers[2].cast::<u64>();
unsafe fn x86_in(address: u16) -> u32 {
x86_64::instructions::port::Port::new(address).read()
}
unsafe fn x86_out(address: u16, value: u32) {
x86_64::instructions::port::Port::new(address).write(value);
}
let x = hbvm::value::Value(unsafe { x86_in(r2 as u16) } as u64);
info!("Read {:?} from Port {:?}", x, r2);
let x = hbvm::value::Value(unsafe { x86_in::<u8>(r2 as u16) } as u64);
// info!("Read {:?} from Port {:?}", x, r2);
vm.registers[3] = x
}
}
// 5
6 => {
// Wait till interrupt
use crate::kmain::EXECUTOR;
let interrupt_type = vm.registers[3].cast::<u8>();
debug!("Interrupt subscribed: {}", interrupt_type);
unsafe {
LazyCell::<Executor>::get_mut(&mut EXECUTOR)
.unwrap()
.interrupt_subscribe(*pid, interrupt_type);
}
}
7 => {
// Wait till buffer
use crate::kmain::EXECUTOR;
let buffer_id = vm.registers[3].cast::<u64>() as usize;
debug!("Buffer subscribed: {}", buffer_id);
unsafe {
LazyCell::<Executor>::get_mut(&mut EXECUTOR)
.unwrap()
.buffer_subscribe(*pid, buffer_id);
}
}
_ => {
log::error!("Syscall unknown {:?}{:?}", ecall_number, vm.registers);
}
}
}
fn log_msg_handler(vm: &mut Vm, mem_addr: u64, length: usize) -> Result<(), LogError> {
// let message_length = 8 + 8 + 8;
// log::info!("Mem Addr 0x{:x?} length {}", mem_addr, length);
let mut msg_vec = block_read(mem_addr, length);
let log_level = msg_vec.pop().unwrap();
match String::from_utf8(msg_vec) {
Ok(strr) => {
// use LogLevel::*;
let ll = match log_level {
0 | 48 => error!("{}", strr),
1 | 49 => warn!("{}", strr),
2 | 50 => info!("{}", strr),
3 | 51 => debug!("{}", strr),
4 | 52 => trace!("{}", strr),
_ => {
return Err(LogError::InvalidLogFormat);
}
};
}
Err(e) => {
error!("{:?}", e);
}
}
Ok(())
}
#[derive(Debug)]
pub enum LogError {
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

@ -1,10 +1,7 @@
use {
crate::holeybytes::{
ecah::LogError,
kernel_services::{block_read, mem_serve},
Vm,
},
alloc::alloc::alloc_zeroed,
crate::holeybytes::{kernel_services::block_read, Vm},
alloc::alloc::{alloc, dealloc},
core::alloc::Layout,
log::{debug, info},
};
@ -19,84 +16,100 @@ pub enum MemoryQuotaType {
KillQuota = 3,
}
fn alloc_page(vm: &mut Vm, mem_addr: u64, length: usize) -> Result<(), MemoryServiceError> {
let mut val = alloc::vec::Vec::new();
for _ in 0..4096 {
val.push(0);
}
info!("Block address: {:?}", val.as_ptr());
vm.registers[1] = hbvm::value::Value(val.as_ptr() as u64);
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 mut msg_vec = block_read(mem_addr, length);
let msg_vec = block_read(mem_addr, length);
let msg_type = msg_vec[0];
msg_vec.remove(0);
match msg_type {
0 => {
let page_count = msg_vec[0];
msg_vec.remove(0);
0 => unsafe {
let page_count = msg_vec[1];
let mptr_raw: [u8; 8] = msg_vec[0..8].try_into().unwrap();
let mptr: u64 = u64::from_le_bytes(mptr_raw);
let ptr = alloc(Layout::from_size_align_unchecked(
page_count as usize * 4096,
8,
));
log::debug!("Allocating {} pages @ {:x}", page_count, mptr);
log::debug!("Allocating {} pages @ {:x}", page_count, ptr as u64);
let mut val = alloc::vec::Vec::new();
for _ in 0..(page_count as isize * 4096) {
val.push(0);
}
vm.registers[1] = hbvm::value::Value(val.as_ptr() as u64);
log::debug!("Kernel ptr: {:x}", val.as_ptr() as u64);
}
1 => {
let page_count = msg_vec[0];
msg_vec.remove(0);
vm.registers[1] = hbvm::value::Value(ptr as u64);
log::debug!("Kernel ptr: {:x}", ptr as u64);
},
let mptr_raw: [u8; 8] = msg_vec[0..8].try_into().unwrap();
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[0] {
let quota_type = match msg_vec[1] {
0 => NoQuota,
1 => SoftQuota,
2 => HardQuota,
3 => KillQuota,
_ => NoQuota,
};
msg_vec.remove(0);
let hid_raw: [u8; 8] = msg_vec[0..8].try_into().unwrap();
let hid_raw: [u8; 8] = msg_vec[2..10].try_into().unwrap();
let hid: u64 = u64::from_le_bytes(hid_raw);
for _ in 0..8 {
msg_vec.remove(0);
}
let pid_raw: [u8; 8] = msg_vec[0..8].try_into().unwrap();
let pid: u64 = u64::from_le_bytes(hid_raw);
for _ in 0..8 {
msg_vec.remove(0);
}
let pid_raw: [u8; 8] = msg_vec[10..18].try_into().unwrap();
let pid: u64 = u64::from_le_bytes(pid_raw);
debug!(
"Setting HID-{:x}:PID-{:x}'s quota type to {:?}",
hid, pid, quota_type
)
}
3 => {
let page_count = msg_vec[0];
let page_count = msg_vec[1];
log::debug!(" {} pages", page_count);
msg_vec.remove(0);
}
4 => unsafe {
let count = u32::from_le_bytes(msg_vec[1..5].try_into().unwrap_unchecked()) as usize;
let src = u64::from_le_bytes(msg_vec[5..13].try_into().unwrap_unchecked()) as *const u8;
let dest = u64::from_le_bytes(msg_vec[13..21].try_into().unwrap_unchecked()) as *mut u8;
src.copy_to_nonoverlapping(dest, count);
},
5 => unsafe {
let count = u32::from_le_bytes(msg_vec[1..5].try_into().unwrap_unchecked()) as usize;
let size = u32::from_le_bytes(msg_vec[5..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;
memset(dest, src, count, size);
},
_ => {
log::debug!("Unknown memory service message type: {}", msg_type);
}

View file

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

@ -1,43 +1,40 @@
use {
crate::{
alloc::string::ToString,
arch::hardware_random_u64,
holeybytes::{ecah::LogError, kernel_services::block_read, Vm},
ipc::{
buffer::IpcBuffer,
protocol::{self, Protocol},
},
holeybytes::{kernel_services::block_read, Vm},
ipc::{buffer::IpcBuffer, protocol::Protocol},
kmain::IPC_BUFFERS,
},
alloc::string::String,
hashbrown::HashMap,
log::{info, trace},
spin::{lazy::Lazy, Mutex},
};
pub struct Services(HashMap<u64, Protocol>);
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)
});
pub fn sds_msg_handler(vm: &mut Vm, mem_addr: u64, length: usize) -> Result<(), LogError> {
let mut msg_vec = block_read(mem_addr, length);
#[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();
msg_vec.remove(0);
// info!("Length {}", msg_vec.len());
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 string = String::from_utf8(msg_vec).expect("Our bytes should be valid utf8");
let ret = sds_create_service(string);
vm.registers[1] = hbvm::value::Value(ret as u64);
}
DeleteService => todo!(),
SearchServices => {
let string = String::from_utf8(msg_vec).expect("Our bytes should be valid utf8");
let ret = sds_search_service(string);
vm.registers[1] = hbvm::value::Value(ret as u64);
}
@ -79,30 +76,29 @@ impl From<u8> for ServiceEventType {
}
}
fn sds_create_service(protocol: String) -> u64 {
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.clone());
let protocol_ = Protocol::from(protocol);
let mut buff = IpcBuffer::new(false, 0);
services.0.insert(buff_id, protocol_.clone());
buff.protocol = protocol_.clone();
buff.protocol = protocol_;
buffers.insert(buff_id, buff);
trace!("BufferID({}) => {}", buff_id, protocol);
// let a: protocol::Protocol = protocol.into();
buff_id
}
fn sds_search_service(protocol: String) -> u64 {
let mut services = SERVICES.lock();
let compare = Protocol::from(protocol.clone());
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.clone());
trace!("BufferID({}) => {}", bid, protocol);
return *bid;
}
}

View file

@ -7,7 +7,7 @@
use hbvm::mem::Address;
fn calc_start_of_page(ptr: u64) -> u64 {
let mut page_aligned = false;
let _page_aligned = false;
if ptr % 4096 == 0 {
// page_aligned = true;
return ptr / 4096;
@ -21,41 +21,39 @@ pub struct Memory {
impl Memory {
#[cfg(target_arch = "x86_64")]
fn read_device(addr: Address) {
unsafe {
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> {
use log::{error, info};
if addr.get() % 4096 == 0 {}
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> {
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,77 +1,76 @@
mod ecah;
mod kernel_services;
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},
hbvm::{
mem::{
softpaging::{icache::ICache, HandlePageFault, SoftPagedMem},
Address, Memory,
alloc::alloc::{alloc, dealloc},
core::{
alloc::Layout,
future::Future,
pin::Pin,
task::{Context, Poll},
},
hbvm::{
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(
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!(
@ -91,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

@ -9,12 +9,12 @@ pub enum BufferTypes {
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,7 +24,7 @@ impl IpcBuffer {
length
);
match (bounded, length) {
(false, a) => {
(false, ..) => {
let buftype = BufferTypes::Unbound(SegQueue::new());
Self {
@ -48,10 +48,8 @@ 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) -> Result<Message, IpcError> {

View file

@ -1,21 +1,17 @@
use {
alloc::{string::String, vec::Vec},
hashbrown::HashMap,
log::info,
};
use {alloc::vec::Vec, hashbrown::HashMap};
#[derive(Debug, PartialEq, Clone)]
pub struct Type {}
#[derive(Debug, PartialEq, Clone)]
pub struct Funct {
takes: Vec<String>,
gives: Vec<String>,
pub struct Funct<'a> {
takes: Vec<&'a str>,
gives: Vec<&'a str>,
}
#[derive(Debug, PartialEq, Clone)]
pub struct Protocol {
types: HashMap<String, Type>,
fns: HashMap<String, Funct>,
pub struct Protocol<'a> {
types: HashMap<&'a str, Type>,
fns: HashMap<&'a str, Funct<'a>>,
}
impl Protocol {
impl<'a> Protocol<'a> {
pub fn void() -> Self {
Self {
types: HashMap::new(),
@ -28,8 +24,8 @@ impl Protocol {
}
}
impl From<String> for Protocol {
fn from(value: alloc::string::String) -> Self {
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 {

View file

@ -2,27 +2,40 @@
use {
crate::{
arch::{hardware_random_u64, logging::SERIAL_CONSOLE},
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);
@ -38,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
@ -52,64 +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));
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_bytes().as_ptr() as u64, cmd_len);
thr.set_arguments(cmd.as_ptr() as u64, cmd_len);
}
executor.spawn(Box::pin(async {
if let Err(e) = thr.await {
log::error!("{e:?}");
}
});
}));
}
info!("Random number: {}", hardware_random_u64());
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);
@ -120,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,21 +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;
@ -23,6 +24,7 @@ mod arch;
mod bootmodules;
mod capabilities;
mod device_tree;
mod exe_format;
mod handle;
mod holeybytes;
mod ipc;
@ -32,6 +34,9 @@ mod memory;
mod task;
mod utils;
#[allow(improper_ctypes, non_upper_case_globals)]
mod ktest;
use versioning::Version;
/// Kernel's version
@ -42,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() {
@ -54,17 +61,7 @@ fn panic(info: &core::panic::PanicInfo) -> ! {
));
}
if let Some(msg) = info.message() {
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)?;
if cfg!(debug_assertions) {
log::set_max_level(log::LevelFilter::Debug);
} else {
log::set_max_level(log::LevelFilter::Info);
}
Lazy::force(&TERMINAL_LOGGER);
@ -31,7 +36,19 @@ impl log::Log for Logger {
Level::Debug => "25",
Level::Trace => "103",
};
let module = record.module_path().unwrap_or_default();
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",
@ -39,6 +56,7 @@ impl log::Log for Logger {
))
.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>,
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),
}))
}));
match task.poll(&mut cx) {
Poll::Ready(()) => {
self.tasks.remove(id.0);
self.wakers.remove(&id);
}
Poll::Pending => (),
}
},
self.tasks.is_empty() => break,
_ => (),
while let Some(id) = self.task_queue.pop() {
task_batch[batch_len] = id;
batch_len += 1;
if batch_len == task_batch.len() {
break;
}
}
*SPAWN_QUEUE.write() = None;
if batch_len == 0 {
// break;
continue;
}
for &(mut id) in &task_batch[..batch_len] {
if let Some(task) = self.tasks.get_mut(id) {
if task.is_paused() {
continue;
}
let waker = create_waker(id, Arc::clone(&self.task_queue));
let mut cx = ContextBuilder::from_waker(&waker).ext(&mut id).build();
if let Poll::Ready(()) = task.poll(&mut cx) {
self.tasks.remove(id);
self.interrupt_lookup.map(|pid| {
if let Some(pid) = pid {
if pid == id {
return None;
}
}
return pid;
});
self.buffer_lookup.iter_mut().for_each(|(_, pid_set)| {
pid_set.remove(&id);
});
}
}
}
}
}
pub fn send_interrupt(&self, interrupt: u8) {
let id = self.interrupt_lookup[interrupt as usize];
if let Some(id) = id {
self.unpause(id);
}
}
pub fn send_buffer(&self, id: usize) {
if let Some(buf) = self.buffer_lookup.get(&id) {
buf.iter().for_each(|pid| self.unpause(*pid));
}
}
}
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)
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
struct TaskId(usize);
fn set_paused(&self, paused: bool) {
self.paused.store(paused, Ordering::Release)
}
}
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();
impl TaskWaker {
fn wake(&self) {
self.task_queue.push(self.task_id);
}
}
fn wake_by_ref(self: &Arc<Self>) {
self.queue.push(self.id);
const VTABLE: RawWakerVTable = RawWakerVTable::new(clone_raw, wake_raw, wake_by_ref_raw, drop_raw);
unsafe fn clone_raw(ptr: *const ()) -> RawWaker {
let task_waker = Box::from_raw(ptr as *mut TaskWaker);
let raw_waker = RawWaker::new(Box::into_raw(task_waker.clone()) as *const (), &VTABLE);
raw_waker
}
unsafe fn wake_raw(ptr: *const ()) {
let task_waker = Box::from_raw(ptr as *mut TaskWaker);
task_waker.wake();
}
unsafe fn wake_by_ref_raw(ptr: *const ()) {
let task_waker = &*(ptr as *const TaskWaker);
task_waker.wake();
}
unsafe fn drop_raw(ptr: *const ()) {
drop(Box::from_raw(ptr as *mut TaskWaker));
}

View file

@ -4,7 +4,6 @@
/// 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
@ -12,7 +11,7 @@ pub const TAB: &str = " ";
macro_rules! tab {
($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());
}
};
}

View file

@ -1,6 +1,6 @@
{
"arch": "aarch64",
"data-layout": "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128",
"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,
@ -21,5 +21,5 @@
"target-c-int-width": "32",
"target-endian": "little",
"target-pointer-width": "64",
"vendor": ""
"vendor": "ablecorp"
}

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,15 +4,17 @@ version = "0.2.0"
edition = "2021"
[dependencies]
str-reader = "0.1.2"
derive_more = "0.99"
error-stack = "0.4"
fatfs = "0.3"
toml = "0.5.2"
# hbasm.git = "https://git.ablecorp.us/AbleOS/holey-bytes.git"
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"
[dependencies.reqwest]
version = "0.11"
default-features = false
features = ["rustls-tls", "blocking"]
log = "0.4"
raw-cpuid = "11"
ureq = { version = "2", default-features = false, features = ["tls"] }

View file

@ -1,4 +1,6 @@
#![allow(unused)]
use std::{
collections::HashMap,
fmt::format,
fs::{read_to_string, File},
io::{BufWriter, Write},
@ -12,6 +14,7 @@ pub struct Package {
name: String,
binaries: Vec<String>,
build_cmd: String,
args: HashMap<String, String>,
}
impl Package {
@ -45,49 +48,81 @@ impl Package {
let mut binaries = vec![];
for (count, (name, table)) in bin_table.into_iter().enumerate() {
// if count != 0 {
println!("{}", name);
binaries.push(name.clone());
// }
}
let build_table = data.get("build").unwrap();
let mut build_cmd: String = build_table.get("command").unwrap().as_str().unwrap().into();
build_cmd.remove(0);
// build_cmd.pop();
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) {
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);
let mut bytes = Vec::new();
// compile here
let _ = hblang::run_compiler(
let mut warnings = String::new();
hblang::run_compiler(
&path,
Options {
fmt: true,
resolver: Some(hblang::ABLEOS_PATH_RESOLVER),
..Default::default()
},
&mut bytes,
);
let _ = hblang::run_compiler(&path, Default::default(), &mut bytes);
out,
&mut warnings,
)?;
match std::fs::create_dir("target/programs") {
Ok(_) => (),
Err(e) if e.kind() == std::io::ErrorKind::AlreadyExists => (),
Err(e) => panic!("{}", e),
}
let path = format!("target/programs/{}.hbf", self.name);
let mut file = File::create(path).unwrap();
file.write_all(&bytes).unwrap();
}
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();
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();
}
Ok(())
}
}

View file

@ -1,16 +1,16 @@
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::{self, File},
io::{self, Write},
path::Path,
process::{exit, Command},
process::{exit, Command, Stdio},
},
toml::Value,
};
@ -19,41 +19,85 @@ fn main() -> Result<(), Error> {
let mut args = std::env::args();
args.next();
log::set_logger(&hblang::Logger).unwrap();
log::set_max_level(log::LevelFilter::Error);
match args.next().as_deref() {
Some("build" | "b") => {
let mut release = false;
let mut debuginfo = false;
let mut target = Target::X86_64;
let mut tests = false;
for arg in args {
if arg == "-r" || arg == "--release" {
release = true;
} else if arg == "-d" || arg == "--debuginfo" {
debuginfo = true;
} else if arg == "rv64" || arg == "riscv64" || arg == "riscv64-virt" {
target = Target::Riscv64Virt;
} else if arg == "arm64" || arg == "aarch64" || arg == "aarch64-virt" {
target = Target::Aarch64;
} else if arg == "avx2" {
target = Target::X86_64Avx2;
} else if arg == "--ktest" {
tests = true;
} else {
return Err(report!(Error::InvalidSubCom));
}
}
build(release, target).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));
}
}
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(())
}
@ -187,7 +234,12 @@ TERM_BACKDROP={}
let modules = value.get_mut("modules").unwrap().as_table_mut().unwrap();
// let mut real_modules = modules.clone();
modules.into_iter().for_each(|(key, value)| {
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"),
@ -199,9 +251,26 @@ TERM_BACKDROP={}
let p = Package::load_from_file(
format!("sysdata/programs/{}/meta.toml", path).to_owned(),
);
p.build();
match p.build(&mut out) {
Ok(()) => {}
Err(_) => {
writeln!(errors, "========= while compiling {} =========", path)
.unwrap();
errors.push_str(core::str::from_utf8(&out).expect("no"));
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");
@ -236,7 +305,7 @@ TERM_BACKDROP={}
let bootdir = fs.root_dir().create_dir("efi")?.create_dir("boot")?;
let mut f = fs.root_dir().create_file("limine.cfg")?;
let a = f.write(limine_str.as_bytes())?;
let _ = f.write(limine_str.as_bytes())?;
drop(f);
io::copy(
@ -270,7 +339,7 @@ fn copy_file_to_img(fpath: &str, fs: &FileSystem<File>) {
.expect("Copy failed");
}
fn build(release: bool, target: Target) -> Result<(), Error> {
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");
@ -278,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"]);
@ -285,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),
@ -298,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");
@ -320,25 +403,72 @@ 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", "host",
"-device", "isa-debug-exit,iobase=0xf4,iosize=0x04"
"-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 => {
@ -359,7 +489,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",
@ -382,7 +512,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",
),
@ -404,12 +534,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)?;
@ -418,11 +548,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,
}
@ -431,30 +561,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-2024-05-17"
# 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.

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 B

View file

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

View file

@ -1,3 +0,0 @@
protocol Foo{
fn bar(i32, u8, bool) -> void;
}

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

@ -1,14 +0,0 @@
Element := struct {
width: int,
height: int,
x: u16,
y: u16,
id: int,
}
create_element := fn(): Element {
return Element.(0, 0, 0, 0, 0)
}

View file

@ -1,3 +0,0 @@
FrameID := struct {
}

View file

@ -1,12 +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,
}
create_window := fn(): WindowID {
return WindowID.(1, 2)
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([u8; 4096], windowing_system_buffer, mem_buf)
if ret == null {
log.info("No messages\0")
}
update_ui := fn(window_id: WindowID): void {
return
if *mem_buf == 0 {
log.info("No messages\0")
}
return @as(^render.Surface, idk)
}
}

View file

@ -1,3 +0,0 @@
ui_lisp_text_example := "(text id_1)\0";

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.new_surface(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 {
render.clear(label.surface, label.bg)
render.put_text(label.surface, font, .(0, 0), label.fg, label.text)
}
render.put_surface(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,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
}

View file

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

View file

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

View file

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

View file

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

View file

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

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