Compare commits
885 Commits
Author | SHA1 | Date |
---|---|---|
|
46a31b8efa | |
|
85a5e81224 | |
|
7d4cdcd1fd | |
|
d72db1f81c | |
|
6cfa56dcec | |
|
f97922a2b5 | |
|
566724d986 | |
|
a7b1810aa2 | |
|
a6a5c00763 | |
|
f2397b775c | |
|
8b81406b81 | |
|
e2515c1109 | |
|
5293ae070d | |
|
6e2443ca72 | |
|
a312d75bb2 | |
|
a554bd0fd8 | |
|
f0d2a211ea | |
|
065eec430e | |
|
5f4d81a502 | |
|
41065d2f9a | |
|
3daf3d53a3 | |
|
ec56e9c6f1 | |
|
07ae1bbf34 | |
|
03b80ed113 | |
|
407a7b80c5 | |
|
8b4f169d0f | |
|
6f9b3ab5de | |
|
aa7a8124ce | |
|
a9412aa741 | |
|
8aab3a62cc | |
|
b0b39c56ba | |
|
055b1a2a1a | |
|
d99ef11e48 | |
|
732eb9da41 | |
|
8faad47843 | |
|
aa4f3046ff | |
|
b4775fbe75 | |
|
8a5753b0fe | |
|
1a75262b04 | |
|
39801e51da | |
|
6e3f176457 | |
|
447da99f0b | |
|
a3a287f5ca | |
|
c47f6a78bc | |
|
430a006acf | |
|
845ed66e5e | |
|
2191ca46bb | |
|
cec04a2858 | |
|
b87351f6d5 | |
|
464737fbe9 | |
|
8b4f661acb | |
|
27963febc0 | |
|
6d4b684219 | |
|
670c787af3 | |
|
a0fbf18d3b | |
|
1acc0abf2e | |
|
c20f773c5d | |
|
a46b2f43d9 | |
|
a20f8607de | |
|
af330f7b8e | |
|
e33b3bcdff | |
|
181d139c7d | |
|
639fd8804c | |
|
cbb2c37e00 | |
|
ab4f033385 | |
|
1ed08f62d3 | |
|
8164c15b6c | |
|
f9bf47ab30 | |
|
e5ffadb109 | |
|
061d10e635 | |
|
6d899aa6ce | |
|
120f7329b1 | |
|
4f25c20c97 | |
|
5e396851f4 | |
|
a44482639d | |
|
3bac19e518 | |
|
4dbe15aa0e | |
|
1c5985148c | |
|
ce2461d0e8 | |
|
4e785a133c | |
|
26c7aee327 | |
|
0405461742 | |
|
8a10853ba7 | |
|
5d34cebeca | |
|
3d899d2e44 | |
|
f72fdeeb59 | |
|
382f9d9bb3 | |
|
bc1d1bf919 | |
|
f05b9a6877 | |
|
ea5ed3001e | |
|
f312c3a4d7 | |
|
1af3ca19ab | |
|
09fcc613c7 | |
|
3940f53231 | |
|
0757834176 | |
|
3bffbe330d | |
|
8d583c8b67 | |
|
99bde9aa49 | |
|
98d702ac60 | |
|
1ec341e2dd | |
|
d09310f388 | |
|
126edea119 | |
|
74bfb930f2 | |
|
091c5b6a66 | |
|
fda4a4ad24 | |
|
8bb47aee02 | |
|
1f794e4ac0 | |
|
e85f9ac6a1 | |
|
6ee5576dcc | |
|
b890e2fc14 | |
|
4f4b8ada8c | |
|
9e4adc1264 | |
|
7a54a088b4 | |
|
15bb1804ef | |
|
e8890062d6 | |
|
1e2c2fb973 | |
|
988a4e1cd8 | |
|
adbbdf73c4 | |
|
e8d20bc653 | |
|
00ee86920a | |
|
51ad27ea3c | |
|
df69612bb1 | |
|
5bfeb9f3ca | |
|
db5c24b2a5 | |
|
781c950af6 | |
|
e2e5c31d54 | |
|
be3efb0b92 | |
|
792bb2df1c | |
|
e01928d186 | |
|
48980b56ab | |
|
b767317a7a | |
|
6f8fce94a0 | |
|
31aa157201 | |
|
5977341610 | |
|
76f17bd569 | |
|
6b1b3d333c | |
|
cb65be3e33 | |
|
dafc016293 | |
|
c7b6fc950a | |
|
45a6783c3d | |
|
6b180da4e8 | |
|
cf4f5f64a5 | |
|
5630f64175 | |
|
1d61bccfc3 | |
|
f842a9255f | |
|
72f3c378dd | |
|
39be6ab099 | |
|
773dcdd3a2 | |
|
f0820e6f24 | |
|
a2b5e71654 | |
|
d3e5c8e0aa | |
|
f4b901a646 | |
|
790064d248 | |
|
ab8b77406d | |
|
1b9e14a53b | |
|
d2cfc843e4 | |
|
521513bed2 | |
|
400db176d1 | |
|
211cad03ff | |
|
8a9816d6e0 | |
|
03d2bf4002 | |
|
f071240b33 | |
|
27364f64a6 | |
|
bcf62c5f2e | |
|
4d6322ff9c | |
|
2eef581737 | |
|
7ce8e2d57b | |
|
e780eaa45f | |
|
44cb0af64f | |
|
bb0989fdef | |
|
f0b6844feb | |
|
b712c70c75 | |
|
797ca65c66 | |
|
762b7a4276 | |
|
a511441f7e | |
|
cd61d710df | |
|
f88ad7efcd | |
|
38320018dc | |
|
d883d212b1 | |
|
dedb2a2399 | |
|
8604c55de8 | |
|
e949e8550c | |
|
eb5c6cf736 | |
|
94ce2c97be | |
|
3f164c6b82 | |
|
f953f3d3ff | |
|
9fc75fe445 | |
|
7a5bb6a56b | |
|
d54c6b7f6b | |
|
db5d6a7f80 | |
|
4a92f44cf6 | |
|
376b9f7272 | |
|
7e9e4c47ae | |
|
603fc200e6 | |
|
c11e84b248 | |
|
be13120554 | |
|
9943edad5a | |
|
f4049be975 | |
|
6cf7e01fe9 | |
|
b51d2f5295 | |
|
49d941ad65 | |
|
a66c3bdae5 | |
|
547eabb403 | |
|
79851394b3 | |
|
fcdc922343 | |
|
0b11d76576 | |
|
f7097398ca | |
|
85b1252b9e | |
|
1cd12b5f16 | |
|
c84b66d078 | |
|
27adb9486b | |
|
8d5369fafe | |
|
feafc57b63 | |
|
f9b347f9d9 | |
|
6e1825d6b4 | |
|
ec2baeb276 | |
|
6cb8bda6e1 | |
|
05e57801e7 | |
|
b924c85669 | |
|
09c1aa44d8 | |
|
1d470fb5ba | |
|
b4e4f7a6cc | |
|
55d30a7cc3 | |
|
b62186441b | |
|
8caba1e774 | |
|
7bdb428938 | |
|
3ea707c0e7 | |
|
18d582c6ce | |
|
8b2bb95b81 | |
|
2ef496a24a | |
|
c0a89e8951 | |
|
fc953df281 | |
|
fe2dca16f0 | |
|
f662aa6da2 | |
|
fee3677fb9 | |
|
4818c6e3dd | |
|
971eb737c1 | |
|
9a3286ad57 | |
|
c9e09b840e | |
|
8136248a67 | |
|
0d67e46041 | |
|
bc1087f5a7 | |
|
3a9c6fc51a | |
|
7774f56ab6 | |
|
14a608effd | |
|
5fae3cec2a | |
|
b0c22b61ec | |
|
82b049204d | |
|
aa59142bfa | |
|
c55bb77ff5 | |
|
9b4e2e1e21 | |
|
202c38a65a | |
|
720bc418a6 | |
|
d77f455065 | |
|
7e08f0fb66 | |
|
9e4a87021c | |
|
5887f6bcaa | |
|
5d67559e33 | |
|
e631eb7a7a | |
|
64ff4c232a | |
|
0ec4f970f7 | |
|
afe95be42f | |
|
14ac1c9904 | |
|
7c11ea3694 | |
|
c1fd341698 | |
|
0deab1be51 | |
|
5a623adaa6 | |
|
4363118d9d | |
|
d613da4b6c | |
|
f46f5b2050 | |
|
d9c4114b5f | |
|
ddd36af0f1 | |
|
35fd30ee29 | |
|
4a0652684c | |
|
33c81f00b7 | |
|
55714b90cd | |
|
9b47603a1d | |
|
2e2a913412 | |
|
42b85dc33b | |
|
a15ffcb071 | |
|
692b77fb8e | |
|
044378cfa3 | |
|
f1d4d5f995 | |
|
19d0fb6fcd | |
|
7933265095 | |
|
d810644018 | |
|
a7bfc1c2ec | |
|
104b2740bc | |
|
65501837b7 | |
|
3ed0a54847 | |
|
cbd2519b9a | |
|
e8a73f9696 | |
|
1a0d114861 | |
|
5c3497681e | |
|
b05cf9ef09 | |
|
a74eb357a1 | |
|
8eb71084f0 | |
|
ef1077fd7b | |
|
f1ba5c7e0f | |
|
97ea4986af | |
|
25c021c15b | |
|
2bf12a52d1 | |
|
6ada36d3cb | |
|
42b90ae76c | |
|
ccc61cb10c | |
|
be5b81740e | |
|
e7458ca10a | |
|
b10168eb1c | |
|
30463c9082 | |
|
dc7391dc89 | |
|
eb98d70a0b | |
|
dcd8374b89 | |
|
8e4216215e | |
|
5bd7099b96 | |
|
9a63d3b2da | |
|
bf02330db9 | |
|
5806a6484f | |
|
0fa5401800 | |
|
b30f4cbfb5 | |
|
ba37183c9c | |
|
2f298a1979 | |
|
8c282a5d83 | |
|
d34c0a5abe | |
|
8f3348cf2b | |
|
38c0bc7bae | |
|
313b00b11f | |
|
165a379c73 | |
|
a7f37236bf | |
|
51532336b0 | |
|
03d4b47f63 | |
|
8b57edde6b | |
|
778778fede | |
|
f7449c4ab9 | |
|
fd2bcc9156 | |
|
a5b1555725 | |
|
e74fdbc55b | |
|
008c777a9f | |
|
d8a9d4a24e | |
|
bc0e1fa898 | |
|
17f1737c9a | |
|
868444f043 | |
|
fdae253695 | |
|
d4adcff958 | |
|
2c59c9a3cc | |
|
3a59a64355 | |
|
9363c1cdaf | |
|
198e6d7cf6 | |
|
07ee898f4f | |
|
6feb8a99d2 | |
|
e57c1fc9fc | |
|
a11b5ae41f | |
|
c67a7cec5b | |
|
91f04ce250 | |
|
926df2b276 | |
|
9fe878bbec | |
|
217dbca7b7 | |
|
13852e865c | |
|
679d47131d | |
|
8b1bccb79b | |
|
e86e755c51 | |
|
8ec6d4c9fc | |
|
08cdf88586 | |
|
6f7d97cf94 | |
|
5e434f5131 | |
|
a152d0aac5 | |
|
879706e6e9 | |
|
00f1f30a08 | |
|
a5813f9ba5 | |
|
5652af3384 | |
|
22cd9af8cc | |
|
a9cf9bceef | |
|
6c0f864a6e | |
|
e4509d9482 | |
|
0f23e1f0f4 | |
|
642a6aa4ad | |
|
432c296b7b | |
|
b576d373c4 | |
|
522aa8e762 | |
|
146802fa4c | |
|
cc8af25d73 | |
|
f5f4bf58ad | |
|
3784da0d18 | |
|
9eb72f4392 | |
|
f7bf6d5e62 | |
|
adb14ba373 | |
|
7391d91317 | |
|
2149cec29f | |
|
ad756c36fc | |
|
b56316e9da | |
|
a989c44211 | |
|
217e5f81cc | |
|
5f2549b198 | |
|
dcd4d0daeb | |
|
faf4220b38 | |
|
193ddaa2f6 | |
|
46eb27883a | |
|
2db7cdb71e | |
|
5411c5aa4a | |
|
f8a1a10897 | |
|
adbe13938e | |
|
4d5b14753d | |
|
ba9fa00947 | |
|
98cedf155c | |
|
88e3998664 | |
|
c0c0bbc1bf | |
|
650e1b4fc5 | |
|
6c1ada8d0a | |
|
7d00c2670f | |
|
bca7e9a1e8 | |
|
3748f0304f | |
|
2576bdbd14 | |
|
e341a36287 | |
|
bba09a3cd0 | |
|
985df3532b | |
|
72041a52e8 | |
|
891144dac1 | |
|
41e7b53903 | |
|
6b0920e8c0 | |
|
4285729d5c | |
|
a9c10d0751 | |
|
74c79c7eff | |
|
9174a89971 | |
|
5c94a583bc | |
|
6e1fc2766f | |
|
d3bb00cb55 | |
|
5a5656b2d3 | |
|
1a1e584cba | |
|
65fa05f998 | |
|
2276fc95b8 | |
|
1e173c178d | |
|
773747cf9c | |
|
4972284dde | |
|
45789fda08 | |
|
3b5bc63d1b | |
|
f1089e2b8a | |
|
6d93c1eb92 | |
|
363c325c79 | |
|
583504ebe0 | |
|
b354b77f8b | |
|
74af46cb4a | |
|
19dab08275 | |
|
3840fbf957 | |
|
78c091f7f8 | |
|
274ecbba78 | |
|
683c2a68cd | |
|
ad98181069 | |
|
a549336530 | |
|
4eb95c963d | |
|
22caacd2a9 | |
|
af30d537da | |
|
f1bd26fb92 | |
|
5c6bbcb62f | |
|
21bd87bb07 | |
|
79450df04c | |
|
7f8b7b811e | |
|
3c068aa0ae | |
|
86df258365 | |
|
d99e704728 | |
|
0d620f3e0f | |
|
4dce0f9074 | |
|
54f89cba33 | |
|
de88f60d1a | |
|
f7060970e6 | |
|
e7a98ac6cc | |
|
10544db52e | |
|
5e123031aa | |
|
388f530edd | |
|
d354cccd37 | |
|
714305ef56 | |
|
f83ae1e9c6 | |
|
c38e8de6b5 | |
|
97638f7ade | |
|
326a30d1af | |
|
32e1473c94 | |
|
bf617036c7 | |
|
ce55422a24 | |
|
388cc7c3bb | |
|
37f9404d93 | |
|
38dff41e25 | |
|
d360340b9e | |
|
0f63cfa43f | |
|
537780ee1e | |
|
4ca99fcb4e | |
|
eb7ee13f43 | |
|
b2de706693 | |
|
6a8180470d | |
|
12d56be5cc | |
|
bb4d81a4fa | |
|
b254ade69b | |
|
ef4ebaa969 | |
|
99f8133b91 | |
|
51eb44bf40 | |
|
a0be415e09 | |
|
071da18fa3 | |
|
c62e820bcf | |
|
46c34db6cb | |
|
25a2a4879c | |
|
8be28012ee | |
|
5aed186827 | |
|
91f812e17f | |
|
f0b22c48b2 | |
|
52c4eebd77 | |
|
24f0d26fce | |
|
825ec221b7 | |
|
e31080bce3 | |
|
7a5d5cabad | |
|
f7de310889 | |
|
e209ca7c82 | |
|
ee8de77a90 | |
|
db49cbd6e2 | |
|
e001eecb7b | |
|
7f34d00c95 | |
|
2c18adbddd | |
|
97c7fc42d1 | |
|
7da0627f8e | |
|
27cef23823 | |
|
b7fc2dc3d0 | |
|
8af390e0f6 | |
|
96d6453ea8 | |
|
2b9900e56e | |
|
86f58f60cb | |
|
064ce568c2 | |
|
6aff459e1c | |
|
0b1b4d8f7e | |
|
3fc2c3529a | |
|
b0e9ab0519 | |
|
668517a723 | |
|
649f08ec78 | |
|
2f2c298c68 | |
|
90e48970e6 | |
|
480842a203 | |
|
5425394880 | |
|
a365813fa9 | |
|
9d64dbd5c2 | |
|
30bb61a775 | |
|
1f36ed0cf9 | |
|
d54c76f88a | |
|
cbb9f47ee5 | |
|
b68d5a5833 | |
|
94d2090777 | |
|
e97585daf9 | |
|
924fc2118c | |
|
51f4c0c750 | |
|
37b93da650 | |
|
35e739dcdd | |
|
8352392b38 | |
|
413f05bfca | |
|
dc1aff58ed | |
|
9f75d9cfe5 | |
|
a42af7e973 | |
|
2ce244d303 | |
|
a775a920d0 | |
|
4f84faf392 | |
|
a4cb5d8360 | |
|
da7f09cf82 | |
|
0166af472b | |
|
884d986bd6 | |
|
59b807189f | |
|
fb1c7015b1 | |
|
d4123f62b2 | |
|
a3f410d1a1 | |
|
1d19a4bffe | |
|
271dd91292 | |
|
9bd4d68f9c | |
|
3c3c7826ef | |
|
2207357b93 | |
|
3a69768eb0 | |
|
afb29ff3ec | |
|
e6f0f891a6 | |
|
36e5aa4683 | |
|
7738050105 | |
|
4bf11ec349 | |
|
d821012eed | |
|
35c6edd989 | |
|
633cb4f282 | |
|
4d4d0e26a9 | |
|
feea2d4024 | |
|
0ffd2a5c1d | |
|
232fdcb82c | |
|
0ccc23d544 | |
|
789ca3db1a | |
|
cb359a05dc | |
|
14982c137a | |
|
0acab11620 | |
|
02f0239016 | |
|
ab61b49aca | |
|
4da1d6fd27 | |
|
909e847369 | |
|
eafa09fecf | |
|
8175348284 | |
|
b2832cb47a | |
|
9f499991c8 | |
|
9a416e8ae8 | |
|
911922c6a3 | |
|
1f2fd59ad5 | |
|
708d401d2c | |
|
ed0dcacab3 | |
|
e86050f343 | |
|
57f7da6ce1 | |
|
93e6455171 | |
|
8f38780197 | |
|
341f7e41e5 | |
|
265fe9c62e | |
|
3b9d60d7cb | |
|
278b873e89 | |
|
e640344d7a | |
|
7151bb86a8 | |
|
2a34391b71 | |
|
3d95cf02f3 | |
|
dd3f34cb2c | |
|
0c316ebfb2 | |
|
282bf24f65 | |
|
f964f6be8d | |
|
0202ccec5f | |
|
636c308993 | |
|
6fdbe6f9c2 | |
|
c19f4c019a | |
|
83eb3dc0cb | |
|
481c8406f3 | |
|
0129619d9a | |
|
e0479b291d | |
|
b847d7dfd5 | |
|
245dff8027 | |
|
fed690a7f2 | |
|
54d981120d | |
|
f79250c4d4 | |
|
78b62776d2 | |
|
bda4614783 | |
|
0ab3332ad3 | |
|
9e0abbc2f0 | |
|
496adb61a4 | |
|
4a4a3bf184 | |
|
f33e78882e | |
|
0ff067bdb7 | |
|
31ac3260ed | |
|
d82c6c2337 | |
|
632b699475 | |
|
85039020d3 | |
|
1a0fdc5a44 | |
|
fb1bab7c30 | |
|
7eb43990ad | |
|
53f4b5a9da | |
|
1d4a6c3a42 | |
|
40083e4aa1 | |
|
bd929bff07 | |
|
cd4a0530fa | |
|
273fdd2235 | |
|
b20f2e8d31 | |
|
e756cde2b1 | |
|
de18d3e64d | |
|
441999ba9f | |
|
dd046b1ace | |
|
926aa238ab | |
|
01fa521a03 | |
|
f31da19266 | |
|
48edc38817 | |
|
ac12132ac0 | |
|
13fabcc1f1 | |
|
67005a80be | |
|
f43bfcb398 | |
|
d5ce4c9d2c | |
|
1cf7ef3de6 | |
|
5248a3fe48 | |
|
812e61ca70 | |
|
2d0a5a9e15 | |
|
f32d594879 | |
|
c2ad76fe4f | |
|
10d9b72da1 | |
|
2fe9af7165 | |
|
0deda83d05 | |
|
ff5bcd4416 | |
|
b65cd1d09b | |
|
bc35a561d3 | |
|
06bc807e34 | |
|
6262e41de1 | |
|
0cb53efa01 | |
|
4e859bedbc | |
|
f139fc2229 | |
|
e48acbb03b | |
|
d1155c968e | |
|
88a2c60065 | |
|
5bfcf6783e | |
|
94f8a657f1 | |
|
7fac2a7526 | |
|
46dcf98fc1 | |
|
58ce907327 | |
|
6ecc8cac0e | |
|
bd95f17426 | |
|
0718bea5a1 | |
|
175f07cd2f | |
|
7b19d6e479 | |
|
77c83e5552 | |
|
b15deb420f | |
|
b38989d594 | |
|
79e6de325f | |
|
163d2e4ba8 | |
|
4f8f3ddc29 | |
|
82a1a29260 | |
|
8a5608df91 | |
|
3f1c0ec91b | |
|
1406a75a92 | |
|
8001493df3 | |
|
8c1f5bfe1e | |
|
ec8b9640e2 | |
|
4ae1332a43 | |
|
10c884bba4 | |
|
c15f031c3f | |
|
1b4c744974 | |
|
d9068eebb5 | |
|
3ad0d2328d | |
|
3f2beb4547 | |
|
be14a6c239 | |
|
3aa0eeb4a3 | |
|
b3eeb6412f | |
|
d38470c8e2 | |
|
a159c980ee | |
|
a993d997ad | |
|
4475e3e184 | |
|
cf0320e47d | |
|
cd03a95128 | |
|
51e299c7e3 | |
|
6f65453fd4 | |
|
67e0c21e0f | |
|
702016a6e3 | |
|
d74ce4950c | |
|
59a682c720 | |
|
7bd4593748 | |
|
c5b006bf19 | |
|
115c44630d | |
|
1dc81abca4 | |
|
5aaf2128a8 | |
|
6aeac17072 | |
|
6d425182a2 | |
|
04ac23b67c | |
|
5494e2c125 | |
|
aba82564f5 | |
|
93abee9c7c | |
|
4034bef42e | |
|
821d065eba | |
|
2614437ba0 | |
|
1aac3a0425 | |
|
a4568f9263 | |
|
a180e72b6f | |
|
2de64b592d | |
|
9c0f3dd996 | |
|
079df39ca8 | |
|
60a99d1d23 | |
|
fe87c08a02 | |
|
8637959289 | |
|
6be53668b9 | |
|
d1b7249803 | |
|
ff7c50c627 | |
|
12779cdef8 | |
|
f5e676b2b7 | |
|
8e5e5f819f | |
|
370a958379 | |
|
0ee7da92a3 | |
|
a0bd3dc54f | |
|
809eb2fe3e | |
|
7010d8614f | |
|
69f13f1896 | |
|
bdaf7cddcb | |
|
8d6db168d6 | |
|
2fabe1949c | |
|
c660df14ec | |
|
e704968f96 | |
|
32359df939 | |
|
641ed23380 | |
|
9f977488fa | |
|
ac0b22f9b9 | |
|
7752b02fb7 | |
|
7610670287 | |
|
31a1b23fb7 | |
|
91c8f9a596 | |
|
f70cd3ea77 | |
|
5db5ff069a | |
|
b8d852ddb7 | |
|
46eedbd1a4 | |
|
e760bafeeb | |
|
12351d5cb6 | |
|
e84f613c4d | |
|
5db4e5b4d5 | |
|
b00dd8d68d | |
|
abbbf7ec15 | |
|
22c72d8c70 | |
|
d0b1457f30 | |
|
a423cd8bb3 | |
|
db076058b9 | |
|
fe10ea85db | |
|
a1100624bf | |
|
28e1497f88 | |
|
8d6111641e | |
|
3ee20d1a84 | |
|
002c2d0aca | |
|
de9f109f2a | |
|
461a5774f8 | |
|
914f718767 | |
|
ebfd092075 | |
|
e322826347 | |
|
3998c5f955 | |
|
762d22ed28 | |
|
f2362b2b78 | |
|
471ac80420 | |
|
4a887fc706 | |
|
e49d3c7bfe | |
|
c5b83074ac | |
|
79090c2648 | |
|
7a6b1c8e47 | |
|
8988ce2766 | |
|
dcde2ae6b4 | |
|
c62849a783 | |
|
f453e8e170 | |
|
990887891e | |
|
5da801d12b | |
|
3a4557d417 | |
|
26d9a3e253 | |
|
eef3631a5a | |
|
88ee35165f | |
|
c8f05b4a7a | |
|
c32584cca0 | |
|
2995a36942 | |
|
c1dbafc101 | |
|
3e8ab8271d | |
|
5b3a00c64f | |
|
0ce9fd8597 | |
|
c9badb5a1c | |
|
a513bc5749 | |
|
5d5487315f | |
|
3508df67b1 | |
|
06ce1f0667 | |
|
f9c3ae7090 | |
|
1fb8c211f0 | |
|
9c7670847e | |
|
a24c2d9be2 | |
|
f4db246658 | |
|
7f90079ea7 | |
|
f4b4987d43 | |
|
7f88ba70d4 | |
|
ac094a48d6 | |
|
779912d8af | |
|
f205b8e883 | |
|
f9a0412e78 | |
|
0ef318633c | |
|
2f8c9746e3 | |
|
6d6bef1b04 | |
|
3dab392296 | |
|
f8a2c60c8d | |
|
770f7716a0 | |
|
a011c0384f | |
|
0d356c5bbc | |
|
d67de70126 | |
|
6f334756c5 | |
|
310713d203 | |
|
7d2ab53baa | |
|
2152b8b95f | |
|
8ac1ae1574 | |
|
4fd21bc303 | |
|
15037bfc7a | |
|
5831c72aad | |
|
a063d041c9 | |
|
3572e9794a | |
|
cef6999dc7 | |
|
6ed9651176 | |
|
3efbe22a1b | |
|
96579b88cf | |
|
2ec18855f2 | |
|
b222581d18 | |
|
a8e3ee6f19 | |
|
a083e588ba | |
|
9b500842a0 | |
|
b21348379f | |
|
633055293e | |
|
ae9d618803 | |
|
9c744dfc44 | |
|
faf1b661bb | |
|
22e45278a2 | |
|
43f4657566 | |
|
70f2908056 | |
|
ef381d0600 | |
|
cfa87526a7 | |
|
39b560fde3 | |
|
0c582b4490 | |
|
61caf566fc | |
|
76d5364a55 | |
|
5224df321e |
|
@ -0,0 +1,4 @@
|
|||
[submodule "kernel/lai"]
|
||||
path = kernel/lai
|
||||
url = https://github.com/managarm/lai.git
|
||||
ignore = untracked
|
|
@ -1,8 +0,0 @@
|
|||
# .pre-commit-config.yaml
|
||||
exclude: '.patch$'
|
||||
repos:
|
||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||
rev: v4.1.0 # this is optional, use `pre-commit autoupdate` to get the latest rev!
|
||||
hooks:
|
||||
- id: end-of-file-fixer
|
||||
- id: trailing-whitespace
|
|
@ -1,36 +0,0 @@
|
|||
{
|
||||
"configurations": [
|
||||
{
|
||||
"name": "banan-os",
|
||||
"includePath": [
|
||||
"${workspaceFolder}/BAN/include",
|
||||
"${workspaceFolder}/kernel/include",
|
||||
"${workspaceFolder}/userspace/libraries/*/include"
|
||||
],
|
||||
"defines": [
|
||||
"__arch=x86_64"
|
||||
],
|
||||
"compilerPath": "${workspaceFolder}/toolchain/local/bin/x86_64-banan_os-gcc",
|
||||
"cStandard": "c17",
|
||||
"cppStandard": "gnu++20",
|
||||
"intelliSenseMode": "linux-gcc-x64"
|
||||
},
|
||||
{
|
||||
"name": "banan-os-kernel",
|
||||
"includePath": [
|
||||
"${workspaceFolder}/BAN/include",
|
||||
"${workspaceFolder}/kernel/include",
|
||||
"${workspaceFolder}/userspace/libraries/*/include"
|
||||
],
|
||||
"defines": [
|
||||
"__arch=x86_64",
|
||||
"__is_kernel"
|
||||
],
|
||||
"compilerPath": "${workspaceFolder}/toolchain/local/bin/x86_64-banan_os-gcc",
|
||||
"cStandard": "c17",
|
||||
"cppStandard": "gnu++20",
|
||||
"intelliSenseMode": "linux-gcc-x64"
|
||||
}
|
||||
],
|
||||
"version": 4
|
||||
}
|
|
@ -1,6 +0,0 @@
|
|||
{
|
||||
"cmake.configureOnOpen": false,
|
||||
"editor.tabSize": 4,
|
||||
"editor.insertSpaces": false,
|
||||
"editor.detectIndentation": false
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
*.a
|
||||
*.d
|
||||
*.o
|
|
@ -1,22 +0,0 @@
|
|||
#include <BAN/Assert.h>
|
||||
|
||||
#if __is_kernel
|
||||
|
||||
#include <kernel/Panic.h>
|
||||
|
||||
[[noreturn]] void __ban_assertion_failed(const char* location, const char* msg)
|
||||
{
|
||||
Kernel::panic_impl(location, msg);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#include <BAN/Debug.h>
|
||||
|
||||
[[noreturn]] void __ban_assertion_failed(const char* location, const char* msg)
|
||||
{
|
||||
derrorln("{}: {}", location, msg);
|
||||
__builtin_trap();
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,269 @@
|
|||
#include <BAN/String.h>
|
||||
#include <BAN/New.h>
|
||||
|
||||
namespace BAN
|
||||
{
|
||||
|
||||
String::String()
|
||||
{
|
||||
}
|
||||
|
||||
String::String(const String& other)
|
||||
{
|
||||
*this = other;
|
||||
}
|
||||
|
||||
String::String(String&& other)
|
||||
{
|
||||
*this = move(other);
|
||||
}
|
||||
|
||||
String::String(StringView other)
|
||||
{
|
||||
*this = other;
|
||||
}
|
||||
|
||||
String::~String()
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
String& String::operator=(const String& other)
|
||||
{
|
||||
clear();
|
||||
MUST(ensure_capacity(other.size()));
|
||||
memcpy(data(), other.data(), other.size() + 1);
|
||||
m_size = other.size();
|
||||
return *this;
|
||||
}
|
||||
|
||||
String& String::operator=(String&& other)
|
||||
{
|
||||
clear();
|
||||
|
||||
if (other.has_sso())
|
||||
memcpy(data(), other.data(), other.size() + 1);
|
||||
else
|
||||
{
|
||||
m_storage.general_storage = other.m_storage.general_storage;
|
||||
m_has_sso = false;
|
||||
}
|
||||
m_size = other.m_size;
|
||||
|
||||
other.m_size = 0;
|
||||
other.m_storage.sso_storage = SSOStorage();
|
||||
other.m_has_sso = true;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
String& String::operator=(StringView other)
|
||||
{
|
||||
clear();
|
||||
MUST(ensure_capacity(other.size()));
|
||||
memcpy(data(), other.data(), other.size());
|
||||
m_size = other.size();
|
||||
data()[m_size] = '\0';
|
||||
return *this;
|
||||
}
|
||||
|
||||
ErrorOr<void> String::push_back(char c)
|
||||
{
|
||||
TRY(ensure_capacity(m_size + 1));
|
||||
data()[m_size] = c;
|
||||
m_size++;
|
||||
data()[m_size] = '\0';
|
||||
return {};
|
||||
}
|
||||
|
||||
ErrorOr<void> String::insert(char c, size_type index)
|
||||
{
|
||||
ASSERT(index <= m_size);
|
||||
TRY(ensure_capacity(m_size + 1));
|
||||
memmove(data() + index + 1, data() + index, m_size - index);
|
||||
data()[index] = c;
|
||||
m_size++;
|
||||
data()[m_size] = '\0';
|
||||
return {};
|
||||
}
|
||||
|
||||
ErrorOr<void> String::insert(StringView str, size_type index)
|
||||
{
|
||||
ASSERT(index <= m_size);
|
||||
TRY(ensure_capacity(m_size + str.size()));
|
||||
memmove(data() + index + str.size(), data() + index, m_size - index);
|
||||
memcpy(data() + index, str.data(), str.size());
|
||||
m_size += str.size();
|
||||
data()[m_size] = '\0';
|
||||
return {};
|
||||
}
|
||||
|
||||
ErrorOr<void> String::append(StringView str)
|
||||
{
|
||||
TRY(ensure_capacity(m_size + str.size()));
|
||||
memcpy(data() + m_size, str.data(), str.size());
|
||||
m_size += str.size();
|
||||
data()[m_size] = '\0';
|
||||
return {};
|
||||
}
|
||||
|
||||
void String::pop_back()
|
||||
{
|
||||
ASSERT(m_size > 0);
|
||||
m_size--;
|
||||
data()[m_size] = '\0';
|
||||
}
|
||||
|
||||
void String::remove(size_type index)
|
||||
{
|
||||
ASSERT(index < m_size);
|
||||
memcpy(data() + index, data() + index + 1, m_size - index);
|
||||
m_size--;
|
||||
data()[m_size] = '\0';
|
||||
}
|
||||
|
||||
void String::clear()
|
||||
{
|
||||
if (!has_sso())
|
||||
{
|
||||
deallocator(m_storage.general_storage.data);
|
||||
m_storage.sso_storage = SSOStorage();
|
||||
m_has_sso = true;
|
||||
}
|
||||
m_size = 0;
|
||||
data()[m_size] = '\0';
|
||||
}
|
||||
|
||||
bool String::operator==(StringView str) const
|
||||
{
|
||||
if (size() != str.size())
|
||||
return false;
|
||||
for (size_type i = 0; i < m_size; i++)
|
||||
if (data()[i] != str.data()[i])
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool String::operator==(const char* cstr) const
|
||||
{
|
||||
for (size_type i = 0; i < m_size; i++)
|
||||
if (data()[i] != cstr[i])
|
||||
return false;
|
||||
if (cstr[size()] != '\0')
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
ErrorOr<void> String::resize(size_type new_size, char init_c)
|
||||
{
|
||||
if (m_size == new_size)
|
||||
return {};
|
||||
|
||||
// expanding
|
||||
if (m_size < new_size)
|
||||
{
|
||||
TRY(ensure_capacity(new_size));
|
||||
memset(data() + m_size, init_c, new_size - m_size);
|
||||
m_size = new_size;
|
||||
data()[m_size] = '\0';
|
||||
return {};
|
||||
}
|
||||
|
||||
m_size = new_size;
|
||||
data()[m_size] = '\0';
|
||||
return {};
|
||||
}
|
||||
|
||||
ErrorOr<void> String::reserve(size_type new_size)
|
||||
{
|
||||
TRY(ensure_capacity(new_size));
|
||||
return {};
|
||||
}
|
||||
|
||||
ErrorOr<void> String::shrink_to_fit()
|
||||
{
|
||||
if (has_sso())
|
||||
return {};
|
||||
|
||||
if (fits_in_sso())
|
||||
{
|
||||
char* data = m_storage.general_storage.data;
|
||||
m_storage.sso_storage = SSOStorage();
|
||||
m_has_sso = true;
|
||||
memcpy(this->data(), data, m_size + 1);
|
||||
deallocator(data);
|
||||
return {};
|
||||
}
|
||||
|
||||
GeneralStorage& storage = m_storage.general_storage;
|
||||
if (storage.capacity == m_size)
|
||||
return {};
|
||||
|
||||
char* new_data = (char*)allocator(m_size + 1);
|
||||
if (new_data == nullptr)
|
||||
return Error::from_errno(ENOMEM);
|
||||
|
||||
memcpy(new_data, storage.data, m_size);
|
||||
deallocator(storage.data);
|
||||
|
||||
storage.capacity = m_size;
|
||||
storage.data = new_data;
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
String::size_type String::capacity() const
|
||||
{
|
||||
if (has_sso())
|
||||
return sso_capacity;
|
||||
return m_storage.general_storage.capacity;
|
||||
}
|
||||
|
||||
char* String::data()
|
||||
{
|
||||
if (has_sso())
|
||||
return m_storage.sso_storage.data;
|
||||
return m_storage.general_storage.data;
|
||||
}
|
||||
|
||||
const char* String::data() const
|
||||
{
|
||||
if (has_sso())
|
||||
return m_storage.sso_storage.data;
|
||||
return m_storage.general_storage.data;
|
||||
}
|
||||
|
||||
ErrorOr<void> String::ensure_capacity(size_type new_size)
|
||||
{
|
||||
if (m_size >= new_size)
|
||||
return {};
|
||||
if (has_sso() && fits_in_sso(new_size))
|
||||
return {};
|
||||
|
||||
char* new_data = (char*)allocator(new_size + 1);
|
||||
if (new_data == nullptr)
|
||||
return Error::from_errno(ENOMEM);
|
||||
|
||||
memcpy(new_data, data(), m_size + 1);
|
||||
|
||||
if (has_sso())
|
||||
{
|
||||
m_storage.general_storage = GeneralStorage();
|
||||
m_has_sso = false;
|
||||
}
|
||||
else
|
||||
deallocator(m_storage.general_storage.data);
|
||||
|
||||
auto& storage = m_storage.general_storage;
|
||||
storage.capacity = new_size;
|
||||
storage.data = new_data;
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
bool String::has_sso() const
|
||||
{
|
||||
return m_has_sso;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,11 +1,180 @@
|
|||
#include <BAN/String.h>
|
||||
#include <BAN/StringView.h>
|
||||
#include <BAN/Vector.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
namespace BAN
|
||||
{
|
||||
|
||||
StringView::StringView()
|
||||
{ }
|
||||
|
||||
StringView::StringView(const String& other)
|
||||
: StringView(other.data(), other.size())
|
||||
{ }
|
||||
|
||||
}
|
||||
StringView::StringView(const char* string, size_type len)
|
||||
{
|
||||
if (len == size_type(-1))
|
||||
len = strlen(string);
|
||||
m_data = string;
|
||||
m_size = len;
|
||||
}
|
||||
|
||||
char StringView::operator[](size_type index) const
|
||||
{
|
||||
ASSERT(index < m_size);
|
||||
return m_data[index];
|
||||
}
|
||||
|
||||
bool StringView::operator==(const String& other) const
|
||||
{
|
||||
if (m_size != other.size())
|
||||
return false;
|
||||
return memcmp(m_data, other.data(), m_size) == 0;
|
||||
}
|
||||
|
||||
bool StringView::operator==(StringView other) const
|
||||
{
|
||||
if (m_size != other.m_size)
|
||||
return false;
|
||||
return memcmp(m_data, other.m_data, m_size) == 0;
|
||||
}
|
||||
|
||||
bool StringView::operator==(const char* other) const
|
||||
{
|
||||
if (memcmp(m_data, other, m_size))
|
||||
return false;
|
||||
return other[m_size] == '\0';
|
||||
}
|
||||
|
||||
StringView StringView::substring(size_type index, size_type len) const
|
||||
{
|
||||
ASSERT(index <= m_size);
|
||||
if (len == size_type(-1))
|
||||
len = m_size - index;
|
||||
ASSERT(len <= m_size - index); // weird order to avoid overflow
|
||||
StringView result;
|
||||
result.m_data = m_data + index;
|
||||
result.m_size = len;
|
||||
return result;
|
||||
}
|
||||
|
||||
ErrorOr<Vector<StringView>> StringView::split(char delim, bool allow_empties)
|
||||
{
|
||||
size_type count = 0;
|
||||
{
|
||||
size_type start = 0;
|
||||
for (size_type i = 0; i < m_size; i++)
|
||||
{
|
||||
if (m_data[i] == delim)
|
||||
{
|
||||
if (allow_empties || start != i)
|
||||
count++;
|
||||
start = i + 1;
|
||||
}
|
||||
}
|
||||
if (start != m_size)
|
||||
count++;
|
||||
}
|
||||
|
||||
Vector<StringView> result;
|
||||
TRY(result.reserve(count));
|
||||
|
||||
size_type start = 0;
|
||||
for (size_type i = 0; i < m_size; i++)
|
||||
{
|
||||
if (m_data[i] == delim)
|
||||
{
|
||||
if (allow_empties || start != i)
|
||||
TRY(result.push_back(this->substring(start, i - start)));
|
||||
start = i + 1;
|
||||
}
|
||||
}
|
||||
if (start != m_size)
|
||||
TRY(result.push_back(this->substring(start)));
|
||||
return result;
|
||||
}
|
||||
|
||||
ErrorOr<Vector<StringView>> StringView::split(bool(*comp)(char), bool allow_empties)
|
||||
{
|
||||
size_type count = 0;
|
||||
{
|
||||
size_type start = 0;
|
||||
for (size_type i = 0; i < m_size; i++)
|
||||
{
|
||||
if (comp(m_data[i]))
|
||||
{
|
||||
if (allow_empties || start != i)
|
||||
count++;
|
||||
start = i + 1;
|
||||
}
|
||||
}
|
||||
if (start != m_size)
|
||||
count++;
|
||||
}
|
||||
|
||||
Vector<StringView> result;
|
||||
TRY(result.reserve(count));
|
||||
|
||||
size_type start = 0;
|
||||
for (size_type i = 0; i < m_size; i++)
|
||||
{
|
||||
if (comp(m_data[i]))
|
||||
{
|
||||
if (allow_empties || start != i)
|
||||
TRY(result.push_back(this->substring(start, i - start)));
|
||||
start = i + 1;
|
||||
}
|
||||
}
|
||||
if (start != m_size)
|
||||
TRY(result.push_back(this->substring(start)));
|
||||
return result;
|
||||
}
|
||||
|
||||
char StringView::back() const
|
||||
{
|
||||
ASSERT(m_size > 0);
|
||||
return m_data[m_size - 1];
|
||||
}
|
||||
|
||||
char StringView::front() const
|
||||
{
|
||||
ASSERT(m_size > 0);
|
||||
return m_data[0];
|
||||
}
|
||||
|
||||
bool StringView::contains(char ch) const
|
||||
{
|
||||
for (size_type i = 0; i < m_size; i++)
|
||||
if (m_data[i] == ch)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
StringView::size_type StringView::count(char ch) const
|
||||
{
|
||||
size_type result = 0;
|
||||
for (size_type i = 0; i < m_size; i++)
|
||||
if (m_data[i] == ch)
|
||||
result++;
|
||||
return result;
|
||||
}
|
||||
|
||||
bool StringView::empty() const
|
||||
{
|
||||
return m_size == 0;
|
||||
}
|
||||
|
||||
StringView::size_type StringView::size() const
|
||||
{
|
||||
return m_size;
|
||||
}
|
||||
|
||||
const char* StringView::data() const
|
||||
{
|
||||
return m_data;
|
||||
}
|
||||
|
||||
}
|
|
@ -38,7 +38,7 @@ namespace BAN
|
|||
}
|
||||
|
||||
BAN::Time from_unix_time(uint64_t unix_time)
|
||||
{
|
||||
{
|
||||
BAN::Time time {};
|
||||
|
||||
time.second = unix_time % 60; unix_time /= 60;
|
||||
|
@ -68,4 +68,4 @@ namespace BAN
|
|||
return time;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -1,12 +1,24 @@
|
|||
cmake_minimum_required(VERSION 3.26)
|
||||
|
||||
project(BAN CXX)
|
||||
|
||||
set(BAN_SOURCES
|
||||
BAN/Assert.cpp
|
||||
BAN/New.cpp
|
||||
BAN/String.cpp
|
||||
BAN/StringView.cpp
|
||||
BAN/Time.cpp
|
||||
)
|
||||
|
||||
add_library(ban ${BAN_SOURCES})
|
||||
banan_link_library(ban libc)
|
||||
add_custom_target(ban-headers
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_directory_if_different ${CMAKE_CURRENT_SOURCE_DIR}/include/ ${BANAN_INCLUDE}/
|
||||
DEPENDS sysroot
|
||||
)
|
||||
|
||||
banan_install_headers(ban)
|
||||
install(TARGETS ban OPTIONAL)
|
||||
add_library(ban ${BAN_SOURCES})
|
||||
add_dependencies(ban headers libc-install)
|
||||
|
||||
add_custom_target(ban-install
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_BINARY_DIR}/libban.a ${BANAN_LIB}/
|
||||
DEPENDS ban
|
||||
BYPRODUCTS ${BANAN_LIB}/libban.a
|
||||
)
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#include <BAN/Errors.h>
|
||||
#include <BAN/Iterators.h>
|
||||
#include <BAN/Span.h>
|
||||
|
||||
|
@ -18,7 +19,7 @@ namespace BAN
|
|||
using const_iterator = ConstIteratorSimple<T, Array>;
|
||||
|
||||
public:
|
||||
Array() = default;
|
||||
Array();
|
||||
Array(const T&);
|
||||
|
||||
iterator begin() { return iterator(m_data); }
|
||||
|
@ -38,14 +39,21 @@ namespace BAN
|
|||
const Span<T> span() const { return Span(m_data, size()); }
|
||||
|
||||
constexpr size_type size() const;
|
||||
|
||||
|
||||
const T* data() const { return m_data; }
|
||||
T* data() { return m_data; }
|
||||
|
||||
private:
|
||||
T m_data[S] {};
|
||||
T m_data[S];
|
||||
};
|
||||
|
||||
template<typename T, size_t S>
|
||||
Array<T, S>::Array()
|
||||
{
|
||||
for (size_type i = 0; i < S; i++)
|
||||
m_data[i] = T();
|
||||
}
|
||||
|
||||
template<typename T, size_t S>
|
||||
Array<T, S>::Array(const T& value)
|
||||
{
|
||||
|
@ -101,4 +109,4 @@ namespace BAN
|
|||
return S;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -1,14 +1,33 @@
|
|||
#pragma once
|
||||
|
||||
#define __ban_assert_stringify_helper(s) #s
|
||||
#define __ban_assert_stringify(s) __ban_assert_stringify_helper(s)
|
||||
#include <BAN/Traits.h>
|
||||
|
||||
#define ASSERT(cond) \
|
||||
(__builtin_expect(!(cond), 0) \
|
||||
? __ban_assertion_failed(__FILE__ ":" __ban_assert_stringify(__LINE__), "ASSERT(" #cond ") failed") \
|
||||
: (void)0)
|
||||
#if defined(__is_kernel)
|
||||
#include <kernel/Panic.h>
|
||||
|
||||
#define ASSERT_NOT_REACHED() \
|
||||
__ban_assertion_failed(__FILE__ ":" __ban_assert_stringify(__LINE__), "ASSERT_NOT_REACHED() reached")
|
||||
#define ASSERT(cond) \
|
||||
do { \
|
||||
if (!(cond)) \
|
||||
Kernel::panic("ASSERT(" #cond ") failed"); \
|
||||
} while (false)
|
||||
|
||||
[[noreturn]] void __ban_assertion_failed(const char* location, const char* msg);
|
||||
#define __ASSERT_BIN_OP(lhs, rhs, name, op) \
|
||||
do { \
|
||||
auto&& _lhs = lhs; \
|
||||
auto&& _rhs = rhs; \
|
||||
if (!(_lhs op _rhs)) \
|
||||
Kernel::panic(name "(" #lhs ", " #rhs ") ({} " #op " {}) failed", _lhs, _rhs); \
|
||||
} while (false)
|
||||
|
||||
#define ASSERT_LT(lhs, rhs) __ASSERT_BIN_OP(lhs, rhs, "ASSERT_LT", <)
|
||||
#define ASSERT_LTE(lhs, rhs) __ASSERT_BIN_OP(lhs, rhs, "ASSERT_LTE", <=)
|
||||
#define ASSERT_GT(lhs, rhs) __ASSERT_BIN_OP(lhs, rhs, "ASSERT_GT", >)
|
||||
#define ASSERT_GTE(lhs, rhs) __ASSERT_BIN_OP(lhs, rhs, "ASSERT_GTE", >=)
|
||||
#define ASSERT_EQ(lhs, rhs) __ASSERT_BIN_OP(lhs, rhs, "ASSERT_EQ", ==)
|
||||
#define ASSERT_NEQ(lhs, rhs) __ASSERT_BIN_OP(lhs, rhs, "ASSERT_NEQ", !=)
|
||||
#define ASSERT_NOT_REACHED() Kernel::panic("ASSERT_NOT_REACHED() failed")
|
||||
#else
|
||||
#include <assert.h>
|
||||
#define ASSERT(cond) assert((cond) && "ASSERT("#cond") failed")
|
||||
#define ASSERT_NOT_REACHED() do { assert(false && "ASSERT_NOT_REACHED() failed"); __builtin_unreachable(); } while (false)
|
||||
#endif
|
||||
|
|
|
@ -1,69 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
namespace BAN
|
||||
{
|
||||
|
||||
enum MemoryOrder
|
||||
{
|
||||
memory_order_relaxed = __ATOMIC_RELAXED,
|
||||
memory_order_consume = __ATOMIC_CONSUME,
|
||||
memory_order_acquire = __ATOMIC_ACQUIRE,
|
||||
memory_order_release = __ATOMIC_RELEASE,
|
||||
memory_order_acq_rel = __ATOMIC_ACQ_REL,
|
||||
memory_order_seq_cst = __ATOMIC_SEQ_CST,
|
||||
};
|
||||
|
||||
template<typename T, MemoryOrder MEM_ORDER = MemoryOrder::memory_order_seq_cst>
|
||||
requires requires { __atomic_always_lock_free(sizeof(T), 0); }
|
||||
class Atomic
|
||||
{
|
||||
Atomic(const Atomic&) = delete;
|
||||
Atomic(Atomic&&) = delete;
|
||||
Atomic& operator=(const Atomic&) volatile = delete;
|
||||
Atomic& operator=(Atomic&&) volatile = delete;
|
||||
|
||||
public:
|
||||
constexpr Atomic() : m_value(0) {}
|
||||
constexpr Atomic(T val) : m_value(val) {}
|
||||
|
||||
inline T load(MemoryOrder mem_order = MEM_ORDER) const volatile { return __atomic_load_n(&m_value, mem_order); }
|
||||
inline void store(T val, MemoryOrder mem_order = MEM_ORDER) volatile { __atomic_store_n(&m_value, val, mem_order); }
|
||||
|
||||
inline T operator=(T val) volatile { store(val); return val; }
|
||||
|
||||
inline operator T() const volatile { return load(); }
|
||||
|
||||
inline T operator+=(T val) volatile { return __atomic_add_fetch(&m_value, val, MEM_ORDER); }
|
||||
inline T operator-=(T val) volatile { return __atomic_sub_fetch(&m_value, val, MEM_ORDER); }
|
||||
inline T operator&=(T val) volatile { return __atomic_and_fetch(&m_value, val, MEM_ORDER); }
|
||||
inline T operator^=(T val) volatile { return __atomic_xor_fetch(&m_value, val, MEM_ORDER); }
|
||||
inline T operator|=(T val) volatile { return __atomic_or_fetch(&m_value, val, MEM_ORDER); }
|
||||
|
||||
inline T operator--() volatile { return __atomic_sub_fetch(&m_value, 1, MEM_ORDER); }
|
||||
inline T operator++() volatile { return __atomic_add_fetch(&m_value, 1, MEM_ORDER); }
|
||||
|
||||
inline T operator--(int) volatile { return __atomic_fetch_sub(&m_value, 1, MEM_ORDER); }
|
||||
inline T operator++(int) volatile { return __atomic_fetch_add(&m_value, 1, MEM_ORDER); }
|
||||
|
||||
inline bool compare_exchange(T& expected, T desired, MemoryOrder mem_order = MEM_ORDER) volatile { return __atomic_compare_exchange_n(&m_value, &expected, desired, false, mem_order, mem_order); }
|
||||
inline T exchange(T desired, MemoryOrder mem_order = MEM_ORDER) volatile { return __atomic_exchange_n(&m_value, desired, mem_order); };
|
||||
|
||||
inline T add_fetch (T val, MemoryOrder mem_order = MEM_ORDER) volatile { return __atomic_add_fetch (&m_value, val, mem_order); }
|
||||
inline T sub_fetch (T val, MemoryOrder mem_order = MEM_ORDER) volatile { return __atomic_sub_fetch (&m_value, val, mem_order); }
|
||||
inline T and_fetch (T val, MemoryOrder mem_order = MEM_ORDER) volatile { return __atomic_and_fetch (&m_value, val, mem_order); }
|
||||
inline T xor_fetch (T val, MemoryOrder mem_order = MEM_ORDER) volatile { return __atomic_xor_fetch (&m_value, val, mem_order); }
|
||||
inline T or_fetch (T val, MemoryOrder mem_order = MEM_ORDER) volatile { return __atomic_or_fetch (&m_value, val, mem_order); }
|
||||
inline T nand_fetch(T val, MemoryOrder mem_order = MEM_ORDER) volatile { return __atomic_nand_fetch(&m_value, val, mem_order); }
|
||||
|
||||
inline T fetch_add (T val, MemoryOrder mem_order = MEM_ORDER) volatile { return __atomic_fetch_add (&m_value, val, mem_order); }
|
||||
inline T fetch_sub (T val, MemoryOrder mem_order = MEM_ORDER) volatile { return __atomic_fetch_sub (&m_value, val, mem_order); }
|
||||
inline T fetch_and (T val, MemoryOrder mem_order = MEM_ORDER) volatile { return __atomic_fetch_and (&m_value, val, mem_order); }
|
||||
inline T fetch_xor (T val, MemoryOrder mem_order = MEM_ORDER) volatile { return __atomic_fetch_xor (&m_value, val, mem_order); }
|
||||
inline T fetch_or (T val, MemoryOrder mem_order = MEM_ORDER) volatile { return __atomic_fetch__or (&m_value, val, mem_order); }
|
||||
inline T fetch_nand(T val, MemoryOrder mem_order = MEM_ORDER) volatile { return __atomic_nfetch_and(&m_value, val, mem_order); }
|
||||
|
||||
private:
|
||||
T m_value;
|
||||
};
|
||||
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
namespace BAN
|
||||
{
|
||||
|
||||
template<typename To, typename From>
|
||||
constexpr To bit_cast(const From& from)
|
||||
{
|
||||
return __builtin_bit_cast(To, from);
|
||||
}
|
||||
|
||||
}
|
|
@ -2,8 +2,6 @@
|
|||
|
||||
#include <BAN/Span.h>
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace BAN
|
||||
{
|
||||
|
||||
|
@ -25,26 +23,11 @@ namespace BAN
|
|||
: m_data(other.data())
|
||||
, m_size(other.size())
|
||||
{ }
|
||||
ByteSpanGeneral(ByteSpanGeneral&& other)
|
||||
: m_data(other.data())
|
||||
, m_size(other.size())
|
||||
{
|
||||
other.m_data = nullptr;
|
||||
other.m_size = 0;
|
||||
}
|
||||
template<bool C2>
|
||||
ByteSpanGeneral(const ByteSpanGeneral<C2>& other) requires(CONST)
|
||||
: m_data(other.data())
|
||||
, m_size(other.size())
|
||||
{ }
|
||||
template<bool C2>
|
||||
ByteSpanGeneral(ByteSpanGeneral<C2>&& other) requires(CONST)
|
||||
: m_data(other.data())
|
||||
, m_size(other.size())
|
||||
{
|
||||
other.m_data = nullptr;
|
||||
other.m_size = 0;
|
||||
}
|
||||
ByteSpanGeneral(Span<uint8_t> other)
|
||||
: m_data(other.data())
|
||||
, m_size(other.size())
|
||||
|
@ -142,18 +125,16 @@ namespace BAN
|
|||
}
|
||||
|
||||
value_type* data() { return m_data; }
|
||||
const value_type* data() const { return m_data; }
|
||||
const value_type* data() const { return m_data; }
|
||||
|
||||
size_type size() const { return m_size; }
|
||||
|
||||
private:
|
||||
value_type* m_data { nullptr };
|
||||
size_type m_size { 0 };
|
||||
|
||||
friend class ByteSpanGeneral<!CONST>;
|
||||
};
|
||||
|
||||
using ByteSpan = ByteSpanGeneral<false>;
|
||||
using ConstByteSpan = ByteSpanGeneral<true>;
|
||||
|
||||
}
|
||||
}
|
|
@ -1,8 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#include <BAN/Assert.h>
|
||||
#include <BAN/Move.h>
|
||||
#include <BAN/PlacementNew.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
@ -31,13 +29,10 @@ namespace BAN
|
|||
const T& front() const;
|
||||
T& front();
|
||||
|
||||
const T& back() const;
|
||||
T& back();
|
||||
|
||||
size_type size() const { return m_size; }
|
||||
bool empty() const { return size() == 0; }
|
||||
bool full() const { return size() == capacity(); }
|
||||
|
||||
|
||||
static constexpr size_type capacity() { return S; }
|
||||
|
||||
private:
|
||||
|
@ -101,20 +96,6 @@ namespace BAN
|
|||
return *element_at(m_first);
|
||||
}
|
||||
|
||||
template<typename T, size_t S>
|
||||
const T& CircularQueue<T, S>::back() const
|
||||
{
|
||||
ASSERT(!empty());
|
||||
return *element_at((m_first + m_size - 1) % capacity());
|
||||
}
|
||||
|
||||
template<typename T, size_t S>
|
||||
T& CircularQueue<T, S>::back()
|
||||
{
|
||||
ASSERT(!empty());
|
||||
return *element_at((m_first + m_size - 1) % capacity());
|
||||
}
|
||||
|
||||
template<typename T, size_t S>
|
||||
const T* CircularQueue<T, S>::element_at(size_type index) const
|
||||
{
|
||||
|
@ -129,4 +110,4 @@ namespace BAN
|
|||
return (T*)(m_storage + index * sizeof(T));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -1,55 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#if __is_kernel
|
||||
|
||||
#include <kernel/Debug.h>
|
||||
|
||||
#else
|
||||
|
||||
#include <BAN/Formatter.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define __debug_putchar [](int c) { putc(c, stddbg); }
|
||||
|
||||
#define dprintln(...) \
|
||||
do { \
|
||||
BAN::Formatter::print(__debug_putchar, __VA_ARGS__); \
|
||||
BAN::Formatter::print(__debug_putchar,"\r\n"); \
|
||||
fflush(stddbg); \
|
||||
} while (false)
|
||||
|
||||
#define dwarnln(...) \
|
||||
do { \
|
||||
BAN::Formatter::print(__debug_putchar, "\e[33m"); \
|
||||
BAN::Formatter::print(__debug_putchar, __VA_ARGS__); \
|
||||
BAN::Formatter::print(__debug_putchar, "\e[m\r\n"); \
|
||||
fflush(stddbg); \
|
||||
} while(false)
|
||||
|
||||
#define derrorln(...) \
|
||||
do { \
|
||||
BAN::Formatter::print(__debug_putchar, "\e[31m"); \
|
||||
BAN::Formatter::print(__debug_putchar, __VA_ARGS__); \
|
||||
BAN::Formatter::print(__debug_putchar, "\e[m\r\n"); \
|
||||
fflush(stddbg); \
|
||||
} while(false)
|
||||
|
||||
#define dprintln_if(cond, ...) \
|
||||
do { \
|
||||
if constexpr(cond) \
|
||||
dprintln(__VA_ARGS__); \
|
||||
} while(false)
|
||||
|
||||
#define dwarnln_if(cond, ...) \
|
||||
do { \
|
||||
if constexpr(cond) \
|
||||
dwarnln(__VA_ARGS__); \
|
||||
} while(false)
|
||||
|
||||
#define derrorln_if(cond, ...) \
|
||||
do { \
|
||||
if constexpr(cond) \
|
||||
derrorln(__VA_ARGS__); \
|
||||
} while(false)
|
||||
|
||||
#endif
|
|
@ -45,12 +45,6 @@ namespace BAN
|
|||
#endif
|
||||
}
|
||||
|
||||
template<integral T>
|
||||
constexpr T little_endian_to_host(T value)
|
||||
{
|
||||
return host_to_little_endian(value);
|
||||
}
|
||||
|
||||
template<integral T>
|
||||
constexpr T host_to_big_endian(T value)
|
||||
{
|
||||
|
@ -61,20 +55,9 @@ namespace BAN
|
|||
#endif
|
||||
}
|
||||
|
||||
template<integral T>
|
||||
constexpr T big_endian_to_host(T value)
|
||||
{
|
||||
return host_to_big_endian(value);
|
||||
}
|
||||
|
||||
template<integral T>
|
||||
struct LittleEndian
|
||||
{
|
||||
constexpr LittleEndian(T value)
|
||||
{
|
||||
raw = host_to_little_endian(value);
|
||||
}
|
||||
|
||||
constexpr operator T() const
|
||||
{
|
||||
return host_to_little_endian(raw);
|
||||
|
@ -86,11 +69,6 @@ namespace BAN
|
|||
template<integral T>
|
||||
struct BigEndian
|
||||
{
|
||||
constexpr BigEndian(T value)
|
||||
{
|
||||
raw = host_to_big_endian(value);
|
||||
}
|
||||
|
||||
constexpr operator T() const
|
||||
{
|
||||
return host_to_big_endian(raw);
|
||||
|
@ -99,19 +77,4 @@ namespace BAN
|
|||
T raw;
|
||||
};
|
||||
|
||||
template<integral T>
|
||||
using NetworkEndian = BigEndian<T>;
|
||||
|
||||
template<integral T>
|
||||
constexpr T host_to_network_endian(T value)
|
||||
{
|
||||
return host_to_big_endian(value);
|
||||
}
|
||||
|
||||
template<integral T>
|
||||
constexpr T network_endian_to_host(T value)
|
||||
{
|
||||
return big_endian_to_host(value);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <BAN/Formatter.h>
|
||||
#include <BAN/StringView.h>
|
||||
#include <BAN/Variant.h>
|
||||
|
||||
#include <errno.h>
|
||||
|
@ -55,15 +56,13 @@ namespace BAN
|
|||
#endif
|
||||
|
||||
uint64_t get_error_code() const { return m_error_code; }
|
||||
const char* get_message() const
|
||||
BAN::StringView get_message() const
|
||||
{
|
||||
#ifdef __is_kernel
|
||||
if (m_error_code & kernel_error_mask)
|
||||
return Kernel::error_string(kernel_error());
|
||||
#endif
|
||||
if (auto* desc = strerrordesc_np(m_error_code))
|
||||
return desc;
|
||||
return "Unknown error";
|
||||
return strerror(m_error_code);
|
||||
}
|
||||
|
||||
private:
|
||||
|
|
|
@ -192,7 +192,7 @@ namespace BAN::Formatter
|
|||
|
||||
if (sign)
|
||||
*(--ptr) = '-';
|
||||
|
||||
|
||||
print(putc, ptr);
|
||||
}
|
||||
|
||||
|
@ -205,10 +205,10 @@ namespace BAN::Formatter
|
|||
frac_part = -frac_part;
|
||||
|
||||
print_integer(putc, int_part, format);
|
||||
|
||||
|
||||
if (format.percision > 0)
|
||||
putc('.');
|
||||
|
||||
|
||||
for (int i = 0; i < format.percision; i++)
|
||||
{
|
||||
frac_part *= format.base;
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
#include <BAN/Errors.h>
|
||||
#include <BAN/Move.h>
|
||||
#include <BAN/PlacementNew.h>
|
||||
#include <BAN/New.h>
|
||||
|
||||
namespace BAN
|
||||
{
|
||||
|
@ -32,7 +32,7 @@ namespace BAN
|
|||
new (m_storage) CallableMemberConst<Own>(function, owner);
|
||||
}
|
||||
template<typename Lambda>
|
||||
Function(Lambda lambda) requires requires(Lambda lamda, Args&&... args) { { lambda(forward<Args>(args)...) } -> BAN::same_as<Ret>; }
|
||||
Function(Lambda lambda)
|
||||
{
|
||||
static_assert(sizeof(CallableLambda<Lambda>) <= m_size);
|
||||
new (m_storage) CallableLambda<Lambda>(lambda);
|
||||
|
@ -56,7 +56,7 @@ namespace BAN
|
|||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void clear()
|
||||
{
|
||||
if (*this)
|
||||
|
@ -141,8 +141,8 @@ namespace BAN
|
|||
};
|
||||
|
||||
private:
|
||||
static constexpr size_t m_size = sizeof(void*) * 8;
|
||||
static constexpr size_t m_size = sizeof(void*) * 5;
|
||||
alignas(CallableBase) uint8_t m_storage[m_size] { 0 };
|
||||
};
|
||||
|
||||
}
|
||||
}
|
|
@ -1,25 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <BAN/Optional.h>
|
||||
#include <BAN/StringView.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
namespace BAN
|
||||
{
|
||||
|
||||
struct GUID
|
||||
{
|
||||
uint32_t component1 { 0 };
|
||||
uint16_t component2 { 0 };
|
||||
uint16_t component3 { 0 };
|
||||
uint8_t component45[8] { };
|
||||
|
||||
bool operator==(const GUID& other) const
|
||||
{
|
||||
return memcmp(this, &other, sizeof(GUID)) == 0;
|
||||
}
|
||||
};
|
||||
static_assert(sizeof(GUID) == 16);
|
||||
|
||||
}
|
|
@ -47,4 +47,4 @@ namespace BAN
|
|||
}
|
||||
};
|
||||
|
||||
}
|
||||
}
|
|
@ -7,6 +7,9 @@
|
|||
namespace BAN
|
||||
{
|
||||
|
||||
template<typename Container>
|
||||
class HashMapIterator;
|
||||
|
||||
template<typename Key, typename T, typename HASH = BAN::hash<Key>>
|
||||
class HashMap
|
||||
{
|
||||
|
@ -52,14 +55,11 @@ namespace BAN
|
|||
ErrorOr<void> reserve(size_type);
|
||||
|
||||
void remove(const Key&);
|
||||
void remove(iterator it);
|
||||
void clear();
|
||||
|
||||
T& operator[](const Key&);
|
||||
const T& operator[](const Key&) const;
|
||||
|
||||
iterator find(const Key& key);
|
||||
const_iterator find(const Key& key) const;
|
||||
bool contains(const Key&) const;
|
||||
|
||||
bool empty() const;
|
||||
|
@ -69,9 +69,7 @@ namespace BAN
|
|||
ErrorOr<void> rebucket(size_type);
|
||||
LinkedList<Entry>& get_bucket(const Key&);
|
||||
const LinkedList<Entry>& get_bucket(const Key&) const;
|
||||
Vector<LinkedList<Entry>>::iterator get_bucket_iterator(const Key&);
|
||||
Vector<LinkedList<Entry>>::const_iterator get_bucket_iterator(const Key&) const;
|
||||
|
||||
|
||||
private:
|
||||
Vector<LinkedList<Entry>> m_buckets;
|
||||
size_type m_size = 0;
|
||||
|
@ -135,7 +133,9 @@ namespace BAN
|
|||
ASSERT(!contains(key));
|
||||
TRY(rebucket(m_size + 1));
|
||||
auto& bucket = get_bucket(key);
|
||||
TRY(bucket.emplace_back(key, forward<Args>(args)...));
|
||||
auto result = bucket.emplace_back(key, forward<Args>(args)...);
|
||||
if (result.is_error())
|
||||
return Error::from_errno(ENOMEM);
|
||||
m_size++;
|
||||
return {};
|
||||
}
|
||||
|
@ -150,16 +150,17 @@ namespace BAN
|
|||
template<typename Key, typename T, typename HASH>
|
||||
void HashMap<Key, T, HASH>::remove(const Key& key)
|
||||
{
|
||||
auto it = find(key);
|
||||
if (it != end())
|
||||
remove(it);
|
||||
}
|
||||
|
||||
template<typename Key, typename T, typename HASH>
|
||||
void HashMap<Key, T, HASH>::remove(iterator it)
|
||||
{
|
||||
it.outer_current()->remove(it.inner_current());
|
||||
m_size--;
|
||||
if (empty()) return;
|
||||
auto& bucket = get_bucket(key);
|
||||
for (auto it = bucket.begin(); it != bucket.end(); it++)
|
||||
{
|
||||
if (it->key == key)
|
||||
{
|
||||
bucket.remove(it);
|
||||
m_size--;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Key, typename T, typename HASH>
|
||||
|
@ -191,34 +192,15 @@ namespace BAN
|
|||
ASSERT(false);
|
||||
}
|
||||
|
||||
template<typename Key, typename T, typename HASH>
|
||||
typename HashMap<Key, T, HASH>::iterator HashMap<Key, T, HASH>::find(const Key& key)
|
||||
{
|
||||
if (empty())
|
||||
return end();
|
||||
auto bucket_it = get_bucket_iterator(key);
|
||||
for (auto it = bucket_it->begin(); it != bucket_it->end(); it++)
|
||||
if (it->key == key)
|
||||
return iterator(m_buckets.end(), bucket_it, it);
|
||||
return end();
|
||||
}
|
||||
|
||||
template<typename Key, typename T, typename HASH>
|
||||
typename HashMap<Key, T, HASH>::const_iterator HashMap<Key, T, HASH>::find(const Key& key) const
|
||||
{
|
||||
if (empty())
|
||||
return end();
|
||||
auto bucket_it = get_bucket_iterator(key);
|
||||
for (auto it = bucket_it->begin(); it != bucket_it->end(); it++)
|
||||
if (it->key == key)
|
||||
return const_iterator(m_buckets.end(), bucket_it, it);
|
||||
return end();
|
||||
}
|
||||
|
||||
template<typename Key, typename T, typename HASH>
|
||||
bool HashMap<Key, T, HASH>::contains(const Key& key) const
|
||||
{
|
||||
return find(key) != end();
|
||||
if (empty()) return false;
|
||||
const auto& bucket = get_bucket(key);
|
||||
for (const Entry& entry : bucket)
|
||||
if (entry.key == key)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
template<typename Key, typename T, typename HASH>
|
||||
|
@ -241,14 +223,18 @@ namespace BAN
|
|||
|
||||
size_type new_bucket_count = BAN::Math::max<size_type>(bucket_count, m_buckets.size() * 2);
|
||||
Vector<LinkedList<Entry>> new_buckets;
|
||||
TRY(new_buckets.resize(new_bucket_count));
|
||||
|
||||
if (new_buckets.resize(new_bucket_count).is_error())
|
||||
return Error::from_errno(ENOMEM);
|
||||
|
||||
// NOTE: We have to copy the old entries to the new entries and not move
|
||||
// since we might run out of memory half way through.
|
||||
for (auto& bucket : m_buckets)
|
||||
{
|
||||
for (auto it = bucket.begin(); it != bucket.end();)
|
||||
for (Entry& entry : bucket)
|
||||
{
|
||||
size_type new_bucket_index = HASH()(it->key) % new_buckets.size();
|
||||
it = bucket.move_element_to_other_linked_list(new_buckets[new_bucket_index], new_buckets[new_bucket_index].end(), it);
|
||||
size_type bucket_index = HASH()(entry.key) % new_buckets.size();
|
||||
if (new_buckets[bucket_index].push_back(entry).is_error())
|
||||
return Error::from_errno(ENOMEM);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -259,29 +245,17 @@ namespace BAN
|
|||
template<typename Key, typename T, typename HASH>
|
||||
LinkedList<typename HashMap<Key, T, HASH>::Entry>& HashMap<Key, T, HASH>::get_bucket(const Key& key)
|
||||
{
|
||||
return *get_bucket_iterator(key);
|
||||
ASSERT(!m_buckets.empty());
|
||||
auto index = HASH()(key) % m_buckets.size();
|
||||
return m_buckets[index];
|
||||
}
|
||||
|
||||
template<typename Key, typename T, typename HASH>
|
||||
const LinkedList<typename HashMap<Key, T, HASH>::Entry>& HashMap<Key, T, HASH>::get_bucket(const Key& key) const
|
||||
{
|
||||
return *get_bucket_iterator(key);
|
||||
}
|
||||
|
||||
template<typename Key, typename T, typename HASH>
|
||||
Vector<LinkedList<typename HashMap<Key, T, HASH>::Entry>>::iterator HashMap<Key, T, HASH>::get_bucket_iterator(const Key& key)
|
||||
{
|
||||
ASSERT(!m_buckets.empty());
|
||||
auto index = HASH()(key) % m_buckets.size();
|
||||
return next(m_buckets.begin(), index);
|
||||
}
|
||||
|
||||
template<typename Key, typename T, typename HASH>
|
||||
Vector<LinkedList<typename HashMap<Key, T, HASH>::Entry>>::const_iterator HashMap<Key, T, HASH>::get_bucket_iterator(const Key& key) const
|
||||
{
|
||||
ASSERT(!m_buckets.empty());
|
||||
auto index = HASH()(key) % m_buckets.size();
|
||||
return next(m_buckets.begin(), index);
|
||||
return m_buckets[index];
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -2,8 +2,6 @@
|
|||
|
||||
#include <BAN/Errors.h>
|
||||
#include <BAN/Hash.h>
|
||||
#include <BAN/Iterators.h>
|
||||
#include <BAN/LinkedList.h>
|
||||
#include <BAN/Math.h>
|
||||
#include <BAN/Move.h>
|
||||
#include <BAN/Vector.h>
|
||||
|
@ -11,22 +9,24 @@
|
|||
namespace BAN
|
||||
{
|
||||
|
||||
template<typename T, typename HASH>
|
||||
class HashSetIterator;
|
||||
|
||||
template<typename T, typename HASH = hash<T>>
|
||||
class HashSet
|
||||
{
|
||||
public:
|
||||
using value_type = T;
|
||||
using size_type = size_t;
|
||||
using iterator = IteratorDouble<T, Vector, LinkedList, HashSet>;
|
||||
using const_iterator = ConstIteratorDouble<T, Vector, LinkedList, HashSet>;
|
||||
|
||||
using size_type = hash_t;
|
||||
using const_iterator = HashSetIterator<T, HASH>;
|
||||
|
||||
public:
|
||||
HashSet() = default;
|
||||
HashSet(const HashSet&);
|
||||
HashSet(HashSet&&);
|
||||
HashSet(const HashSet<T, HASH>&);
|
||||
HashSet(HashSet<T, HASH>&&);
|
||||
|
||||
HashSet& operator=(const HashSet&);
|
||||
HashSet& operator=(HashSet&&);
|
||||
HashSet<T, HASH>& operator=(const HashSet<T, HASH>&);
|
||||
HashSet<T, HASH>& operator=(HashSet<T, HASH>&&);
|
||||
|
||||
ErrorOr<void> insert(const T&);
|
||||
ErrorOr<void> insert(T&&);
|
||||
|
@ -35,10 +35,8 @@ namespace BAN
|
|||
|
||||
ErrorOr<void> reserve(size_type);
|
||||
|
||||
iterator begin() { return iterator(m_buckets.end(), m_buckets.begin()); }
|
||||
iterator end() { return iterator(m_buckets.end(), m_buckets.end()); }
|
||||
const_iterator begin() const { return const_iterator(m_buckets.end(), m_buckets.begin()); }
|
||||
const_iterator end() const { return const_iterator(m_buckets.end(), m_buckets.end()); }
|
||||
const_iterator begin() const { return const_iterator(this, m_buckets.begin()); }
|
||||
const_iterator end() const { return const_iterator(this, m_buckets.end()); }
|
||||
|
||||
bool contains(const T&) const;
|
||||
|
||||
|
@ -47,23 +45,55 @@ namespace BAN
|
|||
|
||||
private:
|
||||
ErrorOr<void> rebucket(size_type);
|
||||
LinkedList<T>& get_bucket(const T&);
|
||||
const LinkedList<T>& get_bucket(const T&) const;
|
||||
Vector<T>& get_bucket(const T&);
|
||||
const Vector<T>& get_bucket(const T&) const;
|
||||
|
||||
private:
|
||||
Vector<LinkedList<T>> m_buckets;
|
||||
Vector<Vector<T>> m_buckets;
|
||||
size_type m_size = 0;
|
||||
|
||||
friend class HashSetIterator<T, HASH>;
|
||||
};
|
||||
|
||||
template<typename T, typename HASH>
|
||||
HashSet<T, HASH>::HashSet(const HashSet& other)
|
||||
class HashSetIterator
|
||||
{
|
||||
public:
|
||||
HashSetIterator() = default;
|
||||
HashSetIterator(const HashSetIterator<T, HASH>&);
|
||||
|
||||
HashSetIterator<T, HASH>& operator++();
|
||||
HashSetIterator<T, HASH> operator++(int);
|
||||
|
||||
const T& operator*() const;
|
||||
const T* operator->() const;
|
||||
|
||||
bool operator==(const HashSetIterator<T, HASH>&) const;
|
||||
bool operator!=(const HashSetIterator<T, HASH>&) const;
|
||||
|
||||
operator bool() const { return m_owner && m_current_bucket; }
|
||||
|
||||
private:
|
||||
HashSetIterator(const HashSet<T, HASH>* owner, Vector<Vector<T>>::const_iterator bucket);
|
||||
void find_next();
|
||||
|
||||
private:
|
||||
const HashSet<T, HASH>* m_owner = nullptr;
|
||||
Vector<Vector<T>>::const_iterator m_current_bucket;
|
||||
Vector<T>::const_iterator m_current_key;
|
||||
|
||||
friend class HashSet<T, HASH>;
|
||||
};
|
||||
|
||||
template<typename T, typename HASH>
|
||||
HashSet<T, HASH>::HashSet(const HashSet<T, HASH>& other)
|
||||
: m_buckets(other.m_buckets)
|
||||
, m_size(other.m_size)
|
||||
{
|
||||
}
|
||||
|
||||
template<typename T, typename HASH>
|
||||
HashSet<T, HASH>::HashSet(HashSet&& other)
|
||||
HashSet<T, HASH>::HashSet(HashSet<T, HASH>&& other)
|
||||
: m_buckets(move(other.m_buckets))
|
||||
, m_size(other.m_size)
|
||||
{
|
||||
|
@ -71,7 +101,7 @@ namespace BAN
|
|||
}
|
||||
|
||||
template<typename T, typename HASH>
|
||||
HashSet<T, HASH>& HashSet<T, HASH>::operator=(const HashSet& other)
|
||||
HashSet<T, HASH>& HashSet<T, HASH>::operator=(const HashSet<T, HASH>& other)
|
||||
{
|
||||
clear();
|
||||
m_buckets = other.m_buckets;
|
||||
|
@ -80,7 +110,7 @@ namespace BAN
|
|||
}
|
||||
|
||||
template<typename T, typename HASH>
|
||||
HashSet<T, HASH>& HashSet<T, HASH>::operator=(HashSet&& other)
|
||||
HashSet<T, HASH>& HashSet<T, HASH>::operator=(HashSet<T, HASH>&& other)
|
||||
{
|
||||
clear();
|
||||
m_buckets = move(other.m_buckets);
|
||||
|
@ -111,15 +141,15 @@ namespace BAN
|
|||
void HashSet<T, HASH>::remove(const T& key)
|
||||
{
|
||||
if (empty()) return;
|
||||
auto& bucket = get_bucket(key);
|
||||
for (auto it = bucket.begin(); it != bucket.end(); it++)
|
||||
Vector<T>& bucket = get_bucket(key);
|
||||
for (size_type i = 0; i < bucket.size(); i++)
|
||||
{
|
||||
if (*it == key)
|
||||
if (bucket[i] == key)
|
||||
{
|
||||
bucket.remove(it);
|
||||
bucket.remove(i);
|
||||
m_size--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -162,17 +192,20 @@ namespace BAN
|
|||
if (m_buckets.size() >= bucket_count)
|
||||
return {};
|
||||
|
||||
size_type new_bucket_count = Math::max<size_type>(bucket_count, m_buckets.size() * 2);
|
||||
Vector<LinkedList<T>> new_buckets;
|
||||
size_type new_bucket_count = BAN::Math::max<size_type>(bucket_count, m_buckets.size() * 2);
|
||||
Vector<Vector<T>> new_buckets;
|
||||
if (new_buckets.resize(new_bucket_count).is_error())
|
||||
return Error::from_errno(ENOMEM);
|
||||
|
||||
for (auto& bucket : m_buckets)
|
||||
|
||||
// NOTE: We have to copy the old keys to the new keys and not move
|
||||
// since we might run out of memory half way through.
|
||||
for (Vector<T>& bucket : m_buckets)
|
||||
{
|
||||
for (auto it = bucket.begin(); it != bucket.end();)
|
||||
for (T& key : bucket)
|
||||
{
|
||||
size_type new_bucket_index = HASH()(*it) % new_buckets.size();
|
||||
it = bucket.move_element_to_other_linked_list(new_buckets[new_bucket_index], new_buckets[new_bucket_index].end(), it);
|
||||
size_type bucket_index = HASH()(key) % new_buckets.size();
|
||||
if (new_buckets[bucket_index].push_back(key).is_error())
|
||||
return Error::from_errno(ENOMEM);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -181,7 +214,7 @@ namespace BAN
|
|||
}
|
||||
|
||||
template<typename T, typename HASH>
|
||||
LinkedList<T>& HashSet<T, HASH>::get_bucket(const T& key)
|
||||
Vector<T>& HashSet<T, HASH>::get_bucket(const T& key)
|
||||
{
|
||||
ASSERT(!m_buckets.empty());
|
||||
size_type index = HASH()(key) % m_buckets.size();
|
||||
|
@ -189,11 +222,83 @@ namespace BAN
|
|||
}
|
||||
|
||||
template<typename T, typename HASH>
|
||||
const LinkedList<T>& HashSet<T, HASH>::get_bucket(const T& key) const
|
||||
const Vector<T>& HashSet<T, HASH>::get_bucket(const T& key) const
|
||||
{
|
||||
ASSERT(!m_buckets.empty());
|
||||
size_type index = HASH()(key) % m_buckets.size();
|
||||
return m_buckets[index];
|
||||
}
|
||||
|
||||
}
|
||||
template<typename T, typename HASH>
|
||||
HashSetIterator<T, HASH>& HashSetIterator<T, HASH>::operator++()
|
||||
{
|
||||
ASSERT(*this);
|
||||
if (m_current_key == m_current_bucket->end())
|
||||
m_current_bucket++;
|
||||
else
|
||||
m_current_key++;
|
||||
find_next();
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename T, typename HASH>
|
||||
HashSetIterator<T, HASH> HashSetIterator<T, HASH>::operator++(int)
|
||||
{
|
||||
auto temp = *this;
|
||||
++(*this);
|
||||
return temp;
|
||||
}
|
||||
|
||||
template<typename T, typename HASH>
|
||||
const T& HashSetIterator<T, HASH>::operator*() const
|
||||
{
|
||||
ASSERT(m_owner && m_current_bucket && m_current_key);
|
||||
return *m_current_key;
|
||||
}
|
||||
|
||||
template<typename T, typename HASH>
|
||||
const T* HashSetIterator<T, HASH>::operator->() const
|
||||
{
|
||||
return &**this;
|
||||
}
|
||||
|
||||
template<typename T, typename HASH>
|
||||
bool HashSetIterator<T, HASH>::operator==(const HashSetIterator<T, HASH>& other) const
|
||||
{
|
||||
if (!m_owner || m_owner != other.m_owner)
|
||||
return false;
|
||||
return m_current_bucket == other.m_current_bucket
|
||||
&& m_current_key == other.m_current_key;
|
||||
}
|
||||
|
||||
template<typename T, typename HASH>
|
||||
bool HashSetIterator<T, HASH>::operator!=(const HashSetIterator<T, HASH>& other) const
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
template<typename T, typename HASH>
|
||||
HashSetIterator<T, HASH>::HashSetIterator(const HashSet<T, HASH>* owner, Vector<Vector<T>>::const_iterator bucket)
|
||||
: m_owner(owner)
|
||||
, m_current_bucket(bucket)
|
||||
{
|
||||
if (m_current_bucket != m_owner->m_buckets.end())
|
||||
m_current_key = m_current_bucket->begin();
|
||||
find_next();
|
||||
}
|
||||
|
||||
template<typename T, typename HASH>
|
||||
void HashSetIterator<T, HASH>::find_next()
|
||||
{
|
||||
ASSERT(m_owner && m_current_bucket);
|
||||
while (m_current_bucket != m_owner->m_buckets.end())
|
||||
{
|
||||
if (m_current_key && m_current_key != m_current_bucket->end())
|
||||
return;
|
||||
m_current_bucket++;
|
||||
m_current_key = m_current_bucket->begin();
|
||||
}
|
||||
m_current_key = typename Vector<T>::const_iterator();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,75 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <BAN/Endianness.h>
|
||||
#include <BAN/Formatter.h>
|
||||
#include <BAN/Hash.h>
|
||||
|
||||
namespace BAN
|
||||
{
|
||||
|
||||
struct IPv4Address
|
||||
{
|
||||
constexpr IPv4Address(uint32_t u32_address)
|
||||
{
|
||||
raw = u32_address;
|
||||
}
|
||||
|
||||
constexpr IPv4Address(uint8_t oct1, uint8_t oct2, uint8_t oct3, uint8_t oct4)
|
||||
{
|
||||
octets[0] = oct1;
|
||||
octets[1] = oct2;
|
||||
octets[2] = oct3;
|
||||
octets[3] = oct4;
|
||||
}
|
||||
|
||||
constexpr bool operator==(const IPv4Address& other) const
|
||||
{
|
||||
return raw == other.raw;
|
||||
}
|
||||
|
||||
constexpr IPv4Address mask(const IPv4Address& other) const
|
||||
{
|
||||
return IPv4Address(raw & other.raw);
|
||||
}
|
||||
|
||||
union
|
||||
{
|
||||
uint8_t octets[4];
|
||||
uint32_t raw;
|
||||
} __attribute__((packed));
|
||||
};
|
||||
static_assert(sizeof(IPv4Address) == 4);
|
||||
|
||||
template<>
|
||||
struct hash<IPv4Address>
|
||||
{
|
||||
constexpr hash_t operator()(IPv4Address ipv4) const
|
||||
{
|
||||
return hash<uint32_t>()(ipv4.raw);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
namespace BAN::Formatter
|
||||
{
|
||||
|
||||
template<typename F>
|
||||
void print_argument(F putc, const IPv4Address& ipv4, const ValueFormat&)
|
||||
{
|
||||
ValueFormat format {
|
||||
.base = 10,
|
||||
.percision = 0,
|
||||
.fill = 0,
|
||||
.upper = false,
|
||||
};
|
||||
|
||||
print_argument(putc, ipv4.octets[0], format);
|
||||
for (size_t i = 1; i < 4; i++)
|
||||
{
|
||||
putc('.');
|
||||
print_argument(putc, ipv4.octets[i], format);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -9,4 +9,4 @@ namespace BAN
|
|||
Break
|
||||
};
|
||||
|
||||
}
|
||||
}
|
|
@ -1,180 +1,92 @@
|
|||
#pragma once
|
||||
|
||||
#include <BAN/Assert.h>
|
||||
#include <BAN/Traits.h>
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
namespace BAN
|
||||
{
|
||||
|
||||
template<typename It>
|
||||
constexpr It next(It it, size_t count)
|
||||
{
|
||||
for (size_t i = 0; i < count; i++)
|
||||
++it;
|
||||
return it;
|
||||
}
|
||||
|
||||
template<typename It>
|
||||
requires requires(It it, size_t n) { requires is_same_v<decltype(it + n), It>; }
|
||||
constexpr It next(It it, size_t count)
|
||||
{
|
||||
return it + count;
|
||||
}
|
||||
|
||||
template<typename It>
|
||||
constexpr It prev(It it, size_t count)
|
||||
{
|
||||
for (size_t i = 0; i < count; i++)
|
||||
--it;
|
||||
return it;
|
||||
}
|
||||
|
||||
template<typename It>
|
||||
requires requires(It it, size_t n) { requires is_same_v<decltype(it - n), It>; }
|
||||
constexpr It prev(It it, size_t count)
|
||||
{
|
||||
return it - count;
|
||||
}
|
||||
|
||||
template<typename It>
|
||||
constexpr size_t distance(It it1, It it2)
|
||||
{
|
||||
size_t dist = 0;
|
||||
while (it1 != it2)
|
||||
{
|
||||
++it1;
|
||||
++dist;
|
||||
}
|
||||
return dist;
|
||||
}
|
||||
|
||||
template<typename It>
|
||||
requires requires(It it1, It it2) { requires is_integral_v<decltype(it2 - it1)>; }
|
||||
constexpr size_t distance(It it1, It it2)
|
||||
{
|
||||
return it2 - it1;
|
||||
}
|
||||
|
||||
template<typename T, typename Container, bool CONST>
|
||||
class IteratorSimpleGeneral
|
||||
{
|
||||
public:
|
||||
using value_type = T;
|
||||
|
||||
public:
|
||||
constexpr IteratorSimpleGeneral() = default;
|
||||
IteratorSimpleGeneral() = default;
|
||||
template<bool CONST2, typename = enable_if_t<CONST2 == CONST || CONST>>
|
||||
constexpr IteratorSimpleGeneral(const IteratorSimpleGeneral<T, Container, CONST2>& other)
|
||||
IteratorSimpleGeneral(const IteratorSimpleGeneral<T, Container, CONST2>& other)
|
||||
: m_pointer(other.m_pointer)
|
||||
, m_valid(other.m_valid)
|
||||
{
|
||||
}
|
||||
|
||||
constexpr const T& operator*() const
|
||||
const T& operator*() const
|
||||
{
|
||||
ASSERT(m_pointer);
|
||||
return *m_pointer;
|
||||
}
|
||||
template<bool CONST2 = CONST>
|
||||
constexpr enable_if_t<!CONST2, T&> operator*()
|
||||
enable_if_t<!CONST2, T&> operator*()
|
||||
{
|
||||
ASSERT(*this);
|
||||
ASSERT(m_pointer);
|
||||
return *m_pointer;
|
||||
}
|
||||
|
||||
constexpr const T* operator->() const
|
||||
const T* operator->() const
|
||||
{
|
||||
ASSERT(*this);
|
||||
ASSERT(m_pointer);
|
||||
return m_pointer;
|
||||
}
|
||||
template<bool CONST2 = CONST>
|
||||
constexpr enable_if_t<!CONST2, T*> operator->()
|
||||
enable_if_t<!CONST2, T*> operator->()
|
||||
{
|
||||
ASSERT(*this);
|
||||
ASSERT(m_pointer);
|
||||
return m_pointer;
|
||||
}
|
||||
|
||||
constexpr IteratorSimpleGeneral& operator++()
|
||||
IteratorSimpleGeneral& operator++()
|
||||
{
|
||||
ASSERT(*this);
|
||||
ASSERT(m_pointer);
|
||||
++m_pointer;
|
||||
return *this;
|
||||
}
|
||||
constexpr IteratorSimpleGeneral operator++(int)
|
||||
IteratorSimpleGeneral operator++(int)
|
||||
{
|
||||
auto temp = *this;
|
||||
++(*this);
|
||||
return temp;
|
||||
}
|
||||
|
||||
constexpr IteratorSimpleGeneral& operator--()
|
||||
IteratorSimpleGeneral& operator--()
|
||||
{
|
||||
ASSERT(*this);
|
||||
ASSERT(m_pointer);
|
||||
--m_pointer;
|
||||
return *this;
|
||||
return --m_pointer;
|
||||
}
|
||||
constexpr IteratorSimpleGeneral operator--(int)
|
||||
IteratorSimpleGeneral operator--(int)
|
||||
{
|
||||
auto temp = *this;
|
||||
--(*this);
|
||||
return temp;
|
||||
}
|
||||
|
||||
constexpr size_t operator-(const IteratorSimpleGeneral& other) const
|
||||
bool operator==(const IteratorSimpleGeneral& other) const
|
||||
{
|
||||
ASSERT(*this && other);
|
||||
return m_pointer - other.m_pointer;
|
||||
}
|
||||
|
||||
constexpr IteratorSimpleGeneral operator+(size_t offset) const
|
||||
{
|
||||
return IteratorSimpleGeneral(m_pointer + offset);
|
||||
}
|
||||
|
||||
constexpr IteratorSimpleGeneral operator-(size_t offset) const
|
||||
{
|
||||
return IteratorSimpleGeneral(m_pointer - offset);
|
||||
}
|
||||
|
||||
constexpr bool operator<(const IteratorSimpleGeneral& other) const
|
||||
{
|
||||
ASSERT(*this);
|
||||
return m_pointer < other.m_pointer;
|
||||
}
|
||||
|
||||
constexpr bool operator==(const IteratorSimpleGeneral& other) const
|
||||
{
|
||||
ASSERT(*this);
|
||||
return m_pointer == other.m_pointer;
|
||||
}
|
||||
constexpr bool operator!=(const IteratorSimpleGeneral& other) const
|
||||
bool operator!=(const IteratorSimpleGeneral& other) const
|
||||
{
|
||||
ASSERT(*this);
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
constexpr explicit operator bool() const
|
||||
operator bool() const
|
||||
{
|
||||
return m_valid;
|
||||
return m_pointer;
|
||||
}
|
||||
|
||||
private:
|
||||
constexpr IteratorSimpleGeneral(maybe_const_t<CONST, T>* pointer)
|
||||
IteratorSimpleGeneral(maybe_const_t<CONST, T>* pointer)
|
||||
: m_pointer(pointer)
|
||||
, m_valid(true)
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
maybe_const_t<CONST, T>* m_pointer = nullptr;
|
||||
bool m_valid = false;
|
||||
|
||||
friend IteratorSimpleGeneral<T, Container, !CONST>;
|
||||
friend Container;
|
||||
|
@ -190,19 +102,17 @@ namespace BAN
|
|||
using InnerIterator = either_or_t<CONST, typename Inner::const_iterator, typename Inner::iterator>;
|
||||
using OuterIterator = either_or_t<CONST, typename Outer::const_iterator, typename Outer::iterator>;
|
||||
|
||||
using value_type = T;
|
||||
|
||||
public:
|
||||
constexpr IteratorDoubleGeneral() = default;
|
||||
IteratorDoubleGeneral() = default;
|
||||
template<bool CONST2, typename = enable_if_t<CONST2 == CONST || CONST>>
|
||||
constexpr IteratorDoubleGeneral(const IteratorDoubleGeneral<T, OuterContainer, InnerContainer, Container, CONST2>& other)
|
||||
IteratorDoubleGeneral(const IteratorDoubleGeneral<T, OuterContainer, InnerContainer, Container, CONST2>& other)
|
||||
: m_outer_end(other.m_outer_end)
|
||||
, m_outer_current(other.m_outer_current)
|
||||
, m_inner_current(other.m_inner_current)
|
||||
{
|
||||
}
|
||||
|
||||
constexpr const T& operator*() const
|
||||
const T& operator*() const
|
||||
{
|
||||
ASSERT(*this);
|
||||
ASSERT(m_outer_current != m_outer_end);
|
||||
|
@ -210,7 +120,7 @@ namespace BAN
|
|||
return m_inner_current.operator*();
|
||||
}
|
||||
template<bool CONST2 = CONST>
|
||||
constexpr enable_if_t<!CONST2, T&> operator*()
|
||||
enable_if_t<!CONST2, T&> operator*()
|
||||
{
|
||||
ASSERT(*this);
|
||||
ASSERT(m_outer_current != m_outer_end);
|
||||
|
@ -218,7 +128,7 @@ namespace BAN
|
|||
return m_inner_current.operator*();
|
||||
}
|
||||
|
||||
constexpr const T* operator->() const
|
||||
const T* operator->() const
|
||||
{
|
||||
ASSERT(*this);
|
||||
ASSERT(m_outer_current != m_outer_end);
|
||||
|
@ -226,7 +136,7 @@ namespace BAN
|
|||
return m_inner_current.operator->();
|
||||
}
|
||||
template<bool CONST2 = CONST>
|
||||
constexpr enable_if_t<!CONST2, T*> operator->()
|
||||
enable_if_t<!CONST2, T*> operator->()
|
||||
{
|
||||
ASSERT(*this);
|
||||
ASSERT(m_outer_current != m_outer_end);
|
||||
|
@ -234,7 +144,7 @@ namespace BAN
|
|||
return m_inner_current.operator->();
|
||||
}
|
||||
|
||||
constexpr IteratorDoubleGeneral& operator++()
|
||||
IteratorDoubleGeneral& operator++()
|
||||
{
|
||||
ASSERT(*this);
|
||||
ASSERT(m_outer_current != m_outer_end);
|
||||
|
@ -243,37 +153,37 @@ namespace BAN
|
|||
find_valid_or_end();
|
||||
return *this;
|
||||
}
|
||||
constexpr IteratorDoubleGeneral operator++(int)
|
||||
IteratorDoubleGeneral operator++(int)
|
||||
{
|
||||
auto temp = *this;
|
||||
++(*this);
|
||||
return temp;
|
||||
}
|
||||
|
||||
constexpr bool operator==(const IteratorDoubleGeneral& other) const
|
||||
bool operator==(const IteratorDoubleGeneral& other) const
|
||||
{
|
||||
ASSERT(*this && other);
|
||||
if (!*this || !other)
|
||||
return false;
|
||||
if (m_outer_end != other.m_outer_end)
|
||||
return false;
|
||||
if (m_outer_current != other.m_outer_current)
|
||||
return false;
|
||||
if (m_outer_current == m_outer_end)
|
||||
return true;
|
||||
ASSERT(m_inner_current && other.m_inner_current);
|
||||
return m_inner_current == other.m_inner_current;
|
||||
}
|
||||
constexpr bool operator!=(const IteratorDoubleGeneral& other) const
|
||||
bool operator!=(const IteratorDoubleGeneral& other) const
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
constexpr explicit operator bool() const
|
||||
operator bool() const
|
||||
{
|
||||
return !!m_outer_current;
|
||||
return m_outer_end && m_outer_current;
|
||||
}
|
||||
|
||||
private:
|
||||
constexpr IteratorDoubleGeneral(const OuterIterator& outer_end, const OuterIterator& outer_current)
|
||||
IteratorDoubleGeneral(const OuterIterator& outer_end, const OuterIterator& outer_current)
|
||||
: m_outer_end(outer_end)
|
||||
, m_outer_current(outer_current)
|
||||
{
|
||||
|
@ -284,15 +194,7 @@ namespace BAN
|
|||
}
|
||||
}
|
||||
|
||||
constexpr IteratorDoubleGeneral(const OuterIterator& outer_end, const OuterIterator& outer_current, const InnerIterator& inner_current)
|
||||
: m_outer_end(outer_end)
|
||||
, m_outer_current(outer_current)
|
||||
, m_inner_current(inner_current)
|
||||
{
|
||||
find_valid_or_end();
|
||||
}
|
||||
|
||||
constexpr void find_valid_or_end()
|
||||
void find_valid_or_end()
|
||||
{
|
||||
while (m_inner_current == m_outer_current->end())
|
||||
{
|
||||
|
@ -303,9 +205,6 @@ namespace BAN
|
|||
}
|
||||
}
|
||||
|
||||
constexpr OuterIterator outer_current() { return m_outer_current; }
|
||||
constexpr InnerIterator inner_current() { return m_inner_current; }
|
||||
|
||||
private:
|
||||
OuterIterator m_outer_end;
|
||||
OuterIterator m_outer_current;
|
||||
|
|
|
@ -1,156 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <BAN/Traits.h>
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace BAN
|
||||
{
|
||||
|
||||
template<typename T>
|
||||
class numeric_limits
|
||||
{
|
||||
public:
|
||||
numeric_limits() = delete;
|
||||
|
||||
static inline constexpr T max()
|
||||
{
|
||||
if constexpr(is_same_v<T, char>)
|
||||
return __SCHAR_MAX__;
|
||||
if constexpr(is_same_v<T, signed char>)
|
||||
return __SCHAR_MAX__;
|
||||
if constexpr(is_same_v<T, unsigned char>)
|
||||
return (T)__SCHAR_MAX__ * 2 + 1;
|
||||
|
||||
if constexpr(is_same_v<T, short>)
|
||||
return __SHRT_MAX__;
|
||||
if constexpr(is_same_v<T, int>)
|
||||
return __INT_MAX__;
|
||||
if constexpr(is_same_v<T, long>)
|
||||
return __LONG_MAX__;
|
||||
if constexpr(is_same_v<T, long long>)
|
||||
return __LONG_LONG_MAX__;
|
||||
|
||||
if constexpr(is_same_v<T, unsigned short>)
|
||||
return (T)__SHRT_MAX__ * 2 + 1;
|
||||
if constexpr(is_same_v<T, unsigned int>)
|
||||
return (T)__INT_MAX__ * 2 + 1;
|
||||
if constexpr(is_same_v<T, unsigned long>)
|
||||
return (T)__LONG_MAX__ * 2 + 1;
|
||||
if constexpr(is_same_v<T, unsigned long long>)
|
||||
return (T)__LONG_LONG_MAX__ * 2 + 1;
|
||||
|
||||
if constexpr(is_same_v<T, float>)
|
||||
return __FLT_MAX__;
|
||||
if constexpr(is_same_v<T, double>)
|
||||
return __DBL_MAX__;
|
||||
if constexpr(is_same_v<T, long double>)
|
||||
return __LDBL_MAX__;
|
||||
}
|
||||
|
||||
static inline constexpr T min()
|
||||
{
|
||||
if constexpr(is_signed_v<T> && is_integral_v<T>)
|
||||
return -max() - 1;
|
||||
|
||||
if constexpr(is_unsigned_v<T> && is_integral_v<T>)
|
||||
return 0;
|
||||
|
||||
if constexpr(is_same_v<T, float>)
|
||||
return __FLT_MIN__;
|
||||
if constexpr(is_same_v<T, double>)
|
||||
return __DBL_MIN__;
|
||||
if constexpr(is_same_v<T, long double>)
|
||||
return __LDBL_MIN__;
|
||||
}
|
||||
|
||||
static inline constexpr bool has_infinity()
|
||||
{
|
||||
if constexpr(is_same_v<T, float>)
|
||||
return __FLT_HAS_INFINITY__;
|
||||
if constexpr(is_same_v<T, double>)
|
||||
return __DBL_HAS_INFINITY__;
|
||||
if constexpr(is_same_v<T, long double>)
|
||||
return __LDBL_HAS_INFINITY__;
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline constexpr T infinity() requires(has_infinity())
|
||||
{
|
||||
if constexpr(is_same_v<T, float>)
|
||||
return __builtin_inff();
|
||||
if constexpr(is_same_v<T, double>)
|
||||
return __builtin_inf();
|
||||
if constexpr(is_same_v<T, long double>)
|
||||
return __builtin_infl();
|
||||
}
|
||||
|
||||
static inline constexpr bool has_quiet_NaN()
|
||||
{
|
||||
if constexpr(is_same_v<T, float>)
|
||||
return __FLT_HAS_QUIET_NAN__;
|
||||
if constexpr(is_same_v<T, double>)
|
||||
return __DBL_HAS_QUIET_NAN__;
|
||||
if constexpr(is_same_v<T, long double>)
|
||||
return __LDBL_HAS_QUIET_NAN__;
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline constexpr T quiet_NaN() requires(has_quiet_NaN())
|
||||
{
|
||||
if constexpr(is_same_v<T, float>)
|
||||
return __builtin_nanf("");
|
||||
if constexpr(is_same_v<T, double>)
|
||||
return __builtin_nan("");
|
||||
if constexpr(is_same_v<T, long double>)
|
||||
return __builtin_nanl("");
|
||||
}
|
||||
|
||||
static inline constexpr int max_exponent2()
|
||||
{
|
||||
static_assert(__FLT_RADIX__ == 2);
|
||||
if constexpr(is_same_v<T, float>)
|
||||
return __FLT_MAX_EXP__;
|
||||
if constexpr(is_same_v<T, double>)
|
||||
return __DBL_MAX_EXP__;
|
||||
if constexpr(is_same_v<T, long double>)
|
||||
return __LDBL_MAX_EXP__;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline constexpr int max_exponent10()
|
||||
{
|
||||
if constexpr(is_same_v<T, float>)
|
||||
return __FLT_MAX_10_EXP__;
|
||||
if constexpr(is_same_v<T, double>)
|
||||
return __DBL_MAX_10_EXP__;
|
||||
if constexpr(is_same_v<T, long double>)
|
||||
return __LDBL_MAX_10_EXP__;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline constexpr int min_exponent2()
|
||||
{
|
||||
static_assert(__FLT_RADIX__ == 2);
|
||||
if constexpr(is_same_v<T, float>)
|
||||
return __FLT_MIN_EXP__;
|
||||
if constexpr(is_same_v<T, double>)
|
||||
return __DBL_MIN_EXP__;
|
||||
if constexpr(is_same_v<T, long double>)
|
||||
return __LDBL_MIN_EXP__;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline constexpr int min_exponent10()
|
||||
{
|
||||
if constexpr(is_same_v<T, float>)
|
||||
return __FLT_MIN_10_EXP__;
|
||||
if constexpr(is_same_v<T, double>)
|
||||
return __DBL_MIN_10_EXP__;
|
||||
if constexpr(is_same_v<T, long double>)
|
||||
return __LDBL_MIN_10_EXP__;
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
|
@ -3,7 +3,6 @@
|
|||
#include <BAN/Errors.h>
|
||||
#include <BAN/Move.h>
|
||||
#include <BAN/New.h>
|
||||
#include <BAN/PlacementNew.h>
|
||||
|
||||
namespace BAN
|
||||
{
|
||||
|
@ -22,11 +21,11 @@ namespace BAN
|
|||
|
||||
public:
|
||||
LinkedList() = default;
|
||||
LinkedList(const LinkedList<T>& other) requires is_copy_constructible_v<T> { *this = other; }
|
||||
LinkedList(const LinkedList<T>& other) { *this = other; }
|
||||
LinkedList(LinkedList<T>&& other) { *this = move(other); }
|
||||
~LinkedList() { clear(); }
|
||||
|
||||
LinkedList<T>& operator=(const LinkedList<T>&) requires is_copy_constructible_v<T>;
|
||||
LinkedList<T>& operator=(const LinkedList<T>&);
|
||||
LinkedList<T>& operator=(LinkedList<T>&&);
|
||||
|
||||
ErrorOr<void> push_back(const T&);
|
||||
|
@ -42,8 +41,6 @@ namespace BAN
|
|||
iterator remove(iterator);
|
||||
void clear();
|
||||
|
||||
iterator move_element_to_other_linked_list(LinkedList& dest_list, iterator dest_iter, iterator src_iter);
|
||||
|
||||
iterator begin() { return iterator(m_data, empty()); }
|
||||
const_iterator begin() const { return const_iterator(m_data, empty()); }
|
||||
iterator end() { return iterator(m_last, true); }
|
||||
|
@ -67,11 +64,7 @@ namespace BAN
|
|||
Node* prev;
|
||||
};
|
||||
|
||||
template<typename... Args>
|
||||
ErrorOr<Node*> allocate_node(Args&&...) const;
|
||||
|
||||
Node* remove_node(iterator);
|
||||
void insert_node(iterator, Node*);
|
||||
ErrorOr<Node*> allocate_node() const;
|
||||
|
||||
Node* m_data = nullptr;
|
||||
Node* m_last = nullptr;
|
||||
|
@ -122,7 +115,7 @@ namespace BAN
|
|||
};
|
||||
|
||||
template<typename T>
|
||||
LinkedList<T>& LinkedList<T>::operator=(const LinkedList<T>& other) requires is_copy_constructible_v<T>
|
||||
LinkedList<T>& LinkedList<T>::operator=(const LinkedList<T>& other)
|
||||
{
|
||||
clear();
|
||||
for (const T& elem : other)
|
||||
|
@ -143,31 +136,6 @@ namespace BAN
|
|||
return *this;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
LinkedList<T>::Node* LinkedList<T>::remove_node(iterator iter)
|
||||
{
|
||||
ASSERT(!empty() && iter);
|
||||
Node* node = iter.m_current;
|
||||
Node* prev = node->prev;
|
||||
Node* next = node->next;
|
||||
(prev ? prev->next : m_data) = next;
|
||||
(next ? next->prev : m_last) = prev;
|
||||
m_size--;
|
||||
return node;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void LinkedList<T>::insert_node(iterator iter, Node* node)
|
||||
{
|
||||
Node* next = iter.m_past_end ? nullptr : iter.m_current;
|
||||
Node* prev = next ? next->prev : m_last;
|
||||
node->next = next;
|
||||
node->prev = prev;
|
||||
(prev ? prev->next : m_data) = node;
|
||||
(next ? next->prev : m_last) = node;
|
||||
m_size++;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
ErrorOr<void> LinkedList<T>::push_back(const T& value)
|
||||
{
|
||||
|
@ -189,8 +157,15 @@ namespace BAN
|
|||
template<typename T>
|
||||
ErrorOr<void> LinkedList<T>::insert(iterator iter, T&& value)
|
||||
{
|
||||
Node* new_node = TRY(allocate_node(move(value)));
|
||||
insert_node(iter, new_node);
|
||||
Node* next = iter.m_past_end ? nullptr : iter.m_current;
|
||||
Node* prev = next ? next->prev : m_last;
|
||||
Node* new_node = TRY(allocate_node());
|
||||
new (&new_node->value) T(move(value));
|
||||
new_node->next = next;
|
||||
new_node->prev = prev;
|
||||
(prev ? prev->next : m_data) = new_node;
|
||||
(next ? next->prev : m_last) = new_node;
|
||||
m_size++;
|
||||
return {};
|
||||
}
|
||||
|
||||
|
@ -205,15 +180,21 @@ namespace BAN
|
|||
template<typename... Args>
|
||||
ErrorOr<void> LinkedList<T>::emplace(iterator iter, Args&&... args)
|
||||
{
|
||||
Node* new_node = TRY(allocate_node(forward<Args>(args)...));
|
||||
insert_node(iter, new_node);
|
||||
Node* next = iter.m_past_end ? nullptr : iter.m_current;
|
||||
Node* prev = next ? next->prev : m_last;
|
||||
Node* new_node = TRY(allocate_node());
|
||||
new (&new_node->value) T(forward<Args>(args)...);
|
||||
new_node->next = next;
|
||||
new_node->prev = prev;
|
||||
(prev ? prev->next : m_data) = new_node;
|
||||
(next ? next->prev : m_last) = new_node;
|
||||
m_size++;
|
||||
return {};
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void LinkedList<T>::pop_back()
|
||||
{
|
||||
ASSERT(!empty());
|
||||
remove(iterator(m_last, false));
|
||||
}
|
||||
|
||||
|
@ -221,10 +202,14 @@ namespace BAN
|
|||
LinkedList<T>::iterator LinkedList<T>::remove(iterator iter)
|
||||
{
|
||||
ASSERT(!empty() && iter);
|
||||
Node* node = remove_node(iter);
|
||||
Node* node = iter.m_current;
|
||||
Node* prev = node->prev;
|
||||
Node* next = node->next;
|
||||
node->value.~T();
|
||||
BAN::deallocator(node);
|
||||
(prev ? prev->next : m_data) = next;
|
||||
(next ? next->prev : m_last) = prev;
|
||||
m_size--;
|
||||
return next ? iterator(next, false) : iterator(m_last, true);
|
||||
}
|
||||
|
||||
|
@ -244,16 +229,6 @@ namespace BAN
|
|||
m_size = 0;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
LinkedList<T>::iterator LinkedList<T>::move_element_to_other_linked_list(LinkedList& dest_list, iterator dest_iter, iterator src_iter)
|
||||
{
|
||||
ASSERT(!empty() && src_iter);
|
||||
Node* node = remove_node(src_iter);
|
||||
iterator ret = node->next ? iterator(node->next, false) : iterator(m_last, true);
|
||||
dest_list.insert_node(dest_iter, node);
|
||||
return ret;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
const T& LinkedList<T>::back() const
|
||||
{
|
||||
|
@ -308,13 +283,11 @@ namespace BAN
|
|||
}
|
||||
|
||||
template<typename T>
|
||||
template<typename... Args>
|
||||
ErrorOr<typename LinkedList<T>::Node*> LinkedList<T>::allocate_node(Args&&... args) const
|
||||
ErrorOr<typename LinkedList<T>::Node*> LinkedList<T>::allocate_node() const
|
||||
{
|
||||
Node* node = (Node*)BAN::allocator(sizeof(Node));
|
||||
if (node == nullptr)
|
||||
return Error::from_errno(ENOMEM);
|
||||
new (&node->value) T(forward<Args>(args)...);
|
||||
return Error::from_errno(ENOMEM);
|
||||
return node;
|
||||
}
|
||||
|
||||
|
@ -423,4 +396,4 @@ namespace BAN
|
|||
return m_current;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -1,47 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <BAN/Formatter.h>
|
||||
|
||||
namespace BAN
|
||||
{
|
||||
|
||||
struct MACAddress
|
||||
{
|
||||
uint8_t address[6];
|
||||
|
||||
constexpr bool operator==(const MACAddress& other) const
|
||||
{
|
||||
return
|
||||
address[0] == other.address[0] &&
|
||||
address[1] == other.address[1] &&
|
||||
address[2] == other.address[2] &&
|
||||
address[3] == other.address[3] &&
|
||||
address[4] == other.address[4] &&
|
||||
address[5] == other.address[5];
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
namespace BAN::Formatter
|
||||
{
|
||||
|
||||
template<typename F>
|
||||
void print_argument(F putc, const MACAddress& mac, const ValueFormat&)
|
||||
{
|
||||
ValueFormat format {
|
||||
.base = 16,
|
||||
.percision = 0,
|
||||
.fill = 2,
|
||||
.upper = true,
|
||||
};
|
||||
|
||||
print_argument(putc, mac.address[0], format);
|
||||
for (size_t i = 1; i < 6; i++)
|
||||
{
|
||||
putc(':');
|
||||
print_argument(putc, mac.address[i], format);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,6 +1,5 @@
|
|||
#pragma once
|
||||
|
||||
#include <BAN/Limits.h>
|
||||
#include <BAN/Traits.h>
|
||||
|
||||
#include <stddef.h>
|
||||
|
@ -9,12 +8,6 @@
|
|||
namespace BAN::Math
|
||||
{
|
||||
|
||||
template<typename T>
|
||||
inline constexpr T abs(T val)
|
||||
{
|
||||
return val < 0 ? -val : val;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline constexpr T min(T a, T b)
|
||||
{
|
||||
|
@ -66,38 +59,6 @@ namespace BAN::Math
|
|||
return (value & (value - 1)) == 0;
|
||||
}
|
||||
|
||||
template<BAN::integral T>
|
||||
static constexpr bool will_multiplication_overflow(T a, T b)
|
||||
{
|
||||
if (a == 0 || b == 0)
|
||||
return false;
|
||||
if ((a > 0) == (b > 0))
|
||||
return a > BAN::numeric_limits<T>::max() / b;
|
||||
else
|
||||
return a < BAN::numeric_limits<T>::min() / b;
|
||||
}
|
||||
|
||||
template<BAN::integral T>
|
||||
static constexpr bool will_addition_overflow(T a, T b)
|
||||
{
|
||||
if (a > 0 && b > 0)
|
||||
return a > BAN::numeric_limits<T>::max() - b;
|
||||
if (a < 0 && b < 0)
|
||||
return a < BAN::numeric_limits<T>::min() - b;
|
||||
return false;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
requires is_same_v<T, unsigned int> || is_same_v<T, unsigned long> || is_same_v<T, unsigned long long>
|
||||
inline constexpr T ilog2(T value)
|
||||
{
|
||||
if constexpr(is_same_v<T, unsigned int>)
|
||||
return sizeof(T) * 8 - __builtin_clz(value) - 1;
|
||||
if constexpr(is_same_v<T, unsigned long>)
|
||||
return sizeof(T) * 8 - __builtin_clzl(value) - 1;
|
||||
return sizeof(T) * 8 - __builtin_clzll(value) - 1;
|
||||
}
|
||||
|
||||
template<floating_point T>
|
||||
inline constexpr T log2(T value)
|
||||
{
|
||||
|
@ -141,4 +102,4 @@ namespace BAN::Math
|
|||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -27,3 +27,6 @@ namespace BAN
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
inline void* operator new(size_t, void* addr) { return addr; }
|
||||
inline void* operator new[](size_t, void* addr) { return addr; }
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
#include <BAN/Assert.h>
|
||||
#include <BAN/Move.h>
|
||||
#include <BAN/PlacementNew.h>
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
|
@ -13,35 +12,35 @@ namespace BAN
|
|||
class Optional
|
||||
{
|
||||
public:
|
||||
constexpr Optional();
|
||||
constexpr Optional(Optional&&);
|
||||
constexpr Optional(const Optional&);
|
||||
constexpr Optional(const T&);
|
||||
constexpr Optional(T&&);
|
||||
Optional();
|
||||
Optional(Optional&&);
|
||||
Optional(const Optional&);
|
||||
Optional(const T&);
|
||||
Optional(T&&);
|
||||
template<typename... Args>
|
||||
constexpr Optional(Args&&...);
|
||||
Optional(Args&&...);
|
||||
|
||||
~Optional();
|
||||
|
||||
constexpr Optional& operator=(Optional&&);
|
||||
constexpr Optional& operator=(const Optional&);
|
||||
Optional& operator=(Optional&&);
|
||||
Optional& operator=(const Optional&);
|
||||
|
||||
template<typename... Args>
|
||||
constexpr Optional& emplace(Args&&...);
|
||||
Optional& emplace(Args&&...);
|
||||
|
||||
constexpr T* operator->();
|
||||
constexpr const T* operator->() const;
|
||||
T* operator->();
|
||||
const T* operator->() const;
|
||||
|
||||
constexpr T& operator*();
|
||||
constexpr const T& operator*() const;
|
||||
T& operator*();
|
||||
const T& operator*() const;
|
||||
|
||||
constexpr bool has_value() const;
|
||||
bool has_value() const;
|
||||
|
||||
constexpr T release_value();
|
||||
constexpr T& value();
|
||||
constexpr const T& value() const;
|
||||
T release_value();
|
||||
T& value();
|
||||
const T& value() const;
|
||||
|
||||
constexpr void clear();
|
||||
void clear();
|
||||
|
||||
private:
|
||||
alignas(T) uint8_t m_storage[sizeof(T)];
|
||||
|
@ -49,12 +48,12 @@ namespace BAN
|
|||
};
|
||||
|
||||
template<typename T>
|
||||
constexpr Optional<T>::Optional()
|
||||
Optional<T>::Optional()
|
||||
: m_has_value(false)
|
||||
{}
|
||||
|
||||
template<typename T>
|
||||
constexpr Optional<T>::Optional(Optional<T>&& other)
|
||||
Optional<T>::Optional(Optional<T>&& other)
|
||||
: m_has_value(other.has_value())
|
||||
{
|
||||
if (other.has_value())
|
||||
|
@ -62,7 +61,7 @@ namespace BAN
|
|||
}
|
||||
|
||||
template<typename T>
|
||||
constexpr Optional<T>::Optional(const Optional<T>& other)
|
||||
Optional<T>::Optional(const Optional<T>& other)
|
||||
: m_has_value(other.has_value())
|
||||
{
|
||||
if (other.has_value())
|
||||
|
@ -70,14 +69,14 @@ namespace BAN
|
|||
}
|
||||
|
||||
template<typename T>
|
||||
constexpr Optional<T>::Optional(const T& value)
|
||||
Optional<T>::Optional(const T& value)
|
||||
: m_has_value(true)
|
||||
{
|
||||
new (m_storage) T(value);
|
||||
new (m_storage) T(value);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
constexpr Optional<T>::Optional(T&& value)
|
||||
Optional<T>::Optional(T&& value)
|
||||
: m_has_value(true)
|
||||
{
|
||||
new (m_storage) T(move(value));
|
||||
|
@ -85,7 +84,7 @@ namespace BAN
|
|||
|
||||
template<typename T>
|
||||
template<typename... Args>
|
||||
constexpr Optional<T>::Optional(Args&&... args)
|
||||
Optional<T>::Optional(Args&&... args)
|
||||
: m_has_value(true)
|
||||
{
|
||||
new (m_storage) T(forward<Args>(args)...);
|
||||
|
@ -98,7 +97,7 @@ namespace BAN
|
|||
}
|
||||
|
||||
template<typename T>
|
||||
constexpr Optional<T>& Optional<T>::operator=(Optional&& other)
|
||||
Optional<T>& Optional<T>::operator=(Optional&& other)
|
||||
{
|
||||
clear();
|
||||
m_has_value = other.has_value();
|
||||
|
@ -108,7 +107,7 @@ namespace BAN
|
|||
}
|
||||
|
||||
template<typename T>
|
||||
constexpr Optional<T>& Optional<T>::operator=(const Optional& other)
|
||||
Optional<T>& Optional<T>::operator=(const Optional& other)
|
||||
{
|
||||
clear();
|
||||
m_has_value = other.has_value();
|
||||
|
@ -119,7 +118,7 @@ namespace BAN
|
|||
|
||||
template<typename T>
|
||||
template<typename... Args>
|
||||
constexpr Optional<T>& Optional<T>::emplace(Args&&... args)
|
||||
Optional<T>& Optional<T>::emplace(Args&&... args)
|
||||
{
|
||||
clear();
|
||||
m_has_value = true;
|
||||
|
@ -128,41 +127,41 @@ namespace BAN
|
|||
}
|
||||
|
||||
template<typename T>
|
||||
constexpr T* Optional<T>::operator->()
|
||||
T* Optional<T>::operator->()
|
||||
{
|
||||
ASSERT(has_value());
|
||||
return &value();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
constexpr const T* Optional<T>::operator->() const
|
||||
const T* Optional<T>::operator->() const
|
||||
{
|
||||
ASSERT(has_value());
|
||||
return &value();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
constexpr T& Optional<T>::operator*()
|
||||
T& Optional<T>::operator*()
|
||||
{
|
||||
ASSERT(has_value());
|
||||
return value();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
constexpr const T& Optional<T>::operator*() const
|
||||
const T& Optional<T>::operator*() const
|
||||
{
|
||||
ASSERT(has_value());
|
||||
return value();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
constexpr bool Optional<T>::has_value() const
|
||||
bool Optional<T>::has_value() const
|
||||
{
|
||||
return m_has_value;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
constexpr T Optional<T>::release_value()
|
||||
T Optional<T>::release_value()
|
||||
{
|
||||
ASSERT(has_value());
|
||||
T released_value = move(value());
|
||||
|
@ -172,25 +171,25 @@ namespace BAN
|
|||
}
|
||||
|
||||
template<typename T>
|
||||
constexpr T& Optional<T>::value()
|
||||
T& Optional<T>::value()
|
||||
{
|
||||
ASSERT(has_value());
|
||||
return (T&)m_storage;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
constexpr const T& Optional<T>::value() const
|
||||
const T& Optional<T>::value() const
|
||||
{
|
||||
ASSERT(has_value());
|
||||
return (const T&)m_storage;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
constexpr void Optional<T>::clear()
|
||||
void Optional<T>::clear()
|
||||
{
|
||||
if (m_has_value)
|
||||
value().~T();
|
||||
m_has_value = false;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -1,6 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
inline void* operator new(size_t, void* addr) { return addr; }
|
||||
inline void* operator new[](size_t, void* addr) { return addr; }
|
|
@ -5,7 +5,6 @@
|
|||
#include <BAN/Math.h>
|
||||
#include <BAN/Move.h>
|
||||
#include <BAN/New.h>
|
||||
#include <BAN/PlacementNew.h>
|
||||
|
||||
namespace BAN
|
||||
{
|
||||
|
@ -45,7 +44,6 @@ namespace BAN
|
|||
void clear();
|
||||
|
||||
bool empty() const;
|
||||
size_type capacity() const;
|
||||
size_type size() const;
|
||||
|
||||
const T& front() const;
|
||||
|
@ -187,12 +185,6 @@ namespace BAN
|
|||
return m_size == 0;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
typename Queue<T>::size_type Queue<T>::capacity() const
|
||||
{
|
||||
return m_capacity;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
typename Queue<T>::size_type Queue<T>::size() const
|
||||
{
|
||||
|
@ -233,4 +225,4 @@ namespace BAN
|
|||
return {};
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -1,6 +1,5 @@
|
|||
#pragma once
|
||||
|
||||
#include <BAN/Atomic.h>
|
||||
#include <BAN/Errors.h>
|
||||
#include <BAN/Move.h>
|
||||
#include <BAN/NoCopyMove.h>
|
||||
|
@ -23,36 +22,24 @@ namespace BAN
|
|||
|
||||
void ref() const
|
||||
{
|
||||
uint32_t old = m_ref_count.fetch_add(1, MemoryOrder::memory_order_relaxed);
|
||||
ASSERT(old > 0);
|
||||
}
|
||||
|
||||
bool try_ref() const
|
||||
{
|
||||
uint32_t expected = m_ref_count.load(MemoryOrder::memory_order_relaxed);
|
||||
for (;;)
|
||||
{
|
||||
if (expected == 0)
|
||||
return false;
|
||||
if (m_ref_count.compare_exchange(expected, expected + 1, MemoryOrder::memory_order_acquire))
|
||||
return true;
|
||||
}
|
||||
ASSERT(m_ref_count > 0);
|
||||
m_ref_count++;
|
||||
}
|
||||
|
||||
void unref() const
|
||||
{
|
||||
uint32_t old = m_ref_count.fetch_sub(1);
|
||||
ASSERT(old > 0);
|
||||
if (old == 1)
|
||||
ASSERT(m_ref_count > 0);
|
||||
m_ref_count--;
|
||||
if (m_ref_count == 0)
|
||||
delete (const T*)this;
|
||||
}
|
||||
|
||||
protected:
|
||||
RefCounted() = default;
|
||||
virtual ~RefCounted() { ASSERT(m_ref_count == 0); }
|
||||
~RefCounted() { ASSERT(m_ref_count == 0); }
|
||||
|
||||
private:
|
||||
mutable Atomic<uint32_t> m_ref_count = 1;
|
||||
mutable uint32_t m_ref_count = 1;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
|
@ -137,11 +124,8 @@ namespace BAN
|
|||
T* operator->() { return ptr(); }
|
||||
const T* operator->() const { return ptr(); }
|
||||
|
||||
bool operator==(RefPtr other) const { return m_pointer == other.m_pointer; }
|
||||
bool operator!=(RefPtr other) const { return m_pointer != other.m_pointer; }
|
||||
|
||||
bool empty() const { return m_pointer == nullptr; }
|
||||
explicit operator bool() const { return m_pointer; }
|
||||
operator bool() const { return m_pointer; }
|
||||
|
||||
void clear()
|
||||
{
|
||||
|
|
|
@ -25,4 +25,4 @@ namespace BAN
|
|||
bool m_enabled { true };
|
||||
};
|
||||
|
||||
}
|
||||
}
|
|
@ -1,240 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <BAN/Math.h>
|
||||
#include <BAN/Swap.h>
|
||||
#include <BAN/Traits.h>
|
||||
#include <BAN/Vector.h>
|
||||
|
||||
namespace BAN::sort
|
||||
{
|
||||
|
||||
template<typename It, typename Comp = less<typename It::value_type>>
|
||||
void exchange_sort(It begin, It end, Comp comp = {})
|
||||
{
|
||||
for (It lhs = begin; lhs != end; ++lhs)
|
||||
for (It rhs = next(lhs, 1); rhs != end; ++rhs)
|
||||
if (!comp(*lhs, *rhs))
|
||||
swap(*lhs, *rhs);
|
||||
}
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
template<typename It, typename Comp>
|
||||
It partition(It begin, It end, Comp comp)
|
||||
{
|
||||
It pivot = prev(end, 1);
|
||||
|
||||
It it1 = begin;
|
||||
for (It it2 = begin; it2 != pivot; ++it2)
|
||||
{
|
||||
if (comp(*it2, *pivot))
|
||||
{
|
||||
swap(*it1, *it2);
|
||||
++it1;
|
||||
}
|
||||
}
|
||||
|
||||
swap(*it1, *pivot);
|
||||
|
||||
return it1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
template<typename It, typename Comp = less<typename It::value_type>>
|
||||
void quick_sort(It begin, It end, Comp comp = {})
|
||||
{
|
||||
if (distance(begin, end) <= 1)
|
||||
return;
|
||||
It mid = detail::partition(begin, end, comp);
|
||||
quick_sort(begin, mid, comp);
|
||||
quick_sort(++mid, end, comp);
|
||||
}
|
||||
|
||||
template<typename It, typename Comp = less<typename It::value_type>>
|
||||
void insertion_sort(It begin, It end, Comp comp = {})
|
||||
{
|
||||
if (distance(begin, end) <= 1)
|
||||
return;
|
||||
for (It it1 = next(begin, 1); it1 != end; ++it1)
|
||||
{
|
||||
typename It::value_type x = move(*it1);
|
||||
It it2 = it1;
|
||||
for (; it2 != begin && comp(x, *prev(it2, 1)); --it2)
|
||||
*it2 = move(*prev(it2, 1));
|
||||
*it2 = move(x);
|
||||
}
|
||||
}
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
template<typename It, typename Comp>
|
||||
void push_heap(It begin, size_t hole_index, size_t top_index, typename It::value_type value, Comp comp)
|
||||
{
|
||||
size_t parent = (hole_index - 1) / 2;
|
||||
while (hole_index > top_index && comp(*next(begin, parent), value))
|
||||
{
|
||||
*next(begin, hole_index) = move(*next(begin, parent));
|
||||
hole_index = parent;
|
||||
parent = (hole_index - 1) / 2;
|
||||
}
|
||||
*next(begin, hole_index) = move(value);
|
||||
}
|
||||
|
||||
template<typename It, typename Comp>
|
||||
void adjust_heap(It begin, size_t hole_index, size_t len, typename It::value_type value, Comp comp)
|
||||
{
|
||||
const size_t top_index = hole_index;
|
||||
size_t child = hole_index;
|
||||
while (child < (len - 1) / 2)
|
||||
{
|
||||
child = 2 * (child + 1);
|
||||
if (comp(*next(begin, child), *next(begin, child - 1)))
|
||||
child--;
|
||||
*next(begin, hole_index) = move(*next(begin, child));
|
||||
hole_index = child;
|
||||
}
|
||||
if (len % 2 == 0 && child == (len - 2) / 2)
|
||||
{
|
||||
child = 2 * (child + 1);
|
||||
*next(begin, hole_index) = move(*next(begin, child - 1));
|
||||
hole_index = child - 1;
|
||||
}
|
||||
push_heap(begin, hole_index, top_index, move(value), comp);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
template<typename It, typename Comp = less<typename It::value_type>>
|
||||
void make_heap(It begin, It end, Comp comp = {})
|
||||
{
|
||||
const size_t len = distance(begin, end);
|
||||
if (len <= 1)
|
||||
return;
|
||||
|
||||
size_t parent = (len - 2) / 2;
|
||||
while (true)
|
||||
{
|
||||
detail::adjust_heap(begin, parent, len, move(*next(begin, parent)), comp);
|
||||
|
||||
if (parent == 0)
|
||||
break;
|
||||
|
||||
parent--;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename It, typename Comp = less<typename It::value_type>>
|
||||
void sort_heap(It begin, It end, Comp comp = {})
|
||||
{
|
||||
const size_t len = distance(begin, end);
|
||||
if (len <= 1)
|
||||
return;
|
||||
|
||||
size_t last = len;
|
||||
while (last > 1)
|
||||
{
|
||||
last--;
|
||||
typename It::value_type x = move(*next(begin, last));
|
||||
*next(begin, last) = move(*begin);
|
||||
detail::adjust_heap(begin, 0, last, move(x), comp);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename It, typename Comp = less<typename It::value_type>>
|
||||
void heap_sort(It begin, It end, Comp comp = {})
|
||||
{
|
||||
make_heap(begin, end, comp);
|
||||
sort_heap(begin, end, comp);
|
||||
}
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
template<typename It, typename Comp>
|
||||
void intro_sort_impl(It begin, It end, size_t max_depth, Comp comp)
|
||||
{
|
||||
if (distance(begin, end) <= 16)
|
||||
return insertion_sort(begin, end, comp);
|
||||
if (max_depth == 0)
|
||||
return heap_sort(begin, end, comp);
|
||||
It mid = detail::partition(begin, end, comp);
|
||||
intro_sort_impl(begin, mid, max_depth - 1, comp);
|
||||
intro_sort_impl(++mid, end, max_depth - 1, comp);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
template<typename It, typename Comp = less<typename It::value_type>>
|
||||
void intro_sort(It begin, It end, Comp comp = {})
|
||||
{
|
||||
const size_t len = distance(begin, end);
|
||||
if (len <= 1)
|
||||
return;
|
||||
detail::intro_sort_impl(begin, end, 2 * Math::ilog2(len), comp);
|
||||
}
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
template<unsigned_integral T>
|
||||
consteval T lsb_index(T value)
|
||||
{
|
||||
for (T result = 0;; result++)
|
||||
if (value & (1 << result))
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
template<typename It, size_t radix = 256>
|
||||
requires is_unsigned_v<typename It::value_type> && (radix > 0 && (radix & (radix - 1)) == 0)
|
||||
BAN::ErrorOr<void> radix_sort(It begin, It end)
|
||||
{
|
||||
using value_type = typename It::value_type;
|
||||
|
||||
const size_t len = distance(begin, end);
|
||||
if (len <= 1)
|
||||
return {};
|
||||
|
||||
Vector<value_type> temp;
|
||||
TRY(temp.resize(len));
|
||||
|
||||
Vector<size_t> counts;
|
||||
TRY(counts.resize(radix));
|
||||
|
||||
constexpr size_t mask = radix - 1;
|
||||
constexpr size_t shift = detail::lsb_index(radix);
|
||||
|
||||
for (size_t s = 0; s < sizeof(value_type) * 8; s += shift)
|
||||
{
|
||||
for (auto& cnt : counts)
|
||||
cnt = 0;
|
||||
for (It it = begin; it != end; ++it)
|
||||
counts[(*it >> s) & mask]++;
|
||||
|
||||
for (size_t i = 0; i < radix - 1; i++)
|
||||
counts[i + 1] += counts[i];
|
||||
|
||||
for (It it = end; it != begin;)
|
||||
{
|
||||
--it;
|
||||
temp[--counts[(*it >> s) & mask]] = *it;
|
||||
}
|
||||
|
||||
for (size_t j = 0; j < temp.size(); j++)
|
||||
*next(begin, j) = temp[j];
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
template<typename It, typename Comp = less<typename It::value_type>>
|
||||
void sort(It begin, It end, Comp comp = {})
|
||||
{
|
||||
return intro_sort(begin, end, comp);
|
||||
}
|
||||
|
||||
}
|
|
@ -131,4 +131,4 @@ namespace BAN
|
|||
return Span(m_data + start, length);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -2,10 +2,9 @@
|
|||
|
||||
#include <BAN/Errors.h>
|
||||
#include <BAN/Formatter.h>
|
||||
#include <BAN/ForwardList.h>
|
||||
#include <BAN/Hash.h>
|
||||
#include <BAN/Iterators.h>
|
||||
#include <BAN/New.h>
|
||||
#include <BAN/StringView.h>
|
||||
|
||||
namespace BAN
|
||||
{
|
||||
|
@ -19,130 +18,28 @@ namespace BAN
|
|||
static constexpr size_type sso_capacity = 15;
|
||||
|
||||
public:
|
||||
String() {}
|
||||
String(const String& other) { *this = other; }
|
||||
String(String&& other) { *this = move(other); }
|
||||
String(StringView other) { *this = other; }
|
||||
~String() { clear(); }
|
||||
String();
|
||||
String(const String&);
|
||||
String(String&&);
|
||||
String(StringView);
|
||||
~String();
|
||||
|
||||
template<typename... Args>
|
||||
static BAN::ErrorOr<String> formatted(const char* format, Args&&... args)
|
||||
{
|
||||
size_type length = 0;
|
||||
BAN::Formatter::print([&](char) { length++; }, format, BAN::forward<Args>(args)...);
|
||||
static String formatted(const char* format, const Args&... args);
|
||||
|
||||
String result;
|
||||
TRY(result.reserve(length));
|
||||
BAN::Formatter::print([&](char c){ MUST(result.push_back(c)); }, format, BAN::forward<Args>(args)...);
|
||||
String& operator=(const String&);
|
||||
String& operator=(String&&);
|
||||
String& operator=(StringView);
|
||||
|
||||
return result;
|
||||
}
|
||||
ErrorOr<void> push_back(char);
|
||||
ErrorOr<void> insert(char, size_type);
|
||||
ErrorOr<void> insert(StringView, size_type);
|
||||
ErrorOr<void> append(StringView);
|
||||
|
||||
String& operator=(const String& other)
|
||||
{
|
||||
clear();
|
||||
MUST(ensure_capacity(other.size()));
|
||||
memcpy(data(), other.data(), other.size() + 1);
|
||||
m_size = other.size();
|
||||
return *this;
|
||||
}
|
||||
void pop_back();
|
||||
void remove(size_type);
|
||||
|
||||
String& operator=(String&& other)
|
||||
{
|
||||
clear();
|
||||
|
||||
if (other.has_sso())
|
||||
memcpy(data(), other.data(), other.size() + 1);
|
||||
else
|
||||
{
|
||||
m_storage.general_storage = other.m_storage.general_storage;
|
||||
m_has_sso = false;
|
||||
}
|
||||
m_size = other.m_size;
|
||||
|
||||
other.m_size = 0;
|
||||
other.m_storage.sso_storage = SSOStorage();
|
||||
other.m_has_sso = true;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
String& operator=(StringView other)
|
||||
{
|
||||
clear();
|
||||
MUST(ensure_capacity(other.size()));
|
||||
memcpy(data(), other.data(), other.size());
|
||||
m_size = other.size();
|
||||
data()[m_size] = '\0';
|
||||
return *this;
|
||||
}
|
||||
|
||||
ErrorOr<void> push_back(char c)
|
||||
{
|
||||
TRY(ensure_capacity(m_size + 1));
|
||||
data()[m_size] = c;
|
||||
m_size++;
|
||||
data()[m_size] = '\0';
|
||||
return {};
|
||||
}
|
||||
|
||||
ErrorOr<void> insert(char c, size_type index)
|
||||
{
|
||||
ASSERT(index <= m_size);
|
||||
TRY(ensure_capacity(m_size + 1));
|
||||
memmove(data() + index + 1, data() + index, m_size - index);
|
||||
data()[index] = c;
|
||||
m_size++;
|
||||
data()[m_size] = '\0';
|
||||
return {};
|
||||
}
|
||||
|
||||
ErrorOr<void> insert(StringView str, size_type index)
|
||||
{
|
||||
ASSERT(index <= m_size);
|
||||
TRY(ensure_capacity(m_size + str.size()));
|
||||
memmove(data() + index + str.size(), data() + index, m_size - index);
|
||||
memcpy(data() + index, str.data(), str.size());
|
||||
m_size += str.size();
|
||||
data()[m_size] = '\0';
|
||||
return {};
|
||||
}
|
||||
|
||||
ErrorOr<void> append(StringView str)
|
||||
{
|
||||
TRY(ensure_capacity(m_size + str.size()));
|
||||
memcpy(data() + m_size, str.data(), str.size());
|
||||
m_size += str.size();
|
||||
data()[m_size] = '\0';
|
||||
return {};
|
||||
}
|
||||
|
||||
void pop_back()
|
||||
{
|
||||
ASSERT(m_size > 0);
|
||||
m_size--;
|
||||
data()[m_size] = '\0';
|
||||
}
|
||||
|
||||
void remove(size_type index)
|
||||
{
|
||||
ASSERT(index < m_size);
|
||||
memcpy(data() + index, data() + index + 1, m_size - index);
|
||||
m_size--;
|
||||
data()[m_size] = '\0';
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
if (!has_sso())
|
||||
{
|
||||
deallocator(m_storage.general_storage.data);
|
||||
m_storage.sso_storage = SSOStorage();
|
||||
m_has_sso = true;
|
||||
}
|
||||
m_size = 0;
|
||||
data()[m_size] = '\0';
|
||||
}
|
||||
void clear();
|
||||
|
||||
const_iterator begin() const { return const_iterator(data()); }
|
||||
iterator begin() { return iterator(data()); }
|
||||
|
@ -158,151 +55,26 @@ namespace BAN
|
|||
char operator[](size_type index) const { ASSERT(index < m_size); return data()[index]; }
|
||||
char& operator[](size_type index) { ASSERT(index < m_size); return data()[index]; }
|
||||
|
||||
bool operator==(const String& str) const
|
||||
{
|
||||
if (size() != str.size())
|
||||
return false;
|
||||
for (size_type i = 0; i < m_size; i++)
|
||||
if (data()[i] != str.data()[i])
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
bool operator==(StringView) const;
|
||||
bool operator==(const char*) const;
|
||||
|
||||
bool operator==(StringView str) const
|
||||
{
|
||||
if (size() != str.size())
|
||||
return false;
|
||||
for (size_type i = 0; i < m_size; i++)
|
||||
if (data()[i] != str.data()[i])
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool operator==(const char* cstr) const
|
||||
{
|
||||
for (size_type i = 0; i < m_size; i++)
|
||||
if (data()[i] != cstr[i])
|
||||
return false;
|
||||
if (cstr[size()] != '\0')
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
ErrorOr<void> resize(size_type new_size, char init_c = '\0')
|
||||
{
|
||||
if (m_size == new_size)
|
||||
return {};
|
||||
|
||||
// expanding
|
||||
if (m_size < new_size)
|
||||
{
|
||||
TRY(ensure_capacity(new_size));
|
||||
memset(data() + m_size, init_c, new_size - m_size);
|
||||
m_size = new_size;
|
||||
data()[m_size] = '\0';
|
||||
return {};
|
||||
}
|
||||
|
||||
m_size = new_size;
|
||||
data()[m_size] = '\0';
|
||||
return {};
|
||||
}
|
||||
|
||||
ErrorOr<void> reserve(size_type new_size)
|
||||
{
|
||||
TRY(ensure_capacity(new_size));
|
||||
return {};
|
||||
}
|
||||
|
||||
ErrorOr<void> shrink_to_fit()
|
||||
{
|
||||
if (has_sso())
|
||||
return {};
|
||||
|
||||
if (fits_in_sso())
|
||||
{
|
||||
char* data = m_storage.general_storage.data;
|
||||
m_storage.sso_storage = SSOStorage();
|
||||
m_has_sso = true;
|
||||
memcpy(this->data(), data, m_size + 1);
|
||||
deallocator(data);
|
||||
return {};
|
||||
}
|
||||
|
||||
GeneralStorage& storage = m_storage.general_storage;
|
||||
if (storage.capacity == m_size)
|
||||
return {};
|
||||
|
||||
char* new_data = (char*)allocator(m_size + 1);
|
||||
if (new_data == nullptr)
|
||||
return Error::from_errno(ENOMEM);
|
||||
|
||||
memcpy(new_data, storage.data, m_size);
|
||||
deallocator(storage.data);
|
||||
|
||||
storage.capacity = m_size;
|
||||
storage.data = new_data;
|
||||
|
||||
return {};
|
||||
}
|
||||
ErrorOr<void> resize(size_type, char = '\0');
|
||||
ErrorOr<void> reserve(size_type);
|
||||
ErrorOr<void> shrink_to_fit();
|
||||
|
||||
StringView sv() const { return StringView(data(), size()); }
|
||||
|
||||
bool empty() const { return m_size == 0; }
|
||||
size_type size() const { return m_size; }
|
||||
size_type capacity() const;
|
||||
|
||||
size_type capacity() const
|
||||
{
|
||||
if (has_sso())
|
||||
return sso_capacity;
|
||||
return m_storage.general_storage.capacity;
|
||||
}
|
||||
|
||||
char* data()
|
||||
{
|
||||
if (has_sso())
|
||||
return m_storage.sso_storage.data;
|
||||
return m_storage.general_storage.data;
|
||||
}
|
||||
|
||||
const char* data() const
|
||||
{
|
||||
if (has_sso())
|
||||
return m_storage.sso_storage.data;
|
||||
return m_storage.general_storage.data;
|
||||
}
|
||||
char* data();
|
||||
const char* data() const;
|
||||
|
||||
private:
|
||||
ErrorOr<void> ensure_capacity(size_type new_size)
|
||||
{
|
||||
if (m_size >= new_size)
|
||||
return {};
|
||||
if (has_sso() && fits_in_sso(new_size))
|
||||
return {};
|
||||
ErrorOr<void> ensure_capacity(size_type);
|
||||
|
||||
char* new_data = (char*)allocator(new_size + 1);
|
||||
if (new_data == nullptr)
|
||||
return Error::from_errno(ENOMEM);
|
||||
|
||||
if (m_size)
|
||||
memcpy(new_data, data(), m_size + 1);
|
||||
|
||||
if (has_sso())
|
||||
{
|
||||
m_storage.general_storage = GeneralStorage();
|
||||
m_has_sso = false;
|
||||
}
|
||||
else
|
||||
deallocator(m_storage.general_storage.data);
|
||||
|
||||
auto& storage = m_storage.general_storage;
|
||||
storage.capacity = new_size;
|
||||
storage.data = new_data;
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
bool has_sso() const { return m_has_sso; }
|
||||
bool has_sso() const;
|
||||
|
||||
bool fits_in_sso() const { return fits_in_sso(m_size); }
|
||||
static bool fits_in_sso(size_type size) { return size < sso_capacity; }
|
||||
|
@ -327,6 +99,14 @@ namespace BAN
|
|||
size_type m_has_sso : 1 { true };
|
||||
};
|
||||
|
||||
template<typename... Args>
|
||||
String String::formatted(const char* format, const Args&... args)
|
||||
{
|
||||
String result;
|
||||
BAN::Formatter::print([&](char c){ MUST(result.push_back(c)); }, format, args...);
|
||||
return result;
|
||||
}
|
||||
|
||||
template<>
|
||||
struct hash<String>
|
||||
{
|
||||
|
|
|
@ -1,11 +1,8 @@
|
|||
#pragma once
|
||||
|
||||
#include <BAN/Formatter.h>
|
||||
#include <BAN/ForwardList.h>
|
||||
#include <BAN/Hash.h>
|
||||
#include <BAN/Formatter.h>
|
||||
#include <BAN/Iterators.h>
|
||||
#include <BAN/Optional.h>
|
||||
#include <BAN/Vector.h>
|
||||
|
||||
namespace BAN
|
||||
{
|
||||
|
@ -17,234 +14,43 @@ namespace BAN
|
|||
using const_iterator = ConstIteratorSimple<char, StringView>;
|
||||
|
||||
public:
|
||||
constexpr StringView() {}
|
||||
constexpr StringView(const char* string, size_type len = -1)
|
||||
{
|
||||
if (len == size_type(-1))
|
||||
len = strlen(string);
|
||||
m_data = string;
|
||||
m_size = len;
|
||||
}
|
||||
StringView();
|
||||
StringView(const String&);
|
||||
StringView(const char*, size_type = -1);
|
||||
|
||||
constexpr const_iterator begin() const { return const_iterator(m_data); }
|
||||
constexpr const_iterator end() const { return const_iterator(m_data + m_size); }
|
||||
const_iterator begin() const { return const_iterator(m_data); }
|
||||
const_iterator end() const { return const_iterator(m_data + m_size); }
|
||||
|
||||
constexpr char operator[](size_type index) const
|
||||
{
|
||||
ASSERT(index < m_size);
|
||||
return m_data[index];
|
||||
}
|
||||
char operator[](size_type) const;
|
||||
|
||||
constexpr bool operator==(StringView other) const
|
||||
{
|
||||
if (m_size != other.m_size)
|
||||
return false;
|
||||
for (size_type i = 0; i < m_size; i++)
|
||||
if (m_data[i] != other.m_data[i])
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
bool operator==(const String&) const;
|
||||
bool operator==(StringView) const;
|
||||
bool operator==(const char*) const;
|
||||
|
||||
constexpr bool operator==(const char* other) const
|
||||
{
|
||||
for (size_type i = 0; i < m_size; i++)
|
||||
if (m_data[i] != other[i])
|
||||
return false;
|
||||
return other[m_size] == '\0';
|
||||
}
|
||||
StringView substring(size_type, size_type = -1) const;
|
||||
|
||||
constexpr StringView substring(size_type index, size_type len = -1) const
|
||||
{
|
||||
ASSERT(index <= m_size);
|
||||
if (len == size_type(-1))
|
||||
len = m_size - index;
|
||||
ASSERT(len <= m_size - index); // weird order to avoid overflow
|
||||
StringView result;
|
||||
result.m_data = m_data + index;
|
||||
result.m_size = len;
|
||||
return result;
|
||||
}
|
||||
ErrorOr<Vector<StringView>> split(char, bool = false);
|
||||
ErrorOr<Vector<StringView>> split(bool(*comp)(char), bool = false);
|
||||
|
||||
ErrorOr<Vector<StringView>> split(char delim, bool allow_empties = false) const
|
||||
{
|
||||
size_type count = 0;
|
||||
{
|
||||
size_type start = 0;
|
||||
for (size_type i = 0; i < m_size; i++)
|
||||
{
|
||||
if (m_data[i] == delim)
|
||||
{
|
||||
if (allow_empties || start != i)
|
||||
count++;
|
||||
start = i + 1;
|
||||
}
|
||||
}
|
||||
if (start != m_size)
|
||||
count++;
|
||||
}
|
||||
char back() const;
|
||||
char front() const;
|
||||
|
||||
Vector<StringView> result;
|
||||
TRY(result.reserve(count));
|
||||
bool contains(char) const;
|
||||
size_type count(char) const;
|
||||
|
||||
size_type start = 0;
|
||||
for (size_type i = 0; i < m_size; i++)
|
||||
{
|
||||
if (m_data[i] == delim)
|
||||
{
|
||||
if (allow_empties || start != i)
|
||||
TRY(result.push_back(this->substring(start, i - start)));
|
||||
start = i + 1;
|
||||
}
|
||||
}
|
||||
if (start < m_size || (start == m_size && allow_empties))
|
||||
TRY(result.push_back(this->substring(start)));
|
||||
return result;
|
||||
}
|
||||
|
||||
ErrorOr<Vector<StringView>> split(bool(*comp)(char), bool allow_empties = false) const
|
||||
{
|
||||
size_type count = 0;
|
||||
{
|
||||
size_type start = 0;
|
||||
for (size_type i = 0; i < m_size; i++)
|
||||
{
|
||||
if (comp(m_data[i]))
|
||||
{
|
||||
if (allow_empties || start != i)
|
||||
count++;
|
||||
start = i + 1;
|
||||
}
|
||||
}
|
||||
if (start != m_size)
|
||||
count++;
|
||||
}
|
||||
|
||||
Vector<StringView> result;
|
||||
TRY(result.reserve(count));
|
||||
|
||||
size_type start = 0;
|
||||
for (size_type i = 0; i < m_size; i++)
|
||||
{
|
||||
if (comp(m_data[i]))
|
||||
{
|
||||
if (allow_empties || start != i)
|
||||
TRY(result.push_back(this->substring(start, i - start)));
|
||||
start = i + 1;
|
||||
}
|
||||
}
|
||||
if (start < m_size || (start == m_size && allow_empties))
|
||||
TRY(result.push_back(this->substring(start)));
|
||||
return result;
|
||||
}
|
||||
|
||||
constexpr char back() const
|
||||
{
|
||||
ASSERT(m_size > 0);
|
||||
return m_data[m_size - 1];
|
||||
}
|
||||
|
||||
constexpr char front() const
|
||||
{
|
||||
ASSERT(m_size > 0);
|
||||
return m_data[0];
|
||||
}
|
||||
|
||||
BAN::Optional<size_type> find(char ch) const
|
||||
{
|
||||
for (size_type i = 0; i < m_size; i++)
|
||||
if (m_data[i] == ch)
|
||||
return i;
|
||||
return {};
|
||||
}
|
||||
|
||||
BAN::Optional<size_type> find(bool(*comp)(char)) const
|
||||
{
|
||||
for (size_type i = 0; i < m_size; i++)
|
||||
if (comp(m_data[i]))
|
||||
return i;
|
||||
return {};
|
||||
}
|
||||
|
||||
BAN::Optional<size_type> rfind(char ch) const
|
||||
{
|
||||
for (size_type i = m_size; i > 0; i--)
|
||||
if (m_data[i - 1] == ch)
|
||||
return i - 1;
|
||||
return {};
|
||||
}
|
||||
|
||||
BAN::Optional<size_type> rfind(bool(*comp)(char)) const
|
||||
{
|
||||
for (size_type i = m_size; i > 0; i--)
|
||||
if (comp(m_data[i - 1]))
|
||||
return i - 1;
|
||||
return {};
|
||||
}
|
||||
|
||||
constexpr bool starts_with(BAN::StringView target) const
|
||||
{
|
||||
if (target.size() > m_size)
|
||||
return false;
|
||||
for (size_type i = 0; i < m_size - target.size(); i++)
|
||||
{
|
||||
bool valid = true;
|
||||
for (size_type j = 0; j < target.size() && valid; j++)
|
||||
valid = (m_data[i + j] == target[j]);
|
||||
if (valid)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
constexpr bool contains(char ch) const
|
||||
{
|
||||
for (size_type i = 0; i < m_size; i++)
|
||||
if (m_data[i] == ch)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
constexpr size_type count(char ch) const
|
||||
{
|
||||
size_type result = 0;
|
||||
for (size_type i = 0; i < m_size; i++)
|
||||
if (m_data[i] == ch)
|
||||
result++;
|
||||
return result;
|
||||
}
|
||||
|
||||
constexpr bool empty() const { return m_size == 0; }
|
||||
constexpr size_type size() const { return m_size; }
|
||||
constexpr const char* data() const { return m_data; }
|
||||
bool empty() const;
|
||||
size_type size() const;
|
||||
|
||||
const char* data() const;
|
||||
|
||||
private:
|
||||
const char* m_data = nullptr;
|
||||
size_type m_size = 0;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct hash<StringView>
|
||||
{
|
||||
hash_t operator()(StringView string) const
|
||||
{
|
||||
constexpr hash_t FNV_offset_basis = 0x811c9dc5;
|
||||
constexpr hash_t FNV_prime = 0x01000193;
|
||||
|
||||
hash_t hash = FNV_offset_basis;
|
||||
for (StringView::size_type i = 0; i < string.size(); i++)
|
||||
{
|
||||
hash *= FNV_prime;
|
||||
hash ^= (uint8_t)string[i];
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
inline constexpr BAN::StringView operator""_sv(const char* str, BAN::StringView::size_type len) { return BAN::StringView(str, len); }
|
||||
inline BAN::StringView operator""sv(const char* str, BAN::StringView::size_type len) { return BAN::StringView(str, len); }
|
||||
|
||||
namespace BAN::Formatter
|
||||
{
|
||||
|
|
|
@ -1,16 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <BAN/Move.h>
|
||||
|
||||
namespace BAN
|
||||
{
|
||||
|
||||
template<typename T>
|
||||
void swap(T& lhs, T& rhs)
|
||||
{
|
||||
T tmp = move(lhs);
|
||||
lhs = move(rhs);
|
||||
rhs = move(tmp);
|
||||
}
|
||||
|
||||
}
|
|
@ -34,4 +34,4 @@ namespace BAN::Formatter
|
|||
print(putc, "{} {} {} {2}:{2}:{2} GMT+0 {4}", week_days[time.week_day], months[time.month], time.day, time.hour, time.minute, time.second, time.year);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -34,33 +34,18 @@ namespace BAN
|
|||
template<typename T1, typename T2> struct either_or<true, T1, T2> { using type = T1; };
|
||||
template<bool B, typename T1, typename T2> using either_or_t = typename either_or<B, T1, T2>::type;
|
||||
|
||||
template<typename T, T V> struct integral_constant { static constexpr T value = V; };
|
||||
template<typename T, T V > inline constexpr T integral_constant_v = integral_constant<T, V>::value;
|
||||
using true_type = integral_constant<bool, true>;
|
||||
using false_type = integral_constant<bool, false>;
|
||||
struct true_type { static constexpr bool value = true; };
|
||||
struct false_type { static constexpr bool value = false; };
|
||||
|
||||
template<typename T, typename S> struct is_same : false_type {};
|
||||
template<typename T> struct is_same<T, T> : true_type {};
|
||||
template<typename T, typename S> inline constexpr bool is_same_v = is_same<T, S>::value;
|
||||
template<typename T, typename S> concept same_as = BAN::is_same_v<T, S>;
|
||||
|
||||
template<typename T> struct is_lvalue_reference : false_type {};
|
||||
template<typename T> struct is_lvalue_reference<T&> : true_type {};
|
||||
template<typename T> inline constexpr bool is_lvalue_reference_v = is_lvalue_reference<T>::value;
|
||||
template<typename T> concept lvalue_reference = is_lvalue_reference_v<T>;
|
||||
|
||||
template<typename T, typename... Args> struct is_constructible { static constexpr bool value = __is_constructible(T, Args...); };
|
||||
template<typename T, typename... Args> inline constexpr bool is_constructible_v = is_constructible<T, Args...>::value;
|
||||
|
||||
template<typename T> struct is_default_constructible { static constexpr bool value = is_constructible_v<T>; };
|
||||
template<typename T> inline constexpr bool is_default_constructible_v = is_default_constructible<T>::value;
|
||||
|
||||
template<typename T> struct is_copy_constructible { static constexpr bool value = is_constructible_v<T, const T&>; };
|
||||
template<typename T> inline constexpr bool is_copy_constructible_v = is_copy_constructible<T>::value;
|
||||
|
||||
template<typename T> struct is_move_constructible { static constexpr bool value = is_constructible_v<T, T&&>; };
|
||||
template<typename T> inline constexpr bool is_move_constructible_v = is_move_constructible<T>::value;
|
||||
|
||||
template<typename T> struct is_integral { static constexpr bool value = requires (T t, T* p, void (*f)(T)) { reinterpret_cast<T>(t); f(0); p + t; }; };
|
||||
template<typename T> inline constexpr bool is_integral_v = is_integral<T>::value;
|
||||
template<typename T> concept integral = is_integral_v<T>;
|
||||
|
@ -87,57 +72,16 @@ namespace BAN
|
|||
template<typename T> struct is_arithmetic { static constexpr bool value = is_integral_v<T> || is_floating_point_v<T>; };
|
||||
template<typename T> inline constexpr bool is_arithmetic_v = is_arithmetic<T>::value;
|
||||
|
||||
template<typename Base, typename Derived> struct is_base_of { static constexpr bool value = __is_base_of(Base, Derived); };
|
||||
template<typename Base, typename Derived> inline constexpr bool is_base_of_v = is_base_of<Base, Derived>::value;
|
||||
|
||||
namespace detail
|
||||
{
|
||||
template<typename T, bool = is_arithmetic_v<T>> struct is_signed { static constexpr bool value = T(-1) < T(0); };
|
||||
template<typename T> struct is_signed<T, false> : false_type {};
|
||||
|
||||
template<typename T, bool = is_arithmetic_v<T>> struct is_unsigned { static constexpr bool value = T(0) < T(-1); };
|
||||
template<typename T> struct is_unsigned<T, false> : false_type {};
|
||||
}
|
||||
template<typename T> struct is_signed : detail::is_signed<T> {};
|
||||
template<typename T> inline constexpr bool is_signed_v = is_signed<T>::value;
|
||||
template<typename T> concept signed_integral = is_signed_v<T> && is_integral_v<T>;
|
||||
|
||||
template<typename T> struct is_unsigned : detail::is_unsigned<T> {};
|
||||
template<typename T> inline constexpr bool is_unsigned_v = is_unsigned<T>::value;
|
||||
template<typename T> concept unsigned_integral = is_unsigned_v<T> && is_integral_v<T>;
|
||||
|
||||
#define __BAN_TRAITS_MAKE_UNSIGNED_CV(__type) \
|
||||
template<> struct make_unsigned<__type> { using type = unsigned __type; }; \
|
||||
template<> struct make_unsigned<const __type> { using type = unsigned const __type; }; \
|
||||
template<> struct make_unsigned<volatile __type> { using type = unsigned volatile __type; }; \
|
||||
template<> struct make_unsigned<const volatile __type> { using type = unsigned const volatile __type; };
|
||||
|
||||
template<typename T> requires is_arithmetic_v<T> struct make_unsigned { using type = T; };
|
||||
__BAN_TRAITS_MAKE_UNSIGNED_CV(char)
|
||||
__BAN_TRAITS_MAKE_UNSIGNED_CV(short)
|
||||
__BAN_TRAITS_MAKE_UNSIGNED_CV(int)
|
||||
__BAN_TRAITS_MAKE_UNSIGNED_CV(long)
|
||||
__BAN_TRAITS_MAKE_UNSIGNED_CV(long long)
|
||||
template<typename T> using make_unsigned_t = typename make_unsigned<T>::type;
|
||||
#undef __BAN_TRAITS_MAKE_UNSIGNED_CV
|
||||
|
||||
#define __BAN_TRAITS_MAKE_SIGNED_CV(__type) \
|
||||
template<> struct make_signed<unsigned __type> { using type = __type; }; \
|
||||
template<> struct make_signed<unsigned const __type> { using type = const __type; }; \
|
||||
template<> struct make_signed<unsigned volatile __type> { using type = volatile __type; }; \
|
||||
template<> struct make_signed<unsigned const volatile __type> { using type = const volatile __type; };
|
||||
|
||||
template<typename T> requires is_arithmetic_v<T> struct make_signed { using type = T; };
|
||||
__BAN_TRAITS_MAKE_SIGNED_CV(char)
|
||||
__BAN_TRAITS_MAKE_SIGNED_CV(short)
|
||||
__BAN_TRAITS_MAKE_SIGNED_CV(int)
|
||||
__BAN_TRAITS_MAKE_SIGNED_CV(long)
|
||||
__BAN_TRAITS_MAKE_SIGNED_CV(long long)
|
||||
template<typename T> using make_signed_t = typename make_signed<T>::type;
|
||||
#undef __BAN_TRAITS_MAKE_SIGNED_CV
|
||||
|
||||
template<typename T> struct less { constexpr bool operator()(const T& lhs, const T& rhs) const { return lhs < rhs; } };
|
||||
template<typename T> struct equal { constexpr bool operator()(const T& lhs, const T& rhs) const { return lhs == rhs; } };
|
||||
template<typename T> struct greater { constexpr bool operator()(const T& lhs, const T& rhs) const { return lhs > rhs; } };
|
||||
|
||||
}
|
||||
}
|
|
@ -21,21 +21,20 @@ namespace BAN::UTF8
|
|||
return 0;
|
||||
}
|
||||
|
||||
template<typename T> requires (sizeof(T) == 1)
|
||||
constexpr uint32_t to_codepoint(const T* bytes)
|
||||
constexpr uint32_t to_codepoint(uint8_t* bytes)
|
||||
{
|
||||
uint32_t length = byte_length(bytes[0]);
|
||||
|
||||
for (uint32_t i = 1; i < length; i++)
|
||||
if (((uint8_t)bytes[i] & 0xC0) != 0x80)
|
||||
if ((bytes[i] & 0xC0) != 0x80)
|
||||
return UTF8::invalid;
|
||||
|
||||
|
||||
switch (length)
|
||||
{
|
||||
case 1: return (((uint8_t)bytes[0] & 0x80) != 0x00) ? UTF8::invalid : (uint8_t)bytes[0];
|
||||
case 2: return (((uint8_t)bytes[0] & 0xE0) != 0xC0) ? UTF8::invalid : (((uint8_t)bytes[0] & 0x1F) << 6) | ((uint8_t)bytes[1] & 0x3F);
|
||||
case 3: return (((uint8_t)bytes[0] & 0xF0) != 0xE0) ? UTF8::invalid : (((uint8_t)bytes[0] & 0x0F) << 12) | (((uint8_t)bytes[1] & 0x3F) << 6) | ((uint8_t)bytes[2] & 0x3F);
|
||||
case 4: return (((uint8_t)bytes[0] & 0xF8) != 0xF0) ? UTF8::invalid : (((uint8_t)bytes[0] & 0x07) << 18) | (((uint8_t)bytes[1] & 0x3F) << 12) | (((uint8_t)bytes[2] & 0x3F) << 6) | ((uint8_t)bytes[3] & 0x3F);
|
||||
case 1: return ((bytes[0] & 0x80) != 0x00) ? UTF8::invalid : bytes[0];
|
||||
case 2: return ((bytes[0] & 0xE0) != 0xC0) ? UTF8::invalid : ((bytes[0] & 0x1F) << 6) | (bytes[1] & 0x3F);
|
||||
case 3: return ((bytes[0] & 0xF0) != 0xE0) ? UTF8::invalid : ((bytes[0] & 0x0F) << 12) | ((bytes[1] & 0x3F) << 6) | (bytes[2] & 0x3F);
|
||||
case 4: return ((bytes[0] & 0xF8) != 0xF0) ? UTF8::invalid : ((bytes[0] & 0x07) << 18) | ((bytes[1] & 0x3F) << 12) | ((bytes[2] & 0x3F) << 6) | (bytes[3] & 0x3F);
|
||||
}
|
||||
|
||||
return UTF8::invalid;
|
||||
|
@ -79,4 +78,4 @@ namespace BAN::UTF8
|
|||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -67,7 +67,7 @@ namespace BAN
|
|||
T* operator->()
|
||||
{
|
||||
ASSERT(m_pointer);
|
||||
return m_pointer;
|
||||
return m_pointer;
|
||||
}
|
||||
|
||||
const T* operator->() const
|
||||
|
@ -95,4 +95,4 @@ namespace BAN
|
|||
friend class UniqPtr;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
|
@ -3,7 +3,6 @@
|
|||
#include <BAN/Assert.h>
|
||||
#include <BAN/Math.h>
|
||||
#include <BAN/Move.h>
|
||||
#include <BAN/PlacementNew.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
|
@ -43,10 +42,9 @@ namespace BAN
|
|||
void destruct(size_t index, uint8_t* data)
|
||||
{
|
||||
if (index == 0)
|
||||
{
|
||||
if constexpr(!is_lvalue_reference_v<T>)
|
||||
reinterpret_cast<T*>(data)->~T();
|
||||
}
|
||||
else;
|
||||
else if constexpr(sizeof...(Ts) > 0)
|
||||
destruct<Ts...>(index - 1, data);
|
||||
else
|
||||
|
@ -140,14 +138,14 @@ namespace BAN
|
|||
Variant(T&& value) requires (can_have<T>() && !is_lvalue_reference_v<T>)
|
||||
: m_index(detail::index<T, Ts...>())
|
||||
{
|
||||
new (m_storage) T(move(value));
|
||||
new (m_storage) T(move(value));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
Variant(const T& value) requires (can_have<T>() && !is_lvalue_reference_v<T>)
|
||||
: m_index(detail::index<T, Ts...>())
|
||||
{
|
||||
new (m_storage) T(value);
|
||||
new (m_storage) T(value);
|
||||
}
|
||||
|
||||
~Variant()
|
||||
|
@ -216,14 +214,6 @@ namespace BAN
|
|||
return m_index == detail::index<T, Ts...>();
|
||||
}
|
||||
|
||||
template<typename T, typename... Args>
|
||||
void emplace(Args&&... args) requires (can_have<T>())
|
||||
{
|
||||
clear();
|
||||
m_index = detail::index<T, Ts...>();
|
||||
new (m_storage) T(BAN::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void set(T&& value) requires (can_have<T>() && !is_lvalue_reference_v<T>)
|
||||
{
|
||||
|
@ -300,4 +290,4 @@ namespace BAN
|
|||
size_t m_index { invalid_index() };
|
||||
};
|
||||
|
||||
}
|
||||
}
|
|
@ -5,7 +5,6 @@
|
|||
#include <BAN/Math.h>
|
||||
#include <BAN/Move.h>
|
||||
#include <BAN/New.h>
|
||||
#include <BAN/PlacementNew.h>
|
||||
#include <BAN/Span.h>
|
||||
|
||||
namespace BAN
|
||||
|
@ -39,7 +38,7 @@ namespace BAN
|
|||
ErrorOr<void> emplace(size_type, Args&&...);
|
||||
ErrorOr<void> insert(size_type, T&&);
|
||||
ErrorOr<void> insert(size_type, const T&);
|
||||
|
||||
|
||||
iterator begin() { return iterator(m_data); }
|
||||
iterator end() { return iterator(m_data + m_size); }
|
||||
const_iterator begin() const { return const_iterator(m_data); }
|
||||
|
@ -65,8 +64,7 @@ namespace BAN
|
|||
const T& front() const;
|
||||
T& front();
|
||||
|
||||
ErrorOr<void> resize(size_type) requires is_default_constructible_v<T>;
|
||||
ErrorOr<void> resize(size_type, const T&) requires is_copy_constructible_v<T>;
|
||||
ErrorOr<void> resize(size_type, const T& = T());
|
||||
ErrorOr<void> reserve(size_type);
|
||||
ErrorOr<void> shrink_to_fit();
|
||||
|
||||
|
@ -138,13 +136,10 @@ namespace BAN
|
|||
template<typename T>
|
||||
Vector<T>& Vector<T>::operator=(const Vector<T>& other)
|
||||
{
|
||||
clear();
|
||||
MUST(ensure_capacity(other.size()));
|
||||
for (size_type i = 0; i < BAN::Math::min(size(), other.size()); i++)
|
||||
m_data[i] = other.m_data[i];
|
||||
for (size_type i = size(); i < other.size(); i++)
|
||||
for (size_type i = 0; i < other.size(); i++)
|
||||
new (m_data + i) T(other[i]);
|
||||
for (size_type i = other.size(); i < size(); i++)
|
||||
m_data[i].~T();
|
||||
m_size = other.m_size;
|
||||
return *this;
|
||||
}
|
||||
|
@ -302,21 +297,7 @@ namespace BAN
|
|||
}
|
||||
|
||||
template<typename T>
|
||||
ErrorOr<void> Vector<T>::resize(size_type size) requires is_default_constructible_v<T>
|
||||
{
|
||||
TRY(ensure_capacity(size));
|
||||
if (size < m_size)
|
||||
for (size_type i = size; i < m_size; i++)
|
||||
m_data[i].~T();
|
||||
if (size > m_size)
|
||||
for (size_type i = m_size; i < size; i++)
|
||||
new (m_data + i) T();
|
||||
m_size = size;
|
||||
return {};
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
ErrorOr<void> Vector<T>::resize(size_type size, const T& value) requires is_copy_constructible_v<T>
|
||||
ErrorOr<void> Vector<T>::resize(size_type size, const T& value)
|
||||
{
|
||||
TRY(ensure_capacity(size));
|
||||
if (size < m_size)
|
||||
|
|
|
@ -2,10 +2,6 @@
|
|||
|
||||
#include <BAN/RefPtr.h>
|
||||
|
||||
#if __is_kernel
|
||||
#include <kernel/Lock/SpinLock.h>
|
||||
#endif
|
||||
|
||||
namespace BAN
|
||||
{
|
||||
|
||||
|
@ -15,37 +11,22 @@ namespace BAN
|
|||
template<typename T>
|
||||
class WeakPtr;
|
||||
|
||||
// FIXME: Write this without using locks...
|
||||
template<typename T>
|
||||
class WeakLink : public RefCounted<WeakLink<T>>
|
||||
{
|
||||
public:
|
||||
RefPtr<T> try_lock()
|
||||
{
|
||||
#if __is_kernel
|
||||
Kernel::SpinLockGuard _(m_weak_lock);
|
||||
#endif
|
||||
if (m_ptr && m_ptr->try_ref())
|
||||
return RefPtr<T>::adopt(m_ptr);
|
||||
return nullptr;
|
||||
}
|
||||
RefPtr<T> lock() { ASSERT(m_ptr); return raw_ptr(); }
|
||||
T* raw_ptr() { return m_ptr; }
|
||||
|
||||
bool valid() const { return m_ptr; }
|
||||
void invalidate()
|
||||
{
|
||||
#if __is_kernel
|
||||
Kernel::SpinLockGuard _(m_weak_lock);
|
||||
#endif
|
||||
m_ptr = nullptr;
|
||||
}
|
||||
void invalidate() { m_ptr = nullptr; }
|
||||
|
||||
private:
|
||||
WeakLink(T* ptr) : m_ptr(ptr) {}
|
||||
|
||||
private:
|
||||
T* m_ptr;
|
||||
#if __is_kernel
|
||||
Kernel::SpinLock m_weak_lock;
|
||||
#endif
|
||||
|
||||
friend class RefPtr<WeakLink<T>>;
|
||||
};
|
||||
|
||||
|
@ -53,7 +34,7 @@ namespace BAN
|
|||
class Weakable
|
||||
{
|
||||
public:
|
||||
virtual ~Weakable()
|
||||
~Weakable()
|
||||
{
|
||||
if (m_link)
|
||||
m_link->invalidate();
|
||||
|
@ -101,8 +82,8 @@ namespace BAN
|
|||
|
||||
RefPtr<T> lock()
|
||||
{
|
||||
if (m_link)
|
||||
return m_link->try_lock();
|
||||
if (m_link->valid())
|
||||
return m_link->lock();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -110,8 +91,6 @@ namespace BAN
|
|||
|
||||
bool valid() const { return m_link && m_link->valid(); }
|
||||
|
||||
explicit operator bool() const { return valid(); }
|
||||
|
||||
private:
|
||||
WeakPtr(const RefPtr<WeakLink<T>>& link)
|
||||
: m_link(link)
|
||||
|
@ -125,4 +104,4 @@ namespace BAN
|
|||
friend class Weakable<T>;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
|
@ -4,55 +4,41 @@ if (NOT ${CMAKE_SYSTEM_NAME} STREQUAL "banan-os")
|
|||
message(FATAL_ERROR "CMAKE_SYSTEM_NAME is not banan-os")
|
||||
endif ()
|
||||
|
||||
#add_compile_options(-mno-sse -mno-sse2)
|
||||
add_compile_definitions(__enable_sse=1)
|
||||
add_compile_options(-mno-sse -mno-sse2)
|
||||
add_compile_definitions(__enable_sse=0)
|
||||
|
||||
project(banan-os CXX C ASM)
|
||||
|
||||
set(BANAN_BASE_SYSROOT ${CMAKE_SOURCE_DIR}/base-sysroot.tar.gz)
|
||||
|
||||
set(BANAN_INCLUDE ${BANAN_SYSROOT}/usr/include)
|
||||
set(BANAN_LIB ${BANAN_SYSROOT}/usr/lib)
|
||||
set(BANAN_BIN ${BANAN_SYSROOT}/usr/bin)
|
||||
set(BANAN_ETC ${BANAN_SYSROOT}/usr/etc)
|
||||
set(BANAN_SHARE ${BANAN_SYSROOT}/usr/share)
|
||||
set(BANAN_BOOT ${BANAN_SYSROOT}/boot)
|
||||
|
||||
set(CMAKE_INSTALL_BINDIR ${BANAN_BIN})
|
||||
set(CMAKE_INSTALL_SBINDIR ${BANAN_BIN})
|
||||
set(CMAKE_INSTALL_LIBDIR ${BANAN_LIB})
|
||||
set(CMAKE_INSTALL_INCLUDEDIR ${BANAN_INCLUDE})
|
||||
set(CMAKE_INSTALL_SYSCONF ${BANAN_ETC})
|
||||
set(CMAKE_INSTALL_MESSAGE NEVER)
|
||||
set(CMAKE_SKIP_INSTALL_ALL_DEPENDENCY True)
|
||||
|
||||
# include headers of ${library} to ${target}
|
||||
function(banan_include_headers target library)
|
||||
target_include_directories(${target} PRIVATE $<TARGET_PROPERTY:${library},SOURCE_DIR>/include)
|
||||
endfunction()
|
||||
|
||||
# include headers and link ${library} to ${target}
|
||||
function(banan_link_library target library)
|
||||
target_link_libraries(${target} PRIVATE ${library})
|
||||
banan_include_headers(${target} ${library})
|
||||
endfunction()
|
||||
|
||||
# add install step for all header files of target
|
||||
function(banan_install_headers target)
|
||||
file(GLOB_RECURSE headers RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}/include *.h)
|
||||
foreach(header ${headers})
|
||||
get_filename_component(subdirectory ${header} DIRECTORY)
|
||||
install(FILES include/${header} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${subdirectory})
|
||||
endforeach()
|
||||
target_include_directories(${target} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include)
|
||||
endfunction()
|
||||
set(BANAN_LIB ${BANAN_SYSROOT}/usr/lib)
|
||||
set(BANAN_BIN ${BANAN_SYSROOT}/usr/bin)
|
||||
set(BANAN_BOOT ${BANAN_SYSROOT}/boot)
|
||||
|
||||
add_subdirectory(kernel)
|
||||
add_subdirectory(bootloader)
|
||||
add_subdirectory(BAN)
|
||||
add_subdirectory(libc)
|
||||
add_subdirectory(LibELF)
|
||||
add_subdirectory(userspace)
|
||||
|
||||
add_custom_target(sysroot
|
||||
COMMAND ${CMAKE_COMMAND} -E make_directory ${BANAN_SYSROOT}
|
||||
COMMAND cd ${BANAN_SYSROOT} && tar xf ${BANAN_BASE_SYSROOT}
|
||||
)
|
||||
|
||||
add_custom_target(headers
|
||||
DEPENDS kernel-headers
|
||||
DEPENDS ban-headers
|
||||
DEPENDS libc-headers
|
||||
DEPENDS libelf-headers
|
||||
)
|
||||
|
||||
add_custom_target(install-sysroot
|
||||
COMMAND cd ${BANAN_SYSROOT} && tar cf ${BANAN_SYSROOT_TAR} *
|
||||
DEPENDS kernel-install
|
||||
DEPENDS ban-install
|
||||
DEPENDS libc-install
|
||||
DEPENDS userspace-install
|
||||
DEPENDS libelf-install
|
||||
)
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
cmake_minimum_required(VERSION 3.26)
|
||||
|
||||
project(LibELF CXX)
|
||||
|
||||
add_custom_target(libelf-headers
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_directory_if_different ${CMAKE_CURRENT_SOURCE_DIR}/include/ ${BANAN_INCLUDE}/
|
||||
DEPENDS sysroot
|
||||
)
|
||||
|
||||
add_custom_target(libelf-install
|
||||
DEPENDS libelf-headers
|
||||
)
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
#ifdef __is_kernel
|
||||
#include <kernel/FS/VirtualFileSystem.h>
|
||||
#include <kernel/Memory/PageTableScope.h>
|
||||
#include <kernel/Process.h>
|
||||
#endif
|
||||
|
||||
|
@ -76,7 +77,7 @@ namespace LibELF
|
|||
return BAN::Error::from_errno(EINVAL);
|
||||
}
|
||||
|
||||
if (m_data[EI_MAG0] != ELFMAG0 ||
|
||||
if (m_data[EI_MAG0] != ELFMAG0 ||
|
||||
m_data[EI_MAG1] != ELFMAG1 ||
|
||||
m_data[EI_MAG2] != ELFMAG2 ||
|
||||
m_data[EI_MAG3] != ELFMAG3)
|
||||
|
@ -251,7 +252,7 @@ namespace LibELF
|
|||
break;
|
||||
default:
|
||||
ASSERT(false);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
(void)header;
|
||||
return true;
|
||||
|
@ -374,7 +375,7 @@ namespace LibELF
|
|||
break;
|
||||
default:
|
||||
ASSERT(false);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
(void)header;
|
||||
return true;
|
|
@ -1,6 +1,7 @@
|
|||
#include <BAN/ScopeGuard.h>
|
||||
#include <kernel/CriticalScope.h>
|
||||
#include <kernel/Memory/Heap.h>
|
||||
#include <kernel/Lock/LockGuard.h>
|
||||
#include <kernel/LockGuard.h>
|
||||
#include <LibELF/LoadableELF.h>
|
||||
#include <LibELF/Values.h>
|
||||
|
||||
|
@ -65,7 +66,7 @@ namespace LibELF
|
|||
size_t nread = TRY(m_inode->read(0, BAN::ByteSpan::from(m_file_header)));
|
||||
ASSERT(nread == sizeof(m_file_header));
|
||||
|
||||
if (m_file_header.e_ident[EI_MAG0] != ELFMAG0 ||
|
||||
if (m_file_header.e_ident[EI_MAG0] != ELFMAG0 ||
|
||||
m_file_header.e_ident[EI_MAG1] != ELFMAG1 ||
|
||||
m_file_header.e_ident[EI_MAG2] != ELFMAG2 ||
|
||||
m_file_header.e_ident[EI_MAG3] != ELFMAG3)
|
||||
|
@ -86,13 +87,13 @@ namespace LibELF
|
|||
return BAN::Error::from_errno(ENOEXEC);
|
||||
}
|
||||
|
||||
#if ARCH(i686)
|
||||
#if ARCH(i386)
|
||||
if (m_file_header.e_ident[EI_CLASS] != ELFCLASS32)
|
||||
#elif ARCH(x86_64)
|
||||
if (m_file_header.e_ident[EI_CLASS] != ELFCLASS64)
|
||||
#endif
|
||||
{
|
||||
dprintln("Not in native format");
|
||||
dprintln("Not in native format");
|
||||
return BAN::Error::from_errno(EINVAL);
|
||||
}
|
||||
|
||||
|
@ -202,14 +203,6 @@ namespace LibELF
|
|||
m_loaded = true;
|
||||
}
|
||||
|
||||
void LoadableELF::update_suid_sgid(Kernel::Credentials& credentials)
|
||||
{
|
||||
if (m_inode->mode().mode & +Inode::Mode::ISUID)
|
||||
credentials.set_euid(m_inode->uid());
|
||||
if (m_inode->mode().mode & +Inode::Mode::ISGID)
|
||||
credentials.set_egid(m_inode->gid());
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> LoadableELF::load_page_to_memory(vaddr_t address)
|
||||
{
|
||||
for (const auto& program_header : m_program_headers)
|
||||
|
@ -239,13 +232,13 @@ namespace LibELF
|
|||
m_physical_page_count++;
|
||||
|
||||
memset((void*)vaddr, 0x00, PAGE_SIZE);
|
||||
|
||||
|
||||
if (vaddr / PAGE_SIZE < BAN::Math::div_round_up<size_t>(program_header.p_vaddr + program_header.p_filesz, PAGE_SIZE))
|
||||
{
|
||||
size_t vaddr_offset = 0;
|
||||
if (vaddr < program_header.p_vaddr)
|
||||
vaddr_offset = program_header.p_vaddr - vaddr;
|
||||
|
||||
|
||||
size_t file_offset = 0;
|
||||
if (vaddr > program_header.p_vaddr)
|
||||
file_offset = vaddr - program_header.p_vaddr;
|
||||
|
@ -266,7 +259,7 @@ namespace LibELF
|
|||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
|
||||
|
||||
BAN::ErrorOr<BAN::UniqPtr<LoadableELF>> LoadableELF::clone(Kernel::PageTable& new_page_table)
|
||||
{
|
||||
auto* elf_ptr = new LoadableELF(new_page_table, m_inode);
|
||||
|
@ -281,6 +274,10 @@ namespace LibELF
|
|||
|
||||
elf->reserve_address_space();
|
||||
|
||||
ASSERT(&PageTable::current() == &m_page_table);
|
||||
LockGuard _(m_page_table);
|
||||
ASSERT(m_page_table.is_page_free(0));
|
||||
|
||||
for (const auto& program_header : m_program_headers)
|
||||
{
|
||||
switch (program_header.p_type)
|
||||
|
@ -310,9 +307,12 @@ namespace LibELF
|
|||
if (paddr == 0)
|
||||
return BAN::Error::from_errno(ENOMEM);
|
||||
|
||||
PageTable::with_fast_page(paddr, [&] {
|
||||
{
|
||||
CriticalScope _;
|
||||
PageTable::map_fast_page(paddr);
|
||||
memcpy(PageTable::fast_page_as_ptr(), (void*)(start + i * PAGE_SIZE), PAGE_SIZE);
|
||||
});
|
||||
PageTable::unmap_fast_page();
|
||||
}
|
||||
|
||||
new_page_table.map_page_at(paddr, start + i * PAGE_SIZE, flags);
|
||||
elf->m_physical_page_count++;
|
|
@ -42,7 +42,7 @@ namespace LibELF
|
|||
const Elf32SectionHeader& section_header32(size_t) const;
|
||||
const char* lookup_section_name32(uint32_t) const;
|
||||
const char* lookup_string32(size_t, uint32_t) const;
|
||||
#if ARCH(i686)
|
||||
#if ARCH(i386)
|
||||
const Elf32FileHeader& file_header_native() const { return file_header32(); }
|
||||
const Elf32ProgramHeader& program_header_native(size_t index) const { return program_header32(index); }
|
||||
const Elf32SectionHeader& section_header_native(size_t index) const { return section_header32(index); }
|
||||
|
@ -68,7 +68,7 @@ namespace LibELF
|
|||
{}
|
||||
//#endif
|
||||
BAN::ErrorOr<void> load();
|
||||
|
||||
|
||||
bool parse_elf64_file_header(const Elf64FileHeader&);
|
||||
bool parse_elf64_program_header(const Elf64ProgramHeader&);
|
||||
bool parse_elf64_section_header(const Elf64SectionHeader&);
|
||||
|
@ -86,4 +86,4 @@ namespace LibELF
|
|||
//#endif
|
||||
};
|
||||
|
||||
}
|
||||
}
|
|
@ -7,7 +7,6 @@
|
|||
#include <BAN/UniqPtr.h>
|
||||
#include <BAN/Vector.h>
|
||||
|
||||
#include <kernel/Credentials.h>
|
||||
#include <kernel/FS/Inode.h>
|
||||
#include <kernel/Memory/PageTable.h>
|
||||
|
||||
|
@ -31,8 +30,6 @@ namespace LibELF
|
|||
bool is_address_space_free() const;
|
||||
void reserve_address_space();
|
||||
|
||||
void update_suid_sgid(Kernel::Credentials&);
|
||||
|
||||
BAN::ErrorOr<void> load_page_to_memory(Kernel::vaddr_t address);
|
||||
|
||||
BAN::ErrorOr<BAN::UniqPtr<LoadableELF>> clone(Kernel::PageTable&);
|
||||
|
@ -54,4 +51,4 @@ namespace LibELF
|
|||
bool m_loaded { false };
|
||||
};
|
||||
|
||||
}
|
||||
}
|
|
@ -155,7 +155,7 @@ namespace LibELF
|
|||
Elf64Xword p_align;
|
||||
};
|
||||
|
||||
#if ARCH(i686)
|
||||
#if ARCH(i386)
|
||||
using ElfNativeAddr = Elf32Addr;
|
||||
using ElfNativeOff = Elf32Off;
|
||||
using ElfNativeHalf = Elf32Half;
|
||||
|
@ -183,4 +183,4 @@ namespace LibELF
|
|||
using ElfNativeProgramHeader = Elf64ProgramHeader;
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
|
@ -137,4 +137,4 @@ namespace LibELF
|
|||
PF_MASKPROC = 0xFF000000,
|
||||
};
|
||||
|
||||
}
|
||||
}
|
102
README.md
102
README.md
|
@ -1,58 +1,8 @@
|
|||
[![](https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fbananymous.com%2Fbanan-os%2Ftokei.json&query=%24.lines&label=total%20lines)](https://git.bananymous.com/Bananymous/banan-os)
|
||||
[![](https://img.shields.io/github/commit-activity/m/Bananymous/banan-os)](https://git.bananymous.com/Bananymous/banan-os)
|
||||
[![](https://img.shields.io/github/license/bananymous/banan-os)](https://git.bananymous.com/Bananymous/banan-os/src/branch/main/LICENSE)
|
||||
[![](https://img.shields.io/discord/1242165176032297040?logo=discord&label=discord)](https://discord.gg/ehjGySwYdK)
|
||||
![license](https://img.shields.io/github/license/bananymous/banan-os)
|
||||
|
||||
# banan-os
|
||||
|
||||
This is my hobby operating system written in C++. Currently supports x86\_64 and i686 architectures.
|
||||
|
||||
You can find a live demo [here](https://bananymous.com/banan-os)
|
||||
|
||||
### Features
|
||||
|
||||
#### General
|
||||
- [x] Ring3 userspace
|
||||
- [x] SMP (multiprocessing)
|
||||
- [x] Linear framebuffer (VESA and GOP)
|
||||
- [x] Network stack
|
||||
- [x] ELF executable loading
|
||||
- [x] AML interpreter (partial)
|
||||
- [ ] ELF dynamic linking
|
||||
- [ ] Graphical desktop
|
||||
- [ ] copy-on-write memory
|
||||
|
||||
#### Drivers
|
||||
- [x] NVMe disks
|
||||
- [x] ATA (IDE, SATA) disks
|
||||
- [x] E1000 and E1000E NICs
|
||||
- [x] PS2 keyboard (all scancode sets)
|
||||
- [x] PS2 mouse
|
||||
- [ ] USB
|
||||
- [ ] virtio devices (network, storage)
|
||||
|
||||
#### Network
|
||||
- [x] ARP
|
||||
- [x] ICMP
|
||||
- [x] IPv4
|
||||
- [x] UDP
|
||||
- [x] TCP (partial and buggy)
|
||||
- [x] Unix domain sockets
|
||||
|
||||
#### Filesystems
|
||||
- [x] Virtual filesystem
|
||||
- [x] Ext2
|
||||
- [x] FAT12/16/32
|
||||
- [x] Dev
|
||||
- [x] Ram
|
||||
- [x] Proc
|
||||
- [ ] Sys
|
||||
- [ ] 9P
|
||||
|
||||
#### Bootloader support
|
||||
- [x] GRUB
|
||||
- [x] Custom BIOS bootloader
|
||||
- [ ] Custom UEFI bootloader
|
||||
This is my hobby operating system written in C++. Currently supports only x86\_64 architecture. We have a ext2 filesystem, basic ramfs, IDE disk drivers in ATA PIO mode, ATA AHCI drivers, userspace processes, executable loading from ELF format, linear VBE graphics and multithreaded processing on single core.
|
||||
|
||||
![screenshot from qemu running banan-os](assets/banan-os.png)
|
||||
|
||||
|
@ -62,59 +12,37 @@ Each major component and library has its own subdirectory (kernel, userspace, li
|
|||
|
||||
## Building
|
||||
|
||||
### Needed packages
|
||||
|
||||
#### apt (tested on ubuntu 22.04)
|
||||
```# apt install build-essential git ninja-build texinfo bison flex libgmp-dev libmpfr-dev libmpc-dev parted qemu-system-x86 cpu-checker```
|
||||
|
||||
#### pacman
|
||||
```# pacman -S --needed base-devel git wget cmake ninja parted qemu-system-x86```
|
||||
|
||||
|
||||
### Compilation
|
||||
There does not exist a complete list of needed packages for building. From the top of my head I can say that *cmake*, *ninja*, *make*, *grub*, *rsync* and emulator (*qemu* or *bochs*) are needed.
|
||||
|
||||
To build the toolchain for this os. You can run the following command.
|
||||
> ***NOTE:*** The following step has to be done only once. This might take a long time since we are compiling binutils and gcc.
|
||||
```sh
|
||||
./bos toolchain
|
||||
./script/build.sh toolchain
|
||||
```
|
||||
|
||||
To build the os itself you can run one of the following commands. You will need root access for disk image creation/modification.
|
||||
```sh
|
||||
./bos qemu
|
||||
./bos qemu-nographic
|
||||
./bos qemu-debug
|
||||
./bos bochs
|
||||
./script/build.sh qemu
|
||||
./script/build.sh qemu-nographic
|
||||
./script/build.sh qemu-debug
|
||||
./script/build.sh bochs
|
||||
```
|
||||
|
||||
You can also build the kernel or disk image without running it:
|
||||
```sh
|
||||
./bos kernel
|
||||
./bos image
|
||||
./script/build.sh kernel
|
||||
./script/build.sh image
|
||||
```
|
||||
|
||||
To build for other architectures set environment variable BANAN\_ARCH=*arch* (e.g. BANAN\_ARCH=i686).
|
||||
|
||||
To change the bootloader you can set environment variable BANAN\_BOOTLOADER; supported values are BANAN (my custom bootloader) and GRUB.
|
||||
|
||||
To run with UEFI set environment variable BANAN\_UEFI\_BOOT=1. You will also have to set OVMF\_PATH to the correct OVMF (default */usr/share/ovmf/x64/OVMF.fd*).
|
||||
|
||||
If you have corrupted your disk image or want to create new one, you can either manually delete *build/banan-os.img* and build system will automatically create you a new one or you can run the following command.
|
||||
```sh
|
||||
./bos image-full
|
||||
./script/build.sh image-full
|
||||
```
|
||||
|
||||
If you feel like ```./script/build.sh``` is too verbose, there exists a symlink _bos_ in this projects root directory. All build commands can be used with ```./bos args...``` instead.
|
||||
|
||||
I have also created shell completion script for zsh. You can either copy the file in _script/shell-completion/zsh/\_bos_ to _/usr/share/zsh/site-functions/_ or add the _script/shell-completion/zsh_ to your fpath in _.zshrc_.
|
||||
|
||||
## Contributing
|
||||
### Contributing
|
||||
|
||||
As the upstream is hosted on my server https://git.bananymous.com/Bananymous/banan-os, please contact me about account creation ([email](mailto:oskari.alaranta@bananymous.com), [discord](https://discord.gg/xMXKt9Wf)) and I will add a account for you. This is done to limit the people with access to the server.
|
||||
|
||||
As this is mostly a learning experience for me, I would appreciate if you first contacted me about adding new features (email, discord, issue, ...). Bug fixes are always welcome!
|
||||
|
||||
Commit message should be formatted followingly
|
||||
|
||||
1. First line is of the form "_Subject: Description_", where _Subject_ tells the area touched (Kernel, Shell, BuildSystem, ...) and _Description_ is brief description of the change done. First line should fit fully in 70 characters.
|
||||
2. Body of the message should further describe the change and reasoning behind the change.
|
||||
|
||||
All commits should pass the pre-commit hook defined in _.pre-commit-config.yaml_. For instructions on how to setup pre-commit, please see https://pre-commit.com/#install.
|
||||
Currently I don't accept contributions to this repository unless explicitly told otherwise. This is a learning project for me and I want to do everything myself. Feel free to fork/clone this repo and tinker with it yourself.
|
||||
|
|
Binary file not shown.
|
@ -3,7 +3,6 @@ cmake_minimum_required(VERSION 3.26)
|
|||
project(bootloader ASM)
|
||||
|
||||
set(BOOTLOADER_SOURCES
|
||||
a20_line.S
|
||||
boot.S
|
||||
command_line.S
|
||||
disk.S
|
||||
|
@ -15,6 +14,5 @@ set(BOOTLOADER_SOURCES
|
|||
)
|
||||
|
||||
add_executable(bootloader ${BOOTLOADER_SOURCES})
|
||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
|
||||
target_link_options(bootloader PRIVATE LINKER:-T,${CMAKE_CURRENT_SOURCE_DIR}/linker.ld)
|
||||
target_link_options(bootloader PRIVATE -nostdlib)
|
||||
|
|
|
@ -1,168 +0,0 @@
|
|||
.code16
|
||||
.section .stage2
|
||||
|
||||
# checks whether A20 line is enabled or disabled
|
||||
# return
|
||||
# ax: 1 if enabled, 0 otherwise
|
||||
check_a20:
|
||||
pushf
|
||||
pushw %si
|
||||
pushw %di
|
||||
pushw %ds
|
||||
pushw %es
|
||||
|
||||
cli
|
||||
|
||||
xorw %ax, %ax
|
||||
movw %ax, %es
|
||||
notw %ax
|
||||
movw %ax, %ds
|
||||
|
||||
movw $0x0500, %di
|
||||
movw $0x0510, %si
|
||||
|
||||
movb %es:(%di), %al
|
||||
pushw %ax
|
||||
|
||||
movb %ds:(%si), %al
|
||||
pushw %ax
|
||||
|
||||
movb $0x00, %es:(%di)
|
||||
movb $0xFF, %ds:(%si)
|
||||
|
||||
cmpb $0xFF, %es:(%di)
|
||||
|
||||
pop %ax
|
||||
movb %al, %ds:(%si)
|
||||
|
||||
pop %ax
|
||||
movb %al, %es:(%di)
|
||||
|
||||
movw $0, %ax
|
||||
je .check_a20_done
|
||||
|
||||
movw $1, %ax
|
||||
|
||||
.check_a20_done:
|
||||
popw %es
|
||||
popw %ds
|
||||
popw %di
|
||||
popw %si
|
||||
popf
|
||||
ret
|
||||
|
||||
|
||||
# Try to enable A20 using PS2 controller
|
||||
enable_a20_ps2:
|
||||
pushf
|
||||
pushw %ax
|
||||
|
||||
cli
|
||||
|
||||
# disable first port
|
||||
call .enable_a20_ps2_wait1
|
||||
movb $0xAD, %al
|
||||
outb %al, $0x64
|
||||
|
||||
# read controller output
|
||||
call .enable_a20_ps2_wait1
|
||||
movb $0xD0, %al
|
||||
outb %al, $0x64
|
||||
|
||||
call .enable_a20_ps2_wait2
|
||||
inb $0x60, %al
|
||||
pushw %ax
|
||||
|
||||
# write controller output
|
||||
call .enable_a20_ps2_wait1
|
||||
movb $0xD1, %al
|
||||
outb %al, $0x64
|
||||
|
||||
call .enable_a20_ps2_wait1
|
||||
popw %ax
|
||||
orw $2, %ax
|
||||
outb %al, $0x60
|
||||
|
||||
# enable first port
|
||||
call .enable_a20_ps2_wait1
|
||||
movb $0xAE, %al
|
||||
outb %al, $0x64
|
||||
|
||||
call .enable_a20_ps2_wait1
|
||||
|
||||
popw %ax
|
||||
popf
|
||||
ret
|
||||
|
||||
.enable_a20_ps2_wait1:
|
||||
inb $0x64, %al
|
||||
test $2, %al
|
||||
jnz .enable_a20_ps2_wait1
|
||||
ret
|
||||
|
||||
.enable_a20_ps2_wait2:
|
||||
inb $0x64, %al
|
||||
test $1, %al
|
||||
jnz .enable_a20_ps2_wait1
|
||||
ret
|
||||
|
||||
|
||||
# Check if A20 line is disabled. If it is, try to enable it
|
||||
.global enable_a20
|
||||
enable_a20:
|
||||
pushw %ax
|
||||
pushw %si
|
||||
|
||||
call check_a20
|
||||
testw %ax, %ax
|
||||
jnz .enable_a20_done
|
||||
|
||||
movw $a20_line_disabled_msg, %si
|
||||
call puts; call print_newline
|
||||
|
||||
# Try to enable A20 line using bios interrupt
|
||||
movw $0x2401, %ax
|
||||
int $0x15
|
||||
call check_a20
|
||||
testw %ax, %ax
|
||||
jnz .enable_a20_done
|
||||
|
||||
# Try to enable A20 line using ps2 controller
|
||||
call enable_a20_ps2
|
||||
call check_a20
|
||||
testw %ax, %ax
|
||||
jnz .enable_a20_done
|
||||
|
||||
# Try to enable A20 line using fast A20 gate
|
||||
inb $0x92, %al
|
||||
testb $2, %al
|
||||
jnz .enable_a20_fast_done
|
||||
orb $2, %al
|
||||
outb %al, $0x92
|
||||
.enable_a20_fast_done:
|
||||
|
||||
call check_a20
|
||||
testw %ax, %ax
|
||||
jnz .enable_a20_done
|
||||
|
||||
movw $a20_could_not_enable_msg, %si
|
||||
call print_and_halt
|
||||
|
||||
.enable_a20_done:
|
||||
movw $a20_line_enabled_msg, %si
|
||||
call puts; call print_newline
|
||||
|
||||
popw %si
|
||||
popw %ax
|
||||
ret
|
||||
|
||||
.section .data
|
||||
|
||||
a20_line_disabled_msg:
|
||||
.asciz "A20 line disabled. Trying to enable it"
|
||||
|
||||
a20_line_enabled_msg:
|
||||
.asciz "A20 line enabled"
|
||||
|
||||
a20_could_not_enable_msg:
|
||||
.asciz "Could not enable A20 line"
|
|
@ -1,5 +1,3 @@
|
|||
.include "common.S"
|
||||
|
||||
.code16
|
||||
|
||||
#########################################
|
||||
|
@ -15,10 +13,12 @@
|
|||
|
||||
.global stage1_main
|
||||
stage1_main:
|
||||
# setup segments and stack
|
||||
xorw %ax, %ax
|
||||
# setup segments
|
||||
movw $0, %ax
|
||||
movw %ax, %ds
|
||||
movw %ax, %es
|
||||
|
||||
# setup stack
|
||||
movw %ax, %ss
|
||||
movl $0x7C00, %esp
|
||||
|
||||
|
@ -53,18 +53,14 @@ stage2_main:
|
|||
movw $hello_msg, %si
|
||||
call puts; call print_newline
|
||||
|
||||
lgdt gdtr
|
||||
|
||||
call enter_unreal_mode
|
||||
movw $unreal_enter_msg, %si
|
||||
call puts; call print_newline
|
||||
|
||||
call enable_a20
|
||||
|
||||
call get_memory_map
|
||||
|
||||
call print_newline
|
||||
call read_user_command_line
|
||||
|
||||
call vesa_find_video_mode
|
||||
|
||||
call print_newline
|
||||
|
||||
|
@ -88,36 +84,36 @@ stage2_main:
|
|||
|
||||
call elf_read_kernel_to_memory
|
||||
|
||||
call vesa_set_video_mode
|
||||
call vesa_set_target_mode
|
||||
|
||||
cli
|
||||
|
||||
# kernel entry point
|
||||
movl %eax, %ecx
|
||||
|
||||
# setup kernel parameters
|
||||
movl $0xD3C60CFF, %eax
|
||||
movl $banan_boot_info, %ebx
|
||||
|
||||
# setup protected mode
|
||||
movl %cr0, %edx
|
||||
orb $1, %dl
|
||||
movl %edx, %cr0
|
||||
movl %cr0, %ebx
|
||||
orb $1, %bl
|
||||
movl %ebx, %cr0
|
||||
|
||||
# jump to kernel in protected mode
|
||||
ljmpl $0x18, $protected_mode
|
||||
|
||||
# jump to protected mode
|
||||
ljmpl $GDT_CODE32, $protected_mode
|
||||
|
||||
.code32
|
||||
protected_mode:
|
||||
# setup protected mode segments
|
||||
movw $GDT_DATA32, %dx
|
||||
movw %dx, %ds
|
||||
movw %dx, %es
|
||||
movw %dx, %fs
|
||||
movw %dx, %gs
|
||||
movw %dx, %ss
|
||||
movw $0x10, %bx
|
||||
movw %bx, %ds
|
||||
movw %bx, %es
|
||||
movw %bx, %fs
|
||||
movw %bx, %gs
|
||||
movw %bx, %ss
|
||||
|
||||
movl %eax, %ecx
|
||||
|
||||
movl $0xD3C60CFF, %eax
|
||||
movl $banan_boot_info, %ebx
|
||||
xorl %edx, %edx
|
||||
xorl %esi, %esi
|
||||
xorl %edi, %edi
|
||||
|
||||
# jump to kernel entry
|
||||
jmp *%ecx
|
||||
|
||||
|
||||
|
@ -126,18 +122,20 @@ enter_unreal_mode:
|
|||
cli
|
||||
pushw %ds
|
||||
|
||||
lgdt gdtr
|
||||
|
||||
movl %cr0, %eax
|
||||
orb $1, %al
|
||||
movl %eax, %cr0
|
||||
ljmpl $GDT_CODE16, $.enter_unreal_mode_pmode
|
||||
ljmpl $0x8, $.enter_unreal_mode_pmode
|
||||
|
||||
.enter_unreal_mode_pmode:
|
||||
movw $GDT_DATA32, %bx
|
||||
movw $0x10, %bx
|
||||
movw %bx, %ds
|
||||
|
||||
andb $0xFE, %al
|
||||
andb 0xFE, %al
|
||||
movl %eax, %cr0
|
||||
ljmpl $0x00, $.enter_unreal_mode_unreal
|
||||
ljmpl $0x0, $.enter_unreal_mode_unreal
|
||||
|
||||
.enter_unreal_mode_unreal:
|
||||
popw %ds
|
||||
|
@ -145,8 +143,6 @@ enter_unreal_mode:
|
|||
|
||||
ret
|
||||
|
||||
.section .data
|
||||
|
||||
hello_msg:
|
||||
.asciz "This is banan-os bootloader"
|
||||
|
||||
|
@ -158,12 +154,12 @@ start_kernel_load_msg:
|
|||
|
||||
gdt:
|
||||
.quad 0x0000000000000000
|
||||
.quad 0x008F9A000000FFFF # 16-bit code
|
||||
.quad 0x00CF92000000FFFF # 32-bit data
|
||||
.quad 0x00CF9A000000FFFF # 32-bit code
|
||||
.quad 0x00009A000000FFFF
|
||||
.quad 0x00CF92000000FFFF
|
||||
.quad 0x00CF9A000000FFFF
|
||||
gdtr:
|
||||
.short . - gdt - 1
|
||||
.long gdt
|
||||
.quad gdt
|
||||
|
||||
banan_boot_info:
|
||||
boot_command_line:
|
||||
|
|
|
@ -26,8 +26,6 @@ read_user_command_line:
|
|||
|
||||
cmpb $'\b', %al
|
||||
je .read_user_command_line_backspace
|
||||
cmpb $0x7F, %al
|
||||
je .read_user_command_line_backspace
|
||||
|
||||
# Not sure if some BIOSes return '\n' as enter, but check it just in case
|
||||
cmpb $'\r', %al
|
||||
|
@ -74,8 +72,6 @@ read_user_command_line:
|
|||
ret
|
||||
|
||||
|
||||
.section .data
|
||||
|
||||
command_line_enter_msg:
|
||||
.asciz "cmdline: "
|
||||
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
.set GDT_CODE16, 0x08
|
||||
.set GDT_DATA32, 0x10
|
||||
.set GDT_CODE32, 0x18
|
|
@ -41,7 +41,7 @@ read_from_disk:
|
|||
call drive_has_int13_ext
|
||||
|
||||
# prepare disk read packet
|
||||
movw $disk_address_packet, %si
|
||||
mov $disk_address_packet, %si
|
||||
movb $0x10, 0x00(%si) # packet size
|
||||
movb $0x00, 0x01(%si) # always 0
|
||||
movw %cx, 0x02(%si) # lba count
|
||||
|
@ -389,8 +389,10 @@ find_root_partition:
|
|||
|
||||
# increment 8 byte entry array lba
|
||||
incl 0(%esp)
|
||||
adcl $0, 4(%esp)
|
||||
jnc .find_root_partition_no_overflow
|
||||
incl 4(%esp)
|
||||
|
||||
.find_root_partition_no_overflow:
|
||||
# loop to read next section if entries remaining
|
||||
cmpl $0, 12(%esp)
|
||||
jnz .find_root_partition_read_entry_section
|
||||
|
@ -414,11 +416,13 @@ find_root_partition:
|
|||
|
||||
# ebx:eax -= first lba - 1
|
||||
subl (root_partition_entry + 36), %ebx
|
||||
movl (root_partition_entry + 32), %ecx
|
||||
movl (root_partition_entry + 32), %ecx;
|
||||
decl %ecx
|
||||
subl %ecx, %eax
|
||||
sbbl $0, %ebx
|
||||
|
||||
jnc .find_root_partition_count_sub_no_carry
|
||||
decl %ebx
|
||||
.find_root_partition_count_sub_no_carry:
|
||||
|
||||
# ecx: min(partition count, 0xFFFFFFFF)
|
||||
movl $0xFFFFFFFF, %edx
|
||||
movl %eax, %ecx
|
||||
|
@ -470,7 +474,6 @@ print_root_partition_info:
|
|||
popw %ax
|
||||
ret
|
||||
|
||||
.section .data
|
||||
|
||||
# These will be patched during bootloader installation
|
||||
root_disk_guid:
|
||||
|
|
|
@ -5,26 +5,15 @@
|
|||
.set e_machine, 18
|
||||
.set e_version, 20
|
||||
.set e_entry, 24
|
||||
|
||||
.set e32_phoff, 28
|
||||
.set e32_shoff, 32
|
||||
.set e32_flags, 36
|
||||
.set e32_ehsize, 40
|
||||
.set e32_phentsize, 42
|
||||
.set e32_phnum, 44
|
||||
.set e32_shentsize, 46
|
||||
.set e32_shnum, 48
|
||||
.set e32_shstrndx, 50
|
||||
|
||||
.set e64_phoff, 32
|
||||
.set e64_shoff, 40
|
||||
.set e64_flags, 48
|
||||
.set e64_ehsize, 52
|
||||
.set e64_phentsize, 54
|
||||
.set e64_phnum, 56
|
||||
.set e64_shentsize, 58
|
||||
.set e64_shnum, 60
|
||||
.set e64_shstrndx, 62
|
||||
.set e_phoff, 32
|
||||
.set e_shoff, 40
|
||||
.set e_flags, 48
|
||||
.set e_ehsize, 52
|
||||
.set e_phentsize, 54
|
||||
.set e_phnum, 56
|
||||
.set e_shentsize, 58
|
||||
.set e_shnum, 60
|
||||
.set e_shstrndx, 62
|
||||
|
||||
# e_ident offsets
|
||||
.set EI_CLASS, 4
|
||||
|
@ -33,7 +22,6 @@
|
|||
|
||||
# e_ident constants
|
||||
.set ELFMAGIC, 0x464C457F
|
||||
.set ELFCLASS32, 1
|
||||
.set ELFCLASS64, 2
|
||||
.set ELFDATA2LSB, 1
|
||||
.set EV_CURRENT, 1
|
||||
|
@ -43,30 +31,18 @@
|
|||
|
||||
# program header field offsets
|
||||
.set p_type, 0
|
||||
|
||||
.set p32_offset, 4
|
||||
.set p32_vaddr, 8
|
||||
.set p32_paddr, 12
|
||||
.set p32_filesz, 16
|
||||
.set p32_memsz, 20
|
||||
.set p32_flags, 24
|
||||
.set p32_align, 28
|
||||
|
||||
.set p64_flags, 4
|
||||
.set p64_offset, 8
|
||||
.set p64_vaddr, 16
|
||||
.set p64_paddr, 24
|
||||
.set p64_filesz, 32
|
||||
.set p64_memsz, 40
|
||||
.set p64_align, 48
|
||||
.set p_flags, 4
|
||||
.set p_offset, 8
|
||||
.set p_vaddr, 16
|
||||
.set p_paddr, 24
|
||||
.set p_filesz, 32
|
||||
.set p_memsz, 40
|
||||
.set p_align, 48
|
||||
|
||||
# p_type constants
|
||||
.set PT_NULL, 0
|
||||
.set PT_LOAD, 1
|
||||
|
||||
# mask for entry point and segment loading
|
||||
.set LOAD_MASK, 0x07FFFFFF
|
||||
|
||||
.code16
|
||||
.section .stage2
|
||||
|
||||
|
@ -76,12 +52,8 @@ elf_validate_file_header:
|
|||
cmpl $ELFMAGIC, (elf_file_header)
|
||||
jne .elf_validate_file_header_invalid_magic
|
||||
|
||||
cmpb $ELFCLASS32, (elf_file_header + EI_CLASS)
|
||||
je .elf_validate_file_header_class_valid
|
||||
cmpb $ELFCLASS64, (elf_file_header + EI_CLASS)
|
||||
je .elf_validate_file_header_class_valid
|
||||
jmp .elf_validate_file_header_invalid_class
|
||||
.elf_validate_file_header_class_valid:
|
||||
jne .elf_validate_file_header_only_64bit_supported
|
||||
|
||||
cmpb $ELFDATA2LSB, (elf_file_header + EI_DATA)
|
||||
jne .elf_validate_file_header_only_little_endian_supported
|
||||
|
@ -100,8 +72,8 @@ elf_validate_file_header:
|
|||
.elf_validate_file_header_invalid_magic:
|
||||
movw $elf_validate_file_header_invalid_magic_msg, %si
|
||||
jmp print_and_halt
|
||||
.elf_validate_file_header_invalid_class:
|
||||
movw $elf_validate_file_header_invalid_class_msg, %si
|
||||
.elf_validate_file_header_only_64bit_supported:
|
||||
movw $elf_validate_file_header_only_64bit_supported_msg, %si
|
||||
jmp print_and_halt
|
||||
.elf_validate_file_header_only_little_endian_supported:
|
||||
movw $elf_validate_file_header_only_little_endian_supported_msg, %si
|
||||
|
@ -113,59 +85,6 @@ elf_validate_file_header:
|
|||
movw $elf_validate_file_header_not_executable_msg, %si
|
||||
jmp print_and_halt
|
||||
|
||||
# reads memory specified by 32 bit elf_program_header to memory
|
||||
elf_read_program_header32_to_memory:
|
||||
pushal
|
||||
pushl %ebp
|
||||
movl %esp, %ebp
|
||||
|
||||
# memset p_filesz -> p_memsz to 0
|
||||
movl (elf_program_header + p32_filesz), %ebx
|
||||
movl (elf_program_header + p32_vaddr), %edi
|
||||
andl $LOAD_MASK, %edi
|
||||
addl %ebx, %edi
|
||||
movl (elf_program_header + p32_memsz), %ecx
|
||||
subl %ebx, %ecx
|
||||
xorb %al, %al; call memset32
|
||||
|
||||
# read file specified in program header to memory
|
||||
movl (elf_program_header + p32_offset), %eax
|
||||
movl (elf_program_header + p32_vaddr), %edi
|
||||
andl $LOAD_MASK, %edi
|
||||
movl (elf_program_header + p32_filesz), %ecx
|
||||
call *%esi
|
||||
|
||||
leavel
|
||||
popal
|
||||
ret
|
||||
|
||||
|
||||
# reads memory specified by 64 bit elf_program_header to memory
|
||||
elf_read_program_header64_to_memory:
|
||||
pushal
|
||||
pushl %ebp
|
||||
movl %esp, %ebp
|
||||
|
||||
# memset p_filesz -> p_memsz to 0
|
||||
movl (elf_program_header + p64_filesz), %ebx
|
||||
movl (elf_program_header + p64_vaddr), %edi
|
||||
andl $LOAD_MASK, %edi
|
||||
addl %ebx, %edi
|
||||
movl (elf_program_header + p64_memsz), %ecx
|
||||
subl %ebx, %ecx
|
||||
xorb %al, %al; call memset32
|
||||
|
||||
# read file specified in program header to memory
|
||||
movl (elf_program_header + p64_offset), %eax
|
||||
movl (elf_program_header + p64_vaddr), %edi
|
||||
andl $LOAD_MASK, %edi
|
||||
movl (elf_program_header + p64_filesz), %ecx
|
||||
call *%esi
|
||||
|
||||
leavel
|
||||
popal
|
||||
ret
|
||||
|
||||
|
||||
# read callback format
|
||||
# eax: first byte
|
||||
|
@ -185,72 +104,42 @@ elf_read_kernel_to_memory:
|
|||
movl %esp, %ebp
|
||||
subl $2, %esp
|
||||
|
||||
# read start of file header
|
||||
# read file header
|
||||
movl $0, %eax
|
||||
movl $24, %ecx
|
||||
movl $64, %ecx
|
||||
movl $elf_file_header, %edi
|
||||
call *%esi
|
||||
|
||||
call elf_validate_file_header
|
||||
|
||||
# determine file header size
|
||||
movl $52, %ecx
|
||||
movl $64, %edx
|
||||
cmpb $ELFCLASS64, (elf_file_header + EI_CLASS)
|
||||
cmovel %edx, %ecx
|
||||
|
||||
# read full file header
|
||||
movl $0, %eax
|
||||
movl $elf_file_header, %edi
|
||||
call *%esi
|
||||
|
||||
# verify that e_phoff fits in 32 bits
|
||||
cmpb $ELFCLASS64, (elf_file_header + EI_CLASS)
|
||||
jne .elf_read_kernel_to_memory_valid_offset
|
||||
cmpl $0, (elf_file_header + e64_phoff + 4)
|
||||
cmpl $0, (elf_file_header + e_phoff + 4)
|
||||
jnz .elf_read_kernel_to_memory_unsupported_offset
|
||||
.elf_read_kernel_to_memory_valid_offset:
|
||||
|
||||
# read architecture phentsize and phnum to fixed locations
|
||||
movw (elf_file_header + e32_phentsize), %ax
|
||||
movw (elf_file_header + e32_phnum), %bx
|
||||
movl (elf_file_header + e32_phoff), %ecx
|
||||
cmpb $ELFCLASS64, (elf_file_header + EI_CLASS)
|
||||
cmovew (elf_file_header + e64_phentsize), %ax
|
||||
cmovew (elf_file_header + e64_phnum), %bx
|
||||
cmovel (elf_file_header + e64_phoff), %ecx
|
||||
movw %ax, (elf_file_header_phentsize)
|
||||
movw %bx, (elf_file_header_phnum)
|
||||
movl %ecx, (elf_file_header_phoff)
|
||||
|
||||
# current program header
|
||||
movw $0, -2(%ebp)
|
||||
|
||||
.elf_read_kernel_to_memory_loop_program_headers:
|
||||
movw -2(%ebp), %cx
|
||||
cmpw (elf_file_header_phnum), %cx
|
||||
cmpw (elf_file_header + e_phnum), %cx
|
||||
jae .elf_read_kernel_to_memory_done
|
||||
|
||||
# eax := program_header_index * e_phentsize + e_phoff
|
||||
xorl %eax, %eax
|
||||
movw %cx, %ax
|
||||
xorl %ebx, %ebx
|
||||
movw (elf_file_header_phentsize), %bx
|
||||
movw (elf_file_header + e_phentsize), %bx
|
||||
mull %ebx
|
||||
addl (elf_file_header_phoff), %eax
|
||||
addl (elf_file_header + e_phoff), %eax
|
||||
jc .elf_read_kernel_to_memory_unsupported_offset
|
||||
|
||||
# determine program header size
|
||||
movl $32, %ecx
|
||||
movl $56, %edx
|
||||
cmpb $ELFCLASS64, (elf_file_header + EI_CLASS)
|
||||
cmovel %edx, %ecx
|
||||
|
||||
# read program header
|
||||
# setup program header size and address
|
||||
movl $56, %ecx
|
||||
movl $elf_program_header, %edi
|
||||
|
||||
# read the program header
|
||||
call *%esi
|
||||
|
||||
# test if program header is NULL header
|
||||
# test if program header is empty
|
||||
cmpl $PT_NULL, (elf_program_header + p_type)
|
||||
je .elf_read_kernel_to_memory_null_program_header
|
||||
|
||||
|
@ -258,12 +147,33 @@ elf_read_kernel_to_memory:
|
|||
cmpl $PT_LOAD, (elf_program_header + p_type)
|
||||
jne .elf_read_kernel_to_memory_not_loadable_header
|
||||
|
||||
# read program header to memory
|
||||
movl $elf_read_program_header32_to_memory, %eax
|
||||
movl $elf_read_program_header64_to_memory, %ebx
|
||||
cmpb $ELFCLASS64, (elf_file_header + EI_CLASS)
|
||||
cmovel %ebx, %eax
|
||||
call *%eax
|
||||
# memset p_filesz -> p_memsz to 0
|
||||
movl (elf_program_header + p_filesz), %ebx
|
||||
|
||||
movl (elf_program_header + p_vaddr), %edi
|
||||
andl $0x7FFFFFFF, %edi
|
||||
addl %ebx, %edi
|
||||
|
||||
movl (elf_program_header + p_memsz), %ecx
|
||||
subl %ebx, %ecx
|
||||
jz .elf_read_kernel_to_memory_memset_done
|
||||
|
||||
.elf_read_kernel_to_memory_memset:
|
||||
movb $0, (%edi)
|
||||
incl %edi
|
||||
decl %ecx
|
||||
jnz .elf_read_kernel_to_memory_memset
|
||||
.elf_read_kernel_to_memory_memset_done:
|
||||
|
||||
# read file specified in program header to memory
|
||||
movl (elf_program_header + p_offset), %eax
|
||||
movl (elf_program_header + p_vaddr), %edi
|
||||
andl $0x7FFFFFFF, %edi
|
||||
movl (elf_program_header + p_filesz), %ecx
|
||||
|
||||
#call print_hex32; call print_newline
|
||||
|
||||
call *%esi
|
||||
|
||||
.elf_read_kernel_to_memory_null_program_header:
|
||||
incw -2(%ebp)
|
||||
|
@ -275,7 +185,7 @@ elf_read_kernel_to_memory:
|
|||
|
||||
# set kernel entry address
|
||||
movl (elf_file_header + e_entry), %eax
|
||||
andl $LOAD_MASK, %eax
|
||||
andl $0x7FFFFF, %eax
|
||||
|
||||
ret
|
||||
|
||||
|
@ -286,12 +196,11 @@ elf_read_kernel_to_memory:
|
|||
movw $elf_read_kernel_to_memory_not_loadable_header_msg, %si
|
||||
jmp print_and_halt
|
||||
|
||||
.section .data
|
||||
|
||||
elf_validate_file_header_invalid_magic_msg:
|
||||
.asciz "ELF: file has invalid ELF magic"
|
||||
elf_validate_file_header_invalid_class_msg:
|
||||
.asciz "ELF: file has invalid ELF class"
|
||||
elf_validate_file_header_only_64bit_supported_msg:
|
||||
.asciz "ELF: file is not targettint 64 bit"
|
||||
elf_validate_file_header_only_little_endian_supported_msg:
|
||||
.asciz "ELF: file is not in little endian format"
|
||||
elf_validate_file_header_not_current_version_msg:
|
||||
|
@ -309,12 +218,5 @@ elf_read_kernel_to_memory_not_loadable_header_msg:
|
|||
elf_file_header:
|
||||
.skip 64
|
||||
|
||||
elf_file_header_phentsize:
|
||||
.skip 2
|
||||
elf_file_header_phnum:
|
||||
.skip 2
|
||||
elf_file_header_phoff:
|
||||
.skip 4 # NOTE: only 32 bit offsets are supported
|
||||
|
||||
elf_program_header:
|
||||
.skip 56
|
||||
|
|
|
@ -2,7 +2,9 @@
|
|||
.set SECTOR_SHIFT, 9
|
||||
.set SECTOR_SIZE, 1 << SECTOR_SHIFT
|
||||
|
||||
.set EXT2_MAX_BLOCK_SIZE, 4096
|
||||
# FIXME: don't assume 1024 byte blocks
|
||||
.set EXT2_BLOCK_SHIFT, 10
|
||||
.set EXT2_BLOCK_SIZE, 1 << EXT2_BLOCK_SHIFT
|
||||
.set EXT2_SUPERBLOCK_SIZE, 264
|
||||
.set EXT2_BGD_SHIFT, 5
|
||||
.set EXT2_BGD_SIZE, 1 << EXT2_BGD_SHIFT
|
||||
|
@ -16,7 +18,6 @@
|
|||
.set EXT2_S_IFREG, 0x8000
|
||||
|
||||
# superblock offsets
|
||||
.set s_first_data_block, 20
|
||||
.set s_log_block_size, 24
|
||||
.set s_inodes_per_group, 40
|
||||
.set s_magic, 56
|
||||
|
@ -65,7 +66,9 @@ has_ext2_filesystem:
|
|||
|
||||
# from byte offset 1024
|
||||
addl $(1024 / SECTOR_SIZE), %eax
|
||||
adcw $0, %bx
|
||||
jnc .has_ext2_filesystem_no_overflow
|
||||
incw %bx
|
||||
.has_ext2_filesystem_no_overflow:
|
||||
|
||||
# into sector buffer
|
||||
movw $ext2_block_buffer, %di
|
||||
|
@ -87,16 +90,11 @@ has_ext2_filesystem:
|
|||
movl (ext2_superblock_buffer + s_log_block_size), %ecx
|
||||
testl $0xFFFFFF00, %ecx
|
||||
jnz .has_ext2_filesystem_unsupported_block_size
|
||||
# verify 1024 << s_log_block_size <= EXT2_MAX_BLOCK_SIZE
|
||||
# verify 1024 << s_log_block_size == EXT2_BLOCK_SIZE
|
||||
movl $1024, %eax
|
||||
shll %cl, %eax
|
||||
cmpl $EXT2_MAX_BLOCK_SIZE, %eax
|
||||
ja .has_ext2_filesystem_unsupported_block_size
|
||||
|
||||
# fill block size and shift
|
||||
movl %eax, (ext2_block_size)
|
||||
addl $10, %ecx
|
||||
movl %ecx, (ext2_block_shift)
|
||||
cmpl $EXT2_BLOCK_SIZE, %eax
|
||||
jne .has_ext2_filesystem_unsupported_block_size
|
||||
|
||||
# fill inode size
|
||||
movl $128, %eax
|
||||
|
@ -132,23 +130,38 @@ has_ext2_filesystem:
|
|||
# reads block in to ext2_block_buffer
|
||||
# eax: block number
|
||||
ext2_read_block:
|
||||
pushal
|
||||
pushl %eax
|
||||
pushl %ebx
|
||||
pushw %cx
|
||||
pushl %edx
|
||||
pushw %di
|
||||
|
||||
# ecx := sectors_per_block := block_size / sector_size
|
||||
movl (ext2_block_size), %ecx
|
||||
shrl $SECTOR_SHIFT, %ecx
|
||||
# NOTE: this assumes 1024 block size
|
||||
# eax := (block * block_size) / sector_size := (eax << EXT2_BLOCK_SHIFT) >> SECTOR_SHIFT
|
||||
xorl %edx, %edx
|
||||
shll $EXT2_BLOCK_SHIFT, %eax
|
||||
shrl $SECTOR_SHIFT, %eax
|
||||
|
||||
# ebx:eax := block * sectors_per_block + (ext2_partition_first_sector)
|
||||
xorl %ebx, %ebx
|
||||
mull %ecx
|
||||
# ebx:eax := eax + (ext2_partition_first_sector)
|
||||
movl (ext2_partition_first_sector + 4), %ebx
|
||||
addl (ext2_partition_first_sector + 0), %eax
|
||||
adcl (ext2_partition_first_sector + 4), %ebx
|
||||
jnc .ext2_read_block_no_carry
|
||||
incl %ebx
|
||||
.ext2_read_block_no_carry:
|
||||
|
||||
# sectors per block
|
||||
movw $(EXT2_BLOCK_SIZE / SECTOR_SIZE), %cx
|
||||
|
||||
movw $ext2_block_buffer, %di
|
||||
|
||||
movb (ext2_drive_number), %dl
|
||||
call read_from_disk
|
||||
|
||||
popal
|
||||
popw %di
|
||||
popl %edx
|
||||
popw %cx
|
||||
popl %ebx
|
||||
popl %eax
|
||||
ret
|
||||
|
||||
|
||||
|
@ -157,23 +170,15 @@ ext2_read_block:
|
|||
ext2_read_block_group_descriptor:
|
||||
pushal
|
||||
|
||||
# ebx := bgd_block_byte_offset := (s_first_data_block + 1) * block_size
|
||||
# := (s_first_data_block + 1) << ext2_block_shift
|
||||
movl (ext2_superblock_buffer + s_first_data_block), %ebx
|
||||
incl %ebx
|
||||
movb (ext2_block_shift), %cl
|
||||
shll %cl, %ebx
|
||||
# eax := bgd_byte_offset := 2048 + EXT2_BGD_SIZE * eax := (eax << EXT2_BGD_SHIFT) + 2048
|
||||
shll $EXT2_BGD_SHIFT, %eax
|
||||
addl $2048, %eax
|
||||
|
||||
# eax := bgd_byte_offset := bgd_block_byte_offset + EXT2_BGD_SIZE * block_group;
|
||||
# := bgd_block_byte_offset + (block_group << EXT2_BGD_SHIFT)
|
||||
movb $EXT2_BGD_SHIFT, %cl
|
||||
shll %cl, %eax
|
||||
addl %ebx, %eax
|
||||
|
||||
# eax: bgd_block := bgd_byte_offset / block_size
|
||||
# ebx: bgd_offset := bgd_byte_offset % block_size
|
||||
# eax: bgd_block := bgd_byte_offset / EXT2_BLOCK_SIZE
|
||||
# ebx: bgd_offset := bgd_byte_offset % EXT2_BLOCK_SIZE
|
||||
xorl %edx, %edx
|
||||
divl (ext2_block_size)
|
||||
movl $EXT2_BLOCK_SIZE, %ebx
|
||||
divl %ebx
|
||||
movl %edx, %ebx
|
||||
|
||||
call ext2_read_block
|
||||
|
@ -199,19 +204,23 @@ ext2_read_inode:
|
|||
# ebx := inode_index = (ino - 1) % s_inodes_per_group
|
||||
xorl %edx, %edx
|
||||
decl %eax
|
||||
divl (ext2_superblock_buffer + s_inodes_per_group)
|
||||
movl (ext2_superblock_buffer + s_inodes_per_group), %ebx
|
||||
divl %ebx
|
||||
movl %edx, %ebx
|
||||
|
||||
call ext2_read_block_group_descriptor
|
||||
|
||||
# eax := inode_table_block := (inode_index * inode_size) / block_size
|
||||
# ebx := inode_table_offset := (inode_index * inode_size) % block_size
|
||||
# eax := inode_table_block := (inode_index * inode_size) / EXT2_BLOCK_SIZE
|
||||
# ebx := inode_table_offset := (inode_index * inode_size) % EXT2_BLOCK_SIZE
|
||||
xorl %edx, %edx
|
||||
movl %ebx, %eax
|
||||
mull (ext2_inode_size)
|
||||
divl (ext2_block_size)
|
||||
movl (ext2_inode_size), %ebx
|
||||
mull %ebx
|
||||
movl $EXT2_BLOCK_SIZE, %ebx
|
||||
divl %ebx
|
||||
movl %edx, %ebx
|
||||
|
||||
# eax := filesystem_block := eax + bg_inode_table
|
||||
# eax := file system block := eax + bg_inode_table
|
||||
addl (ext2_block_group_descriptor_buffer + bg_inode_table), %eax
|
||||
|
||||
movb (ext2_drive_number), %dl
|
||||
|
@ -227,10 +236,6 @@ ext2_read_inode:
|
|||
movl (ext2_inode_size), %ecx
|
||||
rep movsb
|
||||
|
||||
# reset indirect cache to zero
|
||||
movl $0, (ext2_inode_indirect_number)
|
||||
|
||||
.ext2_read_inode_done:
|
||||
popal
|
||||
ret
|
||||
|
||||
|
@ -244,19 +249,15 @@ ext2_data_block_index:
|
|||
pushl %ecx
|
||||
pushl %edx
|
||||
pushl %esi
|
||||
pushl %edi
|
||||
|
||||
# ebx := max_data_blocks := (file_size + block_size - 1) / block_size
|
||||
# := (i_size + ext2_block_size - 1) >> ext2_block_shift
|
||||
# cl := ext2_block_shift
|
||||
movl (ext2_inode_buffer + i_size), %ebx
|
||||
addl (ext2_block_size), %ebx
|
||||
decl %ebx
|
||||
movb (ext2_block_shift), %cl
|
||||
shrl %cl, %ebx
|
||||
# calculate max data blocks
|
||||
movl (ext2_inode_buffer + i_size), %ecx
|
||||
addl (ext2_inode_size), %ecx
|
||||
decl %ecx
|
||||
shll $EXT2_BLOCK_SHIFT, %ecx
|
||||
|
||||
# verify data block is within bounds
|
||||
cmpl %ebx, %eax
|
||||
cmpl %ecx, %eax
|
||||
jae .ext2_data_block_index_out_of_bounds
|
||||
|
||||
# check if this is direct block access
|
||||
|
@ -264,26 +265,18 @@ ext2_data_block_index:
|
|||
jb .ext2_data_block_index_direct
|
||||
subl $12, %eax
|
||||
|
||||
# cl := indices_per_block_shift := ext2_block_shift - 2
|
||||
# ebx := comp
|
||||
subb $2, %cl
|
||||
movl $1, %ebx
|
||||
shll %cl, %ebx
|
||||
|
||||
# check if this is singly indirect block access
|
||||
cmpl %ebx, %eax
|
||||
cmpl $(EXT2_BLOCK_SIZE / 4), %eax
|
||||
jb .ext2_data_block_index_singly_indirect
|
||||
subl %ebx, %eax
|
||||
shll %cl, %ebx
|
||||
subl $(EXT2_BLOCK_SIZE / 4), %eax
|
||||
|
||||
# check if this is doubly indirect block access
|
||||
cmpl %ebx, %eax
|
||||
cmpl $((EXT2_BLOCK_SIZE / 4) * (EXT2_BLOCK_SIZE / 4)), %eax
|
||||
jb .ext2_data_block_index_doubly_indirect
|
||||
subl %ebx, %eax
|
||||
shll %cl, %ebx
|
||||
subl $((EXT2_BLOCK_SIZE / 4) * (EXT2_BLOCK_SIZE / 4)), %eax
|
||||
|
||||
# check if this is triply indirect block access
|
||||
cmpl %ebx, %eax
|
||||
cmpl $((EXT2_BLOCK_SIZE / 4) * (EXT2_BLOCK_SIZE / 4) * (EXT2_BLOCK_SIZE / 4)), %eax
|
||||
jb .ext2_data_block_index_triply_indirect
|
||||
|
||||
# otherwise this is invalid access
|
||||
|
@ -316,28 +309,6 @@ ext2_data_block_index:
|
|||
# ebx := index
|
||||
# cx := depth
|
||||
.ext2_data_block_index_indirect:
|
||||
# edx := cache index := (index & ~(block_size / 4 - 1)) | depth
|
||||
# := (index & -(block_size >> 2)) | depth
|
||||
movl (ext2_block_size), %edx
|
||||
shrl $2, %edx
|
||||
negl %edx
|
||||
andl %ebx, %edx
|
||||
orw %cx, %dx
|
||||
|
||||
# check whether this block is already cached
|
||||
cmpl $0, (ext2_inode_indirect_number)
|
||||
je .ext2_data_block_index_indirect_no_cache
|
||||
cmpl %edx, (ext2_inode_indirect_number)
|
||||
je .ext2_data_block_index_indirect_cached
|
||||
|
||||
.ext2_data_block_index_indirect_no_cache:
|
||||
# update cache block number, will be cached when found
|
||||
movl %edx, (ext2_inode_indirect_number)
|
||||
|
||||
# eax := current block
|
||||
# ebx := index
|
||||
# cx := depth
|
||||
.ext2_data_block_index_indirect_loop:
|
||||
call ext2_read_block
|
||||
|
||||
# store depth and index
|
||||
|
@ -348,21 +319,20 @@ ext2_data_block_index:
|
|||
jbe .ext2_data_block_index_no_shift
|
||||
|
||||
# cl := shift
|
||||
movb (ext2_block_shift), %al
|
||||
subb $2, %al
|
||||
movb $(EXT2_BLOCK_SHIFT - 2), %al
|
||||
decb %cl
|
||||
mulb %cl
|
||||
movb %al, %cl
|
||||
|
||||
# ebx := ebx >> shift
|
||||
# ebx := ebx >> cl
|
||||
shrl %cl, %ebx
|
||||
|
||||
.ext2_data_block_index_no_shift:
|
||||
# edx := index of next block (ebx & (block_size / 4 - 1))
|
||||
movl (ext2_block_size), %edx
|
||||
shrl $2, %edx
|
||||
decl %edx
|
||||
andl %ebx, %edx
|
||||
# edx := index of next block
|
||||
movl %ebx, %eax
|
||||
xorl %edx, %edx
|
||||
movl $(EXT2_BLOCK_SIZE / 4), %ebx
|
||||
divl %ebx
|
||||
|
||||
# eax := next block
|
||||
movl $ext2_block_buffer, %esi
|
||||
|
@ -372,13 +342,7 @@ ext2_data_block_index:
|
|||
popl %ebx
|
||||
popw %cx
|
||||
|
||||
loop .ext2_data_block_index_indirect_loop
|
||||
|
||||
# cache last read block
|
||||
movw $ext2_block_buffer, %si
|
||||
movw $ext2_inode_indirect_buffer, %di
|
||||
movw (ext2_block_size), %cx
|
||||
rep movsb
|
||||
loop .ext2_data_block_index_indirect
|
||||
|
||||
jmp .ext2_data_block_index_done
|
||||
|
||||
|
@ -394,16 +358,7 @@ ext2_data_block_index:
|
|||
movl $0, %eax
|
||||
jmp .ext2_data_block_index_done
|
||||
|
||||
.ext2_data_block_index_indirect_cached:
|
||||
movl $ext2_inode_indirect_buffer, %esi
|
||||
movl (ext2_block_size), %edx
|
||||
shrl $2, %edx
|
||||
decl %edx
|
||||
andl %edx, %ebx
|
||||
movl (%esi, %ebx, 4), %eax
|
||||
|
||||
.ext2_data_block_index_done:
|
||||
popl %edi
|
||||
popl %esi
|
||||
popl %edx
|
||||
popl %ecx
|
||||
|
@ -419,7 +374,6 @@ ext2_data_block_index:
|
|||
.global ext2_inode_read_bytes
|
||||
ext2_inode_read_bytes:
|
||||
pushal
|
||||
|
||||
pushl %ebp
|
||||
movl %esp, %ebp
|
||||
subl $8, %esp
|
||||
|
@ -428,11 +382,11 @@ ext2_inode_read_bytes:
|
|||
movl %eax, 0(%esp)
|
||||
movl %ecx, 4(%esp)
|
||||
|
||||
# eax := first_byte / block_size
|
||||
# edx := first_byte % block_size
|
||||
# when edx == 0, no partial read needed
|
||||
# check if eax % EXT2_BLOCK_SIZE != 0,
|
||||
# then we need to read a partial block starting from an offset
|
||||
xorl %edx, %edx
|
||||
divl (ext2_block_size)
|
||||
movl $EXT2_BLOCK_SIZE, %ebx
|
||||
divl %ebx
|
||||
testl %edx, %edx
|
||||
jz .ext2_inode_read_bytes_no_partial_start
|
||||
|
||||
|
@ -441,7 +395,7 @@ ext2_inode_read_bytes:
|
|||
call ext2_read_block
|
||||
|
||||
# ecx := byte count (min(block_size - edx, remaining_bytes))
|
||||
movl (ext2_block_size), %ecx
|
||||
movl $EXT2_BLOCK_SIZE, %ecx
|
||||
subl %edx, %ecx
|
||||
cmpl %ecx, 4(%esp)
|
||||
cmovbl 4(%esp), %ecx
|
||||
|
@ -454,7 +408,15 @@ ext2_inode_read_bytes:
|
|||
movl $ext2_block_buffer, %esi
|
||||
addl %edx, %esi
|
||||
|
||||
call memcpy32
|
||||
# very dumb memcpy with 32 bit addresses
|
||||
movl $0, %ebx
|
||||
.ext2_inode_read_bytes_memcpy_partial:
|
||||
movb (%esi, %ebx), %al
|
||||
movb %al, (%edi, %ebx)
|
||||
incl %ebx
|
||||
decl %ecx
|
||||
jnz .ext2_inode_read_bytes_memcpy_partial
|
||||
addl %ebx, %edi
|
||||
|
||||
# check if all sectors are read
|
||||
cmpl $0, 4(%esp)
|
||||
|
@ -463,15 +425,14 @@ ext2_inode_read_bytes:
|
|||
.ext2_inode_read_bytes_no_partial_start:
|
||||
# eax := data block index (byte_start / block_size)
|
||||
movl 0(%esp), %eax
|
||||
movb (ext2_block_shift), %cl
|
||||
shrl %cl, %eax
|
||||
shrl $(EXT2_BLOCK_SHIFT), %eax
|
||||
|
||||
# get data block index and read block
|
||||
call ext2_data_block_index
|
||||
call ext2_read_block
|
||||
|
||||
# calculate bytes to copy (min(block_size, remaining_bytes))
|
||||
movl (ext2_block_size), %ecx
|
||||
movl $EXT2_BLOCK_SIZE, %ecx
|
||||
cmpl %ecx, 4(%esp)
|
||||
cmovbl 4(%esp), %ecx
|
||||
|
||||
|
@ -479,8 +440,16 @@ ext2_inode_read_bytes:
|
|||
addl %ecx, 0(%esp)
|
||||
subl %ecx, 4(%esp)
|
||||
|
||||
# very dumb memcpy with 32 bit addresses
|
||||
movl $ext2_block_buffer, %esi
|
||||
call memcpy32
|
||||
movl $0, %ebx
|
||||
.ext2_inode_read_bytes_memcpy:
|
||||
movb (%esi, %ebx), %al
|
||||
movb %al, (%edi, %ebx)
|
||||
incl %ebx
|
||||
decl %ecx
|
||||
jnz .ext2_inode_read_bytes_memcpy
|
||||
addl %ebx, %edi
|
||||
|
||||
# read next block if more sectors remaining
|
||||
cmpl $0, 4(%esp)
|
||||
|
@ -519,12 +488,11 @@ ext2_directory_find_inode:
|
|||
cmpw $0xFF, %cx
|
||||
ja .ext2_directory_find_inode_not_found
|
||||
|
||||
# ebx := max data blocks: ceil(i_size / block_size)
|
||||
# ebx := max data blocks: ceil(i_size / EXT2_BLOCK_SIZE)
|
||||
movl (ext2_inode_buffer + i_size), %ebx
|
||||
addl (ext2_block_size), %ebx
|
||||
addl $EXT2_BLOCK_SHIFT, %ebx
|
||||
decl %ebx
|
||||
movb (ext2_block_shift), %cl
|
||||
shrl %cl, %ebx
|
||||
shrl $EXT2_BLOCK_SHIFT, %ebx
|
||||
jz .ext2_directory_find_inode_not_found
|
||||
|
||||
# 4(%esp) := current block
|
||||
|
@ -571,9 +539,7 @@ ext2_directory_find_inode:
|
|||
|
||||
# go to next entry if this block contains one
|
||||
addw 4(%si), %si
|
||||
movw $ext2_block_buffer, %di
|
||||
addw (ext2_block_size), %di
|
||||
cmpw %di, %si
|
||||
cmpw $(ext2_block_buffer + EXT2_BLOCK_SIZE), %si
|
||||
jb .ext2_directory_find_inode_loop_entries
|
||||
|
||||
.ext2_directory_find_inode_next_block:
|
||||
|
@ -582,7 +548,7 @@ ext2_directory_find_inode:
|
|||
jb .ext2_directory_find_inode_block_read_loop
|
||||
|
||||
.ext2_directory_find_inode_not_found:
|
||||
xorb %al, %al
|
||||
movb $0, %al
|
||||
jmp .ext2_directory_find_inode_done
|
||||
|
||||
.ext2_directory_find_inode_found:
|
||||
|
@ -676,7 +642,6 @@ ext2_find_kernel:
|
|||
movw $ext2_kernel_not_reg_msg, %si
|
||||
jmp print_and_halt
|
||||
|
||||
.section .data
|
||||
|
||||
kernel_path:
|
||||
.short kernel_path1
|
||||
|
@ -689,12 +654,13 @@ kernel_path2:
|
|||
.short 15
|
||||
.asciz "banan-os.kernel"
|
||||
|
||||
|
||||
root_partition_does_not_fit_ext2_filesystem_msg:
|
||||
.asciz "Root partition is too small to contain ext2 filesystem"
|
||||
root_partition_has_invalid_ext2_magic_msg:
|
||||
.asciz "Root partition doesn't contain ext2 magic number"
|
||||
root_partition_has_unsupported_ext2_block_size_msg:
|
||||
.asciz "Root partition has unsupported ext2 block size (1 KiB, 2 KiB and 4 KiB are supported)"
|
||||
.asciz "Root partition has unsupported ext2 block size (only 1024 supported)"
|
||||
|
||||
ext2_part_not_dir_msg:
|
||||
.asciz "inode in root path is not directory"
|
||||
|
@ -715,14 +681,8 @@ ext2_looking_for_msg:
|
|||
|
||||
.section .bss
|
||||
|
||||
.align SECTOR_SIZE
|
||||
ext2_block_buffer:
|
||||
.skip EXT2_MAX_BLOCK_SIZE
|
||||
|
||||
ext2_inode_indirect_buffer:
|
||||
.skip EXT2_MAX_BLOCK_SIZE
|
||||
ext2_inode_indirect_number:
|
||||
.skip 4
|
||||
.skip EXT2_BLOCK_SIZE
|
||||
|
||||
ext2_partition_first_sector:
|
||||
.skip 8
|
||||
|
@ -734,10 +694,6 @@ ext2_drive_number:
|
|||
# NOTE: fits in 2 bytes
|
||||
ext2_inode_size:
|
||||
.skip 4
|
||||
ext2_block_size:
|
||||
.skip 4
|
||||
ext2_block_shift:
|
||||
.skip 4
|
||||
|
||||
ext2_superblock_buffer:
|
||||
.skip EXT2_SUPERBLOCK_SIZE
|
||||
|
|
|
@ -1,67 +1,19 @@
|
|||
.set TARGET_WIDTH, 800
|
||||
.set TARGET_HEIGHT, 600
|
||||
.set TARGET_BPP, 32
|
||||
|
||||
.code16
|
||||
.section .stage2
|
||||
|
||||
# kernel framebuffer information format
|
||||
# .align 8
|
||||
# .long 0xBABAB007
|
||||
# .long -(0xBABAB007 + width + height + bpp)
|
||||
# .long width (2 bytes used, 4 bytes for ease of calculation)
|
||||
# .long height (2 bytes used, 4 bytes for ease of calculation)
|
||||
# .long bpp (1 bytes used, 4 bytes for ease of calculation)
|
||||
|
||||
# scan memory 0x100000 -> 0x200000 for framebuffer information
|
||||
# Find suitable video mode
|
||||
# return:
|
||||
# ax: target width
|
||||
# bx: target height
|
||||
# cx: target bpp
|
||||
vesa_scan_kernel_image:
|
||||
pushl %edx
|
||||
pushl %esi
|
||||
|
||||
movl $0x100000, %esi
|
||||
|
||||
.vesa_scan_kernel_image_loop:
|
||||
# check magic
|
||||
cmpl $0xBABAB007, (%esi)
|
||||
jne .vesa_scan_kernel_image_next_addr
|
||||
|
||||
# check checksum
|
||||
movl 0x00(%esi), %edx
|
||||
addl 0x04(%esi), %edx
|
||||
addl 0x08(%esi), %edx
|
||||
addl 0x0C(%esi), %edx
|
||||
addl 0x10(%esi), %edx
|
||||
testl %edx, %edx
|
||||
jnz .vesa_scan_kernel_image_next_addr
|
||||
|
||||
# set return registers
|
||||
movw 0x08(%esi), %ax
|
||||
movw 0x0C(%esi), %bx
|
||||
movw 0x10(%esi), %cx
|
||||
jmp .vesa_scan_kernel_image_done
|
||||
|
||||
.vesa_scan_kernel_image_next_addr:
|
||||
addl $8, %esi
|
||||
cmpl $0x200000, %esi
|
||||
jb .vesa_scan_kernel_image_loop
|
||||
|
||||
# zero out return registers
|
||||
xorw %ax, %ax
|
||||
xorw %bx, %bx
|
||||
xorw %cx, %cx
|
||||
|
||||
.vesa_scan_kernel_image_done:
|
||||
popl %esi
|
||||
popl %edx
|
||||
ret
|
||||
|
||||
# Find suitable video mode and save it in (vesa_target_mode)
|
||||
# ax: video mode number if found, 0 otherwise
|
||||
.global vesa_find_video_mode
|
||||
vesa_find_video_mode:
|
||||
pushal
|
||||
|
||||
pushl %ebp
|
||||
movl %esp, %ebp
|
||||
subl $6, %esp
|
||||
pushw %ax
|
||||
pushw %cx
|
||||
pushw %di
|
||||
pushl %esi
|
||||
|
||||
# clear target mode and frame buffer
|
||||
movw $0, (vesa_target_mode)
|
||||
|
@ -71,19 +23,10 @@ vesa_find_video_mode:
|
|||
movl $0, (framebuffer + 12)
|
||||
movw $0, (framebuffer + 16)
|
||||
|
||||
call vesa_scan_kernel_image
|
||||
testw %ax, %ax
|
||||
jz .vesa_find_video_mode_loop_modes_done
|
||||
|
||||
# save arguments in stack
|
||||
movw %ax, -2(%ebp)
|
||||
movw %bx, -4(%ebp)
|
||||
movw %cx, -6(%ebp)
|
||||
|
||||
# get vesa information
|
||||
movw $0x4F00, %ax
|
||||
movw $vesa_info_buffer, %di
|
||||
pushl %ebp; int $0x10; popl %ebp # BOCHS doesn't seem to reserve ebp
|
||||
int $0x10
|
||||
cmpb $0x4F, %al; jne .vesa_unsupported
|
||||
cmpb $0x00, %ah; jne .vesa_error
|
||||
|
||||
|
@ -95,7 +38,8 @@ vesa_find_video_mode:
|
|||
cmpw $0x0200, (vesa_info_buffer + 0x04)
|
||||
jb .vesa_unsupported_version
|
||||
|
||||
movl (vesa_info_buffer + 0x0E), %esi
|
||||
movl $(vesa_info_buffer + 0x0E), %esi
|
||||
movl (%esi), %esi
|
||||
.vesa_find_video_mode_loop_modes:
|
||||
cmpw $0xFFFF, (%esi)
|
||||
je .vesa_find_video_mode_loop_modes_done
|
||||
|
@ -104,7 +48,7 @@ vesa_find_video_mode:
|
|||
movw $0x4F01, %ax
|
||||
movw (%esi), %cx
|
||||
movw $vesa_mode_info_buffer, %di
|
||||
pushl %ebp; int $0x10; popl %ebp # BOCHS doesn't seem to reserve ebp
|
||||
int $0x10
|
||||
cmpb $0x4F, %al; jne .vesa_unsupported
|
||||
cmpb $0x00, %ah; jne .vesa_error
|
||||
|
||||
|
@ -113,24 +57,21 @@ vesa_find_video_mode:
|
|||
jz .vesa_find_video_mode_next_mode
|
||||
|
||||
# compare mode's dimensions
|
||||
movw -2(%ebp), %ax; cmpw %ax, (vesa_mode_info_buffer + 0x12)
|
||||
cmpw $TARGET_WIDTH, (vesa_mode_info_buffer + 0x12)
|
||||
jne .vesa_find_video_mode_next_mode
|
||||
movw -4(%ebp), %ax; cmpw %ax, (vesa_mode_info_buffer + 0x14)
|
||||
cmpw $TARGET_HEIGHT, (vesa_mode_info_buffer + 0x14)
|
||||
jne .vesa_find_video_mode_next_mode
|
||||
movb -6(%ebp), %al; cmpb %al, (vesa_mode_info_buffer + 0x19)
|
||||
cmpb $TARGET_BPP, (vesa_mode_info_buffer + 0x19)
|
||||
jne .vesa_find_video_mode_next_mode
|
||||
|
||||
# set address, pitch, type
|
||||
movl (vesa_mode_info_buffer + 0x28), %esi
|
||||
movl %esi, (framebuffer + 0)
|
||||
movl %esi, (framebuffer + 0)
|
||||
movw (vesa_mode_info_buffer + 0x10), %ax
|
||||
movw %ax, (framebuffer + 4)
|
||||
movb $1, (framebuffer + 17)
|
||||
|
||||
# set width, height, bpp
|
||||
movw -2(%ebp), %ax; movw %ax, (framebuffer + 8)
|
||||
movw -4(%ebp), %ax; movw %ax, (framebuffer + 12)
|
||||
movw -6(%ebp), %ax; movb %al, (framebuffer + 16)
|
||||
movw %ax, (framebuffer + 4)
|
||||
movl $TARGET_WIDTH, (framebuffer + 8)
|
||||
movl $TARGET_HEIGHT, (framebuffer + 12)
|
||||
movb $TARGET_BPP, (framebuffer + 16)
|
||||
movb $1, (framebuffer + 17)
|
||||
|
||||
movw %cx, (vesa_target_mode)
|
||||
jmp .vesa_find_video_mode_loop_modes_done
|
||||
|
@ -140,8 +81,10 @@ vesa_find_video_mode:
|
|||
jmp .vesa_find_video_mode_loop_modes
|
||||
|
||||
.vesa_find_video_mode_loop_modes_done:
|
||||
leavel
|
||||
popal
|
||||
popl %esi
|
||||
popw %di
|
||||
popw %cx
|
||||
popw %ax
|
||||
ret
|
||||
|
||||
.vesa_unsupported:
|
||||
|
@ -155,37 +98,33 @@ vesa_find_video_mode:
|
|||
jmp print_and_halt
|
||||
|
||||
|
||||
# scan for video mode in kernel memory and set the correct one.
|
||||
# when video mode is not found or does not exists,
|
||||
# set it to 80x25 text mode to clear the screen.
|
||||
.global vesa_set_video_mode
|
||||
vesa_set_video_mode:
|
||||
# set mode found from vesa_find_video_mode. if no mode
|
||||
# was found, set it to 80x25 text mode to clear the screen.
|
||||
.global vesa_set_target_mode
|
||||
vesa_set_target_mode:
|
||||
pushw %ax
|
||||
pushw %bx
|
||||
|
||||
call vesa_find_video_mode
|
||||
|
||||
movw (vesa_target_mode), %bx
|
||||
testw %bx, %bx
|
||||
jz .vesa_set_target_mode_generic
|
||||
jz .vesa_set_target_mode_generic
|
||||
|
||||
movw $0x4F02, %ax
|
||||
orw $0x4000, %bx
|
||||
pushl %ebp; int $0x10; popl %ebp # BOCHS doesn't seem to reserve ebp
|
||||
int $0x10
|
||||
|
||||
jmp .set_video_done
|
||||
|
||||
.vesa_set_target_mode_generic:
|
||||
movb $0x03, %al
|
||||
movb $0x00, %ah
|
||||
pushl %ebp; int $0x10; popl %ebp # BOCHS doesn't seem to reserve ebp
|
||||
int $0x10
|
||||
|
||||
.set_video_done:
|
||||
popw %bx
|
||||
popw %ax
|
||||
ret
|
||||
|
||||
.section .data
|
||||
|
||||
vesa_error_msg:
|
||||
.asciz "VESA error"
|
||||
|
@ -208,7 +147,6 @@ vesa_target_mode:
|
|||
.skip 2
|
||||
|
||||
.global framebuffer
|
||||
.align 8
|
||||
framebuffer:
|
||||
.skip 4 # address
|
||||
.skip 4 # pitch
|
||||
|
|
|
@ -8,10 +8,8 @@ SECTIONS
|
|||
. = ALIGN(512);
|
||||
stage2_start = .;
|
||||
.stage2 : { *(.stage2) }
|
||||
. = ALIGN(512);
|
||||
.data : { *(.data) }
|
||||
stage2_end = .;
|
||||
|
||||
. = ALIGN(512);
|
||||
.bss : { *(.bss) }
|
||||
}
|
||||
}
|
|
@ -114,7 +114,6 @@ print_memory_map:
|
|||
|
||||
ret
|
||||
|
||||
.section .data
|
||||
|
||||
memory_map_msg:
|
||||
.asciz "memmap:"
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
.include "common.S"
|
||||
|
||||
.set SCREEN_WIDTH, 80
|
||||
.set SCREEN_HEIGHT, 25
|
||||
|
||||
|
@ -275,127 +273,6 @@ isprint:
|
|||
movb $0, %al
|
||||
ret
|
||||
|
||||
|
||||
# memset with 32 bit registers
|
||||
# edi: destination address
|
||||
# ecx: bytes count
|
||||
# al: value to set
|
||||
# return:
|
||||
# edi: destination address + bytes count
|
||||
# ecx: 0
|
||||
# other: preserved
|
||||
.global memset32
|
||||
memset32:
|
||||
testl %ecx, %ecx
|
||||
jz .memset32_done
|
||||
|
||||
pushf; cli
|
||||
pushw %es
|
||||
pushl %eax
|
||||
pushl %ebx
|
||||
pushl %edx
|
||||
|
||||
movl %cr0, %ebx
|
||||
orb $1, %bl
|
||||
movl %ebx, %cr0
|
||||
|
||||
ljmpl $GDT_CODE32, $.memset32_pmode32
|
||||
|
||||
.code32
|
||||
.memset32_pmode32:
|
||||
movw $GDT_DATA32, %dx
|
||||
movw %dx, %es
|
||||
|
||||
movl %ecx, %edx
|
||||
|
||||
andl $3, %ecx
|
||||
rep stosb %es:(%edi)
|
||||
|
||||
movl %edx, %ecx
|
||||
shrl $2, %ecx
|
||||
|
||||
movb %al, %ah
|
||||
movw %ax, %dx
|
||||
shll $16, %eax
|
||||
movw %dx, %ax
|
||||
rep stosl %es:(%edi)
|
||||
|
||||
ljmpl $GDT_CODE16, $.memset32_pmode16
|
||||
|
||||
.code16
|
||||
.memset32_pmode16:
|
||||
andb $0xFE, %bl
|
||||
movl %ebx, %cr0
|
||||
ljmpl $0x00, $.memset32_rmode16
|
||||
|
||||
.memset32_rmode16:
|
||||
popl %edx
|
||||
popl %ebx
|
||||
popl %eax
|
||||
popw %es
|
||||
popf
|
||||
|
||||
.memset32_done:
|
||||
ret
|
||||
|
||||
# memcpy with 32 bit registers
|
||||
# esi: source address
|
||||
# edi: destination address
|
||||
# ecx: bytes count
|
||||
# return:
|
||||
# esi: source address + bytes count
|
||||
# edi: destination address + bytes count
|
||||
# ecx: 0
|
||||
# other: preserved
|
||||
.global memcpy32
|
||||
memcpy32:
|
||||
testl %ecx, %ecx
|
||||
jz .memcpy32_done
|
||||
|
||||
pushf; cli
|
||||
pushw %ds
|
||||
pushw %es
|
||||
pushl %ebx
|
||||
pushl %edx
|
||||
|
||||
movl %cr0, %ebx
|
||||
orb $1, %bl
|
||||
movl %ebx, %cr0
|
||||
|
||||
ljmpl $GDT_CODE32, $.memcpy32_pmode32
|
||||
|
||||
.code32
|
||||
.memcpy32_pmode32:
|
||||
movw $GDT_DATA32, %dx
|
||||
movw %dx, %ds
|
||||
movw %dx, %es
|
||||
|
||||
movl %ecx, %edx
|
||||
andl $3, %ecx
|
||||
rep movsb %ds:(%esi), %es:(%edi)
|
||||
|
||||
movl %edx, %ecx
|
||||
shrl $2, %ecx
|
||||
rep movsl %ds:(%esi), %es:(%edi)
|
||||
|
||||
ljmpl $GDT_CODE16, $.memcpy32_pmode16
|
||||
|
||||
.code16
|
||||
.memcpy32_pmode16:
|
||||
andb $0xFE, %bl
|
||||
movl %ebx, %cr0
|
||||
ljmpl $0x00, $.memcpy32_rmode16
|
||||
|
||||
.memcpy32_rmode16:
|
||||
popl %edx
|
||||
popl %ebx
|
||||
popw %es
|
||||
popw %ds
|
||||
popf
|
||||
|
||||
.memcpy32_done:
|
||||
ret
|
||||
|
||||
.section .bss
|
||||
|
||||
# enough for base 2 printing
|
||||
|
|
|
@ -1,11 +1,6 @@
|
|||
cmake_minimum_required(VERSION 3.26)
|
||||
|
||||
if (NOT DEFINED ENV{BANAN_ARCH})
|
||||
message(FATAL_ERROR "environment variable BANAN_ARCH not defined")
|
||||
endif ()
|
||||
set(BANAN_ARCH $ENV{BANAN_ARCH})
|
||||
|
||||
project(banan_os-bootloader-installer CXX)
|
||||
project(x86_64-banan_os-bootloader-installer CXX)
|
||||
|
||||
set(SOURCES
|
||||
crc32.cpp
|
||||
|
@ -15,8 +10,8 @@ set(SOURCES
|
|||
main.cpp
|
||||
)
|
||||
|
||||
add_executable(banan_os-bootloader-installer ${SOURCES})
|
||||
target_compile_options(banan_os-bootloader-installer PRIVATE -O2 -std=c++20)
|
||||
target_compile_definitions(banan_os-bootloader-installer PRIVATE __arch=${BANAN_ARCH})
|
||||
target_include_directories(banan_os-bootloader-installer PRIVATE ${CMAKE_SOURCE_DIR}/../../userspace/libraries/LibELF/include)
|
||||
target_include_directories(banan_os-bootloader-installer PRIVATE ${CMAKE_SOURCE_DIR}/../../kernel/include)
|
||||
add_executable(x86_64-banan_os-bootloader-installer ${SOURCES})
|
||||
target_compile_options(x86_64-banan_os-bootloader-installer PRIVATE -O2 -std=c++20)
|
||||
target_compile_definitions(x86_64-banan_os-bootloader-installer PRIVATE __arch=x86_64)
|
||||
target_include_directories(x86_64-banan_os-bootloader-installer PRIVATE ${CMAKE_SOURCE_DIR}/../../LibELF/include)
|
||||
target_include_directories(x86_64-banan_os-bootloader-installer PRIVATE ${CMAKE_SOURCE_DIR}/../../kernel/include)
|
||||
|
|
|
@ -81,7 +81,7 @@ bool ELFFile::validate_elf_header() const
|
|||
|
||||
#if ARCH(x86_64)
|
||||
if (elf_header.e_ident[EI_CLASS] != ELFCLASS64)
|
||||
#elif ARCH(i686)
|
||||
#elif ARCH(i386)
|
||||
if (elf_header.e_ident[EI_CLASS] != ELFCLASS32)
|
||||
#endif
|
||||
{
|
||||
|
|
|
@ -99,33 +99,33 @@ bool GPTFile::install_stage1(std::span<const uint8_t> stage1)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool GPTFile::install_stage2(std::span<const uint8_t> stage2, std::span<const uint8_t> data, const GUID& root_partition_guid)
|
||||
bool GPTFile::install_stage2(std::span<const uint8_t> stage2, const GUID& root_partition_guid)
|
||||
{
|
||||
if (data.size() < 16)
|
||||
if (stage2.size() < 16)
|
||||
{
|
||||
std::cerr << m_path << ": contains invalid .data section, too small for patches" << std::endl;
|
||||
std::cerr << m_path << ": contains invalid .stage2 section, too small for patches" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// find GUID patch offsets
|
||||
std::size_t disk_guid_offset(-1);
|
||||
std::size_t part_guid_offset(-1);
|
||||
for (std::size_t i = 0; i < data.size() - 16; i++)
|
||||
for (std::size_t i = 0; i < stage2.size() - 16; i++)
|
||||
{
|
||||
if (memcmp(data.data() + i, "root disk guid ", 16) == 0)
|
||||
if (memcmp(stage2.data() + i, "root disk guid ", 16) == 0)
|
||||
{
|
||||
if (disk_guid_offset != std::size_t(-1))
|
||||
{
|
||||
std::cerr << m_path << ": contains invalid .data section, multiple patchable disk guids" << std::endl;
|
||||
std::cerr << m_path << ": contains invalid .stage2 section, multiple patchable disk guids" << std::endl;
|
||||
return false;
|
||||
}
|
||||
disk_guid_offset = i;
|
||||
}
|
||||
if (memcmp(data.data() + i, "root part guid ", 16) == 0)
|
||||
if (memcmp(stage2.data() + i, "root part guid ", 16) == 0)
|
||||
{
|
||||
if (part_guid_offset != std::size_t(-1))
|
||||
{
|
||||
std::cerr << m_path << ": contains invalid .data section, multiple patchable partition guids" << std::endl;
|
||||
std::cerr << m_path << ": contains invalid .stage2 section, multiple patchable partition guids" << std::endl;
|
||||
return false;
|
||||
}
|
||||
part_guid_offset = i;
|
||||
|
@ -133,14 +133,15 @@ bool GPTFile::install_stage2(std::span<const uint8_t> stage2, std::span<const ui
|
|||
}
|
||||
if (disk_guid_offset == std::size_t(-1))
|
||||
{
|
||||
std::cerr << m_path << ": contains invalid .data section, no patchable disk guid" << std::endl;
|
||||
std::cerr << m_path << ": contains invalid .stage2 section, no patchable disk guid" << std::endl;
|
||||
return false;
|
||||
}
|
||||
if (part_guid_offset == std::size_t(-1))
|
||||
{
|
||||
std::cerr << m_path << ": contains invalid .data section, no patchable partition guid" << std::endl;
|
||||
std::cerr << m_path << ": contains invalid .stage2 section, no patchable partition guid" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
auto partition = find_partition_with_type(bios_boot_guid);
|
||||
if (!partition.has_value())
|
||||
|
@ -151,28 +152,23 @@ bool GPTFile::install_stage2(std::span<const uint8_t> stage2, std::span<const ui
|
|||
|
||||
const std::size_t partition_size = (partition->ending_lba - partition->starting_lba + 1) * SECTOR_SIZE;
|
||||
|
||||
std::size_t data_offset = stage2.size();
|
||||
if (std::size_t rem = data_offset % 512)
|
||||
data_offset += 512 - rem;
|
||||
|
||||
if (data_offset + data.size() > partition_size)
|
||||
if (stage2.size() > partition_size)
|
||||
{
|
||||
std::cerr << m_path << ": can't fit " << stage2.size() + data.size() << " bytes of data to partition of size " << partition_size << std::endl;
|
||||
std::cerr << m_path << ": can't fit " << stage2.size() << " bytes of data to partition of size " << partition_size << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t* partition_start = m_mmap + partition->starting_lba * SECTOR_SIZE;
|
||||
memcpy(partition_start, stage2.data(), stage2.size());
|
||||
memcpy(partition_start + data_offset, data.data(), data.size());
|
||||
|
||||
// patch GUIDs
|
||||
*reinterpret_cast<GUID*>(partition_start + data_offset + disk_guid_offset) = gpt_header().disk_guid;
|
||||
*reinterpret_cast<GUID*>(partition_start + data_offset + part_guid_offset) = root_partition_guid;
|
||||
*reinterpret_cast<GUID*>(partition_start + disk_guid_offset) = gpt_header().disk_guid;
|
||||
*reinterpret_cast<GUID*>(partition_start + part_guid_offset) = root_partition_guid;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GPTFile::install_bootloader(std::span<const uint8_t> stage1, std::span<const uint8_t> stage2, std::span<const uint8_t> data, const GUID& root_partition_guid)
|
||||
bool GPTFile::install_bootloader(std::span<const uint8_t> stage1, std::span<const uint8_t> stage2, const GUID& root_partition_guid)
|
||||
{
|
||||
if (!find_partition_with_guid(root_partition_guid).has_value())
|
||||
{
|
||||
|
@ -181,7 +177,7 @@ bool GPTFile::install_bootloader(std::span<const uint8_t> stage1, std::span<cons
|
|||
}
|
||||
if (!install_stage1(stage1))
|
||||
return false;
|
||||
if (!install_stage2(stage2, data, root_partition_guid))
|
||||
if (!install_stage2(stage2, root_partition_guid))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -65,7 +65,7 @@ public:
|
|||
GPTFile(std::string_view path);
|
||||
~GPTFile();
|
||||
|
||||
bool install_bootloader(std::span<const uint8_t> stage1, std::span<const uint8_t> stage2, std::span<const uint8_t> data, const GUID& root_partition_guid);
|
||||
bool install_bootloader(std::span<const uint8_t> stage1, std::span<const uint8_t> stage2, const GUID& root_partition_guid);
|
||||
|
||||
const GPTHeader& gpt_header() const;
|
||||
|
||||
|
@ -80,7 +80,7 @@ private:
|
|||
std::optional<GPTPartitionEntry> find_partition_with_type(const GUID& type_guid) const;
|
||||
|
||||
bool install_stage1(std::span<const uint8_t> stage1);
|
||||
bool install_stage2(std::span<const uint8_t> stage2, std::span<const uint8_t> data, const GUID& root_partition_guid);
|
||||
bool install_stage2(std::span<const uint8_t> stage2, const GUID& root_partition_guid);
|
||||
|
||||
private:
|
||||
const std::string m_path;
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
#!/bin/sh
|
||||
|
||||
g++ -O2 -std=c++20 main.cpp crc32.cpp ELF.cpp GPT.cpp GUID.cpp -o install-bootloader
|
|
@ -26,10 +26,9 @@ int main(int argc, char** argv)
|
|||
|
||||
auto stage1 = bootloader.find_section(".stage1"sv);
|
||||
auto stage2 = bootloader.find_section(".stage2"sv);
|
||||
auto data = bootloader.find_section(".data"sv);
|
||||
if (!stage1.has_value() || !stage2.has_value() || !data.has_value())
|
||||
if (!stage1.has_value() || !stage2.has_value())
|
||||
{
|
||||
std::cerr << bootloader.path() << " doesn't contain .stage1, .stage2 and .data sections" << std::endl;
|
||||
std::cerr << bootloader.path() << " doesn't contain .stage1 and .stage2 sections" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -37,9 +36,9 @@ int main(int argc, char** argv)
|
|||
if (!disk_image.success())
|
||||
return 1;
|
||||
|
||||
if (!disk_image.install_bootloader(*stage1, *stage2, *data, *root_partition_guid))
|
||||
if (!disk_image.install_bootloader(*stage1, *stage2, *root_partition_guid))
|
||||
return 1;
|
||||
std::cout << "bootloader installed" << std::endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
|
@ -1,30 +1,28 @@
|
|||
cmake_minimum_required(VERSION 3.26)
|
||||
|
||||
project(kernel CXX C ASM)
|
||||
|
||||
if("${BANAN_ARCH}" STREQUAL "x86_64")
|
||||
set(ELF_FORMAT elf64-x86-64)
|
||||
elseif("${BANAN_ARCH}" STREQUAL "i386")
|
||||
set(ELF_FORMAT elf32-i386)
|
||||
endif()
|
||||
|
||||
set(KERNEL_SOURCES
|
||||
font/prefs.psf.o
|
||||
kernel/ACPI/ACPI.cpp
|
||||
kernel/ACPI/AML.cpp
|
||||
kernel/ACPI/AML/Field.cpp
|
||||
kernel/ACPI/AML/NamedObject.cpp
|
||||
kernel/ACPI/AML/Namespace.cpp
|
||||
kernel/ACPI/AML/Node.cpp
|
||||
kernel/ACPI/AML/Package.cpp
|
||||
kernel/ACPI/AML/Scope.cpp
|
||||
kernel/ACPI.cpp
|
||||
kernel/APIC.cpp
|
||||
kernel/BootInfo.cpp
|
||||
kernel/CPUID.cpp
|
||||
kernel/Credentials.cpp
|
||||
kernel/Debug.cpp
|
||||
kernel/Device/DebugDevice.cpp
|
||||
kernel/Device/Device.cpp
|
||||
kernel/Device/FramebufferDevice.cpp
|
||||
kernel/Device/NullDevice.cpp
|
||||
kernel/Device/ZeroDevice.cpp
|
||||
kernel/Errors.cpp
|
||||
kernel/Font.cpp
|
||||
kernel/FS/DevFS/FileSystem.cpp
|
||||
kernel/FS/Ext2/FileSystem.cpp
|
||||
kernel/FS/Ext2/Inode.cpp
|
||||
kernel/FS/FAT/FileSystem.cpp
|
||||
kernel/FS/FAT/Inode.cpp
|
||||
kernel/FS/FileSystem.cpp
|
||||
kernel/FS/Inode.cpp
|
||||
kernel/FS/Pipe.cpp
|
||||
kernel/FS/ProcFS/FileSystem.cpp
|
||||
|
@ -32,14 +30,9 @@ set(KERNEL_SOURCES
|
|||
kernel/FS/TmpFS/FileSystem.cpp
|
||||
kernel/FS/TmpFS/Inode.cpp
|
||||
kernel/FS/VirtualFileSystem.cpp
|
||||
kernel/GDT.cpp
|
||||
kernel/IDT.cpp
|
||||
kernel/Input/PS2/Controller.cpp
|
||||
kernel/Input/PS2/Device.cpp
|
||||
kernel/Input/PS2/Keyboard.cpp
|
||||
kernel/Input/PS2/Keymap.cpp
|
||||
kernel/Input/PS2/Mouse.cpp
|
||||
kernel/Interruptable.cpp
|
||||
kernel/Input/PS2Controller.cpp
|
||||
kernel/Input/PS2Keyboard.cpp
|
||||
kernel/Input/PS2Keymap.cpp
|
||||
kernel/InterruptController.cpp
|
||||
kernel/kernel.cpp
|
||||
kernel/Memory/DMARegion.cpp
|
||||
|
@ -49,28 +42,16 @@ set(KERNEL_SOURCES
|
|||
kernel/Memory/MemoryBackedRegion.cpp
|
||||
kernel/Memory/MemoryRegion.cpp
|
||||
kernel/Memory/PhysicalRange.cpp
|
||||
kernel/Memory/SharedMemoryObject.cpp
|
||||
kernel/Memory/VirtualRange.cpp
|
||||
kernel/Networking/ARPTable.cpp
|
||||
kernel/Networking/E1000/E1000.cpp
|
||||
kernel/Networking/E1000/E1000E.cpp
|
||||
kernel/Networking/IPv4Layer.cpp
|
||||
kernel/Networking/NetworkInterface.cpp
|
||||
kernel/Networking/NetworkLayer.cpp
|
||||
kernel/Networking/NetworkManager.cpp
|
||||
kernel/Networking/NetworkSocket.cpp
|
||||
kernel/Networking/TCPSocket.cpp
|
||||
kernel/Networking/UDPSocket.cpp
|
||||
kernel/Networking/UNIX/Socket.cpp
|
||||
kernel/Networking/E1000.cpp
|
||||
kernel/OpenFileDescriptorSet.cpp
|
||||
kernel/Panic.cpp
|
||||
kernel/PCI.cpp
|
||||
kernel/PIC.cpp
|
||||
kernel/Process.cpp
|
||||
kernel/Processor.cpp
|
||||
kernel/Random.cpp
|
||||
kernel/Scheduler.cpp
|
||||
kernel/Semaphore.cpp
|
||||
kernel/SpinLock.cpp
|
||||
kernel/SSP.cpp
|
||||
kernel/Storage/ATA/AHCI/Controller.cpp
|
||||
kernel/Storage/ATA/AHCI/Device.cpp
|
||||
|
@ -78,15 +59,12 @@ set(KERNEL_SOURCES
|
|||
kernel/Storage/ATA/ATAController.cpp
|
||||
kernel/Storage/ATA/ATADevice.cpp
|
||||
kernel/Storage/DiskCache.cpp
|
||||
kernel/Storage/NVMe/Controller.cpp
|
||||
kernel/Storage/NVMe/Namespace.cpp
|
||||
kernel/Storage/NVMe/Queue.cpp
|
||||
kernel/Storage/Partition.cpp
|
||||
kernel/Storage/StorageDevice.cpp
|
||||
kernel/Syscall.cpp
|
||||
kernel/Terminal/FramebufferTerminal.cpp
|
||||
kernel/Syscall.S
|
||||
kernel/Terminal/Serial.cpp
|
||||
kernel/Terminal/TTY.cpp
|
||||
kernel/Terminal/VesaTerminalDriver.cpp
|
||||
kernel/Terminal/VirtualTTY.cpp
|
||||
kernel/Thread.cpp
|
||||
kernel/Timer/HPET.cpp
|
||||
|
@ -96,7 +74,7 @@ set(KERNEL_SOURCES
|
|||
icxxabi.cpp
|
||||
)
|
||||
|
||||
set(ENABLE_KERNEL_UBSAN False)
|
||||
#set(ENABLE_KERNEL_UBSAN True)
|
||||
|
||||
if(ENABLE_KERNEL_UBSAN)
|
||||
set(KERNEL_SOURCES ${KERNEL_SOURCES} ubsan.cpp)
|
||||
|
@ -106,62 +84,61 @@ if("${BANAN_ARCH}" STREQUAL "x86_64")
|
|||
set(KERNEL_SOURCES
|
||||
${KERNEL_SOURCES}
|
||||
arch/x86_64/boot.S
|
||||
arch/x86_64/GDT.cpp
|
||||
arch/x86_64/IDT.cpp
|
||||
arch/x86_64/interrupts.S
|
||||
arch/x86_64/PageTable.cpp
|
||||
arch/x86_64/Signal.S
|
||||
arch/x86_64/Syscall.S
|
||||
arch/x86_64/Thread.S
|
||||
)
|
||||
elseif("${BANAN_ARCH}" STREQUAL "i686")
|
||||
elseif("${BANAN_ARCH}" STREQUAL "i386")
|
||||
set(KERNEL_SOURCES
|
||||
${KERNEL_SOURCES}
|
||||
arch/i686/boot.S
|
||||
arch/i686/interrupts.S
|
||||
arch/i686/PageTable.cpp
|
||||
arch/i686/Signal.S
|
||||
arch/i686/Syscall.S
|
||||
arch/i686/Thread.S
|
||||
arch/i386/boot.S
|
||||
arch/i386/GDT.cpp
|
||||
arch/i386/IDT.cpp
|
||||
arch/i386/MMU.cpp
|
||||
arch/i386/SpinLock.S
|
||||
arch/i386/Thread.S
|
||||
)
|
||||
else()
|
||||
message(FATAL_ERROR "unsupported architecure ${BANAN_ARCH}")
|
||||
endif()
|
||||
|
||||
file(GLOB_RECURSE LAI_SOURCES
|
||||
lai/*.c
|
||||
)
|
||||
set(LAI_SOURCES
|
||||
${LAI_SOURCES}
|
||||
kernel/lai_host.cpp
|
||||
)
|
||||
|
||||
set(BAN_SOURCES
|
||||
../BAN/BAN/Assert.cpp
|
||||
../BAN/BAN/New.cpp
|
||||
../BAN/BAN/String.cpp
|
||||
../BAN/BAN/StringView.cpp
|
||||
../BAN/BAN/Time.cpp
|
||||
)
|
||||
|
||||
set(KLIBC_SOURCES
|
||||
klibc/ctype.cpp
|
||||
klibc/string.cpp
|
||||
set(LIBC_SOURCES
|
||||
../libc/ctype.cpp
|
||||
../libc/string.cpp
|
||||
)
|
||||
|
||||
set(LIBELF_SOURCES
|
||||
../userspace/libraries/LibELF/LibELF/LoadableELF.cpp
|
||||
)
|
||||
|
||||
set(LIBFONT_SOURCES
|
||||
../userspace/libraries/LibFont/Font.cpp
|
||||
../userspace/libraries/LibFont/PSF.cpp
|
||||
)
|
||||
|
||||
set(LIBINPUT_SOURCE
|
||||
../userspace/libraries/LibInput/KeyboardLayout.cpp
|
||||
../userspace/libraries/LibInput/KeyEvent.cpp
|
||||
../LibELF/LibELF/LoadableELF.cpp
|
||||
)
|
||||
|
||||
set(KERNEL_SOURCES
|
||||
${KERNEL_SOURCES}
|
||||
${LAI_SOURCES}
|
||||
${BAN_SOURCES}
|
||||
${KLIBC_SOURCES}
|
||||
${LIBC_SOURCES}
|
||||
${LIBELF_SOURCES}
|
||||
${LIBFONT_SOURCES}
|
||||
${LIBINPUT_SOURCE}
|
||||
)
|
||||
|
||||
add_executable(kernel ${KERNEL_SOURCES})
|
||||
add_dependencies(kernel headers)
|
||||
|
||||
target_compile_definitions(kernel PUBLIC __is_kernel)
|
||||
target_compile_definitions(kernel PUBLIC __arch=${BANAN_ARCH})
|
||||
|
@ -169,7 +146,7 @@ target_compile_definitions(kernel PUBLIC __arch=${BANAN_ARCH})
|
|||
target_compile_options(kernel PUBLIC -O2 -g)
|
||||
target_compile_options(kernel PUBLIC $<$<COMPILE_LANGUAGE:CXX>:-Wno-literal-suffix -fno-rtti -fno-exceptions>)
|
||||
target_compile_options(kernel PUBLIC -fmacro-prefix-map=${CMAKE_CURRENT_SOURCE_DIR}=.)
|
||||
target_compile_options(kernel PUBLIC -fstack-protector -ffreestanding -Wall -Wextra -Werror -Wstack-usage=1024 -fno-omit-frame-pointer -mgeneral-regs-only)
|
||||
target_compile_options(kernel PUBLIC -fstack-protector -ffreestanding -Wall -Werror=return-type -Wstack-usage=1024 -fno-omit-frame-pointer -mgeneral-regs-only)
|
||||
|
||||
# This might not work with other toolchains
|
||||
target_compile_options(kernel PUBLIC $<$<COMPILE_LANGUAGE:CXX>:-Wno-invalid-offsetof>)
|
||||
|
@ -179,15 +156,26 @@ if(ENABLE_KERNEL_UBSAN)
|
|||
endif()
|
||||
|
||||
if("${BANAN_ARCH}" STREQUAL "x86_64")
|
||||
target_compile_options(kernel PUBLIC -mcmodel=kernel -mno-red-zone)
|
||||
target_compile_options(kernel PUBLIC -mcmodel=kernel -mno-red-zone -mno-mmx)
|
||||
target_link_options(kernel PUBLIC LINKER:-z,max-page-size=4096)
|
||||
target_link_options(kernel PUBLIC LINKER:-T,${CMAKE_CURRENT_SOURCE_DIR}/arch/x86_64/linker.ld)
|
||||
elseif("${BANAN_ARCH}" STREQUAL "i686")
|
||||
target_link_options(kernel PUBLIC LINKER:-T,${CMAKE_CURRENT_SOURCE_DIR}/arch/i686/linker.ld)
|
||||
elseif("${BANAN_ARCH}" STREQUAL "i386")
|
||||
target_link_options(kernel PUBLIC LINKER:-T,${CMAKE_CURRENT_SOURCE_DIR}/arch/i386/linker.ld)
|
||||
endif()
|
||||
|
||||
target_link_options(kernel PUBLIC -ffreestanding -nostdlib)
|
||||
|
||||
add_custom_target(kernel-headers
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_directory_if_different ${CMAKE_CURRENT_SOURCE_DIR}/include/ ${BANAN_INCLUDE}/
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_directory_if_different ${CMAKE_CURRENT_SOURCE_DIR}/lai/include/ ${BANAN_INCLUDE}/
|
||||
DEPENDS sysroot
|
||||
)
|
||||
|
||||
add_custom_target(kernel-install
|
||||
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_BINARY_DIR}/kernel ${BANAN_BOOT}/banan-os.kernel
|
||||
DEPENDS kernel
|
||||
)
|
||||
|
||||
execute_process(COMMAND ${CMAKE_CXX_COMPILER} -print-file-name=crtbegin.o OUTPUT_VARIABLE CRTBEGIN OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
execute_process(COMMAND ${CMAKE_CXX_COMPILER} -print-file-name=crtend.o OUTPUT_VARIABLE CRTEND OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
|
||||
|
@ -204,22 +192,6 @@ add_custom_command(
|
|||
# COMMAND x86_64-banan_os-strip ${CMAKE_CURRENT_BINARY_DIR}/kernel
|
||||
#)
|
||||
|
||||
banan_include_headers(kernel ban)
|
||||
banan_include_headers(kernel libc)
|
||||
banan_include_headers(kernel libfont)
|
||||
banan_include_headers(kernel libelf)
|
||||
banan_include_headers(kernel libinput)
|
||||
|
||||
banan_install_headers(kernel)
|
||||
set_target_properties(kernel PROPERTIES OUTPUT_NAME banan-os.kernel)
|
||||
install(TARGETS kernel DESTINATION ${BANAN_BOOT} OPTIONAL)
|
||||
|
||||
if("${BANAN_ARCH}" STREQUAL "x86_64")
|
||||
set(ELF_FORMAT elf64-x86-64)
|
||||
elseif("${BANAN_ARCH}" STREQUAL "i686")
|
||||
set(ELF_FORMAT elf32-i386)
|
||||
endif()
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT font/prefs.psf.o
|
||||
COMMAND cd ${CMAKE_CURRENT_SOURCE_DIR} && objcopy -O ${ELF_FORMAT} -B i386 -I binary font/prefs.psf ${CMAKE_CURRENT_BINARY_DIR}/font/prefs.psf.o
|
||||
|
|
|
@ -0,0 +1,147 @@
|
|||
#include <BAN/Assert.h>
|
||||
#include <kernel/GDT.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
extern "C" uintptr_t g_boot_stack_top[0];
|
||||
|
||||
namespace Kernel::GDT
|
||||
{
|
||||
|
||||
struct TaskStateSegment
|
||||
{
|
||||
uint16_t link;
|
||||
uint16_t reserved1;
|
||||
uint32_t esp0;
|
||||
uint16_t ss0;
|
||||
uint16_t reserved2;
|
||||
uint32_t esp1;
|
||||
uint16_t ss1;
|
||||
uint16_t reserved3;
|
||||
uint32_t esp2;
|
||||
uint16_t ss2;
|
||||
uint16_t reserved4;
|
||||
uint32_t cr3;
|
||||
uint32_t eip;
|
||||
uint32_t eflags;
|
||||
uint32_t eax;
|
||||
uint32_t ecx;
|
||||
uint32_t edx;
|
||||
uint32_t ebx;
|
||||
uint32_t esp;
|
||||
uint32_t ebp;
|
||||
uint32_t esi;
|
||||
uint32_t edi;
|
||||
uint16_t es;
|
||||
uint16_t reserved5;
|
||||
uint16_t cs;
|
||||
uint16_t reserved6;
|
||||
uint16_t ss;
|
||||
uint16_t reserved7;
|
||||
uint16_t ds;
|
||||
uint16_t reserved8;
|
||||
uint16_t fs;
|
||||
uint16_t reserved9;
|
||||
uint16_t gs;
|
||||
uint16_t reserved10;
|
||||
uint16_t ldtr;
|
||||
uint16_t reserved11;
|
||||
uint16_t reserved12;
|
||||
uint16_t iopb;
|
||||
uint32_t ssp;
|
||||
} __attribute__((packed));
|
||||
|
||||
union SegmentDescriptor
|
||||
{
|
||||
struct
|
||||
{
|
||||
uint16_t limit1;
|
||||
uint16_t base1;
|
||||
uint8_t base2;
|
||||
uint8_t access;
|
||||
uint8_t limit2 : 4;
|
||||
uint8_t flags : 4;
|
||||
uint8_t base3;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct
|
||||
{
|
||||
uint32_t low;
|
||||
uint32_t high;
|
||||
} __attribute__((packed));
|
||||
|
||||
} __attribute__((packed));
|
||||
|
||||
struct GDTR
|
||||
{
|
||||
uint16_t size;
|
||||
uint32_t address;
|
||||
} __attribute__((packed));
|
||||
|
||||
static TaskStateSegment* s_tss = nullptr;
|
||||
static SegmentDescriptor* s_gdt = nullptr;
|
||||
static GDTR s_gdtr;
|
||||
|
||||
static void write_entry(uint8_t offset, uint32_t base, uint32_t limit, uint8_t access, uint8_t flags)
|
||||
{
|
||||
SegmentDescriptor& desc = *(SegmentDescriptor*)((uintptr_t)s_gdt + offset);
|
||||
desc.base1 = base;
|
||||
desc.base2 = base >> 16;
|
||||
desc.base3 = base >> 24;
|
||||
|
||||
desc.limit1 = limit;
|
||||
desc.limit2 = limit >> 16;
|
||||
|
||||
desc.access = access;
|
||||
|
||||
desc.flags = flags;
|
||||
}
|
||||
|
||||
static void write_tss(uint8_t offset)
|
||||
{
|
||||
s_tss = new TaskStateSegment();
|
||||
ASSERT(s_tss);
|
||||
|
||||
memset(s_tss, 0x00, sizeof(TaskStateSegment));
|
||||
s_tss->ss0 = 0x10;
|
||||
s_tss->esp0 = (uintptr_t)g_boot_stack_top;
|
||||
|
||||
write_entry(offset, (uint32_t)s_tss, sizeof(TaskStateSegment), 0x89, 0x0);
|
||||
}
|
||||
|
||||
void set_tss_stack(uintptr_t esp)
|
||||
{
|
||||
s_tss->esp0 = esp;
|
||||
}
|
||||
|
||||
static void flush_gdt()
|
||||
{
|
||||
asm volatile("lgdt %0" :: "m"(s_gdtr));
|
||||
}
|
||||
|
||||
extern "C" void flush_tss(uint16_t offset)
|
||||
{
|
||||
asm volatile("ltr %0" :: "m"(offset));
|
||||
}
|
||||
|
||||
void initialize()
|
||||
{
|
||||
constexpr uint32_t descriptor_count = 6;
|
||||
s_gdt = new SegmentDescriptor[descriptor_count];
|
||||
ASSERT(s_gdt);
|
||||
|
||||
s_gdtr.address = (uint64_t)s_gdt;
|
||||
s_gdtr.size = descriptor_count * sizeof(SegmentDescriptor) - 1;
|
||||
|
||||
write_entry(0x00, 0x00000000, 0x00000, 0x00, 0x0); // null
|
||||
write_entry(0x08, 0x00000000, 0xFFFFF, 0x9A, 0xC); // kernel code
|
||||
write_entry(0x10, 0x00000000, 0xFFFFF, 0x92, 0xC); // kernel data
|
||||
write_entry(0x18, 0x00000000, 0xFFFFF, 0xFA, 0xC); // user code
|
||||
write_entry(0x20, 0x00000000, 0xFFFFF, 0xF2, 0xC); // user data
|
||||
write_tss(0x28);
|
||||
|
||||
flush_gdt();
|
||||
flush_tss(0x28);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,270 @@
|
|||
#include <BAN/Errors.h>
|
||||
#include <kernel/IDT.h>
|
||||
#include <kernel/InterruptController.h>
|
||||
#include <kernel/Memory/kmalloc.h>
|
||||
#include <kernel/Panic.h>
|
||||
#include <kernel/Scheduler.h>
|
||||
|
||||
#define INTERRUPT_HANDLER____(i, msg) \
|
||||
static void interrupt ## i () \
|
||||
{ \
|
||||
uint32_t eax, ebx, ecx, edx; \
|
||||
uint32_t esp, ebp; \
|
||||
uint32_t cr0, cr2, cr3, cr4; \
|
||||
asm volatile("":"=a"(eax),"=b"(ebx),"=c"(ecx),"=d"(edx)); \
|
||||
asm volatile("movl %%esp, %%eax":"=a"(esp)); \
|
||||
asm volatile("movl %%ebp, %%eax":"=a"(ebp)); \
|
||||
asm volatile("movl %%cr0, %%eax":"=a"(cr0)); \
|
||||
asm volatile("movl %%cr2, %%eax":"=a"(cr2)); \
|
||||
asm volatile("movl %%cr3, %%eax":"=a"(cr3)); \
|
||||
asm volatile("movl %%cr4, %%eax":"=a"(cr4)); \
|
||||
Kernel::panic(msg "\r\nRegister dump\r\n" \
|
||||
"eax=0x{8H}, ebx=0x{8H}, ecx=0x{8H}, edx=0x{8H}\r\n" \
|
||||
"esp=0x{8H}, ebp=0x{8H}\r\n" \
|
||||
"CR0=0x{8H}, CR2=0x{8H}, CR3=0x{8H}, CR4=0x{8H}\r\n", \
|
||||
eax, ebx, ecx, edx, esp, ebp, cr0, cr2, cr3, cr4); \
|
||||
}
|
||||
|
||||
#define INTERRUPT_HANDLER_ERR(i, msg) \
|
||||
static void interrupt ## i () \
|
||||
{ \
|
||||
uint32_t eax, ebx, ecx, edx; \
|
||||
uint32_t esp, ebp; \
|
||||
uint32_t cr0, cr2, cr3, cr4; \
|
||||
uint32_t error_code; \
|
||||
asm volatile("":"=a"(eax),"=b"(ebx),"=c"(ecx),"=d"(edx)); \
|
||||
asm volatile("movl %%esp, %%eax":"=a"(esp)); \
|
||||
asm volatile("movl %%ebp, %%eax":"=a"(ebp)); \
|
||||
asm volatile("movl %%cr0, %%eax":"=a"(cr0)); \
|
||||
asm volatile("movl %%cr2, %%eax":"=a"(cr2)); \
|
||||
asm volatile("movl %%cr3, %%eax":"=a"(cr3)); \
|
||||
asm volatile("movl %%cr4, %%eax":"=a"(cr4)); \
|
||||
asm volatile("popl %%eax":"=a"(error_code)); \
|
||||
Kernel::panic(msg " (error code: 0x{8H})\r\n" \
|
||||
"Register dump\r\n" \
|
||||
"eax=0x{8H}, ebx=0x{8H}, ecx=0x{8H}, edx=0x{8H}\r\n" \
|
||||
"esp=0x{8H}, ebp=0x{8H}\r\n" \
|
||||
"CR0=0x{8H}, CR2=0x{8H}, CR3=0x{8H}, CR4=0x{8H}\r\n", \
|
||||
eax, ebx, ecx, edx, esp, ebp, cr0, cr2, cr3, cr4, error_code); \
|
||||
}
|
||||
|
||||
#define REGISTER_HANDLER(i) register_interrupt_handler(i, interrupt ## i)
|
||||
|
||||
namespace IDT
|
||||
{
|
||||
|
||||
struct GateDescriptor
|
||||
{
|
||||
uint16_t offset1;
|
||||
uint16_t selector;
|
||||
uint8_t reserved : 5;
|
||||
uint8_t zero1 : 3;
|
||||
uint8_t type : 4;
|
||||
uint8_t zero2 : 1;
|
||||
uint8_t DPL : 2;
|
||||
uint8_t present : 1;
|
||||
uint16_t offset2;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct IDTR
|
||||
{
|
||||
uint16_t size;
|
||||
void* offset;
|
||||
} __attribute((packed));
|
||||
|
||||
static IDTR s_idtr;
|
||||
static GateDescriptor* s_idt = nullptr;
|
||||
|
||||
static void(*s_irq_handlers[16])() { nullptr };
|
||||
|
||||
INTERRUPT_HANDLER____(0x00, "Division Error")
|
||||
INTERRUPT_HANDLER____(0x01, "Debug")
|
||||
INTERRUPT_HANDLER____(0x02, "Non-maskable Interrupt")
|
||||
INTERRUPT_HANDLER____(0x03, "Breakpoint")
|
||||
INTERRUPT_HANDLER____(0x04, "Overflow")
|
||||
INTERRUPT_HANDLER____(0x05, "Bound Range Exception")
|
||||
INTERRUPT_HANDLER____(0x06, "Invalid Opcode")
|
||||
INTERRUPT_HANDLER____(0x07, "Device Not Available")
|
||||
INTERRUPT_HANDLER_ERR(0x08, "Double Fault")
|
||||
INTERRUPT_HANDLER____(0x09, "Coprocessor Segment Overrun")
|
||||
INTERRUPT_HANDLER_ERR(0x0A, "Invalid TSS")
|
||||
INTERRUPT_HANDLER_ERR(0x0B, "Segment Not Present")
|
||||
INTERRUPT_HANDLER_ERR(0x0C, "Stack-Segment Fault")
|
||||
INTERRUPT_HANDLER_ERR(0x0D, "General Protection Fault")
|
||||
INTERRUPT_HANDLER_ERR(0x0E, "Page Fault")
|
||||
INTERRUPT_HANDLER____(0x0F, "Unknown Exception 0x0F")
|
||||
INTERRUPT_HANDLER____(0x10, "x87 Floating-Point Exception")
|
||||
INTERRUPT_HANDLER_ERR(0x11, "Alignment Check")
|
||||
INTERRUPT_HANDLER____(0x12, "Machine Check")
|
||||
INTERRUPT_HANDLER____(0x13, "SIMD Floating-Point Exception")
|
||||
INTERRUPT_HANDLER____(0x14, "Virtualization Exception")
|
||||
INTERRUPT_HANDLER_ERR(0x15, "Control Protection Exception")
|
||||
INTERRUPT_HANDLER____(0x16, "Unknown Exception 0x16")
|
||||
INTERRUPT_HANDLER____(0x17, "Unknown Exception 0x17")
|
||||
INTERRUPT_HANDLER____(0x18, "Unknown Exception 0x18")
|
||||
INTERRUPT_HANDLER____(0x19, "Unknown Exception 0x19")
|
||||
INTERRUPT_HANDLER____(0x1A, "Unknown Exception 0x1A")
|
||||
INTERRUPT_HANDLER____(0x1B, "Unknown Exception 0x1B")
|
||||
INTERRUPT_HANDLER____(0x1C, "Hypervisor Injection Exception")
|
||||
INTERRUPT_HANDLER_ERR(0x1D, "VMM Communication Exception")
|
||||
INTERRUPT_HANDLER_ERR(0x1E, "Security Exception")
|
||||
INTERRUPT_HANDLER____(0x1F, "Unkown Exception 0x1F")
|
||||
|
||||
extern "C" void handle_irq()
|
||||
{
|
||||
uint8_t irq;
|
||||
for (uint32_t i = 0; i < 16; i++)
|
||||
{
|
||||
if (InterruptController::get().is_in_service(i))
|
||||
{
|
||||
irq = i;
|
||||
goto found;
|
||||
}
|
||||
}
|
||||
|
||||
dprintln("Spurious irq");
|
||||
return;
|
||||
found:
|
||||
if (s_irq_handlers[irq])
|
||||
s_irq_handlers[irq]();
|
||||
else
|
||||
dprintln("no handler for irq 0x{2H}\n", irq);
|
||||
|
||||
// NOTE: Scheduler sends PIT eoi's
|
||||
if (irq != PIT_IRQ)
|
||||
InterruptController::get().eoi(irq);
|
||||
|
||||
Kernel::Scheduler::get().reschedule_if_idling();
|
||||
}
|
||||
|
||||
extern "C" void handle_irq_common();
|
||||
asm(
|
||||
".globl handle_irq_common;"
|
||||
"handle_irq_common:"
|
||||
"pusha;"
|
||||
"pushw %ds;"
|
||||
"pushw %es;"
|
||||
"pushw %ss;"
|
||||
"pushw %ss;"
|
||||
"popw %ds;"
|
||||
"popw %es;"
|
||||
"call handle_irq;"
|
||||
"popw %es;"
|
||||
"popw %ds;"
|
||||
"popa;"
|
||||
"iret;"
|
||||
);
|
||||
|
||||
extern "C" void syscall_asm();
|
||||
asm(
|
||||
".global syscall_asm;"
|
||||
"syscall_asm:"
|
||||
"pusha;"
|
||||
"pushw %ds;"
|
||||
"pushw %es;"
|
||||
"pushw %ss;"
|
||||
"pushw %ss;"
|
||||
"popw %ds;"
|
||||
"popw %es;"
|
||||
"pushl %edx;"
|
||||
"pushl %ecx;"
|
||||
"pushl %ebx;"
|
||||
"pushl %eax;"
|
||||
"call cpp_syscall_handler;"
|
||||
"addl $16, %esp;"
|
||||
"popw %es;"
|
||||
"popw %ds;"
|
||||
|
||||
// NOTE: following instructions are same as in 'popa', except we skip eax
|
||||
// since it holds the return value of the syscall.
|
||||
"popl %edi;"
|
||||
"popl %esi;"
|
||||
"popl %ebp;"
|
||||
"addl $4, %esp;"
|
||||
"popl %ebx;"
|
||||
"popl %edx;"
|
||||
"popl %ecx;"
|
||||
"addl $4, %esp;"
|
||||
|
||||
"iret;"
|
||||
);
|
||||
|
||||
static void flush_idt()
|
||||
{
|
||||
asm volatile("lidt %0"::"m"(s_idtr));
|
||||
}
|
||||
|
||||
static void register_interrupt_handler(uint8_t index, void(*f)())
|
||||
{
|
||||
GateDescriptor& descriptor = s_idt[index];
|
||||
descriptor.offset1 = (uint32_t)f & 0xFFFF;
|
||||
descriptor.selector = 0x08;
|
||||
descriptor.type = 0xE;
|
||||
descriptor.DPL = 0;
|
||||
descriptor.present = 1;
|
||||
descriptor.offset2 = (uint32_t)f >> 16;
|
||||
}
|
||||
|
||||
void register_irq_handler(uint8_t irq, void(*f)())
|
||||
{
|
||||
s_irq_handlers[irq] = f;
|
||||
register_interrupt_handler(IRQ_VECTOR_BASE + irq, handle_irq_common);
|
||||
flush_idt();
|
||||
}
|
||||
|
||||
void register_syscall_handler(uint8_t offset, void(*handler)())
|
||||
{
|
||||
register_interrupt_handler(offset, handler);
|
||||
s_idt[offset].DPL = 3;
|
||||
}
|
||||
|
||||
void initialize()
|
||||
{
|
||||
constexpr size_t idt_size = 0x100 * sizeof(GateDescriptor);
|
||||
|
||||
s_idt = (GateDescriptor*)kmalloc(idt_size);
|
||||
ASSERT(s_idt);
|
||||
memset(s_idt, 0x00, idt_size);
|
||||
|
||||
s_idtr.offset = s_idt;
|
||||
s_idtr.size = idt_size - 1;
|
||||
|
||||
REGISTER_HANDLER(0x00);
|
||||
REGISTER_HANDLER(0x01);
|
||||
REGISTER_HANDLER(0x02);
|
||||
REGISTER_HANDLER(0x03);
|
||||
REGISTER_HANDLER(0x04);
|
||||
REGISTER_HANDLER(0x05);
|
||||
REGISTER_HANDLER(0x06);
|
||||
REGISTER_HANDLER(0x07);
|
||||
REGISTER_HANDLER(0x08);
|
||||
REGISTER_HANDLER(0x09);
|
||||
REGISTER_HANDLER(0x0A);
|
||||
REGISTER_HANDLER(0x0B);
|
||||
REGISTER_HANDLER(0x0C);
|
||||
REGISTER_HANDLER(0x0D);
|
||||
REGISTER_HANDLER(0x0E);
|
||||
REGISTER_HANDLER(0x0F);
|
||||
REGISTER_HANDLER(0x10);
|
||||
REGISTER_HANDLER(0x11);
|
||||
REGISTER_HANDLER(0x12);
|
||||
REGISTER_HANDLER(0x13);
|
||||
REGISTER_HANDLER(0x14);
|
||||
REGISTER_HANDLER(0x15);
|
||||
REGISTER_HANDLER(0x16);
|
||||
REGISTER_HANDLER(0x17);
|
||||
REGISTER_HANDLER(0x18);
|
||||
REGISTER_HANDLER(0x19);
|
||||
REGISTER_HANDLER(0x1A);
|
||||
REGISTER_HANDLER(0x1B);
|
||||
REGISTER_HANDLER(0x1C);
|
||||
REGISTER_HANDLER(0x1D);
|
||||
REGISTER_HANDLER(0x1E);
|
||||
REGISTER_HANDLER(0x1F);
|
||||
|
||||
register_syscall_handler(0x80, syscall_asm);
|
||||
|
||||
flush_idt();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,227 @@
|
|||
#include <BAN/Errors.h>
|
||||
#include <kernel/Debug.h>
|
||||
#include <kernel/Memory/MMU.h>
|
||||
#include <kernel/Memory/kmalloc.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#define MMU_DEBUG_PRINT 0
|
||||
|
||||
// bits 31-12 set
|
||||
#define PAGE_MASK 0xfffff000
|
||||
#define FLAGS_MASK 0x00000fff
|
||||
|
||||
namespace Kernel
|
||||
{
|
||||
|
||||
static MMU* s_instance = nullptr;
|
||||
|
||||
void MMU::initialize()
|
||||
{
|
||||
ASSERT(s_instance == nullptr);
|
||||
s_instance = new MMU();
|
||||
ASSERT(s_instance);
|
||||
s_instance->initialize_kernel();
|
||||
s_instance->load();
|
||||
}
|
||||
|
||||
MMU& MMU::get()
|
||||
{
|
||||
ASSERT(s_instance);
|
||||
return *s_instance;
|
||||
}
|
||||
|
||||
static uint64_t* allocate_page_aligned_page()
|
||||
{
|
||||
uint64_t* page = (uint64_t*)kmalloc(PAGE_SIZE, PAGE_SIZE);
|
||||
ASSERT(page);
|
||||
ASSERT(((uintptr_t)page % PAGE_SIZE) == 0);
|
||||
memset(page, 0, PAGE_SIZE);
|
||||
return page;
|
||||
}
|
||||
|
||||
void MMU::initialize_kernel()
|
||||
{
|
||||
m_highest_paging_struct = (uint64_t*)kmalloc(sizeof(uint64_t) * 4, 32);
|
||||
ASSERT(m_highest_paging_struct);
|
||||
ASSERT(((uintptr_t)m_highest_paging_struct % 32) == 0);
|
||||
|
||||
// allocate all page directories
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
uint64_t* page_directory = allocate_page_aligned_page();
|
||||
m_highest_paging_struct[i] = (uint64_t)page_directory | Flags::Present;
|
||||
}
|
||||
|
||||
// FIXME: We should just identity map until g_kernel_end
|
||||
|
||||
// create and identity map first 6 MiB
|
||||
uint64_t* page_directory1 = (uint64_t*)(m_highest_paging_struct[0] & PAGE_MASK);
|
||||
for (uint64_t i = 0; i < 3; i++)
|
||||
{
|
||||
uint64_t* page_table = allocate_page_aligned_page();
|
||||
for (uint64_t j = 0; j < 512; j++)
|
||||
page_table[j] = (i << 21) | (j << 12) | Flags::ReadWrite | Flags::Present;
|
||||
|
||||
page_directory1[i] = (uint64_t)page_table | Flags::ReadWrite | Flags::Present;
|
||||
}
|
||||
|
||||
// dont map first page (0 -> 4 KiB) so that nullptr dereference
|
||||
// causes page fault :)
|
||||
uint64_t* page_table1 = (uint64_t*)(page_directory1[0] & PAGE_MASK);
|
||||
page_table1[0] = 0;
|
||||
}
|
||||
|
||||
MMU::MMU()
|
||||
{
|
||||
if (s_instance == nullptr)
|
||||
return;
|
||||
|
||||
// Here we copy the s_instances paging structs since they are
|
||||
// global for every process
|
||||
|
||||
uint64_t* global_pdpt = s_instance->m_highest_paging_struct;
|
||||
|
||||
uint64_t* pdpt = (uint64_t*)kmalloc(sizeof(uint64_t) * 4, 32);
|
||||
ASSERT(pdpt);
|
||||
|
||||
for (uint32_t pdpte = 0; pdpte < 4; pdpte++)
|
||||
{
|
||||
if (!(global_pdpt[pdpte] & Flags::Present))
|
||||
continue;
|
||||
|
||||
uint64_t* global_pd = (uint64_t*)(global_pdpt[pdpte] & PAGE_MASK);
|
||||
|
||||
uint64_t* pd = allocate_page_aligned_page();
|
||||
pdpt[pdpte] = (uint64_t)pd | (global_pdpt[pdpte] & ~PAGE_MASK);
|
||||
|
||||
for (uint32_t pde = 0; pde < 512; pde++)
|
||||
{
|
||||
if (!(global_pd[pde] & Flags::Present))
|
||||
continue;
|
||||
|
||||
uint64_t* global_pt = (uint64_t*)(global_pd[pde] & PAGE_MASK);
|
||||
|
||||
uint64_t* pt = allocate_page_aligned_page();
|
||||
pd[pde] = (uint64_t)pt | (global_pd[pde] & ~PAGE_MASK);
|
||||
|
||||
memcpy(pt, global_pt, PAGE_SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
m_highest_paging_struct = pdpt;
|
||||
}
|
||||
|
||||
MMU::~MMU()
|
||||
{
|
||||
uint64_t* pdpt = m_highest_paging_struct;
|
||||
for (uint32_t pdpte = 0; pdpte < 512; pdpte++)
|
||||
{
|
||||
if (!(pdpt[pdpte] & Flags::Present))
|
||||
continue;
|
||||
uint64_t* pd = (uint64_t*)(pdpt[pdpte] & PAGE_MASK);
|
||||
for (uint32_t pde = 0; pde < 512; pde++)
|
||||
{
|
||||
if (!(pd[pde] & Flags::Present))
|
||||
continue;
|
||||
kfree((void*)(pd[pde] & PAGE_MASK));
|
||||
}
|
||||
kfree(pd);
|
||||
}
|
||||
kfree(pdpt);
|
||||
}
|
||||
|
||||
void MMU::load()
|
||||
{
|
||||
asm volatile("movl %0, %%cr3" :: "r"(m_highest_paging_struct));
|
||||
}
|
||||
|
||||
void MMU::map_page_at(paddr_t paddr, vaddr_t vaddr, uint8_t flags)
|
||||
{
|
||||
#if MMU_DEBUG_PRINT
|
||||
dprintln("AllocatePage(0x{8H})", address);
|
||||
#endif
|
||||
ASSERT(flags & Flags::Present);
|
||||
|
||||
ASSERT(!(paddr & ~PAGE_MASK));
|
||||
ASSERT(!(vaddr & ~PAGE_MASK));
|
||||
|
||||
uint32_t pdpte = (vaddr & 0xC0000000) >> 30;
|
||||
uint32_t pde = (vaddr & 0x3FE00000) >> 21;
|
||||
uint32_t pte = (vaddr & 0x001FF000) >> 12;
|
||||
|
||||
uint64_t* page_directory = (uint64_t*)(m_highest_paging_struct[pdpte] & PAGE_MASK);
|
||||
if (!(page_directory[pde] & Flags::Present))
|
||||
{
|
||||
uint64_t* page_table = allocate_page_aligned_page();
|
||||
page_directory[pde] = (uint64_t)page_table;
|
||||
}
|
||||
page_directory[pde] |= flags;
|
||||
|
||||
uint64_t* page_table = (uint64_t*)(page_directory[pde] & PAGE_MASK);
|
||||
page_table[pte] = paddr | flags;
|
||||
}
|
||||
|
||||
void MMU::identity_map_page(paddr_t address, uint8_t flags)
|
||||
{
|
||||
address &= PAGE_MASK;
|
||||
map_page_at(address, address, flags);
|
||||
}
|
||||
|
||||
void MMU::identity_map_range(paddr_t address, ptrdiff_t size, uint8_t flags)
|
||||
{
|
||||
paddr_t s_page = address & PAGE_MASK;
|
||||
paddr_t e_page = (address + size - 1) & PAGE_MASK;
|
||||
for (paddr_t page = s_page; page <= e_page; page += PAGE_SIZE)
|
||||
identity_map_page(page, flags);
|
||||
}
|
||||
|
||||
void MMU::unmap_page(vaddr_t address)
|
||||
{
|
||||
#if MMU_DEBUG_PRINT
|
||||
dprintln("UnAllocatePage(0x{8H})", address & PAGE_MASK);
|
||||
#endif
|
||||
|
||||
uint32_t pdpte = (address & 0xC0000000) >> 30;
|
||||
uint32_t pde = (address & 0x3FE00000) >> 21;
|
||||
uint32_t pte = (address & 0x001FF000) >> 12;
|
||||
|
||||
uint64_t* page_directory = (uint64_t*)(m_highest_paging_struct[pdpte] & PAGE_MASK);
|
||||
if (!(page_directory[pde] & Flags::Present))
|
||||
return;
|
||||
|
||||
uint64_t* page_table = (uint64_t*)(page_directory[pde] & PAGE_MASK);
|
||||
if (!(page_table[pte] & Flags::Present))
|
||||
return;
|
||||
|
||||
page_table[pte] = 0;
|
||||
|
||||
// TODO: Unallocate the page table if this was the only allocated page
|
||||
}
|
||||
|
||||
void MMU::unmap_range(vaddr_t address, ptrdiff_t size)
|
||||
{
|
||||
uintptr_t s_page = address & PAGE_MASK;
|
||||
uintptr_t e_page = (address + size - 1) & PAGE_MASK;
|
||||
for (uintptr_t page = s_page; page <= e_page; page += PAGE_SIZE)
|
||||
unmap_page(page);
|
||||
}
|
||||
|
||||
uint8_t MMU::get_page_flags(vaddr_t address) const
|
||||
{
|
||||
uint32_t pdpte = (address & 0xC0000000) >> 30;
|
||||
uint32_t pde = (address & 0x3FE00000) >> 21;
|
||||
uint32_t pte = (address & 0x001FF000) >> 12;
|
||||
|
||||
uint64_t* page_directory = (uint64_t*)(m_highest_paging_struct[pdpte] & PAGE_MASK);
|
||||
if (!(page_directory[pde] & Flags::Present))
|
||||
return 0;
|
||||
|
||||
uint64_t* page_table = (uint64_t*)(page_directory[pde] & PAGE_MASK);
|
||||
if (!(page_table[pte] & Flags::Present))
|
||||
return 0;
|
||||
|
||||
return page_table[pte] & FLAGS_MASK;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
.global spinlock_lock_asm
|
||||
spinlock_lock_asm:
|
||||
movl 4(%esp), %eax
|
||||
lock; btsl $0, (%eax)
|
||||
jnc .done
|
||||
.retry:
|
||||
pause
|
||||
testl $1, (%eax)
|
||||
jne .retry
|
||||
lock; btsl $0, (%eax)
|
||||
jc .retry
|
||||
.done:
|
||||
ret
|
||||
|
||||
.global spinlock_unlock_asm
|
||||
spinlock_unlock_asm:
|
||||
movl 4(%esp), %eax
|
||||
movl $0, (%eax)
|
||||
ret
|
|
@ -0,0 +1,47 @@
|
|||
# uint32_t read_rip()
|
||||
.global read_rip
|
||||
read_rip:
|
||||
popl %eax
|
||||
jmp *%eax
|
||||
|
||||
exit_thread_trampoline:
|
||||
addl $4, %esp
|
||||
pushl (%esp)
|
||||
ret
|
||||
|
||||
# void start_thread(uint32_t esp, uint32_t eip)
|
||||
.global start_thread
|
||||
start_thread:
|
||||
movl 8(%esp), %ecx
|
||||
movl 4(%esp), %esp
|
||||
movl $0, %ebp
|
||||
pushl $exit_thread_trampoline
|
||||
sti
|
||||
jmp *%ecx
|
||||
|
||||
# void continue_thread(uint32_t rsp, uint32_t rip)
|
||||
.global continue_thread
|
||||
continue_thread:
|
||||
movl 8(%esp), %ecx
|
||||
movl 4(%esp), %esp
|
||||
movl $0, %eax
|
||||
jmp *%ecx
|
||||
|
||||
# void thread_jump_userspace(uint32_t rsp, uint32_t rip)
|
||||
.global thread_jump_userspace
|
||||
thread_jump_userspace:
|
||||
movl $0x23, %eax
|
||||
movw %ax, %ds
|
||||
movw %ax, %es
|
||||
movw %ax, %fs
|
||||
movw %ax, %gs
|
||||
|
||||
movl 8(%esp), %ecx
|
||||
movl 4(%esp), %esp
|
||||
|
||||
pushl $0x23
|
||||
pushl %esp
|
||||
pushfl
|
||||
pushl $0x1B
|
||||
pushl %ecx
|
||||
iret
|
|
@ -0,0 +1,182 @@
|
|||
# Declare constants for the multiboot header
|
||||
.set ALIGN, 1<<0 # align loaded modules on page boundaries
|
||||
.set MEMINFO, 1<<1 # provide memory map
|
||||
.set VIDEOINFO, 1<<2 # provide video info
|
||||
.set MB_FLAGS, ALIGN | MEMINFO | VIDEOINFO # this is the Multiboot 'flag' field
|
||||
.set MB_MAGIC, 0x1BADB002 # 'magic number' lets bootloader find the header
|
||||
.set MB_CHECKSUM, -(MB_MAGIC + MB_FLAGS) #checksum of above, to prove we are multiboot
|
||||
|
||||
# Multiboot header
|
||||
.section .multiboot, "aw"
|
||||
.align 4
|
||||
.long MB_MAGIC
|
||||
.long MB_FLAGS
|
||||
.long MB_CHECKSUM
|
||||
.skip 20
|
||||
|
||||
.long 0
|
||||
.long 800
|
||||
.long 600
|
||||
.long 32
|
||||
|
||||
.section .bss, "aw", @nobits
|
||||
# Create stack
|
||||
.global g_boot_stack_bottom
|
||||
g_boot_stack_bottom:
|
||||
.skip 16384
|
||||
.global g_boot_stack_top
|
||||
g_boot_stack_top:
|
||||
|
||||
# 0 MiB -> 1 MiB: bootloader stuff
|
||||
# 1 MiB -> : kernel
|
||||
.align 32
|
||||
boot_page_directory_pointer_table:
|
||||
.skip 4 * 8
|
||||
.align 4096
|
||||
boot_page_directory1:
|
||||
.skip 512 * 8
|
||||
|
||||
.global g_kernel_cmdline
|
||||
g_kernel_cmdline:
|
||||
.skip 4096
|
||||
|
||||
.global g_multiboot_info
|
||||
g_multiboot_info:
|
||||
.skip 4
|
||||
.global g_multiboot_magic
|
||||
g_multiboot_magic:
|
||||
.skip 4
|
||||
|
||||
.section .text
|
||||
|
||||
boot_gdt:
|
||||
.quad 0x0000000000000000 # null
|
||||
.quad 0x00CF9A000000FFFF # kernel code
|
||||
.quad 0x00CF92000000FFFF # kernel data
|
||||
boot_gdtr:
|
||||
.short . - boot_gdt - 1
|
||||
.long boot_gdt
|
||||
|
||||
has_cpuid:
|
||||
pushfl
|
||||
pushfl
|
||||
xorl $0x00200000, (%esp)
|
||||
popfl
|
||||
pushfl
|
||||
popl %eax
|
||||
xorl (%esp), %eax
|
||||
popfl
|
||||
testl $0x00200000, %eax
|
||||
ret
|
||||
|
||||
has_pae:
|
||||
movl $0, %eax
|
||||
cpuid
|
||||
testl $(1 << 6), %edx
|
||||
ret
|
||||
|
||||
has_sse:
|
||||
movl $1, %eax
|
||||
cpuid
|
||||
testl $(1 << 25), %edx
|
||||
ret
|
||||
|
||||
check_requirements:
|
||||
call has_cpuid
|
||||
jz .exit
|
||||
call has_pae
|
||||
jz .exit
|
||||
call has_sse
|
||||
jz .exit
|
||||
ret
|
||||
.exit:
|
||||
jmp system_halt
|
||||
|
||||
copy_kernel_commandline:
|
||||
pushl %esi
|
||||
pushl %edi
|
||||
movl g_multiboot_info, %esi
|
||||
addl $16, %esi
|
||||
movl (%esi), %esi
|
||||
movl $1024, %ecx
|
||||
movl $g_kernel_cmdline, %edi
|
||||
rep movsl
|
||||
popl %edi
|
||||
popl %esi
|
||||
ret
|
||||
|
||||
enable_sse:
|
||||
movl %cr0, %eax
|
||||
andw $0xFFFB, %ax
|
||||
orw $0x0002, %ax
|
||||
movl %eax, %cr0
|
||||
movl %cr4, %eax
|
||||
orw $0x0600, %ax
|
||||
movl %eax, %cr4
|
||||
ret
|
||||
|
||||
initialize_paging:
|
||||
# identity map first 6 MiB
|
||||
movl $(0x00000000 + 0x83), boot_page_directory1 + 0
|
||||
movl $(0x00200000 + 0x83), boot_page_directory1 + 8
|
||||
movl $(0x00400000 + 0x83), boot_page_directory1 + 16
|
||||
movl $(boot_page_directory1 + 0x01), boot_page_directory_pointer_table
|
||||
|
||||
# enable PAE
|
||||
movl %cr4, %ecx
|
||||
orl $0x20, %ecx
|
||||
movl %ecx, %cr4
|
||||
|
||||
# set address of paging structures
|
||||
movl $boot_page_directory_pointer_table, %ecx
|
||||
movl %ecx, %cr3
|
||||
|
||||
# enable paging
|
||||
movl %cr0, %ecx
|
||||
orl $0x80000000, %ecx
|
||||
movl %ecx, %cr0
|
||||
|
||||
ret
|
||||
|
||||
initialize_gdt:
|
||||
lgdt boot_gdtr
|
||||
|
||||
# flush gdt
|
||||
movw $0x10, %ax
|
||||
movw %ax, %ds
|
||||
movw %ax, %es
|
||||
movw %ax, %fs
|
||||
movw %ax, %gs
|
||||
movw %ax, %ss
|
||||
jmp $0x08, $flush
|
||||
flush:
|
||||
ret
|
||||
|
||||
.global _start
|
||||
.type _start, @function
|
||||
_start:
|
||||
# Initialize stack and multiboot info
|
||||
movl $g_boot_stack_top, %esp
|
||||
movl %eax, g_multiboot_magic
|
||||
movl %ebx, g_multiboot_info
|
||||
|
||||
call copy_kernel_commandline
|
||||
call check_requirements
|
||||
call enable_sse
|
||||
|
||||
call initialize_paging
|
||||
call initialize_gdt
|
||||
|
||||
call _init
|
||||
|
||||
# call to the kernel itself (clear ebp for stacktrace)
|
||||
xorl %ebp, %ebp
|
||||
call kernel_main
|
||||
|
||||
call _fini
|
||||
|
||||
system_halt:
|
||||
xchgw %bx, %bx
|
||||
cli
|
||||
1: hlt
|
||||
jmp 1b
|
|
@ -0,0 +1,28 @@
|
|||
ENTRY (_start)
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
. = 0x00100000;
|
||||
|
||||
g_kernel_start = .;
|
||||
.text BLOCK(4K) : ALIGN(4K)
|
||||
{
|
||||
*(.multiboot)
|
||||
*(.text)
|
||||
}
|
||||
.rodata BLOCK(4K) : ALIGN(4K)
|
||||
{
|
||||
*(.rodata.*)
|
||||
}
|
||||
.data BLOCK(4K) : ALIGN(4K)
|
||||
{
|
||||
*(.data)
|
||||
}
|
||||
.bss BLOCK(4K) : ALIGN(4K)
|
||||
{
|
||||
*(COMMON)
|
||||
*(.bss)
|
||||
}
|
||||
|
||||
g_kernel_end = .;
|
||||
}
|
|
@ -1,620 +0,0 @@
|
|||
#include <kernel/CPUID.h>
|
||||
#include <kernel/Lock/SpinLock.h>
|
||||
#include <kernel/Memory/kmalloc.h>
|
||||
#include <kernel/Memory/PageTable.h>
|
||||
|
||||
extern uint8_t g_kernel_start[];
|
||||
extern uint8_t g_kernel_end[];
|
||||
|
||||
extern uint8_t g_kernel_execute_start[];
|
||||
extern uint8_t g_kernel_execute_end[];
|
||||
|
||||
extern uint8_t g_userspace_start[];
|
||||
extern uint8_t g_userspace_end[];
|
||||
|
||||
namespace Kernel
|
||||
{
|
||||
|
||||
SpinLock PageTable::s_fast_page_lock;
|
||||
|
||||
static PageTable* s_kernel = nullptr;
|
||||
static bool s_has_nxe = false;
|
||||
static bool s_has_pge = false;
|
||||
|
||||
static paddr_t s_global_pdpte = 0;
|
||||
|
||||
static inline PageTable::flags_t parse_flags(uint64_t entry)
|
||||
{
|
||||
using Flags = PageTable::Flags;
|
||||
|
||||
PageTable::flags_t result = 0;
|
||||
if (s_has_nxe && !(entry & (1ull << 63)))
|
||||
result |= Flags::Execute;
|
||||
if (entry & Flags::Reserved)
|
||||
result |= Flags::Reserved;
|
||||
if (entry & Flags::CacheDisable)
|
||||
result |= Flags::CacheDisable;
|
||||
if (entry & Flags::UserSupervisor)
|
||||
result |= Flags::UserSupervisor;
|
||||
if (entry & Flags::ReadWrite)
|
||||
result |= Flags::ReadWrite;
|
||||
if (entry & Flags::Present)
|
||||
result |= Flags::Present;
|
||||
return result;
|
||||
}
|
||||
|
||||
void PageTable::initialize()
|
||||
{
|
||||
if (CPUID::has_nxe())
|
||||
s_has_nxe = true;
|
||||
|
||||
if (CPUID::has_pge())
|
||||
s_has_pge = true;
|
||||
|
||||
ASSERT(s_kernel == nullptr);
|
||||
s_kernel = new PageTable();
|
||||
ASSERT(s_kernel);
|
||||
|
||||
s_kernel->initialize_kernel();
|
||||
s_kernel->initial_load();
|
||||
}
|
||||
|
||||
void PageTable::initial_load()
|
||||
{
|
||||
if (s_has_nxe)
|
||||
{
|
||||
asm volatile(
|
||||
"movl $0xC0000080, %%ecx;"
|
||||
"rdmsr;"
|
||||
"orl $0x800, %%eax;"
|
||||
"wrmsr"
|
||||
::: "eax", "ecx", "edx", "memory"
|
||||
);
|
||||
}
|
||||
|
||||
if (s_has_pge)
|
||||
{
|
||||
asm volatile(
|
||||
"movl %%cr4, %%eax;"
|
||||
"orl $0x80, %%eax;"
|
||||
"movl %%eax, %%cr4;"
|
||||
::: "eax"
|
||||
);
|
||||
}
|
||||
|
||||
// enable write protect
|
||||
asm volatile(
|
||||
"movl %%cr0, %%eax;"
|
||||
"orl $0x10000, %%eax;"
|
||||
"movl %%eax, %%cr0;"
|
||||
::: "rax"
|
||||
);
|
||||
|
||||
load();
|
||||
}
|
||||
|
||||
PageTable& PageTable::kernel()
|
||||
{
|
||||
ASSERT(s_kernel);
|
||||
return *s_kernel;
|
||||
}
|
||||
|
||||
bool PageTable::is_valid_pointer(uintptr_t)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
static uint64_t* allocate_zeroed_page_aligned_page()
|
||||
{
|
||||
void* page = kmalloc(PAGE_SIZE, PAGE_SIZE, true);
|
||||
ASSERT(page);
|
||||
memset(page, 0, PAGE_SIZE);
|
||||
return (uint64_t*)page;
|
||||
}
|
||||
|
||||
void PageTable::initialize_kernel()
|
||||
{
|
||||
ASSERT(s_global_pdpte == 0);
|
||||
s_global_pdpte = V2P(allocate_zeroed_page_aligned_page());
|
||||
|
||||
map_kernel_memory();
|
||||
|
||||
prepare_fast_page();
|
||||
|
||||
// Map main bios area below 1 MiB
|
||||
map_range_at(
|
||||
0x000E0000,
|
||||
P2V(0x000E0000),
|
||||
0x00100000 - 0x000E0000,
|
||||
PageTable::Flags::Present
|
||||
);
|
||||
|
||||
// Map (phys_kernel_start -> phys_kernel_end) to (virt_kernel_start -> virt_kernel_end)
|
||||
ASSERT((vaddr_t)g_kernel_start % PAGE_SIZE == 0);
|
||||
map_range_at(
|
||||
V2P(g_kernel_start),
|
||||
(vaddr_t)g_kernel_start,
|
||||
g_kernel_end - g_kernel_start,
|
||||
Flags::ReadWrite | Flags::Present
|
||||
);
|
||||
|
||||
// Map executable kernel memory as executable
|
||||
map_range_at(
|
||||
V2P(g_kernel_execute_start),
|
||||
(vaddr_t)g_kernel_execute_start,
|
||||
g_kernel_execute_end - g_kernel_execute_start,
|
||||
Flags::Execute | Flags::Present
|
||||
);
|
||||
|
||||
// Map userspace memory
|
||||
map_range_at(
|
||||
V2P(g_userspace_start),
|
||||
(vaddr_t)g_userspace_start,
|
||||
g_userspace_end - g_userspace_start,
|
||||
Flags::Execute | Flags::UserSupervisor | Flags::Present
|
||||
);
|
||||
}
|
||||
|
||||
void PageTable::prepare_fast_page()
|
||||
{
|
||||
constexpr uint64_t pdpte = (fast_page() >> 30) & 0x1FF;
|
||||
constexpr uint64_t pde = (fast_page() >> 21) & 0x1FF;
|
||||
constexpr uint64_t pte = (fast_page() >> 12) & 0x1FF;
|
||||
|
||||
uint64_t* pdpt = reinterpret_cast<uint64_t*>(P2V(m_highest_paging_struct));
|
||||
ASSERT(pdpt[pdpte] & Flags::Present);
|
||||
|
||||
uint64_t* pd = reinterpret_cast<uint64_t*>(P2V(pdpt[pdpte]) & PAGE_ADDR_MASK);
|
||||
ASSERT(!(pd[pde] & Flags::Present));
|
||||
pd[pde] = V2P(allocate_zeroed_page_aligned_page()) | Flags::ReadWrite | Flags::Present;
|
||||
|
||||
uint64_t* pt = reinterpret_cast<uint64_t*>(P2V(pd[pde]) & PAGE_ADDR_MASK);
|
||||
ASSERT(!(pt[pte] & Flags::Present));
|
||||
pt[pte] = V2P(allocate_zeroed_page_aligned_page());
|
||||
}
|
||||
|
||||
void PageTable::map_fast_page(paddr_t paddr)
|
||||
{
|
||||
ASSERT(s_kernel);
|
||||
ASSERT(paddr);
|
||||
|
||||
ASSERT(s_fast_page_lock.current_processor_has_lock());
|
||||
|
||||
constexpr uint64_t pdpte = (fast_page() >> 30) & 0x1FF;
|
||||
constexpr uint64_t pde = (fast_page() >> 21) & 0x1FF;
|
||||
constexpr uint64_t pte = (fast_page() >> 12) & 0x1FF;
|
||||
|
||||
uint64_t* pdpt = reinterpret_cast<uint64_t*>(P2V(s_kernel->m_highest_paging_struct));
|
||||
uint64_t* pd = reinterpret_cast<uint64_t*>(P2V(pdpt[pdpte] & PAGE_ADDR_MASK));
|
||||
uint64_t* pt = reinterpret_cast<uint64_t*>(P2V(pd[pde] & PAGE_ADDR_MASK));
|
||||
|
||||
ASSERT(!(pt[pte] & Flags::Present));
|
||||
pt[pte] = paddr | Flags::ReadWrite | Flags::Present;
|
||||
|
||||
invalidate(fast_page());
|
||||
}
|
||||
|
||||
void PageTable::unmap_fast_page()
|
||||
{
|
||||
ASSERT(s_kernel);
|
||||
|
||||
ASSERT(s_fast_page_lock.current_processor_has_lock());
|
||||
|
||||
constexpr uint64_t pdpte = (fast_page() >> 30) & 0x1FF;
|
||||
constexpr uint64_t pde = (fast_page() >> 21) & 0x1FF;
|
||||
constexpr uint64_t pte = (fast_page() >> 12) & 0x1FF;
|
||||
|
||||
uint64_t* pdpt = reinterpret_cast<uint64_t*>(P2V(s_kernel->m_highest_paging_struct));
|
||||
uint64_t* pd = reinterpret_cast<uint64_t*>(P2V(pdpt[pdpte] & PAGE_ADDR_MASK));
|
||||
uint64_t* pt = reinterpret_cast<uint64_t*>(P2V(pd[pde] & PAGE_ADDR_MASK));
|
||||
|
||||
ASSERT(pt[pte] & Flags::Present);
|
||||
pt[pte] = 0;
|
||||
|
||||
invalidate(fast_page());
|
||||
}
|
||||
|
||||
BAN::ErrorOr<PageTable*> PageTable::create_userspace()
|
||||
{
|
||||
SpinLockGuard _(s_kernel->m_lock);
|
||||
PageTable* page_table = new PageTable;
|
||||
if (page_table == nullptr)
|
||||
return BAN::Error::from_errno(ENOMEM);
|
||||
page_table->map_kernel_memory();
|
||||
return page_table;
|
||||
}
|
||||
|
||||
void PageTable::map_kernel_memory()
|
||||
{
|
||||
ASSERT(s_kernel);
|
||||
ASSERT(s_global_pdpte);
|
||||
|
||||
ASSERT(m_highest_paging_struct == 0);
|
||||
m_highest_paging_struct = V2P(kmalloc(32, 32, true));
|
||||
ASSERT(m_highest_paging_struct);
|
||||
|
||||
uint64_t* pdpt = reinterpret_cast<uint64_t*>(P2V(m_highest_paging_struct));
|
||||
pdpt[0] = 0;
|
||||
pdpt[1] = 0;
|
||||
pdpt[2] = 0;
|
||||
pdpt[3] = s_global_pdpte | Flags::Present;
|
||||
static_assert(KERNEL_OFFSET == 0xC0000000);
|
||||
}
|
||||
|
||||
PageTable::~PageTable()
|
||||
{
|
||||
uint64_t* pdpt = reinterpret_cast<uint64_t*>(P2V(m_highest_paging_struct));
|
||||
|
||||
for (uint32_t pdpte = 0; pdpte < 3; pdpte++)
|
||||
{
|
||||
if (!(pdpt[pdpte] & Flags::Present))
|
||||
continue;
|
||||
uint64_t* pd = reinterpret_cast<uint64_t*>(P2V(pdpt[pdpte] & PAGE_ADDR_MASK));
|
||||
for (uint32_t pde = 0; pde < 512; pde++)
|
||||
{
|
||||
if (!(pd[pde] & Flags::Present))
|
||||
continue;
|
||||
kfree(reinterpret_cast<uint64_t*>(P2V(pd[pde] & PAGE_ADDR_MASK)));
|
||||
}
|
||||
kfree(pd);
|
||||
}
|
||||
kfree(pdpt);
|
||||
}
|
||||
|
||||
void PageTable::load()
|
||||
{
|
||||
SpinLockGuard _(m_lock);
|
||||
ASSERT(m_highest_paging_struct < 0x100000000);
|
||||
const uint32_t pdpt_lo = m_highest_paging_struct;
|
||||
asm volatile("movl %0, %%cr3" :: "r"(pdpt_lo));
|
||||
Processor::set_current_page_table(this);
|
||||
}
|
||||
|
||||
void PageTable::invalidate(vaddr_t vaddr)
|
||||
{
|
||||
ASSERT(vaddr % PAGE_SIZE == 0);
|
||||
asm volatile("invlpg (%0)" :: "r"(vaddr) : "memory");
|
||||
}
|
||||
|
||||
void PageTable::unmap_page(vaddr_t vaddr)
|
||||
{
|
||||
ASSERT(vaddr);
|
||||
ASSERT(vaddr % PAGE_SIZE == 0);
|
||||
ASSERT(vaddr != fast_page());
|
||||
if (vaddr >= KERNEL_OFFSET)
|
||||
ASSERT(vaddr >= (vaddr_t)g_kernel_start);
|
||||
if ((vaddr >= KERNEL_OFFSET) != (this == s_kernel))
|
||||
Kernel::panic("unmapping {8H}, kernel: {}", vaddr, this == s_kernel);
|
||||
|
||||
const uint64_t pdpte = (vaddr >> 30) & 0x1FF;
|
||||
const uint64_t pde = (vaddr >> 21) & 0x1FF;
|
||||
const uint64_t pte = (vaddr >> 12) & 0x1FF;
|
||||
|
||||
SpinLockGuard _(m_lock);
|
||||
|
||||
if (is_page_free(vaddr))
|
||||
{
|
||||
dwarnln("unmapping unmapped page {8H}", vaddr);
|
||||
return;
|
||||
}
|
||||
|
||||
uint64_t* pdpt = reinterpret_cast<uint64_t*>(P2V(m_highest_paging_struct));
|
||||
uint64_t* pd = reinterpret_cast<uint64_t*>(P2V(pdpt[pdpte] & PAGE_ADDR_MASK));
|
||||
uint64_t* pt = reinterpret_cast<uint64_t*>(P2V(pd[pde] & PAGE_ADDR_MASK));
|
||||
|
||||
pt[pte] = 0;
|
||||
invalidate(vaddr);
|
||||
}
|
||||
|
||||
void PageTable::unmap_range(vaddr_t vaddr, size_t size)
|
||||
{
|
||||
vaddr_t s_page = vaddr / PAGE_SIZE;
|
||||
vaddr_t e_page = BAN::Math::div_round_up<vaddr_t>(vaddr + size, PAGE_SIZE);
|
||||
|
||||
SpinLockGuard _(m_lock);
|
||||
for (vaddr_t page = s_page; page < e_page; page++)
|
||||
unmap_page(page * PAGE_SIZE);
|
||||
}
|
||||
|
||||
void PageTable::map_page_at(paddr_t paddr, vaddr_t vaddr, flags_t flags)
|
||||
{
|
||||
ASSERT(vaddr);
|
||||
ASSERT(vaddr != fast_page());
|
||||
if ((vaddr >= KERNEL_OFFSET) != (this == s_kernel))
|
||||
Kernel::panic("mapping {8H} to {8H}, kernel: {}", paddr, vaddr, this == s_kernel);
|
||||
|
||||
ASSERT(paddr % PAGE_SIZE == 0);
|
||||
ASSERT(vaddr % PAGE_SIZE == 0);
|
||||
ASSERT(flags & Flags::Used);
|
||||
|
||||
const uint64_t pdpte = (vaddr >> 30) & 0x1FF;
|
||||
const uint64_t pde = (vaddr >> 21) & 0x1FF;
|
||||
const uint64_t pte = (vaddr >> 12) & 0x1FF;
|
||||
|
||||
uint64_t extra_flags = 0;
|
||||
if (s_has_pge && vaddr >= KERNEL_OFFSET) // Map kernel memory as global
|
||||
extra_flags |= 1ull << 8;
|
||||
if (s_has_nxe && !(flags & Flags::Execute))
|
||||
extra_flags |= 1ull << 63;
|
||||
if (flags & Flags::Reserved)
|
||||
extra_flags |= Flags::Reserved;
|
||||
if (flags & Flags::CacheDisable)
|
||||
extra_flags |= Flags::CacheDisable;
|
||||
|
||||
// NOTE: we add present here, since it has to be available in higher level structures
|
||||
flags_t uwr_flags = (flags & (Flags::UserSupervisor | Flags::ReadWrite)) | Flags::Present;
|
||||
|
||||
SpinLockGuard _(m_lock);
|
||||
|
||||
uint64_t* pdpt = reinterpret_cast<uint64_t*>(P2V(m_highest_paging_struct));
|
||||
if (!(pdpt[pdpte] & Flags::Present))
|
||||
pdpt[pdpte] = V2P(allocate_zeroed_page_aligned_page()) | Flags::Present;
|
||||
|
||||
uint64_t* pd = reinterpret_cast<uint64_t*>(P2V(pdpt[pdpte] & PAGE_ADDR_MASK));
|
||||
if ((pd[pde] & uwr_flags) != uwr_flags)
|
||||
{
|
||||
if (!(pd[pde] & Flags::Present))
|
||||
pd[pde] = V2P(allocate_zeroed_page_aligned_page());
|
||||
pd[pde] |= uwr_flags;
|
||||
}
|
||||
|
||||
if (!(flags & Flags::Present))
|
||||
uwr_flags &= ~Flags::Present;
|
||||
|
||||
uint64_t* pt = reinterpret_cast<uint64_t*>(P2V(pd[pde] & PAGE_ADDR_MASK));
|
||||
pt[pte] = paddr | uwr_flags | extra_flags;
|
||||
|
||||
invalidate(vaddr);
|
||||
}
|
||||
|
||||
void PageTable::map_range_at(paddr_t paddr, vaddr_t vaddr, size_t size, flags_t flags)
|
||||
{
|
||||
ASSERT(vaddr);
|
||||
ASSERT(paddr % PAGE_SIZE == 0);
|
||||
ASSERT(vaddr % PAGE_SIZE == 0);
|
||||
|
||||
size_t page_count = range_page_count(vaddr, size);
|
||||
|
||||
SpinLockGuard _(m_lock);
|
||||
for (size_t page = 0; page < page_count; page++)
|
||||
map_page_at(paddr + page * PAGE_SIZE, vaddr + page * PAGE_SIZE, flags);
|
||||
}
|
||||
|
||||
uint64_t PageTable::get_page_data(vaddr_t vaddr) const
|
||||
{
|
||||
ASSERT(vaddr % PAGE_SIZE == 0);
|
||||
|
||||
const uint64_t pdpte = (vaddr >> 30) & 0x1FF;
|
||||
const uint64_t pde = (vaddr >> 21) & 0x1FF;
|
||||
const uint64_t pte = (vaddr >> 12) & 0x1FF;
|
||||
|
||||
SpinLockGuard _(m_lock);
|
||||
|
||||
uint64_t* pdpt = (uint64_t*)P2V(m_highest_paging_struct);
|
||||
if (!(pdpt[pdpte] & Flags::Present))
|
||||
return 0;
|
||||
|
||||
uint64_t* pd = (uint64_t*)P2V(pdpt[pdpte] & PAGE_ADDR_MASK);
|
||||
if (!(pd[pde] & Flags::Present))
|
||||
return 0;
|
||||
|
||||
uint64_t* pt = (uint64_t*)P2V(pd[pde] & PAGE_ADDR_MASK);
|
||||
if (!(pt[pte] & Flags::Used))
|
||||
return 0;
|
||||
|
||||
return pt[pte];
|
||||
}
|
||||
|
||||
PageTable::flags_t PageTable::get_page_flags(vaddr_t vaddr) const
|
||||
{
|
||||
return parse_flags(get_page_data(vaddr));
|
||||
}
|
||||
|
||||
paddr_t PageTable::physical_address_of(vaddr_t vaddr) const
|
||||
{
|
||||
uint64_t page_data = get_page_data(vaddr);
|
||||
return (page_data & PAGE_ADDR_MASK) & ~(1ull << 63);
|
||||
}
|
||||
|
||||
bool PageTable::is_page_free(vaddr_t vaddr) const
|
||||
{
|
||||
ASSERT(vaddr % PAGE_SIZE == 0);
|
||||
return !(get_page_flags(vaddr) & Flags::Used);
|
||||
}
|
||||
|
||||
bool PageTable::is_range_free(vaddr_t vaddr, size_t size) const
|
||||
{
|
||||
vaddr_t s_page = vaddr / PAGE_SIZE;
|
||||
vaddr_t e_page = BAN::Math::div_round_up<vaddr_t>(vaddr + size, PAGE_SIZE);
|
||||
|
||||
SpinLockGuard _(m_lock);
|
||||
for (vaddr_t page = s_page; page < e_page; page++)
|
||||
if (!is_page_free(page * PAGE_SIZE))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PageTable::reserve_page(vaddr_t vaddr, bool only_free)
|
||||
{
|
||||
SpinLockGuard _(m_lock);
|
||||
ASSERT(vaddr % PAGE_SIZE == 0);
|
||||
if (only_free && !is_page_free(vaddr))
|
||||
return false;
|
||||
map_page_at(0, vaddr, Flags::Reserved);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PageTable::reserve_range(vaddr_t vaddr, size_t bytes, bool only_free)
|
||||
{
|
||||
if (size_t rem = bytes % PAGE_SIZE)
|
||||
bytes += PAGE_SIZE - rem;
|
||||
ASSERT(vaddr % PAGE_SIZE == 0);
|
||||
|
||||
SpinLockGuard _(m_lock);
|
||||
if (only_free && !is_range_free(vaddr, bytes))
|
||||
return false;
|
||||
for (size_t offset = 0; offset < bytes; offset += PAGE_SIZE)
|
||||
reserve_page(vaddr + offset);
|
||||
return true;
|
||||
}
|
||||
|
||||
vaddr_t PageTable::reserve_free_page(vaddr_t first_address, vaddr_t last_address)
|
||||
{
|
||||
if (first_address >= KERNEL_OFFSET && first_address < (vaddr_t)g_kernel_end)
|
||||
first_address = (vaddr_t)g_kernel_end;
|
||||
if (size_t rem = first_address % PAGE_SIZE)
|
||||
first_address += PAGE_SIZE - rem;
|
||||
if (size_t rem = last_address % PAGE_SIZE)
|
||||
last_address -= rem;
|
||||
|
||||
const uint32_t s_pdpte = (first_address >> 30) & 0x1FF;
|
||||
const uint32_t s_pde = (first_address >> 21) & 0x1FF;
|
||||
const uint32_t s_pte = (first_address >> 12) & 0x1FF;
|
||||
|
||||
const uint32_t e_pdpte = (last_address >> 30) & 0x1FF;
|
||||
const uint32_t e_pde = (last_address >> 21) & 0x1FF;
|
||||
const uint32_t e_pte = (last_address >> 12) & 0x1FF;
|
||||
|
||||
SpinLockGuard _(m_lock);
|
||||
|
||||
// Try to find free page that can be mapped without
|
||||
// allocations (page table with unused entries)
|
||||
uint64_t* pdpt = reinterpret_cast<uint64_t*>(P2V(m_highest_paging_struct));
|
||||
for (uint32_t pdpte = s_pdpte; pdpte < 4; pdpte++)
|
||||
{
|
||||
if (pdpte > e_pdpte)
|
||||
break;
|
||||
if (!(pdpt[pdpte] & Flags::Present))
|
||||
continue;
|
||||
uint64_t* pd = reinterpret_cast<uint64_t*>(P2V(pdpt[pdpte] & PAGE_ADDR_MASK));
|
||||
for (uint32_t pde = s_pde; pde < 512; pde++)
|
||||
{
|
||||
if (pdpte == e_pdpte && pde > e_pde)
|
||||
break;
|
||||
if (!(pd[pde] & Flags::Present))
|
||||
continue;
|
||||
uint64_t* pt = (uint64_t*)P2V(pd[pde] & PAGE_ADDR_MASK);
|
||||
for (uint32_t pte = s_pte; pte < 512; pte++)
|
||||
{
|
||||
if (pdpte == e_pdpte && pde == e_pde && pte >= e_pte)
|
||||
break;
|
||||
if (!(pt[pte] & Flags::Used))
|
||||
{
|
||||
vaddr_t vaddr = 0;
|
||||
vaddr |= (vaddr_t)pdpte << 30;
|
||||
vaddr |= (vaddr_t)pde << 21;
|
||||
vaddr |= (vaddr_t)pte << 12;
|
||||
ASSERT(reserve_page(vaddr));
|
||||
return vaddr;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Find any free page
|
||||
for (vaddr_t vaddr = first_address; vaddr < last_address; vaddr += PAGE_SIZE)
|
||||
{
|
||||
if (is_page_free(vaddr))
|
||||
{
|
||||
ASSERT(reserve_page(vaddr));
|
||||
return vaddr;
|
||||
}
|
||||
}
|
||||
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
vaddr_t PageTable::reserve_free_contiguous_pages(size_t page_count, vaddr_t first_address, vaddr_t last_address)
|
||||
{
|
||||
if (first_address >= KERNEL_OFFSET && first_address < (vaddr_t)g_kernel_start)
|
||||
first_address = (vaddr_t)g_kernel_start;
|
||||
if (size_t rem = first_address % PAGE_SIZE)
|
||||
first_address += PAGE_SIZE - rem;
|
||||
if (size_t rem = last_address % PAGE_SIZE)
|
||||
last_address -= rem;
|
||||
|
||||
SpinLockGuard _(m_lock);
|
||||
|
||||
for (vaddr_t vaddr = first_address; vaddr < last_address;)
|
||||
{
|
||||
bool valid { true };
|
||||
for (size_t page = 0; page < page_count; page++)
|
||||
{
|
||||
if (!is_page_free(vaddr + page * PAGE_SIZE))
|
||||
{
|
||||
vaddr += (page + 1) * PAGE_SIZE;
|
||||
valid = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (valid)
|
||||
{
|
||||
ASSERT(reserve_range(vaddr, page_count * PAGE_SIZE));
|
||||
return vaddr;
|
||||
}
|
||||
}
|
||||
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
static void dump_range(vaddr_t start, vaddr_t end, PageTable::flags_t flags)
|
||||
{
|
||||
if (start == 0)
|
||||
return;
|
||||
dprintln("{}-{}: {}{}{}{}",
|
||||
(void*)(start), (void*)(end - 1),
|
||||
flags & PageTable::Flags::Execute ? 'x' : '-',
|
||||
flags & PageTable::Flags::UserSupervisor ? 'u' : '-',
|
||||
flags & PageTable::Flags::ReadWrite ? 'w' : '-',
|
||||
flags & PageTable::Flags::Present ? 'r' : '-'
|
||||
);
|
||||
}
|
||||
|
||||
void PageTable::debug_dump()
|
||||
{
|
||||
SpinLockGuard _(m_lock);
|
||||
|
||||
flags_t flags = 0;
|
||||
vaddr_t start = 0;
|
||||
|
||||
uint64_t* pdpt = reinterpret_cast<uint64_t*>(P2V(m_highest_paging_struct));
|
||||
for (uint32_t pdpte = 0; pdpte < 4; pdpte++)
|
||||
{
|
||||
if (!(pdpt[pdpte] & Flags::Present))
|
||||
{
|
||||
dump_range(start, (pdpte << 30), flags);
|
||||
start = 0;
|
||||
continue;
|
||||
}
|
||||
uint64_t* pd = (uint64_t*)P2V(pdpt[pdpte] & PAGE_ADDR_MASK);
|
||||
for (uint64_t pde = 0; pde < 512; pde++)
|
||||
{
|
||||
if (!(pd[pde] & Flags::Present))
|
||||
{
|
||||
dump_range(start, (pdpte << 30) | (pde << 21), flags);
|
||||
start = 0;
|
||||
continue;
|
||||
}
|
||||
uint64_t* pt = (uint64_t*)P2V(pd[pde] & PAGE_ADDR_MASK);
|
||||
for (uint64_t pte = 0; pte < 512; pte++)
|
||||
{
|
||||
if (parse_flags(pt[pte]) != flags)
|
||||
{
|
||||
dump_range(start, (pdpte << 30) | (pde << 21) | (pte << 12), flags);
|
||||
start = 0;
|
||||
}
|
||||
|
||||
if (!(pt[pte] & Flags::Used))
|
||||
continue;
|
||||
|
||||
if (start == 0)
|
||||
{
|
||||
flags = parse_flags(pt[pte]);
|
||||
start = (pdpte << 30) | (pde << 21) | (pte << 12);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,35 +0,0 @@
|
|||
.section .userspace, "aw"
|
||||
|
||||
// stack contains
|
||||
// return address
|
||||
// signal number
|
||||
// signal handler
|
||||
|
||||
.global signal_trampoline
|
||||
signal_trampoline:
|
||||
pushl %ebp
|
||||
movl %esp, %ebp
|
||||
|
||||
pusha
|
||||
|
||||
movl 40(%esp), %edi
|
||||
movl 36(%esp), %eax
|
||||
|
||||
// align stack to 16 bytes
|
||||
movl %esp, %ebx
|
||||
andl $0x0F, %ebx
|
||||
subl %ebx, %esp
|
||||
|
||||
subl $12, %esp
|
||||
pushl %edi
|
||||
call *%eax
|
||||
addl $16, %esp
|
||||
|
||||
// restore stack
|
||||
addl %ebx, %esp
|
||||
popa
|
||||
|
||||
leave
|
||||
addl $8, %esp
|
||||
|
||||
ret
|
|
@ -1,85 +0,0 @@
|
|||
// arguments in EAX, EBX, ECX, EDX, ESI, EDI
|
||||
.global asm_syscall_handler
|
||||
asm_syscall_handler:
|
||||
# save segment registers
|
||||
pushw %ds
|
||||
pushw %es
|
||||
pushw %fs
|
||||
pushw %gs
|
||||
|
||||
# save general purpose registers
|
||||
pushl %ebx
|
||||
pushl %ecx
|
||||
pushl %edx
|
||||
pushl %edi
|
||||
pushl %esi
|
||||
pushl %ebp
|
||||
|
||||
# align stack and push arguments
|
||||
pushl %esp
|
||||
addl $32, (%esp)
|
||||
pushl %edi
|
||||
pushl %esi
|
||||
pushl %edx
|
||||
pushl %ecx
|
||||
pushl %ebx
|
||||
pushl %eax
|
||||
|
||||
# load kernel segments
|
||||
movw $0x10, %ax
|
||||
movw %ax, %ds
|
||||
movw %ax, %es
|
||||
movw %ax, %fs
|
||||
movw $0x28, %ax
|
||||
movw %ax, %gs
|
||||
|
||||
call cpp_syscall_handler
|
||||
addl $28, %esp
|
||||
|
||||
# restore general purpose registers
|
||||
popl %ebp
|
||||
popl %esi
|
||||
popl %edi
|
||||
popl %edx
|
||||
popl %ecx
|
||||
popl %ebx
|
||||
|
||||
# restore segment registers
|
||||
popw %gs
|
||||
popw %fs
|
||||
popw %es
|
||||
popw %ds
|
||||
|
||||
iret
|
||||
|
||||
.global sys_fork_trampoline
|
||||
sys_fork_trampoline:
|
||||
pushl %ebp
|
||||
pushl %ebx
|
||||
pushl %esi
|
||||
pushl %edi
|
||||
|
||||
call read_ip
|
||||
testl %eax, %eax
|
||||
jz .reload_stack
|
||||
|
||||
movl %esp, %ebx
|
||||
|
||||
subl $8, %esp
|
||||
pushl %eax
|
||||
pushl %ebx
|
||||
call sys_fork
|
||||
addl $16, %esp
|
||||
|
||||
.done:
|
||||
popl %edi
|
||||
popl %esi
|
||||
popl %ebx
|
||||
popl %ebp
|
||||
ret
|
||||
|
||||
.reload_stack:
|
||||
call get_thread_start_sp
|
||||
movl %eax, %esp
|
||||
xorl %eax, %eax
|
||||
jmp .done
|
|
@ -1,68 +0,0 @@
|
|||
# uint32_t read_ip()
|
||||
.global read_ip
|
||||
read_ip:
|
||||
popl %eax
|
||||
jmp *%eax
|
||||
|
||||
# void start_kernel_thread()
|
||||
.global start_kernel_thread
|
||||
start_kernel_thread:
|
||||
call get_thread_start_sp
|
||||
movl %eax, %esp
|
||||
|
||||
# STACK LAYOUT
|
||||
# on_exit arg
|
||||
# on_exit func
|
||||
# entry arg
|
||||
# entry func
|
||||
|
||||
movl 4(%esp), %edi
|
||||
movl 0(%esp), %esi
|
||||
|
||||
subl $12, %esp
|
||||
pushl %edi
|
||||
sti
|
||||
call *%esi
|
||||
addl $16, %esp
|
||||
|
||||
movl 12(%esp), %edi
|
||||
movl 8(%esp), %esi
|
||||
|
||||
subl $12, %esp
|
||||
pushl %edi
|
||||
call *%esi
|
||||
addl $16, %esp
|
||||
|
||||
|
||||
.global start_userspace_thread
|
||||
start_userspace_thread:
|
||||
call get_thread_start_sp
|
||||
movl %eax, %esp
|
||||
|
||||
# STACK LAYOUT
|
||||
# entry
|
||||
# argc
|
||||
# argv
|
||||
# envp
|
||||
# userspace stack
|
||||
|
||||
call get_userspace_thread_stack_top
|
||||
|
||||
movw $(0x20 | 3), %bx
|
||||
movw %bx, %ds
|
||||
movw %bx, %es
|
||||
movw %bx, %fs
|
||||
movw %bx, %gs
|
||||
xorw %bx, %bx
|
||||
|
||||
popl %edx
|
||||
popl %esi
|
||||
popl %edi
|
||||
popl %ecx
|
||||
|
||||
pushl $(0x20 | 3)
|
||||
pushl %eax
|
||||
pushl $0x202
|
||||
pushl $(0x18 | 3)
|
||||
pushl %ecx
|
||||
iret
|
|
@ -1,305 +0,0 @@
|
|||
.set PG_PRESENT, 1<<0
|
||||
.set PG_READ_WRITE, 1<<1
|
||||
.set PG_PAGE_SIZE, 1<<7
|
||||
|
||||
.set FB_WIDTH, 800
|
||||
.set FB_HEIGHT, 600
|
||||
.set FB_BPP, 32
|
||||
|
||||
#define KERNEL_OFFSET 0xC0000000
|
||||
#define V2P(vaddr) ((vaddr) - KERNEL_OFFSET)
|
||||
|
||||
.code32
|
||||
|
||||
# multiboot2 header
|
||||
.section .multiboot, "aw"
|
||||
.align 8
|
||||
multiboot2_start:
|
||||
.long 0xE85250D6
|
||||
.long 0
|
||||
.long multiboot2_end - multiboot2_start
|
||||
.long -(0xE85250D6 + (multiboot2_end - multiboot2_start))
|
||||
|
||||
# framebuffer tag
|
||||
.align 8
|
||||
.short 5
|
||||
.short 0
|
||||
.long 20
|
||||
.long FB_WIDTH
|
||||
.long FB_HEIGHT
|
||||
.long FB_BPP
|
||||
|
||||
# legacy start
|
||||
.align 8
|
||||
.short 3
|
||||
.short 0
|
||||
.long 12
|
||||
.long V2P(_start)
|
||||
|
||||
.align 8
|
||||
.short 0
|
||||
.short 0
|
||||
.long 8
|
||||
multiboot2_end:
|
||||
|
||||
.section .bananboot, "aw"
|
||||
.align 8
|
||||
bananboot_start:
|
||||
.long 0xBABAB007
|
||||
.long -(0xBABAB007 + FB_WIDTH + FB_HEIGHT + FB_BPP)
|
||||
.long FB_WIDTH
|
||||
.long FB_HEIGHT
|
||||
.long FB_BPP
|
||||
bananboot_end:
|
||||
|
||||
.section .bss, "aw", @nobits
|
||||
.align 4096
|
||||
boot_stack_bottom:
|
||||
.skip 4096 * 4
|
||||
boot_stack_top:
|
||||
|
||||
.global g_kernel_cmdline
|
||||
g_kernel_cmdline:
|
||||
.skip 4096
|
||||
|
||||
bootloader_magic:
|
||||
.skip 8
|
||||
bootloader_info:
|
||||
.skip 8
|
||||
|
||||
.section .data
|
||||
|
||||
# Map first GiB to 0x00000000 and 0xC0000000
|
||||
.align 32
|
||||
boot_pdpt:
|
||||
.long V2P(boot_pd) + (PG_PRESENT)
|
||||
.long 0
|
||||
.quad 0
|
||||
.quad 0
|
||||
.long V2P(boot_pd) + (PG_PRESENT)
|
||||
.long 0
|
||||
.align 4096
|
||||
boot_pd:
|
||||
.set i, 0
|
||||
.rept 512
|
||||
.long V2P(boot_pts) + i + (PG_READ_WRITE | PG_PRESENT)
|
||||
.long 0
|
||||
.set i, i + 0x1000
|
||||
.endr
|
||||
boot_pts:
|
||||
.set i, 0
|
||||
.rept 512
|
||||
.rept 512
|
||||
.long i + (PG_READ_WRITE | PG_PRESENT)
|
||||
.long 0
|
||||
.set i, i + 0x1000
|
||||
.endr
|
||||
.endr
|
||||
|
||||
boot_gdt:
|
||||
.quad 0x0000000000000000 # null descriptor
|
||||
.quad 0x00CF9A000000FFFF # kernel code
|
||||
.quad 0x00CF92000000FFFF # kernel data
|
||||
boot_gdtr:
|
||||
.short . - boot_gdt - 1
|
||||
.long V2P(boot_gdt)
|
||||
|
||||
.global g_ap_startup_done
|
||||
g_ap_startup_done:
|
||||
.byte 0
|
||||
.global g_ap_running_count
|
||||
g_ap_running_count:
|
||||
.byte 0
|
||||
.global g_ap_stack_loaded
|
||||
g_ap_stack_loaded:
|
||||
.byte 0
|
||||
|
||||
.section .text
|
||||
|
||||
has_cpuid:
|
||||
pushfl
|
||||
pushfl
|
||||
xorl $0x00200000, (%esp)
|
||||
popfl
|
||||
pushfl
|
||||
popl %eax
|
||||
xorl (%esp), %eax
|
||||
popfl
|
||||
testl $0x00200000, %eax
|
||||
ret
|
||||
|
||||
has_pae:
|
||||
movl $0, %eax
|
||||
cpuid
|
||||
testl $(1 << 6), %edx
|
||||
ret
|
||||
|
||||
has_sse:
|
||||
movl $1, %eax
|
||||
cpuid
|
||||
testl $(1 << 25), %edx
|
||||
ret
|
||||
|
||||
check_requirements:
|
||||
call has_cpuid
|
||||
jz .exit
|
||||
call has_pae
|
||||
jz .exit
|
||||
call has_sse
|
||||
jz .exit
|
||||
ret
|
||||
.exit:
|
||||
jmp system_halt
|
||||
|
||||
enable_sse:
|
||||
movl %cr0, %eax
|
||||
andw $0xFFFB, %ax
|
||||
orw $0x0002, %ax
|
||||
movl %eax, %cr0
|
||||
movl %cr4, %eax
|
||||
orw $0x0600, %ax
|
||||
movl %eax, %cr4
|
||||
ret
|
||||
|
||||
initialize_paging:
|
||||
# enable PAE
|
||||
movl %cr4, %ecx
|
||||
orl $(1 << 5), %ecx
|
||||
movl %ecx, %cr4
|
||||
|
||||
# load page tables
|
||||
movl $V2P(boot_pdpt), %ecx
|
||||
movl %ecx, %cr3
|
||||
|
||||
# enable paging
|
||||
movl %cr0, %ecx
|
||||
orl $(1 << 31), %ecx
|
||||
movl %ecx, %cr0
|
||||
|
||||
ret
|
||||
|
||||
.global _start
|
||||
.type _start, @function
|
||||
_start:
|
||||
cli; cld
|
||||
|
||||
# save bootloader magic and info
|
||||
movl %eax, V2P(bootloader_magic)
|
||||
movl %ebx, V2P(bootloader_info)
|
||||
|
||||
# load boot stack
|
||||
movl $V2P(boot_stack_top), %esp
|
||||
|
||||
# load boot GDT
|
||||
lgdt V2P(boot_gdtr)
|
||||
ljmpl $0x08, $V2P(gdt_flush)
|
||||
gdt_flush:
|
||||
# set correct segment registers
|
||||
movw $0x10, %ax
|
||||
movw %ax, %ds
|
||||
movw %ax, %ss
|
||||
movw %ax, %es
|
||||
|
||||
# do processor initialization
|
||||
call check_requirements
|
||||
call enable_sse
|
||||
call initialize_paging
|
||||
|
||||
# load higher half stack pointer
|
||||
movl $boot_stack_top, %esp
|
||||
|
||||
# jump to higher half
|
||||
leal higher_half, %ecx
|
||||
jmp *%ecx
|
||||
|
||||
higher_half:
|
||||
# call global constuctors
|
||||
call _init
|
||||
|
||||
# call to the kernel itself (clear ebp for stacktrace)
|
||||
xorl %ebp, %ebp
|
||||
|
||||
subl $8, %esp
|
||||
pushl bootloader_info
|
||||
pushl bootloader_magic
|
||||
call kernel_main
|
||||
addl $16, %esp
|
||||
|
||||
# call global destructors
|
||||
call _fini
|
||||
|
||||
system_halt:
|
||||
xchgw %bx, %bx
|
||||
cli
|
||||
1: hlt
|
||||
jmp 1b
|
||||
|
||||
|
||||
.section .ap_init, "ax"
|
||||
|
||||
.code16
|
||||
.global ap_trampoline
|
||||
ap_trampoline:
|
||||
jmp 1f
|
||||
.align 8
|
||||
ap_stack_ptr:
|
||||
.skip 4
|
||||
1:
|
||||
cli; cld
|
||||
ljmpl $0x00, $ap_cs_clear
|
||||
ap_cs_clear:
|
||||
|
||||
# load ap gdt and enter protected mode
|
||||
lgdt ap_gdtr
|
||||
movl %cr0, %eax
|
||||
orb $1, %al
|
||||
movl %eax, %cr0
|
||||
ljmpl $0x08, $ap_protected_mode
|
||||
|
||||
.code32
|
||||
ap_protected_mode:
|
||||
movw $0x10, %ax
|
||||
movw %ax, %ds
|
||||
movw %ax, %ss
|
||||
movw %ax, %es
|
||||
|
||||
movl ap_stack_ptr, %esp
|
||||
movb $1, V2P(g_ap_stack_loaded)
|
||||
|
||||
call V2P(enable_sse)
|
||||
|
||||
call V2P(initialize_paging)
|
||||
|
||||
# load boot gdt and enter long mode
|
||||
lgdt V2P(boot_gdtr)
|
||||
ljmpl $0x08, $ap_flush_gdt
|
||||
|
||||
ap_flush_gdt:
|
||||
# move stack pointer to higher half
|
||||
movl %esp, %esp
|
||||
addl $KERNEL_OFFSET, %esp
|
||||
|
||||
# jump to higher half
|
||||
leal ap_higher_half, %ecx
|
||||
jmp *%ecx
|
||||
|
||||
ap_higher_half:
|
||||
# clear rbp for stacktrace
|
||||
xorl %ebp, %ebp
|
||||
|
||||
1: pause
|
||||
cmpb $0, g_ap_startup_done
|
||||
jz 1b
|
||||
|
||||
lock incb g_ap_running_count
|
||||
|
||||
call ap_main
|
||||
jmp system_halt
|
||||
|
||||
ap_gdt:
|
||||
.quad 0x0000000000000000 # null descriptor
|
||||
.quad 0x00CF9A000000FFFF # 32 bit code
|
||||
.quad 0x00CF92000000FFFF # 32 bit data
|
||||
ap_gdtr:
|
||||
.short . - ap_gdt - 1
|
||||
.long ap_gdt
|
|
@ -1,173 +0,0 @@
|
|||
.macro push_userspace
|
||||
pushw %gs
|
||||
pushw %fs
|
||||
pushw %es
|
||||
pushw %ds
|
||||
pushal
|
||||
.endm
|
||||
|
||||
.macro load_kernel_segments
|
||||
movw $0x10, %ax
|
||||
movw %ax, %ds
|
||||
movw %ax, %es
|
||||
movw %ax, %fs
|
||||
|
||||
movw $0x28, %ax
|
||||
movw %ax, %gs
|
||||
.endm
|
||||
|
||||
.macro pop_userspace
|
||||
popal
|
||||
popw %ds
|
||||
popw %es
|
||||
popw %fs
|
||||
popw %gs
|
||||
.endm
|
||||
|
||||
isr_stub:
|
||||
push_userspace
|
||||
load_kernel_segments
|
||||
|
||||
movl %cr0, %eax; pushl %eax
|
||||
movl %cr2, %eax; pushl %eax
|
||||
movl %cr3, %eax; pushl %eax
|
||||
movl %cr4, %eax; pushl %eax
|
||||
|
||||
movl %esp, %eax // register ptr
|
||||
leal 64(%esp), %ebx // interrupt stack ptr
|
||||
movl 60(%esp), %ecx // error code
|
||||
movl 56(%esp), %edx // isr number
|
||||
|
||||
subl $12, %esp
|
||||
pushl %eax
|
||||
pushl %ebx
|
||||
pushl %ecx
|
||||
pushl %edx
|
||||
call cpp_isr_handler
|
||||
addl $44, %esp
|
||||
|
||||
pop_userspace
|
||||
addl $8, %esp
|
||||
iret
|
||||
|
||||
irq_stub:
|
||||
push_userspace
|
||||
load_kernel_segments
|
||||
|
||||
movl 40(%esp), %eax # interrupt number
|
||||
|
||||
subl $12, %esp
|
||||
pushl %eax
|
||||
call cpp_irq_handler
|
||||
addl $16, %esp
|
||||
|
||||
pop_userspace
|
||||
addl $8, %esp
|
||||
iret
|
||||
|
||||
.global asm_yield_handler
|
||||
asm_yield_handler:
|
||||
# This can only be called from kernel, so no segment saving is needed
|
||||
pushal
|
||||
|
||||
movl %esp, %eax # interrupt registers ptr
|
||||
leal 32(%esp), %ebx # interrupt stack ptr
|
||||
|
||||
subl $4, %esp
|
||||
pushl %eax
|
||||
pushl %ebx
|
||||
call cpp_yield_handler
|
||||
addl $12, %esp
|
||||
|
||||
popal
|
||||
iret
|
||||
|
||||
.macro isr n
|
||||
.global isr\n
|
||||
isr\n:
|
||||
pushl $0
|
||||
pushl $\n
|
||||
jmp isr_stub
|
||||
.endm
|
||||
|
||||
.macro isr_err n
|
||||
.global isr\n
|
||||
isr\n:
|
||||
pushl $\n
|
||||
jmp isr_stub
|
||||
.endm
|
||||
|
||||
.macro irq n
|
||||
.global irq\n
|
||||
irq\n:
|
||||
pushl $0
|
||||
pushl $\n
|
||||
jmp irq_stub
|
||||
.endm
|
||||
|
||||
isr 0
|
||||
isr 1
|
||||
isr 2
|
||||
isr 3
|
||||
isr 4
|
||||
isr 5
|
||||
isr 6
|
||||
isr 7
|
||||
isr_err 8
|
||||
isr 9
|
||||
isr_err 10
|
||||
isr_err 11
|
||||
isr_err 12
|
||||
isr_err 13
|
||||
isr_err 14
|
||||
isr 15
|
||||
isr 16
|
||||
isr_err 17
|
||||
isr 18
|
||||
isr 19
|
||||
isr 20
|
||||
isr 21
|
||||
isr 22
|
||||
isr 23
|
||||
isr 24
|
||||
isr 25
|
||||
isr 26
|
||||
isr 27
|
||||
isr 28
|
||||
isr 29
|
||||
isr 30
|
||||
isr 31
|
||||
|
||||
irq 0
|
||||
irq 1
|
||||
irq 2
|
||||
irq 3
|
||||
irq 4
|
||||
irq 5
|
||||
irq 6
|
||||
irq 7
|
||||
irq 8
|
||||
irq 9
|
||||
irq 10
|
||||
irq 11
|
||||
irq 12
|
||||
irq 13
|
||||
irq 14
|
||||
irq 15
|
||||
irq 16
|
||||
irq 17
|
||||
irq 18
|
||||
irq 19
|
||||
irq 20
|
||||
irq 21
|
||||
irq 22
|
||||
irq 23
|
||||
irq 24
|
||||
irq 25
|
||||
irq 26
|
||||
irq 27
|
||||
irq 28
|
||||
irq 29
|
||||
irq 30
|
||||
irq 31
|
||||
irq 32
|
|
@ -1,45 +0,0 @@
|
|||
ENTRY (_start)
|
||||
|
||||
KERNEL_OFFSET = 0xC0000000;
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
. = 0xF000;
|
||||
.ap_init ALIGN(4K) : AT(ADDR(.ap_init))
|
||||
{
|
||||
g_ap_init_addr = .;
|
||||
*(.ap_init)
|
||||
}
|
||||
|
||||
. = 0x00100000 + KERNEL_OFFSET;
|
||||
|
||||
g_kernel_start = .;
|
||||
.text ALIGN(4K) : AT(ADDR(.text) - KERNEL_OFFSET)
|
||||
{
|
||||
g_kernel_execute_start = .;
|
||||
*(.multiboot)
|
||||
*(.bananboot)
|
||||
*(.text.*)
|
||||
}
|
||||
.userspace ALIGN(4K) : AT(ADDR(.userspace) - KERNEL_OFFSET)
|
||||
{
|
||||
g_userspace_start = .;
|
||||
*(.userspace)
|
||||
g_userspace_end = .;
|
||||
g_kernel_execute_end = .;
|
||||
}
|
||||
.rodata ALIGN(4K) : AT(ADDR(.rodata) - KERNEL_OFFSET)
|
||||
{
|
||||
*(.rodata.*)
|
||||
}
|
||||
.data ALIGN(4K) : AT(ADDR(.data) - KERNEL_OFFSET)
|
||||
{
|
||||
*(.data)
|
||||
}
|
||||
.bss ALIGN(4K) : AT(ADDR(.bss) - KERNEL_OFFSET)
|
||||
{
|
||||
*(COMMON)
|
||||
*(.bss)
|
||||
}
|
||||
g_kernel_end = .;
|
||||
}
|
|
@ -0,0 +1,125 @@
|
|||
#include <BAN/Array.h>
|
||||
#include <kernel/GDT.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
extern "C" uintptr_t g_boot_stack_top[0];
|
||||
|
||||
namespace Kernel::GDT
|
||||
{
|
||||
|
||||
struct TaskStateSegment
|
||||
{
|
||||
uint32_t reserved1;
|
||||
uint64_t rsp0;
|
||||
uint64_t rsp1;
|
||||
uint64_t rsp2;
|
||||
uint64_t reserved2;
|
||||
uint64_t ist1;
|
||||
uint64_t ist2;
|
||||
uint64_t ist3;
|
||||
uint64_t ist4;
|
||||
uint64_t ist5;
|
||||
uint64_t ist6;
|
||||
uint64_t ist7;
|
||||
uint64_t reserved3;
|
||||
uint16_t reserved4;
|
||||
uint16_t iopb;
|
||||
} __attribute__((packed));
|
||||
|
||||
union SegmentDescriptor
|
||||
{
|
||||
struct
|
||||
{
|
||||
uint16_t limit1;
|
||||
uint16_t base1;
|
||||
uint8_t base2;
|
||||
uint8_t access;
|
||||
uint8_t limit2 : 4;
|
||||
uint8_t flags : 4;
|
||||
uint8_t base3;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct
|
||||
{
|
||||
uint32_t low;
|
||||
uint32_t high;
|
||||
} __attribute__((packed));
|
||||
|
||||
} __attribute__((packed));
|
||||
|
||||
struct GDTR
|
||||
{
|
||||
uint16_t size;
|
||||
uint64_t address;
|
||||
} __attribute__((packed));
|
||||
|
||||
static constexpr uint16_t s_tss_offset = 0x28;
|
||||
|
||||
static TaskStateSegment s_tss;
|
||||
static BAN::Array<SegmentDescriptor, 7> s_gdt; // null, kernel code, kernel data, user code, user data, tss low, tss high
|
||||
static GDTR s_gdtr;
|
||||
|
||||
static void write_entry(uint8_t offset, uint32_t base, uint32_t limit, uint8_t access, uint8_t flags)
|
||||
{
|
||||
ASSERT(offset % sizeof(SegmentDescriptor) == 0);
|
||||
|
||||
SegmentDescriptor& desc = s_gdt[offset / sizeof(SegmentDescriptor)];
|
||||
desc.base1 = (base >> 0) & 0xFFFF;
|
||||
desc.base2 = (base >> 16) & 0xFF;
|
||||
desc.base3 = (base >> 24) & 0xFF;
|
||||
|
||||
desc.limit1 = (limit >> 0) & 0xFFFF;
|
||||
desc.limit2 = (limit >> 16) & 0x0F;
|
||||
|
||||
desc.access = access & 0xFF;
|
||||
|
||||
desc.flags = flags & 0x0F;
|
||||
}
|
||||
|
||||
static void write_tss()
|
||||
{
|
||||
memset(&s_tss, 0x00, sizeof(TaskStateSegment));
|
||||
s_tss.iopb = sizeof(TaskStateSegment);
|
||||
|
||||
uint64_t base = (uint64_t)&s_tss;
|
||||
|
||||
write_entry(s_tss_offset, (uint32_t)base, sizeof(TaskStateSegment), 0x89, 0x0);
|
||||
|
||||
SegmentDescriptor& desc = s_gdt[s_tss_offset / sizeof(SegmentDescriptor) + 1];
|
||||
desc.low = base >> 32;
|
||||
desc.high = 0;
|
||||
}
|
||||
|
||||
void set_tss_stack(uintptr_t rsp)
|
||||
{
|
||||
s_tss.rsp0 = rsp;
|
||||
}
|
||||
|
||||
static void flush_gdt()
|
||||
{
|
||||
asm volatile("lgdt %0" :: "m"(s_gdtr));
|
||||
}
|
||||
|
||||
static void flush_tss()
|
||||
{
|
||||
asm volatile("ltr %0" :: "m"(s_tss_offset));
|
||||
}
|
||||
|
||||
void initialize()
|
||||
{
|
||||
s_gdtr.address = (uint64_t)&s_gdt;
|
||||
s_gdtr.size = s_gdt.size() * sizeof(SegmentDescriptor) - 1;
|
||||
|
||||
write_entry(0x00, 0x00000000, 0x00000, 0x00, 0x0); // null
|
||||
write_entry(0x08, 0x00000000, 0xFFFFF, 0x9A, 0xA); // kernel code
|
||||
write_entry(0x10, 0x00000000, 0xFFFFF, 0x92, 0xC); // kernel data
|
||||
write_entry(0x18, 0x00000000, 0xFFFFF, 0xFA, 0xA); // user code
|
||||
write_entry(0x20, 0x00000000, 0xFFFFF, 0xF2, 0xC); // user data
|
||||
write_tss();
|
||||
|
||||
flush_gdt();
|
||||
flush_tss();
|
||||
}
|
||||
|
||||
}
|
|
@ -10,14 +10,16 @@
|
|||
#include <kernel/Timer/PIT.h>
|
||||
|
||||
#define ISR_LIST_X X(0) X(1) X(2) X(3) X(4) X(5) X(6) X(7) X(8) X(9) X(10) X(11) X(12) X(13) X(14) X(15) X(16) X(17) X(18) X(19) X(20) X(21) X(22) X(23) X(24) X(25) X(26) X(27) X(28) X(29) X(30) X(31)
|
||||
#define IRQ_LIST_X X(0) X(1) X(2) X(3) X(4) X(5) X(6) X(7) X(8) X(9) X(10) X(11) X(12) X(13) X(14) X(15) X(16) X(17) X(18) X(19) X(20) X(21) X(22) X(23) X(24) X(25) X(26) X(27) X(28) X(29) X(30) X(31) X(32)
|
||||
#define IRQ_LIST_X X(0) X(1) X(2) X(3) X(4) X(5) X(6) X(7) X(8) X(9) X(10) X(11) X(12) X(13) X(14) X(15) X(16) X(17) X(18) X(19) X(20) X(21) X(22) X(23) X(24) X(25) X(26) X(27) X(28) X(29) X(30) X(31)
|
||||
|
||||
namespace Kernel
|
||||
namespace Kernel::IDT
|
||||
{
|
||||
|
||||
#if ARCH(x86_64)
|
||||
struct Registers
|
||||
{
|
||||
uint64_t rsp;
|
||||
uint64_t rip;
|
||||
uint64_t rflags;
|
||||
uint64_t cr4;
|
||||
uint64_t cr3;
|
||||
uint64_t cr2;
|
||||
|
@ -31,33 +33,34 @@ namespace Kernel
|
|||
uint64_t r10;
|
||||
uint64_t r9;
|
||||
uint64_t r8;
|
||||
|
||||
uint64_t rdi;
|
||||
uint64_t rsi;
|
||||
uint64_t rdi;
|
||||
uint64_t rbp;
|
||||
uint64_t rbx;
|
||||
uint64_t rdx;
|
||||
uint64_t rcx;
|
||||
uint64_t rbx;
|
||||
uint64_t rax;
|
||||
};
|
||||
#elif ARCH(i686)
|
||||
struct Registers
|
||||
{
|
||||
uint32_t cr4;
|
||||
uint32_t cr3;
|
||||
uint32_t cr2;
|
||||
uint32_t cr0;
|
||||
|
||||
uint32_t edi;
|
||||
uint32_t esi;
|
||||
uint32_t ebp;
|
||||
uint32_t unused;
|
||||
uint32_t ebx;
|
||||
uint32_t edx;
|
||||
uint32_t ecx;
|
||||
uint32_t eax;
|
||||
};
|
||||
#endif
|
||||
struct GateDescriptor
|
||||
{
|
||||
uint16_t offset1;
|
||||
uint16_t selector;
|
||||
uint8_t IST;
|
||||
uint8_t flags;
|
||||
uint16_t offset2;
|
||||
uint32_t offset3;
|
||||
uint32_t reserved;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct IDTR
|
||||
{
|
||||
uint16_t size;
|
||||
uint64_t offset;
|
||||
} __attribute__((packed));
|
||||
|
||||
static IDTR s_idtr;
|
||||
static GateDescriptor* s_idt = nullptr;
|
||||
|
||||
#define X(num) 1 +
|
||||
static BAN::Array<Interruptable*, IRQ_LIST_X 0> s_interruptables;
|
||||
|
@ -118,7 +121,7 @@ namespace Kernel
|
|||
uint32_t reserved2 : 16;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
};
|
||||
static_assert(sizeof(PageFaultError) == 4);
|
||||
|
||||
|
@ -158,98 +161,68 @@ namespace Kernel
|
|||
"Unkown Exception 0x1F",
|
||||
};
|
||||
|
||||
extern "C" void cpp_isr_handler(uint32_t isr, uint32_t error, InterruptStack* interrupt_stack, const Registers* regs)
|
||||
extern "C" void cpp_isr_handler(uint64_t isr, uint64_t error, InterruptStack& interrupt_stack, const Registers* regs)
|
||||
{
|
||||
if (g_paniced)
|
||||
{
|
||||
dprintln("Processor {} halted", Processor::current_id());
|
||||
if (InterruptController::is_initialized())
|
||||
InterruptController::get().broadcast_ipi();
|
||||
asm volatile("cli; 1: hlt; jmp 1b");
|
||||
}
|
||||
#if __enable_sse
|
||||
bool from_userspace = (interrupt_stack.cs & 0b11) == 0b11;
|
||||
if (from_userspace)
|
||||
Thread::current().save_sse();
|
||||
#endif
|
||||
|
||||
pid_t tid = Scheduler::current_tid();
|
||||
pid_t pid = tid ? Process::current().pid() : 0;
|
||||
|
||||
if (tid)
|
||||
{
|
||||
Thread::current().set_return_rsp(interrupt_stack.rsp);
|
||||
Thread::current().set_return_rip(interrupt_stack.rip);
|
||||
|
||||
if (isr == ISR::PageFault)
|
||||
{
|
||||
// Check if stack is OOB
|
||||
auto& thread = Thread::current();
|
||||
if (thread.userspace_stack_bottom() < interrupt_stack->sp && interrupt_stack->sp <= thread.userspace_stack_top())
|
||||
; // using userspace stack
|
||||
else if (thread.kernel_stack_bottom() < interrupt_stack->sp && interrupt_stack->sp <= thread.kernel_stack_top())
|
||||
; // using kernel stack
|
||||
auto& stack = Thread::current().stack();
|
||||
auto& istack = Thread::current().interrupt_stack();
|
||||
if (stack.vaddr() < interrupt_stack.rsp && interrupt_stack.rsp <= stack.vaddr() + stack.size())
|
||||
; // using normal stack
|
||||
else if (istack.vaddr() < interrupt_stack.rsp && interrupt_stack.rsp <= istack.vaddr() + istack.size())
|
||||
; // using interrupt stack
|
||||
else
|
||||
{
|
||||
derrorln("Stack pointer out of bounds!");
|
||||
derrorln("rip {H}", interrupt_stack->ip);
|
||||
derrorln("rsp {H}, userspace stack {H}->{H}, kernel stack {H}->{H}",
|
||||
interrupt_stack->sp,
|
||||
thread.userspace_stack_bottom(), thread.userspace_stack_top(),
|
||||
thread.kernel_stack_bottom(), thread.kernel_stack_top()
|
||||
derrorln("rsp {H}, stack {H}->{H}, istack {H}->{H}",
|
||||
interrupt_stack.rsp,
|
||||
stack.vaddr(), stack.vaddr() + stack.size(),
|
||||
istack.vaddr(), istack.vaddr() + istack.size()
|
||||
);
|
||||
Thread::current().handle_signal(SIGKILL);
|
||||
goto done;
|
||||
}
|
||||
|
||||
// Demand paging is only supported in userspace
|
||||
if (thread.is_userspace())
|
||||
// Try demand paging on non present pages
|
||||
PageFaultError page_fault_error;
|
||||
page_fault_error.raw = error;
|
||||
if (!page_fault_error.present)
|
||||
{
|
||||
// Try demand paging on non present pages
|
||||
PageFaultError page_fault_error;
|
||||
page_fault_error.raw = error;
|
||||
if (!page_fault_error.present)
|
||||
asm volatile("sti");
|
||||
auto result = Process::current().allocate_page_for_demand_paging(regs->cr2);
|
||||
asm volatile("cli");
|
||||
|
||||
if (!result.is_error() && result.value())
|
||||
goto done;
|
||||
|
||||
if (result.is_error())
|
||||
{
|
||||
Processor::set_interrupt_state(InterruptState::Enabled);
|
||||
auto result = Process::current().allocate_page_for_demand_paging(regs->cr2);
|
||||
Processor::set_interrupt_state(InterruptState::Disabled);
|
||||
|
||||
if (!result.is_error() && result.value())
|
||||
goto done;
|
||||
|
||||
if (result.is_error())
|
||||
{
|
||||
dwarnln("Demand paging: {}", result.error());
|
||||
Thread::current().handle_signal(SIGKILL);
|
||||
goto done;
|
||||
}
|
||||
dwarnln("Demand paging: {}", result.error());
|
||||
Thread::current().handle_signal(SIGKILL);
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
}
|
||||
#if __enable_sse
|
||||
else if (isr == ISR::DeviceNotAvailable)
|
||||
{
|
||||
#if ARCH(x86_64)
|
||||
asm volatile(
|
||||
"movq %cr0, %rax;"
|
||||
"andq $~(1 << 3), %rax;"
|
||||
"movq %rax, %cr0;"
|
||||
);
|
||||
#elif ARCH(i686)
|
||||
asm volatile(
|
||||
"movl %cr0, %eax;"
|
||||
"andl $~(1 << 3), %eax;"
|
||||
"movl %eax, %cr0;"
|
||||
);
|
||||
#endif
|
||||
if (auto* current = &Thread::current(); current != Thread::sse_thread())
|
||||
{
|
||||
if (auto* sse = Thread::sse_thread())
|
||||
sse->save_sse();
|
||||
current->load_sse();
|
||||
}
|
||||
goto done;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
Debug::s_debug_lock.lock();
|
||||
|
||||
if (PageTable::current().get_page_flags(interrupt_stack->ip & PAGE_ADDR_MASK) & PageTable::Flags::Present)
|
||||
if (PageTable::current().get_page_flags(interrupt_stack.rip & PAGE_ADDR_MASK) & PageTable::Flags::Present)
|
||||
{
|
||||
auto* machine_code = (const uint8_t*)interrupt_stack->ip;
|
||||
auto* machine_code = (const uint8_t*)interrupt_stack.rip;
|
||||
dwarnln("While executing: {2H}{2H}{2H}{2H}{2H}{2H}{2H}{2H}",
|
||||
machine_code[0],
|
||||
machine_code[1],
|
||||
|
@ -262,9 +235,8 @@ namespace Kernel
|
|||
);
|
||||
}
|
||||
|
||||
#if ARCH(x86_64)
|
||||
dwarnln(
|
||||
"{} (error code: 0x{8H}), pid {}, tid {}\r\n"
|
||||
"{} (error code: 0x{16H}), pid {}, tid {}\r\n"
|
||||
"Register dump\r\n"
|
||||
"rax=0x{16H}, rbx=0x{16H}, rcx=0x{16H}, rdx=0x{16H}\r\n"
|
||||
"rsp=0x{16H}, rbp=0x{16H}, rdi=0x{16H}, rsi=0x{16H}\r\n"
|
||||
|
@ -272,31 +244,14 @@ namespace Kernel
|
|||
"cr0=0x{16H}, cr2=0x{16H}, cr3=0x{16H}, cr4=0x{16H}",
|
||||
isr_exceptions[isr], error, pid, tid,
|
||||
regs->rax, regs->rbx, regs->rcx, regs->rdx,
|
||||
interrupt_stack->sp, regs->rbp, regs->rdi, regs->rsi,
|
||||
interrupt_stack->ip, interrupt_stack->flags,
|
||||
regs->rsp, regs->rbp, regs->rdi, regs->rsi,
|
||||
regs->rip, regs->rflags,
|
||||
regs->cr0, regs->cr2, regs->cr3, regs->cr4
|
||||
);
|
||||
#elif ARCH(i686)
|
||||
dwarnln(
|
||||
"{} (error code: 0x{8H}), pid {}, tid {}\r\n"
|
||||
"Register dump\r\n"
|
||||
"eax=0x{8H}, ebx=0x{8H}, ecx=0x{8H}, edx=0x{8H}\r\n"
|
||||
"esp=0x{8H}, ebp=0x{8H}, edi=0x{8H}, esi=0x{8H}\r\n"
|
||||
"eip=0x{8H}, eflags=0x{8H}\r\n"
|
||||
"cr0=0x{8H}, cr2=0x{8H}, cr3=0x{8H}, cr4=0x{8H}",
|
||||
isr_exceptions[isr], error, pid, tid,
|
||||
regs->eax, regs->ebx, regs->ecx, regs->edx,
|
||||
interrupt_stack->sp, regs->ebp, regs->edi, regs->esi,
|
||||
interrupt_stack->ip, interrupt_stack->flags,
|
||||
regs->cr0, regs->cr2, regs->cr3, regs->cr4
|
||||
);
|
||||
#endif
|
||||
if (isr == ISR::PageFault)
|
||||
PageTable::current().debug_dump();
|
||||
Debug::dump_stack_trace();
|
||||
|
||||
Debug::s_debug_lock.unlock(InterruptState::Disabled);
|
||||
|
||||
if (tid && Thread::current().is_userspace())
|
||||
{
|
||||
// TODO: Confirm and fix the exception to signal mappings
|
||||
|
@ -304,6 +259,7 @@ namespace Kernel
|
|||
int signal = 0;
|
||||
switch (isr)
|
||||
{
|
||||
case ISR::DeviceNotAvailable:
|
||||
case ISR::DivisionError:
|
||||
case ISR::SIMDFloatingPointException:
|
||||
case ISR::x87FloatingPointException:
|
||||
|
@ -317,7 +273,7 @@ namespace Kernel
|
|||
break;
|
||||
case ISR::PageFault:
|
||||
signal = SIGSEGV;
|
||||
break;
|
||||
break;
|
||||
default:
|
||||
dwarnln("Unhandled exception");
|
||||
signal = SIGABRT;
|
||||
|
@ -332,29 +288,30 @@ namespace Kernel
|
|||
}
|
||||
|
||||
ASSERT(Thread::current().state() != Thread::State::Terminated);
|
||||
|
||||
|
||||
done:
|
||||
#if __enable_sse
|
||||
if (from_userspace)
|
||||
{
|
||||
ASSERT(Thread::current().state() == Thread::State::Executing);
|
||||
Thread::current().load_sse();
|
||||
}
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
extern "C" void cpp_yield_handler(InterruptStack* interrupt_stack, InterruptRegisters* interrupt_registers)
|
||||
extern "C" void cpp_irq_handler(uint64_t irq, InterruptStack& interrupt_stack)
|
||||
{
|
||||
ASSERT(!InterruptController::get().is_in_service(IRQ_YIELD));
|
||||
ASSERT(!GDT::is_user_segment(interrupt_stack->cs));
|
||||
#if __enable_sse
|
||||
bool from_userspace = (interrupt_stack.cs & 0b11) == 0b11;
|
||||
if (from_userspace)
|
||||
Thread::current().save_sse();
|
||||
#endif
|
||||
|
||||
Processor::enter_interrupt(interrupt_stack, interrupt_registers);
|
||||
Scheduler::get().irq_reschedule();
|
||||
Processor::leave_interrupt();
|
||||
}
|
||||
|
||||
extern "C" void cpp_irq_handler(uint32_t irq)
|
||||
{
|
||||
if (g_paniced)
|
||||
if (Scheduler::current_tid())
|
||||
{
|
||||
dprintln("Processor {} halted", Processor::current_id());
|
||||
if (InterruptController::is_initialized())
|
||||
InterruptController::get().broadcast_ipi();
|
||||
asm volatile("cli; 1: hlt; jmp 1b");
|
||||
Thread::current().set_return_rsp(interrupt_stack.rsp);
|
||||
Thread::current().set_return_rip(interrupt_stack.rip);
|
||||
}
|
||||
|
||||
if (!InterruptController::get().is_in_service(irq))
|
||||
|
@ -362,45 +319,49 @@ done:
|
|||
else
|
||||
{
|
||||
InterruptController::get().eoi(irq);
|
||||
if (auto* handler = s_interruptables[irq])
|
||||
handler->handle_irq();
|
||||
else if (irq == IRQ_IPI)
|
||||
Scheduler::get().yield();
|
||||
if (s_interruptables[irq])
|
||||
s_interruptables[irq]->handle_irq();
|
||||
else
|
||||
dprintln("no handler for irq 0x{2H}", irq);
|
||||
dprintln("no handler for irq 0x{2H}\n", irq);
|
||||
}
|
||||
|
||||
auto& current_thread = Thread::current();
|
||||
if (current_thread.can_add_signal_to_execute())
|
||||
current_thread.handle_signal();
|
||||
|
||||
Scheduler::get().reschedule_if_idling();
|
||||
|
||||
ASSERT(Thread::current().state() != Thread::State::Terminated);
|
||||
}
|
||||
|
||||
void IDT::register_interrupt_handler(uint8_t index, void (*handler)())
|
||||
{
|
||||
auto& desc = m_idt[index];
|
||||
memset(&desc, 0, sizeof(GateDescriptor));
|
||||
|
||||
desc.offset0 = (uint16_t)((uintptr_t)handler >> 0);
|
||||
desc.offset1 = (uint16_t)((uintptr_t)handler >> 16);
|
||||
#if ARCH(x86_64)
|
||||
desc.offset2 = (uint32_t)((uintptr_t)handler >> 32);
|
||||
#if __enable_sse
|
||||
if (from_userspace)
|
||||
{
|
||||
ASSERT(Thread::current().state() == Thread::State::Executing);
|
||||
Thread::current().load_sse();
|
||||
}
|
||||
#endif
|
||||
|
||||
desc.selector = 0x08;
|
||||
desc.flags = 0x8E;
|
||||
}
|
||||
|
||||
void IDT::register_syscall_handler(uint8_t index, void (*handler)())
|
||||
static void flush_idt()
|
||||
{
|
||||
asm volatile("lidt %0"::"m"(s_idtr));
|
||||
}
|
||||
|
||||
static void register_interrupt_handler(uint8_t index, void(*handler)())
|
||||
{
|
||||
GateDescriptor& descriptor = s_idt[index];
|
||||
descriptor.offset1 = (uint16_t)((uint64_t)handler >> 0);
|
||||
descriptor.offset2 = (uint16_t)((uint64_t)handler >> 16);
|
||||
descriptor.offset3 = (uint32_t)((uint64_t)handler >> 32);
|
||||
|
||||
descriptor.selector = 0x08;
|
||||
descriptor.IST = 0;
|
||||
descriptor.flags = 0x8E;
|
||||
}
|
||||
|
||||
static void register_syscall_handler(uint8_t index, void(*handler)())
|
||||
{
|
||||
register_interrupt_handler(index, handler);
|
||||
m_idt[index].flags = 0xEE;
|
||||
s_idt[index].flags = 0xEE;
|
||||
}
|
||||
|
||||
void IDT::register_irq_handler(uint8_t irq, Interruptable* interruptable)
|
||||
void register_irq_handler(uint8_t irq, Interruptable* interruptable)
|
||||
{
|
||||
if (irq > s_interruptables.size())
|
||||
Kernel::panic("Trying to assign handler for irq {} while only {} are supported", irq, s_interruptables.size());
|
||||
|
@ -415,37 +376,36 @@ done:
|
|||
IRQ_LIST_X
|
||||
#undef X
|
||||
|
||||
extern "C" void asm_yield_handler();
|
||||
extern "C" void asm_syscall_handler();
|
||||
extern "C" void syscall_asm();
|
||||
|
||||
IDT* IDT::create()
|
||||
void initialize()
|
||||
{
|
||||
auto* idt = new IDT();
|
||||
ASSERT(idt);
|
||||
s_idt = (GateDescriptor*)kmalloc(0x100 * sizeof(GateDescriptor));
|
||||
ASSERT(s_idt);
|
||||
memset(s_idt, 0x00, 0x100 * sizeof(GateDescriptor));
|
||||
|
||||
memset(idt->m_idt.data(), 0x00, 0x100 * sizeof(GateDescriptor));
|
||||
s_idtr.offset = (uint64_t)s_idt;
|
||||
s_idtr.size = 0x100 * sizeof(GateDescriptor) - 1;
|
||||
|
||||
#define X(num) idt->register_interrupt_handler(num, isr ## num);
|
||||
#define X(num) register_interrupt_handler(num, isr ## num);
|
||||
ISR_LIST_X
|
||||
#undef X
|
||||
|
||||
#define X(num) idt->register_interrupt_handler(IRQ_VECTOR_BASE + num, irq ## num);
|
||||
#define X(num) register_interrupt_handler(IRQ_VECTOR_BASE + num, irq ## num);
|
||||
IRQ_LIST_X
|
||||
#undef X
|
||||
|
||||
idt->register_interrupt_handler(IRQ_VECTOR_BASE + IRQ_YIELD, asm_yield_handler);
|
||||
register_syscall_handler(0x80, syscall_asm);
|
||||
|
||||
idt->register_syscall_handler(0x80, asm_syscall_handler);
|
||||
|
||||
return idt;
|
||||
flush_idt();
|
||||
}
|
||||
|
||||
[[noreturn]] void IDT::force_triple_fault()
|
||||
[[noreturn]] void force_triple_fault()
|
||||
{
|
||||
// load 0 sized IDT and trigger an interrupt to force triple fault
|
||||
Processor::set_interrupt_state(InterruptState::Disabled);
|
||||
Processor::idt().m_idtr.size = 0;
|
||||
Processor::idt().load();
|
||||
asm volatile("cli");
|
||||
s_idtr.size = 0;
|
||||
flush_idt();
|
||||
asm volatile("int $0x00");
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
#include <kernel/Arch.h>
|
||||
#include <kernel/CPUID.h>
|
||||
#include <kernel/InterruptController.h>
|
||||
#include <kernel/Lock/SpinLock.h>
|
||||
#include <kernel/LockGuard.h>
|
||||
#include <kernel/Memory/kmalloc.h>
|
||||
#include <kernel/Memory/PageTable.h>
|
||||
|
||||
|
@ -17,9 +17,8 @@ extern uint8_t g_userspace_end[];
|
|||
namespace Kernel
|
||||
{
|
||||
|
||||
SpinLock PageTable::s_fast_page_lock;
|
||||
|
||||
static PageTable* s_kernel = nullptr;
|
||||
static PageTable* s_current = nullptr;
|
||||
static bool s_has_nxe = false;
|
||||
static bool s_has_pge = false;
|
||||
|
||||
|
@ -70,51 +69,40 @@ namespace Kernel
|
|||
void PageTable::initialize()
|
||||
{
|
||||
if (CPUID::has_nxe())
|
||||
{
|
||||
asm volatile(
|
||||
"movl $0xC0000080, %ecx;"
|
||||
"rdmsr;"
|
||||
"orl $0x800, %eax;"
|
||||
"wrmsr"
|
||||
);
|
||||
s_has_nxe = true;
|
||||
}
|
||||
|
||||
if (CPUID::has_pge())
|
||||
uint32_t ecx, edx;
|
||||
CPUID::get_features(ecx, edx);
|
||||
if (edx & CPUID::EDX_PGE)
|
||||
{
|
||||
asm volatile(
|
||||
"movq %cr4, %rax;"
|
||||
"orq $0x80, %rax;"
|
||||
"movq %rax, %cr4;"
|
||||
);
|
||||
s_has_pge = true;
|
||||
}
|
||||
|
||||
// enable write protect to kernel
|
||||
asm volatile(
|
||||
"movq %cr0, %rax;"
|
||||
"orq $0x10000, %rax;"
|
||||
"movq %rax, %cr0;"
|
||||
);
|
||||
|
||||
ASSERT(s_kernel == nullptr);
|
||||
s_kernel = new PageTable();
|
||||
ASSERT(s_kernel);
|
||||
|
||||
s_kernel->initialize_kernel();
|
||||
s_kernel->initial_load();
|
||||
}
|
||||
|
||||
void PageTable::initial_load()
|
||||
{
|
||||
if (s_has_nxe)
|
||||
{
|
||||
asm volatile(
|
||||
"movl $0xC0000080, %%ecx;"
|
||||
"rdmsr;"
|
||||
"orl $0x800, %%eax;"
|
||||
"wrmsr"
|
||||
::: "eax", "ecx", "edx", "memory"
|
||||
);
|
||||
}
|
||||
|
||||
if (s_has_pge)
|
||||
{
|
||||
asm volatile(
|
||||
"movq %%cr4, %%rax;"
|
||||
"orq $0x80, %%rax;"
|
||||
"movq %%rax, %%cr4;"
|
||||
::: "rax"
|
||||
);
|
||||
}
|
||||
|
||||
// enable write protect
|
||||
asm volatile(
|
||||
"movq %%cr0, %%rax;"
|
||||
"orq $0x10000, %%rax;"
|
||||
"movq %%rax, %%cr0;"
|
||||
::: "rax"
|
||||
);
|
||||
|
||||
load();
|
||||
s_kernel->load();
|
||||
}
|
||||
|
||||
PageTable& PageTable::kernel()
|
||||
|
@ -123,6 +111,12 @@ namespace Kernel
|
|||
return *s_kernel;
|
||||
}
|
||||
|
||||
PageTable& PageTable::current()
|
||||
{
|
||||
ASSERT(s_current);
|
||||
return *s_current;
|
||||
}
|
||||
|
||||
bool PageTable::is_valid_pointer(uintptr_t pointer)
|
||||
{
|
||||
if (!is_canonical(pointer))
|
||||
|
@ -144,7 +138,7 @@ namespace Kernel
|
|||
s_global_pml4e = V2P(allocate_zeroed_page_aligned_page());
|
||||
|
||||
m_highest_paging_struct = V2P(allocate_zeroed_page_aligned_page());
|
||||
|
||||
|
||||
uint64_t* pml4 = (uint64_t*)P2V(m_highest_paging_struct);
|
||||
pml4[511] = s_global_pml4e;
|
||||
|
||||
|
@ -212,9 +206,8 @@ namespace Kernel
|
|||
void PageTable::map_fast_page(paddr_t paddr)
|
||||
{
|
||||
ASSERT(s_kernel);
|
||||
ASSERT(paddr);
|
||||
|
||||
ASSERT(s_fast_page_lock.current_processor_has_lock());
|
||||
ASSERT_NEQ(paddr, 0);
|
||||
ASSERT(!interrupts_enabled());
|
||||
|
||||
constexpr vaddr_t uc_vaddr = uncanonicalize(fast_page());
|
||||
constexpr uint64_t pml4e = (uc_vaddr >> 39) & 0x1FF;
|
||||
|
@ -236,8 +229,7 @@ namespace Kernel
|
|||
void PageTable::unmap_fast_page()
|
||||
{
|
||||
ASSERT(s_kernel);
|
||||
|
||||
ASSERT(s_fast_page_lock.current_processor_has_lock());
|
||||
ASSERT(!interrupts_enabled());
|
||||
|
||||
constexpr vaddr_t uc_vaddr = uncanonicalize(fast_page());
|
||||
constexpr uint64_t pml4e = (uc_vaddr >> 39) & 0x1FF;
|
||||
|
@ -258,7 +250,7 @@ namespace Kernel
|
|||
|
||||
BAN::ErrorOr<PageTable*> PageTable::create_userspace()
|
||||
{
|
||||
SpinLockGuard _(s_kernel->m_lock);
|
||||
LockGuard _(s_kernel->m_lock);
|
||||
PageTable* page_table = new PageTable;
|
||||
if (page_table == nullptr)
|
||||
return BAN::Error::from_errno(ENOMEM);
|
||||
|
@ -310,9 +302,8 @@ namespace Kernel
|
|||
|
||||
void PageTable::load()
|
||||
{
|
||||
SpinLockGuard _(m_lock);
|
||||
asm volatile("movq %0, %%cr3" :: "r"(m_highest_paging_struct));
|
||||
Processor::set_current_page_table(this);
|
||||
s_current = this;
|
||||
}
|
||||
|
||||
void PageTable::invalidate(vaddr_t vaddr)
|
||||
|
@ -326,7 +317,7 @@ namespace Kernel
|
|||
ASSERT(vaddr);
|
||||
ASSERT(vaddr != fast_page());
|
||||
if (vaddr >= KERNEL_OFFSET)
|
||||
ASSERT(vaddr >= (vaddr_t)g_kernel_start);
|
||||
ASSERT_GTE(vaddr, (vaddr_t)g_kernel_start);
|
||||
if ((vaddr >= KERNEL_OFFSET) != (this == s_kernel))
|
||||
Kernel::panic("unmapping {8H}, kernel: {}", vaddr, this == s_kernel);
|
||||
|
||||
|
@ -340,7 +331,7 @@ namespace Kernel
|
|||
uint64_t pde = (uc_vaddr >> 21) & 0x1FF;
|
||||
uint64_t pte = (uc_vaddr >> 12) & 0x1FF;
|
||||
|
||||
SpinLockGuard _(m_lock);
|
||||
LockGuard _(m_lock);
|
||||
|
||||
if (is_page_free(vaddr))
|
||||
{
|
||||
|
@ -362,7 +353,7 @@ namespace Kernel
|
|||
vaddr_t s_page = vaddr / PAGE_SIZE;
|
||||
vaddr_t e_page = BAN::Math::div_round_up<vaddr_t>(vaddr + size, PAGE_SIZE);
|
||||
|
||||
SpinLockGuard _(m_lock);
|
||||
LockGuard _(m_lock);
|
||||
for (vaddr_t page = s_page; page < e_page; page++)
|
||||
unmap_page(page * PAGE_SIZE);
|
||||
}
|
||||
|
@ -371,6 +362,8 @@ namespace Kernel
|
|||
{
|
||||
ASSERT(vaddr);
|
||||
ASSERT(vaddr != fast_page());
|
||||
if (vaddr >= KERNEL_OFFSET && s_current)
|
||||
ASSERT_GTE(vaddr, (vaddr_t)g_kernel_start);
|
||||
if ((vaddr >= KERNEL_OFFSET) != (this == s_kernel))
|
||||
Kernel::panic("mapping {8H} to {8H}, kernel: {}", paddr, vaddr, this == s_kernel);
|
||||
|
||||
|
@ -399,7 +392,7 @@ namespace Kernel
|
|||
// NOTE: we add present here, since it has to be available in higher level structures
|
||||
flags_t uwr_flags = (flags & (Flags::UserSupervisor | Flags::ReadWrite)) | Flags::Present;
|
||||
|
||||
SpinLockGuard _(m_lock);
|
||||
LockGuard _(m_lock);
|
||||
|
||||
uint64_t* pml4 = (uint64_t*)P2V(m_highest_paging_struct);
|
||||
if ((pml4[pml4e] & uwr_flags) != uwr_flags)
|
||||
|
@ -443,8 +436,8 @@ namespace Kernel
|
|||
ASSERT(vaddr % PAGE_SIZE == 0);
|
||||
|
||||
size_t page_count = range_page_count(vaddr, size);
|
||||
|
||||
SpinLockGuard _(m_lock);
|
||||
|
||||
LockGuard _(m_lock);
|
||||
for (size_t page = 0; page < page_count; page++)
|
||||
map_page_at(paddr + page * PAGE_SIZE, vaddr + page * PAGE_SIZE, flags);
|
||||
}
|
||||
|
@ -460,8 +453,8 @@ namespace Kernel
|
|||
uint64_t pdpte = (uc_vaddr >> 30) & 0x1FF;
|
||||
uint64_t pde = (uc_vaddr >> 21) & 0x1FF;
|
||||
uint64_t pte = (uc_vaddr >> 12) & 0x1FF;
|
||||
|
||||
SpinLockGuard _(m_lock);
|
||||
|
||||
LockGuard _(m_lock);
|
||||
|
||||
uint64_t* pml4 = (uint64_t*)P2V(m_highest_paging_struct);
|
||||
if (!(pml4[pml4e] & Flags::Present))
|
||||
|
@ -495,7 +488,7 @@ namespace Kernel
|
|||
|
||||
bool PageTable::reserve_page(vaddr_t vaddr, bool only_free)
|
||||
{
|
||||
SpinLockGuard _(m_lock);
|
||||
LockGuard _(m_lock);
|
||||
ASSERT(vaddr % PAGE_SIZE == 0);
|
||||
if (only_free && !is_page_free(vaddr))
|
||||
return false;
|
||||
|
@ -509,7 +502,7 @@ namespace Kernel
|
|||
bytes += PAGE_SIZE - rem;
|
||||
ASSERT(vaddr % PAGE_SIZE == 0);
|
||||
|
||||
SpinLockGuard _(m_lock);
|
||||
LockGuard _(m_lock);
|
||||
if (only_free && !is_range_free(vaddr, bytes))
|
||||
return false;
|
||||
for (size_t offset = 0; offset < bytes; offset += PAGE_SIZE)
|
||||
|
@ -540,8 +533,8 @@ namespace Kernel
|
|||
const uint16_t e_pdpte = (uc_vaddr_end >> 30) & 0x1FF;
|
||||
const uint16_t e_pde = (uc_vaddr_end >> 21) & 0x1FF;
|
||||
const uint16_t e_pte = (uc_vaddr_end >> 12) & 0x1FF;
|
||||
|
||||
SpinLockGuard _(m_lock);
|
||||
|
||||
LockGuard _(m_lock);
|
||||
|
||||
// Try to find free page that can be mapped without
|
||||
// allocations (page table with unused entries)
|
||||
|
@ -614,7 +607,7 @@ namespace Kernel
|
|||
ASSERT(is_canonical(first_address));
|
||||
ASSERT(is_canonical(last_address));
|
||||
|
||||
SpinLockGuard _(m_lock);
|
||||
LockGuard _(m_lock);
|
||||
|
||||
for (vaddr_t vaddr = first_address; vaddr < last_address;)
|
||||
{
|
||||
|
@ -655,7 +648,7 @@ namespace Kernel
|
|||
vaddr_t s_page = vaddr / PAGE_SIZE;
|
||||
vaddr_t e_page = BAN::Math::div_round_up<vaddr_t>(vaddr + size, PAGE_SIZE);
|
||||
|
||||
SpinLockGuard _(m_lock);
|
||||
LockGuard _(m_lock);
|
||||
for (vaddr_t page = s_page; page < e_page; page++)
|
||||
if (!is_page_free(page * PAGE_SIZE))
|
||||
return false;
|
||||
|
@ -678,7 +671,7 @@ namespace Kernel
|
|||
|
||||
void PageTable::debug_dump()
|
||||
{
|
||||
SpinLockGuard _(m_lock);
|
||||
LockGuard _(m_lock);
|
||||
|
||||
flags_t flags = 0;
|
||||
vaddr_t start = 0;
|
||||
|
@ -721,7 +714,7 @@ namespace Kernel
|
|||
|
||||
if (!(pt[pte] & Flags::Used))
|
||||
continue;
|
||||
|
||||
|
||||
if (start == 0)
|
||||
{
|
||||
flags = parse_flags(pt[pte]);
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue