Compare commits

...

246 commits

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

1268
Cargo.lock generated

File diff suppressed because it is too large Load diff

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

@ -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();
@ -117,8 +138,8 @@ fn build(name: String) {
}
}
pub fn build_program(name: String) {}
pub fn build_library(name: String) {}
pub fn build_program(_name: String) {}
pub fn build_library(_name: String) {}
fn help() {
println!(

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,10 +3,15 @@ edition = "2021"
name = "kernel"
version = "0.2.0"
[features]
ktest = []
[dependencies]
embedded-graphics = "0.8"
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"
slab = { version = "0.4", default-features = false }
@ -14,42 +19,35 @@ uart_16550 = { version = "0.3", features = ["nightly"] }
xml.git = "https://git.ablecorp.us/ableos/ableos_userland"
versioning.git = "https://git.ablecorp.us/ableos/ableos_userland"
# able_graphics_library.git = "https://git.ablecorp.us/ableos/ableos_userland"
hashbrown = { version = "0.14", features = ["nightly"] }
[dependencies.limine]
version = "0.1"
#git = "https://github.com/limine-bootloader/limine-rs"
hashbrown = { version = "0.15", features = ["nightly"] }
limine = "0.1"
[dependencies.crossbeam-queue]
version = "0.3"
default-features = false
features = ["alloc", "nightly"]
# [dependencies.clparse]
# git = "https://git.ablecorp.us/ableos/ableos_userland"
# default-features = false
[dependencies.derive_more]
version = "1"
default-features = false
features = [
"add",
"add_assign",
"constructor",
"display",
"from",
"into",
"mul",
"mul_assign",
"not",
"sum",
"add",
"add_assign",
"constructor",
"display",
"from",
"into",
"mul",
"mul_assign",
"not",
"sum",
]
[target.'cfg(target_arch = "x86_64")'.dependencies]
x86_64 = "0.15"
x2apic = "0.4"
virtio-drivers = "0.7"
# virtio-drivers = "0.7"
[target.'cfg(target_arch = "riscv64")'.dependencies]
sbi = "0.2.0"

View file

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

View file

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

View file

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

View file

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

View file

@ -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,7 +27,7 @@ fn collect_cpu_info(device_tree: &mut DeviceTree) {
cpus.push(cpu);
}
fn cpu_id() -> (String, u64) {
fn cpu_id<'a>() -> (&'a str, u64) {
let mut cpu_id: u64;
unsafe {
asm!("mrs {cpu_id}, MIDR_EL1",
@ -39,11 +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(),
0x410FD034 => "Cortex-A53",
0x410FD083 => "Cortex-A72",
// the source of this one was checking the cpu id :thinking:
0x410FD493 => "Neoverse N2".to_string(),
_ => "Unknown".to_string(),
0x410FD493 => "Neoverse N2",
_ => "Unknown",
};
log::trace!("CPU Name: {cpu_name} - CPU ID: 0x{:X}", cpu_id);

View file

@ -3,7 +3,7 @@ pub static SERIAL_CONSOLE: Mutex<SerialConsole> = Mutex::new(SerialConsole {
uart: 0x09000000 as *mut u8,
});
struct SerialConsole {
pub struct SerialConsole {
uart: *mut u8,
}
@ -22,7 +22,7 @@ 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

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

@ -12,7 +12,7 @@ use {
pub const DOUBLE_FAULT_IX: u16 = 0;
const STACK_SIZE: usize = 5 * 1024;
const STACK_ALIGNMENT: usize = 4096;
const STACK_ALIGNMENT: usize = 1;
pub unsafe fn init() {
use x86_64::instructions::{
@ -39,7 +39,7 @@ static TSS: Lazy<TaskStateSegment> = Lazy::new(|| {
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_zeroed(layout);
let stack = alloc::alloc::alloc(layout);
VirtAddr::from_ptr(stack) + STACK_SIZE as u64
};

View file

@ -1,56 +1,54 @@
// TODO: Turn apic keyboard interrupt into a standard ipc message
use {
core::mem::MaybeUninit,
log::trace,
spin::{Lazy, Mutex},
x2apic::lapic::{LocalApic, LocalApicBuilder},
x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame, PageFaultErrorCode},
};
pub unsafe fn init() {
trace!("Initialising IDT");
IDT.load();
Lazy::force(&LAPIC);
x86_64::instructions::interrupts::enable();
}
/// Safety: Using LAPIC or IDT before init() is UB
/// Using
static mut LAPIC: LocalApic = unsafe { MaybeUninit::zeroed().assume_init() };
static mut IDT: InterruptDescriptorTable = unsafe { MaybeUninit::zeroed().assume_init() };
#[repr(u8)]
enum Interrupt {
Timer = 32,
#[derive(Debug, Eq, Hash, PartialEq)]
pub enum Interrupt {
Timer = 32,
ApicErr = u8::MAX - 1,
Spurious = u8::MAX,
}
pub(crate) static LAPIC: Lazy<Mutex<LocalApic>> = Lazy::new(|| {
let mut lapic = LocalApicBuilder::new()
pub unsafe fn init() {
trace!("Initializing IDT and LAPIC");
// Initialize and load the IDT
IDT = InterruptDescriptorTable::new();
IDT.double_fault
.set_handler_fn(double_fault)
.set_stack_index(super::gdt::DOUBLE_FAULT_IX);
IDT.page_fault.set_handler_fn(page_fault);
IDT[Interrupt::ApicErr as u8].set_handler_fn(apic_err);
IDT[Interrupt::Spurious as u8].set_handler_fn(spurious);
IDT[Interrupt::Timer as u8].set_handler_fn(timer);
IDT.load();
LAPIC = LocalApicBuilder::new()
.timer_vector(Interrupt::Timer as usize)
.error_vector(Interrupt::ApicErr as usize)
.spurious_vector(Interrupt::Spurious as usize)
.set_xapic_base(
unsafe { x2apic::lapic::xapic_base() }
x2apic::lapic::xapic_base()
+ super::memory::HHDM_OFFSET.load(core::sync::atomic::Ordering::Relaxed),
)
.build()
.expect("failed to setup Local APIC");
unsafe { lapic.enable() };
Mutex::new(lapic)
});
.expect("Failed to setup Local APIC");
LAPIC.enable();
static IDT: Lazy<InterruptDescriptorTable> = Lazy::new(|| {
let mut idt = InterruptDescriptorTable::new();
unsafe {
idt.double_fault
.set_handler_fn(double_fault)
.set_stack_index(super::gdt::DOUBLE_FAULT_IX);
}
idt.page_fault.set_handler_fn(page_fault);
idt[Interrupt::ApicErr as 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
});
x86_64::instructions::interrupts::enable();
}
extern "x86-interrupt" fn double_fault(stack_frame: InterruptStackFrame, error_code: u64) -> ! {
panic!("Double fault: error code {error_code} \n{stack_frame:#?}")
@ -64,13 +62,52 @@ extern "x86-interrupt" fn page_fault(
}
extern "x86-interrupt" fn timer(_isf: InterruptStackFrame) {
unsafe { LAPIC.lock().end_of_interrupt() };
interrupt(Interrupt::Timer);
unsafe {
LAPIC.end_of_interrupt();
}
}
extern "x86-interrupt" fn apic_err(_: InterruptStackFrame) {
interrupt(Interrupt::ApicErr);
panic!("Internal APIC error");
}
extern "x86-interrupt" fn spurious(_: InterruptStackFrame) {
unsafe { LAPIC.lock().end_of_interrupt() };
interrupt(Interrupt::Spurious);
unsafe {
LAPIC.end_of_interrupt();
}
}
#[allow(unused_imports)]
fn interrupt(interrupt_type: Interrupt) {
use crate::{arch::INTERRUPT_LIST, kmain::EXECUTOR};
// let il = INTERRUPT_LIST.lock();
// let val = il.list.get(&interrupt_type).unwrap();
// use crate::holeybytes::kernel_services::service_definition_service::sds_search_service;
// let buffer = sds_search_service(val);
// if buffer != 0 {
// use {crate::kmain::IPC_BUFFERS, alloc::vec::Vec};
// let mut buffs = IPC_BUFFERS.lock();
// match buffs.get_mut(&buffer) {
// Some(buff) => {
// let mut msg_vec = Vec::new();
// msg_vec.push(0xFF);
// buff.push(msg_vec.to_vec());
// log::debug!("Sent Message {:?} to Buffer({})", msg_vec, buffer);
// }
// None => {
// log::error!("Access of non-existent buffer {}", buffer)
// }
// }
// }
unsafe {
EXECUTOR.send_interrupt(interrupt_type as u8);
}
}

View file

@ -10,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};
@ -30,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",
@ -40,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(
@ -128,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();
@ -166,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);
}
@ -189,6 +249,7 @@ unsafe extern "C" fn start() -> ! {
/// Spin loop
pub fn spin_loop() -> ! {
loop {
core::hint::spin_loop();
x86_64::instructions::hlt()
}
}

View file

@ -8,13 +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![]);
.insert("Unidentified PCI", alloc::vec![]);
let mut devices = alloc::vec![];
for bus in 0..=255 {
@ -47,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));
}
@ -68,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);
@ -459,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);
@ -469,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,11 +1,6 @@
//! 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
@ -14,11 +9,11 @@ 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 {
@ -47,7 +42,7 @@ impl DeviceTree {
}
}
use crate::{device_tree, tab, utils::TAB};
impl fmt::Display for DeviceTree {
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,21 +1,40 @@
//! Environment call handling routines
use crate::holeybytes::kernel_services::{
block_read, dt_msg_handler::dt_msg_handler, logging_service::log_msg_handler,
service_definition_service::sds_msg_handler,
use {alloc::boxed::Box, core::cell::LazyCell, hbvm::mem::Address};
use crate::{
holeybytes::{
kernel_services::{
block_read, dt_msg_handler::dt_msg_handler, logging_service::log_msg_handler,
service_definition_service::sds_msg_handler,
},
ExecThread,
},
kmain::EXECUTOR,
task::Executor,
};
use {
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 => {
@ -28,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");
}
@ -39,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 => {
@ -63,7 +79,10 @@ 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) {
@ -81,77 +100,43 @@ pub fn handler(vm: &mut Vm) {
Err(_) => {}
}
}
#[cfg(not(target_arch = "x86_64"))]
3 => info!("TODO: implement whatever buffer 3 does for no x86_64"),
#[cfg(target_arch = "x86_64")]
3 => {
unsafe fn x86_out<T: x86_64::instructions::port::PortWrite>(
address: u16,
value: T,
) {
x86_64::instructions::port::Port::new(address).write(value);
}
unsafe fn x86_in<T: x86_64::instructions::port::PortRead>(address: u16) -> T {
x86_64::instructions::port::Port::new(address).read()
}
let msg_vec = block_read(mem_addr, length);
let msg_type = msg_vec[0];
match msg_type {
0 => 'wow: {
let size = match msg_vec[0] {
0 => 1,
1 => 2,
2 => 4,
_ => {
error!("Tried to write more than 32 bits");
break 'wow;
}
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."),
};
let addr = u16::from_le_bytes(msg_vec[1..3].try_into().unwrap());
let value = unsafe {
match size {
1 => x86_in::<u8>(addr) as u64,
2 => x86_in::<u16>(addr) as u64,
4 => x86_in::<u32>(addr) as u64,
_ => panic!("how?"),
}
};
trace!("Read the value {} from address {}", value, addr);
// info!("Read the value {} from address {}", value, addr);
vm.registers[1] = hbvm::value::Value(value);
}
1 => 'wow: {
let size = match msg_vec[1] {
0 => 1,
1 => 2,
2 => 4,
_ => {
error!("Tried to write more than 32 bits");
break 'wow;
}
};
let addr = unsafe {
u16::from_le_bytes(msg_vec[1..3].try_into().unwrap_unchecked())
};
trace!("Setting address {}", addr);
unsafe {
match size {
1 => x86_out(addr, msg_vec[3]),
2 => x86_out(
addr,
u16::from_le_bytes(
msg_vec[3..5].try_into().unwrap_unchecked(),
),
),
4 => x86_out(
addr,
u32::from_le_bytes(
msg_vec[3..7].try_into().unwrap_unchecked(),
),
),
_ => panic!("How?"),
}
},
1 => unsafe {
let size = msg_vec[1];
let addr =
u16::from_le_bytes(msg_vec[2..4].try_into().unwrap_unchecked());
// info!("Setting address {}", addr);
match size {
0 => x86_out(addr, msg_vec[4]),
1 => x86_out(
addr,
u16::from_le_bytes(msg_vec[4..6].try_into().unwrap_unchecked()),
),
2 => x86_out(
addr,
u32::from_le_bytes(msg_vec[4..8].try_into().unwrap_unchecked()),
),
_ => panic!("How?"),
}
}
},
_ => {}
}
}
@ -159,68 +144,94 @@ pub fn handler(vm: &mut Vm) {
3 => unimplemented!("TODO: implement whatever buffer 3 does for no x86_64"),
// source of rng
4 => {
// limit to last 32 bits
vm.registers[1] =
hbvm::value::Value(crate::arch::hardware_random_u64() & 0xFFFFFFFF);
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::with_capacity(length);
for x in 0..(length as isize) {
let xyz = mem_addr as *const u8;
let value = unsafe { xyz.offset(x).read() };
msg_vec.push(value);
}
debug!(
"Message {:?} has been sent to Buffer({})",
msg_vec, buffer_id
);
buff.push(msg_vec);
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 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());
}
debug!("Recieve {:?} from Buffer({})", msg, buffer_id);
@ -230,17 +241,33 @@ pub fn handler(vm: &mut Vm) {
#[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
}
}
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);
}
@ -252,15 +279,3 @@ 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

@ -1,9 +1,6 @@
use {
crate::holeybytes::{kernel_services::block_read, Vm},
alloc::{
string::{String, ToString},
vec::Vec,
},
alloc::vec::Vec,
};
pub enum DtError {
QueryFailure,
@ -11,14 +8,13 @@ pub enum DtError {
pub fn dt_msg_handler(vm: &mut Vm, mem_addr: u64, length: usize) -> Result<(), DtError> {
let msg_vec = block_read(mem_addr, length);
let mut bytes: Vec<u8> = Vec::new();
for byte in msg_vec {
if *byte == 0 {
break;
}
bytes.push(*byte)
}
let query_string = String::from_utf8(bytes).unwrap();
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);
@ -29,17 +25,13 @@ pub fn dt_msg_handler(vm: &mut Vm, mem_addr: u64, length: usize) -> Result<(), D
Ok(())
}
fn query_parse(query_string: String) -> u64 {
let qt_parse_step_one = query_string.split("/");
let mut qt_parse_step_two: Vec<String> = Vec::new();
for a in qt_parse_step_one {
qt_parse_step_two.push(a.to_string());
}
fn query_parse(query_string: &str) -> u64 {
let query = query_string.split('/').collect::<Vec<&str>>();
let first_fragment: &str = &qt_parse_step_two[0];
let first_fragment: &str = &query[0];
let ret = match first_fragment {
"framebuffer" => framebuffer_parse(qt_parse_step_two),
"cpu" => cpu_parse(qt_parse_step_two),
"framebuffer" => framebuffer_parse(query),
"cpu" => cpu_parse(query),
_ => 0,
};
@ -47,8 +39,8 @@ fn query_parse(query_string: String) -> u64 {
return ret;
}
fn cpu_parse(qt_parse_step_two: Vec<String>) -> u64 {
let second_fragment: &str = &qt_parse_step_two[1];
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;
@ -59,15 +51,14 @@ fn cpu_parse(qt_parse_step_two: Vec<String>) -> u64 {
};
}
fn framebuffer_parse(qt_parse_step_two: Vec<String>) -> u64 {
fn framebuffer_parse(qt_parse_step_two: Vec<&str>) -> u64 {
use crate::kmain::FB_REQ;
let fbs = &FB_REQ.get_response().get().unwrap().framebuffers();
let second_fragment: &str = &qt_parse_step_two[1];
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 third_fragment: &str = qt_parse_step_two[2];
let ret = match third_fragment {
"ptr" => {
let ptr = fb_front.address.as_ptr().unwrap();

View file

@ -9,25 +9,30 @@ use log::Record;
pub fn log_msg_handler(_vm: &mut Vm, mem_addr: u64, length: usize) -> Result<(), LogError> {
let msg_vec = block_read(mem_addr, length);
let log_level = msg_vec.last().unwrap();
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(&msg_vec[..msg_vec.len()]) {
match core::str::from_utf8(&str) {
Ok(strr) => {
use log::Level::*;
let log_level = match log_level {
0 | 48 => Error,
1 | 49 => Warn,
2 | 50 => Info,
3 | 51 => Debug,
4 | 52 => Trace,
_ => {
return Err(LogError::InvalidLogFormat);
}
};
log::logger().log(
&Record::builder()
.args(format_args!("{}", strr))

View file

@ -1,6 +1,6 @@
use {
crate::holeybytes::{kernel_services::block_read, Vm},
alloc::alloc::{alloc_zeroed, dealloc},
alloc::alloc::{alloc, dealloc},
core::alloc::Layout,
log::{debug, info},
};
@ -17,13 +17,28 @@ pub enum MemoryQuotaType {
}
fn alloc_page(vm: &mut Vm, _mem_addr: u64, _length: usize) -> Result<(), MemoryServiceError> {
let ptr = unsafe { alloc_zeroed(Layout::new::<[u8; 4096]>()) };
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,
@ -32,40 +47,35 @@ pub fn memory_msg_handler(
let msg_vec = block_read(mem_addr, length);
let msg_type = msg_vec[0];
match msg_type {
0 => {
0 => 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!("Allocating {} pages @ {:x}", page_count, mptr);
let ptr = alloc(Layout::from_size_align_unchecked(
page_count as usize * 4096,
8,
));
let ptr = unsafe {
alloc_zeroed(Layout::from_size_align_unchecked(
page_count as usize * 4096,
1,
))
};
log::debug!("Allocating {} pages @ {:x}", page_count, ptr as u64);
vm.registers[1] = hbvm::value::Value(ptr as u64);
log::debug!("Kernel ptr: {:x}", ptr as u64);
}
},
1 => {
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);
unsafe {
dealloc(
mptr as *mut u8,
Layout::from_size_align_unchecked(page_count as usize * 4096, 1),
)
}
}
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,
@ -82,10 +92,27 @@ pub fn memory_msg_handler(
)
}
3 => {
let page_count = msg_vec[0];
let page_count = msg_vec[1];
log::debug!(" {} pages", page_count);
}
4 => unsafe {
let count = u64::from_le_bytes(msg_vec[1..9].try_into().unwrap_unchecked()) as usize;
let src = u64::from_le_bytes(msg_vec[9..17].try_into().unwrap_unchecked()) as *const u8;
let dest = u64::from_le_bytes(msg_vec[17..25].try_into().unwrap_unchecked()) as *mut u8;
debug_assert!(src.addr() & 0xFFFF000000000000 != 0);
debug_assert!(dest.addr() & 0xFFFF000000000000 != 0);
src.copy_to_nonoverlapping(dest, count);
},
5 => unsafe {
let count = u64::from_le_bytes(msg_vec[1..9].try_into().unwrap_unchecked()) as usize;
let size = u64::from_le_bytes(msg_vec[9..17].try_into().unwrap_unchecked()) as usize;
let src =
u64::from_le_bytes(msg_vec[17..25].try_into().unwrap_unchecked()) as *const u8;
let dest = u64::from_le_bytes(msg_vec[25..33].try_into().unwrap_unchecked()) as *mut u8;
debug_assert!(src.addr() & 0xFFFF000000000000 != 0);
debug_assert!(dest.addr() & 0xFFFF000000000000 != 0);
memset(dest, src, count, size);
},
_ => {
log::debug!("Unknown memory service message type: {}", msg_type);
}

View file

@ -6,6 +6,6 @@ pub mod mem_serve;
pub mod service_definition_service;
#[inline(always)]
pub fn block_read<'a>(mem_addr: u64, length: usize) -> &'a [u8] {
unsafe { slice::from_raw_parts(mem_addr as *const u8, length) }
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

@ -22,21 +22,19 @@ pub enum ServiceError {
pub fn sds_msg_handler(vm: &mut Vm, mem_addr: u64, length: usize) -> Result<(), ServiceError> {
let msg_vec = block_read(mem_addr, length);
let sds_event_type: ServiceEventType = msg_vec[0].into();
// info!("Length {}", msg_vec.len());
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 =
core::str::from_utf8(&msg_vec[1..]).expect("Our bytes should be valid utf8");
let ret = sds_create_service(string);
vm.registers[1] = hbvm::value::Value(ret as u64);
}
DeleteService => todo!(),
SearchServices => {
let string =
core::str::from_utf8(&msg_vec[1..]).expect("Our bytes should be valid utf8");
let ret = sds_search_service(string);
vm.registers[1] = hbvm::value::Value(ret as u64);
}
@ -94,8 +92,7 @@ fn sds_create_service(protocol: &'static str) -> u64 {
// let a: protocol::Protocol = protocol.into();
buff_id
}
fn sds_search_service(protocol: &str) -> u64 {
pub fn sds_search_service(protocol: &str) -> u64 {
let services = SERVICES.lock();
let compare = Protocol::from(protocol);
for (bid, protocol_canidate) in &services.0 {

View file

@ -30,30 +30,29 @@ impl Memory {
}
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> {
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()
}

View file

@ -1,9 +1,9 @@
mod ecah;
mod kernel_services;
pub mod kernel_services;
mod mem;
use {
alloc::alloc::{alloc_zeroed, dealloc},
alloc::alloc::{alloc, dealloc},
core::{
alloc::Layout,
future::Future,
@ -61,28 +61,27 @@ impl<'p> Future for ExecThread {
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
match self.vm.run() {
Err(err) => {
error!("HBVM Error\r\nRegister dump: {:?}", self.vm.registers);
Poll::Ready(Err(err))
}
Ok(VmRunOk::End) => Poll::Ready(Ok(())),
Ok(VmRunOk::Ecall) => {
ecah::handler(&mut self.vm);
cx.waker().wake_by_ref();
Poll::Pending
}
Ok(VmRunOk::Timer) => {
cx.waker().wake_by_ref();
Poll::Pending
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,
cx.ext()
.downcast_ref()
.expect("PID did not exist in Context"),
),
Ok(VmRunOk::Timer) => (),
Ok(VmRunOk::Breakpoint) => {
error!(
log::error!(
"HBVM Debug breakpoint\r\nRegister dump: {:?}",
self.vm.registers
self.vm.registers,
);
cx.waker().wake_by_ref();
Poll::Pending
}
}
cx.waker().wake_by_ref();
Poll::Pending
}
}
@ -103,10 +102,10 @@ impl HandlePageFault for PageFaultHandler {
#[inline(always)]
const fn stack_layout() -> Layout {
unsafe { Layout::from_size_align_unchecked(STACK_SIZE, 4096) }
unsafe { Layout::from_size_align_unchecked(STACK_SIZE, 8) }
}
#[inline(always)]
fn allocate_stack() -> *mut u8 {
unsafe { alloc_zeroed(stack_layout()) }
unsafe { alloc(stack_layout()) }
}

View file

@ -49,9 +49,7 @@ impl<'a> IpcBuffer<'a> {
pub fn push(&mut self, msg: Message) {
match &self.buffer {
BufferTypes::Unbound(buff) => buff.push(msg),
BufferTypes::Bound(buff) => {
let _ = buff.push(msg);
}
BufferTypes::Bound(buff) => buff.push(msg).unwrap(),
};
}
pub fn pop(&mut self) -> Result<Message, IpcError> {

View file

@ -1,18 +1,15 @@
use {
alloc::{string::String, vec::Vec},
hashbrown::HashMap,
};
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<'a> {
types: HashMap<&'a str, Type>,
fns: HashMap<&'a str, Funct>,
fns: HashMap<&'a str, Funct<'a>>,
}
impl<'a> Protocol<'a> {
pub fn void() -> Self {

View file

@ -8,17 +8,32 @@ use {
device_tree::DeviceTree,
holeybytes::ExecThread,
ipc::buffer::IpcBuffer,
task::Executor,
},
alloc::boxed::Box,
core::cell::LazyCell,
hashbrown::HashMap,
hbvm::mem::Address,
limine::{Framebuffer, FramebufferRequest, NonNullPtr},
log::{debug, info},
log::{debug, error, trace},
spin::{Lazy, Mutex},
};
pub fn kmain(_cmdline: &str, boot_modules: BootModules) -> ! {
debug!("Entered kmain");
#[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:?}");
@ -36,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
@ -50,56 +65,84 @@ 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::new(256);
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();
cmd = &cmd[1..cmd.len()]
}
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!("Spawning {} with arguments \"{}\"", module.path, cmd);
log::info!(
"Starting {}",
module
.path
.split('/')
.last()
.unwrap()
.split('.')
.next()
.unwrap()
);
log::debug!("Spawning {} with arguments \"{}\"", module.path, cmd);
executor.spawn(async move {
let mut thr = ExecThread::new(&module.bytes, Address::new(0));
if cmd_len > 0 {
thr.set_arguments(cmd.as_bytes().as_ptr() as u64, cmd_len);
}
// 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 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;
};
let code_length = u64::from_le_bytes(header[7..15].try_into().unwrap());
let data_length = u64::from_le_bytes(header[15..23].try_into().unwrap());
let end = (code_length + data_length) as usize;
log::debug!("{code_length} + {data_length} = {end}");
let mut thr = ExecThread::new(&module.bytes[offset..end], Address::new(0));
if cmd_len > 0 {
thr.set_arguments(cmd.as_ptr() as u64, cmd_len);
}
executor.spawn(Box::pin(async {
if let Err(e) = thr.await {
log::error!("{e:?}");
}
})
}));
}
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)
@ -117,10 +160,3 @@ pub static IPC_BUFFERS: Lazy<Mutex<IpcBuffers>> = Lazy::new(|| {
Mutex::new(bufs)
});
#[test_case]
fn trivial_assertion() {
trace!("trivial assertion... ");
assert_eq!(1, 1);
info!("[ok]");
}

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

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

View file

@ -2,18 +2,21 @@
//! Named akern.
//! Akern is woefully undersupported at the moment but we are looking to add support improve hardware discovery and make our lives as kernel and operating system developers easier and better
#![no_std]
#![feature(new_uninit)]
#![no_main]
#![feature(
slice_split_once,
exclusive_wrapper,
core_intrinsics,
abi_x86_interrupt,
lazy_get,
alloc_error_handler,
local_waker,
context_ext,
ptr_sub_ptr,
custom_test_frameworks,
naked_functions,
pointer_is_aligned_to
)]
#![test_runner(crate::test_runner)]
#![cfg_attr(not(debug_assertions), allow(unused, deprecated))]
#![allow(dead_code)]
#![allow(dead_code, internal_features, static_mut_refs)]
extern crate alloc;
mod allocator;
@ -21,6 +24,7 @@ mod arch;
mod bootmodules;
mod capabilities;
mod device_tree;
mod exe_format;
mod handle;
mod holeybytes;
mod ipc;
@ -30,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,6 +49,7 @@ pub const VERSION: Version = Version {
#[panic_handler]
#[cfg(target_os = "none")]
fn panic(info: &core::panic::PanicInfo) -> ! {
use alloc::string::ToString;
arch::register_dump();
if let Some(loc) = info.location() {
@ -53,15 +61,7 @@ fn panic(info: &core::panic::PanicInfo) -> ! {
));
}
let 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

@ -36,13 +36,26 @@ impl log::Log for Logger {
Level::Debug => "25",
Level::Trace => "103",
};
let module = record.module_path().unwrap_or_default();
let line = record.line().unwrap_or_default();
crate::arch::log(format_args!(
"\x1b[38;5;{lvl_color}m{lvl}\x1b[0m [{module}:{line}]: {}\r\n",
record.args(),
))
.expect("write to serial console");
let module = record
.module_path()
.unwrap_or_default()
.rsplit_once(':')
.unwrap_or_default()
.1;
if module == "" {
crate::arch::log(format_args!(
"\x1b[38;5;{lvl_color}m{lvl}\x1b[0m: {}\r\n",
record.args(),
))
.expect("write to serial console");
} else {
let line = record.line().unwrap_or_default();
crate::arch::log(format_args!(
"\x1b[38;5;{lvl_color}m{lvl}\x1b[0m [{module}:{line}]: {}\r\n",
record.args(),
))
.expect("write to serial console");
}
}
fn flush(&self) {}

View file

@ -1,9 +1,14 @@
use {
alloc::{boxed::Box, sync::Arc},
alloc::{
boxed::Box,
collections::{BTreeMap, BTreeSet},
sync::Arc,
},
core::{
future::Future,
pin::Pin,
task::{Context, Poll, RawWaker, RawWakerVTable, Waker},
sync::atomic::{AtomicBool, Ordering},
task::{Context, ContextBuilder, Poll, RawWaker, RawWakerVTable, Waker},
},
crossbeam_queue::SegQueue,
slab::Slab,
@ -14,7 +19,6 @@ pub fn yield_now() -> impl Future<Output = ()> {
impl Future for YieldNow {
type Output = ();
#[inline(always)]
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
if self.0 {
Poll::Ready(())
@ -29,150 +33,184 @@ pub fn yield_now() -> impl Future<Output = ()> {
YieldNow(false)
}
pub struct Executor<F: Future<Output = ()> + Send> {
tasks: Slab<Task<F>>,
task_queue: Arc<TaskQueue>,
pub trait Process: Future<Output = ()> + Send {}
impl<T: Future<Output = ()> + Send> Process for T {}
pub struct Executor {
tasks: Slab<Task>,
task_queue: Arc<SegQueue<usize>>,
interrupt_lookup: [Option<usize>; u8::MAX as usize],
buffer_lookup: BTreeMap<usize, BTreeSet<usize>>,
}
impl<F: Future<Output = ()> + Send> Executor<F> {
pub fn new(size: usize) -> Self {
impl Executor {
pub fn new() -> Self {
Self {
tasks: Slab::with_capacity(size),
task_queue: Arc::new(TaskQueue::new()),
tasks: Slab::new(),
task_queue: Arc::new(SegQueue::new()),
interrupt_lookup: [None; u8::MAX as usize],
buffer_lookup: BTreeMap::new(),
}
}
#[inline]
pub fn spawn(&mut self, future: F) {
self.task_queue
.queue
.push(self.tasks.insert(Task::new(future)));
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 task_batch = [0; 32];
let mut batch_len = 0;
loop {
self.task_queue.batch_pop(&mut task_batch, &mut batch_len);
let mut batch_len = 0;
if batch_len == 0 {
if self.task_queue.is_empty() {
while let Some(id) = self.task_queue.pop() {
task_batch[batch_len] = id;
batch_len += 1;
if batch_len == task_batch.len() {
break;
} else {
continue;
}
}
for &id in &task_batch[..batch_len] {
if let Some(task) = self.tasks.get_mut(id) {
let waker = task
.waker
.get_or_insert_with(|| TaskWaker::new(id, Arc::clone(&self.task_queue)));
if batch_len == 0 {
// break;
continue;
}
let waker = unsafe { Waker::from_raw(TaskWaker::into_raw_waker(waker)) };
let mut cx = Context::from_waker(&waker);
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.task_queue.free_tasks.push(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<F: Future<Output = ()> + Send> {
future: Pin<Box<F>>,
waker: Option<TaskWaker>,
struct Task {
future: Pin<Box<dyn Process>>,
paused: AtomicBool,
}
impl<F: Future<Output = ()> + Send> Task<F> {
#[inline(always)]
pub fn new(future: F) -> Self {
impl Task {
fn new(future: Pin<Box<dyn Process>>) -> Self {
Self {
future: Box::pin(future),
waker: None,
future,
paused: AtomicBool::new(false),
}
}
#[inline(always)]
fn poll(&mut self, cx: &mut Context) -> Poll<()> {
self.future.as_mut().poll(cx)
}
fn is_paused(&self) -> bool {
self.paused.load(Ordering::Acquire)
}
fn set_paused(&self, paused: bool) {
self.paused.store(paused, Ordering::Release)
}
}
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: usize,
task_queue: Arc<TaskQueue>,
task_id: usize,
task_queue: Arc<SegQueue<usize>>,
}
impl TaskWaker {
#[inline(always)]
fn new(id: usize, task_queue: Arc<TaskQueue>) -> Self {
Self { id, task_queue }
}
#[inline(always)]
fn wake(&self) {
self.task_queue.queue.push(self.id);
}
fn into_raw_waker(waker: &TaskWaker) -> RawWaker {
let ptr = waker as *const TaskWaker;
RawWaker::new(ptr.cast(), &VTABLE)
self.task_queue.push(self.task_id);
}
}
const VTABLE: RawWakerVTable = RawWakerVTable::new(clone_raw, wake_raw, wake_by_ref_raw, drop_raw);
unsafe fn clone_raw(ptr: *const ()) -> RawWaker {
let waker = &*(ptr as *const TaskWaker);
TaskWaker::into_raw_waker(waker)
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 waker = &*(ptr as *const TaskWaker);
waker.wake();
let task_waker = Box::from_raw(ptr as *mut TaskWaker);
task_waker.wake();
}
unsafe fn wake_by_ref_raw(ptr: *const ()) {
let waker = &*(ptr as *const TaskWaker);
waker.wake();
let task_waker = &*(ptr as *const TaskWaker);
task_waker.wake();
}
unsafe fn drop_raw(_: *const ()) {}
struct TaskQueue {
queue: SegQueue<usize>,
next_task: usize,
free_tasks: SegQueue<usize>,
}
impl TaskQueue {
fn new() -> Self {
Self {
queue: SegQueue::new(),
next_task: 0,
free_tasks: SegQueue::new(),
}
}
#[inline(always)]
fn batch_pop(&self, output: &mut [usize], len: &mut usize) {
*len = 0;
while let Some(id) = self.queue.pop() {
output[*len] = id;
*len += 1;
if *len == output.len() {
break;
}
}
}
#[inline(always)]
fn is_empty(&self) -> bool {
self.queue.is_empty()
}
unsafe fn drop_raw(ptr: *const ()) {
drop(Box::from_raw(ptr as *mut TaskWaker));
}

View file

@ -4,15 +4,14 @@
/// Used when tab `\t` in hardware is not known and we will default to two spaces
pub const TAB: &str = " ";
// NOTE: this only reduces the code duplication in source code not in generated code!
// Written by Yours Truly: Munir
/// A simple macro to reduce code duplication when we use TAB internally
#[macro_export]
macro_rules! tab {
($num:expr) => {
($num:expr) => {
TAB.repeat($num)
}
};
}
// NOTE: this only reduces the code duplication in source code not in generated code!
@ -22,7 +21,7 @@ macro_rules! tab {
macro_rules! device_tree {
($devtree:expr, $dev_type_vec:expr) => {
for each_device_type in $dev_type_vec {
$devtree.devices.insert(each_device_type.to_string(), Vec::new());
$devtree.devices.insert(each_device_type, Vec::new());
}
};
}
@ -50,4 +49,4 @@ macro_rules! cpu_features {
$result_vec.push(("rdseed", rdseed));
$result_vec.push(("x2apic", x2));
};
}
}

View file

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

View file

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

View file

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

2
known_bugs.md Normal file
View file

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

View file

@ -6,24 +6,16 @@ edition = "2021"
[dependencies]
str-reader = "0.1"
derive_more = { version = "1", default-features = false, features = [
"add",
"add_assign",
"constructor",
"display",
"from",
"into",
"mul",
"mul_assign",
"not",
"sum",
"display",
] }
error-stack = "0.5"
fatfs = "0.3"
fatfs = { version = "0.3", default-features = false, features = [
"std",
"alloc",
] }
toml = "0.8"
# hbasm.git = "https://git.ablecorp.us/AbleOS/holey-bytes.git"
hblang.git = "https://git.ablecorp.us/AbleOS/holey-bytes.git"
[dependencies.reqwest]
version = "0.12"
default-features = false
features = ["rustls-tls", "blocking"]
# hblang.path = "../../holey-bytes/lang/"
log = "0.4"
raw-cpuid = "11"
ureq = { version = "2", default-features = false, features = ["tls"] }

View file

@ -1,5 +1,6 @@
#![allow(unused)]
use std::{
collections::HashMap,
fmt::format,
fs::{read_to_string, File},
io::{BufWriter, Write},
@ -13,6 +14,7 @@ pub struct Package {
name: String,
binaries: Vec<String>,
build_cmd: String,
args: HashMap<String, String>,
}
impl Package {
@ -46,57 +48,82 @@ 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),
}
std::fs::write(format!("target/programs/{}.hbf", self.name), &bytes).unwrap();
bytes.clear();
let _ = hblang::run_compiler(
hblang::run_compiler(
&path,
Options {
dump_asm: true,
resolver: Some(hblang::ABLEOS_PATH_RESOLVER),
..Default::default()
},
&mut bytes,
out,
&mut warnings,
)?;
std::fs::write(format!("target/programs/{}.hbf", self.name), &out)?;
out.clear();
let err = hblang::run_compiler(
&path,
Options {
resolver: Some(hblang::ABLEOS_PATH_RESOLVER),
dump_asm: true,
..Default::default()
},
out,
&mut warnings,
);
std::fs::write(format!("target/programs/{}.hba", self.name), &bytes).unwrap();
std::fs::write(format!("target/programs/{}.hba", self.name), &out)?;
out.clear();
return err;
}
Ok(())
}
}

View file

@ -1,18 +1,16 @@
// #![allow(unused)]
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,
};
@ -21,11 +19,15 @@ 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;
@ -35,17 +37,45 @@ fn main() -> Result<(), Error> {
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, debuginfo).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;
@ -55,13 +85,19 @@ fn main() -> Result<(), Error> {
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, debuginfo)?;
run(release, target)
build(release, target, debuginfo, tests)?;
run(release, target, do_accel)
}
Some("help" | "h") => {
println!(concat!(
@ -71,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(())
}
@ -195,21 +234,43 @@ TERM_BACKDROP={}
let modules = value.get_mut("modules").unwrap().as_table_mut().unwrap();
// let mut real_modules = modules.clone();
modules.into_iter().for_each(|(_, value)| {
if value.is_table() {
let path = get_path_without_boot_prefix(
value.get("path").expect("You must have `path` as a value"),
)
.unwrap()
.split(".")
.next()
.unwrap();
let p = Package::load_from_file(
format!("sysdata/programs/{}/meta.toml", path).to_owned(),
);
p.build();
}
});
let mut errors = String::new();
let mut out = Vec::new();
modules
.into_iter()
.map(|(_, value)| -> Result<(), io::Error> {
if value.is_table() {
let path = get_path_without_boot_prefix(
value.get("path").expect("You must have `path` as a value"),
)
.unwrap()
.split(".")
.next()
.unwrap();
let p = Package::load_from_file(
format!("sysdata/programs/{}/meta.toml", path).to_owned(),
);
match p.build(&mut out) {
Ok(()) => {}
Err(e) => {
writeln!(errors, "========= while compiling {} {} =========", path, e)
.unwrap();
errors.push_str(&String::from_utf8_lossy(&out));
out.clear();
}
}
}
Ok(())
})
.for_each(drop);
if !errors.is_empty() {
let _ = writeln!(errors, "!!! STOPPING DUE TO PREVIOUS ERRORS !!!");
std::eprint!("{errors}");
continue;
}
modules.into_iter().for_each(|(_key, value)| {
if value.is_table() {
let path = value.get("path").expect("You must have `path` as a value");
@ -278,7 +339,7 @@ fn copy_file_to_img(fpath: &str, fs: &FileSystem<File>) {
.expect("Copy failed");
}
fn build(release: bool, target: Target, debuginfo: bool) -> 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");
@ -290,12 +351,19 @@ fn build(release: bool, target: Target, debuginfo: bool) -> Result<(), Error> {
com.env("RUSTFLAGS", "-Cdebug-assertions=true");
}
if tests {
com.args(["--features", "ktest"]);
}
if target == Target::Riscv64Virt {
com.args(["--target", "targets/riscv64-virt-ableos.json"]);
}
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),
@ -309,6 +377,10 @@ fn build(release: bool, target: Target, debuginfo: bool) -> 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");
@ -331,25 +403,73 @@ fn build(release: bool, target: Target, debuginfo: bool) -> 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"
//"-hda", "target/disk.img",
"-drive", "file=target/disk.img,index=0,if=ide,format=raw",
"-device", "vmware-svga",
// "-serial", "stdio",
"-m", "2G",
"-smp", "1",
"-audiodev",
"pa,id=speaker",
"-machine",
"pcspk-audiodev=speaker",
"-parallel", "none",
"-monitor", "none",
"-machine", accel,
"-cpu", "max",
"-device", "isa-debug-exit,iobase=0xf4,iosize=0x04",
]);
}
Target::Riscv64Virt => {
@ -370,7 +490,7 @@ fn run(release: bool, target: Target) -> Result<(), Error> {
#[rustfmt::skip]
com.args([
"-M", "virt",
"-cpu", "neoverse-n2",
"-cpu", "max",
"-device", "ramfb",
"-device", "qemu-xhci",
"-device", "usb-kbd",
@ -393,7 +513,7 @@ fn run(release: bool, target: Target) -> Result<(), Error> {
fn fetch_ovmf(target: Target) -> Result<String, OvmfFetchError> {
let (ovmf_url, ovmf_path) = match target {
Target::X86_64 => (
Target::X86_64 | Target::X86_64Avx2 => (
"https://retrage.github.io/edk2-nightly/bin/RELEASEX64_OVMF.fd",
"target/RELEASEX64_OVMF.fd",
),
@ -415,12 +535,12 @@ fn fetch_ovmf(target: Target) -> Result<String, OvmfFetchError> {
Ok(_) => return Ok(ovmf_path.to_owned()),
Err(e) => return Err(report!(e).change_context(OvmfFetchError::Io)),
};
let mut bytes = reqwest::blocking::get(ovmf_url)
let req = ureq::get(ovmf_url)
.call()
.map_err(Report::from)
.change_context(OvmfFetchError::Fetch)?;
bytes
.copy_to(&mut file)
std::io::copy(&mut req.into_reader(), &mut file)
.map_err(Report::from)
.change_context(OvmfFetchError::Io)?;
@ -442,6 +562,7 @@ impl Context for OvmfFetchError {}
#[derive(Clone, Copy, PartialEq, Eq)]
enum Target {
X86_64,
X86_64Avx2,
Riscv64Virt,
Aarch64,
}

View file

@ -1,3 +1,7 @@
[toolchain]
channel = "nightly-2024-07-27"
# 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 +0,0 @@
# dt_api

View file

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

View file

@ -0,0 +1,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,24 +1,43 @@
stn := @use("rel:../../stn/src/lib.hb");
.{string, memory, buffer} := stn
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(channel: int): void {
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 {
msg := "\{01}\0"
msg_length := 2
@eca(void, 3, windowing_system_buffer, msg, msg_length)
}
x := 0
loop if x > 1000 break else x += 1
return
}
ret := buffer.recv([4096]u8, windowing_system_buffer, mem_buf)
if ret == null {
log.info("No messages\0")
}
if *mem_buf == 0 {
log.info("No messages\0")
}
return @as(^render.Surface, idk)
}
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,5 +1,5 @@
structures := @use("rel:structures.hb")
version := @use("rel:version.hb")
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 {
@ -7,7 +7,7 @@ ApplicationInfo := struct {
pNext: ^int,
application_name: ^u8,
application_version: int,
engine_name: int,
engine_name: ^u8,
engine_version: int,
api_version: int,
}

View file

@ -1,8 +1,8 @@
application := @use("rel:application.hb");
application := @use("application.hb");
.{ApplicationInfo} := application
structures := @use("rel:structures.hb")
errors := @use("rel:errors.hb")
structures := @use("structures.hb")
errors := @use("errors.hb")
// https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkInstanceCreateInfo.html
InstanceCreateInfo := struct {

View file

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

View file

@ -1,5 +1,5 @@
offsets := @use("rel:offset.hb")
extends := @use("rel:extends.hb")
offsets := @use("offset.hb")
extends := @use("extends.hb")
Rect2D := struct {
offset: offsets.Offset2D,

View file

@ -0,0 +1,20 @@
# intouch
This library is exclusively focused on allowing your to get input regardless of which devices you have.
Partially modeled after SDL.
Current goals include
- Interfaces
- PS/2
- Device Types
- Keyboard
- Mouse
Longer Term goals
- Interfaces
- USB
- USB-HID
- Device Types
- Gamepads/controllers
- Drawing Tablets
- Microphones

View file

@ -0,0 +1,2 @@
0x0D -> press Tab
0xF0 0x0D -> release Tab

View file

@ -0,0 +1,18 @@
keycodes := @use("keycodes.hb");
.{KeyCode} := keycodes
KeyEvent := packed struct {
up: bool,
just_triggered: bool,
key: KeyCode,
}
MouseEvent := packed struct {
x_change: i8,
y_change: i8,
left: bool,
middle: bool,
right: bool,
}
GamepadEvent := struct {}

View file

@ -0,0 +1,121 @@
/*
Originally I was modelling this after the following(1). I have since changed my mind.
I am now modelling it as I see fit. This is likely not the final version.
1) https://www.libsdl.org/release/SDL-1.2.15/include/SDL_keysym.h
*/
KeyCode := u32
// Typically this is not a keycode you will ever recieve.
None := KeyCode.(0)
Escape := KeyCode.(1)
/* Alphabet keycodes */
A := KeyCode.(2)
B := KeyCode.(3)
C := KeyCode.(4)
D := KeyCode.(5)
E := KeyCode.(6)
F := KeyCode.(7)
G := KeyCode.(8)
H := KeyCode.(9)
I := KeyCode.(10)
J := KeyCode.(11)
K := KeyCode.(12)
L := KeyCode.(13)
M := KeyCode.(14)
N := KeyCode.(15)
O := KeyCode.(16)
P := KeyCode.(17)
Q := KeyCode.(18)
R := KeyCode.(19)
S := KeyCode.(20)
T := KeyCode.(21)
U := KeyCode.(22)
V := KeyCode.(23)
W := KeyCode.(24)
X := KeyCode.(25)
Y := KeyCode.(26)
Z := KeyCode.(27)
/* Numeric keycodes*/
Number0 := KeyCode.(28)
Number1 := KeyCode.(29)
Number2 := KeyCode.(30)
Number3 := KeyCode.(31)
Number4 := KeyCode.(32)
Number5 := KeyCode.(33)
Number6 := KeyCode.(34)
Number7 := KeyCode.(35)
Number8 := KeyCode.(36)
Number9 := KeyCode.(37)
KeypadNumber0 := KeyCode.(38)
KeypadNumber1 := KeyCode.(39)
KeypadNumber2 := KeyCode.(40)
KeypadNumber3 := KeyCode.(41)
KeypadNumber4 := KeyCode.(42)
KeypadNumber5 := KeyCode.(43)
KeypadNumber6 := KeyCode.(44)
KeypadNumber7 := KeyCode.(45)
KeypadNumber8 := KeyCode.(46)
KeypadNumber9 := KeyCode.(47)
KeypadPeriod := KeyCode.(48)
KeypadDivide := KeyCode.(49)
KeypadMultiply := KeyCode.(50)
KeypadMinus := KeyCode.(51)
KeypadPlus := KeyCode.(52)
KeypadEnter := KeyCode.(53)
KeypadEquals := KeyCode.(54)
Delete := KeyCode.(55)
/* Locking Keys */
NumLock := KeyCode.(56)
CapsLock := KeyCode.(57)
ScrollLock := KeyCode.(58)
/* "Alt Gr" key */
Mode := KeyCode.(59)
/* Multi-key compose key */
Compose := KeyCode.(60)
LeftAlt := KeyCode.(61)
LeftControl := KeyCode.(62)
LeftMeta := KeyCode.(63)
LeftShift := KeyCode.(64)
/* Left "Windows" key */
LeftSuper := KeyCode.(65)
RightAlt := KeyCode.(66)
RightControl := KeyCode.(67)
RightMeta := KeyCode.(68)
RightShift := KeyCode.(69)
/* Right "Windows" key */
RightSuper := KeyCode.(70)
/*
This block of any triggers on any press of any of the keys.
Typically this is the event to care about.
*/
AnyNumber0 := KeyCode.(71)
AnyNumber1 := KeyCode.(72)
AnyNumber2 := KeyCode.(73)
AnyNumber3 := KeyCode.(74)
AnyNumber4 := KeyCode.(75)
AnyNumber5 := KeyCode.(76)
AnyNumber6 := KeyCode.(77)
AnyNumber7 := KeyCode.(78)
AnyNumber8 := KeyCode.(79)
AnyNumber9 := KeyCode.(80)
AnyAlt := KeyCode.(81)
AnyControl := KeyCode.(82)
AnyMeta := KeyCode.(83)
AnyShift := KeyCode.(84)
/* Any "Windows" key */
AnySuper := KeyCode.(85)

View file

@ -0,0 +1,36 @@
stn := @use("../../stn/src/lib.hb");
.{log, buffer, memory} := stn
keycodes := @use("keycodes.hb")
events := @use("events.hb");
.{KeyEvent, MouseEvent} := events
recieve_key_event := fn(): ?KeyEvent {
kevent := KeyEvent.(false, false, 0)
buf_id := buffer.search("PS/2 Keyboard\0")
// Read out of the Keyboard buffer here
buffer.recv(KeyEvent, buf_id, &kevent)
if kevent.just_triggered {
return kevent
}
return null
}
recieve_mouse_event := fn(): ?MouseEvent {
mevent := MouseEvent.(0, 0, false, false, false)
buf_id := buffer.search("PS/2 Mouse\0")
// Read out of the Mouse buffer here
buffer.recv(MouseEvent, buf_id, &mevent)
if mevent.x_change != 0 | mevent.y_change != 0 | mevent.left | mevent.middle | mevent.right {
return mevent
}
return null
}

View file

@ -1,11 +1,75 @@
.{string, memory, buffer, log} := @use("../../stn/src/lib.hb")
PCIAddress := struct {
bus: u8,
device: u8,
function: u8,
}
find_device := fn(vendor_id: int, device_id: int, pci_address: PCIAddress): int {
return 1
PCI_ID := struct {
vendor: u16,
device: u16,
inner: int,
}
get_ids := fn(bus: u8, device: u8, function: u8): PCI_ID {
res := config_read32(bus, device, function, 0)
dev_id := res >> 16
dev_id &= 0xFFFF
vnd_id := res & 0xFFFF
return PCI_ID.(dev_id, vnd_id, 0)
}
PciDeviceInfo := struct {
header_type: u8,
device: u8,
bus: u8,
device_id: PCI_ID,
class: u16,
rev_id: u8,
}
calculate_address := fn(bus: u8, device: u8, function: u8, offset: u8): int {
address := bus << 16
address |= device << 11
address |= function << 8
address |= offset & 0xFC
address |= 0x80000000
return address
}
get_header_type := fn(bus: u8, device: u8, function: u8): u8 {
res := config_read32(bus, device, function, 0xC)
ret := res >> 16
ret &= 0xFF
return ret
}
check_device := fn(bus: u8, device: u8): PciDeviceInfo {
pci_id := get_ids(bus, device, 0)
if pci_id.vendor == 0xFFFF {
log.warn(":|\0")
} else {
log.info(":)\0")
}
address := calculate_address(bus, device, 0, 0x8)
reg2 := config_read32(bus, device, 0, 0x8)
class := reg2 >> 16 & 0xFFFF
header_type := get_header_type(bus, device, 0)
rev_id := reg2 & 0xFF
return PciDeviceInfo.(header_type, device, bus, pci_id, class, rev_id)
}
find_device := fn(vendor_id: int, device_id: int, pci_address: PCIAddress): PCI_ID {
pci_id := get_ids(0, 2, 0)
return pci_id
}
scan_bus := fn(): void {
@ -13,16 +77,17 @@ scan_bus := fn(): void {
config_read32 := fn(bus: u32, device: u32, func: u32, offset: u32): u32 {
// construct address param
address := bus << 16 | device << 11 | func << 8
address |= offset
address &= 0xFC
offset_and := offset & 0xFC
address := bus << 16
address |= device << 11
address |= func << 8
address |= offset_and
address |= 0x80000000
// write address
//Port::new(0xCF8).write(address);
memory.outl(0xCF8, address)
// read data
//Port::new(0xCFC).read()
return
return memory.inl(0xCFC)
}

View file

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

View file

@ -0,0 +1,27 @@
# Images
- Animation
# API
- Colour operations:
- Alpha Composite
- Invert
- Surface Operations:
- FlipH
- Resize
- Wrap the colour operations
- Tile
- Gradient overlay
- Draw operations:
- Curve raster algorithm
- VGA font fast blit
- Polygon
- Rounded rects
# Backend
- SVGA Driver
- Support whatever vulkan stuff able is cooking
# Bits and bobs on the table
- Funny 3D Renderer
- stn.memory.swap & kernel message
- Make memory.{copy, set} smart

View file

@ -0,0 +1,49 @@
.{Color, Surface, new_surface, put_surface} := @use("../lib.hb");
.{log} := @use("../../../stn/src/lib.hb")
BitmapFileHeader := packed struct {
magic: u16,
size: u32,
reserved_1: u16,
reserved_2: u16,
offset: u32,
}
BitmapInfoHeader := packed struct {
size: u32,
width: i32,
height: i32,
planes: u16,
bits: u16,
compression: u32,
image_size: u32,
x_resolution: i32,
y_resolution: i32,
n_colours: u32,
important_colours: u32,
}
BitmapColorHeader := packed struct {
red_mask: u32,
green_mask: u32,
blue_mask: u32,
alpha_mask: u32,
color_space_type: u32,
unused: u32,
}
from := fn(bmp: ^u8): ?Surface {
file_header := @as(^BitmapFileHeader, @bitcast(bmp))
info_header := @as(^BitmapInfoHeader, @bitcast(bmp + @sizeof(BitmapFileHeader)))
if file_header.magic != 0x4D42 | info_header.width == 0 | info_header.height == 0 {
log.error("Invalid BMP image.\0")
return null
}
lhs := Surface.(@bitcast(bmp + file_header.offset), info_header.width, info_header.height, info_header.width * info_header.height)
rhs := Surface.new(info_header.width, info_header.height)
rhs.put_surface(lhs, .(0, 0), true)
return rhs
}

View file

@ -0,0 +1,31 @@
.{log} := @use("../../../stn/src/lib.hb");
.{Surface} := @use("../lib.hb")
bmp := @use("bmp.hb")
qoi := @use("qoi.hb")
$BMP := 0x4D42
$QOI := 0x66696F71
get_format := fn(file: ^u8): ?uint {
if *@as(^u16, @bitcast(file)) == BMP {
return BMP
} else if *@as(^u32, @bitcast(file)) == QOI {
return QOI
} else {
return null
}
}
from := fn(file: ^u8): ?Surface {
format := get_format(file)
if format == null {
log.error("Could not detect image format.\0")
return null
} else if format == BMP {
return bmp.from(file)
} else if format == QOI {
return qoi.from(file)
}
return null
}

View file

@ -0,0 +1,101 @@
.{Color, Surface, new_surface} := @use("../lib.hb");
.{log} := @use("../../../stn/src/lib.hb")
/* source:
https://github.com/phoboslab/qoi/blob/master/qoi.h */
$QOI_SRGB := 0
$QOI_LINEAR := 1
$QOI_OP_INDEX := 0x0
$QOI_OP_DIFF := 0x40
$QOI_OP_LUMA := 0x80
$QOI_OP_RUN := 0xC0
$QOI_OP_RGB := 0xFE
$QOI_OP_RGBA := 0xFF
$QOI_MASK_2 := 0xC0
$QOI_COLOR_HASH := fn(c: Color): u8 {
return (c.r * 3 + c.g * 5 + c.b * 7 + c.a * 11) % 64
}
$QOI_MAGIC := 0x716F6966
$QOI_PIXELS_MAX := 400000000
QuiteOkayHeader := packed struct {
magic: u32,
width: u32,
height: u32,
channels: u8,
colorspace: u8,
}
be_to_le := fn(big: u32): u32 {
return big >> 24 | big >> 8 & 0xFF00 | big << 8 & 0xFF0000 | big << 24
}
from := fn(qoi: ^u8): ?Surface {
header := @as(^QuiteOkayHeader, @bitcast(qoi))
qoi += @sizeof(QuiteOkayHeader)
width := be_to_le(header.width)
height := be_to_le(header.height)
if be_to_le(header.magic) != QOI_MAGIC | width == 0 | height == 0 | header.channels < 3 | header.channels > 4 {
log.error("Invalid QOI image.\0")
return null
}
surface := Surface.new(width, height)
index := @as([64]Color, idk)
run := 0
px := Color.(0, 0, 0, 255)
px_pos := 0
total_pixels := width * height
loop if px_pos >= total_pixels break else {
if run > 0 {
run -= 1
} else {
b1 := *qoi
qoi += 1
if b1 == QOI_OP_RGB {
px.r = *qoi
px.g = *(qoi + 1)
px.b = *(qoi + 2)
qoi += 3
} else if b1 == QOI_OP_RGBA {
px.r = *qoi
px.g = *(qoi + 1)
px.b = *(qoi + 2)
px.a = *(qoi + 3)
qoi += 4
} else if (b1 & QOI_MASK_2) == QOI_OP_INDEX {
px = index[b1 & 0x3F]
} else if (b1 & QOI_MASK_2) == QOI_OP_DIFF {
px.r = px.r + (b1 >> 4 & 0x3) - 2 & 0xFF
px.g = px.g + (b1 >> 2 & 0x3) - 2 & 0xFF
px.b = px.b + (b1 & 0x3) - 2 & 0xFF
} else if (b1 & QOI_MASK_2) == QOI_OP_LUMA {
b2 := *qoi
vg := (b1 & 0x3F) - 32
px.r = px.r + vg - 8 + (b2 >> 4 & 0xF) & 0xFF
px.g = px.g + vg & 0xFF
px.b = px.b + vg - 8 + (b2 & 0xF) & 0xFF
qoi += 1
} else if (b1 & QOI_MASK_2) == QOI_OP_RUN {
run = b1 & 0x3F
}
index[QOI_COLOR_HASH(px)] = px
};
*(surface.buf + px_pos) = px
px_pos += 1
}
return surface
}

View file

@ -1,47 +1,28 @@
svga := @use("rel:svga.hb")
software := @use("rel:software.hb")
software := @use("software.hb")
image := @use("image/lib.hb")
text := @use("text.hb")
// default mode
mode := software
init := mode.init
doublebuffer := mode.doublebuffer
Surface := mode.Surface
// Colours
Color := mode.Color
white := mode.white
black := mode.black
gray := mode.gray
red := mode.red
green := mode.green
yellow := mode.yellow
blue := mode.blue
magenta := mode.magenta
cyan := mode.cyan
light_gray := mode.light_gray
light_red := mode.light_red
light_green := mode.light_green
light_yellow := mode.light_yellow
light_blue := mode.light_blue
light_magenta := mode.light_magenta
light_cyan := mode.light_cyan
// Drawing
put_pixel := mode.put_pixel
put_rect := mode.put_rect
put_filled_rect := mode.put_filled_rect
put_line := mode.put_line
clear := mode.clear
// Display
width := mode.width
height := mode.height
dimensions := mode.dimensions
set_height := mode.set_height
set_width := mode.set_width
set_dimensions := mode.set_dimensions
sync := mode.sync
// Math
UVec2 := struct {x: uint, y: uint}
IVec2 := struct {x: int, y: int}
Color := packed struct {b: u8, g: u8, r: u8, a: u8}
$WHITE := Color.(255, 255, 255, 255)
$BLACK := Color.(0, 0, 0, 255)
$GRAY := Color.(127, 127, 127, 255)
$RED := Color.(0, 0, 205, 255)
$GREEN := Color.(0, 205, 0, 255)
$YELLOW := Color.(0, 205, 205, 255)
$BLUE := Color.(205, 0, 0, 255)
$MAGENTA := Color.(205, 0, 205, 255)
$CYAN := Color.(205, 205, 0, 255)
$LIGHT_GRAY := Color.(229, 229, 229, 255)
$LIGHT_RED := Color.(0, 0, 255, 255)
$LIGHT_GREEN := Color.(0, 255, 0, 255)
$LIGHT_YELLOW := Color.(0, 255, 255, 255)
$LIGHT_BLUE := Color.(255, 0, 0, 255)
$LIGHT_MAGENTA := Color.(255, 0, 255, 255)
$LIGHT_CYAN := Color.(255, 255, 0, 255)

View file

@ -1,261 +1,441 @@
.{math, memory} := @use("../../stn/src/lib.hb");
.{dt_get} := @use("../../dt_api/src/lib.hb");
.{IVec2} := @use("rel:lib.hb")
.{math, memory, dt} := @use("stn");
.{Color, text} := @use("lib:render");
.{get_glyph, get_glyph_unicode, Font, UNC_TABLE_SIZE} := text;
.{Vec2} := math
Color := struct {b: u8, g: u8, r: u8, a: u8}
white := Color.(255, 255, 255, 255)
black := Color.(0, 0, 0, 255)
gray := Color.(127, 127, 127, 255)
red := Color.(0, 0, 205, 255)
green := Color.(0, 205, 0, 255)
yellow := Color.(0, 205, 205, 255)
blue := Color.(205, 0, 0, 255)
magenta := Color.(205, 0, 205, 255)
cyan := Color.(205, 205, 0, 255)
light_gray := Color.(229, 229, 229, 255)
light_red := Color.(0, 0, 255, 255)
light_green := Color.(0, 255, 0, 255)
light_yellow := Color.(0, 255, 255, 255)
light_blue := Color.(255, 0, 0, 255)
light_magenta := Color.(255, 0, 255, 255)
light_cyan := Color.(255, 255, 0, 255)
// safety: don't use before init() or you will get a memory access violation
framebuffer := memory.dangling(Color)
utf8_len_table := u8.[0, 0, 2, 3]
// might not work for some resolutions, but needs to be comptime because...
copy_pixels := 0xC000 >> 2
ctx := @as(Context, idk)
// some of these are redudant holdovers from fb_driver
// will keep them for future work if necessary
Context := struct {
fb: ^Color,
bb: ^Color,
buf: ^Color,
width: int,
height: int,
partitions: int,
pixels: int,
bb_pages: int,
double_buffer: bool,
}
init := fn(): void {
width := dt_get("framebuffer/fb0/width\0")
height := dt_get("framebuffer/fb0/height\0")
// width := 1024
// height := 768
pixels := width * height
bytes := pixels << 2
partitions := pixels / copy_pixels
pages := 1 + bytes >> 12
back_buffer := create_back_buffer(pages)
ctx = Context.{
fb: dt_get("framebuffer/fb0/ptr\0"),
bb: back_buffer,
buf: back_buffer,
width,
height,
partitions,
pixels,
bb_pages: pages,
double_buffer: true,
}
return
}
doublebuffer := fn(enable: bool): void {
if enable {
ctx.buf = ctx.bb
init := fn(doublebuffer: bool): Surface {
framebuffer = dt.get(^Color, "framebuffer/fb0/ptr\0")
width := dt.get(uint, "framebuffer/fb0/width\0")
height := dt.get(uint, "framebuffer/fb0/height\0")
if doublebuffer {
return Surface.new(width, height)
} else {
ctx.buf = ctx.fb
return .(framebuffer, width, height, width * height)
}
ctx.double_buffer = enable
return
}
create_back_buffer := fn(pages: int): ^Color {
if pages <= 0xFF {
return @bitcast(@inline(memory.request_page, pages))
Surface := struct {
buf: ^Color,
width: uint,
height: uint,
size: uint,
new := fn(width: uint, height: uint): Self {
size := width * height
return .(
memory.alloc(Color, size),
width,
height,
size,
)
}
ptr := @inline(memory.request_page, 255)
remaining := pages - 0xFF
loop if remaining <= 0 break else {
if remaining < 0xFF {
memory.request_page(remaining)
} else {
memory.request_page(0xFF)
clone := fn(self: ^Self): Self {
new_self := Self.new(self.width, self.height)
memory.copy(Color, self.buf, new_self.buf, self.size)
return new_self
}
$clear := fn(self: Self, color: Color): void {
memory.set(Color, &color, self.buf, self.size)
}
$sync := fn(self: Self): void {
memory.copy(Color, self.buf, framebuffer, self.size)
}
$index := fn(self: Self, x: uint, y: uint): uint {
return x + self.width * y
}
$indexptr := fn(self: Self, x: uint, y: uint): ^Color {
return self.buf + self.index(x, y)
}
$put_pixel := fn(self: Self, pos: Vec2(uint), color: Color): void {
*self.indexptr(pos.x, pos.y) = color
}
put_filled_rect := fn(self: Self, pos: Vec2(uint), tr: Vec2(uint), color: Color): void {
top_start_idx := self.indexptr(pos.x, pos.y)
bottom_start_idx := self.indexptr(pos.x, pos.y + tr.y - 1)
rows_to_fill := tr.y
loop if rows_to_fill <= 1 break else {
memory.set(Color, &color, top_start_idx, tr.x)
memory.set(Color, &color, bottom_start_idx, tr.x)
top_start_idx += self.width
bottom_start_idx -= self.width
rows_to_fill -= 2
}
remaining -= 0xFF
}
return @bitcast(ptr)
}
clear := fn(color: Color): void {
cursor := ctx.buf
boundary := cursor + 512
loop if cursor == boundary break else {
*cursor = color
cursor += 1
}
boundary += 512 * 7
loop if cursor == boundary break else {
*@as(^[Color; 512], @bitcast(cursor)) = *@as(^[Color; 512], @bitcast(ctx.buf))
cursor += 512
}
boundary += copy_pixels - 4096
loop if cursor == boundary break else {
*@as(^[Color; 4096], @bitcast(cursor)) = *@as(^[Color; 4096], @bitcast(ctx.buf))
cursor += 4096
}
boundary += (ctx.partitions - 1) * copy_pixels
loop if cursor == boundary break else {
*@as(^[Color; copy_pixels], @bitcast(cursor)) = *@as(^[Color; copy_pixels], @bitcast(ctx.buf))
cursor += @sizeof([u8; copy_pixels])
}
return
}
sync := fn(): void {
if ctx.double_buffer {
bb := ctx.buf
fb := ctx.fb
boundary := bb + ctx.pixels
loop if bb == boundary break else {
*@as(^[Color; copy_pixels], @bitcast(fb)) = *@as(^[Color; copy_pixels], @bitcast(bb))
bb += copy_pixels
fb += copy_pixels
if rows_to_fill == 1 {
memory.set(Color, &color, top_start_idx, tr.x)
}
}
return
}
width := fn(): int {
return ctx.width
}
put_rect := fn(self: Self, pos: Vec2(uint), tr: Vec2(uint), color: Color): void {
start_idx := self.indexptr(pos.x, pos.y)
end_idx := self.indexptr(pos.x, pos.y + tr.y)
right_start_idx := self.indexptr(pos.x + tr.x, pos.y)
height := fn(): int {
return ctx.height
}
loop if start_idx > end_idx break else {
*start_idx = color;
*right_start_idx = color
start_idx += self.width
right_start_idx += self.width
}
screenidx := fn(x: int, y: int): int {
return x + ctx.width * y
}
memory.set(Color, &color, self.indexptr(pos.x, pos.y), @bitcast(tr.x + 1))
memory.set(Color, &color, self.indexptr(pos.x, pos.y + tr.y), @bitcast(tr.x + 1))
}
put_pixel := fn(pos: IVec2, color: Color): void {
*(ctx.buf + @inline(screenidx, pos.x, pos.y)) = color
return
}
put_line_low := fn(self: Self, p0: Vec2(uint), p1: Vec2(uint), color: Color): void {
dx := @as(int, @bitcast(p1.x - p0.x))
dy := @as(int, @bitcast(p1.y - p0.y))
yi := 1
if dy < 0 {
yi = -1
dy = -dy
}
D := @as(int, 2) * dy - dx
y := p0.y
x := p0.x
loop if x == p1.x break else {
*self.indexptr(x, y) = color
if D > 0 {
y += yi
D += 2 * (dy - dx)
} else {
D += 2 * dy
}
x += 1
}
}
put_filled_rect := fn(pos: IVec2, tr: IVec2, color: Color): void {
x := pos.x
y := pos.y
end := pos + tr
loop if x == end.x break else {
loop if y == end.y break else {
*(ctx.buf + @inline(screenidx, x, y)) = color
put_line_high := fn(self: Self, p0: Vec2(uint), p1: Vec2(uint), color: Color): void {
dx := @as(int, @bitcast(p1.x - p0.x))
dy := @as(int, @bitcast(p1.y - p0.y))
xi := 1
if dy < 0 {
xi = -1
dx = -dx
}
D := @as(int, 2) * dx - dy
x := p0.x
y := p0.y
loop if y == p1.y break else {
*self.indexptr(x, y) = color
if D > 0 {
x += xi
D += 2 * (dx - dy)
} else {
D += 2 * dx
}
y += 1
}
x += 1
y = pos.y
}
return
}
put_rect := fn(pos: IVec2, tr: IVec2, color: Color): void {
x := pos.x
y := pos.y
end := pos + tr
loop if y == end.y break else {
*(ctx.buf + @inline(screenidx, x, y)) = color;
*(ctx.buf + @inline(screenidx, x + tr.x, y)) = color
y += 1
}
y = pos.y
loop if x == end.x break else {
*(ctx.buf + @inline(screenidx, x, y)) = color;
*(ctx.buf + @inline(screenidx, x, y + tr.y)) = color
x += 1
}
return
}
put_line_low := fn(p0: IVec2, p1: IVec2, color: Color): void {
dx := p1.x - p0.x
dy := p1.y - p0.y
yi := 1
if dy < 0 {
yi = -1
dy = -dy
}
D := 2 * dy - dx
y := p0.y
x := p0.x
loop if x == p1.x break else {
*(ctx.buf + @inline(screenidx, x, y)) = color
if D > 0 {
y += yi
D += 2 * (dy - dx)
put_line := fn(self: Self, p0: Vec2(uint), p1: Vec2(uint), color: Color): void {
if math.abs(int, @bitcast(p1.y - p0.y)) < math.abs(int, @bitcast(p1.x - p0.x)) {
if p0.x > p1.x {
@inline(put_line_low, self, p1, p0, color)
} else {
@inline(put_line_low, self, p0, p1, color)
}
} else {
D += 2 * dy
}
x += 1
}
return
}
put_line_high := fn(p0: IVec2, p1: IVec2, color: Color): void {
dx := p1.x - p0.x
dy := p1.y - p0.y
xi := 1
if dy < 0 {
xi = -1
dx = -dx
}
D := 2 * dx - dy
x := p0.x
y := p0.y
loop if y == p1.y break else {
*(ctx.buf + @inline(screenidx, x, y)) = color
if D > 0 {
x += xi
D += 2 * (dx - dy)
} else {
D += 2 * dx
}
y += 1
}
return
}
put_line := fn(p0: IVec2, p1: IVec2, color: Color): void {
if @inline(math.abs, p1.y - p0.y) < @inline(math.abs, p1.x - p0.x) {
if p0.x > p1.x {
@inline(put_line_low, p1, p0, color)
} else {
@inline(put_line_low, p0, p1, color)
}
} else {
if p0.y > p1.y {
@inline(put_line_high, p1, p0, color)
} else {
@inline(put_line_high, p0, p1, color)
if p0.y > p1.y {
@inline(put_line_high, self, p1, p0, color)
} else {
@inline(put_line_high, self, p0, p1, color)
}
}
}
return
}
set_height := fn(new: int): void {
return
}
put_surface := fn(self: Self, top: Self, pos: Vec2(uint), flip_v: bool): void {
src_top_cursor := top.buf
src_bottom_cursor := top.buf + top.width * (top.height - 1)
set_width := fn(new: int): void {
return
}
dst_top_idx := self.indexptr(pos.x, pos.y)
dst_bottom_idx := self.indexptr(pos.x, pos.y + top.height - 1)
dimensions := fn(): IVec2 {
return .(ctx.width, ctx.height)
}
dst_increment := self.width
set_dimensions := fn(new: IVec2): void {
return
if flip_v {
dst_increment = -dst_increment
tmp := dst_top_idx
dst_top_idx = dst_bottom_idx
dst_bottom_idx = tmp
}
rows_to_copy := top.height
loop if rows_to_copy <= 1 break else {
memory.copy(Color, src_top_cursor, dst_top_idx, top.width)
memory.copy(Color, src_bottom_cursor, dst_bottom_idx, top.width)
dst_top_idx += dst_increment
dst_bottom_idx -= dst_increment
src_top_cursor += top.width
src_bottom_cursor -= top.width
rows_to_copy -= 2
}
if rows_to_copy == 1 {
memory.copy(Color, src_top_cursor, dst_top_idx, top.width)
}
}
// peony-made
put_trirect := fn(self: Self, pos: Vec2(uint), size: Vec2(int), color0: Color, color1: Color): void {
step := Vec2(int).(1, 1)
if size.x < 0 {
step.x = -1
}
if size.y < 0 {
step.y /= @bitcast(size.x)
}
start_y := pos.y
target := pos + @bitcast(size)
loop if pos.x == target.x break else {
@inline(put_vline, self, pos.x, pos.y, target.y, color0)
@inline(put_vline, self, pos.x, pos.y, start_y, color1)
pos += @bitcast(step)
}
}
// peony-made
put_vline := fn(self: Self, x: uint, y0: uint, y1: uint, color: Color): void {
if y1 < y0 {
tmp := y0
y0 = y1
y1 = tmp
}
y := y0
loop if y == y1 break else {
*self.indexptr(x, y) = color
y += 1
}
}
// peony-made
put_hline := fn(self: Self, y: uint, x0: uint, x1: uint, color: Color): void {
if x1 < x0 {
tmp := x0
x0 = x1
x1 = tmp
}
memory.set(Color, &color, self.indexptr(x0, y), @bitcast(x1 - x0))
}
put_circle := fn(self: Self, pos: Vec2(uint), radius: uint, color: Color): void {
x := 0
y := radius
error := @as(int, 3) - 2 * @intcast(radius)
loop if x > y break else {
self.put_pixel(pos + .(x, y), color)
self.put_pixel(pos + .(-x, y), color)
self.put_pixel(pos + .(x, -y), color)
self.put_pixel(pos + .(-x, -y), color)
self.put_pixel(pos + .(y, x), color)
self.put_pixel(pos + .(-y, x), color)
self.put_pixel(pos + .(y, -x), color)
self.put_pixel(pos + .(-y, -x), color)
if error < 0 {
error += 4 * @intcast(x) + 6
} else {
error += 4 * (@intcast(x) - @intcast(y)) + 10
y -= 1
}
x += 1
}
}
put_filled_circle := fn(self: Self, pos: Vec2(uint), radius: uint, color: Color): void {
x := 0
y := radius
error := @as(int, 3) - 2 * @intcast(radius)
loop if x > y break else {
self.put_hline(pos.y + y, pos.x - x, pos.x + x, color)
self.put_hline(pos.y - y, pos.x - x, pos.x + x, color)
if x != y {
self.put_hline(pos.y + x, pos.x - y, pos.x + y, color)
self.put_hline(pos.y - x, pos.x - y, pos.x + y, color)
}
if error < 0 {
error += 4 * @intcast(x) + 6
} else {
error += 4 * (@intcast(x) - @intcast(y)) + 10
y -= 1
}
x += 1
}
}
put_textured_circle := fn(self: Self, source: Self, source_pos: Vec2(uint), pos: Vec2(uint), radius: uint): void {
x := 0
y := radius
error := @as(int, 3) - 2 * @intcast(radius)
loop if x > y break else {
memory.copy(Color, source.indexptr(source_pos.x - x, source_pos.y + y), self.indexptr(pos.x - x, pos.y + y), 2 * x)
memory.copy(Color, source.indexptr(source_pos.x - x, source_pos.y - y), self.indexptr(pos.x - x, pos.y - y), 2 * x)
if x != y {
memory.copy(Color, source.indexptr(source_pos.x - y, source_pos.y + x), self.indexptr(pos.x - y, pos.y + x), 2 * y)
memory.copy(Color, source.indexptr(source_pos.x - y, source_pos.y - x), self.indexptr(pos.x - y, pos.y - x), 2 * y)
}
if error < 0 {
error += 4 * @intcast(x) + 6
} else {
error += 4 * (@intcast(x) - @intcast(y)) + 10
y -= 1
}
x += 1
}
}
put_text := fn(self: Self, font: Font, pos: Vec2(uint), color: Color, str: ^u8): void {
cursor := Vec2(uint).(pos.x, pos.y)
max_y := self.height - font.height
next_line_y := font.height + font.line_gap
char_advance := font.width + font.char_gap
self_width := self.width
loop if *str == 0 break else {
if cursor.y > max_y break
glyph_data := @as(^u8, idk)
code_point := @as(uint, 0)
if (*str & 0x80) == 0 {
if *str == 10 {
cursor.x = pos.x
cursor.y += next_line_y
str += 1
continue
}
if font.unicode == null {
if *str > font.num_glyphs {
str += 1
continue
}
glyph_data = get_glyph(font, *str)
} else {
if *str < UNC_TABLE_SIZE {
glyph_index := *(font.unicode + *str)
if glyph_index == 0xFFFF {
str += 1
continue
}
glyph_data = font.data + glyph_index * font.bytes_per_glyph
} else {
str += 1
continue
}
}
str += 1
} else if font.unicode != null {
first_byte := *str
num_bytes := @as(uint, 0)
num_bytes = utf8_len_table[first_byte >> 5 & 0x3]
if num_bytes == 0 {
str += 1
continue
}
code_point = first_byte & (0x7F >> num_bytes | 0x1F)
valid_sequence := true
bytes_processed := 1
loop if bytes_processed >= num_bytes break else {
str += 1
if *str == 0 | (*str & 0xC0) != 0x80 {
valid_sequence = false
}
if valid_sequence == false {
break
}
code_point = code_point << 6 | *str & 0x3F
bytes_processed += 1
}
if valid_sequence == false {
str += 1
continue
}
str += 1
if code_point == 10 {
cursor.x = pos.x
cursor.y += next_line_y
continue
}
if code_point >= UNC_TABLE_SIZE {
continue
}
glyph_index := *(font.unicode + code_point)
if glyph_index == 0xFFFF {
continue
}
glyph_data = font.data + glyph_index * font.bytes_per_glyph
}
if cursor.x + font.width >= self_width {
cursor.x = pos.x
cursor.y += next_line_y
}
dest := self.indexptr(cursor.x, cursor.y)
rows := font.height
loop if rows == 0 break else {
byte := *glyph_data
pixel_dest := dest
mask := @as(u8, 0x80)
bits := font.width
loop if bits == 0 break else {
if (byte & mask) != 0 {
*pixel_dest = color
}
pixel_dest += 1
mask >>= 1
if mask == 0 & bits > 0 {
glyph_data += 1
byte = *glyph_data
mask = 0x80
}
bits -= 1
}
if mask != 0x80 {
glyph_data += 1
}
dest += self_width
rows -= 1
}
cursor.x += char_advance
}
}
}

View file

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

View file

@ -0,0 +1,160 @@
.{log, memory} := @use("../../stn/src/lib.hb")
PSF1Header := packed struct {
magic: u16,
font_mode: u8,
character_size: u8,
}
PSF2Header := packed struct {
magic: u32,
version: u32,
header_size: u32,
flags: u32,
num_glyph: u32,
bytes_per_glyph: u32,
height: u32,
width: u32,
}
Font := struct {
data: ^u8,
width: uint,
height: uint,
num_glyphs: uint,
bytes_per_glyph: uint,
line_gap: uint,
char_gap: uint,
unicode: ?^u16,
}
font_from_psf1 := fn(psf: ^u8): ?Font {
header := @as(^PSF1Header, @bitcast(psf))
if header.magic != 0x436 {
log.error("failed to load psf font: not a psf1 font, idiot\0")
return null
}
psf += @sizeof(PSF1Header)
return .(
psf,
8,
header.character_size,
256,
header.character_size,
0,
0,
null,
)
}
font_from_psf2 := fn(psf: ^u8, unicode: bool): ?Font {
header := @as(^PSF2Header, @bitcast(psf))
if header.magic != 0x864AB572 {
log.error("failed to load psf font: not a psf2 font, idiot\0")
return null
}
psf += header.header_size
font := Font.(
psf,
header.width,
header.height,
header.num_glyph,
header.bytes_per_glyph,
0,
0,
null,
)
if (header.flags & 1) != 0 & unicode {
init_unicode(&font)
}
return font
}
$get_glyph := fn(font: Font, index: u8): ^u8 {
return font.data + @as(uint, index) * font.bytes_per_glyph
}
$UNC_TABLE_SIZE := 1 << 16
init_unicode := fn(font: ^Font): void {
font.unicode = memory.alloc(u16, UNC_TABLE_SIZE)
memory.set(u16, &0xFFFF, font.unicode, UNC_TABLE_SIZE)
table := font.data + font.num_glyphs * font.bytes_per_glyph
curr_glyph := @as(u16, 0)
loop if curr_glyph >= font.num_glyphs break else {
loop {
byte := *table
table += 1
if byte == 0xFF break
if byte == 0xFE {
continue
}
unicode := @as(uint, 0)
bytes_to_read := @as(uint, 1)
if (byte & 0x80) == 0 {
unicode = byte
} else if (byte & 0xE0) == 0xC0 {
unicode = byte & 0x1F
bytes_to_read = 2
} else if (byte & 0xF0) == 0xE0 {
unicode = byte & 0xF
bytes_to_read = 3
} else if (byte & 0xF8) == 0xF0 {
unicode = byte & 0x7
bytes_to_read = 4
} else {
continue
}
valid := true
loop if bytes_to_read <= 1 break else {
next_byte := *table
if (next_byte & 0xC0) != 0x80 {
valid = false
break
}
unicode = unicode << 6 | next_byte & 0x3F
table += 1
bytes_to_read -= 1
}
if valid == false continue
if bytes_to_read == 4 {
if unicode < 0x10000 | unicode > 0x10FFFF continue
if unicode <= 0xFFFF {
if unicode < UNC_TABLE_SIZE {
*(@unwrap(font.unicode) + unicode) = curr_glyph
}
} else {
unicode -= 0x10000
high_surrogate := 0xD800 | unicode >> 10 & 0x3FF
low_surrogate := 0xDC00 | unicode & 0x3FF
if high_surrogate < UNC_TABLE_SIZE {
*(@unwrap(font.unicode) + high_surrogate) = curr_glyph
}
if low_surrogate < UNC_TABLE_SIZE {
*(@unwrap(font.unicode) + low_surrogate) = curr_glyph
}
}
} else {
if unicode < UNC_TABLE_SIZE {
*(@unwrap(font.unicode) + unicode) = curr_glyph
}
}
}
curr_glyph += 1
}
}

View file

@ -0,0 +1,31 @@
//! This is a reserved file for use with the AbleOS Clustering System
HostID := int
ID := int
FileID := struct {
host_id: HostID,
id: ID,
}
// A DeviceID points to a specific device in the ACS.
DeviceID := struct {
host_id: HostID,
id: ID,
}
DiskID := DeviceID
BufferID := struct {
host_id: HostID,
id: ID,
}
ProcessID := struct {
host_id: HostID,
id: ID,
}
WindowID := struct {
host_id: HostID,
id: ID,
}

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