Compare commits
247 Commits
Author | SHA1 | Date | |
---|---|---|---|
ecc9c8b28b | |||
|
cfb49c7316 | ||
|
a3fad2e171 | ||
|
dd5db8484a | ||
|
5affd51250 | ||
|
ce27b5ebce | ||
|
fce9cd8c22 | ||
|
8faa916d93 | ||
|
e52802162c | ||
|
f3ec246b67 | ||
|
434c9ceb5d | ||
|
c3fb81d1a1 | ||
|
c340f57207 | ||
|
bbe1bf9c3a | ||
|
accda1211b | ||
|
daee1f4cb8 | ||
|
87cb10c558 | ||
|
904651ada9 | ||
|
1d3ce93107 | ||
|
103dcdeea8 | ||
|
f77531138a | ||
|
c8b3b060aa | ||
|
7780ee6a34 | ||
|
2e2625e952 | ||
|
55c3eb7c14 | ||
|
a7a9855493 | ||
|
5eaaee0dbe | ||
|
b2bc718c1f | ||
|
7118ad494c | ||
|
582e0e718c | ||
|
1713583a19 | ||
|
38aef49428 | ||
|
a9caf3fbe4 | ||
|
80ff844dc2 | ||
|
c53be5a3fb | ||
|
6addd6cf1e | ||
|
3995d2f4a2 | ||
|
b95dc611d6 | ||
|
4cccf74664 | ||
|
8cc48d5688 | ||
|
b76bd57ed1 | ||
|
2afc218767 | ||
|
5bbaa30655 | ||
|
5440cd4b50 | ||
|
e686ff78e9 | ||
|
2bd77722c7 | ||
|
00f69bc70d | ||
|
d1609e771a | ||
|
89f813f113 | ||
|
9b0fbf000e | ||
|
725d16e18e | ||
|
e42a205a51 | ||
|
0d5f185267 | ||
|
c146a215fb | ||
|
eef7b5e168 | ||
|
a753b6ce46 | ||
|
793e12f8f3 | ||
|
751e6430fa | ||
|
9eb20c2be7 | ||
|
5e460394d2 | ||
|
88043e144a | ||
|
3cc7774fe4 | ||
|
a04243aaf4 | ||
|
5a95183c3e | ||
|
6a5aa18a7b | ||
|
4b3c40f35b | ||
|
79fba6c2ac | ||
|
4f217b19a9 | ||
|
202333c881 | ||
|
2ce0395fd8 | ||
bbdf181828 | |||
|
0181c6025a | ||
|
6eff83c1eb | ||
|
5aae0f2379 | ||
|
49ae4a834f | ||
|
5b650434b0 | ||
|
e612f7cd7d | ||
|
7cc4aa2a28 | ||
|
60f5d0e34a | ||
|
46c5a90ba1 | ||
|
1273c573b6 | ||
|
3a2895af19 | ||
|
0bffac6c98 | ||
|
c25de5dba3 | ||
|
60edfa4d77 | ||
|
52e582132f | ||
|
a888041ba4 | ||
|
844af06782 | ||
|
7da3404bd0 | ||
|
7676f47540 | ||
|
9d7a58f6a7 | ||
|
9bd3d2aa5c | ||
|
28e782dda5 | ||
|
597098845c | ||
|
8a7deae238 | ||
|
73f2c7043c | ||
|
de24035066 | ||
|
57ea1dbdd3 | ||
|
9f73f09cec | ||
|
d56b21d329 | ||
|
8d60bc11b5 | ||
|
604f4c666b | ||
|
ff5175ec76 | ||
|
6aebd5dd95 | ||
|
3d4bed3374 | ||
|
ee7a77643e | ||
|
646d6c368c | ||
|
d96e14fe16 | ||
|
3a9d450106 | ||
|
a73ef9fc06 | ||
|
3016b64fac | ||
|
22498e0b09 | ||
|
79dff674fd | ||
|
56ef7ca9e7 | ||
|
9db50753f1 | ||
|
e84e1bbf36 | ||
|
fda337a1c0 | ||
|
f49f91da08 | ||
|
90535a1401 | ||
|
43719b5fd1 | ||
|
2a94f8cdb4 | ||
|
1e578f1a50 | ||
|
a036d2373a | ||
|
a2b303e95a | ||
|
7b964fa700 | ||
|
72f5f9d133 | ||
|
186a6bc080 | ||
|
567d9f7910 | ||
|
d70cf314d8 | ||
|
c6445da654 | ||
|
96cde52838 | ||
|
c67a0d3dd8 | ||
|
78c0e5f6b6 | ||
|
f82e7df0ba | ||
|
640a001ab6 | ||
|
c5c5f8754c | ||
|
5be3bf4f26 | ||
|
d132fc0a73 | ||
|
285a33c97d | ||
|
f09ac23144 | ||
|
734752d6b5 | ||
|
4fc6c4ff5c | ||
|
746d373362 | ||
|
2256f5fb4b | ||
|
d8e2c95597 | ||
|
6506240642 | ||
|
bd284347da | ||
|
3813f9772a | ||
|
1902d1a06b | ||
|
7ecabb25eb | ||
|
5b633a83df | ||
|
beb8bf498c | ||
|
de764d8490 | ||
|
5635c1318c | ||
|
01713c74f9 | ||
|
9ec66f0594 | ||
|
6947bddd3f | ||
|
37ec636018 | ||
|
9bba6613e7 | ||
|
d4f246517c | ||
|
5bfebe7a3f | ||
|
3df67362b4 | ||
|
f1042e7fb1 | ||
|
b29112efdf | ||
|
fe899eecc7 | ||
|
c2a2ec121f | ||
|
e1e1fa23b7 | ||
|
aee8d35dc4 | ||
|
4bbbf5d2e3 | ||
|
ba7e832c5d | ||
|
bbfc092a31 | ||
|
de52cf1cdd | ||
|
783c05fd6c | ||
|
6ae98e2e6d | ||
|
ffc099eb54 | ||
|
9321067b68 | ||
|
0eaa1f7a08 | ||
|
18f90ca1e3 | ||
|
9a35743df6 | ||
|
8d63a3c1f3 | ||
|
1ac33caa90 | ||
|
1c361bf545 | ||
|
a41dd48986 | ||
|
b931b67cba | ||
|
24435e9ca1 | ||
|
e54ff599ca | ||
|
04969b6be0 | ||
|
1ddf1dbc25 | ||
|
8699f5592f | ||
|
73d089da36 | ||
|
c8cd09e72c | ||
|
be1ef01f10 | ||
|
0a1bc1f4b7 | ||
|
bcb7f45201 | ||
|
33db0e0d4d | ||
|
504539ad1e | ||
|
a62fce8dc5 | ||
|
81a78cf1d0 | ||
|
283135c9cd | ||
|
22d4d5c1c1 | ||
|
9c372c36c1 | ||
|
9767c4db0e | ||
|
9812799b24 | ||
|
d385749ead | ||
|
23ed5d3936 | ||
|
cebc963396 | ||
|
0c8ec41c21 | ||
|
9f7b8c1a17 | ||
|
cd92b32622 | ||
|
5853a68904 | ||
|
ae64830bd5 | ||
|
e8878eee8a | ||
|
3897ddea03 | ||
|
6858270517 | ||
|
4e57b6eceb | ||
|
298f317f44 | ||
|
5820ad8309 | ||
|
b7fbe65ff2 | ||
|
d1cf216384 | ||
|
3011dc5876 | ||
|
6e99f00f5c | ||
|
beb1e084a6 | ||
|
e34b443c29 | ||
|
6b17bb647e | ||
|
4299b85cdb | ||
|
6dae147785 | ||
|
e4255e4c8b | ||
|
161274f785 | ||
|
6145cdcf37 | ||
|
b57a4c98cf | ||
a3e43aca87 | |||
|
6b6915e304 | ||
|
3f83ac5580 | ||
7f57de1b74 | |||
648382db74 | |||
2c510bb7f9 | |||
23710dff5e | |||
ff0436357b | |||
091e5157aa | |||
|
c1e181a407 | ||
|
8f71c90ca8 | ||
|
f85ec313de | ||
|
2aa6471608 | ||
|
9814fc5447 | ||
|
3655ea77a3 | ||
|
89d35bc41e | ||
|
93639532f0 |
|
@ -12,19 +12,19 @@ sCaRvwPZdRCDDdhObkgkMlYROVNdC7ju8jZmB4n5O/5N7Ll7/RVhUWD7KeJu1UTM
|
||||||
oNEmhxEMrEcYcHFt8N8YVtJleRMVnsrZBNxOkFnpsPZr02XIQKfYi5tqSaBQZ47h
|
oNEmhxEMrEcYcHFt8N8YVtJleRMVnsrZBNxOkFnpsPZr02XIQKfYi5tqSaBQZ47h
|
||||||
TTtXP3+FEaU+EoJprWqH55Sh97Fg6vuBJEmcGJeMGudFrypTzwqnM22DHwARAQAB
|
TTtXP3+FEaU+EoJprWqH55Sh97Fg6vuBJEmcGJeMGudFrypTzwqnM22DHwARAQAB
|
||||||
tCdKb3NlZiBTw7ZudGdlbiA8Y251a2VAZGVwb3QuZ2Vub2RlLm9yZz6JAlQEEwEI
|
tCdKb3NlZiBTw7ZudGdlbiA8Y251a2VAZGVwb3QuZ2Vub2RlLm9yZz6JAlQEEwEI
|
||||||
AD4WIQSFq6G0496kOfRE2qnpSz5BlOa1+AUCWpAOsgIbAwUJA8JnAAULCQgHAgYV
|
AD4CGwMFCwkIBwIGFQgJCgsCBBYCAwECHgECF4AWIQSFq6G0496kOfRE2qnpSz5B
|
||||||
CAkKCwIEFgIDAQIeAQIXgAAKCRDpSz5BlOa1+NGTEACg69FezAbc9Rzeb7j66NwW
|
lOa1+AUCXk6dFAUJB4D1YgAKCRDpSz5BlOa1+JHXEACyB6vfzfuyo8fu1IaGrloC
|
||||||
3x/Zpi/jbmezMEtCZqAOcR8HJ7C0DN8gmCWPPB6oxAEeyL/i2cUb+9F0fTD6N7OL
|
qUUuSfhdleF1tPhZQn9W92bEEoXPfqFUuiNaxeFIXonyiD7wJYdcowdIb6CiNWrx
|
||||||
TSOH75mNlyB9b8D2HdDILnLy4ClEitEOHFLMnlP58PGVtUNgbmsiM6cLLQtlJKvg
|
B8yjDQ7yb08sDLlL821I93kByy24Er5hY3QEMuEL3qv8YD/6Bh36Q0aoTXqQXMuQ
|
||||||
1xHlBTG9Ic8qgBcd808lLSC1XWN+nufVYBTE2RHNZqGeIWqPG5z1eW/JJO4M3V3j
|
3AcHp0JI932Oez3q+gEdW7CUe40N9LaTx0A7ZTHe0i8IELkUPFtDg8xibOjZhBMR
|
||||||
MAw1p5Rpf9G6iWNxURutQOl/ii+97IKmHXX7N6ZRzawMGkOCAGNk1xeI71wCrALv
|
vlxNUtzQVvC5kT5Wt0w6ZFKPGJguFylaE+TcsTNtiLNS4Z8PmRPgygrWotmprELo
|
||||||
i3m7NmXb6XIJjD88hO5xfjjRO/0Gcw3vdmTXcVNzM1TvWj8ZsU6XjnMvNxa4LHqh
|
2/py/VMxgQb7p4LFj+sNmU9x3ulFO3Efb9cVZVjBMYx5xh83ZiLZ3PvK43Eo+7nm
|
||||||
MxWuHlX0cAeCOzo1LJZ54f13hJ3YlTCrv68UIoNGRVi1LEbpE0sU0Ycdbw7ur2Gt
|
kYQhPinAjNmqng4/ZdQFrayFMkZc4oKCqV6BaYnybbsSn2ZEwVQqpDMeswWXTf9k
|
||||||
8Brx5WXv3hXTL8s3fmJzYU3/cFDfXjnaRiMWcNYdvckdHy6R7zPTk1NOvmfkolnO
|
qC6DONz3ETtyzBEF8cHDpy+BwHRXx+pysGLhIvHS9C3M91j8oXvogZRbw/dEKGX2
|
||||||
W73ivdbonXpn0YqRGo2L76GdahLaVYn2gEeisqHnyeBCvI2snI+dMlEK0YNFrEkP
|
eWes7nsdHeTbyRJunCCnsXDm0Js8cZcqj3Eu3Kpeu2CbgJGD+ajOel2RSMo2mFtg
|
||||||
wgtWnF131Oorn0HMS6mpjcq4su4s5d84KCMGevFnW69oBRG27Bk/fJQiv2dSqkZg
|
OoRWjCibWHDSeUS+LGtspDpry+4VYwm4KBdcyEgiXnE8WDb/xk/hZgJCr2814AJC
|
||||||
+3TnyNApg1G7Bp5uD83mOvJWKdTWAntCJSQGbg1dmEsOBG+Bu7EE5LVBoMH3h/LQ
|
RPpXoIZdFiwSP46vgoAnHynPbGTmE/Wt+F9Y2cn/dz6rmg5ynS8AKuTOUSoAKEUV
|
||||||
GB7c5NpgNIFQ2DZy2vkOI7kCDQRakA6yARAAws48PKN3BQPEM0M4kTO57/OqwGrA
|
J20mBJpkSx7Cc95AGE8K/LkCDQRakA6yARAAws48PKN3BQPEM0M4kTO57/OqwGrA
|
||||||
AMlxnB3n+AP7rtZEC2L548+3pfg7Ub45Oq1X0ySxgPhV15CDUEK69pgs0JhphMbM
|
AMlxnB3n+AP7rtZEC2L548+3pfg7Ub45Oq1X0ySxgPhV15CDUEK69pgs0JhphMbM
|
||||||
DyaUp04DyQWFhdueAqQVFnKvg6nZm/WIJF1VYEc0/q6Ramsdv2cWdxFBkFHYsH3P
|
DyaUp04DyQWFhdueAqQVFnKvg6nZm/WIJF1VYEc0/q6Ramsdv2cWdxFBkFHYsH3P
|
||||||
G2bXCZZAEO6eJI8cdmBH6+bVptky/AybzBLztp1ruWlj+rm79qULmW7zJfxYwL1U
|
G2bXCZZAEO6eJI8cdmBH6+bVptky/AybzBLztp1ruWlj+rm79qULmW7zJfxYwL1U
|
||||||
|
@ -35,18 +35,18 @@ kAVN0Y0H9EGSEoVyKwS1DErzcBgajPKWedKlmjU1uIzupRWn5oqetVbNfZ3Z/EJ/
|
||||||
HdMCX0PN1kxg4WoI9mkP/moly1yopVOTTLJwvC2C85NQUmxyZeb4h9O7toFczBxn
|
HdMCX0PN1kxg4WoI9mkP/moly1yopVOTTLJwvC2C85NQUmxyZeb4h9O7toFczBxn
|
||||||
7pV9Eprm/xRcO3ZEEpmdM7gR3+R3PpxkjgPIZAn9il32VYzdT3eQmDZ8sKC0qASG
|
7pV9Eprm/xRcO3ZEEpmdM7gR3+R3PpxkjgPIZAn9il32VYzdT3eQmDZ8sKC0qASG
|
||||||
ik2if34YnAggGmsrVB0nzT9fZR7CQq2IR7eohczLJRl+n7USQMgRweF+sl9PcbDT
|
ik2if34YnAggGmsrVB0nzT9fZR7CQq2IR7eohczLJRl+n7USQMgRweF+sl9PcbDT
|
||||||
aC0b0i+VveSEBOEAEQEAAYkCPAQYAQgAJhYhBIWrobTj3qQ59ETaqelLPkGU5rX4
|
aC0b0i+VveSEBOEAEQEAAYkCPAQYAQgAJgIbDBYhBIWrobTj3qQ59ETaqelLPkGU
|
||||||
BQJakA6yAhsMBQkDwmcAAAoJEOlLPkGU5rX4QjEQAIJF78XjvGomhafMsWlcd7fP
|
5rX4BQJeTp05BQkHgPWHAAoJEOlLPkGU5rX4RRAQAKSsr//mEXy6iQyoqaxJ796s
|
||||||
/j45B+KIpyruc7wHtLqWibi+YoDuvtG4m1/4Ckcz5qNrV0f5nQojEAeCSCh7Sl+s
|
ljaoqsmT4ly/+0k9diX1+/wkulSkj4/fL2fDvRQK2cU1i6mYJVugN5swqXvp8WF8
|
||||||
yAJ9tmP1XET29DJq1t0iMsu+RDCLhdOfL/Wi/YJARtDloYbDlD8Rc/JnL2aOx2W/
|
scnDS/H75v/3Z+clTlsMjZ4qI0PmXYDpcvp5+zU85USEjOxpHmIKvQGflZ0NMvkI
|
||||||
Ybajj2lloxSDxKCnzCh1aZixie1YaQSm8ErshT2k4qTx48D3mRoBLAYyzdEbLkl3
|
uo2ZC6F4xnB5iizx9Ebm0gGAiKKEJ8ID/LLhJmOtidnGc3322SUVXIl4+ue9KgpO
|
||||||
ZBGDQy3Xk/miJ/hsj6L3w3G2YjMywZZZEjgDSUgSJ6MazBTgMmbCy1/0YGh7rNF7
|
hTBjx5UdIQ+21uSRf+zv3ZQH/KA/08iNyD20fIiUZKfEoeovlW8SipoO/pf/+1DE
|
||||||
iUoWyDZq4qiDGNAI695I6tas7s4X2dhZn10xgbJoa5Dq2rqQLek+ErEsr3DFYN53
|
WSiJqL3K7T3ixkC4oWSp7tbo2MWU247PItxTnnGF+KjwbkzpPwyPYPHT5Ed3XEZV
|
||||||
7e9H0vJ9ydXB7piRJ9bxVFBng5CX9677IN5k9T/0lvcZWAFnDcHiMkIjIrTQ1Y04
|
e39r9xUzdvYKKDCNDToDFsh4bm4hq7xXgnTwAbF6hw0iyBK02ZB6FKJsF/ZJi8gC
|
||||||
WkG6DMVvzLD+PKA07cZLf692rsrbfpP4sGj8X6baWh58mGAMMwZ2Dy07grsi73qI
|
Ni4d3Lb54CV/Z7nAqMFbTa6KT8o9fc0Bw6tgX2ch7SRWU70yVGYmQzrdRsOtDkIV
|
||||||
p/H4r4c/xRsH6nTbvb40zLfqcCz1xOTEcDtflYGMoeshu/H2EoruNMFi3c/9WO2G
|
iYA05JozwwsIcJQS7hBVnsqgD/huYLd+y7iCUgw35NdQ5764jzVlUpYtFO0NFrM6
|
||||||
3zrSOUenWFSiacbsh8HVE9HUFGddBTB3SrLddO5vvvi15OvGI4aWpnkW+9s4107h
|
QSKnnFFRiwr3+ZqIja2SGW455uP1hsl2ccA4Rdp/JRuEI6ojIo0R+JBpcMeqdv9d
|
||||||
jE0d0+c/Xm4AS0T59OGj/cd45k/vRe5vaPhQobZ6hXBzkKWPVt5uH8xbROiGiqdR
|
HcNsAoZkrm/cQfIwlyKsU4/dEFL09kEtv7x/aO2ImqjAZ5xT3ml+4kFGEn7M7rsc
|
||||||
jMuaeWIldeJ60aeu39Dh
|
M6R6fgkYrVo1GhjXTlCL
|
||||||
=JE0L
|
=4bj4
|
||||||
-----END PGP PUBLIC KEY BLOCK-----
|
-----END PGP PUBLIC KEY BLOCK-----
|
||||||
|
|
|
@ -6,26 +6,26 @@ spm0DdNCEVfUbIQUstbSNt1kDGIlqPvZmoRj5YwDECW6ULG8jTWhaAz9SybJCE86
|
||||||
jLPzZHjKtVhCVO1X0ogSxvvYGemUpqVCLfKcIb1TucieKKCrnjiHwp0XZ41DWqSb
|
jLPzZHjKtVhCVO1X0ogSxvvYGemUpqVCLfKcIb1TucieKKCrnjiHwp0XZ41DWqSb
|
||||||
kBwWW2YQMEsw8JNGNTfCCUFf6+1l4mMixtv2sEqFiH1wQJ0c4gSa4iSYZ+eNmzJ0
|
kBwWW2YQMEsw8JNGNTfCCUFf6+1l4mMixtv2sEqFiH1wQJ0c4gSa4iSYZ+eNmzJ0
|
||||||
B13K8kONOctSg3NYZz/dC1aUzLOTkgJHqEPHABEBAAG0KVN0ZWZhbiBLYWxrb3dz
|
B13K8kONOctSg3NYZz/dC1aUzLOTkgJHqEPHABEBAAG0KVN0ZWZhbiBLYWxrb3dz
|
||||||
a2kgPHNrYWxrQGRlcG90Lmdlbm9kZS5vcmc+iQFUBBMBCAA+FiEEI2X1/oP+p+Ls
|
a2kgPHNrYWxrQGRlcG90Lmdlbm9kZS5vcmc+iQFUBBMBCAA+AhsDBQsJCAcCBhUI
|
||||||
2L28qrC4CLnp/P8FAlrQZGACGwMFCQPCZwAFCwkIBwIGFQgJCgsCBBYCAwECHgEC
|
CQoLAgQWAgMBAh4BAheAFiEEI2X1/oP+p+Ls2L28qrC4CLnp/P8FAl4XHPUFCQ0p
|
||||||
F4AACgkQqrC4CLnp/P9kKQgAxc11eDhYkMVg9cuipFoqtV5lY9aT2qkocZ28IhbF
|
OkcACgkQqrC4CLnp/P8bAgf/ToUKzXMGdRXpB+xIBbOxuu8xVdLRj+5cm7cjZRiy
|
||||||
LXhy9lcn5FlxZSVdkzJQ5tUf4nSuhhMb6z3r8edaOebcYAyFk0DTymNpcEyT2XHd
|
N0ulrzAlaZqrfqb5rTujPDjakmVSBVRIi8zWlzU7y67fevTFdi/Q9xeLgbqP3cWU
|
||||||
lsOcInhfU423m1tCNHdmxtv9HERtj2zS1KNkjWxY6xsqfEw1eDfUvdS3K9KpUqc6
|
UgUJs03cdacFIamSIO//I9gaImZ2kpUcA6Nj+N+jPepRgUBzljsJG8678ndicA0e
|
||||||
vWZwsPd9EHxW3mzWJS3lrSAnNsCwtdmiqB9045Yss4KednMcN6qxE+uHppQ+25Ib
|
Yio4uAvZY9JmsWGn48rmkqshPf9lag4GUnXn+R/AFKCts55kOiPekux3pJBhmrLJ
|
||||||
5ZICpiVqOJ+eQXeY3kRx84lfZJr3uFdn00RSU5fn0uol8ZZYX9tQd9SC1GIlkyYj
|
TdLgdAzlzGQfHxQbz3oVK4yE19ReAd6rnpW06oK4KfiWrgCmaEk1quirDNfIMDfr
|
||||||
HxNLKNVaYzF1nnmR1s7cpY6PUAYbt0im6kd4VJ1wQcWTnrkBDQRaU+QuAQgAuame
|
nwe6571TY5is0f9zJjJgP8ogLUMI3n54OvwMezUMz+bLbbkBDQRaU+QuAQgAuame
|
||||||
2VDCgNmiwu+QmWyNN4jzbE7+VNmDr37HO9lZRIROC4eACPOGfUL03jLGvUn7rrxQ
|
2VDCgNmiwu+QmWyNN4jzbE7+VNmDr37HO9lZRIROC4eACPOGfUL03jLGvUn7rrxQ
|
||||||
JK+Pit6gXXCoIWDhCMNRSZKho416KJZWxF2jxKBKGQ7DtWaTR3YOzSf0ka9DZSrp
|
JK+Pit6gXXCoIWDhCMNRSZKho416KJZWxF2jxKBKGQ7DtWaTR3YOzSf0ka9DZSrp
|
||||||
wG22xS0Uf1U/0ZBIf24LbyUDFLc8zt4eey2D9AHm+9vCf7wnf8TV6SNIXRz3wj7d
|
wG22xS0Uf1U/0ZBIf24LbyUDFLc8zt4eey2D9AHm+9vCf7wnf8TV6SNIXRz3wj7d
|
||||||
VqoZLXRTT7twBSaNahLhNtg7fhS8Nu6/THuwXpNKPAvAsgJRTGk7kmrKj5P7rOZA
|
VqoZLXRTT7twBSaNahLhNtg7fhS8Nu6/THuwXpNKPAvAsgJRTGk7kmrKj5P7rOZA
|
||||||
rNHC1pvK1EWJJi2onHOmCzBccKRp9SeQlj+ddqG6seZhEnRYG6l7uhkyNZoyvKxO
|
rNHC1pvK1EWJJi2onHOmCzBccKRp9SeQlj+ddqG6seZhEnRYG6l7uhkyNZoyvKxO
|
||||||
Fguc5g8Xf37VyuRMfwARAQABiQE8BBgBCAAmFiEEI2X1/oP+p+Ls2L28qrC4CLnp
|
Fguc5g8Xf37VyuRMfwARAQABiQE8BBgBCAAmAhsMFiEEI2X1/oP+p+Ls2L28qrC4
|
||||||
/P8FAlpT5C4CGwwFCQPCZwAACgkQqrC4CLnp/P/IOAf+LnQVtU7aHh4AZDsi1wXq
|
CLnp/P8FAl4XHW4FCQ0pOsAACgkQqrC4CLnp/P/xGggAhMz6NH1dYiFtc9+3vkAW
|
||||||
KBo5l6r3G8tC/S0HEf8nnWMUio2/mwVrkbuTvBeKrcQ/mXFHHAG8YCAIHPgR7T0y
|
bZ10MDvxdgyU+G1a0BVYVo2ZXkhJlb2yg5MEeL1MZ6cUtM7MR1OL0U1jayfdcTfr
|
||||||
2L6l2PL4HoXiLD8EwJ0sWZu2waxuxcTX+bb1i3Xm3squnqDtCX3pyoXWx0GVgrz9
|
kkUi2a35BdvKRpxc3hcc4i2CdDxdx+IGrBa75P+vIKFj8WIvwABgRJNVzY1Oq6Lq
|
||||||
7I/zitxeER+35ScaZ+JAAcNW59LpiV1SdIXqbtrw5QBJBuZUp0bvnzCNvdZLhnhb
|
zKPUpVPug80Hch++Kv6l1DEpcoXlGaI8Z1dWfAjYQ7HJF/YJNHloKwxa1mXo/l/S
|
||||||
gWfwPEfcXFt5K87iTmfMFJOJpbUrEz/NWE9gOBCBjqxW0wVb+IWr0oFWvfxjuBq7
|
qQSFHB23IN682ANm8iEUphuvJVbOw4mubpCEpmJvIhEBeesgXfB503nniOsshq+9
|
||||||
IW9DezwkN1wAavP6g7+B4esCD6SRq+3CCzbT1By3X2h3SevU8tHkCSA3cIKgWdyD
|
1bNZ3CFv/ylnj5sy5VzU0lfW/TrHiW4OOOSbX8mCSvcqN2mhjcu6r4olV0fWPrrV
|
||||||
2A==
|
Lg==
|
||||||
=IsaH
|
=H+8g
|
||||||
-----END PGP PUBLIC KEY BLOCK-----
|
-----END PGP PUBLIC KEY BLOCK-----
|
||||||
|
|
60
doc/news.txt
60
doc/news.txt
|
@ -3,6 +3,66 @@
|
||||||
Genode News
|
Genode News
|
||||||
===========
|
===========
|
||||||
|
|
||||||
|
|
||||||
|
Genode OS Framework release 20.02 | 2020-02-28
|
||||||
|
##############################################
|
||||||
|
|
||||||
|
| With version 20.02, Genode makes Sculpt OS fit for running on i.MX 64-bit
|
||||||
|
| ARM hardware, optimizes the performance throughout the entire software stack,
|
||||||
|
| and takes the next evolutionary step of the user-facing side of Sculpt OS.
|
||||||
|
|
||||||
|
Without any doubt, Sculpt OS has been the driving motivation behind most
|
||||||
|
working topics featured by the new release. One particularly exciting line
|
||||||
|
of work is the enabling of Sculpt on i.MX-based 64-bit ARM hardware, which
|
||||||
|
touched the framework on all levels, from the boot loader, over the kernel,
|
||||||
|
device drivers, libraries, system management, up to the application level.
|
||||||
|
The work goes as far as supporting Sculpt OS as a hypervisor platform for
|
||||||
|
hosting Linux in a virtual machine.
|
||||||
|
|
||||||
|
As a second Sculpt-related development, we strive to make the user-visible
|
||||||
|
side of the operating system better approachable and more logical. With this
|
||||||
|
background, the current release comes with a profound redesign of the
|
||||||
|
administrative user interface of Sculpt OS. An updated downloadable system
|
||||||
|
image will follow soon.
|
||||||
|
|
||||||
|
Also related to Sculpt are an updated audio driver based on OpenBSD 6.6,
|
||||||
|
the support of virtual desktops, and performance optimization of the
|
||||||
|
Seoul virtual machine monitor on x86 hardware.
|
||||||
|
|
||||||
|
Regarding the framework API, the release introduces a new library for
|
||||||
|
building multi-component applications. It aims to bring the benefits of
|
||||||
|
Genode's unique security architecture from the operating-system level to the
|
||||||
|
application level.
|
||||||
|
|
||||||
|
These topics are only the tip of the iceberg. For the complete picture,
|
||||||
|
please consult the
|
||||||
|
[https:/documentation/release-notes/20.02 - release documentation of version 20.02...]
|
||||||
|
|
||||||
|
|
||||||
|
Road Map for 2020 | 2020-01-20
|
||||||
|
##############################
|
||||||
|
|
||||||
|
| In 2019, we will be concerned about dwarfing the barrier of entry into
|
||||||
|
| the Genode world.
|
||||||
|
|
||||||
|
Following the last year's leitmotif of "bridging worlds", we turn our
|
||||||
|
attention to the removal of the hurdles faced by aspiring developers and
|
||||||
|
users. During the annual road-map
|
||||||
|
[https://lists.genode.org/pipermail/users/2019-December/006987.html - discussion]
|
||||||
|
on our mailing list, we identified four tangible approaches towards that
|
||||||
|
goal. First, making Sculpt OS more user friendly. Second, reinforcing trust in
|
||||||
|
Genode by fostering the framework's high quality. Third, making the tooling
|
||||||
|
around Genode a joy to use. And finally, the illustration of Genode's
|
||||||
|
versatility in the form practical use cases.
|
||||||
|
|
||||||
|
Besides this overall theme, we plan to continue our commitment to the
|
||||||
|
NXP i.MX SoC family, revisit Genode's low-latency audio support, and
|
||||||
|
extend the cultivation of Ada/SPARK within (and on top of) Genode.
|
||||||
|
|
||||||
|
More background information about the new road map and a rough schedule are
|
||||||
|
presented at our official [https:/about/road-map - road-map page].
|
||||||
|
|
||||||
|
|
||||||
Genode OS Framework release 19.11 | 2019-11-28
|
Genode OS Framework release 19.11 | 2019-11-28
|
||||||
##############################################
|
##############################################
|
||||||
|
|
||||||
|
|
814
doc/release_notes-20-02.txt
Normal file
814
doc/release_notes-20-02.txt
Normal file
|
@ -0,0 +1,814 @@
|
||||||
|
|
||||||
|
|
||||||
|
===============================================
|
||||||
|
Release notes for the Genode OS Framework 20.02
|
||||||
|
===============================================
|
||||||
|
|
||||||
|
Genode Labs
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
This year's [https://genode.org/about/road-map - road map] is all about making
|
||||||
|
Genode and Sculpt OS more approachable. It turns out that the first release of
|
||||||
|
the year already pays tribute to that goal. First, it equips Sculpt OS with a
|
||||||
|
much more logical and welcoming graphical user interface
|
||||||
|
(Section [Redesign of the administrative user interface of Sculpt OS]).
|
||||||
|
Second, it greatly reduces the friction when hosting existing applications on
|
||||||
|
Genode by smoothening several rough edges with respect to POSIX compatibility,
|
||||||
|
and by generally improving performance.
|
||||||
|
|
||||||
|
Most topics of the release are closely related to Sculpt. The biggest
|
||||||
|
break-though is certainly the ability of running Sculpt OS on 64-bit ARM
|
||||||
|
hardware (Section [Sculpt OS on 64-bit ARM i.MX8 hardware]) along with our
|
||||||
|
custom virtual machine monitor (VMM). On PC hardware, Sculpt users can enjoy
|
||||||
|
an updated audio driver and optimizations of the Seoul VMM. Furthermore,
|
||||||
|
Sculpt's window manager received the much anticipated ability to use virtual
|
||||||
|
desktops.
|
||||||
|
|
||||||
|
At the framework-API level, the most significant changes are the introduction
|
||||||
|
of dedicated types for inter-thread synchronization patterns
|
||||||
|
(Section [Base-framework refinements]) and a new library for
|
||||||
|
bringing the benefits of the Genode architecture to the application level
|
||||||
|
(Section [New sandbox library based on the init component]).
|
||||||
|
|
||||||
|
|
||||||
|
Redesign of the administrative user interface of Sculpt OS
|
||||||
|
##########################################################
|
||||||
|
|
||||||
|
On our [https://genode.org/about/road-map - road map] for 2020, we stated
|
||||||
|
the dwarfing of the barrier of entry as our main concern of the year.
|
||||||
|
We highlighted the ease of use of Sculpt OS as one particular work area.
|
||||||
|
|
||||||
|
|
||||||
|
Removing Unix from the picture
|
||||||
|
------------------------------
|
||||||
|
|
||||||
|
Until now, Sculpt's administrative user interface - lyrically called
|
||||||
|
Leitzentrale - employed a small Unix runtime and the Vim editor as utility for
|
||||||
|
basic file operations and for the tweaking of configurations. Even though this
|
||||||
|
was a practical intermediate solution, we have to face the fact that not
|
||||||
|
everyone loves the Unix command-line interface as much as we do. Quite the
|
||||||
|
opposite, actually. When presenting Sculpt, we can clearly sense that people
|
||||||
|
with a non-Unix background are put off by it. The audience generally loves the
|
||||||
|
runtime graph, visual cues, and discoverability. Furthermore, command-line
|
||||||
|
interfaces are (albeit wrongly) perceived as archaic and impenetrable relics
|
||||||
|
by many computer users who are otherwise perfectly happy with the notion of
|
||||||
|
files and directories. We identified that file-manipulation tasks performed in
|
||||||
|
the Leitzentrale are rare and simple. Relying on Unix for those basic tasks is
|
||||||
|
like taking a sledgehammer to crack a nut. On average, the Leitzentrale is
|
||||||
|
used in just a few moments a day for basic things like browsing a file-system
|
||||||
|
hierarchy, glimpsing at the reports stored on the report file system, deleting
|
||||||
|
or copying a file or two, or tweaking a configuration file. With a Unix shell
|
||||||
|
presenting one barrier, Vim is certainly an even higher one. Familiarity with
|
||||||
|
Vim should definitely not be a prerequisite for using an operating system.
|
||||||
|
Following this reasoning, we decided to swap out the command-line interface
|
||||||
|
and Vim by a simple GUI-based file browser and a notepad-like editor, which do
|
||||||
|
not require any learning curve.
|
||||||
|
|
||||||
|
Note that even once the Unix command-line interface is removed from Sculpt's
|
||||||
|
Leitzentrale, advanced users will still be able to manipulate Sculpt's config
|
||||||
|
file system via a Unix runtime deployed as a regular component, similar to the
|
||||||
|
use of the noux-system package we have today.
|
||||||
|
|
||||||
|
|
||||||
|
New user-interface layout
|
||||||
|
-------------------------
|
||||||
|
|
||||||
|
The move away from the command-line interface goes hand in hand with the
|
||||||
|
redesign of the overall user-interface layout. A new panel at the top of the
|
||||||
|
screen contains two centered tabs for switching between the runtime graph and
|
||||||
|
the file-system browser.
|
||||||
|
|
||||||
|
[image sculpt_20.02_panel]
|
||||||
|
|
||||||
|
The storage-management functionality has been moved from the former storage
|
||||||
|
dialog into the respective nodes of the runtime graph. E.g., to format a block
|
||||||
|
device, the user can now select a USB or storage node of the graph to get a
|
||||||
|
menu of block-device-level operations.
|
||||||
|
|
||||||
|
[image sculpt_20.02_storage]
|
||||||
|
|
||||||
|
The network-management is now located at a drop-down menu that can be toggled
|
||||||
|
via a button at the right side of the panel.
|
||||||
|
|
||||||
|
[image sculpt_20.02_network]
|
||||||
|
|
||||||
|
A new button on the left side of the panel allows the user to toggle a
|
||||||
|
drop-down menu for GUI settings. At the current time, there is only the option
|
||||||
|
to adjust the font size. In the future, the dialog will give easy access to
|
||||||
|
the screen-resolution options and the keyboard layout.
|
||||||
|
|
||||||
|
The log-message view is now hidden in another drop-down menu that can be
|
||||||
|
toggled via a panel button. So when starting the system, the user is greeted
|
||||||
|
with only the runtime graph, which is a much nicer and cleaner looking
|
||||||
|
experience.
|
||||||
|
|
||||||
|
Informative or diagnostic messages are displayed in the left-bottom corner of
|
||||||
|
the screen.
|
||||||
|
|
||||||
|
[image sculpt_20.02_message]
|
||||||
|
|
||||||
|
The "Files" tab of the panel switches the main screen area to a simple file
|
||||||
|
browser that lists all file systems available. By toggling one of the
|
||||||
|
file-system buttons, the directory hierarchy can be browsed. When hovering
|
||||||
|
a file, an "Edit" or "View" button appears, which can be used to open
|
||||||
|
the file in a text area that appears on the right side of the file browser.
|
||||||
|
The editor supports the usual notepad-like motions, operations, and
|
||||||
|
shortcuts (control-c for copy, control-v for paste, control-s for save).
|
||||||
|
|
||||||
|
[image sculpt_20.02_editor]
|
||||||
|
|
||||||
|
|
||||||
|
Half-way there
|
||||||
|
--------------
|
||||||
|
|
||||||
|
With the current release, one can already accomplish a lot without having to
|
||||||
|
resort to a command-line interface: connecting to the network, managing
|
||||||
|
storage devices, installing and deploying software, inspecting the system
|
||||||
|
state, and tweaking configurations.
|
||||||
|
|
||||||
|
There are still a few gaps though. In particular the file browser does
|
||||||
|
not yet support file operations like the copying, renaming, or removal of
|
||||||
|
files. For these tasks, the current version of Sculpt still features the
|
||||||
|
Unix-based inspect window, which can be accessed by toggling the "Inspect"
|
||||||
|
button inside the USB or storage dialog. Once selected, the panel presents an
|
||||||
|
"Inspect" tab that features the familiar Unix shell and Vim. Note, however,
|
||||||
|
that we keep the inspect window only as an interim solution. It will
|
||||||
|
eventually be removed. As with every new feature, there are still rough edges
|
||||||
|
to be expected in the editor and file browser, e.g., the editing of files with
|
||||||
|
long lines or the browsing of directories with many entries is not
|
||||||
|
appropriately covered yet.
|
||||||
|
|
||||||
|
To see the current new version of Sculpt OS in action, you may find the
|
||||||
|
following presentation entertaining.
|
||||||
|
|
||||||
|
:Live demonstration of Sculpt OS at FOSDEM 2020:
|
||||||
|
|
||||||
|
[https://fosdem.org/2020/schedule/event/uk_sculpt/]
|
||||||
|
|
||||||
|
The new version 20.02 of Sculpt OS is part of this release and can be built
|
||||||
|
from source and used right now. Several Genode developers already provide
|
||||||
|
ready-to-use packages for the new version. The software depots by alex-ab,
|
||||||
|
cnuke, skalk are worth exploring. A downloadable system image along with an
|
||||||
|
updated manual will be released shortly.
|
||||||
|
|
||||||
|
|
||||||
|
Sculpt OS on 64-bit ARM i.MX8 hardware
|
||||||
|
######################################
|
||||||
|
|
||||||
|
Within the past two releases, big steps were taken to support ARMv8 hardware in
|
||||||
|
the Genode OS framework. After implementing basic support for Raspberry Pi 3,
|
||||||
|
and the i.MX 8M Evaluation Kit, the network card was enabled for the latter.
|
||||||
|
Moreover, we updated the Linux TCP/IP, and C library ports, as well as
|
||||||
|
the Noux environment to support the architecture. Finally, with the latest
|
||||||
|
releases, a new ARMv8-compliant virtual-machine monitor for the base-hw kernel
|
||||||
|
entered the framework.
|
||||||
|
|
||||||
|
The rapid achievements motivated us to strive for a more ambitious scenario to
|
||||||
|
run on top of the currently focused ARMv8 hardware platform. So why not using
|
||||||
|
Sculpt OS on the i.MX 8M System-on-Chip?
|
||||||
|
|
||||||
|
|
||||||
|
Persistent storage
|
||||||
|
==================
|
||||||
|
|
||||||
|
There were several challenges to cope with initially. First, persistent
|
||||||
|
storage was needed. Luckily, the Genode OS framework contained already an
|
||||||
|
SD-card driver implementation for the i.MX series. The driver was written for
|
||||||
|
Genode from scratch and initially supported the i.MX53 SoC only. From then, it
|
||||||
|
got extended repeatedly to drive the SD-card controller of several i.MX6 and
|
||||||
|
i.MX7 platforms. Therefore, it was not a big issue to support the new hardware
|
||||||
|
too. However, when we later used it in Sculpt, it turned out that the driver
|
||||||
|
has some low-latency requirements. If those were not met, it got stuck. This
|
||||||
|
was the time where the CPU-quota mechanism came in handy in a real-world
|
||||||
|
scenario. It helped to let the interrupt handler of the driver be scheduled in
|
||||||
|
time, and thereby let the driver run stable.
|
||||||
|
|
||||||
|
Having a working block device is one part, but it is of little use without a
|
||||||
|
file system. In Sculpt OS, the NetBSD rump kernel's ext2 file-system is
|
||||||
|
typically used to host the depot package system and for keeping configuration
|
||||||
|
files persistent. Unfortunately, the version of NetBSD as used in Genode's
|
||||||
|
rump kernel port does not contain the ARMv8 architecture. Of course, we could
|
||||||
|
have upgraded the rump kernel as a whole. But this software stack is quite
|
||||||
|
complex with a lot of threads reproducing a sophisticated state machine. It
|
||||||
|
took some time in the past to meet its required semantics. Therefore,
|
||||||
|
backporting some header definitions and a few architecture-dependent functions
|
||||||
|
seemed more attractive. Luckily, it turned out to be the right decision, and
|
||||||
|
after a day of backporting work, the file system could run on ARMv8.
|
||||||
|
|
||||||
|
Display engine
|
||||||
|
==============
|
||||||
|
|
||||||
|
One of the more challenging tasks was certainly the enabling of the Display
|
||||||
|
Controller Subsystem (DCSS) of the i.MX 8M SoC. Originally, we hoped to profit
|
||||||
|
from our experiences with the Image Processing Unit (IPU), the display engine
|
||||||
|
of former i.MX SoCs. But as it turned out, the DCSS is a completely new
|
||||||
|
design, and has not much in common with the IPU. When first writing a driver
|
||||||
|
for the IPU of the i.MX53, we were surprised by the complexity and flexibility
|
||||||
|
of this piece of hardware. Back then, it took months to get something
|
||||||
|
meaningful working. To not lose too much time by re-implementing a driver from
|
||||||
|
scratch, we decided to take the DDE Linux approach, which worked out pretty
|
||||||
|
fast. The resulting driver should provide the same flexibility like the Linux
|
||||||
|
original one. However, as the i.MX 8M EVK board provides a HDMI connector
|
||||||
|
only, we did not test more than that. The configuration of the driver is
|
||||||
|
analogous to the Intel framebuffer driver, and looks like the following:
|
||||||
|
|
||||||
|
! <config>
|
||||||
|
! <connector name="HDMI-A-1" width="1920" height="1080" hz="60" enabled="true"/>
|
||||||
|
! </config>
|
||||||
|
|
||||||
|
Later, when using the driver in practice within the Sculpt OS, we could
|
||||||
|
experience a slightly sluggish behaviour, which was due to a missing
|
||||||
|
architectural back end of the blitting library of Genode. After tweaking this
|
||||||
|
too, the graphical user interface experience was good.
|
||||||
|
|
||||||
|
|
||||||
|
USB and Input
|
||||||
|
=============
|
||||||
|
|
||||||
|
The last missing I/O device to run Sculpt OS on the ARMv8 was something for
|
||||||
|
user generated input. Therefore, the existent USB host controller driver for
|
||||||
|
the i.MX series got updated. The only roadblock here was the powering of the
|
||||||
|
device. As there is no platform driver for the target hardware yet, which
|
||||||
|
would manage power and clocks, the hardware either has to be pre-configured
|
||||||
|
correctly, or the driver has to enable it on its own. Ethernet card, SD-card,
|
||||||
|
and the display engine were all already powered by the bootloader, but not
|
||||||
|
USB. In contrast to the first devices, the u-boot bootloader turns off USB
|
||||||
|
explicitly as soon as it starts the OS. As an interim solution, we patched
|
||||||
|
u-boot to not turn off the USB host controller, and enforced u-boot to
|
||||||
|
initialize the powering in our boot scripts. Therefore, if one wants to use
|
||||||
|
USB on the i.MX 8M EVK, make sure to take our modified version. As a
|
||||||
|
convenient solution, you can use the 'uboot' port within the base repository.
|
||||||
|
Just issue the following command in the Genode directory:
|
||||||
|
|
||||||
|
! tool/ports/prepare_port uboot
|
||||||
|
|
||||||
|
Finally, you have to copy u-boot to the SD-card as root user:
|
||||||
|
|
||||||
|
! dd if=`tool/ports/current uboot`/imx8q_evk/imx-mkimage/iMX8M/flash.bin \
|
||||||
|
! of=/dev/sd<?> bs=1k seek=33 conv=fsync
|
||||||
|
|
||||||
|
Of course, you have replace 'sd<?>' with the correct device node of your
|
||||||
|
attached SD-card.
|
||||||
|
|
||||||
|
After enabling the USB host controller driver, we could successfully re-use the
|
||||||
|
USB HID client driver to drive keyboard and mouse connected to the board. As a
|
||||||
|
nice side-effect, the list of possible storage devices got extended with USB
|
||||||
|
mass storage too by adding the USB block client driver.
|
||||||
|
|
||||||
|
|
||||||
|
Missing libraries
|
||||||
|
=================
|
||||||
|
|
||||||
|
Finally, when building the necessary and optional packages for Sculpt OS, we
|
||||||
|
stumbled across several libraries that needed to be adapted to compile and
|
||||||
|
link for ARMv8 too. Mostly, the inclusion of some other compilation units and
|
||||||
|
headers was sufficient. The related libraries are: libssl, libcrypto, libpng,
|
||||||
|
and Mesa. With the latter two, it is now even possible to execute Qt5
|
||||||
|
components on the target hardware.
|
||||||
|
|
||||||
|
Apart from all the new driver components and extended libraries, the Sculpt
|
||||||
|
manager had to be slightly modified to execute on the i.MX 8M hardware. In its
|
||||||
|
original form it is inherently dependent on x86 drivers, as it for example
|
||||||
|
generates configurations for some of those drivers. For the time being, the
|
||||||
|
changes to the Sculpt manager are not yet part of the official release.
|
||||||
|
Nevertheless, you can produce a Sculpt OS image to be run on an i.MX 8M EVK
|
||||||
|
board by using the following
|
||||||
|
[https://github.com/skalk/sculpt_20.02_imx8q_evk/ - topic branch].
|
||||||
|
|
||||||
|
Alternatively, you can also have a look at Sculpt OS on ARMv8 hardware by
|
||||||
|
following the video recordings of the following talk at FOSDEM 2020.
|
||||||
|
|
||||||
|
:Live demonstration of Sculpt OS on i.MX 8M EVK at FOSDEM 2020:
|
||||||
|
|
||||||
|
[https://fosdem.org/2020/schedule/event/uk_genode_armv8/]
|
||||||
|
|
||||||
|
|
||||||
|
Base framework and OS-level infrastructure
|
||||||
|
##########################################
|
||||||
|
|
||||||
|
New sandbox library based on the init component
|
||||||
|
===============================================
|
||||||
|
|
||||||
|
The init component is Genode's canonical mechanism for the composition of
|
||||||
|
components. This role was further amplified when init became
|
||||||
|
[https://genode.org/documentation/release-notes/17.02#Dynamically_reconfigurable_init_component - dynamically reconfigurable].
|
||||||
|
The latter change cleared the ground for system scenarios like Sculpt OS, the
|
||||||
|
on-target deployment of packages, and dynamic device discovery. One typical
|
||||||
|
pattern found in such scenarios is one dynamically configured instance of init
|
||||||
|
accompanied by a controlling component that is usually called "manager". The
|
||||||
|
manager would consume reports of the subsystem hosted within the dynamic init,
|
||||||
|
and adjust the init configuration according to a domain-specific policy. Such
|
||||||
|
a configuration change, in turn, may trigger new reports, which effectively
|
||||||
|
turns this setting into a feedback control loop.
|
||||||
|
|
||||||
|
Whereas this established pattern is suitable for many scenarios, it is not
|
||||||
|
always natural. In particular if the manager does not only need to
|
||||||
|
manage a subsystem but also wants to intercept a service used by the
|
||||||
|
subsystem, the roles are no longer clear-cut. A practical example is a
|
||||||
|
GUI application that employs the menu-view component for the GUI rendering
|
||||||
|
while processing keyboard events locally. This application would need to
|
||||||
|
intercept the menu-view's GUI session to obtain the stream of user input
|
||||||
|
events. For such an application, the most natural approach would be the
|
||||||
|
co-location of the init functionality with the application logic into a
|
||||||
|
single all-encompassing component.
|
||||||
|
|
||||||
|
To accommodate such scenarios where a domain-specific management component is
|
||||||
|
tightly coupled with a dynamic subsystem, we extracted the child-management
|
||||||
|
functionality from the init component into a new library called "sandbox". The
|
||||||
|
library API is located at
|
||||||
|
[https://github.com/genodelabs/genode/blob/master/repos/os/include/os/sandbox.h - os/include/os/sandbox.h].
|
||||||
|
|
||||||
|
In addition to the hosting of components, the sandbox API also allows for the
|
||||||
|
interaction with the sandboxed children by providing locally implemented
|
||||||
|
services. The latter mechanism is illustrated by a new test available at
|
||||||
|
_os/src/test/sandbox_.
|
||||||
|
|
||||||
|
|
||||||
|
POSIX compatibility improvements
|
||||||
|
================================
|
||||||
|
|
||||||
|
During the release cycle of Genode 20.02, we continued our mission to host
|
||||||
|
POSIX software effortlessly as Genode components. In particular, we followed
|
||||||
|
up the line of work pursued with the two previous releases
|
||||||
|
[https://genode.org/documentation/release-notes/19.08#Consolidation_of_the_C_runtime_and_Noux - 19.08] and
|
||||||
|
[https://genode.org/documentation/release-notes/19.11#C_runtime_with_improved_POSIX_compatibility - 19.11]
|
||||||
|
with respect to the traditional Unix mechanisms fork, execve, and pipes.
|
||||||
|
After covering several edge cases - cloexec, file-descriptor lifetimes,
|
||||||
|
line-buffer handling, vfork, just to name a few - as needed by programs like
|
||||||
|
make, bash, and tclsh, we eventually reached a state where the website
|
||||||
|
generator of [https://genodians.org] works without the need for the now
|
||||||
|
deprecated Noux runtime.
|
||||||
|
|
||||||
|
For years we have been running complex software stacks like the Qt-based web
|
||||||
|
browser on top of our C runtime but not without carefully placed tweaks and
|
||||||
|
occasional patches. With the current release, we address the area of
|
||||||
|
concurrency and introduce a thorough reimplementation of the synchronization
|
||||||
|
primitives namely POSIX mutexes and condition variables as well as semaphores.
|
||||||
|
We also reaped the fruit of our labor by replacing our custom Qt thread back
|
||||||
|
end by the standard POSIX-thread based implementation. Further, we reduced the
|
||||||
|
number of threads in Qt applications by moving the QPA event handling to the
|
||||||
|
component entrypoint and removing the timed-semaphore utility from LibC.
|
||||||
|
|
||||||
|
Beyond Qt, we also address synchronization issues revealed by running a
|
||||||
|
third-party port of [https://grpc.io/ - gRPC] in our network back ends and
|
||||||
|
amended thread-local errno in the C runtime. Finally, our POSIX thread
|
||||||
|
implementation supports cleanup handlers now.
|
||||||
|
|
||||||
|
|
||||||
|
Base-framework refinements
|
||||||
|
==========================
|
||||||
|
|
||||||
|
Replacing the 'Lock' type by new 'Mutex' and 'Blockade' types
|
||||||
|
-------------------------------------------------------------
|
||||||
|
|
||||||
|
Up to now, Genode's lock implementation supports mainly two flavour of usage.
|
||||||
|
On the one hand, it is used to protect critical sections where the lock is
|
||||||
|
initialized as unlocked. In the contention case, the lock holder is supposed
|
||||||
|
to release the critical section. On the other hand, the lock is used as
|
||||||
|
blockade to synchronize startup between various executions of threads. Here
|
||||||
|
the lock is initialized as locked during instantiation whereby the thread that
|
||||||
|
releases the lock is not necessarily the same thread as the creator of the
|
||||||
|
lock.
|
||||||
|
|
||||||
|
We decided to make the two usage pattern more obvious by introducing two
|
||||||
|
separate classes, called 'Mutex' and 'Blockade'. The reasons are two fold.
|
||||||
|
First, during code review, the usage pattern at hand becomes more obvious.
|
||||||
|
Second, by codifying the programmer's intent behind the use of a
|
||||||
|
synchronization primitive, Genode becomes able to perform additional checks,
|
||||||
|
and diagnose certain dead-lock situations and other usage errors on the spot.
|
||||||
|
|
||||||
|
The separation got introduced shortly before this release. Up to now, it is
|
||||||
|
only used in 'Genode::Thread', 'Genode::Heap', and 'Genode::Registry'. The
|
||||||
|
plan is to cultivate the usage across all Genode sources over the next
|
||||||
|
releases and to ultimately remove the 'Genode::Lock' from the public API.
|
||||||
|
|
||||||
|
The 'Mutex' class is more restrictive compared to the 'Lock' class.
|
||||||
|
|
||||||
|
* At initialisation time, it is always unlocked.
|
||||||
|
* To enter and leave a critical section the methods 'acquire()' and
|
||||||
|
'release()' are used.
|
||||||
|
* A 'Mutex::Guard' is provided, which will 'acquire()' a mutex at
|
||||||
|
construction time and release it automatically at destruction time of
|
||||||
|
the guard.
|
||||||
|
* No thread is permitted to lock twice. The code will generate a warning if
|
||||||
|
a dead-lock is detected.
|
||||||
|
* Only the lock holder is permitted to release the mutex. The code will
|
||||||
|
generate a warning and will not release the mutex if this rule is violated.
|
||||||
|
|
||||||
|
! Genode::Mutex mutex;
|
||||||
|
! mutex.acquire();
|
||||||
|
! mutex.release();
|
||||||
|
!
|
||||||
|
! {
|
||||||
|
! Genode::Mutex::Guard guard(mutex) /* acquire() during construction */
|
||||||
|
! } /* release() on guard object destruction */
|
||||||
|
!
|
||||||
|
! Genode::Mutex::Guard guard(mutex);
|
||||||
|
! mutex.acquire(); /* <-- Will cause a warning about the dead-lock */
|
||||||
|
|
||||||
|
The 'Blockade' class is always initialized as locked and provides the methods
|
||||||
|
'block()' and 'wakeup()'. Beside the initialization aspect, the 'Blockade'
|
||||||
|
behaves up to now like the 'Genode::Lock' implementation.
|
||||||
|
|
||||||
|
! Genode::Blockade blockade;
|
||||||
|
!
|
||||||
|
! /* step */ /* thread A */ /* thread B */
|
||||||
|
! 0: -start thread B-
|
||||||
|
! 1: ... -startup-
|
||||||
|
! 2: blockade.block(); ...
|
||||||
|
! 3: -sleep- ...
|
||||||
|
! 4: -sleep- blockade.wakeup();
|
||||||
|
! 5: ... ...
|
||||||
|
|
||||||
|
|
||||||
|
Performance optimization of the XML parser
|
||||||
|
------------------------------------------
|
||||||
|
|
||||||
|
Genode's XML parser used to rely on C++ exceptions while parsing, which is an
|
||||||
|
almost historic artifact inherited from the initial implementation. The
|
||||||
|
performance penalties of exceptions in the rare use of XML was acceptable
|
||||||
|
back when we started. But modern Genode systems like Sculpt OS rely on the
|
||||||
|
dynamic processing of XML like a back bone. The overhead became particularly
|
||||||
|
apparent when executing [Sculpt OS on 64-bit ARM i.MX8 hardware]. Prompted by
|
||||||
|
this observation, we reworked the code such that exceptions are no longer
|
||||||
|
thrown in any hot code path. The public interface of 'Xml_node' remains
|
||||||
|
unchanged.
|
||||||
|
|
||||||
|
|
||||||
|
New polling variant for register framework
|
||||||
|
------------------------------------------
|
||||||
|
|
||||||
|
Genode's register framework has offered a 'wait_for' method for a long time.
|
||||||
|
This function sleeps for a certain amount of microseconds and checks if one or
|
||||||
|
more given conditions become true. The number of attempts to sleep and check
|
||||||
|
the conditions must also be specified. In case the conditions are not met
|
||||||
|
after these attempts, a polling timeout exception is thrown. The function
|
||||||
|
simply returns in case of success. With the current Genode release, we have
|
||||||
|
added a 'wait_for_any' method with almost the same semantics but instead of
|
||||||
|
waiting for all conditions to become true, it returns if any condition is
|
||||||
|
meet, and thus, implements a logical OR.
|
||||||
|
|
||||||
|
|
||||||
|
Migration to modern block-device API
|
||||||
|
====================================
|
||||||
|
|
||||||
|
With release 19.02, Genode introduced two new APIs for block-session handling.
|
||||||
|
The client side of a block session now uses the job API in order to send block
|
||||||
|
requests to the server, which in turn receives those jobs as requests through
|
||||||
|
the Request API. These two APIs replace Genode's 'Block::Driver' and
|
||||||
|
'Block::Session_component' implementations that used the packet stream API
|
||||||
|
directly, which turned out to be error prone for block session implementations.
|
||||||
|
Instead, these new APIs wrap the packet stream handling in a controlled
|
||||||
|
manner while handling all corner cases and even the overcommit of packets.
|
||||||
|
With the current release, we have adapted Genode's AHCI driver and partition
|
||||||
|
manager to these new interfaces, with the plan to adjust all block session
|
||||||
|
clients/servers to the new APIs with Genode release 20.05.
|
||||||
|
|
||||||
|
During this line of work, the AHCI driver received a major cleanup. For
|
||||||
|
example, dynamic memory allocations were removed, the whole initialization
|
||||||
|
state machine has been removed, ATAPI support for Qemu has been re-enabled,
|
||||||
|
and Exynos5 AHCI support is gone - since the platform is outdated and not
|
||||||
|
supported by Genode any more.
|
||||||
|
|
||||||
|
|
||||||
|
Updated audio driver based on OpenBSD 6.6
|
||||||
|
=========================================
|
||||||
|
|
||||||
|
In this release, we updated the 3rd-party sources of the audio driver component
|
||||||
|
to OpenBSD 6.6 and adapted the emulation glue code. While doing so, we fixed
|
||||||
|
a bug regarding the 'delay()' implementation where the function expects
|
||||||
|
microseconds but was given milliseconds. This led to a increased start-up
|
||||||
|
time of the component. We also fixed the logging back end that accidentally
|
||||||
|
was rendered silent and brought in the 'printf' back end from DDE Linux to
|
||||||
|
be able to produce better formatted LOG messages in the future.
|
||||||
|
|
||||||
|
Until now the component only supported HDA and EAP (ES1370 PCI) devices. The
|
||||||
|
first is primarily intended to be used with real hardware wheres the latter
|
||||||
|
was used during the initial porting effort in Qemu. That being said, the EAP
|
||||||
|
driver apparently also works on hardware according to community feedback.
|
||||||
|
|
||||||
|
Since the HDA driver does not work when used in VirtualBox and users expressed
|
||||||
|
the desire to also use audio when running in a VM, we enabled another driver,
|
||||||
|
for which a device-model in VirtualBox exists: the AC97 ICH. As it turned out,
|
||||||
|
using this driver, we can produce audio, albeit the quality is far from
|
||||||
|
usable. Nevertheless, with the driver enabled, interested parties are free to
|
||||||
|
investigate the cause for the current issues.
|
||||||
|
|
||||||
|
All in all, this update is solely a catch up effort to stay more
|
||||||
|
update-to-date with the upstream changes and to pull in HDA quirks for more
|
||||||
|
recent systems. More interesting changes to the driver component, like
|
||||||
|
reworking the OpenBSD kernel emulation layer and bringing support for USB
|
||||||
|
audio devices, are scheduled for future releases.
|
||||||
|
|
||||||
|
|
||||||
|
Support for unlabeled LOG output
|
||||||
|
================================
|
||||||
|
|
||||||
|
In situations where a Genode system is remotely controlled and monitored,
|
||||||
|
it is useful to allow a special component to produce log output with no
|
||||||
|
Genode label applied. This way, such a component can produce log data in
|
||||||
|
a format that is immediately suitable for a controller. This feature can be
|
||||||
|
enabled for a component by rewriting the label of the component's LOG session
|
||||||
|
to "unlabeled".
|
||||||
|
|
||||||
|
! <route>
|
||||||
|
! <service name="LOG"> <parent label="unlabeled"/> </service>
|
||||||
|
! ...
|
||||||
|
! </route>
|
||||||
|
|
||||||
|
|
||||||
|
Libraries and applications
|
||||||
|
##########################
|
||||||
|
|
||||||
|
Custom virtual machine monitor on ARM
|
||||||
|
=====================================
|
||||||
|
|
||||||
|
The ARMv8-compliant virtual-machine monitor introduced in the previous release
|
||||||
|
19.11 now contains new device models to enable the interaction with a
|
||||||
|
virtual-machine via network and terminal services. The new virtual ethernet
|
||||||
|
card and console implementations are compliant to the virtualization standard
|
||||||
|
VIRTIO 1.1.
|
||||||
|
|
||||||
|
Currently, the VMM cannot be configured to contain specific devices. It is
|
||||||
|
hard-wired to provide exactly:
|
||||||
|
|
||||||
|
* One virtual ethernet card that connects to Genode's "Nic" service,
|
||||||
|
* A VIRTIO console that opens up a session to the "Terminal" service using the
|
||||||
|
label "console", and
|
||||||
|
* The traditional PL011 serial device model, which connects to a
|
||||||
|
"Terminal" service too but uses the label "earlycon"
|
||||||
|
|
||||||
|
|
||||||
|
Seoul VMM
|
||||||
|
=========
|
||||||
|
|
||||||
|
During the usage of Seoul on Sculpt, it became apparent that the Seoul VMM
|
||||||
|
caused a constant CPU load even when the guest VM was idling. After some
|
||||||
|
investigation it became clear that having a fixed rate to synchronize the
|
||||||
|
guest graphic memory with the Genode GUI service was the main reason for the
|
||||||
|
constant load. With this release, we added the feature to dynamically adjust
|
||||||
|
the GUI refresh rate depending on the rate of user interactivity.
|
||||||
|
Additionally, if all virtual CPUs go to idle state, the GUI refresh is stopped
|
||||||
|
completely. With these measures, the overall CPU load could be reduced
|
||||||
|
noticeable.
|
||||||
|
|
||||||
|
|
||||||
|
TCP terminal
|
||||||
|
============
|
||||||
|
|
||||||
|
The TCP terminal is a long-living component in the Genode OS framework since
|
||||||
|
release 11.11. It can be used, e.g., to connect to a headless Genode system
|
||||||
|
via telnet. Until now, it always listened to incoming network connections at
|
||||||
|
configured ports. The port had to be configured for each terminal session
|
||||||
|
client.
|
||||||
|
|
||||||
|
The TCP terminal got extended to either listen to incoming network
|
||||||
|
connections, or to directly connect to another network server, dependent on
|
||||||
|
the policy defined for the corresponding terminal client. The following
|
||||||
|
example configuration illustrates the differences:
|
||||||
|
|
||||||
|
! <config>
|
||||||
|
! <policy label="client" ip="10.0.0.5" port="1234"/>
|
||||||
|
! <policy label="another_client" port="4567"/>
|
||||||
|
! </config>
|
||||||
|
|
||||||
|
If only a port is described in the policy, the TCP terminal will listen on
|
||||||
|
that port for incoming connections. If an IP address is provided additionally,
|
||||||
|
it connects to the IP address using the given port.
|
||||||
|
|
||||||
|
|
||||||
|
Virtual desktops
|
||||||
|
================
|
||||||
|
|
||||||
|
Genode's GUI stack enables a high degree of flexibility. Beside the fundamental
|
||||||
|
nitpicker component, responsible for basically multiplexing input events and
|
||||||
|
framebuffer content, there is the window-manager component, and example
|
||||||
|
implementations of a window-layouter, and decorator. The interplay of the
|
||||||
|
latter three allows a window management that scales from simple to rich and
|
||||||
|
sophisticated without lowering its security properties. For a brief description
|
||||||
|
of its architecture, please refer to the release notes of
|
||||||
|
[http://genode.org/documentation/release-notes/14.08 - 14.08].
|
||||||
|
|
||||||
|
In this architecture, the window layouter is responsible for the arrangement
|
||||||
|
of the different windows. It exports a data model of the window layout.
|
||||||
|
Although, the example implementation of the window layouter introduced in
|
||||||
|
14.08 was simple, it already contained a notion of having different virtual
|
||||||
|
screens and screen sections, beside the actual window placements. However,
|
||||||
|
until now there was no use-case of switching dynamically in between different
|
||||||
|
virtual screens respectively window sets related to them.
|
||||||
|
|
||||||
|
While using more and more different graphical components within Sculpt, the
|
||||||
|
window layouter in its initial form hit a limit. Although it already allowed to
|
||||||
|
switch in-between different windows via configured key-combinations, it became
|
||||||
|
inconvenient when having more than a handful windows hiding each other.
|
||||||
|
|
||||||
|
Therefore, the window layouter now got extended to allow switching dynamically
|
||||||
|
in between several pre-defined virtual screens. For the time being, one has to
|
||||||
|
assign a new window to a screen in the rule-set of the window layouter
|
||||||
|
initially by hand. Defining the currently visible screen can either be done by
|
||||||
|
editing the rule-set, or by using pre-configured key-combinations.
|
||||||
|
|
||||||
|
The new default configuration of the window layouter as exported by its
|
||||||
|
corresponding depot package looks like the following:
|
||||||
|
|
||||||
|
! <config rules="rom">
|
||||||
|
! <rules>
|
||||||
|
! <screen name="screen_1"/>
|
||||||
|
! <screen name="screen_2"/>
|
||||||
|
! <screen name="screen_3"/>
|
||||||
|
! <screen name="screen_4"/>
|
||||||
|
! <screen name="screen_5"/>
|
||||||
|
! <screen name="screen_6"/>
|
||||||
|
! <screen name="screen_7"/>
|
||||||
|
! <screen name="screen_8"/>
|
||||||
|
! <screen name="screen_9"/>
|
||||||
|
! <screen name="screen_0"/>
|
||||||
|
! <assign label_prefix="" target="screen_1" xpos="any" ypos="any"/>
|
||||||
|
! </rules>
|
||||||
|
!
|
||||||
|
! <press key="KEY_SCREEN">
|
||||||
|
! <press key="KEY_ENTER" action="toggle_fullscreen"/>
|
||||||
|
! <press key="KEY_1" action="screen" target="screen_1"/>
|
||||||
|
! <press key="KEY_2" action="screen" target="screen_2"/>
|
||||||
|
! <press key="KEY_3" action="screen" target="screen_3"/>
|
||||||
|
! <press key="KEY_4" action="screen" target="screen_4"/>
|
||||||
|
! <press key="KEY_5" action="screen" target="screen_5"/>
|
||||||
|
! <press key="KEY_6" action="screen" target="screen_6"/>
|
||||||
|
! <press key="KEY_7" action="screen" target="screen_7"/>
|
||||||
|
! <press key="KEY_8" action="screen" target="screen_8"/>
|
||||||
|
! <press key="KEY_9" action="screen" target="screen_9"/>
|
||||||
|
! <press key="KEY_0" action="screen" target="screen_0"/>
|
||||||
|
! ...
|
||||||
|
|
||||||
|
As can be seen, individual keys are assigned to switch to a specific virtual
|
||||||
|
screen. By default ten screens are defined that are accessible via the number
|
||||||
|
keys. The first screen definition in the rules configuration marks the
|
||||||
|
currently visible screen.
|
||||||
|
|
||||||
|
|
||||||
|
Menu-view widget renderer
|
||||||
|
=========================
|
||||||
|
|
||||||
|
The line of work described in Section
|
||||||
|
[Redesign of the administrative user interface of Sculpt OS] called for
|
||||||
|
the enhancement of Genode's GUI-rendering component. This component - named
|
||||||
|
menu view - was
|
||||||
|
[https://genode.org/documentation/release-notes/14.11#New_menu_view_application - originally introduced in Genode 14.11]
|
||||||
|
for the rendering of the relatively simple menus of an application launcher.
|
||||||
|
Its software design largely deviates from the beaten track of established
|
||||||
|
widget toolkits, which come in the form of client-side libraries. The
|
||||||
|
menu view is not a complete toolkit but solely a dialog renderer sandboxed
|
||||||
|
in a dedicated component. This design reinforces the strict separation of the
|
||||||
|
view from the application logic, fosters screen-resolution independence, and -
|
||||||
|
most importantly - keeps the complexity of pixel processing out of the
|
||||||
|
application program. Because of the latter, it lends itself to the
|
||||||
|
implementation of security-sensitive interactive applications.
|
||||||
|
|
||||||
|
It would certainly be misguiding to tout our menu-view as feature competitive
|
||||||
|
with existing toolkits. We certainly won't recommend using it over Qt in
|
||||||
|
general. But Sculpt's custom administrative user interface "Leitzentrale"
|
||||||
|
presented us with the perfect playground to explore and grow the potential of
|
||||||
|
our novel approach.
|
||||||
|
|
||||||
|
In contrast to the previous iteration of the Leitzentrale GUI, which relied on
|
||||||
|
a small Unix runtime and Vim for editing text files, the new version ought to
|
||||||
|
feature a simple text editor integrated in the GUI. A text editor requires
|
||||||
|
a much tighter interplay between the view and the actual program logic
|
||||||
|
compared to an application with just a bunch of buttons. Think about cursor
|
||||||
|
handling, scrolling text, displaying textual selections, or placing a text
|
||||||
|
cursor with the mouse. On the course of the work towards the text-area
|
||||||
|
component featured in the new Leitzentrale, the menu view received the
|
||||||
|
following improvements:
|
||||||
|
|
||||||
|
:Text-cursor support:
|
||||||
|
|
||||||
|
The label widget gained the ability to display one or multiple text cursors,
|
||||||
|
as illustrated by the following example:
|
||||||
|
|
||||||
|
! <label text="...">
|
||||||
|
! <cursor at="10"/>
|
||||||
|
! </label>
|
||||||
|
|
||||||
|
For the display of multiple cursors, each cursor must feature a distinctive
|
||||||
|
'name' attribute.
|
||||||
|
|
||||||
|
:Character position featured in the hover report:
|
||||||
|
|
||||||
|
The hovering information provided by the menu view used to be at the
|
||||||
|
granularity of widgets, which is insufficient for placing a text cursor with
|
||||||
|
the mouse. Hence, the information of a hovered label additionally provides
|
||||||
|
the character position within the label now.
|
||||||
|
|
||||||
|
:Unquoting label text attribute values:
|
||||||
|
|
||||||
|
The text displayed in label widgets is provided by a 'text' attribute value,
|
||||||
|
which raises the question of how to present '"' characters on the GUI. With
|
||||||
|
the new version, the attribute value can contain XML-quoted characters,
|
||||||
|
specifically """.
|
||||||
|
|
||||||
|
:Support for displaying text selections:
|
||||||
|
|
||||||
|
Similarly to the way of how a <cursor> can be defined for a <label>
|
||||||
|
widget, a selection can now be expressed as follows:
|
||||||
|
|
||||||
|
! <label ...>
|
||||||
|
! <selection at="2" length="12"/>
|
||||||
|
! </label>
|
||||||
|
|
||||||
|
:Support of multiple '<float>' widgets within a '<frame>':
|
||||||
|
|
||||||
|
We refined the hover reporting of <float> widgets such that a float widget
|
||||||
|
never responds to hovering unless a child is hovered. This way, it becomes
|
||||||
|
possible to stack multiple float widgets within one frame and still reach
|
||||||
|
all child widgets. This is useful for aligning multiple widgets within one
|
||||||
|
screen area independently from each other. For example, for left-aligning,
|
||||||
|
centering, and right-aligning the elements of a panel.
|
||||||
|
|
||||||
|
:Enforcing the minimum size of a label:
|
||||||
|
|
||||||
|
The new '<label min_ex="..">' attribute can be used to enforce a minimum
|
||||||
|
width in the unit of the size of the character 'x'. In the absence of a
|
||||||
|
'text' attribute, the minimum height of a label is implicitly set to 0. The
|
||||||
|
combination of both changes makes the label usable as a horizontal spacer.
|
||||||
|
|
||||||
|
:Basic support for styling labels:
|
||||||
|
|
||||||
|
The new version allows for the customization of the text color and alpha
|
||||||
|
value of the label widget by the means of a style-definition file. The
|
||||||
|
mechanism is exemplified with the new "invisible" label style that sets the
|
||||||
|
alpha value to zero.
|
||||||
|
|
||||||
|
With these few incremental changes in place, the menu-view widget renderer
|
||||||
|
becomes usable as the basis of the simple text editor used in Sculpt's new user
|
||||||
|
interface.
|
||||||
|
|
||||||
|
|
||||||
|
Self-hosting the tool chain on 64-bit ARM
|
||||||
|
=========================================
|
||||||
|
|
||||||
|
With our ongoing ARM 64-bit effort, we have successfully updated Genode's tool
|
||||||
|
chain with release
|
||||||
|
[https://genode.org/documentation/release-notes/19.05#Broadened_CPU_architecture_support_and_updated_tool_chain - 19.05].
|
||||||
|
With the current release, we have additionally managed to make Genode's tool
|
||||||
|
chain self hosting on ARM 64-bit, which means the tool chain can compile
|
||||||
|
source code on ARM 64-bit directly.
|
||||||
|
|
||||||
|
|
||||||
|
Platforms
|
||||||
|
#########
|
||||||
|
|
||||||
|
Execution on bare hardware (base-hw)
|
||||||
|
====================================
|
||||||
|
|
||||||
|
The generic code base of the base-hw kernel underwent several cosmetic changes
|
||||||
|
to reduce or eliminate the application of certain problematic constructs like
|
||||||
|
too much inheritance, pointers, and dynamic casts. Those changes were
|
||||||
|
motivated to ease the translation of several kernel parts to the Ada/SPARK
|
||||||
|
language in the context of the Spunky project. For more information regarding
|
||||||
|
this experiment to write a Genode kernel in Ada/SPARK, please have a look at
|
||||||
|
the recent [https://genodians.org/m-stein/index - genodians.org article series]
|
||||||
|
of Martin Stein or listen to his recent
|
||||||
|
[https://video.fosdem.org/2020/AW1.125/ada_spunky.mp4 - FOSDEM talk].
|
||||||
|
|
||||||
|
Moreover, the IPC path implementation got simplified to lower the overhead
|
||||||
|
costs introduced by the transfer of capabilities. Together with the mentioned
|
||||||
|
Spunky cleanup efforts, this change measurably improved IPC performance.
|
||||||
|
|
||||||
|
The base-hw kernel now exports time consumption of individual threads via
|
||||||
|
the trace service analogously to the implementation for NOVA. Thereby, it
|
||||||
|
becomes possible to use for instance the top component within the Sculpt OS
|
||||||
|
also on this kernel.
|
||||||
|
|
||||||
|
Until now, support for the Raspberry Pi 3 was limited to Qemu emulation only.
|
||||||
|
Thanks to a contribution of Tomasz Gajewski, it is now possible to execute
|
||||||
|
Genode on all four CPUs of the actual hardware concurrently.
|
||||||
|
|
||||||
|
|
||||||
|
Execution on Linux
|
||||||
|
==================
|
||||||
|
|
||||||
|
Traditionally, the Linux version of Genode serves us as very handy development
|
||||||
|
vehicle but it was never intended as an actual target platform. On Linux,
|
||||||
|
Genode is usually executed as a multi-process application on top of a regular
|
||||||
|
GNU/Linux desktop distribution by specifying 'KERNEL=linux' and 'BOARD=linux'
|
||||||
|
to the run tool.
|
||||||
|
|
||||||
|
However, thanks to the work of Johannes Kliemann, Genode has become able to
|
||||||
|
run on a bare-bone Linux kernel without any other user land.
|
||||||
|
We blatantly used to refer to this idea as the
|
||||||
|
[https://genode.org/about/challenges#Platforms - microkernelization of Linux].
|
||||||
|
Johannes picked up the idea, supplemented Genode's core with the services
|
||||||
|
needed for user-level device drivers (IRQ, IOMEM, IOPORT) and supplemented
|
||||||
|
the tooling for the integration of Genode scenarios into a bootable initrd
|
||||||
|
image. This target of execution can be addressed by specifying 'KERNEL=linux'
|
||||||
|
and 'BOARD=pc' to the run tool now. If specified, the run tool will produce a
|
||||||
|
bootable Linux system image for the given run script and run it in Qemu.
|
||||||
|
|
||||||
|
That said, as this line of work is still considered as an experimental
|
||||||
|
playground - not for productive use - the work flow is not entirely automated.
|
||||||
|
In particular, one needs to prepare a suitable
|
||||||
|
[https://github.com/jklmnn/linux/commits/genode - Linux kernel] manually.
|
||||||
|
If you are interested in the topic, please refer to the background information
|
||||||
|
given in the [https://github.com/genodelabs/genode/pull/2829 - issue tracker].
|
||||||
|
|
278
doc/road_map.txt
278
doc/road_map.txt
|
@ -14,122 +14,121 @@ The road map is not fixed. If there is commercial interest of pushing the
|
||||||
Genode technology to a certain direction, we are willing to revisit our plans.
|
Genode technology to a certain direction, we are willing to revisit our plans.
|
||||||
|
|
||||||
|
|
||||||
Review of 2018
|
Review of 2019
|
||||||
##############
|
##############
|
||||||
|
|
||||||
Sculpt is our take on creating a Genode-based general-purpose operating
|
For the road map 2019, we picked "bridging worlds" as our guiding theme:
|
||||||
system. When we declared 2018 as Genode's Year of Sculpt one year ago, our
|
(1) Lowering the friction when combining existing software with Genode,
|
||||||
vision of how Sculpt OS would shape up was still vague. We were convinced that
|
(2) Fostering interoperability with widely used protocols and APIs, and
|
||||||
we had - functionality-wise - all building blocks of a general-purpose OS in
|
(3) Making Genode easier to approach and generally more practical.
|
||||||
place. But it was rather unclear how to best put them together to attain a
|
|
||||||
practical system. The unconquered design space seemed vast, which was both
|
|
||||||
exciting but also - at times - a bit paralyzing.
|
|
||||||
|
|
||||||
The Year of Sculpt was more than anything a design-space exploration, not
|
With respect to (1), we identified Genode's custom tooling (build
|
||||||
an up-front planned activity. The process was driven by intensive
|
system, run scripts, ports mechanism, depot tools) as a point of
|
||||||
brainstorming, experimentation, and the continuous practical evaluation
|
friction. They are arguably powerful and flexible but require a lot of
|
||||||
through the day-to-day use of the system by its developers. For us, this ride
|
up-front learning. This is certainly a burden unacceptable for a casual
|
||||||
was certainly the most rewarding period in Genode's history so far. Now, when
|
developer without a black belt in Make and Expect/Tcl. The new
|
||||||
looking at the result, we are proud about what we have achieved together.
|
[https://genode.org/documentation/release-notes/19.11#New_tooling_for_bridging_existing_build_systems_with_Genode - Goa]
|
||||||
Whenever having the chance to showing off Sculpt running on our laptops,
|
tool rearranges the existing tools in a way that puts the concerns of casual
|
||||||
the system doesn't fail to impress.
|
developers into focus, allowing for the use of commodity build systems,
|
||||||
|
eliminating Tcl syntax from the equation, running sub-second test cycles, and
|
||||||
|
streamlining the packaging of software.
|
||||||
|
|
||||||
Unsurprisingly, many topics of the past year had a direct connection to
|
On account of (2), we
|
||||||
Sculpt, e.g., the NIC router, the huge device-driver efforts, the GUI-stack
|
[https://genode.org/documentation/release-notes/19.05#Broadened_CPU_architecture_support_and_updated_tool_chain - switched to C++17]
|
||||||
improvements, our custom microcode update mechanism, the software packaging
|
by default, fostered the use of
|
||||||
and deployment, and the work on the file-system and networking stacks.
|
[https://genodians.org/ssumpf/2019-02-27-java-19-02 - Java],
|
||||||
|
updated Qt5, and put
|
||||||
|
[https://genode.org/documentation/release-notes/19.11#C_runtime_with_improved_POSIX_compatibility - POSIX]
|
||||||
|
compatibility into the spotlight. We were eventually able to dissolve the need
|
||||||
|
for our custom Unix runtime (Noux) because all features of Noux are covered by
|
||||||
|
our regular libc now.
|
||||||
|
|
||||||
The bottom line of the Year of Sculpt is that Sculpt OS has become a
|
Our biggest step towards (3) is the [https://genodians.org] website we
|
||||||
surprisingly versatile and robust system. It can be deployed in a few seconds
|
started in winter 2019, which gives individual members of our community
|
||||||
by booting from USB, runs as day-to-day OS on almost all of our laptops, its
|
an easy way to present thoughts, projects, and experiences.
|
||||||
mechanisms for installing and updating software from packages have become a
|
Complementing Genode's formal documentation, it also conserves practical
|
||||||
second nature, and it continues to inspire us to explore new application
|
tips and tricks that were previously not covered in written form.
|
||||||
areas. Even outside of Genode Labs, there is a small and enthusiastic user
|
|
||||||
base.
|
|
||||||
|
|
||||||
Besides Sculpt, we set forth a number of other goals one year ago.
|
When speaking of "bridging worlds", we should not forget to mention the
|
||||||
|
tremendous effort to bring Sculpt-OS-like workloads to the 64-bit ARM world.
|
||||||
|
Thanks to the added support for
|
||||||
|
[https://genode.org/documentation/release-notes/19.08#64-bit_ARM_and_NXP_i.MX8 - multi-core AARCH64],
|
||||||
|
hardware-based
|
||||||
|
[https://genode.org/documentation/release-notes/19.11#Virtualization_of_64-bit_ARM_platforms - virtualization],
|
||||||
|
and network/USB/graphics drivers for the i.MX8 SoC, the flexibility of Sculpt
|
||||||
|
OS will eventually become available on PC hardware and ARM-based devices
|
||||||
|
alike.
|
||||||
|
|
||||||
:The transition from NOVA to our custom kernel and seL4: is ongoing but
|
Over the course of 2019, we admittedly skipped a few topics originally
|
||||||
the topic received less attention than originally planned. This has
|
mentioned on our road map. In particular, the user-visible side of
|
||||||
two reasons. First, Alexander Boettcher's excellent maintenance and gradual
|
Sculpt OS received less attention than originally envisioned. We also
|
||||||
improvement of NOVA keeps us hooked. Over the past year, there has been not
|
deferred several ideas we had in mind about reworking our GUI stack.
|
||||||
much incentive of actual Sculpt users to move away from NOVA. Second, there
|
Instead, we expanded our work in the areas of storage (block-level APIs,
|
||||||
is renewed interest in NOVA beyond our use of the kernel. Most specifically,
|
test infrastructure,
|
||||||
we started joining forces with
|
[https://genode.org/documentation/release-notes/19.11#Preliminary_block-device_encrypter - block encryption])
|
||||||
[https://cyberus-technology.de - Cyberus Technology] to improve NOVA
|
and
|
||||||
together. That's fantastic!
|
[https://genode.org/documentation/release-notes/19.08#Flexible_keyboard_layouts - input processing].
|
||||||
|
This shift of focus is mostly attributed to the priorities of Genode Labs'
|
||||||
This development notwithstanding, we still follow our ambition to bring the
|
customers who fund our work.
|
||||||
support for the other kernels like seL4 on par with NOVA to give Genode
|
|
||||||
users the ultimate choice.
|
|
||||||
Speaking of seL4, throughout the year, we have continuously adapted Genode
|
|
||||||
to the kernel's upstream development and enjoy the informal collaboration
|
|
||||||
with seL4 developer community. That said, the seL4 version of Genode still
|
|
||||||
remains a side activity with no commercial backing.
|
|
||||||
|
|
||||||
:NXP i.MX: support has become much better, particularly with respect to
|
|
||||||
network support and performance. Our ongoing commitment to the i.MX
|
|
||||||
platform is also fueled by privacy-advocating projects like the Librem
|
|
||||||
phone that are based on the same SoC.
|
|
||||||
|
|
||||||
:Software quality and resilience: ultimately became the title story of the
|
|
||||||
[https://genode.org/documentation/release-notes/18.11#Raising_the_bar_of_quality_assurance - release 18.11].
|
|
||||||
We greatly intensified the amount and quality of testing, explored static
|
|
||||||
code analysis, and vastly scaled up the complexity of workloads carried
|
|
||||||
by Genode.
|
|
||||||
|
|
||||||
:System monitoring, tracing, profiling: remains a somewhat underdeveloped area
|
|
||||||
of Genode. As a step in the right direction, we introduced a simple
|
|
||||||
trace-logging tool. Also, Sculpt's introspection features like the ability
|
|
||||||
to inspect the runtime's state live on the machine make Genode's behavior
|
|
||||||
easier to capture and to understand. But that said, the use of these
|
|
||||||
features remains a black art mastered only by a few.
|
|
||||||
|
|
||||||
:Java: has found its way into Genode via our port of OpenJDK. Details such as
|
|
||||||
the enabling of the JIT engine on ARM took much more effort than anticipated.
|
|
||||||
We are happy to report that Tomcat works fine. But at the current state, it
|
|
||||||
is still too early to advertise Java as a stable feature.
|
|
||||||
|
|
||||||
|
|
||||||
2019 - Bridging Worlds
|
2020 - Dwarfing the barrier of entry
|
||||||
######################
|
####################################
|
||||||
|
|
||||||
We dedicated the year 2018 to prove that Genode scales to general-purpose
|
Genode as a technology is there. For more than one decade, we walked unfathomed
|
||||||
computing. [https://genode.org/download/sculpt - Sculpt OS] leaves no doubt
|
territory, fought with countless deep rabbit holes, took risky decisions,
|
||||||
about that. The logical next step is to make Sculpt OS relevant and appealing
|
tracked back, explored design spaces, developed taste and distaste, pruned
|
||||||
for a broader community.
|
technical debt, and eventually found formulas of success. Today, there are no
|
||||||
During our public road-map
|
(fundamental) unsolved questions. All the puzzle pieces are in place. There
|
||||||
[https://lists.genode.org/pipermail/users/2018-December/006517.html - discussion]
|
could be no better proof than our daily use of Sculpt OS. The time is right
|
||||||
on our mailing list, we identified three ways towards that goal:
|
to make Genode palatable for a wider circle. We identified four actionable
|
||||||
|
topics to achieve that.
|
||||||
|
|
||||||
# In order to capture the interest of new Genode users, we have to
|
:User friendliness of Sculpt OS:
|
||||||
put *emphasis on the practical use* of Genode, not on its technical prowess.
|
|
||||||
With practical use, we refer to both desktop computing and headless
|
|
||||||
scenarios like network appliances and servers. Over the course of 2019,
|
|
||||||
we plan to establish (variations of) Sculpt as an attractive foundation for
|
|
||||||
those application areas, and advance Genode's protocol stacks (storage and
|
|
||||||
encryption come in mind) and hardware support (e.g., ARM 64-bit) accordingly.
|
|
||||||
|
|
||||||
This will go hand in hand with making Genode easier to discover and to use,
|
Until now, Sculpt OS is not exactly friendly towards users who are
|
||||||
describing use cases at a digestible level of detail, and fostering the
|
unfamiliar with the Unix command-line tools. Since Sculpt is not Unix
|
||||||
sense of one community that includes both users and developers.
|
based, this is a bit paradoxical. 2020 will give Sculpt OS a friendlier
|
||||||
|
and discoverable user experience. In this context, we will inevitably
|
||||||
|
put our attention to Genode's GUI stack.
|
||||||
|
|
||||||
# Since an operating system is only valuable with applications, we have
|
:Perception of high quality:
|
||||||
to make the *porting of existing software* and the use of popular
|
|
||||||
*programming languages* a frictionless experience. Besides supporting the
|
|
||||||
reuse of existing software, we should also cultivate the "Genode way" as
|
|
||||||
an option for designing native applications. Such applications can
|
|
||||||
leverage the unique capabilities of the framework, in particular the
|
|
||||||
sandboxing of code at a very fine granularity and the low footprint of raw
|
|
||||||
Genode components.
|
|
||||||
|
|
||||||
# Because an operating system does not exist in isolation, we must foster
|
Compared to commodity operating systems who stood the test of time,
|
||||||
Genode's *interoperability* with other systems and applications by speaking
|
Genode is a young and largely unproven technology. It understandably calls
|
||||||
widely used protocols and supporting universally expected
|
for skepticism. All the more we must leave no doubts about our high
|
||||||
software-integration features.
|
quality standards. There must be no room for uncertainty. Hence, during
|
||||||
|
2020, we will intensify the consolidation and optimization of the framework
|
||||||
|
and its API, and talk about it.
|
||||||
|
|
||||||
|
:Enjoyable tooling:
|
||||||
|
|
||||||
|
Genode's success at large will depend on developers. As of today, software
|
||||||
|
development for Genode requires a huge up-front learning curve. This is
|
||||||
|
fine for people who are already convinced of Genode. But it unacceptable
|
||||||
|
for casual developers who want to get their toes wet. We should aim for
|
||||||
|
tooling that allows new developers to keep up their flow and beloved
|
||||||
|
tools. The recently introduced [https://genodians.org/nfeske/2019-11-25-goa - Goa]
|
||||||
|
tooling is our first take in this respect. It is certainly too early to call
|
||||||
|
Goa a success. In order to find out if we are on the right track, we want to
|
||||||
|
expose Goa to as many problems as possible, primarily by the means of
|
||||||
|
porting software. Also, things like IDE usage or adapters for a variety of
|
||||||
|
build systems will certainly move into focus in 2020.
|
||||||
|
|
||||||
|
:Convincing use cases:
|
||||||
|
|
||||||
|
Use cases can give exemplary proof of the fitness of Genode. We already
|
||||||
|
took a few baby steps to extend the range of documented use cases beyond
|
||||||
|
Sculpt OS last year. The boot2java scenenario comes in mind. 2020 will
|
||||||
|
hopefully see several more illustrations of Genode's versatility.
|
||||||
|
|
||||||
|
|
||||||
Milestones for 2019
|
Apart from this overall theme, we plan to continue our commitment to the
|
||||||
|
NXP i.MX SoC family, revisit Genode's low-latency audio support, and
|
||||||
|
extend the cultivation of Ada/SPARK within (and on top of) Genode.
|
||||||
|
|
||||||
|
|
||||||
|
Milestones for 2020
|
||||||
###################
|
###################
|
||||||
|
|
||||||
In the following, we present a rough schedule of the planned work. As usual,
|
In the following, we present a rough schedule of the planned work. As usual,
|
||||||
|
@ -137,57 +136,64 @@ it is not set in stone. If you are interested in a particular line of work,
|
||||||
please get in touch.
|
please get in touch.
|
||||||
|
|
||||||
|
|
||||||
February - Release 19.02
|
February - Release 20.02
|
||||||
========================
|
========================
|
||||||
|
|
||||||
* OpenJDK with JIT on ARM and x86
|
* Consolidation: removal of the Noux runtime
|
||||||
* Sculpt with support for online package discovery
|
* Library version of the init component
|
||||||
* Showcase of a Genode-based web appliance
|
* Updated audio drivers
|
||||||
* Showcase of a multi-port network appliance
|
* Sculpt
|
||||||
|
* 64-bit ARM (i.MX8)
|
||||||
|
* Revised administrative user interface
|
||||||
|
* System image without Unix tools
|
||||||
|
|
||||||
|
|
||||||
May - Release 19.05
|
May - Release 20.05
|
||||||
===================
|
===================
|
||||||
|
|
||||||
* Updated "Genode Foundations" book
|
* Updated "Genode Foundations" book
|
||||||
* Tool-chain update and SDK (C++-17, enabling O3 by default, considering GDC)
|
* Consolidation
|
||||||
* Headless Sculpt
|
* Block-level components (update to Genode's modern block APIs)
|
||||||
* Pluggable network drivers
|
* ARM device drivers (introducing the notion of a platform driver)
|
||||||
* Native support for Let's Encrypt certificates
|
* Improved STL support (e.g., threading and mutexes)
|
||||||
* Revisited GUI-related framework interfaces
|
* Continuous POSIX-compliance testing
|
||||||
|
* Systematic network-stack stress and performance tests
|
||||||
|
* Desktop: panel and virtual desktops
|
||||||
|
* Use case: Genode-based network router
|
||||||
|
* Goa: broadened support for 3rd-party build systems
|
||||||
|
* Native tool chain, including Git
|
||||||
* Sculpt
|
* Sculpt
|
||||||
* Improved interactive system composition
|
* Interactive device management
|
||||||
* Passphrase handling
|
* Keyboard-controlled administration
|
||||||
* Clipboard support
|
* Support for BSPs maintained outside of Genode's mainline repository
|
||||||
* Kernel-agnostic virtual-machine monitors
|
|
||||||
* ARM 64-bit
|
|
||||||
|
|
||||||
|
|
||||||
August - Release 19.08
|
August - Release 20.08
|
||||||
======================
|
======================
|
||||||
|
|
||||||
* Interactive tracing tool
|
* Revisited GUI-related framework interfaces
|
||||||
* Virtualization support for the base-hw kernel on x86
|
* Extended tooling for performance monitoring
|
||||||
* Library version of the init component
|
* Goa: Qt development workflow
|
||||||
|
* Desktop
|
||||||
|
* Native mail client
|
||||||
|
* Native web browser
|
||||||
* Sculpt
|
* Sculpt
|
||||||
* Fine-grained USB-device policies
|
* Configurable CPU resources
|
||||||
* Interactive depot manager (ability to add/remove software providers)
|
* On-screen documentation
|
||||||
* Configuration of CPU affinities and scheduling priorities
|
* Block encryption via our
|
||||||
* Audio
|
[https://genode.org/documentation/release-notes/19.11#Preliminary_block-device_encrypter - consistent block encrypter]
|
||||||
* Showcase of a Sculpt-based network router
|
implemented in Ada/SPARK
|
||||||
* VM-based desktop applications (enhanced VM integration features)
|
* USB audio
|
||||||
* Updated Qt5
|
* Initial version of a kernel implemented in Ada/SPARK
|
||||||
* Consolidation of the Noux runtime (performance)
|
|
||||||
|
|
||||||
|
|
||||||
November - Release 19.11
|
November - Release 20.11
|
||||||
========================
|
========================
|
||||||
|
|
||||||
* Building Genode packages directly on Sculpt
|
* Consolidation of capability-space management across kernels
|
||||||
* VNC server support
|
* CPU-load balancing
|
||||||
* Sculpt
|
* Hardware-accelerated graphics on i.MX8 (experimental)
|
||||||
* On-target debugging of components
|
* Reworked audio stack (interfaces, mixing)
|
||||||
* Shutdown protocol
|
* Sculpt: component lifetime management, shutdown protocol
|
||||||
* Block-level encrypted storage
|
* VFS plugins for lwext4 and FUSE-based file systems
|
||||||
* Drag-and-drop protocol
|
|
||||||
|
|
||||||
|
|
|
@ -10,5 +10,7 @@ LIBS += startup-fiasco syscall-fiasco
|
||||||
|
|
||||||
SRC_CC += capability.cc capability_raw.cc
|
SRC_CC += capability.cc capability_raw.cc
|
||||||
SRC_CC += rpc_dispatch_loop.cc
|
SRC_CC += rpc_dispatch_loop.cc
|
||||||
|
SRC_CC += rpc_entrypoint_manage.cc
|
||||||
SRC_CC += thread.cc thread_bootstrap.cc thread_myself.cc
|
SRC_CC += thread.cc thread_bootstrap.cc thread_myself.cc
|
||||||
SRC_CC += stack_area_addr.cc
|
SRC_CC += stack_area_addr.cc
|
||||||
|
SRC_CC += rpc_entry.cc
|
||||||
|
|
|
@ -6,3 +6,4 @@ SRC_CC += thread_start.cc
|
||||||
SRC_CC += cache.cc
|
SRC_CC += cache.cc
|
||||||
SRC_CC += capability_space.cc
|
SRC_CC += capability_space.cc
|
||||||
SRC_CC += signal_transmitter.cc signal.cc
|
SRC_CC += signal_transmitter.cc signal.cc
|
||||||
|
SRC_CC += platform.cc
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
2019-11-25 c7e2a3eca5820b2304b4520d0fc831ede73691f2
|
2020-02-27 6311f83c887384fa01828af695bae799b148e0ad
|
||||||
|
|
|
@ -29,7 +29,7 @@ void Thread::_thread_start()
|
||||||
{
|
{
|
||||||
Thread::myself()->_thread_bootstrap();
|
Thread::myself()->_thread_bootstrap();
|
||||||
Thread::myself()->entry();
|
Thread::myself()->entry();
|
||||||
Thread::myself()->_join_lock.unlock();
|
Thread::myself()->_join.wakeup();
|
||||||
sleep_forever();
|
sleep_forever();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -201,16 +201,14 @@ void Genode::ipc_reply(Native_capability caller, Rpc_exception_code exc,
|
||||||
snd_header.protocol_word,
|
snd_header.protocol_word,
|
||||||
snd_header.num_caps,
|
snd_header.num_caps,
|
||||||
L4_IPC_SEND_TIMEOUT_0, &result);
|
L4_IPC_SEND_TIMEOUT_0, &result);
|
||||||
|
|
||||||
if (L4_IPC_IS_ERROR(result))
|
|
||||||
error("ipc_send error ", Hex(L4_IPC_ERROR(result)), ", ignored");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Genode::Rpc_request Genode::ipc_reply_wait(Reply_capability const &last_caller,
|
Genode::Rpc_request Genode::ipc_reply_wait(Reply_capability const &last_caller,
|
||||||
Rpc_exception_code exc,
|
Rpc_exception_code exc,
|
||||||
Msgbuf_base &reply_msg,
|
Msgbuf_base &reply_msg,
|
||||||
Msgbuf_base &request_msg)
|
Msgbuf_base &request_msg,
|
||||||
|
Rpc_entrypoint::Native_context &)
|
||||||
{
|
{
|
||||||
using namespace Fiasco;
|
using namespace Fiasco;
|
||||||
|
|
||||||
|
@ -277,9 +275,10 @@ Genode::Rpc_request Genode::ipc_reply_wait(Reply_capability const &last_caller,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Ipc_server::Ipc_server()
|
Ipc_server::Ipc_server(Rpc_entrypoint::Native_context& native_context)
|
||||||
:
|
:
|
||||||
Native_capability(Capability_space::import(Fiasco::l4_myself(), Rpc_obj_key()))
|
Native_capability(Capability_space::import(Fiasco::l4_myself(), Rpc_obj_key())),
|
||||||
|
_native_context(native_context)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
|
|
||||||
/* Genode includes */
|
/* Genode includes */
|
||||||
#include <base/cancelable_lock.h>
|
#include <base/cancelable_lock.h>
|
||||||
|
#include <base/thread.h>
|
||||||
#include <cpu/atomic.h>
|
#include <cpu/atomic.h>
|
||||||
#include <cpu/memory_barrier.h>
|
#include <cpu/memory_barrier.h>
|
||||||
|
|
||||||
|
@ -33,6 +34,13 @@ Cancelable_lock::Cancelable_lock(Cancelable_lock::State initial)
|
||||||
|
|
||||||
|
|
||||||
void Cancelable_lock::lock()
|
void Cancelable_lock::lock()
|
||||||
|
{
|
||||||
|
Applicant myself(Thread::myself());
|
||||||
|
lock(myself);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Cancelable_lock::lock(Applicant &myself)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* XXX: How to notice cancel-blocking signals issued when being outside the
|
* XXX: How to notice cancel-blocking signals issued when being outside the
|
||||||
|
@ -41,11 +49,14 @@ void Cancelable_lock::lock()
|
||||||
while (!Genode::cmpxchg(&_state, UNLOCKED, LOCKED))
|
while (!Genode::cmpxchg(&_state, UNLOCKED, LOCKED))
|
||||||
if (Fiasco::l4_ipc_sleep(Fiasco::l4_ipc_timeout(0, 0, 500, 0)) != L4_IPC_RETIMEOUT)
|
if (Fiasco::l4_ipc_sleep(Fiasco::l4_ipc_timeout(0, 0, 500, 0)) != L4_IPC_RETIMEOUT)
|
||||||
throw Genode::Blocking_canceled();
|
throw Genode::Blocking_canceled();
|
||||||
|
|
||||||
|
_owner = myself;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Cancelable_lock::unlock()
|
void Cancelable_lock::unlock()
|
||||||
{
|
{
|
||||||
|
_owner = Applicant(nullptr);
|
||||||
Genode::memory_barrier();
|
Genode::memory_barrier();
|
||||||
_state = UNLOCKED;
|
_state = UNLOCKED;
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,9 @@ LIBS += syscall-foc startup-foc
|
||||||
|
|
||||||
SRC_CC += spin_lock.cc cap_map.cc
|
SRC_CC += spin_lock.cc cap_map.cc
|
||||||
SRC_CC += rpc_dispatch_loop.cc
|
SRC_CC += rpc_dispatch_loop.cc
|
||||||
|
SRC_CC += rpc_entrypoint_manage.cc
|
||||||
SRC_CC += thread.cc thread_bootstrap.cc thread_myself.cc utcb.cc
|
SRC_CC += thread.cc thread_bootstrap.cc thread_myself.cc utcb.cc
|
||||||
SRC_CC += capability.cc
|
SRC_CC += capability.cc
|
||||||
SRC_CC += signal_source_client.cc
|
SRC_CC += signal_source_client.cc
|
||||||
|
SRC_CC += platform.cc
|
||||||
|
SRC_CC += rpc_entry.cc
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
2019-11-25 9a459c4fd8a907810d91041751affcf3e119fcb1
|
2020-02-27 82bbd7275951340ff82061af8bc2cce41f1519e3
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
2019-11-25 d8ff4913b8aa117aef77a7918bc82808e38a4ee7
|
2020-02-27 c5602daf28cdc5d005a26f408527e64ab905197e
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
2019-11-25 a750c8988106d5c26e46dcceb1f76bfd7bfa1457
|
2020-02-27 a3912478467dcf01ab6379502bb15719b748c388
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
2019-11-25 0c0a26b6ddb0ee5261f0be30f229e9ce04b61eda
|
2020-02-27 e7f8bca57dbed6597e46aafd0256dfd5a6ac42c3
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
2019-11-25 bce6f0a8f1f46f8edf62ef2180dbfc949123432d
|
2020-02-27 b03dfe2bde7fe637c0a7eff9e709845e64b4d09c
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
2019-11-25 307d01e531dbbcd672463a4ea090f40bb399cae8
|
2020-02-27 a1eb6dfc01d82b598f0778c0b74f2a49387cc42d
|
||||||
|
|
|
@ -36,7 +36,7 @@ void Ipc_pager::_parse(unsigned long label) {
|
||||||
if (_type == PAGEFAULT || _type == EXCEPTION)
|
if (_type == PAGEFAULT || _type == EXCEPTION)
|
||||||
_parse_pagefault();
|
_parse_pagefault();
|
||||||
if (_type == PAUSE || _type == EXCEPTION)
|
if (_type == PAUSE || _type == EXCEPTION)
|
||||||
memcpy(&_regs, l4_utcb_exc(), sizeof(l4_exc_regs_t));
|
_regs = *l4_utcb_exc();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -134,7 +134,7 @@ void Ipc_pager::acknowledge_wakeup()
|
||||||
|
|
||||||
void Ipc_pager::acknowledge_exception()
|
void Ipc_pager::acknowledge_exception()
|
||||||
{
|
{
|
||||||
memcpy(l4_utcb_exc(), &_regs, sizeof(l4_exc_regs_t));
|
_regs = *l4_utcb_exc();
|
||||||
l4_cap_idx_t dst = Fiasco::Capability::valid(_last.kcap)
|
l4_cap_idx_t dst = Fiasco::Capability::valid(_last.kcap)
|
||||||
? _last.kcap : (l4_cap_idx_t)L4_SYSF_REPLY;
|
? _last.kcap : (l4_cap_idx_t)L4_SYSF_REPLY;
|
||||||
Fiasco::l4_msgtag_t const msg_tag =
|
Fiasco::l4_msgtag_t const msg_tag =
|
||||||
|
|
|
@ -495,6 +495,10 @@ Platform::Platform() :
|
||||||
xml.node("hardware", [&] () {
|
xml.node("hardware", [&] () {
|
||||||
_setup_platform_info(xml, sigma0_map_kip());
|
_setup_platform_info(xml, sigma0_map_kip());
|
||||||
});
|
});
|
||||||
|
xml.node("affinity-space", [&] () {
|
||||||
|
xml.attribute("width", affinity_space().width());
|
||||||
|
xml.attribute("height", affinity_space().height());
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
_rom_fs.insert(new (core_mem_alloc()) Rom_module(phys_addr, size,
|
_rom_fs.insert(new (core_mem_alloc()) Rom_module(phys_addr, size,
|
||||||
|
|
|
@ -78,7 +78,7 @@ static inline void thread_switch_to(Genode::Thread *thread_base)
|
||||||
__attribute__((optimize("-fno-omit-frame-pointer")))
|
__attribute__((optimize("-fno-omit-frame-pointer")))
|
||||||
__attribute__((noinline))
|
__attribute__((noinline))
|
||||||
__attribute__((used))
|
__attribute__((used))
|
||||||
static void thread_stop_myself()
|
static void thread_stop_myself(Genode::Thread *)
|
||||||
{
|
{
|
||||||
using namespace Fiasco;
|
using namespace Fiasco;
|
||||||
|
|
||||||
|
|
|
@ -238,6 +238,11 @@ static l4_msgtag_t copy_msgbuf_to_utcb(Msgbuf_base &snd_msg,
|
||||||
/* setup flexpage for valid capability to delegate */
|
/* setup flexpage for valid capability to delegate */
|
||||||
if (caps[i].valid) {
|
if (caps[i].valid) {
|
||||||
unsigned const idx = num_msg_words + 2*num_cap_sel;
|
unsigned const idx = num_msg_words + 2*num_cap_sel;
|
||||||
|
|
||||||
|
/* check bounds of 'l4_msg_regs_t::mr' */
|
||||||
|
if (idx + 1 >= L4_UTCB_GENERIC_DATA_SIZE)
|
||||||
|
break;
|
||||||
|
|
||||||
l4_utcb_mr()->mr[idx] = L4_ITEM_MAP/* | L4_ITEM_CONT*/;
|
l4_utcb_mr()->mr[idx] = L4_ITEM_MAP/* | L4_ITEM_CONT*/;
|
||||||
l4_utcb_mr()->mr[idx + 1] = l4_obj_fpage(caps[i].sel,
|
l4_utcb_mr()->mr[idx + 1] = l4_obj_fpage(caps[i].sel,
|
||||||
0, L4_FPAGE_RWX).raw;
|
0, L4_FPAGE_RWX).raw;
|
||||||
|
@ -311,10 +316,11 @@ void Genode::ipc_reply(Native_capability, Rpc_exception_code exc,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Genode::Rpc_request Genode::ipc_reply_wait(Reply_capability const &,
|
Genode::Rpc_request Genode::ipc_reply_wait(Reply_capability const &,
|
||||||
Rpc_exception_code exc,
|
Rpc_exception_code exc,
|
||||||
Msgbuf_base &reply_msg,
|
Msgbuf_base &reply_msg,
|
||||||
Msgbuf_base &request_msg)
|
Msgbuf_base &request_msg,
|
||||||
|
Rpc_entrypoint::Native_context &)
|
||||||
{
|
{
|
||||||
Receive_window &rcv_window = Thread::myself()->native_thread().rcv_window;
|
Receive_window &rcv_window = Thread::myself()->native_thread().rcv_window;
|
||||||
|
|
||||||
|
@ -365,9 +371,10 @@ Genode::Rpc_request Genode::ipc_reply_wait(Reply_capability const &,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Ipc_server::Ipc_server()
|
Ipc_server::Ipc_server(Rpc_entrypoint::Native_context& native_context)
|
||||||
:
|
:
|
||||||
Native_capability((Cap_index*)Fiasco::l4_utcb_tcr()->user[Fiasco::UTCB_TCR_BADGE])
|
Native_capability((Cap_index*)Fiasco::l4_utcb_tcr()->user[Fiasco::UTCB_TCR_BADGE]),
|
||||||
|
_native_context(native_context)
|
||||||
{
|
{
|
||||||
Thread::myself()->native_thread().rcv_window.init();
|
Thread::myself()->native_thread().rcv_window.init();
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,6 +59,6 @@ void Genode::Thread::_thread_start()
|
||||||
|
|
||||||
Thread::myself()->_thread_bootstrap();
|
Thread::myself()->_thread_bootstrap();
|
||||||
Thread::myself()->entry();
|
Thread::myself()->entry();
|
||||||
Thread::myself()->_join_lock.unlock();
|
Thread::myself()->_join.wakeup();
|
||||||
sleep_forever();
|
sleep_forever();
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,5 +10,7 @@ include $(BASE_DIR)/lib/mk/base-common.inc
|
||||||
LIBS += syscall-hw
|
LIBS += syscall-hw
|
||||||
|
|
||||||
SRC_CC += rpc_dispatch_loop.cc
|
SRC_CC += rpc_dispatch_loop.cc
|
||||||
|
SRC_CC += rpc_entrypoint_manage.cc
|
||||||
SRC_CC += thread.cc thread_myself.cc thread_bootstrap.cc
|
SRC_CC += thread.cc thread_myself.cc thread_bootstrap.cc
|
||||||
SRC_CC += signal_transmitter.cc
|
SRC_CC += signal_transmitter.cc
|
||||||
|
SRC_CC += rpc_entry.cc
|
||||||
|
|
|
@ -7,5 +7,6 @@ SRC_CC += raw_write_string.cc
|
||||||
SRC_CC += signal_receiver.cc
|
SRC_CC += signal_receiver.cc
|
||||||
SRC_CC += stack_area_addr.cc
|
SRC_CC += stack_area_addr.cc
|
||||||
SRC_CC += native_utcb.cc
|
SRC_CC += native_utcb.cc
|
||||||
|
SRC_CC += platform.cc
|
||||||
|
|
||||||
LIBS += startup-hw base-hw-common cxx timeout-hw
|
LIBS += startup-hw base-hw-common cxx timeout-hw
|
||||||
|
|
|
@ -52,7 +52,6 @@ SRC_CC += pager.cc
|
||||||
SRC_CC += _main.cc
|
SRC_CC += _main.cc
|
||||||
SRC_CC += kernel/cpu.cc
|
SRC_CC += kernel/cpu.cc
|
||||||
SRC_CC += kernel/cpu_scheduler.cc
|
SRC_CC += kernel/cpu_scheduler.cc
|
||||||
SRC_CC += kernel/double_list.cc
|
|
||||||
SRC_CC += kernel/init.cc
|
SRC_CC += kernel/init.cc
|
||||||
SRC_CC += kernel/ipc_node.cc
|
SRC_CC += kernel/ipc_node.cc
|
||||||
SRC_CC += kernel/irq.cc
|
SRC_CC += kernel/irq.cc
|
||||||
|
|
|
@ -17,7 +17,7 @@ SRC_CC += spec/arm/platform_support.cc
|
||||||
|
|
||||||
# add assembly sources
|
# add assembly sources
|
||||||
SRC_S += spec/arm/crt0.s
|
SRC_S += spec/arm/crt0.s
|
||||||
SRC_S += spec/arm/exception_vector.s
|
SRC_S += spec/arm/exception_vector.S
|
||||||
|
|
||||||
vpath spec/32bit/memory_map.cc $(BASE_DIR)/../base-hw/src/lib/hw
|
vpath spec/32bit/memory_map.cc $(BASE_DIR)/../base-hw/src/lib/hw
|
||||||
|
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
2019-11-25 c60d834ce54a46a946c36249784e734e06274d97
|
2020-02-27 e1a80cef41a848e8f63df9a249a4e57148e66331
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
2019-11-25 e9232754efd81c14aa65d4852d276852f591f3e5
|
2020-02-27 bd79fb9d11cef09e99ba545408128a605b47814a
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
2019-11-25 2ab0250606cee0da4f08ac08f7f33c743f32c88c
|
2020-02-27 879f89b08454a6aab78bab0c018d1902af792a47
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
2019-11-25 7780e0570ac0277d678dee76a579a9d9f9a1a776
|
2020-02-27 447889337c681d7b9f68c637f9a3eac3abfd2f30
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
2019-11-25 2dee497b7892f706236fdbfabae53bbd4e62463b
|
2020-02-27 42c284564d38f3bdbd6b30e58280a2f699b657f9
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
2019-11-25 efd164d66086a998484d7413c5416e3aa128e560
|
2020-02-27 9d9e438a93c416499bb7b414bbcf2de7f2d3650f
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
2019-11-25 25f54b8744778f0860ac2a93c11ee6b1cd16d0c9
|
2020-02-27 ff3428ffdd5d60514fa5028b003b54327da895ad
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
2019-11-25 ceeaef3ad58fc5b88cf4686aa42f50fd254063e3
|
2020-02-27 84aec73deeae79a6b34374fe859ea5333d05da69
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
2019-11-25 aee36abdef456d2d1c6bba023f16cbca08eceabe
|
2020-02-27 e87fc4e86962227db5c41bf048eeacf1c27d04c1
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
2019-11-25 ede7ce464c3f4b8486fd93413088a1b83fbf796a
|
2020-02-27 ebd97e5400e2b99fd810cd233c0f881ede48f376
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
2019-11-25 2bea4132b9ab877e802cfb81ad3c62bda0c2bc50
|
2020-02-27 5d0722736647b538eb52b35286b7734581402426
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
2019-11-25 807893480c51457cad7e00e1275eff9749c91c68
|
2020-02-27 1caed3e6b2d8bc98948b9fd43f3bb26abd52f780
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
2019-11-25 6a3f12cd6429f5d5bcf617cdd3ea9d345e8614ad
|
2020-02-27 6d72eb037774a58fc079c5df7bd5b7348c8799b4
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
2019-11-25 a318db7d985930e3f58ce3bccce290bc13aaedab
|
2020-02-27 41e345219f64781ef6cb472d4f9d374b0295328b
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
2019-11-25 75f1b89ea50fdfd0a69c33dee4ba1e120d49fad5
|
2020-02-27 c2481cbfd690b653b38c6bfe09c296094240e90d
|
||||||
|
|
|
@ -23,7 +23,7 @@ install_config {
|
||||||
<default-route>
|
<default-route>
|
||||||
<any-service> <parent/> </any-service>
|
<any-service> <parent/> </any-service>
|
||||||
</default-route>
|
</default-route>
|
||||||
<start name="test-cpu_scheduler">
|
<start name="test-cpu_scheduler" caps="100">
|
||||||
<resource name="RAM" quantum="10M"/>
|
<resource name="RAM" quantum="10M"/>
|
||||||
</start>
|
</start>
|
||||||
</config>}
|
</config>}
|
||||||
|
|
|
@ -16,11 +16,14 @@ install_config {
|
||||||
<parent-provides>
|
<parent-provides>
|
||||||
<service name="LOG"/>
|
<service name="LOG"/>
|
||||||
<service name="RM"/>
|
<service name="RM"/>
|
||||||
|
<service name="PD"/>
|
||||||
|
<service name="CPU"/>
|
||||||
|
<service name="ROM"/>
|
||||||
</parent-provides>
|
</parent-provides>
|
||||||
<default-route>
|
<default-route>
|
||||||
<any-service> <parent/> </any-service>
|
<any-service> <parent/> </any-service>
|
||||||
</default-route>
|
</default-route>
|
||||||
<start name="test-double_list">
|
<start name="test-double_list" caps="100">
|
||||||
<resource name="RAM" quantum="10M"/>
|
<resource name="RAM" quantum="10M"/>
|
||||||
</start>
|
</start>
|
||||||
</config>
|
</config>
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <base/lock.h>
|
#include <base/lock.h>
|
||||||
|
#include <base/mutex.h>
|
||||||
#include <hw/assert.h>
|
#include <hw/assert.h>
|
||||||
|
|
||||||
Genode::Cancelable_lock::Cancelable_lock(Genode::Cancelable_lock::State state)
|
Genode::Cancelable_lock::Cancelable_lock(Genode::Cancelable_lock::State state)
|
||||||
|
@ -30,3 +31,13 @@ void Genode::Cancelable_lock::lock()
|
||||||
assert(_state == UNLOCKED);
|
assert(_state == UNLOCKED);
|
||||||
_state = LOCKED;
|
_state = LOCKED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Genode::Mutex::acquire()
|
||||||
|
{
|
||||||
|
_lock.lock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Genode::Mutex::release()
|
||||||
|
{
|
||||||
|
_lock.unlock();
|
||||||
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
|
|
||||||
using namespace Bootstrap;
|
using namespace Bootstrap;
|
||||||
|
|
||||||
|
extern unsigned _bss_end;
|
||||||
|
|
||||||
/*****************************
|
/*****************************
|
||||||
** Platform::Ram_allocator **
|
** Platform::Ram_allocator **
|
||||||
|
@ -179,7 +180,7 @@ Platform::Platform()
|
||||||
/* temporarily map all bootstrap memory 1:1 for transition to core */
|
/* temporarily map all bootstrap memory 1:1 for transition to core */
|
||||||
// FIXME do not insert as mapping for core
|
// FIXME do not insert as mapping for core
|
||||||
core_pd->map_insert(Mapping(bootstrap_region.base, bootstrap_region.base,
|
core_pd->map_insert(Mapping(bootstrap_region.base, bootstrap_region.base,
|
||||||
bootstrap_region.size, Hw::PAGE_FLAGS_KERN_TEXT));
|
(addr_t)&_bss_end - (addr_t)&_prog_img_beg, Hw::PAGE_FLAGS_KERN_TEXT));
|
||||||
|
|
||||||
/* map memory-mapped I/O for core */
|
/* map memory-mapped I/O for core */
|
||||||
board.core_mmio.for_each_mapping([&] (Mapping const & m) {
|
board.core_mmio.for_each_mapping([&] (Mapping const & m) {
|
||||||
|
|
|
@ -109,13 +109,18 @@ unsigned Bootstrap::Platform::enable_mmu()
|
||||||
static Cpu_counter data_cache_invalidated;
|
static Cpu_counter data_cache_invalidated;
|
||||||
static Cpu_counter data_cache_enabled;
|
static Cpu_counter data_cache_enabled;
|
||||||
static Cpu_counter smp_coherency_enabled;
|
static Cpu_counter smp_coherency_enabled;
|
||||||
|
static unsigned long diag_reg = 0;
|
||||||
|
|
||||||
bool primary = primary_cpu;
|
bool primary = primary_cpu;
|
||||||
if (primary) primary_cpu = false;
|
if (primary) {
|
||||||
|
primary_cpu = false;
|
||||||
|
diag_reg = Cpu::Diag::read();
|
||||||
|
}
|
||||||
|
|
||||||
Cpu::Sctlr::init();
|
Cpu::Sctlr::init();
|
||||||
Cpu::Cpsr::init();
|
Cpu::Cpsr::init();
|
||||||
Actlr::disable_smp();
|
Actlr::disable_smp();
|
||||||
|
Cpu::Diag::write(diag_reg);
|
||||||
|
|
||||||
/* locally initialize interrupt controller */
|
/* locally initialize interrupt controller */
|
||||||
::Board::Pic pic { };
|
::Board::Pic pic { };
|
||||||
|
@ -170,6 +175,7 @@ unsigned Bootstrap::Platform::enable_mmu()
|
||||||
/* wait for other cores' coherency activation */
|
/* wait for other cores' coherency activation */
|
||||||
smp_coherency_enabled.wait_for(NR_OF_CPUS);
|
smp_coherency_enabled.wait_for(NR_OF_CPUS);
|
||||||
|
|
||||||
Cpu::synchronization_barrier();
|
asm volatile("dsb sy\n"
|
||||||
|
"isb sy\n" ::: "memory");
|
||||||
return Cpu::Mpidr::Aff_0::get(Cpu::Mpidr::read());
|
return Cpu::Mpidr::Aff_0::get(Cpu::Mpidr::read());
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
|
|
||||||
using Board::Cpu;
|
using Board::Cpu;
|
||||||
|
|
||||||
extern "C" void * _crt0_enable_fpu;
|
extern "C" void * _crt0_start_secondary;
|
||||||
|
|
||||||
static inline void prepare_non_secure_world()
|
static inline void prepare_non_secure_world()
|
||||||
{
|
{
|
||||||
|
@ -144,6 +144,9 @@ unsigned Bootstrap::Platform::enable_mmu()
|
||||||
Cpu::Ttbr::access_t ttbr =
|
Cpu::Ttbr::access_t ttbr =
|
||||||
Cpu::Ttbr::Baddr::masked((Genode::addr_t)core_pd->table_base);
|
Cpu::Ttbr::Baddr::masked((Genode::addr_t)core_pd->table_base);
|
||||||
|
|
||||||
|
/* primary cpu wakes up all others */
|
||||||
|
if (primary && NR_OF_CPUS > 1) Cpu::wake_up_all_cpus(&_crt0_start_secondary);
|
||||||
|
|
||||||
while (Cpu::current_privilege_level() > Cpu::Current_el::EL1) {
|
while (Cpu::current_privilege_level() > Cpu::Current_el::EL1) {
|
||||||
if (Cpu::current_privilege_level() == Cpu::Current_el::EL3) {
|
if (Cpu::current_privilege_level() == Cpu::Current_el::EL3) {
|
||||||
prepare_non_secure_world();
|
prepare_non_secure_world();
|
||||||
|
@ -153,11 +156,11 @@ unsigned Bootstrap::Platform::enable_mmu()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* primary cpu wakes up all others */
|
|
||||||
if (primary && NR_OF_CPUS > 1) Cpu::wake_up_all_cpus(&_crt0_enable_fpu);
|
|
||||||
|
|
||||||
/* enable performance counter for user-land */
|
/* enable performance counter for user-land */
|
||||||
Cpu::Pmuserenr_el0::write(0b1111);
|
Cpu::Pmuserenr_el0::write(0b1111);
|
||||||
|
Cpu::Pmcr_el0::access_t pmcr = Cpu::Pmcr_el0::read();
|
||||||
|
Cpu::Pmcr_el0::write(pmcr | 1);
|
||||||
|
Cpu::Pmcntenset_el0::write(1 << 31);
|
||||||
|
|
||||||
/* enable user-level access of physical/virtual counter */
|
/* enable user-level access of physical/virtual counter */
|
||||||
Cpu::Cntkctl_el1::write(0b11);
|
Cpu::Cntkctl_el1::write(0b11);
|
||||||
|
@ -198,5 +201,5 @@ unsigned Bootstrap::Platform::enable_mmu()
|
||||||
Cpu::Sctlr::Uct::set(sctlr, 1);
|
Cpu::Sctlr::Uct::set(sctlr, 1);
|
||||||
Cpu::Sctlr_el1::write(sctlr);
|
Cpu::Sctlr_el1::write(sctlr);
|
||||||
|
|
||||||
return 0;
|
return (Cpu::Mpidr::read() & 0xff);
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,22 +11,25 @@
|
||||||
* under the terms of the GNU Affero General Public License version 3.
|
* under the terms of the GNU Affero General Public License version 3.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Store CPU number in register x0
|
||||||
|
*/
|
||||||
|
.macro _cpu_number
|
||||||
|
mrs x0, mpidr_el1
|
||||||
|
and x0, x0, #0b11111111
|
||||||
|
.endm
|
||||||
|
|
||||||
.section ".text.crt0"
|
.section ".text.crt0"
|
||||||
|
|
||||||
.global _start
|
.global _start
|
||||||
_start:
|
_start:
|
||||||
|
|
||||||
/***********************
|
|
||||||
** Detect CPU number **
|
|
||||||
***********************/
|
|
||||||
|
|
||||||
mrs x0, mpidr_el1
|
|
||||||
and x0, x0, #0b11111111
|
|
||||||
cbz x0, _crt0_fill_bss_zero
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hack for Qemu, which starts all cpus at once
|
* Hack for Qemu, which starts all cpus at once
|
||||||
|
* only first CPU runs through, all others wait for wakeup
|
||||||
*/
|
*/
|
||||||
|
_cpu_number
|
||||||
|
cbz x0, _crt0_fill_bss_zero
|
||||||
1:
|
1:
|
||||||
ldr x1, =_crt0_qemu_start_secondary_cpus
|
ldr x1, =_crt0_qemu_start_secondary_cpus
|
||||||
ldr w1, [x1]
|
ldr w1, [x1]
|
||||||
|
@ -52,11 +55,18 @@
|
||||||
b 1b
|
b 1b
|
||||||
|
|
||||||
|
|
||||||
|
/************************************
|
||||||
|
** Common Entrypoint for all CPUs **
|
||||||
|
************************************/
|
||||||
|
|
||||||
|
.global _crt0_start_secondary
|
||||||
|
_crt0_start_secondary:
|
||||||
|
|
||||||
|
|
||||||
/****************
|
/****************
|
||||||
** Enable FPU **
|
** Enable FPU **
|
||||||
****************/
|
****************/
|
||||||
|
|
||||||
.global _crt0_enable_fpu
|
|
||||||
_crt0_enable_fpu:
|
_crt0_enable_fpu:
|
||||||
mov x1, #0b11
|
mov x1, #0b11
|
||||||
lsl x1, x1, #20
|
lsl x1, x1, #20
|
||||||
|
@ -69,6 +79,7 @@
|
||||||
|
|
||||||
.set STACK_SIZE, 0x2000
|
.set STACK_SIZE, 0x2000
|
||||||
|
|
||||||
|
_cpu_number
|
||||||
ldr x1, =_crt0_start_stack
|
ldr x1, =_crt0_start_stack
|
||||||
ldr x2, [x1]
|
ldr x2, [x1]
|
||||||
mul x0, x0, x2
|
mul x0, x0, x2
|
||||||
|
@ -82,4 +93,3 @@
|
||||||
.endr
|
.endr
|
||||||
_crt0_start_stack:
|
_crt0_start_stack:
|
||||||
.long STACK_SIZE
|
.long STACK_SIZE
|
||||||
|
|
||||||
|
|
|
@ -30,8 +30,16 @@ Bootstrap::Platform::Board::Board()
|
||||||
|
|
||||||
extern unsigned int _crt0_qemu_start_secondary_cpus;
|
extern unsigned int _crt0_qemu_start_secondary_cpus;
|
||||||
|
|
||||||
void Board::Cpu::wake_up_all_cpus(void *)
|
void Board::Cpu::wake_up_all_cpus(void * ip)
|
||||||
{
|
{
|
||||||
|
/* start when in qemu */
|
||||||
_crt0_qemu_start_secondary_cpus = 1;
|
_crt0_qemu_start_secondary_cpus = 1;
|
||||||
asm volatile("dsb #0; sev");
|
|
||||||
|
/* start on real hardware */
|
||||||
|
*((void * volatile *) 0xe0) = ip; /* cpu 1 */
|
||||||
|
*((void * volatile *) 0xe8) = ip; /* cpu 2 */
|
||||||
|
*((void * volatile *) 0xf0) = ip; /* cpu 3 */
|
||||||
|
|
||||||
|
/* send event for both variants */
|
||||||
|
asm volatile("dsb #15; sev");
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,9 @@
|
||||||
#include <cpu_session_component.h>
|
#include <cpu_session_component.h>
|
||||||
#include <kernel/configuration.h>
|
#include <kernel/configuration.h>
|
||||||
|
|
||||||
|
/* base-internal includes */
|
||||||
|
#include <base/internal/native_utcb.h>
|
||||||
|
|
||||||
using namespace Genode;
|
using namespace Genode;
|
||||||
|
|
||||||
|
|
||||||
|
@ -33,3 +36,7 @@ Cpu_session::Quota Cpu_session_component::quota()
|
||||||
size_t const u = quota_lim_downscale<sizet_arithm_t>(_quota, spu);
|
size_t const u = quota_lim_downscale<sizet_arithm_t>(_quota, spu);
|
||||||
return { spu, u };
|
return { spu, u };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
size_t Cpu_session_component::_utcb_quota_size() {
|
||||||
|
return sizeof(Native_utcb); }
|
||||||
|
|
|
@ -40,7 +40,7 @@ void Cpu_job::_activate_own_share() { _cpu->schedule(this); }
|
||||||
void Cpu_job::_deactivate_own_share()
|
void Cpu_job::_deactivate_own_share()
|
||||||
{
|
{
|
||||||
assert(_cpu->id() == Cpu::executing_id());
|
assert(_cpu->id() == Cpu::executing_id());
|
||||||
_cpu->scheduler().unready(this);
|
_cpu->scheduler().unready(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -74,13 +74,13 @@ void Cpu_job::_interrupt(unsigned const /* cpu_id */)
|
||||||
void Cpu_job::affinity(Cpu &cpu)
|
void Cpu_job::affinity(Cpu &cpu)
|
||||||
{
|
{
|
||||||
_cpu = &cpu;
|
_cpu = &cpu;
|
||||||
_cpu->scheduler().insert(this);
|
_cpu->scheduler().insert(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Cpu_job::quota(unsigned const q)
|
void Cpu_job::quota(unsigned const q)
|
||||||
{
|
{
|
||||||
if (_cpu) { _cpu->scheduler().quota(this, q); }
|
if (_cpu) { _cpu->scheduler().quota(*this, q); }
|
||||||
else { Cpu_share::quota(q); }
|
else { Cpu_share::quota(q); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -93,7 +93,7 @@ Cpu_job::Cpu_job(Cpu_priority const p, unsigned const q)
|
||||||
Cpu_job::~Cpu_job()
|
Cpu_job::~Cpu_job()
|
||||||
{
|
{
|
||||||
if (!_cpu) { return; }
|
if (!_cpu) { return; }
|
||||||
_cpu->scheduler().remove(this);
|
_cpu->scheduler().remove(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -115,8 +115,13 @@ Cpu::Idle_thread::Idle_thread(Cpu &cpu)
|
||||||
|
|
||||||
void Cpu::schedule(Job * const job)
|
void Cpu::schedule(Job * const job)
|
||||||
{
|
{
|
||||||
if (_id == executing_id()) { _scheduler.ready(&job->share()); }
|
if (_id == executing_id()) { _scheduler.ready(job->share()); }
|
||||||
else if (_scheduler.ready_check(&job->share())) { trigger_ip_interrupt(); }
|
else {
|
||||||
|
_scheduler.ready_check(job->share());
|
||||||
|
if (_scheduler.need_to_schedule()) {
|
||||||
|
trigger_ip_interrupt();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -140,7 +145,8 @@ Cpu_job & Cpu::schedule()
|
||||||
_scheduler.update(_timer.time());
|
_scheduler.update(_timer.time());
|
||||||
time_t t = _scheduler.head_quota();
|
time_t t = _scheduler.head_quota();
|
||||||
_timer.set_timeout(this, t);
|
_timer.set_timeout(this, t);
|
||||||
_timer.schedule_timeout();
|
time_t duration = _timer.schedule_timeout();
|
||||||
|
old_job.update_execution_time(duration);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* return new job */
|
/* return new job */
|
||||||
|
@ -161,7 +167,7 @@ Cpu::Cpu(unsigned const id,
|
||||||
Inter_processor_work_list & global_work_list)
|
Inter_processor_work_list & global_work_list)
|
||||||
:
|
:
|
||||||
_id(id), _timer(*this),
|
_id(id), _timer(*this),
|
||||||
_scheduler(&_idle, _quota(), _fill()), _idle(*this),
|
_scheduler(_idle, _quota(), _fill()), _idle(*this),
|
||||||
_ipi_irq(*this),
|
_ipi_irq(*this),
|
||||||
_global_work_list(global_work_list)
|
_global_work_list(global_work_list)
|
||||||
{ _arch_init(); }
|
{ _arch_init(); }
|
||||||
|
|
|
@ -169,7 +169,7 @@ class Kernel::Cpu : public Genode::Cpu, private Irq::Pool, private Timeout
|
||||||
* Returns the currently active job
|
* Returns the currently active job
|
||||||
*/
|
*/
|
||||||
Job & scheduled_job() const {
|
Job & scheduled_job() const {
|
||||||
return *static_cast<Job *>(_scheduler.head())->helping_sink(); }
|
return *static_cast<Job *>(&_scheduler.head())->helping_sink(); }
|
||||||
|
|
||||||
unsigned id() const { return _id; }
|
unsigned id() const { return _id; }
|
||||||
Cpu_scheduler &scheduler() { return _scheduler; }
|
Cpu_scheduler &scheduler() { return _scheduler; }
|
||||||
|
@ -178,6 +178,11 @@ class Kernel::Cpu : public Genode::Cpu, private Irq::Pool, private Timeout
|
||||||
|
|
||||||
Inter_processor_work_list & work_list() {
|
Inter_processor_work_list & work_list() {
|
||||||
return _local_work_list; }
|
return _local_work_list; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return CPU's idle thread object
|
||||||
|
*/
|
||||||
|
Kernel::Thread &idle_thread() { return _idle; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -35,6 +35,8 @@ class Kernel::Cpu_job : private Cpu_share
|
||||||
|
|
||||||
friend class Cpu; /* static_cast from 'Cpu_share' to 'Cpu_job' */
|
friend class Cpu; /* static_cast from 'Cpu_share' to 'Cpu_job' */
|
||||||
|
|
||||||
|
time_t _execution_time { 0 };
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Noncopyable
|
* Noncopyable
|
||||||
*/
|
*/
|
||||||
|
@ -112,6 +114,16 @@ class Kernel::Cpu_job : private Cpu_share
|
||||||
*/
|
*/
|
||||||
bool own_share_active() { return Cpu_share::ready(); }
|
bool own_share_active() { return Cpu_share::ready(); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update total execution time
|
||||||
|
*/
|
||||||
|
void update_execution_time(time_t duration) { _execution_time += duration; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return total execution time
|
||||||
|
*/
|
||||||
|
time_t execution_time() const { return _execution_time; }
|
||||||
|
|
||||||
|
|
||||||
/***************
|
/***************
|
||||||
** Accessors **
|
** Accessors **
|
||||||
|
|
|
@ -18,14 +18,16 @@
|
||||||
using namespace Kernel;
|
using namespace Kernel;
|
||||||
|
|
||||||
|
|
||||||
void Cpu_scheduler::_reset(Claim * const c) {
|
void Cpu_scheduler::_reset(Cpu_share &share)
|
||||||
_share(c)->_claim = _share(c)->_quota; }
|
{
|
||||||
|
share._claim = share._quota;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void Cpu_scheduler::_reset_claims(unsigned const p)
|
void Cpu_scheduler::_reset_claims(unsigned const p)
|
||||||
{
|
{
|
||||||
_rcl[p].for_each([&] (Claim * const c) { _reset(c); });
|
_rcl[p].for_each([&] (Cpu_share &share) { _reset(share); });
|
||||||
_ucl[p].for_each([&] (Claim * const c) { _reset(c); });
|
_ucl[p].for_each([&] (Cpu_share &share) { _reset(share); });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -43,11 +45,11 @@ void Cpu_scheduler::_consumed(unsigned const q)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Cpu_scheduler::_set_head(Share * const s, unsigned const q, bool const c)
|
void Cpu_scheduler::_set_head(Share &s, unsigned const q, bool const c)
|
||||||
{
|
{
|
||||||
_head_quota = q;
|
_head_quota = q;
|
||||||
_head_claims = c;
|
_head_claims = c;
|
||||||
_head = s;
|
_head = &s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -63,13 +65,13 @@ void Cpu_scheduler::_head_claimed(unsigned const r)
|
||||||
if (!_head->_quota) { return; }
|
if (!_head->_quota) { return; }
|
||||||
_head->_claim = r > _head->_quota ? _head->_quota : r;
|
_head->_claim = r > _head->_quota ? _head->_quota : r;
|
||||||
if (_head->_claim || !_head->_ready) { return; }
|
if (_head->_claim || !_head->_ready) { return; }
|
||||||
_rcl[_head->_prio].to_tail(_head);
|
_rcl[_head->_prio].to_tail(&_head->_claim_item);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Cpu_scheduler::_head_filled(unsigned const r)
|
void Cpu_scheduler::_head_filled(unsigned const r)
|
||||||
{
|
{
|
||||||
if (_fills.head() != _head) { return; }
|
if (_fills.head() != &_head->_fill_item) { return; }
|
||||||
if (r) { _head->_fill = r; }
|
if (r) { _head->_fill = r; }
|
||||||
else { _next_fill(); }
|
else { _next_fill(); }
|
||||||
}
|
}
|
||||||
|
@ -78,10 +80,11 @@ void Cpu_scheduler::_head_filled(unsigned const r)
|
||||||
bool Cpu_scheduler::_claim_for_head()
|
bool Cpu_scheduler::_claim_for_head()
|
||||||
{
|
{
|
||||||
for (signed p = Prio::MAX; p > Prio::MIN - 1; p--) {
|
for (signed p = Prio::MAX; p > Prio::MIN - 1; p--) {
|
||||||
Share * const s = _share(_rcl[p].head());
|
Double_list_item<Cpu_share> *const item { _rcl[p].head() };
|
||||||
if (!s) { continue; }
|
if (!item) { continue; }
|
||||||
if (!s->_claim) { continue; }
|
Cpu_share &share { item->payload() };
|
||||||
_set_head(s, s->_claim, 1);
|
if (!share._claim) { continue; }
|
||||||
|
_set_head(share, share._claim, 1);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -90,14 +93,17 @@ bool Cpu_scheduler::_claim_for_head()
|
||||||
|
|
||||||
bool Cpu_scheduler::_fill_for_head()
|
bool Cpu_scheduler::_fill_for_head()
|
||||||
{
|
{
|
||||||
Share * const s = _share(_fills.head());
|
Double_list_item<Cpu_share> *const item { _fills.head() };
|
||||||
if (!s) { return 0; }
|
if (!item) {
|
||||||
_set_head(s, s->_fill, 0);
|
return 0;
|
||||||
|
}
|
||||||
|
Share &share = item->payload();
|
||||||
|
_set_head(share, share._fill, 0);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
unsigned Cpu_scheduler::_trim_consumption(unsigned & q)
|
unsigned Cpu_scheduler::_trim_consumption(unsigned &q)
|
||||||
{
|
{
|
||||||
q = Genode::min(Genode::min(q, _head_quota), _residual);
|
q = Genode::min(Genode::min(q, _head_quota), _residual);
|
||||||
if (!_head_yields) { return _head_quota - q; }
|
if (!_head_yields) { return _head_quota - q; }
|
||||||
|
@ -106,23 +112,23 @@ unsigned Cpu_scheduler::_trim_consumption(unsigned & q)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Cpu_scheduler::_quota_introduction(Share * const s)
|
void Cpu_scheduler::_quota_introduction(Share &s)
|
||||||
{
|
{
|
||||||
if (s->_ready) { _rcl[s->_prio].insert_tail(s); }
|
if (s._ready) { _rcl[s._prio].insert_tail(&s._claim_item); }
|
||||||
else { _ucl[s->_prio].insert_tail(s); }
|
else { _ucl[s._prio].insert_tail(&s._claim_item); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Cpu_scheduler::_quota_revokation(Share * const s)
|
void Cpu_scheduler::_quota_revokation(Share &s)
|
||||||
{
|
{
|
||||||
if (s->_ready) { _rcl[s->_prio].remove(s); }
|
if (s._ready) { _rcl[s._prio].remove(&s._claim_item); }
|
||||||
else { _ucl[s->_prio].remove(s); }
|
else { _ucl[s._prio].remove(&s._claim_item); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Cpu_scheduler::_quota_adaption(Share * const s, unsigned const q)
|
void Cpu_scheduler::_quota_adaption(Share &s, unsigned const q)
|
||||||
{
|
{
|
||||||
if (q) { if (s->_claim > q) { s->_claim = q; } }
|
if (q) { if (s._claim > q) { s._claim = q; } }
|
||||||
else { _quota_revokation(s); }
|
else { _quota_revokation(s); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -147,56 +153,62 @@ void Cpu_scheduler::update(time_t time)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool Cpu_scheduler::ready_check(Share * const s1)
|
void Cpu_scheduler::ready_check(Share &s1)
|
||||||
{
|
{
|
||||||
assert(_head);
|
assert(_head);
|
||||||
|
|
||||||
ready(s1);
|
ready(s1);
|
||||||
|
|
||||||
if (_need_to_schedule) return _need_to_schedule;
|
if (_need_to_schedule) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
Share * s2 = _head;
|
Share * s2 = _head;
|
||||||
if (!s1->_claim) {
|
if (!s1._claim) {
|
||||||
_need_to_schedule = s2 == _idle;
|
_need_to_schedule = s2 == &_idle;
|
||||||
} else if (!_head_claims) {
|
} else if (!_head_claims) {
|
||||||
_need_to_schedule = true;
|
_need_to_schedule = true;
|
||||||
} else if (s1->_prio != s2->_prio) {
|
} else if (s1._prio != s2->_prio) {
|
||||||
_need_to_schedule = s1->_prio > s2->_prio;
|
_need_to_schedule = s1._prio > s2->_prio;
|
||||||
} else {
|
} else {
|
||||||
for (; s2 && s2 != s1; s2 = _share(Claim_list::next(s2))) ;
|
for (
|
||||||
|
; s2 && s2 != &s1;
|
||||||
|
s2 =
|
||||||
|
Double_list<Cpu_share>::next(&s2->_claim_item) != nullptr ?
|
||||||
|
&Double_list<Cpu_share>::next(&s2->_claim_item)->payload() :
|
||||||
|
nullptr) ;
|
||||||
|
|
||||||
_need_to_schedule = !s2;
|
_need_to_schedule = !s2;
|
||||||
}
|
}
|
||||||
return _need_to_schedule;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Cpu_scheduler::ready(Share * const s)
|
void Cpu_scheduler::ready(Share &s)
|
||||||
{
|
{
|
||||||
assert(!s->_ready && s != _idle);
|
assert(!s._ready && &s != &_idle);
|
||||||
|
|
||||||
_need_to_schedule = true;
|
_need_to_schedule = true;
|
||||||
|
|
||||||
s->_ready = 1;
|
s._ready = 1;
|
||||||
s->_fill = _fill;
|
s._fill = _fill;
|
||||||
_fills.insert_tail(s);
|
_fills.insert_tail(&s._fill_item);
|
||||||
if (!s->_quota) { return; }
|
if (!s._quota) { return; }
|
||||||
_ucl[s->_prio].remove(s);
|
_ucl[s._prio].remove(&s._claim_item);
|
||||||
if (s->_claim) { _rcl[s->_prio].insert_head(s); }
|
if (s._claim) { _rcl[s._prio].insert_head(&s._claim_item); }
|
||||||
else { _rcl[s->_prio].insert_tail(s); }
|
else { _rcl[s._prio].insert_tail(&s._claim_item); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Cpu_scheduler::unready(Share * const s)
|
void Cpu_scheduler::unready(Share &s)
|
||||||
{
|
{
|
||||||
assert(s->_ready && s != _idle);
|
assert(s._ready && &s != &_idle);
|
||||||
|
|
||||||
_need_to_schedule = true;
|
_need_to_schedule = true;
|
||||||
|
|
||||||
s->_ready = 0;
|
s._ready = 0;
|
||||||
_fills.remove(s);
|
_fills.remove(&s._fill_item);
|
||||||
if (!s->_quota) { return; }
|
if (!s._quota) { return; }
|
||||||
_rcl[s->_prio].remove(s);
|
_rcl[s._prio].remove(&s._claim_item);
|
||||||
_ucl[s->_prio].insert_tail(s);
|
_ucl[s._prio].insert_tail(&s._claim_item);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -207,39 +219,46 @@ void Cpu_scheduler::yield()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Cpu_scheduler::remove(Share * const s)
|
void Cpu_scheduler::remove(Share &s)
|
||||||
{
|
{
|
||||||
assert(s != _idle);
|
assert(&s != &_idle);
|
||||||
|
|
||||||
_need_to_schedule = true;
|
_need_to_schedule = true;
|
||||||
if (s == _head) _head = nullptr;
|
if (&s == _head) _head = nullptr;
|
||||||
if (s->_ready) { _fills.remove(s); }
|
if (s._ready) { _fills.remove(&s._fill_item); }
|
||||||
if (!s->_quota) { return; }
|
if (!s._quota) { return; }
|
||||||
if (s->_ready) { _rcl[s->_prio].remove(s); }
|
if (s._ready) { _rcl[s._prio].remove(&s._claim_item); }
|
||||||
else { _ucl[s->_prio].remove(s); }
|
else { _ucl[s._prio].remove(&s._claim_item); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Cpu_scheduler::insert(Share * const s)
|
void Cpu_scheduler::insert(Share &s)
|
||||||
{
|
{
|
||||||
assert(!s->_ready);
|
assert(!s._ready);
|
||||||
_need_to_schedule = true;
|
_need_to_schedule = true;
|
||||||
if (!s->_quota) { return; }
|
if (!s._quota) { return; }
|
||||||
s->_claim = s->_quota;
|
s._claim = s._quota;
|
||||||
_ucl[s->_prio].insert_head(s);
|
_ucl[s._prio].insert_head(&s._claim_item);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Cpu_scheduler::quota(Share * const s, unsigned const q)
|
void Cpu_scheduler::quota(Share &s, unsigned const q)
|
||||||
{
|
{
|
||||||
assert(s != _idle);
|
assert(&s != &_idle);
|
||||||
if (s->_quota) { _quota_adaption(s, q); }
|
if (s._quota) { _quota_adaption(s, q); }
|
||||||
else if (q) { _quota_introduction(s); }
|
else if (q) { _quota_introduction(s); }
|
||||||
s->_quota = q;
|
s._quota = q;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Cpu_scheduler::Cpu_scheduler(Share * const i, unsigned const q,
|
Cpu_share &Cpu_scheduler::head() const
|
||||||
|
{
|
||||||
|
assert(_head);
|
||||||
|
return *_head;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Cpu_scheduler::Cpu_scheduler(Share &i, unsigned const q,
|
||||||
unsigned const f)
|
unsigned const f)
|
||||||
: _idle(i), _quota(q), _residual(q), _fill(f)
|
: _idle(i), _quota(q), _residual(q), _fill(f)
|
||||||
{ _set_head(i, f, 0); }
|
{ _set_head(i, f, 0); }
|
||||||
|
|
|
@ -27,16 +27,6 @@ namespace Kernel
|
||||||
*/
|
*/
|
||||||
class Cpu_priority;
|
class Cpu_priority;
|
||||||
|
|
||||||
/**
|
|
||||||
* Scheduling context that has quota and priority (low-latency)
|
|
||||||
*/
|
|
||||||
class Cpu_claim : public Double_list_item { };
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Scheduling context that has no quota or priority (best effort)
|
|
||||||
*/
|
|
||||||
class Cpu_fill : public Double_list_item { };
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Scheduling context that is both claim and fill
|
* Scheduling context that is both claim and fill
|
||||||
*/
|
*/
|
||||||
|
@ -70,7 +60,7 @@ class Kernel::Cpu_priority
|
||||||
* Standard operators
|
* Standard operators
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Cpu_priority & operator =(signed const v)
|
Cpu_priority &operator =(signed const v)
|
||||||
{
|
{
|
||||||
_value = Genode::min(v, MAX);
|
_value = Genode::min(v, MAX);
|
||||||
return *this;
|
return *this;
|
||||||
|
@ -79,17 +69,19 @@ class Kernel::Cpu_priority
|
||||||
operator signed() const { return _value; }
|
operator signed() const { return _value; }
|
||||||
};
|
};
|
||||||
|
|
||||||
class Kernel::Cpu_share : public Cpu_claim, public Cpu_fill
|
class Kernel::Cpu_share
|
||||||
{
|
{
|
||||||
friend class Cpu_scheduler;
|
friend class Cpu_scheduler;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
signed const _prio;
|
Double_list_item<Cpu_share> _fill_item { *this };
|
||||||
unsigned _quota;
|
Double_list_item<Cpu_share> _claim_item { *this };
|
||||||
unsigned _claim;
|
signed const _prio;
|
||||||
unsigned _fill = 0;
|
unsigned _quota;
|
||||||
bool _ready = false;
|
unsigned _claim;
|
||||||
|
unsigned _fill { 0 };
|
||||||
|
bool _ready { false };
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
@ -114,60 +106,53 @@ class Kernel::Cpu_scheduler
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
|
||||||
typedef Cpu_share Share;
|
typedef Cpu_share Share;
|
||||||
typedef Cpu_fill Fill;
|
typedef Cpu_priority Prio;
|
||||||
typedef Cpu_claim Claim;
|
|
||||||
typedef Double_list_typed<Claim> Claim_list;
|
|
||||||
typedef Double_list_typed<Fill> Fill_list;
|
|
||||||
typedef Cpu_priority Prio;
|
|
||||||
|
|
||||||
Claim_list _rcl[Prio::MAX + 1]; /* ready claims */
|
Double_list<Cpu_share> _rcl[Prio::MAX + 1]; /* ready claims */
|
||||||
Claim_list _ucl[Prio::MAX + 1]; /* unready claims */
|
Double_list<Cpu_share> _ucl[Prio::MAX + 1]; /* unready claims */
|
||||||
Fill_list _fills { }; /* ready fills */
|
Double_list<Cpu_share> _fills { }; /* ready fills */
|
||||||
Share * const _idle;
|
Share &_idle;
|
||||||
Share * _head = nullptr;
|
Share *_head = nullptr;
|
||||||
unsigned _head_quota = 0;
|
unsigned _head_quota = 0;
|
||||||
bool _head_claims = false;
|
bool _head_claims = false;
|
||||||
bool _head_yields = false;
|
bool _head_yields = false;
|
||||||
unsigned const _quota;
|
unsigned const _quota;
|
||||||
unsigned _residual;
|
unsigned _residual;
|
||||||
unsigned const _fill;
|
unsigned const _fill;
|
||||||
bool _need_to_schedule { true };
|
bool _need_to_schedule { true };
|
||||||
time_t _last_time { 0 };
|
time_t _last_time { 0 };
|
||||||
|
|
||||||
template <typename F> void _for_each_prio(F f) {
|
template <typename F> void _for_each_prio(F f) {
|
||||||
for (signed p = Prio::MAX; p > Prio::MIN - 1; p--) { f(p); } }
|
for (signed p = Prio::MAX; p > Prio::MIN - 1; p--) { f(p); } }
|
||||||
|
|
||||||
template <typename T>
|
static void _reset(Cpu_share &share);
|
||||||
static Share * _share(T * const t) { return static_cast<Share *>(t); }
|
|
||||||
|
|
||||||
static void _reset(Claim * const c);
|
|
||||||
|
|
||||||
void _reset_claims(unsigned const p);
|
void _reset_claims(unsigned const p);
|
||||||
void _next_round();
|
void _next_round();
|
||||||
void _consumed(unsigned const q);
|
void _consumed(unsigned const q);
|
||||||
void _set_head(Share * const s, unsigned const q, bool const c);
|
void _set_head(Share &s, unsigned const q, bool const c);
|
||||||
void _next_fill();
|
void _next_fill();
|
||||||
void _head_claimed(unsigned const r);
|
void _head_claimed(unsigned const r);
|
||||||
void _head_filled(unsigned const r);
|
void _head_filled(unsigned const r);
|
||||||
bool _claim_for_head();
|
bool _claim_for_head();
|
||||||
bool _fill_for_head();
|
bool _fill_for_head();
|
||||||
unsigned _trim_consumption(unsigned & q);
|
unsigned _trim_consumption(unsigned &q);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fill 's' becomes a claim due to a quota donation
|
* Fill 's' becomes a claim due to a quota donation
|
||||||
*/
|
*/
|
||||||
void _quota_introduction(Share * const s);
|
void _quota_introduction(Share &s);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Claim 's' looses its state as claim due to quota revokation
|
* Claim 's' looses its state as claim due to quota revokation
|
||||||
*/
|
*/
|
||||||
void _quota_revokation(Share * const s);
|
void _quota_revokation(Share &s);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The quota of claim 's' changes to 'q'
|
* The quota of claim 's' changes to 'q'
|
||||||
*/
|
*/
|
||||||
void _quota_adaption(Share * const s, unsigned const q);
|
void _quota_adaption(Share &s, unsigned const q);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
@ -179,7 +164,7 @@ class Kernel::Cpu_scheduler
|
||||||
* \param q total amount of time quota that can be claimed by shares
|
* \param q total amount of time quota that can be claimed by shares
|
||||||
* \param f time-slice length of the fill round-robin
|
* \param f time-slice length of the fill round-robin
|
||||||
*/
|
*/
|
||||||
Cpu_scheduler(Share * const i, unsigned const q, unsigned const f);
|
Cpu_scheduler(Share &i, unsigned const q, unsigned const f);
|
||||||
|
|
||||||
bool need_to_schedule() { return _need_to_schedule; }
|
bool need_to_schedule() { return _need_to_schedule; }
|
||||||
void timeout() { _need_to_schedule = true; }
|
void timeout() { _need_to_schedule = true; }
|
||||||
|
@ -192,17 +177,17 @@ class Kernel::Cpu_scheduler
|
||||||
/**
|
/**
|
||||||
* Set 's1' ready and return wether this outdates current head
|
* Set 's1' ready and return wether this outdates current head
|
||||||
*/
|
*/
|
||||||
bool ready_check(Share * const s1);
|
void ready_check(Share &s1);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set share 's' ready
|
* Set share 's' ready
|
||||||
*/
|
*/
|
||||||
void ready(Share * const s);
|
void ready(Share &s);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set share 's' unready
|
* Set share 's' unready
|
||||||
*/
|
*/
|
||||||
void unready(Share * const s);
|
void unready(Share &s);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Current head looses its current claim/fill for this round
|
* Current head looses its current claim/fill for this round
|
||||||
|
@ -212,23 +197,23 @@ class Kernel::Cpu_scheduler
|
||||||
/**
|
/**
|
||||||
* Remove share 's' from scheduler
|
* Remove share 's' from scheduler
|
||||||
*/
|
*/
|
||||||
void remove(Share * const s);
|
void remove(Share &s);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Insert share 's' into scheduler
|
* Insert share 's' into scheduler
|
||||||
*/
|
*/
|
||||||
void insert(Share * const s);
|
void insert(Share &s);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set quota of share 's' to 'q'
|
* Set quota of share 's' to 'q'
|
||||||
*/
|
*/
|
||||||
void quota(Share * const s, unsigned const q);
|
void quota(Share &s, unsigned const q);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Accessors
|
* Accessors
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Share * head() const { return _head; }
|
Share &head() const;
|
||||||
unsigned head_quota() const {
|
unsigned head_quota() const {
|
||||||
return Genode::min(_head_quota, _residual); }
|
return Genode::min(_head_quota, _residual); }
|
||||||
unsigned quota() const { return _quota; }
|
unsigned quota() const { return _quota; }
|
||||||
|
|
|
@ -1,86 +0,0 @@
|
||||||
/*
|
|
||||||
* \brief List of double connected items
|
|
||||||
* \author Martin Stein
|
|
||||||
* \date 2012-11-30
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Copyright (C) 2012-2017 Genode Labs GmbH
|
|
||||||
*
|
|
||||||
* This file is part of the Genode OS framework, which is distributed
|
|
||||||
* under the terms of the GNU Affero General Public License version 3.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* core includes */
|
|
||||||
#include <kernel/double_list.h>
|
|
||||||
|
|
||||||
using namespace Kernel;
|
|
||||||
|
|
||||||
|
|
||||||
void Double_list::_connect_neighbors(Item * const i)
|
|
||||||
{
|
|
||||||
i->_prev->_next = i->_next;
|
|
||||||
i->_next->_prev = i->_prev;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Double_list::_to_tail(Item * const i)
|
|
||||||
{
|
|
||||||
if (i == _tail) { return; }
|
|
||||||
_connect_neighbors(i);
|
|
||||||
i->_prev = _tail;
|
|
||||||
i->_next = 0;
|
|
||||||
_tail->_next = i;
|
|
||||||
_tail = i;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Double_list::Double_list(): _head(0), _tail(0) { }
|
|
||||||
|
|
||||||
|
|
||||||
void Double_list::to_tail(Item * const i)
|
|
||||||
{
|
|
||||||
if (i == _head) { head_to_tail(); }
|
|
||||||
else { _to_tail(i); }
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Double_list::insert_tail(Item * const i)
|
|
||||||
{
|
|
||||||
if (_tail) { _tail->_next = i; }
|
|
||||||
else { _head = i; }
|
|
||||||
i->_prev = _tail;
|
|
||||||
i->_next = 0;
|
|
||||||
_tail = i;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Double_list::insert_head(Item * const i)
|
|
||||||
{
|
|
||||||
if (_head) { _head->_prev = i; }
|
|
||||||
else { _tail = i; }
|
|
||||||
i->_next = _head;
|
|
||||||
i->_prev = 0;
|
|
||||||
_head = i;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Double_list::remove(Item * const i)
|
|
||||||
{
|
|
||||||
if (i == _tail) { _tail = i->_prev; }
|
|
||||||
else { i->_next->_prev = i->_prev; }
|
|
||||||
if (i == _head) { _head = i->_next; }
|
|
||||||
else { i->_prev->_next = i->_next; }
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Double_list::head_to_tail()
|
|
||||||
{
|
|
||||||
if (!_head || _head == _tail) { return; }
|
|
||||||
_head->_prev = _tail;
|
|
||||||
_tail->_next = _head;
|
|
||||||
_head = _head->_next;
|
|
||||||
_head->_prev = 0;
|
|
||||||
_tail = _tail->_next;
|
|
||||||
_tail->_next = 0;
|
|
||||||
}
|
|
|
@ -19,78 +19,130 @@ namespace Kernel
|
||||||
/**
|
/**
|
||||||
* Ability to be an item in a double connected list
|
* Ability to be an item in a double connected list
|
||||||
*/
|
*/
|
||||||
|
template <typename T>
|
||||||
class Double_list_item;
|
class Double_list_item;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* List of double connected items
|
* List of double connected items
|
||||||
*/
|
*/
|
||||||
|
template <typename T>
|
||||||
class Double_list;
|
class Double_list;
|
||||||
|
|
||||||
/**
|
|
||||||
* Double list over objects of type 'T' that inherits from double-list item
|
|
||||||
*/
|
|
||||||
template <typename T> class Double_list_typed;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
class Kernel::Double_list_item
|
class Kernel::Double_list_item
|
||||||
{
|
{
|
||||||
friend class Double_list;
|
friend class Double_list<T>;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
Double_list_item * _next = nullptr;
|
Double_list_item * _next = nullptr;
|
||||||
Double_list_item * _prev = nullptr;
|
Double_list_item * _prev = nullptr;
|
||||||
|
T & _payload;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
Double_list_item(T &payload) : _payload(payload) { }
|
||||||
|
|
||||||
|
T &payload() { return _payload; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
class Kernel::Double_list
|
class Kernel::Double_list
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
|
||||||
typedef Double_list_item Item;
|
typedef Double_list_item<T> Item;
|
||||||
|
|
||||||
Item * _head;
|
Item * _head;
|
||||||
Item * _tail;
|
Item * _tail;
|
||||||
|
|
||||||
void _connect_neighbors(Item * const i);
|
void _connect_neighbors(Item * const i)
|
||||||
void _to_tail(Item * const i);
|
{
|
||||||
|
i->_prev->_next = i->_next;
|
||||||
|
i->_next->_prev = i->_prev;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _to_tail(Item * const i)
|
||||||
|
{
|
||||||
|
if (i == _tail) { return; }
|
||||||
|
_connect_neighbors(i);
|
||||||
|
i->_prev = _tail;
|
||||||
|
i->_next = 0;
|
||||||
|
_tail->_next = i;
|
||||||
|
_tail = i;
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct empty list
|
* Construct empty list
|
||||||
*/
|
*/
|
||||||
Double_list();
|
Double_list() : _head(0), _tail(0) { }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Move item 'i' from its current list position to the tail
|
* Move item 'i' from its current list position to the tail
|
||||||
*/
|
*/
|
||||||
void to_tail(Item * const i);
|
void to_tail(Item * const i)
|
||||||
|
{
|
||||||
|
if (i == _head) { head_to_tail(); }
|
||||||
|
else { _to_tail(i); }
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Insert item 'i' as new tail into list
|
* Insert item 'i' as new tail into list
|
||||||
*/
|
*/
|
||||||
void insert_tail(Item * const i);
|
void insert_tail(Item * const i)
|
||||||
|
{
|
||||||
|
if (_tail) { _tail->_next = i; }
|
||||||
|
else { _head = i; }
|
||||||
|
i->_prev = _tail;
|
||||||
|
i->_next = 0;
|
||||||
|
_tail = i;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Insert item 'i' as new head into list
|
* Insert item 'i' as new head into list
|
||||||
*/
|
*/
|
||||||
void insert_head(Item * const i);
|
void insert_head(Item * const i)
|
||||||
|
{
|
||||||
|
if (_head) { _head->_prev = i; }
|
||||||
|
else { _tail = i; }
|
||||||
|
i->_next = _head;
|
||||||
|
i->_prev = 0;
|
||||||
|
_head = i;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove item 'i' from list
|
* Remove item 'i' from list
|
||||||
*/
|
*/
|
||||||
void remove(Item * const i);
|
void remove(Item * const i)
|
||||||
|
{
|
||||||
|
if (i == _tail) { _tail = i->_prev; }
|
||||||
|
else { i->_next->_prev = i->_prev; }
|
||||||
|
if (i == _head) { _head = i->_next; }
|
||||||
|
else { i->_prev->_next = i->_next; }
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Move head item of list to tail position
|
* Move head item of list to tail position
|
||||||
*/
|
*/
|
||||||
void head_to_tail();
|
void head_to_tail()
|
||||||
|
{
|
||||||
|
if (!_head || _head == _tail) { return; }
|
||||||
|
_head->_prev = _tail;
|
||||||
|
_tail->_next = _head;
|
||||||
|
_head = _head->_next;
|
||||||
|
_head->_prev = 0;
|
||||||
|
_tail = _tail->_next;
|
||||||
|
_tail->_next = 0;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Call function 'f' of type 'void (Item *)' for each item in the list
|
* Call function 'f' of type 'void (Item *)' for each item in the list
|
||||||
*/
|
*/
|
||||||
template <typename F> void for_each(F f) {
|
template <typename F> void for_each(F f) {
|
||||||
for (Item * i = _head; i; i = i->_next) { f(i); } }
|
for (Item * i = _head; i; i = i->_next) { f(i->payload()); } }
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Accessors
|
* Accessors
|
||||||
|
@ -100,30 +152,4 @@ class Kernel::Double_list
|
||||||
static Item * next(Item * const i) { return i->_next; }
|
static Item * next(Item * const i) { return i->_next; }
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T> class Kernel::Double_list_typed : public Double_list
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
|
|
||||||
typedef Double_list_item Item;
|
|
||||||
|
|
||||||
static T * _typed(Item * const i) {
|
|
||||||
return i ? static_cast<T *>(i) : 0; }
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 'Double_list' interface
|
|
||||||
*/
|
|
||||||
|
|
||||||
template <typename F> void for_each(F f) {
|
|
||||||
Double_list::for_each([&] (Item * const i) { f(_typed(i)); }); }
|
|
||||||
|
|
||||||
void to_tail(T * const t) { Double_list::to_tail(t); }
|
|
||||||
void insert_tail(T * const t) { Double_list::insert_tail(t); }
|
|
||||||
void insert_head(T * const t) { Double_list::insert_head(t); }
|
|
||||||
void remove(T * const t) { Double_list::remove(t); }
|
|
||||||
static T * next(T * const t) { return _typed(Double_list::next(t)); }
|
|
||||||
T * head() const { return _typed(Double_list::head()); }
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif /* _CORE__KERNEL__DOUBLE_LIST_H_ */
|
#endif /* _CORE__KERNEL__DOUBLE_LIST_H_ */
|
||||||
|
|
|
@ -19,74 +19,16 @@
|
||||||
#include <base/internal/native_utcb.h>
|
#include <base/internal/native_utcb.h>
|
||||||
|
|
||||||
/* core includes */
|
/* core includes */
|
||||||
#include <platform_pd.h>
|
|
||||||
#include <kernel/ipc_node.h>
|
#include <kernel/ipc_node.h>
|
||||||
#include <kernel/pd.h>
|
|
||||||
#include <kernel/kernel.h>
|
#include <kernel/kernel.h>
|
||||||
#include <kernel/thread.h>
|
#include <kernel/thread.h>
|
||||||
|
|
||||||
using namespace Kernel;
|
using namespace Kernel;
|
||||||
|
|
||||||
|
|
||||||
static inline void free_obj_id_ref(Pd &pd, void *ptr)
|
|
||||||
{
|
|
||||||
pd.platform_pd().capability_slab().free(ptr, sizeof(Object_identity_reference));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Ipc_node::copy_msg(Ipc_node &sender)
|
|
||||||
{
|
|
||||||
using namespace Genode;
|
|
||||||
using Reference = Object_identity_reference;
|
|
||||||
|
|
||||||
/* copy payload and set destination capability id */
|
|
||||||
*_utcb = *sender._utcb;
|
|
||||||
_utcb->destination(sender._capid);
|
|
||||||
|
|
||||||
/* translate capabilities */
|
|
||||||
for (unsigned i = 0; i < _rcv_caps; i++) {
|
|
||||||
|
|
||||||
capid_t id = sender._utcb->cap_get(i);
|
|
||||||
|
|
||||||
/* if there is no capability to send, just free the pre-allocation */
|
|
||||||
if (i >= sender._utcb->cap_cnt()) {
|
|
||||||
free_obj_id_ref(pd(), _obj_id_ref_ptr[i]);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* lookup the capability id within the caller's cap space */
|
|
||||||
Reference *oir = (id == cap_id_invalid())
|
|
||||||
? nullptr : sender.pd().cap_tree().find(id);
|
|
||||||
|
|
||||||
/* if the caller's capability is invalid, free the pre-allocation */
|
|
||||||
if (!oir) {
|
|
||||||
_utcb->cap_add(cap_id_invalid());
|
|
||||||
free_obj_id_ref(pd(), _obj_id_ref_ptr[i]);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* lookup the capability id within the callee's cap space */
|
|
||||||
Reference *dst_oir = oir->find(pd());
|
|
||||||
|
|
||||||
/* if it is not found, and the target is not core, create a reference */
|
|
||||||
if (!dst_oir && (&pd() != &core_pd())) {
|
|
||||||
dst_oir = oir->factory(_obj_id_ref_ptr[i], pd());
|
|
||||||
if (!dst_oir)
|
|
||||||
free_obj_id_ref(pd(), _obj_id_ref_ptr[i]);
|
|
||||||
} else /* otherwise free the pre-allocation */
|
|
||||||
free_obj_id_ref(pd(), _obj_id_ref_ptr[i]);
|
|
||||||
|
|
||||||
if (dst_oir) dst_oir->add_to_utcb();
|
|
||||||
|
|
||||||
/* add the translated capability id to the target buffer */
|
|
||||||
_utcb->cap_add(dst_oir ? dst_oir->capid() : cap_id_invalid());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Ipc_node::_receive_request(Ipc_node &caller)
|
void Ipc_node::_receive_request(Ipc_node &caller)
|
||||||
{
|
{
|
||||||
copy_msg(caller);
|
_thread.ipc_copy_msg(caller._thread);
|
||||||
_caller = &caller;
|
_caller = &caller;
|
||||||
_state = INACTIVE;
|
_state = INACTIVE;
|
||||||
}
|
}
|
||||||
|
@ -94,9 +36,9 @@ void Ipc_node::_receive_request(Ipc_node &caller)
|
||||||
|
|
||||||
void Ipc_node::_receive_reply(Ipc_node &callee)
|
void Ipc_node::_receive_reply(Ipc_node &callee)
|
||||||
{
|
{
|
||||||
copy_msg(callee);
|
_thread.ipc_copy_msg(callee._thread);
|
||||||
_state = INACTIVE;
|
_state = INACTIVE;
|
||||||
_send_request_succeeded();
|
_thread.ipc_send_request_succeeded();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -105,19 +47,21 @@ void Ipc_node::_announce_request(Ipc_node &node)
|
||||||
/* directly receive request if we've awaited it */
|
/* directly receive request if we've awaited it */
|
||||||
if (_state == AWAIT_REQUEST) {
|
if (_state == AWAIT_REQUEST) {
|
||||||
_receive_request(node);
|
_receive_request(node);
|
||||||
_await_request_succeeded();
|
_thread.ipc_await_request_succeeded();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* cannot receive yet, so queue request */
|
/* cannot receive yet, so queue request */
|
||||||
_request_queue.enqueue(node);
|
_request_queue.enqueue(node._request_queue_item);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Ipc_node::_cancel_request_queue()
|
void Ipc_node::_cancel_request_queue()
|
||||||
{
|
{
|
||||||
_request_queue.dequeue_all([] (Ipc_node &node) {
|
_request_queue.dequeue_all([] (Queue_item &item) {
|
||||||
node._outbuf_request_cancelled(); });
|
Ipc_node &node { item.object() };
|
||||||
|
node._outbuf_request_cancelled();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -142,7 +86,7 @@ void Ipc_node::_cancel_inbuf_request()
|
||||||
void Ipc_node::_announced_request_cancelled(Ipc_node &node)
|
void Ipc_node::_announced_request_cancelled(Ipc_node &node)
|
||||||
{
|
{
|
||||||
if (_caller == &node) _caller = nullptr;
|
if (_caller == &node) _caller = nullptr;
|
||||||
else _request_queue.remove(node);
|
else _request_queue.remove(node._request_queue_item);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -152,40 +96,24 @@ void Ipc_node::_outbuf_request_cancelled()
|
||||||
|
|
||||||
_callee = nullptr;
|
_callee = nullptr;
|
||||||
_state = INACTIVE;
|
_state = INACTIVE;
|
||||||
_send_request_failed();
|
_thread.ipc_send_request_failed();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool Ipc_node::_helps_outbuf_dst() { return (_state == AWAIT_REPLY) && _help; }
|
bool Ipc_node::_helps_outbuf_dst() { return (_state == AWAIT_REPLY) && _help; }
|
||||||
|
|
||||||
|
|
||||||
void Ipc_node::_init(Genode::Native_utcb &utcb, Ipc_node &starter)
|
bool Ipc_node::can_send_request()
|
||||||
{
|
{
|
||||||
_utcb = &utcb;
|
return _state == INACTIVE;
|
||||||
_rcv_caps = starter._utcb->cap_cnt();
|
|
||||||
Genode::Allocator &slab = pd().platform_pd().capability_slab();
|
|
||||||
for (unsigned i = 0; i < _rcv_caps; i++)
|
|
||||||
_obj_id_ref_ptr[i] = slab.alloc(sizeof(Object_identity_reference));
|
|
||||||
copy_msg(starter);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Ipc_node::send_request(Ipc_node &callee, capid_t capid, bool help,
|
void Ipc_node::send_request(Ipc_node &callee, bool help)
|
||||||
unsigned rcv_caps)
|
|
||||||
{
|
{
|
||||||
if (_state != INACTIVE) {
|
|
||||||
Genode::raw("IPC send request: bad state");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Genode::Allocator &slab = pd().platform_pd().capability_slab();
|
|
||||||
for (unsigned i = 0; i < rcv_caps; i++)
|
|
||||||
_obj_id_ref_ptr[i] = slab.alloc(sizeof(Object_identity_reference));
|
|
||||||
|
|
||||||
_state = AWAIT_REPLY;
|
_state = AWAIT_REPLY;
|
||||||
_callee = &callee;
|
_callee = &callee;
|
||||||
_capid = capid;
|
|
||||||
_help = false;
|
_help = false;
|
||||||
_rcv_caps = rcv_caps;
|
|
||||||
|
|
||||||
/* announce request */
|
/* announce request */
|
||||||
_callee->_announce_request(*this);
|
_callee->_announce_request(*this);
|
||||||
|
@ -194,32 +122,22 @@ void Ipc_node::send_request(Ipc_node &callee, capid_t capid, bool help,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Ipc_node * Ipc_node::helping_sink() {
|
Thread &Ipc_node::helping_sink() {
|
||||||
return _helps_outbuf_dst() ? _callee->helping_sink() : this; }
|
return _helps_outbuf_dst() ? _callee->helping_sink() : _thread; }
|
||||||
|
|
||||||
|
|
||||||
bool Ipc_node::await_request(unsigned rcv_caps)
|
bool Ipc_node::can_await_request()
|
||||||
{
|
{
|
||||||
if (_state != INACTIVE) {
|
return _state == INACTIVE;
|
||||||
Genode::raw("IPC await request: bad state");
|
}
|
||||||
return true;
|
|
||||||
}
|
|
||||||
Genode::Allocator &slab = pd().platform_pd().capability_slab();
|
|
||||||
for (unsigned i = 0; i < rcv_caps; i++)
|
|
||||||
_obj_id_ref_ptr[i] = slab.alloc(sizeof(Object_identity_reference));
|
|
||||||
|
|
||||||
_rcv_caps = rcv_caps;
|
|
||||||
|
|
||||||
/* if no request announced then wait */
|
void Ipc_node::await_request()
|
||||||
bool announced = false;
|
{
|
||||||
_state = AWAIT_REQUEST;
|
_state = AWAIT_REQUEST;
|
||||||
|
_request_queue.dequeue([&] (Queue_item &item) {
|
||||||
/* if anybody already announced a request receive it */
|
_receive_request(item.object());
|
||||||
_request_queue.dequeue([&] (Ipc_node &ipc) {
|
|
||||||
_receive_request(ipc);
|
|
||||||
announced = true;
|
|
||||||
});
|
});
|
||||||
return announced;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -239,11 +157,11 @@ void Ipc_node::cancel_waiting()
|
||||||
case AWAIT_REPLY:
|
case AWAIT_REPLY:
|
||||||
_cancel_outbuf_request();
|
_cancel_outbuf_request();
|
||||||
_state = INACTIVE;
|
_state = INACTIVE;
|
||||||
_send_request_failed();
|
_thread.ipc_send_request_failed();
|
||||||
break;
|
break;
|
||||||
case AWAIT_REQUEST:
|
case AWAIT_REQUEST:
|
||||||
_state = INACTIVE;
|
_state = INACTIVE;
|
||||||
_await_request_failed();
|
_thread.ipc_await_request_failed();
|
||||||
break;
|
break;
|
||||||
return;
|
return;
|
||||||
default: return;
|
default: return;
|
||||||
|
@ -251,6 +169,12 @@ void Ipc_node::cancel_waiting()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Ipc_node::Ipc_node(Thread &thread)
|
||||||
|
:
|
||||||
|
_thread(thread)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
|
||||||
Ipc_node::~Ipc_node()
|
Ipc_node::~Ipc_node()
|
||||||
{
|
{
|
||||||
_cancel_request_queue();
|
_cancel_request_queue();
|
||||||
|
|
|
@ -15,30 +15,25 @@
|
||||||
#ifndef _CORE__KERNEL__IPC_NODE_H_
|
#ifndef _CORE__KERNEL__IPC_NODE_H_
|
||||||
#define _CORE__KERNEL__IPC_NODE_H_
|
#define _CORE__KERNEL__IPC_NODE_H_
|
||||||
|
|
||||||
/* base-local includes */
|
/* Genode includes */
|
||||||
#include <base/internal/native_utcb.h>
|
#include <util/fifo.h>
|
||||||
|
|
||||||
/* core includes */
|
|
||||||
#include <kernel/interface.h>
|
|
||||||
#include <assertion.h>
|
|
||||||
|
|
||||||
namespace Genode { class Msgbuf_base; };
|
|
||||||
|
|
||||||
namespace Kernel
|
namespace Kernel
|
||||||
{
|
{
|
||||||
class Pd;
|
class Thread;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Backend for end points of synchronous interprocess communication
|
* Backend for end points of synchronous interprocess communication
|
||||||
*/
|
*/
|
||||||
class Ipc_node;
|
class Ipc_node;
|
||||||
|
|
||||||
using Ipc_node_queue = Genode::Fifo<Ipc_node>;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class Kernel::Ipc_node : private Ipc_node_queue::Element
|
class Kernel::Ipc_node
|
||||||
{
|
{
|
||||||
protected:
|
private:
|
||||||
|
|
||||||
|
using Queue_item = Genode::Fifo_element<Ipc_node>;
|
||||||
|
using Queue = Genode::Fifo<Queue_item>;
|
||||||
|
|
||||||
enum State
|
enum State
|
||||||
{
|
{
|
||||||
|
@ -47,26 +42,13 @@ class Kernel::Ipc_node : private Ipc_node_queue::Element
|
||||||
AWAIT_REQUEST = 3,
|
AWAIT_REQUEST = 3,
|
||||||
};
|
};
|
||||||
|
|
||||||
void _init(Genode::Native_utcb &utcb, Ipc_node &callee);
|
Thread &_thread;
|
||||||
|
Queue_item _request_queue_item { *this };
|
||||||
private:
|
State _state { INACTIVE };
|
||||||
|
Ipc_node *_caller { nullptr };
|
||||||
friend class Core_thread;
|
Ipc_node *_callee { nullptr };
|
||||||
friend class Genode::Fifo<Ipc_node>;
|
bool _help { false };
|
||||||
|
Queue _request_queue { };
|
||||||
State _state = INACTIVE;
|
|
||||||
capid_t _capid = cap_id_invalid();
|
|
||||||
Ipc_node * _caller = nullptr;
|
|
||||||
Ipc_node * _callee = nullptr;
|
|
||||||
bool _help = false;
|
|
||||||
size_t _rcv_caps = 0; /* max capability num to receive */
|
|
||||||
Genode::Native_utcb * _utcb = nullptr;
|
|
||||||
Ipc_node_queue _request_queue { };
|
|
||||||
|
|
||||||
/* pre-allocation array for obkject identity references */
|
|
||||||
void * _obj_id_ref_ptr[Genode::Msgbuf_base::MAX_CAPS_PER_MSG];
|
|
||||||
|
|
||||||
inline void copy_msg(Ipc_node &sender);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Buffer next request from request queue in 'r' to handle it
|
* Buffer next request from request queue in 'r' to handle it
|
||||||
|
@ -114,40 +96,26 @@ class Kernel::Ipc_node : private Ipc_node_queue::Element
|
||||||
bool _helps_outbuf_dst();
|
bool _helps_outbuf_dst();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* IPC node returned from waiting due to reply receipt
|
* Make the class noncopyable because it has pointer members
|
||||||
*/
|
*/
|
||||||
virtual void _send_request_succeeded() = 0;
|
Ipc_node(const Ipc_node&) = delete;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* IPC node returned from waiting due to reply cancellation
|
* Make the class noncopyable because it has pointer members
|
||||||
*/
|
*/
|
||||||
virtual void _send_request_failed() = 0;
|
const Ipc_node& operator=(const Ipc_node&) = delete;
|
||||||
|
|
||||||
/**
|
|
||||||
* IPC node returned from waiting due to request receipt
|
|
||||||
*/
|
|
||||||
virtual void _await_request_succeeded() = 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* IPC node returned from waiting due to request cancellation
|
|
||||||
*/
|
|
||||||
virtual void _await_request_failed() = 0;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
Pd * _pd = nullptr; /* pointer to PD this IPC node is part of */
|
|
||||||
|
|
||||||
|
|
||||||
/***************
|
|
||||||
** Accessors **
|
|
||||||
***************/
|
|
||||||
|
|
||||||
Ipc_node * callee() { return _callee; }
|
|
||||||
State state() { return _state; }
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
virtual ~Ipc_node();
|
/**
|
||||||
|
* Destructor
|
||||||
|
*/
|
||||||
|
~Ipc_node();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
*/
|
||||||
|
Ipc_node(Thread &thread);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send a request and wait for the according reply
|
* Send a request and wait for the according reply
|
||||||
|
@ -155,13 +123,14 @@ class Kernel::Ipc_node : private Ipc_node_queue::Element
|
||||||
* \param callee targeted IPC node
|
* \param callee targeted IPC node
|
||||||
* \param help wether the request implies a helping relationship
|
* \param help wether the request implies a helping relationship
|
||||||
*/
|
*/
|
||||||
void send_request(Ipc_node &callee, capid_t capid, bool help,
|
bool can_send_request();
|
||||||
unsigned rcv_caps);
|
void send_request(Ipc_node &callee,
|
||||||
|
bool help);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return root destination of the helping-relation tree we are in
|
* Return root destination of the helping-relation tree we are in
|
||||||
*/
|
*/
|
||||||
Ipc_node * helping_sink();
|
Thread &helping_sink();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Call function 'f' of type 'void (Ipc_node *)' for each helper
|
* Call function 'f' of type 'void (Ipc_node *)' for each helper
|
||||||
|
@ -169,11 +138,13 @@ class Kernel::Ipc_node : private Ipc_node_queue::Element
|
||||||
template <typename F> void for_each_helper(F f)
|
template <typename F> void for_each_helper(F f)
|
||||||
{
|
{
|
||||||
/* if we have a helper in the receive buffer, call 'f' for it */
|
/* if we have a helper in the receive buffer, call 'f' for it */
|
||||||
if (_caller && _caller->_help) f(*_caller);
|
if (_caller && _caller->_help) f(_caller->_thread);
|
||||||
|
|
||||||
/* call 'f' for each helper in our request queue */
|
/* call 'f' for each helper in our request queue */
|
||||||
_request_queue.for_each([f] (Ipc_node &node) {
|
_request_queue.for_each([f] (Queue_item &item) {
|
||||||
if (node._help) f(node); });
|
Ipc_node &node { item.object() };
|
||||||
|
if (node._help) f(node._thread);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -181,7 +152,8 @@ class Kernel::Ipc_node : private Ipc_node_queue::Element
|
||||||
*
|
*
|
||||||
* \return wether a request could be received already
|
* \return wether a request could be received already
|
||||||
*/
|
*/
|
||||||
bool await_request(unsigned rcv_caps);
|
bool can_await_request();
|
||||||
|
void await_request();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reply to last request if there's any
|
* Reply to last request if there's any
|
||||||
|
@ -193,20 +165,7 @@ class Kernel::Ipc_node : private Ipc_node_queue::Element
|
||||||
*/
|
*/
|
||||||
void cancel_waiting();
|
void cancel_waiting();
|
||||||
|
|
||||||
|
bool awaits_request() const { return _state == AWAIT_REQUEST; }
|
||||||
/***************
|
|
||||||
** Accessors **
|
|
||||||
***************/
|
|
||||||
|
|
||||||
Pd &pd() const
|
|
||||||
{
|
|
||||||
if (_pd)
|
|
||||||
return *_pd;
|
|
||||||
|
|
||||||
ASSERT_NEVER_CALLED;
|
|
||||||
}
|
|
||||||
|
|
||||||
Genode::Native_utcb *utcb() { return _utcb; }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* _CORE__KERNEL__IPC_NODE_H_ */
|
#endif /* _CORE__KERNEL__IPC_NODE_H_ */
|
||||||
|
|
|
@ -119,10 +119,11 @@ class Kernel::Irq : Genode::Avl_node<Irq>
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class Kernel::User_irq : public Kernel::Irq, public Kernel::Object
|
class Kernel::User_irq : public Kernel::Irq
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
Kernel::Object _kernel_object { *this };
|
||||||
Signal_context &_context;
|
Signal_context &_context;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -150,7 +151,9 @@ class Kernel::User_irq : public Kernel::Irq, public Kernel::Object
|
||||||
*/
|
*/
|
||||||
void occurred() override
|
void occurred() override
|
||||||
{
|
{
|
||||||
_context.submit(1);
|
if (_context.can_submit(1)) {
|
||||||
|
_context.submit(1);
|
||||||
|
}
|
||||||
disable();
|
disable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -186,6 +189,8 @@ class Kernel::User_irq : public Kernel::Irq, public Kernel::Object
|
||||||
*/
|
*/
|
||||||
static void syscall_destroy(Genode::Kernel_object<User_irq> &irq) {
|
static void syscall_destroy(Genode::Kernel_object<User_irq> &irq) {
|
||||||
call(call_id_delete_irq(), (Call_arg) &irq); }
|
call(call_id_delete_irq(), (Call_arg) &irq); }
|
||||||
|
|
||||||
|
Object &kernel_object() { return _kernel_object; }
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* _CORE__KERNEL__IRQ_H_ */
|
#endif /* _CORE__KERNEL__IRQ_H_ */
|
||||||
|
|
|
@ -11,12 +11,99 @@ using namespace Kernel;
|
||||||
** Object **
|
** Object **
|
||||||
************/
|
************/
|
||||||
|
|
||||||
|
Object::Object(Thread &obj)
|
||||||
|
:
|
||||||
|
_type { THREAD },
|
||||||
|
_obj { (void *)&obj }
|
||||||
|
{ }
|
||||||
|
|
||||||
|
Object::Object(Irq &obj)
|
||||||
|
:
|
||||||
|
_type { IRQ },
|
||||||
|
_obj { (void *)&obj }
|
||||||
|
{ }
|
||||||
|
|
||||||
|
Object::Object(Signal_receiver &obj)
|
||||||
|
:
|
||||||
|
_type { SIGNAL_RECEIVER },
|
||||||
|
_obj { (void *)&obj }
|
||||||
|
{ }
|
||||||
|
|
||||||
|
Object::Object(Signal_context &obj)
|
||||||
|
:
|
||||||
|
_type { SIGNAL_CONTEXT },
|
||||||
|
_obj { (void *)&obj }
|
||||||
|
{ }
|
||||||
|
|
||||||
|
Object::Object(Pd &obj)
|
||||||
|
:
|
||||||
|
_type { PD },
|
||||||
|
_obj { (void *)&obj }
|
||||||
|
{ }
|
||||||
|
|
||||||
|
Object::Object(Vm &obj)
|
||||||
|
:
|
||||||
|
_type { VM },
|
||||||
|
_obj { (void *)&obj }
|
||||||
|
{ }
|
||||||
|
|
||||||
Object::~Object()
|
Object::~Object()
|
||||||
{
|
{
|
||||||
for (Object_identity * oi = first(); oi; oi = first())
|
for (Object_identity * oi = first(); oi; oi = first())
|
||||||
oi->invalidate();
|
oi->invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace Kernel {
|
||||||
|
|
||||||
|
template <> Pd *Object::obj<Pd>() const
|
||||||
|
{
|
||||||
|
if (_type != PD) {
|
||||||
|
return nullptr; }
|
||||||
|
|
||||||
|
return reinterpret_cast<Pd *>(_obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <> Irq *Object::obj<Irq>() const
|
||||||
|
{
|
||||||
|
if (_type != IRQ) {
|
||||||
|
return nullptr; }
|
||||||
|
|
||||||
|
return reinterpret_cast<Irq *>(_obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <> Signal_receiver *Object::obj<Signal_receiver>() const
|
||||||
|
{
|
||||||
|
if (_type != SIGNAL_RECEIVER) {
|
||||||
|
return nullptr; }
|
||||||
|
|
||||||
|
return reinterpret_cast<Signal_receiver *>(_obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <> Signal_context *Object::obj<Signal_context>() const
|
||||||
|
{
|
||||||
|
if (_type != SIGNAL_CONTEXT) {
|
||||||
|
return nullptr; }
|
||||||
|
|
||||||
|
return reinterpret_cast<Signal_context *>(_obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <> Thread *Object::obj<Thread>() const
|
||||||
|
{
|
||||||
|
if (_type != THREAD) {
|
||||||
|
return nullptr; }
|
||||||
|
|
||||||
|
return reinterpret_cast<Thread *>(_obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <> Vm *Object::obj<Vm>() const
|
||||||
|
{
|
||||||
|
if (_type != VM) {
|
||||||
|
return nullptr; }
|
||||||
|
|
||||||
|
return reinterpret_cast<Vm *>(_obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*********************
|
/*********************
|
||||||
** Object_identity **
|
** Object_identity **
|
||||||
|
|
|
@ -27,7 +27,16 @@
|
||||||
|
|
||||||
namespace Kernel
|
namespace Kernel
|
||||||
{
|
{
|
||||||
class Pd; /* forward declaration */
|
/*
|
||||||
|
* Forward declarations
|
||||||
|
*/
|
||||||
|
|
||||||
|
class Pd;
|
||||||
|
class Irq;
|
||||||
|
class Thread;
|
||||||
|
class Signal_context;
|
||||||
|
class Signal_receiver;
|
||||||
|
class Vm;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base class of all Kernel objects
|
* Base class of all Kernel objects
|
||||||
|
@ -73,12 +82,39 @@ namespace Kernel
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
struct Kernel::Object : private Object_identity_list
|
class Kernel::Object : private Object_identity_list
|
||||||
{
|
{
|
||||||
using Object_identity_list::remove;
|
private:
|
||||||
using Object_identity_list::insert;
|
|
||||||
|
|
||||||
virtual ~Object();
|
enum Type { THREAD, PD, SIGNAL_RECEIVER, SIGNAL_CONTEXT, IRQ, VM };
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Noncopyable
|
||||||
|
*/
|
||||||
|
Object(Object const &) = delete;
|
||||||
|
Object &operator = (Object const &) = delete;
|
||||||
|
|
||||||
|
Type const _type;
|
||||||
|
void *const _obj;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
struct Cannot_cast_to_type : Genode::Exception { };
|
||||||
|
|
||||||
|
using Object_identity_list::remove;
|
||||||
|
using Object_identity_list::insert;
|
||||||
|
|
||||||
|
Object(Thread &obj);
|
||||||
|
Object(Irq &obj);
|
||||||
|
Object(Signal_receiver &obj);
|
||||||
|
Object(Signal_context &obj);
|
||||||
|
Object(Pd &obj);
|
||||||
|
Object(Vm &obj);
|
||||||
|
|
||||||
|
~Object();
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
T *obj() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -102,7 +138,7 @@ class Kernel::Object_identity
|
||||||
~Object_identity();
|
~Object_identity();
|
||||||
|
|
||||||
template <typename KOBJECT>
|
template <typename KOBJECT>
|
||||||
KOBJECT * object() { return dynamic_cast<KOBJECT*>(_object); }
|
KOBJECT * object() { return _object->obj<KOBJECT>(); }
|
||||||
|
|
||||||
void invalidate();
|
void invalidate();
|
||||||
};
|
};
|
||||||
|
@ -190,7 +226,7 @@ class Kernel::Core_object_identity : public Object_identity,
|
||||||
public:
|
public:
|
||||||
|
|
||||||
Core_object_identity(T & object)
|
Core_object_identity(T & object)
|
||||||
: Object_identity(object),
|
: Object_identity(object.kernel_object()),
|
||||||
Object_identity_reference(this, core_pd()) { }
|
Object_identity_reference(this, core_pd()) { }
|
||||||
|
|
||||||
capid_t core_capid() { return capid(); }
|
capid_t core_capid() { return capid(); }
|
||||||
|
|
|
@ -39,7 +39,7 @@ namespace Kernel
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class Kernel::Pd : public Kernel::Object
|
class Kernel::Pd
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
@ -49,6 +49,7 @@ class Kernel::Pd : public Kernel::Object
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
Kernel::Object _kernel_object { *this };
|
||||||
Hw::Page_table &_table;
|
Hw::Page_table &_table;
|
||||||
Genode::Platform_pd &_platform_pd;
|
Genode::Platform_pd &_platform_pd;
|
||||||
Capid_allocator _capid_alloc { };
|
Capid_allocator _capid_alloc { };
|
||||||
|
@ -108,6 +109,7 @@ class Kernel::Pd : public Kernel::Object
|
||||||
** Accessors **
|
** Accessors **
|
||||||
***************/
|
***************/
|
||||||
|
|
||||||
|
Object &kernel_object() { return _kernel_object; }
|
||||||
Genode::Platform_pd &platform_pd() { return _platform_pd; }
|
Genode::Platform_pd &platform_pd() { return _platform_pd; }
|
||||||
Hw::Page_table &translation_table() { return _table; }
|
Hw::Page_table &translation_table() { return _table; }
|
||||||
Capid_allocator &capid_alloc() { return _capid_alloc; }
|
Capid_allocator &capid_alloc() { return _capid_alloc; }
|
||||||
|
@ -118,7 +120,7 @@ class Kernel::Pd : public Kernel::Object
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
inline Kernel::Core_object_identity<Kernel::Pd>::Core_object_identity(Kernel::Pd & pd)
|
inline Kernel::Core_object_identity<Kernel::Pd>::Core_object_identity(Kernel::Pd & pd)
|
||||||
: Object_identity(pd),
|
: Object_identity(pd.kernel_object()),
|
||||||
Object_identity_reference(this, pd.core_pd() ? pd : core_pd()) { }
|
Object_identity_reference(this, pd.core_pd() ? pd : core_pd()) { }
|
||||||
|
|
||||||
#endif /* _CORE__KERNEL__PD_H_ */
|
#endif /* _CORE__KERNEL__PD_H_ */
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
|
|
||||||
/* core includes */
|
/* core includes */
|
||||||
#include <kernel/signal_receiver.h>
|
#include <kernel/signal_receiver.h>
|
||||||
|
#include <kernel/thread.h>
|
||||||
|
|
||||||
using namespace Kernel;
|
using namespace Kernel;
|
||||||
|
|
||||||
|
@ -24,12 +25,14 @@ using namespace Kernel;
|
||||||
void Signal_handler::cancel_waiting()
|
void Signal_handler::cancel_waiting()
|
||||||
{
|
{
|
||||||
if (_receiver) {
|
if (_receiver) {
|
||||||
_receiver->_handler_cancelled(this);
|
_receiver->_handler_cancelled(*this);
|
||||||
_receiver = 0;
|
_receiver = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Signal_handler::Signal_handler(Thread &thread) : _thread { thread } { }
|
||||||
|
|
||||||
Signal_handler::~Signal_handler() { cancel_waiting(); }
|
Signal_handler::~Signal_handler() { cancel_waiting(); }
|
||||||
|
|
||||||
|
|
||||||
|
@ -43,7 +46,10 @@ void Signal_context_killer::cancel_waiting()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Signal_context_killer::Signal_context_killer() : _context(nullptr) { }
|
Signal_context_killer::Signal_context_killer(Thread &thread)
|
||||||
|
:
|
||||||
|
_thread { thread }
|
||||||
|
{ }
|
||||||
|
|
||||||
|
|
||||||
Signal_context_killer::~Signal_context_killer() { cancel_waiting(); }
|
Signal_context_killer::~Signal_context_killer() { cancel_waiting(); }
|
||||||
|
@ -55,7 +61,7 @@ Signal_context_killer::~Signal_context_killer() { cancel_waiting(); }
|
||||||
|
|
||||||
void Signal_context::_deliverable()
|
void Signal_context::_deliverable()
|
||||||
{
|
{
|
||||||
if (_submits) { _receiver._add_deliverable(this); }
|
if (_submits) { _receiver._add_deliverable(*this); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -69,12 +75,18 @@ void Signal_context::_delivered()
|
||||||
void Signal_context::_killer_cancelled() { _killer = 0; }
|
void Signal_context::_killer_cancelled() { _killer = 0; }
|
||||||
|
|
||||||
|
|
||||||
int Signal_context::submit(unsigned const n)
|
bool Signal_context::can_submit(unsigned const n) const
|
||||||
{
|
{
|
||||||
if (_killed || _submits >= (unsigned)~0 - n) { return -1; }
|
if (_killed || _submits >= (unsigned)~0 - n) { return false; }
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Signal_context::submit(unsigned const n)
|
||||||
|
{
|
||||||
|
if (_killed || _submits >= (unsigned)~0 - n) { return; }
|
||||||
_submits += n;
|
_submits += n;
|
||||||
if (_ack) { _deliverable(); }
|
if (_ack) { _deliverable(); }
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -88,37 +100,46 @@ void Signal_context::ack()
|
||||||
}
|
}
|
||||||
if (_killer) {
|
if (_killer) {
|
||||||
_killer->_context = 0;
|
_killer->_context = 0;
|
||||||
_killer->_signal_context_kill_done();
|
_killer->_thread.signal_context_kill_done();
|
||||||
_killer = 0;
|
_killer = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int Signal_context::kill(Signal_context_killer * const k)
|
bool Signal_context::can_kill() const
|
||||||
{
|
{
|
||||||
/* check if in a kill operation or already killed */
|
/* check if in a kill operation or already killed */
|
||||||
if (_killed) {
|
if (_killed) {
|
||||||
if (_ack) { return 0; }
|
if (_ack) { return true; }
|
||||||
return -1;
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Signal_context::kill(Signal_context_killer &k)
|
||||||
|
{
|
||||||
|
/* check if in a kill operation or already killed */
|
||||||
|
if (_killed) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
/* kill directly if there is no unacknowledged delivery */
|
/* kill directly if there is no unacknowledged delivery */
|
||||||
if (_ack) {
|
if (_ack) {
|
||||||
_killed = 1;
|
_killed = 1;
|
||||||
return 0;
|
return;
|
||||||
}
|
}
|
||||||
/* wait for delivery acknowledgement */
|
/* wait for delivery acknowledgement */
|
||||||
_killer = k;
|
_killer = &k;
|
||||||
_killed = 1;
|
_killed = 1;
|
||||||
_killer->_context = this;
|
_killer->_context = this;
|
||||||
_killer->_signal_context_kill_pending();
|
_killer->_thread.signal_context_kill_pending();
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Signal_context::~Signal_context()
|
Signal_context::~Signal_context()
|
||||||
{
|
{
|
||||||
if (_killer) { _killer->_signal_context_kill_failed(); }
|
if (_killer) { _killer->_thread.signal_context_kill_failed(); }
|
||||||
_receiver._context_destructed(this);
|
_receiver._context_destructed(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -126,7 +147,7 @@ Signal_context::Signal_context(Signal_receiver & r, addr_t const imprint)
|
||||||
: _receiver(r),
|
: _receiver(r),
|
||||||
_imprint(imprint)
|
_imprint(imprint)
|
||||||
{
|
{
|
||||||
r._add_context(this);
|
r._add_context(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -134,10 +155,10 @@ Signal_context::Signal_context(Signal_receiver & r, addr_t const imprint)
|
||||||
** Signal_receiver **
|
** Signal_receiver **
|
||||||
*********************/
|
*********************/
|
||||||
|
|
||||||
void Signal_receiver::_add_deliverable(Signal_context * const c)
|
void Signal_receiver::_add_deliverable(Signal_context &c)
|
||||||
{
|
{
|
||||||
if (!c->_deliver_fe.enqueued()) {
|
if (!c._deliver_fe.enqueued()) {
|
||||||
_deliver.enqueue(c->_deliver_fe);
|
_deliver.enqueue(c._deliver_fe);
|
||||||
}
|
}
|
||||||
_listen();
|
_listen();
|
||||||
}
|
}
|
||||||
|
@ -164,7 +185,7 @@ void Signal_receiver::_listen()
|
||||||
_handlers.dequeue([&] (Signal_handler::Fifo_element &elem) {
|
_handlers.dequeue([&] (Signal_handler::Fifo_element &elem) {
|
||||||
auto const handler = &elem.object();
|
auto const handler = &elem.object();
|
||||||
handler->_receiver = nullptr;
|
handler->_receiver = nullptr;
|
||||||
handler->_receive_signal(&data, sizeof(data));
|
handler->_thread.signal_receive_signal(&data, sizeof(data));
|
||||||
});
|
});
|
||||||
context->_delivered();
|
context->_delivered();
|
||||||
});
|
});
|
||||||
|
@ -172,30 +193,36 @@ void Signal_receiver::_listen()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Signal_receiver::_context_destructed(Signal_context * const c)
|
void Signal_receiver::_context_destructed(Signal_context &c)
|
||||||
{
|
{
|
||||||
_contexts.remove(c->_contexts_fe);
|
_contexts.remove(c._contexts_fe);
|
||||||
if (!c->_deliver_fe.enqueued()) { return; }
|
if (!c._deliver_fe.enqueued()) { return; }
|
||||||
_deliver.remove(c->_deliver_fe);
|
_deliver.remove(c._deliver_fe);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Signal_receiver::_handler_cancelled(Signal_handler * const h) {
|
void Signal_receiver::_handler_cancelled(Signal_handler &h) {
|
||||||
_handlers.remove(h->_handlers_fe); }
|
_handlers.remove(h._handlers_fe); }
|
||||||
|
|
||||||
|
|
||||||
void Signal_receiver::_add_context(Signal_context * const c) {
|
void Signal_receiver::_add_context(Signal_context &c) {
|
||||||
_contexts.enqueue(c->_contexts_fe); }
|
_contexts.enqueue(c._contexts_fe); }
|
||||||
|
|
||||||
|
|
||||||
int Signal_receiver::add_handler(Signal_handler * const h)
|
bool Signal_receiver::can_add_handler(Signal_handler const &h) const
|
||||||
{
|
{
|
||||||
if (h->_receiver) { return -1; }
|
if (h._receiver) { return false; }
|
||||||
_handlers.enqueue(h->_handlers_fe);
|
return true;
|
||||||
h->_receiver = this;
|
}
|
||||||
h->_await_signal(this);
|
|
||||||
|
|
||||||
|
void Signal_receiver::add_handler(Signal_handler &h)
|
||||||
|
{
|
||||||
|
if (h._receiver) { return; }
|
||||||
|
_handlers.enqueue(h._handlers_fe);
|
||||||
|
h._receiver = this;
|
||||||
|
h._thread.signal_wait_for_signal();
|
||||||
_listen();
|
_listen();
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,8 @@
|
||||||
|
|
||||||
namespace Kernel
|
namespace Kernel
|
||||||
{
|
{
|
||||||
|
class Thread;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ability to receive signals from signal receivers
|
* Ability to receive signals from signal receivers
|
||||||
*/
|
*/
|
||||||
|
@ -59,36 +61,15 @@ class Kernel::Signal_handler
|
||||||
|
|
||||||
typedef Genode::Fifo_element<Signal_handler> Fifo_element;
|
typedef Genode::Fifo_element<Signal_handler> Fifo_element;
|
||||||
|
|
||||||
Fifo_element _handlers_fe { *this };
|
Thread &_thread;
|
||||||
Signal_receiver * _receiver { nullptr };
|
Fifo_element _handlers_fe { *this };
|
||||||
|
Signal_receiver *_receiver { nullptr };
|
||||||
/**
|
|
||||||
* Let the handler block for signal receipt
|
|
||||||
*
|
|
||||||
* \param receiver the signal pool that the thread blocks for
|
|
||||||
*/
|
|
||||||
virtual void _await_signal(Signal_receiver * const receiver) = 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Signal delivery backend
|
|
||||||
*
|
|
||||||
* \param base signal-data base
|
|
||||||
* \param size signal-data size
|
|
||||||
*/
|
|
||||||
virtual void _receive_signal(void * const base, size_t const size) = 0;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
/***************
|
|
||||||
** Accessors **
|
|
||||||
***************/
|
|
||||||
|
|
||||||
Signal_receiver * receiver() const { return _receiver; }
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
Signal_handler() { }
|
Signal_handler(Thread &thread);
|
||||||
virtual ~Signal_handler();
|
|
||||||
|
~Signal_handler();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stop waiting for a signal receiver
|
* Stop waiting for a signal receiver
|
||||||
|
@ -108,35 +89,14 @@ class Kernel::Signal_context_killer
|
||||||
Signal_context_killer(Signal_context_killer const &);
|
Signal_context_killer(Signal_context_killer const &);
|
||||||
Signal_context_killer &operator = (Signal_context_killer const &);
|
Signal_context_killer &operator = (Signal_context_killer const &);
|
||||||
|
|
||||||
Signal_context * _context;
|
Thread &_thread;
|
||||||
|
Signal_context *_context { nullptr };
|
||||||
/**
|
|
||||||
* Notice that the kill operation is pending
|
|
||||||
*/
|
|
||||||
virtual void _signal_context_kill_pending() = 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Notice that pending kill operation is done
|
|
||||||
*/
|
|
||||||
virtual void _signal_context_kill_done() = 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Notice that pending kill operation failed
|
|
||||||
*/
|
|
||||||
virtual void _signal_context_kill_failed() = 0;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
/***************
|
|
||||||
** Accessors **
|
|
||||||
***************/
|
|
||||||
|
|
||||||
Signal_context * context() const { return _context; }
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
Signal_context_killer();
|
Signal_context_killer(Thread &thread);
|
||||||
virtual ~Signal_context_killer();
|
|
||||||
|
~Signal_context_killer();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stop waiting for a signal context
|
* Stop waiting for a signal context
|
||||||
|
@ -144,7 +104,7 @@ class Kernel::Signal_context_killer
|
||||||
void cancel_waiting();
|
void cancel_waiting();
|
||||||
};
|
};
|
||||||
|
|
||||||
class Kernel::Signal_context : public Kernel::Object
|
class Kernel::Signal_context
|
||||||
{
|
{
|
||||||
friend class Signal_receiver;
|
friend class Signal_receiver;
|
||||||
friend class Signal_context_killer;
|
friend class Signal_context_killer;
|
||||||
|
@ -159,14 +119,15 @@ class Kernel::Signal_context : public Kernel::Object
|
||||||
|
|
||||||
typedef Genode::Fifo_element<Signal_context> Fifo_element;
|
typedef Genode::Fifo_element<Signal_context> Fifo_element;
|
||||||
|
|
||||||
Fifo_element _deliver_fe { *this };
|
Kernel::Object _kernel_object { *this };
|
||||||
Fifo_element _contexts_fe { *this };
|
Fifo_element _deliver_fe { *this };
|
||||||
|
Fifo_element _contexts_fe { *this };
|
||||||
Signal_receiver & _receiver;
|
Signal_receiver & _receiver;
|
||||||
addr_t const _imprint;
|
addr_t const _imprint;
|
||||||
Signal_context_killer * _killer { nullptr };
|
Signal_context_killer * _killer { nullptr };
|
||||||
unsigned _submits { 0 };
|
unsigned _submits { 0 };
|
||||||
bool _ack { true };
|
bool _ack { true };
|
||||||
bool _killed { false };
|
bool _killed { false };
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tell receiver about the submits of the context if any
|
* Tell receiver about the submits of the context if any
|
||||||
|
@ -208,7 +169,8 @@ class Kernel::Signal_context : public Kernel::Object
|
||||||
* \retval 0 succeeded
|
* \retval 0 succeeded
|
||||||
* \retval -1 failed
|
* \retval -1 failed
|
||||||
*/
|
*/
|
||||||
int submit(unsigned const n);
|
bool can_submit(unsigned const n) const;
|
||||||
|
void submit(unsigned const n);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Acknowledge delivery of signal
|
* Acknowledge delivery of signal
|
||||||
|
@ -223,7 +185,8 @@ class Kernel::Signal_context : public Kernel::Object
|
||||||
* \retval 0 succeeded
|
* \retval 0 succeeded
|
||||||
* \retval -1 failed
|
* \retval -1 failed
|
||||||
*/
|
*/
|
||||||
int kill(Signal_context_killer * const k);
|
bool can_kill() const;
|
||||||
|
void kill(Signal_context_killer &k);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a signal context and assign it to a signal receiver
|
* Create a signal context and assign it to a signal receiver
|
||||||
|
@ -249,9 +212,11 @@ class Kernel::Signal_context : public Kernel::Object
|
||||||
*/
|
*/
|
||||||
static void syscall_destroy(Genode::Kernel_object<Signal_context> &c) {
|
static void syscall_destroy(Genode::Kernel_object<Signal_context> &c) {
|
||||||
call(call_id_delete_signal_context(), (Call_arg)&c); }
|
call(call_id_delete_signal_context(), (Call_arg)&c); }
|
||||||
|
|
||||||
|
Object &kernel_object() { return _kernel_object; }
|
||||||
};
|
};
|
||||||
|
|
||||||
class Kernel::Signal_receiver : public Kernel::Object
|
class Kernel::Signal_receiver
|
||||||
{
|
{
|
||||||
friend class Signal_context;
|
friend class Signal_context;
|
||||||
friend class Signal_handler;
|
friend class Signal_handler;
|
||||||
|
@ -262,14 +227,15 @@ class Kernel::Signal_receiver : public Kernel::Object
|
||||||
|
|
||||||
template <typename T> class Fifo : public Genode::Fifo<T> { };
|
template <typename T> class Fifo : public Genode::Fifo<T> { };
|
||||||
|
|
||||||
Fifo<Signal_handler::Fifo_element> _handlers { };
|
Kernel::Object _kernel_object { *this };
|
||||||
Fifo<Signal_context::Fifo_element> _deliver { };
|
Fifo<Signal_handler::Fifo_element> _handlers { };
|
||||||
Fifo<Signal_context::Fifo_element> _contexts { };
|
Fifo<Signal_context::Fifo_element> _deliver { };
|
||||||
|
Fifo<Signal_context::Fifo_element> _contexts { };
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Recognize that context 'c' has submits to deliver
|
* Recognize that context 'c' has submits to deliver
|
||||||
*/
|
*/
|
||||||
void _add_deliverable(Signal_context * const c);
|
void _add_deliverable(Signal_context &c);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deliver as much submits as possible
|
* Deliver as much submits as possible
|
||||||
|
@ -281,17 +247,17 @@ class Kernel::Signal_receiver : public Kernel::Object
|
||||||
*
|
*
|
||||||
* \param c destructed context
|
* \param c destructed context
|
||||||
*/
|
*/
|
||||||
void _context_destructed(Signal_context * const c);
|
void _context_destructed(Signal_context &c);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Notice that handler 'h' has cancelled waiting
|
* Notice that handler 'h' has cancelled waiting
|
||||||
*/
|
*/
|
||||||
void _handler_cancelled(Signal_handler * const h);
|
void _handler_cancelled(Signal_handler &h);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Assign context 'c' to the receiver
|
* Assign context 'c' to the receiver
|
||||||
*/
|
*/
|
||||||
void _add_context(Signal_context * const c);
|
void _add_context(Signal_context &c);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
@ -303,7 +269,8 @@ class Kernel::Signal_receiver : public Kernel::Object
|
||||||
* \retval 0 succeeded
|
* \retval 0 succeeded
|
||||||
* \retval -1 failed
|
* \retval -1 failed
|
||||||
*/
|
*/
|
||||||
int add_handler(Signal_handler * const h);
|
bool can_add_handler(Signal_handler const &h) const;
|
||||||
|
void add_handler(Signal_handler &h);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Syscall to create a signal receiver
|
* Syscall to create a signal receiver
|
||||||
|
@ -322,6 +289,8 @@ class Kernel::Signal_receiver : public Kernel::Object
|
||||||
*/
|
*/
|
||||||
static void syscall_destroy(Genode::Kernel_object<Signal_receiver> &r) {
|
static void syscall_destroy(Genode::Kernel_object<Signal_receiver> &r) {
|
||||||
call(call_id_delete_signal_receiver(), (Call_arg)&r); }
|
call(call_id_delete_signal_receiver(), (Call_arg)&r); }
|
||||||
|
|
||||||
|
Object &kernel_object() { return _kernel_object; }
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* _CORE__KERNEL__SIGNAL_RECEIVER_H_ */
|
#endif /* _CORE__KERNEL__SIGNAL_RECEIVER_H_ */
|
||||||
|
|
|
@ -36,6 +36,81 @@ extern "C" void _core_start(void);
|
||||||
using namespace Kernel;
|
using namespace Kernel;
|
||||||
|
|
||||||
|
|
||||||
|
void Thread::_ipc_alloc_recv_caps(unsigned cap_count)
|
||||||
|
{
|
||||||
|
Genode::Allocator &slab = pd().platform_pd().capability_slab();
|
||||||
|
for (unsigned i = 0; i < cap_count; i++) {
|
||||||
|
if (_obj_id_ref_ptr[i] == nullptr)
|
||||||
|
_obj_id_ref_ptr[i] = slab.alloc(sizeof(Object_identity_reference));
|
||||||
|
}
|
||||||
|
_ipc_rcv_caps = cap_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Thread::_ipc_free_recv_caps()
|
||||||
|
{
|
||||||
|
for (unsigned i = 0; i < _ipc_rcv_caps; i++) {
|
||||||
|
if (_obj_id_ref_ptr[i]) {
|
||||||
|
Genode::Allocator &slab = pd().platform_pd().capability_slab();
|
||||||
|
slab.free(_obj_id_ref_ptr[i], sizeof(Object_identity_reference));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ipc_rcv_caps = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Thread::_ipc_init(Genode::Native_utcb &utcb, Thread &starter)
|
||||||
|
{
|
||||||
|
_utcb = &utcb;
|
||||||
|
_ipc_alloc_recv_caps(starter._utcb->cap_cnt());
|
||||||
|
ipc_copy_msg(starter);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Thread::ipc_copy_msg(Thread &sender)
|
||||||
|
{
|
||||||
|
using namespace Genode;
|
||||||
|
using Reference = Object_identity_reference;
|
||||||
|
|
||||||
|
/* copy payload and set destination capability id */
|
||||||
|
*_utcb = *sender._utcb;
|
||||||
|
_utcb->destination(sender._ipc_capid);
|
||||||
|
|
||||||
|
/* translate capabilities */
|
||||||
|
for (unsigned i = 0; i < _ipc_rcv_caps; i++) {
|
||||||
|
|
||||||
|
capid_t id = sender._utcb->cap_get(i);
|
||||||
|
|
||||||
|
/* if there is no capability to send, nothing to do */
|
||||||
|
if (i >= sender._utcb->cap_cnt()) { continue; }
|
||||||
|
|
||||||
|
/* lookup the capability id within the caller's cap space */
|
||||||
|
Reference *oir = (id == cap_id_invalid())
|
||||||
|
? nullptr : sender.pd().cap_tree().find(id);
|
||||||
|
|
||||||
|
/* if the caller's capability is invalid, continue */
|
||||||
|
if (!oir) {
|
||||||
|
_utcb->cap_add(cap_id_invalid());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* lookup the capability id within the callee's cap space */
|
||||||
|
Reference *dst_oir = oir->find(pd());
|
||||||
|
|
||||||
|
/* if it is not found, and the target is not core, create a reference */
|
||||||
|
if (!dst_oir && (&pd() != &core_pd())) {
|
||||||
|
dst_oir = oir->factory(_obj_id_ref_ptr[i], pd());
|
||||||
|
if (dst_oir) _obj_id_ref_ptr[i] = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dst_oir) dst_oir->add_to_utcb();
|
||||||
|
|
||||||
|
/* add the translated capability id to the target buffer */
|
||||||
|
_utcb->cap_add(dst_oir ? dst_oir->capid() : cap_id_invalid());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Thread::Tlb_invalidation::Tlb_invalidation(Thread & caller, Pd & pd,
|
Thread::Tlb_invalidation::Tlb_invalidation(Thread & caller, Pd & pd,
|
||||||
addr_t addr, size_t size,
|
addr_t addr, size_t size,
|
||||||
unsigned cnt)
|
unsigned cnt)
|
||||||
|
@ -76,14 +151,14 @@ void Thread_fault::print(Genode::Output &out) const
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Thread::_signal_context_kill_pending()
|
void Thread::signal_context_kill_pending()
|
||||||
{
|
{
|
||||||
assert(_state == ACTIVE);
|
assert(_state == ACTIVE);
|
||||||
_become_inactive(AWAITS_SIGNAL_CONTEXT_KILL);
|
_become_inactive(AWAITS_SIGNAL_CONTEXT_KILL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Thread::_signal_context_kill_done()
|
void Thread::signal_context_kill_done()
|
||||||
{
|
{
|
||||||
assert(_state == AWAITS_SIGNAL_CONTEXT_KILL);
|
assert(_state == AWAITS_SIGNAL_CONTEXT_KILL);
|
||||||
user_arg_0(0);
|
user_arg_0(0);
|
||||||
|
@ -91,7 +166,7 @@ void Thread::_signal_context_kill_done()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Thread::_signal_context_kill_failed()
|
void Thread::signal_context_kill_failed()
|
||||||
{
|
{
|
||||||
assert(_state == AWAITS_SIGNAL_CONTEXT_KILL);
|
assert(_state == AWAITS_SIGNAL_CONTEXT_KILL);
|
||||||
user_arg_0(-1);
|
user_arg_0(-1);
|
||||||
|
@ -99,14 +174,13 @@ void Thread::_signal_context_kill_failed()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Thread::_await_signal(Signal_receiver * const receiver)
|
void Thread::signal_wait_for_signal()
|
||||||
{
|
{
|
||||||
_become_inactive(AWAITS_SIGNAL);
|
_become_inactive(AWAITS_SIGNAL);
|
||||||
_signal_receiver = receiver;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Thread::_receive_signal(void * const base, size_t const size)
|
void Thread::signal_receive_signal(void * const base, size_t const size)
|
||||||
{
|
{
|
||||||
assert(_state == AWAITS_SIGNAL);
|
assert(_state == AWAITS_SIGNAL);
|
||||||
Genode::memcpy(utcb()->data(), base, size);
|
Genode::memcpy(utcb()->data(), base, size);
|
||||||
|
@ -114,7 +188,7 @@ void Thread::_receive_signal(void * const base, size_t const size)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Thread::_send_request_succeeded()
|
void Thread::ipc_send_request_succeeded()
|
||||||
{
|
{
|
||||||
assert(_state == AWAITS_IPC);
|
assert(_state == AWAITS_IPC);
|
||||||
user_arg_0(0);
|
user_arg_0(0);
|
||||||
|
@ -123,7 +197,7 @@ void Thread::_send_request_succeeded()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Thread::_send_request_failed()
|
void Thread::ipc_send_request_failed()
|
||||||
{
|
{
|
||||||
assert(_state == AWAITS_IPC);
|
assert(_state == AWAITS_IPC);
|
||||||
user_arg_0(-1);
|
user_arg_0(-1);
|
||||||
|
@ -132,7 +206,7 @@ void Thread::_send_request_failed()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Thread::_await_request_succeeded()
|
void Thread::ipc_await_request_succeeded()
|
||||||
{
|
{
|
||||||
assert(_state == AWAITS_IPC);
|
assert(_state == AWAITS_IPC);
|
||||||
user_arg_0(0);
|
user_arg_0(0);
|
||||||
|
@ -140,7 +214,7 @@ void Thread::_await_request_succeeded()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Thread::_await_request_failed()
|
void Thread::ipc_await_request_failed()
|
||||||
{
|
{
|
||||||
assert(_state == AWAITS_IPC);
|
assert(_state == AWAITS_IPC);
|
||||||
user_arg_0(-1);
|
user_arg_0(-1);
|
||||||
|
@ -151,15 +225,15 @@ void Thread::_await_request_failed()
|
||||||
void Thread::_deactivate_used_shares()
|
void Thread::_deactivate_used_shares()
|
||||||
{
|
{
|
||||||
Cpu_job::_deactivate_own_share();
|
Cpu_job::_deactivate_own_share();
|
||||||
Ipc_node::for_each_helper([&] (Ipc_node &h) {
|
_ipc_node.for_each_helper([&] (Thread &thread) {
|
||||||
static_cast<Thread &>(h)._deactivate_used_shares(); });
|
thread._deactivate_used_shares(); });
|
||||||
}
|
}
|
||||||
|
|
||||||
void Thread::_activate_used_shares()
|
void Thread::_activate_used_shares()
|
||||||
{
|
{
|
||||||
Cpu_job::_activate_own_share();
|
Cpu_job::_activate_own_share();
|
||||||
Ipc_node::for_each_helper([&] (Ipc_node &h) {
|
_ipc_node.for_each_helper([&] (Thread &thread) {
|
||||||
static_cast<Thread &>(h)._activate_used_shares(); });
|
thread._activate_used_shares(); });
|
||||||
}
|
}
|
||||||
|
|
||||||
void Thread::_become_active()
|
void Thread::_become_active()
|
||||||
|
@ -180,7 +254,7 @@ void Thread::_die() { _become_inactive(DEAD); }
|
||||||
|
|
||||||
|
|
||||||
Cpu_job * Thread::helping_sink() {
|
Cpu_job * Thread::helping_sink() {
|
||||||
return static_cast<Thread *>(Ipc_node::helping_sink()); }
|
return &_ipc_node.helping_sink(); }
|
||||||
|
|
||||||
|
|
||||||
size_t Thread::_core_to_kernel_quota(size_t const quota) const
|
size_t Thread::_core_to_kernel_quota(size_t const quota) const
|
||||||
|
@ -212,7 +286,7 @@ void Thread::_call_start_thread()
|
||||||
|
|
||||||
/* join protection domain */
|
/* join protection domain */
|
||||||
thread._pd = (Pd *) user_arg_3();
|
thread._pd = (Pd *) user_arg_3();
|
||||||
thread.Ipc_node::_init(*(Native_utcb *)user_arg_4(), *this);
|
thread._ipc_init(*(Native_utcb *)user_arg_4(), *this);
|
||||||
thread._become_active();
|
thread._become_active();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -285,15 +359,15 @@ void Thread::_cancel_blocking()
|
||||||
_become_active();
|
_become_active();
|
||||||
return;
|
return;
|
||||||
case AWAITS_IPC:
|
case AWAITS_IPC:
|
||||||
Ipc_node::cancel_waiting();
|
_ipc_node.cancel_waiting();
|
||||||
return;
|
return;
|
||||||
case AWAITS_SIGNAL:
|
case AWAITS_SIGNAL:
|
||||||
Signal_handler::cancel_waiting();
|
_signal_handler.cancel_waiting();
|
||||||
user_arg_0(-1);
|
user_arg_0(-1);
|
||||||
_become_active();
|
_become_active();
|
||||||
return;
|
return;
|
||||||
case AWAITS_SIGNAL_CONTEXT_KILL:
|
case AWAITS_SIGNAL_CONTEXT_KILL:
|
||||||
Signal_context_killer::cancel_waiting();
|
_signal_context_killer.cancel_waiting();
|
||||||
return;
|
return;
|
||||||
case ACTIVE:
|
case ACTIVE:
|
||||||
return;
|
return;
|
||||||
|
@ -339,11 +413,18 @@ void Thread::_call_delete_thread()
|
||||||
|
|
||||||
void Thread::_call_await_request_msg()
|
void Thread::_call_await_request_msg()
|
||||||
{
|
{
|
||||||
if (Ipc_node::await_request(user_arg_1())) {
|
if (_ipc_node.can_await_request()) {
|
||||||
|
_ipc_alloc_recv_caps(user_arg_1());
|
||||||
|
_ipc_node.await_request();
|
||||||
|
if (_ipc_node.awaits_request()) {
|
||||||
|
_become_inactive(AWAITS_IPC);
|
||||||
|
} else {
|
||||||
|
user_arg_0(0);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Genode::raw("IPC await request: bad state");
|
||||||
user_arg_0(0);
|
user_arg_0(0);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
_become_inactive(AWAITS_IPC);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -372,8 +453,11 @@ void Thread::timeout_triggered()
|
||||||
{
|
{
|
||||||
Signal_context * const c =
|
Signal_context * const c =
|
||||||
pd().cap_tree().find<Signal_context>(_timeout_sigid);
|
pd().cap_tree().find<Signal_context>(_timeout_sigid);
|
||||||
if (!c || c->submit(1))
|
if (!c || !c->can_submit(1)) {
|
||||||
Genode::raw(*this, ": failed to submit timeout signal");
|
Genode::raw(*this, ": failed to submit timeout signal");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
c->submit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -390,8 +474,14 @@ void Thread::_call_send_request_msg()
|
||||||
bool const help = Cpu_job::_helping_possible(*dst);
|
bool const help = Cpu_job::_helping_possible(*dst);
|
||||||
oir = oir->find(dst->pd());
|
oir = oir->find(dst->pd());
|
||||||
|
|
||||||
Ipc_node::send_request(*dst, oir ? oir->capid() : cap_id_invalid(),
|
if (!_ipc_node.can_send_request()) {
|
||||||
help, user_arg_2());
|
Genode::raw("IPC send request: bad state");
|
||||||
|
} else {
|
||||||
|
_ipc_alloc_recv_caps(user_arg_2());
|
||||||
|
_ipc_capid = oir ? oir->capid() : cap_id_invalid();
|
||||||
|
_ipc_node.send_request(dst->_ipc_node, help);
|
||||||
|
}
|
||||||
|
|
||||||
_state = AWAITS_IPC;
|
_state = AWAITS_IPC;
|
||||||
if (!help || !dst->own_share_active()) { _deactivate_used_shares(); }
|
if (!help || !dst->own_share_active()) { _deactivate_used_shares(); }
|
||||||
}
|
}
|
||||||
|
@ -399,7 +489,7 @@ void Thread::_call_send_request_msg()
|
||||||
|
|
||||||
void Thread::_call_send_reply_msg()
|
void Thread::_call_send_reply_msg()
|
||||||
{
|
{
|
||||||
Ipc_node::send_reply();
|
_ipc_node.send_reply();
|
||||||
bool const await_request_msg = user_arg_2();
|
bool const await_request_msg = user_arg_2();
|
||||||
if (await_request_msg) { _call_await_request_msg(); }
|
if (await_request_msg) { _call_await_request_msg(); }
|
||||||
else { user_arg_0(0); }
|
else { user_arg_0(0); }
|
||||||
|
@ -434,11 +524,12 @@ void Thread::_call_await_signal()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
/* register handler at the receiver */
|
/* register handler at the receiver */
|
||||||
if (r->add_handler(this)) {
|
if (!r->can_add_handler(_signal_handler)) {
|
||||||
Genode::raw("failed to register handler at signal receiver");
|
Genode::raw("failed to register handler at signal receiver");
|
||||||
user_arg_0(-1);
|
user_arg_0(-1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
r->add_handler(_signal_handler);
|
||||||
user_arg_0(0);
|
user_arg_0(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -455,10 +546,11 @@ void Thread::_call_pending_signal()
|
||||||
}
|
}
|
||||||
|
|
||||||
/* register handler at the receiver */
|
/* register handler at the receiver */
|
||||||
if (r->add_handler(this)) {
|
if (!r->can_add_handler(_signal_handler)) {
|
||||||
user_arg_0(-1);
|
user_arg_0(-1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
r->add_handler(_signal_handler);
|
||||||
|
|
||||||
if (_state == AWAITS_SIGNAL) {
|
if (_state == AWAITS_SIGNAL) {
|
||||||
_cancel_blocking();
|
_cancel_blocking();
|
||||||
|
@ -500,11 +592,12 @@ void Thread::_call_submit_signal()
|
||||||
}
|
}
|
||||||
|
|
||||||
/* trigger signal context */
|
/* trigger signal context */
|
||||||
if (c->submit(user_arg_2())) {
|
if (!c->can_submit(user_arg_2())) {
|
||||||
Genode::raw("failed to submit signal context");
|
Genode::raw("failed to submit signal context");
|
||||||
user_arg_0(-1);
|
user_arg_0(-1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
c->submit(user_arg_2());
|
||||||
user_arg_0(0);
|
user_arg_0(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -534,11 +627,12 @@ void Thread::_call_kill_signal_context()
|
||||||
}
|
}
|
||||||
|
|
||||||
/* kill signal context */
|
/* kill signal context */
|
||||||
if (c->kill(this)) {
|
if (!c->can_kill()) {
|
||||||
Genode::raw("failed to kill signal context");
|
Genode::raw("failed to kill signal context");
|
||||||
user_arg_0(-1);
|
user_arg_0(-1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
c->kill(_signal_context_killer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -721,17 +815,23 @@ void Thread::_mmu_exception()
|
||||||
|
|
||||||
if (_core)
|
if (_core)
|
||||||
Genode::raw(*this, " raised a fault, which should never happen ",
|
Genode::raw(*this, " raised a fault, which should never happen ",
|
||||||
_fault);
|
_fault);
|
||||||
|
|
||||||
if (_pager) _pager->submit(1);
|
if (_pager && _pager->can_submit(1)) {
|
||||||
|
_pager->submit(1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Thread::Thread(unsigned const priority, unsigned const quota,
|
Thread::Thread(unsigned const priority, unsigned const quota,
|
||||||
char const * const label, bool core)
|
char const * const label, bool core)
|
||||||
:
|
:
|
||||||
Cpu_job(priority, quota), _state(AWAITS_START),
|
Kernel::Object { *this },
|
||||||
_signal_receiver(0), _label(label), _core(core), regs(core) { }
|
Cpu_job(priority, quota), _ipc_node(*this), _state(AWAITS_START),
|
||||||
|
_label(label), _core(core), regs(core) { }
|
||||||
|
|
||||||
|
|
||||||
|
Thread::~Thread() { _ipc_free_recv_caps(); }
|
||||||
|
|
||||||
|
|
||||||
void Thread::print(Genode::Output &out) const
|
void Thread::print(Genode::Output &out) const
|
||||||
|
|
|
@ -14,6 +14,8 @@
|
||||||
#ifndef _CORE__KERNEL__THREAD_H_
|
#ifndef _CORE__KERNEL__THREAD_H_
|
||||||
#define _CORE__KERNEL__THREAD_H_
|
#define _CORE__KERNEL__THREAD_H_
|
||||||
|
|
||||||
|
|
||||||
|
/* Genode includes */
|
||||||
#include <base/signal.h>
|
#include <base/signal.h>
|
||||||
#include <util/reconstructible.h>
|
#include <util/reconstructible.h>
|
||||||
|
|
||||||
|
@ -24,6 +26,12 @@
|
||||||
#include <kernel/signal_receiver.h>
|
#include <kernel/signal_receiver.h>
|
||||||
#include <kernel/ipc_node.h>
|
#include <kernel/ipc_node.h>
|
||||||
#include <object.h>
|
#include <object.h>
|
||||||
|
#include <kernel/interface.h>
|
||||||
|
#include <assertion.h>
|
||||||
|
|
||||||
|
/* base-local includes */
|
||||||
|
#include <base/internal/native_utcb.h>
|
||||||
|
|
||||||
|
|
||||||
namespace Kernel
|
namespace Kernel
|
||||||
{
|
{
|
||||||
|
@ -48,11 +56,7 @@ struct Kernel::Thread_fault
|
||||||
/**
|
/**
|
||||||
* Kernel back-end for userland execution-contexts
|
* Kernel back-end for userland execution-contexts
|
||||||
*/
|
*/
|
||||||
class Kernel::Thread
|
class Kernel::Thread : private Kernel::Object, public Cpu_job, private Timeout
|
||||||
:
|
|
||||||
public Kernel::Object, public Cpu_job,
|
|
||||||
public Ipc_node, public Signal_context_killer, public Signal_handler,
|
|
||||||
private Timeout
|
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
@ -121,15 +125,24 @@ class Kernel::Thread
|
||||||
DEAD = 7,
|
DEAD = 7,
|
||||||
};
|
};
|
||||||
|
|
||||||
Signal_context * _pager = nullptr;
|
enum { MAX_RCV_CAPS = Genode::Msgbuf_base::MAX_CAPS_PER_MSG };
|
||||||
Thread_fault _fault { };
|
|
||||||
State _state;
|
void *_obj_id_ref_ptr[MAX_RCV_CAPS] { nullptr };
|
||||||
Signal_receiver * _signal_receiver;
|
Ipc_node _ipc_node;
|
||||||
char const * const _label;
|
capid_t _ipc_capid { cap_id_invalid() };
|
||||||
capid_t _timeout_sigid = 0;
|
size_t _ipc_rcv_caps { 0 };
|
||||||
bool _paused = false;
|
Genode::Native_utcb *_utcb { nullptr };
|
||||||
bool _cancel_next_await_signal = false;
|
Pd *_pd { nullptr };
|
||||||
bool const _core = false;
|
Signal_context *_pager { nullptr };
|
||||||
|
Thread_fault _fault { };
|
||||||
|
State _state;
|
||||||
|
Signal_handler _signal_handler { *this };
|
||||||
|
Signal_context_killer _signal_context_killer { *this };
|
||||||
|
char const *const _label;
|
||||||
|
capid_t _timeout_sigid { 0 };
|
||||||
|
bool _paused { false };
|
||||||
|
bool _cancel_next_await_signal { false };
|
||||||
|
bool const _core { false };
|
||||||
|
|
||||||
Genode::Constructible<Tlb_invalidation> _tlb_invalidation {};
|
Genode::Constructible<Tlb_invalidation> _tlb_invalidation {};
|
||||||
Genode::Constructible<Destroy> _destroy {};
|
Genode::Constructible<Destroy> _destroy {};
|
||||||
|
@ -258,32 +271,9 @@ class Kernel::Thread
|
||||||
kobj.destruct();
|
kobj.destruct();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _ipc_alloc_recv_caps(unsigned rcv_cap_count);
|
||||||
/***************************
|
void _ipc_free_recv_caps();
|
||||||
** Signal_context_killer **
|
void _ipc_init(Genode::Native_utcb &utcb, Thread &callee);
|
||||||
***************************/
|
|
||||||
|
|
||||||
void _signal_context_kill_pending() override;
|
|
||||||
void _signal_context_kill_failed() override;
|
|
||||||
void _signal_context_kill_done() override;
|
|
||||||
|
|
||||||
|
|
||||||
/********************
|
|
||||||
** Signal_handler **
|
|
||||||
********************/
|
|
||||||
|
|
||||||
void _await_signal(Signal_receiver * const receiver) override;
|
|
||||||
void _receive_signal(void * const base, size_t const size) override;
|
|
||||||
|
|
||||||
|
|
||||||
/**************
|
|
||||||
** Ipc_node **
|
|
||||||
**************/
|
|
||||||
|
|
||||||
void _send_request_succeeded() override;
|
|
||||||
void _send_request_failed() override;
|
|
||||||
void _await_request_succeeded() override;
|
|
||||||
void _await_request_failed() override;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
@ -308,6 +298,8 @@ class Kernel::Thread
|
||||||
Thread(char const * const label)
|
Thread(char const * const label)
|
||||||
: Thread(Cpu_priority::MIN, 0, label, true) { }
|
: Thread(Cpu_priority::MIN, 0, label, true) { }
|
||||||
|
|
||||||
|
~Thread();
|
||||||
|
|
||||||
|
|
||||||
/**************************
|
/**************************
|
||||||
** Support for syscalls **
|
** Support for syscalls **
|
||||||
|
@ -373,6 +365,27 @@ class Kernel::Thread
|
||||||
|
|
||||||
void print(Genode::Output &out) const;
|
void print(Genode::Output &out) const;
|
||||||
|
|
||||||
|
/**************
|
||||||
|
** Ipc_node **
|
||||||
|
**************/
|
||||||
|
|
||||||
|
void ipc_send_request_succeeded() ;
|
||||||
|
void ipc_send_request_failed() ;
|
||||||
|
void ipc_await_request_succeeded();
|
||||||
|
void ipc_await_request_failed() ;
|
||||||
|
void ipc_copy_msg(Thread &sender) ;
|
||||||
|
|
||||||
|
|
||||||
|
/*************
|
||||||
|
** Signals **
|
||||||
|
*************/
|
||||||
|
|
||||||
|
void signal_context_kill_pending();
|
||||||
|
void signal_context_kill_failed();
|
||||||
|
void signal_context_kill_done();
|
||||||
|
void signal_wait_for_signal();
|
||||||
|
void signal_receive_signal(void * const base, size_t const size);
|
||||||
|
|
||||||
|
|
||||||
/*************
|
/*************
|
||||||
** Cpu_job **
|
** Cpu_job **
|
||||||
|
@ -394,8 +407,18 @@ class Kernel::Thread
|
||||||
** Accessors **
|
** Accessors **
|
||||||
***************/
|
***************/
|
||||||
|
|
||||||
|
Object &kernel_object() { return *this; }
|
||||||
char const * label() const { return _label; }
|
char const * label() const { return _label; }
|
||||||
Thread_fault fault() const { return _fault; }
|
Thread_fault fault() const { return _fault; }
|
||||||
|
Genode::Native_utcb *utcb() { return _utcb; }
|
||||||
|
|
||||||
|
Pd &pd() const
|
||||||
|
{
|
||||||
|
if (_pd)
|
||||||
|
return *_pd;
|
||||||
|
|
||||||
|
ASSERT_NEVER_CALLED;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -60,16 +60,19 @@ void Timer::set_timeout(Timeout * const timeout, time_t const duration)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Timer::schedule_timeout()
|
time_t Timer::schedule_timeout()
|
||||||
{
|
{
|
||||||
/* get the timeout with the nearest end time */
|
/* get the timeout with the nearest end time */
|
||||||
Timeout * timeout = _timeout_list.first();
|
Timeout * timeout = _timeout_list.first();
|
||||||
assert(timeout);
|
assert(timeout);
|
||||||
|
|
||||||
/* install timeout at timer hardware */
|
/* install timeout at timer hardware */
|
||||||
_time += _duration();
|
time_t duration = _duration();
|
||||||
|
_time += duration;
|
||||||
_last_timeout_duration = (timeout->_end > _time) ? timeout->_end - _time : 1;
|
_last_timeout_duration = (timeout->_end > _time) ? timeout->_end - _time : 1;
|
||||||
_start_one_shot(_last_timeout_duration);
|
_start_one_shot(_last_timeout_duration);
|
||||||
|
|
||||||
|
return duration;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -91,7 +91,10 @@ class Kernel::Timer
|
||||||
|
|
||||||
Timer(Cpu & cpu);
|
Timer(Cpu & cpu);
|
||||||
|
|
||||||
void schedule_timeout();
|
/**
|
||||||
|
* Return duration from last call of this function
|
||||||
|
*/
|
||||||
|
time_t schedule_timeout();
|
||||||
|
|
||||||
void process_timeouts();
|
void process_timeouts();
|
||||||
|
|
||||||
|
|
|
@ -33,8 +33,7 @@ namespace Kernel
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class Kernel::Vm : public Cpu_job,
|
class Kernel::Vm : public Cpu_job
|
||||||
public Kernel::Object
|
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
@ -48,6 +47,7 @@ class Kernel::Vm : public Cpu_job,
|
||||||
|
|
||||||
enum Scheduler_state { ACTIVE, INACTIVE };
|
enum Scheduler_state { ACTIVE, INACTIVE };
|
||||||
|
|
||||||
|
Object _kernel_object { *this };
|
||||||
unsigned _id = 0;
|
unsigned _id = 0;
|
||||||
State & _state;
|
State & _state;
|
||||||
Signal_context & _context;
|
Signal_context & _context;
|
||||||
|
@ -110,6 +110,7 @@ class Kernel::Vm : public Cpu_job,
|
||||||
static void syscall_destroy(Genode::Kernel_object<Vm> & vm) {
|
static void syscall_destroy(Genode::Kernel_object<Vm> & vm) {
|
||||||
call(call_id_delete_vm(), (Call_arg) &vm); }
|
call(call_id_delete_vm(), (Call_arg) &vm); }
|
||||||
|
|
||||||
|
Object &kernel_object() { return _kernel_object; }
|
||||||
|
|
||||||
/****************
|
/****************
|
||||||
** Vm_session **
|
** Vm_session **
|
||||||
|
|
|
@ -12,8 +12,6 @@
|
||||||
* under the terms of the GNU Affero General Public License version 3.
|
* under the terms of the GNU Affero General Public License version 3.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Genode includes */
|
|
||||||
#include <base/log.h>
|
|
||||||
|
|
||||||
/* core includes */
|
/* core includes */
|
||||||
#include <boot_modules.h>
|
#include <boot_modules.h>
|
||||||
|
@ -32,6 +30,10 @@
|
||||||
#include <base/internal/crt0.h>
|
#include <base/internal/crt0.h>
|
||||||
#include <base/internal/stack_area.h>
|
#include <base/internal/stack_area.h>
|
||||||
|
|
||||||
|
/* Genode includes */
|
||||||
|
#include <base/log.h>
|
||||||
|
#include <trace/source_registry.h>
|
||||||
|
|
||||||
using namespace Genode;
|
using namespace Genode;
|
||||||
|
|
||||||
|
|
||||||
|
@ -128,6 +130,10 @@ void Platform::_init_platform_info()
|
||||||
{
|
{
|
||||||
xml.node("kernel", [&] () { xml.attribute("name", "hw"); });
|
xml.node("kernel", [&] () { xml.attribute("name", "hw"); });
|
||||||
_init_additional_platform_info(xml);
|
_init_additional_platform_info(xml);
|
||||||
|
xml.node("affinity-space", [&] () {
|
||||||
|
xml.attribute("width", affinity_space().width());
|
||||||
|
xml.attribute("height", affinity_space().height());
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!unmap_local(virt_addr, pages)) {
|
if (!unmap_local(virt_addr, pages)) {
|
||||||
|
@ -205,6 +211,40 @@ Platform::Platform()
|
||||||
init_core_log(Core_log_range { core_local_addr, log_size } );
|
init_core_log(Core_log_range { core_local_addr, log_size } );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct Trace_source : public Trace::Source::Info_accessor,
|
||||||
|
private Trace::Control,
|
||||||
|
private Trace::Source
|
||||||
|
{
|
||||||
|
Kernel::Thread &thread;
|
||||||
|
Affinity::Location const affinity;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Trace::Source::Info_accessor interface
|
||||||
|
*/
|
||||||
|
Info trace_source_info() const override
|
||||||
|
{
|
||||||
|
Trace::Execution_time execution_time { thread.execution_time(), 0 };
|
||||||
|
return { Session_label("kernel"), thread.label(), execution_time,
|
||||||
|
affinity };
|
||||||
|
}
|
||||||
|
|
||||||
|
Trace_source(Trace::Source_registry ®istry,
|
||||||
|
Kernel::Thread &thread, Affinity::Location affinity)
|
||||||
|
:
|
||||||
|
Trace::Control(),
|
||||||
|
Trace::Source(*this, *this),
|
||||||
|
thread(thread), affinity(affinity)
|
||||||
|
{
|
||||||
|
registry.insert(this);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/* create trace sources for idle threads */
|
||||||
|
Kernel::cpu_pool().for_each_cpu([&] (Kernel::Cpu & cpu) {
|
||||||
|
new (core_mem_alloc()) Trace_source(Trace::sources(), cpu.idle_thread(),
|
||||||
|
Affinity::Location(cpu.id(), 0));
|
||||||
|
});
|
||||||
|
|
||||||
log(_rom_fs);
|
log(_rom_fs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -88,7 +88,7 @@ Hw::Address_space::Address_space(Page_table & tt,
|
||||||
Hw::Address_space::Address_space(Platform_pd & pd)
|
Hw::Address_space::Address_space(Platform_pd & pd)
|
||||||
: _tt(*construct_at<Page_table>(_table_alloc(), *((Page_table*)Hw::Mm::core_page_tables().base))),
|
: _tt(*construct_at<Page_table>(_table_alloc(), *((Page_table*)Hw::Mm::core_page_tables().base))),
|
||||||
_tt_phys((addr_t)_cma().phys_addr(&_tt)),
|
_tt_phys((addr_t)_cma().phys_addr(&_tt)),
|
||||||
_tt_array(new (_cma()) Array([this] (void * virt) {
|
_tt_array(new (_cma()) Array([] (void * virt) {
|
||||||
return (addr_t)_cma().phys_addr(virt);})),
|
return (addr_t)_cma().phys_addr(virt);})),
|
||||||
_tt_alloc(_tt_array->alloc()),
|
_tt_alloc(_tt_array->alloc()),
|
||||||
_kobj(true, *(Page_table*)translation_table_phys(), pd) { }
|
_kobj(true, *(Page_table*)translation_table_phys(), pd) { }
|
||||||
|
@ -132,10 +132,6 @@ bool Platform_pd::bind_thread(Platform_thread &t)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Platform_pd::unbind_thread(Platform_thread &t) {
|
|
||||||
t.join_pd(nullptr, false, Address_space::weak_ptr()); }
|
|
||||||
|
|
||||||
|
|
||||||
void Platform_pd::assign_parent(Native_capability parent)
|
void Platform_pd::assign_parent(Native_capability parent)
|
||||||
{
|
{
|
||||||
if (!_parent.valid() && parent.valid())
|
if (!_parent.valid() && parent.valid())
|
||||||
|
|
|
@ -209,11 +209,6 @@ class Genode::Platform_pd : public Hw::Address_space,
|
||||||
*/
|
*/
|
||||||
bool bind_thread(Platform_thread &);
|
bool bind_thread(Platform_thread &);
|
||||||
|
|
||||||
/**
|
|
||||||
* Unbind thread from protection domain
|
|
||||||
*/
|
|
||||||
void unbind_thread(Platform_thread &);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Assign parent interface to protection domain
|
* Assign parent interface to protection domain
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -208,8 +208,11 @@ namespace Genode {
|
||||||
/**
|
/**
|
||||||
* Return execution time consumed by the thread
|
* Return execution time consumed by the thread
|
||||||
*/
|
*/
|
||||||
Trace::Execution_time execution_time() const {
|
Trace::Execution_time execution_time() const
|
||||||
return { 0, 0, _quota, _priority }; }
|
{
|
||||||
|
Genode::uint64_t execution_time =
|
||||||
|
const_cast<Platform_thread *>(this)->_kobj->execution_time();
|
||||||
|
return { execution_time, 0, _quota, _priority }; }
|
||||||
|
|
||||||
|
|
||||||
/***************
|
/***************
|
||||||
|
|
|
@ -83,3 +83,24 @@ void Arm_cpu::mmu_fault_status(Fsr::access_t fsr, Thread_fault & fault)
|
||||||
default: fault.type = Thread_fault::UNKNOWN;
|
default: fault.type = Thread_fault::UNKNOWN;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Arm_cpu::switch_to(Arm_cpu::Context&, Arm_cpu::Mmu_context & o)
|
||||||
|
{
|
||||||
|
if (o.cidr == 0) return;
|
||||||
|
|
||||||
|
Cidr::access_t cidr = Cidr::read();
|
||||||
|
if (cidr != o.cidr) {
|
||||||
|
/**
|
||||||
|
* First switch to global mappings only to prevent
|
||||||
|
* that wrong branch predicts result due to ASID
|
||||||
|
* and Page-Table not being in sync (see ARM RM B 3.10.4)
|
||||||
|
*/
|
||||||
|
Cidr::write(0);
|
||||||
|
Cpu::synchronization_barrier();
|
||||||
|
Ttbr0::write(o.ttbr0);
|
||||||
|
Cpu::synchronization_barrier();
|
||||||
|
Cidr::write(o.cidr);
|
||||||
|
Cpu::synchronization_barrier();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -110,16 +110,7 @@ struct Genode::Arm_cpu : public Hw::Arm_cpu
|
||||||
else Tlbiall::write(0);
|
else Tlbiall::write(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void switch_to(Context&, Mmu_context & o)
|
void switch_to(Context&, Mmu_context & o);
|
||||||
{
|
|
||||||
if (o.cidr == 0) return;
|
|
||||||
|
|
||||||
Cidr::access_t cidr = Cidr::read();
|
|
||||||
if (cidr != o.cidr) {
|
|
||||||
Cidr::write(o.cidr);
|
|
||||||
Ttbr0::write(o.ttbr0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void mmu_fault(Context & c, Kernel::Thread_fault & fault);
|
static void mmu_fault(Context & c, Kernel::Thread_fault & fault);
|
||||||
static void mmu_fault_status(Fsr::access_t fsr,
|
static void mmu_fault_status(Fsr::access_t fsr,
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
* under the terms of the GNU Affero General Public License version 3.
|
* under the terms of the GNU Affero General Public License version 3.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <synchronize.s>
|
||||||
|
|
||||||
/*********************
|
/*********************
|
||||||
** Constant values **
|
** Constant values **
|
||||||
|
@ -123,6 +124,8 @@
|
||||||
ldr r1, [r1]
|
ldr r1, [r1]
|
||||||
blx r1
|
blx r1
|
||||||
|
|
||||||
|
SYSTEM_REGISTER_SYNC_BARRIER /* synchronize after the context switch */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Go to kernel entry code
|
* Go to kernel entry code
|
||||||
*/
|
*/
|
||||||
|
@ -164,4 +167,5 @@
|
||||||
ldr r1, [sp, #16*4]
|
ldr r1, [sp, #16*4]
|
||||||
msr spsr_cxsf, r1
|
msr spsr_cxsf, r1
|
||||||
ldm sp, {r0-r14}^
|
ldm sp, {r0-r14}^
|
||||||
|
SYSTEM_REGISTER_SYNC_BARRIER /* synchronize after the context switch */
|
||||||
subs pc, lr, #0
|
subs pc, lr, #0
|
|
@ -18,6 +18,11 @@
|
||||||
/* core includes */
|
/* core includes */
|
||||||
#include <spec/arm/cpu_support.h>
|
#include <spec/arm/cpu_support.h>
|
||||||
|
|
||||||
namespace Genode { using Cpu = Arm_cpu; }
|
namespace Genode { struct Cpu; }
|
||||||
|
|
||||||
|
struct Genode::Cpu : Arm_cpu
|
||||||
|
{
|
||||||
|
static inline void synchronization_barrier() {}
|
||||||
|
};
|
||||||
|
|
||||||
#endif /* _CORE__SPEC__ARM_V6__CPU_H_ */
|
#endif /* _CORE__SPEC__ARM_V6__CPU_H_ */
|
||||||
|
|
15
repos/base-hw/src/core/spec/arm_v6/synchronize.s
Normal file
15
repos/base-hw/src/core/spec/arm_v6/synchronize.s
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
/*
|
||||||
|
* \brief Assembler macros for ARMv6
|
||||||
|
* \author Stefan Kalkowski
|
||||||
|
* \date 2020-02-16
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2020 Genode Labs GmbH
|
||||||
|
*
|
||||||
|
* This file is part of the Genode OS framework, which is distributed
|
||||||
|
* under the terms of the GNU Affero General Public License version 3.
|
||||||
|
*/
|
||||||
|
|
||||||
|
.macro SYSTEM_REGISTER_SYNC_BARRIER
|
||||||
|
.endm
|
|
@ -41,6 +41,12 @@ struct Genode::Arm_v7_cpu : Arm_cpu
|
||||||
else Tlbiallis::write(0);
|
else Tlbiallis::write(0);
|
||||||
} else Arm_cpu::invalidate_tlb(asid);
|
} else Arm_cpu::invalidate_tlb(asid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void synchronization_barrier()
|
||||||
|
{
|
||||||
|
asm volatile("dsb sy\n"
|
||||||
|
"isb sy\n" ::: "memory");
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* _CORE__SPEC__ARM_V7__CPU_SUPPORT_H_ */
|
#endif /* _CORE__SPEC__ARM_V7__CPU_SUPPORT_H_ */
|
||||||
|
|
17
repos/base-hw/src/core/spec/arm_v7/synchronize.s
Normal file
17
repos/base-hw/src/core/spec/arm_v7/synchronize.s
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
/*
|
||||||
|
* \brief Assembler macros for ARMv7
|
||||||
|
* \author Stefan Kalkowski
|
||||||
|
* \date 2020-02-16
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2020 Genode Labs GmbH
|
||||||
|
*
|
||||||
|
* This file is part of the Genode OS framework, which is distributed
|
||||||
|
* under the terms of the GNU Affero General Public License version 3.
|
||||||
|
*/
|
||||||
|
|
||||||
|
.macro SYSTEM_REGISTER_SYNC_BARRIER
|
||||||
|
dsb sy
|
||||||
|
isb sy
|
||||||
|
.endm
|
|
@ -40,12 +40,13 @@ class Board::Pic
|
||||||
|
|
||||||
void irq_occurred(unsigned irq)
|
void irq_occurred(unsigned irq)
|
||||||
{
|
{
|
||||||
isr[irq] = true;
|
if (irq < NR_OF_IRQ)
|
||||||
|
isr[irq] = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool take_request(unsigned &irq)
|
bool take_request(unsigned &irq)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < 256; i++) {
|
for (int i = 0; i < NR_OF_IRQ; i++) {
|
||||||
if (isr[i] == true) {
|
if (isr[i] == true) {
|
||||||
irq = i;
|
irq = i;
|
||||||
isr[i] = false;
|
isr[i] = false;
|
||||||
|
|
|
@ -209,9 +209,12 @@ class Board::Pic : public Genode::Mmio
|
||||||
|
|
||||||
void irq_mode(unsigned irq, unsigned trigger, unsigned polarity);
|
void irq_mode(unsigned irq, unsigned trigger, unsigned polarity);
|
||||||
|
|
||||||
void store_apic_id(unsigned const cpu_id) {
|
void store_apic_id(unsigned const cpu_id)
|
||||||
Id::access_t const lapic_id = read<Id>();
|
{
|
||||||
lapic_ids[cpu_id] = (lapic_id >> 24) & 0xff;
|
if (cpu_id < NR_OF_CPUS) {
|
||||||
|
Id::access_t const lapic_id = read<Id>();
|
||||||
|
lapic_ids[cpu_id] = (lapic_id >> 24) & 0xff;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void send_ipi(unsigned const);
|
void send_ipi(unsigned const);
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
#include <kernel/kernel.h>
|
#include <kernel/kernel.h>
|
||||||
#include <platform.h>
|
#include <platform.h>
|
||||||
#include <platform_thread.h>
|
#include <platform_thread.h>
|
||||||
|
#include <trace/source_registry.h>
|
||||||
|
|
||||||
using namespace Genode;
|
using namespace Genode;
|
||||||
|
|
||||||
|
@ -35,8 +36,44 @@ namespace Hw { extern Untyped_capability _main_thread_cap; }
|
||||||
void Thread::start()
|
void Thread::start()
|
||||||
{
|
{
|
||||||
/* start thread with stack pointer at the top of stack */
|
/* start thread with stack pointer at the top of stack */
|
||||||
if (native_thread().platform_thread->start((void *)&_thread_start, stack_top()))
|
if (native_thread().platform_thread->start((void *)&_thread_start, stack_top())) {
|
||||||
error("failed to start thread");
|
error("failed to start thread");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Trace_source : public Trace::Source::Info_accessor,
|
||||||
|
private Trace::Control,
|
||||||
|
private Trace::Source
|
||||||
|
{
|
||||||
|
Genode::Thread &thread;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Trace::Source::Info_accessor interface
|
||||||
|
*/
|
||||||
|
Info trace_source_info() const override
|
||||||
|
{
|
||||||
|
Platform_thread * t = thread.native_thread().platform_thread;
|
||||||
|
|
||||||
|
Trace::Execution_time execution_time { 0, 0 };
|
||||||
|
if (t)
|
||||||
|
execution_time = t->execution_time();
|
||||||
|
|
||||||
|
return { Session_label("core"), thread.name(),
|
||||||
|
execution_time, thread.affinity() };
|
||||||
|
}
|
||||||
|
|
||||||
|
Trace_source(Trace::Source_registry ®istry, Genode::Thread &thread)
|
||||||
|
:
|
||||||
|
Trace::Control(),
|
||||||
|
Trace::Source(*this, *this),
|
||||||
|
thread(thread)
|
||||||
|
{
|
||||||
|
registry.insert(this);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/* create trace sources for core threads */
|
||||||
|
new (platform().core_mem_alloc()) Trace_source(Trace::sources(), *this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -62,7 +62,7 @@ thread_check_stopped_and_restart(Genode::Thread * const t)
|
||||||
/**
|
/**
|
||||||
* Pause execution of current thread
|
* Pause execution of current thread
|
||||||
*/
|
*/
|
||||||
static inline void thread_stop_myself() { Kernel::stop_thread(); }
|
static inline void thread_stop_myself(Genode::Thread *) { Kernel::stop_thread(); }
|
||||||
|
|
||||||
|
|
||||||
#endif /* _INCLUDE__BASE__INTERNAL__LOCK_HELPER_H_ */
|
#endif /* _INCLUDE__BASE__INTERNAL__LOCK_HELPER_H_ */
|
||||||
|
|
|
@ -249,6 +249,9 @@ struct Hw::Arm_cpu
|
||||||
/* Physical Count register */
|
/* Physical Count register */
|
||||||
ARM_CP15_REGISTER_64BIT(Cntpct, c14, 0);
|
ARM_CP15_REGISTER_64BIT(Cntpct, c14, 0);
|
||||||
|
|
||||||
|
/* Diagnostic register */
|
||||||
|
ARM_CP15_REGISTER_32BIT(Diag, c15, c0, 0, 1);
|
||||||
|
|
||||||
/******************************
|
/******************************
|
||||||
** Program status registers **
|
** Program status registers **
|
||||||
******************************/
|
******************************/
|
||||||
|
@ -283,12 +286,6 @@ struct Hw::Arm_cpu
|
||||||
** Cache maintainance functions **
|
** Cache maintainance functions **
|
||||||
**********************************/
|
**********************************/
|
||||||
|
|
||||||
static inline void synchronization_barrier()
|
|
||||||
{
|
|
||||||
asm volatile("dsb\n"
|
|
||||||
"isb\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void wait_for_xchg(volatile void * addr,
|
static inline void wait_for_xchg(volatile void * addr,
|
||||||
unsigned long new_value,
|
unsigned long new_value,
|
||||||
unsigned long expected_value)
|
unsigned long expected_value)
|
||||||
|
|
|
@ -422,6 +422,9 @@ class Hw::Page_table
|
||||||
size_t const size, Page_flags const & flags,
|
size_t const size, Page_flags const & flags,
|
||||||
Allocator & alloc)
|
Allocator & alloc)
|
||||||
{
|
{
|
||||||
|
if (i > MAX_INDEX)
|
||||||
|
return;
|
||||||
|
|
||||||
using Pt = Page_table_level_2;
|
using Pt = Page_table_level_2;
|
||||||
using Ptd = Page_table_descriptor;
|
using Ptd = Page_table_descriptor;
|
||||||
|
|
||||||
|
|
|
@ -137,6 +137,8 @@ struct Hw::Arm_64_cpu
|
||||||
|
|
||||||
SYSTEM_REGISTER(64, Mpidr, mpidr_el1);
|
SYSTEM_REGISTER(64, Mpidr, mpidr_el1);
|
||||||
|
|
||||||
|
SYSTEM_REGISTER(32, Pmcr_el0, pmcr_el0);
|
||||||
|
SYSTEM_REGISTER(32, Pmcntenset_el0, pmcntenset_el0);
|
||||||
SYSTEM_REGISTER(32, Pmuserenr_el0, pmuserenr_el0);
|
SYSTEM_REGISTER(32, Pmuserenr_el0, pmuserenr_el0);
|
||||||
|
|
||||||
SYSTEM_REGISTER(64, Scr, scr_el3,
|
SYSTEM_REGISTER(64, Scr, scr_el3,
|
||||||
|
|
|
@ -57,13 +57,6 @@ namespace Hw
|
||||||
template <typename ENTRY, unsigned PAGE_SIZE_LOG2, unsigned SIZE_LOG2>
|
template <typename ENTRY, unsigned PAGE_SIZE_LOG2, unsigned SIZE_LOG2>
|
||||||
class Page_directory;
|
class Page_directory;
|
||||||
|
|
||||||
using Level_3_translation_table =
|
|
||||||
Page_directory<Level_4_translation_table,
|
|
||||||
SIZE_LOG2_2MB, SIZE_LOG2_1GB>;
|
|
||||||
using Level_2_translation_table =
|
|
||||||
Page_directory<Level_3_translation_table,
|
|
||||||
SIZE_LOG2_1GB, SIZE_LOG2_512GB>;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* IA-32e common descriptor.
|
* IA-32e common descriptor.
|
||||||
*
|
*
|
||||||
|
@ -489,7 +482,24 @@ class Hw::Page_directory
|
||||||
*/
|
*/
|
||||||
void remove_translation(addr_t vo, size_t size, Allocator & alloc) {
|
void remove_translation(addr_t vo, size_t size, Allocator & alloc) {
|
||||||
_range_op(vo, 0, size, Remove_func(alloc)); }
|
_range_op(vo, 0, size, Remove_func(alloc)); }
|
||||||
} __attribute__((aligned(1 << ALIGNM_LOG2)));
|
};
|
||||||
|
|
||||||
|
|
||||||
|
namespace Hw {
|
||||||
|
|
||||||
|
struct Level_3_translation_table :
|
||||||
|
Page_directory<
|
||||||
|
Level_4_translation_table,
|
||||||
|
SIZE_LOG2_2MB, SIZE_LOG2_1GB>
|
||||||
|
{ } __attribute__((aligned(1 << ALIGNM_LOG2)));
|
||||||
|
|
||||||
|
struct Level_2_translation_table :
|
||||||
|
Page_directory<
|
||||||
|
Level_3_translation_table,
|
||||||
|
SIZE_LOG2_1GB, SIZE_LOG2_512GB>
|
||||||
|
{ } __attribute__((aligned(1 << ALIGNM_LOG2)));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
class Hw::Pml4_table
|
class Hw::Pml4_table
|
||||||
|
|
|
@ -56,7 +56,7 @@ namespace Hw
|
||||||
* \param p pointer
|
* \param p pointer
|
||||||
* \param alignm_log2 log2 of the required alignment
|
* \param alignm_log2 log2 of the required alignment
|
||||||
*/
|
*/
|
||||||
constexpr bool aligned(void * const p, addr_t alignm_log2) {
|
inline bool aligned(void * const p, addr_t alignm_log2) {
|
||||||
return (addr_t)p == trunc((addr_t)p, alignm_log2); }
|
return (addr_t)p == trunc((addr_t)p, alignm_log2); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -130,10 +130,11 @@ void Genode::ipc_reply(Native_capability, Rpc_exception_code exc,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Genode::Rpc_request Genode::ipc_reply_wait(Reply_capability const &,
|
Genode::Rpc_request Genode::ipc_reply_wait(Reply_capability const &,
|
||||||
Rpc_exception_code exc,
|
Rpc_exception_code exc,
|
||||||
Msgbuf_base &reply_msg,
|
Msgbuf_base &reply_msg,
|
||||||
Msgbuf_base &request_msg)
|
Msgbuf_base &request_msg,
|
||||||
|
Rpc_entrypoint::Native_context &)
|
||||||
{
|
{
|
||||||
Native_utcb &utcb = *Thread::myself()->utcb();
|
Native_utcb &utcb = *Thread::myself()->utcb();
|
||||||
|
|
||||||
|
@ -162,10 +163,11 @@ Genode::Rpc_request Genode::ipc_reply_wait(Reply_capability const &,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Ipc_server::Ipc_server()
|
Ipc_server::Ipc_server(Rpc_entrypoint::Native_context& _native_context)
|
||||||
:
|
:
|
||||||
Native_capability(Thread::myself() ? Thread::myself()->native_thread().cap
|
Native_capability(Thread::myself() ? Thread::myself()->native_thread().cap
|
||||||
: Hw::_main_thread_cap)
|
: Hw::_main_thread_cap),
|
||||||
|
_native_context(_native_context)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -75,7 +75,7 @@ void Thread::_thread_start()
|
||||||
{
|
{
|
||||||
Thread::myself()->_thread_bootstrap();
|
Thread::myself()->_thread_bootstrap();
|
||||||
Thread::myself()->entry();
|
Thread::myself()->entry();
|
||||||
Thread::myself()->_join_lock.unlock();
|
Thread::myself()->_join.wakeup();
|
||||||
Genode::sleep_forever();
|
Genode::sleep_forever();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
#
|
#
|
||||||
|
|
||||||
TARGET = test-cpu_scheduler
|
TARGET = test-cpu_scheduler
|
||||||
SRC_CC = test.cc cpu_scheduler.cc double_list.cc
|
SRC_CC = test.cc cpu_scheduler.cc
|
||||||
INC_DIR += $(REP_DIR)/src/core $(REP_DIR)/src/include $(BASE_DIR)/src/include
|
INC_DIR += $(REP_DIR)/src/core $(REP_DIR)/src/include $(BASE_DIR)/src/include
|
||||||
LIBS = base
|
LIBS = base
|
||||||
|
|
||||||
|
|
|
@ -33,7 +33,7 @@ struct Data
|
||||||
Cpu_scheduler scheduler;
|
Cpu_scheduler scheduler;
|
||||||
char shares[9][sizeof(Cpu_share)];
|
char shares[9][sizeof(Cpu_share)];
|
||||||
|
|
||||||
Data() : idle(0, 0), scheduler(&idle, 1000, 100) { }
|
Data() : idle(0, 0), scheduler(idle, 1000, 100) { }
|
||||||
};
|
};
|
||||||
|
|
||||||
Data * data()
|
Data * data()
|
||||||
|
@ -79,13 +79,13 @@ void create(unsigned const id)
|
||||||
case 9: new (p) Cpu_share(2, 0); break;
|
case 9: new (p) Cpu_share(2, 0); break;
|
||||||
default: return;
|
default: return;
|
||||||
}
|
}
|
||||||
data()->scheduler.insert(s);
|
data()->scheduler.insert(*s);
|
||||||
}
|
}
|
||||||
|
|
||||||
void destroy(unsigned const id)
|
void destroy(unsigned const id)
|
||||||
{
|
{
|
||||||
Cpu_share * const s = share(id);
|
Cpu_share * const s = share(id);
|
||||||
data()->scheduler.remove(s);
|
data()->scheduler.remove(*s);
|
||||||
s->~Cpu_share();
|
s->~Cpu_share();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,10 +104,10 @@ void update_check(unsigned const l, unsigned const c, unsigned const t,
|
||||||
Genode::log("wrong time ", st, " in line ", l);
|
Genode::log("wrong time ", st, " in line ", l);
|
||||||
done();
|
done();
|
||||||
}
|
}
|
||||||
Cpu_share * const hs = data()->scheduler.head();
|
Cpu_share &hs = data()->scheduler.head();
|
||||||
unsigned const hq = data()->scheduler.head_quota();
|
unsigned const hq = data()->scheduler.head_quota();
|
||||||
if (hs != share(s)) {
|
if (&hs != share(s)) {
|
||||||
unsigned const hi = share_id(hs);
|
unsigned const hi = share_id(&hs);
|
||||||
Genode::log("wrong share ", hi, " in line ", l);
|
Genode::log("wrong share ", hi, " in line ", l);
|
||||||
done();
|
done();
|
||||||
}
|
}
|
||||||
|
@ -119,9 +119,9 @@ void update_check(unsigned const l, unsigned const c, unsigned const t,
|
||||||
|
|
||||||
void ready_check(unsigned const l, unsigned const s, bool const x)
|
void ready_check(unsigned const l, unsigned const s, bool const x)
|
||||||
{
|
{
|
||||||
bool const y = data()->scheduler.ready_check(share(s));
|
data()->scheduler.ready_check(*share(s));
|
||||||
if (y != x) {
|
if (data()->scheduler.need_to_schedule() != x) {
|
||||||
Genode::log("wrong check result ", y, " in line ", l);
|
Genode::log("wrong check result ", data()->scheduler.need_to_schedule(), " in line ", l);
|
||||||
done();
|
done();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -133,10 +133,10 @@ void ready_check(unsigned const l, unsigned const s, bool const x)
|
||||||
|
|
||||||
#define C(s) create(s);
|
#define C(s) create(s);
|
||||||
#define D(s) destroy(s);
|
#define D(s) destroy(s);
|
||||||
#define A(s) data()->scheduler.ready(share(s));
|
#define A(s) data()->scheduler.ready(*share(s));
|
||||||
#define I(s) data()->scheduler.unready(share(s));
|
#define I(s) data()->scheduler.unready(*share(s));
|
||||||
#define Y data()->scheduler.yield();
|
#define Y data()->scheduler.yield();
|
||||||
#define Q(s, q) data()->scheduler.quota(share(s), q);
|
#define Q(s, q) data()->scheduler.quota(*share(s), q);
|
||||||
#define U(c, t, s, q) update_check(__LINE__, c, t, s, q);
|
#define U(c, t, s, q) update_check(__LINE__, c, t, s, q);
|
||||||
#define O(s) ready_check(__LINE__, s, true);
|
#define O(s) ready_check(__LINE__, s, true);
|
||||||
#define N(s) ready_check(__LINE__, s, false);
|
#define N(s) ready_check(__LINE__, s, false);
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
|
|
||||||
TARGET = test-double_list
|
TARGET = test-double_list
|
||||||
INC_DIR = $(REP_DIR)/src/core
|
INC_DIR = $(REP_DIR)/src/core
|
||||||
SRC_CC = test.cc double_list.cc
|
SRC_CC = test.cc
|
||||||
LIBS = base
|
LIBS = base
|
||||||
|
|
||||||
vpath double_list.cc $(REP_DIR)/src/core/kernel
|
vpath double_list.cc $(REP_DIR)/src/core/kernel
|
||||||
|
|
|
@ -24,18 +24,18 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using Genode::size_t;
|
using Genode::size_t;
|
||||||
using Kernel::Double_list_typed;
|
using Kernel::Double_list;
|
||||||
using Kernel::Double_list_item;
|
using Kernel::Double_list_item;
|
||||||
|
|
||||||
void * operator new(__SIZE_TYPE__, void * p) { return p; }
|
void * operator new(__SIZE_TYPE__, void * p) { return p; }
|
||||||
|
|
||||||
struct Item_load { char volatile x = 0, y = 0, z = 0; };
|
struct Item_load { char volatile x = 0, y = 0, z = 0; };
|
||||||
|
|
||||||
struct Item : Item_load, Double_list_item
|
struct Item : Item_load, Double_list_item<Item>
|
||||||
{
|
{
|
||||||
unsigned _id;
|
unsigned _id;
|
||||||
|
|
||||||
Item(unsigned const id) : _id(id) { x = 1; y = 2; z = 3; }
|
Item(unsigned const id) : Double_list_item<Item>(*this), _id(id) { x = 1; y = 2; z = 3; }
|
||||||
|
|
||||||
void iteration() { Genode::log(_id); }
|
void iteration() { Genode::log(_id); }
|
||||||
};
|
};
|
||||||
|
@ -44,7 +44,7 @@ struct Data
|
||||||
{
|
{
|
||||||
static constexpr unsigned nr_of_items = 9;
|
static constexpr unsigned nr_of_items = 9;
|
||||||
|
|
||||||
Double_list_typed<Item> list { };
|
Double_list<Item> list { };
|
||||||
char items[nr_of_items][sizeof(Item)];
|
char items[nr_of_items][sizeof(Item)];
|
||||||
|
|
||||||
Data()
|
Data()
|
||||||
|
@ -68,24 +68,27 @@ void done()
|
||||||
|
|
||||||
void check(unsigned i1, unsigned l)
|
void check(unsigned i1, unsigned l)
|
||||||
{
|
{
|
||||||
Item * const i2 = data()->list.head();
|
Double_list_item<Item> * const li2 = data()->list.head();
|
||||||
if (i1 && i2) {
|
if (li2) {
|
||||||
if(i1 == i2->_id) { return; }
|
Item * const i2 = &li2->payload();
|
||||||
Genode::log("head ", i2->_id, " in line ", l);
|
if (i1) {
|
||||||
done();
|
if(i1 == i2->_id) { return; }
|
||||||
} else if (i1 && !i2) {
|
Genode::log("head ", i2->_id, " in line ", l);
|
||||||
|
done();
|
||||||
|
} else {
|
||||||
|
Genode::log("non-empty ", i2->_id, " in line ", l);
|
||||||
|
done();
|
||||||
|
}
|
||||||
|
} else if (i1) {
|
||||||
Genode::log("empty in line ", l);
|
Genode::log("empty in line ", l);
|
||||||
done();
|
done();
|
||||||
} else if (!i1 && i2){
|
|
||||||
Genode::log("non-empty ", i2->_id, " in line ", l);
|
|
||||||
done();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void print_each()
|
void print_each()
|
||||||
{
|
{
|
||||||
Genode::log("print each");
|
Genode::log("print each");
|
||||||
data()->list.for_each([] (Item * const i) { i->iteration(); });
|
data()->list.for_each([] (Item &i) { i.iteration(); });
|
||||||
}
|
}
|
||||||
|
|
||||||
Item * item(unsigned const i) {
|
Item * item(unsigned const i) {
|
||||||
|
|
|
@ -7,7 +7,7 @@ include $(call select_from_repositories,lib/import/import-syscall-linux.mk)
|
||||||
# Manually supply all library search paths of the host compiler to our tool
|
# Manually supply all library search paths of the host compiler to our tool
|
||||||
# chain.
|
# chain.
|
||||||
#
|
#
|
||||||
HOST_LIB_SEARCH_DIRS = $(shell cc $(CC_MARCH) -print-search-dirs | grep libraries |\
|
HOST_LIB_SEARCH_DIRS = $(shell $(CUSTOM_HOST_CC) $(CC_MARCH) -print-search-dirs | grep libraries |\
|
||||||
sed "s/.*=//" | sed "s/:/ /g" |\
|
sed "s/.*=//" | sed "s/:/ /g" |\
|
||||||
sed "s/\/ / /g" | sed "s/\/\$$//")
|
sed "s/\/ / /g" | sed "s/\/\$$//")
|
||||||
#
|
#
|
||||||
|
@ -68,11 +68,11 @@ endif
|
||||||
LD_TEXT_ADDR ?=
|
LD_TEXT_ADDR ?=
|
||||||
LD_SCRIPT_STATIC ?=
|
LD_SCRIPT_STATIC ?=
|
||||||
|
|
||||||
EXT_OBJECTS += $(shell cc $(CC_MARCH) -print-file-name=crt1.o)
|
EXT_OBJECTS += $(shell $(CUSTOM_HOST_CC) $(CC_MARCH) -print-file-name=crt1.o)
|
||||||
EXT_OBJECTS += $(shell cc $(CC_MARCH) -print-file-name=crti.o)
|
EXT_OBJECTS += $(shell $(CUSTOM_HOST_CC) $(CC_MARCH) -print-file-name=crti.o)
|
||||||
EXT_OBJECTS += $(shell $(CUSTOM_CC) $(CC_MARCH) -print-file-name=crtbegin.o)
|
EXT_OBJECTS += $(shell $(CUSTOM_CC) $(CC_MARCH) -print-file-name=crtbegin.o)
|
||||||
EXT_OBJECTS += $(shell $(CUSTOM_CC) $(CC_MARCH) -print-file-name=crtend.o)
|
EXT_OBJECTS += $(shell $(CUSTOM_CC) $(CC_MARCH) -print-file-name=crtend.o)
|
||||||
EXT_OBJECTS += $(shell cc $(CC_MARCH) -print-file-name=crtn.o)
|
EXT_OBJECTS += $(shell $(CUSTOM_HOST_CC) $(CC_MARCH) -print-file-name=crtn.o)
|
||||||
|
|
||||||
LX_LIBS_OPT += -lgcc -lgcc_s -lsupc++ -lc -lpthread
|
LX_LIBS_OPT += -lgcc -lgcc_s -lsupc++ -lc -lpthread
|
||||||
|
|
||||||
|
@ -105,7 +105,7 @@ endif
|
||||||
LD_LIBGCC = $(LX_LIBS_OPT)
|
LD_LIBGCC = $(LX_LIBS_OPT)
|
||||||
|
|
||||||
# use the host c++ for linking to find shared libraries in DT_RPATH library paths
|
# use the host c++ for linking to find shared libraries in DT_RPATH library paths
|
||||||
LD_CMD = c++
|
LD_CMD = $(CUSTOM_HOST_CXX)
|
||||||
|
|
||||||
# disable format-string security checks, which prevent non-literal format strings
|
# disable format-string security checks, which prevent non-literal format strings
|
||||||
CC_OPT += -Wno-format-security
|
CC_OPT += -Wno-format-security
|
||||||
|
@ -114,8 +114,8 @@ CC_OPT += -Wno-format-security
|
||||||
# Disable position-independent executables (which are enabled by default on
|
# Disable position-independent executables (which are enabled by default on
|
||||||
# Ubuntu 16.10 or newer)
|
# Ubuntu 16.10 or newer)
|
||||||
#
|
#
|
||||||
CXX_LINK_OPT_NO_PIE := $(shell \
|
CXX_LINK_OPT_NO_PIE = $(shell \
|
||||||
(echo "int main(){}" | $(LD_CMD) -no-pie -x c++ - -o /dev/null >& /dev/null \
|
(echo "int main(){}" | $(CUSTOM_HOST_CXX) -no-pie -x c++ - -o /dev/null >& /dev/null \
|
||||||
&& echo "-no-pie") || true)
|
&& echo "-no-pie") || true)
|
||||||
CXX_LINK_OPT += $(CXX_LINK_OPT_NO_PIE)
|
CXX_LINK_OPT += $(CXX_LINK_OPT_NO_PIE)
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
HOST_INC_DIR += $(dir $(call select_from_repositories,src/lib/syscall/linux_syscalls.h))
|
HOST_INC_DIR += $(dir $(call select_from_repositories,src/lib/syscall/linux_syscalls.h))
|
||||||
|
HOST_INC_DIR += $(dir $(CUSTOM_HOST_CC))/../$(shell $(CUSTOM_HOST_CC) -dumpmachine)/libc/usr/include
|
||||||
HOST_INC_DIR += /usr/include
|
HOST_INC_DIR += /usr/include
|
||||||
|
|
||||||
# needed for Ubuntu >= 11.04
|
# needed for Ubuntu >= 11.04
|
||||||
HOST_INC_DIR += /usr/include/$(shell gcc -dumpmachine)
|
HOST_INC_DIR += /usr/include/$(shell $(CUSTOM_HOST_CC) -dumpmachine)
|
||||||
|
|
||||||
#
|
#
|
||||||
# Explicitly add some well-known paths as the dumpmachine magic above does not
|
# Explicitly add some well-known paths as the dumpmachine magic above does not
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user